cwist
Modern C web framework with libttak runtime
Loading...
Searching...
No Matches
seq.c File Reference

Implementation of the CWIST sequenced-message protocol. More...

#include <cwist/core/seq/seq.h>
#include <cwist/core/mem/alloc.h>
#include <string.h>
Include dependency graph for seq.c:

Go to the source code of this file.

Functions

bool cwist_seq_chunk_parse (const uint8_t *data, size_t len, cwist_seq_chunk_t *out)
 Parse and validate a sequenced chunk header.
 
void cwist_seq_chunk_build_header (uint8_t out[CWIST_SEQ_HEADER_SIZE], uint16_t seq, uint16_t total, uint16_t payload_len, uint16_t chunk_size)
 Serialize a chunk header into an 8-byte buffer.
 
bool cwist_seq_split (const uint8_t *data, size_t len, uint16_t chunk_payload_size, cwist_seq_message_t *out)
 Split a message buffer into sequenced chunks.
 
void cwist_seq_message_free (cwist_seq_message_t *msg)
 Free all memory owned by a cwist_seq_message_t.
 
cwist_seq_assembler_t * cwist_seq_assembler_create (void)
 Create an assembler with no reassembled-size limit.
 
cwist_seq_assembler_t * cwist_seq_assembler_create_limited (size_t max_data_len)
 Create an assembler with a reassembled-size limit.
 
void cwist_seq_assembler_destroy (cwist_seq_assembler_t *a)
 Destroy an assembler and free all its buffers.
 
void cwist_seq_assembler_reset (cwist_seq_assembler_t *a)
 Discard all received state, keeping the size limit.
 
bool cwist_seq_assembler_feed (cwist_seq_assembler_t *a, const cwist_seq_chunk_t *chunk)
 Feed one sequenced chunk into the assembler.
 
bool cwist_seq_assembler_is_complete (const cwist_seq_assembler_t *a)
 Check whether all chunks of the message have been received intact.
 
size_t cwist_seq_assembler_recovery_targets (const cwist_seq_assembler_t *a, uint16_t *out, size_t out_cap)
 List the sequence numbers of missing chunks.
 
bool cwist_seq_assembler_get_data (cwist_seq_assembler_t *a, const uint8_t **out_data, size_t *out_len)
 Access the fully reassembled message.
 

Detailed Description

Implementation of the CWIST sequenced-message protocol.

Definition in file seq.c.

Function Documentation

◆ cwist_seq_assembler_create()

cwist_seq_assembler_t * cwist_seq_assembler_create ( void  )

Create an assembler with no reassembled-size limit.

Create an empty assembler.

Returns
New assembler, or NULL on allocation failure.

Definition at line 196 of file seq.c.

References cwist_seq_assembler_create_limited().

Referenced by cwist_jwt_join_chunks(), and cwist_websocket_receive_sequenced().

◆ cwist_seq_assembler_create_limited()

cwist_seq_assembler_t * cwist_seq_assembler_create_limited ( size_t  max_data_len)

Create an assembler with a reassembled-size limit.

Create an assembler with a maximum possible reassembled size.

Allocates an empty assembler state; buffers are allocated lazily on the first cwist_seq_assembler_feed() call. Destroy with cwist_seq_assembler_destroy().

Parameters
max_data_lenMaximum accepted reassembled size in bytes, or 0 to use the CWIST_SEQ_MAX_REASSEMBLED_SIZE default.
Returns
New assembler, or NULL on allocation failure.

Definition at line 211 of file seq.c.

References cap, and cwist_alloc().

Referenced by cwist_http2_serve_connection_ex(), and cwist_seq_assembler_create().

◆ cwist_seq_assembler_destroy()

void cwist_seq_assembler_destroy ( cwist_seq_assembler_t *  a)

Destroy an assembler and free all its buffers.

Destroy an assembler and its internal buffer.

Parameters
aAssembler to destroy; may be NULL.

Definition at line 223 of file seq.c.

References cap, and cwist_free().

Referenced by cwist_jwt_join_chunks(), and cwist_websocket_receive_sequenced().

◆ cwist_seq_assembler_feed()

bool cwist_seq_assembler_feed ( cwist_seq_assembler_t *  a,
const cwist_seq_chunk_t *  chunk 
)

Feed one sequenced chunk into the assembler.

Feed one parsed chunk into the assembler.

The first valid chunk establishes the message's total and chunk_size; subsequent chunks must match them or are rejected. Identical duplicates are accepted idempotently; a conflicting duplicate is flagged as contamination (retaining the original bytes) and never overwrites good data. The total message length is determined only when the final chunk (seq == total) arrives, so reordered delivery is tolerated. On allocation failure all state is cleared and false is returned.

Parameters
aAssembler to feed.
chunkParsed chunk to accept; payload bytes are copied into the reassembly buffer.
Return values
trueThe chunk was accepted (new data or an identical duplicate).
falseInvalid or inconsistent chunk, conflicting duplicate (contamination), size-limit exceeded, or allocation failure.

Definition at line 268 of file seq.c.

References cap, cwist_alloc(), cwist_alloc_array(), cwist_free(), CWIST_SEQ_MAX_CHUNKS, and CWIST_SEQ_MAX_REASSEMBLED_SIZE.

Referenced by cwist_http2_serve_connection_ex(), cwist_jwt_join_chunks(), and cwist_websocket_receive_sequenced().

◆ cwist_seq_assembler_get_data()

bool cwist_seq_assembler_get_data ( cwist_seq_assembler_t *  a,
const uint8_t **  out_data,
size_t *  out_len 
)

Access the fully reassembled message.

Borrow the assembled message when complete.

Succeeds only when cwist_seq_assembler_is_complete() is true. The returned pointer refers to the assembler's internal buffer, which remains valid until the assembler is reset, destroyed, or fed another chunk; ownership stays with the assembler.

Parameters
aAssembler to query.
out_dataReceives a pointer to the reassembled bytes.
out_lenReceives the reassembled length in bytes.
Return values
trueThe message is complete; outputs are populated.
falseThe message is incomplete or an output pointer is NULL.

Definition at line 390 of file seq.c.

References cap, and cwist_seq_assembler_is_complete().

Referenced by cwist_http2_serve_connection_ex(), cwist_jwt_join_chunks(), and cwist_websocket_receive_sequenced().

◆ cwist_seq_assembler_is_complete()

bool cwist_seq_assembler_is_complete ( const cwist_seq_assembler_t *  a)

Check whether all chunks of the message have been received intact.

Return true when every expected chunk has been received.

Completion requires every chunk to be present, no conflicting duplicates (contamination), and the final chunk to have arrived so the total length is known.

Parameters
aAssembler to query; may be NULL.
Return values
trueThe message is fully reassembled and clean.
falseNot complete, or a is NULL.

Definition at line 343 of file seq.c.

References cap.

Referenced by cwist_seq_assembler_get_data(), cwist_seq_assembler_recovery_targets(), and cwist_websocket_receive_sequenced().

◆ cwist_seq_assembler_recovery_targets()

size_t cwist_seq_assembler_recovery_targets ( const cwist_seq_assembler_t *  a,
uint16_t *  out,
size_t  out_cap 
)

List the sequence numbers of missing chunks.

Return the sequence numbers still required to complete a message.

Returns the count of missing chunks and, when out has capacity, writes their 1-based sequence numbers in ascending order. Returns 0 if the assembler has no state or the message is already complete; in those cases nothing is written to out.

Parameters
aAssembler to query; may be NULL.
outOptional array to receive missing sequence numbers.
out_capNumber of elements out can hold; ignored when out is NULL.
Returns
Total number of missing chunks (may exceed out_cap).

Definition at line 362 of file seq.c.

References cap, and cwist_seq_assembler_is_complete().

◆ cwist_seq_assembler_reset()

void cwist_seq_assembler_reset ( cwist_seq_assembler_t *  a)

Discard all received state, keeping the size limit.

Reset an assembler so it can receive a new message.

Frees the reassembly buffers but retains the max_data_len configured at creation so the assembler can be reused for a new message. Does nothing if a is NULL.

Parameters
aAssembler to reset; may be NULL.

Definition at line 240 of file seq.c.

References cap, and cwist_free().

◆ cwist_seq_chunk_build_header()

void cwist_seq_chunk_build_header ( uint8_t  out[CWIST_SEQ_HEADER_SIZE],
uint16_t  seq,
uint16_t  total,
uint16_t  payload_len,
uint16_t  chunk_size 
)

Serialize a chunk header into an 8-byte buffer.

Write an 8-byte sequence header.

Encodes seq, total, payload_len, and chunk_size as big-endian 16-bit fields. Performs no validation; callers must supply a consistent sequence pair (see cwist_seq_chunk_parse()).

Parameters
outBuffer of CWIST_SEQ_HEADER_SIZE bytes to write.
seqChunk sequence number (1-based).
totalTotal number of chunks in the message.
payload_lenPayload bytes in this chunk.
chunk_sizeFull payload size of every non-final chunk.

Definition at line 97 of file seq.c.

Referenced by cwist_seq_split().

◆ cwist_seq_chunk_parse()

bool cwist_seq_chunk_parse ( const uint8_t *  data,
size_t  len,
cwist_seq_chunk_t *  out 
)

Parse and validate a sequenced chunk header.

Parse a sequence chunk from raw bytes.

Reads the fixed-size chunk header from data and fills out. The payload pointer in out references memory inside data and is not copied. The chunk is rejected if the sequence pair (seq/total) is missing, out of range, or inconsistent, or if the payload length fields disagree with the buffer length.

Parameters
dataBuffer containing at least CWIST_SEQ_HEADER_SIZE bytes.
lenLength of data in bytes.
outReceives the parsed chunk fields on success.
Return values
trueThe chunk is valid and out is populated.
falseInvalid arguments or a malformed chunk; out is untouched.

Definition at line 63 of file seq.c.

References cap, cwist_seq_chunk::chunk_size, CWIST_SEQ_HEADER_SIZE, CWIST_SEQ_MAX_CHUNKS, cwist_seq_chunk::payload, cwist_seq_chunk::payload_len, cwist_seq_chunk::seq, and cwist_seq_chunk::total.

Referenced by cwist_http2_serve_connection_ex(), cwist_jwt_join_chunks(), cwist_seq_auth_wrap(), and cwist_websocket_receive_sequenced().

◆ cwist_seq_message_free()

void cwist_seq_message_free ( cwist_seq_message_t *  msg)

Free all memory owned by a cwist_seq_message_t.

Free all buffers allocated by cwist_seq_split().

Releases each chunk buffer plus the chunk and length arrays, then zeroes the struct so it is safe to reuse. Does nothing if msg is NULL.

Parameters
msgMessage to free; may be NULL.

Definition at line 178 of file seq.c.

References cap, and cwist_free().

Referenced by cwist_jwt_split_chunks(), and cwist_websocket_send_sequenced().

◆ cwist_seq_split()

bool cwist_seq_split ( const uint8_t *  data,
size_t  len,
uint16_t  chunk_payload_size,
cwist_seq_message_t *  out 
)

Split a message buffer into sequenced chunks.

Split data into sequenced chunks.

Allocates each chunk with cwist_alloc() and writes it into out; the result is released with cwist_seq_message_free(). Every chunk except the last carries exactly chunk_payload_size payload bytes. out is zeroed before use and again on failure.

Parameters
dataMessage bytes to split.
lenLength of data in bytes.
chunk_payload_sizePayload bytes per chunk; must be non-zero.
outReceives the chunk array on success.
Return values
trueout holds out->count chunks.
falseInvalid arguments, or the message would exceed the chunk or reassembled-size limits, or allocation failed; out is zeroed.

Definition at line 125 of file seq.c.

References cap, cwist_seq_message::chunk_lens, cwist_seq_message::chunks, cwist_seq_message::count, cwist_alloc(), cwist_alloc_array(), cwist_free(), cwist_seq_chunk_build_header(), CWIST_SEQ_HEADER_SIZE, CWIST_SEQ_MAX_CHUNKS, and CWIST_SEQ_MAX_REASSEMBLED_SIZE.

Referenced by cwist_jwt_split_chunks(), and cwist_websocket_send_sequenced().