comparison src/event/ngx_event_quic.c @ 8504:d277e25e37fc quic

QUIC: create streams for STREAM_DATA_BLOCKED and MAX_STREAM_DATA. Creating client-initiated streams is moved from ngx_quic_handle_stream_frame() to a separate function ngx_quic_create_client_stream(). This function is responsible for creating streams with lower ids as well. Also, simplified and fixed initial data buffering in ngx_quic_handle_stream_frame(). It is now done before calling the initial handler as the handler can destroy the stream.
author Roman Arutyunyan <arut@nginx.com>
date Tue, 11 Aug 2020 19:10:57 +0300
parents b66a2a041d7e
children 240931629995
comparison
equal deleted inserted replaced
8503:b66a2a041d7e 8504:d277e25e37fc
31 /* 31 /*
32 * 7.4. Cryptographic Message Buffering 32 * 7.4. Cryptographic Message Buffering
33 * Implementations MUST support buffering at least 4096 bytes of data 33 * Implementations MUST support buffering at least 4096 bytes of data
34 */ 34 */
35 #define NGX_QUIC_MAX_BUFFERED 65535 35 #define NGX_QUIC_MAX_BUFFERED 65535
36
37 #define NGX_QUIC_STREAM_GONE (void *) -1
36 38
37 39
38 typedef struct { 40 typedef struct {
39 ngx_rbtree_t tree; 41 ngx_rbtree_t tree;
40 ngx_rbtree_node_t sentinel; 42 ngx_rbtree_node_t sentinel;
268 270
269 static void ngx_quic_rbtree_insert_stream(ngx_rbtree_node_t *temp, 271 static void ngx_quic_rbtree_insert_stream(ngx_rbtree_node_t *temp,
270 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); 272 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
271 static ngx_quic_stream_t *ngx_quic_find_stream(ngx_rbtree_t *rbtree, 273 static ngx_quic_stream_t *ngx_quic_find_stream(ngx_rbtree_t *rbtree,
272 uint64_t id); 274 uint64_t id);
275 static ngx_quic_stream_t *ngx_quic_create_client_stream(ngx_connection_t *c,
276 uint64_t id);
273 static ngx_quic_stream_t *ngx_quic_create_stream(ngx_connection_t *c, 277 static ngx_quic_stream_t *ngx_quic_create_stream(ngx_connection_t *c,
274 uint64_t id, size_t rcvbuf_size); 278 uint64_t id, size_t rcvbuf_size);
275 static ssize_t ngx_quic_stream_recv(ngx_connection_t *c, u_char *buf, 279 static ssize_t ngx_quic_stream_recv(ngx_connection_t *c, u_char *buf,
276 size_t size); 280 size_t size);
277 static ssize_t ngx_quic_stream_send(ngx_connection_t *c, u_char *buf, 281 static ssize_t ngx_quic_stream_send(ngx_connection_t *c, u_char *buf,
2891 2895
2892 static ngx_int_t 2896 static ngx_int_t
2893 ngx_quic_handle_stream_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, 2897 ngx_quic_handle_stream_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
2894 ngx_quic_frame_t *frame) 2898 ngx_quic_frame_t *frame)
2895 { 2899 {
2896 size_t n; 2900 ngx_pool_t *pool;
2897 uint64_t id; 2901 ngx_connection_t *sc;
2898 ngx_buf_t *b;
2899 ngx_event_t *rev;
2900 ngx_quic_stream_t *sn; 2902 ngx_quic_stream_t *sn;
2901 ngx_quic_connection_t *qc; 2903 ngx_quic_connection_t *qc;
2902 ngx_quic_stream_frame_t *f; 2904 ngx_quic_stream_frame_t *f;
2903 ngx_quic_frames_stream_t *fs; 2905 ngx_quic_frames_stream_t *fs;
2904 2906
2913 } 2915 }
2914 2916
2915 sn = ngx_quic_find_stream(&qc->streams.tree, f->stream_id); 2917 sn = ngx_quic_find_stream(&qc->streams.tree, f->stream_id);
2916 2918
2917 if (sn == NULL) { 2919 if (sn == NULL) {
2918 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, 2920 sn = ngx_quic_create_client_stream(c, f->stream_id);
2919 "quic stream id 0x%xL is new", f->stream_id); 2921
2920 2922 if (sn == NULL) {
2921 if (f->stream_id & NGX_QUIC_STREAM_SERVER_INITIATED) {
2922 qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR;
2923 return NGX_ERROR; 2923 return NGX_ERROR;
2924 } 2924 }
2925 2925
2926 if (f->stream_id & NGX_QUIC_STREAM_UNIDIRECTIONAL) { 2926 if (sn == NGX_QUIC_STREAM_GONE) {
2927 if ((f->stream_id >> 2) < qc->streams.client_streams_uni) { 2927 return NGX_OK;
2928 return NGX_OK; 2928 }
2929 } 2929
2930 2930 sc = sn->c;
2931 if ((f->stream_id >> 2) >= qc->streams.client_max_streams_uni) { 2931 fs = &sn->fs;
2932 qc->error = NGX_QUIC_ERR_STREAM_LIMIT_ERROR; 2932
2933 return NGX_ERROR; 2933 if (ngx_quic_handle_ordered_frame(c, fs, frame, ngx_quic_stream_input,
2934 } 2934 sn)
2935 2935 != NGX_OK)
2936 id = (qc->streams.client_streams_uni << 2) 2936 {
2937 | NGX_QUIC_STREAM_UNIDIRECTIONAL; 2937 pool = sc->pool;
2938 qc->streams.client_streams_uni = (f->stream_id >> 2) + 1; 2938
2939 n = qc->tp.initial_max_stream_data_uni; 2939 ngx_close_connection(sc);
2940 2940 ngx_destroy_pool(pool);
2941 } else { 2941
2942 if ((f->stream_id >> 2) < qc->streams.client_streams_bidi) {
2943 return NGX_OK;
2944 }
2945
2946 if ((f->stream_id >> 2) >= qc->streams.client_max_streams_bidi) {
2947 qc->error = NGX_QUIC_ERR_STREAM_LIMIT_ERROR;
2948 return NGX_ERROR;
2949 }
2950
2951 id = (qc->streams.client_streams_bidi << 2);
2952 qc->streams.client_streams_bidi = (f->stream_id >> 2) + 1;
2953 n = qc->tp.initial_max_stream_data_bidi_remote;
2954 }
2955
2956 if (n < NGX_QUIC_STREAM_BUFSIZE) {
2957 n = NGX_QUIC_STREAM_BUFSIZE;
2958 }
2959
2960 if (n < f->length) {
2961 ngx_log_error(NGX_LOG_INFO, c->log, 0,
2962 "quic no space in stream buffer");
2963 return NGX_ERROR; 2942 return NGX_ERROR;
2964 } 2943 }
2965 2944
2966 /* 2945 sc->listening->handler(sc);
2967 * 2.1. Stream Types and Identifiers 2946
2968 * 2947 return NGX_OK;
2969 * Within each type, streams are created with numerically increasing
2970 * stream IDs. A stream ID that is used out of order results in all
2971 * streams of that type with lower-numbered stream IDs also being
2972 * opened.
2973 */
2974
2975 for ( /* void */ ; id <= f->stream_id; id += 0x04) {
2976
2977 sn = ngx_quic_create_stream(c, id, n);
2978 if (sn == NULL) {
2979 return NGX_ERROR;
2980 }
2981
2982 if (id == f->stream_id && f->offset == 0) {
2983 b = sn->b;
2984 b->last = ngx_cpymem(b->last, f->data, f->length);
2985
2986 sn->fs.received += f->length;
2987
2988 rev = sn->c->read;
2989 rev->ready = 1;
2990
2991 if (f->fin) {
2992 rev->pending_eof = 1;
2993 }
2994 }
2995
2996 sn->c->listening->handler(sn->c);
2997 }
2998
2999 if (f->offset == 0) {
3000 return NGX_OK;
3001 }
3002
3003 /* out-of-order stream: proceed to buffering */
3004 } 2948 }
3005 2949
3006 fs = &sn->fs; 2950 fs = &sn->fs;
3007 2951
3008 return ngx_quic_handle_ordered_frame(c, fs, frame, ngx_quic_stream_input, 2952 return ngx_quic_handle_ordered_frame(c, fs, frame, ngx_quic_stream_input,
3024 sn = data; 2968 sn = data;
3025 2969
3026 f = &frame->u.stream; 2970 f = &frame->u.stream;
3027 id = f->stream_id; 2971 id = f->stream_id;
3028 2972
3029 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic existing stream");
3030
3031 b = sn->b; 2973 b = sn->b;
3032 2974
3033 if ((size_t) ((b->pos - b->start) + (b->end - b->last)) < f->length) { 2975 if ((size_t) ((b->pos - b->start) + (b->end - b->last)) < f->length) {
3034 ngx_log_error(NGX_LOG_INFO, c->log, 0, 2976 ngx_log_error(NGX_LOG_INFO, c->log, 0,
3035 "quic no space in stream buffer"); 2977 "quic no space in stream buffer");
3130 } 3072 }
3131 3073
3132 sn = ngx_quic_find_stream(&qc->streams.tree, f->id); 3074 sn = ngx_quic_find_stream(&qc->streams.tree, f->id);
3133 3075
3134 if (sn == NULL) { 3076 if (sn == NULL) {
3135 ngx_log_error(NGX_LOG_INFO, c->log, 0, 3077 sn = ngx_quic_create_client_stream(c, f->id);
3136 "quic unknown stream id:0x%xL", f->id); 3078
3137 return NGX_ERROR; 3079 if (sn == NULL) {
3138 } 3080 return NGX_ERROR;
3139 3081 }
3140 b = sn->b; 3082
3141 n = sn->fs.received + (b->pos - b->start) + (b->end - b->last); 3083 if (sn == NGX_QUIC_STREAM_GONE) {
3084 return NGX_OK;
3085 }
3086
3087 b = sn->b;
3088 n = b->end - b->last;
3089
3090 sn->c->listening->handler(sn->c);
3091
3092 } else {
3093 b = sn->b;
3094 n = sn->fs.received + (b->pos - b->start) + (b->end - b->last);
3095 }
3142 3096
3143 frame = ngx_quic_alloc_frame(c, 0); 3097 frame = ngx_quic_alloc_frame(c, 0);
3144 if (frame == NULL) { 3098 if (frame == NULL) {
3145 return NGX_ERROR; 3099 return NGX_ERROR;
3146 } 3100 }
3180 } 3134 }
3181 3135
3182 sn = ngx_quic_find_stream(&qc->streams.tree, f->id); 3136 sn = ngx_quic_find_stream(&qc->streams.tree, f->id);
3183 3137
3184 if (sn == NULL) { 3138 if (sn == NULL) {
3185 ngx_log_error(NGX_LOG_INFO, c->log, 0, 3139 sn = ngx_quic_create_client_stream(c, f->id);
3186 "unknown stream id:0x%xL", f->id); 3140
3187 3141 if (sn == NULL) {
3188 if (f->id & NGX_QUIC_STREAM_SERVER_INITIATED) { 3142 return NGX_ERROR;
3189 qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR; 3143 }
3190 } 3144
3191 3145 if (sn == NGX_QUIC_STREAM_GONE) {
3192 return NGX_ERROR; 3146 return NGX_OK;
3147 }
3148
3149 if (f->limit > sn->send_max_data) {
3150 sn->send_max_data = f->limit;
3151 }
3152
3153 sn->c->listening->handler(sn->c);
3154
3155 return NGX_OK;
3193 } 3156 }
3194 3157
3195 if (f->limit <= sn->send_max_data) { 3158 if (f->limit <= sn->send_max_data) {
3196 return NGX_OK; 3159 return NGX_OK;
3197 } 3160 }
3885 return NULL; 3848 return NULL;
3886 } 3849 }
3887 3850
3888 3851
3889 static ngx_quic_stream_t * 3852 static ngx_quic_stream_t *
3853 ngx_quic_create_client_stream(ngx_connection_t *c, uint64_t id)
3854 {
3855 size_t n;
3856 uint64_t min_id;
3857 ngx_quic_stream_t *sn;
3858 ngx_quic_connection_t *qc;
3859
3860 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
3861 "quic stream id 0x%xL is new", id);
3862
3863 qc = c->quic;
3864
3865 if (id & NGX_QUIC_STREAM_UNIDIRECTIONAL) {
3866
3867 if (id & NGX_QUIC_STREAM_SERVER_INITIATED) {
3868 if ((id >> 2) < qc->streams.server_streams_uni) {
3869 return NGX_QUIC_STREAM_GONE;
3870 }
3871
3872 qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR;
3873 return NULL;
3874 }
3875
3876 if ((id >> 2) < qc->streams.client_streams_uni) {
3877 return NGX_QUIC_STREAM_GONE;
3878 }
3879
3880 if ((id >> 2) >= qc->streams.client_max_streams_uni) {
3881 qc->error = NGX_QUIC_ERR_STREAM_LIMIT_ERROR;
3882 return NULL;
3883 }
3884
3885 min_id = (qc->streams.client_streams_uni << 2)
3886 | NGX_QUIC_STREAM_UNIDIRECTIONAL;
3887 qc->streams.client_streams_uni = (id >> 2) + 1;
3888 n = qc->tp.initial_max_stream_data_uni;
3889
3890 } else {
3891
3892 if (id & NGX_QUIC_STREAM_SERVER_INITIATED) {
3893 if ((id >> 2) < qc->streams.server_streams_bidi) {
3894 return NGX_QUIC_STREAM_GONE;
3895 }
3896
3897 qc->error = NGX_QUIC_ERR_STREAM_STATE_ERROR;
3898 return NULL;
3899 }
3900
3901 if ((id >> 2) < qc->streams.client_streams_bidi) {
3902 return NGX_QUIC_STREAM_GONE;
3903 }
3904
3905 if ((id >> 2) >= qc->streams.client_max_streams_bidi) {
3906 qc->error = NGX_QUIC_ERR_STREAM_LIMIT_ERROR;
3907 return NULL;
3908 }
3909
3910 min_id = (qc->streams.client_streams_bidi << 2);
3911 qc->streams.client_streams_bidi = (id >> 2) + 1;
3912 n = qc->tp.initial_max_stream_data_bidi_remote;
3913 }
3914
3915 if (n < NGX_QUIC_STREAM_BUFSIZE) {
3916 n = NGX_QUIC_STREAM_BUFSIZE;
3917 }
3918
3919 /*
3920 * 2.1. Stream Types and Identifiers
3921 *
3922 * Within each type, streams are created with numerically increasing
3923 * stream IDs. A stream ID that is used out of order results in all
3924 * streams of that type with lower-numbered stream IDs also being
3925 * opened.
3926 */
3927
3928 for ( /* void */ ; min_id < id; min_id += 0x04) {
3929
3930 sn = ngx_quic_create_stream(c, min_id, n);
3931 if (sn == NULL) {
3932 return NULL;
3933 }
3934
3935 sn->c->listening->handler(sn->c);
3936 }
3937
3938 return ngx_quic_create_stream(c, id, n);
3939 }
3940
3941
3942 static ngx_quic_stream_t *
3890 ngx_quic_create_stream(ngx_connection_t *c, uint64_t id, size_t rcvbuf_size) 3943 ngx_quic_create_stream(ngx_connection_t *c, uint64_t id, size_t rcvbuf_size)
3891 { 3944 {
3892 ngx_log_t *log; 3945 ngx_log_t *log;
3893 ngx_pool_t *pool; 3946 ngx_pool_t *pool;
3894 ngx_quic_stream_t *sn; 3947 ngx_quic_stream_t *sn;