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