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