-coverity
[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  * A QueueEntry.
48  */
49 struct GNUNET_GNS_QueueEntry
50 {
51   /**
52    * DLL
53    */
54   struct GNUNET_GNS_QueueEntry *next;
55   
56   /**
57    * DLL
58    */
59   struct GNUNET_GNS_QueueEntry *prev;
60
61   /* request id */
62   uint32_t r_id;
63   
64   /* handle to gns */
65   struct GNUNET_GNS_Handle *gns_handle;
66   
67   /* processor to call on shorten result */
68   GNUNET_GNS_ShortenResultProcessor shorten_proc;
69   
70   /* processor to call on lookup result */
71   GNUNET_GNS_LookupResultProcessor lookup_proc;
72
73   /* processor to call on authority lookup result */
74   GNUNET_GNS_GetAuthResultProcessor auth_proc;
75   
76   /* processor closure */
77   void *proc_cls;
78   
79 };
80
81
82 /**
83  * Entry in our list of messages to be (re-)transmitted.
84  */
85 struct PendingMessage
86 {
87   /**
88    * This is a doubly-linked list.
89    */
90   struct PendingMessage *prev;
91
92   /**
93    * This is a doubly-linked list.
94    */
95   struct PendingMessage *next;
96
97   /**
98    * Size of the message.
99    */
100   size_t size;
101
102 };
103
104
105 /**
106  * Connection to the GNS service.
107  */
108 struct GNUNET_GNS_Handle
109 {
110
111   /**
112    * Configuration to use.
113    */
114   const struct GNUNET_CONFIGURATION_Handle *cfg;
115
116   /**
117    * Socket (if available).
118    */
119   struct GNUNET_CLIENT_Connection *client;
120
121   /**
122    * Currently pending transmission request (or NULL).
123    */
124   struct GNUNET_CLIENT_TransmitHandle *th;
125   
126   uint32_t r_id;
127   
128   /**
129    * Head of linked list of shorten messages we would like to transmit.
130    */
131   struct PendingMessage *pending_head;
132
133   /**
134    * Tail of linked list of shorten messages we would like to transmit.
135    */
136   struct PendingMessage *pending_tail;
137   
138   /**
139    * Head of linked list of shorten messages we would like to transmit.
140    */
141   struct GNUNET_GNS_QueueEntry *shorten_head;
142
143   /**
144    * Tail of linked list of shorten messages we would like to transmit.
145    */
146   struct GNUNET_GNS_QueueEntry *shorten_tail;
147   
148   /**
149    * Head of linked list of lookup messages we would like to transmit.
150    */
151   struct GNUNET_GNS_QueueEntry *lookup_head;
152
153   /**
154    * Tail of linked list of lookup messages we would like to transmit.
155    */
156   struct GNUNET_GNS_QueueEntry *lookup_tail;
157   
158   /**
159    * Head of linked list of authority lookup messages we would like to transmit.
160    */
161   struct GNUNET_GNS_QueueEntry *get_auth_head;
162
163   /**
164    * Tail of linked list of authority lookup messages we would like to transmit.
165    */
166   struct GNUNET_GNS_QueueEntry *get_auth_tail;
167
168   /**
169    * Reconnect task
170    */
171   GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
172
173   /**
174    * Did we start our receive loop yet?
175    */
176   int in_receive;
177
178   /**
179    * Reconnect necessary
180    */
181   int reconnect;
182 };
183
184 /**
185  * Try to send messages from list of messages to send
186  * @param handle GNS_Handle
187  */
188 static void
189 process_pending_messages (struct GNUNET_GNS_Handle *handle);
190
191
192 /**
193  * Reconnect to GNS service.
194  *
195  * @param h the handle to the namestore service
196  */
197 static void
198 reconnect (struct GNUNET_GNS_Handle *h)
199 {
200   GNUNET_assert (NULL == h->client);
201   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
202              "Trying to connect to GNS...\n");
203   h->client = GNUNET_CLIENT_connect ("gns", h->cfg);
204   GNUNET_assert (NULL != h->client);
205 }
206
207 /**
208  * Reconnect to GNS
209  *
210  * @param cls the handle
211  * @param tc task context
212  */
213 static void
214 reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
215 {
216   struct GNUNET_GNS_Handle *h = cls;
217
218   h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
219   reconnect (h);
220 }
221
222
223 /**
224  * Disconnect from service and then reconnect.
225  *
226  * @param h our handle
227  */
228 static void
229 force_reconnect (struct GNUNET_GNS_Handle *h)
230 {
231   h->reconnect = GNUNET_NO;
232   GNUNET_CLIENT_disconnect (h->client);
233   h->client = NULL;
234   h->reconnect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
235                                                     &reconnect_task,
236                                                     h);
237 }
238
239 /**
240  * Transmit the next pending message, called by notify_transmit_ready
241  */
242 static size_t
243 transmit_pending (void *cls, size_t size, void *buf);
244
245 /**
246  * Handler for messages received from the GNS service
247  *
248  * @param cls the 'struct GNUNET_GNS_Handle'
249  * @param msg the incoming message
250  */
251 static void
252 process_message (void *cls, const struct GNUNET_MessageHeader *msg);
253
254 /**
255  * Try to send messages from list of messages to send
256  */
257 static void
258 process_pending_messages (struct GNUNET_GNS_Handle *handle)
259 {
260   struct PendingMessage *p;
261
262   if (handle->client == NULL)
263   {
264     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
265          "process_pending_messages called, but client is null\n");
266     return;
267   }
268   
269   if (handle->th != NULL)
270     return;
271   
272   if (NULL == (p = handle->pending_head))
273     return;
274   
275   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
276              "Trying to transmit %d bytes...\n", p->size);
277
278   handle->th =
279     GNUNET_CLIENT_notify_transmit_ready (handle->client,
280                                          p->size,
281                                          GNUNET_TIME_UNIT_FOREVER_REL,
282                                          GNUNET_NO, &transmit_pending,
283                                          handle);
284   if (NULL != handle->th)
285     return;
286
287   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
288               "notify_transmit_ready returned NULL!\n");
289 }
290
291
292 /**
293  * Transmit the next pending message, called by notify_transmit_ready
294  */
295 static size_t
296 transmit_pending (void *cls, size_t size, void *buf)
297 {
298   struct GNUNET_GNS_Handle *handle = cls;
299   struct PendingMessage *p;
300   size_t tsize;
301   char *cbuf;
302
303   handle->th = NULL;
304   
305   if ((size == 0) || (buf == NULL))
306   {
307     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
308          "Transmission to GNS service failed!\n");
309     force_reconnect(handle);
310     return 0;
311   }
312   
313   tsize = 0;
314   cbuf = buf;
315
316   if (NULL == (p = handle->pending_head))
317     return 0;
318
319   while ((NULL != (p = handle->pending_head)) && (p->size <= size))
320   {
321     memcpy (&cbuf[tsize], &p[1], p->size);
322     tsize += p->size;
323     size -= p->size;
324     GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail, p);
325     if (GNUNET_YES != handle->in_receive)
326     {
327       GNUNET_CLIENT_receive (handle->client, &process_message, handle,
328                              GNUNET_TIME_UNIT_FOREVER_REL);
329       handle->in_receive = GNUNET_YES;
330     }
331     GNUNET_free(p);
332   }
333
334   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
335               "Sending %d bytes\n", tsize);
336
337   process_pending_messages(handle);
338   return tsize;
339 }
340
341 /**
342  * Process a given reply that might match the given
343  * request.
344  *
345  * @param qe a queue entry
346  * @param msg the shorten msg received
347  */
348 static void
349 process_shorten_reply (struct GNUNET_GNS_QueueEntry *qe,
350                        const struct GNUNET_GNS_ClientShortenResultMessage *msg)
351 {
352   struct GNUNET_GNS_Handle *h = qe->gns_handle;
353   const char *short_name;
354
355   GNUNET_CONTAINER_DLL_remove(h->shorten_head, h->shorten_tail, qe);
356
357   short_name = (char*)(&msg[1]);
358
359   if (ntohs (((struct GNUNET_MessageHeader*)msg)->size) <
360       sizeof (struct GNUNET_GNS_ClientShortenResultMessage))
361   {
362     GNUNET_break (0);
363     force_reconnect (h);
364     GNUNET_free(qe);
365     return;
366   }
367   
368   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
369               "Received shortened reply `%s' from GNS service\n",
370               short_name);
371   
372   GNUNET_CLIENT_receive (h->client, &process_message, h,
373                          GNUNET_TIME_UNIT_FOREVER_REL);
374   qe->shorten_proc(qe->proc_cls, short_name);
375   GNUNET_free(qe);
376
377 }
378
379
380 /**
381  * Process a given reply that might match the given
382  * request.
383  *
384  * @param qe the handle to the request
385  * @param msg the message to process
386  */
387 static void
388 process_get_auth_reply (struct GNUNET_GNS_QueueEntry *qe,
389                        const struct GNUNET_GNS_ClientGetAuthResultMessage *msg)
390 {
391   struct GNUNET_GNS_Handle *h = qe->gns_handle;
392   const char *auth_name;
393
394   GNUNET_CONTAINER_DLL_remove(h->get_auth_head, h->get_auth_tail, qe);
395
396   auth_name = (char*)(&msg[1]);
397
398   if (ntohs (((struct GNUNET_MessageHeader*)msg)->size) <
399       sizeof (struct GNUNET_GNS_ClientGetAuthResultMessage))
400   {
401     GNUNET_free(qe);
402     GNUNET_break (0);
403     force_reconnect (h);
404     return;
405   }
406   
407   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
408               "Received GET_AUTH reply `%s' from GNS service\n",
409               auth_name);
410   
411   GNUNET_CLIENT_receive (h->client, &process_message, h,
412                          GNUNET_TIME_UNIT_FOREVER_REL);
413   qe->auth_proc(qe->proc_cls, auth_name);
414   GNUNET_free(qe);
415
416 }
417 /**
418  * Process a given reply to the lookup request
419  *
420  * @param qe a queue entry
421  * @param msg the lookup message received
422  */
423 static void
424 process_lookup_reply (struct GNUNET_GNS_QueueEntry *qe,
425                       const struct GNUNET_GNS_ClientLookupResultMessage *msg)
426 {
427   struct GNUNET_GNS_Handle *h = qe->gns_handle;
428   int rd_count = ntohl(msg->rd_count);
429   size_t len = ntohs (((struct GNUNET_MessageHeader*)msg)->size);
430   struct GNUNET_NAMESTORE_RecordData rd[rd_count];
431
432   GNUNET_CONTAINER_DLL_remove(h->lookup_head, h->lookup_tail, qe);
433
434   if (len < sizeof (struct GNUNET_GNS_ClientLookupResultMessage))
435   {
436     GNUNET_free(qe);
437     GNUNET_break (0);
438     force_reconnect (h);
439     return;
440   }
441
442   len -= sizeof(struct GNUNET_GNS_ClientLookupResultMessage);
443
444   GNUNET_CLIENT_receive (h->client, &process_message, h,
445                          GNUNET_TIME_UNIT_FOREVER_REL);
446   if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (len,
447                                                              (char*)&msg[1],
448                                                              rd_count,
449                                                              rd))
450   {
451     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
452                 "Failed to serialize lookup reply from GNS service!\n");
453     qe->lookup_proc(qe->proc_cls, 0, NULL);
454   }
455   else
456   {
457   
458     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
459                 "Received lookup reply from GNS service (count=%d)\n",
460                 ntohl(msg->rd_count));
461     qe->lookup_proc(qe->proc_cls, rd_count, rd);
462   }
463   GNUNET_free(qe);
464 }
465
466 /**
467  * Handler for messages received from the GNS service
468  *
469  * @param cls the 'struct GNUNET_GNS_Handle'
470  * @param msg the incoming message
471  */
472 static void
473 process_message (void *cls, const struct GNUNET_MessageHeader *msg)
474 {
475   struct GNUNET_GNS_Handle *handle = cls;
476   struct GNUNET_GNS_QueueEntry *qe;
477   const struct GNUNET_GNS_ClientLookupResultMessage *lookup_msg;
478   const struct GNUNET_GNS_ClientShortenResultMessage *shorten_msg;
479   const struct GNUNET_GNS_ClientGetAuthResultMessage *get_auth_msg;
480   uint16_t type;
481   uint32_t r_id;
482   
483   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
484               "Got message\n");
485   if (msg == NULL)
486   {
487     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
488          "Error receiving data from GNS service, reconnecting\n");
489     force_reconnect (handle);
490     return;
491   }
492
493   type = ntohs (msg->type);
494
495   if (type == GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT)
496   {
497     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
498                 "Got lookup msg\n");
499     lookup_msg = (const struct GNUNET_GNS_ClientLookupResultMessage *) msg;
500     r_id = ntohl (lookup_msg->id);
501     
502     if (r_id > handle->r_id)
503     {
504       /** no request found */
505       GNUNET_break_op (0);
506       GNUNET_CLIENT_receive (handle->client, &process_message, handle,
507                              GNUNET_TIME_UNIT_FOREVER_REL);
508       return;
509     }
510
511     for (qe = handle->lookup_head; qe != NULL; qe = qe->next)
512     {
513       if (qe->r_id == r_id)
514         break;
515     }
516     if (qe)
517       process_lookup_reply(qe, lookup_msg);
518     
519     return;
520
521   }
522   else if (type == GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT)
523   {
524     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
525                 "Got SHORTEN_RESULT msg\n");
526     shorten_msg = (struct GNUNET_GNS_ClientShortenResultMessage *) msg;
527     
528     r_id = ntohl (shorten_msg->id);
529     
530     if (r_id > handle->r_id)
531     {
532       /** no request found */
533       GNUNET_break_op (0);
534       GNUNET_CLIENT_receive (handle->client, &process_message, handle,
535                              GNUNET_TIME_UNIT_FOREVER_REL);
536       return;
537     }
538
539     for (qe = handle->shorten_head; qe != NULL; qe = qe->next)
540     {
541       if (qe->r_id == r_id)
542         break;
543     }
544     if (qe)
545       process_shorten_reply(qe, shorten_msg);
546     return;
547   }
548   else if (type == GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT)
549   {
550     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
551                 "Got GET_AUTH_RESULT msg\n");
552     get_auth_msg = (struct GNUNET_GNS_ClientGetAuthResultMessage *) msg;
553
554     r_id = ntohl (get_auth_msg->id);
555
556     if (r_id > handle->r_id)
557     {
558       /** no request found */
559       GNUNET_break_op (0);
560       GNUNET_CLIENT_receive (handle->client, &process_message, handle,
561                              GNUNET_TIME_UNIT_FOREVER_REL);
562       return;
563     }
564
565     for (qe = handle->get_auth_head; qe != NULL; qe = qe->next)
566     {
567       if (qe->r_id == r_id)
568         break;
569     }
570     if (qe)
571       process_get_auth_reply(qe, get_auth_msg);
572     return;
573   }
574
575
576   if (GNUNET_YES == handle->reconnect)
577     force_reconnect (handle);
578   
579 }
580
581
582 /**
583  * Initialize the connection with the GNS service.
584  *
585  * @param cfg configuration to use
586  * @return handle to the GNS service, or NULL on error
587  */
588 struct GNUNET_GNS_Handle *
589 GNUNET_GNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
590 {
591   struct GNUNET_GNS_Handle *handle;
592
593   handle = GNUNET_malloc (sizeof (struct GNUNET_GNS_Handle));
594   handle->reconnect = GNUNET_NO;
595   handle->cfg = cfg;
596   reconnect (handle);
597   //handle->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect_task, handle);
598   handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
599   handle->r_id = 0;
600   handle->in_receive = GNUNET_NO;
601   return handle;
602 }
603
604
605 /**
606  * Shutdown connection with the GNS service.
607  *
608  * @param handle handle of the GNS connection to stop
609  */
610 void
611 GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle)
612 {
613   GNUNET_CLIENT_disconnect (handle->client);
614   if (GNUNET_SCHEDULER_NO_TASK != handle->reconnect_task)
615   {
616     GNUNET_SCHEDULER_cancel (handle->reconnect_task);
617     handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
618   }
619   GNUNET_free(handle);
620   /* disco from GNS */
621 }
622
623 /*
624  * Helper function to generate request ids
625  * 
626  * @param h handle
627  * @return a new id
628  */
629 static uint32_t
630 get_request_id (struct GNUNET_GNS_Handle *h)
631 {
632   uint32_t r_id = h->r_id;
633   h->r_id++;
634   return r_id;
635 }
636
637 /**
638  * Perform an asynchronous Lookup operation on the GNS.
639  *
640  * @param handle handle to the GNS service
641  * @param name the name to look up
642  * @param zone the zone to start the resolution in
643  * @param type the record type to look up
644  * @param only_cached GNUNET_NO to only check locally not DHT for performance
645  * @param shorten_key the private key of the shorten zone (can be NULL)
646  * @param proc processor to call on result
647  * @param proc_cls closure for processor
648  * @return handle to the get
649  */
650 struct GNUNET_GNS_QueueEntry *
651 GNUNET_GNS_lookup_zone (struct GNUNET_GNS_Handle *handle,
652                    const char * name,
653                    struct GNUNET_CRYPTO_ShortHashCode *zone,
654                    enum GNUNET_GNS_RecordType type,
655                    int only_cached,
656                    struct GNUNET_CRYPTO_RsaPrivateKey *shorten_key,
657                    GNUNET_GNS_LookupResultProcessor proc,
658                    void *proc_cls)
659 {
660   /* IPC to shorten gns names, return shorten_handle */
661   struct GNUNET_GNS_ClientLookupMessage *lookup_msg;
662   struct GNUNET_GNS_QueueEntry *qe;
663   size_t msize;
664   struct PendingMessage *pending;
665   struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *pkey_enc=NULL;
666   size_t key_len = 0;
667   char* pkey_tmp;
668
669   if (NULL == name)
670   {
671     return NULL;
672   }
673   
674   if (NULL != shorten_key)
675   {
676     pkey_enc = GNUNET_CRYPTO_rsa_encode_key (shorten_key);
677     GNUNET_assert (pkey_enc != NULL);
678     key_len = ntohs (pkey_enc->len);
679   }
680
681   msize = sizeof (struct GNUNET_GNS_ClientLookupMessage)
682     + key_len + strlen(name) + 1;
683   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to lookup %s in GNS\n", name);
684
685   qe = GNUNET_malloc(sizeof (struct GNUNET_GNS_QueueEntry));
686   qe->gns_handle = handle;
687   qe->lookup_proc = proc;
688   qe->proc_cls = proc_cls;
689   qe->r_id = get_request_id(handle);
690   GNUNET_CONTAINER_DLL_insert_tail(handle->lookup_head,
691                                    handle->lookup_tail, qe);
692
693   pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
694   memset(pending, 0, (sizeof (struct PendingMessage) + msize));
695   
696   pending->size = msize;
697
698   lookup_msg = (struct GNUNET_GNS_ClientLookupMessage *) &pending[1];
699   lookup_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_LOOKUP);
700   lookup_msg->header.size = htons (msize);
701   lookup_msg->id = htonl(qe->r_id);
702   lookup_msg->only_cached = htonl(only_cached);
703
704   if (NULL != zone)
705   {
706     lookup_msg->use_default_zone = htonl(0);
707     memcpy(&lookup_msg->zone, zone, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
708   }
709   else
710   {
711     lookup_msg->use_default_zone = htonl(1);
712     memset(&lookup_msg->zone, 0, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
713   }
714   
715   lookup_msg->type = htonl(type);
716
717   pkey_tmp = (char *) &lookup_msg[1];
718   
719   if (pkey_enc != NULL)
720   {
721     lookup_msg->have_key = htonl(1);
722     memcpy(pkey_tmp, pkey_enc, key_len);
723   }
724   else
725     lookup_msg->have_key = htonl(0);
726
727   memcpy(&pkey_tmp[key_len], name, strlen(name));
728
729   GNUNET_CONTAINER_DLL_insert_tail (handle->pending_head, handle->pending_tail,
730                                pending);
731   GNUNET_free_non_null (pkey_enc);
732   process_pending_messages (handle);
733   return qe;
734 }
735
736 /**
737  * Perform an asynchronous Lookup operation on the GNS.
738  *
739  * @param handle handle to the GNS service
740  * @param name the name to look up
741  * @param type the record type to look up
742  * @param only_cached GNUNET_NO to only check locally not DHT for performance
743  * @param shorten_key the private key of the shorten zone (can be NULL)
744  * @param proc processor to call on result
745  * @param proc_cls closure for processor
746  * @return handle to the get
747  */
748 struct GNUNET_GNS_QueueEntry *
749 GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle,
750                    const char * name,
751                    enum GNUNET_GNS_RecordType type,
752                    int only_cached,
753                    struct GNUNET_CRYPTO_RsaPrivateKey *shorten_key,
754                    GNUNET_GNS_LookupResultProcessor proc,
755                    void *proc_cls)
756 {
757   return GNUNET_GNS_lookup_zone (handle, name,
758                                  NULL,
759                                  type, only_cached,
760                                  shorten_key,
761                                  proc, proc_cls);
762 }
763
764 /**
765  * Perform a name shortening operation on the GNS.
766  *
767  * @param handle handle to the GNS service
768  * @param name the name to look up
769  * @param zone the zone to start the resolution in
770  * @param proc function to call on result
771  * @param proc_cls closure for processor
772  * @return handle to the operation
773  */
774 struct GNUNET_GNS_QueueEntry *
775 GNUNET_GNS_shorten_zone (struct GNUNET_GNS_Handle *handle,
776                     const char * name,
777                     struct GNUNET_CRYPTO_ShortHashCode *zone,
778                     GNUNET_GNS_ShortenResultProcessor proc,
779                     void *proc_cls)
780 {
781   /* IPC to shorten gns names, return shorten_handle */
782   struct GNUNET_GNS_ClientShortenMessage *shorten_msg;
783   struct GNUNET_GNS_QueueEntry *qe;
784   size_t msize;
785   struct PendingMessage *pending;
786
787   if (NULL == name)
788   {
789     return NULL;
790   }
791
792   msize = sizeof (struct GNUNET_GNS_ClientShortenMessage) + strlen(name) + 1;
793   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to shorten %s in GNS\n", name);
794
795   qe = GNUNET_malloc(sizeof (struct GNUNET_GNS_QueueEntry));
796   qe->gns_handle = handle;
797   qe->shorten_proc = proc;
798   qe->proc_cls = proc_cls;
799   qe->r_id = get_request_id(handle);
800   GNUNET_CONTAINER_DLL_insert_tail(handle->shorten_head,
801                                    handle->shorten_tail, qe);
802
803   pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
804   memset(pending, 0, (sizeof (struct PendingMessage) + msize));
805   
806   pending->size = msize;
807
808   shorten_msg = (struct GNUNET_GNS_ClientShortenMessage *) &pending[1];
809   shorten_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_SHORTEN);
810   shorten_msg->header.size = htons (msize);
811   shorten_msg->id = htonl(qe->r_id);
812   
813   if (NULL != zone)
814   {
815     shorten_msg->use_default_zone = htonl(0);
816     memcpy(&shorten_msg->zone, zone,
817            sizeof(struct GNUNET_CRYPTO_ShortHashCode));
818   }
819   else
820   {
821     shorten_msg->use_default_zone = htonl(1);
822     memset(&shorten_msg->zone, 0, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
823   }
824   
825   memcpy(&shorten_msg[1], name, strlen(name));
826
827   GNUNET_CONTAINER_DLL_insert_tail (handle->pending_head, handle->pending_tail,
828                                pending);
829   
830   process_pending_messages (handle);
831   return qe;
832 }
833
834 /**
835  * Perform a name shortening operation on the GNS.
836  *
837  * @param handle handle to the GNS service
838  * @param name the name to look up
839  * @param proc function to call on result
840  * @param proc_cls closure for processor
841  * @return handle to the operation
842  */
843 struct GNUNET_GNS_QueueEntry *
844 GNUNET_GNS_shorten (struct GNUNET_GNS_Handle *handle,
845                     const char * name,
846                     GNUNET_GNS_ShortenResultProcessor proc,
847                     void *proc_cls)
848 {
849   return GNUNET_GNS_shorten_zone (handle, name, NULL, proc, proc_cls);
850 }
851 /**
852  * Perform an authority lookup for a given name.
853  *
854  * @param handle handle to the GNS service
855  * @param name the name to look up authority for
856  * @param proc function to call on result
857  * @param proc_cls closure for processor
858  * @return handle to the operation
859  */
860 struct GNUNET_GNS_QueueEntry *
861 GNUNET_GNS_get_authority (struct GNUNET_GNS_Handle *handle,
862                     const char * name,
863                     GNUNET_GNS_GetAuthResultProcessor proc,
864                     void *proc_cls)
865 {
866   struct GNUNET_GNS_ClientGetAuthMessage *get_auth_msg;
867   struct GNUNET_GNS_QueueEntry *qe;
868   size_t msize;
869   struct PendingMessage *pending;
870
871   if (NULL == name)
872   {
873     return NULL;
874   }
875
876   msize = sizeof (struct GNUNET_GNS_ClientGetAuthMessage) + strlen(name) + 1;
877   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
878               "Trying to look up authority for %s in GNS\n", name);
879
880   qe = GNUNET_malloc(sizeof (struct GNUNET_GNS_QueueEntry));
881   qe->gns_handle = handle;
882   qe->auth_proc = proc;
883   qe->proc_cls = proc_cls;
884   qe->r_id = get_request_id(handle);
885   GNUNET_CONTAINER_DLL_insert_tail(handle->get_auth_head,
886                                    handle->get_auth_tail, qe);
887
888   pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
889   memset(pending, 0, (sizeof (struct PendingMessage) + msize));
890   
891   pending->size = msize;
892
893   get_auth_msg = (struct GNUNET_GNS_ClientGetAuthMessage *) &pending[1];
894   get_auth_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_GET_AUTH);
895   get_auth_msg->header.size = htons (msize);
896   get_auth_msg->id = htonl(qe->r_id);
897
898   memcpy(&get_auth_msg[1], name, strlen(name));
899
900   GNUNET_CONTAINER_DLL_insert_tail (handle->pending_head, handle->pending_tail,
901                                pending);
902   
903   process_pending_messages (handle);
904   return qe;
905 }
906
907
908 /* end of gns_api.c */