ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
client.c File Reference

Go to the source code of this file.

Macros

#define MAX_RECONNECT_DELAY   (5 * 1000 * 1000)
 

Functions

tcp_client_ttcp_client_create (void)
 Create and initialize TCP client.
 
void tcp_client_destroy (tcp_client_t **client_ptr)
 Destroy TCP client and free resources.
 
bool tcp_client_is_active (const tcp_client_t *client)
 Check if connection is currently active.
 
bool tcp_client_is_lost (const tcp_client_t *client)
 Check if connection was lost.
 
socket_t tcp_client_get_socket (const tcp_client_t *client)
 Get current socket descriptor.
 
uint32_t tcp_client_get_id (const tcp_client_t *client)
 Get client ID assigned by server.
 
void tcp_client_signal_lost (tcp_client_t *client)
 Signal that connection was lost (triggers reconnection)
 
void tcp_client_close (tcp_client_t *client)
 Close connection gracefully.
 
void tcp_client_shutdown (tcp_client_t *client)
 Shutdown connection forcefully (for signal handlers)
 
void tcp_client_cleanup (tcp_client_t *client)
 Cleanup connection resources.
 
int tcp_client_send_packet (tcp_client_t *client, packet_type_t type, const void *data, size_t len)
 Send packet with thread-safe mutex protection.
 
int tcp_client_send_ping (tcp_client_t *client)
 Send ping packet.
 
int tcp_client_send_pong (tcp_client_t *client)
 Send pong packet.
 
int tcp_client_connect (tcp_client_t *client, const char *address, int port, int reconnect_attempt, bool first_connection, bool has_ever_connected)
 Establish TCP connection to server.
 
int tcp_client_send_audio_opus (tcp_client_t *client, const uint8_t *opus_data, size_t opus_size, int sample_rate, int frame_duration)
 Send Opus-encoded audio frame.
 
int tcp_client_send_audio_opus_batch (tcp_client_t *client, const uint8_t *opus_data, size_t opus_size, const uint16_t *frame_sizes, int frame_count)
 Send Opus audio batch packet.
 
int tcp_client_send_terminal_capabilities (tcp_client_t *client, unsigned short width, unsigned short height)
 Send terminal capabilities packet.
 
int tcp_client_send_join (tcp_client_t *client, const char *display_name, uint32_t capabilities)
 Send client join packet.
 
int tcp_client_send_stream_start (tcp_client_t *client, uint32_t stream_type)
 Send stream start packet.
 
int tcp_client_send_audio_batch (tcp_client_t *client, const float *samples, int num_samples, int batch_count)
 Send audio batch packet.
 

Macro Definition Documentation

◆ MAX_RECONNECT_DELAY

#define MAX_RECONNECT_DELAY   (5 * 1000 * 1000)

Maximum delay between reconnection attempts (microseconds)

Definition at line 56 of file lib/network/tcp/client.c.

Function Documentation

◆ tcp_client_cleanup()

void tcp_client_cleanup ( tcp_client_t client)

Cleanup connection resources.

Parameters
clientTCP client instance

Definition at line 317 of file lib/network/tcp/client.c.

317 {
318 if (!client)
319 return;
320
321 // Close connection
322 tcp_client_close(client);
323
324 // Reset state flags
325 atomic_store(&client->connection_lost, false);
326 atomic_store(&client->should_reconnect, false);
327 memset(client->server_ip, 0, sizeof(client->server_ip));
328}
void tcp_client_close(tcp_client_t *client)
Close connection gracefully.
atomic_bool should_reconnect
atomic_bool connection_lost

References tcp_client::connection_lost, tcp_client::server_ip, tcp_client::should_reconnect, and tcp_client_close().

◆ tcp_client_close()

void tcp_client_close ( tcp_client_t client)

Close connection gracefully.

Parameters
clientTCP client instance

Definition at line 280 of file lib/network/tcp/client.c.

280 {
281 if (!client)
282 return;
283
284 log_debug("Closing client connection");
285
286 // Mark connection as inactive
287 atomic_store(&client->connection_active, false);
288
289 // Close socket
290 if (socket_is_valid(client->sockfd)) {
291 close_socket_safe(client->sockfd);
293 }
294
295 // Reset client ID
296 client->my_client_id = 0;
297}
#define log_debug(...)
Log a DEBUG message.
bool socket_is_valid(socket_t sock)
Check if a socket handle is valid.
#define INVALID_SOCKET_VALUE
Invalid socket value (POSIX: -1)
Definition socket.h:52
atomic_bool connection_active

References tcp_client::connection_active, INVALID_SOCKET_VALUE, log_debug, tcp_client::my_client_id, socket_is_valid(), and tcp_client::sockfd.

Referenced by tcp_client_cleanup().

◆ tcp_client_connect()

int tcp_client_connect ( tcp_client_t client,
const char *  address,
int  port,
int  reconnect_attempt,
bool  first_connection,
bool  has_ever_connected 
)

Establish TCP connection to server.

Performs full connection lifecycle:

  • DNS resolution with IPv4/IPv6 dual-stack support
  • Socket creation and connection with timeout
  • Crypto handshake (if enabled)
  • Initial capability exchange
  • Client ID assignment from local port
Parameters
clientTCP client instance
addressServer hostname or IP address
portServer port number
reconnect_attemptCurrent reconnection attempt (0 for first, 1+ for retries)
first_connectionTrue if this is the very first connection since program start
has_ever_connectedTrue if client has successfully connected at least once
Returns
0 on success, negative on error

Definition at line 411 of file lib/network/tcp/client.c.

412 {
413 (void)first_connection; // Currently unused
414 (void)has_ever_connected; // Currently unused
415
416 if (!client || !address || port <= 0) {
417 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid client, address, or port");
418 }
419
420 // Close any existing connection
421 if (socket_is_valid(client->sockfd)) {
422 close_socket_safe(client->sockfd);
424 }
425
426 // Apply reconnection delay if this is a retry
427 if (reconnect_attempt > 0) {
428 unsigned int delay_us = get_reconnect_delay(reconnect_attempt);
429 platform_sleep_usec(delay_us);
430 }
431
432 // Resolve server address using getaddrinfo() for IPv4/IPv6 support
433 // Special handling for localhost: ensure we try both IPv6 (::1) and IPv4 (127.0.0.1)
434 bool is_localhost =
435 (strcmp(address, "localhost") == 0 || strcmp(address, "127.0.0.1") == 0 || strcmp(address, "::1") == 0);
436
437 struct addrinfo hints, *res = NULL, *addr_iter;
438 memset(&hints, 0, sizeof(hints));
439 hints.ai_family = AF_UNSPEC; // Allow IPv4 or IPv6
440 hints.ai_socktype = SOCK_STREAM;
441 if (is_localhost) {
442 hints.ai_flags = AI_NUMERICSERV; // Optimize for localhost
443 }
444
445 char port_str[16];
446 SAFE_SNPRINTF(port_str, sizeof(port_str), "%d", port);
447
448 // For localhost, try IPv6 loopback (::1) first, then fall back to IPv4
449 if (is_localhost) {
450 log_debug("Localhost detected - trying IPv6 loopback [::1]:%s first...", port_str);
451 hints.ai_family = AF_INET6;
452 hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
453
454 int ipv6_result = getaddrinfo("::1", port_str, &hints, &res);
455 if (ipv6_result == 0 && res != NULL) {
456 // Try IPv6 loopback connection
457 client->sockfd = socket_create(res->ai_family, res->ai_socktype, res->ai_protocol);
458 if (client->sockfd != INVALID_SOCKET_VALUE) {
459 log_info("Trying IPv6 loopback connection to [::1]:%s...", port_str);
460 if (connect_with_timeout(client->sockfd, res->ai_addr, res->ai_addrlen, CONNECT_TIMEOUT)) {
461 log_debug("Connection successful using IPv6 loopback");
462 SAFE_STRNCPY(client->server_ip, "::1", sizeof(client->server_ip));
463 freeaddrinfo(res);
464 res = NULL; // Prevent double-free at connection_success label
465 goto connection_success;
466 }
467 close_socket_safe(client->sockfd);
469 }
470 freeaddrinfo(res);
471 res = NULL;
472 }
473
474 // IPv6 failed, try IPv4 loopback (127.0.0.1)
475 log_debug("IPv6 failed, trying IPv4 loopback 127.0.0.1:%s...", port_str);
476 hints.ai_family = AF_INET;
477
478 int ipv4_result = getaddrinfo("127.0.0.1", port_str, &hints, &res);
479 if (ipv4_result == 0 && res != NULL) {
480 client->sockfd = socket_create(res->ai_family, res->ai_socktype, res->ai_protocol);
481 if (client->sockfd != INVALID_SOCKET_VALUE) {
482 log_info("Trying IPv4 loopback connection to 127.0.0.1:%s...", port_str);
483 if (connect_with_timeout(client->sockfd, res->ai_addr, res->ai_addrlen, CONNECT_TIMEOUT)) {
484 log_debug("Connection successful using IPv4 loopback");
485 SAFE_STRNCPY(client->server_ip, "127.0.0.1", sizeof(client->server_ip));
486 freeaddrinfo(res);
487 res = NULL;
488 goto connection_success;
489 }
490 close_socket_safe(client->sockfd);
492 }
493 freeaddrinfo(res);
494 res = NULL;
495 }
496
497 // Both IPv6 and IPv4 loopback failed for localhost
498 log_warn("Could not connect to localhost using either IPv6 or IPv4 loopback");
499 return -1;
500 }
501
502 // For non-localhost addresses, use standard resolution
503 log_debug("Resolving server address '%s' port %s...", address, port_str);
504 hints.ai_family = AF_UNSPEC;
505 hints.ai_flags = 0;
506 int getaddr_result = getaddrinfo(address, port_str, &hints, &res);
507 if (getaddr_result != 0) {
508 log_error("Failed to resolve server address '%s': %s", address, gai_strerror(getaddr_result));
509 return -1;
510 }
511
512 // Try each address returned by getaddrinfo() - prefer IPv6, fall back to IPv4
513 for (int address_family = AF_INET6; address_family >= AF_INET; address_family -= (AF_INET6 - AF_INET)) {
514 for (addr_iter = res; addr_iter != NULL; addr_iter = addr_iter->ai_next) {
515 if (addr_iter->ai_family != address_family) {
516 continue;
517 }
518
519 client->sockfd = socket_create(addr_iter->ai_family, addr_iter->ai_socktype, addr_iter->ai_protocol);
520 if (client->sockfd == INVALID_SOCKET_VALUE) {
521 continue;
522 }
523
524 if (addr_iter->ai_family == AF_INET) {
525 log_debug("Trying IPv4 connection...");
526 } else if (addr_iter->ai_family == AF_INET6) {
527 log_debug("Trying IPv6 connection...");
528 }
529
530 if (connect_with_timeout(client->sockfd, addr_iter->ai_addr, addr_iter->ai_addrlen, CONNECT_TIMEOUT)) {
531 log_debug("Connection successful using %s", addr_iter->ai_family == AF_INET ? "IPv4"
532 : addr_iter->ai_family == AF_INET6 ? "IPv6"
533 : "unknown protocol");
534
535 // Extract server IP address for known_hosts
536 if (format_ip_address(addr_iter->ai_family, addr_iter->ai_addr, client->server_ip, sizeof(client->server_ip)) ==
537 ASCIICHAT_OK) {
538 log_debug("Resolved server IP: %s", client->server_ip);
539 } else {
540 log_warn("Failed to format server IP address");
541 }
542
543 goto connection_success;
544 }
545
546 close_socket_safe(client->sockfd);
548 }
549 }
550
551connection_success:
552
553 if (res) {
554 freeaddrinfo(res);
555 }
556
557 // If we exhausted all addresses without success, fail
558 if (client->sockfd == INVALID_SOCKET_VALUE) {
559 log_warn("Could not connect to server %s:%d (tried all addresses)", address, port);
560 return -1;
561 }
562
563 // Extract local port for client ID
564 struct sockaddr_storage local_addr = {0};
565 socklen_t addr_len = sizeof(local_addr);
566 if (getsockname(client->sockfd, (struct sockaddr *)&local_addr, &addr_len) == -1) {
567 log_error("Failed to get local socket address: %s", network_error_string());
568 close_socket_safe(client->sockfd);
570 return -1;
571 }
572
573 // Extract port from either IPv4 or IPv6 address
574 int local_port = 0;
575 if (((struct sockaddr *)&local_addr)->sa_family == AF_INET) {
576 local_port = NET_TO_HOST_U16(((struct sockaddr_in *)&local_addr)->sin_port);
577 } else if (((struct sockaddr *)&local_addr)->sa_family == AF_INET6) {
578 local_port = NET_TO_HOST_U16(((struct sockaddr_in6 *)&local_addr)->sin6_port);
579 }
580 client->my_client_id = (uint32_t)local_port;
581
582 // Mark connection as active
583 atomic_store(&client->connection_active, true);
584 atomic_store(&client->connection_lost, false);
585 atomic_store(&client->should_reconnect, false);
586
587 // Initialize crypto (application must set crypto_initialized flag)
588 // This is done outside this function by calling client_crypto_init()
589
590 // Configure socket options
591 if (socket_set_keepalive(client->sockfd, true) < 0) {
592 log_warn("Failed to set socket keepalive: %s", network_error_string());
593 }
594
595 asciichat_error_t sock_config_result = socket_configure_buffers(client->sockfd);
596 if (sock_config_result != ASCIICHAT_OK) {
597 log_warn("Failed to configure socket: %s", network_error_string());
598 }
599
600 log_debug("Connection established successfully to %s:%d (client_id=%u)", address, port, client->my_client_id);
601 return 0;
602}
#define NET_TO_HOST_U16(val)
Definition endian.h:116
unsigned int uint32_t
Definition common.h:58
#define SAFE_STRNCPY(dst, src, size)
Definition common.h:358
#define SAFE_SNPRINTF(buffer, buffer_size,...)
Definition common.h:412
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:46
@ ASCIICHAT_OK
Definition error_codes.h:48
@ ERROR_INVALID_PARAM
#define log_warn(...)
Log a WARN message.
#define log_error(...)
Log an ERROR message.
#define log_info(...)
Log an INFO message.
#define CONNECT_TIMEOUT
Connection timeout in seconds (3 seconds)
Definition network.h:98
bool connect_with_timeout(socket_t sockfd, const struct sockaddr *addr, socklen_t addrlen, int timeout_seconds)
Connect with timeout.
Definition network.c:547
const char * network_error_string()
Get human-readable error string for network errors.
Definition network.c:535
asciichat_error_t socket_configure_buffers(socket_t sockfd)
Configure socket buffers and TCP_NODELAY for optimal performance.
Definition network.c:493
int socket_set_keepalive(socket_t sock, bool keepalive)
Set SO_KEEPALIVE socket option.
void platform_sleep_usec(unsigned int usec)
High-precision sleep function with microsecond precision.
socket_t socket_create(int domain, int type, int protocol)
Create a new socket.
asciichat_error_t format_ip_address(int family, const struct sockaddr *addr, char *output, size_t output_size)
Format IP address from socket address structure.
Definition ip.c:205

References ASCIICHAT_OK, CONNECT_TIMEOUT, connect_with_timeout(), tcp_client::connection_active, tcp_client::connection_lost, ERROR_INVALID_PARAM, format_ip_address(), INVALID_SOCKET_VALUE, log_debug, log_error, log_info, log_warn, tcp_client::my_client_id, NET_TO_HOST_U16, network_error_string(), platform_sleep_usec(), SAFE_SNPRINTF, SAFE_STRNCPY, tcp_client::server_ip, SET_ERRNO, tcp_client::should_reconnect, socket_configure_buffers(), socket_create(), socket_is_valid(), socket_set_keepalive(), and tcp_client::sockfd.

◆ tcp_client_create()

tcp_client_t * tcp_client_create ( void  )

Create and initialize TCP client.

Create and initialize a TCP client instance.

Allocates tcp_client_t and initializes all fields to safe defaults.

Definition at line 95 of file lib/network/tcp/client.c.

95 {
97 if (!client) {
98 log_error("Failed to allocate tcp_client_t");
99 return NULL;
100 }
101
102 // Zero-initialize all fields
103 memset(client, 0, sizeof(*client));
104
105 /* Connection State */
107 atomic_store(&client->connection_active, false);
108 atomic_store(&client->connection_lost, false);
109 atomic_store(&client->should_reconnect, false);
110 client->my_client_id = 0;
111 memset(client->server_ip, 0, sizeof(client->server_ip));
112 client->encryption_enabled = false;
113
114 // Initialize send mutex
115 if (mutex_init(&client->send_mutex) != 0) {
116 log_error("Failed to initialize send mutex");
117 SAFE_FREE(client);
118 return NULL;
119 }
120
121 /* Audio State */
122 memset(&client->audio_ctx, 0, sizeof(client->audio_ctx));
123 memset(client->audio_send_queue, 0, sizeof(client->audio_send_queue));
124 client->audio_send_queue_head = 0;
125 client->audio_send_queue_tail = 0;
126 client->audio_send_queue_initialized = false;
127 atomic_store(&client->audio_sender_should_exit, false);
128
129 // Initialize audio queue mutex and condition variable
130 if (mutex_init(&client->audio_send_queue_mutex) != 0) {
131 log_error("Failed to initialize audio queue mutex");
132 mutex_destroy(&client->send_mutex);
133 SAFE_FREE(client);
134 return NULL;
135 }
136
137 if (cond_init(&client->audio_send_queue_cond) != 0) {
138 log_error("Failed to initialize audio queue cond");
140 mutex_destroy(&client->send_mutex);
141 SAFE_FREE(client);
142 return NULL;
143 }
144
145 client->audio_capture_thread_created = false;
146 client->audio_sender_thread_created = false;
147 atomic_store(&client->audio_capture_thread_exited, false);
148
149 /* Protocol State */
150 client->data_thread_created = false;
151 atomic_store(&client->data_thread_exited, false);
152 client->last_active_count = 0;
153 client->server_state_initialized = false;
154 client->should_clear_before_next_frame = false;
155
156 /* Capture State */
157 client->capture_thread_created = false;
158 atomic_store(&client->capture_thread_exited, false);
159
160 /* Keepalive State */
161 client->ping_thread_created = false;
162 atomic_store(&client->ping_thread_exited, false);
163
164 /* Display State */
165 client->has_tty = false;
166 atomic_store(&client->is_first_frame_of_connection, true);
167 memset(&client->tty_info, 0, sizeof(client->tty_info));
168
169 /* Crypto State */
170 memset(&client->crypto_ctx, 0, sizeof(client->crypto_ctx));
171 client->crypto_initialized = false;
172
173 log_debug("TCP client created successfully");
174 return client;
175}
#define SAFE_FREE(ptr)
Definition common.h:320
#define SAFE_MALLOC(size, cast)
Definition common.h:208
int mutex_init(mutex_t *mutex)
Initialize a mutex.
int cond_init(cond_t *cond)
Initialize a condition variable.
int mutex_destroy(mutex_t *mutex)
Destroy a mutex.
TCP client connection and state management.
crypto_handshake_context_t crypto_ctx
atomic_bool ping_thread_exited
atomic_bool audio_capture_thread_exited
atomic_bool audio_sender_should_exit
audio_context_t audio_ctx
atomic_bool capture_thread_exited
tcp_client_audio_packet_t audio_send_queue[256]
atomic_bool is_first_frame_of_connection
atomic_bool data_thread_exited

References tcp_client::audio_capture_thread_created, tcp_client::audio_capture_thread_exited, tcp_client::audio_ctx, tcp_client::audio_send_queue, tcp_client::audio_send_queue_cond, tcp_client::audio_send_queue_head, tcp_client::audio_send_queue_initialized, tcp_client::audio_send_queue_mutex, tcp_client::audio_send_queue_tail, tcp_client::audio_sender_should_exit, tcp_client::audio_sender_thread_created, tcp_client::capture_thread_created, tcp_client::capture_thread_exited, cond_init(), tcp_client::connection_active, tcp_client::connection_lost, tcp_client::crypto_ctx, tcp_client::crypto_initialized, tcp_client::data_thread_created, tcp_client::data_thread_exited, tcp_client::encryption_enabled, tcp_client::has_tty, INVALID_SOCKET_VALUE, tcp_client::is_first_frame_of_connection, tcp_client::last_active_count, log_debug, log_error, mutex_destroy(), mutex_init(), tcp_client::my_client_id, tcp_client::ping_thread_created, tcp_client::ping_thread_exited, SAFE_FREE, SAFE_MALLOC, tcp_client::send_mutex, tcp_client::server_ip, tcp_client::server_state_initialized, tcp_client::should_clear_before_next_frame, tcp_client::should_reconnect, tcp_client::sockfd, and tcp_client::tty_info.

◆ tcp_client_destroy()

void tcp_client_destroy ( tcp_client_t **  client_ptr)

Destroy TCP client and free resources.

Destroy TCP client and free all resources.

Must be called AFTER all threads have been joined.

Definition at line 182 of file lib/network/tcp/client.c.

182 {
183 if (!client_ptr || !*client_ptr) {
184 return;
185 }
186
187 tcp_client_t *client = *client_ptr;
188
189#ifndef NDEBUG
190 // Debug: verify all threads have exited
191 if (client->audio_capture_thread_created && !atomic_load(&client->audio_capture_thread_exited)) {
192 log_warn("Destroying client while audio capture thread may still be running");
193 }
194 if (client->data_thread_created && !atomic_load(&client->data_thread_exited)) {
195 log_warn("Destroying client while data thread may still be running");
196 }
197 if (client->capture_thread_created && !atomic_load(&client->capture_thread_exited)) {
198 log_warn("Destroying client while capture thread may still be running");
199 }
200 if (client->ping_thread_created && !atomic_load(&client->ping_thread_exited)) {
201 log_warn("Destroying client while ping thread may still be running");
202 }
203#endif
204
205 // Close socket if still open
206 if (socket_is_valid(client->sockfd)) {
207 close_socket_safe(client->sockfd);
209 }
210
211 // Destroy synchronization primitives
212 mutex_destroy(&client->send_mutex);
215
216 // Free client structure
217 SAFE_FREE(client);
218 *client_ptr = NULL;
219
220 log_debug("TCP client destroyed");
221}
int cond_destroy(cond_t *cond)
Destroy a condition variable.

References tcp_client::audio_capture_thread_created, tcp_client::audio_capture_thread_exited, tcp_client::audio_send_queue_cond, tcp_client::audio_send_queue_mutex, tcp_client::capture_thread_created, tcp_client::capture_thread_exited, cond_destroy(), tcp_client::data_thread_created, tcp_client::data_thread_exited, INVALID_SOCKET_VALUE, log_debug, log_warn, mutex_destroy(), tcp_client::ping_thread_created, tcp_client::ping_thread_exited, SAFE_FREE, tcp_client::send_mutex, socket_is_valid(), and tcp_client::sockfd.

Referenced by connection_context_cleanup().

◆ tcp_client_get_id()

uint32_t tcp_client_get_id ( const tcp_client_t client)

Get client ID assigned by server.

Parameters
clientTCP client instance
Returns
Client ID (from local port) or 0 if not connected

Definition at line 255 of file lib/network/tcp/client.c.

255 {
256 return client ? client->my_client_id : 0;
257}

References tcp_client::my_client_id.

◆ tcp_client_get_socket()

socket_t tcp_client_get_socket ( const tcp_client_t client)

Get current socket descriptor.

Parameters
clientTCP client instance
Returns
Socket descriptor or INVALID_SOCKET_VALUE if not connected

Definition at line 248 of file lib/network/tcp/client.c.

248 {
249 return client ? client->sockfd : INVALID_SOCKET_VALUE;
250}

References INVALID_SOCKET_VALUE, and tcp_client::sockfd.

◆ tcp_client_is_active()

bool tcp_client_is_active ( const tcp_client_t client)

Check if connection is currently active.

Parameters
clientTCP client instance
Returns
true if connection is active, false otherwise

Definition at line 230 of file lib/network/tcp/client.c.

230 {
231 if (!client)
232 return false;
233 return atomic_load(&client->connection_active);
234}

References tcp_client::connection_active.

◆ tcp_client_is_lost()

bool tcp_client_is_lost ( const tcp_client_t client)

Check if connection was lost.

Parameters
clientTCP client instance
Returns
true if connection loss was detected, false otherwise

Definition at line 239 of file lib/network/tcp/client.c.

239 {
240 if (!client)
241 return false;
242 return atomic_load(&client->connection_lost);
243}

References tcp_client::connection_lost.

◆ tcp_client_send_audio_batch()

int tcp_client_send_audio_batch ( tcp_client_t client,
const float *  samples,
int  num_samples,
int  batch_count 
)

Send audio batch packet.

Parameters
clientTCP client instance
samplesAudio sample buffer
num_samplesNumber of samples in buffer
batch_countNumber of chunks in batch
Returns
0 on success, negative on error

Definition at line 878 of file lib/network/tcp/client.c.

878 {
879 if (!client || !samples) {
880 return SET_ERRNO(ERROR_INVALID_PARAM, "NULL client or samples");
881 }
882
883 if (!atomic_load(&client->connection_active)) {
884 return SET_ERRNO(ERROR_NETWORK, "Connection not active");
885 }
886
887 mutex_lock(&client->send_mutex);
888
889 if (!atomic_load(&client->connection_active) || client->sockfd == INVALID_SOCKET_VALUE) {
890 mutex_unlock(&client->send_mutex);
891 return -1;
892 }
893
894 crypto_context_t *crypto_ctx = NULL;
896 crypto_ctx = crypto_handshake_get_context(&client->crypto_ctx);
897 }
898
899 int result = send_audio_batch_packet(client->sockfd, samples, num_samples, batch_count, crypto_ctx);
900
901 mutex_unlock(&client->send_mutex);
902
903 if (result < 0) {
905 }
906
907 return result;
908}
const crypto_context_t * crypto_handshake_get_context(const crypto_handshake_context_t *ctx)
Get the crypto context for encryption/decryption.
bool crypto_handshake_is_ready(const crypto_handshake_context_t *ctx)
Check if handshake is complete and encryption is ready.
@ ERROR_NETWORK
Definition error_codes.h:69
asciichat_error_t send_audio_batch_packet(socket_t sockfd, const float *samples, int num_samples, int batch_count, crypto_context_t *crypto_ctx)
Send a batched audio packet with encryption support.
Definition packet.c:1072
#define mutex_lock(mutex)
Lock a mutex (with debug tracking in debug builds)
Definition mutex.h:140
#define mutex_unlock(mutex)
Unlock a mutex (with debug tracking in debug builds)
Definition mutex.h:175
void tcp_client_signal_lost(tcp_client_t *client)
Signal that connection was lost (triggers reconnection)
Cryptographic context structure.

References tcp_client::connection_active, tcp_client::crypto_ctx, crypto_handshake_get_context(), crypto_handshake_is_ready(), tcp_client::crypto_initialized, ERROR_INVALID_PARAM, ERROR_NETWORK, INVALID_SOCKET_VALUE, mutex_lock, mutex_unlock, send_audio_batch_packet(), tcp_client::send_mutex, SET_ERRNO, tcp_client::sockfd, and tcp_client_signal_lost().

◆ tcp_client_send_audio_opus()

int tcp_client_send_audio_opus ( tcp_client_t client,
const uint8_t opus_data,
size_t  opus_size,
int  sample_rate,
int  frame_duration 
)

Send Opus-encoded audio frame.

Parameters
clientTCP client instance
opus_dataOpus-encoded audio data
opus_sizeSize of encoded frame
sample_rateSample rate in Hz
frame_durationFrame duration in milliseconds
Returns
0 on success, negative on error

Definition at line 618 of file lib/network/tcp/client.c.

619 {
620 if (!client || !opus_data) {
621 return SET_ERRNO(ERROR_INVALID_PARAM, "NULL client or opus_data");
622 }
623
624 if (!atomic_load(&client->connection_active)) {
625 return SET_ERRNO(ERROR_NETWORK, "Connection not active");
626 }
627
628 mutex_lock(&client->send_mutex);
629
630 // Recheck connection status inside mutex to prevent TOCTOU race
631 if (!atomic_load(&client->connection_active) || client->sockfd == INVALID_SOCKET_VALUE) {
632 mutex_unlock(&client->send_mutex);
633 return SET_ERRNO(ERROR_NETWORK, "Connection not active");
634 }
635
636 // Get crypto context if encryption is enabled
637 crypto_context_t *crypto_ctx = NULL;
639 crypto_ctx = crypto_handshake_get_context(&client->crypto_ctx);
640 }
641
642 // Build Opus packet with header
643 size_t header_size = 16; // sample_rate (4), frame_duration (4), reserved (8)
644 size_t total_size = header_size + opus_size;
645 void *packet_data = buffer_pool_alloc(NULL, total_size);
646 if (!packet_data) {
647 mutex_unlock(&client->send_mutex);
648 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for Opus packet: %zu bytes", total_size);
649 }
650
651 // Write header in network byte order
652 uint8_t *buf = (uint8_t *)packet_data;
653 uint32_t sr = HOST_TO_NET_U32((uint32_t)sample_rate);
654 uint32_t fd = HOST_TO_NET_U32((uint32_t)frame_duration);
655 memcpy(buf, &sr, 4);
656 memcpy(buf + 4, &fd, 4);
657 memset(buf + 8, 0, 8); // Reserved
658
659 // Copy Opus data
660 memcpy(buf + header_size, opus_data, opus_size);
661
662 // Send packet with encryption if available
663 asciichat_error_t result;
664 if (crypto_ctx) {
665 result = send_packet_secure(client->sockfd, PACKET_TYPE_AUDIO_OPUS, packet_data, total_size, crypto_ctx);
666 } else {
667 result = packet_send(client->sockfd, PACKET_TYPE_AUDIO_OPUS, packet_data, total_size);
668 }
669
670 buffer_pool_free(NULL, packet_data, total_size);
671 mutex_unlock(&client->send_mutex);
672
673 if (result != ASCIICHAT_OK) {
675 }
676
677 return result;
678}
#define HOST_TO_NET_U32(val)
Definition endian.h:71
void buffer_pool_free(buffer_pool_t *pool, void *data, size_t size)
Free a buffer back to the pool (lock-free)
void * buffer_pool_alloc(buffer_pool_t *pool, size_t size)
Allocate a buffer from the pool (lock-free fast path)
unsigned char uint8_t
Definition common.h:56
@ ERROR_MEMORY
Definition error_codes.h:53
asciichat_error_t send_packet_secure(socket_t sockfd, packet_type_t type, const void *data, size_t len, crypto_context_t *crypto_ctx)
Send a packet with encryption and compression support.
Definition packet.c:433
asciichat_error_t packet_send(socket_t sockfd, packet_type_t type, const void *data, size_t len)
Send a packet with proper header and CRC32.
Definition packet.c:291
@ PACKET_TYPE_AUDIO_OPUS
Opus-encoded single audio frame.
Definition packet.h:357

References ASCIICHAT_OK, buffer_pool_alloc(), buffer_pool_free(), tcp_client::connection_active, tcp_client::crypto_ctx, crypto_handshake_get_context(), crypto_handshake_is_ready(), tcp_client::crypto_initialized, ERROR_INVALID_PARAM, ERROR_MEMORY, ERROR_NETWORK, HOST_TO_NET_U32, INVALID_SOCKET_VALUE, mutex_lock, mutex_unlock, packet_send(), PACKET_TYPE_AUDIO_OPUS, tcp_client::send_mutex, send_packet_secure(), SET_ERRNO, tcp_client::sockfd, and tcp_client_signal_lost().

◆ tcp_client_send_audio_opus_batch()

int tcp_client_send_audio_opus_batch ( tcp_client_t client,
const uint8_t opus_data,
size_t  opus_size,
const uint16_t frame_sizes,
int  frame_count 
)

Send Opus audio batch packet.

Parameters
clientTCP client instance
opus_dataOpus-encoded audio data (multiple frames)
opus_sizeTotal size of Opus data
frame_sizesArray of individual frame sizes
frame_countNumber of frames in batch
Returns
0 on success, negative on error

Definition at line 690 of file lib/network/tcp/client.c.

691 {
692 if (!client || !opus_data || !frame_sizes) {
693 return SET_ERRNO(ERROR_INVALID_PARAM, "NULL client, opus_data, or frame_sizes");
694 }
695
696 if (!atomic_load(&client->connection_active)) {
697 return SET_ERRNO(ERROR_NETWORK, "Connection not active");
698 }
699
700 mutex_lock(&client->send_mutex);
701
702 if (!atomic_load(&client->connection_active) || client->sockfd == INVALID_SOCKET_VALUE) {
703 mutex_unlock(&client->send_mutex);
704 return -1;
705 }
706
707 crypto_context_t *crypto_ctx = NULL;
709 crypto_ctx = crypto_handshake_get_context(&client->crypto_ctx);
710 }
711
712 // Opus uses 20ms frames at 48kHz
713 int result =
714 av_send_audio_opus_batch(client->sockfd, opus_data, opus_size, frame_sizes, 48000, 20, frame_count, crypto_ctx);
715
716 mutex_unlock(&client->send_mutex);
717
718 if (result < 0) {
720 }
721
722 return result;
723}
asciichat_error_t av_send_audio_opus_batch(socket_t sockfd, const uint8_t *opus_data, size_t opus_size, const uint16_t *frame_sizes, int sample_rate, int frame_duration, int frame_count, crypto_context_t *crypto_ctx)
Send Opus-encoded audio batch packet with encryption support.
Definition packet.c:1136

References av_send_audio_opus_batch(), tcp_client::connection_active, tcp_client::crypto_ctx, crypto_handshake_get_context(), crypto_handshake_is_ready(), tcp_client::crypto_initialized, ERROR_INVALID_PARAM, ERROR_NETWORK, INVALID_SOCKET_VALUE, mutex_lock, mutex_unlock, tcp_client::send_mutex, SET_ERRNO, tcp_client::sockfd, and tcp_client_signal_lost().

◆ tcp_client_send_join()

int tcp_client_send_join ( tcp_client_t client,
const char *  display_name,
uint32_t  capabilities 
)

Send client join packet.

Parameters
clientTCP client instance
display_nameClient display name
capabilitiesClient capability flags
Returns
0 on success, negative on error

Definition at line 814 of file lib/network/tcp/client.c.

814 {
815 if (!client) {
816 return SET_ERRNO(ERROR_INVALID_PARAM, "NULL client");
817 }
818
819 if (!atomic_load(&client->connection_active) || client->sockfd == INVALID_SOCKET_VALUE) {
820 return -1;
821 }
822
823 // Build CLIENT_JOIN packet
824 client_info_packet_t join_packet;
825 SAFE_MEMSET(&join_packet, sizeof(join_packet), 0, sizeof(join_packet));
826 join_packet.client_id = HOST_TO_NET_U32(0); // Will be assigned by server
827 SAFE_SNPRINTF(join_packet.display_name, MAX_DISPLAY_NAME_LEN, "%s", display_name ? display_name : "Unknown");
828 join_packet.capabilities = HOST_TO_NET_U32(capabilities);
829
830 int send_result = tcp_client_send_packet(client, PACKET_TYPE_CLIENT_JOIN, &join_packet, sizeof(join_packet));
831 if (send_result == 0) {
832 mutex_lock(&client->send_mutex);
833 bool active = atomic_load(&client->connection_active);
834 socket_t socket_snapshot = client->sockfd;
835 crypto_context_t *crypto_ctx = NULL;
837 crypto_ctx = crypto_handshake_get_context(&client->crypto_ctx);
838 }
839 if (active && socket_snapshot != INVALID_SOCKET_VALUE) {
841 socket_snapshot, (const struct crypto_context_t *)crypto_ctx, LOG_INFO, REMOTE_LOG_DIRECTION_CLIENT_TO_SERVER,
842 "CLIENT_JOIN sent (display=\"%s\", capabilities=0x%x)", join_packet.display_name, capabilities);
843 }
844 mutex_unlock(&client->send_mutex);
845 }
846 return send_result;
847}
#define SAFE_MEMSET(dest, dest_size, ch, count)
Definition common.h:389
#define MAX_DISPLAY_NAME_LEN
Maximum display name length in characters.
Definition limits.h:20
asciichat_error_t log_network_message(socket_t sockfd, const struct crypto_context_t *crypto_ctx, log_level_t level, remote_log_direction_t direction, const char *fmt,...)
Send a formatted log message over the network.
@ REMOTE_LOG_DIRECTION_CLIENT_TO_SERVER
@ LOG_INFO
Definition log/logging.h:62
char display_name[MAX_DISPLAY_NAME_LEN]
User display name (null-terminated, max MAX_DISPLAY_NAME_LEN bytes)
Definition packet.h:549
uint32_t client_id
Unique client identifier (1-9, 0 = server)
Definition packet.h:547
uint32_t capabilities
Client capabilities bitmask (CLIENT_CAP_VIDEO | CLIENT_CAP_AUDIO | CLIENT_CAP_COLOR | CLIENT_CAP_STRE...
Definition packet.h:552
@ PACKET_TYPE_CLIENT_JOIN
Client announces capability to send media.
Definition packet.h:300
int socket_t
Socket handle type (POSIX: int)
Definition socket.h:50
int tcp_client_send_packet(tcp_client_t *client, packet_type_t type, const void *data, size_t len)
Send packet with thread-safe mutex protection.
Client information packet structure.
Definition packet.h:545

References client_info_packet_t::capabilities, client_info_packet_t::client_id, tcp_client::connection_active, tcp_client::crypto_ctx, crypto_handshake_get_context(), crypto_handshake_is_ready(), tcp_client::crypto_initialized, client_info_packet_t::display_name, ERROR_INVALID_PARAM, HOST_TO_NET_U32, INVALID_SOCKET_VALUE, LOG_INFO, log_network_message(), MAX_DISPLAY_NAME_LEN, mutex_lock, mutex_unlock, PACKET_TYPE_CLIENT_JOIN, REMOTE_LOG_DIRECTION_CLIENT_TO_SERVER, SAFE_MEMSET, SAFE_SNPRINTF, tcp_client::send_mutex, SET_ERRNO, tcp_client::sockfd, and tcp_client_send_packet().

◆ tcp_client_send_packet()

int tcp_client_send_packet ( tcp_client_t client,
packet_type_t  type,
const void *  data,
size_t  len 
)

Send packet with thread-safe mutex protection.

All packet transmission goes through this function to ensure packets aren't interleaved on the wire.

Definition at line 340 of file lib/network/tcp/client.c.

340 {
341 if (!client) {
342 return SET_ERRNO(ERROR_INVALID_PARAM, "NULL client");
343 }
344
345 if (!atomic_load(&client->connection_active)) {
346 return SET_ERRNO(ERROR_NETWORK, "Connection not active");
347 }
348
349 // Acquire send mutex for thread-safe transmission
350 mutex_lock(&client->send_mutex);
351
352 // Determine if encryption should be used
353 crypto_context_t *crypto_ctx = NULL;
355 crypto_ctx = crypto_handshake_get_context(&client->crypto_ctx);
356 }
357
358 // Send packet (encrypted if crypto context available)
359 asciichat_error_t result = send_packet_secure(client->sockfd, type, data, len, crypto_ctx);
360
361 mutex_unlock(&client->send_mutex);
362
363 if (result != ASCIICHAT_OK) {
364 log_debug("Failed to send packet type %d: %s", type, asciichat_error_string(result));
365 return -1;
366 }
367
368 return 0;
369}

References ASCIICHAT_OK, tcp_client::connection_active, tcp_client::crypto_ctx, crypto_handshake_get_context(), crypto_handshake_is_ready(), tcp_client::crypto_initialized, ERROR_INVALID_PARAM, ERROR_NETWORK, log_debug, mutex_lock, mutex_unlock, tcp_client::send_mutex, send_packet_secure(), SET_ERRNO, and tcp_client::sockfd.

Referenced by tcp_client_send_join(), tcp_client_send_ping(), tcp_client_send_pong(), tcp_client_send_stream_start(), and tcp_client_send_terminal_capabilities().

◆ tcp_client_send_ping()

int tcp_client_send_ping ( tcp_client_t client)

Send ping packet.

Parameters
clientTCP client instance
Returns
0 on success, negative on error

Definition at line 374 of file lib/network/tcp/client.c.

374 {
375 if (!client)
376 return -1;
377 return tcp_client_send_packet(client, PACKET_TYPE_PING, NULL, 0);
378}
@ PACKET_TYPE_PING
Keepalive ping packet.
Definition packet.h:295

References PACKET_TYPE_PING, and tcp_client_send_packet().

◆ tcp_client_send_pong()

int tcp_client_send_pong ( tcp_client_t client)

Send pong packet.

Parameters
clientTCP client instance
Returns
0 on success, negative on error

Definition at line 383 of file lib/network/tcp/client.c.

383 {
384 if (!client)
385 return -1;
386 return tcp_client_send_packet(client, PACKET_TYPE_PONG, NULL, 0);
387}
@ PACKET_TYPE_PONG
Keepalive pong response.
Definition packet.h:297

References PACKET_TYPE_PONG, and tcp_client_send_packet().

◆ tcp_client_send_stream_start()

int tcp_client_send_stream_start ( tcp_client_t client,
uint32_t  stream_type 
)

Send stream start packet.

Parameters
clientTCP client instance
stream_typeType of stream (audio/video)
Returns
0 on success, negative on error

Definition at line 856 of file lib/network/tcp/client.c.

856 {
857 if (!client) {
858 return SET_ERRNO(ERROR_INVALID_PARAM, "NULL client");
859 }
860
861 if (!atomic_load(&client->connection_active) || client->sockfd == INVALID_SOCKET_VALUE) {
862 return -1;
863 }
864
865 uint32_t type_data = HOST_TO_NET_U32(stream_type);
866 return tcp_client_send_packet(client, PACKET_TYPE_STREAM_START, &type_data, sizeof(type_data));
867}
@ PACKET_TYPE_STREAM_START
Client requests to start sending video/audio.
Definition packet.h:304

References tcp_client::connection_active, ERROR_INVALID_PARAM, HOST_TO_NET_U32, INVALID_SOCKET_VALUE, PACKET_TYPE_STREAM_START, SET_ERRNO, tcp_client::sockfd, and tcp_client_send_packet().

◆ tcp_client_send_terminal_capabilities()

int tcp_client_send_terminal_capabilities ( tcp_client_t client,
unsigned short  width,
unsigned short  height 
)

Send terminal capabilities packet.

Parameters
clientTCP client instance
widthTerminal width in characters
heightTerminal height in characters
Returns
0 on success, negative on error

Definition at line 733 of file lib/network/tcp/client.c.

733 {
734 if (!client) {
735 return SET_ERRNO(ERROR_INVALID_PARAM, "NULL client");
736 }
737
738 if (!atomic_load(&client->connection_active) || client->sockfd == INVALID_SOCKET_VALUE) {
739 return -1;
740 }
741
742 // Detect terminal capabilities automatically
744
745 // Apply user's color mode override
746 caps = apply_color_mode_override(caps);
747
748 // Check if detection was reliable, use fallback only for auto-detection
749 if (!caps.detection_reliable && (int)GET_OPTION(color_mode) == COLOR_MODE_AUTO) {
750 log_warn("Terminal capability detection not reliable, using fallback");
751 SAFE_MEMSET(&caps, sizeof(caps), 0, sizeof(caps));
753 caps.color_count = 2;
754 caps.capabilities = 0;
755 SAFE_STRNCPY(caps.term_type, "unknown", sizeof(caps.term_type));
756 SAFE_STRNCPY(caps.colorterm, "", sizeof(caps.colorterm));
757 caps.detection_reliable = 0;
758 }
759
760 // Convert to network packet format
762 net_packet.capabilities = HOST_TO_NET_U32(caps.capabilities);
763 net_packet.color_level = HOST_TO_NET_U32(caps.color_level);
764 net_packet.color_count = HOST_TO_NET_U32(caps.color_count);
765 net_packet.render_mode = HOST_TO_NET_U32(caps.render_mode);
766 net_packet.width = HOST_TO_NET_U16(width);
767 net_packet.height = HOST_TO_NET_U16(height);
768 net_packet.palette_type = HOST_TO_NET_U32(GET_OPTION(palette_type));
769 net_packet.utf8_support = HOST_TO_NET_U32(caps.utf8_support ? 1 : 0);
770
771 const options_t *opts = options_get();
772 if (GET_OPTION(palette_type) == PALETTE_CUSTOM && GET_OPTION(palette_custom_set)) {
773 const char *palette_custom = opts && opts->palette_custom_set ? opts->palette_custom : "";
774 SAFE_STRNCPY(net_packet.palette_custom, palette_custom, sizeof(net_packet.palette_custom));
775 net_packet.palette_custom[sizeof(net_packet.palette_custom) - 1] = '\0';
776 } else {
777 SAFE_MEMSET(net_packet.palette_custom, sizeof(net_packet.palette_custom), 0, sizeof(net_packet.palette_custom));
778 }
779
780 // Set desired FPS (from global g_max_fps if available, otherwise from caps)
781 extern int g_max_fps; // Will be passed via options in future refactoring
782 if (g_max_fps > 0) {
783 net_packet.desired_fps = (uint8_t)(g_max_fps > 144 ? 144 : g_max_fps);
784 } else {
785 net_packet.desired_fps = caps.desired_fps;
786 }
787
788 if (net_packet.desired_fps == 0) {
789 net_packet.desired_fps = DEFAULT_MAX_FPS;
790 }
791
792 SAFE_STRNCPY(net_packet.term_type, caps.term_type, sizeof(net_packet.term_type));
793 net_packet.term_type[sizeof(net_packet.term_type) - 1] = '\0';
794
795 SAFE_STRNCPY(net_packet.colorterm, caps.colorterm, sizeof(net_packet.colorterm));
796 net_packet.colorterm[sizeof(net_packet.colorterm) - 1] = '\0';
797
798 net_packet.detection_reliable = caps.detection_reliable;
799 net_packet.utf8_support = GET_OPTION(force_utf8) ? 1 : 0;
800
801 SAFE_MEMSET(net_packet.reserved, sizeof(net_packet.reserved), 0, sizeof(net_packet.reserved));
802
803 return tcp_client_send_packet(client, PACKET_TYPE_CLIENT_CAPABILITIES, &net_packet, sizeof(net_packet));
804}
#define HOST_TO_NET_U16(val)
Definition endian.h:101
#define DEFAULT_MAX_FPS
Default maximum frame rate (frames per second)
Definition limits.h:26
int g_max_fps
Runtime configurable maximum frame rate (can be overridden via environment or command line)
Definition common.c:30
uint32_t capabilities
Terminal capabilities bitmask (TERM_CAP_* flags)
Definition packet.h:911
uint32_t color_level
Color level enum value (terminal_color_mode_t)
Definition packet.h:913
uint32_t color_count
Actual color count (16, 256, or 16777216)
Definition packet.h:915
uint16_t height
Terminal height in characters.
Definition packet.h:921
uint8_t reserved[2]
Reserved bytes for alignment (must be zero)
Definition packet.h:937
uint32_t render_mode
Render mode enum value (foreground/background/half-block)
Definition packet.h:917
uint16_t width
Terminal width in characters.
Definition packet.h:919
uint8_t desired_fps
Client's desired frame rate (1-144 FPS)
Definition packet.h:935
uint8_t detection_reliable
Detection reliability flag (1=reliable detection, 0=best guess)
Definition packet.h:927
char palette_custom[64]
Custom palette characters (if palette_type == PALETTE_CUSTOM)
Definition packet.h:933
char colorterm[32]
$COLORTERM environment variable value (for debugging)
Definition packet.h:925
uint32_t palette_type
Palette type enum value (palette_type_t)
Definition packet.h:931
uint32_t utf8_support
UTF-8 support flag (0=no UTF-8, 1=UTF-8 supported)
Definition packet.h:929
char term_type[32]
$TERM environment variable value (for debugging)
Definition packet.h:923
#define GET_OPTION(field)
Safely get a specific option field (lock-free read)
Definition options.h:644
#define COLOR_MODE_AUTO
Backward compatibility aliases for color mode enum values.
Definition options.h:156
const options_t * options_get(void)
Get current options (lock-free read)
Definition rcu.c:222
@ PACKET_TYPE_CLIENT_CAPABILITIES
Client reports terminal capabilities.
Definition packet.h:293
@ PALETTE_CUSTOM
User-defined via –palette-chars.
Definition palette.h:96
terminal_capabilities_t apply_color_mode_override(terminal_capabilities_t caps)
Apply command-line overrides to detected capabilities.
terminal_capabilities_t detect_terminal_capabilities(void)
Detect terminal capabilities.
@ TERM_COLOR_NONE
No color support (monochrome terminal)
Definition terminal.h:428
Consolidated options structure.
Definition options.h:439
char palette_custom[256]
Custom palette characters.
Definition options.h:582
bool palette_custom_set
True if custom palette was set.
Definition options.h:583
Terminal capabilities packet structure (Packet Type 5)
Definition packet.h:909
Complete terminal capabilities structure.
Definition terminal.h:485
terminal_color_mode_t color_level
Detected color support level (terminal_color_mode_t)
Definition terminal.h:487
uint8_t desired_fps
Client's desired frame rate (1-144 FPS)
Definition terminal.h:509
render_mode_t render_mode
Preferred rendering mode (render_mode_t)
Definition terminal.h:497
bool utf8_support
True if terminal supports UTF-8 encoding.
Definition terminal.h:493
uint32_t capabilities
Capability flags bitmask (terminal_capability_flags_t)
Definition terminal.h:489
uint32_t color_count
Maximum number of colors (16, 256, or 16777216)
Definition terminal.h:491
char term_type[64]
$TERM environment variable value (for debugging)
Definition terminal.h:499
char colorterm[64]
$COLORTERM environment variable value (for debugging)
Definition terminal.h:501
bool detection_reliable
True if detection is confident (reliable detection)
Definition terminal.h:495

References apply_color_mode_override(), terminal_capabilities_packet_t::capabilities, terminal_capabilities_t::capabilities, terminal_capabilities_packet_t::color_count, terminal_capabilities_t::color_count, terminal_capabilities_packet_t::color_level, terminal_capabilities_t::color_level, COLOR_MODE_AUTO, terminal_capabilities_packet_t::colorterm, terminal_capabilities_t::colorterm, tcp_client::connection_active, DEFAULT_MAX_FPS, terminal_capabilities_packet_t::desired_fps, terminal_capabilities_t::desired_fps, detect_terminal_capabilities(), terminal_capabilities_packet_t::detection_reliable, terminal_capabilities_t::detection_reliable, ERROR_INVALID_PARAM, g_max_fps, GET_OPTION, terminal_capabilities_packet_t::height, HOST_TO_NET_U16, HOST_TO_NET_U32, INVALID_SOCKET_VALUE, log_warn, options_get(), PACKET_TYPE_CLIENT_CAPABILITIES, terminal_capabilities_packet_t::palette_custom, PALETTE_CUSTOM, terminal_capabilities_packet_t::palette_type, terminal_capabilities_packet_t::render_mode, terminal_capabilities_t::render_mode, terminal_capabilities_packet_t::reserved, SAFE_MEMSET, SAFE_STRNCPY, SET_ERRNO, tcp_client::sockfd, tcp_client_send_packet(), TERM_COLOR_NONE, terminal_capabilities_packet_t::term_type, terminal_capabilities_t::term_type, terminal_capabilities_packet_t::utf8_support, terminal_capabilities_t::utf8_support, and terminal_capabilities_packet_t::width.

◆ tcp_client_shutdown()

void tcp_client_shutdown ( tcp_client_t client)

Shutdown connection forcefully (for signal handlers)

Parameters
clientTCP client instance

Definition at line 302 of file lib/network/tcp/client.c.

302 {
303 if (!client)
304 return;
305
306 atomic_store(&client->connection_active, false);
307
308 // Shutdown socket for reading/writing to interrupt blocking calls
309 if (socket_is_valid(client->sockfd)) {
310 socket_shutdown(client->sockfd, SHUT_RDWR);
311 }
312}
int socket_shutdown(socket_t sock, int how)
Shutdown socket I/O.

References tcp_client::connection_active, socket_is_valid(), socket_shutdown(), and tcp_client::sockfd.

◆ tcp_client_signal_lost()

void tcp_client_signal_lost ( tcp_client_t client)

Signal that connection was lost (triggers reconnection)

Parameters
clientTCP client instance

Definition at line 266 of file lib/network/tcp/client.c.

266 {
267 if (!client)
268 return;
269
270 if (!atomic_load(&client->connection_lost)) {
271 atomic_store(&client->connection_lost, true);
272 atomic_store(&client->connection_active, false);
273 log_info("Connection lost signaled");
274 }
275}

References tcp_client::connection_active, tcp_client::connection_lost, and log_info.

Referenced by tcp_client_send_audio_batch(), tcp_client_send_audio_opus(), and tcp_client_send_audio_opus_batch().