From 00d3afeb53bf6a9726c7a3a86680954f88111d9d Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Thu, 20 Dec 2018 09:33:26 +1100 Subject: [PATCH] fix game crashing when socket fd is >= 1024 on linux (Thanks Odd0002) --- src/LScreens.c | 5 +-- src/LWeb.c | 4 --- src/Platform.c | 71 ++++++++++++++++++++++++++---------------- src/Platform.h | 14 +++++---- src/ServerConnection.c | 9 +++--- 5 files changed, 61 insertions(+), 42 deletions(-) diff --git a/src/LScreens.c b/src/LScreens.c index 2379ed6fd..820d81a64 100644 --- a/src/LScreens.c +++ b/src/LScreens.c @@ -1281,6 +1281,7 @@ CC_NOINLINE static void UpdatesScreen_FormatTime(String* str, char* type, int de static void UpdatesScreen_Format(struct LLabel* lbl, const char* prefix, TimeMS time) { String str; char buffer[STRING_SIZE]; TimeMS now; + int delta; String_InitArray(str, buffer); String_AppendConst(&str, prefix); @@ -1288,8 +1289,8 @@ static void UpdatesScreen_Format(struct LLabel* lbl, const char* prefix, TimeMS if (!time) { String_AppendConst(&str, "&cCheck failed"); } else { - now = DateTime_CurrentUTC_MS(); - int delta = (int)(now - time) / 1000; + now = DateTime_CurrentUTC_MS(); + delta = (int)(now - time) / 1000; if (delta < SECS_PER_MIN) { UpdatesScreen_FormatTime(&str, "second", delta, 1); diff --git a/src/LWeb.c b/src/LWeb.c index 4e1587562..524d78f6f 100644 --- a/src/LWeb.c +++ b/src/LWeb.c @@ -223,10 +223,6 @@ void LWebTask_Tick(struct LWebTask* task) { ASyncRequest_Free(&req); } -static void LWebTask_DefaultBegin(struct LWebTask* task) { - AsyncDownloader_GetData(&task->URL, false, &task->Identifier); -} - /*########################################################################################################################* *-------------------------------------------------------GetTokenTask------------------------------------------------------* diff --git a/src/Platform.c b/src/Platform.c index 0defd02a1..b02288284 100644 --- a/src/Platform.c +++ b/src/Platform.c @@ -71,6 +71,7 @@ const ReturnCode ReturnCode_SocketWouldBlock = WSAEWOULDBLOCK; #include #include #include +#include #define Socket__Error() errno char* Platform_NewLine = "\n"; @@ -875,17 +876,6 @@ static bool Font_MakeArgs(const String* path, FT_Stream stream, FT_Open_Args* ar return true; } -static int Font_Find(const String* name, StringsBuffer* entries) { - String faceName; - int i; - - for (i = 1; i < entries->Count; i += 2) { - faceName = StringsBuffer_UNSAFE_Get(entries, i); - if (String_CaselessEquals(&faceName, name)) return i; - } - return -1; -} - void Font_GetNames(StringsBuffer* buffer) { String entry, name, path; int i; @@ -1273,33 +1263,62 @@ ReturnCode Socket_Close(SocketHandle socket) { return res; } -ReturnCode Socket_Select(SocketHandle socket, int selectMode, bool* success) { +/* Alas, a simple cross-platform select() is not good enough */ +#ifdef CC_BUILD_WIN +ReturnCode Socket_Poll(SocketHandle socket, int mode, bool* success) { fd_set set; struct timeval time = { 0 }; - int selectCount, nfds; + int selectCount; + + set.fd_count = 1; + set.fd_array[0] = socket; + + if (mode == SOCKET_POLL_READ) { + selectCount = select(1, &set, NULL, NULL, &time); + } else { + selectCount = select(1, NULL, &set, NULL, &time); + } + + if (selectCount == -1) { *success = false; return Socket__Error(); } + + *success = set.fd_count != 0; return 0; +} +#else +#ifdef CC_BUILD_OSX +/* poll is broken on old OSX apparently https://daniel.haxx.se/docs/poll-vs-select.html */ +ReturnCode Socket_Poll(SocketHandle socket, int mode, bool* success) { + fd_set set; + struct timeval time = { 0 }; + int selectCount; FD_ZERO(&set); FD_SET(socket, &set); - #ifdef CC_BUILD_WIN - nfds = 1; - #else - nfds = socket + 1; - #endif - - if (selectMode == SOCKET_SELECT_READ) { - selectCount = select(nfds, &set, NULL, NULL, &time); + if (selectMode == SOCKET_POLL_READ) { + selectCount = select(socket + 1, &set, NULL, NULL, &time); } else { - selectCount = select(nfds, NULL, &set, NULL, &time); + selectCount = select(socket + 1, NULL, &set, NULL, &time); } if (selectCount == -1) { *success = false; return Socket__Error(); } -#ifdef CC_BUILD_WIN - *success = set.fd_count != 0; return 0; -#else *success = FD_ISSET(socket, &set); return 0; -#endif } +#else +ReturnCode Socket_Poll(SocketHandle socket, int mode, bool* success) { + struct pollfd pfd; + int flags; + + pfd.fd = socket; + pfd.events = mode == SOCKET_POLL_READ ? POLLIN : POLLOUT; + if (poll(&pfd, 1, 0) == -1) { *success = false; return Socket__Error(); } + + /* to match select, closed socket still counts as readable */ + flags = mode == SOCKET_POLL_READ ? (POLLIN | POLLHUP) : POLLOUT; + *success = (pfd.revents & flags) != 0; + return 0; +} +#endif +#endif /*########################################################################################################################* diff --git a/src/Platform.h b/src/Platform.h index 5465ba6d3..3eccafc5e 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -9,7 +9,7 @@ struct DrawTextArgs; struct AsyncRequest; struct DateTime; -enum Socket_Select { SOCKET_SELECT_READ, SOCKET_SELECT_WRITE }; +enum Socket_PollMode { SOCKET_POLL_READ, SOCKET_POLL_WRITE }; #ifdef CC_BUILD_WIN typedef uintptr_t SocketHandle; typedef void* FileHandle; @@ -201,13 +201,13 @@ int Platform_TextDraw(struct DrawTextArgs* args, Bitmap* bmp, int x, int y, Bitm void Socket_Create(SocketHandle* socket); /* Returns how much data is available to be read from the given socket. */ ReturnCode Socket_Available(SocketHandle socket, uint32_t* available); -/* Sets whether operations on this socket block the calling thread. */ +/* Sets whether operations on the given socket block the calling thread. */ /* e.g. if blocking is on, calling Connect() blocks until a response is received. */ ReturnCode Socket_SetBlocking(SocketHandle socket, bool blocking); -/* Returns (and resets) the last error generated by this socket. */ +/* Returns (and resets) the last error generated by the given socket. */ ReturnCode Socket_GetError(SocketHandle socket, ReturnCode* result); -/* Attempts to initalise a TCP connection to the given IP address:port. */ +/* Attempts to initalise a connection to the given IP address:port. */ ReturnCode Socket_Connect(SocketHandle socket, const String* ip, int port); /* Attempts to read data from the given socket. */ ReturnCode Socket_Read(SocketHandle socket, uint8_t* buffer, uint32_t count, uint32_t* modified); @@ -215,8 +215,10 @@ ReturnCode Socket_Read(SocketHandle socket, uint8_t* buffer, uint32_t count, uin ReturnCode Socket_Write(SocketHandle socket, uint8_t* buffer, uint32_t count, uint32_t* modified); /* Attempts to close the given socket. */ ReturnCode Socket_Close(SocketHandle socket); -/* Attempts to poll the socket for reading or writing. */ -ReturnCode Socket_Select(SocketHandle socket, int selectMode, bool* success); +/* Attempts to poll the given socket for readability or writability. */ +/* NOTE: A closed socket is still considered readable. */ +/* NOTE: A socket is considered writable once it has finished connecting. */ +ReturnCode Socket_Poll(SocketHandle socket, int mode, bool* success); /* Initalises the platform specific http library state. */ void Http_Init(void); diff --git a/src/ServerConnection.c b/src/ServerConnection.c index b4fd7fa55..3e498891e 100644 --- a/src/ServerConnection.c +++ b/src/ServerConnection.c @@ -311,7 +311,7 @@ static void MPConnection_TickConnect(void) { if (res) { MPConnection_FailConnect(res); return; } now = DateTime_CurrentUTC_MS(); - Socket_Select(net_socket, SOCKET_SELECT_WRITE, &poll_write); + Socket_Poll(net_socket, SOCKET_POLL_WRITE, &poll_write); if (poll_write) { Socket_SetBlocking(net_socket, true); @@ -381,16 +381,17 @@ static void MPConnection_CheckDisconnection(double delta) { ReturnCode availRes, selectRes; uint32_t pending = 0; - bool poll_success; + bool poll_read; net_discAccumulator += delta; if (net_discAccumulator < 1.0) return; net_discAccumulator = 0.0; availRes = Socket_Available(net_socket, &pending); - selectRes = Socket_Select(net_socket, SOCKET_SELECT_READ, &poll_success); + /* poll read returns true when socket is closed */ + selectRes = Socket_Poll(net_socket, SOCKET_POLL_READ, &poll_read); - if (net_writeFailed || availRes || selectRes || (pending == 0 && poll_success)) { + if (net_writeFailed || availRes || selectRes || (pending == 0 && poll_read)) { Game_Disconnect(&title, &reason); } }