Mercurial > hg > nginx
comparison src/event/quic/ngx_event_quic_ack.c @ 9143:48691bab4474
QUIC: fixed probe-congestion deadlock.
When probe timeout expired while congestion window was exhausted, probe PINGs
could not be sent. As a result, lost packets could not be declared lost and
congestion window could not be freed for new packets. This deadlock
continued until connection idle timeout expiration.
Now PINGs are sent separately from the frame queue without congestion control,
as specified by RFC 9002, Section 7:
An endpoint MUST NOT send a packet if it would cause bytes_in_flight
(see Appendix B.2) to be larger than the congestion window, unless the
packet is sent on a PTO timer expiration (see Section 6.2) or when entering
recovery (see Section 7.3.2).
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Mon, 14 Aug 2023 08:28:30 +0400 |
parents | 7e8ee4b7cbf4 |
children | 58afcd72446f |
comparison
equal
deleted
inserted
replaced
9142:7e8ee4b7cbf4 | 9143:48691bab4474 |
---|---|
818 void | 818 void |
819 ngx_quic_pto_handler(ngx_event_t *ev) | 819 ngx_quic_pto_handler(ngx_event_t *ev) |
820 { | 820 { |
821 ngx_uint_t i; | 821 ngx_uint_t i; |
822 ngx_msec_t now; | 822 ngx_msec_t now; |
823 ngx_queue_t *q, *next; | 823 ngx_queue_t *q; |
824 ngx_connection_t *c; | 824 ngx_connection_t *c; |
825 ngx_quic_frame_t *f; | 825 ngx_quic_frame_t *f, frame; |
826 ngx_quic_send_ctx_t *ctx; | 826 ngx_quic_send_ctx_t *ctx; |
827 ngx_quic_connection_t *qc; | 827 ngx_quic_connection_t *qc; |
828 | 828 |
829 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "quic pto timer"); | 829 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "quic pto timer"); |
830 | 830 |
857 | 857 |
858 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | 858 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, |
859 "quic pto %s pto_count:%ui", | 859 "quic pto %s pto_count:%ui", |
860 ngx_quic_level_name(ctx->level), qc->pto_count); | 860 ngx_quic_level_name(ctx->level), qc->pto_count); |
861 | 861 |
862 for (q = ngx_queue_head(&ctx->frames); | 862 ngx_memzero(&frame, sizeof(ngx_quic_frame_t)); |
863 q != ngx_queue_sentinel(&ctx->frames); | 863 |
864 /* void */) | 864 frame.level = ctx->level; |
865 frame.type = NGX_QUIC_FT_PING; | |
866 | |
867 if (ngx_quic_frame_sendto(c, &frame, 0, qc->path) != NGX_OK | |
868 || ngx_quic_frame_sendto(c, &frame, 0, qc->path) != NGX_OK) | |
865 { | 869 { |
866 next = ngx_queue_next(q); | 870 ngx_quic_close_connection(c, NGX_ERROR); |
867 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | 871 return; |
868 | 872 } |
869 if (f->type == NGX_QUIC_FT_PING) { | |
870 ngx_queue_remove(q); | |
871 ngx_quic_free_frame(c, f); | |
872 } | |
873 | |
874 q = next; | |
875 } | |
876 | |
877 for (q = ngx_queue_head(&ctx->sent); | |
878 q != ngx_queue_sentinel(&ctx->sent); | |
879 /* void */) | |
880 { | |
881 next = ngx_queue_next(q); | |
882 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
883 | |
884 if (f->type == NGX_QUIC_FT_PING) { | |
885 ngx_quic_congestion_lost(c, f); | |
886 ngx_queue_remove(q); | |
887 ngx_quic_free_frame(c, f); | |
888 } | |
889 | |
890 q = next; | |
891 } | |
892 | |
893 /* enforce 2 udp datagrams */ | |
894 | |
895 f = ngx_quic_alloc_frame(c); | |
896 if (f == NULL) { | |
897 break; | |
898 } | |
899 | |
900 f->level = ctx->level; | |
901 f->type = NGX_QUIC_FT_PING; | |
902 f->flush = 1; | |
903 | |
904 ngx_quic_queue_frame(qc, f); | |
905 | |
906 f = ngx_quic_alloc_frame(c); | |
907 if (f == NULL) { | |
908 break; | |
909 } | |
910 | |
911 f->level = ctx->level; | |
912 f->type = NGX_QUIC_FT_PING; | |
913 | |
914 ngx_quic_queue_frame(qc, f); | |
915 } | 873 } |
916 | 874 |
917 qc->pto_count++; | 875 qc->pto_count++; |
876 | |
877 ngx_quic_set_lost_timer(c); | |
918 | 878 |
919 ngx_quic_connstate_dbg(c); | 879 ngx_quic_connstate_dbg(c); |
920 } | 880 } |
921 | 881 |
922 | 882 |