Line data Source code
1 : /*
2 : * PeerTalk POSIX Networking Layer
3 : *
4 : * Platform-specific networking implementation using BSD sockets.
5 : * Implements UDP discovery, TCP connections, and message I/O.
6 : */
7 :
8 : #ifndef PT_NET_POSIX_H
9 : #define PT_NET_POSIX_H
10 :
11 : #include "pt_internal.h"
12 : #include "protocol.h"
13 : #include <sys/uio.h> /* For struct iovec, writev() */
14 : #include <sys/select.h> /* For fd_set, FD_SET, etc. */
15 :
16 : /* ========================================================================== */
17 : /* Receive State Machine (Data-Oriented Design) */
18 : /* ========================================================================== */
19 :
20 : /**
21 : * Receive state - using uint8_t instead of enum for cache efficiency
22 : *
23 : * On 68030, enum uses 4 bytes. Using uint8_t reduces hot section from
24 : * 4 bytes to 1 byte, keeping per-peer state smaller.
25 : */
26 : typedef uint8_t pt_recv_state;
27 : #define PT_RECV_HEADER 0 /* Waiting for header bytes */
28 : #define PT_RECV_PAYLOAD 1 /* Waiting for payload bytes */
29 : #define PT_RECV_CRC 2 /* Waiting for CRC bytes */
30 :
31 : /* ========================================================================== */
32 : /* Per-Peer Receive Buffers (HOT/COLD Separation) */
33 : /* ========================================================================== */
34 :
35 : /**
36 : * HOT Section - checked every poll cycle per active connection (8 bytes)
37 : *
38 : * CRITICAL 68k ALIGNMENT: _pad0 ensures bytes_needed starts at even offset.
39 : * On 68000/68020/68030, uint16_t at odd offsets causes performance penalty
40 : * or crashes. This padding is NOT optional.
41 : *
42 : * With 16 peers, hot scan touches only 128 bytes (fits in 68030 L1 cache)
43 : * instead of 131KB if payload buffers were inline.
44 : */
45 : typedef struct {
46 : pt_recv_state state; /* 1 byte at offset 0 */
47 : uint8_t is_compact; /* 1 byte at offset 1: 1 if current msg is compact header */
48 : uint16_t bytes_needed; /* 2 bytes at offset 2 */
49 : uint16_t bytes_received; /* 2 bytes at offset 4 */
50 : uint16_t _pad1; /* 2 bytes at offset 6: align to 8 bytes */
51 : } pt_recv_hot; /* Total: 8 bytes, all uint16_t at even offsets */
52 :
53 : /**
54 : * COLD Section - only accessed when actual I/O happens
55 : *
56 : * Large buffers separated to avoid cache pollution during hot scans.
57 : */
58 : typedef struct {
59 : pt_message_header hdr;
60 : uint8_t header_buf[PT_MESSAGE_HEADER_SIZE]; /* 10 bytes */
61 : uint8_t crc_buf[2];
62 : uint8_t payload_buf[PT_MAX_MESSAGE_SIZE];
63 : } pt_recv_cold;
64 :
65 : /**
66 : * Complete receive buffer - hot and cold sections
67 : *
68 : * IMPORTANT: These are allocated separately (not inline in pt_posix_data)
69 : * to prevent massive payload buffers from polluting cache when accessing
70 : * hot fields in the platform context.
71 : */
72 : typedef struct {
73 : pt_recv_hot hot;
74 : pt_recv_cold cold;
75 : } pt_recv_buffer;
76 :
77 : /* ========================================================================== */
78 : /* Platform Context Extension (pt_posix_data) */
79 : /* ========================================================================== */
80 :
81 : /**
82 : * POSIX platform-specific data
83 : *
84 : * Extends pt_context with networking state. Allocated after pt_context
85 : * structure via pt_posix_extra_size().
86 : *
87 : * Field ordering follows Data-Oriented Design:
88 : * - HOT: Accessed every poll cycle
89 : * - WARM: Accessed on socket operations
90 : * - COLD: Per-peer data
91 : *
92 : * recv_bufs is a POINTER, not inline array, to avoid cache pollution.
93 : */
94 : typedef struct {
95 : /* HOT - accessed every poll cycle (20 bytes on 32-bit) */
96 : int max_fd; /* 4 bytes: highest fd for select() */
97 : uint8_t active_count; /* 1 byte: number of active peer connections */
98 : uint8_t fd_dirty; /* 1 byte: non-zero when fd_sets need rebuild */
99 : uint16_t batch_count; /* 2 bytes: messages in current batch */
100 : pt_tick_t last_announce; /* 4 bytes: tick of last discovery announce */
101 : uint32_t local_ip; /* 4 bytes: our IP (for filtering own broadcasts) */
102 : uint8_t _pad0[4]; /* 4 bytes: align to 8-byte boundary */
103 :
104 : /* Active peer tracking - O(1) removal via swap-back */
105 : uint8_t active_peers[PT_MAX_PEERS]; /* Indices of peers with active sockets */
106 : uint8_t active_position[PT_MAX_PEERS]; /* Reverse mapping for O(1) removal */
107 :
108 : /* WARM - accessed on socket operations (24 bytes) */
109 : int discovery_sock;
110 : int listen_sock;
111 : int udp_msg_sock;
112 : uint32_t broadcast_addr; /* INADDR_BROADCAST */
113 : uint16_t discovery_port;
114 : uint16_t listen_port;
115 : uint16_t udp_msg_port;
116 : uint16_t _pad1;
117 :
118 : /* Cached fd_set - rebuilt only when fd_dirty is set */
119 : fd_set cached_read_fds;
120 : fd_set cached_write_fds;
121 :
122 : /* COLD - per-peer data */
123 : int tcp_socks[PT_MAX_PEERS]; /* TCP socket per peer, -1 if not connected */
124 :
125 : /* SEPARATE ALLOCATION - do NOT embed inline */
126 : pt_recv_buffer *recv_bufs; /* Pointer to allocated array */
127 : } pt_posix_data;
128 :
129 : /* ========================================================================== */
130 : /* Helper Inline Functions */
131 : /* ========================================================================== */
132 :
133 : /**
134 : * Get POSIX platform data from context
135 : *
136 : * The platform data is allocated immediately after the context structure.
137 : */
138 1965 : static inline pt_posix_data *pt_posix_get(struct pt_context *ctx) {
139 1965 : return (pt_posix_data *)((char *)ctx + sizeof(struct pt_context));
140 : }
141 :
142 : /* ========================================================================== */
143 : /* Platform Size/Init */
144 : /* ========================================================================== */
145 :
146 : /**
147 : * Return extra memory size needed for POSIX platform data
148 : */
149 : size_t pt_posix_extra_size(void);
150 :
151 : /**
152 : * Initialize POSIX networking subsystem
153 : *
154 : * Creates sockets, initializes data structures, detects local IP.
155 : * Called from PeerTalk_Init().
156 : *
157 : * Returns: 0 on success, -1 on failure
158 : */
159 : int pt_posix_net_init(struct pt_context *ctx);
160 :
161 : /**
162 : * Shutdown POSIX networking subsystem
163 : *
164 : * Closes all sockets, frees allocated buffers.
165 : * Called from PeerTalk_Shutdown().
166 : */
167 : void pt_posix_net_shutdown(struct pt_context *ctx);
168 :
169 : /* ========================================================================== */
170 : /* Discovery */
171 : /* ========================================================================== */
172 :
173 : /**
174 : * Start UDP discovery broadcasts
175 : *
176 : * Creates discovery socket, enables broadcast, sends initial announcement.
177 : *
178 : * Returns: 0 on success, -1 on failure
179 : */
180 : int pt_posix_discovery_start(struct pt_context *ctx);
181 :
182 : /**
183 : * Stop UDP discovery broadcasts
184 : *
185 : * Closes discovery socket.
186 : */
187 : void pt_posix_discovery_stop(struct pt_context *ctx);
188 :
189 : /**
190 : * Poll discovery socket for incoming packets
191 : *
192 : * Non-blocking receive of discovery packets. Processes ANNOUNCE, QUERY,
193 : * GOODBYE types. Creates/updates/removes peers as appropriate.
194 : *
195 : * Returns: 1 if packet processed, 0 if no data, -1 on error
196 : */
197 : int pt_posix_discovery_poll(struct pt_context *ctx);
198 :
199 : /**
200 : * Send discovery packet
201 : *
202 : * @param ctx Context
203 : * @param type PT_DISC_TYPE_ANNOUNCE, PT_DISC_TYPE_QUERY, or PT_DISC_TYPE_GOODBYE
204 : *
205 : * Returns: 0 on success, -1 on failure
206 : */
207 : int pt_posix_discovery_send(struct pt_context *ctx, uint8_t type);
208 :
209 : /* ========================================================================== */
210 : /* TCP Server */
211 : /* ========================================================================== */
212 :
213 : /**
214 : * Start TCP listening socket
215 : *
216 : * Creates listening socket on TCP port for incoming connections.
217 : *
218 : * Returns: 0 on success, -1 on failure
219 : */
220 : int pt_posix_listen_start(struct pt_context *ctx);
221 :
222 : /**
223 : * Stop TCP listening socket
224 : */
225 : void pt_posix_listen_stop(struct pt_context *ctx);
226 :
227 : /**
228 : * Poll TCP listening socket for incoming connections
229 : *
230 : * Non-blocking accept() of incoming connections.
231 : *
232 : * Returns: 1 if connection accepted, 0 if no pending, -1 on error
233 : */
234 : int pt_posix_listen_poll(struct pt_context *ctx);
235 :
236 : /* ========================================================================== */
237 : /* TCP Client */
238 : /* ========================================================================== */
239 :
240 : /**
241 : * Connect to a peer via TCP
242 : *
243 : * Initiates non-blocking connection to peer. Connection completes
244 : * asynchronously; poll for writability to detect completion.
245 : *
246 : * Returns: 0 on success (connecting), -1 on failure
247 : */
248 : int pt_posix_connect(struct pt_context *ctx, struct pt_peer *peer);
249 :
250 : /**
251 : * Disconnect from a peer
252 : *
253 : * Closes TCP connection, removes from active peer tracking.
254 : *
255 : * Returns: 0 on success, -1 on failure
256 : */
257 : int pt_posix_disconnect(struct pt_context *ctx, struct pt_peer *peer);
258 :
259 : /* ========================================================================== */
260 : /* I/O */
261 : /* ========================================================================== */
262 :
263 : /**
264 : * Send data to peer
265 : *
266 : * Non-blocking send. If socket buffer is full, returns PT_ERR_WOULD_BLOCK.
267 : *
268 : * Returns: 0 on success, PT_ERR_WOULD_BLOCK if would block, -1 on error
269 : */
270 : int pt_posix_send(struct pt_context *ctx, struct pt_peer *peer,
271 : const void *data, size_t len);
272 :
273 : /**
274 : * Receive data from peer
275 : *
276 : * Non-blocking receive with state machine for header/payload/CRC.
277 : *
278 : * Returns: 1 if complete message received, 0 if incomplete, -1 on error
279 : */
280 : int pt_posix_recv(struct pt_context *ctx, struct pt_peer *peer);
281 :
282 : /**
283 : * Send control message to peer
284 : *
285 : * Helper for sending protocol control messages (PING, PONG, etc).
286 : *
287 : * Returns: 0 on success, -1 on failure
288 : */
289 : int pt_posix_send_control(struct pt_context *ctx, struct pt_peer *peer,
290 : uint8_t msg_type);
291 :
292 : /**
293 : * Send capability message to peer
294 : *
295 : * Called after connection established to exchange capability information.
296 : * Enables automatic fragmentation for constrained peers.
297 : *
298 : * Returns: PT_OK on success, error code on failure
299 : */
300 : int pt_posix_send_capability(struct pt_context *ctx, struct pt_peer *peer);
301 :
302 : /* ========================================================================== */
303 : /* UDP Messaging (Session 4.4) */
304 : /* ========================================================================== */
305 :
306 : /**
307 : * Initialize UDP messaging socket (separate from discovery)
308 : *
309 : * Returns: 0 on success, -1 on failure
310 : */
311 : int pt_posix_udp_init(struct pt_context *ctx);
312 :
313 : /**
314 : * Shutdown UDP messaging socket
315 : */
316 : void pt_posix_udp_shutdown(struct pt_context *ctx);
317 :
318 : /**
319 : * Send unreliable UDP message to peer
320 : *
321 : * Returns: 0 on success, -1 on failure
322 : */
323 : int pt_posix_send_udp(struct pt_context *ctx, struct pt_peer *peer,
324 : const void *data, uint16_t len);
325 :
326 : /**
327 : * Receive UDP message
328 : *
329 : * Non-blocking receive of UDP messages (not discovery packets).
330 : *
331 : * Returns: 1 if message received, 0 if no data, -1 on error
332 : */
333 : int pt_posix_recv_udp(struct pt_context *ctx);
334 :
335 : /* ========================================================================== */
336 : /* Main Poll */
337 : /* ========================================================================== */
338 :
339 : /**
340 : * Main POSIX poll function
341 : *
342 : * Polls all sockets (discovery, listen, UDP, TCP peers) using select().
343 : * Delegates to appropriate handlers based on ready sockets.
344 : *
345 : * Returns: 0 on success, -1 on error
346 : */
347 : int pt_posix_poll(struct pt_context *ctx);
348 :
349 : /**
350 : * Fast POSIX poll function
351 : *
352 : * Only handles TCP I/O for connected peers - no discovery, UDP, listen,
353 : * periodic announces, or peer timeouts. Use for tight game loops.
354 : *
355 : * Performs:
356 : * - TCP send queue drain for connected peers
357 : * - TCP receive for connected peers
358 : *
359 : * Does NOT:
360 : * - Poll discovery socket
361 : * - Poll UDP message socket
362 : * - Poll listen socket for new connections
363 : * - Send periodic discovery announces
364 : * - Check peer timeouts
365 : *
366 : * Returns: 0 on success, -1 on error
367 : */
368 : int pt_posix_poll_fast(struct pt_context *ctx);
369 :
370 : #endif /* PT_NET_POSIX_H */
|