|
|
|
|
@ -28,6 +28,8 @@ static void etcp_link_send_init(struct ETCP_LINK* link, uint8_t reset);
|
|
|
|
|
static void etcp_link_init_timer_cbk(void* arg); |
|
|
|
|
static void etcp_link_send_keepalive(struct ETCP_LINK* link); |
|
|
|
|
static void keepalive_timer_cb(void* arg); |
|
|
|
|
static void link_stats_timer_cb(void* arg); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void etcp_link_update_inflight_lim(struct ETCP_LINK* link, uint32_t new_lim) { |
|
|
|
|
if (!link) return; |
|
|
|
|
@ -389,7 +391,7 @@ int etcp_find_free_local_link_id(struct ETCP_CONN* etcp) {
|
|
|
|
|
|
|
|
|
|
// ===============================
|
|
|
|
|
|
|
|
|
|
struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct sockaddr_storage* ip, uint32_t netif_index, int so_mark, uint8_t type, int mtu, int loss_rate) { |
|
|
|
|
struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct sockaddr_storage* ip, uint32_t netif_index, int so_mark, uint8_t type, int mtu, int loss_rate, char* name) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_CONNECTION, ""); |
|
|
|
|
if (!instance) return NULL; |
|
|
|
|
|
|
|
|
|
@ -399,6 +401,13 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct socka
|
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
e_sock->fd = SOCKET_INVALID; // Initialize to invalid socket
|
|
|
|
|
|
|
|
|
|
if (name && name[0]) { |
|
|
|
|
strncpy(e_sock->name, name, MAX_CONN_NAME_LEN - 1); |
|
|
|
|
e_sock->name[MAX_CONN_NAME_LEN - 1] = '\0'; |
|
|
|
|
} else { |
|
|
|
|
e_sock->name[0] = '\0'; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int family = AF_INET; |
|
|
|
|
if (ip) { |
|
|
|
|
@ -587,6 +596,16 @@ struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn
|
|
|
|
|
link->rtt_max_idx = 0; |
|
|
|
|
// rtt_history[] is already zeroed by calloc
|
|
|
|
|
|
|
|
|
|
// Инициализация статистики
|
|
|
|
|
link->win_timebase = 50000; // 50 ms в микросекундах
|
|
|
|
|
link->win_ptr = 0; |
|
|
|
|
link->window_pkt_transmitted = 0; |
|
|
|
|
link->window_retransmissions = 0; |
|
|
|
|
link->total_retransmissions = 0; |
|
|
|
|
memset(link->stat_win, 0, sizeof(link->stat_win)); |
|
|
|
|
|
|
|
|
|
start_stats_timer(link); |
|
|
|
|
|
|
|
|
|
// insert_link(conn, link);
|
|
|
|
|
if (insert_link(conn, link) < 0) { |
|
|
|
|
// откатываем то, что успели
|
|
|
|
|
@ -619,6 +638,11 @@ void etcp_link_close(struct ETCP_LINK* link) {
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (link->stats_timer) { |
|
|
|
|
uasync_cancel_timeout(link->etcp->instance->ua, link->stats_timer); |
|
|
|
|
link->stats_timer = NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Cancel init timer if active
|
|
|
|
|
if (link->init_timer) { |
|
|
|
|
uasync_cancel_timeout(link->etcp->instance->ua, link->init_timer); |
|
|
|
|
@ -652,6 +676,54 @@ void etcp_link_close(struct ETCP_LINK* link) {
|
|
|
|
|
u_free(link); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void start_stats_timer(struct ETCP_LINK* link) { |
|
|
|
|
if (!link || !link->etcp || !link->etcp->instance) return; |
|
|
|
|
if (link->stats_timer) { |
|
|
|
|
uasync_cancel_timeout(link->etcp->instance->ua, link->stats_timer); |
|
|
|
|
} |
|
|
|
|
uint32_t tb = link->win_timebase / 100; // us → 0.1 ms units
|
|
|
|
|
if (tb < 50) tb = 50; // минимум 5 ms
|
|
|
|
|
if (tb > 5000) tb = 5000; // max 500 ms
|
|
|
|
|
link->stats_timer = uasync_set_timeout( |
|
|
|
|
link->etcp->instance->ua, |
|
|
|
|
tb, |
|
|
|
|
link, |
|
|
|
|
link_stats_timer_cb |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// === Новый callback таймера ===
|
|
|
|
|
static void link_stats_timer_cb(void* arg) { |
|
|
|
|
struct ETCP_LINK* link = (struct ETCP_LINK*)arg; |
|
|
|
|
if (!link || !link->etcp) return; |
|
|
|
|
|
|
|
|
|
// 1. Сохраняем снимок текущего окна
|
|
|
|
|
link->stat_win[link->win_ptr].rtt = link->rtt_avg10; |
|
|
|
|
link->stat_win[link->win_ptr].pkt_loss = (uint16_t)link->window_retransmissions; |
|
|
|
|
link->stat_win[link->win_ptr].pkt_transmitted = link->window_pkt_transmitted; |
|
|
|
|
|
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] stats window updated (win_timebase=%u us, rtt=%u, retrans=%u, transmitted=%u)", |
|
|
|
|
link->etcp->log_name, link->win_timebase, link->rtt_avg10, link->window_retransmissions, link->window_pkt_transmitted); |
|
|
|
|
|
|
|
|
|
// 2. Переходим к следующему слоту
|
|
|
|
|
link->win_ptr = (link->win_ptr + 1) % 32; |
|
|
|
|
|
|
|
|
|
// 3. Обнуляем накопители для нового окна
|
|
|
|
|
link->window_pkt_transmitted = 0; |
|
|
|
|
link->window_retransmissions = 0; |
|
|
|
|
|
|
|
|
|
// 4. Плавная подстройка win_timebase под rtt/2 (в микросекундах)
|
|
|
|
|
uint32_t target_us = (uint32_t)link->rtt_avg10 * 50ULL; // rtt_avg10 (0.1 ms) → rtt/2 в us
|
|
|
|
|
if (target_us < 10000) target_us = 10000; // минимум 10 ms
|
|
|
|
|
if (target_us > 500000) target_us = 500000; // максимум 0.5 s
|
|
|
|
|
|
|
|
|
|
link->win_timebase = (link->win_timebase * 7 + target_us) / 8; |
|
|
|
|
|
|
|
|
|
// 5. Перезапускаем таймер с новым интервалом
|
|
|
|
|
start_stats_timer(link); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int etcp_encrypt_send(struct ETCP_DGRAM* dgram) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_CONNECTION, ""); |
|
|
|
|
|
|
|
|
|
@ -1127,7 +1199,7 @@ int init_connections(struct UTUN_INSTANCE* instance) {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct ETCP_SOCKET* e_sock = etcp_socket_add(instance, &server->ip, server->netif_index, server->so_mark, server->type, server->mtu ? server->mtu : instance->config->global.mtu, server->loss_rate); |
|
|
|
|
struct ETCP_SOCKET* e_sock = etcp_socket_add(instance, &server->ip, server->netif_index, server->so_mark, server->type, server->mtu ? server->mtu : instance->config->global.mtu, server->loss_rate, server->name); |
|
|
|
|
if (e_sock && default_ip != 0) { |
|
|
|
|
struct in_addr addr; |
|
|
|
|
addr.s_addr = default_ip; |
|
|
|
|
|