BUG#9678: Client library hangs after network communication failure

          (back-port to 4.0)

Socket timeouts in client library were used only on Windows.
Additionally, in 4.0 write operations erroneously set read timeout.

The solution is to use socket timeouts in client library on all
systems were they are supported, and to differentiate between read
and write timeouts.

No test case is provided because it is impossible to simulate network
failure in current test suite.
parent 7d0b042e
...@@ -77,7 +77,7 @@ my_bool vio_peer_addr(Vio* vio, char *buf, uint16 *port); ...@@ -77,7 +77,7 @@ my_bool vio_peer_addr(Vio* vio, char *buf, uint16 *port);
/* Remotes in_addr */ /* Remotes in_addr */
void vio_in_addr(Vio *vio, struct in_addr *in); void vio_in_addr(Vio *vio, struct in_addr *in);
my_bool vio_poll_read(Vio *vio,uint timeout); my_bool vio_poll_read(Vio *vio,uint timeout);
void vio_timeout(Vio *vio,uint timeout); void vio_timeout(Vio *vio, uint which, uint timeout);
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
#include <openssl/opensslv.h> #include <openssl/opensslv.h>
...@@ -140,7 +140,7 @@ Vio *new_VioSSL(struct st_VioSSLAcceptorFd *fd, Vio *sd, int state); ...@@ -140,7 +140,7 @@ Vio *new_VioSSL(struct st_VioSSLAcceptorFd *fd, Vio *sd, int state);
#define vio_close(vio) ((vio)->vioclose)(vio) #define vio_close(vio) ((vio)->vioclose)(vio)
#define vio_peer_addr(vio, buf, prt) (vio)->peer_addr(vio, buf, prt) #define vio_peer_addr(vio, buf, prt) (vio)->peer_addr(vio, buf, prt)
#define vio_in_addr(vio, in) (vio)->in_addr(vio, in) #define vio_in_addr(vio, in) (vio)->in_addr(vio, in)
#define vio_timeout(vio, seconds) (vio)->timeout(vio, seconds) #define vio_timeout(vio, which, seconds) (vio)->timeout(vio, which, seconds)
#endif /* defined(HAVE_VIO) && !defined(DONT_MAP_VIO) */ #endif /* defined(HAVE_VIO) && !defined(DONT_MAP_VIO) */
/* This enumerator is used in parser - should be always visible */ /* This enumerator is used in parser - should be always visible */
...@@ -180,7 +180,7 @@ struct st_vio ...@@ -180,7 +180,7 @@ struct st_vio
my_bool (*should_retry)(Vio*); my_bool (*should_retry)(Vio*);
my_bool (*was_interrupted)(Vio*); my_bool (*was_interrupted)(Vio*);
int (*vioclose)(Vio*); int (*vioclose)(Vio*);
void (*timeout)(Vio*, unsigned int timeout); void (*timeout)(Vio*, unsigned int which, unsigned int timeout);
void *ssl_arg; void *ssl_arg;
#endif /* HAVE_VIO */ #endif /* HAVE_VIO */
}; };
......
...@@ -229,6 +229,7 @@ my_bool vio_poll_read(Vio *vio,uint timeout) ...@@ -229,6 +229,7 @@ my_bool vio_poll_read(Vio *vio,uint timeout)
void vio_timeout(Vio *vio __attribute__((unused)), void vio_timeout(Vio *vio __attribute__((unused)),
uint which __attribute__((unused)),
uint timeout __attribute__((unused))) uint timeout __attribute__((unused)))
{ {
} }
......
...@@ -436,7 +436,7 @@ net_real_write(NET *net,const char *packet,ulong len) ...@@ -436,7 +436,7 @@ net_real_write(NET *net,const char *packet,ulong len)
thr_alarm(&alarmed,(uint) net->write_timeout,&alarm_buff); thr_alarm(&alarmed,(uint) net->write_timeout,&alarm_buff);
#else #else
alarmed=0; alarmed=0;
vio_timeout(net->vio, net->write_timeout); vio_timeout(net->vio, 1, net->write_timeout);
#endif /* NO_ALARM */ #endif /* NO_ALARM */
pos=(char*) packet; end=pos+len; pos=(char*) packet; end=pos+len;
...@@ -627,7 +627,7 @@ my_real_read(NET *net, ulong *complen) ...@@ -627,7 +627,7 @@ my_real_read(NET *net, ulong *complen)
if (net_blocking) if (net_blocking)
thr_alarm(&alarmed,net->read_timeout,&alarm_buff); thr_alarm(&alarmed,net->read_timeout,&alarm_buff);
#else #else
vio_timeout(net->vio, net->read_timeout); vio_timeout(net->vio, 0, net->read_timeout);
#endif /* NO_ALARM */ #endif /* NO_ALARM */
pos = net->buff + net->where_b; /* net->packet -4 */ pos = net->buff + net->where_b; /* net->packet -4 */
......
...@@ -345,12 +345,26 @@ my_bool vio_poll_read(Vio *vio,uint timeout) ...@@ -345,12 +345,26 @@ my_bool vio_poll_read(Vio *vio,uint timeout)
} }
void vio_timeout(Vio *vio __attribute__((unused)), void vio_timeout(Vio *vio, uint which, uint timeout)
uint timeout __attribute__((unused)))
{ {
#if defined(SO_SNDTIMEO) && defined(SO_RCVTIMEO)
#ifdef __WIN__ #ifdef __WIN__
ulong wait_timeout= (ulong) timeout * 1000;
(void) setsockopt(vio->sd, SOL_SOCKET, SO_RCVTIMEO, (char*) &wait_timeout, /* Windows expects time in milliseconds as int. */
sizeof(wait_timeout)); int wait_timeout= (int) timeout * 1000;
#endif /* __WIN__ */
#else /* ! __WIN__ */
/* POSIX specifies time as struct timeval. */
struct timeval wait_timeout;
wait_timeout.tv_sec= timeout;
wait_timeout.tv_usec= 0;
#endif /* ! __WIN__ */
(void) setsockopt(vio->sd, SOL_SOCKET, which ? SO_SNDTIMEO : SO_RCVTIMEO,
(char*) &wait_timeout, sizeof(wait_timeout));
#endif /* defined(SO_SNDTIMEO) && defined(SO_RCVTIMEO) */
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment