cwist
Modern C web framework with libttak runtime
Loading...
Searching...
No Matches
websocket_async.c File Reference

Reactor-driven, callback-shaped non-blocking WebSocket path (C1M mode). More...

#include <cwist/net/websocket/websocket_async.h>
#include <cwist/core/mem/alloc.h>
#include <cwist/net/http/writer_fast.h>
#include <cwist/sys/io/reactor.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <pthread.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
Include dependency graph for websocket_async.c:

Go to the source code of this file.

Macros

#define _GNU_SOURCE
 
#define WS_ASYNC_MAX_PAYLOAD_BYTES   ((uint64_t)(16u * 1024u * 1024u))
 
#define WS_ASYNC_MAX_MESSAGE_BYTES   ((size_t)(64u * 1024u * 1024u))
 
#define WS_ASYNC_PARK_DEADLINE_SEC   30u
 
#define WS_ASYNC_READ_CHUNK   16384u
 
#define WS_ASYNC_SWEEP_SLICE_MS   100u
 

Typedefs

typedef struct ws_async_sweep ws_async_sweep_t
 

Functions

int cwist_websocket_async_send (cwist_websocket_async *ws, cwist_ws_opcode_t opcode, const uint8_t *data, size_t len)
 Send one complete WebSocket message frame on an async connection.
 
void cwist_websocket_async_close (cwist_websocket_async *ws)
 Initiate the WebSocket close handshake with an empty CLOSE frame.
 
void cwist_websocket_async_close_code (cwist_websocket_async *ws, uint16_t code)
 Initiate the WebSocket close handshake with a CLOSE frame carrying a status code.
 
cwist_websocket_async * cwist_websocket_async_attach_ex (int fd, cwist_reactor_t *reactor, cwist_ws_on_message_t on_message, cwist_ws_on_close_t on_close, void *user_data, const uint8_t *initial, size_t initial_len)
 Attach an upgraded, HTTP-connection-owned fd to the reactor as an async WebSocket connection.
 
bool cwist_websocket_async_attach (int fd, cwist_reactor_t *reactor, cwist_ws_on_message_t on_message, void *user_data, const uint8_t *initial, size_t initial_len)
 Attach an upgraded fd to the reactor as an async WebSocket connection (no on_close callback variant).
 

Detailed Description

Reactor-driven, callback-shaped non-blocking WebSocket path (C1M mode).

Issue #181: on the C1M path the route handler runs on the reactor thread, so the blocking recv() loop of cwist_websocket_receive() would park the entire worker. This module instead registers the upgraded fd with the reactor, drains it with non-blocking recv() calls, parses frames incrementally from a grow-by-doubling stash buffer (same model as the HTTP async connection rbuf), and delivers each complete message through the route's on_message callback.

Frame validation mirrors cwist_websocket_receive() rule-for-rule so both paths enforce identical RFC 6455 semantics (issues #145-#164).

Definition in file websocket_async.c.

Macro Definition Documentation

◆ _GNU_SOURCE

#define _GNU_SOURCE

Definition at line 2 of file websocket_async.c.

◆ WS_ASYNC_MAX_MESSAGE_BYTES

#define WS_ASYNC_MAX_MESSAGE_BYTES   ((size_t)(64u * 1024u * 1024u))

Definition at line 38 of file websocket_async.c.

◆ WS_ASYNC_MAX_PAYLOAD_BYTES

#define WS_ASYNC_MAX_PAYLOAD_BYTES   ((uint64_t)(16u * 1024u * 1024u))

Definition at line 37 of file websocket_async.c.

◆ WS_ASYNC_PARK_DEADLINE_SEC

#define WS_ASYNC_PARK_DEADLINE_SEC   30u

Definition at line 42 of file websocket_async.c.

◆ WS_ASYNC_READ_CHUNK

#define WS_ASYNC_READ_CHUNK   16384u

Definition at line 44 of file websocket_async.c.

◆ WS_ASYNC_SWEEP_SLICE_MS

#define WS_ASYNC_SWEEP_SLICE_MS   100u

Definition at line 410 of file websocket_async.c.

Typedef Documentation

◆ ws_async_sweep_t

Definition at line 54 of file websocket_async.c.

Function Documentation

◆ cwist_websocket_async_attach()

bool cwist_websocket_async_attach ( int  fd,
cwist_reactor_t *  reactor,
cwist_ws_on_message_t  on_message,
void *  user_data,
const uint8_t *  initial,
size_t  initial_len 
)

Attach an upgraded fd to the reactor as an async WebSocket connection (no on_close callback variant).

Take ownership of a connected, upgraded fd and drive it reactively.

Thin boolean wrapper around cwist_websocket_async_attach_ex().

Parameters
fdUpgraded socket fd (owned by the new connection on success).
reactorReactor to register the fd with.
on_messageCallback invoked per complete message. Must not be NULL.
user_dataOpaque pointer passed back to the callback.
initialBytes already read past the upgrade request; may be NULL.
initial_lenNumber of bytes in initial.
Return values
trueThe connection was attached and the read slot armed.
falseInvalid arguments or failure (fd is closed).

Definition at line 1211 of file websocket_async.c.

References cap, and cwist_websocket_async_attach_ex().

◆ cwist_websocket_async_attach_ex()

cwist_websocket_async * cwist_websocket_async_attach_ex ( int  fd,
cwist_reactor_t *  reactor,
cwist_ws_on_message_t  on_message,
cwist_ws_on_close_t  on_close,
void *  user_data,
const uint8_t *  initial,
size_t  initial_len 
)

Attach an upgraded, HTTP-connection-owned fd to the reactor as an async WebSocket connection.

Attach variant that reports the connection handle and teardown.

Sets the fd non-blocking, feeds any bytes already read past the upgrade request through the parser (delivery can happen inline here, including a close from the on_message callback), arms the one-shot read slot, and joins the reactor's idle sweep. On any failure the fd is closed and all state is freed; on_close does not fire because the attach itself failed.

Parameters
fdUpgraded socket fd (owned by the new connection on success).
reactorReactor to register the fd with.
on_messageCallback invoked per complete message; takes ownership of the delivered frame. Must not be NULL.
on_closeOptional callback invoked exactly once during teardown.
user_dataOpaque pointer passed back to both callbacks.
initialBytes already read past the upgrade request; may be NULL.
initial_lenNumber of bytes in initial.
Returns
The new async connection, or NULL on invalid arguments or failure (fd is closed in the latter case).

Definition at line 1116 of file websocket_async.c.

References cap, cwist_alloc(), cwist_fast_monotonic_sec(), cwist_free(), cwist_reactor_add(), and CWIST_WS_FRAME_CONTINUATION.

Referenced by cwist_graphql_ws_attach(), and cwist_websocket_async_attach().

◆ cwist_websocket_async_close()

void cwist_websocket_async_close ( cwist_websocket_async *  ws)

Initiate the WebSocket close handshake with an empty CLOSE frame.

Initiate the close handshake without blocking.

Idempotent: calling again on a connection already closing is a no-op. The connection is torn down once the CLOSE frame has drained or, on queueing failure, via a deferred termination.

Parameters
wsAsync connection to close. Safe to call with NULL.

Definition at line 725 of file websocket_async.c.

References cap, and CWIST_WS_FRAME_CLOSE.

◆ cwist_websocket_async_close_code()

void cwist_websocket_async_close_code ( cwist_websocket_async *  ws,
uint16_t  code 
)

Initiate the WebSocket close handshake with a CLOSE frame carrying a status code.

The 2-byte big-endian status code is echoed to the peer. Idempotent: calling again on a connection already closing is a no-op. The connection is torn down once the CLOSE frame has drained or, on queueing failure, via a deferred termination.

Parameters
wsAsync connection to close. Safe to call with NULL.
codeRFC 6455 close status code (big-endian on the wire).

Definition at line 754 of file websocket_async.c.

References cap, and CWIST_WS_FRAME_CLOSE.

◆ cwist_websocket_async_send()

int cwist_websocket_async_send ( cwist_websocket_async *  ws,
cwist_ws_opcode_t  opcode,
const uint8_t *  data,
size_t  len 
)

Send one complete WebSocket message frame on an async connection.

Serialize and send one FIN-terminated frame without blocking.

May be called from the reactor thread (e.g. inside the on_message callback); partial writes are parked and resumed by a POLLOUT slot.

Parameters
wsAsync connection.
opcodeFrame opcode (text, binary, PING, ...).
dataPayload bytes; may be NULL when len is 0.
lenPayload length in bytes.
Return values
0The frame was sent or parked.
-1Invalid arguments, the connection is already closing/closed, or queueing failed (the connection is torn down).

Definition at line 710 of file websocket_async.c.