aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeny Grin (Karlson2k) <k2k@narod.ru>2020-12-13 18:35:27 +0300
committerEvgeny Grin (Karlson2k) <k2k@narod.ru>2020-12-13 18:35:27 +0300
commit005c7686995e68700032f178e3919c10e19047d9 (patch)
tree8e7d07a796409190bd8d914e8dc9cadde2b10f26
parentee8b31980686e127a36684073a5d411c7657671d (diff)
downloadlibmicrohttpd-005c7686995e68700032f178e3919c10e19047d9.tar.gz
libmicrohttpd-005c7686995e68700032f178e3919c10e19047d9.zip
mhd_send.c: fixed: properly handle send errors
Fixed busy-waiting with epoll and sendmsg().
-rw-r--r--src/microhttpd/mhd_send.c54
1 files changed, 44 insertions, 10 deletions
diff --git a/src/microhttpd/mhd_send.c b/src/microhttpd/mhd_send.c
index d19d4a57..b1c0dda6 100644
--- a/src/microhttpd/mhd_send.c
+++ b/src/microhttpd/mhd_send.c
@@ -727,19 +727,23 @@ MHD_send_on_connection_ (struct MHD_Connection *connection,
727 ret = gnutls_record_send (connection->tls_session, 727 ret = gnutls_record_send (connection->tls_session,
728 buffer, 728 buffer,
729 buffer_size); 729 buffer_size);
730 if ( (GNUTLS_E_AGAIN == ret) || 730 if (GNUTLS_E_AGAIN == ret)
731 (GNUTLS_E_INTERRUPTED == ret) )
732 { 731 {
733#ifdef EPOLL_SUPPORT 732#ifdef EPOLL_SUPPORT
734 if (GNUTLS_E_AGAIN == ret) 733 connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
735 connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
736#endif 734#endif
737 return MHD_ERR_AGAIN_; 735 return MHD_ERR_AGAIN_;
738 } 736 }
737 if (GNUTLS_E_INTERRUPTED == ret)
738 return MHD_ERR_AGAIN_;
739 if ( (GNUTLS_E_ENCRYPTION_FAILED == ret) ||
740 (GNUTLS_E_INVALID_SESSION == ret) )
741 return MHD_ERR_CONNRESET_;
742 if (GNUTLS_E_MEMORY_ERROR == ret)
743 return MHD_ERR_NOMEM_;
739 if (ret < 0) 744 if (ret < 0)
740 { 745 {
741 /* Likely 'GNUTLS_E_INVALID_SESSION' (client communication 746 /* Treat any other error as hard error. */
742 disrupted); interpret as a hard error */
743 return MHD_ERR_NOTCONN_; 747 return MHD_ERR_NOTCONN_;
744 } 748 }
745#ifdef EPOLL_SUPPORT 749#ifdef EPOLL_SUPPORT
@@ -784,6 +788,8 @@ MHD_send_on_connection_ (struct MHD_Connection *connection,
784 return MHD_ERR_AGAIN_; 788 return MHD_ERR_AGAIN_;
785 if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_ECONNRESET_)) 789 if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_ECONNRESET_))
786 return MHD_ERR_CONNRESET_; 790 return MHD_ERR_CONNRESET_;
791 if (MHD_SCKT_ERR_IS_LOW_RESOURCES_ (err))
792 return MHD_ERR_NOMEM_;
787 /* Treat any other error as hard error. */ 793 /* Treat any other error as hard error. */
788 return MHD_ERR_NOTCONN_; 794 return MHD_ERR_NOTCONN_;
789 } 795 }
@@ -819,8 +825,8 @@ MHD_send_hdr_and_body_ (struct MHD_Connection *connection,
819 ssize_t ret; 825 ssize_t ret;
820 bool push_hdr; 826 bool push_hdr;
821 bool push_body; 827 bool push_body;
822#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
823 MHD_socket s = connection->socket_fd; 828 MHD_socket s = connection->socket_fd;
829#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
824 struct iovec vector[2]; 830 struct iovec vector[2];
825#ifdef HAVE_SENDMSG 831#ifdef HAVE_SENDMSG
826 struct msghdr msg; 832 struct msghdr msg;
@@ -833,6 +839,12 @@ MHD_send_hdr_and_body_ (struct MHD_Connection *connection,
833#endif /* HAVE_SENDMSG || HAVE_WRITEV */ 839#endif /* HAVE_SENDMSG || HAVE_WRITEV */
834 mhd_assert ( (NULL != body) || (0 == body_size) ); 840 mhd_assert ( (NULL != body) || (0 == body_size) );
835 841
842 if ( (MHD_INVALID_SOCKET == s) ||
843 (MHD_CONNECTION_CLOSED == connection->state) )
844 {
845 return MHD_ERR_NOTCONN_;
846 }
847
836 push_body = complete_response; 848 push_body = complete_response;
837 849
838 if (! never_push_hdr) 850 if (! never_push_hdr)
@@ -936,9 +948,31 @@ MHD_send_hdr_and_body_ (struct MHD_Connection *connection,
936#elif HAVE_WRITEV 948#elif HAVE_WRITEV
937 ret = writev (s, vector, 2); 949 ret = writev (s, vector, 2);
938#endif 950#endif
939 if ( (-1 == ret) && 951 if (0 > ret)
940 (EAGAIN == errno) ) 952 {
941 return MHD_ERR_AGAIN_; 953 const int err = MHD_socket_get_error_ ();
954
955 if (MHD_SCKT_ERR_IS_EAGAIN_ (err))
956 {
957#if EPOLL_SUPPORT
958 /* EAGAIN, no longer write-ready */
959 connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
960#endif /* EPOLL_SUPPORT */
961 return MHD_ERR_AGAIN_;
962 }
963 if (MHD_SCKT_ERR_IS_EINTR_ (err))
964 return MHD_ERR_AGAIN_;
965 if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_ECONNRESET_))
966 return MHD_ERR_CONNRESET_;
967 if (MHD_SCKT_ERR_IS_LOW_RESOURCES_ (err))
968 return MHD_ERR_NOMEM_;
969 /* Treat any other error as hard error. */
970 return MHD_ERR_NOTCONN_;
971 }
972#if EPOLL_SUPPORT
973 else if ((header_size + body_size) > (size_t) ret)
974 connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
975#endif /* EPOLL_SUPPORT */
942 976
943 /* If there is a need to push the data from network buffers 977 /* If there is a need to push the data from network buffers
944 * call post_send_setopt(). */ 978 * call post_send_setopt(). */