ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
Network Module

🌐 Core network I/O operations with timeout support More...

Files

file  protocol.h
 ASCII-Chat IP Protocol (ACIP) packet type definitions.
 
file  http_client.c
 🌐 HTTPS client with BearSSL for fetching public keys from GitHub/GitLab with CA validation
 
file  http_client.h
 Simple HTTPS client for fetching public keys from GitHub/GitLab.
 
file  network.c
 🌐 Cross-platform socket I/O with timeout management and connection handling
 
file  network.h
 🌐 Core network I/O operations with timeout support
 
file  packet.c
 📦 Packet protocol handler with CRC validation, encryption, and compression
 
file  packet.h
 Packet protocol implementation with encryption and compression support.
 
file  protocol.h
 Server packet processing and protocol implementation.
 

Data Structures

struct  packet_header_t
 Network packet header structure. More...
 
struct  size_packet_t
 Terminal size update packet. More...
 
struct  client_info_packet_t
 Client information packet structure. More...
 
struct  stream_header_t
 Stream header packet structure. More...
 
struct  client_list_packet_t
 Client list packet structure. More...
 
struct  server_state_packet_t
 Server state packet structure. More...
 
struct  error_packet_t
 Error packet structure carrying error code and textual description. More...
 
struct  remote_log_packet_t
 Remote log packet structure carrying log level and message text. More...
 
struct  auth_failure_packet_t
 Authentication failure packet structure. More...
 
struct  protocol_version_packet_t
 Protocol version negotiation packet structure (Packet Type 1) More...
 
struct  ascii_frame_packet_t
 ASCII frame packet structure (Packet Type 2) More...
 
struct  image_frame_packet_t
 Image frame packet structure (Packet Type 3) More...
 
struct  audio_batch_packet_t
 Audio batch packet structure (Packet Type 28) More...
 
struct  crypto_capabilities_packet_t
 Crypto capabilities packet structure (Packet Type 14) More...
 
struct  crypto_parameters_packet_t
 Crypto parameters packet structure (Packet Type 15) More...
 
struct  terminal_capabilities_packet_t
 Terminal capabilities packet structure (Packet Type 5) More...
 
struct  packet_envelope_t
 Packet envelope containing received packet data. More...
 

Macros

#define REMOTE_LOG_FLAG_TRUNCATED   0x0001U
 Remote log packet flag definitions.
 

Enumerations

enum  packet_recv_result_t { PACKET_RECV_SUCCESS = 0 , PACKET_RECV_EOF = -1 , PACKET_RECV_ERROR = -2 , PACKET_RECV_SECURITY_VIOLATION = -3 }
 Packet reception result codes. More...
 

Variables

uint32_t packet_header_t::magic
 Magic number (PACKET_MAGIC) for packet validation.
 
uint16_t packet_header_t::type
 Packet type (packet_type_t enumeration)
 
uint32_t packet_header_t::length
 Payload data length in bytes (0 for header-only packets)
 
uint32_t packet_header_t::crc32
 CRC32 checksum of payload data (0 if length == 0)
 
uint32_t packet_header_t::client_id
 Client ID (0 = server, >0 = client identifier)
 
uint32_t size_packet_t::width
 Terminal width in characters.
 
uint32_t size_packet_t::height
 Terminal height in characters.
 
uint32_t client_info_packet_t::client_id
 Unique client identifier (1-9, 0 = server)
 
char client_info_packet_t::display_name [MAX_DISPLAY_NAME_LEN]
 User display name (null-terminated, max MAX_DISPLAY_NAME_LEN bytes)
 
uint32_t client_info_packet_t::capabilities
 Client capabilities bitmask (CLIENT_CAP_VIDEO | CLIENT_CAP_AUDIO | CLIENT_CAP_COLOR | CLIENT_CAP_STRETCH)
 
uint32_t stream_header_t::client_id
 Client ID that this stream originates from (1-9)
 
uint32_t stream_header_t::stream_type
 Stream type bitmask (STREAM_TYPE_VIDEO | STREAM_TYPE_AUDIO)
 
uint32_t stream_header_t::timestamp
 Timestamp when frame/audio was captured (milliseconds since epoch)
 
uint32_t client_list_packet_t::client_count
 Number of clients in the list (0 to MAX_CLIENTS)
 
client_info_packet_t client_list_packet_t::clients [MAX_CLIENTS]
 Array of client information structures.
 
uint32_t server_state_packet_t::connected_client_count
 Total number of currently connected clients.
 
uint32_t server_state_packet_t::active_client_count
 Number of clients actively sending video/audio streams.
 
uint32_t server_state_packet_t::reserved [6]
 Reserved fields for future use (must be zero)
 
uint32_t error_packet_t::error_code
 Error code from asciichat_error_t enumeration.
 
uint32_t error_packet_t::message_length
 Length of message payload in bytes (0-512)
 
uint8_t remote_log_packet_t::log_level
 Log level associated with the message (log_level_t cast to uint8_t)
 
uint8_t remote_log_packet_t::direction
 Direction hint so receivers can annotate origin.
 
uint16_t remote_log_packet_t::flags
 Additional flags (REMOTE_LOG_FLAG_*)
 
uint32_t remote_log_packet_t::message_length
 Message payload length in bytes (0-512)
 
uint8_t auth_failure_packet_t::reason_flags
 Bitmask of auth_failure_reason_t values indicating failure causes.
 
uint8_t auth_failure_packet_t::reserved [7]
 Reserved bytes for future use (must be zero)
 
uint16_t protocol_version_packet_t::protocol_version
 Major protocol version (must match for compatibility)
 
uint16_t protocol_version_packet_t::protocol_revision
 Minor protocol revision (server can be newer)
 
uint8_t protocol_version_packet_t::supports_encryption
 Encryption support flag (1=support encryption, 0=plaintext only)
 
uint8_t protocol_version_packet_t::compression_algorithms
 Supported compression algorithms bitmask (COMPRESS_ALGO_*)
 
uint8_t protocol_version_packet_t::compression_threshold
 Compression threshold percentage (0-100, e.g., 80 = compress if >80% size reduction)
 
uint16_t protocol_version_packet_t::feature_flags
 Feature flags bitmask (FEATURE_RLE_ENCODING, etc.)
 
uint8_t protocol_version_packet_t::reserved [7]
 Reserved bytes for future expansion (must be zero)
 
uint32_t ascii_frame_packet_t::width
 Terminal width in characters.
 
uint32_t ascii_frame_packet_t::height
 Terminal height in characters.
 
uint32_t ascii_frame_packet_t::original_size
 Size of original uncompressed ASCII data in bytes.
 
uint32_t ascii_frame_packet_t::compressed_size
 Size of compressed data (0 = not compressed)
 
uint32_t ascii_frame_packet_t::checksum
 CRC32 checksum of original ASCII data.
 
uint32_t ascii_frame_packet_t::flags
 Frame flags bitmask (HAS_COLOR, IS_COMPRESSED, etc.)
 
uint32_t image_frame_packet_t::width
 Image width in pixels.
 
uint32_t image_frame_packet_t::height
 Image height in pixels.
 
uint32_t image_frame_packet_t::pixel_format
 Pixel format enum (0=RGB24, 1=RGBA32, 2=BGR24, etc.)
 
uint32_t image_frame_packet_t::compressed_size
 Compressed data size (0 = not compressed, >0 = compressed)
 
uint32_t image_frame_packet_t::checksum
 CRC32 checksum of pixel data.
 
uint32_t image_frame_packet_t::timestamp
 Timestamp when frame was captured (milliseconds since epoch)
 
uint32_t audio_batch_packet_t::batch_count
 Number of audio chunks in this batch (usually AUDIO_BATCH_COUNT = 32)
 
uint32_t audio_batch_packet_t::total_samples
 Total audio samples across all chunks (typically 8192)
 
uint32_t audio_batch_packet_t::sample_rate
 Sample rate in Hz (e.g., 44100, 48000)
 
uint32_t audio_batch_packet_t::channels
 Number of audio channels (1=mono, 2=stereo)
 
uint16_t crypto_capabilities_packet_t::supported_kex_algorithms
 Supported key exchange algorithms bitmask (KEX_ALGO_*)
 
uint16_t crypto_capabilities_packet_t::supported_auth_algorithms
 Supported authentication algorithms bitmask (AUTH_ALGO_*)
 
uint16_t crypto_capabilities_packet_t::supported_cipher_algorithms
 Supported cipher algorithms bitmask (CIPHER_ALGO_*)
 
uint8_t crypto_capabilities_packet_t::requires_verification
 Server verification requirement flag (1=required, 0=optional)
 
uint8_t crypto_capabilities_packet_t::preferred_kex
 Preferred key exchange algorithm (KEX_ALGO_*)
 
uint8_t crypto_capabilities_packet_t::preferred_auth
 Preferred authentication algorithm (AUTH_ALGO_*)
 
uint8_t crypto_capabilities_packet_t::preferred_cipher
 Preferred cipher algorithm (CIPHER_ALGO_*)
 
uint8_t crypto_parameters_packet_t::selected_kex
 Selected key exchange algorithm (KEX_ALGO_*)
 
uint8_t crypto_parameters_packet_t::selected_auth
 Selected authentication algorithm (AUTH_ALGO_*)
 
uint8_t crypto_parameters_packet_t::selected_cipher
 Selected cipher algorithm (CIPHER_ALGO_*)
 
uint8_t crypto_parameters_packet_t::verification_enabled
 Server verification enabled flag (1=enabled, 0=disabled)
 
uint16_t crypto_parameters_packet_t::kex_public_key_size
 Key exchange public key size in bytes (e.g., 32 for X25519, 1568 for Kyber1024)
 
uint16_t crypto_parameters_packet_t::auth_public_key_size
 Authentication public key size in bytes (e.g., 32 for Ed25519, 1952 for Dilithium3)
 
uint16_t crypto_parameters_packet_t::signature_size
 Signature size in bytes (e.g., 64 for Ed25519, 3309 for Dilithium3)
 
uint16_t crypto_parameters_packet_t::shared_secret_size
 Shared secret size in bytes (e.g., 32 for X25519)
 
uint8_t crypto_parameters_packet_t::nonce_size
 Nonce size in bytes (e.g., 24 for XSalsa20)
 
uint8_t crypto_parameters_packet_t::mac_size
 MAC size in bytes (e.g., 16 for Poly1305)
 
uint8_t crypto_parameters_packet_t::hmac_size
 HMAC size in bytes (e.g., 32 for HMAC-SHA256)
 
uint8_t crypto_parameters_packet_t::reserved [3]
 Reserved bytes for future use (must be zero)
 
uint32_t terminal_capabilities_packet_t::capabilities
 Terminal capabilities bitmask (TERM_CAP_* flags)
 
uint32_t terminal_capabilities_packet_t::color_level
 Color level enum value (terminal_color_mode_t)
 
uint32_t terminal_capabilities_packet_t::color_count
 Actual color count (16, 256, or 16777216)
 
uint32_t terminal_capabilities_packet_t::render_mode
 Render mode enum value (foreground/background/half-block)
 
uint16_t terminal_capabilities_packet_t::width
 Terminal width in characters.
 
uint16_t terminal_capabilities_packet_t::height
 Terminal height in characters.
 
char terminal_capabilities_packet_t::term_type [32]
 $TERM environment variable value (for debugging)
 
char terminal_capabilities_packet_t::colorterm [32]
 $COLORTERM environment variable value (for debugging)
 
uint8_t terminal_capabilities_packet_t::detection_reliable
 Detection reliability flag (1=reliable detection, 0=best guess)
 
uint32_t terminal_capabilities_packet_t::utf8_support
 UTF-8 support flag (0=no UTF-8, 1=UTF-8 supported)
 
uint32_t terminal_capabilities_packet_t::palette_type
 Palette type enum value (palette_type_t)
 
char terminal_capabilities_packet_t::palette_custom [64]
 Custom palette characters (if palette_type == PALETTE_CUSTOM)
 
uint8_t terminal_capabilities_packet_t::desired_fps
 Client's desired frame rate (1-144 FPS)
 
uint8_t terminal_capabilities_packet_t::reserved [2]
 Reserved bytes for alignment (must be zero)
 
packet_type_t packet_envelope_t::type
 Packet type (from packet_types.h)
 
void * packet_envelope_t::data
 Packet payload data (decrypted and decompressed if applicable)
 
size_t packet_envelope_t::len
 Length of payload data in bytes.
 
bool packet_envelope_t::was_encrypted
 True if packet was encrypted (decrypted before envelope creation)
 
void * packet_envelope_t::allocated_buffer
 Buffer that needs to be freed by caller (may be NULL if not allocated)
 
size_t packet_envelope_t::allocated_size
 Size of allocated buffer in bytes.
 

HTTPS Client

char * https_get (const char *hostname, const char *path)
 Perform HTTPS GET request.
 

Socket I/O Operations

ssize_t send_with_timeout (socket_t sockfd, const void *data, size_t len, int timeout_seconds)
 Send data with timeout using chunked transmission.
 
ssize_t recv_with_timeout (socket_t sockfd, void *buf, size_t len, int timeout_seconds)
 Receive data with timeout.
 
int accept_with_timeout (socket_t listenfd, struct sockaddr *addr, socklen_t *addrlen, int timeout_seconds)
 Accept connection with timeout.
 
bool connect_with_timeout (socket_t sockfd, const struct sockaddr *addr, socklen_t addrlen, int timeout_seconds)
 Connect to server with timeout.
 

Socket Configuration Functions

asciichat_error_t set_socket_timeout (socket_t sockfd, int timeout_seconds)
 Set socket timeout for send/receive operations.
 
asciichat_error_t set_socket_keepalive (socket_t sockfd)
 Enable TCP keepalive on socket.
 
asciichat_error_t set_socket_nonblocking (socket_t sockfd)
 Set socket to non-blocking mode.
 
asciichat_error_t socket_configure_buffers (socket_t sockfd)
 Configure socket buffers and TCP_NODELAY for optimal performance.
 

Error Reporting Functions

const char * network_error_string ()
 Get human-readable error string for network errors.
 

Packet Validation Functions

asciichat_error_t packet_validate_header (const packet_header_t *header, uint16_t *pkt_type, uint32_t *pkt_len, uint32_t *expected_crc)
 Validate packet header and extract information.
 
asciichat_error_t packet_validate_crc32 (const void *data, size_t len, uint32_t expected_crc)
 Validate packet CRC32 checksum.
 

Basic Packet I/O Functions

asciichat_error_t packet_send (socket_t sockfd, packet_type_t type, const void *data, size_t len)
 Send a packet with header and CRC32 checksum.
 
asciichat_error_t packet_receive (socket_t sockfd, packet_type_t *type, void **data, size_t *len)
 Receive a packet with header validation and CRC32 checking.
 

Secure Packet I/O Functions

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.
 
packet_recv_result_t receive_packet_secure (socket_t sockfd, void *crypto_ctx, bool enforce_encryption, packet_envelope_t *envelope)
 Receive a packet with decryption and decompression support.
 

Legacy Packet I/O Functions

These functions provide basic packet I/O without encryption support. Use send_packet_secure() and receive_packet_secure() for encryption support.

int send_packet (socket_t sockfd, packet_type_t type, const void *data, size_t len)
 Send a basic packet without encryption.
 
int receive_packet (socket_t sockfd, packet_type_t *type, void **data, size_t *len)
 Receive a basic packet without encryption.
 

Protocol Packet Functions

Convenience functions for sending specific protocol packets. These functions construct the appropriate packet structure and send it over the socket.

int send_ping_packet (socket_t sockfd)
 Send a ping packet (keepalive)
 
int send_pong_packet (socket_t sockfd)
 Send a pong packet (keepalive response)
 
int send_clear_console_packet (socket_t sockfd)
 Send a clear console packet.
 
asciichat_error_t packet_send_error (socket_t sockfd, const crypto_context_t *crypto_ctx, asciichat_error_t error_code, const char *message)
 Send an error packet with optional encryption context.
 
asciichat_error_t packet_parse_error_message (const void *data, size_t len, asciichat_error_t *out_error_code, char *message_buffer, size_t message_buffer_size, size_t *out_message_length)
 Parse an error packet payload into components.
 
asciichat_error_t packet_send_remote_log (socket_t sockfd, const crypto_context_t *crypto_ctx, log_level_t level, remote_log_direction_t direction, uint16_t flags, const char *message)
 Send a remote log packet with optional encryption context.
 
asciichat_error_t packet_parse_remote_log (const void *data, size_t len, log_level_t *out_level, remote_log_direction_t *out_direction, uint16_t *out_flags, char *message_buffer, size_t message_buffer_size, size_t *out_message_length)
 Parse a remote log packet payload into components.
 
int send_protocol_version_packet (socket_t sockfd, const protocol_version_packet_t *version)
 Send protocol version negotiation packet.
 
int send_crypto_capabilities_packet (socket_t sockfd, const crypto_capabilities_packet_t *caps)
 Send crypto capabilities packet.
 
int send_crypto_parameters_packet (socket_t sockfd, const crypto_parameters_packet_t *params)
 Send crypto parameters packet.
 
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.
 
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.
 
asciichat_error_t send_ascii_frame_packet (socket_t sockfd, const char *frame_data, size_t frame_size)
 Send ASCII frame packet.
 
asciichat_error_t send_image_frame_packet (socket_t sockfd, const void *image_data, uint16_t width, uint16_t height, uint8_t format)
 Send image frame packet.
 

Network Timeout Constants

Timeout values tuned for real-time video streaming. All timeouts are specified in seconds.

#define CONNECT_TIMEOUT   3
 Connection timeout in seconds (3 seconds)
 
#define SEND_TIMEOUT   5
 Send timeout in seconds (5 seconds)
 
#define RECV_TIMEOUT   15
 Receive timeout in seconds (15 seconds)
 
#define ACCEPT_TIMEOUT   3
 Accept timeout in seconds (3 seconds)
 

Test Environment Detection

#define network_is_test_environment()   ((int)is_test_environment())
 Check if we're in a test environment.
 

Socket Keepalive Settings

Keepalive settings to detect dead connections. TCP keepalive probes are sent when connection is idle to detect broken connections.

#define KEEPALIVE_IDLE   60
 Keepalive idle time in seconds (60 seconds)
 
#define KEEPALIVE_INTERVAL   10
 Keepalive interval in seconds (10 seconds)
 
#define KEEPALIVE_COUNT   8
 Keepalive probe count (8 probes)
 

Network Protocol Constants

#define MAX_ERROR_MESSAGE_LENGTH   512
 Maximum error message length (512 bytes)
 
#define MAX_REMOTE_LOG_MESSAGE_LENGTH   512
 Maximum remote log message length (512 bytes)
 

Protocol Negotiation Constants

#define FEATURE_RLE_ENCODING   0x01
 Feature flags for protocol_version_packet_t.
 
#define FEATURE_DELTA_FRAMES   0x02
 Delta frame encoding (future)
 

Client Capability Flags

Bitmask flags for client capabilities in multi-user protocol.

#define CLIENT_CAP_VIDEO   0x01
 Client can send/receive video.
 
#define CLIENT_CAP_AUDIO   0x02
 Client can send/receive audio.
 
#define CLIENT_CAP_COLOR   0x04
 Client supports color rendering.
 
#define CLIENT_CAP_STRETCH   0x08
 Client can stretch frames to fill terminal.
 

Stream Type Flags

Bitmask flags for stream types in multi-user protocol.

#define STREAM_TYPE_VIDEO   0x01
 Video stream.
 
#define STREAM_TYPE_AUDIO   0x02
 Audio stream.
 

Crypto Algorithm Constants

Algorithm identifiers for key exchange, authentication, and encryption. Used in crypto handshake packet negotiation.

#define KEX_ALGO_X25519   0x01
 X25519 key exchange (Curve25519)
 
#define AUTH_ALGO_ED25519   0x01
 Ed25519 authentication (Edwards-curve signatures)
 
#define AUTH_ALGO_NONE   0x00
 No authentication (plaintext mode)
 
#define CIPHER_ALGO_XSALSA20_POLY1305   0x01
 XSalsa20-Poly1305 authenticated encryption.
 

Detailed Description

🌐 Core network I/O operations with timeout support

This module provides basic HTTPS GET functionality using BearSSL for TLS. It's designed specifically for fetching SSH/GPG public keys from GitHub and GitLab.

Note
TLS library: Uses BearSSL for TLS connections. BearSSL is a minimal TLS implementation with system CA certificate support.
Security: Uses system CA certificates for trust validation (20-year longevity). Validates server certificates against system trust store.
Key fetching: Fetches keys from GitHub/GitLab endpoints:
Key fetching functions: fetch_github_ssh_keys, fetch_gitlab_ssh_keys, fetch_github_gpg_keys, and fetch_gitlab_gpg_keys are in crypto/keys/https_keys.h. They properly belong in the keys module.
Author
Zachary Fogg me@zf.nosp@m.o.gg
Date
October 2025

This module provides fundamental network I/O operations including socket management, timeout handling, and basic send/receive operations. All operations support configurable timeouts to prevent indefinite blocking, critical for real-time video streaming applications.

CORE RESPONSIBILITIES:

  1. Socket I/O operations with timeout support
  2. Connection management (connect, accept) with timeouts
  3. Socket configuration (keepalive, non-blocking, timeouts)
  4. Chunked transmission for large data transfers
  5. Error reporting and diagnostics

ARCHITECTURAL OVERVIEW:

TIMEOUT SYSTEM:

SOCKET CONFIGURATION:

ERROR HANDLING:

INTEGRATION WITH OTHER MODULES:

PERFORMANCE CHARACTERISTICS:

Note
Timeout values are tuned for real-time video streaming. Adjust CONNECT_TIMEOUT, SEND_TIMEOUT, and RECV_TIMEOUT if needed for different network conditions.
Chunked transmission is used automatically for large data to prevent timeouts and enable progress tracking.
Warning
Timeout values that are too short may cause false positives on slow networks. Values that are too long may delay error detection unnecessarily.
Author
Zachary Fogg me@zf.nosp@m.o.gg
Date
September 2025
Version
2.0 (Post-Modularization)

This module provides comprehensive packet protocol implementation including packet verification, CRC validation, protocol compliance checking, encryption support, and compression integration. It serves as the core network protocol layer for ascii-chat's communication system.

CORE RESPONSIBILITIES:

  1. Packet header validation and CRC32 checksum verification
  2. Secure packet transmission with encryption support
  3. Secure packet reception with decryption and validation
  4. Protocol compliance checking and error handling
  5. Integration with cryptographic and compression subsystems

ARCHITECTURAL OVERVIEW:

PACKET STRUCTURE:

ENCRYPTION INTEGRATION:

COMPRESSION INTEGRATION:

PROTOCOL VALIDATION:

INTEGRATION WITH OTHER MODULES:

PERFORMANCE CHARACTERISTICS:

Note
All packet functions handle encryption automatically when crypto context is provided. Plaintext packets are used for handshake.
Compression is automatically applied to large packets (frames, audio batches) based on size thresholds.
Warning
Packet buffers are allocated by receive functions and must be freed by caller using the allocated_buffer pointer.
Author
Zachary Fogg me@zf.nosp@m.o.gg
Date
September 2025
Version
2.0 (Post-Modularization)

Network README

Overview

Welcome to the Network I/O module! This is where all the network communication happens—everything from basic socket operations to packet transmission. The network module is designed for real-time video streaming, which means it's optimized for low latency, reliability, and handling large data transfers smoothly.

What does the network module do?

The Network I/O module provides fundamental network operations that everything else builds on. Think of it as the foundation for all network communication. Here's what it handles:

  • Socket I/O operations with timeout support (so operations don't hang forever)
  • Connection management (connect, accept) with timeouts (critical for reliable connections)
  • Socket configuration (keepalive, non-blocking mode, timeouts) to keep connections healthy
  • Chunked transmission for large data transfers (so big video frames don't block the connection)
  • Packet protocol with encryption and compression support (built on top of the basic I/O)
  • Error reporting and diagnostics (so you know what went wrong when things break)

All operations support configurable timeouts, which is critical for real-time video streaming—we can't afford to wait forever when something goes wrong. The timeout system ensures that operations fail fast rather than hanging indefinitely.

Implementation: lib/network/network.h, lib/network/packet.h

Architecture

The network module is built around a few key concepts: timeouts to prevent hanging, socket configuration to keep connections healthy, and a packet protocol that handles the complexity of reliable data transmission. Let's walk through how everything fits together.

Timeout System

All I/O operations support configurable timeouts—this is probably the most important feature for real-time video streaming. Without timeouts, operations can hang forever when the network is flaky, which would freeze your video stream.

What timeouts do we have?

  • Connection timeout: 3 seconds (CONNECT_TIMEOUT)—when you're trying to connect to a server, we'll give up after 3 seconds rather than waiting forever
  • Send timeout: 5 seconds (SEND_TIMEOUT)—when sending data, we'll give up after 5 seconds if it's not going through
  • Receive timeout: 15 seconds (RECV_TIMEOUT)—when receiving data, we'll wait up to 15 seconds (this is longer because network delays are more common on receive)
  • Accept timeout: 3 seconds (ACCEPT_TIMEOUT)—when waiting for incoming connections, we'll check every 3 seconds rather than blocking forever

Why these values?

These timeouts are tuned specifically for real-time video streaming. They're short enough that you notice problems quickly, but long enough that normal network hiccups don't cause false positives. Chunked transmission prevents large data from blocking indefinitely—even if a single chunk times out, we can still make progress on the rest.

Socket Configuration

Socket configuration is about keeping your connections healthy and efficient. We configure sockets with several important settings:

What socket options do we set?

  • TCP keepalive: This detects dead connections automatically—if the connection has been idle for a while, keepalive probes check if it's still alive. If the other end doesn't respond, we know the connection is dead and can clean it up. We use KEEPALIVE_IDLE, KEEPALIVE_INTERVAL, and KEEPALIVE_COUNT to tune this.
  • Non-blocking mode: This enables asynchronous I/O patterns—instead of blocking and waiting for data, we can check if data is available and do other work while waiting
  • Socket-level timeouts: We set SO_SNDTIMEO and SO_RCVTIMEO at the socket level, so even if the application doesn't explicitly check timeouts, the socket itself will time out
  • Platform abstraction: All of this works cross-platform (Linux, macOS, Windows) through our platform abstraction layer

Packet Protocol

The packet protocol sits on top of the basic socket I/O and adds structure, validation, encryption, and compression. It's how we reliably transmit data even when the network is unreliable.

What does the packet protocol do?

The packet protocol provides:

  • Packet header validation: Every packet starts with a magic number and CRC32 checksum, so we can detect corrupted packets immediately
  • Secure packet transmission: Packets can be encrypted using the crypto context (automatic encryption/decryption)
  • Secure packet reception: Packets are automatically decrypted and validated when received
  • Automatic compression: Large packets are automatically compressed to save bandwidth
  • Protocol compliance checking: We verify that packets follow the protocol specification, so malformed packets are rejected early

How are packets structured?

Packet Structure:

  • Header: Contains a magic number (so we know it's really our packet), type (what kind of packet it is), length (how much data follows), CRC32 (to detect corruption), and client ID (which client this is from)
  • Payload: The actual data, which can be encrypted and/or compressed
  • Validation: The CRC32 checksum in the header lets us verify packet integrity before we even try to decrypt or decompress

This structure makes it easy to detect problems early—if the magic number is wrong or the CRC32 doesn't match, we know the packet is corrupted before we waste time trying to decrypt it.

Operations

Socket I/O Operations

Send/Receive Operations:

// Send data with timeout
ssize_t sent = send_with_timeout(sockfd, data, len, SEND_TIMEOUT);
if (sent < 0) {
log_error("Send failed: %s", network_error_string());
}
// Receive data with timeout
ssize_t received = recv_with_timeout(sockfd, buffer, len, RECV_TIMEOUT);
if (received < 0) {
log_error("Receive failed: %s", network_error_string());
}
#define log_error(...)
Log an ERROR message.
ssize_t send_with_timeout(socket_t sockfd, const void *data, size_t len, int timeout_seconds)
Send data with timeout using chunked transmission.
Definition network.c:200
const char * network_error_string()
Get human-readable error string for network errors.
Definition network.c:535
#define RECV_TIMEOUT
Receive timeout in seconds (15 seconds)
Definition network.h:118
ssize_t recv_with_timeout(socket_t sockfd, void *buf, size_t len, int timeout_seconds)
Receive data with timeout.
Definition network.c:272
#define SEND_TIMEOUT
Send timeout in seconds (5 seconds)
Definition network.h:108

Connection Operations:

// Connect to server with timeout
if (!connect_with_timeout(sockfd, &addr, addrlen, CONNECT_TIMEOUT)) {
log_error("Connection failed: %s", network_error_string());
}
// Accept connection with timeout
int client_fd = accept_with_timeout(listenfd, NULL, NULL, ACCEPT_TIMEOUT);
if (client_fd < 0) {
log_error("Accept failed: %s", network_error_string());
}
#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
int accept_with_timeout(socket_t listenfd, struct sockaddr *addr, socklen_t *addrlen, int timeout_seconds)
Accept connection with timeout.
Definition network.c:346
#define ACCEPT_TIMEOUT
Accept timeout in seconds (3 seconds)
Definition network.h:128

Packet Operations

Basic Packet I/O:

// Send a packet
if (err != ASCIICHAT_OK) {
log_error("Packet send failed");
}
// Receive a packet
void *data;
size_t len;
err = packet_receive(sockfd, &type, &data, &len);
if (err == ASCIICHAT_OK) {
// Process packet
process_packet(type, data, len);
free(data); // Free allocated buffer
}
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:46
@ ASCIICHAT_OK
Definition error_codes.h:48
asciichat_error_t packet_receive(socket_t sockfd, packet_type_t *type, void **data, size_t *len)
Receive a packet with proper header validation and CRC32 checking.
Definition packet.c:351
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_t
Network protocol packet type enumeration.
Definition packet.h:281
@ PACKET_TYPE_PING
Keepalive ping packet.
Definition packet.h:295

Secure Packet I/O:

// Send encrypted packet
frame_data, frame_size, crypto_ctx);
if (result < 0) {
log_error("Secure send failed");
}
// Receive and decrypt packet
packet_recv_result_t result = receive_packet_secure(sockfd, crypto_ctx,
true, &envelope);
if (result == PACKET_RECV_SUCCESS) {
// Process decrypted packet
process_packet(envelope.type, envelope.data, envelope.len);
free(envelope.allocated_buffer); // Free allocated buffer
}
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
void * allocated_buffer
Buffer that needs to be freed by caller (may be NULL if not allocated)
Definition packet.h:990
size_t len
Length of payload data in bytes.
Definition packet.h:986
void * data
Packet payload data (decrypted and decompressed if applicable)
Definition packet.h:984
packet_recv_result_t receive_packet_secure(socket_t sockfd, void *crypto_ctx, bool enforce_encryption, packet_envelope_t *envelope)
Receive a packet with decryption and decompression support.
Definition packet.c:568
packet_type_t type
Packet type (from packet_types.h)
Definition packet.h:982
packet_recv_result_t
Packet reception result codes.
Definition packet.h:1003
@ PACKET_RECV_SUCCESS
Packet received successfully.
Definition packet.h:1005
@ PACKET_TYPE_ASCII_FRAME
Complete ASCII frame with all metadata.
Definition packet.h:286
Packet envelope containing received packet data.
Definition packet.h:980

Socket Configuration

Socket Setup:

// Set socket timeout
if (set_socket_timeout(sockfd, SEND_TIMEOUT) < 0) {
log_error("Failed to set socket timeout");
}
// Enable TCP keepalive
if (set_socket_keepalive(sockfd) < 0) {
log_error("Failed to enable keepalive");
}
// Set non-blocking mode
if (set_socket_nonblocking(sockfd) < 0) {
log_error("Failed to set non-blocking mode");
}
asciichat_error_t set_socket_timeout(socket_t sockfd, int timeout_seconds)
Set socket timeout.
Definition network.c:436
asciichat_error_t set_socket_keepalive(socket_t sockfd)
Set socket keepalive.
Definition network.c:461
asciichat_error_t set_socket_nonblocking(socket_t sockfd)
Set socket non-blocking.
Definition network.c:477

Integration

The Network I/O module integrates with:

  • platform/socket.h: Uses platform socket abstraction
  • network/packet_types.h: Packet type definitions
  • crypto/crypto.h: Encryption/decryption operations
  • compression.h: Compression/decompression support
  • network/av.h: Media packet sending
  • crypto/handshake.h: Crypto handshake operations

Performance

Chunked Transmission:

  • Enables progressive sending of large frames
  • Prevents timeout issues with large data
  • Allows progress tracking

Timeout Handling:

  • Prevents indefinite blocking
  • Tuned for real-time video streaming
  • Platform-specific optimizations (select/poll/epoll)

Keepalive Settings:

  • Efficiently detects dead connections
  • No application-level heartbeats required
  • Configurable idle time and probe count

Error Handling

Error Reporting:

// Get human-readable error string
const char *error_msg = network_error_string();
log_error("Network error: %s", error_msg);

Error Codes:

  • Function return values: -1 indicates error
  • asciichat_error_t codes: ASCIICHAT_OK on success, error codes on failure
  • packet_recv_result_t codes: PACKET_RECV_SUCCESS, PACKET_RECV_EOF, etc.

Timeout Configuration

Timeout configuration is all about balance—too short and you get false positives on slow networks, too long and you delay error detection unnecessarily. We've tuned these values specifically for real-time video streaming.

What timeouts do we use?

  • CONNECT_TIMEOUT (3 seconds): Reduced from the default for faster connection attempts. If a connection doesn't work, we want to know quickly so we can try again or report the error
  • SEND_TIMEOUT (5 seconds): This gives enough time for timely delivery of video frames. It's long enough that network hiccups don't cause false positives, but short enough that stuck sends are detected quickly
  • RECV_TIMEOUT (15 seconds): This is longer than send timeout because network delays are more common on receive. We want to give the network time to deliver data, but not so much time that we hang forever
  • ACCEPT_TIMEOUT (3 seconds): This is balanced between responsiveness (we don't want to waste CPU checking too often) and quick detection of problems

⚠️ Important timeout notes:

Timeout values that are too short may cause false positives on slow networks—you might think the connection is dead when it's just slow. Values that are too long may delay error detection unnecessarily—you might wait too long before realizing something is wrong.

If you're running on a very slow network (like satellite internet), you might want to increase these timeouts. If you're running on a very fast network (like a local LAN), you could decrease them for faster error detection.

Chunked Transmission

Large data transfers are automatically chunked—this is how we send big video frames without blocking the connection. Instead of sending everything at once (which could cause timeouts or block other operations), we break large data into smaller chunks.

How does chunked transmission work?

  • Prevents timeout issues: Large frames can be several megabytes—if we try to send it all at once, we might timeout before it finishes. Chunking lets us send the frame in pieces, so each piece can complete quickly
  • Enables progress tracking: We can report progress as chunks are sent, so you know things are working even when sending large frames
  • Handles partial sends automatically: Sometimes send() doesn't send everything you ask it to—chunking handles this gracefully by retrying until the chunk is sent
  • Retries until complete: If a chunk fails to send, we retry until all data is sent or the timeout occurs

This is used automatically for large data—you don't need to do anything special. The system detects when data is large enough to benefit from chunking and handles it automatically.

Packet Security

The packet protocol supports:

  • Encryption: Automatic encryption/decryption when crypto context provided
  • Compression: Automatic compression for large packets
  • Validation: Magic number and CRC32 checksum verification
  • Policy Enforcement: Encryption requirement enforcement

Handshake Packets:

  • Always sent unencrypted (plaintext)
  • Use packet_is_handshake_type() to check before encryption
  • Required for crypto handshake establishment

Best Practices

  1. Always check return values:
    if (send_with_timeout(sockfd, data, len, timeout) < 0) {
    // Handle error
    }
  2. Free allocated packet buffers:
    void *data;
    size_t len;
    packet_receive(sockfd, &type, &data, &len);
    // ... use data ...
    free(data); // Always free
  3. Use secure packet functions for encryption:
    send_packet_secure(sockfd, type, data, len, crypto_ctx);
    receive_packet_secure(sockfd, crypto_ctx, true, &envelope);
  4. Enable keepalive for long-lived connections:
  5. Configure timeouts appropriately:
See also
network/network.h
network/packet.h
network/packet_types.h

Macro Definition Documentation

◆ ACCEPT_TIMEOUT

#define ACCEPT_TIMEOUT   3

#include <network.h>

Accept timeout in seconds (3 seconds)

Maximum time to wait for incoming connections. Balanced between responsiveness and CPU usage.

Definition at line 128 of file network.h.

◆ AUTH_ALGO_ED25519

#define AUTH_ALGO_ED25519   0x01

#include <packet.h>

Ed25519 authentication (Edwards-curve signatures)

Definition at line 950 of file packet.h.

◆ AUTH_ALGO_NONE

#define AUTH_ALGO_NONE   0x00

#include <packet.h>

No authentication (plaintext mode)

Definition at line 951 of file packet.h.

◆ CIPHER_ALGO_XSALSA20_POLY1305

#define CIPHER_ALGO_XSALSA20_POLY1305   0x01

#include <packet.h>

XSalsa20-Poly1305 authenticated encryption.

Definition at line 952 of file packet.h.

◆ CLIENT_CAP_AUDIO

#define CLIENT_CAP_AUDIO   0x02

#include <packet.h>

Client can send/receive audio.

Definition at line 816 of file packet.h.

◆ CLIENT_CAP_COLOR

#define CLIENT_CAP_COLOR   0x04

#include <packet.h>

Client supports color rendering.

Definition at line 817 of file packet.h.

◆ CLIENT_CAP_STRETCH

#define CLIENT_CAP_STRETCH   0x08

#include <packet.h>

Client can stretch frames to fill terminal.

Definition at line 818 of file packet.h.

◆ CLIENT_CAP_VIDEO

#define CLIENT_CAP_VIDEO   0x01

#include <packet.h>

Client can send/receive video.

Definition at line 815 of file packet.h.

◆ CONNECT_TIMEOUT

#define CONNECT_TIMEOUT   3

#include <network.h>

Connection timeout in seconds (3 seconds)

Maximum time to wait for connection establishment. Reduced from default for faster connection attempts and quicker failure detection.

Definition at line 98 of file network.h.

◆ FEATURE_DELTA_FRAMES

#define FEATURE_DELTA_FRAMES   0x02

#include <packet.h>

Delta frame encoding (future)

Definition at line 695 of file packet.h.

◆ FEATURE_RLE_ENCODING

#define FEATURE_RLE_ENCODING   0x01

#include <packet.h>

Feature flags for protocol_version_packet_t.

Bitmask values for optional protocol features. Used in protocol negotiation to enable advanced capabilities.

Run-length encoding support

Definition at line 694 of file packet.h.

◆ KEEPALIVE_COUNT

#define KEEPALIVE_COUNT   8

#include <network.h>

Keepalive probe count (8 probes)

Number of keepalive probes to send before considering connection dead.

Definition at line 186 of file network.h.

◆ KEEPALIVE_IDLE

#define KEEPALIVE_IDLE   60

#include <network.h>

Keepalive idle time in seconds (60 seconds)

Time to wait before sending first keepalive probe after connection becomes idle.

Definition at line 168 of file network.h.

◆ KEEPALIVE_INTERVAL

#define KEEPALIVE_INTERVAL   10

#include <network.h>

Keepalive interval in seconds (10 seconds)

Interval between subsequent keepalive probes.

Definition at line 177 of file network.h.

◆ KEX_ALGO_X25519

#define KEX_ALGO_X25519   0x01

#include <packet.h>

X25519 key exchange (Curve25519)

Definition at line 949 of file packet.h.

◆ MAX_ERROR_MESSAGE_LENGTH

#define MAX_ERROR_MESSAGE_LENGTH   512

#include <packet.h>

Maximum error message length (512 bytes)

Error packets include a message payload. This defines the maximum number of bytes allowed in the message portion to prevent excessive allocations and potential abuse.

Definition at line 122 of file packet.h.

◆ MAX_REMOTE_LOG_MESSAGE_LENGTH

#define MAX_REMOTE_LOG_MESSAGE_LENGTH   512

#include <packet.h>

Maximum remote log message length (512 bytes)

Remote logging packets mirror the error packet structure but are intended for diagnostic log forwarding between client and server. Limiting the payload size keeps allocations predictable and prevents log flooding over the network.

Definition at line 132 of file packet.h.

◆ network_is_test_environment

#define network_is_test_environment ( )    ((int)is_test_environment())

#include <network.h>

Check if we're in a test environment.

Compatibility macro that calls is_test_environment() from tests/test_env.h. Used to adjust timeouts for faster test execution.

Returns
1 if test environment, 0 otherwise

Definition at line 147 of file network.h.

◆ RECV_TIMEOUT

#define RECV_TIMEOUT   15

#include <network.h>

Receive timeout in seconds (15 seconds)

Maximum time to wait for incoming data. If no data is received within this time, connection is considered dead.

Definition at line 118 of file network.h.

◆ REMOTE_LOG_FLAG_TRUNCATED

#define REMOTE_LOG_FLAG_TRUNCATED   0x0001U

#include <packet.h>

Remote log packet flag definitions.

Message payload was truncated to fit the maximum length

Definition at line 628 of file packet.h.

◆ SEND_TIMEOUT

#define SEND_TIMEOUT   5

#include <network.h>

Send timeout in seconds (5 seconds)

Maximum time to wait for data transmission. Video frames need timely delivery to maintain real-time performance.

Definition at line 108 of file network.h.

◆ STREAM_TYPE_AUDIO

#define STREAM_TYPE_AUDIO   0x02

#include <packet.h>

Audio stream.

Definition at line 830 of file packet.h.

◆ STREAM_TYPE_VIDEO

#define STREAM_TYPE_VIDEO   0x01

#include <packet.h>

Video stream.

Definition at line 829 of file packet.h.

Enumeration Type Documentation

◆ packet_recv_result_t

#include <packet.h>

Packet reception result codes.

Result codes for packet reception operations. Negative values indicate errors, zero indicates success.

Enumerator
PACKET_RECV_SUCCESS 

Packet received successfully.

PACKET_RECV_EOF 

Connection closed (EOF)

PACKET_RECV_ERROR 

Network error occurred.

PACKET_RECV_SECURITY_VIOLATION 

Encryption policy violation (e.g., unencrypted packet when encryption required)

Definition at line 1003 of file packet.h.

1003 {
1007 PACKET_RECV_EOF = -1,
1009 PACKET_RECV_ERROR = -2,
@ PACKET_RECV_ERROR
Network error occurred.
Definition packet.h:1009
@ PACKET_RECV_EOF
Connection closed (EOF)
Definition packet.h:1007
@ PACKET_RECV_SECURITY_VIOLATION
Encryption policy violation (e.g., unencrypted packet when encryption required)
Definition packet.h:1011

Function Documentation

◆ accept_with_timeout()

int accept_with_timeout ( socket_t  listenfd,
struct sockaddr *  addr,
socklen_t *  addrlen,
int  timeout_seconds 
)

#include <network.h>

Accept connection with timeout.

Parameters
listenfdListening socket file descriptor
addrOutput: Client address structure (can be NULL)
addrlenInput/output: Length of address structure
timeout_secondsTimeout in seconds
Returns
Client socket file descriptor on success, -1 on error

Accepts incoming connection with timeout support. Waits up to timeout_seconds for incoming connection.

Note
If addr is NULL, client address information is not returned.
addrlen must point to initialized value containing size of addr buffer. On return, contains actual size of address.
Parameters
listenfdListening socket
addrClient address structure
addrlenLength of address structure
timeout_secondsTimeout in seconds
Returns
Client socket, or -1 on error

Definition at line 346 of file network.c.

346 {
347 fd_set read_fds;
348 struct timeval timeout;
349
350 socket_fd_zero(&read_fds);
351 socket_fd_set(listenfd, &read_fds);
352
353 timeout.tv_sec = timeout_seconds;
354 timeout.tv_usec = 0;
355
356 int result = socket_select(listenfd, &read_fds, NULL, NULL, &timeout);
357
358 if (result <= 0) {
359 if (result == 0) {
360 // Timeout is expected behavior for server waiting for connections
365 return -1;
366 }
367
368 if (network_handle_select_error(result)) {
369 return -1; // Don't retry for accept
370 }
371 return -1;
372 }
373
374 // Check if socket is ready
375 if (!socket_fd_isset(listenfd, &read_fds)) {
380 return -1;
381 }
382
383 // Check if socket is still valid before attempting accept
384 if (listenfd == INVALID_SOCKET_VALUE) {
385 SET_ERRNO(ERROR_NETWORK, "accept_with_timeout: listening socket is closed");
386 return -1;
387 }
388
389 socket_t accept_result = socket_accept(listenfd, addr, addrlen);
390
391 if (accept_result == INVALID_SOCKET_VALUE) {
392 // Check if this is a socket closed error (common during shutdown)
393#ifdef _WIN32
394 // On Windows, use WSAGetLastError() instead of errno
395 int error_code = WSAGetLastError();
396 // Windows-specific error codes for closed/invalid sockets
397 // WSAENOTSOCK = 10038, WSAEBADF = 10009, WSAENOTCONN = 10057
398 if (error_code == WSAENOTSOCK || error_code == WSAEBADF || error_code == WSAENOTCONN) {
399 // During shutdown, don't log this as an error since it's expected behavior
403 } else {
404 // Save Windows socket error to WSA error field for debugging
405 errno = EIO; // Set a generic errno
406#ifdef NDEBUG
408#else
410#endif
411 }
412#else
413 // POSIX error codes for closed/invalid sockets
414 int error_code = errno;
415 if (error_code == EBADF || error_code == ENOTSOCK) {
416 // During shutdown, don't log this as an error since it's expected behavior
420 } else {
421 SET_ERRNO_SYS(ERROR_NETWORK_BIND, "accept_with_timeout accept failed: %s", network_get_error_string(errno));
422 }
423#endif
424 return -1;
425 }
426
427 return (int)accept_result;
428}
asciichat_error_t error_code
#define SET_ERRNO_SYS(code, context_msg,...)
Set error code with custom message and system error context.
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
__thread asciichat_error_t asciichat_errno
Thread-local current error code.
void asciichat_set_errno_with_wsa_error(asciichat_error_t code, const char *file, int line, const char *function, int wsa_error)
Set error code with Windows socket error (WSA error)
__thread asciichat_error_context_t asciichat_errno_context
Thread-local error context storage.
@ ERROR_NETWORK_BIND
Definition error_codes.h:70
@ ERROR_NETWORK
Definition error_codes.h:69
@ ERROR_NETWORK_TIMEOUT
Definition error_codes.h:72
void socket_fd_zero(fd_set *set)
Clear an fd_set.
int socket_t
Socket handle type (POSIX: int)
Definition socket.h:50
#define ETIMEDOUT
#define INVALID_SOCKET_VALUE
Invalid socket value (POSIX: -1)
Definition socket.h:52
void socket_fd_set(socket_t sock, fd_set *set)
Add a socket to an fd_set.
socket_t socket_accept(socket_t sock, struct sockaddr *addr, socklen_t *addrlen)
Accept an incoming connection.
int socket_select(socket_t max_fd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
Select sockets for I/O readiness.
#define EBADF
int errno
int socket_fd_isset(socket_t sock, fd_set *set)
Check if a socket is in an fd_set.
#define ENOTSOCK
int system_errno
System errno value (if applicable, 0 otherwise)
bool has_system_error
True if system_errno is valid.
asciichat_error_t code
Error code (asciichat_error_t enum value)

References asciichat_errno, asciichat_errno_context, asciichat_set_errno_with_wsa_error(), asciichat_error_context_t::code, EBADF, ENOTSOCK, errno, error_code, ERROR_NETWORK, ERROR_NETWORK_BIND, ERROR_NETWORK_TIMEOUT, ETIMEDOUT, asciichat_error_context_t::has_system_error, INVALID_SOCKET_VALUE, SET_ERRNO, SET_ERRNO_SYS, socket_accept(), socket_fd_isset(), socket_fd_set(), socket_fd_zero(), socket_select(), and asciichat_error_context_t::system_errno.

◆ av_send_audio_opus_batch()

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 
)

#include <packet.h>

Send Opus-encoded audio batch packet with encryption support.

Parameters
sockfdSocket file descriptor
opus_dataOpus-encoded audio data buffer
opus_sizeSize of Opus-encoded data in bytes
frame_sizesArray of frame sizes (one per Opus frame)
sample_rateSample rate in Hz (e.g., 48000)
frame_durationFrame duration in milliseconds (e.g., 20)
frame_countNumber of Opus frames in batch
crypto_ctxCryptographic context for encryption (NULL for plaintext)
Returns
ASCIICHAT_OK on success, error code on failure

Sends PACKET_TYPE_AUDIO_OPUS_BATCH with multiple Opus-encoded frames. Opus provides better compression than raw audio (30-100 bytes per 20ms frame).

Note
Opus packets are NOT compressed again (already compressed by Opus codec).
Encryption is applied automatically when crypto_ctx is provided.

Definition at line 1136 of file packet.c.

1138 {
1139 if (!opus_data || opus_size == 0 || !frame_sizes || sample_rate <= 0 || frame_duration <= 0 || frame_count <= 0) {
1141 "Invalid Opus batch parameters: opus_data=%p, opus_size=%zu, frame_sizes=%p, sample_rate=%d, "
1142 "frame_duration=%d, frame_count=%d",
1143 (const void *)opus_data, opus_size, (const void *)frame_sizes, sample_rate, frame_duration,
1144 frame_count);
1145 }
1146
1147 // Validate frame_count to prevent integer overflow in size calculations
1148 // Max reasonable frames per batch: ~1 second of 10ms frames = 100 frames
1149 if (frame_count > 1000) {
1150 return SET_ERRNO(ERROR_INVALID_PARAM, "Too many Opus frames: %d (max 1000)", frame_count);
1151 }
1152
1153 // Allocate buffer for header + frame sizes + encoded data
1154 size_t header_size = 16; // sample_rate (4), frame_duration (4), frame_count (4), reserved (4)
1155 size_t frame_sizes_bytes = (size_t)frame_count * sizeof(uint16_t);
1156 size_t total_size = header_size + frame_sizes_bytes + opus_size;
1157 void *packet_data = buffer_pool_alloc(NULL, total_size);
1158 if (!packet_data) {
1159 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for Opus batch packet: %zu bytes", total_size);
1160 }
1161
1162 // Write header (network byte order for cross-platform compatibility)
1163 uint8_t *buf = (uint8_t *)packet_data;
1164 uint32_t sr = HOST_TO_NET_U32((uint32_t)sample_rate);
1165 uint32_t fd = HOST_TO_NET_U32((uint32_t)frame_duration);
1166 uint32_t fc = HOST_TO_NET_U32((uint32_t)frame_count);
1167 memcpy(buf, &sr, 4);
1168 memcpy(buf + 4, &fd, 4);
1169 memcpy(buf + 8, &fc, 4);
1170 memset(buf + 12, 0, 4); // Reserved
1171
1172 // Write frame sizes array (convert each to network byte order)
1173 uint16_t *frame_sizes_out = (uint16_t *)(buf + header_size);
1174 for (int i = 0; i < frame_count; i++) {
1175 frame_sizes_out[i] = HOST_TO_NET_U16(frame_sizes[i]);
1176 }
1177
1178 // Copy Opus data
1179 memcpy(buf + header_size + frame_sizes_bytes, opus_data, opus_size);
1180
1181 // Send packet (with encryption support)
1182 asciichat_error_t result =
1183 send_packet_secure(sockfd, PACKET_TYPE_AUDIO_OPUS_BATCH, packet_data, total_size, crypto_ctx);
1184
1185 // Clean up
1186 buffer_pool_free(NULL, packet_data, total_size);
1187
1188 return result;
1189}
#define HOST_TO_NET_U16(val)
Definition endian.h:101
#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 short uint16_t
Definition common.h:57
unsigned int uint32_t
Definition common.h:58
unsigned char uint8_t
Definition common.h:56
@ ERROR_MEMORY
Definition error_codes.h:53
@ ERROR_INVALID_PARAM
@ PACKET_TYPE_AUDIO_OPUS_BATCH
Batched Opus-encoded audio frames.
Definition packet.h:359

References buffer_pool_alloc(), buffer_pool_free(), ERROR_INVALID_PARAM, ERROR_MEMORY, HOST_TO_NET_U16, HOST_TO_NET_U32, PACKET_TYPE_AUDIO_OPUS_BATCH, send_packet_secure(), and SET_ERRNO.

Referenced by client_send_thread_func(), and tcp_client_send_audio_opus_batch().

◆ connect_with_timeout()

bool connect_with_timeout ( socket_t  sockfd,
const struct sockaddr *  addr,
socklen_t  addrlen,
int  timeout_seconds 
)

#include <network.h>

Connect to server with timeout.

Parameters
sockfdSocket file descriptor
addrServer address structure
addrlenAddress structure length
timeout_secondsTimeout in seconds
Returns
true on success, false on failure

Establishes connection to server with timeout support. Waits up to timeout_seconds for connection to complete.

Note
Uses platform-specific connection timeout mechanism (select/poll).
Returns false on timeout or connection failure. Use network_error_string() to get human-readable error description.

Connect to server with timeout.

Parameters
sockfdSocket file descriptor
addrAddress to connect to
addrlenAddress length
timeout_secondsTimeout in seconds
Returns
true on success, false on failure

Definition at line 547 of file network.c.

547 {
548 if (sockfd == INVALID_SOCKET_VALUE) {
549 errno = EBADF;
550 return false;
551 }
552
553 // Set socket to non-blocking for timeout control
554 if (set_socket_nonblocking(sockfd) != ASCIICHAT_OK) {
555 return false;
556 }
557
558 // Attempt connection
559 int result = connect(sockfd, addr, addrlen);
560
561 if (result == 0) {
562 // Connected immediately
563 return true;
564 }
565
566#ifdef _WIN32
567 int error = WSAGetLastError();
568 if (error != WSAEWOULDBLOCK && error != WSAEINPROGRESS) {
569 return false;
570 }
571#else
572 if (errno != EINPROGRESS && errno != EWOULDBLOCK) {
573 return false;
574 }
575#endif
576
577 // Use select to wait for connection with timeout
578 fd_set write_fds;
579 struct timeval timeout;
580
581 socket_fd_zero(&write_fds);
582 socket_fd_set(sockfd, &write_fds);
583
584 timeout.tv_sec = timeout_seconds;
585 timeout.tv_usec = 0;
586
587 result = socket_select(sockfd, NULL, &write_fds, NULL, &timeout);
588
589 if (result <= 0) {
590 return false; // Timeout or error
591 }
592
593 if (!socket_fd_isset(sockfd, &write_fds)) {
594 return false; // Socket not ready
595 }
596
597 // Check if connection was successful
598 int error_code = 0;
599 socklen_t error_len = sizeof(error_code);
600
601 if (socket_getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error_code, &error_len) != 0) {
602 return false;
603 }
604
605 if (error_code != 0) {
606 return false;
607 }
608
609 // Connection successful - restore blocking mode
610 if (socket_set_blocking(sockfd) != 0) {
611 log_warn("Failed to restore socket to blocking mode after connect");
612 // Continue anyway - non-blocking mode works but may cause issues with send/recv
613 }
614
615 return true;
616}
#define log_warn(...)
Log a WARN message.
int socket_getsockopt(socket_t sock, int level, int optname, void *optval, socklen_t *optlen)
Get socket option.
#define EWOULDBLOCK
int socket_set_blocking(socket_t sock)
Set socket to blocking mode.

References ASCIICHAT_OK, EBADF, errno, error_code, EWOULDBLOCK, INVALID_SOCKET_VALUE, log_warn, set_socket_nonblocking(), socket_fd_isset(), socket_fd_set(), socket_fd_zero(), socket_getsockopt(), socket_select(), and socket_set_blocking().

Referenced by server_connection_establish(), and tcp_client_connect().

◆ https_get()

char * https_get ( const char *  hostname,
const char *  path 
)

#include <http_client.h>

Perform HTTPS GET request.

Parameters
hostnameServer hostname (e.g., "github.com", must not be NULL)
pathResource path (e.g., "/username.keys", must not be NULL)
Returns
Allocated string containing response body (caller must free), or NULL on error

Makes a secure HTTPS connection to the specified hostname and fetches the resource at the given path. Uses system CA certificates for validation.

Note
TLS connection: Uses BearSSL for TLS connections. Validates server certificate against system CA certificates.
Memory management: Returns allocated string that caller must free. Use SAFE_FREE() to free the returned string.
Error handling: Returns NULL on error (network error, TLS error, etc.). Error messages are logged via logging system.
Hostname format: Hostname should be domain name only (no "https://" prefix). Example: "github.com", not "https://github.com".
Path format: Path should start with "/" for absolute paths. Example: "/username.keys", not "username.keys".
Response body: Returns complete response body as null-terminated string. Response may contain multiple keys (one per line for SSH keys).
Warning
Network dependency: Requires network connectivity and valid hostname. May fail if network is unavailable or hostname is unreachable.
Memory leak: Caller must free returned string using SAFE_FREE(). Function allocates memory that must be freed.
Certificate validation: Uses system CA certificates for validation. May fail if system CA certificates are missing or outdated.

Definition at line 109 of file http_client.c.

109 {
110 if (!hostname || !path) {
111 log_error("Invalid arguments to https_get");
112 return NULL;
113 }
114
115 log_info("HTTPS GET https://%s%s", hostname, path);
116
117 // Load system CA certificates
118 char *pem_data = NULL;
119 size_t pem_size = 0;
120 if (platform_load_system_ca_certs(&pem_data, &pem_size) != 0) {
121 log_error("Failed to load system CA certificates");
122 return NULL;
123 }
124
125 // Parse PEM certificates into BearSSL trust anchors
127 size_t num_anchors = read_trust_anchors_from_memory(&anchors, (unsigned char *)pem_data, pem_size);
128 SAFE_FREE(pem_data);
129
130 if (num_anchors == 0) {
131 log_error("No trust anchors loaded");
132 // Free anchors before returning to prevent leak
133 goto cleanup_anchors;
134 }
135 log_info("Loaded %zu trust anchors", num_anchors);
136
137 // Resolve hostname using getaddrinfo (modern, non-deprecated API)
138 struct addrinfo hints, *result;
139 memset(&hints, 0, sizeof(hints));
140 hints.ai_family = AF_INET; // IPv4
141 hints.ai_socktype = SOCK_STREAM;
142 hints.ai_protocol = IPPROTO_TCP;
143
144 if (getaddrinfo(hostname, "443", &hints, &result) != 0) {
145 log_error("Failed to resolve hostname: %s", hostname);
146 goto cleanup_anchors;
147 }
148
149 // Create TCP socket
150 socket_t sock = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
151 if (sock == INVALID_SOCKET_VALUE) {
152 log_error("Failed to create socket");
153 freeaddrinfo(result);
154 goto cleanup_anchors;
155 }
156
157 // Connect to server
158 if (connect(sock, result->ai_addr, (int)result->ai_addrlen) != 0) {
159 log_error("Failed to connect to %s:443", hostname);
160 socket_close(sock);
161 freeaddrinfo(result);
162 goto cleanup_anchors;
163 }
164
165 freeaddrinfo(result);
166
167 log_info("Connected to %s:443", hostname);
168
169 // Initialize BearSSL X.509 minimal validator
170 br_x509_minimal_context xc;
171 br_x509_minimal_init(&xc, &br_sha256_vtable, anchors.buf, anchors.ptr);
172
173 // Initialize BearSSL client context
174 br_ssl_client_context sc;
175 br_ssl_client_init_full(&sc, &xc, anchors.buf, anchors.ptr);
176
177 // Set I/O buffer
178 unsigned char *iobuf;
179 iobuf = SAFE_MALLOC(BR_SSL_BUFSIZE_BIDI, unsigned char *);
180 br_ssl_engine_set_buffer(&sc.eng, iobuf, BR_SSL_BUFSIZE_BIDI, 1);
181
182 // Initialize I/O context
183 br_sslio_context ioc;
184 br_sslio_init(&ioc, &sc.eng, sock_read, &sock, sock_write, &sock);
185
186 // Start TLS handshake
187 br_ssl_client_reset(&sc, hostname, 0);
188
189 log_info("Starting TLS handshake with %s", hostname);
190
191 // Build HTTP request
192 char request[BUFFER_SIZE_LARGE];
193 int request_len = safe_snprintf(request, sizeof(request),
194 "GET %s HTTP/1.1\r\n"
195 "Host: %s\r\n"
196 "Connection: close\r\n"
197 "User-Agent: ascii-chat/" ASCII_CHAT_VERSION_STRING "\r\n"
198 "\r\n",
199 path, hostname);
200
201 // Send HTTP request over TLS
202 if (br_sslio_write_all(&ioc, request, (size_t)request_len) != 0) {
203 log_error("Failed to send HTTP request");
204 SAFE_FREE(iobuf);
205 socket_close(sock);
206 goto cleanup_anchors;
207 }
208
209 br_sslio_flush(&ioc);
210 log_info("Sent HTTP request");
211
212 // Read HTTP response
213 char *response_buf = NULL;
214 size_t response_capacity = 8192;
215 size_t response_len = 0;
216 response_buf = SAFE_MALLOC(response_capacity, char *);
217
218 while (1) {
219 // Ensure we have space to read
220 if (response_len + 1024 > response_capacity) {
221 response_capacity *= 2;
222 response_buf = SAFE_REALLOC(response_buf, response_capacity, char *);
223 }
224
225 // Read data
226 int n = br_sslio_read(&ioc, response_buf + response_len, response_capacity - response_len);
227 if (n < 0) {
228 // Check for TLS errors
229 int err = br_ssl_engine_last_error(&sc.eng);
230 if (err != BR_ERR_OK) {
231 log_error("TLS error: %d", err);
232 SAFE_FREE(response_buf);
233 SAFE_FREE(iobuf);
234 socket_close(sock);
235 goto cleanup_anchors;
236 }
237 // EOF or connection closed
238 break;
239 }
240 if (n == 0) {
241 break; // EOF
242 }
243
244 response_len += (size_t)n;
245 }
246
247 response_buf[response_len] = '\0';
248 log_info("Received %zu bytes", response_len);
249
250 // Close connection
251 br_sslio_close(&ioc);
252 socket_close(sock);
253
254 // Parse HTTP response
255 asciichat_error_t status = check_http_status(response_buf);
256 if (status != ASCIICHAT_OK) {
257 SAFE_FREE(response_buf);
258 SAFE_FREE(iobuf);
259 goto cleanup_anchors;
260 }
261
262 char *body = extract_http_body(response_buf, response_len);
263 SAFE_FREE(response_buf);
264 SAFE_FREE(iobuf);
265
266 // Cleanup trust anchors
267 for (size_t i = 0; i < anchors.ptr; i++) {
268 free_ta_contents(&anchors.buf[i]);
269 }
270 SAFE_FREE(anchors.buf);
271
272 return body;
273
274cleanup_anchors:
275 for (size_t i = 0; i < anchors.ptr; i++) {
276 free_ta_contents(&anchors.buf[i]);
277 }
278 SAFE_FREE(anchors.buf);
279 return NULL;
280}
#define BUFFER_SIZE_LARGE
Large buffer size (1024 bytes)
#define SAFE_REALLOC(ptr, size, cast)
Definition common.h:228
#define SAFE_FREE(ptr)
Definition common.h:320
#define SAFE_MALLOC(size, cast)
Definition common.h:208
br_x509_trust_anchor * buf
Definition pem_utils.h:79
#define ANCHOR_LIST_INIT
Initializer for anchor_list.
Definition pem_utils.h:93
size_t read_trust_anchors_from_memory(anchor_list *dst, const unsigned char *pem_data, size_t pem_len)
Read trust anchors from PEM-encoded data in memory.
Definition pem_utils.c:440
void free_ta_contents(br_x509_trust_anchor *ta)
Free the contents of a trust anchor.
Definition pem_utils.c:419
size_t ptr
Definition pem_utils.h:80
#define log_info(...)
Log an INFO message.
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Safe version of snprintf that ensures null termination.
asciichat_error_t platform_load_system_ca_certs(char **pem_data_out, size_t *pem_size_out)
Load system CA certificates for TLS/HTTPS.
int socket_close(socket_t sock)
Close a socket.
Vector type for trust anchors.
Definition pem_utils.h:78

References ANCHOR_LIST_INIT, ASCIICHAT_OK, anchor_list::buf, BUFFER_SIZE_LARGE, free_ta_contents(), INVALID_SOCKET_VALUE, log_error, log_info, platform_load_system_ca_certs(), anchor_list::ptr, read_trust_anchors_from_memory(), SAFE_FREE, SAFE_MALLOC, SAFE_REALLOC, safe_snprintf(), and socket_close().

◆ network_error_string()

const char * network_error_string ( )

#include <network.h>

Get human-readable error string for network errors.

Returns
Error string describing last network error

Returns a human-readable description of the last network error. Useful for error logging and user-facing error messages.

Note
Error string is thread-local - each thread has its own error state.
Parameters
error_codeError code
Returns
Error string

Definition at line 535 of file network.c.

535 {
537}
const char * socket_get_error_string(void)
Get last socket error as string.

References socket_get_error_string().

Referenced by server_connection_establish(), socket_configure_buffers(), and tcp_client_connect().

◆ packet_parse_error_message()

asciichat_error_t packet_parse_error_message ( const void *  data,
size_t  len,
asciichat_error_t out_error_code,
char *  message_buffer,
size_t  message_buffer_size,
size_t *  out_message_length 
)

#include <packet.h>

Parse an error packet payload into components.

Parameters
dataPacket payload buffer
lenPayload length in bytes
out_error_codeOutput pointer for asciichat_error_t value (must not be NULL)
message_bufferDestination buffer for message string (must not be NULL)
message_buffer_sizeSize of destination buffer in bytes (must be > 0)
out_message_lengthOptional output for message length reported by sender
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 854 of file packet.c.

856 {
857 if (!data || len < sizeof(error_packet_t) || !out_error_code || !message_buffer || message_buffer_size == 0) {
859 "Invalid parameters: data=%p len=%zu out_error_code=%p message_buffer=%p buffer_size=%zu", data,
860 len, out_error_code, message_buffer, message_buffer_size);
861 }
862
863 const error_packet_t *packet = (const error_packet_t *)data;
864 uint32_t raw_error_code = NET_TO_HOST_U32(packet->error_code);
865 uint32_t raw_message_length = NET_TO_HOST_U32(packet->message_length);
866
867 if (raw_message_length > MAX_ERROR_MESSAGE_LENGTH) {
868 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Error message length too large: %u", raw_message_length);
869 }
870
871 size_t total_required = sizeof(error_packet_t) + (size_t)raw_message_length;
872 if (total_required > len) {
873 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Error packet truncated: expected %zu bytes, have %zu", total_required,
874 len);
875 }
876
877 const uint8_t *message_bytes = (const uint8_t *)data + sizeof(error_packet_t);
878 size_t copy_len = raw_message_length;
879 if (copy_len >= message_buffer_size) {
880 copy_len = message_buffer_size - 1;
881 }
882
883 if (copy_len > 0) {
884 memcpy(message_buffer, message_bytes, copy_len);
885 }
886 message_buffer[copy_len] = '\0';
887
888 if (out_message_length) {
889 *out_message_length = raw_message_length;
890 }
891
892 *out_error_code = (asciichat_error_t)raw_error_code;
893 return ASCIICHAT_OK;
894}
#define NET_TO_HOST_U32(val)
Definition endian.h:86
@ ERROR_NETWORK_PROTOCOL
Definition error_codes.h:73
uint32_t message_length
Length of message payload in bytes (0-512)
Definition packet.h:623
uint32_t error_code
Error code from asciichat_error_t enumeration.
Definition packet.h:621
#define MAX_ERROR_MESSAGE_LENGTH
Maximum error message length (512 bytes)
Definition packet.h:122
Error packet structure carrying error code and textual description.
Definition packet.h:619

References ASCIICHAT_OK, error_packet_t::error_code, ERROR_INVALID_PARAM, ERROR_NETWORK_PROTOCOL, MAX_ERROR_MESSAGE_LENGTH, error_packet_t::message_length, NET_TO_HOST_U32, and SET_ERRNO.

◆ packet_parse_remote_log()

asciichat_error_t packet_parse_remote_log ( const void *  data,
size_t  len,
log_level_t out_level,
remote_log_direction_t out_direction,
uint16_t out_flags,
char *  message_buffer,
size_t  message_buffer_size,
size_t *  out_message_length 
)

#include <packet.h>

Parse a remote log packet payload into components.

Parameters
dataPacket payload buffer
lenPayload length in bytes
out_levelOutput pointer for log level (must not be NULL)
out_directionOutput pointer for direction (must not be NULL)
out_flagsOutput pointer for flags (must not be NULL)
message_bufferDestination buffer for message string (must not be NULL)
message_buffer_sizeSize of destination buffer in bytes (must be > 0)
out_message_lengthOptional output for message length reported by sender
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 953 of file packet.c.

956 {
957 if (!data || len < sizeof(remote_log_packet_t) || !out_level || !out_direction || !out_flags || !message_buffer ||
958 message_buffer_size == 0) {
959 return SET_ERRNO(
961 "Invalid parameters: data=%p len=%zu out_level=%p out_direction=%p out_flags=%p buffer=%p size=%zu", data, len,
962 out_level, out_direction, out_flags, message_buffer, message_buffer_size);
963 }
964
965 const remote_log_packet_t *packet = (const remote_log_packet_t *)data;
966 uint8_t raw_level = packet->log_level;
967 if (raw_level > LOG_FATAL) {
968 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid remote log level: %u", raw_level);
969 }
970 *out_level = (log_level_t)raw_level;
971
972 uint8_t raw_direction = packet->direction;
973 if (raw_direction > REMOTE_LOG_DIRECTION_CLIENT_TO_SERVER) {
974 raw_direction = REMOTE_LOG_DIRECTION_UNKNOWN;
975 }
976 *out_direction = (remote_log_direction_t)raw_direction;
977
978 uint16_t raw_flags = NET_TO_HOST_U16(packet->flags);
979 *out_flags = raw_flags;
980
981 uint32_t raw_message_length = NET_TO_HOST_U32(packet->message_length);
982 if (raw_message_length > MAX_REMOTE_LOG_MESSAGE_LENGTH) {
983 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Remote log message length too large: %u", raw_message_length);
984 }
985
986 size_t total_required = sizeof(remote_log_packet_t) + (size_t)raw_message_length;
987 if (total_required > len) {
988 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Remote log packet truncated: expected %zu bytes, have %zu",
989 total_required, len);
990 }
991
992 const uint8_t *message_bytes = (const uint8_t *)data + sizeof(remote_log_packet_t);
993 size_t copy_len = raw_message_length;
994 if (copy_len >= message_buffer_size) {
995 copy_len = message_buffer_size - 1;
996 }
997
998 if (copy_len > 0) {
999 memcpy(message_buffer, message_bytes, copy_len);
1000 }
1001 message_buffer[copy_len] = '\0';
1002
1003 if (out_message_length) {
1004 *out_message_length = raw_message_length;
1005 }
1006
1007 return ASCIICHAT_OK;
1008}
#define NET_TO_HOST_U16(val)
Definition endian.h:116
enum remote_log_direction remote_log_direction_t
Remote log packet direction enumeration.
log_level_t
Logging levels enumeration.
Definition log/logging.h:59
@ REMOTE_LOG_DIRECTION_UNKNOWN
@ REMOTE_LOG_DIRECTION_CLIENT_TO_SERVER
@ LOG_FATAL
Definition log/logging.h:65
uint16_t flags
Additional flags (REMOTE_LOG_FLAG_*)
Definition packet.h:639
uint32_t message_length
Message payload length in bytes (0-512)
Definition packet.h:641
uint8_t log_level
Log level associated with the message (log_level_t cast to uint8_t)
Definition packet.h:635
uint8_t direction
Direction hint so receivers can annotate origin.
Definition packet.h:637
#define MAX_REMOTE_LOG_MESSAGE_LENGTH
Maximum remote log message length (512 bytes)
Definition packet.h:132
Remote log packet structure carrying log level and message text.
Definition packet.h:633

References ASCIICHAT_OK, remote_log_packet_t::direction, ERROR_INVALID_PARAM, ERROR_NETWORK_PROTOCOL, remote_log_packet_t::flags, LOG_FATAL, remote_log_packet_t::log_level, MAX_REMOTE_LOG_MESSAGE_LENGTH, remote_log_packet_t::message_length, NET_TO_HOST_U16, NET_TO_HOST_U32, REMOTE_LOG_DIRECTION_CLIENT_TO_SERVER, REMOTE_LOG_DIRECTION_UNKNOWN, and SET_ERRNO.

Referenced by handle_remote_log_packet_from_client().

◆ packet_receive()

asciichat_error_t packet_receive ( socket_t  sockfd,
packet_type_t type,
void **  data,
size_t *  len 
)

#include <packet.h>

Receive a packet with header validation and CRC32 checking.

Parameters
sockfdSocket file descriptor
typeOutput: Packet type
dataOutput: Packet payload data (allocated by function, freed by caller)
lenOutput: Payload data length in bytes
Returns
ASCIICHAT_OK on success, error code on failure

Receives a complete packet, validates header, and verifies CRC32 checksum. Allocates buffer for payload data which must be freed by caller.

Note
Allocates buffer for payload data - caller must free when done.
Validates magic number and CRC32 checksum before returning data.
Warning
Allocated data buffer must be freed by caller to prevent memory leaks.

Receive a packet with header validation and CRC32 checking.

Parameters
sockfdSocket file descriptor
typeOutput: packet type
dataOutput: packet data (allocated by caller, freed by caller)
lenOutput: data length
Returns
0 on success, -1 on error

Definition at line 351 of file packet.c.

351 {
352 if (sockfd == INVALID_SOCKET_VALUE) {
353 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid socket descriptor");
354 }
355 if (!type || !data || !len) {
356 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: type=%p, data=%p, len=%p", type, data, len);
357 }
358
359 // Read packet header into memory from network socket
360 packet_header_t header;
361 ssize_t received =
362 recv_with_timeout(sockfd, &header, sizeof(header), network_is_test_environment() ? 1 : RECV_TIMEOUT);
363 if (received < 0) {
364 // Error context is already set by recv_with_timeout
365 return ERROR_NETWORK;
366 }
367 if ((size_t)received != sizeof(header)) {
368 if (received == 0) {
369 log_warn("Connection closed while reading packet header");
370 return SET_ERRNO(ERROR_NETWORK, "Connection closed by peer while reading packet header");
371 }
372
373 return SET_ERRNO(ERROR_NETWORK, "Partial packet header received: %zd/%zu bytes", received, sizeof(header));
374 }
375
376 // Validate packet header
377 uint16_t pkt_type;
378 uint32_t pkt_len;
379 uint32_t expected_crc;
380 if (packet_validate_header(&header, &pkt_type, &pkt_len, &expected_crc) != ASCIICHAT_OK) {
381 // Error context is already set by packet_validate_header
383 }
384
385 // Allocate buffer for payload
386 void *payload = NULL;
387 if (pkt_len > 0) {
388 payload = buffer_pool_alloc(NULL, pkt_len);
389
390 // Use adaptive timeout for large packets
391 int recv_timeout = network_is_test_environment() ? 1 : calculate_packet_timeout(pkt_len);
392 received = recv_with_timeout(sockfd, payload, pkt_len, recv_timeout);
393 if (received < 0) {
394 buffer_pool_free(NULL, payload, pkt_len);
395 return SET_ERRNO_SYS(ERROR_NETWORK, "Failed to receive packet payload");
396 }
397 if (received != (ssize_t)pkt_len) {
398 buffer_pool_free(NULL, payload, pkt_len);
399 return SET_ERRNO(ERROR_NETWORK, "Partial packet payload received: %zd/%u bytes", received, pkt_len);
400 }
401
402 // Validate CRC32
403 if (packet_validate_crc32(payload, pkt_len, expected_crc) != ASCIICHAT_OK) {
404 buffer_pool_free(NULL, payload, pkt_len);
405 // Error context is already set by packet_validate_crc32
407 }
408 }
409
410 // Return results
411 *type = (packet_type_t)pkt_type;
412 *data = payload;
413 *len = pkt_len;
414
415 return ASCIICHAT_OK;
416}
asciichat_error_t packet_validate_crc32(const void *data, size_t len, uint32_t expected_crc)
Validate packet CRC32.
Definition packet.c:261
#define network_is_test_environment()
Check if we're in a test environment.
Definition network.h:147
asciichat_error_t packet_validate_header(const packet_header_t *header, uint16_t *pkt_type, uint32_t *pkt_len, uint32_t *expected_crc)
Validate packet header and return parsed information.
Definition packet.c:75
Network packet header structure.
Definition packet.h:490

References ASCIICHAT_OK, buffer_pool_alloc(), buffer_pool_free(), ERROR_INVALID_PARAM, ERROR_NETWORK, ERROR_NETWORK_PROTOCOL, INVALID_SOCKET_VALUE, log_warn, network_is_test_environment, packet_validate_crc32(), packet_validate_header(), RECV_TIMEOUT, recv_with_timeout(), SET_ERRNO, and SET_ERRNO_SYS.

Referenced by receive_packet().

◆ packet_send()

asciichat_error_t packet_send ( socket_t  sockfd,
packet_type_t  type,
const void *  data,
size_t  len 
)

#include <packet.h>

Send a packet with header and CRC32 checksum.

Parameters
sockfdSocket file descriptor
typePacket type (from packet_types.h)
dataPacket payload data (can be NULL for header-only packets)
lenPayload data length in bytes
Returns
ASCIICHAT_OK on success, error code on failure

Sends a complete packet with header (magic, type, length, CRC32) and optional payload. CRC32 is computed automatically and included in header.

Note
Packet header is constructed with all required fields including magic number, type, length, CRC32, and client ID.
CRC32 is computed over payload data (or zero if data is NULL).

Send a packet with header and CRC32 checksum.

Parameters
sockfdSocket file descriptor
typePacket type
dataPacket data
lenData length
Returns
0 on success, -1 on error

Definition at line 291 of file packet.c.

291 {
292 if (sockfd == INVALID_SOCKET_VALUE) {
293 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid socket descriptor");
294 }
295
296 if (len > MAX_PACKET_SIZE) {
297 return SET_ERRNO(ERROR_NETWORK_SIZE, "Packet too large: %zu > %d", len, MAX_PACKET_SIZE);
298 }
299
301 .type = HOST_TO_NET_U16((uint16_t)type),
302 .length = HOST_TO_NET_U32((uint32_t)len),
303 .crc32 = HOST_TO_NET_U32(len > 0 ? asciichat_crc32(data, len) : 0),
304 .client_id = HOST_TO_NET_U32(0)}; // Always initialize client_id to 0 in network byte order
305
306 // Calculate timeout based on packet size
307 int timeout = calculate_packet_timeout(len);
308
309 // Send header first
310 ssize_t sent = send_with_timeout(sockfd, &header, sizeof(header), timeout);
311 if (sent < 0) {
312 // Error context is already set by send_with_timeout
313 return ERROR_NETWORK;
314 }
315 if ((size_t)sent != sizeof(header)) {
316 return SET_ERRNO(ERROR_NETWORK, "Failed to fully send packet header. Sent %zd/%zu bytes", sent, sizeof(header));
317 }
318
319 // Send payload if present
320 if (len > 0 && data) {
321 // Check socket validity before sending payload to avoid race conditions
322 if (!socket_is_valid(sockfd)) {
323 return SET_ERRNO(ERROR_NETWORK, "Socket became invalid between header and payload send");
324 }
325 sent = send_with_timeout(sockfd, data, len, timeout);
326 // Check for error first to avoid signed/unsigned comparison issues
327 if (sent < 0) {
328 // Error context is already set by send_with_timeout
329 return ERROR_NETWORK;
330 }
331 if ((size_t)sent != len) {
332 return SET_ERRNO(ERROR_NETWORK, "Failed to fully send packet payload. Sent %zd/%zu bytes", sent, len);
333 }
334 }
335
336#ifdef DEBUG_NETWORK
337 log_debug("Sent packet type=%d, len=%zu, errno=%d (%s)", type, len, errno, SAFE_STRERROR(errno));
338#endif
339
340 return 0;
341}
#define SAFE_STRERROR(errnum)
Definition common.h:385
@ ERROR_NETWORK_SIZE
Definition error_codes.h:74
#define log_debug(...)
Log a DEBUG message.
uint32_t magic
Magic number (PACKET_MAGIC) for packet validation.
Definition packet.h:492
#define MAX_PACKET_SIZE
Maximum packet size (5MB)
Definition packet.h:113
#define PACKET_MAGIC
Packet magic number (0xDEADBEEF)
Definition packet.h:251
bool socket_is_valid(socket_t sock)
Check if a socket handle is valid.
#define asciichat_crc32(data, len)
Main CRC32 dispatcher macro - use this in application code.
Definition crc32.h:144

References asciichat_crc32, errno, ERROR_INVALID_PARAM, ERROR_NETWORK, ERROR_NETWORK_SIZE, HOST_TO_NET_U16, HOST_TO_NET_U32, INVALID_SOCKET_VALUE, log_debug, packet_header_t::magic, MAX_PACKET_SIZE, PACKET_MAGIC, SAFE_STRERROR, send_with_timeout(), SET_ERRNO, and socket_is_valid().

Referenced by packet_send_error(), packet_send_remote_log(), send_ascii_frame_packet(), send_image_frame_packet(), send_packet(), send_packet_secure(), and tcp_client_send_audio_opus().

◆ packet_send_error()

asciichat_error_t packet_send_error ( socket_t  sockfd,
const crypto_context_t crypto_ctx,
asciichat_error_t  error_code,
const char *  message 
)

#include <packet.h>

Send an error packet with optional encryption context.

Parameters
sockfdSocket file descriptor
crypto_ctxCrypto context for encryption (NULL or not ready sends plaintext)
error_codeError code from asciichat_error_t enumeration
messageHuman-readable message to accompany the error (can be NULL)
Returns
ASCIICHAT_OK on success, error code otherwise

When the crypto context is ready, the packet is encrypted automatically. During the handshake (or when encryption is disabled), the packet is sent in plaintext so protocol errors can be delivered before encryption is active.

Definition at line 807 of file packet.c.

808 {
809 if (sockfd == INVALID_SOCKET_VALUE) {
810 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid socket descriptor");
811 }
812
813 if (!message) {
814 message = "";
815 }
816
817 size_t message_len = strnlen(message, MAX_ERROR_MESSAGE_LENGTH);
818 if (message_len == MAX_ERROR_MESSAGE_LENGTH) {
819 log_warn("Error message truncated to %zu bytes", (size_t)MAX_ERROR_MESSAGE_LENGTH);
820 }
821
822 size_t payload_len = sizeof(error_packet_t) + message_len;
823 uint8_t *payload = SAFE_MALLOC(payload_len, uint8_t *);
824 if (!payload) {
825 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate %zu bytes for error packet", payload_len);
826 }
827
828 error_packet_t *packet = (error_packet_t *)payload;
830 packet->message_length = HOST_TO_NET_U32((uint32_t)message_len);
831
832 if (message_len > 0) {
833 memcpy(payload + sizeof(error_packet_t), message, message_len);
834 }
835
836 bool encryption_ready = crypto_ctx && crypto_is_ready(crypto_ctx);
837 asciichat_error_t send_result;
838
839 if (encryption_ready) {
840 send_result =
841 send_packet_secure(sockfd, PACKET_TYPE_ERROR_MESSAGE, payload, payload_len, (crypto_context_t *)crypto_ctx);
842 } else {
843 send_result = packet_send(sockfd, PACKET_TYPE_ERROR_MESSAGE, payload, payload_len);
844 }
845 SAFE_FREE(payload);
846
847 if (send_result != ASCIICHAT_OK) {
848 return SET_ERRNO(ERROR_NETWORK, "Failed to send error packet: %s", asciichat_error_string(send_result));
849 }
850
851 return ASCIICHAT_OK;
852}
bool crypto_is_ready(const crypto_context_t *ctx)
Check if key exchange is complete and ready for encryption.
@ PACKET_TYPE_ERROR_MESSAGE
Error packet with asciichat_error_t code and human-readable message.
Definition packet.h:352
Cryptographic context structure.

References ASCIICHAT_OK, crypto_is_ready(), error_code, error_packet_t::error_code, ERROR_INVALID_PARAM, ERROR_MEMORY, ERROR_NETWORK, HOST_TO_NET_U32, INVALID_SOCKET_VALUE, log_warn, MAX_ERROR_MESSAGE_LENGTH, error_packet_t::message_length, packet_send(), PACKET_TYPE_ERROR_MESSAGE, SAFE_FREE, SAFE_MALLOC, send_packet_secure(), and SET_ERRNO.

Referenced by disconnect_client_for_bad_data().

◆ packet_send_remote_log()

asciichat_error_t packet_send_remote_log ( socket_t  sockfd,
const crypto_context_t crypto_ctx,
log_level_t  level,
remote_log_direction_t  direction,
uint16_t  flags,
const char *  message 
)

#include <packet.h>

Send a remote log packet with optional encryption context.

Parameters
sockfdSocket file descriptor
crypto_ctxCrypto context for encryption (NULL or not ready sends plaintext)
levelLog level to transmit
directionDirection flag (REMOTE_LOG_DIRECTION_*)
flagsAdditional flags (REMOTE_LOG_FLAG_*)
messageLog message text
Returns
ASCIICHAT_OK on success, error code otherwise

<Message payload was truncated to fit the maximum length

Definition at line 896 of file packet.c.

897 {
898 if (sockfd == INVALID_SOCKET_VALUE) {
899 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid socket descriptor");
900 }
901
902 if (level < LOG_DEV || level > LOG_FATAL) {
903 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid log level: %d", level);
904 }
905
906 const char *safe_message = message ? message : "";
907 bool truncated = false;
908 size_t message_len = strnlen(safe_message, MAX_REMOTE_LOG_MESSAGE_LENGTH);
909 if (message_len == MAX_REMOTE_LOG_MESSAGE_LENGTH && safe_message[message_len] != '\0') {
910 truncated = true;
911 }
912
913 size_t payload_len = sizeof(remote_log_packet_t) + message_len;
914 uint8_t *payload = SAFE_MALLOC(payload_len, uint8_t *);
915 if (!payload) {
916 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate %zu bytes for remote log packet", payload_len);
917 }
918
919 remote_log_packet_t *packet = (remote_log_packet_t *)payload;
920 packet->log_level = (uint8_t)level;
921 packet->direction = (uint8_t)direction;
922 uint16_t final_flags = flags;
923 if (truncated) {
924 final_flags |= REMOTE_LOG_FLAG_TRUNCATED;
925 }
926 packet->flags = HOST_TO_NET_U16(final_flags);
927 packet->message_length = HOST_TO_NET_U32((uint32_t)message_len);
928
929 if (message_len > 0) {
930 memcpy(payload + sizeof(remote_log_packet_t), safe_message, message_len);
931 }
932
933 bool encryption_ready = crypto_ctx && crypto_is_ready(crypto_ctx);
934 asciichat_error_t send_result;
935
936 if (encryption_ready) {
937 int secure_result =
938 send_packet_secure(sockfd, PACKET_TYPE_REMOTE_LOG, payload, payload_len, (crypto_context_t *)crypto_ctx);
939 send_result = secure_result == 0 ? ASCIICHAT_OK : ERROR_NETWORK;
940 } else {
941 send_result = packet_send(sockfd, PACKET_TYPE_REMOTE_LOG, payload, payload_len);
942 }
943
944 SAFE_FREE(payload);
945
946 if (send_result != ASCIICHAT_OK) {
947 return SET_ERRNO(ERROR_NETWORK, "Failed to send remote log packet: %d", send_result);
948 }
949
950 return ASCIICHAT_OK;
951}
#define REMOTE_LOG_FLAG_TRUNCATED
Remote log packet flag definitions.
Definition packet.h:628
@ PACKET_TYPE_REMOTE_LOG
Bidirectional remote logging packet.
Definition packet.h:354

References ASCIICHAT_OK, crypto_is_ready(), remote_log_packet_t::direction, ERROR_INVALID_PARAM, ERROR_MEMORY, ERROR_NETWORK, remote_log_packet_t::flags, HOST_TO_NET_U16, HOST_TO_NET_U32, INVALID_SOCKET_VALUE, LOG_FATAL, remote_log_packet_t::log_level, MAX_REMOTE_LOG_MESSAGE_LENGTH, remote_log_packet_t::message_length, packet_send(), PACKET_TYPE_REMOTE_LOG, REMOTE_LOG_FLAG_TRUNCATED, SAFE_FREE, SAFE_MALLOC, send_packet_secure(), and SET_ERRNO.

◆ packet_validate_crc32()

asciichat_error_t packet_validate_crc32 ( const void *  data,
size_t  len,
uint32_t  expected_crc 
)

#include <packet.h>

Validate packet CRC32 checksum.

Parameters
dataPacket payload data
lenData length in bytes
expected_crcExpected CRC32 checksum value
Returns
ASCIICHAT_OK on success, error code on failure

Validates packet integrity by computing CRC32 checksum of payload and comparing with expected value. Uses hardware acceleration when available for optimal performance.

Note
CRC32 validation prevents corrupted packets from being processed.
Uses hardware-accelerated CRC32 when available (automatic fallback to software implementation).

Validate packet CRC32 checksum.

Parameters
dataPacket data
lenData length
expected_crcExpected CRC32 value
Returns
0 on success, -1 on error

Definition at line 261 of file packet.c.

261 {
262 if (!data && len > 0) {
263 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: data=%p but len=%zu", data, len);
264 }
265
266 if (len == 0) {
267 // Empty packets should have CRC32 of 0
268 if (expected_crc != 0) {
269 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid CRC32 for empty packet: 0x%x (expected 0)", expected_crc);
270 }
271 return 0;
272 }
273
274 uint32_t calculated_crc = asciichat_crc32(data, len);
275 if (calculated_crc != expected_crc) {
276 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "CRC32 mismatch: calculated 0x%x, expected 0x%x", calculated_crc,
277 expected_crc);
278 }
279
280 return ASCIICHAT_OK;
281}

References asciichat_crc32, ASCIICHAT_OK, ERROR_INVALID_PARAM, ERROR_NETWORK_PROTOCOL, and SET_ERRNO.

Referenced by packet_receive().

◆ packet_validate_header()

asciichat_error_t packet_validate_header ( const packet_header_t header,
uint16_t pkt_type,
uint32_t pkt_len,
uint32_t expected_crc 
)

#include <packet.h>

Validate packet header and extract information.

Parameters
headerPacket header to validate
pkt_typeOutput: Packet type
pkt_lenOutput: Packet payload length
expected_crcOutput: Expected CRC32 checksum
Returns
ASCIICHAT_OK on success, error code on failure

Validates packet header structure including magic number, type, and length fields. Extracts packet information for further processing.

Note
Validates magic number to detect corrupted packets.
All output parameters must be non-NULL.

Validate packet header and extract information.

Parameters
headerPacket header to validate
pkt_typeOutput: packet type
pkt_lenOutput: packet length
expected_crcOutput: expected CRC32
Returns
0 on success, -1 on error

Definition at line 75 of file packet.c.

76 {
77 if (!header || !pkt_type || !pkt_len || !expected_crc) {
78 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: header=%p, pkt_type=%p, pkt_len=%p, expected_crc=%p",
79 header, pkt_type, pkt_len, expected_crc);
80 }
81
82 // First validate packet length BEFORE converting from network byte order
83 // This prevents potential integer overflow issues
84 uint32_t pkt_len_network = header->length;
85 if (pkt_len_network == 0xFFFFFFFF) {
86 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid packet length in network byte order: 0xFFFFFFFF");
87 }
88
89 // Convert from network byte order using safe helpers
90 uint32_t magic = endian_unpack_u32(header->magic);
91 uint16_t type = endian_unpack_u16(header->type);
92 uint32_t len = endian_unpack_u32(pkt_len_network);
93 uint32_t crc = endian_unpack_u32(header->crc32);
94
95 // Validate magic
96 if (magic != PACKET_MAGIC) {
97 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid packet magic: 0x%x (expected 0x%x)", magic, PACKET_MAGIC);
98 }
99
100 // Validate packet size with bounds checking
101 if (len > MAX_PACKET_SIZE) {
102 return SET_ERRNO(ERROR_NETWORK_SIZE, "Packet too large: %u > %d", len, MAX_PACKET_SIZE);
103 }
104
105 // Validate packet type and size constraints
106 switch (type) {
108 // Protocol version packet has fixed size
109 if (len != sizeof(protocol_version_packet_t)) {
110 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid protocol version packet size: %u, expected %zu", len,
112 }
113 break;
115 // ASCII frame contains header + frame data
116 if (len < sizeof(ascii_frame_packet_t)) {
117 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid ASCII frame packet size: %u, minimum %zu", len,
118 sizeof(ascii_frame_packet_t));
119 }
120 break;
122 // Image frame contains header + pixel data
123 if (len < sizeof(image_frame_packet_t)) {
124 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid image frame packet size: %u, minimum %zu", len,
125 sizeof(image_frame_packet_t));
126 }
127 break;
129 if (len == 0 || len > AUDIO_SAMPLES_PER_PACKET * sizeof(float) * 2) { // Max stereo samples
130 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid audio packet size: %u", len);
131 }
132 break;
134 // Batch must have at least header + some samples
135 if (len < sizeof(audio_batch_packet_t) + sizeof(float)) {
136 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid audio batch packet size: %u", len);
137 }
138 break;
139 case PACKET_TYPE_PING:
140 case PACKET_TYPE_PONG:
141 if (len != 0) { // Ping/pong are just header packets and no payload.
142 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid ping/pong packet size: %u", len);
143 }
144 break;
146 // Client capabilities packet can be empty or contain capability data
147 if (len > 1024) { // Reasonable limit for capability data
148 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid client capabilities packet size: %u", len);
149 }
150 break;
152 if (len != sizeof(client_info_packet_t)) {
153 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid client join packet size: %u, expected %zu", len,
154 sizeof(client_info_packet_t));
155 }
156 break;
158 // Client leave packet can be empty or contain reason
159 if (len > 256) {
160 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid client leave packet size: %u", len);
161 }
162 break;
165 if (len != sizeof(uint32_t)) {
166 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid stream control packet size: %u, expected %zu", len,
167 sizeof(uint32_t));
168 }
169 break;
171 // Size message format: "SIZE:width,height"
172 if (len == 0 || len > 32) { // Reasonable size for "SIZE:1234,5678"
173 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid size message packet size: %u", len);
174 }
175 break;
177 // Audio message format: "AUDIO:num_samples"
178 if (len == 0 || len > 32) { // Reasonable size for "AUDIO:1234"
179 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid audio message packet size: %u", len);
180 }
181 break;
183 // Text message can be empty or contain message
184 if (len > 1024) { // Reasonable limit for text messages
185 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid text message packet size: %u", len);
186 }
187 break;
189 if (len < sizeof(error_packet_t)) {
190 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid error packet size: %u (minimum %zu)", len,
191 sizeof(error_packet_t));
192 }
193 if (len > sizeof(error_packet_t) + MAX_ERROR_MESSAGE_LENGTH) {
194 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Error packet message too large: %u (max %zu)", len,
195 sizeof(error_packet_t) + (size_t)MAX_ERROR_MESSAGE_LENGTH);
196 }
197 break;
198 // All crypto handshake packet types - validate using session parameters
210 // Crypto packets are validated by the crypto handshake context
211 // This is just a basic sanity check for extremely large packets
212 if (len > 65536) { // 64KB should be enough for even large post-quantum crypto packets
213 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Crypto packet too large: %u bytes (max 65536)", len);
214 }
215 // Note: Proper size validation is done in crypto_handshake_validate_packet_size()
216 // which uses the session's crypto parameters for accurate validation
217 break;
218 // ACIP protocol packets (Discovery Service)
236 // ACIP packets - basic size validation
237 // Discovery service packets can vary in size (variable-length strings, etc.)
238 if (len > 65536) { // 64KB max for discovery packets
239 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "ACIP packet too large: %u bytes (max 65536)", len);
240 }
241 break;
242 default:
243 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Unknown packet type: %u", type);
244 }
245
246 // Return parsed values
247 *pkt_type = type;
248 *pkt_len = len;
249 *expected_crc = crc;
250
251 return ASCIICHAT_OK;
252}
uint32_t length
Payload data length in bytes (0 for header-only packets)
Definition packet.h:496
uint16_t type
Packet type (packet_type_t enumeration)
Definition packet.h:494
uint32_t crc32
CRC32 checksum of payload data (0 if length == 0)
Definition packet.h:498
#define AUDIO_SAMPLES_PER_PACKET
Samples per audio packet (256 samples)
Definition packet.h:233
@ PACKET_TYPE_ACIP_WEBRTC_ICE
WebRTC ICE candidate (bidirectional)
Definition packet.h:390
@ PACKET_TYPE_CLIENT_LEAVE
Clean disconnect notification.
Definition packet.h:302
@ PACKET_TYPE_ACIP_SESSION_INFO
Session info response (Discovery Server -> Client)
Definition packet.h:375
@ PACKET_TYPE_IMAGE_FRAME
Complete RGB image with dimensions.
Definition packet.h:288
@ PACKET_TYPE_CRYPTO_AUTH_RESPONSE
Client -> Server: {HMAC[32]} (UNENCRYPTED)
Definition packet.h:323
@ PACKET_TYPE_TEXT_MESSAGE
Text message.
Definition packet.h:350
@ PACKET_TYPE_AUDIO_MESSAGE
Audio message.
Definition packet.h:348
@ PACKET_TYPE_PONG
Keepalive pong response.
Definition packet.h:297
@ PACKET_TYPE_ACIP_SESSION_RECONNECT
Reconnect to session (Client -> Discovery Server)
Definition packet.h:385
@ PACKET_TYPE_CRYPTO_HANDSHAKE_COMPLETE
Server -> Client: "encryption ready" (UNENCRYPTED)
Definition packet.h:329
@ PACKET_TYPE_STREAM_START
Client requests to start sending video/audio.
Definition packet.h:304
@ PACKET_TYPE_CRYPTO_KEY_EXCHANGE_INIT
Server -> Client: {server_pubkey[32]} (UNENCRYPTED)
Definition packet.h:317
@ PACKET_TYPE_ACIP_ERROR
Generic error response (Discovery Server -> Client)
Definition packet.h:404
@ PACKET_TYPE_AUDIO
Single audio packet (legacy)
Definition packet.h:291
@ PACKET_TYPE_CRYPTO_KEY_EXCHANGE_RESP
Client -> Server: {client_pubkey[32]} (UNENCRYPTED)
Definition packet.h:319
@ PACKET_TYPE_ACIP_STRING_RESERVE
Reserve session string (Client -> Discovery Server)
Definition packet.h:393
@ PACKET_TYPE_CRYPTO_AUTH_FAILED
Server -> Client: "authentication failed" (UNENCRYPTED)
Definition packet.h:325
@ PACKET_TYPE_ENCRYPTED
Encrypted packet (after handshake completion)
Definition packet.h:333
@ PACKET_TYPE_SIZE_MESSAGE
Terminal size message.
Definition packet.h:346
@ PACKET_TYPE_CRYPTO_SERVER_AUTH_RESP
Server -> Client: {HMAC[32]} server proves knowledge (UNENCRYPTED)
Definition packet.h:327
@ PACKET_TYPE_PROTOCOL_VERSION
Protocol version and capabilities negotiation.
Definition packet.h:283
@ PACKET_TYPE_CRYPTO_NO_ENCRYPTION
Client -> Server: "I want to proceed without encryption" (UNENCRYPTED)
Definition packet.h:331
@ PACKET_TYPE_ACIP_SESSION_CREATE
Create new session (Client -> Discovery Server)
Definition packet.h:369
@ PACKET_TYPE_ACIP_STRING_RESERVED
String reserved response (Discovery Server -> Client)
Definition packet.h:395
@ PACKET_TYPE_ACIP_DISCOVERY_PING
Discovery server ping (keepalive)
Definition packet.h:402
@ PACKET_TYPE_CRYPTO_AUTH_CHALLENGE
Server -> Client: {nonce[32]} (UNENCRYPTED)
Definition packet.h:321
@ PACKET_TYPE_CRYPTO_PARAMETERS
Server -> Client: Chosen algorithms + data sizes (UNENCRYPTED)
Definition packet.h:315
@ PACKET_TYPE_ACIP_SESSION_LOOKUP
Lookup session by string (Client -> Discovery Server)
Definition packet.h:373
@ PACKET_TYPE_CRYPTO_CAPABILITIES
Client -> Server: Supported crypto algorithms (UNENCRYPTED)
Definition packet.h:313
@ PACKET_TYPE_ACIP_SESSION_LEAVE
Leave session (Client -> Discovery Server)
Definition packet.h:381
@ PACKET_TYPE_ACIP_WEBRTC_SDP
WebRTC SDP offer/answer (bidirectional)
Definition packet.h:388
@ PACKET_TYPE_ACIP_SESSION_JOIN
Join existing session (Client -> Discovery Server)
Definition packet.h:377
@ PACKET_TYPE_ACIP_SESSION_CREATED
Session created response (Discovery Server -> Client)
Definition packet.h:371
@ PACKET_TYPE_ACIP_STRING_RELEASE
Release string reservation (Client -> Discovery Server)
Definition packet.h:399
@ PACKET_TYPE_CLIENT_JOIN
Client announces capability to send media.
Definition packet.h:300
@ PACKET_TYPE_CLIENT_CAPABILITIES
Client reports terminal capabilities.
Definition packet.h:293
@ PACKET_TYPE_ACIP_STRING_RENEW
Renew string reservation (Client -> Discovery Server)
Definition packet.h:397
@ PACKET_TYPE_AUDIO_BATCH
Batched audio packets for efficiency.
Definition packet.h:343
@ PACKET_TYPE_ACIP_SESSION_JOINED
Session joined response (Discovery Server -> Client)
Definition packet.h:379
@ PACKET_TYPE_STREAM_STOP
Client stops sending media.
Definition packet.h:306
@ PACKET_TYPE_ACIP_SESSION_END
End session (Host -> Discovery Server)
Definition packet.h:383
ASCII frame packet structure (Packet Type 2)
Definition packet.h:740
Audio batch packet structure (Packet Type 28)
Definition packet.h:796
Client information packet structure.
Definition packet.h:545
Image frame packet structure (Packet Type 3)
Definition packet.h:768
Protocol version negotiation packet structure (Packet Type 1)
Definition packet.h:710

References ASCIICHAT_OK, AUDIO_SAMPLES_PER_PACKET, packet_header_t::crc32, ERROR_INVALID_PARAM, ERROR_NETWORK_PROTOCOL, ERROR_NETWORK_SIZE, packet_header_t::length, packet_header_t::magic, MAX_ERROR_MESSAGE_LENGTH, MAX_PACKET_SIZE, PACKET_MAGIC, PACKET_TYPE_ACIP_DISCOVERY_PING, PACKET_TYPE_ACIP_ERROR, PACKET_TYPE_ACIP_SESSION_CREATE, PACKET_TYPE_ACIP_SESSION_CREATED, PACKET_TYPE_ACIP_SESSION_END, PACKET_TYPE_ACIP_SESSION_INFO, PACKET_TYPE_ACIP_SESSION_JOIN, PACKET_TYPE_ACIP_SESSION_JOINED, PACKET_TYPE_ACIP_SESSION_LEAVE, PACKET_TYPE_ACIP_SESSION_LOOKUP, PACKET_TYPE_ACIP_SESSION_RECONNECT, PACKET_TYPE_ACIP_STRING_RELEASE, PACKET_TYPE_ACIP_STRING_RENEW, PACKET_TYPE_ACIP_STRING_RESERVE, PACKET_TYPE_ACIP_STRING_RESERVED, PACKET_TYPE_ACIP_WEBRTC_ICE, PACKET_TYPE_ACIP_WEBRTC_SDP, PACKET_TYPE_ASCII_FRAME, PACKET_TYPE_AUDIO, PACKET_TYPE_AUDIO_BATCH, PACKET_TYPE_AUDIO_MESSAGE, PACKET_TYPE_CLIENT_CAPABILITIES, PACKET_TYPE_CLIENT_JOIN, PACKET_TYPE_CLIENT_LEAVE, PACKET_TYPE_CRYPTO_AUTH_CHALLENGE, PACKET_TYPE_CRYPTO_AUTH_FAILED, PACKET_TYPE_CRYPTO_AUTH_RESPONSE, PACKET_TYPE_CRYPTO_CAPABILITIES, PACKET_TYPE_CRYPTO_HANDSHAKE_COMPLETE, PACKET_TYPE_CRYPTO_KEY_EXCHANGE_INIT, PACKET_TYPE_CRYPTO_KEY_EXCHANGE_RESP, PACKET_TYPE_CRYPTO_NO_ENCRYPTION, PACKET_TYPE_CRYPTO_PARAMETERS, PACKET_TYPE_CRYPTO_SERVER_AUTH_RESP, PACKET_TYPE_ENCRYPTED, PACKET_TYPE_ERROR_MESSAGE, PACKET_TYPE_IMAGE_FRAME, PACKET_TYPE_PING, PACKET_TYPE_PONG, PACKET_TYPE_PROTOCOL_VERSION, PACKET_TYPE_SIZE_MESSAGE, PACKET_TYPE_STREAM_START, PACKET_TYPE_STREAM_STOP, PACKET_TYPE_TEXT_MESSAGE, SET_ERRNO, and packet_header_t::type.

Referenced by packet_receive().

◆ receive_packet()

int receive_packet ( socket_t  sockfd,
packet_type_t type,
void **  data,
size_t *  len 
)

#include <packet.h>

Receive a basic packet without encryption.

Parameters
sockfdSocket file descriptor
typeOutput: Packet type
dataOutput: Packet payload data (allocated by function)
lenOutput: Payload data length in bytes
Returns
0 on success, -1 on error

Receives a plaintext packet without decryption. Allocates buffer for payload data which must be freed by caller.

Note
Use receive_packet_secure() if decryption support is needed.
Warning
Allocated data buffer must be freed by caller.
Parameters
sockfdSocket file descriptor
typeOutput: packet type
dataOutput: packet data
lenOutput: data length
Returns
0 on success, -1 on error

Definition at line 767 of file packet.c.

767 {
768 asciichat_error_t result = packet_receive(sockfd, type, data, len);
769 return result == ASCIICHAT_OK ? 0 : -1;
770}

References ASCIICHAT_OK, and packet_receive().

Referenced by acds_client_handler(), acds_session_create(), acds_session_join(), acds_session_lookup(), client_crypto_handshake(), crypto_handshake_client_auth_response(), crypto_handshake_client_complete(), crypto_handshake_client_key_exchange(), crypto_handshake_server_auth_challenge(), crypto_handshake_server_complete(), and server_crypto_handshake().

◆ receive_packet_secure()

packet_recv_result_t receive_packet_secure ( socket_t  sockfd,
void *  crypto_ctx,
bool  enforce_encryption,
packet_envelope_t envelope 
)

#include <packet.h>

Receive a packet with decryption and decompression support.

Parameters
sockfdSocket file descriptor
crypto_ctxCryptographic context for decryption (NULL for plaintext)
enforce_encryptionIf true, reject unencrypted packets (except handshake)
envelopeOutput: Received packet envelope with all metadata
Returns
PACKET_RECV_SUCCESS on success, error code on failure

Receives a packet with automatic decryption (if encrypted) and decompression (if compressed). Validates encryption policy and packet integrity.

Note
Decryption is applied automatically when packet is encrypted and crypto_ctx is provided.
Decompression is applied automatically when packet is compressed.
If enforce_encryption is true, unencrypted packets (except handshake packets) cause PACKET_RECV_SECURITY_VIOLATION.
Warning
Envelope's allocated_buffer must be freed by caller to prevent memory leaks.
Parameters
sockfdSocket file descriptor
crypto_ctxCrypto context for decryption
enforce_encryptionWhether to require encryption
envelopeOutput: received packet envelope
Returns
Packet receive result

Definition at line 568 of file packet.c.

569 {
570
571 if (!envelope) {
572 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: envelope=%p", envelope);
573 return PACKET_RECV_ERROR;
574 }
575
576 // Initialize envelope
577 memset(envelope, 0, sizeof(*envelope));
578
579 // Receive packet header
580 packet_header_t header;
581 ssize_t received =
582 recv_with_timeout(sockfd, &header, sizeof(header), network_is_test_environment() ? 1 : RECV_TIMEOUT);
583
584 // Check for errors first (before comparing signed with unsigned)
585 if (received < 0) {
586 SET_ERRNO(ERROR_NETWORK, "Failed to receive packet header: %zd/%zu bytes", received, sizeof(header));
587 return PACKET_RECV_ERROR;
588 }
589
590 if (received == 0) {
591 return PACKET_RECV_EOF;
592 }
593
594 if ((size_t)received != sizeof(header)) {
595 SET_ERRNO(ERROR_NETWORK, "Failed to receive packet header: %zd/%zu bytes", received, sizeof(header));
596 return PACKET_RECV_ERROR;
597 }
598
599 // Convert from network byte order
600 uint32_t magic = NET_TO_HOST_U32(header.magic);
601 uint16_t pkt_type = NET_TO_HOST_U16(header.type);
602 uint32_t pkt_len = NET_TO_HOST_U32(header.length);
603 uint32_t expected_crc = NET_TO_HOST_U32(header.crc32);
604
605 // Validate magic number
606 if (magic != PACKET_MAGIC) {
607 SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid packet magic: 0x%x (expected 0x%x)", magic, PACKET_MAGIC);
608 return PACKET_RECV_ERROR;
609 }
610
611 // Validate packet size
612 if (pkt_len > MAX_PACKET_SIZE) {
613 SET_ERRNO(ERROR_NETWORK_SIZE, "Packet too large: %u > %d", pkt_len, MAX_PACKET_SIZE);
614 return PACKET_RECV_ERROR;
615 }
616
617 // Handle encrypted packets
618 if (pkt_type == PACKET_TYPE_ENCRYPTED) {
619 if (!crypto_ctx) {
620 SET_ERRNO(ERROR_CRYPTO, "Received encrypted packet but no crypto context");
621 return PACKET_RECV_ERROR;
622 }
623
624 // Read encrypted payload
625 uint8_t *ciphertext = buffer_pool_alloc(NULL, pkt_len);
626 if (!ciphertext) {
627 SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for ciphertext");
628 return PACKET_RECV_ERROR;
629 }
630
631 int recv_timeout = network_is_test_environment() ? 1 : calculate_packet_timeout(pkt_len);
632 received = recv_with_timeout(sockfd, ciphertext, pkt_len, recv_timeout);
633 if (received != (ssize_t)pkt_len) {
634 SET_ERRNO(ERROR_NETWORK, "Failed to receive encrypted payload: %zd/%u bytes", received, pkt_len);
635 buffer_pool_free(NULL, ciphertext, pkt_len);
636 return PACKET_RECV_ERROR;
637 }
638
639 // Decrypt - allocate plaintext buffer with extra space
640 // pkt_len is already validated to be <= MAX_PACKET_SIZE, so adding 1024 cannot overflow
641 size_t plaintext_size = (size_t)pkt_len + 1024;
642 uint8_t *plaintext = buffer_pool_alloc(NULL, plaintext_size);
643 if (!plaintext) {
644 SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for plaintext");
645 buffer_pool_free(NULL, ciphertext, pkt_len);
646 return PACKET_RECV_ERROR;
647 }
648
649 size_t plaintext_len;
650 crypto_result_t result = crypto_decrypt(crypto_ctx, ciphertext, pkt_len, plaintext, plaintext_size, &plaintext_len);
651 buffer_pool_free(NULL, ciphertext, pkt_len);
652
653 if (result != CRYPTO_OK) {
654 SET_ERRNO(ERROR_CRYPTO, "Failed to decrypt packet: %s", crypto_result_to_string(result));
655 buffer_pool_free(NULL, plaintext, plaintext_size);
656 return PACKET_RECV_ERROR;
657 }
658
659 if (plaintext_len < sizeof(packet_header_t)) {
660 SET_ERRNO(ERROR_CRYPTO, "Decrypted packet too small: %zu < %zu", plaintext_len, sizeof(packet_header_t));
661 buffer_pool_free(NULL, plaintext, plaintext_size);
662 return PACKET_RECV_ERROR;
663 }
664
665 // Parse decrypted header
666 packet_header_t *decrypted_header = (packet_header_t *)plaintext;
667 pkt_type = NET_TO_HOST_U16(decrypted_header->type);
668 pkt_len = NET_TO_HOST_U32(decrypted_header->length);
669 expected_crc = NET_TO_HOST_U32(decrypted_header->crc32);
670
671 // Extract payload
672 size_t payload_len = plaintext_len - sizeof(packet_header_t);
673 if (payload_len != pkt_len) {
674 SET_ERRNO(ERROR_CRYPTO, "Decrypted payload size mismatch: %zu != %u", payload_len, pkt_len);
675 buffer_pool_free(NULL, plaintext, plaintext_size);
676 return PACKET_RECV_ERROR;
677 }
678
679 // Verify CRC
680 if (pkt_len > 0) {
681 uint32_t actual_crc = asciichat_crc32(plaintext + sizeof(packet_header_t), pkt_len);
682 if (actual_crc != expected_crc) {
683 SET_ERRNO(ERROR_CRYPTO, "Decrypted packet CRC mismatch: 0x%x != 0x%x", actual_crc, expected_crc);
684 buffer_pool_free(NULL, plaintext, plaintext_size);
685 return PACKET_RECV_ERROR;
686 }
687 }
688
689 // Set envelope
690 envelope->type = (packet_type_t)pkt_type;
691 envelope->data = plaintext + sizeof(packet_header_t);
692 envelope->len = pkt_len;
693 envelope->allocated_buffer = plaintext;
694 envelope->allocated_size = plaintext_size;
695
696 return PACKET_RECV_SUCCESS;
697 }
698
699 // Handle unencrypted packets
700 if (enforce_encryption && !packet_is_handshake_type(pkt_type)) {
701 SET_ERRNO(ERROR_CRYPTO, "Received unencrypted packet type %d but encryption is required", pkt_type);
702 return PACKET_RECV_ERROR;
703 }
704
705 // Read payload
706 if (pkt_len > 0) {
707 uint8_t *payload = buffer_pool_alloc(NULL, pkt_len);
708 if (!payload) {
709 SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for payload");
710 return PACKET_RECV_ERROR;
711 }
712
713 int recv_timeout = network_is_test_environment() ? 1 : calculate_packet_timeout(pkt_len);
714 received = recv_with_timeout(sockfd, payload, pkt_len, recv_timeout);
715 if (received != (ssize_t)pkt_len) {
716 SET_ERRNO(ERROR_NETWORK, "Failed to receive payload: %zd/%u bytes", received, pkt_len);
717 buffer_pool_free(NULL, payload, pkt_len);
718 return PACKET_RECV_ERROR;
719 }
720
721 // Verify CRC
722 uint32_t actual_crc = asciichat_crc32(payload, pkt_len);
723 if (actual_crc != expected_crc) {
724 SET_ERRNO(ERROR_NETWORK, "Packet CRC mismatch: 0x%x != 0x%x", actual_crc, expected_crc);
725 buffer_pool_free(NULL, payload, pkt_len);
726 return PACKET_RECV_ERROR;
727 }
728
729 envelope->data = payload;
730 envelope->allocated_buffer = payload;
731 envelope->allocated_size = pkt_len;
732 }
733
734 envelope->type = (packet_type_t)pkt_type;
735 envelope->len = pkt_len;
736
737 return PACKET_RECV_SUCCESS;
738}
const char * crypto_result_to_string(crypto_result_t result)
Convert crypto result to human-readable string.
crypto_result_t
Cryptographic operation result codes.
crypto_result_t crypto_decrypt(crypto_context_t *ctx, const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *plaintext_out, size_t plaintext_out_size, size_t *plaintext_len_out)
Decrypt data using XSalsa20-Poly1305.
@ CRYPTO_OK
@ ERROR_CRYPTO
Definition error_codes.h:88
size_t allocated_size
Size of allocated buffer in bytes.
Definition packet.h:992

References packet_envelope_t::allocated_buffer, packet_envelope_t::allocated_size, asciichat_crc32, buffer_pool_alloc(), buffer_pool_free(), packet_header_t::crc32, crypto_decrypt(), CRYPTO_OK, crypto_result_to_string(), packet_envelope_t::data, ERROR_CRYPTO, ERROR_INVALID_PARAM, ERROR_MEMORY, ERROR_NETWORK, ERROR_NETWORK_PROTOCOL, ERROR_NETWORK_SIZE, packet_envelope_t::len, packet_header_t::length, packet_header_t::magic, MAX_PACKET_SIZE, NET_TO_HOST_U16, NET_TO_HOST_U32, network_is_test_environment, PACKET_MAGIC, PACKET_RECV_EOF, PACKET_RECV_ERROR, PACKET_RECV_SUCCESS, PACKET_TYPE_ENCRYPTED, RECV_TIMEOUT, recv_with_timeout(), SET_ERRNO, packet_header_t::type, and packet_envelope_t::type.

Referenced by acip_client_receive_and_dispatch(), and acip_server_receive_and_dispatch().

◆ recv_with_timeout()

ssize_t recv_with_timeout ( socket_t  sockfd,
void *  buf,
size_t  len,
int  timeout_seconds 
)

#include <network.h>

Receive data with timeout.

Parameters
sockfdSocket file descriptor
bufBuffer to receive data
lenLength of buffer in bytes
timeout_secondsTimeout in seconds
Returns
Number of bytes received on success, -1 on error

Receives data from socket with timeout support. Waits up to timeout_seconds for data to arrive.

Note
Partial receives are possible - function returns number of bytes actually received.
Returns -1 on timeout or error. Use network_error_string() to get human-readable error description.
Parameters
sockfdSocket file descriptor
bufBuffer to receive data
lenLength of buffer
timeout_secondsTimeout in seconds
Returns
Number of bytes received, or -1 on error

Definition at line 272 of file network.c.

272 {
273 if (sockfd == INVALID_SOCKET_VALUE) {
274 log_error("NETWORK_DEBUG: recv_with_timeout called with INVALID_SOCKET_VALUE");
275 errno = EBADF;
276 return -1;
277 }
278
279 fd_set read_fds;
280 struct timeval timeout;
281 ssize_t total_received = 0;
282 char *data = (char *)buf;
283
284 while (total_received < (ssize_t)len) {
285 // Set up select for read timeout
286 socket_fd_zero(&read_fds);
287 socket_fd_set(sockfd, &read_fds);
288
289 timeout.tv_sec = network_is_test_environment() ? 1 : timeout_seconds;
290 timeout.tv_usec = 0;
291
292 int result = socket_select(sockfd, &read_fds, NULL, NULL, &timeout);
293 if (result <= 0) {
294 if (result == 0) {
295 SET_ERRNO_SYS(ERROR_NETWORK_TIMEOUT, "recv_with_timeout timed out after %d seconds", timeout_seconds);
296 return -1;
297 }
298 if (network_handle_select_error(result)) {
299 continue; // Retry
300 }
301 return -1; // Fatal error
302 }
303
304 // Check if socket is ready
305 if (!socket_fd_isset(sockfd, &read_fds)) {
306 SET_ERRNO_SYS(ERROR_NETWORK_TIMEOUT, "recv_with_timeout socket not ready after select");
307 return -1;
308 }
309
310 // Calculate how much we still need to receive
311 size_t bytes_to_recv = len - (size_t)total_received;
312 ssize_t received = network_platform_recv(sockfd, data + total_received, bytes_to_recv);
313
314 if (received < 0) {
315 int error = errno;
316 log_error("NETWORK_DEBUG: network_platform_recv failed with error %d (errno=%d), sockfd=%d, buf=%p, len=%zu",
317 received, error, sockfd, data + total_received, bytes_to_recv);
318 if (network_handle_recv_error(error)) {
319 log_debug("NETWORK_DEBUG: retrying after error %d", error);
320 continue; // Retry
321 }
322 log_error("NETWORK_DEBUG: fatal error %d, giving up", error);
323 return -1; // Fatal error
324 }
325
326 if (received == 0) {
327 // Connection closed by peer
328 log_debug("Connection closed by peer during recv");
329 return total_received; // Return what we got so far
330 }
331
332 total_received += received;
333 }
334
335 return total_received;
336}

References EBADF, errno, ERROR_NETWORK_TIMEOUT, INVALID_SOCKET_VALUE, log_debug, log_error, network_is_test_environment, SET_ERRNO_SYS, socket_fd_isset(), socket_fd_set(), socket_fd_zero(), and socket_select().

Referenced by packet_receive(), and receive_packet_secure().

◆ send_ascii_frame_packet()

asciichat_error_t send_ascii_frame_packet ( socket_t  sockfd,
const char *  frame_data,
size_t  frame_size 
)

#include <packet.h>

Send ASCII frame packet.

Parameters
sockfdSocket file descriptor
frame_dataASCII frame data buffer
frame_sizeSize of frame data in bytes
Returns
ASCIICHAT_OK on success, error code on failure

Sends PACKET_TYPE_ASCII_FRAME with ASCII text data. Used for transmitting terminal output or text-based frames.

Note
Frame dimensions (width, height) are set to 0 and determined by receiver.

Definition at line 1191 of file packet.c.

1191 {
1192 if (!frame_data || frame_size == 0) {
1193 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: frame_data=%p, frame_size=%zu", frame_data, frame_size);
1194 }
1195
1196 // Create ASCII frame packet
1197 ascii_frame_packet_t packet;
1198 packet.width = 0; // Will be set by receiver
1199 packet.height = 0; // Will be set by receiver
1200 packet.original_size = (uint32_t)frame_size;
1201 packet.compressed_size = 0;
1202 packet.checksum = 0;
1203 packet.flags = 0;
1204
1205 // Calculate total packet size with overflow checking
1206 size_t total_size;
1207 if (checked_size_add(sizeof(ascii_frame_packet_t), frame_size, &total_size) != ASCIICHAT_OK) {
1208 return SET_ERRNO(ERROR_INVALID_PARAM, "Packet size calculation would overflow");
1209 }
1210
1211 // Allocate buffer for complete packet
1212 void *packet_data = buffer_pool_alloc(NULL, total_size);
1213 if (!packet_data) {
1214 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for ASCII frame packet: %zu bytes", total_size);
1215 }
1216
1217 // Copy packet header and frame data
1218 memcpy(packet_data, &packet, sizeof(ascii_frame_packet_t));
1219 memcpy((char *)packet_data + sizeof(ascii_frame_packet_t), frame_data, frame_size);
1220
1221 // Send packet
1222 asciichat_error_t result = packet_send(sockfd, PACKET_TYPE_ASCII_FRAME, packet_data, total_size);
1223
1224 // Clean up
1225 buffer_pool_free(NULL, packet_data, total_size);
1226
1227 return result;
1228}
uint32_t width
Terminal width in characters.
Definition packet.h:742
uint32_t checksum
CRC32 checksum of original ASCII data.
Definition packet.h:750
uint32_t original_size
Size of original uncompressed ASCII data in bytes.
Definition packet.h:746
uint32_t height
Terminal height in characters.
Definition packet.h:744
uint32_t compressed_size
Size of compressed data (0 = not compressed)
Definition packet.h:748
uint32_t flags
Frame flags bitmask (HAS_COLOR, IS_COMPRESSED, etc.)
Definition packet.h:752

References ASCIICHAT_OK, buffer_pool_alloc(), buffer_pool_free(), ascii_frame_packet_t::checksum, ascii_frame_packet_t::compressed_size, ERROR_INVALID_PARAM, ERROR_MEMORY, ascii_frame_packet_t::flags, ascii_frame_packet_t::height, ascii_frame_packet_t::original_size, packet_send(), PACKET_TYPE_ASCII_FRAME, SET_ERRNO, and ascii_frame_packet_t::width.

◆ send_audio_batch_packet()

asciichat_error_t send_audio_batch_packet ( socket_t  sockfd,
const float *  samples,
int  num_samples,
int  batch_count,
crypto_context_t crypto_ctx 
)

#include <packet.h>

Send a batched audio packet with encryption support.

Parameters
sockfdSocket file descriptor
samplesFloat audio samples buffer
num_samplesTotal number of audio samples
batch_countNumber of chunks in batch
crypto_ctxCryptographic context for encryption (NULL for plaintext)
Returns
ASCIICHAT_OK on success, error code on failure

Sends PACKET_TYPE_AUDIO_BATCH with multiple audio chunks batched together. Reduces packet overhead by sending 32 chunks (~186ms) per packet. Uses system-defined AUDIO_SAMPLE_RATE and mono audio.

Note
Encryption is applied automatically when crypto_ctx is provided.

Definition at line 1072 of file packet.c.

1073 {
1074 if (!samples || num_samples <= 0 || batch_count <= 0) {
1075 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid audio batch: samples=%p, num_samples=%d, batch_count=%d", samples,
1076 num_samples, batch_count);
1077 }
1078
1079 // Build batch header
1080 audio_batch_packet_t header;
1081 header.batch_count = HOST_TO_NET_U32((u_long)batch_count);
1082 header.total_samples = HOST_TO_NET_U32((u_long)num_samples);
1083 header.sample_rate = HOST_TO_NET_U32(AUDIO_SAMPLE_RATE); // Use system-defined sample rate
1084 header.channels = HOST_TO_NET_U32(1UL); // Mono for now
1085
1086 // Calculate total payload size
1087 size_t data_size = (size_t)num_samples * sizeof(uint32_t); // Send as 32-bit integers for portability
1088 size_t total_size = sizeof(header) + data_size;
1089
1090 // Allocate buffer for header + data
1091 uint8_t *buffer = buffer_pool_alloc(NULL, total_size);
1092 if (!buffer) {
1093 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for audio batch packet");
1094 }
1095
1096 // Copy header
1097 memcpy(buffer, &header, sizeof(header));
1098
1099 // Convert floats to network byte order (as 32-bit integers with scaling)
1100 // Floats in range [-1.0, 1.0] are scaled to INT32 range for transmission
1101 // Use memcpy to avoid alignment issues when casting from uint8_t* to uint32_t*
1102 uint8_t *sample_data_ptr = buffer + sizeof(header);
1103 for (int i = 0; i < num_samples; i++) {
1104 // Clamp samples to [-1.0, 1.0] range before scaling to prevent overflow
1105 float clamped_sample = samples[i];
1106 if (clamped_sample > 1.0f)
1107 clamped_sample = 1.0f;
1108 if (clamped_sample < -1.0f)
1109 clamped_sample = -1.0f;
1110
1111 // Scale float [-1.0, 1.0] to int32 range and convert to network byte order
1112 int32_t scaled = (int32_t)(clamped_sample * 2147483647.0f);
1113 uint32_t network_value = HOST_TO_NET_U32((uint32_t)scaled);
1114 memcpy(sample_data_ptr + (size_t)i * sizeof(uint32_t), &network_value, sizeof(uint32_t));
1115 }
1116
1117#ifndef NDEBUG
1118 // Debug: Log first few samples to verify conversion
1119 static int send_count = 0;
1120 send_count++;
1121 if (send_count % 100 == 0) {
1122 log_info("SEND: samples[0]=%.6f, samples[1]=%.6f, samples[2]=%.6f", (double)samples[0], (double)samples[1],
1123 (double)samples[2]);
1124 log_info("SEND: scaled[0]=%d, scaled[1]=%d, scaled[2]=%d", (int32_t)(samples[0] * 2147483647.0f),
1125 (int32_t)(samples[1] * 2147483647.0f), (int32_t)(samples[2] * 2147483647.0f));
1126 }
1127#endif
1128
1129 // Send packet with encryption support
1130 asciichat_error_t result = send_packet_secure(sockfd, PACKET_TYPE_AUDIO_BATCH, buffer, total_size, crypto_ctx);
1131 buffer_pool_free(NULL, buffer, total_size);
1132
1133 return result;
1134}
#define AUDIO_SAMPLE_RATE
Audio sample rate (48kHz professional quality, Opus-compatible)
uint32_t channels
Number of audio channels (1=mono, 2=stereo)
Definition packet.h:804
uint32_t batch_count
Number of audio chunks in this batch (usually AUDIO_BATCH_COUNT = 32)
Definition packet.h:798
uint32_t sample_rate
Sample rate in Hz (e.g., 44100, 48000)
Definition packet.h:802
uint32_t total_samples
Total audio samples across all chunks (typically 8192)
Definition packet.h:800

References AUDIO_SAMPLE_RATE, audio_batch_packet_t::batch_count, buffer_pool_alloc(), buffer_pool_free(), audio_batch_packet_t::channels, ERROR_INVALID_PARAM, ERROR_MEMORY, HOST_TO_NET_U32, log_info, PACKET_TYPE_AUDIO_BATCH, audio_batch_packet_t::sample_rate, send_packet_secure(), SET_ERRNO, and audio_batch_packet_t::total_samples.

Referenced by client_send_thread_func(), tcp_client_send_audio_batch(), and threaded_send_audio_batch_packet().

◆ send_clear_console_packet()

int send_clear_console_packet ( socket_t  sockfd)

#include <packet.h>

Send a clear console packet.

Parameters
sockfdSocket file descriptor
Returns
0 on success, -1 on error

Sends a PACKET_TYPE_CLEAR_CONSOLE packet to request client to clear terminal display.

Parameters
sockfdSocket file descriptor
Returns
0 on success, -1 on error

Definition at line 803 of file packet.c.

803 {
804 return send_packet(sockfd, PACKET_TYPE_CLEAR_CONSOLE, NULL, 0);
805}
int send_packet(socket_t sockfd, packet_type_t type, const void *data, size_t len)
Send a basic packet without encryption.
Definition packet.c:754
@ PACKET_TYPE_CLEAR_CONSOLE
Server tells client to clear console.
Definition packet.h:308

References PACKET_TYPE_CLEAR_CONSOLE, and send_packet().

◆ send_crypto_capabilities_packet()

int send_crypto_capabilities_packet ( socket_t  sockfd,
const crypto_capabilities_packet_t caps 
)

#include <packet.h>

Send crypto capabilities packet.

Parameters
sockfdSocket file descriptor
capsCrypto capabilities packet structure
Returns
0 on success, -1 on error

Sends a PACKET_TYPE_CRYPTO_CAPABILITIES packet to advertise supported cryptographic algorithms (key exchange, authentication, cipher).

Note
Crypto capabilities packets are always sent unencrypted (handshake packets).
Parameters
sockfdSocket file descriptor
capsCrypto capabilities packet
Returns
0 on success, -1 on error

Definition at line 1030 of file packet.c.

1030 {
1031 if (!caps) {
1032 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: caps=%p", caps);
1033 return -1;
1034 }
1035 return send_packet(sockfd, PACKET_TYPE_CRYPTO_CAPABILITIES, caps, sizeof(*caps));
1036}

References ERROR_INVALID_PARAM, PACKET_TYPE_CRYPTO_CAPABILITIES, send_packet(), and SET_ERRNO.

Referenced by client_crypto_handshake().

◆ send_crypto_parameters_packet()

int send_crypto_parameters_packet ( socket_t  sockfd,
const crypto_parameters_packet_t params 
)

#include <packet.h>

Send crypto parameters packet.

Parameters
sockfdSocket file descriptor
paramsCrypto parameters packet structure
Returns
0 on success, -1 on error

Sends a PACKET_TYPE_CRYPTO_PARAMETERS packet containing chosen cryptographic algorithms and data sizes for handshake continuation.

Note
Crypto parameters packets are always sent unencrypted (handshake packets).
Parameters
sockfdSocket file descriptor
paramsCrypto parameters packet
Returns
0 on success, -1 on error

Definition at line 1044 of file packet.c.

1044 {
1045 if (!params) {
1046 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: params=%p", params);
1047 return -1;
1048 }
1049
1050 // Create a copy and convert uint16_t fields to network byte order
1051 crypto_parameters_packet_t net_params = *params;
1052 log_debug("NETWORK_DEBUG: Before htons: kex=%u, auth=%u, sig=%u, secret=%u", params->kex_public_key_size,
1053 params->auth_public_key_size, params->signature_size, params->shared_secret_size);
1056 net_params.signature_size = HOST_TO_NET_U16(params->signature_size);
1058 log_debug("NETWORK_DEBUG: After htons: kex=%u, auth=%u, sig=%u, secret=%u", net_params.kex_public_key_size,
1059 net_params.auth_public_key_size, net_params.signature_size, net_params.shared_secret_size);
1060
1061 return send_packet(sockfd, PACKET_TYPE_CRYPTO_PARAMETERS, &net_params, sizeof(net_params));
1062}
uint16_t auth_public_key_size
Authentication public key size in bytes (e.g., 32 for Ed25519, 1952 for Dilithium3)
Definition packet.h:885
uint16_t signature_size
Signature size in bytes (e.g., 64 for Ed25519, 3309 for Dilithium3)
Definition packet.h:887
uint16_t shared_secret_size
Shared secret size in bytes (e.g., 32 for X25519)
Definition packet.h:889
uint16_t kex_public_key_size
Key exchange public key size in bytes (e.g., 32 for X25519, 1568 for Kyber1024)
Definition packet.h:883
Crypto parameters packet structure (Packet Type 15)
Definition packet.h:873

References crypto_parameters_packet_t::auth_public_key_size, ERROR_INVALID_PARAM, HOST_TO_NET_U16, crypto_parameters_packet_t::kex_public_key_size, log_debug, PACKET_TYPE_CRYPTO_PARAMETERS, send_packet(), SET_ERRNO, crypto_parameters_packet_t::shared_secret_size, and crypto_parameters_packet_t::signature_size.

Referenced by server_crypto_handshake().

◆ send_image_frame_packet()

asciichat_error_t send_image_frame_packet ( socket_t  sockfd,
const void *  image_data,
uint16_t  width,
uint16_t  height,
uint8_t  format 
)

#include <packet.h>

Send image frame packet.

Parameters
sockfdSocket file descriptor
image_dataImage pixel data buffer
widthImage width in pixels
heightImage height in pixels
formatPixel format (0=RGB24)
Returns
ASCIICHAT_OK on success, error code on failure

Sends PACKET_TYPE_IMAGE_FRAME with RGB image data. Used for transmitting camera frames or video input.

Note
Maximum dimensions: 4096x4096 pixels (~25MB per frame).
Pixel data must be in RGB24 format (3 bytes per pixel).

Definition at line 1230 of file packet.c.

1231 {
1232 if (!image_data || width == 0 || height == 0) {
1233 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: image_data=%p, width=%u, height=%u", image_data, width,
1234 height);
1235 }
1236
1237 // Validate dimensions to prevent integer overflow
1238 // Max reasonable dimensions: 4K (3840x2160) = ~25MB per frame
1239 if (width > 4096 || height > 4096) {
1240 return SET_ERRNO(ERROR_INVALID_PARAM, "Image dimensions too large: %ux%u (max 4096x4096)", width, height);
1241 }
1242
1243 // Create image frame packet
1244 image_frame_packet_t packet;
1245 packet.width = width;
1246 packet.height = height;
1247 packet.pixel_format = format;
1248 packet.compressed_size = 0;
1249 packet.checksum = 0;
1250 packet.timestamp = 0; // Will be set by receiver
1251
1252 // Calculate total packet size
1253 // Cast to size_t before multiplication to prevent integer overflow
1254 // Use overflow-checked multiplication
1255 size_t width_times_height;
1256 if (checked_size_mul((size_t)width, (size_t)height, &width_times_height) != ASCIICHAT_OK) {
1257 return SET_ERRNO(ERROR_BUFFER_OVERFLOW, "Image dimensions too large: %d x %d", width, height);
1258 }
1259
1260 size_t frame_size;
1261 if (checked_size_mul(width_times_height, 3u, &frame_size) != ASCIICHAT_OK) {
1262 return SET_ERRNO(ERROR_BUFFER_OVERFLOW, "Frame size overflow for RGB format");
1263 }
1264
1265 size_t total_size;
1266 if (checked_size_add(sizeof(image_frame_packet_t), frame_size, &total_size) != ASCIICHAT_OK) {
1267 return SET_ERRNO(ERROR_BUFFER_OVERFLOW, "Total packet size overflow");
1268 }
1269
1270 // Allocate buffer for complete packet
1271 void *packet_data = buffer_pool_alloc(NULL, total_size);
1272 if (!packet_data) {
1273 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for image frame packet: %zu bytes", total_size);
1274 }
1275
1276 // Copy packet header and image data
1277 memcpy(packet_data, &packet, sizeof(image_frame_packet_t));
1278 memcpy((char *)packet_data + sizeof(image_frame_packet_t), image_data, frame_size);
1279
1280 // Send packet
1281 asciichat_error_t result = packet_send(sockfd, PACKET_TYPE_IMAGE_FRAME, packet_data, total_size);
1282
1283 // Clean up
1284 buffer_pool_free(NULL, packet_data, total_size);
1285
1286 return result;
1287}
@ ERROR_BUFFER_OVERFLOW
Definition error_codes.h:98
uint32_t pixel_format
Pixel format enum (0=RGB24, 1=RGBA32, 2=BGR24, etc.)
Definition packet.h:774
uint32_t timestamp
Timestamp when frame was captured (milliseconds since epoch)
Definition packet.h:780
uint32_t compressed_size
Compressed data size (0 = not compressed, >0 = compressed)
Definition packet.h:776
uint32_t checksum
CRC32 checksum of pixel data.
Definition packet.h:778
uint32_t height
Image height in pixels.
Definition packet.h:772
uint32_t width
Image width in pixels.
Definition packet.h:770

References ASCIICHAT_OK, buffer_pool_alloc(), buffer_pool_free(), image_frame_packet_t::checksum, image_frame_packet_t::compressed_size, ERROR_BUFFER_OVERFLOW, ERROR_INVALID_PARAM, ERROR_MEMORY, image_frame_packet_t::height, packet_send(), PACKET_TYPE_IMAGE_FRAME, image_frame_packet_t::pixel_format, SET_ERRNO, image_frame_packet_t::timestamp, and image_frame_packet_t::width.

◆ send_packet()

int send_packet ( socket_t  sockfd,
packet_type_t  type,
const void *  data,
size_t  len 
)

#include <packet.h>

Send a basic packet without encryption.

Parameters
sockfdSocket file descriptor
typePacket type (from packet_types.h)
dataPacket payload data
lenPayload data length in bytes
Returns
0 on success, -1 on error

Sends a plaintext packet without encryption. Equivalent to packet_send() but returns int instead of asciichat_error_t for compatibility.

Note
Use send_packet_secure() if encryption support is needed.
Parameters
sockfdSocket file descriptor
typePacket type
dataPacket data
lenData length
Returns
0 on success, -1 on error

Definition at line 754 of file packet.c.

754 {
755 asciichat_error_t result = packet_send(sockfd, type, data, len);
756 return result == ASCIICHAT_OK ? 0 : -1;
757}

References ASCIICHAT_OK, and packet_send().

Referenced by acds_session_create(), acds_session_join(), acds_session_lookup(), acip_server_send_error(), crypto_handshake_client_key_exchange(), crypto_handshake_rekey_complete(), crypto_handshake_rekey_request(), crypto_handshake_rekey_response(), crypto_handshake_server_auth_challenge(), crypto_handshake_server_complete(), crypto_handshake_server_start(), send_clear_console_packet(), send_crypto_capabilities_packet(), send_crypto_parameters_packet(), send_error_packet_message(), send_ping_packet(), send_pong_packet(), send_protocol_version_packet(), signaling_relay_ice(), and signaling_relay_sdp().

◆ send_packet_secure()

asciichat_error_t send_packet_secure ( socket_t  sockfd,
packet_type_t  type,
const void *  data,
size_t  len,
crypto_context_t crypto_ctx 
)

#include <packet.h>

Send a packet with encryption and compression support.

Parameters
sockfdSocket file descriptor
typePacket type (from packet_types.h)
dataPacket payload data
lenPayload data length in bytes
crypto_ctxCryptographic context for encryption (NULL for plaintext)
Returns
0 on success, negative on error

Sends a packet with automatic encryption (if crypto context provided) and compression (if packet is large enough). Handshake packets are never encrypted.

Note
Encryption is applied automatically when crypto_ctx is provided and packet type is not a handshake packet.
Compression is applied automatically to large packets based on size thresholds and compression ratios.
Handshake packets (packet_is_handshake_type(type) == true) are always sent unencrypted, even when crypto_ctx is provided.
Parameters
sockfdSocket file descriptor
typePacket type
dataPacket data
lenData length
crypto_ctxCrypto context for encryption
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 433 of file packet.c.

434 {
435 if (len > MAX_PACKET_SIZE) {
436 return SET_ERRNO(ERROR_NETWORK_SIZE, "Packet too large: %zu > %d", len, MAX_PACKET_SIZE);
437 }
438
439 // Handshake packets are ALWAYS sent unencrypted
440 if (packet_is_handshake_type(type)) {
441 return packet_send(sockfd, type, data, len);
442 }
443
444 // Apply compression if beneficial for large packets
445 const void *final_data = data;
446 size_t final_len = len;
447 void *compressed_data = NULL;
448
449 // Skip compression for pre-compressed data (Opus audio) or if --no-compress flag is set
450 bool should_skip_compression = packet_is_precompressed(type) || GET_OPTION(no_compress);
451 if (!should_skip_compression && len > COMPRESSION_MIN_SIZE && should_compress(len, len)) {
452 void *temp_compressed = NULL;
453 size_t compressed_size = 0;
454
455 // Use configured compression level from options (default: 1 for fastest compression)
456 int compression_level = (GET_OPTION(compression_level) > 0) ? GET_OPTION(compression_level) : 1;
457 asciichat_error_t compress_result = compress_data(data, len, &temp_compressed, &compressed_size, compression_level);
458 if (compress_result == ASCIICHAT_OK) {
459 double ratio = (double)compressed_size / (double)len;
460 if (ratio < COMPRESSION_RATIO_THRESHOLD) {
461 final_data = temp_compressed;
462 final_len = compressed_size;
463 compressed_data = temp_compressed;
464 log_debug("Compressed packet: %zu -> %zu bytes (%.1f%%)", len, compressed_size, ratio * 100.0);
465 } else {
466 SAFE_FREE(temp_compressed);
467 }
468 }
469 }
470
471 // If no crypto context or crypto not ready, send unencrypted
472 bool ready = crypto_ctx ? crypto_is_ready(crypto_ctx) : false;
473 if (!crypto_ctx || !ready) {
474 log_warn_every(LOG_RATE_FAST, "CRYPTO_DEBUG: Sending packet type %d UNENCRYPTED (crypto_ctx=%p, ready=%d)", type,
475 (void *)crypto_ctx, ready);
476 asciichat_error_t result = packet_send(sockfd, type, final_data, final_len);
477 if (compressed_data) {
478 SAFE_FREE(compressed_data);
479 }
480 if (result != ASCIICHAT_OK) {
481 SET_ERRNO(ERROR_NETWORK, "Failed to send packet: %s", asciichat_error_string(result));
482 }
483 return result;
484 }
485
486 // Encrypt the packet: create header + payload, encrypt everything, wrap in PACKET_TYPE_ENCRYPTED
488 .type = HOST_TO_NET_U16((uint16_t)type),
489 .length = HOST_TO_NET_U32((uint32_t)final_len),
490 .crc32 = HOST_TO_NET_U32(final_len > 0 ? asciichat_crc32(final_data, final_len) : 0),
491 .client_id = HOST_TO_NET_U32(0)}; // Always 0 - client_id is not used in practice
492
493 // Combine header + payload for encryption
494 // Check for integer overflow before addition
495 if (final_len > SIZE_MAX - sizeof(header)) {
496 if (compressed_data) {
497 SAFE_FREE(compressed_data);
498 }
499 return SET_ERRNO(ERROR_NETWORK_SIZE, "Packet too large: would overflow plaintext buffer size");
500 }
501 size_t plaintext_len = sizeof(header) + final_len;
502 uint8_t *plaintext = buffer_pool_alloc(NULL, plaintext_len);
503 if (!plaintext) {
504 if (compressed_data) {
505 SAFE_FREE(compressed_data);
506 }
507 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for plaintext packet");
508 }
509
510 memcpy(plaintext, &header, sizeof(header));
511 if (final_len > 0 && final_data) {
512 memcpy(plaintext + sizeof(header), final_data, final_len);
513 }
514
515 // Encrypt
516 // Check for integer overflow before calculating ciphertext size
517 if (plaintext_len > SIZE_MAX - CRYPTO_NONCE_SIZE - CRYPTO_MAC_SIZE) {
518 buffer_pool_free(NULL, plaintext, plaintext_len);
519 if (compressed_data) {
520 SAFE_FREE(compressed_data);
521 }
522 return SET_ERRNO(ERROR_NETWORK_SIZE, "Packet too large: would overflow ciphertext buffer size");
523 }
524 size_t ciphertext_size = plaintext_len + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE;
525 uint8_t *ciphertext = buffer_pool_alloc(NULL, ciphertext_size);
526 if (!ciphertext) {
527 buffer_pool_free(NULL, plaintext, plaintext_len);
528 if (compressed_data) {
529 SAFE_FREE(compressed_data);
530 }
531 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate buffer for ciphertext");
532 }
533
534 size_t ciphertext_len;
535 crypto_result_t result =
536 crypto_encrypt(crypto_ctx, plaintext, plaintext_len, ciphertext, ciphertext_size, &ciphertext_len);
537 buffer_pool_free(NULL, plaintext, plaintext_len);
538
539 if (result != CRYPTO_OK) {
540 buffer_pool_free(NULL, ciphertext, ciphertext_size);
541 if (compressed_data) {
542 SAFE_FREE(compressed_data);
543 }
544 return SET_ERRNO(ERROR_CRYPTO, "Failed to encrypt packet: %s", crypto_result_to_string(result));
545 }
546
547 // Send as PACKET_TYPE_ENCRYPTED
548 log_debug_every(LOG_RATE_SLOW, "CRYPTO_DEBUG: Sending encrypted packet (original type %d as PACKET_TYPE_ENCRYPTED)",
549 type);
550 asciichat_error_t send_result = packet_send(sockfd, PACKET_TYPE_ENCRYPTED, ciphertext, ciphertext_len);
551 buffer_pool_free(NULL, ciphertext, ciphertext_size);
552
553 if (compressed_data) {
554 SAFE_FREE(compressed_data);
555 }
556
557 return send_result;
558}
#define COMPRESSION_MIN_SIZE
Minimum packet size to attempt compression (1KB)
Definition compression.h:61
bool should_compress(size_t original_size, size_t compressed_size)
Determine if compression should be used for given data sizes.
Definition compression.c:74
asciichat_error_t compress_data(const void *input, size_t input_size, void **output, size_t *output_size, int compression_level)
Compress data using zstd with configurable compression level.
Definition compression.c:14
#define COMPRESSION_RATIO_THRESHOLD
Compression ratio threshold - only use if <80% original size.
Definition compression.h:58
crypto_result_t crypto_encrypt(crypto_context_t *ctx, const uint8_t *plaintext, size_t plaintext_len, uint8_t *ciphertext_out, size_t ciphertext_out_size, size_t *ciphertext_len_out)
Encrypt data using XSalsa20-Poly1305.
#define CRYPTO_NONCE_SIZE
Nonce size (XSalsa20)
#define CRYPTO_MAC_SIZE
MAC size (Poly1305)
#define LOG_RATE_FAST
Log rate limit: 1 second (1,000,000 microseconds)
Definition log_rates.h:26
#define LOG_RATE_SLOW
Log rate limit: 10 seconds (10,000,000 microseconds)
Definition log_rates.h:35
#define log_debug_every(interval_us, fmt,...)
Rate-limited DEBUG logging.
#define log_warn_every(interval_us, fmt,...)
Rate-limited WARN logging.
#define GET_OPTION(field)
Safely get a specific option field (lock-free read)
Definition options.h:644
#define false
Definition stdbool.h:24

References asciichat_crc32, ASCIICHAT_OK, buffer_pool_alloc(), buffer_pool_free(), compress_data(), COMPRESSION_MIN_SIZE, COMPRESSION_RATIO_THRESHOLD, crypto_encrypt(), crypto_is_ready(), CRYPTO_MAC_SIZE, CRYPTO_NONCE_SIZE, CRYPTO_OK, crypto_result_to_string(), ERROR_CRYPTO, ERROR_MEMORY, ERROR_NETWORK, ERROR_NETWORK_SIZE, GET_OPTION, HOST_TO_NET_U16, HOST_TO_NET_U32, log_debug, log_debug_every, LOG_RATE_FAST, LOG_RATE_SLOW, log_warn_every, packet_header_t::magic, MAX_PACKET_SIZE, PACKET_MAGIC, packet_send(), PACKET_TYPE_ENCRYPTED, SAFE_FREE, SET_ERRNO, and should_compress().

Referenced by av_send_audio_opus_batch(), packet_send_error(), packet_send_remote_log(), send_audio_batch_packet(), tcp_client_send_audio_opus(), and tcp_client_send_packet().

◆ send_ping_packet()

int send_ping_packet ( socket_t  sockfd)

#include <packet.h>

Send a ping packet (keepalive)

Parameters
sockfdSocket file descriptor
Returns
0 on success, -1 on error

Sends a PACKET_TYPE_PING packet to keep connection alive. Server/client responds with PACKET_TYPE_PONG.

Note
Ping packets are always sent unencrypted (handshake packets).

Send a ping packet (keepalive)

Parameters
sockfdSocket file descriptor
Returns
0 on success, -1 on error

Definition at line 783 of file packet.c.

783 {
784 asciichat_error_t result = send_packet(sockfd, PACKET_TYPE_PING, NULL, 0);
785 return result == ASCIICHAT_OK ? 0 : -1;
786}

References ASCIICHAT_OK, PACKET_TYPE_PING, and send_packet().

◆ send_pong_packet()

int send_pong_packet ( socket_t  sockfd)

#include <packet.h>

Send a pong packet (keepalive response)

Parameters
sockfdSocket file descriptor
Returns
0 on success, -1 on error

Sends a PACKET_TYPE_PONG packet in response to PACKET_TYPE_PING. Indicates that connection is alive and responsive.

Note
Pong packets are always sent unencrypted (handshake packets).

Send a pong packet (keepalive response)

Parameters
sockfdSocket file descriptor
Returns
0 on success, -1 on error

Definition at line 793 of file packet.c.

793 {
794 asciichat_error_t result = send_packet(sockfd, PACKET_TYPE_PONG, NULL, 0);
795 return result == ASCIICHAT_OK ? 0 : -1;
796}

References ASCIICHAT_OK, PACKET_TYPE_PONG, and send_packet().

◆ send_protocol_version_packet()

int send_protocol_version_packet ( socket_t  sockfd,
const protocol_version_packet_t version 
)

#include <packet.h>

Send protocol version negotiation packet.

Parameters
sockfdSocket file descriptor
versionProtocol version packet structure
Returns
0 on success, -1 on error

Sends a PACKET_TYPE_PROTOCOL_VERSION packet for protocol capability negotiation. Both client and server send this during handshake.

Note
Protocol version packets are always sent unencrypted (handshake packets).

Send protocol version negotiation packet.

Parameters
sockfdSocket file descriptor
versionProtocol version packet
Returns
0 on success, -1 on error

Definition at line 1016 of file packet.c.

1016 {
1017 if (!version) {
1018 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters: version=%p", version);
1019 return -1;
1020 }
1021 return send_packet(sockfd, PACKET_TYPE_PROTOCOL_VERSION, version, sizeof(*version));
1022}

References ERROR_INVALID_PARAM, PACKET_TYPE_PROTOCOL_VERSION, send_packet(), and SET_ERRNO.

Referenced by client_crypto_handshake(), and server_crypto_handshake().

◆ send_with_timeout()

ssize_t send_with_timeout ( socket_t  sockfd,
const void *  data,
size_t  len,
int  timeout_seconds 
)

#include <network.h>

Send data with timeout using chunked transmission.

Parameters
sockfdSocket file descriptor
dataData to send
lenLength of data in bytes
timeout_secondsTimeout in seconds
Returns
Number of bytes sent on success, -1 on error

Sends data to socket with timeout support. Uses chunked transmission for large data to prevent blocking and enable progress tracking.

Note
Chunked transmission automatically handles large frames by sending in smaller chunks, preventing timeout issues.
Partial sends are handled automatically - function retries until all data is sent or timeout occurs.
Parameters
sockfdSocket file descriptor
dataData to send
lenLength of data
timeout_secondsTimeout in seconds
Returns
Number of bytes sent, or -1 on error

Definition at line 200 of file network.c.

200 {
201 if (sockfd == INVALID_SOCKET_VALUE) {
202 errno = EBADF;
203 return -1;
204 }
205
206 size_t total_sent = 0;
207 const char *data_ptr = (const char *)data;
208
209 while (total_sent < len) {
210 // Calculate chunk size
211 size_t bytes_to_send = len - total_sent;
212 const size_t MAX_CHUNK_SIZE = 65536; // 64KB chunks for reliable TCP transmission
213 if (bytes_to_send > MAX_CHUNK_SIZE) {
214 bytes_to_send = MAX_CHUNK_SIZE;
215 }
216
217 // Set up select for write timeout
218 fd_set write_fds;
219 struct timeval timeout;
220
221 socket_fd_zero(&write_fds);
222 socket_fd_set(sockfd, &write_fds);
223
224 timeout.tv_sec = network_is_test_environment() ? 1 : timeout_seconds;
225 timeout.tv_usec = 0;
226
227 int result = socket_select(sockfd, NULL, &write_fds, NULL, &timeout);
228 if (result <= 0) {
229 if (result == 0) {
230 SET_ERRNO_SYS(ERROR_NETWORK_TIMEOUT, "send_with_timeout timed out after %d seconds", timeout_seconds);
231 return -1;
232 }
233 if (network_handle_select_error(result)) {
234 continue; // Retry
235 }
236 return -1; // Fatal error
237 }
238
239 // Check if socket is ready for writing
240 if (!socket_fd_isset(sockfd, &write_fds)) {
241 SET_ERRNO_SYS(ERROR_NETWORK_TIMEOUT, "send_with_timeout socket not ready for writing after select");
242 return -1;
243 }
244
245 // Use platform-specific send
246 ssize_t sent = network_platform_send(sockfd, data_ptr + total_sent, bytes_to_send);
247
248 if (sent < 0) {
249 int error = errno;
250 if (network_handle_send_error(error)) {
251 continue; // Retry
252 }
253 return -1; // Fatal error
254 }
255
256 if (sent > 0) {
257 total_sent += (size_t)sent;
258 }
259 }
260
261 return (ssize_t)total_sent;
262}

References EBADF, errno, ERROR_NETWORK_TIMEOUT, INVALID_SOCKET_VALUE, network_is_test_environment, SET_ERRNO_SYS, socket_fd_isset(), socket_fd_set(), socket_fd_zero(), and socket_select().

Referenced by packet_send().

◆ set_socket_keepalive()

asciichat_error_t set_socket_keepalive ( socket_t  sockfd)

#include <network.h>

Enable TCP keepalive on socket.

Parameters
sockfdSocket file descriptor
Returns
ASCIICHAT_OK on success, error code on failure

Enables TCP keepalive probes on socket using KEEPALIVE_IDLE, KEEPALIVE_INTERVAL, and KEEPALIVE_COUNT settings.

Note
Keepalive helps detect dead connections (broken network path) without application-level heartbeats.

Enable TCP keepalive on socket.

Parameters
sockfdSocket file descriptor
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 461 of file network.c.

461 {
462 if (sockfd == INVALID_SOCKET_VALUE) {
463 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid socket file descriptor");
464 }
466 if (result != 0) {
467 return SET_ERRNO_SYS(ERROR_NETWORK, "Failed to set socket keepalive parameters");
468 }
469 return ASCIICHAT_OK;
470}
#define KEEPALIVE_COUNT
Keepalive probe count (8 probes)
Definition network.h:186
#define KEEPALIVE_INTERVAL
Keepalive interval in seconds (10 seconds)
Definition network.h:177
#define KEEPALIVE_IDLE
Keepalive idle time in seconds (60 seconds)
Definition network.h:168
int socket_set_keepalive_params(socket_t sock, bool enable, int idle, int interval, int count)
Set TCP keepalive parameters.

References ASCIICHAT_OK, ERROR_INVALID_PARAM, ERROR_NETWORK, INVALID_SOCKET_VALUE, KEEPALIVE_COUNT, KEEPALIVE_IDLE, KEEPALIVE_INTERVAL, SET_ERRNO, SET_ERRNO_SYS, and socket_set_keepalive_params().

◆ set_socket_nonblocking()

asciichat_error_t set_socket_nonblocking ( socket_t  sockfd)

#include <network.h>

Set socket to non-blocking mode.

Parameters
sockfdSocket file descriptor
Returns
ASCIICHAT_OK on success, error code on failure

Sets socket to non-blocking mode. I/O operations return immediately with error if data is not available.

Note
Non-blocking sockets require different error handling - EAGAIN/EWOULDBLOCK indicates operation would block.
Useful for asynchronous I/O patterns with select/poll/epoll.

Set socket to non-blocking mode.

Parameters
sockfdSocket file descriptor
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 477 of file network.c.

477 {
478 if (sockfd == INVALID_SOCKET_VALUE) {
479 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid socket file descriptor");
480 }
481 int result = socket_set_nonblocking(sockfd, true);
482 if (result != 0) {
483 return SET_ERRNO_SYS(ERROR_NETWORK, "Failed to set socket non-blocking mode");
484 }
485 return ASCIICHAT_OK;
486}
int socket_set_nonblocking(socket_t sock, bool nonblocking)
Set socket to non-blocking mode.

References ASCIICHAT_OK, ERROR_INVALID_PARAM, ERROR_NETWORK, INVALID_SOCKET_VALUE, SET_ERRNO, SET_ERRNO_SYS, and socket_set_nonblocking().

Referenced by connect_with_timeout().

◆ set_socket_timeout()

asciichat_error_t set_socket_timeout ( socket_t  sockfd,
int  timeout_seconds 
)

#include <network.h>

Set socket timeout for send/receive operations.

Parameters
sockfdSocket file descriptor
timeout_secondsTimeout in seconds
Returns
ASCIICHAT_OK on success, error code on failure

Configures socket-level timeout for send and receive operations. This sets SO_SNDTIMEO and SO_RCVTIMEO socket options.

Note
Socket-level timeouts work in addition to application-level timeouts in send_with_timeout() and recv_with_timeout().

Set socket timeout for send/receive operations.

Parameters
sockfdSocket file descriptor
timeout_secondsTimeout in seconds
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 436 of file network.c.

436 {
437 if (sockfd == INVALID_SOCKET_VALUE) {
438 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid socket file descriptor");
439 }
440
441 struct timeval timeout;
442 timeout.tv_sec = timeout_seconds;
443 timeout.tv_usec = 0;
444
445 if (socket_setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
446 return SET_ERRNO_SYS(ERROR_NETWORK, "Failed to set socket receive timeout");
447 }
448
449 if (socket_setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0) {
450 return SET_ERRNO_SYS(ERROR_NETWORK, "Failed to set socket send timeout");
451 }
452
453 return ASCIICHAT_OK;
454}
int socket_setsockopt(socket_t sock, int level, int optname, const void *optval, socklen_t optlen)
Set socket option.

References ASCIICHAT_OK, ERROR_INVALID_PARAM, ERROR_NETWORK, INVALID_SOCKET_VALUE, SET_ERRNO, SET_ERRNO_SYS, and socket_setsockopt().

◆ socket_configure_buffers()

asciichat_error_t socket_configure_buffers ( socket_t  sockfd)

#include <network.h>

Configure socket buffers and TCP_NODELAY for optimal performance.

Parameters
sockfdSocket file descriptor
Returns
ASCIICHAT_OK on success, or ERROR_NETWORK if all options fail

Configures socket with large send/receive buffers (1MB each) and enables TCP_NODELAY for low-latency real-time video streaming.

CONFIGURATION:

  • Send buffer: 1MB (SO_SNDBUF)
  • Receive buffer: 1MB (SO_RCVBUF)
  • TCP_NODELAY: enabled (disables Nagle's algorithm)

BEHAVIOR: Attempts to set all three socket options independently. Individual failures are logged as warnings but do not prevent attempting other options. This ensures TCP_NODELAY is always set even if buffer size configuration fails (common on systems with strict limits). Only returns error if ALL options fail.

Note
Large buffers prevent packet loss during frame bursts
TCP_NODELAY ensures frames are sent immediately without buffering
Call this immediately after socket creation/connection
Parameters
sockfdSocket file descriptor
Returns
ASCIICHAT_OK on success, ERROR_NETWORK_CONFIG on failure

Definition at line 493 of file network.c.

493 {
494 if (sockfd == INVALID_SOCKET_VALUE) {
495 return SET_ERRNO_SYS(ERROR_NETWORK, "Invalid socket file descriptor");
496 }
497
498 int failed_options = 0;
499
500 // Attempt to configure 1MB send buffer for optimal frame transmission
501 int send_buffer_size = 1024 * 1024;
502 if (socket_setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &send_buffer_size, sizeof(send_buffer_size)) < 0) {
503 log_warn("Failed to set send buffer size to 1MB: %s", network_error_string());
504 failed_options++;
505 }
506
507 // Attempt to configure 1MB receive buffer for optimal frame reception
508 int recv_buffer_size = 1024 * 1024;
509 if (socket_setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &recv_buffer_size, sizeof(recv_buffer_size)) < 0) {
510 log_warn("Failed to set receive buffer size to 1MB: %s", network_error_string());
511 failed_options++;
512 }
513
514 // Attempt to enable TCP_NODELAY to disable Nagle's algorithm for low-latency transmission
515 // CRITICAL: This must be set even if buffer configuration fails, as it's essential for real-time video
516 int tcp_nodelay = 1;
517 if (socket_setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &tcp_nodelay, sizeof(tcp_nodelay)) < 0) {
518 log_warn("Failed to set TCP_NODELAY: %s", network_error_string());
519 failed_options++;
520 }
521
522 // Return error only if ALL options failed
523 if (failed_options >= 3) {
524 return SET_ERRNO_SYS(ERROR_NETWORK, "Failed to configure all socket options");
525 }
526
527 return ASCIICHAT_OK;
528}

References ASCIICHAT_OK, ERROR_NETWORK, INVALID_SOCKET_VALUE, log_warn, network_error_string(), SET_ERRNO_SYS, and socket_setsockopt().

Referenced by server_connection_establish(), and tcp_client_connect().

Variable Documentation

◆ active_client_count

uint32_t server_state_packet_t::active_client_count

Number of clients actively sending video/audio streams.

Definition at line 602 of file packet.h.

Referenced by broadcast_server_state_to_all_clients(), and send_server_state_to_client().

◆ allocated_buffer

void* packet_envelope_t::allocated_buffer

Buffer that needs to be freed by caller (may be NULL if not allocated)

Definition at line 990 of file packet.h.

Referenced by acip_client_receive_and_dispatch(), acip_server_receive_and_dispatch(), and receive_packet_secure().

◆ allocated_size

size_t packet_envelope_t::allocated_size

Size of allocated buffer in bytes.

Definition at line 992 of file packet.h.

Referenced by acip_client_receive_and_dispatch(), acip_server_receive_and_dispatch(), and receive_packet_secure().

◆ auth_public_key_size

uint16_t crypto_parameters_packet_t::auth_public_key_size

Authentication public key size in bytes (e.g., 32 for Ed25519, 1952 for Dilithium3)

Definition at line 885 of file packet.h.

Referenced by client_crypto_handshake(), crypto_handshake_set_parameters(), send_crypto_parameters_packet(), and server_crypto_handshake().

◆ batch_count

uint32_t audio_batch_packet_t::batch_count

Number of audio chunks in this batch (usually AUDIO_BATCH_COUNT = 32)

Definition at line 798 of file packet.h.

Referenced by acip_send_audio_batch(), audio_parse_batch_header(), and send_audio_batch_packet().

◆ capabilities [1/2]

uint32_t client_info_packet_t::capabilities

Client capabilities bitmask (CLIENT_CAP_VIDEO | CLIENT_CAP_AUDIO | CLIENT_CAP_COLOR | CLIENT_CAP_STRETCH)

Definition at line 552 of file packet.h.

Referenced by handle_client_join_packet(), tcp_client_send_join(), and threaded_send_client_join_packet().

◆ capabilities [2/2]

uint32_t terminal_capabilities_packet_t::capabilities

Terminal capabilities bitmask (TERM_CAP_* flags)

Definition at line 911 of file packet.h.

Referenced by handle_client_capabilities_packet(), tcp_client_send_terminal_capabilities(), and threaded_send_terminal_size_with_auto_detect().

◆ channels

uint32_t audio_batch_packet_t::channels

Number of audio channels (1=mono, 2=stereo)

Definition at line 804 of file packet.h.

Referenced by acip_send_audio_batch(), audio_parse_batch_header(), and send_audio_batch_packet().

◆ checksum [1/2]

uint32_t ascii_frame_packet_t::checksum

CRC32 checksum of original ASCII data.

Definition at line 750 of file packet.h.

Referenced by acip_send_ascii_frame(), and send_ascii_frame_packet().

◆ checksum [2/2]

uint32_t image_frame_packet_t::checksum

CRC32 checksum of pixel data.

Definition at line 778 of file packet.h.

Referenced by acip_send_image_frame(), and send_image_frame_packet().

◆ client_count

uint32_t client_list_packet_t::client_count

Number of clients in the list (0 to MAX_CLIENTS)

Definition at line 584 of file packet.h.

◆ client_id [1/3]

uint32_t packet_header_t::client_id

Client ID (0 = server, >0 = client identifier)

Definition at line 500 of file packet.h.

Referenced by packet_queue_enqueue(), packet_send_via_transport(), and process_encrypted_packet().

◆ client_id [2/3]

uint32_t client_info_packet_t::client_id

Unique client identifier (1-9, 0 = server)

Definition at line 547 of file packet.h.

Referenced by tcp_client_send_join(), and threaded_send_client_join_packet().

◆ client_id [3/3]

uint32_t stream_header_t::client_id

Client ID that this stream originates from (1-9)

Definition at line 566 of file packet.h.

◆ clients

client_info_packet_t client_list_packet_t::clients[MAX_CLIENTS]

Array of client information structures.

Definition at line 586 of file packet.h.

◆ color_count

uint32_t terminal_capabilities_packet_t::color_count

Actual color count (16, 256, or 16777216)

Definition at line 915 of file packet.h.

Referenced by handle_client_capabilities_packet(), tcp_client_send_terminal_capabilities(), and threaded_send_terminal_size_with_auto_detect().

◆ color_level

uint32_t terminal_capabilities_packet_t::color_level

Color level enum value (terminal_color_mode_t)

Definition at line 913 of file packet.h.

Referenced by handle_client_capabilities_packet(), tcp_client_send_terminal_capabilities(), and threaded_send_terminal_size_with_auto_detect().

◆ colorterm

char terminal_capabilities_packet_t::colorterm[32]

$COLORTERM environment variable value (for debugging)

Definition at line 925 of file packet.h.

Referenced by handle_client_capabilities_packet(), tcp_client_send_terminal_capabilities(), and threaded_send_terminal_size_with_auto_detect().

◆ compressed_size [1/2]

uint32_t ascii_frame_packet_t::compressed_size

Size of compressed data (0 = not compressed)

Definition at line 748 of file packet.h.

Referenced by acip_send_ascii_frame(), and send_ascii_frame_packet().

◆ compressed_size [2/2]

uint32_t image_frame_packet_t::compressed_size

Compressed data size (0 = not compressed, >0 = compressed)

Definition at line 776 of file packet.h.

Referenced by acip_send_image_frame(), and send_image_frame_packet().

◆ compression_algorithms

uint8_t protocol_version_packet_t::compression_algorithms

Supported compression algorithms bitmask (COMPRESS_ALGO_*)

Definition at line 718 of file packet.h.

Referenced by client_crypto_handshake(), handle_protocol_version_packet(), and server_crypto_handshake().

◆ compression_threshold

uint8_t protocol_version_packet_t::compression_threshold

Compression threshold percentage (0-100, e.g., 80 = compress if >80% size reduction)

Definition at line 720 of file packet.h.

Referenced by client_crypto_handshake(), and server_crypto_handshake().

◆ connected_client_count

uint32_t server_state_packet_t::connected_client_count

Total number of currently connected clients.

Definition at line 600 of file packet.h.

Referenced by broadcast_server_state_to_all_clients(), and send_server_state_to_client().

◆ crc32

uint32_t packet_header_t::crc32

CRC32 checksum of payload data (0 if length == 0)

Definition at line 498 of file packet.h.

Referenced by packet_queue_enqueue(), packet_queue_try_dequeue(), packet_queue_validate_packet(), packet_send_via_transport(), packet_validate_header(), and receive_packet_secure().

◆ data

void* packet_envelope_t::data

Packet payload data (decrypted and decompressed if applicable)

Definition at line 984 of file packet.h.

Referenced by acip_client_receive_and_dispatch(), acip_server_receive_and_dispatch(), and receive_packet_secure().

◆ desired_fps

uint8_t terminal_capabilities_packet_t::desired_fps

Client's desired frame rate (1-144 FPS)

Definition at line 935 of file packet.h.

Referenced by handle_client_capabilities_packet(), tcp_client_send_terminal_capabilities(), and threaded_send_terminal_size_with_auto_detect().

◆ detection_reliable

uint8_t terminal_capabilities_packet_t::detection_reliable

Detection reliability flag (1=reliable detection, 0=best guess)

Definition at line 927 of file packet.h.

Referenced by handle_client_capabilities_packet(), tcp_client_send_terminal_capabilities(), and threaded_send_terminal_size_with_auto_detect().

◆ direction

uint8_t remote_log_packet_t::direction

Direction hint so receivers can annotate origin.

Definition at line 637 of file packet.h.

Referenced by acip_send_remote_log(), packet_parse_remote_log(), and packet_send_remote_log().

◆ display_name

char client_info_packet_t::display_name[MAX_DISPLAY_NAME_LEN]

User display name (null-terminated, max MAX_DISPLAY_NAME_LEN bytes)

Definition at line 549 of file packet.h.

Referenced by handle_client_join_packet(), tcp_client_send_join(), and threaded_send_client_join_packet().

◆ error_code

uint32_t error_packet_t::error_code

Error code from asciichat_error_t enumeration.

Definition at line 621 of file packet.h.

Referenced by acip_send_error(), packet_parse_error_message(), and packet_send_error().

◆ feature_flags

uint16_t protocol_version_packet_t::feature_flags

Feature flags bitmask (FEATURE_RLE_ENCODING, etc.)

Definition at line 722 of file packet.h.

Referenced by client_crypto_handshake(), handle_protocol_version_packet(), and server_crypto_handshake().

◆ flags [1/2]

uint16_t remote_log_packet_t::flags

Additional flags (REMOTE_LOG_FLAG_*)

Definition at line 639 of file packet.h.

Referenced by acip_send_remote_log(), packet_parse_remote_log(), and packet_send_remote_log().

◆ flags [2/2]

uint32_t ascii_frame_packet_t::flags

Frame flags bitmask (HAS_COLOR, IS_COMPRESSED, etc.)

Definition at line 752 of file packet.h.

Referenced by acip_send_ascii_frame(), and send_ascii_frame_packet().

◆ height [1/4]

uint32_t size_packet_t::height

Terminal height in characters.

Definition at line 533 of file packet.h.

Referenced by handle_size_packet().

◆ height [2/4]

uint32_t ascii_frame_packet_t::height

Terminal height in characters.

Definition at line 744 of file packet.h.

Referenced by acip_send_ascii_frame(), and send_ascii_frame_packet().

◆ height [3/4]

uint32_t image_frame_packet_t::height

Image height in pixels.

Definition at line 772 of file packet.h.

Referenced by acip_send_image_frame(), and send_image_frame_packet().

◆ height [4/4]

uint16_t terminal_capabilities_packet_t::height

◆ hmac_size

uint8_t crypto_parameters_packet_t::hmac_size

HMAC size in bytes (e.g., 32 for HMAC-SHA256)

Definition at line 895 of file packet.h.

Referenced by crypto_handshake_set_parameters(), and server_crypto_handshake().

◆ kex_public_key_size

uint16_t crypto_parameters_packet_t::kex_public_key_size

Key exchange public key size in bytes (e.g., 32 for X25519, 1568 for Kyber1024)

Definition at line 883 of file packet.h.

Referenced by client_crypto_handshake(), crypto_handshake_set_parameters(), send_crypto_parameters_packet(), and server_crypto_handshake().

◆ len

size_t packet_envelope_t::len

Length of payload data in bytes.

Definition at line 986 of file packet.h.

Referenced by acip_client_receive_and_dispatch(), acip_server_receive_and_dispatch(), and receive_packet_secure().

◆ length

uint32_t packet_header_t::length

Payload data length in bytes (0 for header-only packets)

Definition at line 496 of file packet.h.

Referenced by packet_queue_enqueue(), packet_queue_validate_packet(), packet_send_via_transport(), packet_validate_header(), and receive_packet_secure().

◆ log_level

uint8_t remote_log_packet_t::log_level

Log level associated with the message (log_level_t cast to uint8_t)

Definition at line 635 of file packet.h.

Referenced by acip_send_remote_log(), packet_parse_remote_log(), and packet_send_remote_log().

◆ mac_size

uint8_t crypto_parameters_packet_t::mac_size

MAC size in bytes (e.g., 16 for Poly1305)

Definition at line 893 of file packet.h.

Referenced by crypto_handshake_set_parameters(), and server_crypto_handshake().

◆ magic

◆ message_length [1/2]

uint32_t error_packet_t::message_length

Length of message payload in bytes (0-512)

Definition at line 623 of file packet.h.

Referenced by acip_send_error(), packet_parse_error_message(), and packet_send_error().

◆ message_length [2/2]

uint32_t remote_log_packet_t::message_length

Message payload length in bytes (0-512)

Definition at line 641 of file packet.h.

Referenced by acip_send_remote_log(), packet_parse_remote_log(), and packet_send_remote_log().

◆ nonce_size

uint8_t crypto_parameters_packet_t::nonce_size

Nonce size in bytes (e.g., 24 for XSalsa20)

Definition at line 891 of file packet.h.

Referenced by crypto_handshake_set_parameters(), and server_crypto_handshake().

◆ original_size

uint32_t ascii_frame_packet_t::original_size

Size of original uncompressed ASCII data in bytes.

Definition at line 746 of file packet.h.

Referenced by acip_send_ascii_frame(), and send_ascii_frame_packet().

◆ palette_custom

char terminal_capabilities_packet_t::palette_custom[64]

Custom palette characters (if palette_type == PALETTE_CUSTOM)

Definition at line 933 of file packet.h.

Referenced by handle_client_capabilities_packet(), tcp_client_send_terminal_capabilities(), and threaded_send_terminal_size_with_auto_detect().

◆ palette_type

uint32_t terminal_capabilities_packet_t::palette_type

Palette type enum value (palette_type_t)

Definition at line 931 of file packet.h.

Referenced by handle_client_capabilities_packet(), tcp_client_send_terminal_capabilities(), and threaded_send_terminal_size_with_auto_detect().

◆ pixel_format

uint32_t image_frame_packet_t::pixel_format

Pixel format enum (0=RGB24, 1=RGBA32, 2=BGR24, etc.)

Definition at line 774 of file packet.h.

Referenced by acip_send_image_frame(), and send_image_frame_packet().

◆ preferred_auth

uint8_t crypto_capabilities_packet_t::preferred_auth

Preferred authentication algorithm (AUTH_ALGO_*)

Definition at line 856 of file packet.h.

Referenced by client_crypto_handshake().

◆ preferred_cipher

uint8_t crypto_capabilities_packet_t::preferred_cipher

Preferred cipher algorithm (CIPHER_ALGO_*)

Definition at line 858 of file packet.h.

Referenced by client_crypto_handshake().

◆ preferred_kex

uint8_t crypto_capabilities_packet_t::preferred_kex

Preferred key exchange algorithm (KEX_ALGO_*)

Definition at line 854 of file packet.h.

Referenced by client_crypto_handshake().

◆ protocol_revision

uint16_t protocol_version_packet_t::protocol_revision

Minor protocol revision (server can be newer)

Definition at line 714 of file packet.h.

Referenced by client_crypto_handshake(), handle_protocol_version_packet(), and server_crypto_handshake().

◆ protocol_version

uint16_t protocol_version_packet_t::protocol_version

Major protocol version (must match for compatibility)

Definition at line 712 of file packet.h.

Referenced by client_crypto_handshake(), handle_protocol_version_packet(), and server_crypto_handshake().

◆ reason_flags

uint8_t auth_failure_packet_t::reason_flags

Bitmask of auth_failure_reason_t values indicating failure causes.

Definition at line 676 of file packet.h.

Referenced by crypto_handshake_client_complete(), crypto_handshake_server_auth_challenge(), and crypto_handshake_server_complete().

◆ render_mode

uint32_t terminal_capabilities_packet_t::render_mode

Render mode enum value (foreground/background/half-block)

Definition at line 917 of file packet.h.

Referenced by handle_client_capabilities_packet(), tcp_client_send_terminal_capabilities(), and threaded_send_terminal_size_with_auto_detect().

◆ requires_verification

uint8_t crypto_capabilities_packet_t::requires_verification

Server verification requirement flag (1=required, 0=optional)

Definition at line 852 of file packet.h.

Referenced by client_crypto_handshake().

◆ reserved [1/5]

uint8_t terminal_capabilities_packet_t::reserved[2]

Reserved bytes for alignment (must be zero)

Definition at line 937 of file packet.h.

Referenced by tcp_client_send_terminal_capabilities(), and threaded_send_terminal_size_with_auto_detect().

◆ reserved [2/5]

uint8_t crypto_parameters_packet_t::reserved[3]

Reserved bytes for future use (must be zero)

Definition at line 897 of file packet.h.

◆ reserved [3/5]

uint32_t server_state_packet_t::reserved[6]

Reserved fields for future use (must be zero)

Definition at line 604 of file packet.h.

Referenced by broadcast_server_state_to_all_clients(), and send_server_state_to_client().

◆ reserved [4/5]

uint8_t auth_failure_packet_t::reserved[7]

Reserved bytes for future use (must be zero)

Definition at line 678 of file packet.h.

◆ reserved [5/5]

uint8_t protocol_version_packet_t::reserved[7]

Reserved bytes for future expansion (must be zero)

Definition at line 724 of file packet.h.

Referenced by handle_protocol_version_packet().

◆ sample_rate

uint32_t audio_batch_packet_t::sample_rate

Sample rate in Hz (e.g., 44100, 48000)

Definition at line 802 of file packet.h.

Referenced by acip_send_audio_batch(), audio_parse_batch_header(), and send_audio_batch_packet().

◆ selected_auth

uint8_t crypto_parameters_packet_t::selected_auth

Selected authentication algorithm (AUTH_ALGO_*)

Definition at line 877 of file packet.h.

Referenced by client_crypto_handshake(), and server_crypto_handshake().

◆ selected_cipher

uint8_t crypto_parameters_packet_t::selected_cipher

Selected cipher algorithm (CIPHER_ALGO_*)

Definition at line 879 of file packet.h.

Referenced by client_crypto_handshake(), and server_crypto_handshake().

◆ selected_kex

uint8_t crypto_parameters_packet_t::selected_kex

Selected key exchange algorithm (KEX_ALGO_*)

Definition at line 875 of file packet.h.

Referenced by client_crypto_handshake(), and server_crypto_handshake().

◆ shared_secret_size

uint16_t crypto_parameters_packet_t::shared_secret_size

Shared secret size in bytes (e.g., 32 for X25519)

Definition at line 889 of file packet.h.

Referenced by client_crypto_handshake(), crypto_handshake_set_parameters(), send_crypto_parameters_packet(), and server_crypto_handshake().

◆ signature_size

uint16_t crypto_parameters_packet_t::signature_size

Signature size in bytes (e.g., 64 for Ed25519, 3309 for Dilithium3)

Definition at line 887 of file packet.h.

Referenced by client_crypto_handshake(), crypto_handshake_set_parameters(), send_crypto_parameters_packet(), and server_crypto_handshake().

◆ stream_type

uint32_t stream_header_t::stream_type

Stream type bitmask (STREAM_TYPE_VIDEO | STREAM_TYPE_AUDIO)

Definition at line 568 of file packet.h.

◆ supported_auth_algorithms

uint16_t crypto_capabilities_packet_t::supported_auth_algorithms

Supported authentication algorithms bitmask (AUTH_ALGO_*)

Definition at line 848 of file packet.h.

Referenced by client_crypto_handshake(), and server_crypto_handshake().

◆ supported_cipher_algorithms

uint16_t crypto_capabilities_packet_t::supported_cipher_algorithms

Supported cipher algorithms bitmask (CIPHER_ALGO_*)

Definition at line 850 of file packet.h.

Referenced by client_crypto_handshake(), and server_crypto_handshake().

◆ supported_kex_algorithms

uint16_t crypto_capabilities_packet_t::supported_kex_algorithms

Supported key exchange algorithms bitmask (KEX_ALGO_*)

Definition at line 846 of file packet.h.

Referenced by client_crypto_handshake(), and server_crypto_handshake().

◆ supports_encryption

uint8_t protocol_version_packet_t::supports_encryption

Encryption support flag (1=support encryption, 0=plaintext only)

Definition at line 716 of file packet.h.

Referenced by client_crypto_handshake(), handle_protocol_version_packet(), and server_crypto_handshake().

◆ term_type

char terminal_capabilities_packet_t::term_type[32]

$TERM environment variable value (for debugging)

Definition at line 923 of file packet.h.

Referenced by handle_client_capabilities_packet(), tcp_client_send_terminal_capabilities(), and threaded_send_terminal_size_with_auto_detect().

◆ timestamp [1/2]

uint32_t stream_header_t::timestamp

Timestamp when frame/audio was captured (milliseconds since epoch)

Definition at line 570 of file packet.h.

◆ timestamp [2/2]

uint32_t image_frame_packet_t::timestamp

Timestamp when frame was captured (milliseconds since epoch)

Definition at line 780 of file packet.h.

Referenced by acip_send_image_frame(), and send_image_frame_packet().

◆ total_samples

uint32_t audio_batch_packet_t::total_samples

Total audio samples across all chunks (typically 8192)

Definition at line 800 of file packet.h.

Referenced by acip_send_audio_batch(), audio_parse_batch_header(), and send_audio_batch_packet().

◆ type [1/2]

◆ type [2/2]

packet_type_t packet_envelope_t::type

Packet type (from packet_types.h)

Definition at line 982 of file packet.h.

Referenced by acip_client_receive_and_dispatch(), acip_server_receive_and_dispatch(), and receive_packet_secure().

◆ utf8_support

uint32_t terminal_capabilities_packet_t::utf8_support

UTF-8 support flag (0=no UTF-8, 1=UTF-8 supported)

Definition at line 929 of file packet.h.

Referenced by handle_client_capabilities_packet(), tcp_client_send_terminal_capabilities(), and threaded_send_terminal_size_with_auto_detect().

◆ verification_enabled

uint8_t crypto_parameters_packet_t::verification_enabled

Server verification enabled flag (1=enabled, 0=disabled)

Definition at line 881 of file packet.h.

Referenced by client_crypto_handshake(), and server_crypto_handshake().

◆ was_encrypted

bool packet_envelope_t::was_encrypted

True if packet was encrypted (decrypted before envelope creation)

Definition at line 988 of file packet.h.

◆ width [1/4]

uint32_t size_packet_t::width

Terminal width in characters.

Definition at line 531 of file packet.h.

Referenced by handle_size_packet().

◆ width [2/4]

uint32_t ascii_frame_packet_t::width

Terminal width in characters.

Definition at line 742 of file packet.h.

Referenced by acip_send_ascii_frame(), and send_ascii_frame_packet().

◆ width [3/4]

uint32_t image_frame_packet_t::width

Image width in pixels.

Definition at line 770 of file packet.h.

Referenced by acip_send_image_frame(), and send_image_frame_packet().

◆ width [4/4]

uint16_t terminal_capabilities_packet_t::width