diff --git a/Makefile.platform b/Makefile.platform index a706f165..40f84819 100644 --- a/Makefile.platform +++ b/Makefile.platform @@ -18,7 +18,7 @@ .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 @@ -32,7 +32,7 @@ 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 diff --git a/cmake/ConfigureChecks.cmake b/cmake/ConfigureChecks.cmake index f36be3ef..5367602a 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 @@ -22,9 +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) -check_include_file("netinet/in.h" HAVE_NETINET_IN_H) -check_include_files("sys/types.h;netinet/tcp.h" HAVE_NETINET_TCP_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) +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_file("poll.h" HAVE_POLL_H) check_include_file("stdint.h" HAVE_STDINT_H) check_include_file("stdio.h" HAVE_STDIO_H) @@ -35,7 +57,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 +77,15 @@ check_include_file("errno.h" HAVE_ERRNO_H) check_include_file("stddef.h" STDC_HEADERS) include(CheckStructHasMember) +if(SMB2_OGC_SINGLE_NETWORK_HEADER) + set(HAVE_SOCKADDR_LEN 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) 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/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.c b/lib/compat.c index 66ba3bbd..a96373d5 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,153 @@ 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) +{ + 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) +{ + 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) +{ +#ifdef __wii__ + /* 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, &ex, &tv) == 0) { + errno = EAGAIN; + return -1; + } +#endif + s32 ret = net_read(fd, buf, count); + if (ret < 0) { + errno = -ret; + return -1; + } + return ret; +} + +int smb2_net_socket(int domain, int type, int protocol) +{ + 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__ - return net_getsockopt(sockfd, level, optname, optval, optlen); -#else - return 0; + 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 @@ -460,7 +598,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; diff --git a/lib/compat.h b/lib/compat.h index 638225b2..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,29 @@ 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) +/* + * 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 char ss_len; + unsigned char ss_family; + char __ss_pad1[_SS_PAD1SIZE]; + double __ss_align; + char __ss_pad2[_SS_PAD2SIZE]; +}; +#endif +#endif #endif #define sockaddr_in6 sockaddr_in @@ -741,16 +773,41 @@ void smb2_freeaddrinfo(struct addrinfo *res); #define freeaddrinfo smb2_freeaddrinfo #ifndef __NDS__ -#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 -#endif - +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_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 + +#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; @@ -758,6 +815,7 @@ struct pollfd { }; int poll(struct pollfd *fds, unsigned int nfds, int timo); +#endif #endif diff --git a/lib/socket.c b/lib/socket.c index fe8c394b..04d825e7 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; + net_ioctl(fd, FIONBIO, &one); #else unsigned v; v = fcntl(fd, F_GETFL, 0);