aboutsummaryrefslogtreecommitdiff
path: root/src/microhttpd/mhd_send.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2019-08-01 18:05:17 +0200
committerChristian Grothoff <christian@grothoff.org>2019-08-01 18:05:17 +0200
commitb8f3cf79d55cbf985780e6ccec0b0aec74160ce2 (patch)
tree69ba17440229fd9de30c2e95572240a3664fcc1a /src/microhttpd/mhd_send.c
parent8ad5fab2e8173476b78c3fda9a416540b925cd0f (diff)
downloadlibmicrohttpd-b8f3cf79d55cbf985780e6ccec0b0aec74160ce2.tar.gz
libmicrohttpd-b8f3cf79d55cbf985780e6ccec0b0aec74160ce2.zip
fixes, comments, FIXMEs
Diffstat (limited to 'src/microhttpd/mhd_send.c')
-rw-r--r--src/microhttpd/mhd_send.c147
1 files changed, 94 insertions, 53 deletions
diff --git a/src/microhttpd/mhd_send.c b/src/microhttpd/mhd_send.c
index a41586d9..10cb97cb 100644
--- a/src/microhttpd/mhd_send.c
+++ b/src/microhttpd/mhd_send.c
@@ -51,8 +51,6 @@ pre_cork_setsockopt (struct MHD_Connection *connection,
51#if HAVE_MSG_MORE 51#if HAVE_MSG_MORE
52#else 52#else
53 int ret; 53 int ret;
54 const MHD_SCKT_OPT_BOOL_ off_val = 0;
55 const MHD_SCKT_OPT_BOOL_ on_val = 1;
56 54
57 /* If sk_cork_on is already what we pass in, return. */ 55 /* If sk_cork_on is already what we pass in, return. */
58 if (connection->sk_cork_on == want_cork) 56 if (connection->sk_cork_on == want_cork)
@@ -64,33 +62,72 @@ pre_cork_setsockopt (struct MHD_Connection *connection,
64 ret = -1; 62 ret = -1;
65#if TCP_CORK 63#if TCP_CORK
66 if (want_cork) 64 if (want_cork)
65 {
66 const MHD_SCKT_OPT_BOOL_ on_val = 1;
67
67 ret = setsockopt (connection->socket_fd, 68 ret = setsockopt (connection->socket_fd,
68 IPPROTO_TCP, 69 IPPROTO_TCP,
69 TCP_CORK, 70 TCP_CORK,
70 (const void *) &on_val, 71 (const void *) &on_val,
71 sizeof (on_val)); 72 sizeof (on_val));
73 }
72#elif TCP_NODELAY 74#elif TCP_NODELAY
73 ret = setsockopt (connection->socket_fd, 75 {
74 IPPROTO_TCP, 76 const MHD_SCKT_OPT_BOOL_ off_val = 0;
75 TCP_NODELAY, 77 const MHD_SCKT_OPT_BOOL_ on_val = 1;
76 (const void *) want_cork ? &off_val : &on_val, 78
77 sizeof (on_val)); 79 ret = setsockopt (connection->socket_fd,
80 IPPROTO_TCP,
81 TCP_NODELAY,
82 (const void *) want_cork ? &off_val : &on_val,
83 sizeof (on_val));
84 }
78#elif TCP_NOPUSH 85#elif TCP_NOPUSH
79 ret = setsockopt (connection->socket_fd, 86 {
80 IPPROTO_TCP, 87 const MHD_SCKT_OPT_BOOL_ on_val = 1;
81 TCP_NOPUSH,
82 (const void *) &on_val,
83 sizeof (on_val));
84#endif
85 88
89 // FIXME: this must be wrong, set unconditionally irrespective of 'want_cork'!
90 ret = setsockopt (connection->socket_fd,
91 IPPROTO_TCP,
92 TCP_NOPUSH,
93 (const void *) &on_val,
94 sizeof (on_val));
95 }
96#endif
86 if (0 == ret) 97 if (0 == ret)
87 { 98 {
88 connection->sk_cork_on = want_cork; 99 connection->sk_cork_on = want_cork;
89 } 100 }
101 else
102 {
103 switch (errno)
104 {
105 case ENOTSOCK:
106 /* FIXME: Could be we are talking to a pipe, maybe remember this
107 and avoid all setsockopt() in the future? */
108 break;
109 case EBADF:
110 /* FIXME: should we die hard here? */
111 break;
112 case EINVAL:
113 /* FIXME: optlen invalid, should at least log this, maybe die */
114 break;
115 case EFAULT:
116 /* FIXME: wopsie, should at leats log this, maybe die */
117 break;
118 case ENOPROTOOPT:
119 /* FIXME: optlen unknown, should at least log this */
120 break;
121 default:
122 /* any others? man page does not list more... */
123 break;
124 }
125 }
90 return; 126 return;
91#endif /* MSG_MORE */ 127#endif /* MSG_MORE */
92} 128}
93 129
130
94/** 131/**
95 * Handle setsockopt calls. 132 * Handle setsockopt calls.
96 * 133 *
@@ -104,8 +141,6 @@ post_cork_setsockopt (struct MHD_Connection *connection,
104#if HAVE_MSG_MORE 141#if HAVE_MSG_MORE
105#else 142#else
106 int ret; 143 int ret;
107 const MHD_SCKT_OPT_BOOL_ off_val = 0;
108 const MHD_SCKT_OPT_BOOL_ on_val = 1;
109 144
110 /* If sk_cork_on is already what we pass in, return. */ 145 /* If sk_cork_on is already what we pass in, return. */
111 if (connection->sk_cork_on == want_cork) 146 if (connection->sk_cork_on == want_cork)
@@ -116,19 +151,29 @@ post_cork_setsockopt (struct MHD_Connection *connection,
116 ret = -1; 151 ret = -1;
117#if TCP_CORK 152#if TCP_CORK
118 if (! want_cork) 153 if (! want_cork)
154 {
155 const MHD_SCKT_OPT_BOOL_ off_val = 0;
156
119 ret = setsockopt (connection->socket_fd, 157 ret = setsockopt (connection->socket_fd,
120 IPPROTO_TCP, 158 IPPROTO_TCP,
121 TCP_CORK, 159 TCP_CORK,
122 &off_val, 160 &off_val,
123 sizeof (off_val)); 161 sizeof (off_val));
162 }
124#elif TCP_NODELAY 163#elif TCP_NODELAY
125 /* nothing to do */ 164 /* nothing to do */
126#elif TCP_NOPUSH 165#elif TCP_NOPUSH
127 ret = setsockopt (connection->socket_fd, 166 // FIXME: this must be wrong, set unconditionally irrespective of 'want_cork'!
128 IPPROTO_TCP, 167 {
129 TCP_NOPUSH, 168 const MHD_SCKT_OPT_BOOL_ off_val = 0;
130 (const void *) &off_val, 169 const MHD_SCKT_OPT_BOOL_ on_val = 1;
131 sizeof (off_val)); 170
171 ret = setsockopt (connection->socket_fd,
172 IPPROTO_TCP,
173 TCP_NOPUSH,
174 (const void *) &off_val,
175 sizeof (off_val));
176 }
132#endif 177#endif
133 if (0 == ret) 178 if (0 == ret)
134 { 179 {
@@ -138,6 +183,7 @@ post_cork_setsockopt (struct MHD_Connection *connection,
138#endif /* MSG_MORE */ 183#endif /* MSG_MORE */
139} 184}
140 185
186
141/** 187/**
142 * Send buffer on connection, and remember the current state of 188 * Send buffer on connection, and remember the current state of
143 * the socket options; only call setsockopt when absolutely 189 * the socket options; only call setsockopt when absolutely
@@ -164,11 +210,8 @@ MHD_send_on_connection_ (struct MHD_Connection *connection,
164 enum MHD_SendSocketOptions options) 210 enum MHD_SendSocketOptions options)
165{ 211{
166 bool want_cork; 212 bool want_cork;
167 bool using_tls = false;
168 MHD_socket s = connection->socket_fd; 213 MHD_socket s = connection->socket_fd;
169 ssize_t ret; 214 ssize_t ret;
170 const MHD_SCKT_OPT_BOOL_ off_val = 0;
171 const MHD_SCKT_OPT_BOOL_ on_val = 1;
172 215
173 /* error handling from send_param_adapter() */ 216 /* error handling from send_param_adapter() */
174 if ((MHD_INVALID_SOCKET == s) || (MHD_CONNECTION_CLOSED == connection->state)) 217 if ((MHD_INVALID_SOCKET == s) || (MHD_CONNECTION_CLOSED == connection->state))
@@ -197,21 +240,15 @@ MHD_send_on_connection_ (struct MHD_Connection *connection,
197 break; 240 break;
198 } 241 }
199 242
200 /* ! could be avoided by redefining the variable. */
201 // bool have_cork = ! connection->sk_tcp_nodelay_on;
202 bool have_cork = ! connection->sk_cork_on;
203
204#ifdef HTTPS_SUPPORT
205 using_tls = (0 != (connection->daemon->options & MHD_USE_TLS));
206#endif
207
208#ifdef HTTPS_SUPPORT 243#ifdef HTTPS_SUPPORT
209 if (using_tls) 244 if (0 != (connection->daemon->options & MHD_USE_TLS))
210 { 245 {
246 bool have_cork = connection->sk_cork_on;
247
211 if (want_cork && ! have_cork) 248 if (want_cork && ! have_cork)
212 { 249 {
213 gnutls_record_cork (connection->tls_session); 250 gnutls_record_cork (connection->tls_session);
214 connection->sk_cork_on = false; 251 connection->sk_cork_on = true;
215 } 252 }
216 if (buffer_size > SSIZE_MAX) 253 if (buffer_size > SSIZE_MAX)
217 buffer_size = SSIZE_MAX; 254 buffer_size = SSIZE_MAX;
@@ -242,7 +279,7 @@ MHD_send_on_connection_ (struct MHD_Connection *connection,
242 if (! want_cork && have_cork) 279 if (! want_cork && have_cork)
243 { 280 {
244 (void) gnutls_record_uncork (connection->tls_session, 0); 281 (void) gnutls_record_uncork (connection->tls_session, 0);
245 connection->sk_cork_on = true; 282 connection->sk_cork_on = false;
246 } 283 }
247 } 284 }
248 else 285 else
@@ -285,8 +322,8 @@ MHD_send_on_connection_ (struct MHD_Connection *connection,
285 else if (buffer_size > (size_t) ret) 322 else if (buffer_size > (size_t) ret)
286 connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; 323 connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
287#endif /* EPOLL_SUPPORT */ 324#endif /* EPOLL_SUPPORT */
288 325 if (ret == buffer_size)
289 post_cork_setsockopt (connection, want_cork); 326 post_cork_setsockopt (connection, want_cork);
290 } 327 }
291 328
292 return ret; 329 return ret;
@@ -319,28 +356,26 @@ MHD_send_on_connection2_ (struct MHD_Connection *connection,
319{ 356{
320#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV) 357#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
321 MHD_socket s = connection->socket_fd; 358 MHD_socket s = connection->socket_fd;
322 bool want_cork;
323 int iovcnt; 359 int iovcnt;
324 int eno;
325 ssize_t ret; 360 ssize_t ret;
326 const MHD_SCKT_OPT_BOOL_ off_val = 0;
327 struct iovec vector[2]; 361 struct iovec vector[2];
328 362
329 want_cork = ! connection->sk_cork_on; 363 /* Since we generally give the fully answer, we do not want
330 364 corking to happen */
331 pre_cork_setsockopt (connection, want_cork); 365 pre_cork_setsockopt (connection, false);
332 366
333 vector[0].iov_base = (void *) header; 367 vector[0].iov_base = (void *) header;
334 vector[0].iov_len = strlen (header); 368 vector[0].iov_len = header_size;
335 vector[1].iov_base = (void *) buffer; 369 vector[1].iov_base = (void *) buffer;
336 vector[1].iov_len = strlen (buffer); 370 vector[1].iov_len = buffer_size;
337 371
338#if HAVE_SENDMSG 372#if HAVE_SENDMSG
339 struct msghdr msg; 373 {
340 memset(&msg, 0, sizeof(struct msghdr)); 374 struct msghdr msg;
341 375
342 msg.msg_iov = vector; 376 memset(&msg, 0, sizeof(struct msghdr));
343 msg.msg_iovlen = 2; 377 msg.msg_iov = vector;
378 msg.msg_iovlen = 2;
344 379
345 /* 380 /*
346 * questionable for this case, bus maybe worth considering for now: 381 * questionable for this case, bus maybe worth considering for now:
@@ -349,21 +384,23 @@ MHD_send_on_connection2_ (struct MHD_Connection *connection,
349 * If you set msg_control to nonnull, NetBSD expects you to have 384 * If you set msg_control to nonnull, NetBSD expects you to have
350 * msg_controllen > 0. (sys/kern/uipc_syscalls.c in do_sys_sendmsg_so) 385 * msg_controllen > 0. (sys/kern/uipc_syscalls.c in do_sys_sendmsg_so)
351 * for reference. Thanks to pDNS (for FreeBSD), Riastradh for NetBSD. 386 * for reference. Thanks to pDNS (for FreeBSD), Riastradh for NetBSD.
387 * FIXME: this is unnecessary, see the memset() above?
352 */ 388 */
353 /* 389 /*
354 msg.msg_control = 0; 390 msg.msg_control = 0;
355 msg.msg_controllen = 0; 391 msg.msg_controllen = 0;
356 */ 392 */
357 ret = sendmsg (s, &msg, MAYBE_MSG_NOSIGNAL); 393 ret = sendmsg (s, &msg, MAYBE_MSG_NOSIGNAL);
394 }
358#elif HAVE_WRITEV 395#elif HAVE_WRITEV
359 iovcnt = sizeof (vector) / sizeof (struct iovec); 396 iovcnt = sizeof (vector) / sizeof (struct iovec);
360 ret = writev (s, vector, iovcnt); 397 ret = writev (s, vector, iovcnt);
361#endif 398#endif
362 399
400 /* Only if we succeeded sending the full buffer, we need to make sure that
401 the OS flushes at the end */
363 if (ret == header_size + buffer_size) 402 if (ret == header_size + buffer_size)
364 want_cork = false; 403 post_cork_setsockopt (connection, false);
365
366 post_cork_setsockopt (connection, want_cork);
367 404
368 return ret; 405 return ret;
369 406
@@ -407,6 +444,7 @@ static int freebsd_sendfile_flags_thd_p_c_;
407 * @param connection the MHD connection structure 444 * @param connection the MHD connection structure
408 * @return actual number of bytes sent 445 * @return actual number of bytes sent
409 */ 446 */
447// FIXME: rename...
410ssize_t 448ssize_t
411sendfile_adapter (struct MHD_Connection *connection) 449sendfile_adapter (struct MHD_Connection *connection)
412{ 450{
@@ -579,7 +617,10 @@ sendfile_adapter (struct MHD_Connection *connection)
579 ret = (ssize_t)len; 617 ret = (ssize_t)len;
580#endif /* HAVE_FREEBSD_SENDFILE */ 618#endif /* HAVE_FREEBSD_SENDFILE */
581 619
582 post_cork_setsockopt (connection, false); 620 /* Make sure we send the data without delay ONLY if we
621 provided the complete response (not on partial write) */
622 if (ret == left)
623 post_cork_setsockopt (connection, false);
583 624
584 return ret; 625 return ret;
585} 626}