Csilk 0.2.1
A lightweight, high-performance C HTTP web framework
Loading...
Searching...
No Matches
websocket.c File Reference

WebSocket handshake, frame encoding, and frame parsing implementation. More...

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <uv.h>
#include "csilk/core/internal.h"
#include "csilk/csilk.h"
#include "../core/context_internal.h"
Include dependency graph for websocket.c:

Macros

#define WS_GUID   "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
 WebSocket magic GUID string per RFC 6455 Section 4.2.2.
 

Functions

void csilk_ws_handshake (csilk_ctx_t *c)
 Perform the WebSocket upgrade handshake per RFC 6455.
 
static void on_ws_write (uv_write_t *req, int status)
 libuv write completion callback for WebSocket frame sends.
 
void csilk_ws_send (csilk_ctx_t *c, const uint8_t *payload, size_t len, int opcode)
 Send a WebSocket data frame (text or binary opcode) per RFC 6455 §5.2.
 
static void on_close_write (uv_write_t *req, int status)
 libuv write completion callback for WebSocket close frames.
 
void csilk_ws_close (csilk_ctx_t *c, uint16_t status_code, const char *reason)
 Send a WebSocket close frame per RFC 6455 §5.5.1.
 
void csilk_ws_parse_frame (csilk_ctx_t *c, const uint8_t *buf, size_t nread)
 Parse and dispatch an incoming WebSocket frame per RFC 6455 §5.2.
 

Detailed Description

WebSocket handshake, frame encoding, and frame parsing implementation.

Architecture: The WebSocket implementation follows RFC 6455. The handshake (csilk_ws_handshake) performs the HTTP upgrade using SHA-1 + Base64 on the Sec-WebSocket-Key. Frame encoding (csilk_ws_send) constructs a raw WebSocket frame buffer per §5.2 and writes it via libuv. Frame parsing (csilk_ws_parse_frame) reads a complete frame from a buffer, unmasks client-to-server payloads, and dispatches by opcode. Close frames (csilk_ws_close) are encoded with optional status code + reason and sent asynchronously; the underlying TCP handle is closed after receiving the peer's close frame.

Wire format (RFC 6455 §5.2, 1 byte = 8 bits): Byte 0: [FIN=1][RSV=000][opcode=xxxx] Byte 1: [MASK=1][payload len=xxxxxxx] Bytes 2+ : Extended payload length (2 or 8 bytes, if len==126 or 127) Bytes 2/4/10+: Masking key (4 bytes, if MASK==1) Remaining: Payload data (XOR-decoded with masking key if MASK==1)

Macro Definition Documentation

◆ WS_GUID

#define WS_GUID   "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"

WebSocket magic GUID string per RFC 6455 Section 4.2.2.

Appended to the client's Sec-WebSocket-Key before SHA-1 hashing to produce the Sec-WebSocket-Accept response header.

Function Documentation

◆ csilk_ws_close()

void csilk_ws_close ( csilk_ctx_t *  c,
uint16_t  status_code,
const char *  reason 
)

Send a WebSocket close frame per RFC 6455 §5.5.1.

Send a WebSocket close frame.

Constructs and sends a close frame with an optional status code and reason string. The payload is limited to 125 bytes (close frame + reason). After sending, the connection is NOT immediately closed — the peer is expected to respond with its own close frame.

Parameters
cThe request context.
status_codeWebSocket close status code (e.g., 1000 for normal, 1001 for "going away"). Pass 0 to omit the status code.
reasonHuman-readable reason string (may be NULL).
Note
The frame is sent asynchronously. The connection should be closed by the caller after receiving the peer's close frame or on timeout.

◆ csilk_ws_handshake()

void csilk_ws_handshake ( csilk_ctx_t *  c)

Perform the WebSocket upgrade handshake per RFC 6455.

Perform the WebSocket upgrade handshake (HTTP Upgrade request).

Validates the presence of the Sec-WebSocket-Key header, computes the expected Sec-WebSocket-Accept response by concatenating the key with the WebSocket GUID ("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"), SHA-1 hashing the result, and Base64-encoding the digest. Sets the Upgrade, Connection, and Sec-WebSocket-Accept response headers, sets status to 101 Switching Protocols, and marks the context as a WebSocket connection.

Parameters
cThe request context.
Note
After a successful handshake, the context's is_websocket flag is set and the connection is ready for frame I/O via csilk_ws_send() and csilk_ws_parse_frame(). On failure (missing Sec-WebSocket-Key), a 400 Bad Request JSON error is sent.

◆ csilk_ws_parse_frame()

void csilk_ws_parse_frame ( csilk_ctx_t *  c,
const uint8_t *  buf,
size_t  nread 
)

Parse and dispatch an incoming WebSocket frame per RFC 6455 §5.2.

Parse an incoming WebSocket frame from the raw TCP stream.

Parses the frame header (FIN, opcode, mask, payload length), extracts the payload, applies client-to-server masking if present, and dispatches based on opcode:

  • Opcode 0x08 (close): auto-responds with a close frame and closes the TCP connection.
  • Other data opcodes: invokes the on_ws_message callback if set.
Parameters
cThe request context.
bufRaw frame data received from the socket.
nreadNumber of bytes available in buf.
Note
Only complete frames should be passed. Partial frames will be silently ignored (insufficient data check returns early).
The payload is heap-allocated, unmasked, and freed after dispatch.

◆ csilk_ws_send()

void csilk_ws_send ( csilk_ctx_t *  c,
const uint8_t *  payload,
size_t  len,
int  opcode 
)

Send a WebSocket data frame (text or binary opcode) per RFC 6455 §5.2.

Send a WebSocket data frame.

Constructs a WebSocket frame with the FIN bit set (final fragment), the specified opcode (0x01 for text, 0x02 for binary), and no masking (server-to-client frames are unmasked per RFC 6455). Supports payload lengths up to 2^64-1 using 7-bit, 16-bit, or 64-bit extended length fields as appropriate.

Parameters
cThe request context (must have _internal_client set).
payloadFrame payload data.
lenPayload length in bytes.
opcodeWebSocket opcode (0x01 for text, 0x02 for binary).
Note
The payload is copied into a heap-allocated frame buffer which is freed by the write completion callback. This function returns immediately; the write happens asynchronously.

◆ on_close_write()

static void on_close_write ( uv_write_t *  req,
int  status 
)
static

libuv write completion callback for WebSocket close frames.

Frees the frame buffer and write request. Logs an error if the write failed.

Parameters
reqThe completed write request (freed by this callback).
statusUV status code (negative indicates error, logged to stderr).

◆ on_ws_write()

static void on_ws_write ( uv_write_t *  req,
int  status 
)
static

libuv write completion callback for WebSocket frame sends.

Frees the frame buffer and the write request structure. Errors are silently ignored.

Parameters
reqThe completed write request (freed by this callback).
statusUV status code (ignored).