From 5140163e907cc6f334e4747473d4ceeee9484e59 Mon Sep 17 00:00:00 2001 From: Daryl Borth Date: Fri, 11 Sep 2026 18:53:10 -0600 Subject: [PATCH 01/17] wii/gamecube are missing sockaddr_storage --- lib/compat.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lib/compat.h b/lib/compat.h index 638225b2..98bf20be 100644 --- a/lib/compat.h +++ b/lib/compat.h @@ -671,6 +671,27 @@ struct addrinfo { struct addrinfo *ai_next; /* next structure in linked list */ }; +#if defined(__wii__) || defined(__gamecube__) +#if !defined(HAVE_SOCKADDR_STORAGE) +/* + * RFC 2553: protocol-independent placeholder for socket addresses. + * libogc's has no sockaddr_storage of its own. + */ +#define _SS_MAXSIZE 128 +#define _SS_ALIGNSIZE (sizeof(double)) +#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof(unsigned short)) +#define _SS_PAD2SIZE (_SS_MAXSIZE - sizeof(unsigned short) - \ + _SS_PAD1SIZE - _SS_ALIGNSIZE) + +struct sockaddr_storage { + unsigned short ss_family; + char __ss_pad1[_SS_PAD1SIZE]; + double __ss_align; + char __ss_pad2[_SS_PAD2SIZE]; +}; +#endif +#endif + #endif #define sockaddr_in6 sockaddr_in #else From b93aaec7c8a9f8b1254351c760c1e005a7053f32 Mon Sep 17 00:00:00 2001 From: Daryl Borth Date: Fri, 11 Sep 2026 18:53:35 -0600 Subject: [PATCH 02/17] use ninja for devkitpro builds. fixes path issues on windows --- Makefile.platform | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Makefile.platform b/Makefile.platform index a706f165..c7a46bd4 100644 --- a/Makefile.platform +++ b/Makefile.platform @@ -18,42 +18,42 @@ .PHONY: gc_all gc_install nds_all nds_install wii_all wii_install 3ds_all 3ds_install wiiu_all wiiu_install switch_all switch_install dc_all dc_install ps2_ee_all ps2_ee_install ps2_ips_all ps2_ips_install ps2_iop_all ps2_iop_install ps4_all ps4_install gc_all: - cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/GameCube.cmake" + cmake -S . -B build -G Ninja "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/GameCube.cmake" cmake --build build gc_install: gc_all cmake --build build --target install nds_all: - cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/NDS.cmake" + cmake -S . -B build -G Ninja "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/NDS.cmake" cmake --build build nds_install: nds_all cmake --build build --target install wii_all: - cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/Wii.cmake" + cmake -S . -B build -G Ninja "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/Wii.cmake" cmake --build build wii_install: wii_all cmake --build build --target install 3ds_all: - cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/3DS.cmake" + cmake -S . -B build -G Ninja "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/3DS.cmake" cmake --build build 3ds_install: 3ds_all - cmake --build build --target install + cmake --build build -G Ninja --target install wiiu_all: - cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/WiiU.cmake" + cmake -S . -B build -G Ninja "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/WiiU.cmake" cmake --build build wiiu_install: wiiu_all - cmake --build build --target install + cmake --build build -G Ninja --target install switch_all: - cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/Switch.cmake" + cmake -S . -B build -G Ninja "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/Switch.cmake" cmake --build build switch_install: switch_all From ee2caf8d5ef44a6bdfb2d87105cc4c3ad411529f Mon Sep 17 00:00:00 2001 From: Daryl Borth Date: Fri, 11 Sep 2026 20:18:43 -0600 Subject: [PATCH 03/17] fix sockaddr_storage layout for wii/gamecube --- lib/compat.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/compat.h b/lib/compat.h index 98bf20be..78e984a1 100644 --- a/lib/compat.h +++ b/lib/compat.h @@ -684,7 +684,8 @@ struct addrinfo { _SS_PAD1SIZE - _SS_ALIGNSIZE) struct sockaddr_storage { - unsigned short ss_family; + unsigned char ss_len; + unsigned char ss_family; char __ss_pad1[_SS_PAD1SIZE]; double __ss_align; char __ss_pad2[_SS_PAD2SIZE]; From 0397d84f350fd9e3d91c64a0a3b79bc2b19b4b6a Mon Sep 17 00:00:00 2001 From: Daryl Borth Date: Sat, 12 Sep 2026 01:57:17 -0600 Subject: [PATCH 04/17] add wii/gamecube shims for net_write, net_read, net_close --- lib/compat.c | 32 ++++++++++++++++++++++++++++++++ lib/compat.h | 7 +++++++ 2 files changed, 39 insertions(+) diff --git a/lib/compat.c b/lib/compat.c index 66ba3bbd..410c0a87 100644 --- a/lib/compat.c +++ b/lib/compat.c @@ -251,6 +251,38 @@ socklen_t *optlen) } + +ssize_t smb2_net_write(int fd, const void *buf, size_t count) +{ + s32 ret = net_write(fd, buf, count); + if (ret < 0) { + errno = -ret; + return -1; + } + return ret; +} + +ssize_t smb2_net_read(int fd, void *buf, size_t count) +{ + s32 ret = net_read(fd, buf, count); + if (ret < 0) { + errno = -ret; + return -1; + } + return ret; +} + +int smb2_net_close(int fd) +{ + s32 ret = net_close(fd); + if (ret < 0) { + errno = -ret; + return -1; + } + return 0; +} + + #endif #endif /* __SWITCH__ */ diff --git a/lib/compat.h b/lib/compat.h index 78e984a1..f3fef284 100644 --- a/lib/compat.h +++ b/lib/compat.h @@ -763,6 +763,10 @@ void smb2_freeaddrinfo(struct addrinfo *res); #define freeaddrinfo smb2_freeaddrinfo #ifndef __NDS__ +ssize_t smb2_net_write(int fd, const void *buf, size_t count); +ssize_t smb2_net_read(int fd, void *buf, size_t count); +int smb2_net_close(int fd); + #define connect net_connect #define socket net_socket #define setsockopt net_setsockopt @@ -771,6 +775,9 @@ s32 getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optl #define accept net_accept #define listen net_listen #define bind net_bind +#define write(fd, buf, count) smb2_net_write(fd, buf, count) +#define read(fd, buf, count) smb2_net_read(fd, buf, count) +#define close(fd) smb2_net_close(fd) #endif struct pollfd { From e55fbda9b44739cce538e772a7c8db2827980e90 Mon Sep 17 00:00:00 2001 From: Daryl Borth Date: Sat, 12 Sep 2026 13:26:43 -0600 Subject: [PATCH 05/17] add missing compatibility shims for gamecube/wii --- lib/compat.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++----- lib/compat.h | 36 +++++++++++------- lib/socket.c | 11 ++++++ 3 files changed, 129 insertions(+), 22 deletions(-) diff --git a/lib/compat.c b/lib/compat.c index 410c0a87..b9c4084c 100644 --- a/lib/compat.c +++ b/lib/compat.c @@ -231,6 +231,7 @@ int iop_connect(int sockfd, struct sockaddr *addr, socklen_t addrlen) #include <3ds/types.h> #elif defined(__wii__) || defined(__gamecube__) #include +#include #elif defined(__WIIU__) #include #elif defined(__NDS__) @@ -240,16 +241,41 @@ int iop_connect(int sockfd, struct sockaddr *addr, socklen_t addrlen) #define login_num ENXIO #if defined(__wii__) || defined(__gamecube__) -s32 getsockopt(int sockfd, int level, int optname, void *optval, -socklen_t *optlen) +int smb2_net_connect(int fd, struct sockaddr *addr, socklen_t addrlen) { -#ifdef __gamecube__ - return net_getsockopt(sockfd, level, optname, optval, optlen); -#else - return 0; -#endif + s32 ret = net_connect(fd, addr, addrlen); + if (ret < 0) { + errno = -ret; + return -1; + } + return 0; +} +int smb2_net_close(int fd) +{ + s32 ret = net_close(fd); + if (ret < 0) { + errno = -ret; + return -1; + } + return 0; +} +int smb2_net_fcntl(int fd, int cmd, ...) +{ + u32 val = 0; + va_list ap; + + va_start(ap, cmd); + val = (u32)va_arg(ap, int); + va_end(ap); + + s32 ret = net_fcntl(fd, (u32)cmd, val); + if (ret < 0) { + errno = -ret; + return -1; + } + return (int)ret; } ssize_t smb2_net_write(int fd, const void *buf, size_t count) @@ -272,17 +298,77 @@ ssize_t smb2_net_read(int fd, void *buf, size_t count) return ret; } -int smb2_net_close(int fd) +int smb2_net_socket(int domain, int type, int protocol) { - s32 ret = net_close(fd); + s32 ret = net_socket((u32)domain, (u32)type, (u32)protocol); if (ret < 0) { errno = -ret; return -1; } + return (int)ret; +} + +int smb2_net_getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen) +{ +#ifdef __gamecube__ + s32 ret = net_getsockopt(fd, (u32)level, (u32)optname, optval, optlen); + if (ret < 0) { + errno = -ret; + return -1; + } +#endif return 0; } +int smb2_net_setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) +{ + s32 ret = net_setsockopt(fd, (u32)level, (u32)optname, optval, optlen); + if (ret < 0) { + errno = -ret; + return -1; + } + return 0; +} + +int smb2_net_bind(int fd, struct sockaddr *addr, socklen_t addrlen) +{ + s32 ret = net_bind(fd, addr, addrlen); + if (ret < 0) { + errno = -ret; + return -1; + } + return 0; +} + +int smb2_net_listen(int fd, int backlog) +{ + s32 ret = net_listen(fd, (u32)backlog); + if (ret < 0) { + errno = -ret; + return -1; + } + return 0; +} + +int smb2_net_accept(int fd, struct sockaddr *addr, socklen_t *addrlen) +{ + s32 ret = net_accept(fd, addr, addrlen); + if (ret < 0) { + errno = -ret; + return -1; + } + return (int)ret; +} +int smb2_net_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) +{ + s32 ret = net_select(nfds, readfds, writefds, exceptfds, timeout); + if (ret < 0) { + errno = -ret; + return -1; + } + return (int)ret; +} #endif #endif /* __SWITCH__ */ diff --git a/lib/compat.h b/lib/compat.h index f3fef284..0bd60647 100644 --- a/lib/compat.h +++ b/lib/compat.h @@ -763,21 +763,31 @@ void smb2_freeaddrinfo(struct addrinfo *res); #define freeaddrinfo smb2_freeaddrinfo #ifndef __NDS__ +int smb2_net_connect(int fd, struct sockaddr *addr, socklen_t addrlen); +int smb2_net_close(int fd); +int smb2_net_fcntl(int fd, int cmd, ...); ssize_t smb2_net_write(int fd, const void *buf, size_t count); ssize_t smb2_net_read(int fd, void *buf, size_t count); -int smb2_net_close(int fd); - -#define connect net_connect -#define socket net_socket -#define setsockopt net_setsockopt -s32 getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); -#define select net_select -#define accept net_accept -#define listen net_listen -#define bind net_bind -#define write(fd, buf, count) smb2_net_write(fd, buf, count) -#define read(fd, buf, count) smb2_net_read(fd, buf, count) -#define close(fd) smb2_net_close(fd) +int smb2_net_socket(int domain, int type, int protocol); +int smb2_net_getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen); +int smb2_net_setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen); +int smb2_net_bind(int fd, struct sockaddr *addr, socklen_t addrlen); +int smb2_net_listen(int fd, int backlog); +int smb2_net_accept(int fd, struct sockaddr *addr, socklen_t *addrlen); +int smb2_net_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); + +#define socket smb2_net_socket +#define getsockopt smb2_net_getsockopt +#define setsockopt smb2_net_setsockopt +#define select smb2_net_select +#define accept smb2_net_accept +#define listen smb2_net_listen +#define bind smb2_net_bind +#define connect smb2_net_connect +#define close smb2_net_close +#define fcntl smb2_net_fcntl +#define write smb2_net_write +#define read smb2_net_read #endif struct pollfd { diff --git a/lib/socket.c b/lib/socket.c index fe8c394b..c8803166 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -1219,6 +1219,17 @@ set_nonblocking(t_socket fd) #elif (defined(__AMIGA__) || defined(__AROS__)) && !defined(__amigaos4__) && !defined(__amigaos3__) unsigned long opt = 0; IoctlSocket(fd, FIONBIO, (char *)&opt); +#elif defined(__wii__) || defined(__gamecube__) + /* net_fcntl(F_SETFL, O_NONBLOCK) is a dead end on this platform: + * IOS's SO_FCNTL only recognises its own internal IOS_O_NONBLOCK + * bit (0x04) - the flags word goes straight through to IOS with + * no translation of this toolchain's real O_NONBLOCK (0x4000), + * so the call "succeeds" (ret=0) without the socket ever actually + * becoming non-blocking. net_ioctl(FIONBIO) does the correct + * translation internally, so use that instead of building the + * F_SETFL flags word ourselves. */ + int one = 1; + int ioctl_ret = net_ioctl(fd, FIONBIO, &one); #else unsigned v; v = fcntl(fd, F_GETFL, 0); From 6c1724343e556bede5fa6d84af907babb861e40b Mon Sep 17 00:00:00 2001 From: Daryl Borth Date: Sat, 12 Sep 2026 14:21:33 -0600 Subject: [PATCH 06/17] handle different libogc versions --- lib/compat.h | 10 +++++++++- lib/socket.c | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/compat.h b/lib/compat.h index 0bd60647..052554d0 100644 --- a/lib/compat.h +++ b/lib/compat.h @@ -657,7 +657,15 @@ struct iovec { }; #if defined(__wii__) || defined(__gamecube__) || defined(__NDS__) #ifndef __NDS__ + +#if !defined(AF_INET) && !defined(_SYS_SOCKET_H_) && !defined(_SYS_SOCKET_H) && \ + !defined(_NETINET_IN_H_) && !defined(_NETINET_IN_H) && \ + !defined(_ARPA_INET_H_) && !defined(_ARPA_INET_H) #include +#define SMB2_HAVE_OGC_NETWORK_H 1 +#endif +#else +#define SMB2_HAVE_OGC_NETWORK_H 1 /* __NDS__ never touches ; nothing below depends on it */ #endif struct addrinfo { @@ -762,7 +770,7 @@ void smb2_freeaddrinfo(struct addrinfo *res); #define getaddrinfo smb2_getaddrinfo #define freeaddrinfo smb2_freeaddrinfo -#ifndef __NDS__ +#if !defined(__NDS__) && defined(SMB2_HAVE_OGC_NETWORK_H) int smb2_net_connect(int fd, struct sockaddr *addr, socklen_t addrlen); int smb2_net_close(int fd); int smb2_net_fcntl(int fd, int cmd, ...); diff --git a/lib/socket.c b/lib/socket.c index c8803166..04d825e7 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -1229,7 +1229,7 @@ set_nonblocking(t_socket fd) * translation internally, so use that instead of building the * F_SETFL flags word ourselves. */ int one = 1; - int ioctl_ret = net_ioctl(fd, FIONBIO, &one); + net_ioctl(fd, FIONBIO, &one); #else unsigned v; v = fcntl(fd, F_GETFL, 0); From f50696b71c72a8a32b90b41b27ef982b0e08f809 Mon Sep 17 00:00:00 2001 From: Daryl Borth Date: Sat, 12 Sep 2026 14:35:57 -0600 Subject: [PATCH 07/17] handle libogc2 versions with poll defined --- lib/compat.c | 2 +- lib/compat.h | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/compat.c b/lib/compat.c index b9c4084c..73349ab9 100644 --- a/lib/compat.c +++ b/lib/compat.c @@ -577,7 +577,7 @@ ssize_t readv(t_socket fd, const struct iovec* vector, int count) } #endif -#ifdef NEED_POLL +#if defined(NEED_POLL) && !defined(SMB2_HAVE_OGC_POLL_H) int poll(struct pollfd *fds, unsigned int nfds, int timo) { struct timeval timeout, *toptr; diff --git a/lib/compat.h b/lib/compat.h index 052554d0..efb74a4d 100644 --- a/lib/compat.h +++ b/lib/compat.h @@ -798,6 +798,14 @@ int smb2_net_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptf #define read smb2_net_read #endif +#if defined(__has_include) +#if __has_include() +#include +#define SMB2_HAVE_OGC_POLL_H 1 +#endif +#endif + +#ifndef SMB2_HAVE_OGC_POLL_H struct pollfd { int fd; short events; @@ -805,6 +813,7 @@ struct pollfd { }; int poll(struct pollfd *fds, unsigned int nfds, int timo); +#endif #endif From 0a944c44273ac8d6fd0e7af1229523c949f0a292 Mon Sep 17 00:00:00 2001 From: Daryl Borth Date: Sat, 12 Sep 2026 16:11:54 -0600 Subject: [PATCH 08/17] fix cmake checks for gamecube/wii --- cmake/ConfigureChecks.cmake | 32 +++++++++++++++++++++++++++++--- lib/compat.h | 10 +--------- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/cmake/ConfigureChecks.cmake b/cmake/ConfigureChecks.cmake index f36be3ef..6dd60ba1 100644 --- a/cmake/ConfigureChecks.cmake +++ b/cmake/ConfigureChecks.cmake @@ -1,6 +1,16 @@ include(CheckIncludeFile) include(CheckIncludeFiles) + +set(SMB2_OGC_SINGLE_NETWORK_HEADER FALSE) +if(CMAKE_SYSTEM_NAME MATCHES NintendoGameCube OR CMAKE_SYSTEM_NAME MATCHES NintendoWii) + set(SMB2_OGC_SINGLE_NETWORK_HEADER TRUE) +endif() + +if(SMB2_OGC_SINGLE_NETWORK_HEADER) + set(HAVE_ARPA_INET_H OFF) +else() check_include_file("arpa/inet.h" HAVE_ARPA_INET_H) +endif() check_include_file("dlfcn.h" HAVE_DLFCN_H) check_include_file("fcntl.h" HAVE_FCNTL_H) # CommonCrypto.framework is not always reachable on Apple platforms @@ -23,7 +33,11 @@ check_include_file("GSS/GSS.h" HAVE_GSS_GSS_H) endif() check_include_file("inttypes.h" HAVE_INTTYPES_H) check_include_file("netdb.h" HAVE_NETDB_H) +if(SMB2_OGC_SINGLE_NETWORK_HEADER) + set(HAVE_NETINET_IN_H OFF) +else() check_include_file("netinet/in.h" HAVE_NETINET_IN_H) +endif() check_include_files("sys/types.h;netinet/tcp.h" HAVE_NETINET_TCP_H) check_include_file("poll.h" HAVE_POLL_H) check_include_file("stdint.h" HAVE_STDINT_H) @@ -35,7 +49,11 @@ check_include_file("sys/ioctl.h" HAVE_SYS_IOCTL_H) if(NOT PS4) check_include_file("sys/poll.h" HAVE_SYS_POLL_H) endif() +if(SMB2_OGC_SINGLE_NETWORK_HEADER) + set(HAVE_SYS_SOCKET_H OFF) +else() check_include_file("sys/socket.h" HAVE_SYS_SOCKET_H) +endif() check_include_file("sys/stat.h" HAVE_SYS_STAT_H) check_include_file("sys/types.h" HAVE_SYS_TYPES_H) check_include_file("sys/uio.h" HAVE_SYS_UIO_H) @@ -51,11 +69,19 @@ check_include_file("errno.h" HAVE_ERRNO_H) check_include_file("stddef.h" STDC_HEADERS) include(CheckStructHasMember) +if(SMB2_OGC_SINGLE_NETWORK_HEADER) + # Same reasoning as above: probing sys/socket.h in isolation here would + # report a result for a header lib/compat.h never actually includes on + # this platform. Leave both unset so lib/compat.h's own libogc2 fallback + # (unsigned char ss_len first, matching 's 4.4BSD-style + # struct sockaddr_in layout) is the one that's compiled in, instead of + # silently deferring to a struct that's never included. + set(HAVE_SOCKADDR_LEN OFF) + set(HAVE_SOCKADDR_STORAGE OFF) + check_struct_has_member("struct linger" l_linger network.h HAVE_LINGER) +else() check_struct_has_member("struct sockaddr" sa_len sys/socket.h HAVE_SOCKADDR_LEN) check_struct_has_member("struct sockaddr_storage" ss_family sys/socket.h HAVE_SOCKADDR_STORAGE) -if(CMAKE_SYSTEM_NAME MATCHES NintendoGameCube OR CMAKE_SYSTEM_NAME MATCHES NintendoWii) -check_struct_has_member("struct linger" l_linger network.h HAVE_LINGER) -else() check_struct_has_member("struct linger" l_linger sys/socket.h HAVE_LINGER) endif() diff --git a/lib/compat.h b/lib/compat.h index efb74a4d..a2d7e98c 100644 --- a/lib/compat.h +++ b/lib/compat.h @@ -657,15 +657,7 @@ struct iovec { }; #if defined(__wii__) || defined(__gamecube__) || defined(__NDS__) #ifndef __NDS__ - -#if !defined(AF_INET) && !defined(_SYS_SOCKET_H_) && !defined(_SYS_SOCKET_H) && \ - !defined(_NETINET_IN_H_) && !defined(_NETINET_IN_H) && \ - !defined(_ARPA_INET_H_) && !defined(_ARPA_INET_H) #include -#define SMB2_HAVE_OGC_NETWORK_H 1 -#endif -#else -#define SMB2_HAVE_OGC_NETWORK_H 1 /* __NDS__ never touches ; nothing below depends on it */ #endif struct addrinfo { @@ -770,7 +762,7 @@ void smb2_freeaddrinfo(struct addrinfo *res); #define getaddrinfo smb2_getaddrinfo #define freeaddrinfo smb2_freeaddrinfo -#if !defined(__NDS__) && defined(SMB2_HAVE_OGC_NETWORK_H) +#ifndef __NDS__ int smb2_net_connect(int fd, struct sockaddr *addr, socklen_t addrlen); int smb2_net_close(int fd); int smb2_net_fcntl(int fd, int cmd, ...); From 55ec974867c28e844fbde133ed336970458dc4c5 Mon Sep 17 00:00:00 2001 From: Daryl Borth Date: Sat, 12 Sep 2026 16:13:33 -0600 Subject: [PATCH 09/17] remove comment --- cmake/ConfigureChecks.cmake | 6 ------ 1 file changed, 6 deletions(-) diff --git a/cmake/ConfigureChecks.cmake b/cmake/ConfigureChecks.cmake index 6dd60ba1..f608a985 100644 --- a/cmake/ConfigureChecks.cmake +++ b/cmake/ConfigureChecks.cmake @@ -70,12 +70,6 @@ check_include_file("stddef.h" STDC_HEADERS) include(CheckStructHasMember) if(SMB2_OGC_SINGLE_NETWORK_HEADER) - # Same reasoning as above: probing sys/socket.h in isolation here would - # report a result for a header lib/compat.h never actually includes on - # this platform. Leave both unset so lib/compat.h's own libogc2 fallback - # (unsigned char ss_len first, matching 's 4.4BSD-style - # struct sockaddr_in layout) is the one that's compiled in, instead of - # silently deferring to a struct that's never included. set(HAVE_SOCKADDR_LEN OFF) set(HAVE_SOCKADDR_STORAGE OFF) check_struct_has_member("struct linger" l_linger network.h HAVE_LINGER) From 730fc5db41bd9aaeb4bf3c344179900b729b07cf Mon Sep 17 00:00:00 2001 From: Daryl Borth Date: Sat, 12 Sep 2026 16:21:07 -0600 Subject: [PATCH 10/17] handle more headers for gamecube/wii for cmake --- cmake/ConfigureChecks.cmake | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/cmake/ConfigureChecks.cmake b/cmake/ConfigureChecks.cmake index f608a985..10f046c9 100644 --- a/cmake/ConfigureChecks.cmake +++ b/cmake/ConfigureChecks.cmake @@ -32,13 +32,21 @@ check_include_file("krb5/krb5.h" HAVE_LIBKRB5) check_include_file("GSS/GSS.h" HAVE_GSS_GSS_H) endif() check_include_file("inttypes.h" HAVE_INTTYPES_H) -check_include_file("netdb.h" HAVE_NETDB_H) +if(SMB2_OGC_SINGLE_NETWORK_HEADER) + set(HAVE_NETDB_H OFF) +else() + check_include_file("netdb.h" HAVE_NETDB_H) +endif() if(SMB2_OGC_SINGLE_NETWORK_HEADER) set(HAVE_NETINET_IN_H OFF) else() -check_include_file("netinet/in.h" HAVE_NETINET_IN_H) + check_include_file("netinet/in.h" HAVE_NETINET_IN_H) +endif() +if(SMB2_OGC_SINGLE_NETWORK_HEADER) + set(HAVE_NETINET_TCP_H OFF) +else() + check_include_files("sys/types.h;netinet/tcp.h" HAVE_NETINET_TCP_H) endif() -check_include_files("sys/types.h;netinet/tcp.h" HAVE_NETINET_TCP_H) check_include_file("poll.h" HAVE_POLL_H) check_include_file("stdint.h" HAVE_STDINT_H) check_include_file("stdio.h" HAVE_STDIO_H) From f4c28a97f26c9f8c3bdf575e36b1f72f61f90fa1 Mon Sep 17 00:00:00 2001 From: Daryl Borth Date: Sat, 12 Sep 2026 20:54:36 -0600 Subject: [PATCH 11/17] fix poll on wii/gamecube --- lib/compat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compat.c b/lib/compat.c index 73349ab9..b9c4084c 100644 --- a/lib/compat.c +++ b/lib/compat.c @@ -577,7 +577,7 @@ ssize_t readv(t_socket fd, const struct iovec* vector, int count) } #endif -#if defined(NEED_POLL) && !defined(SMB2_HAVE_OGC_POLL_H) +#ifdef NEED_POLL int poll(struct pollfd *fds, unsigned int nfds, int timo) { struct timeval timeout, *toptr; From bb18d669197f6ec5d07137e84e019fdc01794309 Mon Sep 17 00:00:00 2001 From: Daryl Borth Date: Sat, 12 Sep 2026 21:01:50 -0600 Subject: [PATCH 12/17] wii/gc - match expected signature for libogc poll --- lib/compat.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/compat.c b/lib/compat.c index b9c4084c..199675bb 100644 --- a/lib/compat.c +++ b/lib/compat.c @@ -578,7 +578,11 @@ ssize_t readv(t_socket fd, const struct iovec* vector, int count) #endif #ifdef NEED_POLL +#ifdef SMB2_HAVE_OGC_POLL_H +int poll(struct pollfd *fds, nfds_t nfds, int timo) +#else int poll(struct pollfd *fds, unsigned int nfds, int timo) +#endif { struct timeval timeout, *toptr; fd_set ifds, ofds, efds, *ip, *op; From 9bd1e201e0c41de876465bcd54ba972df2bd3c87 Mon Sep 17 00:00:00 2001 From: Daryl Borth Date: Sat, 12 Sep 2026 21:07:42 -0600 Subject: [PATCH 13/17] rollback build changes for non gc/wii builds --- Makefile.platform | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile.platform b/Makefile.platform index c7a46bd4..40f84819 100644 --- a/Makefile.platform +++ b/Makefile.platform @@ -25,7 +25,7 @@ gc_install: gc_all cmake --build build --target install nds_all: - cmake -S . -B build -G Ninja "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/NDS.cmake" + cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/NDS.cmake" cmake --build build nds_install: nds_all @@ -39,21 +39,21 @@ wii_install: wii_all cmake --build build --target install 3ds_all: - cmake -S . -B build -G Ninja "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/3DS.cmake" + cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/3DS.cmake" cmake --build build 3ds_install: 3ds_all - cmake --build build -G Ninja --target install + cmake --build build --target install wiiu_all: - cmake -S . -B build -G Ninja "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/WiiU.cmake" + cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/WiiU.cmake" cmake --build build wiiu_install: wiiu_all - cmake --build build -G Ninja --target install + cmake --build build --target install switch_all: - cmake -S . -B build -G Ninja "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/Switch.cmake" + cmake -S . -B build "-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/Switch.cmake" cmake --build build switch_install: switch_all From 92e087c15e79e6adfdb3ff9a7ba81243c3c741d0 Mon Sep 17 00:00:00 2001 From: Daryl Borth Date: Sat, 19 Sep 2026 20:49:56 -0600 Subject: [PATCH 14/17] improve handling for libogc/libogc2 differences --- cmake/ConfigureChecks.cmake | 4 +++- cmake/config.h.cmake | 2 ++ lib/compat.h | 12 +++++++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/cmake/ConfigureChecks.cmake b/cmake/ConfigureChecks.cmake index 10f046c9..5367602a 100644 --- a/cmake/ConfigureChecks.cmake +++ b/cmake/ConfigureChecks.cmake @@ -79,7 +79,9 @@ check_include_file("stddef.h" STDC_HEADERS) include(CheckStructHasMember) if(SMB2_OGC_SINGLE_NETWORK_HEADER) set(HAVE_SOCKADDR_LEN OFF) - set(HAVE_SOCKADDR_STORAGE OFF) + check_struct_has_member("struct sockaddr_storage" ss_family "sys/types.h;network.h" HAVE_SOCKADDR_STORAGE) + check_struct_has_member("struct addrinfo" ai_next "sys/types.h;network.h" HAVE_STRUCT_ADDRINFO) + check_struct_has_member("struct iovec" iov_base "sys/types.h;network.h" HAVE_STRUCT_IOVEC) check_struct_has_member("struct linger" l_linger network.h HAVE_LINGER) else() check_struct_has_member("struct sockaddr" sa_len sys/socket.h HAVE_SOCKADDR_LEN) diff --git a/cmake/config.h.cmake b/cmake/config.h.cmake index fe08fbe9..7b3921b6 100644 --- a/cmake/config.h.cmake +++ b/cmake/config.h.cmake @@ -47,6 +47,8 @@ /* Whether we have sockaddr_Storage */ #cmakedefine HAVE_SOCKADDR_STORAGE "@HAVE_SOCKADDR_STORAGE@" +#cmakedefine HAVE_STRUCT_ADDRINFO "@HAVE_STRUCT_ADDRINFO@" +#cmakedefine HAVE_STRUCT_IOVEC "@HAVE_STRUCT_IOVEC@" /* Whether we have linger */ #cmakedefine HAVE_LINGER "@HAVE_LINGER@" diff --git a/lib/compat.h b/lib/compat.h index a2d7e98c..f8a1c8e2 100644 --- a/lib/compat.h +++ b/lib/compat.h @@ -650,16 +650,25 @@ ssize_t readv(t_socket fd, const struct iovec *iov, int iovcnt); #include +#if defined(__wii__) || defined(__gamecube__) +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#endif + #if defined(__3DS__) || defined(__wii__) || defined(__gamecube__) || defined(__WIIU__) || defined(__NDS__) +#if !defined(HAVE_STRUCT_IOVEC) struct iovec { void *iov_base; size_t iov_len; -}; +}; +#endif #if defined(__wii__) || defined(__gamecube__) || defined(__NDS__) #ifndef __NDS__ #include #endif +#if !defined(HAVE_STRUCT_ADDRINFO) struct addrinfo { int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ int ai_family; /* PF_xxx */ @@ -670,6 +679,7 @@ struct addrinfo { struct sockaddr *ai_addr; /* binary address */ struct addrinfo *ai_next; /* next structure in linked list */ }; +#endif #if defined(__wii__) || defined(__gamecube__) #if !defined(HAVE_SOCKADDR_STORAGE) From f4e8ea033a6ecb837d0f6ae3eb6029d06f4d80e8 Mon Sep 17 00:00:00 2001 From: TeleTubby666 Date: Tue, 13 Oct 2026 16:54:25 +0200 Subject: [PATCH 15/17] Wii: fix hang after connect and failure on large replies in net_read/net_write On the Wii, connecting to an SMB share hangs after the tree connect, and opening a directory with many entries fails (the share root works, a large subfolder does not). A packet capture shows the server side is fine. - smb2_net_read(): libsmb2 reads in a loop until the socket reports EAGAIN, but net_read() does not return EAGAIN when no data is waiting, so smb2_service() never returns. Only read when select() reports data, otherwise return EAGAIN. - smb2_net_read()/smb2_net_write(): libogc's net_read()/net_write() copy the whole buffer through a fixed 64 KB IOS heap. A large reply (a directory listing is up to ~64 KB) fails with IPC_ENOMEM and breaks the connection. Cap a single call to 8 KB; libsmb2 resumes partial reads and writes. Only affects __wii__. --- lib/compat.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/lib/compat.c b/lib/compat.c index 199675bb..35655aa7 100644 --- a/lib/compat.c +++ b/lib/compat.c @@ -278,8 +278,22 @@ int smb2_net_fcntl(int fd, int cmd, ...) return (int)ret; } +#ifdef __wii__ +/* On the Wii, libogc's net_read()/net_write() copy the whole buffer through a + * fixed 64 KB heap shared with IOS. A request that doesn't fit (e.g. the ~64 KB + * reply to a large directory query, or a big write) fails with IPC_ENOMEM and + * leaves the SMB stream out of sync. Both calls may return fewer bytes than + * asked for, and libsmb2 resumes partial PDUs, so cap the size of a single call. */ +#define SMB2_WII_MAX_NET_CHUNK 8192 +#endif + ssize_t smb2_net_write(int fd, const void *buf, size_t count) { +#ifdef __wii__ + if (count > SMB2_WII_MAX_NET_CHUNK) { + count = SMB2_WII_MAX_NET_CHUNK; + } +#endif s32 ret = net_write(fd, buf, count); if (ret < 0) { errno = -ret; @@ -290,6 +304,26 @@ ssize_t smb2_net_write(int fd, const void *buf, size_t count) ssize_t smb2_net_read(int fd, void *buf, size_t count) { +#ifdef __wii__ + /* The socket is non-blocking, but net_read() can still block when there + * is nothing to read, so libsmb2's "read until EAGAIN" loop never ends + * and smb2_service() does not return. Only read when select() says + * there is data. */ + fd_set rd; + struct timeval tv; + + FD_ZERO(&rd); + FD_SET(fd, &rd); + tv.tv_sec = 0; + tv.tv_usec = 0; + if (net_select(fd + 1, &rd, NULL, NULL, &tv) == 0) { + errno = EAGAIN; + return -1; + } + if (count > SMB2_WII_MAX_NET_CHUNK) { + count = SMB2_WII_MAX_NET_CHUNK; + } +#endif s32 ret = net_read(fd, buf, count); if (ret < 0) { errno = -ret; From 5f9ce8e65e49994d1adde01d2855c1565a85e561 Mon Sep 17 00:00:00 2001 From: TeleTubby666 Date: Sun, 18 Oct 2026 19:08:27 +0200 Subject: [PATCH 16/17] Wii: drop the 8 KB read/write cap, keep only the EAGAIN readiness check The size limit for large replies is handled in libogc2 (net_recvfrom/net_sendto in blocks). What remains is the hang: net_read() blocks instead of returning EAGAIN when nothing is pending, so libsmb2's read loop never ends. Only read when select() reports data. --- lib/compat.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/lib/compat.c b/lib/compat.c index 35655aa7..2bb39ff3 100644 --- a/lib/compat.c +++ b/lib/compat.c @@ -278,22 +278,8 @@ int smb2_net_fcntl(int fd, int cmd, ...) return (int)ret; } -#ifdef __wii__ -/* On the Wii, libogc's net_read()/net_write() copy the whole buffer through a - * fixed 64 KB heap shared with IOS. A request that doesn't fit (e.g. the ~64 KB - * reply to a large directory query, or a big write) fails with IPC_ENOMEM and - * leaves the SMB stream out of sync. Both calls may return fewer bytes than - * asked for, and libsmb2 resumes partial PDUs, so cap the size of a single call. */ -#define SMB2_WII_MAX_NET_CHUNK 8192 -#endif - ssize_t smb2_net_write(int fd, const void *buf, size_t count) { -#ifdef __wii__ - if (count > SMB2_WII_MAX_NET_CHUNK) { - count = SMB2_WII_MAX_NET_CHUNK; - } -#endif s32 ret = net_write(fd, buf, count); if (ret < 0) { errno = -ret; @@ -320,9 +306,6 @@ ssize_t smb2_net_read(int fd, void *buf, size_t count) errno = EAGAIN; return -1; } - if (count > SMB2_WII_MAX_NET_CHUNK) { - count = SMB2_WII_MAX_NET_CHUNK; - } #endif s32 ret = net_read(fd, buf, count); if (ret < 0) { From 8c2dd1b5a167dac5f1bf63f2242d81b5a6344f3b Mon Sep 17 00:00:00 2001 From: dborth Date: Sun, 18 Oct 2026 12:49:41 -0600 Subject: [PATCH 17/17] Improve error handling in smb2_net_read function Added an exception set for error handling in smb2_net_read on Wii. --- lib/compat.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/compat.c b/lib/compat.c index 2bb39ff3..a96373d5 100644 --- a/lib/compat.c +++ b/lib/compat.c @@ -291,18 +291,21 @@ ssize_t smb2_net_write(int fd, const void *buf, size_t count) ssize_t smb2_net_read(int fd, void *buf, size_t count) { #ifdef __wii__ - /* The socket is non-blocking, but net_read() can still block when there - * is nothing to read, so libsmb2's "read until EAGAIN" loop never ends - * and smb2_service() does not return. Only read when select() says - * there is data. */ - fd_set rd; + /* On the Wii net_read() can block when there is nothing to read even + * though the socket is non-blocking, so libsmb2's "read until EAGAIN" + * loop never ends and smb2_service() does not return. Only read when + * select() says there is data (or an error/hangup, which net_read() + * then reports), otherwise report EAGAIN. */ + fd_set rd, ex; struct timeval tv; FD_ZERO(&rd); FD_SET(fd, &rd); + FD_ZERO(&ex); + FD_SET(fd, &ex); tv.tv_sec = 0; tv.tv_usec = 0; - if (net_select(fd + 1, &rd, NULL, NULL, &tv) == 0) { + if (net_select(fd + 1, &rd, NULL, &ex, &tv) == 0) { errno = EAGAIN; return -1; }