// test_stcp_link.c — integration test for stcp_link API (TCP via STCP) #include "stcp_link.h" #include "secure_channel.h" #include "../lib/u_async.h" #include "../lib/ll_queue.h" #include "../lib/debug_config.h" #include "../lib/mem.h" #include #include #include static int tests_passed = 0, tests_total = 0; static struct SC_MYKEYS s_keys, c_keys; static int test_failed = 0; #define BASE_PORT 24567 #define TASSERT(cond) do { \ if (!(cond)) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, " FAIL: %s", #cond); test_failed = 1; return test_failed; } \ } while(0) struct recv_ctx { uint8_t *data; size_t len, cap; int count; }; static void recv_cb(struct ll_queue *q, void *arg) { struct recv_ctx *r = (struct recv_ctx *)arg; struct ll_entry *e = queue_data_get(q); if (!e) { queue_resume_callback(q); return; } r->count++; size_t need = r->len + e->len; if (need > r->cap) { r->cap = need + 256; r->data = u_realloc(r->data, r->cap); } if (e->dgram && e->len) memcpy(r->data + r->len, e->dgram, e->len); r->len += e->len; queue_entry_free(e); queue_resume_callback(q); } static void on_srv_link(struct stcp_link *link, void *arg) { struct stcp_link **out = (struct stcp_link **)arg; *out = link; } static void on_cli_ready(struct stcp_link *link, void *arg) { int *ready = (int *)arg; *ready = 1; (void)link; } static int test1_basic(void) { struct UASYNC *ua = uasync_create(); TASSERT(ua); struct stcp_link_config cfg = {.ua = ua, .my_keys = &s_keys, .inst = NULL}; struct stcp_link *srv_link = NULL; struct stcp_server *ss = stcp_server_listen(&cfg, BASE_PORT + 1, on_srv_link, &srv_link); TASSERT(ss); struct sockaddr_in raddr; memset(&raddr, 0, sizeof(raddr)); raddr.sin_family = AF_INET; raddr.sin_port = htons(BASE_PORT + 1); raddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); struct stcp_link_config cli_cfg = {.ua = ua, .my_keys = &c_keys, .inst = NULL, .peer_pubkey = s_keys.public_key, .remote_addr = (struct sockaddr_storage *)&raddr}; int cli_ready = 0; struct stcp_link *cli_link = stcp_link_connect(&cli_cfg); TASSERT(cli_link); stcp_link_set_on_ready(cli_link, on_cli_ready, &cli_ready); int ticks = 0; while ((!srv_link || !cli_ready) && ticks < 5000) { uasync_poll(ua, 10); ticks++; } TASSERT(srv_link != NULL); TASSERT(cli_ready); // Verify send works (no crash, data goes through TCP) const char *msg = "hello link!"; int r = stcp_link_send(cli_link, (const uint8_t *)msg, strlen(msg)); TASSERT(r == 0); stcp_link_close(cli_link); stcp_link_server_destroy(ss); uasync_destroy(ua, 1); return 0; } static int test2_wrong_key(void) { struct UASYNC *ua = uasync_create(); TASSERT(ua); struct stcp_link_config cfg = {.ua = ua, .my_keys = &s_keys, .inst = NULL}; struct stcp_link *srv_link = NULL; struct stcp_server *ss = stcp_server_listen(&cfg, BASE_PORT + 2, on_srv_link, &srv_link); TASSERT(ss); struct SC_MYKEYS rogue; TASSERT(sc_generate_keypair(&rogue) == SC_OK); struct sockaddr_in raddr; memset(&raddr, 0, sizeof(raddr)); raddr.sin_family = AF_INET; raddr.sin_port = htons(BASE_PORT + 2); raddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); struct stcp_link_config cli_cfg = {.ua = ua, .my_keys = &c_keys, .inst = NULL, .peer_pubkey = rogue.public_key, .remote_addr = (struct sockaddr_storage *)&raddr}; struct stcp_link *cli_link = stcp_link_connect(&cli_cfg); TASSERT(cli_link); int ticks = 0; while (!srv_link && ticks < 2000) { uasync_poll(ua, 10); ticks++; } TASSERT(!srv_link); // should NOT connect with wrong key stcp_link_close(cli_link); stcp_link_server_destroy(ss); uasync_destroy(ua, 1); return 0; } int main(void) { debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO); debug_set_categories(DEBUG_CATEGORY_GENERAL | DEBUG_CATEGORY_SOCKET | DEBUG_CATEGORY_CRYPTO); TASSERT(sc_generate_keypair(&s_keys) == SC_OK); TASSERT(sc_generate_keypair(&c_keys) == SC_OK); test1_basic(); test2_wrong_key(); DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "Results: %d/%d passed", 2 - (test_failed ? 1 : 0), 2); return test_failed ? 1 : 0; }