Add etcp_api.c/h - ETCP packet send/receive API
Implemented: - etcp_send(conn, entry) - отправляет пакет в очередь normalizer - etcp_bind(id, callback) - подписка на пакеты с определенным ID - etcp_unbind(id) - отписка от пакетов - etcp_recv(queue, arg) - коллбэк для маршрутизации пакетов по ID - etcp_api_init/deinit - инициализация API Integration: - pn_init() теперь устанавливает etcp_recv как callback для pn->output - Добавлены etcp_api.c/h в src/Makefile.am - Добавлен etcp_api.o в тестовые зависимости API использует первый байт кодограммы (cmd) как ID для маршрутизации. ID=0 используется как default handler если нет специфичного binding.
This commit is contained in:
1 parent
5dfb67a4e3
commit
ffaf7a25b8
11 files changed
+282
-7
No files matched your search
+2
-1
@@ -14,7 +14,8 @@ utun_CORE_SOURCES = \
|
||||
etcp_loadbalancer.c \
|
||||
secure_channel.c \
|
||||
crc32.c \
|
||||
pkt_normalizer.c
|
||||
pkt_normalizer.c \
|
||||
etcp_api.c
|
||||
|
||||
# TinyCrypt sources (only used without OpenSSL)
|
||||
utun_TINYCRYPT_SOURCES = \
|
||||
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* @file etcp_api.c
|
||||
* @brief Реализация API для приёма-передачи пакетов через ETCP
|
||||
*/
|
||||
|
||||
#include "etcp_api.h"
|
||||
#include "etcp.h"
|
||||
#include "pkt_normalizer.h"
|
||||
#include "../lib/debug_config.h"
|
||||
#include <string.h>
|
||||
|
||||
#define DEBUG_CATEGORY_ETCP_API 1
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
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");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!callback) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_bind: NULL callback for id=%u", id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (g_bindings[id].active) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCP_API, "etcp_bind: ID %u already bound, overwriting", id);
|
||||
}
|
||||
|
||||
g_bindings[id].callback = callback;
|
||||
g_bindings[id].active = 1;
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP_API, "etcp_bind: Bound ID %u to callback %p", id, (void*)callback);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int etcp_unbind(uint8_t id) {
|
||||
if (!g_api_initialized) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_unbind: API not initialized");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!g_bindings[id].active) {
|
||||
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;
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ETCP_API, "etcp_unbind: Unbound ID %u", id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int etcp_send(struct ETCP_CONN* conn, struct ll_entry* 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;
|
||||
}
|
||||
|
||||
struct PKTNORM* pn = conn->normalizer;
|
||||
|
||||
if (!pn->input) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_send: Normalizer has no input queue");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Помещаем entry в очередь input normalizer
|
||||
// queue_data_put забирает ownership entry
|
||||
int result = queue_data_put(pn->input, entry, 0);
|
||||
|
||||
if (result != 0) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCP_API, "etcp_send: queue_data_put failed (queue full?)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP_API, "etcp_send: Packet queued for sending");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void etcp_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 %p",
|
||||
id, (void*)conn);
|
||||
|
||||
// Ищем binding для этого ID
|
||||
if (id < ETCP_MAX_BINDINGS && g_bindings[id].active && g_bindings[id].callback) {
|
||||
// Вызываем коллбэк
|
||||
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);
|
||||
} else {
|
||||
// Нет binding для этого ID - по умолчанию считаем что это данные (ID=0)
|
||||
if (g_bindings[0].active && g_bindings[0].callback) {
|
||||
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);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
// Возобновляем коллбэк для получения следующего пакета
|
||||
queue_resume_callback(queue);
|
||||
}
|
||||
+93
-3
@@ -1,5 +1,95 @@
|
||||
/* api для приёма-передачи пакетов через etcp
|
||||
/**
|
||||
* @file etcp_api.h
|
||||
* @brief API для приёма-передачи пакетов через ETCP
|
||||
*
|
||||
* Основные функции:
|
||||
* - etcp_send() - отправить пакет в очередь normalizer
|
||||
* - etcp_bind() - подписаться на пакеты с определенным ID
|
||||
* - etcp_recv() - коллбэк для сбора пакетов из всех подключений
|
||||
*
|
||||
* Формат кодограмм: <cmd 1 byte> <data ... n bytes>
|
||||
* cmd = 0 - пакет для передачи адресату
|
||||
* cmd = 1 - элемент роутинг-таблицы
|
||||
* cmd = 2 - запрос роутинг-таблицы
|
||||
*/
|
||||
|
||||
1.
|
||||
#ifndef ETCP_API_H
|
||||
#define ETCP_API_H
|
||||
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include "../lib/ll_queue.h"
|
||||
|
||||
// Forward declarations
|
||||
struct ETCP_CONN;
|
||||
|
||||
/**
|
||||
* @brief Тип коллбэка для приёма пакетов
|
||||
* @param conn ETCP соединение от которого получен пакет
|
||||
* @param entry Элемент очереди с данными пакета
|
||||
*
|
||||
* @note Коллбэк должен освободить entry через queue_entry_free()
|
||||
* и dgram через queue_dgram_free() после обработки
|
||||
*/
|
||||
typedef void (*etcp_recv_fn)(struct ETCP_CONN* conn, struct ll_entry* entry);
|
||||
|
||||
/**
|
||||
* @brief Отправить пакет в очередь normalizer
|
||||
*
|
||||
* @param conn ETCP соединение
|
||||
* @param entry Элемент очереди с данными для отправки
|
||||
* @return 0 при успехе, -1 при ошибке
|
||||
*
|
||||
* @note Функция забирает ownership entry - вызывающий код не должен
|
||||
* освобождать entry после вызова
|
||||
*/
|
||||
int etcp_send(struct ETCP_CONN* conn, struct ll_entry* entry);
|
||||
|
||||
/**
|
||||
* @brief Подписаться на все пакеты с указанным ID
|
||||
*
|
||||
* @param id Идентификатор пакета (первый байт кодограммы, cmd)
|
||||
* @param callback Коллбэк для обработки пакетов с этим ID
|
||||
* @return 0 при успехе, -1 при ошибке (например, нет свободных слотов)
|
||||
*
|
||||
* @note ID=0 зарезервирован для обычных пакетов данных
|
||||
* @note Можно зарегистрировать только один коллбэк на каждый ID
|
||||
*/
|
||||
int etcp_bind(uint8_t id, etcp_recv_fn callback);
|
||||
|
||||
/**
|
||||
* @brief Отписаться от пакетов с указанным ID
|
||||
*
|
||||
* @param id Идентификатор пакета
|
||||
* @return 0 при успехе, -1 если binding не найден
|
||||
*/
|
||||
int etcp_unbind(uint8_t id);
|
||||
|
||||
/**
|
||||
* @brief Коллбэк для очередей output ll_queue normalizer
|
||||
*
|
||||
* Собирает пакеты из всех подключений и отправляет в bind->cbk
|
||||
* по ID (первый байт кодограммы).
|
||||
*
|
||||
* @param queue Очередь из которой получен пакет
|
||||
* @param arg Аргумент - указатель на ETCP_CONN
|
||||
*
|
||||
* @note Этот коллбэк устанавливается автоматически при создании
|
||||
* ETCP подключения через pn_init()
|
||||
*/
|
||||
void etcp_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
|
||||
@@ -1,6 +1,7 @@
|
||||
// pkt_normalizer.c - Implementation of packet normalizer for ETCP
|
||||
#include "pkt_normalizer.h"
|
||||
#include "etcp.h" // For ETCP_CONN and related structures
|
||||
#include "etcp_api.h" // For etcp_recv callback
|
||||
#include "routing.h" // For routing_add_conn/routing_del_conn
|
||||
#include "utun_instance.h" // For UTUN_INSTANCE
|
||||
#include "ll_queue.h" // For queue operations
|
||||
@@ -47,7 +48,10 @@ struct PKTNORM* pn_init(struct ETCP_CONN* etcp) {
|
||||
}
|
||||
|
||||
queue_set_callback(pn->input, packer_cb, pn);
|
||||
queue_set_callback(etcp->output_queue, pn_unpacker_cb, pn);
|
||||
|
||||
// Setup etcp_recv callback for output queue - handles all received packets
|
||||
// according to etcp_api protocol (routes by first byte ID)
|
||||
queue_set_callback(pn->output, etcp_recv, etcp);
|
||||
|
||||
pn->data = NULL;
|
||||
pn->recvpart = NULL;
|
||||
|
||||
Reference in new issue
Block a user