diff --git a/modules/juce_core/network/juce_Socket.cpp b/modules/juce_core/network/juce_Socket.cpp index 1c15fc5645..515aa25f0f 100644 --- a/modules/juce_core/network/juce_Socket.cpp +++ b/modules/juce_core/network/juce_Socket.cpp @@ -55,6 +55,24 @@ namespace juce //============================================================================== namespace SocketHelpers { + #if JUCE_WINDOWS + using WSAPollFunc = int (WSAAPI*) (LPWSAPOLLFD, ULONG, INT); + static WSAPollFunc wsaPollFunc = nullptr; + + static void checkForWSAPoll() + { + static bool hasChecked = false; + + if (! hasChecked) + { + hasChecked = true; + + if (auto* moduleHandle = GetModuleHandleW (L"Ws2_32.dll")) + wsaPollFunc = (WSAPollFunc) GetProcAddress (moduleHandle, "WSAPoll"); + } + } + #endif + static void initSockets() { #if JUCE_WINDOWS @@ -67,6 +85,8 @@ namespace SocketHelpers WSADATA wsaData; const WORD wVersionRequested = MAKEWORD (1, 1); WSAStartup (wVersionRequested, &wsaData); + + checkForWSAPoll(); } #endif } @@ -286,9 +306,61 @@ namespace SocketHelpers if (! lock.isLocked()) return -1; + auto hasErrorOccured = [&handle] () -> bool + { + auto h = handle.load(); + + if (h == invalidSocket) + return true; + + int opt; + juce_socklen_t len = sizeof (opt); + + if (getsockopt (h, SOL_SOCKET, SO_ERROR, (char*) &opt, &len) < 0 || opt != 0) + return true; + + return false; + }; + auto h = handle.load(); - #if JUCE_MINGW + #if ! JUCE_MINGW + #if JUCE_WINDOWS + if (wsaPollFunc != nullptr) + #endif + { + short eventsFlag = (forReading ? POLLIN : POLLOUT); + pollfd pfd { (SocketHandle) h, eventsFlag, 0 }; + + int result = 0; + + for (;;) + { + #if JUCE_WINDOWS + result = SocketHelpers::wsaPollFunc (&pfd, 1, timeoutMsecs); + #else + result = poll (&pfd, 1, timeoutMsecs); + #endif + + if (result >= 0 + #if JUCE_WINDOWS + || result == SOCKET_ERROR + #else + || errno != EINTR + #endif + ) + { + break; + } + } + + if (result < 0 || hasErrorOccured()) + return -1; + + return (pfd.revents & eventsFlag) != 0; + } + #endif + struct timeval timeout; struct timeval* timeoutp; @@ -309,59 +381,13 @@ namespace SocketHelpers FD_ZERO (&wset); FD_SET (h, &wset); - fd_set* const prset = forReading ? &rset : nullptr; - fd_set* const pwset = forReading ? nullptr : &wset; + fd_set* prset = forReading ? &rset : nullptr; + fd_set* pwset = forReading ? nullptr : &wset; - if (select ((int) h + 1, prset, pwset, 0, timeoutp) < 0) - return -1; - #else - short eventsFlag = (forReading ? POLLIN : POLLOUT); - pollfd pfd { (SocketHandle) h, eventsFlag, 0 }; - - int result = 0; - - for (;;) - { - #if JUCE_WINDOWS - result = WSAPoll (&pfd, 1, timeoutMsecs); - #else - result = poll (&pfd, 1, timeoutMsecs); - #endif - - if (result >= 0 - #if JUCE_WINDOWS - || result == SOCKET_ERROR - #else - || errno != EINTR - #endif - ) - { - break; - } - } - - if (result < 0) - return -1; - #endif - - // we are closing - if (handle.load() < 0) + if (select ((int) h + 1, prset, pwset, nullptr, timeoutp) < 0 || hasErrorOccured()) return -1; - { - int opt; - juce_socklen_t len = sizeof (opt); - - if (getsockopt (h, SOL_SOCKET, SO_ERROR, (char*) &opt, &len) < 0 - || opt != 0) - return -1; - } - - #if JUCE_MINGW return FD_ISSET (h, forReading ? &rset : &wset) ? 1 : 0; - #else - return (pfd.revents & eventsFlag) != 0; - #endif } static addrinfo* getAddressInfo (bool isDatagram, const String& hostName, int portNumber)