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