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