Zero-copy FTP/HTTP Daemon compatible with all POSIX systems
| 1 | /* |
| 2 | MIT License |
| 3 | |
| 4 | Copyright (c) 2026 Seregon |
| 5 | |
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy |
| 7 | of this software and associated documentation files (the "Software"), to deal |
| 8 | in the Software without restriction, including without limitation the rights |
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 10 | copies of the Software, and to permit persons to whom the Software is |
| 11 | furnished to do so, subject to the following conditions: |
| 12 | |
| 13 | The above copyright notice and this permission notice shall be included in all |
| 14 | copies or substantial portions of the Software. |
| 15 | |
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 22 | SOFTWARE. |
| 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 |