aboutsummaryrefslogtreecommitdiff
path: root/src/microhttpd/mhd_send.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/microhttpd/mhd_send.c')
-rw-r--r--src/microhttpd/mhd_send.c347
1 files changed, 176 insertions, 171 deletions
diff --git a/src/microhttpd/mhd_send.c b/src/microhttpd/mhd_send.c
index b3fb25da..e50be96e 100644
--- a/src/microhttpd/mhd_send.c
+++ b/src/microhttpd/mhd_send.c
@@ -55,68 +55,69 @@ pre_cork_setsockopt (struct MHD_Connection *connection,
55 55
56 /* If sk_cork_on is already what we pass in, return. */ 56 /* If sk_cork_on is already what we pass in, return. */
57 if (connection->sk_cork_on == want_cork) 57 if (connection->sk_cork_on == want_cork)
58 { 58 {
59 /* nothing to do, success! */ 59 /* nothing to do, success! */
60 return; 60 return;
61 } 61 }
62 if (! want_cork) 62 if (! want_cork)
63 return; /* nothing to do *pre* syscall! */ 63 return; /* nothing to do *pre* syscall! */
64 ret = MHD_socket_cork_ (connection->socket_fd, 64 ret = MHD_socket_cork_ (connection->socket_fd,
65 true); 65 true);
66 if (0 == ret) 66 if (0 == ret)
67 { 67 {
68 connection->sk_cork_on = true; 68 connection->sk_cork_on = true;
69 return; 69 return;
70 } 70 }
71 switch (errno) 71 switch (errno)
72 { 72 {
73 case ENOTSOCK: 73 case ENOTSOCK:
74 /* FIXME: Could be we are talking to a pipe, maybe remember this 74 /* FIXME: Could be we are talking to a pipe, maybe remember this
75 and avoid all setsockopt() in the future? */ 75 and avoid all setsockopt() in the future? */
76 break; 76 break;
77 case EBADF: 77 case EBADF:
78 /* FIXME: should we die hard here? */ 78 /* FIXME: should we die hard here? */
79 break; 79 break;
80 case EINVAL: 80 case EINVAL:
81 /* FIXME: optlen invalid, should at least log this, maybe die */ 81 /* FIXME: optlen invalid, should at least log this, maybe die */
82#ifdef HAVE_MESSAGES 82#ifdef HAVE_MESSAGES
83 MHD_DLOG (daemon, 83 MHD_DLOG (daemon,
84 _("optlen invalid: %s\n"), 84 _ ("optlen invalid: %s\n"),
85 MHD_socket_last_strerr_()); 85 MHD_socket_last_strerr_ ());
86#endif 86#endif
87 break; 87 break;
88 case EFAULT: 88 case EFAULT:
89 /* wopsie, should at leats log this, FIXME: maybe die */ 89 /* wopsie, should at leats log this, FIXME: maybe die */
90#ifdef HAVE_MESSAGES 90#ifdef HAVE_MESSAGES
91 MHD_DLOG (daemon, 91 MHD_DLOG (daemon,
92 _("The addresss pointed to by optval is not a valid part of the process address space: %s\n"), 92 _ (
93 MHD_socket_last_strerr_()); 93 "The addresss pointed to by optval is not a valid part of the process address space: %s\n"),
94 MHD_socket_last_strerr_ ());
94#endif 95#endif
95 break; 96 break;
96 case ENOPROTOOPT: 97 case ENOPROTOOPT:
97 /* optlen unknown, should at least log this */ 98 /* optlen unknown, should at least log this */
98#ifdef HAVE_MESSAGES 99#ifdef HAVE_MESSAGES
99 MHD_DLOG (daemon, 100 MHD_DLOG (daemon,
100 _("The option is unknown: %s\n"), 101 _ ("The option is unknown: %s\n"),
101 MHD_socket_last_strerr_()); 102 MHD_socket_last_strerr_ ());
102#endif 103#endif
103 break; 104 break;
104 default: 105 default:
105 /* any others? man page does not list more... */ 106 /* any others? man page does not list more... */
106 break; 107 break;
107 } 108 }
108#else 109#else
109 /* CORK/NOPUSH/MSG_MORE do not exist on this platform, 110 /* CORK/NOPUSH/MSG_MORE do not exist on this platform,
110 so we must toggle Naggle's algorithm on/off instead 111 so we must toggle Naggle's algorithm on/off instead
111 (otherwise we keep it always off) */ 112 (otherwise we keep it always off) */
112 if (connection->sk_cork_on == want_cork) 113 if (connection->sk_cork_on == want_cork)
113 { 114 {
114 /* nothing to do, success! */ 115 /* nothing to do, success! */
115 return; 116 return;
116 } 117 }
117 if ( (want_cork) && 118 if ( (want_cork) &&
118 (0 == MHD_socket_set_nodelay_ (connection->socket_fd, 119 (0 == MHD_socket_set_nodelay_ (connection->socket_fd,
119 false)) ) 120 false)) )
120 connection->sk_cork_on = true; 121 connection->sk_cork_on = true;
121#endif 122#endif
122} 123}
@@ -139,10 +140,10 @@ post_cork_setsockopt (struct MHD_Connection *connection,
139 140
140 /* If sk_cork_on is already what we pass in, return. */ 141 /* If sk_cork_on is already what we pass in, return. */
141 if (connection->sk_cork_on == want_cork) 142 if (connection->sk_cork_on == want_cork)
142 { 143 {
143 /* nothing to do, success! */ 144 /* nothing to do, success! */
144 return; 145 return;
145 } 146 }
146 if (want_cork) 147 if (want_cork)
147 return; /* nothing to do *post* syscall (in fact, we should never 148 return; /* nothing to do *post* syscall (in fact, we should never
148 get here, as sk_cork_on should have succeeded in the 149 get here, as sk_cork_on should have succeeded in the
@@ -150,59 +151,60 @@ post_cork_setsockopt (struct MHD_Connection *connection,
150 ret = MHD_socket_cork_ (connection->socket_fd, 151 ret = MHD_socket_cork_ (connection->socket_fd,
151 false); 152 false);
152 if (0 == ret) 153 if (0 == ret)
153 { 154 {
154 connection->sk_cork_on = false; 155 connection->sk_cork_on = false;
155 return; 156 return;
156 } 157 }
157 switch (errno) 158 switch (errno)
158 { 159 {
159 case ENOTSOCK: 160 case ENOTSOCK:
160 /* FIXME: Could be we are talking to a pipe, maybe remember this 161 /* FIXME: Could be we are talking to a pipe, maybe remember this
161 and avoid all setsockopt() in the future? */ 162 and avoid all setsockopt() in the future? */
162 break; 163 break;
163 case EBADF: 164 case EBADF:
164 /* FIXME: should we die hard here? */ 165 /* FIXME: should we die hard here? */
165 break; 166 break;
166 case EINVAL: 167 case EINVAL:
167 /* FIXME: optlen invalid, should at least log this, maybe die */ 168 /* FIXME: optlen invalid, should at least log this, maybe die */
168#ifdef HAVE_MESSAGES 169#ifdef HAVE_MESSAGES
169 MHD_DLOG (daemon, 170 MHD_DLOG (daemon,
170 _("optlen invalid: %s\n"), 171 _ ("optlen invalid: %s\n"),
171 MHD_socket_last_strerr_()); 172 MHD_socket_last_strerr_ ());
172#endif 173#endif
173 break; 174 break;
174 case EFAULT: 175 case EFAULT:
175 /* wopsie, should at leats log this, FIXME: maybe die */ 176 /* wopsie, should at leats log this, FIXME: maybe die */
176#ifdef HAVE_MESSAGES 177#ifdef HAVE_MESSAGES
177 MHD_DLOG (daemon, 178 MHD_DLOG (daemon,
178 _("The addresss pointed to by optval is not a valid part of the process address space: %s\n"), 179 _ (
179 MHD_socket_last_strerr_()); 180 "The addresss pointed to by optval is not a valid part of the process address space: %s\n"),
181 MHD_socket_last_strerr_ ());
180#endif 182#endif
181 break; 183 break;
182 case ENOPROTOOPT: 184 case ENOPROTOOPT:
183 /* optlen unknown, should at least log this */ 185 /* optlen unknown, should at least log this */
184#ifdef HAVE_MESSAGES 186#ifdef HAVE_MESSAGES
185 MHD_DLOG (daemon, 187 MHD_DLOG (daemon,
186 _("The option is unknown: %s\n"), 188 _ ("The option is unknown: %s\n"),
187 MHD_socket_last_strerr_()); 189 MHD_socket_last_strerr_ ());
188#endif 190#endif
189 break; 191 break;
190 default: 192 default:
191 /* any others? man page does not list more... */ 193 /* any others? man page does not list more... */
192 break; 194 break;
193 } 195 }
194#else 196#else
195 /* CORK/NOPUSH/MSG_MORE do not exist on this platform, 197 /* CORK/NOPUSH/MSG_MORE do not exist on this platform,
196 so we must toggle Naggle's algorithm on/off instead 198 so we must toggle Naggle's algorithm on/off instead
197 (otherwise we keep it always off) */ 199 (otherwise we keep it always off) */
198 if (connection->sk_cork_on == want_cork) 200 if (connection->sk_cork_on == want_cork)
199 { 201 {
200 /* nothing to do, success! */ 202 /* nothing to do, success! */
201 return; 203 return;
202 } 204 }
203 if ( (! want_cork) && 205 if ( (! want_cork) &&
204 (0 == MHD_socket_set_nodelay_ (connection->socket_fd, 206 (0 == MHD_socket_set_nodelay_ (connection->socket_fd,
205 true)) ) 207 true)) )
206 connection->sk_cork_on = false; 208 connection->sk_cork_on = false;
207#endif 209#endif
208} 210}
@@ -403,7 +405,7 @@ MHD_send_on_connection2_ (struct MHD_Connection *connection,
403 { 405 {
404 struct msghdr msg; 406 struct msghdr msg;
405 407
406 memset(&msg, 0, sizeof(struct msghdr)); 408 memset (&msg, 0, sizeof(struct msghdr));
407 msg.msg_iov = vector; 409 msg.msg_iov = vector;
408 msg.msg_iovlen = 2; 410 msg.msg_iovlen = 2;
409 411
@@ -473,9 +475,9 @@ MHD_send_sendfile_ (struct MHD_Connection *connection)
473 uint64_t left; 475 uint64_t left;
474 uint64_t offsetu64; 476 uint64_t offsetu64;
475#ifndef HAVE_SENDFILE64 477#ifndef HAVE_SENDFILE64
476 const uint64_t max_off_t = (uint64_t)OFF_T_MAX; 478 const uint64_t max_off_t = (uint64_t) OFF_T_MAX;
477#else /* HAVE_SENDFILE64 */ 479#else /* HAVE_SENDFILE64 */
478 const uint64_t max_off_t = (uint64_t)OFF64_T_MAX; 480 const uint64_t max_off_t = (uint64_t) OFF64_T_MAX;
479#endif /* HAVE_SENDFILE64 */ 481#endif /* HAVE_SENDFILE64 */
480#ifdef MHD_LINUX_SOLARIS_SENDFILE 482#ifdef MHD_LINUX_SOLARIS_SENDFILE
481#ifndef HAVE_SENDFILE64 483#ifndef HAVE_SENDFILE64
@@ -491,23 +493,26 @@ MHD_send_sendfile_ (struct MHD_Connection *connection)
491#ifdef HAVE_DARWIN_SENDFILE 493#ifdef HAVE_DARWIN_SENDFILE
492 off_t len; 494 off_t len;
493#endif /* HAVE_DARWIN_SENDFILE */ 495#endif /* HAVE_DARWIN_SENDFILE */
494 const bool used_thr_p_c = (0 != (connection->daemon->options & MHD_USE_THREAD_PER_CONNECTION)); 496 const bool used_thr_p_c = (0 != (connection->daemon->options
495 const size_t chunk_size = used_thr_p_c ? MHD_SENFILE_CHUNK_THR_P_C_ : MHD_SENFILE_CHUNK_; 497 & MHD_USE_THREAD_PER_CONNECTION));
498 const size_t chunk_size = used_thr_p_c ? MHD_SENFILE_CHUNK_THR_P_C_ :
499 MHD_SENFILE_CHUNK_;
496 size_t send_size = 0; 500 size_t send_size = 0;
497 mhd_assert (MHD_resp_sender_sendfile == connection->resp_sender); 501 mhd_assert (MHD_resp_sender_sendfile == connection->resp_sender);
498 502
499 pre_cork_setsockopt (connection, false); 503 pre_cork_setsockopt (connection, false);
500 504
501 offsetu64 = connection->response_write_position + connection->response->fd_off; 505 offsetu64 = connection->response_write_position
506 + connection->response->fd_off;
502 left = connection->response->total_size - connection->response_write_position; 507 left = connection->response->total_size - connection->response_write_position;
503 /* Do not allow system to stick sending on single fast connection: 508 /* Do not allow system to stick sending on single fast connection:
504 * use 128KiB chunks (2MiB for thread-per-connection). */ 509 * use 128KiB chunks (2MiB for thread-per-connection). */
505 send_size = (left > chunk_size) ? chunk_size : (size_t) left; 510 send_size = (left > chunk_size) ? chunk_size : (size_t) left;
506 if (max_off_t < offsetu64) 511 if (max_off_t < offsetu64)
507 { /* Retry to send with standard 'send()'. */ 512 { /* Retry to send with standard 'send()'. */
508 connection->resp_sender = MHD_resp_sender_std; 513 connection->resp_sender = MHD_resp_sender_std;
509 return MHD_ERR_AGAIN_; 514 return MHD_ERR_AGAIN_;
510 } 515 }
511#ifdef MHD_LINUX_SOLARIS_SENDFILE 516#ifdef MHD_LINUX_SOLARIS_SENDFILE
512#ifndef HAVE_SENDFILE64 517#ifndef HAVE_SENDFILE64
513 offset = (off_t) offsetu64; 518 offset = (off_t) offsetu64;
@@ -523,53 +528,53 @@ MHD_send_sendfile_ (struct MHD_Connection *connection)
523 send_size); 528 send_size);
524#endif /* HAVE_SENDFILE64 */ 529#endif /* HAVE_SENDFILE64 */
525 if (0 > ret) 530 if (0 > ret)
531 {
532 const int err = MHD_socket_get_error_ ();
533 if (MHD_SCKT_ERR_IS_EAGAIN_ (err))
526 { 534 {
527 const int err = MHD_socket_get_error_();
528 if (MHD_SCKT_ERR_IS_EAGAIN_(err))
529 {
530#ifdef EPOLL_SUPPORT 535#ifdef EPOLL_SUPPORT
531 /* EAGAIN --- no longer write-ready */ 536 /* EAGAIN --- no longer write-ready */
532 connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; 537 connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
533#endif /* EPOLL_SUPPORT */ 538#endif /* EPOLL_SUPPORT */
534 return MHD_ERR_AGAIN_; 539 return MHD_ERR_AGAIN_;
535 } 540 }
536 if (MHD_SCKT_ERR_IS_EINTR_ (err)) 541 if (MHD_SCKT_ERR_IS_EINTR_ (err))
537 return MHD_ERR_AGAIN_; 542 return MHD_ERR_AGAIN_;
538#ifdef HAVE_LINUX_SENDFILE 543#ifdef HAVE_LINUX_SENDFILE
539 if (MHD_SCKT_ERR_IS_(err, 544 if (MHD_SCKT_ERR_IS_ (err,
540 MHD_SCKT_EBADF_)) 545 MHD_SCKT_EBADF_))
541 return MHD_ERR_BADF_; 546 return MHD_ERR_BADF_;
542 /* sendfile() failed with EINVAL if mmap()-like operations are not 547 /* sendfile() failed with EINVAL if mmap()-like operations are not
543 supported for FD or other 'unusual' errors occurred, so we should try 548 supported for FD or other 'unusual' errors occurred, so we should try
544 to fall back to 'SEND'; see also this thread for info on 549 to fall back to 'SEND'; see also this thread for info on
545 odd libc/Linux behavior with sendfile: 550 odd libc/Linux behavior with sendfile:
546 http://lists.gnu.org/archive/html/libmicrohttpd/2011-02/msg00015.html */ 551 http://lists.gnu.org/archive/html/libmicrohttpd/2011-02/msg00015.html */
552 connection->resp_sender = MHD_resp_sender_std;
553 return MHD_ERR_AGAIN_;
554#else /* HAVE_SOLARIS_SENDFILE */
555 if ( (EAFNOSUPPORT == err) ||
556 (EINVAL == err) ||
557 (EOPNOTSUPP == err) )
558 { /* Retry with standard file reader. */
547 connection->resp_sender = MHD_resp_sender_std; 559 connection->resp_sender = MHD_resp_sender_std;
548 return MHD_ERR_AGAIN_; 560 return MHD_ERR_AGAIN_;
549#else /* HAVE_SOLARIS_SENDFILE */
550 if ( (EAFNOSUPPORT == err) ||
551 (EINVAL == err) ||
552 (EOPNOTSUPP == err) )
553 { /* Retry with standard file reader. */
554 connection->resp_sender = MHD_resp_sender_std;
555 return MHD_ERR_AGAIN_;
556 }
557 if ( (ENOTCONN == err) ||
558 (EPIPE == err) )
559 {
560 return MHD_ERR_CONNRESET_;
561 }
562 return MHD_ERR_BADF_; /* Fail hard */
563#endif /* HAVE_SOLARIS_SENDFILE */
564 } 561 }
562 if ( (ENOTCONN == err) ||
563 (EPIPE == err) )
564 {
565 return MHD_ERR_CONNRESET_;
566 }
567 return MHD_ERR_BADF_; /* Fail hard */
568#endif /* HAVE_SOLARIS_SENDFILE */
569 }
565#ifdef EPOLL_SUPPORT 570#ifdef EPOLL_SUPPORT
566 else if (send_size > (size_t)ret) 571 else if (send_size > (size_t) ret)
567 connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; 572 connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
568#endif /* EPOLL_SUPPORT */ 573#endif /* EPOLL_SUPPORT */
569#elif defined(HAVE_FREEBSD_SENDFILE) 574#elif defined(HAVE_FREEBSD_SENDFILE)
570#ifdef SF_FLAGS 575#ifdef SF_FLAGS
571 flags = used_thr_p_c ? 576 flags = used_thr_p_c ?
572 freebsd_sendfile_flags_thd_p_c_ : freebsd_sendfile_flags_; 577 freebsd_sendfile_flags_thd_p_c_ : freebsd_sendfile_flags_;
573#endif /* SF_FLAGS */ 578#endif /* SF_FLAGS */
574 if (0 != sendfile (file_fd, 579 if (0 != sendfile (file_fd,
575 connection->socket_fd, 580 connection->socket_fd,
@@ -578,63 +583,63 @@ MHD_send_sendfile_ (struct MHD_Connection *connection)
578 NULL, 583 NULL,
579 &sent_bytes, 584 &sent_bytes,
580 flags)) 585 flags))
586 {
587 const int err = MHD_socket_get_error_ ();
588 if (MHD_SCKT_ERR_IS_EAGAIN_ (err) ||
589 MHD_SCKT_ERR_IS_EINTR_ (err) ||
590 (EBUSY == err) )
581 { 591 {
582 const int err = MHD_socket_get_error_(); 592 mhd_assert (SSIZE_MAX >= sent_bytes);
583 if (MHD_SCKT_ERR_IS_EAGAIN_(err) || 593 if (0 != sent_bytes)
584 MHD_SCKT_ERR_IS_EINTR_(err) || 594 return (ssize_t) sent_bytes;
585 EBUSY == err) 595
586 {
587 mhd_assert (SSIZE_MAX >= sent_bytes);
588 if (0 != sent_bytes)
589 return (ssize_t)sent_bytes;
590
591 return MHD_ERR_AGAIN_;
592 }
593 /* Some unrecoverable error. Possibly file FD is not suitable
594 * for sendfile(). Retry with standard send(). */
595 connection->resp_sender = MHD_resp_sender_std;
596 return MHD_ERR_AGAIN_; 596 return MHD_ERR_AGAIN_;
597 } 597 }
598 /* Some unrecoverable error. Possibly file FD is not suitable
599 * for sendfile(). Retry with standard send(). */
600 connection->resp_sender = MHD_resp_sender_std;
601 return MHD_ERR_AGAIN_;
602 }
598 mhd_assert (0 < sent_bytes); 603 mhd_assert (0 < sent_bytes);
599 mhd_assert (SSIZE_MAX >= sent_bytes); 604 mhd_assert (SSIZE_MAX >= sent_bytes);
600 ret = (ssize_t)sent_bytes; 605 ret = (ssize_t) sent_bytes;
601#elif defined(HAVE_DARWIN_SENDFILE) 606#elif defined(HAVE_DARWIN_SENDFILE)
602 len = (off_t)send_size; /* chunk always fit */ 607 len = (off_t) send_size; /* chunk always fit */
603 if (0 != sendfile (file_fd, 608 if (0 != sendfile (file_fd,
604 connection->socket_fd, 609 connection->socket_fd,
605 (off_t) offsetu64, 610 (off_t) offsetu64,
606 &len, 611 &len,
607 NULL, 612 NULL,
608 0)) 613 0))
614 {
615 const int err = MHD_socket_get_error_ ();
616 if (MHD_SCKT_ERR_IS_EAGAIN_ (err) ||
617 MHD_SCKT_ERR_IS_EINTR_ (err))
609 { 618 {
610 const int err = MHD_socket_get_error_(); 619 mhd_assert (0 <= len);
611 if (MHD_SCKT_ERR_IS_EAGAIN_(err) || 620 mhd_assert (SSIZE_MAX >= len);
612 MHD_SCKT_ERR_IS_EINTR_(err)) 621 mhd_assert (send_size >= (size_t) len);
613 { 622 if (0 != len)
614 mhd_assert (0 <= len); 623 return (ssize_t) len;
615 mhd_assert (SSIZE_MAX >= len); 624
616 mhd_assert (send_size >= (size_t)len); 625 return MHD_ERR_AGAIN_;
617 if (0 != len) 626 }
618 return (ssize_t)len; 627 if ((ENOTCONN == err) ||
619 628 (EPIPE == err) )
620 return MHD_ERR_AGAIN_; 629 return MHD_ERR_CONNRESET_;
621 } 630 if ((ENOTSUP == err) ||
622 if (ENOTCONN == err || 631 (EOPNOTSUPP == err) )
623 EPIPE == err) 632 { /* This file FD is not suitable for sendfile().
624 return MHD_ERR_CONNRESET_;
625 if (ENOTSUP == err ||
626 EOPNOTSUPP == err)
627 { /* This file FD is not suitable for sendfile().
628 * Retry with standard send(). */ 633 * Retry with standard send(). */
629 connection->resp_sender = MHD_resp_sender_std; 634 connection->resp_sender = MHD_resp_sender_std;
630 return MHD_ERR_AGAIN_; 635 return MHD_ERR_AGAIN_;
631 }
632 return MHD_ERR_BADF_; /* Return hard error. */
633 } 636 }
637 return MHD_ERR_BADF_; /* Return hard error. */
638 }
634 mhd_assert (0 <= len); 639 mhd_assert (0 <= len);
635 mhd_assert (SSIZE_MAX >= len); 640 mhd_assert (SSIZE_MAX >= len);
636 mhd_assert (send_size >= (size_t)len); 641 mhd_assert (send_size >= (size_t) len);
637 ret = (ssize_t)len; 642 ret = (ssize_t) len;
638#endif /* HAVE_FREEBSD_SENDFILE */ 643#endif /* HAVE_FREEBSD_SENDFILE */
639 644
640 /* Make sure we send the data without delay ONLY if we 645 /* Make sure we send the data without delay ONLY if we