diff options
-rw-r--r-- | src/microhttpd/daemon.c | 14 | ||||
-rw-r--r-- | src/microhttpd/mhd_send.c | 166 | ||||
-rw-r--r-- | src/microhttpd/mhd_sockets.c | 92 | ||||
-rw-r--r-- | src/microhttpd/mhd_sockets.h | 38 |
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 | */ | ||
473 | int | ||
474 | MHD_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 | */ | ||
502 | int | ||
503 | MHD_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) | |||
470 | int | 528 | int |
471 | MHD_socket_buffering_reset_ (MHD_socket sock) | 529 | MHD_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 | */ | ||
757 | int | ||
758 | MHD_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 | */ | ||
791 | int | ||
792 | MHD_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 |