Mercurial > hg > nginx-quic
comparison src/event/ngx_event_quic.c @ 8051:38f1be6c603f quic
QUIC: sending probe packets on PTO timer expiration.
The PTO handler is split into separate PTO and loss detection handlers
that operate interchangeably depending on which timer should be set.
The present ngx_quic_lost_handler is now only used for packet loss detection.
It replaces ngx_quic_pto_handler if there are packets preceeding largest_ack.
Once there is no more such packets, ngx_quic_pto_handler is installed again.
Probes carry unacknowledged data previously sent in the oldest packet number,
one per each packet number space. That is, it could be up to two probes.
PTO backoff is now increased before scheduling next probes.
author | Sergey Kandaurov <pluknet@nginx.com> |
---|---|
date | Wed, 19 Aug 2020 13:24:23 +0300 |
parents | 6e1c88f82280 |
children | 52c88f41d24c |
comparison
equal
deleted
inserted
replaced
8050:6e1c88f82280 | 8051:38f1be6c603f |
---|---|
263 ngx_quic_send_ctx_t *ctx, ngx_queue_t *frames); | 263 ngx_quic_send_ctx_t *ctx, ngx_queue_t *frames); |
264 | 264 |
265 static void ngx_quic_set_packet_number(ngx_quic_header_t *pkt, | 265 static void ngx_quic_set_packet_number(ngx_quic_header_t *pkt, |
266 ngx_quic_send_ctx_t *ctx); | 266 ngx_quic_send_ctx_t *ctx); |
267 static void ngx_quic_pto_handler(ngx_event_t *ev); | 267 static void ngx_quic_pto_handler(ngx_event_t *ev); |
268 static ngx_int_t ngx_quic_detect_lost(ngx_connection_t *c, ngx_uint_t ack); | 268 static void ngx_quic_lost_handler(ngx_event_t *ev); |
269 static ngx_int_t ngx_quic_detect_lost(ngx_connection_t *c); | |
270 static ngx_int_t ngx_quic_resend_frames(ngx_connection_t *c, | |
271 ngx_quic_send_ctx_t *ctx, ngx_quic_frame_t *start); | |
269 static void ngx_quic_push_handler(ngx_event_t *ev); | 272 static void ngx_quic_push_handler(ngx_event_t *ev); |
270 | 273 |
271 static void ngx_quic_rbtree_insert_stream(ngx_rbtree_node_t *temp, | 274 static void ngx_quic_rbtree_insert_stream(ngx_rbtree_node_t *temp, |
272 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); | 275 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); |
273 static ngx_quic_stream_t *ngx_quic_find_stream(ngx_rbtree_t *rbtree, | 276 static ngx_quic_stream_t *ngx_quic_find_stream(ngx_rbtree_t *rbtree, |
2399 { | 2402 { |
2400 return NGX_ERROR; | 2403 return NGX_ERROR; |
2401 } | 2404 } |
2402 } | 2405 } |
2403 | 2406 |
2404 return ngx_quic_detect_lost(c, 1); | 2407 return ngx_quic_detect_lost(c); |
2405 } | 2408 } |
2406 | 2409 |
2407 | 2410 |
2408 static ngx_int_t | 2411 static ngx_int_t |
2409 ngx_quic_handle_ack_frame_range(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, | 2412 ngx_quic_handle_ack_frame_range(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, |
3680 | 3683 |
3681 | 3684 |
3682 static void | 3685 static void |
3683 ngx_quic_pto_handler(ngx_event_t *ev) | 3686 ngx_quic_pto_handler(ngx_event_t *ev) |
3684 { | 3687 { |
3685 ngx_connection_t *c; | 3688 ngx_uint_t i; |
3689 ngx_queue_t *q; | |
3690 ngx_connection_t *c; | |
3691 ngx_quic_frame_t *start; | |
3692 ngx_quic_send_ctx_t *ctx; | |
3693 ngx_quic_connection_t *qc; | |
3686 | 3694 |
3687 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "quic pto timer"); | 3695 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "quic pto timer"); |
3688 | 3696 |
3689 c = ev->data; | 3697 c = ev->data; |
3690 | 3698 qc = c->quic; |
3691 if (ngx_quic_detect_lost(c, 0) != NGX_OK) { | 3699 |
3692 ngx_quic_close_connection(c, NGX_ERROR); | 3700 qc->pto_count++; |
3693 return; | 3701 |
3694 } | 3702 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { |
3695 | 3703 |
3696 c->quic->pto_count++; | 3704 ctx = &qc->send_ctx[i]; |
3705 | |
3706 if (ngx_queue_empty(&ctx->sent)) { | |
3707 continue; | |
3708 } | |
3709 | |
3710 q = ngx_queue_head(&ctx->sent); | |
3711 start = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
3712 | |
3713 if (start->pnum <= ctx->largest_ack | |
3714 && ctx->largest_ack != (uint64_t) -1) | |
3715 { | |
3716 continue; | |
3717 } | |
3718 | |
3719 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
3720 "quic pto pnum:%ui pto_count:%ui level:%d", | |
3721 start->pnum, c->quic->pto_count, start->level); | |
3722 | |
3723 if (ngx_quic_resend_frames(c, ctx, start) != NGX_OK) { | |
3724 ngx_quic_close_connection(c, NGX_ERROR); | |
3725 return; | |
3726 } | |
3727 } | |
3697 } | 3728 } |
3698 | 3729 |
3699 | 3730 |
3700 static void | 3731 static void |
3701 ngx_quic_push_handler(ngx_event_t *ev) | 3732 ngx_quic_push_handler(ngx_event_t *ev) |
3711 return; | 3742 return; |
3712 } | 3743 } |
3713 } | 3744 } |
3714 | 3745 |
3715 | 3746 |
3747 static | |
3748 void ngx_quic_lost_handler(ngx_event_t *ev) | |
3749 { | |
3750 ngx_connection_t *c; | |
3751 | |
3752 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "quic lost timer"); | |
3753 | |
3754 c = ev->data; | |
3755 | |
3756 if (ngx_quic_detect_lost(c) != NGX_OK) { | |
3757 ngx_quic_close_connection(c, NGX_ERROR); | |
3758 } | |
3759 } | |
3760 | |
3761 | |
3716 static ngx_int_t | 3762 static ngx_int_t |
3717 ngx_quic_detect_lost(ngx_connection_t *c, ngx_uint_t ack) | 3763 ngx_quic_detect_lost(ngx_connection_t *c) |
3718 { | 3764 { |
3719 uint64_t pn; | |
3720 ngx_uint_t i; | 3765 ngx_uint_t i; |
3721 ngx_msec_t now, wait, min_wait, thr; | 3766 ngx_msec_t now, wait, min_wait, thr; |
3722 ngx_queue_t *q, range; | 3767 ngx_queue_t *q; |
3723 ngx_quic_frame_t *f, *start; | 3768 ngx_quic_frame_t *start; |
3724 ngx_quic_send_ctx_t *ctx; | 3769 ngx_quic_send_ctx_t *ctx; |
3725 ngx_quic_connection_t *qc; | 3770 ngx_quic_connection_t *qc; |
3726 | 3771 |
3727 qc = c->quic; | 3772 qc = c->quic; |
3728 now = ngx_current_msec; | 3773 now = ngx_current_msec; |
3729 | 3774 |
3730 min_wait = 0; | 3775 min_wait = 0; |
3731 | 3776 |
3732 #if (NGX_SUPPRESS_WARN) | 3777 thr = NGX_QUIC_TIME_THR * ngx_max(qc->latest_rtt, qc->avg_rtt); |
3733 thr = 0; | 3778 thr = ngx_max(thr, NGX_QUIC_TIME_GRANULARITY); |
3734 #endif | |
3735 | |
3736 if (ack) { | |
3737 thr = NGX_QUIC_TIME_THR * ngx_max(qc->latest_rtt, qc->avg_rtt); | |
3738 thr = ngx_max(thr, NGX_QUIC_TIME_GRANULARITY); | |
3739 } | |
3740 | 3779 |
3741 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { | 3780 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { |
3742 | 3781 |
3743 ctx = &qc->send_ctx[i]; | 3782 ctx = &qc->send_ctx[i]; |
3744 | 3783 |
3745 if (ngx_queue_empty(&ctx->sent)) { | 3784 while (!ngx_queue_empty(&ctx->sent)) { |
3746 continue; | 3785 |
3747 } | 3786 q = ngx_queue_head(&ctx->sent); |
3748 | |
3749 if (!ack) { | |
3750 thr = ngx_quic_pto(c, ctx); | |
3751 } | |
3752 | |
3753 q = ngx_queue_head(&ctx->sent); | |
3754 | |
3755 do { | |
3756 start = ngx_queue_data(q, ngx_quic_frame_t, queue); | 3787 start = ngx_queue_data(q, ngx_quic_frame_t, queue); |
3757 | 3788 |
3758 wait = start->last + thr - now; | 3789 wait = start->last + thr - now; |
3790 | |
3791 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
3792 "quic detect_lost pnum:%ui thr:%M wait:%i level:%d", | |
3793 start->pnum, thr, (ngx_int_t) wait, start->level); | |
3759 | 3794 |
3760 if ((ngx_msec_int_t) wait >= 0) { | 3795 if ((ngx_msec_int_t) wait >= 0) { |
3761 | 3796 |
3762 if (min_wait == 0 || wait < min_wait) { | 3797 if (min_wait == 0 || wait < min_wait) { |
3763 min_wait = wait; | 3798 min_wait = wait; |
3764 } | 3799 } |
3765 | 3800 |
3766 if (!ack) { | |
3767 break; | |
3768 } | |
3769 | |
3770 if ((start->pnum > ctx->largest_ack) | 3801 if ((start->pnum > ctx->largest_ack) |
3802 || ctx->largest_ack == (uint64_t) -1 | |
3771 || ((ctx->largest_ack - start->pnum) < NGX_QUIC_PKT_THR)) | 3803 || ((ctx->largest_ack - start->pnum) < NGX_QUIC_PKT_THR)) |
3772 { | 3804 { |
3773 break; | 3805 break; |
3774 } | 3806 } |
3775 } | 3807 } |
3776 | 3808 |
3777 pn = start->pnum; | 3809 if (ngx_quic_resend_frames(c, ctx, start) != NGX_OK) { |
3778 | |
3779 ngx_queue_init(&range); | |
3780 | |
3781 /* send frames with same packet number to the wire */ | |
3782 do { | |
3783 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
3784 | |
3785 if (f->pnum != pn) { | |
3786 break; | |
3787 } | |
3788 | |
3789 q = ngx_queue_next(q); | |
3790 | |
3791 ngx_queue_remove(&f->queue); | |
3792 ngx_queue_insert_tail(&range, &f->queue); | |
3793 | |
3794 } while (q != ngx_queue_sentinel(&ctx->sent)); | |
3795 | |
3796 ngx_quic_congestion_lost(c, start); | |
3797 | |
3798 if (ngx_quic_send_frames(c, ctx, &range) != NGX_OK) { | |
3799 return NGX_ERROR; | 3810 return NGX_ERROR; |
3800 } | 3811 } |
3801 | 3812 } |
3802 } while (q != ngx_queue_sentinel(&ctx->sent)); | 3813 } |
3803 } | 3814 |
3815 /* no more preceeding packets */ | |
3816 | |
3817 if (min_wait == 0) { | |
3818 qc->pto.handler = ngx_quic_pto_handler; | |
3819 return NGX_OK; | |
3820 } | |
3821 | |
3822 qc->pto.handler = ngx_quic_lost_handler; | |
3804 | 3823 |
3805 if (qc->pto.timer_set) { | 3824 if (qc->pto.timer_set) { |
3806 ngx_del_timer(&qc->pto); | 3825 ngx_del_timer(&qc->pto); |
3807 } | 3826 } |
3808 | 3827 |
3809 if (min_wait > 0) { | 3828 ngx_add_timer(&qc->pto, min_wait); |
3810 ngx_add_timer(&qc->pto, min_wait); | |
3811 } | |
3812 | 3829 |
3813 return NGX_OK; | 3830 return NGX_OK; |
3831 } | |
3832 | |
3833 | |
3834 static ngx_int_t | |
3835 ngx_quic_resend_frames(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, | |
3836 ngx_quic_frame_t *start) | |
3837 { | |
3838 ngx_queue_t *q, range; | |
3839 ngx_quic_frame_t *f; | |
3840 | |
3841 ngx_queue_init(&range); | |
3842 | |
3843 /* send frames with same packet number to the wire */ | |
3844 | |
3845 q = ngx_queue_head(&ctx->sent); | |
3846 | |
3847 do { | |
3848 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
3849 | |
3850 if (f->pnum != start->pnum) { | |
3851 break; | |
3852 } | |
3853 | |
3854 q = ngx_queue_next(q); | |
3855 | |
3856 ngx_queue_remove(&f->queue); | |
3857 ngx_queue_insert_tail(&range, &f->queue); | |
3858 | |
3859 } while (q != ngx_queue_sentinel(&ctx->sent)); | |
3860 | |
3861 ngx_quic_congestion_lost(c, start); | |
3862 | |
3863 return ngx_quic_send_frames(c, ctx, &range); | |
3814 } | 3864 } |
3815 | 3865 |
3816 | 3866 |
3817 ngx_connection_t * | 3867 ngx_connection_t * |
3818 ngx_quic_open_stream(ngx_connection_t *c, ngx_uint_t bidi) | 3868 ngx_quic_open_stream(ngx_connection_t *c, ngx_uint_t bidi) |