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