Expose socket interruption

On Linux, socket functions are unblocked by shutdown(), but on Windows
they are unblocked by closesocket().

Expose net_interrupt() and net_close() to abstract these differences:
 - net_interrupt() calls shutdown() on Linux and closesocket() on
   Windows (if not already called);
 - net_close() calls close() on Linux and closesocket() on Windows (if
   not already called).

This simplifies the server code, and prevents a data race on close
(reported by TSAN) on Linux (but does not fix it on Windows):

    WARNING: ThreadSanitizer: data race (pid=836124)
      Write of size 8 at 0x7ba0000000d0 by main thread:
        #0 close ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1690 (libtsan.so.0+0x359d8)
        #1 net_close ../app/src/util/net.c:211 (scrcpy+0x1c76b)
        #2 close_socket ../app/src/server.c:330 (scrcpy+0x19442)
        #3 server_stop ../app/src/server.c:522 (scrcpy+0x19e33)
        #4 scrcpy ../app/src/scrcpy.c:532 (scrcpy+0x156fc)
        #5 main ../app/src/main.c:92 (scrcpy+0x622a)

      Previous read of size 8 at 0x7ba0000000d0 by thread T6:
        #0 recv ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:6603 (libtsan.so.0+0x4f4a6)
        #1 net_recv ../app/src/util/net.c:167 (scrcpy+0x1c5a7)
        #2 run_receiver ../app/src/receiver.c:76 (scrcpy+0x12819)
        #3 <null> <null> (libSDL2-2.0.so.0+0x84f40)
This commit is contained in:
Romain Vimont
2021-10-26 22:49:45 +02:00
parent e5ea13770b
commit ac23bec144
4 changed files with 62 additions and 42 deletions

View File

@@ -1,5 +1,6 @@
#include "net.h"
#include <assert.h>
#include <stdio.h>
#include <SDL2/SDL_platform.h>
@@ -55,6 +56,7 @@ wrap(sc_raw_socket sock) {
}
socket->socket = sock;
socket->closed = (atomic_flag) ATOMIC_FLAG_INIT;
return socket;
#else
@@ -195,18 +197,33 @@ net_send_all(sc_socket socket, const void *buf, size_t len) {
}
bool
net_shutdown(sc_socket socket, int how) {
net_interrupt(sc_socket socket) {
assert(socket != SC_INVALID_SOCKET);
sc_raw_socket raw_sock = unwrap(socket);
return !shutdown(raw_sock, how);
#ifdef __WINDOWS__
if (!atomic_flag_test_and_set(&socket->closed)) {
return !closesocket(raw_sock);
}
return true;
#else
return !shutdown(raw_sock, SHUT_RDWR);
#endif
}
#include <errno.h>
bool
net_close(sc_socket socket) {
sc_raw_socket raw_sock = unwrap(socket);
#ifdef __WINDOWS__
bool ret = true;
if (!atomic_flag_test_and_set(&socket->closed)) {
ret = !closesocket(raw_sock);
}
free(socket);
return !closesocket(raw_sock);
return ret;
#else
return !close(raw_sock);
#endif