headless: expose OS-assigned control and audio listener ports

This commit is contained in:
evgeny committed 2026-10-10 15:51:04 +02:00
1 parent 91909fbb1e
commit dc0dbbf720
12 files changed
+91 -53

No files matched your search

+12 -2
View File
@@ -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;
+2
View File
@@ -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
}
+12 -2
View File
@@ -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;
+2
View File
@@ -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 */
+12 -2
View File
@@ -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;
+2
View File
@@ -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
}
+1 -10
View File
@@ -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) {