From 4e05f3626fdd2e102cd8913908bf7b522419c1dd Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 23 Dec 2023 23:29:59 +1100 Subject: [PATCH] Move consoles to use new socket parsing API, also improve PS3 input support 3DS seems to be broken though, not sure why yet --- src/ClassiCube.vcxproj | 3 ++ src/ClassiCube.vcxproj.filters | 9 ++++ src/Graphics_GL1.c | 2 +- src/Graphics_PS2.c | 2 +- src/Http_Worker.c | 4 +- src/Platform.h | 4 +- src/Platform_3DS.c | 78 +++++++++++++-------------- src/Platform_Dreamcast.c | 82 +++++++++------------------- src/Platform_GCWii.c | 65 +++++++++++++---------- src/Platform_N64.c | 6 +-- src/Platform_PS2.c | 69 ++++++++++++------------ src/Platform_PS3.c | 62 +++++++++++++--------- src/Platform_PSP.c | 57 +++++++++----------- src/Platform_PSVita.c | 57 +++++++++----------- src/Platform_Posix.c | 97 +++++++++++++++++++--------------- src/Platform_Web.c | 6 +-- src/Platform_Windows.c | 26 +++++---- src/Platform_Xbox.c | 65 ++++++++--------------- src/Platform_Xbox360.c | 6 +-- src/Server.c | 4 +- src/Window_PS3.c | 33 ++++++++++-- 21 files changed, 362 insertions(+), 375 deletions(-) diff --git a/src/ClassiCube.vcxproj b/src/ClassiCube.vcxproj index c646dba04..39539976a 100644 --- a/src/ClassiCube.vcxproj +++ b/src/ClassiCube.vcxproj @@ -480,6 +480,7 @@ + @@ -507,6 +508,7 @@ + @@ -550,6 +552,7 @@ + diff --git a/src/ClassiCube.vcxproj.filters b/src/ClassiCube.vcxproj.filters index 5721985b0..86b40ac23 100644 --- a/src/ClassiCube.vcxproj.filters +++ b/src/ClassiCube.vcxproj.filters @@ -704,6 +704,15 @@ Source Files\Game + + Source Files\Platform + + + Source Files\Window + + + Source Files\Graphics + diff --git a/src/Graphics_GL1.c b/src/Graphics_GL1.c index 2ba114a1f..cbaca73ba 100644 --- a/src/Graphics_GL1.c +++ b/src/Graphics_GL1.c @@ -31,7 +31,7 @@ typedef unsigned int GLuint; typedef float GLfloat; typedef void GLvoid; -/* NOTE: With the OpenGL 1.1 backend "pointer" arguments are actual pointers, +/* NOTE: With the OpenGL 1.1 backend "pointer" arguments are actual pointers, */ /* but with VBOs they are just offsets instead */ #ifdef CC_BUILD_GL11 typedef const void* GLpointer; diff --git a/src/Graphics_PS2.c b/src/Graphics_PS2.c index f51f28dc6..429619bfe 100644 --- a/src/Graphics_PS2.c +++ b/src/Graphics_PS2.c @@ -450,7 +450,7 @@ void Gfx_SetVertexFormat(VertexFormat fmt) { // TODO update cached primitive state } -typedef struct Vector4 { float X, Y, Z, W; } Vector4; +typedef struct Vector4 { float x, y, z, w; } Vector4; static cc_bool NotClipped(Vector4 pos) { // The code below clips to the viewport clip planes diff --git a/src/Http_Worker.c b/src/Http_Worker.c index aa5b27b56..1678fc3dc 100644 --- a/src/Http_Worker.c +++ b/src/Http_Worker.c @@ -517,7 +517,7 @@ static cc_result HttpConnection_Open(struct HttpConnection* conn, const struct H cc_uint16 portNum; cc_result res; cc_sockaddr addrs[SOCKET_MAX_ADDRS]; - int numAddrs; + int numValidAddrs; /* address can be either "host" or "host:port" */ String_UNSAFE_Separate(&url->address, ':', &host, &port); @@ -527,7 +527,7 @@ static cc_result HttpConnection_Open(struct HttpConnection* conn, const struct H conn->socket = -1; conn->sslCtx = NULL; - if ((res = Socket_ParseAddress(&host, portNum, addrs, &numAddrs))) return res; + if ((res = Socket_ParseAddress(&host, portNum, addrs, &numValidAddrs))) return res; /* TODO multi addresses support */ if ((res = Socket_Connect(&conn->socket, &addrs[0], false))) return res; diff --git a/src/Platform.h b/src/Platform.h index 952e15e61..087071ef8 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -243,7 +243,7 @@ CC_API void Waitable_WaitFor(void* handle, cc_uint32 milliseconds); void Platform_LoadSysFonts(void); #define CC_SOCKETADDR_MAXSIZE 512 -#define SOCKET_MAX_ADDRS 5 +#define SOCKET_MAX_ADDRS 8 typedef struct cc_sockaddr_ { int size; /* Actual size of the raw socket address */ @@ -257,7 +257,7 @@ cc_result Socket_CheckReadable(cc_socket s, cc_bool* readable); cc_result Socket_CheckWritable(cc_socket s, cc_bool* writable); /* If the input represents an IP address, then parses the input into a single IP address */ /* Otherwise, attempts to resolve the input via DNS into one or more IP addresses */ -cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* addrs, int* numAddrs); +cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* addrs, int* numValidAddrs); /* Allocates a new socket and then begins connecting to the given address */ cc_result Socket_Connect(cc_socket* s, cc_sockaddr* addr, cc_bool nonblocking); diff --git a/src/Platform_3DS.c b/src/Platform_3DS.c index 7b6dd9100..878acfb13 100644 --- a/src/Platform_3DS.c +++ b/src/Platform_3DS.c @@ -285,59 +285,60 @@ void Waitable_WaitFor(void* handle, cc_uint32 milliseconds) { /*########################################################################################################################* *---------------------------------------------------------Socket----------------------------------------------------------* *#########################################################################################################################*/ -union SocketAddress { - struct sockaddr raw; - struct sockaddr_in v4; - struct sockaddr_storage total; // matches max size of addr returned by getaddrinfo -}; - -static int ParseHost(union SocketAddress* addr, const char* host) { +cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* addrs, int* numValidAddrs) { + char str[NATIVE_STR_LEN]; + char portRaw[32]; cc_string portStr; struct addrinfo hints = { 0 }; struct addrinfo* result; struct addrinfo* cur; - int found = false; + int i = 0; + + String_EncodeUtf8(str, address); + *numValidAddrs = 0; + struct sockaddr_in* addr4 = (struct sockaddr_in*)addrs[0].data; + if (inet_aton(str, &addr4->sin_addr) > 0) { + // TODO have to have this path, otherwise Citra crashes when crashing connecting to server if you always use getaddrinfo instead + // Need to investigate further as I'm probably doing something wrong + // TODO still doesn't work + + addr4->sin_family = AF_INET; + addr4->sin_port = htons(port); + + addrs[0].size = sizeof(*addr4); + *numValidAddrs = 1; + return 0; + } - hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; + + String_InitArray(portStr, portRaw); + String_AppendInt(&portStr, port); + portRaw[portStr.length] = '\0'; - int res = getaddrinfo(host, NULL, &hints, &result); + int res = getaddrinfo(str, portRaw, &hints, &result); if (res == -NO_DATA) return SOCK_ERR_UNKNOWN_HOST; if (res) return res; - for (cur = result; cur; cur = cur->ai_next) { - if (cur->ai_family != AF_INET) continue; - found = true; - - Mem_Copy(addr, cur->ai_addr, cur->ai_addrlen); - break; + for (cur = result; cur && i < SOCKET_MAX_ADDRS; cur = cur->ai_next, i++) + { + if (!cur->ai_addrlen) break; + // TODO citra returns empty addresses past first one? does that happen on real hardware too? + + Mem_Copy(addrs[i].data, cur->ai_addr, cur->ai_addrlen); + addrs[i].size = cur->ai_addrlen; } freeaddrinfo(result); - return found ? 0 : ERR_INVALID_ARGUMENT; + *numValidAddrs = i; + return i == 0 ? ERR_INVALID_ARGUMENT : 0; } -static int ParseAddress(union SocketAddress* addr, const cc_string* address) { - char str[NATIVE_STR_LEN]; - String_EncodeUtf8(str, address); - - if (inet_pton(AF_INET, str, &addr->v4.sin_addr) > 0) return 0; - return ParseHost(addr, str); -} - -int Socket_ValidAddress(const cc_string* address) { - union SocketAddress addr; - return ParseAddress(&addr, address) == 0; -} - -cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bool nonblocking) { - union SocketAddress addr; +cc_result Socket_Connect(cc_socket* s, cc_sockaddr* addr, cc_bool nonblocking) { + struct sockaddr* raw = (struct sockaddr*)addr->data; int res; - *s = -1; - if ((res = ParseAddress(&addr, address))) return res; - - *s = socket(AF_INET, SOCK_STREAM, 0); // https://www.3dbrew.org/wiki/SOCU:socket + *s = socket(raw->sa_family, SOCK_STREAM, 0); // https://www.3dbrew.org/wiki/SOCU:socket if (*s == -1) return errno; if (nonblocking) { @@ -345,10 +346,7 @@ cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bo if (flags >= 0) fcntl(*s, F_SETFL, flags | O_NONBLOCK); } - addr.v4.sin_family = AF_INET; - addr.v4.sin_port = htons(port); - - res = connect(*s, &addr.raw, sizeof(addr.v4)); + res = connect(*s, raw, addr->size); return res == -1 ? errno : 0; } diff --git a/src/Platform_Dreamcast.c b/src/Platform_Dreamcast.c index 041e92390..7f30a741e 100644 --- a/src/Platform_Dreamcast.c +++ b/src/Platform_Dreamcast.c @@ -284,86 +284,52 @@ void Waitable_WaitFor(void* handle, cc_uint32 milliseconds) { /*########################################################################################################################* *---------------------------------------------------------Socket----------------------------------------------------------* *#########################################################################################################################*/ -union SocketAddress { - struct sockaddr raw; - struct sockaddr_in v4; - #ifdef AF_INET6 - struct sockaddr_in6 v6; - struct sockaddr_storage total; - #endif -}; +cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* addrs, int* numValidAddrs) { + char str[NATIVE_STR_LEN]; -static int ParseHost(union SocketAddress* addr, const char* host) { + char portRaw[32]; cc_string portStr; struct addrinfo hints = { 0 }; struct addrinfo* result; struct addrinfo* cur; - int family = 0, res; + int res, i = 0; + + String_EncodeUtf8(str, address); + *numValidAddrs = 0; - hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; + + String_InitArray(portStr, portRaw); + String_AppendInt(&portStr, port); + portRaw[portStr.length] = '\0'; - res = getaddrinfo(host, NULL, &hints, &result); - if (res) return 0; + res = getaddrinfo(str, portRaw, &hints, &result); + if (res == EAI_NONAME) return SOCK_ERR_UNKNOWN_HOST; + if (res) return res; - for (cur = result; cur; cur = cur->ai_next) { - if (cur->ai_family != AF_INET) continue; - family = AF_INET; - - Mem_Copy(addr, cur->ai_addr, cur->ai_addrlen); - break; + for (cur = result; cur && i < SOCKET_MAX_ADDRS; cur = cur->ai_next, i++) + { + Mem_Copy(addrs[i].data, cur->ai_addr, cur->ai_addrlen); + addrs[i].size = cur->ai_addrlen; } freeaddrinfo(result); - return family; + *numValidAddrs = i; + return i == 0 ? ERR_INVALID_ARGUMENT : 0; } -static int ParseAddress(union SocketAddress* addr, const cc_string* address) { - char str[NATIVE_STR_LEN]; - String_EncodeUtf8(str, address); - - if (inet_pton(AF_INET, str, &addr->v4.sin_addr) > 0) return AF_INET; - #ifdef AF_INET6 - if (inet_pton(AF_INET6, str, &addr->v6.sin6_addr) > 0) return AF_INET6; - #endif - return ParseHost(addr, str); -} - -int Socket_ValidAddress(const cc_string* address) { - union SocketAddress addr; - return ParseAddress(&addr, address); -} - -cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bool nonblocking) { - int family, addrSize = 0; - union SocketAddress addr; +cc_result Socket_Connect(cc_socket* s, cc_sockaddr* addr, cc_bool nonblocking) { + struct sockaddr* raw = (struct sockaddr*)addr->data; cc_result res; - *s = -1; - if (!(family = ParseAddress(&addr, address))) - return ERR_INVALID_ARGUMENT; - - *s = socket(family, SOCK_STREAM, IPPROTO_TCP); + *s = socket(raw->sa_family, SOCK_STREAM, IPPROTO_TCP); if (*s == -1) return errno; if (nonblocking) { fcntl(*s, F_SETFL, O_NONBLOCK); } - #ifdef AF_INET6 - if (family == AF_INET6) { - addr.v6.sin6_family = AF_INET6; - addr.v6.sin6_port = htons(port); - addrSize = sizeof(addr.v6); - } - #endif - if (family == AF_INET) { - addr.v4.sin_family = AF_INET; - addr.v4.sin_port = htons(port); - addrSize = sizeof(addr.v4); - } - - res = connect(*s, &addr.raw, addrSize); + res = connect(*s, raw, addr->size); return res == -1 ? errno : 0; } diff --git a/src/Platform_GCWii.c b/src/Platform_GCWii.c index 9ef07f9e6..1d3d7a42c 100644 --- a/src/Platform_GCWii.c +++ b/src/Platform_GCWii.c @@ -360,51 +360,61 @@ void Waitable_WaitFor(void* handle, cc_uint32 milliseconds) { /*########################################################################################################################* *---------------------------------------------------------Socket----------------------------------------------------------* *#########################################################################################################################*/ -union SocketAddress { - struct sockaddr raw; - struct sockaddr_in v4; -}; - -static int ParseHost(union SocketAddress* addr, const char* host) { +static cc_result ParseHost(const char* host, int port, cc_sockaddr* addrs, int* numValidAddrs) { #ifdef HW_RVL struct hostent* res = net_gethostbyname(host); + struct sockaddr_in* addr4; + char* src_addr; + int i; + // avoid confusion with SSL error codes // e.g. FFFF FFF7 > FF00 FFF7 if (!res) return -0xFF0000 + errno; // Must have at least one IPv4 address if (res->h_addrtype != AF_INET) return ERR_INVALID_ARGUMENT; - if (!res->h_addr_list[0]) return ERR_INVALID_ARGUMENT; + if (!res->h_addr_list) return ERR_INVALID_ARGUMENT; - addr->v4.sin_addr = *(struct in_addr*)res->h_addr_list[0]; - return 0; + for (i = 0; i < SOCKET_MAX_ADDRS; i++) + { + src_addr = res->h_addr_list[i]; + if (!src_addr) break; + addrs[i].size = sizeof(struct sockaddr_in); + + addr4 = (struct sockaddr_in*)addrs[i].data; + addr4->sin_family = AF_INET; + addr4->sin_port = htons(port); + addr4->sin_addr = *(struct in_addr*)src_addr; + } + + *numValidAddrs = i; + return i == 0 ? ERR_INVALID_ARGUMENT : 0; #else // DNS resolution not implemented in gamecube libbba return ERR_NOT_SUPPORTED; #endif } - -static int ParseAddress(union SocketAddress* addr, const cc_string* address) { +cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* addrs, int* numValidAddrs) { + struct sockaddr_in* addr4 = (struct sockaddr_in*)addrs[0].data; char str[NATIVE_STR_LEN]; String_EncodeUtf8(str, address); - - if (inet_aton(str, &addr->v4.sin_addr) > 0) return 0; - return ParseHost(addr, str); + *numValidAddrs = 1; + if (inet_aton(str, &addr4->sin_addr) > 0) { + addr4->sin_family = AF_INET; + addr4->sin_port = htons(port); + + addrs[0].size = sizeof(*addr4); + return 0; + } + + return ParseHost(str, port, addrs, numValidAddrs); } -int Socket_ValidAddress(const cc_string* address) { - union SocketAddress addr; - return ParseAddress(&addr, address) == 0; -} - -cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bool nonblocking) { - union SocketAddress addr; +cc_result Socket_Connect(cc_socket* s, cc_sockaddr* addr, cc_bool nonblocking) { + struct sockaddr* raw = (struct sockaddr*)addr->data; int res; - *s = -1; - if ((res = ParseAddress(&addr, address))) return res; - - *s = net_socket(AF_INET, SOCK_STREAM, 0); + *s = net_socket(raw->sa_family, SOCK_STREAM, 0); if (*s < 0) return *s; if (nonblocking) { @@ -412,10 +422,7 @@ cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bo net_ioctl(*s, FIONBIO, &blocking_raw); } - addr.v4.sin_family = AF_INET; - addr.v4.sin_port = htons(port); - - res = net_connect(*s, &addr.raw, sizeof(addr.v4)); + res = net_connect(*s, raw, addr->size); return res < 0 ? res : 0; } diff --git a/src/Platform_N64.c b/src/Platform_N64.c index 85f759ea6..ff8b2c913 100644 --- a/src/Platform_N64.c +++ b/src/Platform_N64.c @@ -219,11 +219,11 @@ void Waitable_WaitFor(void* handle, cc_uint32 milliseconds) { /*########################################################################################################################* *---------------------------------------------------------Socket----------------------------------------------------------* *#########################################################################################################################*/ -int Socket_ValidAddress(const cc_string* address) { - return false; +cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* addrs, int* numValidAddrs) { + return ERR_NOT_SUPPORTED; } -cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bool nonblocking) { +cc_result Socket_Connect(cc_socket* s, cc_sockaddr* addr, cc_bool nonblocking) { return ERR_NOT_SUPPORTED; } diff --git a/src/Platform_PS2.c b/src/Platform_PS2.c index a28823a7d..56102147d 100644 --- a/src/Platform_PS2.c +++ b/src/Platform_PS2.c @@ -460,49 +460,52 @@ static void Networking_LoadIOPModules(void) { /*########################################################################################################################* *---------------------------------------------------------Socket----------------------------------------------------------* *#########################################################################################################################*/ -union SocketAddress { - struct sockaddr raw; - struct sockaddr_in v4; - struct sockaddr_storage total; // matches max size of addr returned by getaddrinfo -}; - -static int ParseHost(union SocketAddress* addr, const char* host) { +static cc_result ParseHost(const char* host, int port, cc_sockaddr* addrs, int* numValidAddrs) { + char portRaw[32]; cc_string portStr; struct addrinfo hints = { 0 }; struct addrinfo* result; struct addrinfo* cur; - int found = false; + int res, i = 0; - hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; + + String_InitArray(portStr, portRaw); + String_AppendInt(&portStr, port); + portRaw[portStr.length] = '\0'; - int res = getaddrinfo(host, NULL, &hints, &result); + res = getaddrinfo(host, portRaw, &hints, &result); if (res == -NO_DATA) return SOCK_ERR_UNKNOWN_HOST; if (res) return res; - for (cur = result; cur; cur = cur->ai_next) { - if (cur->ai_family != AF_INET) continue; - found = true; - - Mem_Copy(addr, cur->ai_addr, cur->ai_addrlen); - break; + for (cur = result; cur && i < SOCKET_MAX_ADDRS; cur = cur->ai_next, i++) + { + Mem_Copy(addrs[i].data, cur->ai_addr, cur->ai_addrlen); + addrs[i].size = cur->ai_addrlen; } - + freeaddrinfo(result); - return found ? 0 : ERR_INVALID_ARGUMENT; + *numValidAddrs = i; + return i == 0 ? ERR_INVALID_ARGUMENT : 0; } -static int ParseAddress(union SocketAddress* addr, const cc_string* address) { +cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* addrs, int* numValidAddrs) { + struct sockaddr_in* addr4 = (struct sockaddr_in*)addrs[0].data; char str[NATIVE_STR_LEN]; + String_EncodeUtf8(str, address); + *numValidAddrs = 0; - if (inet_aton(str, &addr->v4.sin_addr) > 0) return 0; - return ParseHost(addr, str); -} - -int Socket_ValidAddress(const cc_string* address) { - union SocketAddress addr; - return ParseAddress(&addr, address) == 0; + if (inet_aton(str, &addr4->sin_addr) > 0) { + addr4->sin_family = AF_INET; + addr4->sin_port = htons(port); + + addrs[0].size = sizeof(*addr4); + *numValidAddrs = 1; + return 0; + } + + return ParseHost(str, port, addrs, numValidAddrs); } static cc_result GetSocketError(cc_socket s) { @@ -512,14 +515,11 @@ static cc_result GetSocketError(cc_socket s) { return res; } -cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bool nonblocking) { - union SocketAddress addr; +cc_result Socket_Connect(cc_socket* s, cc_sockaddr* addr, cc_bool nonblocking) { + struct sockaddr* raw = (struct sockaddr*)addr->data; int res; - *s = -1; - if ((res = ParseAddress(&addr, address))) return res; - - *s = socket(AF_INET, SOCK_STREAM, 0); + *s = socket(raw->sa_family, SOCK_STREAM, 0); if (*s < 0) return *s; if (nonblocking) { @@ -527,10 +527,7 @@ cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bo //ioctlsocket(*s, FIONBIO, &blocking_raw); TODO doesn't work } - addr.v4.sin_family = AF_INET; - addr.v4.sin_port = htons(port); - - res = connect(*s, &addr.raw, sizeof(addr.v4)); + res = connect(*s, raw, addr->size); return res == -1 ? GetSocketError(*s) : 0; } diff --git a/src/Platform_PS3.c b/src/Platform_PS3.c index aee2e7840..6fddd2265 100644 --- a/src/Platform_PS3.c +++ b/src/Platform_PS3.c @@ -339,44 +339,57 @@ union SocketAddress { struct sockaddr raw; struct sockaddr_in v4; }; - -static int ParseHost(union SocketAddress* addr, const char* host) { +static cc_result ParseHost(char* host, int port, cc_sockaddr* addrs, int* numValidAddrs) { struct net_hostent* res = netGetHostByName(host); + struct sockaddr_in* addr4; if (!res) return net_h_errno; // Must have at least one IPv4 address if (res->h_addrtype != AF_INET) return ERR_INVALID_ARGUMENT; if (!res->h_addr_list) return ERR_INVALID_ARGUMENT; - u32* addrlist = (u32*)res->h_addr_list; - char* addr0 = (char*)addrlist[0]; - - addr->v4.sin_addr = *(struct in_addr*)addr0; - return 0; + // each address pointer is only 4 bytes long + u32* addr_list = (u32*)res->h_addr_list; + char* src_addr; + int i; + + for (i = 0; i < SOCKET_MAX_ADDRS; i++) + { + src_addr = (char*)addr_list[i]; + if (!src_addr) break; + addrs[i].size = sizeof(struct sockaddr_in); + addr4 = (struct sockaddr_in*)addrs[i].data; + addr4->sin_family = AF_INET; + addr4->sin_port = htons(port); + addr4->sin_addr = *(struct in_addr*)src_addr; + } + *numValidAddrs = i; + return i == 0 ? ERR_INVALID_ARGUMENT : 0; } -static int ParseAddress(union SocketAddress* addr, const cc_string* address) { +cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* addrs, int* numValidAddrs) { + struct sockaddr_in* addr4 = (struct sockaddr_in*)addrs[0].data; char str[NATIVE_STR_LEN]; String_EncodeUtf8(str, address); + *numValidAddrs = 0; - if (inet_aton(str, &addr->v4.sin_addr) > 0) return 0; - return ParseHost(addr, str); + if (inet_aton(str, &addr4->sin_addr) > 0) { + addr4->sin_family = AF_INET; + addr4->sin_port = htons(port); + + addrs[0].size = sizeof(*addr4); + *numValidAddrs = 1; + return 0; + } + + return ParseHost(str, port, addrs, numValidAddrs); } -int Socket_ValidAddress(const cc_string* address) { - union SocketAddress addr; - return ParseAddress(&addr, address) == 0; -} - -cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bool nonblocking) { - union SocketAddress addr; +cc_result Socket_Connect(cc_socket* s, cc_sockaddr* addr, cc_bool nonblocking) { + struct sockaddr* raw = (struct sockaddr*)addr->data; int res; - *s = -1; - res = ParseAddress(&addr, address); - if (res) return res; - - res = netSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + res = netSocket(raw->sa_family, SOCK_STREAM, IPPROTO_TCP); if (res < 0) return net_errno; *s = res; @@ -385,10 +398,7 @@ cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bo netSetSockOpt(*s, SOL_SOCKET, SO_NBIO, &on, sizeof(int)); } - addr.v4.sin_family = AF_INET; - addr.v4.sin_port = htons(port); - - res = netConnect(*s, &addr.raw, sizeof(addr.v4)); + res = netConnect(*s, raw, addr->size); return res < 0 ? net_errno : 0; } diff --git a/src/Platform_PSP.c b/src/Platform_PSP.c index a0297283c..9df19eabf 100644 --- a/src/Platform_PSP.c +++ b/src/Platform_PSP.c @@ -292,54 +292,45 @@ void Waitable_WaitFor(void* handle, cc_uint32 milliseconds) { /*########################################################################################################################* *---------------------------------------------------------Socket----------------------------------------------------------* *#########################################################################################################################*/ -union SocketAddress { - struct sockaddr raw; - struct sockaddr_in v4; -}; - -static int ParseHost(union SocketAddress* addr, const char* host) { +cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* addrs, int* numValidAddrs) { + struct sockaddr_in* addr4 = (struct sockaddr_in*)addrs[0].data; + char str[NATIVE_STR_LEN]; char buf[1024]; int rid, ret; - - if (sceNetResolverCreate(&rid, buf, sizeof(buf)) < 0) return 0; - - ret = sceNetResolverStartNtoA(rid, host, &addr->v4.sin_addr, 1 /* timeout */, 5 /* retries */); - sceNetResolverDelete(rid); - return ret >= 0; -} - -static int ParseAddress(union SocketAddress* addr, const cc_string* address) { - char str[NATIVE_STR_LEN]; + String_EncodeUtf8(str, address); + *numValidAddrs = 1; - if (sceNetInetInetPton(AF_INET,str, &addr->v4.sin_addr) > 0) return true; - return ParseHost(addr, str); + if (sceNetInetInetPton(AF_INET, str, &addr4->sin_addr) <= 0) { + /* Fallback to resolving as DNS name */ + if (sceNetResolverCreate(&rid, buf, sizeof(buf)) < 0) + return ERR_INVALID_ARGUMENT; + + ret = sceNetResolverStartNtoA(rid, str, &addr4->sin_addr, 1 /* timeout */, 5 /* retries */); + sceNetResolverDelete(rid); + if (ret < 0) return ret; + } + + addr4->sin_family = AF_INET; + addr4->sin_port = htons(port); + + addrs[0].size = sizeof(*addr4); + return 0; } -int Socket_ValidAddress(const cc_string* address) { - union SocketAddress addr; - return ParseAddress(&addr, address); -} - -cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bool nonblocking) { - union SocketAddress addr; +cc_result Socket_Connect(cc_socket* s, cc_sockaddr* addr, cc_bool nonblocking) { + struct sockaddr* raw = (struct sockaddr*)addr->data; int res; - *s = -1; - if (!ParseAddress(&addr, address)) return ERR_INVALID_ARGUMENT; - - *s = sceNetInetSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + *s = sceNetInetSocket(raw->sa_family, SOCK_STREAM, IPPROTO_TCP); if (*s < 0) return sceNetInetGetErrno(); if (nonblocking) { int on = 1; sceNetInetSetsockopt(*s, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(int)); } - - addr.v4.sin_family = AF_INET; - addr.v4.sin_port = htons(port); - res = sceNetInetConnect(*s, &addr.raw, sizeof(addr.v4)); + res = sceNetInetConnect(*s, raw, addr->size); return res < 0 ? sceNetInetGetErrno() : 0; } diff --git a/src/Platform_PSVita.c b/src/Platform_PSVita.c index 46bb15047..ac82c0401 100644 --- a/src/Platform_PSVita.c +++ b/src/Platform_PSVita.c @@ -280,52 +280,45 @@ void Waitable_WaitFor(void* handle, cc_uint32 milliseconds) { /*########################################################################################################################* *---------------------------------------------------------Socket----------------------------------------------------------* *#########################################################################################################################*/ -union SocketAddress { - struct SceNetSockaddr raw; - struct SceNetSockaddrIn v4; -}; - -static int ParseHost(union SocketAddress* addr, const char* host) { - int rid = sceNetResolverCreate("CC resolver", NULL, 0); - if (rid < 0) return ERR_INVALID_ARGUMENT; - - int ret = sceNetResolverStartNtoa(rid, host, &addr->v4.sin_addr, 0, 0, 0); - sceNetResolverDestroy(rid); - return ret; -} - -static int ParseAddress(union SocketAddress* addr, const cc_string* address) { +cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* addrs, int* numValidAddrs) { + struct SceNetSockaddrIn* addr4 = (struct SceNetSockaddrIn*)addrs[0].data; char str[NATIVE_STR_LEN]; + char buf[1024]; + int rid, ret; + String_EncodeUtf8(str, address); + *numValidAddrs = 1; - if (sceNetInetPton(SCE_NET_AF_INET, str, &addr->v4.sin_addr) > 0) return 0; - return ParseHost(addr, str); + if (sceNetInetPton(SCE_NET_AF_INET, str, &addr4->sin_addr) <= 0) { + /* Fallback to resolving as DNS name */ + rid = sceNetResolverCreate("CC resolver", NULL, 0); + if (rid < 0) return ERR_INVALID_ARGUMENT; + + ret = sceNetResolverStartNtoa(rid, str, &addr4->sin_addr, 0, 0, 0); + sceNetResolverDestroy(rid); + if (ret) return ret; + } + + addr4->sin_family = SCE_NET_AF_INET; + addr4->sin_port = sceNetHtons(port); + + addrs[0].size = sizeof(*addr4); + return 0; } -int Socket_ValidAddress(const cc_string* address) { - union SocketAddress addr; - return ParseAddress(&addr, address) == 0; -} - -cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bool nonblocking) { - union SocketAddress addr; +cc_result Socket_Connect(cc_socket* s, cc_sockaddr* addr, cc_bool nonblocking) { + struct SceNetSockaddr* raw = (struct SceNetSockaddr*)addr->data; int res; - *s = -1; - if ((res = ParseAddress(&addr, address))) return res; - - *s = sceNetSocket("CC socket", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, SCE_NET_IPPROTO_TCP); + *s = sceNetSocket("CC socket", raw->sa_family, SCE_NET_SOCK_STREAM, SCE_NET_IPPROTO_TCP); if (*s < 0) return *s; if (nonblocking) { int on = 1; sceNetSetsockopt(*s, SCE_NET_SOL_SOCKET, SCE_NET_SO_NBIO, &on, sizeof(int)); } - - addr.v4.sin_family = SCE_NET_AF_INET; - addr.v4.sin_port = sceNetHtons(port); - res = sceNetConnect(*s, &addr.raw, sizeof(addr.v4)); + res = sceNetConnect(*s, raw, addr->size); return res; } diff --git a/src/Platform_Posix.c b/src/Platform_Posix.c index bde5580f1..ccf33be48 100644 --- a/src/Platform_Posix.c +++ b/src/Platform_Posix.c @@ -528,58 +528,82 @@ union SocketAddress { struct sockaddr_storage total; #endif }; +/* Sanity check to ensure cc_sockaddr struct is large enough to contain all socket addresses supported by this platform */ +static char sockaddr_size_check[sizeof(union SocketAddress) < CC_SOCKETADDR_MAXSIZE ? 1 : -1]; -static int ParseHost(union SocketAddress* addr, const char* host) { +static cc_result ParseHost(const char* host, int port, cc_sockaddr* addrs, int* numValidAddrs) { + char portRaw[32]; cc_string portStr; struct addrinfo hints = { 0 }; struct addrinfo* result; struct addrinfo* cur; - int family = 0, res; + int res, i = 0; - hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; + + String_InitArray(portStr, portRaw); + String_AppendInt(&portStr, port); + portRaw[portStr.length] = '\0'; - res = getaddrinfo(host, NULL, &hints, &result); - if (res) return 0; + res = getaddrinfo(host, portRaw, &hints, &result); + if (res == EAI_AGAIN) return SOCK_ERR_UNKNOWN_HOST; + if (res) return res; - for (cur = result; cur; cur = cur->ai_next) { + /* Prefer IPv4 addresses first */ + for (cur = result; cur && i < SOCKET_MAX_ADDRS; cur = cur->ai_next) + { if (cur->ai_family != AF_INET) continue; - family = AF_INET; - - Mem_Copy(addr, cur->ai_addr, cur->ai_addrlen); - break; + Mem_Copy(addrs[i].data, cur->ai_addr, cur->ai_addrlen); + addrs[i].size = cur->ai_addrlen; i++; + } + + for (cur = result; cur && i < SOCKET_MAX_ADDRS; cur = cur->ai_next) + { + if (cur->ai_family == AF_INET) continue; + Mem_Copy(addrs[i].data, cur->ai_addr, cur->ai_addrlen); + addrs[i].size = cur->ai_addrlen; i++; } freeaddrinfo(result); - return family; + *numValidAddrs = i; + return i == 0 ? ERR_INVALID_ARGUMENT : 0; } -static int ParseAddress(union SocketAddress* addr, const cc_string* address) { +cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* addrs, int* numValidAddrs) { + union SocketAddress* addr = (union SocketAddress*)addrs[0].data; char str[NATIVE_STR_LEN]; + String_EncodeUtf8(str, address); + *numValidAddrs = 0; - if (inet_pton(AF_INET, str, &addr->v4.sin_addr) > 0) return AF_INET; + if (inet_pton(AF_INET, str, &addr->v4.sin_addr) > 0) { + addr->v4.sin_family = AF_INET; + addr->v4.sin_port = htons(port); + + addrs[0].size = sizeof(addr->v4); + *numValidAddrs = 1; + return 0; + } + #ifdef AF_INET6 - if (inet_pton(AF_INET6, str, &addr->v6.sin6_addr) > 0) return AF_INET6; + if (inet_pton(AF_INET6, str, &addr->v6.sin6_addr) > 0) { + addr->v6.sin6_family = AF_INET6; + addr->v6.sin6_port = htons(port); + + addrs[0].size = sizeof(addr->v6); + *numValidAddrs = 1; + return 0; + } #endif - return ParseHost(addr, str); + + return ParseHost(str, port, addrs, numValidAddrs); } -int Socket_ValidAddress(const cc_string* address) { - union SocketAddress addr; - return ParseAddress(&addr, address); -} - -cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bool nonblocking) { - int family, addrSize = 0; - union SocketAddress addr; +cc_result Socket_Connect(cc_socket* s, cc_sockaddr* addr, cc_bool nonblocking) { + struct sockaddr* raw = (struct sockaddr*)addr->data; cc_result res; - *s = -1; - if (!(family = ParseAddress(&addr, address))) - return ERR_INVALID_ARGUMENT; - - *s = socket(family, SOCK_STREAM, IPPROTO_TCP); + *s = socket(raw->sa_family, SOCK_STREAM, IPPROTO_TCP); if (*s == -1) return errno; if (nonblocking) { @@ -587,20 +611,7 @@ cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bo ioctl(*s, FIONBIO, &blocking_raw); } - #ifdef AF_INET6 - if (family == AF_INET6) { - addr.v6.sin6_family = AF_INET6; - addr.v6.sin6_port = htons(port); - addrSize = sizeof(addr.v6); - } - #endif - if (family == AF_INET) { - addr.v4.sin_family = AF_INET; - addr.v4.sin_port = htons(port); - addrSize = sizeof(addr.v4); - } - - res = connect(*s, &addr.raw, addrSize); + res = connect(*s, raw, addr->size); return res == -1 ? errno : 0; } @@ -1421,4 +1432,4 @@ cc_result Platform_SetDefaultCurrentDirectory(int argc, char **argv) { return chdir(path) == -1 ? errno : 0; } #endif -#endif +#endif \ No newline at end of file diff --git a/src/Platform_Web.c b/src/Platform_Web.c index d596b62f3..a8efacda8 100644 --- a/src/Platform_Web.c +++ b/src/Platform_Web.c @@ -251,13 +251,13 @@ void Platform_LoadSysFonts(void) { } *#########################################################################################################################*/ extern void interop_InitSockets(void); -cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* addrs, int* numAddrs) { +cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* addrs, int* numValidAddrs) { int len = String_EncodeUtf8(addrs[0].data, address); /* TODO can this ever happen */ if (len >= CC_SOCKETADDR_MAXSIZE) Logger_Abort("Overrun in Socket_ParseAddress"); - addrs[0].size = port; - *numAddrs = 1; + addrs[0].size = port; + *numValidAddrs = 1; return 0; } diff --git a/src/Platform_Windows.c b/src/Platform_Windows.c index e5f5858f8..bfd40ecd5 100644 --- a/src/Platform_Windows.c +++ b/src/Platform_Windows.c @@ -459,10 +459,9 @@ static void LoadWinsockFuncs(void) { if (!_WSAStringToAddressW) _WSAStringToAddressW = FallbackParseAddress; } -static cc_result ParseHost(char* host, int port, cc_sockaddr* addrs, int* numAddrs) { +static cc_result ParseHost(char* host, int port, cc_sockaddr* addrs, int* numValidAddrs) { struct hostent* res; cc_result wsa_res; - cc_sockaddr* dst_addr; SOCKADDR_IN* addr4; char* src_addr; int i; @@ -478,41 +477,40 @@ static cc_result ParseHost(char* host, int port, cc_sockaddr* addrs, int* numAdd /* per MSDN, should only be getting AF_INET returned from this */ if (res->h_addrtype != AF_INET) return ERR_INVALID_ARGUMENT; + if (!res->h_addr_list) return ERR_INVALID_ARGUMENT; for (i = 0; i < SOCKET_MAX_ADDRS; i++) { src_addr = res->h_addr_list[i]; if (!src_addr) break; + addrs[i].size = sizeof(SOCKADDR_IN); - dst_addr = &addrs[i]; - dst_addr->size = sizeof(SOCKADDR_IN); - - addr4 = (SOCKADDR_IN*)dst_addr->data; + addr4 = (SOCKADDR_IN*)addrs[i].data; addr4->sin_family = AF_INET; addr4->sin_port = _htons(port); addr4->sin_addr = *(IN_ADDR*)src_addr; } - *numAddrs = i; + *numValidAddrs = i; /* Must have at least one IPv4 address */ return i == 0 ? ERR_INVALID_ARGUMENT : 0; } -cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* addrs, int* numAddrs) { +cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* addrs, int* numValidAddrs) { SOCKADDR_IN* addr4 = (SOCKADDR_IN* )addrs[0].data; SOCKADDR_IN6* addr6 = (SOCKADDR_IN6*)addrs[0].data; cc_winstring str; INT size; - *numAddrs = 0; + *numValidAddrs = 0; Platform_EncodeString(&str, address); size = sizeof(*addr4); if (!_WSAStringToAddressW(str.uni, AF_INET, NULL, addr4, &size)) { addr4->sin_port = _htons(port); - addrs[0].size = size; - *numAddrs = 1; + addrs[0].size = size; + *numValidAddrs = 1; return 0; } @@ -520,12 +518,12 @@ cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* a if (!_WSAStringToAddressW(str.uni, AF_INET6, NULL, addr6, &size)) { addr6->sin6_port = _htons(port); - addrs[0].size = size; - *numAddrs = 1; + addrs[0].size = size; + *numValidAddrs = 1; return 0; } - return ParseHost(str.ansi, port, addrs, numAddrs); + return ParseHost(str.ansi, port, addrs, numValidAddrs); } cc_result Socket_Connect(cc_socket* s, cc_sockaddr* addr, cc_bool nonblocking) { diff --git a/src/Platform_Xbox.c b/src/Platform_Xbox.c index 936f45fda..3ffd446eb 100644 --- a/src/Platform_Xbox.c +++ b/src/Platform_Xbox.c @@ -296,62 +296,44 @@ void Waitable_WaitFor(void* handle, cc_uint32 milliseconds) { /*########################################################################################################################* *---------------------------------------------------------Socket----------------------------------------------------------* *#########################################################################################################################*/ -union SocketAddress { - struct sockaddr raw; - struct sockaddr_in v4; - struct sockaddr_storage total; // needed for lwip_getaddrinfo -}; - -static int ParseHost(union SocketAddress* addr, const char* host) { +cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* addrs, int* numValidAddrs) { + char str[NATIVE_STR_LEN]; + char portRaw[32]; cc_string portStr; struct addrinfo hints = { 0 }; struct addrinfo* result; struct addrinfo* cur; - int found = 0, res; + int i = 0; + + String_EncodeUtf8(str, address); + *numValidAddrs = 0; - hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; + + String_InitArray(portStr, portRaw); + String_AppendInt(&portStr, port); + portRaw[portStr.length] = '\0'; - res = lwip_getaddrinfo(host, NULL, &hints, &result); + int res = lwip_getaddrinfo(str, portRaw, &hints, &result); + if (res == EAI_FAIL) return SOCK_ERR_UNKNOWN_HOST; if (res) return res; - for (cur = result; cur; cur = cur->ai_next) + for (cur = result; cur && i < SOCKET_MAX_ADDRS; cur = cur->ai_next, i++) { - if (cur->ai_family != AF_INET) continue; - found = true; - - // NOTE: cur->ai_addrlen will always be set to sizeof(struct sockaddr_storage) by lwip - // https://github.com/m-labs/lwip/blob/0178d1d2ee35fb82ab0a13256425f9aa33b08f60/src/api/netdb.c#L402C20-L402C52 - Mem_Copy(addr, cur->ai_addr, cur->ai_addrlen); - break; + Mem_Copy(addrs[i].data, cur->ai_addr, cur->ai_addrlen); + addrs[i].size = cur->ai_addrlen; } lwip_freeaddrinfo(result); - return found ? 0 : ERR_INVALID_ARGUMENT; + *numValidAddrs = i; + return i == 0 ? ERR_INVALID_ARGUMENT : 0; } -static int ParseAddress(union SocketAddress* addr, const cc_string* address) { - char str[NATIVE_STR_LEN]; - String_EncodeUtf8(str, address); - - if (inet_pton(AF_INET, str, &addr->v4.sin_addr) > 0) return 0; - return ParseHost(addr, str); -} - -int Socket_ValidAddress(const cc_string* address) { - union SocketAddress addr; - return ParseAddress(&addr, address) == 0; -} - -cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bool nonblocking) { - union SocketAddress addr; +cc_result Socket_Connect(cc_socket* s, cc_sockaddr* addr, cc_bool nonblocking) { + struct sockaddr* raw = (struct sockaddr*)addr->data; int res; - *s = -1; - res = ParseAddress(&addr, address); - if (res) return res; - - *s = lwip_socket(AF_INET, SOCK_STREAM, 0); + *s = lwip_socket(raw->sa_family, SOCK_STREAM, 0); if (*s == -1) return errno; if (nonblocking) { @@ -359,10 +341,7 @@ cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bo lwip_ioctl(*s, FIONBIO, &blocking_raw); } - addr.v4.sin_family = AF_INET; - addr.v4.sin_port = htons(port); - - res = lwip_connect(*s, &addr.raw, sizeof(addr.v4)); + res = lwip_connect(*s, raw, addr->size); return res == -1 ? errno : 0; } diff --git a/src/Platform_Xbox360.c b/src/Platform_Xbox360.c index 153238288..ff60a1439 100644 --- a/src/Platform_Xbox360.c +++ b/src/Platform_Xbox360.c @@ -241,11 +241,11 @@ void Waitable_WaitFor(void* handle, cc_uint32 milliseconds) { /*########################################################################################################################* *---------------------------------------------------------Socket----------------------------------------------------------* *#########################################################################################################################*/ -int Socket_ValidAddress(const cc_string* address) { - return false; +cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* addrs, int* numValidAddrs) { + return ERR_NOT_SUPPORTED; } -cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bool nonblocking) { +cc_result Socket_Connect(cc_socket* s, cc_sockaddr* addr, cc_bool nonblocking) { return ERR_NOT_SUPPORTED; } diff --git a/src/Server.c b/src/Server.c index bb6c7ba87..7bc2a2713 100644 --- a/src/Server.c +++ b/src/Server.c @@ -280,7 +280,7 @@ static void MPConnection_BeginConnect(void) { static const cc_string invalid_reason = String_FromConst("Invalid IP address"); cc_string title; char titleBuffer[STRING_SIZE]; cc_sockaddr addrs[SOCKET_MAX_ADDRS]; - int numAddrs; + int numValidAddrs; cc_result res; String_InitArray(title, titleBuffer); @@ -292,7 +292,7 @@ static void MPConnection_BeginConnect(void) { Blocks.CanPlace[BLOCK_STILL_WATER] = false; Blocks.CanDelete[BLOCK_STILL_WATER] = false; Blocks.CanPlace[BLOCK_BEDROCK] = false; Blocks.CanDelete[BLOCK_BEDROCK] = false; - res = Socket_ParseAddress(&Server.Address, Server.Port, addrs, &numAddrs); + res = Socket_ParseAddress(&Server.Address, Server.Port, addrs, &numValidAddrs); if (res == ERR_INVALID_ARGUMENT) { MPConnection_Fail(&invalid_reason); return; } else if (res) { diff --git a/src/Window_PS3.c b/src/Window_PS3.c index 6a874aecf..2b00ed78a 100644 --- a/src/Window_PS3.c +++ b/src/Window_PS3.c @@ -155,11 +155,36 @@ static int MapKey(int k) { } return 0; } +static cc_bool kb_deferredClear; static void ProcessKBButtons(void) { - // PS3 keyboard APIs only seem to return current keys pressed ? - if (!kb_data.nb_keycode) return; + // PS3 keyboard APIs only seem to return current keys pressed, + // which is a massive pain to work with + // + // The API is really strange and when pressing two keys produces e.g. + // - Event 1) pressed 82 + // - Event 2) pressed 46 + // instead of + // - Event 1) pressed 82 + // - Event 2) pressed 82 46 + // + // Additionally on real hardware, the following events when observed + // - Releasing key: [key] [0] + // - Holding key: [key] [0] [key] [0] [key] [0] + // I don't really know why this happens, so try to detect this by + // deferring resetting all keys to next Window_ProcessEvents + // TODO properly investigate this + + if (kb_deferredClear && (kb_data.nb_keycode == 0 || kb_data.keycode[0] == 0)) { + Mem_Set(now_pressed, 0, sizeof(now_pressed)); + kb_deferredClear = false; + } else { + kb_deferredClear = false; + if (!kb_data.nb_keycode) return; + } + + // possibly unpress all keys next time around + if (kb_data.keycode[0] == 0) kb_deferredClear = true; - Mem_Set(now_pressed, 0, sizeof(now_pressed)); for (int i = 0; i < kb_data.nb_keycode; i++) { int rawcode = kb_data.keycode[i]; @@ -248,7 +273,7 @@ static void HandleJoystick_Left(int x, int y) { } static void HandleJoystick_Right(int x, int y, double delta) { - float scale = (delta * 60.0) / 64.0f; + float scale = (delta * 60.0) / 32.0f; if (Math_AbsI(x) <= 32) x = 0; if (Math_AbsI(y) <= 32) y = 0;