Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor tests/server/socksd.c to support --unix-socket #8687

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -58,3 +58,4 @@ scripts/curl.fish
curl_fuzzer
curl_fuzzer_seed_corpus.zip
libstandaloneengine.a
tests/string
134 changes: 94 additions & 40 deletions tests/server/socksd.c
Expand Up @@ -143,10 +143,7 @@ const char *serverlogfile = DEFAULT_LOGFILE;
const char *reqlogfile = DEFAULT_REQFILE;
static const char *configfile = DEFAULT_CONFIG;

#ifdef ENABLE_IPV6
static bool use_ipv6 = FALSE;
#endif
static const char *ipv_inuse = "IPv4";
static const char *socket_type = "IPv4";
static unsigned short port = DEFAULT_PORT;

static void resetdefaults(void)
Expand Down Expand Up @@ -177,6 +174,16 @@ static unsigned short shortval(char *value)
return num & 0xffff;
}

static enum {
socket_domain_inet = AF_INET
#ifdef ENABLE_IPV6
, socket_domain_inet6 = AF_INET6
#endif
#ifdef USE_UNIX_SOCKETS
, socket_domain_unix = AF_UNIX
#endif
} socket_domain = AF_INET;

static void getconfig(void)
{
FILE *fp = fopen(configfile, FOPEN_READTEXT);
Expand Down Expand Up @@ -777,7 +784,11 @@ static bool incoming(curl_socket_t listenfd)
}

static curl_socket_t sockdaemon(curl_socket_t sock,
unsigned short *listenport)
unsigned short *listenport
#ifdef USE_UNIX_SOCKETS
, const char *unix_socket
#endif
)
{
/* passive daemon style */
srvr_sockaddr_union_t listener;
Expand Down Expand Up @@ -828,24 +839,29 @@ static curl_socket_t sockdaemon(curl_socket_t sock,
/* 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 ENABLE_IPV6
if(!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 /* ENABLE_IPV6 */
#ifdef USE_UNIX_SOCKETS
case AF_UNIX:
rc = bind_unix_socket(sock, unix_socket, &listener.sau);
#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 ENABLE_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 /* ENABLE_IPV6 */

if(rc) {
error = SOCKERRNO;
logmsg("Error binding socket on port %hu: (%d) %s",
Expand All @@ -854,19 +870,21 @@ static curl_socket_t sockdaemon(curl_socket_t sock,
return CURL_SOCKET_BAD;
}

if(!*listenport) {
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 ENABLE_IPV6
if(!use_ipv6)
#endif
la_size = sizeof(localaddr.sa4);
#ifdef ENABLE_IPV6
else
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;
Expand Down Expand Up @@ -924,6 +942,11 @@ int main(int argc, char *argv[])
int error;
int arg = 1;

#ifdef USE_UNIX_SOCKETS
const char *unix_socket = NULL;
bool unlink_socket = false;
#endif

while(argc>arg) {
if(!strcmp("--version", argv[arg])) {
printf("socksd IPv4%s\n",
Expand Down Expand Up @@ -972,19 +995,36 @@ int main(int argc, char *argv[])
}
else if(!strcmp("--ipv6", argv[arg])) {
#ifdef ENABLE_IPV6
ipv_inuse = "IPv6";
use_ipv6 = TRUE;
socket_domain = AF_INET6;
socket_type = "IPv6";
#endif
arg++;
}
else if(!strcmp("--ipv4", argv[arg])) {
/* for completeness, we support this option as well */
#ifdef ENABLE_IPV6
ipv_inuse = "IPv4";
use_ipv6 = FALSE;
socket_type = "IPv4";
#endif
arg++;
}
else if(!strcmp("--unix-socket", argv[arg])) {
arg++;
if(argc>arg) {
#ifdef USE_UNIX_SOCKETS
struct sockaddr_un sau;
unix_socket = argv[arg];
if(strlen(unix_socket) >= sizeof(sau.sun_path)) {
fprintf(stderr,
"socksd: socket path must be shorter than %zu chars\n",
sizeof(sau.sun_path));
return 0;
}
socket_domain = AF_UNIX;
socket_type = "unix";
#endif
arg++;
}
}
else if(!strcmp("--port", argv[arg])) {
arg++;
if(argc>arg) {
Expand All @@ -1006,6 +1046,7 @@ int main(int argc, char *argv[])
" --reqfile [file]\n"
" --ipv4\n"
" --ipv6\n"
" --unix-socket [file]\n"
" --bindonly\n"
" --port [port]\n");
return 0;
Expand All @@ -1023,14 +1064,7 @@ int main(int argc, char *argv[])

install_signal_handlers(false);

#ifdef ENABLE_IPV6
if(!use_ipv6)
#endif
sock = socket(AF_INET, SOCK_STREAM, 0);
#ifdef ENABLE_IPV6
else
sock = socket(AF_INET6, SOCK_STREAM, 0);
#endif
sock = socket(socket_domain, SOCK_STREAM, 0);

if(CURL_SOCKET_BAD == sock) {
error = SOCKERRNO;
Expand All @@ -1041,14 +1075,27 @@ int main(int argc, char *argv[])

{
/* passive daemon style */
sock = sockdaemon(sock, &port);
sock = sockdaemon(sock, &port
#ifdef USE_UNIX_SOCKETS
, unix_socket
#endif
);
if(CURL_SOCKET_BAD == sock) {
goto socks5_cleanup;
}
#ifdef USE_UNIX_SOCKETS
unlink_socket = true;
#endif
msgsock = CURL_SOCKET_BAD; /* no stream socket yet */
}

logmsg("Running %s version", ipv_inuse);
logmsg("Running %s version", socket_type);

#ifdef USE_UNIX_SOCKETS
if(socket_domain == AF_UNIX)
logmsg("Listening on unix socket %s", unix_socket);
else
#endif
logmsg("Listening on port %hu", port);

wrotepidfile = write_pidfile(pidname);
Expand All @@ -1075,6 +1122,13 @@ int main(int argc, char *argv[])
if(sock != CURL_SOCKET_BAD)
sclose(sock);

#ifdef USE_UNIX_SOCKETS
if(unlink_socket && socket_domain == AF_UNIX) {
error = unlink(unix_socket);
logmsg("unlink(%s) = %d (%s)", unix_socket, error, strerror(error));
}
#endif

if(wrotepidfile)
unlink(pidname);
if(wroteportfile)
Expand Down
54 changes: 1 addition & 53 deletions tests/server/sws.c
Expand Up @@ -2066,59 +2066,7 @@ int main(int argc, char *argv[])
#endif /* ENABLE_IPV6 */
#ifdef USE_UNIX_SOCKETS
case AF_UNIX:
memset(&me.sau, 0, sizeof(me.sau));
me.sau.sun_family = AF_UNIX;
strncpy(me.sau.sun_path, unix_socket, sizeof(me.sau.sun_path) - 1);
rc = bind(sock, &me.sa, sizeof(me.sau));
if(0 != rc && errno == EADDRINUSE) {
struct_stat statbuf;
/* socket already exists. Perhaps it is stale? */
curl_socket_t unixfd = socket(AF_UNIX, SOCK_STREAM, 0);
if(CURL_SOCKET_BAD == unixfd) {
error = SOCKERRNO;
logmsg("Error binding socket, failed to create socket at %s: (%d) %s",
unix_socket, error, strerror(error));
goto sws_cleanup;
}
/* check whether the server is alive */
rc = connect(unixfd, &me.sa, sizeof(me.sau));
error = errno;
sclose(unixfd);
if(ECONNREFUSED != error) {
logmsg("Error binding socket, failed to connect to %s: (%d) %s",
unix_socket, error, strerror(error));
goto sws_cleanup;
}
/* socket server is not alive, now check if it was actually a socket. */
#ifdef WIN32
/* Windows does not have lstat function. */
rc = curlx_win32_stat(unix_socket, &statbuf);
#else
rc = lstat(unix_socket, &statbuf);
#endif
if(0 != rc) {
logmsg("Error binding socket, failed to stat %s: (%d) %s",
unix_socket, errno, strerror(errno));
goto sws_cleanup;
}
#ifdef S_IFSOCK
if((statbuf.st_mode & S_IFSOCK) != S_IFSOCK) {
logmsg("Error binding socket, failed to stat %s: (%d) %s",
unix_socket, error, strerror(error));
goto sws_cleanup;
}
#endif
/* dead socket, cleanup and retry bind */
rc = unlink(unix_socket);
if(0 != rc) {
logmsg("Error binding socket, failed to unlink %s: (%d) %s",
unix_socket, errno, strerror(errno));
goto sws_cleanup;
}
/* stale socket is gone, retry bind */
rc = bind(sock, &me.sa, sizeof(me.sau));
}
break;
rc = bind_unix_socket(sock, unix_socket, &me.sau);
#endif /* USE_UNIX_SOCKETS */
}
if(0 != rc) {
Expand Down
63 changes: 63 additions & 0 deletions tests/server/util.c
Expand Up @@ -809,3 +809,66 @@ void restore_signal_handlers(bool keep_sigalrm)
}
#endif
}

#ifdef USE_UNIX_SOCKETS

int bind_unix_socket(curl_socket_t sock, const char *unix_socket,
struct sockaddr_un *sau) {
int error;
int rc;

memset(sau, 0, sizeof(struct sockaddr_un));
sau->sun_family = AF_UNIX;
strncpy(sau->sun_path, unix_socket, sizeof(sau->sun_path) - 1);
rc = bind(sock, (struct sockaddr*)sau, sizeof(struct sockaddr_un));
if(0 != rc && errno == EADDRINUSE) {
struct_stat statbuf;
/* socket already exists. Perhaps it is stale? */
curl_socket_t unixfd = socket(AF_UNIX, SOCK_STREAM, 0);
if(CURL_SOCKET_BAD == unixfd) {
error = SOCKERRNO;
logmsg("Error binding socket, failed to create socket at %s: (%d) %s",
unix_socket, error, strerror(error));
return rc;
}
/* check whether the server is alive */
rc = connect(unixfd, (struct sockaddr*)sau, sizeof(struct sockaddr_un));
error = errno;
sclose(unixfd);
if(ECONNREFUSED != error) {
logmsg("Error binding socket, failed to connect to %s: (%d) %s",
unix_socket, error, strerror(error));
return rc;
}
/* socket server is not alive, now check if it was actually a socket. */
#ifdef WIN32
/* Windows does not have lstat function. */
rc = curlx_win32_stat(unix_socket, &statbuf);
#else
rc = lstat(unix_socket, &statbuf);
#endif
if(0 != rc) {
logmsg("Error binding socket, failed to stat %s: (%d) %s",
unix_socket, errno, strerror(errno));
return rc;
}
#ifdef S_IFSOCK
if((statbuf.st_mode & S_IFSOCK) != S_IFSOCK) {
logmsg("Error binding socket, failed to stat %s: (%d) %s",
unix_socket, error, strerror(error));
return rc;
}
#endif
/* dead socket, cleanup and retry bind */
rc = unlink(unix_socket);
if(0 != rc) {
logmsg("Error binding socket, failed to unlink %s: (%d) %s",
unix_socket, errno, strerror(errno));
return rc;
}
/* stale socket is gone, retry bind */
rc = bind(sock, (struct sockaddr*)sau, sizeof(struct sockaddr_un));
}
return rc;
}
#endif
10 changes: 10 additions & 0 deletions tests/server/util.h
Expand Up @@ -79,4 +79,14 @@ extern HANDLE exit_event;
void install_signal_handlers(bool keep_sigalrm);
void restore_signal_handlers(bool keep_sigalrm);

#ifdef USE_UNIX_SOCKETS

#ifdef HAVE_SYS_UN_H
#include <sys/un.h> /* for sockaddr_un */
#endif /* HAVE_SYS_UN_H */

int bind_unix_socket(curl_socket_t sock, const char *unix_socket,
struct sockaddr_un *sau);
#endif /* USE_UNIX_SOCKETS */

#endif /* HEADER_CURL_SERVER_UTIL_H */