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 "namecache.h"
40 #define LOG(kind,...) GNUNET_log_from (kind, "namecache-api",__VA_ARGS__)
44 * An QueueEntry used to store information for a pending
45 * NAMECACHE record operation
47 struct GNUNET_NAMECACHE_QueueEntry
53 struct GNUNET_NAMECACHE_QueueEntry *next;
58 struct GNUNET_NAMECACHE_QueueEntry *prev;
61 * Main handle to access the namecache.
63 struct GNUNET_NAMECACHE_Handle *nsh;
66 * Continuation to call
68 GNUNET_NAMECACHE_ContinuationWithStatus cont;
71 * Closure for @e cont.
76 * Function to call with the blocks we get back; or NULL.
78 GNUNET_NAMECACHE_BlockProcessor block_proc;
81 * Closure for @e block_proc.
86 * The operation id this zone iteration operation has
94 * Message in linked list we should send to the service. The
95 * actual binary message follows this struct.
103 struct PendingMessage *next;
108 struct PendingMessage *prev;
111 * Size of the message.
119 * Connection to the NAMECACHE service.
121 struct GNUNET_NAMECACHE_Handle
125 * Configuration to use.
127 const struct GNUNET_CONFIGURATION_Handle *cfg;
130 * Socket (if available).
132 struct GNUNET_CLIENT_Connection *client;
135 * Currently pending transmission request (or NULL).
137 struct GNUNET_CLIENT_TransmitHandle *th;
140 * Head of linked list of pending messages to send to the service
142 struct PendingMessage *pending_head;
145 * Tail of linked list of pending messages to send to the service
147 struct PendingMessage *pending_tail;
150 * Head of pending namecache queue entries
152 struct GNUNET_NAMECACHE_QueueEntry *op_head;
155 * Tail of pending namecache queue entries
157 struct GNUNET_NAMECACHE_QueueEntry *op_tail;
162 GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
165 * Delay introduced before we reconnect.
167 struct GNUNET_TIME_Relative reconnect_delay;
170 * Should we reconnect to service due to some serious error?
175 * Did we start to receive yet?
180 * The last operation id used for a NAMECACHE operation
182 uint32_t last_op_id_used;
188 * Disconnect from service and then reconnect.
190 * @param h our handle
193 force_reconnect (struct GNUNET_NAMECACHE_Handle *h);
197 * Handle an incoming message of type
198 * #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE.
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
206 handle_lookup_block_response (struct GNUNET_NAMECACHE_QueueEntry *qe,
207 const struct LookupBlockResponseMessage *msg,
210 struct GNUNET_GNSRECORD_Block *block;
211 char buf[size + sizeof (struct GNUNET_GNSRECORD_Block)
212 - sizeof (struct LookupBlockResponseMessage)];
214 LOG (GNUNET_ERROR_TYPE_DEBUG,
216 "LOOKUP_BLOCK_RESPONSE");
217 if (0 == GNUNET_TIME_absolute_ntoh (msg->expire).abs_value_us)
220 if (NULL != qe->block_proc)
221 qe->block_proc (qe->block_proc_cls, NULL);
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;
235 size - sizeof (struct LookupBlockResponseMessage));
237 GNUNET_GNSRECORD_block_verify (block))
240 return GNUNET_SYSERR;
242 if (NULL != qe->block_proc)
243 qe->block_proc (qe->block_proc_cls, block);
251 * Handle an incoming message of type
252 * #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE
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
260 handle_block_cache_response (struct GNUNET_NAMECACHE_QueueEntry *qe,
261 const struct BlockCacheResponseMessage *msg,
266 LOG (GNUNET_ERROR_TYPE_DEBUG,
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,
276 : _("Namecache failed to cache block"));
282 * Handle incoming messages for record operations
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
292 manage_record_operations (struct GNUNET_NAMECACHE_QueueEntry *qe,
293 const struct GNUNET_MessageHeader *msg,
297 /* handle different message type */
300 case GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE:
301 if (size < sizeof (struct LookupBlockResponseMessage))
304 return GNUNET_SYSERR;
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))
311 return GNUNET_SYSERR;
313 return handle_block_cache_response (qe, (const struct BlockCacheResponseMessage *) msg, size);
316 return GNUNET_SYSERR;
322 * Type of a function to call when we receive a message
325 * @param cls the `struct GNUNET_NAMECACHE_SchedulingHandle`
326 * @param msg message received, NULL on timeout or fatal error
329 process_namecache_message (void *cls,
330 const struct GNUNET_MessageHeader *msg)
332 struct GNUNET_NAMECACHE_Handle *h = cls;
333 const struct GNUNET_NAMECACHE_Header *gm;
334 struct GNUNET_NAMECACHE_QueueEntry *qe;
345 size = ntohs (msg->size);
346 type = ntohs (msg->type);
347 if (size < sizeof (struct GNUNET_NAMECACHE_Header))
350 GNUNET_CLIENT_receive (h->client,
351 &process_namecache_message, h,
352 GNUNET_TIME_UNIT_FOREVER_REL);
355 gm = (const struct GNUNET_NAMECACHE_Header *) msg;
356 r_id = ntohl (gm->r_id);
358 LOG (GNUNET_ERROR_TYPE_DEBUG,
359 "Received message type %u size %u op %u\n",
362 (unsigned int) r_id);
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)
370 ret = manage_record_operations (qe, msg, type, size);
371 if (GNUNET_SYSERR == ret)
373 /* protocol error, need to reconnect */
374 h->reconnect = GNUNET_YES;
378 /* client was notified about success or failure, clean up 'qe' */
379 GNUNET_CONTAINER_DLL_remove (h->op_head,
385 if (GNUNET_YES == h->reconnect)
390 GNUNET_CLIENT_receive (h->client, &process_namecache_message, h,
391 GNUNET_TIME_UNIT_FOREVER_REL);
396 * Transmit messages from the message queue to the service
397 * (if there are any, and if we are not already trying).
399 * @param h handle to use
402 do_transmit (struct GNUNET_NAMECACHE_Handle *h);
406 * We can now transmit a message to NAMECACHE. Do it.
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
414 transmit_message_to_namecache (void *cls,
418 struct GNUNET_NAMECACHE_Handle *h = cls;
419 struct PendingMessage *p;
424 if ((0 == size) || (NULL == buf))
431 while ( (NULL != (p = h->pending_head)) &&
434 memcpy (&cbuf[ret], &p[1], p->size);
437 GNUNET_CONTAINER_DLL_remove (h->pending_head,
440 if (GNUNET_NO == h->is_receiving)
442 h->is_receiving = GNUNET_YES;
443 GNUNET_CLIENT_receive (h->client,
444 &process_namecache_message, h,
445 GNUNET_TIME_UNIT_FOREVER_REL);
455 * Transmit messages from the message queue to the service
456 * (if there are any, and if we are not already trying).
458 * @param h handle to use
461 do_transmit (struct GNUNET_NAMECACHE_Handle *h)
463 struct PendingMessage *p;
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,
475 GNUNET_break (NULL != h->th);
480 * Reconnect to namecache service.
482 * @param h the handle to the NAMECACHE service
485 reconnect (struct GNUNET_NAMECACHE_Handle *h)
487 GNUNET_assert (NULL == h->client);
488 h->client = GNUNET_CLIENT_connect ("namecache", h->cfg);
489 GNUNET_assert (NULL != h->client);
495 * Re-establish the connection to the service.
497 * @param cls handle to use to re-connect.
498 * @param tc scheduler context
501 reconnect_task (void *cls,
502 const struct GNUNET_SCHEDULER_TaskContext *tc)
504 struct GNUNET_NAMECACHE_Handle *h = cls;
506 h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
512 * Disconnect from service and then reconnect.
514 * @param h our handle
517 force_reconnect (struct GNUNET_NAMECACHE_Handle *h)
521 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
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;
530 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
531 h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
538 * Get a fresh operation id to distinguish between namecache requests
540 * @param h the namecache handle
541 * @return next operation id to use
544 get_op_id (struct GNUNET_NAMECACHE_Handle *h)
546 return h->last_op_id_used++;
551 * Initialize the connection with the NAMECACHE service.
553 * @param cfg configuration to use
554 * @return handle to the GNS service, or NULL on error
556 struct GNUNET_NAMECACHE_Handle *
557 GNUNET_NAMECACHE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
559 struct GNUNET_NAMECACHE_Handle *h;
561 h = GNUNET_new (struct GNUNET_NAMECACHE_Handle);
563 h->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect_task, h);
564 h->last_op_id_used = 0;
570 * Disconnect from the namecache service (and free associated
573 * @param h handle to the namecache
576 GNUNET_NAMECACHE_disconnect (struct GNUNET_NAMECACHE_Handle *h)
578 struct PendingMessage *p;
579 struct GNUNET_NAMECACHE_QueueEntry *q;
581 LOG (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
582 GNUNET_assert (NULL != h);
585 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
588 while (NULL != (p = h->pending_head))
590 GNUNET_CONTAINER_DLL_remove (h->pending_head, h->pending_tail, p);
593 GNUNET_break (NULL == h->op_head);
594 while (NULL != (q = h->op_head))
596 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, q);
599 if (NULL != h->client)
601 GNUNET_CLIENT_disconnect (h->client);
604 if (GNUNET_SCHEDULER_NO_TASK != h->reconnect_task)
606 GNUNET_SCHEDULER_cancel (h->reconnect_task);
607 h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
614 * Store an item in the namecache. If the item is already present,
615 * it is replaced with the new record.
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
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,
629 struct GNUNET_NAMECACHE_QueueEntry *qe;
630 struct PendingMessage *pe;
631 struct BlockCacheMessage *msg;
636 GNUNET_assert (NULL != h);
637 blen = ntohl (block->purpose.size)
638 - sizeof (struct GNUNET_TIME_AbsoluteNBO)
639 - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose);
641 qe = GNUNET_new (struct GNUNET_NAMECACHE_QueueEntry);
644 qe->cont_cls = cont_cls;
646 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe);
649 msg_size = sizeof (struct BlockCacheMessage) + blen;
650 pe = GNUNET_malloc (sizeof (struct PendingMessage) + 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);
672 * Get a result for a particular key from the namecache. The processor
673 * will only be called once.
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
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)
687 struct GNUNET_NAMECACHE_QueueEntry *qe;
688 struct PendingMessage *pe;
689 struct LookupBlockMessage *msg;
693 LOG (GNUNET_ERROR_TYPE_DEBUG,
694 "Looking for block under %s\n",
695 GNUNET_h2s (derived_hash));
697 qe = GNUNET_new (struct GNUNET_NAMECACHE_QueueEntry);
699 qe->block_proc = proc;
700 qe->block_proc_cls = proc_cls;
702 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe);
704 msg_size = sizeof (struct LookupBlockMessage);
705 pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size);
707 msg = (struct LookupBlockMessage *) &pe[1];
708 msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK);
709 msg->gns_header.header.size = htons (msg_size);
710 msg->gns_header.r_id = htonl (rid);
711 msg->query = *derived_hash;
712 GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe);
719 * Cancel a namecache operation. The final callback from the
720 * operation must not have been done yet.
722 * @param qe operation to cancel
725 GNUNET_NAMECACHE_cancel (struct GNUNET_NAMECACHE_QueueEntry *qe)
727 struct GNUNET_NAMECACHE_Handle *h = qe->nsh;
729 GNUNET_assert (NULL != qe);
730 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, qe);
735 /* end of namecache_api.c */