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

Go to the source code of this file.

Macros

#define SESSION_STRING_MAX_LEN   38
 Maximum length of a session string (without null terminator).
#define SESSION_STRING_BUFFER_SIZE   (SESSION_STRING_MAX_LEN + 1)
 Buffer size needed for session string storage (with null terminator) Used for static character array declarations.
#define ACDS_MAX_UNIQUE_SESSIONS   (2500LL * 5000LL * 5000LL)
 Maximum number of unique session strings that can be generated.

Functions

asciichat_error_t acds_string_generate (char *output, size_t output_size)
 Generate random session string.
asciichat_error_t acds_string_init (void)
 Initialize session string system with cached word validation.
bool is_session_string (const char *str)
 Check if a string is a valid session string.
void acds_strings_destroy (void)
 Cleanup function for session string cache Called by asciichat_shared_destroy() during library cleanup. Safe to call multiple times (idempotent).

Macro Definition Documentation

◆ ACDS_MAX_UNIQUE_SESSIONS

#define ACDS_MAX_UNIQUE_SESSIONS   (2500LL * 5000LL * 5000LL)

Maximum number of unique session strings that can be generated.

Calculated from wordlist entropy: 2500 adjectives × 5000 nouns × 5000 nouns = 62,500,000,000 combinations

Definition at line 46 of file discovery/strings.h.

◆ SESSION_STRING_BUFFER_SIZE

#define SESSION_STRING_BUFFER_SIZE   (SESSION_STRING_MAX_LEN + 1)

Buffer size needed for session string storage (with null terminator) Used for static character array declarations.

Definition at line 38 of file discovery/strings.h.

◆ SESSION_STRING_MAX_LEN

#define SESSION_STRING_MAX_LEN   38

Maximum length of a session string (without null terminator).

Calculated from longest words:

  • Longest adjective: 12 chars (e.g., "affectionate")
  • Longest noun: 12 chars (e.g., "acquaintance")
  • Format: adjective-noun-noun = 12 + 1 + 12 + 1 + 12 = 38 chars

Definition at line 32 of file discovery/strings.h.

Referenced by is_session_string().

Function Documentation

◆ acds_string_generate()

asciichat_error_t acds_string_generate ( char * output,
size_t output_size )

Generate random session string.

Parameters
outputOutput buffer for session string
output_sizeSize of output buffer (should be at least SESSION_STRING_BUFFER_SIZE bytes)
Returns
ASCIICHAT_OK on success, error code otherwise

Generates strings in format: adjective-noun-noun Example: "affectionate-acquaintance-acquaintance" (38 characters max)

Use acds_string_get_max_length() to get the maximum possible length. Entropy: 2500 adjectives * 5000 nouns * 5000 nouns = 62.5 billion combinations

Definition at line 235 of file discovery/strings.c.

235 {
236 if (!output || output_size < SESSION_STRING_BUFFER_SIZE) {
237 return SET_ERRNO(ERROR_INVALID_PARAM, "output buffer must be at least %zu bytes",
239 }
240
241 // libsodium is guaranteed to be initialized by acds_string_init() before this is called
242 // No need to call sodium_init() again (redundant initialization removed)
243
244 // Pick random adjective
245 uint32_t adj_idx = randombytes_uniform((uint32_t)adjectives_count);
246 const char *adj = adjectives[adj_idx];
247
248 // Pick two random nouns
249 uint32_t noun1_idx = randombytes_uniform((uint32_t)nouns_count);
250 uint32_t noun2_idx = randombytes_uniform((uint32_t)nouns_count);
251 const char *noun1 = nouns[noun1_idx];
252 const char *noun2 = nouns[noun2_idx];
253
254 // Format: adjective-noun-noun
255 int written = safe_snprintf(output, output_size, "%s-%s-%s", adj, noun1, noun2);
256 if (written < 0 || (size_t)written >= output_size) {
257 return SET_ERRNO(ERROR_BUFFER_OVERFLOW, "Session string too long for buffer");
258 }
259
260 log_dev("Generated session string: %s", output);
261 return ASCIICHAT_OK;
262}
const char * adjectives[]
Array of English adjectives for ACDS session naming.
Definition adjectives.c:51
const size_t adjectives_count
Count of adjectives in the adjectives array.
Definition adjectives.c:411
#define SET_ERRNO(code,...)
unsigned int uint32_t
Definition common.h:62
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_INVALID_PARAM
@ ERROR_BUFFER_OVERFLOW
#define log_dev(...)
Log a DEV message (most verbose, development only).
Definition log/log.h:581
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Platform-safe snprintf wrapper.
const char * nouns[]
Array of English nouns for session and client naming.
Definition nouns.c:55
const size_t nouns_count
Count of nouns in the nouns array.
Definition nouns.c:772
#define SESSION_STRING_BUFFER_SIZE

References adjectives, adjectives_count, ASCIICHAT_OK, ERROR_BUFFER_OVERFLOW, ERROR_INVALID_PARAM, log_dev, nouns, nouns_count, safe_snprintf(), SESSION_STRING_BUFFER_SIZE, and SET_ERRNO.

Referenced by options_preset_unified().

◆ acds_string_init()

asciichat_error_t acds_string_init ( void )

Initialize session string system with cached word validation.

Returns
ASCIICHAT_OK on success, error code otherwise

Initializes the random number generator and caches adjectives/nouns in a hashtable for fast validation. Must be called before acds_string_generate() and before any is_session_string() validation calls.

Uses libsodium's randombytes for cryptographically secure randomness. Cleans up cached data on program exit via atexit() handler.

Definition at line 231 of file discovery/strings.c.

231 {
232 return ASCIICHAT_OK;
233}

References ASCIICHAT_OK.

◆ acds_strings_destroy()

void acds_strings_destroy ( void )

Cleanup function for session string cache Called by asciichat_shared_destroy() during library cleanup. Safe to call multiple times (idempotent).

Definition at line 62 of file discovery/strings.c.

62 {
63 // Shutdown if initialized
64 if (!lifecycle_shutdown(&g_cache_lc)) {
65 return; // Not initialized
66 }
67
68 // Cleanup adjectives cache
69 word_cache_entry_t *adj_entry, *adj_tmp;
70 HASH_ITER(hh, g_adjectives_cache, adj_entry, adj_tmp) {
71 HASH_DEL(g_adjectives_cache, adj_entry);
72 SAFE_FREE(adj_entry->word);
73 SAFE_FREE(adj_entry);
74 }
75 g_adjectives_cache = NULL;
76
77 // Cleanup nouns cache
78 word_cache_entry_t *noun_entry, *noun_tmp;
79 HASH_ITER(hh, g_nouns_cache, noun_entry, noun_tmp) {
80 HASH_DEL(g_nouns_cache, noun_entry);
81 SAFE_FREE(noun_entry->word);
82 SAFE_FREE(noun_entry);
83 }
84 g_nouns_cache = NULL;
85
86 log_dev("Session string word cache cleaned up");
87}
#define SAFE_FREE(ptr)
Definition common.h:377
One owned word in the adjective or noun validation hash table.
char * word
The word string (key).

References log_dev, SAFE_FREE, and word_cache_entry_t::word.

Referenced by asciichat_shared_destroy().

◆ is_session_string()

bool is_session_string ( const char * str)

Check if a string is a valid session string.

Parameters
strString to validate
Returns
true if valid session string (adjective-noun-noun format), false otherwise

A valid session string must:

  • Be in format: adjective-noun-noun
  • Contain exactly 3 words separated by exactly 2 hyphens
  • Have each word be a real adjective or noun from cached wordlists
  • Contain only lowercase ASCII letters and hyphens
  • Be 5-47 characters long
  • Not start or end with hyphen
  • Not contain consecutive hyphens

This function validates against the cached wordlists populated by acds_string_init(). Non-session inputs return false without setting an error. Internal failures set errno.

Definition at line 264 of file discovery/strings.c.

264 {
265 if (!str || str[0] == '\0') {
266 return false;
267 }
268
269 size_t len = strlen(str);
270
271 // Check length bounds (min 4, max defined by SESSION_STRING_MAX_LEN)
272 if (len < 4 || len > SESSION_STRING_MAX_LEN) {
273 return false;
274 }
275
276 // Session strings must be ASCII-only (homograph attack prevention)
277 if (!utf8_is_ascii_only(str)) {
278 return false;
279 }
280
281 // Get compiled regex (lazy initialization)
282 pcre2_code *regex = session_format_regex_get();
283 if (!regex) {
284 SET_ERRNO(ERROR_INTERNAL, "Session string PCRE2 regex failed to initialize");
285 return false;
286 }
287
288 // Validate format using PCRE2 regex
289 pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(regex, NULL);
290 if (!match_data) {
291 log_error("Failed to allocate match data for session string regex");
292 SET_ERRNO(ERROR_MEMORY, "Failed to allocate match data");
293 return false;
294 }
295
296 int match_result = pcre2_match(regex, (PCRE2_SPTR8)str, len, 0, 0, match_data, NULL);
297
298 pcre2_match_data_free(match_data);
299
300 if (match_result < 0) {
301 if (match_result != PCRE2_ERROR_NOMATCH) {
302 SET_ERRNO(ERROR_INTERNAL, "Session string PCRE2 matching failed: %d", match_result);
303 }
304 return false;
305 }
306
307 // Extract the three words by finding hyphens
308 // Format is guaranteed to be: word-word-word where each word is 2-12 lowercase letters
309 const char *hyphen1 = strchr(str, '-');
310 if (!hyphen1) {
311 return false;
312 }
313
314 const char *hyphen2 = strchr(hyphen1 + 1, '-');
315 if (!hyphen2) {
316 return false;
317 }
318
319 // Extract three words
320 size_t adj_len = hyphen1 - str;
321 size_t noun1_len = hyphen2 - hyphen1 - 1;
322 size_t noun2_len = len - (hyphen2 - str) - 1;
323
324 if (adj_len >= 32 || noun1_len >= 32 || noun2_len >= 32) {
325 return false;
326 }
327
330 memcpy(adj, str, adj_len);
331 adj[adj_len] = '\0';
332 memcpy(noun1, hyphen1 + 1, noun1_len);
333 noun1[noun1_len] = '\0';
334 memcpy(noun2, hyphen2 + 1, noun2_len);
335 noun2[noun2_len] = '\0';
336
337 // Lazy initialization: build validation caches on first use
338 // call_once ensures thread-safe exactly-once execution
339 build_validation_caches();
340 // If initialization fails silently (logs warning), hashtables will be empty
341 // and validation will fail, which is safe behavior
342
343 // Validate first word is an adjective
344 word_cache_entry_t *adj_entry = NULL;
345 HASH_FIND_STR(g_adjectives_cache, adj, adj_entry);
346 if (!adj_entry) {
347 return false;
348 }
349
350 // Validate second and third words are nouns
351 word_cache_entry_t *noun_entry1 = NULL;
352 HASH_FIND_STR(g_nouns_cache, noun1, noun_entry1);
353 if (!noun_entry1) {
354 return false;
355 }
356
357 word_cache_entry_t *noun_entry2 = NULL;
358 HASH_FIND_STR(g_nouns_cache, noun2, noun_entry2);
359 if (!noun_entry2) {
360 return false;
361 }
362
363 log_dev("Valid session string: %s", str);
364 return true;
365}
#define DISCOVERY_STRINGS_ADJ_BUFFER_SIZE
#define DISCOVERY_STRINGS_NOUN1_BUFFER_SIZE
#define DISCOVERY_STRINGS_NOUN2_BUFFER_SIZE
#define SESSION_STRING_MAX_LEN
Maximum length of a session string (without null terminator).
@ ERROR_MEMORY
Definition error_codes.h:51
@ ERROR_INTERNAL
Definition error_codes.h:87
#define log_error(...)
Log an ERROR message.
Definition log/log.h:634
bool utf8_is_ascii_only(const char *str)
Check if a string contains only ASCII characters.
Definition utf8.c:137

References DISCOVERY_STRINGS_ADJ_BUFFER_SIZE, DISCOVERY_STRINGS_NOUN1_BUFFER_SIZE, DISCOVERY_STRINGS_NOUN2_BUFFER_SIZE, ERROR_INTERNAL, ERROR_MEMORY, log_dev, log_error, SESSION_STRING_MAX_LEN, SET_ERRNO, and utf8_is_ascii_only().

Referenced by discover_session_parallel(), and parse_client_address().