cwist
Modern C web framework with libttak runtime
Loading...
Searching...
No Matches
WebSocket API

The WebSocket module allows upgrading standard HTTP connections to persistent WebSocket connections.

Functions

cwist_websocket_upgrade

Upgrades an incoming HTTP request to a WebSocket connection.

cwist_websocket * cwist_websocket_upgrade(cwist_http_request *req, int client_fd)
Upgrade a standard HTTP request to a WebSocket connection.
Definition websocket.c:119
  • Returns a cwist_websocket context on success, or NULL on failure.
  • Automatically handles the handshake and sends the 101 Switching Protocols response.
  • Ownership: The returned pointer is owned by the caller and must be destroyed with cwist_websocket_destroy.

cwist_websocket_receive

Receives a single WebSocket frame.

cwist_ws_frame * cwist_websocket_receive(cwist_websocket *ws)
Receive a frame, blocking until data arrives or the socket closes.
Definition websocket.c:217
  • Blocks until a frame is available.
  • Returns NULL if the connection is closed or an error occurs.
  • Ownership: The returned frame must be freed with cwist_websocket_frame_destroy.

cwist_websocket_send

Sends data as a WebSocket frame.

int cwist_websocket_send(cwist_websocket *ws, cwist_ws_opcode_t opcode, const uint8_t *data, size_t len);
cwist_ws_opcode_t
Definition websocket.h:13
int cwist_websocket_send(cwist_websocket *ws, cwist_ws_opcode_t opcode, const uint8_t *data, size_t len)
Send a frame with the specified opcode and payload.
Definition websocket.c:398
size_t cap
Definition otel.c:56

Opcode Types

  • CWIST_WS_FRAME_TEXT: Text data (UTF-8)
  • CWIST_WS_FRAME_BINARY: Binary data
  • CWIST_WS_FRAME_CLOSE: Connection close
  • CWIST_WS_FRAME_PING / CWIST_WS_FRAME_PONG: Heartbeat

Integration with cwist_app

Use cwist_app_ws to register a WebSocket route.

// Handling logic
}
cwist_app_ws(app, "/chat", my_ws_handler);
void cwist_app_ws(cwist_app *app, const char *path, cwist_ws_handler_func handler)
Register a WebSocket upgrade endpoint with default options.
Definition app.c:2309

Async (C1M) WebSocket API

Header: <cwist/net/websocket/websocket_async.h>

In C1M mode (CWIST_C1M_MODE=1) the reactor watches sockets and delivers each complete message through a callback instead of blocking in cwist_websocket_receive. Use cwist_app_ws_async to register a route on this path.

cwist_app_ws_async

void cwist_app_ws_async(cwist_app *app, const char *path,
cwist_ws_on_message_t on_message, void *user_data);
Main Application Context.
Definition app.h:155
void cwist_app_ws_async(cwist_app *app, const char *path, cwist_ws_on_message_t on_message, void *user_data)
Register a callback-shaped non-blocking WebSocket endpoint (C1M mode).
Definition app.c:2330
void(* cwist_ws_on_message_t)(cwist_websocket_async *ws, cwist_ws_frame *frame, void *user_data)
Callback invoked for each complete WebSocket message on the C1M path.

Registers a reactor-driven WebSocket route. For each complete message the reactor invokes on_message(ws, frame, user_data) on the reactor thread. user_data is an opaque pointer passed through unchanged; use it for per-handler state (broadcast list, room context, etc.).

cwist_ws_on_message_t

void *user_data);
struct cwist_websocket_async cwist_websocket_async

Callback invoked once per complete message. The callback must release frame with cwist_websocket_frame_destroy(). It is safe to call cwist_websocket_async_send() and cwist_websocket_async_close() from inside this callback.

cwist_websocket_async_send

int cwist_websocket_async_send(cwist_websocket_async *ws,
const uint8_t *data, size_t len);
int cwist_websocket_async_send(cwist_websocket_async *ws, cwist_ws_opcode_t opcode, const uint8_t *data, size_t len)
Serialize and send one FIN-terminated frame without blocking.

Sends one FIN-terminated frame without blocking. On EAGAIN or a short write the remainder is parked on a one-shot reactor write slot and drained when the socket becomes writable. Returns 0 on success, -1 on failure.

cwist_websocket_async_close

void cwist_websocket_async_close(cwist_websocket_async *ws);
void cwist_websocket_async_close(cwist_websocket_async *ws)
Initiate the close handshake without blocking.

Initiates the close handshake without blocking. Queues a CLOSE frame and schedules connection cleanup. Safe to call from inside the on_message callback; NULL is ignored.

GraphQL subscriptions (graphql-ws)

‍Supported since v3.8. The feature is opt-in only and changes no existing behavior when unused.

cwist/graphql_ws.h implements the graphql-transport-ws subprotocol on top of the non-blocking WebSocket transport:

  • connection_init -> connection_ack; subscribe before init closes the socket with code 4429.
  • subscribe {id, payload:{query,variables,operationName}} -> one next {id, payload:{data:{...}}} per published event, error {id, payload:[...]} when the operation fails to start, complete {id} when it ends.
  • ping/pong JSON keepalive after init. Malformed traffic closes with 4400/4401; duplicate operation ids close with 4409.

Subscription fields are registered on an endpoint with cwist_graphql_ws_add_subscription(); the resolver returns an event source (cwist_graphql_event_source_create() + cwist_graphql_event_source_add_topic()). Application code fans events out through the in-process, thread-safe topic broker cwist_graphql_publish(topic, payload) — delivery to the wire happens on the owning reactor thread, so publish may be called from any thread.

/* elsewhere, any thread: */
cwist_graphql_publish("counter", payload); /* -> next {data:{counter: payload}} */
bool cwist_graphql_ws_attach(cwist_graphql_ws_t *gws, int fd, cwist_reactor_t *reactor, const uint8_t *initial, size_t initial_len)
Definition graphql_ws.c:730
bool cwist_graphql_ws_add_subscription(cwist_graphql_ws_t *gws, const char *field, cwist_graphql_subscribe_fn subscribe_fn, void *ctx)
Register (or replace) the resolver for a subscription root field.
Definition graphql_ws.c:190
cwist_graphql_ws_t * cwist_graphql_ws_create(cwist_graphql_schema_t *schema)
Create a graphql-ws endpoint holding a subscription field registry.
Definition graphql_ws.c:144
struct cwist_graphql_ws cwist_graphql_ws_t
Definition graphql_ws.h:33
size_t cwist_graphql_publish(const char *topic, const cJSON *payload)
Definition graphql_ws.c:468

Client complete {id} and socket close both tear the subscription down without leaking. See tests/test_graphql_subscriptions.c for an end-to-end example over a socketpair-driven reactor.