#ifndef TEST_CONNECTION_LOSS_H #define TEST_CONNECTION_LOSS_H #include "etcp_api.h" #include "etcp_connections.h" #include "utun_instance.h" #include "../lib/debug_config.h" /* Разрыв пары узлов охватывает и новые линки из свежего NODEINFO. * only/spared позволяют отдельно проверить потерю одного линка и работу * единственного оставшегося линка. Контекст живёт до loss_destroy(). */ struct test_connection_loss { struct UTUN_INSTANCE* instance; uint64_t peer_id; struct ETCP_LINK* only; struct ETCP_LINK* spared; int blocked; unsigned links; unsigned long long dropped; }; static ssize_t test_loss_send(socket_t fd, const void* buf, size_t len, const struct sockaddr* addr, socklen_t addr_len, struct ETCP_LINK* link, void* arg) { struct test_connection_loss* loss = arg; if (loss->blocked && (!loss->only || loss->only == link) && loss->spared != link) { loss->dropped++; return (ssize_t)len; } return socket_sendto(fd, buf, len, addr, addr_len); } static void test_loss_link(struct ETCP_CONN* conn, struct ETCP_LINK* link, int old_state, int old_status, void* arg) { (void)old_state; (void)old_status; struct test_connection_loss* loss = arg; if (conn->peer_node_id != loss->peer_id || link->send_hook == test_loss_send) return; link->send_hook = test_loss_send; link->send_hook_ctx = loss; loss->links++; DEBUG_INFO(DEBUG_CATEGORY_BGP, "test partition: peer=%016llx attached link=%p total=%u blocked=%d", (unsigned long long)loss->peer_id, (void*)link, loss->links, loss->blocked); } static void test_loss_init(struct test_connection_loss* loss, struct UTUN_INSTANCE* instance, uint64_t peer_id) { loss->instance = instance; loss->peer_id = peer_id; etcp_add_link_status_cbk(instance, test_loss_link, loss); struct ETCP_CONN* conn = instance_find_conn(instance, peer_id); for (struct ETCP_LINK* link = conn ? conn->links : NULL; link; link = link->next) test_loss_link(conn, link, 0, 0, loss); } static void test_loss_set(struct test_connection_loss* loss, int blocked, struct ETCP_LINK* only, struct ETCP_LINK* spared) { loss->blocked = blocked; loss->only = only; loss->spared = spared; DEBUG_INFO(DEBUG_CATEGORY_BGP, "test partition: peer=%016llx blocked=%d only=%p spared=%p links=%u dropped=%llu", (unsigned long long)loss->peer_id, blocked, (void*)only, (void*)spared, loss->links, loss->dropped); } static void test_loss_destroy(struct test_connection_loss* loss) { if (!loss->instance) return; etcp_remove_link_status_cbk(loss->instance, test_loss_link, loss); struct ETCP_CONN* conn = instance_find_conn(loss->instance, loss->peer_id); for (struct ETCP_LINK* link = conn ? conn->links : NULL; link; link = link->next) { if (link->send_hook_ctx != loss) continue; link->send_hook = NULL; link->send_hook_ctx = NULL; } loss->instance = NULL; } #endif