diff options
author | Christian Grothoff <christian@grothoff.org> | 2009-07-05 20:36:30 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2009-07-05 20:36:30 +0000 |
commit | 47bd24d3d6759ddade329e90300fbf03486d8ab7 (patch) | |
tree | adf9a5bb44541e6a4f81c17e09ae7a38b7b76660 /src/util/network.c | |
parent | 7ff499ccb77cb3943b49a85a5594f7cc152ca5d1 (diff) | |
download | gnunet-47bd24d3d6759ddade329e90300fbf03486d8ab7.tar.gz gnunet-47bd24d3d6759ddade329e90300fbf03486d8ab7.zip |
tolerate funky IPv4/Ipv6 localhost configs and getaddr returning only IPv6 addresses for af-unspec
Diffstat (limited to 'src/util/network.c')
-rw-r--r-- | src/util/network.c | 75 |
1 files changed, 59 insertions, 16 deletions
diff --git a/src/util/network.c b/src/util/network.c index 021f5afaf..aae9d6872 100644 --- a/src/util/network.c +++ b/src/util/network.c | |||
@@ -42,6 +42,13 @@ | |||
42 | 42 | ||
43 | #define DEBUG_NETWORK GNUNET_NO | 43 | #define DEBUG_NETWORK GNUNET_NO |
44 | 44 | ||
45 | /** | ||
46 | * List of address families to give as hints to | ||
47 | * getaddrinfo, in reverse order of preference. | ||
48 | */ | ||
49 | static int address_families[] = | ||
50 | { AF_INET, AF_INET6, AF_UNSPEC }; | ||
51 | |||
45 | struct GNUNET_NETWORK_TransmitHandle | 52 | struct GNUNET_NETWORK_TransmitHandle |
46 | { | 53 | { |
47 | 54 | ||
@@ -106,6 +113,12 @@ struct GNUNET_NETWORK_SocketHandle | |||
106 | struct sockaddr *addr; | 113 | struct sockaddr *addr; |
107 | 114 | ||
108 | /** | 115 | /** |
116 | * Pointer to the hostname if socket was | ||
117 | * created using DNS lookup, otherwise NULL. | ||
118 | */ | ||
119 | char *hostname; | ||
120 | |||
121 | /** | ||
109 | * Pointer to our write buffer. | 122 | * Pointer to our write buffer. |
110 | */ | 123 | */ |
111 | char *write_buffer; | 124 | char *write_buffer; |
@@ -133,6 +146,12 @@ struct GNUNET_NETWORK_SocketHandle | |||
133 | socklen_t addrlen; | 146 | socklen_t addrlen; |
134 | 147 | ||
135 | /** | 148 | /** |
149 | * Offset in our address family list | ||
150 | * that we used last. | ||
151 | */ | ||
152 | int af_fam_offset; | ||
153 | |||
154 | /** | ||
136 | * Connect task that we may need to wait for. | 155 | * Connect task that we may need to wait for. |
137 | */ | 156 | */ |
138 | GNUNET_SCHEDULER_TaskIdentifier connect_task; | 157 | GNUNET_SCHEDULER_TaskIdentifier connect_task; |
@@ -390,6 +409,37 @@ socket_set_blocking (int handle, int doBlock) | |||
390 | 409 | ||
391 | 410 | ||
392 | /** | 411 | /** |
412 | * Perform a DNS lookup for the hostname associated | ||
413 | * with the current socket, iterating over the address | ||
414 | * families as specified in the "address_families" array. | ||
415 | */ | ||
416 | static void | ||
417 | try_lookup (struct GNUNET_NETWORK_SocketHandle *sock) | ||
418 | { | ||
419 | struct addrinfo hints; | ||
420 | int ec; | ||
421 | |||
422 | while ( (sock->ai_pos == NULL) && | ||
423 | (sock->af_fam_offset > 0) ) | ||
424 | { | ||
425 | if (sock->ai != NULL) | ||
426 | freeaddrinfo (sock->ai); | ||
427 | memset (&hints, 0, sizeof (hints)); | ||
428 | hints.ai_family = address_families[--sock->af_fam_offset]; | ||
429 | hints.ai_socktype = SOCK_STREAM; | ||
430 | if (0 != (ec = getaddrinfo (sock->hostname, NULL, &hints, &sock->ai))) | ||
431 | { | ||
432 | GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK, | ||
433 | "`%s' failed for hostname `%s': %s\n", | ||
434 | "getaddrinfo", sock->hostname, gai_strerror (ec)); | ||
435 | sock->ai = NULL; | ||
436 | } | ||
437 | sock->ai_pos = sock->ai; | ||
438 | } | ||
439 | } | ||
440 | |||
441 | |||
442 | /** | ||
393 | * Initiate asynchronous TCP connect request. | 443 | * Initiate asynchronous TCP connect request. |
394 | * | 444 | * |
395 | * @param sock what socket to connect | 445 | * @param sock what socket to connect |
@@ -409,6 +459,8 @@ try_connect (struct GNUNET_NETWORK_SocketHandle *sock) | |||
409 | while (1) | 459 | while (1) |
410 | { | 460 | { |
411 | if (sock->ai_pos == NULL) | 461 | if (sock->ai_pos == NULL) |
462 | try_lookup (sock); | ||
463 | if (sock->ai_pos == NULL) | ||
412 | { | 464 | { |
413 | /* no more addresses to try, fatal! */ | 465 | /* no more addresses to try, fatal! */ |
414 | return GNUNET_SYSERR; | 466 | return GNUNET_SYSERR; |
@@ -559,8 +611,6 @@ GNUNET_NETWORK_socket_create_from_connect (struct GNUNET_SCHEDULER_Handle | |||
559 | uint16_t port, size_t maxbuf) | 611 | uint16_t port, size_t maxbuf) |
560 | { | 612 | { |
561 | struct GNUNET_NETWORK_SocketHandle *ret; | 613 | struct GNUNET_NETWORK_SocketHandle *ret; |
562 | struct addrinfo hints; | ||
563 | int ec; | ||
564 | 614 | ||
565 | ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_SocketHandle) + maxbuf); | 615 | ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_SocketHandle) + maxbuf); |
566 | ret->sock = -1; | 616 | ret->sock = -1; |
@@ -568,21 +618,13 @@ GNUNET_NETWORK_socket_create_from_connect (struct GNUNET_SCHEDULER_Handle | |||
568 | ret->write_buffer = (char *) &ret[1]; | 618 | ret->write_buffer = (char *) &ret[1]; |
569 | ret->write_buffer_size = maxbuf; | 619 | ret->write_buffer_size = maxbuf; |
570 | ret->port = port; | 620 | ret->port = port; |
571 | memset (&hints, 0, sizeof (hints)); | 621 | ret->af_fam_offset = sizeof (address_families) / sizeof(address_families[0]); |
572 | hints.ai_family = AF_UNSPEC; | 622 | ret->hostname = GNUNET_strdup (hostname); |
573 | hints.ai_socktype = SOCK_STREAM; | ||
574 | if (0 != (ec = getaddrinfo (hostname, NULL, &hints, &ret->ai))) | ||
575 | { | ||
576 | GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK, | ||
577 | "`%s' failed for hostname `%s': %s\n", | ||
578 | "getaddrinfo", hostname, gai_strerror (ec)); | ||
579 | GNUNET_free (ret); | ||
580 | return NULL; | ||
581 | } | ||
582 | ret->ai_pos = ret->ai; | ||
583 | if (GNUNET_SYSERR == try_connect (ret)) | 623 | if (GNUNET_SYSERR == try_connect (ret)) |
584 | { | 624 | { |
585 | freeaddrinfo (ret->ai); | 625 | if (NULL != ret->ai) |
626 | freeaddrinfo (ret->ai); | ||
627 | GNUNET_free (ret->hostname); | ||
586 | GNUNET_free (ret); | 628 | GNUNET_free (ret); |
587 | return NULL; | 629 | return NULL; |
588 | } | 630 | } |
@@ -724,7 +766,8 @@ destroy_continuation (void *cls, | |||
724 | GNUNET_break (0 == CLOSE (sock->sock)); | 766 | GNUNET_break (0 == CLOSE (sock->sock)); |
725 | GNUNET_free_non_null (sock->addr); | 767 | GNUNET_free_non_null (sock->addr); |
726 | if (sock->ai != NULL) | 768 | if (sock->ai != NULL) |
727 | freeaddrinfo (sock->ai); | 769 | freeaddrinfo (sock->ai); |
770 | GNUNET_free_non_null (sock->hostname); | ||
728 | GNUNET_free (sock); | 771 | GNUNET_free (sock); |
729 | } | 772 | } |
730 | 773 | ||