Mercurial > hg > nginx
comparison src/event/ngx_event_quic.c @ 8496:c5324bb3a704 quic
QUIC: limited the number of client-initiated streams.
The limits on active bidi and uni client streams are maintained at their
initial values initial_max_streams_bidi and initial_max_streams_uni by sending
a MAX_STREAMS frame upon each client stream closure.
Also, the following is changed for data arriving to non-existing streams:
- if a stream was already closed, such data is ignored
- when creating a new stream, all streams of the same type with lower ids are
created too
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Mon, 27 Jul 2020 19:15:17 +0300 |
parents | 455a8536eaa7 |
children | b0e74a54c98b |
comparison
equal
deleted
inserted
replaced
8495:455a8536eaa7 | 8496:c5324bb3a704 |
---|---|
46 | 46 |
47 uint64_t server_max_streams_uni; | 47 uint64_t server_max_streams_uni; |
48 uint64_t server_max_streams_bidi; | 48 uint64_t server_max_streams_bidi; |
49 uint64_t server_streams_uni; | 49 uint64_t server_streams_uni; |
50 uint64_t server_streams_bidi; | 50 uint64_t server_streams_bidi; |
51 | |
52 uint64_t client_max_streams_uni; | |
53 uint64_t client_max_streams_bidi; | |
54 uint64_t client_streams_uni; | |
55 uint64_t client_streams_bidi; | |
51 } ngx_quic_streams_t; | 56 } ngx_quic_streams_t; |
52 | 57 |
53 | 58 |
54 typedef struct { | 59 typedef struct { |
55 size_t in_flight; | 60 size_t in_flight; |
119 #endif | 124 #endif |
120 | 125 |
121 ngx_quic_streams_t streams; | 126 ngx_quic_streams_t streams; |
122 ngx_quic_congestion_t congestion; | 127 ngx_quic_congestion_t congestion; |
123 size_t received; | 128 size_t received; |
124 | |
125 uint64_t cur_streams; | |
126 uint64_t max_streams; | |
127 | 129 |
128 ngx_uint_t error; | 130 ngx_uint_t error; |
129 enum ssl_encryption_level_t error_level; | 131 enum ssl_encryption_level_t error_level; |
130 ngx_uint_t error_ftype; | 132 ngx_uint_t error_ftype; |
131 const char *error_reason; | 133 const char *error_reason; |
231 static ngx_int_t ngx_quic_handle_stream_frame(ngx_connection_t *c, | 233 static ngx_int_t ngx_quic_handle_stream_frame(ngx_connection_t *c, |
232 ngx_quic_header_t *pkt, ngx_quic_frame_t *frame); | 234 ngx_quic_header_t *pkt, ngx_quic_frame_t *frame); |
233 static ngx_int_t ngx_quic_stream_input(ngx_connection_t *c, | 235 static ngx_int_t ngx_quic_stream_input(ngx_connection_t *c, |
234 ngx_quic_frame_t *frame, void *data); | 236 ngx_quic_frame_t *frame, void *data); |
235 | 237 |
236 static ngx_int_t ngx_quic_handle_max_streams(ngx_connection_t *c); | |
237 static ngx_int_t ngx_quic_handle_max_data_frame(ngx_connection_t *c, | 238 static ngx_int_t ngx_quic_handle_max_data_frame(ngx_connection_t *c, |
238 ngx_quic_max_data_frame_t *f); | 239 ngx_quic_max_data_frame_t *f); |
239 static ngx_int_t ngx_quic_handle_streams_blocked_frame(ngx_connection_t *c, | 240 static ngx_int_t ngx_quic_handle_streams_blocked_frame(ngx_connection_t *c, |
240 ngx_quic_header_t *pkt, ngx_quic_streams_blocked_frame_t *f); | 241 ngx_quic_header_t *pkt, ngx_quic_streams_blocked_frame_t *f); |
241 static ngx_int_t ngx_quic_handle_stream_data_blocked_frame(ngx_connection_t *c, | 242 static ngx_int_t ngx_quic_handle_stream_data_blocked_frame(ngx_connection_t *c, |
720 ctp->ack_delay_exponent = NGX_QUIC_DEFAULT_ACK_DELAY_EXPONENT; | 721 ctp->ack_delay_exponent = NGX_QUIC_DEFAULT_ACK_DELAY_EXPONENT; |
721 ctp->max_ack_delay = NGX_QUIC_DEFAULT_MAX_ACK_DELAY; | 722 ctp->max_ack_delay = NGX_QUIC_DEFAULT_MAX_ACK_DELAY; |
722 | 723 |
723 qc->streams.recv_max_data = qc->tp.initial_max_data; | 724 qc->streams.recv_max_data = qc->tp.initial_max_data; |
724 | 725 |
726 qc->streams.client_max_streams_uni = qc->tp.initial_max_streams_uni; | |
727 qc->streams.client_max_streams_bidi = qc->tp.initial_max_streams_bidi; | |
728 | |
725 qc->congestion.window = ngx_min(10 * qc->tp.max_udp_payload_size, | 729 qc->congestion.window = ngx_min(10 * qc->tp.max_udp_payload_size, |
726 ngx_max(2 * qc->tp.max_udp_payload_size, | 730 ngx_max(2 * qc->tp.max_udp_payload_size, |
727 14720)); | 731 14720)); |
728 qc->congestion.ssthresh = NGX_MAX_SIZE_T_VALUE; | 732 qc->congestion.ssthresh = NGX_MAX_SIZE_T_VALUE; |
729 qc->congestion.recovery_start = ngx_current_msec; | 733 qc->congestion.recovery_start = ngx_current_msec; |
1179 ngx_log_error(NGX_LOG_INFO, c->log, 0, | 1183 ngx_log_error(NGX_LOG_INFO, c->log, 0, |
1180 "quic SSL_set_quic_early_data_context() failed"); | 1184 "quic SSL_set_quic_early_data_context() failed"); |
1181 return NGX_ERROR; | 1185 return NGX_ERROR; |
1182 } | 1186 } |
1183 #endif | 1187 #endif |
1184 | |
1185 qc->max_streams = qc->tp.initial_max_streams_bidi; | |
1186 | 1188 |
1187 return NGX_OK; | 1189 return NGX_OK; |
1188 } | 1190 } |
1189 | 1191 |
1190 | 1192 |
2883 static ngx_int_t | 2885 static ngx_int_t |
2884 ngx_quic_handle_stream_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, | 2886 ngx_quic_handle_stream_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, |
2885 ngx_quic_frame_t *frame) | 2887 ngx_quic_frame_t *frame) |
2886 { | 2888 { |
2887 size_t n; | 2889 size_t n; |
2890 uint64_t id; | |
2888 ngx_buf_t *b; | 2891 ngx_buf_t *b; |
2889 ngx_event_t *rev; | 2892 ngx_event_t *rev; |
2890 ngx_quic_stream_t *sn; | 2893 ngx_quic_stream_t *sn; |
2891 ngx_quic_connection_t *qc; | 2894 ngx_quic_connection_t *qc; |
2892 ngx_quic_stream_frame_t *f; | 2895 ngx_quic_stream_frame_t *f; |
2911 if (f->stream_id & NGX_QUIC_STREAM_SERVER_INITIATED) { | 2914 if (f->stream_id & NGX_QUIC_STREAM_SERVER_INITIATED) { |
2912 qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR; | 2915 qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR; |
2913 return NGX_ERROR; | 2916 return NGX_ERROR; |
2914 } | 2917 } |
2915 | 2918 |
2916 n = (f->stream_id & NGX_QUIC_STREAM_UNIDIRECTIONAL) | 2919 if (f->stream_id & NGX_QUIC_STREAM_UNIDIRECTIONAL) { |
2917 ? qc->tp.initial_max_stream_data_uni | 2920 if ((f->stream_id >> 2) < qc->streams.client_streams_uni) { |
2918 : qc->tp.initial_max_stream_data_bidi_remote; | 2921 return NGX_OK; |
2922 } | |
2923 | |
2924 if ((f->stream_id >> 2) >= qc->streams.client_max_streams_uni) { | |
2925 qc->error = NGX_QUIC_ERR_STREAM_LIMIT_ERROR; | |
2926 return NGX_ERROR; | |
2927 } | |
2928 | |
2929 id = (qc->streams.client_streams_uni << 2) | |
2930 | NGX_QUIC_STREAM_UNIDIRECTIONAL; | |
2931 qc->streams.client_streams_uni = (f->stream_id >> 2) + 1; | |
2932 n = qc->tp.initial_max_stream_data_uni; | |
2933 | |
2934 } else { | |
2935 if ((f->stream_id >> 2) < qc->streams.client_streams_bidi) { | |
2936 return NGX_OK; | |
2937 } | |
2938 | |
2939 if ((f->stream_id >> 2) >= qc->streams.client_max_streams_bidi) { | |
2940 qc->error = NGX_QUIC_ERR_STREAM_LIMIT_ERROR; | |
2941 return NGX_ERROR; | |
2942 } | |
2943 | |
2944 id = (qc->streams.client_streams_bidi << 2); | |
2945 qc->streams.client_streams_bidi = (f->stream_id >> 2) + 1; | |
2946 n = qc->tp.initial_max_stream_data_bidi_remote; | |
2947 } | |
2919 | 2948 |
2920 if (n < NGX_QUIC_STREAM_BUFSIZE) { | 2949 if (n < NGX_QUIC_STREAM_BUFSIZE) { |
2921 n = NGX_QUIC_STREAM_BUFSIZE; | 2950 n = NGX_QUIC_STREAM_BUFSIZE; |
2922 } | 2951 } |
2923 | 2952 |
2926 "quic no space in stream buffer"); | 2955 "quic no space in stream buffer"); |
2927 return NGX_ERROR; | 2956 return NGX_ERROR; |
2928 } | 2957 } |
2929 | 2958 |
2930 /* | 2959 /* |
2931 * TODO: check IDs are increasing ? create all lower-numbered? | |
2932 * | |
2933 * 2.1. Stream Types and Identifiers | 2960 * 2.1. Stream Types and Identifiers |
2934 * | 2961 * |
2935 * Within each type, streams are created with numerically increasing | 2962 * Within each type, streams are created with numerically increasing |
2936 * stream IDs. A stream ID that is used out of order results in all | 2963 * stream IDs. A stream ID that is used out of order results in all |
2937 * streams of that type with lower-numbered stream IDs also being | 2964 * streams of that type with lower-numbered stream IDs also being |
2938 * opened. | 2965 * opened. |
2939 */ | 2966 */ |
2940 sn = ngx_quic_create_stream(c, f->stream_id, n); | 2967 |
2941 if (sn == NULL) { | 2968 for ( /* void */ ; id <= f->stream_id; id += 0x04) { |
2942 return NGX_ERROR; | 2969 |
2943 } | 2970 sn = ngx_quic_create_stream(c, id, n); |
2944 | 2971 if (sn == NULL) { |
2945 rev = sn->c->read; | 2972 return NGX_ERROR; |
2946 | |
2947 if (f->offset == 0) { | |
2948 | |
2949 b = sn->b; | |
2950 b->last = ngx_cpymem(b->last, f->data, f->length); | |
2951 | |
2952 sn->fs.received += f->length; | |
2953 | |
2954 rev->ready = 1; | |
2955 | |
2956 if (f->fin) { | |
2957 rev->pending_eof = 1; | |
2958 } | 2973 } |
2959 | 2974 |
2960 } else { | 2975 if (id == f->stream_id && f->offset == 0) { |
2961 rev->ready = 0; | 2976 b = sn->b; |
2962 } | 2977 b->last = ngx_cpymem(b->last, f->data, f->length); |
2963 | 2978 |
2964 if ((f->stream_id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0) { | 2979 sn->fs.received += f->length; |
2965 ngx_quic_handle_max_streams(c); | 2980 |
2966 } | 2981 rev = sn->c->read; |
2967 | 2982 rev->ready = 1; |
2968 sn->c->listening->handler(sn->c); | 2983 |
2984 if (f->fin) { | |
2985 rev->pending_eof = 1; | |
2986 } | |
2987 } | |
2988 | |
2989 sn->c->listening->handler(sn->c); | |
2990 } | |
2969 | 2991 |
2970 if (f->offset == 0) { | 2992 if (f->offset == 0) { |
2971 return NGX_OK; | 2993 return NGX_OK; |
2972 } | 2994 } |
2973 | 2995 |
3025 | 3047 |
3026 /* check if stream was destroyed by handler */ | 3048 /* check if stream was destroyed by handler */ |
3027 if (ngx_quic_find_stream(&qc->streams.tree, f->stream_id) == NULL) { | 3049 if (ngx_quic_find_stream(&qc->streams.tree, f->stream_id) == NULL) { |
3028 return NGX_DONE; | 3050 return NGX_DONE; |
3029 } | 3051 } |
3030 | |
3031 return NGX_OK; | |
3032 } | |
3033 | |
3034 | |
3035 static ngx_int_t | |
3036 ngx_quic_handle_max_streams(ngx_connection_t *c) | |
3037 { | |
3038 ngx_quic_frame_t *frame; | |
3039 ngx_quic_connection_t *qc; | |
3040 | |
3041 qc = c->quic; | |
3042 qc->cur_streams++; | |
3043 | |
3044 if (qc->cur_streams + NGX_QUIC_STREAMS_INC / 2 < qc->max_streams) { | |
3045 return NGX_OK; | |
3046 } | |
3047 | |
3048 frame = ngx_quic_alloc_frame(c, 0); | |
3049 if (frame == NULL) { | |
3050 return NGX_ERROR; | |
3051 } | |
3052 | |
3053 qc->max_streams = ngx_max(qc->max_streams + NGX_QUIC_STREAMS_INC, | |
3054 NGX_QUIC_STREAMS_LIMIT); | |
3055 | |
3056 frame->level = ssl_encryption_application; | |
3057 frame->type = NGX_QUIC_FT_MAX_STREAMS; | |
3058 frame->u.max_streams.limit = qc->max_streams; | |
3059 frame->u.max_streams.bidi = 1; | |
3060 | |
3061 ngx_sprintf(frame->info, "MAX_STREAMS limit:%d bidi:%d level=%d", | |
3062 (int) frame->u.max_streams.limit, | |
3063 (int) frame->u.max_streams.bidi, | |
3064 frame->level); | |
3065 | |
3066 ngx_quic_queue_frame(qc, frame); | |
3067 | 3052 |
3068 return NGX_OK; | 3053 return NGX_OK; |
3069 } | 3054 } |
3070 | 3055 |
3071 | 3056 |
3110 | 3095 |
3111 static ngx_int_t | 3096 static ngx_int_t |
3112 ngx_quic_handle_streams_blocked_frame(ngx_connection_t *c, | 3097 ngx_quic_handle_streams_blocked_frame(ngx_connection_t *c, |
3113 ngx_quic_header_t *pkt, ngx_quic_streams_blocked_frame_t *f) | 3098 ngx_quic_header_t *pkt, ngx_quic_streams_blocked_frame_t *f) |
3114 { | 3099 { |
3115 ngx_quic_frame_t *frame; | |
3116 | |
3117 frame = ngx_quic_alloc_frame(c, 0); | |
3118 if (frame == NULL) { | |
3119 return NGX_ERROR; | |
3120 } | |
3121 | |
3122 frame->level = pkt->level; | |
3123 frame->type = NGX_QUIC_FT_MAX_STREAMS; | |
3124 frame->u.max_streams.limit = ngx_max(f->limit * 2, NGX_QUIC_STREAMS_LIMIT); | |
3125 frame->u.max_streams.bidi = f->bidi; | |
3126 | |
3127 c->quic->max_streams = frame->u.max_streams.limit; | |
3128 | |
3129 ngx_sprintf(frame->info, "MAX_STREAMS limit:%d bidi:%d level=%d", | |
3130 (int) frame->u.max_streams.limit, | |
3131 (int) frame->u.max_streams.bidi, | |
3132 frame->level); | |
3133 | |
3134 ngx_quic_queue_frame(c->quic, frame); | |
3135 | |
3136 return NGX_OK; | 3100 return NGX_OK; |
3137 } | 3101 } |
3138 | 3102 |
3139 | 3103 |
3140 static ngx_int_t | 3104 static ngx_int_t |
3919 ngx_pool_t *pool; | 3883 ngx_pool_t *pool; |
3920 ngx_quic_stream_t *sn; | 3884 ngx_quic_stream_t *sn; |
3921 ngx_pool_cleanup_t *cln; | 3885 ngx_pool_cleanup_t *cln; |
3922 ngx_quic_connection_t *qc; | 3886 ngx_quic_connection_t *qc; |
3923 | 3887 |
3888 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
3889 "quic stream id 0x%uL create", id); | |
3890 | |
3924 qc = c->quic; | 3891 qc = c->quic; |
3925 | 3892 |
3926 pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, c->log); | 3893 pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, c->log); |
3927 if (pool == NULL) { | 3894 if (pool == NULL) { |
3928 return NULL; | 3895 return NULL; |
4255 /* schedule handler call to continue ngx_quic_close_connection() */ | 4222 /* schedule handler call to continue ngx_quic_close_connection() */ |
4256 ngx_post_event(pc->read, &ngx_posted_events); | 4223 ngx_post_event(pc->read, &ngx_posted_events); |
4257 return; | 4224 return; |
4258 } | 4225 } |
4259 | 4226 |
4260 if ((qs->id & 0x03) == NGX_QUIC_STREAM_UNIDIRECTIONAL) { | 4227 if ((qs->id & NGX_QUIC_STREAM_SERVER_INITIATED) == 0) { |
4261 /* do not send fin for client unidirectional streams */ | 4228 frame = ngx_quic_alloc_frame(pc, 0); |
4262 return; | 4229 if (frame == NULL) { |
4230 return; | |
4231 } | |
4232 | |
4233 frame->level = ssl_encryption_application; | |
4234 frame->type = NGX_QUIC_FT_MAX_STREAMS; | |
4235 | |
4236 if (qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) { | |
4237 frame->u.max_streams.limit = ++qc->streams.client_max_streams_uni; | |
4238 frame->u.max_streams.bidi = 0; | |
4239 | |
4240 } else { | |
4241 frame->u.max_streams.limit = ++qc->streams.client_max_streams_bidi; | |
4242 frame->u.max_streams.bidi = 1; | |
4243 } | |
4244 | |
4245 ngx_sprintf(frame->info, "MAX_STREAMS limit:%uL bidi:%ui level=%d", | |
4246 frame->u.max_streams.limit, | |
4247 frame->u.max_streams.bidi, | |
4248 (int) frame->level); | |
4249 | |
4250 ngx_quic_queue_frame(qc, frame); | |
4251 | |
4252 if (qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) { | |
4253 /* do not send fin for client unidirectional streams */ | |
4254 return; | |
4255 } | |
4263 } | 4256 } |
4264 | 4257 |
4265 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | 4258 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, |
4266 "quic stream id 0x%xL send fin", qs->id); | 4259 "quic stream id 0x%xL send fin", qs->id); |
4267 | 4260 |