Files

74 lines
2.4 KiB
C

// HTTP über den Systemdienst http:C. Alles läuft über den MBMNET-Server (einfaches HTTP),
// der Katalog, Symbole und Downloads von Universal-DB und GitHub holt.
#include <3ds.h>
#include <stdlib.h>
#include <string.h>
#include "net.h"
#define CHUNK (128 * 1024)
static Result open_request(httpcContext *ctx, const char *url, u32 *status)
{
Result rc = httpcOpenContext(ctx, HTTPC_METHOD_GET, url, 1);
if (R_FAILED(rc)) return rc;
httpcAddRequestHeaderField(ctx, "User-Agent", "MBMNET-Shop/" APP_VERSION);
httpcSetKeepAlive(ctx, HTTPC_KEEPALIVE_DISABLED);
if (R_SUCCEEDED(rc = httpcBeginRequest(ctx)))
rc = httpcGetResponseStatusCodeTimeout(ctx, status, 30ULL * 1000 * 1000 * 1000);
if (R_FAILED(rc)) httpcCloseContext(ctx);
return rc;
}
u32 net_stream(const char *url, NetSink sink, void *ctx, Result *rcOut)
{
httpcContext http;
u32 status = 0, total = 0, got;
Result rc = open_request(&http, url, &status);
if (rcOut) *rcOut = rc;
if (R_FAILED(rc)) return 0;
if (status != 200) { httpcCloseContext(&http); return status; }
httpcGetDownloadSizeState(&http, NULL, &total);
u8 *buf = malloc(CHUNK);
if (!buf) { httpcCloseContext(&http); if (rcOut) *rcOut = -2; return 0; }
do {
got = 0;
rc = httpcDownloadData(&http, buf, CHUNK, &got);
if (got && !sink(ctx, buf, got, total)) { rc = -3; break; } // -3 = Empfänger hat abgebrochen
} while (rc == (Result)HTTPC_RESULTCODE_DOWNLOADPENDING);
free(buf);
httpcCloseContext(&http);
if (rcOut) *rcOut = rc;
return R_SUCCEEDED(rc) ? 200 : 0;
}
typedef struct { u8 *data; u32 size, cap, max; } MemSink;
static bool to_memory(void *p, const u8 *data, u32 len, u32 total)
{
MemSink *m = p;
if (m->size + len > m->max) return false;
if (m->size + len > m->cap) {
u32 cap = m->cap ? m->cap : (total && total <= m->max ? total : 64 * 1024);
while (cap < m->size + len) cap *= 2;
u8 *bigger = realloc(m->data, cap);
if (!bigger) return false;
m->data = bigger;
m->cap = cap;
}
memcpy(m->data + m->size, data, len);
m->size += len;
return true;
}
u32 net_get(const char *url, u8 **out, u32 *size, u32 max, Result *rc)
{
MemSink m = { NULL, 0, 0, max };
u32 status = net_stream(url, to_memory, &m, rc);
if (status != 200) { free(m.data); m.data = NULL; m.size = 0; }
*out = m.data;
*size = m.size;
return status;
}