From bb50dee510a34db03bb963b88b51550166b34c37 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Mon, 23 Jun 2025 14:51:37 +0200 Subject: [PATCH] tests/server: de-dupe/merge three `sockdaemon()` clones into one Also: tidy up `if()` expressions here and there. Follow-up to f4f25505df1d2ede727071eb0c518368a206f64b #15000 Closes #17719 --- tests/server/dnsd.c | 2 +- tests/server/first.h | 4 + tests/server/mqttd.c | 158 +----------------------------- tests/server/rtspd.c | 4 +- tests/server/sockfilt.c | 209 ++++++---------------------------------- tests/server/socksd.c | 162 +------------------------------ tests/server/sws.c | 4 +- tests/server/tftpd.c | 2 +- tests/server/util.c | 171 +++++++++++++++++++++++++++++++- 9 files changed, 214 insertions(+), 502 deletions(-) diff --git a/tests/server/dnsd.c b/tests/server/dnsd.c index 3050303760..e64fa64222 100644 --- a/tests/server/dnsd.c +++ b/tests/server/dnsd.c @@ -504,7 +504,7 @@ static int test_dnsd(int argc, char **argv) rc = bind(sock, &me.sa, sizeof(me.sa6)); } #endif /* USE_IPV6 */ - if(0 != rc) { + if(rc) { error = SOCKERRNO; logmsg("Error binding socket on port %hu (%d) %s", port, error, sstrerror(error)); diff --git a/tests/server/first.h b/tests/server/first.h index 4fb32c44bd..b7b795c835 100644 --- a/tests/server/first.h +++ b/tests/server/first.h @@ -135,6 +135,10 @@ extern int bind_unix_socket(curl_socket_t sock, const char *unix_socket, struct sockaddr_un *sau); #endif extern unsigned short util_ultous(unsigned long ulnum); +extern curl_socket_t sockdaemon(curl_socket_t sock, + unsigned short *listenport, + const char *unix_socket, + bool bind_only); /* global variables */ static const char *srcpath = "."; /* pointing to the test dir */ diff --git a/tests/server/mqttd.c b/tests/server/mqttd.c index fb89ccb77e..d42b277d93 100644 --- a/tests/server/mqttd.c +++ b/tests/server/mqttd.c @@ -715,149 +715,6 @@ static bool mqttd_incoming(curl_socket_t listenfd) return TRUE; } -static curl_socket_t mqttd_sockdaemon(curl_socket_t sock, - unsigned short *listenport, - bool bind_only) -{ - /* passive daemon style */ - srvr_sockaddr_union_t listener; - int flag; - int rc; - int totdelay = 0; - int maxretr = 10; - int delay = 20; - int attempt = 0; - int error = 0; - - do { - attempt++; - flag = 1; - rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, - (void *)&flag, sizeof(flag)); - if(rc) { - error = SOCKERRNO; - logmsg("setsockopt(SO_REUSEADDR) failed with error (%d) %s", - error, sstrerror(error)); - if(maxretr) { - rc = curlx_wait_ms(delay); - if(rc) { - /* should not happen */ - error = SOCKERRNO; - logmsg("curlx_wait_ms() failed with error (%d) %s", - error, sstrerror(error)); - sclose(sock); - return CURL_SOCKET_BAD; - } - if(got_exit_signal) { - logmsg("signalled to die, exiting..."); - sclose(sock); - return CURL_SOCKET_BAD; - } - totdelay += delay; - delay *= 2; /* double the sleep for next attempt */ - } - } - } while(rc && maxretr--); - - if(rc) { - logmsg("setsockopt(SO_REUSEADDR) failed %d times in %d ms. Error (%d) %s", - attempt, totdelay, error, strerror(error)); - logmsg("Continuing anyway..."); - } - - /* When the specified listener port is zero, it is actually a - request to let the system choose a non-zero available port. */ - -#ifdef USE_IPV6 - if(!use_ipv6) { -#endif - memset(&listener.sa4, 0, sizeof(listener.sa4)); - listener.sa4.sin_family = AF_INET; - listener.sa4.sin_addr.s_addr = INADDR_ANY; - listener.sa4.sin_port = htons(*listenport); - rc = bind(sock, &listener.sa, sizeof(listener.sa4)); -#ifdef USE_IPV6 - } - else { - memset(&listener.sa6, 0, sizeof(listener.sa6)); - listener.sa6.sin6_family = AF_INET6; - listener.sa6.sin6_addr = in6addr_any; - listener.sa6.sin6_port = htons(*listenport); - rc = bind(sock, &listener.sa, sizeof(listener.sa6)); - } -#endif /* USE_IPV6 */ - if(rc) { - error = SOCKERRNO; - logmsg("Error binding socket on port %hu (%d) %s", - *listenport, error, sstrerror(error)); - sclose(sock); - return CURL_SOCKET_BAD; - } - - if(!*listenport) { - /* The system was supposed to choose a port number, figure out which - port we actually got and update the listener port value with it. */ - curl_socklen_t la_size; - srvr_sockaddr_union_t localaddr; -#ifdef USE_IPV6 - if(!use_ipv6) -#endif - la_size = sizeof(localaddr.sa4); -#ifdef USE_IPV6 - else - la_size = sizeof(localaddr.sa6); -#endif - memset(&localaddr.sa, 0, (size_t)la_size); - if(getsockname(sock, &localaddr.sa, &la_size) < 0) { - error = SOCKERRNO; - logmsg("getsockname() failed with error (%d) %s", - error, sstrerror(error)); - sclose(sock); - return CURL_SOCKET_BAD; - } - switch(localaddr.sa.sa_family) { - case AF_INET: - *listenport = ntohs(localaddr.sa4.sin_port); - break; -#ifdef USE_IPV6 - case AF_INET6: - *listenport = ntohs(localaddr.sa6.sin6_port); - break; -#endif - default: - break; - } - if(!*listenport) { - /* Real failure, listener port shall not be zero beyond this point. */ - logmsg("Apparently getsockname() succeeded, with listener port zero."); - logmsg("A valid reason for this failure is a binary built without"); - logmsg("proper network library linkage. This might not be the only"); - logmsg("reason, but double check it before anything else."); - sclose(sock); - return CURL_SOCKET_BAD; - } - } - - /* bindonly option forces no listening */ - if(bind_only) { - logmsg("instructed to bind port without listening"); - return sock; - } - - /* start accepting connections */ - rc = listen(sock, 5); - if(0 != rc) { - error = SOCKERRNO; - logmsg("listen(%ld, 5) failed with error (%d) %s", - (long)sock, error, sstrerror(error)); - sclose(sock); - return CURL_SOCKET_BAD; - } - - return sock; -} - - static int test_mqttd(int argc, char *argv[]) { curl_socket_t sock = CURL_SOCKET_BAD; @@ -912,16 +769,16 @@ static int test_mqttd(int argc, char *argv[]) } else if(!strcmp("--ipv6", argv[arg])) { #ifdef USE_IPV6 + socket_domain = AF_INET6; ipv_inuse = "IPv6"; - use_ipv6 = TRUE; #endif arg++; } else if(!strcmp("--ipv4", argv[arg])) { /* for completeness, we support this option as well */ #ifdef USE_IPV6 + socket_domain = AF_INET; ipv_inuse = "IPv4"; - use_ipv6 = FALSE; #endif arg++; } @@ -969,14 +826,7 @@ static int test_mqttd(int argc, char *argv[]) install_signal_handlers(FALSE); -#ifdef USE_IPV6 - if(!use_ipv6) -#endif - sock = socket(AF_INET, SOCK_STREAM, 0); -#ifdef USE_IPV6 - else - sock = socket(AF_INET6, SOCK_STREAM, 0); -#endif + sock = socket(socket_domain, SOCK_STREAM, 0); if(CURL_SOCKET_BAD == sock) { error = SOCKERRNO; @@ -986,7 +836,7 @@ static int test_mqttd(int argc, char *argv[]) { /* passive daemon style */ - sock = mqttd_sockdaemon(sock, &server_port, FALSE); + sock = sockdaemon(sock, &server_port, NULL, FALSE); if(CURL_SOCKET_BAD == sock) { goto mqttd_cleanup; } diff --git a/tests/server/rtspd.c b/tests/server/rtspd.c index 1825361718..d4baa3ff1a 100644 --- a/tests/server/rtspd.c +++ b/tests/server/rtspd.c @@ -1127,7 +1127,7 @@ static int test_rtspd(int argc, char *argv[]) rc = bind(sock, &me.sa, sizeof(me.sa6)); } #endif /* USE_IPV6 */ - if(0 != rc) { + if(rc) { error = SOCKERRNO; logmsg("Error binding socket on port %hu (%d) %s", port, error, sstrerror(error)); @@ -1181,7 +1181,7 @@ static int test_rtspd(int argc, char *argv[]) /* start accepting connections */ rc = listen(sock, 5); - if(0 != rc) { + if(rc) { error = SOCKERRNO; logmsg("listen() failed with error (%d) %s", error, sstrerror(error)); diff --git a/tests/server/sockfilt.c b/tests/server/sockfilt.c index 477e433f8e..c17bca34bf 100644 --- a/tests/server/sockfilt.c +++ b/tests/server/sockfilt.c @@ -554,6 +554,7 @@ static unsigned int WINAPI select_ws_wait_thread(void *lpParameter) return 0; } + static HANDLE select_ws_wait(HANDLE handle, HANDLE signal, HANDLE abort) { typedef uintptr_t curl_win_thread_handle_t; @@ -578,6 +579,7 @@ static HANDLE select_ws_wait(HANDLE handle, HANDLE signal, HANDLE abort) } return NULL; } + struct select_ws_data { int fd; /* provided file descriptor (indexed by nfd) */ long wsastate; /* internal pre-select state (indexed by nfd) */ @@ -586,6 +588,7 @@ struct select_ws_data { HANDLE signal; /* internal thread signal (indexed by nth) */ HANDLE thread; /* internal thread handle (indexed by nth) */ }; + static int select_ws(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *tv) { @@ -1206,149 +1209,6 @@ static bool juggle(curl_socket_t *sockfdp, #endif } -static curl_socket_t sockfilt_sockdaemon(curl_socket_t sock, - unsigned short *listenport, - bool bind_only) -{ - /* passive daemon style */ - srvr_sockaddr_union_t listener; - int flag; - int rc; - int totdelay = 0; - int maxretr = 10; - int delay = 20; - int attempt = 0; - int error = 0; - - do { - attempt++; - flag = 1; - rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, - (void *)&flag, sizeof(flag)); - if(rc) { - error = SOCKERRNO; - logmsg("setsockopt(SO_REUSEADDR) failed with error (%d) %s", - error, sstrerror(error)); - if(maxretr) { - rc = curlx_wait_ms(delay); - if(rc) { - /* should not happen */ - error = SOCKERRNO; - logmsg("curlx_wait_ms() failed with error (%d) %s", - error, sstrerror(error)); - sclose(sock); - return CURL_SOCKET_BAD; - } - if(got_exit_signal) { - logmsg("signalled to die, exiting..."); - sclose(sock); - return CURL_SOCKET_BAD; - } - totdelay += delay; - delay *= 2; /* double the sleep for next attempt */ - } - } - } while(rc && maxretr--); - - if(rc) { - logmsg("setsockopt(SO_REUSEADDR) failed %d times in %d ms. Error (%d) %s", - attempt, totdelay, error, strerror(error)); - logmsg("Continuing anyway..."); - } - - /* When the specified listener port is zero, it is actually a - request to let the system choose a non-zero available port. */ - -#ifdef USE_IPV6 - if(!use_ipv6) { -#endif - memset(&listener.sa4, 0, sizeof(listener.sa4)); - listener.sa4.sin_family = AF_INET; - listener.sa4.sin_addr.s_addr = INADDR_ANY; - listener.sa4.sin_port = htons(*listenport); - rc = bind(sock, &listener.sa, sizeof(listener.sa4)); -#ifdef USE_IPV6 - } - else { - memset(&listener.sa6, 0, sizeof(listener.sa6)); - listener.sa6.sin6_family = AF_INET6; - listener.sa6.sin6_addr = in6addr_any; - listener.sa6.sin6_port = htons(*listenport); - rc = bind(sock, &listener.sa, sizeof(listener.sa6)); - } -#endif /* USE_IPV6 */ - if(rc) { - error = SOCKERRNO; - logmsg("Error binding socket on port %hu (%d) %s", - *listenport, error, sstrerror(error)); - sclose(sock); - return CURL_SOCKET_BAD; - } - - if(!*listenport) { - /* The system was supposed to choose a port number, figure out which - port we actually got and update the listener port value with it. */ - curl_socklen_t la_size; - srvr_sockaddr_union_t localaddr; -#ifdef USE_IPV6 - if(!use_ipv6) -#endif - la_size = sizeof(localaddr.sa4); -#ifdef USE_IPV6 - else - la_size = sizeof(localaddr.sa6); -#endif - memset(&localaddr.sa, 0, (size_t)la_size); - if(getsockname(sock, &localaddr.sa, &la_size) < 0) { - error = SOCKERRNO; - logmsg("getsockname() failed with error (%d) %s", - error, sstrerror(error)); - sclose(sock); - return CURL_SOCKET_BAD; - } - switch(localaddr.sa.sa_family) { - case AF_INET: - *listenport = ntohs(localaddr.sa4.sin_port); - break; -#ifdef USE_IPV6 - case AF_INET6: - *listenport = ntohs(localaddr.sa6.sin6_port); - break; -#endif - default: - break; - } - if(!*listenport) { - /* Real failure, listener port shall not be zero beyond this point. */ - logmsg("Apparently getsockname() succeeded, with listener port zero."); - logmsg("A valid reason for this failure is a binary built without"); - logmsg("proper network library linkage. This might not be the only"); - logmsg("reason, but double check it before anything else."); - sclose(sock); - return CURL_SOCKET_BAD; - } - } - - /* bindonly option forces no listening */ - if(bind_only) { - logmsg("instructed to bind port without listening"); - return sock; - } - - /* start accepting connections */ - rc = listen(sock, 5); - if(0 != rc) { - error = SOCKERRNO; - logmsg("listen() failed with error (%d) %s", - error, sstrerror(error)); - sclose(sock); - return CURL_SOCKET_BAD; - } - - return sock; -} - - static int test_sockfilt(int argc, char *argv[]) { srvr_sockaddr_union_t me; @@ -1399,16 +1259,16 @@ static int test_sockfilt(int argc, char *argv[]) } else if(!strcmp("--ipv6", argv[arg])) { #ifdef USE_IPV6 + socket_domain = AF_INET6; ipv_inuse = "IPv6"; - use_ipv6 = TRUE; #endif arg++; } else if(!strcmp("--ipv4", argv[arg])) { /* for completeness, we support this option as well */ #ifdef USE_IPV6 + socket_domain = AF_INET; ipv_inuse = "IPv4"; - use_ipv6 = FALSE; #endif arg++; } @@ -1478,14 +1338,7 @@ static int test_sockfilt(int argc, char *argv[]) install_signal_handlers(false); -#ifdef USE_IPV6 - if(!use_ipv6) -#endif - sock = socket(AF_INET, SOCK_STREAM, 0); -#ifdef USE_IPV6 - else - sock = socket(AF_INET6, SOCK_STREAM, 0); -#endif + sock = socket(socket_domain, SOCK_STREAM, 0); if(CURL_SOCKET_BAD == sock) { error = SOCKERRNO; @@ -1497,31 +1350,33 @@ static int test_sockfilt(int argc, char *argv[]) if(server_connectport) { /* Active mode, we should connect to the given port number */ mode = ACTIVE; + switch(socket_domain) { + case AF_INET: + memset(&me.sa4, 0, sizeof(me.sa4)); + me.sa4.sin_family = AF_INET; + me.sa4.sin_port = htons(server_connectport); + me.sa4.sin_addr.s_addr = INADDR_ANY; + if(!addr) + addr = "127.0.0.1"; + curlx_inet_pton(AF_INET, addr, &me.sa4.sin_addr); + + rc = connect(sock, &me.sa, sizeof(me.sa4)); + break; #ifdef USE_IPV6 - if(!use_ipv6) { -#endif - memset(&me.sa4, 0, sizeof(me.sa4)); - me.sa4.sin_family = AF_INET; - me.sa4.sin_port = htons(server_connectport); - me.sa4.sin_addr.s_addr = INADDR_ANY; - if(!addr) - addr = "127.0.0.1"; - curlx_inet_pton(AF_INET, addr, &me.sa4.sin_addr); - - rc = connect(sock, &me.sa, sizeof(me.sa4)); -#ifdef USE_IPV6 - } - else { - memset(&me.sa6, 0, sizeof(me.sa6)); - me.sa6.sin6_family = AF_INET6; - me.sa6.sin6_port = htons(server_connectport); - if(!addr) - addr = "::1"; - curlx_inet_pton(AF_INET6, addr, &me.sa6.sin6_addr); - - rc = connect(sock, &me.sa, sizeof(me.sa6)); - } + case AF_INET6: + memset(&me.sa6, 0, sizeof(me.sa6)); + me.sa6.sin6_family = AF_INET6; + me.sa6.sin6_port = htons(server_connectport); + if(!addr) + addr = "::1"; + curlx_inet_pton(AF_INET6, addr, &me.sa6.sin6_addr); + + rc = connect(sock, &me.sa, sizeof(me.sa6)); + break; #endif /* USE_IPV6 */ + default: + rc = 1; + } if(rc) { error = SOCKERRNO; logmsg("Error connecting to port %hu (%d) %s", @@ -1534,7 +1389,7 @@ static int test_sockfilt(int argc, char *argv[]) } else { /* passive daemon style */ - sock = sockfilt_sockdaemon(sock, &server_port, s_bind_only); + sock = sockdaemon(sock, &server_port, NULL, s_bind_only); if(CURL_SOCKET_BAD == sock) { write_stdout("FAIL\n", 5); goto sockfilt_cleanup; diff --git a/tests/server/socksd.c b/tests/server/socksd.c index 64c55a64e7..70e27af2ff 100644 --- a/tests/server/socksd.c +++ b/tests/server/socksd.c @@ -730,166 +730,6 @@ static bool socksd_incoming(curl_socket_t listenfd) return TRUE; } -static curl_socket_t socksd_sockdaemon(curl_socket_t sock, - unsigned short *listenport, - const char *unix_socket, - bool bind_only) -{ - /* passive daemon style */ - srvr_sockaddr_union_t listener; - int flag; - int rc; - int totdelay = 0; - int maxretr = 10; - int delay = 20; - int attempt = 0; - int error = 0; - -#ifndef USE_UNIX_SOCKETS - (void)unix_socket; -#endif - - do { - attempt++; - flag = 1; - rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, - (void *)&flag, sizeof(flag)); - if(rc) { - error = SOCKERRNO; - logmsg("setsockopt(SO_REUSEADDR) failed with error (%d) %s", - error, sstrerror(error)); - if(maxretr) { - rc = curlx_wait_ms(delay); - if(rc) { - /* should not happen */ - error = SOCKERRNO; - logmsg("curlx_wait_ms() failed with error (%d) %s", - error, sstrerror(error)); - sclose(sock); - return CURL_SOCKET_BAD; - } - if(got_exit_signal) { - logmsg("signalled to die, exiting..."); - sclose(sock); - return CURL_SOCKET_BAD; - } - totdelay += delay; - delay *= 2; /* double the sleep for next attempt */ - } - } - } while(rc && maxretr--); - - if(rc) { - logmsg("setsockopt(SO_REUSEADDR) failed %d times in %d ms. Error (%d) %s", - attempt, totdelay, error, strerror(error)); - logmsg("Continuing anyway..."); - } - - /* When the specified listener port is zero, it is actually a - request to let the system choose a non-zero available port. */ - - switch(socket_domain) { - case AF_INET: - memset(&listener.sa4, 0, sizeof(listener.sa4)); - listener.sa4.sin_family = AF_INET; - listener.sa4.sin_addr.s_addr = INADDR_ANY; - listener.sa4.sin_port = htons(*listenport); - rc = bind(sock, &listener.sa, sizeof(listener.sa4)); - break; -#ifdef USE_IPV6 - case AF_INET6: - memset(&listener.sa6, 0, sizeof(listener.sa6)); - listener.sa6.sin6_family = AF_INET6; - listener.sa6.sin6_addr = in6addr_any; - listener.sa6.sin6_port = htons(*listenport); - rc = bind(sock, &listener.sa, sizeof(listener.sa6)); - break; -#endif /* USE_IPV6 */ -#ifdef USE_UNIX_SOCKETS - case AF_UNIX: - rc = bind_unix_socket(sock, unix_socket, &listener.sau); -#endif - } - - if(rc) { - error = SOCKERRNO; -#ifdef USE_UNIX_SOCKETS - if(socket_domain == AF_UNIX) - logmsg("Error binding socket on path %s (%d) %s", - unix_socket, error, sstrerror(error)); - else -#endif - logmsg("Error binding socket on port %hu (%d) %s", - *listenport, error, sstrerror(error)); - sclose(sock); - return CURL_SOCKET_BAD; - } - - if(!*listenport -#ifdef USE_UNIX_SOCKETS - && !unix_socket -#endif - ) { - /* The system was supposed to choose a port number, figure out which - port we actually got and update the listener port value with it. */ - curl_socklen_t la_size; - srvr_sockaddr_union_t localaddr; -#ifdef USE_IPV6 - if(socket_domain == AF_INET6) - la_size = sizeof(localaddr.sa6); - else -#endif - la_size = sizeof(localaddr.sa4); - memset(&localaddr.sa, 0, (size_t)la_size); - if(getsockname(sock, &localaddr.sa, &la_size) < 0) { - error = SOCKERRNO; - logmsg("getsockname() failed with error (%d) %s", - error, sstrerror(error)); - sclose(sock); - return CURL_SOCKET_BAD; - } - switch(localaddr.sa.sa_family) { - case AF_INET: - *listenport = ntohs(localaddr.sa4.sin_port); - break; -#ifdef USE_IPV6 - case AF_INET6: - *listenport = ntohs(localaddr.sa6.sin6_port); - break; -#endif - default: - break; - } - if(!*listenport) { - /* Real failure, listener port shall not be zero beyond this point. */ - logmsg("Apparently getsockname() succeeded, with listener port zero."); - logmsg("A valid reason for this failure is a binary built without"); - logmsg("proper network library linkage. This might not be the only"); - logmsg("reason, but double check it before anything else."); - sclose(sock); - return CURL_SOCKET_BAD; - } - } - - /* bindonly option forces no listening */ - if(bind_only) { - logmsg("instructed to bind port without listening"); - return sock; - } - - /* start accepting connections */ - rc = listen(sock, 5); - if(0 != rc) { - error = SOCKERRNO; - logmsg("listen() failed with error (%d) %s", error, sstrerror(error)); - sclose(sock); - return CURL_SOCKET_BAD; - } - - return sock; -} - - static int test_socksd(int argc, char *argv[]) { curl_socket_t sock = CURL_SOCKET_BAD; @@ -1038,7 +878,7 @@ static int test_socksd(int argc, char *argv[]) { /* passive daemon style */ - sock = socksd_sockdaemon(sock, &server_port, unix_socket, FALSE); + sock = sockdaemon(sock, &server_port, unix_socket, FALSE); if(CURL_SOCKET_BAD == sock) { goto socks5_cleanup; } diff --git a/tests/server/sws.c b/tests/server/sws.c index 30bc2f0f61..7b90e510b4 100644 --- a/tests/server/sws.c +++ b/tests/server/sws.c @@ -2200,7 +2200,7 @@ static int test_sws(int argc, char *argv[]) rc = bind_unix_socket(sock, unix_socket, &me.sau); #endif /* USE_UNIX_SOCKETS */ } - if(0 != rc) { + if(rc) { error = SOCKERRNO; #ifdef USE_UNIX_SOCKETS if(socket_domain == AF_UNIX) @@ -2266,7 +2266,7 @@ static int test_sws(int argc, char *argv[]) /* start accepting connections */ rc = listen(sock, 50); - if(0 != rc) { + if(rc) { error = SOCKERRNO; logmsg("listen() failed with error (%d) %s", error, sstrerror(error)); goto sws_cleanup; diff --git a/tests/server/tftpd.c b/tests/server/tftpd.c index 1505d4de17..fc08c729ed 100644 --- a/tests/server/tftpd.c +++ b/tests/server/tftpd.c @@ -689,7 +689,7 @@ static int test_tftpd(int argc, char **argv) rc = bind(sock, &me.sa, sizeof(me.sa6)); } #endif /* USE_IPV6 */ - if(0 != rc) { + if(rc) { error = SOCKERRNO; logmsg("Error binding socket on port %hu (%d) %s", port, error, sstrerror(error)); diff --git a/tests/server/util.c b/tests/server/util.c index 8297c20270..b4d0e92c0d 100644 --- a/tests/server/util.c +++ b/tests/server/util.c @@ -707,7 +707,7 @@ int bind_unix_socket(curl_socket_t sock, const char *unix_socket, } strcpy(sau->sun_path, unix_socket); rc = bind(sock, (struct sockaddr*)sau, sizeof(struct sockaddr_un)); - if(0 != rc && SOCKERRNO == SOCKEADDRINUSE) { + if(rc && SOCKERRNO == SOCKEADDRINUSE) { struct_stat statbuf; /* socket already exists. Perhaps it is stale? */ curl_socket_t unixfd = socket(AF_UNIX, SOCK_STREAM, 0); @@ -720,7 +720,7 @@ int bind_unix_socket(curl_socket_t sock, const char *unix_socket, rc = connect(unixfd, (struct sockaddr*)sau, sizeof(struct sockaddr_un)); error = SOCKERRNO; sclose(unixfd); - if(0 != rc && SOCKECONNREFUSED != error) { + if(rc && error != SOCKECONNREFUSED) { logmsg("Failed to connect to %s (%d) %s", unix_socket, error, sstrerror(error)); return rc; @@ -732,7 +732,7 @@ int bind_unix_socket(curl_socket_t sock, const char *unix_socket, #else rc = lstat(unix_socket, &statbuf); #endif - if(0 != rc) { + if(rc) { logmsg("Error binding socket, failed to stat %s (%d) %s", unix_socket, errno, strerror(errno)); return rc; @@ -745,7 +745,7 @@ int bind_unix_socket(curl_socket_t sock, const char *unix_socket, #endif /* dead socket, cleanup and retry bind */ rc = unlink(unix_socket); - if(0 != rc) { + if(rc) { logmsg("Error binding socket, failed to unlink %s (%d) %s", unix_socket, errno, strerror(errno)); return rc; @@ -777,3 +777,166 @@ unsigned short util_ultous(unsigned long ulnum) # pragma warning(pop) #endif } + +curl_socket_t sockdaemon(curl_socket_t sock, + unsigned short *listenport, + const char *unix_socket, + bool bind_only) +{ + /* passive daemon style */ + srvr_sockaddr_union_t listener; + int flag; + int rc; + int totdelay = 0; + int maxretr = 10; + int delay = 20; + int attempt = 0; + int error = 0; + +#ifndef USE_UNIX_SOCKETS + (void)unix_socket; +#endif + + do { + attempt++; + flag = 1; + rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + (void *)&flag, sizeof(flag)); + if(rc) { + error = SOCKERRNO; + logmsg("setsockopt(SO_REUSEADDR) failed with error (%d) %s", + error, sstrerror(error)); + if(maxretr) { + rc = curlx_wait_ms(delay); + if(rc) { + /* should not happen */ + error = SOCKERRNO; + logmsg("curlx_wait_ms() failed with error (%d) %s", + error, sstrerror(error)); + sclose(sock); + return CURL_SOCKET_BAD; + } + if(got_exit_signal) { + logmsg("signalled to die, exiting..."); + sclose(sock); + return CURL_SOCKET_BAD; + } + totdelay += delay; + delay *= 2; /* double the sleep for next attempt */ + } + } + } while(rc && maxretr--); + + if(rc) { + logmsg("setsockopt(SO_REUSEADDR) failed %d times in %d ms. Error (%d) %s", + attempt, totdelay, error, strerror(error)); + logmsg("Continuing anyway..."); + } + + /* When the specified listener port is zero, it is actually a + request to let the system choose a non-zero available port. */ + + switch(socket_domain) { + case AF_INET: + memset(&listener.sa4, 0, sizeof(listener.sa4)); + listener.sa4.sin_family = AF_INET; + listener.sa4.sin_addr.s_addr = INADDR_ANY; + listener.sa4.sin_port = htons(*listenport); + rc = bind(sock, &listener.sa, sizeof(listener.sa4)); + break; +#ifdef USE_IPV6 + case AF_INET6: + memset(&listener.sa6, 0, sizeof(listener.sa6)); + listener.sa6.sin6_family = AF_INET6; + listener.sa6.sin6_addr = in6addr_any; + listener.sa6.sin6_port = htons(*listenport); + rc = bind(sock, &listener.sa, sizeof(listener.sa6)); + break; +#endif /* USE_IPV6 */ +#ifdef USE_UNIX_SOCKETS + case AF_UNIX: + rc = bind_unix_socket(sock, unix_socket, &listener.sau); + break; +#endif + default: + rc = 1; + } + + if(rc) { + error = SOCKERRNO; +#ifdef USE_UNIX_SOCKETS + if(socket_domain == AF_UNIX) + logmsg("Error binding socket on path %s (%d) %s", + unix_socket, error, sstrerror(error)); + else +#endif + logmsg("Error binding socket on port %hu (%d) %s", + *listenport, error, sstrerror(error)); + sclose(sock); + return CURL_SOCKET_BAD; + } + + if(!*listenport +#ifdef USE_UNIX_SOCKETS + && !unix_socket +#endif + ) { + /* The system was supposed to choose a port number, figure out which + port we actually got and update the listener port value with it. */ + curl_socklen_t la_size; + srvr_sockaddr_union_t localaddr; +#ifdef USE_IPV6 + if(socket_domain == AF_INET6) + la_size = sizeof(localaddr.sa6); + else +#endif + la_size = sizeof(localaddr.sa4); + memset(&localaddr.sa, 0, (size_t)la_size); + if(getsockname(sock, &localaddr.sa, &la_size) < 0) { + error = SOCKERRNO; + logmsg("getsockname() failed with error (%d) %s", + error, sstrerror(error)); + sclose(sock); + return CURL_SOCKET_BAD; + } + switch(localaddr.sa.sa_family) { + case AF_INET: + *listenport = ntohs(localaddr.sa4.sin_port); + break; +#ifdef USE_IPV6 + case AF_INET6: + *listenport = ntohs(localaddr.sa6.sin6_port); + break; +#endif + default: + break; + } + if(!*listenport) { + /* Real failure, listener port shall not be zero beyond this point. */ + logmsg("Apparently getsockname() succeeded, with listener port zero."); + logmsg("A valid reason for this failure is a binary built without"); + logmsg("proper network library linkage. This might not be the only"); + logmsg("reason, but double check it before anything else."); + sclose(sock); + return CURL_SOCKET_BAD; + } + } + + /* bindonly option forces no listening */ + if(bind_only) { + logmsg("instructed to bind port without listening"); + return sock; + } + + /* start accepting connections */ + rc = listen(sock, 5); + if(rc) { + error = SOCKERRNO; + logmsg("listen(%ld, 5) failed with error (%d) %s", + (long)sock, error, sstrerror(error)); + sclose(sock); + return CURL_SOCKET_BAD; + } + + return sock; +} -- 2.47.2