Start rewriting sockets backends to supporting resolving a hostname to multiple IP addresses

This commit is contained in:
UnknownShadow200 2023-12-22 12:57:55 +11:00
parent 0d24afb9b8
commit 39d582a88c
6 changed files with 102 additions and 55 deletions

View File

@ -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 numAddrs;
/* 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, &numAddrs))) 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;
}

View File

@ -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)) {

View File

@ -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 5
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* numAddrs);
/* 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

View File

@ -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* numAddrs) {
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;
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;

View File

@ -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,16 @@ 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* numAddrs) {
struct hostent* res;
cc_result wsa_res;
cc_sockaddr* dst_addr;
SOCKADDR_IN* addr4;
char* src_addr;
int i;
res = _gethostbyname(host);
if (!res) {
wsa_res = _WSAGetLastError();
@ -472,53 +479,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;
for (i = 0; i < SOCKET_MAX_ADDRS; i++)
{
src_addr = res->h_addr_list[i];
if (!src_addr) break;
dst_addr = &addrs[i];
dst_addr->size = sizeof(SOCKADDR_IN);
addr4 = (SOCKADDR_IN*)dst_addr->data;
addr4->sin_family = AF_INET;
addr4->sin_port = _htons(port);
addr4->sin_addr = *(IN_ADDR*)src_addr;
}
*numAddrs = 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* numAddrs) {
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)) {
*numAddrs = 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;
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;
*numAddrs = 1;
return 0;
}
*size = sizeof(*addr4);
return ParseHost(dst, addr.ansi, port);
return ParseHost(str.ansi, port, addrs, numAddrs);
}
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 +540,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;
}

View File

@ -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 numAddrs;
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, &numAddrs);
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 {