Simplify socket API a bit

This commit is contained in:
UnknownShadow200 2022-12-22 17:21:29 +11:00
parent 85bb75e1a6
commit 30406de3eb
7 changed files with 106 additions and 103 deletions

View File

@ -233,25 +233,24 @@ CC_API void Waitable_WaitFor(void* handle, cc_uint32 milliseconds);
/* Calls SysFonts_Register on each font that is available on this platform. */ /* Calls SysFonts_Register on each font that is available on this platform. */
void Platform_LoadSysFonts(void); void Platform_LoadSysFonts(void);
/* Returns how much data is available to be read from the given socket. */ /* Checks if data is available to be read from the given socket */
CC_API cc_result Socket_Available(cc_socket s, int* available); cc_result Socket_CheckAvailable(cc_socket s, int* available);
/* Returns (and resets) the last error generated by the given socket. */ /* Checks if the given socket is readable (i.e. has data available to read) */
CC_API cc_result Socket_GetError(cc_socket s, cc_result* result); /* NOTE: A closed socket is also considered readable */
/* Returns non-zero if the given address is valid for a socket to connect to */ cc_result Socket_CheckReadable(cc_socket s, cc_bool* readable);
CC_API int Socket_ValidAddress(const cc_string* address); /* Checks if the given socket is writable (i.e. has finished connecting) */
cc_result Socket_CheckWritable(cc_socket s, cc_bool* writable);
/* Returns non-zero if the given address is valid for a socket to connect to */
int Socket_ValidAddress(const cc_string* address);
/* Allocates a new non-blocking socket and then begins connecting to the given address:port. */ /* Allocates a new non-blocking socket and then begins connecting to the given address:port. */
CC_API cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port); cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port);
/* Attempts to read data from the given socket. */ /* Attempts to read data from the given socket. */
CC_API cc_result Socket_Read(cc_socket s, cc_uint8* data, cc_uint32 count, cc_uint32* modified); cc_result Socket_Read(cc_socket s, cc_uint8* data, cc_uint32 count, cc_uint32* modified);
/* Attempts to write data to the given socket. */ /* Attempts to write data to the given socket. */
CC_API cc_result Socket_Write(cc_socket s, const cc_uint8* data, cc_uint32 count, cc_uint32* modified); cc_result Socket_Write(cc_socket s, const cc_uint8* data, cc_uint32 count, cc_uint32* modified);
/* Attempts to close the given socket. */ /* Attempts to close the given socket. */
CC_API void Socket_Close(cc_socket s); void Socket_Close(cc_socket s);
/* 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. */
CC_API cc_result Socket_Poll(cc_socket s, int mode, cc_bool* success);
#ifdef CC_BUILD_MOBILE #ifdef CC_BUILD_MOBILE
void Platform_ShareScreenshot(const cc_string* filename); void Platform_ShareScreenshot(const cc_string* filename);

View File

@ -483,15 +483,6 @@ union SocketAddress {
struct sockaddr_in6 v6; struct sockaddr_in6 v6;
}; };
cc_result Socket_Available(cc_socket s, int* available) {
return ioctl(s, FIONREAD, available);
}
cc_result Socket_GetError(cc_socket s, cc_result* result) {
socklen_t resultSize = sizeof(cc_result);
return getsockopt(s, SOL_SOCKET, SO_ERROR, result, &resultSize);
}
static int ParseHost(union SocketAddress* addr, const char* host) { static int ParseHost(union SocketAddress* addr, const char* host) {
struct addrinfo hints = { 0 }; struct addrinfo hints = { 0 };
struct addrinfo* result; struct addrinfo* result;
@ -577,7 +568,7 @@ void Socket_Close(cc_socket s) {
#if defined CC_BUILD_DARWIN #if defined CC_BUILD_DARWIN
/* poll is broken on old OSX apparently https://daniel.haxx.se/docs/poll-vs-select.html */ /* poll is broken on old OSX apparently https://daniel.haxx.se/docs/poll-vs-select.html */
cc_result Socket_Poll(cc_socket s, int mode, cc_bool* success) { static cc_result Socket_Poll(cc_socket s, int mode, cc_bool* success) {
fd_set set; fd_set set;
struct timeval time = { 0 }; struct timeval time = { 0 };
int selectCount; int selectCount;
@ -596,7 +587,7 @@ cc_result Socket_Poll(cc_socket s, int mode, cc_bool* success) {
} }
#else #else
#include <poll.h> #include <poll.h>
cc_result Socket_Poll(cc_socket s, int mode, cc_bool* success) { static cc_result Socket_Poll(cc_socket s, int mode, cc_bool* success) {
struct pollfd pfd; struct pollfd pfd;
int flags; int flags;
@ -611,6 +602,24 @@ cc_result Socket_Poll(cc_socket s, int mode, cc_bool* success) {
} }
#endif #endif
cc_result Socket_CheckAvailable(cc_socket s, int* available) {
return ioctl(s, FIONREAD, available);
}
cc_result Socket_CheckReadable(cc_socket s, cc_bool* readable) {
return Socket_Poll(s, SOCKET_POLL_READ, readable);
}
cc_result Socket_CheckWritable(cc_socket s, cc_bool* writable) {
socklen_t resultSize;
cc_result res = Socket_Poll(s, SOCKET_POLL_WRITE, writable);
if (res || *writable) return res;
/* https://stackoverflow.com/questions/29479953/so-error-value-after-successful-socket-operation */
getsockopt(s, SOL_SOCKET, SO_ERROR, &res, &resultSize);
return res;
}
/*########################################################################################################################* /*########################################################################################################################*
*-----------------------------------------------------Process/Module------------------------------------------------------* *-----------------------------------------------------Process/Module------------------------------------------------------*

View File

@ -253,30 +253,7 @@ void Platform_LoadSysFonts(void) { }
*#########################################################################################################################*/ *#########################################################################################################################*/
extern void interop_InitSockets(void); extern void interop_InitSockets(void);
int Socket_ValidAddress(const cc_string* address) { return true; } int Socket_ValidAddress(const cc_string* address) { return true; }
extern int interop_SocketGetPending(int sock); extern int interop_SocketGetPending(int sock);
cc_result Socket_Available(cc_socket s, int* available) {
int res = interop_SocketGetPending(s);
/* returned result is negative for error */
if (res >= 0) {
*available = res; return 0;
} else {
*available = 0; return -res;
}
}
extern int interop_SocketGetError(int sock);
cc_result Socket_GetError(cc_socket s, cc_result* result) {
int res = interop_SocketGetError(s);
/* returned result is negative for error */
if (res >= 0) {
*result = res; return 0;
} else {
*result = 0; return -res;
}
}
extern int interop_SocketCreate(void); extern int interop_SocketCreate(void);
extern int interop_SocketConnect(int sock, const char* addr, int port); extern int interop_SocketConnect(int sock, const char* addr, int port);
@ -332,20 +309,29 @@ void Socket_Close(cc_socket s) {
interop_SocketClose(s); interop_SocketClose(s);
} }
extern int interop_SocketPoll(int sock); cc_result Socket_CheckAvailable(cc_socket s, int* available) {
cc_result Socket_Poll(cc_socket s, int mode, cc_bool* success) { int res = interop_SocketGetPending(s);
/* returned result is negative for error */ /* returned result is negative for error */
int res = interop_SocketPoll(s), flags;
if (res >= 0) { if (res >= 0) {
flags = mode == SOCKET_POLL_READ ? 0x01 : 0x02; *available = res; return 0;
*success = (res & flags) != 0;
return 0;
} else { } else {
*success = false; return -res; *available = 0; return -res;
} }
} }
extern int interop_SocketReadable(int sock, cc_bool* readable);
cc_result Socket_CheckReadable(cc_socket s, int mode, cc_bool* readable) {
/* returned result is negative for error */
return -interop_SocketReadable(s, readable);
}
extern int interop_SocketWritable(int sock, cc_bool* writable);
cc_result Socket_CheckWritable(cc_socket s, cc_bool* writable) {
/* returned result is negative for error */
return -interop_SocketWritable(s, writable);
}
/*########################################################################################################################* /*########################################################################################################################*
*-----------------------------------------------------Process/Module------------------------------------------------------* *-----------------------------------------------------Process/Module------------------------------------------------------*

View File

@ -453,15 +453,6 @@ static void LoadWinsockFuncs(void) {
if (!_WSAStringToAddressW) _WSAStringToAddressW = FallbackParseAddress; if (!_WSAStringToAddressW) _WSAStringToAddressW = FallbackParseAddress;
} }
cc_result Socket_Available(cc_socket s, int* available) {
return _ioctlsocket(s, FIONREAD, available);
}
cc_result Socket_GetError(cc_socket s, cc_result* result) {
int resultSize = sizeof(cc_result);
return _getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)result, &resultSize);
}
static int ParseHost(void* dst, WCHAR* host, int port) { static int ParseHost(void* dst, WCHAR* host, int port) {
SOCKADDR_IN* addr4 = (SOCKADDR_IN*)dst; SOCKADDR_IN* addr4 = (SOCKADDR_IN*)dst;
struct hostent* res; struct hostent* res;
@ -542,7 +533,7 @@ void Socket_Close(cc_socket s) {
_closesocket(s); _closesocket(s);
} }
cc_result Socket_Poll(cc_socket s, int mode, cc_bool* success) { static cc_result Socket_Poll(cc_socket s, int mode, cc_bool* success) {
fd_set set; fd_set set;
struct timeval time = { 0 }; struct timeval time = { 0 };
int selectCount; int selectCount;
@ -561,6 +552,25 @@ cc_result Socket_Poll(cc_socket s, int mode, cc_bool* success) {
*success = set.fd_count != 0; return 0; *success = set.fd_count != 0; return 0;
} }
cc_result Socket_CheckAvailable(cc_socket s, int* available) {
return _ioctlsocket(s, FIONREAD, available);
}
cc_result Socket_CheckReadable(cc_socket s, cc_bool* readable) {
return Socket_Poll(s, SOCKET_POLL_READ, readable);
}
cc_result Socket_CheckWritable(cc_socket s, cc_bool* writable) {
int resultSize;
cc_result res = Socket_Poll(s, SOCKET_POLL_WRITE, writable);
if (res || *writable) return res;
/* https://stackoverflow.com/questions/29479953/so-error-value-after-successful-socket-operation */
resultSize = sizeof(cc_result);
_getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&res, &resultSize);
return res;
}
/*########################################################################################################################* /*########################################################################################################################*
*-----------------------------------------------------Process/Module------------------------------------------------------* *-----------------------------------------------------Process/Module------------------------------------------------------*

View File

@ -76,9 +76,9 @@ static int RunProgram(int argc, char** argv) {
int argsCount = Platform_GetCommandLineArgs(argc, argv, args); int argsCount = Platform_GetCommandLineArgs(argc, argv, args);
#ifdef _MSC_VER #ifdef _MSC_VER
/* NOTE: Make sure to comment this out before pushing a commit */ /* NOTE: Make sure to comment this out before pushing a commit */
//cc_string rawArgs = String_FromConst("UnknownShadow200 fffff 127.0.0.1 25565"); cc_string rawArgs = String_FromConst("UnknownShadow200 fffff 127.0.0.1 25565");
//cc_string rawArgs = String_FromConst("UnknownShadow200"); //cc_string rawArgs = String_FromConst("UnknownShadow200");
//argsCount = String_UNSAFE_Split(&rawArgs, ' ', args, 4); argsCount = String_UNSAFE_Split(&rawArgs, ' ', args, 4);
#endif #endif
if (argsCount == 0) { if (argsCount == 0) {

View File

@ -116,7 +116,6 @@ cc_string SP_AutoloadMap = String_FromArray(autoloadBuffer);
static void SPConnection_BeginConnect(void) { static void SPConnection_BeginConnect(void) {
static const cc_string logName = String_FromConst("Singleplayer"); static const cc_string logName = String_FromConst("Singleplayer");
cc_string path;
RNGState rnd; RNGState rnd;
Chat_SetLogName(&logName); Chat_SetLogName(&logName);
Game_UseCPEBlocks = Game_UseCPE; Game_UseCPEBlocks = Game_UseCPE;
@ -214,7 +213,7 @@ static cc_uint8 net_readBuffer[4096 * 5];
static cc_uint8* net_readCurrent; static cc_uint8* net_readCurrent;
static cc_result net_writeFailure; static cc_result net_writeFailure;
static double lastPacket; static double net_lastPacket;
static cc_uint8 lastOpcode; static cc_uint8 lastOpcode;
static cc_bool net_connecting; static cc_bool net_connecting;
@ -228,8 +227,8 @@ static void MPConnection_FinishConnect(void) {
Event_RaiseFloat(&WorldEvents.Loading, 0.0f); Event_RaiseFloat(&WorldEvents.Loading, 0.0f);
net_readCurrent = net_readBuffer; net_readCurrent = net_readBuffer;
net_lastPacket = Game.Time;
Classic_SendLogin(); Classic_SendLogin();
lastPacket = Game.Time;
} }
static void MPConnection_Fail(const cc_string* reason) { static void MPConnection_Fail(const cc_string* reason) {
@ -255,17 +254,13 @@ static void MPConnection_FailConnect(cc_result result) {
} }
static void MPConnection_TickConnect(void) { static void MPConnection_TickConnect(void) {
cc_result res = 0; cc_bool writable;
cc_bool poll_write; double now = Game.Time;
double now; cc_result res = Socket_CheckWritable(net_socket, &writable);
Socket_GetError(net_socket, &res); if (res) {
if (res) { MPConnection_FailConnect(res); return; } MPConnection_FailConnect(res);
} else if (writable) {
Socket_Poll(net_socket, SOCKET_POLL_WRITE, &poll_write);
now = Game.Time;
if (poll_write) {
MPConnection_FinishConnect(); MPConnection_FinishConnect();
} else if (now > net_connectTimeout) { } else if (now > net_connectTimeout) {
MPConnection_FailConnect(0); MPConnection_FailConnect(0);
@ -332,15 +327,16 @@ static void MPConnection_Disconnect(void) {
} }
static void MPConnection_CheckDisconnection(void) { static void MPConnection_CheckDisconnection(void) {
cc_result availRes, selectRes; cc_result readableRes;
int pending = 0; cc_bool readable;
cc_bool poll_read;
availRes = Socket_Available(net_socket, &pending); /* poll read returns true when either: */
/* poll read returns true when socket is closed */ /* a) data is available to read */
selectRes = Socket_Poll(net_socket, SOCKET_POLL_READ, &poll_read); /* b) socket is closed */
/* since a) is already handled in MPConnection_Tick, this only handles b) */
readableRes = Socket_CheckReadable(net_socket, &readable);
if (net_writeFailure || availRes || selectRes || (pending == 0 && poll_read)) { if (net_writeFailure || readableRes || readable) {
MPConnection_Disconnect(); MPConnection_Disconnect();
} }
} }
@ -367,12 +363,12 @@ static void MPConnection_Tick(struct ScheduledTask* task) {
if (Server.Disconnected) return; if (Server.Disconnected) return;
if (net_connecting) { MPConnection_TickConnect(); return; } if (net_connecting) { MPConnection_TickConnect(); return; }
/* Over 30 seconds since last packet, connection likely dropped */ /* Over 30 seconds since last packet, connection probably dropped */
if (lastPacket + 30 < Game.Time) MPConnection_CheckDisconnection(); if (net_lastPacket + 30 < Game.Time) MPConnection_CheckDisconnection();
if (Server.Disconnected) return; if (Server.Disconnected) return;
pending = 0; pending = 0;
res = Socket_Available(net_socket, &pending); res = Socket_CheckAvailable(net_socket, &pending);
readEnd = net_readCurrent; /* todo change to int remaining instead */ readEnd = net_readCurrent; /* todo change to int remaining instead */
if (!res && pending) { if (!res && pending) {
@ -383,7 +379,9 @@ static void MPConnection_Tick(struct ScheduledTask* task) {
if (res == ReturnCode_SocketInProgess) return; if (res == ReturnCode_SocketInProgess) return;
if (res == ReturnCode_SocketWouldBlock) return; if (res == ReturnCode_SocketWouldBlock) return;
} }
readEnd += pending; readEnd += pending;
net_lastPacket = Game.Time;
} }
if (res) { if (res) {
@ -412,7 +410,6 @@ static void MPConnection_Tick(struct ScheduledTask* task) {
if (!handler) { DisconnectInvalidOpcode(opcode); return; } if (!handler) { DisconnectInvalidOpcode(opcode); return; }
lastOpcode = opcode; lastOpcode = opcode;
lastPacket = Game.Time;
handler(net_readCurrent + 1); /* skip opcode */ handler(net_readCurrent + 1); /* skip opcode */
net_readCurrent += Protocol.Sizes[opcode]; net_readCurrent += Protocol.Sizes[opcode];
} }

View File

@ -537,7 +537,7 @@ mergeInto(LibraryManager.library, {
}, },
interop_SocketCreate: function() { interop_SocketCreate: function() {
var sock = { var sock = {
error: null, // Used by interop_SocketGetError error: null, // Used by interop_SocketWritable
recv_queue: [], recv_queue: [],
socket: null, socket: null,
}; };
@ -593,7 +593,7 @@ mergeInto(LibraryManager.library, {
ws.onerror = function(error) { ws.onerror = function(error) {
// The WebSocket spec only allows a 'simple event' to be thrown on error, // The WebSocket spec only allows a 'simple event' to be thrown on error,
// so we only really know as much as ECONNREFUSED. // so we only really know as much as ECONNREFUSED.
sock.error = -SOCKETS.ECONNREFUSED; // Used by interop_SocketGetError sock.error = SOCKETS.ECONNREFUSED; // Used by interop_SocketWritable
}; };
// always "fail" in non-blocking mode // always "fail" in non-blocking mode
return SOCKETS.EINPROGRESS; return SOCKETS.EINPROGRESS;
@ -673,23 +673,25 @@ mergeInto(LibraryManager.library, {
return sock.recv_queue.length; return sock.recv_queue.length;
}, },
interop_SocketGetError: function(sockFD) { interop_SocketReadable: function(sockFD, readable) {
HEAPU8[readable|0] = 0;
var sock = SOCKETS.sockets[sockFD]; var sock = SOCKETS.sockets[sockFD];
if (!sock) return SOCKETS.EBADF; if (!sock) return SOCKETS.EBADF;
return sock.error || 0; var ws = sock.socket;
if (!ws) return SOCKETS.ENOTCONN;
if (sock.recv_queue.length || (ws.readyState === ws.CLOSING || ws.readyState === ws.CLOSED)) HEAPU8[readable|0] = 1
return 0;
}, },
interop_SocketPoll: function(sockFD) { interop_SocketWritable: function(sockFD, writable) {
HEAPU8[writable|0] = 0;
var sock = SOCKETS.sockets[sockFD]; var sock = SOCKETS.sockets[sockFD];
if (!sock) return SOCKETS.EBADF; if (!sock) return SOCKETS.EBADF;
var ws = sock.socket; var ws = sock.socket;
if (!ws) return 0; if (!ws) return SOCKETS.ENOTCONN;
var mask = 0; if (ws.readyState === ws.OPEN) HEAPU8[writable|0] = 1;
return sock.error || 0;
if (sock.recv_queue.length || (ws.readyState === ws.CLOSING || ws.readyState === ws.CLOSED)) mask |= 1;
if (ws.readyState === ws.OPEN) mask |= 2;
return mask;
}, },