diff options
author | Christian Grothoff <christian@grothoff.org> | 2009-10-27 22:27:11 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2009-10-27 22:27:11 +0000 |
commit | b3443c6ab7b18ee57866ac531bf9f40aa3eb5261 (patch) | |
tree | 272b88c59422b9954acb6c7ee08e4a2e9e520a70 /src/util/resolver_api.c | |
parent | 64d39ac5f14b54eecc2c7cd99b04d05ff04a894f (diff) | |
download | gnunet-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.c | 599 |
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 | */ |
38 | struct GetAddressContext | 38 | #define MAX_HOSTNAME 1024 |
39 | |||
40 | |||
41 | /** | ||
42 | * Possible hostnames for "loopback". | ||
43 | */ | ||
44 | static const char *loopback[] = { | ||
45 | "localhost", | ||
46 | "ip6-localnet", | ||
47 | NULL | ||
48 | }; | ||
49 | |||
50 | |||
51 | /** | ||
52 | * Handle to a request given to the resolver. Can be used to cancel | ||
53 | * the request prior to the timeout or successful execution. Also | ||
54 | * used to track our internal state for the request. | ||
55 | */ | ||
56 | struct GNUNET_RESOLVER_RequestHandle | ||
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). |
66 | static 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 | */ |
171 | static void | 225 | static void |
172 | handle_address_response (void *cls, const struct GNUNET_MessageHeader *msg) | 226 | handle_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 | */ |
246 | void | 299 | static void |
247 | GNUNET_RESOLVER_ip_get (struct GNUNET_SCHEDULER_Handle *sched, | 300 | numeric_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 | */ | ||
367 | static void | ||
368 | loopback_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 | */ | ||
428 | struct GNUNET_RESOLVER_RequestHandle * | ||
429 | GNUNET_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 | */ | ||
392 | struct 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 | */ |
423 | static void | 541 | static void |
424 | handle_hostname_response (void *cls, const struct GNUNET_MessageHeader *msg) | 542 | handle_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 | */ | ||
599 | static void | ||
600 | numeric_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 | */ |
484 | void | 636 | struct GNUNET_RESOLVER_RequestHandle * |
485 | GNUNET_RESOLVER_hostname_get (struct GNUNET_SCHEDULER_Handle *sched, | 637 | GNUNET_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 | */ |
577 | void | 724 | struct GNUNET_RESOLVER_RequestHandle * |
578 | GNUNET_RESOLVER_hostname_resolve (struct GNUNET_SCHEDULER_Handle *sched, | 725 | GNUNET_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 | */ | ||
758 | void | ||
759 | GNUNET_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 */ |