Mercurial > hg > nginx-quic
comparison src/event/quic/ngx_event_quic_output.c @ 8547:ad046179eb91 quic
QUIC: handle EAGAIN properly on UDP sockets.
Previously, the error was ignored leading to unnecessary retransmits.
Now, unsent frames are returned into output queue, state is reset, and
timer is started for the next send attempt.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Wed, 28 Jul 2021 17:23:18 +0300 |
parents | 8ab0d609af09 |
children | f3331deed357 |
comparison
equal
deleted
inserted
replaced
8546:d80365ca678d | 8547:ad046179eb91 |
---|---|
37 #define NGX_QUIC_MIN_SR_PACKET 43 /* 5 rand + 16 srt + 22 padding */ | 37 #define NGX_QUIC_MIN_SR_PACKET 43 /* 5 rand + 16 srt + 22 padding */ |
38 #define NGX_QUIC_MAX_SR_PACKET 1200 | 38 #define NGX_QUIC_MAX_SR_PACKET 1200 |
39 | 39 |
40 #define NGX_QUIC_CC_MIN_INTERVAL 1000 /* 1s */ | 40 #define NGX_QUIC_CC_MIN_INTERVAL 1000 /* 1s */ |
41 | 41 |
42 #define NGX_QUIC_SOCKET_RETRY_DELAY 10 /* ms, for NGX_AGAIN on write */ | |
43 | |
42 | 44 |
43 static ngx_int_t ngx_quic_socket_output(ngx_connection_t *c, | 45 static ngx_int_t ngx_quic_socket_output(ngx_connection_t *c, |
44 ngx_quic_socket_t *qsock); | 46 ngx_quic_socket_t *qsock); |
45 static ngx_int_t ngx_quic_create_datagrams(ngx_connection_t *c, | 47 static ngx_int_t ngx_quic_create_datagrams(ngx_connection_t *c, |
46 ngx_quic_socket_t *qsock); | 48 ngx_quic_socket_t *qsock); |
49 static void ngx_quic_commit_send(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx); | |
50 static void ngx_quic_revert_send(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, | |
51 uint64_t pnum); | |
47 #if ((NGX_HAVE_UDP_SEGMENT) && (NGX_HAVE_MSGHDR_MSG_CONTROL)) | 52 #if ((NGX_HAVE_UDP_SEGMENT) && (NGX_HAVE_MSGHDR_MSG_CONTROL)) |
48 static ngx_uint_t ngx_quic_allow_segmentation(ngx_connection_t *c, | 53 static ngx_uint_t ngx_quic_allow_segmentation(ngx_connection_t *c, |
49 ngx_quic_socket_t *qsock); | 54 ngx_quic_socket_t *qsock); |
50 static ngx_int_t ngx_quic_create_segments(ngx_connection_t *c, | 55 static ngx_int_t ngx_quic_create_segments(ngx_connection_t *c, |
51 ngx_quic_socket_t *qsock); | 56 ngx_quic_socket_t *qsock); |
136 { | 141 { |
137 off_t max; | 142 off_t max; |
138 size_t len, min; | 143 size_t len, min; |
139 ssize_t n; | 144 ssize_t n; |
140 u_char *p; | 145 u_char *p; |
146 uint64_t preserved_pnum[NGX_QUIC_SEND_CTX_LAST]; | |
141 ngx_uint_t i, pad; | 147 ngx_uint_t i, pad; |
142 ngx_quic_path_t *path; | 148 ngx_quic_path_t *path; |
143 ngx_quic_send_ctx_t *ctx; | 149 ngx_quic_send_ctx_t *ctx; |
144 ngx_quic_connection_t *qc; | 150 ngx_quic_connection_t *qc; |
145 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | 151 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; |
146 | 152 |
147 qc = ngx_quic_get_connection(c); | 153 qc = ngx_quic_get_connection(c); |
148 | |
149 path = qsock->path; | 154 path = qsock->path; |
150 | 155 |
151 for ( ;; ) { | 156 for ( ;; ) { |
152 p = dst; | 157 p = dst; |
153 | 158 |
164 pad = ngx_quic_get_padding_level(c); | 169 pad = ngx_quic_get_padding_level(c); |
165 | 170 |
166 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { | 171 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { |
167 | 172 |
168 ctx = &qc->send_ctx[i]; | 173 ctx = &qc->send_ctx[i]; |
174 | |
175 preserved_pnum[i] = ctx->pnum; | |
169 | 176 |
170 if (ngx_quic_generate_ack(c, ctx) != NGX_OK) { | 177 if (ngx_quic_generate_ack(c, ctx) != NGX_OK) { |
171 return NGX_ERROR; | 178 return NGX_ERROR; |
172 } | 179 } |
173 | 180 |
192 | 199 |
193 if (n == NGX_ERROR) { | 200 if (n == NGX_ERROR) { |
194 return NGX_ERROR; | 201 return NGX_ERROR; |
195 } | 202 } |
196 | 203 |
204 if (n == NGX_AGAIN) { | |
205 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { | |
206 ngx_quic_revert_send(c, &qc->send_ctx[i], preserved_pnum[i]); | |
207 } | |
208 | |
209 ngx_add_timer(&qc->push, NGX_QUIC_SOCKET_RETRY_DELAY); | |
210 break; | |
211 } | |
212 | |
213 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { | |
214 ngx_quic_commit_send(c, &qc->send_ctx[i]); | |
215 } | |
216 | |
197 path->sent += len; | 217 path->sent += len; |
198 } | 218 } |
199 | 219 |
200 return NGX_OK; | 220 return NGX_OK; |
221 } | |
222 | |
223 | |
224 static void | |
225 ngx_quic_commit_send(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) | |
226 { | |
227 ngx_queue_t *q; | |
228 ngx_quic_frame_t *f; | |
229 ngx_quic_congestion_t *cg; | |
230 ngx_quic_connection_t *qc; | |
231 | |
232 qc = ngx_quic_get_connection(c); | |
233 | |
234 cg = &qc->congestion; | |
235 | |
236 while (!ngx_queue_empty(&ctx->sending)) { | |
237 | |
238 q = ngx_queue_head(&ctx->sending); | |
239 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
240 | |
241 ngx_queue_remove(q); | |
242 | |
243 if (f->pkt_need_ack && !qc->closing) { | |
244 ngx_queue_insert_tail(&ctx->sent, q); | |
245 | |
246 cg->in_flight += f->plen; | |
247 | |
248 } else { | |
249 ngx_quic_free_frame(c, f); | |
250 } | |
251 } | |
252 | |
253 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
254 "quic congestion send if:%uz", cg->in_flight); | |
255 } | |
256 | |
257 | |
258 static void | |
259 ngx_quic_revert_send(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, | |
260 uint64_t pnum) | |
261 { | |
262 ngx_queue_t *q; | |
263 | |
264 while (!ngx_queue_empty(&ctx->sending)) { | |
265 | |
266 q = ngx_queue_last(&ctx->sending); | |
267 ngx_queue_remove(q); | |
268 ngx_queue_insert_head(&ctx->frames, q); | |
269 } | |
270 | |
271 ctx->pnum = pnum; | |
201 } | 272 } |
202 | 273 |
203 | 274 |
204 #if ((NGX_HAVE_UDP_SEGMENT) && (NGX_HAVE_MSGHDR_MSG_CONTROL)) | 275 #if ((NGX_HAVE_UDP_SEGMENT) && (NGX_HAVE_MSGHDR_MSG_CONTROL)) |
205 | 276 |
262 ngx_quic_create_segments(ngx_connection_t *c, ngx_quic_socket_t *qsock) | 333 ngx_quic_create_segments(ngx_connection_t *c, ngx_quic_socket_t *qsock) |
263 { | 334 { |
264 size_t len, segsize; | 335 size_t len, segsize; |
265 ssize_t n; | 336 ssize_t n; |
266 u_char *p, *end; | 337 u_char *p, *end; |
338 uint64_t preserved_pnum; | |
267 ngx_uint_t nseg; | 339 ngx_uint_t nseg; |
340 ngx_quic_path_t *path; | |
268 ngx_quic_send_ctx_t *ctx; | 341 ngx_quic_send_ctx_t *ctx; |
269 ngx_quic_path_t *path; | |
270 ngx_quic_connection_t *qc; | 342 ngx_quic_connection_t *qc; |
271 static u_char dst[NGX_QUIC_MAX_UDP_SEGMENT_BUF]; | 343 static u_char dst[NGX_QUIC_MAX_UDP_SEGMENT_BUF]; |
272 | 344 |
273 qc = ngx_quic_get_connection(c); | 345 qc = ngx_quic_get_connection(c); |
274 path = qsock->path; | 346 path = qsock->path; |
283 NGX_QUIC_MAX_UDP_SEGMENT_BUF); | 355 NGX_QUIC_MAX_UDP_SEGMENT_BUF); |
284 p = dst; | 356 p = dst; |
285 end = dst + sizeof(dst); | 357 end = dst + sizeof(dst); |
286 | 358 |
287 nseg = 0; | 359 nseg = 0; |
360 | |
361 preserved_pnum = ctx->pnum; | |
288 | 362 |
289 for ( ;; ) { | 363 for ( ;; ) { |
290 | 364 |
291 len = ngx_min(segsize, (size_t) (end - p)); | 365 len = ngx_min(segsize, (size_t) (end - p)); |
292 | 366 |
313 path->socklen, segsize); | 387 path->socklen, segsize); |
314 if (n == NGX_ERROR) { | 388 if (n == NGX_ERROR) { |
315 return NGX_ERROR; | 389 return NGX_ERROR; |
316 } | 390 } |
317 | 391 |
392 if (n == NGX_AGAIN) { | |
393 ngx_quic_revert_send(c, ctx, preserved_pnum); | |
394 | |
395 ngx_add_timer(&qc->push, NGX_QUIC_SOCKET_RETRY_DELAY); | |
396 break; | |
397 } | |
398 | |
399 ngx_quic_commit_send(c, ctx); | |
400 | |
318 path->sent += n; | 401 path->sent += n; |
319 | 402 |
320 p = dst; | 403 p = dst; |
321 nseg = 0; | 404 nseg = 0; |
405 preserved_pnum = ctx->pnum; | |
322 } | 406 } |
323 } | 407 } |
324 | 408 |
325 return NGX_OK; | 409 return NGX_OK; |
326 } | 410 } |
378 #endif | 462 #endif |
379 | 463 |
380 msg.msg_controllen = clen; | 464 msg.msg_controllen = clen; |
381 | 465 |
382 n = ngx_sendmsg(c, &msg, 0); | 466 n = ngx_sendmsg(c, &msg, 0); |
383 if (n == -1) { | 467 if (n < 0) { |
384 return NGX_ERROR; | 468 return n; |
385 } | 469 } |
386 | 470 |
387 c->sent += n; | 471 c->sent += n; |
388 | 472 |
389 return n; | 473 return n; |
620 } | 704 } |
621 | 705 |
622 ctx->pnum++; | 706 ctx->pnum++; |
623 | 707 |
624 if (pkt.need_ack) { | 708 if (pkt.need_ack) { |
625 /* move frames into the sent queue to wait for ack */ | 709 q = ngx_queue_head(&ctx->frames); |
626 | 710 f = ngx_queue_data(q, ngx_quic_frame_t, queue); |
627 if (!qc->closing) { | 711 |
628 q = ngx_queue_head(&ctx->frames); | 712 f->plen = res.len; |
629 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
630 f->plen = res.len; | |
631 | |
632 do { | |
633 q = ngx_queue_head(&ctx->frames); | |
634 ngx_queue_remove(q); | |
635 ngx_queue_insert_tail(&ctx->sent, q); | |
636 } while (--nframes); | |
637 } | |
638 | |
639 cg->in_flight += res.len; | |
640 | |
641 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
642 "quic congestion send if:%uz", cg->in_flight); | |
643 } | 713 } |
644 | 714 |
645 while (nframes--) { | 715 while (nframes--) { |
646 q = ngx_queue_head(&ctx->frames); | 716 q = ngx_queue_head(&ctx->frames); |
647 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | 717 f = ngx_queue_data(q, ngx_quic_frame_t, queue); |
648 | 718 |
719 f->pkt_need_ack = pkt.need_ack; | |
720 | |
649 ngx_queue_remove(q); | 721 ngx_queue_remove(q); |
650 ngx_quic_free_frame(c, f); | 722 ngx_queue_insert_tail(&ctx->sending, q); |
651 } | 723 } |
652 | 724 |
653 return res.len; | 725 return res.len; |
654 } | 726 } |
655 | 727 |
656 | 728 |
657 static ssize_t | 729 static ssize_t |
658 ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len, | 730 ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len, |
659 struct sockaddr *sockaddr, socklen_t socklen) | 731 struct sockaddr *sockaddr, socklen_t socklen) |
660 { | 732 { |
661 ngx_buf_t b; | 733 ssize_t n; |
662 socklen_t orig_socklen; | 734 struct iovec iov; |
663 ngx_chain_t cl, *res; | 735 struct msghdr msg; |
664 struct sockaddr *orig_sockaddr; | 736 #if defined(NGX_HAVE_ADDRINFO_CMSG) |
665 | 737 struct cmsghdr *cmsg; |
666 ngx_memzero(&b, sizeof(ngx_buf_t)); | 738 char msg_control[CMSG_SPACE(sizeof(ngx_addrinfo_t))]; |
667 | 739 #endif |
668 b.pos = b.start = buf; | 740 |
669 b.last = b.end = buf + len; | 741 ngx_memzero(&msg, sizeof(struct msghdr)); |
670 b.last_buf = 1; | 742 |
671 b.temporary = 1; | 743 iov.iov_len = len; |
672 | 744 iov.iov_base = buf; |
673 cl.buf = &b; | 745 |
674 cl.next= NULL; | 746 msg.msg_iov = &iov; |
675 | 747 msg.msg_iovlen = 1; |
676 orig_socklen = c->socklen; | 748 |
677 orig_sockaddr = c->sockaddr; | 749 msg.msg_name = sockaddr; |
678 | 750 msg.msg_namelen = socklen; |
679 c->sockaddr = sockaddr; | 751 |
680 c->socklen = socklen; | 752 #if defined(NGX_HAVE_ADDRINFO_CMSG) |
681 | 753 if (c->listening && c->listening->wildcard && c->local_sockaddr) { |
682 res = c->send_chain(c, &cl, 0); | 754 |
683 | 755 msg.msg_control = msg_control; |
684 c->sockaddr = orig_sockaddr; | 756 msg.msg_controllen = sizeof(msg_control); |
685 c->socklen = orig_socklen; | 757 ngx_memzero(msg_control, sizeof(msg_control)); |
686 | 758 |
687 if (res == NGX_CHAIN_ERROR) { | 759 cmsg = CMSG_FIRSTHDR(&msg); |
688 return NGX_ERROR; | 760 |
689 } | 761 msg.msg_controllen = ngx_set_srcaddr_cmsg(cmsg, c->local_sockaddr); |
690 | 762 } |
691 return len; | 763 #endif |
764 | |
765 n = ngx_sendmsg(c, &msg, 0); | |
766 if (n < 0) { | |
767 return n; | |
768 } | |
769 | |
770 c->sent += n; | |
771 | |
772 return n; | |
692 } | 773 } |
693 | 774 |
694 | 775 |
695 static void | 776 static void |
696 ngx_quic_set_packet_number(ngx_quic_header_t *pkt, ngx_quic_send_ctx_t *ctx) | 777 ngx_quic_set_packet_number(ngx_quic_header_t *pkt, ngx_quic_send_ctx_t *ctx) |
943 | 1024 |
944 if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { | 1025 if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { |
945 return NGX_ERROR; | 1026 return NGX_ERROR; |
946 } | 1027 } |
947 | 1028 |
948 if (ngx_quic_send(c, res.data, res.len, c->sockaddr, c->socklen) | 1029 if (ngx_quic_send(c, res.data, res.len, c->sockaddr, c->socklen) < 0) { |
949 == NGX_ERROR) | |
950 { | |
951 return NGX_ERROR; | 1030 return NGX_ERROR; |
952 } | 1031 } |
953 | 1032 |
954 return NGX_OK; | 1033 return NGX_OK; |
955 } | 1034 } |
1004 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | 1083 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, |
1005 "quic packet to send len:%uz %xV", res.len, &res); | 1084 "quic packet to send len:%uz %xV", res.len, &res); |
1006 #endif | 1085 #endif |
1007 | 1086 |
1008 len = ngx_quic_send(c, res.data, res.len, c->sockaddr, c->socklen); | 1087 len = ngx_quic_send(c, res.data, res.len, c->sockaddr, c->socklen); |
1009 if (len == NGX_ERROR) { | 1088 if (len < 0) { |
1010 return NGX_ERROR; | 1089 return NGX_ERROR; |
1011 } | 1090 } |
1012 | 1091 |
1013 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | 1092 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, |
1014 "quic retry packet sent to %xV", &pkt.dcid); | 1093 "quic retry packet sent to %xV", &pkt.dcid); |
1219 return -1; | 1298 return -1; |
1220 } | 1299 } |
1221 | 1300 |
1222 ctx->pnum++; | 1301 ctx->pnum++; |
1223 | 1302 |
1224 len = ngx_quic_send(c, res.data, res.len, sockaddr, socklen); | 1303 return ngx_quic_send(c, res.data, res.len, sockaddr, socklen); |
1225 | 1304 } |
1226 return len; | |
1227 } |