ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
acds_client_io.c
Go to the documentation of this file.
1
2/* Storage capacities in elements; text buffers include the terminating NUL. */
3#define NETWORK_ACIP_ACDS_CLIENT_IO_ACDS_NAME_BUFFER_SIZE 64
4
19
21#include <ascii-chat/buffer.h>
22#include <ascii-chat/common.h>
25#include <ascii-chat/log/log.h>
30#include <libplatform/socket.h>
34
36#include <string.h>
37#include <time.h>
38#include <errno.h>
39
40static asciichat_error_t acds_client_handshake(acds_client_t *client) {
42 asciichat_error_t result = crypto_handshake_init("acds_client", client->handshake_ctx, false);
43 if (result != ASCIICHAT_OK)
44 return result;
45 crypto_policy_t policy = client->config.security_policy;
47 if (client->config.identity_key && client->config.identity_key[0]) {
49 if (result != ASCIICHAT_OK)
50 return result;
54 policy.has_identity = true;
55 }
56 uint8_t mode;
57 result = crypto_policy_resolve(&policy, &mode);
58 if (result != ASCIICHAT_OK)
59 return result;
61}
62
63#ifdef _WIN32
64#include <winsock2.h>
65#include <ws2tcpip.h>
66#else
67#include <netdb.h>
68#include <sys/socket.h>
69#include <sys/types.h>
70#include <sys/select.h>
71#include <fcntl.h>
72#endif
73
74// ============================================================================
75// Helper Functions
76// ============================================================================
77
79 if (!config) {
80 return;
81 }
82
83 memset(config, 0, sizeof(*config));
84 SAFE_STRNCPY(config->server_address, "127.0.0.1", sizeof(config->server_address));
86 config->timeout_ms = 5 * MS_PER_SEC_INT;
87}
88
89// ============================================================================
90// Connection Management
91// ============================================================================
92
94 if (!client || !config) {
95 return SET_ERRNO(ERROR_INVALID_PARAM, "client or config is NULL");
96 }
97
98 memset(client, 0, sizeof(*client));
99 memcpy(&client->config, config, sizeof(acds_client_config_t));
100 client->connected = false;
101
102 network_connect_config_t settings = {.timeout_ms = config->timeout_ms,
103 .should_exit_callback = config->should_exit_callback,
104 .callback_data = config->callback_data};
105 asciichat_error_t pconn_result = network_connection_open("acds", config->server_address, config->server_port,
106 &settings, &client->connection, NULL);
107 if (pconn_result == ASCIICHAT_OK) {
108 client->connected = true;
110
111 asciichat_error_t handshake_result = acds_client_handshake(client);
112 if (handshake_result != ASCIICHAT_OK) {
114 client->transport = NULL;
115 client->connected = false;
116 client->handshake_ctx = NULL;
117 return handshake_result;
118 }
119
121
122 /* Register ACDS client with named registry */
124 snprintf(acds_name, sizeof(acds_name), "acds_client:%s:%d", config->server_address, config->server_port);
125 NAMED_REGISTER(client, acds_name, "acds_client_t", "0x%tx", NULL);
126
127 log_info("Connected to ACDS server at %s:%d", config->server_address, config->server_port);
128 return ASCIICHAT_OK;
129 }
130
131 return pconn_result;
132}
133
135 if (!client) {
136 return;
137 }
138
140 client->transport = NULL;
141 client->handshake_ctx = NULL;
142
143 client->connected = false;
144 log_debug("Disconnected from ACDS server");
145}
146
147// ============================================================================
148// Session Management
149// ============================================================================
150
151static asciichat_error_t client_protocol_send(void *data, packet_type_t type, const void *payload, size_t length) {
152 acds_client_t *client = data;
153 return packet_send_via_transport(client->transport, type, payload, length, 0);
154}
155static asciichat_error_t client_protocol_receive(acds_client_t *client, acds_protocol_t *protocol) {
156 packet_type_t type;
157 void *payload = NULL, *allocation = NULL;
158 size_t length = 0;
159 asciichat_error_t result = packet_receive_via_transport(client->transport, &type, &payload, &length, &allocation);
160 if (result == ASCIICHAT_OK)
161 result = acds_protocol_receive(protocol, type, payload, length);
162 buffer_release(allocation);
163 return result;
164}
167 if (!client || !client->connected || !params || !result)
168 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid discovery create parameters");
169 acds_protocol_t protocol;
170 acds_protocol_init(&protocol, client_protocol_send, client);
171 asciichat_error_t error = acds_protocol_create(&protocol, params, 0, 0);
172 if (error == ASCIICHAT_OK)
173 error = client_protocol_receive(client, &protocol);
174 if (error == ASCIICHAT_OK) {
175 memset(result, 0, sizeof(*result));
176 SAFE_STRNCPY(result->session_string, protocol.name, sizeof(result->session_string));
177 memcpy(result->session_id, protocol.created.session_id, sizeof(result->session_id));
178 result->expires_at = protocol.created.expires_at;
179 }
180 acds_protocol_destroy(&protocol);
181 return error;
182}
184 if (!client || !client->connected || !name || !result)
185 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid discovery lookup parameters");
186 acds_protocol_t protocol;
187 acds_protocol_init(&protocol, client_protocol_send, client);
188 asciichat_error_t error = acds_protocol_lookup(&protocol, name);
189 if (error == ASCIICHAT_OK)
190 error = client_protocol_receive(client, &protocol);
191 if (error == ASCIICHAT_OK) {
192 memset(result, 0, sizeof(*result));
193 result->found = protocol.info.found;
194 if (result->found) {
195 memcpy(result->session_id, protocol.info.session_id, sizeof(result->session_id));
196 memcpy(result->host_pubkey, protocol.info.host_pubkey, sizeof(result->host_pubkey));
197 result->capabilities = protocol.info.capabilities;
198 result->max_participants = protocol.info.max_participants;
199 result->current_participants = protocol.info.current_participants;
200 result->has_password = protocol.info.has_password;
201 result->created_at = protocol.info.created_at;
202 result->expires_at = protocol.info.expires_at;
203 result->require_server_verify = protocol.info.require_server_verify;
204 result->require_client_verify = protocol.info.require_client_verify;
205 }
206 }
207 acds_protocol_destroy(&protocol);
208 return error;
209}
212 if (!client || !client->connected || !params || !result)
213 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid discovery join parameters");
214 acds_protocol_t protocol;
215 acds_protocol_init(&protocol, client_protocol_send, client);
216 memset(result, 0, sizeof(*result));
217 asciichat_error_t error = acds_protocol_join(&protocol, params);
218 if (error == ASCIICHAT_OK)
219 error = client_protocol_receive(client, &protocol);
220 result->success = protocol.joined.success;
221 result->error_code = protocol.joined.error_code;
222 SAFE_STRNCPY(result->error_message, protocol.joined.error_message, sizeof(result->error_message));
223 if (error == ASCIICHAT_OK) {
224 memcpy(result->participant_id, protocol.joined.participant_id, sizeof(result->participant_id));
225 memcpy(result->session_id, protocol.joined.session_id, sizeof(result->session_id));
226 result->session_type = protocol.joined.session_type;
227 SAFE_STRNCPY(result->server_address, protocol.joined.server_address, sizeof(result->server_address));
228 result->server_port = protocol.joined.server_port;
229 }
230 acds_protocol_destroy(&protocol);
231 return error;
232}
asciichat_error_t acds_protocol_join(acds_protocol_t *p, const acds_session_join_params_t *params)
void acds_protocol_init(acds_protocol_t *p, acds_protocol_send_fn send, void *user_data)
void acds_protocol_destroy(acds_protocol_t *p)
asciichat_error_t acds_protocol_lookup(acds_protocol_t *p, const char *name)
asciichat_error_t acds_protocol_create(acds_protocol_t *p, const acds_session_create_params_t *params, uint8_t total_keys, uint8_t key_index)
asciichat_error_t acds_protocol_receive(acds_protocol_t *p, packet_type_t type, const void *payload, size_t length)
void acds_client_config_init_defaults(acds_client_config_t *config)
Initialize ACDS client configuration with defaults.
asciichat_error_t acds_session_create(acds_client_t *client, const acds_session_create_params_t *params, acds_session_create_result_t *result)
Create a new session on the discovery server.
asciichat_error_t acds_session_lookup(acds_client_t *client, const char *name, acds_session_lookup_result_t *result)
Look up session by string.
asciichat_error_t acds_session_join(acds_client_t *client, const acds_session_join_params_t *params, acds_session_join_result_t *result)
Join an existing session.
asciichat_error_t acds_client_connect(acds_client_t *client, const acds_client_config_t *config)
Connect to ACDS server.
void acds_client_disconnect(acds_client_t *client)
Disconnect from ACDS server.
#define NETWORK_ACIP_ACDS_CLIENT_IO_ACDS_NAME_BUFFER_SIZE
struct acds_protocol acds_protocol_t
#define SET_ERRNO(code,...)
#define buffer_release(data)
Definition buffer.h:91
⚙️ Common definitions, error codes, macros, and types shared throughout the application
asciichat_error_t crypto_handshake_init(const char *name, crypto_handshake_context_t *ctx, bool is_server)
Initialize named crypto handshake context.
Named object registry for debugging — log identifiable resource names.
🔄 Network byte order conversion helpers
#define SAFE_STRNCPY(dst, src, size)
Definition common.h:423
unsigned char uint8_t
Definition common.h:60
#define NAMED_REGISTER(ptr, name, type, fmt, parent_ptr)
Register any pointer with base name, type, format spec, and location (auto-suffix).
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_INVALID_PARAM
uint8_t key[CRYPTO_PUBLIC_KEY_SIZE]
Definition key_types.h:74
asciichat_error_t parse_private_key(const char *key_path, private_key_t *key_out)
Parse SSH private key from file.
Definition keys.c:219
uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]
Definition key_types.h:105
key_type_t type
Definition key_types.h:73
@ KEY_TYPE_ED25519
Definition key_types.h:54
#define log_info(...)
Log an INFO message.
Definition log/log.h:608
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:595
#define ACIP_DISCOVERY_DEFAULT_PORT
Discovery server default port (use OPT_ACDS_PORT_INT_DEFAULT from options.h).
Definition acds.h:1102
#define MS_PER_SEC_INT
Definition time.h:176
packet_type_t
Network protocol packet type enumeration.
Definition packet.h:301
Client-side handshake functions.
Network error handling utilities.
void network_connection_destroy(network_connection_t **owner)
asciichat_error_t network_connection_open(const char *name, const char *address, uint16_t port, const network_connect_config_t *settings, network_connection_t **out, connection_endpoint_t *resolved)
void network_connection_ready(network_connection_t *c)
crypto_handshake_context_t * network_connection_handshake(network_connection_t *c)
bool network_connection_secure(network_connection_t *c)
acip_transport_t * network_connection_transport(network_connection_t *c)
📝 Logging API with multiple log levels and terminal output control
asciichat_error_t network_client_negotiate(acip_transport_t *transport, crypto_handshake_context_t *ctx, uint8_t mode, network_protocol_t protocol)
@ NETWORK_PROTOCOL_DISCOVERY
Definition negotiation.h:5
asciichat_error_t crypto_policy_resolve(const crypto_policy_t *policy, uint8_t *mode)
Definition policy.c:4
asciichat_error_t packet_receive_via_transport(acip_transport_t *transport, packet_type_t *type, void **payload, size_t *payload_len, void **alloc_buffer)
Receive a packet via transport with header parsing and validation.
Definition send.c:200
asciichat_error_t packet_send_via_transport(acip_transport_t *transport, packet_type_t type, const void *payload, size_t payload_len, uint32_t client_id)
Definition send.c:190
ACIP shared/bidirectional packet sending functions.
🔤 String Manipulation and Shell Escaping Utilities
acds client config is intentionally a small, concrete record. Fields such as server_port,...
char server_address[256]
ACDS server address (e.g., "discovery.ascii.chat" or "127.0.0.1").
uint32_t timeout_ms
Connection timeout in milliseconds.
uint16_t server_port
ACDS server port (default: 27225).
crypto_policy_t security_policy
Signaling policy, independent of peer media policy.
parallel_connect_should_exit_fn should_exit_callback
const char * identity_key
Optional private identity key path, borrowed during connect.
ACDS client connection handle.
crypto_handshake_context_t * handshake_ctx
Borrowed from connection owner.
acds_client_config_t config
bool connected
Connection status.
network_connection_t * connection
acip_transport_t * transport
Transport used for the initial crypto handshake.
acip_session_joined_t joined
acip_session_created_t created
acip_session_info_t info
Session creation request parameters.
Session creation result.
uint8_t session_id[16]
Session UUID.
char session_string[48+1]
Generated session string (null-terminated).
uint64_t expires_at
Expiration timestamp (Unix ms).
Session join parameters.
Session join result.
uint8_t error_code
Error code (if !success).
uint8_t session_type
acds_session_type_t: 0=DIRECT_TCP, 1=WEBRTC (if success)
uint8_t participant_id[16]
Participant UUID (if success).
bool success
Join succeeded.
uint16_t server_port
Server port (if success).
char error_message[128+1]
Error message (if !success, null-terminated).
uint8_t session_id[16]
Session UUID (if success).
char server_address[64+1]
Server IP/hostname (if success, null-terminated).
Session lookup result.
uint8_t capabilities
Session capabilities.
bool found
Session exists.
bool require_client_verify
ACDS policy: client must verify server identity.
bool has_password
Password required to join.
uint64_t expires_at
Expiration timestamp (Unix ms).
uint8_t max_participants
Maximum participants.
bool require_server_verify
ACDS policy: server must verify client identity.
uint64_t created_at
Creation timestamp (Unix ms).
uint8_t host_pubkey[32]
Host's Ed25519 public key.
uint8_t current_participants
Current participant count.
uint8_t session_id[16]
Session UUID (if found).
The useful part of crypto policy is in transport_secure, encrypt, no_encrypt, no_auth: together they ...
Definition policy.h:12
bool transport_secure
Definition policy.h:13
bool has_identity
Definition policy.h:18
For network connect config, this is the live record that ties timeout_ms, callback_data,...
⏱️ High-precision timing utilities using sokol_time.h and uthash