Mercurial > hg > nginx-quic
comparison src/event/ngx_event_quic.c @ 7992:909b989ec088 quic
QUIC: reworked retransmission mechanism.
Instead of timer-based retransmissions with constant packet lifetime,
this patch implements ack-based loss detection and probe timeout
for the cases, when no ack is received, according to the quic-recovery
draft 29.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Mon, 13 Jul 2020 17:31:29 +0300 |
parents | 1b9db5c8c29b |
children | b276833111cf |
comparison
equal
deleted
inserted
replaced
7991:1b9db5c8c29b | 7992:909b989ec088 |
---|---|
245 ngx_quic_send_ctx_t *ctx, ngx_queue_t *frames); | 245 ngx_quic_send_ctx_t *ctx, ngx_queue_t *frames); |
246 | 246 |
247 static void ngx_quic_set_packet_number(ngx_quic_header_t *pkt, | 247 static void ngx_quic_set_packet_number(ngx_quic_header_t *pkt, |
248 ngx_quic_send_ctx_t *ctx); | 248 ngx_quic_send_ctx_t *ctx); |
249 static void ngx_quic_pto_handler(ngx_event_t *ev); | 249 static void ngx_quic_pto_handler(ngx_event_t *ev); |
250 static ngx_int_t ngx_quic_detect_lost(ngx_connection_t *c, | 250 static ngx_int_t ngx_quic_detect_lost(ngx_connection_t *c, ngx_uint_t ack); |
251 ngx_quic_send_ctx_t *ctx, ngx_msec_t *waitp); | |
252 static void ngx_quic_push_handler(ngx_event_t *ev); | 251 static void ngx_quic_push_handler(ngx_event_t *ev); |
253 | 252 |
254 static void ngx_quic_rbtree_insert_stream(ngx_rbtree_node_t *temp, | 253 static void ngx_quic_rbtree_insert_stream(ngx_rbtree_node_t *temp, |
255 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); | 254 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); |
256 static ngx_quic_stream_t *ngx_quic_find_stream(ngx_rbtree_t *rbtree, | 255 static ngx_quic_stream_t *ngx_quic_find_stream(ngx_rbtree_t *rbtree, |
2339 { | 2338 { |
2340 return NGX_ERROR; | 2339 return NGX_ERROR; |
2341 } | 2340 } |
2342 } | 2341 } |
2343 | 2342 |
2344 return NGX_OK; | 2343 return ngx_quic_detect_lost(c, 1); |
2345 } | 2344 } |
2346 | 2345 |
2347 | 2346 |
2348 static ngx_int_t | 2347 static ngx_int_t |
2349 ngx_quic_handle_ack_frame_range(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, | 2348 ngx_quic_handle_ack_frame_range(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, |
3533 | 3532 |
3534 | 3533 |
3535 static void | 3534 static void |
3536 ngx_quic_pto_handler(ngx_event_t *ev) | 3535 ngx_quic_pto_handler(ngx_event_t *ev) |
3537 { | 3536 { |
3538 ngx_uint_t i; | 3537 ngx_connection_t *c; |
3539 ngx_msec_t wait, nswait; | |
3540 ngx_connection_t *c; | |
3541 ngx_quic_connection_t *qc; | |
3542 | 3538 |
3543 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "quic pto timer"); | 3539 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "quic pto timer"); |
3544 | 3540 |
3545 c = ev->data; | 3541 c = ev->data; |
3546 qc = c->quic; | 3542 |
3547 | 3543 if (ngx_quic_detect_lost(c, 0) != NGX_OK) { |
3548 wait = 0; | 3544 ngx_quic_close_connection(c, NGX_ERROR); |
3549 | 3545 return; |
3550 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { | |
3551 if (ngx_quic_detect_lost(c, &qc->send_ctx[i], &nswait) != NGX_OK) { | |
3552 ngx_quic_close_connection(c, NGX_ERROR); | |
3553 return; | |
3554 } | |
3555 | |
3556 if (i == 0) { | |
3557 wait = nswait; | |
3558 | |
3559 } else if (nswait > 0 && (wait == 0 || wait > nswait)) { | |
3560 wait = nswait; | |
3561 } | |
3562 } | |
3563 | |
3564 if (wait > 0) { | |
3565 ngx_add_timer(&qc->pto, wait); | |
3566 } | 3546 } |
3567 } | 3547 } |
3568 | 3548 |
3569 | 3549 |
3570 static void | 3550 static void |
3582 } | 3562 } |
3583 } | 3563 } |
3584 | 3564 |
3585 | 3565 |
3586 static ngx_int_t | 3566 static ngx_int_t |
3587 ngx_quic_detect_lost(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, | 3567 ngx_quic_detect_lost(ngx_connection_t *c, ngx_uint_t ack) |
3588 ngx_msec_t *waitp) | |
3589 { | 3568 { |
3590 uint64_t pn; | 3569 uint64_t pn; |
3591 ngx_msec_t now, wait; | 3570 ngx_uint_t i; |
3571 ngx_msec_t now, wait, min_wait, thr; | |
3592 ngx_queue_t *q, range; | 3572 ngx_queue_t *q, range; |
3593 ngx_quic_frame_t *f, *start; | 3573 ngx_quic_frame_t *f, *start; |
3574 ngx_quic_send_ctx_t *ctx; | |
3594 ngx_quic_connection_t *qc; | 3575 ngx_quic_connection_t *qc; |
3595 | 3576 |
3596 qc = c->quic; | 3577 qc = c->quic; |
3597 | |
3598 now = ngx_current_msec; | 3578 now = ngx_current_msec; |
3599 | 3579 |
3600 if (ngx_queue_empty(&ctx->sent)) { | 3580 min_wait = 0; |
3601 *waitp = 0; | 3581 |
3602 return NGX_OK; | 3582 if (ack) { |
3603 } | 3583 thr = NGX_QUIC_TIME_THR * ngx_max(qc->latest_rtt, qc->avg_rtt); |
3604 | 3584 thr = ngx_max(thr, NGX_QUIC_TIME_GRANULARITY); |
3605 q = ngx_queue_head(&ctx->sent); | 3585 |
3606 | 3586 } else { |
3607 do { | 3587 thr = NGX_QUIC_HARDCODED_PTO; |
3608 start = ngx_queue_data(q, ngx_quic_frame_t, queue); | 3588 } |
3609 | 3589 |
3610 wait = start->last + qc->ctp.max_ack_delay | 3590 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { |
3611 + NGX_QUIC_HARDCODED_PTO - now; | 3591 |
3612 | 3592 ctx = &qc->send_ctx[i]; |
3613 if ((ngx_msec_int_t) wait > 0) { | 3593 |
3614 break; | 3594 if (ngx_queue_empty(&ctx->sent)) { |
3615 } | 3595 continue; |
3616 | 3596 } |
3617 pn = start->pnum; | 3597 |
3618 | 3598 q = ngx_queue_head(&ctx->sent); |
3619 ngx_queue_init(&range); | 3599 |
3620 | |
3621 /* send frames with same packet number to the wire */ | |
3622 do { | 3600 do { |
3623 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | 3601 start = ngx_queue_data(q, ngx_quic_frame_t, queue); |
3624 | 3602 |
3625 if (now - start->first > qc->tp.max_idle_timeout) { | 3603 wait = start->last + thr - now; |
3626 ngx_log_error(NGX_LOG_ERR, c->log, 0, | 3604 |
3627 "quic retransmission timeout"); | 3605 if ((ngx_msec_int_t) wait >= 0) { |
3628 return NGX_DECLINED; | 3606 |
3607 if (min_wait == 0 || wait < min_wait) { | |
3608 min_wait = wait; | |
3609 } | |
3610 | |
3611 if (!ack) { | |
3612 break; | |
3613 } | |
3614 | |
3615 if ((start->pnum > ctx->largest_ack) | |
3616 || ((ctx->largest_ack - start->pnum) < NGX_QUIC_PKT_THR)) | |
3617 { | |
3618 break; | |
3619 } | |
3629 } | 3620 } |
3630 | 3621 |
3631 if (f->pnum != pn) { | 3622 pn = start->pnum; |
3632 break; | 3623 |
3624 ngx_queue_init(&range); | |
3625 | |
3626 /* send frames with same packet number to the wire */ | |
3627 do { | |
3628 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
3629 | |
3630 if (f->pnum != pn) { | |
3631 break; | |
3632 } | |
3633 | |
3634 q = ngx_queue_next(q); | |
3635 | |
3636 ngx_queue_remove(&f->queue); | |
3637 ngx_queue_insert_tail(&range, &f->queue); | |
3638 | |
3639 } while (q != ngx_queue_sentinel(&ctx->sent)); | |
3640 | |
3641 ngx_quic_congestion_lost(c, start->last); | |
3642 | |
3643 if (ngx_quic_send_frames(c, ctx, &range) != NGX_OK) { | |
3644 return NGX_ERROR; | |
3633 } | 3645 } |
3634 | 3646 |
3635 q = ngx_queue_next(q); | |
3636 | |
3637 ngx_queue_remove(&f->queue); | |
3638 ngx_queue_insert_tail(&range, &f->queue); | |
3639 | |
3640 } while (q != ngx_queue_sentinel(&ctx->sent)); | 3647 } while (q != ngx_queue_sentinel(&ctx->sent)); |
3641 | 3648 } |
3642 ngx_quic_congestion_lost(c, start->last); | 3649 |
3643 | 3650 if (qc->pto.timer_set) { |
3644 if (ngx_quic_send_frames(c, ctx, &range) != NGX_OK) { | 3651 ngx_del_timer(&qc->pto); |
3645 return NGX_ERROR; | 3652 } |
3646 } | 3653 |
3647 | 3654 if (min_wait > 0) { |
3648 } while (q != ngx_queue_sentinel(&ctx->sent)); | 3655 ngx_add_timer(&qc->pto, min_wait); |
3649 | 3656 } |
3650 *waitp = wait; | |
3651 | 3657 |
3652 return NGX_OK; | 3658 return NGX_OK; |
3653 } | 3659 } |
3654 | 3660 |
3655 | 3661 |