Files
CST-agent/tests/test_peer_auth.c
T
WHCandCursor de2eaf87f7 fix: stop parliament accept starvation on outbound dial (0.9.22)
Peer dial used per-step read timeouts so a stuck handshake could block the
single-threaded daemon for tens of seconds; inbound hellos piled up unread
(CLOSE-WAIT). Use a wall-clock dial budget, drain accepts before each dial,
skip self, and only one side initiates idle polls.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-29 13:19:03 +08:00

133 lines
4.3 KiB
C

#define _POSIX_C_SOURCE 200809L
#include "cst_net.h"
#include "cst_peer.h"
#include "cst_realm.h"
#include "cst_test_util.h"
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
typedef struct {
os_socket_t listen;
cst_realm_cert_t cert;
uint8_t sk[64];
uint8_t realm_pk[32];
int ok;
char remote_id[64];
unsigned long got_rev;
char got_ctx[128];
} srv_t;
static void *server_main(void *p) {
srv_t *s = p;
cst_peer_session_t sess;
char err[128];
s->ok = cst_peer_accept((intptr_t)s->listen, &s->cert, s->sk, s->realm_pk,
5000, &sess, err, sizeof(err)) == 0;
if (s->ok) {
snprintf(s->remote_id, sizeof(s->remote_id), "%s", sess.remote.instance_id);
assert(sess.sealed);
cst_peer_sync_bundle_t local = {0};
local.revision = 1;
snprintf(local.parliament_id, sizeof(local.parliament_id), "parl-s");
snprintf(local.project_id, sizeof(local.project_id), "proj");
snprintf(local.chair_instance, sizeof(local.chair_instance), "peer-b");
local.context = strdup("server-old");
assert(cst_peer_sync(&sess, &local, 5000, err, sizeof(err)) == 0);
s->got_rev = local.revision;
snprintf(s->got_ctx, sizeof(s->got_ctx), "%s",
local.context ? local.context : "");
free(local.context);
cst_peer_close(&sess);
}
return NULL;
}
int main(void) {
os_net_init();
cst_realm_keys_t realm;
assert(cst_realm_generate(&realm) == 0);
cst_realm_cert_t ca, cb;
uint8_t sa[32], ska[64], sb[32], skb[64];
assert(cst_realm_enroll(&realm, "peer-a", "A", 0, &ca, sa, ska) == 0);
assert(cst_realm_enroll(&realm, "peer-b", "B", 0, &cb, sb, skb) == 0);
char err[128];
os_socket_t ls = os_net_listen("127.0.0.1", 0, err, sizeof(err));
assert(ls != OS_SOCKET_BAD);
int port = os_net_port(ls);
assert(port > 0);
srv_t srv = {.listen = ls, .cert = cb};
memcpy(srv.sk, skb, 64);
memcpy(srv.realm_pk, realm.pk, 32);
pthread_t th;
assert(pthread_create(&th, NULL, server_main, &srv) == 0);
cst_peer_session_t sess;
assert(cst_peer_dial("127.0.0.1", port, &ca, ska, realm.pk, 5000, &sess, err,
sizeof(err)) == 0);
assert(!strcmp(sess.remote.instance_id, "peer-b"));
assert(sess.sealed);
cst_peer_sync_bundle_t local = {0};
local.revision = 9;
snprintf(local.parliament_id, sizeof(local.parliament_id), "parl-c");
snprintf(local.project_id, sizeof(local.project_id), "proj");
snprintf(local.chair_instance, sizeof(local.chair_instance), "peer-a");
local.context = strdup("client-wins-secret");
assert(cst_peer_sync(&sess, &local, 5000, err, sizeof(err)) == 0);
/* Client already has higher rev; stays. */
assert(local.revision == 9);
assert(strstr(local.context, "client-wins-secret"));
free(local.context);
cst_peer_close(&sess);
pthread_join(th, NULL);
assert(srv.ok);
assert(!strcmp(srv.remote_id, "peer-a"));
assert(srv.got_rev == 9);
assert(strstr(srv.got_ctx, "client-wins-secret"));
/* Foreign realm must fail. */
cst_realm_keys_t other;
assert(cst_realm_generate(&other) == 0);
cst_realm_cert_t cf;
uint8_t sf[32], skf[64];
assert(cst_realm_enroll(&other, "peer-f", "F", 0, &cf, sf, skf) == 0);
os_socket_t ls2 = os_net_listen("127.0.0.1", 0, err, sizeof(err));
assert(ls2 != OS_SOCKET_BAD);
int port2 = os_net_port(ls2);
srv_t srv2 = {.listen = ls2, .cert = cb};
memcpy(srv2.sk, skb, 64);
memcpy(srv2.realm_pk, realm.pk, 32);
assert(pthread_create(&th, NULL, server_main, &srv2) == 0);
assert(cst_peer_dial("127.0.0.1", port2, &cf, skf, other.pk, 3000, &sess, err,
sizeof(err)) != 0);
pthread_join(th, NULL);
assert(!srv2.ok);
/* Wall-clock dial budget: listener that never accepts must fail fast. */
os_socket_t ls3 = os_net_listen("127.0.0.1", 0, err, sizeof(err));
assert(ls3 != OS_SOCKET_BAD);
int port3 = os_net_port(ls3);
struct timespec t0, t1;
clock_gettime(CLOCK_MONOTONIC, &t0);
assert(cst_peer_dial("127.0.0.1", port3, &ca, ska, realm.pk, 800, &sess, err,
sizeof(err)) != 0);
clock_gettime(CLOCK_MONOTONIC, &t1);
long ms = (long)((t1.tv_sec - t0.tv_sec) * 1000 +
(t1.tv_nsec - t0.tv_nsec) / 1000000);
assert(ms >= 400 && ms < 2500);
os_net_close(ls);
os_net_close(ls2);
os_net_close(ls3);
os_net_cleanup();
puts("test_peer_auth: OK");
return 0;
}