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