Link namesotre to libgnunetgnsrecord too
[oweals/gnunet.git] / src / namecache / namecache_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010-2013 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file namecache/namecache_api.c
23  * @brief API to access the NAMECACHE 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_gnsrecord_lib.h"
35 #include "gnunet_signatures.h"
36 #include "gnunet_namecache_service.h"
37 #include "namecache.h"
38
39
40 #define LOG(kind,...) GNUNET_log_from (kind, "namecache-api",__VA_ARGS__)
41
42
43 /**
44  * An QueueEntry used to store information for a pending
45  * NAMECACHE record operation
46  */
47 struct GNUNET_NAMECACHE_QueueEntry
48 {
49
50   /**
51    * Kept in a DLL.
52    */
53   struct GNUNET_NAMECACHE_QueueEntry *next;
54
55   /**
56    * Kept in a DLL.
57    */
58   struct GNUNET_NAMECACHE_QueueEntry *prev;
59
60   /**
61    * Main handle to access the namecache.
62    */
63   struct GNUNET_NAMECACHE_Handle *nsh;
64
65   /**
66    * Continuation to call
67    */
68   GNUNET_NAMECACHE_ContinuationWithStatus cont;
69
70   /**
71    * Closure for @e cont.
72    */
73   void *cont_cls;
74
75   /**
76    * Function to call with the blocks we get back; or NULL.
77    */
78   GNUNET_NAMECACHE_BlockProcessor block_proc;
79
80   /**
81    * Closure for @e block_proc.
82    */
83   void *block_proc_cls;
84
85   /**
86    * The operation id this zone iteration operation has
87    */
88   uint32_t op_id;
89
90 };
91
92
93 /**
94  * Message in linked list we should send to the service.  The
95  * actual binary message follows this struct.
96  */
97 struct PendingMessage
98 {
99
100   /**
101    * Kept in a DLL.
102    */
103   struct PendingMessage *next;
104
105   /**
106    * Kept in a DLL.
107    */
108   struct PendingMessage *prev;
109
110   /**
111    * Size of the message.
112    */
113   size_t size;
114
115 };
116
117
118 /**
119  * Connection to the NAMECACHE service.
120  */
121 struct GNUNET_NAMECACHE_Handle
122 {
123
124   /**
125    * Configuration to use.
126    */
127   const struct GNUNET_CONFIGURATION_Handle *cfg;
128
129   /**
130    * Socket (if available).
131    */
132   struct GNUNET_CLIENT_Connection *client;
133
134   /**
135    * Currently pending transmission request (or NULL).
136    */
137   struct GNUNET_CLIENT_TransmitHandle *th;
138
139   /**
140    * Head of linked list of pending messages to send to the service
141    */
142   struct PendingMessage *pending_head;
143
144   /**
145    * Tail of linked list of pending messages to send to the service
146    */
147   struct PendingMessage *pending_tail;
148
149   /**
150    * Head of pending namecache queue entries
151    */
152   struct GNUNET_NAMECACHE_QueueEntry *op_head;
153
154   /**
155    * Tail of pending namecache queue entries
156    */
157   struct GNUNET_NAMECACHE_QueueEntry *op_tail;
158
159   /**
160    * Reconnect task
161    */
162   GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
163
164   /**
165    * Delay introduced before we reconnect.
166    */
167   struct GNUNET_TIME_Relative reconnect_delay;
168
169   /**
170    * Should we reconnect to service due to some serious error?
171    */
172   int reconnect;
173
174   /**
175    * Did we start to receive yet?
176    */
177   int is_receiving;
178
179   /**
180    * The last operation id used for a NAMECACHE operation
181    */
182   uint32_t last_op_id_used;
183
184 };
185
186
187 /**
188  * Disconnect from service and then reconnect.
189  *
190  * @param h our handle
191  */
192 static void
193 force_reconnect (struct GNUNET_NAMECACHE_Handle *h);
194
195
196 /**
197  * Handle an incoming message of type
198  * #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE.
199  *
200  * @param qe the respective entry in the message queue
201  * @param msg the message we received
202  * @param size the message size
203  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error and we did NOT notify the client
204  */
205 static int
206 handle_lookup_block_response (struct GNUNET_NAMECACHE_QueueEntry *qe,
207                               const struct LookupBlockResponseMessage *msg,
208                               size_t size)
209 {
210   struct GNUNET_GNSRECORD_Block *block;
211   char buf[size + sizeof (struct GNUNET_GNSRECORD_Block)
212            - sizeof (struct LookupBlockResponseMessage)];
213
214   LOG (GNUNET_ERROR_TYPE_DEBUG,
215        "Received `%s'\n",
216        "LOOKUP_BLOCK_RESPONSE");
217   if (0 == GNUNET_TIME_absolute_ntoh (msg->expire).abs_value_us)
218   {
219     /* no match found */
220     if (NULL != qe->block_proc)
221       qe->block_proc (qe->block_proc_cls, NULL);
222     return GNUNET_OK;
223   }
224
225   block = (struct GNUNET_GNSRECORD_Block *) buf;
226   block->signature = msg->signature;
227   block->derived_key = msg->derived_key;
228   block->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
229   block->purpose.size = htonl (size - sizeof (struct LookupBlockResponseMessage) +
230                                sizeof (struct GNUNET_TIME_AbsoluteNBO) +
231                                sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose));
232   block->expiration_time = msg->expire;
233   memcpy (&block[1],
234           &msg[1],
235           size - sizeof (struct LookupBlockResponseMessage));
236   if (GNUNET_OK !=
237       GNUNET_GNSRECORD_block_verify (block))
238   {
239     GNUNET_break (0);
240     return GNUNET_SYSERR;
241   }
242   if (NULL != qe->block_proc)
243     qe->block_proc (qe->block_proc_cls, block);
244   else
245     GNUNET_break (0);
246   return GNUNET_OK;
247 }
248
249
250 /**
251  * Handle an incoming message of type
252  * #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE
253  *
254  * @param qe the respective entry in the message queue
255  * @param msg the message we received
256  * @param size the message size
257  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error and we did NOT notify the client
258  */
259 static int
260 handle_block_cache_response (struct GNUNET_NAMECACHE_QueueEntry *qe,
261                             const struct BlockCacheResponseMessage *msg,
262                             size_t size)
263 {
264   int res;
265
266   LOG (GNUNET_ERROR_TYPE_DEBUG,
267        "Received `%s'\n",
268        "BLOCK_CACHE_RESPONSE");
269   res = ntohl (msg->op_result);
270   /* TODO: add actual error message from namecache to response... */
271   if (NULL != qe->cont)
272     qe->cont (qe->cont_cls,
273               res,
274               (GNUNET_OK == res) ?
275               NULL
276               : _("Namecache failed to cache block"));
277   return GNUNET_OK;
278 }
279
280
281 /**
282  * Handle incoming messages for record operations
283  *
284  * @param qe the respective zone iteration handle
285  * @param msg the message we received
286  * @param type the message type in host byte order
287  * @param size the message size
288  * @return #GNUNET_OK on success, #GNUNET_NO if we notified the client about
289  *         the error, #GNUNET_SYSERR on error and we did NOT notify the client
290  */
291 static int
292 manage_record_operations (struct GNUNET_NAMECACHE_QueueEntry *qe,
293                           const struct GNUNET_MessageHeader *msg,
294                           uint16_t type,
295                           size_t size)
296 {
297   /* handle different message type */
298   switch (type)
299   {
300   case GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE:
301     if (size < sizeof (struct LookupBlockResponseMessage))
302     {
303       GNUNET_break (0);
304       return GNUNET_SYSERR;
305     }
306     return handle_lookup_block_response (qe, (const struct LookupBlockResponseMessage *) msg, size);
307   case GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE:
308     if (size != sizeof (struct BlockCacheResponseMessage))
309     {
310       GNUNET_break (0);
311       return GNUNET_SYSERR;
312     }
313     return handle_block_cache_response (qe, (const struct BlockCacheResponseMessage *) msg, size);
314   default:
315     GNUNET_break (0);
316     return GNUNET_SYSERR;
317   }
318 }
319
320
321 /**
322  * Type of a function to call when we receive a message
323  * from the service.
324  *
325  * @param cls the `struct GNUNET_NAMECACHE_SchedulingHandle`
326  * @param msg message received, NULL on timeout or fatal error
327  */
328 static void
329 process_namecache_message (void *cls,
330                            const struct GNUNET_MessageHeader *msg)
331 {
332   struct GNUNET_NAMECACHE_Handle *h = cls;
333   const struct GNUNET_NAMECACHE_Header *gm;
334   struct GNUNET_NAMECACHE_QueueEntry *qe;
335   uint16_t size;
336   uint16_t type;
337   uint32_t r_id;
338   int ret;
339
340   if (NULL == msg)
341   {
342     force_reconnect (h);
343     return;
344   }
345   size = ntohs (msg->size);
346   type = ntohs (msg->type);
347   if (size < sizeof (struct GNUNET_NAMECACHE_Header))
348   {
349     GNUNET_break_op (0);
350     GNUNET_CLIENT_receive (h->client,
351                            &process_namecache_message, h,
352                            GNUNET_TIME_UNIT_FOREVER_REL);
353     return;
354   }
355   gm = (const struct GNUNET_NAMECACHE_Header *) msg;
356   r_id = ntohl (gm->r_id);
357
358   LOG (GNUNET_ERROR_TYPE_DEBUG,
359        "Received message type %u size %u op %u\n",
360        (unsigned int) type,
361        (unsigned int) size,
362        (unsigned int) r_id);
363
364   /* Is it a record related operation ? */
365   for (qe = h->op_head; qe != NULL; qe = qe->next)
366     if (qe->op_id == r_id)
367       break;
368   if (NULL != qe)
369   {
370     ret = manage_record_operations (qe, msg, type, size);
371     if (GNUNET_SYSERR == ret)
372     {
373       /* protocol error, need to reconnect */
374       h->reconnect = GNUNET_YES;
375     }
376     else
377     {
378       /* client was notified about success or failure, clean up 'qe' */
379       GNUNET_CONTAINER_DLL_remove (h->op_head,
380                                    h->op_tail,
381                                    qe);
382       GNUNET_free (qe);
383     }
384   }
385   if (GNUNET_YES == h->reconnect)
386   {
387     force_reconnect (h);
388     return;
389   }
390   GNUNET_CLIENT_receive (h->client, &process_namecache_message, h,
391                          GNUNET_TIME_UNIT_FOREVER_REL);
392 }
393
394
395 /**
396  * Transmit messages from the message queue to the service
397  * (if there are any, and if we are not already trying).
398  *
399  * @param h handle to use
400  */
401 static void
402 do_transmit (struct GNUNET_NAMECACHE_Handle *h);
403
404
405 /**
406  * We can now transmit a message to NAMECACHE. Do it.
407  *
408  * @param cls the `struct GNUNET_NAMECACHE_Handle`
409  * @param size number of bytes we can transmit
410  * @param buf where to copy the messages
411  * @return number of bytes copied into @a buf
412  */
413 static size_t
414 transmit_message_to_namecache (void *cls,
415                                size_t size,
416                                void *buf)
417 {
418   struct GNUNET_NAMECACHE_Handle *h = cls;
419   struct PendingMessage *p;
420   size_t ret;
421   char *cbuf;
422
423   h->th = NULL;
424   if ((0 == size) || (NULL == buf))
425   {
426     force_reconnect (h);
427     return 0;
428   }
429   ret = 0;
430   cbuf = buf;
431   while ( (NULL != (p = h->pending_head)) &&
432           (p->size <= size) )
433   {
434     memcpy (&cbuf[ret], &p[1], p->size);
435     ret += p->size;
436     size -= p->size;
437     GNUNET_CONTAINER_DLL_remove (h->pending_head,
438                                  h->pending_tail,
439                                  p);
440     if (GNUNET_NO == h->is_receiving)
441     {
442       h->is_receiving = GNUNET_YES;
443       GNUNET_CLIENT_receive (h->client,
444                              &process_namecache_message, h,
445                              GNUNET_TIME_UNIT_FOREVER_REL);
446     }
447     GNUNET_free (p);
448   }
449   do_transmit (h);
450   return ret;
451 }
452
453
454 /**
455  * Transmit messages from the message queue to the service
456  * (if there are any, and if we are not already trying).
457  *
458  * @param h handle to use
459  */
460 static void
461 do_transmit (struct GNUNET_NAMECACHE_Handle *h)
462 {
463   struct PendingMessage *p;
464
465   if (NULL != h->th)
466     return; /* transmission request already pending */
467   if (NULL == (p = h->pending_head))
468     return; /* transmission queue empty */
469   if (NULL == h->client)
470     return;                     /* currently reconnecting */
471   h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, p->size,
472                                                GNUNET_TIME_UNIT_FOREVER_REL,
473                                                GNUNET_NO, &transmit_message_to_namecache,
474                                                h);
475   GNUNET_break (NULL != h->th);
476 }
477
478
479 /**
480  * Reconnect to namecache service.
481  *
482  * @param h the handle to the NAMECACHE service
483  */
484 static void
485 reconnect (struct GNUNET_NAMECACHE_Handle *h)
486 {
487   GNUNET_assert (NULL == h->client);
488   h->client = GNUNET_CLIENT_connect ("namecache", h->cfg);
489   GNUNET_assert (NULL != h->client);
490   do_transmit (h);
491 }
492
493
494 /**
495  * Re-establish the connection to the service.
496  *
497  * @param cls handle to use to re-connect.
498  * @param tc scheduler context
499  */
500 static void
501 reconnect_task (void *cls,
502                 const struct GNUNET_SCHEDULER_TaskContext *tc)
503 {
504   struct GNUNET_NAMECACHE_Handle *h = cls;
505
506   h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
507   reconnect (h);
508 }
509
510
511 /**
512  * Disconnect from service and then reconnect.
513  *
514  * @param h our handle
515  */
516 static void
517 force_reconnect (struct GNUNET_NAMECACHE_Handle *h)
518 {
519   if (NULL != h->th)
520   {
521     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
522     h->th = NULL;
523   }
524   h->reconnect = GNUNET_NO;
525   GNUNET_CLIENT_disconnect (h->client);
526   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
527               "Reconnecting to namecache\n");
528   h->is_receiving = GNUNET_NO;
529   h->client = NULL;
530   h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
531   h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
532                                                     &reconnect_task,
533                                                     h);
534 }
535
536
537 /**
538  * Get a fresh operation id to distinguish between namecache requests
539  *
540  * @param h the namecache handle
541  * @return next operation id to use
542  */
543 static uint32_t
544 get_op_id (struct GNUNET_NAMECACHE_Handle *h)
545 {
546   return h->last_op_id_used++;
547 }
548
549
550 /**
551  * Initialize the connection with the NAMECACHE service.
552  *
553  * @param cfg configuration to use
554  * @return handle to the GNS service, or NULL on error
555  */
556 struct GNUNET_NAMECACHE_Handle *
557 GNUNET_NAMECACHE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
558 {
559   struct GNUNET_NAMECACHE_Handle *h;
560
561   h = GNUNET_new (struct GNUNET_NAMECACHE_Handle);
562   h->cfg = cfg;
563   h->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect_task, h);
564   h->last_op_id_used = 0;
565   return h;
566 }
567
568
569 /**
570  * Disconnect from the namecache service (and free associated
571  * resources).
572  *
573  * @param h handle to the namecache
574  */
575 void
576 GNUNET_NAMECACHE_disconnect (struct GNUNET_NAMECACHE_Handle *h)
577 {
578   struct PendingMessage *p;
579   struct GNUNET_NAMECACHE_QueueEntry *q;
580
581   LOG (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
582   GNUNET_assert (NULL != h);
583   if (NULL != h->th)
584   {
585     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
586     h->th = NULL;
587   }
588   while (NULL != (p = h->pending_head))
589   {
590     GNUNET_CONTAINER_DLL_remove (h->pending_head, h->pending_tail, p);
591     GNUNET_free (p);
592   }
593   GNUNET_break (NULL == h->op_head);
594   while (NULL != (q = h->op_head))
595   {
596     GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, q);
597     GNUNET_free (q);
598   }
599   if (NULL != h->client)
600   {
601     GNUNET_CLIENT_disconnect (h->client);
602     h->client = NULL;
603   }
604   if (GNUNET_SCHEDULER_NO_TASK != h->reconnect_task)
605   {
606     GNUNET_SCHEDULER_cancel (h->reconnect_task);
607     h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
608   }
609   GNUNET_free (h);
610 }
611
612
613 /**
614  * Store an item in the namecache.  If the item is already present,
615  * it is replaced with the new record.
616  *
617  * @param h handle to the namecache
618  * @param block block to store
619  * @param cont continuation to call when done
620  * @param cont_cls closure for cont
621  * @return handle to abort the request
622  */
623 struct GNUNET_NAMECACHE_QueueEntry *
624 GNUNET_NAMECACHE_block_cache (struct GNUNET_NAMECACHE_Handle *h,
625                               const struct GNUNET_GNSRECORD_Block *block,
626                               GNUNET_NAMECACHE_ContinuationWithStatus cont,
627                               void *cont_cls)
628 {
629   struct GNUNET_NAMECACHE_QueueEntry *qe;
630   struct PendingMessage *pe;
631   struct BlockCacheMessage *msg;
632   uint32_t rid;
633   size_t blen;
634   size_t msg_size;
635
636   GNUNET_assert (NULL != h);
637   blen = ntohl (block->purpose.size)
638     - sizeof (struct GNUNET_TIME_AbsoluteNBO)
639     - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose);
640   rid = get_op_id (h);
641   qe = GNUNET_new (struct GNUNET_NAMECACHE_QueueEntry);
642   qe->nsh = h;
643   qe->cont = cont;
644   qe->cont_cls = cont_cls;
645   qe->op_id = rid;
646   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe);
647
648   /* setup msg */
649   msg_size = sizeof (struct BlockCacheMessage) + blen;
650   pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size);
651   pe->size = msg_size;
652   msg = (struct BlockCacheMessage *) &pe[1];
653   msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE);
654   msg->gns_header.header.size = htons (msg_size);
655   msg->gns_header.r_id = htonl (rid);
656   msg->expire = block->expiration_time;
657   msg->signature = block->signature;
658   msg->derived_key = block->derived_key;
659   memcpy (&msg[1], &block[1], blen);
660   LOG (GNUNET_ERROR_TYPE_DEBUG,
661        "Sending `%s' message with size %u and expiration %s\n",
662        "NAMECACHE_BLOCK_CACHE",
663        (unsigned int) msg_size,
664        GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (msg->expire)));
665   GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe);
666   do_transmit (h);
667   return qe;
668 }
669
670
671 /**
672  * Get a result for a particular key from the namecache.  The processor
673  * will only be called once.
674  *
675  * @param h handle to the namecache
676  * @param derived_hash hash of zone key combined with name to lookup
677  * @param proc function to call on the matching block, or with
678  *        NULL if there is no matching block
679  * @param proc_cls closure for proc
680  * @return a handle that can be used to cancel
681  */
682 struct GNUNET_NAMECACHE_QueueEntry *
683 GNUNET_NAMECACHE_lookup_block (struct GNUNET_NAMECACHE_Handle *h,
684                                const struct GNUNET_HashCode *derived_hash,
685                                GNUNET_NAMECACHE_BlockProcessor proc, void *proc_cls)
686 {
687   struct GNUNET_NAMECACHE_QueueEntry *qe;
688   struct PendingMessage *pe;
689   struct LookupBlockMessage *msg;
690   size_t msg_size;
691   uint32_t rid;
692
693   GNUNET_assert (NULL != h);
694   GNUNET_assert (NULL != derived_hash);
695   LOG (GNUNET_ERROR_TYPE_DEBUG,
696        "Looking for block under %s\n",
697        GNUNET_h2s (derived_hash));
698   rid = get_op_id(h);
699   qe = GNUNET_new (struct GNUNET_NAMECACHE_QueueEntry);
700   qe->nsh = h;
701   qe->block_proc = proc;
702   qe->block_proc_cls = proc_cls;
703   qe->op_id = rid;
704   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe);
705
706   msg_size = sizeof (struct LookupBlockMessage);
707   pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size);
708   pe->size = msg_size;
709   msg = (struct LookupBlockMessage *) &pe[1];
710   msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK);
711   msg->gns_header.header.size = htons (msg_size);
712   msg->gns_header.r_id = htonl (rid);
713   msg->query = *derived_hash;
714   GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe);
715   do_transmit (h);
716   return qe;
717 }
718
719
720 /**
721  * Cancel a namecache operation.  The final callback from the
722  * operation must not have been done yet.
723  *
724  * @param qe operation to cancel
725  */
726 void
727 GNUNET_NAMECACHE_cancel (struct GNUNET_NAMECACHE_QueueEntry *qe)
728 {
729   struct GNUNET_NAMECACHE_Handle *h = qe->nsh;
730
731   GNUNET_assert (NULL != qe);
732   GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, qe);
733   GNUNET_free(qe);
734 }
735
736
737 /* end of namecache_api.c */