diff --git a/src/transport_layer/etcp_connections.c b/src/transport_layer/etcp_connections.c index fa44c4658..9e695716f 100644 --- a/src/transport_layer/etcp_connections.c +++ b/src/transport_layer/etcp_connections.c @@ -1117,10 +1117,10 @@ static struct ETCP_LINK* link_create(struct ETCP_CONN* etcp, struct ETCP_SOCKET* link->etcp = etcp; link->is_server = is_server; link->is_tcp = (uint8_t)is_tcp; - int mtu; - mtu = conn ? conn->mtu : STCP_MAX_MSG_SIZE; - if (is_tcp) mtu = STCP_MAX_MSG_SIZE; - else { if (mtu == 0) mtu = 1280; if (mtu > PACKET_DATA_MAX_MTU) mtu = PACKET_DATA_MAX_MTU; } + // Предел кадра STCP не задаёт MTU ETCP: фрагмент со служебными секциями должен вмещаться в 1500 байт. + int mtu = is_tcp || !conn ? PACKET_DATA_MAX_MTU : conn->mtu; + if (mtu == 0) mtu = 1280; + if (mtu > PACKET_DATA_MAX_MTU) mtu = PACKET_DATA_MAX_MTU; if (driver) { size_t maximum = driver->get_state(driver->ctx).max_packet; mtu = maximum < PACKET_DATA_MAX_MTU ? (int)maximum : PACKET_DATA_MAX_MTU; diff --git a/tests/test_etcp_stcp.c b/tests/test_etcp_stcp.c index bd5f5a5c2..e3a992916 100644 --- a/tests/test_etcp_stcp.c +++ b/tests/test_etcp_stcp.c @@ -5,6 +5,7 @@ #include "etcp.h" #include "etcp_api.h" #include "etcp_connections.h" +#include "etcp_loadbalancer.h" #include "etcp_session.h" #include "etcp_bbr.h" #include "stcp_link.h" @@ -210,6 +211,34 @@ static void exchange_messages(void) { for (int i = 0; i < 2; i++) CHECK(!endpoints[i].conn->input_wait_ack->count && !endpoints[i].conn->input_send_q->count); } +// Накопленные ACK должны разбиваться на пакеты до 1500 байт и успешно уходить через настоящий STCP. +static void check_tcp_ack_mtu(void) { + for (int i = 0; i < 2; i++) { + struct ETCP_CONN* conn = endpoints[i].conn; + for (struct ETCP_LINK* l = conn->links; l; l = l->next) + CHECK(l->is_tcp && l->mtu == PACKET_DATA_MAX_MTU && l->mtu_local == PACKET_DATA_MAX_MTU); + struct ETCP_LINK* link = conn->links; CHECK(link && link->initialized && link->link_status); + for (unsigned attempt = 1; attempt <= 202; attempt++) + CHECK(etcp_tx_queue_ack(link, conn->last_delivered_id, etcp_tx_attempt_id(conn->last_delivered_id, attempt)) == 0); + unsigned packets = 0, max_size = 0; + while (link->ack_q->count) { + unsigned before = link->ack_q->count; + link->ack_reply_pending = 1; + struct ETCP_DGRAM* packet = etcp_request_pkt(conn); CHECK(packet && packet->link == link && packet->ack_count); + unsigned size = packet->data_len + ETCP_ENCRYPTED_HDR_SIZE + ETCP_SESSION_HEADER_SIZE; + CHECK(size <= link->mtu && size <= PACKET_DATA_MAX_MTU); + if (size > max_size) max_size = size; + unsigned count = packet->ack_count; + CHECK(etcp_loadbalancer_send(packet) >= 0); + CHECK(link->ack_q->count == (int)(before - count)); + packets++; + } + CHECK(packets >= 2); + DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "PASS TCP ACK MTU: side=%d mtu=%u packets=%u max_packet=%u ACK_queue=0", + i, link->mtu, packets, max_size); + } +} + static void run_case(int reality, int simultaneous, int restarted) { DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "Transport case: reality=%d simultaneous=%d restart=%d", reality, simultaneous, restarted); memset(endpoints, 0, sizeof(endpoints)); phase = 0; failed = 0; stream_packets = session_packets = 0; @@ -229,7 +258,7 @@ static void run_case(int reality, int simultaneous, int restarted) { CHECK(node_conn_direct_update_node(endpoints[0].inst, peers[0]->node_id) == 0); unsigned updated = 0; for (struct ETCP_LINK* l = endpoints[0].conn->links; l; l = l->next) updated++; CHECK(updated == links); node_conn_direct_close(extra); - exchange_messages(); + exchange_messages(); check_tcp_ack_mtu(); if (restarted < 2) { int survivor = 1 - restarted;