From 104e8393f316af541a8c0783ae36aa5bb5de9707 Mon Sep 17 00:00:00 2001 From: Duncaen Date: Sat, 15 Jun 2019 18:48:06 +0200 Subject: [PATCH] lib/fetch: fix happy eyeballs without any usable addresses and catch more errors --- lib/fetch/common.c | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/lib/fetch/common.c b/lib/fetch/common.c index 2f56e156..e61638b8 100644 --- a/lib/fetch/common.c +++ b/lib/fetch/common.c @@ -488,19 +488,28 @@ happy_eyeballs_connect(struct addrinfo *res0) for (;;) { int sd = -1; int ret; - unsigned short family; + unsigned short family = 0; #ifdef FULL_DEBUG - fetch_info("happy eyeballs state: i4=%u n4=%u i6=%u n6=%u", i4, n4, i6, n6); + fetch_info("happy eyeballs state: i4=%u n4=%u i6=%u n6=%u" + " attempts=%u waiting=%u", i4, n4, i6, n6, attempts, waiting); #endif - if (res == NULL) { - /* prefer ipv6 */ - family = i6+1 < n6 ? AF_INET6 : AF_INET; - } else if (i4+1 < n4) { - family = res->ai_family == AF_INET && i6+1 < n6 ? AF_INET6 : AF_INET; - } else if (i6+1 < n6) { - family = res->ai_family == AF_INET6 && i4+1 < n4 ? AF_INET : AF_INET6; + if (i6+i4 < n6+n4) { + /* first round when res == NULL, prefer ipv6 */ + if (res == NULL || res->ai_family == AF_INET) { + /* prefer ipv6 */ + if (i6 < n6) + family = AF_INET6; + else if (i4 < n4) + family = AF_INET; + } else { + /* prefer ipv4 */ + if (i4 < n4) + family = AF_INET; + else if (i6 < n6) + family = AF_INET6; + } } else { /* no more connections to try */ #ifdef FULL_DEBUG @@ -511,6 +520,7 @@ happy_eyeballs_connect(struct addrinfo *res0) goto wait; } + for (i = 0, res = res0; res; res = res->ai_next) { if (res->ai_family == family) { if (family == AF_INET && i == i4) { @@ -524,6 +534,8 @@ happy_eyeballs_connect(struct addrinfo *res0) i++; } } + if (res == NULL) + goto error; if ((sd = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK, res->ai_protocol)) == -1) @@ -570,6 +582,11 @@ happy_eyeballs_connect(struct addrinfo *res0) attempts++; waiting++; wait: + if (!attempts) { +error: + netdb_seterr(EAI_FAIL); + return -1; + } for (i = 0; i < attempts; i++) { pfd[i].revents = pfd[i].events = 0; if (pfd[i].fd != -1) @@ -621,8 +638,8 @@ wait: rv = -1; } } - - errno = err; + if ((errno = err)) + fetch_syserr(); return rv; } @@ -675,10 +692,8 @@ fetch_connect(struct url *url, int af, int verbose) sd = happy_eyeballs_connect(res0); freeaddrinfo(res0); - if (sd == -1) { - fetch_syserr(); + if (sd == -1) return (NULL); - } if ((conn = fetch_reopen(sd)) == NULL) { fetch_syserr();