11#include <mysql2_ext.h>
22
3+ #include <time.h>
34#include <errno.h>
45#ifndef _WIN32
56#include <sys/types.h>
@@ -255,6 +256,7 @@ static VALUE allocate(VALUE klass) {
255256 wrapper -> active_thread = Qnil ;
256257 wrapper -> server_version = 0 ;
257258 wrapper -> reconnect_enabled = 0 ;
259+ wrapper -> connect_timeout = 0 ;
258260 wrapper -> connected = 0 ; /* means that a database connection is open */
259261 wrapper -> initialized = 0 ; /* means that that the wrapper is initialized */
260262 wrapper -> refcount = 1 ;
@@ -326,6 +328,8 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
326328 struct nogvl_connect_args args ;
327329 VALUE rv ;
328330 GET_CLIENT (self );
331+ time_t start_time , end_time ;
332+ unsigned int elapsed_time , connect_timeout ;
329333
330334 args .host = NIL_P (host ) ? NULL : StringValuePtr (host );
331335 args .unix_socket = NIL_P (socket ) ? NULL : StringValuePtr (socket );
@@ -336,12 +340,31 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
336340 args .mysql = wrapper -> client ;
337341 args .client_flag = NUM2ULONG (flags );
338342
343+ if (wrapper -> connect_timeout )
344+ time (& start_time );
339345 rv = (VALUE ) rb_thread_call_without_gvl (nogvl_connect , & args , RUBY_UBF_IO , 0 );
340346 if (rv == Qfalse ) {
341- while (rv == Qfalse && errno == EINTR && !mysql_errno (wrapper -> client )) {
347+ while (rv == Qfalse && errno == EINTR ) {
348+ if (wrapper -> connect_timeout ) {
349+ time (& end_time );
350+ /* avoid long connect timeout from system time changes */
351+ if (end_time < start_time )
352+ start_time = end_time ;
353+ elapsed_time = end_time - start_time ;
354+ /* avoid an early timeout due to time truncating milliseconds off the start time */
355+ if (elapsed_time > 0 )
356+ elapsed_time -- ;
357+ if (elapsed_time >= wrapper -> connect_timeout )
358+ break ;
359+ connect_timeout = wrapper -> connect_timeout - elapsed_time ;
360+ mysql_options (wrapper -> client , MYSQL_OPT_CONNECT_TIMEOUT , & connect_timeout );
361+ }
342362 errno = 0 ;
343363 rv = (VALUE ) rb_thread_call_without_gvl (nogvl_connect , & args , RUBY_UBF_IO , 0 );
344364 }
365+ /* restore the connect timeout for reconnecting */
366+ if (wrapper -> connect_timeout )
367+ mysql_options (wrapper -> client , MYSQL_OPT_CONNECT_TIMEOUT , & wrapper -> connect_timeout );
345368 if (rv == Qfalse )
346369 return rb_raise_mysql2_error (wrapper );
347370 }
@@ -795,9 +818,15 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) {
795818 if (result != 0 ) {
796819 rb_warn ("%s\n" , mysql_error (wrapper -> client ));
797820 } else {
798- /* Special case for reconnect, this option is also stored in the wrapper struct */
799- if (opt == MYSQL_OPT_RECONNECT )
800- wrapper -> reconnect_enabled = boolval ;
821+ /* Special case for options that are stored in the wrapper struct */
822+ switch (opt ) {
823+ case MYSQL_OPT_RECONNECT :
824+ wrapper -> reconnect_enabled = boolval ;
825+ break ;
826+ case MYSQL_OPT_CONNECT_TIMEOUT :
827+ wrapper -> connect_timeout = intval ;
828+ break ;
829+ }
801830 }
802831
803832 return (result == 0 ) ? Qtrue : Qfalse ;
0 commit comments