Mercurial > hg > nginx-quic
comparison src/event/ngx_event_quic.c @ 7993:b276833111cf quic
QUIC: implemented probe timeout (PTO) calculation.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Thu, 16 Jul 2020 16:05:44 +0300 |
parents | 909b989ec088 |
children | f9fbeb4ee0de |
comparison
equal
deleted
inserted
replaced
7992:909b989ec088 | 7993:b276833111cf |
---|---|
101 | 101 |
102 ngx_msec_t latest_rtt; | 102 ngx_msec_t latest_rtt; |
103 ngx_msec_t avg_rtt; | 103 ngx_msec_t avg_rtt; |
104 ngx_msec_t min_rtt; | 104 ngx_msec_t min_rtt; |
105 ngx_msec_t rttvar; | 105 ngx_msec_t rttvar; |
106 | |
107 ngx_msec_t pto_count; | |
106 | 108 |
107 #if (NGX_DEBUG) | 109 #if (NGX_DEBUG) |
108 ngx_uint_t nframes; | 110 ngx_uint_t nframes; |
109 #endif | 111 #endif |
110 | 112 |
198 static ngx_int_t ngx_quic_handle_ack_frame_range(ngx_connection_t *c, | 200 static ngx_int_t ngx_quic_handle_ack_frame_range(ngx_connection_t *c, |
199 ngx_quic_send_ctx_t *ctx, uint64_t min, uint64_t max, | 201 ngx_quic_send_ctx_t *ctx, uint64_t min, uint64_t max, |
200 ngx_msec_t *send_time); | 202 ngx_msec_t *send_time); |
201 static void ngx_quic_rtt_sample(ngx_connection_t *c, ngx_quic_ack_frame_t *ack, | 203 static void ngx_quic_rtt_sample(ngx_connection_t *c, ngx_quic_ack_frame_t *ack, |
202 enum ssl_encryption_level_t level, ngx_msec_t send_time); | 204 enum ssl_encryption_level_t level, ngx_msec_t send_time); |
205 static ngx_inline ngx_msec_t ngx_quic_pto(ngx_connection_t *c, | |
206 ngx_quic_send_ctx_t *ctx); | |
203 static void ngx_quic_handle_stream_ack(ngx_connection_t *c, | 207 static void ngx_quic_handle_stream_ack(ngx_connection_t *c, |
204 ngx_quic_frame_t *f); | 208 ngx_quic_frame_t *f); |
205 | 209 |
206 static ngx_int_t ngx_quic_handle_ordered_frame(ngx_connection_t *c, | 210 static ngx_int_t ngx_quic_handle_ordered_frame(ngx_connection_t *c, |
207 ngx_quic_frames_stream_t *fs, ngx_quic_frame_t *frame, | 211 ngx_quic_frames_stream_t *fs, ngx_quic_frame_t *frame, |
1320 * | 1324 * |
1321 * An endpoint sends a CONNECTION_CLOSE frame (Section 19.19) | 1325 * An endpoint sends a CONNECTION_CLOSE frame (Section 19.19) |
1322 * to terminate the connection immediately. | 1326 * to terminate the connection immediately. |
1323 */ | 1327 */ |
1324 | 1328 |
1329 qc->error_level = c->ssl ? SSL_quic_read_level(c->ssl->connection) | |
1330 : ssl_encryption_initial; | |
1331 | |
1325 if (rc == NGX_OK) { | 1332 if (rc == NGX_OK) { |
1326 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | 1333 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, |
1327 "quic immediate close, drain = %d", | 1334 "quic immediate close, drain = %d", |
1328 qc->draining); | 1335 qc->draining); |
1329 | 1336 |
1330 qc->close.log = c->log; | 1337 qc->close.log = c->log; |
1331 qc->close.data = c; | 1338 qc->close.data = c; |
1332 qc->close.handler = ngx_quic_close_timer_handler; | 1339 qc->close.handler = ngx_quic_close_timer_handler; |
1333 qc->close.cancelable = 1; | 1340 qc->close.cancelable = 1; |
1334 | 1341 |
1335 ngx_add_timer(&qc->close, 3 * NGX_QUIC_HARDCODED_PTO); | 1342 ctx = ngx_quic_get_send_ctx(qc, qc->error_level); |
1343 | |
1344 ngx_add_timer(&qc->close, 3 * ngx_quic_pto(c, ctx)); | |
1336 | 1345 |
1337 qc->error = NGX_QUIC_ERR_NO_ERROR; | 1346 qc->error = NGX_QUIC_ERR_NO_ERROR; |
1338 | 1347 |
1339 } else { | 1348 } else { |
1340 if (qc->error == 0 && !qc->error_app) { | 1349 if (qc->error == 0 && !qc->error_app) { |
1344 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | 1353 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, |
1345 "quic immediate close due to %serror: %ui %s", | 1354 "quic immediate close due to %serror: %ui %s", |
1346 qc->error_app ? "app " : "", qc->error, | 1355 qc->error_app ? "app " : "", qc->error, |
1347 qc->error_reason ? qc->error_reason : ""); | 1356 qc->error_reason ? qc->error_reason : ""); |
1348 } | 1357 } |
1349 | |
1350 qc->error_level = c->ssl ? SSL_quic_read_level(c->ssl->connection) | |
1351 : ssl_encryption_initial; | |
1352 | 1358 |
1353 (void) ngx_quic_send_cc(c); | 1359 (void) ngx_quic_send_cc(c); |
1354 | 1360 |
1355 if (qc->error_level == ssl_encryption_handshake) { | 1361 if (qc->error_level == ssl_encryption_handshake) { |
1356 /* for clients that might not have handshake keys */ | 1362 /* for clients that might not have handshake keys */ |
1749 * that no more Initial packets need to be exchanged | 1755 * that no more Initial packets need to be exchanged |
1750 */ | 1756 */ |
1751 ctx = ngx_quic_get_send_ctx(c->quic, ssl_encryption_initial); | 1757 ctx = ngx_quic_get_send_ctx(c->quic, ssl_encryption_initial); |
1752 ngx_quic_free_frames(c, &ctx->sent); | 1758 ngx_quic_free_frames(c, &ctx->sent); |
1753 | 1759 |
1760 qc->pto_count = 0; | |
1761 | |
1754 return ngx_quic_payload_handler(c, pkt); | 1762 return ngx_quic_payload_handler(c, pkt); |
1755 } | 1763 } |
1756 | 1764 |
1757 | 1765 |
1758 static ngx_int_t | 1766 static ngx_int_t |
2402 | 2410 |
2403 if (!qc->push.timer_set) { | 2411 if (!qc->push.timer_set) { |
2404 ngx_post_event(&qc->push, &ngx_posted_events); | 2412 ngx_post_event(&qc->push, &ngx_posted_events); |
2405 } | 2413 } |
2406 | 2414 |
2415 qc->pto_count = 0; | |
2416 | |
2407 return NGX_OK; | 2417 return NGX_OK; |
2408 } | 2418 } |
2409 | 2419 |
2410 | 2420 |
2411 static void | 2421 static void |
2449 } | 2459 } |
2450 | 2460 |
2451 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, | 2461 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, |
2452 "quic rtt sample: latest %M, min %M, avg %M, var %M", | 2462 "quic rtt sample: latest %M, min %M, avg %M, var %M", |
2453 latest_rtt, qc->min_rtt, qc->avg_rtt, qc->rttvar); | 2463 latest_rtt, qc->min_rtt, qc->avg_rtt, qc->rttvar); |
2464 } | |
2465 | |
2466 | |
2467 static ngx_inline ngx_msec_t | |
2468 ngx_quic_pto(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) | |
2469 { | |
2470 ngx_msec_t duration; | |
2471 ngx_quic_connection_t *qc; | |
2472 | |
2473 qc = c->quic; | |
2474 | |
2475 /* PTO calculation: quic-recovery, Appendix 8 */ | |
2476 duration = qc->avg_rtt; | |
2477 | |
2478 duration += ngx_max(4 * qc->rttvar, NGX_QUIC_TIME_GRANULARITY); | |
2479 duration <<= qc->pto_count; | |
2480 | |
2481 if (qc->congestion.in_flight == 0) { /* no in-flight packets */ | |
2482 return duration; | |
2483 } | |
2484 | |
2485 if (ctx == &qc->send_ctx[2] && c->ssl->handshaked) { | |
2486 /* application send space */ | |
2487 | |
2488 duration += qc->tp.max_ack_delay << qc->pto_count; | |
2489 } | |
2490 | |
2491 return duration; | |
2454 } | 2492 } |
2455 | 2493 |
2456 | 2494 |
2457 static void | 2495 static void |
2458 ngx_quic_handle_stream_ack(ngx_connection_t *c, ngx_quic_frame_t *f) | 2496 ngx_quic_handle_stream_ack(ngx_connection_t *c, ngx_quic_frame_t *f) |
2764 "quic ssl cipher: %s", SSL_get_cipher(ssl_conn)); | 2802 "quic ssl cipher: %s", SSL_get_cipher(ssl_conn)); |
2765 | 2803 |
2766 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | 2804 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, |
2767 "quic handshake completed successfully"); | 2805 "quic handshake completed successfully"); |
2768 | 2806 |
2807 c->ssl->handshaked = 1; | |
2808 | |
2769 frame = ngx_quic_alloc_frame(c, 0); | 2809 frame = ngx_quic_alloc_frame(c, 0); |
2770 if (frame == NULL) { | 2810 if (frame == NULL) { |
2771 return NGX_ERROR; | 2811 return NGX_ERROR; |
2772 } | 2812 } |
2773 | 2813 |
2797 * 4.10.2 An endpoint MUST discard its handshake keys | 2837 * 4.10.2 An endpoint MUST discard its handshake keys |
2798 * when the TLS handshake is confirmed | 2838 * when the TLS handshake is confirmed |
2799 */ | 2839 */ |
2800 ctx = ngx_quic_get_send_ctx(c->quic, ssl_encryption_handshake); | 2840 ctx = ngx_quic_get_send_ctx(c->quic, ssl_encryption_handshake); |
2801 ngx_quic_free_frames(c, &ctx->sent); | 2841 ngx_quic_free_frames(c, &ctx->sent); |
2842 | |
2843 c->quic->pto_count = 0; | |
2802 } | 2844 } |
2803 | 2845 |
2804 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | 2846 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, |
2805 "quic SSL_quic_read_level: %d, SSL_quic_write_level: %d", | 2847 "quic SSL_quic_read_level: %d, SSL_quic_write_level: %d", |
2806 (int) SSL_quic_read_level(ssl_conn), | 2848 (int) SSL_quic_read_level(ssl_conn), |
3482 /* if we are closing, any ack will be discarded */ | 3524 /* if we are closing, any ack will be discarded */ |
3483 ngx_quic_free_frames(c, frames); | 3525 ngx_quic_free_frames(c, frames); |
3484 | 3526 |
3485 } else { | 3527 } else { |
3486 ngx_queue_add(&ctx->sent, frames); | 3528 ngx_queue_add(&ctx->sent, frames); |
3487 ngx_add_timer(&qc->pto, NGX_QUIC_HARDCODED_PTO); | 3529 if (qc->pto.timer_set) { |
3530 ngx_del_timer(&qc->pto); | |
3531 } | |
3532 ngx_add_timer(&qc->pto, ngx_quic_pto(c, ctx)); | |
3488 } | 3533 } |
3489 | 3534 |
3490 qc->congestion.in_flight += out.len; | 3535 qc->congestion.in_flight += out.len; |
3491 | 3536 |
3492 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | 3537 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, |
3542 | 3587 |
3543 if (ngx_quic_detect_lost(c, 0) != NGX_OK) { | 3588 if (ngx_quic_detect_lost(c, 0) != NGX_OK) { |
3544 ngx_quic_close_connection(c, NGX_ERROR); | 3589 ngx_quic_close_connection(c, NGX_ERROR); |
3545 return; | 3590 return; |
3546 } | 3591 } |
3592 | |
3593 c->quic->pto_count++; | |
3547 } | 3594 } |
3548 | 3595 |
3549 | 3596 |
3550 static void | 3597 static void |
3551 ngx_quic_push_handler(ngx_event_t *ev) | 3598 ngx_quic_push_handler(ngx_event_t *ev) |
3577 qc = c->quic; | 3624 qc = c->quic; |
3578 now = ngx_current_msec; | 3625 now = ngx_current_msec; |
3579 | 3626 |
3580 min_wait = 0; | 3627 min_wait = 0; |
3581 | 3628 |
3629 #if (NGX_SUPPRESS_WARN) | |
3630 thr = 0; | |
3631 #endif | |
3632 | |
3582 if (ack) { | 3633 if (ack) { |
3583 thr = NGX_QUIC_TIME_THR * ngx_max(qc->latest_rtt, qc->avg_rtt); | 3634 thr = NGX_QUIC_TIME_THR * ngx_max(qc->latest_rtt, qc->avg_rtt); |
3584 thr = ngx_max(thr, NGX_QUIC_TIME_GRANULARITY); | 3635 thr = ngx_max(thr, NGX_QUIC_TIME_GRANULARITY); |
3585 | |
3586 } else { | |
3587 thr = NGX_QUIC_HARDCODED_PTO; | |
3588 } | 3636 } |
3589 | 3637 |
3590 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { | 3638 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { |
3591 | 3639 |
3592 ctx = &qc->send_ctx[i]; | 3640 ctx = &qc->send_ctx[i]; |
3593 | 3641 |
3594 if (ngx_queue_empty(&ctx->sent)) { | 3642 if (ngx_queue_empty(&ctx->sent)) { |
3595 continue; | 3643 continue; |
3644 } | |
3645 | |
3646 if (!ack) { | |
3647 thr = ngx_quic_pto(c, ctx); | |
3596 } | 3648 } |
3597 | 3649 |
3598 q = ngx_queue_head(&ctx->sent); | 3650 q = ngx_queue_head(&ctx->sent); |
3599 | 3651 |
3600 do { | 3652 do { |