|
cwist
Modern C web framework with libttak runtime
|
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>
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). | |
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.
| #define _GNU_SOURCE |
Definition at line 2 of file websocket_async.c.
Definition at line 38 of file websocket_async.c.
Definition at line 37 of file websocket_async.c.
| #define WS_ASYNC_PARK_DEADLINE_SEC 30u |
Definition at line 42 of file websocket_async.c.
| #define WS_ASYNC_READ_CHUNK 16384u |
Definition at line 44 of file websocket_async.c.
| #define WS_ASYNC_SWEEP_SLICE_MS 100u |
Definition at line 410 of file websocket_async.c.
| typedef struct ws_async_sweep ws_async_sweep_t |
Definition at line 54 of file websocket_async.c.
| 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().
| fd | Upgraded socket fd (owned by the new connection on success). |
| reactor | Reactor to register the fd with. |
| on_message | Callback invoked per complete message. Must not be NULL. |
| user_data | Opaque pointer passed back to the callback. |
| initial | Bytes already read past the upgrade request; may be NULL. |
| initial_len | Number of bytes in initial. |
| true | The connection was attached and the read slot armed. |
| false | Invalid 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 * 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.
| fd | Upgraded socket fd (owned by the new connection on success). |
| reactor | Reactor to register the fd with. |
| on_message | Callback invoked per complete message; takes ownership of the delivered frame. Must not be NULL. |
| on_close | Optional callback invoked exactly once during teardown. |
| user_data | Opaque pointer passed back to both callbacks. |
| initial | Bytes already read past the upgrade request; may be NULL. |
| initial_len | Number of bytes in initial. |
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().
| 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.
| ws | Async connection to close. Safe to call with NULL. |
Definition at line 725 of file websocket_async.c.
References cap, and CWIST_WS_FRAME_CLOSE.
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.
| ws | Async connection to close. Safe to call with NULL. |
| code | RFC 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.
| 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.
| ws | Async connection. |
| opcode | Frame opcode (text, binary, PING, ...). |
| data | Payload bytes; may be NULL when len is 0. |
| len | Payload length in bytes. |
| 0 | The frame was sent or parked. |
| -1 | Invalid arguments, the connection is already closing/closed, or queueing failed (the connection is torn down). |
Definition at line 710 of file websocket_async.c.