-code review
[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 fixme
346  */
347 static size_t
348 transmit_pending (void *cls, size_t size, void *buf);
349
350
351 /**
352  * Handler for messages received from the GNS service
353  *
354  * @param cls the 'struct GNUNET_GNS_Handle'
355  * @param msg the incoming message
356  */
357 static void
358 process_message (void *cls, const struct GNUNET_MessageHeader *msg);
359
360
361 /**
362  * Try to send messages from list of messages to send
363  *
364  * @param fixme
365  */
366 static void
367 process_pending_messages (struct GNUNET_GNS_Handle *handle)
368 {
369   struct PendingMessage *p = handle->pending_head;
370
371   if (NULL == handle->client)
372     return; /* wait for reconnect */ 
373   if (NULL != handle->th)
374     return; /* transmission request already pending */ 
375
376   while ((NULL != p) && (p->transmitted == GNUNET_YES))
377     p = p->next;
378   if (NULL == p)
379     return; /* no messages pending */
380   
381   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
382               "Trying to transmit %u bytes\n", 
383               (unsigned int) p->size);
384   handle->th =
385     GNUNET_CLIENT_notify_transmit_ready (handle->client,
386                                          p->size,
387                                          GNUNET_TIME_UNIT_FOREVER_REL,
388                                          GNUNET_NO, &transmit_pending,
389                                          handle);
390   GNUNET_break (NULL != handle->th);
391 }
392
393
394 /**
395  * Transmit the next pending message, called by notify_transmit_ready
396  *
397  * @param fixme
398  */
399 static size_t
400 transmit_pending (void *cls, size_t size, void *buf)
401 {
402   struct GNUNET_GNS_Handle *h = cls;
403   char *cbuf = buf;
404   struct PendingMessage *p;
405   size_t tsize;
406
407   h->th = NULL;  
408   if ((0 == size) || (NULL == buf))
409   {
410     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
411                 "Transmission to GNS service failed!\n");
412     force_reconnect (h);
413     return 0;
414   }  
415   if (NULL == (p = h->pending_head))
416     return 0;
417
418   tsize = 0;
419   while ((NULL != (p = h->pending_head)) && (p->size <= size))
420   {
421     memcpy (&cbuf[tsize], &p[1], p->size);
422     tsize += p->size;
423     size -= p->size;
424     p->transmitted = GNUNET_YES;
425     GNUNET_CONTAINER_DLL_remove (h->pending_head,
426                                  h->pending_tail,
427                                  p);
428     if (GNUNET_YES != h->in_receive)
429     {
430       GNUNET_CLIENT_receive (h->client, &process_message, h,
431                              GNUNET_TIME_UNIT_FOREVER_REL);
432       h->in_receive = GNUNET_YES;
433     }
434   }
435   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
436               "Sending %u bytes\n",
437               (unsigned int) tsize);
438   process_pending_messages (h);
439   return tsize;
440 }
441
442
443 /**
444  * Process a given reply that might match the given
445  * request.
446  *
447  * @param qe a queue entry
448  * @param msg the shorten msg received
449  */
450 static void
451 process_shorten_reply (struct GNUNET_GNS_ShortenRequest *qe,
452                        const struct GNUNET_GNS_ClientShortenResultMessage *msg)
453 {
454   struct GNUNET_GNS_Handle *h = qe->gns_handle;
455   struct PendingMessage *p = (struct PendingMessage *)&qe[1];
456   const char *short_name;
457   size_t mlen;
458   
459   if (GNUNET_YES != p->transmitted)
460   {
461     /* service send reply to query we never managed to send!? */
462     GNUNET_break (0);
463     force_reconnect (h);
464     return;
465   }
466   mlen = ntohs (msg->header.size);
467   if (ntohs (msg->header.size) == sizeof (struct GNUNET_GNS_ClientShortenResultMessage))
468   {
469     /* service reports resolution failed */
470     short_name = NULL;
471   }
472   else
473   {
474     short_name = (const char *) &msg[1];
475     if ('\0' != short_name[mlen - sizeof (struct GNUNET_GNS_ClientShortenResultMessage) - 1])
476     {
477       GNUNET_break (0);
478       force_reconnect (h);
479       return;
480     } 
481   }
482   GNUNET_CONTAINER_DLL_remove (h->shorten_head, h->shorten_tail, qe);
483   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
484               "Received shortened reply `%s' from GNS service\n",
485               short_name);
486   qe->shorten_proc (qe->proc_cls, short_name);
487   GNUNET_free (qe);
488 }
489
490
491 /**
492  * Process a given reply that might match the given
493  * request.
494  *
495  * @param qe the handle to the request
496  * @param msg the message to process
497  */
498 static void
499 process_get_auth_reply (struct GNUNET_GNS_GetAuthRequest *qe,
500                        const struct GNUNET_GNS_ClientGetAuthResultMessage *msg)
501 {
502   struct GNUNET_GNS_Handle *h = qe->gns_handle;
503   struct PendingMessage *p = (struct PendingMessage *)&qe[1];
504   const char *auth_name;
505   size_t mlen;
506
507   if (GNUNET_YES != p->transmitted)
508   {
509     /* service send reply to query we never managed to send!? */
510     GNUNET_break (0);
511     force_reconnect (h);
512     return;
513   }
514   mlen = ntohs (msg->header.size);
515   if (mlen == sizeof (struct GNUNET_GNS_ClientGetAuthResultMessage))
516   {
517     auth_name = NULL;
518   }
519   else
520   {
521     auth_name = (const char*) &msg[1];
522     if ('\0' != auth_name[mlen - sizeof (struct GNUNET_GNS_ClientGetAuthResultMessage) - 1])
523     {
524       GNUNET_break (0);
525       force_reconnect (h);
526       return;
527     }
528   }
529   GNUNET_CONTAINER_DLL_remove (h->get_auth_head, h->get_auth_tail, qe);
530   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
531               "Received GET_AUTH reply `%s' from GNS service\n",
532               auth_name);
533   qe->auth_proc (qe->proc_cls, auth_name);
534   GNUNET_free (qe);
535 }
536
537
538 /**
539  * Process a given reply to the lookup request
540  *
541  * @param qe a queue entry
542  * @param msg the lookup message received
543  */
544 static void
545 process_lookup_reply (struct GNUNET_GNS_LookupRequest *qe,
546                       const struct GNUNET_GNS_ClientLookupResultMessage *msg)
547 {
548   struct GNUNET_GNS_Handle *h = qe->gns_handle;
549   struct PendingMessage *p = (struct PendingMessage *) &qe[1];
550   uint32_t rd_count = ntohl (msg->rd_count);
551   struct GNUNET_NAMESTORE_RecordData rd[rd_count];
552   size_t mlen;
553
554   if (GNUNET_YES != p->transmitted)
555   {
556     /* service send reply to query we never managed to send!? */
557     GNUNET_break (0);
558     force_reconnect (h);
559     return;
560   }
561   mlen = ntohs (msg->header.size);
562   mlen -= sizeof (struct GNUNET_GNS_ClientLookupResultMessage);
563   if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (mlen,
564                                                              (const char*) &msg[1],
565                                                              rd_count,
566                                                              rd))
567   {
568     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
569                 _("Failed to serialize lookup reply from GNS service!\n"));
570     qe->lookup_proc (qe->proc_cls, 0, NULL);
571   }
572   else
573   { 
574     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
575                 "Received lookup reply from GNS service (%u records)\n",
576                 (unsigned int) rd_count);
577     qe->lookup_proc (qe->proc_cls, rd_count, rd);
578   }
579   GNUNET_CONTAINER_DLL_remove (h->lookup_head, h->lookup_tail, qe);
580   GNUNET_free (qe);
581 }
582
583
584 /**
585  * Handler for messages received from the GNS service
586  *
587  * @param cls the 'struct GNUNET_GNS_Handle'
588  * @param msg the incoming message
589  */
590 static void
591 process_message (void *cls, const struct GNUNET_MessageHeader *msg)
592 {
593   struct GNUNET_GNS_Handle *handle = cls;
594   struct GNUNET_GNS_LookupRequest *lr;
595   struct GNUNET_GNS_ShortenRequest *sr;
596   struct GNUNET_GNS_GetAuthRequest *gar;
597   const struct GNUNET_GNS_ClientLookupResultMessage *lookup_msg;
598   const struct GNUNET_GNS_ClientShortenResultMessage *shorten_msg;
599   const struct GNUNET_GNS_ClientGetAuthResultMessage *get_auth_msg;
600   uint64_t r_id;
601   
602   if (NULL == msg)
603   {
604     force_reconnect (handle);
605     return;
606   }
607   switch (ntohs (msg->type))
608   {
609   case GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT:
610     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
611                 "Got LOOKUP_RESULT msg\n");
612     if (ntohs (msg->size) < sizeof (struct GNUNET_GNS_ClientLookupResultMessage))
613     {
614       GNUNET_break (0);
615       force_reconnect (handle);
616       return;
617     }
618     lookup_msg = (const struct GNUNET_GNS_ClientLookupResultMessage *) msg;
619     r_id = ntohl (lookup_msg->id);   
620     for (lr = handle->lookup_head; NULL != lr; lr = lr->next)    
621       if (lr->r_id == r_id)
622       {
623         process_lookup_reply(lr, lookup_msg);    
624         break;
625       }
626     break;
627   case GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT:  
628     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
629                 "Got SHORTEN_RESULT msg\n");
630     if (ntohs (msg->size) < sizeof (struct GNUNET_GNS_ClientShortenResultMessage))
631     {
632       GNUNET_break (0);
633       force_reconnect (handle);
634       return;
635     }
636     shorten_msg = (const struct GNUNET_GNS_ClientShortenResultMessage *) msg;   
637     r_id = ntohl (shorten_msg->id);
638     for (sr = handle->shorten_head; NULL != sr; sr = sr->next)    
639       if (sr->r_id == r_id)
640       {
641         process_shorten_reply (sr, shorten_msg);
642         break;
643       }
644     break;
645   case GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT:
646     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
647                 "Got GET_AUTH_RESULT msg\n");
648     if (ntohs (msg->size) < sizeof (struct GNUNET_GNS_ClientGetAuthResultMessage))
649     {
650       GNUNET_break (0);
651       force_reconnect (handle);
652       return;
653     }
654     get_auth_msg = (const struct GNUNET_GNS_ClientGetAuthResultMessage *) msg;
655     r_id = ntohl (get_auth_msg->id);
656     for (gar = handle->get_auth_head; NULL != gar; gar = gar->next)
657       if (gar->r_id == r_id)
658       {
659         process_get_auth_reply (gar, get_auth_msg);
660         break;
661       }
662     break;
663   default:
664     GNUNET_break (0);
665     force_reconnect (handle);
666     return;
667   }
668   GNUNET_CLIENT_receive (handle->client, &process_message, handle,
669                          GNUNET_TIME_UNIT_FOREVER_REL);
670 }
671
672
673 /**
674  * Initialize the connection with the GNS service.
675  *
676  * @param cfg configuration to use
677  * @return handle to the GNS service, or NULL on error
678  */
679 struct GNUNET_GNS_Handle *
680 GNUNET_GNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
681 {
682   struct GNUNET_GNS_Handle *handle;
683
684   handle = GNUNET_malloc (sizeof (struct GNUNET_GNS_Handle));
685   handle->cfg = cfg;
686   reconnect (handle);
687   return handle;
688 }
689
690
691 /**
692  * Shutdown connection with the GNS service.
693  *
694  * @param handle handle of the GNS connection to stop
695  */
696 void
697 GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle)
698 {
699   GNUNET_CLIENT_disconnect (handle->client);
700   if (GNUNET_SCHEDULER_NO_TASK != handle->reconnect_task)
701   {
702     GNUNET_SCHEDULER_cancel (handle->reconnect_task);
703     handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
704   }
705   GNUNET_assert (NULL == handle->lookup_head);
706   GNUNET_assert (NULL == handle->shorten_head);
707   GNUNET_assert (NULL == handle->get_auth_head);
708   GNUNET_free (handle);
709 }
710
711
712 /**
713  * Cancel pending lookup request
714  *
715  * @param lr the lookup request to cancel
716  */
717 void
718 GNUNET_GNS_cancel_lookup_request (struct GNUNET_GNS_LookupRequest *lr)
719 {
720   struct PendingMessage *p = (struct PendingMessage*) &lr[1];
721
722   GNUNET_assert (NULL != lr->gns_handle); 
723   if (GNUNET_NO == p->transmitted)
724     GNUNET_CONTAINER_DLL_remove (lr->gns_handle->pending_head,
725                                  lr->gns_handle->pending_tail,
726                                  p);
727   GNUNET_CONTAINER_DLL_remove (lr->gns_handle->lookup_head,
728                                lr->gns_handle->lookup_tail,
729                                lr);
730   GNUNET_free (lr);
731 }
732
733
734 /**
735  * Cancel pending shorten request
736  *
737  * @param sr the lookup request to cancel
738  */
739 void
740 GNUNET_GNS_cancel_shorten_request (struct GNUNET_GNS_ShortenRequest *sr)
741 {
742   struct PendingMessage *p = (struct PendingMessage*) &sr[1];
743
744   GNUNET_assert (NULL != sr->gns_handle);
745   if (GNUNET_NO == p->transmitted)
746     GNUNET_CONTAINER_DLL_remove (sr->gns_handle->pending_head,
747                                  sr->gns_handle->pending_tail,
748                                  p);
749   GNUNET_CONTAINER_DLL_remove (sr->gns_handle->shorten_head,
750                                sr->gns_handle->shorten_tail,
751                                sr);
752   GNUNET_free (sr);
753 }
754
755
756 /**
757  * Cancel pending get auth  request
758  *
759  * @param gar the lookup request to cancel
760  */
761 void
762 GNUNET_GNS_cancel_get_auth_request (struct GNUNET_GNS_GetAuthRequest *gar)
763 {
764   struct PendingMessage *p = (struct PendingMessage*) &gar[1];
765
766   GNUNET_assert (NULL != gar->gns_handle); 
767   if (GNUNET_NO == p->transmitted)
768     GNUNET_CONTAINER_DLL_remove (gar->gns_handle->pending_head,
769                                  gar->gns_handle->pending_tail,
770                                  p);  
771   GNUNET_CONTAINER_DLL_remove (gar->gns_handle->get_auth_head,
772                                gar->gns_handle->get_auth_tail,
773                                gar);
774   GNUNET_free (gar);
775 }
776
777
778 /**
779  * Perform an asynchronous Lookup operation on the GNS.
780  *
781  * @param handle handle to the GNS service
782  * @param name the name to look up
783  * @param zone the zone to start the resolution in
784  * @param type the record type to look up
785  * @param only_cached GNUNET_YES to only check locally not DHT for performance
786  * @param shorten_key the private key of the shorten zone (can be NULL)
787  * @param proc processor to call on result
788  * @param proc_cls closure for processor
789  * @return handle to the get request
790  */
791 struct GNUNET_GNS_LookupRequest*
792 GNUNET_GNS_lookup_zone (struct GNUNET_GNS_Handle *handle,
793                         const char *name,
794                         struct GNUNET_CRYPTO_ShortHashCode *zone,
795                         enum GNUNET_GNS_RecordType type,
796                         int only_cached,
797                         struct GNUNET_CRYPTO_RsaPrivateKey *shorten_key,
798                         GNUNET_GNS_LookupResultProcessor proc,
799                         void *proc_cls)
800 {
801   /* IPC to shorten gns names, return shorten_handle */
802   struct GNUNET_GNS_ClientLookupMessage *lookup_msg;
803   struct GNUNET_GNS_LookupRequest *lr;
804   size_t msize;
805   struct PendingMessage *pending;
806   struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *pkey_enc;
807   size_t key_len;
808   char* pkey_tmp;
809
810   if (NULL == name)
811   {
812     GNUNET_break (0);
813     return NULL;
814   } 
815   if (NULL != shorten_key)
816   {
817     pkey_enc = GNUNET_CRYPTO_rsa_encode_key (shorten_key);
818     GNUNET_assert (pkey_enc != NULL);
819     key_len = ntohs (pkey_enc->len);
820   }
821   else
822   {
823     pkey_enc = NULL;
824     key_len = 0;
825   }
826   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
827               "Trying to lookup `%s' in GNS\n", 
828               name);
829   msize = sizeof (struct GNUNET_GNS_ClientLookupMessage)
830     + key_len + strlen (name) + 1;
831   if (msize > UINT16_MAX)
832   {
833     GNUNET_break (0);
834     return NULL;
835   }
836   lr = GNUNET_malloc (sizeof (struct GNUNET_GNS_LookupRequest) +
837                       sizeof (struct PendingMessage) + msize);
838   lr->gns_handle = handle;
839   lr->lookup_proc = proc;
840   lr->proc_cls = proc_cls;
841   lr->r_id = handle->r_id++;
842   pending = (struct PendingMessage *)&lr[1];
843   pending->size = msize;
844   pending->r_id = lr->r_id;
845   GNUNET_CONTAINER_DLL_insert_tail (handle->lookup_head,
846                                     handle->lookup_tail, lr);
847
848   lookup_msg = (struct GNUNET_GNS_ClientLookupMessage *) &pending[1];
849   lookup_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_LOOKUP);
850   lookup_msg->header.size = htons (msize);
851   lookup_msg->id = htonl (lr->r_id);
852   lookup_msg->only_cached = htonl (only_cached);
853   if (NULL != zone)
854   {
855     lookup_msg->use_default_zone = htonl (GNUNET_NO);
856     memcpy (&lookup_msg->zone, zone, sizeof (struct GNUNET_CRYPTO_ShortHashCode));
857   }
858   else
859   {
860     lookup_msg->use_default_zone = htonl (GNUNET_YES);
861     memset (&lookup_msg->zone, 0, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
862   }  
863   lookup_msg->type = htonl (type);
864   pkey_tmp = (char *) &lookup_msg[1];  
865   if (pkey_enc != NULL)
866   {
867     lookup_msg->have_key = htonl (GNUNET_YES);
868     memcpy (pkey_tmp, pkey_enc, key_len);
869   }
870   else
871     lookup_msg->have_key = htonl (GNUNET_NO);
872   GNUNET_free_non_null (pkey_enc);
873   memcpy (&pkey_tmp[key_len], name, strlen (name) + 1);
874
875   GNUNET_CONTAINER_DLL_insert_tail (handle->pending_head,
876                                     handle->pending_tail,
877                                     pending);
878   process_pending_messages (handle);
879   return lr;
880 }
881
882
883 /**
884  * Perform an asynchronous Lookup operation on the GNS.
885  *
886  * @param handle handle to the GNS service
887  * @param name the name to look up
888  * @param type the record type to look up
889  * @param only_cached GNUNET_YES to only check locally not DHT for performance
890  * @param shorten_key the private key of the shorten zone (can be NULL)
891  * @param proc processor to call on result
892  * @param proc_cls closure for processor
893  * @return handle to the lookup request
894  */
895 struct GNUNET_GNS_LookupRequest*
896 GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle,
897                    const char *name,
898                    enum GNUNET_GNS_RecordType type,
899                    int only_cached,
900                    struct GNUNET_CRYPTO_RsaPrivateKey *shorten_key,
901                    GNUNET_GNS_LookupResultProcessor proc,
902                    void *proc_cls)
903 {
904   return GNUNET_GNS_lookup_zone (handle, name,
905                                  NULL,
906                                  type, only_cached,
907                                  shorten_key,
908                                  proc, proc_cls);
909 }
910
911
912 /**
913  * Perform a name shortening operation on the GNS.
914  *
915  * @param handle handle to the GNS service
916  * @param name the name to look up
917  * @param private_zone the public zone of the private zone
918  * @param shorten_zone the public zone of the shorten zone
919  * @param zone the zone to start the resolution in
920  * @param proc function to call on result
921  * @param proc_cls closure for processor
922  * @return handle to the operation
923  */
924 struct GNUNET_GNS_ShortenRequest*
925 GNUNET_GNS_shorten_zone (struct GNUNET_GNS_Handle *handle,
926                          const char *name,
927                          struct GNUNET_CRYPTO_ShortHashCode *private_zone,
928                          struct GNUNET_CRYPTO_ShortHashCode *shorten_zone,
929                          struct GNUNET_CRYPTO_ShortHashCode *zone,
930                          GNUNET_GNS_ShortenResultProcessor proc,
931                          void *proc_cls)
932 {
933   /* IPC to shorten gns names, return shorten_handle */
934   struct GNUNET_GNS_ClientShortenMessage *shorten_msg;
935   struct GNUNET_GNS_ShortenRequest *sr;
936   size_t msize;
937   struct PendingMessage *pending;
938
939   if (NULL == name)
940   {
941     GNUNET_break (0);
942     return NULL;
943   }
944   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to shorten `%s' in GNS\n", name);
945   msize = sizeof (struct GNUNET_GNS_ClientShortenMessage) + strlen (name) + 1;
946   if (msize > UINT16_MAX)
947   {
948     GNUNET_break (0);
949     return NULL;
950   }
951   sr = GNUNET_malloc (sizeof (struct GNUNET_GNS_ShortenRequest) +
952                       sizeof (struct PendingMessage) + msize);
953   sr->gns_handle = handle;
954   sr->shorten_proc = proc;
955   sr->proc_cls = proc_cls;
956   sr->r_id = handle->r_id++;
957   GNUNET_CONTAINER_DLL_insert_tail (handle->shorten_head,
958                                     handle->shorten_tail, sr);
959   pending = (struct PendingMessage *)&sr[1];
960   pending->size = msize;
961   pending->r_id = sr->r_id;
962
963   shorten_msg = (struct GNUNET_GNS_ClientShortenMessage *) &pending[1];
964   shorten_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_SHORTEN);
965   shorten_msg->header.size = htons ((uint16_t) msize);
966   shorten_msg->id = htonl (sr->r_id);
967   shorten_msg->private_zone = *private_zone;
968   shorten_msg->shorten_zone = *shorten_zone;  
969   if (NULL != zone)
970   {
971     shorten_msg->use_default_zone = htonl (GNUNET_NO);
972     memcpy (&shorten_msg->zone, zone,
973             sizeof (struct GNUNET_CRYPTO_ShortHashCode));
974   }
975   else
976   {
977     shorten_msg->use_default_zone = htonl (GNUNET_YES);
978     memset (&shorten_msg->zone, 0, sizeof (struct GNUNET_CRYPTO_ShortHashCode));
979   } 
980   memcpy (&shorten_msg[1], name, strlen (name) + 1);
981   GNUNET_CONTAINER_DLL_insert_tail (handle->pending_head, handle->pending_tail,
982                                pending);  
983   process_pending_messages (handle);
984   return sr;
985 }
986
987
988 /**
989  * Perform a name shortening operation on the GNS.
990  *
991  * @param handle handle to the GNS service
992  * @param name the name to look up
993  * @param private_zone the public zone of the private zone
994  * @param shorten_zone the public zone of the shorten zone
995  * @param proc function to call on result
996  * @param proc_cls closure for processor
997  * @return handle to the operation
998  */
999 struct GNUNET_GNS_ShortenRequest*
1000 GNUNET_GNS_shorten (struct GNUNET_GNS_Handle *handle,
1001                     const char *name,
1002                     struct GNUNET_CRYPTO_ShortHashCode *private_zone,
1003                     struct GNUNET_CRYPTO_ShortHashCode *shorten_zone,
1004                     GNUNET_GNS_ShortenResultProcessor proc,
1005                     void *proc_cls)
1006 {
1007   return GNUNET_GNS_shorten_zone (handle, name,
1008                                   private_zone, shorten_zone,
1009                                   NULL, proc, proc_cls);
1010 }
1011
1012
1013 /**
1014  * Perform an authority lookup for a given name.
1015  *
1016  * @param handle handle to the GNS service
1017  * @param name the name to look up authority for
1018  * @param proc function to call on result
1019  * @param proc_cls closure for processor
1020  * @return handle to the operation
1021  */
1022 struct GNUNET_GNS_GetAuthRequest*
1023 GNUNET_GNS_get_authority (struct GNUNET_GNS_Handle *handle,
1024                           const char *name,
1025                           GNUNET_GNS_GetAuthResultProcessor proc,
1026                           void *proc_cls)
1027 {
1028   struct GNUNET_GNS_ClientGetAuthMessage *get_auth_msg;
1029   struct GNUNET_GNS_GetAuthRequest *gar;
1030   size_t msize;
1031   struct PendingMessage *pending;
1032
1033   if (NULL == name)
1034   {
1035     GNUNET_break (0);
1036     return NULL;
1037   }
1038   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1039               "Trying to look up authority for %s in GNS\n", name);
1040   msize = sizeof (struct GNUNET_GNS_ClientGetAuthMessage) + strlen (name) + 1;
1041   if (msize > UINT16_MAX)
1042   {
1043     GNUNET_break (0);
1044     return NULL;
1045   }
1046   gar = GNUNET_malloc (sizeof (struct GNUNET_GNS_GetAuthRequest) +
1047                        sizeof (struct PendingMessage) + msize);
1048   gar->gns_handle = handle;
1049   gar->auth_proc = proc;
1050   gar->proc_cls = proc_cls;
1051   gar->r_id = handle->r_id++;
1052   GNUNET_CONTAINER_DLL_insert_tail (handle->get_auth_head,
1053                                     handle->get_auth_tail, gar);
1054
1055   pending = (struct PendingMessage *) &gar[1];
1056   pending->size = msize;
1057   pending->r_id = gar->r_id;
1058   get_auth_msg = (struct GNUNET_GNS_ClientGetAuthMessage *) &pending[1];
1059   get_auth_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_GET_AUTH);
1060   get_auth_msg->header.size = htons (msize);
1061   get_auth_msg->id = htonl (gar->r_id);
1062   memcpy (&get_auth_msg[1], name, strlen (name) + 1);
1063   GNUNET_CONTAINER_DLL_insert_tail (handle->pending_head, 
1064                                     handle->pending_tail,
1065                                     pending);
1066   process_pending_messages (handle);
1067   return gar;
1068 }
1069
1070
1071 /* end of gns_api.c */