Seregon/zftpd

Zero-copy FTP/HTTP Daemon compatible with all POSIX systems

C/11.0 KB/No license
include/pal_curl.h
zftpd / include / pal_curl.h
1/*
2 * GNU GPLv3 License — Copyright (c) 2026 SeregonWar
3 * See LICENSE for full text.
4 */
5/* ═══════════════════════════════════════════════════════════════════════════
6 * PAL CURL — Complete libcurl shim for PS4/PS5
7 *
8 * Drop-in replacement for the libcurl subset used by http_api.c.
9 * Implemented on top of BSD sockets + HTTP/1.1. No TLS (HTTPS is
10 * rejected with CURLE_UNSUPPORTED_PROTOCOL; the console uses plain HTTP
11 * for all local-network transfers).
12 *
13 * Supported API surface:
14 * curl_global_init / curl_global_cleanup (no-ops; for source compat)
15 * curl_easy_init / curl_easy_cleanup
16 * curl_easy_reset
17 * curl_easy_setopt
18 * curl_easy_perform
19 * curl_easy_getinfo
20 * curl_easy_strerror
21 * curl_slist_append / curl_slist_free_all
22 * curl_version
23 *
24 * Supported methods : GET, POST, HEAD (CURLOPT_NOBODY)
25 * Transfer encodings: Content-Length and chunked (HTTP/1.1 §4.1)
26 * Redirect : 3xx with Location, including relative URLs
27 * Timeouts : connect and transfer, via select(2)
28 * Speed guard : CURLOPT_LOW_SPEED_LIMIT / LOW_SPEED_TIME
29 * Progress : CURLOPT_XFERINFOFUNCTION
30 *
31 * ── Thread-safety ──────────────────────────────────────────────────────────
32 * NO function in this unit is thread-safe. Each CURL handle must be
33 * used from a single thread at a time.
34 *
35 * ── Build guard ────────────────────────────────────────────────────────────
36 * Compiled only when ENABLE_LIBCURL=1 && (PS4 || PS5).
37 * On desktop the real libcurl is linked; this file is excluded.
38 * ═══════════════════════════════════════════════════════════════════════════ */
39 
40#ifndef PAL_CURL_H
41#define PAL_CURL_H
42 
43#include <stddef.h> /* size_t */
44#include <stdint.h> /* int64_t */
45 
46#ifdef __cplusplus
47extern "C" {
48#endif
49 
50/* ═══════════════════════════════════════════════════════════════════════════
51 * Scalar types
52 * ═════════════════════════════════════════════════════════════════════════*/
53 
54/** Error / result code (matches real libcurl values for ABI compat). */
55typedef int CURLcode;
56 
57/** Option identifier passed to curl_easy_setopt(). */
58typedef int CURLoption;
59 
60/** Info identifier passed to curl_easy_getinfo(). */
61typedef int CURLINFO;
62 
63/** Signed 64-bit file-size type (matches real libcurl's curl_off_t). */
64typedef long long curl_off_t;
65 
66/** Opaque handle type (allocated by curl_easy_init). */
67typedef void CURL;
68 
69/** Size of the error message buffer supplied via CURLOPT_ERRORBUFFER. */
70#define CURL_ERROR_SIZE 256
71 
72/* ═══════════════════════════════════════════════════════════════════════════
73 * Error codes (values match real libcurl for source-level compatibility)
74 * ═════════════════════════════════════════════════════════════════════════*/
75#define CURLE_OK 0
76#define CURLE_UNSUPPORTED_PROTOCOL 1
77#define CURLE_URL_MALFORMAT 3
78#define CURLE_COULDNT_RESOLVE_HOST 6
79#define CURLE_COULDNT_CONNECT 7
80#define CURLE_PARTIAL_FILE 18
81#define CURLE_HTTP_RETURNED_ERROR 22
82#define CURLE_WRITE_ERROR 23
83#define CURLE_OUT_OF_MEMORY 27
84#define CURLE_OPERATION_TIMEDOUT 28
85#define CURLE_ABORTED_BY_CALLBACK 42
86#define CURLE_TOO_MANY_REDIRECTS 47
87#define CURLE_UNKNOWN_OPTION 48
88#define CURLE_GOT_NOTHING 52
89#define CURLE_SEND_ERROR 55
90#define CURLE_RECV_ERROR 56
91 
92/* ═══════════════════════════════════════════════════════════════════════════
93 * curl_slist — linked list of strings (for CURLOPT_HTTPHEADER etc.)
94 * ═════════════════════════════════════════════════════════════════════════*/
95 
96typedef struct curl_slist {
97 char *data;
98 struct curl_slist *next;
99} curl_slist;
100 
101/* ═══════════════════════════════════════════════════════════════════════════
102 * Callback signatures
103 * ═════════════════════════════════════════════════════════════════════════*/
104 
105/**
106 * Write callback. Called by curl_easy_perform() for each received data
107 * chunk. Must return nmemb on success. Returning CURL_WRITEFUNC_PAUSE
108 * requests a brief pause (implementation re-invokes after a short delay;
109 * up to PAL_PAUSE_MAX_RETRIES times, then aborts with
110 * CURLE_ABORTED_BY_CALLBACK).
111 */
112typedef size_t (*curl_write_callback)(void *ptr, size_t size, size_t nmemb,
113 void *userdata);
114 
115#define CURL_WRITEFUNC_PAUSE 0x10000001U
116 
117/**
118 * Transfer-info / progress callback. Called periodically during body
119 * download if CURLOPT_NOPROGRESS is 0 (the default).
120 * Return 0 to continue; any other value aborts with
121 * CURLE_ABORTED_BY_CALLBACK.
122 */
123typedef int (*curl_xferinfo_callback)(void *clientp,
124 curl_off_t dltotal,
125 curl_off_t dlnow,
126 curl_off_t ultotal,
127 curl_off_t ulnow);
128 
129/* ═══════════════════════════════════════════════════════════════════════════
130 * CURLoption IDs (values match real libcurl)
131 * ═════════════════════════════════════════════════════════════════════════*/
132 
133/*
134 * OBJECTPOINT options (base 10000 in libcurl)
135 * CURLOPTTYPE_OBJECTPOINT = 10000
136 */
137#define CURLOPT_WRITEDATA 10001 /* void * */
138#define CURLOPT_URL 10002 /* const char * */
139#define CURLOPT_RANGE 10007 /* const char * e.g. "0-4095" */
140#define CURLOPT_ERRORBUFFER 10010 /* char[CURL_ERROR_SIZE] */
141#define CURLOPT_POSTFIELDS 10015 /* const char * (not copied) */
142#define CURLOPT_USERAGENT 10018 /* const char * */
143#define CURLOPT_HTTPHEADER 10023 /* curl_slist * */
144#define CURLOPT_XFERINFODATA 10057 /* void * */
145 
146/*
147 * LONG options (base 0 in libcurl)
148 */
149#define CURLOPT_VERBOSE 41 /* long bool */
150#define CURLOPT_NOPROGRESS 43 /* long bool (default 1) */
151#define CURLOPT_NOBODY 44 /* long bool — HEAD request */
152#define CURLOPT_POST 47 /* long bool */
153#define CURLOPT_FOLLOWLOCATION 52 /* long bool */
154#define CURLOPT_TIMEOUT 13 /* long seconds */
155#define CURLOPT_LOW_SPEED_LIMIT 19 /* long bytes/s */
156#define CURLOPT_LOW_SPEED_TIME 20 /* long seconds */
157#define CURLOPT_SSL_VERIFYPEER 64 /* long — accepted, ignored */
158#define CURLOPT_MAXREDIRS 68 /* long (-1 = unlimited) */
159#define CURLOPT_POSTFIELDSIZE 60 /* long (-1 = use strlen) */
160#define CURLOPT_CONNECTTIMEOUT 78 /* long seconds */
161#define CURLOPT_TIMEOUT_MS 155 /* long milliseconds */
162#define CURLOPT_CONNECTTIMEOUT_MS 156 /* long milliseconds */
163 
164/*
165 * FUNCTIONPOINT options (base 20000 in libcurl)
166 */
167#define CURLOPT_WRITEFUNCTION 20011 /* curl_write_callback */
168#define CURLOPT_XFERINFOFUNCTION 20219 /* curl_xferinfo_callback */
169 
170/* ═══════════════════════════════════════════════════════════════════════════
171 * CURLINFO IDs (values match real libcurl)
172 * ═════════════════════════════════════════════════════════════════════════*/
173 
174/*
175 * LONG info (base 0x200000)
176 */
177#define CURLINFO_RESPONSE_CODE 0x200002 /* long */
178 
179/*
180 * DOUBLE info (base 0x300000)
181 */
182#define CURLINFO_TOTAL_TIME 0x300003 /* double (seconds) */
183#define CURLINFO_SIZE_DOWNLOAD 0x300008 /* double (bytes) */
184#define CURLINFO_SPEED_DOWNLOAD 0x30000B /* double (bytes/s) */
185#define CURLINFO_CONTENT_LENGTH_DOWNLOAD 0x30000F /* double (-1 if unknown) */
186 
187/* ═══════════════════════════════════════════════════════════════════════════
188 * API
189 * ═════════════════════════════════════════════════════════════════════════*/
190 
191/**
192 * @brief No-op stub for source-level compatibility with libcurl callers.
193 * Must be called before any other curl_* function (libcurl requires
194 * this; our implementation has nothing to initialise globally).
195 *
196 * @param flags Ignored.
197 * @return Always CURLE_OK.
198 *
199 * @note Thread-safety: safe to call from any thread.
200 * @note WCET: O(1).
201 */
202CURLcode curl_global_init(long flags);
203 
204/**
205 * @brief No-op stub counterpart to curl_global_init().
206 *
207 * @note Thread-safety: safe to call from any thread.
208 * @note WCET: O(1).
209 */
210void curl_global_cleanup(void);
211 
212/**
213 * @brief Allocate and initialise a new easy handle.
214 *
215 * Default values after init:
216 * max_redirs = 10
217 * connect_timeout = 30 s
218 * noprogress = 1 (progress callback disabled)
219 *
220 * @return New handle on success, NULL on allocation failure.
221 *
222 * @note Thread-safety: NOT thread-safe.
223 * @note WCET: O(1), one calloc.
224 */
225CURL *curl_easy_init(void);
226 
227/**
228 * @brief Reset all options on an existing handle to their defaults.
229 *
230 * The handle remains valid and may be re-used. The file handle and
231 * response info fields are also cleared.
232 *
233 * @param handle Non-NULL easy handle.
234 *
235 * @note Thread-safety: NOT thread-safe.
236 * @note WCET: O(1).
237 */
238void curl_easy_reset(CURL *handle);
239 
240/**
241 * @brief Release all resources owned by handle and free it.
242 *
243 * After this call the handle pointer is invalid. Idempotent on NULL.
244 *
245 * @param handle Easy handle or NULL (ignored).
246 *
247 * @note Thread-safety: NOT thread-safe.
248 * @note WCET: O(1).
249 */
250void curl_easy_cleanup(CURL *handle);
251 
252/**
253 * @brief Set an option on a handle.
254 *
255 * The third argument type depends on the option:
256 * OBJECTPOINT options expect const char * or void * or curl_slist *
257 * FUNCTIONPOINT options expect a function pointer
258 * LONG options expect long
259 *
260 * @param handle Non-NULL easy handle.
261 * @param option CURLOPT_* constant.
262 * @param ... Option value (type depends on option).
263 *
264 * @return CURLE_OK on success.
265 * @retval CURLE_UNKNOWN_OPTION handle is NULL or option is unrecognised.
266 *
267 * @note Thread-safety: NOT thread-safe.
268 * @note WCET: O(1) for all options except CURLOPT_HTTPHEADER (no copy made).
269 */
270CURLcode curl_easy_setopt(CURL *handle, CURLoption option, ...);
271 
272/**
273 * @brief Perform the transfer described by the handle's options.
274 *
275 * Executes: DNS resolve → TCP connect → HTTP request → response stream.
276 * Redirects (3xx) are followed up to max_redirs times if
277 * CURLOPT_FOLLOWLOCATION is set.
278 *
279 * Response info fields (CURLINFO_*) are populated on return, regardless
280 * of success or failure.
281 *
282 * @param handle Fully configured easy handle.
283 *
284 * @return CURLE_OK on a completed transfer (HTTP status < 400).
285 * Other CURLcode values on error.
286 *
287 * @note Thread-safety: NOT thread-safe.
288 * @note WCET: Unbounded (network I/O).
289 * @warning Must not be called from an interrupt context.
290 */
291CURLcode curl_easy_perform(CURL *handle);
292 
293/**
294 * @brief Retrieve information about the last completed transfer.
295 *
296 * @param handle Easy handle (must have completed at least one perform).
297 * @param info CURLINFO_* constant.
298 * @param ... Pointer to receive the value (type depends on info).
299 *
300 * @return CURLE_OK on success.
301 * @retval CURLE_UNKNOWN_OPTION handle is NULL or info is unrecognised.
302 *
303 * @note Thread-safety: NOT thread-safe.
304 * @note WCET: O(1).
305 */
306CURLcode curl_easy_getinfo(CURL *handle, CURLINFO info, ...);
307 
308/**
309 * @brief Map a CURLcode to a human-readable English string.
310 *
311 * The returned pointer is to a string literal; do not free or modify it.
312 *
313 * @param code Any CURLcode value.
314 * @return NUL-terminated string; never NULL.
315 *
316 * @note Thread-safety: safe (returns a pointer to a constant literal).
317 * @note WCET: O(1).
318 */
319const char *curl_easy_strerror(CURLcode code);
320 
321/**
322 * @brief Return a brief version identifier string.
323 *
324 * @return Pointer to a string literal. Never NULL.
325 *
326 * @note Thread-safety: safe.
327 * @note WCET: O(1).
328 */
329const char *curl_version(void);
330 
331/**
332 * @brief Append a copy of data to a slist, or create a new slist.
333 *
334 * If allocation fails the original list is returned unchanged (the caller
335 * should check whether the list grew by comparing pointers or list length).
336 *
337 * @param list Existing slist or NULL to create a new one.
338 * @param data NUL-terminated string to append; must not be NULL.
339 *
340 * @return Updated (or newly created) slist head, or the original list on
341 * allocation failure.
342 *
343 * @note Thread-safety: NOT thread-safe.
344 * @note WCET: O(n) for traversal to the tail.
345 */
346curl_slist *curl_slist_append(curl_slist *list, const char *data);
347 
348/**
349 * @brief Free all nodes in a slist and their string data.
350 *
351 * Safe to call with NULL. The caller must not use the list after this call.
352 *
353 * @param list Head of the slist, or NULL.
354 *
355 * @note Thread-safety: NOT thread-safe.
356 * @note WCET: O(n).
357 */
358void curl_slist_free_all(curl_slist *list);
359 
360#ifdef __cplusplus
361}
362#endif
363 
364#endif /* PAL_CURL_H */