From ae52ab9761cb6a9d2e5959a8900e4070ebcd5540 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 25 Nov 2023 10:37:23 +1100 Subject: [PATCH] PS2: Not really working networking --- misc/ps2/Makefile | 11 +- src/Platform_Dreamcast.c | 2 +- src/Platform_PS2.c | 228 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 225 insertions(+), 16 deletions(-) diff --git a/misc/ps2/Makefile b/misc/ps2/Makefile index cc85f8a57..b6f1d3518 100644 --- a/misc/ps2/Makefile +++ b/misc/ps2/Makefile @@ -4,7 +4,7 @@ CFILES := $(wildcard src/*.c) OBJS :=$(patsubst %.c, %.o, $(CFILES)) EE_BIN = ClassiCube-ps2.elf -EE_OBJS = $(OBJS) +EE_OBJS = $(OBJS) DEV9_irx.o NETMAN_irx.o SMAP_irx.o EE_LIBS = -lpatches -lpad -lpacket -ldma -lgraph -ldraw -lc EE_CFLAGS = -DPLAT_PS2 @@ -12,6 +12,15 @@ all: $(EE_BIN) clean: rm -f $(EE_BIN) $(EE_OBJS) + +DEV9_irx.c: $(PS2SDK)/iop/irx/ps2dev9.irx + bin2c $< DEV9_irx.c DEV9_irx + +NETMAN_irx.c: $(PS2SDK)/iop/irx/netman.irx + bin2c $< NETMAN_irx.c NETMAN_irx + +SMAP_irx.c: $(PS2SDK)/iop/irx/smap.irx + bin2c $< SMAP_irx.c SMAP_irx include $(PS2SDK)/samples/Makefile.pref include $(PS2SDK)/samples/Makefile.eeglobal diff --git a/src/Platform_Dreamcast.c b/src/Platform_Dreamcast.c index 088c0f0d2..041e92390 100644 --- a/src/Platform_Dreamcast.c +++ b/src/Platform_Dreamcast.c @@ -197,7 +197,7 @@ cc_result File_Length(cc_file file, cc_uint32* len) { /*########################################################################################################################* *--------------------------------------------------------Threading--------------------------------------------------------* *#########################################################################################################################*/ -// !!! NOTE: Dreamcast uses cooperative multithreading (not preemptive multithreading) !!! +// !!! NOTE: Dreamcast is configured to use preemptive multithreading !!! void Thread_Sleep(cc_uint32 milliseconds) { thd_sleep(milliseconds); } diff --git a/src/Platform_PS2.c b/src/Platform_PS2.c index af557166f..86e24a86e 100644 --- a/src/Platform_PS2.c +++ b/src/Platform_PS2.c @@ -29,13 +29,13 @@ #include #include #include +#include +#include #include "_PlatformConsole.h" const cc_result ReturnCode_FileShareViolation = 1000000000; // not used -const cc_result ReturnCode_FileNotFound = 0x80010006; // ENOENT; -//const cc_result ReturnCode_SocketInProgess = 0x80010032; // EINPROGRESS -//const cc_result ReturnCode_SocketWouldBlock = 0x80010001; // EWOULDBLOCK; -const cc_result ReturnCode_DirectoryExists = 0x80010014; // EEXIST +const cc_result ReturnCode_FileNotFound = ENOENT; +const cc_result ReturnCode_DirectoryExists = EEXIST; const cc_result ReturnCode_SocketInProgess = EINPROGRESS; const cc_result ReturnCode_SocketWouldBlock = EWOULDBLOCK; @@ -337,41 +337,240 @@ void Waitable_WaitFor(void* handle, cc_uint32 milliseconds) { /*########################################################################################################################* *-------------------------------------------------------Networking--------------------------------------------------------* *#########################################################################################################################*/ +// https://github.com/ps2dev/ps2sdk/blob/master/NETMAN.txt +// https://github.com/ps2dev/ps2sdk/blob/master/ee/network/tcpip/samples/tcpip_dhcp/ps2ip.c +extern unsigned char DEV9_irx[]; +extern unsigned int size_DEV9_irx; + +extern unsigned char SMAP_irx[]; +extern unsigned int size_SMAP_irx; + +extern unsigned char NETMAN_irx[]; +extern unsigned int size_NETMAN_irx; + +static void ethStatusCheckCb(s32 alarm_id, u16 time, void *common) { + int threadID = *(int*)common; + iWakeupThread(threadID); +} + +static int WaitValidNetState(int (*checkingFunction)(void)) { + // Wait for a valid network status + int threadID = GetThreadId(); + + for (int retries = 0; checkingFunction() == 0; retries++) + { + // Sleep for 500ms + SetAlarm(500 * 16, ðStatusCheckCb, &threadID); + SleepThread(); + + if (retries >= 10) // 5s = 10 * 500ms + return -1; + } + return 0; +} + +static int ethGetNetIFLinkStatus(void) { + return NetManIoctl(NETMAN_NETIF_IOCTL_GET_LINK_STATUS, NULL, 0, NULL, 0) == NETMAN_NETIF_ETH_LINK_STATE_UP; +} + +static int ethWaitValidNetIFLinkState(void) { + return WaitValidNetState(ðGetNetIFLinkStatus); +} + +static int ethGetDHCPStatus(void) { + t_ip_info ip_info; + int result; + if ((result = ps2ip_getconfig("sm0", &ip_info)) < 0) return result; + + if (ip_info.dhcp_enabled) { + return ip_info.dhcp_status == DHCP_STATE_BOUND || ip_info.dhcp_status == DHCP_STATE_OFF; + } + return -1; +} + +static int ethWaitValidDHCPState(void) { + return WaitValidNetState(ðGetDHCPStatus); +} + +static int ethEnableDHCP(void) { + t_ip_info ip_info; + int result; + // SMAP is registered as the "sm0" device to the TCP/IP stack. + if ((result = ps2ip_getconfig("sm0", &ip_info)) < 0) return result; + + if (!ip_info.dhcp_enabled) { + ip_info.dhcp_enabled = 1; + return ps2ip_setconfig(&ip_info); + } + return 0; +} + +static void SetupNetworking(void) { + struct ip4_addr IP = { 0 }, NM = { 0 }, GW = { 0 }; + ps2ipInit(&IP, &NM, &GW); + ethEnableDHCP(); + + Platform_LogConst("Waiting for net link connection..."); + if(ethWaitValidNetIFLinkState() != 0) { + Platform_LogConst("Failed to establish net link"); + return; + } + + Platform_LogConst("Waiting for DHCP lease..."); + if (ethWaitValidDHCPState() != 0) { + Platform_LogConst("Failed to acquire DHCP lease"); + return; + } + Platform_LogConst("Network setup done"); +} + static void InitNetworking(void) { - //SifExecModuleBuffer(DEV9_irx, size_DEV9_irx, 0, NULL, NULL); - //SifExecModuleBuffer(NETMAN_irx, size_NETMAN_irx, 0, NULL, NULL); - //SifExecModuleBuffer(SMAP_irx, size_SMAP_irx, 0, NULL, NULL); - //NetManInit(); + SifExecModuleBuffer(DEV9_irx, size_DEV9_irx, 0, NULL, NULL); + SifExecModuleBuffer(NETMAN_irx, size_NETMAN_irx, 0, NULL, NULL); + SifExecModuleBuffer(SMAP_irx, size_SMAP_irx, 0, NULL, NULL); + NetManInit(); } /*########################################################################################################################* *---------------------------------------------------------Socket----------------------------------------------------------* *#########################################################################################################################*/ +union SocketAddress { + struct sockaddr raw; + struct sockaddr_in v4; +}; + +static int ParseHost(union SocketAddress* addr, const char* host) { + struct addrinfo hints = { 0 }; + struct addrinfo* result; + struct addrinfo* cur; + int found = false; + + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + int res = getaddrinfo(host, NULL, &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; + } + + freeaddrinfo(result); + return found ? 0 : ERR_INVALID_ARGUMENT; +} + +static int ParseAddress(union SocketAddress* addr, const cc_string* address) { + char str[NATIVE_STR_LEN]; + String_EncodeUtf8(str, address); + + if (inet_aton(str, &addr->v4.sin_addr) > 0) return 0; + return ParseHost(addr, str); +} + int Socket_ValidAddress(const cc_string* address) { - return false; + union SocketAddress addr; + return ParseAddress(&addr, address) == 0; +} + +static cc_result GetSocketError(cc_socket s) { + socklen_t resultSize = sizeof(socklen_t); + cc_result res = 0; + getsockopt(s, SOL_SOCKET, SO_ERROR, &res, &resultSize); + return res; } cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bool nonblocking) { - return ERR_NOT_SUPPORTED; + union SocketAddress addr; + int res; + + *s = -1; + if ((res = ParseAddress(&addr, address))) return res; + + *s = socket(AF_INET, SOCK_STREAM, 0); + if (*s < 0) return *s; + + if (nonblocking) { + int blocking_raw = -1; // non-blocking mode + //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)); + return res == -1 ? GetSocketError(*s) : 0; } cc_result Socket_Read(cc_socket s, cc_uint8* data, cc_uint32 count, cc_uint32* modified) { - return ERR_NOT_SUPPORTED; + Platform_Log1("PREPARE TO READ: %i", &count); + int recvCount = recv(s, data, count, 0); + Platform_Log1(" .. read %i", &recvCount); + if (recvCount != -1) { *modified = recvCount; return 0; } + + int ERR = GetSocketError(s); + Platform_Log1("ERR: %i", &ERR); + *modified = 0; return ERR; } cc_result Socket_Write(cc_socket s, const cc_uint8* data, cc_uint32 count, cc_uint32* modified) { - return ERR_NOT_SUPPORTED; + Platform_Log1("PREPARE TO WRITE: %i", &count); + int sentCount = send(s, data, count, 0); + Platform_Log1(" .. wrote %i", &sentCount); + if (sentCount != -1) { *modified = sentCount; return 0; } + + int ERR = GetSocketError(s); + Platform_Log1("ERR: %i", &ERR); + *modified = 0; return ERR; } void Socket_Close(cc_socket s) { + shutdown(s, SHUT_RDWR); + close(s); +} + +static cc_result Socket_Poll(cc_socket s, int mode, cc_bool* success) { + fd_set read_set, write_set, error_set; + struct timeval time = { 0 }; + int selectCount; + + FD_ZERO(&read_set); + FD_SET(s, &read_set); + FD_ZERO(&write_set); + FD_SET(s, &write_set); + FD_ZERO(&error_set); + FD_SET(s, &error_set); + + selectCount = select(s + 1, &read_set, &write_set, &error_set, &time); + + Platform_Log4("SELECT %i = %h / %h / %h", &selectCount, &read_set, &write_set, &error_set); + if (selectCount == -1) { *success = false; return errno; } + *success = FD_ISSET(s, &write_set) != 0; return 0; } cc_result Socket_CheckReadable(cc_socket s, cc_bool* readable) { - return ERR_NOT_SUPPORTED; + Platform_LogConst("POLL READ"); + return Socket_Poll(s, SOCKET_POLL_READ, readable); } +static int tries; cc_result Socket_CheckWritable(cc_socket s, cc_bool* writable) { - return ERR_NOT_SUPPORTED; + cc_result res = Socket_Poll(s, SOCKET_POLL_WRITE, writable); + Platform_Log1("POLL WRITE: %i", &res); + if (res || *writable) return res; + + // INPROGRESS error code returned if connect is still in progress + res = GetSocketError(s); + Platform_Log1("POLL FAIL: %i", &res); + if (res == EINPROGRESS) res = 0; + + if (tries++ > 20) { *writable = true; } + return res; } @@ -396,6 +595,7 @@ void Platform_Init(void) { sbv_patch_enable_lmb(); InitNetworking(); + SetupNetworking(); // Create root directory Directory_Create(&String_Empty); }