Encode 16-bit attempt numbers and guard pair reuse by session epochs
This commit is contained in:
1 parent
6414cb15ef
commit
ccbd214c97
3 files changed
+34
-20
No files matched your search
+17
-11
@@ -177,7 +177,6 @@ struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance, char* n
|
||||
etcp->recv_q = queue_new(instance->ua, INFLIGHT_INITIAL_HASH_SIZE, 0, 4, "recv_q"); // Hash for recv_q
|
||||
etcp->inflight_pool = memory_pool_init(sizeof(struct INFLIGHT_PACKET), "inflight_pool");
|
||||
etcp->attempt_pool = memory_pool_init(sizeof(struct ETCP_TX_ATTEMPT), "attempt_pool");
|
||||
etcp->next_attempt_id = 1;
|
||||
etcp->io_pool = memory_pool_init(sizeof(struct ETCP_FRAGMENT), "io_pool");
|
||||
etcp->max_inflight = (uint32_t)instance->config->global.bbr_max_cwnd;
|
||||
if (instance->config->global.bbr_max_cwnd < INFLIGHT_LIM_MIN) {
|
||||
@@ -826,6 +825,10 @@ 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;
|
||||
if (!etcp->next_tx_id) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "[%s] sequence numbers exhausted; restarting stream before reuse", etcp->log_name);
|
||||
etcp_conn_fatal_reinit(etcp, "sequence numbers exhausted"); return;
|
||||
}
|
||||
/* 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",
|
||||
@@ -1068,9 +1071,9 @@ struct ETCP_DGRAM* etcp_request_pkt(struct ETCP_CONN* conn) {
|
||||
while (ack_space >= ETCP_ACK_ENTRY_SIZE && data[1] != UINT8_MAX) {
|
||||
struct ACK_PACKET* ack = (struct ACK_PACKET*)queue_data_get(link->ack_q);
|
||||
if (!ack) break;
|
||||
write_le(data + ptr, ack->seq, 4); write_le(data + ptr + 4, ack->attempt_id, 8);
|
||||
write_le(data + ptr, ack->seq, 4); write_le(data + ptr + 4, (uint16_t)ack->attempt_id, 2);
|
||||
uint64_t delay = get_time_us() - ack->received_at_us;
|
||||
write_le(data + ptr + 12, delay >= UINT32_MAX ? UINT32_MAX : delay, 4);
|
||||
write_le(data + ptr + 6, delay >= UINT32_MAX ? UINT32_MAX : delay, 4);
|
||||
ptr += ETCP_ACK_ENTRY_SIZE; remaining -= ETCP_ACK_ENTRY_SIZE; ack_space -= ETCP_ACK_ENTRY_SIZE; data[1]++;
|
||||
queue_entry_free(&ack->ll);
|
||||
}
|
||||
@@ -1118,7 +1121,7 @@ struct ETCP_DGRAM* etcp_request_pkt(struct ETCP_CONN* conn) {
|
||||
}
|
||||
if (packet) {
|
||||
data[ptr++] = ETCP_SECTION_PAYLOAD; write_le(data + ptr, packet->seq, 4); ptr += 4;
|
||||
write_le(data + ptr, dgram->attempt->attempt_id, 8); ptr += 8;
|
||||
write_le(data + ptr, (uint16_t)dgram->attempt->attempt_id, 2); ptr += 2;
|
||||
memcpy(data + ptr, packet->ll.dgram, packet->ll.len); ptr += packet->ll.len;
|
||||
}
|
||||
dgram->data_len = ptr;
|
||||
@@ -1260,8 +1263,10 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) {
|
||||
etcp->tx_dup_count += (int16_t)(duplicates - (uint16_t)etcp->tx_dup_count);
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
const uint8_t* entry = data + ETCP_ACK_BASE_SIZE + i * ETCP_ACK_ENTRY_SIZE;
|
||||
etcp_tx_ack(pkt->link, (uint32_t)read_le(entry, 4), read_le(entry + 4, 8),
|
||||
(uint32_t)read_le(entry + 12, 4), rx_bytes, rx_time);
|
||||
uint32_t seq = (uint32_t)read_le(entry, 4);
|
||||
uint16_t number = (uint16_t)read_le(entry + 4, 2);
|
||||
etcp_tx_ack(pkt->link, seq, etcp_tx_attempt_id(seq, number),
|
||||
(uint32_t)read_le(entry + 6, 4), rx_bytes, rx_time);
|
||||
if (etcp->close_requested || etcp->reinit_pending) break;
|
||||
}
|
||||
uint32_t advanced = 0;
|
||||
@@ -1343,11 +1348,12 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCP, "[%s] short DATA len=%u", etcp->log_name, len); len = 0; break;
|
||||
}
|
||||
uint32_t seq = (uint32_t)read_le(data + 1, 4);
|
||||
uint64_t attempt_id = read_le(data + 5, 8);
|
||||
uint16_t attempt_no = (uint16_t)read_le(data + 5, 2);
|
||||
uint64_t attempt_id = etcp_tx_attempt_id(seq, attempt_no);
|
||||
uint32_t payload_len = len - ETCP_PAYLOAD_HEADER_SIZE;
|
||||
if (!attempt_id || (!etcp->got_initial_pkt && seq != 1)) {
|
||||
if (!attempt_no || (!etcp->got_initial_pkt && seq != 1)) {
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] DATA rejected before initial fragment seq=%u attempt=%llu",
|
||||
etcp->log_name, seq, (unsigned long long)attempt_id);
|
||||
etcp->log_name, seq, (unsigned long long)attempt_no);
|
||||
len = 0; break;
|
||||
}
|
||||
int32_t distance = (int32_t)(seq - etcp->last_delivered_id);
|
||||
@@ -1370,7 +1376,7 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) {
|
||||
if (fragment) queue_entry_free(&fragment->ll);
|
||||
if (payload) memory_pool_free(etcp->instance->data_pool, payload);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "[%s] DATA admission OOM seq=%u attempt=%llu; no ACK",
|
||||
etcp->log_name, seq, (unsigned long long)attempt_id);
|
||||
etcp->log_name, seq, (unsigned long long)attempt_no);
|
||||
len = 0; break;
|
||||
}
|
||||
fragment->seq = seq; fragment->timestamp = pkt->timestamp;
|
||||
@@ -1387,7 +1393,7 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) {
|
||||
etcp->got_initial_pkt = 1;
|
||||
if (etcp_tx_queue_ack(pkt->link, seq, attempt_id) == 0) ack_schedule(etcp);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] accepted DATA seq=%u attempt=%llu path=%u bytes=%u duplicate=%d",
|
||||
etcp->log_name, seq, (unsigned long long)attempt_id, pkt->link->local_link_id, payload_len, duplicate);
|
||||
etcp->log_name, seq, (unsigned long long)attempt_no, pkt->link->local_link_id, payload_len, duplicate);
|
||||
if (distance == 1) etcp_output_try_assembly(etcp);
|
||||
len = 0;
|
||||
break;
|
||||
|
||||
@@ -81,11 +81,10 @@ void etcp_dump_pkt_sections(struct ETCP_DGRAM* pkt, struct ETCP_LINK* link, int
|
||||
payload_seq = (uint32_t)data[offset + 1] | ((uint32_t)data[offset + 2] << 8) |
|
||||
((uint32_t)data[offset + 3] << 16) | ((uint32_t)data[offset + 4] << 24);
|
||||
payload_size = len - offset - ETCP_PAYLOAD_HEADER_SIZE;
|
||||
uint64_t attempt_id = 0;
|
||||
for (unsigned i = 0; i < 8; i++) attempt_id |= (uint64_t)data[offset + 5 + i] << (8 * i);
|
||||
uint16_t attempt_no = data[offset + 5] | ((uint16_t)data[offset + 6] << 8);
|
||||
has_payload = 1;
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, " payload=%u(seq=%u attempt=%llu)",
|
||||
payload_size, payload_seq, (unsigned long long)attempt_id);
|
||||
pos += snprintf(buf + pos, sizeof(buf) - pos, " payload=%u(seq=%u attempt=%u)",
|
||||
payload_size, payload_seq, attempt_no);
|
||||
offset = len;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -156,13 +156,15 @@ struct ETCP_TX_ATTEMPT* etcp_tx_prepare(struct ETCP_LINK* link, struct INFLIGHT_
|
||||
conn->log_name, conn->active_attempts, link->local_link_id, link->attempts->count);
|
||||
return NULL;
|
||||
}
|
||||
if (!conn->next_attempt_id || conn->next_attempt_id == UINT64_MAX) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "[%s] transmission attempt ID exhausted", conn->log_name);
|
||||
conn->callbacks_running++; etcp_connection_close(conn); conn->callbacks_running--; return NULL;
|
||||
if (packet->attempt_count == UINT16_MAX) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "[%s] attempt numbers exhausted seq=%u count=%u; restarting stream",
|
||||
conn->log_name, packet->seq, packet->attempt_count);
|
||||
etcp_conn_fatal_reinit(conn, "attempt numbers exhausted"); return NULL;
|
||||
}
|
||||
struct ETCP_TX_ATTEMPT* attempt = (struct ETCP_TX_ATTEMPT*)queue_entry_new_from_pool(conn->attempt_pool);
|
||||
if (!attempt) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "[%s] cannot allocate transmission attempt", conn->log_name); return NULL; }
|
||||
attempt->attempt_id = conn->next_attempt_id++; attempt->seq = packet->seq; attempt->ll.len = packet->ll.len;
|
||||
attempt->attempt_id = etcp_tx_attempt_id(packet->seq, ++packet->attempt_count);
|
||||
attempt->seq = packet->seq; attempt->ll.len = packet->ll.len;
|
||||
if (queue_data_put_with_index(link->attempts, &attempt->ll) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "[%s] cannot index transmission attempt", conn->log_name); return NULL;
|
||||
}
|
||||
@@ -219,6 +221,10 @@ void etcp_tx_complete(struct ETCP_DGRAM* dgram, int success) {
|
||||
void etcp_tx_ack(struct ETCP_LINK* link, uint32_t seq, uint64_t attempt_id, uint32_t receiver_delay_us,
|
||||
uint64_t peer_rx_bytes, uint64_t peer_rx_time_us) {
|
||||
struct ETCP_CONN* conn = link->etcp;
|
||||
if (!(uint16_t)attempt_id) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCP, "[%s] ACK attempt_no=0 rejected seq=%u path=%u", conn->log_name, seq, link->local_link_id);
|
||||
return;
|
||||
}
|
||||
struct ETCP_TX_ATTEMPT* attempt = (struct ETCP_TX_ATTEMPT*)queue_find_data_by_index(link->attempts, &attempt_id);
|
||||
if (attempt && (attempt->seq != seq || !attempt->sent_at_us)) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCP, "[%s] invalid attempt ACK path=%u id=%llu seq=%u expected=%u committed=%d",
|
||||
@@ -306,7 +312,10 @@ void etcp_tx_ack(struct ETCP_LINK* link, uint32_t seq, uint64_t attempt_id, uint
|
||||
}
|
||||
|
||||
int etcp_tx_queue_ack(struct ETCP_LINK* link, uint32_t seq, uint64_t attempt_id) {
|
||||
if (!attempt_id) { DEBUG_WARN(DEBUG_CATEGORY_ETCP, "[%s] DATA attempt_id=0 rejected", link->etcp->log_name); return -1; }
|
||||
if (!(uint16_t)attempt_id || attempt_id != etcp_tx_attempt_id(seq, (uint16_t)attempt_id)) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCP, "[%s] invalid DATA attempt key=%llu seq=%u", link->etcp->log_name,
|
||||
(unsigned long long)attempt_id, seq); return -1;
|
||||
}
|
||||
if (queue_find_data_by_index(link->ack_q, &attempt_id)) return 0;
|
||||
struct ACK_PACKET* ack = (struct ACK_PACKET*)queue_entry_new_from_pool(link->etcp->instance->ack_pool);
|
||||
if (!ack) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "[%s] cannot allocate path ACK", link->etcp->log_name); return -1; }
|
||||
|
||||
Reference in new issue
Block a user