From ebced71ec35e0de4fcb976039a63c8a9ceb0cad6 Mon Sep 17 00:00:00 2001 From: Dave Murphy Date: Mon, 19 Mar 2018 20:42:58 +0000 Subject: [PATCH] Add nxlink support (#27) * Add nxlink support * use libnx nro.h * make sure path doesn't overflow * convert indentation to spaces --- Makefile.nx | 2 +- Makefile.pc | 9 +- common/common.h | 12 +- common/math.h | 2 +- common/menu.c | 86 ++++-- common/menu.h | 27 +- common/netloader.c | 575 ++++++++++++++++++++++++++++++++++++++ common/netloader.h | 5 + common/nro.h | 54 ---- nx_main/loaders/builtin.c | 18 +- nx_main/main.c | 14 +- pc_main/main.cpp | 13 +- 12 files changed, 723 insertions(+), 94 deletions(-) create mode 100644 common/netloader.c create mode 100644 common/netloader.h delete mode 100644 common/nro.h diff --git a/Makefile.nx b/Makefile.nx index 2f8cbd4..6f3da32 100644 --- a/Makefile.nx +++ b/Makefile.nx @@ -53,7 +53,7 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 ASFLAGS := -g $(ARCH) LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) -LIBS := -lnx -lm +LIBS := -lnx -lm -lz #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing diff --git a/Makefile.pc b/Makefile.pc index 43c50df..5709374 100644 --- a/Makefile.pc +++ b/Makefile.pc @@ -4,6 +4,10 @@ ifeq ($(strip $(HOST_OS)),Darwin) BIN2S_FLAGS := --apple-llvm endif +ifneq (,$(findstring MINGW,$(HOST_OS))) +EXTRA_CFLAGS="-D__USE_MINGW_ANSI_STDIO" +EXTRA_LDFLAGS="-lws2_32" +endif # canned command sequence for binary data #--------------------------------------------------------------------------------- @@ -18,11 +22,12 @@ test : pc_main/main.cpp pc_main/pc_launch.c \ common/menu.c common/font.c common/language.c common/launch.c \ common/menu-entry.c common/menu-list.c common/message-box.c common/text.c \ common/nanojpeg.c common/ui.c common/math.c common/theme.c \ + common/netloader.c \ build_pc/tahoma24.o build_pc/tahoma12.o build_pc/interuimedium20.o build_pc/interuimedium30.o \ build_pc/interuiregular14.o build_pc/interuiregular18.o \ build_pc/invalid_icon.bin.o build_pc/folder_icon.bin.o \ build_pc/button_a_light.bin.o build_pc/button_a_dark.bin.o build_pc/button_b_light.bin.o build_pc/button_b_dark.bin.o build_pc/hbmenu_logo_light.bin.o build_pc/hbmenu_logo_dark.bin.o - gcc -Wall -O2 -g0 -DVERSION=\"$(APP_VERSION)\" $^ -lsfml-graphics -lsfml-window -lsfml-system -lstdc++ -lm -I. -Ibuild_pc -o $@ + gcc -Wall -O2 -g -DVERSION=\"$(APP_VERSION)\" $(EXTRA_CFLAGS) $^ -lsfml-graphics -lsfml-window -lsfml-system -lstdc++ -lm -lz $(EXTRA_LDFLAGS) -I. -I$(DEVKITPRO)/libnx/include -Ibuild_pc -g -o $@ build_pc/tahoma12.o : data/tahoma12.nxfnt mkdir -p $(dir $@) @@ -73,7 +78,7 @@ build_pc/button_a_dark.bin.o : data/button_a_dark.bin mkdir -p $(dir $@) @echo $(notdir $<) @$(bin2o) - + build_pc/button_b_light.bin.o : data/button_b_light.bin mkdir -p $(dir $@) @echo $(notdir $<) diff --git a/common/common.h b/common/common.h index bc39791..3fd9212 100644 --- a/common/common.h +++ b/common/common.h @@ -23,6 +23,16 @@ typedef uint8_t u8; typedef uint32_t u32; typedef uint64_t u64; + +#ifdef _WIN32 +#define DIRECTORY_SEPARATOR_CHAR '\\' +static const char DIRECTORY_SEPARATOR[] = "\\"; +#else +#define DIRECTORY_SEPARATOR_CHAR '/' +static const char DIRECTORY_SEPARATOR[] = "/"; +#endif + + #define M_TAU (2*M_PI) typedef union { @@ -44,7 +54,7 @@ typedef union { // when building for pc we need to include nro.h separately #ifndef __SWITCH__ -#include "nro.h" +#include #endif void menuStartup(); diff --git a/common/math.h b/common/math.h index 08b7add..672f04d 100644 --- a/common/math.h +++ b/common/math.h @@ -4,6 +4,6 @@ float approxSin(float x); -inline float clamp(float x, float min, float max) { +static inline float clamp(float x, float min, float max) { return fmin(fmax(x, min), max); } \ No newline at end of file diff --git a/common/menu.c b/common/menu.c index 20c5cda..182f5a8 100644 --- a/common/menu.c +++ b/common/menu.c @@ -1,9 +1,16 @@ #include #include "common.h" +#include "netloader.h" #include "invalid_icon_bin.h" #include "folder_icon_bin.h" +char rootPath[PATH_MAX]; + +char *menuGetRootPath() { + return rootPath; +} + void launchMenuEntryTask(menuEntry_s* arg) { menuEntry_s* me = arg; @@ -14,7 +21,29 @@ void launchMenuEntryTask(menuEntry_s* arg) launchMenuEntry(me); } +static enum +{ + HBMENU_DEFAULT, + HBMENU_NETLOADER_ACTIVE, + HBMENU_NETLOADER_ERROR, + HBMENU_NETLOADER_SUCCESS, +} hbmenu_state = HBMENU_DEFAULT; +void launchMenuNetloaderTask() { + if(hbmenu_state == HBMENU_DEFAULT) + if(netloader_activate() == 0) hbmenu_state = HBMENU_NETLOADER_ACTIVE; +} + +void launchMenuBackTask() +{ + if(hbmenu_state == HBMENU_NETLOADER_ACTIVE) { + netloader_deactivate(); + hbmenu_state = HBMENU_DEFAULT; + } else { + menuScan(".."); + } + +} //Draws an RGB888 or RGBA8888 image. static void drawImage(int x, int y, int width, int height, const uint8_t *image, ImageMode mode) { @@ -35,7 +64,7 @@ static void drawImage(int x, int y, int width, int height, const uint8_t *image, current_color = MakeColor(image[pos+0], image[pos+1], image[pos+2], image[pos+3]); break; } - + DrawPixel(x+tmpx, y+tmpy, current_color); } } @@ -59,7 +88,7 @@ static void drawEntry(menuEntry_s* me, int off_x, int is_active) { int border_start_x, border_end_x; int border_start_y, border_end_y; color_t border_color = MakeColor(255, 255, 255, 255); - + int shadow_start_y, shadow_y; int shadow_inset; color_t shadow_color; @@ -91,7 +120,7 @@ static void drawEntry(menuEntry_s* me, int off_x, int is_active) { Draw4PixelsRaw(x, end_y +2, border_color); Draw4PixelsRaw(x, start_y-3, border_color); Draw4PixelsRaw(x, end_y +3, border_color); - + if (is_active) { Draw4PixelsRaw(x, start_y-3, border_color); Draw4PixelsRaw(x, end_y +3, border_color); @@ -191,7 +220,7 @@ static void drawEntry(menuEntry_s* me, int off_x, int is_active) { DrawText(interuiregular14, start_x, start_y + 28 + 30, themeCurrent.textColor, tmpstr); memset(tmpstr, 0, sizeof(tmpstr)); snprintf(tmpstr, sizeof(tmpstr)-1, "%s: %s", textGetString(StrId_AppInfo_Version), me->version); - DrawText(interuiregular14, start_x, start_y + 28 + 30 + 18 + 6, themeCurrent.textColor, tmpstr); + DrawText(interuiregular14, start_x, start_y + 28 + 30 + 18 + 6, themeCurrent.textColor, tmpstr); } } } @@ -219,15 +248,16 @@ void computeFrontGradient(color_t baseColor, int height) { } void menuStartup() { - const char *path; + #ifdef __SWITCH__ - path = "sdmc:/switch"; + strcpy(rootPath,"sdmc:"); #else - path = "switch"; + getcwd(rootPath, PATH_MAX); #endif + sprintf(rootPath,"%s%s%s" , rootPath, DIRECTORY_SEPARATOR, "switch" ); - menuScan(path); + menuScan(rootPath); folder_icon_small = downscaleImg(folder_icon_bin, 256, 256, 140, 140, IMAGE_MODE_RGB24); invalid_icon_small = downscaleImg(invalid_icon_bin, 256, 256, 140, 140, IMAGE_MODE_RGB24); @@ -243,14 +273,14 @@ void drawWave(int id, float timer, color_t color, int height, float phase, float int x, y; float wave_top_y, alpha, one_minus_alpha; color_t existing_color, new_color; - + height = 720 - height; for (x=0; x<1280; x++) { wave_top_y = approxSin(x*speed/1280.0+timer+phase) * 10.0 + height; for (y=wave_top_y; y<720; y++) { - if (id != 2 && y > wave_top_y + 30) + if (id != 2 && y > wave_top_y + 30) break; alpha = y-wave_top_y; @@ -258,11 +288,11 @@ void drawWave(int id, float timer, color_t color, int height, float phase, float if (themeCurrent.enableWaveBlending) { existing_color = FetchPixelColor(x, y); new_color = waveBlendAdd(existing_color, color, clamp(alpha, 0.0, 1.0) * 0.3); - } - else if (alpha >= 0.3) { + } + else if (alpha >= 0.3) { if (id == 2) { new_color = frontWaveGradient[y]; - } + } else { // no anti-aliasing new_color = color; } @@ -282,29 +312,29 @@ void drawWave(int id, float timer, color_t color, int height, float phase, float void drawTime() { char timeString[9]; - + time_t unixTime = time(NULL); struct tm* timeStruct = gmtime((const time_t *)&unixTime); - + int hours = timeStruct->tm_hour; int minutes = timeStruct->tm_min; int seconds = timeStruct->tm_sec; - + sprintf(timeString, "%02d:%02d:%02d", hours, minutes, seconds); DrawText(interuimedium20, 1280 - (9 * 16) - 30, 30, MakeColor(255, 255, 255, 255), timeString); - + } void drawBackBtn(menu_s* menu, bool emptyDir) { int x_image = 1280 - 252 - 30 - 32; int x_text = 1280 - 216 - 30 - 32; - + if(emptyDir) { x_image = 1280 - 126 - 30 - 32; x_text = 1280 - 90 - 30 - 32; } - + #ifdef __SWITCH__ if (strcmp( menu->dirname, "sdmc:/") != 0) #else @@ -352,9 +382,23 @@ void menuLoop() { //drawTime(); - if (menu->nEntries==0) + if (menu->nEntries==0 || hbmenu_state == HBMENU_NETLOADER_ACTIVE) { - DrawText(interuiregular14, 64, 128, themeCurrent.textColor, textGetString(StrId_NoAppsFound_Msg)); + if (hbmenu_state == HBMENU_NETLOADER_ACTIVE) { + menuEntry_s me; + menuEntryInit(&me,ENTRY_TYPE_FILE); + + int netloader_result = netloader_loop(&me); + if( netloader_result != 0) { + hbmenu_state = HBMENU_DEFAULT; + if (netloader_result == 1) { + menuCreateMsgBox(240,240, textGetString(StrId_Loading)); + launchMenuEntryTask(&me); + } + } + } else { + DrawText(interuiregular14, 64, 128, themeCurrent.textColor, textGetString(StrId_NoAppsFound_Msg)); + } drawBackBtn(menu, true); } else diff --git a/common/menu.h b/common/menu.h index 31247f3..6c8be14 100644 --- a/common/menu.h +++ b/common/menu.h @@ -1,5 +1,15 @@ #pragma once +#ifndef _WIN32 +#include +#else +#define WIN32_LEAN_AND_MEAN +#include +#include +#undef DrawText +#undef MessageBox +#endif + #define ENTRY_NAMELENGTH 0x200 #define ENTRY_AUTHORLENGTH 0x100 #define ENTRY_VERLENGTH 0x10 @@ -27,6 +37,7 @@ typedef struct { char* dst; uint32_t buf[ENTRY_ARGBUFSIZE/sizeof(uint32_t)]; + struct in_addr nxlink_host; } argData_s; struct menuEntry_s_tag @@ -50,7 +61,7 @@ struct menuEntry_s_tag NacpStruct *nacp; }; -typedef enum +typedef enum { IMAGE_MODE_RGB24, IMAGE_MODE_RGBA32 @@ -58,6 +69,10 @@ typedef enum double menuTimer; +#ifdef __cplusplus +extern "C" { +#endif + void menuCreateMsgBox(int width, int height, const char *text); void menuCloseMsgBox(); bool menuIsMsgBoxOpen(); @@ -74,6 +89,16 @@ void menuEntryParseNacp(menuEntry_s* me); menu_s* menuGetCurrent(void); int menuScan(const char* target); +void launchMenuEntryTask(menuEntry_s* arg); +void launchMenuBackTask(); +void launchMenuNetloaderTask(); +char *menuGetRootPath(); + + +#ifdef __cplusplus +} +#endif + static inline char* getExtension(const char* str) { const char* p; diff --git a/common/netloader.c b/common/netloader.c new file mode 100644 index 0000000..5962d7c --- /dev/null +++ b/common/netloader.c @@ -0,0 +1,575 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef __WIN32__ +#include +#include +#include +#include +#else + +#define WIN32_LEAN_AND_MEAN +#include +#include +typedef int socklen_t; +typedef uint32_t in_addr_t; + +#undef DrawText + +#endif + + +#include "common.h" +#include "netloader.h" + +#include + +// having trouble with non blocking sockets & udp on switch currently +#ifndef __SWITCH__ +#define PING_ENABLED 1 +#else +#define PING_ENABLED 0 +#endif + +#define ZLIB_CHUNK (16 * 1024) +#define FILE_BUFFER_SIZE (128*1024) + +static int netloader_listenfd = -1; +static int netloader_datafd = -1; +#if PING_ENABLED +static int netloader_udpfd = -1; +#endif +unsigned char in[ZLIB_CHUNK]; +unsigned char out[ZLIB_CHUNK]; + +//--------------------------------------------------------------------------------- +static void netloader_error(const char *func, int err) { +//--------------------------------------------------------------------------------- + char errortext[1024]; + + sprintf(errortext, "%s: err=%d\n %s\n", func, err, strerror(errno)); + + menuCreateMsgBox(640,480, errortext); + + netloader_deactivate(); +} + +//--------------------------------------------------------------------------------- +static void netloader_socket_error(const char *func) { +//--------------------------------------------------------------------------------- + int errcode; +#ifdef __WIN32__ + errcode = WSAGetLastError(); +#else + errcode = errno; +#endif + netloader_error(func,errcode); +} + +//--------------------------------------------------------------------------------- +void shutdownSocket(int socket) { +//--------------------------------------------------------------------------------- +#ifdef __WIN32__ + shutdown (socket, SD_SEND); + closesocket (socket); +#else + close(socket); +#endif +} + +static const char DIRECTORY_THIS[] = "."; +static const char DIRECTORY_PARENT[] = ".."; + +//--------------------------------------------------------------------------------- +static bool isDirectorySeparator(int c) { +//--------------------------------------------------------------------------------- + return c == DIRECTORY_SEPARATOR_CHAR; +} + +//--------------------------------------------------------------------------------- +static void sanitisePath(char *path) { +//--------------------------------------------------------------------------------- + char *tmpPath = strdup(path); + tmpPath[0] = 0; + + char *dirStart = path; + char *curPath = tmpPath; + +#ifdef _WIN32 + while(dirStart[0]) { + if (dirStart[0] == '/') dirStart[0] =DIRECTORY_SEPARATOR_CHAR; + dirStart++; + } +#endif + + dirStart = path; + + while(isDirectorySeparator(dirStart[0])) dirStart++; + + + do { + char *dirEnd = strchr(dirStart, DIRECTORY_SEPARATOR_CHAR); + if (dirEnd) { + dirEnd++; + if(!strncmp(DIRECTORY_PARENT,dirStart,strlen(DIRECTORY_PARENT))) { + /* move back one directory */ + size_t pathlen = strlen(tmpPath); + if(tmpPath[pathlen-1] == DIRECTORY_SEPARATOR_CHAR) tmpPath[pathlen-1] = 0; + char *prev = strrchr(tmpPath,DIRECTORY_SEPARATOR_CHAR); + if (prev) { + curPath = prev + 1; + } else { + curPath = tmpPath; + } + + + dirStart = dirEnd; + } else if (!strncmp(DIRECTORY_THIS,dirStart,strlen(DIRECTORY_THIS))) { + /* strip this entry */ + dirStart = dirEnd; + } else { + size_t dirSize = dirEnd - dirStart; + strncpy(curPath,dirStart,dirSize); + curPath[dirSize] = 0; + curPath += dirSize; + dirStart += dirSize; + } + } else { + strcpy(curPath,dirStart); + dirStart += strlen(dirStart); + } + } while(dirStart[0]); + + strcpy(path, tmpPath); + free(tmpPath); +} + +//--------------------------------------------------------------------------------- +static int set_socket_nonblocking(int sock) { +//--------------------------------------------------------------------------------- + +#ifndef __WIN32__ + int flags = fcntl(sock, F_GETFL); + + if(flags == -1) return -1; + + int rc = fcntl(sock, F_SETFL, flags | O_NONBLOCK); + + if(rc != 0) return -1; + +#else + u_long opt = 1; + ioctlsocket(sock, FIONBIO, &opt); +#endif + + + return 0; +} + + +//--------------------------------------------------------------------------------- +static int recvall(int sock, void *buffer, int size, int flags) { +//--------------------------------------------------------------------------------- + int len, sizeleft = size; + + while (sizeleft) { + + len = recv(sock,buffer,sizeleft,flags); + + if (len == 0) { + size = 0; + break; + }; + + if (len != -1) { + sizeleft -=len; + buffer +=len; + } else { +#ifdef _WIN32 + int errcode = WSAGetLastError(); + if (errcode != WSAEWOULDBLOCK) { + netloader_error("win socket error",errcode); + break; + } +#else + if ( errno != EWOULDBLOCK && errno != EAGAIN) { + perror(NULL); + break; + } +#endif + } + } + return size; +} + + +//--------------------------------------------------------------------------------- +static int decompress(int sock, FILE *fh, size_t filesize) { +//--------------------------------------------------------------------------------- + int ret; + unsigned have; + z_stream strm; + size_t chunksize; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit(&strm); + if (ret != Z_OK) { + netloader_error("inflateInit failed.",ret); + return ret; + } + + size_t total = 0; + /* decompress until deflate stream ends or end of file */ + do { + + int len = recvall(sock, &chunksize, 4, 0); + + if (len != 4) { + (void)inflateEnd(&strm); + netloader_error("Error getting chunk size",len); + return Z_DATA_ERROR; + } + + strm.avail_in = recvall(sock,in,chunksize,0); + + if (strm.avail_in == 0) { + (void)inflateEnd(&strm); + netloader_error("remote closed socket.",0); + return Z_DATA_ERROR; + } + + strm.next_in = in; + + /* run inflate() on input until output buffer not full */ + do { + strm.avail_out = ZLIB_CHUNK; + strm.next_out = out; + ret = inflate(&strm, Z_NO_FLUSH); + + switch (ret) { + + case Z_NEED_DICT: + ret = Z_DATA_ERROR; /* and fall through */ + + case Z_DATA_ERROR: + case Z_MEM_ERROR: + case Z_STREAM_ERROR: + (void)inflateEnd(&strm); + netloader_error("inflate error",ret); + return ret; + } + + have = ZLIB_CHUNK - strm.avail_out; + + if (fwrite(out, 1, have, fh) != have || ferror(fh)) { + (void)inflateEnd(&strm); + netloader_error("file write error",0); + return Z_ERRNO; + } + + total += have; + //printf("%zu (%zd%%)",total, (100 * total) / filesize); + } while (strm.avail_out == 0); + + /* done when inflate() says it's done */ + } while (ret != Z_STREAM_END); + + /* clean up and return */ + (void)inflateEnd(&strm); + return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; +} + + + +//--------------------------------------------------------------------------------- +int loadnro(menuEntry_s *me, int sock, struct in_addr remote) { +//--------------------------------------------------------------------------------- + int len, namelen, filelen; + char filename[PATH_MAX+1]; + len = recvall(sock, &namelen, 4, 0); + + if (len != 4) { + netloader_error("Error getting name length", errno); + return -1; + } + + if (namelen >= sizeof(filename)-1) { + netloader_error("Filename length is too large",errno); + return -1; + } + + len = recvall(sock, filename, namelen, 0); + + if (len != namelen) { + netloader_error("Error getting filename", errno); + return -1; + } + + filename[namelen] = 0; + + len = recvall(sock, &filelen, 4, 0); + + if (len != 4) { + netloader_error("Error getting file length",errno); + return -1; + } + + int response = 0; + + sanitisePath(filename); + + snprintf(me->path, PATH_MAX, "%s%s%s", menuGetRootPath(), DIRECTORY_SEPARATOR, filename); + // make sure it's terminated + me->path[PATH_MAX] = 0; + + argData_s* ad = &me->args; + ad->dst = (char*)&ad->buf[1]; + ad->nxlink_host = remote; + + launchAddArg(ad, me->path); + +#ifndef _WIN32 + int fd = open(me->path,O_CREAT|O_WRONLY, ACCESSPERMS); + + if (fd < 0) { + response = -1; + netloader_error("open", errno); + } else { + if (ftruncate(fd,filelen) == -1) { + response = -2; + netloader_error("ftruncate",errno); + } + close(fd); + } +#endif + + FILE *file = NULL; + + if (response == 0) file = fopen(me->path,"wb"); + + if(NULL == file) { + perror("file"); + response = -1; + } + + send(sock,(char *)&response,sizeof(response),0); + + if (response == 0 ) { + + //char *writebuffer=malloc(FILE_BUFFER_SIZE); + //setvbuf(file,writebuffer,_IOFBF, FILE_BUFFER_SIZE); + + //printf("transferring %s\n%d bytes.\n", filename, filelen); + + if (decompress(sock,file,filelen)==Z_OK) { + int netloaded_cmdlen = 0; + send(sock,(char *)&response,sizeof(response),0); + //printf("\ntransferring command line\n"); + len = recvall(sock,(char*)&netloaded_cmdlen,4,0); + + len = recvall(sock,me->args.dst, netloaded_cmdlen,0); + + while(netloaded_cmdlen) { + size_t len = strlen(me->args.dst) + 1; + ad->dst += len; + ad->buf[0]++; + netloaded_cmdlen -= len; + } + + } else { + response = -1; + } + + //free(writebuffer); + fflush(file); + fclose(file); + + } + + return response; +} + +//--------------------------------------------------------------------------------- +int netloader_activate(void) { +//--------------------------------------------------------------------------------- + struct sockaddr_in serv_addr; + +#ifdef __SWITCH__ + socketInitializeDefault(); +#endif + +#ifdef __WIN32__ + WSADATA wsa_data; + if (WSAStartup (MAKEWORD(2,2), &wsa_data)) { + netloader_error("WSAStartup failed\n",1); + return 1; + } +#endif + + + memset(&serv_addr, '0', sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + serv_addr.sin_port = htons(NXLINK_SERVER_PORT); + +#if PING_ENABLED + // create udp socket for broadcast ping + netloader_udpfd = socket(AF_INET, SOCK_DGRAM, 0); + if (netloader_udpfd < 0) + { + netloader_socket_error("udp socket"); + return -1; + } + + if(bind(netloader_udpfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) { + netloader_socket_error("bind udp socket"); + return -1; + } + + if (set_socket_nonblocking(netloader_udpfd) == -1) + { + netloader_socket_error("listen fcntl"); + return -1; + } +#endif + // create listening socket on all addresses on NXLINK_SERVER_PORT + + netloader_listenfd = socket(AF_INET, SOCK_STREAM, 0); + if(netloader_listenfd < 0) + { + netloader_socket_error("socket"); + return -1; + } + + int rc = bind(netloader_listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); + if(rc != 0) + { + netloader_socket_error("bind"); + return -1; + } + + if (set_socket_nonblocking(netloader_listenfd) == -1) + { + netloader_socket_error("listen fcntl"); + return -1; + } + + rc = listen(netloader_listenfd, 10); + if(rc != 0) + { + netloader_socket_error("listen"); + return -1; + } + + return 0; +} + + +//--------------------------------------------------------------------------------- +int netloader_deactivate(void) { +//--------------------------------------------------------------------------------- + // close all remaining sockets and allow mainloop to return to main menu + if(netloader_listenfd >= 0) + { + shutdownSocket(netloader_listenfd); + netloader_listenfd = -1; + } + + if(netloader_datafd >= 0) + { + shutdownSocket(netloader_datafd); + netloader_datafd = -1; + } + +#if PING_ENABLED + if(netloader_udpfd >= 0) + { + shutdownSocket(netloader_udpfd); + netloader_udpfd = -1; + } +#endif + +#ifdef __SWITCH__ + socketExit(); +#endif + +#ifdef __WIN32__ + WSACleanup (); +#endif + + return 0; +} + +//--------------------------------------------------------------------------------- +int netloader_loop(menuEntry_s *me) { +//--------------------------------------------------------------------------------- + + struct sockaddr_in sa_remote; + +#if PING_ENABLED + char recvbuf[256]; + socklen_t fromlen = sizeof(sa_remote); + + int len = recvfrom(netloader_udpfd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr*) &sa_remote, &fromlen); + + if (len!=-1) { + if (strncmp(recvbuf,"nxboot",strlen("nxboot")) == 0) { + sa_remote.sin_family=AF_INET; + sa_remote.sin_port=htons(NXLINK_CLIENT_PORT); + sendto(netloader_udpfd, "bootnx", strlen("bootnx"), 0, (struct sockaddr*) &sa_remote,sizeof(sa_remote)); + } + } +#endif + if(netloader_listenfd >= 0 && netloader_datafd < 0) { + socklen_t addrlen = sizeof(sa_remote); + netloader_datafd = accept(netloader_listenfd, (struct sockaddr*)&sa_remote, &addrlen); + if(netloader_datafd < 0) + { + +#ifdef _WIN32 + int errcode = WSAGetLastError(); + if (errcode != WSAEWOULDBLOCK) { + netloader_error("accept", errcode); + return -1; + } +#else + if ( errno != EWOULDBLOCK && errno != EAGAIN) { + netloader_error("accept", errno); + return -1; + } +#endif + + } + else + { + close(netloader_listenfd); + netloader_listenfd = -1; + } + } + + if(netloader_datafd >= 0) + { + int result = loadnro(me, netloader_datafd,sa_remote.sin_addr); + netloader_deactivate(); + if (result== 0) { + return 1; + } else { + return -1; + } + } + + return 0; +} diff --git a/common/netloader.h b/common/netloader.h new file mode 100644 index 0000000..aed5619 --- /dev/null +++ b/common/netloader.h @@ -0,0 +1,5 @@ +#pragma once + +int netloader_activate(void); +int netloader_deactivate(void); +int netloader_loop( menuEntry_s *me;); diff --git a/common/nro.h b/common/nro.h deleted file mode 100644 index 53e7c27..0000000 --- a/common/nro.h +++ /dev/null @@ -1,54 +0,0 @@ -/** - * @file nro.h - * @brief NRO headers. - * @copyright libnx Authors - */ - -#pragma once - -#define NROHEADER_MAGIC 0x304f524e - -#define NROASSETHEADER_MAGIC 0x54455341 -#define NROASSETHEADER_VERSION 0 - -/// Entry for each segment in the codebin. -typedef struct { - u32 file_off; - u32 size; -} NroSegment; - -/// Offset 0x0 in the NRO. -typedef struct { - u32 unused; - u32 mod_offset; - u8 padding[8]; -} NroStart; - -/// This follows NroStart, the actual nro-header. -typedef struct { - u32 magic; - u32 unk1; - u32 size; - u32 unk2; - NroSegment segments[3]; - u32 bss_size; - u32 unk3; - u8 build_id[0x20]; - u8 padding[0x20]; -} NroHeader; - -/// Custom asset section. -typedef struct { - u64 offset; - u64 size; -} NroAssetSection; - -/// Custom asset header. -typedef struct { - u32 magic; - u32 version; - NroAssetSection icon; - NroAssetSection nacp; - NroAssetSection romfs; -} NroAssetHeader; - diff --git a/nx_main/loaders/builtin.c b/nx_main/loaders/builtin.c index 4d347a1..08728fe 100644 --- a/nx_main/loaders/builtin.c +++ b/nx_main/loaders/builtin.c @@ -1,8 +1,10 @@ +#include + #include "../common/common.h" static char argBuf[ENTRY_ARGBUFSIZE]; -static void init_args(char *dst, size_t dst_maxsize, u32 *in_args, size_t size) +static char *init_args(char *dst, size_t dst_maxsize, u32 *in_args, size_t size) { size_t tmplen; u32 argi; @@ -36,6 +38,7 @@ static void init_args(char *dst, size_t dst_maxsize, u32 *in_args, size_t size) dst_maxsize--; } } + return dst; } static bool init(void) @@ -45,7 +48,7 @@ static bool init(void) static void deinit(void) { - + } static void launchFile(const char* path, argData_s* args) @@ -53,8 +56,19 @@ static void launchFile(const char* path, argData_s* args) /*if (strncmp(path, "sdmc:/",6) == 0) path += 5;*/ memset(argBuf, 0, sizeof(argBuf)); + + uint32_t remote = args->nxlink_host.s_addr; + + if (remote) { + char nxlinked[17]; + sprintf(nxlinked,"%08" PRIx32 "_NXLINK_",remote); + launchAddArg(args, nxlinked); + } + init_args(argBuf, sizeof(argBuf)-1, args->buf, sizeof(args->buf)); + Result rc = envSetNextLoad(path, argBuf); + if(R_FAILED(rc)) fatalSimple(rc);//TODO: How should failing be handled? uiExitLoop(); } diff --git a/nx_main/main.c b/nx_main/main.c index 8201931..04d6255 100644 --- a/nx_main/main.c +++ b/nx_main/main.c @@ -82,15 +82,17 @@ int main(int argc, char **argv) return 0; } -void launchMenuEntryTask(menuEntry_s* arg); - //This is implemented here due to the hid code. bool menuUpdate(void) { bool exitflag = 0; menu_s* menu = menuGetCurrent(); u32 down = hidKeysDown(CONTROLLER_P1_AUTO); - if (down & KEY_A) + if (down & KEY_Y) + { + launchMenuNetloaderTask(); + } + else if (down & KEY_A) { if (menuIsMsgBoxOpen()) { menuCloseMsgBox(); @@ -106,11 +108,7 @@ bool menuUpdate(void) { } else if (down & KEY_B) { - if (strcmp( menu->dirname, "sdmc:/") != 0) - { - //workerSchedule(changeDirTask, ".."); - menuScan(".."); - } + launchMenuBackTask(); } else if (down & KEY_PLUS) { diff --git a/pc_main/main.cpp b/pc_main/main.cpp index c1914b1..1adc3de 100644 --- a/pc_main/main.cpp +++ b/pc_main/main.cpp @@ -53,8 +53,6 @@ int main() return 0; } -extern "C" void launchMenuEntryTask(menuEntry_s* arg); - extern "C" bool menuUpdate(void) { //This is implemented here due to the hid code. menu_s* menu = menuGetCurrent(); @@ -63,10 +61,18 @@ extern "C" bool menuUpdate(void) { int new_esc_state = sf::Keyboard::isKeyPressed(sf::Keyboard::Escape); static int return_state = 0; int new_return_state = sf::Keyboard::isKeyPressed(sf::Keyboard::Return); + static int y_state = 0; + int new_y_state = sf::Keyboard::isKeyPressed(sf::Keyboard::Y); + + if(!new_y_state && y_state) + { + launchMenuNetloaderTask(); + + } if (!new_esc_state && esc_state) { - menuScan(".."); + launchMenuBackTask(); } else if (!new_return_state && return_state) { @@ -106,6 +112,7 @@ extern "C" bool menuUpdate(void) { esc_state = new_esc_state; return_state = new_return_state; + y_state = new_y_state; return 0; }