From dc0dbbf7205617009bf26bd934fce4761ce6d7df Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 10 Oct 2026 15:51:04 +0200 Subject: [PATCH] headless: expose OS-assigned control and audio listener ports --- lib/socket_compat.c | 13 +++++++++++++ lib/socket_compat.h | 2 ++ src/call/call_headless.c | 14 ++++++++++++-- src/call/call_headless.h | 2 ++ src/chat/chat_headless_control.c | 14 ++++++++++++-- src/chat/chat_headless_control.h | 2 ++ src/radio/radio_headless.c | 14 ++++++++++++-- src/radio/radio_headless.h | 2 ++ src/transport_layer/stcp_server.c | 11 +---------- tests/test_call_headless.c | 31 +++++++++++++++---------------- tests/test_net.h | 9 +++------ tests/test_radio_headless.c | 30 +++++++++++++++--------------- 12 files changed, 91 insertions(+), 53 deletions(-) diff --git a/lib/socket_compat.c b/lib/socket_compat.c index 55e8fcab..027d53e1 100644 --- a/lib/socket_compat.c +++ b/lib/socket_compat.c @@ -246,3 +246,16 @@ uint16_t ss_get_port(const struct sockaddr_storage *addr) { return 0; } + +uint16_t socket_get_bound_port(socket_t sock) { + struct sockaddr_storage address; socklen_t size = sizeof(address); + if (getsockname(sock, (struct sockaddr*)&address, &size) != 0) { + DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "getsockname fd=%llu failed: %s", + (unsigned long long)sock, socket_strerror(socket_get_error())); + return 0; + } + uint16_t port = ss_get_port(&address); + if (!port) DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "socket fd=%llu family=%d has no bound port", + (unsigned long long)sock, address.ss_family); + return port; +} diff --git a/lib/socket_compat.h b/lib/socket_compat.h index e0d18864..ee524454 100644 --- a/lib/socket_compat.h +++ b/lib/socket_compat.h @@ -78,6 +78,8 @@ const char* socket_strerror(int err); // взять порт из sockaddr_storage uint16_t ss_get_port(const struct sockaddr_storage *addr); +// Фактический IPv4/IPv6-порт уже привязанного сокета; 0 при ошибке. +uint16_t socket_get_bound_port(socket_t sock); #ifdef __cplusplus diff --git a/src/call/call_headless.c b/src/call/call_headless.c index 5e146113..259bdf1c 100644 --- a/src/call/call_headless.c +++ b/src/call/call_headless.c @@ -312,7 +312,9 @@ static void ca_cleanup(void* arg) { int call_headless_init(struct UASYNC* ua, struct UTUN_INSTANCE* inst, const char* bind_ip, int port) { - if (!ua || !inst || !bind_ip || port <= 0 || port > 65535) return -1; + if (!ua || !inst || !bind_ip || port < 0 || port > 65535) { + DEBUG_ERROR(DEBUG_CATEGORY_CALL, "%s: invalid init arguments port=%d", CH_ID, port); return -1; + } struct call_audio* ca = ca_of(inst); if (ca && ca->running) return 0; @@ -336,6 +338,8 @@ int call_headless_init(struct UASYNC* ua, struct UTUN_INSTANCE* inst, socket_close_wrapper(ca->listen_fd); ca->listen_fd = SOCKET_INVALID; return -1; } if (listen(ca->listen_fd, 5) < 0) { socket_close_wrapper(ca->listen_fd); ca->listen_fd = SOCKET_INVALID; return -1; } + uint16_t bound_port = socket_get_bound_port(ca->listen_fd); + if (!bound_port) { socket_close_wrapper(ca->listen_fd); ca->listen_fd = SOCKET_INVALID; return -1; } ca->listen_sock_id = uasync_add_socket_t(ua, ca->listen_fd, ca_accept_callback, NULL, NULL, "call_listen", ca); if (!ca->listen_sock_id) { socket_close_wrapper(ca->listen_fd); ca->listen_fd = SOCKET_INVALID; return -1; } @@ -345,10 +349,16 @@ int call_headless_init(struct UASYNC* ua, struct UTUN_INSTANCE* inst, if (!ca->cleanup_timer) DEBUG_ERROR(DEBUG_CATEGORY_CALL, "%s: cleanup timer scheduling failed", CH_ID); ca->running = 1; - DEBUG_INFO(DEBUG_CATEGORY_CALL, "%s: audio socket listening on %s:%d", CH_ID, bind_ip, port); + DEBUG_INFO(DEBUG_CATEGORY_CALL, "%s: audio socket listening on %s:%u", CH_ID, bind_ip, bound_port); return 0; } +uint16_t call_headless_get_port(struct UTUN_INSTANCE* inst) { + if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_CALL, "%s: get port without instance", CH_ID); return 0; } + struct call_audio* ca = ca_of(inst); + return ca && ca->running ? socket_get_bound_port(ca->listen_fd) : 0; +} + void call_headless_destroy(struct UTUN_INSTANCE* inst) { struct call_audio* ca = ca_of(inst); if (!ca || !ca->running) return; diff --git a/src/call/call_headless.h b/src/call/call_headless.h index 7cd59139..56900c38 100644 --- a/src/call/call_headless.h +++ b/src/call/call_headless.h @@ -31,6 +31,8 @@ extern "C" { int call_headless_init(struct UASYNC* ua, struct UTUN_INSTANCE* inst, const char* bind_ip, int port); void call_headless_destroy(struct UTUN_INSTANCE* inst); +// port=0 при init выбирает ОС; 0 для остановленной службы или при ошибке. +uint16_t call_headless_get_port(struct UTUN_INSTANCE* inst); #ifdef __cplusplus } diff --git a/src/chat/chat_headless_control.c b/src/chat/chat_headless_control.c index 1729db46..04ca5b24 100644 --- a/src/chat/chat_headless_control.c +++ b/src/chat/chat_headless_control.c @@ -903,7 +903,9 @@ static void hc_cleanup(void* arg) { int chat_headless_control_init(struct UASYNC* ua, struct UTUN_INSTANCE* inst, const char* bind_ip, int port) { - if (!ua || !inst || !bind_ip || port <= 0 || port > 65535) return -1; + if (!ua || !inst || !bind_ip || port < 0 || port > 65535) { + DEBUG_ERROR(DEBUG_CATEGORY_HEADLESS, "headless: invalid init arguments port=%d", port); return -1; + } struct headless_control* hc = hc_of(inst); if (hc && hc->running) return 0; @@ -929,6 +931,8 @@ int chat_headless_control_init(struct UASYNC* ua, struct UTUN_INSTANCE* inst, socket_close_wrapper(hc->listen_fd); hc->listen_fd = SOCKET_INVALID; return -1; } if (listen(hc->listen_fd, 5) < 0) { socket_close_wrapper(hc->listen_fd); hc->listen_fd = SOCKET_INVALID; return -1; } + uint16_t bound_port = socket_get_bound_port(hc->listen_fd); + if (!bound_port) { socket_close_wrapper(hc->listen_fd); hc->listen_fd = SOCKET_INVALID; return -1; } hc->listen_sock_id = uasync_add_socket_t(ua, hc->listen_fd, accept_callback, NULL, NULL, "chatctl_listen", hc); if (!hc->listen_sock_id) { socket_close_wrapper(hc->listen_fd); hc->listen_fd = SOCKET_INVALID; return -1; } @@ -941,10 +945,16 @@ int chat_headless_control_init(struct UASYNC* ua, struct UTUN_INSTANCE* inst, } hc->running = 1; - DEBUG_INFO((int)DEBUG_CATEGORY_HEADLESS, "headless: listening on %s:%d", bind_ip, port); + DEBUG_INFO((int)DEBUG_CATEGORY_HEADLESS, "headless: listening on %s:%u", bind_ip, bound_port); return 0; } +uint16_t chat_headless_control_get_port(struct UTUN_INSTANCE* inst) { + if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_HEADLESS, "headless: get port without instance"); return 0; } + struct headless_control* hc = hc_of(inst); + return hc && hc->running ? socket_get_bound_port(hc->listen_fd) : 0; +} + void chat_headless_control_destroy(struct UTUN_INSTANCE* inst) { struct headless_control* hc = hc_of(inst); if (!hc) return; diff --git a/src/chat/chat_headless_control.h b/src/chat/chat_headless_control.h index 2289ab8e..168fec85 100644 --- a/src/chat/chat_headless_control.h +++ b/src/chat/chat_headless_control.h @@ -23,5 +23,7 @@ struct UTUN_INSTANCE; int chat_headless_control_init(struct UASYNC* ua, struct UTUN_INSTANCE* inst, const char* bind_ip, int port); void chat_headless_control_destroy(struct UTUN_INSTANCE* inst); +// port=0 при init выбирает ОС; getter возвращает 0 для остановленной службы или при ошибке. +uint16_t chat_headless_control_get_port(struct UTUN_INSTANCE* inst); #endif /* CHAT_HEADLESS_CONTROL_H */ diff --git a/src/radio/radio_headless.c b/src/radio/radio_headless.c index 23e37b87..7d6b5a4c 100644 --- a/src/radio/radio_headless.c +++ b/src/radio/radio_headless.c @@ -446,7 +446,9 @@ static void rh_cleanup(void* arg) { int radio_headless_init(struct UASYNC* ua, struct UTUN_INSTANCE* inst, const char* bind_ip, int port) { - if (!ua || !inst || !bind_ip || port <= 0 || port > 65535) return -1; + if (!ua || !inst || !bind_ip || port < 0 || port > 65535) { + DEBUG_ERROR(DEBUG_CATEGORY_RADIO, "%s: invalid init arguments port=%d", RH_ID, port); return -1; + } struct radio_headless* rh = rh_of(inst); if (rh && rh->running) return 0; @@ -470,6 +472,8 @@ int radio_headless_init(struct UASYNC* ua, struct UTUN_INSTANCE* inst, socket_close_wrapper(rh->listen_fd); rh->listen_fd = SOCKET_INVALID; return -1; } if (listen(rh->listen_fd, 5) < 0) { socket_close_wrapper(rh->listen_fd); rh->listen_fd = SOCKET_INVALID; return -1; } + uint16_t bound_port = socket_get_bound_port(rh->listen_fd); + if (!bound_port) { socket_close_wrapper(rh->listen_fd); rh->listen_fd = SOCKET_INVALID; return -1; } rh->listen_sock_id = uasync_add_socket_t(ua, rh->listen_fd, rh_accept_callback, NULL, NULL, "radio_listen", rh); if (!rh->listen_sock_id) { socket_close_wrapper(rh->listen_fd); rh->listen_fd = SOCKET_INVALID; return -1; } @@ -480,10 +484,16 @@ int radio_headless_init(struct UASYNC* ua, struct UTUN_INSTANCE* inst, rh->mix_timer = uasync_set_timeout(ua, RH_MIX_TIMER_TB, rh, rh_mix_tick, "rh_mix"); rh->running = 1; - DEBUG_INFO(DEBUG_CATEGORY_RADIO, "%s: audio socket listening on %s:%d", RH_ID, bind_ip, port); + DEBUG_INFO(DEBUG_CATEGORY_RADIO, "%s: audio socket listening on %s:%u", RH_ID, bind_ip, bound_port); return 0; } +uint16_t radio_headless_get_port(struct UTUN_INSTANCE* inst) { + if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_RADIO, "%s: get port without instance", RH_ID); return 0; } + struct radio_headless* rh = rh_of(inst); + return rh && rh->running ? socket_get_bound_port(rh->listen_fd) : 0; +} + void radio_headless_destroy(struct UTUN_INSTANCE* inst) { struct radio_headless* rh = rh_of(inst); if (!rh || !rh->running) return; diff --git a/src/radio/radio_headless.h b/src/radio/radio_headless.h index 0bdf9550..1d75dd12 100644 --- a/src/radio/radio_headless.h +++ b/src/radio/radio_headless.h @@ -36,6 +36,8 @@ extern "C" { int radio_headless_init(struct UASYNC* ua, struct UTUN_INSTANCE* inst, const char* bind_ip, int port); void radio_headless_destroy(struct UTUN_INSTANCE* inst); +// port=0 при init выбирает ОС; 0 для остановленной службы или при ошибке. +uint16_t radio_headless_get_port(struct UTUN_INSTANCE* inst); #ifdef __cplusplus } diff --git a/src/transport_layer/stcp_server.c b/src/transport_layer/stcp_server.c index 1de57f34..81476f16 100644 --- a/src/transport_layer/stcp_server.c +++ b/src/transport_layer/stcp_server.c @@ -344,16 +344,7 @@ struct stcp_server *stcp_server_create(struct UASYNC *ua, uint16_t port, uint16_t stcp_server_get_port(const struct stcp_server *srv) { if (!srv) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "stcp_server_get_port: invalid server"); return 0; } - struct sockaddr_storage address; - socklen_t size = sizeof(address); - if (getsockname(srv->listen_sock, (struct sockaddr *)&address, &size) != 0) { - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "stcp_server_get_port: getsockname failed err=%d", socket_get_error()); - return 0; - } - if (address.ss_family == AF_INET) return ntohs(((struct sockaddr_in *)&address)->sin_port); - if (address.ss_family == AF_INET6) return ntohs(((struct sockaddr_in6 *)&address)->sin6_port); - DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "stcp_server_get_port: unexpected family=%d", address.ss_family); - return 0; + return socket_get_bound_port(srv->listen_sock); } void stcp_server_destroy(struct stcp_server *srv) { diff --git a/tests/test_call_headless.c b/tests/test_call_headless.c index 3b42290f..e41d7b7c 100644 --- a/tests/test_call_headless.c +++ b/tests/test_call_headless.c @@ -30,6 +30,7 @@ #include "../lib/socket_compat.h" #include "../lib/platform_compat.h" #include "test_utils.h" +#include "test_net.h" #include #define OPENSSL_API_COMPAT 0x10100000L @@ -91,7 +92,6 @@ struct hs_shared { uint8_t ch_x_pub[32], ch_ed_pub[32], ch_ed_priv[32], ch_sig[64]; uint64_t nid[2]; uint8_t x_pub[2][32], x_priv[2][32], ed_pub[2][32]; - int port[2]; /* etcp-порты */ }; static struct hs_shared g_sh; @@ -130,13 +130,12 @@ static int wf(const char* p, const char* f, ...) { va_start(ap, f); vfprintf(fp, f, ap); va_end(ap); fclose(fp); return 0; } -static void fill_shared(int base_port) { +static void fill_shared(void) { memset(&g_sh, 0, sizeof(g_sh)); for (int i = 0; i < 2; i++) { gen_x25519(g_sh.x_pub[i], g_sh.x_priv[i]); sc_derive_ed25519_pubkey(g_sh.x_priv[i], g_sh.ed_pub[i]); g_sh.nid[i] = sc_derive_node_id_from_pubkey(g_sh.x_pub[i]); - g_sh.port[i] = base_port + i * 1000; } { uint8_t ch_x_priv[32]; gen_x25519(g_sh.ch_x_pub, ch_x_priv); } gen_ed25519(g_sh.ch_ed_pub, g_sh.ch_ed_priv); @@ -164,17 +163,16 @@ static void write_configs(const char* dir) { if (i == IDX_B) { char apub[65]; to_hex(g_sh.x_pub[IDX_A], 32, apub); snprintf(client, sizeof(client), - "[client: to_a]\npeer_public_key=%s\nlink=s1:127.0.0.1:%d\n", - apub, g_sh.port[IDX_A]); + "[client: to_a]\npeer_public_key=%s\nlink=s1:127.0.0.1:0\n", apub); } wf(path, "[global]\ntun_ip=10.97.%d.1/24\ntun_ifname=tun%d0\ndb_path=%s/db%s\n" "my_private_key=%s\nmy_public_key=%s\n" - "[server: s1]\naddr=127.0.0.1:%d\ntype=public\n" + "[server: s1]\naddr=127.0.0.1:0\ntype=public\n" "%s" "[chatserver]\nstorage_autoload=0\n[allowed_keys]\nallow_all=1\n", i, i, dir, i == IDX_A ? "a" : "b", - priv, pub, g_sh.port[i], client); + priv, pub, client); } } @@ -312,12 +310,12 @@ static void hs_tick(void* arg) { case P_SETUP: do_setup(A, IDX_A); do_setup(B, IDX_B); - if (chat_headless_control_init(A->ua, A, "127.0.0.1", 9700 + (int)(getpid() % 100)) != 0 - || chat_headless_control_init(B->ua, B, "127.0.0.1", 9800 + (int)(getpid() % 100)) != 0) { + if (chat_headless_control_init(A->ua, A, "127.0.0.1", 0) != 0 + || chat_headless_control_init(B->ua, B, "127.0.0.1", 0) != 0) { fprintf(stderr, "headless control init failed\n"); t->result = 2; break; } - if (call_headless_init(A->ua, A, "127.0.0.1", 9710 + (int)(getpid() % 100)) != 0 - || call_headless_init(B->ua, B, "127.0.0.1", 9810 + (int)(getpid() % 100)) != 0) { + if (call_headless_init(A->ua, A, "127.0.0.1", 0) != 0 + || call_headless_init(B->ua, B, "127.0.0.1", 0) != 0) { fprintf(stderr, "call headless audio init failed\n"); t->result = 2; break; } t->phase = P_WAIT_BGP; @@ -326,10 +324,10 @@ static void hs_tick(void* arg) { if (bgp_has(A, nb) && bgp_has(B, na)) t->phase = P_CONNECT_CLIENTS; break; case P_CONNECT_CLIENTS: - if (hs_connect(t, &t->ctl[IDX_A], 9700 + (int)(getpid() % 100)) != 0 - || hs_connect(t, &t->ctl[IDX_B], 9800 + (int)(getpid() % 100)) != 0 - || hs_connect(t, &t->aud[IDX_A], 9710 + (int)(getpid() % 100)) != 0 - || hs_connect(t, &t->aud[IDX_B], 9810 + (int)(getpid() % 100)) != 0) { + if (hs_connect(t, &t->ctl[IDX_A], chat_headless_control_get_port(A)) != 0 + || hs_connect(t, &t->ctl[IDX_B], chat_headless_control_get_port(B)) != 0 + || hs_connect(t, &t->aud[IDX_A], call_headless_get_port(A)) != 0 + || hs_connect(t, &t->aud[IDX_B], call_headless_get_port(B)) != 0) { fprintf(stderr, "client connect failed\n"); t->result = 2; break; } t->phase = P_SUBSCRIBE; @@ -460,7 +458,7 @@ int main(int argc, char** argv) { if (test_mkdtemp(dir) != 0) { fprintf(stderr, "mkdtemp failed\n"); return 1; } test_setenv("UTUN_TEST_DIR", dir, 1); - fill_shared(56000 + (getpid() % 2000)); + fill_shared(); write_configs(dir); printf("=== test_call_headless ===\n"); fflush(stdout); @@ -486,6 +484,7 @@ int main(int argc, char** argv) { uasync_destroy(ua, 0); return 1; } + test_etcp_set_peer(t.inst[IDX_B], "to_a", t.inst[IDX_A], "s1"); utun_instance_init(t.inst[IDX_A]); utun_instance_init(t.inst[IDX_B]); diff --git a/tests/test_net.h b/tests/test_net.h index c02c6720..3aec6d3c 100644 --- a/tests/test_net.h +++ b/tests/test_net.h @@ -10,12 +10,9 @@ // Читаем порт уже открытого сокета; владение fd и резервирование порта сохраняются. static inline uint16_t test_bound_port(socket_t fd) { - struct sockaddr_storage address; socklen_t size = sizeof(address); - if (getsockname(fd, (struct sockaddr*)&address, &size) != 0 || !ss_get_port(&address)) { - DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "test fixture: cannot read bound port fd=%d error=%d", (int)fd, socket_get_error()); - abort(); - } - return ss_get_port(&address); + uint16_t port = socket_get_bound_port(fd); + if (!port) abort(); + return port; } static inline struct ETCP_SOCKET* test_etcp_bound_socket(struct UTUN_INSTANCE* inst, const char* name) { diff --git a/tests/test_radio_headless.c b/tests/test_radio_headless.c index 15696d11..364f16f0 100644 --- a/tests/test_radio_headless.c +++ b/tests/test_radio_headless.c @@ -28,6 +28,7 @@ #include "../lib/socket_compat.h" #include "../lib/platform_compat.h" #include "test_utils.h" +#include "test_net.h" #include #define OPENSSL_API_COMPAT 0x10100000L @@ -84,7 +85,6 @@ struct hr_shared { uint8_t ch_x_pub[32], ch_ed_pub[32], ch_ed_priv[32], ch_sig[64]; uint64_t nid[2]; uint8_t x_pub[2][32], x_priv[2][32], ed_pub[2][32]; - int port[2]; }; static struct hr_shared g_sh; @@ -121,13 +121,12 @@ static int wf(const char* p, const char* f, ...) { va_start(ap, f); vfprintf(fp, f, ap); va_end(ap); fclose(fp); return 0; } -static void fill_shared(int base_port) { +static void fill_shared(void) { memset(&g_sh, 0, sizeof(g_sh)); for (int i = 0; i < 2; i++) { gen_x25519(g_sh.x_pub[i], g_sh.x_priv[i]); sc_derive_ed25519_pubkey(g_sh.x_priv[i], g_sh.ed_pub[i]); g_sh.nid[i] = sc_derive_node_id_from_pubkey(g_sh.x_pub[i]); - g_sh.port[i] = base_port + i * 1000; } { uint8_t ch_x_priv[32]; gen_x25519(g_sh.ch_x_pub, ch_x_priv); } gen_ed25519(g_sh.ch_ed_pub, g_sh.ch_ed_priv); @@ -154,16 +153,16 @@ static void write_configs(const char* dir) { char client[512] = ""; if (i == IDX_B) { char apub[65]; to_hex(g_sh.x_pub[IDX_A], 32, apub); - snprintf(client, sizeof(client), "[client: to_a]\npeer_public_key=%s\nlink=s1:127.0.0.1:%d\n", apub, g_sh.port[IDX_A]); + snprintf(client, sizeof(client), "[client: to_a]\npeer_public_key=%s\nlink=s1:127.0.0.1:0\n", apub); } wf(path, "[global]\ntun_ip=10.99.%d.1/24\ntun_ifname=tun%d0\ndb_path=%s/db%s\n" "my_private_key=%s\nmy_public_key=%s\n" - "[server: s1]\naddr=127.0.0.1:%d\ntype=public\n" + "[server: s1]\naddr=127.0.0.1:0\ntype=public\n" "%s" "[chatserver]\nstorage_autoload=0\n[allowed_keys]\nallow_all=1\n", i, i, dir, i == IDX_A ? "a" : "b", - priv, pub, g_sh.port[i], client); + priv, pub, client); } } @@ -307,12 +306,12 @@ static void hr_tick(void* arg) { case P_SETUP: do_setup(A, IDX_A); do_setup(B, IDX_B); - if (chat_headless_control_init(A->ua, A, "127.0.0.1", 9700 + (int)(getpid() % 100)) != 0 - || chat_headless_control_init(B->ua, B, "127.0.0.1", 9800 + (int)(getpid() % 100)) != 0) { + if (chat_headless_control_init(A->ua, A, "127.0.0.1", 0) != 0 + || chat_headless_control_init(B->ua, B, "127.0.0.1", 0) != 0) { fprintf(stderr, "headless control init failed\n"); t->result = 2; break; } - if (radio_headless_init(A->ua, A, "127.0.0.1", 9710 + (int)(getpid() % 100)) != 0 - || radio_headless_init(B->ua, B, "127.0.0.1", 9810 + (int)(getpid() % 100)) != 0) { + if (radio_headless_init(A->ua, A, "127.0.0.1", 0) != 0 + || radio_headless_init(B->ua, B, "127.0.0.1", 0) != 0) { fprintf(stderr, "radio headless audio init failed\n"); t->result = 2; break; } t->phase = P_WAIT_BGP; @@ -321,10 +320,10 @@ static void hr_tick(void* arg) { if (bgp_has(A, nb) && bgp_has(B, na)) t->phase = P_CONNECT_CLIENTS; break; case P_CONNECT_CLIENTS: - if (hr_connect(t, &t->ctl[IDX_A], 9700 + (int)(getpid() % 100)) != 0 - || hr_connect(t, &t->ctl[IDX_B], 9800 + (int)(getpid() % 100)) != 0 - || hr_connect(t, &t->aud[IDX_A], 9710 + (int)(getpid() % 100)) != 0 - || hr_connect(t, &t->aud[IDX_B], 9810 + (int)(getpid() % 100)) != 0) { + if (hr_connect(t, &t->ctl[IDX_A], chat_headless_control_get_port(A)) != 0 + || hr_connect(t, &t->ctl[IDX_B], chat_headless_control_get_port(B)) != 0 + || hr_connect(t, &t->aud[IDX_A], radio_headless_get_port(A)) != 0 + || hr_connect(t, &t->aud[IDX_B], radio_headless_get_port(B)) != 0) { fprintf(stderr, "client connect failed\n"); t->result = 2; break; } t->phase = P_RADIO_ON; @@ -419,7 +418,7 @@ int main(int argc, char** argv) { if (test_mkdtemp(dir) != 0) { fprintf(stderr, "mkdtemp failed\n"); return 1; } test_setenv("UTUN_TEST_DIR", dir, 1); - fill_shared(59000 + (getpid() % 2000)); + fill_shared(); write_configs(dir); printf("=== test_radio_headless ===\n"); fflush(stdout); @@ -445,6 +444,7 @@ int main(int argc, char** argv) { uasync_destroy(ua, 0); return 1; } + test_etcp_set_peer(t.inst[IDX_B], "to_a", t.inst[IDX_A], "s1"); utun_instance_init(t.inst[IDX_A]); utun_instance_init(t.inst[IDX_B]);