Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
kcenon::network::internal::websocket_frame Class Reference

Provides WebSocket frame encoding and decoding functionality. More...

#include <websocket_frame.h>

Collaboration diagram for kcenon::network::internal::websocket_frame:
Collaboration graph

Static Public Member Functions

static auto encode_frame (ws_opcode opcode, std::vector< uint8_t > &&payload, bool fin=true, bool mask=false) -> std::vector< uint8_t >
 Encodes data into a WebSocket frame.
 
static auto decode_header (const std::vector< uint8_t > &data) -> std::optional< ws_frame_header >
 Decodes a WebSocket frame header from raw data.
 
static auto decode_payload (const ws_frame_header &header, const std::vector< uint8_t > &data) -> std::vector< uint8_t >
 Decodes the payload from a WebSocket frame.
 
static auto apply_mask (std::vector< uint8_t > &data, const std::array< uint8_t, 4 > &mask) -> void
 Applies or removes XOR masking on data.
 
static auto generate_mask () -> std::array< uint8_t, 4 >
 Generates a random 4-byte masking key.
 
static auto calculate_header_size (uint64_t payload_len, bool mask) -> size_t
 Calculates the size of the frame header.
 

Detailed Description

Provides WebSocket frame encoding and decoding functionality.

This class implements RFC 6455 compliant frame encoding and decoding, including support for masking, fragmentation, and all frame types.

Definition at line 57 of file websocket_frame.h.

Member Function Documentation

◆ apply_mask()

auto kcenon::network::internal::websocket_frame::apply_mask ( std::vector< uint8_t > & data,
const std::array< uint8_t, 4 > & mask ) -> void
static

Applies or removes XOR masking on data.

WebSocket masking is symmetric (XOR operation), so this function can be used both to apply and remove masking.

Parameters
dataThe data to mask/unmask (modified in place)
maskThe 4-byte masking key

Definition at line 249 of file websocket_frame.cpp.

251 {
252 for (size_t i = 0; i < data.size(); ++i)
253 {
254 data[i] ^= mask[i % 4];
255 }
256 }
constexpr uint8_t mask
Mask for all flags.
Definition frame_types.h:66

◆ calculate_header_size()

auto kcenon::network::internal::websocket_frame::calculate_header_size ( uint64_t payload_len,
bool mask ) -> size_t
static

Calculates the size of the frame header.

Determines how many bytes the header will occupy based on payload length and masking flag.

Parameters
payload_lenThe length of the payload
maskWhether the frame will be masked
Returns
The header size in bytes

Definition at line 78 of file websocket_frame.cpp.

79 {
80 size_t header_size = MIN_HEADER_SIZE;
81
82 if (payload_len >= 65536)
83 {
84 header_size += 8; // 64-bit length field
85 }
86 else if (payload_len >= 126)
87 {
88 header_size += 2; // 16-bit length field
89 }
90
91 if (mask)
92 {
93 header_size += MASKING_KEY_SIZE;
94 }
95
96 return header_size;
97 }

Referenced by kcenon::network::internal::websocket_protocol::process_frames().

Here is the caller graph for this function:

◆ decode_header()

auto kcenon::network::internal::websocket_frame::decode_header ( const std::vector< uint8_t > & data) -> std::optional<ws_frame_header>
static

Decodes a WebSocket frame header from raw data.

Parses the first bytes of a WebSocket frame to extract header information. Does not validate or extract the payload.

Parameters
dataThe raw frame data
Returns
Decoded header if valid, std::nullopt if invalid or incomplete

Definition at line 164 of file websocket_frame.cpp.

166 {
167 if (data.size() < MIN_HEADER_SIZE)
168 {
169 return std::nullopt;
170 }
171
172 ws_frame_header header{};
173
174 // Parse byte 0: FIN, RSV1-3, Opcode
175 const uint8_t byte0 = data[0];
176 header.fin = (byte0 & FIN_BIT) != 0;
177 header.rsv1 = (byte0 & RSV1_BIT) != 0;
178 header.rsv2 = (byte0 & RSV2_BIT) != 0;
179 header.rsv3 = (byte0 & RSV3_BIT) != 0;
180 header.opcode = static_cast<ws_opcode>(byte0 & OPCODE_MASK);
181
182 // Parse byte 1: Mask, Payload length
183 const uint8_t byte1 = data[1];
184 header.mask = (byte1 & MASK_BIT) != 0;
185 uint8_t payload_len = byte1 & PAYLOAD_LEN_MASK;
186
187 size_t offset = MIN_HEADER_SIZE;
188
189 // Extended payload length
190 if (payload_len == PAYLOAD_LEN_16BIT)
191 {
192 if (data.size() < offset + 2)
193 {
194 return std::nullopt;
195 }
196 header.payload_len = from_network_u16(&data[offset]);
197 offset += 2;
198 }
199 else if (payload_len == PAYLOAD_LEN_64BIT)
200 {
201 if (data.size() < offset + 8)
202 {
203 return std::nullopt;
204 }
205 header.payload_len = from_network_u64(&data[offset]);
206 offset += 8;
207 }
208 else
209 {
210 header.payload_len = payload_len;
211 }
212
213 // Masking key
214 if (header.mask)
215 {
216 if (data.size() < offset + MASKING_KEY_SIZE)
217 {
218 return std::nullopt;
219 }
220 std::copy_n(data.begin() + offset, MASKING_KEY_SIZE, header.masking_key.begin());
221 }
222
223 return header;
224 }
ws_opcode
WebSocket frame operation codes as defined in RFC 6455.

Referenced by kcenon::network::internal::websocket_protocol::process_frames().

Here is the caller graph for this function:

◆ decode_payload()

auto kcenon::network::internal::websocket_frame::decode_payload ( const ws_frame_header & header,
const std::vector< uint8_t > & data ) -> std::vector<uint8_t>
static

Decodes the payload from a WebSocket frame.

Extracts and unmasks (if necessary) the payload data from a frame using the provided header information.

Parameters
headerThe decoded frame header
dataThe complete frame data
Returns
Decoded (and unmasked if needed) payload

Definition at line 226 of file websocket_frame.cpp.

229 {
230 const size_t header_size = calculate_header_size(header.payload_len, header.mask);
231
232 if (data.size() < header_size + header.payload_len)
233 {
234 return {};
235 }
236
237 std::vector<uint8_t> payload(data.begin() + header_size,
238 data.begin() + header_size + header.payload_len);
239
240 // Unmask if necessary
241 if (header.mask)
242 {
243 apply_mask(payload, header.masking_key);
244 }
245
246 return payload;
247 }
static auto calculate_header_size(uint64_t payload_len, bool mask) -> size_t
Calculates the size of the frame header.
static auto apply_mask(std::vector< uint8_t > &data, const std::array< uint8_t, 4 > &mask) -> void
Applies or removes XOR masking on data.

Referenced by kcenon::network::internal::websocket_protocol::process_frames().

Here is the caller graph for this function:

◆ encode_frame()

auto kcenon::network::internal::websocket_frame::encode_frame ( ws_opcode opcode,
std::vector< uint8_t > && payload,
bool fin = true,
bool mask = false ) -> std::vector<uint8_t>
static

Encodes data into a WebSocket frame.

Creates a properly formatted WebSocket frame with the specified opcode and payload. Uses move semantics for zero-copy operation.

Parameters
opcodeThe operation code for this frame
payloadThe payload data (will be moved)
finFinal fragment flag (default: true)
maskWhether to mask the payload (default: false)
Returns
Encoded frame as a byte vector

Definition at line 99 of file websocket_frame.cpp.

101 {
102 const uint64_t payload_len = payload.size();
103 const size_t header_size = calculate_header_size(payload_len, mask);
104
105 std::vector<uint8_t> frame;
106 frame.reserve(header_size + payload_len);
107
108 // Byte 0: FIN, RSV1-3, Opcode
109 uint8_t byte0 = static_cast<uint8_t>(opcode);
110 if (fin)
111 {
112 byte0 |= FIN_BIT;
113 }
114 frame.push_back(byte0);
115
116 // Byte 1: Mask, Payload length
117 uint8_t byte1 = 0;
118 if (mask)
119 {
120 byte1 |= MASK_BIT;
121 }
122
123 if (payload_len < 126)
124 {
125 byte1 |= static_cast<uint8_t>(payload_len);
126 frame.push_back(byte1);
127 }
128 else if (payload_len < 65536)
129 {
130 byte1 |= PAYLOAD_LEN_16BIT;
131 frame.push_back(byte1);
132
133 // Extended payload length (16-bit)
134 auto len_bytes = to_network_u16(static_cast<uint16_t>(payload_len));
135 frame.insert(frame.end(), len_bytes.begin(), len_bytes.end());
136 }
137 else
138 {
139 byte1 |= PAYLOAD_LEN_64BIT;
140 frame.push_back(byte1);
141
142 // Extended payload length (64-bit)
143 auto len_bytes = to_network_u64(payload_len);
144 frame.insert(frame.end(), len_bytes.begin(), len_bytes.end());
145 }
146
147 // Masking key (if mask is enabled)
148 std::array<uint8_t, 4> masking_key{};
149 if (mask)
150 {
151 masking_key = generate_mask();
152 frame.insert(frame.end(), masking_key.begin(), masking_key.end());
153
154 // Apply masking to payload
155 apply_mask(payload, masking_key);
156 }
157
158 // Append payload
159 frame.insert(frame.end(), payload.begin(), payload.end());
160
161 return frame;
162 }
static auto generate_mask() -> std::array< uint8_t, 4 >
Generates a random 4-byte masking key.
std::variant< padding_frame, ping_frame, ack_frame, reset_stream_frame, stop_sending_frame, crypto_frame, new_token_frame, stream_frame, max_data_frame, max_stream_data_frame, max_streams_frame, data_blocked_frame, stream_data_blocked_frame, streams_blocked_frame, new_connection_id_frame, retire_connection_id_frame, path_challenge_frame, path_response_frame, connection_close_frame, handshake_done_frame > frame
Variant type holding any QUIC frame.

Referenced by kcenon::network::internal::websocket_protocol::create_binary_message(), kcenon::network::internal::websocket_protocol::create_close(), kcenon::network::internal::websocket_protocol::create_ping(), kcenon::network::internal::websocket_protocol::create_pong(), and kcenon::network::internal::websocket_protocol::create_text_message().

Here is the caller graph for this function:

◆ generate_mask()

auto kcenon::network::internal::websocket_frame::generate_mask ( ) -> std::array<uint8_t, 4>
static

Generates a random 4-byte masking key.

Creates a cryptographically random masking key as required by RFC 6455 for client-to-server frames.

Returns
A 4-byte random masking key

Definition at line 258 of file websocket_frame.cpp.

259 {
260 static thread_local std::random_device rd;
261 static thread_local std::mt19937 gen(rd());
262 static thread_local std::uniform_int_distribution<uint32_t> dis;
263
264 const uint32_t random_value = dis(gen);
265 return {static_cast<uint8_t>((random_value >> 24) & 0xFF),
266 static_cast<uint8_t>((random_value >> 16) & 0xFF),
267 static_cast<uint8_t>((random_value >> 8) & 0xFF),
268 static_cast<uint8_t>(random_value & 0xFF)};
269 }

The documentation for this class was generated from the following files: