Synchronous client connection (with no timeout set) to non listening socket blocks indefinitely [SOLVED] #214
Description
Hello,
I am testing on Windows 7 the C++ library redis3m, based upon hiredis and boost, and I am using the hiredis client/Win32_Interop libraries (git tag 2.8.17.3) provided by you.
I have compiled from scratch all the needed components, both hiredis and redis3m along with all its dependencies, with Visual Studio Express 2013 for Windows Desktop, the only change I have made to your project files is to use the DLL version of the C/C++ runtime libraries.
The resulting executable uses only static libraries, I have no additional dependencies upon DLLs exept for those provided by Windows itself; Dependency Walker shows for the debug version: KERNEL32.DLL, WS2_32.DLL, MSVCP120D.DLL, MSVCR120D.DLL, USER32.DLL, ADVAPI32.DLL.
I am writing you here because I have experienced this issue: it seems that a blocking connection to redis with no timeout set, initiated by calling redisConnect (host, port) blocks indefinitely if the remote port is not open, I would have expected instead returning from the function and c->err set to an appropriate error.
Stepping inside the library code, I saw that inside the function _redisContextConnectTcp:
-
connect (redis_connect_impl, actually) is called and it returns EINPROGRESS because WSAGetLastError returns 10035 (WSAEWOULDBLOCK)
-
After that redisContextWaitReady is called, and the execution blocks indefinitely inside it, specifically when calling poll on the socket:
if (errno == EINPROGRESS) {
int res;if ((res = poll(wfd, 1, msec)) == -1) {
After reading here: https://msdn.microsoft.com/en-us/library/windows/desktop/ms741669%28v=vs.85%29.aspx
and here: http://curl.haxx.se/mail/lib-2012-10/0038.html
At first I tried changing the polled events from just POLLOUT to POLLOUT | POLLERR, but then a legitimate connection did not work anymore (I didn't investigate this), so in the end I chose to try to use select instead of poll (keeping POLLERR, so that internally the socket is added to the excepSet).
I opted to enable using poll only if the OS is at least Windows 8 by changing this check:
if (IsWindowsVersionAtLeast(HIBYTE(_WIN32_WINNT_WIN6), LOBYTE(_WIN32_WINNT_WIN6), 0)) {
to this one:
IsWindowsVersionAtLeast(HIBYTE(0x0602), LOBYTE(0x0602), 0)) {
(the SDK provided by VS 2003 Express does not now anything about the _WIN8/_WINBLUE defines)
but there were again some problems (caused, I think, by the code not being really maintained/tested) so in the end I debugged and modified the code and I finally got it working.
I don't know if using select already works in the 2.8 branch (or in some other version); if it isn't, I would like to contribute my modification to you (if it's appreciated).
Thank you in advance and best regards
Fabrizio