Browse Source

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.
nodeinfo-routing-update
Evgeny 8 months ago
parent
commit
ffaf7a25b8
  1. 3
      src/Makefile.am
  2. 179
      src/etcp_api.c
  3. 94
      src/etcp_api.h
  4. 6
      src/pkt_normalizer.c
  5. 5
      tests/Makefile.am
  6. BIN
      tests/test_etcp_100_packets
  7. BIN
      tests/test_etcp_minimal
  8. BIN
      tests/test_etcp_simple_traffic
  9. BIN
      tests/test_etcp_two_instances
  10. BIN
      tests/test_pkt_normalizer_etcp
  11. BIN
      tests/test_pkt_normalizer_standalone

3
src/Makefile.am

@ -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
src/etcp_api.c

@ -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);
}

94
src/etcp_api.h

@ -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 - запрос роутинг-таблицы
*/
#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);
1.
/**
* @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

6
src/pkt_normalizer.c

@ -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;

5
tests/Makefile.am

@ -55,7 +55,8 @@ ETCP_CORE_OBJS = \
$(SRC_OBJDIR)/utun-etcp.o \
$(SRC_OBJDIR)/utun-etcp_connections.o \
$(SRC_OBJDIR)/utun-etcp_loadbalancer.o \
$(SRC_OBJDIR)/utun-pkt_normalizer.o
$(SRC_OBJDIR)/utun-pkt_normalizer.o \
$(SRC_OBJDIR)/utun-etcp_api.o
# Full ETCP objects
ETCP_FULL_OBJS = \
@ -139,7 +140,7 @@ test_pkt_normalizer_etcp_LDADD = $(ETCP_FULL_OBJS) $(SECURE_CHANNEL_OBJS) $(CRYP
test_pkt_normalizer_standalone_SOURCES = test_pkt_normalizer_standalone.c
test_pkt_normalizer_standalone_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/tinycrypt/lib/include -I$(top_srcdir)/tinycrypt/lib/source
test_pkt_normalizer_standalone_LDADD = $(SRC_OBJDIR)/utun-pkt_normalizer.o $(SRC_OBJDIR)/utun-route_lib.o $(SRC_OBJDIR)/utun-routing.o $(TINYCRYPT_OBJS) $(COMMON_LIBS)
test_pkt_normalizer_standalone_LDADD = $(SRC_OBJDIR)/utun-pkt_normalizer.o $(SRC_OBJDIR)/utun-route_lib.o $(SRC_OBJDIR)/utun-routing.o $(SRC_OBJDIR)/utun-etcp_api.o $(TINYCRYPT_OBJS) $(COMMON_LIBS)
test_ll_queue_SOURCES = test_ll_queue.c
test_ll_queue_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib

BIN
tests/test_etcp_100_packets

Binary file not shown.

BIN
tests/test_etcp_minimal

Binary file not shown.

BIN
tests/test_etcp_simple_traffic

Binary file not shown.

BIN
tests/test_etcp_two_instances

Binary file not shown.

BIN
tests/test_pkt_normalizer_etcp

Binary file not shown.

BIN
tests/test_pkt_normalizer_standalone

Binary file not shown.
Loading…
Cancel
Save