diff --git a/src/control_server.c b/src/control_server.c index 0cc852b6..e4b1ef21 100644 --- a/src/control_server.c +++ b/src/control_server.c @@ -969,6 +969,8 @@ static void send_metrics(struct control_server* server, struct control_client* c rsp->etcp.cnt_ack_hit_sndq = conn->cnt_ack_hit_sndq; rsp->etcp.cnt_ack_miss = conn->cnt_ack_miss; rsp->etcp.cnt_link_wait = conn->cnt_link_wait; + rsp->etcp.rx_dup_count = conn->rx_dup_count; + rsp->etcp.tx_dup_count = conn->tx_dup_count; rsp->etcp.tx_state = conn->tx_state; for (int i = 0; i < 8; i++) { rsp->etcp.debug[i] = conn->debug[i]; diff --git a/src/etcp.c b/src/etcp.c index f8f35601..ce3daed4 100644 --- a/src/etcp.c +++ b/src/etcp.c @@ -256,6 +256,8 @@ void etcp_conn_reset(struct ETCP_CONN* etcp) { etcp->bytes_sent_total = 0; etcp->retransmissions_count = 0; etcp->ack_packets_count = 0; + etcp->rx_dup_count = 0; + etcp->tx_dup_count = 0; // Reset RTT history memset(etcp->rtt_history, 0, sizeof(etcp->rtt_history)); @@ -504,6 +506,8 @@ void etcp_stats(struct ETCP_CONN* etcp) { DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] retransmissions_count: %u", etcp->log_name, etcp->retransmissions_count); DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] ack_packets_count: %u", etcp->log_name, etcp->ack_packets_count); DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] unacked_bytes: %u", etcp->log_name, etcp->unacked_bytes); + DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] rx_dup_count: %u", etcp->log_name, etcp->rx_dup_count); + DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] tx_dup_count: %u", etcp->log_name, etcp->tx_dup_count); // IDs DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] IDs:", etcp->log_name); @@ -810,7 +814,7 @@ struct ETCP_DGRAM* etcp_request_pkt(struct ETCP_CONN* etcp) { dgram->noencrypt_len=0; dgram->timestamp = get_current_timestamp(); -// формат ack: [01] [elements count] [4 байта last_delivered_id] и <[4 байта seq][2 байта recv_ts][2 байта txrx delay ts]> x count +// формат ack: [01] [elements count] [4 байта last_delivered_id] [2 байта rx_dup_count] и <[4 байта seq][2 байта recv_ts][2 байта txrx delay ts]> x count dgram->data[0]=1;// ack int ptr=2; @@ -819,9 +823,12 @@ struct ETCP_DGRAM* etcp_request_pkt(struct ETCP_CONN* etcp) { dgram->data[ptr++]=etcp->last_delivered_id>>16; dgram->data[ptr++]=etcp->last_delivered_id>>24; + dgram->data[ptr++]=etcp->rx_dup_count; + dgram->data[ptr++]=etcp->rx_dup_count>>8; + int data_len=0; if (inf_pkt) data_len=inf_pkt->ll.len; - int remain_len=link->mtu -28/*udp headers*/ -13-8-4/*sc_nonce+tag size+crc*/ -9/*hdr[3] + min ack[6]*/ -5/*payload hdr*/ - data_len; + int remain_len=link->mtu -28/*udp headers*/ -13-8-4/*sc_nonce+tag size+crc*/ -11/*hdr[3] + min ack[8]*/ -5/*payload hdr*/ - data_len; // DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "remain_len= %d pl=%d", remain_len, data_len); // добавим опциональные заголовки @@ -851,7 +858,7 @@ struct ETCP_DGRAM* etcp_request_pkt(struct ETCP_CONN* etcp) { if (ptr>500) break; } - dgram->data[1]=ptr/8; + dgram->data[1]=(ptr - 8) / 8; if (link->last_recv_updated && remain_len>=5) {// если есть данные - добавим channel_timestamp @@ -1035,13 +1042,17 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) { case ETCP_SECTION_ACK: { int elm_cnt=data[1]; uint32_t till=data[2] | (data[3]<<8) | (data[4]<<16) | (data[5]<<24); - int ack_section_len = 6 + elm_cnt * 8; + 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); + etcp->tx_dup_count += diff; + int ack_section_len = 8 + elm_cnt * 8; data+=ack_section_len; len-=ack_section_len; for (int i=0; irx_ack_till-till)<0) { etcp->rx_ack_till++; etcp_ack_recv(etcp, etcp->rx_ack_till, -1, -1); }// подтверждаем всё по till @@ -1190,6 +1201,7 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) { DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] RX seq=%u need=%u asm_len=%d", etcp->log_name, seq, etcp->last_delivered_id+1, etcp->recv_q->count); if ((int32_t)(seq - etcp->last_delivered_id) == 1) etcp_output_try_assembly(etcp);// пробуем собрать выходную очередь из фрагментов } else { + etcp->rx_dup_count++; DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] RX dup: seq=%u need=%u asm_len=%d", etcp->log_name, seq, etcp->last_delivered_id+1, etcp->recv_q->count); } } else DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "payload len %d < 5", len); diff --git a/src/etcp.h b/src/etcp.h index 01aa3f39..cd9743e3 100644 --- a/src/etcp.h +++ b/src/etcp.h @@ -165,6 +165,8 @@ struct ETCP_CONN { uint32_t cnt_ack_hit_sndq; // счетчик удалений inflight пакетов из sndq uint32_t cnt_ack_miss; // счетчик не найденных ack uint32_t cnt_link_wait; // счетчик переходов в ожидание когда link busy + uint32_t rx_dup_count; // счетчик принятых дубликатов (локальные) + uint32_t tx_dup_count; // счетчик дубликатов удаленной стороны (из ACK) uint32_t debug[8]; // 8 значений для дебага (live watch) // Logging identifier (format: "XXXX→XXXX [name]" - last 4 digits of local and peer node_id + optional name) diff --git a/src/etcp_debug.c b/src/etcp_debug.c index 4207604f..7b1fe652 100644 --- a/src/etcp_debug.c +++ b/src/etcp_debug.c @@ -42,11 +42,12 @@ void etcp_dump_pkt_sections(struct ETCP_DGRAM* pkt, struct ETCP_LINK* link, int case ETCP_SECTION_ACK: { if (offset + 2 > len) { offset = len; break; } ack_count = data[offset + 1]; - if (offset + 6 > len) { offset = len; break; } + if (offset + 8 > len) { offset = len; break; } ack_last_delivered = data[offset + 2] | (data[offset + 3] << 8) | (data[offset + 4] << 16) | (data[offset + 5] << 24); - pos += snprintf(buf + pos, sizeof(buf) - pos, " ack=%u/%d", ack_last_delivered, ack_count); - offset += 6 + ack_count * 8; + uint16_t ack_rx_dup = data[offset + 6] | (data[offset + 7] << 8); + pos += snprintf(buf + pos, sizeof(buf) - pos, " ack=%u/%d dup=%u", ack_last_delivered, ack_count, ack_rx_dup); + offset += 8 + ack_count * 8; break; } case ETCP_SECTION_TIMESTAMP: { diff --git a/tools/etcpmon/etcpmon_protocol.h b/tools/etcpmon/etcpmon_protocol.h index d7504364..23dc61d6 100644 --- a/tools/etcpmon/etcpmon_protocol.h +++ b/tools/etcpmon/etcpmon_protocol.h @@ -190,6 +190,8 @@ struct etcpmon_etcp_metrics { uint32_t cnt_ack_hit_sndq; uint32_t cnt_ack_miss; uint32_t cnt_link_wait; + uint32_t rx_dup_count; + uint32_t tx_dup_count; uint32_t tx_state; uint32_t debug[8];