Mercurial > hg > nginx
comparison src/event/quic/ngx_event_quic_ssl.c @ 8782:b3f6ad181df4 quic
QUIC: refactored CRYPTO and STREAM buffer ordering.
Generic function ngx_quic_order_bufs() is introduced. This function creates
and maintains a chain of buffers with holes. Holes are marked with b->sync
flag. Several buffers and holes in this chain may share the same underlying
memory buffer.
When processing STREAM frames with this function, frame data is copied only
once to the right place in the stream input chain. Previously data could
be copied twice. First when buffering an out-of-order frame data, and then
when filling stream buffer from ordered frame queue. Now there's only one
data chain for both tasks.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Tue, 25 May 2021 13:55:12 +0300 |
parents | 4117aa7fa38e |
children | 80d396fd8ee8 |
comparison
equal
deleted
inserted
replaced
8781:81d491f0dc8c | 8782:b3f6ad181df4 |
---|---|
31 #endif | 31 #endif |
32 | 32 |
33 static int ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, | 33 static int ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, |
34 enum ssl_encryption_level_t level, const uint8_t *data, size_t len); | 34 enum ssl_encryption_level_t level, const uint8_t *data, size_t len); |
35 static int ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn); | 35 static int ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn); |
36 static ngx_int_t ngx_quic_crypto_input(ngx_connection_t *c, ngx_chain_t *data); | |
36 | 37 |
37 | 38 |
38 static SSL_QUIC_METHOD quic_method = { | 39 static SSL_QUIC_METHOD quic_method = { |
39 #if BORINGSSL_API_VERSION >= 10 | 40 #if BORINGSSL_API_VERSION >= 10 |
40 ngx_quic_set_read_secret, | 41 ngx_quic_set_read_secret, |
147 | 148 |
148 static int | 149 static int |
149 ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, | 150 ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, |
150 enum ssl_encryption_level_t level, const uint8_t *data, size_t len) | 151 enum ssl_encryption_level_t level, const uint8_t *data, size_t len) |
151 { | 152 { |
152 u_char *p, *end; | 153 u_char *p, *end; |
153 size_t client_params_len; | 154 size_t client_params_len; |
154 const uint8_t *client_params; | 155 const uint8_t *client_params; |
155 ngx_quic_tp_t ctp; | 156 ngx_quic_tp_t ctp; |
156 ngx_quic_frame_t *frame; | 157 ngx_quic_frame_t *frame; |
157 ngx_connection_t *c; | 158 ngx_connection_t *c; |
158 ngx_quic_connection_t *qc; | 159 ngx_quic_send_ctx_t *ctx; |
159 ngx_quic_frames_stream_t *fs; | 160 ngx_quic_connection_t *qc; |
160 | 161 |
161 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | 162 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); |
162 qc = ngx_quic_get_connection(c); | 163 qc = ngx_quic_get_connection(c); |
163 | 164 |
164 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | 165 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, |
226 } | 227 } |
227 | 228 |
228 qc->client_tp_done = 1; | 229 qc->client_tp_done = 1; |
229 } | 230 } |
230 | 231 |
231 fs = &qc->crypto[level]; | 232 ctx = ngx_quic_get_send_ctx(qc, level); |
232 | 233 |
233 frame = ngx_quic_alloc_frame(c); | 234 frame = ngx_quic_alloc_frame(c); |
234 if (frame == NULL) { | 235 if (frame == NULL) { |
235 return 0; | 236 return 0; |
236 } | 237 } |
240 return 0; | 241 return 0; |
241 } | 242 } |
242 | 243 |
243 frame->level = level; | 244 frame->level = level; |
244 frame->type = NGX_QUIC_FT_CRYPTO; | 245 frame->type = NGX_QUIC_FT_CRYPTO; |
245 frame->u.crypto.offset = fs->sent; | 246 frame->u.crypto.offset = ctx->crypto_sent; |
246 frame->u.crypto.length = len; | 247 frame->u.crypto.length = len; |
247 | 248 |
248 fs->sent += len; | 249 ctx->crypto_sent += len; |
249 | 250 |
250 ngx_quic_queue_frame(qc, frame); | 251 ngx_quic_queue_frame(qc, frame); |
251 | 252 |
252 return 1; | 253 return 1; |
253 } | 254 } |
270 | 271 |
271 ngx_int_t | 272 ngx_int_t |
272 ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, | 273 ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, |
273 ngx_quic_frame_t *frame) | 274 ngx_quic_frame_t *frame) |
274 { | 275 { |
275 uint64_t last; | 276 size_t len; |
276 ngx_int_t rc; | 277 uint64_t last; |
277 ngx_quic_send_ctx_t *ctx; | 278 ngx_buf_t *b; |
278 ngx_quic_connection_t *qc; | 279 ngx_chain_t *cl, **ll; |
279 ngx_quic_crypto_frame_t *f; | 280 ngx_quic_send_ctx_t *ctx; |
280 ngx_quic_frames_stream_t *fs; | 281 ngx_quic_connection_t *qc; |
281 | 282 ngx_quic_crypto_frame_t *f; |
282 qc = ngx_quic_get_connection(c); | 283 |
283 fs = &qc->crypto[pkt->level]; | 284 qc = ngx_quic_get_connection(c); |
285 ctx = ngx_quic_get_send_ctx(qc, pkt->level); | |
284 f = &frame->u.crypto; | 286 f = &frame->u.crypto; |
285 | 287 |
286 /* no overflow since both values are 62-bit */ | 288 /* no overflow since both values are 62-bit */ |
287 last = f->offset + f->length; | 289 last = f->offset + f->length; |
288 | 290 |
289 if (last > fs->received && last - fs->received > NGX_QUIC_MAX_BUFFERED) { | 291 if (last > ctx->crypto_received + NGX_QUIC_MAX_BUFFERED) { |
290 qc->error = NGX_QUIC_ERR_CRYPTO_BUFFER_EXCEEDED; | 292 qc->error = NGX_QUIC_ERR_CRYPTO_BUFFER_EXCEEDED; |
291 return NGX_ERROR; | 293 return NGX_ERROR; |
292 } | 294 } |
293 | 295 |
294 rc = ngx_quic_handle_ordered_frame(c, fs, frame, ngx_quic_crypto_input, | 296 if (last <= ctx->crypto_received) { |
295 NULL); | 297 if (pkt->level == ssl_encryption_initial) { |
296 if (rc != NGX_DECLINED) { | 298 /* speeding up handshake completion */ |
297 return rc; | 299 |
298 } | 300 if (!ngx_queue_empty(&ctx->sent)) { |
299 | |
300 /* speeding up handshake completion */ | |
301 | |
302 if (pkt->level == ssl_encryption_initial) { | |
303 ctx = ngx_quic_get_send_ctx(qc, pkt->level); | |
304 | |
305 if (!ngx_queue_empty(&ctx->sent)) { | |
306 ngx_quic_resend_frames(c, ctx); | |
307 | |
308 ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_handshake); | |
309 while (!ngx_queue_empty(&ctx->sent)) { | |
310 ngx_quic_resend_frames(c, ctx); | 301 ngx_quic_resend_frames(c, ctx); |
302 | |
303 ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_handshake); | |
304 while (!ngx_queue_empty(&ctx->sent)) { | |
305 ngx_quic_resend_frames(c, ctx); | |
306 } | |
311 } | 307 } |
312 } | 308 } |
309 | |
310 return NGX_OK; | |
311 } | |
312 | |
313 if (f->offset > ctx->crypto_received) { | |
314 return ngx_quic_order_bufs(c, &ctx->crypto, frame->data, | |
315 f->offset - ctx->crypto_received); | |
316 } | |
317 | |
318 ngx_quic_trim_bufs(frame->data, ctx->crypto_received - f->offset); | |
319 | |
320 if (ngx_quic_crypto_input(c, frame->data) != NGX_OK) { | |
321 return NGX_ERROR; | |
322 } | |
323 | |
324 ngx_quic_trim_bufs(ctx->crypto, last - ctx->crypto_received); | |
325 ctx->crypto_received = last; | |
326 | |
327 cl = ctx->crypto; | |
328 ll = &cl; | |
329 len = 0; | |
330 | |
331 while (*ll) { | |
332 b = (*ll)->buf; | |
333 | |
334 if (b->sync && b->pos != b->last) { | |
335 /* hole */ | |
336 break; | |
337 } | |
338 | |
339 len += b->last - b->pos; | |
340 ll = &(*ll)->next; | |
341 } | |
342 | |
343 ctx->crypto_received += len; | |
344 ctx->crypto = *ll; | |
345 *ll = NULL; | |
346 | |
347 if (cl) { | |
348 if (ngx_quic_crypto_input(c, cl) != NGX_OK) { | |
349 return NGX_ERROR; | |
350 } | |
351 | |
352 ngx_quic_free_bufs(c, cl); | |
313 } | 353 } |
314 | 354 |
315 return NGX_OK; | 355 return NGX_OK; |
316 } | 356 } |
317 | 357 |
318 | 358 |
319 ngx_int_t | 359 static ngx_int_t |
320 ngx_quic_crypto_input(ngx_connection_t *c, ngx_quic_frame_t *frame, void *data) | 360 ngx_quic_crypto_input(ngx_connection_t *c, ngx_chain_t *data) |
321 { | 361 { |
322 int n, sslerr; | 362 int n, sslerr; |
323 ngx_buf_t *b; | 363 ngx_buf_t *b; |
324 ngx_chain_t *cl; | 364 ngx_chain_t *cl; |
325 ngx_ssl_conn_t *ssl_conn; | 365 ngx_ssl_conn_t *ssl_conn; |
366 ngx_quic_frame_t *frame; | |
326 ngx_quic_connection_t *qc; | 367 ngx_quic_connection_t *qc; |
327 | 368 |
328 qc = ngx_quic_get_connection(c); | 369 qc = ngx_quic_get_connection(c); |
329 | 370 |
330 ssl_conn = c->ssl->connection; | 371 ssl_conn = c->ssl->connection; |
332 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | 373 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, |
333 "quic SSL_quic_read_level:%d SSL_quic_write_level:%d", | 374 "quic SSL_quic_read_level:%d SSL_quic_write_level:%d", |
334 (int) SSL_quic_read_level(ssl_conn), | 375 (int) SSL_quic_read_level(ssl_conn), |
335 (int) SSL_quic_write_level(ssl_conn)); | 376 (int) SSL_quic_write_level(ssl_conn)); |
336 | 377 |
337 for (cl = frame->data; cl; cl = cl->next) { | 378 for (cl = data; cl; cl = cl->next) { |
338 b = cl->buf; | 379 b = cl->buf; |
339 | 380 |
340 if (!SSL_provide_quic_data(ssl_conn, SSL_quic_read_level(ssl_conn), | 381 if (!SSL_provide_quic_data(ssl_conn, SSL_quic_read_level(ssl_conn), |
341 b->pos, b->last - b->pos)) | 382 b->pos, b->last - b->pos)) |
342 { | 383 { |