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