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));
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 */
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;
}
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++;
}
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;
{
/* 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;
}
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));
/* start accepting connections */
rc = listen(sock, 5);
- if(0 != rc) {
+ if(rc) {
error = SOCKERRNO;
logmsg("listen() failed with error (%d) %s",
error, sstrerror(error));
return 0;
}
+
static HANDLE select_ws_wait(HANDLE handle, HANDLE signal, HANDLE abort)
{
typedef uintptr_t curl_win_thread_handle_t;
}
return NULL;
}
+
struct select_ws_data {
int fd; /* provided file descriptor (indexed by nfd) */
long wsastate; /* internal pre-select state (indexed by nfd) */
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)
{
#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;
}
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++;
}
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;
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",
}
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;
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;
{
/* 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;
}
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)
/* 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;
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));
}
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);
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;
#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;
#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;
# 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;
+}