Seregon/zftpd

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

C/11.0 KB/No license
docs/internal_apis.md
zftpd / docs / internal_apis.md
1# zftpd Internal APIs for Module Authors
2 
3This document summarizes the main internal facilities you can rely on when adding modules that need file/network I/O, memory management, logging, and optional crypto. Follow the existing safety/embedded style (C11, MISRA/CERT minded: explicit error codes, no unchecked pointers, defensive bounds checks, handle EINTR/EAGAIN, prefer zero-copy paths where available).
4 
5## Design Principles
6- Single-threaded event-driven model; avoid blocking where possible.
7- Return `ftp_error_t` (or `int` errno-style) and never leave partially initialized state.
8- Validate inputs (null, length, ranges) before use.
9- Keep allocations bounded and free/release buffers on all paths.
10- Prefer platform abstraction layers (`pal_*`) instead of direct syscalls.
11 
12## Error Types
13- `ftp_error_t` in `include/ftp_types.h` covers FTP-domain errors.
14- Use `FTP_OK` for success; return specific error enums for callers to translate into FTP replies/logs.
15 
16## Memory Management
17### Arena Scratch (`pal_scratch`)
18- Fast temp buffers with rollback semantics.
19- Typical use:
20```c
21#include "pal_scratch.h"
22 
23pal_scratch_t arena;
24pal_scratch_mark_t mark;
25pal_scratch_init(&arena, buffer, buffer_len);
26pal_scratch_mark(&arena, &mark);
27void *tmp = pal_scratch_alloc(&arena, needed, alignof(max_align_t));
28/* ...use tmp... */
29pal_scratch_reset(&arena, &mark); // frees all since mark
30```
31 
32### Heap Alloc (`pal_alloc`)
33- Thin wrappers for tracked malloc/free; prefer for persistent objects.
34```c
35#include "pal_alloc.h"
36void *p = pal_malloc(size);
37if (p == NULL) return FTP_ERR_NO_MEMORY;
38/* ... */
39pal_free(p);
40```
41 
42### Buffer Pool (`ftp_buffer_pool`)
43- Reusable I/O buffers sized for data path.
44```c
45#include "ftp_buffer_pool.h"
46void *buf = ftp_buffer_acquire();
47size_t sz = ftp_buffer_size();
48/* use buf up to sz bytes */
49ftp_buffer_release(buf);
50```
51 
52## File I/O (`pal_fileio`)
53- Portable wrappers for open/read/write/close/stat; handle EINTR internally where applicable.
54- Sendfile fast path (Linux/FreeBSD/PS4/PS5) via `pal_sendfile`.
55```c
56#include "pal_fileio.h"
57int fd = pal_file_open(path, O_RDONLY, 0);
58struct stat st;
59if (pal_file_fstat(fd, &st) != FTP_OK) { pal_file_close(fd); return FTP_ERR_FILE_STAT; }
60ssize_t n = pal_file_read(fd, buf, len);
61pal_file_close(fd);
62```
63 
64## Virtual Filesystem (`pal_filesystem`, `pal_filesystem_psx`)
65- `vfs_*` helpers abstract file nodes with optional PS4/PS5 self-handling.
66```c
67#include "pal_filesystem.h"
68vfs_node_t node;
69if (vfs_open(&node, "/data/pkg.bin") != FTP_OK) return FTP_ERR_FILE_OPEN;
70ssize_t n = vfs_read(&node, buf, len);
71vfs_close(&node);
72```
73 
74## Path Utilities (`ftp_path`)
75- Safe canonicalization and traversal checks, returns resolved paths under session root.
76```c
77#include "ftp_path.h"
78char resolved[FTP_PATH_MAX];
79ftp_error_t err = ftp_path_resolve(session, user_path, resolved, sizeof(resolved));
80if (err != FTP_OK) return err; /* use resolved */
81```
82 
83## Networking (`pal_network`)
84- Socket creation, sockaddr helpers, byte-order macros; wraps platform differences.
85```c
86#include "pal_network.h"
87struct sockaddr_in addr;
88ftp_error_t err = pal_make_sockaddr("192.168.0.10", 2121, &addr);
89int fd = PAL_SOCKET(AF_INET, SOCK_STREAM, 0);
90if (PAL_CONNECT(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {/* handle */}
91```
92 
93### Advanced: Scratch arena with fallback
94```c
95#include "pal_scratch.h"
96#include "pal_alloc.h"
97 
98typedef struct {
99 pal_scratch_t arena;
100 uint8_t stack_buf[4096];
101} my_ctx_t;
102 
103void my_ctx_init(my_ctx_t *ctx) {
104 pal_scratch_init(&ctx->arena, ctx->stack_buf, sizeof(ctx->stack_buf));
105}
106 
107void *my_tmp_alloc(my_ctx_t *ctx, size_t sz) {
108 pal_scratch_mark_t mark;
109 pal_scratch_mark(&ctx->arena, &mark);
110 void *p = pal_scratch_alloc(&ctx->arena, sz, alignof(max_align_t));
111 if (p != NULL) {
112 pal_scratch_reset(&ctx->arena, &mark); // single alloc, safe to drop mark after use
113 return p;
114 }
115 pal_scratch_reset(&ctx->arena, &mark);
116 return pal_malloc(sz); // fallback to heap if arena exhausted
117}
118```
119 
120### Advanced: Custom HTTP endpoint (ZHTTP)
121```c
122// http_api.c
123#include "http_api.h"
124#include "http_response.h"
125#include "pal_fileio.h"
126 
127static http_response_t *handle_ping(const http_request_t *req) {
128 (void)req;
129 return http_response_json(200, "{\"ok\":true}\n");
130}
131 
132http_response_t *http_api_handle(const http_request_t *req) {
133 if (strncmp(req->uri, "/api/ping", 9) == 0) {
134 return handle_ping(req);
135 }
136 // existing handlers...
137 return http_response_not_found();
138}
139```
140- Use `pal_socket_set_reuseaddr`, `pal_socket_set_nonblock`, `pal_network_get_primary_ip` when needed.
141 
142## Logging (`ftp_log`)
143- Session-aware structured logging; prefer to emit events instead of printf.
144```c
145#include "ftp_log.h"
146ftp_log_session_event(session, "MYMODULE", FTP_OK, bytes_processed);
147```
148 
149## Notifications (PS4/PS5) (`pal_notification`)
150- Lightweight wrapper to display toast messages on consoles.
151```c
152#include "pal_notification.h"
153pal_notify("zftpd", "Started on 192.168.0.10:2122");
154```
155 
156## Crypto (optional) (`ftp_crypto`)
157- ChaCha20 PSK via `AUTH XCRYPT`; keep disabled unless explicitly required.
158```c
159#include "ftp_crypto.h"
160uint8_t key[32] = { /* PSK */ };
161uint8_t nonce[12] = {0};
162ftp_crypto_derive_key(key, nonce, out_key);
163```
164- Never hardcode secrets in source destined for payloads; load from secure source when possible.
165 
166## Rate Limiting
167- Token-bucket per session in `ftp_commands.c` (`ftp_rate_limit_wait`); reuse pattern for new data paths.
168 
169## HTTP/ZHTTP Modules
170- When `ENABLE_ZHTTPD=1`, HTTP server modules live in `src/http_*.c`; add endpoints in `http_api.c`.
171```c
172// http_api.c
173if (strncmp(req->uri, "/api/custom", 11) == 0) {
174 return handle_custom(req);
175}
176```
177 
178## Quality Bar (Embedded-grade)
179- Check all return values; handle `EINTR`, `EAGAIN`, and short I/O.
180- Keep stack usage bounded; avoid VLAs and unbounded recursion.
181- Zero-init structs before use; clear sensitive buffers after use (e.g., keys).
182- Respect compile-time toggles: `ENABLE_ZHTTPD`, `ENABLE_WEB_UPLOAD`, `FTP_ENABLE_CRYPTO`, `FTP_ENABLE_MLST`, `FTP_ENABLE_UTF8`, rate-limit macros.
183- Use `PAL_*` macros for portability (sockets, htons/ntohl, close) instead of raw syscalls.
184- Prefer `snprintf` with size checks; guard against path overflows (see `ftp_path_resolve`).
185 
186## Minimal Example: Reading a file and sending over data FD
187```c
188#include "pal_filesystem.h"
189#include "pal_network.h"
190#include "ftp_buffer_pool.h"
191 
192ftp_error_t send_file(int data_fd, const char *path) {
193 vfs_node_t node;
194 if (vfs_open(&node, path) != FTP_OK) return FTP_ERR_FILE_OPEN;
195 
196 void *buf = ftp_buffer_acquire();
197 size_t sz = ftp_buffer_size();
198 ftp_error_t status = FTP_OK;
199 
200 while (status == FTP_OK) {
201 ssize_t n = vfs_read(&node, buf, sz);
202 if (n == 0) break; // EOF
203 if (n < 0) { status = FTP_ERR_FILE_READ; break; }
204 ssize_t sent = pal_send(data_fd, buf, (size_t)n, 0);
205 if (sent != n) { status = FTP_ERR_NET_SEND; break; }
206 }
207 
208 ftp_buffer_release(buf);
209 vfs_close(&node);
210 return status;
211}
212```
213 
214## Where to Look
215- Headers: `include/pal_*.h`, `include/ftp_*.h`
216- Implementations: `src/pal_*`, `src/ftp_commands.c`, `src/http_*.c`, `src/ftp_crypto.c`
217- The PAL layers are usable to build standalone apps (e.g., custom services like a lightweight game server or tools unrelated to FTP). Reuse `pal_*` for portability, `ftp_buffer_pool` for I/O buffers, and add your own protocol handlers atop the same evented model.
218 
219Keep modules small, defensive, and consistent with existing patterns.
220