diff options
Diffstat (limited to 'src/util/resolver_api.c')
-rw-r--r-- | src/util/resolver_api.c | 1294 |
1 files changed, 0 insertions, 1294 deletions
diff --git a/src/util/resolver_api.c b/src/util/resolver_api.c deleted file mode 100644 index d38c700e4..000000000 --- a/src/util/resolver_api.c +++ /dev/null | |||
@@ -1,1294 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009-2018 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your 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 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
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_util_lib.h" | ||
28 | #include "gnunet_protocols.h" | ||
29 | #include "gnunet_resolver_service.h" | ||
30 | #include "resolver.h" | ||
31 | |||
32 | #define LOG(kind, ...) GNUNET_log_from (kind, "util-resolver-api", __VA_ARGS__) | ||
33 | |||
34 | #define LOG_STRERROR(kind, syscall) GNUNET_log_from_strerror (kind, \ | ||
35 | "util-resolver-api", \ | ||
36 | syscall) | ||
37 | |||
38 | /** | ||
39 | * Maximum supported length for a hostname | ||
40 | */ | ||
41 | #define MAX_HOSTNAME 1024 | ||
42 | |||
43 | |||
44 | /** | ||
45 | * Possible hostnames for "loopback". | ||
46 | */ | ||
47 | static const char *loopback[] = { | ||
48 | "localhost", | ||
49 | "ip6-localnet", | ||
50 | NULL | ||
51 | }; | ||
52 | |||
53 | |||
54 | /** | ||
55 | * Configuration. | ||
56 | */ | ||
57 | static const struct GNUNET_CONFIGURATION_Handle *resolver_cfg; | ||
58 | |||
59 | /** | ||
60 | * Our connection to the resolver service, created on-demand, but then | ||
61 | * persists until error or shutdown. | ||
62 | */ | ||
63 | static struct GNUNET_MQ_Handle *mq; | ||
64 | |||
65 | /** | ||
66 | * Head of DLL of requests. | ||
67 | */ | ||
68 | static struct GNUNET_RESOLVER_RequestHandle *req_head; | ||
69 | |||
70 | /** | ||
71 | * Tail of DLL of requests. | ||
72 | */ | ||
73 | static struct GNUNET_RESOLVER_RequestHandle *req_tail; | ||
74 | |||
75 | /** | ||
76 | * ID of the last request we sent to the service | ||
77 | */ | ||
78 | static uint32_t last_request_id; | ||
79 | |||
80 | /** | ||
81 | * How long should we wait to reconnect? | ||
82 | */ | ||
83 | static struct GNUNET_TIME_Relative backoff; | ||
84 | |||
85 | /** | ||
86 | * Task for reconnecting. | ||
87 | */ | ||
88 | static struct GNUNET_SCHEDULER_Task *r_task; | ||
89 | |||
90 | /** | ||
91 | * Task ID of shutdown task; only present while we have a | ||
92 | * connection to the resolver service. | ||
93 | */ | ||
94 | static struct GNUNET_SCHEDULER_Task *s_task; | ||
95 | |||
96 | |||
97 | /** | ||
98 | * Handle to a request given to the resolver. Can be used to cancel | ||
99 | * the request prior to the timeout or successful execution. Also | ||
100 | * used to track our internal state for the request. | ||
101 | */ | ||
102 | struct GNUNET_RESOLVER_RequestHandle | ||
103 | { | ||
104 | /** | ||
105 | * Next entry in DLL of requests. | ||
106 | */ | ||
107 | struct GNUNET_RESOLVER_RequestHandle *next; | ||
108 | |||
109 | /** | ||
110 | * Previous entry in DLL of requests. | ||
111 | */ | ||
112 | struct GNUNET_RESOLVER_RequestHandle *prev; | ||
113 | |||
114 | /** | ||
115 | * Callback if this is an name resolution request, | ||
116 | * otherwise NULL. | ||
117 | */ | ||
118 | GNUNET_RESOLVER_AddressCallback addr_callback; | ||
119 | |||
120 | /** | ||
121 | * Callback if this is a reverse lookup request, | ||
122 | * otherwise NULL. | ||
123 | */ | ||
124 | GNUNET_RESOLVER_HostnameCallback name_callback; | ||
125 | |||
126 | /** | ||
127 | * Closure for the callbacks. | ||
128 | */ | ||
129 | void *cls; | ||
130 | |||
131 | /** | ||
132 | * When should this request time out? | ||
133 | */ | ||
134 | struct GNUNET_TIME_Absolute timeout; | ||
135 | |||
136 | /** | ||
137 | * Task handle for making reply callbacks in numeric lookups | ||
138 | * asynchronous, and for timeout handling. | ||
139 | */ | ||
140 | struct GNUNET_SCHEDULER_Task *task; | ||
141 | |||
142 | /** | ||
143 | * Desired address family. | ||
144 | */ | ||
145 | int af; | ||
146 | |||
147 | /** | ||
148 | * Identifies the request. The response will contain this id. | ||
149 | */ | ||
150 | uint32_t id; | ||
151 | |||
152 | /** | ||
153 | * Has this request been transmitted to the service? | ||
154 | * #GNUNET_YES if transmitted | ||
155 | * #GNUNET_NO if not transmitted | ||
156 | * #GNUNET_SYSERR when request was canceled | ||
157 | */ | ||
158 | int was_transmitted; | ||
159 | |||
160 | /** | ||
161 | * Did we add this request to the queue? | ||
162 | */ | ||
163 | int was_queued; | ||
164 | |||
165 | /** | ||
166 | * Desired direction (IP to name or name to IP) | ||
167 | */ | ||
168 | int direction; | ||
169 | |||
170 | /** | ||
171 | * #GNUNET_YES if a response was received | ||
172 | */ | ||
173 | int received_response; | ||
174 | |||
175 | /** | ||
176 | * Length of the data that follows this struct. | ||
177 | */ | ||
178 | size_t data_len; | ||
179 | }; | ||
180 | |||
181 | |||
182 | /** | ||
183 | * Check that the resolver service runs on localhost | ||
184 | * (or equivalent). | ||
185 | * | ||
186 | * @return #GNUNET_OK if the resolver is properly configured, | ||
187 | * #GNUNET_SYSERR otherwise. | ||
188 | */ | ||
189 | static int | ||
190 | check_config () | ||
191 | { | ||
192 | char *hostname; | ||
193 | struct sockaddr_in v4; | ||
194 | struct sockaddr_in6 v6; | ||
195 | |||
196 | if (GNUNET_OK == | ||
197 | GNUNET_CONFIGURATION_have_value (resolver_cfg, | ||
198 | "resolver", | ||
199 | "UNIXPATH")) | ||
200 | return GNUNET_OK; | ||
201 | memset (&v4, 0, sizeof(v4)); | ||
202 | v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | ||
203 | v4.sin_family = AF_INET; | ||
204 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
205 | v4.sin_len = sizeof(v4); | ||
206 | #endif | ||
207 | memset (&v6, 0, sizeof(v6)); | ||
208 | v6.sin6_family = AF_INET6; | ||
209 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
210 | v6.sin6_len = sizeof(v6); | ||
211 | #endif | ||
212 | if (GNUNET_OK != | ||
213 | GNUNET_CONFIGURATION_get_value_string (resolver_cfg, | ||
214 | "resolver", | ||
215 | "HOSTNAME", | ||
216 | &hostname)) | ||
217 | { | ||
218 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
219 | _ ( | ||
220 | "Missing `%s' for `%s' in configuration, DNS resolution will be unavailable.\n"), | ||
221 | "HOSTNAME", | ||
222 | "resolver"); | ||
223 | return GNUNET_SYSERR; | ||
224 | } | ||
225 | if ((1 == inet_pton (AF_INET, hostname, &v4)) || | ||
226 | (1 == inet_pton (AF_INET6, hostname, &v6))) | ||
227 | { | ||
228 | GNUNET_free (hostname); | ||
229 | return GNUNET_OK; | ||
230 | } | ||
231 | for (unsigned int i = 0; | ||
232 | NULL != loopback[i]; | ||
233 | i++) | ||
234 | if (0 == strcasecmp (loopback[i], | ||
235 | hostname)) | ||
236 | { | ||
237 | GNUNET_free (hostname); | ||
238 | return GNUNET_OK; | ||
239 | } | ||
240 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
241 | _ ( | ||
242 | "Missing `%s' or numeric IP address for `%s' of `%s' in configuration, DNS resolution will be unavailable.\n"), | ||
243 | "localhost", | ||
244 | "HOSTNAME", | ||
245 | "resolver"); | ||
246 | GNUNET_free (hostname); | ||
247 | return GNUNET_SYSERR; | ||
248 | } | ||
249 | |||
250 | |||
251 | /** | ||
252 | * Create the connection to the resolver service. | ||
253 | * | ||
254 | * @param cfg configuration to use | ||
255 | */ | ||
256 | void | ||
257 | GNUNET_RESOLVER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
258 | { | ||
259 | GNUNET_assert (NULL != cfg); | ||
260 | backoff = GNUNET_TIME_UNIT_MILLISECONDS; | ||
261 | resolver_cfg = cfg; | ||
262 | } | ||
263 | |||
264 | |||
265 | /** | ||
266 | * Destroy the connection to the resolver service. | ||
267 | */ | ||
268 | void | ||
269 | GNUNET_RESOLVER_disconnect () | ||
270 | { | ||
271 | struct GNUNET_RESOLVER_RequestHandle *rh; | ||
272 | |||
273 | while (NULL != (rh = req_head)) | ||
274 | { | ||
275 | GNUNET_assert (GNUNET_SYSERR == rh->was_transmitted); | ||
276 | GNUNET_CONTAINER_DLL_remove (req_head, | ||
277 | req_tail, | ||
278 | rh); | ||
279 | GNUNET_free (rh); | ||
280 | } | ||
281 | if (NULL != mq) | ||
282 | { | ||
283 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
284 | "Disconnecting from DNS service\n"); | ||
285 | GNUNET_MQ_destroy (mq); | ||
286 | mq = NULL; | ||
287 | } | ||
288 | if (NULL != r_task) | ||
289 | { | ||
290 | GNUNET_SCHEDULER_cancel (r_task); | ||
291 | r_task = NULL; | ||
292 | } | ||
293 | if (NULL != s_task) | ||
294 | { | ||
295 | GNUNET_SCHEDULER_cancel (s_task); | ||
296 | s_task = NULL; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | |||
301 | /** | ||
302 | * Task executed on system shutdown. | ||
303 | */ | ||
304 | static void | ||
305 | shutdown_task (void *cls) | ||
306 | { | ||
307 | (void) cls; | ||
308 | s_task = NULL; | ||
309 | GNUNET_RESOLVER_disconnect (); | ||
310 | backoff = GNUNET_TIME_UNIT_MILLISECONDS; | ||
311 | } | ||
312 | |||
313 | |||
314 | /** | ||
315 | * Consider disconnecting if we have no further requests pending. | ||
316 | */ | ||
317 | static void | ||
318 | check_disconnect () | ||
319 | { | ||
320 | for (struct GNUNET_RESOLVER_RequestHandle *rh = req_head; | ||
321 | NULL != rh; | ||
322 | rh = rh->next) | ||
323 | if (GNUNET_SYSERR != rh->was_transmitted) | ||
324 | return; | ||
325 | if (NULL != r_task) | ||
326 | { | ||
327 | GNUNET_SCHEDULER_cancel (r_task); | ||
328 | r_task = NULL; | ||
329 | } | ||
330 | if (NULL != s_task) | ||
331 | return; | ||
332 | s_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, | ||
333 | &shutdown_task, | ||
334 | NULL); | ||
335 | } | ||
336 | |||
337 | |||
338 | /** | ||
339 | * Convert IP address to string without DNS resolution. | ||
340 | * | ||
341 | * @param af address family | ||
342 | * @param ip the address | ||
343 | * @param ip_len number of bytes in @a ip | ||
344 | * @return address as a string, NULL on error | ||
345 | */ | ||
346 | static char * | ||
347 | no_resolve (int af, | ||
348 | const void *ip, | ||
349 | socklen_t ip_len) | ||
350 | { | ||
351 | char buf[INET6_ADDRSTRLEN]; | ||
352 | |||
353 | switch (af) | ||
354 | { | ||
355 | case AF_INET: | ||
356 | if (ip_len != sizeof(struct in_addr)) | ||
357 | return NULL; | ||
358 | if (NULL == | ||
359 | inet_ntop (AF_INET, | ||
360 | ip, | ||
361 | buf, | ||
362 | sizeof(buf))) | ||
363 | { | ||
364 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, | ||
365 | "inet_ntop"); | ||
366 | return NULL; | ||
367 | } | ||
368 | break; | ||
369 | |||
370 | case AF_INET6: | ||
371 | if (ip_len != sizeof(struct in6_addr)) | ||
372 | return NULL; | ||
373 | if (NULL == | ||
374 | inet_ntop (AF_INET6, | ||
375 | ip, | ||
376 | buf, | ||
377 | sizeof(buf))) | ||
378 | { | ||
379 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, | ||
380 | "inet_ntop"); | ||
381 | return NULL; | ||
382 | } | ||
383 | break; | ||
384 | |||
385 | default: | ||
386 | GNUNET_break (0); | ||
387 | return NULL; | ||
388 | } | ||
389 | return GNUNET_strdup (buf); | ||
390 | } | ||
391 | |||
392 | |||
393 | /** | ||
394 | * Adjust exponential back-off and reconnect to the service. | ||
395 | */ | ||
396 | static void | ||
397 | reconnect (void); | ||
398 | |||
399 | |||
400 | /** | ||
401 | * Generic error handler, called with the appropriate error code and | ||
402 | * the same closure specified at the creation of the message queue. | ||
403 | * Not every message queue implementation supports an error handler. | ||
404 | * | ||
405 | * @param cls NULL | ||
406 | * @param error error code | ||
407 | */ | ||
408 | static void | ||
409 | mq_error_handler (void *cls, | ||
410 | enum GNUNET_MQ_Error error) | ||
411 | { | ||
412 | (void) cls; | ||
413 | GNUNET_MQ_destroy (mq); | ||
414 | mq = NULL; | ||
415 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
416 | "MQ error %d, reconnecting\n", | ||
417 | error); | ||
418 | reconnect (); | ||
419 | } | ||
420 | |||
421 | |||
422 | /** | ||
423 | * Process pending requests to the resolver. | ||
424 | */ | ||
425 | static void | ||
426 | process_requests () | ||
427 | { | ||
428 | struct GNUNET_RESOLVER_GetMessage *msg; | ||
429 | struct GNUNET_MQ_Envelope *env; | ||
430 | struct GNUNET_RESOLVER_RequestHandle *rh = req_head; | ||
431 | |||
432 | if (NULL == mq) | ||
433 | { | ||
434 | reconnect (); | ||
435 | return; | ||
436 | } | ||
437 | if (NULL == rh) | ||
438 | { | ||
439 | /* nothing to do, release socket really soon if there is nothing | ||
440 | * else happening... */ | ||
441 | if (NULL == s_task) | ||
442 | s_task = | ||
443 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, | ||
444 | &shutdown_task, | ||
445 | NULL); | ||
446 | return; | ||
447 | } | ||
448 | if (GNUNET_NO != rh->was_transmitted) | ||
449 | return; /* waiting for reply */ | ||
450 | env = GNUNET_MQ_msg_extra (msg, | ||
451 | rh->data_len, | ||
452 | GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST); | ||
453 | msg->direction = htonl (rh->direction); | ||
454 | msg->af = htonl (rh->af); | ||
455 | msg->client_id = rh->id; | ||
456 | GNUNET_memcpy (&msg[1], | ||
457 | &rh[1], | ||
458 | rh->data_len); | ||
459 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
460 | "Transmitting DNS resolution request (ID %u) to DNS service\n", | ||
461 | rh->id); | ||
462 | GNUNET_MQ_send (mq, | ||
463 | env); | ||
464 | rh->was_transmitted = GNUNET_YES; | ||
465 | } | ||
466 | |||
467 | |||
468 | /** | ||
469 | * Check validity of response with a hostname for a DNS lookup. | ||
470 | * | ||
471 | * @param cls NULL | ||
472 | * @param msg message with the hostname | ||
473 | */ | ||
474 | static int | ||
475 | check_response (void *cls, | ||
476 | const struct GNUNET_RESOLVER_ResponseMessage *msg) | ||
477 | { | ||
478 | (void) cls; | ||
479 | (void) msg; | ||
480 | |||
481 | /* implemented in #handle_response() for now */ | ||
482 | return GNUNET_OK; | ||
483 | } | ||
484 | |||
485 | |||
486 | /** | ||
487 | * Check validity of response with a hostname for a DNS lookup. | ||
488 | * NOTE: right now rather messy, might want to use different | ||
489 | * message types for different response formats in the future. | ||
490 | * | ||
491 | * @param cls NULL | ||
492 | * @param msg message with the response | ||
493 | */ | ||
494 | static void | ||
495 | handle_response (void *cls, | ||
496 | const struct GNUNET_RESOLVER_ResponseMessage *msg) | ||
497 | { | ||
498 | struct GNUNET_RESOLVER_RequestHandle *rh = req_head; | ||
499 | uint16_t size; | ||
500 | char *nret; | ||
501 | uint32_t client_request_id = msg->client_id; | ||
502 | |||
503 | for (; rh != NULL; rh = rh->next) | ||
504 | { | ||
505 | if (rh->id == client_request_id) | ||
506 | break; | ||
507 | } | ||
508 | |||
509 | (void) cls; | ||
510 | if (NULL == rh) | ||
511 | { | ||
512 | /* Resolver service sent extra replies to query (after terminator)? Bad! */ | ||
513 | GNUNET_break (0); | ||
514 | GNUNET_MQ_destroy (mq); | ||
515 | mq = NULL; | ||
516 | reconnect (); | ||
517 | return; | ||
518 | } | ||
519 | size = ntohs (msg->header.size); | ||
520 | if (size == sizeof(struct GNUNET_RESOLVER_ResponseMessage)) | ||
521 | { | ||
522 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
523 | "Received empty response from DNS service\n"); | ||
524 | /* message contains not data, just header; end of replies */ | ||
525 | /* check if request was canceled */ | ||
526 | if (GNUNET_SYSERR != rh->was_transmitted) | ||
527 | { | ||
528 | /* no reverse lookup was successful, return IP as string */ | ||
529 | if (NULL != rh->name_callback) | ||
530 | { | ||
531 | if (GNUNET_NO == rh->received_response) | ||
532 | { | ||
533 | nret = no_resolve (rh->af, | ||
534 | &rh[1], | ||
535 | rh->data_len); | ||
536 | rh->name_callback (rh->cls, nret); | ||
537 | GNUNET_free (nret); | ||
538 | } | ||
539 | /* finally, make termination call */ | ||
540 | if (GNUNET_SYSERR != rh->was_transmitted) | ||
541 | rh->name_callback (rh->cls, | ||
542 | NULL); | ||
543 | } | ||
544 | if ((NULL != rh->addr_callback) && | ||
545 | (GNUNET_SYSERR != rh->was_transmitted)) | ||
546 | rh->addr_callback (rh->cls, | ||
547 | NULL, | ||
548 | 0); | ||
549 | } | ||
550 | rh->was_transmitted = GNUNET_NO; | ||
551 | GNUNET_RESOLVER_request_cancel (rh); | ||
552 | process_requests (); | ||
553 | return; | ||
554 | } | ||
555 | /* return reverse lookup results to caller */ | ||
556 | if (NULL != rh->name_callback) | ||
557 | { | ||
558 | const char *hostname; | ||
559 | |||
560 | hostname = (const char *) &msg[1]; | ||
561 | if (hostname[size - sizeof(struct GNUNET_RESOLVER_ResponseMessage) - 1] != | ||
562 | '\0') | ||
563 | { | ||
564 | GNUNET_break (0); | ||
565 | if (GNUNET_SYSERR != rh->was_transmitted) | ||
566 | rh->name_callback (rh->cls, | ||
567 | NULL); | ||
568 | rh->was_transmitted = GNUNET_NO; | ||
569 | GNUNET_RESOLVER_request_cancel (rh); | ||
570 | GNUNET_MQ_destroy (mq); | ||
571 | mq = NULL; | ||
572 | reconnect (); | ||
573 | return; | ||
574 | } | ||
575 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
576 | "Resolver returns `%s' for IP `%s'.\n", | ||
577 | hostname, | ||
578 | GNUNET_a2s ((const void *) &rh[1], | ||
579 | rh->data_len)); | ||
580 | if (rh->was_transmitted != GNUNET_SYSERR) | ||
581 | rh->name_callback (rh->cls, | ||
582 | hostname); | ||
583 | rh->received_response = GNUNET_YES; | ||
584 | } | ||
585 | /* return lookup results to caller */ | ||
586 | if (NULL != rh->addr_callback) | ||
587 | { | ||
588 | struct sockaddr_in v4; | ||
589 | struct sockaddr_in6 v6; | ||
590 | const struct sockaddr *sa; | ||
591 | socklen_t salen; | ||
592 | const void *ip; | ||
593 | size_t ip_len; | ||
594 | |||
595 | ip = &msg[1]; | ||
596 | ip_len = size - sizeof(struct GNUNET_RESOLVER_ResponseMessage); | ||
597 | if (ip_len == sizeof(struct in_addr)) | ||
598 | { | ||
599 | memset (&v4, 0, sizeof(v4)); | ||
600 | v4.sin_family = AF_INET; | ||
601 | v4.sin_addr = *(struct in_addr*) ip; | ||
602 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
603 | v4.sin_len = sizeof(v4); | ||
604 | #endif | ||
605 | salen = sizeof(v4); | ||
606 | sa = (const struct sockaddr *) &v4; | ||
607 | } | ||
608 | else if (ip_len == sizeof(struct in6_addr)) | ||
609 | { | ||
610 | memset (&v6, 0, sizeof(v6)); | ||
611 | v6.sin6_family = AF_INET6; | ||
612 | v6.sin6_addr = *(struct in6_addr*) ip; | ||
613 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
614 | v6.sin6_len = sizeof(v6); | ||
615 | #endif | ||
616 | salen = sizeof(v6); | ||
617 | sa = (const struct sockaddr *) &v6; | ||
618 | } | ||
619 | else | ||
620 | { | ||
621 | GNUNET_break (0); | ||
622 | if (GNUNET_SYSERR != rh->was_transmitted) | ||
623 | rh->addr_callback (rh->cls, | ||
624 | NULL, | ||
625 | 0); | ||
626 | rh->was_transmitted = GNUNET_NO; | ||
627 | GNUNET_RESOLVER_request_cancel (rh); | ||
628 | GNUNET_MQ_destroy (mq); | ||
629 | mq = NULL; | ||
630 | reconnect (); | ||
631 | return; | ||
632 | } | ||
633 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
634 | "Received IP from DNS service\n"); | ||
635 | if (GNUNET_SYSERR != rh->was_transmitted) | ||
636 | rh->addr_callback (rh->cls, | ||
637 | sa, | ||
638 | salen); | ||
639 | } | ||
640 | } | ||
641 | |||
642 | |||
643 | /** | ||
644 | * We've been asked to lookup the address for a hostname and were | ||
645 | * given a valid numeric string. Perform the callbacks for the | ||
646 | * numeric addresses. | ||
647 | * | ||
648 | * @param cls `struct GNUNET_RESOLVER_RequestHandle` for the request | ||
649 | */ | ||
650 | static void | ||
651 | numeric_resolution (void *cls) | ||
652 | { | ||
653 | struct GNUNET_RESOLVER_RequestHandle *rh = cls; | ||
654 | struct sockaddr_in v4; | ||
655 | struct sockaddr_in6 v6; | ||
656 | const char *hostname; | ||
657 | |||
658 | rh->task = NULL; | ||
659 | memset (&v4, 0, sizeof(v4)); | ||
660 | v4.sin_family = AF_INET; | ||
661 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
662 | v4.sin_len = sizeof(v4); | ||
663 | #endif | ||
664 | memset (&v6, 0, sizeof(v6)); | ||
665 | v6.sin6_family = AF_INET6; | ||
666 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
667 | v6.sin6_len = sizeof(v6); | ||
668 | #endif | ||
669 | hostname = (const char *) &rh[1]; | ||
670 | if (((rh->af == AF_UNSPEC) || | ||
671 | (rh->af == AF_INET)) && | ||
672 | (1 == inet_pton (AF_INET, | ||
673 | hostname, | ||
674 | &v4.sin_addr))) | ||
675 | { | ||
676 | rh->addr_callback (rh->cls, | ||
677 | (const struct sockaddr *) &v4, | ||
678 | sizeof(v4)); | ||
679 | if ((rh->af == AF_UNSPEC) && | ||
680 | (GNUNET_SYSERR != rh->was_transmitted) && | ||
681 | (1 == inet_pton (AF_INET6, | ||
682 | hostname, | ||
683 | &v6.sin6_addr))) | ||
684 | { | ||
685 | /* this can happen on some systems IF "hostname" is "localhost" */ | ||
686 | rh->addr_callback (rh->cls, | ||
687 | (const struct sockaddr *) &v6, | ||
688 | sizeof(v6)); | ||
689 | } | ||
690 | if (GNUNET_SYSERR != rh->was_transmitted) | ||
691 | rh->addr_callback (rh->cls, | ||
692 | NULL, | ||
693 | 0); | ||
694 | GNUNET_free (rh); | ||
695 | return; | ||
696 | } | ||
697 | if (((rh->af == AF_UNSPEC) || | ||
698 | (rh->af == AF_INET6)) && | ||
699 | (1 == inet_pton (AF_INET6, | ||
700 | hostname, | ||
701 | &v6.sin6_addr))) | ||
702 | { | ||
703 | rh->addr_callback (rh->cls, | ||
704 | (const struct sockaddr *) &v6, | ||
705 | sizeof(v6)); | ||
706 | if (GNUNET_SYSERR != rh->was_transmitted) | ||
707 | rh->addr_callback (rh->cls, | ||
708 | NULL, | ||
709 | 0); | ||
710 | GNUNET_free (rh); | ||
711 | return; | ||
712 | } | ||
713 | /* why are we here? this task should not have been scheduled! */ | ||
714 | GNUNET_assert (0); | ||
715 | GNUNET_free (rh); | ||
716 | } | ||
717 | |||
718 | |||
719 | /** | ||
720 | * We've been asked to lookup the address for a hostname and were | ||
721 | * given a variant of "loopback". Perform the callbacks for the | ||
722 | * respective loopback numeric addresses. | ||
723 | * | ||
724 | * @param cls `struct GNUNET_RESOLVER_RequestHandle` for the request | ||
725 | */ | ||
726 | static void | ||
727 | loopback_resolution (void *cls) | ||
728 | { | ||
729 | struct GNUNET_RESOLVER_RequestHandle *rh = cls; | ||
730 | struct sockaddr_in v4; | ||
731 | struct sockaddr_in6 v6; | ||
732 | |||
733 | rh->task = NULL; | ||
734 | memset (&v4, 0, sizeof(v4)); | ||
735 | v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | ||
736 | v4.sin_family = AF_INET; | ||
737 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
738 | v4.sin_len = sizeof(v4); | ||
739 | #endif | ||
740 | memset (&v6, 0, sizeof(v6)); | ||
741 | v6.sin6_family = AF_INET6; | ||
742 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
743 | v6.sin6_len = sizeof(v6); | ||
744 | #endif | ||
745 | v6.sin6_addr = in6addr_loopback; | ||
746 | switch (rh->af) | ||
747 | { | ||
748 | case AF_INET: | ||
749 | rh->addr_callback (rh->cls, | ||
750 | (const struct sockaddr *) &v4, | ||
751 | sizeof(v4)); | ||
752 | break; | ||
753 | |||
754 | case AF_INET6: | ||
755 | rh->addr_callback (rh->cls, | ||
756 | (const struct sockaddr *) &v6, | ||
757 | sizeof(v6)); | ||
758 | break; | ||
759 | |||
760 | case AF_UNSPEC: | ||
761 | rh->addr_callback (rh->cls, | ||
762 | (const struct sockaddr *) &v6, | ||
763 | sizeof(v6)); | ||
764 | rh->addr_callback (rh->cls, | ||
765 | (const struct sockaddr *) &v4, | ||
766 | sizeof(v4)); | ||
767 | |||
768 | break; | ||
769 | |||
770 | default: | ||
771 | GNUNET_break (0); | ||
772 | break; | ||
773 | } | ||
774 | if (GNUNET_SYSERR != rh->was_transmitted) | ||
775 | rh->addr_callback (rh->cls, | ||
776 | NULL, | ||
777 | 0); | ||
778 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
779 | "Finished resolving hostname `%s'.\n", | ||
780 | (const char *) &rh[1]); | ||
781 | GNUNET_free (rh); | ||
782 | } | ||
783 | |||
784 | |||
785 | /** | ||
786 | * Now try to reconnect to the resolver service. | ||
787 | * | ||
788 | * @param cls NULL | ||
789 | */ | ||
790 | static void | ||
791 | reconnect_task (void *cls) | ||
792 | { | ||
793 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
794 | GNUNET_MQ_hd_var_size (response, | ||
795 | GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE, | ||
796 | struct GNUNET_RESOLVER_ResponseMessage, | ||
797 | NULL), | ||
798 | GNUNET_MQ_handler_end () | ||
799 | }; | ||
800 | |||
801 | (void) cls; | ||
802 | r_task = NULL; | ||
803 | if (NULL == req_head) | ||
804 | return; /* no work pending */ | ||
805 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
806 | "Trying to connect to DNS service\n"); | ||
807 | mq = GNUNET_CLIENT_connect (resolver_cfg, | ||
808 | "resolver", | ||
809 | handlers, | ||
810 | &mq_error_handler, | ||
811 | NULL); | ||
812 | if (NULL == mq) | ||
813 | { | ||
814 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
815 | "Failed to connect, will try again later\n"); | ||
816 | reconnect (); | ||
817 | return; | ||
818 | } | ||
819 | process_requests (); | ||
820 | } | ||
821 | |||
822 | |||
823 | /** | ||
824 | * Adjust exponential back-off and reconnect to the service. | ||
825 | */ | ||
826 | static void | ||
827 | reconnect () | ||
828 | { | ||
829 | struct GNUNET_RESOLVER_RequestHandle *rh; | ||
830 | |||
831 | if (NULL != r_task) | ||
832 | return; | ||
833 | GNUNET_assert (NULL == mq); | ||
834 | if (NULL != (rh = req_head)) | ||
835 | { | ||
836 | switch (rh->was_transmitted) | ||
837 | { | ||
838 | case GNUNET_NO: | ||
839 | /* nothing more to do */ | ||
840 | break; | ||
841 | |||
842 | case GNUNET_YES: | ||
843 | /* disconnected, transmit again! */ | ||
844 | rh->was_transmitted = GNUNET_NO; | ||
845 | break; | ||
846 | |||
847 | case GNUNET_SYSERR: | ||
848 | /* request was cancelled, remove entirely */ | ||
849 | GNUNET_CONTAINER_DLL_remove (req_head, | ||
850 | req_tail, | ||
851 | rh); | ||
852 | GNUNET_free (rh); | ||
853 | check_disconnect (); | ||
854 | break; | ||
855 | |||
856 | default: | ||
857 | GNUNET_assert (0); | ||
858 | break; | ||
859 | } | ||
860 | } | ||
861 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
862 | "Will try to connect to DNS service in %s\n", | ||
863 | GNUNET_STRINGS_relative_time_to_string (backoff, | ||
864 | GNUNET_YES)); | ||
865 | GNUNET_assert (NULL != resolver_cfg); | ||
866 | r_task = GNUNET_SCHEDULER_add_delayed (backoff, | ||
867 | &reconnect_task, | ||
868 | NULL); | ||
869 | backoff = GNUNET_TIME_STD_BACKOFF (backoff); | ||
870 | } | ||
871 | |||
872 | |||
873 | /** | ||
874 | * A DNS resolution timed out. Notify the application. | ||
875 | * | ||
876 | * @param cls the `struct GNUNET_RESOLVER_RequestHandle *` | ||
877 | */ | ||
878 | static void | ||
879 | handle_lookup_timeout (void *cls) | ||
880 | { | ||
881 | struct GNUNET_RESOLVER_RequestHandle *rh = cls; | ||
882 | |||
883 | rh->task = NULL; | ||
884 | if (GNUNET_NO == rh->direction) | ||
885 | { | ||
886 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
887 | _ ("Timeout trying to resolve hostname `%s'.\n"), | ||
888 | (const char *) &rh[1]); | ||
889 | if (NULL != rh->addr_callback) | ||
890 | rh->addr_callback (rh->cls, | ||
891 | NULL, | ||
892 | 0); | ||
893 | } | ||
894 | else | ||
895 | { | ||
896 | #if ! defined(GNUNET_CULL_LOGGING) | ||
897 | char buf[INET6_ADDRSTRLEN]; | ||
898 | |||
899 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
900 | _ ("Timeout trying to resolve IP address `%s'.\n"), | ||
901 | inet_ntop (rh->af, | ||
902 | (const void *) &rh[1], | ||
903 | buf, | ||
904 | sizeof(buf))); | ||
905 | #endif | ||
906 | if (GNUNET_NO == rh->received_response) | ||
907 | { | ||
908 | char *nret; | ||
909 | |||
910 | nret = no_resolve (rh->af, | ||
911 | &rh[1], | ||
912 | rh->data_len); | ||
913 | if (NULL != rh->name_callback) | ||
914 | rh->name_callback (rh->cls, nret); | ||
915 | GNUNET_free (nret); | ||
916 | } | ||
917 | /* finally, make termination call */ | ||
918 | if (NULL != rh->name_callback) | ||
919 | rh->name_callback (rh->cls, | ||
920 | NULL); | ||
921 | } | ||
922 | rh->was_transmitted = GNUNET_NO; | ||
923 | GNUNET_RESOLVER_request_cancel (rh); | ||
924 | process_requests (); | ||
925 | } | ||
926 | |||
927 | |||
928 | /** | ||
929 | * Convert a string to one or more IP addresses. | ||
930 | * | ||
931 | * @param hostname the hostname to resolve | ||
932 | * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any" | ||
933 | * @param callback function to call with addresses | ||
934 | * @param callback_cls closure for @a callback | ||
935 | * @param timeout how long to try resolving | ||
936 | * @return handle that can be used to cancel the request, NULL on error | ||
937 | */ | ||
938 | struct GNUNET_RESOLVER_RequestHandle * | ||
939 | GNUNET_RESOLVER_ip_get (const char *hostname, | ||
940 | int af, | ||
941 | struct GNUNET_TIME_Relative timeout, | ||
942 | GNUNET_RESOLVER_AddressCallback callback, | ||
943 | void *callback_cls) | ||
944 | { | ||
945 | struct GNUNET_RESOLVER_RequestHandle *rh; | ||
946 | size_t slen; | ||
947 | struct in_addr v4; | ||
948 | struct in6_addr v6; | ||
949 | |||
950 | slen = strlen (hostname) + 1; | ||
951 | if (slen + sizeof(struct GNUNET_RESOLVER_GetMessage) >= | ||
952 | GNUNET_MAX_MESSAGE_SIZE) | ||
953 | { | ||
954 | GNUNET_break (0); | ||
955 | return NULL; | ||
956 | } | ||
957 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
958 | "Trying to resolve hostname `%s'.\n", | ||
959 | hostname); | ||
960 | rh = GNUNET_malloc (sizeof(struct GNUNET_RESOLVER_RequestHandle) + slen); | ||
961 | rh->af = af; | ||
962 | rh->id = ++last_request_id; | ||
963 | rh->addr_callback = callback; | ||
964 | rh->cls = callback_cls; | ||
965 | GNUNET_memcpy (&rh[1], | ||
966 | hostname, | ||
967 | slen); | ||
968 | rh->data_len = slen; | ||
969 | rh->timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
970 | rh->direction = GNUNET_NO; | ||
971 | /* first, check if this is a numeric address */ | ||
972 | if (((1 == inet_pton (AF_INET, | ||
973 | hostname, | ||
974 | &v4)) && | ||
975 | ((af == AF_INET) || | ||
976 | (af == AF_UNSPEC))) || | ||
977 | ((1 == inet_pton (AF_INET6, | ||
978 | hostname, | ||
979 | &v6)) && | ||
980 | ((af == AF_INET6) || | ||
981 | (af == AF_UNSPEC)))) | ||
982 | { | ||
983 | rh->task = GNUNET_SCHEDULER_add_now (&numeric_resolution, | ||
984 | rh); | ||
985 | return rh; | ||
986 | } | ||
987 | /* then, check if this is a loopback address */ | ||
988 | for (unsigned int i = 0; | ||
989 | NULL != loopback[i]; | ||
990 | i++) | ||
991 | if (0 == strcasecmp (loopback[i], | ||
992 | hostname)) | ||
993 | { | ||
994 | rh->task = GNUNET_SCHEDULER_add_now (&loopback_resolution, | ||
995 | rh); | ||
996 | return rh; | ||
997 | } | ||
998 | if (GNUNET_OK != check_config ()) | ||
999 | { | ||
1000 | GNUNET_free (rh); | ||
1001 | return NULL; | ||
1002 | } | ||
1003 | rh->task = GNUNET_SCHEDULER_add_delayed (timeout, | ||
1004 | &handle_lookup_timeout, | ||
1005 | rh); | ||
1006 | GNUNET_CONTAINER_DLL_insert_tail (req_head, | ||
1007 | req_tail, | ||
1008 | rh); | ||
1009 | rh->was_queued = GNUNET_YES; | ||
1010 | if (NULL != s_task) | ||
1011 | { | ||
1012 | GNUNET_SCHEDULER_cancel (s_task); | ||
1013 | s_task = NULL; | ||
1014 | } | ||
1015 | process_requests (); | ||
1016 | return rh; | ||
1017 | } | ||
1018 | |||
1019 | |||
1020 | /** | ||
1021 | * We've been asked to convert an address to a string without | ||
1022 | * a reverse lookup, either because the client asked for it | ||
1023 | * or because the DNS lookup hit a timeout. Do the numeric | ||
1024 | * conversion and invoke the callback. | ||
1025 | * | ||
1026 | * @param cls `struct GNUNET_RESOLVER_RequestHandle` for the request | ||
1027 | */ | ||
1028 | static void | ||
1029 | numeric_reverse (void *cls) | ||
1030 | { | ||
1031 | struct GNUNET_RESOLVER_RequestHandle *rh = cls; | ||
1032 | char *result; | ||
1033 | |||
1034 | rh->task = NULL; | ||
1035 | result = no_resolve (rh->af, | ||
1036 | &rh[1], | ||
1037 | rh->data_len); | ||
1038 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1039 | "Resolver returns `%s'.\n", | ||
1040 | result); | ||
1041 | if (NULL != result) | ||
1042 | { | ||
1043 | rh->name_callback (rh->cls, | ||
1044 | result); | ||
1045 | GNUNET_free (result); | ||
1046 | } | ||
1047 | rh->name_callback (rh->cls, | ||
1048 | NULL); | ||
1049 | if (NULL != rh->task) | ||
1050 | { | ||
1051 | GNUNET_SCHEDULER_cancel (rh->task); | ||
1052 | rh->task = NULL; | ||
1053 | } | ||
1054 | GNUNET_free (rh); | ||
1055 | } | ||
1056 | |||
1057 | |||
1058 | /** | ||
1059 | * Get an IP address as a string. | ||
1060 | * | ||
1061 | * @param sa host address | ||
1062 | * @param salen length of host address in @a sa | ||
1063 | * @param do_resolve use #GNUNET_NO to return numeric hostname | ||
1064 | * @param timeout how long to try resolving | ||
1065 | * @param callback function to call with hostnames | ||
1066 | * last callback is NULL when finished | ||
1067 | * @param cls closure for @a callback | ||
1068 | * @return handle that can be used to cancel the request | ||
1069 | */ | ||
1070 | struct GNUNET_RESOLVER_RequestHandle * | ||
1071 | GNUNET_RESOLVER_hostname_get (const struct sockaddr *sa, | ||
1072 | socklen_t salen, | ||
1073 | int do_resolve, | ||
1074 | struct GNUNET_TIME_Relative timeout, | ||
1075 | GNUNET_RESOLVER_HostnameCallback callback, | ||
1076 | void *cls) | ||
1077 | { | ||
1078 | struct GNUNET_RESOLVER_RequestHandle *rh; | ||
1079 | size_t ip_len; | ||
1080 | const void *ip; | ||
1081 | |||
1082 | if (GNUNET_OK != check_config ()) | ||
1083 | { | ||
1084 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1085 | _ ("Resolver not configured correctly.\n")); | ||
1086 | return NULL; | ||
1087 | } | ||
1088 | |||
1089 | switch (sa->sa_family) | ||
1090 | { | ||
1091 | case AF_INET: | ||
1092 | GNUNET_assert (salen == sizeof(struct sockaddr_in)); | ||
1093 | ip_len = sizeof(struct in_addr); | ||
1094 | ip = &((const struct sockaddr_in*) sa)->sin_addr; | ||
1095 | break; | ||
1096 | |||
1097 | case AF_INET6: | ||
1098 | GNUNET_assert (salen == sizeof(struct sockaddr_in6)); | ||
1099 | ip_len = sizeof(struct in6_addr); | ||
1100 | ip = &((const struct sockaddr_in6*) sa)->sin6_addr; | ||
1101 | break; | ||
1102 | |||
1103 | default: | ||
1104 | GNUNET_break (0); | ||
1105 | return NULL; | ||
1106 | } | ||
1107 | rh = GNUNET_malloc (sizeof(struct GNUNET_RESOLVER_RequestHandle) + salen); | ||
1108 | rh->name_callback = callback; | ||
1109 | rh->cls = cls; | ||
1110 | rh->af = sa->sa_family; | ||
1111 | rh->id = ++last_request_id; | ||
1112 | rh->timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
1113 | GNUNET_memcpy (&rh[1], | ||
1114 | ip, | ||
1115 | ip_len); | ||
1116 | rh->data_len = ip_len; | ||
1117 | rh->direction = GNUNET_YES; | ||
1118 | rh->received_response = GNUNET_NO; | ||
1119 | if (GNUNET_NO == do_resolve) | ||
1120 | { | ||
1121 | rh->task = GNUNET_SCHEDULER_add_now (&numeric_reverse, | ||
1122 | rh); | ||
1123 | return rh; | ||
1124 | } | ||
1125 | rh->task = GNUNET_SCHEDULER_add_delayed (timeout, | ||
1126 | &handle_lookup_timeout, | ||
1127 | rh); | ||
1128 | GNUNET_CONTAINER_DLL_insert_tail (req_head, | ||
1129 | req_tail, | ||
1130 | rh); | ||
1131 | rh->was_queued = GNUNET_YES; | ||
1132 | if (NULL != s_task) | ||
1133 | { | ||
1134 | GNUNET_SCHEDULER_cancel (s_task); | ||
1135 | s_task = NULL; | ||
1136 | } | ||
1137 | process_requests (); | ||
1138 | return rh; | ||
1139 | } | ||
1140 | |||
1141 | |||
1142 | /** | ||
1143 | * Get local fully qualified af name | ||
1144 | * | ||
1145 | * @return fqdn | ||
1146 | */ | ||
1147 | char * | ||
1148 | GNUNET_RESOLVER_local_fqdn_get () | ||
1149 | { | ||
1150 | char hostname[GNUNET_OS_get_hostname_max_length () + 1]; | ||
1151 | |||
1152 | if (0 != gethostname (hostname, | ||
1153 | sizeof(hostname) - 1)) | ||
1154 | { | ||
1155 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1156 | "gethostname"); | ||
1157 | return NULL; | ||
1158 | } | ||
1159 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1160 | "Resolving our FQDN `%s'\n", | ||
1161 | hostname); | ||
1162 | #if HAVE_GETADDRINFO | ||
1163 | { | ||
1164 | struct addrinfo *ai; | ||
1165 | int ret; | ||
1166 | char *rval; | ||
1167 | |||
1168 | if (0 != (ret = getaddrinfo (hostname, | ||
1169 | NULL, | ||
1170 | NULL, | ||
1171 | &ai))) | ||
1172 | { | ||
1173 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1174 | _ ("Could not resolve our FQDN: %s\n"), | ||
1175 | gai_strerror (ret)); | ||
1176 | return NULL; | ||
1177 | } | ||
1178 | if (NULL != ai->ai_canonname) | ||
1179 | rval = GNUNET_strdup (ai->ai_canonname); | ||
1180 | else | ||
1181 | rval = GNUNET_strdup (hostname); | ||
1182 | freeaddrinfo (ai); | ||
1183 | return rval; | ||
1184 | } | ||
1185 | #elif HAVE_GETHOSTBYNAME2 | ||
1186 | { | ||
1187 | struct hostent *host; | ||
1188 | |||
1189 | host = gethostbyname2 (hostname, | ||
1190 | AF_INET); | ||
1191 | if (NULL == host) | ||
1192 | host = gethostbyname2 (hostname, | ||
1193 | AF_INET6); | ||
1194 | if (NULL == host) | ||
1195 | { | ||
1196 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1197 | _ ("Could not resolve our FQDN: %s\n"), | ||
1198 | hstrerror (h_errno)); | ||
1199 | return NULL; | ||
1200 | } | ||
1201 | return GNUNET_strdup (host->h_name); | ||
1202 | } | ||
1203 | #elif HAVE_GETHOSTBYNAME | ||
1204 | { | ||
1205 | struct hostent *host; | ||
1206 | |||
1207 | host = gethostbyname (hostname); | ||
1208 | if (NULL == host) | ||
1209 | { | ||
1210 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1211 | _ ("Could not resolve our FQDN: %s\n"), | ||
1212 | hstrerror (h_errno)); | ||
1213 | return NULL; | ||
1214 | } | ||
1215 | return GNUNET_strdup (host->h_name); | ||
1216 | } | ||
1217 | #else | ||
1218 | /* fallback: just hope name is already FQDN */ | ||
1219 | return GNUNET_strdup (hostname); | ||
1220 | #endif | ||
1221 | } | ||
1222 | |||
1223 | |||
1224 | /** | ||
1225 | * Looking our own hostname. | ||
1226 | * | ||
1227 | * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any" | ||
1228 | * @param timeout how long to try resolving | ||
1229 | * @param callback function to call with addresses | ||
1230 | * @param cls closure for @a callback | ||
1231 | * @return handle that can be used to cancel the request, NULL on error | ||
1232 | */ | ||
1233 | struct GNUNET_RESOLVER_RequestHandle * | ||
1234 | GNUNET_RESOLVER_hostname_resolve (int af, | ||
1235 | struct GNUNET_TIME_Relative timeout, | ||
1236 | GNUNET_RESOLVER_AddressCallback callback, | ||
1237 | void *cls) | ||
1238 | { | ||
1239 | char hostname[GNUNET_OS_get_hostname_max_length () + 1]; | ||
1240 | |||
1241 | if (0 != gethostname (hostname, sizeof(hostname) - 1)) | ||
1242 | { | ||
1243 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1244 | "gethostname"); | ||
1245 | return NULL; | ||
1246 | } | ||
1247 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1248 | "Resolving our hostname `%s'\n", | ||
1249 | hostname); | ||
1250 | return GNUNET_RESOLVER_ip_get (hostname, | ||
1251 | af, | ||
1252 | timeout, | ||
1253 | callback, | ||
1254 | cls); | ||
1255 | } | ||
1256 | |||
1257 | |||
1258 | /** | ||
1259 | * Cancel a request that is still pending with the resolver. | ||
1260 | * Note that a client MUST NOT cancel a request that has | ||
1261 | * been completed (i.e, the callback has been called to | ||
1262 | * signal timeout or the final result). | ||
1263 | * | ||
1264 | * @param rh handle of request to cancel | ||
1265 | */ | ||
1266 | void | ||
1267 | GNUNET_RESOLVER_request_cancel (struct GNUNET_RESOLVER_RequestHandle *rh) | ||
1268 | { | ||
1269 | if (GNUNET_NO == rh->direction) | ||
1270 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1271 | "Asked to cancel request to resolve hostname `%s'.\n", | ||
1272 | (const char *) &rh[1]); | ||
1273 | if (NULL != rh->task) | ||
1274 | { | ||
1275 | GNUNET_SCHEDULER_cancel (rh->task); | ||
1276 | rh->task = NULL; | ||
1277 | } | ||
1278 | if (GNUNET_NO == rh->was_transmitted) | ||
1279 | { | ||
1280 | if (GNUNET_YES == rh->was_queued) | ||
1281 | GNUNET_CONTAINER_DLL_remove (req_head, | ||
1282 | req_tail, | ||
1283 | rh); | ||
1284 | GNUNET_free (rh); | ||
1285 | check_disconnect (); | ||
1286 | return; | ||
1287 | } | ||
1288 | GNUNET_assert (GNUNET_YES == rh->was_transmitted); | ||
1289 | rh->was_transmitted = GNUNET_SYSERR; /* mark as cancelled */ | ||
1290 | check_disconnect (); | ||
1291 | } | ||
1292 | |||
1293 | |||
1294 | /* end of resolver_api.c */ | ||