diff --git a/architecture.md b/architecture.md index 762aacd..e635e2a 100644 --- a/architecture.md +++ b/architecture.md @@ -126,20 +126,23 @@ Header fields: | Field | Size | Purpose | |---|---|---| -| `message_type` | 2 bytes | Distinguishes video frame, control request, control response | -| `channel_id` | 2 bytes | For video: identifies the stream. For control: identifies the request/response pair (correlation ID) | +| `message_type` | 2 bytes | Determines how the payload is interpreted | | `payload_length` | 4 bytes | Byte length of the following payload | -**Message types:** +The header is intentionally minimal. Any node — including a relay that does not recognise a message type — can skip or forward the frame by reading exactly `payload_length` bytes without needing to understand the payload. All message-specific identifiers (stream ID, correlation ID, etc.) live inside the payload and are handled by the relevant message type handler. -| Value | Meaning | -|---|---| -| `0x0001` | Video frame | -| `0x0002` | Control request | -| `0x0003` | Control response | -| `0x0004` | Stream event | +**Message types and their payload structure:** -Video frame payloads are raw compressed frames. Control payloads are binary-serialized structures — see [Protocol Serialization](#protocol-serialization). Stream events carry lifecycle signals for a channel — see [Device Resilience](#device-resilience). +| Value | Type | Payload starts with | +|---|---|---| +| `0x0001` | Video frame | `stream_id` (u16), then compressed frame data | +| `0x0002` | Control request | `request_id` (u16), then command-specific fields | +| `0x0003` | Control response | `request_id` (u16), then result-specific fields | +| `0x0004` | Stream event | `stream_id` (u16), `event_code` (u8), then event-specific fields | + +Node-level messages (not tied to any stream or request) have no prefix beyond the header — the payload begins with the message-specific fields directly. + +Control payloads are binary-serialized structures — see [Protocol Serialization](#protocol-serialization). Stream events carry lifecycle signals — see [Device Resilience](#device-resilience). ### Unified Control and Video on One Connection diff --git a/dev/cli/transport_cli.c b/dev/cli/transport_cli.c index 18490b2..8bc029b 100644 --- a/dev/cli/transport_cli.c +++ b/dev/cli/transport_cli.c @@ -13,8 +13,8 @@ static void server_on_frame(struct Transport_Conn *conn, { (void)userdata; - printf("recv type=0x%04x channel=%u length=%u", - frame->message_type, frame->channel_id, frame->payload_length); + printf("recv type=0x%04x length=%u", + frame->message_type, frame->payload_length); if (frame->payload_length > 0) { uint32_t show = frame->payload_length < 8 ? frame->payload_length : 8; @@ -28,7 +28,7 @@ static void server_on_frame(struct Transport_Conn *conn, printf("\n"); struct App_Error err = transport_send_frame(conn, - frame->message_type, frame->channel_id, + frame->message_type, frame->payload, frame->payload_length); if (!APP_IS_OK(err)) { @@ -90,8 +90,8 @@ static void client_on_frame(struct Transport_Conn *conn, struct Transport_Frame *frame, void *userdata) { (void)conn; (void)userdata; - printf("echo type=0x%04x channel=%u length=%u\n", - frame->message_type, frame->channel_id, frame->payload_length); + printf("echo type=0x%04x length=%u\n", + frame->message_type, frame->payload_length); free(frame->payload); } @@ -123,15 +123,15 @@ static void cmd_client(int argc, char **argv) { printf("connected to %s:%u\n", host, port); - for (uint16_t i = 0; i < 3; i++) { + for (int i = 0; i < 3; i++) { uint8_t payload[] = { 0xde, 0xad, 0xbe, 0xef, (uint8_t)i }; - err = transport_send_frame(conn, 0x0001, i, payload, sizeof(payload)); + err = transport_send_frame(conn, 0x0001, payload, sizeof(payload)); if (!APP_IS_OK(err)) { - fprintf(stderr, "send failed on frame %u (errno %d)\n", + fprintf(stderr, "send failed on frame %d (errno %d)\n", i, err.detail.syscall.err_no); break; } - printf("sent type=0x0001 channel=%u length=5\n", i); + printf("sent type=0x0001 length=5\n"); } sleep(1); diff --git a/include/transport.h b/include/transport.h index 376505f..03b38b1 100644 --- a/include/transport.h +++ b/include/transport.h @@ -3,7 +3,7 @@ #include #include "error.h" -#define TRANSPORT_FRAME_HEADER_SIZE 8u +#define TRANSPORT_FRAME_HEADER_SIZE 6u #define TRANSPORT_DEFAULT_MAX_PAYLOAD (16u * 1024u * 1024u) struct Transport_Conn; @@ -13,10 +13,13 @@ 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; - uint16_t channel_id; uint32_t payload_length; uint8_t *payload; }; @@ -77,7 +80,6 @@ struct App_Error transport_connect(struct Transport_Conn **out, */ 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); diff --git a/src/modules/transport/transport.c b/src/modules/transport/transport.c index e57e601..425d134 100644 --- a/src/modules/transport/transport.c +++ b/src/modules/transport/transport.c @@ -61,8 +61,7 @@ static void *conn_read_thread_fn(void *arg) { struct Transport_Frame frame; frame.message_type = get_u16(header_buf, 0); - frame.channel_id = get_u16(header_buf, 2); - frame.payload_length = get_u32(header_buf, 4); + frame.payload_length = get_u32(header_buf, 2); if (frame.payload_length > conn->max_payload) { break; @@ -287,13 +286,12 @@ struct App_Error transport_connect(struct Transport_Conn **out, } struct App_Error transport_send_frame(struct Transport_Conn *conn, - uint16_t message_type, uint16_t channel_id, + uint16_t message_type, const uint8_t *payload, uint32_t length) { uint8_t header[TRANSPORT_FRAME_HEADER_SIZE]; put_u16(header, 0, message_type); - put_u16(header, 2, channel_id); - put_u32(header, 4, length); + put_u32(header, 2, length); pthread_mutex_lock(&conn->write_mutex); int ok = write_exact(conn->fd, header, TRANSPORT_FRAME_HEADER_SIZE);