small API change: do no longer pass rarely needed GNUNET_SCHEDULER_TaskContext to...
[oweals/gnunet.git] / src / namecache / namecache_api.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2010-2013 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 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   struct GNUNET_SCHEDULER_Task * 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  */
499 static void
500 reconnect_task (void *cls)
501 {
502   struct GNUNET_NAMECACHE_Handle *h = cls;
503
504   h->reconnect_task = NULL;
505   reconnect (h);
506 }
507
508
509 /**
510  * Disconnect from service and then reconnect.
511  *
512  * @param h our handle
513  */
514 static void
515 force_reconnect (struct GNUNET_NAMECACHE_Handle *h)
516 {
517   if (NULL != h->th)
518   {
519     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
520     h->th = NULL;
521   }
522   h->reconnect = GNUNET_NO;
523   GNUNET_CLIENT_disconnect (h->client);
524   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
525               "Reconnecting to namecache\n");
526   h->is_receiving = GNUNET_NO;
527   h->client = NULL;
528   h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
529   h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
530                                                     &reconnect_task,
531                                                     h);
532 }
533
534
535 /**
536  * Get a fresh operation id to distinguish between namecache requests
537  *
538  * @param h the namecache handle
539  * @return next operation id to use
540  */
541 static uint32_t
542 get_op_id (struct GNUNET_NAMECACHE_Handle *h)
543 {
544   return h->last_op_id_used++;
545 }
546
547
548 /**
549  * Initialize the connection with the NAMECACHE service.
550  *
551  * @param cfg configuration to use
552  * @return handle to the GNS service, or NULL on error
553  */
554 struct GNUNET_NAMECACHE_Handle *
555 GNUNET_NAMECACHE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
556 {
557   struct GNUNET_NAMECACHE_Handle *h;
558
559   h = GNUNET_new (struct GNUNET_NAMECACHE_Handle);
560   h->cfg = cfg;
561   h->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect_task, h);
562   h->last_op_id_used = 0;
563   return h;
564 }
565
566
567 /**
568  * Disconnect from the namecache service (and free associated
569  * resources).
570  *
571  * @param h handle to the namecache
572  */
573 void
574 GNUNET_NAMECACHE_disconnect (struct GNUNET_NAMECACHE_Handle *h)
575 {
576   struct PendingMessage *p;
577   struct GNUNET_NAMECACHE_QueueEntry *q;
578
579   LOG (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
580   GNUNET_assert (NULL != h);
581   if (NULL != h->th)
582   {
583     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
584     h->th = NULL;
585   }
586   while (NULL != (p = h->pending_head))
587   {
588     GNUNET_CONTAINER_DLL_remove (h->pending_head, h->pending_tail, p);
589     GNUNET_free (p);
590   }
591   GNUNET_break (NULL == h->op_head);
592   while (NULL != (q = h->op_head))
593   {
594     GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, q);
595     GNUNET_free (q);
596   }
597   if (NULL != h->client)
598   {
599     GNUNET_CLIENT_disconnect (h->client);
600     h->client = NULL;
601   }
602   if (NULL != h->reconnect_task)
603   {
604     GNUNET_SCHEDULER_cancel (h->reconnect_task);
605     h->reconnect_task = NULL;
606   }
607   GNUNET_free (h);
608 }
609
610
611 /**
612  * Store an item in the namecache.  If the item is already present,
613  * it is replaced with the new record.
614  *
615  * @param h handle to the namecache
616  * @param block block to store
617  * @param cont continuation to call when done
618  * @param cont_cls closure for cont
619  * @return handle to abort the request
620  */
621 struct GNUNET_NAMECACHE_QueueEntry *
622 GNUNET_NAMECACHE_block_cache (struct GNUNET_NAMECACHE_Handle *h,
623                               const struct GNUNET_GNSRECORD_Block *block,
624                               GNUNET_NAMECACHE_ContinuationWithStatus cont,
625                               void *cont_cls)
626 {
627   struct GNUNET_NAMECACHE_QueueEntry *qe;
628   struct PendingMessage *pe;
629   struct BlockCacheMessage *msg;
630   uint32_t rid;
631   size_t blen;
632   size_t msg_size;
633
634   GNUNET_assert (NULL != h);
635   blen = ntohl (block->purpose.size)
636     - sizeof (struct GNUNET_TIME_AbsoluteNBO)
637     - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose);
638   rid = get_op_id (h);
639   qe = GNUNET_new (struct GNUNET_NAMECACHE_QueueEntry);
640   qe->nsh = h;
641   qe->cont = cont;
642   qe->cont_cls = cont_cls;
643   qe->op_id = rid;
644   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe);
645
646   /* setup msg */
647   msg_size = sizeof (struct BlockCacheMessage) + blen;
648   pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size);
649   pe->size = msg_size;
650   msg = (struct BlockCacheMessage *) &pe[1];
651   msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE);
652   msg->gns_header.header.size = htons (msg_size);
653   msg->gns_header.r_id = htonl (rid);
654   msg->expire = block->expiration_time;
655   msg->signature = block->signature;
656   msg->derived_key = block->derived_key;
657   memcpy (&msg[1], &block[1], blen);
658   LOG (GNUNET_ERROR_TYPE_DEBUG,
659        "Sending `%s' message with size %u and expiration %s\n",
660        "NAMECACHE_BLOCK_CACHE",
661        (unsigned int) msg_size,
662        GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (msg->expire)));
663   GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe);
664   do_transmit (h);
665   return qe;
666 }
667
668
669 /**
670  * Get a result for a particular key from the namecache.  The processor
671  * will only be called once.
672  *
673  * @param h handle to the namecache
674  * @param derived_hash hash of zone key combined with name to lookup
675  * @param proc function to call on the matching block, or with
676  *        NULL if there is no matching block
677  * @param proc_cls closure for proc
678  * @return a handle that can be used to cancel
679  */
680 struct GNUNET_NAMECACHE_QueueEntry *
681 GNUNET_NAMECACHE_lookup_block (struct GNUNET_NAMECACHE_Handle *h,
682                                const struct GNUNET_HashCode *derived_hash,
683                                GNUNET_NAMECACHE_BlockProcessor proc, void *proc_cls)
684 {
685   struct GNUNET_NAMECACHE_QueueEntry *qe;
686   struct PendingMessage *pe;
687   struct LookupBlockMessage *msg;
688   size_t msg_size;
689   uint32_t rid;
690
691   LOG (GNUNET_ERROR_TYPE_DEBUG,
692        "Looking for block under %s\n",
693        GNUNET_h2s (derived_hash));
694   rid = get_op_id(h);
695   qe = GNUNET_new (struct GNUNET_NAMECACHE_QueueEntry);
696   qe->nsh = h;
697   qe->block_proc = proc;
698   qe->block_proc_cls = proc_cls;
699   qe->op_id = rid;
700   GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe);
701
702   msg_size = sizeof (struct LookupBlockMessage);
703   pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size);
704   pe->size = msg_size;
705   msg = (struct LookupBlockMessage *) &pe[1];
706   msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK);
707   msg->gns_header.header.size = htons (msg_size);
708   msg->gns_header.r_id = htonl (rid);
709   msg->query = *derived_hash;
710   GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe);
711   do_transmit (h);
712   return qe;
713 }
714
715
716 /**
717  * Cancel a namecache operation.  The final callback from the
718  * operation must not have been done yet.
719  *
720  * @param qe operation to cancel
721  */
722 void
723 GNUNET_NAMECACHE_cancel (struct GNUNET_NAMECACHE_QueueEntry *qe)
724 {
725   struct GNUNET_NAMECACHE_Handle *h = qe->nsh;
726
727   GNUNET_assert (NULL != qe);
728   GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, qe);
729   GNUNET_free(qe);
730 }
731
732
733 /* end of namecache_api.c */