Compare commits

...

2 Commits

Author SHA1 Message Date
Romain Vimont
1ddf289d82 Enable close-on-interrupt for macOS
This behavior is also necessary on macOS.

TODO ref 5536
2024-11-27 10:19:34 +01:00
Romain Vimont
bf7c7d8038 Split network macro conditions
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.

TODO ref 5536
2024-11-27 10:19:26 +01:00
2 changed files with 46 additions and 36 deletions

View File

@ -9,8 +9,6 @@
#ifdef _WIN32 #ifdef _WIN32
# include <ws2tcpip.h> # include <ws2tcpip.h>
typedef int socklen_t; typedef int socklen_t;
typedef SOCKET sc_raw_socket;
# define SC_RAW_SOCKET_NONE INVALID_SOCKET
#else #else
# include <sys/types.h> # include <sys/types.h>
# include <sys/socket.h> # include <sys/socket.h>
@ -23,8 +21,6 @@
typedef struct sockaddr_in SOCKADDR_IN; typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR; typedef struct sockaddr SOCKADDR;
typedef struct in_addr IN_ADDR; typedef struct in_addr IN_ADDR;
typedef int sc_raw_socket;
# define SC_RAW_SOCKET_NONE -1
#endif #endif
bool bool
@ -47,17 +43,26 @@ net_cleanup(void) {
#endif #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 static inline sc_socket
wrap(sc_raw_socket sock) { wrap(sc_raw_socket sock) {
#ifdef _WIN32 #ifdef SC_SOCKET_CLOSE_ON_INTERRUPT
if (sock == INVALID_SOCKET) { if (sock == SC_RAW_SOCKET_NONE) {
return SC_SOCKET_NONE; return SC_SOCKET_NONE;
} }
struct sc_socket_windows *socket = malloc(sizeof(*socket)); struct sc_socket_wrapper *socket = malloc(sizeof(*socket));
if (!socket) { if (!socket) {
LOG_OOM(); LOG_OOM();
closesocket(sock); sc_raw_socket_close(sock);
return SC_SOCKET_NONE; return SC_SOCKET_NONE;
} }
@ -72,9 +77,9 @@ wrap(sc_raw_socket sock) {
static inline sc_raw_socket static inline sc_raw_socket
unwrap(sc_socket socket) { unwrap(sc_socket socket) {
#ifdef _WIN32 #ifdef SC_SOCKET_CLOSE_ON_INTERRUPT
if (socket == SC_SOCKET_NONE) { if (socket == SC_SOCKET_NONE) {
return INVALID_SOCKET; return SC_RAW_SOCKET_NONE;
} }
return socket->socket; return socket->socket;
@ -83,17 +88,6 @@ unwrap(sc_socket socket) {
#endif #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 #ifndef HAVE_SOCK_CLOEXEC
// If SOCK_CLOEXEC does not exist, the flag must be set manually once the // If SOCK_CLOEXEC does not exist, the flag must be set manually once the
// socket is created // socket is created
@ -248,9 +242,9 @@ net_interrupt(sc_socket socket) {
sc_raw_socket raw_sock = unwrap(socket); sc_raw_socket raw_sock = unwrap(socket);
#ifdef _WIN32 #ifdef SC_SOCKET_CLOSE_ON_INTERRUPT
if (!atomic_flag_test_and_set(&socket->closed)) { if (!atomic_flag_test_and_set(&socket->closed)) {
return !closesocket(raw_sock); return sc_raw_socket_close(raw_sock);
} }
return true; return true;
#else #else
@ -262,15 +256,15 @@ bool
net_close(sc_socket socket) { net_close(sc_socket socket) {
sc_raw_socket raw_sock = unwrap(socket); sc_raw_socket raw_sock = unwrap(socket);
#ifdef _WIN32 #ifdef SC_SOCKET_CLOSE_ON_INTERRUPT
bool ret = true; bool ret = true;
if (!atomic_flag_test_and_set(&socket->closed)) { if (!atomic_flag_test_and_set(&socket->closed)) {
ret = !closesocket(raw_sock); ret = sc_raw_socket_close(raw_sock);
} }
free(socket); free(socket);
return ret; return ret;
#else #else
return !close(raw_sock); return sc_raw_socket_close(raw_sock);
#endif #endif
} }

View File

@ -7,21 +7,37 @@
#include <stdint.h> #include <stdint.h>
#ifdef _WIN32 #ifdef _WIN32
# include <winsock2.h> # include <winsock2.h>
# include <stdatomic.h> typedef SOCKET sc_raw_socket;
# define SC_SOCKET_NONE NULL # define SC_RAW_SOCKET_NONE INVALID_SOCKET
typedef struct sc_socket_windows {
SOCKET socket;
atomic_flag closed;
} *sc_socket;
#else // not _WIN32 #else // not _WIN32
# include <sys/socket.h> # include <sys/socket.h>
# define SC_SOCKET_NONE -1 # define SC_SOCKET_NONE -1
typedef int sc_socket; typedef int sc_raw_socket;
# define SC_RAW_SOCKET_NONE -1
#endif
#if defined(_WIN32) || defined(__APPLE__)
// On Windows and macOS, 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_wrapper {
sc_raw_socket socket;
atomic_flag closed;
} *sc_socket;
#else
# define SC_SOCKET_NONE -1
typedef sc_raw_socket sc_socket;
#endif #endif
#define IPV4_LOCALHOST 0x7F000001 #define IPV4_LOCALHOST 0x7F000001