mirror of https://github.com/ClassiCube/ClassiCube
Merge pull request #1115 from UnknownShadow200/SocketAddrRewrite
Rewrite address parsing to support resolving hostnames to multiple IP addresses
This commit is contained in:
commit
fefc2c5ff4
|
|
@ -480,6 +480,7 @@
|
|||
<ClCompile Include="Graphics_PSVita.c" />
|
||||
<ClCompile Include="Graphics_SoftGPU.c" />
|
||||
<ClCompile Include="Graphics_Xbox.c" />
|
||||
<ClCompile Include="Graphics_Xbox360.c" />
|
||||
<ClCompile Include="Gui.c" />
|
||||
<ClCompile Include="HeldBlockRenderer.c" />
|
||||
<ClCompile Include="Http_Web.c" />
|
||||
|
|
@ -507,6 +508,7 @@
|
|||
<ClCompile Include="Platform_Web.c" />
|
||||
<ClCompile Include="Platform_Windows.c" />
|
||||
<ClCompile Include="Platform_Xbox.c" />
|
||||
<ClCompile Include="Platform_Xbox360.c" />
|
||||
<ClCompile Include="Protocol.c" />
|
||||
<ClCompile Include="Physics.c" />
|
||||
<ClCompile Include="IsometricDrawer.c" />
|
||||
|
|
@ -550,6 +552,7 @@
|
|||
<ClCompile Include="Window_Win.c" />
|
||||
<ClCompile Include="Window_X11.c" />
|
||||
<ClCompile Include="Window_Xbox.c" />
|
||||
<ClCompile Include="Window_Xbox360.c" />
|
||||
<ClCompile Include="World.c" />
|
||||
<ClCompile Include="_autofit.c" />
|
||||
<ClCompile Include="_cff.c" />
|
||||
|
|
|
|||
|
|
@ -704,6 +704,15 @@
|
|||
<ClCompile Include="Commands.c">
|
||||
<Filter>Source Files\Game</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Platform_Xbox360.c">
|
||||
<Filter>Source Files\Platform</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Window_Xbox360.c">
|
||||
<Filter>Source Files\Window</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Graphics_Xbox360.c">
|
||||
<Filter>Source Files\Graphics</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="..\misc\windows\CCicon.rc">
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -516,6 +516,8 @@ static cc_result HttpConnection_Open(struct HttpConnection* conn, const struct H
|
|||
cc_string host, port;
|
||||
cc_uint16 portNum;
|
||||
cc_result res;
|
||||
cc_sockaddr addrs[SOCKET_MAX_ADDRS];
|
||||
int numValidAddrs;
|
||||
|
||||
/* address can be either "host" or "host:port" */
|
||||
String_UNSAFE_Separate(&url->address, ':', &host, &port);
|
||||
|
|
@ -523,9 +525,12 @@ static cc_result HttpConnection_Open(struct HttpConnection* conn, const struct H
|
|||
portNum = url->https ? 443 : 80;
|
||||
}
|
||||
|
||||
conn->socket = 0;
|
||||
conn->socket = -1;
|
||||
conn->sslCtx = NULL;
|
||||
if ((res = Socket_Connect(&conn->socket, &host, portNum, false))) 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;
|
||||
|
||||
conn->valid = true;
|
||||
if (!url->https) return 0;
|
||||
|
|
@ -550,9 +555,9 @@ static void HttpConnection_Close(struct HttpConnection* conn) {
|
|||
conn->sslCtx = NULL;
|
||||
}
|
||||
|
||||
if (conn->socket) { /* Closing socket 0 will crash on GC/Wii */
|
||||
if (conn->socket != -1) {
|
||||
Socket_Close(conn->socket);
|
||||
conn->socket = 0;
|
||||
conn->socket = -1;
|
||||
}
|
||||
conn->valid = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -494,6 +494,8 @@ static void DirectConnectScreen_StartClient(void* w) {
|
|||
|
||||
cc_string ip, port;
|
||||
cc_uint16 raw_port;
|
||||
cc_sockaddr addrs[SOCKET_MAX_ADDRS];
|
||||
int numAddrs;
|
||||
|
||||
int index = String_LastIndexOf(addr, ':');
|
||||
if (index == 0 || index == addr->length - 1) {
|
||||
|
|
@ -512,7 +514,7 @@ static void DirectConnectScreen_StartClient(void* w) {
|
|||
if (!user->length) {
|
||||
LLabel_SetConst(status, "&cUsername required"); return;
|
||||
}
|
||||
if (!Socket_ValidAddress(&ip)) {
|
||||
if (Socket_ParseAddress(&ip, 0, addrs, &numAddrs)) {
|
||||
LLabel_SetConst(status, "&cInvalid ip"); return;
|
||||
}
|
||||
if (!Convert_ParseUInt16(&port, &raw_port)) {
|
||||
|
|
|
|||
|
|
@ -242,22 +242,31 @@ CC_API void Waitable_WaitFor(void* handle, cc_uint32 milliseconds);
|
|||
/* Calls SysFonts_Register on each font that is available on this platform. */
|
||||
void Platform_LoadSysFonts(void);
|
||||
|
||||
#define CC_SOCKETADDR_MAXSIZE 512
|
||||
#define SOCKET_MAX_ADDRS 8
|
||||
|
||||
typedef struct cc_sockaddr_ {
|
||||
int size; /* Actual size of the raw socket address */
|
||||
cc_uint8 data[CC_SOCKETADDR_MAXSIZE]; /* Raw socket address (e.g. sockaddr_in) */
|
||||
} cc_sockaddr;
|
||||
|
||||
/* Checks if the given socket is currently readable (i.e. has data available to read) */
|
||||
/* NOTE: A closed socket is also considered readable */
|
||||
cc_result Socket_CheckReadable(cc_socket s, cc_bool* readable);
|
||||
/* Checks if the given socket is currently 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);
|
||||
/* 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* numValidAddrs);
|
||||
|
||||
/* Allocates a new socket and then begins connecting to the given address:port. */
|
||||
cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bool nonblocking);
|
||||
/* Attempts to read data from the given socket. */
|
||||
/* 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);
|
||||
/* Attempts to read data from the given socket */
|
||||
/* NOTE: A closed socket may set modified to 0, but still return 'success' (i.e. 0) */
|
||||
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_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 */
|
||||
void Socket_Close(cc_socket s);
|
||||
|
||||
#ifdef CC_BUILD_MOBILE
|
||||
|
|
|
|||
|
|
@ -285,59 +285,58 @@ 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 eliminate this path?
|
||||
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_family = AF_INET; // TODO: you need this, otherwise resolving dl.dropboxusercontent.com crashes in Citra. probably something to do with IPv6 addresses
|
||||
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 +344,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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -250,18 +250,26 @@ void Platform_LoadSysFonts(void) { }
|
|||
*---------------------------------------------------------Socket----------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
extern void interop_InitSockets(void);
|
||||
int Socket_ValidAddress(const cc_string* address) { return true; }
|
||||
|
||||
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;
|
||||
*numValidAddrs = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int interop_SocketCreate(void);
|
||||
extern int interop_SocketConnect(int sock, const char* addr, int port);
|
||||
cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bool nonblocking) {
|
||||
char addr[NATIVE_STR_LEN];
|
||||
extern int interop_SocketConnect(int sock, const cc_uint8* host, int port);
|
||||
cc_result Socket_Connect(cc_socket* s, cc_sockaddr* addr, cc_bool nonblocking) {
|
||||
int res;
|
||||
String_EncodeUtf8(addr, address);
|
||||
|
||||
*s = interop_SocketCreate();
|
||||
/* size is used to store port number instead */
|
||||
/* returned result is negative for error */
|
||||
res = -interop_SocketConnect(*s, addr, port);
|
||||
res = -interop_SocketConnect(*s, addr->data, addr->size);
|
||||
|
||||
/* error returned when invalid address provided */
|
||||
if (res == _EHOSTUNREACH) return ERR_INVALID_ARGUMENT;
|
||||
|
|
|
|||
|
|
@ -395,6 +395,9 @@ void Platform_LoadSysFonts(void) {
|
|||
/*########################################################################################################################*
|
||||
*---------------------------------------------------------Socket----------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
/* 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(SOCKADDR_STORAGE) < CC_SOCKETADDR_MAXSIZE ? 1 : -1];
|
||||
|
||||
static int (WSAAPI *_WSAStartup)(WORD versionRequested, LPWSADATA wsaData);
|
||||
static int (WSAAPI *_WSACleanup)(void);
|
||||
static int (WSAAPI *_WSAGetLastError)(void);
|
||||
|
|
@ -456,12 +459,15 @@ static void LoadWinsockFuncs(void) {
|
|||
if (!_WSAStringToAddressW) _WSAStringToAddressW = FallbackParseAddress;
|
||||
}
|
||||
|
||||
static int ParseHost(void* dst, char* host, int port) {
|
||||
SOCKADDR_IN* addr4 = (SOCKADDR_IN*)dst;
|
||||
static cc_result ParseHost(char* host, int port, cc_sockaddr* addrs, int* numValidAddrs) {
|
||||
struct hostent* res;
|
||||
cc_result wsa_res;
|
||||
SOCKADDR_IN* addr4;
|
||||
char* src_addr;
|
||||
int i;
|
||||
|
||||
res = _gethostbyname(host);
|
||||
|
||||
if (!res) {
|
||||
wsa_res = _WSAGetLastError();
|
||||
|
||||
|
|
@ -471,54 +477,60 @@ static int ParseHost(void* dst, char* host, int port) {
|
|||
|
||||
/* 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);
|
||||
|
||||
addr4 = (SOCKADDR_IN*)addrs[i].data;
|
||||
addr4->sin_family = AF_INET;
|
||||
addr4->sin_port = _htons(port);
|
||||
addr4->sin_addr = *(IN_ADDR*)src_addr;
|
||||
}
|
||||
|
||||
*numValidAddrs = i;
|
||||
/* Must have at least one IPv4 address */
|
||||
if (!res->h_addr_list[0]) return ERR_INVALID_ARGUMENT;
|
||||
|
||||
addr4->sin_family = AF_INET;
|
||||
addr4->sin_port = _htons(port);
|
||||
addr4->sin_addr = *(IN_ADDR*)res->h_addr_list[0];
|
||||
return 0;
|
||||
return i == 0 ? ERR_INVALID_ARGUMENT : 0;
|
||||
}
|
||||
|
||||
static int Socket_ParseAddress(void* dst, INT* size, const cc_string* address, int port) {
|
||||
SOCKADDR_IN* addr4 = (SOCKADDR_IN*)dst;
|
||||
SOCKADDR_IN6* addr6 = (SOCKADDR_IN6*)dst;
|
||||
cc_winstring addr;
|
||||
Platform_EncodeString(&addr, address);
|
||||
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;
|
||||
|
||||
*size = sizeof(*addr4);
|
||||
if (!_WSAStringToAddressW(addr.uni, AF_INET, NULL, addr4, size)) {
|
||||
*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;
|
||||
*numValidAddrs = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*size = sizeof(*addr6);
|
||||
if (!_WSAStringToAddressW(addr.uni, AF_INET6, NULL, addr6, size)) {
|
||||
size = sizeof(*addr6);
|
||||
if (!_WSAStringToAddressW(str.uni, AF_INET6, NULL, addr6, &size)) {
|
||||
addr6->sin6_port = _htons(port);
|
||||
|
||||
addrs[0].size = size;
|
||||
*numValidAddrs = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*size = sizeof(*addr4);
|
||||
return ParseHost(dst, addr.ansi, port);
|
||||
return ParseHost(str.ansi, port, addrs, numValidAddrs);
|
||||
}
|
||||
|
||||
int Socket_ValidAddress(const cc_string* address) {
|
||||
SOCKADDR_STORAGE addr;
|
||||
INT addrSize;
|
||||
return Socket_ParseAddress(&addr, &addrSize, address, 0) == 0;
|
||||
}
|
||||
|
||||
cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bool nonblocking) {
|
||||
SOCKADDR_STORAGE addr;
|
||||
cc_result Socket_Connect(cc_socket* s, cc_sockaddr* addr, cc_bool nonblocking) {
|
||||
SOCKADDR* raw_addr = (SOCKADDR*)addr->data;
|
||||
cc_result res;
|
||||
INT addrSize;
|
||||
|
||||
*s = -1;
|
||||
res = Socket_ParseAddress(&addr, &addrSize, address, port);
|
||||
if (res) return res;
|
||||
|
||||
*s = _socket(addr.ss_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
*s = _socket(raw_addr->sa_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (*s == -1) return _WSAGetLastError();
|
||||
|
||||
if (nonblocking) {
|
||||
|
|
@ -526,7 +538,7 @@ cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bo
|
|||
_ioctlsocket(*s, FIONBIO, &blockingMode);
|
||||
}
|
||||
|
||||
res = _connect(*s, (SOCKADDR*)&addr, addrSize);
|
||||
res = _connect(*s, raw_addr, addr->size);
|
||||
return res == -1 ? _WSAGetLastError() : 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
17
src/Server.c
17
src/Server.c
|
|
@ -214,7 +214,7 @@ static void SPConnection_Init(void) {
|
|||
/*########################################################################################################################*
|
||||
*--------------------------------------------------Multiplayer connection-------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
static cc_socket net_socket;
|
||||
static cc_socket net_socket = -1;
|
||||
static cc_uint8 net_readBuffer[4096 * 5];
|
||||
static cc_uint8* net_readCurrent;
|
||||
|
||||
|
|
@ -277,7 +277,10 @@ static void MPConnection_TickConnect(void) {
|
|||
}
|
||||
|
||||
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 numValidAddrs;
|
||||
cc_result res;
|
||||
String_InitArray(title, titleBuffer);
|
||||
|
||||
|
|
@ -289,10 +292,16 @@ 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_Connect(&net_socket, &Server.Address, Server.Port, true);
|
||||
res = Socket_ParseAddress(&Server.Address, Server.Port, addrs, &numValidAddrs);
|
||||
if (res == ERR_INVALID_ARGUMENT) {
|
||||
static const cc_string reason = String_FromConst("Invalid IP address");
|
||||
MPConnection_Fail(&reason);
|
||||
MPConnection_Fail(&invalid_reason); return;
|
||||
} else if (res) {
|
||||
MPConnection_FailConnect(res); return;
|
||||
}
|
||||
|
||||
res = Socket_Connect(&net_socket, &addrs[0], true);
|
||||
if (res == ERR_INVALID_ARGUMENT) {
|
||||
MPConnection_Fail(&invalid_reason);
|
||||
} else if (res && res != ReturnCode_SocketInProgess && res != ReturnCode_SocketWouldBlock) {
|
||||
MPConnection_FailConnect(res);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue