From 23f0a85446c810c168ada86f3e9bae1735f890f3 Mon Sep 17 00:00:00 2001 From: gblues Date: Sun, 6 May 2018 14:31:17 -0700 Subject: [PATCH 1/2] Implement UDP broadcast network logging on Wii U == DETAILS The broadcast address is a standard part of TCP/IP that is used to send messages to everyone on the subnet. This patch updates the logging code to do the following: 1. Derive the broadcast address from the Wii U's own IP address and subnet mask. These can all be obtained at runtime, which means we can... 2. Remove the PC_DEVELOPMENT_IP_ADDRESS define from Wii U's Makefile, because compiling in an IP is no longer needed. 3. Rewrite the net_listen script to listen for broadcast packets and print them out with timestamps. Since it's using the broadcast address, the only requirement is that the PC be on the same network subnet as the Wii U. Because of the low overhead of UDP, I've made logging on by default. This will make it a ton easier to get useful bug reports from users. --- Makefile.wiiu | 5 -- dist-scripts/wiiu-new-cores.sh | 1 - frontend/drivers/platform_wiiu.c | 81 +++++++++++++++++++++++++------- wiiu-devel.properties.template | 1 - wiiu/include/wiiu/ac.h | 24 ++++++++++ wiiu/net_listen.sh | 28 ++++++++++- wiiu/system/imports.h | 10 ++++ 7 files changed, 124 insertions(+), 26 deletions(-) create mode 100644 wiiu/include/wiiu/ac.h diff --git a/Makefile.wiiu b/Makefile.wiiu index de00b85258..9ac0deb15d 100644 --- a/Makefile.wiiu +++ b/Makefile.wiiu @@ -10,7 +10,6 @@ WIIU_HID = 1 HAVE_RUNAHEAD = 1 WIIU_LOG_RPX = 0 BUILD_DIR = objs/wiiu -PC_DEVELOPMENT_IP_ADDRESS ?= PC_DEVELOPMENT_TCP_PORT ?= ifeq ($(SALAMANDER_BUILD),1) @@ -163,10 +162,6 @@ DEFINES += -DWIIU -DMSB_FIRST -D__WUT__ DEFINES += -DHAVE_MAIN DEFINES += -DRARCH_CONSOLE -ifneq ($(PC_DEVELOPMENT_IP_ADDRESS),) - DEFINES += -DPC_DEVELOPMENT_IP_ADDRESS='"$(PC_DEVELOPMENT_IP_ADDRESS)"' -endif - ifneq ($(PC_DEVELOPMENT_TCP_PORT),) DEFINES += -DPC_DEVELOPMENT_TCP_PORT=$(PC_DEVELOPMENT_TCP_PORT) endif diff --git a/dist-scripts/wiiu-new-cores.sh b/dist-scripts/wiiu-new-cores.sh index 9f595dcfd8..6aaf07eb9d 100755 --- a/dist-scripts/wiiu-new-cores.sh +++ b/dist-scripts/wiiu-new-cores.sh @@ -137,7 +137,6 @@ buildCore() rm -f libretro_wiiu.a cp $distDir/$core libretro_wiiu.a make -f Makefile.wiiu \ - PC_DEVELOPMENT_IP_ADDRESS=$PC_DEVELOPMENT_IP_ADDRESS \ PC_DEVELOPMENT_TCP_PORT=$PC_DEVELOPMENT_TCP_PORT \ -j3 || exit 1 diff --git a/frontend/drivers/platform_wiiu.c b/frontend/drivers/platform_wiiu.c index 1d03602533..3a47fb576f 100644 --- a/frontend/drivers/platform_wiiu.c +++ b/frontend/drivers/platform_wiiu.c @@ -23,6 +23,7 @@ #include #include +#include #include #ifndef IS_SALAMANDER @@ -314,9 +315,10 @@ static void main_loop(void); static void main_teardown(void); static void init_network(void); +static void deinit_network(void); static void init_logging(void); static void deinit_logging(void); -static void wiiu_log_init(const char *ipString, int port); +static void wiiu_log_init(int port); static void wiiu_log_deinit(void); static ssize_t wiiu_log_write(struct _reent *r, void *fd, const char *ptr, size_t len); static void init_pad_libraries(void); @@ -324,10 +326,14 @@ static void deinit_pad_libraries(void); static void SaveCallback(void); static bool swap_is_pending(void *start_time); +static struct sockaddr_in broadcast; static int wiiu_log_socket = -1; static volatile int wiiu_log_lock = 0; -#if defined(PC_DEVELOPMENT_IP_ADDRESS) && defined(PC_DEVELOPMENT_TCP_PORT) +#if !defined(PC_DEVELOPMENT_TCP_PORT) +#define PC_DEVELOPMENT_TCP_PORT 4405 +#endif + static devoptab_t dotab_stdout = { "stdout_net", /* device name */ @@ -337,7 +343,6 @@ static devoptab_t dotab_stdout = wiiu_log_write, /* device write */ NULL, /* ... */ }; -#endif /* defined(PC_DEVELOPMENT_IP_ADDRESS) && defined(PC_DEVELOPMENT_TCP_PORT) */ int main(int argc, char **argv) { @@ -400,6 +405,7 @@ static void main_teardown(void) deinit_pad_libraries(); ProcUIShutdown(); deinit_logging(); + deinit_network(); } static void main_loop(void) @@ -457,6 +463,8 @@ static bool swap_is_pending(void *start_time) static void init_network(void) { + ACInitialize(); + ACConnect(); #ifdef IS_SALAMANDER socket_lib_init(); #else @@ -464,13 +472,36 @@ static void init_network(void) #endif /* IS_SALAMANDER */ } +static void deinit_network(void) +{ + ACClose(); + ACFinalize(); +} + +int getBroadcastAddress(ACIpAddress *broadcast) +{ + ACIpAddress myIp, mySubnet; + ACResult result; + + if(broadcast == NULL) + return -1; + + result = ACGetAssignedAddress(&myIp); + if(result < 0) + return -1; + result = ACGetAssignedSubnet(&mySubnet); + if(result < 0) + return -1; + + *broadcast = myIp | (~mySubnet); + return 0; +} + static void init_logging(void) { -#if defined(PC_DEVELOPMENT_IP_ADDRESS) && defined(PC_DEVELOPMENT_TCP_PORT) - wiiu_log_init(PC_DEVELOPMENT_IP_ADDRESS, PC_DEVELOPMENT_TCP_PORT); + wiiu_log_init(PC_DEVELOPMENT_TCP_PORT); devoptab_list[STD_OUT] = &dotab_stdout; devoptab_list[STD_ERR] = &dotab_stdout; -#endif /* defined(PC_DEVELOPMENT_IP_ADDRESS) && defined(PC_DEVELOPMENT_TCP_PORT) */ } static void deinit_logging(void) @@ -478,16 +509,31 @@ static void deinit_logging(void) fflush(stdout); fflush(stderr); -#if defined(PC_DEVELOPMENT_IP_ADDRESS) && defined(PC_DEVELOPMENT_TCP_PORT) wiiu_log_deinit(); -#endif /* defined(PC_DEVELOPMENT_IP_ADDRESS) && defined(PC_DEVELOPMENT_TCP_PORT) */ } +static int broadcast_init(int port) +{ + ACIpAddress broadcast_ip; + if(getBroadcastAddress(&broadcast_ip) < 0) + return -1; -static void wiiu_log_init(const char *ipString, int port) + memset(&broadcast, 0, sizeof(broadcast)); + broadcast.sin_family = AF_INET; + broadcast.sin_port = htons(port); + broadcast.sin_addr.s_addr = htonl(broadcast_ip); + + return 0; +} + +static void wiiu_log_init(int port) { wiiu_log_lock = 0; - wiiu_log_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if(broadcast_init(port) < 0) + return; + + wiiu_log_socket = socket(AF_INET, SOCK_DGRAM, 0); if(wiiu_log_socket < 0) return; @@ -495,15 +541,14 @@ static void wiiu_log_init(const char *ipString, int port) struct sockaddr_in connect_addr; memset(&connect_addr, 0, sizeof(connect_addr)); connect_addr.sin_family = AF_INET; - connect_addr.sin_port = port; - inet_aton(ipString, &connect_addr.sin_addr); + connect_addr.sin_port = 0; + connect_addr.sin_addr.s_addr = htonl(INADDR_ANY); - if(connect(wiiu_log_socket, - (struct sockaddr *)&connect_addr, - sizeof(connect_addr)) < 0) + if( bind(wiiu_log_socket, (struct sockaddr *)&connect_addr, sizeof(connect_addr)) < 0) { socketclose(wiiu_log_socket); wiiu_log_socket = -1; + return; } } @@ -541,7 +586,7 @@ void net_print(const char *str) void net_print_exp(const char *str) { - send(wiiu_log_socket, str, strlen(str), 0); + sendto(wiiu_log_socket, str, strlen(str), 0, (struct sockaddr *)&broadcast, sizeof(broadcast)); } static ssize_t wiiu_log_write(struct _reent *r, void *fd, const char *ptr, size_t len) @@ -559,8 +604,8 @@ static ssize_t wiiu_log_write(struct _reent *r, void *fd, const char *ptr, size_ while(remaining > 0) { - int block = remaining < 1400 ? remaining : 1400; - ret = send(wiiu_log_socket, ptr, block, 0); + int block = remaining < 1472 ? remaining : 1472; + ret = sendto(wiiu_log_socket, ptr, block, 0, (struct sockaddr *)&broadcast, sizeof(broadcast)); if(ret < 0) break; diff --git a/wiiu-devel.properties.template b/wiiu-devel.properties.template index 33fa40b40f..5a778f0503 100644 --- a/wiiu-devel.properties.template +++ b/wiiu-devel.properties.template @@ -5,6 +5,5 @@ # port number. # -PC_DEVELOPMENT_IP_ADDRESS= PC_DEVELOPMENT_TCP_PORT=4405 WIIU_IP_ADDRESS= diff --git a/wiiu/include/wiiu/ac.h b/wiiu/include/wiiu/ac.h new file mode 100644 index 0000000000..962b3ad8f0 --- /dev/null +++ b/wiiu/include/wiiu/ac.h @@ -0,0 +1,24 @@ +#pragma once + +/** + * These functions manage the Wii U's AutoConnect library--basically + * connecting to the LAN/Internet via the network profile set up in + * System Preferences. + */ + + +typedef int ACResult; +enum { + AC_FAILED = -1, + AC_OK = 0, + AC_BUSY = 1 +}; + +typedef unsigned long ACIpAddress; + +ACResult ACInitialize(void); +void ACFinalize(void); +ACResult ACConnect(void); +ACResult ACClose(void); +ACResult ACGetAssignedAddress(ACIpAddress *addr); +ACResult ACGetAssignedSubnet(ACIpAddress *addr); diff --git a/wiiu/net_listen.sh b/wiiu/net_listen.sh index 04271637b8..f023734305 100755 --- a/wiiu/net_listen.sh +++ b/wiiu/net_listen.sh @@ -8,6 +8,10 @@ script_dir=$(dirname $(readlink -f $0)) +IP=$(which ip 2>/dev/null | grep '^/') +IFCONFIG=$(which ifconfig 2>/dev/null | grep '^/') +TS=$(which ts 2>/dev/null | grep '^/') + # Using wiiu-devel.properties ensure your make file and this listen script # stay in sync with each other. # @@ -23,13 +27,35 @@ fi exit_listen_loop=0 +getBroadcastIp() +{ + if [ ! -z "$IP" ]; then + $IP addr show | grep 'inet' |grep 'brd' | awk '{print $4}' + elif [ ! -z "$IFCONFIG" ]; then + $IFCONFIG | grep 'broadcast' | awk '{print $6}' + else + echo "255.255.255.255" + fi +} + # # This prevents a tug-of-war between bash and netcat as to who gets the # CTRL+C code. # trap 'exit_listen_loop=1' SIGINT +if [ -z "$TS" ]; then + echo "[WARN] 'ts' not found. Install the moreutils package to get timestamps." +fi + +broadcast=$(getBroadcastIp) +echo "Listening for UDP packets on broadcast IP: $broadcast" + while [ $exit_listen_loop -eq 0 ]; do echo ========= `date` ========= - netcat -p $PC_DEVELOPMENT_TCP_PORT -l + if [ -z "$TS" ]; then + netcat -kluw 0 $broadcast $PC_DEVELOPMENT_TCP_PORT + else + netcat -kluw 0 $broadcast $PC_DEVELOPMENT_TCP_PORT |ts '[%Y-%m-%d %H:%M:%.S]' + fi done diff --git a/wiiu/system/imports.h b/wiiu/system/imports.h index 5a2f3daf77..0335c18755 100644 --- a/wiiu/system/imports.h +++ b/wiiu/system/imports.h @@ -203,6 +203,16 @@ IMPORT(GX2GetSwapStatus); IMPORT_END(); +/* nn_ac */ +IMPORT_BEGIN(nn_ac); +IMPORT(ACInitialize); +IMPORT(ACFinalize); +IMPORT(ACConnect); +IMPORT(ACClose); +IMPORT(ACGetAssignedAddress); +IMPORT(ACGetAssignedSubnet); +IMPORT_END(); + /* proc_ui */ IMPORT_BEGIN(proc_ui); From 5b3dd70ac37ed5854309173afeda78737fd6bd1c Mon Sep 17 00:00:00 2001 From: gblues Date: Sun, 6 May 2018 19:08:32 -0700 Subject: [PATCH 2/2] Use a different packet size == DETAILS We had some disagreement on what packet size to use. The maximum packet size varies depending on the actual network hardware in use; the typical Ethernet value is relatively safe, but not 100% compatible. RFC 791 does, however, define a minimum datagram size that all IP hosts must be able to handle--and it's large enough for our needs, since we're generally not writing more than maybe 100 bytes at a time anyway. I also did a little bit of cleanup for readability. --- frontend/drivers/platform_wiiu.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/frontend/drivers/platform_wiiu.c b/frontend/drivers/platform_wiiu.c index 3a47fb576f..1960e12ec3 100644 --- a/frontend/drivers/platform_wiiu.c +++ b/frontend/drivers/platform_wiiu.c @@ -589,6 +589,11 @@ void net_print_exp(const char *str) sendto(wiiu_log_socket, str, strlen(str), 0, (struct sockaddr *)&broadcast, sizeof(broadcast)); } +/* RFC 791 specifies that any IP host must be able to receive a datagram of 576 bytes. + * Since we're generally never logging more than a line or two's worth of data (~100 bytes) + * this is a reasonable size for our use. */ +#define DGRAM_SIZE 576 + static ssize_t wiiu_log_write(struct _reent *r, void *fd, const char *ptr, size_t len) { if( wiiu_log_socket < 0) @@ -599,19 +604,19 @@ static ssize_t wiiu_log_write(struct _reent *r, void *fd, const char *ptr, size_ wiiu_log_lock = 1; - int ret; + int sent; int remaining = len; while(remaining > 0) { - int block = remaining < 1472 ? remaining : 1472; - ret = sendto(wiiu_log_socket, ptr, block, 0, (struct sockaddr *)&broadcast, sizeof(broadcast)); + int block = remaining < DGRAM_SIZE ? remaining : DGRAM_SIZE; + sent = sendto(wiiu_log_socket, ptr, block, 0, (struct sockaddr *)&broadcast, sizeof(broadcast)); - if(ret < 0) + if(sent < 0) break; - remaining -= ret; - ptr += ret; + remaining -= sent; + ptr += sent; } wiiu_log_lock = 0;