2 This file is part of GNUnet.
3 (C) 2012, 2013 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file namestore/gnunet-service-namestore.c
23 * @brief namestore for the GNUnet naming system
24 * @author Matthias Wachs
25 * @author Christian Grothoff
28 #include "gnunet_util_lib.h"
29 #include "gnunet_dnsparser_lib.h"
30 #include "gnunet_namestore_service.h"
31 #include "gnunet_namestore_plugin.h"
32 #include "gnunet_signatures.h"
33 #include "namestore.h"
35 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
41 struct NamestoreClient;
45 * A namestore iteration operation.
50 * Next element in the DLL
52 struct ZoneIteration *next;
55 * Previous element in the DLL
57 struct ZoneIteration *prev;
60 * Namestore client which intiated this zone iteration
62 struct NamestoreClient *client;
65 * GNUNET_YES if we iterate over a specific zone
66 * GNUNET_NO if we iterate over all zones
71 * Hash of the specific zone if 'has_zone' is GNUNET_YES,
72 * othwerwise set to '\0'
74 struct GNUNET_CRYPTO_ShortHashCode zone;
77 * The operation id fot the zone iteration in the response for the client
82 * Offset of the zone iteration used to address next result of the zone
83 * iteration in the store
85 * Initialy set to 0 in handle_iteration_start
86 * Incremented with by every call to handle_iteration_next
91 * Which flags must be included
93 uint16_t must_have_flags;
96 * Which flags must not be included
98 uint16_t must_not_have_flags;
105 struct NamestoreClient
108 * Next element in the DLL
110 struct NamestoreClient *next;
113 * Previous element in the DLL
115 struct NamestoreClient *prev;
120 struct GNUNET_SERVER_Client *client;
124 * Zone iteration operations in progress initiated by this client
126 struct ZoneIteration *op_head;
130 * Zone iteration operations in progress initiated by this client
132 struct ZoneIteration *op_tail;
137 * A container struct to store information belonging to a zone crypto key pair
139 struct GNUNET_NAMESTORE_CryptoContainer
142 * Filename where to store the container
147 * Short hash of the zone's public key
149 struct GNUNET_CRYPTO_ShortHashCode zone;
154 struct GNUNET_CRYPTO_EccPrivateKey *privkey;
160 * A namestore monitor.
165 * Next element in the DLL
167 struct ZoneMonitor *next;
170 * Previous element in the DLL
172 struct ZoneMonitor *prev;
175 * Namestore client which intiated this zone monitor
177 struct GNUNET_SERVER_Client *client;
180 * GNUNET_YES if we monitor over a specific zone
181 * GNUNET_NO if we monitor all zones
186 * Hash of the specific zone if 'has_zone' is GNUNET_YES,
187 * othwerwise set to '\0'
189 struct GNUNET_CRYPTO_ShortHashCode zone;
192 * The operation id fot the zone iteration in the response for the client
197 * Task active during initial iteration.
199 GNUNET_SCHEDULER_TaskIdentifier task;
202 * Offset of the zone iteration used to address next result of the zone
203 * iteration in the store
205 * Initialy set to 0 in handle_iteration_start
206 * Incremented with by every call to handle_iteration_next
216 * Configuration handle.
218 static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
223 static struct GNUNET_NAMESTORE_PluginFunctions *GSN_database;
228 static char *zonefile_directory;
231 * Name of the database plugin
233 static char *db_lib_name;
236 * Our notification context.
238 static struct GNUNET_SERVER_NotificationContext *snc;
241 * Head of the Client DLL
243 static struct NamestoreClient *client_head;
246 * Tail of the Client DLL
248 static struct NamestoreClient *client_tail;
251 * Hashmap containing the zone keys this namestore has is authoritative for
253 * Keys are the GNUNET_CRYPTO_HashCode of the GNUNET_CRYPTO_ShortHashCode
254 * The values are 'struct GNUNET_NAMESTORE_CryptoContainer *'
256 static struct GNUNET_CONTAINER_MultiHashMap *zonekeys;
259 * First active zone monitor.
261 static struct ZoneMonitor *monitor_head;
264 * Last active zone monitor.
266 static struct ZoneMonitor *monitor_tail;
269 * Notification context shared by all monitors.
271 static struct GNUNET_SERVER_NotificationContext *monitor_nc;
275 * Writes the encrypted private key of a zone in a file
277 * @param filename where to store the zone
278 * @param c the crypto container containing private key of the zone
279 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
282 write_key_to_file (const char *filename,
283 struct GNUNET_NAMESTORE_CryptoContainer *c)
285 struct GNUNET_CRYPTO_EccPrivateKey *ret = c->privkey;
286 struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *enc;
287 struct GNUNET_DISK_FileHandle *fd;
288 struct GNUNET_CRYPTO_ShortHashCode zone;
289 struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded pubkey;
290 struct GNUNET_CRYPTO_EccPrivateKey *privkey;
292 fd = GNUNET_DISK_file_open (filename,
293 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_FAILIFEXISTS,
294 GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
295 if ( (NULL == fd) && (EEXIST == errno) )
297 privkey = GNUNET_CRYPTO_ecc_key_create_from_file (filename);
300 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
301 _("Failed to write zone key to file `%s': %s\n"),
303 _("file exists but reading key failed"));
304 return GNUNET_SYSERR;
306 GNUNET_CRYPTO_ecc_key_get_public (privkey, &pubkey);
307 GNUNET_CRYPTO_short_hash (&pubkey,
308 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
310 GNUNET_CRYPTO_ecc_key_free (privkey);
311 if (0 == memcmp (&zone, &c->zone, sizeof(zone)))
313 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
314 "File zone `%s' containing this key already exists\n",
315 GNUNET_NAMESTORE_short_h2s (&zone));
318 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
319 _("Failed to write zone key to file `%s': %s\n"),
321 _("file exists with different key"));
326 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
327 return GNUNET_SYSERR;
329 if (GNUNET_YES != GNUNET_DISK_file_lock (fd, 0, sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded), GNUNET_YES))
331 GNUNET_break (GNUNET_YES == GNUNET_DISK_file_close (fd));
332 return GNUNET_SYSERR;
334 enc = GNUNET_CRYPTO_ecc_encode_key (ret);
335 GNUNET_assert (NULL != enc);
336 GNUNET_assert (ntohs (enc->size) == GNUNET_DISK_file_write (fd, enc, ntohs (enc->size)));
338 GNUNET_DISK_file_sync (fd);
339 if (GNUNET_YES != GNUNET_DISK_file_unlock (fd, 0, sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded)))
340 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
341 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
342 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
343 "Stored zonekey for zone `%s' in file `%s'\n",
344 GNUNET_NAMESTORE_short_h2s(&c->zone), c->filename);
350 * Write allthe given zone key to disk and then removes the entry from the
351 * 'zonekeys' hash map.
354 * @param key zone key
355 * @param value 'struct GNUNET_NAMESTORE_CryptoContainer' containing the private
357 * @return GNUNET_OK to continue iteration
360 zone_to_disk_it (void *cls,
361 const struct GNUNET_HashCode *key,
364 struct GNUNET_NAMESTORE_CryptoContainer *c = value;
366 if (NULL == c->filename)
367 GNUNET_asprintf(&c->filename,
370 GNUNET_NAMESTORE_short_h2s (&c->zone));
371 (void) write_key_to_file(c->filename, c);
372 GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (zonekeys, key, value));
373 GNUNET_CRYPTO_ecc_key_free (c->privkey);
374 GNUNET_free (c->filename);
381 * Add the given private key to the set of private keys
382 * this namestore can use to sign records when needed.
384 * @param pkey private key to add to our list (reference will
385 * be taken over or freed and should not be used afterwards)
388 learn_private_key (struct GNUNET_CRYPTO_EccPrivateKey *pkey)
390 struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded pub;
391 struct GNUNET_HashCode long_hash;
392 struct GNUNET_CRYPTO_ShortHashCode pubkey_hash;
393 struct GNUNET_NAMESTORE_CryptoContainer *cc;
395 GNUNET_CRYPTO_ecc_key_get_public (pkey, &pub);
396 GNUNET_CRYPTO_short_hash (&pub,
397 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
399 GNUNET_CRYPTO_short_hash_double (&pubkey_hash, &long_hash);
401 if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains(zonekeys, &long_hash))
403 GNUNET_CRYPTO_ecc_key_free (pkey);
406 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
407 "Received new private key for zone `%s'\n",
408 GNUNET_NAMESTORE_short_h2s(&pubkey_hash));
409 cc = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_CryptoContainer));
411 cc->zone = pubkey_hash;
412 GNUNET_assert (GNUNET_YES ==
413 GNUNET_CONTAINER_multihashmap_put(zonekeys, &long_hash, cc,
414 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
419 * Returns the expiration time of the given block of records. The block
420 * expiration time is the expiration time of the block with smallest
423 * @param rd_count number of records given in 'rd'
424 * @param rd array of records
425 * @return absolute expiration time
427 static struct GNUNET_TIME_Absolute
428 get_block_expiration_time (unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd)
431 struct GNUNET_TIME_Absolute expire;
432 struct GNUNET_TIME_Absolute at;
433 struct GNUNET_TIME_Relative rt;
436 return GNUNET_TIME_UNIT_ZERO_ABS;
437 expire = GNUNET_TIME_UNIT_FOREVER_ABS;
438 for (c = 0; c < rd_count; c++)
440 if (0 != (rd[c].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION))
442 rt.rel_value = rd[c].expiration_time;
443 at = GNUNET_TIME_relative_to_absolute (rt);
447 at.abs_value = rd[c].expiration_time;
449 expire = GNUNET_TIME_absolute_min (at, expire);
456 * Task run during shutdown.
462 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
464 struct ZoneIteration *no;
465 struct NamestoreClient *nc;
467 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping namestore service\n");
470 GNUNET_SERVER_notification_context_destroy (snc);
473 GNUNET_CONTAINER_multihashmap_iterate (zonekeys, &zone_to_disk_it, NULL);
474 GNUNET_CONTAINER_multihashmap_destroy (zonekeys);
476 while (NULL != (nc = client_head))
478 while (NULL != (no = nc->op_head))
480 GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no);
483 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
486 GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, GSN_database));
487 GNUNET_free (db_lib_name);
489 GNUNET_free_non_null (zonefile_directory);
490 zonefile_directory = NULL;
491 if (NULL != monitor_nc)
493 GNUNET_SERVER_notification_context_destroy (monitor_nc);
500 * Lookup our internal data structure for a given client.
502 * @param client server client handle to use for the lookup
503 * @return our internal structure for the client, NULL if
504 * we do not have any yet
506 static struct NamestoreClient *
507 client_lookup (struct GNUNET_SERVER_Client *client)
509 struct NamestoreClient *nc;
511 GNUNET_assert (NULL != client);
512 for (nc = client_head; NULL != nc; nc = nc->next)
513 if (client == nc->client)
520 * Called whenever a client is disconnected.
521 * Frees our resources associated with that client.
524 * @param client identification of the client
527 client_disconnect_notification (void *cls,
528 struct GNUNET_SERVER_Client *client)
530 struct ZoneIteration *no;
531 struct NamestoreClient *nc;
532 struct ZoneMonitor *zm;
536 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
537 "Client %p disconnected\n",
539 if (NULL == (nc = client_lookup (client)))
541 while (NULL != (no = nc->op_head))
543 GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no);
546 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
548 for (zm = monitor_head; NULL != zm; zm = zm->next)
550 if (client == zm->client)
552 GNUNET_CONTAINER_DLL_remove (monitor_head,
555 if (GNUNET_SCHEDULER_NO_TASK != zm->task)
557 GNUNET_SCHEDULER_cancel (zm->task);
558 zm->task = GNUNET_SCHEDULER_NO_TASK;
568 * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_START' message
571 * @param client GNUNET_SERVER_Client sending the message
572 * @param message unused
575 handle_start (void *cls,
576 struct GNUNET_SERVER_Client *client,
577 const struct GNUNET_MessageHeader *message)
579 struct NamestoreClient *nc;
581 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
582 "Client %p connected\n", client);
583 if (NULL != client_lookup (client))
586 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
589 nc = GNUNET_malloc (sizeof (struct NamestoreClient));
591 GNUNET_SERVER_notification_context_add (snc, client);
592 GNUNET_CONTAINER_DLL_insert (client_head, client_tail, nc);
593 GNUNET_SERVER_receive_done (client, GNUNET_OK);
598 * Context for name lookups passed from 'handle_lookup_name' to
599 * 'handle_lookup_name_it' as closure
601 struct LookupNameContext
604 * The client to send the response to
606 struct NamestoreClient *nc;
611 const struct GNUNET_CRYPTO_ShortHashCode *zone;
619 * Operation id for the name lookup
624 * Requested specific record type
626 uint32_t record_type;
631 * A 'GNUNET_NAMESTORE_RecordIterator' for name lookups in handle_lookup_name
633 * @param cls a 'struct LookupNameContext *' with information about the request
634 * @param zone_key zone key of the zone
635 * @param expire expiration time
637 * @param rd_count number of records
638 * @param rd array of records
639 * @param signature signature
642 handle_lookup_name_it (void *cls,
643 const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *zone_key,
644 struct GNUNET_TIME_Absolute expire,
646 unsigned int rd_count,
647 const struct GNUNET_NAMESTORE_RecordData *rd,
648 const struct GNUNET_CRYPTO_EccSignature *signature)
650 struct LookupNameContext *lnc = cls;
651 struct LookupNameResponseMessage *lnr_msg;
652 struct GNUNET_NAMESTORE_RecordData *rd_selected;
653 struct GNUNET_NAMESTORE_CryptoContainer *cc;
654 struct GNUNET_CRYPTO_EccSignature *signature_new;
655 struct GNUNET_TIME_Absolute e;
656 struct GNUNET_TIME_Relative re;
657 struct GNUNET_CRYPTO_ShortHashCode zone_key_hash;
658 struct GNUNET_HashCode long_hash;
665 int contains_signature;
670 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
671 "Found %u records under name `%s'\n",
674 authoritative = GNUNET_NO;
675 signature_new = NULL;
677 if (NULL != zone_key)
679 GNUNET_CRYPTO_short_hash (zone_key,
680 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
682 GNUNET_CRYPTO_short_hash_double (&zone_key_hash, &long_hash);
683 if (NULL != (cc = GNUNET_CONTAINER_multihashmap_get (zonekeys, &long_hash)))
685 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
686 "Am authoritative for zone `%s'\n",
687 GNUNET_NAMESTORE_short_h2s (&zone_key_hash));
688 authoritative = GNUNET_YES;
693 rd_modified = GNUNET_NO;
695 /* count records to copy */
696 for (c = 0; c < rd_count; c++)
698 if ( (GNUNET_YES == authoritative) &&
700 GNUNET_NAMESTORE_is_expired (&rd[c]) ) )
702 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
703 "Skipping expired record\n");
706 if ( (GNUNET_NAMESTORE_TYPE_ANY == lnc->record_type) ||
707 (rd[c].record_type == lnc->record_type) )
708 copied_elements++; /* found matching record */
711 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
712 "Skipping non-mtaching record\n");
713 rd_modified = GNUNET_YES;
716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
717 "Found %u records with type %u for name `%s' in zone `%s'\n",
721 GNUNET_NAMESTORE_short_h2s(lnc->zone));
722 if (copied_elements > 0)
724 rd_selected = GNUNET_malloc (copied_elements * sizeof (struct GNUNET_NAMESTORE_RecordData));
726 for (c = 0; c < rd_count; c++)
728 if ( (GNUNET_YES == authoritative) &&
730 GNUNET_NAMESTORE_is_expired (&rd[c])) )
732 if ( (GNUNET_NAMESTORE_TYPE_ANY == lnc->record_type) ||
733 (rd[c].record_type == lnc->record_type) )
735 if (0 != (rd[c].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION))
737 GNUNET_break (GNUNET_YES == authoritative);
738 rd_modified = GNUNET_YES;
739 re.rel_value = rd[c].expiration_time;
740 e = GNUNET_TIME_relative_to_absolute (re);
744 e.abs_value = rd[c].expiration_time;
746 /* found matching record, copy and convert flags to public format */
747 rd_selected[copied_elements] = rd[c]; /* shallow copy! */
748 rd_selected[copied_elements].expiration_time = e.abs_value;
749 if (0 != (rd_selected[copied_elements].flags &
750 (GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION | GNUNET_NAMESTORE_RF_AUTHORITY)))
752 rd_selected[copied_elements].flags &= ~ (GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION |
753 GNUNET_NAMESTORE_RF_AUTHORITY);
754 rd_modified = GNUNET_YES;
760 rd_modified = GNUNET_YES;
767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
768 "Found %u matching records for name `%s' in zone `%s'\n",
771 GNUNET_NAMESTORE_short_h2s (lnc->zone));
772 contains_signature = GNUNET_NO;
773 if (copied_elements > 0)
775 if (GNUNET_YES == authoritative)
777 GNUNET_assert (NULL != cc);
778 e = get_block_expiration_time (rd_count, rd);
779 signature_new = GNUNET_NAMESTORE_create_signature (cc->privkey, e, name, rd_selected, copied_elements);
780 GNUNET_assert (NULL != signature_new);
781 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
782 "Creating signature for name `%s' with %u records in zone `%s'\n",
785 GNUNET_NAMESTORE_short_h2s(&zone_key_hash));
789 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
790 "Not authoritative, records modified is %d, have sig is %d\n",
793 if ((GNUNET_NO == rd_modified) && (NULL != signature))
794 contains_signature = GNUNET_YES; /* returning all records, so include signature */
798 rd_ser_len = GNUNET_NAMESTORE_records_get_size (copied_elements, rd_selected);
799 name_len = (NULL == name) ? 0 : strlen(name) + 1;
800 r_size = sizeof (struct LookupNameResponseMessage) +
803 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
804 "Sending `%s' message\n",
805 "NAMESTORE_LOOKUP_NAME_RESPONSE");
806 lnr_msg = GNUNET_malloc (r_size);
807 lnr_msg->gns_header.header.type = ntohs (GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE);
808 lnr_msg->gns_header.header.size = ntohs (r_size);
809 lnr_msg->gns_header.r_id = htonl (lnc->request_id);
810 lnr_msg->rd_count = htons (copied_elements);
811 lnr_msg->rd_len = htons (rd_ser_len);
812 lnr_msg->name_len = htons (name_len);
813 lnr_msg->expire = GNUNET_TIME_absolute_hton (get_block_expiration_time (copied_elements,
815 name_tmp = (char *) &lnr_msg[1];
816 memcpy (name_tmp, name, name_len);
817 rd_tmp = &name_tmp[name_len];
818 GNUNET_NAMESTORE_records_serialize (copied_elements, rd_selected, rd_ser_len, rd_tmp);
819 if (rd_selected != rd)
820 GNUNET_free_non_null (rd_selected);
821 if (NULL != zone_key)
822 lnr_msg->public_key = *zone_key;
823 if ( (GNUNET_YES == authoritative) &&
824 (copied_elements > 0) )
826 /* use new created signature */
827 lnr_msg->contains_sig = htons (GNUNET_YES);
828 GNUNET_assert (NULL != signature_new);
829 lnr_msg->signature = *signature_new;
830 GNUNET_free (signature_new);
832 else if (GNUNET_YES == contains_signature)
834 /* use existing signature */
835 lnr_msg->contains_sig = htons (GNUNET_YES);
836 GNUNET_assert (NULL != signature);
837 lnr_msg->signature = *signature;
839 GNUNET_SERVER_notification_context_unicast (snc, lnc->nc->client,
840 &lnr_msg->gns_header.header,
842 GNUNET_free (lnr_msg);
847 * Send an empty name response to indicate the end of the
848 * set of results to the client.
850 * @param nc notification context to use for sending
851 * @param client destination of the empty response
852 * @param request_id identification for the request
855 send_empty_response (struct GNUNET_SERVER_NotificationContext *nc,
856 struct GNUNET_SERVER_Client *client,
859 struct LookupNameResponseMessage zir_end;
861 memset (&zir_end, 0, sizeof (zir_end));
862 zir_end.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE);
863 zir_end.gns_header.header.size = htons (sizeof (struct LookupNameResponseMessage));
864 zir_end.gns_header.r_id = htonl(request_id);
865 GNUNET_SERVER_notification_context_unicast (nc,
867 &zir_end.gns_header.header, GNUNET_NO);
872 * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME' message
875 * @param client GNUNET_SERVER_Client sending the message
876 * @param message message of type 'struct LookupNameMessage'
879 handle_lookup_name (void *cls,
880 struct GNUNET_SERVER_Client *client,
881 const struct GNUNET_MessageHeader *message)
883 const struct LookupNameMessage *ln_msg;
884 struct LookupNameContext lnc;
885 struct NamestoreClient *nc;
893 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
894 "Received `%s' message\n",
895 "NAMESTORE_LOOKUP_NAME");
896 if (ntohs (message->size) < sizeof (struct LookupNameMessage))
899 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
902 if (NULL == (nc = client_lookup(client)))
905 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
908 ln_msg = (const struct LookupNameMessage *) message;
909 rid = ntohl (ln_msg->gns_header.r_id);
910 name_len = ntohl (ln_msg->name_len);
911 type = ntohl (ln_msg->record_type);
912 if ((0 == name_len) || (name_len > MAX_NAME_LEN))
915 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
918 name = (const char *) &ln_msg[1];
919 if ('\0' != name[name_len - 1])
922 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
925 if (GNUNET_NAMESTORE_TYPE_ANY == type)
926 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
927 "Looking up all records for name `%s' in zone `%s'\n",
929 GNUNET_NAMESTORE_short_h2s(&ln_msg->zone));
931 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
932 "Looking up records with type %u for name `%s' in zone `%s'\n",
934 GNUNET_NAMESTORE_short_h2s(&ln_msg->zone));
936 conv_name = GNUNET_NAMESTORE_normalize_string (name);
937 if (NULL == conv_name)
939 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
940 "Error converting name `%s'\n", name);
944 /* do the actual lookup */
945 lnc.request_id = rid;
947 lnc.record_type = type;
948 lnc.name = conv_name;
949 lnc.zone = &ln_msg->zone;
951 (ret = GSN_database->iterate_records (GSN_database->cls,
952 &ln_msg->zone, conv_name, 0 /* offset */,
953 &handle_lookup_name_it, &lnc)))
955 /* internal error (in database plugin); might be best to just hang up on
956 plugin rather than to signal that there are 'no' results, which
957 might also be false... */
959 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
960 GNUNET_free (conv_name);
963 GNUNET_free (conv_name);
966 /* no records match at all, generate empty response */
967 send_empty_response (snc, nc->client, rid);
969 GNUNET_SERVER_receive_done (client, GNUNET_OK);
974 * Generate a 'struct LookupNameResponseMessage' and send it to the
975 * given client using the given notification context.
977 * @param nc notification context to use
978 * @param client client to unicast to
979 * @param request_id request ID to use
980 * @param zone_key zone key of the zone
981 * @param expire expiration time
983 * @param rd_count number of records
984 * @param rd array of records
985 * @param signature signature
988 send_lookup_response (struct GNUNET_SERVER_NotificationContext *nc,
989 struct GNUNET_SERVER_Client *client,
991 const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *zone_key,
992 struct GNUNET_TIME_Absolute expire,
994 unsigned int rd_count,
995 const struct GNUNET_NAMESTORE_RecordData *rd,
996 const struct GNUNET_CRYPTO_EccSignature *signature)
998 struct LookupNameResponseMessage *zir_msg;
1005 name_len = strlen (name) + 1;
1006 rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
1007 msg_size = sizeof (struct LookupNameResponseMessage) + name_len + rd_ser_len;
1009 zir_msg = GNUNET_malloc (msg_size);
1010 zir_msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE);
1011 zir_msg->gns_header.header.size = htons (msg_size);
1012 zir_msg->gns_header.r_id = htonl (request_id);
1013 zir_msg->expire = GNUNET_TIME_absolute_hton (expire);
1014 zir_msg->contains_sig = htons ((NULL == signature) ? GNUNET_NO : GNUNET_YES);
1015 zir_msg->name_len = htons (name_len);
1016 zir_msg->rd_count = htons (rd_count);
1017 zir_msg->rd_len = htons (rd_ser_len);
1018 if (NULL != signature)
1019 zir_msg->signature = *signature;
1020 zir_msg->public_key = *zone_key;
1021 name_tmp = (char *) &zir_msg[1];
1022 memcpy (name_tmp, name, name_len);
1023 rd_ser = &name_tmp[name_len];
1024 GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_ser);
1025 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1026 "Sending `%s' message with size %u\n",
1027 "ZONE_ITERATION_RESPONSE",
1029 GNUNET_SERVER_notification_context_unicast (nc,
1031 &zir_msg->gns_header.header,
1033 GNUNET_free (zir_msg);
1038 * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT' message
1041 * @param client GNUNET_SERVER_Client sending the message
1042 * @param message message of type 'struct RecordPutMessage'
1045 handle_record_put (void *cls,
1046 struct GNUNET_SERVER_Client *client,
1047 const struct GNUNET_MessageHeader *message)
1049 struct NamestoreClient *nc;
1050 const struct RecordPutMessage *rp_msg;
1051 struct GNUNET_TIME_Absolute expire;
1052 const struct GNUNET_CRYPTO_EccSignature *signature;
1053 struct RecordPutResponseMessage rpr_msg;
1054 struct GNUNET_CRYPTO_ShortHashCode zone_hash;
1057 size_t msg_size_exp;
1062 uint32_t rd_ser_len;
1066 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1067 "Received `%s' message\n",
1068 "NAMESTORE_RECORD_PUT");
1069 if (ntohs (message->size) < sizeof (struct RecordPutMessage))
1072 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1075 if (NULL == (nc = client_lookup (client)))
1078 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1081 rp_msg = (const struct RecordPutMessage *) message;
1082 rid = ntohl (rp_msg->gns_header.r_id);
1083 msg_size = ntohs (rp_msg->gns_header.header.size);
1084 name_len = ntohs (rp_msg->name_len);
1085 rd_count = ntohs (rp_msg->rd_count);
1086 rd_ser_len = ntohs (rp_msg->rd_len);
1087 if ((rd_count < 1) || (rd_ser_len < 1) || (name_len >= MAX_NAME_LEN) || (0 == name_len))
1090 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1093 msg_size_exp = sizeof (struct RecordPutMessage) + name_len + rd_ser_len;
1094 if (msg_size != msg_size_exp)
1097 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1100 name = (const char *) &rp_msg[1];
1101 if ('\0' != name[name_len -1])
1104 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1107 expire = GNUNET_TIME_absolute_ntoh (rp_msg->expire);
1108 signature = &rp_msg->signature;
1109 rd_ser = &name[name_len];
1110 struct GNUNET_NAMESTORE_RecordData rd[rd_count];
1113 GNUNET_NAMESTORE_records_deserialize (rd_ser_len, rd_ser, rd_count, rd))
1116 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1119 GNUNET_CRYPTO_short_hash (&rp_msg->public_key,
1120 sizeof (rp_msg->public_key),
1123 conv_name = GNUNET_NAMESTORE_normalize_string (name);
1124 if (NULL == conv_name)
1126 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1127 "Error converting name `%s'\n", name);
1131 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1132 "Putting %u records under name `%s' in zone `%s'\n",
1133 rd_count, conv_name,
1134 GNUNET_NAMESTORE_short_h2s (&zone_hash));
1135 res = GSN_database->put_records (GSN_database->cls,
1136 &rp_msg->public_key,
1141 if (GNUNET_OK == res)
1143 struct ZoneMonitor *zm;
1145 for (zm = monitor_head; NULL != zm; zm = zm->next)
1146 if ( (GNUNET_NO == zm->has_zone) ||
1147 (0 == memcmp (&zone_hash, &zm->zone, sizeof (struct GNUNET_CRYPTO_ShortHashCode))) )
1148 send_lookup_response (monitor_nc,
1151 &rp_msg->public_key,
1157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1158 "Putting record for name `%s': %s\n",
1160 (GNUNET_OK == res) ? "OK" : "FAILED");
1161 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1162 "Sending `%s' message\n",
1163 "RECORD_PUT_RESPONSE");
1164 GNUNET_free (conv_name);
1165 rpr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT_RESPONSE);
1166 rpr_msg.gns_header.header.size = htons (sizeof (struct RecordPutResponseMessage));
1167 rpr_msg.gns_header.r_id = htonl (rid);
1168 rpr_msg.op_result = htonl (res);
1169 GNUNET_SERVER_notification_context_unicast (snc,
1171 &rpr_msg.gns_header.header,
1173 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1178 * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE' message
1181 * @param client GNUNET_SERVER_Client sending the message
1182 * @param message message of type 'struct RecordCreateMessage'
1185 handle_record_create (void *cls,
1186 struct GNUNET_SERVER_Client *client,
1187 const struct GNUNET_MessageHeader *message)
1189 static struct GNUNET_CRYPTO_EccSignature dummy_signature;
1190 struct NamestoreClient *nc;
1191 const struct RecordCreateMessage *rp_msg;
1192 struct GNUNET_CRYPTO_EccPrivateKey *pkey;
1193 struct RecordCreateResponseMessage rcr_msg;
1196 size_t msg_size_exp;
1200 const char *pkey_tmp;
1201 const char *name_tmp;
1204 unsigned int rd_count;
1206 struct GNUNET_CRYPTO_ShortHashCode pubkey_hash;
1207 struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded pubkey;
1209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1210 "Received `%s' message\n", "NAMESTORE_RECORD_CREATE");
1211 if (ntohs (message->size) < sizeof (struct RecordCreateMessage))
1214 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1217 if (NULL == (nc = client_lookup (client)))
1220 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1223 rp_msg = (const struct RecordCreateMessage *) message;
1224 rid = ntohl (rp_msg->gns_header.r_id);
1225 name_len = ntohs (rp_msg->name_len);
1226 msg_size = ntohs (message->size);
1227 rd_count = ntohs (rp_msg->rd_count);
1228 rd_ser_len = ntohs (rp_msg->rd_len);
1229 key_len = ntohs (rp_msg->pkey_len);
1230 msg_size_exp = sizeof (struct RecordCreateMessage) + key_len + name_len + rd_ser_len;
1231 if (msg_size != msg_size_exp)
1234 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1237 if ((0 == name_len) || (name_len > MAX_NAME_LEN))
1240 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1243 pkey_tmp = (const char *) &rp_msg[1];
1244 name_tmp = &pkey_tmp[key_len];
1245 rd_ser = &name_tmp[name_len];
1246 if ('\0' != name_tmp[name_len -1])
1249 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1252 if (NULL == (pkey = GNUNET_CRYPTO_ecc_decode_key (pkey_tmp, key_len,
1256 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1260 struct GNUNET_NAMESTORE_RecordData rd[rd_count];
1263 GNUNET_NAMESTORE_records_deserialize (rd_ser_len, rd_ser, rd_count, rd))
1266 GNUNET_CRYPTO_ecc_key_free (pkey);
1267 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1271 /* Extracting and converting private key */
1272 GNUNET_CRYPTO_ecc_key_get_public (pkey, &pubkey);
1273 GNUNET_CRYPTO_short_hash (&pubkey,
1274 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
1276 learn_private_key (pkey);
1277 conv_name = GNUNET_NAMESTORE_normalize_string (name_tmp);
1278 if (NULL == conv_name)
1280 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1281 "Error converting name `%s'\n", name_tmp);
1282 GNUNET_CRYPTO_ecc_key_free (pkey);
1283 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1286 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1287 "Creating %u records for name `%s' in zone `%s'\n",
1288 (unsigned int) rd_count,
1290 GNUNET_NAMESTORE_short_h2s (&pubkey_hash));
1292 res = GSN_database->remove_records (GSN_database->cls,
1296 res = GSN_database->put_records (GSN_database->cls,
1298 GNUNET_TIME_absolute_ntoh (rp_msg->expire),
1302 if (GNUNET_OK == res)
1304 struct ZoneMonitor *zm;
1306 for (zm = monitor_head; NULL != zm; zm = zm->next)
1307 if ( (GNUNET_NO == zm->has_zone) ||
1308 (0 == memcmp (&pubkey_hash, &zm->zone, sizeof (struct GNUNET_CRYPTO_ShortHashCode))) )
1309 send_lookup_response (monitor_nc,
1313 GNUNET_TIME_absolute_ntoh (rp_msg->expire),
1318 GNUNET_free (conv_name);
1322 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1323 "Sending `%s' message\n", "RECORD_CREATE_RESPONSE");
1324 rcr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE_RESPONSE);
1325 rcr_msg.gns_header.header.size = htons (sizeof (struct RecordCreateResponseMessage));
1326 rcr_msg.gns_header.r_id = htonl (rid);
1327 rcr_msg.op_result = htonl (res);
1328 GNUNET_SERVER_notification_context_unicast (snc, nc->client,
1329 &rcr_msg.gns_header.header,
1331 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1336 * Context for record remove operations passed from 'handle_zone_to_name' to
1337 * 'handle_zone_to_name_it' as closure
1339 struct ZoneToNameCtx
1344 struct NamestoreClient *nc;
1347 * Request id (to be used in the response to the client).
1352 * Set to GNUNET_OK on success, GNUNET_SYSERR on error. Note that
1353 * not finding a name for the zone still counts as a 'success' here,
1354 * as this field is about the success of executing the IPC protocol.
1361 * Zone to name iterator
1363 * @param cls struct ZoneToNameCtx *
1364 * @param zone_key the zone key
1365 * @param expire expiration date
1367 * @param rd_count number of records
1368 * @param rd record data
1369 * @param signature signature
1372 handle_zone_to_name_it (void *cls,
1373 const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *zone_key,
1374 struct GNUNET_TIME_Absolute expire,
1376 unsigned int rd_count,
1377 const struct GNUNET_NAMESTORE_RecordData *rd,
1378 const struct GNUNET_CRYPTO_EccSignature *signature)
1380 struct ZoneToNameCtx *ztn_ctx = cls;
1381 struct ZoneToNameResponseMessage *ztnr_msg;
1390 if ((NULL != zone_key) && (NULL != name))
1393 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1394 "Found result: name `%s' has %u records\n",
1397 name_len = strlen (name) + 1;
1401 /* no result found */
1402 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1403 "Found no results\n");
1407 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1408 "Sending `%s' message\n",
1409 "ZONE_TO_NAME_RESPONSE");
1410 rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
1411 msg_size = sizeof (struct ZoneToNameResponseMessage) + name_len + rd_ser_len;
1412 if (NULL != signature)
1413 msg_size += sizeof (struct GNUNET_CRYPTO_EccSignature);
1414 if (msg_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1417 ztn_ctx->success = GNUNET_SYSERR;
1420 ztnr_msg = GNUNET_malloc (msg_size);
1421 ztnr_msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE);
1422 ztnr_msg->gns_header.header.size = htons (msg_size);
1423 ztnr_msg->gns_header.r_id = htonl (ztn_ctx->rid);
1424 ztnr_msg->res = htons (res);
1425 ztnr_msg->rd_len = htons (rd_ser_len);
1426 ztnr_msg->rd_count = htons (rd_count);
1427 ztnr_msg->name_len = htons (name_len);
1428 ztnr_msg->expire = GNUNET_TIME_absolute_hton (expire);
1429 if (NULL != zone_key)
1430 ztnr_msg->zone_key = *zone_key;
1431 name_tmp = (char *) &ztnr_msg[1];
1433 memcpy (name_tmp, name, name_len);
1434 rd_tmp = &name_tmp[name_len];
1435 GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_tmp);
1436 sig_tmp = &rd_tmp[rd_ser_len];
1437 if (NULL != signature)
1438 memcpy (sig_tmp, signature, sizeof (struct GNUNET_CRYPTO_EccSignature));
1439 ztn_ctx->success = GNUNET_OK;
1440 GNUNET_SERVER_notification_context_unicast (snc, ztn_ctx->nc->client,
1441 &ztnr_msg->gns_header.header,
1443 GNUNET_free (ztnr_msg);
1448 * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME' message
1451 * @param client GNUNET_SERVER_Client sending the message
1452 * @param message message of type 'struct ZoneToNameMessage'
1455 handle_zone_to_name (void *cls,
1456 struct GNUNET_SERVER_Client *client,
1457 const struct GNUNET_MessageHeader *message)
1459 struct NamestoreClient *nc;
1460 const struct ZoneToNameMessage *ztn_msg;
1461 struct ZoneToNameCtx ztn_ctx;
1463 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1464 "Received `%s' message\n",
1466 ztn_msg = (const struct ZoneToNameMessage *) message;
1467 if (NULL == (nc = client_lookup(client)))
1470 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1473 ztn_ctx.rid = ntohl (ztn_msg->gns_header.r_id);
1475 ztn_ctx.success = GNUNET_SYSERR;
1476 if (GNUNET_SYSERR ==
1477 GSN_database->zone_to_name (GSN_database->cls,
1479 &ztn_msg->value_zone,
1480 &handle_zone_to_name_it, &ztn_ctx))
1482 /* internal error, hang up instead of signalling something
1483 that might be wrong */
1485 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1488 GNUNET_SERVER_receive_done (client, ztn_ctx.success);
1493 * Zone iteration processor result
1495 enum ZoneIterationResult
1498 * Found records, but all records were filtered
1499 * Continue to iterate
1501 IT_ALL_RECORDS_FILTERED = -1,
1505 * Continue to iterate with next iteration_next call
1507 IT_SUCCESS_MORE_AVAILABLE = 0,
1510 * Iteration complete
1512 IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE = 1
1517 * Context for record remove operations passed from
1518 * 'run_zone_iteration_round' to 'zone_iteraterate_proc' as closure
1520 struct ZoneIterationProcResult
1523 * The zone iteration handle
1525 struct ZoneIteration *zi;
1528 * Iteration result: iteration done?
1529 * IT_SUCCESS_MORE_AVAILABLE: if there may be more results overall but
1530 * we got one for now and have sent it to the client
1531 * IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE: if there are no further results,
1532 * IT_ALL_RECORDS_FILTERED: if all results were filtered so far.
1534 int res_iteration_finished;
1540 * Process results for zone iteration from database
1542 * @param cls struct ZoneIterationProcResult *proc
1543 * @param zone_key the zone key
1544 * @param expire expiration time
1546 * @param rd_count number of records for this name
1547 * @param rd record data
1548 * @param signature block signature
1551 zone_iteraterate_proc (void *cls,
1552 const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *zone_key,
1553 struct GNUNET_TIME_Absolute expire,
1555 unsigned int rd_count,
1556 const struct GNUNET_NAMESTORE_RecordData *rd,
1557 const struct GNUNET_CRYPTO_EccSignature *signature)
1559 struct ZoneIterationProcResult *proc = cls;
1560 struct GNUNET_NAMESTORE_RecordData rd_filtered[rd_count];
1561 struct GNUNET_CRYPTO_EccSignature *new_signature = NULL;
1562 struct GNUNET_NAMESTORE_CryptoContainer *cc;
1563 struct GNUNET_HashCode long_hash;
1564 struct GNUNET_CRYPTO_ShortHashCode zone_hash;
1565 struct GNUNET_TIME_Relative rt;
1566 unsigned int rd_count_filtered;
1569 proc->res_iteration_finished = IT_SUCCESS_MORE_AVAILABLE;
1570 if ((NULL == zone_key) && (NULL == name))
1572 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1573 "Iteration done\n");
1574 proc->res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE;
1577 if ((NULL == zone_key) || (NULL == name))
1579 /* what is this!? should never happen */
1583 rd_count_filtered = 0;
1584 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1585 "Received result for zone iteration: `%s'\n",
1587 for (c = 0; c < rd_count; c++)
1589 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1590 "Record %u has flags: %x must have flags are %x, must not have flags are %x\n",
1592 proc->zi->must_have_flags,
1593 proc->zi->must_not_have_flags);
1594 /* Checking must have flags, except 'relative-expiration' which is a special flag */
1595 if ((rd[c].flags & proc->zi->must_have_flags & (~GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION))
1596 != (proc->zi->must_have_flags & (~ GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION)))
1598 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %u lacks 'must-have' flags: Not included\n", c);
1601 /* Checking must-not-have flags */
1602 if (0 != (rd[c].flags & proc->zi->must_not_have_flags))
1604 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1605 "Record %u has 'must-not-have' flags: Not included\n", c);
1608 rd_filtered[rd_count_filtered] = rd[c];
1609 /* convert relative to absolute expiration time unless explicitly requested otherwise */
1610 if ( (0 == (proc->zi->must_have_flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION)) &&
1611 (0 != (rd[c].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION)) )
1613 /* should convert relative-to-absolute expiration time */
1614 rt.rel_value = rd[c].expiration_time;
1615 rd_filtered[c].expiration_time = GNUNET_TIME_relative_to_absolute (rt).abs_value;
1616 rd_filtered[c].flags &= ~ GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION;
1618 /* we NEVER keep the 'authority' flag */
1619 rd_filtered[c].flags &= ~ GNUNET_NAMESTORE_RF_AUTHORITY;
1620 rd_count_filtered++;
1622 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1623 "Included %u of %u records\n",
1624 rd_count_filtered, rd_count);
1627 if ( (rd_count_filtered > 0) &&
1628 (0 == (proc->zi->must_have_flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION)) )
1630 /* compute / obtain signature, but only if we (a) have records and (b) expiration times were
1631 converted to absolute expiration times */
1632 GNUNET_CRYPTO_short_hash (zone_key,
1633 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
1635 GNUNET_CRYPTO_short_hash_double (&zone_hash, &long_hash);
1636 if (NULL != (cc = GNUNET_CONTAINER_multihashmap_get (zonekeys, &long_hash)))
1638 expire = get_block_expiration_time (rd_count_filtered, rd_filtered);
1639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1640 "Creating signature for `%s' in zone `%s' with %u records and expiration %llu\n",
1641 name, GNUNET_NAMESTORE_short_h2s(&zone_hash),
1643 (unsigned long long) expire.abs_value);
1644 new_signature = GNUNET_NAMESTORE_create_signature (cc->privkey, expire, name,
1645 rd_filtered, rd_count_filtered);
1646 GNUNET_assert (NULL != new_signature);
1647 signature = new_signature;
1649 else if (rd_count_filtered == rd_count)
1651 if (NULL != signature)
1653 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1654 "Using provided signature for `%s' in zone `%s' with %u records and expiration %llu\n",
1655 name, GNUNET_NAMESTORE_short_h2s (&zone_hash), rd_count_filtered,
1656 (unsigned long long) expire.abs_value);
1661 if (0 == rd_count_filtered)
1663 /* After filtering records there are no records left to return */
1664 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No records to transmit\n");
1665 proc->res_iteration_finished = IT_ALL_RECORDS_FILTERED;
1669 if (GNUNET_YES == proc->zi->has_zone)
1670 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1671 "Sending name `%s' for iteration over zone `%s'\n",
1672 name, GNUNET_NAMESTORE_short_h2s(&proc->zi->zone));
1674 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1675 "Sending name `%s' for iteration over all zones\n",
1677 send_lookup_response (snc,
1678 proc->zi->client->client,
1679 proc->zi->request_id,
1686 proc->res_iteration_finished = IT_SUCCESS_MORE_AVAILABLE;
1687 GNUNET_free_non_null (new_signature);
1692 * Perform the next round of the zone iteration.
1694 * @param zi zone iterator to process
1697 run_zone_iteration_round (struct ZoneIteration *zi)
1699 struct ZoneIterationProcResult proc;
1700 struct GNUNET_CRYPTO_ShortHashCode *zone;
1703 memset (&proc, 0, sizeof (proc));
1705 if (GNUNET_YES == zi->has_zone)
1709 proc.res_iteration_finished = IT_ALL_RECORDS_FILTERED;
1710 while (IT_ALL_RECORDS_FILTERED == proc.res_iteration_finished)
1712 if (GNUNET_SYSERR ==
1713 (ret = GSN_database->iterate_records (GSN_database->cls, zone, NULL,
1715 &zone_iteraterate_proc, &proc)))
1720 if (GNUNET_NO == ret)
1721 proc.res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE;
1724 if (IT_SUCCESS_MORE_AVAILABLE == proc.res_iteration_finished)
1726 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1727 "More results available\n");
1728 return; /* more results later */
1730 if (GNUNET_YES == zi->has_zone)
1731 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1732 "No more results for zone `%s'\n",
1733 GNUNET_NAMESTORE_short_h2s(&zi->zone));
1735 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1736 "No more results for all zones\n");
1737 send_empty_response (snc, zi->client->client, zi->request_id);
1738 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1739 "Removing zone iterator\n");
1740 GNUNET_CONTAINER_DLL_remove (zi->client->op_head,
1741 zi->client->op_tail,
1748 * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START' message
1751 * @param client GNUNET_SERVER_Client sending the message
1752 * @param message message of type 'struct ZoneIterationStartMessage'
1755 handle_iteration_start (void *cls,
1756 struct GNUNET_SERVER_Client *client,
1757 const struct GNUNET_MessageHeader *message)
1759 static struct GNUNET_CRYPTO_ShortHashCode zeros;
1760 const struct ZoneIterationStartMessage *zis_msg;
1761 struct NamestoreClient *nc;
1762 struct ZoneIteration *zi;
1764 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_START");
1765 if (NULL == (nc = client_lookup (client)))
1768 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1771 zis_msg = (const struct ZoneIterationStartMessage *) message;
1772 zi = GNUNET_new (struct ZoneIteration);
1773 zi->request_id = ntohl (zis_msg->gns_header.r_id);
1776 zi->must_have_flags = ntohs (zis_msg->must_have_flags);
1777 zi->must_not_have_flags = ntohs (zis_msg->must_not_have_flags);
1778 if (0 == memcmp (&zeros, &zis_msg->zone, sizeof (zeros)))
1780 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting to iterate over all zones\n");
1781 zi->zone = zis_msg->zone;
1782 zi->has_zone = GNUNET_NO;
1786 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1787 "Starting to iterate over zone `%s'\n", GNUNET_NAMESTORE_short_h2s (&zis_msg->zone));
1788 zi->zone = zis_msg->zone;
1789 zi->has_zone = GNUNET_YES;
1791 GNUNET_CONTAINER_DLL_insert (nc->op_head, nc->op_tail, zi);
1792 run_zone_iteration_round (zi);
1793 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1798 * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP' message
1801 * @param client GNUNET_SERVER_Client sending the message
1802 * @param message message of type 'struct ZoneIterationStopMessage'
1805 handle_iteration_stop (void *cls,
1806 struct GNUNET_SERVER_Client *client,
1807 const struct GNUNET_MessageHeader *message)
1809 struct NamestoreClient *nc;
1810 struct ZoneIteration *zi;
1811 const struct ZoneIterationStopMessage *zis_msg;
1814 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1815 "Received `%s' message\n",
1816 "ZONE_ITERATION_STOP");
1817 if (NULL == (nc = client_lookup(client)))
1820 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1823 zis_msg = (const struct ZoneIterationStopMessage *) message;
1824 rid = ntohl (zis_msg->gns_header.r_id);
1825 for (zi = nc->op_head; NULL != zi; zi = zi->next)
1826 if (zi->request_id == rid)
1831 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1834 GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, zi);
1835 if (GNUNET_YES == zi->has_zone)
1836 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1837 "Stopped zone iteration for zone `%s'\n",
1838 GNUNET_NAMESTORE_short_h2s (&zi->zone));
1840 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1841 "Stopped zone iteration over all zones\n");
1843 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1848 * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT' message
1851 * @param client GNUNET_SERVER_Client sending the message
1852 * @param message message of type 'struct ZoneIterationNextMessage'
1855 handle_iteration_next (void *cls,
1856 struct GNUNET_SERVER_Client *client,
1857 const struct GNUNET_MessageHeader *message)
1859 struct NamestoreClient *nc;
1860 struct ZoneIteration *zi;
1861 const struct ZoneIterationNextMessage *zis_msg;
1864 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_NEXT");
1865 if (NULL == (nc = client_lookup(client)))
1868 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1871 zis_msg = (const struct ZoneIterationNextMessage *) message;
1872 rid = ntohl (zis_msg->gns_header.r_id);
1873 for (zi = nc->op_head; NULL != zi; zi = zi->next)
1874 if (zi->request_id == rid)
1879 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1882 run_zone_iteration_round (zi);
1883 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1888 * Load zone keys from directory by reading all .zkey files in this directory
1890 * @param cls int * 'counter' to store the number of files found
1891 * @param filename directory to scan
1892 * @return GNUNET_OK to continue
1895 zonekey_file_it (void *cls, const char *filename)
1897 unsigned int *counter = cls;
1898 struct GNUNET_CRYPTO_EccPrivateKey *pk;
1901 if ((NULL == filename) ||
1902 (NULL == strstr (filename, ".zkey")))
1904 pk = GNUNET_CRYPTO_ecc_key_create_from_file (filename);
1905 learn_private_key (pk);
1912 * Send 'sync' message to zone monitor, we're now in sync.
1914 * @param zm monitor that is now in sync
1917 monitor_sync (struct ZoneMonitor *zm)
1919 struct GNUNET_MessageHeader sync;
1921 sync.size = htons (sizeof (struct GNUNET_MessageHeader));
1922 sync.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_SYNC);
1923 GNUNET_SERVER_notification_context_unicast (monitor_nc,
1931 * Obtain the next datum during the zone monitor's zone intiial iteration.
1933 * @param cls zone monitor that does its initial iteration
1934 * @param tc scheduler context
1937 monitor_next (void *cls,
1938 const struct GNUNET_SCHEDULER_TaskContext *tc);
1942 * A 'GNUNET_NAMESTORE_RecordIterator' for monitors.
1944 * @param cls a 'struct ZoneMonitor *' with information about the monitor
1945 * @param zone_key zone key of the zone
1946 * @param expire expiration time
1948 * @param rd_count number of records
1949 * @param rd array of records
1950 * @param signature signature
1953 monitor_iterate_cb (void *cls,
1954 const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *zone_key,
1955 struct GNUNET_TIME_Absolute expire,
1957 unsigned int rd_count,
1958 const struct GNUNET_NAMESTORE_RecordData *rd,
1959 const struct GNUNET_CRYPTO_EccSignature *signature)
1961 struct ZoneMonitor *zm = cls;
1965 /* finished with iteration */
1969 send_lookup_response (monitor_nc,
1978 zm->task = GNUNET_SCHEDULER_add_now (&monitor_next, zm);
1983 * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START' message
1986 * @param client GNUNET_SERVER_Client sending the message
1987 * @param message message of type 'struct ZoneMonitorStartMessage'
1990 handle_monitor_start (void *cls,
1991 struct GNUNET_SERVER_Client *client,
1992 const struct GNUNET_MessageHeader *message)
1994 static struct GNUNET_CRYPTO_ShortHashCode zeros;
1995 const struct ZoneMonitorStartMessage *zis_msg;
1996 struct ZoneMonitor *zm;
1998 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1999 "Received `%s' message\n",
2000 "ZONE_MONITOR_START");
2001 zis_msg = (const struct ZoneMonitorStartMessage *) message;
2002 zm = GNUNET_new (struct ZoneMonitor);
2003 zm->request_id = ntohl (zis_msg->gns_header.r_id);
2005 zm->client = client; // FIXME: notify handler for disconnects, check monitors!
2006 if (0 == memcmp (&zeros, &zis_msg->zone, sizeof (zeros)))
2008 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2009 "Starting to monitor all zones\n");
2010 zm->zone = zis_msg->zone;
2011 zm->has_zone = GNUNET_NO;
2015 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2016 "Starting to monitor zone `%s'\n",
2017 GNUNET_NAMESTORE_short_h2s (&zis_msg->zone));
2018 zm->zone = zis_msg->zone;
2019 zm->has_zone = GNUNET_YES;
2021 GNUNET_CONTAINER_DLL_insert (monitor_head, monitor_tail, zm);
2022 GNUNET_SERVER_client_mark_monitor (client);
2023 GNUNET_SERVER_notification_context_add (monitor_nc,
2025 zm->task = GNUNET_SCHEDULER_add_now (&monitor_next, zm);
2030 * Obtain the next datum during the zone monitor's zone intiial iteration.
2032 * @param cls zone monitor that does its initial iteration
2033 * @param tc scheduler context
2036 monitor_next (void *cls,
2037 const struct GNUNET_SCHEDULER_TaskContext *tc)
2039 struct ZoneMonitor *zm = cls;
2042 zm->task = GNUNET_SCHEDULER_NO_TASK;
2043 ret = GSN_database->iterate_records (GSN_database->cls,
2044 (GNUNET_YES == zm->has_zone) ? &zm->zone : NULL,
2046 &monitor_iterate_cb, zm);
2047 if (GNUNET_SYSERR == ret)
2049 GNUNET_SERVER_client_disconnect (zm->client);
2052 if (GNUNET_NO == ret)
2062 * Process namestore requests.
2064 * @param cls closure
2065 * @param server the initialized server
2066 * @param cfg configuration to use
2069 run (void *cls, struct GNUNET_SERVER_Handle *server,
2070 const struct GNUNET_CONFIGURATION_Handle *cfg)
2072 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
2073 {&handle_start, NULL,
2074 GNUNET_MESSAGE_TYPE_NAMESTORE_START, sizeof (struct StartMessage)},
2075 {&handle_lookup_name, NULL,
2076 GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME, 0},
2077 {&handle_record_put, NULL,
2078 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT, 0},
2079 {&handle_record_create, NULL,
2080 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE, 0},
2081 {&handle_zone_to_name, NULL,
2082 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME, sizeof (struct ZoneToNameMessage) },
2083 {&handle_iteration_start, NULL,
2084 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START, sizeof (struct ZoneIterationStartMessage) },
2085 {&handle_iteration_next, NULL,
2086 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT, sizeof (struct ZoneIterationNextMessage) },
2087 {&handle_iteration_stop, NULL,
2088 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP, sizeof (struct ZoneIterationStopMessage) },
2089 {&handle_monitor_start, NULL,
2090 GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START, sizeof (struct ZoneMonitorStartMessage) },
2094 unsigned int counter;
2096 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namestore service\n");
2098 monitor_nc = GNUNET_SERVER_notification_context_create (server, 1);
2099 /* Load private keys from disk */
2101 GNUNET_CONFIGURATION_get_value_filename (cfg, "namestore",
2102 "zonefile_directory",
2103 &zonefile_directory))
2105 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2106 _("No directory to load zonefiles specified in configuration\n"));
2107 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
2111 if (GNUNET_NO == GNUNET_DISK_file_test (zonefile_directory))
2113 if (GNUNET_SYSERR == GNUNET_DISK_directory_create (zonefile_directory))
2115 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2116 _("Creating directory `%s' for zone files failed!\n"),
2117 zonefile_directory);
2118 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
2121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2122 "Created directory `%s' for zone files\n",
2123 zonefile_directory);
2126 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2127 "Scanning directory `%s' for zone files\n",
2128 zonefile_directory);
2129 zonekeys = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO);
2131 GNUNET_DISK_directory_scan (zonefile_directory,
2132 &zonekey_file_it, &counter);
2133 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2134 "Found %u zone files\n",
2137 /* Loading database plugin */
2139 GNUNET_CONFIGURATION_get_value_string (cfg, "namestore", "database",
2141 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
2143 GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", database);
2144 GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg);
2145 GNUNET_free (database);
2146 if (NULL == GSN_database)
2148 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2149 "Could not load database backend `%s'\n",
2151 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
2155 /* Configuring server handles */
2156 GNUNET_SERVER_add_handlers (server, handlers);
2157 snc = GNUNET_SERVER_notification_context_create (server, 16);
2158 GNUNET_SERVER_disconnect_notify (server,
2159 &client_disconnect_notification,
2161 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
2167 * The main function for the template service.
2169 * @param argc number of arguments from the command line
2170 * @param argv command line arguments
2171 * @return 0 ok, 1 on error
2174 main (int argc, char *const *argv)
2176 return (GNUNET_OK ==
2177 GNUNET_SERVICE_run (argc, argv, "namestore",
2178 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
2181 /* end of gnunet-service-namestore.c */