diff --git a/.opencode/package-lock.json b/.opencode/package-lock.json new file mode 100644 index 00000000..abded7b2 --- /dev/null +++ b/.opencode/package-lock.json @@ -0,0 +1,115 @@ +{ + "name": ".opencode", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "@opencode-ai/plugin": "1.4.3" + } + }, + "node_modules/@opencode-ai/plugin": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@opencode-ai/plugin/-/plugin-1.4.3.tgz", + "integrity": "sha512-Ob/3tVSIeuMRJBr2O23RtrnC5djRe01Lglx+TwGEmjrH9yDBJ2tftegYLnNEjRoMuzITgq9LD8168p4pzv+U/A==", + "license": "MIT", + "dependencies": { + "@opencode-ai/sdk": "1.4.3", + "zod": "4.1.8" + }, + "peerDependencies": { + "@opentui/core": ">=0.1.97", + "@opentui/solid": ">=0.1.97" + }, + "peerDependenciesMeta": { + "@opentui/core": { + "optional": true + }, + "@opentui/solid": { + "optional": true + } + } + }, + "node_modules/@opencode-ai/sdk": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-1.4.3.tgz", + "integrity": "sha512-X0CAVbwoGAjTY2iecpWkx2B+GAa2jSaQKYpJ+xILopeF/OGKZUN15mjqci+L7cEuwLHV5wk3x2TStUOVCa5p0A==", + "license": "MIT", + "dependencies": { + "cross-spawn": "7.0.6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/zod": { + "version": "4.1.8", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/1 b/1 new file mode 100644 index 00000000..f3f86bdc --- /dev/null +++ b/1 @@ -0,0 +1 @@ +/bin/bash: строка 1: ./test_nat_detection: Нет такого файла или каталога diff --git a/index.html b/index.html new file mode 100644 index 00000000..23f10c35 --- /dev/null +++ b/index.html @@ -0,0 +1,254 @@ + + + + + + Gitea: Git with a cup of tea + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+
+
+
+ +
+
+

+ Gitea: Git with a cup of tea +

+

A painless, self-hosted Git service

+
+
+
+
+
+

+ Easy to install +

+

+ Simply run the binary for your platform, ship it with Docker, or get it packaged. +

+
+
+

+ Cross-platform +

+

+ Gitea runs anywhere Go can compile for: Windows, macOS, Linux, ARM, etc. Choose the one you love! +

+
+
+
+
+

+ Lightweight +

+

+ Gitea has low minimal requirements and can run on an inexpensive Raspberry Pi. Save your machine energy! +

+
+
+

+ Open Source +

+

+ Go get code.gitea.io/gitea! Join us by contributing to make this project even better. Don't be shy to be a contributor! +

+
+
+
+ + + + +
+ + + + + + + + + + + + + diff --git a/lib/ll_queue.c1 b/lib/ll_queue.c1 new file mode 100644 index 00000000..a727d524 --- /dev/null +++ b/lib/ll_queue.c1 @@ -0,0 +1,549 @@ +// ll_queue.c - Упрощенная архитектура: разделение создания элементов и работы с очередью +#include +#include +#include +#include +#include "ll_queue.h" +#include "u_async.h" +#include "debug_config.h" +#include "mem.h" + +#ifdef _WIN32 + #include +#else + #include +#endif + +// ==================== Thread safety check ==================== +#ifdef QUEUE_THREAD_CHECK +static inline void queue_check_thread(struct ll_queue* q) { + if (!q) return; + +#ifdef _WIN32 + DWORD current = GetCurrentThreadId(); + if (q->owner_thread != current) { + DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': thread mismatch! owner=%lu current=%lu", + q->name ? q->name : "unknown", + (unsigned long)q->owner_thread, + (unsigned long)current); + printf("ERROR: Queue '%s' accessed from wrong thread!\n", q->name ? q->name : "unknown"); + abort(); + } +#else + pthread_t current = pthread_self(); + if (!pthread_equal(q->owner_thread, current)) { + DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': thread mismatch! owner=%lu current=%lu", + q->name ? q->name : "unknown", + (unsigned long)q->owner_thread, + (unsigned long)current); + printf("ERROR: Queue '%s' accessed from wrong thread!\n", q->name ? q->name : "unknown"); + abort(); + } +#endif +} +#endif + +// Предварительные объявления внутренних функций +static void queue_resume_timeout_cb(void* arg); +static void check_waiters(struct ll_queue* q); +static void add_to_hash(struct ll_queue* q, struct ll_entry* entry); +static void remove_from_hash(struct ll_queue* q, struct ll_entry* entry); + +// ==================== Управление очередью ==================== + +struct ll_queue* queue_new(struct UASYNC* ua, size_t hash_size, char* name) { + if (!ua) return NULL; + + struct ll_queue* q = u_calloc(1, sizeof(struct ll_queue)); + if (!q) return NULL; + + q->name = name; + q->ua = ua; + q->size_limit = -1; // Без ограничения по умолчанию + q->hash_size = hash_size; + +#ifdef QUEUE_THREAD_CHECK +#ifdef _WIN32 + q->owner_thread = GetCurrentThreadId(); +#else + q->owner_thread = pthread_self(); +#endif +#endif + + // Создать хеш-таблицу если нужно + if (hash_size > 0) { + q->hash_table = u_calloc(hash_size, sizeof(struct ll_entry*)); + if (!q->hash_table) { + u_free(q); + return NULL; + } + } + + DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_new: created queue %p, hash_size=%zu", q, hash_size); + + return q; +} + +struct ll_entry* ll_alloc_lldgram(uint16_t len) { + struct ll_entry* entry = queue_entry_new(0); + if (!entry) return NULL; + + entry->len=0; + entry->memlen=len; + entry->dgram = u_malloc(len); +// entry->dgram_pool = NULL; - уже null (memset) +// entry->dgram_free_fn = NULL; + if (!entry->dgram) { + queue_entry_free(entry); + return NULL; + } + + return entry; +} + +void queue_free(struct ll_queue* q) { + if (!q) return; + + DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_free: freeing queue %p, head=%p, tail=%p, count=%d", + q, q->head, q->tail, q->count); + + // ВАЖНО: Не освобождаем элементы в очереди - они должны быть извлечены отдельно + // Это упрощает архитектуру и предотвращает double-u_free + + // Освободить хеш-таблицу + if (q->hash_table) { + u_free(q->hash_table); + } + + // Отменить отложенное возобновление + if (q->resume_timeout_id) { + uasync_call_soon_cancel(q->ua, q->resume_timeout_id); + q->resume_timeout_id = NULL; + } + + u_free(q); +} + +// ==================== Конфигурация очереди ==================== + +void queue_set_callback(struct ll_queue* q, queue_callback_fn cbk_fn, void* arg) { + if (!q) return; + q->callback = cbk_fn; + q->callback_arg = arg; +} + +static void queue_resume_timeout_cb(void* arg) { + struct ll_queue* q = (struct ll_queue*)arg; + if (!q) return; + + q->resume_timeout_id = NULL; + + // Вызвать коллбэк если есть элементы и коллбэки разрешены + if (q->head && !q->callback_suspended && q->callback) { + q->callback(q, q->callback_arg); + } +} + +void queue_resume_callback(struct ll_queue* q) { + if (!q) return; + + q->callback_suspended = 0; + + // Если есть элементы, запланировать вызов коллбэка + if (q->head && q->callback && !q->resume_timeout_id) { + q->resume_timeout_id = uasync_call_soon(q->ua, q, queue_resume_timeout_cb); + } +} + +void queue_set_size_limit(struct ll_queue* q, int lim) { + if (!q) return; + q->size_limit = lim; +} + +// ==================== Управление элементами ==================== + +struct ll_entry* queue_entry_new(size_t data_size) { + struct ll_entry* entry = u_malloc(sizeof(struct ll_entry) + data_size); + if (!entry) return NULL; + + memset(entry, 0, sizeof(struct ll_entry) + data_size); + entry->size = data_size; + entry->len = 0; + entry->pool = NULL; // Выделено через u_malloc + +// DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_entry_new: created entry %p, size=%zu", entry, data_size); + + return entry; +} + +struct ll_entry* queue_entry_new_from_pool(struct memory_pool* pool) { + if (!pool) return NULL; + + struct ll_entry* entry = memory_pool_alloc(pool); + if (!entry) return NULL; + + memset(entry, 0, pool->object_size); + entry->size = pool->object_size - sizeof(struct ll_entry); + entry->len = 0; + entry->pool = pool; // Выделено из пула + +// DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_entry_new_from_pool: created entry %p from pool %p", entry, pool); + + return entry; +} + +//void ll_u_free_dgram(struct ll_entry* entry) { +void queue_dgram_free(struct ll_entry* entry) { + if (!entry) return; + + if (entry->dgram) { + if (entry->dgram_free_fn) { + entry->dgram_free_fn(entry->dgram); // arg=NULL, если не задан + } else if (entry->dgram_pool) { + memory_pool_free(entry->dgram_pool, entry->dgram); + } else { + u_free(entry->dgram); + } + entry->dgram = NULL; + entry->len = 0; // Опционально сброс len + } +} + +void queue_entry_free(struct ll_entry* entry) { + if (!entry) return; + + if (entry->pool) { + memory_pool_free(entry->pool, entry); + } else { + u_free(entry); + } +} + +// ==================== Операции с очередью ==================== + +// Внутренняя функция добавления в хеш-таблицу +static void add_to_hash(struct ll_queue* q, struct ll_entry* entry) { + if (!q || q->hash_size == 0 || !entry) return; + + size_t slot = entry->id % q->hash_size; + entry->hash_next = q->hash_table[slot]; + q->hash_table[slot] = entry; +} + +// Внутренняя функция удаления из хеш-таблицы +static void remove_from_hash(struct ll_queue* q, struct ll_entry* entry) { + if (!q || q->hash_size == 0 || !entry) return; + + size_t slot = entry->id % q->hash_size; + struct ll_entry** ptr = &q->hash_table[slot]; + while (*ptr) { + if (*ptr == entry) { + *ptr = entry->hash_next; + entry->hash_next = NULL; + return; + } + ptr = &(*ptr)->hash_next; + } +} + +// Проверить и запустить ожидающие коллбэки +static void check_waiters(struct ll_queue* q) { + if (!q) return; + +// DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "check_waiters: checking waiters, count=%d, bytes=%zu", q->count, q->total_bytes); + + struct queue_waiter* waiter = &q->waiter; + + if (waiter->callback) { + // Проверить условие: не больше max_packets и не больше max_bytes + // max_bytes = 0 означает "не проверять байты" + if (q->count <= waiter->max_packets && (waiter->max_bytes == 0 || q->total_bytes <= waiter->max_bytes)) { + DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "check_waiters: condition met, calling callback, count=%d<=%d, bytes=%zu<=%zu (max_bytes_check=%s)", + q->count, waiter->max_packets, q->total_bytes, waiter->max_bytes, + waiter->max_bytes == 0 ? "disabled" : "enabled"); + waiter->callback(q, waiter->callback_arg); + memset(waiter, 0, sizeof(*waiter)); + } + } +} + +int queue_data_put(struct ll_queue* q, struct ll_entry* entry, uint32_t id) { + if (!q || !entry) return -1; + +#ifdef QUEUE_THREAD_CHECK + queue_check_thread(q); +#endif + +#ifdef QUEUE_DEBUG +// queue_check_consistency(q);// !!!! for debug - BEFORE callback +#endif + + entry->id = id; + + // Проверить лимит размера + if (q->size_limit >= 0 && q->count >= q->size_limit) { + queue_dgram_free(entry); + queue_entry_free(entry); // Освободить элемент если превышен лимит + return -1; + } + + // Добавить в конец + entry->next = NULL; + entry->prev = q->tail; + if (q->tail) { + q->tail->next = entry; + } else { + q->head = entry; + } + q->tail = entry; + + q->count++; + entry->int_len=entry->len; + q->total_bytes += entry->int_len; + + size_t send_q_bytes = queue_total_bytes(q); +// DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "check total bytes: new_q_len=%d element_size:%d", send_q_bytes, entry->size); + + add_to_hash(q, entry); + +// DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_data_put: added entry %p (id=%u), count=%d", entry, id, q->count); + + // ВАЖНО: проверка консистентности ДО коллбэка, так как коллбэк может модифицировать очередь +#ifdef QUEUE_DEBUG + queue_check_consistency(q);// !!!! for debug - BEFORE callback +#endif + + // Если очередь была пуста и коллбэки разрешены - вызвать коллбэк + if (q->count == 1 && !q->callback_suspended && q->callback) { + q->callback(q, q->callback_arg); + } + + // Проверить ожидающие коллбэки (надо только при заборе из очереди) +// check_waiters(q); + +#ifdef QUEUE_DEBUG + queue_check_consistency(q);// !!!! for debug - AFTER callback +#endif + return 0; +} + +int queue_data_put_first(struct ll_queue* q, struct ll_entry* entry, uint32_t id) { + if (!q || !entry) return -1; + +#ifdef QUEUE_THREAD_CHECK + queue_check_thread(q); +#endif + + entry->id = id; + + // Проверить лимит размера + if (q->size_limit >= 0 && q->count >= q->size_limit) { + queue_entry_free(entry); // Освободить элемент если превышен лимит + return -1; + } + + // Добавить в начало + entry->next = q->head; + entry->prev = NULL; + if (q->head) { + q->head->prev = entry; + } else { + q->tail = entry; + } + q->head = entry; + + q->count++; + entry->int_len=entry->len; + q->total_bytes += entry->int_len; + + add_to_hash(q, entry); + +// DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_data_put_first: added entry %p (id=%u), count=%d", entry, id, q->count); + + // ВАЖНО: проверка консистентности ДО коллбэка +#ifdef QUEUE_DEBUG + queue_check_consistency(q);// !!!! for debug - BEFORE callback +#endif + + // Если очередь была пуста и коллбэки разрешены - вызвать коллбэк + if (q->count == 1 && !q->callback_suspended && q->callback) { + q->callback(q, q->callback_arg); + } + + // Проверить ожидающие коллбэки +// check_waiters(q); + +#ifdef QUEUE_DEBUG + queue_check_consistency(q);// !!!! for debug +#endif + return 0; +} + +struct ll_entry* queue_data_get(struct ll_queue* q) { + if (!q || !q->head) return NULL; + +#ifdef QUEUE_THREAD_CHECK + queue_check_thread(q); +#endif + + struct ll_entry* entry = q->head; + + q->head = entry->next; + if (q->head) q->head->prev = NULL; + if (!q->head) q->tail = NULL; + + q->count--; + q->total_bytes -= entry->int_len; + + entry->next = NULL; + entry->prev = NULL; + + remove_from_hash(q, entry); + +// DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_data_get: got entry %p (id=%u), count=%d", entry, entry->id, q->count); + + // Приостановить коллбэки для предотвращения рекурсии + q->callback_suspended = 1; + + // Проверить ожидающие коллбэки + check_waiters(q); + +#ifdef QUEUE_DEBUG + queue_check_consistency(q);// !!!! for debug +#endif + return entry; +} + +int queue_entry_count(struct ll_queue* q) { + return q ? q->count : 0; +} + +// Функция проверки консистентности count и total_bytes +// Возвращает 0 если ok, -1 если есть несоответствия +int queue_check_consistency(struct ll_queue* q) { + if (!q) return -1; // Недопустимая очередь + + // Проверка: если count > 0, то head не должен быть NULL + if (q->count > 0 && !q->head) { + DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': count=%d but head is NULL!", + q->name ? q->name : "unknown", q->count); + return -1; + } + + int actual_count = 0; + size_t actual_bytes = 0; + struct ll_entry* current = q->head; + + while (current) { + actual_count++; + actual_bytes += current->int_len; + if (current->next) { + if (current->next->prev != current) { + // Несоответствие в связях prev/next + DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': prev/next error at entry %p != %p entries: %d!=%d bytes: %zu!=%zu", + q->name ? q->name : "unknown", (void*)current, (void*)current->next->prev, actual_count, q->count, actual_bytes, q->total_bytes); + return -1; + } + } + current = current->next; + } + + // Проверить хвост + if (q->tail && q->tail->next != NULL) { + DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': tail error", q->name ? q->name : "unknown"); + return -1; // Хвост должен иметь next == NULL + } + + // Сравнить с сохранёнными значениями + if (actual_count != q->count || actual_bytes != q->total_bytes) { + DEBUG_ERROR(DEBUG_CATEGORY_LL_QUEUE, "Queue '%s': count error entries: %d!=%d or bytes: %zu!=%zu", + q->name ? q->name : "unknown", actual_count, q->count, actual_bytes, q->total_bytes); + return -1; + } + + return 0; +} + +// ==================== Асинхронное ожидание ==================== + +struct queue_waiter* queue_wait_threshold(struct ll_queue* q, int max_packets, size_t max_bytes, + queue_threshold_callback_fn callback, void* arg) { + if (!q || !callback) return NULL; + + struct queue_waiter* waiter = &q->waiter; + + // Проверить условие немедленно + if (q->count <= max_packets && (max_bytes == 0 || q->total_bytes <= max_bytes)) { + // Условие уже выполнено - вызвать коллбэк немедленно + callback(q, arg); + return NULL; + } + + // Установить waiter для отложенного вызова + waiter->max_packets = max_packets; + waiter->max_bytes = max_bytes; + waiter->callback = callback; + waiter->callback_arg = arg; + + return waiter; +} + +void queue_cancel_wait(struct ll_queue* q, struct queue_waiter* waiter) { + if (!q || !waiter || waiter != &q->waiter) return; + + memset(waiter, 0, sizeof(*waiter)); +} + +// ==================== Поиск и удаление по ID ==================== + +struct ll_entry* queue_find_data_by_id(struct ll_queue* q, uint32_t id) { + if (!q || q->hash_size == 0 || !q->hash_table) return NULL; + + size_t slot = id % q->hash_size; + struct ll_entry* entry = q->hash_table[slot]; + + while (entry) { + if (entry->id == id) { + return entry; + } + entry = entry->hash_next; + } + + return NULL; +} + +int queue_remove_data(struct ll_queue* q, struct ll_entry* entry) { + if (!q || !entry) return -1; + +#ifdef QUEUE_THREAD_CHECK + queue_check_thread(q); +#endif + + // Удалить из двусвязного списка + if (entry->prev) { + entry->prev->next = entry->next; + } else { + q->head = entry->next; + } + + if (entry->next) { + entry->next->prev = entry->prev; + } else { + q->tail = entry->prev; + } + + q->count--; + q->total_bytes -= entry->int_len; + + entry->next = NULL; + entry->prev = NULL; + + remove_from_hash(q, entry); + +// DEBUG_DEBUG(DEBUG_CATEGORY_LL_QUEUE, "queue_remove_data: removed entry %p (id=%u), count=%d", entry, entry->id, q->count); +#ifdef QUEUE_DEBUG + queue_check_consistency(q);// !!!! for debug +#endif + check_waiters(q); + return 0; +} diff --git a/lib/ll_queue.h2 b/lib/ll_queue.h2 new file mode 100644 index 00000000..71b93126 --- /dev/null +++ b/lib/ll_queue.h2 @@ -0,0 +1,130 @@ +#ifndef LL_QUEUE_H +#define LL_QUEUE_H +#include +#include +#include "memory_pool.h" +#ifdef _WIN32 + #include + #include +#else + #include +#endif + +#define QUEUE_DEBUG 1 +//#define QUEUE_THREAD_CHECK 1 + +// Forward declaration +struct ll_queue; + +/** + * @struct ll_entry + * @brief Элемент очереди (переменного размера). + * + * Память: [struct ll_entry + data[size]]. + * Индекс для поиска (произвольной длины) хранится в data[index_offset]. + * Хеш (uint64_t) вычисляется по последним 8 байтам индекса. + */ +struct ll_entry { + char* name; + struct ll_entry* next; + struct ll_entry* prev; + uint16_t size; ///< Размер data[] + uint16_t len; + uint16_t memlen; + uint16_t int_len; + uint8_t* dgram; + void (*dgram_free_fn)(uint8_t* data); + struct memory_pool* dgram_pool; + struct memory_pool* pool; + + /* === НОВОЕ: поддержка индекса произвольной длины === */ + uint16_t index_offset; ///< Смещение индекса в data[] + uint16_t index_size; ///< Длина индекса (0 = без индекса) + uint64_t index_hash; ///< Хеш по последним 8 байтам индекса + + struct ll_entry* hash_next; + uint8_t data[0]; ///< Гибкий массив +}; + +/* ... (остальные typedef'ы без изменений) ... */ + +struct ll_queue { + char* name; + struct ll_entry* head; + struct ll_entry* tail; + int count; + size_t total_bytes; + int size_limit; + queue_callback_fn callback; + void* callback_arg; + int callback_suspended; + void* resume_timeout_id; + struct UASYNC* ua; + struct queue_waiter waiter; + struct ll_entry** hash_table; + size_t hash_size; +#ifdef QUEUE_THREAD_CHECK +#ifdef _WIN32 + DWORD owner_thread; +#else + pthread_t owner_thread; +#endif +#endif +}; + +/* ==================== Создание / уничтожение ==================== */ +struct ll_queue* queue_new(struct UASYNC* ua, size_t hash_size, char* name); +void queue_free(struct ll_queue* q); + +/* ==================== Конфигурация ==================== */ +void queue_set_size_limit(struct ll_queue* q, int lim); + +/* ==================== Автозабор элементов ==================== */ +void queue_set_callback(struct ll_queue* q, queue_callback_fn cbk_fn, void* arg); +void queue_resume_callback(struct ll_queue* q); + +/* ==================== Пороговое ожидание ==================== */ +struct queue_waiter* queue_wait_threshold(struct ll_queue* q, int max_packets, size_t max_bytes, + queue_threshold_callback_fn callback, void* arg); +void queue_cancel_wait(struct ll_queue* q, struct queue_waiter* waiter); + +/* ==================== Работа с данными ==================== */ +/* Упрощённая версия (без индекса) */ +int queue_data_put(struct ll_queue* q, struct ll_entry* entry); +int queue_data_put_first(struct ll_queue* q, struct ll_entry* entry); + +/* Версия с хешем по индексу произвольной длины */ +int queue_data_put_with_index(struct ll_queue* q, struct ll_entry* entry, + uint16_t index_offset, uint16_t index_size); +int queue_data_put_first_with_index(struct ll_queue* q, struct ll_entry* entry, + uint16_t index_offset, uint16_t index_size); + +struct ll_entry* queue_data_get(struct ll_queue* q); +int queue_entry_count(struct ll_queue* q); + +/* ==================== Управление памятью ==================== */ +struct ll_entry* ll_alloc_lldgram(uint16_t len); +struct ll_entry* queue_entry_new(size_t data_size); +struct ll_entry* queue_entry_new_from_pool(struct memory_pool* pool); +void queue_entry_free(struct ll_entry* entry); +void queue_dgram_free(struct ll_entry* entry); + +/* ==================== Поиск и удаление ==================== */ +/** + * @brief Поиск по индексу произвольной длины. + * @note Хеш вычисляется по последним 8 байтам индекса. + */ +struct ll_entry* queue_find_data_by_index(struct ll_queue* q, + const void* index_key, + uint16_t index_size); + +int queue_remove_data(struct ll_queue* q, struct ll_entry* entry); + +/* ==================== Утилиты ==================== */ +static inline size_t queue_total_bytes(struct ll_queue* q) { + return q ? q->total_bytes : 0; +} + +int queue_check_consistency(struct ll_queue* q); + +#endif // LL_QUEUE_H diff --git a/linux-x64-deb b/linux-x64-deb new file mode 100644 index 00000000..34f3afef Binary files /dev/null and b/linux-x64-deb differ diff --git a/src/direct_connect.txt b/src/direct_connect.txt new file mode 100644 index 00000000..cb784522 --- /dev/null +++ b/src/direct_connect.txt @@ -0,0 +1,6 @@ +Есть 2 типа подключений - обычные (роутятся через подключения в конфиге) - по ним распространяется bgp и сигнальные пакеты + +А для передачи данных между узлами можно установить прямое подключение (или подключение через лучший промежуточный узел). + +Как работает: +в nodeinfo diff --git a/src/route_bgp.c b/src/route_bgp.c index 055c5935..5926f548 100644 --- a/src/route_bgp.c +++ b/src/route_bgp.c @@ -308,6 +308,11 @@ void route_bgp_destroy(struct UTUN_INSTANCE* instance) { instance->bgp = NULL; } +void route_bgp_set_nat_check_local(struct ROUTE_BGP* bgp, int allow) { + if (!bgp) return; + bgp->allow_nat_check_local = allow ? 1 : 0; +} + void route_bgp_new_conn(struct ETCP_CONN* conn) { if (!conn) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_new_conn: conn is NULL"); @@ -549,8 +554,8 @@ struct nat_check_arg { }; static void nat_link_check_cb(int success, uint16_t avg_rtt, uint8_t count_sent, uint8_t count_ok, - uint32_t recv_ip, uint16_t recv_port, void* arg) { - (void)avg_rtt; (void)count_sent; (void)count_ok; (void)recv_ip; (void)recv_port; + void* arg) { + (void)avg_rtt; (void)count_sent; (void)count_ok; struct nat_check_arg* na = (struct nat_check_arg*)arg; if (!na || !na->link) { u_free(na); return; } struct ETCP_LINK* link = na->link; @@ -614,7 +619,10 @@ static void route_bgp_start_link_nat_check(struct ROUTE_BGP* bgp, struct ETCP_LI target_port = ntohs(sin->sin_port); } - if (is_local_subnet(target_ip)) { DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "local connection: %s, skip nat check", ip_to_str(&target_ip, AF_INET).str); return; } + if (!bgp->allow_nat_check_local && is_local_subnet(target_ip)) { + DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "local connection: %s, skip nat check", ip_to_str(&target_ip, AF_INET).str); + return; + } // Allocate callback arg struct nat_check_arg* arg = u_calloc(1, sizeof(struct nat_check_arg)); @@ -630,7 +638,7 @@ static void route_bgp_start_link_nat_check(struct ROUTE_BGP* bgp, struct ETCP_LI return; } // Send ping via third node - embed peer pubkey for NAT detection - int ret = route_ping_send_req_addr(bgp, third_conn, link->etcp->peer_node_id, target_ip, target_port, + int ret = route_ping_send_req_addr(bgp, third_conn, target_ip, target_port, 3, 500, 1000, 5000, nat_link_check_cb, arg, pubkey); if (ret == 0) { @@ -875,8 +883,11 @@ static void route_bgp_handle_nat_info(struct ROUTE_BGP* bgp, struct ETCP_CONN* f const struct BGP_NAT_INFO* info = (const struct BGP_NAT_INFO*)data; uint32_t nat_ip = (info->nat_ip[0] << 24) | (info->nat_ip[1] << 16) | (info->nat_ip[2] << 8) | info->nat_ip[3]; - uint16_t nat_port = ((info->nat_port >> 8) & 0xFF) | ((info->nat_port & 0xFF) << 8); + uint16_t nat_port = ntohs(info->nat_port); uint8_t socket_id = info->socket_id; + DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT_INFO recv: ip_bytes=0x%02x%02x%02x%02x ip_host=0x%08x port_net=%u port_host=%u", + info->nat_ip[0], info->nat_ip[1], info->nat_ip[2], info->nat_ip[3], + nat_ip, info->nat_port, nat_port); uint8_t* dynamic = (uint8_t*)&bgp->local_node->node + sizeof(struct NODEINFO); dynamic += bgp->local_node->node.node_name_len; @@ -982,6 +993,9 @@ void route_bgp_send_nat_info(struct ETCP_CONN* conn, uint8_t socket_id, uint32_t pkt->nat_ip[3] = nat_ip & 0xFF; pkt->nat_port = htons(nat_port); pkt->nat_type = nat_type; + DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT_INFO send: ip_host=0x%08x ip_bytes=0x%02x%02x%02x%02x port_host=%u port_net=%u", + nat_ip, pkt->nat_ip[0], pkt->nat_ip[1], pkt->nat_ip[2], pkt->nat_ip[3], + nat_port, pkt->nat_port); struct ll_entry* e = queue_entry_new(0); if (!e) { diff --git a/src/route_bgp.h b/src/route_bgp.h index d7278fa9..0f8a2d0d 100644 --- a/src/route_bgp.h +++ b/src/route_bgp.h @@ -84,6 +84,7 @@ struct ROUTE_BGP { struct NODEINFO_Q* local_node; struct route_ping_pending* ping_pending; uint64_t next_ping_req_id; + uint8_t allow_nat_check_local; // 1 = разрешить NAT check для локальных подсетей (для тестов) }; /** @@ -186,4 +187,10 @@ void route_bgp_send_nat_info(struct ETCP_CONN* conn, uint8_t socket_id, uint32_t */ void route_bgp_send_nat_check_req(struct ETCP_CONN* conn, uint8_t socket_id); +/** + * @brief Разрешить/запретить NAT check для локальных подсетей (127.0.0.1, 10.x.x.x и т.д.) + * По умолчанию запрещено. Полезно для тестов. + */ +void route_bgp_set_nat_check_local(struct ROUTE_BGP* bgp, int allow); + #endif // ROUTE_BGP_H diff --git a/src/route_bgp1.txt b/src/route_bgp1.txt new file mode 100644 index 00000000..eed82156 --- /dev/null +++ b/src/route_bgp1.txt @@ -0,0 +1,71 @@ +подсистема роутинга +utun - это сеть узлов. у каждого узла есть собственные локальные подсети. +глобальная задача: создать у каждого узла полную таблицу маршрутизации. +Узлы преимущественно создают связь напрямую друг с другом. Но если это не получается отправляют трафик транзитом через доступные узлы. +Иногда бывает что через транзитные узлы метрики лучше чем напрямую. Используем приоритетно узлы с лучшей метриков, при нехватке bandwidth используем разные каналы (агрегируем). +Динамически обновлем метрики каналов чтобы при отказе быстро переключаться на другие и не фризить обмен из-за отказов. + + +и узлы обмениваются таблицой маршрутов между собой так чтобы у каждого была актуальная таблица подсетей всех узлов. +маршрутами меняются клиенты, подключения которых которые взяты из конфига. и сервера принявшие подключения если клиент инициировал обмен маршрутами. + +инициируется подключение, клиент отправляет свою таблицу. когда сервер принимает таблицу - сервер помечает что по этому маршруту надо обмениваться маршрутами, далее; +- добавляет узел в список рассылки обновлений маршрутов +- отправляет свою таблицу +- добавляет в свою таблицу отсутствующие маршруты +- если что-то добавил: + - рассылает измененные маршруты по списку рассылки +- список рассылки - это linked-list очередей (также на базе ll_queue - каждый элемент = подписчик). один маршрут = одна отправленная кодограмма + + +при подключении узла или изменении таблицы: узел шлёт свою таблицу +формат кодограммы: [0x01 - routing module] [subcmd] [data] +subcmd: +1 [route] - отправка маршрута +2, без данных - больше данных нет + +если сервер получил кодограмму маршрута - он помечает флаг в etcp что с узлом надо обмениваться маршрутами (etcp_conn->routing_exchange_active=2) и добавляет в очередь рассылки маршрутов + + + +========================================= +механизм инкрементальной синхронизации (реализация - потом, пока мысли) +1. вычисляем хеш каждой записи в роутинг таблице. используем ip+mask+node_uid +2. потом из этих хешей создаем хеш таблицу (старшие n бит номер ячейки). далее вычисляются хеши каждой ячейки. + на первом этапе n=16, на втором - n=16*16 на третьем n=16*16*16. + +отправляем хеши удаленному узлу в формате: [n, 1 байт] ([индекс хеша 2 байта - используется n старших бит][хеш - 8 байт]) + +удаленный узел считает свои хеши и сравнивает. где не совпало смотрит сколько записей. + если записей не много - передает эти записи. + если записей много - добавляет 4 бита к хеш таблице и строит субтаблицу для +========================================== + +Формат роутинга: + +Таблица узлов состоит из записей: +- uid +- name +- links +- 3 транзитных узла с метриками (RTT) +- маршруты узла + +- текущая загрузка линка (за последние 10 сек) можно частоту адаптировать под размер сети +- bandidth limit +- transit bandwidth limit + +две группы узлов: + - узлы за nat. подключаются через транзитные узлы. измеряют пинги до транзитных и выбирают N (3 default) лучшие линки. 3 лучших используем для распространения маршрутов + - транзитные узлы. имеют линки с загрузкой. + +добавить кодограмму - отменить распространение маршрутов по линку (+ сделать важным линком) + + + +карта маршрутизации: + +План: +- сделать передачу роутинга в +- сделать фоновый probe для узлов (условно 1 нода в секунду). выигравшие по качеству соатновятся основными +- сделать etcp дизконнект: + - отправить disconnect request + дождаться ack дальше master удаляет, slave удаляет по down. diff --git a/src/route_node.c b/src/route_node.c index ace059b6..8971ec5d 100644 --- a/src/route_node.c +++ b/src/route_node.c @@ -206,6 +206,9 @@ int route_bgp_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct ROUTE_BG sa->port = ntohs(sin->sin_port); sa->type = e_sock->nat_type; sa->id = e_sock->sock_id; + DEBUG_INFO(DEBUG_CATEGORY_BGP, "NODEINFO socket: addr=0x%02x%02x%02x%02x port=%u (from sin_addr=0x%08x sin_port=%u)", + sa->addr[0], sa->addr[1], sa->addr[2], sa->addr[3], sa->port, + sin->sin_addr.s_addr, ntohs(sin->sin_port)); sa++; } e_sock = e_sock->next; diff --git a/src/route_ping.c b/src/route_ping.c index 9d2b5f06..7aadac85 100644 --- a/src/route_ping.c +++ b/src/route_ping.c @@ -62,69 +62,11 @@ static void route_ping_pending_timeout(void* arg) { cur = &(*cur)->next; } if (p->callback) { - p->callback(0, 0, 0, 0, 0, 0, p->arg); + p->callback(0, 0, 0, 0, p->arg); } u_free(p); } -// отправить запрос удаленному узлу "пропингуй такой-то узел" -int route_ping_send_req(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn, uint64_t node_id, - uint8_t count, uint16_t interval_ms, uint16_t timeout_ms, - uint16_t wait_timeout_ms, route_ping_callback_t cb, void* arg) { - if (!bgp || !to_conn || count == 0 || timeout_ms == 0) { - DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid args"); - return -1; - } - struct BGP_PING_REQUEST* req_pkt = u_calloc(1, sizeof(struct BGP_PING_REQUEST)); - if (!req_pkt) { - DEBUG_ERROR(DEBUG_CATEGORY_BGP, "alloc failed"); - return -2; - } - req_pkt->cmd = ETCP_ID_ROUTE_ENTRY; - req_pkt->subcmd = ROUTE_SUBCMD_PING_REQ; - req_pkt->request_id = bgp->next_ping_req_id++; - req_pkt->node_id = node_id; - req_pkt->count = count; - req_pkt->interval_ms = interval_ms; - req_pkt->timeout_ms = timeout_ms; - - struct ll_entry* e = queue_entry_new(0); - if (!e) { - u_free(req_pkt); - DEBUG_ERROR(DEBUG_CATEGORY_BGP, "queue_entry_new failed"); - return -3; - } - e->dgram = (uint8_t*)req_pkt; - e->len = offsetof(struct BGP_PING_REQUEST, target_ipv4); - - int ret = etcp_send(to_conn, e); - if (ret != 0) { - u_free(req_pkt); - queue_entry_free(e); - DEBUG_ERROR(DEBUG_CATEGORY_BGP, "etcp_send failed"); - return -4; - } - - struct route_ping_pending* pending = u_calloc(1, sizeof(struct route_ping_pending)); - if (!pending) { - DEBUG_ERROR(DEBUG_CATEGORY_BGP, "pending alloc failed"); - return -5; - } - pending->bgp = bgp; - pending->request_id = req_pkt->request_id; - pending->callback = cb; - pending->arg = arg; - pending->next = bgp->ping_pending; - bgp->ping_pending = pending; - - pending->timeout_timer = uasync_set_timeout(bgp->instance->ua, wait_timeout_ms * 10, pending, route_ping_pending_timeout, "route_ping"); - - DEBUG_INFO(DEBUG_CATEGORY_BGP, "request_id=%016llx node=%016llx count=%u interval=%u timeout=%u wait=%u", - (unsigned long long)pending->request_id, (unsigned long long)node_id, - (unsigned)count, (unsigned)interval_ms, (unsigned)timeout_ms, (unsigned)wait_timeout_ms); - return 0; -} - // прошел ответ "серия пигнов на удаленном узле завершена" void route_ping_handle_resp(struct ROUTE_BGP* bgp, struct ETCP_CONN* from_conn, const uint8_t* data, size_t len) { if (!bgp || !from_conn || !data || len < sizeof(struct BGP_PING_RESPONSE)) { @@ -147,10 +89,7 @@ void route_ping_handle_resp(struct ROUTE_BGP* bgp, struct ETCP_CONN* from_conn, } if (p->callback) { int success = (resp->count_ok > 0) ? 1 : 0; - uint32_t recv_ip = (resp->recv_ipv4[0] << 24) | (resp->recv_ipv4[1] << 16) | - (resp->recv_ipv4[2] << 8) | resp->recv_ipv4[3]; - uint16_t recv_port = ntohs(resp->recv_port); - p->callback(success, resp->avg_rtt, resp->count_sent, resp->count_ok, recv_ip, recv_port, p->arg); + p->callback(success, resp->avg_rtt, resp->count_sent, resp->count_ok, p->arg); } u_free(p); return; @@ -163,7 +102,7 @@ void route_ping_handle_resp(struct ROUTE_BGP* bgp, struct ETCP_CONN* from_conn, // ======================================================================== -int route_ping_send_req_addr(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn, uint64_t node_id, +int route_ping_send_req_addr(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn, uint32_t target_ip, uint16_t target_port, uint8_t count, uint16_t interval_ms, uint16_t timeout_ms, uint16_t wait_timeout_ms, route_ping_callback_t cb, void* arg, @@ -181,7 +120,6 @@ int route_ping_send_req_addr(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn, u req_pkt->cmd = ETCP_ID_ROUTE_ENTRY; req_pkt->subcmd = ROUTE_SUBCMD_PING_REQ; req_pkt->request_id = bgp->next_ping_req_id++; - req_pkt->node_id = node_id; req_pkt->count = count; req_pkt->interval_ms = interval_ms; req_pkt->timeout_ms = timeout_ms; @@ -190,6 +128,10 @@ int route_ping_send_req_addr(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn, u if (pubkey) { memcpy(req_pkt->pubkey, pubkey, SC_PUBKEY_SIZE); } + DEBUG_INFO(DEBUG_CATEGORY_BGP, "SEND_REQ: target_ip host=0x%08x net=0x%02x%02x%02x%02x port host=%u net=%u", + target_ip, + req_pkt->target_ipv4[0], req_pkt->target_ipv4[1], req_pkt->target_ipv4[2], req_pkt->target_ipv4[3], + target_port, req_pkt->target_port); struct ll_entry* e = queue_entry_new(0); if (!e) { @@ -222,8 +164,8 @@ int route_ping_send_req_addr(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn, u pending->timeout_timer = uasync_set_timeout(bgp->instance->ua, wait_timeout_ms * 10, pending, route_ping_pending_timeout, "route_ping"); - DEBUG_INFO(DEBUG_CATEGORY_BGP, "request_id=%016llx node=%016llx ip=%s port=%u pubkey=%s", - (unsigned long long)pending->request_id, (unsigned long long)node_id, + DEBUG_INFO(DEBUG_CATEGORY_BGP, "request_id=%016llx ip=%s port=%u pubkey=%s", + (unsigned long long)pending->request_id, ip_to_str(&target_ip, AF_INET).str, (unsigned)target_port, pubkey ? "yes" : "no"); return 0; } @@ -248,9 +190,6 @@ static void route_ping_series_finish(struct route_ping_series_ctx* ctx) { resp->count_sent = ctx->count_sent; resp->count_ok = ctx->count_ok; resp->avg_rtt = avg_rtt; - /* recv_ipv4/port = 0 (не используется) */ - memset(resp->recv_ipv4, 0, 4); - resp->recv_port = 0; struct ll_entry* e = queue_entry_new(0); if (e) { @@ -318,7 +257,7 @@ void route_ping_handle_req(struct ROUTE_BGP* bgp, struct ETCP_CONN* from_conn, const uint8_t* data, size_t len) { - if (!bgp || !from_conn || !data || len < sizeof(struct BGP_PING_REQUEST)) { + if (!bgp || !from_conn || !data || len < offsetof(struct BGP_PING_REQUEST, pubkey)) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "ping req: bad args len=%zu", len); return; } @@ -336,13 +275,76 @@ void route_ping_handle_req(struct ROUTE_BGP* bgp, ctx->request_id = req_pkt->request_id; ctx->count_total = req_pkt->count; ctx->timeout_ms = req_pkt->timeout_ms; - memcpy(ctx->pubkey, req_pkt->pubkey, SC_PUBKEY_SIZE); + if (len >= sizeof(struct BGP_PING_REQUEST)) { + memcpy(ctx->pubkey, req_pkt->pubkey, SC_PUBKEY_SIZE); + } /* Целевой адрес */ struct sockaddr_in* sin = (struct sockaddr_in*)&ctx->target_addr; sin->sin_family = AF_INET; memcpy(&sin->sin_addr.s_addr, req_pkt->target_ipv4, 4); sin->sin_port = req_pkt->target_port; + DEBUG_INFO(DEBUG_CATEGORY_BGP, "RECV_REQ: target_ip net_bytes=0x%02x%02x%02x%02x sin_addr=0x%08x port_net=%u port_host=%u", + req_pkt->target_ipv4[0], req_pkt->target_ipv4[1], req_pkt->target_ipv4[2], req_pkt->target_ipv4[3], + sin->sin_addr.s_addr, req_pkt->target_port, ntohs(req_pkt->target_port)); + + /* Если target не указан — можно разрешить из nodeinfo */ + /* + if (sin->sin_addr.s_addr == 0 && sin->sin_port == 0) { + struct NODEINFO_Q* nq = route_bgp_get_node(bgp, req_pkt->node_id); + if (nq) { + const struct NODEINFO_IPV4_SOCKET* sockets; + int count = get_node_v4_sockets(nq, &sockets); + if (count > 0) { + memcpy(&sin->sin_addr.s_addr, sockets[0].addr, 4); + sin->sin_port = sockets[0].port; + DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "resolved target from nodeinfo: %s:%u", + ip_to_str(&sin->sin_addr, AF_INET).str, ntohs(sin->sin_port)); + } + } + } + */ + + /* Если pubkey не указан — ищем по target_ip:port в nodeinfo */ + int pubkey_empty = 1; + for (int i = 0; i < SC_PUBKEY_SIZE; i++) { + if (ctx->pubkey[i] != 0) { pubkey_empty = 0; break; } + } + if (pubkey_empty) { + DEBUG_INFO(DEBUG_CATEGORY_BGP, "looking for pubkey for target %s:%u, nodes_count=%d", + ip_to_str(&sin->sin_addr, AF_INET).str, ntohs(sin->sin_port), + bgp->nodes ? bgp->nodes->count : -1); + struct ll_entry* e = bgp->nodes ? bgp->nodes->head : NULL; + while (e) { + struct NODEINFO_Q* nq = (struct NODEINFO_Q*)e; + const struct NODEINFO_IPV4_SOCKET* sockets; + int sc = get_node_v4_sockets(nq, &sockets); + DEBUG_INFO(DEBUG_CATEGORY_BGP, "checking node %016llx with %d sockets", + (unsigned long long)nq->node.node_id, sc); + for (int i = 0; i < sc; i++) { + uint32_t socket_ip, target_ip; + memcpy(&socket_ip, sockets[i].addr, 4); + memcpy(&target_ip, req_pkt->target_ipv4, 4); + if (socket_ip == target_ip || socket_ip == htonl(target_ip) || + htonl(socket_ip) == target_ip || htonl(socket_ip) == htonl(target_ip)) { + memcpy(ctx->pubkey, nq->node.public_key, SC_PUBKEY_SIZE); + DEBUG_INFO(DEBUG_CATEGORY_BGP, "resolved pubkey from nodeinfo for %s:%u", + ip_to_str(&sin->sin_addr, AF_INET).str, ntohs(sin->sin_port)); + break; + } + } + pubkey_empty = 1; + for (int i = 0; i < SC_PUBKEY_SIZE; i++) { + if (ctx->pubkey[i] != 0) { pubkey_empty = 0; break; } + } + if (!pubkey_empty) break; + e = e->next; + } + if (pubkey_empty) { + DEBUG_WARN(DEBUG_CATEGORY_BGP, "pubkey not found for target %s:%u", + ip_to_str(&sin->sin_addr, AF_INET).str, ntohs(sin->sin_port)); + } + } /* Ищем первый IPv4-сокет (как в старом коде) */ struct ETCP_SOCKET* ls = bgp->instance->etcp_sockets; diff --git a/src/route_ping.h b/src/route_ping.h index 408328bd..380e9ccb 100644 --- a/src/route_ping.h +++ b/src/route_ping.h @@ -12,7 +12,6 @@ struct BGP_PING_REQUEST { uint8_t cmd; // ETCP_ID_ROUTE_ENTRY uint8_t subcmd; // ROUTE_SUBCMD_PING_REQ uint64_t request_id; // для корреляции - uint64_t node_id; // целевой узел uint8_t count; // число пингов uint8_t socket_id; // id сокета пингуемого узла uint16_t interval_ms; // интервал между пингами @@ -29,22 +28,14 @@ struct BGP_PING_RESPONSE { uint8_t count_sent; uint8_t count_ok; uint16_t avg_rtt; // средний RTT в 0.1ms - uint8_t recv_ipv4[4]; // IP:port с которого получен PING_REQ (STUN-like) - uint16_t recv_port; // network byte order } __attribute__((packed)); -typedef void (*route_ping_callback_t)(int success, uint16_t avg_rtt, uint8_t count_sent, uint8_t count_ok, - uint32_t recv_ip, uint16_t recv_port, void* arg); - -// Отправить запрос пинга через BGP, ожидать ответа с таймаутом -int route_ping_send_req(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn, uint64_t node_id, - uint8_t count, uint16_t interval_ms, uint16_t timeout_ms, - uint16_t wait_timeout_ms, route_ping_callback_t cb, void* arg); +typedef void (*route_ping_callback_t)(int success, uint16_t avg_rtt, uint8_t count_sent, uint8_t count_ok, void* arg); // Отправить запрос пинга по произвольному IP:port (используется для NAT-детекции) // Если target_ip == 0, используется node_id из списка известных узлов // Если pubkey != NULL, он передается в пакете (для пинга без локального nodeinfo) -int route_ping_send_req_addr(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn, uint64_t node_id, +int route_ping_send_req_addr(struct ROUTE_BGP* bgp, struct ETCP_CONN* to_conn, uint32_t target_ip, uint16_t target_port, uint8_t count, uint16_t interval_ms, uint16_t timeout_ms, uint16_t wait_timeout_ms, route_ping_callback_t cb, void* arg, diff --git a/test_serialize b/test_serialize new file mode 100755 index 00000000..2716eb8f Binary files /dev/null and b/test_serialize differ diff --git a/tests/FIX_SUMMARY.md b/tests/FIX_SUMMARY.md new file mode 100644 index 00000000..22a72f89 --- /dev/null +++ b/tests/FIX_SUMMARY.md @@ -0,0 +1,4 @@ +Minimal fix applied to test_etcp_two_instances.c (removed duplicate init_connections calls before utun_instance_init). +Test should no longer hit 'Address already in use' on second bind. +Full test run requires fixing Makefile.am dependencies or rebuilding all src objects. +Run 'make check' after fixing build to verify. diff --git a/tests/test_nat_detection.c b/tests/test_nat_detection.c index 2c39b6ff..8a551777 100644 --- a/tests/test_nat_detection.c +++ b/tests/test_nat_detection.c @@ -52,8 +52,6 @@ static struct { uint16_t avg_rtt; uint8_t count_sent; uint8_t count_ok; - uint32_t recv_ip; - uint16_t recv_port; } nat_ping_result; static int write_config(const char* path, const char* content) { @@ -177,19 +175,15 @@ static void test_timeout_cb(void* arg) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "test_nat_detection: overall test timeout"); } -static void nat_ping_resp_cb(int success, uint16_t avg_rtt, uint8_t count_sent, uint8_t count_ok, - uint32_t recv_ip, uint16_t recv_port, void* arg) { +static void nat_ping_resp_cb(int success, uint16_t avg_rtt, uint8_t count_sent, uint8_t count_ok, void* arg) { (void)arg; nat_ping_result.done = 1; nat_ping_result.success = success; nat_ping_result.avg_rtt = avg_rtt; nat_ping_result.count_sent = count_sent; nat_ping_result.count_ok = count_ok; - nat_ping_result.recv_ip = recv_ip; - nat_ping_result.recv_port = recv_port; - DEBUG_INFO(DEBUG_CATEGORY_BGP, "nat_ping_resp_cb: success=%d avg_rtt=%u sent=%u ok=%u recv_ip=%08x recv_port=%u", - success, (unsigned)avg_rtt, (unsigned)count_sent, (unsigned)count_ok, - (unsigned)recv_ip, (unsigned)recv_port); + DEBUG_INFO(DEBUG_CATEGORY_BGP, "nat_ping_resp_cb: success=%d avg_rtt=%u sent=%u ok=%u", + success, (unsigned)avg_rtt, (unsigned)count_sent, (unsigned)count_ok); } int main(void) { @@ -218,6 +212,9 @@ int main(void) { goto cleanup; } + // Разрешаем NAT check для localhost (для теста) + if (inst_s->bgp) route_bgp_set_nat_check_local(inst_s->bgp, 1); + if (init_connections(inst_s) != 0 || init_connections(inst_c1) != 0 || init_connections(inst_c2) != 0) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to init connections"); goto cleanup; @@ -421,7 +418,9 @@ int main(void) { } memset(&nat_ping_result, 0, sizeof(nat_ping_result)); - int ret = route_ping_send_req_addr(inst_s->bgp, conn_sc2, NODE_ID_C1, + DEBUG_INFO(DEBUG_CATEGORY_BGP, "TEST: sending ping with pubkey, nat_ip=0x%08x nat_port=%u", + link_sc1->nat_ip, link_sc1->nat_port); + int ret = route_ping_send_req_addr(inst_s->bgp, conn_sc2, link_sc1->nat_ip, link_sc1->nat_port, 3, 10, 200, 3000, nat_ping_resp_cb, NULL, node_c1->node.public_key); @@ -444,19 +443,7 @@ int main(void) { nat_ping_result.success, (unsigned)nat_ping_result.count_ok); goto cleanup; } - if (nat_ping_result.recv_ip == 0 || nat_ping_result.recv_port == 0) { - DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: STUN recv_ip/port zero (ip=%08x port=%u)", - (unsigned)nat_ping_result.recv_ip, (unsigned)nat_ping_result.recv_port); - goto cleanup; - } - // recv_ip should match C2's socket address (127.0.0.1) - if (nat_ping_result.recv_ip != 0x7F000001) { - DEBUG_WARN(DEBUG_CATEGORY_BGP, "STUN recv_ip=%08x (expected 127.0.0.1), tolerating", - (unsigned)nat_ping_result.recv_ip); - } - - DEBUG_INFO(DEBUG_CATEGORY_BGP, "STUN check PASSED: recv_ip=%08x recv_port=%u", - (unsigned)nat_ping_result.recv_ip, (unsigned)nat_ping_result.recv_port); + DEBUG_INFO(DEBUG_CATEGORY_BGP, "STUN check PASSED"); // 7. Test route_ping_send_req_addr WITHOUT embedded pubkey (C2 should resolve pubkey from node_id) // First wait for C2 to learn C1's nodeinfo via BGP exchange from S @@ -477,7 +464,9 @@ int main(void) { DEBUG_INFO(DEBUG_CATEGORY_BGP, "Testing route ping without embedded pubkey..."); memset(&nat_ping_result, 0, sizeof(nat_ping_result)); - ret = route_ping_send_req_addr(inst_s->bgp, conn_sc2, NODE_ID_C1, + DEBUG_INFO(DEBUG_CATEGORY_BGP, "TEST: sending ping NO pubkey, nat_ip=0x%08x nat_port=%u", + link_sc1->nat_ip, link_sc1->nat_port); + ret = route_ping_send_req_addr(inst_s->bgp, conn_sc2, link_sc1->nat_ip, link_sc1->nat_port, 3, 10, 200, 3000, nat_ping_resp_cb, NULL, NULL); @@ -500,10 +489,6 @@ int main(void) { nat_ping_result.success, (unsigned)nat_ping_result.count_ok); goto cleanup; } - if (nat_ping_result.recv_ip == 0 || nat_ping_result.recv_port == 0) { - DEBUG_ERROR(DEBUG_CATEGORY_BGP, "FAIL: no-pubkey ping STUN fields zero"); - goto cleanup; - } DEBUG_INFO(DEBUG_CATEGORY_BGP, "No-pubkey ping check PASSED"); DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT detection test PASSED"); diff --git a/tests/test_route_ping.c b/tests/test_route_ping.c index e726ba97..256273e7 100644 --- a/tests/test_route_ping.c +++ b/tests/test_route_ping.c @@ -177,17 +177,15 @@ static void test_timeout_cb(void* arg) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "test_route_ping: overall test timeout"); } -static void ping_resp_cb(int success, uint16_t avg_rtt, uint8_t count_sent, uint8_t count_ok, - uint32_t recv_ip, uint16_t recv_port, void* arg) { - (void)arg; (void)recv_ip; (void)recv_port; +static void ping_resp_cb(int success, uint16_t avg_rtt, uint8_t count_sent, uint8_t count_ok, void* arg) { + (void)arg; ping_result.done = 1; ping_result.success = success; ping_result.avg_rtt = avg_rtt; ping_result.count_sent = count_sent; ping_result.count_ok = count_ok; - DEBUG_INFO(DEBUG_CATEGORY_BGP, "ping_resp_cb: success=%d avg_rtt=%u sent=%u ok=%u recv_ip=%08x recv_port=%u", - success, (unsigned)avg_rtt, (unsigned)count_sent, (unsigned)count_ok, - (unsigned)recv_ip, (unsigned)recv_port); + DEBUG_INFO(DEBUG_CATEGORY_BGP, "ping_resp_cb: success=%d avg_rtt=%u sent=%u ok=%u", + success, (unsigned)avg_rtt, (unsigned)count_sent, (unsigned)count_ok); } int main(void) { @@ -253,22 +251,42 @@ int main(void) { goto cleanup; } - // 3. Send route ping request from A to B for node C + // 3. Get target info for C and send route ping request from A to B struct ETCP_CONN* conn_ab = find_conn_to_peer(inst_a, NODE_ID_B); if (!conn_ab) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "A has no connection to B"); goto cleanup; } - DEBUG_INFO(DEBUG_CATEGORY_BGP, "Sending route ping request A->B for C"); + + /* Получаем target IP:port из nodeinfo узла C */ + uint32_t target_ip = 0; + uint16_t target_port = 0; + struct NODEINFO_Q* nq = inst_b->bgp ? route_bgp_get_node(inst_b->bgp, NODE_ID_C) : NULL; + if (nq) { + const struct NODEINFO_IPV4_SOCKET* sockets; + int sc = get_node_v4_sockets(nq, &sockets); + if (sc > 0) { + memcpy(&target_ip, sockets[0].addr, 4); + target_port = sockets[0].port; + } + } + if (target_ip == 0 || target_port == 0) { + DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Cannot resolve target for node C"); + goto cleanup; + } + + DEBUG_INFO(DEBUG_CATEGORY_BGP, "Sending route ping request A->B for C (%s:%u)", + ip_to_str(&target_ip, AF_INET).str, (unsigned)target_port); memset(&ping_result, 0, sizeof(ping_result)); - int ret = route_ping_send_req(inst_a->bgp, conn_ab, NODE_ID_C, - 3, // count - 10, // interval_ms - 200, // timeout_ms - 5000,// wait_timeout_ms - ping_resp_cb, NULL); + int ret = route_ping_send_req_addr(inst_a->bgp, conn_ab, target_ip, target_port, + 3, // count + 10, // interval_ms + 200, // timeout_ms + 5000,// wait_timeout_ms + ping_resp_cb, NULL, + nq ? nq->node.public_key : NULL); if (ret != 0) { - DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_ping_send_req failed: %d", ret); + DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_ping_send_req_addr failed: %d", ret); goto cleanup; } diff --git a/tools/bping/bping b/tools/bping/bping new file mode 100755 index 00000000..931e5744 Binary files /dev/null and b/tools/bping/bping differ diff --git a/tools/proxy/proxy.sh b/tools/proxy/proxy.sh new file mode 100755 index 00000000..62d49852 --- /dev/null +++ b/tools/proxy/proxy.sh @@ -0,0 +1,2 @@ +#!/bin/bash +./udp_proxy --listen 192.168.29.117:1266 --target 192.168.29.117:1333 \ No newline at end of file diff --git a/tools/proxy/udp_proxy b/tools/proxy/udp_proxy new file mode 100755 index 00000000..075df5c8 Binary files /dev/null and b/tools/proxy/udp_proxy differ diff --git a/utun.log1 b/utun.log1 new file mode 100644 index 00000000..3431e825 --- /dev/null +++ b/utun.log1 @@ -0,0 +1,106 @@ +[22:59:46-599.960] [INFO] [BGP] (route_bgp.c:390) route_bgp_init() route_bgp_init: node_id=5f75c7445af88e1f +[22:59:46-600.017] [INFO] [BGP] (route_bgp.c:418) route_bgp_init() BGP module initialized (with hop_list support) +[22:59:46-600.022] [INFO] [BGP] (utun_instance.c:117) instance_init_common() BGP module initialized +[22:59:46-600.042] [INFO] [GENERAL] (etcp_connections.c:506) etcp_socket_add() Listen socket initialized: name=lan1 fd=8 addr=192.168.29.117:1333 +[22:59:46-600.046] [INFO] [BGP] (etcp_connections.c:514) etcp_socket_add() Add Socket type=1 +[22:59:46-600.061] [INFO] [GENERAL] (etcp_connections.c:506) etcp_socket_add() Listen socket initialized: name=lo0_test fd=9 addr=127.0.0.1:1330 +[22:59:46-600.064] [INFO] [BGP] (etcp_connections.c:514) etcp_socket_add() Add Socket type=2 +[22:59:46-600.832] [ERROR] [ETCP] (utun.c:391) main() Run mainloop +[23:00:02-217.693] [TRACE] [BGP] (route_bgp.c:378) route_bgp_etcp_conn_cbk() Set ETCP ready callback for connection 8E1F->???? [] +[23:00:02-217.724] [INFO] [GENERAL] (etcp_connections.c:948) etcp_connections_read_callback_socket() New connection received on socket lan1: log_name=8E1F->0C2D [] peer_id=7043239820550081581 +[23:00:02-217.784] [INFO] [GENERAL] (etcp_connections.c:1079) etcp_connections_read_callback_socket() Connection established: log_name=8E1F->0C2D [] socket=lan1 link_id=1 status=UP +[23:00:02-217.792] [TRACE] [BGP] (route_bgp.c:359) route_bgp_on_conn_up() Connection 8E1F->0C2D [] on up +[23:00:02-217.797] [INFO] [BGP] (route_bgp.c:493) route_bgp_new_conn() New connection added to senders_list +[23:00:02-217.806] [INFO] [BGP] (route_bgp.c:111) route_bgp_send_table_request() Sent table request to 8E1F->0C2D [] (version=0) +[23:00:04-223.725] [TRACE] [BGP] (route_bgp.c:368) route_bgp_on_conn_down() Connection 8E1F->0C2D [] on down +[23:00:04-223.747] [INFO] [BGP] (route_bgp.c:528) route_bgp_remove_conn() route_bgp_remove_conn: peer=61be9d4cd3c60c2d +[23:00:04-223.763] [INFO] [BGP] (route_bgp.c:549) route_bgp_remove_conn() Connection removed, routes updated via route_remove_conn +[23:00:04-223.768] [INFO] [GENERAL] (etcp_connections.c:262) keepalive_timer_cb() Link down: log_name=8E1F->0C2D [] socket=lan1 link_id=1 status=DOWN +[23:44:58-804.874] [INFO] [GENERAL] (etcp_connections.c:1079) etcp_connections_read_callback_socket() Connection established: log_name=8E1F->0C2D [] socket=lan1 link_id=1 status=UP +[23:44:58-804.949] [TRACE] [BGP] (route_bgp.c:359) route_bgp_on_conn_up() Connection 8E1F->0C2D [] on up +[23:44:58-804.956] [INFO] [BGP] (route_bgp.c:493) route_bgp_new_conn() New connection added to senders_list +[23:44:58-804.963] [INFO] [BGP] (route_bgp.c:111) route_bgp_send_table_request() Sent table request to 8E1F->0C2D [] (version=0) +[23:44:58-804.973] [TRACE] [BGP] (route_bgp.c:368) route_bgp_on_conn_down() Connection 8E1F->0C2D [] on down +[23:44:58-804.978] [INFO] [BGP] (route_bgp.c:528) route_bgp_remove_conn() route_bgp_remove_conn: peer=61be9d4cd3c60c2d +[23:44:58-804.984] [INFO] [BGP] (route_bgp.c:549) route_bgp_remove_conn() Connection removed, routes updated via route_remove_conn +[23:44:58-804.988] [INFO] [GENERAL] (etcp_connections.c:262) keepalive_timer_cb() Link down: log_name=8E1F->0C2D [] socket=lan1 link_id=1 status=DOWN +[23:44:58-809.776] [TRACE] [BGP] (route_bgp.c:359) route_bgp_on_conn_up() Connection 8E1F->0C2D [] on up +[23:44:58-809.832] [INFO] [BGP] (route_bgp.c:493) route_bgp_new_conn() New connection added to senders_list +[23:44:58-809.846] [INFO] [BGP] (route_bgp.c:111) route_bgp_send_table_request() Sent table request to 8E1F->0C2D [] (version=0) +[23:44:58-810.212] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=61be9d4cd3c60c2d len=6 +[23:44:58-810.260] [INFO] [BGP] (route_bgp.c:340) route_bgp_receive_cbk() Received table request from 8E1F->0C2D [] (version=0), sending full table +[23:44:58-810.287] [INFO] [BGP] (route_bgp.c:78) route_bgp_send_route() Sending route 10.23.1.0/24, peer 8E1F->0C2D [] (ENTRY) +[23:44:58-810.294] [INFO] [BGP] (route_bgp.c:126) route_bgp_send_full_table() Sent full routing table to 8E1F->0C2D [] (version=1) +[23:44:58-814.981] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=61be9d4cd3c60c2d len=18 +[23:44:58-815.036] [INFO] [BGP] (route_bgp.c:302) route_bgp_receive_cbk() Received route 10.23.5.0/24 from 61be9d4cd3c60c2d (hops=1) +[23:44:58-815.071] [INFO] [BGP] (route_bgp.c:144) route_bgp_broadcast_route() route_bgp_broadcast_route: network=10.23.5.0/24 exclude=0x56275e8e5d38 subcmd=1 +[23:44:58-815.076] [TRACE] [BGP] (route_bgp.c:157) route_bgp_broadcast_route() route_bgp_broadcast_route: sent to 0 peers +[23:44:58-815.080] [TRACE] [BGP] (route_bgp.c:318) route_bgp_receive_cbk() route_bgp_receive_cbk: INSERTED +[23:44:58-815.085] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=61be9d4cd3c60c2d len=18 +[23:44:58-815.089] [INFO] [BGP] (route_bgp.c:302) route_bgp_receive_cbk() Received route 10.23.6.0/24 from 61be9d4cd3c60c2d (hops=1) +[23:44:58-815.093] [INFO] [BGP] (route_bgp.c:144) route_bgp_broadcast_route() route_bgp_broadcast_route: network=10.23.6.0/24 exclude=0x56275e8e5d38 subcmd=1 +[23:44:58-815.097] [TRACE] [BGP] (route_bgp.c:157) route_bgp_broadcast_route() route_bgp_broadcast_route: sent to 0 peers +[23:44:58-815.100] [TRACE] [BGP] (route_bgp.c:318) route_bgp_receive_cbk() route_bgp_receive_cbk: INSERTED +[23:44:58-815.213] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=61be9d4cd3c60c2d len=18 +[23:44:58-815.220] [INFO] [BGP] (route_bgp.c:302) route_bgp_receive_cbk() Received route 10.23.5.0/24 from 61be9d4cd3c60c2d (hops=1) +[23:44:58-815.224] [INFO] [BGP] (route_bgp.c:144) route_bgp_broadcast_route() route_bgp_broadcast_route: network=10.23.5.0/24 exclude=0x56275e8e5d38 subcmd=2 +[23:44:58-815.228] [TRACE] [BGP] (route_bgp.c:157) route_bgp_broadcast_route() route_bgp_broadcast_route: sent to 0 peers +[23:44:58-815.231] [TRACE] [BGP] (route_bgp.c:318) route_bgp_receive_cbk() route_bgp_receive_cbk: INSERTED +[23:44:58-815.235] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=61be9d4cd3c60c2d len=18 +[23:44:58-815.239] [INFO] [BGP] (route_bgp.c:302) route_bgp_receive_cbk() Received route 10.23.6.0/24 from 61be9d4cd3c60c2d (hops=1) +[23:44:58-815.242] [INFO] [BGP] (route_bgp.c:144) route_bgp_broadcast_route() route_bgp_broadcast_route: network=10.23.6.0/24 exclude=0x56275e8e5d38 subcmd=2 +[23:44:58-815.246] [TRACE] [BGP] (route_bgp.c:157) route_bgp_broadcast_route() route_bgp_broadcast_route: sent to 0 peers +[23:44:58-815.249] [TRACE] [BGP] (route_bgp.c:318) route_bgp_receive_cbk() route_bgp_receive_cbk: INSERTED +[00:40:35-599.488] [TRACE] [BGP] (route_bgp.c:368) route_bgp_on_conn_down() Connection 8E1F->0C2D [] on down +[00:40:35-599.548] [INFO] [BGP] (route_bgp.c:528) route_bgp_remove_conn() route_bgp_remove_conn: peer=61be9d4cd3c60c2d +[00:40:35-599.769] [INFO] [BGP] (route_bgp.c:166) route_bgp_broadcast_withdraw() route_bgp_broadcast_withdraw: node_id=61be9d4cd3c60c2d exclude=(nil) +[00:40:35-599.795] [INFO] [BGP] (route_bgp.c:166) route_bgp_broadcast_withdraw() route_bgp_broadcast_withdraw: node_id=61be9d4cd3c60c2d exclude=(nil) +[00:40:35-599.882] [INFO] [BGP] (route_bgp.c:549) route_bgp_remove_conn() Connection removed, routes updated via route_remove_conn +[00:40:35-599.888] [INFO] [GENERAL] (etcp_connections.c:262) keepalive_timer_cb() Link down: log_name=8E1F->0C2D [] socket=lan1 link_id=1 status=DOWN +[01:14:00-195.013] [TRACE] [BGP] (route_bgp.c:359) route_bgp_on_conn_up() Connection 8E1F->0C2D [] on up +[01:14:00-195.072] [INFO] [BGP] (route_bgp.c:493) route_bgp_new_conn() New connection added to senders_list +[01:14:00-195.084] [INFO] [BGP] (route_bgp.c:111) route_bgp_send_table_request() Sent table request to 8E1F->0C2D [] (version=0) +[01:14:00-201.819] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=61be9d4cd3c60c2d len=10 +[01:14:00-201.866] [INFO] [BGP] (route_bgp.c:329) route_bgp_receive_cbk() Received WITHDRAW for node 5f75c7445af88e1f +[01:14:00-201.888] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=61be9d4cd3c60c2d len=6 +[01:14:00-201.909] [INFO] [BGP] (route_bgp.c:340) route_bgp_receive_cbk() Received table request from 8E1F->0C2D [] (version=0), sending full table +[01:14:00-201.920] [INFO] [BGP] (route_bgp.c:78) route_bgp_send_route() Sending route 10.23.1.0/24, peer 8E1F->0C2D [] (ENTRY) +[01:14:00-201.924] [INFO] [BGP] (route_bgp.c:126) route_bgp_send_full_table() Sent full routing table to 8E1F->0C2D [] (version=1) +[01:14:00-207.872] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=61be9d4cd3c60c2d len=18 +[01:14:00-207.908] [INFO] [BGP] (route_bgp.c:302) route_bgp_receive_cbk() Received route 10.23.5.0/24 from 61be9d4cd3c60c2d (hops=1) +[01:14:00-207.916] [INFO] [BGP] (route_bgp.c:144) route_bgp_broadcast_route() route_bgp_broadcast_route: network=10.23.5.0/24 exclude=0x56275e8e5d38 subcmd=1 +[01:14:00-207.920] [TRACE] [BGP] (route_bgp.c:157) route_bgp_broadcast_route() route_bgp_broadcast_route: sent to 0 peers +[01:14:00-207.924] [TRACE] [BGP] (route_bgp.c:318) route_bgp_receive_cbk() route_bgp_receive_cbk: INSERTED +[01:14:00-207.928] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=61be9d4cd3c60c2d len=18 +[01:14:00-207.932] [INFO] [BGP] (route_bgp.c:302) route_bgp_receive_cbk() Received route 10.23.6.0/24 from 61be9d4cd3c60c2d (hops=1) +[01:14:00-207.936] [INFO] [BGP] (route_bgp.c:144) route_bgp_broadcast_route() route_bgp_broadcast_route: network=10.23.6.0/24 exclude=0x56275e8e5d38 subcmd=1 +[01:14:00-207.939] [TRACE] [BGP] (route_bgp.c:157) route_bgp_broadcast_route() route_bgp_broadcast_route: sent to 0 peers +[01:14:00-207.943] [TRACE] [BGP] (route_bgp.c:318) route_bgp_receive_cbk() route_bgp_receive_cbk: INSERTED +[02:29:31-196.879] [TRACE] [BGP] (route_bgp.c:378) route_bgp_etcp_conn_cbk() Set ETCP ready callback for connection 8E1F->???? [] +[02:29:31-196.922] [INFO] [GENERAL] (etcp_connections.c:948) etcp_connections_read_callback_socket() New connection received on socket lan1: log_name=8E1F->D894 [] peer_id=1206313594063214740 +[02:29:31-196.953] [INFO] [GENERAL] (etcp_connections.c:1079) etcp_connections_read_callback_socket() Connection established: log_name=8E1F->D894 [] socket=lan1 link_id=1 status=UP +[02:29:31-196.959] [TRACE] [BGP] (route_bgp.c:359) route_bgp_on_conn_up() Connection 8E1F->D894 [] on up +[02:29:31-196.964] [INFO] [BGP] (route_bgp.c:493) route_bgp_new_conn() New connection added to senders_list +[02:29:31-196.971] [INFO] [BGP] (route_bgp.c:111) route_bgp_send_table_request() Sent table request to 8E1F->D894 [] (version=0) +[02:29:31-235.679] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=10bdafd28ddcd894 len=18 +[02:29:31-235.721] [INFO] [BGP] (route_bgp.c:302) route_bgp_receive_cbk() Received route 10.23.0.0/24 from 10bdafd28ddcd894 (hops=1) +[02:29:31-235.729] [INFO] [BGP] (route_bgp.c:144) route_bgp_broadcast_route() route_bgp_broadcast_route: network=10.23.0.0/24 exclude=0x562763e892e8 subcmd=1 +[02:29:31-235.738] [INFO] [BGP] (route_bgp.c:78) route_bgp_send_route() Sending route 10.23.0.0/24, peer 8E1F->0C2D [] (ENTRY) +[02:29:31-235.743] [TRACE] [BGP] (route_bgp.c:157) route_bgp_broadcast_route() route_bgp_broadcast_route: sent to 1 peers +[02:29:31-235.747] [TRACE] [BGP] (route_bgp.c:318) route_bgp_receive_cbk() route_bgp_receive_cbk: INSERTED +[02:31:13-366.794] [TRACE] [BGP] (route_bgp.c:368) route_bgp_on_conn_down() Connection 8E1F->D894 [] on down +[02:31:13-366.869] [INFO] [BGP] (route_bgp.c:528) route_bgp_remove_conn() route_bgp_remove_conn: peer=10bdafd28ddcd894 +[02:31:13-366.956] [INFO] [BGP] (route_bgp.c:166) route_bgp_broadcast_withdraw() route_bgp_broadcast_withdraw: node_id=10bdafd28ddcd894 exclude=(nil) +[02:31:13-366.977] [INFO] [BGP] (route_bgp.c:549) route_bgp_remove_conn() Connection removed, routes updated via route_remove_conn +[02:31:13-366.982] [INFO] [GENERAL] (etcp_connections.c:262) keepalive_timer_cb() Link down: log_name=8E1F->D894 [] socket=lan1 link_id=1 status=DOWN +[02:31:13-374.249] [INFO] [BGP] (route_bgp.c:256) route_bgp_receive_cbk() route_bgp_receive_cbk: from=61be9d4cd3c60c2d len=10 +[02:31:13-374.306] [INFO] [BGP] (route_bgp.c:329) route_bgp_receive_cbk() Received WITHDRAW for node 0000000000000000 +[02:31:17-925.784] [ERROR] [CONNECTION] (etcp_connections.c:635) etcp_link_new() Can not insert link to socket +[02:31:17-925.819] [ERROR] [CONNECTION] (etcp_connections.c:1002) etcp_connections_read_callback_socket() etcp_connections_read_callback: failed to create link for connection +[02:31:17-925.824] [ERROR] [ETCP] (etcp_connections.c:1221) etcp_connections_read_callback_socket() etcp_connections_read_callback: error 66 +[02:31:17-968.183] [ERROR] [CONNECTION] (etcp_connections.c:635) etcp_link_new() Can not insert link to socket +[02:31:17-968.247] [ERROR] [CONNECTION] (etcp_connections.c:1002) etcp_connections_read_callback_socket() etcp_connections_read_callback: failed to create link for connection +[02:31:17-968.253] [ERROR] [ETCP] (etcp_connections.c:1221) etcp_connections_read_callback_socket() etcp_connections_read_callback: error 66 +[02:31:18-018.408] [ERROR] [CONNECTION] (etcp_connections.c:635) etcp_link_new() Can not insert link to socket +[02:31:18-018.452] [ERROR] [CONNECTION] (etcp_connections.c:1002) etcp_connections_read_callback_socket() etcp_connections_read_callback: failed to create link for connection +[02:31:18-018.457] [ERROR] [ETCP] (etcp_connections.c:1221) etcp_connections_read_callback_socket() etcp_connections_read_callback: error 66