MBMNET-App v2.8.2: Quellcode (GPLv3)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Nico Meister
2026-10-18 17:05:44 +02:00
co-authored by Claude Opus 5.5
commit d264cd93cd
42 changed files with 7054 additions and 0 deletions
+109
View File
@@ -0,0 +1,109 @@
// 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 <arpa/inet.h>
#include <malloc.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#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 ..."; }