2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2014 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, 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_gns_service.h"
31 #include "gnunet_namecache_service.h"
32 #include "gnunet_namestore_service.h"
33 #include "gnunet_namestore_plugin.h"
34 #include "gnunet_statistics_service.h"
35 #include "gnunet_signatures.h"
36 #include "namestore.h"
38 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
44 struct NamestoreClient;
48 * A namestore iteration operation.
53 * Next element in the DLL
55 struct ZoneIteration *next;
58 * Previous element in the DLL
60 struct ZoneIteration *prev;
63 * Namestore client which intiated this zone iteration
65 struct NamestoreClient *nc;
68 * The nick to add to the records
70 struct GNUNET_GNSRECORD_Data *nick;
73 * Key of the zone we are iterating over.
75 struct GNUNET_CRYPTO_EcdsaPrivateKey zone;
78 * Last sequence number in the zone iteration used to address next
79 * result of the zone iteration in the store
82 * Updated in #zone_iterate_proc()
87 * The operation id fot the zone iteration in the response for the client
92 * Offset of the zone iteration used to address next result of the zone
93 * iteration in the store
95 * Initialy set to 0 in #handle_iteration_start
96 * Incremented with by every call to #handle_iteration_next
106 struct NamestoreClient
112 struct GNUNET_SERVICE_Client *client;
115 * Message queue for transmission to @e client
117 struct GNUNET_MQ_Handle *mq;
121 * Zone iteration operations in progress initiated by this client
123 struct ZoneIteration *op_head;
127 * Zone iteration operations in progress initiated by this client
129 struct ZoneIteration *op_tail;
134 * A namestore monitor.
139 * Next element in the DLL
141 struct ZoneMonitor *next;
144 * Previous element in the DLL
146 struct ZoneMonitor *prev;
149 * Namestore client which intiated this zone monitor
151 struct NamestoreClient *nc;
154 * Private key of the zone.
156 struct GNUNET_CRYPTO_EcdsaPrivateKey zone;
159 * Task active during initial iteration.
161 struct GNUNET_SCHEDULER_Task *task;
164 * Last sequence number in the zone iteration used to address next
165 * result of the zone iteration in the store
168 * Updated in #monitor_iterate_cb()
176 * Pending operation on the namecache.
178 struct CacheOperation
184 struct CacheOperation *prev;
189 struct CacheOperation *next;
192 * Handle to namecache queue.
194 struct GNUNET_NAMECACHE_QueueEntry *qe;
197 * Client to notify about the result.
199 struct NamestoreClient *nc;
202 * Client's request ID.
209 * Public key of all zeros.
211 static const struct GNUNET_CRYPTO_EcdsaPrivateKey zero;
214 * Configuration handle.
216 static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
219 * Handle to the statistics service
221 static struct GNUNET_STATISTICS_Handle *statistics;
226 static struct GNUNET_NAMECACHE_Handle *namecache;
231 static struct GNUNET_NAMESTORE_PluginFunctions *GSN_database;
234 * Name of the database plugin
236 static char *db_lib_name;
241 static struct CacheOperation *cop_head;
246 static struct CacheOperation *cop_tail;
249 * First active zone monitor.
251 static struct ZoneMonitor *monitor_head;
254 * Last active zone monitor.
256 static struct ZoneMonitor *monitor_tail;
259 * Notification context shared by all monitors.
261 static struct GNUNET_NotificationContext *monitor_nc;
264 * Optimize block insertion by caching map of private keys to
265 * public keys in memory?
267 static int cache_keys;
270 * Use the namecache? Doing so creates additional cryptographic
271 * operations whenever we touch a record.
273 static int disable_namecache;
277 * Task run during shutdown.
282 cleanup_task (void *cls)
284 struct CacheOperation *cop;
287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
288 "Stopping namestore service\n");
289 while (NULL != (cop = cop_head))
291 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
292 "Aborting incomplete namecache operation\n");
293 GNUNET_NAMECACHE_cancel (cop->qe);
294 GNUNET_CONTAINER_DLL_remove (cop_head,
299 if (NULL != namecache)
301 GNUNET_NAMECACHE_disconnect (namecache);
304 GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name,
306 GNUNET_free (db_lib_name);
308 if (NULL != monitor_nc)
310 GNUNET_notification_context_destroy (monitor_nc);
313 if (NULL != statistics)
315 GNUNET_STATISTICS_destroy (statistics,
323 * Called whenever a client is disconnected.
324 * Frees our resources associated with that client.
327 * @param client identification of the client
328 * @param app_ctx the `struct NamestoreClient` of @a client
331 client_disconnect_cb (void *cls,
332 struct GNUNET_SERVICE_Client *client,
335 struct NamestoreClient *nc = app_ctx;
336 struct ZoneIteration *no;
337 struct ZoneMonitor *zm;
338 struct CacheOperation *cop;
341 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
342 "Client %p disconnected\n",
344 for (zm = monitor_head; NULL != zm; zm = zm->next)
348 GNUNET_CONTAINER_DLL_remove (monitor_head,
351 if (NULL != zm->task)
353 GNUNET_SCHEDULER_cancel (zm->task);
360 while (NULL != (no = nc->op_head))
362 GNUNET_CONTAINER_DLL_remove (nc->op_head,
367 for (cop = cop_head; NULL != cop; cop = cop->next)
375 * Add a client to our list of active clients.
378 * @param client client to add
379 * @param mq message queue for @a client
380 * @return internal namestore client structure for this client
383 client_connect_cb (void *cls,
384 struct GNUNET_SERVICE_Client *client,
385 struct GNUNET_MQ_Handle *mq)
387 struct NamestoreClient *nc;
390 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
391 "Client %p connected\n",
393 nc = GNUNET_new (struct NamestoreClient);
401 * Function called with the records for the #GNUNET_GNS_EMPTY_LABEL_AT
402 * label in the zone. Used to locate the #GNUNET_GNSRECORD_TYPE_NICK
403 * record, which (if found) is then copied to @a cls for future use.
405 * @param cls a `struct GNUNET_GNSRECORD_Data **` for storing the nick (if found)
406 * @param seq sequence number of the record
407 * @param private_key the private key of the zone (unused)
408 * @param label should be #GNUNET_GNS_EMPTY_LABEL_AT
409 * @param rd_count number of records in @a rd
410 * @param rd records stored under @a label in the zone
413 lookup_nick_it (void *cls,
415 const struct GNUNET_CRYPTO_EcdsaPrivateKey *private_key,
417 unsigned int rd_count,
418 const struct GNUNET_GNSRECORD_Data *rd)
420 struct GNUNET_GNSRECORD_Data **res = cls;
424 if (0 != strcmp (label, GNUNET_GNS_EMPTY_LABEL_AT))
429 for (unsigned int c = 0; c < rd_count; c++)
431 if (GNUNET_GNSRECORD_TYPE_NICK == rd[c].record_type)
433 (*res) = GNUNET_malloc (rd[c].data_size + sizeof (struct GNUNET_GNSRECORD_Data));
434 (*res)->data = &(*res)[1];
435 GNUNET_memcpy ((void *) (*res)->data,
438 (*res)->data_size = rd[c].data_size;
439 (*res)->expiration_time = rd[c].expiration_time;
440 (*res)->flags = rd[c].flags;
441 (*res)->record_type = GNUNET_GNSRECORD_TYPE_NICK;
450 * Return the NICK record for the zone (if it exists).
452 * @param zone private key for the zone to look for nick
453 * @return NULL if no NICK record was found
455 static struct GNUNET_GNSRECORD_Data *
456 get_nick_record (const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone)
458 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
459 struct GNUNET_GNSRECORD_Data *nick;
463 res = GSN_database->lookup_records (GSN_database->cls,
465 GNUNET_GNS_EMPTY_LABEL_AT,
468 if ( (GNUNET_OK != res) ||
471 GNUNET_CRYPTO_ecdsa_key_get_public (zone, &pub);
472 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
473 "No nick name set for zone `%s'\n",
474 GNUNET_GNSRECORD_z2s (&pub));
482 * Merge the nick record @a nick_rd with the rest of the
483 * record set given in @a rd2. Store the result in @a rdc_res
484 * and @a rd_res. The @a nick_rd's expiration time is set to
485 * the maximum expiration time of all of the records in @a rd2.
487 * @param nick_rd the nick record to integrate
488 * @param rd2_length length of the @a rd2 array
489 * @param rd2 array of records
490 * @param rdc_res[out] length of the resulting @a rd_res array
491 * @param rd_res[out] set to an array of records,
492 * including @a nick_rd and @a rd2;
493 * all of the variable-size 'data' fields in @a rd2 are
494 * allocated in the same chunk of memory!
497 merge_with_nick_records (const struct GNUNET_GNSRECORD_Data *nick_rd,
498 unsigned int rd2_length,
499 const struct GNUNET_GNSRECORD_Data *rd2,
500 unsigned int *rdc_res,
501 struct GNUNET_GNSRECORD_Data **rd_res)
503 uint64_t latest_expiration;
509 (*rdc_res) = 1 + rd2_length;
510 if (0 == 1 + rd2_length)
516 for (unsigned int c=0; c< 1; c++)
517 req += sizeof (struct GNUNET_GNSRECORD_Data) + nick_rd[c].data_size;
518 for (unsigned int c=0; c< rd2_length; c++)
519 req += sizeof (struct GNUNET_GNSRECORD_Data) + rd2[c].data_size;
520 (*rd_res) = GNUNET_malloc (req);
521 data = (char *) &(*rd_res)[1 + rd2_length];
523 latest_expiration = 0;
524 for (unsigned int c=0; c< rd2_length; c++)
526 if (0 != (rd2[c].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
528 if ((GNUNET_TIME_absolute_get().abs_value_us + rd2[c].expiration_time) >
530 latest_expiration = rd2[c].expiration_time;
532 else if (rd2[c].expiration_time > latest_expiration)
533 latest_expiration = rd2[c].expiration_time;
534 (*rd_res)[c] = rd2[c];
535 (*rd_res)[c].data = (void *) &data[data_offset];
536 GNUNET_memcpy ((void *) (*rd_res)[c].data,
539 data_offset += (*rd_res)[c].data_size;
542 record_offset = rd2_length;
543 (*rd_res)[record_offset] = *nick_rd;
544 (*rd_res)[record_offset].expiration_time = latest_expiration;
545 (*rd_res)[record_offset].data = (void *) &data[data_offset];
546 GNUNET_memcpy ((void *) (*rd_res)[record_offset].data,
549 data_offset += (*rd_res)[record_offset].data_size;
550 GNUNET_assert (req == (sizeof (struct GNUNET_GNSRECORD_Data)) * (*rdc_res) + data_offset);
555 * Generate a `struct LookupNameResponseMessage` and send it to the
556 * given client using the given notification context.
558 * @param nc client to unicast to
559 * @param request_id request ID to use
560 * @param zone_key zone key of the zone
562 * @param rd_count number of records in @a rd
563 * @param rd array of records
566 send_lookup_response (struct NamestoreClient *nc,
568 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
570 unsigned int rd_count,
571 const struct GNUNET_GNSRECORD_Data *rd)
573 struct GNUNET_MQ_Envelope *env;
574 struct RecordResultMessage *zir_msg;
575 struct GNUNET_GNSRECORD_Data *nick;
576 struct GNUNET_GNSRECORD_Data *res;
577 unsigned int res_count;
583 nick = get_nick_record (zone_key);
584 if ( (NULL != nick) &&
586 GNUNET_GNS_EMPTY_LABEL_AT)))
588 nick->flags = (nick->flags | GNUNET_GNSRECORD_RF_PRIVATE) ^ GNUNET_GNSRECORD_RF_PRIVATE;
589 merge_with_nick_records (nick,
598 res_count = rd_count;
599 res = (struct GNUNET_GNSRECORD_Data *) rd;
602 name_len = strlen (name) + 1;
603 rd_ser_len = GNUNET_GNSRECORD_records_get_size (res_count, res);
604 env = GNUNET_MQ_msg_extra (zir_msg,
605 name_len + rd_ser_len,
606 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT);
607 zir_msg->gns_header.r_id = htonl (request_id);
608 zir_msg->name_len = htons (name_len);
609 zir_msg->rd_count = htons (res_count);
610 zir_msg->rd_len = htons (rd_ser_len);
611 zir_msg->private_key = *zone_key;
612 name_tmp = (char *) &zir_msg[1];
613 GNUNET_memcpy (name_tmp,
616 rd_ser = &name_tmp[name_len];
617 GNUNET_GNSRECORD_records_serialize (res_count,
621 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
622 "Sending RECORD_RESULT message with %u records\n",
624 GNUNET_STATISTICS_update (statistics,
625 "Record sets sent to clients",
628 GNUNET_MQ_send (nc->mq,
636 * Send response to the store request to the client.
638 * @param client client to talk to
639 * @param res status of the operation
640 * @param rid client's request ID
643 send_store_response (struct NamestoreClient *nc,
647 struct GNUNET_MQ_Envelope *env;
648 struct RecordStoreResponseMessage *rcr_msg;
650 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
651 "Sending RECORD_STORE_RESPONSE message\n");
652 env = GNUNET_MQ_msg (rcr_msg,
653 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE);
654 rcr_msg->gns_header.r_id = htonl (rid);
655 rcr_msg->op_result = htonl (res);
656 GNUNET_MQ_send (nc->mq,
662 * Cache operation complete, clean up.
664 * @param cls the `struct CacheOperation`
665 * @param success success
666 * @param emsg error messages
669 finish_cache_operation (void *cls,
673 struct CacheOperation *cop = cls;
676 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
677 _("Failed to replicate block in namecache: %s\n"),
680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
681 "CACHE operation completed\n");
682 GNUNET_CONTAINER_DLL_remove (cop_head,
686 send_store_response (cop->nc,
694 * We just touched the plaintext information about a name in our zone;
695 * refresh the corresponding (encrypted) block in the namecache.
697 * @param nc client responsible for the request, can be NULL
698 * @param rid request ID of the client
699 * @param zone_key private key of the zone
700 * @param name label for the records
701 * @param rd_count number of records
702 * @param rd records stored under the given @a name
705 refresh_block (struct NamestoreClient *nc,
707 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
709 unsigned int rd_count,
710 const struct GNUNET_GNSRECORD_Data *rd)
712 struct GNUNET_GNSRECORD_Block *block;
713 struct CacheOperation *cop;
714 struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
715 struct GNUNET_GNSRECORD_Data *nick;
716 struct GNUNET_GNSRECORD_Data *res;
717 unsigned int res_count;
718 struct GNUNET_TIME_Absolute exp_time;
720 nick = get_nick_record (zone_key);
721 res_count = rd_count;
722 res = (struct GNUNET_GNSRECORD_Data *) rd; /* fixme: a bit unclean... */
725 nick->flags = (nick->flags | GNUNET_GNSRECORD_RF_PRIVATE) ^ GNUNET_GNSRECORD_RF_PRIVATE;
726 merge_with_nick_records (nick,
734 send_store_response (nc,
737 return; /* no data, no need to update cache */
739 if (GNUNET_YES == disable_namecache)
741 GNUNET_STATISTICS_update (statistics,
742 "Namecache updates skipped (NC disabled)",
745 send_store_response (nc,
750 exp_time = GNUNET_GNSRECORD_record_get_expiration_time (res_count,
753 block = GNUNET_GNSRECORD_block_create2 (zone_key,
759 block = GNUNET_GNSRECORD_block_create (zone_key,
764 GNUNET_assert (NULL != block);
765 GNUNET_CRYPTO_ecdsa_key_get_public (zone_key,
767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
768 "Caching block for label `%s' with %u records and expiration %s in zone `%s' in namecache\n",
771 GNUNET_STRINGS_absolute_time_to_string (exp_time),
772 GNUNET_GNSRECORD_z2s (&pkey));
773 GNUNET_STATISTICS_update (statistics,
774 "Namecache updates pushed",
777 cop = GNUNET_new (struct CacheOperation);
780 GNUNET_CONTAINER_DLL_insert (cop_head,
783 cop->qe = GNUNET_NAMECACHE_block_cache (namecache,
785 &finish_cache_operation,
792 * Closure for #lookup_it().
794 struct RecordLookupContext
810 struct GNUNET_GNSRECORD_Data *nick;
820 unsigned int res_rd_count;
831 * @param seq sequence number of the record
834 lookup_it (void *cls,
836 const struct GNUNET_CRYPTO_EcdsaPrivateKey *private_key,
838 unsigned int rd_count,
839 const struct GNUNET_GNSRECORD_Data *rd)
841 struct RecordLookupContext *rlc = cls;
842 struct GNUNET_GNSRECORD_Data *rd_res;
843 unsigned int rdc_res;
847 if (0 == strcmp (label,
850 rlc->found = GNUNET_YES;
853 if ( (NULL != rlc->nick) &&
855 GNUNET_GNS_EMPTY_LABEL_AT)) )
860 rlc->nick->flags = (rlc->nick->flags | GNUNET_GNSRECORD_RF_PRIVATE) ^ GNUNET_GNSRECORD_RF_PRIVATE;
861 merge_with_nick_records (rlc->nick,
866 rlc->rd_ser_len = GNUNET_GNSRECORD_records_get_size (rdc_res,
868 rlc->res_rd_count = rdc_res;
869 rlc->res_rd = GNUNET_malloc (rlc->rd_ser_len);
870 GNUNET_GNSRECORD_records_serialize (rdc_res,
875 GNUNET_free (rd_res);
876 GNUNET_free (rlc->nick);
881 rlc->rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count,
883 rlc->res_rd_count = rd_count;
884 rlc->res_rd = GNUNET_malloc (rlc->rd_ser_len);
885 GNUNET_GNSRECORD_records_serialize (rd_count,
894 rlc->res_rd_count = 0;
902 * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP message
904 * @param cls client sending the message
905 * @param ll_msg message of type `struct LabelLookupMessage`
906 * @return #GNUNET_OK if @a ll_msg is well-formed
909 check_record_lookup (void *cls,
910 const struct LabelLookupMessage *ll_msg)
914 const char *name_tmp;
917 name_len = ntohl (ll_msg->label_len);
918 src_size = ntohs (ll_msg->gns_header.header.size);
919 if (name_len != src_size - sizeof (struct LabelLookupMessage))
922 return GNUNET_SYSERR;
925 name_tmp = (const char *) &ll_msg[1];
926 if ('\0' != name_tmp[name_len -1])
929 return GNUNET_SYSERR;
936 * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP message
938 * @param cls client sending the message
939 * @param ll_msg message of type `struct LabelLookupMessage`
942 handle_record_lookup (void *cls,
943 const struct LabelLookupMessage *ll_msg)
945 struct NamestoreClient *nc = cls;
946 struct GNUNET_MQ_Envelope *env;
947 struct LabelLookupResponseMessage *llr_msg;
948 struct RecordLookupContext rlc;
949 const char *name_tmp;
955 name_len = ntohl (ll_msg->label_len);
956 name_tmp = (const char *) &ll_msg[1];
957 GNUNET_SERVICE_client_continue (nc->client);
958 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
959 "Received NAMESTORE_RECORD_LOOKUP message for name `%s'\n",
962 conv_name = GNUNET_GNSRECORD_string_to_lowercase (name_tmp);
963 if (NULL == conv_name)
965 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
966 "Error converting name `%s'\n",
968 GNUNET_SERVICE_client_drop (nc->client);
971 rlc.label = conv_name;
972 rlc.found = GNUNET_NO;
973 rlc.res_rd_count = 0;
976 rlc.nick = get_nick_record (&ll_msg->zone);
977 res = GSN_database->lookup_records (GSN_database->cls,
982 GNUNET_free (conv_name);
983 env = GNUNET_MQ_msg_extra (llr_msg,
984 name_len + rlc.rd_ser_len,
985 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP_RESPONSE);
986 llr_msg->gns_header.r_id = ll_msg->gns_header.r_id;
987 llr_msg->private_key = ll_msg->zone;
988 llr_msg->name_len = htons (name_len);
989 llr_msg->rd_count = htons (rlc.res_rd_count);
990 llr_msg->rd_len = htons (rlc.rd_ser_len);
991 res_name = (char *) &llr_msg[1];
992 if ((GNUNET_YES == rlc.found) && (GNUNET_OK == res))
993 llr_msg->found = ntohs (GNUNET_YES);
995 llr_msg->found = ntohs (GNUNET_NO);
996 GNUNET_memcpy (&llr_msg[1],
999 GNUNET_memcpy (&res_name[name_len],
1002 GNUNET_MQ_send (nc->mq,
1004 GNUNET_free_non_null (rlc.res_rd);
1009 * Checks a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE message
1011 * @param cls client sending the message
1012 * @param rp_msg message of type `struct RecordStoreMessage`
1013 * @return #GNUNET_OK if @a rp_msg is well-formed
1016 check_record_store (void *cls,
1017 const struct RecordStoreMessage *rp_msg)
1021 size_t msg_size_exp;
1023 const char *name_tmp;
1026 name_len = ntohs (rp_msg->name_len);
1027 msg_size = ntohs (rp_msg->gns_header.header.size);
1028 rd_ser_len = ntohs (rp_msg->rd_len);
1029 msg_size_exp = sizeof (struct RecordStoreMessage) + name_len + rd_ser_len;
1030 if (msg_size != msg_size_exp)
1033 return GNUNET_SYSERR;
1035 if ((0 == name_len) || (name_len > MAX_NAME_LEN))
1038 return GNUNET_SYSERR;
1040 name_tmp = (const char *) &rp_msg[1];
1041 if ('\0' != name_tmp[name_len -1])
1044 return GNUNET_SYSERR;
1051 * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE message
1053 * @param cls client sending the message
1054 * @param rp_msg message of type `struct RecordStoreMessage`
1057 handle_record_store (void *cls,
1058 const struct RecordStoreMessage *rp_msg)
1060 struct NamestoreClient *nc = cls;
1064 const char *name_tmp;
1067 unsigned int rd_count;
1069 struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
1070 struct ZoneMonitor *zm;
1072 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1073 "Received NAMESTORE_RECORD_STORE message\n");
1074 rid = ntohl (rp_msg->gns_header.r_id);
1075 name_len = ntohs (rp_msg->name_len);
1076 rd_count = ntohs (rp_msg->rd_count);
1077 rd_ser_len = ntohs (rp_msg->rd_len);
1078 GNUNET_break (0 == ntohs (rp_msg->reserved));
1079 name_tmp = (const char *) &rp_msg[1];
1080 rd_ser = &name_tmp[name_len];
1082 struct GNUNET_GNSRECORD_Data rd[rd_count];
1085 GNUNET_GNSRECORD_records_deserialize (rd_ser_len,
1091 GNUNET_SERVICE_client_drop (nc->client);
1095 /* Extracting and converting private key */
1096 GNUNET_CRYPTO_ecdsa_key_get_public (&rp_msg->private_key,
1098 conv_name = GNUNET_GNSRECORD_string_to_lowercase (name_tmp);
1099 if (NULL == conv_name)
1101 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1102 "Error converting name `%s'\n",
1104 GNUNET_SERVICE_client_drop (nc->client);
1107 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1108 "Creating %u records for name `%s' in zone `%s'\n",
1109 (unsigned int) rd_count,
1111 GNUNET_GNSRECORD_z2s (&pubkey));
1113 if ( (0 == rd_count) &&
1115 GSN_database->iterate_records (GSN_database->cls,
1116 &rp_msg->private_key,
1122 /* This name does not exist, so cannot be removed */
1123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1124 "Name `%s' does not exist, no deletion required\n",
1130 struct GNUNET_GNSRECORD_Data rd_clean[rd_count];
1131 unsigned int rd_clean_off;
1133 /* remove "NICK" records, unless this is for the
1134 #GNUNET_GNS_EMPTY_LABEL_AT label */
1136 for (unsigned int i=0;i<rd_count;i++)
1138 rd_clean[rd_clean_off] = rd[i];
1139 if ( (0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT,
1141 (GNUNET_GNSRECORD_TYPE_NICK != rd[i].record_type) )
1144 res = GSN_database->store_records (GSN_database->cls,
1145 &rp_msg->private_key,
1149 if (GNUNET_OK == res)
1151 for (zm = monitor_head; NULL != zm; zm = zm->next)
1153 if ( (0 == memcmp (&rp_msg->private_key, &zm->zone,
1154 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))) ||
1155 (0 == memcmp (&zm->zone,
1157 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))) )
1159 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1160 "Notifying monitor about changes under label `%s'\n",
1162 send_lookup_response (zm->nc,
1164 &rp_msg->private_key,
1169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1170 "Monitor is for another zone\n");
1172 if (NULL == monitor_head)
1173 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1174 "No monitors active\n");
1178 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1179 "Error storing record: %d\n",
1183 if (GNUNET_OK == res)
1187 &rp_msg->private_key,
1191 GNUNET_SERVICE_client_continue (nc->client);
1192 GNUNET_free (conv_name);
1195 GNUNET_free (conv_name);
1197 send_store_response (nc,
1200 GNUNET_SERVICE_client_continue (nc->client);
1205 * Context for record remove operations passed from #handle_zone_to_name to
1206 * #handle_zone_to_name_it as closure
1208 struct ZoneToNameCtx
1213 struct NamestoreClient *nc;
1216 * Request id (to be used in the response to the client).
1221 * Set to #GNUNET_OK on success, #GNUNET_SYSERR on error. Note that
1222 * not finding a name for the zone still counts as a 'success' here,
1223 * as this field is about the success of executing the IPC protocol.
1230 * Zone to name iterator
1232 * @param cls struct ZoneToNameCtx *
1233 * @param seq sequence number of the record
1234 * @param zone_key the zone key
1236 * @param rd_count number of records in @a rd
1237 * @param rd record data
1240 handle_zone_to_name_it (void *cls,
1242 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
1244 unsigned int rd_count,
1245 const struct GNUNET_GNSRECORD_Data *rd)
1247 struct ZoneToNameCtx *ztn_ctx = cls;
1248 struct GNUNET_MQ_Envelope *env;
1249 struct ZoneToNameResponseMessage *ztnr_msg;
1258 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1259 "Found result for zone-to-name lookup: `%s'\n",
1262 name_len = (NULL == name) ? 0 : strlen (name) + 1;
1263 rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
1264 msg_size = sizeof (struct ZoneToNameResponseMessage) + name_len + rd_ser_len;
1265 if (msg_size >= GNUNET_MAX_MESSAGE_SIZE)
1268 ztn_ctx->success = GNUNET_SYSERR;
1271 env = GNUNET_MQ_msg_extra (ztnr_msg,
1272 name_len + rd_ser_len,
1273 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE);
1274 ztnr_msg->gns_header.header.size = htons (msg_size);
1275 ztnr_msg->gns_header.r_id = htonl (ztn_ctx->rid);
1276 ztnr_msg->res = htons (res);
1277 ztnr_msg->rd_len = htons (rd_ser_len);
1278 ztnr_msg->rd_count = htons (rd_count);
1279 ztnr_msg->name_len = htons (name_len);
1280 ztnr_msg->zone = *zone_key;
1281 name_tmp = (char *) &ztnr_msg[1];
1282 GNUNET_memcpy (name_tmp,
1285 rd_tmp = &name_tmp[name_len];
1286 GNUNET_GNSRECORD_records_serialize (rd_count,
1290 ztn_ctx->success = GNUNET_OK;
1291 GNUNET_MQ_send (ztn_ctx->nc->mq,
1297 * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME message
1299 * @param cls client client sending the message
1300 * @param ztn_msg message of type 'struct ZoneToNameMessage'
1303 handle_zone_to_name (void *cls,
1304 const struct ZoneToNameMessage *ztn_msg)
1306 struct NamestoreClient *nc = cls;
1307 struct ZoneToNameCtx ztn_ctx;
1308 struct GNUNET_MQ_Envelope *env;
1309 struct ZoneToNameResponseMessage *ztnr_msg;
1311 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1312 "Received `%s' message\n",
1314 ztn_ctx.rid = ntohl (ztn_msg->gns_header.r_id);
1316 ztn_ctx.success = GNUNET_NO;
1317 if (GNUNET_SYSERR ==
1318 GSN_database->zone_to_name (GSN_database->cls,
1320 &ztn_msg->value_zone,
1321 &handle_zone_to_name_it, &ztn_ctx))
1323 /* internal error, hang up instead of signalling something
1324 that might be wrong */
1326 GNUNET_SERVICE_client_drop (nc->client);
1329 if (GNUNET_NO == ztn_ctx.success)
1331 /* no result found, send empty response */
1332 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1333 "Found no result for zone-to-name lookup.\n");
1334 env = GNUNET_MQ_msg (ztnr_msg,
1335 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE);
1336 ztnr_msg->gns_header.r_id = ztn_msg->gns_header.r_id;
1337 ztnr_msg->res = htons (GNUNET_NO);
1338 GNUNET_MQ_send (nc->mq,
1341 GNUNET_SERVICE_client_continue (nc->client);
1346 * Context for record remove operations passed from
1347 * #run_zone_iteration_round to #zone_iterate_proc as closure
1349 struct ZoneIterationProcResult
1352 * The zone iteration handle
1354 struct ZoneIteration *zi;
1357 * Number of results left to be returned in this iteration.
1365 * Process results for zone iteration from database
1367 * @param cls struct ZoneIterationProcResult
1368 * @param seq sequence number of the record
1369 * @param zone_key the zone key
1371 * @param rd_count number of records for this name
1372 * @param rd record data
1375 zone_iterate_proc (void *cls,
1377 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
1379 unsigned int rd_count,
1380 const struct GNUNET_GNSRECORD_Data *rd)
1382 struct ZoneIterationProcResult *proc = cls;
1383 int do_refresh_block;
1385 if ( (NULL == zone_key) &&
1388 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1389 "Iteration done\n");
1392 if ( (NULL == zone_key) ||
1395 /* what is this!? should never happen */
1399 if (0 == proc->limit)
1401 /* what is this!? should never happen */
1406 proc->zi->seq = seq;
1407 send_lookup_response (proc->zi->nc,
1408 proc->zi->request_id,
1413 do_refresh_block = GNUNET_NO;
1414 for (unsigned int i=0;i<rd_count;i++)
1415 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
1417 do_refresh_block = GNUNET_YES;
1420 if (GNUNET_YES == do_refresh_block)
1421 refresh_block (NULL,
1431 * Perform the next round of the zone iteration.
1433 * @param zi zone iterator to process
1434 * @param limit number of results to return in one pass
1437 run_zone_iteration_round (struct ZoneIteration *zi,
1440 struct ZoneIterationProcResult proc;
1441 struct GNUNET_MQ_Envelope *env;
1442 struct RecordResultMessage *rrm;
1443 struct GNUNET_TIME_Absolute start;
1444 struct GNUNET_TIME_Relative duration;
1451 start = GNUNET_TIME_absolute_get ();
1452 GNUNET_break (GNUNET_SYSERR !=
1453 GSN_database->iterate_records (GSN_database->cls,
1454 (0 == memcmp (&zi->zone,
1463 duration = GNUNET_TIME_absolute_get_duration (start);
1464 duration = GNUNET_TIME_relative_divide (duration,
1465 limit - proc.limit);
1466 GNUNET_STATISTICS_set (statistics,
1467 "NAMESTORE iteration delay (μs/record)",
1468 duration.rel_value_us,
1470 if (0 == proc.limit)
1472 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1473 "More results available\n");
1474 return; /* more results later after we get the
1475 #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT message */
1477 /* send empty response to indicate end of list */
1478 env = GNUNET_MQ_msg (rrm,
1479 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT);
1480 rrm->gns_header.r_id = htonl (zi->request_id);
1481 GNUNET_MQ_send (zi->nc->mq,
1483 GNUNET_CONTAINER_DLL_remove (zi->nc->op_head,
1491 * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START message
1493 * @param cls the client sending the message
1494 * @param zis_msg message from the client
1497 handle_iteration_start (void *cls,
1498 const struct ZoneIterationStartMessage *zis_msg)
1500 struct NamestoreClient *nc = cls;
1501 struct ZoneIteration *zi;
1503 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1504 "Received ZONE_ITERATION_START message\n");
1505 zi = GNUNET_new (struct ZoneIteration);
1506 zi->request_id = ntohl (zis_msg->gns_header.r_id);
1509 zi->zone = zis_msg->zone;
1511 GNUNET_CONTAINER_DLL_insert (nc->op_head,
1514 run_zone_iteration_round (zi,
1516 GNUNET_SERVICE_client_continue (nc->client);
1521 * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP message
1523 * @param cls the client sending the message
1524 * @param zis_msg message from the client
1527 handle_iteration_stop (void *cls,
1528 const struct ZoneIterationStopMessage *zis_msg)
1530 struct NamestoreClient *nc = cls;
1531 struct ZoneIteration *zi;
1534 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1535 "Received ZONE_ITERATION_STOP message\n");
1536 rid = ntohl (zis_msg->gns_header.r_id);
1537 for (zi = nc->op_head; NULL != zi; zi = zi->next)
1538 if (zi->request_id == rid)
1543 GNUNET_SERVICE_client_drop (nc->client);
1546 GNUNET_CONTAINER_DLL_remove (nc->op_head,
1550 GNUNET_SERVICE_client_continue (nc->client);
1555 * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT message
1557 * @param cls the client sending the message
1558 * @param message message from the client
1561 handle_iteration_next (void *cls,
1562 const struct ZoneIterationNextMessage *zis_msg)
1564 struct NamestoreClient *nc = cls;
1565 struct ZoneIteration *zi;
1569 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1570 "Received ZONE_ITERATION_NEXT message\n");
1571 GNUNET_STATISTICS_update (statistics,
1572 "Iteration NEXT messages received",
1575 rid = ntohl (zis_msg->gns_header.r_id);
1576 limit = GNUNET_ntohll (zis_msg->limit);
1577 for (zi = nc->op_head; NULL != zi; zi = zi->next)
1578 if (zi->request_id == rid)
1583 GNUNET_SERVICE_client_drop (nc->client);
1586 run_zone_iteration_round (zi,
1588 GNUNET_SERVICE_client_continue (nc->client);
1593 * Send 'sync' message to zone monitor, we're now in sync.
1595 * @param zm monitor that is now in sync
1598 monitor_sync (struct ZoneMonitor *zm)
1600 struct GNUNET_MQ_Envelope *env;
1601 struct GNUNET_MessageHeader *sync;
1603 env = GNUNET_MQ_msg (sync,
1604 GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_SYNC);
1605 GNUNET_MQ_send (zm->nc->mq,
1611 * Obtain the next datum during the zone monitor's zone intiial iteration.
1613 * @param cls zone monitor that does its initial iteration
1616 monitor_next (void *cls);
1620 * A #GNUNET_NAMESTORE_RecordIterator for monitors.
1622 * @param cls a 'struct ZoneMonitor *' with information about the monitor
1623 * @param seq sequence number of the record
1624 * @param zone_key zone key of the zone
1626 * @param rd_count number of records in @a rd
1627 * @param rd array of records
1630 monitor_iterate_cb (void *cls,
1632 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
1634 unsigned int rd_count,
1635 const struct GNUNET_GNSRECORD_Data *rd)
1637 struct ZoneMonitor *zm = cls;
1642 /* finished with iteration */
1646 GNUNET_STATISTICS_update (statistics,
1647 "Monitor notifications sent",
1650 send_lookup_response (zm->nc,
1656 zm->task = GNUNET_SCHEDULER_add_now (&monitor_next,
1662 * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START message
1664 * @param cls the client sending the message
1665 * @param message message from the client
1668 handle_monitor_start (void *cls,
1669 const struct ZoneMonitorStartMessage *zis_msg)
1671 struct NamestoreClient *nc = cls;
1672 struct ZoneMonitor *zm;
1674 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1675 "Received ZONE_MONITOR_START message\n");
1676 zm = GNUNET_new (struct ZoneMonitor);
1678 zm->zone = zis_msg->zone;
1679 GNUNET_CONTAINER_DLL_insert (monitor_head,
1682 GNUNET_SERVICE_client_mark_monitor (nc->client);
1683 GNUNET_SERVICE_client_disable_continue_warning (nc->client);
1684 GNUNET_notification_context_add (monitor_nc,
1686 if (GNUNET_YES == ntohl (zis_msg->iterate_first))
1687 zm->task = GNUNET_SCHEDULER_add_now (&monitor_next,
1695 * Obtain the next datum during the zone monitor's zone intiial iteration.
1697 * @param cls zone monitor that does its initial iteration
1700 monitor_next (void *cls)
1702 struct ZoneMonitor *zm = cls;
1706 ret = GSN_database->iterate_records (GSN_database->cls,
1707 (0 == memcmp (&zm->zone,
1714 &monitor_iterate_cb,
1716 if (GNUNET_SYSERR == ret)
1718 GNUNET_SERVICE_client_drop (zm->nc->client);
1721 if (GNUNET_NO == ret)
1731 * Process namestore requests.
1733 * @param cls closure
1734 * @param cfg configuration to use
1735 * @param service the initialized service
1739 const struct GNUNET_CONFIGURATION_Handle *cfg,
1740 struct GNUNET_SERVICE_Handle *service)
1746 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1747 "Starting namestore service\n");
1748 cache_keys = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1751 disable_namecache = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1755 monitor_nc = GNUNET_notification_context_create (1);
1756 if (GNUNET_YES != disable_namecache)
1758 namecache = GNUNET_NAMECACHE_connect (cfg);
1759 GNUNET_assert (NULL != namecache);
1761 /* Loading database plugin */
1763 GNUNET_CONFIGURATION_get_value_string (cfg,
1767 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1768 "No database backend configured\n");
1770 GNUNET_asprintf (&db_lib_name,
1771 "libgnunet_plugin_namestore_%s",
1773 GSN_database = GNUNET_PLUGIN_load (db_lib_name,
1775 GNUNET_free (database);
1776 statistics = GNUNET_STATISTICS_create ("namestore",
1778 GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
1780 if (NULL == GSN_database)
1782 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1783 "Could not load database backend `%s'\n",
1785 GNUNET_SCHEDULER_shutdown ();
1792 * Define "main" method using service macro.
1796 GNUNET_SERVICE_OPTION_NONE,
1799 &client_disconnect_cb,
1801 GNUNET_MQ_hd_var_size (record_store,
1802 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE,
1803 struct RecordStoreMessage,
1805 GNUNET_MQ_hd_var_size (record_lookup,
1806 GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP,
1807 struct LabelLookupMessage,
1809 GNUNET_MQ_hd_fixed_size (zone_to_name,
1810 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME,
1811 struct ZoneToNameMessage,
1813 GNUNET_MQ_hd_fixed_size (iteration_start,
1814 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START,
1815 struct ZoneIterationStartMessage,
1817 GNUNET_MQ_hd_fixed_size (iteration_next,
1818 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT,
1819 struct ZoneIterationNextMessage,
1821 GNUNET_MQ_hd_fixed_size (iteration_stop,
1822 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP,
1823 struct ZoneIterationStopMessage,
1825 GNUNET_MQ_hd_fixed_size (monitor_start,
1826 GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START,
1827 struct ZoneMonitorStartMessage,
1829 GNUNET_MQ_handler_end ());
1832 /* end of gnunet-service-namestore.c */