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)
38 * A namestore operation.
40 struct GNUNET_NAMESTORE_ZoneIteration
43 * Next element in the DLL
45 struct GNUNET_NAMESTORE_ZoneIteration *next;
48 * Previous element in the DLL
50 struct GNUNET_NAMESTORE_ZoneIteration *prev;
53 * Namestore client which intiated this zone iteration
55 struct GNUNET_NAMESTORE_Client *client;
58 * GNUNET_YES if we iterate over a specific zone
59 * GNUNET_NO if we iterate over all zones
64 * Hash of the specific zone if 'has_zone' is GNUNET_YES,
65 * othwerwise set to '\0'
67 struct GNUNET_CRYPTO_ShortHashCode zone;
70 * The operation id fot the zone iteration in the response for the client
75 * Offset of the zone iteration used to address next result of the zone
76 * iteration in the store
78 * Initialy set to 0 in handle_iteration_start
79 * Incremented with by every call to handle_iteration_next
84 * Which flags must be included
86 uint16_t must_have_flags;
89 * Which flags must not be included
91 uint16_t must_not_have_flags;
98 struct GNUNET_NAMESTORE_Client
101 * Next element in the DLL
103 struct GNUNET_NAMESTORE_Client *next;
106 * Previous element in the DLL
108 struct GNUNET_NAMESTORE_Client *prev;
113 struct GNUNET_SERVER_Client *client;
117 * Zone iteration operations in progress initiated by this client
119 struct GNUNET_NAMESTORE_ZoneIteration *op_head;
123 * Zone iteration operations in progress initiated by this client
125 struct GNUNET_NAMESTORE_ZoneIteration *op_tail;
130 * A container struct to store information belonging to a zone crypto key pair
132 struct GNUNET_NAMESTORE_CryptoContainer
135 * Filename where to store the container
140 * Short hash of the zone's public key
142 struct GNUNET_CRYPTO_ShortHashCode zone;
147 struct GNUNET_CRYPTO_EccPrivateKey *privkey;
153 * Configuration handle.
155 static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
160 static struct GNUNET_NAMESTORE_PluginFunctions *GSN_database;
165 static char *zonefile_directory;
168 * Name of the database plugin
170 static char *db_lib_name;
173 * Our notification context.
175 static struct GNUNET_SERVER_NotificationContext *snc;
178 * Head of the Client DLL
180 static struct GNUNET_NAMESTORE_Client *client_head;
183 * Tail of the Client DLL
185 static struct GNUNET_NAMESTORE_Client *client_tail;
188 * Hashmap containing the zone keys this namestore has is authoritative for
190 * Keys are the GNUNET_CRYPTO_HashCode of the GNUNET_CRYPTO_ShortHashCode
191 * The values are 'struct GNUNET_NAMESTORE_CryptoContainer *'
193 static struct GNUNET_CONTAINER_MultiHashMap *zonekeys;
196 * DLL head for key loading contexts
198 static struct KeyLoadContext *kl_head;
201 * DLL tail for key loading contexts
203 static struct KeyLoadContext *kl_tail;
205 struct KeyLoadContext
207 struct KeyLoadContext *next;
208 struct KeyLoadContext *prev;
209 struct GNUNET_CRYPTO_EccKeyGenerationContext *keygen;
211 unsigned int *counter;
216 * Writes the encrypted private key of a zone in a file
218 * @param filename where to store the zone
219 * @param c the crypto container containing private key of the zone
220 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
223 write_key_to_file (const char *filename,
224 struct GNUNET_NAMESTORE_CryptoContainer *c)
226 struct GNUNET_CRYPTO_EccPrivateKey *ret = c->privkey;
227 struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *enc;
228 struct GNUNET_DISK_FileHandle *fd;
229 struct GNUNET_CRYPTO_ShortHashCode zone;
230 struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded pubkey;
231 struct GNUNET_CRYPTO_EccPrivateKey *privkey;
233 fd = GNUNET_DISK_file_open (filename,
234 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_FAILIFEXISTS,
235 GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
236 if ( (NULL == fd) && (EEXIST == errno) )
238 privkey = GNUNET_CRYPTO_ecc_key_create_from_file (filename);
241 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
242 _("Failed to write zone key to file `%s': %s\n"),
244 _("file exists but reading key failed"));
245 return GNUNET_SYSERR;
247 GNUNET_CRYPTO_ecc_key_get_public (privkey, &pubkey);
248 GNUNET_CRYPTO_short_hash (&pubkey, sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded), &zone);
249 GNUNET_CRYPTO_ecc_key_free (privkey);
250 if (0 == memcmp (&zone, &c->zone, sizeof(zone)))
252 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
253 "File zone `%s' containing this key already exists\n",
254 GNUNET_NAMESTORE_short_h2s (&zone));
257 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
258 _("Failed to write zone key to file `%s': %s\n"),
260 _("file exists with different key"));
265 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
266 return GNUNET_SYSERR;
268 if (GNUNET_YES != GNUNET_DISK_file_lock (fd, 0, sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded), GNUNET_YES))
270 GNUNET_break (GNUNET_YES == GNUNET_DISK_file_close (fd));
271 return GNUNET_SYSERR;
273 enc = GNUNET_CRYPTO_ecc_encode_key (ret);
274 GNUNET_assert (NULL != enc);
275 GNUNET_assert (ntohs (enc->size) == GNUNET_DISK_file_write (fd, enc, ntohs (enc->size)));
277 GNUNET_DISK_file_sync (fd);
278 if (GNUNET_YES != GNUNET_DISK_file_unlock (fd, 0, sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded)))
279 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
280 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
281 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
282 "Stored zonekey for zone `%s' in file `%s'\n",
283 GNUNET_NAMESTORE_short_h2s(&c->zone), c->filename);
289 * Write allthe given zone key to disk and then removes the entry from the
290 * 'zonekeys' hash map.
293 * @param key zone key
294 * @param value 'struct GNUNET_NAMESTORE_CryptoContainer' containing the private
296 * @return GNUNET_OK to continue iteration
299 zone_to_disk_it (void *cls,
300 const struct GNUNET_HashCode *key,
303 struct GNUNET_NAMESTORE_CryptoContainer *c = value;
305 if (NULL == c->filename)
306 GNUNET_asprintf(&c->filename,
309 GNUNET_NAMESTORE_short_h2s (&c->zone));
310 (void) write_key_to_file(c->filename, c);
311 GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (zonekeys, key, value));
312 GNUNET_CRYPTO_ecc_key_free (c->privkey);
313 GNUNET_free (c->filename);
320 * Add the given private key to the set of private keys
321 * this namestore can use to sign records when needed.
323 * @param pkey private key to add to our list (reference will
324 * be taken over or freed and should not be used afterwards)
327 learn_private_key (struct GNUNET_CRYPTO_EccPrivateKey *pkey)
329 struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded pub;
330 struct GNUNET_HashCode long_hash;
331 struct GNUNET_CRYPTO_ShortHashCode pubkey_hash;
332 struct GNUNET_NAMESTORE_CryptoContainer *cc;
334 GNUNET_CRYPTO_ecc_key_get_public (pkey, &pub);
335 GNUNET_CRYPTO_short_hash (&pub,
336 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
338 GNUNET_CRYPTO_short_hash_double (&pubkey_hash, &long_hash);
340 if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains(zonekeys, &long_hash))
342 GNUNET_CRYPTO_ecc_key_free (pkey);
345 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
346 "Received new private key for zone `%s'\n",
347 GNUNET_NAMESTORE_short_h2s(&pubkey_hash));
348 cc = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_CryptoContainer));
350 cc->zone = pubkey_hash;
351 GNUNET_assert (GNUNET_YES ==
352 GNUNET_CONTAINER_multihashmap_put(zonekeys, &long_hash, cc,
353 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
358 * Returns the expiration time of the given block of records. The block
359 * expiration time is the expiration time of the block with smallest
362 * @param rd_count number of records given in 'rd'
363 * @param rd array of records
364 * @return absolute expiration time
366 static struct GNUNET_TIME_Absolute
367 get_block_expiration_time (unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd)
370 struct GNUNET_TIME_Absolute expire;
371 struct GNUNET_TIME_Absolute at;
372 struct GNUNET_TIME_Relative rt;
375 return GNUNET_TIME_UNIT_ZERO_ABS;
376 expire = GNUNET_TIME_UNIT_FOREVER_ABS;
377 for (c = 0; c < rd_count; c++)
379 if (0 != (rd[c].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION))
381 rt.rel_value = rd[c].expiration_time;
382 at = GNUNET_TIME_relative_to_absolute (rt);
386 at.abs_value = rd[c].expiration_time;
388 expire = GNUNET_TIME_absolute_min (at, expire);
395 * Task run during shutdown.
401 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
403 struct GNUNET_NAMESTORE_ZoneIteration *no;
404 struct GNUNET_NAMESTORE_Client *nc;
405 struct KeyLoadContext *kl;
407 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping namestore service\n");
410 GNUNET_SERVER_notification_context_destroy (snc);
414 while (NULL != (kl = kl_head))
416 GNUNET_CONTAINER_DLL_remove (kl_head, kl_tail, kl);
417 if (NULL != kl->keygen)
418 GNUNET_CRYPTO_ecc_key_create_stop (kl->keygen);
419 GNUNET_free (kl->filename);
423 GNUNET_CONTAINER_multihashmap_iterate (zonekeys, &zone_to_disk_it, NULL);
424 GNUNET_CONTAINER_multihashmap_destroy (zonekeys);
426 while (NULL != (nc = client_head))
428 while (NULL != (no = nc->op_head))
430 GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no);
433 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
436 GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, GSN_database));
437 GNUNET_free (db_lib_name);
439 GNUNET_free_non_null (zonefile_directory);
440 zonefile_directory = NULL;
445 * Lookup our internal data structure for a given client.
447 * @param client server client handle to use for the lookup
448 * @return our internal structure for the client, NULL if
449 * we do not have any yet
451 static struct GNUNET_NAMESTORE_Client *
452 client_lookup (struct GNUNET_SERVER_Client *client)
454 struct GNUNET_NAMESTORE_Client *nc;
456 GNUNET_assert (NULL != client);
457 for (nc = client_head; NULL != nc; nc = nc->next)
458 if (client == nc->client)
465 * Called whenever a client is disconnected.
466 * Frees our resources associated with that client.
469 * @param client identification of the client
472 client_disconnect_notification (void *cls,
473 struct GNUNET_SERVER_Client *client)
475 struct GNUNET_NAMESTORE_ZoneIteration *no;
476 struct GNUNET_NAMESTORE_Client *nc;
480 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
481 "Client %p disconnected\n",
483 if (NULL == (nc = client_lookup (client)))
485 while (NULL != (no = nc->op_head))
487 GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no);
490 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
496 * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_START' message
499 * @param client GNUNET_SERVER_Client sending the message
500 * @param message unused
503 handle_start (void *cls,
504 struct GNUNET_SERVER_Client *client,
505 const struct GNUNET_MessageHeader *message)
507 struct GNUNET_NAMESTORE_Client *nc;
509 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
510 "Client %p connected\n", client);
511 if (NULL != client_lookup (client))
514 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
517 nc = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Client));
519 GNUNET_SERVER_notification_context_add (snc, client);
520 GNUNET_CONTAINER_DLL_insert (client_head, client_tail, nc);
521 GNUNET_SERVER_receive_done (client, GNUNET_OK);
526 * Context for name lookups passed from 'handle_lookup_name' to
527 * 'handle_lookup_name_it' as closure
529 struct LookupNameContext
532 * The client to send the response to
534 struct GNUNET_NAMESTORE_Client *nc;
539 const struct GNUNET_CRYPTO_ShortHashCode *zone;
547 * Operation id for the name lookup
552 * Requested specific record type
554 uint32_t record_type;
559 * A 'GNUNET_NAMESTORE_RecordIterator' for name lookups in handle_lookup_name
561 * @param cls a 'struct LookupNameContext *' with information about the request
562 * @param zone_key zone key of the zone
563 * @param expire expiration time
565 * @param rd_count number of records
566 * @param rd array of records
567 * @param signature signature
570 handle_lookup_name_it (void *cls,
571 const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *zone_key,
572 struct GNUNET_TIME_Absolute expire,
574 unsigned int rd_count,
575 const struct GNUNET_NAMESTORE_RecordData *rd,
576 const struct GNUNET_CRYPTO_EccSignature *signature)
578 struct LookupNameContext *lnc = cls;
579 struct LookupNameResponseMessage *lnr_msg;
580 struct GNUNET_NAMESTORE_RecordData *rd_selected;
581 struct GNUNET_NAMESTORE_CryptoContainer *cc;
582 struct GNUNET_CRYPTO_EccSignature *signature_new;
583 struct GNUNET_TIME_Absolute e;
584 struct GNUNET_TIME_Relative re;
585 struct GNUNET_CRYPTO_ShortHashCode zone_key_hash;
586 struct GNUNET_HashCode long_hash;
593 int contains_signature;
598 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
599 "Found %u records under name `%s'\n",
602 authoritative = GNUNET_NO;
603 signature_new = NULL;
605 if (NULL != zone_key)
607 GNUNET_CRYPTO_short_hash (zone_key,
608 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
610 GNUNET_CRYPTO_short_hash_double (&zone_key_hash, &long_hash);
611 if (NULL != (cc = GNUNET_CONTAINER_multihashmap_get (zonekeys, &long_hash)))
613 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
614 "Am authoritative for zone `%s'\n",
615 GNUNET_NAMESTORE_short_h2s (&zone_key_hash));
616 authoritative = GNUNET_YES;
621 rd_modified = GNUNET_NO;
623 /* count records to copy */
624 for (c = 0; c < rd_count; c++)
626 if ( (GNUNET_YES == authoritative) &&
628 GNUNET_NAMESTORE_is_expired (&rd[c]) ) )
630 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
631 "Skipping expired record\n");
634 if ( (GNUNET_NAMESTORE_TYPE_ANY == lnc->record_type) ||
635 (rd[c].record_type == lnc->record_type) )
636 copied_elements++; /* found matching record */
639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
640 "Skipping non-mtaching record\n");
641 rd_modified = GNUNET_YES;
644 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
645 "Found %u records with type %u for name `%s' in zone `%s'\n",
649 GNUNET_NAMESTORE_short_h2s(lnc->zone));
650 if (copied_elements > 0)
652 rd_selected = GNUNET_malloc (copied_elements * sizeof (struct GNUNET_NAMESTORE_RecordData));
654 for (c = 0; c < rd_count; c++)
656 if ( (GNUNET_YES == authoritative) &&
658 GNUNET_NAMESTORE_is_expired (&rd[c])) )
660 if ( (GNUNET_NAMESTORE_TYPE_ANY == lnc->record_type) ||
661 (rd[c].record_type == lnc->record_type) )
663 if (0 != (rd[c].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION))
665 GNUNET_break (GNUNET_YES == authoritative);
666 rd_modified = GNUNET_YES;
667 re.rel_value = rd[c].expiration_time;
668 e = GNUNET_TIME_relative_to_absolute (re);
672 e.abs_value = rd[c].expiration_time;
674 /* found matching record, copy and convert flags to public format */
675 rd_selected[copied_elements] = rd[c]; /* shallow copy! */
676 rd_selected[copied_elements].expiration_time = e.abs_value;
677 if (0 != (rd_selected[copied_elements].flags &
678 (GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION | GNUNET_NAMESTORE_RF_AUTHORITY)))
680 rd_selected[copied_elements].flags &= ~ (GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION |
681 GNUNET_NAMESTORE_RF_AUTHORITY);
682 rd_modified = GNUNET_YES;
688 rd_modified = GNUNET_YES;
695 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
696 "Found %u matching records for name `%s' in zone `%s'\n",
699 GNUNET_NAMESTORE_short_h2s (lnc->zone));
700 contains_signature = GNUNET_NO;
701 if (copied_elements > 0)
703 if (GNUNET_YES == authoritative)
705 GNUNET_assert (NULL != cc);
706 e = get_block_expiration_time (rd_count, rd);
707 signature_new = GNUNET_NAMESTORE_create_signature (cc->privkey, e, name, rd_selected, copied_elements);
708 GNUNET_assert (NULL != signature_new);
709 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
710 "Creating signature for name `%s' with %u records in zone `%s'\n",
713 GNUNET_NAMESTORE_short_h2s(&zone_key_hash));
717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
718 "Not authoritative, records modified is %d, have sig is %d\n",
721 if ((GNUNET_NO == rd_modified) && (NULL != signature))
722 contains_signature = GNUNET_YES; /* returning all records, so include signature */
726 rd_ser_len = GNUNET_NAMESTORE_records_get_size (copied_elements, rd_selected);
727 name_len = (NULL == name) ? 0 : strlen(name) + 1;
728 r_size = sizeof (struct LookupNameResponseMessage) +
729 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded) +
732 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
733 "Sending `%s' message\n",
734 "NAMESTORE_LOOKUP_NAME_RESPONSE");
735 lnr_msg = GNUNET_malloc (r_size);
736 lnr_msg->gns_header.header.type = ntohs (GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE);
737 lnr_msg->gns_header.header.size = ntohs (r_size);
738 lnr_msg->gns_header.r_id = htonl (lnc->request_id);
739 lnr_msg->rd_count = htons (copied_elements);
740 lnr_msg->rd_len = htons (rd_ser_len);
741 lnr_msg->name_len = htons (name_len);
742 lnr_msg->expire = GNUNET_TIME_absolute_hton (get_block_expiration_time (copied_elements,
744 name_tmp = (char *) &lnr_msg[1];
745 memcpy (name_tmp, name, name_len);
746 rd_tmp = &name_tmp[name_len];
747 GNUNET_NAMESTORE_records_serialize (copied_elements, rd_selected, rd_ser_len, rd_tmp);
748 if (rd_selected != rd)
749 GNUNET_free_non_null (rd_selected);
750 if (NULL != zone_key)
751 lnr_msg->public_key = *zone_key;
752 if ( (GNUNET_YES == authoritative) &&
753 (copied_elements > 0) )
755 /* use new created signature */
756 lnr_msg->contains_sig = htons (GNUNET_YES);
757 GNUNET_assert (NULL != signature_new);
758 lnr_msg->signature = *signature_new;
759 GNUNET_free (signature_new);
761 else if (GNUNET_YES == contains_signature)
763 /* use existing signature */
764 lnr_msg->contains_sig = htons (GNUNET_YES);
765 GNUNET_assert (NULL != signature);
766 lnr_msg->signature = *signature;
768 GNUNET_SERVER_notification_context_unicast (snc, lnc->nc->client,
769 &lnr_msg->gns_header.header,
771 GNUNET_free (lnr_msg);
776 * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME' message
779 * @param client GNUNET_SERVER_Client sending the message
780 * @param message message of type 'struct LookupNameMessage'
783 handle_lookup_name (void *cls,
784 struct GNUNET_SERVER_Client *client,
785 const struct GNUNET_MessageHeader *message)
787 const struct LookupNameMessage *ln_msg;
788 struct LookupNameContext lnc;
789 struct GNUNET_NAMESTORE_Client *nc;
796 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
797 "Received `%s' message\n",
798 "NAMESTORE_LOOKUP_NAME");
799 if (ntohs (message->size) < sizeof (struct LookupNameMessage))
802 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
805 if (NULL == (nc = client_lookup(client)))
808 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
811 ln_msg = (const struct LookupNameMessage *) message;
812 rid = ntohl (ln_msg->gns_header.r_id);
813 name_len = ntohl (ln_msg->name_len);
814 type = ntohl (ln_msg->record_type);
815 if ((0 == name_len) || (name_len > MAX_NAME_LEN))
818 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
821 name = (const char *) &ln_msg[1];
822 if ('\0' != name[name_len -1])
825 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
828 if (GNUNET_NAMESTORE_TYPE_ANY == type)
829 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
830 "Looking up all records for name `%s' in zone `%s'\n",
832 GNUNET_NAMESTORE_short_h2s(&ln_msg->zone));
834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
835 "Looking up records with type %u for name `%s' in zone `%s'\n",
837 GNUNET_NAMESTORE_short_h2s(&ln_msg->zone));
839 conv_name = GNUNET_NAMESTORE_normalize_string (name);
840 if (NULL == conv_name)
842 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
843 "Error converting name `%s'\n", name);
847 /* do the actual lookup */
848 lnc.request_id = rid;
850 lnc.record_type = type;
851 lnc.name = conv_name;
852 lnc.zone = &ln_msg->zone;
854 GSN_database->iterate_records (GSN_database->cls,
855 &ln_msg->zone, conv_name, 0 /* offset */,
856 &handle_lookup_name_it, &lnc))
858 /* internal error (in database plugin); might be best to just hang up on
859 plugin rather than to signal that there are 'no' results, which
860 might also be false... */
862 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
863 GNUNET_free (conv_name);
866 GNUNET_free (conv_name);
867 GNUNET_SERVER_receive_done (client, GNUNET_OK);
872 * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT' message
875 * @param client GNUNET_SERVER_Client sending the message
876 * @param message message of type 'struct RecordPutMessage'
879 handle_record_put (void *cls,
880 struct GNUNET_SERVER_Client *client,
881 const struct GNUNET_MessageHeader *message)
883 struct GNUNET_NAMESTORE_Client *nc;
884 const struct RecordPutMessage *rp_msg;
885 struct GNUNET_TIME_Absolute expire;
886 const struct GNUNET_CRYPTO_EccSignature *signature;
887 struct RecordPutResponseMessage rpr_msg;
888 struct GNUNET_CRYPTO_ShortHashCode zone_hash;
900 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
901 "Received `%s' message\n",
902 "NAMESTORE_RECORD_PUT");
903 if (ntohs (message->size) < sizeof (struct RecordPutMessage))
906 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
909 if (NULL == (nc = client_lookup (client)))
912 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
915 rp_msg = (const struct RecordPutMessage *) message;
916 rid = ntohl (rp_msg->gns_header.r_id);
917 msg_size = ntohs (rp_msg->gns_header.header.size);
918 name_len = ntohs (rp_msg->name_len);
919 rd_count = ntohs (rp_msg->rd_count);
920 rd_ser_len = ntohs (rp_msg->rd_len);
921 if ((rd_count < 1) || (rd_ser_len < 1) || (name_len >= MAX_NAME_LEN) || (0 == name_len))
924 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
927 msg_size_exp = sizeof (struct RecordPutMessage) + name_len + rd_ser_len;
928 if (msg_size != msg_size_exp)
931 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
934 name = (const char *) &rp_msg[1];
935 if ('\0' != name[name_len -1])
938 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
941 expire = GNUNET_TIME_absolute_ntoh (rp_msg->expire);
942 signature = &rp_msg->signature;
943 rd_ser = &name[name_len];
944 struct GNUNET_NAMESTORE_RecordData rd[rd_count];
947 GNUNET_NAMESTORE_records_deserialize (rd_ser_len, rd_ser, rd_count, rd))
950 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
953 GNUNET_CRYPTO_short_hash (&rp_msg->public_key,
954 sizeof (rp_msg->public_key),
957 conv_name = GNUNET_NAMESTORE_normalize_string (name);
958 if (NULL == conv_name)
960 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
961 "Error converting name `%s'\n", name);
965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
966 "Putting %u records under name `%s' in zone `%s'\n",
968 GNUNET_NAMESTORE_short_h2s (&zone_hash));
969 res = GSN_database->put_records(GSN_database->cls,
975 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
976 "Putting record for name `%s': %s\n",
978 (GNUNET_OK == res) ? "OK" : "FAILED");
979 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
980 "Sending `%s' message\n",
981 "RECORD_PUT_RESPONSE");
982 GNUNET_free (conv_name);
983 rpr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT_RESPONSE);
984 rpr_msg.gns_header.header.size = htons (sizeof (struct RecordPutResponseMessage));
985 rpr_msg.gns_header.r_id = htonl (rid);
986 rpr_msg.op_result = htonl (res);
987 GNUNET_SERVER_notification_context_unicast (snc,
989 &rpr_msg.gns_header.header,
991 GNUNET_SERVER_receive_done (client, GNUNET_OK);
996 * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE' message
999 * @param client GNUNET_SERVER_Client sending the message
1000 * @param message message of type 'struct RecordCreateMessage'
1003 handle_record_create (void *cls,
1004 struct GNUNET_SERVER_Client *client,
1005 const struct GNUNET_MessageHeader *message)
1007 static struct GNUNET_CRYPTO_EccSignature dummy_signature;
1008 struct GNUNET_NAMESTORE_Client *nc;
1009 const struct RecordCreateMessage *rp_msg;
1010 struct GNUNET_CRYPTO_EccPrivateKey *pkey;
1011 struct RecordCreateResponseMessage rcr_msg;
1014 size_t msg_size_exp;
1018 const char *pkey_tmp;
1019 const char *name_tmp;
1022 unsigned int rd_count;
1024 struct GNUNET_CRYPTO_ShortHashCode pubkey_hash;
1025 struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded pubkey;
1027 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1028 "Received `%s' message\n", "NAMESTORE_RECORD_CREATE");
1029 if (ntohs (message->size) < sizeof (struct RecordCreateMessage))
1032 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1035 if (NULL == (nc = client_lookup (client)))
1038 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1041 rp_msg = (const struct RecordCreateMessage *) message;
1042 rid = ntohl (rp_msg->gns_header.r_id);
1043 name_len = ntohs (rp_msg->name_len);
1044 msg_size = ntohs (message->size);
1045 rd_count = ntohs (rp_msg->rd_count);
1046 rd_ser_len = ntohs (rp_msg->rd_len);
1047 key_len = ntohs (rp_msg->pkey_len);
1048 msg_size_exp = sizeof (struct RecordCreateMessage) + key_len + name_len + rd_ser_len;
1049 if (msg_size != msg_size_exp)
1052 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1055 if ((0 == name_len) || (name_len > MAX_NAME_LEN))
1058 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1061 pkey_tmp = (const char *) &rp_msg[1];
1062 name_tmp = &pkey_tmp[key_len];
1063 rd_ser = &name_tmp[name_len];
1064 if ('\0' != name_tmp[name_len -1])
1067 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1070 if (NULL == (pkey = GNUNET_CRYPTO_ecc_decode_key (pkey_tmp, key_len,
1074 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1078 struct GNUNET_NAMESTORE_RecordData rd[rd_count];
1081 GNUNET_NAMESTORE_records_deserialize (rd_ser_len, rd_ser, rd_count, rd))
1084 GNUNET_CRYPTO_ecc_key_free (pkey);
1085 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1089 /* Extracting and converting private key */
1090 GNUNET_CRYPTO_ecc_key_get_public (pkey, &pubkey);
1091 GNUNET_CRYPTO_short_hash (&pubkey,
1092 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
1094 learn_private_key (pkey);
1095 conv_name = GNUNET_NAMESTORE_normalize_string (name_tmp);
1096 if (NULL == conv_name)
1098 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1099 "Error converting name `%s'\n", name_tmp);
1100 GNUNET_CRYPTO_ecc_key_free (pkey);
1101 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1104 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1105 "Creating %u records for name `%s' in zone `%s'\n",
1106 (unsigned int) rd_count,
1108 GNUNET_NAMESTORE_short_h2s (&pubkey_hash));
1110 res = GSN_database->remove_records (GSN_database->cls,
1114 res = GSN_database->put_records (GSN_database->cls,
1116 GNUNET_TIME_absolute_ntoh(rp_msg->expire),
1120 GNUNET_free (conv_name);
1124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1125 "Sending `%s' message\n", "RECORD_CREATE_RESPONSE");
1126 rcr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE_RESPONSE);
1127 rcr_msg.gns_header.header.size = htons (sizeof (struct RecordCreateResponseMessage));
1128 rcr_msg.gns_header.r_id = htonl (rid);
1129 rcr_msg.op_result = htonl (res);
1130 GNUNET_SERVER_notification_context_unicast (snc, nc->client,
1131 &rcr_msg.gns_header.header,
1133 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1138 * Context for record remove operations passed from 'handle_zone_to_name' to
1139 * 'handle_zone_to_name_it' as closure
1141 struct ZoneToNameCtx
1146 struct GNUNET_NAMESTORE_Client *nc;
1149 * Request id (to be used in the response to the client).
1154 * Set to GNUNET_OK on success, GNUNET_SYSERR on error. Note that
1155 * not finding a name for the zone still counts as a 'success' here,
1156 * as this field is about the success of executing the IPC protocol.
1163 * Zone to name iterator
1165 * @param cls struct ZoneToNameCtx *
1166 * @param zone_key the zone key
1167 * @param expire expiration date
1169 * @param rd_count number of records
1170 * @param rd record data
1171 * @param signature signature
1174 handle_zone_to_name_it (void *cls,
1175 const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *zone_key,
1176 struct GNUNET_TIME_Absolute expire,
1178 unsigned int rd_count,
1179 const struct GNUNET_NAMESTORE_RecordData *rd,
1180 const struct GNUNET_CRYPTO_EccSignature *signature)
1182 struct ZoneToNameCtx *ztn_ctx = cls;
1183 struct ZoneToNameResponseMessage *ztnr_msg;
1192 if ((NULL != zone_key) && (NULL != name))
1195 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1196 "Found result: name `%s' has %u records\n",
1199 name_len = strlen (name) + 1;
1203 /* no result found */
1204 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1205 "Found no results\n");
1209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1210 "Sending `%s' message\n",
1211 "ZONE_TO_NAME_RESPONSE");
1212 rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
1213 msg_size = sizeof (struct ZoneToNameResponseMessage) + name_len + rd_ser_len;
1214 if (NULL != signature)
1215 msg_size += sizeof (struct GNUNET_CRYPTO_EccSignature);
1216 if (msg_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1219 ztn_ctx->success = GNUNET_SYSERR;
1222 ztnr_msg = GNUNET_malloc (msg_size);
1223 ztnr_msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE);
1224 ztnr_msg->gns_header.header.size = htons (msg_size);
1225 ztnr_msg->gns_header.r_id = htonl (ztn_ctx->rid);
1226 ztnr_msg->res = htons (res);
1227 ztnr_msg->rd_len = htons (rd_ser_len);
1228 ztnr_msg->rd_count = htons (rd_count);
1229 ztnr_msg->name_len = htons (name_len);
1230 ztnr_msg->expire = GNUNET_TIME_absolute_hton (expire);
1231 if (NULL != zone_key)
1232 ztnr_msg->zone_key = *zone_key;
1233 name_tmp = (char *) &ztnr_msg[1];
1235 memcpy (name_tmp, name, name_len);
1236 rd_tmp = &name_tmp[name_len];
1237 GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_tmp);
1238 sig_tmp = &rd_tmp[rd_ser_len];
1239 if (NULL != signature)
1240 memcpy (sig_tmp, signature, sizeof (struct GNUNET_CRYPTO_EccSignature));
1241 ztn_ctx->success = GNUNET_OK;
1242 GNUNET_SERVER_notification_context_unicast (snc, ztn_ctx->nc->client,
1243 &ztnr_msg->gns_header.header,
1245 GNUNET_free (ztnr_msg);
1250 * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME' message
1253 * @param client GNUNET_SERVER_Client sending the message
1254 * @param message message of type 'struct ZoneToNameMessage'
1257 handle_zone_to_name (void *cls,
1258 struct GNUNET_SERVER_Client *client,
1259 const struct GNUNET_MessageHeader *message)
1261 struct GNUNET_NAMESTORE_Client *nc;
1262 const struct ZoneToNameMessage *ztn_msg;
1263 struct ZoneToNameCtx ztn_ctx;
1265 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1266 "Received `%s' message\n",
1268 ztn_msg = (const struct ZoneToNameMessage *) message;
1269 if (NULL == (nc = client_lookup(client)))
1272 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1275 ztn_ctx.rid = ntohl (ztn_msg->gns_header.r_id);
1277 ztn_ctx.success = GNUNET_SYSERR;
1278 if (GNUNET_SYSERR ==
1279 GSN_database->zone_to_name (GSN_database->cls,
1281 &ztn_msg->value_zone,
1282 &handle_zone_to_name_it, &ztn_ctx))
1284 /* internal error, hang up instead of signalling something
1285 that might be wrong */
1287 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1290 GNUNET_SERVER_receive_done (client, ztn_ctx.success);
1295 * Zone iteration processor result
1297 enum ZoneIterationResult
1300 * Found records, but all records were filtered
1301 * Continue to iterate
1303 IT_ALL_RECORDS_FILTERED = -1,
1307 * Continue to iterate with next iteration_next call
1309 IT_SUCCESS_MORE_AVAILABLE = 0,
1312 * Iteration complete
1314 IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE = 1
1319 * Context for record remove operations passed from
1320 * 'run_zone_iteration_round' to 'zone_iteraterate_proc' as closure
1322 struct ZoneIterationProcResult
1325 * The zone iteration handle
1327 struct GNUNET_NAMESTORE_ZoneIteration *zi;
1330 * Iteration result: iteration done?
1331 * IT_SUCCESS_MORE_AVAILABLE: if there may be more results overall but
1332 * we got one for now and have sent it to the client
1333 * IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE: if there are no further results,
1334 * IT_ALL_RECORDS_FILTERED: if all results were filtered so far.
1336 int res_iteration_finished;
1342 * Process results for zone iteration from database
1344 * @param cls struct ZoneIterationProcResult *proc
1345 * @param zone_key the zone key
1346 * @param expire expiration time
1348 * @param rd_count number of records for this name
1349 * @param rd record data
1350 * @param signature block signature
1353 zone_iteraterate_proc (void *cls,
1354 const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *zone_key,
1355 struct GNUNET_TIME_Absolute expire,
1357 unsigned int rd_count,
1358 const struct GNUNET_NAMESTORE_RecordData *rd,
1359 const struct GNUNET_CRYPTO_EccSignature *signature)
1361 struct ZoneIterationProcResult *proc = cls;
1362 struct GNUNET_NAMESTORE_RecordData rd_filtered[rd_count];
1363 struct GNUNET_CRYPTO_EccSignature *new_signature = NULL;
1364 struct GNUNET_NAMESTORE_CryptoContainer *cc;
1365 struct GNUNET_HashCode long_hash;
1366 struct GNUNET_CRYPTO_ShortHashCode zone_hash;
1367 struct ZoneIterationResponseMessage *zir_msg;
1368 struct GNUNET_TIME_Relative rt;
1369 unsigned int rd_count_filtered;
1377 proc->res_iteration_finished = IT_SUCCESS_MORE_AVAILABLE;
1378 if ((NULL == zone_key) && (NULL == name))
1380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1381 "Iteration done\n");
1382 proc->res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE;
1385 if ((NULL == zone_key) || (NULL == name))
1387 /* what is this!? should never happen */
1391 rd_count_filtered = 0;
1392 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1393 "Received result for zone iteration: `%s'\n",
1395 for (c = 0; c < rd_count; c++)
1397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1398 "Record %u has flags: %x must have flags are %x, must not have flags are %x\n",
1400 proc->zi->must_have_flags,
1401 proc->zi->must_not_have_flags);
1402 /* Checking must have flags, except 'relative-expiration' which is a special flag */
1403 if ((rd[c].flags & proc->zi->must_have_flags & (~GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION))
1404 != (proc->zi->must_have_flags & (~ GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION)))
1406 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %u lacks 'must-have' flags: Not included\n", c);
1409 /* Checking must-not-have flags */
1410 if (0 != (rd[c].flags & proc->zi->must_not_have_flags))
1412 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1413 "Record %u has 'must-not-have' flags: Not included\n", c);
1416 rd_filtered[rd_count_filtered] = rd[c];
1417 /* convert relative to absolute expiration time unless explicitly requested otherwise */
1418 if ( (0 == (proc->zi->must_have_flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION)) &&
1419 (0 != (rd[c].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION)) )
1421 /* should convert relative-to-absolute expiration time */
1422 rt.rel_value = rd[c].expiration_time;
1423 rd_filtered[c].expiration_time = GNUNET_TIME_relative_to_absolute (rt).abs_value;
1424 rd_filtered[c].flags &= ~ GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION;
1426 /* we NEVER keep the 'authority' flag */
1427 rd_filtered[c].flags &= ~ GNUNET_NAMESTORE_RF_AUTHORITY;
1428 rd_count_filtered++;
1430 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1431 "Included %u of %u records\n",
1432 rd_count_filtered, rd_count);
1435 if ( (rd_count_filtered > 0) &&
1436 (0 == (proc->zi->must_have_flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION)) )
1438 /* compute / obtain signature, but only if we (a) have records and (b) expiration times were
1439 converted to absolute expiration times */
1440 GNUNET_CRYPTO_short_hash (zone_key,
1441 sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
1443 GNUNET_CRYPTO_short_hash_double (&zone_hash, &long_hash);
1444 if (NULL != (cc = GNUNET_CONTAINER_multihashmap_get(zonekeys, &long_hash)))
1446 expire = get_block_expiration_time (rd_count_filtered, rd_filtered);
1447 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1448 "Creating signature for `%s' in zone `%s' with %u records and expiration %llu\n",
1449 name, GNUNET_NAMESTORE_short_h2s(&zone_hash),
1451 (unsigned long long) expire.abs_value);
1452 new_signature = GNUNET_NAMESTORE_create_signature (cc->privkey, expire, name,
1453 rd_filtered, rd_count_filtered);
1454 GNUNET_assert (NULL != new_signature);
1455 signature = new_signature;
1457 else if (rd_count_filtered == rd_count)
1459 if (NULL != signature)
1461 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1462 "Using provided signature for `%s' in zone `%s' with %u records and expiration %llu\n",
1463 name, GNUNET_NAMESTORE_short_h2s (&zone_hash), rd_count_filtered,
1464 (unsigned long long) expire.abs_value);
1469 if (rd_count_filtered == 0)
1471 /* After filtering records there are no records left to return */
1472 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No records to transmit\n");
1473 proc->res_iteration_finished = IT_ALL_RECORDS_FILTERED;
1477 if (GNUNET_YES == proc->zi->has_zone)
1478 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1479 "Sending name `%s' for iteration over zone `%s'\n",
1480 name, GNUNET_NAMESTORE_short_h2s(&proc->zi->zone));
1482 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1483 "Sending name `%s' for iteration over all zones\n",
1485 name_len = strlen (name) + 1;
1486 rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count_filtered, rd_filtered);
1487 msg_size = sizeof (struct ZoneIterationResponseMessage) + name_len + rd_ser_len;
1489 zir_msg = GNUNET_malloc (msg_size);
1490 zir_msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE);
1491 zir_msg->gns_header.header.size = htons (msg_size);
1492 zir_msg->gns_header.r_id = htonl (proc->zi->request_id);
1493 zir_msg->expire = GNUNET_TIME_absolute_hton (expire);
1494 zir_msg->reserved = htons (0);
1495 zir_msg->name_len = htons (name_len);
1496 zir_msg->rd_count = htons (rd_count_filtered);
1497 zir_msg->rd_len = htons (rd_ser_len);
1498 if (NULL != signature)
1499 zir_msg->signature = *signature;
1500 zir_msg->public_key = *zone_key;
1501 name_tmp = (char *) &zir_msg[1];
1502 memcpy (name_tmp, name, name_len);
1503 rd_ser = &name_tmp[name_len];
1504 GNUNET_NAMESTORE_records_serialize (rd_count_filtered, rd_filtered, rd_ser_len, rd_ser);
1505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1506 "Sending `%s' message with size %u\n",
1507 "ZONE_ITERATION_RESPONSE",
1509 GNUNET_SERVER_notification_context_unicast (snc, proc->zi->client->client,
1510 (const struct GNUNET_MessageHeader *) zir_msg,
1512 proc->res_iteration_finished = IT_SUCCESS_MORE_AVAILABLE;
1513 GNUNET_free (zir_msg);
1514 GNUNET_free_non_null (new_signature);
1519 * Perform the next round of the zone iteration.
1521 * @param zi zone iterator to process
1524 run_zone_iteration_round (struct GNUNET_NAMESTORE_ZoneIteration *zi)
1526 struct ZoneIterationProcResult proc;
1527 struct ZoneIterationResponseMessage zir_end;
1528 struct GNUNET_CRYPTO_ShortHashCode *zone;
1530 memset (&proc, 0, sizeof (proc));
1532 if (GNUNET_YES == zi->has_zone)
1536 proc.res_iteration_finished = IT_ALL_RECORDS_FILTERED;
1537 while (IT_ALL_RECORDS_FILTERED == proc.res_iteration_finished)
1539 if (GNUNET_SYSERR ==
1540 GSN_database->iterate_records (GSN_database->cls, zone, NULL,
1542 &zone_iteraterate_proc, &proc))
1549 if (IT_SUCCESS_MORE_AVAILABLE == proc.res_iteration_finished)
1551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1552 "More results available\n");
1553 return; /* more results later */
1555 if (GNUNET_YES == zi->has_zone)
1556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1557 "No more results for zone `%s'\n",
1558 GNUNET_NAMESTORE_short_h2s(&zi->zone));
1560 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1561 "No more results for all zones\n");
1562 memset (&zir_end, 0, sizeof (zir_end));
1563 zir_end.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE);
1564 zir_end.gns_header.header.size = htons (sizeof (struct ZoneIterationResponseMessage));
1565 zir_end.gns_header.r_id = htonl(zi->request_id);
1566 GNUNET_SERVER_notification_context_unicast (snc,
1568 &zir_end.gns_header.header, GNUNET_NO);
1569 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1570 "Removing zone iterator\n");
1571 GNUNET_CONTAINER_DLL_remove (zi->client->op_head, zi->client->op_tail, zi);
1577 * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START' message
1580 * @param client GNUNET_SERVER_Client sending the message
1581 * @param message message of type 'struct ZoneIterationStartMessage'
1584 handle_iteration_start (void *cls,
1585 struct GNUNET_SERVER_Client *client,
1586 const struct GNUNET_MessageHeader *message)
1588 static struct GNUNET_CRYPTO_ShortHashCode zeros;
1589 const struct ZoneIterationStartMessage *zis_msg;
1590 struct GNUNET_NAMESTORE_Client *nc;
1591 struct GNUNET_NAMESTORE_ZoneIteration *zi;
1593 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_START");
1594 if (NULL == (nc = client_lookup (client)))
1597 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1600 zis_msg = (const struct ZoneIterationStartMessage *) message;
1601 zi = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_ZoneIteration));
1602 zi->request_id = ntohl (zis_msg->gns_header.r_id);
1605 zi->must_have_flags = ntohs (zis_msg->must_have_flags);
1606 zi->must_not_have_flags = ntohs (zis_msg->must_not_have_flags);
1607 if (0 == memcmp (&zeros, &zis_msg->zone, sizeof (zeros)))
1609 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting to iterate over all zones\n");
1610 zi->zone = zis_msg->zone;
1611 zi->has_zone = GNUNET_NO;
1615 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1616 "Starting to iterate over zone `%s'\n", GNUNET_NAMESTORE_short_h2s (&zis_msg->zone));
1617 zi->zone = zis_msg->zone;
1618 zi->has_zone = GNUNET_YES;
1620 GNUNET_CONTAINER_DLL_insert (nc->op_head, nc->op_tail, zi);
1621 run_zone_iteration_round (zi);
1622 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1627 * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP' message
1630 * @param client GNUNET_SERVER_Client sending the message
1631 * @param message message of type 'struct ZoneIterationStopMessage'
1634 handle_iteration_stop (void *cls,
1635 struct GNUNET_SERVER_Client *client,
1636 const struct GNUNET_MessageHeader *message)
1638 struct GNUNET_NAMESTORE_Client *nc;
1639 struct GNUNET_NAMESTORE_ZoneIteration *zi;
1640 const struct ZoneIterationStopMessage *zis_msg;
1643 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1644 "Received `%s' message\n",
1645 "ZONE_ITERATION_STOP");
1646 if (NULL == (nc = client_lookup(client)))
1649 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1652 zis_msg = (const struct ZoneIterationStopMessage *) message;
1653 rid = ntohl (zis_msg->gns_header.r_id);
1654 for (zi = nc->op_head; NULL != zi; zi = zi->next)
1655 if (zi->request_id == rid)
1660 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1663 GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, zi);
1664 if (GNUNET_YES == zi->has_zone)
1665 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1666 "Stopped zone iteration for zone `%s'\n",
1667 GNUNET_NAMESTORE_short_h2s (&zi->zone));
1669 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1670 "Stopped zone iteration over all zones\n");
1672 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1677 * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT' message
1680 * @param client GNUNET_SERVER_Client sending the message
1681 * @param message message of type 'struct ZoneIterationNextMessage'
1684 handle_iteration_next (void *cls,
1685 struct GNUNET_SERVER_Client *client,
1686 const struct GNUNET_MessageHeader *message)
1688 struct GNUNET_NAMESTORE_Client *nc;
1689 struct GNUNET_NAMESTORE_ZoneIteration *zi;
1690 const struct ZoneIterationNextMessage *zis_msg;
1693 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_NEXT");
1694 if (NULL == (nc = client_lookup(client)))
1697 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1700 zis_msg = (const struct ZoneIterationNextMessage *) message;
1701 rid = ntohl (zis_msg->gns_header.r_id);
1702 for (zi = nc->op_head; NULL != zi; zi = zi->next)
1703 if (zi->request_id == rid)
1708 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1711 run_zone_iteration_round (zi);
1712 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1716 zonekey_it_key_cb (void *cls,
1717 struct GNUNET_CRYPTO_EccPrivateKey *pk,
1720 struct KeyLoadContext *kl = cls;
1725 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1726 _("Could not parse zone key file `%s'\n"),
1730 learn_private_key (pk);
1733 GNUNET_CONTAINER_DLL_remove (kl_head, kl_tail, kl);
1734 GNUNET_free (kl->filename);
1740 * Load zone keys from directory by reading all .zkey files in this directory
1742 * @param cls int * 'counter' to store the number of files found
1743 * @param filename directory to scan
1744 * @return GNUNET_OK to continue
1747 zonekey_file_it (void *cls, const char *filename)
1749 struct KeyLoadContext *kl;
1751 if ((NULL == filename) ||
1752 (NULL == strstr(filename, ".zkey")))
1755 kl = GNUNET_malloc (sizeof (struct KeyLoadContext));
1756 kl->filename = strdup (filename);
1758 kl->keygen = GNUNET_CRYPTO_ecc_key_create_start (filename, zonekey_it_key_cb, kl);
1759 if (NULL == kl->keygen)
1761 GNUNET_free (kl->filename);
1766 GNUNET_CONTAINER_DLL_insert (kl_head, kl_tail, kl);
1772 * Process namestore requests.
1774 * @param cls closure
1775 * @param server the initialized server
1776 * @param cfg configuration to use
1779 run (void *cls, struct GNUNET_SERVER_Handle *server,
1780 const struct GNUNET_CONFIGURATION_Handle *cfg)
1782 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1783 {&handle_start, NULL,
1784 GNUNET_MESSAGE_TYPE_NAMESTORE_START, sizeof (struct StartMessage)},
1785 {&handle_lookup_name, NULL,
1786 GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME, 0},
1787 {&handle_record_put, NULL,
1788 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT, 0},
1789 {&handle_record_create, NULL,
1790 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE, 0},
1791 {&handle_zone_to_name, NULL,
1792 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME, sizeof (struct ZoneToNameMessage) },
1793 {&handle_iteration_start, NULL,
1794 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START, sizeof (struct ZoneIterationStartMessage) },
1795 {&handle_iteration_next, NULL,
1796 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT, sizeof (struct ZoneIterationNextMessage) },
1797 {&handle_iteration_stop, NULL,
1798 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP, sizeof (struct ZoneIterationStopMessage) },
1802 unsigned int counter;
1804 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namestore service\n");
1807 /* Load private keys from disk */
1809 GNUNET_CONFIGURATION_get_value_filename (cfg, "namestore",
1810 "zonefile_directory",
1811 &zonefile_directory))
1813 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1814 _("No directory to load zonefiles specified in configuration\n"));
1815 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
1819 if (GNUNET_NO == GNUNET_DISK_file_test (zonefile_directory))
1821 if (GNUNET_SYSERR == GNUNET_DISK_directory_create (zonefile_directory))
1823 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1824 _("Creating directory `%s' for zone files failed!\n"),
1825 zonefile_directory);
1826 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
1829 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1830 "Created directory `%s' for zone files\n",
1831 zonefile_directory);
1834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1835 "Scanning directory `%s' for zone files\n", zonefile_directory);
1836 zonekeys = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO);
1838 GNUNET_DISK_directory_scan (zonefile_directory, zonekey_file_it, &counter);
1839 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1840 "Found %u zone files\n",
1843 /* Loading database plugin */
1845 GNUNET_CONFIGURATION_get_value_string (cfg, "namestore", "database",
1847 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
1849 GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", database);
1850 GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg);
1851 GNUNET_free (database);
1852 if (NULL == GSN_database)
1854 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1855 "Could not load database backend `%s'\n",
1857 GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
1861 /* Configuring server handles */
1862 GNUNET_SERVER_add_handlers (server, handlers);
1863 snc = GNUNET_SERVER_notification_context_create (server, 16);
1864 GNUNET_SERVER_disconnect_notify (server,
1865 &client_disconnect_notification,
1867 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1873 * The main function for the template service.
1875 * @param argc number of arguments from the command line
1876 * @param argv command line arguments
1877 * @return 0 ok, 1 on error
1880 main (int argc, char *const *argv)
1882 return (GNUNET_OK ==
1883 GNUNET_SERVICE_run (argc, argv, "namestore",
1884 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
1887 /* end of gnunet-service-namestore.c */