mirror of
https://github.com/seregonwar/zftpd.git
synced 2026-10-19 01:59:57 -05:00
7.6 KiB
7.6 KiB
zftpd Internal APIs for Module Authors
This 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).
Design Principles
- Single-threaded event-driven model; avoid blocking where possible.
- Return
ftp_error_t(orinterrno-style) and never leave partially initialized state. - Validate inputs (null, length, ranges) before use.
- Keep allocations bounded and free/release buffers on all paths.
- Prefer platform abstraction layers (
pal_*) instead of direct syscalls.
Error Types
ftp_error_tininclude/ftp/ftp_types.hcovers FTP-domain errors.- Use
FTP_OKfor success; return specific error enums for callers to translate into FTP replies/logs.
Memory Management
Arena Scratch (pal_scratch)
- Fast temp buffers with rollback semantics.
- Typical use:
#include "pal_scratch.h"
pal_scratch_t arena;
pal_scratch_mark_t mark;
pal_scratch_init(&arena, buffer, buffer_len);
pal_scratch_mark(&arena, &mark);
void *tmp = pal_scratch_alloc(&arena, needed, alignof(max_align_t));
/* ...use tmp... */
pal_scratch_reset(&arena, &mark); // frees all since mark
Heap Alloc (pal_alloc)
- Thin wrappers for tracked malloc/free; prefer for persistent objects.
#include "pal_alloc.h"
void *p = pal_malloc(size);
if (p == NULL) return FTP_ERR_NO_MEMORY;
/* ... */
pal_free(p);
Buffer Pool (ftp_buffer_pool)
- Reusable I/O buffers sized for data path.
#include "ftp_buffer_pool.h"
void *buf = ftp_buffer_acquire();
size_t sz = ftp_buffer_size();
/* use buf up to sz bytes */
ftp_buffer_release(buf);
File I/O (pal_fileio)
- Portable wrappers for open/read/write/close/stat; handle EINTR internally where applicable.
- Sendfile fast path (Linux/FreeBSD/PS4/PS5) via
pal_sendfile.
#include "pal_fileio.h"
int fd = pal_file_open(path, O_RDONLY, 0);
struct stat st;
if (pal_file_fstat(fd, &st) != FTP_OK) { pal_file_close(fd); return FTP_ERR_FILE_STAT; }
ssize_t n = pal_file_read(fd, buf, len);
pal_file_close(fd);
Virtual Filesystem (pal_filesystem, pal_filesystem_psx)
vfs_*helpers abstract file nodes with optional PS4/PS5 self-handling.
#include "pal_filesystem.h"
vfs_node_t node;
if (vfs_open(&node, "/data/pkg.bin") != FTP_OK) return FTP_ERR_FILE_OPEN;
ssize_t n = vfs_read(&node, buf, len);
vfs_close(&node);
Path Utilities (ftp_path)
- Safe canonicalization and traversal checks, returns resolved paths under session root.
#include "ftp_path.h"
char resolved[FTP_PATH_MAX];
ftp_error_t err = ftp_path_resolve(session, user_path, resolved, sizeof(resolved));
if (err != FTP_OK) return err; /* use resolved */
Networking (pal_network)
- Socket creation, sockaddr helpers, byte-order macros; wraps platform differences.
#include "pal_network.h"
struct sockaddr_in addr;
ftp_error_t err = pal_make_sockaddr("192.168.0.10", 2121, &addr);
int fd = PAL_SOCKET(AF_INET, SOCK_STREAM, 0);
if (PAL_CONNECT(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {/* handle */}
Advanced: Scratch arena with fallback
#include "pal_scratch.h"
#include "pal_alloc.h"
typedef struct {
pal_scratch_t arena;
uint8_t stack_buf[4096];
} my_ctx_t;
void my_ctx_init(my_ctx_t *ctx) {
pal_scratch_init(&ctx->arena, ctx->stack_buf, sizeof(ctx->stack_buf));
}
void *my_tmp_alloc(my_ctx_t *ctx, size_t sz) {
pal_scratch_mark_t mark;
pal_scratch_mark(&ctx->arena, &mark);
void *p = pal_scratch_alloc(&ctx->arena, sz, alignof(max_align_t));
if (p != NULL) {
pal_scratch_reset(&ctx->arena, &mark); // single alloc, safe to drop mark after use
return p;
}
pal_scratch_reset(&ctx->arena, &mark);
return pal_malloc(sz); // fallback to heap if arena exhausted
}
Advanced: Custom HTTP endpoint (ZHTTP)
// http_api.c
#include "http_api.h"
#include "http_response.h"
#include "pal_fileio.h"
static http_response_t *handle_ping(const http_request_t *req) {
(void)req;
return http_response_json(200, "{\"ok\":true}\n");
}
http_response_t *http_api_handle(const http_request_t *req) {
if (strncmp(req->uri, "/api/ping", 9) == 0) {
return handle_ping(req);
}
// existing handlers...
return http_response_not_found();
}
- Use
pal_socket_set_reuseaddr,pal_socket_set_nonblock,pal_network_get_primary_ipwhen needed.
Logging (ftp_log)
- Session-aware structured logging; prefer to emit events instead of printf.
#include "ftp_log.h"
ftp_log_session_event(session, "MYMODULE", FTP_OK, bytes_processed);
Notifications (PS4/PS5) (pal_notification)
- Lightweight wrapper to display toast messages on consoles.
#include "pal_notification.h"
pal_notification_send("Started on 192.168.0.10:2122");
pal_notification_send_ex("Doorbell", "icon_system");
- HTTP:
GET /api/notify?text=...[&icon=...](see API.md).
Crypto (optional) (ftp_crypto)
- ChaCha20 PSK via
AUTH XCRYPT; keep disabled unless explicitly required.
#include "ftp_crypto.h"
uint8_t key[32] = { /* PSK */ };
uint8_t nonce[12] = {0};
ftp_crypto_derive_key(key, nonce, out_key);
- Never hardcode secrets in source destined for payloads; load from secure source when possible.
Rate Limiting
- Token-bucket per session in
ftp_commands.c(ftp_rate_limit_wait); reuse pattern for new data paths.
HTTP/ZHTTP Modules
- When
ENABLE_ZHTTPD=1, HTTP server modules live insrc/http/http_*.c; add endpoints inhttp_api.c.
// http_api.c
if (strncmp(req->uri, "/api/custom", 11) == 0) {
return handle_custom(req);
}
Quality Bar (Embedded-grade)
- Check all return values; handle
EINTR,EAGAIN, and short I/O. - Keep stack usage bounded; avoid VLAs and unbounded recursion.
- Zero-init structs before use; clear sensitive buffers after use (e.g., keys).
- Respect compile-time toggles:
ENABLE_ZHTTPD,ENABLE_WEB_UPLOAD,FTP_ENABLE_CRYPTO,FTP_ENABLE_MLST,FTP_ENABLE_UTF8, rate-limit macros. - Use
PAL_*macros for portability (sockets, htons/ntohl, close) instead of raw syscalls. - Prefer
snprintfwith size checks; guard against path overflows (seeftp_path_resolve).
Minimal Example: Reading a file and sending over data FD
#include "pal_filesystem.h"
#include "pal_network.h"
#include "ftp_buffer_pool.h"
ftp_error_t send_file(int data_fd, const char *path) {
vfs_node_t node;
if (vfs_open(&node, path) != FTP_OK) return FTP_ERR_FILE_OPEN;
void *buf = ftp_buffer_acquire();
size_t sz = ftp_buffer_size();
ftp_error_t status = FTP_OK;
while (status == FTP_OK) {
ssize_t n = vfs_read(&node, buf, sz);
if (n == 0) break; // EOF
if (n < 0) { status = FTP_ERR_FILE_READ; break; }
ssize_t sent = pal_send(data_fd, buf, (size_t)n, 0);
if (sent != n) { status = FTP_ERR_NET_SEND; break; }
}
ftp_buffer_release(buf);
vfs_close(&node);
return status;
}
Where to Look
- Headers:
include/platform/pal_*.h,include/ftp/ftp_*.h - Implementations:
src/platform/pal_*,src/ftp/ftp_commands.c,src/http/http_*.c,src/ftp/ftp_crypto.c - 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_poolfor I/O buffers, and add your own protocol handlers atop the same evented model.
Keep modules small, defensive, and consistent with existing patterns.