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 }