-more rsa refactoring
[oweals/gnunet.git] / src / gns / gns_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010, 2012 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  * @file gns/gns_api.c
22  * @brief library to access the GNS service
23  * @author Martin Schanzenbach
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_constants.h"
29 #include "gnunet_arm_service.h"
30 #include "gnunet_hello_lib.h"
31 #include "gnunet_protocols.h"
32 #include "gnunet_dht_service.h"
33 #include "gns.h"
34 #include "gnunet_gns_service.h"
35
36
37 /**
38  * Handle to a lookup request
39  */
40 struct GNUNET_GNS_LookupRequest
41 {
42
43   /**
44    * DLL
45    */
46   struct GNUNET_GNS_LookupRequest *next;
47   
48   /**
49    * DLL
50    */
51   struct GNUNET_GNS_LookupRequest *prev;
52   
53   /**
54    * handle to gns 
55    */
56   struct GNUNET_GNS_Handle *gns_handle;
57   
58   /**
59    * processor to call on lookup result 
60    */
61   GNUNET_GNS_LookupResultProcessor lookup_proc;
62
63   /**
64    * processor closure 
65    */
66   void *proc_cls;
67  
68   /**
69    * request id 
70    */
71   uint64_t r_id;
72  
73 };
74
75
76 /**
77  * Handle to a shorten request
78  */
79 struct GNUNET_GNS_ShortenRequest
80 {
81   /**
82    * DLL
83    */
84   struct GNUNET_GNS_ShortenRequest *next;
85   
86   /**
87    * DLL
88    */
89   struct GNUNET_GNS_ShortenRequest *prev;
90
91   /**
92    * handle to gns
93    */
94   struct GNUNET_GNS_Handle *gns_handle;
95   
96   /**
97    *  processor to call on shorten result
98    */
99   GNUNET_GNS_ShortenResultProcessor shorten_proc;
100   
101   /**
102    * processor closure
103    */
104   void *proc_cls;
105
106   /**
107    * request id
108    */
109   uint64_t r_id;
110   
111 };
112
113
114 /**
115  * Handle to GetAuthorityRequest
116  */
117 struct GNUNET_GNS_GetAuthRequest
118 {
119   /**
120    * DLL
121    */
122   struct GNUNET_GNS_GetAuthRequest *next;
123   
124   /**
125    * DLL
126    */
127   struct GNUNET_GNS_GetAuthRequest *prev;
128
129   /**
130    * handle to gns
131    */
132   struct GNUNET_GNS_Handle *gns_handle;
133   
134   /**
135    * processor to call on authority lookup result
136    */
137   GNUNET_GNS_GetAuthResultProcessor auth_proc;
138   
139   /**
140    * processor closure
141    */
142   void *proc_cls;
143   
144   /**
145    * request id
146    */
147   uint32_t r_id;
148   
149 };
150
151
152 /**
153  * Entry in our list of messages to be (re-)transmitted.
154  */
155 struct PendingMessage
156 {
157   /**
158    * This is a doubly-linked list.
159    */
160   struct PendingMessage *prev;
161
162   /**
163    * This is a doubly-linked list.
164    */
165   struct PendingMessage *next;
166
167   /**
168    * request id
169    */
170   uint64_t r_id;
171
172   /**
173    * Size of the message.
174    */
175   size_t size;
176
177   /**
178    * This message has been transmitted.  GNUNET_NO if the message is
179    * in the "pending" DLL, GNUNET_YES if it has been transmitted to
180    * the service via the current client connection.
181    */
182   int transmitted;
183
184 };
185
186
187 /**
188  * Connection to the GNS service.
189  */
190 struct GNUNET_GNS_Handle
191 {
192
193   /**
194    * Configuration to use.
195    */
196   const struct GNUNET_CONFIGURATION_Handle *cfg;
197
198   /**
199    * Socket (if available).
200    */
201   struct GNUNET_CLIENT_Connection *client;
202
203   /**
204    * Currently pending transmission request (or NULL).
205    */
206   struct GNUNET_CLIENT_TransmitHandle *th;
207   
208   /**
209    * Head of linked list of shorten messages we would like to transmit.
210    */
211   struct PendingMessage *pending_head;
212
213   /**
214    * Tail of linked list of shorten messages we would like to transmit.
215    */
216   struct PendingMessage *pending_tail;
217   
218   /**
219    * Head of linked list of shorten messages we would like to transmit.
220    */
221   struct GNUNET_GNS_ShortenRequest *shorten_head;
222
223   /**
224    * Tail of linked list of shorten messages we would like to transmit.
225    */
226   struct GNUNET_GNS_ShortenRequest *shorten_tail;
227   
228   /**
229    * Head of linked list of lookup messages we would like to transmit.
230    */
231   struct GNUNET_GNS_LookupRequest *lookup_head;
232
233   /**
234    * Tail of linked list of lookup messages we would like to transmit.
235    */
236   struct GNUNET_GNS_LookupRequest *lookup_tail;
237   
238   /**
239    * Head of linked list of authority lookup messages we would like to transmit.
240    */
241   struct GNUNET_GNS_GetAuthRequest *get_auth_head;
242
243   /**
244    * Tail of linked list of authority lookup messages we would like to transmit.
245    */
246   struct GNUNET_GNS_GetAuthRequest *get_auth_tail;
247
248   /**
249    * Reconnect task
250    */
251   GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
252
253   uint32_t r_id;
254   
255   /**
256    * Did we start our receive loop yet?
257    */
258   int in_receive;
259
260 };
261
262
263 /**
264  * Try to send messages from list of messages to send
265  * @param handle GNS_Handle
266  */
267 static void
268 process_pending_messages (struct GNUNET_GNS_Handle *handle);
269
270
271 /**
272  * Reconnect to GNS service.
273  *
274  * @param h the handle to the GNS service
275  */
276 static void
277 reconnect (struct GNUNET_GNS_Handle *h)
278 {
279   GNUNET_assert (NULL == h->client);
280   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
281               "Trying to connect to GNS\n");
282   h->client = GNUNET_CLIENT_connect ("gns", h->cfg);
283   GNUNET_assert (NULL != h->client);
284   process_pending_messages (h);
285 }
286
287
288 /**
289  * Reconnect to GNS
290  *
291  * @param cls the handle
292  * @param tc task context
293  */
294 static void
295 reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
296 {
297   struct GNUNET_GNS_Handle *h = cls;
298
299   h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
300   reconnect (h);
301 }
302
303
304 /**
305  * Disconnect from service and then reconnect.
306  *
307  * @param h our handle
308  */
309 static void
310 force_reconnect (struct GNUNET_GNS_Handle *h)
311 {
312   struct GNUNET_GNS_ShortenRequest *st;
313   struct GNUNET_GNS_LookupRequest *lh;
314   struct GNUNET_GNS_GetAuthRequest *ga;
315   struct PendingMessage *p;
316
317   GNUNET_CLIENT_disconnect (h->client);
318   h->client = NULL;
319   h->in_receive = GNUNET_NO;
320   for (st = h->shorten_head; NULL != st; st = st->next)
321   {
322     p = (struct PendingMessage*) &st[1];
323     if (GNUNET_NO == p->transmitted)
324       continue;
325     p->transmitted = GNUNET_NO;
326     GNUNET_CONTAINER_DLL_insert (h->pending_head,
327                                  h->pending_tail,
328                                  p);  
329   }
330   for (lh = h->lookup_head; NULL != lh; lh = lh->next)
331   {
332     p = (struct PendingMessage*) &lh[1];
333     if (GNUNET_NO == p->transmitted)
334       continue;
335     p->transmitted = GNUNET_NO;
336     GNUNET_CONTAINER_DLL_insert (h->pending_head,
337                                  h->pending_tail,
338                                  p);  
339   }
340   for (ga = h->get_auth_head; NULL != ga; ga = ga->next)
341   {
342     p = (struct PendingMessage*) &ga[1];
343     if (GNUNET_NO == p->transmitted)
344       continue;
345     p->transmitted = GNUNET_NO;
346     GNUNET_CONTAINER_DLL_insert (h->pending_head,
347                                  h->pending_tail,
348                                  p);  
349   }
350   /* FIXME: 1s too long, exponential-backoff, starting at 1ms! (max = 1s might be OK) */
351   h->reconnect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
352                                                     &reconnect_task,
353                                                     h);
354 }
355
356
357 /**
358  * Transmit the next pending message, called by notify_transmit_ready
359  *
360  * @param cls the closure
361  * @param size size of pending data
362  * @param buf buffer with pending data
363  * @return size data transmitted
364  */
365 static size_t
366 transmit_pending (void *cls, size_t size, void *buf);
367
368
369 /**
370  * Handler for messages received from the GNS service
371  *
372  * @param cls the 'struct GNUNET_GNS_Handle'
373  * @param msg the incoming message
374  */
375 static void
376 process_message (void *cls, const struct GNUNET_MessageHeader *msg);
377
378
379 /**
380  * Try to send messages from list of messages to send
381  *
382  * @param handle the GNS handle
383  */
384 static void
385 process_pending_messages (struct GNUNET_GNS_Handle *handle)
386 {
387   struct PendingMessage *p = handle->pending_head;
388
389   if (NULL == handle->client)
390     return; /* wait for reconnect */ 
391   if (NULL != handle->th)
392     return; /* transmission request already pending */ 
393
394   while ((NULL != p) && (p->transmitted == GNUNET_YES))
395     p = p->next;
396   if (NULL == p)
397     return; /* no messages pending */
398   
399   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
400               "Trying to transmit %u bytes\n", 
401               (unsigned int) p->size);
402   handle->th =
403     GNUNET_CLIENT_notify_transmit_ready (handle->client,
404                                          p->size,
405                                          GNUNET_TIME_UNIT_FOREVER_REL,
406                                          GNUNET_NO, &transmit_pending,
407                                          handle);
408   GNUNET_break (NULL != handle->th);
409 }
410
411
412 /**
413  * Transmit the next pending message, called by notify_transmit_ready
414  *
415  * @param cls the closure
416  * @param size size of pending data
417  * @param buf buffer with pending data
418  * @return size data transmitted
419  */
420 static size_t
421 transmit_pending (void *cls, size_t size, void *buf)
422 {
423   struct GNUNET_GNS_Handle *h = cls;
424   char *cbuf = buf;
425   struct PendingMessage *p;
426   size_t tsize;
427
428   h->th = NULL;  
429   if ((0 == size) || (NULL == buf))
430   {
431     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
432                 "Transmission to GNS service failed!\n");
433     force_reconnect (h);
434     return 0;
435   }  
436   if (NULL == (p = h->pending_head))
437     return 0;
438
439   tsize = 0;
440   while ((NULL != (p = h->pending_head)) && (p->size <= size))
441   {
442     memcpy (&cbuf[tsize], &p[1], p->size);
443     tsize += p->size;
444     size -= p->size;
445     p->transmitted = GNUNET_YES;
446     GNUNET_CONTAINER_DLL_remove (h->pending_head,
447                                  h->pending_tail,
448                                  p);
449     if (GNUNET_YES != h->in_receive)
450     {
451       GNUNET_CLIENT_receive (h->client, &process_message, h,
452                              GNUNET_TIME_UNIT_FOREVER_REL);
453       h->in_receive = GNUNET_YES;
454     }
455   }
456   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
457               "Sending %u bytes\n",
458               (unsigned int) tsize);
459   process_pending_messages (h);
460   return tsize;
461 }
462
463
464 /**
465  * Process a given reply that might match the given
466  * request.
467  *
468  * @param qe a queue entry
469  * @param msg the shorten msg received
470  */
471 static void
472 process_shorten_reply (struct GNUNET_GNS_ShortenRequest *qe,
473                        const struct GNUNET_GNS_ClientShortenResultMessage *msg)
474 {
475   struct GNUNET_GNS_Handle *h = qe->gns_handle;
476   struct PendingMessage *p = (struct PendingMessage *)&qe[1];
477   const char *short_name;
478   size_t mlen;
479   
480   if (GNUNET_YES != p->transmitted)
481   {
482     /* service send reply to query we never managed to send!? */
483     GNUNET_break (0);
484     force_reconnect (h);
485     return;
486   }
487   mlen = ntohs (msg->header.size);
488   if (ntohs (msg->header.size) == sizeof (struct GNUNET_GNS_ClientShortenResultMessage))
489   {
490     /* service reports resolution failed */
491     short_name = NULL;
492   }
493   else
494   {
495     short_name = (const char *) &msg[1];
496     if ('\0' != short_name[mlen - sizeof (struct GNUNET_GNS_ClientShortenResultMessage) - 1])
497     {
498       GNUNET_break (0);
499       force_reconnect (h);
500       return;
501     } 
502   }
503   GNUNET_CONTAINER_DLL_remove (h->shorten_head, h->shorten_tail, qe);
504   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
505               "Received shortened reply `%s' from GNS service\n",
506               short_name);
507   qe->shorten_proc (qe->proc_cls, short_name);
508   GNUNET_free (qe);
509 }
510
511
512 /**
513  * Process a given reply that might match the given
514  * request.
515  *
516  * @param qe the handle to the request
517  * @param msg the message to process
518  */
519 static void
520 process_get_auth_reply (struct GNUNET_GNS_GetAuthRequest *qe,
521                        const struct GNUNET_GNS_ClientGetAuthResultMessage *msg)
522 {
523   struct GNUNET_GNS_Handle *h = qe->gns_handle;
524   struct PendingMessage *p = (struct PendingMessage *)&qe[1];
525   const char *auth_name;
526   size_t mlen;
527
528   if (GNUNET_YES != p->transmitted)
529   {
530     /* service send reply to query we never managed to send!? */
531     GNUNET_break (0);
532     force_reconnect (h);
533     return;
534   }
535   mlen = ntohs (msg->header.size);
536   if (mlen == sizeof (struct GNUNET_GNS_ClientGetAuthResultMessage))
537   {
538     auth_name = NULL;
539   }
540   else
541   {
542     auth_name = (const char*) &msg[1];
543     if ('\0' != auth_name[mlen - sizeof (struct GNUNET_GNS_ClientGetAuthResultMessage) - 1])
544     {
545       GNUNET_break (0);
546       force_reconnect (h);
547       return;
548     }
549   }
550   GNUNET_CONTAINER_DLL_remove (h->get_auth_head, h->get_auth_tail, qe);
551   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
552               "Received GET_AUTH reply `%s' from GNS service\n",
553               auth_name);
554   qe->auth_proc (qe->proc_cls, auth_name);
555   GNUNET_free (qe);
556 }
557
558
559 /**
560  * Process a given reply to the lookup request
561  *
562  * @param qe a queue entry
563  * @param msg the lookup message received
564  */
565 static void
566 process_lookup_reply (struct GNUNET_GNS_LookupRequest *qe,
567                       const struct GNUNET_GNS_ClientLookupResultMessage *msg)
568 {
569   struct GNUNET_GNS_Handle *h = qe->gns_handle;
570   struct PendingMessage *p = (struct PendingMessage *) &qe[1];
571   uint32_t rd_count = ntohl (msg->rd_count);
572   struct GNUNET_NAMESTORE_RecordData rd[rd_count];
573   size_t mlen;
574
575   if (GNUNET_YES != p->transmitted)
576   {
577     /* service send reply to query we never managed to send!? */
578     GNUNET_break (0);
579     force_reconnect (h);
580     return;
581   }
582   mlen = ntohs (msg->header.size);
583   mlen -= sizeof (struct GNUNET_GNS_ClientLookupResultMessage);
584   if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (mlen,
585                                                              (const char*) &msg[1],
586                                                              rd_count,
587                                                              rd))
588   {
589     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
590                 _("Failed to serialize lookup reply from GNS service!\n"));
591     qe->lookup_proc (qe->proc_cls, 0, NULL);
592   }
593   else
594   { 
595     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
596                 "Received lookup reply from GNS service (%u records)\n",
597                 (unsigned int) rd_count);
598     qe->lookup_proc (qe->proc_cls, rd_count, rd);
599   }
600   GNUNET_CONTAINER_DLL_remove (h->lookup_head, h->lookup_tail, qe);
601   GNUNET_free (qe);
602 }
603
604
605 /**
606  * Handler for messages received from the GNS service
607  *
608  * @param cls the 'struct GNUNET_GNS_Handle'
609  * @param msg the incoming message
610  */
611 static void
612 process_message (void *cls, const struct GNUNET_MessageHeader *msg)
613 {
614   struct GNUNET_GNS_Handle *handle = cls;
615   struct GNUNET_GNS_LookupRequest *lr;
616   struct GNUNET_GNS_ShortenRequest *sr;
617   struct GNUNET_GNS_GetAuthRequest *gar;
618   const struct GNUNET_GNS_ClientLookupResultMessage *lookup_msg;
619   const struct GNUNET_GNS_ClientShortenResultMessage *shorten_msg;
620   const struct GNUNET_GNS_ClientGetAuthResultMessage *get_auth_msg;
621   uint64_t r_id;
622   
623   if (NULL == msg)
624   {
625     force_reconnect (handle);
626     return;
627   }
628   switch (ntohs (msg->type))
629   {
630   case GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT:
631     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
632                 "Got LOOKUP_RESULT msg\n");
633     if (ntohs (msg->size) < sizeof (struct GNUNET_GNS_ClientLookupResultMessage))
634     {
635       GNUNET_break (0);
636       force_reconnect (handle);
637       return;
638     }
639     lookup_msg = (const struct GNUNET_GNS_ClientLookupResultMessage *) msg;
640     r_id = ntohl (lookup_msg->id);   
641     for (lr = handle->lookup_head; NULL != lr; lr = lr->next)    
642       if (lr->r_id == r_id)
643       {
644         process_lookup_reply(lr, lookup_msg);    
645         break;
646       }
647     break;
648   case GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT:  
649     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
650                 "Got SHORTEN_RESULT msg\n");
651     if (ntohs (msg->size) < sizeof (struct GNUNET_GNS_ClientShortenResultMessage))
652     {
653       GNUNET_break (0);
654       force_reconnect (handle);
655       return;
656     }
657     shorten_msg = (const struct GNUNET_GNS_ClientShortenResultMessage *) msg;   
658     r_id = ntohl (shorten_msg->id);
659     for (sr = handle->shorten_head; NULL != sr; sr = sr->next)    
660       if (sr->r_id == r_id)
661       {
662         process_shorten_reply (sr, shorten_msg);
663         break;
664       }
665     break;
666   case GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT:
667     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
668                 "Got GET_AUTH_RESULT msg\n");
669     if (ntohs (msg->size) < sizeof (struct GNUNET_GNS_ClientGetAuthResultMessage))
670     {
671       GNUNET_break (0);
672       force_reconnect (handle);
673       return;
674     }
675     get_auth_msg = (const struct GNUNET_GNS_ClientGetAuthResultMessage *) msg;
676     r_id = ntohl (get_auth_msg->id);
677     for (gar = handle->get_auth_head; NULL != gar; gar = gar->next)
678       if (gar->r_id == r_id)
679       {
680         process_get_auth_reply (gar, get_auth_msg);
681         break;
682       }
683     break;
684   default:
685     GNUNET_break (0);
686     force_reconnect (handle);
687     return;
688   }
689   GNUNET_CLIENT_receive (handle->client, &process_message, handle,
690                          GNUNET_TIME_UNIT_FOREVER_REL);
691 }
692
693
694 /**
695  * Initialize the connection with the GNS service.
696  *
697  * @param cfg configuration to use
698  * @return handle to the GNS service, or NULL on error
699  */
700 struct GNUNET_GNS_Handle *
701 GNUNET_GNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
702 {
703   struct GNUNET_GNS_Handle *handle;
704
705   handle = GNUNET_malloc (sizeof (struct GNUNET_GNS_Handle));
706   handle->cfg = cfg;
707   reconnect (handle);
708   return handle;
709 }
710
711
712 /**
713  * Shutdown connection with the GNS service.
714  *
715  * @param handle handle of the GNS connection to stop
716  */
717 void
718 GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle)
719 {
720   GNUNET_CLIENT_disconnect (handle->client);
721   if (GNUNET_SCHEDULER_NO_TASK != handle->reconnect_task)
722   {
723     GNUNET_SCHEDULER_cancel (handle->reconnect_task);
724     handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
725   }
726   GNUNET_assert (NULL == handle->lookup_head);
727   GNUNET_assert (NULL == handle->shorten_head);
728   GNUNET_assert (NULL == handle->get_auth_head);
729   GNUNET_free (handle);
730 }
731
732
733 /**
734  * Cancel pending lookup request
735  *
736  * @param lr the lookup request to cancel
737  */
738 void
739 GNUNET_GNS_cancel_lookup_request (struct GNUNET_GNS_LookupRequest *lr)
740 {
741   struct PendingMessage *p = (struct PendingMessage*) &lr[1];
742
743   GNUNET_assert (NULL != lr->gns_handle); 
744   if (GNUNET_NO == p->transmitted)
745     GNUNET_CONTAINER_DLL_remove (lr->gns_handle->pending_head,
746                                  lr->gns_handle->pending_tail,
747                                  p);
748   GNUNET_CONTAINER_DLL_remove (lr->gns_handle->lookup_head,
749                                lr->gns_handle->lookup_tail,
750                                lr);
751   GNUNET_free (lr);
752 }
753
754
755 /**
756  * Cancel pending shorten request
757  *
758  * @param sr the lookup request to cancel
759  */
760 void
761 GNUNET_GNS_cancel_shorten_request (struct GNUNET_GNS_ShortenRequest *sr)
762 {
763   struct PendingMessage *p = (struct PendingMessage*) &sr[1];
764
765   GNUNET_assert (NULL != sr->gns_handle);
766   if (GNUNET_NO == p->transmitted)
767     GNUNET_CONTAINER_DLL_remove (sr->gns_handle->pending_head,
768                                  sr->gns_handle->pending_tail,
769                                  p);
770   GNUNET_CONTAINER_DLL_remove (sr->gns_handle->shorten_head,
771                                sr->gns_handle->shorten_tail,
772                                sr);
773   GNUNET_free (sr);
774 }
775
776
777 /**
778  * Cancel pending get auth  request
779  *
780  * @param gar the lookup request to cancel
781  */
782 void
783 GNUNET_GNS_cancel_get_auth_request (struct GNUNET_GNS_GetAuthRequest *gar)
784 {
785   struct PendingMessage *p = (struct PendingMessage*) &gar[1];
786
787   GNUNET_assert (NULL != gar->gns_handle); 
788   if (GNUNET_NO == p->transmitted)
789     GNUNET_CONTAINER_DLL_remove (gar->gns_handle->pending_head,
790                                  gar->gns_handle->pending_tail,
791                                  p);  
792   GNUNET_CONTAINER_DLL_remove (gar->gns_handle->get_auth_head,
793                                gar->gns_handle->get_auth_tail,
794                                gar);
795   GNUNET_free (gar);
796 }
797
798
799 /**
800  * Perform an asynchronous Lookup operation on the GNS.
801  *
802  * @param handle handle to the GNS service
803  * @param name the name to look up
804  * @param zone the zone to start the resolution in
805  * @param type the record type to look up
806  * @param only_cached GNUNET_YES to only check locally not DHT for performance
807  * @param shorten_key the private key of the shorten zone (can be NULL)
808  * @param proc processor to call on result
809  * @param proc_cls closure for processor
810  * @return handle to the get request
811  */
812 struct GNUNET_GNS_LookupRequest*
813 GNUNET_GNS_lookup_zone (struct GNUNET_GNS_Handle *handle,
814                         const char *name,
815                         struct GNUNET_CRYPTO_ShortHashCode *zone,
816                         enum GNUNET_GNS_RecordType type,
817                         int only_cached,
818                         struct GNUNET_CRYPTO_RsaPrivateKey *shorten_key,
819                         GNUNET_GNS_LookupResultProcessor proc,
820                         void *proc_cls)
821 {
822   /* IPC to shorten gns names, return shorten_handle */
823   struct GNUNET_GNS_ClientLookupMessage *lookup_msg;
824   struct GNUNET_GNS_LookupRequest *lr;
825   size_t msize;
826   struct PendingMessage *pending;
827   struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *pkey_enc;
828   size_t key_len;
829   char* pkey_tmp;
830
831   if (NULL == name)
832   {
833     GNUNET_break (0);
834     return NULL;
835   } 
836   if (NULL != shorten_key)
837   {
838     pkey_enc = GNUNET_CRYPTO_rsa_encode_key (shorten_key);
839     GNUNET_assert (pkey_enc != NULL);
840     key_len = ntohs (pkey_enc->len);
841   }
842   else
843   {
844     pkey_enc = NULL;
845     key_len = 0;
846   }
847   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
848               "Trying to lookup `%s' in GNS\n", 
849               name);
850   msize = sizeof (struct GNUNET_GNS_ClientLookupMessage)
851     + key_len + strlen (name) + 1;
852   if (msize > UINT16_MAX)
853   {
854     GNUNET_break (0);
855     GNUNET_free (pkey_enc);
856     return NULL;
857   }
858   lr = GNUNET_malloc (sizeof (struct GNUNET_GNS_LookupRequest) +
859                       sizeof (struct PendingMessage) + msize);
860   lr->gns_handle = handle;
861   lr->lookup_proc = proc;
862   lr->proc_cls = proc_cls;
863   lr->r_id = handle->r_id++;
864   pending = (struct PendingMessage *)&lr[1];
865   pending->size = msize;
866   pending->r_id = lr->r_id;
867   GNUNET_CONTAINER_DLL_insert_tail (handle->lookup_head,
868                                     handle->lookup_tail, lr);
869
870   lookup_msg = (struct GNUNET_GNS_ClientLookupMessage *) &pending[1];
871   lookup_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_LOOKUP);
872   lookup_msg->header.size = htons (msize);
873   lookup_msg->id = htonl (lr->r_id);
874   lookup_msg->only_cached = htonl (only_cached);
875   if (NULL != zone)
876   {
877     lookup_msg->use_default_zone = htonl (GNUNET_NO);
878     memcpy (&lookup_msg->zone, zone, sizeof (struct GNUNET_CRYPTO_ShortHashCode));
879   }
880   else
881   {
882     lookup_msg->use_default_zone = htonl (GNUNET_YES);
883     memset (&lookup_msg->zone, 0, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
884   }  
885   lookup_msg->type = htonl (type);
886   pkey_tmp = (char *) &lookup_msg[1];  
887   if (pkey_enc != NULL)
888   {
889     lookup_msg->have_key = htonl (GNUNET_YES);
890     memcpy (pkey_tmp, pkey_enc, key_len);
891   }
892   else
893     lookup_msg->have_key = htonl (GNUNET_NO);
894   GNUNET_free_non_null (pkey_enc);
895   memcpy (&pkey_tmp[key_len], name, strlen (name) + 1);
896
897   GNUNET_CONTAINER_DLL_insert_tail (handle->pending_head,
898                                     handle->pending_tail,
899                                     pending);
900   process_pending_messages (handle);
901   return lr;
902 }
903
904
905 /**
906  * Perform an asynchronous Lookup operation on the GNS.
907  *
908  * @param handle handle to the GNS service
909  * @param name the name to look up
910  * @param type the record type to look up
911  * @param only_cached GNUNET_YES to only check locally not DHT for performance
912  * @param shorten_key the private key of the shorten zone (can be NULL)
913  * @param proc processor to call on result
914  * @param proc_cls closure for processor
915  * @return handle to the lookup request
916  */
917 struct GNUNET_GNS_LookupRequest *
918 GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle,
919                    const char *name,
920                    enum GNUNET_GNS_RecordType type,
921                    int only_cached,
922                    struct GNUNET_CRYPTO_RsaPrivateKey *shorten_key,
923                    GNUNET_GNS_LookupResultProcessor proc,
924                    void *proc_cls)
925 {
926   return GNUNET_GNS_lookup_zone (handle, name,
927                                  NULL,
928                                  type, only_cached,
929                                  shorten_key,
930                                  proc, proc_cls);
931 }
932
933
934 /**
935  * Perform a name shortening operation on the GNS.
936  *
937  * @param handle handle to the GNS service
938  * @param name the name to look up
939  * @param private_zone the public zone of the private zone
940  * @param shorten_zone the public zone of the shorten zone
941  * @param zone the zone to start the resolution in
942  * @param proc function to call on result
943  * @param proc_cls closure for processor
944  * @return handle to the operation
945  */
946 struct GNUNET_GNS_ShortenRequest*
947 GNUNET_GNS_shorten_zone (struct GNUNET_GNS_Handle *handle,
948                          const char *name,
949                          struct GNUNET_CRYPTO_ShortHashCode *private_zone,
950                          struct GNUNET_CRYPTO_ShortHashCode *shorten_zone,
951                          struct GNUNET_CRYPTO_ShortHashCode *zone,
952                          GNUNET_GNS_ShortenResultProcessor proc,
953                          void *proc_cls)
954 {
955   /* IPC to shorten gns names, return shorten_handle */
956   struct GNUNET_GNS_ClientShortenMessage *shorten_msg;
957   struct GNUNET_GNS_ShortenRequest *sr;
958   size_t msize;
959   struct PendingMessage *pending;
960
961   if (NULL == name)
962   {
963     GNUNET_break (0);
964     return NULL;
965   }
966   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to shorten `%s' in GNS\n", name);
967   msize = sizeof (struct GNUNET_GNS_ClientShortenMessage) + strlen (name) + 1;
968   if (msize > UINT16_MAX)
969   {
970     GNUNET_break (0);
971     return NULL;
972   }
973   sr = GNUNET_malloc (sizeof (struct GNUNET_GNS_ShortenRequest) +
974                       sizeof (struct PendingMessage) + msize);
975   sr->gns_handle = handle;
976   sr->shorten_proc = proc;
977   sr->proc_cls = proc_cls;
978   sr->r_id = handle->r_id++;
979   GNUNET_CONTAINER_DLL_insert_tail (handle->shorten_head,
980                                     handle->shorten_tail, sr);
981   pending = (struct PendingMessage *)&sr[1];
982   pending->size = msize;
983   pending->r_id = sr->r_id;
984
985   shorten_msg = (struct GNUNET_GNS_ClientShortenMessage *) &pending[1];
986   shorten_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_SHORTEN);
987   shorten_msg->header.size = htons ((uint16_t) msize);
988   shorten_msg->id = htonl (sr->r_id);
989   shorten_msg->private_zone = *private_zone;
990   shorten_msg->shorten_zone = *shorten_zone;  
991   if (NULL != zone)
992   {
993     shorten_msg->use_default_zone = htonl (GNUNET_NO);
994     memcpy (&shorten_msg->zone, zone,
995             sizeof (struct GNUNET_CRYPTO_ShortHashCode));
996   }
997   else
998   {
999     shorten_msg->use_default_zone = htonl (GNUNET_YES);
1000     memset (&shorten_msg->zone, 0, sizeof (struct GNUNET_CRYPTO_ShortHashCode));
1001   } 
1002   memcpy (&shorten_msg[1], name, strlen (name) + 1);
1003   GNUNET_CONTAINER_DLL_insert_tail (handle->pending_head, handle->pending_tail,
1004                                pending);  
1005   process_pending_messages (handle);
1006   return sr;
1007 }
1008
1009
1010 /**
1011  * Perform a name shortening operation on the GNS.
1012  *
1013  * @param handle handle to the GNS service
1014  * @param name the name to look up
1015  * @param private_zone the public zone of the private zone
1016  * @param shorten_zone the public zone of the shorten zone
1017  * @param proc function to call on result
1018  * @param proc_cls closure for processor
1019  * @return handle to the operation
1020  */
1021 struct GNUNET_GNS_ShortenRequest*
1022 GNUNET_GNS_shorten (struct GNUNET_GNS_Handle *handle,
1023                     const char *name,
1024                     struct GNUNET_CRYPTO_ShortHashCode *private_zone,
1025                     struct GNUNET_CRYPTO_ShortHashCode *shorten_zone,
1026                     GNUNET_GNS_ShortenResultProcessor proc,
1027                     void *proc_cls)
1028 {
1029   return GNUNET_GNS_shorten_zone (handle, name,
1030                                   private_zone, shorten_zone,
1031                                   NULL, proc, proc_cls);
1032 }
1033
1034
1035 /**
1036  * Perform an authority lookup for a given name.
1037  *
1038  * @param handle handle to the GNS service
1039  * @param name the name to look up authority for
1040  * @param proc function to call on result
1041  * @param proc_cls closure for processor
1042  * @return handle to the operation
1043  */
1044 struct GNUNET_GNS_GetAuthRequest*
1045 GNUNET_GNS_get_authority (struct GNUNET_GNS_Handle *handle,
1046                           const char *name,
1047                           GNUNET_GNS_GetAuthResultProcessor proc,
1048                           void *proc_cls)
1049 {
1050   struct GNUNET_GNS_ClientGetAuthMessage *get_auth_msg;
1051   struct GNUNET_GNS_GetAuthRequest *gar;
1052   size_t msize;
1053   struct PendingMessage *pending;
1054
1055   if (NULL == name)
1056   {
1057     GNUNET_break (0);
1058     return NULL;
1059   }
1060   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1061               "Trying to look up authority for %s in GNS\n", name);
1062   msize = sizeof (struct GNUNET_GNS_ClientGetAuthMessage) + strlen (name) + 1;
1063   if (msize > UINT16_MAX)
1064   {
1065     GNUNET_break (0);
1066     return NULL;
1067   }
1068   gar = GNUNET_malloc (sizeof (struct GNUNET_GNS_GetAuthRequest) +
1069                        sizeof (struct PendingMessage) + msize);
1070   gar->gns_handle = handle;
1071   gar->auth_proc = proc;
1072   gar->proc_cls = proc_cls;
1073   gar->r_id = handle->r_id++;
1074   GNUNET_CONTAINER_DLL_insert_tail (handle->get_auth_head,
1075                                     handle->get_auth_tail, gar);
1076
1077   pending = (struct PendingMessage *) &gar[1];
1078   pending->size = msize;
1079   pending->r_id = gar->r_id;
1080   get_auth_msg = (struct GNUNET_GNS_ClientGetAuthMessage *) &pending[1];
1081   get_auth_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_GET_AUTH);
1082   get_auth_msg->header.size = htons (msize);
1083   get_auth_msg->id = htonl (gar->r_id);
1084   memcpy (&get_auth_msg[1], name, strlen (name) + 1);
1085   GNUNET_CONTAINER_DLL_insert_tail (handle->pending_head, 
1086                                     handle->pending_tail,
1087                                     pending);
1088   process_pending_messages (handle);
1089   return gar;
1090 }
1091
1092
1093 /* end of gns_api.c */