-lookup now works in test, removed dns hijack from defaults
[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
44 /**
45  * A QueueEntry.
46  */
47 struct GNUNET_GNS_QueueEntry
48 {
49   /**
50    * DLL
51    */
52   struct GNUNET_GNS_QueueEntry *next;
53   
54   /**
55    * DLL
56    */
57   struct GNUNET_GNS_QueueEntry *prev;
58
59   /* request id */
60   uint32_t r_id;
61   
62   /* handle to gns */
63   struct GNUNET_GNS_Handle *gns_handle;
64   
65   /* processor to call on shorten result */
66   GNUNET_GNS_ShortenResultProcessor shorten_proc;
67   
68   /* processor to call on lookup result */
69   GNUNET_GNS_LookupResultProcessor lookup_proc;
70   
71   /* processor closure */
72   void *proc_cls;
73   
74 };
75
76
77 /**
78  * Entry in our list of messages to be (re-)transmitted.
79  */
80 struct PendingMessage
81 {
82   /**
83    * This is a doubly-linked list.
84    */
85   struct PendingMessage *prev;
86
87   /**
88    * This is a doubly-linked list.
89    */
90   struct PendingMessage *next;
91
92   /**
93    * Size of the message.
94    */
95   size_t size;
96
97 };
98
99
100 /**
101  * Connection to the GNS service.
102  */
103 struct GNUNET_GNS_Handle
104 {
105
106   /**
107    * Configuration to use.
108    */
109   const struct GNUNET_CONFIGURATION_Handle *cfg;
110
111   /**
112    * Socket (if available).
113    */
114   struct GNUNET_CLIENT_Connection *client;
115
116   /**
117    * Currently pending transmission request (or NULL).
118    */
119   struct GNUNET_CLIENT_TransmitHandle *th;
120   
121   uint32_t r_id;
122   
123   /**
124    * Head of linked list of shorten messages we would like to transmit.
125    */
126   struct PendingMessage *pending_head;
127
128   /**
129    * Tail of linked list of shorten messages we would like to transmit.
130    */
131   struct PendingMessage *pending_tail;
132   
133   /**
134    * Head of linked list of shorten messages we would like to transmit.
135    */
136   struct GNUNET_GNS_QueueEntry *shorten_head;
137
138   /**
139    * Tail of linked list of shorten messages we would like to transmit.
140    */
141   struct GNUNET_GNS_QueueEntry *shorten_tail;
142   
143   /**
144    * Head of linked list of lookup messages we would like to transmit.
145    */
146   struct GNUNET_GNS_QueueEntry *lookup_head;
147
148   /**
149    * Tail of linked list of lookup messages we would like to transmit.
150    */
151   struct GNUNET_GNS_QueueEntry *lookup_tail;
152   
153   /**
154    * Reconnect task
155    */
156   GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
157
158   /**
159    * Did we start our receive loop yet?
160    */
161   int in_receive;
162
163   /**
164    * Reconnect necessary
165    */
166   int reconnect;
167 };
168
169 /**
170  * Try to send messages from list of messages to send
171  * @param handle GNS_Handle
172  */
173 static void
174 process_pending_messages (struct GNUNET_GNS_Handle *handle);
175
176
177 /**
178  * Reconnect to GNS service.
179  *
180  * @param h the handle to the namestore service
181  */
182 static void
183 reconnect (struct GNUNET_GNS_Handle *h)
184 {
185   GNUNET_assert (NULL == h->client);
186   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
187              "Trying to connect to GNS...\n");
188   h->client = GNUNET_CLIENT_connect ("gns", h->cfg);
189   GNUNET_assert (NULL != h->client);
190 }
191
192 /**
193  * Reconnect to GNS
194  *
195  * @param cls the handle
196  * @param tc task context
197  */
198 static void
199 reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
200 {
201   struct GNUNET_GNS_Handle *h = cls;
202
203   h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
204   reconnect (h);
205 }
206
207
208 /**
209  * Disconnect from service and then reconnect.
210  *
211  * @param h our handle
212  */
213 static void
214 force_reconnect (struct GNUNET_GNS_Handle *h)
215 {
216   h->reconnect = GNUNET_NO;
217   GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
218   h->client = NULL;
219   h->reconnect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
220                                                     &reconnect_task,
221                                                     h);
222 }
223
224 /**
225  * Transmit the next pending message, called by notify_transmit_ready
226  */
227 static size_t
228 transmit_pending (void *cls, size_t size, void *buf);
229
230 /**
231  * Handler for messages received from the GNS service
232  *
233  * @param cls the 'struct GNUNET_GNS_Handle'
234  * @param msg the incoming message
235  */
236 static void
237 process_message (void *cls, const struct GNUNET_MessageHeader *msg);
238
239 /**
240  * Try to send messages from list of messages to send
241  */
242 static void
243 process_pending_messages (struct GNUNET_GNS_Handle *handle)
244 {
245   struct PendingMessage *p;
246
247   if (handle->client == NULL)
248   {
249     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
250          "process_pending_messages called, but client is null\n");
251     return;
252   }
253   
254   if (handle->th != NULL)
255     return;
256   
257   if (NULL == (p = handle->pending_head))
258     return;
259   
260   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
261              "Trying to transmit %d bytes...\n", p->size);
262
263   handle->th =
264     GNUNET_CLIENT_notify_transmit_ready (handle->client,
265                                          p->size,
266                                          GNUNET_TIME_UNIT_FOREVER_REL,
267                                          GNUNET_NO, &transmit_pending,
268                                          handle);
269   if (NULL != handle->th)
270     return;
271
272   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
273               "notify_transmit_ready returned NULL!\n");
274 }
275
276
277 /**
278  * Transmit the next pending message, called by notify_transmit_ready
279  */
280 static size_t
281 transmit_pending (void *cls, size_t size, void *buf)
282 {
283   struct GNUNET_GNS_Handle *handle = cls;
284   struct PendingMessage *p;
285   size_t tsize;
286   char *cbuf;
287
288   handle->th = NULL;
289   
290   if ((size == 0) || (buf == NULL))
291   {
292     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
293          "Transmission to GNS service failed!\n");
294     force_reconnect(handle);
295     return 0;
296   }
297   
298   tsize = 0;
299   cbuf = buf;
300
301   if (NULL == (p = handle->pending_head))
302     return 0;
303
304   while ((NULL != (p = handle->pending_head)) && (p->size <= size))
305   {
306     memcpy (&cbuf[tsize], &p[1], p->size);
307     tsize += p->size;
308     size -= p->size;
309     GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail, p);
310     if (GNUNET_YES != handle->in_receive)
311     {
312       GNUNET_CLIENT_receive (handle->client, &process_message, handle,
313                              GNUNET_TIME_UNIT_FOREVER_REL);
314       handle->in_receive = GNUNET_YES;
315     }
316     GNUNET_free(p);
317   }
318
319   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
320               "Sending %d bytes\n", tsize);
321
322   process_pending_messages(handle);
323   return tsize;
324 }
325
326 /**
327  * Process a given reply that might match the given
328  * request.
329  *
330  * @param cls the 'struct GNUNET_GNS_ClientResultMessage'
331  * @param key query of the request
332  * @param value the 'struct GNUNET_GNS_LookupHandle' of a request matching the same key
333  */
334 static void
335 process_shorten_reply (struct GNUNET_GNS_QueueEntry *qe,
336                        const struct GNUNET_GNS_ClientShortenResultMessage *msg)
337 {
338   struct GNUNET_GNS_Handle *h = qe->gns_handle;
339   const char *short_name;
340
341   GNUNET_CONTAINER_DLL_remove(h->shorten_head, h->shorten_tail, qe);
342
343   short_name = (char*)(&msg[1]);
344
345   if (ntohs (((struct GNUNET_MessageHeader*)msg)->size) <
346       sizeof (struct GNUNET_GNS_ClientShortenResultMessage))
347   {
348     GNUNET_break (0);
349     force_reconnect (h);
350     return;
351   }
352   
353   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
354               "Received shortened reply `%s' from GNS service\n",
355               short_name);
356   
357   qe->shorten_proc(qe->proc_cls, short_name);
358
359 }
360
361
362 /**
363  * Process a given reply to the lookup request
364  *
365  * @param cls the 'struct GNUNET_GNS_ClientResultMessage'
366  * @param key query of the request
367  * @param value the 'struct GNUNET_GNS_LookupHandle' of a request matching the same key
368  * @return GNUNET_YES to continue to iterate over all results,
369  *         GNUNET_NO if the reply is malformed
370  */
371 static void
372 process_lookup_reply (struct GNUNET_GNS_QueueEntry *qe,
373                       const struct GNUNET_GNS_ClientLookupResultMessage *msg)
374 {
375   struct GNUNET_GNS_Handle *h = qe->gns_handle;
376   int rd_count = ntohl(msg->rd_count);
377   size_t len = ntohs (((struct GNUNET_MessageHeader*)msg)->size);
378   struct GNUNET_NAMESTORE_RecordData rd[rd_count];
379
380   GNUNET_CONTAINER_DLL_remove(h->lookup_head, h->lookup_tail, qe);
381
382   if (len < sizeof (struct GNUNET_GNS_ClientLookupResultMessage))
383   {
384     GNUNET_break (0);
385     force_reconnect (h);
386     return;
387   }
388
389   len -= sizeof(struct GNUNET_GNS_ClientLookupResultMessage);
390
391   GNUNET_NAMESTORE_records_deserialize (len, (char*)&msg[1],
392                                         rd_count,
393                                         rd);
394   
395   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
396               "Received lookup reply from GNS service (count=%d)\n",
397               ntohl(msg->rd_count));
398   
399   qe->lookup_proc(qe->proc_cls, rd_count, rd);
400 }
401
402 /**
403  * Handler for messages received from the GNS service
404  *
405  * @param cls the 'struct GNUNET_GNS_Handle'
406  * @param msg the incoming message
407  */
408 static void
409 process_message (void *cls, const struct GNUNET_MessageHeader *msg)
410 {
411   struct GNUNET_GNS_Handle *handle = cls;
412   struct GNUNET_GNS_QueueEntry *qe;
413   const struct GNUNET_GNS_ClientLookupResultMessage *lookup_msg;
414   const struct GNUNET_GNS_ClientShortenResultMessage *shorten_msg;
415   uint16_t size;
416   uint16_t type;
417   uint32_t r_id;
418   
419   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
420               "Got message\n");
421   if (msg == NULL)
422   {
423     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
424          "Error receiving data from GNS service, reconnecting\n");
425     force_reconnect (handle);
426     return;
427   }
428
429   size = ntohs (msg->size);
430   type = ntohs (msg->type);
431
432   if (type == GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT)
433   {
434     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
435                 "Got lookup msg\n");
436     lookup_msg = (const struct GNUNET_GNS_ClientLookupResultMessage *) msg;
437     r_id = ntohl (lookup_msg->id);
438     
439     if (r_id > handle->r_id)
440     {
441       /** no request found */
442       GNUNET_break_op (0);
443       GNUNET_CLIENT_receive (handle->client, &process_message, handle,
444                              GNUNET_TIME_UNIT_FOREVER_REL);
445     }
446
447     for (qe = handle->lookup_head; qe != NULL; qe = qe->next)
448     {
449       if (qe->r_id == r_id)
450         break;
451     }
452     if (qe)
453       process_lookup_reply(qe, lookup_msg);
454
455
456   }
457   else if (type == GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT)
458   {
459     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
460                 "Got shorten msg\n");
461     shorten_msg = (struct GNUNET_GNS_ClientShortenResultMessage *) msg;
462     
463     r_id = ntohl (shorten_msg->id);
464     
465     if (r_id > handle->r_id)
466     {
467       /** no request found */
468       GNUNET_break_op (0);
469       GNUNET_CLIENT_receive (handle->client, &process_message, handle,
470                              GNUNET_TIME_UNIT_FOREVER_REL);
471     }
472
473     for (qe = handle->shorten_head; qe != NULL; qe = qe->next)
474     {
475       if (qe->r_id == r_id)
476         break;
477     }
478     if (qe)
479       process_shorten_reply(qe, shorten_msg);
480   }
481
482   GNUNET_CLIENT_receive (handle->client, &process_message, handle,
483                          GNUNET_TIME_UNIT_FOREVER_REL);
484
485   if (GNUNET_YES == handle->reconnect)
486     force_reconnect (handle);
487   
488 }
489
490
491 /**
492  * Initialize the connection with the GNS service.
493  *
494  * @param cfg configuration to use
495  * @param ht_len size of the internal hash table to use for parallel requests
496  * @return handle to the GNS service, or NULL on error
497  */
498 struct GNUNET_GNS_Handle *
499 GNUNET_GNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
500 {
501   struct GNUNET_GNS_Handle *handle;
502
503   handle = GNUNET_malloc (sizeof (struct GNUNET_GNS_Handle));
504   handle->cfg = cfg;
505   reconnect (handle);
506   //handle->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect_task, handle);
507   handle->r_id = 0;
508   handle->in_receive = GNUNET_NO;
509   return handle;
510 }
511
512
513 /**
514  * Shutdown connection with the GNS service.
515  *
516  * @param handle handle of the GNS connection to stop
517  */
518 void
519 GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle)
520 {
521   /* disco from GNS */
522 }
523
524 /*
525  * Helper function to generate request ids
526  * 
527  * @param h handle
528  * @return a new id
529  */
530 static uint32_t
531 get_request_id (struct GNUNET_GNS_Handle *h)
532 {
533   uint32_t r_id = h->r_id;
534   h->r_id++;
535   return r_id;
536 }
537
538 /**
539  * Perform an asynchronous Lookup operation on the GNS.
540  *
541  * @param handle handle to the GNS service
542  * @param name the name to look up
543  * @param iter function to call on each result
544  * @param iter_cls closure for iter
545  * @return handle to stop the async get
546  */
547 struct GNUNET_GNS_QueueEntry *
548 GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle,
549                    const char * name,
550                    enum GNUNET_GNS_RecordType type,
551                    GNUNET_GNS_LookupResultProcessor proc,
552                    void *proc_cls)
553 {
554   /* IPC to shorten gns names, return shorten_handle */
555   struct GNUNET_GNS_ClientLookupMessage *lookup_msg;
556   struct GNUNET_GNS_QueueEntry *qe;
557   size_t msize;
558   struct PendingMessage *pending;
559
560   if (NULL == name)
561   {
562     return NULL;
563   }
564
565   msize = sizeof (struct GNUNET_GNS_ClientLookupMessage) + strlen(name) + 1;
566   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to shorten %s in GNS\n", name);
567
568   qe = GNUNET_malloc(sizeof (struct GNUNET_GNS_QueueEntry));
569   qe->gns_handle = handle;
570   qe->lookup_proc = proc;
571   qe->proc_cls = proc_cls;
572   qe->r_id = get_request_id(handle);
573   GNUNET_CONTAINER_DLL_insert_tail(handle->lookup_head,
574                                    handle->lookup_tail, qe);
575
576   pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
577   memset(pending, 0, (sizeof (struct PendingMessage) + msize));
578   
579   pending->size = msize;
580
581   lookup_msg = (struct GNUNET_GNS_ClientLookupMessage *) &pending[1];
582   lookup_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_LOOKUP);
583   lookup_msg->header.size = htons (msize);
584   lookup_msg->id = htonl(qe->r_id);
585   lookup_msg->type = htonl(type);
586
587   memcpy(&lookup_msg[1], name, strlen(name));
588
589   GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail,
590                                pending);
591   
592   process_pending_messages (handle);
593   return qe;
594 }
595
596
597 /**
598  * Perform a name shortening operation on the GNS.
599  *
600  * @param handle handle to the GNS service
601  * @param name the name to look up
602  * @param proc function to call on result
603  * @param proc_cls closure for processor
604  * @return handle to the operation
605  */
606 struct GNUNET_GNS_QueueEntry *
607 GNUNET_GNS_shorten (struct GNUNET_GNS_Handle *handle,
608                     const char * name,
609                     GNUNET_GNS_ShortenResultProcessor proc,
610                     void *proc_cls)
611 {
612   /* IPC to shorten gns names, return shorten_handle */
613   struct GNUNET_GNS_ClientShortenMessage *shorten_msg;
614   struct GNUNET_GNS_QueueEntry *qe;
615   size_t msize;
616   struct PendingMessage *pending;
617
618   if (NULL == name)
619   {
620     return NULL;
621   }
622
623   msize = sizeof (struct GNUNET_GNS_ClientShortenMessage) + strlen(name) + 1;
624   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to shorten %s in GNS\n", name);
625
626   qe = GNUNET_malloc(sizeof (struct GNUNET_GNS_QueueEntry));
627   qe->gns_handle = handle;
628   qe->shorten_proc = proc;
629   qe->proc_cls = proc_cls;
630   qe->r_id = get_request_id(handle);
631   GNUNET_CONTAINER_DLL_insert_tail(handle->shorten_head,
632                                    handle->shorten_tail, qe);
633
634   pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
635   memset(pending, 0, (sizeof (struct PendingMessage) + msize));
636   
637   pending->size = msize;
638
639   shorten_msg = (struct GNUNET_GNS_ClientShortenMessage *) &pending[1];
640   shorten_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_SHORTEN);
641   shorten_msg->header.size = htons (msize);
642   shorten_msg->id = htonl(qe->r_id);
643
644   memcpy(&shorten_msg[1], name, strlen(name));
645
646   GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail,
647                                pending);
648   
649   process_pending_messages (handle);
650   return qe;
651 }
652
653
654
655 /* end of gns_api.c */