ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
internal.h File Reference

Internal WebSocket implementation types shared between transport.c and server.c. More...

Go to the source code of this file.

Data Structures

struct  websocket_msg_t
 Owned WebSocket frame queued for sending or reassembly. More...
struct  websocket_transport_data_t
 Private state for one libwebsockets-backed ACIP transport. More...

Typedefs

typedef websocket_msg_t websocket_recv_msg_t

Functions

asciichat_error_t websocket_transport_send (acip_transport_t *transport, const void *data, size_t len)
void websocket_transport_write_pending (struct lws *wsi, websocket_transport_data_t *ws_data)
 Drain client messages from the send queue on the service thread.

Detailed Description

Internal WebSocket implementation types shared between transport.c and server.c.

Definition in file network/websocket/internal.h.

Typedef Documentation

◆ websocket_recv_msg_t

Function Documentation

◆ websocket_transport_send()

asciichat_error_t websocket_transport_send ( acip_transport_t * transport,
const void * data,
size_t len )

Queue one packet, preserving its control budget through encryption and ownership transfer.

Definition at line 642 of file websocket/transport.c.

642 {
643 // NOTE: Disabled START_TIMER/STOP_TIMER due to thread safety issues with timer hashtable
644 // causing heap-use-after-free crashes in ASAN. The timer system has race conditions
645 // when accessed from the service thread context. See: line 325 (similar issue).
647
648 // For server-side transports (owns_context=false), the connection is already established.
649 // For client-side transports, packets may be queued before the asynchronous WebSocket
650 // handshake completes. The service thread drains that queue after CLIENT_ESTABLISHED.
651 if (ws_data->owns_context) {
652 // Check connection state without blocking the service thread.
653 mutex_lock(&ws_data->state_mutex);
654 bool connected = ws_data->is_connected;
655 bool connection_failed = ws_data->connection_failed;
656 mutex_unlock(&ws_data->state_mutex);
657
658 if (connection_failed) {
659 log_error("Connection failed - cannot send");
660 return SET_ERRNO(ERROR_NETWORK, "WebSocket connection failed");
661 }
662
663 if (!connected) {
664 log_debug("Connection is opening; queueing packet for delivery after handshake");
665 }
666
667 log_dev_every(1000000, "websocket_send (client): is_connected=%d, wsi=%p, send_len=%zu", connected,
668 (void *)ws_data->wsi, len);
669 } else {
671 "[WEBSOCKET_SEND_SERVER] Server transport send: wsi=%p, len=%zu (bypassing is_connected check)",
672 (void *)ws_data->wsi, len);
673 }
674
675 // Classify the original packet before encryption hides its type. Keep this
676 // domain through every allocation, including the asynchronous queue owner.
677 buffer_domain_t *domain = NULL;
678 if (data && len >= sizeof(packet_header_t)) {
679 packet_header_t header;
680 memcpy(&header, data, sizeof(header));
681 packet_type_t type = NET_TO_HOST_U16(header.type);
682 if (packet_is_handshake_type(type) || type == PACKET_TYPE_ERROR_MESSAGE)
683 domain = buffer_control_domain();
684 }
685 const void *send_data = NULL;
686 size_t send_len = 0;
687 uint8_t *encrypted_packet = NULL;
688 size_t encrypted_packet_size = 0;
689 asciichat_error_t result = websocket_prepare_payload(transport, domain, data, len, &send_data, &send_len,
690 &encrypted_packet, &encrypted_packet_size);
691 if (result != ASCIICHAT_OK) {
692 return result;
693 }
694
695 result = websocket_queue_payload(ws_data, domain, send_data, send_len);
696 if (encrypted_packet) {
697 buffer_release(encrypted_packet);
698 }
699 return result;
700}
#define SET_ERRNO(code,...)
buffer_domain_t * buffer_control_domain(void)
Definition buffer.c:436
struct buffer_domain buffer_domain_t
Definition buffer.h:24
#define buffer_release(data)
Definition buffer.h:91
#define NET_TO_HOST_U16(val)
Definition endian.h:111
unsigned char uint8_t
Definition common.h:60
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ERROR_NETWORK
Definition error_codes.h:72
@ ASCIICHAT_OK
Definition error_codes.h:46
#define log_error(...)
Log an ERROR message.
Definition log/log.h:634
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:595
#define US_PER_MS_INT
Definition time.h:172
packet_type_t
Network protocol packet type enumeration.
Definition packet.h:301
@ PACKET_TYPE_ERROR_MESSAGE
Error packet with asciichat_error_t code and human-readable message.
Definition packet.h:374
#define log_dev_every(interval_us, fmt,...)
Rate-limited DEV logging.
Definition log/log.h:746
void * impl_data
Transport-specific state.
Fixed prefix shared by every ACIP packet on the wire.
Definition packet.h:628
Private state for one libwebsockets-backed ACIP transport.

References ASCIICHAT_OK, buffer_control_domain(), buffer_release, websocket_transport_data_t::connection_failed, ERROR_NETWORK, acip_transport::impl_data, websocket_transport_data_t::is_connected, log_debug, log_dev_every, log_error, NET_TO_HOST_U16, websocket_transport_data_t::owns_context, PACKET_TYPE_ERROR_MESSAGE, SET_ERRNO, websocket_transport_data_t::state_mutex, US_PER_MS_INT, and websocket_transport_data_t::wsi.

◆ websocket_transport_write_pending()

void websocket_transport_write_pending ( struct lws * wsi,
websocket_transport_data_t * ws_data )

Drain client messages from the send queue on the service thread.

Definition at line 459 of file websocket/transport.c.

459 {
460 if (!ws_data || atomic_load_bool(&ws_data->is_destroying))
461 return;
462 /* lws suppresses writable callbacks until previously buffered output is
463 * consumed. Keep one owner until this completion boundary, or connection
464 * teardown; elapsed service-loop iterations are not a completion signal. */
465 websocket_recv_msg_t msg = {0};
466 mutex_lock(&ws_data->send_mutex);
468 ws_data->inflight_buffer = NULL;
469 ws_data->pending_send_bytes -= ws_data->inflight_bytes;
470 ws_data->inflight_bytes = 0;
471 bool available = ringbuffer_read(ws_data->send_queue, &msg);
472 if (available)
473 ws_data->inflight_buffer = msg.data;
474 ws_data->inflight_bytes = msg.len;
475 mutex_unlock(&ws_data->send_mutex);
476 if (!available)
477 return;
478 int written = lws_write(wsi, msg.data + LWS_PRE, msg.len, LWS_WRITE_BINARY);
479 if (written < 0 || (size_t)written < msg.len) {
480 mutex_lock(&ws_data->state_mutex);
481 ws_data->is_connected = false;
482 ws_data->connection_failed = true;
483 cond_broadcast(&ws_data->state_cond);
484 mutex_unlock(&ws_data->state_mutex);
485 lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_SEND, LWS_TO_KILL_ASYNC);
486 return;
487 }
488 /* Exactly one write per callback. Request a completion callback even if
489 * there is no next message, so the final owner is promptly released. */
490 lws_callback_on_writable(wsi);
491}
bool ringbuffer_read(ringbuffer_t *rb, void *data)
Try to read an element from the ring buffer (non-blocking).
Definition ringbuffer.c:93
websocket_msg_t websocket_recv_msg_t
size_t len
Frame length in bytes.
uint8_t * data
Frame data (allocated, caller must free).
mutex_t send_mutex
Protect send_queue operations only.
mutex_t state_mutex
Protect state changes.
uint8_t * inflight_buffer
Owned until the next writable callback or teardown.
ringbuffer_t * send_queue
Send message queue (for server-side transports).
cond_t state_cond
Signal when is_connected changes (for connection wait).
bool connection_failed
Connection attempt failed (for client-side detection).
size_t pending_send_bytes
Includes the inflight owner until writable completion.
atomic_t is_destroying
True when destruction has started.

References buffer_release, websocket_transport_data_t::connection_failed, websocket_msg_t::data, websocket_transport_data_t::inflight_buffer, websocket_transport_data_t::inflight_bytes, websocket_transport_data_t::is_connected, websocket_transport_data_t::is_destroying, websocket_msg_t::len, websocket_transport_data_t::pending_send_bytes, ringbuffer_read(), websocket_transport_data_t::send_mutex, websocket_transport_data_t::send_queue, websocket_transport_data_t::state_cond, and websocket_transport_data_t::state_mutex.