aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2019-08-01 20:44:41 +0200
committerChristian Grothoff <christian@grothoff.org>2019-08-01 20:44:41 +0200
commitc5081fb276b52fc9d48b9ba441686727eafaaad8 (patch)
treed8741e84111ed226c2bc2426e18d4e90bbd85184
parentda7cb682a24915a4bc37faf2c76583996fe26aea (diff)
downloadlibmicrohttpd-c5081fb276b52fc9d48b9ba441686727eafaaad8.tar.gz
libmicrohttpd-c5081fb276b52fc9d48b9ba441686727eafaaad8.zip
always set nodelay, except if we cannot cork
-rw-r--r--src/microhttpd/daemon.c14
-rw-r--r--src/microhttpd/mhd_send.c166
-rw-r--r--src/microhttpd/mhd_sockets.c92
-rw-r--r--src/microhttpd/mhd_sockets.h38
4 files changed, 181 insertions, 129 deletions
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index bf01ba9b..16655f65 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -3224,6 +3224,19 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
3224 } 3224 }
3225 return MHD_NO; 3225 return MHD_NO;
3226 } 3226 }
3227#if defined(MHD_TCP_CORK_NOPUSH) || defined(HAVE_MSG_MORE)
3228 /* We will use TCP_CORK or TCP_NOPUSH or MSG_MORE to control
3229 transmission, disable Nagle's algorithm (always) */
3230 if (0 != MHD_socket_set_nodelay_ (s,
3231 true))
3232 {
3233#ifdef HAVE_MESSAGES
3234 MHD_DLOG (daemon,
3235 _("Failed to disable TCP Nagle on socket: %s\n"),
3236 MHD_socket_last_strerr_());
3237 }
3238#endif
3239#endif
3227#if !defined(USE_ACCEPT4) || !defined(HAVE_SOCK_NONBLOCK) 3240#if !defined(USE_ACCEPT4) || !defined(HAVE_SOCK_NONBLOCK)
3228 if (! MHD_socket_nonblocking_ (s)) 3241 if (! MHD_socket_nonblocking_ (s))
3229 { 3242 {
@@ -6223,7 +6236,6 @@ MHD_start_daemon_va (unsigned int flags,
6223 } 6236 }
6224 } 6237 }
6225#endif /* HAVE_GETSOCKNAME */ 6238#endif /* HAVE_GETSOCKNAME */
6226
6227 if ( (MHD_INVALID_SOCKET != listen_fd) && 6239 if ( (MHD_INVALID_SOCKET != listen_fd) &&
6228 (! MHD_socket_nonblocking_ (listen_fd)) ) 6240 (! MHD_socket_nonblocking_ (listen_fd)) )
6229 { 6241 {
diff --git a/src/microhttpd/mhd_send.c b/src/microhttpd/mhd_send.c
index 7ca2b506..9b07115c 100644
--- a/src/microhttpd/mhd_send.c
+++ b/src/microhttpd/mhd_send.c
@@ -49,7 +49,8 @@ pre_cork_setsockopt (struct MHD_Connection *connection,
49 bool want_cork) 49 bool want_cork)
50{ 50{
51#if HAVE_MSG_MORE 51#if HAVE_MSG_MORE
52#else 52 /* We use the MSG_MORE option for corking, no need for extra syscalls! */
53#elif defined(MHD_TCP_CORK_NOPUSH)
53 int ret; 54 int ret;
54 55
55 /* If sk_cork_on is already what we pass in, return. */ 56 /* If sk_cork_on is already what we pass in, return. */
@@ -58,84 +59,38 @@ pre_cork_setsockopt (struct MHD_Connection *connection,
58 /* nothing to do, success! */ 59 /* nothing to do, success! */
59 return; 60 return;
60 } 61 }
61 62 if (! want_cork)
62 ret = -1; 63 return; /* nothing to do *pre* syscall! */
63#if TCP_CORK 64 ret = MHD_socket_cork_ (connection->socket_fd,
64 if (want_cork) 65 true);
65 {
66 const MHD_SCKT_OPT_BOOL_ on_val = 1;
67
68 ret = setsockopt (connection->socket_fd,
69 IPPROTO_TCP,
70 TCP_CORK,
71 (const void *) &on_val,
72 sizeof (on_val));
73 }
74#elif TCP_NOPUSH
75 if (want_cork)
76 {
77 const MHD_SCKT_OPT_BOOL_ on_val = 1;
78 /* TCP_NOPUSH has the same logic as MSG_MSG_MORE.
79 * The two are more or less equivalent by a source
80 * transformation (ie
81 * send(MSG_MORE) => "set TCP_NOPUSH + send() + clear TCP_NOPUSH".
82 * Both of them are really fairly "local", but TCP_NOPUSH has a
83 * _notion_ of persistency that is entirely lacking in MSG_MORE.
84 * ... with TCP_NOPUSH you basically have to know what your last
85 * write is, and clear the bit _before_ that write if you want
86 * to avoid bad latencies.
87 * https://yarchive.net/comp/linux/sendfile.html A thread from 2001,
88 * take with 18 grains of salt. */
89
90 ret = setsockopt (connection->socket_fd,
91 IPPROTO_TCP,
92 TCP_NOPUSH,
93 (const void *) &on_val,
94 sizeof (on_val));
95 }
96#elif TCP_NODELAY
97 {
98 const MHD_SCKT_OPT_BOOL_ off_val = 0;
99 const MHD_SCKT_OPT_BOOL_ on_val = 1;
100
101 ret = setsockopt (connection->socket_fd,
102 IPPROTO_TCP,
103 TCP_NODELAY,
104 (const void *) want_cork ? &off_val : &on_val,
105 sizeof (on_val));
106 }
107#endif
108 if (0 == ret) 66 if (0 == ret)
109 { 67 {
110 connection->sk_cork_on = want_cork; 68 connection->sk_cork_on = true;
69 return;
111 } 70 }
112 else 71 switch (errno)
113 { 72 {
114 switch (errno) 73 case ENOTSOCK:
115 { 74 /* FIXME: Could be we are talking to a pipe, maybe remember this
116 case ENOTSOCK: 75 and avoid all setsockopt() in the future? */
117 /* FIXME: Could be we are talking to a pipe, maybe remember this 76 break;
118 and avoid all setsockopt() in the future? */ 77 case EBADF:
119 break; 78 /* FIXME: should we die hard here? */
120 case EBADF: 79 break;
121 /* FIXME: should we die hard here? */ 80 case EINVAL:
122 break; 81 /* FIXME: optlen invalid, should at least log this, maybe die */
123 case EINVAL: 82 break;
124 /* FIXME: optlen invalid, should at least log this, maybe die */ 83 case EFAULT:
125 break; 84 /* FIXME: wopsie, should at leats log this, maybe die */
126 case EFAULT: 85 break;
127 /* FIXME: wopsie, should at leats log this, maybe die */ 86 case ENOPROTOOPT:
128 break; 87 /* FIXME: optlen unknown, should at least log this */
129 case ENOPROTOOPT: 88 break;
130 /* FIXME: optlen unknown, should at least log this */ 89 default:
131 break; 90 /* any others? man page does not list more... */
132 default: 91 break;
133 /* any others? man page does not list more... */
134 break;
135 }
136 } 92 }
137 return; 93#endif
138#endif /* MSG_MORE */
139} 94}
140 95
141 96
@@ -150,7 +105,8 @@ post_cork_setsockopt (struct MHD_Connection *connection,
150 bool want_cork) 105 bool want_cork)
151{ 106{
152#if HAVE_MSG_MORE 107#if HAVE_MSG_MORE
153#else 108 /* We use the MSG_MORE option for corking, no need for extra syscalls! */
109#elif defined(MHD_TCP_CORK_NOPUSH)
154 int ret; 110 int ret;
155 111
156 /* If sk_cork_on is already what we pass in, return. */ 112 /* If sk_cork_on is already what we pass in, return. */
@@ -159,38 +115,40 @@ post_cork_setsockopt (struct MHD_Connection *connection,
159 /* nothing to do, success! */ 115 /* nothing to do, success! */
160 return; 116 return;
161 } 117 }
162 ret = -1; 118 if (want_cork)
163#if TCP_CORK 119 return; /* nothing to do *post* syscall (in fact, we should never
164 if (! want_cork) 120 get here, as sk_cork_on should have succeeded in the
165 { 121 pre-syscall) */
166 const MHD_SCKT_OPT_BOOL_ off_val = 0; 122 ret = MHD_socket_cork_ (connection->socket_fd,
167 123 false);
168 ret = setsockopt (connection->socket_fd,
169 IPPROTO_TCP,
170 TCP_CORK,
171 &off_val,
172 sizeof (off_val));
173 }
174#elif TCP_NOPUSH
175 if (! want_cork)
176 {
177 const MHD_SCKT_OPT_BOOL_ off_val = 0;
178
179 ret = setsockopt (connection->socket_fd,
180 IPPROTO_TCP,
181 TCP_NOPUSH,
182 (const void *) &off_val,
183 sizeof (off_val));
184 }
185#elif TCP_NODELAY
186 /* nothing to do */
187#endif
188 if (0 == ret) 124 if (0 == ret)
189 { 125 {
190 connection->sk_cork_on = want_cork; 126 connection->sk_cork_on = false;
127 return;
128 }
129 switch (errno)
130 {
131 case ENOTSOCK:
132 /* FIXME: Could be we are talking to a pipe, maybe remember this
133 and avoid all setsockopt() in the future? */
134 break;
135 case EBADF:
136 /* FIXME: should we die hard here? */
137 break;
138 case EINVAL:
139 /* FIXME: optlen invalid, should at least log this, maybe die */
140 break;
141 case EFAULT:
142 /* FIXME: wopsie, should at leats log this, maybe die */
143 break;
144 case ENOPROTOOPT:
145 /* FIXME: optlen unknown, should at least log this */
146 break;
147 default:
148 /* any others? man page does not list more... */
149 break;
191 } 150 }
192 return; 151#endif
193#endif /* MSG_MORE */
194} 152}
195 153
196 154
diff --git a/src/microhttpd/mhd_sockets.c b/src/microhttpd/mhd_sockets.c
index 0bfe2517..b4e73480 100644
--- a/src/microhttpd/mhd_sockets.c
+++ b/src/microhttpd/mhd_sockets.c
@@ -462,6 +462,64 @@ MHD_socket_noninheritable_ (MHD_socket sock)
462 462
463 463
464/** 464/**
465 * Disable Nagle's algorithm on @a sock. This is what we do by default for
466 * all TCP sockets in MHD, unless the platform does not support the MSG_MORE
467 * or MSG_CORK or MSG_NOPUSH options.
468 *
469 * @param sock socket to manipulate
470 * @param on value to use
471 * @return 0 on success
472 */
473int
474MHD_socket_set_nodelay_ (MHD_socket sock,
475 bool on)
476{
477#ifdef TCP_NODELAY
478 {
479 const MHD_SCKT_OPT_BOOL_ off_val = 0;
480 const MHD_SCKT_OPT_BOOL_ on_val = 1;
481 /* Disable Nagle's algorithm for normal buffering */
482 return setsockopt (sock,
483 IPPROTO_TCP,
484 TCP_NODELAY,
485 (const void *) (on) ? &on_val : &off_val,
486 sizeof (on_val));
487 }
488#else
489 (void) sock;
490 return 0;
491#endif /* TCP_NODELAY */
492}
493
494
495/**
496 * Enable/disable the cork option.
497 *
498 * @param sock socket to manipulate
499 * @param on set to true to enable CORK, false to disable
500 * @return non-zero if succeeded, zero otherwise
501 */
502int
503MHD_socket_cork_ (MHD_socket sock,
504 bool on)
505{
506#if defined(MHD_TCP_CORK_NOPUSH)
507 const MHD_SCKT_OPT_BOOL_ off_val = 0;
508 const MHD_SCKT_OPT_BOOL_ on_val = 1;
509
510 /* Disable extra buffering */
511 return (0 == setsockopt (sock,
512 IPPROTO_TCP,
513 MHD_TCP_CORK_NOPUSH,
514 (const void *) (on ? &on_val : &off_val),
515 sizeof (off_val)));
516#else
517 return 0;
518#endif /* MHD_TCP_CORK_NOPUSH */
519}
520
521
522/**
465 * Change socket buffering mode to default. 523 * Change socket buffering mode to default.
466 * 524 *
467 * @param sock socket to manipulate 525 * @param sock socket to manipulate
@@ -470,33 +528,19 @@ MHD_socket_noninheritable_ (MHD_socket sock)
470int 528int
471MHD_socket_buffering_reset_ (MHD_socket sock) 529MHD_socket_buffering_reset_ (MHD_socket sock)
472{ 530{
473 int res = !0;
474#if defined(TCP_NODELAY) || defined(MHD_TCP_CORK_NOPUSH)
475 const MHD_SCKT_OPT_BOOL_ off_val = 0;
476#if defined(MHD_TCP_CORK_NOPUSH) 531#if defined(MHD_TCP_CORK_NOPUSH)
477 //#if OLD_SOCKOPT 532 int res = ! MHD_socket_set_nodelay_ (sock,
533 true);
478 /* Disable extra buffering */ 534 /* Disable extra buffering */
479 res = (0 == setsockopt (sock, 535 return MHD_socket_cork_ (sock,
480 IPPROTO_TCP, 536 false) && res;
481 MHD_TCP_CORK_NOPUSH, 537#elif defined(HAVE_MSG_MORE)
482 (const void *) &off_val, 538 return ! MHD_socket_set_nodelay_ (sock,
483 sizeof (off_val))) && res; 539 true);
484 //#endif 540#else
541 return ! MHD_socket_set_nodelay_ (sock,
542 false);
485#endif /* MHD_TCP_CORK_NOPUSH */ 543#endif /* MHD_TCP_CORK_NOPUSH */
486#if defined(TCP_NODELAY)
487 //#if OLD_SOCKOPT
488 /* Enable Nagle's algorithm for normal buffering */
489 res = (0 == setsockopt (sock,
490 IPPROTO_TCP,
491 TCP_NODELAY,
492 (const void *) &off_val,
493 sizeof (off_val))) && res;
494 //#endif
495#endif /* TCP_NODELAY */
496#else /* !TCP_NODELAY && !MHD_TCP_CORK_NOPUSH */
497 (void) sock;
498#endif /* !TCP_NODELAY && !MHD_TCP_CORK_NOPUSH */
499 return res;
500} 544}
501 545
502 546
diff --git a/src/microhttpd/mhd_sockets.h b/src/microhttpd/mhd_sockets.h
index a684d71d..08b01c20 100644
--- a/src/microhttpd/mhd_sockets.h
+++ b/src/microhttpd/mhd_sockets.h
@@ -35,6 +35,7 @@
35#include "mhd_options.h" 35#include "mhd_options.h"
36 36
37#include <errno.h> 37#include <errno.h>
38#include <stdbool.h>
38 39
39#if !defined(MHD_POSIX_SOCKETS) && !defined(MHD_WINSOCK_SOCKETS) 40#if !defined(MHD_POSIX_SOCKETS) && !defined(MHD_WINSOCK_SOCKETS)
40# if !defined(_WIN32) || defined(__CYGWIN__) 41# if !defined(_WIN32) || defined(__CYGWIN__)
@@ -745,6 +746,19 @@ MHD_socket_nonblocking_ (MHD_socket sock);
745 746
746 747
747/** 748/**
749 * Disable Nagle's algorithm on @a sock. This is what we do by default for
750 * all TCP sockets in MHD, unless the platform does not support the MSG_MORE
751 * or MSG_CORK or MSG_NOPUSH options.
752 *
753 * @param sock socket to manipulate
754 * @param on value to use
755 * @return 0 on success
756 */
757int
758MHD_socket_set_nodelay_ (MHD_socket sock,
759 bool on);
760
761/**
748 * Change socket options to be non-inheritable. 762 * Change socket options to be non-inheritable.
749 * 763 *
750 * @param sock socket to manipulate 764 * @param sock socket to manipulate
@@ -756,6 +770,30 @@ MHD_socket_noninheritable_ (MHD_socket sock);
756 770
757 771
758/** 772/**
773 * Enable/disable the cork option.
774 *
775 * TCP_NOPUSH has the same logic as MSG_MSG_MORE.
776 * The two are more or less equivalent by a source
777 * transformation (ie
778 * send(MSG_MORE) => "set TCP_NOPUSH + send() + clear TCP_NOPUSH".
779 * Both of them are really fairly "local", but TCP_NOPUSH has a
780 * _notion_ of persistency that is entirely lacking in MSG_MORE.
781 * ... with TCP_NOPUSH you basically have to know what your last
782 * write is, and clear the bit _before_ that write if you want
783 * to avoid bad latencies.
784 *
785 * See also: https://yarchive.net/comp/linux/sendfile.html
786 *
787 * @param sock socket to manipulate
788 * @param on set to true to enable CORK, false to disable
789 * @return non-zero if succeeded, zero otherwise
790 */
791int
792MHD_socket_cork_ (MHD_socket sock,
793 bool on);
794
795
796/**
759 * Change socket buffering mode to default. 797 * Change socket buffering mode to default.
760 * 798 *
761 * @param sock socket to manipulate 799 * @param sock socket to manipulate