2 This file is part of GNUnet.
3 Copyright (C) 2009-2018 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU 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.
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.
17 * @file util/resolver_api.c
18 * @brief resolver for writing a tool
19 * @author Christian Grothoff
22 #include "gnunet_util_lib.h"
23 #include "gnunet_protocols.h"
24 #include "gnunet_resolver_service.h"
27 #define LOG(kind,...) GNUNET_log_from (kind, "util-resolver-api", __VA_ARGS__)
29 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-resolver-api", syscall)
32 * Maximum supported length for a hostname
34 #define MAX_HOSTNAME 1024
38 * Possible hostnames for "loopback".
40 static const char *loopback[] = {
50 static const struct GNUNET_CONFIGURATION_Handle *resolver_cfg;
53 * Our connection to the resolver service, created on-demand, but then
54 * persists until error or shutdown.
56 static struct GNUNET_MQ_Handle *mq;
59 * Head of DLL of requests.
61 static struct GNUNET_RESOLVER_RequestHandle *req_head;
64 * Tail of DLL of requests.
66 static struct GNUNET_RESOLVER_RequestHandle *req_tail;
69 * How long should we wait to reconnect?
71 static struct GNUNET_TIME_Relative backoff;
74 * Task for reconnecting.
76 static struct GNUNET_SCHEDULER_Task *r_task;
79 * Task ID of shutdown task; only present while we have a
80 * connection to the resolver service.
82 static struct GNUNET_SCHEDULER_Task *s_task;
86 * Handle to a request given to the resolver. Can be used to cancel
87 * the request prior to the timeout or successful execution. Also
88 * used to track our internal state for the request.
90 struct GNUNET_RESOLVER_RequestHandle
94 * Next entry in DLL of requests.
96 struct GNUNET_RESOLVER_RequestHandle *next;
99 * Previous entry in DLL of requests.
101 struct GNUNET_RESOLVER_RequestHandle *prev;
104 * Callback if this is an name resolution request,
107 GNUNET_RESOLVER_AddressCallback addr_callback;
110 * Callback if this is a reverse lookup request,
113 GNUNET_RESOLVER_HostnameCallback name_callback;
116 * Closure for the callbacks.
121 * When should this request time out?
123 struct GNUNET_TIME_Absolute timeout;
126 * Task handle for making reply callbacks in numeric lookups
127 * asynchronous, and for timeout handling.
129 struct GNUNET_SCHEDULER_Task *task;
132 * Desired address family.
137 * Has this request been transmitted to the service?
138 * #GNUNET_YES if transmitted
139 * #GNUNET_YES if not transmitted
140 * #GNUNET_SYSERR when request was canceled
145 * Did we add this request to the queue?
150 * Desired direction (IP to name or name to IP)
155 * #GNUNET_YES if a response was received
157 int received_response;
160 * Length of the data that follows this struct.
167 * Check that the resolver service runs on localhost
170 * @return #GNUNET_OK if the resolver is properly configured,
171 * #GNUNET_SYSERR otherwise.
177 struct sockaddr_in v4;
178 struct sockaddr_in6 v6;
180 memset (&v4, 0, sizeof (v4));
181 v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
182 v4.sin_family = AF_INET;
183 #if HAVE_SOCKADDR_IN_SIN_LEN
184 v4.sin_len = sizeof (v4);
186 memset (&v6, 0, sizeof (v6));
187 v6.sin6_family = AF_INET6;
188 #if HAVE_SOCKADDR_IN_SIN_LEN
189 v6.sin6_len = sizeof (v6);
192 GNUNET_CONFIGURATION_get_value_string (resolver_cfg,
197 LOG (GNUNET_ERROR_TYPE_INFO,
198 _("Missing `%s' for `%s' in configuration, DNS resolution will be unavailable.\n"),
201 return GNUNET_SYSERR;
203 if ( (1 == inet_pton (AF_INET, hostname, &v4)) ||
204 (1 == inet_pton (AF_INET6, hostname, &v6)) )
206 GNUNET_free (hostname);
209 for (unsigned int i = 0;
212 if (0 == strcasecmp (loopback[i],
215 GNUNET_free (hostname);
218 LOG (GNUNET_ERROR_TYPE_INFO,
219 _("Missing `%s' or numeric IP address for `%s' of `%s' in configuration, DNS resolution will be unavailable.\n"),
223 GNUNET_free (hostname);
224 return GNUNET_SYSERR;
229 * Create the connection to the resolver service.
231 * @param cfg configuration to use
234 GNUNET_RESOLVER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
236 GNUNET_assert (NULL != cfg);
237 backoff = GNUNET_TIME_UNIT_MILLISECONDS;
243 * Destroy the connection to the resolver service.
246 GNUNET_RESOLVER_disconnect ()
248 struct GNUNET_RESOLVER_RequestHandle *rh;
250 while (NULL != (rh = req_head))
252 GNUNET_assert (GNUNET_SYSERR == rh->was_transmitted);
253 GNUNET_CONTAINER_DLL_remove (req_head,
260 LOG (GNUNET_ERROR_TYPE_DEBUG,
261 "Disconnecting from DNS service\n");
262 GNUNET_MQ_destroy (mq);
267 GNUNET_SCHEDULER_cancel (r_task);
272 GNUNET_SCHEDULER_cancel (s_task);
279 * Task executed on system shutdown.
282 shutdown_task (void *cls)
286 GNUNET_RESOLVER_disconnect ();
287 backoff = GNUNET_TIME_UNIT_MILLISECONDS;
292 * Consider disconnecting if we have no further requests pending.
297 for (struct GNUNET_RESOLVER_RequestHandle *rh = req_head;
300 if (GNUNET_SYSERR != rh->was_transmitted)
304 GNUNET_SCHEDULER_cancel (r_task);
309 s_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
316 * Convert IP address to string without DNS resolution.
318 * @param af address family
319 * @param ip the address
320 * @param ip_len number of bytes in @a ip
321 * @return address as a string, NULL on error
328 char buf[INET6_ADDRSTRLEN];
333 if (ip_len != sizeof (struct in_addr))
341 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
347 if (ip_len != sizeof (struct in6_addr))
355 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
364 return GNUNET_strdup (buf);
369 * Adjust exponential back-off and reconnect to the service.
376 * Generic error handler, called with the appropriate error code and
377 * the same closure specified at the creation of the message queue.
378 * Not every message queue implementation supports an error handler.
381 * @param error error code
384 mq_error_handler (void *cls,
385 enum GNUNET_MQ_Error error)
388 GNUNET_MQ_destroy (mq);
390 LOG (GNUNET_ERROR_TYPE_DEBUG,
391 "MQ error %d, reconnecting\n",
398 * Process pending requests to the resolver.
403 struct GNUNET_RESOLVER_GetMessage *msg;
404 struct GNUNET_MQ_Envelope *env;
405 struct GNUNET_RESOLVER_RequestHandle *rh = req_head;
414 /* nothing to do, release socket really soon if there is nothing
415 * else happening... */
418 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
423 if (GNUNET_NO != rh->was_transmitted)
424 return; /* waiting for reply */
425 env = GNUNET_MQ_msg_extra (msg,
427 GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
428 msg->direction = htonl (rh->direction);
429 msg->af = htonl (rh->af);
430 GNUNET_memcpy (&msg[1],
433 LOG (GNUNET_ERROR_TYPE_DEBUG,
434 "Transmitting DNS resolution request to DNS service\n");
437 rh->was_transmitted = GNUNET_YES;
442 * Check validity of response with a hostname for a DNS lookup.
445 * @param msg message with the hostname
448 check_response (void *cls,
449 const struct GNUNET_MessageHeader *msg)
454 /* implemented in #handle_response() for now */
460 * Check validity of response with a hostname for a DNS lookup.
461 * NOTE: right now rather messy, might want to use different
462 * message types for different response formats in the future.
465 * @param msg message with the response
468 handle_response (void *cls,
469 const struct GNUNET_MessageHeader *msg)
471 struct GNUNET_RESOLVER_RequestHandle *rh = req_head;
478 /* Resolver service sent extra replies to query (after terminator)? Bad! */
480 GNUNET_MQ_destroy (mq);
485 size = ntohs (msg->size);
486 if (size == sizeof (struct GNUNET_MessageHeader))
488 LOG (GNUNET_ERROR_TYPE_DEBUG,
489 "Received empty response from DNS service\n");
490 /* message contains not data, just header; end of replies */
491 /* check if request was canceled */
492 if (GNUNET_SYSERR != rh->was_transmitted)
494 /* no reverse lookup was successful, return IP as string */
495 if (NULL != rh->name_callback)
497 if (GNUNET_NO == rh->received_response)
499 nret = no_resolve (rh->af,
502 rh->name_callback (rh->cls, nret);
505 /* finally, make termination call */
506 if (GNUNET_SYSERR != rh->was_transmitted)
507 rh->name_callback (rh->cls,
510 if ( (NULL != rh->addr_callback) &&
511 (GNUNET_SYSERR != rh->was_transmitted) )
512 rh->addr_callback (rh->cls,
516 rh->was_transmitted = GNUNET_NO;
517 GNUNET_RESOLVER_request_cancel (rh);
521 /* return reverse lookup results to caller */
522 if (NULL != rh->name_callback)
524 const char *hostname;
526 hostname = (const char *) &msg[1];
527 if (hostname[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0')
530 if (GNUNET_SYSERR != rh->was_transmitted)
531 rh->name_callback (rh->cls,
533 rh->was_transmitted = GNUNET_NO;
534 GNUNET_RESOLVER_request_cancel (rh);
535 GNUNET_MQ_destroy (mq);
540 LOG (GNUNET_ERROR_TYPE_DEBUG,
541 "Resolver returns `%s' for IP `%s'.\n",
543 GNUNET_a2s ((const void *) &rh[1],
545 if (rh->was_transmitted != GNUNET_SYSERR)
546 rh->name_callback (rh->cls,
548 rh->received_response = GNUNET_YES;
550 /* return lookup results to caller */
551 if (NULL != rh->addr_callback)
553 struct sockaddr_in v4;
554 struct sockaddr_in6 v6;
555 const struct sockaddr *sa;
561 ip_len = size - sizeof (struct GNUNET_MessageHeader);
562 if (ip_len == sizeof (struct in_addr))
564 memset (&v4, 0, sizeof (v4));
565 v4.sin_family = AF_INET;
566 v4.sin_addr = *(struct in_addr*) ip;
567 #if HAVE_SOCKADDR_IN_SIN_LEN
568 v4.sin_len = sizeof (v4);
571 sa = (const struct sockaddr *) &v4;
573 else if (ip_len == sizeof (struct in6_addr))
575 memset (&v6, 0, sizeof (v6));
576 v6.sin6_family = AF_INET6;
577 v6.sin6_addr = *(struct in6_addr*) ip;
578 #if HAVE_SOCKADDR_IN_SIN_LEN
579 v6.sin6_len = sizeof (v6);
582 sa = (const struct sockaddr *) &v6;
587 if (GNUNET_SYSERR != rh->was_transmitted)
588 rh->addr_callback (rh->cls,
591 rh->was_transmitted = GNUNET_NO;
592 GNUNET_RESOLVER_request_cancel (rh);
593 GNUNET_MQ_destroy (mq);
598 LOG (GNUNET_ERROR_TYPE_DEBUG,
599 "Received IP from DNS service\n");
600 if (GNUNET_SYSERR != rh->was_transmitted)
601 rh->addr_callback (rh->cls,
609 * We've been asked to lookup the address for a hostname and were
610 * given a valid numeric string. Perform the callbacks for the
613 * @param cls `struct GNUNET_RESOLVER_RequestHandle` for the request
616 numeric_resolution (void *cls)
618 struct GNUNET_RESOLVER_RequestHandle *rh = cls;
619 struct sockaddr_in v4;
620 struct sockaddr_in6 v6;
621 const char *hostname;
624 memset (&v4, 0, sizeof (v4));
625 v4.sin_family = AF_INET;
626 #if HAVE_SOCKADDR_IN_SIN_LEN
627 v4.sin_len = sizeof (v4);
629 memset (&v6, 0, sizeof (v6));
630 v6.sin6_family = AF_INET6;
631 #if HAVE_SOCKADDR_IN_SIN_LEN
632 v6.sin6_len = sizeof (v6);
634 hostname = (const char *) &rh[1];
635 if ( ( (rh->af == AF_UNSPEC) ||
636 (rh->af == AF_INET) ) &&
637 (1 == inet_pton (AF_INET,
641 rh->addr_callback (rh->cls,
642 (const struct sockaddr *) &v4,
644 if ( (rh->af == AF_UNSPEC) &&
645 (GNUNET_SYSERR != rh->was_transmitted) &&
646 (1 == inet_pton (AF_INET6,
650 /* this can happen on some systems IF "hostname" is "localhost" */
651 rh->addr_callback (rh->cls,
652 (const struct sockaddr *) &v6,
655 if (GNUNET_SYSERR != rh->was_transmitted)
656 rh->addr_callback (rh->cls,
662 if ( ( (rh->af == AF_UNSPEC) ||
663 (rh->af == AF_INET6) ) &&
664 (1 == inet_pton (AF_INET6,
668 rh->addr_callback (rh->cls,
669 (const struct sockaddr *) &v6,
671 if (GNUNET_SYSERR != rh->was_transmitted)
672 rh->addr_callback (rh->cls,
678 /* why are we here? this task should not have been scheduled! */
685 * We've been asked to lookup the address for a hostname and were
686 * given a variant of "loopback". Perform the callbacks for the
687 * respective loopback numeric addresses.
689 * @param cls `struct GNUNET_RESOLVER_RequestHandle` for the request
692 loopback_resolution (void *cls)
694 struct GNUNET_RESOLVER_RequestHandle *rh = cls;
695 struct sockaddr_in v4;
696 struct sockaddr_in6 v6;
699 memset (&v4, 0, sizeof (v4));
700 v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
701 v4.sin_family = AF_INET;
702 #if HAVE_SOCKADDR_IN_SIN_LEN
703 v4.sin_len = sizeof (v4);
705 memset (&v6, 0, sizeof (v6));
706 v6.sin6_family = AF_INET6;
707 #if HAVE_SOCKADDR_IN_SIN_LEN
708 v6.sin6_len = sizeof (v6);
710 v6.sin6_addr = in6addr_loopback;
714 rh->addr_callback (rh->cls,
715 (const struct sockaddr *) &v4,
719 rh->addr_callback (rh->cls,
720 (const struct sockaddr *) &v6,
724 rh->addr_callback (rh->cls,
725 (const struct sockaddr *) &v6,
727 rh->addr_callback (rh->cls,
728 (const struct sockaddr *) &v4,
736 if (GNUNET_SYSERR != rh->was_transmitted)
737 rh->addr_callback (rh->cls,
740 LOG (GNUNET_ERROR_TYPE_DEBUG,
741 "Finished resolving hostname `%s'.\n",
742 (const char *) &rh[1]);
748 * Now try to reconnect to the resolver service.
753 reconnect_task (void *cls)
755 struct GNUNET_MQ_MessageHandler handlers[] = {
756 GNUNET_MQ_hd_var_size (response,
757 GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE,
758 struct GNUNET_MessageHeader,
760 GNUNET_MQ_handler_end ()
765 if (NULL == req_head)
766 return; /* no work pending */
767 LOG (GNUNET_ERROR_TYPE_DEBUG,
768 "Trying to connect to DNS service\n");
769 mq = GNUNET_CLIENT_connect (resolver_cfg,
776 LOG (GNUNET_ERROR_TYPE_DEBUG,
777 "Failed to connect, will try again later\n");
786 * Adjust exponential back-off and reconnect to the service.
791 struct GNUNET_RESOLVER_RequestHandle *rh;
795 GNUNET_assert (NULL == mq);
796 if (NULL != (rh = req_head))
798 switch (rh->was_transmitted)
801 /* nothing more to do */
804 /* disconnected, transmit again! */
805 rh->was_transmitted = GNUNET_NO;
808 /* request was cancelled, remove entirely */
809 GNUNET_CONTAINER_DLL_remove (req_head,
820 LOG (GNUNET_ERROR_TYPE_DEBUG,
821 "Will try to connect to DNS service in %s\n",
822 GNUNET_STRINGS_relative_time_to_string (backoff,
824 GNUNET_assert (NULL != resolver_cfg);
825 r_task = GNUNET_SCHEDULER_add_delayed (backoff,
828 backoff = GNUNET_TIME_STD_BACKOFF (backoff);
833 * A DNS resolution timed out. Notify the application.
835 * @param cls the `struct GNUNET_RESOLVER_RequestHandle *`
838 handle_lookup_timeout (void *cls)
840 struct GNUNET_RESOLVER_RequestHandle *rh = cls;
843 if (GNUNET_NO == rh->direction)
845 LOG (GNUNET_ERROR_TYPE_INFO,
846 _("Timeout trying to resolve hostname `%s'.\n"),
847 (const char *) &rh[1]);
848 if (NULL != rh->addr_callback)
849 rh->addr_callback (rh->cls,
855 #if !defined(GNUNET_CULL_LOGGING)
856 char buf[INET6_ADDRSTRLEN];
858 LOG (GNUNET_ERROR_TYPE_INFO,
859 _("Timeout trying to resolve IP address `%s'.\n"),
861 (const void *) &rh[1],
865 if (GNUNET_NO == rh->received_response)
869 nret = no_resolve (rh->af,
872 if (NULL != rh->name_callback)
873 rh->name_callback (rh->cls, nret);
876 /* finally, make termination call */
877 if (NULL != rh->name_callback)
878 rh->name_callback (rh->cls,
881 rh->was_transmitted = GNUNET_NO;
882 GNUNET_RESOLVER_request_cancel (rh);
888 * Convert a string to one or more IP addresses.
890 * @param hostname the hostname to resolve
891 * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any"
892 * @param callback function to call with addresses
893 * @param callback_cls closure for @a callback
894 * @param timeout how long to try resolving
895 * @return handle that can be used to cancel the request, NULL on error
897 struct GNUNET_RESOLVER_RequestHandle *
898 GNUNET_RESOLVER_ip_get (const char *hostname,
900 struct GNUNET_TIME_Relative timeout,
901 GNUNET_RESOLVER_AddressCallback callback,
904 struct GNUNET_RESOLVER_RequestHandle *rh;
909 slen = strlen (hostname) + 1;
910 if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) >=
911 GNUNET_MAX_MESSAGE_SIZE)
916 LOG (GNUNET_ERROR_TYPE_DEBUG,
917 "Trying to resolve hostname `%s'.\n",
919 rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + slen);
921 rh->addr_callback = callback;
922 rh->cls = callback_cls;
923 GNUNET_memcpy (&rh[1],
927 rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
928 rh->direction = GNUNET_NO;
929 /* first, check if this is a numeric address */
930 if ( ( (1 == inet_pton (AF_INET,
934 (af == AF_UNSPEC) ) ) ||
935 ( (1 == inet_pton (AF_INET6,
938 ( (af == AF_INET6) ||
939 (af == AF_UNSPEC)) ) )
941 rh->task = GNUNET_SCHEDULER_add_now (&numeric_resolution,
945 /* then, check if this is a loopback address */
946 for (unsigned int i = 0;
949 if (0 == strcasecmp (loopback[i],
952 rh->task = GNUNET_SCHEDULER_add_now (&loopback_resolution,
956 if (GNUNET_OK != check_config ())
961 rh->task = GNUNET_SCHEDULER_add_delayed (timeout,
962 &handle_lookup_timeout,
964 GNUNET_CONTAINER_DLL_insert_tail (req_head,
967 rh->was_queued = GNUNET_YES;
970 GNUNET_SCHEDULER_cancel (s_task);
979 * We've been asked to convert an address to a string without
980 * a reverse lookup, either because the client asked for it
981 * or because the DNS lookup hit a timeout. Do the numeric
982 * conversion and invoke the callback.
984 * @param cls `struct GNUNET_RESOLVER_RequestHandle` for the request
987 numeric_reverse (void *cls)
989 struct GNUNET_RESOLVER_RequestHandle *rh = cls;
993 result = no_resolve (rh->af,
996 LOG (GNUNET_ERROR_TYPE_DEBUG,
997 "Resolver returns `%s'.\n",
1001 rh->name_callback (rh->cls,
1003 GNUNET_free (result);
1005 rh->name_callback (rh->cls,
1007 if (NULL != rh->task)
1009 GNUNET_SCHEDULER_cancel (rh->task);
1017 * Get an IP address as a string.
1019 * @param sa host address
1020 * @param salen length of host address in @a sa
1021 * @param do_resolve use #GNUNET_NO to return numeric hostname
1022 * @param timeout how long to try resolving
1023 * @param callback function to call with hostnames
1024 * last callback is NULL when finished
1025 * @param cls closure for @a callback
1026 * @return handle that can be used to cancel the request
1028 struct GNUNET_RESOLVER_RequestHandle *
1029 GNUNET_RESOLVER_hostname_get (const struct sockaddr *sa,
1032 struct GNUNET_TIME_Relative timeout,
1033 GNUNET_RESOLVER_HostnameCallback callback,
1036 struct GNUNET_RESOLVER_RequestHandle *rh;
1040 if (GNUNET_OK != check_config ())
1042 LOG (GNUNET_ERROR_TYPE_ERROR,
1043 _("Resolver not configured correctly.\n"));
1047 switch (sa->sa_family)
1050 GNUNET_assert (salen == sizeof (struct sockaddr_in));
1051 ip_len = sizeof (struct in_addr);
1052 ip = &((const struct sockaddr_in*)sa)->sin_addr;
1055 GNUNET_assert (salen == sizeof (struct sockaddr_in6));
1056 ip_len = sizeof (struct in6_addr);
1057 ip = &((const struct sockaddr_in6*)sa)->sin6_addr;
1063 rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + salen);
1064 rh->name_callback = callback;
1066 rh->af = sa->sa_family;
1067 rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1068 GNUNET_memcpy (&rh[1],
1071 rh->data_len = ip_len;
1072 rh->direction = GNUNET_YES;
1073 rh->received_response = GNUNET_NO;
1074 if (GNUNET_NO == do_resolve)
1076 rh->task = GNUNET_SCHEDULER_add_now (&numeric_reverse,
1080 rh->task = GNUNET_SCHEDULER_add_delayed (timeout,
1081 &handle_lookup_timeout,
1083 GNUNET_CONTAINER_DLL_insert_tail (req_head,
1086 rh->was_queued = GNUNET_YES;
1089 GNUNET_SCHEDULER_cancel (s_task);
1092 process_requests ();
1098 * Get local fully qualified af name
1103 GNUNET_RESOLVER_local_fqdn_get ()
1105 char hostname[GNUNET_OS_get_hostname_max_length () + 1];
1107 if (0 != gethostname (hostname,
1108 sizeof (hostname) - 1))
1110 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1114 LOG (GNUNET_ERROR_TYPE_DEBUG,
1115 "Resolving our FQDN `%s'\n",
1117 #if HAVE_GETADDRINFO
1119 struct addrinfo *ai;
1123 if (0 != (ret = getaddrinfo (hostname,
1128 LOG (GNUNET_ERROR_TYPE_ERROR,
1129 _("Could not resolve our FQDN: %s\n"),
1130 gai_strerror (ret));
1133 if (NULL != ai->ai_canonname)
1134 rval = GNUNET_strdup (ai->ai_canonname);
1136 rval = GNUNET_strdup (hostname);
1140 #elif HAVE_GETHOSTBYNAME2
1142 struct hostent *host;
1144 host = gethostbyname2 (hostname,
1147 host = gethostbyname2 (hostname,
1151 LOG (GNUNET_ERROR_TYPE_ERROR,
1152 _("Could not resolve our FQDN: %s\n"),
1153 hstrerror (h_errno));
1156 return GNUNET_strdup (host->h_name);
1158 #elif HAVE_GETHOSTBYNAME
1160 struct hostent *host;
1162 host = gethostbyname (hostname);
1165 LOG (GNUNET_ERROR_TYPE_ERROR,
1166 _("Could not resolve our FQDN: %s\n"),
1167 hstrerror (h_errno));
1170 return GNUNET_strdup (host->h_name);
1173 /* fallback: just hope name is already FQDN */
1174 return GNUNET_strdup (hostname);
1180 * Looking our own hostname.
1182 * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any"
1183 * @param timeout how long to try resolving
1184 * @param callback function to call with addresses
1185 * @param cls closure for @a callback
1186 * @return handle that can be used to cancel the request, NULL on error
1188 struct GNUNET_RESOLVER_RequestHandle *
1189 GNUNET_RESOLVER_hostname_resolve (int af,
1190 struct GNUNET_TIME_Relative timeout,
1191 GNUNET_RESOLVER_AddressCallback callback,
1194 char hostname[GNUNET_OS_get_hostname_max_length () + 1];
1196 if (0 != gethostname (hostname, sizeof (hostname) - 1))
1198 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
1202 LOG (GNUNET_ERROR_TYPE_DEBUG,
1203 "Resolving our hostname `%s'\n",
1205 return GNUNET_RESOLVER_ip_get (hostname,
1214 * Cancel a request that is still pending with the resolver.
1215 * Note that a client MUST NOT cancel a request that has
1216 * been completed (i.e, the callback has been called to
1217 * signal timeout or the final result).
1219 * @param rh handle of request to cancel
1222 GNUNET_RESOLVER_request_cancel (struct GNUNET_RESOLVER_RequestHandle *rh)
1224 if (GNUNET_NO == rh->direction)
1225 LOG (GNUNET_ERROR_TYPE_DEBUG,
1226 "Asked to cancel request to resolve hostname `%s'.\n",
1227 (const char *) &rh[1]);
1228 if (NULL != rh->task)
1230 GNUNET_SCHEDULER_cancel (rh->task);
1233 if (GNUNET_NO == rh->was_transmitted)
1235 if (GNUNET_YES == rh->was_queued)
1236 GNUNET_CONTAINER_DLL_remove (req_head,
1240 check_disconnect ();
1243 GNUNET_assert (GNUNET_YES == rh->was_transmitted);
1244 rh->was_transmitted = GNUNET_SYSERR; /* mark as cancelled */
1245 check_disconnect ();
1249 /* end of resolver_api.c */