2 This file is part of GNUnet.
3 (C) 2010-2013 Christian Grothoff (and other contributing authors)
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.
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.
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.
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
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 "gnunet_namestore_service.h"
38 #include "namecache.h"
41 #define LOG(kind,...) GNUNET_log_from (kind, "namecache-api",__VA_ARGS__)
45 * An QueueEntry used to store information for a pending
46 * NAMECACHE record operation
48 struct GNUNET_NAMECACHE_QueueEntry
54 struct GNUNET_NAMECACHE_QueueEntry *next;
59 struct GNUNET_NAMECACHE_QueueEntry *prev;
62 * Main handle to access the namecache.
64 struct GNUNET_NAMECACHE_Handle *nsh;
67 * Continuation to call
69 GNUNET_NAMECACHE_ContinuationWithStatus cont;
72 * Closure for @e cont.
77 * Function to call with the blocks we get back; or NULL.
79 GNUNET_NAMECACHE_BlockProcessor block_proc;
82 * Closure for @e block_proc.
87 * The operation id this zone iteration operation has
95 * Message in linked list we should send to the service. The
96 * actual binary message follows this struct.
104 struct PendingMessage *next;
109 struct PendingMessage *prev;
112 * Size of the message.
120 * Connection to the NAMECACHE service.
122 struct GNUNET_NAMECACHE_Handle
126 * Configuration to use.
128 const struct GNUNET_CONFIGURATION_Handle *cfg;
131 * Socket (if available).
133 struct GNUNET_CLIENT_Connection *client;
136 * Currently pending transmission request (or NULL).
138 struct GNUNET_CLIENT_TransmitHandle *th;
141 * Head of linked list of pending messages to send to the service
143 struct PendingMessage *pending_head;
146 * Tail of linked list of pending messages to send to the service
148 struct PendingMessage *pending_tail;
151 * Head of pending namecache queue entries
153 struct GNUNET_NAMECACHE_QueueEntry *op_head;
156 * Tail of pending namecache queue entries
158 struct GNUNET_NAMECACHE_QueueEntry *op_tail;
163 GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
166 * Delay introduced before we reconnect.
168 struct GNUNET_TIME_Relative reconnect_delay;
171 * Should we reconnect to service due to some serious error?
176 * Did we start to receive yet?
181 * The last operation id used for a NAMECACHE operation
183 uint32_t last_op_id_used;
189 * Disconnect from service and then reconnect.
191 * @param h our handle
194 force_reconnect (struct GNUNET_NAMECACHE_Handle *h);
198 * Handle an incoming message of type
199 * #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE.
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
207 handle_lookup_block_response (struct GNUNET_NAMECACHE_QueueEntry *qe,
208 const struct LookupBlockResponseMessage *msg,
211 struct GNUNET_GNSRECORD_Block *block;
212 char buf[size + sizeof (struct GNUNET_GNSRECORD_Block)
213 - sizeof (struct LookupBlockResponseMessage)];
215 LOG (GNUNET_ERROR_TYPE_DEBUG,
217 "LOOKUP_BLOCK_RESPONSE");
218 if (0 == GNUNET_TIME_absolute_ntoh (msg->expire).abs_value_us)
221 if (NULL != qe->block_proc)
222 qe->block_proc (qe->block_proc_cls, NULL);
226 block = (struct GNUNET_GNSRECORD_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;
236 size - sizeof (struct LookupBlockResponseMessage));
238 GNUNET_GNSRECORD_block_verify (block))
241 return GNUNET_SYSERR;
243 if (NULL != qe->block_proc)
244 qe->block_proc (qe->block_proc_cls, block);
252 * Handle an incoming message of type
253 * #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE
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
261 handle_block_cache_response (struct GNUNET_NAMECACHE_QueueEntry *qe,
262 const struct BlockCacheResponseMessage *msg,
267 LOG (GNUNET_ERROR_TYPE_DEBUG,
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,
277 : _("Namecache failed to cache block"));
283 * Handle incoming messages for record operations
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
293 manage_record_operations (struct GNUNET_NAMECACHE_QueueEntry *qe,
294 const struct GNUNET_MessageHeader *msg,
298 /* handle different message type */
301 case GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE:
302 if (size < sizeof (struct LookupBlockResponseMessage))
305 return GNUNET_SYSERR;
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))
312 return GNUNET_SYSERR;
314 return handle_block_cache_response (qe, (const struct BlockCacheResponseMessage *) msg, size);
317 return GNUNET_SYSERR;
323 * Type of a function to call when we receive a message
326 * @param cls the `struct GNUNET_NAMECACHE_SchedulingHandle`
327 * @param msg message received, NULL on timeout or fatal error
330 process_namecache_message (void *cls,
331 const struct GNUNET_MessageHeader *msg)
333 struct GNUNET_NAMECACHE_Handle *h = cls;
334 const struct GNUNET_NAMECACHE_Header *gm;
335 struct GNUNET_NAMECACHE_QueueEntry *qe;
346 size = ntohs (msg->size);
347 type = ntohs (msg->type);
348 if (size < sizeof (struct GNUNET_NAMECACHE_Header))
351 GNUNET_CLIENT_receive (h->client,
352 &process_namecache_message, h,
353 GNUNET_TIME_UNIT_FOREVER_REL);
356 gm = (const struct GNUNET_NAMECACHE_Header *) msg;
357 r_id = ntohl (gm->r_id);
359 LOG (GNUNET_ERROR_TYPE_DEBUG,
360 "Received message type %u size %u op %u\n",
363 (unsigned int) r_id);
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)
371 ret = manage_record_operations (qe, msg, type, size);
372 if (GNUNET_SYSERR == ret)
374 /* protocol error, need to reconnect */
375 h->reconnect = GNUNET_YES;
379 /* client was notified about success or failure, clean up 'qe' */
380 GNUNET_CONTAINER_DLL_remove (h->op_head,
386 if (GNUNET_YES == h->reconnect)
391 GNUNET_CLIENT_receive (h->client, &process_namecache_message, h,
392 GNUNET_TIME_UNIT_FOREVER_REL);
397 * Transmit messages from the message queue to the service
398 * (if there are any, and if we are not already trying).
400 * @param h handle to use
403 do_transmit (struct GNUNET_NAMECACHE_Handle *h);
407 * We can now transmit a message to NAMECACHE. Do it.
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
415 transmit_message_to_namecache (void *cls,
419 struct GNUNET_NAMECACHE_Handle *h = cls;
420 struct PendingMessage *p;
425 if ((0 == size) || (NULL == buf))
432 while ( (NULL != (p = h->pending_head)) &&
435 memcpy (&cbuf[ret], &p[1], p->size);
438 GNUNET_CONTAINER_DLL_remove (h->pending_head,
441 if (GNUNET_NO == h->is_receiving)
443 h->is_receiving = GNUNET_YES;
444 GNUNET_CLIENT_receive (h->client,
445 &process_namecache_message, h,
446 GNUNET_TIME_UNIT_FOREVER_REL);
456 * Transmit messages from the message queue to the service
457 * (if there are any, and if we are not already trying).
459 * @param h handle to use
462 do_transmit (struct GNUNET_NAMECACHE_Handle *h)
464 struct PendingMessage *p;
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,
476 GNUNET_break (NULL != h->th);
481 * Reconnect to namecache service.
483 * @param h the handle to the NAMECACHE service
486 reconnect (struct GNUNET_NAMECACHE_Handle *h)
488 GNUNET_assert (NULL == h->client);
489 h->client = GNUNET_CLIENT_connect ("namecache", h->cfg);
490 GNUNET_assert (NULL != h->client);
496 * Re-establish the connection to the service.
498 * @param cls handle to use to re-connect.
499 * @param tc scheduler context
502 reconnect_task (void *cls,
503 const struct GNUNET_SCHEDULER_TaskContext *tc)
505 struct GNUNET_NAMECACHE_Handle *h = cls;
507 h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
513 * Disconnect from service and then reconnect.
515 * @param h our handle
518 force_reconnect (struct GNUNET_NAMECACHE_Handle *h)
522 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
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;
531 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
532 h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
539 * Get a fresh operation id to distinguish between namecache requests
541 * @param h the namecache handle
542 * @return next operation id to use
545 get_op_id (struct GNUNET_NAMECACHE_Handle *h)
547 return h->last_op_id_used++;
552 * Initialize the connection with the NAMECACHE service.
554 * @param cfg configuration to use
555 * @return handle to the GNS service, or NULL on error
557 struct GNUNET_NAMECACHE_Handle *
558 GNUNET_NAMECACHE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
560 struct GNUNET_NAMECACHE_Handle *h;
562 h = GNUNET_new (struct GNUNET_NAMECACHE_Handle);
564 h->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect_task, h);
565 h->last_op_id_used = 0;
571 * Disconnect from the namecache service (and free associated
574 * @param h handle to the namecache
577 GNUNET_NAMECACHE_disconnect (struct GNUNET_NAMECACHE_Handle *h)
579 struct PendingMessage *p;
580 struct GNUNET_NAMECACHE_QueueEntry *q;
582 LOG (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
583 GNUNET_assert (NULL != h);
586 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
589 while (NULL != (p = h->pending_head))
591 GNUNET_CONTAINER_DLL_remove (h->pending_head, h->pending_tail, p);
594 GNUNET_break (NULL == h->op_head);
595 while (NULL != (q = h->op_head))
597 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, q);
600 if (NULL != h->client)
602 GNUNET_CLIENT_disconnect (h->client);
605 if (GNUNET_SCHEDULER_NO_TASK != h->reconnect_task)
607 GNUNET_SCHEDULER_cancel (h->reconnect_task);
608 h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
615 * Store an item in the namecache. If the item is already present,
616 * it is replaced with the new record.
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
624 struct GNUNET_NAMECACHE_QueueEntry *
625 GNUNET_NAMECACHE_block_cache (struct GNUNET_NAMECACHE_Handle *h,
626 const struct GNUNET_GNSRECORD_Block *block,
627 GNUNET_NAMECACHE_ContinuationWithStatus cont,
630 struct GNUNET_NAMECACHE_QueueEntry *qe;
631 struct PendingMessage *pe;
632 struct BlockCacheMessage *msg;
637 GNUNET_assert (NULL != h);
638 blen = ntohl (block->purpose.size)
639 - sizeof (struct GNUNET_TIME_AbsoluteNBO)
640 - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose);
642 qe = GNUNET_new (struct GNUNET_NAMECACHE_QueueEntry);
645 qe->cont_cls = cont_cls;
647 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe);
650 msg_size = sizeof (struct BlockCacheMessage) + blen;
651 pe = GNUNET_malloc (sizeof (struct PendingMessage) + 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);
673 * Get a result for a particular key from the namecache. The processor
674 * will only be called once.
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
683 struct GNUNET_NAMECACHE_QueueEntry *
684 GNUNET_NAMECACHE_lookup_block (struct GNUNET_NAMECACHE_Handle *h,
685 const struct GNUNET_HashCode *derived_hash,
686 GNUNET_NAMECACHE_BlockProcessor proc, void *proc_cls)
688 struct GNUNET_NAMECACHE_QueueEntry *qe;
689 struct PendingMessage *pe;
690 struct LookupBlockMessage *msg;
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));
700 qe = GNUNET_new (struct GNUNET_NAMECACHE_QueueEntry);
702 qe->block_proc = proc;
703 qe->block_proc_cls = proc_cls;
705 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe);
707 msg_size = sizeof (struct LookupBlockMessage);
708 pe = GNUNET_malloc (sizeof (struct PendingMessage) + 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);
722 * Cancel a namecache operation. The final callback from the
723 * operation must not have been done yet.
725 * @param qe operation to cancel
728 GNUNET_NAMECACHE_cancel (struct GNUNET_NAMECACHE_QueueEntry *qe)
730 struct GNUNET_NAMECACHE_Handle *h = qe->nsh;
732 GNUNET_assert (NULL != qe);
733 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, qe);
738 /* end of namecache_api.c */