The memory frame is a fixed-length continuos memory buffer which is managed by a libft (see memory pool). It is typically aligned with underlying system memory pages and the capacity (aka size) is an integer multiple of the memory page size. The default capacity of the memory frame is 20KiB respectively five 4KiB memory pages. Memory frames are used as buffers for storing data that are send to and received from network.
The content of a memory frame can be organized using vectors. Vectors provide scatter/gather mechanism which means that vectors divide a memory space of the assigned frame into smaller pieces. Each memory frame can contain series of vectors. Vectors can overlaps each other, have gaps between each others and/or be organised in random non-continuos manner. Vector provide a convinient functionality for effective parsing and building data from/to wire protocols.
Memory frame
+------------------------------------------------------------+
| |- 1st Vector -| |
| |---- 2nd Vector ----| |
| |-- 3rd Vector --|
|- 4th Vector -| |
+------------------------------------------------------------+
^ Frame data ^ Frame data + capacity
Vector
|-------------+-------------+-------------|
^ ^ ^ ^
Offset Position Limit Capacity
The location of the vector within a frame is defined by vector's O_ffset_ and Capacity. Vector cannot cross low and high boundary of the frame. Vector defines also its Position and Limit. Read/write operations happen at the Position, which is increased as the operation finishes.
It is postulated that: 0 <= Position <= Limit <= Capacity. It means that:
- Position can be in range of 0 to Capacity but lower or equal to Limit.
- Limit can be in range of 0 to Capacity but higher of equal to Position.
- If Position equals to Limit, no futher read/write operations are possible because we hit the end of a vector.
Specify how much data can fit into a frame in bytes. Typically 20KiB.
Capacity is read-only value that is provided during frame construction time.
A pointer to a frame memory space as an array of bytes.
Each memory frame carries information about its type. This information can be used for faster dispatching of the frame. The type is a number and can be changed by an application.
Known memory frame types:
FT_FRAME_TYPE_FREE
- a memory frame is not used, a frame is returned back to pool. If you encounter frames of this type, it is likely an incorrect implementation (use after release).FT_FRAME_TYPE_END_OF_STREAM
- a special frame that signalizes an end of a stream. There are no data in this frame.FT_FRAME_TYPE_RAW_DATA
- unspecified (raw) data are present in the frame.FT_FRAME_TYPE_LOG
- the frame carries logging information
The memory frame can be received of the network from a peer. The peer address is stored in addr
and addrlen
attributes.
WARNING: This is obsolete part and will be removed in future releases of libft.
Vector objects are stored at the end of the frame so that available capacity of a given frame is a bit smaller if vectors are used.
Here we present a typical lifecycle of the memory frames with vectors on the network protocol, that utilizes a concept of fixed headers and variable-length bodies (such as HTTP/2 or SPDY).
+------------------------------------------------------------------------------
|---- vector ---|
^ Offset = 0
^ Limit = 8
^ Position = 0
^ Capacity = 8
The frame is prepared so that it contains a one vector, that points at the begin of the frame. The capacity of vector is set to a known size of the protocol header (in this example it is 8 bytes).
+------------------------------------------------------------------------------
|---- vector ---|
^ Offset = 0
^ Limit = 8
^ Position = 8
^ Capacity = 8
The protocol header is received e.g. by libft sockets. The Position is equal Limit. Now the length of the body needs to be parsed from data.
+------------------------------------------------------------------------------
|---- vector ---|
^ Offset = 0
^ Limit = 8
^ Position = 0
^ Capacity = 8
The flip set Position to 0 (Limit stays the same because previous value of Position was 8).
+------------------------------------------------------------------------------
|---- vector ---|
^ Offset = 0
^ Limit = 8
............ >> ^ Position = 8
^ Capacity = 8
Iterate thru a vector and use load/store family of functions to parse the header data from the frame. For this example let's assume, that we extracted length of the body to be 32 bytes.
+------------------------------------------------------------------------------
|---- vector ---|
^ Offset = 0
^ Limit = 8
^ Position = 8
^ Capacity = 8
| ----------------- vector -------------------|
^ Offset = 8
^ Limit = 32
^ Position = 0
^ Capacity = 32
Add a second vector with capacity 32 bytes (the value received from parser of the header data).
+------------------------------------------------------------------------------
|---- vector ---|
^ Offset = 0
^ Limit = 8
^ Position = 8
^ Capacity = 8
| ----------------- vector -------------------|
^ Offset = 8
^ Limit = 32
^ Position = 32
^ Capacity = 32
The protocol header is received e.g. by libft sockets. The Position is equal Limit. Now the length of the body needs to be parsed from data.
+------------------------------------------------------------------------------
|---- vector ---|
^ Offset = 0
^ Limit = 8
^ Position = 0
^ Capacity = 8
| ----------------- vector -------------------|
^ Offset = 8
^ Limit = 32
^ Position = 0
^ Capacity = 32
The frame is flipped again and the read cycle is over. The frame is prepared for any upstream processing e.g. by application layer or by an higher level protocol such as HTTP or TLS. Equally it is ready for being send over the network. The later will be demonstrated in the next steps of this example.
+------------------------------------------------------------------------------
|---- vector ---|
^ Offset = 0
^ Limit = 8
^ Position = 8
^ Capacity = 8
| ----------------- vector -------------------|
^ Offset = 8
^ Limit = 32
^ Position = 32
^ Capacity = 32
Because the frame has been correctly prepared, libft sent the frame at once. libft iterated over all vectors and sent data from each vector based on its Position and Limit.
Move a Position forward by position_delta
bytes. position_delta
can be a negative value, in that case, a Position will be moved backward.
Returns true
if Position has been changed correctly, false
for error such as exceeding vector Limit or Capacity.
Set a Position value. Negative values are not accepted.
Returns true
if Position has been changed correctly, false
for error such as exceeding vector Limit or Capacity.
Set a Position value from a prt
.
Returns true
if Position has been changed correctly, false
for error such as ptr
is not within the vector.
Set Limit to a current value of Position and reset Position to 0.
Flip function is used to flip the vector from "writing" to "reading" and vice verse. After a sequence of writes is used to fill the vector, flip will set the limit of the vector to the current position and reset the position to zero. This has the effect of making a future read from the vector read all of what was written into the vector and no more.
Set Limit and Capacity to a current Position.
Add a value of size
to a currect Capacity of the vector. It means that the vector will be extended by a provided value.
Returns true
if Position has been changed correctly, false
for error such as exceeding capacity of the frame.
Print a formatted string into a vector using a current Position and move Position at the end of the resulting string.
Returns true
if successful, false
when error has been observed (e.g. result doesn't fit into a frame).
Print a formatted string into a vector using a current Position (variable argument style) and move Position at the end of the resulting string.
Returns true
if successful, false
when error has been observed (e.g. result doesn't fit into a frame).
Append a text
to a NUL-terminated string in the a vector in a strcat()
way and move Position at the end of the resulting string.
Returns true
if successful, false
when error has been observed (e.g. result doesn't fit into a frame).
Copy bytes from data
(length is defined bydata_len
) into the a vector and move Position by data_len
.
Returns true
if successful, false
when error has been observed (e.g. result doesn't fit into a frame).
Returns a difference between Position and Limit. It means how many more data can fit into a vector or how many data can be still read from a vector.
Get pointer to a memory as specified by vector Offset and Position.
Get pointer to a memory as specified by vector Offset.
Get pointer to a memory as specified by vector Offset and Limit.
A location of the vector within the frame.
A size of the vector.
The position is the index of the next byte to be read or written.
The limit is the index of the first byte that should not be read or written.
A pointer to a frame that owns a vector.