From c5f9fc0a342ed28b793b64fcf35dc950d4a098d8 Mon Sep 17 00:00:00 2001 From: Nathan Strong Date: Thu, 11 Oct 2018 15:37:15 -0700 Subject: [PATCH] WiiU: fix network information == DETAILS For local netplay, it's useful to have your IP address easily available. This commit makes the Information > Network Information menu display the Wii U's IP address. Change summary: - Fix the logging init to be reentrant to avoid socket consumption - Add implementation of POSIX `getifaddrs()` and `freeifaddrs()` to `missing_libc_functions.c` - Remove compiler directives protecting the code paths that call `getifaddrs()` from being used in Wii U builds == TESTING Have tested locally, successfully get IP address information in the Information > Network Information. I think this may also fix NAT traversal. Will need to be tested. --- Makefile.wiiu | 2 - frontend/drivers/platform_wiiu.c | 3 + libretro-common/net/net_natt.c | 2 +- menu/menu_displaylist.c | 4 +- wiiu/include/arpa/inet.h | 1 + wiiu/include/ifaddrs.h | 18 ++++ wiiu/system/missing_libc_functions.c | 129 +++++++++++++++++++++++++++ 7 files changed, 154 insertions(+), 5 deletions(-) create mode 100644 wiiu/include/ifaddrs.h diff --git a/Makefile.wiiu b/Makefile.wiiu index 83c890e2a8..81bd02c697 100644 --- a/Makefile.wiiu +++ b/Makefile.wiiu @@ -137,8 +137,6 @@ endif WANT_IOSUHAX = 1 include Makefile.common - BLACKLIST := $(LIBRETRO_COMM_DIR)/net/net_ifinfo.o - OBJ := $(filter-out $(BLACKLIST),$(OBJ)) OBJ += gfx/drivers/gx2_gfx.o OBJ += gfx/drivers_font/wiiu_font.o diff --git a/frontend/drivers/platform_wiiu.c b/frontend/drivers/platform_wiiu.c index 1976beb86a..69e9ffc7c4 100644 --- a/frontend/drivers/platform_wiiu.c +++ b/frontend/drivers/platform_wiiu.c @@ -530,6 +530,9 @@ static void wiiu_log_init(int port) { wiiu_log_lock = 0; + if(wiiu_log_socket >= 0) + return; + if(broadcast_init(port) < 0) return; diff --git a/libretro-common/net/net_natt.c b/libretro-common/net/net_natt.c index 14dbdeeb8b..b6dc5c91b4 100644 --- a/libretro-common/net/net_natt.c +++ b/libretro-common/net/net_natt.c @@ -184,7 +184,7 @@ static bool natt_open_port(struct natt_status *status, bool natt_open_port_any(struct natt_status *status, uint16_t port, enum socket_protocol proto) { -#if !defined(HAVE_SOCKET_LEGACY) && !defined(WIIU) && !defined(SWITCH) +#if !defined(HAVE_SOCKET_LEGACY) && !defined(SWITCH) size_t i; char port_str[6]; struct net_ifinfo list; diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 96b64a43a2..d816d94af0 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -97,7 +97,7 @@ static enum msg_hash_enums new_type = MSG_UNKNOWN; * function pointer callback functions that don't necessarily * call each other. */ -#if !defined(HAVE_SOCKET_LEGACY) && !defined(WIIU) && !defined(SWITCH) +#if !defined(HAVE_SOCKET_LEGACY) && !defined(SWITCH) #include static int menu_displaylist_parse_network_info(menu_displaylist_info_t *info) @@ -4834,7 +4834,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) break; case DISPLAYLIST_NETWORK_INFO: menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); -#if defined(HAVE_NETWORKING) && !defined(HAVE_SOCKET_LEGACY) && !defined(WIIU) && !defined(SWITCH) +#if defined(HAVE_NETWORKING) && !defined(HAVE_SOCKET_LEGACY) && !defined(SWITCH) count = menu_displaylist_parse_network_info(info); #endif diff --git a/wiiu/include/arpa/inet.h b/wiiu/include/arpa/inet.h index fa505565c6..2a79d9526d 100644 --- a/wiiu/include/arpa/inet.h +++ b/wiiu/include/arpa/inet.h @@ -6,6 +6,7 @@ extern "C" { #endif #include +#include char *inet_ntoa(struct in_addr in); const char *inet_ntop(int af, const void *cp, char *buf, socklen_t len); diff --git a/wiiu/include/ifaddrs.h b/wiiu/include/ifaddrs.h new file mode 100644 index 0000000000..bf78a06c02 --- /dev/null +++ b/wiiu/include/ifaddrs.h @@ -0,0 +1,18 @@ +#ifndef _IFADDRS_H_ +#define _IFADDRS_H_ + +#include + +struct ifaddrs { + struct ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + struct sockaddr *ifa_addr; + struct sockaddr *ifa_netmask; + struct sockaddr *ifa_dstaddr; + void *ifa_data; +}; + +int getifaddrs(struct ifaddrs **ifap); +void freeifaddrs(struct ifaddrs *ifp); +#endif // _IFADDRS_H_ \ No newline at end of file diff --git a/wiiu/system/missing_libc_functions.c b/wiiu/system/missing_libc_functions.c index bc47266b3a..4a35405a10 100644 --- a/wiiu/system/missing_libc_functions.c +++ b/wiiu/system/missing_libc_functions.c @@ -5,10 +5,18 @@ #include #include #include +#include +#include #include #include +#include #include #include +#include +#include +#include + +#include /* This is usually in libogc; we can't use that on wiiu */ int usleep(useconds_t microseconds) { @@ -112,3 +120,124 @@ int clock_gettime(clockid_t clk_id, struct timespec* tp) { } return 0; } + +/** + * Implementation of getifaddrs() and freeifaddrs() for WiiU. + */ + +// the Wii U doesn't define an interface name, so we'll use something generic. +static const char *wiiu_iface_name = "eth0"; + +/** + * Allocate and zeroize the hunk of memory for the ifaddrs struct and its contents; the struct will be filled + * out later. + * + * returns NULL if any of the memory allocations fail. + */ +static struct ifaddrs *buildEmptyIfa() { + struct ifaddrs *result = (struct ifaddrs *)malloc(sizeof(struct ifaddrs)); + if(result != NULL) { + memset(result, 0, sizeof(struct ifaddrs)); + result->ifa_name = strdup(wiiu_iface_name); + result->ifa_addr = (struct sockaddr *)malloc(sizeof(struct sockaddr_in)); + result->ifa_netmask = (struct sockaddr *)malloc(sizeof(struct sockaddr_in)); + result->ifa_dstaddr = (struct sockaddr *)malloc(sizeof(struct sockaddr_in)); + + if(!result->ifa_name || !result->ifa_addr || !result->ifa_netmask || !result->ifa_dstaddr) + goto error; + + memset(result->ifa_addr, 0, sizeof(struct sockaddr_in)); + result->ifa_addr->sa_family = AF_INET; + memset(result->ifa_netmask, 0, sizeof(struct sockaddr_in)); + result->ifa_netmask->sa_family = AF_INET; + memset(result->ifa_dstaddr, 0, sizeof(struct sockaddr_in)); + result->ifa_dstaddr->sa_family = AF_INET; + } + + return result; + error: + freeifaddrs(result); + return NULL; +} + +static int getAssignedAddress(struct sockaddr_in *sa) { + if(sa == NULL) + return -1; + ACIpAddress addr; + int result = ACGetAssignedAddress(&addr); + if(result == 0) + sa->sin_addr.s_addr = addr; + + return result; +} + +static int getAssignedSubnet(struct sockaddr_in *sa) { + if(sa == NULL) + return -1; + + ACIpAddress mask; + int result = ACGetAssignedSubnet(&mask); + if(result == 0) + sa->sin_addr.s_addr = mask; + + return result; +} + +static int getBroadcastAddress(struct sockaddr_in *sa, struct sockaddr_in *addr, struct sockaddr_in *mask) { + if(!sa || !addr || !mask) + return -1; + + sa->sin_addr.s_addr = addr->sin_addr.s_addr | (~mask->sin_addr.s_addr); + return 0; +} + +static struct ifaddrs *getWiiUInterfaceAddressData(void) { + struct ifaddrs *result = buildEmptyIfa(); + + if(result != NULL) { + if(getAssignedAddress((struct sockaddr_in *)result->ifa_addr) < 0 || + getAssignedSubnet((struct sockaddr_in *)result->ifa_netmask) < 0 || + getBroadcastAddress((struct sockaddr_in *)result->ifa_dstaddr, + (struct sockaddr_in *)result->ifa_addr, + (struct sockaddr_in *)result->ifa_netmask) < 0) { + goto error; + } + } + + return result; + + error: + freeifaddrs(result); + return NULL; +} + +int getifaddrs(struct ifaddrs **ifap) { + if(ifap == NULL) { + return -1; + } + *ifap = getWiiUInterfaceAddressData(); + + return (*ifap == NULL) ? -1 : 0; +} + +void freeifaddrs(struct ifaddrs *ifp) { + if(ifp != NULL) { + if(ifp->ifa_name) { + free(ifp->ifa_name); + ifp->ifa_name = NULL; + } + if(ifp->ifa_addr) { + free(ifp->ifa_addr); + ifp->ifa_addr = NULL; + } + if(ifp->ifa_netmask) { + free(ifp->ifa_netmask); + ifp->ifa_netmask = NULL; + } + if(ifp->ifa_dstaddr) { + free(ifp->ifa_dstaddr); + ifp->ifa_dstaddr = NULL; + } + free(ifp); + } +} \ No newline at end of file