Bound ETCP receive window and fix timestamp and allocator UB

This commit is contained in:
evgeny committed 2026-09-27 12:16:15 +03:00
1 parent 59f4802904
commit 03f71fd94e
10 files changed
+211 -47

No files matched your search

+22 -12
View File
@@ -927,6 +927,12 @@ void etcp_stats(struct ETCP_CONN* etcp) {
static void input_queue_cb(struct ll_queue* q, void* arg) {
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "");
struct ETCP_CONN* etcp = (struct ETCP_CONN*)arg;
/* Selective ACK освобождает inflight, но не место за дыркой в приёмном окне пира. */
if ((uint32_t)(etcp->next_tx_id - etcp->rx_ack_till) > MAX_INFLIGHT_SIZE) {
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] peer receive window full: next=%u cumulative_ack=%u queued=%d",
etcp->log_name, etcp->next_tx_id, etcp->rx_ack_till, q->count);
return;
}
struct ETCP_FRAGMENT* in_pkt = (struct ETCP_FRAGMENT*)queue_data_get(q);
if (!in_pkt) {
@@ -1595,8 +1601,9 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) {
case ETCP_SECTION_ACK: {
if (len < ETCP_ACK_BASE_SIZE) { len = 0; break; }
int elm_cnt=data[1];
uint32_t till=data[2] | (data[3]<<8) | (data[4]<<16) | (data[5]<<24);
if ((int32_t)(till - etcp->next_tx_id) > 0) till = etcp->next_tx_id; // wrap-aware: пир не мог подтвердить больше, чем мы отправили
uint32_t till=data[2] | (data[3]<<8) | (data[4]<<16) | ((uint32_t)data[5]<<24);
uint32_t last_tx = etcp->next_tx_id - 1;
if ((int32_t)(till - last_tx) > 0) till = last_tx; // нельзя подтвердить ещё не назначенный seq
uint16_t rx_dup_count_16 = data[6] | (data[7]<<8);
uint16_t old_tx_dup_16 = etcp->tx_dup_count & 0xFFFF;
int16_t diff = (int16_t)(rx_dup_count_16 - old_tx_dup_16);
@@ -1610,7 +1617,7 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) {
data+=ack_section_len;
len-=ack_section_len;
for (int i=0; i<elm_cnt; i++) {
uint32_t seq=data[-ack_section_len+8+i*8] | (data[-ack_section_len+9+i*8]<<8) | (data[-ack_section_len+10+i*8]<<16) | (data[-ack_section_len+11+i*8]<<24);
uint32_t seq=data[-ack_section_len+8+i*8] | (data[-ack_section_len+9+i*8]<<8) | (data[-ack_section_len+10+i*8]<<16) | ((uint32_t)data[-ack_section_len+11+i*8]<<24);
uint16_t ts=data[-ack_section_len+12+i*8] | (data[-ack_section_len+13+i*8]<<8);
uint16_t dts=data[-ack_section_len+14+i*8] | (data[-ack_section_len+15+i*8]<<8);
etcp_ack_recv(etcp, seq, ts, dts);
@@ -1619,6 +1626,8 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) {
while ((int32_t)(etcp->rx_ack_till-till)<0 && ack_gap < ETCP_ACK_GAP_MAX_PACKETS) {
etcp->rx_ack_till++; etcp_ack_recv(etcp, etcp->rx_ack_till, -1, -1); ack_gap++;
}// подтверждаем всё по till
/* Все записи могли уже уйти по selective ACK; тогда ack_recv не вызовет resume. */
if (ack_gap) input_queue_try_resume(etcp);
break;
}
case ETCP_SECTION_TIMESTAMP: {
@@ -1626,6 +1635,7 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) {
uint16_t cur_ts=get_current_timestamp();
uint16_t ret_ts=data[1] | (data[2]<<8);// cur_ts=ret_ts = RTT
uint16_t new_rtt=cur_ts-ret_ts;
int prev_rtt = pkt->link->rtt_last;
pkt->link->rtt_last=new_rtt;
DEBUG_DEBUG(DEBUG_CATEGORY_KEEPALIVE, "[%s] KA-RTT: rtt=%u cur=%u ret=%u dlen=%u",
etcp->log_name, new_rtt, cur_ts, ret_ts, pkt->data_len);
@@ -1634,19 +1644,21 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) {
int recv_dt_rx=cur_ts - pkt->link->rtt_last/2 - 1000 - ts;
int recv_dt_tx=recv_dt_tx1 - pkt->link->rtt_last/2 - 1000;
if (pkt->link->recv_dt_avg_rx==0) pkt->link->recv_dt_avg_rx=recv_dt_rx*65536;
if (pkt->link->recv_dt_avg_tx==0) pkt->link->recv_dt_avg_tx=recv_dt_tx*65536;
pkt->link->recv_dt_avg_rx +=((int32_t)(recv_dt_rx*65536 - pkt->link->recv_dt_avg_rx))/32;
pkt->link->recv_dt_avg_tx +=((int32_t)(recv_dt_tx*65536 - pkt->link->recv_dt_avg_tx))/32;
/* Timestamp циклический uint16: Q16 также вычисляем по модулю 2^32, без signed overflow. */
uint32_t sample_rx = (uint32_t)recv_dt_rx * 65536u;
uint32_t sample_tx = (uint32_t)recv_dt_tx * 65536u;
if (pkt->link->recv_dt_avg_rx==0) pkt->link->recv_dt_avg_rx=sample_rx;
if (pkt->link->recv_dt_avg_tx==0) pkt->link->recv_dt_avg_tx=sample_tx;
pkt->link->recv_dt_avg_rx +=((int32_t)(sample_rx - pkt->link->recv_dt_avg_rx))/32;
pkt->link->recv_dt_avg_tx +=((int32_t)(sample_tx - pkt->link->recv_dt_avg_tx))/32;
pkt->link->rt_last = cur_ts - ts - pkt->link->recv_dt_avg_rx/65536;
pkt->link->tt_last = recv_dt_tx1 - pkt->link->recv_dt_avg_tx/65536;
//tts_correction += ((NOW - RTT/2 - TTS) - tts_correction)/16 (инициализируем сразу по 1 пакету)
data+=5; len-=5;
int prev_rtt = pkt->link->rtt_last;
int d_rtt = new_rtt - prev_rtt;
if (d_rtt<0) d_rtt=-d_rtt;
pkt->link->jitter +=((int32_t)(d_rtt*65536 - pkt->link->jitter))/32;
pkt->link->jitter += ((int64_t)d_rtt * 65536 - pkt->link->jitter) / 32;
struct ETCP_LINK* c=etcp->links;
int rtt_sum=0;
@@ -1679,7 +1691,7 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) {
if (len>=5) {
// формируем ACK
uint32_t seq=data[1] | (data[2]<<8) | (data[3]<<16) | (data[4]<<24);
uint32_t seq=data[1] | (data[2]<<8) | (data[3]<<16) | ((uint32_t)data[4]<<24);
if (etcp->got_initial_pkt == 0) {
if (seq==1) { etcp->got_initial_pkt = 1; DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] Initial packet seq=1 received", etcp->log_name); }
else {
@@ -1889,5 +1901,3 @@ void etcp_update_mtu(struct ETCP_CONN* etcp) {
}
}
}