Merge remote-tracking branch 'origin/identity_abe'
[oweals/gnunet.git] / src / util / resolver_api.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009-2016 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], hostname))
218     {
219       GNUNET_free (hostname);
220       return GNUNET_OK;
221     }
222   LOG (GNUNET_ERROR_TYPE_INFO,
223        _("Missing `%s' or numeric IP address for `%s' of `%s' in configuration, DNS resolution will be unavailable.\n"),
224        "localhost",
225        "HOSTNAME",
226        "resolver");
227   GNUNET_free (hostname);
228   return GNUNET_SYSERR;
229 }
230
231
232 /**
233  * Create the connection to the resolver service.
234  *
235  * @param cfg configuration to use
236  */
237 void
238 GNUNET_RESOLVER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
239 {
240   GNUNET_assert (NULL != cfg);
241   backoff = GNUNET_TIME_UNIT_MILLISECONDS;
242   resolver_cfg = cfg;
243 }
244
245
246 /**
247  * Destroy the connection to the resolver service.
248  */
249 void
250 GNUNET_RESOLVER_disconnect ()
251 {
252   struct GNUNET_RESOLVER_RequestHandle *rh;
253
254   while (NULL != (rh = req_head))
255   {
256     GNUNET_assert (GNUNET_SYSERR == rh->was_transmitted);
257     GNUNET_CONTAINER_DLL_remove (req_head,
258                                  req_tail,
259                                  rh);
260     GNUNET_free (rh);
261   }
262   if (NULL != mq)
263   {
264     LOG (GNUNET_ERROR_TYPE_DEBUG,
265          "Disconnecting from DNS service\n");
266     GNUNET_MQ_destroy (mq);
267     mq = NULL;
268   }
269   if (NULL != r_task)
270   {
271     GNUNET_SCHEDULER_cancel (r_task);
272     r_task = NULL;
273   }
274   if (NULL != s_task)
275   {
276     GNUNET_SCHEDULER_cancel (s_task);
277     s_task = NULL;
278   }
279 }
280
281
282 /**
283  * Task executed on system shutdown.
284  */
285 static void
286 shutdown_task (void *cls)
287 {
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   GNUNET_MQ_destroy (mq);
391   mq = NULL;
392   LOG (GNUNET_ERROR_TYPE_DEBUG,
393        "MQ error, reconnecting\n");
394   reconnect ();
395 }
396
397
398 /**
399  * Process pending requests to the resolver.
400  */
401 static void
402 process_requests ()
403 {
404   struct GNUNET_RESOLVER_GetMessage *msg;
405   struct GNUNET_MQ_Envelope *env;
406   struct GNUNET_RESOLVER_RequestHandle *rh = req_head;
407
408   if (NULL == mq)
409   {
410     reconnect ();
411     return;
412   }
413   if (NULL == rh)
414   {
415     /* nothing to do, release socket really soon if there is nothing
416      * else happening... */
417     if (NULL == s_task)
418       s_task =
419         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
420                                       &shutdown_task,
421                                       NULL);
422     return;
423   }
424   if (GNUNET_NO != rh->was_transmitted)
425     return;                     /* waiting for reply */
426   env = GNUNET_MQ_msg_extra (msg,
427                              rh->data_len,
428                              GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
429   msg->direction = htonl (rh->direction);
430   msg->af = htonl (rh->af);
431   GNUNET_memcpy (&msg[1],
432                  &rh[1],
433                  rh->data_len);
434   LOG (GNUNET_ERROR_TYPE_DEBUG,
435        "Transmitting DNS resolution request to DNS service\n");
436   GNUNET_MQ_send (mq,
437                   env);
438   rh->was_transmitted = GNUNET_YES;
439 }
440
441
442 /**
443  * Check validity of response with a hostname for a DNS lookup.
444  *
445  * @param cls NULL
446  * @param msg message with the hostname
447  */
448 static int
449 check_response (void *cls,
450                 const struct GNUNET_MessageHeader *msg)
451 {
452   /* implemented in #handle_response() for now */
453   return GNUNET_OK;
454 }
455
456
457 /**
458  * Check validity of response with a hostname for a DNS lookup.
459  * NOTE: right now rather messy, might want to use different
460  * message types for different response formats in the future.
461  *
462  * @param cls NULL
463  * @param msg message with the response
464  */
465 static void
466 handle_response (void *cls,
467                  const struct GNUNET_MessageHeader *msg)
468 {
469   struct GNUNET_RESOLVER_RequestHandle *rh = req_head;
470   uint16_t size;
471   char *nret;
472
473   GNUNET_assert (NULL != rh);
474   size = ntohs (msg->size);
475   if (size == sizeof (struct GNUNET_MessageHeader))
476   {
477     LOG (GNUNET_ERROR_TYPE_DEBUG,
478          "Received empty response from DNS service\n");
479     /* message contains not data, just header; end of replies */
480     /* check if request was canceled */
481     if (GNUNET_SYSERR != rh->was_transmitted)
482     {
483       /* no reverse lookup was successful, return IP as string */
484       if (NULL != rh->name_callback)
485       {
486         if (GNUNET_NO == rh->received_response)
487         {
488           nret = no_resolve (rh->af,
489                              &rh[1],
490                              rh->data_len);
491           rh->name_callback (rh->cls, nret);
492           GNUNET_free (nret);
493         }
494         /* finally, make termination call */
495         rh->name_callback (rh->cls,
496                            NULL);
497       }
498       if (NULL != rh->addr_callback)
499         rh->addr_callback (rh->cls,
500                            NULL,
501                            0);
502     }
503     rh->was_transmitted = GNUNET_NO;
504     GNUNET_RESOLVER_request_cancel (rh);
505     process_requests ();
506     return;
507   }
508   /* return reverse lookup results to caller */
509   if (NULL != rh->name_callback)
510   {
511     const char *hostname;
512
513     hostname = (const char *) &msg[1];
514     if (hostname[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0')
515     {
516       GNUNET_break (0);
517       if (GNUNET_SYSERR != rh->was_transmitted)
518         rh->name_callback (rh->cls,
519                            NULL);
520       rh->was_transmitted = GNUNET_NO;
521       GNUNET_RESOLVER_request_cancel (rh);
522       GNUNET_MQ_destroy (mq);
523       mq = NULL;
524       reconnect ();
525       return;
526     }
527     LOG (GNUNET_ERROR_TYPE_DEBUG,
528          "Resolver returns `%s' for IP `%s'.\n",
529          hostname,
530          GNUNET_a2s ((const void *) &rh[1],
531                      rh->data_len));
532     if (rh->was_transmitted != GNUNET_SYSERR)
533       rh->name_callback (rh->cls,
534                          hostname);
535     rh->received_response = GNUNET_YES;
536   }
537   /* return lookup results to caller */
538   if (NULL != rh->addr_callback)
539   {
540     struct sockaddr_in v4;
541     struct sockaddr_in6 v6;
542     const struct sockaddr *sa;
543     socklen_t salen;
544     const void *ip;
545     size_t ip_len;
546
547     ip = &msg[1];
548     ip_len = size - sizeof (struct GNUNET_MessageHeader);
549     if (ip_len == sizeof (struct in_addr))
550     {
551       memset (&v4, 0, sizeof (v4));
552       v4.sin_family = AF_INET;
553       v4.sin_addr = *(struct in_addr*) ip;
554 #if HAVE_SOCKADDR_IN_SIN_LEN
555       v4.sin_len = sizeof (v4);
556 #endif
557       salen = sizeof (v4);
558       sa = (const struct sockaddr *) &v4;
559     }
560     else if (ip_len == sizeof (struct in6_addr))
561     {
562       memset (&v6, 0, sizeof (v6));
563       v6.sin6_family = AF_INET6;
564       v6.sin6_addr = *(struct in6_addr*) ip;
565 #if HAVE_SOCKADDR_IN_SIN_LEN
566       v6.sin6_len = sizeof (v6);
567 #endif
568       salen = sizeof (v6);
569       sa = (const struct sockaddr *) &v6;
570     }
571     else
572     {
573       GNUNET_break (0);
574       if (GNUNET_SYSERR != rh->was_transmitted)
575         rh->addr_callback (rh->cls,
576                            NULL,
577                            0);
578       rh->was_transmitted = GNUNET_NO;
579       GNUNET_RESOLVER_request_cancel (rh);
580       GNUNET_MQ_destroy (mq);
581       mq = NULL;
582       reconnect ();
583       return;
584     }
585     LOG (GNUNET_ERROR_TYPE_DEBUG,
586          "Received IP from DNS service\n");
587     if (GNUNET_SYSERR != rh->was_transmitted)
588       rh->addr_callback (rh->cls,
589                          sa,
590                          salen);
591   }
592 }
593
594
595 /**
596  * We've been asked to lookup the address for a hostname and were
597  * given a valid numeric string.  Perform the callbacks for the
598  * numeric addresses.
599  *
600  * @param cls `struct GNUNET_RESOLVER_RequestHandle` for the request
601  */
602 static void
603 numeric_resolution (void *cls)
604 {
605   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
606   struct sockaddr_in v4;
607   struct sockaddr_in6 v6;
608   const char *hostname;
609
610   rh->task = NULL;
611   memset (&v4, 0, sizeof (v4));
612   v4.sin_family = AF_INET;
613 #if HAVE_SOCKADDR_IN_SIN_LEN
614   v4.sin_len = sizeof (v4);
615 #endif
616   memset (&v6, 0, sizeof (v6));
617   v6.sin6_family = AF_INET6;
618 #if HAVE_SOCKADDR_IN_SIN_LEN
619   v6.sin6_len = sizeof (v6);
620 #endif
621   hostname = (const char *) &rh[1];
622   if ( ( (rh->af == AF_UNSPEC) ||
623          (rh->af == AF_INET) ) &&
624        (1 == inet_pton (AF_INET,
625                         hostname,
626                         &v4.sin_addr)) )
627   {
628     rh->addr_callback (rh->cls,
629                        (const struct sockaddr *) &v4,
630                        sizeof (v4));
631     if ( (rh->af == AF_UNSPEC) &&
632          (1 == inet_pton (AF_INET6,
633                           hostname,
634                           &v6.sin6_addr)) )
635     {
636       /* this can happen on some systems IF "hostname" is "localhost" */
637       rh->addr_callback (rh->cls,
638                          (const struct sockaddr *) &v6,
639                          sizeof (v6));
640     }
641     rh->addr_callback (rh->cls,
642                        NULL,
643                        0);
644     GNUNET_free (rh);
645     return;
646   }
647   if ( ( (rh->af == AF_UNSPEC) ||
648          (rh->af == AF_INET6) ) &&
649        (1 == inet_pton (AF_INET6,
650                         hostname,
651                         &v6.sin6_addr) ) )
652   {
653     rh->addr_callback (rh->cls,
654                        (const struct sockaddr *) &v6,
655                        sizeof (v6));
656     rh->addr_callback (rh->cls,
657                        NULL,
658                        0);
659     GNUNET_free (rh);
660     return;
661   }
662   /* why are we here? this task should not have been scheduled! */
663   GNUNET_assert (0);
664   GNUNET_free (rh);
665 }
666
667
668 /**
669  * We've been asked to lookup the address for a hostname and were
670  * given a variant of "loopback".  Perform the callbacks for the
671  * respective loopback numeric addresses.
672  *
673  * @param cls `struct GNUNET_RESOLVER_RequestHandle` for the request
674  */
675 static void
676 loopback_resolution (void *cls)
677 {
678   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
679   struct sockaddr_in v4;
680   struct sockaddr_in6 v6;
681
682   rh->task = NULL;
683   memset (&v4, 0, sizeof (v4));
684   v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
685   v4.sin_family = AF_INET;
686 #if HAVE_SOCKADDR_IN_SIN_LEN
687   v4.sin_len = sizeof (v4);
688 #endif
689   memset (&v6, 0, sizeof (v6));
690   v6.sin6_family = AF_INET6;
691 #if HAVE_SOCKADDR_IN_SIN_LEN
692   v6.sin6_len = sizeof (v6);
693 #endif
694   v6.sin6_addr = in6addr_loopback;
695   switch (rh->af)
696   {
697   case AF_INET:
698     rh->addr_callback (rh->cls,
699                        (const struct sockaddr *) &v4,
700                        sizeof (v4));
701     break;
702   case AF_INET6:
703     rh->addr_callback (rh->cls,
704                        (const struct sockaddr *) &v6,
705                        sizeof (v6));
706     break;
707   case AF_UNSPEC:
708     rh->addr_callback (rh->cls,
709                        (const struct sockaddr *) &v6,
710                        sizeof (v6));
711     rh->addr_callback (rh->cls,
712                        (const struct sockaddr *) &v4,
713                        sizeof (v4));
714
715     break;
716   default:
717     GNUNET_break (0);
718     break;
719   }
720   rh->addr_callback (rh->cls,
721                      NULL,
722                      0);
723   LOG (GNUNET_ERROR_TYPE_DEBUG,
724        "Finished resolving hostname `%s'.\n",
725        (const char *) &rh[1]);
726   GNUNET_free (rh);
727 }
728
729
730 /**
731  * Now try to reconnect to the resolver service.
732  *
733  * @param cls NULL
734  */
735 static void
736 reconnect_task (void *cls)
737 {
738   struct GNUNET_MQ_MessageHandler handlers[] = {
739     GNUNET_MQ_hd_var_size (response,
740                            GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE,
741                            struct GNUNET_MessageHeader,
742                            NULL),
743     GNUNET_MQ_handler_end ()
744   };
745
746   r_task = NULL;
747   if (NULL == req_head)
748     return;                     /* no work pending */
749   LOG (GNUNET_ERROR_TYPE_DEBUG,
750        "Trying to connect to DNS service\n");
751   mq = GNUNET_CLIENT_connect (resolver_cfg,
752                               "resolver",
753                               handlers,
754                               &mq_error_handler,
755                               NULL);
756   if (NULL == mq)
757   {
758     LOG (GNUNET_ERROR_TYPE_DEBUG,
759          "Failed to connect, will try again later\n");
760     reconnect ();
761     return;
762   }
763   process_requests ();
764 }
765
766
767 /**
768  * Adjust exponential back-off and reconnect to the service.
769  */
770 static void
771 reconnect ()
772 {
773   struct GNUNET_RESOLVER_RequestHandle *rh;
774
775   if (NULL != r_task)
776     return;
777   GNUNET_assert (NULL == mq);
778   if (NULL != (rh = req_head))
779   {
780     switch (rh->was_transmitted)
781     {
782     case GNUNET_NO:
783       /* nothing more to do */
784       break;
785     case GNUNET_YES:
786       /* disconnected, transmit again! */
787       rh->was_transmitted = GNUNET_NO;
788       break;
789     case GNUNET_SYSERR:
790       /* request was cancelled, remove entirely */
791       GNUNET_CONTAINER_DLL_remove (req_head,
792                                    req_tail,
793                                    rh);
794       GNUNET_free (rh);
795       check_disconnect ();
796       break;
797     default:
798       GNUNET_assert (0);
799       break;
800     }
801   }
802   LOG (GNUNET_ERROR_TYPE_DEBUG,
803        "Will try to connect to DNS service in %s\n",
804        GNUNET_STRINGS_relative_time_to_string (backoff,
805                                                GNUNET_YES));
806   GNUNET_assert (NULL != resolver_cfg);
807   r_task = GNUNET_SCHEDULER_add_delayed (backoff,
808                                          &reconnect_task,
809                                          NULL);
810   backoff = GNUNET_TIME_STD_BACKOFF (backoff);
811 }
812
813
814 /**
815  * A DNS resolution timed out. Notify the application.
816  *
817  * @param cls the `struct GNUNET_RESOLVER_RequestHandle *`
818  */
819 static void
820 handle_lookup_timeout (void *cls)
821 {
822   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
823
824   rh->task = NULL;
825   if (GNUNET_NO == rh->direction)
826   {
827     LOG (GNUNET_ERROR_TYPE_INFO,
828          _("Timeout trying to resolve hostname `%s'.\n"),
829          (const char *) &rh[1]);
830     if (NULL != rh->addr_callback)
831       rh->addr_callback (rh->cls,
832                          NULL,
833                          0);
834   }
835   else
836   {
837 #if !defined(GNUNET_CULL_LOGGING)
838     char buf[INET6_ADDRSTRLEN];
839
840     LOG (GNUNET_ERROR_TYPE_INFO,
841          _("Timeout trying to resolve IP address `%s'.\n"),
842          inet_ntop (rh->af,
843                     (const void *) &rh[1],
844                     buf,
845                     sizeof(buf)));
846 #endif
847     if (GNUNET_NO == rh->received_response)
848     {
849       char *nret;
850
851       nret = no_resolve (rh->af,
852                          &rh[1],
853                          rh->data_len);
854       if (NULL != rh->name_callback)
855         rh->name_callback (rh->cls, nret);
856       GNUNET_free (nret);
857     }
858     /* finally, make termination call */
859     if (NULL != rh->name_callback)
860       rh->name_callback (rh->cls,
861                          NULL);
862   }
863   rh->was_transmitted = GNUNET_NO;
864   GNUNET_RESOLVER_request_cancel (rh);
865   process_requests ();
866 }
867
868
869 /**
870  * Convert a string to one or more IP addresses.
871  *
872  * @param hostname the hostname to resolve
873  * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any"
874  * @param callback function to call with addresses
875  * @param callback_cls closure for @a callback
876  * @param timeout how long to try resolving
877  * @return handle that can be used to cancel the request, NULL on error
878  */
879 struct GNUNET_RESOLVER_RequestHandle *
880 GNUNET_RESOLVER_ip_get (const char *hostname,
881                         int af,
882                         struct GNUNET_TIME_Relative timeout,
883                         GNUNET_RESOLVER_AddressCallback callback,
884                         void *callback_cls)
885 {
886   struct GNUNET_RESOLVER_RequestHandle *rh;
887   size_t slen;
888   struct in_addr v4;
889   struct in6_addr v6;
890
891   slen = strlen (hostname) + 1;
892   if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) >=
893       GNUNET_MAX_MESSAGE_SIZE)
894   {
895     GNUNET_break (0);
896     return NULL;
897   }
898   LOG (GNUNET_ERROR_TYPE_DEBUG,
899        "Trying to resolve hostname `%s'.\n",
900        hostname);
901   rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + slen);
902   rh->af = af;
903   rh->addr_callback = callback;
904   rh->cls = callback_cls;
905   GNUNET_memcpy (&rh[1],
906                  hostname,
907                  slen);
908   rh->data_len = slen;
909   rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
910   rh->direction = GNUNET_NO;
911   /* first, check if this is a numeric address */
912   if ( ( (1 == inet_pton (AF_INET,
913                           hostname,
914                           &v4)) &&
915          ( (af == AF_INET) ||
916            (af == AF_UNSPEC) ) ) ||
917        ( (1 == inet_pton (AF_INET6,
918                           hostname,
919                           &v6)) &&
920          ( (af == AF_INET6) ||
921            (af == AF_UNSPEC)) ) )
922   {
923     rh->task = GNUNET_SCHEDULER_add_now (&numeric_resolution,
924                                          rh);
925     return rh;
926   }
927   /* then, check if this is a loopback address */
928   for (unsigned int i = 0;
929        NULL != loopback[i];
930        i++)
931     if (0 == strcasecmp (loopback[i],
932                          hostname))
933     {
934       rh->task = GNUNET_SCHEDULER_add_now (&loopback_resolution,
935                                            rh);
936       return rh;
937     }
938   if (GNUNET_OK != check_config ())
939   {
940     GNUNET_free (rh);
941     return NULL;
942   }
943   rh->task = GNUNET_SCHEDULER_add_delayed (timeout,
944                                            &handle_lookup_timeout,
945                                            rh);
946   GNUNET_CONTAINER_DLL_insert_tail (req_head,
947                                     req_tail,
948                                     rh);
949   rh->was_queued = GNUNET_YES;
950   if (NULL != s_task)
951   {
952     GNUNET_SCHEDULER_cancel (s_task);
953     s_task = NULL;
954   }
955   process_requests ();
956   return rh;
957 }
958
959
960 /**
961  * We've been asked to convert an address to a string without
962  * a reverse lookup, either because the client asked for it
963  * or because the DNS lookup hit a timeout.  Do the numeric
964  * conversion and invoke the callback.
965  *
966  * @param cls `struct GNUNET_RESOLVER_RequestHandle` for the request
967  */
968 static void
969 numeric_reverse (void *cls)
970 {
971   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
972   char *result;
973
974   rh->task = NULL;
975   result = no_resolve (rh->af,
976                        &rh[1],
977                        rh->data_len);
978   LOG (GNUNET_ERROR_TYPE_DEBUG,
979        "Resolver returns `%s'.\n",
980        result);
981   if (NULL != result)
982   {
983     rh->name_callback (rh->cls,
984                        result);
985     GNUNET_free (result);
986   }
987   rh->name_callback (rh->cls,
988                      NULL);
989   if (NULL != rh->task)
990   {
991     GNUNET_SCHEDULER_cancel (rh->task);
992     rh->task = NULL;
993   }
994   GNUNET_free (rh);
995 }
996
997
998 /**
999  * Get an IP address as a string.
1000  *
1001  * @param sa host address
1002  * @param salen length of host address in @a sa
1003  * @param do_resolve use #GNUNET_NO to return numeric hostname
1004  * @param timeout how long to try resolving
1005  * @param callback function to call with hostnames
1006  *        last callback is NULL when finished
1007  * @param cls closure for @a callback
1008  * @return handle that can be used to cancel the request
1009  */
1010 struct GNUNET_RESOLVER_RequestHandle *
1011 GNUNET_RESOLVER_hostname_get (const struct sockaddr *sa,
1012                               socklen_t salen,
1013                               int do_resolve,
1014                               struct GNUNET_TIME_Relative timeout,
1015                               GNUNET_RESOLVER_HostnameCallback callback,
1016                               void *cls)
1017 {
1018   struct GNUNET_RESOLVER_RequestHandle *rh;
1019   size_t ip_len;
1020   const void *ip;
1021
1022   if (GNUNET_OK != check_config ())
1023   {
1024     LOG (GNUNET_ERROR_TYPE_ERROR,
1025          _("Resolver not configured correctly.\n"));
1026     return NULL;
1027   }
1028
1029   switch (sa->sa_family)
1030   {
1031   case AF_INET:
1032     GNUNET_assert (salen == sizeof (struct sockaddr_in));
1033     ip_len = sizeof (struct in_addr);
1034     ip = &((const struct sockaddr_in*)sa)->sin_addr;
1035     break;
1036   case AF_INET6:
1037     GNUNET_assert (salen == sizeof (struct sockaddr_in6));
1038     ip_len = sizeof (struct in6_addr);
1039     ip = &((const struct sockaddr_in6*)sa)->sin6_addr;
1040     break;
1041   default:
1042     GNUNET_break (0);
1043     return NULL;
1044   }
1045   rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + salen);
1046   rh->name_callback = callback;
1047   rh->cls = cls;
1048   rh->af = sa->sa_family;
1049   rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1050   GNUNET_memcpy (&rh[1],
1051                  ip,
1052                  ip_len);
1053   rh->data_len = ip_len;
1054   rh->direction = GNUNET_YES;
1055   rh->received_response = GNUNET_NO;
1056   if (GNUNET_NO == do_resolve)
1057   {
1058     rh->task = GNUNET_SCHEDULER_add_now (&numeric_reverse,
1059                                          rh);
1060     return rh;
1061   }
1062   rh->task = GNUNET_SCHEDULER_add_delayed (timeout,
1063                                            &handle_lookup_timeout,
1064                                            rh);
1065   GNUNET_CONTAINER_DLL_insert_tail (req_head,
1066                                     req_tail,
1067                                     rh);
1068   rh->was_queued = GNUNET_YES;
1069   if (NULL != s_task)
1070   {
1071     GNUNET_SCHEDULER_cancel (s_task);
1072     s_task = NULL;
1073   }
1074   process_requests ();
1075   return rh;
1076 }
1077
1078
1079 /**
1080  * Get local fully qualified af name
1081  *
1082  * @return fqdn
1083  */
1084 char *
1085 GNUNET_RESOLVER_local_fqdn_get ()
1086 {
1087   char hostname[GNUNET_OS_get_hostname_max_length () + 1];
1088
1089   if (0 != gethostname (hostname,
1090                         sizeof (hostname) - 1))
1091   {
1092     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1093                   "gethostname");
1094     return NULL;
1095   }
1096   LOG (GNUNET_ERROR_TYPE_DEBUG,
1097        "Resolving our FQDN `%s'\n",
1098        hostname);
1099 #if HAVE_GETADDRINFO
1100   {
1101     struct addrinfo *ai;
1102     int ret;
1103     char *rval;
1104
1105     if (0 != (ret = getaddrinfo (hostname,
1106                                  NULL,
1107                                  NULL,
1108                                  &ai)))
1109     {
1110       LOG (GNUNET_ERROR_TYPE_ERROR,
1111            _("Could not resolve our FQDN: %s\n"),
1112            gai_strerror (ret));
1113       return NULL;
1114     }
1115     if (NULL != ai->ai_canonname)
1116       rval = GNUNET_strdup (ai->ai_canonname);
1117     else
1118       rval = GNUNET_strdup (hostname);
1119     freeaddrinfo (ai);
1120     return rval;
1121   }
1122 #elif HAVE_GETHOSTBYNAME2
1123   {
1124     struct hostent *host;
1125
1126     host = gethostbyname2 (hostname,
1127                            AF_INET);
1128     if (NULL == host)
1129       host = gethostbyname2 (hostname,
1130                              AF_INET6);
1131     if (NULL == host)
1132       {
1133         LOG (GNUNET_ERROR_TYPE_ERROR,
1134              _("Could not resolve our FQDN: %s\n"),
1135              hstrerror (h_errno));
1136         return NULL;
1137       }
1138     return GNUNET_strdup (host->h_name);
1139   }
1140 #elif HAVE_GETHOSTBYNAME
1141   {
1142     struct hostent *host;
1143
1144     host = gethostbyname (hostname);
1145     if (NULL == host)
1146       {
1147         LOG (GNUNET_ERROR_TYPE_ERROR,
1148              _("Could not resolve our FQDN: %s\n"),
1149              hstrerror (h_errno));
1150         return NULL;
1151       }
1152     return GNUNET_strdup (host->h_name);
1153   }
1154 #else
1155   /* fallback: just hope name is already FQDN */
1156   return GNUNET_strdup (hostname);
1157 #endif
1158 }
1159
1160
1161 /**
1162  * Looking our own hostname.
1163  *
1164  * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any"
1165  * @param timeout how long to try resolving
1166  * @param callback function to call with addresses
1167  * @param cls closure for @a callback
1168  * @return handle that can be used to cancel the request, NULL on error
1169  */
1170 struct GNUNET_RESOLVER_RequestHandle *
1171 GNUNET_RESOLVER_hostname_resolve (int af,
1172                                   struct GNUNET_TIME_Relative timeout,
1173                                   GNUNET_RESOLVER_AddressCallback callback,
1174                                   void *cls)
1175 {
1176   char hostname[GNUNET_OS_get_hostname_max_length () + 1];
1177
1178   if (0 != gethostname (hostname, sizeof (hostname) - 1))
1179   {
1180     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1181                   "gethostname");
1182     return NULL;
1183   }
1184   LOG (GNUNET_ERROR_TYPE_DEBUG,
1185        "Resolving our hostname `%s'\n",
1186        hostname);
1187   return GNUNET_RESOLVER_ip_get (hostname,
1188                                  af,
1189                                  timeout,
1190                                  callback,
1191                                  cls);
1192 }
1193
1194
1195 /**
1196  * Cancel a request that is still pending with the resolver.
1197  * Note that a client MUST NOT cancel a request that has
1198  * been completed (i.e, the callback has been called to
1199  * signal timeout or the final result).
1200  *
1201  * @param rh handle of request to cancel
1202  */
1203 void
1204 GNUNET_RESOLVER_request_cancel (struct GNUNET_RESOLVER_RequestHandle *rh)
1205 {
1206   if (GNUNET_NO == rh->direction)
1207     LOG (GNUNET_ERROR_TYPE_DEBUG,
1208          "Asked to cancel request to resolve hostname `%s'.\n",
1209          (const char *) &rh[1]);
1210   if (NULL != rh->task)
1211   {
1212     GNUNET_SCHEDULER_cancel (rh->task);
1213     rh->task = NULL;
1214   }
1215   if (GNUNET_NO == rh->was_transmitted)
1216   {
1217     if (GNUNET_YES == rh->was_queued)
1218       GNUNET_CONTAINER_DLL_remove (req_head,
1219                                    req_tail,
1220                                    rh);
1221     GNUNET_free (rh);
1222     check_disconnect ();
1223     return;
1224   }
1225   GNUNET_assert (GNUNET_YES == rh->was_transmitted);
1226   rh->was_transmitted = GNUNET_SYSERR;  /* mark as cancelled */
1227   check_disconnect ();
1228 }
1229
1230
1231 /* end of resolver_api.c */