Seregon/zftpd

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

C/11.0 KB/No license
include/ftp_config.h
zftpd / include / ftp_config.h
1/*
2MIT License
3 
4Copyright (c) 2026 Seregon
5 
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12 
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15 
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24 
25/**
26 * @file ftp_config.h
27 * @brief Compile-time configuration for multi-platform FTP server
28 *
29 * @author SeregonWar
30 * @version 1.0.0
31 * @date 2026-02-13
32 *
33 */
34 
35#ifndef FTP_CONFIG_H
36#define FTP_CONFIG_H
37 
38#include <stddef.h>
39#include <stdint.h>
40 
41/*===========================================================================*
42 * VERSION INFORMATION
43 *===========================================================================*/
44 
45#ifndef RELEASE_VERSION
46#define RELEASE_VERSION "1.5.0"
47#endif
48 
49/*===========================================================================*
50 * SERVER CONFIGURATION
51 *===========================================================================*/
52 
53/**
54 * Default FTP server port
55 * @note Well-known FTP port is 21, but requires root on POSIX systems
56 * @note Using 2121 as default for unprivileged operation on POSIX systems
57 * @note Using 2122 as default on PS4/PS5 because 2121 may be occupied
58 */
59#ifndef FTP_DEFAULT_PORT
60#if defined(PS4) || defined(PS5) || defined(PLATFORM_PS4) || defined(PLATFORM_PS5)
61#define FTP_DEFAULT_PORT 2120U
62#else
63#define FTP_DEFAULT_PORT 2121U
64#endif
65#endif
66 
67#ifndef FTP_STREAM_BUFFER_SIZE
68#if defined(PS5) || defined(PLATFORM_PS5)
69#define FTP_STREAM_BUFFER_SIZE 1048576U /* 1 MB — PS5 has plenty of RAM */
70#elif defined(PS4) || defined(PLATFORM_PS4)
71#define FTP_STREAM_BUFFER_SIZE 262144U /* 256 KB */
72#else
73#define FTP_STREAM_BUFFER_SIZE 524288U /* 512 KB — saturates GbE links */
74#endif
75#endif
76 
77#ifndef FTP_STREAM_BUFFER_COUNT
78#define FTP_STREAM_BUFFER_COUNT FTP_MAX_SESSIONS
79#endif
80 
81/**
82 * Maximum number of concurrent client connections
83 * @note This is a hard limit to prevent resource exhaustion
84 * @note Each client requires ~2KB of memory plus thread stack
85 */
86#ifndef FTP_MAX_SESSIONS
87#define FTP_MAX_SESSIONS 32U
88#endif
89 
90/**
91 * Session idle timeout in seconds
92 * @note Client disconnected after this period of inactivity
93 */
94#ifndef FTP_SESSION_TIMEOUT
95#if defined(PS5) || defined(PS4) || defined(PLATFORM_PS5) || defined(PLATFORM_PS4)
96#define FTP_SESSION_TIMEOUT 7200U
97#else
98#define FTP_SESSION_TIMEOUT 300U
99#endif
100#endif
101 
102#ifndef FTP_CTRL_IO_TIMEOUT_MS
103#define FTP_CTRL_IO_TIMEOUT_MS 1000U
104#endif
105 
106/**
107 * Data socket I/O timeout (recv/send) in milliseconds
108 *
109 * Prevents infinite stalls when disk write-back cache fills
110 * or the remote client disappears. 2 minutes is generous
111 * enough for slow USB drives while still detecting dead links.
112 */
113#ifndef FTP_DATA_IO_TIMEOUT_MS
114#define FTP_DATA_IO_TIMEOUT_MS 120000U
115#endif
116 
117/**
118 * SO_LINGER timeout for data sockets (seconds)
119 *
120 * After close(), the kernel keeps the socket open for this
121 * long to flush remaining data. Prevents ECONNRESET on the
122 * client when the server closes right after the last write.
123 */
124#ifndef FTP_DATA_LINGER_TIMEOUT_S
125#define FTP_DATA_LINGER_TIMEOUT_S 10
126#endif
127 
128#ifndef FTP_DATA_CONNECT_TIMEOUT_MS
129#define FTP_DATA_CONNECT_TIMEOUT_MS 15000U
130#endif
131 
132/**
133 * Listen backlog for accept queue
134 * @note Number of pending connections before refusing new ones
135 */
136#ifndef FTP_LISTEN_BACKLOG
137#define FTP_LISTEN_BACKLOG 8U
138#endif
139 
140/*===========================================================================*
141 * BUFFER SIZES
142 *===========================================================================*/
143 
144/**
145 * File transfer buffer size (must be power of 2)
146 * @note 64KB is optimal for most network/disk combinations
147 * @note Larger buffers provide diminishing returns
148 */
149#ifndef FTP_BUFFER_SIZE
150#if defined(PS5) || defined(PLATFORM_PS5)
151#define FTP_BUFFER_SIZE 1048576U /* 1 MB */
152#elif defined(PS4) || defined(PLATFORM_PS4)
153#define FTP_BUFFER_SIZE 262144U /* 256 KB */
154#else
155#define FTP_BUFFER_SIZE 524288U /* 512 KB */
156#endif
157#endif
158 
159/**
160 * Command line buffer size (RFC 959: max 512 bytes)
161 * @note Includes command + arguments + CRLF
162 */
163#ifndef FTP_CMD_BUFFER_SIZE
164#define FTP_CMD_BUFFER_SIZE 512U
165#endif
166 
167/**
168 * Reply line buffer size
169 * @note Should accommodate longest possible reply
170 */
171#ifndef FTP_REPLY_BUFFER_SIZE
172#define FTP_REPLY_BUFFER_SIZE 1024U
173#endif
174 
175/**
176 * Directory listing line buffer size
177 * @note Long filenames may require larger buffer
178 */
179#ifndef FTP_LIST_LINE_SIZE
180#define FTP_LIST_LINE_SIZE 512U
181#endif
182 
183/*===========================================================================*
184 * PATH LIMITS (Platform-dependent)
185 *===========================================================================*/
186 
187#if defined(PS4) || defined(PS5) || defined(PLATFORM_PS4) || defined(PLATFORM_PS5)
188/**
189 * PlayStation maximum path length
190 * @note PS4/PS5 use custom BSD with 1024-byte limit
191 */
192#ifndef FTP_PATH_MAX
193#define FTP_PATH_MAX 1024U
194#endif
195#elif defined(PS3)
196/**
197 * PlayStation 3 maximum path length
198 * @note PS3 has more limited path support
199 */
200#ifndef FTP_PATH_MAX
201#define FTP_PATH_MAX 512U
202#endif
203#else
204/**
205 * POSIX maximum path length
206 * @note Linux typically supports 4096 bytes
207 */
208#ifndef FTP_PATH_MAX
209#define FTP_PATH_MAX 4096U
210#endif
211#endif
212 
213/**
214 * Maximum directory nesting depth
215 * @note Prevents stack overflow in recursive operations
216 * @note Protects against malicious deep directory structures
217 */
218#ifndef FTP_MAX_PATH_DEPTH
219#define FTP_MAX_PATH_DEPTH 32U
220#endif
221 
222/**
223 * Maximum symlink recursion depth
224 * @note Prevents symlink loops
225 */
226#ifndef FTP_MAX_SYMLINK_DEPTH
227#define FTP_MAX_SYMLINK_DEPTH 8U
228#endif
229 
230/*===========================================================================*
231 * FEATURE FLAGS
232 *===========================================================================*/
233 
234/**
235 * Enable MLST/MLSD commands (RFC 3659)
236 * @note Modern directory listing with machine-readable format
237 */
238#ifndef FTP_ENABLE_MLST
239#define FTP_ENABLE_MLST 1
240#endif
241 
242/**
243 * Enable UTF-8 filename support
244 * @note PS3 does not support UTF-8, disable for that platform
245 */
246#ifndef FTP_ENABLE_UTF8
247#if defined(PS3)
248#define FTP_ENABLE_UTF8 0
249#else
250#define FTP_ENABLE_UTF8 1
251#endif
252#endif
253 
254/**
255 * Enable SIZE command
256 * @note Returns file size in bytes
257 */
258#ifndef FTP_ENABLE_SIZE
259#define FTP_ENABLE_SIZE 1
260#endif
261 
262/**
263 * Enable MDTM command
264 * @note Returns file modification time
265 */
266#ifndef FTP_ENABLE_MDTM
267#define FTP_ENABLE_MDTM 1
268#endif
269 
270/**
271 * Enable REST command
272 * @note Resume interrupted transfers
273 */
274#ifndef FTP_ENABLE_REST
275#define FTP_ENABLE_REST 1
276#endif
277 
278/**
279 * Enable ChaCha20 stream encryption (AUTH XCRYPT)
280 *
281 * ON (1) : Linux, macOS — encrypts ctrl + data channels
282 * OFF (0) : PS4, PS5 — local-network trust, no overhead
283 *
284 * @note Encryption is negotiated per-session via AUTH XCRYPT.
285 * Clients that do not send AUTH XCRYPT transfer in cleartext.
286 */
287#ifndef FTP_ENABLE_CRYPTO
288#if defined(PS4) || defined(PS5) || defined(PLATFORM_PS4) || \
289 defined(PLATFORM_PS5)
290#define FTP_ENABLE_CRYPTO 0
291#else
292#define FTP_ENABLE_CRYPTO 1
293#endif
294#endif
295 
296/**
297 * Pre-shared key for ChaCha20 encryption (256-bit / 32 bytes)
298 *
299 * Override at compile time:
300 * -DFTP_CRYPTO_PSK='{ 0x01,0x02,...,0x20 }'
301 *
302 * @warning Change this default before deploying to production!
303 */
304#ifndef FTP_CRYPTO_PSK
305#define FTP_CRYPTO_PSK \
306 {0x7A, 0x46, 0x54, 0x50, 0x44, 0x2D, 0x43, 0x68, 0x61, 0x43, 0x68, \
307 0x61, 0x32, 0x30, 0x2D, 0x4B, 0x65, 0x79, 0x2D, 0x44, 0x65, 0x66, \
308 0x61, 0x75, 0x6C, 0x74, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E}
309#endif
310 
311/*===========================================================================*
312 * PERFORMANCE TUNING
313 *===========================================================================*/
314 
315#ifndef FTP_LIST_SAFE_MODE
316#if defined(PLATFORM_PS4) || defined(PLATFORM_PS5)
317#define FTP_LIST_SAFE_MODE 1
318#else
319#define FTP_LIST_SAFE_MODE 0
320#endif
321#endif
322 
323/**
324 * Enable TCP_NODELAY (disable Nagle's algorithm)
325 * @note Reduces latency for small packets (control commands)
326 * @note Recommended: enabled for FTP control connection
327 */
328#ifndef FTP_TCP_NODELAY
329#define FTP_TCP_NODELAY 1
330#endif
331 
332/**
333 * TCP send buffer size for control socket (bytes)
334 *
335 * Sized to fill the bandwidth-delay product (BDP):
336 * GbE 1 ms RTT -> BDP = 125 KB -> 1 MB is generous
337 * WiFi 5 ms RTT -> BDP = 62 KB -> 1 MB has headroom
338 */
339#ifndef FTP_TCP_SNDBUF
340#define FTP_TCP_SNDBUF 1048576U
341#endif
342 
343/**
344 * TCP send buffer size for DATA socket (bytes)
345 *
346 * On PS5/PS4, OrbisOS clamps SO_SNDBUF auto-tuning to a system
347 * maximum that is lower than what GbE LAN transfers need.
348 * Setting this explicitly forces 4 MB, covering the BDP for
349 * a 1 GbE link at LAN RTTs (0.1–1 ms) with headroom.
350 *
351 * Set to 0 on other platforms to leave kernel auto-tuning active.
352 */
353#ifndef FTP_TCP_DATA_SNDBUF
354#if defined(PS5) || defined(PLATFORM_PS5) || defined(PS4) || defined(PLATFORM_PS4)
355#define FTP_TCP_DATA_SNDBUF (4U * 1024U * 1024U) /* 4 MB — supera il clamping OrbisOS */
356#else
357#define FTP_TCP_DATA_SNDBUF 0U /* 0 = lascia auto-tuning attivo */
358#endif
359#endif
360 
361/**
362 * Maximum retries when sendfile() returns 0 bytes (TCP back-pressure)
363 *
364 * Each retry sleeps FTP_SENDFILE_EAGAIN_SLEEP_US microseconds.
365 * Total maximum wait = retries × sleep = 256 × 1000 µs = 256 ms.
366 * This covers internet RTTs up to ~256 ms before declaring a driver stall.
367 */
368#ifndef FTP_SENDFILE_EAGAIN_RETRIES
369#define FTP_SENDFILE_EAGAIN_RETRIES 256
370#endif
371 
372/** Sleep between sendfile EAGAIN retries (microseconds) */
373#ifndef FTP_SENDFILE_EAGAIN_SLEEP_US
374#define FTP_SENDFILE_EAGAIN_SLEEP_US 500U /* 0.5 ms — PS5 LAN RTT ~0.1-0.3ms, 1ms era eccessivo */
375#endif
376 
377/**
378 * DESIGN RATIONALE - distinct from PAL_FILE_WRITE_CHUNK_MAX:
379 *
380 * PAL_FILE_WRITE_CHUNK_MAX (64 KB on PS4, 128 KB on PS5) was designed
381 * to keep per-chunk PFS WRITE latency under ~5 ms in the STOR
382 * double-buffer path so the FTP recv thread never starves the TCP
383 * receive window. It is a WRITE latency constraint, not a READ one.
384 *
385 * Using it in cmd_RETR sendfile() penalises downloads with 4-8x the
386 * number of syscalls compared to the HTTP server (512 KB chunks).
387 * Each unnecessary syscall boundary:
388 * - re-acquires the socket lock
389 * - may flush a partial TCP_CORK/TCP_NOPUSH window prematurely
390 * - triggers a false "driver stall" if the send buffer is momentarily
391 * full (TCP back-pressure) before sufficient ACKs have arrived
392 *
393 * 512 KB is:
394 * - below the PS5 sendfile EAGAIN threshold (>= 1 MB)
395 * - large enough that one chunk fills the BDP on most internet paths
396 * - the value HTTP /api/download already uses (HTTP_SENDFILE_CHUNK_SIZE)
397 *
398 * @see cmd_RETR in ftp_commands.c
399 * @see HTTP_SENDFILE_CHUNK_SIZE in http_config.h
400 */
401#ifndef FTP_RETR_SENDFILE_CHUNK
402#define FTP_RETR_SENDFILE_CHUNK (2U * 1024U * 1024U) /* 2 MB — PS5 NVMe: meno syscall boundary, meno TCP flush prematuri */
403#endif
404 
405/**
406 * TCP receive buffer size in bytes
407 *
408 * PS4/PS5: PFS-encrypted writes stall the recv thread while the
409 * double-buffer writer drains each chunk through PFS crypto.
410 * At typical LAN speeds, 1 MB of recv buffer fills in ~10ms
411 * → TCP zero window → sender stalls → FileZilla 20s timeout.
412 * 4 MB gives enough runway to cover the write latency.
413 */
414#ifndef FTP_TCP_RCVBUF
415#if defined(PS5) || defined(PLATFORM_PS5)
416#define FTP_TCP_RCVBUF 4194304U /* 4 MB — absorb PFS write latency */
417#elif defined(PS4) || defined(PLATFORM_PS4)
418#define FTP_TCP_RCVBUF 4194304U /* 4 MB — same reason: PFS crypto stalls recv */
419#else
420#define FTP_TCP_RCVBUF 1048576U /* 1 MB — generic default */
421#endif
422#endif
423 
424/**
425 * Enable SO_KEEPALIVE
426 * @note Detects dead connections via TCP keepalive probes
427 */
428#ifndef FTP_TCP_KEEPALIVE
429#define FTP_TCP_KEEPALIVE 1
430#endif
431 
432/**
433 * Keepalive idle time in seconds
434 * @note Time before first keepalive probe
435 */
436#ifndef FTP_TCP_KEEPIDLE
437#define FTP_TCP_KEEPIDLE 60U
438#endif
439 
440/**
441 * Keepalive interval in seconds
442 * @note Time between keepalive probes
443 */
444#ifndef FTP_TCP_KEEPINTVL
445#define FTP_TCP_KEEPINTVL 10U
446#endif
447 
448/**
449 * Keepalive probe count
450 * @note Number of probes before considering connection dead
451 */
452#ifndef FTP_TCP_KEEPCNT
453#define FTP_TCP_KEEPCNT 3U
454#endif
455 
456#ifndef FTP_SOCKET_TELEMETRY
457#define FTP_SOCKET_TELEMETRY 0
458#endif
459 
460/*===========================================================================*
461 * SECURITY LIMITS
462 *===========================================================================*/
463 
464/**
465 * Maximum authentication attempts before disconnect
466 * @note Prevents brute-force password attacks
467 */
468#ifndef FTP_MAX_AUTH_ATTEMPTS
469#define FTP_MAX_AUTH_ATTEMPTS 3U
470#endif
471 
472/**
473 * Delay after failed authentication (seconds)
474 * @note Slows down brute-force attempts
475 */
476#ifndef FTP_AUTH_DELAY
477#define FTP_AUTH_DELAY 2U
478#endif
479 
480/**
481 * Maximum filename length
482 * @note Conservative limit to prevent buffer overflows
483 */
484#ifndef FTP_MAX_FILENAME_LEN
485#define FTP_MAX_FILENAME_LEN 255U
486#endif
487 
488/*===========================================================================*
489 * THREAD CONFIGURATION
490 *===========================================================================*/
491 
492/**
493 * Thread stack size in bytes
494 * @note Console environments may require larger stacks due to libc/network
495 * internals
496 * @note See whitepaper section 4.2 for worst-case analysis
497 */
498#ifndef FTP_THREAD_STACK_SIZE
499#if defined(PLATFORM_PS4) || defined(PLATFORM_PS5)
500#define FTP_THREAD_STACK_SIZE 524288U
501#else
502#define FTP_THREAD_STACK_SIZE 65536U
503#endif
504#endif
505 
506/*===========================================================================*
507 * DEBUG AND LOGGING
508 *===========================================================================*/
509 
510/**
511 * Enable debug logging
512 * @note Set to 1 for development, 0 for production
513 */
514#ifndef FTP_DEBUG
515#define FTP_DEBUG 0
516#endif
517 
518/**
519 * Enable verbose command logging
520 * @note Logs all FTP commands (privacy concern in production)
521 */
522#ifndef FTP_LOG_COMMANDS
523#define FTP_LOG_COMMANDS 1
524#endif
525 
526/**
527 * Enable performance statistics
528 * @note Track throughput, latency, error rates
529 */
530#ifndef FTP_ENABLE_STATS
531#define FTP_ENABLE_STATS 1
532#endif
533 
534#ifndef FTP_TRANSFER_RATE_LIMIT_BPS
535#define FTP_TRANSFER_RATE_LIMIT_BPS 0U
536#endif
537 
538#ifndef FTP_TRANSFER_RATE_BURST_BYTES
539#define FTP_TRANSFER_RATE_BURST_BYTES (FTP_TRANSFER_RATE_LIMIT_BPS)
540#endif
541 
542#if defined(PLATFORM_PS5)
543#undef FTP_TRANSFER_RATE_LIMIT_BPS
544#define FTP_TRANSFER_RATE_LIMIT_BPS 0U
545#undef FTP_TRANSFER_RATE_BURST_BYTES
546#define FTP_TRANSFER_RATE_BURST_BYTES 0U
547#endif
548 
549/*===========================================================================*
550 * COMPILE-TIME ASSERTIONS
551 *===========================================================================*/
552 
553/* Ensure buffer size is power of 2 (optimization) */
554_Static_assert((FTP_BUFFER_SIZE & (FTP_BUFFER_SIZE - 1U)) == 0U,
555 "FTP_BUFFER_SIZE must be power of 2");
556 
557/* Ensure command buffer meets RFC 959 requirement */
558_Static_assert(FTP_CMD_BUFFER_SIZE >= 512U,
559 "FTP_CMD_BUFFER_SIZE must be >= 512 bytes (RFC 959)");
560 
561/* Ensure at least one session allowed */
562_Static_assert(FTP_MAX_SESSIONS > 0U, "FTP_MAX_SESSIONS must be > 0");
563 
564/* Ensure reasonable session limit (resource exhaustion) */
565_Static_assert(FTP_MAX_SESSIONS <= 256U, "FTP_MAX_SESSIONS must be <= 256");
566 
567/* Ensure path depth is reasonable */
568_Static_assert(FTP_MAX_PATH_DEPTH > 0U && FTP_MAX_PATH_DEPTH <= 128U,
569 "FTP_MAX_PATH_DEPTH must be 1-128");
570 
571/* Ensure stack size is sufficient (minimum 32KB) */
572_Static_assert(FTP_THREAD_STACK_SIZE >= 32768U,
573 "FTP_THREAD_STACK_SIZE must be >= 32KB");
574 
575#endif /* FTP_CONFIG_H */
576