summaryrefslogtreecommitdiff
path: root/src/util/resolver_api.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2009-10-27 22:27:11 +0000
committerChristian Grothoff <christian@grothoff.org>2009-10-27 22:27:11 +0000
commitb3443c6ab7b18ee57866ac531bf9f40aa3eb5261 (patch)
tree272b88c59422b9954acb6c7ee08e4a2e9e520a70 /src/util/resolver_api.c
parent64d39ac5f14b54eecc2c7cd99b04d05ff04a894f (diff)
downloadgnunet-b3443c6ab7b18ee57866ac531bf9f40aa3eb5261.tar.gz
gnunet-b3443c6ab7b18ee57866ac531bf9f40aa3eb5261.zip
allowing cancellation of resolver requests
Diffstat (limited to 'src/util/resolver_api.c')
-rw-r--r--src/util/resolver_api.c599
1 files changed, 382 insertions, 217 deletions
diff --git a/src/util/resolver_api.c b/src/util/resolver_api.c
index 284a3cef6..e1198a9a3 100644
--- a/src/util/resolver_api.c
+++ b/src/util/resolver_api.c
@@ -33,40 +33,81 @@
33 33
34 34
35/** 35/**
36 * FIXME. 36 * Maximum supported length for a hostname
37 */ 37 */
38struct GetAddressContext 38#define MAX_HOSTNAME 1024
39
40
41/**
42 * Possible hostnames for "loopback".
43 */
44static 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 */
56struct GNUNET_RESOLVER_RequestHandle
39{ 57{
40 58
41 /** 59 /**
42 * FIXME. 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.
43 */ 68 */
44 GNUNET_RESOLVER_AddressCallback callback; 69 GNUNET_RESOLVER_HostnameCallback name_callback;
45 70
46 /** 71 /**
47 * Closure for "callback". 72 * Closure for the respective "callback".
48 */ 73 */
49 void *cls; 74 void *cls;
50 75
51 /** 76 /**
52 * FIXME. 77 * Our connection to the resolver service.
53 */ 78 */
54 struct GNUNET_CLIENT_Connection *client; 79 struct GNUNET_CLIENT_Connection *client;
55 80
56 /** 81 /**
57 * FIXME. 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?
58 */ 93 */
59 struct GNUNET_TIME_Absolute timeout; 94 struct GNUNET_TIME_Absolute timeout;
60};
61 95
96 /**
97 * Task handle for numeric lookups.
98 */
99 GNUNET_SCHEDULER_TaskIdentifier task;
100
101 /**
102 * Desired address family.
103 */
104 int domain;
62 105
63/** 106 /**
64 * Possible hostnames for "loopback". 107 * Length of the "struct sockaddr" that follows this
65 */ 108 * struct (only for reverse lookup).
66static const char *loopback[] = { 109 */
67 "localhost", 110 socklen_t salen;
68 "ip6-localnet",
69 NULL
70}; 111};
71 112
72 113
@@ -79,9 +120,20 @@ check_config (const struct GNUNET_CONFIGURATION_Handle *cfg)
79{ 120{
80 char *hostname; 121 char *hostname;
81 unsigned int i; 122 unsigned int i;
82 struct in_addr v4; 123 struct sockaddr_in v4;
83 struct in6_addr v6; 124 struct sockaddr_in6 v6;
84 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
85 if (GNUNET_OK != 137 if (GNUNET_OK !=
86 GNUNET_CONFIGURATION_get_value_string (cfg, 138 GNUNET_CONFIGURATION_get_value_string (cfg,
87 "resolver", 139 "resolver",
@@ -94,10 +146,10 @@ check_config (const struct GNUNET_CONFIGURATION_Handle *cfg)
94 "resolver"); 146 "resolver");
95 GNUNET_assert (0); 147 GNUNET_assert (0);
96 } 148 }
97 if ( (0 == inet_pton (AF_INET, 149 if ( (1 != inet_pton (AF_INET,
98 hostname, 150 hostname,
99 &v4)) || 151 &v4)) ||
100 (0 == inet_pton (AF_INET6, 152 (1 != inet_pton (AF_INET6,
101 hostname, 153 hostname,
102 &v6)) ) 154 &v6)) )
103 { 155 {
@@ -106,14 +158,15 @@ check_config (const struct GNUNET_CONFIGURATION_Handle *cfg)
106 } 158 }
107 i = 0; 159 i = 0;
108 while (loopback[i] != NULL) 160 while (loopback[i] != NULL)
109 if (0 == strcmp (loopback[i++], hostname)) 161 if (0 == strcasecmp (loopback[i++], hostname))
110 { 162 {
111 GNUNET_free (hostname); 163 GNUNET_free (hostname);
112 return; 164 return;
113 } 165 }
114 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 166 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
115 _("Must specify `%s' for `%s' in configuration!\n"), 167 _("Must specify `%s' or numeric IP address for `%s' of `%s' in configuration!\n"),
116 "localhost", 168 "localhost",
169 "HOSTNAME",
117 "resolver"); 170 "resolver");
118 GNUNET_free (hostname); 171 GNUNET_free (hostname);
119 GNUNET_assert (0); 172 GNUNET_assert (0);
@@ -163,15 +216,16 @@ no_resolve (const struct sockaddr *sa, socklen_t salen)
163 216
164 217
165/** 218/**
166 * FIXME 219 * Process the reply from the resolver (which is presumably
220 * the numeric IP address for a name resolution request).
167 * 221 *
168 * @param cls FIXME 222 * @param cls the "GNUNET_RESOLVER_RequestHandle" for which this is a reply
169 * @param msg FIXME 223 * @param msg reply from the resolver or NULL on error
170 */ 224 */
171static void 225static void
172handle_address_response (void *cls, const struct GNUNET_MessageHeader *msg) 226handle_address_response (void *cls, const struct GNUNET_MessageHeader *msg)
173{ 227{
174 struct GetAddressContext *gac = cls; 228 struct GNUNET_RESOLVER_RequestHandle *rh = cls;
175 uint16_t size; 229 uint16_t size;
176 const struct sockaddr *sa; 230 const struct sockaddr *sa;
177 socklen_t salen; 231 socklen_t salen;
@@ -181,17 +235,17 @@ handle_address_response (void *cls, const struct GNUNET_MessageHeader *msg)
181 { 235 {
182 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 236 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
183 _("Timeout trying to resolve hostname.\n")); 237 _("Timeout trying to resolve hostname.\n"));
184 gac->callback (gac->cls, NULL, 0); 238 rh->addr_callback (rh->cls, NULL, 0);
185 GNUNET_CLIENT_disconnect (gac->client); 239 GNUNET_CLIENT_disconnect (rh->client);
186 GNUNET_free (gac); 240 GNUNET_free (rh);
187 return; 241 return;
188 } 242 }
189 if (GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE != ntohs (msg->type)) 243 if (GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE != ntohs (msg->type))
190 { 244 {
191 GNUNET_break (0); 245 GNUNET_break (0);
192 gac->callback (gac->cls, NULL, 0); 246 rh->addr_callback (rh->cls, NULL, 0);
193 GNUNET_CLIENT_disconnect (gac->client); 247 GNUNET_CLIENT_disconnect (rh->client);
194 GNUNET_free (gac); 248 GNUNET_free (rh);
195 return; 249 return;
196 } 250 }
197 251
@@ -202,9 +256,9 @@ handle_address_response (void *cls, const struct GNUNET_MessageHeader *msg)
202 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 256 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
203 _("Received end message resolving hostname.\n")); 257 _("Received end message resolving hostname.\n"));
204#endif 258#endif
205 gac->callback (gac->cls, NULL, 0); 259 rh->addr_callback (rh->cls, NULL, 0);
206 GNUNET_CLIENT_disconnect (gac->client); 260 GNUNET_CLIENT_disconnect (rh->client);
207 GNUNET_free (gac); 261 GNUNET_free (rh);
208 return; 262 return;
209 } 263 }
210 sa = (const struct sockaddr *) &msg[1]; 264 sa = (const struct sockaddr *) &msg[1];
@@ -212,56 +266,45 @@ handle_address_response (void *cls, const struct GNUNET_MessageHeader *msg)
212 if (salen < sizeof (struct sockaddr)) 266 if (salen < sizeof (struct sockaddr))
213 { 267 {
214 GNUNET_break (0); 268 GNUNET_break (0);
215 gac->callback (gac->cls, NULL, 0); 269 rh->addr_callback (rh->cls, NULL, 0);
216 GNUNET_CLIENT_disconnect (gac->client); 270 GNUNET_CLIENT_disconnect (rh->client);
217 GNUNET_free (gac); 271 GNUNET_free (rh);
218 return; 272 return;
219 } 273 }
220#if DEBUG_RESOLVER 274#if DEBUG_RESOLVER
221 { 275 {
222 char *ips = no_resolve (sa, salen); 276 char *ips = no_resolve (sa, salen);
223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Resolver returns `%s'.\n"), ips); 277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
278 "Resolver returns `%s'.\n",
279 ips);
224 GNUNET_free (ips); 280 GNUNET_free (ips);
225 } 281 }
226#endif 282#endif
227 gac->callback (gac->cls, sa, salen); 283 rh->addr_callback (rh->cls, sa, salen);
228 GNUNET_CLIENT_receive (gac->client, 284 GNUNET_CLIENT_receive (rh->client,
229 &handle_address_response, 285 &handle_address_response,
230 gac, 286 rh,
231 GNUNET_TIME_absolute_get_remaining (gac->timeout)); 287 GNUNET_TIME_absolute_get_remaining (rh->timeout));
232} 288}
233 289
234 290
235/** 291/**
236 * Convert a string to one or more IP addresses. 292 * We've been asked to lookup the address for a hostname and were
293 * given a valid numeric string. Perform the callbacks for the
294 * numeric addresses.
237 * 295 *
238 * @param sched scheduler to use 296 * @param cls struct GNUNET_RESOLVER_RequestHandle for the request
239 * @param cfg configuration to use 297 * @param tc unused scheduler context
240 * @param hostname the hostname to resolve
241 * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any"
242 * @param callback function to call with addresses
243 * @param callback_cls closure for callback
244 * @param timeout how long to try resolving
245 */ 298 */
246void 299static void
247GNUNET_RESOLVER_ip_get (struct GNUNET_SCHEDULER_Handle *sched, 300numeric_resolution (void *cls,
248 const struct GNUNET_CONFIGURATION_Handle *cfg, 301 const struct GNUNET_SCHEDULER_TaskContext *tc)
249 const char *hostname,
250 int domain,
251 struct GNUNET_TIME_Relative timeout,
252 GNUNET_RESOLVER_AddressCallback callback,
253 void *callback_cls)
254{ 302{
255 struct GNUNET_CLIENT_Connection *client; 303 struct GNUNET_RESOLVER_RequestHandle *rh = cls;
256 struct GNUNET_RESOLVER_GetMessage *msg;
257 struct GetAddressContext *actx;
258 size_t slen;
259 unsigned int i;
260 struct sockaddr_in v4; 304 struct sockaddr_in v4;
261 struct sockaddr_in6 v6; 305 struct sockaddr_in6 v6;
262 306
263 memset (&v4, 0, sizeof(v4)); 307 memset (&v4, 0, sizeof(v4));
264 v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
265 v4.sin_family = AF_INET; 308 v4.sin_family = AF_INET;
266#if HAVE_SOCKADDR_IN_SIN_LEN 309#if HAVE_SOCKADDR_IN_SIN_LEN
267 v4.sin_len = sizeof(v4); 310 v4.sin_len = sizeof(v4);
@@ -271,97 +314,202 @@ GNUNET_RESOLVER_ip_get (struct GNUNET_SCHEDULER_Handle *sched,
271#if HAVE_SOCKADDR_IN_SIN_LEN 314#if HAVE_SOCKADDR_IN_SIN_LEN
272 v6.sin6_len = sizeof(v6); 315 v6.sin6_len = sizeof(v6);
273#endif 316#endif
274 /* first, check if this is a numeric address */ 317
275 if ( ( (domain == AF_UNSPEC) || (domain == AF_INET) ) && 318 if ( ( (rh->domain == AF_UNSPEC) || (rh->domain == AF_INET) ) &&
276 (1 == inet_pton (AF_INET, 319 (1 == inet_pton (AF_INET,
277 hostname, 320 rh->hostname,
278 &v4.sin_addr)) ) 321 &v4.sin_addr)) )
279 { 322 {
280 callback (callback_cls, 323 rh->addr_callback (rh->cls,
281 (const struct sockaddr*) &v4, 324 (const struct sockaddr*) &v4,
282 sizeof(v4)); 325 sizeof(v4));
283 if ( (domain == AF_UNSPEC) && 326 if ( (rh->domain == AF_UNSPEC) &&
284 (1 == inet_pton (AF_INET6, 327 (1 == inet_pton (AF_INET6,
285 hostname, 328 rh->hostname,
286 &v6.sin6_addr)) ) 329 &v6.sin6_addr)) )
287 { 330 {
288 /* this can happen on some systems IF "hostname" is "localhost" */ 331 /* this can happen on some systems IF "hostname" is "localhost" */
289 callback (callback_cls, 332 rh->addr_callback (rh->cls,
290 (const struct sockaddr*) &v6, 333 (const struct sockaddr*) &v6,
291 sizeof(v6)); 334 sizeof(v6));
292 } 335 }
293 callback (callback_cls, NULL, 0); 336 rh->addr_callback (rh->cls, NULL, 0);
337 GNUNET_free (rh);
294 return; 338 return;
295 } 339 }
296 if ( ( (domain == AF_UNSPEC) || (domain == AF_INET6) ) && 340 if ( ( (rh->domain == AF_UNSPEC) || (rh->domain == AF_INET6) ) &&
297 (1 == inet_pton (AF_INET6, 341 (1 == inet_pton (AF_INET6,
298 hostname, 342 rh->hostname,
299 &v6.sin6_addr)) ) 343 &v6.sin6_addr)) )
300 { 344 {
301 callback (callback_cls, 345 rh->addr_callback (rh->cls,
302 (const struct sockaddr*) &v6, 346 (const struct sockaddr*) &v6,
303 sizeof(v6)); 347 sizeof(v6));
304 callback (callback_cls, NULL, 0); 348 rh->addr_callback (rh->cls, NULL, 0);
349 GNUNET_free (rh);
305 return; 350 return;
306 } 351 }
352 /* why are we here? this task should not have been scheduled! */
353 GNUNET_assert (0);
354 GNUNET_free (rh);
355}
356
357
358
359/**
360 * We've been asked to lookup the address for a hostname and were
361 * given a variant of "loopback". Perform the callbacks for the
362 * respective loopback numeric addresses.
363 *
364 * @param cls struct GNUNET_RESOLVER_RequestHandle for the request
365 * @param tc unused scheduler context
366 */
367static void
368loopback_resolution (void *cls,
369 const struct GNUNET_SCHEDULER_TaskContext *tc)
370{
371 struct GNUNET_RESOLVER_RequestHandle *rh = cls;
372 struct sockaddr_in v4;
373 struct sockaddr_in6 v6;
374
375 memset (&v4, 0, sizeof(v4));
376 v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
377 v4.sin_family = AF_INET;
378#if HAVE_SOCKADDR_IN_SIN_LEN
379 v4.sin_len = sizeof(v4);
380#endif
381 memset (&v6, 0, sizeof(v6));
382 v6.sin6_family = AF_INET6;
383#if HAVE_SOCKADDR_IN_SIN_LEN
384 v6.sin6_len = sizeof(v6);
385#endif
386 v6.sin6_addr = in6addr_loopback;
387 switch (rh->domain)
388 {
389 case AF_INET:
390 rh->addr_callback (rh->cls,
391 (const struct sockaddr*) &v4,
392 sizeof(v4));
393 break;
394 case AF_INET6:
395 rh->addr_callback (rh->cls,
396 (const struct sockaddr*) &v6,
397 sizeof(v6));
398 break;
399 case AF_UNSPEC:
400 rh->addr_callback (rh->cls,
401 (const struct sockaddr*) &v6,
402 sizeof(v6));
403 rh->addr_callback (rh->cls,
404 (const struct sockaddr*) &v4,
405 sizeof(v4));
406 break;
407 default:
408 GNUNET_break (0);
409 break;
410 }
411 rh->addr_callback (rh->cls, NULL, 0);
412 GNUNET_free (rh);
413}
414
415
416/**
417 * Convert a string to one or more IP addresses.
418 *
419 * @param sched scheduler to use
420 * @param cfg configuration to use
421 * @param hostname the hostname to resolve
422 * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any"
423 * @param callback function to call with addresses
424 * @param callback_cls closure for callback
425 * @param timeout how long to try resolving
426 * @return handle that can be used to cancel the request, NULL on error
427 */
428struct GNUNET_RESOLVER_RequestHandle *
429GNUNET_RESOLVER_ip_get (struct GNUNET_SCHEDULER_Handle *sched,
430 const struct GNUNET_CONFIGURATION_Handle *cfg,
431 const char *hostname,
432 int domain,
433 struct GNUNET_TIME_Relative timeout,
434 GNUNET_RESOLVER_AddressCallback callback,
435 void *callback_cls)
436{
437 struct GNUNET_CLIENT_Connection *client;
438 struct GNUNET_RESOLVER_GetMessage *msg;
439 struct GNUNET_RESOLVER_RequestHandle *rh;
440 size_t slen;
441 unsigned int i;
442 struct in_addr v4;
443 struct in6_addr v6;
444 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE];
445
307 check_config (cfg); 446 check_config (cfg);
308 /* then, check if this is a loopback address */
309 i = 0;
310 while (loopback[i] != NULL)
311 if (0 == strcmp (loopback[i++], hostname))
312 {
313 v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
314 v6.sin6_addr = in6addr_loopback;
315 switch (domain)
316 {
317 case AF_INET:
318 callback (callback_cls,
319 (const struct sockaddr*) &v4,
320 sizeof(v4));
321 break;
322 case AF_INET6:
323 callback (callback_cls,
324 (const struct sockaddr*) &v6,
325 sizeof(v6));
326 break;
327 case AF_UNSPEC:
328 callback (callback_cls,
329 (const struct sockaddr*) &v6,
330 sizeof(v6));
331 callback (callback_cls,
332 (const struct sockaddr*) &v4,
333 sizeof(v4));
334 break;
335 }
336 callback (callback_cls, NULL, 0);
337 return;
338 }
339 slen = strlen (hostname) + 1; 447 slen = strlen (hostname) + 1;
340 if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) > 448 if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) >
341 GNUNET_SERVER_MAX_MESSAGE_SIZE) 449 GNUNET_SERVER_MAX_MESSAGE_SIZE)
342 { 450 {
343 GNUNET_break (0); 451 GNUNET_break (0);
344 callback (callback_cls, NULL, 0); 452 return NULL;
345 return; 453 }
454 rh = GNUNET_malloc (sizeof(struct GNUNET_RESOLVER_RequestHandle) + slen);
455 rh->client = client;
456 rh->sched = sched;
457 rh->domain = domain;
458 rh->addr_callback = callback;
459 rh->cls = callback_cls;
460 memcpy (&rh[1], hostname, slen);
461 rh->hostname = (const char*) &rh[1];
462 rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
463
464 /* first, check if this is a numeric address */
465 if ( ( (1 == inet_pton (AF_INET,
466 hostname,
467 &v4)) &&
468 ( (domain == AF_INET) || (domain == AF_UNSPEC)) ) ||
469 ( (1 == inet_pton (AF_INET6,
470 hostname,
471 &v6)) &&
472 ( (domain == AF_INET6) || (domain == AF_UNSPEC)) ) )
473 {
474 rh->task = GNUNET_SCHEDULER_add_delayed (sched,
475 GNUNET_NO,
476 GNUNET_SCHEDULER_PRIORITY_KEEP,
477 GNUNET_SCHEDULER_NO_TASK,
478 GNUNET_TIME_UNIT_ZERO,
479 &numeric_resolution,
480 rh);
481 return rh;
346 } 482 }
483 /* then, check if this is a loopback address */
484 i = 0;
485 while (loopback[i] != NULL)
486 if (0 == strcasecmp (loopback[i++], hostname))
487 {
488 rh->task = GNUNET_SCHEDULER_add_delayed (sched,
489 GNUNET_NO,
490 GNUNET_SCHEDULER_PRIORITY_KEEP,
491 GNUNET_SCHEDULER_NO_TASK,
492 GNUNET_TIME_UNIT_ZERO,
493 &loopback_resolution,
494 rh);
495 return rh;
496 }
497
347 client = GNUNET_CLIENT_connect (sched, "resolver", cfg); 498 client = GNUNET_CLIENT_connect (sched, "resolver", cfg);
348 if (client == NULL) 499 if (client == NULL)
349 { 500 {
350 callback (callback_cls, NULL, 0); 501 GNUNET_free (rh);
351 return; 502 return NULL;
352 } 503 }
353 msg = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_GetMessage) + slen); 504 rh->client = client;
505
506 msg = (struct GNUNET_RESOLVER_GetMessage*) buf;
354 msg->header.size = 507 msg->header.size =
355 htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + slen); 508 htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + slen);
356 msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST); 509 msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
357 msg->direction = htonl (GNUNET_NO); 510 msg->direction = htonl (GNUNET_NO);
358 msg->domain = htonl (domain); 511 msg->domain = htonl (domain);
359 memcpy (&msg[1], hostname, slen); 512 memcpy (&msg[1], hostname, slen);
360 actx = GNUNET_malloc (sizeof (struct GetAddressContext));
361 actx->callback = callback;
362 actx->cls = callback_cls;
363 actx->client = client;
364 actx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
365 513
366#if DEBUG_RESOLVER 514#if DEBUG_RESOLVER
367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 515 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -374,56 +522,27 @@ GNUNET_RESOLVER_ip_get (struct GNUNET_SCHEDULER_Handle *sched,
374 timeout, 522 timeout,
375 GNUNET_YES, 523 GNUNET_YES,
376 &handle_address_response, 524 &handle_address_response,
377 actx)) 525 rh))
378 { 526 {
379 GNUNET_free (msg); 527 GNUNET_free (rh);
380 GNUNET_free (actx);
381 callback (callback_cls, NULL, 0);
382 GNUNET_CLIENT_disconnect (client); 528 GNUNET_CLIENT_disconnect (client);
383 return; 529 return NULL;
384 } 530 }
385 GNUNET_free (msg); 531 return rh;
386} 532}
387 533
388 534
389/** 535/**
390 * FIXME. 536 * Process response with a hostname for a reverse DNS lookup.
391 */
392struct GetHostnameContext
393{
394
395 /**
396 * FIXME.
397 */
398 GNUNET_RESOLVER_HostnameCallback callback;
399
400 /**
401 * FIXME.
402 */
403 void *cls;
404
405 /**
406 * FIXME.
407 */
408 struct GNUNET_CLIENT_Connection *client;
409
410 /**
411 * FIXME.
412 */
413 struct GNUNET_TIME_Absolute timeout;
414};
415
416
417/**
418 * FIXME.
419 * 537 *
420 * @param cls FIXME 538 * @param cls our "struct GNUNET_RESOLVER_RequestHandle" context
421 * @param msg FIXME 539 * @param msg message with the hostname, NULL on error
422 */ 540 */
423static void 541static void
424handle_hostname_response (void *cls, const struct GNUNET_MessageHeader *msg) 542handle_hostname_response (void *cls,
543 const struct GNUNET_MessageHeader *msg)
425{ 544{
426 struct GetHostnameContext *ghc = cls; 545 struct GNUNET_RESOLVER_RequestHandle *rh = cls;
427 uint16_t size; 546 uint16_t size;
428 const char *hostname; 547 const char *hostname;
429 548
@@ -431,9 +550,9 @@ handle_hostname_response (void *cls, const struct GNUNET_MessageHeader *msg)
431 { 550 {
432 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 551 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
433 _("Timeout trying to resolve IP address.\n")); 552 _("Timeout trying to resolve IP address.\n"));
434 ghc->callback (ghc->cls, NULL); 553 rh->name_callback (rh->cls, NULL);
435 GNUNET_CLIENT_disconnect (ghc->client); 554 GNUNET_CLIENT_disconnect (rh->client);
436 GNUNET_free (ghc); 555 GNUNET_free (rh);
437 return; 556 return;
438 } 557 }
439 size = ntohs (msg->size); 558 size = ntohs (msg->size);
@@ -443,32 +562,64 @@ handle_hostname_response (void *cls, const struct GNUNET_MessageHeader *msg)
443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 562 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
444 _("Received end message resolving IP address.\n")); 563 _("Received end message resolving IP address.\n"));
445#endif 564#endif
446 ghc->callback (ghc->cls, NULL); 565 rh->name_callback (rh->cls, NULL);
447 GNUNET_CLIENT_disconnect (ghc->client); 566 GNUNET_CLIENT_disconnect (rh->client);
448 GNUNET_free (ghc); 567 GNUNET_free (rh);
449 return; 568 return;
450 } 569 }
451 hostname = (const char *) &msg[1]; 570 hostname = (const char *) &msg[1];
452 if (hostname[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0') 571 if (hostname[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0')
453 { 572 {
454 GNUNET_break (0); 573 GNUNET_break (0);
455 ghc->callback (ghc->cls, NULL); 574 rh->name_callback (rh->cls, NULL);
456 GNUNET_CLIENT_disconnect (ghc->client); 575 GNUNET_CLIENT_disconnect (rh->client);
457 GNUNET_free (ghc); 576 GNUNET_free (rh);
458 return; 577 return;
459 } 578 }
460#if DEBUG_RESOLVER 579#if DEBUG_RESOLVER
461 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 580 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
462 _("Resolver returns `%s'.\n"), hostname); 581 _("Resolver returns `%s'.\n"), hostname);
463#endif 582#endif
464 ghc->callback (ghc->cls, hostname); 583 rh->name_callback (rh->cls, hostname);
465 GNUNET_CLIENT_receive (ghc->client, 584 GNUNET_CLIENT_receive (rh->client,
466 &handle_hostname_response, 585 &handle_hostname_response,
467 ghc, 586 rh,
468 GNUNET_TIME_absolute_get_remaining (ghc->timeout)); 587 GNUNET_TIME_absolute_get_remaining (rh->timeout));
469} 588}
470 589
471 590
591
592/**
593 * We've been asked to convert an address to a string without
594 * a reverse lookup. Do it.
595 *
596 * @param cls struct GNUNET_RESOLVER_RequestHandle for the request
597 * @param tc unused scheduler context
598 */
599static void
600numeric_reverse (void *cls,
601 const struct GNUNET_SCHEDULER_TaskContext *tc)
602{
603 struct GNUNET_RESOLVER_RequestHandle *rh = cls;
604 char *result;
605
606 result = no_resolve ((const struct sockaddr*) &rh[1],
607 rh->salen);
608#if DEBUG_RESOLVER
609 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
610 _("Resolver returns `%s'.\n"), result);
611#endif
612 if (result != NULL)
613 {
614 rh->name_callback (rh->cls, result);
615 GNUNET_free (result);
616 }
617 rh->name_callback (rh->cls, NULL);
618 GNUNET_free (rh);
619}
620
621
622
472/** 623/**
473 * Get an IP address as a string. 624 * Get an IP address as a string.
474 * 625 *
@@ -480,8 +631,9 @@ handle_hostname_response (void *cls, const struct GNUNET_MessageHeader *msg)
480 * @param timeout how long to try resolving 631 * @param timeout how long to try resolving
481 * @param callback function to call with hostnames 632 * @param callback function to call with hostnames
482 * @param cls closure for callback 633 * @param cls closure for callback
634 * @return handle that can be used to cancel the request
483 */ 635 */
484void 636struct GNUNET_RESOLVER_RequestHandle *
485GNUNET_RESOLVER_hostname_get (struct GNUNET_SCHEDULER_Handle *sched, 637GNUNET_RESOLVER_hostname_get (struct GNUNET_SCHEDULER_Handle *sched,
486 const struct GNUNET_CONFIGURATION_Handle *cfg, 638 const struct GNUNET_CONFIGURATION_Handle *cfg,
487 const struct sockaddr *sa, 639 const struct sockaddr *sa,
@@ -491,41 +643,47 @@ GNUNET_RESOLVER_hostname_get (struct GNUNET_SCHEDULER_Handle *sched,
491 GNUNET_RESOLVER_HostnameCallback callback, 643 GNUNET_RESOLVER_HostnameCallback callback,
492 void *cls) 644 void *cls)
493{ 645{
494 char *result;
495 struct GNUNET_CLIENT_Connection *client; 646 struct GNUNET_CLIENT_Connection *client;
496 struct GNUNET_RESOLVER_GetMessage *msg; 647 struct GNUNET_RESOLVER_GetMessage *msg;
497 struct GetHostnameContext *hctx; 648 struct GNUNET_RESOLVER_RequestHandle *rh;
649 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE];
498 650
499 check_config (cfg); 651 check_config (cfg);
652 rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + salen);
653 rh->name_callback = callback;
654 rh->cls = cls;
655 rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
656 rh->sched = sched;
657 rh->salen = salen;
658 memcpy (&rh[1], sa, salen);
659
500 if (GNUNET_NO == do_resolve) 660 if (GNUNET_NO == do_resolve)
501 { 661 {
502 result = no_resolve (sa, salen); 662 rh->task = GNUNET_SCHEDULER_add_delayed (sched,
503#if DEBUG_RESOLVER 663 GNUNET_NO,
504 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 664 GNUNET_SCHEDULER_PRIORITY_KEEP,
505 _("Resolver returns `%s'.\n"), result); 665 GNUNET_SCHEDULER_NO_TASK,
506#endif 666 GNUNET_TIME_UNIT_ZERO,
507 callback (cls, result); 667 &numeric_reverse,
508 if (result != NULL) 668 rh);
509 { 669 return rh;
510 GNUNET_free (result);
511 callback (cls, NULL);
512 }
513 return;
514 } 670 }
515 if (salen + sizeof (struct GNUNET_RESOLVER_GetMessage) > 671 if (salen + sizeof (struct GNUNET_RESOLVER_GetMessage) >
516 GNUNET_SERVER_MAX_MESSAGE_SIZE) 672 GNUNET_SERVER_MAX_MESSAGE_SIZE)
517 { 673 {
518 GNUNET_break (0); 674 GNUNET_break (0);
519 callback (cls, NULL); 675 GNUNET_free (rh);
520 return; 676 return NULL;
521 } 677 }
522 client = GNUNET_CLIENT_connect (sched, "resolver", cfg); 678 client = GNUNET_CLIENT_connect (sched, "resolver", cfg);
523 if (client == NULL) 679 if (client == NULL)
524 { 680 {
525 callback (cls, NULL); 681 GNUNET_free (rh);
526 return; 682 return NULL;
527 } 683 }
528 msg = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_GetMessage) + salen); 684 rh->client = client;
685
686 msg = (struct GNUNET_RESOLVER_GetMessage*) buf;
529 msg->header.size = 687 msg->header.size =
530 htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + salen); 688 htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + salen);
531 msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST); 689 msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
@@ -536,36 +694,24 @@ GNUNET_RESOLVER_hostname_get (struct GNUNET_SCHEDULER_Handle *sched,
536 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 694 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
537 _("Resolver requests DNS resolution of IP address.\n")); 695 _("Resolver requests DNS resolution of IP address.\n"));
538#endif 696#endif
539 hctx = GNUNET_malloc (sizeof (struct GetHostnameContext));
540 hctx->callback = callback;
541 hctx->cls = cls;
542 hctx->client = client;
543 hctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
544 if (GNUNET_OK != 697 if (GNUNET_OK !=
545 GNUNET_CLIENT_transmit_and_get_response (client, 698 GNUNET_CLIENT_transmit_and_get_response (client,
546 &msg->header, 699 &msg->header,
547 timeout, 700 timeout,
548 GNUNET_YES, 701 GNUNET_YES,
549 &handle_hostname_response, 702 &handle_hostname_response,
550 hctx)) 703 rh))
551 { 704 {
552 GNUNET_free (msg);
553 callback (cls, NULL);
554 GNUNET_CLIENT_disconnect (client); 705 GNUNET_CLIENT_disconnect (client);
555 GNUNET_free (hctx); 706 GNUNET_free (rh);
556 return; 707 return NULL;
557 } 708 }
558 GNUNET_free (msg); 709 return rh;
559} 710}
560 711
561/**
562 * Maximum supported length of hostname
563 */
564#define MAX_HOSTNAME 1024
565
566 712
567/** 713/**
568 * Resolve our hostname to an IP address. 714 * Perform a reverse DNS lookup.
569 * 715 *
570 * @param sched scheduler to use 716 * @param sched scheduler to use
571 * @param cfg configuration to use 717 * @param cfg configuration to use
@@ -573,8 +719,9 @@ GNUNET_RESOLVER_hostname_get (struct GNUNET_SCHEDULER_Handle *sched,
573 * @param callback function to call with addresses 719 * @param callback function to call with addresses
574 * @param cls closure for callback 720 * @param cls closure for callback
575 * @param timeout how long to try resolving 721 * @param timeout how long to try resolving
722 * @return handle that can be used to cancel the request, NULL on error
576 */ 723 */
577void 724struct GNUNET_RESOLVER_RequestHandle *
578GNUNET_RESOLVER_hostname_resolve (struct GNUNET_SCHEDULER_Handle *sched, 725GNUNET_RESOLVER_hostname_resolve (struct GNUNET_SCHEDULER_Handle *sched,
579 const struct GNUNET_CONFIGURATION_Handle *cfg, 726 const struct GNUNET_CONFIGURATION_Handle *cfg,
580 int domain, 727 int domain,
@@ -589,18 +736,36 @@ GNUNET_RESOLVER_hostname_resolve (struct GNUNET_SCHEDULER_Handle *sched,
589 { 736 {
590 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | 737 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR |
591 GNUNET_ERROR_TYPE_BULK, "gethostname"); 738 GNUNET_ERROR_TYPE_BULK, "gethostname");
592 callback (cls, NULL, 0); 739 return NULL;
593 return;
594 } 740 }
595#if DEBUG_RESOLVER 741#if DEBUG_RESOLVER
596 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 742 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
597 _("Resolving our hostname `%s'\n"), hostname); 743 _("Resolving our hostname `%s'\n"), hostname);
598#endif 744#endif
599 GNUNET_RESOLVER_ip_get (sched, 745 return GNUNET_RESOLVER_ip_get (sched,
600 cfg, hostname, domain, timeout, callback, cls); 746 cfg, hostname, domain, timeout, callback, cls);
601} 747}
602 748
603 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 */
758void
759GNUNET_RESOLVER_request_cancel (struct GNUNET_RESOLVER_RequestHandle *h)
760{
761 if (h->client != NULL)
762 GNUNET_CLIENT_disconnect (h->client);
763 if (h->task != GNUNET_SCHEDULER_NO_TASK)
764 GNUNET_SCHEDULER_cancel (h->sched,
765 h->task);
766 GNUNET_free (h);
767}
768
604 769
605 770
606/* end of resolver_api.c */ 771/* end of resolver_api.c */