Seregon/zftpd

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

C/11.0 KB/No license
include/pal_network.h
zftpd / include / pal_network.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 pal_network.h
27 * @brief Platform-agnostic network I/O operations
28 *
29 * @author SeregonWar
30 * @version 1.0.0
31 * @date 2026-02-13
32 *
33 * DESIGN: Zero-overhead abstraction via compile-time selection
34 * PERFORMANCE: Inline functions and macros (no runtime cost)
35 *
36 */
37 
38#ifndef PAL_NETWORK_H
39#define PAL_NETWORK_H
40 
41#include "ftp_types.h"
42#include <arpa/inet.h>
43#include <netinet/in.h>
44#include <netinet/tcp.h>
45#include <sys/socket.h>
46#include <unistd.h>
47 
48/*===========================================================================*
49 * PLATFORM DETECTION
50 *===========================================================================*/
51 
52#if defined(__PS3__)
53#define PLATFORM_PS3 1
54#elif defined(__ORBIS__) || defined(PS4)
55#define PLATFORM_PS4 1
56#elif defined(__PROSPERO__) || defined(PS5)
57#define PLATFORM_PS5 1
58#elif defined(__linux__)
59#define PLATFORM_LINUX 1
60#elif defined(__FreeBSD__)
61#define PLATFORM_FREEBSD 1
62#else
63#define PLATFORM_POSIX 1
64#endif
65 
66/*===========================================================================*
67 * PLATFORM-SPECIFIC INCLUDES
68 *===========================================================================*/
69 
70#ifdef PLATFORM_PS4
71/* PS4 payload environment provides BSD/POSIX networking via libc */
72#endif
73 
74#ifdef PLATFORM_PS5
75/* PS5 uses standard BSD sockets via syscalls */
76#include <sys/syscall.h>
77#endif
78 
79#ifdef PLATFORM_PS3
80#include <net/net.h>
81/* PS3 uses custom network stack */
82#endif
83 
84/*===========================================================================*
85 * SOCKET TYPE ABSTRACTION
86 *===========================================================================*/
87 
88typedef int socket_t;
89 
90#define INVALID_SOCKET (-1)
91#define SOCKET_ERROR (-1)
92 
93/*===========================================================================*
94 * NETWORK API MACROS
95 *===========================================================================*/
96 
97#ifdef PLATFORM_PS4
98/**
99 * PS4 socket operations (BSD/POSIX)
100 */
101#define PAL_SOCKET(domain, type, proto) socket((domain), (type), (proto))
102 
103#define PAL_BIND(s, addr, len) bind((s), (addr), (len))
104 
105#define PAL_LISTEN(s, backlog) listen((s), (backlog))
106 
107#define PAL_ACCEPT(s, addr, len) accept((s), (addr), (len))
108 
109#define PAL_CONNECT(s, addr, len) connect((s), (addr), (len))
110 
111#define PAL_SEND(s, buf, len, flags) send((s), (buf), (len), (flags))
112 
113#define PAL_RECV(s, buf, len, flags) recv((s), (buf), (len), (flags))
114 
115#define PAL_SENDTO(s, buf, len, flags, addr, addrlen) \
116 sendto((s), (buf), (len), (flags), (addr), (addrlen))
117 
118#define PAL_RECVFROM(s, buf, len, flags, addr, addrlen) \
119 recvfrom((s), (buf), (len), (flags), (addr), (addrlen))
120 
121#define PAL_CLOSE(s) close(s)
122 
123#define PAL_SETSOCKOPT(s, level, optname, optval, optlen) \
124 setsockopt((s), (level), (optname), (optval), (optlen))
125 
126#define PAL_GETSOCKOPT(s, level, optname, optval, optlen) \
127 getsockopt((s), (level), (optname), (optval), (optlen))
128 
129#define PAL_GETSOCKNAME(s, addr, len) getsockname((s), (addr), (len))
130 
131#define PAL_GETPEERNAME(s, addr, len) getpeername((s), (addr), (len))
132 
133#define PAL_HTONL(x) htonl(x)
134#define PAL_HTONS(x) htons(x)
135#define PAL_NTOHL(x) ntohl(x)
136#define PAL_NTOHS(x) ntohs(x)
137 
138#define PAL_INET_NTOP(af, src, dst, size) inet_ntop((af), (src), (dst), (size))
139 
140#define PAL_INET_PTON(af, src, dst) inet_pton((af), (src), (dst))
141 
142#elif defined(PLATFORM_PS5)
143/**
144 * PS5 socket operations (standard BSD via syscalls)
145 */
146#define PAL_SOCKET(domain, type, proto) socket((domain), (type), (proto))
147 
148#define PAL_BIND(s, addr, len) bind((s), (addr), (len))
149 
150#define PAL_LISTEN(s, backlog) listen((s), (backlog))
151 
152#define PAL_ACCEPT(s, addr, len) accept((s), (addr), (len))
153 
154#define PAL_CONNECT(s, addr, len) connect((s), (addr), (len))
155 
156#define PAL_SEND(s, buf, len, flags) send((s), (buf), (len), (flags))
157 
158#define PAL_RECV(s, buf, len, flags) recv((s), (buf), (len), (flags))
159 
160#define PAL_SENDTO(s, buf, len, flags, addr, addrlen) \
161 sendto((s), (buf), (len), (flags), (addr), (addrlen))
162 
163#define PAL_RECVFROM(s, buf, len, flags, addr, addrlen) \
164 recvfrom((s), (buf), (len), (flags), (addr), (addrlen))
165 
166#define PAL_CLOSE(s) close(s)
167 
168#define PAL_SETSOCKOPT(s, level, optname, optval, optlen) \
169 setsockopt((s), (level), (optname), (optval), (optlen))
170 
171#define PAL_GETSOCKOPT(s, level, optname, optval, optlen) \
172 getsockopt((s), (level), (optname), (optval), (optlen))
173 
174#define PAL_GETSOCKNAME(s, addr, len) getsockname((s), (addr), (len))
175 
176#define PAL_GETPEERNAME(s, addr, len) getpeername((s), (addr), (len))
177 
178#define PAL_HTONL(x) htonl(x)
179#define PAL_HTONS(x) htons(x)
180#define PAL_NTOHL(x) ntohl(x)
181#define PAL_NTOHS(x) ntohs(x)
182 
183#define PAL_INET_NTOP(af, src, dst, size) inet_ntop((af), (src), (dst), (size))
184 
185#define PAL_INET_PTON(af, src, dst) inet_pton((af), (src), (dst))
186 
187#else /* POSIX (Linux, FreeBSD, etc.) */
188/**
189 * Standard POSIX socket operations
190 */
191#define PAL_SOCKET socket
192#define PAL_BIND bind
193#define PAL_LISTEN listen
194#define PAL_ACCEPT accept
195#define PAL_CONNECT connect
196#define PAL_SEND send
197#define PAL_RECV recv
198#define PAL_SENDTO sendto
199#define PAL_RECVFROM recvfrom
200#define PAL_CLOSE close
201#define PAL_SETSOCKOPT setsockopt
202#define PAL_GETSOCKOPT getsockopt
203#define PAL_GETSOCKNAME getsockname
204#define PAL_GETPEERNAME getpeername
205#define PAL_HTONL htonl
206#define PAL_HTONS htons
207#define PAL_NTOHL ntohl
208#define PAL_NTOHS ntohs
209#define PAL_INET_NTOP inet_ntop
210#define PAL_INET_PTON inet_pton
211#endif
212 
213/*===========================================================================*
214 * NETWORK INITIALIZATION
215 *===========================================================================*/
216 
217/**
218 * @brief Initialize platform network subsystem
219 *
220 * @return FTP_OK on success, negative error code on failure
221 *
222 * @note PS4: Initializes libkernel networking
223 * @note PS5: No-op (network always available)
224 * @note POSIX: No-op (network always available)
225 *
226 * @note Thread-safety: Must be called before any network operations
227 * @note Call only once during application startup
228 */
229ftp_error_t pal_network_init(void);
230 
231/**
232 * @brief Cleanup platform network subsystem
233 *
234 * @note PS4: Terminates libkernel networking
235 * @note PS5/POSIX: No-op
236 *
237 * @note Thread-safety: Must be called after all network operations complete
238 * @note Call only once during application shutdown
239 */
240void pal_network_fini(void);
241 
242/*===========================================================================*
243 * SOCKET CONFIGURATION
244 *===========================================================================*/
245 
246/**
247 * @brief Configure socket for optimal FTP performance
248 *
249 * @param fd Socket file descriptor
250 *
251 * @return FTP_OK on success, negative error code on failure
252 * @retval FTP_OK All options set successfully
253 * @retval FTP_ERR_INVALID_PARAM Invalid socket descriptor
254 * @retval FTP_ERR_SOCKET_SEND setsockopt() failed
255 *
256 * @pre fd >= 0
257 * @pre fd is a valid socket descriptor
258 *
259 * @note Sets the following options:
260 * - TCP_NODELAY (disable Nagle's algorithm)
261 * - SO_SNDBUF (send buffer size)
262 * - SO_RCVBUF (receive buffer size)
263 * - SO_KEEPALIVE (enable keepalive)
264 * - TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT (keepalive params)
265 *
266 * @note Thread-safety: Safe to call on different sockets concurrently
267 */
268ftp_error_t pal_socket_configure(socket_t fd);
269 
270/**
271 * @brief Configure data socket for bulk file transfer
272 *
273 * Unlike pal_socket_configure() (ctrl channel), this function:
274 * - Enables Nagle (TCP_NODELAY=0) for bulk coalescing
275 * - Sets SO_RCVTIMEO / SO_SNDTIMEO to FTP_DATA_IO_TIMEOUT_MS
276 * - Sets SO_LINGER to flush remaining data on close
277 * - Keeps SO_KEEPALIVE and large SO_SNDBUF / SO_RCVBUF
278 *
279 * @param fd Socket file descriptor
280 * @return FTP_OK on success
281 */
282ftp_error_t pal_socket_configure_data(socket_t fd);
283 
284/**
285 * @brief Set socket to non-blocking mode
286 *
287 * @param fd Socket file descriptor
288 *
289 * @return FTP_OK on success, negative error code on failure
290 *
291 * @pre fd >= 0
292 */
293ftp_error_t pal_socket_set_nonblocking(socket_t fd);
294 
295/**
296 * @brief Set socket to blocking mode
297 *
298 * @param fd Socket file descriptor
299 *
300 * @return FTP_OK on success, negative error code on failure
301 *
302 * @pre fd >= 0
303 */
304ftp_error_t pal_socket_set_blocking(socket_t fd);
305 
306/**
307 * @brief Enable address reuse on socket
308 *
309 * @param fd Socket file descriptor
310 *
311 * @return FTP_OK on success, negative error code on failure
312 *
313 * @pre fd >= 0
314 *
315 * @note Required to avoid "Address already in use" errors on restart
316 */
317ftp_error_t pal_socket_set_reuseaddr(socket_t fd);
318 
319/**
320 * @brief Cork data socket (hold TCP segments for coalescing)
321 *
322 * Call before a burst of small sends (e.g. sendfile loop).
323 * Accumulated data is flushed as large MSS packets on uncork.
324 *
325 * Linux: TCP_CORK
326 * BSD/PS5: TCP_NOPUSH
327 */
328void pal_socket_cork(socket_t fd);
329 
330/**
331 * @brief Uncork data socket (flush accumulated segments)
332 */
333void pal_socket_uncork(socket_t fd);
334 
335ftp_error_t pal_socket_set_timeouts(socket_t fd, uint32_t recv_timeout_ms,
336 uint32_t send_timeout_ms);
337 
338ssize_t pal_send_all(socket_t fd, const void *buffer, size_t length, int flags);
339 
340/*===========================================================================*
341 * UTILITY FUNCTIONS
342 *===========================================================================*/
343 
344/**
345 * @brief Get IP address from sockaddr structure
346 *
347 * @param addr Socket address structure
348 * @param buffer Output buffer for IP string
349 * @param size Size of output buffer
350 *
351 * @return FTP_OK on success, negative error code on failure
352 *
353 * @pre addr != NULL
354 * @pre buffer != NULL
355 * @pre size >= INET_ADDRSTRLEN
356 *
357 * @post buffer contains null-terminated IP address string
358 *
359 * @note Thread-safety: Safe (no shared state)
360 */
361ftp_error_t pal_sockaddr_to_ip(const struct sockaddr_in *addr, char *buffer,
362 size_t size);
363 
364ftp_error_t pal_network_get_primary_ip(char *buffer, size_t size);
365 
366/**
367 * @brief Get port number from sockaddr structure
368 *
369 * @param addr Socket address structure
370 *
371 * @return Port number in host byte order, or 0 on error
372 *
373 * @pre addr != NULL
374 *
375 * @note Thread-safety: Safe (no shared state)
376 */
377uint16_t pal_sockaddr_get_port(const struct sockaddr_in *addr);
378 
379/**
380 * @brief Create sockaddr_in structure from IP and port
381 *
382 * @param ip IP address string (e.g., "192.168.1.1")
383 * @param port Port number (host byte order)
384 * @param addr Output sockaddr_in structure
385 *
386 * @return FTP_OK on success, negative error code on failure
387 *
388 * @pre ip != NULL
389 * @pre addr != NULL
390 * @pre port > 0
391 *
392 * @post addr is initialized with IP and port
393 *
394 * @note Thread-safety: Safe (no shared state)
395 */
396ftp_error_t pal_make_sockaddr(const char *ip, uint16_t port,
397 struct sockaddr_in *addr);
398 
399/**
400 * @brief Create sockaddr from address:port string with IPv6 bracket support
401 *
402 * Parses both IPv4 and IPv6 addresses:
403 * - "192.168.1.1:8888" → IPv4
404 * - "[::1]:8888" → IPv6 loopback
405 * - "[fe80::2e4:21ff:fef5:240d]:8888" → IPv6 link-local
406 *
407 * @param addr_str Address string with embedded port
408 * @param out_addr Output sockaddr_storage (union of IPv4/IPv6)
409 * @param out_len Output length (sizeof(sockaddr_in) or sizeof(sockaddr_in6))
410 *
411 * @return FTP_OK on success, FTP_ERR_INVALID_PARAM on parse error
412 *
413 * @note Thread-safety: Safe (no shared state)
414 */
415ftp_error_t pal_make_sockaddr_ex(const char *addr_str,
416 struct sockaddr_storage *out_addr,
417 socklen_t *out_len);
418 
419#endif /* PAL_NETWORK_H */
420 
421/*===========================================================================*
422 * NETWORK STACK RESET (Issues #3, #4, #7)
423 *===========================================================================*/
424 
425#include "ftp_types.h"
426#include <stddef.h>
427 
428/**
429 * @brief Reset TCP buffer accounting for idle FTP sessions.
430 *
431 * Flushes kernel SO_SNDBUF / SO_RCVBUF accounting and closes orphaned data
432 * sockets. Addresses progressive throughput degradation after large transfers
433 * to the internal SSD or M.2 on PS4/PS5.
434 *
435 * @param sessions Pointer to the server session pool (ftp_server_context_t.sessions)
436 * @param count Pool size (FTP_MAX_SESSIONS)
437 *
438 * @return 0 on success, -1 if sessions/count invalid
439 *
440 * @note Thread-safety: Do NOT call while a session is mid-accept.
441 * Safe to call from the HTTP API handler thread.
442 * @note Does NOT interrupt active (TRANSFERRING) sessions.
443 */
444int pal_network_reset_ftp_stack(ftp_session_t *sessions, size_t count);
445