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