Add transport module: TCP framing, thread-per-connection, inbound limit
transport_server_create/start: binds TCP, spawns accept thread, closes excess inbound connections when max_connections is reached. transport_connect: outbound TCP, spawns read thread before returning. transport_send_frame: packs 8-byte header with serial put_*, then writes header + payload under a per-connection mutex (thread-safe). Read thread: reads header, validates payload_length <= max_payload, mallocs payload, calls on_frame (callback owns and must free payload). On error or disconnect calls on_disconnect then frees conn. transport_cli: server mode echoes received frames; client mode sends 3 test frames and prints echoes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
89
include/transport.h
Normal file
89
include/transport.h
Normal file
@@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "error.h"
|
||||
|
||||
#define TRANSPORT_FRAME_HEADER_SIZE 8u
|
||||
#define TRANSPORT_DEFAULT_MAX_PAYLOAD (16u * 1024u * 1024u)
|
||||
|
||||
struct Transport_Conn;
|
||||
struct Transport_Server;
|
||||
|
||||
/*
|
||||
* A received frame. payload is malloc'd by the transport layer;
|
||||
* the on_frame callback takes ownership and must free it.
|
||||
* payload is NULL when payload_length is 0.
|
||||
*/
|
||||
struct Transport_Frame {
|
||||
uint16_t message_type;
|
||||
uint16_t channel_id;
|
||||
uint32_t payload_length;
|
||||
uint8_t *payload;
|
||||
};
|
||||
|
||||
typedef void (*Transport_Frame_Cb)(
|
||||
struct Transport_Conn *conn,
|
||||
struct Transport_Frame *frame,
|
||||
void *userdata);
|
||||
|
||||
typedef void (*Transport_Connect_Cb)(
|
||||
struct Transport_Conn *conn,
|
||||
void *userdata);
|
||||
|
||||
typedef void (*Transport_Disconnect_Cb)(
|
||||
struct Transport_Conn *conn,
|
||||
void *userdata);
|
||||
|
||||
struct Transport_Server_Config {
|
||||
uint16_t port;
|
||||
int max_connections; /* inbound limit; excess connections are closed immediately */
|
||||
uint32_t max_payload; /* max payload bytes; frames exceeding this disconnect the peer */
|
||||
Transport_Frame_Cb on_frame; /* required */
|
||||
Transport_Connect_Cb on_connect; /* optional; called before read loop starts */
|
||||
Transport_Disconnect_Cb on_disconnect; /* optional; called from read thread before conn is freed */
|
||||
void *userdata;
|
||||
};
|
||||
|
||||
/* Create a server (does not start listening yet). */
|
||||
struct App_Error transport_server_create(struct Transport_Server **out,
|
||||
struct Transport_Server_Config *config);
|
||||
|
||||
/* Bind, listen, and spawn the accept thread. */
|
||||
struct App_Error transport_server_start(struct Transport_Server *server);
|
||||
|
||||
/*
|
||||
* Stop accepting new connections and free the server.
|
||||
* Active connections continue until they disconnect naturally.
|
||||
*/
|
||||
void transport_server_destroy(struct Transport_Server *server);
|
||||
|
||||
/*
|
||||
* Connect outbound to host:port and spawn a read thread.
|
||||
* on_disconnect is optional. on_frame is required.
|
||||
* The conn is freed when the read thread exits.
|
||||
* Do not use conn after on_disconnect has been called.
|
||||
*/
|
||||
struct App_Error transport_connect(struct Transport_Conn **out,
|
||||
const char *host,
|
||||
uint16_t port,
|
||||
uint32_t max_payload,
|
||||
Transport_Frame_Cb on_frame,
|
||||
Transport_Disconnect_Cb on_disconnect,
|
||||
void *userdata);
|
||||
|
||||
/*
|
||||
* Send a frame. Thread-safe.
|
||||
* payload may be NULL when length is 0.
|
||||
*/
|
||||
struct App_Error transport_send_frame(struct Transport_Conn *conn,
|
||||
uint16_t message_type,
|
||||
uint16_t channel_id,
|
||||
const uint8_t *payload,
|
||||
uint32_t length);
|
||||
|
||||
/*
|
||||
* Close the connection fd. The read thread will detect the error,
|
||||
* call on_disconnect, then free the conn.
|
||||
* Do not use conn after calling this.
|
||||
*/
|
||||
void transport_conn_close(struct Transport_Conn *conn);
|
||||
Reference in New Issue
Block a user