fstrm  0.4.0
Frame Streams implementation in C
fstrm_control

Detailed Description

fstrm_control is an interface for encoding and decoding Frame Streams control frames.

Two types of frames are possible in a Frame Streams byte stream: data frames and control frames. Both are variable length byte sequences prefixed by a 32-bit big endian unsigned integer (the frame length) specifying the length of the following byte sequence. If this frame length value is greater than zero, the frame length specifies the data frame length, and a data frame follows it. If the frame length is zero (i.e., it is the four byte sequence 00 00 00 00), this is an escape sequence, which means that a control frame follows. The control frame itself is prefixed by a 32-bit big endian unsigned integer (the control frame length) specifying the length of the following control frame payload.

There are two types of control frames used for uni-directional streams: START and STOP. These control frame types bracket the stream of data frames. START indicates the beginning of the stream and communicates metadata about the stream to follow, and STOP indicates the end of the stream.

Bi-directional streams make use of three additional control frame types: READY, ACCEPT, and FINISH. These control frame types are used in a simple handshake protocol between sender and receiver.

A uni-directional Frame Streams byte stream normally consists of the following:

  1. The START control frame.
  2. A sequence of zero or more data frames or control frames that are not of the control frame types START, STOP, ACCEPT, READY, or FINISH.
  3. The STOP control frame.

The START and STOP control frames are not optional. The START control frame must appear at the beginning of the byte stream, and the STOP control frame must appear at the end of the byte stream. (If the byte stream has an end.) START control frames must not appear anywhere other than at the beginning of the byte stream, and STOP control frames must not appear anywhere other than at the end of the byte stream. Only one START control frame and only one STOP control frame may appear in a Frame Streams byte stream.

Control frames may optionally include zero or more control frame fields. There is currently one type of control frame field defined: CONTENT_TYPE. This field specifies a variable length byte sequence describing the encoding of data frames that appear in the Frame Streams byte stream. This field is used by cooperating programs to unambiguously identify how to interpret the data frames in a particular Frame Streams byte stream. For instance, this field may specify a particular schema to use to interpret the data frames appearing in the byte stream. Zero, one, or more CONTENT_TYPE fields may appear in READY or ACCEPT control frames. Zero or one CONTENT_TYPE fields may appear in START control frames. No CONTENT_TYPE fields may appear in STOP or FINISH control frames.

A uni-directional Frame Streams encoder would normally produce a byte stream as follows:

  1. Write the START control frame.
    • At the start of the byte stream, write the four byte escape sequence 00 00 00 00 that precedes control frames.
    • Write the control frame length as a 32-bit big endian unsigned integer.
    • Write the control frame payload. It must be a START control frame. It may optionally specify a CONTENT_TYPE field.
  2. Write zero or more data frames.
  3. Write the STOP control frame.
    • At the start of the byte stream, write the four byte escape sequence 00 00 00 00 that precedes control frames.
    • Write the control frame length as a 32-bit big endian unsigned integer.
    • Write the control frame payload. It must be a STOP control frame.

A uni-directional Frame Streams decoder would normally process the byte stream as follows:

  1. Read the START control frame.
    • At the start of the byte stream, read the four byte escape sequence 00 00 00 00 that precedes control frames.
    • Read the 32-bit big endian unsigned integer specifying the control frame length.
    • Decode the control frame payload. It must be a START control frame. It may optionally specify a CONTENT_TYPE field.
  2. Repeatedly read data frames or control frames following the START control frame.
    • Read the frame length, a 32-bit big endian unsigned integer.
    • If the frame length is zero, a control frame follows:
      • Read the 32-bit big endian unsigned integer specifying the control frame length.
      • Decode the control frame payload. If it is a STOP control frame, the end of the Frame Streams byte stream has occurred, and no frames follow. Break out of the decoding loop and halt processing. (READY, ACCEPT, START, and FINISH may not occur here. For forward compatibility, control frames of types other than the types READY, ACCEPT, START, STOP, and FINISH must be ignored here. No control frames specified in the future may alter the encoding of succeeding frames.)
    • If the frame length is non-zero, it specifies the number of bytes in the following data frame. Consume these bytes from the byte stream.

The functions fstrm_control_encode() and fstrm_control_decode() are provided to encode and decode control frames. See the detailed descriptions of those functions for code examples showing their usage.

Macros

#define FSTRM_CONTROL_FRAME_LENGTH_MAX   512
 The maximum length in bytes of an "Accept", "Start", or "Stop" control frame payload. More...
 
#define FSTRM_CONTROL_FIELD_CONTENT_TYPE_LENGTH_MAX   256
 The maximum length in bytes of a "Content Type" control frame field payload. More...
 

Enumerations

enum  fstrm_control_type
 Control frame types. More...
 
enum  fstrm_control_field
 Control frame field types. More...
 
enum  fstrm_control_flag
 Flags for controlling the behavior of the encoding and decoding functions. More...
 

Functions

const char * fstrm_control_type_to_str (fstrm_control_type type)
 Convert an fstrm_control_type enum value to a string representation. More...
 
const char * fstrm_control_field_type_to_str (fstrm_control_field f_type)
 Convert an fstrm_control_field enum value to a string representation. More...
 
struct fstrm_control * fstrm_control_init (void)
 Initialize an fstrm_control object. More...
 
void fstrm_control_destroy (struct fstrm_control **c)
 Destroy an fstrm_control object. More...
 
void fstrm_control_reset (struct fstrm_control *c)
 Reinitialize an fstrm_control object. More...
 
fstrm_res fstrm_control_get_type (const struct fstrm_control *c, fstrm_control_type *type)
 Retrieve the type of the control frame. More...
 
fstrm_res fstrm_control_set_type (struct fstrm_control *c, fstrm_control_type type)
 Set the type of the control frame. More...
 
fstrm_res fstrm_control_get_num_field_content_type (const struct fstrm_control *c, size_t *n_content_type)
 Retrieve the number of "Content Type" fields present in the control frame. More...
 
fstrm_res fstrm_control_get_field_content_type (const struct fstrm_control *c, const size_t idx, const uint8_t **content_type, size_t *len_content_type)
 Retrieve a "Content Type" field from the control frame. More...
 
fstrm_res fstrm_control_add_field_content_type (struct fstrm_control *c, const uint8_t *content_type, size_t len_content_type)
 Add a "Content Type" field to the control frame. More...
 
fstrm_res fstrm_control_match_field_content_type (const struct fstrm_control *c, const uint8_t *match, const size_t len_match)
 Check if the control frame matches a particular content type value. More...
 
fstrm_res fstrm_control_decode (struct fstrm_control *c, const void *control_frame, size_t len_control_frame, const uint32_t flags)
 Decode a control frame from a buffer. More...
 
fstrm_res fstrm_control_encoded_size (const struct fstrm_control *c, size_t *len_control_frame, const uint32_t flags)
 Calculate the number of bytes needed to serialize the control frame. More...
 
fstrm_res fstrm_control_encode (const struct fstrm_control *c, void *control_frame, size_t *len_control_frame, const uint32_t flags)
 Encode a control frame into a buffer. More...
 

Macro Definition Documentation

◆ FSTRM_CONTROL_FRAME_LENGTH_MAX

#define FSTRM_CONTROL_FRAME_LENGTH_MAX   512

The maximum length in bytes of an "Accept", "Start", or "Stop" control frame payload.

This excludes the escape sequence and the control frame length.

◆ FSTRM_CONTROL_FIELD_CONTENT_TYPE_LENGTH_MAX

#define FSTRM_CONTROL_FIELD_CONTENT_TYPE_LENGTH_MAX   256

The maximum length in bytes of a "Content Type" control frame field payload.

This excludes the field type and payload length.

Enumeration Type Documentation

◆ fstrm_control_type

Control frame types.

Enumerator
FSTRM_CONTROL_ACCEPT 

Control frame type value for "Accept" control frames.

FSTRM_CONTROL_START 

Control frame type value for "Start" control frames.

FSTRM_CONTROL_STOP 

Control frame type value for "Stop" control frames.

FSTRM_CONTROL_READY 

Control frame type value for "Ready" control frames.

FSTRM_CONTROL_FINISH 

Control frame type value for "Finish" control frames.

◆ fstrm_control_field

Control frame field types.

These are optional fields that can appear in control frames.

Enumerator
FSTRM_CONTROL_FIELD_CONTENT_TYPE 

Control frame field type value for the "Content Type" control frame option.

◆ fstrm_control_flag

Flags for controlling the behavior of the encoding and decoding functions.

Enumerator
FSTRM_CONTROL_FLAG_WITH_HEADER 

Set to control whether to include the control frame header in encoding/decoding operations.

Causes fstrm_control_encode() and fstrm_control_encoded_size() to include the control frame header containing the escape sequence and control frame payload length in the encoded output. Otherwise, only the control frame payload itself is encoded.

Tells fstrm_control_decode() that the input buffer to be decoded begins with the control frame header containing the escape sequence and control frame payload length. (Note that this requires the caller to peek at the input buffer to calculate the right buffer length.) Otherwise, the input buffer begins with the control frame payload.

Function Documentation

◆ fstrm_control_type_to_str()

const char* fstrm_control_type_to_str ( fstrm_control_type  type)

Convert an fstrm_control_type enum value to a string representation.

Unknown values are represented as "FSTRM_CONTROL_UNKNOWN".

Parameters
typeThe fstrm_control_type enum value.
Returns
The string representation of the enum value. (Always non-NULL.)

◆ fstrm_control_field_type_to_str()

const char* fstrm_control_field_type_to_str ( fstrm_control_field  f_type)

Convert an fstrm_control_field enum value to a string representation.

Unknown values are represented as "FSTRM_CONTROL_FIELD_UNKNOWN".

Parameters
f_typeThe fstrm_control_field enum value.
Returns
The string representation of the enum value. (Always non-NULL.)

◆ fstrm_control_init()

struct fstrm_control* fstrm_control_init ( void  )

Initialize an fstrm_control object.

This object represents Frame Streams control frames and is used for encoding and decoding control frames.

Returns
An fstrm_control object.

◆ fstrm_control_destroy()

void fstrm_control_destroy ( struct fstrm_control **  c)

Destroy an fstrm_control object.

Parameters
[in]cPointer to an fstrm_control object.

◆ fstrm_control_reset()

void fstrm_control_reset ( struct fstrm_control *  c)

Reinitialize an fstrm_control object.

This resets the internal state to default values.

Parameters
cfstrm_control object.

◆ fstrm_control_get_type()

fstrm_res fstrm_control_get_type ( const struct fstrm_control *  c,
fstrm_control_type type 
)

Retrieve the type of the control frame.

Parameters
cfstrm_control object.
[out]typeType of the control frame.
Return values
fstrm_res_success
fstrm_res_failure

◆ fstrm_control_set_type()

fstrm_res fstrm_control_set_type ( struct fstrm_control *  c,
fstrm_control_type  type 
)

Set the type of the control frame.

Parameters
cfstrm_control object.
[in]typeType of the control frame.
Return values
fstrm_res_success
fstrm_res_failure

◆ fstrm_control_get_num_field_content_type()

fstrm_res fstrm_control_get_num_field_content_type ( const struct fstrm_control *  c,
size_t *  n_content_type 
)

Retrieve the number of "Content Type" fields present in the control frame.

Parameters
cfstrm_control object.
[out]n_content_typeThe number of "Content Type" fields.
Return values
fstrm_res_success
fstrm_res_failure

◆ fstrm_control_get_field_content_type()

fstrm_res fstrm_control_get_field_content_type ( const struct fstrm_control *  c,
const size_t  idx,
const uint8_t **  content_type,
size_t *  len_content_type 
)

Retrieve a "Content Type" field from the control frame.

This function returns a reference which must not be modified. Control frames may contain zero, one, or more "Content Type" fields.

See also
fstrm_control_get_num_field_content_type()
Parameters
cfstrm_control object.
[in]idxThe index of the "Content Type" field to retrieve.
[out]content_typePointer to where the reference to the "Content Type" string will be stored. Note that this string is not NUL-terminated and may contain embedded NULs.
[out]len_content_typeThe number of bytes in content_type.
Return values
fstrm_res_successThe control frame has a "Content Type" field.
fstrm_res_failureThe control frame does not have a "Content Type" field.

◆ fstrm_control_add_field_content_type()

fstrm_res fstrm_control_add_field_content_type ( struct fstrm_control *  c,
const uint8_t *  content_type,
size_t  len_content_type 
)

Add a "Content Type" field to the control frame.

This function makes a copy of the provided string. This function may be called multiple times, in which case multiple "Content Type" fields will be added to the control frame.

The "Content Type" fields are removed on a call to fstrm_control_reset().

Parameters
cfstrm_control object.
[in]content_typeThe "Content Type" string to copy. Note that this string is not NUL-terminated and may contain embedded NULs.
[in]len_content_typeThe number of bytes in content_type.
Return values
fstrm_res_successThe "Content Type" field was successfully added.
fstrm_res_failureThe "Content Type" string is too long.

◆ fstrm_control_match_field_content_type()

fstrm_res fstrm_control_match_field_content_type ( const struct fstrm_control *  c,
const uint8_t *  match,
const size_t  len_match 
)

Check if the control frame matches a particular content type value.

That is, the content type given in the match and len_match parameters is checked for compatibility with the content types (if any) specified in the control frame.

Parameters
cfstrm_control object.
matchThe "Content Type" string to match. Note that this string is not NUL-terminated and may contain embedded NULs. May be NULL, in which case the control frame must not have any content type fields in order to match.
len_matchThe number of bytes in match.
Return values
fstrm_res_successA match was found.
fstrm_res_failureA match was not found.

◆ fstrm_control_decode()

fstrm_res fstrm_control_decode ( struct fstrm_control *  c,
const void *  control_frame,
size_t  len_control_frame,
const uint32_t  flags 
)

Decode a control frame from a buffer.

The buffer starts with either the escape sequence or the control frame payload depending on whether the FSTRM_CONTROL_FLAG_WITH_HEADER flag is set or not. In either case, the 'len_control_frame' parameter must be exact. Underflow or overflow is not permitted.

The following code example shows a function that decodes a control frame payload:

static fstrm_res
decode_control_frame(const void *control_frame, size_t len_control_frame)
{
fstrm_res res;
struct fstrm_control *c;
uint32_t flags = 0;
res = fstrm_control_decode(c, control_frame, len_control_frame, flags);
if (res != fstrm_res_success) {
puts("fstrm_control_decode() failed.");
return res;
}
res = fstrm_control_get_type(c, &c_type);
if (res != fstrm_res_success) {
puts("fstrm_control_get_type() failed.");
return res;
}
printf("The control frame is of type %s (%u).\n",
fstrm_control_type_to_str(c_type), c_type);
size_t n_content_type;
res = fstrm_control_get_num_field_content_type(c, &n_content_type);
if (res != fstrm_res_success) {
puts("fstrm_control_get_num_field_content_type() failed.");
return res;
}
const uint8_t *content_type;
size_t len_content_type;
for (size_t idx = 0; idx < n_content_type; idx++) {
&content_type, &len_content_type);
if (res == fstrm_res_success) {
printf("The control frame has a CONTENT_TYPE field of length %zd.\n",
len_content_type);
}
}
}
Parameters
cfstrm_control object. Its state will be overwritten.
[in]control_frameBuffer containing the serialized control frame.
[in]len_control_frameThe number of bytes in control_frame. This parameter must specify the exact number of bytes in the control frame.
flagsFlags controlling the decoding process. See fstrm_control_flag.
Return values
fstrm_res_success
fstrm_res_failure

◆ fstrm_control_encoded_size()

fstrm_res fstrm_control_encoded_size ( const struct fstrm_control *  c,
size_t *  len_control_frame,
const uint32_t  flags 
)

Calculate the number of bytes needed to serialize the control frame.

Parameters
cfstrm_control object.
[out]len_control_frameThe number of bytes needed to encode c.
flagsFlags controlling the encoding process. See fstrm_control_flag.
Return values
fstrm_res_success
fstrm_res_failure

◆ fstrm_control_encode()

fstrm_res fstrm_control_encode ( const struct fstrm_control *  c,
void *  control_frame,
size_t *  len_control_frame,
const uint32_t  flags 
)

Encode a control frame into a buffer.

Since a Frame Streams control frame is a variable length byte sequence of up to FSTRM_CONTROL_FRAME_LENGTH_MAX bytes, this function can be used in two different ways. The first way is to call fstrm_control_encoded_size() to obtain the exact number of bytes needed to encode the frame, and then pass a buffer of this exact size to fstrm_control_encode(). The following example shows this usage:

struct fstrm_control *c;
uint8_t *control_frame;
size_t len_control_frame;
uint32_t flags = 0;
if (res != fstrm_res_success) {
// Error handling goes here.
}
// Calculate the number of bytes needed.
res = fstrm_control_encoded_size(c, &len_control_frame, flags);
if (res != fstrm_res_success) {
// Error handling goes here.
}
// 'len_control_frame' now specifies the number of bytes required for
// the control frame. Allocate the needed space.
control_frame = malloc(len_control_frame);
if (!control_frame) {
// Error handling goes here.
}
// Serialize the control frame into the allocated buffer.
res = fstrm_control_encode(c, control_frame, &len_control_frame, 0);
if (res != fstrm_res_success) {
// Error handling goes here.
}
// Do something with 'control_frame' and 'len_control_frame'.
// Clean up.
free(control_frame);

The second way to use fstrm_control_encode() is to allocate a statically sized buffer of FSTRM_CONTROL_FRAME_LENGTH_MAX bytes. The exact number of bytes serialized by the encoder will be returned in the len_control_frame parameter. The following example shows this usage:

struct fstrm_control *c;
uint8_t control_frame[FSTRM_CONTROL_FRAME_LENGTH_MAX];
size_t len_control_frame = sizeof(control_frame);
if (res != fstrm_res_success) {
// Error handling.
}
// Serialize the control frame.
res = fstrm_control_encode(c, control_frame, &len_control_frame, 0);
if (res != fstrm_res_success) {
// Error handling goes here.
}
// Do something with 'control_frame' and 'len_control_frame'.
// Clean up.
Parameters
cfstrm_control object.
[out]control_frameThe buffer in which to serialize the control frame.
[in,out]len_control_frameThe size in bytes of control_frame. On a successful return, contains the number of bytes actually written into control_frame.
flagsFlags controlling the encoding process. See fstrm_control_flag.
Return values
fstrm_res_success
fstrm_res_failure