v2.9.5: schnelleres Umschalten (Miiverse-CA aus dem SD-Zwischenspeicher, kurzes Warten beim Beenden)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Nico Meister
2026-10-19 18:36:57 +02:00
co-authored by Claude Opus 5.5
parent 9ffe07ff48
commit 93efce6f58
10 changed files with 42 additions and 9 deletions
+1 -1
View File
@@ -17,7 +17,7 @@ SOURCES := source
INCLUDES := source INCLUDES := source
# Bei jedem Release erhöhen - das Auto-Update vergleicht diese Nummer # Bei jedem Release erhöhen - das Auto-Update vergleicht diese Nummer
VERSION := 2.9.4 VERSION := 2.9.5
APP_TITLE := MBMNET APP_TITLE := MBMNET
APP_DESCRIPTION := Dein eigenes 3DS-Netzwerk APP_DESCRIPTION := Dein eigenes 3DS-Netzwerk
+1 -1
View File
@@ -52,7 +52,7 @@ bool admin_is(void) { return isAdmin; }
bool admin_finish(void) bool admin_finish(void)
{ {
if (!thread) return true; if (!thread) return true;
if (R_FAILED(threadJoin(thread, 15ULL * 1000 * 1000 * 1000))) return false; // läuft noch if (R_FAILED(threadJoin(thread, 300ULL * 1000 * 1000))) return false; // läuft noch
threadFree(thread); threadFree(thread);
thread = NULL; thread = NULL;
return true; return true;
+1 -1
View File
@@ -6,4 +6,4 @@
void admin_start(const char *server, u32 pid); void admin_start(const char *server, u32 pid);
// Admin? (gemerkte Antwort, bis der Server geantwortet hat) // Admin? (gemerkte Antwort, bis der Server geantwortet hat)
bool admin_is(void); bool admin_is(void);
bool admin_finish(void); // wartet höchstens 15 s, false = läuft noch bool admin_finish(void); // wartet höchstens 0,3 s, false = läuft noch
+5
View File
@@ -293,8 +293,10 @@ static void maintenance_worker(void *arg)
} }
} }
bool changed = false; bool changed = false;
patchFreshCa = true; // im Hintergrund darf es dauern: Miiverse-CA frisch vom Server
// Patches auffrischen: neue Versionen bringen neue Ziele mit (z. B. Miiverse ab v2.8.0) // Patches auffrischen: neue Versionen bringen neue Ziele mit (z. B. Miiverse ab v2.8.0)
if (patch_enable(MBMNET_SERVER, &changed, detail, sizeof(detail)) && changed) maintenanceChanged = true; if (patch_enable(MBMNET_SERVER, &changed, detail, sizeof(detail)) && changed) maintenanceChanged = true;
patchFreshCa = false;
maintaining = false; maintaining = false;
} }
@@ -685,6 +687,9 @@ int main(int argc, char **argv)
// schreiben sie nach dem Freigeben hinein und Luma zeigt einen Absturz (z. B. beim Neustart nach "Nintendo"). // schreiben sie nach dem Freigeben hinein und Luma zeigt einen Absturz (z. B. beim Neustart nach "Nintendo").
ftpctl_stop(NULL, 0); ftpctl_stop(NULL, 0);
shopctl_exit(); shopctl_exit();
// Update- und Admin-Abfrage nur kurz abwarten: Läuft noch etwas, beendet sich die App hart (schneller
// Neustart nach dem Umschalten). Das Auffrischen schreibt Patch-Dateien - darauf warten (beim Umschalten
// ist es ohnehin schon fertig, Aktionen warten darauf).
bool clean = true; bool clean = true;
if (maintenanceThread) { if (maintenanceThread) {
if (R_SUCCEEDED(threadJoin(maintenanceThread, 20ULL * 1000 * 1000 * 1000))) threadFree(maintenanceThread); if (R_SUCCEEDED(threadJoin(maintenanceThread, 20ULL * 1000 * 1000 * 1000))) threadFree(maintenanceThread);
+24 -2
View File
@@ -13,6 +13,7 @@
#include <3ds.h> #include <3ds.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/stat.h>
#include "olvpatch.h" #include "olvpatch.h"
@@ -47,17 +48,38 @@ static u32 fetch(const char *server, const char *path, u8 *buf, u32 cap)
return R_SUCCEEDED(rc) && status == 200 && got < cap ? got : 0; return R_SUCCEEDED(rc) && status == 200 && got < cap ? got : 0;
} }
bool olvpatch_fetch_ca(const char *server, u8 *der, u32 *derLen) // Zwischenspeicher der CA auf der SD: Beim Umschalten nicht jedes Mal den Server fragen (das dauerte
// Sekunden, solange das WLAN noch verbindet). Frisch geholt wird beim Auffrischen im Hintergrund.
#define CA_DER_CACHE "sdmc:/3ds/mbmnet/cache/olv-ca.der"
static u32 read_cached(u8 *der)
{ {
FILE *f = fopen(CA_DER_CACHE, "rb");
if (!f) return 0;
u32 n = fread(der, 1, CA_MAX + 1, f);
fclose(f);
FILE *pem = fopen(CA_PEM_FILE, "rb"); // die PEM-Datei für den Browser muss auch da sein
if (!pem) return 0;
fclose(pem);
return n > 0 && n <= CA_MAX ? n : 0;
}
bool olvpatch_fetch_ca(const char *server, u8 *der, u32 *derLen, bool fresh)
{
if (!fresh && (*derLen = read_cached(der))) return true;
static u8 pem[2048]; static u8 pem[2048];
u32 n = fetch(server, "/olv/ca.der", der, CA_MAX + 1); u32 n = fetch(server, "/olv/ca.der", der, CA_MAX + 1);
if (n == 0 || n > CA_MAX) return false; if (n == 0 || n > CA_MAX) return !fresh ? false : (*derLen = read_cached(der)) != 0;
u32 p = fetch(server, "/olv/ca.pem", pem, sizeof(pem)); u32 p = fetch(server, "/olv/ca.pem", pem, sizeof(pem));
if (p == 0) return false; if (p == 0) return false;
// Der Browser der Miiverse-App liest die CA von der SD-Karte // Der Browser der Miiverse-App liest die CA von der SD-Karte
FILE *f = fopen(CA_PEM_FILE, "wb"); FILE *f = fopen(CA_PEM_FILE, "wb");
bool ok = f && fwrite(pem, 1, p, f) == p; bool ok = f && fwrite(pem, 1, p, f) == p;
if (f) fclose(f); if (f) fclose(f);
mkdir("sdmc:/3ds/mbmnet", 0777);
mkdir("sdmc:/3ds/mbmnet/cache", 0777);
f = fopen(CA_DER_CACHE, "wb");
if (f) { fwrite(der, 1, n, f); fclose(f); }
*derLen = n; *derLen = n;
return ok; return ok;
} }
+2 -1
View File
@@ -4,7 +4,8 @@
// Miiverse-Patch (siehe olvpatch.c). Die CA kommt vom MBMNET-Server (/olv/ca.der, /olv/ca.pem). // Miiverse-Patch (siehe olvpatch.c). Die CA kommt vom MBMNET-Server (/olv/ca.der, /olv/ca.pem).
// Holt die MBMNET-CA (DER, höchstens 889 Bytes) und legt die PEM-Fassung für den Browser auf die SD. // Holt die MBMNET-CA (DER, höchstens 889 Bytes) und legt die PEM-Fassung für den Browser auf die SD.
bool olvpatch_fetch_ca(const char *server, u8 *der, u32 *derLen); // fresh = false: erst den Zwischenspeicher auf der SD versuchen (schnell), sonst vom Server holen
bool olvpatch_fetch_ca(const char *server, u8 *der, u32 *derLen, bool fresh);
// Ist das genau die Miiverse-Version, für die der Patch gebaut ist? (entpackter .code) // Ist das genau die Miiverse-Version, für die der Patch gebaut ist? (entpackter .code)
bool olvpatch_supported(const u8 *code, u32 size); bool olvpatch_supported(const u8 *code, u32 size);
// Baut den IPS-Patch. Gibt die Länge zurück, 0 bei Fehler. // Baut den IPS-Patch. Gibt die Länge zurück, 0 bei Fehler.
+3 -1
View File
@@ -414,6 +414,8 @@ static bool write_ips(const char *path, const u8 *data, u32 n, bool *changed)
// Miiverse-Patch (olvpatch.c): eigene Code-Änderungen + MBMNET-CA statt einfacher Text-Regeln. // Miiverse-Patch (olvpatch.c): eigene Code-Änderungen + MBMNET-CA statt einfacher Text-Regeln.
// 0 = nicht installiert, andere Version oder CA nicht vom Server zu holen (dann bleibt ein alter Patch stehen). // 0 = nicht installiert, andere Version oder CA nicht vom Server zu holen (dann bleibt ein alter Patch stehen).
bool patchFreshCa; // CA frisch vom Server holen (Auffrischen im Hintergrund), sonst aus dem Zwischenspeicher
static u32 build_miiverse(const Target *t, const char *server, u8 *out, u32 cap) static u32 build_miiverse(const Target *t, const char *server, u8 *out, u32 cap)
{ {
static u8 der[1024]; static u8 der[1024];
@@ -421,7 +423,7 @@ static u32 build_miiverse(const Target *t, const char *server, u8 *out, u32 cap)
static int caState; // 0 = noch nicht geholt, 1 = da, -1 = nicht zu holen static int caState; // 0 = noch nicht geholt, 1 = da, -1 = nicht zu holen
char fp[64]; char fp[64];
fingerprint(t->tid, fp, sizeof(fp)); // leer = kein Zwischenspeicher, gebaut wird trotzdem fingerprint(t->tid, fp, sizeof(fp)); // leer = kein Zwischenspeicher, gebaut wird trotzdem
if (caState == 0) caState = olvpatch_fetch_ca(server, der, &derLen) ? 1 : -1; if (caState == 0) caState = olvpatch_fetch_ca(server, der, &derLen, patchFreshCa) ? 1 : -1;
if (caState < 0) return 0; if (caState < 0) return 0;
u32 sum = 2166136261u; // FNV-1a über die CA: neue CA -> neuer Patch u32 sum = 2166136261u; // FNV-1a über die CA: neue CA -> neuer Patch
+3
View File
@@ -4,6 +4,9 @@
// Offizieller MBMNET-Server. Über "Server-Adresse" lässt sich ein anderer eintragen (z. B. zum Testen). // Offizieller MBMNET-Server. Über "Server-Adresse" lässt sich ein anderer eintragen (z. B. zum Testen).
// Fester MBMNET-Server: einfaches HTTP über den NetBird-TCP-Service auf Port 81. // Fester MBMNET-Server: einfaches HTTP über den NetBird-TCP-Service auf Port 81.
// Höchstens 21 Zeichen passen in den Patch. // Höchstens 21 Zeichen passen in den Patch.
// true: patch_enable holt die Miiverse-CA frisch vom Server (sonst aus dem Zwischenspeicher auf der SD)
extern bool patchFreshCa;
#define MBMNET_SERVER "mbmnetapi.mbm.wtf:81" #define MBMNET_SERVER "mbmnetapi.mbm.wtf:81"
#define APP_DIR "sdmc:/3ds/mbmnet" #define APP_DIR "sdmc:/3ds/mbmnet"
+1 -1
View File
@@ -273,7 +273,7 @@ bool update_finish(void)
if (!thread) return true; if (!thread) return true;
// Läuft die Abfrage noch, nicht freigeben (sonst schreibt der Thread in freigegebenen Speicher). // Läuft die Abfrage noch, nicht freigeben (sonst schreibt der Thread in freigegebenen Speicher).
// false = läuft noch, die App muss sich hart beenden (main.c). // false = läuft noch, die App muss sich hart beenden (main.c).
if (R_FAILED(threadJoin(thread, 15ULL * 1000 * 1000 * 1000))) return false; if (R_FAILED(threadJoin(thread, 300ULL * 1000 * 1000))) return false;
threadFree(thread); threadFree(thread);
thread = NULL; thread = NULL;
return true; return true;
+1 -1
View File
@@ -21,7 +21,7 @@ void update_download(void);
bool update_pending(void); bool update_pending(void);
UpdateState update_state(void); UpdateState update_state(void);
const char *update_new_version(void); const char *update_new_version(void);
// Wartet auf den Hintergrund-Thread (höchstens 15 s). false = läuft noch. // Wartet auf den Hintergrund-Thread (höchstens 0,3 s). false = läuft noch.
bool update_finish(void); bool update_finish(void);
// Laufender Download-Versuch (1-3) // Laufender Download-Versuch (1-3)
int update_attempt(void); int update_attempt(void);