Refactor etcp_api: per-instance bindings with struct ETCP_BINDINGS
Changed from global bindings to per-instance bindings: 1. Added struct ETCP_BINDINGS in etcp_api.h: - Contains array of callbacks[ETCP_MAX_BINDINGS] - NULL means not bound 2. Updated UTUN_INSTANCE (utun_instance.h): - Added field: struct ETCP_BINDINGS api_bindings - Initialized to NULL by calloc in utun_instance_create 3. Updated API functions (etcp_api.h/c): - etcp_bind(inst, id, callback) - per-instance binding - etcp_unbind(inst, id) - per-instance unbinding - Removed etcp_api_init/etcp_api_deinit (not needed) - etcp_int_recv now uses conn->instance->api_bindings.callbacks[id] 4. Updated test_etcp_api.c: - Separate callbacks for server and client - Register via etcp_bind(server_instance, ...) and etcp_bind(client_instance, ...) - Removed global etcp_api_init/etcp_api_deinit calls Test passes: All 100 packets transmitted in each direction.
This commit is contained in:
1 parent
1a7356e923
commit
d694c92b1f
4 files changed
+124
-126
No files matched your search
+42
-56
@@ -1,11 +1,12 @@
|
||||
/**
|
||||
* @file etcp_api.c
|
||||
* @brief Реализация API для приёма-передачи пакетов через ETCP
|
||||
* @brief Реализация API для приёма-передачи пакетов через ETCP (per-instance bindings)
|
||||
*/
|
||||
|
||||
#include "etcp_api.h"
|
||||
#include "etcp.h"
|
||||
#include "pkt_normalizer.h"
|
||||
#include "utun_instance.h"
|
||||
#include "../lib/debug_config.h"
|
||||
#include <string.h>
|
||||
|
||||
@@ -13,43 +14,14 @@
|
||||
|
||||
#define ETCP_MAX_BINDINGS 256 /**< Максимальное количество bindings (по одному на каждый ID 0-255) */
|
||||
|
||||
/**
|
||||
* @brief Структура binding для ID
|
||||
*/
|
||||
struct ETCP_BINDING {
|
||||
etcp_recv_fn callback; /**< Коллбэк для обработки пакетов */
|
||||
uint8_t active; /**< Флаг активности binding */
|
||||
};
|
||||
|
||||
// Таблица bindings (индекс = ID пакета)
|
||||
static struct ETCP_BINDING g_bindings[ETCP_MAX_BINDINGS];
|
||||
static int g_api_initialized = 0;
|
||||
|
||||
void etcp_api_init(void) {
|
||||
if (g_api_initialized) {
|
||||
return;
|
||||
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;
|
||||
}
|
||||
|
||||
memset(g_bindings, 0, sizeof(g_bindings));
|
||||
g_api_initialized = 1;
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP_API, "ETCP API initialized");
|
||||
}
|
||||
|
||||
void etcp_api_deinit(void) {
|
||||
if (!g_api_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(g_bindings, 0, sizeof(g_bindings));
|
||||
g_api_initialized = 0;
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP_API, "ETCP API deinitialized");
|
||||
}
|
||||
|
||||
int etcp_bind(uint8_t id, etcp_recv_fn callback) {
|
||||
if (!g_api_initialized) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_bind: API not initialized");
|
||||
if (id >= ETCP_MAX_BINDINGS) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_bind: Invalid ID %u (max=%d)", id, ETCP_MAX_BINDINGS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -58,32 +30,36 @@ int etcp_bind(uint8_t id, etcp_recv_fn callback) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (g_bindings[id].active) {
|
||||
if (inst->api_bindings.callbacks[id] != NULL) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCP_API, "etcp_bind: ID %u already bound, overwriting", id);
|
||||
}
|
||||
|
||||
g_bindings[id].callback = callback;
|
||||
g_bindings[id].active = 1;
|
||||
inst->api_bindings.callbacks[id] = callback;
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP_API, "etcp_bind: Bound ID %u to callback %p", id, (void*)callback);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP_API, "etcp_bind: Bound ID %u to callback %p for instance %p",
|
||||
id, (void*)callback, (void*)inst);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int etcp_unbind(uint8_t id) {
|
||||
if (!g_api_initialized) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_unbind: API not initialized");
|
||||
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 (!g_bindings[id].active) {
|
||||
if (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;
|
||||
}
|
||||
|
||||
g_bindings[id].callback = NULL;
|
||||
g_bindings[id].active = 0;
|
||||
inst->api_bindings.callbacks[id] = NULL;
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP_API, "etcp_unbind: Unbound ID %u", id);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP_API, "etcp_unbind: Unbound ID %u for instance %p", id, (void*)inst);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -119,7 +95,7 @@ int etcp_send(struct ETCP_CONN* conn, struct ll_entry* entry) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP_API, "etcp_send: Packet queued for sending");
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP_API, "etcp_send: Packet queued for sending to [%s]", conn->log_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -152,20 +128,30 @@ void etcp_int_recv(struct ll_queue* queue, void* arg) {
|
||||
// Получаем ID пакета (первый байт кодограммы)
|
||||
uint8_t id = entry->dgram[0];
|
||||
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP_API, "etcp_recv: Received packet with ID %u from conn %p",
|
||||
id, (void*)conn);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP_API, "etcp_recv: Received packet with ID %u from conn [%s] %p",
|
||||
id, conn->log_name, (void*)conn);
|
||||
|
||||
// Ищем binding для этого ID
|
||||
if (id < ETCP_MAX_BINDINGS && g_bindings[id].active && g_bindings[id].callback) {
|
||||
// Получаем instance из соединения
|
||||
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 (id < ETCP_MAX_BINDINGS && inst->api_bindings.callbacks[id] != NULL) {
|
||||
// Вызываем коллбэк
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP_API, "etcp_recv: Delivering packet ID %u to callback %p",
|
||||
id, (void*)g_bindings[id].callback);
|
||||
g_bindings[id].callback(conn, entry);
|
||||
id, (void*)inst->api_bindings.callbacks[id]);
|
||||
inst->api_bindings.callbacks[id](conn, entry);
|
||||
} else {
|
||||
// Нет binding для этого ID - по умолчанию считаем что это данные (ID=0)
|
||||
if (g_bindings[0].active && g_bindings[0].callback) {
|
||||
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);
|
||||
g_bindings[0].callback(conn, entry);
|
||||
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);
|
||||
|
||||
+20
-22
@@ -1,11 +1,11 @@
|
||||
/**
|
||||
* @file etcp_api.h
|
||||
* @brief API для приёма-передачи пакетов через ETCP
|
||||
* @brief API для приёма-передачи пакетов через ETCP (per-instance bindings)
|
||||
*
|
||||
* Основные функции:
|
||||
* - etcp_send() - отправить пакет в очередь normalizer
|
||||
* - etcp_bind() - подписаться на пакеты с определенным ID
|
||||
* - etcp_recv() - коллбэк для сбора пакетов из всех подключений
|
||||
* - etcp_int_recv() - коллбэк для сбора пакетов из всех подключений
|
||||
*
|
||||
* Формат кодограмм: <cmd 1 byte> <data ... n bytes>
|
||||
* cmd = 0 - пакет для передачи адресату
|
||||
@@ -19,8 +19,11 @@
|
||||
#include <stdint.h>
|
||||
#include "../lib/ll_queue.h"
|
||||
|
||||
#define ETCP_MAX_BINDINGS 256
|
||||
|
||||
// Forward declarations
|
||||
struct ETCP_CONN;
|
||||
struct UTUN_INSTANCE;
|
||||
|
||||
/**
|
||||
* @brief Тип коллбэка для приёма пакетов
|
||||
@@ -32,6 +35,13 @@ struct ETCP_CONN;
|
||||
*/
|
||||
typedef void (*etcp_recv_fn)(struct ETCP_CONN* conn, struct ll_entry* entry);
|
||||
|
||||
/**
|
||||
* @brief Структура bindings для ETCP API (per-instance)
|
||||
*/
|
||||
struct ETCP_BINDINGS {
|
||||
etcp_recv_fn callbacks[ETCP_MAX_BINDINGS]; /**< Массив callbacks, NULL = не установлен */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Отправить пакет в очередь normalizer
|
||||
*
|
||||
@@ -45,24 +55,26 @@ typedef void (*etcp_recv_fn)(struct ETCP_CONN* conn, struct ll_entry* entry);
|
||||
int etcp_send(struct ETCP_CONN* conn, struct ll_entry* entry);
|
||||
|
||||
/**
|
||||
* @brief Подписаться на все пакеты с указанным ID
|
||||
* @brief Подписаться на все пакеты с указанным ID для данного instance
|
||||
*
|
||||
* @param inst UTUN instance
|
||||
* @param id Идентификатор пакета (первый байт кодограммы, cmd)
|
||||
* @param callback Коллбэк для обработки пакетов с этим ID
|
||||
* @return 0 при успехе, -1 при ошибке (например, нет свободных слотов)
|
||||
* @return 0 при успехе, -1 при ошибке
|
||||
*
|
||||
* @note ID=0 зарезервирован для обычных пакетов данных
|
||||
* @note Можно зарегистрировать только один коллбэк на каждый ID
|
||||
* @note Можно зарегистрировать только один коллбэк на каждый ID в пределах instance
|
||||
*/
|
||||
int etcp_bind(uint8_t id, etcp_recv_fn callback);
|
||||
int etcp_bind(struct UTUN_INSTANCE* inst, uint8_t id, etcp_recv_fn callback);
|
||||
|
||||
/**
|
||||
* @brief Отписаться от пакетов с указанным ID
|
||||
* @brief Отписаться от пакетов с указанным ID для данного instance
|
||||
*
|
||||
* @param inst UTUN instance
|
||||
* @param id Идентификатор пакета
|
||||
* @return 0 при успехе, -1 если binding не найден
|
||||
*/
|
||||
int etcp_unbind(uint8_t id);
|
||||
int etcp_unbind(struct UTUN_INSTANCE* inst, uint8_t id);
|
||||
|
||||
/**
|
||||
* @brief Коллбэк для очередей output ll_queue normalizer
|
||||
@@ -78,18 +90,4 @@ int etcp_unbind(uint8_t id);
|
||||
*/
|
||||
void etcp_int_recv(struct ll_queue* queue, void* arg);
|
||||
|
||||
/**
|
||||
* @brief Инициализация API
|
||||
*
|
||||
* Должна быть вызвана один раз перед использованием API
|
||||
*/
|
||||
void etcp_api_init(void);
|
||||
|
||||
/**
|
||||
* @brief Деинициализация API
|
||||
*
|
||||
* Очищает все bindings
|
||||
*/
|
||||
void etcp_api_deinit(void);
|
||||
|
||||
#endif // ETCP_API_H
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <stdio.h>
|
||||
#include "../lib/memory_pool.h"
|
||||
#include "secure_channel.h"
|
||||
#include "etcp_api.h"
|
||||
|
||||
// Forward declarations
|
||||
struct utun_config;
|
||||
@@ -14,6 +15,7 @@ struct ROUTE_TABLE;
|
||||
struct ETCP_CONN;
|
||||
struct ETCP_SOCKET;
|
||||
struct tun_if;
|
||||
struct ETCP_BINDINGS;
|
||||
|
||||
// uTun instance configuration
|
||||
struct UTUN_INSTANCE {
|
||||
@@ -47,6 +49,8 @@ struct UTUN_INSTANCE {
|
||||
// Active sockets
|
||||
struct ETCP_SOCKET* etcp_sockets;// linked-list
|
||||
|
||||
// ETCP API bindings (per-instance)
|
||||
struct ETCP_BINDINGS api_bindings;
|
||||
};
|
||||
|
||||
// Functions
|
||||
|
||||
Reference in new issue
Block a user