comparison src/event/ngx_event_quic.c @ 8345:6481427ca3fc quic

Respecting maximum packet size. The header size macros for long and short packets were fixed to provide correct values in bytes. Currently the sending code limits frames so they don't exceed max_packet_size. But it does not account the case when a single frame can exceed the limit. As a result of this patch, big payload (CRYPTO and STREAM) will be split into a number of smaller frames that fit into advertised max_packet_size (which specifies final packet size, after encryption).
author Vladimir Homutov <vl@nginx.com>
date Mon, 20 Apr 2020 22:25:22 +0300
parents e0abe17a2878
children 4e4485793418
comparison
equal deleted inserted replaced
8344:e0abe17a2878 8345:6481427ca3fc
318 static int 318 static int
319 ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, 319 ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn,
320 enum ssl_encryption_level_t level, const uint8_t *data, size_t len) 320 enum ssl_encryption_level_t level, const uint8_t *data, size_t len)
321 { 321 {
322 u_char *p, *end; 322 u_char *p, *end;
323 size_t client_params_len; 323 size_t client_params_len, fsize, limit;
324 const uint8_t *client_params; 324 const uint8_t *client_params;
325 ngx_quic_frame_t *frame; 325 ngx_quic_frame_t *frame;
326 ngx_connection_t *c; 326 ngx_connection_t *c;
327 ngx_quic_connection_t *qc; 327 ngx_quic_connection_t *qc;
328 ngx_quic_frames_stream_t *fs; 328 ngx_quic_frames_stream_t *fs;
357 && qc->ctp.max_idle_timeout < qc->tp.max_idle_timeout) 357 && qc->ctp.max_idle_timeout < qc->tp.max_idle_timeout)
358 { 358 {
359 qc->tp.max_idle_timeout = qc->ctp.max_idle_timeout; 359 qc->tp.max_idle_timeout = qc->ctp.max_idle_timeout;
360 } 360 }
361 361
362 if (qc->ctp.max_packet_size < NGX_QUIC_MIN_INITIAL_SIZE
363 || qc->ctp.max_packet_size > NGX_QUIC_DEFAULT_MAX_PACKET_SIZE)
364 {
365 ngx_log_error(NGX_LOG_INFO, c->log, 0,
366 "maximum packet size is invalid");
367 return NGX_ERROR;
368 }
369
362 qc->client_tp_done = 1; 370 qc->client_tp_done = 1;
363 } 371 }
364 } 372 }
365 373
374 /*
375 * we need to fit at least 1 frame into a packet, thus account head/tail;
376 * 17 = 1 + 8x2 is max header for CRYPTO frame, with 1 byte for frame type
377 */
378 limit = qc->ctp.max_packet_size - NGX_QUIC_MAX_LONG_HEADER - 17
379 - EVP_GCM_TLS_TAG_LEN;
380
366 fs = &qc->crypto[level]; 381 fs = &qc->crypto[level];
367 382
368 frame = ngx_quic_alloc_frame(c, len); 383 p = (u_char *) data;
369 if (frame == NULL) { 384 end = (u_char *) data + len;
370 return 0; 385
371 } 386 while (p < end) {
372 387
373 ngx_memcpy(frame->data, data, len); 388 fsize = ngx_min(limit, (size_t) (end - p));
374 389
375 frame->level = level; 390 frame = ngx_quic_alloc_frame(c, fsize);
376 frame->type = NGX_QUIC_FT_CRYPTO; 391 if (frame == NULL) {
377 frame->u.crypto.offset += fs->sent; 392 return 0;
378 frame->u.crypto.length = len; 393 }
379 frame->u.crypto.data = frame->data; 394
380 395 ngx_memcpy(frame->data, p, fsize);
381 fs->sent += len; 396
382 397 frame->level = level;
383 ngx_sprintf(frame->info, "crypto, generated by SSL len=%ui level=%d", len, level); 398 frame->type = NGX_QUIC_FT_CRYPTO;
384 399 frame->u.crypto.offset = fs->sent;
385 ngx_quic_queue_frame(qc, frame); 400 frame->u.crypto.length = fsize;
401 frame->u.crypto.data = frame->data;
402
403 fs->sent += fsize;
404 p += fsize;
405
406 ngx_sprintf(frame->info, "crypto, generated by SSL len=%ui level=%d",
407 fsize, level);
408
409 ngx_quic_queue_frame(qc, frame);
410 }
386 411
387 return 1; 412 return 1;
388 } 413 }
389 414
390 415
476 ngx_quic_secrets_t *keys; 501 ngx_quic_secrets_t *keys;
477 ngx_quic_send_ctx_t *ctx; 502 ngx_quic_send_ctx_t *ctx;
478 ngx_quic_connection_t *qc; 503 ngx_quic_connection_t *qc;
479 static u_char buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE]; 504 static u_char buf[NGX_QUIC_DEFAULT_MAX_PACKET_SIZE];
480 505
481 if (ngx_buf_size(pkt->raw) < 1200) { 506 if (ngx_buf_size(pkt->raw) < NGX_QUIC_MIN_INITIAL_SIZE) {
482 ngx_log_error(NGX_LOG_INFO, c->log, 0, "too small UDP datagram"); 507 ngx_log_error(NGX_LOG_INFO, c->log, 0, "too small UDP datagram");
483 return NGX_ERROR; 508 return NGX_ERROR;
484 } 509 }
485 510
486 if (ngx_quic_parse_long_header(pkt) != NGX_OK) { 511 if (ngx_quic_parse_long_header(pkt) != NGX_OK) {
2669 2694
2670 2695
2671 static ssize_t 2696 static ssize_t
2672 ngx_quic_stream_send(ngx_connection_t *c, u_char *buf, size_t size) 2697 ngx_quic_stream_send(ngx_connection_t *c, u_char *buf, size_t size)
2673 { 2698 {
2699 u_char *p, *end;
2700 size_t fsize, limit;
2674 ngx_connection_t *pc; 2701 ngx_connection_t *pc;
2675 ngx_quic_frame_t *frame; 2702 ngx_quic_frame_t *frame;
2676 ngx_quic_stream_t *qs; 2703 ngx_quic_stream_t *qs;
2677 ngx_quic_connection_t *qc; 2704 ngx_quic_connection_t *qc;
2678 2705
2684 return NGX_ERROR; 2711 return NGX_ERROR;
2685 } 2712 }
2686 2713
2687 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic send: %uz", size); 2714 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic send: %uz", size);
2688 2715
2689 frame = ngx_quic_alloc_frame(pc, size); 2716 /*
2690 if (frame == NULL) { 2717 * we need to fit at least 1 frame into a packet, thus account head/tail;
2691 return 0; 2718 * 25 = 1 + 8x3 is max header for STREAM frame, with 1 byte for frame type
2692 } 2719 */
2693 2720 limit = qc->ctp.max_packet_size - NGX_QUIC_MAX_SHORT_HEADER - 25
2694 ngx_memcpy(frame->data, buf, size); 2721 - EVP_GCM_TLS_TAG_LEN;
2695 2722
2696 frame->level = ssl_encryption_application; 2723 p = (u_char *) buf;
2697 frame->type = NGX_QUIC_FT_STREAM6; /* OFF=1 LEN=1 FIN=0 */ 2724 end = (u_char *) buf + size;
2698 frame->u.stream.off = 1; 2725
2699 frame->u.stream.len = 1; 2726 while (p < end) {
2700 frame->u.stream.fin = 0; 2727
2701 2728 fsize = ngx_min(limit, (size_t) (end - p));
2702 frame->u.stream.type = frame->type; 2729
2703 frame->u.stream.stream_id = qs->id; 2730 frame = ngx_quic_alloc_frame(pc, fsize);
2704 frame->u.stream.offset = c->sent; 2731 if (frame == NULL) {
2705 frame->u.stream.length = size; 2732 return 0;
2706 frame->u.stream.data = frame->data; 2733 }
2707 2734
2708 c->sent += size; 2735 ngx_memcpy(frame->data, p, fsize);
2709 2736
2710 ngx_sprintf(frame->info, "stream %xi len=%ui level=%d", 2737 frame->level = ssl_encryption_application;
2711 qs->id, size, frame->level); 2738 frame->type = NGX_QUIC_FT_STREAM6; /* OFF=1 LEN=1 FIN=0 */
2712 2739 frame->u.stream.off = 1;
2713 ngx_quic_queue_frame(qc, frame); 2740 frame->u.stream.len = 1;
2741 frame->u.stream.fin = 0;
2742
2743 frame->u.stream.type = frame->type;
2744 frame->u.stream.stream_id = qs->id;
2745 frame->u.stream.offset = c->sent;
2746 frame->u.stream.length = fsize;
2747 frame->u.stream.data = frame->data;
2748
2749 c->sent += fsize;
2750 p += fsize;
2751
2752 ngx_sprintf(frame->info, "stream %xi len=%ui level=%d",
2753 qs->id, fsize, frame->level);
2754
2755 ngx_quic_queue_frame(qc, frame);
2756 }
2714 2757
2715 return size; 2758 return size;
2716 } 2759 }
2717 2760
2718 2761