psycstore
[oweals/gnunet.git] / src / namecache / namecache_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 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  * Connection to the NAMECACHE service.
95  */
96 struct GNUNET_NAMECACHE_Handle
97 {
98
99   /**
100    * Configuration to use.
101    */
102   const struct GNUNET_CONFIGURATION_Handle *cfg;
103
104   /**
105    * Message queue to service.
106    */
107   struct GNUNET_MQ_Handle *mq;
108
109   /**
110    * Currently pending transmission request (or NULL).
111    */
112   struct GNUNET_CLIENT_TransmitHandle *th;
113
114   /**
115    * Head of pending namecache queue entries
116    */
117   struct GNUNET_NAMECACHE_QueueEntry *op_head;
118
119   /**
120    * Tail of pending namecache queue entries
121    */
122   struct GNUNET_NAMECACHE_QueueEntry *op_tail;
123
124   /**
125    * Reconnect task
126    */
127   struct GNUNET_SCHEDULER_Task *reconnect_task;
128
129   /**
130    * Delay introduced before we reconnect.
131    */
132   struct GNUNET_TIME_Relative reconnect_delay;
133
134   /**
135    * Should we reconnect to service due to some serious error?
136    */
137   int reconnect;
138
139   /**
140    * The last operation id used for a NAMECACHE operation
141    */
142   uint32_t last_op_id_used;
143
144 };
145
146
147 /**
148  * Disconnect from service and then reconnect.
149  *
150  * @param h our handle
151  */
152 static void
153 force_reconnect (struct GNUNET_NAMECACHE_Handle *h);
154
155
156 /**
157  * Find queue entry for the given @a rid.
158  *
159  * @param h handle to search
160  * @param rid request ID to look for
161  * @return NULL if not found, otherwise the queue entry (removed from the queue)
162  */
163 static struct GNUNET_NAMECACHE_QueueEntry *
164 find_qe (struct GNUNET_NAMECACHE_Handle *h,
165          uint32_t rid)
166 {
167   struct GNUNET_NAMECACHE_QueueEntry *qe;
168
169   for (qe = h->op_head; qe != NULL; qe = qe->next)
170   {
171     if (qe->op_id == rid)
172     {
173       GNUNET_CONTAINER_DLL_remove (h->op_head,
174                                    h->op_tail,
175                                    qe);
176       return qe;
177     }
178   }
179   return NULL;
180 }
181
182
183 /**
184  * Handle an incoming message of type
185  * #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE.
186  *
187  * @param cls the `struct GNUNET_NAMECACHE_Handle`
188  * @param msg the message we received
189  */
190 static int
191 check_lookup_block_response (void *cls,
192                              const struct LookupBlockResponseMessage *msg)
193 {
194   /* any length will do, format validation is in handler */
195   return GNUNET_OK;
196 }
197
198
199 /**
200  * Handle an incoming message of type
201  * #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE.
202  *
203  * @param cls the `struct GNUNET_NAMECACHE_Handle`
204  * @param msg the message we received
205  */
206 static void
207 handle_lookup_block_response (void *cls,
208                               const struct LookupBlockResponseMessage *msg)
209 {
210   struct GNUNET_NAMECACHE_Handle *h = cls;
211   size_t size;
212   struct GNUNET_NAMECACHE_QueueEntry *qe;
213
214   LOG (GNUNET_ERROR_TYPE_DEBUG,
215        "Received LOOKUP_BLOCK_RESPONSE\n");
216   qe = find_qe (h,
217                 ntohl (msg->gns_header.r_id));
218   if (NULL == qe)
219     return;
220   if (0 == GNUNET_TIME_absolute_ntoh (msg->expire).abs_value_us)
221   {
222     /* no match found */
223     if (NULL != qe->block_proc)
224       qe->block_proc (qe->block_proc_cls,
225                       NULL);
226     GNUNET_free (qe);
227     return;
228   }
229   size = ntohs (msg->gns_header.header.size)
230     - sizeof (struct LookupBlockResponseMessage);
231   {
232     char buf[size + sizeof (struct GNUNET_GNSRECORD_Block)] GNUNET_ALIGN;
233     struct GNUNET_GNSRECORD_Block *block;
234
235     block = (struct GNUNET_GNSRECORD_Block *) buf;
236     block->signature = msg->signature;
237     block->derived_key = msg->derived_key;
238     block->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
239     block->purpose.size = htonl (size +
240                                  sizeof (struct GNUNET_TIME_AbsoluteNBO) +
241                                  sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose));
242     block->expiration_time = msg->expire;
243     GNUNET_memcpy (&block[1],
244             &msg[1],
245             size);
246     if (GNUNET_OK !=
247         GNUNET_GNSRECORD_block_verify (block))
248     {
249       GNUNET_break (0);
250       if (NULL != qe->block_proc)
251         qe->block_proc (qe->block_proc_cls,
252                         NULL);
253       force_reconnect (h);
254     }
255     else
256     {
257       if (NULL != qe->block_proc)
258         qe->block_proc (qe->block_proc_cls,
259                         block);
260     }
261   }
262   GNUNET_free (qe);
263 }
264
265
266 /**
267  * Handle an incoming message of type
268  * #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE
269  *
270  * @param cls the `struct GNUNET_NAMECACHE_Handle`
271  * @param msg the message we received
272  * @param size the message size
273  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error and we did NOT notify the client
274  */
275 static void
276 handle_block_cache_response (void *cls,
277                              const struct BlockCacheResponseMessage *msg)
278 {
279   struct GNUNET_NAMECACHE_Handle *h = cls;
280   struct GNUNET_NAMECACHE_QueueEntry *qe;
281   int res;
282
283   LOG (GNUNET_ERROR_TYPE_DEBUG,
284        "Received BLOCK_CACHE_RESPONSE\n");
285   qe = find_qe (h,
286                 ntohl (msg->gns_header.r_id));
287   if (NULL == qe)
288     return;
289   res = ntohl (msg->op_result);
290   /* TODO: add actual error message from namecache to response... */
291   if (NULL != qe->cont)
292     qe->cont (qe->cont_cls,
293               res,
294               (GNUNET_OK == res)
295               ? NULL
296               : _("Namecache failed to cache block"));
297   GNUNET_free (qe);
298 }
299
300
301 /**
302  * Generic error handler, called with the appropriate error code and
303  * the same closure specified at the creation of the message queue.
304  * Not every message queue implementation supports an error handler.
305  *
306  * @param cls closure with the `struct GNUNET_NAMECACHE_Handle *`
307  * @param error error code
308  */
309 static void
310 mq_error_handler (void *cls,
311                   enum GNUNET_MQ_Error error)
312 {
313   struct GNUNET_NAMECACHE_Handle *h = cls;
314
315   force_reconnect (h);
316 }
317
318
319 /**
320  * Reconnect to namecache service.
321  *
322  * @param h the handle to the NAMECACHE service
323  */
324 static void
325 reconnect (struct GNUNET_NAMECACHE_Handle *h)
326 {
327   struct GNUNET_MQ_MessageHandler handlers[] = {
328     GNUNET_MQ_hd_var_size (lookup_block_response,
329                            GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE,
330                            struct LookupBlockResponseMessage,
331                            h),
332     GNUNET_MQ_hd_fixed_size (block_cache_response,
333                              GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE,
334                              struct BlockCacheResponseMessage,
335                              h),
336     GNUNET_MQ_handler_end ()
337   };
338   GNUNET_assert (NULL == h->mq);
339   h->mq = GNUNET_CLIENT_connecT (h->cfg,
340                                  "namecache",
341                                  handlers,
342                                  &mq_error_handler,
343                                  h);
344 }
345
346
347 /**
348  * Re-establish the connection to the service.
349  *
350  * @param cls handle to use to re-connect.
351  */
352 static void
353 reconnect_task (void *cls)
354 {
355   struct GNUNET_NAMECACHE_Handle *h = cls;
356
357   h->reconnect_task = NULL;
358   reconnect (h);
359 }
360
361
362 /**
363  * Disconnect from service and then reconnect.
364  *
365  * @param h our handle
366  */
367 static void
368 force_reconnect (struct GNUNET_NAMECACHE_Handle *h)
369 {
370   struct GNUNET_NAMECACHE_QueueEntry *qe;
371
372   h->reconnect = GNUNET_NO;
373   GNUNET_MQ_destroy (h->mq);
374   h->mq = NULL;
375   while (NULL != (qe = h->op_head))
376   {
377     GNUNET_CONTAINER_DLL_remove (h->op_head,
378                                  h->op_tail,
379                                  qe);
380     if (NULL != qe->cont)
381       qe->cont (qe->cont_cls,
382                 GNUNET_SYSERR,
383                 _("Error communicating with namecache service"));
384     GNUNET_free (qe);
385   }
386   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
387               "Reconnecting to namecache\n");
388   h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
389   h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
390                                                     &reconnect_task,
391                                                     h);
392 }
393
394
395 /**
396  * Get a fresh operation id to distinguish between namecache requests
397  *
398  * @param h the namecache handle
399  * @return next operation id to use
400  */
401 static uint32_t
402 get_op_id (struct GNUNET_NAMECACHE_Handle *h)
403 {
404   return h->last_op_id_used++;
405 }
406
407
408 /**
409  * Initialize the connection with the NAMECACHE service.
410  *
411  * @param cfg configuration to use
412  * @return handle to the GNS service, or NULL on error
413  */
414 struct GNUNET_NAMECACHE_Handle *
415 GNUNET_NAMECACHE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
416 {
417   struct GNUNET_NAMECACHE_Handle *h;
418
419   h = GNUNET_new (struct GNUNET_NAMECACHE_Handle);
420   h->cfg = cfg;
421   reconnect (h);
422   if (NULL == h->mq)
423   {
424     GNUNET_free (h);
425     return NULL;
426   }
427   return h;
428 }
429
430
431 /**
432  * Disconnect from the namecache service (and free associated
433  * resources).
434  *
435  * @param h handle to the namecache
436  */
437 void
438 GNUNET_NAMECACHE_disconnect (struct GNUNET_NAMECACHE_Handle *h)
439 {
440   struct GNUNET_NAMECACHE_QueueEntry *q;
441
442   GNUNET_break (NULL == h->op_head);
443   while (NULL != (q = h->op_head))
444   {
445     GNUNET_CONTAINER_DLL_remove (h->op_head,
446                                  h->op_tail,
447                                  q);
448     GNUNET_free (q);
449   }
450   if (NULL != h->mq)
451   {
452     GNUNET_MQ_destroy (h->mq);
453     h->mq = NULL;
454   }
455   if (NULL != h->reconnect_task)
456   {
457     GNUNET_SCHEDULER_cancel (h->reconnect_task);
458     h->reconnect_task = NULL;
459   }
460   GNUNET_free (h);
461 }
462
463
464 /**
465  * Store an item in the namecache.  If the item is already present,
466  * it is replaced with the new record.
467  *
468  * @param h handle to the namecache
469  * @param block block to store
470  * @param cont continuation to call when done
471  * @param cont_cls closure for @a cont
472  * @return handle to abort the request, NULL on error
473  */
474 struct GNUNET_NAMECACHE_QueueEntry *
475 GNUNET_NAMECACHE_block_cache (struct GNUNET_NAMECACHE_Handle *h,
476                               const struct GNUNET_GNSRECORD_Block *block,
477                               GNUNET_NAMECACHE_ContinuationWithStatus cont,
478                               void *cont_cls)
479 {
480   struct GNUNET_NAMECACHE_QueueEntry *qe;
481   struct BlockCacheMessage *msg;
482   struct GNUNET_MQ_Envelope *env;
483   uint32_t rid;
484   size_t blen;
485
486   if (NULL == h->mq)
487     return NULL;
488   blen = ntohl (block->purpose.size)
489     - sizeof (struct GNUNET_TIME_AbsoluteNBO)
490     - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose);
491   rid = get_op_id (h);
492   qe = GNUNET_new (struct GNUNET_NAMECACHE_QueueEntry);
493   qe->nsh = h;
494   qe->cont = cont;
495   qe->cont_cls = cont_cls;
496   qe->op_id = rid;
497   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
498                                     h->op_tail,
499                                     qe);
500   /* send msg */
501   env = GNUNET_MQ_msg_extra (msg,
502                              blen,
503                              GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE);
504   msg->gns_header.r_id = htonl (rid);
505   msg->expire = block->expiration_time;
506   msg->signature = block->signature;
507   msg->derived_key = block->derived_key;
508   GNUNET_memcpy (&msg[1],
509           &block[1],
510           blen);
511   GNUNET_MQ_send (h->mq,
512                   env);
513   return qe;
514 }
515
516
517 /**
518  * Get a result for a particular key from the namecache.  The processor
519  * will only be called once.
520  *
521  * @param h handle to the namecache
522  * @param derived_hash hash of zone key combined with name to lookup
523  * @param proc function to call on the matching block, or with
524  *        NULL if there is no matching block
525  * @param proc_cls closure for @a proc
526  * @return a handle that can be used to cancel, NULL on error
527  */
528 struct GNUNET_NAMECACHE_QueueEntry *
529 GNUNET_NAMECACHE_lookup_block (struct GNUNET_NAMECACHE_Handle *h,
530                                const struct GNUNET_HashCode *derived_hash,
531                                GNUNET_NAMECACHE_BlockProcessor proc,
532                                void *proc_cls)
533 {
534   struct GNUNET_NAMECACHE_QueueEntry *qe;
535   struct LookupBlockMessage *msg;
536   struct GNUNET_MQ_Envelope *env;
537   uint32_t rid;
538
539   if (NULL == h->mq)
540     return NULL;
541   LOG (GNUNET_ERROR_TYPE_DEBUG,
542        "Looking for block under %s\n",
543        GNUNET_h2s (derived_hash));
544   rid = get_op_id (h);
545   qe = GNUNET_new (struct GNUNET_NAMECACHE_QueueEntry);
546   qe->nsh = h;
547   qe->block_proc = proc;
548   qe->block_proc_cls = proc_cls;
549   qe->op_id = rid;
550   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
551                                     h->op_tail,
552                                     qe);
553   env = GNUNET_MQ_msg (msg,
554                        GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK);
555   msg->gns_header.r_id = htonl (rid);
556   msg->query = *derived_hash;
557   GNUNET_MQ_send (h->mq,
558                   env);
559   return qe;
560 }
561
562
563 /**
564  * Cancel a namecache operation.  The final callback from the
565  * operation must not have been done yet.
566  *
567  * @param qe operation to cancel
568  */
569 void
570 GNUNET_NAMECACHE_cancel (struct GNUNET_NAMECACHE_QueueEntry *qe)
571 {
572   struct GNUNET_NAMECACHE_Handle *h = qe->nsh;
573
574   GNUNET_CONTAINER_DLL_remove (h->op_head,
575                                h->op_tail,
576                                qe);
577   GNUNET_free(qe);
578 }
579
580
581 /* end of namecache_api.c */