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