-shortening in cli app (in progress)
[oweals/gnunet.git] / src / gns / gns_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  *
23  * @file gns/gns_api.c
24  * @brief library to access the GNS service
25  * @author Martin Schanzenbach
26  */
27
28 #include "platform.h"
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"
35 #include "gns.h"
36 #include "gnunet_gns_service.h"
37
38 #define DEBUG_GNS_API GNUNET_EXTRA_LOGGING
39
40 #define LOG(kind,...) GNUNET_log_from (kind, "gns-api",__VA_ARGS__)
41
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
47
48 /**
49  * Entry in our list of messages to be (re-)transmitted.
50  */
51 struct PendingMessage
52 {
53   /**
54    * This is a doubly-linked list.
55    */
56   struct PendingMessage *prev;
57
58   /**
59    * This is a doubly-linked list.
60    */
61   struct PendingMessage *next;
62
63   /**
64    * Message that is pending, allocated at the end
65    * of this struct.
66    */
67   const struct GNUNET_MessageHeader *msg;
68
69   /**
70    * Handle to the GNS API context.
71    */
72   struct GNUNET_GNS_Handle *handle;
73
74   /**
75    * Continuation to call when the request has been
76    * transmitted (for the first time) to the service; can be NULL.
77    */
78   GNUNET_SCHEDULER_Task cont;
79
80   /**
81    * Closure for 'cont'.
82    */
83   void *cont_cls;
84
85   /**
86    * Unique ID for this request
87    */
88   uint64_t unique_id;
89
90   /**
91    * Free the saved message once sent, set to GNUNET_YES for messages
92    * that do not receive responses; GNUNET_NO if this pending message
93    * is aliased from a 'struct GNUNET_DHT_RouteHandle' and will be freed
94    * from there.
95    */
96
97   int free_on_send;
98   /**
99    * GNUNET_YES if this message is in our pending queue right now.
100    */
101   int in_pending_queue;
102
103 };
104
105 /**
106  * Handle to a Lookup request
107  */
108 struct GNUNET_GNS_LookupHandle
109 {
110
111   /**
112    * Iterator to call on data receipt
113    */
114   GNUNET_GNS_LookupIterator iter;
115
116   /**
117    * Closure for the iterator callback
118    */
119   void *iter_cls;
120
121   /**
122    * Main handle to this GNS api
123    */
124   struct GNUNET_GNS_Handle *gns_handle;
125
126   /**
127    * Key that this get request is for
128    */
129   GNUNET_HashCode key;
130
131   /**
132    * Unique identifier for this request (for key collisions).
133    */
134   uint64_t unique_id;
135
136   struct PendingMessage *message;
137
138 };
139
140
141 /**
142  * Handle to a shorten request
143  */
144 struct GNUNET_GNS_ShortenHandle
145 {
146
147   /**
148    * Processor to call on data receipt
149    */
150   GNUNET_GNS_ShortenResultProcessor proc;
151
152   /**
153    * Closure for the processor
154    */
155   void *proc_cls;
156
157   /**
158    * Main handle to this GNS api
159    */
160   struct GNUNET_GNS_Handle *gns_handle;
161
162   /**
163    * Key that this get request is for
164    */
165   GNUNET_HashCode key;
166
167   /**
168    * Unique identifier for this request (for key collisions).
169    */
170   uint64_t unique_id;
171
172   struct PendingMessage *message;
173
174 };
175
176
177 /**
178  * Connection to the GNS service.
179  */
180 struct GNUNET_GNS_Handle
181 {
182
183   /**
184    * Configuration to use.
185    */
186   const struct GNUNET_CONFIGURATION_Handle *cfg;
187
188   /**
189    * Socket (if available).
190    */
191   struct GNUNET_CLIENT_Connection *client;
192
193   /**
194    * Currently pending transmission request (or NULL).
195    */
196   struct GNUNET_CLIENT_TransmitHandle *th;
197
198   /**
199    * Head of linked list of messages we would like to transmit.
200    */
201   struct PendingMessage *pending_head;
202
203   /**
204    * Tail of linked list of messages we would like to transmit.
205    */
206   struct PendingMessage *pending_tail;
207
208   /**
209    * Hash maps containing the current outstanding unique requests.
210    */
211   struct GNUNET_CONTAINER_MultiHashMap *active_lookup_requests;
212   struct GNUNET_CONTAINER_MultiHashMap *active_shorten_requests;
213
214   GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
215
216   /**
217    * How quickly should we retry?  Used for exponential back-off on
218    * connect-errors.
219    */
220   struct GNUNET_TIME_Relative retry_time;
221
222   /**
223    * Generator for unique ids.
224    */
225   uint64_t uid_gen;
226
227   /**
228    * Did we start our receive loop yet?
229    */
230   int in_receive;
231 };
232
233 /**
234  * Try to send messages from list of messages to send
235  * @param handle GNS_Handle
236  */
237 static void
238 process_pending_messages (struct GNUNET_GNS_Handle *handle);
239
240 /**
241  * Try to (re)connect to the GNS service.
242  *
243  * @return GNUNET_YES on success, GNUNET_NO on failure.
244  */
245 static int
246 try_connect (struct GNUNET_GNS_Handle *handle)
247 {
248   if (handle->client != NULL)
249     return GNUNET_OK;
250   handle->in_receive = GNUNET_NO;
251   handle->client = GNUNET_CLIENT_connect ("gns", handle->cfg);
252   if (handle->client == NULL)
253   {
254     LOG (GNUNET_ERROR_TYPE_WARNING,
255          _("Failed to connect to the GNS service!\n"));
256     return GNUNET_NO;
257   }
258   return GNUNET_YES;
259 }
260
261 /**
262  * Add the request corresponding to the given handle
263  * to the pending queue (if it is not already in there).
264  *
265  * @param cls the 'struct GNUNET_GNS_Handle*'
266  * @param key key for the request (not used)
267  * @param value the 'struct GNUNET_GNS_LookupHandle*'
268  * @return GNUNET_YES (always)
269  */
270 static int
271 add_lookup_request_to_pending (void *cls, const GNUNET_HashCode * key,
272                                void *value)
273 {
274   struct GNUNET_GNS_Handle *handle = cls;
275   struct GNUNET_GNS_LookupHandle *lh = value;
276
277   if (GNUNET_NO == lh->message->in_pending_queue)
278   {
279     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
280          "Retransmitting request related to %s to GNS %p\n", GNUNET_h2s(key),
281          handle);
282     GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail,
283                                  lh->message);
284     lh->message->in_pending_queue = GNUNET_YES;
285   }
286   return GNUNET_YES;
287 }
288
289
290 /**
291  * Add the request corresponding to the given handle
292  * to the pending queue (if it is not already in there).
293  *
294  * @param cls the 'struct GNUNET_GNS_Handle*'
295  * @param key key for the request (not used)
296  * @param value the 'struct GNUNET_GNS_ShortenHandle*'
297  * @return GNUNET_YES (always)
298  */
299 static int
300 add_shorten_request_to_pending (void *cls, const GNUNET_HashCode * key,
301                                 void *value)
302 {
303   struct GNUNET_GNS_Handle *handle = cls;
304   struct GNUNET_GNS_ShortenHandle *sh = value;
305
306   if (GNUNET_NO == sh->message->in_pending_queue)
307   {
308     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
309          "Retransmitting shorten request related to %s to GNS %p\n",
310          GNUNET_h2s(key),
311          handle);
312     GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail,
313                                  sh->message);
314     sh->message->in_pending_queue = GNUNET_YES;
315   }
316   return GNUNET_YES;
317 }
318
319
320 /**
321  * Try reconnecting to the GNS service.
322  *
323  * @param cls GNUNET_GNS_Handle
324  * @param tc scheduler context
325  */
326 static void
327 try_reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
328 {
329   struct GNUNET_GNS_Handle *handle = cls;
330
331   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Reconnecting with GNS %p\n", handle);
332   handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
333   if (handle->retry_time.rel_value < GNUNET_CONSTANTS_SERVICE_RETRY.rel_value)
334     handle->retry_time = GNUNET_CONSTANTS_SERVICE_RETRY;
335   else
336     handle->retry_time = GNUNET_TIME_relative_multiply (handle->retry_time, 2);
337   if (handle->retry_time.rel_value > GNUNET_CONSTANTS_SERVICE_TIMEOUT.rel_value)
338     handle->retry_time = GNUNET_CONSTANTS_SERVICE_TIMEOUT;
339   handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
340   if (GNUNET_YES != try_connect (handle))
341   {
342     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS reconnect failed(!)\n");
343     return;
344   }
345   GNUNET_CONTAINER_multihashmap_iterate (handle->active_lookup_requests,
346                                        &add_lookup_request_to_pending, handle);
347   GNUNET_CONTAINER_multihashmap_iterate (handle->active_shorten_requests,
348                                        &add_shorten_request_to_pending, handle);
349   process_pending_messages (handle);
350 }
351
352
353 /**
354  * Try reconnecting to the GNS service.
355  *
356  * @param handle handle to gns to (possibly) disconnect and reconnect
357  */
358 static void
359 do_disconnect (struct GNUNET_GNS_Handle *handle)
360 {
361   if (handle->client == NULL)
362     return;
363   GNUNET_assert (handle->reconnect_task == GNUNET_SCHEDULER_NO_TASK);
364   if (NULL != handle->th)
365     GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th);
366   handle->th = NULL;
367   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
368               "Disconnecting from GNS service, will try to reconnect in %llu ms\n",
369               (unsigned long long) handle->retry_time.rel_value);
370   GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO);
371   handle->client = NULL;
372   handle->reconnect_task =
373       GNUNET_SCHEDULER_add_delayed (handle->retry_time, &try_reconnect, handle);
374 }
375
376 /**
377  * Transmit the next pending message, called by notify_transmit_ready
378  */
379 static size_t
380 transmit_pending (void *cls, size_t size, void *buf);
381
382 /**
383  * Handler for messages received from the GNS service
384  *
385  * @param cls the 'struct GNUNET_GNS_Handle'
386  * @param msg the incoming message
387  */
388 static void
389 message_handler (void *cls, const struct GNUNET_MessageHeader *msg);
390
391 /**
392  * Try to send messages from list of messages to send
393  */
394 static void
395 process_pending_messages (struct GNUNET_GNS_Handle *handle)
396 {
397   struct PendingMessage *head;
398
399   if (handle->client == NULL)
400   {
401     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
402          "process_pending_messages called, but client is null, reconnecting\n");
403     do_disconnect (handle);
404     return;
405   }
406   
407   if (handle->th != NULL)
408     return;
409   
410   if (NULL == (head = handle->pending_head))
411     return;
412   
413   handle->th =
414     GNUNET_CLIENT_notify_transmit_ready (handle->client,
415                                          ntohs (head->msg->size),
416                                          GNUNET_TIME_UNIT_FOREVER_REL,
417                                          GNUNET_YES, &transmit_pending,
418                                          handle);
419   if (NULL != handle->th)
420     return;
421   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
422               "notify_transmit_ready returned NULL, reconnecting\n");
423   do_disconnect (handle);
424 }
425
426
427 /**
428  * Transmit the next pending message, called by notify_transmit_ready
429  */
430 static size_t
431 transmit_pending (void *cls, size_t size, void *buf)
432 {
433   struct GNUNET_GNS_Handle *handle = cls;
434   struct PendingMessage *head;
435   size_t tsize;
436
437   handle->th = NULL;
438   
439   if (buf == NULL)
440   {
441     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
442          "Transmission to GNS service failed!  Reconnecting!\n");
443     do_disconnect (handle);
444     return 0;
445   }
446   
447   if (NULL == (head = handle->pending_head))
448     return 0;
449
450   tsize = ntohs (head->msg->size);
451   
452   if (size < tsize)
453   {
454     process_pending_messages (handle);
455     return 0;
456   }
457   
458   memcpy (buf, head->msg, tsize);
459   
460   GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail,
461                                head);
462   
463   head->in_pending_queue = GNUNET_NO;
464   
465   if (GNUNET_YES == head->free_on_send)
466     GNUNET_free (head);
467
468   process_pending_messages (handle);
469   
470   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
471        "Forwarded request of %u bytes to GNS service\n", (unsigned int) tsize);
472   
473   if (GNUNET_NO == handle->in_receive)
474   {
475     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
476                 "Starting to process replies from GNS\n");
477     handle->in_receive = GNUNET_YES;
478     GNUNET_CLIENT_receive (handle->client, &message_handler, handle,
479                            GNUNET_TIME_UNIT_FOREVER_REL);
480   }
481   return tsize;
482 }
483
484 /**
485  * Process a given reply that might match the given
486  * request.
487  *
488  * @param cls the 'struct GNUNET_GNS_ClientResultMessage'
489  * @param key query of the request
490  * @param value the 'struct GNUNET_GNS_LookupHandle' of a request matching the same key
491  * @return GNUNET_YES to continue to iterate over all results,
492  *         GNUNET_NO if the reply is malformed
493  */
494 static int
495 process_shorten_reply (void *cls, const GNUNET_HashCode * key, void *value)
496 {
497   const struct GNUNET_GNS_ClientShortenResultMessage *gns_msg = cls;
498   struct GNUNET_GNS_ShortenHandle *shorten_handle = value;
499   const char *name = (const char*)&((struct GNUNET_GNS_ClientShortenMessage *) &((shorten_handle->message)[1]))[1]; //FIXME
500   const char *short_name;
501
502   if (ntohs (((struct GNUNET_MessageHeader*)gns_msg)->size) <
503       sizeof (struct GNUNET_GNS_ClientShortenResultMessage))
504   {
505     GNUNET_break (0);
506     do_disconnect (shorten_handle->gns_handle);
507     return GNUNET_NO;
508   }
509   
510   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
511               "Received reply for `%s' from GNS service %p\n",
512               name, shorten_handle->gns_handle);
513   
514   if (gns_msg->unique_id != shorten_handle->unique_id)
515   {
516     /* UID mismatch */
517     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
518          "Ignoring reply for %s: UID mismatch: %llu/%llu\n", GNUNET_h2s (key),
519          gns_msg->unique_id, shorten_handle->unique_id);
520     return GNUNET_YES;
521   }
522   short_name = (char*)&gns_msg[1];
523   
524   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
525               "Giving shorten reply %s for %s to application\n",
526               short_name, name);
527   
528   shorten_handle->proc (shorten_handle->proc_cls, name, short_name);
529   
530   GNUNET_CLIENT_receive (shorten_handle->gns_handle->client,
531                          &message_handler, shorten_handle->gns_handle,
532                          GNUNET_TIME_UNIT_FOREVER_REL);
533   return GNUNET_YES;
534 }
535
536
537 /**
538  * Process a given reply to the lookup request
539  *
540  * @param cls the 'struct GNUNET_GNS_ClientResultMessage'
541  * @param key query of the request
542  * @param value the 'struct GNUNET_GNS_LookupHandle' of a request matching the same key
543  * @return GNUNET_YES to continue to iterate over all results,
544  *         GNUNET_NO if the reply is malformed
545  */
546 static int
547 process_lookup_reply (void *cls, const GNUNET_HashCode * key, void *value)
548 {
549   const struct GNUNET_GNS_ClientLookupResultMessage *gns_msg = cls;
550   struct GNUNET_GNS_LookupHandle *lookup_handle = value;
551   const char *name = (const char*) &lookup_handle[1];
552   struct GNUNET_NAMESTORE_RecordData *rd;
553   uint32_t rd_count;
554
555   if (ntohs (((struct GNUNET_MessageHeader*)gns_msg)->size) <
556       sizeof (struct GNUNET_GNS_ClientLookupResultMessage))
557   {
558     GNUNET_break (0);
559     do_disconnect (lookup_handle->gns_handle);
560     return GNUNET_NO;
561   }
562   
563   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
564               "Received lookup reply for `%s' from GNS service %p\n",
565               name, lookup_handle->gns_handle);
566   
567   if (gns_msg->unique_id != lookup_handle->unique_id)
568   {
569     /* UID mismatch */
570     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
571          "Ignoring reply for %s: UID mismatch: %llu/%llu\n", GNUNET_h2s (key),
572          gns_msg->unique_id, lookup_handle->unique_id);
573     return GNUNET_YES;
574   }
575   
576   rd_count = ntohl(gns_msg->rd_count);
577   rd = (struct GNUNET_NAMESTORE_RecordData*)&gns_msg[1];
578   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
579               "Giving lookup reply for %s to application\n",
580               name);
581   
582   lookup_handle->iter (lookup_handle->iter_cls, name, rd_count, rd);
583   
584   GNUNET_CLIENT_receive (lookup_handle->gns_handle->client, &message_handler,
585                          lookup_handle->gns_handle,
586                          GNUNET_TIME_UNIT_FOREVER_REL);
587   return GNUNET_YES;
588 }
589
590 /**
591  * Handler for messages received from the GNS service
592  *
593  * @param cls the 'struct GNUNET_GNS_Handle'
594  * @param msg the incoming message
595  */
596 static void
597 message_handler (void *cls, const struct GNUNET_MessageHeader *msg)
598 {
599   struct GNUNET_GNS_Handle *handle = cls;
600   const struct GNUNET_GNS_ClientLookupResultMessage *lookup_msg;
601   const struct GNUNET_GNS_ClientShortenResultMessage *shorten_msg;
602   
603   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
604               "Got message\n");
605   if (msg == NULL)
606   {
607     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
608          "Error receiving data from GNS service, reconnecting\n");
609     do_disconnect (handle);
610     return;
611   }
612
613   if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT)
614   {
615     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
616                 "Got lookup msg\n");
617     lookup_msg = (const struct GNUNET_GNS_ClientLookupResultMessage *) msg;
618     GNUNET_CONTAINER_multihashmap_get_multiple (handle->active_lookup_requests,
619                                                 &lookup_msg->key,
620                                                 &process_lookup_reply,
621                                                 (void *) lookup_msg);
622   }
623   else if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT)
624   {
625     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
626                 "Got shorten msg\n");
627     shorten_msg = (const struct GNUNET_GNS_ClientShortenResultMessage *) msg;
628     GNUNET_CONTAINER_multihashmap_get_multiple (handle->active_shorten_requests,
629                                                 &shorten_msg->key,
630                                                 &process_shorten_reply,
631                                                 (void *) shorten_msg);
632   }
633   else
634   {
635     GNUNET_break (0);
636     do_disconnect (handle);
637     return;
638   }
639   
640 }
641
642
643 /**
644  * Initialize the connection with the GNS service.
645  *
646  * @param cfg configuration to use
647  * @param ht_len size of the internal hash table to use for parallel requests
648  * @return handle to the GNS service, or NULL on error
649  */
650 struct GNUNET_GNS_Handle *
651 GNUNET_GNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
652 {
653   struct GNUNET_GNS_Handle *handle;
654
655   handle = GNUNET_malloc (sizeof (struct GNUNET_GNS_Handle));
656   handle->cfg = cfg;
657   handle->uid_gen =
658       GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
659   handle->active_lookup_requests =
660     GNUNET_CONTAINER_multihashmap_create (5);
661   handle->active_shorten_requests =
662     GNUNET_CONTAINER_multihashmap_create (5);
663   if (GNUNET_NO == try_connect (handle))
664   {
665     GNUNET_GNS_disconnect (handle);
666     return NULL;
667   }
668   return handle;
669 }
670
671
672 /**
673  * Shutdown connection with the GNS service.
674  *
675  * @param handle handle of the GNS connection to stop
676  */
677 void
678 GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle)
679 {
680   /* disco from GNS */
681 }
682
683
684 /**
685  * Perform an asynchronous Lookup operation on the GNS.
686  *
687  * @param handle handle to the GNS service
688  * @param name the name to look up
689  * @param iter function to call on each result
690  * @param iter_cls closure for iter
691  * @return handle to stop the async get
692  */
693 struct GNUNET_GNS_LookupHandle *
694 GNUNET_GNS_lookup_start (struct GNUNET_GNS_Handle *handle,
695                          const char * name,
696                          enum GNUNET_GNS_RecordType type,
697                          GNUNET_GNS_LookupIterator iter,
698                          void *iter_cls)
699 {
700   /* IPC to look for local entries, start dht lookup, return lookup_handle */
701   struct GNUNET_GNS_ClientLookupMessage *lookup_msg;
702   struct GNUNET_GNS_LookupHandle *lookup_handle;
703   GNUNET_HashCode key;
704   size_t msize;
705   struct PendingMessage *pending;
706
707   if (NULL == name)
708   {
709     return NULL;
710   }
711
712   GNUNET_CRYPTO_hash (name, strlen(name), &key);
713
714   msize = sizeof (struct GNUNET_GNS_ClientLookupMessage) + strlen(name);
715   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting lookup for %s in GNS %p\n",
716               name, handle);
717   pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
718   lookup_msg = (struct GNUNET_GNS_ClientLookupMessage *) &pending[1];
719   pending->msg = &lookup_msg->header;
720   pending->handle = handle;
721   pending->free_on_send = GNUNET_NO;
722   lookup_msg->header.size = htons (msize);
723   lookup_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_LOOKUP);
724   lookup_msg->key = key;
725   memcpy(&lookup_msg[1], name, strlen(name));
726   handle->uid_gen++;
727   lookup_msg->unique_id = handle->uid_gen;
728   GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail,
729                                pending);
730   pending->in_pending_queue = GNUNET_YES;
731   lookup_handle = GNUNET_malloc (sizeof (struct GNUNET_GNS_LookupHandle));
732   lookup_handle->iter = iter;
733   lookup_handle->iter_cls = iter_cls;
734   lookup_handle->message = pending;
735   lookup_handle->unique_id = lookup_msg->unique_id;
736   GNUNET_CONTAINER_multihashmap_put (handle->active_lookup_requests,
737                                   &lookup_msg->key,
738                                   lookup_handle,
739                                   GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
740   process_pending_messages (handle);
741   return lookup_handle;
742 }
743
744
745 /**
746  * Stop async GNS lookup.
747  *
748  * @param lookup_handle handle to the GNS lookup operation to stop
749  */
750 void
751 GNUNET_GNS_lookup_stop (struct GNUNET_GNS_LookupHandle *lookup_handle)
752 {
753   /* TODO Stop gns lookups */
754 }
755
756
757 /**
758  * Perform a name shortening operation on the GNS.
759  *
760  * @param handle handle to the GNS service
761  * @param name the name to look up
762  * @param proc function to call on result
763  * @param proc_cls closure for processor
764  * @return handle to the operation
765  */
766 struct GNUNET_GNS_ShortenHandle *
767 GNUNET_GNS_shorten (struct GNUNET_GNS_Handle *handle,
768                     const char * name,
769                     GNUNET_GNS_ShortenResultProcessor proc,
770                     void *proc_cls)
771 {
772   /* IPC to shorten gns names, return shorten_handle */
773   struct GNUNET_GNS_ClientShortenMessage *shorten_msg;
774   struct GNUNET_GNS_ShortenHandle *shorten_handle;
775   size_t msize;
776   struct PendingMessage *pending;
777
778   if (NULL == name)
779   {
780     return NULL;
781   }
782
783   msize = sizeof (struct GNUNET_GNS_ClientShortenMessage) + strlen(name);
784   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to shorten %s in GNS\n", name);
785   pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
786   shorten_msg = (struct GNUNET_GNS_ClientShortenMessage *) &pending[1];
787   pending->msg = &shorten_msg->header;
788   pending->handle = handle;
789   pending->free_on_send = GNUNET_NO;
790   shorten_msg->header.size = htons (msize);
791   shorten_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_SHORTEN);
792   memcpy(&shorten_msg[1], name, strlen(name));
793   handle->uid_gen++;
794   shorten_msg->unique_id = handle->uid_gen;
795   GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail,
796                                pending);
797   pending->in_pending_queue = GNUNET_YES;
798   shorten_handle = GNUNET_malloc (sizeof (struct GNUNET_GNS_ShortenHandle));
799   shorten_handle->proc = proc;
800   shorten_handle->proc_cls = proc_cls;
801   shorten_handle->message = pending;
802   shorten_handle->unique_id = shorten_msg->unique_id;
803   GNUNET_CONTAINER_multihashmap_put (handle->active_shorten_requests,
804                                      &shorten_msg->key,
805                                  shorten_handle,
806                                  GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
807   process_pending_messages (handle);
808   return shorten_handle;
809 }
810
811
812
813 /* end of gns_api.c */