aboutsummaryrefslogtreecommitdiff
path: root/src/util/network.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2009-07-05 20:36:30 +0000
committerChristian Grothoff <christian@grothoff.org>2009-07-05 20:36:30 +0000
commit47bd24d3d6759ddade329e90300fbf03486d8ab7 (patch)
treeadf9a5bb44541e6a4f81c17e09ae7a38b7b76660 /src/util/network.c
parent7ff499ccb77cb3943b49a85a5594f7cc152ca5d1 (diff)
downloadgnunet-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.c75
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 */
49static int address_families[] =
50 { AF_INET, AF_INET6, AF_UNSPEC };
51
45struct GNUNET_NETWORK_TransmitHandle 52struct 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 */
416static void
417try_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