Files
knutwurst--ps5-patchdl/src/patchdl_net.h
T
Knutwurst a371a67521 Net: drop HTTPS pin on the streaming download paths
Real regression from c9d721f: pinning CURLOPT_PROTOCOLS_STR /
REDIR_PROTOCOLS_STR to "https" on the piece downloader (and the simple
file streamer) broke real-world Sony patch downloads. Banishers reliably
aborted after ~73 MB and Last of Us Part I after ~127 MB — the Sony CDN
appears to 302 the piece URL to an http:// signed edge inside its own
infrastructure, and refusing those redirects killed the transfer mid-piece.

The smaller patchdl_http_get path (version.xml + manifest JSON) keeps the
HTTPS pin since those payloads always come back from the public https
endpoints. The defence still holds elsewhere: host_allowed gates every
URL to the Sony CDN allowlist, TLS verifies against the pinned SCEI root
even on a 302, and NOSIGNAL stays so a connection RST can't smuggle a
SIGPIPE back into the worker thread.

For future regressions of this class /api/downloads now exposes the last
CURLcode + HTTP status per job (last_curl_rc, last_http_code) so we don't
have to instrument the binary again to find out what curl returned.
2026-06-24 22:13:16 +02:00

100 lines
4.7 KiB
C

#pragma once
#include <stddef.h>
typedef struct {
char *data;
size_t size;
size_t cap;
size_t max; /* 0 = unbounded (legacy). Otherwise write_cb fails past this. */
} patchdl_buf_t;
patchdl_buf_t *patchdl_buf_new(void);
void patchdl_buf_free(patchdl_buf_t *b);
/* Call once, single-threaded, before any concurrent download worker starts /
after they have all joined. curl's global/OpenSSL init is otherwise lazy and
races across threads. */
void patchdl_net_global_init(void);
void patchdl_net_global_cleanup(void);
int patchdl_http_get(const char *url, patchdl_buf_t *out);
/* ---- parallel piece download (used by the connection pool) ------------- */
/* One piece of a split manifest package. `url` is heap-allocated. */
typedef struct {
char *url;
long long offset; /* byte offset of this piece in the assembled file */
long long size; /* exact length of this piece */
char hash[80]; /* manifest SHA-256 hex, or "" */
} patchdl_piece_t;
typedef struct {
patchdl_piece_t *pieces;
int count;
long long total; /* assembled file size = sum of piece sizes */
} patchdl_manifest_t;
/* Fetch + parse a Sony JSON manifest into a validated, contiguously-tiled
piece list. Returns 0 on success (caller frees with patchdl_manifest_free),
-1 on fetch/parse/tiling failure. */
int patchdl_fetch_manifest(const char *manifest_url, patchdl_manifest_t *out);
void patchdl_manifest_free(patchdl_manifest_t *m);
/* Live state shared with one in-flight piece download. The worker owns these;
the curl callbacks read `abort` (set elsewhere) and publish progress into
`bytes_slot` (single-writer per worker slot). */
typedef struct {
volatile long long *bytes_slot; /* bytes written so far for this piece */
volatile int *abort; /* non-zero -> stop this transfer */
} patchdl_piece_ctx_t;
/* Download one whole piece and pwrite it into `fd` at `file_offset`. Concurrent
non-overlapping pieces of the same fd are safe. Returns 0 on success (and
fdatasyncs fd), -1 on network/IO/abort, -2 on a SHA-256 mismatch.
`curl_rc_out`/`http_code_out` (either may be NULL) receive the last libcurl
CURLcode + HTTP status for failure diagnosis. */
int patchdl_http_download_piece(const char *url, int fd,
long long file_offset, long long file_size,
const char *expected_sha256_or_null,
patchdl_piece_ctx_t *ctx,
int *curl_rc_out, long *http_code_out);
/* Read-only: SHA-256 a [offset, offset+size) region of fd into out_hex
(caller provides >= 65 bytes). Returns 0 on success. */
int patchdl_sha256_fd_region(int fd, long long offset, long long size,
char *out_hex);
/* Progress callback. Return non-zero to ABORT the in-flight download (used to
cancel large patch downloads); return 0 to continue. */
typedef int (*patchdl_download_progress_cb)(void *ctx,
long long downloaded,
long long total);
/* Stream a URL to a file on disk (for large PKG downloads). Returns 0 on
success and writes the byte count to *bytes_out. */
int patchdl_http_download(const char *url, const char *dest_path,
long long *bytes_out);
int patchdl_http_download_progress(const char *url, const char *dest_path,
long long *bytes_out,
patchdl_download_progress_cb cb, void *ctx);
/* Download a Sony JSON package manifest by concatenating every entry in
"pieces" into one installable PKG. When `verify` is non-zero each piece is
checked against its manifest SHA-256 (a mismatch returns -2). When `resume`
is non-zero an existing partial at dest_path is kept: fully-downloaded pieces
are skipped and only the remainder is fetched (survives a reboot). On any
failure the partial is left in place for a later resume. */
int patchdl_http_download_manifest(const char *manifest_url, const char *dest_path,
long long *bytes_out);
int patchdl_http_download_manifest_progress(const char *manifest_url,
const char *dest_path,
long long *bytes_out,
patchdl_download_progress_cb cb,
void *ctx, int verify, int resume);
/* Diagnostic: run the GET pipeline for `url` and write a JSON report
(dns result/ip, curl code, http status, bytes) into `out_json`. */
void patchdl_net_diag(const char *url, char *out_json, size_t sz);