Bug #36225 Connect time out not using values that are set
Submitted: 21 Apr 2008 6:30 Modified: 16 Apr 2013 15:05
Reporter: Michael Ryan Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: C API (client library) Severity:S2 (Serious)
Version:5.0.46, 5.0.54a, 5.1.23 OS:Windows (Windows XP)
Assigned to: CPU Architecture:Any
Tags: connect_timeout, MYSQL_OPT_CONNECT_TIMEOUT

[21 Apr 2008 6:30] Michael Ryan
Description:
I have a client program which is attempting to connect to a remote host that has been powered down due to failure. I have used ADISetOptions() with the MYSQL_OPT_CONNECT_TIMEOUT option and also I have set the value directory in the MYSQL structure for connect_timeout but it is not being used. Instead of timing the connection attempt out after X seconds, it always takes between 21 and 23 seconds. My client program is running on Windows XP and the remote machine is also Windows XP. This is not a firewall related issue as I have shut down the firewall and there was no difference in the time taken to fail the connection attempt.

How to repeat:
This is the test code I have created to make a repeatable test (I link with lib\opt\mysqlient.lib and I use MS VS2005).

#include <windows.h>
#include <process.h>
#include <stdio.h>
#include <stdlib.h>
#include <mysql.h>
#include <time.h>

#define CONVERT_TO_MS_DOUBLE(start, stop, ticksInSec) ((double)((stop).QuadPart - (start).QuadPart) / (ticksInSec).QuadPart) * 1000

int main(int argc, char **argv)
{
	MYSQL *myData;
   LARGE_INTEGER startTime, stopTime, ticksInSec;

   QueryPerformanceFrequency(&ticksInSec);

   QueryPerformanceCounter(&startTime);
	
	myData = mysql_init((MYSQL*) 0);
	myData->options.connect_timeout = 1;

	if (!mysql_real_connect(myData, "192.168.1.190", "adb_user", "adb", "adb", 3306, NULL, 0))
		printf("Error: %s\n", mysql_error(myData));
	else
		mysql_close( myData ) ;

   QueryPerformanceCounter(&stopTime);

	printf("Time in millisecs was %f\n", CONVERT_TO_MS_DOUBLE(startTime, stopTime, ticksInSec));

	return 0;
}
[5 May 2008 18:15] Sveta Smirnova
Thank you for the report.

Verified as described. Bug is repeatable only on Windows.
[6 Aug 2008 23:19] Michael Ryan
Is there any progress on this bug ? It was verified as a bug nearly 4 months ago and there has been no further update. I do not use the community edition. I actually paid for MySQL licenses so expected the feedback and response to be a little better than what it has been. The software I am writing is due to go live in a couple of months and this is still a major issue !
[7 Aug 2008 5:16] Sveta Smirnova
Thank you for the feedback.

> I actually paid for MySQL licenses so expected the feedback and response to be a little better than what it has been.

I am sorry, but bug database is only for discussions related to bug reports itself, not for usage. If you need feedback please open support issue.
[7 Aug 2008 5:21] Michael Ryan
> I am sorry, but bug database is only for discussions related to bug reports itself, not for usage. If you need feedback please open support issue.

Feedback to bugs corrected should be done through the bug database. I did not expect nor ask for feedback to me personally but feedback about the bug in the bug database. This should not need to be a support request seeing it is a bug and I simply want the bug report updated with progress (i.e. when will this bug be fixed).
[11 Jan 2009 15:00] Sveta Smirnova
Bug #41911 was marked as duplicate of this one.
[3 Jun 2011 10:42] Samuel Cabrero
I have written a patch that works for me. Maybe someone wants to review it and commit.

--- client.c.org	Fri Jun 03 12:25:45 2011
+++ client.c	Fri Jun 03 12:20:58 2011
@@ -129,6 +129,10 @@
 static int wait_for_data(my_socket fd, uint timeout);
 #endif
 
+#if defined(__WIN__) 
+static int is_socket_connected(int fd, fd_set *rd, fd_set *wr, fd_set *ex);
+#endif
+
 CHARSET_INFO *default_client_charset_info = &my_charset_latin1;
 
 /* Server error code and message */
@@ -147,8 +151,51 @@
 int my_connect(my_socket fd, const struct sockaddr *name, uint namelen,
 	       uint timeout)
 {
-#if defined(__WIN__) || defined(__NETWARE__)
+#if defined(__NETWARE__)
   return connect(fd, (struct sockaddr*) name, namelen);
+#elif defined(__WIN__)
+  int ret;
+  
+  // Set the socket to Non-blocking mode
+  int NonBlk = 1;  
+  ioctlsocket(fd, FIONBIO, &NonBlk);
+      
+  ret = connect(fd, (struct sockaddr*) name, namelen);
+  
+  // If connected, it will return 0, else it will return an error code
+  if (ret == SOCKET_ERROR)
+  {
+    ret = WSAGetLastError();
+    // Check if the error was WSAEWOULDBLOCK, where we'll wait.
+    if (ret == WSAEWOULDBLOCK)
+    {      
+      fd_set rd, wr, err;
+      struct timeval tv;
+
+      FD_ZERO(&rd);      
+      FD_SET(fd, &rd);
+      wr = rd;
+      err = rd;
+
+      // Set the timeout
+      tv.tv_sec  = timeout;
+      tv.tv_usec = 0;
+
+      ret = select (0, &rd, &wr, &err, &tv);
+      if ( ret == SOCKET_ERROR )
+        return(-1); /* select failed */		
+	    else if ( ret == 0 )
+        return(-1); /* select timeout */		    
+	    else if( is_socket_connected(fd, &rd, &wr, &err) )
+	      return(0);			
+	    else
+        return(-1);
+    }
+  }
+  else 
+    return(0);  /* Connect with no waiting! */
+
+  return(-1);    
 #else
   int flags, res, s_err;
 
@@ -179,6 +226,24 @@
 #endif
 }
 
+/*
+  Check socket status. Code taken from Effective TCP/IP Programming, 
+  by Jon Snader.
+*/
+#if defined(__WIN__)
+int is_socket_connected(int fd, fd_set *rd, fd_set *wr, fd_set *ex)
+{  
+  WSASetLastError(0);
+
+  if (!FD_ISSET(fd, rd) && !FD_ISSET(fd, wr))  
+    return(0);
+
+  if (FD_ISSET(fd, ex))  
+    return(0);  
+    
+  return(1);
+}
+#endif /*__WIN__*/
 
 /*
   Wait up to timeout seconds for a connection to be established.
@@ -278,7 +343,7 @@
   return (0);					/* ok */
 #endif /* HAVE_POLL */
 }
-#endif /* defined(__WIN__) || defined(__NETWARE__) */
+#endif /* !defined(__WIN__) || defined(__NETWARE__) */
 
 /**
   Set the internal error message to mysql handler
[3 Jun 2011 15:46] Davi Arnaut
This issue was addressed by the patch for Bug#54790.
[16 Apr 2013 15:05] Igor Solodovnikov
Reproduced this problem on MySQL 5.1 and 5.5.
5.6 is not affected.