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