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