use the asynchronous DNS resolution API (getaddrinfo_a) in the resolver module
[oweals/gnunet.git] / src / util / resolver_api.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009-2018 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14     
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /**
20  * @file util/resolver_api.c
21  * @brief resolver for writing a tool
22  * @author Christian Grothoff
23  */
24 #include "platform.h"
25 #include "gnunet_util_lib.h"
26 #include "gnunet_protocols.h"
27 #include "gnunet_resolver_service.h"
28 #include "resolver.h"
29
30 #define LOG(kind,...) GNUNET_log_from (kind, "util-resolver-api", __VA_ARGS__)
31
32 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-resolver-api", syscall)
33
34 /**
35  * Maximum supported length for a hostname
36  */
37 #define MAX_HOSTNAME 1024
38
39
40 /**
41  * Possible hostnames for "loopback".
42  */
43 static const char *loopback[] = {
44   "localhost",
45   "ip6-localnet",
46   NULL
47 };
48
49
50 /**
51  * Configuration.
52  */
53 static const struct GNUNET_CONFIGURATION_Handle *resolver_cfg;
54
55 /**
56  * Our connection to the resolver service, created on-demand, but then
57  * persists until error or shutdown.
58  */
59 static struct GNUNET_MQ_Handle *mq;
60
61 /**
62  * Head of DLL of requests.
63  */
64 static struct GNUNET_RESOLVER_RequestHandle *req_head;
65
66 /**
67  * Tail of DLL of requests.
68  */
69 static struct GNUNET_RESOLVER_RequestHandle *req_tail;
70
71 /**
72  * ID of the last request we sent to the service
73  */
74 static uint32_t last_request_id;
75
76 /**
77  * How long should we wait to reconnect?
78  */
79 static struct GNUNET_TIME_Relative backoff;
80
81 /**
82  * Task for reconnecting.
83  */
84 static struct GNUNET_SCHEDULER_Task *r_task;
85
86 /**
87  * Task ID of shutdown task; only present while we have a
88  * connection to the resolver service.
89  */
90 static struct GNUNET_SCHEDULER_Task *s_task;
91
92
93 /**
94  * Handle to a request given to the resolver.  Can be used to cancel
95  * the request prior to the timeout or successful execution.  Also
96  * used to track our internal state for the request.
97  */
98 struct GNUNET_RESOLVER_RequestHandle
99 {
100
101   /**
102    * Next entry in DLL of requests.
103    */
104   struct GNUNET_RESOLVER_RequestHandle *next;
105
106   /**
107    * Previous entry in DLL of requests.
108    */
109   struct GNUNET_RESOLVER_RequestHandle *prev;
110
111   /**
112    * Callback if this is an name resolution request,
113    * otherwise NULL.
114    */
115   GNUNET_RESOLVER_AddressCallback addr_callback;
116
117   /**
118    * Callback if this is a reverse lookup request,
119    * otherwise NULL.
120    */
121   GNUNET_RESOLVER_HostnameCallback name_callback;
122
123   /**
124    * Closure for the callbacks.
125    */
126   void *cls;
127
128   /**
129    * When should this request time out?
130    */
131   struct GNUNET_TIME_Absolute timeout;
132
133   /**
134    * Task handle for making reply callbacks in numeric lookups
135    * asynchronous, and for timeout handling.
136    */
137   struct GNUNET_SCHEDULER_Task *task;
138
139   /**
140    * Desired address family.
141    */
142   int af;
143
144   /**
145    * Identifies the request. The response will contain this id.
146    */
147   uint32_t id;
148
149   /**
150    * Has this request been transmitted to the service?
151    * #GNUNET_YES if transmitted
152    * #GNUNET_YES if not transmitted
153    * #GNUNET_SYSERR when request was canceled
154    */
155   int was_transmitted;
156
157   /**
158    * Did we add this request to the queue?
159    */
160   int was_queued;
161
162   /**
163    * Desired direction (IP to name or name to IP)
164    */
165   int direction;
166
167   /**
168    * #GNUNET_YES if a response was received
169    */
170   int received_response;
171
172   /**
173    * Length of the data that follows this struct.
174    */
175   size_t data_len;
176 };
177
178
179 /**
180  * Check that the resolver service runs on localhost
181  * (or equivalent).
182  *
183  * @return #GNUNET_OK if the resolver is properly configured,
184  *         #GNUNET_SYSERR otherwise.
185  */
186 static int
187 check_config ()
188 {
189   char *hostname;
190   struct sockaddr_in v4;
191   struct sockaddr_in6 v6;
192
193   if (GNUNET_OK ==
194       GNUNET_CONFIGURATION_have_value (resolver_cfg,
195                                        "resolver",
196                                        "UNIXPATH"))
197     return GNUNET_OK;
198   memset (&v4, 0, sizeof (v4));
199   v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
200   v4.sin_family = AF_INET;
201 #if HAVE_SOCKADDR_IN_SIN_LEN
202   v4.sin_len = sizeof (v4);
203 #endif
204   memset (&v6, 0, sizeof (v6));
205   v6.sin6_family = AF_INET6;
206 #if HAVE_SOCKADDR_IN_SIN_LEN
207   v6.sin6_len = sizeof (v6);
208 #endif
209   if (GNUNET_OK !=
210       GNUNET_CONFIGURATION_get_value_string (resolver_cfg,
211                                              "resolver",
212                                              "HOSTNAME",
213                                              &hostname))
214   {
215     LOG (GNUNET_ERROR_TYPE_INFO,
216          _("Missing `%s' for `%s' in configuration, DNS resolution will be unavailable.\n"),
217          "HOSTNAME",
218          "resolver");
219     return GNUNET_SYSERR;
220   }
221   if ( (1 == inet_pton (AF_INET, hostname, &v4)) ||
222        (1 == inet_pton (AF_INET6, hostname, &v6)) )
223   {
224     GNUNET_free (hostname);
225     return GNUNET_OK;
226   }
227   for (unsigned int i = 0;
228        NULL != loopback[i];
229        i++)
230     if (0 == strcasecmp (loopback[i],
231                          hostname))
232     {
233       GNUNET_free (hostname);
234       return GNUNET_OK;
235     }
236   LOG (GNUNET_ERROR_TYPE_INFO,
237        _("Missing `%s' or numeric IP address for `%s' of `%s' in configuration, DNS resolution will be unavailable.\n"),
238        "localhost",
239        "HOSTNAME",
240        "resolver");
241   GNUNET_free (hostname);
242   return GNUNET_SYSERR;
243 }
244
245
246 /**
247  * Create the connection to the resolver service.
248  *
249  * @param cfg configuration to use
250  */
251 void
252 GNUNET_RESOLVER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
253 {
254   GNUNET_assert (NULL != cfg);
255   backoff = GNUNET_TIME_UNIT_MILLISECONDS;
256   resolver_cfg = cfg;
257 }
258
259
260 /**
261  * Destroy the connection to the resolver service.
262  */
263 void
264 GNUNET_RESOLVER_disconnect ()
265 {
266   struct GNUNET_RESOLVER_RequestHandle *rh;
267
268   while (NULL != (rh = req_head))
269   {
270     GNUNET_assert (GNUNET_SYSERR == rh->was_transmitted);
271     GNUNET_CONTAINER_DLL_remove (req_head,
272                                  req_tail,
273                                  rh);
274     GNUNET_free (rh);
275   }
276   if (NULL != mq)
277   {
278     LOG (GNUNET_ERROR_TYPE_DEBUG,
279          "Disconnecting from DNS service\n");
280     GNUNET_MQ_destroy (mq);
281     mq = NULL;
282   }
283   if (NULL != r_task)
284   {
285     GNUNET_SCHEDULER_cancel (r_task);
286     r_task = NULL;
287   }
288   if (NULL != s_task)
289   {
290     GNUNET_SCHEDULER_cancel (s_task);
291     s_task = NULL;
292   }
293 }
294
295
296 /**
297  * Task executed on system shutdown.
298  */
299 static void
300 shutdown_task (void *cls)
301 {
302   (void) cls;
303   s_task = NULL;
304   GNUNET_RESOLVER_disconnect ();
305   backoff = GNUNET_TIME_UNIT_MILLISECONDS;
306 }
307
308
309 /**
310  * Consider disconnecting if we have no further requests pending.
311  */
312 static void
313 check_disconnect ()
314 {
315   for (struct GNUNET_RESOLVER_RequestHandle *rh = req_head;
316        NULL != rh;
317        rh = rh->next)
318     if (GNUNET_SYSERR != rh->was_transmitted)
319       return;
320   if (NULL != r_task)
321   {
322     GNUNET_SCHEDULER_cancel (r_task);
323     r_task = NULL;
324   }
325   if (NULL != s_task)
326     return;
327   s_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
328                                          &shutdown_task,
329                                          NULL);
330 }
331
332
333 /**
334  * Convert IP address to string without DNS resolution.
335  *
336  * @param af address family
337  * @param ip the address
338  * @param ip_len number of bytes in @a ip
339  * @return address as a string, NULL on error
340  */
341 static char *
342 no_resolve (int af,
343             const void *ip,
344             socklen_t ip_len)
345 {
346   char buf[INET6_ADDRSTRLEN];
347
348   switch (af)
349   {
350   case AF_INET:
351     if (ip_len != sizeof (struct in_addr))
352       return NULL;
353     if (NULL ==
354         inet_ntop (AF_INET,
355                    ip,
356                    buf,
357                    sizeof (buf)))
358     {
359       LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
360                     "inet_ntop");
361       return NULL;
362     }
363     break;
364   case AF_INET6:
365     if (ip_len != sizeof (struct in6_addr))
366       return NULL;
367     if (NULL ==
368         inet_ntop (AF_INET6,
369                    ip,
370                    buf,
371                    sizeof (buf)))
372     {
373       LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
374                     "inet_ntop");
375       return NULL;
376     }
377     break;
378   default:
379     GNUNET_break (0);
380     return NULL;
381   }
382   return GNUNET_strdup (buf);
383 }
384
385
386 /**
387  * Adjust exponential back-off and reconnect to the service.
388  */
389 static void
390 reconnect (void);
391
392
393 /**
394  * Generic error handler, called with the appropriate error code and
395  * the same closure specified at the creation of the message queue.
396  * Not every message queue implementation supports an error handler.
397  *
398  * @param cls NULL
399  * @param error error code
400  */
401 static void
402 mq_error_handler (void *cls,
403                   enum GNUNET_MQ_Error error)
404 {
405   (void) cls;
406   GNUNET_MQ_destroy (mq);
407   mq = NULL;
408   LOG (GNUNET_ERROR_TYPE_DEBUG,
409        "MQ error %d, reconnecting\n",
410        error);
411   reconnect ();
412 }
413
414
415 /**
416  * Process pending requests to the resolver.
417  */
418 static void
419 process_requests ()
420 {
421   struct GNUNET_RESOLVER_GetMessage *msg;
422   struct GNUNET_MQ_Envelope *env;
423   struct GNUNET_RESOLVER_RequestHandle *rh = req_head;
424
425   if (NULL == mq)
426   {
427     reconnect ();
428     return;
429   }
430   if (NULL == rh)
431   {
432     /* nothing to do, release socket really soon if there is nothing
433      * else happening... */
434     if (NULL == s_task)
435       s_task =
436         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
437                                       &shutdown_task,
438                                       NULL);
439     return;
440   }
441   if (GNUNET_NO != rh->was_transmitted)
442     return;                     /* waiting for reply */
443   env = GNUNET_MQ_msg_extra (msg,
444                              rh->data_len,
445                              GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
446   msg->direction = htonl (rh->direction);
447   msg->af = htonl (rh->af);
448   msg->id = htonl (rh->id);
449   GNUNET_memcpy (&msg[1],
450                  &rh[1],
451                  rh->data_len);
452   LOG (GNUNET_ERROR_TYPE_DEBUG,
453        "Transmitting DNS resolution request (ID %u) to DNS service\n",
454        rh->id);
455   GNUNET_MQ_send (mq,
456                   env);
457   rh->was_transmitted = GNUNET_YES;
458 }
459
460
461 /**
462  * Check validity of response with a hostname for a DNS lookup.
463  *
464  * @param cls NULL
465  * @param msg message with the hostname
466  */
467 static int
468 check_response (void *cls,
469                 const struct GNUNET_RESOLVER_ResponseMessage *msg)
470 {
471   (void) cls;
472   (void) msg;
473
474   /* implemented in #handle_response() for now */
475   return GNUNET_OK;
476 }
477
478
479 /**
480  * Check validity of response with a hostname for a DNS lookup.
481  * NOTE: right now rather messy, might want to use different
482  * message types for different response formats in the future.
483  *
484  * @param cls NULL
485  * @param msg message with the response
486  */
487 static void
488 handle_response (void *cls,
489                  const struct GNUNET_RESOLVER_ResponseMessage *msg)
490 {
491   struct GNUNET_RESOLVER_RequestHandle *rh = req_head;
492   uint16_t size;
493   char *nret;
494   uint32_t request_id = msg->id;
495
496   for (; rh != NULL; rh = rh->next)
497   {
498     if (rh->id == request_id)
499       break;
500   }
501
502   (void) cls;
503   if (NULL == rh)
504   {
505     /* Resolver service sent extra replies to query (after terminator)? Bad! */
506     GNUNET_break (0);
507     GNUNET_MQ_destroy (mq);
508     mq = NULL;
509     reconnect ();
510     return;
511   }
512   size = ntohs (msg->header.size);
513   if (size == sizeof (struct GNUNET_RESOLVER_ResponseMessage))
514   {
515     LOG (GNUNET_ERROR_TYPE_DEBUG,
516          "Received empty response from DNS service\n");
517     /* message contains not data, just header; end of replies */
518     /* check if request was canceled */
519     if (GNUNET_SYSERR != rh->was_transmitted)
520     {
521       /* no reverse lookup was successful, return IP as string */
522       if (NULL != rh->name_callback)
523       {
524         if (GNUNET_NO == rh->received_response)
525         {
526           nret = no_resolve (rh->af,
527                              &rh[1],
528                              rh->data_len);
529           rh->name_callback (rh->cls, nret);
530           GNUNET_free (nret);
531         }
532         /* finally, make termination call */
533         if (GNUNET_SYSERR != rh->was_transmitted)
534           rh->name_callback (rh->cls,
535                              NULL);
536       }
537       if ( (NULL != rh->addr_callback) &&
538            (GNUNET_SYSERR != rh->was_transmitted) )
539           rh->addr_callback (rh->cls,
540                              NULL,
541                              0);
542     }
543     rh->was_transmitted = GNUNET_NO;
544     GNUNET_RESOLVER_request_cancel (rh);
545     process_requests ();
546     return;
547   }
548   /* return reverse lookup results to caller */
549   if (NULL != rh->name_callback)
550   {
551     const char *hostname;
552
553     hostname = (const char *) &msg[1];
554     if (hostname[size - sizeof (struct GNUNET_RESOLVER_ResponseMessage) - 1] != '\0')
555     {
556       GNUNET_break (0);
557       if (GNUNET_SYSERR != rh->was_transmitted)
558         rh->name_callback (rh->cls,
559                            NULL);
560       rh->was_transmitted = GNUNET_NO;
561       GNUNET_RESOLVER_request_cancel (rh);
562       GNUNET_MQ_destroy (mq);
563       mq = NULL;
564       reconnect ();
565       return;
566     }
567     LOG (GNUNET_ERROR_TYPE_DEBUG,
568          "Resolver returns `%s' for IP `%s'.\n",
569          hostname,
570          GNUNET_a2s ((const void *) &rh[1],
571                      rh->data_len));
572     if (rh->was_transmitted != GNUNET_SYSERR)
573       rh->name_callback (rh->cls,
574                          hostname);
575     rh->received_response = GNUNET_YES;
576   }
577   /* return lookup results to caller */
578   if (NULL != rh->addr_callback)
579   {
580     struct sockaddr_in v4;
581     struct sockaddr_in6 v6;
582     const struct sockaddr *sa;
583     socklen_t salen;
584     const void *ip;
585     size_t ip_len;
586
587     ip = &msg[1];
588     ip_len = size - sizeof (struct GNUNET_RESOLVER_ResponseMessage);
589     if (ip_len == sizeof (struct in_addr))
590     {
591       memset (&v4, 0, sizeof (v4));
592       v4.sin_family = AF_INET;
593       v4.sin_addr = *(struct in_addr*) ip;
594 #if HAVE_SOCKADDR_IN_SIN_LEN
595       v4.sin_len = sizeof (v4);
596 #endif
597       salen = sizeof (v4);
598       sa = (const struct sockaddr *) &v4;
599     }
600     else if (ip_len == sizeof (struct in6_addr))
601     {
602       memset (&v6, 0, sizeof (v6));
603       v6.sin6_family = AF_INET6;
604       v6.sin6_addr = *(struct in6_addr*) ip;
605 #if HAVE_SOCKADDR_IN_SIN_LEN
606       v6.sin6_len = sizeof (v6);
607 #endif
608       salen = sizeof (v6);
609       sa = (const struct sockaddr *) &v6;
610     }
611     else
612     {
613       GNUNET_break (0);
614       if (GNUNET_SYSERR != rh->was_transmitted)
615         rh->addr_callback (rh->cls,
616                            NULL,
617                            0);
618       rh->was_transmitted = GNUNET_NO;
619       GNUNET_RESOLVER_request_cancel (rh);
620       GNUNET_MQ_destroy (mq);
621       mq = NULL;
622       reconnect ();
623       return;
624     }
625     LOG (GNUNET_ERROR_TYPE_DEBUG,
626          "Received IP from DNS service\n");
627     if (GNUNET_SYSERR != rh->was_transmitted)
628       rh->addr_callback (rh->cls,
629                          sa,
630                          salen);
631   }
632 }
633
634
635 /**
636  * We've been asked to lookup the address for a hostname and were
637  * given a valid numeric string.  Perform the callbacks for the
638  * numeric addresses.
639  *
640  * @param cls `struct GNUNET_RESOLVER_RequestHandle` for the request
641  */
642 static void
643 numeric_resolution (void *cls)
644 {
645   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
646   struct sockaddr_in v4;
647   struct sockaddr_in6 v6;
648   const char *hostname;
649
650   rh->task = NULL;
651   memset (&v4, 0, sizeof (v4));
652   v4.sin_family = AF_INET;
653 #if HAVE_SOCKADDR_IN_SIN_LEN
654   v4.sin_len = sizeof (v4);
655 #endif
656   memset (&v6, 0, sizeof (v6));
657   v6.sin6_family = AF_INET6;
658 #if HAVE_SOCKADDR_IN_SIN_LEN
659   v6.sin6_len = sizeof (v6);
660 #endif
661   hostname = (const char *) &rh[1];
662   if ( ( (rh->af == AF_UNSPEC) ||
663          (rh->af == AF_INET) ) &&
664        (1 == inet_pton (AF_INET,
665                         hostname,
666                         &v4.sin_addr)) )
667   {
668     rh->addr_callback (rh->cls,
669                        (const struct sockaddr *) &v4,
670                        sizeof (v4));
671     if ( (rh->af == AF_UNSPEC) &&
672          (GNUNET_SYSERR != rh->was_transmitted) &&
673          (1 == inet_pton (AF_INET6,
674                           hostname,
675                           &v6.sin6_addr)) )
676     {
677       /* this can happen on some systems IF "hostname" is "localhost" */
678       rh->addr_callback (rh->cls,
679                          (const struct sockaddr *) &v6,
680                          sizeof (v6));
681     }
682     if (GNUNET_SYSERR != rh->was_transmitted)
683       rh->addr_callback (rh->cls,
684                          NULL,
685                          0);
686     GNUNET_free (rh);
687     return;
688   }
689   if ( ( (rh->af == AF_UNSPEC) ||
690          (rh->af == AF_INET6) ) &&
691        (1 == inet_pton (AF_INET6,
692                         hostname,
693                         &v6.sin6_addr) ) )
694   {
695     rh->addr_callback (rh->cls,
696                        (const struct sockaddr *) &v6,
697                        sizeof (v6));
698     if (GNUNET_SYSERR != rh->was_transmitted)
699       rh->addr_callback (rh->cls,
700                          NULL,
701                          0);
702     GNUNET_free (rh);
703     return;
704   }
705   /* why are we here? this task should not have been scheduled! */
706   GNUNET_assert (0);
707   GNUNET_free (rh);
708 }
709
710
711 /**
712  * We've been asked to lookup the address for a hostname and were
713  * given a variant of "loopback".  Perform the callbacks for the
714  * respective loopback numeric addresses.
715  *
716  * @param cls `struct GNUNET_RESOLVER_RequestHandle` for the request
717  */
718 static void
719 loopback_resolution (void *cls)
720 {
721   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
722   struct sockaddr_in v4;
723   struct sockaddr_in6 v6;
724
725   rh->task = NULL;
726   memset (&v4, 0, sizeof (v4));
727   v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
728   v4.sin_family = AF_INET;
729 #if HAVE_SOCKADDR_IN_SIN_LEN
730   v4.sin_len = sizeof (v4);
731 #endif
732   memset (&v6, 0, sizeof (v6));
733   v6.sin6_family = AF_INET6;
734 #if HAVE_SOCKADDR_IN_SIN_LEN
735   v6.sin6_len = sizeof (v6);
736 #endif
737   v6.sin6_addr = in6addr_loopback;
738   switch (rh->af)
739   {
740   case AF_INET:
741     rh->addr_callback (rh->cls,
742                        (const struct sockaddr *) &v4,
743                        sizeof (v4));
744     break;
745   case AF_INET6:
746     rh->addr_callback (rh->cls,
747                        (const struct sockaddr *) &v6,
748                        sizeof (v6));
749     break;
750   case AF_UNSPEC:
751     rh->addr_callback (rh->cls,
752                        (const struct sockaddr *) &v6,
753                        sizeof (v6));
754     rh->addr_callback (rh->cls,
755                        (const struct sockaddr *) &v4,
756                        sizeof (v4));
757
758     break;
759   default:
760     GNUNET_break (0);
761     break;
762   }
763   if (GNUNET_SYSERR != rh->was_transmitted)
764     rh->addr_callback (rh->cls,
765                        NULL,
766                        0);
767   LOG (GNUNET_ERROR_TYPE_DEBUG,
768        "Finished resolving hostname `%s'.\n",
769        (const char *) &rh[1]);
770   GNUNET_free (rh);
771 }
772
773
774 /**
775  * Now try to reconnect to the resolver service.
776  *
777  * @param cls NULL
778  */
779 static void
780 reconnect_task (void *cls)
781 {
782   struct GNUNET_MQ_MessageHandler handlers[] = {
783     GNUNET_MQ_hd_var_size (response,
784                            GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE,
785                            struct GNUNET_RESOLVER_ResponseMessage,
786                            NULL),
787     GNUNET_MQ_handler_end ()
788   };
789
790   (void) cls;
791   r_task = NULL;
792   if (NULL == req_head)
793     return;                     /* no work pending */
794   LOG (GNUNET_ERROR_TYPE_DEBUG,
795        "Trying to connect to DNS service\n");
796   mq = GNUNET_CLIENT_connect (resolver_cfg,
797                               "resolver",
798                               handlers,
799                               &mq_error_handler,
800                               NULL);
801   if (NULL == mq)
802   {
803     LOG (GNUNET_ERROR_TYPE_DEBUG,
804          "Failed to connect, will try again later\n");
805     reconnect ();
806     return;
807   }
808   process_requests ();
809 }
810
811
812 /**
813  * Adjust exponential back-off and reconnect to the service.
814  */
815 static void
816 reconnect ()
817 {
818   struct GNUNET_RESOLVER_RequestHandle *rh;
819
820   if (NULL != r_task)
821     return;
822   GNUNET_assert (NULL == mq);
823   if (NULL != (rh = req_head))
824   {
825     switch (rh->was_transmitted)
826     {
827     case GNUNET_NO:
828       /* nothing more to do */
829       break;
830     case GNUNET_YES:
831       /* disconnected, transmit again! */
832       rh->was_transmitted = GNUNET_NO;
833       break;
834     case GNUNET_SYSERR:
835       /* request was cancelled, remove entirely */
836       GNUNET_CONTAINER_DLL_remove (req_head,
837                                    req_tail,
838                                    rh);
839       GNUNET_free (rh);
840       check_disconnect ();
841       break;
842     default:
843       GNUNET_assert (0);
844       break;
845     }
846   }
847   LOG (GNUNET_ERROR_TYPE_DEBUG,
848        "Will try to connect to DNS service in %s\n",
849        GNUNET_STRINGS_relative_time_to_string (backoff,
850                                                GNUNET_YES));
851   GNUNET_assert (NULL != resolver_cfg);
852   r_task = GNUNET_SCHEDULER_add_delayed (backoff,
853                                          &reconnect_task,
854                                          NULL);
855   backoff = GNUNET_TIME_STD_BACKOFF (backoff);
856 }
857
858
859 /**
860  * A DNS resolution timed out. Notify the application.
861  *
862  * @param cls the `struct GNUNET_RESOLVER_RequestHandle *`
863  */
864 static void
865 handle_lookup_timeout (void *cls)
866 {
867   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
868
869   rh->task = NULL;
870   if (GNUNET_NO == rh->direction)
871   {
872     LOG (GNUNET_ERROR_TYPE_INFO,
873          _("Timeout trying to resolve hostname `%s'.\n"),
874          (const char *) &rh[1]);
875     if (NULL != rh->addr_callback)
876       rh->addr_callback (rh->cls,
877                          NULL,
878                          0);
879   }
880   else
881   {
882 #if !defined(GNUNET_CULL_LOGGING)
883     char buf[INET6_ADDRSTRLEN];
884
885     LOG (GNUNET_ERROR_TYPE_INFO,
886          _("Timeout trying to resolve IP address `%s'.\n"),
887          inet_ntop (rh->af,
888                     (const void *) &rh[1],
889                     buf,
890                     sizeof(buf)));
891 #endif
892     if (GNUNET_NO == rh->received_response)
893     {
894       char *nret;
895
896       nret = no_resolve (rh->af,
897                          &rh[1],
898                          rh->data_len);
899       if (NULL != rh->name_callback)
900         rh->name_callback (rh->cls, nret);
901       GNUNET_free (nret);
902     }
903     /* finally, make termination call */
904     if (NULL != rh->name_callback)
905       rh->name_callback (rh->cls,
906                          NULL);
907   }
908   rh->was_transmitted = GNUNET_NO;
909   GNUNET_RESOLVER_request_cancel (rh);
910   process_requests ();
911 }
912
913
914 /**
915  * Convert a string to one or more IP addresses.
916  *
917  * @param hostname the hostname to resolve
918  * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any"
919  * @param callback function to call with addresses
920  * @param callback_cls closure for @a callback
921  * @param timeout how long to try resolving
922  * @return handle that can be used to cancel the request, NULL on error
923  */
924 struct GNUNET_RESOLVER_RequestHandle *
925 GNUNET_RESOLVER_ip_get (const char *hostname,
926                         int af,
927                         struct GNUNET_TIME_Relative timeout,
928                         GNUNET_RESOLVER_AddressCallback callback,
929                         void *callback_cls)
930 {
931   struct GNUNET_RESOLVER_RequestHandle *rh;
932   size_t slen;
933   struct in_addr v4;
934   struct in6_addr v6;
935
936   slen = strlen (hostname) + 1;
937   if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) >=
938       GNUNET_MAX_MESSAGE_SIZE)
939   {
940     GNUNET_break (0);
941     return NULL;
942   }
943   LOG (GNUNET_ERROR_TYPE_DEBUG,
944        "Trying to resolve hostname `%s'.\n",
945        hostname);
946   rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + slen);
947   rh->af = af;
948   rh->id = ++last_request_id;
949   rh->addr_callback = callback;
950   rh->cls = callback_cls;
951   GNUNET_memcpy (&rh[1],
952                  hostname,
953                  slen);
954   rh->data_len = slen;
955   rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
956   rh->direction = GNUNET_NO;
957   /* first, check if this is a numeric address */
958   if ( ( (1 == inet_pton (AF_INET,
959                           hostname,
960                           &v4)) &&
961          ( (af == AF_INET) ||
962            (af == AF_UNSPEC) ) ) ||
963        ( (1 == inet_pton (AF_INET6,
964                           hostname,
965                           &v6)) &&
966          ( (af == AF_INET6) ||
967            (af == AF_UNSPEC)) ) )
968   {
969     rh->task = GNUNET_SCHEDULER_add_now (&numeric_resolution,
970                                          rh);
971     return rh;
972   }
973   /* then, check if this is a loopback address */
974   for (unsigned int i = 0;
975        NULL != loopback[i];
976        i++)
977     if (0 == strcasecmp (loopback[i],
978                          hostname))
979     {
980       rh->task = GNUNET_SCHEDULER_add_now (&loopback_resolution,
981                                            rh);
982       return rh;
983     }
984   if (GNUNET_OK != check_config ())
985   {
986     GNUNET_free (rh);
987     return NULL;
988   }
989   rh->task = GNUNET_SCHEDULER_add_delayed (timeout,
990                                            &handle_lookup_timeout,
991                                            rh);
992   GNUNET_CONTAINER_DLL_insert_tail (req_head,
993                                     req_tail,
994                                     rh);
995   rh->was_queued = GNUNET_YES;
996   if (NULL != s_task)
997   {
998     GNUNET_SCHEDULER_cancel (s_task);
999     s_task = NULL;
1000   }
1001   process_requests ();
1002   return rh;
1003 }
1004
1005
1006 /**
1007  * We've been asked to convert an address to a string without
1008  * a reverse lookup, either because the client asked for it
1009  * or because the DNS lookup hit a timeout.  Do the numeric
1010  * conversion and invoke the callback.
1011  *
1012  * @param cls `struct GNUNET_RESOLVER_RequestHandle` for the request
1013  */
1014 static void
1015 numeric_reverse (void *cls)
1016 {
1017   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
1018   char *result;
1019
1020   rh->task = NULL;
1021   result = no_resolve (rh->af,
1022                        &rh[1],
1023                        rh->data_len);
1024   LOG (GNUNET_ERROR_TYPE_DEBUG,
1025        "Resolver returns `%s'.\n",
1026        result);
1027   if (NULL != result)
1028   {
1029     rh->name_callback (rh->cls,
1030                        result);
1031     GNUNET_free (result);
1032   }
1033   rh->name_callback (rh->cls,
1034                      NULL);
1035   if (NULL != rh->task)
1036   {
1037     GNUNET_SCHEDULER_cancel (rh->task);
1038     rh->task = NULL;
1039   }
1040   GNUNET_free (rh);
1041 }
1042
1043
1044 /**
1045  * Get an IP address as a string.
1046  *
1047  * @param sa host address
1048  * @param salen length of host address in @a sa
1049  * @param do_resolve use #GNUNET_NO to return numeric hostname
1050  * @param timeout how long to try resolving
1051  * @param callback function to call with hostnames
1052  *        last callback is NULL when finished
1053  * @param cls closure for @a callback
1054  * @return handle that can be used to cancel the request
1055  */
1056 struct GNUNET_RESOLVER_RequestHandle *
1057 GNUNET_RESOLVER_hostname_get (const struct sockaddr *sa,
1058                               socklen_t salen,
1059                               int do_resolve,
1060                               struct GNUNET_TIME_Relative timeout,
1061                               GNUNET_RESOLVER_HostnameCallback callback,
1062                               void *cls)
1063 {
1064   struct GNUNET_RESOLVER_RequestHandle *rh;
1065   size_t ip_len;
1066   const void *ip;
1067
1068   if (GNUNET_OK != check_config ())
1069   {
1070     LOG (GNUNET_ERROR_TYPE_ERROR,
1071          _("Resolver not configured correctly.\n"));
1072     return NULL;
1073   }
1074
1075   switch (sa->sa_family)
1076   {
1077   case AF_INET:
1078     GNUNET_assert (salen == sizeof (struct sockaddr_in));
1079     ip_len = sizeof (struct in_addr);
1080     ip = &((const struct sockaddr_in*)sa)->sin_addr;
1081     break;
1082   case AF_INET6:
1083     GNUNET_assert (salen == sizeof (struct sockaddr_in6));
1084     ip_len = sizeof (struct in6_addr);
1085     ip = &((const struct sockaddr_in6*)sa)->sin6_addr;
1086     break;
1087   default:
1088     GNUNET_break (0);
1089     return NULL;
1090   }
1091   rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + salen);
1092   rh->name_callback = callback;
1093   rh->cls = cls;
1094   rh->af = sa->sa_family;
1095   rh->id = ++last_request_id;
1096   rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1097   GNUNET_memcpy (&rh[1],
1098                  ip,
1099                  ip_len);
1100   rh->data_len = ip_len;
1101   rh->direction = GNUNET_YES;
1102   rh->received_response = GNUNET_NO;
1103   if (GNUNET_NO == do_resolve)
1104   {
1105     rh->task = GNUNET_SCHEDULER_add_now (&numeric_reverse,
1106                                          rh);
1107     return rh;
1108   }
1109   rh->task = GNUNET_SCHEDULER_add_delayed (timeout,
1110                                            &handle_lookup_timeout,
1111                                            rh);
1112   GNUNET_CONTAINER_DLL_insert_tail (req_head,
1113                                     req_tail,
1114                                     rh);
1115   rh->was_queued = GNUNET_YES;
1116   if (NULL != s_task)
1117   {
1118     GNUNET_SCHEDULER_cancel (s_task);
1119     s_task = NULL;
1120   }
1121   process_requests ();
1122   return rh;
1123 }
1124
1125
1126 /**
1127  * Get local fully qualified af name
1128  *
1129  * @return fqdn
1130  */
1131 char *
1132 GNUNET_RESOLVER_local_fqdn_get ()
1133 {
1134   char hostname[GNUNET_OS_get_hostname_max_length () + 1];
1135
1136   if (0 != gethostname (hostname,
1137                         sizeof (hostname) - 1))
1138   {
1139     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1140                   "gethostname");
1141     return NULL;
1142   }
1143   LOG (GNUNET_ERROR_TYPE_DEBUG,
1144        "Resolving our FQDN `%s'\n",
1145        hostname);
1146 #if HAVE_GETADDRINFO
1147   {
1148     struct addrinfo *ai;
1149     int ret;
1150     char *rval;
1151
1152     if (0 != (ret = getaddrinfo (hostname,
1153                                  NULL,
1154                                  NULL,
1155                                  &ai)))
1156     {
1157       LOG (GNUNET_ERROR_TYPE_ERROR,
1158            _("Could not resolve our FQDN: %s\n"),
1159            gai_strerror (ret));
1160       return NULL;
1161     }
1162     if (NULL != ai->ai_canonname)
1163       rval = GNUNET_strdup (ai->ai_canonname);
1164     else
1165       rval = GNUNET_strdup (hostname);
1166     freeaddrinfo (ai);
1167     return rval;
1168   }
1169 #elif HAVE_GETHOSTBYNAME2
1170   {
1171     struct hostent *host;
1172
1173     host = gethostbyname2 (hostname,
1174                            AF_INET);
1175     if (NULL == host)
1176       host = gethostbyname2 (hostname,
1177                              AF_INET6);
1178     if (NULL == host)
1179       {
1180         LOG (GNUNET_ERROR_TYPE_ERROR,
1181              _("Could not resolve our FQDN: %s\n"),
1182              hstrerror (h_errno));
1183         return NULL;
1184       }
1185     return GNUNET_strdup (host->h_name);
1186   }
1187 #elif HAVE_GETHOSTBYNAME
1188   {
1189     struct hostent *host;
1190
1191     host = gethostbyname (hostname);
1192     if (NULL == host)
1193       {
1194         LOG (GNUNET_ERROR_TYPE_ERROR,
1195              _("Could not resolve our FQDN: %s\n"),
1196              hstrerror (h_errno));
1197         return NULL;
1198       }
1199     return GNUNET_strdup (host->h_name);
1200   }
1201 #else
1202   /* fallback: just hope name is already FQDN */
1203   return GNUNET_strdup (hostname);
1204 #endif
1205 }
1206
1207
1208 /**
1209  * Looking our own hostname.
1210  *
1211  * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any"
1212  * @param timeout how long to try resolving
1213  * @param callback function to call with addresses
1214  * @param cls closure for @a callback
1215  * @return handle that can be used to cancel the request, NULL on error
1216  */
1217 struct GNUNET_RESOLVER_RequestHandle *
1218 GNUNET_RESOLVER_hostname_resolve (int af,
1219                                   struct GNUNET_TIME_Relative timeout,
1220                                   GNUNET_RESOLVER_AddressCallback callback,
1221                                   void *cls)
1222 {
1223   char hostname[GNUNET_OS_get_hostname_max_length () + 1];
1224
1225   if (0 != gethostname (hostname, sizeof (hostname) - 1))
1226   {
1227     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1228                   "gethostname");
1229     return NULL;
1230   }
1231   LOG (GNUNET_ERROR_TYPE_DEBUG,
1232        "Resolving our hostname `%s'\n",
1233        hostname);
1234   return GNUNET_RESOLVER_ip_get (hostname,
1235                                  af,
1236                                  timeout,
1237                                  callback,
1238                                  cls);
1239 }
1240
1241
1242 /**
1243  * Cancel a request that is still pending with the resolver.
1244  * Note that a client MUST NOT cancel a request that has
1245  * been completed (i.e, the callback has been called to
1246  * signal timeout or the final result).
1247  *
1248  * @param rh handle of request to cancel
1249  */
1250 void
1251 GNUNET_RESOLVER_request_cancel (struct GNUNET_RESOLVER_RequestHandle *rh)
1252 {
1253   if (GNUNET_NO == rh->direction)
1254     LOG (GNUNET_ERROR_TYPE_DEBUG,
1255          "Asked to cancel request to resolve hostname `%s'.\n",
1256          (const char *) &rh[1]);
1257   if (NULL != rh->task)
1258   {
1259     GNUNET_SCHEDULER_cancel (rh->task);
1260     rh->task = NULL;
1261   }
1262   if (GNUNET_NO == rh->was_transmitted)
1263   {
1264     if (GNUNET_YES == rh->was_queued)
1265       GNUNET_CONTAINER_DLL_remove (req_head,
1266                                    req_tail,
1267                                    rh);
1268     GNUNET_free (rh);
1269     check_disconnect ();
1270     return;
1271   }
1272   GNUNET_assert (GNUNET_YES == rh->was_transmitted);
1273   rh->was_transmitted = GNUNET_SYSERR;  /* mark as cancelled */
1274   check_disconnect ();
1275 }
1276
1277
1278 /* end of resolver_api.c */