Hi Jules,
I’ve met a problem with URL::createInputStream(). It’s been called in a thread, but if the server doesn’t reply, it’s blocked for a long time.
There is no way to specify a timeout, I guess because the default OS “connect” is used.
Could you implement a non blocking connect (below is my code for this under both windows and linux) so user can specify a time out.
I can do it myself, but to make sure it will be used.
Here’s the code:
#ifdef _WIN32
// Asynchronous Connect with timeout in ms
int Socket::Connect(const uint32 & lTimeout) const
{
int ioNonBlock = 1, iRet = 0;
// Set non blocking socket now
if (ioctlsocket(mxSocket, FIONBIO, (u_long FAR*) &ioNonBlock) != 0) return SOCKET_ERROR;
// Then attempt a connection
if (connect(mxSocket, (const struct sockaddr *)&mxSockOut, sizeof(mxSockOut)) == SOCKET_ERROR)
{
// Failed to connect, check what happened
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
// Connection is quite long so check if we can wait it
// Select stuff
fd_set fds;
struct timeval tv_timeout;
FD_ZERO(&fds);
FD_SET(mxSocket,&fds);
tv_timeout.tv_sec = lTimeout / 1000;
tv_timeout.tv_usec = 1000 * (lTimeout%1000);
if (select(mxSocket + 1, NULL, &fds, NULL, &tv_timeout) <= 0)
{
// Socket doesn't got connection in the specified amount of time
// Reset the blocking mode of the socket
ioNonBlock = 0;
if (ioctlsocket(mxSocket, FIONBIO, (u_long FAR*) &ioNonBlock) != 0) return SOCKET_ERROR;
// Cannot contact server, so exit now
return SOCKET_ERROR;
}
}
else
{
// Reset the blocking mode of the socket
ioNonBlock = 0;
if (ioctlsocket(mxSocket, FIONBIO, (u_long FAR*) &ioNonBlock) != 0) return SOCKET_ERROR;
// Cannot contact server, so exit now
return SOCKET_ERROR;
}
}
// Reset the blocking mode of the socket
ioNonBlock = 0;
if (ioctlsocket(mxSocket, FIONBIO, (u_long FAR*) &ioNonBlock) != 0) return SOCKET_ERROR;
// Connection succeeded
return 0;
}
#else
// Asynchronous Connect with timeout in ms
int Socket::Connect(const tULong & lTimeout) const
{
int socketFlags = 0, iRet = 0;
// Set non blocking socket now
socketFlags = fcntl(mxSocket, F_GETFL, 0);
if (socketFlags == -1) return SOCKET_ERROR;
if (fcntl(mxSocket, F_SETFL, socketFlags | O_NONBLOCK) != 0) return SOCKET_ERROR;
// Then attempt a connection
if ((iRet = connect(mxSocket, (const struct sockaddr *)&mxSockOut, sizeof(mxSockOut))) < 0)
{
// Failed to connect, check what happened
if (iRet == EINPROGRESS)
{
// Connection is quite long so check if we can wait it
// Select stuff
fd_set fds;
struct timeval tv_timeout;
FD_ZERO(&fds);
FD_SET(mxSocket,&fds);
tv_timeout.tv_sec = lTimeout / 1000;
tv_timeout.tv_usec = 1000 * (lTimeout%1000);
if (select(mxSocket + 1, NULL, &fds, NULL, &tv_timeout) <= 0)
{
// Socket doesn't got connection in the specified amount of time
// Reset the blocking mode of the socket
if (fcntl(mxSocket, F_SETFL, socketFlags) != 0) return SOCKET_ERROR;
// Cannot contact server, so exit now
return SOCKET_ERROR;
}
}
else
{
// Reset the blocking mode of the socket
if (fcntl(mxSocket, F_SETFL, socketFlags) != 0) return SOCKET_ERROR;
// Cannot contact server, so exit now
return SOCKET_ERROR;
}
}
// Reset the blocking mode of the socket
if (fcntl(mxSocket, F_SETFL, socketFlags) != 0) return SOCKET_ERROR;
// Connection succeeded
return 0;
}
#endif
// Non blocking receive on a connected socket
int Socket::Recv(char * buf, int len, int flags, uint32 lTimeOut) const
{
// Select stuff
fd_set fds;
struct timeval tv_timeout;
FD_ZERO(&fds);
FD_SET(mxSocket,&fds);
tv_timeout.tv_sec = lTimeOut / 1000;
tv_timeout.tv_usec = 1000 * (lTimeOut%1000);
if (select(mxSocket + 1, &fds, NULL, NULL, &tv_timeout) <= 0)
{
// No data arrived in time, return error
return SOCKET_ERROR;
}
// Read the data and send it now
return recv(mxSocket, buf, len, flags);
}
BTW, the recv should also be non blocking similarly.