gnunet

Main GNUnet Logic
Log | Files | Refs | Submodules | README | LICENSE

gnunet-service-namestore.c (85133B)


      1 /*
      2      This file is part of GNUnet.
      3      Copyright (C) 2012, 2013, 2014, 2018 GNUnet e.V.
      4 
      5      GNUnet is free software: you can redistribute it and/or modify it
      6      under the terms of the GNU Affero General Public License as published
      7      by the Free Software Foundation, either version 3 of the License,
      8      or (at your option) any later version.
      9 
     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      Affero General Public License for more details.
     14 
     15      You should have received a copy of the GNU Affero General Public License
     16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 
     18      SPDX-License-Identifier: AGPL3.0-or-later
     19  */
     20 
     21 /**
     22  * @file namestore/gnunet-service-namestore.c
     23  * @brief namestore for the GNUnet naming system
     24  * @author Matthias Wachs
     25  * @author Christian Grothoff
     26  */
     27 #include "platform.h"
     28 #include "gnunet_error_codes.h"
     29 #include "gnunet_gnsrecord_lib.h"
     30 #include "gnunet_protocols.h"
     31 #include "gnunet_util_lib.h"
     32 #include "gnunet_namestore_plugin.h"
     33 #include "gnunet_statistics_service.h"
     34 #include "namestore.h"
     35 
     36 #define LOG_STRERROR_FILE(kind, syscall, filename) \
     37         GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
     38 
     39 /**
     40  * If a monitor takes more than 1 minute to process an event, print a warning.
     41  */
     42 #define MONITOR_STALL_WARN_DELAY GNUNET_TIME_UNIT_MINUTES
     43 
     44 /**
     45  * Size of the cache used by #get_nick_record()
     46  */
     47 #define NC_SIZE 16
     48 
     49 /**
     50  * A namestore client
     51  */
     52 struct NamestoreClient;
     53 
     54 
     55 /**
     56  * A namestore iteration operation.
     57  */
     58 struct ZoneIteration
     59 {
     60   /**
     61    * Next element in the DLL
     62    */
     63   struct ZoneIteration *next;
     64 
     65   /**
     66    * Previous element in the DLL
     67    */
     68   struct ZoneIteration *prev;
     69 
     70   /**
     71    * Namestore client which initiated this zone iteration
     72    */
     73   struct NamestoreClient *nc;
     74 
     75   /**
     76    * The nick to add to the records
     77    */
     78   struct GNUNET_GNSRECORD_Data *nick;
     79 
     80   /**
     81    * Key of the zone we are iterating over.
     82    */
     83   struct GNUNET_CRYPTO_BlindablePrivateKey zone;
     84 
     85   /**
     86    * The record set filter
     87    */
     88   enum GNUNET_GNSRECORD_Filter filter;
     89 
     90   /**
     91    * Last sequence number in the zone iteration used to address next
     92    * result of the zone iteration in the store
     93    *
     94    * Initially set to 0.
     95    * Updated in #zone_iterate_proc()
     96    */
     97   uint64_t seq;
     98 
     99   /**
    100    * The operation id for the zone iteration in the response for the client
    101    */
    102   uint32_t request_id;
    103 
    104   /**
    105    * Offset of the zone iteration used to address next result of the zone
    106    * iteration in the store
    107    *
    108    * Initially set to 0 in #handle_iteration_start
    109    * Incremented with by every call to #handle_iteration_next
    110    */
    111   uint32_t offset;
    112 
    113   /**
    114    * Set to #GNUNET_YES if the last iteration exhausted the limit set by the
    115    * client and we should send the #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT_END
    116    * message and free the data structure.
    117    */
    118   int send_end;
    119 };
    120 
    121 /**
    122  * A namestore client
    123  */
    124 struct NamestoreClient
    125 {
    126   /**
    127    * The client
    128    */
    129   struct GNUNET_SERVICE_Client *client;
    130 
    131   /**
    132    * Database handle for client
    133    */
    134   struct GNUNET_NAMESTORE_PluginFunctions *GSN_database;
    135 
    136   /**
    137    * Name of loaded plugin (needed for cleanup)
    138    */
    139   char *db_lib_name;
    140 
    141   /**
    142    * Message queue for transmission to @e client
    143    */
    144   struct GNUNET_MQ_Handle *mq;
    145 
    146   /**
    147    * Head of the DLL of
    148    * Zone iteration operations in progress initiated by this client
    149    */
    150   struct ZoneIteration *op_head;
    151 
    152   /**
    153    * Tail of the DLL of
    154    * Zone iteration operations in progress initiated by this client
    155    */
    156   struct ZoneIteration *op_tail;
    157 };
    158 
    159 
    160 /**
    161  * A namestore monitor.
    162  */
    163 struct ZoneMonitor
    164 {
    165   /**
    166    * Next element in the DLL
    167    */
    168   struct ZoneMonitor *next;
    169 
    170   /**
    171    * Previous element in the DLL
    172    */
    173   struct ZoneMonitor *prev;
    174 
    175   /**
    176    * Namestore client which initiated this zone monitor
    177    */
    178   struct NamestoreClient *nc;
    179 
    180   /**
    181    * Private key of the zone.
    182    */
    183   struct GNUNET_CRYPTO_BlindablePrivateKey zone;
    184 
    185   /**
    186    * The record set filter
    187    */
    188   enum GNUNET_GNSRECORD_Filter filter;
    189 
    190   /**
    191    * Task active during initial iteration.
    192    */
    193   struct GNUNET_SCHEDULER_Task *task;
    194 
    195   /**
    196    * Task to warn about slow monitors.
    197    */
    198   struct GNUNET_SCHEDULER_Task *sa_wait_warning;
    199 
    200   /**
    201    * Since when are we blocked on this monitor?
    202    */
    203   struct GNUNET_TIME_Absolute sa_waiting_start;
    204 
    205   /**
    206    * Last sequence number in the zone iteration used to address next
    207    * result of the zone iteration in the store
    208    *
    209    * Initially set to 0.
    210    * Updated in #monitor_iterate_cb()
    211    */
    212   uint64_t seq;
    213 
    214   /**
    215    * Current limit of how many more messages we are allowed
    216    * to queue to this monitor.
    217    */
    218   uint64_t limit;
    219 
    220   /**
    221    * How many more requests may we receive from the iterator
    222    * before it is at the limit we gave it?  Will be below or
    223    * equal to @e limit.  The effective limit for monitor
    224    * events is thus @e iteration_cnt - @e limit!
    225    */
    226   uint64_t iteration_cnt;
    227 
    228   /**
    229    * Are we (still) in the initial iteration pass?
    230    */
    231   int in_first_iteration;
    232 
    233   /**
    234    * Run again because we skipped an orphan
    235    */
    236   int run_again;
    237 
    238   /**
    239    * Is there a store activity waiting for this monitor?  We only raise the
    240    * flag when it happens and search the DLL for the store activity when we
    241    * had a limit increase.  If we cannot find any waiting store activity at
    242    * that time, we clear the flag again.
    243    */
    244   int sa_waiting;
    245 };
    246 
    247 
    248 /**
    249  * Information for an ongoing #handle_record_store() operation.
    250  * Needed as we may wait for monitors to be ready for the notification.
    251  */
    252 struct StoreActivity
    253 {
    254   /**
    255    * Kept in a DLL.
    256    */
    257   struct StoreActivity *next;
    258 
    259   /**
    260    * Kept in a DLL.
    261    */
    262   struct StoreActivity *prev;
    263 
    264   /**
    265    * Which client triggered the store activity?
    266    */
    267   struct NamestoreClient *nc;
    268 
    269   /**
    270    * The request ID
    271    */
    272   uint32_t rid;
    273 
    274   /**
    275    * The currently processed record
    276    */
    277   uint16_t rd_set_pos;
    278 
    279   /**
    280    * The number of records in this activity
    281    */
    282   uint16_t rd_set_count;
    283 
    284   /**
    285    * The zone private key
    286    */
    287   struct GNUNET_CRYPTO_BlindablePrivateKey private_key;
    288 
    289   /**
    290    * Copy of the original record set (as data fields in @e rd will
    291    * point into it!).
    292    */
    293   const struct RecordSet *rs;
    294 
    295   /**
    296    * Next zone monitor that still needs to be notified about this PUT.
    297    */
    298   struct ZoneMonitor *zm_pos;
    299 
    300 };
    301 
    302 
    303 /**
    304  * Entry in list of cached nick resolutions.
    305  */
    306 struct NickCache
    307 {
    308   /**
    309    * Zone the cache entry is for.
    310    */
    311   struct GNUNET_CRYPTO_BlindablePrivateKey zone;
    312 
    313   /**
    314    * Cached record data.
    315    */
    316   struct GNUNET_GNSRECORD_Data *rd;
    317 
    318   /**
    319    * Timestamp when this cache entry was used last.
    320    */
    321   struct GNUNET_TIME_Absolute last_used;
    322 };
    323 
    324 /**
    325  * We cache nick records to reduce DB load.
    326  */
    327 static struct NickCache nick_cache[NC_SIZE];
    328 
    329 /**
    330  * Public key of all zeros.
    331  */
    332 static const struct GNUNET_CRYPTO_BlindablePrivateKey zero;
    333 
    334 /**
    335  * Configuration handle.
    336  */
    337 static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
    338 
    339 /**
    340  * Handle to the statistics service
    341  */
    342 static struct GNUNET_STATISTICS_Handle *statistics;
    343 
    344 /**
    345  * Name of the database plugin
    346  */
    347 static char *db_lib_name;
    348 
    349 /**
    350  * Database handle for service
    351  */
    352 struct GNUNET_NAMESTORE_PluginFunctions *GSN_database;
    353 
    354 
    355 /**
    356  * First active zone monitor.
    357  */
    358 static struct ZoneMonitor *monitor_head;
    359 
    360 /**
    361  * Last active zone monitor.
    362  */
    363 static struct ZoneMonitor *monitor_tail;
    364 
    365 /**
    366  * Head of DLL of monitor-blocked store activities.
    367  */
    368 static struct StoreActivity *sa_head;
    369 
    370 /**
    371  * Tail of DLL of monitor-blocked store activities.
    372  */
    373 static struct StoreActivity *sa_tail;
    374 
    375 /**
    376  * Notification context shared by all monitors.
    377  */
    378 static struct GNUNET_NotificationContext *monitor_nc;
    379 
    380 /**
    381  * Returned orphaned records?
    382  */
    383 static int return_orphaned;
    384 
    385 /**
    386  * Task run during shutdown.
    387  *
    388  * @param cls unused
    389  */
    390 static void
    391 cleanup_task (void *cls)
    392 {
    393   (void) cls;
    394   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping namestore service\n");
    395   if (NULL != monitor_nc)
    396   {
    397     GNUNET_notification_context_destroy (monitor_nc);
    398     monitor_nc = NULL;
    399   }
    400   if (NULL != statistics)
    401   {
    402     GNUNET_STATISTICS_destroy (statistics, GNUNET_NO);
    403     statistics = NULL;
    404   }
    405   GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, GSN_database));
    406   GNUNET_free (db_lib_name);
    407   db_lib_name = NULL;
    408 }
    409 
    410 
    411 /**
    412  * Release memory used by @a sa.
    413  *
    414  * @param sa activity to free
    415  */
    416 static void
    417 free_store_activity (struct StoreActivity *sa)
    418 {
    419   GNUNET_CONTAINER_DLL_remove (sa_head, sa_tail, sa);
    420   GNUNET_free (sa);
    421 }
    422 
    423 
    424 /**
    425  * Function called with the records for the #GNUNET_GNS_EMPTY_LABEL_AT
    426  * label in the zone.  Used to locate the #GNUNET_GNSRECORD_TYPE_NICK
    427  * record, which (if found) is then copied to @a cls for future use.
    428  *
    429  * @param cls a `struct GNUNET_GNSRECORD_Data **` for storing the nick (if found)
    430  * @param seq sequence number of the record, MUST NOT BE ZERO
    431  * @param private_key the private key of the zone (unused)
    432  * @param label should be #GNUNET_GNS_EMPTY_LABEL_AT
    433  * @param rd_count number of records in @a rd
    434  * @param rd records stored under @a label in the zone
    435  */
    436 static void
    437 lookup_nick_it (void *cls,
    438                 uint64_t seq,
    439                 const char *editor_hint,
    440                 const struct GNUNET_CRYPTO_BlindablePrivateKey *private_key,
    441                 const char *label,
    442                 unsigned int rd_count,
    443                 const struct GNUNET_GNSRECORD_Data *rd)
    444 {
    445   struct GNUNET_GNSRECORD_Data **res = cls;
    446 
    447   (void) private_key;
    448   GNUNET_assert (0 != seq);
    449   if (0 != strcmp (label, GNUNET_GNS_EMPTY_LABEL_AT))
    450   {
    451     GNUNET_break (0);
    452     return;
    453   }
    454   for (unsigned int c = 0; c < rd_count; c++)
    455   {
    456     if (GNUNET_GNSRECORD_TYPE_NICK == rd[c].record_type)
    457     {
    458       (*res) =
    459         GNUNET_malloc (rd[c].data_size + sizeof(struct GNUNET_GNSRECORD_Data));
    460       (*res)->data = &(*res)[1];
    461       GNUNET_memcpy ((void *) (*res)->data, rd[c].data, rd[c].data_size);
    462       (*res)->data_size = rd[c].data_size;
    463       (*res)->expiration_time = rd[c].expiration_time;
    464       (*res)->flags = rd[c].flags;
    465       (*res)->record_type = GNUNET_GNSRECORD_TYPE_NICK;
    466       return;
    467     }
    468   }
    469   (*res) = NULL;
    470 }
    471 
    472 
    473 /**
    474  * Add entry to the cache for @a zone and @a nick
    475  *
    476  * @param zone zone key to cache under
    477  * @param nick nick entry to cache
    478  */
    479 static void
    480 cache_nick (const struct GNUNET_CRYPTO_BlindablePrivateKey *zone,
    481             const struct GNUNET_GNSRECORD_Data *nick)
    482 {
    483   struct NickCache *oldest;
    484 
    485   oldest = NULL;
    486   for (unsigned int i = 0; i < NC_SIZE; i++)
    487   {
    488     struct NickCache *pos = &nick_cache[i];
    489 
    490     if ((NULL == oldest) ||
    491         (oldest->last_used.abs_value_us > pos->last_used.abs_value_us))
    492       oldest = pos;
    493     if (0 == GNUNET_memcmp (zone, &pos->zone))
    494     {
    495       oldest = pos;
    496       break;
    497     }
    498   }
    499   GNUNET_free (oldest->rd);
    500   oldest->zone = *zone;
    501   if (NULL != nick)
    502   {
    503     oldest->rd = GNUNET_malloc (sizeof(*nick) + nick->data_size);
    504     *oldest->rd = *nick;
    505     oldest->rd->data = &oldest->rd[1];
    506     memcpy (&oldest->rd[1], nick->data, nick->data_size);
    507   }
    508   else
    509   {
    510     oldest->rd = NULL;
    511   }
    512   oldest->last_used = GNUNET_TIME_absolute_get ();
    513 }
    514 
    515 
    516 /**
    517  * Return the NICK record for the zone (if it exists).
    518  *
    519  * @param nc the namestore client
    520  * @param zone private key for the zone to look for nick
    521  * @return NULL if no NICK record was found
    522  */
    523 static struct GNUNET_GNSRECORD_Data *
    524 get_nick_record (const struct GNUNET_CRYPTO_BlindablePrivateKey *zone)
    525 {
    526   struct GNUNET_CRYPTO_BlindablePublicKey pub;
    527   struct GNUNET_GNSRECORD_Data *nick;
    528   int res;
    529 
    530   /* check cache first */
    531   for (unsigned int i = 0; i < NC_SIZE; i++)
    532   {
    533     struct NickCache *pos = &nick_cache[i];
    534     if ((NULL != pos->rd) && (0 == GNUNET_memcmp (zone, &pos->zone)))
    535     {
    536       if (NULL == pos->rd)
    537         return NULL;
    538       nick = GNUNET_malloc (sizeof(*nick) + pos->rd->data_size);
    539       *nick = *pos->rd;
    540       nick->data = &nick[1];
    541       memcpy (&nick[1], pos->rd->data, pos->rd->data_size);
    542       pos->last_used = GNUNET_TIME_absolute_get ();
    543       return nick;
    544     }
    545   }
    546 
    547   nick = NULL;
    548   res = GSN_database->lookup_records (GSN_database->cls,
    549                                       zone,
    550                                       GNUNET_GNS_EMPTY_LABEL_AT,
    551                                       &lookup_nick_it,
    552                                       &nick);
    553   if ((GNUNET_OK != res) || (NULL == nick))
    554   {
    555 #if ! defined(GNUNET_CULL_LOGGING)
    556     static int do_log = GNUNET_LOG_CALL_STATUS;
    557 
    558     if (0 == do_log)
    559       do_log = GNUNET_get_log_call_status (GNUNET_ERROR_TYPE_DEBUG,
    560                                            "namestore",
    561                                            __FILE__,
    562                                            __FUNCTION__,
    563                                            __LINE__);
    564     if (1 == do_log)
    565     {
    566       GNUNET_CRYPTO_blindable_key_get_public (zone, &pub);
    567       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
    568                   "No nick name set for zone `%s'\n",
    569                   GNUNET_GNSRECORD_z2s (&pub));
    570     }
    571 #endif
    572     /* update cache */
    573     cache_nick (zone, NULL);
    574     return NULL;
    575   }
    576 
    577   /* update cache */
    578   cache_nick (zone, nick);
    579   return nick;
    580 }
    581 
    582 
    583 /**
    584  * Merge the nick record @a nick_rd with the rest of the
    585  * record set given in @a rd2.  Store the result in @a rdc_res
    586  * and @a rd_res.  The @a nick_rd's expiration time is set to
    587  * the maximum expiration time of all of the records in @a rd2.
    588  *
    589  * @param nick_rd the nick record to integrate
    590  * @param rd2_length length of the @a rd2 array
    591  * @param rd2 array of records
    592  * @param[out] rdc_res length of the resulting @a rd_res array
    593  * @param[out] rd_res set to an array of records,
    594  *                    including @a nick_rd and @a rd2;
    595  *           all of the variable-size 'data' fields in @a rd2 are
    596  *           allocated in the same chunk of memory!
    597  */
    598 static void
    599 merge_with_nick_records (const struct GNUNET_GNSRECORD_Data *nick_rd,
    600                          unsigned int rd2_length,
    601                          const struct GNUNET_GNSRECORD_Data *rd2,
    602                          unsigned int *rdc_res,
    603                          struct GNUNET_GNSRECORD_Data **rd_res)
    604 {
    605   uint64_t latest_expiration;
    606   size_t req;
    607   char *data;
    608   size_t data_offset;
    609   struct GNUNET_GNSRECORD_Data *target;
    610 
    611   (*rdc_res) = 1 + rd2_length;
    612   if (0 == 1 + rd2_length)
    613   {
    614     GNUNET_break (0);
    615     (*rd_res) = NULL;
    616     return;
    617   }
    618   req = sizeof(struct GNUNET_GNSRECORD_Data) + nick_rd->data_size;
    619   for (unsigned int i = 0; i < rd2_length; i++)
    620   {
    621     const struct GNUNET_GNSRECORD_Data *orig = &rd2[i];
    622 
    623     if (req + sizeof(struct GNUNET_GNSRECORD_Data) + orig->data_size < req)
    624     {
    625       GNUNET_break (0);
    626       (*rd_res) = NULL;
    627       return;
    628     }
    629     req += sizeof(struct GNUNET_GNSRECORD_Data) + orig->data_size;
    630   }
    631   target = GNUNET_malloc (req);
    632   (*rd_res) = target;
    633   data = (char *) &target[1 + rd2_length];
    634   data_offset = 0;
    635   latest_expiration = 0;
    636   for (unsigned int i = 0; i < rd2_length; i++)
    637   {
    638     const struct GNUNET_GNSRECORD_Data *orig = &rd2[i];
    639 
    640     if (0 != (orig->flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
    641     {
    642       if ((GNUNET_TIME_absolute_get ().abs_value_us + orig->expiration_time) >
    643           latest_expiration)
    644         latest_expiration = orig->expiration_time;
    645     }
    646     else if (orig->expiration_time > latest_expiration)
    647       latest_expiration = orig->expiration_time;
    648     target[i] = *orig;
    649     target[i].data = (void *) &data[data_offset];
    650     GNUNET_memcpy (&data[data_offset], orig->data, orig->data_size);
    651     data_offset += orig->data_size;
    652   }
    653   /* append nick */
    654   target[rd2_length] = *nick_rd;
    655   /* Mark as supplemental */
    656   target[rd2_length].flags = nick_rd->flags | GNUNET_GNSRECORD_RF_SUPPLEMENTAL;
    657   target[rd2_length].expiration_time = latest_expiration;
    658   target[rd2_length].data = (void *) &data[data_offset];
    659   GNUNET_memcpy (&data[data_offset], nick_rd->data, nick_rd->data_size);
    660   data_offset += nick_rd->data_size;
    661   GNUNET_assert (req == (sizeof(struct GNUNET_GNSRECORD_Data)) * (*rdc_res)
    662                  + data_offset);
    663 }
    664 
    665 
    666 /**
    667  * Generate a `struct LookupNameResponseMessage` and send it to the
    668  * given client using the given notification context.
    669  *
    670  * @param nc client to unicast to
    671  * @param request_id request ID to use
    672  * @param zone_key zone key of the zone
    673  * @param name name
    674  * @param rd_count number of records in @a rd
    675  * @param rd array of records
    676  * @param filter record set filter
    677  */
    678 static int
    679 send_lookup_response_with_filter (struct NamestoreClient *nc,
    680                                   uint32_t request_id,
    681                                   const struct
    682                                   GNUNET_CRYPTO_BlindablePrivateKey *zone_key,
    683                                   const char *name,
    684                                   unsigned int rd_count,
    685                                   const struct GNUNET_GNSRECORD_Data *rd,
    686                                   enum GNUNET_GNSRECORD_Filter filter)
    687 {
    688   struct GNUNET_MQ_Envelope *env;
    689   struct RecordResultMessage *zir_msg;
    690   struct GNUNET_GNSRECORD_Data *nick;
    691   struct GNUNET_GNSRECORD_Data *res;
    692   struct GNUNET_GNSRECORD_Data rd_nf[rd_count];
    693   struct GNUNET_TIME_Absolute block_exp;
    694   unsigned int res_count;
    695   unsigned int rd_nf_count;
    696   size_t name_len;
    697   size_t key_len;
    698   ssize_t rd_ser_len;
    699   char *name_tmp;
    700   char *rd_ser;
    701   char *emsg;
    702 
    703   block_exp = GNUNET_TIME_UNIT_ZERO_ABS;
    704   nick = get_nick_record (zone_key);
    705   GNUNET_assert (-1 != GNUNET_GNSRECORD_records_get_size (rd_count, rd));
    706 
    707   if (GNUNET_OK != GNUNET_GNSRECORD_normalize_record_set (name,
    708                                                           rd,
    709                                                           rd_count,
    710                                                           rd_nf,
    711                                                           &rd_nf_count,
    712                                                           &block_exp,
    713                                                           filter,
    714                                                           &emsg))
    715   {
    716     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
    717     GNUNET_free (emsg);
    718     GNUNET_assert (0);
    719   }
    720 
    721   /**
    722    * FIXME if we ever support GNUNET_NAMESTORE_OMIT_PUBLIC,
    723    * we need to omit adding this public record here
    724    */
    725   if ((NULL != nick) && (0 != strcmp (name, GNUNET_GNS_EMPTY_LABEL_AT)))
    726   {
    727     nick->flags =
    728       (nick->flags | GNUNET_GNSRECORD_RF_PRIVATE) ^ GNUNET_GNSRECORD_RF_PRIVATE;
    729     merge_with_nick_records (nick, rd_nf_count, rd_nf, &res_count, &res);
    730   }
    731   else
    732   {
    733     res_count = rd_nf_count;
    734     res = (struct GNUNET_GNSRECORD_Data *) rd_nf;
    735   }
    736   if (NULL != nick)
    737     GNUNET_free (nick);
    738 
    739   if (0 == res_count)
    740   {
    741     if (rd_nf != res)
    742       GNUNET_free (res);
    743     return 0;
    744   }
    745   GNUNET_assert (-1 != GNUNET_GNSRECORD_records_get_size (res_count, res));
    746 
    747 
    748   name_len = strlen (name) + 1;
    749   rd_ser_len = GNUNET_GNSRECORD_records_get_size (res_count, res);
    750   if (rd_ser_len < 0)
    751   {
    752     if (rd_nf != res)
    753       GNUNET_free (res);
    754     GNUNET_break (0);
    755     GNUNET_SERVICE_client_drop (nc->client);
    756     return 0;
    757   }
    758   if (((size_t) rd_ser_len) >= UINT16_MAX - name_len - sizeof(*zir_msg))
    759   {
    760     if (rd_nf != res)
    761       GNUNET_free (res);
    762     GNUNET_break (0);
    763     GNUNET_SERVICE_client_drop (nc->client);
    764     return 0;
    765   }
    766   key_len = GNUNET_CRYPTO_blindable_sk_get_length (zone_key);
    767   env = GNUNET_MQ_msg_extra (zir_msg,
    768                              name_len + rd_ser_len + key_len,
    769                              GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT);
    770   zir_msg->gns_header.r_id = htonl (request_id);
    771   zir_msg->name_len = htons (name_len);
    772   zir_msg->rd_count = htons (res_count);
    773   zir_msg->rd_len = htons ((uint16_t) rd_ser_len);
    774   zir_msg->key_len = htons (key_len);
    775   GNUNET_CRYPTO_write_blindable_sk_to_buffer (zone_key,
    776                                               &zir_msg[1],
    777                                               key_len);
    778   zir_msg->expire = GNUNET_TIME_absolute_hton (block_exp);
    779   name_tmp = (char *) &zir_msg[1] + key_len;
    780   GNUNET_memcpy (name_tmp, name, name_len);
    781   rd_ser = &name_tmp[name_len];
    782   GNUNET_assert (
    783     rd_ser_len ==
    784     GNUNET_GNSRECORD_records_serialize (res_count, res, rd_ser_len, rd_ser));
    785   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    786               "Sending RECORD_RESULT message with %u records\n",
    787               res_count);
    788   GNUNET_STATISTICS_update (statistics,
    789                             "Record sets sent to clients",
    790                             1,
    791                             GNUNET_NO);
    792   GNUNET_MQ_send (nc->mq, env);
    793   if (rd_nf != res)
    794     GNUNET_free (res);
    795   return res_count;
    796 }
    797 
    798 
    799 /**
    800  * Send response to the store request to the client.
    801  *
    802  * @param nc client to talk to
    803  * @param ec status of the operation
    804  * @param rid client's request ID
    805  */
    806 static void
    807 send_store_response (struct NamestoreClient *nc,
    808                      enum GNUNET_ErrorCode ec,
    809                      uint32_t rid)
    810 {
    811   struct GNUNET_MQ_Envelope *env;
    812   struct NamestoreResponseMessage *rcr_msg;
    813 
    814   GNUNET_assert (NULL != nc);
    815   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    816               "Sending GENERIC_RESPONSE message\n");
    817   GNUNET_STATISTICS_update (statistics,
    818                             "Store requests completed",
    819                             1,
    820                             GNUNET_NO);
    821   env = GNUNET_MQ_msg (rcr_msg,
    822                        GNUNET_MESSAGE_TYPE_NAMESTORE_GENERIC_RESPONSE);
    823   rcr_msg->gns_header.r_id = htonl (rid);
    824   rcr_msg->ec = htonl (ec);
    825   GNUNET_MQ_send (nc->mq, env);
    826 }
    827 
    828 
    829 /**
    830  * Function called once we are done with the zone iteration and
    831  * allow the zone iteration client to send us more messages.
    832  *
    833  * @param zi zone iteration we are processing
    834  */
    835 static void
    836 zone_iteration_done_client_continue (struct ZoneIteration *zi)
    837 {
    838   struct GNUNET_MQ_Envelope *env;
    839   struct GNUNET_NAMESTORE_Header *em;
    840 
    841   GNUNET_SERVICE_client_continue (zi->nc->client);
    842   if (! zi->send_end)
    843     return;
    844   /* send empty response to indicate end of list */
    845   env = GNUNET_MQ_msg (em, GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT_END);
    846   em->r_id = htonl (zi->request_id);
    847   GNUNET_MQ_send (zi->nc->mq, env);
    848 
    849   GNUNET_CONTAINER_DLL_remove (zi->nc->op_head, zi->nc->op_tail, zi);
    850   GNUNET_free (zi);
    851 }
    852 
    853 
    854 /**
    855  * Print a warning that one of our monitors is no longer reacting.
    856  *
    857  * @param cls a `struct ZoneMonitor` to warn about
    858  */
    859 static void
    860 warn_monitor_slow (void *cls)
    861 {
    862   struct ZoneMonitor *zm = cls;
    863 
    864   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    865               "No response from monitor since %s\n",
    866               GNUNET_STRINGS_absolute_time_to_string (zm->sa_waiting_start));
    867   zm->sa_wait_warning = GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY,
    868                                                       &warn_monitor_slow,
    869                                                       zm);
    870 }
    871 
    872 
    873 /**
    874  * Continue processing the @a sa.
    875  *
    876  * @param sa store activity to process
    877  */
    878 static int
    879 continue_store_activity (struct StoreActivity *sa,
    880                          int call_continue)
    881 {
    882   const struct RecordSet *rd_set = sa->rs;
    883   unsigned int rd_count;
    884   size_t name_len;
    885   size_t rd_ser_len;
    886   const char *name;
    887   const char *rd_ser;
    888   const char *buf;
    889 
    890   buf = (const char *) &sa[1];
    891   for (int i = sa->rd_set_pos; i < sa->rd_set_count; i++)
    892   {
    893     rd_set = (struct RecordSet *) buf;
    894     name_len = ntohs (rd_set->name_len);
    895     rd_count = ntohs (rd_set->rd_count);
    896     rd_ser_len = ntohs (rd_set->rd_len);
    897     name = (const char *) &rd_set[1];
    898     buf += sizeof (struct RecordSet) + name_len + rd_ser_len;
    899     rd_ser = &name[name_len];
    900     {
    901       struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)];
    902 
    903       /* We did this before, must succeed again */
    904       GNUNET_assert (
    905         GNUNET_OK ==
    906         GNUNET_GNSRECORD_records_deserialize (rd_ser_len, rd_ser, rd_count,
    907                                               rd));
    908 
    909       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    910                   "Checking monitors watching for `%s'\n",
    911                   name);
    912       for (struct ZoneMonitor *zm = sa->zm_pos; NULL != zm; zm = sa->zm_pos)
    913       {
    914         if ((0 != GNUNET_memcmp (&sa->private_key, &zm->zone)) &&
    915             (0 != GNUNET_memcmp (&zm->zone, &zero)))
    916         {
    917           sa->zm_pos = zm->next;   /* not interesting to this monitor */
    918           continue;
    919         }
    920         if (zm->limit == zm->iteration_cnt)
    921         {
    922           zm->sa_waiting = GNUNET_YES;
    923           zm->sa_waiting_start = GNUNET_TIME_absolute_get ();
    924           if (NULL != zm->sa_wait_warning)
    925             GNUNET_SCHEDULER_cancel (zm->sa_wait_warning);
    926           zm->sa_wait_warning =
    927             GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY,
    928                                           &warn_monitor_slow,
    929                                           zm);
    930           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    931                       "Monitor is blocking client for `%s'\n",
    932                       name);
    933           return GNUNET_NO;    /* blocked on zone monitor */
    934         }
    935         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    936                     "Notifying monitor about changes under label `%s'\n",
    937                     name);
    938         if (0 < send_lookup_response_with_filter (zm->nc,
    939                                                   0,
    940                                                   &sa->private_key,
    941                                                   name,
    942                                                   rd_count,
    943                                                   rd,
    944                                                   zm->filter))
    945           zm->limit--;
    946         sa->zm_pos = zm->next;
    947       }
    948       sa->rd_set_pos++;
    949     }
    950   }
    951   if (GNUNET_YES == call_continue)
    952     GNUNET_SERVICE_client_continue (sa->nc->client);
    953   send_store_response (sa->nc, GNUNET_EC_NONE, sa->rid);
    954   free_store_activity (sa);
    955   return GNUNET_OK;
    956 }
    957 
    958 
    959 /**
    960  * Called whenever a client is disconnected.
    961  * Frees our resources associated with that client.
    962  *
    963  * @param cls closure
    964  * @param client identification of the client
    965  * @param app_ctx the `struct NamestoreClient` of @a client
    966  */
    967 static void
    968 client_disconnect_cb (void *cls,
    969                       struct GNUNET_SERVICE_Client *client,
    970                       void *app_ctx)
    971 {
    972   struct NamestoreClient *nc = app_ctx;
    973   struct ZoneIteration *no;
    974   struct StoreActivity *sa = sa_head;
    975   struct StoreActivity *sn;
    976 
    977   (void) cls;
    978   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected\n", client);
    979   for (struct ZoneMonitor *zm = monitor_head; NULL != zm; zm = zm->next)
    980   {
    981     if (nc != zm->nc)
    982       continue;
    983     GNUNET_CONTAINER_DLL_remove (monitor_head, monitor_tail, zm);
    984     if (NULL != zm->task)
    985     {
    986       GNUNET_SCHEDULER_cancel (zm->task);
    987       zm->task = NULL;
    988     }
    989     if (NULL != zm->sa_wait_warning)
    990     {
    991       GNUNET_SCHEDULER_cancel (zm->sa_wait_warning);
    992       zm->sa_wait_warning = NULL;
    993     }
    994     for (sa = sa_head; NULL != sa; sa = sn)
    995     {
    996       sn = sa->next;
    997       if (zm == sa->zm_pos)
    998       {
    999         sa->zm_pos = zm->next;
   1000         /* this may free sa */
   1001         continue_store_activity (sa, GNUNET_YES);
   1002       }
   1003     }
   1004     GNUNET_free (zm);
   1005     break;
   1006   }
   1007   sa = sa_head;
   1008   while (NULL != sa)
   1009   {
   1010     if (nc != sa->nc)
   1011     {
   1012       sa = sa->next;
   1013       continue;
   1014     }
   1015     sn = sa->next;
   1016     free_store_activity (sa);
   1017     sa = sn;
   1018   }
   1019   while (NULL != (no = nc->op_head))
   1020   {
   1021     GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no);
   1022     GNUNET_free (no);
   1023   }
   1024   GNUNET_break (NULL == GNUNET_PLUGIN_unload (nc->db_lib_name,
   1025                                               nc->GSN_database));
   1026   GNUNET_free (nc->db_lib_name);
   1027   GNUNET_free (nc);
   1028 }
   1029 
   1030 
   1031 /**
   1032  * Add a client to our list of active clients.
   1033  *
   1034  * @param cls NULL
   1035  * @param client client to add
   1036  * @param mq message queue for @a client
   1037  * @return internal namestore client structure for this client
   1038  */
   1039 static void *
   1040 client_connect_cb (void *cls,
   1041                    struct GNUNET_SERVICE_Client *client,
   1042                    struct GNUNET_MQ_Handle *mq)
   1043 {
   1044   struct NamestoreClient *nc;
   1045   char *database;
   1046 
   1047   (void) cls;
   1048   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client);
   1049   nc = GNUNET_new (struct NamestoreClient);
   1050   nc->client = client;
   1051   nc->mq = mq;
   1052   /* Loading database plugin */
   1053   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (GSN_cfg,
   1054                                                           "namestore",
   1055                                                           "database",
   1056                                                           &database))
   1057   {
   1058     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
   1059     GNUNET_free (nc);
   1060     return NULL;
   1061   }
   1062   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1063               "Loading %s\n",
   1064               db_lib_name);
   1065   nc->GSN_database = GNUNET_PLUGIN_load (GNUNET_OS_project_data_gnunet (),
   1066                                          db_lib_name,
   1067                                          (void *) GSN_cfg);
   1068   GNUNET_free (database);
   1069   if (NULL == nc->GSN_database)
   1070   {
   1071     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1072                 "Could not load database backend `%s'\n",
   1073                 db_lib_name);
   1074     GNUNET_free (nc);
   1075     return NULL;
   1076   }
   1077   nc->db_lib_name = GNUNET_strdup (db_lib_name);
   1078   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1079               "Loaded %s\n",
   1080               db_lib_name);
   1081   return nc;
   1082 }
   1083 
   1084 
   1085 /**
   1086  * Closure for #lookup_it().
   1087  */
   1088 struct RecordLookupContext
   1089 {
   1090   /**
   1091    * The label to look up.
   1092    */
   1093   const char *label;
   1094 
   1095   /**
   1096    * The editor hint for set
   1097    */
   1098   char *editor_hint;
   1099 
   1100   /**
   1101    * The record result.
   1102    */
   1103   char *res_rd;
   1104 
   1105   /**
   1106    * The nick for the zone.
   1107    */
   1108   struct GNUNET_GNSRECORD_Data *nick;
   1109 
   1110   /**
   1111    * If a record set was found or not.
   1112    */
   1113   int found;
   1114 
   1115   /**
   1116    * The record filter
   1117    */
   1118   enum GNUNET_GNSRECORD_Filter filter;
   1119 
   1120   /**
   1121    * The number of found records.
   1122    */
   1123   unsigned int res_rd_count;
   1124 
   1125   /**
   1126    * The length of the serialized records.
   1127    */
   1128   ssize_t rd_ser_len;
   1129 };
   1130 
   1131 
   1132 /**
   1133  * Function called by the namestore plugin when we are trying to lookup
   1134  * a record as part of #handle_record_lookup().  Merges all results into
   1135  * the context.
   1136  *
   1137  * @param cls closure with a `struct RecordLookupContext`
   1138  * @param seq unique serial number of the record, MUST NOT BE ZERO
   1139  * @param private_key private key of the zone
   1140  * @param label name that is being mapped (at most 255 characters long)
   1141  * @param rd_count number of entries in @a rd array
   1142  * @param rd array of records with data to store
   1143  */
   1144 static void
   1145 lookup_it (void *cls,
   1146            uint64_t seq,
   1147            const char *editor_hint,
   1148            const struct GNUNET_CRYPTO_BlindablePrivateKey *private_key,
   1149            const char *label,
   1150            unsigned int rd_count_nf,
   1151            const struct GNUNET_GNSRECORD_Data *rd_nf)
   1152 {
   1153   struct RecordLookupContext *rlc = cls;
   1154   struct GNUNET_GNSRECORD_Data rd[rd_count_nf];
   1155   struct GNUNET_TIME_Absolute block_exp;
   1156   unsigned int rd_count = 0;
   1157   char *emsg;
   1158 
   1159   (void) private_key;
   1160   GNUNET_assert (0 != seq);
   1161   if (0 != strcmp (label, rlc->label))
   1162     return;
   1163   rlc->found = GNUNET_YES;
   1164   if (NULL == rlc->editor_hint)
   1165     rlc->editor_hint = GNUNET_strdup (editor_hint);
   1166   if (GNUNET_OK != GNUNET_GNSRECORD_normalize_record_set (rlc->label,
   1167                                                           rd_nf,
   1168                                                           rd_count_nf,
   1169                                                           rd,
   1170                                                           &rd_count,
   1171                                                           &block_exp,
   1172                                                           rlc->filter,
   1173                                                           &emsg))
   1174   {
   1175     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
   1176     GNUNET_free (emsg);
   1177     GNUNET_assert (0);
   1178   }
   1179 
   1180   if (0 == rd_count)
   1181   {
   1182     rlc->rd_ser_len = 0;
   1183     rlc->res_rd_count = 0;
   1184     rlc->res_rd = NULL;
   1185     return;
   1186   }
   1187   if ((NULL != rlc->nick) && (0 != strcmp (label, GNUNET_GNS_EMPTY_LABEL_AT)))
   1188   {
   1189     /* Merge */
   1190     struct GNUNET_GNSRECORD_Data *rd_res;
   1191     unsigned int rdc_res;
   1192 
   1193     rd_res = NULL;
   1194     rdc_res = 0;
   1195     rlc->nick->flags = (rlc->nick->flags | GNUNET_GNSRECORD_RF_PRIVATE)
   1196                        ^ GNUNET_GNSRECORD_RF_PRIVATE;
   1197     merge_with_nick_records (rlc->nick, rd_count, rd, &rdc_res, &rd_res);
   1198     rlc->rd_ser_len = GNUNET_GNSRECORD_records_get_size (rdc_res, rd_res);
   1199     if (rlc->rd_ser_len < 0)
   1200     {
   1201       GNUNET_break (0);
   1202       GNUNET_free (rd_res);
   1203       rlc->found = GNUNET_NO;
   1204       rlc->rd_ser_len = 0;
   1205       return;
   1206     }
   1207     rlc->res_rd_count = rdc_res;
   1208     rlc->res_rd = GNUNET_malloc (rlc->rd_ser_len);
   1209     if (rlc->rd_ser_len != GNUNET_GNSRECORD_records_serialize (rdc_res,
   1210                                                                rd_res,
   1211                                                                rlc->rd_ser_len,
   1212                                                                rlc->res_rd))
   1213     {
   1214       GNUNET_break (0);
   1215       GNUNET_free (rlc->res_rd);
   1216       rlc->res_rd = NULL;
   1217       rlc->res_rd_count = 0;
   1218       rlc->rd_ser_len = 0;
   1219       GNUNET_free (rd_res);
   1220       rlc->found = GNUNET_NO;
   1221       return;
   1222     }
   1223     GNUNET_free (rd_res);
   1224     GNUNET_free (rlc->nick);
   1225     rlc->nick = NULL;
   1226   }
   1227   else
   1228   {
   1229     rlc->rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
   1230     if (rlc->rd_ser_len < 0)
   1231     {
   1232       GNUNET_break (0);
   1233       rlc->found = GNUNET_NO;
   1234       rlc->rd_ser_len = 0;
   1235       return;
   1236     }
   1237     rlc->res_rd_count = rd_count;
   1238     rlc->res_rd = GNUNET_malloc (rlc->rd_ser_len);
   1239     if (rlc->rd_ser_len != GNUNET_GNSRECORD_records_serialize (rd_count,
   1240                                                                rd,
   1241                                                                rlc->rd_ser_len,
   1242                                                                rlc->res_rd))
   1243     {
   1244       GNUNET_break (0);
   1245       GNUNET_free (rlc->res_rd);
   1246       rlc->res_rd = NULL;
   1247       rlc->res_rd_count = 0;
   1248       rlc->rd_ser_len = 0;
   1249       rlc->found = GNUNET_NO;
   1250       return;
   1251     }
   1252   }
   1253 }
   1254 
   1255 
   1256 /**
   1257  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_SET_EDIT message
   1258  *
   1259  * @param cls client sending the message
   1260  * @param er_msg message of type `struct EditRecordSetMessage`
   1261  * @return #GNUNET_OK if @a er_msg is well-formed
   1262  */
   1263 static int
   1264 check_edit_record_set (void *cls, const struct EditRecordSetMessage *er_msg)
   1265 {
   1266   uint16_t name_len;
   1267   uint16_t editor_hint_len;
   1268   size_t src_size;
   1269   size_t key_len;
   1270 
   1271   (void) cls;
   1272   name_len = ntohs (er_msg->label_len);
   1273   editor_hint_len = ntohs (er_msg->editor_hint_len);
   1274   key_len = ntohs (er_msg->key_len);
   1275   src_size = ntohs (er_msg->gns_header.header.size);
   1276   if (name_len + editor_hint_len + key_len != src_size - sizeof(struct
   1277                                                                 EditRecordSetMessage))
   1278   {
   1279     GNUNET_break (0);
   1280     return GNUNET_SYSERR;
   1281   }
   1282   return GNUNET_OK;
   1283 }
   1284 
   1285 
   1286 /**
   1287  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_SET_EDIT message
   1288  *
   1289  * @param cls client sending the message
   1290  * @param ll_msg message of type `struct EditRecordSetMessage`
   1291  */
   1292 static void
   1293 handle_edit_record_set (void *cls, const struct EditRecordSetMessage *er_msg)
   1294 {
   1295   struct GNUNET_CRYPTO_BlindablePrivateKey zone;
   1296   struct NamestoreClient *nc = cls;
   1297   struct GNUNET_MQ_Envelope *env;
   1298   struct EditRecordSetResponseMessage *rer_msg;
   1299   struct RecordLookupContext rlc;
   1300   const char *name_tmp;
   1301   const char *editor_hint;
   1302   char *conv_name;
   1303   uint16_t name_len;
   1304   uint16_t old_editor_hint_len;
   1305   int res;
   1306   size_t key_len;
   1307   size_t kb_read;
   1308 
   1309   key_len = ntohs (er_msg->key_len);
   1310   name_len = ntohs (er_msg->label_len);
   1311   if ((GNUNET_SYSERR ==
   1312        GNUNET_CRYPTO_read_private_key_from_buffer (&er_msg[1],
   1313                                                    key_len,
   1314                                                    &zone,
   1315                                                    &kb_read)) ||
   1316       (kb_read != key_len))
   1317   {
   1318     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1319                 "Error reading private key\n");
   1320     GNUNET_SERVICE_client_drop (nc->client);
   1321     return;
   1322   }
   1323   name_tmp = (const char *) &er_msg[1] + key_len;
   1324   editor_hint = (const char *) name_tmp + name_len;
   1325   GNUNET_SERVICE_client_continue (nc->client);
   1326   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1327               "Received NAMESTORE_RECORD_SET_EDIT message for name `%s'\n",
   1328               name_tmp);
   1329 
   1330   conv_name = GNUNET_GNSRECORD_string_normalize (name_tmp);
   1331   if (NULL == conv_name)
   1332   {
   1333     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1334                 "Error converting name `%s'\n",
   1335                 name_tmp);
   1336     GNUNET_SERVICE_client_drop (nc->client);
   1337     return;
   1338   }
   1339   name_len = strlen (conv_name) + 1;
   1340   rlc.editor_hint = NULL;
   1341   rlc.label = conv_name;
   1342   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1343               "Looking up without filter\n");
   1344   rlc.filter = GNUNET_GNSRECORD_FILTER_NONE;
   1345   rlc.found = GNUNET_NO;
   1346   rlc.res_rd_count = 0;
   1347   rlc.res_rd = NULL;
   1348   rlc.rd_ser_len = 0;
   1349   rlc.nick = get_nick_record (&zone);
   1350   res = nc->GSN_database->edit_records (nc->GSN_database->cls,
   1351                                         editor_hint,
   1352                                         &zone,
   1353                                         conv_name,
   1354                                         &lookup_it,
   1355                                         &rlc);
   1356 
   1357   old_editor_hint_len = 0;
   1358   if (NULL != rlc.editor_hint)
   1359     old_editor_hint_len = strlen (rlc.editor_hint) + 1;
   1360   env =
   1361     GNUNET_MQ_msg_extra (rer_msg,
   1362                          rlc.rd_ser_len + old_editor_hint_len,
   1363                          GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_SET_EDIT_RESPONSE)
   1364   ;
   1365   rer_msg->editor_hint_len = htons (old_editor_hint_len);
   1366   rer_msg->gns_header.r_id = er_msg->gns_header.r_id;
   1367   rer_msg->rd_count = htons (rlc.res_rd_count);
   1368   rer_msg->rd_len = htons (rlc.rd_ser_len);
   1369   if (GNUNET_YES == rlc.found)
   1370     rer_msg->ec = htons (GNUNET_EC_NONE);
   1371   else if (GNUNET_SYSERR == res)
   1372     rer_msg->ec = htons (GNUNET_EC_NAMESTORE_UNKNOWN);
   1373   else
   1374     rer_msg->ec = htons (GNUNET_EC_NAMESTORE_NO_RESULTS);
   1375   GNUNET_memcpy (&rer_msg[1], rlc.editor_hint, old_editor_hint_len);
   1376   GNUNET_memcpy ((char*) &rer_msg[1] + old_editor_hint_len, rlc.res_rd,
   1377                  rlc.rd_ser_len);
   1378   GNUNET_MQ_send (nc->mq, env);
   1379   GNUNET_free (rlc.editor_hint);
   1380   GNUNET_free (rlc.res_rd);
   1381   GNUNET_free (conv_name);
   1382 }
   1383 
   1384 
   1385 /**
   1386  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_SET_EDIT_CANCEL message
   1387  *
   1388  * @param cls client sending the message
   1389  * @param er_msg message of type `struct EditRecordSetMessage`
   1390  * @return #GNUNET_OK if @a er_msg is well-formed
   1391  */
   1392 static int
   1393 check_edit_record_set_cancel (void *cls, const struct
   1394                               EditRecordSetCancelMessage *er_msg)
   1395 {
   1396   uint16_t name_len;
   1397   uint16_t editor_hint_len;
   1398   uint16_t editor_hint_repl_len;
   1399   size_t src_size;
   1400   size_t key_len;
   1401 
   1402   (void) cls;
   1403   name_len = ntohs (er_msg->label_len);
   1404   editor_hint_len = ntohs (er_msg->editor_hint_len);
   1405   editor_hint_repl_len = ntohs (er_msg->editor_hint_len);
   1406   key_len = ntohs (er_msg->key_len);
   1407   src_size = ntohs (er_msg->gns_header.header.size);
   1408   if (name_len + editor_hint_len + editor_hint_repl_len + key_len != src_size
   1409       - sizeof(struct
   1410                EditRecordSetCancelMessage))
   1411   {
   1412     GNUNET_break (0);
   1413     return GNUNET_SYSERR;
   1414   }
   1415   return GNUNET_OK;
   1416 }
   1417 
   1418 
   1419 /**
   1420  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_SET_EDIT_CANCEL message
   1421  *
   1422  * @param cls client sending the message
   1423  * @param ll_msg message of type `struct EditRecordSetCancelMessage`
   1424  */
   1425 static void
   1426 handle_edit_record_set_cancel (void *cls, const struct
   1427                                EditRecordSetCancelMessage *er_msg)
   1428 {
   1429   struct GNUNET_CRYPTO_BlindablePrivateKey zone;
   1430   struct NamestoreClient *nc = cls;
   1431   struct GNUNET_MQ_Envelope *env;
   1432   struct NamestoreResponseMessage *rer_msg;
   1433   const char *name_tmp;
   1434   const char *editor_hint;
   1435   const char *editor_hint_repl;
   1436   char *conv_name;
   1437   uint16_t name_len;
   1438   uint16_t editor_hint_len;
   1439   int res;
   1440   size_t key_len;
   1441   size_t kb_read;
   1442 
   1443   key_len = ntohs (er_msg->key_len);
   1444   name_len = ntohs (er_msg->label_len);
   1445   editor_hint_len = ntohs (er_msg->editor_hint_len);
   1446   if ((GNUNET_SYSERR ==
   1447        GNUNET_CRYPTO_read_private_key_from_buffer (&er_msg[1],
   1448                                                    key_len,
   1449                                                    &zone,
   1450                                                    &kb_read)) ||
   1451       (kb_read != key_len))
   1452   {
   1453     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1454                 "Error reading private key\n");
   1455     GNUNET_SERVICE_client_drop (nc->client);
   1456     return;
   1457   }
   1458   name_tmp = (const char *) &er_msg[1] + key_len;
   1459   editor_hint = (const char *) name_tmp + name_len;
   1460   editor_hint_repl = (const char *) name_tmp + name_len + editor_hint_len;
   1461   GNUNET_SERVICE_client_continue (nc->client);
   1462   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1463               "Received NAMESTORE_RECORD_SET_EDIT message for name `%s'\n",
   1464               name_tmp);
   1465 
   1466   conv_name = GNUNET_GNSRECORD_string_normalize (name_tmp);
   1467   if (NULL == conv_name)
   1468   {
   1469     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1470                 "Error converting name `%s'\n",
   1471                 name_tmp);
   1472     GNUNET_SERVICE_client_drop (nc->client);
   1473     return;
   1474   }
   1475   name_len = strlen (conv_name) + 1;
   1476   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1477               "Clearing editor hint\n");
   1478   res = nc->GSN_database->clear_editor_hint (nc->GSN_database->cls,
   1479                                              editor_hint,
   1480                                              editor_hint_repl,
   1481                                              &zone,
   1482                                              conv_name);
   1483   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1484               "Clearing editor hint %s\n", (GNUNET_SYSERR == res) ? "failed." :
   1485               "successful.");
   1486 
   1487   env =
   1488     GNUNET_MQ_msg (rer_msg,
   1489                    GNUNET_MESSAGE_TYPE_NAMESTORE_GENERIC_RESPONSE);
   1490   rer_msg->gns_header.r_id = er_msg->gns_header.r_id;
   1491   rer_msg->ec = htons ((GNUNET_OK == res) ? GNUNET_EC_NONE :
   1492                        GNUNET_EC_NAMESTORE_BACKEND_FAILED);
   1493   GNUNET_MQ_send (nc->mq, env);
   1494   GNUNET_free (conv_name);
   1495 }
   1496 
   1497 
   1498 /**
   1499  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP message
   1500  *
   1501  * @param cls client sending the message
   1502  * @param ll_msg message of type `struct LabelLookupMessage`
   1503  * @return #GNUNET_OK if @a ll_msg is well-formed
   1504  */
   1505 static int
   1506 check_record_lookup (void *cls, const struct LabelLookupMessage *ll_msg)
   1507 {
   1508   uint32_t name_len;
   1509   size_t src_size;
   1510   size_t key_len;
   1511 
   1512   (void) cls;
   1513   name_len = ntohs (ll_msg->label_len);
   1514   key_len = ntohs (ll_msg->key_len);
   1515   src_size = ntohs (ll_msg->gns_header.header.size);
   1516   if (name_len + key_len != src_size - sizeof(struct LabelLookupMessage))
   1517   {
   1518     GNUNET_break (0);
   1519     return GNUNET_SYSERR;
   1520   }
   1521   return GNUNET_OK;
   1522 }
   1523 
   1524 
   1525 /**
   1526  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP message
   1527  *
   1528  * @param cls client sending the message
   1529  * @param ll_msg message of type `struct LabelLookupMessage`
   1530  */
   1531 static void
   1532 handle_record_lookup (void *cls, const struct LabelLookupMessage *ll_msg)
   1533 {
   1534   struct GNUNET_CRYPTO_BlindablePrivateKey zone;
   1535   struct NamestoreClient *nc = cls;
   1536   struct GNUNET_MQ_Envelope *env;
   1537   struct LabelLookupResponseMessage *llr_msg;
   1538   struct RecordLookupContext rlc;
   1539   const char *name_tmp;
   1540   char *res_name;
   1541   char *conv_name;
   1542   uint32_t name_len;
   1543   int res;
   1544   size_t key_len;
   1545   size_t kb_read;
   1546 
   1547   key_len = ntohs (ll_msg->key_len);
   1548   if ((GNUNET_SYSERR ==
   1549        GNUNET_CRYPTO_read_private_key_from_buffer (&ll_msg[1],
   1550                                                    key_len,
   1551                                                    &zone,
   1552                                                    &kb_read)) ||
   1553       (kb_read != key_len))
   1554   {
   1555     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1556                 "Error reading private key\n");
   1557     GNUNET_SERVICE_client_drop (nc->client);
   1558     return;
   1559   }
   1560   name_tmp = (const char *) &ll_msg[1] + key_len;
   1561   GNUNET_SERVICE_client_continue (nc->client);
   1562   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1563               "Received NAMESTORE_RECORD_LOOKUP message for name `%s'\n",
   1564               name_tmp);
   1565 
   1566   conv_name = GNUNET_GNSRECORD_string_normalize (name_tmp);
   1567   if (NULL == conv_name)
   1568   {
   1569     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1570                 "Error converting name `%s'\n",
   1571                 name_tmp);
   1572     GNUNET_SERVICE_client_drop (nc->client);
   1573     return;
   1574   }
   1575   name_len = strlen (conv_name) + 1;
   1576   rlc.editor_hint = NULL;
   1577   rlc.label = conv_name;
   1578   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1579               "Looking up with filter %u\n", ntohs (ll_msg->filter));
   1580   rlc.filter = ntohs (ll_msg->filter);
   1581   rlc.found = GNUNET_NO;
   1582   rlc.res_rd_count = 0;
   1583   rlc.res_rd = NULL;
   1584   rlc.rd_ser_len = 0;
   1585   rlc.nick = get_nick_record (&zone);
   1586   res = nc->GSN_database->lookup_records (nc->GSN_database->cls,
   1587                                           &zone,
   1588                                           conv_name,
   1589                                           &lookup_it,
   1590                                           &rlc);
   1591   env =
   1592     GNUNET_MQ_msg_extra (llr_msg,
   1593                          key_len + name_len + rlc.rd_ser_len,
   1594                          GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP_RESPONSE);
   1595   llr_msg->gns_header.r_id = ll_msg->gns_header.r_id;
   1596   GNUNET_memcpy (&llr_msg[1], &ll_msg[1], key_len);
   1597   llr_msg->key_len = ll_msg->key_len;
   1598   llr_msg->name_len = htons (name_len);
   1599   llr_msg->rd_count = htons (rlc.res_rd_count);
   1600   llr_msg->rd_len = htons (rlc.rd_ser_len);
   1601   llr_msg->reserved = htons (0);
   1602   res_name = ((char *) &llr_msg[1]) + key_len;
   1603   if (GNUNET_YES == rlc.found)
   1604     llr_msg->found = htons (GNUNET_YES);
   1605   else if (GNUNET_SYSERR == res)
   1606     llr_msg->found = htons (GNUNET_SYSERR);
   1607   else
   1608     llr_msg->found = htons (GNUNET_NO);
   1609   GNUNET_memcpy (res_name, conv_name, name_len);
   1610   GNUNET_memcpy (&res_name[name_len], rlc.res_rd, rlc.rd_ser_len);
   1611   GNUNET_MQ_send (nc->mq, env);
   1612   GNUNET_free (rlc.editor_hint);
   1613   GNUNET_free (rlc.res_rd);
   1614   GNUNET_free (conv_name);
   1615 }
   1616 
   1617 
   1618 /**
   1619  * Checks a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE message
   1620  *
   1621  * @param cls client sending the message
   1622  * @param rp_msg message of type `struct RecordStoreMessage`
   1623  * @return #GNUNET_OK if @a rp_msg is well-formed
   1624  */
   1625 static int
   1626 check_record_store (void *cls, const struct RecordStoreMessage *rp_msg)
   1627 {
   1628   size_t msg_size;
   1629   size_t min_size_exp;
   1630   size_t rd_set_count;
   1631   size_t key_len;
   1632 
   1633   (void) cls;
   1634   msg_size = ntohs (rp_msg->gns_header.header.size);
   1635   rd_set_count = ntohs (rp_msg->rd_set_count);
   1636   key_len = ntohs (rp_msg->key_len);
   1637 
   1638   min_size_exp = sizeof(*rp_msg) + key_len + sizeof (struct RecordSet)
   1639                  * rd_set_count;
   1640   if (msg_size < min_size_exp)
   1641   {
   1642     GNUNET_break (0);
   1643     return GNUNET_SYSERR;
   1644   }
   1645   return GNUNET_OK;
   1646 }
   1647 
   1648 
   1649 struct LookupExistingRecordsContext
   1650 {
   1651 
   1652   /**
   1653    * The expiration of the existing records or tombstone
   1654    */
   1655   struct GNUNET_TIME_Absolute exp;
   1656 
   1657   /**
   1658    * Whether the existing record set consists only of a tombstone
   1659    * (e.g. is "empty")
   1660    */
   1661   int only_tombstone;
   1662 
   1663 };
   1664 
   1665 
   1666 /**
   1667  * Check if set contains a tombstone, store if necessary
   1668  *
   1669  * @param cls a `struct GNUNET_GNSRECORD_Data **` for storing the nick (if found)
   1670  * @param seq sequence number of the record, MUST NOT BE ZERO
   1671  * @param private_key the private key of the zone (unused)
   1672  * @param label should be #GNUNET_GNS_EMPTY_LABEL_AT
   1673  * @param rd_count number of records in @a rd
   1674  * @param rd records stored under @a label in the zone
   1675  */
   1676 static void
   1677 get_existing_rd_exp (void *cls,
   1678                      uint64_t seq,
   1679                      const char *editor_hint,
   1680                      const struct
   1681                      GNUNET_CRYPTO_BlindablePrivateKey *private_key,
   1682                      const char *label,
   1683                      unsigned int rd_count,
   1684                      const struct GNUNET_GNSRECORD_Data *rd)
   1685 {
   1686   struct LookupExistingRecordsContext *lctx = cls;
   1687   struct GNUNET_GNSRECORD_Data rd_pub[rd_count];
   1688   unsigned int rd_pub_count;
   1689   char *emsg;
   1690 
   1691   if ((1 == rd_count) &&
   1692       (GNUNET_GNSRECORD_TYPE_TOMBSTONE == rd[0].record_type))
   1693   {
   1694     /* This record set contains only a tombstone! */
   1695     lctx->only_tombstone = GNUNET_YES;
   1696   }
   1697   if (GNUNET_OK !=
   1698       GNUNET_GNSRECORD_normalize_record_set (label,
   1699                                              rd,
   1700                                              rd_count,
   1701                                              rd_pub,
   1702                                              &rd_pub_count,
   1703                                              &lctx->exp,
   1704                                              GNUNET_GNSRECORD_FILTER_OMIT_PRIVATE,
   1705                                              &emsg))
   1706   {
   1707     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1708                 "%s\n", emsg);
   1709     GNUNET_free (emsg);
   1710   }
   1711 }
   1712 
   1713 
   1714 static enum GNUNET_ErrorCode
   1715 store_record_set (struct NamestoreClient *nc,
   1716                   const struct GNUNET_CRYPTO_BlindablePrivateKey *private_key,
   1717                   const struct RecordSet *rd_set,
   1718                   ssize_t *len)
   1719 {
   1720   size_t name_len;
   1721   size_t rd_ser_len;
   1722   const char *name_tmp;
   1723   const char *rd_ser;
   1724   char *emsg;
   1725   char *conv_name;
   1726   unsigned int rd_count;
   1727   int res;
   1728   enum GNUNET_ErrorCode ec;
   1729   struct GNUNET_TIME_Absolute new_block_exp;
   1730   struct LookupExistingRecordsContext lctx;
   1731   *len = sizeof (struct RecordSet);
   1732 
   1733   ec = GNUNET_EC_NONE;
   1734   lctx.only_tombstone = GNUNET_NO;
   1735   lctx.exp = GNUNET_TIME_UNIT_ZERO_ABS;
   1736   new_block_exp = GNUNET_TIME_UNIT_ZERO_ABS;
   1737   name_len = ntohs (rd_set->name_len);
   1738   *len += name_len;
   1739   rd_count = ntohs (rd_set->rd_count);
   1740   rd_ser_len = ntohs (rd_set->rd_len);
   1741   *len += rd_ser_len;
   1742   name_tmp = (const char *) &rd_set[1];
   1743   rd_ser = &name_tmp[name_len];
   1744   {
   1745     struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)];
   1746 
   1747     /* Extracting and converting private key */
   1748     conv_name = GNUNET_GNSRECORD_string_normalize (name_tmp);
   1749     if (NULL == conv_name)
   1750     {
   1751       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1752                   "Error normalizing name `%s'\n",
   1753                   name_tmp);
   1754       return GNUNET_EC_NAMESTORE_LABEL_INVALID;
   1755     }
   1756 
   1757     /* Check name for validity */
   1758     if (GNUNET_OK != GNUNET_GNSRECORD_label_check (conv_name, &emsg))
   1759     {
   1760       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1761                   "Label invalid: `%s'\n",
   1762                   emsg);
   1763       GNUNET_free (emsg);
   1764       GNUNET_free (conv_name);
   1765       return GNUNET_EC_NAMESTORE_LABEL_INVALID;
   1766     }
   1767 
   1768     if (GNUNET_OK !=
   1769         GNUNET_GNSRECORD_records_deserialize (rd_ser_len, rd_ser, rd_count,
   1770                                               rd))
   1771     {
   1772       GNUNET_free (conv_name);
   1773       return GNUNET_EC_NAMESTORE_RECORD_DATA_INVALID;
   1774     }
   1775 
   1776     GNUNET_STATISTICS_update (statistics,
   1777                               "Well-formed store requests received",
   1778                               1,
   1779                               GNUNET_NO);
   1780     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1781                 "Creating %u records for name `%s'\n",
   1782                 (unsigned int) rd_count,
   1783                 conv_name);
   1784     if ((0 == rd_count) &&
   1785         (GNUNET_NO == nc->GSN_database->lookup_records (nc->GSN_database->cls,
   1786                                                         private_key,
   1787                                                         conv_name,
   1788                                                         &get_existing_rd_exp,
   1789                                                         &lctx)))
   1790     {
   1791       /* This name does not exist, so cannot be removed */
   1792       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1793                   "Name `%s' does not exist, no deletion required\n",
   1794                   conv_name);
   1795       res = GNUNET_NO;
   1796       ec = GNUNET_EC_NAMESTORE_RECORD_NOT_FOUND;
   1797     }
   1798     else
   1799     {
   1800       /* remove "NICK" records, unless this is for the
   1801        #GNUNET_GNS_EMPTY_LABEL_AT label
   1802        We may need one additional record later for tombstone.
   1803        FIXME: Since we must normalize the record set (check for
   1804        consistency etc) we have to iterate the set twice.
   1805        May be inefficient.
   1806        We cannot really move the nick caching into GNSRECORD.
   1807        */
   1808       struct GNUNET_GNSRECORD_Data rd_clean[GNUNET_NZL (rd_count)];
   1809       struct GNUNET_GNSRECORD_Data rd_nf[GNUNET_NZL (rd_count) + 1];
   1810       unsigned int rd_clean_off;
   1811       unsigned int rd_nf_count;
   1812       int have_nick;
   1813 
   1814       rd_clean_off = 0;
   1815       have_nick = GNUNET_NO;
   1816       for (unsigned int i = 0; i < rd_count; i++)
   1817       {
   1818         rd_clean[rd_clean_off] = rd[i];
   1819 
   1820         if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) ||
   1821             (GNUNET_GNSRECORD_TYPE_NICK != rd[i].record_type))
   1822           rd_clean_off++;
   1823 
   1824         if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) &&
   1825             (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type))
   1826         {
   1827           cache_nick (private_key, &rd[i]);
   1828           have_nick = GNUNET_YES;
   1829         }
   1830       }
   1831       if (GNUNET_OK !=
   1832           GNUNET_GNSRECORD_normalize_record_set (conv_name,
   1833                                                  rd_clean,
   1834                                                  rd_clean_off,
   1835                                                  rd_nf,
   1836                                                  &rd_nf_count,
   1837                                                  &new_block_exp,
   1838                                                  GNUNET_GNSRECORD_FILTER_INCLUDE_MAINTENANCE,
   1839                                                  &emsg))
   1840       {
   1841         GNUNET_free (conv_name);
   1842         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1843                     "Error normalizing record set: `%s'\n",
   1844                     emsg);
   1845         GNUNET_free (emsg);
   1846         return GNUNET_EC_NAMESTORE_RECORD_DATA_INVALID;
   1847       }
   1848       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1849                   "%u/%u records before tombstone\n", rd_nf_count,
   1850                   rd_clean_off);
   1851       /*
   1852        * If existing_block_exp is 0, then there was no record set
   1853        * and no tombstone.
   1854        * Otherwise, if the existing block expiration is after the
   1855        * new block expiration would be, we need to add a tombstone
   1856        * or update it.
   1857        */
   1858       if (GNUNET_TIME_absolute_cmp (new_block_exp, <=, lctx.exp))
   1859       {
   1860         rd_nf[rd_nf_count].record_type = GNUNET_GNSRECORD_TYPE_TOMBSTONE;
   1861         rd_nf[rd_nf_count].expiration_time =
   1862           lctx.exp.abs_value_us;
   1863         rd_nf[rd_nf_count].data = NULL;
   1864         rd_nf[rd_nf_count].data_size = 0;
   1865         rd_nf[rd_nf_count].flags = GNUNET_GNSRECORD_RF_PRIVATE
   1866                                    | GNUNET_GNSRECORD_RF_MAINTENANCE;
   1867         rd_nf_count++;
   1868       }
   1869       if ((0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT, conv_name)) &&
   1870           (GNUNET_NO == have_nick))
   1871       {
   1872         cache_nick (private_key, NULL);
   1873       }
   1874       res = nc->GSN_database->store_records (nc->GSN_database->cls,
   1875                                              private_key,
   1876                                              conv_name,
   1877                                              rd_nf_count,
   1878                                              rd_nf);
   1879       /* If after a store there is only a TOMBSTONE left, and
   1880        * there was >1 record under this label found (the tombstone; indicated
   1881        * through res != GNUNET_NO) then we should return "NOT FOUND" == GNUNET_NO
   1882        */
   1883       if ((GNUNET_SYSERR != res) &&
   1884           (0 == rd_count) &&
   1885           (1 == rd_nf_count) &&
   1886           (GNUNET_GNSRECORD_TYPE_TOMBSTONE == rd_nf[0].record_type) &&
   1887           (GNUNET_YES == lctx.only_tombstone))
   1888       {
   1889         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1890                     "Client tried to remove non-existent record\n");
   1891         ec = GNUNET_EC_NAMESTORE_RECORD_NOT_FOUND;
   1892       }
   1893     }
   1894 
   1895     if (GNUNET_SYSERR == res)
   1896     {
   1897       /* store not successful, no need to tell monitors */
   1898       GNUNET_free (conv_name);
   1899       return GNUNET_EC_NAMESTORE_STORE_FAILED;
   1900     }
   1901   }
   1902   return ec;
   1903 }
   1904 
   1905 
   1906 /**
   1907  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE message
   1908  *
   1909  * @param cls client sending the message
   1910  * @param rp_msg message of type `struct RecordStoreMessage`
   1911  */
   1912 static void
   1913 handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg)
   1914 {
   1915   struct GNUNET_CRYPTO_BlindablePrivateKey zone;
   1916   struct NamestoreClient *nc = cls;
   1917   uint32_t rid;
   1918   uint16_t rd_set_count;
   1919   const char *buf;
   1920   ssize_t read;
   1921   size_t key_len;
   1922   size_t kb_read;
   1923   size_t rp_msg_len;
   1924   size_t rs_len;
   1925   size_t rs_off;
   1926   struct StoreActivity *sa;
   1927   struct RecordSet *rs;
   1928   enum GNUNET_ErrorCode res;
   1929 
   1930   key_len = ntohs (rp_msg->key_len);
   1931   rp_msg_len = ntohs (rp_msg->gns_header.header.size);
   1932   rs_off = sizeof (*rp_msg) + key_len;
   1933   rs_len = rp_msg_len - rs_off;
   1934   if ((GNUNET_SYSERR ==
   1935        GNUNET_CRYPTO_read_private_key_from_buffer (&rp_msg[1],
   1936                                                    key_len,
   1937                                                    &zone,
   1938                                                    &kb_read)) ||
   1939       (kb_read != key_len))
   1940   {
   1941     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1942                 "Error reading private key\n");
   1943     GNUNET_SERVICE_client_drop (nc->client);
   1944     return;
   1945   }
   1946   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1947               "Received NAMESTORE_RECORD_STORE message\n");
   1948   rid = ntohl (rp_msg->gns_header.r_id);
   1949   rd_set_count = ntohs (rp_msg->rd_set_count);
   1950   buf = (const char *) rp_msg + rs_off;
   1951   if (GNUNET_YES == ntohs (rp_msg->single_tx))
   1952     nc->GSN_database->begin_tx (nc->GSN_database->cls);
   1953   for (int i = 0; i < rd_set_count; i++)
   1954   {
   1955     rs = (struct RecordSet *) buf;
   1956     res = store_record_set (nc, &zone,
   1957                             rs, &read);
   1958     if (GNUNET_EC_NONE != res)
   1959     {
   1960       if (GNUNET_YES == ntohs (rp_msg->single_tx))
   1961         nc->GSN_database->rollback_tx (nc->GSN_database->cls);
   1962       send_store_response (nc, res, rid);
   1963       GNUNET_SERVICE_client_continue (nc->client);
   1964       return;
   1965     }
   1966     buf += read;
   1967   }
   1968   if (GNUNET_YES == ntohs (rp_msg->single_tx))
   1969     nc->GSN_database->commit_tx (nc->GSN_database->cls);
   1970   sa = GNUNET_malloc (sizeof(struct StoreActivity) + rs_len);
   1971   GNUNET_CONTAINER_DLL_insert (sa_head, sa_tail, sa);
   1972   sa->nc = nc;
   1973   sa->rs = (struct RecordSet *) &sa[1];
   1974   sa->rd_set_count = rd_set_count;
   1975   GNUNET_memcpy (&sa[1], (char *) rp_msg + rs_off, rs_len);
   1976   sa->rid = rid;
   1977   sa->rd_set_pos = 0;
   1978   sa->private_key = zone;
   1979   sa->zm_pos = monitor_head;
   1980   continue_store_activity (sa, GNUNET_YES);
   1981 }
   1982 
   1983 
   1984 /**
   1985  * Context for record remove operations passed from #handle_zone_to_name to
   1986  * #handle_zone_to_name_it as closure
   1987  */
   1988 struct ZoneToNameCtx
   1989 {
   1990   /**
   1991    * Namestore client
   1992    */
   1993   struct NamestoreClient *nc;
   1994 
   1995   /**
   1996    * Request id (to be used in the response to the client).
   1997    */
   1998   uint32_t rid;
   1999 
   2000   /**
   2001    * Set to #GNUNET_OK on success, #GNUNET_SYSERR on error.  Note that
   2002    * not finding a name for the zone still counts as a 'success' here,
   2003    * as this field is about the success of executing the IPC protocol.
   2004    */
   2005   enum GNUNET_ErrorCode ec;
   2006 };
   2007 
   2008 
   2009 /**
   2010  * Zone to name iterator
   2011  *
   2012  * @param cls struct ZoneToNameCtx *
   2013  * @param seq sequence number of the record, MUST NOT BE ZERO
   2014  * @param zone_key the zone key
   2015  * @param name name
   2016  * @param rd_count number of records in @a rd
   2017  * @param rd record data
   2018  */
   2019 static void
   2020 handle_zone_to_name_it (void *cls,
   2021                         uint64_t seq,
   2022                         const char *editor_hint,
   2023                         const struct GNUNET_CRYPTO_BlindablePrivateKey *zone_key
   2024                         ,
   2025                         const char *name,
   2026                         unsigned int rd_count,
   2027                         const struct GNUNET_GNSRECORD_Data *rd)
   2028 {
   2029   struct ZoneToNameCtx *ztn_ctx = cls;
   2030   struct GNUNET_MQ_Envelope *env;
   2031   struct ZoneToNameResponseMessage *ztnr_msg;
   2032   size_t name_len;
   2033   size_t key_len;
   2034   ssize_t rd_ser_len;
   2035   size_t msg_size;
   2036   char *name_tmp;
   2037   char *rd_tmp;
   2038 
   2039   GNUNET_assert (0 != seq);
   2040   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2041               "Found result for zone-to-name lookup: `%s'\n",
   2042               name);
   2043   ztn_ctx->ec = GNUNET_EC_NONE;
   2044   name_len = (NULL == name) ? 0 : strlen (name) + 1;
   2045   rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
   2046   if (rd_ser_len < 0)
   2047   {
   2048     GNUNET_break (0);
   2049     ztn_ctx->ec = htonl (GNUNET_EC_NAMESTORE_UNKNOWN);
   2050     return;
   2051   }
   2052   key_len = GNUNET_CRYPTO_blindable_sk_get_length (zone_key);
   2053   msg_size = sizeof(struct ZoneToNameResponseMessage)
   2054              + name_len + rd_ser_len + key_len;
   2055   if (msg_size >= GNUNET_MAX_MESSAGE_SIZE)
   2056   {
   2057     GNUNET_break (0);
   2058     ztn_ctx->ec = GNUNET_EC_NAMESTORE_RECORD_TOO_BIG;
   2059     return;
   2060   }
   2061   env =
   2062     GNUNET_MQ_msg_extra (ztnr_msg,
   2063                          key_len + name_len + rd_ser_len,
   2064                          GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE);
   2065   ztnr_msg->gns_header.header.size = htons (msg_size);
   2066   ztnr_msg->gns_header.r_id = htonl (ztn_ctx->rid);
   2067   ztnr_msg->ec = htonl (ztn_ctx->ec);
   2068   ztnr_msg->rd_len = htons (rd_ser_len);
   2069   ztnr_msg->rd_count = htons (rd_count);
   2070   ztnr_msg->name_len = htons (name_len);
   2071   ztnr_msg->key_len = htons (key_len);
   2072   GNUNET_CRYPTO_write_blindable_sk_to_buffer (zone_key,
   2073                                               &ztnr_msg[1],
   2074                                               key_len);
   2075   name_tmp = (char *) &ztnr_msg[1] + key_len;
   2076   GNUNET_memcpy (name_tmp, name, name_len);
   2077   rd_tmp = &name_tmp[name_len];
   2078   GNUNET_assert (
   2079     rd_ser_len ==
   2080     GNUNET_GNSRECORD_records_serialize (rd_count, rd, rd_ser_len, rd_tmp));
   2081   ztn_ctx->ec = GNUNET_EC_NONE;
   2082   GNUNET_MQ_send (ztn_ctx->nc->mq, env);
   2083 }
   2084 
   2085 
   2086 static enum GNUNET_GenericReturnValue
   2087 check_zone_to_name (void *cls,
   2088                     const struct ZoneToNameMessage *zis_msg)
   2089 {
   2090   return GNUNET_OK;
   2091 }
   2092 
   2093 
   2094 /**
   2095  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME message
   2096  *
   2097  * @param cls client client sending the message
   2098  * @param ztn_msg message of type 'struct ZoneToNameMessage'
   2099  */
   2100 static void
   2101 handle_zone_to_name (void *cls, const struct ZoneToNameMessage *ztn_msg)
   2102 {
   2103   struct GNUNET_CRYPTO_BlindablePrivateKey zone;
   2104   struct GNUNET_CRYPTO_BlindablePublicKey value_zone;
   2105   struct NamestoreClient *nc = cls;
   2106   struct ZoneToNameCtx ztn_ctx;
   2107   struct GNUNET_MQ_Envelope *env;
   2108   struct ZoneToNameResponseMessage *ztnr_msg;
   2109   size_t key_len;
   2110   size_t pkey_len;
   2111   size_t kb_read;
   2112 
   2113   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ZONE_TO_NAME message\n");
   2114   ztn_ctx.rid = ntohl (ztn_msg->gns_header.r_id);
   2115   ztn_ctx.nc = nc;
   2116   ztn_ctx.ec = GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND;
   2117   key_len = ntohs (ztn_msg->key_len);
   2118   if ((GNUNET_SYSERR ==
   2119        GNUNET_CRYPTO_read_private_key_from_buffer (&ztn_msg[1],
   2120                                                    key_len,
   2121                                                    &zone,
   2122                                                    &kb_read)) ||
   2123       (kb_read != key_len))
   2124   {
   2125     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2126                 "Error parsing private key.\n");
   2127     GNUNET_SERVICE_client_drop (nc->client);
   2128     GNUNET_break (0);
   2129     return;
   2130   }
   2131   pkey_len = ntohs (ztn_msg->pkey_len);
   2132   if ((GNUNET_SYSERR ==
   2133        GNUNET_CRYPTO_read_blindable_pk_from_buffer ((char*) &ztn_msg[1]
   2134                                                     + key_len,
   2135                                                     pkey_len,
   2136                                                     &value_zone,
   2137                                                     &kb_read)) ||
   2138       (kb_read != pkey_len))
   2139   {
   2140     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2141                 "Error parsing public key.\n");
   2142     GNUNET_SERVICE_client_drop (nc->client);
   2143     GNUNET_break (0);
   2144     return;
   2145   }
   2146   if (GNUNET_SYSERR == nc->GSN_database->zone_to_name (nc->GSN_database->cls,
   2147                                                        &zone,
   2148                                                        &value_zone,
   2149                                                        &handle_zone_to_name_it,
   2150                                                        &ztn_ctx))
   2151   {
   2152     /* internal error, hang up instead of signalling something
   2153        that might be wrong */
   2154     GNUNET_break (0);
   2155     GNUNET_SERVICE_client_drop (nc->client);
   2156     return;
   2157   }
   2158   if (GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND == ztn_ctx.ec)
   2159   {
   2160     /* no result found, send empty response */
   2161     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2162                 "Found no result for zone-to-name lookup.\n");
   2163     env = GNUNET_MQ_msg (ztnr_msg,
   2164                          GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE);
   2165     ztnr_msg->gns_header.r_id = ztn_msg->gns_header.r_id;
   2166     ztnr_msg->ec = htonl (GNUNET_EC_NAMESTORE_ZONE_NOT_FOUND);
   2167     GNUNET_MQ_send (nc->mq, env);
   2168   }
   2169   GNUNET_SERVICE_client_continue (nc->client);
   2170 }
   2171 
   2172 
   2173 /**
   2174  * Context for record remove operations passed from
   2175  * #run_zone_iteration_round to #zone_iterate_proc as closure
   2176  */
   2177 struct ZoneIterationProcResult
   2178 {
   2179   /**
   2180    * The zone iteration handle
   2181    */
   2182   struct ZoneIteration *zi;
   2183 
   2184   /**
   2185    * Number of results left to be returned in this iteration.
   2186    */
   2187   uint64_t limit;
   2188 
   2189   /**
   2190    * Skip a result and run again unless GNUNET_NO
   2191    */
   2192   int run_again;
   2193 };
   2194 
   2195 
   2196 /**
   2197  * Process results for zone iteration from database
   2198  *
   2199  * @param cls struct ZoneIterationProcResult
   2200  * @param seq sequence number of the record, MUST NOT BE ZERO
   2201  * @param zone_key the zone key
   2202  * @param name name
   2203  * @param rd_count number of records for this name
   2204  * @param rd record data
   2205  */
   2206 static void
   2207 zone_iterate_proc (void *cls,
   2208                    uint64_t seq,
   2209                    const char *editor_hint,
   2210                    const struct GNUNET_CRYPTO_BlindablePrivateKey *zone_key,
   2211                    const char *name,
   2212                    unsigned int rd_count,
   2213                    const struct GNUNET_GNSRECORD_Data *rd)
   2214 {
   2215   struct ZoneIterationProcResult *proc = cls;
   2216 
   2217   GNUNET_assert (0 != seq);
   2218   if ((NULL == zone_key) && (NULL == name))
   2219   {
   2220     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Iteration done\n");
   2221     return;
   2222   }
   2223   if ((NULL == zone_key) || (NULL == name))
   2224   {
   2225     /* what is this!? should never happen */
   2226     GNUNET_break (0);
   2227     return;
   2228   }
   2229   if (0 == proc->limit)
   2230   {
   2231     /* what is this!? should never happen */
   2232     GNUNET_break (0);
   2233     return;
   2234   }
   2235   proc->zi->seq = seq;
   2236   if (0 < send_lookup_response_with_filter (proc->zi->nc,
   2237                                             proc->zi->request_id,
   2238                                             zone_key,
   2239                                             name,
   2240                                             rd_count,
   2241                                             rd,
   2242                                             proc->zi->filter))
   2243     proc->limit--;
   2244   else
   2245     proc->run_again = GNUNET_YES;
   2246 }
   2247 
   2248 
   2249 /**
   2250  * Perform the next round of the zone iteration.
   2251  *
   2252  * @param zi zone iterator to process
   2253  * @param limit number of results to return in one pass
   2254  */
   2255 static void
   2256 run_zone_iteration_round (struct ZoneIteration *zi, uint64_t limit)
   2257 {
   2258   struct ZoneIterationProcResult proc;
   2259   struct GNUNET_TIME_Absolute start;
   2260   struct GNUNET_TIME_Relative duration;
   2261   struct NamestoreClient *nc = zi->nc;
   2262 
   2263   memset (&proc, 0, sizeof(proc));
   2264   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2265               "Asked to return up to %llu records at position %llu\n",
   2266               (unsigned long long) limit,
   2267               (unsigned long long) zi->seq);
   2268   proc.zi = zi;
   2269   proc.limit = limit;
   2270   proc.run_again = GNUNET_YES;
   2271   start = GNUNET_TIME_absolute_get ();
   2272   while (GNUNET_YES == proc.run_again)
   2273   {
   2274     proc.run_again = GNUNET_NO;
   2275     GNUNET_break (GNUNET_SYSERR !=
   2276                   nc->GSN_database->iterate_records (nc->GSN_database->cls,
   2277                                                      (GNUNET_YES ==
   2278                                                       GNUNET_is_zero (
   2279                                                         &zi->zone))
   2280                                                ? NULL
   2281                                                : &zi->zone,
   2282                                                      zi->seq,
   2283                                                      proc.limit,
   2284                                                      &zone_iterate_proc,
   2285                                                      &proc));
   2286   }
   2287   duration = GNUNET_TIME_absolute_get_duration (start);
   2288   duration = GNUNET_TIME_relative_divide (duration, limit - proc.limit);
   2289   GNUNET_STATISTICS_set (statistics,
   2290                          "NAMESTORE iteration delay (μs/record)",
   2291                          duration.rel_value_us,
   2292                          GNUNET_NO);
   2293   if (0 == proc.limit)
   2294     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2295                 "Returned %llu results, more results available\n",
   2296                 (unsigned long long) limit);
   2297   zi->send_end = (0 != proc.limit);
   2298   zone_iteration_done_client_continue (zi);
   2299 }
   2300 
   2301 
   2302 static enum GNUNET_GenericReturnValue
   2303 check_iteration_start (void *cls,
   2304                        const struct ZoneIterationStartMessage *zis_msg)
   2305 {
   2306   uint16_t size;
   2307   size_t key_len;
   2308 
   2309   size = ntohs (zis_msg->gns_header.header.size);
   2310   key_len = ntohs (zis_msg->key_len);
   2311 
   2312   if (size < key_len + sizeof(*zis_msg))
   2313   {
   2314     GNUNET_break (0);
   2315     return GNUNET_SYSERR;
   2316   }
   2317   return GNUNET_OK;
   2318 }
   2319 
   2320 
   2321 /**
   2322  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START message
   2323  *
   2324  * @param cls the client sending the message
   2325  * @param zis_msg message from the client
   2326  */
   2327 static void
   2328 handle_iteration_start (void *cls,
   2329                         const struct ZoneIterationStartMessage *zis_msg)
   2330 {
   2331   struct GNUNET_CRYPTO_BlindablePrivateKey zone;
   2332   struct NamestoreClient *nc = cls;
   2333   struct ZoneIteration *zi;
   2334   size_t key_len;
   2335   size_t kb_read;
   2336 
   2337   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2338               "Received ZONE_ITERATION_START message\n");
   2339   key_len = ntohs (zis_msg->key_len);
   2340   zi = GNUNET_new (struct ZoneIteration);
   2341   if (0 < key_len)
   2342   {
   2343     if ((GNUNET_SYSERR ==
   2344          GNUNET_CRYPTO_read_private_key_from_buffer (&zis_msg[1],
   2345                                                      key_len,
   2346                                                      &zone,
   2347                                                      &kb_read)) ||
   2348         (kb_read != key_len))
   2349     {
   2350       GNUNET_SERVICE_client_drop (nc->client);
   2351       GNUNET_free (zi);
   2352       return;
   2353     }
   2354     zi->zone = zone;
   2355   }
   2356   zi->request_id = ntohl (zis_msg->gns_header.r_id);
   2357   zi->filter = ntohs (zis_msg->filter);
   2358   zi->offset = 0;
   2359   zi->nc = nc;
   2360   GNUNET_CONTAINER_DLL_insert (nc->op_head, nc->op_tail, zi);
   2361   run_zone_iteration_round (zi, 1);
   2362 }
   2363 
   2364 
   2365 /**
   2366  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP message
   2367  *
   2368  * @param cls the client sending the message
   2369  * @param zis_msg message from the client
   2370  */
   2371 static void
   2372 handle_iteration_stop (void *cls,
   2373                        const struct ZoneIterationStopMessage *zis_msg)
   2374 {
   2375   struct NamestoreClient *nc = cls;
   2376   struct ZoneIteration *zi;
   2377   uint32_t rid;
   2378 
   2379   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2380               "Received ZONE_ITERATION_STOP message\n");
   2381   rid = ntohl (zis_msg->gns_header.r_id);
   2382   for (zi = nc->op_head; NULL != zi; zi = zi->next)
   2383     if (zi->request_id == rid)
   2384       break;
   2385   if (NULL == zi)
   2386   {
   2387     GNUNET_break (0);
   2388     GNUNET_SERVICE_client_drop (nc->client);
   2389     return;
   2390   }
   2391   GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, zi);
   2392   GNUNET_free (zi);
   2393   GNUNET_SERVICE_client_continue (nc->client);
   2394 }
   2395 
   2396 
   2397 /**
   2398  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT message
   2399  *
   2400  * @param cls the client sending the message
   2401  * @param zis_msg message from the client
   2402  */
   2403 static void
   2404 handle_iteration_next (void *cls,
   2405                        const struct ZoneIterationNextMessage *zis_msg)
   2406 {
   2407   struct NamestoreClient *nc = cls;
   2408   struct ZoneIteration *zi;
   2409   uint32_t rid;
   2410   uint64_t limit;
   2411 
   2412   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2413               "Received ZONE_ITERATION_NEXT message\n");
   2414   GNUNET_STATISTICS_update (statistics,
   2415                             "Iteration NEXT messages received",
   2416                             1,
   2417                             GNUNET_NO);
   2418   rid = ntohl (zis_msg->gns_header.r_id);
   2419   limit = GNUNET_ntohll (zis_msg->limit);
   2420   for (zi = nc->op_head; NULL != zi; zi = zi->next)
   2421     if (zi->request_id == rid)
   2422       break;
   2423   if (NULL == zi)
   2424   {
   2425     GNUNET_break (0);
   2426     GNUNET_SERVICE_client_drop (nc->client);
   2427     return;
   2428   }
   2429   run_zone_iteration_round (zi, limit);
   2430 }
   2431 
   2432 
   2433 /**
   2434  * Function called when the monitor is ready for more data, and we
   2435  * should thus unblock PUT operations that were blocked on the
   2436  * monitor not being ready.
   2437  */
   2438 static void
   2439 monitor_unblock (struct ZoneMonitor *zm)
   2440 {
   2441   struct StoreActivity *sa = sa_head;
   2442 
   2443   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2444               "Unblocking zone monitor %p\n", zm);
   2445   while ((NULL != sa) && (zm->limit > zm->iteration_cnt))
   2446   {
   2447     struct StoreActivity *sn = sa->next;
   2448 
   2449     if (sa->zm_pos == zm)
   2450       continue_store_activity (sa, GNUNET_YES);
   2451     sa = sn;
   2452   }
   2453   if (zm->limit > zm->iteration_cnt)
   2454   {
   2455     zm->sa_waiting = GNUNET_NO;
   2456     if (NULL != zm->sa_wait_warning)
   2457     {
   2458       GNUNET_SCHEDULER_cancel (zm->sa_wait_warning);
   2459       zm->sa_wait_warning = NULL;
   2460     }
   2461   }
   2462   else if (GNUNET_YES == zm->sa_waiting)
   2463   {
   2464     zm->sa_waiting_start = GNUNET_TIME_absolute_get ();
   2465     if (NULL != zm->sa_wait_warning)
   2466       GNUNET_SCHEDULER_cancel (zm->sa_wait_warning);
   2467     zm->sa_wait_warning =
   2468       GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY,
   2469                                     &warn_monitor_slow,
   2470                                     zm);
   2471   }
   2472 }
   2473 
   2474 
   2475 /**
   2476  * Send 'sync' message to zone monitor, we're now in sync.
   2477  *
   2478  * @param zm monitor that is now in sync
   2479  */
   2480 static void
   2481 monitor_sync (struct ZoneMonitor *zm)
   2482 {
   2483   struct GNUNET_MQ_Envelope *env;
   2484   struct GNUNET_MessageHeader *sync;
   2485   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2486               "Syncing zone monitor %p\n", zm);
   2487 
   2488   env = GNUNET_MQ_msg (sync, GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_SYNC);
   2489   GNUNET_MQ_send (zm->nc->mq, env);
   2490   /* mark iteration done */
   2491   zm->in_first_iteration = GNUNET_NO;
   2492   zm->iteration_cnt = 0;
   2493   if ((zm->limit > 0) && (zm->sa_waiting))
   2494     monitor_unblock (zm);
   2495 }
   2496 
   2497 
   2498 /**
   2499  * Obtain the next datum during the zone monitor's zone initial iteration.
   2500  *
   2501  * @param cls zone monitor that does its initial iteration
   2502  */
   2503 static void
   2504 monitor_iteration_next (void *cls);
   2505 
   2506 
   2507 /**
   2508  * A #GNUNET_NAMESTORE_RecordIterator for monitors.
   2509  *
   2510  * @param cls a 'struct ZoneMonitor *' with information about the monitor
   2511  * @param seq sequence number of the record, MUST NOT BE ZERO
   2512  * @param zone_key zone key of the zone
   2513  * @param name name
   2514  * @param rd_count number of records in @a rd
   2515  * @param rd array of records
   2516  */
   2517 static void
   2518 monitor_iterate_cb (void *cls,
   2519                     uint64_t seq,
   2520                     const char *editor_hint,
   2521                     const struct GNUNET_CRYPTO_BlindablePrivateKey *zone_key,
   2522                     const char *name,
   2523                     unsigned int rd_count,
   2524                     const struct GNUNET_GNSRECORD_Data *rd)
   2525 {
   2526   struct ZoneMonitor *zm = cls;
   2527 
   2528   GNUNET_assert (0 != seq);
   2529   zm->seq = seq;
   2530   GNUNET_assert (NULL != name);
   2531   GNUNET_STATISTICS_update (statistics,
   2532                             "Monitor notifications sent",
   2533                             1,
   2534                             GNUNET_NO);
   2535   if (0 < send_lookup_response_with_filter (zm->nc, 0, zone_key, name,
   2536                                             rd_count, rd, zm->filter))
   2537   {
   2538     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2539                 "Sent records.\n");
   2540     zm->limit--;
   2541     zm->iteration_cnt--;
   2542   }
   2543   else
   2544     zm->run_again = GNUNET_YES;
   2545   if ((0 == zm->iteration_cnt) && (0 != zm->limit))
   2546   {
   2547     /* We are done with the current iteration batch, AND the
   2548        client would right now accept more, so go again! */
   2549     GNUNET_assert (NULL == zm->task);
   2550     zm->task = GNUNET_SCHEDULER_add_now (&monitor_iteration_next, zm);
   2551   }
   2552 }
   2553 
   2554 
   2555 static enum GNUNET_GenericReturnValue
   2556 check_monitor_start (void *cls,
   2557                      const struct ZoneMonitorStartMessage *zis_msg)
   2558 {
   2559   uint16_t size;
   2560   size_t key_len;
   2561 
   2562   size = ntohs (zis_msg->header.size);
   2563   key_len = ntohs (zis_msg->key_len);
   2564 
   2565   if (size < key_len + sizeof(*zis_msg))
   2566   {
   2567     GNUNET_break (0);
   2568     return GNUNET_SYSERR;
   2569   }
   2570   return GNUNET_OK;
   2571 }
   2572 
   2573 
   2574 /**
   2575  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START message
   2576  *
   2577  * @param cls the client sending the message
   2578  * @param zis_msg message from the client
   2579  */
   2580 static void
   2581 handle_monitor_start (void *cls, const struct
   2582                       ZoneMonitorStartMessage *zis_msg)
   2583 {
   2584   struct GNUNET_CRYPTO_BlindablePrivateKey zone;
   2585   struct NamestoreClient *nc = cls;
   2586   struct ZoneMonitor *zm;
   2587   size_t key_len;
   2588   size_t kb_read;
   2589 
   2590   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2591               "Received ZONE_MONITOR_START message\n");
   2592   zm = GNUNET_new (struct ZoneMonitor);
   2593   zm->nc = nc;
   2594   key_len = ntohs (zis_msg->key_len);
   2595   if (0 < key_len)
   2596   {
   2597     if ((GNUNET_SYSERR ==
   2598          GNUNET_CRYPTO_read_private_key_from_buffer (&zis_msg[1],
   2599                                                      key_len,
   2600                                                      &zone,
   2601                                                      &kb_read)) ||
   2602         (kb_read != key_len))
   2603     {
   2604       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2605                   "Error reading private key\n");
   2606       GNUNET_SERVICE_client_drop (nc->client);
   2607       GNUNET_free (zm);
   2608       return;
   2609     }
   2610     zm->zone = zone;
   2611   }
   2612   zm->limit = 1;
   2613   zm->filter = ntohs (zis_msg->filter);
   2614   zm->in_first_iteration = (GNUNET_YES == ntohl (zis_msg->iterate_first));
   2615   GNUNET_CONTAINER_DLL_insert (monitor_head, monitor_tail, zm);
   2616   GNUNET_SERVICE_client_mark_monitor (nc->client);
   2617   GNUNET_SERVICE_client_continue (nc->client);
   2618   GNUNET_notification_context_add (monitor_nc, nc->mq);
   2619   if (zm->in_first_iteration)
   2620     zm->task = GNUNET_SCHEDULER_add_now (&monitor_iteration_next, zm);
   2621   else
   2622     monitor_sync (zm);
   2623 }
   2624 
   2625 
   2626 /**
   2627  * Obtain the next datum during the zone monitor's zone initial iteration.
   2628  *
   2629  * @param cls zone monitor that does its initial iteration
   2630  */
   2631 static void
   2632 monitor_iteration_next (void *cls)
   2633 {
   2634   struct ZoneMonitor *zm = cls;
   2635   struct NamestoreClient *nc = zm->nc;
   2636   int ret;
   2637 
   2638   zm->task = NULL;
   2639   GNUNET_assert (0 == zm->iteration_cnt);
   2640   if (zm->limit > 16)
   2641     zm->iteration_cnt = zm->limit / 2;   /* leave half for monitor events */
   2642   else
   2643     zm->iteration_cnt = zm->limit;   /* use it all */
   2644   zm->run_again = GNUNET_YES;
   2645   while (GNUNET_YES == zm->run_again)
   2646   {
   2647     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2648                 "Running iteration\n");
   2649     zm->run_again = GNUNET_NO;
   2650     ret = nc->GSN_database->iterate_records (nc->GSN_database->cls,
   2651                                              (GNUNET_YES == GNUNET_is_zero (
   2652                                                 &zm->zone)) ? NULL : &zm->zone,
   2653                                              zm->seq,
   2654                                              zm->iteration_cnt,
   2655                                              &monitor_iterate_cb,
   2656                                              zm);
   2657   }
   2658   if (GNUNET_SYSERR == ret)
   2659   {
   2660     GNUNET_SERVICE_client_drop (zm->nc->client);
   2661     return;
   2662   }
   2663   if (GNUNET_NO == ret)
   2664   {
   2665     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2666                 "Zone empty... syncing\n");
   2667     /* empty zone */
   2668     monitor_sync (zm);
   2669     return;
   2670   }
   2671 }
   2672 
   2673 
   2674 /**
   2675  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_NEXT message
   2676  *
   2677  * @param cls the client sending the message
   2678  * @param nm message from the client
   2679  */
   2680 static void
   2681 handle_monitor_next (void *cls, const struct ZoneMonitorNextMessage *nm)
   2682 {
   2683   struct NamestoreClient *nc = cls;
   2684   struct ZoneMonitor *zm;
   2685   uint64_t inc;
   2686 
   2687   inc = GNUNET_ntohll (nm->limit);
   2688   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2689               "Received ZONE_MONITOR_NEXT message with limit %llu\n",
   2690               (unsigned long long) inc);
   2691   for (zm = monitor_head; NULL != zm; zm = zm->next)
   2692     if (zm->nc == nc)
   2693       break;
   2694   if (NULL == zm)
   2695   {
   2696     GNUNET_break (0);
   2697     GNUNET_SERVICE_client_drop (nc->client);
   2698     return;
   2699   }
   2700   GNUNET_SERVICE_client_continue (nc->client);
   2701   if (zm->limit + inc < zm->limit)
   2702   {
   2703     GNUNET_break (0);
   2704     GNUNET_SERVICE_client_drop (nc->client);
   2705     return;
   2706   }
   2707   zm->limit += inc;
   2708   if ((zm->in_first_iteration) && (zm->limit == inc))
   2709   {
   2710     /* We are still iterating, and the previous iteration must
   2711        have stopped due to the client's limit, so continue it! */
   2712     GNUNET_assert (NULL == zm->task);
   2713     zm->task = GNUNET_SCHEDULER_add_now (&monitor_iteration_next, zm);
   2714   }
   2715   GNUNET_assert (zm->iteration_cnt <= zm->limit);
   2716   if ((zm->limit > zm->iteration_cnt) && (zm->sa_waiting))
   2717   {
   2718     monitor_unblock (zm);
   2719   }
   2720   else if (GNUNET_YES == zm->sa_waiting)
   2721   {
   2722     if (NULL != zm->sa_wait_warning)
   2723       GNUNET_SCHEDULER_cancel (zm->sa_wait_warning);
   2724     zm->sa_waiting_start = GNUNET_TIME_absolute_get ();
   2725     zm->sa_wait_warning =
   2726       GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY,
   2727                                     &warn_monitor_slow,
   2728                                     zm);
   2729   }
   2730 }
   2731 
   2732 
   2733 /**
   2734  * Process namestore requests.
   2735  *
   2736  * @param cls closure
   2737  * @param cfg configuration to use
   2738  * @param service the initialized service
   2739  */
   2740 static void
   2741 run (void *cls,
   2742      const struct GNUNET_CONFIGURATION_Handle *cfg,
   2743      struct GNUNET_SERVICE_Handle *service)
   2744 {
   2745   char *database;
   2746   (void) cls;
   2747   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namestore service\n");
   2748   return_orphaned = GNUNET_CONFIGURATION_get_value_yesno (cfg,
   2749                                                           "namestore",
   2750                                                           "RETURN_ORPHANED");
   2751   GSN_cfg = cfg;
   2752   monitor_nc = GNUNET_notification_context_create (1);
   2753   statistics = GNUNET_STATISTICS_create ("namestore", cfg);
   2754   /* Loading database plugin */
   2755   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
   2756                                                           "namestore",
   2757                                                           "database",
   2758                                                           &database))
   2759   {
   2760     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
   2761     GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
   2762     return;
   2763   }
   2764   GNUNET_asprintf (&db_lib_name,
   2765                    "libgnunet_plugin_namestore_%s",
   2766                    database);
   2767   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2768               "Loading %s\n",
   2769               db_lib_name);
   2770   GSN_database = GNUNET_PLUGIN_load (GNUNET_OS_project_data_gnunet (),
   2771                                      db_lib_name,
   2772                                      (void *) cfg);
   2773   GNUNET_free (database);
   2774   if (NULL == GSN_database)
   2775   {
   2776     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2777                 "Could not load database backend `%s'\n",
   2778                 db_lib_name);
   2779     GNUNET_free (db_lib_name);
   2780     GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
   2781     return;
   2782   }
   2783   GNUNET_SCHEDULER_add_shutdown (&cleanup_task, NULL);
   2784 }
   2785 
   2786 
   2787 /**
   2788  * Define "main" method using service macro.
   2789  */
   2790 GNUNET_SERVICE_MAIN (
   2791   GNUNET_OS_project_data_gnunet (),
   2792   "namestore",
   2793   GNUNET_SERVICE_OPTION_NONE,
   2794   &run,
   2795   &client_connect_cb,
   2796   &client_disconnect_cb,
   2797   NULL,
   2798   GNUNET_MQ_hd_var_size (record_store,
   2799                          GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE,
   2800                          struct RecordStoreMessage,
   2801                          NULL),
   2802   GNUNET_MQ_hd_var_size (edit_record_set,
   2803                          GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_SET_EDIT,
   2804                          struct EditRecordSetMessage,
   2805                          NULL),
   2806   GNUNET_MQ_hd_var_size (edit_record_set_cancel,
   2807                          GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_SET_EDIT_CANCEL,
   2808                          struct EditRecordSetCancelMessage,
   2809                          NULL),
   2810   GNUNET_MQ_hd_var_size (record_lookup,
   2811                          GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP,
   2812                          struct LabelLookupMessage,
   2813                          NULL),
   2814   GNUNET_MQ_hd_var_size (zone_to_name,
   2815                          GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME,
   2816                          struct ZoneToNameMessage,
   2817                          NULL),
   2818   GNUNET_MQ_hd_var_size (iteration_start,
   2819                          GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START,
   2820                          struct ZoneIterationStartMessage,
   2821                          NULL),
   2822   GNUNET_MQ_hd_fixed_size (iteration_next,
   2823                            GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT,
   2824                            struct ZoneIterationNextMessage,
   2825                            NULL),
   2826   GNUNET_MQ_hd_fixed_size (iteration_stop,
   2827                            GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP,
   2828                            struct ZoneIterationStopMessage,
   2829                            NULL),
   2830   GNUNET_MQ_hd_var_size (monitor_start,
   2831                          GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START,
   2832                          struct ZoneMonitorStartMessage,
   2833                          NULL),
   2834   GNUNET_MQ_hd_fixed_size (monitor_next,
   2835                            GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_NEXT,
   2836                            struct ZoneMonitorNextMessage,
   2837                            NULL),
   2838   GNUNET_MQ_handler_end ());
   2839 
   2840 
   2841 /* end of gnunet-service-namestore.c */