diff --git a/.gitignore b/.gitignore index 851ee33..9de2f2a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,8 +6,10 @@ *.so *.so.* utun + +# binary files *.exe -*[^.]* # binaries +**/*[^.] # Autotools Makefile diff --git a/src/config_parser.c b/src/config_parser.c index efd01a9..a6330d5 100644 --- a/src/config_parser.c +++ b/src/config_parser.c @@ -379,6 +379,12 @@ static int parse_server(const char *key, const char *value, struct CFG_SERVER *s srv->mtu = atoi(value); return 0; } + if (strcmp(key, "loss_rate") == 0) { + srv->loss_rate = atoi(value); + if (srv->loss_rate < 0) srv->loss_rate = 0; + if (srv->loss_rate > 100) srv->loss_rate = 100; + return 0; + } return 0; } @@ -658,9 +664,9 @@ void print_config(const struct utun_config *cfg) { struct CFG_SERVER *s = cfg->servers; while (s) { struct sockaddr_in *sin = (struct sockaddr_in *)&s->ip; - DEBUG_INFO(DEBUG_CATEGORY_CONFIG, " %s: %s:%d (mark=%d, netif=%u, type=%u, mtu=%d)", + DEBUG_INFO(DEBUG_CATEGORY_CONFIG, " %s: %s:%d (mark=%d, netif=%u, type=%u, mtu=%d, loss_rate=%d%%)", s->name, ip_to_str(&sin->sin_addr, AF_INET).str, ntohs(sin->sin_port), - s->so_mark, s->netif_index, s->type, s->mtu); + s->so_mark, s->netif_index, s->type, s->mtu, s->loss_rate); s = s->next; } diff --git a/src/config_parser.h b/src/config_parser.h index 45b05f7..0fb2ac7 100644 --- a/src/config_parser.h +++ b/src/config_parser.h @@ -35,6 +35,7 @@ struct CFG_SERVER { int so_mark; uint8_t type; // public/nat/private int mtu; + int loss_rate; // packet loss rate in percent (0-100), default 0 }; struct CFG_CLIENT_LINK { diff --git a/src/etcp_connections.c b/src/etcp_connections.c index f3b6558..f27c8c8 100644 --- a/src/etcp_connections.c +++ b/src/etcp_connections.c @@ -374,7 +374,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) { +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) { DEBUG_TRACE(DEBUG_CATEGORY_CONNECTION, ""); if (!instance) return NULL; @@ -456,6 +456,7 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct socka e_sock->pkt_format_errors = 0; e_sock->type = type; e_sock->mtu = mtu; + e_sock->loss_rate = loss_rate; DEBUG_INFO(DEBUG_CATEGORY_BGP, "Add Socket type=%d", type); // Add to instance's socket list @@ -655,9 +656,17 @@ int etcp_encrypt_send(struct ETCP_DGRAM* dgram) { struct sockaddr_in* sin = (struct sockaddr_in*)addr; // inet_ntop removed - use ip_to_str } - - ssize_t sent = socket_sendto(dgram->link->conn->fd, enc_buf, enc_buf_len + dgram->noencrypt_len, + + ssize_t sent=-1; + int loss_rate = dgram->link->conn->loss_rate; + int rnd = rand() % 100; + if (loss_rate == 0 || rnd >= loss_rate) { + sent = socket_sendto(dgram->link->conn->fd, enc_buf, enc_buf_len + dgram->noencrypt_len, (struct sockaddr*)addr, addr_len); + } else { + DEBUG_WARN(DEBUG_CATEGORY_ETCP, "[%s] Packet dropped by loss_rate (rnd=%d, loss_rate=%d%%)", + dgram->link->etcp->log_name, rnd, loss_rate); + } if (sent < 0) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "sendto failed, sock_err=%d", socket_get_error()); dgram->link->send_errors++; errcode=4; goto es_err; @@ -892,6 +901,7 @@ static void etcp_connections_read_callback_socket(socket_t sock, void* arg) { memory_pool_free(e_sock->instance->pkt_pool, pkt); link->initialized = 1;// получен init request (server), считаем линк уже готовым к работе + link->link_state = 3; // connected if (link->etcp->initialized == 0) { etcp_conn_ready(link->etcp); } @@ -1089,7 +1099,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); + 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); if (e_sock && default_ip != 0) { struct in_addr addr; addr.s_addr = default_ip; diff --git a/src/etcp_connections.h b/src/etcp_connections.h index 4311abf..a1975c3 100644 --- a/src/etcp_connections.h +++ b/src/etcp_connections.h @@ -35,6 +35,7 @@ struct ETCP_SOCKET { socket_t fd; // UDP socket (cross-platform) struct sockaddr_storage local_addr; // Локальный адрес int mtu; // MTU для этого сокета + int loss_rate; // packet loss rate in percent (0-100) // для входящих подключений (links) - массив упорядоченный по ip_port_hash size_t max_channels; // сколько выделено памяти @@ -121,7 +122,7 @@ int init_connections(struct UTUN_INSTANCE* instance); // SOCKET FUNCTIONS // добавляет новый версер (сокет для приёма и отправки кодограмм. обслуживает много подключений) -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); +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); // удаляет сокет и освобождает ресурсы (грохает все его подключения и сокет) void etcp_socket_remove(struct ETCP_SOCKET* conn); diff --git a/tests/test_u_async_timeouts.c b/tests/test_u_async_timeouts.c index e6c909a..8847c01 100644 --- a/tests/test_u_async_timeouts.c +++ b/tests/test_u_async_timeouts.c @@ -11,7 +11,7 @@ #define DEBUG_CATEGORY_TEST 1 #define TIMER_COUNT 100 -#define STOP_TIMEOUT_TB 100000 /* 10 seconds in 0.1ms units */ +#define STOP_TIMEOUT_TB 10000 /* 1 seconds in 0.1ms units */ typedef struct { int timer_number; /* номер таймера 0-99 */