diff options
author | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2020-12-13 18:35:27 +0300 |
---|---|---|
committer | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2020-12-13 18:35:27 +0300 |
commit | 005c7686995e68700032f178e3919c10e19047d9 (patch) | |
tree | 8e7d07a796409190bd8d914e8dc9cadde2b10f26 | |
parent | ee8b31980686e127a36684073a5d411c7657671d (diff) | |
download | libmicrohttpd-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.c | 54 |
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(). */ |