handle errors without crashing
[oweals/gnunet.git] / src / namestore / namestore_api.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2010-2013, 2016 GNUnet e.V.
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
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      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 /**
22  * @file namestore/namestore_api.c
23  * @brief API to access the NAMESTORE service
24  * @author Martin Schanzenbach
25  * @author Matthias Wachs
26  * @author Christian Grothoff
27  */
28
29 #include "platform.h"
30 #include "gnunet_util_lib.h"
31 #include "gnunet_crypto_lib.h"
32 #include "gnunet_constants.h"
33 #include "gnunet_dnsparser_lib.h"
34 #include "gnunet_arm_service.h"
35 #include "gnunet_signatures.h"
36 #include "gnunet_gns_service.h"
37 #include "gnunet_namestore_service.h"
38 #include "namestore.h"
39
40
41 #define LOG(kind,...) GNUNET_log_from (kind, "namestore-api",__VA_ARGS__)
42
43
44 /**
45  * An QueueEntry used to store information for a pending
46  * NAMESTORE record operation
47  */
48 struct GNUNET_NAMESTORE_QueueEntry
49 {
50
51   /**
52    * Kept in a DLL.
53    */
54   struct GNUNET_NAMESTORE_QueueEntry *next;
55
56   /**
57    * Kept in a DLL.
58    */
59   struct GNUNET_NAMESTORE_QueueEntry *prev;
60
61   /**
62    * Main handle to access the namestore.
63    */
64   struct GNUNET_NAMESTORE_Handle *h;
65
66   /**
67    * Continuation to call
68    */
69   GNUNET_NAMESTORE_ContinuationWithStatus cont;
70
71   /**
72    * Closure for @e cont.
73    */
74   void *cont_cls;
75
76   /**
77    * Function to call with the records we get back; or NULL.
78    */
79   GNUNET_NAMESTORE_RecordMonitor proc;
80
81   /**
82    * Closure for @e proc.
83    */
84   void *proc_cls;
85
86   /**
87    * Function to call on errors.
88    */
89   GNUNET_SCHEDULER_TaskCallback error_cb;
90
91   /**
92    * Closure for @e error_cb.
93    */
94   void *error_cb_cls;
95
96   /**
97    * Envelope of the message to send to the service, if not yet
98    * sent.
99    */
100   struct GNUNET_MQ_Envelope *env;
101
102   /**
103    * The operation id this zone iteration operation has
104    */
105   uint32_t op_id;
106
107 };
108
109
110 /**
111  * Handle for a zone iterator operation
112  */
113 struct GNUNET_NAMESTORE_ZoneIterator
114 {
115
116   /**
117    * Kept in a DLL.
118    */
119   struct GNUNET_NAMESTORE_ZoneIterator *next;
120
121   /**
122    * Kept in a DLL.
123    */
124   struct GNUNET_NAMESTORE_ZoneIterator *prev;
125
126   /**
127    * Main handle to access the namestore.
128    */
129   struct GNUNET_NAMESTORE_Handle *h;
130
131   /**
132    * Function to call on completion.
133    */
134   GNUNET_SCHEDULER_TaskCallback finish_cb;
135
136   /**
137    * Closure for @e error_cb.
138    */
139   void *finish_cb_cls;
140
141   /**
142    * The continuation to call with the results
143    */
144   GNUNET_NAMESTORE_RecordMonitor proc;
145
146   /**
147    * Closure for @e proc.
148    */
149   void *proc_cls;
150
151   /**
152    * Function to call on errors.
153    */
154   GNUNET_SCHEDULER_TaskCallback error_cb;
155
156   /**
157    * Closure for @e error_cb.
158    */
159   void *error_cb_cls;
160
161   /**
162    * Envelope of the message to send to the service, if not yet
163    * sent.
164    */
165   struct GNUNET_MQ_Envelope *env;
166
167   /**
168    * Private key of the zone.
169    */
170   struct GNUNET_CRYPTO_EcdsaPrivateKey zone;
171
172   /**
173    * The operation id this zone iteration operation has
174    */
175   uint32_t op_id;
176
177 };
178
179
180 /**
181  * Connection to the NAMESTORE service.
182  */
183 struct GNUNET_NAMESTORE_Handle
184 {
185
186   /**
187    * Configuration to use.
188    */
189   const struct GNUNET_CONFIGURATION_Handle *cfg;
190
191   /**
192    * Connection to the service (if available).
193    */
194   struct GNUNET_MQ_Handle *mq;
195
196   /**
197    * Head of pending namestore queue entries
198    */
199   struct GNUNET_NAMESTORE_QueueEntry *op_head;
200
201   /**
202    * Tail of pending namestore queue entries
203    */
204   struct GNUNET_NAMESTORE_QueueEntry *op_tail;
205
206   /**
207    * Head of pending namestore zone iterator entries
208    */
209   struct GNUNET_NAMESTORE_ZoneIterator *z_head;
210
211   /**
212    * Tail of pending namestore zone iterator entries
213    */
214   struct GNUNET_NAMESTORE_ZoneIterator *z_tail;
215
216   /**
217    * Reconnect task
218    */
219   struct GNUNET_SCHEDULER_Task *reconnect_task;
220
221   /**
222    * Delay introduced before we reconnect.
223    */
224   struct GNUNET_TIME_Relative reconnect_delay;
225
226   /**
227    * Should we reconnect to service due to some serious error?
228    */
229   int reconnect;
230
231   /**
232    * The last operation id used for a NAMESTORE operation
233    */
234   uint32_t last_op_id_used;
235
236 };
237
238
239 /**
240  * Disconnect from service and then reconnect.
241  *
242  * @param h our handle
243  */
244 static void
245 force_reconnect (struct GNUNET_NAMESTORE_Handle *h);
246
247
248 /**
249  * Find the queue entry that matches the @a rid
250  *
251  * @param h namestore handle
252  * @param rid id to look up
253  * @return NULL if @a rid was not found
254  */
255 static struct GNUNET_NAMESTORE_QueueEntry *
256 find_qe (struct GNUNET_NAMESTORE_Handle *h,
257          uint32_t rid)
258 {
259   struct GNUNET_NAMESTORE_QueueEntry *qe;
260
261   for (qe = h->op_head; qe != NULL; qe = qe->next)
262     if (qe->op_id == rid)
263       return qe;
264   return NULL;
265 }
266
267
268 /**
269  * Find the zone iteration entry that matches the @a rid
270  *
271  * @param h namestore handle
272  * @param rid id to look up
273  * @return NULL if @a rid was not found
274  */
275 static struct GNUNET_NAMESTORE_ZoneIterator *
276 find_zi (struct GNUNET_NAMESTORE_Handle *h,
277          uint32_t rid)
278 {
279   struct GNUNET_NAMESTORE_ZoneIterator *ze;
280
281   for (ze = h->z_head; ze != NULL; ze = ze->next)
282     if (ze->op_id == rid)
283       return ze;
284   return NULL;
285 }
286
287
288 /**
289  * Free @a qe.
290  *
291  * @param qe entry to free
292  */
293 static void
294 free_qe (struct GNUNET_NAMESTORE_QueueEntry *qe)
295 {
296   struct GNUNET_NAMESTORE_Handle *h = qe->h;
297
298   GNUNET_CONTAINER_DLL_remove (h->op_head,
299                                h->op_tail,
300                                qe);
301   if (NULL != qe->env)
302     GNUNET_MQ_discard (qe->env);
303   GNUNET_free (qe);
304 }
305
306
307 /**
308  * Free @a ze.
309  *
310  * @param ze entry to free
311  */
312 static void
313 free_ze (struct GNUNET_NAMESTORE_ZoneIterator *ze)
314 {
315   struct GNUNET_NAMESTORE_Handle *h = ze->h;
316
317   GNUNET_CONTAINER_DLL_remove (h->z_head,
318                                h->z_tail,
319                                ze);
320   if (NULL != ze->env)
321     GNUNET_MQ_discard (ze->env);
322   GNUNET_free (ze);
323 }
324
325
326 /**
327  * Check that @a rd_buf of lenght @a rd_len contains
328  * @a rd_count records.
329  *
330  * @param rd_len length of @a rd_buf
331  * @param rd_buf buffer with serialized records
332  * @param rd_count number of records expected
333  * @return #GNUNET_OK if @a rd_buf is well-formed
334  */
335 static int
336 check_rd (size_t rd_len,
337           const void *rd_buf,
338           unsigned int rd_count)
339 {
340   struct GNUNET_GNSRECORD_Data rd[rd_count];
341
342   if (GNUNET_OK !=
343       GNUNET_GNSRECORD_records_deserialize (rd_len,
344                                             rd_buf,
345                                             rd_count,
346                                             rd))
347   {
348     GNUNET_break (0);
349     return GNUNET_SYSERR;
350   }
351   return GNUNET_OK;
352 }
353
354
355 /**
356  * Handle an incoming message of type
357  * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE
358  *
359  * @param cls
360  * @param msg the message we received
361  */
362 static void
363 handle_record_store_response (void *cls,
364                               const struct RecordStoreResponseMessage *msg)
365 {
366   struct GNUNET_NAMESTORE_Handle *h = cls;
367   struct GNUNET_NAMESTORE_QueueEntry *qe;
368   int res;
369   const char *emsg;
370
371   qe = find_qe (h,
372                 ntohl (msg->gns_header.r_id));
373   res = ntohl (msg->op_result);
374   LOG (GNUNET_ERROR_TYPE_DEBUG,
375        "Received RECORD_STORE_RESPONSE with result %d\n",
376        res);
377   /* TODO: add actual error message from namestore to response... */
378   if (GNUNET_SYSERR == res)
379     emsg = _("Namestore failed to store record\n");
380   else
381     emsg = NULL;
382   if (NULL != qe->cont)
383     qe->cont (qe->cont_cls,
384               res,
385               emsg);
386   free_qe (qe);
387 }
388
389
390 /**
391  * Check validity of an incoming message of type
392  * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP_RESPONSE
393  *
394  * @param cls
395  * @param msg the message we received
396  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
397  */
398 static int
399 check_lookup_result (void *cls,
400                      const struct LabelLookupResponseMessage *msg)
401 {
402   const char *name;
403   size_t exp_msg_len;
404   size_t msg_len;
405   size_t name_len;
406   size_t rd_len;
407
408   rd_len = ntohs (msg->rd_len);
409   msg_len = ntohs (msg->gns_header.header.size);
410   name_len = ntohs (msg->name_len);
411   exp_msg_len = sizeof (*msg) + name_len + rd_len;
412   if (msg_len != exp_msg_len)
413   {
414     GNUNET_break (0);
415     return GNUNET_SYSERR;
416   }
417   name = (const char *) &msg[1];
418   if ( (name_len > 0) &&
419        ('\0' != name[name_len -1]) )
420   {
421     GNUNET_break (0);
422     return GNUNET_SYSERR;
423   }
424   if (GNUNET_NO == ntohs (msg->found))
425   {
426     if (0 != ntohs (msg->rd_count))
427     {
428       GNUNET_break (0);
429       return GNUNET_SYSERR;
430     }
431     return GNUNET_OK;
432   }
433   return check_rd (rd_len,
434                    &name[name_len],
435                    ntohs (msg->rd_count));
436 }
437
438
439 /**
440  * Handle an incoming message of type
441  * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP_RESPONSE
442  *
443  * @param cls
444  * @param msg the message we received
445  */
446 static void
447 handle_lookup_result (void *cls,
448                       const struct LabelLookupResponseMessage *msg)
449 {
450   struct GNUNET_NAMESTORE_Handle *h = cls;
451   struct GNUNET_NAMESTORE_QueueEntry *qe;
452   const char *name;
453   const char *rd_tmp;
454   size_t name_len;
455   size_t rd_len;
456   unsigned int rd_count;
457
458   LOG (GNUNET_ERROR_TYPE_DEBUG,
459        "Received RECORD_LOOKUP_RESULT\n");
460   qe = find_qe (h,
461                 ntohl (msg->gns_header.r_id));
462   if (NULL == qe)
463     return;
464   rd_len = ntohs (msg->rd_len);
465   rd_count = ntohs (msg->rd_count);
466   name_len = ntohs (msg->name_len);
467   name = (const char *) &msg[1];
468   if (GNUNET_NO == ntohs (msg->found))
469   {
470     /* label was not in namestore */
471     if (NULL != qe->proc)
472       qe->proc (qe->proc_cls,
473                 &msg->private_key,
474                 name,
475                 0,
476                 NULL);
477     free_qe (qe);
478     return;
479   }
480
481   rd_tmp = &name[name_len];
482   {
483     struct GNUNET_GNSRECORD_Data rd[rd_count];
484
485     GNUNET_assert (GNUNET_OK ==
486                    GNUNET_GNSRECORD_records_deserialize (rd_len,
487                                                          rd_tmp,
488                                                          rd_count,
489                                                          rd));
490     if (0 == name_len)
491       name = NULL;
492     if (NULL != qe->proc)
493       qe->proc (qe->proc_cls,
494                 &msg->private_key,
495                 name,
496                 rd_count,
497                 (rd_count > 0) ? rd : NULL);
498   }
499   free_qe (qe);
500 }
501
502
503 /**
504  * Handle an incoming message of type
505  * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT
506  *
507  * @param cls
508  * @param msg the message we received
509  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
510  */
511 static int
512 check_record_result (void *cls,
513                      const struct RecordResultMessage *msg)
514 {
515   const char *name;
516   size_t msg_len;
517   size_t name_len;
518   size_t rd_len;
519
520   rd_len = ntohs (msg->rd_len);
521   msg_len = ntohs (msg->gns_header.header.size);
522   name_len = ntohs (msg->name_len);
523   if (0 != ntohs (msg->reserved))
524   {
525     GNUNET_break (0);
526     return GNUNET_SYSERR;
527   }
528   if (msg_len != sizeof (struct RecordResultMessage) + name_len + rd_len)
529   {
530     GNUNET_break (0);
531     return GNUNET_SYSERR;
532   }
533   name = (const char *) &msg[1];
534   if ( (name_len > 0) &&
535        ('\0' != name[name_len -1]) )
536   {
537     GNUNET_break (0);
538     return GNUNET_SYSERR;
539   }
540   return check_rd (rd_len,
541                    &name[name_len],
542                    ntohs (msg->rd_count));
543 }
544
545
546 /**
547  * Handle an incoming message of type
548  * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT
549  *
550  * @param cls
551  * @param msg the message we received
552  */
553 static void
554 handle_record_result (void *cls,
555                       const struct RecordResultMessage *msg)
556 {
557   static struct GNUNET_CRYPTO_EcdsaPrivateKey priv_dummy;
558   struct GNUNET_NAMESTORE_Handle *h = cls;
559   struct GNUNET_NAMESTORE_QueueEntry *qe;
560   struct GNUNET_NAMESTORE_ZoneIterator *ze;
561   const char *name;
562   const char *rd_tmp;
563   size_t name_len;
564   size_t rd_len;
565   unsigned int rd_count;
566
567   LOG (GNUNET_ERROR_TYPE_DEBUG,
568        "Received RECORD_RESULT\n");
569   rd_len = ntohs (msg->rd_len);
570   rd_count = ntohs (msg->rd_count);
571   name_len = ntohs (msg->name_len);
572   ze = find_zi (h,
573                 ntohl (msg->gns_header.r_id));
574   qe = find_qe (h,
575                 ntohl (msg->gns_header.r_id));
576   if ( (NULL == ze) &&
577        (NULL == qe) )
578     return; /* rid not found */
579   if ( (NULL != ze) &&
580        (NULL != qe) )
581   {
582     GNUNET_break (0);   /* rid ambigous */
583     force_reconnect (h);
584     return;
585   }
586   if ( (0 == name_len) &&
587        (0 == (memcmp (&msg->private_key,
588                       &priv_dummy,
589                       sizeof (priv_dummy)))) )
590   {
591     LOG (GNUNET_ERROR_TYPE_DEBUG,
592          "Zone iteration completed!\n");
593     if (NULL == ze)
594     {
595       GNUNET_break (0);
596       force_reconnect (h);
597       return;
598     }
599     if (NULL != ze->finish_cb)
600       ze->finish_cb (ze->finish_cb_cls);
601     free_ze (ze);
602     return;
603   }
604
605   name = (const char *) &msg[1];
606   rd_tmp = &name[name_len];
607   {
608     struct GNUNET_GNSRECORD_Data rd[rd_count];
609
610     GNUNET_assert (GNUNET_OK ==
611                    GNUNET_GNSRECORD_records_deserialize(rd_len,
612                                                         rd_tmp,
613                                                         rd_count,
614                                                         rd));
615     if (0 == name_len)
616       name = NULL;
617     if (NULL != qe)
618     {
619       if (NULL != qe->proc)
620         qe->proc (qe->proc_cls,
621                   &msg->private_key,
622                   name,
623                   rd_count,
624                   (rd_count > 0) ? rd : NULL);
625       free_qe (qe);
626       return;
627     }
628     if (NULL != ze)
629     {
630       if (NULL != ze->proc)
631         ze->proc (ze->proc_cls,
632                   &msg->private_key,
633                   name,
634                   rd_count,
635                   rd);
636       return;
637     }
638   }
639   GNUNET_assert (0);
640 }
641
642
643 /**
644  * Handle an incoming message of type
645  * #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE.
646  *
647  * @param qe the respective entry in the message queue
648  * @param msg the message we received
649  * @return #GNUNET_OK on success, #GNUNET_SYSERR if message malformed
650  */
651 static int
652 check_zone_to_name_response (void *cls,
653                              const struct ZoneToNameResponseMessage *msg)
654 {
655   size_t name_len;
656   size_t rd_ser_len;
657   const char *name_tmp;
658
659   if (GNUNET_OK != ntohs (msg->res))
660     return GNUNET_OK;
661   name_len = ntohs (msg->name_len);
662   rd_ser_len = ntohs (msg->rd_len);
663   if (ntohs (msg->gns_header.header.size) !=
664       sizeof (struct ZoneToNameResponseMessage) + name_len + rd_ser_len)
665   {
666     GNUNET_break (0);
667     return GNUNET_SYSERR;
668   }
669   name_tmp = (const char *) &msg[1];
670   if ( (name_len > 0) &&
671        ('\0' != name_tmp[name_len -1]) )
672   {
673     GNUNET_break (0);
674     return GNUNET_SYSERR;
675   }
676   return check_rd (rd_ser_len,
677                    &name_tmp[name_len],
678                    ntohs (msg->rd_count));
679 }
680
681
682 /**
683  * Handle an incoming message of type
684  * #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE.
685  *
686  * @param cls
687  * @param msg the message we received
688  */
689 static void
690 handle_zone_to_name_response (void *cls,
691                               const struct ZoneToNameResponseMessage *msg)
692 {
693   struct GNUNET_NAMESTORE_Handle *h = cls;
694   struct GNUNET_NAMESTORE_QueueEntry *qe;
695   int res;
696   size_t name_len;
697   size_t rd_ser_len;
698   unsigned int rd_count;
699   const char *name_tmp;
700   const char *rd_tmp;
701
702   LOG (GNUNET_ERROR_TYPE_DEBUG,
703        "Received ZONE_TO_NAME_RESPONSE\n");
704   qe = find_qe (h,
705                 ntohl (msg->gns_header.r_id));
706   res = ntohs (msg->res);
707   switch (res)
708   {
709   case GNUNET_SYSERR:
710     LOG (GNUNET_ERROR_TYPE_DEBUG,
711          "An error occured during zone to name operation\n");
712     break;
713   case GNUNET_NO:
714     LOG (GNUNET_ERROR_TYPE_DEBUG,
715          "Namestore has no result for zone to name mapping \n");
716     if (NULL != qe->proc)
717       qe->proc (qe->proc_cls, &msg->zone, NULL, 0, NULL);
718     free_qe (qe);
719     return;
720   case GNUNET_YES:
721     LOG (GNUNET_ERROR_TYPE_DEBUG,
722          "Namestore has result for zone to name mapping \n");
723     name_len = ntohs (msg->name_len);
724     rd_count = ntohs (msg->rd_count);
725     rd_ser_len = ntohs (msg->rd_len);
726     name_tmp = (const char *) &msg[1];
727     rd_tmp = &name_tmp[name_len];
728     {
729       struct GNUNET_GNSRECORD_Data rd[rd_count];
730
731       GNUNET_assert (GNUNET_OK ==
732                      GNUNET_GNSRECORD_records_deserialize (rd_ser_len,
733                                                            rd_tmp,
734                                                            rd_count,
735                                                            rd));
736       /* normal end, call continuation with result */
737       if (NULL != qe->proc)
738         qe->proc (qe->proc_cls,
739                   &msg->zone,
740                   name_tmp,
741                   rd_count,
742                   rd);
743       /* return is important here: break would call continuation with error! */
744       free_qe (qe);
745       return;
746     }
747   default:
748     GNUNET_break (0);
749     force_reconnect (h);
750     return;
751   }
752   /* error case, call continuation with error */
753   if (NULL != qe->error_cb)
754     qe->error_cb (qe->error_cb_cls);
755   free_qe (qe);
756 }
757
758
759
760 /**
761  * Generic error handler, called with the appropriate error code and
762  * the same closure specified at the creation of the message queue.
763  * Not every message queue implementation supports an error handler.
764  *
765  * @param cls closure with the `struct GNUNET_NAMESTORE_Handle *`
766  * @param error error code
767  */
768 static void
769 mq_error_handler (void *cls,
770                   enum GNUNET_MQ_Error error)
771 {
772   struct GNUNET_NAMESTORE_Handle *h = cls;
773
774   force_reconnect (h);
775 }
776
777
778 /**
779  * Reconnect to namestore service.
780  *
781  * @param h the handle to the NAMESTORE service
782  */
783 static void
784 reconnect (struct GNUNET_NAMESTORE_Handle *h)
785 {
786   struct GNUNET_MQ_MessageHandler handlers[] = {
787     GNUNET_MQ_hd_fixed_size (record_store_response,
788                              GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE,
789                              struct RecordStoreResponseMessage,
790                              h),
791     GNUNET_MQ_hd_var_size (zone_to_name_response,
792                            GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE,
793                            struct ZoneToNameResponseMessage,
794                            h),
795     GNUNET_MQ_hd_var_size (record_result,
796                            GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT,
797                            struct RecordResultMessage,
798                            h),
799     GNUNET_MQ_hd_var_size (lookup_result,
800                            GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP_RESPONSE,
801                            struct LabelLookupResponseMessage,
802                            h),
803     GNUNET_MQ_handler_end ()
804   };
805   struct GNUNET_NAMESTORE_ZoneIterator *it;
806   struct GNUNET_NAMESTORE_QueueEntry *qe;
807
808   GNUNET_assert (NULL == h->mq);
809   h->mq = GNUNET_CLIENT_connect (h->cfg,
810                                  "namestore",
811                                  handlers,
812                                  &mq_error_handler,
813                                  h);
814   if (NULL == h->mq)
815     return;
816   /* re-transmit pending requests that waited for a reconnect... */
817   for (it = h->z_head; NULL != it; it = it->next)
818   {
819     GNUNET_MQ_send (h->mq,
820                     it->env);
821     it->env = NULL;
822   }
823   for (qe = h->op_head; NULL != qe; qe = qe->next)
824   {
825     GNUNET_MQ_send (h->mq,
826                     qe->env);
827     qe->env = NULL;
828   }
829 }
830
831
832 /**
833  * Re-establish the connection to the service.
834  *
835  * @param cls handle to use to re-connect.
836  */
837 static void
838 reconnect_task (void *cls)
839 {
840   struct GNUNET_NAMESTORE_Handle *h = cls;
841
842   h->reconnect_task = NULL;
843   reconnect (h);
844 }
845
846
847 /**
848  * Disconnect from service and then reconnect.
849  *
850  * @param h our handle
851  */
852 static void
853 force_reconnect (struct GNUNET_NAMESTORE_Handle *h)
854 {
855   struct GNUNET_NAMESTORE_ZoneIterator *ze;
856   struct GNUNET_NAMESTORE_QueueEntry *qe;
857
858   GNUNET_MQ_destroy (h->mq);
859   h->mq = NULL;
860   while (NULL != (ze = h->z_head))
861   {
862     if (NULL != ze->error_cb)
863       ze->error_cb (ze->error_cb_cls);
864     free_ze (ze);
865   }
866   while (NULL != (qe = h->op_head))
867   {
868     if (NULL != qe->error_cb)
869       qe->error_cb (qe->error_cb_cls);
870     if (NULL != qe->cont)
871       qe->cont (qe->cont_cls,
872                 GNUNET_SYSERR,
873                 "failure in communication with namestore service");
874     free_qe (qe);
875   }
876
877   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
878               "Reconnecting to namestore\n");
879   h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
880   h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
881                                                     &reconnect_task,
882                                                     h);
883 }
884
885
886 /**
887  * Get a fresh operation id to distinguish between namestore requests
888  *
889  * @param h the namestore handle
890  * @return next operation id to use
891  */
892 static uint32_t
893 get_op_id (struct GNUNET_NAMESTORE_Handle *h)
894 {
895   return h->last_op_id_used++;
896 }
897
898
899 /**
900  * Initialize the connection with the NAMESTORE service.
901  *
902  * @param cfg configuration to use
903  * @return handle to the GNS service, or NULL on error
904  */
905 struct GNUNET_NAMESTORE_Handle *
906 GNUNET_NAMESTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
907 {
908   struct GNUNET_NAMESTORE_Handle *h;
909
910   h = GNUNET_new (struct GNUNET_NAMESTORE_Handle);
911   h->cfg = cfg;
912   reconnect (h);
913   if (NULL == h->mq)
914   {
915     GNUNET_free (h);
916     return NULL;
917   }
918   return h;
919 }
920
921
922 /**
923  * Disconnect from the namestore service (and free associated
924  * resources).
925  *
926  * @param h handle to the namestore
927  */
928 void
929 GNUNET_NAMESTORE_disconnect (struct GNUNET_NAMESTORE_Handle *h)
930 {
931   struct GNUNET_NAMESTORE_QueueEntry *q;
932   struct GNUNET_NAMESTORE_ZoneIterator *z;
933
934   LOG (GNUNET_ERROR_TYPE_DEBUG,
935        "Cleaning up\n");
936   GNUNET_break (NULL == h->op_head);
937   while (NULL != (q = h->op_head))
938   {
939     GNUNET_CONTAINER_DLL_remove (h->op_head,
940                                  h->op_tail,
941                                  q);
942     GNUNET_free (q);
943   }
944   GNUNET_break (NULL == h->z_head);
945   while (NULL != (z = h->z_head))
946   {
947     GNUNET_CONTAINER_DLL_remove (h->z_head,
948                                  h->z_tail,
949                                  z);
950     GNUNET_free (z);
951   }
952   if (NULL != h->mq)
953   {
954     GNUNET_MQ_destroy (h->mq);
955     h->mq = NULL;
956   }
957   if (NULL != h->reconnect_task)
958   {
959     GNUNET_SCHEDULER_cancel (h->reconnect_task);
960     h->reconnect_task = NULL;
961   }
962   GNUNET_free (h);
963 }
964
965
966 /**
967  * Store an item in the namestore.  If the item is already present,
968  * it is replaced with the new record.  Use an empty array to
969  * remove all records under the given name.
970  *
971  * @param h handle to the namestore
972  * @param pkey private key of the zone
973  * @param label name that is being mapped (at most 255 characters long)
974  * @param rd_count number of records in the @a rd array
975  * @param rd array of records with data to store
976  * @param cont continuation to call when done
977  * @param cont_cls closure for @a cont
978  * @return handle to abort the request
979  */
980 struct GNUNET_NAMESTORE_QueueEntry *
981 GNUNET_NAMESTORE_records_store (struct GNUNET_NAMESTORE_Handle *h,
982                                 const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
983                                 const char *label,
984                                 unsigned int rd_count,
985                                 const struct GNUNET_GNSRECORD_Data *rd,
986                                 GNUNET_NAMESTORE_ContinuationWithStatus cont,
987                                 void *cont_cls)
988 {
989   struct GNUNET_NAMESTORE_QueueEntry *qe;
990   struct GNUNET_MQ_Envelope *env;
991   char *name_tmp;
992   char *rd_ser;
993   size_t rd_ser_len;
994   size_t name_len;
995   uint32_t rid;
996   struct RecordStoreMessage *msg;
997
998   name_len = strlen (label) + 1;
999   if (name_len > MAX_NAME_LEN)
1000   {
1001     GNUNET_break (0);
1002     return NULL;
1003   }
1004   rid = get_op_id (h);
1005   qe = GNUNET_new (struct GNUNET_NAMESTORE_QueueEntry);
1006   qe->h = h;
1007   qe->cont = cont;
1008   qe->cont_cls = cont_cls;
1009   qe->op_id = rid;
1010   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
1011                                     h->op_tail,
1012                                     qe);
1013
1014   /* setup msg */
1015   rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count,
1016                                                   rd);
1017   env = GNUNET_MQ_msg_extra (msg,
1018                              name_len + rd_ser_len,
1019                              GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE);
1020   msg->gns_header.r_id = htonl (rid);
1021   msg->name_len = htons (name_len);
1022   msg->rd_count = htons (rd_count);
1023   msg->rd_len = htons (rd_ser_len);
1024   msg->reserved = htons (0);
1025   msg->private_key = *pkey;
1026
1027   name_tmp = (char *) &msg[1];
1028   GNUNET_memcpy (name_tmp,
1029                  label,
1030                  name_len);
1031   rd_ser = &name_tmp[name_len];
1032   GNUNET_assert (rd_ser_len ==
1033                  GNUNET_GNSRECORD_records_serialize (rd_count,
1034                                                      rd,
1035                                                      rd_ser_len,
1036                                                      rd_ser));
1037   LOG (GNUNET_ERROR_TYPE_DEBUG,
1038        "Sending NAMESTORE_RECORD_STORE message for name `%s' with %u records\n",
1039        label,
1040        rd_count);
1041
1042   if (NULL == h->mq)
1043     qe->env = env;
1044   else
1045     GNUNET_MQ_send (h->mq,
1046                     env);
1047   return qe;
1048 }
1049
1050
1051 /**
1052  * Set the desired nick name for a zone
1053  *
1054  * @param h handle to the namestore
1055  * @param pkey private key of the zone
1056  * @param nick the nick name to set
1057  * @param cont continuation to call when done
1058  * @param cont_cls closure for @a cont
1059  * @return handle to abort the request
1060  */
1061 struct GNUNET_NAMESTORE_QueueEntry *
1062 GNUNET_NAMESTORE_set_nick (struct GNUNET_NAMESTORE_Handle *h,
1063                            const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
1064                            const char *nick,
1065                            GNUNET_NAMESTORE_ContinuationWithStatus cont,
1066                            void *cont_cls)
1067 {
1068   struct GNUNET_GNSRECORD_Data rd;
1069
1070   if (NULL == h->mq)
1071     return NULL;
1072   memset (&rd, 0, sizeof (rd));
1073   rd.data = nick;
1074   rd.data_size = strlen (nick) +1;
1075   rd.record_type = GNUNET_GNSRECORD_TYPE_NICK;
1076   rd.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
1077   rd.flags |= GNUNET_GNSRECORD_RF_PRIVATE;
1078   return GNUNET_NAMESTORE_records_store (h,
1079                                          pkey,
1080                                          GNUNET_GNS_MASTERZONE_STR,
1081                                          1,
1082                                          &rd,
1083                                          cont,
1084                                          cont_cls);
1085 }
1086
1087
1088 /**
1089  * Lookup an item in the namestore.
1090  *
1091  * @param h handle to the namestore
1092  * @param pkey private key of the zone
1093  * @param label name that is being mapped (at most 255 characters long)
1094  * @param error_cb function to call on error (i.e. disconnect)
1095  * @param error_cb_cls closure for @a error_cb
1096  * @param rm function to call with the result (with 0 records if we don't have that label)
1097  * @param rm_cls closure for @a rm
1098  * @return handle to abort the request
1099  */
1100 struct GNUNET_NAMESTORE_QueueEntry *
1101 GNUNET_NAMESTORE_records_lookup (struct GNUNET_NAMESTORE_Handle *h,
1102                                  const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
1103                                  const char *label,
1104                                  GNUNET_SCHEDULER_TaskCallback error_cb,
1105                                  void *error_cb_cls,
1106                                  GNUNET_NAMESTORE_RecordMonitor rm,
1107                                  void *rm_cls)
1108 {
1109   struct GNUNET_NAMESTORE_QueueEntry *qe;
1110   struct GNUNET_MQ_Envelope *env;
1111   struct LabelLookupMessage *msg;
1112   size_t label_len;
1113
1114   if (1 == (label_len = strlen (label) + 1))
1115   {
1116     GNUNET_break (0);
1117     return NULL;
1118   }
1119
1120   qe = GNUNET_new (struct GNUNET_NAMESTORE_QueueEntry);
1121   qe->h = h;
1122   qe->error_cb = error_cb;
1123   qe->error_cb_cls = error_cb_cls;
1124   qe->proc = rm;
1125   qe->proc_cls = rm_cls;
1126   qe->op_id = get_op_id(h);
1127   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
1128                                     h->op_tail,
1129                                     qe);
1130
1131   env = GNUNET_MQ_msg_extra (msg,
1132                              label_len,
1133                              GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP);
1134   msg->gns_header.r_id = htonl (qe->op_id);
1135   msg->zone = *pkey;
1136   msg->label_len = htonl (label_len);
1137   GNUNET_memcpy (&msg[1],
1138           label,
1139           label_len);
1140   if (NULL == h->mq)
1141     qe->env = env;
1142   else
1143     GNUNET_MQ_send (h->mq,
1144                     env);
1145   return qe;
1146 }
1147
1148
1149 /**
1150  * Look for an existing PKEY delegation record for a given public key.
1151  * Returns at most one result to the processor.
1152  *
1153  * @param h handle to the namestore
1154  * @param zone public key of the zone to look up in, never NULL
1155  * @param value_zone public key of the target zone (value), never NULL
1156  * @param error_cb function to call on error (i.e. disconnect)
1157  * @param error_cb_cls closure for @a error_cb
1158  * @param proc function to call on the matching records, or with
1159  *        NULL (rd_count == 0) if there are no matching records
1160  * @param proc_cls closure for @a proc
1161  * @return a handle that can be used to
1162  *         cancel
1163  */
1164 struct GNUNET_NAMESTORE_QueueEntry *
1165 GNUNET_NAMESTORE_zone_to_name (struct GNUNET_NAMESTORE_Handle *h,
1166                                const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1167                                const struct GNUNET_CRYPTO_EcdsaPublicKey *value_zone,
1168                                GNUNET_SCHEDULER_TaskCallback error_cb,
1169                                void *error_cb_cls,
1170                                GNUNET_NAMESTORE_RecordMonitor proc,
1171                                void *proc_cls)
1172 {
1173   struct GNUNET_NAMESTORE_QueueEntry *qe;
1174   struct GNUNET_MQ_Envelope *env;
1175   struct ZoneToNameMessage *msg;
1176   uint32_t rid;
1177
1178   rid = get_op_id(h);
1179   qe = GNUNET_new (struct GNUNET_NAMESTORE_QueueEntry);
1180   qe->h = h;
1181   qe->error_cb = error_cb;
1182   qe->error_cb_cls = error_cb_cls;
1183   qe->proc = proc;
1184   qe->proc_cls = proc_cls;
1185   qe->op_id = rid;
1186   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
1187                                     h->op_tail,
1188                                     qe);
1189
1190   env = GNUNET_MQ_msg (msg,
1191                        GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME);
1192   msg->gns_header.r_id = htonl (rid);
1193   msg->zone = *zone;
1194   msg->value_zone = *value_zone;
1195   if (NULL == h->mq)
1196     qe->env = env;
1197   else
1198     GNUNET_MQ_send (h->mq,
1199                     env);
1200   return qe;
1201 }
1202
1203
1204 /**
1205  * Starts a new zone iteration (used to periodically PUT all of our
1206  * records into our DHT). This MUST lock the struct GNUNET_NAMESTORE_Handle
1207  * for any other calls than #GNUNET_NAMESTORE_zone_iterator_next and
1208  * #GNUNET_NAMESTORE_zone_iteration_stop. @a proc will be called once
1209  * immediately, and then again after
1210  * #GNUNET_NAMESTORE_zone_iterator_next is invoked.
1211  *
1212  * @param h handle to the namestore
1213  * @param zone zone to access, NULL for all zones
1214  * @param error_cb function to call on error (i.e. disconnect)
1215  * @param error_cb_cls closure for @a error_cb
1216  * @param proc function to call on each name from the zone; it
1217  *        will be called repeatedly with a value (if available)
1218  * @param proc_cls closure for @a proc
1219  * @param finish_cb function to call on completion
1220  * @param finish_cb_cls closure for @a finish_cb
1221  * @return an iterator handle to use for iteration
1222  */
1223 struct GNUNET_NAMESTORE_ZoneIterator *
1224 GNUNET_NAMESTORE_zone_iteration_start (struct GNUNET_NAMESTORE_Handle *h,
1225                                        const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1226                                        GNUNET_SCHEDULER_TaskCallback error_cb,
1227                                        void *error_cb_cls,
1228                                        GNUNET_NAMESTORE_RecordMonitor proc,
1229                                        void *proc_cls,
1230                                        GNUNET_SCHEDULER_TaskCallback finish_cb,
1231                                        void *finish_cb_cls)
1232 {
1233   struct GNUNET_NAMESTORE_ZoneIterator *it;
1234   struct GNUNET_MQ_Envelope *env;
1235   struct ZoneIterationStartMessage *msg;
1236   uint32_t rid;
1237
1238   LOG (GNUNET_ERROR_TYPE_DEBUG,
1239        "Sending ZONE_ITERATION_START message\n");
1240   rid = get_op_id (h);
1241   it = GNUNET_new (struct GNUNET_NAMESTORE_ZoneIterator);
1242   it->h = h;
1243   it->error_cb = error_cb;
1244   it->error_cb_cls = error_cb_cls;
1245   it->finish_cb = finish_cb;
1246   it->finish_cb_cls = finish_cb_cls;
1247   it->proc = proc;
1248   it->proc_cls = proc_cls;
1249   it->op_id = rid;
1250   if (NULL != zone)
1251     it->zone = *zone;
1252   GNUNET_CONTAINER_DLL_insert_tail (h->z_head,
1253                                     h->z_tail,
1254                                     it);
1255   env = GNUNET_MQ_msg (msg,
1256                        GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START);
1257   msg->gns_header.r_id = htonl (rid);
1258   if (NULL != zone)
1259     msg->zone = *zone;
1260   if (NULL == h->mq)
1261     it->env = env;
1262   else
1263     GNUNET_MQ_send (h->mq,
1264                     env);
1265   return it;
1266 }
1267
1268
1269 /**
1270  * Calls the record processor specified in #GNUNET_NAMESTORE_zone_iteration_start
1271  * for the next record.
1272  *
1273  * @param it the iterator
1274  */
1275 void
1276 GNUNET_NAMESTORE_zone_iterator_next (struct GNUNET_NAMESTORE_ZoneIterator *it)
1277 {
1278   struct GNUNET_NAMESTORE_Handle *h = it->h;
1279   struct ZoneIterationNextMessage *msg;
1280   struct GNUNET_MQ_Envelope *env;
1281
1282   LOG (GNUNET_ERROR_TYPE_DEBUG,
1283        "Sending ZONE_ITERATION_NEXT message\n");
1284   env = GNUNET_MQ_msg (msg,
1285                        GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT);
1286   msg->gns_header.r_id = htonl (it->op_id);
1287   GNUNET_MQ_send (h->mq,
1288                   env);
1289 }
1290
1291
1292 /**
1293  * Stops iteration and releases the namestore handle for further calls.
1294  *
1295  * @param it the iterator
1296  */
1297 void
1298 GNUNET_NAMESTORE_zone_iteration_stop (struct GNUNET_NAMESTORE_ZoneIterator *it)
1299 {
1300   struct GNUNET_NAMESTORE_Handle *h = it->h;
1301   struct GNUNET_MQ_Envelope *env;
1302   struct ZoneIterationStopMessage *msg;
1303
1304   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1305               "Sending ZONE_ITERATION_STOP message\n");
1306   env = GNUNET_MQ_msg (msg,
1307                        GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP);
1308   msg->gns_header.r_id = htonl (it->op_id);
1309   GNUNET_MQ_send (h->mq,
1310                   env);
1311   free_ze (it);
1312 }
1313
1314
1315 /**
1316  * Cancel a namestore operation.  The final callback from the
1317  * operation must not have been done yet.
1318  *
1319  * @param qe operation to cancel
1320  */
1321 void
1322 GNUNET_NAMESTORE_cancel (struct GNUNET_NAMESTORE_QueueEntry *qe)
1323 {
1324   free_qe (qe);
1325 }
1326
1327
1328 /* end of namestore_api.c */