comparison src/event/ngx_event_quic.c @ 8475: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
8474:909b989ec088 8475: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 {