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

WebSocket protocol handler for message processing. More...

#include <websocket_protocol.h>

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

Public Member Functions

 websocket_protocol (bool is_client)
 Constructs a WebSocket protocol handler.
 
auto process_data (std::span< const uint8_t > data) -> void
 Processes incoming WebSocket data.
 
auto create_text_message (std::string &&text) -> std::vector< uint8_t >
 Creates a text message frame.
 
auto create_binary_message (std::vector< uint8_t > &&data) -> std::vector< uint8_t >
 Creates a binary message frame.
 
auto create_ping (std::vector< uint8_t > &&payload={}) -> std::vector< uint8_t >
 Creates a ping control frame.
 
auto create_pong (std::vector< uint8_t > &&payload={}) -> std::vector< uint8_t >
 Creates a pong control frame.
 
auto create_close (ws_close_code code, std::string &&reason="") -> std::vector< uint8_t >
 Creates a close control frame.
 
auto set_message_callback (std::function< void(const ws_message &)> callback) -> void
 Sets the callback for data messages.
 
auto set_ping_callback (std::function< void(const std::vector< uint8_t > &)> callback) -> void
 Sets the callback for ping frames.
 
auto set_pong_callback (std::function< void(const std::vector< uint8_t > &)> callback) -> void
 Sets the callback for pong frames.
 
auto set_close_callback (std::function< void(ws_close_code, const std::string &)> callback) -> void
 Sets the callback for close frames.
 

Private Member Functions

auto process_frames () -> void
 Processes incoming frames from the buffer.
 
auto handle_data_frame (const ws_frame_header &header, const std::vector< uint8_t > &payload) -> void
 Handles a data frame (text or binary).
 
auto handle_control_frame (const ws_frame_header &header, const std::vector< uint8_t > &payload) -> void
 Handles a control frame (ping, pong, close).
 
auto handle_ping (const std::vector< uint8_t > &payload) -> void
 Handles a ping frame.
 
auto handle_pong (const std::vector< uint8_t > &payload) -> void
 Handles a pong frame.
 
auto handle_close (const std::vector< uint8_t > &payload) -> void
 Handles a close frame.
 

Static Private Member Functions

static auto is_valid_utf8 (const std::vector< uint8_t > &data) -> bool
 Validates UTF-8 encoding.
 

Private Attributes

bool is_client_
 True if client (applies masking)
 
std::vector< uint8_t > buffer_
 Incoming data buffer.
 
std::vector< uint8_t > fragmented_message_
 Reassembly buffer for fragmented messages.
 
ws_opcode fragmented_type_
 Type of fragmented message in progress.
 
std::function< void(const ws_message &)> message_callback_
 
std::function< void(const std::vector< uint8_t > &)> ping_callback_
 
std::function< void(const std::vector< uint8_t > &)> pong_callback_
 
std::function< void(ws_close_code, const std::string &)> close_callback_
 

Detailed Description

WebSocket protocol handler for message processing.

This class handles the WebSocket protocol state machine including:

  • Frame processing and message reassembly
  • Fragmentation handling
  • Control frame processing (ping/pong/close)
  • Message callbacks

Definition at line 82 of file websocket_protocol.h.

Constructor & Destructor Documentation

◆ websocket_protocol()

kcenon::network::internal::websocket_protocol::websocket_protocol ( bool is_client)
explicit

Constructs a WebSocket protocol handler.

Parameters
is_clientTrue if this is a client endpoint (applies masking)

Definition at line 30 of file websocket_protocol.cpp.

31 : is_client_(is_client)
33 {
34 }
ws_opcode fragmented_type_
Type of fragmented message in progress.
bool is_client_
True if client (applies masking)

Member Function Documentation

◆ create_binary_message()

auto kcenon::network::internal::websocket_protocol::create_binary_message ( std::vector< uint8_t > && data) -> std::vector<uint8_t>

Creates a binary message frame.

Encodes the binary data as a WebSocket binary frame. Uses move semantics for zero-copy operation.

Parameters
dataThe binary data to send
Returns
Encoded WebSocket frame ready for transmission

Definition at line 269 of file websocket_protocol.cpp.

271 {
272 return websocket_frame::encode_frame(ws_opcode::binary, std::move(data), true,
273 is_client_);
274 }
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.

References kcenon::network::internal::binary, and kcenon::network::internal::websocket_frame::encode_frame().

Here is the call graph for this function:

◆ create_close()

auto kcenon::network::internal::websocket_protocol::create_close ( ws_close_code code,
std::string && reason = "" ) -> std::vector<uint8_t>

Creates a close control frame.

Initiates the WebSocket closing handshake.

Parameters
codeThe close status code
reasonOptional human-readable reason (UTF-8)
Returns
Encoded close frame

Definition at line 302 of file websocket_protocol.cpp.

304 {
305 std::vector<uint8_t> payload;
306
307 // Encode close code (network byte order)
308 payload.push_back(static_cast<uint8_t>((static_cast<uint16_t>(code) >> 8) & 0xFF));
309 payload.push_back(static_cast<uint8_t>(static_cast<uint16_t>(code) & 0xFF));
310
311 // Append reason (if provided)
312 if (!reason.empty())
313 {
314 // Validate UTF-8 in reason
315 std::vector<uint8_t> reason_bytes(reason.begin(), reason.end());
316 if (is_valid_utf8(reason_bytes))
317 {
318 payload.insert(payload.end(), reason.begin(), reason.end());
319 }
320 }
321
322 // Ensure payload <= 125 bytes
323 if (payload.size() > 125)
324 {
325 payload.resize(125);
326 }
327
328 return websocket_frame::encode_frame(ws_opcode::close, std::move(payload), true,
329 is_client_);
330 }
static auto is_valid_utf8(const std::vector< uint8_t > &data) -> bool
Validates UTF-8 encoding.
@ close
Connection close frame.

References kcenon::network::internal::close, and kcenon::network::internal::websocket_frame::encode_frame().

Here is the call graph for this function:

◆ create_ping()

auto kcenon::network::internal::websocket_protocol::create_ping ( std::vector< uint8_t > && payload = {}) -> std::vector<uint8_t>

Creates a ping control frame.

Ping frames are used to check connection liveness. The peer should respond with a pong frame.

Parameters
payloadOptional payload data (typically empty)
Returns
Encoded ping frame

Definition at line 276 of file websocket_protocol.cpp.

278 {
279 // Ping payload must be <= 125 bytes
280 if (payload.size() > 125)
281 {
282 payload.resize(125);
283 }
284
285 return websocket_frame::encode_frame(ws_opcode::ping, std::move(payload), true,
286 is_client_);
287 }

References kcenon::network::internal::websocket_frame::encode_frame(), and kcenon::network::internal::ping.

Here is the call graph for this function:

◆ create_pong()

auto kcenon::network::internal::websocket_protocol::create_pong ( std::vector< uint8_t > && payload = {}) -> std::vector<uint8_t>

Creates a pong control frame.

Pong frames are sent in response to ping frames.

Parameters
payloadPayload data (should match the ping payload)
Returns
Encoded pong frame

Definition at line 289 of file websocket_protocol.cpp.

291 {
292 // Pong payload must be <= 125 bytes
293 if (payload.size() > 125)
294 {
295 payload.resize(125);
296 }
297
298 return websocket_frame::encode_frame(ws_opcode::pong, std::move(payload), true,
299 is_client_);
300 }

References kcenon::network::internal::websocket_frame::encode_frame(), and kcenon::network::internal::pong.

Referenced by kcenon::network::internal::websocket_socket::websocket_socket().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_text_message()

auto kcenon::network::internal::websocket_protocol::create_text_message ( std::string && text) -> std::vector<uint8_t>

Creates a text message frame.

Encodes the text as a WebSocket text frame with UTF-8 validation. Uses move semantics for zero-copy operation.

Parameters
textThe text message to send
Returns
Encoded WebSocket frame ready for transmission

Definition at line 251 of file websocket_protocol.cpp.

253 {
254 // Convert string to bytes
255 std::vector<uint8_t> payload(text.begin(), text.end());
256
257 // Validate UTF-8
258 if (!is_valid_utf8(payload))
259 {
260 // Return empty frame on invalid UTF-8
261 return {};
262 }
263
264 // Encode as WebSocket frame
265 return websocket_frame::encode_frame(ws_opcode::text, std::move(payload), true,
266 is_client_);
267 }
@ text
Text frame (UTF-8 encoded)

References kcenon::network::internal::websocket_frame::encode_frame(), and kcenon::network::internal::text.

Here is the call graph for this function:

◆ handle_close()

auto kcenon::network::internal::websocket_protocol::handle_close ( const std::vector< uint8_t > & payload) -> void
private

Handles a close frame.

Parses the close code and reason, then invokes the close callback.

Parameters
payloadThe close frame payload

Definition at line 219 of file websocket_protocol.cpp.

220 {
222 std::string reason;
223
224 if (payload.size() >= 2)
225 {
226 // Extract close code (network byte order)
227 code = static_cast<ws_close_code>((payload[0] << 8) | payload[1]);
228
229 // Extract reason (if present)
230 if (payload.size() > 2)
231 {
232 reason = std::string(payload.begin() + 2, payload.end());
233
234 // Validate UTF-8 in reason
235 std::vector<uint8_t> reason_bytes(reason.begin(), reason.end());
236 if (!is_valid_utf8(reason_bytes))
237 {
238 // Invalid UTF-8 in close reason
240 reason.clear();
241 }
242 }
243 }
244
245 if (close_callback_)
246 {
247 close_callback_(code, reason);
248 }
249 }
std::function< void(ws_close_code, const std::string &)> close_callback_
ws_close_code
WebSocket close status codes (RFC 6455 Section 7.4).

References kcenon::network::internal::normal, and kcenon::network::internal::protocol_error.

◆ handle_control_frame()

auto kcenon::network::internal::websocket_protocol::handle_control_frame ( const ws_frame_header & header,
const std::vector< uint8_t > & payload ) -> void
private

Handles a control frame (ping, pong, close).

Control frames must not be fragmented.

Parameters
headerThe frame header
payloadThe frame payload

Definition at line 168 of file websocket_protocol.cpp.

171 {
172 // Control frames must not be fragmented
173 if (!header.fin)
174 {
175 // Protocol error
176 return;
177 }
178
179 // Control frames must have payload <= 125 bytes
180 if (header.payload_len > 125)
181 {
182 // Protocol error
183 return;
184 }
185
186 switch (header.opcode)
187 {
188 case ws_opcode::ping:
189 handle_ping(payload);
190 break;
191 case ws_opcode::pong:
192 handle_pong(payload);
193 break;
194 case ws_opcode::close:
195 handle_close(payload);
196 break;
197 default:
198 // Unknown control frame
199 break;
200 }
201 }
auto handle_ping(const std::vector< uint8_t > &payload) -> void
Handles a ping frame.
auto handle_pong(const std::vector< uint8_t > &payload) -> void
Handles a pong frame.
auto handle_close(const std::vector< uint8_t > &payload) -> void
Handles a close frame.

References kcenon::network::internal::close, kcenon::network::internal::ping, and kcenon::network::internal::pong.

◆ handle_data_frame()

auto kcenon::network::internal::websocket_protocol::handle_data_frame ( const ws_frame_header & header,
const std::vector< uint8_t > & payload ) -> void
private

Handles a data frame (text or binary).

Manages fragmentation and reassembly.

Parameters
headerThe frame header
payloadThe frame payload

Definition at line 90 of file websocket_protocol.cpp.

93 {
94 // Handle fragmentation
95 if (header.opcode == ws_opcode::continuation)
96 {
97 // Continuation frame
98 if (fragmented_message_.empty())
99 {
100 // Protocol error: continuation without initial frame
101 return;
102 }
103
104 // Append to fragmented message
105 fragmented_message_.insert(fragmented_message_.end(), payload.begin(),
106 payload.end());
107
108 if (header.fin)
109 {
110 // Final fragment - complete message
111 ws_message msg;
114 msg.data = std::move(fragmented_message_);
115
116 // Validate UTF-8 for text messages
117 if (msg.type == ws_message_type::text && !is_valid_utf8(msg.data))
118 {
119 // Invalid UTF-8, protocol error
120 fragmented_message_.clear();
121 return;
122 }
123
124 // Clear fragmentation state
125 fragmented_message_.clear();
127
128 // Invoke callback
130 {
132 }
133 }
134 }
135 else
136 {
137 // Initial frame (text or binary)
138 if (!header.fin)
139 {
140 // Start of fragmented message
141 fragmented_type_ = header.opcode;
142 fragmented_message_ = payload;
143 }
144 else
145 {
146 // Complete message in single frame
147 ws_message msg;
148 msg.type = (header.opcode == ws_opcode::text) ? ws_message_type::text
150 msg.data = payload;
151
152 // Validate UTF-8 for text messages
153 if (msg.type == ws_message_type::text && !is_valid_utf8(msg.data))
154 {
155 // Invalid UTF-8, protocol error
156 return;
157 }
158
159 // Invoke callback
161 {
163 }
164 }
165 }
166 }
std::function< void(const ws_message &)> message_callback_
std::vector< uint8_t > fragmented_message_
Reassembly buffer for fragmented messages.
ws_message_type
Type of WebSocket message.
@ text
Text message (UTF-8 encoded)

References kcenon::network::internal::binary, kcenon::network::internal::continuation, kcenon::network::internal::ws_message::data, kcenon::network::internal::text, and kcenon::network::internal::ws_message::type.

◆ handle_ping()

auto kcenon::network::internal::websocket_protocol::handle_ping ( const std::vector< uint8_t > & payload) -> void
private

Handles a ping frame.

Invokes the ping callback if set.

Parameters
payloadThe ping payload

Definition at line 203 of file websocket_protocol.cpp.

204 {
205 if (ping_callback_)
206 {
207 ping_callback_(payload);
208 }
209 }
std::function< void(const std::vector< uint8_t > &)> ping_callback_

◆ handle_pong()

auto kcenon::network::internal::websocket_protocol::handle_pong ( const std::vector< uint8_t > & payload) -> void
private

Handles a pong frame.

Invokes the pong callback if set.

Parameters
payloadThe pong payload

Definition at line 211 of file websocket_protocol.cpp.

212 {
213 if (pong_callback_)
214 {
215 pong_callback_(payload);
216 }
217 }
std::function< void(const std::vector< uint8_t > &)> pong_callback_

◆ is_valid_utf8()

auto kcenon::network::internal::websocket_protocol::is_valid_utf8 ( const std::vector< uint8_t > & data) -> bool
staticprivate

Validates UTF-8 encoding.

Checks if the data is valid UTF-8 (required for text messages).

Parameters
dataThe data to validate
Returns
True if valid UTF-8, false otherwise

Definition at line 356 of file websocket_protocol.cpp.

357 {
358 size_t i = 0;
359 while (i < data.size())
360 {
361 uint8_t byte = data[i];
362
363 // Determine the number of bytes in this UTF-8 character
364 int bytes_to_follow = 0;
365
366 if ((byte & 0x80) == 0x00)
367 {
368 // 1-byte character (0xxxxxxx)
369 bytes_to_follow = 0;
370 }
371 else if ((byte & 0xE0) == 0xC0)
372 {
373 // 2-byte character (110xxxxx)
374 bytes_to_follow = 1;
375 }
376 else if ((byte & 0xF0) == 0xE0)
377 {
378 // 3-byte character (1110xxxx)
379 bytes_to_follow = 2;
380 }
381 else if ((byte & 0xF8) == 0xF0)
382 {
383 // 4-byte character (11110xxx)
384 bytes_to_follow = 3;
385 }
386 else
387 {
388 // Invalid UTF-8 start byte
389 return false;
390 }
391
392 // Check if we have enough bytes
393 if (i + bytes_to_follow >= data.size())
394 {
395 return false;
396 }
397
398 // Validate continuation bytes
399 for (int j = 1; j <= bytes_to_follow; ++j)
400 {
401 if ((data[i + j] & 0xC0) != 0x80)
402 {
403 // Invalid continuation byte (should be 10xxxxxx)
404 return false;
405 }
406 }
407
408 i += bytes_to_follow + 1;
409 }
410
411 return true;
412 }

◆ process_data()

auto kcenon::network::internal::websocket_protocol::process_data ( std::span< const uint8_t > data) -> void

Processes incoming WebSocket data.

Parses frames, handles fragmentation, and invokes appropriate callbacks. This method should be called when data is received from the network.

Zero-Copy Performance

Accepts data as a non-owning span view, avoiding unnecessary copies. The data is copied once into the internal buffer for frame processing.

Lifetime Contract

  • The span must remain valid for the duration of this call.
  • After the call returns, the span may be invalidated.
Parameters
dataThe incoming data buffer as a view

Definition at line 36 of file websocket_protocol.cpp.

37 {
38 // Append incoming data to buffer (single copy from span view)
39 buffer_.insert(buffer_.end(), data.begin(), data.end());
40
41 // Process frames from buffer
43 }
auto process_frames() -> void
Processes incoming frames from the buffer.
std::vector< uint8_t > buffer_
Incoming data buffer.

◆ process_frames()

auto kcenon::network::internal::websocket_protocol::process_frames ( ) -> void
private

Processes incoming frames from the buffer.

Attempts to parse and handle frames from the accumulated buffer. May invoke callbacks for complete messages.

Definition at line 45 of file websocket_protocol.cpp.

46 {
47 while (true)
48 {
49 // Try to decode frame header
50 auto header_opt = websocket_frame::decode_header(buffer_);
51 if (!header_opt.has_value())
52 {
53 // Not enough data for header, wait for more
54 return;
55 }
56
57 const auto& header = header_opt.value();
58
59 // Calculate total frame size
60 const size_t header_size =
61 websocket_frame::calculate_header_size(header.payload_len, header.mask);
62 const size_t frame_size = header_size + header.payload_len;
63
64 // Check if we have the complete frame
65 if (buffer_.size() < frame_size)
66 {
67 // Incomplete frame, wait for more data
68 return;
69 }
70
71 // Decode payload
72 auto payload = websocket_frame::decode_payload(header, buffer_);
73
74 // Remove processed frame from buffer
75 buffer_.erase(buffer_.begin(), buffer_.begin() + frame_size);
76
77 // Dispatch frame based on opcode
78 if (header.opcode == ws_opcode::text || header.opcode == ws_opcode::binary ||
79 header.opcode == ws_opcode::continuation)
80 {
81 handle_data_frame(header, payload);
82 }
83 else
84 {
85 handle_control_frame(header, payload);
86 }
87 }
88 }
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 calculate_header_size(uint64_t payload_len, bool mask) -> size_t
Calculates the size of the frame header.
static auto decode_header(const std::vector< uint8_t > &data) -> std::optional< ws_frame_header >
Decodes a WebSocket frame header from raw data.
auto handle_data_frame(const ws_frame_header &header, const std::vector< uint8_t > &payload) -> void
Handles a data frame (text or binary).
auto handle_control_frame(const ws_frame_header &header, const std::vector< uint8_t > &payload) -> void
Handles a control frame (ping, pong, close).

References kcenon::network::internal::binary, kcenon::network::internal::websocket_frame::calculate_header_size(), kcenon::network::internal::continuation, kcenon::network::internal::websocket_frame::decode_header(), kcenon::network::internal::websocket_frame::decode_payload(), and kcenon::network::internal::text.

Here is the call graph for this function:

◆ set_close_callback()

auto kcenon::network::internal::websocket_protocol::set_close_callback ( std::function< void(ws_close_code, const std::string &)> callback) -> void

Sets the callback for close frames.

This callback is invoked when a close frame is received. The application should respond with a close frame if it hasn't already.

Parameters
callbackThe callback function

Definition at line 350 of file websocket_protocol.cpp.

352 {
353 close_callback_ = std::move(callback);
354 }

Referenced by kcenon::network::internal::websocket_socket::websocket_socket().

Here is the caller graph for this function:

◆ set_message_callback()

auto kcenon::network::internal::websocket_protocol::set_message_callback ( std::function< void(const ws_message &)> callback) -> void

Sets the callback for data messages.

This callback is invoked when a complete text or binary message has been received and reassembled.

Parameters
callbackThe callback function

Definition at line 332 of file websocket_protocol.cpp.

334 {
335 message_callback_ = std::move(callback);
336 }

Referenced by kcenon::network::internal::websocket_socket::websocket_socket().

Here is the caller graph for this function:

◆ set_ping_callback()

auto kcenon::network::internal::websocket_protocol::set_ping_callback ( std::function< void(const std::vector< uint8_t > &)> callback) -> void

Sets the callback for ping frames.

This callback is invoked when a ping frame is received. The application may choose to send a pong response.

Parameters
callbackThe callback function

Definition at line 338 of file websocket_protocol.cpp.

340 {
341 ping_callback_ = std::move(callback);
342 }

Referenced by kcenon::network::internal::websocket_socket::websocket_socket().

Here is the caller graph for this function:

◆ set_pong_callback()

auto kcenon::network::internal::websocket_protocol::set_pong_callback ( std::function< void(const std::vector< uint8_t > &)> callback) -> void

Sets the callback for pong frames.

This callback is invoked when a pong frame is received (typically in response to a ping).

Parameters
callbackThe callback function

Definition at line 344 of file websocket_protocol.cpp.

346 {
347 pong_callback_ = std::move(callback);
348 }

Referenced by kcenon::network::internal::websocket_socket::websocket_socket().

Here is the caller graph for this function:

Member Data Documentation

◆ buffer_

std::vector<uint8_t> kcenon::network::internal::websocket_protocol::buffer_
private

Incoming data buffer.

Definition at line 214 of file websocket_protocol.h.

◆ close_callback_

std::function<void(ws_close_code, const std::string&)> kcenon::network::internal::websocket_protocol::close_callback_
private

Definition at line 222 of file websocket_protocol.h.

◆ fragmented_message_

std::vector<uint8_t> kcenon::network::internal::websocket_protocol::fragmented_message_
private

Reassembly buffer for fragmented messages.

Definition at line 215 of file websocket_protocol.h.

◆ fragmented_type_

ws_opcode kcenon::network::internal::websocket_protocol::fragmented_type_
private

Type of fragmented message in progress.

Definition at line 216 of file websocket_protocol.h.

◆ is_client_

bool kcenon::network::internal::websocket_protocol::is_client_
private

True if client (applies masking)

Definition at line 213 of file websocket_protocol.h.

◆ message_callback_

std::function<void(const ws_message&)> kcenon::network::internal::websocket_protocol::message_callback_
private

Definition at line 219 of file websocket_protocol.h.

◆ ping_callback_

std::function<void(const std::vector<uint8_t>&)> kcenon::network::internal::websocket_protocol::ping_callback_
private

Definition at line 220 of file websocket_protocol.h.

◆ pong_callback_

std::function<void(const std::vector<uint8_t>&)> kcenon::network::internal::websocket_protocol::pong_callback_
private

Definition at line 221 of file websocket_protocol.h.


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