* Windows 7 or lower have an undocumented minimum of 500ms for socket timeouts, detect at runtime and assume it as broken timeouts (https://social.msdn.microsoft.com/Forums/en-US/76620f6d-22b1-4872-aaf0-833204f3f867/minimum-timeout-value-for-sorcvtimeo)

This commit is contained in:
Rangel Reale 2015-07-13 15:05:10 -03:00
parent 51a8292649
commit bd9b5b46d8
2 changed files with 55 additions and 30 deletions

View File

@ -421,11 +421,10 @@ private:
SocketImpl& operator = (const SocketImpl&); SocketImpl& operator = (const SocketImpl&);
poco_socket_t _sockfd; poco_socket_t _sockfd;
#if defined(POCO_BROKEN_TIMEOUTS)
Poco::Timespan _recvTimeout; Poco::Timespan _recvTimeout;
Poco::Timespan _sndTimeout; Poco::Timespan _sndTimeout;
#endif
bool _blocking; bool _blocking;
bool _isbrokentimeout;
friend class Socket; friend class Socket;
friend class SecureSocketImpl; friend class SecureSocketImpl;

View File

@ -33,6 +33,11 @@
#endif #endif
#ifdef POCO_OS_FAMILY_WINDOWS
#include <Windows.h>
#endif
using Poco::IOException; using Poco::IOException;
using Poco::TimeoutException; using Poco::TimeoutException;
using Poco::InvalidArgumentException; using Poco::InvalidArgumentException;
@ -44,16 +49,34 @@ namespace Poco {
namespace Net { namespace Net {
bool CheckIsBrokenTimeout()
{
#if defined(POCO_BROKEN_TIMEOUTS)
return true;
#elif defined(POCO_OS_FAMILY_WINDOWS)
// on Windows 7 and lower, socket timeouts have a minimum of 500ms, use poll for timeouts on this case
// https://social.msdn.microsoft.com/Forums/en-US/76620f6d-22b1-4872-aaf0-833204f3f867/minimum-timeout-value-for-sorcvtimeo
OSVERSIONINFO vi;
vi.dwOSVersionInfoSize = sizeof(vi);
if (GetVersionEx(&vi) == 0) return true; //throw SystemException("Cannot get OS version information");
return vi.dwMajorVersion < 6 || (vi.dwMajorVersion == 6 && vi.dwMinorVersion < 2);
#endif
return false;
}
SocketImpl::SocketImpl(): SocketImpl::SocketImpl():
_sockfd(POCO_INVALID_SOCKET), _sockfd(POCO_INVALID_SOCKET),
_blocking(true) _blocking(true),
_isbrokentimeout(CheckIsBrokenTimeout())
{ {
} }
SocketImpl::SocketImpl(poco_socket_t sockfd): SocketImpl::SocketImpl(poco_socket_t sockfd):
_sockfd(sockfd), _sockfd(sockfd),
_blocking(true) _blocking(true),
_isbrokentimeout(CheckIsBrokenTimeout())
{ {
} }
@ -262,13 +285,14 @@ void SocketImpl::shutdown()
int SocketImpl::sendBytes(const void* buffer, int length, int flags) int SocketImpl::sendBytes(const void* buffer, int length, int flags)
{ {
#if defined(POCO_BROKEN_TIMEOUTS) if (_isbrokentimeout)
if (_sndTimeout.totalMicroseconds() != 0)
{ {
if (!poll(_sndTimeout, SELECT_WRITE)) if (_sndTimeout.totalMicroseconds() != 0)
throw TimeoutException(); {
if (!poll(_sndTimeout, SELECT_WRITE))
throw TimeoutException();
}
} }
#endif
int rc; int rc;
do do
@ -284,13 +308,14 @@ int SocketImpl::sendBytes(const void* buffer, int length, int flags)
int SocketImpl::receiveBytes(void* buffer, int length, int flags) int SocketImpl::receiveBytes(void* buffer, int length, int flags)
{ {
#if defined(POCO_BROKEN_TIMEOUTS) if (_isbrokentimeout)
if (_recvTimeout.totalMicroseconds() != 0)
{ {
if (!poll(_recvTimeout, SELECT_READ)) if (_recvTimeout.totalMicroseconds() != 0)
throw TimeoutException(); {
if (!poll(_recvTimeout, SELECT_READ))
throw TimeoutException();
}
} }
#endif
int rc; int rc;
do do
@ -333,13 +358,14 @@ int SocketImpl::sendTo(const void* buffer, int length, const SocketAddress& addr
int SocketImpl::receiveFrom(void* buffer, int length, SocketAddress& address, int flags) int SocketImpl::receiveFrom(void* buffer, int length, SocketAddress& address, int flags)
{ {
#if defined(POCO_BROKEN_TIMEOUTS) if (_isbrokentimeout)
if (_recvTimeout.totalMicroseconds() != 0)
{ {
if (!poll(_recvTimeout, SELECT_READ)) if (_recvTimeout.totalMicroseconds() != 0)
throw TimeoutException(); {
if (!poll(_recvTimeout, SELECT_READ))
throw TimeoutException();
}
} }
#endif
char abuffer[SocketAddress::MAX_ADDRESS_LENGTH]; char abuffer[SocketAddress::MAX_ADDRESS_LENGTH];
struct sockaddr* pSA = reinterpret_cast<struct sockaddr*>(abuffer); struct sockaddr* pSA = reinterpret_cast<struct sockaddr*>(abuffer);
@ -561,11 +587,11 @@ void SocketImpl::setSendTimeout(const Poco::Timespan& timeout)
#if defined(_WIN32) && !defined(POCO_BROKEN_TIMEOUTS) #if defined(_WIN32) && !defined(POCO_BROKEN_TIMEOUTS)
int value = (int) timeout.totalMilliseconds(); int value = (int) timeout.totalMilliseconds();
setOption(SOL_SOCKET, SO_SNDTIMEO, value); setOption(SOL_SOCKET, SO_SNDTIMEO, value);
#elif defined(POCO_BROKEN_TIMEOUTS) #elif !defined(POCO_BROKEN_TIMEOUTS)
_sndTimeout = timeout;
#else
setOption(SOL_SOCKET, SO_SNDTIMEO, timeout); setOption(SOL_SOCKET, SO_SNDTIMEO, timeout);
#endif #endif
if (_isbrokentimeout)
_sndTimeout = timeout;
} }
@ -576,11 +602,11 @@ Poco::Timespan SocketImpl::getSendTimeout()
int value; int value;
getOption(SOL_SOCKET, SO_SNDTIMEO, value); getOption(SOL_SOCKET, SO_SNDTIMEO, value);
result = Timespan::TimeDiff(value)*1000; result = Timespan::TimeDiff(value)*1000;
#elif defined(POCO_BROKEN_TIMEOUTS) #elif !defined(POCO_BROKEN_TIMEOUTS)
result = _sndTimeout;
#else
getOption(SOL_SOCKET, SO_SNDTIMEO, result); getOption(SOL_SOCKET, SO_SNDTIMEO, result);
#endif #endif
if (_isbrokentimeout)
result = _sndTimeout;
return result; return result;
} }
@ -594,9 +620,9 @@ void SocketImpl::setReceiveTimeout(const Poco::Timespan& timeout)
#else #else
setOption(SOL_SOCKET, SO_RCVTIMEO, timeout); setOption(SOL_SOCKET, SO_RCVTIMEO, timeout);
#endif #endif
#else
_recvTimeout = timeout;
#endif #endif
if (_isbrokentimeout)
_recvTimeout = timeout;
} }
@ -607,11 +633,11 @@ Poco::Timespan SocketImpl::getReceiveTimeout()
int value; int value;
getOption(SOL_SOCKET, SO_RCVTIMEO, value); getOption(SOL_SOCKET, SO_RCVTIMEO, value);
result = Timespan::TimeDiff(value)*1000; result = Timespan::TimeDiff(value)*1000;
#elif defined(POCO_BROKEN_TIMEOUTS) #elif !defined(POCO_BROKEN_TIMEOUTS)
result = _recvTimeout;
#else
getOption(SOL_SOCKET, SO_RCVTIMEO, result); getOption(SOL_SOCKET, SO_RCVTIMEO, result);
#endif #endif
if (_isbrokentimeout)
result = _recvTimeout;
return result; return result;
} }