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