summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCristian Rodríguez <crodriguez@owncloud.com>2020-12-09 16:30:29 -0300
committerDaniel Stenberg <daniel@haxx.se>2020-12-10 08:55:42 +0100
commit25b4e158e94311f8b4a712df722888b9e80dd0e8 (patch)
tree81ab8a3da366b8879867468e02c32906d55e0e6c
parent8a10abaf85c976dfce03332de5d8aaf4781d4870 (diff)
downloadcurl-25b4e158e94311f8b4a712df722888b9e80dd0e8.tar.gz
connect: defer port selection until connect() time
If supported, defer port selection until connect() time if --interface is given and source port is 0. Reproducer: * start fast webserver on port 80 * starve system of ephemeral ports $ sysctl net.ipv4.ip_local_port_range="60990 60999" * start a curl/libcurl "crawler" $curl --keepalive --parallel --parallel-immediate --head --interface 127.0.0.2 "http://127.0.0.[1-254]/file[001-002].txt" current result: (possible some successful data) curl: (45) bind failed with errno 98: Address already in use result after patch: (complete success or few connections failing, higlhy depending on load) Fail only when all the possible 4-tuple combinations are exhausted, which is impossible to do when port is selected at bind() time becuse the kernel does not know if socket will be listen()'ed on or connect'ed yet. Closes #6295
-rw-r--r--lib/connect.c7
1 files changed, 6 insertions, 1 deletions
diff --git a/lib/connect.c b/lib/connect.c
index 6e4608d98..251145ce1 100644
--- a/lib/connect.c
+++ b/lib/connect.c
@@ -256,6 +256,9 @@ static CURLcode bindlocal(struct connectdata *conn,
int portnum = data->set.localportrange;
const char *dev = data->set.str[STRING_DEVICE];
int error;
+#ifdef IP_BIND_ADDRESS_NO_PORT
+ int on = 1;
+#endif
/*************************************************************
* Select device to bind socket to
@@ -441,7 +444,9 @@ static CURLcode bindlocal(struct connectdata *conn,
sizeof_sa = sizeof(struct sockaddr_in);
}
}
-
+#ifdef IP_BIND_ADDRESS_NO_PORT
+ setsockopt(sockfd, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &on, sizeof(on));
+#endif
for(;;) {
if(bind(sockfd, sock, sizeof_sa) >= 0) {
/* we succeeded to bind */