f4844a490ef8aec20bd0ca0506033cbb529a4018
[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
229   if (msg == NULL)
230     {
231       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
232                   _("Timeout trying to resolve hostname `%s'.\n"),
233                   rh->hostname);
234       rh->addr_callback (rh->cls, NULL, 0);
235       GNUNET_CLIENT_disconnect (rh->client, GNUNET_NO);
236       GNUNET_free (rh);
237       return;
238     }
239   if (GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE != ntohs (msg->type))
240     {
241       GNUNET_break (0);
242       rh->addr_callback (rh->cls, NULL, 0);
243       GNUNET_CLIENT_disconnect (rh->client, GNUNET_NO);
244       GNUNET_free (rh);
245       return;
246     }
247
248   size = ntohs (msg->size);
249   if (size == sizeof (struct GNUNET_MessageHeader))
250     {
251 #if DEBUG_RESOLVER
252       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
253                   _("Received end message resolving hostname `%s'.\n"),
254                   rh->hostname);
255 #endif
256       rh->addr_callback (rh->cls, NULL, 0);
257       GNUNET_CLIENT_disconnect (rh->client, GNUNET_NO);
258       GNUNET_free (rh);
259       return;
260     }
261   sa = (const struct sockaddr *) &msg[1];
262   salen = size - sizeof (struct GNUNET_MessageHeader);
263   if (salen < sizeof (struct sockaddr))
264     {
265       GNUNET_break (0);
266       rh->addr_callback (rh->cls, NULL, 0);
267       GNUNET_CLIENT_disconnect (rh->client, GNUNET_NO);
268       GNUNET_free (rh);
269       return;
270     }
271 #if DEBUG_RESOLVER
272   {
273     char *ips = no_resolve (sa, salen);
274     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
275                 "Resolver returns `%s' for `%s'.\n", ips,
276                 rh->hostname);
277     GNUNET_free (ips);
278   }
279 #endif
280   rh->addr_callback (rh->cls, sa, salen);
281   GNUNET_CLIENT_receive (rh->client,
282                          &handle_address_response,
283                          rh,
284                          GNUNET_TIME_absolute_get_remaining (rh->timeout));
285 }
286
287
288 /**
289  * We've been asked to lookup the address for a hostname and were 
290  * given a valid numeric string.  Perform the callbacks for the
291  * numeric addresses.
292  *
293  * @param cls struct GNUNET_RESOLVER_RequestHandle for the request
294  * @param tc unused scheduler context
295  */
296 static void
297 numeric_resolution (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
298 {
299   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
300   struct sockaddr_in v4;
301   struct sockaddr_in6 v6;
302
303   memset (&v4, 0, sizeof (v4));
304   v4.sin_family = AF_INET;
305 #if HAVE_SOCKADDR_IN_SIN_LEN
306   v4.sin_len = sizeof (v4);
307 #endif
308   memset (&v6, 0, sizeof (v6));
309   v6.sin6_family = AF_INET6;
310 #if HAVE_SOCKADDR_IN_SIN_LEN
311   v6.sin6_len = sizeof (v6);
312 #endif
313
314   if (((rh->domain == AF_UNSPEC) || (rh->domain == AF_INET)) &&
315       (1 == inet_pton (AF_INET, rh->hostname, &v4.sin_addr)))
316     {
317       rh->addr_callback (rh->cls, (const struct sockaddr *) &v4, sizeof (v4));
318       if ((rh->domain == AF_UNSPEC) &&
319           (1 == inet_pton (AF_INET6, rh->hostname, &v6.sin6_addr)))
320         {
321           /* this can happen on some systems IF "hostname" is "localhost" */
322           rh->addr_callback (rh->cls,
323                              (const struct sockaddr *) &v6, sizeof (v6));
324         }
325       rh->addr_callback (rh->cls, NULL, 0);
326       GNUNET_free (rh);
327       return;
328     }
329   if (((rh->domain == AF_UNSPEC) || (rh->domain == AF_INET6)) &&
330       (1 == inet_pton (AF_INET6, rh->hostname, &v6.sin6_addr)))
331     {
332       rh->addr_callback (rh->cls, (const struct sockaddr *) &v6, sizeof (v6));
333       rh->addr_callback (rh->cls, NULL, 0);
334       GNUNET_free (rh);
335       return;
336     }
337   /* why are we here? this task should not have been scheduled! */
338   GNUNET_assert (0);
339   GNUNET_free (rh);
340 }
341
342
343
344 /**
345  * We've been asked to lookup the address for a hostname and were 
346  * given a variant of "loopback".  Perform the callbacks for the
347  * respective loopback numeric addresses.
348  *
349  * @param cls struct GNUNET_RESOLVER_RequestHandle for the request
350  * @param tc unused scheduler context
351  */
352 static void
353 loopback_resolution (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
354 {
355   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
356   struct sockaddr_in v4;
357   struct sockaddr_in6 v6;
358
359   memset (&v4, 0, sizeof (v4));
360   v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
361   v4.sin_family = AF_INET;
362 #if HAVE_SOCKADDR_IN_SIN_LEN
363   v4.sin_len = sizeof (v4);
364 #endif
365   memset (&v6, 0, sizeof (v6));
366   v6.sin6_family = AF_INET6;
367 #if HAVE_SOCKADDR_IN_SIN_LEN
368   v6.sin6_len = sizeof (v6);
369 #endif
370   v6.sin6_addr = in6addr_loopback;
371   switch (rh->domain)
372     {
373     case AF_INET:
374       rh->addr_callback (rh->cls, (const struct sockaddr *) &v4, sizeof (v4));
375       break;
376     case AF_INET6:
377       rh->addr_callback (rh->cls, (const struct sockaddr *) &v6, sizeof (v6));
378       break;
379     case AF_UNSPEC:
380       rh->addr_callback (rh->cls, (const struct sockaddr *) &v6, sizeof (v6));
381       rh->addr_callback (rh->cls, (const struct sockaddr *) &v4, sizeof (v4));
382       break;
383     default:
384       GNUNET_break (0);
385       break;
386     }
387   rh->addr_callback (rh->cls, NULL, 0);
388   GNUNET_free (rh);
389 }
390
391
392 /**
393  * Convert a string to one or more IP addresses.
394  *
395  * @param sched scheduler to use
396  * @param cfg configuration to use
397  * @param hostname the hostname to resolve
398  * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any"
399  * @param callback function to call with addresses
400  * @param callback_cls closure for callback
401  * @param timeout how long to try resolving
402  * @return handle that can be used to cancel the request, NULL on error
403  */
404 struct GNUNET_RESOLVER_RequestHandle *
405 GNUNET_RESOLVER_ip_get (struct GNUNET_SCHEDULER_Handle *sched,
406                         const struct GNUNET_CONFIGURATION_Handle *cfg,
407                         const char *hostname,
408                         int domain,
409                         struct GNUNET_TIME_Relative timeout,
410                         GNUNET_RESOLVER_AddressCallback callback,
411                         void *callback_cls)
412 {
413   struct GNUNET_CLIENT_Connection *client;
414   struct GNUNET_RESOLVER_GetMessage *msg;
415   struct GNUNET_RESOLVER_RequestHandle *rh;
416   size_t slen;
417   unsigned int i;
418   struct in_addr v4;
419   struct in6_addr v6;
420   char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE];
421
422   check_config (cfg);
423   slen = strlen (hostname) + 1;
424   if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) >
425       GNUNET_SERVER_MAX_MESSAGE_SIZE)
426     {
427       GNUNET_break (0);
428       return NULL;
429     }
430   rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + slen);
431   rh->sched = sched;
432   rh->domain = domain;
433   rh->addr_callback = callback;
434   rh->cls = callback_cls;
435   memcpy (&rh[1], hostname, slen);
436   rh->hostname = (const char *) &rh[1];
437   rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
438
439   /* first, check if this is a numeric address */
440   if (((1 == inet_pton (AF_INET,
441                         hostname,
442                         &v4)) &&
443        ((domain == AF_INET) || (domain == AF_UNSPEC))) ||
444       ((1 == inet_pton (AF_INET6,
445                         hostname,
446                         &v6)) &&
447        ((domain == AF_INET6) || (domain == AF_UNSPEC))))
448     {
449       rh->task = GNUNET_SCHEDULER_add_now (sched,
450                                            &numeric_resolution, rh);
451       return rh;
452     }
453   /* then, check if this is a loopback address */
454   i = 0;
455   while (loopback[i] != NULL)
456     if (0 == strcasecmp (loopback[i++], hostname))
457       {
458         rh->task = GNUNET_SCHEDULER_add_now (sched,
459                                              &loopback_resolution, rh);
460         return rh;
461       }
462
463   client = GNUNET_CLIENT_connect (sched, "resolver", cfg);
464   if (client == NULL)
465     {
466       GNUNET_free (rh);
467       return NULL;
468     }
469   rh->client = client;
470
471   msg = (struct GNUNET_RESOLVER_GetMessage *) buf;
472   msg->header.size =
473     htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + slen);
474   msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
475   msg->direction = htonl (GNUNET_NO);
476   msg->domain = htonl (domain);
477   memcpy (&msg[1], hostname, slen);
478
479 #if DEBUG_RESOLVER
480   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
481               _("Resolver requests DNS resolution of hostname `%s'.\n"),
482               hostname);
483 #endif
484   if (GNUNET_OK !=
485       GNUNET_CLIENT_transmit_and_get_response (client,
486                                                &msg->header,
487                                                timeout,
488                                                GNUNET_YES,
489                                                &handle_address_response, rh))
490     {
491       GNUNET_free (rh);
492       GNUNET_CLIENT_disconnect (client, GNUNET_NO);
493       return NULL;
494     }
495   return rh;
496 }
497
498
499 /**
500  * Process response with a hostname for a reverse DNS lookup.
501  *
502  * @param cls our "struct GNUNET_RESOLVER_RequestHandle" context
503  * @param msg message with the hostname, NULL on error
504  */
505 static void
506 handle_hostname_response (void *cls, const struct GNUNET_MessageHeader *msg)
507 {
508   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
509   uint16_t size;
510   const char *hostname;
511
512   if (msg == NULL)
513     {
514       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
515                   _("Timeout trying to resolve IP address `%s'.\n"),
516                   GNUNET_a2s ((const void*) &rh[1], rh->salen));
517       rh->name_callback (rh->cls, NULL);
518       GNUNET_CLIENT_disconnect (rh->client, GNUNET_NO);
519       GNUNET_free (rh);
520       return;
521     }
522   size = ntohs (msg->size);
523   if (size == sizeof (struct GNUNET_MessageHeader))
524     {
525 #if DEBUG_RESOLVER
526       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
527                   _("Received end message resolving IP address `%s'.\n"),
528                   GNUNET_a2s ((const void*) &rh[1], rh->salen));
529 #endif
530       rh->name_callback (rh->cls, NULL);
531       GNUNET_CLIENT_disconnect (rh->client, GNUNET_NO);
532       GNUNET_free (rh);
533       return;
534     }
535   hostname = (const char *) &msg[1];
536   if (hostname[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0')
537     {
538       GNUNET_break (0);
539       rh->name_callback (rh->cls, NULL);
540       GNUNET_CLIENT_disconnect (rh->client, GNUNET_NO);
541       GNUNET_free (rh);
542       return;
543     }
544 #if DEBUG_RESOLVER
545   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
546               _("Resolver returns `%s' for IP `%s'.\n"), 
547               hostname,
548               GNUNET_a2s ((const void*) &rh[1], rh->salen));
549 #endif
550   rh->name_callback (rh->cls, hostname);
551   GNUNET_CLIENT_receive (rh->client,
552                          &handle_hostname_response,
553                          rh,
554                          GNUNET_TIME_absolute_get_remaining (rh->timeout));
555 }
556
557
558
559 /**
560  * We've been asked to convert an address to a string without
561  * a reverse lookup.  Do it.
562  *
563  * @param cls struct GNUNET_RESOLVER_RequestHandle for the request
564  * @param tc unused scheduler context
565  */
566 static void
567 numeric_reverse (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
568 {
569   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
570   char *result;
571
572   result = no_resolve ((const struct sockaddr *) &rh[1], rh->salen);
573 #if DEBUG_RESOLVER
574   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Resolver returns `%s'.\n"), result);
575 #endif
576   if (result != NULL)
577     {
578       rh->name_callback (rh->cls, result);
579       GNUNET_free (result);
580     }
581   rh->name_callback (rh->cls, NULL);
582   GNUNET_free (rh);
583 }
584
585
586
587 /**
588  * Get an IP address as a string.
589  *
590  * @param sched scheduler to use
591  * @param cfg configuration to use
592  * @param sa host address
593  * @param salen length of host address
594  * @param do_resolve use GNUNET_NO to return numeric hostname
595  * @param timeout how long to try resolving
596  * @param callback function to call with hostnames
597  * @param cls closure for callback
598  * @return handle that can be used to cancel the request
599  */
600 struct GNUNET_RESOLVER_RequestHandle *
601 GNUNET_RESOLVER_hostname_get (struct GNUNET_SCHEDULER_Handle *sched,
602                               const struct GNUNET_CONFIGURATION_Handle *cfg,
603                               const struct sockaddr *sa,
604                               socklen_t salen,
605                               int do_resolve,
606                               struct GNUNET_TIME_Relative timeout,
607                               GNUNET_RESOLVER_HostnameCallback callback,
608                               void *cls)
609 {
610   struct GNUNET_CLIENT_Connection *client;
611   struct GNUNET_RESOLVER_GetMessage *msg;
612   struct GNUNET_RESOLVER_RequestHandle *rh;
613   char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE];
614
615   check_config (cfg);
616   rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + salen);
617   rh->name_callback = callback;
618   rh->cls = cls;
619   rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
620   rh->sched = sched;
621   rh->salen = salen;
622   memcpy (&rh[1], sa, salen);
623
624   if (GNUNET_NO == do_resolve)
625     {
626       rh->task = GNUNET_SCHEDULER_add_now (sched,
627                                            &numeric_reverse, rh);
628       return rh;
629     }
630   if (salen + sizeof (struct GNUNET_RESOLVER_GetMessage) >
631       GNUNET_SERVER_MAX_MESSAGE_SIZE)
632     {
633       GNUNET_break (0);
634       GNUNET_free (rh);
635       return NULL;
636     }
637   client = GNUNET_CLIENT_connect (sched, "resolver", cfg);
638   if (client == NULL)
639     {
640       GNUNET_free (rh);
641       return NULL;
642     }
643   rh->client = client;
644
645   msg = (struct GNUNET_RESOLVER_GetMessage *) buf;
646   msg->header.size =
647     htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + salen);
648   msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
649   msg->direction = htonl (GNUNET_YES);
650   msg->domain = htonl (sa->sa_family);
651   memcpy (&msg[1], sa, salen);
652 #if DEBUG_RESOLVER
653   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
654               _("Resolver requests DNS resolution of IP address.\n"));
655 #endif
656   if (GNUNET_OK !=
657       GNUNET_CLIENT_transmit_and_get_response (client,
658                                                &msg->header,
659                                                timeout,
660                                                GNUNET_YES,
661                                                &handle_hostname_response, rh))
662     {
663       GNUNET_CLIENT_disconnect (client, GNUNET_NO);
664       GNUNET_free (rh);
665       return NULL;
666     }
667   return rh;
668 }
669
670
671 /**
672  * Get local hostname
673  * @return hostname
674  */
675 char *
676 GNUNET_RESOLVER_local_hostname_get ( )
677 {
678
679   char hostname[GNUNET_OS_get_hostname_max_length() + 1];
680
681
682   if (0 != gethostname (hostname, sizeof (hostname) - 1))
683     {
684       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR |
685                            GNUNET_ERROR_TYPE_BULK, "gethostname");
686       return NULL;
687     }
688 #if DEBUG_RESOLVER
689   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
690               _("Resolving our hostname `%s'\n"), hostname);
691 #endif
692   return GNUNET_strdup (hostname);
693 }
694
695 /**
696  * Looking our own hostname.
697  *
698  * @param sched scheduler to use
699  * @param cfg configuration to use
700  * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any"
701  * @param callback function to call with addresses
702  * @param cls closure for callback
703  * @param timeout how long to try resolving
704  * @return handle that can be used to cancel the request, NULL on error
705  */
706 struct GNUNET_RESOLVER_RequestHandle *
707 GNUNET_RESOLVER_hostname_resolve (struct GNUNET_SCHEDULER_Handle *sched,
708                                   const struct GNUNET_CONFIGURATION_Handle
709                                   *cfg, int domain,
710                                   struct GNUNET_TIME_Relative timeout,
711                                   GNUNET_RESOLVER_AddressCallback callback,
712                                   void *cls)
713 {
714   char hostname[GNUNET_OS_get_hostname_max_length() + 1];
715
716   check_config (cfg);
717   if (0 != gethostname (hostname, sizeof (hostname) - 1))
718     {
719       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR |
720                            GNUNET_ERROR_TYPE_BULK, "gethostname");
721       return NULL;
722     }
723 #if DEBUG_RESOLVER
724   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
725               _("Resolving our hostname `%s'\n"), hostname);
726 #endif
727   return GNUNET_RESOLVER_ip_get (sched,
728                                  cfg, hostname, domain, timeout, callback,
729                                  cls);
730 }
731
732
733 /**
734  * Cancel a request that is still pending with the resolver.
735  * Note that a client MUST NOT cancel a request that has
736  * been completed (i.e, the callback has been called to
737  * signal timeout or the final result).
738  *
739  * @param h handle of request to cancel
740  */
741 void
742 GNUNET_RESOLVER_request_cancel (struct GNUNET_RESOLVER_RequestHandle *h)
743 {
744   if (h->client != NULL)
745     GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
746   if (h->task != GNUNET_SCHEDULER_NO_TASK)
747     GNUNET_SCHEDULER_cancel (h->sched, h->task);
748   GNUNET_free (h);
749 }
750
751
752
753 /* end of resolver_api.c */