Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34683f0500 | ||
|
|
150e9977df |
No files matched your search
@@ -26,6 +26,7 @@ utun_CORE_SOURCES = \
|
||||
etcp_dump.c \
|
||||
secure_channel.c \
|
||||
crc32.c \
|
||||
stcp_link.c \
|
||||
stcp.c \
|
||||
stcp_server.c \
|
||||
stcp_client.c \
|
||||
|
||||
+6
-1
@@ -624,7 +624,12 @@ static int parse_server(const char *key, const char *value, struct CFG_SERVER *s
|
||||
srv->only_local = atoi(value) ? 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Unknown server option '%s'. Valid: addr, so_mark, fib, netif, type, mtu, only_local", filename, line_num, key);
|
||||
if (strcmp(key, "transport") == 0) {
|
||||
if (strcmp(value, "tcp") == 0) srv->transport = 1;
|
||||
else srv->transport = 0; // default udp
|
||||
return 0;
|
||||
}
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Unknown server option '%s'. Valid: addr, so_mark, fib, netif, type, mtu, only_local, transport", filename, line_num, key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ struct CFG_SERVER {
|
||||
int so_mark;
|
||||
int fib; // FreeBSD FIB (routing table), -1 = don't set
|
||||
uint8_t type; // public/nat/private
|
||||
uint8_t transport; // 0=udp (default), 1=tcp
|
||||
uint8_t ipv6_mode; // CFG_IPV6_MODE_*
|
||||
int mtu;
|
||||
uint8_t only_local; // 1 = only local connections, no forwarding
|
||||
|
||||
@@ -13,6 +13,7 @@ extern "C" {
|
||||
|
||||
#include "pkt_normalizer.h"
|
||||
|
||||
struct stcp_link; // forward declaration
|
||||
// In struct ETCP_CONN, add:
|
||||
//struct pn_pair* normalizer;
|
||||
|
||||
@@ -104,6 +105,7 @@ struct ETCP_CONN {
|
||||
// Links (channels) - linked list
|
||||
struct ETCP_LINK* links;
|
||||
struct ETCP_LINK* last_rr_link; // последний линк, выбранный round-robin
|
||||
struct stcp_link *transport_link; // non-NULL for TCP connections
|
||||
|
||||
// Crypto and state
|
||||
struct secure_channel crypto_ctx;
|
||||
|
||||
+31
-163
@@ -1,197 +1,65 @@
|
||||
/**
|
||||
* @file etcp_api.c
|
||||
* @brief Реализация API для приёма-передачи пакетов через ETCP (per-instance bindings)
|
||||
* @brief ETCP API — send/bind/recv dispatch
|
||||
*/
|
||||
|
||||
#include "etcp_api.h"
|
||||
#include "etcp.h"
|
||||
#include "pkt_normalizer.h"
|
||||
#include "utun_instance.h"
|
||||
#include "stcp_link.h"
|
||||
#include "../lib/debug_config.h"
|
||||
#include <string.h>
|
||||
#include "route_lib.h"
|
||||
#include "route_bgp.h"
|
||||
|
||||
#define DEBUG_CATEGORY_ETCP_API 1
|
||||
#define DEBUG_CATEGORY_ETCP_API DEBUG_CATEGORY_ETCP
|
||||
|
||||
#define ETCP_MAX_BINDINGS 256 /**< Максимальное количество bindings (по одному на каждый ID 0-255) */
|
||||
|
||||
// после создания подключения надо выждать conn_ready. только после этого можно передавать сообщения. Иначе сообщения могут потеряться.
|
||||
// conn_ready может вызваться несколько раз (после каждого переподключения - например когда удаленный узел перегрузился или возникла неустранимая ошибка).
|
||||
void etcp_conn_set_ready_cbk(struct ETCP_CONN* etcp, etcp_cbk_fn callback_fn, void* arg) {
|
||||
if (!etcp) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "NULL conn"); return; }
|
||||
etcp->ready_cbk = callback_fn;
|
||||
etcp->ready_arg = arg;
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_ETCP_API, "conn=%s cbk=%p arg=%p", etcp->log_name, (void*)callback_fn, arg);
|
||||
void etcp_conn_set_ready_cbk(struct ETCP_CONN* e, etcp_cbk_fn fn, void* arg) {
|
||||
if (e) { e->ready_cbk = fn; e->ready_arg = arg; }
|
||||
}
|
||||
|
||||
void etcp_conn_set_up_cbk(struct ETCP_CONN* etcp, etcp_cbk_fn callback_fn, void* arg) {
|
||||
if (!etcp) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "NULL conn"); return; }
|
||||
etcp->up_cbk = callback_fn;
|
||||
etcp->up_arg = arg;
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_ETCP_API, "conn=%s cbk=%p arg=%p", etcp->log_name, (void*)callback_fn, arg);
|
||||
void etcp_conn_set_up_cbk(struct ETCP_CONN* e, etcp_cbk_fn fn, void* arg) {
|
||||
if (e) { e->up_cbk = fn; e->up_arg = arg; }
|
||||
}
|
||||
|
||||
void etcp_conn_set_down_cbk(struct ETCP_CONN* etcp, etcp_cbk_fn callback_fn, void* arg) {
|
||||
if (!etcp) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "NULL conn"); return; }
|
||||
etcp->down_cbk = callback_fn;
|
||||
etcp->down_arg = arg;
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_ETCP_API, "conn=%s cbk=%p arg=%p", etcp->log_name, (void*)callback_fn, arg);
|
||||
void etcp_conn_set_down_cbk(struct ETCP_CONN* e, etcp_cbk_fn fn, void* arg) {
|
||||
if (e) { e->down_cbk = fn; e->down_arg = arg; }
|
||||
}
|
||||
|
||||
// Установить callback при создании нового ETCP соединения
|
||||
void etcp_set_new_conn_cbk(struct UTUN_INSTANCE* instance, etcp_cbk_fn callback_fn, void* arg) {
|
||||
if (!instance) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_set_new_conn_cbk: NULL instance");
|
||||
return;
|
||||
}
|
||||
instance->etcp_new_conn_cbk = callback_fn;
|
||||
instance->etcp_new_conn_arg = arg;
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_ETCP_API, "etcp_set_new_conn_cbk: instance=%p cbk=%p arg=%p",
|
||||
(void*)instance, (void*)callback_fn, arg);
|
||||
void etcp_set_new_conn_cbk(struct UTUN_INSTANCE* inst, etcp_cbk_fn fn, void* arg) {
|
||||
if (inst) { inst->etcp_new_conn_cbk = fn; inst->etcp_new_conn_arg = arg; }
|
||||
}
|
||||
|
||||
int etcp_bind(struct UTUN_INSTANCE* inst, uint8_t id, etcp_recv_fn callback) {
|
||||
if (!inst) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_bind: NULL instance");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((unsigned)id >= ETCP_MAX_BINDINGS) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_bind: Invalid ID %u (max=%d)", id, ETCP_MAX_BINDINGS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!callback) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_bind: NULL callback for id=%u", id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (inst->api_bindings.callbacks[id] != NULL) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCP_API, "etcp_bind: Overwriting existing callback for id=%u", id);
|
||||
}
|
||||
if (!inst || !callback || (unsigned)id >= ETCP_MAX_BINDINGS) return -1;
|
||||
inst->api_bindings.callbacks[id] = callback;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP_API, "etcp_bind: Bound id=%u → callback=%p", id, (void*)callback);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int etcp_unbind(struct UTUN_INSTANCE* inst, uint8_t id) {
|
||||
if (!inst) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_unbind: NULL instance");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((unsigned)id >= ETCP_MAX_BINDINGS) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_unbind: Invalid ID %u", id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (inst->api_bindings.callbacks[id] == NULL) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCP_API, "etcp_unbind: ID %u not bound", id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!inst || (unsigned)id >= ETCP_MAX_BINDINGS) return -1;
|
||||
inst->api_bindings.callbacks[id] = NULL;
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP_API, "etcp_unbind: Unbound ID %u for instance %p", id, (void*)inst);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int etcp_send(struct ETCP_CONN* conn, struct ll_entry* entry) {
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_ETCP_API, "etcp_send enter conn=%p entry=%p", conn, entry);
|
||||
if (!conn) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_send: NULL connection");
|
||||
return -1;
|
||||
}
|
||||
if (!entry) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_send: NULL entry");
|
||||
return -1;
|
||||
}
|
||||
if (!conn->normalizer) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_send: Connection has no normalizer");
|
||||
return -1;
|
||||
}
|
||||
if (conn->initialized==0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_send: Connection is not initialized");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct PKTNORM* pn = conn->normalizer;
|
||||
if (!pn || !pn->input) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_send: pn=%p or input null", pn);
|
||||
return -1;
|
||||
}
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP_API, "etcp_send: queued to [%s]", conn->log_name);
|
||||
int result = queue_data_put(pn->input, entry);
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_NORMALIZER, "etcp_send after put result=%d", result);
|
||||
if (result != 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCP_API, "etcp_send: queue_data_put failed");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
if (!conn || !entry) return -1;
|
||||
// TCP (stcp_link) — send directly
|
||||
if (conn->transport_link)
|
||||
return stcp_link_send((struct stcp_link *)conn->transport_link, entry->dgram, entry->len);
|
||||
// UDP — через normalizer
|
||||
if (!conn->normalizer || !conn->normalizer->input) return -1;
|
||||
return queue_data_put(conn->normalizer->input, entry);
|
||||
}
|
||||
|
||||
void etcp_int_recv(struct ll_queue* queue, void* arg) {
|
||||
struct ETCP_CONN* conn = (struct ETCP_CONN*)arg;
|
||||
|
||||
if (!queue || !conn) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_recv: Invalid arguments (queue=%p, conn=%p)",
|
||||
(void*)queue, (void*)conn);
|
||||
return;
|
||||
}
|
||||
|
||||
// Получаем элемент из очереди
|
||||
struct ll_entry* entry = queue_data_get(queue);
|
||||
if (!entry) {
|
||||
// Очередь пуста - это нормально, просто возобновляем коллбэк
|
||||
queue_resume_callback(queue);
|
||||
return;
|
||||
}
|
||||
|
||||
// Проверяем что есть данные
|
||||
if (!entry->dgram || entry->len == 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCP_API, "etcp_recv: Empty packet received");
|
||||
queue_entry_free(entry);
|
||||
queue_dgram_free(entry);
|
||||
queue_resume_callback(queue);
|
||||
return;
|
||||
}
|
||||
|
||||
// Получаем ID пакета (первый байт кодограммы)
|
||||
uint8_t id = entry->dgram[0];
|
||||
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP_API, "etcp_recv: Received packet with ID %u from conn [%s] %p",
|
||||
id, conn->log_name, (void*)conn);
|
||||
|
||||
// Получаем instance из соединения
|
||||
if (!queue || !conn) return;
|
||||
struct ll_entry* e = queue_data_get(queue);
|
||||
if (!e) { queue_resume_callback(queue); return; }
|
||||
if (!e->dgram || e->len == 0) { queue_entry_free(e); queue_dgram_free(e); queue_resume_callback(queue); return; }
|
||||
uint8_t id = e->dgram[0];
|
||||
struct UTUN_INSTANCE* inst = conn->instance;
|
||||
if (!inst) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_recv: Connection has no instance");
|
||||
queue_entry_free(entry);
|
||||
queue_dgram_free(entry);
|
||||
queue_resume_callback(queue);
|
||||
return;
|
||||
}
|
||||
|
||||
// Ищем binding для этого ID в instance
|
||||
if (inst->api_bindings.callbacks[id] != NULL) {
|
||||
// Вызываем коллбэк
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP_API, "etcp_recv: Delivering packet ID %u to callback %p",
|
||||
id, (void*)inst->api_bindings.callbacks[id]);
|
||||
inst->api_bindings.callbacks[id](conn, entry);
|
||||
} else {
|
||||
// Нет binding для этого ID - по умолчанию считаем что это данные (ID=0)
|
||||
if (inst->api_bindings.callbacks[0] != NULL) {
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP_API, "etcp_recv: No binding for ID %u, routing to default (ID=0)", id);
|
||||
inst->api_bindings.callbacks[0](conn, entry);
|
||||
} else {
|
||||
// Нет default binding - освобождаем пакет
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCP_API, "etcp_recv: No binding for ID %u and no default handler, dropping packet", id);
|
||||
queue_entry_free(entry);
|
||||
queue_dgram_free(entry);
|
||||
}
|
||||
}
|
||||
|
||||
// Возобновляем коллбэк для получения следующего пакета
|
||||
if (!inst) { queue_entry_free(e); queue_dgram_free(e); queue_resume_callback(queue); return; }
|
||||
if (inst->api_bindings.callbacks[id])
|
||||
inst->api_bindings.callbacks[id](conn, e);
|
||||
else if (inst->api_bindings.callbacks[0])
|
||||
inst->api_bindings.callbacks[0](conn, e);
|
||||
else { queue_entry_free(e); queue_dgram_free(e); }
|
||||
queue_resume_callback(queue);
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "config_parser.h"
|
||||
#include "crc32.h"
|
||||
#include "etcp.h"
|
||||
#include "stcp_link.h"
|
||||
#include "route_node.h"
|
||||
#include "route_bgp.h"
|
||||
#include "route_ping.h"
|
||||
@@ -27,6 +28,22 @@
|
||||
#include "../lib/mem.h"
|
||||
#include "etcp.h"
|
||||
|
||||
// TCP server: on new incoming connection → create minimal ETCP_CONN
|
||||
static void tcp_server_on_link(struct stcp_link *link, void *arg) {
|
||||
struct UTUN_INSTANCE *inst = (struct UTUN_INSTANCE *)arg;
|
||||
struct ETCP_CONN *conn = u_calloc(1, sizeof(struct ETCP_CONN));
|
||||
if (!conn) return;
|
||||
conn->instance = inst;
|
||||
conn->transport_link = link;
|
||||
snprintf(conn->log_name, sizeof(conn->log_name), "tcp-[%p]", (void*)link);
|
||||
conn->next = inst->connections;
|
||||
inst->connections = conn;
|
||||
inst->connections_count++;
|
||||
if (inst->etcp_new_conn_cbk) inst->etcp_new_conn_cbk(conn, inst->etcp_new_conn_arg);
|
||||
if (conn->ready_cbk) conn->ready_cbk(conn, conn->ready_arg);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "TCP server new conn=%p total=%d", (void*)conn, inst->connections_count);
|
||||
}
|
||||
|
||||
// Forward declaration
|
||||
void etcp_connections_read_callback_socket(socket_t sock, void* arg);
|
||||
static void etcp_link_remove_from_connections(struct ETCP_SOCKET* conn, struct ETCP_LINK* link);
|
||||
@@ -1546,6 +1563,8 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
|
||||
pkt->noencrypt_len=0;
|
||||
pkt->link=link;
|
||||
link->recv_keepalive = 1;
|
||||
link->last_recv_local_time = get_time_tb();
|
||||
link->last_recv_timestamp = pkt->timestamp;
|
||||
|
||||
int xoffset=sizeof(*ack_repl_hdr);
|
||||
// padding
|
||||
@@ -1829,6 +1848,21 @@ int init_sockets(struct UTUN_INSTANCE* instance) {
|
||||
}
|
||||
}
|
||||
|
||||
// TCP transport: create stcp_server instead of UDP socket
|
||||
if (server->transport) {
|
||||
uint16_t port = ntohs(((struct sockaddr_in*)&server->ip)->sin_port);
|
||||
struct stcp_link_config scfg = {.ua = instance->ua, .my_keys = &instance->my_keys, .inst = instance};
|
||||
if (!stcp_server_listen(&scfg, port, tcp_server_on_link, instance)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create TCP server for %s", server->name);
|
||||
fail_count++;
|
||||
} else {
|
||||
success_count++;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "TCP server %s on port %u", server->name, port);
|
||||
}
|
||||
server = server->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
struct ETCP_SOCKET* e_sock = etcp_socket_add(instance, server);
|
||||
if (e_sock && default_ip != 0) {
|
||||
e_sock->local_defaultroute_ip = default_ip;
|
||||
@@ -1971,6 +2005,29 @@ int init_connections(struct UTUN_INSTANCE* instance) {
|
||||
sock = sock->next;
|
||||
}
|
||||
|
||||
if (local_server->transport) {
|
||||
if (strlen(client->peer_public_key_hex) == 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "TCP client %s has no peer key", client->name);
|
||||
client_link = client_link->next; continue;
|
||||
}
|
||||
// TCP transport — use stcp_link instead of etcp_link_new
|
||||
uint16_t rport = ntohs(((struct sockaddr_in*)&client_link->remote_addr)->sin_port);
|
||||
struct stcp_link_config scfg = {
|
||||
.ua = instance->ua, .my_keys = &instance->my_keys, .inst = instance,
|
||||
.peer_pubkey = (const uint8_t*)client->peer_public_key_hex,
|
||||
.peer_pubkey_mode = 1, // hex
|
||||
.remote_addr = &client_link->remote_addr, .remote_port = rport
|
||||
};
|
||||
struct stcp_link *slink = stcp_link_connect(&scfg);
|
||||
if (!slink) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create TCP link for client %s", client->name);
|
||||
client_link = client_link->next; continue;
|
||||
}
|
||||
etcp_conn->transport_link = slink;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "TCP link created for client %s", client->name);
|
||||
client_link = client_link->next; continue;
|
||||
}
|
||||
|
||||
if (!e_sock) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "No socket found for client %s link", client->name);
|
||||
client_link = client_link->next;
|
||||
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
// stcp_link.c — STCP link management implementation
|
||||
#include "stcp_link.h"
|
||||
#include "stcp.h"
|
||||
#include "stcp_server.h"
|
||||
#include "stcp_client.h"
|
||||
#include "secure_channel.h"
|
||||
#include "etcp.h"
|
||||
#include "utun_instance.h"
|
||||
#include "../lib/debug_config.h"
|
||||
#include "../lib/ll_queue.h"
|
||||
#include "../lib/mem.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct stcp_server {
|
||||
struct stcp_server *srv; // stcp_server from stcp_server.h
|
||||
struct stcp_link_config cfg;
|
||||
stcp_server_on_link_cb on_link;
|
||||
void *on_link_arg;
|
||||
};
|
||||
|
||||
struct stcp_link {
|
||||
struct stcp_link_config cfg;
|
||||
struct stcp_client *cli; // only 1 client link for now
|
||||
struct stcp_conn *conn; // STCP connection
|
||||
|
||||
uint8_t ready;
|
||||
uint8_t peer_pubkey[SC_PUBKEY_SIZE];
|
||||
|
||||
stcp_link_cb on_ready_cb;
|
||||
void *ready_arg;
|
||||
void (*on_close_cb)(struct stcp_link *link, int err, void *arg);
|
||||
void *close_arg;
|
||||
|
||||
struct ll_queue *tx_queue; // owned by this link
|
||||
struct ETCP_CONN etcp_conn; // lightweight, for etcp_recv_fn compat
|
||||
};
|
||||
|
||||
// ====== rx dispatch through inst->api_bindings ======
|
||||
|
||||
static void link_rx_cb(struct ll_queue *q, void *arg) {
|
||||
struct stcp_link *link = (struct stcp_link *)arg;
|
||||
struct ll_entry *e = queue_data_get(q);
|
||||
if (!e) { queue_resume_callback(q); return; }
|
||||
|
||||
struct UTUN_INSTANCE *inst = link->cfg.inst;
|
||||
uint8_t id = (e->dgram && e->len > 0) ? e->dgram[0] : 0;
|
||||
|
||||
if (inst && inst->api_bindings.callbacks[id]) {
|
||||
inst->api_bindings.callbacks[id](&link->etcp_conn, e);
|
||||
} else if (inst && inst->api_bindings.callbacks[0]) {
|
||||
inst->api_bindings.callbacks[0](&link->etcp_conn, e);
|
||||
} else {
|
||||
queue_dgram_free(e);
|
||||
queue_entry_free(e);
|
||||
}
|
||||
queue_resume_callback(q);
|
||||
}
|
||||
|
||||
// ====== server accept → link ======
|
||||
|
||||
static void server_accept_cb(struct stcp_conn *conn, void *arg) {
|
||||
struct stcp_server *ss = (struct stcp_server *)arg;
|
||||
struct stcp_link *link = u_calloc(1, sizeof(struct stcp_link));
|
||||
if (!link) { stcp_conn_free(conn); return; }
|
||||
link->cfg = ss->cfg;
|
||||
link->ready = 1;
|
||||
link->conn = conn;
|
||||
link->etcp_conn.instance = ss->cfg.inst;
|
||||
link->etcp_conn.transport_link = (void *)link; // backpointer for stcp_link
|
||||
|
||||
struct ll_queue *rx = queue_new(conn->ua, 0, 0, 0, "srx");
|
||||
queue_set_callback(rx, link_rx_cb, link);
|
||||
stcp_conn_set_rx_queue(conn, rx);
|
||||
link->tx_queue = queue_new(conn->ua, 0, 0, 0, "stx");
|
||||
stcp_conn_set_tx_queue(conn, link->tx_queue);
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "stcp_link: server accepted connection");
|
||||
if (link->on_ready_cb) link->on_ready_cb(link, link->ready_arg);
|
||||
if (ss->on_link) ss->on_link(link, ss->on_link_arg);
|
||||
}
|
||||
|
||||
// ====== client connect → link ======
|
||||
|
||||
static void client_ready_cb(struct stcp_conn *conn, void *arg) {
|
||||
struct stcp_link *link = (struct stcp_link *)arg;
|
||||
if (!conn) return;
|
||||
link->ready = 1;
|
||||
link->conn = conn;
|
||||
link->etcp_conn.instance = link->cfg.inst;
|
||||
link->etcp_conn.transport_link = (void *)link;
|
||||
|
||||
struct ll_queue *rx = queue_new(conn->ua, 0, 0, 0, "crx");
|
||||
queue_set_callback(rx, link_rx_cb, link);
|
||||
stcp_conn_set_rx_queue(conn, rx);
|
||||
link->tx_queue = queue_new(conn->ua, 0, 0, 0, "ctx");
|
||||
stcp_conn_set_tx_queue(conn, link->tx_queue);
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "stcp_link: client connected");
|
||||
if (link->on_ready_cb) link->on_ready_cb(link, link->ready_arg);
|
||||
}
|
||||
|
||||
// ====== API ======
|
||||
|
||||
struct stcp_server *stcp_server_listen(struct stcp_link_config *cfg, uint16_t port,
|
||||
stcp_server_on_link_cb on_link, void *arg) {
|
||||
if (!cfg || !cfg->ua || !cfg->my_keys) return NULL;
|
||||
struct stcp_server *ss = u_calloc(1, sizeof(struct stcp_server));
|
||||
if (!ss) return NULL;
|
||||
ss->cfg = *cfg;
|
||||
ss->on_link = on_link;
|
||||
ss->on_link_arg = arg;
|
||||
ss->srv = stcp_server_create(cfg->ua, port, cfg->my_keys, server_accept_cb, ss);
|
||||
if (!ss->srv) { u_free(ss); return NULL; }
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "stcp_server_listen: port=%u", port);
|
||||
return ss;
|
||||
}
|
||||
|
||||
void stcp_link_server_destroy(struct stcp_server *ss) {
|
||||
if (!ss) return;
|
||||
if (ss->srv) stcp_server_destroy(ss->srv);
|
||||
u_free(ss);
|
||||
}
|
||||
|
||||
struct stcp_link *stcp_link_connect(struct stcp_link_config *cfg) {
|
||||
if (!cfg || !cfg->ua || !cfg->my_keys || !cfg->peer_pubkey || !cfg->remote_addr)
|
||||
return NULL;
|
||||
|
||||
char addr_str[64];
|
||||
struct sockaddr_in *sa = (struct sockaddr_in *)cfg->remote_addr;
|
||||
inet_ntop(AF_INET, &sa->sin_addr, addr_str, sizeof(addr_str));
|
||||
uint16_t port = cfg->remote_port ? cfg->remote_port : ntohs(sa->sin_port);
|
||||
|
||||
struct stcp_link *link = u_calloc(1, sizeof(struct stcp_link));
|
||||
if (!link) return NULL;
|
||||
link->cfg = *cfg;
|
||||
|
||||
// Convert hex pubkey to binary if needed
|
||||
if (cfg->peer_pubkey_mode) {
|
||||
struct secure_channel sc_tmp;
|
||||
sc_init_ctx(&sc_tmp, cfg->my_keys);
|
||||
if (sc_set_peer_public_key(&sc_tmp, cfg->peer_pubkey, 1) != SC_OK) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_SOCKET, "stcp_link_connect: invalid peer pubkey hex");
|
||||
u_free(link); return NULL;
|
||||
}
|
||||
memcpy(link->peer_pubkey, sc_tmp.peer_public_key, SC_PUBKEY_SIZE);
|
||||
} else {
|
||||
memcpy(link->peer_pubkey, cfg->peer_pubkey, SC_PUBKEY_SIZE);
|
||||
}
|
||||
|
||||
link->cli = stcp_client_connect(cfg->ua, addr_str, port, cfg->my_keys, link->peer_pubkey,
|
||||
client_ready_cb, link);
|
||||
if (!link->cli) { u_free(link); return NULL; }
|
||||
|
||||
link->etcp_conn.instance = cfg->inst;
|
||||
link->etcp_conn.transport_link = (void *)link;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_SOCKET, "stcp_link_connect: connecting to %s:%u", addr_str, port);
|
||||
return link;
|
||||
}
|
||||
|
||||
void stcp_link_close(struct stcp_link *link) {
|
||||
if (!link) return;
|
||||
if (link->conn) {
|
||||
if (link->conn->rx_queue) queue_free(link->conn->rx_queue);
|
||||
if (link->tx_queue) queue_free(link->tx_queue);
|
||||
stcp_conn_free(link->conn);
|
||||
}
|
||||
if (link->cli) stcp_client_destroy(link->cli);
|
||||
u_free(link);
|
||||
}
|
||||
|
||||
int stcp_link_send(struct stcp_link *link, const uint8_t *data, size_t len) {
|
||||
if (!link || !link->ready) return -1;
|
||||
struct ll_entry *e = queue_entry_new(0);
|
||||
if (!e) return -1;
|
||||
e->dgram = u_malloc(len ? len : 1);
|
||||
if (!e->dgram) { queue_entry_free(e); return -1; }
|
||||
if (len) memcpy(e->dgram, data, len);
|
||||
e->len = (uint16_t)len;
|
||||
queue_data_put(link->conn->tx_queue, e);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stcp_link_is_ready(struct stcp_link *link) {
|
||||
return link ? link->ready : 0;
|
||||
}
|
||||
|
||||
struct ETCP_CONN *stcp_link_get_etcp_conn(struct stcp_link *link) {
|
||||
return link ? &link->etcp_conn : NULL;
|
||||
}
|
||||
|
||||
void stcp_link_set_on_ready(struct stcp_link *link, stcp_link_cb cb, void *arg) {
|
||||
if (!link) return;
|
||||
link->on_ready_cb = cb;
|
||||
link->ready_arg = arg;
|
||||
}
|
||||
|
||||
void stcp_link_set_on_close(struct stcp_link *link, void (*cb)(struct stcp_link *link, int err, void *arg), void *arg) {
|
||||
if (!link) return;
|
||||
link->on_close_cb = cb;
|
||||
link->close_arg = arg;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// stcp_link.h — STCP link management (TCP connection via STCP protocol)
|
||||
#ifndef STCP_LINK_H
|
||||
#define STCP_LINK_H
|
||||
|
||||
#include "secure_channel.h"
|
||||
#include "../lib/u_async.h"
|
||||
#include "../lib/socket_compat.h"
|
||||
#include <stdint.h>
|
||||
|
||||
struct stcp_link; // opaque
|
||||
struct stcp_server; // opaque
|
||||
struct ETCP_CONN;
|
||||
struct UTUN_INSTANCE;
|
||||
|
||||
// ====== Link config ======
|
||||
|
||||
struct stcp_link_config {
|
||||
struct UASYNC *ua;
|
||||
struct SC_MYKEYS *my_keys; // ключи этой стороны
|
||||
struct UTUN_INSTANCE *inst; // для диспатча через api_bindings
|
||||
const uint8_t *peer_pubkey; // pubkey пира (клиент)
|
||||
int peer_pubkey_mode; // 0=binary, 1=hex
|
||||
const struct sockaddr_storage *remote_addr; // адрес пира (клиент)
|
||||
uint16_t remote_port; // порт пира (клиент)
|
||||
};
|
||||
|
||||
// ====== TCP server ======
|
||||
|
||||
typedef void (*stcp_server_on_link_cb)(struct stcp_link *link, void *arg);
|
||||
|
||||
struct stcp_server *stcp_server_listen(struct stcp_link_config *cfg, uint16_t port,
|
||||
stcp_server_on_link_cb on_link, void *arg);
|
||||
void stcp_link_server_destroy(struct stcp_server *srv);
|
||||
|
||||
// ====== TCP client link ======
|
||||
|
||||
struct stcp_link *stcp_link_connect(struct stcp_link_config *cfg);
|
||||
void stcp_link_close(struct stcp_link *link);
|
||||
int stcp_link_send(struct stcp_link *link, const uint8_t *data, size_t len);
|
||||
int stcp_link_is_ready(struct stcp_link *link);
|
||||
|
||||
struct ETCP_CONN *stcp_link_get_etcp_conn(struct stcp_link *link);
|
||||
|
||||
typedef void (*stcp_link_cb)(struct stcp_link *link, void *arg);
|
||||
void stcp_link_set_on_ready(struct stcp_link *link, stcp_link_cb cb, void *arg);
|
||||
void stcp_link_set_on_close(struct stcp_link *link, void (*cb)(struct stcp_link *link, int err, void *arg), void *arg);
|
||||
|
||||
#endif
|
||||
+6
-1
@@ -8,6 +8,7 @@
|
||||
#include "secure_channel.h"
|
||||
#include "etcp_api.h"
|
||||
#include "config_parser.h"
|
||||
#include "stcp_link.h"
|
||||
#include "firewall.h"
|
||||
#include "eim_nat.h"
|
||||
#include "nat_transport.h"
|
||||
@@ -15,6 +16,9 @@
|
||||
#include "etcp_router.h"
|
||||
#include "proxy/tcp_proxy_server.h"
|
||||
|
||||
#include "etcp_api.h"
|
||||
#include "config_parser.h"
|
||||
|
||||
// Forward declarations
|
||||
struct utun_config;
|
||||
struct uasync_s;
|
||||
@@ -71,8 +75,9 @@ struct UTUN_INSTANCE {
|
||||
struct memory_pool* pkt_pool;
|
||||
struct memory_pool* ack_pool;
|
||||
|
||||
// Active sockets
|
||||
// Active sockets (UDP)
|
||||
struct ETCP_SOCKET* etcp_sockets;// linked-list
|
||||
struct stcp_server *stcp_server; // TCP server (single for now)
|
||||
|
||||
// Pending one-shot pings (for callback on PONG or timeout)
|
||||
struct PING_CONTEXT* pending_pings;
|
||||
|
||||
@@ -5,6 +5,8 @@ check_PROGRAMS = \
|
||||
test_ll_queue \
|
||||
test_serialize \
|
||||
test_stream_cipher \
|
||||
test_etcp_transport \
|
||||
test_transport \
|
||||
test_stcp \
|
||||
test_packet_dump \
|
||||
test_debug_categories \
|
||||
@@ -81,6 +83,9 @@ TINYCRYPT_OBJS = \
|
||||
# Secure channel and CRC objects (built in src directory)
|
||||
SECURE_CHANNEL_OBJS = $(top_builddir)/src/utun-secure_channel.o $(top_builddir)/src/utun-crc32.o
|
||||
|
||||
# Transport objects (needed by etcp_api.c)
|
||||
STCP_LINK_OBJS = $(top_builddir)/src/utun-stcp_link.o $(top_builddir)/src/utun-stcp.o $(top_builddir)/src/utun-stcp_server.o $(top_builddir)/src/utun-stcp_client.o
|
||||
|
||||
# ETCP core objects
|
||||
ETCP_CORE_OBJS = \
|
||||
$(top_builddir)/src/utun-etcp.o \
|
||||
@@ -131,6 +136,7 @@ ETCP_FULL_OBJS = \
|
||||
$(top_builddir)/src/lwip_tcp/utun-lwip_tcp.o \
|
||||
$(top_builddir)/src/lwip_tcp/utun-lwip_tcp_in.o \
|
||||
$(top_builddir)/src/lwip_tcp/utun-lwip_tcp_out.o \
|
||||
$(STCP_LINK_OBJS) \
|
||||
$(ETCP_CORE_OBJS)
|
||||
|
||||
# Windows-specific libraries (advapi32 for CryptGenRandom, ws2_32 for sockets)
|
||||
@@ -182,6 +188,14 @@ test_stream_cipher_SOURCES = test_stream_cipher.c
|
||||
test_stream_cipher_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/tinycrypt/lib/include -I$(top_srcdir)/tinycrypt/lib/source
|
||||
test_stream_cipher_LDADD = $(SECURE_CHANNEL_OBJS) $(CRYPTO_LIBS) $(COMMON_LIBS)
|
||||
|
||||
test_transport_SOURCES = test_stcp_link.c
|
||||
test_transport_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/tinycrypt/lib/include -I$(top_srcdir)/tinycrypt/lib/source
|
||||
test_transport_LDADD = $(STCP_LINK_OBJS) $(SECURE_CHANNEL_OBJS) $(CRYPTO_LIBS) $(COMMON_LIBS)
|
||||
|
||||
test_etcp_transport_SOURCES = test_etcp_stcp.c
|
||||
test_etcp_transport_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/tinycrypt/lib/include -I$(top_srcdir)/tinycrypt/lib/source
|
||||
test_etcp_transport_LDADD = $(STCP_LINK_OBJS) $(top_builddir)/src/utun-etcp_api.o $(SECURE_CHANNEL_OBJS) $(CRYPTO_LIBS) $(COMMON_LIBS)
|
||||
|
||||
test_stcp_SOURCES = test_stcp.c
|
||||
test_stcp_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/tinycrypt/lib/include -I$(top_srcdir)/tinycrypt/lib/source
|
||||
test_stcp_LDADD = $(top_builddir)/src/utun-stcp.o $(top_builddir)/src/utun-stcp_server.o $(top_builddir)/src/utun-stcp_client.o $(SECURE_CHANNEL_OBJS) $(CRYPTO_LIBS) $(COMMON_LIBS)
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
// test_etcp_stcp.c — integration: etcp_send + etcp_bind over STCP link
|
||||
#include "../src/stcp_link.h"
|
||||
#include "../src/etcp_api.h"
|
||||
#include "../src/etcp.h"
|
||||
#include "../src/secure_channel.h"
|
||||
#include "../src/utun_instance.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>
|
||||
|
||||
#define TEST_PORT 25678
|
||||
|
||||
static int test_failed = 0;
|
||||
static struct SC_MYKEYS s_keys, c_keys;
|
||||
|
||||
#define TASSERT(cond) do { \
|
||||
if (!(cond)) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, " FAIL: %s", #cond); test_failed = 1; return; } \
|
||||
} while(0)
|
||||
|
||||
static int g_srv_recv_count = 0;
|
||||
static uint8_t g_srv_recv_data[256];
|
||||
|
||||
static void etcp_recv_cb(struct ETCP_CONN *conn, struct ll_entry *entry) {
|
||||
(void)conn;
|
||||
g_srv_recv_count++;
|
||||
if (entry->dgram && entry->len) memcpy(g_srv_recv_data, entry->dgram, entry->len < 256 ? entry->len : 255);
|
||||
queue_dgram_free(entry);
|
||||
queue_entry_free(entry);
|
||||
}
|
||||
|
||||
static struct stcp_link *g_srv_link;
|
||||
static void on_srv_link_ready(struct stcp_link *link, void *arg) { (void)arg; g_srv_link = link; }
|
||||
|
||||
int main(void) {
|
||||
debug_config_init();
|
||||
debug_set_level(DEBUG_LEVEL_INFO);
|
||||
debug_set_categories(DEBUG_CATEGORY_GENERAL | DEBUG_CATEGORY_SOCKET | DEBUG_CATEGORY_CRYPTO);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "=== etcp_send/bind over STCP link ===");
|
||||
|
||||
TASSERT(sc_generate_keypair(&s_keys) == SC_OK);
|
||||
TASSERT(sc_generate_keypair(&c_keys) == SC_OK);
|
||||
struct UASYNC *ua = uasync_create(); TASSERT(ua);
|
||||
|
||||
struct UTUN_INSTANCE inst; memset(&inst, 0, sizeof(inst));
|
||||
inst.ua = ua;
|
||||
TASSERT(etcp_bind(&inst, 0, etcp_recv_cb) == 0);
|
||||
|
||||
struct stcp_link_config cfg = {.ua = ua, .my_keys = &s_keys, .inst = &inst};
|
||||
struct stcp_server *ss = stcp_server_listen(&cfg, TEST_PORT, on_srv_link_ready, NULL);
|
||||
TASSERT(ss);
|
||||
|
||||
struct sockaddr_in raddr; memset(&raddr, 0, sizeof(raddr));
|
||||
raddr.sin_family = AF_INET; raddr.sin_port = htons(TEST_PORT);
|
||||
raddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
|
||||
struct stcp_link_config cli_cfg = {.ua = ua, .my_keys = &c_keys, .inst = &inst,
|
||||
.peer_pubkey = s_keys.public_key, .remote_addr = (struct sockaddr_storage *)&raddr};
|
||||
struct stcp_link *cli_link = stcp_link_connect(&cli_cfg); TASSERT(cli_link);
|
||||
struct ETCP_CONN *cli_conn = stcp_link_get_etcp_conn(cli_link);
|
||||
|
||||
int ticks = 0;
|
||||
while ((!g_srv_link || !stcp_link_is_ready(cli_link)) && ticks < 5000) { uasync_poll(ua, 10); ticks++; }
|
||||
TASSERT(g_srv_link != NULL);
|
||||
TASSERT(stcp_link_is_ready(cli_link));
|
||||
|
||||
const char *msg = "hello via etcp_send!";
|
||||
struct ll_entry *e = queue_entry_new(0);
|
||||
e->dgram = u_malloc(strlen(msg) + 1);
|
||||
strcpy((char *)e->dgram, msg);
|
||||
e->len = (uint16_t)strlen(msg);
|
||||
TASSERT(etcp_send(cli_conn, e) == 0);
|
||||
|
||||
ticks = 0;
|
||||
while (g_srv_recv_count < 1 && ticks < 2000) { uasync_poll(ua, 10); ticks++; }
|
||||
TASSERT(g_srv_recv_count == 1);
|
||||
TASSERT(memcmp(g_srv_recv_data, msg, strlen(msg)) == 0);
|
||||
|
||||
stcp_link_close(cli_link);
|
||||
stcp_link_server_destroy(ss);
|
||||
uasync_destroy(ua, 1);
|
||||
|
||||
if (test_failed) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "=== FAILED ==="); return 1; }
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "=== PASSED ===");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
// test_stcp_link.c — integration test for stcp_link API (TCP via STCP)
|
||||
#include "../src/stcp_link.h"
|
||||
#include "../src/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; } \
|
||||
} 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;
|
||||
}
|
||||
Reference in new issue
Block a user