newline
[oweals/gnunet.git] / src / util / resolver_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009 Christian Grothoff (and other contributing authors)
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 2, 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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, 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_getopt_lib.h"
28 #include "gnunet_os_lib.h"
29 #include "gnunet_client_lib.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_resolver_service.h"
32 #include "gnunet_server_lib.h"
33 #include "resolver.h"
34
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  * Handle to a request given to the resolver.  Can be used to cancel
54  * the request prior to the timeout or successful execution.  Also
55  * used to track our internal state for the request.
56  */
57 struct GNUNET_RESOLVER_RequestHandle
58 {
59
60   /**
61    * Callback if this is an name resolution request,
62    * otherwise NULL.
63    */
64   GNUNET_RESOLVER_AddressCallback addr_callback;
65
66   /**
67    * Callback if this is a reverse lookup request,
68    * otherwise NULL.
69    */
70   GNUNET_RESOLVER_HostnameCallback name_callback;
71
72   /**
73    * Closure for the respective "callback".
74    */
75   void *cls;
76
77   /**
78    * Our connection to the resolver service.
79    */
80   struct GNUNET_CLIENT_Connection *client;
81
82   /**
83    * Our scheduler.
84    */
85   struct GNUNET_SCHEDULER_Handle *sched;
86
87   /**
88    * Name of the host that we are resolving.
89    */
90   const char *hostname;
91
92   /**
93    * When should this request time out?
94    */
95   struct GNUNET_TIME_Absolute timeout;
96
97   /**
98    * Task handle for numeric lookups.
99    */
100   GNUNET_SCHEDULER_TaskIdentifier task;
101
102   /**
103    * Desired address family.
104    */
105   int domain;
106
107   /**
108    * Length of the "struct sockaddr" that follows this
109    * struct (only for reverse lookup).
110    */
111   socklen_t salen;
112 };
113
114
115 /**
116  * Check that the resolver service runs on localhost
117  * (or equivalent).
118  */
119 static void
120 check_config (const struct GNUNET_CONFIGURATION_Handle *cfg)
121 {
122   char *hostname;
123   unsigned int i;
124   struct sockaddr_in v4;
125   struct sockaddr_in6 v6;
126
127   memset (&v4, 0, sizeof (v4));
128   v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
129   v4.sin_family = AF_INET;
130 #if HAVE_SOCKADDR_IN_SIN_LEN
131   v4.sin_len = sizeof (v4);
132 #endif
133   memset (&v6, 0, sizeof (v6));
134   v6.sin6_family = AF_INET6;
135 #if HAVE_SOCKADDR_IN_SIN_LEN
136   v6.sin6_len = sizeof (v6);
137 #endif
138   if (GNUNET_OK !=
139       GNUNET_CONFIGURATION_get_value_string (cfg,
140                                              "resolver",
141                                              "HOSTNAME", &hostname))
142     {
143       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
144                   _("Must specify `%s' for `%s' in configuration!\n"),
145                   "HOSTNAME", "resolver");
146       GNUNET_assert (0);
147     }
148   if ((1 != inet_pton (AF_INET,
149                        hostname,
150                        &v4)) || (1 != inet_pton (AF_INET6, hostname, &v6)))
151     {
152       GNUNET_free (hostname);
153       return;
154     }
155   i = 0;
156   while (loopback[i] != NULL)
157     if (0 == strcasecmp (loopback[i++], hostname))
158       {
159         GNUNET_free (hostname);
160         return;
161       }
162   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
163               _
164               ("Must specify `%s' or numeric IP address for `%s' of `%s' in configuration!\n"),
165               "localhost", "HOSTNAME", "resolver");
166   GNUNET_free (hostname);
167   GNUNET_assert (0);
168 }
169
170
171 /**
172  * Convert IP address to string without DNS resolution.
173  *
174  * @param sa the address 
175  * @param salen number of bytes in sa
176  * @return address as a string, NULL on error
177  */
178 static char *
179 no_resolve (const struct sockaddr *sa, socklen_t salen)
180 {
181   char *ret;
182   char inet4[INET_ADDRSTRLEN];
183   char inet6[INET6_ADDRSTRLEN];
184
185   if (salen < sizeof (struct sockaddr))
186     return NULL;
187   switch (sa->sa_family)
188     {
189     case AF_INET:
190       if (salen != sizeof (struct sockaddr_in))
191         return NULL;
192       inet_ntop (AF_INET,
193                  &((struct sockaddr_in *) sa)->sin_addr,
194                  inet4, INET_ADDRSTRLEN);
195       ret = GNUNET_strdup (inet4);
196       break;
197     case AF_INET6:
198       if (salen != sizeof (struct sockaddr_in6))
199         return NULL;
200       inet_ntop (AF_INET6,
201                  &((struct sockaddr_in6 *) sa)->sin6_addr,
202                  inet6, INET6_ADDRSTRLEN);
203       ret = GNUNET_strdup (inet6);
204       break;
205     default:
206       ret = NULL;
207       break;
208     }
209   return ret;
210 }
211
212
213 /**
214  * Process the reply from the resolver (which is presumably
215  * the numeric IP address for a name resolution request).
216  *
217  * @param cls the "GNUNET_RESOLVER_RequestHandle" for which this is a reply
218  * @param msg reply from the resolver or NULL on error
219  */
220 static void
221 handle_address_response (void *cls, const struct GNUNET_MessageHeader *msg)
222 {
223   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
224   uint16_t size;
225   const struct sockaddr *sa;
226   socklen_t salen;
227
228   if (msg == NULL)
229     {
230       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
231                   _("Timeout trying to resolve hostname `%s'.\n"),
232                   rh->hostname);
233       rh->addr_callback (rh->cls, NULL, 0);
234       GNUNET_CLIENT_disconnect (rh->client, GNUNET_NO);
235       GNUNET_free (rh);
236       return;
237     }
238   if (GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE != ntohs (msg->type))
239     {
240       GNUNET_break (0);
241       rh->addr_callback (rh->cls, NULL, 0);
242       GNUNET_CLIENT_disconnect (rh->client, GNUNET_NO);
243       GNUNET_free (rh);
244       return;
245     }
246
247   size = ntohs (msg->size);
248   if (size == sizeof (struct GNUNET_MessageHeader))
249     {
250 #if DEBUG_RESOLVER
251       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
252                   _("Received end message resolving hostname `%s'.\n"),
253                   rh->hostname);
254 #endif
255       rh->addr_callback (rh->cls, NULL, 0);
256       GNUNET_CLIENT_disconnect (rh->client, GNUNET_NO);
257       GNUNET_free (rh);
258       return;
259     }
260   sa = (const struct sockaddr *) &msg[1];
261   salen = size - sizeof (struct GNUNET_MessageHeader);
262   if (salen < sizeof (struct sockaddr))
263     {
264       GNUNET_break (0);
265       rh->addr_callback (rh->cls, NULL, 0);
266       GNUNET_CLIENT_disconnect (rh->client, GNUNET_NO);
267       GNUNET_free (rh);
268       return;
269     }
270 #if DEBUG_RESOLVER
271   {
272     char *ips = no_resolve (sa, salen);
273     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
274                 "Resolver returns `%s' for `%s'.\n", ips,
275                 rh->hostname);
276     GNUNET_free (ips);
277   }
278 #endif
279   rh->addr_callback (rh->cls, sa, salen);
280   GNUNET_CLIENT_receive (rh->client,
281                          &handle_address_response,
282                          rh,
283                          GNUNET_TIME_absolute_get_remaining (rh->timeout));
284 }
285
286
287 /**
288  * We've been asked to lookup the address for a hostname and were 
289  * given a valid numeric string.  Perform the callbacks for the
290  * numeric addresses.
291  *
292  * @param cls struct GNUNET_RESOLVER_RequestHandle for the request
293  * @param tc unused scheduler context
294  */
295 static void
296 numeric_resolution (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
297 {
298   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
299   struct sockaddr_in v4;
300   struct sockaddr_in6 v6;
301
302   memset (&v4, 0, sizeof (v4));
303   v4.sin_family = AF_INET;
304 #if HAVE_SOCKADDR_IN_SIN_LEN
305   v4.sin_len = sizeof (v4);
306 #endif
307   memset (&v6, 0, sizeof (v6));
308   v6.sin6_family = AF_INET6;
309 #if HAVE_SOCKADDR_IN_SIN_LEN
310   v6.sin6_len = sizeof (v6);
311 #endif
312
313   if (((rh->domain == AF_UNSPEC) || (rh->domain == AF_INET)) &&
314       (1 == inet_pton (AF_INET, rh->hostname, &v4.sin_addr)))
315     {
316       rh->addr_callback (rh->cls, (const struct sockaddr *) &v4, sizeof (v4));
317       if ((rh->domain == AF_UNSPEC) &&
318           (1 == inet_pton (AF_INET6, rh->hostname, &v6.sin6_addr)))
319         {
320           /* this can happen on some systems IF "hostname" is "localhost" */
321           rh->addr_callback (rh->cls,
322                              (const struct sockaddr *) &v6, sizeof (v6));
323         }
324       rh->addr_callback (rh->cls, NULL, 0);
325       GNUNET_free (rh);
326       return;
327     }
328   if (((rh->domain == AF_UNSPEC) || (rh->domain == AF_INET6)) &&
329       (1 == inet_pton (AF_INET6, rh->hostname, &v6.sin6_addr)))
330     {
331       rh->addr_callback (rh->cls, (const struct sockaddr *) &v6, sizeof (v6));
332       rh->addr_callback (rh->cls, NULL, 0);
333       GNUNET_free (rh);
334       return;
335     }
336   /* why are we here? this task should not have been scheduled! */
337   GNUNET_assert (0);
338   GNUNET_free (rh);
339 }
340
341
342
343 /**
344  * We've been asked to lookup the address for a hostname and were 
345  * given a variant of "loopback".  Perform the callbacks for the
346  * respective loopback numeric addresses.
347  *
348  * @param cls struct GNUNET_RESOLVER_RequestHandle for the request
349  * @param tc unused scheduler context
350  */
351 static void
352 loopback_resolution (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
353 {
354   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
355   struct sockaddr_in v4;
356   struct sockaddr_in6 v6;
357
358   memset (&v4, 0, sizeof (v4));
359   v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
360   v4.sin_family = AF_INET;
361 #if HAVE_SOCKADDR_IN_SIN_LEN
362   v4.sin_len = sizeof (v4);
363 #endif
364   memset (&v6, 0, sizeof (v6));
365   v6.sin6_family = AF_INET6;
366 #if HAVE_SOCKADDR_IN_SIN_LEN
367   v6.sin6_len = sizeof (v6);
368 #endif
369   v6.sin6_addr = in6addr_loopback;
370   switch (rh->domain)
371     {
372     case AF_INET:
373       rh->addr_callback (rh->cls, (const struct sockaddr *) &v4, sizeof (v4));
374       break;
375     case AF_INET6:
376       rh->addr_callback (rh->cls, (const struct sockaddr *) &v6, sizeof (v6));
377       break;
378     case AF_UNSPEC:
379       rh->addr_callback (rh->cls, (const struct sockaddr *) &v6, sizeof (v6));
380       rh->addr_callback (rh->cls, (const struct sockaddr *) &v4, sizeof (v4));
381       break;
382     default:
383       GNUNET_break (0);
384       break;
385     }
386   rh->addr_callback (rh->cls, NULL, 0);
387   GNUNET_free (rh);
388 }
389
390
391 /**
392  * Convert a string to one or more IP addresses.
393  *
394  * @param sched scheduler to use
395  * @param cfg configuration to use
396  * @param hostname the hostname to resolve
397  * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any"
398  * @param callback function to call with addresses
399  * @param callback_cls closure for callback
400  * @param timeout how long to try resolving
401  * @return handle that can be used to cancel the request, NULL on error
402  */
403 struct GNUNET_RESOLVER_RequestHandle *
404 GNUNET_RESOLVER_ip_get (struct GNUNET_SCHEDULER_Handle *sched,
405                         const struct GNUNET_CONFIGURATION_Handle *cfg,
406                         const char *hostname,
407                         int domain,
408                         struct GNUNET_TIME_Relative timeout,
409                         GNUNET_RESOLVER_AddressCallback callback,
410                         void *callback_cls)
411 {
412   struct GNUNET_CLIENT_Connection *client;
413   struct GNUNET_RESOLVER_GetMessage *msg;
414   struct GNUNET_RESOLVER_RequestHandle *rh;
415   size_t slen;
416   unsigned int i;
417   struct in_addr v4;
418   struct in6_addr v6;
419   char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE];
420
421   check_config (cfg);
422   slen = strlen (hostname) + 1;
423   if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) >
424       GNUNET_SERVER_MAX_MESSAGE_SIZE)
425     {
426       GNUNET_break (0);
427       return NULL;
428     }
429   rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + slen);
430   rh->sched = sched;
431   rh->domain = domain;
432   rh->addr_callback = callback;
433   rh->cls = callback_cls;
434   memcpy (&rh[1], hostname, slen);
435   rh->hostname = (const char *) &rh[1];
436   rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
437
438   /* first, check if this is a numeric address */
439   if (((1 == inet_pton (AF_INET,
440                         hostname,
441                         &v4)) &&
442        ((domain == AF_INET) || (domain == AF_UNSPEC))) ||
443       ((1 == inet_pton (AF_INET6,
444                         hostname,
445                         &v6)) &&
446        ((domain == AF_INET6) || (domain == AF_UNSPEC))))
447     {
448       rh->task = GNUNET_SCHEDULER_add_now (sched,
449                                            &numeric_resolution, rh);
450       return rh;
451     }
452   /* then, check if this is a loopback address */
453   i = 0;
454   while (loopback[i] != NULL)
455     if (0 == strcasecmp (loopback[i++], hostname))
456       {
457         rh->task = GNUNET_SCHEDULER_add_now (sched,
458                                              &loopback_resolution, rh);
459         return rh;
460       }
461
462   client = GNUNET_CLIENT_connect (sched, "resolver", cfg);
463   if (client == NULL)
464     {
465       GNUNET_free (rh);
466       return NULL;
467     }
468   rh->client = client;
469
470   msg = (struct GNUNET_RESOLVER_GetMessage *) buf;
471   msg->header.size =
472     htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + slen);
473   msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
474   msg->direction = htonl (GNUNET_NO);
475   msg->domain = htonl (domain);
476   memcpy (&msg[1], hostname, slen);
477
478 #if DEBUG_RESOLVER
479   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
480               _("Resolver requests DNS resolution of hostname `%s'.\n"),
481               hostname);
482 #endif
483   if (GNUNET_OK !=
484       GNUNET_CLIENT_transmit_and_get_response (client,
485                                                &msg->header,
486                                                timeout,
487                                                GNUNET_YES,
488                                                &handle_address_response, rh))
489     {
490       GNUNET_free (rh);
491       GNUNET_CLIENT_disconnect (client, GNUNET_NO);
492       return NULL;
493     }
494   return rh;
495 }
496
497
498 /**
499  * Process response with a hostname for a reverse DNS lookup.
500  *
501  * @param cls our "struct GNUNET_RESOLVER_RequestHandle" context
502  * @param msg message with the hostname, NULL on error
503  */
504 static void
505 handle_hostname_response (void *cls, const struct GNUNET_MessageHeader *msg)
506 {
507   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
508   uint16_t size;
509   const char *hostname;
510
511   if (msg == NULL)
512     {
513       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
514                   _("Timeout trying to resolve IP address `%s'.\n"),
515                   GNUNET_a2s ((const void*) &rh[1], rh->salen));
516       rh->name_callback (rh->cls, NULL);
517       GNUNET_CLIENT_disconnect (rh->client, GNUNET_NO);
518       GNUNET_free (rh);
519       return;
520     }
521   size = ntohs (msg->size);
522   if (size == sizeof (struct GNUNET_MessageHeader))
523     {
524 #if DEBUG_RESOLVER
525       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
526                   _("Received end message resolving IP address `%s'.\n"),
527                   GNUNET_a2s ((const void*) &rh[1], rh->salen));
528 #endif
529       rh->name_callback (rh->cls, NULL);
530       GNUNET_CLIENT_disconnect (rh->client, GNUNET_NO);
531       GNUNET_free (rh);
532       return;
533     }
534   hostname = (const char *) &msg[1];
535   if (hostname[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0')
536     {
537       GNUNET_break (0);
538       rh->name_callback (rh->cls, NULL);
539       GNUNET_CLIENT_disconnect (rh->client, GNUNET_NO);
540       GNUNET_free (rh);
541       return;
542     }
543 #if DEBUG_RESOLVER
544   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
545               _("Resolver returns `%s' for IP `%s'.\n"), 
546               hostname,
547               GNUNET_a2s ((const void*) &rh[1], rh->salen));
548 #endif
549   rh->name_callback (rh->cls, hostname);
550   GNUNET_CLIENT_receive (rh->client,
551                          &handle_hostname_response,
552                          rh,
553                          GNUNET_TIME_absolute_get_remaining (rh->timeout));
554 }
555
556
557
558 /**
559  * We've been asked to convert an address to a string without
560  * a reverse lookup.  Do it.
561  *
562  * @param cls struct GNUNET_RESOLVER_RequestHandle for the request
563  * @param tc unused scheduler context
564  */
565 static void
566 numeric_reverse (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
567 {
568   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
569   char *result;
570
571   result = no_resolve ((const struct sockaddr *) &rh[1], rh->salen);
572 #if DEBUG_RESOLVER
573   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Resolver returns `%s'.\n"), result);
574 #endif
575   if (result != NULL)
576     {
577       rh->name_callback (rh->cls, result);
578       GNUNET_free (result);
579     }
580   rh->name_callback (rh->cls, NULL);
581   GNUNET_free (rh);
582 }
583
584
585
586 /**
587  * Get an IP address as a string.
588  *
589  * @param sched scheduler to use
590  * @param cfg configuration to use
591  * @param sa host address
592  * @param salen length of host address
593  * @param do_resolve use GNUNET_NO to return numeric hostname
594  * @param timeout how long to try resolving
595  * @param callback function to call with hostnames
596  * @param cls closure for callback
597  * @return handle that can be used to cancel the request
598  */
599 struct GNUNET_RESOLVER_RequestHandle *
600 GNUNET_RESOLVER_hostname_get (struct GNUNET_SCHEDULER_Handle *sched,
601                               const struct GNUNET_CONFIGURATION_Handle *cfg,
602                               const struct sockaddr *sa,
603                               socklen_t salen,
604                               int do_resolve,
605                               struct GNUNET_TIME_Relative timeout,
606                               GNUNET_RESOLVER_HostnameCallback callback,
607                               void *cls)
608 {
609   struct GNUNET_CLIENT_Connection *client;
610   struct GNUNET_RESOLVER_GetMessage *msg;
611   struct GNUNET_RESOLVER_RequestHandle *rh;
612   char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE];
613
614   check_config (cfg);
615   rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + salen);
616   rh->name_callback = callback;
617   rh->cls = cls;
618   rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
619   rh->sched = sched;
620   rh->salen = salen;
621   memcpy (&rh[1], sa, salen);
622
623   if (GNUNET_NO == do_resolve)
624     {
625       rh->task = GNUNET_SCHEDULER_add_now (sched,
626                                            &numeric_reverse, rh);
627       return rh;
628     }
629   if (salen + sizeof (struct GNUNET_RESOLVER_GetMessage) >
630       GNUNET_SERVER_MAX_MESSAGE_SIZE)
631     {
632       GNUNET_break (0);
633       GNUNET_free (rh);
634       return NULL;
635     }
636   client = GNUNET_CLIENT_connect (sched, "resolver", cfg);
637   if (client == NULL)
638     {
639       GNUNET_free (rh);
640       return NULL;
641     }
642   rh->client = client;
643
644   msg = (struct GNUNET_RESOLVER_GetMessage *) buf;
645   msg->header.size =
646     htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + salen);
647   msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
648   msg->direction = htonl (GNUNET_YES);
649   msg->domain = htonl (sa->sa_family);
650   memcpy (&msg[1], sa, salen);
651 #if DEBUG_RESOLVER
652   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
653               _("Resolver requests DNS resolution of IP address.\n"));
654 #endif
655   if (GNUNET_OK !=
656       GNUNET_CLIENT_transmit_and_get_response (client,
657                                                &msg->header,
658                                                timeout,
659                                                GNUNET_YES,
660                                                &handle_hostname_response, rh))
661     {
662       GNUNET_CLIENT_disconnect (client, GNUNET_NO);
663       GNUNET_free (rh);
664       return NULL;
665     }
666   return rh;
667 }
668
669
670 /**
671  * Get local fully qualified domain name
672  * @return fqdn
673  */
674 char *
675 GNUNET_RESOLVER_local_fqdn_get ( void )
676 {
677   struct hostent *host;
678   char hostname[GNUNET_OS_get_hostname_max_length() + 1];
679
680
681   if (0 != gethostname (hostname, sizeof (hostname) - 1))
682     {
683       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR |
684                            GNUNET_ERROR_TYPE_BULK, "gethostname");
685       return NULL;
686     }
687 #if DEBUG_RESOLVER
688   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
689               _("Resolving our FQDN `%s'\n"), hostname);
690 #endif
691   host = gethostbyname ( hostname );
692   if ( NULL == host)
693   {
694     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
695                 _("Could not resolve our FQDN : %s\n"),
696                 hstrerror (h_errno));
697     return NULL;
698   }
699   return GNUNET_strdup (host->h_name);
700 }
701
702 /**
703  * Looking our own hostname.
704  *
705  * @param sched scheduler to use
706  * @param cfg configuration to use
707  * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any"
708  * @param callback function to call with addresses
709  * @param cls closure for callback
710  * @param timeout how long to try resolving
711  * @return handle that can be used to cancel the request, NULL on error
712  */
713 struct GNUNET_RESOLVER_RequestHandle *
714 GNUNET_RESOLVER_hostname_resolve (struct GNUNET_SCHEDULER_Handle *sched,
715                                   const struct GNUNET_CONFIGURATION_Handle
716                                   *cfg, int domain,
717                                   struct GNUNET_TIME_Relative timeout,
718                                   GNUNET_RESOLVER_AddressCallback callback,
719                                   void *cls)
720 {
721   char hostname[GNUNET_OS_get_hostname_max_length() + 1];
722
723   check_config (cfg);
724   if (0 != gethostname (hostname, sizeof (hostname) - 1))
725     {
726       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR |
727                            GNUNET_ERROR_TYPE_BULK, "gethostname");
728       return NULL;
729     }
730 #if DEBUG_RESOLVER
731   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
732               _("Resolving our hostname `%s'\n"), hostname);
733 #endif
734   return GNUNET_RESOLVER_ip_get (sched,
735                                  cfg, hostname, domain, timeout, callback,
736                                  cls);
737 }
738
739
740 /**
741  * Cancel a request that is still pending with the resolver.
742  * Note that a client MUST NOT cancel a request that has
743  * been completed (i.e, the callback has been called to
744  * signal timeout or the final result).
745  *
746  * @param h handle of request to cancel
747  */
748 void
749 GNUNET_RESOLVER_request_cancel (struct GNUNET_RESOLVER_RequestHandle *h)
750 {
751   if (h->client != NULL)
752     GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
753   if (h->task != GNUNET_SCHEDULER_NO_TASK)
754     GNUNET_SCHEDULER_cancel (h->sched, h->task);
755   GNUNET_free (h);
756 }
757
758
759
760 /* end of resolver_api.c */