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