fixing common off-by-one error with respect to maximum message size
[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 - 1];
430
431   check_config (cfg);
432   slen = strlen (hostname) + 1;
433   if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
434     {
435       GNUNET_break (0);
436       return NULL;
437     }
438   rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + slen);
439   rh->sched = sched;
440   rh->domain = domain;
441   rh->addr_callback = callback;
442   rh->cls = callback_cls;
443   memcpy (&rh[1], hostname, slen);
444   rh->hostname = (const char *) &rh[1];
445   rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
446
447   /* first, check if this is a numeric address */
448   if (((1 == inet_pton (AF_INET,
449                         hostname,
450                         &v4)) &&
451        ((domain == AF_INET) || (domain == AF_UNSPEC))) ||
452       ((1 == inet_pton (AF_INET6,
453                         hostname,
454                         &v6)) &&
455        ((domain == AF_INET6) || (domain == AF_UNSPEC))))
456     {
457       rh->task = GNUNET_SCHEDULER_add_now (sched,
458                                            &numeric_resolution, rh);
459       return rh;
460     }
461   /* then, check if this is a loopback address */
462   i = 0;
463   while (loopback[i] != NULL)
464     if (0 == strcasecmp (loopback[i++], hostname))
465       {
466         rh->task = GNUNET_SCHEDULER_add_now (sched,
467                                              &loopback_resolution, rh);
468         return rh;
469       }
470
471   client = GNUNET_CLIENT_connect (sched, "resolver", cfg);
472   if (client == NULL)
473     {
474       GNUNET_free (rh);
475       return NULL;
476     }
477   rh->client = client;
478
479   msg = (struct GNUNET_RESOLVER_GetMessage *) buf;
480   msg->header.size =
481     htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + slen);
482   msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
483   msg->direction = htonl (GNUNET_NO);
484   msg->domain = htonl (domain);
485   memcpy (&msg[1], hostname, slen);
486
487 #if DEBUG_RESOLVER
488   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
489               _("Resolver requests DNS resolution of hostname `%s'.\n"),
490               hostname);
491 #endif
492   if (GNUNET_OK !=
493       GNUNET_CLIENT_transmit_and_get_response (client,
494                                                &msg->header,
495                                                timeout,
496                                                GNUNET_YES,
497                                                &handle_address_response, rh))
498     {
499       GNUNET_free (rh);
500       GNUNET_CLIENT_disconnect (client, GNUNET_NO);
501       return NULL;
502     }
503   return rh;
504 }
505
506
507 /**
508  * Process response with a hostname for a reverse DNS lookup.
509  *
510  * @param cls our "struct GNUNET_RESOLVER_RequestHandle" context
511  * @param msg message with the hostname, NULL on error
512  */
513 static void
514 handle_hostname_response (void *cls, const struct GNUNET_MessageHeader *msg)
515 {
516   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
517   uint16_t size;
518   const char *hostname;
519
520   if (msg == NULL)
521     {
522       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
523                   _("Timeout trying to resolve IP address `%s'.\n"),
524                   GNUNET_a2s ((const void*) &rh[1], rh->salen));
525       rh->name_callback (rh->cls, NULL);
526       GNUNET_CLIENT_disconnect (rh->client, GNUNET_NO);
527       GNUNET_free (rh);
528       return;
529     }
530   size = ntohs (msg->size);
531   if (size == sizeof (struct GNUNET_MessageHeader))
532     {
533 #if DEBUG_RESOLVER
534       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
535                   _("Received end message resolving IP address `%s'.\n"),
536                   GNUNET_a2s ((const void*) &rh[1], rh->salen));
537 #endif
538       rh->name_callback (rh->cls, NULL);
539       GNUNET_CLIENT_disconnect (rh->client, GNUNET_NO);
540       GNUNET_free (rh);
541       return;
542     }
543   hostname = (const char *) &msg[1];
544   if (hostname[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0')
545     {
546       GNUNET_break (0);
547       rh->name_callback (rh->cls, NULL);
548       GNUNET_CLIENT_disconnect (rh->client, GNUNET_NO);
549       GNUNET_free (rh);
550       return;
551     }
552 #if DEBUG_RESOLVER
553   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
554               _("Resolver returns `%s' for IP `%s'.\n"), 
555               hostname,
556               GNUNET_a2s ((const void*) &rh[1], rh->salen));
557 #endif
558   rh->name_callback (rh->cls, hostname);
559   GNUNET_CLIENT_receive (rh->client,
560                          &handle_hostname_response,
561                          rh,
562                          GNUNET_TIME_absolute_get_remaining (rh->timeout));
563 }
564
565
566
567 /**
568  * We've been asked to convert an address to a string without
569  * a reverse lookup.  Do it.
570  *
571  * @param cls struct GNUNET_RESOLVER_RequestHandle for the request
572  * @param tc unused scheduler context
573  */
574 static void
575 numeric_reverse (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
576 {
577   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
578   char *result;
579
580   result = no_resolve ((const struct sockaddr *) &rh[1], rh->salen);
581 #if DEBUG_RESOLVER
582   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Resolver returns `%s'.\n"), result);
583 #endif
584   if (result != NULL)
585     {
586       rh->name_callback (rh->cls, result);
587       GNUNET_free (result);
588     }
589   rh->name_callback (rh->cls, NULL);
590   GNUNET_free (rh);
591 }
592
593
594
595 /**
596  * Get an IP address as a string.
597  *
598  * @param sched scheduler to use
599  * @param cfg configuration to use
600  * @param sa host address
601  * @param salen length of host address
602  * @param do_resolve use GNUNET_NO to return numeric hostname
603  * @param timeout how long to try resolving
604  * @param callback function to call with hostnames
605  * @param cls closure for callback
606  * @return handle that can be used to cancel the request
607  */
608 struct GNUNET_RESOLVER_RequestHandle *
609 GNUNET_RESOLVER_hostname_get (struct GNUNET_SCHEDULER_Handle *sched,
610                               const struct GNUNET_CONFIGURATION_Handle *cfg,
611                               const struct sockaddr *sa,
612                               socklen_t salen,
613                               int do_resolve,
614                               struct GNUNET_TIME_Relative timeout,
615                               GNUNET_RESOLVER_HostnameCallback callback,
616                               void *cls)
617 {
618   struct GNUNET_CLIENT_Connection *client;
619   struct GNUNET_RESOLVER_GetMessage *msg;
620   struct GNUNET_RESOLVER_RequestHandle *rh;
621   char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
622
623   check_config (cfg);
624   rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + salen);
625   rh->name_callback = callback;
626   rh->cls = cls;
627   rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
628   rh->sched = sched;
629   rh->salen = salen;
630   memcpy (&rh[1], sa, salen);
631
632   if (GNUNET_NO == do_resolve)
633     {
634       rh->task = GNUNET_SCHEDULER_add_now (sched,
635                                            &numeric_reverse, rh);
636       return rh;
637     }
638   if (salen + sizeof (struct GNUNET_RESOLVER_GetMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
639     {
640       GNUNET_break (0);
641       GNUNET_free (rh);
642       return NULL;
643     }
644   client = GNUNET_CLIENT_connect (sched, "resolver", cfg);
645   if (client == NULL)
646     {
647       GNUNET_free (rh);
648       return NULL;
649     }
650   rh->client = client;
651
652   msg = (struct GNUNET_RESOLVER_GetMessage *) buf;
653   msg->header.size =
654     htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + salen);
655   msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
656   msg->direction = htonl (GNUNET_YES);
657   msg->domain = htonl (sa->sa_family);
658   memcpy (&msg[1], sa, salen);
659 #if DEBUG_RESOLVER
660   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
661               _("Resolver requests DNS resolution of IP address.\n"));
662 #endif
663   if (GNUNET_OK !=
664       GNUNET_CLIENT_transmit_and_get_response (client,
665                                                &msg->header,
666                                                timeout,
667                                                GNUNET_YES,
668                                                &handle_hostname_response, rh))
669     {
670       GNUNET_CLIENT_disconnect (client, GNUNET_NO);
671       GNUNET_free (rh);
672       return NULL;
673     }
674   return rh;
675 }
676
677
678 /**
679  * Get local fully qualified domain name
680  * @return fqdn
681  */
682 char *
683 GNUNET_RESOLVER_local_fqdn_get ( void )
684 {
685   struct hostent *host;
686   char hostname[GNUNET_OS_get_hostname_max_length() + 1];
687
688
689   if (0 != gethostname (hostname, sizeof (hostname) - 1))
690     {
691       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR |
692                            GNUNET_ERROR_TYPE_BULK, "gethostname");
693       return NULL;
694     }
695 #if DEBUG_RESOLVER
696   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
697               _("Resolving our FQDN `%s'\n"), hostname);
698 #endif
699   host = gethostbyname ( hostname );
700   if ( NULL == host)
701   {
702     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
703                 _("Could not resolve our FQDN : %s\n"),
704                 hstrerror (h_errno));
705     return NULL;
706   }
707   return GNUNET_strdup (host->h_name);
708 }
709
710 /**
711  * Looking our own hostname.
712  *
713  * @param sched scheduler to use
714  * @param cfg configuration to use
715  * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any"
716  * @param callback function to call with addresses
717  * @param cls closure for callback
718  * @param timeout how long to try resolving
719  * @return handle that can be used to cancel the request, NULL on error
720  */
721 struct GNUNET_RESOLVER_RequestHandle *
722 GNUNET_RESOLVER_hostname_resolve (struct GNUNET_SCHEDULER_Handle *sched,
723                                   const struct GNUNET_CONFIGURATION_Handle
724                                   *cfg, int domain,
725                                   struct GNUNET_TIME_Relative timeout,
726                                   GNUNET_RESOLVER_AddressCallback callback,
727                                   void *cls)
728 {
729   char hostname[GNUNET_OS_get_hostname_max_length() + 1];
730
731   check_config (cfg);
732   if (0 != gethostname (hostname, sizeof (hostname) - 1))
733     {
734       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR |
735                            GNUNET_ERROR_TYPE_BULK, "gethostname");
736       return NULL;
737     }
738 #if DEBUG_RESOLVER
739   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
740               _("Resolving our hostname `%s'\n"), hostname);
741 #endif
742   return GNUNET_RESOLVER_ip_get (sched,
743                                  cfg, hostname, domain, timeout, callback,
744                                  cls);
745 }
746
747
748 /**
749  * Cancel a request that is still pending with the resolver.
750  * Note that a client MUST NOT cancel a request that has
751  * been completed (i.e, the callback has been called to
752  * signal timeout or the final result).
753  *
754  * @param h handle of request to cancel
755  */
756 void
757 GNUNET_RESOLVER_request_cancel (struct GNUNET_RESOLVER_RequestHandle *h)
758 {
759   if (h->client != NULL)
760     GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
761   if (h->task != GNUNET_SCHEDULER_NO_TASK)
762     GNUNET_SCHEDULER_cancel (h->sched, h->task);
763   GNUNET_free (h);
764 }
765
766
767
768 /* end of resolver_api.c */