diff --git a/app/src/util/net.c b/app/src/util/net.c index d43d1c7aa0..d68b0af60a 100644 --- a/app/src/util/net.c +++ b/app/src/util/net.c @@ -9,8 +9,6 @@ #ifdef _WIN32 # include typedef int socklen_t; - typedef SOCKET sc_raw_socket; -# define SC_RAW_SOCKET_NONE INVALID_SOCKET #else # include # include @@ -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 @@ -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; } @@ -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; @@ -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 @@ -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 @@ -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 } diff --git a/app/src/util/net.h b/app/src/util/net.h index ea54b79350..9f23bac9c8 100644 --- a/app/src/util/net.h +++ b/app/src/util/net.h @@ -7,21 +7,36 @@ #include #ifdef _WIN32 - # include + typedef SOCKET sc_raw_socket; +# define SC_RAW_SOCKET_NONE INVALID_SOCKET +#else // not _WIN32 +# include + 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 # 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 +#else # define SC_SOCKET_NONE -1 - typedef int sc_socket; - + typedef sc_raw_socket sc_socket; #endif #define IPV4_LOCALHOST 0x7F000001