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 #define DEBUG_GNS_API GNUNET_EXTRA_LOGGING
40 #define LOG(kind,...) GNUNET_log_from (kind, "gns-api",__VA_ARGS__)
42 /* TODO into gnunet_protocols */
43 #define GNUNET_MESSAGE_TYPE_GNS_LOOKUP 23
44 #define GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT 24
45 #define GNUNET_MESSAGE_TYPE_GNS_SHORTEN 25
46 #define GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT 26
51 struct GNUNET_GNS_QueueEntry
56 struct GNUNET_GNS_QueueEntry *next;
61 struct GNUNET_GNS_QueueEntry *prev;
67 struct GNUNET_GNS_Handle *gns_handle;
69 /* processor to call on shorten result */
70 GNUNET_GNS_ShortenResultProcessor proc;
72 /* processor closure */
79 * Entry in our list of messages to be (re-)transmitted.
84 * This is a doubly-linked list.
86 struct PendingMessage *prev;
89 * This is a doubly-linked list.
91 struct PendingMessage *next;
94 * Size of the message.
102 * Connection to the GNS service.
104 struct GNUNET_GNS_Handle
108 * Configuration to use.
110 const struct GNUNET_CONFIGURATION_Handle *cfg;
113 * Socket (if available).
115 struct GNUNET_CLIENT_Connection *client;
118 * Currently pending transmission request (or NULL).
120 struct GNUNET_CLIENT_TransmitHandle *th;
125 * Head of linked list of shorten messages we would like to transmit.
127 struct PendingMessage *pending_head;
130 * Tail of linked list of shorten messages we would like to transmit.
132 struct PendingMessage *pending_tail;
135 * Head of linked list of shorten messages we would like to transmit.
137 struct GNUNET_GNS_QueueEntry *shorten_head;
140 * Tail of linked list of shorten messages we would like to transmit.
142 struct GNUNET_GNS_QueueEntry *shorten_tail;
145 * Head of linked list of lookup messages we would like to transmit.
147 struct GNUNET_GNS_QueueEntry *lookup_head;
150 * Tail of linked list of lookup messages we would like to transmit.
152 struct GNUNET_GNS_QueueEntry *lookup_tail;
157 GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
160 * Did we start our receive loop yet?
165 * Reconnect necessary
171 * Try to send messages from list of messages to send
172 * @param handle GNS_Handle
175 process_pending_messages (struct GNUNET_GNS_Handle *handle);
179 * Reconnect to GNS service.
181 * @param h the handle to the namestore service
184 reconnect (struct GNUNET_GNS_Handle *h)
186 GNUNET_assert (NULL == h->client);
187 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
188 "Trying to connect to GNS...\n");
189 h->client = GNUNET_CLIENT_connect ("gns", h->cfg);
190 GNUNET_assert (NULL != h->client);
196 * @param cls the handle
197 * @param tc task context
200 reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
202 struct GNUNET_GNS_Handle *h = cls;
204 h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
210 * Disconnect from service and then reconnect.
212 * @param h our handle
215 force_reconnect (struct GNUNET_GNS_Handle *h)
217 h->reconnect = GNUNET_NO;
218 GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
220 h->reconnect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
226 * Transmit the next pending message, called by notify_transmit_ready
229 transmit_pending (void *cls, size_t size, void *buf);
232 * Handler for messages received from the GNS service
234 * @param cls the 'struct GNUNET_GNS_Handle'
235 * @param msg the incoming message
238 process_message (void *cls, const struct GNUNET_MessageHeader *msg);
241 * Try to send messages from list of messages to send
244 process_pending_messages (struct GNUNET_GNS_Handle *handle)
246 struct PendingMessage *p;
248 if (handle->client == NULL)
250 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
251 "process_pending_messages called, but client is null\n");
255 if (handle->th != NULL)
258 if (NULL == (p = handle->pending_head))
261 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
262 "Trying to transmit %d bytes...\n", p->size);
265 GNUNET_CLIENT_notify_transmit_ready (handle->client,
267 GNUNET_TIME_UNIT_FOREVER_REL,
268 GNUNET_NO, &transmit_pending,
270 if (NULL != handle->th)
273 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
274 "notify_transmit_ready returned NULL!\n");
279 * Transmit the next pending message, called by notify_transmit_ready
282 transmit_pending (void *cls, size_t size, void *buf)
284 struct GNUNET_GNS_Handle *handle = cls;
285 struct PendingMessage *p;
291 if ((size == 0) || (buf == NULL))
293 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
294 "Transmission to GNS service failed!\n");
295 force_reconnect(handle);
302 if (NULL == (p = handle->pending_head))
305 while ((NULL != (p = handle->pending_head)) && (p->size <= size))
307 memcpy (&cbuf[tsize], &p[1], p->size);
310 GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail, p);
311 if (GNUNET_YES != handle->in_receive)
313 GNUNET_CLIENT_receive (handle->client, &process_message, handle,
314 GNUNET_TIME_UNIT_FOREVER_REL);
315 handle->in_receive = GNUNET_YES;
320 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
321 "Sending %d bytes\n", tsize);
323 process_pending_messages(handle);
328 * Process a given reply that might match the given
331 * @param cls the 'struct GNUNET_GNS_ClientResultMessage'
332 * @param key query of the request
333 * @param value the 'struct GNUNET_GNS_LookupHandle' of a request matching the same key
336 process_shorten_reply (struct GNUNET_GNS_QueueEntry *qe,
337 const struct GNUNET_GNS_ClientShortenResultMessage *msg)
339 struct GNUNET_GNS_Handle *h = qe->gns_handle;
340 const char *short_name;
342 GNUNET_CONTAINER_DLL_remove(h->shorten_head, h->shorten_tail, qe);
344 short_name = (char*)(&msg[1]);
346 if (ntohs (((struct GNUNET_MessageHeader*)msg)->size) <
347 sizeof (struct GNUNET_GNS_ClientShortenResultMessage))
354 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
355 "Received shortened reply `%s' from GNS service\n",
358 qe->proc(qe->proc_cls, short_name);
364 * Process a given reply to the lookup request
366 * @param cls the 'struct GNUNET_GNS_ClientResultMessage'
367 * @param key query of the request
368 * @param value the 'struct GNUNET_GNS_LookupHandle' of a request matching the same key
369 * @return GNUNET_YES to continue to iterate over all results,
370 * GNUNET_NO if the reply is malformed
373 process_lookup_reply (struct GNUNET_GNS_QueueEntry *qe,
374 const struct GNUNET_GNS_ClientLookupResultMessage *msg)
379 * Handler for messages received from the GNS service
381 * @param cls the 'struct GNUNET_GNS_Handle'
382 * @param msg the incoming message
385 process_message (void *cls, const struct GNUNET_MessageHeader *msg)
387 struct GNUNET_GNS_Handle *handle = cls;
388 struct GNUNET_GNS_QueueEntry *qe;
389 const struct GNUNET_GNS_ClientLookupResultMessage *lookup_msg;
390 const struct GNUNET_GNS_ClientShortenResultMessage *shorten_msg;
395 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
399 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
400 "Error receiving data from GNS service, reconnecting\n");
401 force_reconnect (handle);
405 size = ntohs (msg->size);
406 type = ntohs (msg->type);
408 if (type == GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT)
410 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
412 lookup_msg = (const struct GNUNET_GNS_ClientLookupResultMessage *) msg;
413 r_id = ntohl (lookup_msg->id);
415 if (r_id > handle->r_id)
417 /** no request found */
419 GNUNET_CLIENT_receive (handle->client, &process_message, handle,
420 GNUNET_TIME_UNIT_FOREVER_REL);
423 for (qe = handle->lookup_head; qe != NULL; qe = qe->next)
425 if (qe->r_id == r_id)
429 process_lookup_reply(qe, lookup_msg);
433 else if (type == GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT)
435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
436 "Got shorten msg\n");
437 shorten_msg = (struct GNUNET_GNS_ClientShortenResultMessage *) msg;
439 r_id = ntohl (shorten_msg->id);
441 if (r_id > handle->r_id)
443 /** no request found */
445 GNUNET_CLIENT_receive (handle->client, &process_message, handle,
446 GNUNET_TIME_UNIT_FOREVER_REL);
449 for (qe = handle->shorten_head; qe != NULL; qe = qe->next)
451 if (qe->r_id == r_id)
455 process_shorten_reply(qe, shorten_msg);
458 GNUNET_CLIENT_receive (handle->client, &process_message, handle,
459 GNUNET_TIME_UNIT_FOREVER_REL);
461 if (GNUNET_YES == handle->reconnect)
462 force_reconnect (handle);
468 * Initialize the connection with the GNS service.
470 * @param cfg configuration to use
471 * @param ht_len size of the internal hash table to use for parallel requests
472 * @return handle to the GNS service, or NULL on error
474 struct GNUNET_GNS_Handle *
475 GNUNET_GNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
477 struct GNUNET_GNS_Handle *handle;
479 handle = GNUNET_malloc (sizeof (struct GNUNET_GNS_Handle));
482 //handle->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect_task, handle);
484 handle->in_receive = GNUNET_NO;
490 * Shutdown connection with the GNS service.
492 * @param handle handle of the GNS connection to stop
495 GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle)
501 * Helper function to generate request ids
507 get_request_id (struct GNUNET_GNS_Handle *h)
509 uint32_t r_id = h->r_id;
515 * Perform an asynchronous Lookup operation on the GNS.
517 * @param handle handle to the GNS service
518 * @param name the name to look up
519 * @param iter function to call on each result
520 * @param iter_cls closure for iter
521 * @return handle to stop the async get
523 struct GNUNET_GNS_QueueEntry *
524 GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle,
526 enum GNUNET_GNS_RecordType type,
527 GNUNET_GNS_LookupIterator iter,
535 * Perform a name shortening operation on the GNS.
537 * @param handle handle to the GNS service
538 * @param name the name to look up
539 * @param proc function to call on result
540 * @param proc_cls closure for processor
541 * @return handle to the operation
543 struct GNUNET_GNS_QueueEntry *
544 GNUNET_GNS_shorten (struct GNUNET_GNS_Handle *handle,
546 GNUNET_GNS_ShortenResultProcessor proc,
549 /* IPC to shorten gns names, return shorten_handle */
550 struct GNUNET_GNS_ClientShortenMessage *shorten_msg;
551 struct GNUNET_GNS_QueueEntry *qe;
553 struct PendingMessage *pending;
560 msize = sizeof (struct GNUNET_GNS_ClientShortenMessage) + strlen(name) + 1;
561 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to shorten %s in GNS\n", name);
563 qe = GNUNET_malloc(sizeof (struct GNUNET_GNS_QueueEntry));
564 qe->gns_handle = handle;
566 qe->proc_cls = proc_cls;
567 qe->r_id = get_request_id(handle);
568 GNUNET_CONTAINER_DLL_insert_tail(handle->shorten_head,
569 handle->shorten_tail, qe);
571 pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
572 memset(pending, 0, (sizeof (struct PendingMessage) + msize));
574 pending->size = msize;
576 shorten_msg = (struct GNUNET_GNS_ClientShortenMessage *) &pending[1];
577 shorten_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_SHORTEN);
578 shorten_msg->header.size = htons (msize);
579 shorten_msg->id = htonl(qe->r_id);
581 memcpy(&shorten_msg[1], name, strlen(name));
583 GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail,
586 process_pending_messages (handle);
592 /* end of gns_api.c */