comparison src/event/ngx_event_quic.c @ 8474: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
8473:1b9db5c8c29b 8474: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