2 This file is part of GNUnet.
3 (C) 2009, 2010 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.
24 * @brief library to access the GNS service
25 * @author Martin Schanzenbach
29 #include "gnunet_util_lib.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_arm_service.h"
32 #include "gnunet_hello_lib.h"
33 #include "gnunet_protocols.h"
34 #include "gnunet_dht_service.h"
36 #include "gnunet_gns_service.h"
38 /* TODO into gnunet_protocols */
39 #define GNUNET_MESSAGE_TYPE_GNS_LOOKUP 23
40 #define GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT 24
41 #define GNUNET_MESSAGE_TYPE_GNS_SHORTEN 25
42 #define GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT 26
47 struct GNUNET_GNS_QueueEntry
52 struct GNUNET_GNS_QueueEntry *next;
57 struct GNUNET_GNS_QueueEntry *prev;
63 struct GNUNET_GNS_Handle *gns_handle;
65 /* processor to call on shorten result */
66 GNUNET_GNS_ShortenResultProcessor shorten_proc;
68 /* processor to call on lookup result */
69 GNUNET_GNS_LookupResultProcessor lookup_proc;
71 /* processor closure */
78 * Entry in our list of messages to be (re-)transmitted.
83 * This is a doubly-linked list.
85 struct PendingMessage *prev;
88 * This is a doubly-linked list.
90 struct PendingMessage *next;
93 * Size of the message.
101 * Connection to the GNS service.
103 struct GNUNET_GNS_Handle
107 * Configuration to use.
109 const struct GNUNET_CONFIGURATION_Handle *cfg;
112 * Socket (if available).
114 struct GNUNET_CLIENT_Connection *client;
117 * Currently pending transmission request (or NULL).
119 struct GNUNET_CLIENT_TransmitHandle *th;
124 * Head of linked list of shorten messages we would like to transmit.
126 struct PendingMessage *pending_head;
129 * Tail of linked list of shorten messages we would like to transmit.
131 struct PendingMessage *pending_tail;
134 * Head of linked list of shorten messages we would like to transmit.
136 struct GNUNET_GNS_QueueEntry *shorten_head;
139 * Tail of linked list of shorten messages we would like to transmit.
141 struct GNUNET_GNS_QueueEntry *shorten_tail;
144 * Head of linked list of lookup messages we would like to transmit.
146 struct GNUNET_GNS_QueueEntry *lookup_head;
149 * Tail of linked list of lookup messages we would like to transmit.
151 struct GNUNET_GNS_QueueEntry *lookup_tail;
156 GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
159 * Did we start our receive loop yet?
164 * Reconnect necessary
170 * Try to send messages from list of messages to send
171 * @param handle GNS_Handle
174 process_pending_messages (struct GNUNET_GNS_Handle *handle);
178 * Reconnect to GNS service.
180 * @param h the handle to the namestore service
183 reconnect (struct GNUNET_GNS_Handle *h)
185 GNUNET_assert (NULL == h->client);
186 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
187 "Trying to connect to GNS...\n");
188 h->client = GNUNET_CLIENT_connect ("gns", h->cfg);
189 GNUNET_assert (NULL != h->client);
195 * @param cls the handle
196 * @param tc task context
199 reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
201 struct GNUNET_GNS_Handle *h = cls;
203 h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
209 * Disconnect from service and then reconnect.
211 * @param h our handle
214 force_reconnect (struct GNUNET_GNS_Handle *h)
216 h->reconnect = GNUNET_NO;
217 GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
219 h->reconnect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
225 * Transmit the next pending message, called by notify_transmit_ready
228 transmit_pending (void *cls, size_t size, void *buf);
231 * Handler for messages received from the GNS service
233 * @param cls the 'struct GNUNET_GNS_Handle'
234 * @param msg the incoming message
237 process_message (void *cls, const struct GNUNET_MessageHeader *msg);
240 * Try to send messages from list of messages to send
243 process_pending_messages (struct GNUNET_GNS_Handle *handle)
245 struct PendingMessage *p;
247 if (handle->client == NULL)
249 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
250 "process_pending_messages called, but client is null\n");
254 if (handle->th != NULL)
257 if (NULL == (p = handle->pending_head))
260 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
261 "Trying to transmit %d bytes...\n", p->size);
264 GNUNET_CLIENT_notify_transmit_ready (handle->client,
266 GNUNET_TIME_UNIT_FOREVER_REL,
267 GNUNET_NO, &transmit_pending,
269 if (NULL != handle->th)
272 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
273 "notify_transmit_ready returned NULL!\n");
278 * Transmit the next pending message, called by notify_transmit_ready
281 transmit_pending (void *cls, size_t size, void *buf)
283 struct GNUNET_GNS_Handle *handle = cls;
284 struct PendingMessage *p;
290 if ((size == 0) || (buf == NULL))
292 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
293 "Transmission to GNS service failed!\n");
294 force_reconnect(handle);
301 if (NULL == (p = handle->pending_head))
304 while ((NULL != (p = handle->pending_head)) && (p->size <= size))
306 memcpy (&cbuf[tsize], &p[1], p->size);
309 GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail, p);
310 if (GNUNET_YES != handle->in_receive)
312 GNUNET_CLIENT_receive (handle->client, &process_message, handle,
313 GNUNET_TIME_UNIT_FOREVER_REL);
314 handle->in_receive = GNUNET_YES;
319 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
320 "Sending %d bytes\n", tsize);
322 process_pending_messages(handle);
327 * Process a given reply that might match the given
330 * @param cls the 'struct GNUNET_GNS_ClientResultMessage'
331 * @param key query of the request
332 * @param value the 'struct GNUNET_GNS_LookupHandle' of a request matching the same key
335 process_shorten_reply (struct GNUNET_GNS_QueueEntry *qe,
336 const struct GNUNET_GNS_ClientShortenResultMessage *msg)
338 struct GNUNET_GNS_Handle *h = qe->gns_handle;
339 const char *short_name;
341 GNUNET_CONTAINER_DLL_remove(h->shorten_head, h->shorten_tail, qe);
343 short_name = (char*)(&msg[1]);
345 if (ntohs (((struct GNUNET_MessageHeader*)msg)->size) <
346 sizeof (struct GNUNET_GNS_ClientShortenResultMessage))
353 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
354 "Received shortened reply `%s' from GNS service\n",
357 qe->shorten_proc(qe->proc_cls, short_name);
363 * Process a given reply to the lookup request
365 * @param cls the 'struct GNUNET_GNS_ClientResultMessage'
366 * @param key query of the request
367 * @param value the 'struct GNUNET_GNS_LookupHandle' of a request matching the same key
368 * @return GNUNET_YES to continue to iterate over all results,
369 * GNUNET_NO if the reply is malformed
372 process_lookup_reply (struct GNUNET_GNS_QueueEntry *qe,
373 const struct GNUNET_GNS_ClientLookupResultMessage *msg)
375 struct GNUNET_GNS_Handle *h = qe->gns_handle;
376 int rd_count = ntohl(msg->rd_count);
377 size_t len = ntohs (((struct GNUNET_MessageHeader*)msg)->size);
378 struct GNUNET_NAMESTORE_RecordData rd[rd_count];
380 GNUNET_CONTAINER_DLL_remove(h->lookup_head, h->lookup_tail, qe);
382 if (len < sizeof (struct GNUNET_GNS_ClientLookupResultMessage))
389 len -= sizeof(struct GNUNET_GNS_ClientLookupResultMessage);
391 GNUNET_NAMESTORE_records_deserialize (len, (char*)&msg[1],
395 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
396 "Received lookup reply from GNS service (count=%d)\n",
397 ntohl(msg->rd_count));
399 qe->lookup_proc(qe->proc_cls, rd_count, rd);
403 * Handler for messages received from the GNS service
405 * @param cls the 'struct GNUNET_GNS_Handle'
406 * @param msg the incoming message
409 process_message (void *cls, const struct GNUNET_MessageHeader *msg)
411 struct GNUNET_GNS_Handle *handle = cls;
412 struct GNUNET_GNS_QueueEntry *qe;
413 const struct GNUNET_GNS_ClientLookupResultMessage *lookup_msg;
414 const struct GNUNET_GNS_ClientShortenResultMessage *shorten_msg;
419 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
423 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
424 "Error receiving data from GNS service, reconnecting\n");
425 force_reconnect (handle);
429 size = ntohs (msg->size);
430 type = ntohs (msg->type);
432 if (type == GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT)
434 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
436 lookup_msg = (const struct GNUNET_GNS_ClientLookupResultMessage *) msg;
437 r_id = ntohl (lookup_msg->id);
439 if (r_id > handle->r_id)
441 /** no request found */
443 GNUNET_CLIENT_receive (handle->client, &process_message, handle,
444 GNUNET_TIME_UNIT_FOREVER_REL);
447 for (qe = handle->lookup_head; qe != NULL; qe = qe->next)
449 if (qe->r_id == r_id)
453 process_lookup_reply(qe, lookup_msg);
457 else if (type == GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT)
459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
460 "Got shorten msg\n");
461 shorten_msg = (struct GNUNET_GNS_ClientShortenResultMessage *) msg;
463 r_id = ntohl (shorten_msg->id);
465 if (r_id > handle->r_id)
467 /** no request found */
469 GNUNET_CLIENT_receive (handle->client, &process_message, handle,
470 GNUNET_TIME_UNIT_FOREVER_REL);
473 for (qe = handle->shorten_head; qe != NULL; qe = qe->next)
475 if (qe->r_id == r_id)
479 process_shorten_reply(qe, shorten_msg);
482 GNUNET_CLIENT_receive (handle->client, &process_message, handle,
483 GNUNET_TIME_UNIT_FOREVER_REL);
485 if (GNUNET_YES == handle->reconnect)
486 force_reconnect (handle);
492 * Initialize the connection with the GNS service.
494 * @param cfg configuration to use
495 * @param ht_len size of the internal hash table to use for parallel requests
496 * @return handle to the GNS service, or NULL on error
498 struct GNUNET_GNS_Handle *
499 GNUNET_GNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
501 struct GNUNET_GNS_Handle *handle;
503 handle = GNUNET_malloc (sizeof (struct GNUNET_GNS_Handle));
506 //handle->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect_task, handle);
508 handle->in_receive = GNUNET_NO;
514 * Shutdown connection with the GNS service.
516 * @param handle handle of the GNS connection to stop
519 GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle)
525 * Helper function to generate request ids
531 get_request_id (struct GNUNET_GNS_Handle *h)
533 uint32_t r_id = h->r_id;
539 * Perform an asynchronous Lookup operation on the GNS.
541 * @param handle handle to the GNS service
542 * @param name the name to look up
543 * @param iter function to call on each result
544 * @param iter_cls closure for iter
545 * @return handle to stop the async get
547 struct GNUNET_GNS_QueueEntry *
548 GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle,
550 enum GNUNET_GNS_RecordType type,
551 GNUNET_GNS_LookupResultProcessor proc,
554 /* IPC to shorten gns names, return shorten_handle */
555 struct GNUNET_GNS_ClientLookupMessage *lookup_msg;
556 struct GNUNET_GNS_QueueEntry *qe;
558 struct PendingMessage *pending;
565 msize = sizeof (struct GNUNET_GNS_ClientLookupMessage) + strlen(name) + 1;
566 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to shorten %s in GNS\n", name);
568 qe = GNUNET_malloc(sizeof (struct GNUNET_GNS_QueueEntry));
569 qe->gns_handle = handle;
570 qe->lookup_proc = proc;
571 qe->proc_cls = proc_cls;
572 qe->r_id = get_request_id(handle);
573 GNUNET_CONTAINER_DLL_insert_tail(handle->lookup_head,
574 handle->lookup_tail, qe);
576 pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
577 memset(pending, 0, (sizeof (struct PendingMessage) + msize));
579 pending->size = msize;
581 lookup_msg = (struct GNUNET_GNS_ClientLookupMessage *) &pending[1];
582 lookup_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_LOOKUP);
583 lookup_msg->header.size = htons (msize);
584 lookup_msg->id = htonl(qe->r_id);
585 lookup_msg->type = htonl(type);
587 memcpy(&lookup_msg[1], name, strlen(name));
589 GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail,
592 process_pending_messages (handle);
598 * Perform a name shortening operation on the GNS.
600 * @param handle handle to the GNS service
601 * @param name the name to look up
602 * @param proc function to call on result
603 * @param proc_cls closure for processor
604 * @return handle to the operation
606 struct GNUNET_GNS_QueueEntry *
607 GNUNET_GNS_shorten (struct GNUNET_GNS_Handle *handle,
609 GNUNET_GNS_ShortenResultProcessor proc,
612 /* IPC to shorten gns names, return shorten_handle */
613 struct GNUNET_GNS_ClientShortenMessage *shorten_msg;
614 struct GNUNET_GNS_QueueEntry *qe;
616 struct PendingMessage *pending;
623 msize = sizeof (struct GNUNET_GNS_ClientShortenMessage) + strlen(name) + 1;
624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to shorten %s in GNS\n", name);
626 qe = GNUNET_malloc(sizeof (struct GNUNET_GNS_QueueEntry));
627 qe->gns_handle = handle;
628 qe->shorten_proc = proc;
629 qe->proc_cls = proc_cls;
630 qe->r_id = get_request_id(handle);
631 GNUNET_CONTAINER_DLL_insert_tail(handle->shorten_head,
632 handle->shorten_tail, qe);
634 pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
635 memset(pending, 0, (sizeof (struct PendingMessage) + msize));
637 pending->size = msize;
639 shorten_msg = (struct GNUNET_GNS_ClientShortenMessage *) &pending[1];
640 shorten_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_SHORTEN);
641 shorten_msg->header.size = htons (msize);
642 shorten_msg->id = htonl(qe->r_id);
644 memcpy(&shorten_msg[1], name, strlen(name));
646 GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail,
649 process_pending_messages (handle);
655 /* end of gns_api.c */