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 {