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