Mercurial > hg > nginx
comparison src/event/ngx_event_quic.c @ 8658:0af4ec6d1f92 quic
QUIC: coalesce output packets into a single UDP datagram.
Now initial output packet is not padded anymore if followed by a handshake
packet. If the datagram is still not big enough to satisfy minimum size
requirements, handshake packet is padded.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Mon, 07 Dec 2020 15:09:08 +0000 |
parents | 2dfc5ef29973 |
children | d9f673d18e9b |
comparison
equal
deleted
inserted
replaced
8657:2dfc5ef29973 | 8658:0af4ec6d1f92 |
---|---|
152 | 152 |
153 ngx_uint_t pto_count; | 153 ngx_uint_t pto_count; |
154 | 154 |
155 ngx_queue_t free_frames; | 155 ngx_queue_t free_frames; |
156 ngx_chain_t *free_bufs; | 156 ngx_chain_t *free_bufs; |
157 ngx_buf_t *free_shadow_bufs; | |
157 | 158 |
158 #ifdef NGX_QUIC_DEBUG_ALLOC | 159 #ifdef NGX_QUIC_DEBUG_ALLOC |
159 ngx_uint_t nframes; | 160 ngx_uint_t nframes; |
160 ngx_uint_t nbufs; | 161 ngx_uint_t nbufs; |
161 #endif | 162 #endif |
162 | 163 |
163 ngx_quic_streams_t streams; | 164 ngx_quic_streams_t streams; |
164 ngx_quic_congestion_t congestion; | 165 ngx_quic_congestion_t congestion; |
165 size_t received; | 166 off_t received; |
166 | 167 |
167 ngx_uint_t error; | 168 ngx_uint_t error; |
168 enum ssl_encryption_level_t error_level; | 169 enum ssl_encryption_level_t error_level; |
169 ngx_uint_t error_ftype; | 170 ngx_uint_t error_ftype; |
170 const char *error_reason; | 171 const char *error_reason; |
329 | 330 |
330 static void ngx_quic_queue_frame(ngx_quic_connection_t *qc, | 331 static void ngx_quic_queue_frame(ngx_quic_connection_t *qc, |
331 ngx_quic_frame_t *frame); | 332 ngx_quic_frame_t *frame); |
332 | 333 |
333 static ngx_int_t ngx_quic_output(ngx_connection_t *c); | 334 static ngx_int_t ngx_quic_output(ngx_connection_t *c); |
334 static ngx_int_t ngx_quic_output_frames(ngx_connection_t *c, | 335 static ngx_uint_t ngx_quic_get_padding_level(ngx_connection_t *c); |
336 static ngx_int_t ngx_quic_generate_ack(ngx_connection_t *c, | |
335 ngx_quic_send_ctx_t *ctx); | 337 ngx_quic_send_ctx_t *ctx); |
338 static ssize_t ngx_quic_output_packet(ngx_connection_t *c, | |
339 ngx_quic_send_ctx_t *ctx, u_char *data, size_t max, size_t min); | |
340 static ngx_int_t ngx_quic_split_frame(ngx_connection_t *c, ngx_quic_frame_t *f, | |
341 size_t len); | |
336 static void ngx_quic_free_frames(ngx_connection_t *c, ngx_queue_t *frames); | 342 static void ngx_quic_free_frames(ngx_connection_t *c, ngx_queue_t *frames); |
337 static ngx_int_t ngx_quic_send_frames(ngx_connection_t *c, | |
338 ngx_quic_send_ctx_t *ctx, ngx_queue_t *frames); | |
339 static ssize_t ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len); | 343 static ssize_t ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len); |
340 | 344 |
341 static void ngx_quic_set_packet_number(ngx_quic_header_t *pkt, | 345 static void ngx_quic_set_packet_number(ngx_quic_header_t *pkt, |
342 ngx_quic_send_ctx_t *ctx); | 346 ngx_quic_send_ctx_t *ctx); |
343 static void ngx_quic_pto_handler(ngx_event_t *ev); | 347 static void ngx_quic_pto_handler(ngx_event_t *ev); |
359 size_t size); | 363 size_t size); |
360 static ssize_t ngx_quic_stream_send(ngx_connection_t *c, u_char *buf, | 364 static ssize_t ngx_quic_stream_send(ngx_connection_t *c, u_char *buf, |
361 size_t size); | 365 size_t size); |
362 static ngx_chain_t *ngx_quic_stream_send_chain(ngx_connection_t *c, | 366 static ngx_chain_t *ngx_quic_stream_send_chain(ngx_connection_t *c, |
363 ngx_chain_t *in, off_t limit); | 367 ngx_chain_t *in, off_t limit); |
364 static size_t ngx_quic_max_stream_frame(ngx_quic_connection_t *qc); | |
365 static size_t ngx_quic_max_stream_flow(ngx_connection_t *c); | 368 static size_t ngx_quic_max_stream_flow(ngx_connection_t *c); |
366 static void ngx_quic_stream_cleanup_handler(void *data); | 369 static void ngx_quic_stream_cleanup_handler(void *data); |
367 static ngx_quic_frame_t *ngx_quic_alloc_frame(ngx_connection_t *c); | 370 static ngx_quic_frame_t *ngx_quic_alloc_frame(ngx_connection_t *c); |
368 static void ngx_quic_free_frame(ngx_connection_t *c, ngx_quic_frame_t *frame); | 371 static void ngx_quic_free_frame(ngx_connection_t *c, ngx_quic_frame_t *frame); |
369 | 372 |
376 static void ngx_quic_free_bufs(ngx_connection_t *c, ngx_chain_t *in); | 379 static void ngx_quic_free_bufs(ngx_connection_t *c, ngx_chain_t *in); |
377 static ngx_chain_t *ngx_quic_copy_buf(ngx_connection_t *c, u_char *data, | 380 static ngx_chain_t *ngx_quic_copy_buf(ngx_connection_t *c, u_char *data, |
378 size_t len); | 381 size_t len); |
379 static ngx_chain_t *ngx_quic_copy_chain(ngx_connection_t *c, ngx_chain_t *in, | 382 static ngx_chain_t *ngx_quic_copy_chain(ngx_connection_t *c, ngx_chain_t *in, |
380 size_t limit); | 383 size_t limit); |
384 static ngx_chain_t *ngx_quic_split_bufs(ngx_connection_t *c, ngx_chain_t *in, | |
385 size_t len); | |
381 | 386 |
382 | 387 |
383 static SSL_QUIC_METHOD quic_method = { | 388 static SSL_QUIC_METHOD quic_method = { |
384 #if BORINGSSL_API_VERSION >= 10 | 389 #if BORINGSSL_API_VERSION >= 10 |
385 ngx_quic_set_read_secret, | 390 ngx_quic_set_read_secret, |
783 static int | 788 static int |
784 ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, | 789 ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, |
785 enum ssl_encryption_level_t level, const uint8_t *data, size_t len) | 790 enum ssl_encryption_level_t level, const uint8_t *data, size_t len) |
786 { | 791 { |
787 u_char *p, *end; | 792 u_char *p, *end; |
788 size_t client_params_len, fsize, limit; | 793 size_t client_params_len; |
789 const uint8_t *client_params; | 794 const uint8_t *client_params; |
790 ngx_quic_frame_t *frame; | 795 ngx_quic_frame_t *frame; |
791 ngx_connection_t *c; | 796 ngx_connection_t *c; |
792 ngx_quic_connection_t *qc; | 797 ngx_quic_connection_t *qc; |
793 ngx_quic_frames_stream_t *fs; | 798 ngx_quic_frames_stream_t *fs; |
891 qc->streams.server_max_streams_uni = qc->ctp.initial_max_streams_uni; | 896 qc->streams.server_max_streams_uni = qc->ctp.initial_max_streams_uni; |
892 | 897 |
893 qc->client_tp_done = 1; | 898 qc->client_tp_done = 1; |
894 } | 899 } |
895 | 900 |
896 /* | |
897 * we need to fit at least 1 frame into a packet, thus account head/tail; | |
898 * 17 = 1 + 8x2 is max header for CRYPTO frame, with 1 byte for frame type | |
899 */ | |
900 limit = qc->ctp.max_udp_payload_size - NGX_QUIC_MAX_LONG_HEADER - 17 | |
901 - EVP_GCM_TLS_TAG_LEN; | |
902 | |
903 fs = &qc->crypto[level]; | 901 fs = &qc->crypto[level]; |
904 | 902 |
905 p = (u_char *) data; | 903 frame = ngx_quic_alloc_frame(c); |
906 end = (u_char *) data + len; | 904 if (frame == NULL) { |
907 | 905 return 0; |
908 while (p < end) { | 906 } |
909 | 907 |
910 fsize = ngx_min(limit, (size_t) (end - p)); | 908 frame->data = ngx_quic_copy_buf(c, (u_char *) data, len); |
911 | 909 if (frame->data == NGX_CHAIN_ERROR) { |
912 frame = ngx_quic_alloc_frame(c); | 910 return 0; |
913 if (frame == NULL) { | 911 } |
914 return 0; | 912 |
915 } | 913 frame->level = level; |
916 | 914 frame->type = NGX_QUIC_FT_CRYPTO; |
917 frame->data = ngx_quic_copy_buf(c, p, fsize); | 915 frame->u.crypto.offset = fs->sent; |
918 if (frame->data == NGX_CHAIN_ERROR) { | 916 frame->u.crypto.length = len; |
919 return 0; | 917 |
920 } | 918 fs->sent += len; |
921 | 919 |
922 frame->level = level; | 920 ngx_quic_queue_frame(qc, frame); |
923 frame->type = NGX_QUIC_FT_CRYPTO; | |
924 frame->u.crypto.offset = fs->sent; | |
925 frame->u.crypto.length = fsize; | |
926 | |
927 fs->sent += fsize; | |
928 p += fsize; | |
929 | |
930 ngx_quic_queue_frame(qc, frame); | |
931 } | |
932 | 921 |
933 return 1; | 922 return 1; |
934 } | 923 } |
935 | 924 |
936 | 925 |
4699 | 4688 |
4700 | 4689 |
4701 static ngx_int_t | 4690 static ngx_int_t |
4702 ngx_quic_output(ngx_connection_t *c) | 4691 ngx_quic_output(ngx_connection_t *c) |
4703 { | 4692 { |
4704 ngx_uint_t i; | 4693 off_t max; |
4705 ngx_msec_t delay; | 4694 size_t len, min; |
4695 ssize_t n; | |
4696 u_char *p; | |
4697 ngx_uint_t i, pad; | |
4706 ngx_quic_send_ctx_t *ctx; | 4698 ngx_quic_send_ctx_t *ctx; |
4707 ngx_quic_connection_t *qc; | 4699 ngx_quic_connection_t *qc; |
4700 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | |
4708 | 4701 |
4709 c->log->action = "sending frames"; | 4702 c->log->action = "sending frames"; |
4710 | 4703 |
4711 qc = ngx_quic_get_connection(c); | 4704 qc = ngx_quic_get_connection(c); |
4712 | 4705 |
4713 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { | 4706 for ( ;; ) { |
4714 | 4707 p = dst; |
4715 ctx = &qc->send_ctx[i]; | 4708 |
4716 | 4709 len = ngx_min(qc->ctp.max_udp_payload_size, |
4717 if (ctx->send_ack) { | 4710 NGX_QUIC_MAX_UDP_PAYLOAD_SIZE); |
4718 | 4711 |
4719 if (ctx->level == ssl_encryption_application) { | 4712 if (!qc->validated) { |
4720 | 4713 max = qc->received * 3; |
4721 delay = ngx_current_msec - ctx->ack_delay_start; | 4714 max = (c->sent >= max) ? 0 : max - c->sent; |
4722 | 4715 len = ngx_min(len, (size_t) max); |
4723 if (ctx->send_ack < NGX_QUIC_MAX_ACK_GAP | 4716 } |
4724 && delay < qc->tp.max_ack_delay) | 4717 |
4725 { | 4718 pad = ngx_quic_get_padding_level(c); |
4726 if (!qc->push.timer_set && !qc->closing) { | 4719 |
4727 ngx_add_timer(&qc->push, qc->tp.max_ack_delay - delay); | 4720 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { |
4728 } | 4721 |
4729 | 4722 ctx = &qc->send_ctx[i]; |
4730 goto output; | 4723 |
4731 } | 4724 if (ngx_quic_generate_ack(c, ctx) != NGX_OK) { |
4732 } | |
4733 | |
4734 if (ngx_quic_send_ack(c, ctx) != NGX_OK) { | |
4735 return NGX_ERROR; | 4725 return NGX_ERROR; |
4736 } | 4726 } |
4737 ctx->send_ack = 0; | 4727 |
4738 } | 4728 min = (i == pad && p - dst < NGX_QUIC_MIN_INITIAL_SIZE) |
4739 | 4729 ? NGX_QUIC_MIN_INITIAL_SIZE - (p - dst) : 0; |
4740 output: | 4730 |
4741 | 4731 n = ngx_quic_output_packet(c, ctx, p, len, min); |
4742 if (ngx_quic_output_frames(c, ctx) != NGX_OK) { | 4732 if (n == NGX_ERROR) { |
4733 return NGX_ERROR; | |
4734 } | |
4735 | |
4736 p += n; | |
4737 len -= n; | |
4738 } | |
4739 | |
4740 len = p - dst; | |
4741 if (len == 0) { | |
4742 break; | |
4743 } | |
4744 | |
4745 n = ngx_quic_send(c, dst, len); | |
4746 if (n == NGX_ERROR) { | |
4743 return NGX_ERROR; | 4747 return NGX_ERROR; |
4744 } | 4748 } |
4745 } | 4749 |
4746 | 4750 if (!qc->send_timer_set && !qc->closing) { |
4747 if (!qc->send_timer_set && !qc->closing) { | 4751 qc->send_timer_set = 1; |
4748 qc->send_timer_set = 1; | 4752 ngx_add_timer(c->read, qc->tp.max_idle_timeout); |
4749 ngx_add_timer(c->read, qc->tp.max_idle_timeout); | 4753 } |
4750 } | 4754 } |
4751 | 4755 |
4752 return NGX_OK; | 4756 return NGX_OK; |
4753 } | 4757 } |
4754 | 4758 |
4755 | 4759 |
4756 static ngx_int_t | 4760 static ngx_uint_t |
4757 ngx_quic_output_frames(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) | 4761 ngx_quic_get_padding_level(ngx_connection_t *c) |
4758 { | 4762 { |
4759 size_t len, hlen, cutoff; | 4763 ngx_queue_t *q; |
4760 ngx_uint_t need_ack; | |
4761 ngx_queue_t *q, range; | |
4762 ngx_quic_frame_t *f; | 4764 ngx_quic_frame_t *f; |
4763 ngx_quic_congestion_t *cg; | 4765 ngx_quic_send_ctx_t *ctx; |
4764 ngx_quic_connection_t *qc; | 4766 ngx_quic_connection_t *qc; |
4765 | 4767 |
4768 /* | |
4769 * 14.1. Initial Datagram Size | |
4770 * | |
4771 * Similarly, a server MUST expand the payload of all UDP datagrams | |
4772 * carrying ack-eliciting Initial packets to at least the smallest | |
4773 * allowed maximum datagram size of 1200 bytes | |
4774 */ | |
4775 | |
4766 qc = ngx_quic_get_connection(c); | 4776 qc = ngx_quic_get_connection(c); |
4767 cg = &qc->congestion; | 4777 ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_initial); |
4768 | 4778 |
4769 if (ngx_queue_empty(&ctx->frames)) { | 4779 for (q = ngx_queue_head(&ctx->frames); |
4770 return NGX_OK; | 4780 q != ngx_queue_sentinel(&ctx->frames); |
4771 } | |
4772 | |
4773 q = ngx_queue_head(&ctx->frames); | |
4774 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
4775 | |
4776 /* all frames in same send_ctx share same level */ | |
4777 hlen = (f->level == ssl_encryption_application) ? NGX_QUIC_MAX_SHORT_HEADER | |
4778 : NGX_QUIC_MAX_LONG_HEADER; | |
4779 hlen += EVP_GCM_TLS_TAG_LEN; | |
4780 hlen -= NGX_QUIC_MAX_CID_LEN - qc->scid.len; | |
4781 | |
4782 do { | |
4783 len = 0; | |
4784 need_ack = 0; | |
4785 ngx_queue_init(&range); | |
4786 | |
4787 do { | |
4788 /* process group of frames that fits into packet */ | |
4789 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
4790 | |
4791 if (len && hlen + len + f->len > qc->ctp.max_udp_payload_size) { | |
4792 break; | |
4793 } | |
4794 | |
4795 if (f->need_ack) { | |
4796 need_ack = 1; | |
4797 } | |
4798 | |
4799 if (need_ack && cg->in_flight + len + f->len > cg->window) { | |
4800 break; | |
4801 } | |
4802 | |
4803 if (!qc->validated) { | |
4804 /* | |
4805 * Prior to validation, endpoints are limited in what they | |
4806 * are able to send. During the handshake, a server cannot | |
4807 * send more than three times the data it receives; | |
4808 */ | |
4809 | |
4810 if (f->level == ssl_encryption_initial) { | |
4811 cutoff = (c->sent + NGX_QUIC_MIN_INITIAL_SIZE) / 3; | |
4812 | |
4813 } else { | |
4814 cutoff = (c->sent + hlen + len + f->len) / 3; | |
4815 } | |
4816 | |
4817 if (cutoff > qc->received) { | |
4818 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
4819 "quic hit amplification limit" | |
4820 " received:%uz sent:%O", | |
4821 qc->received, c->sent); | |
4822 break; | |
4823 } | |
4824 } | |
4825 | |
4826 q = ngx_queue_next(q); | |
4827 | |
4828 f->first = ngx_current_msec; | |
4829 | |
4830 ngx_queue_remove(&f->queue); | |
4831 ngx_queue_insert_tail(&range, &f->queue); | |
4832 | |
4833 len += f->len; | |
4834 | |
4835 } while (q != ngx_queue_sentinel(&ctx->frames)); | |
4836 | |
4837 if (ngx_queue_empty(&range)) { | |
4838 break; | |
4839 } | |
4840 | |
4841 if (ngx_quic_send_frames(c, ctx, &range) != NGX_OK) { | |
4842 return NGX_ERROR; | |
4843 } | |
4844 | |
4845 } while (q != ngx_queue_sentinel(&ctx->frames)); | |
4846 | |
4847 return NGX_OK; | |
4848 } | |
4849 | |
4850 | |
4851 static void | |
4852 ngx_quic_free_frames(ngx_connection_t *c, ngx_queue_t *frames) | |
4853 { | |
4854 ngx_queue_t *q; | |
4855 ngx_quic_frame_t *f; | |
4856 | |
4857 do { | |
4858 q = ngx_queue_head(frames); | |
4859 | |
4860 if (q == ngx_queue_sentinel(frames)) { | |
4861 break; | |
4862 } | |
4863 | |
4864 ngx_queue_remove(q); | |
4865 | |
4866 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
4867 | |
4868 ngx_quic_free_frame(c, f); | |
4869 } while (1); | |
4870 } | |
4871 | |
4872 | |
4873 static ngx_int_t | |
4874 ngx_quic_send_frames(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, | |
4875 ngx_queue_t *frames) | |
4876 { | |
4877 u_char *p; | |
4878 size_t pad_len; | |
4879 ssize_t len; | |
4880 ngx_str_t out, res; | |
4881 ngx_msec_t now; | |
4882 ngx_queue_t *q; | |
4883 ngx_quic_frame_t *f, *start; | |
4884 ngx_quic_header_t pkt; | |
4885 ngx_quic_connection_t *qc; | |
4886 static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | |
4887 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | |
4888 | |
4889 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
4890 "quic ngx_quic_send_frames"); | |
4891 | |
4892 q = ngx_queue_head(frames); | |
4893 start = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
4894 | |
4895 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); | |
4896 | |
4897 now = ngx_current_msec; | |
4898 | |
4899 p = src; | |
4900 out.data = src; | |
4901 | |
4902 for (q = ngx_queue_head(frames); | |
4903 q != ngx_queue_sentinel(frames); | |
4904 q = ngx_queue_next(q)) | 4781 q = ngx_queue_next(q)) |
4905 { | 4782 { |
4906 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | 4783 f = ngx_queue_data(q, ngx_quic_frame_t, queue); |
4907 | 4784 |
4908 ngx_quic_log_frame(c->log, f, 1); | 4785 if (f->need_ack) { |
4909 | 4786 ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_handshake); |
4910 len = ngx_quic_create_frame(p, f); | 4787 |
4911 if (len == -1) { | 4788 if (ngx_queue_empty(&ctx->frames)) { |
4912 ngx_quic_free_frames(c, frames); | 4789 return 0; |
4913 return NGX_ERROR; | 4790 } |
4791 | |
4792 return 1; | |
4793 } | |
4794 } | |
4795 | |
4796 return NGX_QUIC_SEND_CTX_LAST; | |
4797 } | |
4798 | |
4799 | |
4800 static ngx_int_t | |
4801 ngx_quic_generate_ack(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) | |
4802 { | |
4803 ngx_msec_t delay; | |
4804 ngx_quic_connection_t *qc; | |
4805 | |
4806 if (!ctx->send_ack) { | |
4807 return NGX_OK; | |
4808 } | |
4809 | |
4810 if (ctx->level == ssl_encryption_application) { | |
4811 | |
4812 delay = ngx_current_msec - ctx->ack_delay_start; | |
4813 qc = ngx_quic_get_connection(c); | |
4814 | |
4815 if (ctx->send_ack < NGX_QUIC_MAX_ACK_GAP | |
4816 && delay < qc->tp.max_ack_delay) | |
4817 { | |
4818 if (!qc->push.timer_set && !qc->closing) { | |
4819 ngx_add_timer(&qc->push, | |
4820 qc->tp.max_ack_delay - delay); | |
4821 } | |
4822 | |
4823 return NGX_OK; | |
4824 } | |
4825 } | |
4826 | |
4827 if (ngx_quic_send_ack(c, ctx) != NGX_OK) { | |
4828 return NGX_ERROR; | |
4829 } | |
4830 | |
4831 ctx->send_ack = 0; | |
4832 | |
4833 return NGX_OK; | |
4834 } | |
4835 | |
4836 | |
4837 static ssize_t | |
4838 ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, | |
4839 u_char *data, size_t max, size_t min) | |
4840 { | |
4841 size_t len, hlen, pad_len; | |
4842 u_char *p; | |
4843 ssize_t flen; | |
4844 ngx_str_t out, res; | |
4845 ngx_int_t rc; | |
4846 ngx_uint_t nframes; | |
4847 ngx_msec_t now; | |
4848 ngx_queue_t *q; | |
4849 ngx_quic_frame_t *f; | |
4850 ngx_quic_header_t pkt; | |
4851 ngx_quic_congestion_t *cg; | |
4852 ngx_quic_connection_t *qc; | |
4853 static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | |
4854 | |
4855 if (ngx_queue_empty(&ctx->frames)) { | |
4856 return 0; | |
4857 } | |
4858 | |
4859 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
4860 "quic output %s packet max:%uz min:%uz", | |
4861 ngx_quic_level_name(ctx->level), max, min); | |
4862 | |
4863 qc = ngx_quic_get_connection(c); | |
4864 cg = &qc->congestion; | |
4865 | |
4866 hlen = (ctx->level == ssl_encryption_application) | |
4867 ? NGX_QUIC_MAX_SHORT_HEADER | |
4868 : NGX_QUIC_MAX_LONG_HEADER; | |
4869 | |
4870 hlen += EVP_GCM_TLS_TAG_LEN; | |
4871 hlen -= NGX_QUIC_MAX_CID_LEN - qc->scid.len; | |
4872 | |
4873 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); | |
4874 | |
4875 now = ngx_current_msec; | |
4876 nframes = 0; | |
4877 p = src; | |
4878 len = 0; | |
4879 | |
4880 for (q = ngx_queue_head(&ctx->frames); | |
4881 q != ngx_queue_sentinel(&ctx->frames); | |
4882 q = ngx_queue_next(q)) | |
4883 { | |
4884 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
4885 | |
4886 if (!pkt.need_ack && f->need_ack && max > cg->window) { | |
4887 max = cg->window; | |
4888 } | |
4889 | |
4890 if (hlen + len >= max) { | |
4891 break; | |
4892 } | |
4893 | |
4894 if (hlen + len + f->len > max) { | |
4895 rc = ngx_quic_split_frame(c, f, max - hlen - len); | |
4896 | |
4897 if (rc == NGX_ERROR) { | |
4898 return NGX_ERROR; | |
4899 } | |
4900 | |
4901 if (rc == NGX_DECLINED) { | |
4902 break; | |
4903 } | |
4914 } | 4904 } |
4915 | 4905 |
4916 if (f->need_ack) { | 4906 if (f->need_ack) { |
4917 pkt.need_ack = 1; | 4907 pkt.need_ack = 1; |
4918 } | 4908 } |
4919 | 4909 |
4920 p += len; | 4910 ngx_quic_log_frame(c->log, f, 1); |
4911 | |
4912 flen = ngx_quic_create_frame(p, f); | |
4913 if (flen == -1) { | |
4914 return NGX_ERROR; | |
4915 } | |
4916 | |
4917 len += flen; | |
4918 p += flen; | |
4919 | |
4921 f->pnum = ctx->pnum; | 4920 f->pnum = ctx->pnum; |
4921 f->first = now; | |
4922 f->last = now; | 4922 f->last = now; |
4923 f->plen = 0; | 4923 f->plen = 0; |
4924 } | 4924 |
4925 | 4925 nframes++; |
4926 out.len = p - out.data; | 4926 } |
4927 | 4927 |
4928 qc = ngx_quic_get_connection(c); | 4928 if (nframes == 0) { |
4929 return 0; | |
4930 } | |
4931 | |
4932 out.data = src; | |
4933 out.len = len; | |
4929 | 4934 |
4930 pkt.keys = qc->keys; | 4935 pkt.keys = qc->keys; |
4931 | |
4932 pkt.flags = NGX_QUIC_PKT_FIXED_BIT; | 4936 pkt.flags = NGX_QUIC_PKT_FIXED_BIT; |
4933 | 4937 |
4934 if (start->level == ssl_encryption_initial) { | 4938 if (ctx->level == ssl_encryption_initial) { |
4935 pkt.flags |= NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_INITIAL; | 4939 pkt.flags |= NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_INITIAL; |
4936 | 4940 |
4937 } else if (start->level == ssl_encryption_handshake) { | 4941 } else if (ctx->level == ssl_encryption_handshake) { |
4938 pkt.flags |= NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_HANDSHAKE; | 4942 pkt.flags |= NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_HANDSHAKE; |
4939 | 4943 |
4940 } else { | 4944 } else { |
4941 if (qc->key_phase) { | 4945 if (qc->key_phase) { |
4942 pkt.flags |= NGX_QUIC_PKT_KPHASE; | 4946 pkt.flags |= NGX_QUIC_PKT_KPHASE; |
4945 | 4949 |
4946 ngx_quic_set_packet_number(&pkt, ctx); | 4950 ngx_quic_set_packet_number(&pkt, ctx); |
4947 | 4951 |
4948 pkt.version = qc->version; | 4952 pkt.version = qc->version; |
4949 pkt.log = c->log; | 4953 pkt.log = c->log; |
4950 pkt.level = start->level; | 4954 pkt.level = ctx->level; |
4951 pkt.dcid = qc->scid; | 4955 pkt.dcid = qc->scid; |
4952 pkt.scid = qc->dcid; | 4956 pkt.scid = qc->dcid; |
4953 | 4957 |
4954 if (start->level == ssl_encryption_initial && pkt.need_ack) { | 4958 pad_len = 4; |
4955 pad_len = NGX_QUIC_MIN_INITIAL_SIZE - EVP_GCM_TLS_TAG_LEN | 4959 |
4956 - ngx_quic_create_header(&pkt, NULL, out.len, NULL); | 4960 if (min) { |
4957 pad_len = ngx_min(pad_len, NGX_QUIC_MIN_INITIAL_SIZE); | 4961 hlen = EVP_GCM_TLS_TAG_LEN |
4958 | 4962 + ngx_quic_create_header(&pkt, NULL, out.len, NULL); |
4959 } else { | 4963 |
4960 pad_len = 4; | 4964 if (min > hlen + pad_len) { |
4965 pad_len = min - hlen; | |
4966 } | |
4961 } | 4967 } |
4962 | 4968 |
4963 if (out.len < pad_len) { | 4969 if (out.len < pad_len) { |
4964 ngx_memset(p, NGX_QUIC_FT_PADDING, pad_len - out.len); | 4970 ngx_memset(p, NGX_QUIC_FT_PADDING, pad_len - out.len); |
4965 out.len = pad_len; | 4971 out.len = pad_len; |
4966 } | 4972 } |
4967 | 4973 |
4968 pkt.payload = out; | 4974 pkt.payload = out; |
4969 | 4975 |
4970 res.data = dst; | 4976 res.data = data; |
4971 | 4977 |
4972 ngx_log_debug6(NGX_LOG_DEBUG_EVENT, c->log, 0, | 4978 ngx_log_debug6(NGX_LOG_DEBUG_EVENT, c->log, 0, |
4973 "quic packet tx %s bytes:%ui" | 4979 "quic packet tx %s bytes:%ui" |
4974 " need_ack:%d number:%L encoded nl:%d trunc:0x%xD", | 4980 " need_ack:%d number:%L encoded nl:%d trunc:0x%xD", |
4975 ngx_quic_level_name(start->level), out.len, pkt.need_ack, | 4981 ngx_quic_level_name(ctx->level), out.len, pkt.need_ack, |
4976 pkt.number, pkt.num_len, pkt.trunc); | 4982 pkt.number, pkt.num_len, pkt.trunc); |
4977 | 4983 |
4978 if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { | 4984 if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { |
4979 ngx_quic_free_frames(c, frames); | |
4980 return NGX_ERROR; | 4985 return NGX_ERROR; |
4981 } | 4986 } |
4982 | 4987 |
4983 len = ngx_quic_send(c, res.data, res.len); | |
4984 if (len == NGX_ERROR) { | |
4985 ngx_quic_free_frames(c, frames); | |
4986 return NGX_ERROR; | |
4987 } | |
4988 | |
4989 /* len == NGX_OK || NGX_AGAIN */ | |
4990 ctx->pnum++; | 4988 ctx->pnum++; |
4991 | 4989 |
4992 if (pkt.need_ack) { | 4990 if (pkt.need_ack) { |
4993 /* move frames into the sent queue to wait for ack */ | 4991 /* move frames into the sent queue to wait for ack */ |
4994 | 4992 |
4995 if (qc->closing) { | 4993 if (!qc->closing) { |
4996 /* if we are closing, any ack will be discarded */ | 4994 q = ngx_queue_head(&ctx->frames); |
4997 ngx_quic_free_frames(c, frames); | 4995 f = ngx_queue_data(q, ngx_quic_frame_t, queue); |
4998 | 4996 f->plen = res.len; |
4999 } else { | 4997 |
5000 ngx_queue_add(&ctx->sent, frames); | 4998 do { |
4999 q = ngx_queue_head(&ctx->frames); | |
5000 ngx_queue_remove(q); | |
5001 ngx_queue_insert_tail(&ctx->sent, q); | |
5002 } while (--nframes); | |
5003 | |
5001 if (qc->pto.timer_set) { | 5004 if (qc->pto.timer_set) { |
5002 ngx_del_timer(&qc->pto); | 5005 ngx_del_timer(&qc->pto); |
5003 } | 5006 } |
5007 | |
5004 ngx_add_timer(&qc->pto, ngx_quic_pto(c, ctx)); | 5008 ngx_add_timer(&qc->pto, ngx_quic_pto(c, ctx)); |
5005 | 5009 } |
5006 start->plen = len; | 5010 |
5007 } | 5011 cg->in_flight += res.len; |
5008 | |
5009 qc->congestion.in_flight += len; | |
5010 | 5012 |
5011 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | 5013 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, |
5012 "quic congestion send if:%uz", | 5014 "quic congestion send if:%uz", cg->in_flight); |
5013 qc->congestion.in_flight); | 5015 } |
5014 } else { | 5016 |
5015 /* no ack is expected for this frames, so we can free them */ | 5017 while (nframes--) { |
5016 ngx_quic_free_frames(c, frames); | 5018 q = ngx_queue_head(&ctx->frames); |
5017 } | 5019 f = ngx_queue_data(q, ngx_quic_frame_t, queue); |
5020 | |
5021 ngx_queue_remove(q); | |
5022 ngx_quic_free_frame(c, f); | |
5023 } | |
5024 | |
5025 return res.len; | |
5026 } | |
5027 | |
5028 | |
5029 static ngx_int_t | |
5030 ngx_quic_split_frame(ngx_connection_t *c, ngx_quic_frame_t *f, size_t len) | |
5031 { | |
5032 size_t shrink; | |
5033 ngx_quic_frame_t *nf; | |
5034 ngx_quic_ordered_frame_t *of, *onf; | |
5035 | |
5036 switch (f->type) { | |
5037 case NGX_QUIC_FT_CRYPTO: | |
5038 case NGX_QUIC_FT_STREAM0: | |
5039 case NGX_QUIC_FT_STREAM1: | |
5040 case NGX_QUIC_FT_STREAM2: | |
5041 case NGX_QUIC_FT_STREAM3: | |
5042 case NGX_QUIC_FT_STREAM4: | |
5043 case NGX_QUIC_FT_STREAM5: | |
5044 case NGX_QUIC_FT_STREAM6: | |
5045 case NGX_QUIC_FT_STREAM7: | |
5046 break; | |
5047 | |
5048 default: | |
5049 return NGX_DECLINED; | |
5050 } | |
5051 | |
5052 if ((size_t) f->len <= len) { | |
5053 return NGX_OK; | |
5054 } | |
5055 | |
5056 shrink = f->len - len; | |
5057 | |
5058 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
5059 "quic split frame now:%uz need:%uz shrink:%uz", | |
5060 f->len, len, shrink); | |
5061 | |
5062 of = &f->u.ord; | |
5063 | |
5064 if (of->length <= shrink) { | |
5065 return NGX_DECLINED; | |
5066 } | |
5067 | |
5068 of->length -= shrink; | |
5069 f->len = ngx_quic_create_frame(NULL, f); | |
5070 | |
5071 if ((size_t) f->len > len) { | |
5072 ngx_log_error(NGX_LOG_ERR, c->log, 0, "could not split QUIC frame"); | |
5073 return NGX_ERROR; | |
5074 } | |
5075 | |
5076 nf = ngx_quic_alloc_frame(c); | |
5077 if (nf == NULL) { | |
5078 return NGX_ERROR; | |
5079 } | |
5080 | |
5081 *nf = *f; | |
5082 onf = &nf->u.ord; | |
5083 onf->offset += of->length; | |
5084 onf->length = shrink; | |
5085 nf->len = ngx_quic_create_frame(NULL, nf); | |
5086 | |
5087 nf->data = ngx_quic_split_bufs(c, f->data, of->length); | |
5088 if (nf->data == NGX_CHAIN_ERROR) { | |
5089 return NGX_ERROR; | |
5090 } | |
5091 | |
5092 ngx_queue_insert_after(&f->queue, &nf->queue); | |
5018 | 5093 |
5019 return NGX_OK; | 5094 return NGX_OK; |
5095 } | |
5096 | |
5097 | |
5098 static void | |
5099 ngx_quic_free_frames(ngx_connection_t *c, ngx_queue_t *frames) | |
5100 { | |
5101 ngx_queue_t *q; | |
5102 ngx_quic_frame_t *f; | |
5103 | |
5104 do { | |
5105 q = ngx_queue_head(frames); | |
5106 | |
5107 if (q == ngx_queue_sentinel(frames)) { | |
5108 break; | |
5109 } | |
5110 | |
5111 ngx_queue_remove(q); | |
5112 | |
5113 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
5114 | |
5115 ngx_quic_free_frame(c, f); | |
5116 } while (1); | |
5020 } | 5117 } |
5021 | 5118 |
5022 | 5119 |
5023 static ssize_t | 5120 static ssize_t |
5024 ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len) | 5121 ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len) |
5774 | 5871 |
5775 | 5872 |
5776 static ngx_chain_t * | 5873 static ngx_chain_t * |
5777 ngx_quic_stream_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) | 5874 ngx_quic_stream_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) |
5778 { | 5875 { |
5779 size_t n, max, max_frame, max_flow, max_limit; | 5876 size_t n, flow; |
5780 #if (NGX_DEBUG) | |
5781 size_t sent; | |
5782 ngx_uint_t nframes; | |
5783 #endif | |
5784 ngx_event_t *wev; | 5877 ngx_event_t *wev; |
5785 ngx_chain_t *cl; | 5878 ngx_chain_t *cl; |
5786 ngx_connection_t *pc; | 5879 ngx_connection_t *pc; |
5787 ngx_quic_frame_t *frame; | 5880 ngx_quic_frame_t *frame; |
5788 ngx_quic_stream_t *qs; | 5881 ngx_quic_stream_t *qs; |
5795 | 5888 |
5796 if (wev->error) { | 5889 if (wev->error) { |
5797 return NGX_CHAIN_ERROR; | 5890 return NGX_CHAIN_ERROR; |
5798 } | 5891 } |
5799 | 5892 |
5800 max_frame = ngx_quic_max_stream_frame(qc); | 5893 flow = ngx_quic_max_stream_flow(c); |
5801 max_flow = ngx_quic_max_stream_flow(c); | 5894 if (flow == 0) { |
5802 max_limit = limit; | 5895 wev->ready = 0; |
5803 | 5896 return in; |
5804 #if (NGX_DEBUG) | 5897 } |
5805 sent = 0; | 5898 |
5806 nframes = 0; | 5899 n = (limit && (size_t) limit < flow) ? (size_t) limit : flow; |
5807 #endif | 5900 |
5808 | 5901 frame = ngx_quic_alloc_frame(pc); |
5809 for ( ;; ) { | 5902 if (frame == NULL) { |
5810 max = ngx_min(max_frame, max_flow); | 5903 return NGX_CHAIN_ERROR; |
5811 | 5904 } |
5812 if (limit) { | 5905 |
5813 max = ngx_min(max, max_limit); | 5906 frame->data = ngx_quic_copy_chain(pc, in, n); |
5814 } | 5907 if (frame->data == NGX_CHAIN_ERROR) { |
5815 | 5908 return NGX_CHAIN_ERROR; |
5816 for (cl = in, n = 0; in; in = in->next) { | 5909 } |
5817 | 5910 |
5818 if (!ngx_buf_in_memory(in->buf)) { | 5911 for (n = 0, cl = frame->data; cl; cl = cl->next) { |
5819 continue; | 5912 n += ngx_buf_size(cl->buf); |
5820 } | 5913 } |
5821 | 5914 |
5822 n += ngx_buf_size(in->buf); | 5915 while (in && ngx_buf_size(in->buf) == 0) { |
5823 | 5916 in = in->next; |
5824 if (n > max) { | 5917 } |
5825 n = max; | 5918 |
5826 break; | 5919 frame->level = ssl_encryption_application; |
5827 } | 5920 frame->type = NGX_QUIC_FT_STREAM6; /* OFF=1 LEN=1 FIN=0 */ |
5828 } | 5921 frame->u.stream.off = 1; |
5829 | 5922 frame->u.stream.len = 1; |
5830 if (n == 0) { | 5923 frame->u.stream.fin = 0; |
5831 wev->ready = (max_flow ? 1 : 0); | 5924 |
5832 break; | 5925 frame->u.stream.type = frame->type; |
5833 } | 5926 frame->u.stream.stream_id = qs->id; |
5834 | 5927 frame->u.stream.offset = c->sent; |
5835 frame = ngx_quic_alloc_frame(pc); | 5928 frame->u.stream.length = n; |
5836 if (frame == NULL) { | 5929 |
5837 return NGX_CHAIN_ERROR; | 5930 c->sent += n; |
5838 } | 5931 qc->streams.sent += n; |
5839 | 5932 |
5840 frame->level = ssl_encryption_application; | 5933 ngx_quic_queue_frame(qc, frame); |
5841 frame->type = NGX_QUIC_FT_STREAM6; /* OFF=1 LEN=1 FIN=0 */ | 5934 |
5842 frame->u.stream.off = 1; | 5935 wev->ready = (n < flow) ? 1 : 0; |
5843 frame->u.stream.len = 1; | 5936 |
5844 frame->u.stream.fin = 0; | 5937 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, |
5845 | 5938 "quic send_chain sent:%uz", n); |
5846 frame->u.stream.type = frame->type; | |
5847 frame->u.stream.stream_id = qs->id; | |
5848 frame->u.stream.offset = c->sent; | |
5849 frame->u.stream.length = n; | |
5850 | |
5851 c->sent += n; | |
5852 qc->streams.sent += n; | |
5853 max_flow -= n; | |
5854 | |
5855 if (limit) { | |
5856 max_limit -= n; | |
5857 } | |
5858 | |
5859 #if (NGX_DEBUG) | |
5860 sent += n; | |
5861 nframes++; | |
5862 #endif | |
5863 | |
5864 frame->data = ngx_quic_copy_chain(pc, cl, n); | |
5865 if (frame->data == NGX_CHAIN_ERROR) { | |
5866 return NGX_CHAIN_ERROR; | |
5867 } | |
5868 | |
5869 ngx_quic_queue_frame(qc, frame); | |
5870 } | |
5871 | |
5872 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
5873 "quic send_chain sent:%uz nframes:%ui", sent, nframes); | |
5874 | 5939 |
5875 return in; | 5940 return in; |
5876 } | |
5877 | |
5878 | |
5879 static size_t | |
5880 ngx_quic_max_stream_frame(ngx_quic_connection_t *qc) | |
5881 { | |
5882 /* | |
5883 * we need to fit at least 1 frame into a packet, thus account head/tail; | |
5884 * 25 = 1 + 8x3 is max header for STREAM frame, with 1 byte for frame type | |
5885 */ | |
5886 | |
5887 return qc->ctp.max_udp_payload_size - NGX_QUIC_MAX_SHORT_HEADER - 25 | |
5888 - EVP_GCM_TLS_TAG_LEN; | |
5889 } | 5941 } |
5890 | 5942 |
5891 | 5943 |
5892 static size_t | 5944 static size_t |
5893 ngx_quic_max_stream_flow(ngx_connection_t *c) | 5945 ngx_quic_max_stream_flow(ngx_connection_t *c) |
6259 | 6311 |
6260 | 6312 |
6261 static void | 6313 static void |
6262 ngx_quic_free_bufs(ngx_connection_t *c, ngx_chain_t *in) | 6314 ngx_quic_free_bufs(ngx_connection_t *c, ngx_chain_t *in) |
6263 { | 6315 { |
6316 ngx_buf_t *b, *shadow; | |
6264 ngx_chain_t *cl; | 6317 ngx_chain_t *cl; |
6265 ngx_quic_connection_t *qc; | 6318 ngx_quic_connection_t *qc; |
6266 | 6319 |
6267 qc = ngx_quic_get_connection(c); | 6320 qc = ngx_quic_get_connection(c); |
6268 | 6321 |
6272 "quic free buffer n:%ui", qc->nbufs); | 6325 "quic free buffer n:%ui", qc->nbufs); |
6273 #endif | 6326 #endif |
6274 | 6327 |
6275 cl = in; | 6328 cl = in; |
6276 in = in->next; | 6329 in = in->next; |
6330 b = cl->buf; | |
6331 | |
6332 if (b->shadow) { | |
6333 if (!b->last_shadow) { | |
6334 b->recycled = 1; | |
6335 ngx_free_chain(c->pool, cl); | |
6336 continue; | |
6337 } | |
6338 | |
6339 do { | |
6340 shadow = b->shadow; | |
6341 b->shadow = qc->free_shadow_bufs; | |
6342 qc->free_shadow_bufs = b; | |
6343 b = shadow; | |
6344 } while (b->recycled); | |
6345 | |
6346 if (b->shadow) { | |
6347 b->last_shadow = 1; | |
6348 ngx_free_chain(c->pool, cl); | |
6349 continue; | |
6350 } | |
6351 | |
6352 cl->buf = b; | |
6353 } | |
6277 | 6354 |
6278 cl->next = qc->free_bufs; | 6355 cl->next = qc->free_bufs; |
6279 qc->free_bufs = cl; | 6356 qc->free_bufs = cl; |
6280 } | 6357 } |
6281 } | 6358 } |
6371 | 6448 |
6372 *ll = NULL; | 6449 *ll = NULL; |
6373 | 6450 |
6374 return out; | 6451 return out; |
6375 } | 6452 } |
6453 | |
6454 | |
6455 static ngx_chain_t * | |
6456 ngx_quic_split_bufs(ngx_connection_t *c, ngx_chain_t *in, size_t len) | |
6457 { | |
6458 size_t n; | |
6459 ngx_buf_t *b; | |
6460 ngx_chain_t *out; | |
6461 ngx_quic_connection_t *qc; | |
6462 | |
6463 qc = ngx_quic_get_connection(c); | |
6464 | |
6465 while (in) { | |
6466 n = ngx_buf_size(in->buf); | |
6467 | |
6468 if (n == len) { | |
6469 out = in->next; | |
6470 in->next = NULL; | |
6471 return out; | |
6472 } | |
6473 | |
6474 if (n > len) { | |
6475 break; | |
6476 } | |
6477 | |
6478 len -= n; | |
6479 in = in->next; | |
6480 } | |
6481 | |
6482 if (in == NULL) { | |
6483 return NULL; | |
6484 } | |
6485 | |
6486 /* split in->buf by creating shadow bufs which reference it */ | |
6487 | |
6488 if (in->buf->shadow == NULL) { | |
6489 if (qc->free_shadow_bufs) { | |
6490 b = qc->free_shadow_bufs; | |
6491 qc->free_shadow_bufs = b->shadow; | |
6492 | |
6493 } else { | |
6494 b = ngx_alloc_buf(c->pool); | |
6495 if (b == NULL) { | |
6496 return NGX_CHAIN_ERROR; | |
6497 } | |
6498 } | |
6499 | |
6500 *b = *in->buf; | |
6501 b->shadow = in->buf; | |
6502 b->last_shadow = 1; | |
6503 in->buf = b; | |
6504 } | |
6505 | |
6506 out = ngx_alloc_chain_link(c->pool); | |
6507 if (out == NULL) { | |
6508 return NGX_CHAIN_ERROR; | |
6509 } | |
6510 | |
6511 if (qc->free_shadow_bufs) { | |
6512 b = qc->free_shadow_bufs; | |
6513 qc->free_shadow_bufs = b->shadow; | |
6514 | |
6515 } else { | |
6516 b = ngx_alloc_buf(c->pool); | |
6517 if (b == NULL) { | |
6518 ngx_free_chain(c->pool, out); | |
6519 return NGX_CHAIN_ERROR; | |
6520 } | |
6521 } | |
6522 | |
6523 out->buf = b; | |
6524 out->next = in->next; | |
6525 in->next = NULL; | |
6526 | |
6527 *b = *in->buf; | |
6528 b->last_shadow = 0; | |
6529 b->pos = b->pos + len; | |
6530 | |
6531 in->buf->shadow = b; | |
6532 in->buf->last = in->buf->pos + len; | |
6533 | |
6534 return out; | |
6535 } |