#pragma once #include #include "error.h" #define TRANSPORT_FRAME_HEADER_SIZE 6u #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. * * The header carries only message_type and payload_length. * All message-specific fields (stream_id, request_id, etc.) are * the first bytes of the payload, interpreted by the message handler. */ struct Transport_Frame { uint16_t message_type; 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, 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);