Skip to content

Commit

Permalink
Split network macro conditions
Browse files Browse the repository at this point in the history
On Windows, interrupting a socket with shutdown() does not wake up
accept() or read() calls, the socket must be closed.

Introduce a new macro constant SC_SOCKET_CLOSE_ON_INTERRUPT, distinct of
_WIN32, because Windows will not be the only platform exhibiting this
behavior.

Refs #5536 <#5536>
  • Loading branch information
rom1v committed Nov 28, 2024
1 parent 017a367 commit ff06b6d
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 35 deletions.
46 changes: 20 additions & 26 deletions app/src/util/net.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
#ifdef _WIN32
# include <ws2tcpip.h>
typedef int socklen_t;
typedef SOCKET sc_raw_socket;
# define SC_RAW_SOCKET_NONE INVALID_SOCKET
#else
# include <sys/types.h>
# include <sys/socket.h>
Expand All @@ -23,8 +21,6 @@
typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;
typedef struct in_addr IN_ADDR;
typedef int sc_raw_socket;
# define SC_RAW_SOCKET_NONE -1
#endif

bool
Expand All @@ -47,17 +43,26 @@ net_cleanup(void) {
#endif
}

static inline bool
sc_raw_socket_close(sc_raw_socket raw_sock) {
#ifndef _WIN32
return !close(raw_sock);
#else
return !closesocket(raw_sock);
#endif
}

static inline sc_socket
wrap(sc_raw_socket sock) {
#ifdef _WIN32
if (sock == INVALID_SOCKET) {
#ifdef SC_SOCKET_CLOSE_ON_INTERRUPT
if (sock == SC_RAW_SOCKET_NONE) {
return SC_SOCKET_NONE;
}

struct sc_socket_windows *socket = malloc(sizeof(*socket));
struct sc_socket_wrapper *socket = malloc(sizeof(*socket));
if (!socket) {
LOG_OOM();
closesocket(sock);
sc_raw_socket_close(sock);
return SC_SOCKET_NONE;
}

Expand All @@ -72,9 +77,9 @@ wrap(sc_raw_socket sock) {

static inline sc_raw_socket
unwrap(sc_socket socket) {
#ifdef _WIN32
#ifdef SC_SOCKET_CLOSE_ON_INTERRUPT
if (socket == SC_SOCKET_NONE) {
return INVALID_SOCKET;
return SC_RAW_SOCKET_NONE;
}

return socket->socket;
Expand All @@ -83,17 +88,6 @@ unwrap(sc_socket socket) {
#endif
}

#ifndef HAVE_SOCK_CLOEXEC // avoid unused-function warning
static inline bool
sc_raw_socket_close(sc_raw_socket raw_sock) {
#ifndef _WIN32
return !close(raw_sock);
#else
return !closesocket(raw_sock);
#endif
}
#endif

#ifndef HAVE_SOCK_CLOEXEC
// If SOCK_CLOEXEC does not exist, the flag must be set manually once the
// socket is created
Expand Down Expand Up @@ -248,9 +242,9 @@ net_interrupt(sc_socket socket) {

sc_raw_socket raw_sock = unwrap(socket);

#ifdef _WIN32
#ifdef SC_SOCKET_CLOSE_ON_INTERRUPT
if (!atomic_flag_test_and_set(&socket->closed)) {
return !closesocket(raw_sock);
return sc_raw_socket_close(raw_sock);
}
return true;
#else
Expand All @@ -262,15 +256,15 @@ bool
net_close(sc_socket socket) {
sc_raw_socket raw_sock = unwrap(socket);

#ifdef _WIN32
#ifdef SC_SOCKET_CLOSE_ON_INTERRUPT
bool ret = true;
if (!atomic_flag_test_and_set(&socket->closed)) {
ret = !closesocket(raw_sock);
ret = sc_raw_socket_close(raw_sock);
}
free(socket);
return ret;
#else
return !close(raw_sock);
return sc_raw_socket_close(raw_sock);
#endif
}

Expand Down
33 changes: 24 additions & 9 deletions app/src/util/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,36 @@
#include <stdint.h>

#ifdef _WIN32

# include <winsock2.h>
typedef SOCKET sc_raw_socket;
# define SC_RAW_SOCKET_NONE INVALID_SOCKET
#else // not _WIN32
# include <sys/socket.h>
typedef int sc_raw_socket;
# define SC_RAW_SOCKET_NONE -1
#endif

#ifdef _WIN32
// On Windows, shutdown() does not interrupt accept() or read() calls, so
// net_interrupt() must call close() instead, and net_close() must behave
// accordingly.
// This causes a small race condition (once the socket is closed, its
// handle becomes invalid and may in theory be reassigned before another
// thread calls accept() or read()), but it is deemed acceptable as a
// workaround.
# define SC_SOCKET_CLOSE_ON_INTERRUPT
#endif

#ifdef SC_SOCKET_CLOSE_ON_INTERRUPT
# include <stdatomic.h>
# define SC_SOCKET_NONE NULL
typedef struct sc_socket_windows {
SOCKET socket;
typedef struct sc_socket_wrapper {
sc_raw_socket socket;
atomic_flag closed;
} *sc_socket;

#else // not _WIN32

# include <sys/socket.h>
#else
# define SC_SOCKET_NONE -1
typedef int sc_socket;

typedef sc_raw_socket sc_socket;
#endif

#define IPV4_LOCALHOST 0x7F000001
Expand Down

0 comments on commit ff06b6d

Please sign in to comment.