- u_async.c: process immediate_queue BEFORE epoll_wait in uasync_poll - stcp_link.c: defensive NULL etcp_conn/etcp_link in stcp_link_close - utun_instance.c: move stcp_server_list_destroy_all to Phase J (before ETCP), add deferred drain in both Phase J and L - stcp.h/c: STCP_HS_ENC_CLIENT 6→38, STCP_HS_ENC_SERVER 7→39, exchange ed25519_pubkey in both handshake directions - etcp_connections.c: copy peer_ed25519 from STCP to ETCP_CONN in etcp_link_enter_ready_tcp; guard link->etcp in tcp_link_close_cb - chat_sync.c: fix lk->conn NULL dereference for TCP links - test_stcp.c: update stcp_server_create/stcp_client_connect callsites - tools/chat_tcp_test: change transport udp→tcp
121 lines
4.2 KiB
C
121 lines
4.2 KiB
C
// 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 <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
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;
|
|
}
|