fixing remaining network-connection naming confusion in API
[oweals/gnunet.git] / src / resolver / 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 resolver/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 struct GetAddressContext
36 {
37   GNUNET_RESOLVER_AddressCallback callback;
38   void *cls;
39   struct GNUNET_RESOLVER_GetMessage *msg;
40   struct GNUNET_CLIENT_Connection *client;
41   struct GNUNET_TIME_Absolute timeout;
42 };
43
44
45
46 /**
47  * Convert IP address to string without DNS resolution.
48  */
49 static char *
50 no_resolve (const struct sockaddr *sa, socklen_t salen)
51 {
52   char *ret;
53   char inet4[INET_ADDRSTRLEN];
54   char inet6[INET6_ADDRSTRLEN];
55
56   if (salen < sizeof (struct sockaddr))
57     return NULL;
58   switch (sa->sa_family)
59     {
60     case AF_INET:
61       if (salen != sizeof (struct sockaddr_in))
62         return NULL;
63       inet_ntop (AF_INET,
64                  &((struct sockaddr_in *) sa)->sin_addr,
65                  inet4, INET_ADDRSTRLEN);
66       ret = GNUNET_strdup (inet4);
67       break;
68     case AF_INET6:
69       if (salen != sizeof (struct sockaddr_in6))
70         return NULL;
71       inet_ntop (AF_INET6,
72                  &((struct sockaddr_in6 *) sa)->sin6_addr,
73                  inet6, INET6_ADDRSTRLEN);
74       ret = GNUNET_strdup (inet6);
75       break;
76     default:
77       ret = NULL;
78       break;
79     }
80   return ret;
81 }
82
83
84 static void
85 handle_address_response (void *cls, const struct GNUNET_MessageHeader *msg)
86 {
87   struct GetAddressContext *gac = cls;
88   uint16_t size;
89   const struct sockaddr *sa;
90   socklen_t salen;
91
92
93   if (msg == NULL)
94     {
95       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
96                   _("Timeout trying to resolve hostname.\n"));
97       gac->callback (gac->cls, NULL, 0);
98       GNUNET_CLIENT_disconnect (gac->client);
99       GNUNET_free (gac);
100       return;
101     }
102   if (GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE != ntohs (msg->type))
103     {
104       GNUNET_break (0);
105       gac->callback (gac->cls, NULL, 0);
106       GNUNET_CLIENT_disconnect (gac->client);
107       GNUNET_free (gac);
108       return;
109     }
110
111   size = ntohs (msg->size);
112   if (size == sizeof (struct GNUNET_MessageHeader))
113     {
114 #if DEBUG_RESOLVER
115       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
116                   _("Received end message resolving hostname.\n"));
117 #endif
118       gac->callback (gac->cls, NULL, 0);
119       GNUNET_CLIENT_disconnect (gac->client);
120       GNUNET_free (gac);
121       return;
122     }
123   sa = (const struct sockaddr *) &msg[1];
124   salen = size - sizeof (struct GNUNET_MessageHeader);
125   if (salen < sizeof (struct sockaddr))
126     {
127       GNUNET_break (0);
128       gac->callback (gac->cls, NULL, 0);
129       GNUNET_CLIENT_disconnect (gac->client);
130       GNUNET_free (gac);
131       return;
132     }
133 #if DEBUG_RESOLVER
134   {
135     char *ips = no_resolve (sa, salen);
136     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Resolver returns `%s'.\n"), ips);
137     GNUNET_free (ips);
138   }
139 #endif
140   gac->callback (gac->cls, sa, salen);
141   GNUNET_CLIENT_receive (gac->client,
142                          &handle_address_response,
143                          gac,
144                          GNUNET_TIME_absolute_get_remaining (gac->timeout));
145 }
146
147
148 static size_t
149 transmit_get_ip (void *cls, size_t size, void *buf)
150 {
151   struct GetAddressContext *actx = cls;
152   uint16_t ms;
153
154   if (buf == NULL)
155     {
156       /* timeout / error */
157       GNUNET_free (actx->msg);
158       actx->callback (actx->cls, NULL, 0);
159       GNUNET_CLIENT_disconnect (actx->client);
160       GNUNET_free (actx);
161       return 0;
162     }
163   ms = ntohs (actx->msg->header.size);
164   GNUNET_assert (size >= ms);
165   memcpy (buf, actx->msg, ms);
166   GNUNET_free (actx->msg);
167   actx->msg = NULL;
168   GNUNET_CLIENT_receive (actx->client,
169                          &handle_address_response,
170                          actx,
171                          GNUNET_TIME_absolute_get_remaining (actx->timeout));
172   return ms;
173 }
174
175
176
177 /**
178  * Convert a string to one or more IP addresses.
179  *
180  * @param sched scheduler to use
181  * @param cfg configuration to use
182  * @param hostname the hostname to resolve
183  * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any"
184  * @param callback function to call with addresses
185  * @param cls closure for callback
186  * @param timeout how long to try resolving
187  */
188 void
189 GNUNET_RESOLVER_ip_get (struct GNUNET_SCHEDULER_Handle *sched,
190                         const struct GNUNET_CONFIGURATION_Handle *cfg,
191                         const char *hostname,
192                         int domain,
193                         struct GNUNET_TIME_Relative timeout,
194                         GNUNET_RESOLVER_AddressCallback callback, void *cls)
195 {
196   struct GNUNET_CLIENT_Connection *client;
197   struct GNUNET_RESOLVER_GetMessage *msg;
198   struct GetAddressContext *actx;
199   size_t slen;
200
201   slen = strlen (hostname) + 1;
202   if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) >
203       GNUNET_SERVER_MAX_MESSAGE_SIZE)
204     {
205       GNUNET_break (0);
206       callback (cls, NULL, 0);
207       return;
208     }
209   client = GNUNET_CLIENT_connect (sched, "resolver", cfg);
210   if (client == NULL)
211     {
212       callback (cls, NULL, 0);
213       return;
214     }
215   msg = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_GetMessage) + slen);
216   msg->header.size =
217     htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + slen);
218   msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
219   msg->direction = htonl (GNUNET_NO);
220   msg->domain = htonl (domain);
221   memcpy (&msg[1], hostname, slen);
222   actx = GNUNET_malloc (sizeof (struct GetAddressContext));
223   actx->callback = callback;
224   actx->cls = cls;
225   actx->client = client;
226   actx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
227   actx->msg = msg;
228
229 #if DEBUG_RESOLVER
230   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
231               _("Resolver requests DNS resolution of hostname `%s'.\n"),
232               hostname);
233 #endif
234   if (NULL ==
235       GNUNET_CLIENT_notify_transmit_ready (client,
236                                            slen +
237                                            sizeof (struct
238                                                    GNUNET_RESOLVER_GetMessage),
239                                            timeout, &transmit_get_ip, actx))
240     {
241       GNUNET_free (msg);
242       GNUNET_free (actx);
243       callback (cls, NULL, 0);
244       GNUNET_CLIENT_disconnect (client);
245       return;
246     }
247 }
248
249
250 struct GetHostnameContext
251 {
252   GNUNET_RESOLVER_HostnameCallback callback;
253   void *cls;
254   struct GNUNET_RESOLVER_GetMessage *msg;
255   struct GNUNET_CLIENT_Connection *client;
256   struct GNUNET_TIME_Absolute timeout;
257 };
258
259
260 static void
261 handle_hostname_response (void *cls, const struct GNUNET_MessageHeader *msg)
262 {
263   struct GetHostnameContext *ghc = cls;
264   uint16_t size;
265   const char *hostname;
266
267   if (msg == NULL)
268     {
269       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
270                   _("Timeout trying to resolve IP address.\n"));
271       ghc->callback (ghc->cls, NULL);
272       GNUNET_CLIENT_disconnect (ghc->client);
273       GNUNET_free (ghc);
274       return;
275     }
276   size = ntohs (msg->size);
277   if (size == sizeof (struct GNUNET_MessageHeader))
278     {
279 #if DEBUG_RESOLVER
280       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
281                   _("Received end message resolving IP address.\n"));
282 #endif
283       ghc->callback (ghc->cls, NULL);
284       GNUNET_CLIENT_disconnect (ghc->client);
285       GNUNET_free (ghc);
286       return;
287     }
288   hostname = (const char *) &msg[1];
289   if (hostname[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0')
290     {
291       GNUNET_break (0);
292       ghc->callback (ghc->cls, NULL);
293       GNUNET_CLIENT_disconnect (ghc->client);
294       GNUNET_free (ghc);
295       return;
296     }
297 #if DEBUG_RESOLVER
298   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
299               _("Resolver returns `%s'.\n"), hostname);
300 #endif
301   ghc->callback (ghc->cls, hostname);
302   GNUNET_CLIENT_receive (ghc->client,
303                          &handle_hostname_response,
304                          ghc,
305                          GNUNET_TIME_absolute_get_remaining (ghc->timeout));
306 }
307
308
309 static size_t
310 transmit_get_hostname (void *cls, size_t size, void *buf)
311 {
312   struct GetHostnameContext *hctx = cls;
313   uint16_t msize;
314
315   if (buf == NULL)
316     {
317       GNUNET_free (hctx->msg);
318       hctx->callback (hctx->cls, NULL);
319       GNUNET_CLIENT_disconnect (hctx->client);
320       GNUNET_free (hctx);
321       return 0;
322     }
323   msize = ntohs (hctx->msg->header.size);
324   GNUNET_assert (size >= msize);
325   memcpy (buf, hctx->msg, msize);
326   GNUNET_free (hctx->msg);
327   hctx->msg = NULL;
328   GNUNET_CLIENT_receive (hctx->client,
329                          &handle_hostname_response,
330                          hctx,
331                          GNUNET_TIME_absolute_get_remaining (hctx->timeout));
332   return msize;
333 }
334
335
336
337
338 /**
339  * Get an IP address as a string.
340  *
341  * @param sched scheduler to use
342  * @param cfg configuration to use
343  * @param sa host address
344  * @param salen length of host address
345  * @param do_resolve use GNUNET_NO to return numeric hostname
346  * @param timeout how long to try resolving
347  * @param callback function to call with hostnames
348  * @param cls closure for callback
349  */
350 void
351 GNUNET_RESOLVER_hostname_get (struct GNUNET_SCHEDULER_Handle *sched,
352                               const struct GNUNET_CONFIGURATION_Handle *cfg,
353                               const struct sockaddr *sa,
354                               socklen_t salen,
355                               int do_resolve,
356                               struct GNUNET_TIME_Relative timeout,
357                               GNUNET_RESOLVER_HostnameCallback callback,
358                               void *cls)
359 {
360   char *result;
361   struct GNUNET_CLIENT_Connection *client;
362   struct GNUNET_RESOLVER_GetMessage *msg;
363   struct GetHostnameContext *hctx;
364
365   if (GNUNET_NO == do_resolve)
366     {
367       result = no_resolve (sa, salen);
368 #if DEBUG_RESOLVER
369       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
370                   _("Resolver returns `%s'.\n"), result);
371 #endif
372       callback (cls, result);
373       if (result != NULL)
374         {
375           GNUNET_free (result);
376           callback (cls, NULL);
377         }
378       return;
379     }
380   if (salen + sizeof (struct GNUNET_RESOLVER_GetMessage) >
381       GNUNET_SERVER_MAX_MESSAGE_SIZE)
382     {
383       GNUNET_break (0);
384       callback (cls, NULL);
385       return;
386     }
387   client = GNUNET_CLIENT_connect (sched, "resolver", cfg);
388   if (client == NULL)
389     {
390       callback (cls, NULL);
391       return;
392     }
393   msg = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_GetMessage) + salen);
394   msg->header.size =
395     htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + salen);
396   msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
397   msg->direction = htonl (GNUNET_YES);
398   msg->domain = htonl (sa->sa_family);
399   memcpy (&msg[1], sa, salen);
400 #if DEBUG_RESOLVER
401   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
402               _("Resolver requests DNS resolution of IP address.\n"));
403 #endif
404   hctx = GNUNET_malloc (sizeof (struct GetHostnameContext));
405   hctx->callback = callback;
406   hctx->cls = cls;
407   hctx->client = client;
408   hctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
409   hctx->msg = msg;
410   if (NULL ==
411       GNUNET_CLIENT_notify_transmit_ready (client,
412                                            sizeof (struct
413                                                    GNUNET_RESOLVER_GetMessage)
414                                            + salen, timeout,
415                                            &transmit_get_hostname, hctx))
416     {
417       GNUNET_free (msg);
418       callback (cls, NULL);
419       GNUNET_CLIENT_disconnect (client);
420       GNUNET_free (hctx);
421     }
422 }
423
424 /**
425  * Maximum supported length of hostname
426  */
427 #define MAX_HOSTNAME 1024
428
429
430 /**
431  * Resolve our hostname to an IP address.
432  *
433  * @param sched scheduler to use
434  * @param cfg configuration to use
435  * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any"
436  * @param callback function to call with addresses
437  * @param cls closure for callback
438  * @param timeout how long to try resolving
439  */
440 void
441 GNUNET_RESOLVER_hostname_resolve (struct GNUNET_SCHEDULER_Handle *sched,
442                                   const struct GNUNET_CONFIGURATION_Handle *cfg,
443                                   int domain,
444                                   struct GNUNET_TIME_Relative timeout,
445                                   GNUNET_RESOLVER_AddressCallback callback,
446                                   void *cls)
447 {
448   char hostname[MAX_HOSTNAME];
449
450   if (0 != gethostname (hostname, sizeof (hostname) - 1))
451     {
452       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR |
453                            GNUNET_ERROR_TYPE_BULK, "gethostname");
454       callback (cls, NULL, 0);
455       return;
456     }
457 #if DEBUG_RESOLVER
458   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
459               _("Resolving our hostname `%s'\n"), hostname);
460 #endif
461   GNUNET_RESOLVER_ip_get (sched,
462                           cfg, hostname, domain, timeout, callback, cls);
463 }
464
465
466
467
468 /* end of resolver_api.c */