// FTP-Server in der App (Entwickler-Werkzeuge). Läuft in einem eigenen Thread, solange die App offen ist. // // Das Hintergrund-Modul (ftpmodul/, eigener Prozess auf Kern 1) ist abgeschaltet: Es brachte den // Kernel-Scheduler auf Kern 1 zum Absturz (PC FFF21584, kaputter Thread in der Warteschlange). Die App // räumt seine Dateien weg, damit es nie wieder startet. // // Ohne Passwort, Port 5000, Lesen von der ganzen SD, Schreiben/Löschen nur in /3ds/mbmnet (ftp.c). #include <3ds.h> #include #include #include #include #include #include #include #include "ftpctl.h" #include "../ftpmodul/source/ftp.h" #define SOC_BUFFER_SIZE 0x100000 static u32 *socBuffer; static Thread thread; static volatile bool running; static char address[32]; static char status[64]; bool ftp_should_exit(void) { return !running; } static void server(void *arg) { (void)arg; while (running) { u32 ip = (u32)gethostid(); if (!ip) { snprintf(status, sizeof(status), "kein WLAN"); address[0] = 0; svcSleepThread(1000000000LL); continue; } int fd = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in addr = { .sin_family = AF_INET, .sin_port = htons(CONTROL_PORT), .sin_addr.s_addr = INADDR_ANY }; if (fd < 0 || bind(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0 || listen(fd, 2) != 0) { if (fd >= 0) close(fd); snprintf(status, sizeof(status), "Port %d belegt", CONTROL_PORT); svcSleepThread(2000000000LL); continue; } snprintf(address, sizeof(address), "%lu.%lu.%lu.%lu:%d", (unsigned long)(ip & 0xFF), (unsigned long)((ip >> 8) & 0xFF), (unsigned long)((ip >> 16) & 0xFF), (unsigned long)(ip >> 24), CONTROL_PORT); ftp_serve(fd, ip); // bis WLAN weg, IP neu oder "FTP aus" close(fd); address[0] = 0; } } // Reste des abgeschalteten Hintergrund-Moduls entfernen (sonst startete eine alte App-Version es wieder) void ftpctl_cleanup_module(void) { remove("sdmc:/luma/sysmodules/0004013000F1E002.cxi"); remove("sdmc:/luma/sysmodules/0004013000F1E001.cxi"); remove("sdmc:/3ds/mbmnet/ftp-an"); remove("sdmc:/3ds/mbmnet/ftp-stopp"); remove("sdmc:/3ds/mbmnet/ftp-adresse.txt"); } bool ftpctl_running(void) { return running; } bool ftpctl_start(char *msg, size_t msglen) { if (running) return true; socBuffer = memalign(0x1000, SOC_BUFFER_SIZE); if (!socBuffer || R_FAILED(socInit(socBuffer, SOC_BUFFER_SIZE))) { free(socBuffer); socBuffer = NULL; snprintf(msg, msglen, "FTP: Netzwerk nicht verfügbar."); return false; } running = true; status[0] = address[0] = 0; s32 prio = 0x30; svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); thread = threadCreate(server, NULL, 32 * 1024, prio + 1, -2, false); if (!thread) { running = false; socExit(); free(socBuffer); socBuffer = NULL; snprintf(msg, msglen, "FTP: konnte nicht starten."); return false; } snprintf(msg, msglen, "FTP-Server an (läuft, solange die App offen ist).\nOhne Passwort, Port 5000. Herunterladen von der ganzen SD,\n" "Hochladen/Löschen nur in /3ds/mbmnet."); return true; } void ftpctl_stop(char *msg, size_t msglen) { if (running) { running = false; threadJoin(thread, 5000000000LL); threadFree(thread); thread = NULL; socExit(); free(socBuffer); socBuffer = NULL; } address[0] = 0; if (msg) snprintf(msg, msglen, "FTP-Server aus."); } bool ftpctl_resume(char *msg, size_t msglen) { (void)msg; (void)msglen; return false; } const char *ftpctl_address(void) { return address; } const char *ftpctl_status(void) { return status[0] ? status : "startet ..."; }