A standalone RFC 6455 WebSocket protocol library for C11/C++11.
- RFC 6455 compliant WebSocket frame parsing and building
- Client and server handshake handling
- Message reassembly with fragmentation support
- Streaming UTF-8 validation (RFC 3629)
- All opcodes: TEXT, BINARY, CONTINUATION, PING, PONG, CLOSE
- Zero external dependencies
- Protocol-only codec layer (no I/O) -- works with any TCP transport
- C11/C++11 compatible compiler
- CMake 3.13+
mkdir build && cd build
cmake .. [options]
cmake --build . --config Release| Option | Default | Description |
|---|---|---|
BUILD_SHARED |
OFF | Build shared library (SO/DYLIB). Not recommended on Windows due to STL ABI instability across MSVC versions. |
BUILD_DEMO |
OFF | Build demo executable |
BUILD_TESTS |
OFF | Build test suite |
cmake .. -DBUILD_TESTS=ON -DBUILD_DEMO=ON
cmake --build . --config RelWithDebInfo
ctest#include "websocket/websocket.h"
// Build handshake request
std::string key;
std::string request = websocket::client::BuildHandshakeRequest(
&key, "/chat", "example.com", "", "");
// Build and send a text frame (client frames are masked automatically)
std::string frame = websocket::client::BuildSingleDataFrame("Hello, World!",
websocket::DataType::Text);
// Build control frames
std::string ping = websocket::client::BuildPingFrame("ping data");
std::string close = websocket::client::BuildCloseFrame(
websocket::Status::NORMAL, "bye");#include "websocket/websocket.h"
// Parse client handshake
websocket::Handshaker handshaker(request_data, request_size);
if (handshaker.IsValidClientRequest()) {
auto key = handshaker.FindField("Sec-WebSocket-Key");
std::string response = websocket::server::BuildHandshakeSuccessReply(
key.second, "");
}
// Build and send a text frame (server frames are unmasked)
std::string frame = websocket::server::BuildSingleDataFrame("Hello, Client!",
websocket::DataType::Text);#include "websocket/assembler.h"
class MyHandler : public websocket::MessageHandler {
void OnMessage(const websocket::WebSocketMessage& msg) override {
// Handle complete (possibly reassembled) message
if (msg.is_text) {
// process text
} else {
// process binary
}
}
void OnControlFrame(const websocket::ControlFrame& frame) override {
// Handle PING, PONG, or CLOSE control frames
}
void OnError(const std::string& reason) override {
// Handle protocol errors; assembler resets state automatically
}
};
MyHandler handler;
websocket::MessageAssembler assembler(&handler);
// Optional tuning
assembler.SetMaxBufferSize(16 * 1024 * 1024); // 16 MB default
assembler.SetMaxFragmentsPerMessage(1000); // 0 = unlimited (default)
// Feed raw TCP data
assembler.Feed(raw_data, data_size);
// Reset after disconnect
assembler.Reset();#include "websocket/websocket.h"
#include <vector>
#include <string>
// Split a large payload into multiple frames (max 1024 bytes each)
std::string data = "large payload...";
std::vector<std::string> frames;
websocket::server::BuildConsecutiveFrames(
&frames, data, 1024, websocket::DataType::Text);
// On the receiving end, MessageAssembler reassembles them automatically#include "websocket/websocket.h"
// Check how many bytes a complete frame needs
int64_t frame_len = websocket::FrameContext::CheckFrameLength(data, size);
if (frame_len == 0) {
// incomplete -- need more data
} else if (frame_len < 0) {
// error (ParseError value)
} else {
// parse the frame (buffer must be writable for unmasking)
websocket::FrameContext ctx(const_cast<uint8_t*>(data),
static_cast<uint32_t>(frame_len));
if (ctx.ProcessData()) {
bool fin = ctx.Fin();
int opcode = ctx.OpCode();
bool masked = ctx.Mask();
const uint8_t* payload = ctx.Payload();
uint32_t payload_len = ctx.PayloadSize();
}
}
// Determine if incoming data is a handshake or a websocket frame
int32_t pkg_len = websocket::CheckPackageLength(data, len);| Layer | Components | Purpose |
|---|---|---|
| L1 -- Cryptography | sha1.cc, base64.cc (internal) |
Handshake key computation (SHA-1, Base64) |
| L2 -- Frame Protocol | FrameContext, BuildFrame*, CheckPackageLength |
Single frame parse/build, byte-order helpers |
| L3 -- Handshake | Handshaker |
HTTP Upgrade request/response validation |
| L4 -- Message Assembly | MessageAssembler, Utf8Validator (internal) |
Fragment reassembly and UTF-8 validation |
websocket::OpCode-- WebSocket frame opcodes (WS_CONTINUATION,WS_TEXT,WS_BINARY,WS_CLOSE,WS_PING,WS_PONG)websocket::DataType--TextorBinarywebsocket::Status-- Close status codes (RFC 6455 Section 7.4):NORMAL(1000),GOING_AWAY(1001),PROTOCOL_ERROR(1002), etc.websocket::ParseError-- Frame parsing error codes:OK,INSUFFICIENT_DATA,INVALID_LENGTH,PAYLOAD_TOO_LARGE
websocket::Handshaker-- Parse and validate HTTP upgrade requests/responseswebsocket::Handshaker::CheckPackageLength()-- Check if a complete handshake is presentwebsocket::Handshaker::IsValidClientRequest()-- Validate an incoming client requestwebsocket::Handshaker::IsValidServerResponse()-- Validate a server response against the original keywebsocket::Handshaker::FindField()-- Case-insensitive header field lookupwebsocket::client::BuildHandshakeRequest()-- Generate client handshake HTTP requestwebsocket::server::BuildHandshakeSuccessReply()-- Generate server 101 responsewebsocket::server::BuildHandshakeFailedReply()-- Generate non-101 error response
websocket::client::Build*()-- Client frames (payload is masked)websocket::server::Build*()-- Server frames (unmasked)websocket::BuildSingleFrame()-- Low-level frame builderwebsocket::BuildFramePrefix()-- Build frame header byteswebsocket::BuildFrameWithPayload()-- Build frame with masked payloadwebsocket::MaskingPayload()-- Apply XOR mask to payload bytes
websocket::FrameContext-- Parse a single frame from raw byteswebsocket::FrameContext::CheckFrameLength()-- Determine complete frame sizewebsocket::CheckPackageLength()-- Determine if data is a handshake or frame, and its lengthwebsocket::GetCloseInfo()-- Extract close status code and reason from a close frame
websocket::MessageAssembler-- Reassemble fragmented messages from raw TCP streamwebsocket::MessageHandler-- Interface for receiving reassembled messages (OnMessage,OnControlFrame,OnError)websocket::WebSocketMessage-- Complete message withis_textflag andpayloadwebsocket::ControlFrame-- Control frame withopcodeandpayload
cd build
ctestIndividual test executables:
| Test | Description |
|---|---|
test_base64 |
Base64 encode/decode |
test_handshake |
Handshake request/response validation |
test_frame |
Frame build/parse roundtrip |
test_assembler |
Fragmented message reassembly |
test_sha1 |
SHA-1 known-answer vectors (FIPS 180-4) |
test_utf8 |
UTF-8 validation |
Apache License 2.0 -- see LICENSE
src/sha1.cc,src/sha1.h-- Based on SHA-1 implementation by Paul E. Jones