From cbbfd0591fc639ddd21a5850f54f403fb7394174 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 17 Oct 2019 16:52:29 +0200 Subject: presumably last touches on ng0's GSoC setsockopt refactoring --- ChangeLog | 4 + src/microhttpd/connection.c | 63 ---------- src/microhttpd/mhd_sockets.c | 282 +++++++++++++++++++++++-------------------- 3 files changed, 156 insertions(+), 193 deletions(-) diff --git a/ChangeLog b/ChangeLog index b25b9365..1e890e9d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +Thu 17 Oct 2019 04:50:52 PM CEST + Integrate 0-byte send() method for uncorking for old FreeBSD/OS X + systems into new mhd_send.c logic for uncorking. -CG + Fri 18 Aug 2019 00:00:00 PM UTC Fixes and optimizations for the setsockopt handling: * Added: MHD_UPGRADE_ACTION_CORK_ON and MHD_UPGRADE_ACTION_CORK_OFF diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c index 901cac0e..11c7099a 100644 --- a/src/microhttpd/connection.c +++ b/src/microhttpd/connection.c @@ -283,66 +283,6 @@ send_param_adapter (struct MHD_Connection *connection, } -/** - * Check whether is possible to force push socket buffer content as - * partial packet. - * MHD use different buffering logic depending on whether flushing of - * socket buffer is possible or not. - * If flushing IS possible than MHD activates extra buffering before - * sending data to prevent sending partial packets and flush pending - * data in socket buffer to push last partial packet to client after - * sending logical completed part of data (for example: after sending - * full response header or full response message). - * If flushing IS NOT possible than MHD activates no buffering (no - * delay sending) when it going to send formed fully completed logical - * part of data and activate normal buffering after sending. - * For idled keep-alive connection MHD always activate normal - * buffering. - * - * @param connection connection to check - * @return true if force push is possible, false otherwise - */ -_MHD_static_inline bool -socket_flush_possible (struct MHD_Connection *connection) -{ - (void) connection; /* Mute compiler warning. */ -#if defined(TCP_CORK) || defined(TCP_PUSH) - return true; -#else /* !TCP_CORK && !TCP_PUSH */ - return false; -#endif /* !TCP_CORK && !TCP_PUSH */ -} - - -/** - * Activate no buffering mode (no delay sending) on connection socket - * and push to client data pending in socket buffer. - * - * @param connection connection to be processed - * @return true on success, false otherwise - */ -_MHD_static_inline bool -socket_start_no_buffering_flush (struct MHD_Connection *connection) -{ - bool res = false; -#if defined(TCP_NOPUSH) && ! defined(TCP_CORK) - const int dummy = 0; -#endif /* !TCP_CORK */ - -#if defined(__FreeBSD__) && __FreeBSD__ + 0 >= 9 - /* FreeBSD do not need zero-send for flushing starting from version 9 */ -#elif defined(TCP_NOPUSH) && ! defined(TCP_CORK) - /* Force flush data with zero send otherwise Darwin and some BSD systems - will add 5 seconds delay. Not required with TCP_CORK as switching off - TCP_CORK always flushes socket buffer. */ - res = (0 <= MHD_send_ (connection->socket_fd, - &dummy, - 0)) && res; -#endif /* TCP_NOPUSH && !TCP_CORK*/ - return res; -} - - /** * Get all of the headers from the request. * @@ -3593,9 +3533,6 @@ MHD_connection_handle_idle (struct MHD_Connection *connection) break; case MHD_CONNECTION_HEADERS_SENT: /* Some clients may take some actions right after header receive */ - if (socket_flush_possible (connection)) - socket_start_no_buffering_flush (connection); /* REMOVE: Dead */ - #ifdef UPGRADE_SUPPORT if (NULL != connection->response->upgrade_handler) { diff --git a/src/microhttpd/mhd_sockets.c b/src/microhttpd/mhd_sockets.c index b4e73480..38c6ecd4 100644 --- a/src/microhttpd/mhd_sockets.c +++ b/src/microhttpd/mhd_sockets.c @@ -37,10 +37,10 @@ * @param err the WinSock error code. * @return pointer to string description of specified WinSock error. */ -const char* MHD_W32_strerror_winsock_(int err) +const char*MHD_W32_strerror_winsock_ (int err) { switch (err) - { + { case 0: return "No error"; case WSA_INVALID_HANDLE: @@ -233,7 +233,7 @@ const char* MHD_W32_strerror_winsock_(int err) return "Invalid QoS shaping rate object"; case WSA_QOS_RESERVED_PETYPE: return "Reserved policy QoS element type"; - } + } return "Unknown winsock error"; } @@ -246,113 +246,114 @@ const char* MHD_W32_strerror_winsock_(int err) * @return non-zero if succeeded, zero otherwise */ int -MHD_W32_socket_pair_(SOCKET sockets_pair[2], int non_blk) +MHD_W32_socket_pair_ (SOCKET sockets_pair[2], int non_blk) { int i; if (! sockets_pair) - { - WSASetLastError (WSAEFAULT); - return 0; - } + { + WSASetLastError (WSAEFAULT); + return 0; + } #define PAIRMAXTRYIES 800 for (i = 0; i < PAIRMAXTRYIES; i++) + { + struct sockaddr_in listen_addr; + SOCKET listen_s; + static const int c_addinlen = sizeof(struct sockaddr_in); /* help compiler to optimize */ + int addr_len = c_addinlen; + unsigned long on_val = 1; + unsigned long off_val = 0; + + listen_s = socket (AF_INET, + SOCK_STREAM, + IPPROTO_TCP); + if (INVALID_SOCKET == listen_s) + break; /* can't create even single socket */ + + listen_addr.sin_family = AF_INET; + listen_addr.sin_port = 0; /* same as htons(0) */ + listen_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + if ( ((0 == bind (listen_s, + (struct sockaddr*) &listen_addr, + c_addinlen)) && + (0 == listen (listen_s, + 1) ) && + (0 == getsockname (listen_s, + (struct sockaddr*) &listen_addr, + &addr_len))) ) { - struct sockaddr_in listen_addr; - SOCKET listen_s; - static const int c_addinlen = sizeof(struct sockaddr_in); /* help compiler to optimize */ - int addr_len = c_addinlen; - unsigned long on_val = 1; - unsigned long off_val = 0; - - listen_s = socket (AF_INET, - SOCK_STREAM, - IPPROTO_TCP); - if (INVALID_SOCKET == listen_s) - break; /* can't create even single socket */ - - listen_addr.sin_family = AF_INET; - listen_addr.sin_port = 0; /* same as htons(0) */ - listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - if ( (0 == bind (listen_s, - (struct sockaddr*) &listen_addr, - c_addinlen) && - (0 == listen (listen_s, - 1) ) && - (0 == getsockname (listen_s, - (struct sockaddr*) &listen_addr, - &addr_len))) ) - { - SOCKET client_s = socket(AF_INET, - SOCK_STREAM, - IPPROTO_TCP); - struct sockaddr_in accepted_from_addr; - struct sockaddr_in client_addr; - SOCKET server_s; - - if (INVALID_SOCKET == client_s) - { - /* try again */ - closesocket (listen_s); - continue; - } - - if ( (0 != ioctlsocket (client_s, - FIONBIO, - &on_val)) || - ( (0 != connect (client_s, - (struct sockaddr*) &listen_addr, - c_addinlen)) && - (WSAGetLastError() != WSAEWOULDBLOCK)) ) - { - /* try again */ - closesocket (listen_s); - closesocket (client_s); - continue; - } - - addr_len = c_addinlen; - server_s = accept (listen_s, - (struct sockaddr*) &accepted_from_addr, - &addr_len); - if (INVALID_SOCKET == server_s) - { - /* try again */ - closesocket (listen_s); - closesocket (client_s); - continue; - } - - addr_len = c_addinlen; - if ( (0 == getsockname (client_s, - (struct sockaddr*) &client_addr, - &addr_len)) && - (accepted_from_addr.sin_family == client_addr.sin_family) && - (accepted_from_addr.sin_port == client_addr.sin_port) && - (accepted_from_addr.sin_addr.s_addr == client_addr.sin_addr.s_addr) && - ( (0 != non_blk) ? - (0 == ioctlsocket(server_s, - FIONBIO, - &on_val)) : - (0 == ioctlsocket(client_s, - FIONBIO, - &off_val)) ) ) - { - closesocket (listen_s); - sockets_pair[0] = server_s; - sockets_pair[1] = client_s; - return !0; - } - closesocket (server_s); - closesocket (client_s); - } - closesocket(listen_s); + SOCKET client_s = socket (AF_INET, + SOCK_STREAM, + IPPROTO_TCP); + struct sockaddr_in accepted_from_addr; + struct sockaddr_in client_addr; + SOCKET server_s; + + if (INVALID_SOCKET == client_s) + { + /* try again */ + closesocket (listen_s); + continue; + } + + if ( (0 != ioctlsocket (client_s, + FIONBIO, + &on_val)) || + ( (0 != connect (client_s, + (struct sockaddr*) &listen_addr, + c_addinlen)) && + (WSAGetLastError () != WSAEWOULDBLOCK)) ) + { + /* try again */ + closesocket (listen_s); + closesocket (client_s); + continue; + } + + addr_len = c_addinlen; + server_s = accept (listen_s, + (struct sockaddr*) &accepted_from_addr, + &addr_len); + if (INVALID_SOCKET == server_s) + { + /* try again */ + closesocket (listen_s); + closesocket (client_s); + continue; + } + + addr_len = c_addinlen; + if ( (0 == getsockname (client_s, + (struct sockaddr*) &client_addr, + &addr_len)) && + (accepted_from_addr.sin_family == client_addr.sin_family) && + (accepted_from_addr.sin_port == client_addr.sin_port) && + (accepted_from_addr.sin_addr.s_addr == + client_addr.sin_addr.s_addr) && + ( (0 != non_blk) ? + (0 == ioctlsocket (server_s, + FIONBIO, + &on_val)) : + (0 == ioctlsocket (client_s, + FIONBIO, + &off_val)) ) ) + { + closesocket (listen_s); + sockets_pair[0] = server_s; + sockets_pair[1] = client_s; + return ! 0; + } + closesocket (server_s); + closesocket (client_s); } + closesocket (listen_s); + } sockets_pair[0] = INVALID_SOCKET; sockets_pair[1] = INVALID_SOCKET; - WSASetLastError(WSAECONNREFUSED); + WSASetLastError (WSAECONNREFUSED); return 0; } @@ -383,9 +384,9 @@ MHD_add_to_fd_set_ (MHD_socket fd, set, fd_setsize)) return 0; - MHD_SCKT_ADD_FD_TO_FDSET_SETSIZE_(fd, - set, - fd_setsize); + MHD_SCKT_ADD_FD_TO_FDSET_SETSIZE_ (fd, + set, + fd_setsize); if ( (NULL != max_fd) && ( (fd > *max_fd) || (MHD_INVALID_SOCKET == *max_fd) ) ) @@ -424,7 +425,7 @@ MHD_socket_nonblocking_ (MHD_socket sock) &flags)) return 0; #endif /* MHD_WINSOCK_SOCKETS */ - return !0; + return ! 0; } @@ -452,12 +453,12 @@ MHD_socket_noninheritable_ (MHD_socket sock) flags | FD_CLOEXEC)) ) return 0; #elif defined(MHD_WINSOCK_SOCKETS) - if (! SetHandleInformation ((HANDLE)sock, + if (! SetHandleInformation ((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) return 0; #endif /* MHD_WINSOCK_SOCKETS */ - return !0; + return ! 0; } @@ -508,14 +509,34 @@ MHD_socket_cork_ (MHD_socket sock, const MHD_SCKT_OPT_BOOL_ on_val = 1; /* Disable extra buffering */ - return (0 == setsockopt (sock, - IPPROTO_TCP, - MHD_TCP_CORK_NOPUSH, - (const void *) (on ? &on_val : &off_val), - sizeof (off_val))); + if (0 != setsockopt (sock, + IPPROTO_TCP, + MHD_TCP_CORK_NOPUSH, + (const void *) (on ? &on_val : &off_val), + sizeof (off_val))) + return 0; /* failed */ +#if defined(__FreeBSD__) && __FreeBSD__ + 0 >= 9 + /* FreeBSD do not need zero-send for flushing starting from version 9 */ + return 1; +#elif defined(TCP_NOPUSH) && ! defined(TCP_CORK) + { + const int dummy = 0; + /* Force flush data with zero send otherwise Darwin and some BSD systems + will add 5 seconds delay. Not required with TCP_CORK as switching off + TCP_CORK always flushes socket buffer. */ + if (0 > send (sock, + &dummy, + 0)) + return 0; /* even force flush failed!? */ + return 1; /* success */ + } #else return 0; -#endif /* MHD_TCP_CORK_NOPUSH */ +#endif +#elif + /* do not have MHD_TCP_CORK_NOPUSH at all */ + return 0; +#endif } @@ -559,7 +580,8 @@ MHD_socket_create_listen_ (int pf) int nosigpipe_set; #endif /* SOCK_NOSIGPIPE || MHD_socket_nosignal_ */ -#if defined(MHD_POSIX_SOCKETS) && ( defined(SOCK_CLOEXEC) || defined(SOCK_NOSIGPIPE) ) +#if defined(MHD_POSIX_SOCKETS) && (defined(SOCK_CLOEXEC) || \ + defined(SOCK_NOSIGPIPE) ) fd = socket (pf, SOCK_STREAM | SOCK_CLOEXEC | MAYBE_SOCK_NOSIGPIPE, 0); @@ -574,36 +596,36 @@ MHD_socket_create_listen_ (int pf) NULL, 0, WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT); - cloexec_set = !0; + cloexec_set = ! 0; #else /* !SOCK_CLOEXEC */ fd = MHD_INVALID_SOCKET; #endif /* !SOCK_CLOEXEC */ if (MHD_INVALID_SOCKET == fd) - { - fd = socket (pf, - SOCK_STREAM, - 0); - cloexec_set = 0; - } + { + fd = socket (pf, + SOCK_STREAM, + 0); + cloexec_set = 0; + } if (MHD_INVALID_SOCKET == fd) return MHD_INVALID_SOCKET; #if defined(SOCK_NOSIGPIPE) || defined(MHD_socket_nosignal_) if ( ( (! nosigpipe_set) #ifdef MHD_socket_nosignal_ - || (! MHD_socket_nosignal_(fd)) + || (! MHD_socket_nosignal_ (fd)) #endif /* MHD_socket_nosignal_ */ - ) && (0 == MAYBE_MSG_NOSIGNAL) ) - { - /* SIGPIPE disable is possible on this platform - * (so application expect that it will be disabled), - * but failed to be disabled here and it is not - * possible to disable SIGPIPE by MSG_NOSIGNAL. */ - const int err = MHD_socket_get_error_ (); - (void) MHD_socket_close_ (fd); - MHD_socket_fset_error_ (err); - return MHD_INVALID_SOCKET; - } + ) && (0 == MAYBE_MSG_NOSIGNAL) ) + { + /* SIGPIPE disable is possible on this platform + * (so application expect that it will be disabled), + * but failed to be disabled here and it is not + * possible to disable SIGPIPE by MSG_NOSIGNAL. */ + const int err = MHD_socket_get_error_ (); + (void) MHD_socket_close_ (fd); + MHD_socket_fset_error_ (err); + return MHD_INVALID_SOCKET; + } #endif /* SOCK_NOSIGPIPE || MHD_socket_nosignal_ */ if (! cloexec_set) (void) MHD_socket_noninheritable_ (fd); -- cgit v1.2.3