List:Commits« Previous MessageNext Message »
From:Davi Arnaut Date:November 14 2010 12:20pm
Subject:bzr commit into mysql-5.5-runtime branch (davi:3184)
View as plain text  
# At a local mysql-5.5-runtime repository of davi

 3184 Davi Arnaut	2010-11-14
      foobar

    added:
      vio/viopipe.c
      vio/vioshm.c
    modified:
      include/my_global.h
      include/mysql.h.pp
      include/mysql_com.h
      include/violite.h
      mysql-test/r/ssl.result
      mysql-test/r/wait_timeout.result
      mysql-test/t/ssl.test
      mysql-test/t/wait_timeout.test
      sql-common/client.c
      sql/net_serv.cc
      sql/sql_cache.cc
      vio/CMakeLists.txt
      vio/Makefile.am
      vio/vio.c
      vio/vio_priv.h
      vio/viosocket.c
      vio/viossl.c
=== modified file 'include/my_global.h'
--- a/include/my_global.h	2010-10-04 23:14:16 +0000
+++ b/include/my_global.h	2010-11-14 12:19:57 +0000
@@ -977,9 +977,10 @@ typedef ulong nesting_map;  /* Used for
 #define socket_errno	WSAGetLastError()
 #define SOCKET_EINTR	WSAEINTR
 #define SOCKET_EAGAIN	WSAEINPROGRESS
-#define SOCKET_ETIMEDOUT WSAETIMEDOUT
 #define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK
 #define SOCKET_EADDRINUSE WSAEADDRINUSE
+#define SOCKET_ETIMEDOUT WSAETIMEDOUT
+#define SOCKET_ECONNRESET WSAECONNRESET
 #define SOCKET_ENFILE	ENFILE
 #define SOCKET_EMFILE	EMFILE
 #else /* Unix */
@@ -987,9 +988,10 @@ typedef ulong nesting_map;  /* Used for
 #define closesocket(A)	close(A)
 #define SOCKET_EINTR	EINTR
 #define SOCKET_EAGAIN	EAGAIN
-#define SOCKET_ETIMEDOUT SOCKET_EINTR
 #define SOCKET_EWOULDBLOCK EWOULDBLOCK
 #define SOCKET_EADDRINUSE EADDRINUSE
+#define SOCKET_ETIMEDOUT ETIMEDOUT
+#define SOCKET_ECONNRESET ECONNRESET
 #define SOCKET_ENFILE	ENFILE
 #define SOCKET_EMFILE	EMFILE
 #endif

=== modified file 'include/mysql.h.pp'
--- a/include/mysql.h.pp	2010-10-04 12:42:16 +0000
+++ b/include/mysql.h.pp	2010-11-14 12:19:57 +0000
@@ -85,14 +85,14 @@ enum enum_mysql_set_option
 my_bool my_net_init(NET *net, Vio* vio);
 void my_net_local_init(NET *net);
 void net_end(NET *net);
-  void net_clear(NET *net, my_bool clear_buffer);
+void net_clear(NET *net, my_bool check_connection);
 my_bool net_realloc(NET *net, size_t length);
 my_bool net_flush(NET *net);
 my_bool my_net_write(NET *net,const unsigned char *packet, size_t len);
 my_bool net_write_command(NET *net,unsigned char command,
      const unsigned char *header, size_t head_len,
      const unsigned char *packet, size_t len);
-int net_real_write(NET *net,const unsigned char *packet, size_t len);
+my_bool net_write_packet(NET *net, const unsigned char *packet, size_t length);
 unsigned long my_net_read(NET *net);
 struct sockaddr;
 int my_connect(my_socket s, const struct sockaddr *name, unsigned int namelen,

=== modified file 'include/mysql_com.h'
--- a/include/mysql_com.h	2010-11-12 12:56:21 +0000
+++ b/include/mysql_com.h	2010-11-14 12:19:57 +0000
@@ -447,14 +447,14 @@ extern "C" {
 my_bool	my_net_init(NET *net, Vio* vio);
 void	my_net_local_init(NET *net);
 void	net_end(NET *net);
-  void	net_clear(NET *net, my_bool clear_buffer);
+void net_clear(NET *net, my_bool check_connection);
 my_bool net_realloc(NET *net, size_t length);
 my_bool	net_flush(NET *net);
 my_bool	my_net_write(NET *net,const unsigned char *packet, size_t len);
 my_bool	net_write_command(NET *net,unsigned char command,
 			  const unsigned char *header, size_t head_len,
 			  const unsigned char *packet, size_t len);
-int	net_real_write(NET *net,const unsigned char *packet, size_t len);
+my_bool net_write_packet(NET *net, const unsigned char *packet, size_t length);
 unsigned long my_net_read(NET *net);
 
 #ifdef _global_h

=== modified file 'include/violite.h'
--- a/include/violite.h	2010-06-07 14:01:39 +0000
+++ b/include/violite.h	2010-11-14 12:19:57 +0000
@@ -40,6 +40,14 @@ enum enum_vio_type
   VIO_TYPE_SSL, VIO_TYPE_SHARED_MEMORY
 };
 
+/**
+  VIO I/O events.
+*/
+enum enum_vio_io_event
+{
+  VIO_IO_EVENT_READ,
+  VIO_IO_EVENT_WRITE
+};
 
 #define VIO_LOCALHOST 1                         /* a localhost connection */
 #define VIO_BUFFERED_READ 2                     /* use buffered read */
@@ -61,13 +69,9 @@ Vio* vio_new_win32shared_memory(HANDLE h
 
 void	vio_delete(Vio* vio);
 int	vio_close(Vio* vio);
-void    vio_reset(Vio* vio, enum enum_vio_type type,
-                  my_socket sd, HANDLE hPipe, uint flags);
 size_t	vio_read(Vio *vio, uchar *	buf, size_t size);
 size_t  vio_read_buff(Vio *vio, uchar * buf, size_t size);
 size_t	vio_write(Vio *vio, const uchar * buf, size_t size);
-int	vio_blocking(Vio *vio, my_bool onoff, my_bool *old_mode);
-my_bool	vio_is_blocking(Vio *vio);
 /* setsockopt TCP_NODELAY at IPPROTO_TCP level, when possible */
 int	vio_fastsend(Vio *vio);
 /* setsockopt SO_KEEPALIVE at SOL_SOCKET level, when possible */
@@ -75,7 +79,7 @@ int	vio_keepalive(Vio *vio, my_bool	onof
 /* Whenever we should retry the last read/write operation. */
 my_bool	vio_should_retry(Vio *vio);
 /* Check that operation was timed out */
-my_bool	vio_was_interrupted(Vio *vio);
+my_bool vio_was_timeout(Vio *vio);
 /* Short text description of the socket for those, who are curious.. */
 const char* vio_description(Vio *vio);
 /* Return the type of the connection */
@@ -86,9 +90,12 @@ int	vio_errno(Vio*vio);
 my_socket vio_fd(Vio*vio);
 /* Remote peer's address and name in text form */
 my_bool vio_peer_addr(Vio *vio, char *buf, uint16 *port, size_t buflen);
-my_bool vio_poll_read(Vio *vio, uint timeout);
+/* Wait for an I/O event notification. */
+int vio_io_wait(Vio *vio, enum enum_vio_io_event event, int timeout);
 my_bool vio_is_connected(Vio *vio);
 ssize_t vio_pending(Vio *vio);
+/* Set timeout for a network operation. */
+int vio_timeout(Vio *vio, uint which, int timeout_sec);
 
 my_bool vio_get_normalized_ip_string(const struct sockaddr *addr, int addr_length,
                                      char *ip_string, size_t ip_string_size);
@@ -132,6 +139,8 @@ struct st_VioSSLFd
   SSL_CTX *ssl_context;
 };
 
+my_bool vio_rebind_ssl(Vio *vio, SSL *ssl);
+
 int sslaccept(struct st_VioSSLFd*, Vio *, long timeout);
 int sslconnect(struct st_VioSSLFd*, Vio *, long timeout);
 
@@ -158,17 +167,13 @@ void vio_end(void);
 #define vio_errno(vio)	 			(vio)->vioerrno(vio)
 #define vio_read(vio, buf, size)                ((vio)->read)(vio,buf,size)
 #define vio_write(vio, buf, size)               ((vio)->write)(vio, buf, size)
-#define vio_blocking(vio, set_blocking_mode, old_mode)\
- 	(vio)->vioblocking(vio, set_blocking_mode, old_mode)
-#define vio_is_blocking(vio) 			(vio)->is_blocking(vio)
 #define vio_fastsend(vio)			(vio)->fastsend(vio)
 #define vio_keepalive(vio, set_keep_alive)	(vio)->viokeepalive(vio, set_keep_alive)
 #define vio_should_retry(vio) 			(vio)->should_retry(vio)
-#define vio_was_interrupted(vio) 		(vio)->was_interrupted(vio)
+#define vio_was_timeout(vio)                    (vio)->was_timeout(vio)
 #define vio_close(vio)				((vio)->vioclose)(vio)
 #define vio_peer_addr(vio, buf, prt, buflen)	(vio)->peer_addr(vio, buf, prt, buflen)
-#define vio_timeout(vio, which, seconds)	(vio)->timeout(vio, which, seconds)
-#define vio_poll_read(vio, timeout)             (vio)->poll_read(vio, timeout)
+#define vio_io_wait(vio, event, timeout)        (vio)->io_wait(vio, event, timeout)
 #define vio_is_connected(vio)                   (vio)->is_connected(vio)
 #endif /* !defined(DONT_MAP_VIO) */
 
@@ -188,9 +193,7 @@ enum SSL_type
 struct st_vio
 {
   my_socket		sd;		/* my_socket - real or imaginary */
-  HANDLE hPipe;
   my_bool		localhost;	/* Are we from localhost? */
-  int			fcntl_mode;	/* Buffered fcntl(sd,F_GETFL) */
   struct sockaddr_storage	local;		/* Local internet address */
   struct sockaddr_storage	remote;		/* Remote internet address */
   int addrLen;                          /* Length of remote address */
@@ -200,26 +203,31 @@ struct st_vio
   char                  *read_pos;      /* start of unfetched data in the
                                            read buffer */
   char                  *read_end;      /* end of unfetched data */
+  int                   read_timeout;   /* Timeout value (ms) for read ops. */
+  int                   write_timeout;  /* Timeout value (ms) for write ops. */
   /* function pointers. They are similar for socket/SSL/whatever */
   void    (*viodelete)(Vio*);
   int     (*vioerrno)(Vio*);
   size_t  (*read)(Vio*, uchar *, size_t);
   size_t  (*write)(Vio*, const uchar *, size_t);
-  int     (*vioblocking)(Vio*, my_bool, my_bool *);
-  my_bool (*is_blocking)(Vio*);
+  int     (*timeout)(Vio*, uint, my_bool);
   int     (*viokeepalive)(Vio*, my_bool);
   int     (*fastsend)(Vio*);
   my_bool (*peer_addr)(Vio*, char *, uint16*, size_t);
   void    (*in_addr)(Vio*, struct sockaddr_storage*);
   my_bool (*should_retry)(Vio*);
-  my_bool (*was_interrupted)(Vio*);
+  my_bool (*was_timeout)(Vio*);
   int     (*vioclose)(Vio*);
-  void	  (*timeout)(Vio*, unsigned int which, unsigned int timeout);
-  my_bool (*poll_read)(Vio *vio, uint timeout);
   my_bool (*is_connected)(Vio*);
   my_bool (*has_data) (Vio*);
+  int (*io_wait)(Vio*, enum enum_vio_io_event, int);
+#ifdef _WIN32
+  OVERLAPPED overlapped;
+  HANDLE hPipe;
+#endif
 #ifdef HAVE_OPENSSL
   void	  *ssl_arg;
+  int     ssl_error;
 #endif
 #ifdef HAVE_SMEM
   HANDLE  handle_file_map;
@@ -232,10 +240,5 @@ struct st_vio
   size_t  shared_memory_remain;
   char    *shared_memory_pos;
 #endif /* HAVE_SMEM */
-#ifdef _WIN32
-  OVERLAPPED pipe_overlapped;
-  DWORD read_timeout_ms;
-  DWORD write_timeout_ms;
-#endif
 };
 #endif /* vio_violite_h_ */

=== modified file 'mysql-test/r/ssl.result'
--- a/mysql-test/r/ssl.result	2010-02-20 10:07:32 +0000
+++ b/mysql-test/r/ssl.result	2010-11-14 12:19:57 +0000
@@ -2157,3 +2157,10 @@ drop table t1;
 SHOW STATUS LIKE 'Ssl_cipher';
 Variable_name	Value
 Ssl_cipher	DHE-RSA-AES256-SHA
+#
+# Bug#54790: Use of non-blocking mode for sockets limits performance
+#
+SET @@SESSION.wait_timeout = 5;
+# CR_SERVER_LOST, CR_SERVER_GONE_ERROR
+SELECT 1;
+Got one of the listed errors

=== modified file 'mysql-test/r/wait_timeout.result'
--- a/mysql-test/r/wait_timeout.result	2009-01-23 17:19:09 +0000
+++ b/mysql-test/r/wait_timeout.result	2010-11-14 12:19:57 +0000
@@ -31,3 +31,10 @@ SELECT 3;
 3
 SET @@global.wait_timeout= <start_value>;
 disconnection con1;
+#
+# Bug#54790: Use of non-blocking mode for sockets limits performance
+#
+SET @@SESSION.wait_timeout = 5;
+# CR_SERVER_LOST, CR_SERVER_GONE_ERROR
+SELECT 1;
+Got one of the listed errors

=== modified file 'mysql-test/t/ssl.test'
--- a/mysql-test/t/ssl.test	2010-04-13 15:04:45 +0000
+++ b/mysql-test/t/ssl.test	2010-11-14 12:19:57 +0000
@@ -20,6 +20,31 @@ SHOW STATUS LIKE 'Ssl_cipher';
 connection default;
 disconnect ssl_con;
 
+--echo #
+--echo # Bug#54790: Use of non-blocking mode for sockets limits performance
+--echo #
+
+connect (ssl_con,localhost,root,,,,,SSL);
+
+LET $ID= `SELECT connection_id()`;
+SET @@SESSION.wait_timeout = 5;
+
+connection default;
+
+let $wait_condition=
+  SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.PROCESSLIST
+  WHERE ID = $ID;
+--source include/wait_condition.inc
+
+connection ssl_con;
+
+--echo # CR_SERVER_LOST, CR_SERVER_GONE_ERROR
+--error 2006,2013
+SELECT 1;
+
+connection default;
+disconnect ssl_con;
+
 # Wait till all disconnects are completed
 --source include/wait_until_count_sessions.inc
 

=== modified file 'mysql-test/t/wait_timeout.test'
--- a/mysql-test/t/wait_timeout.test	2010-10-19 11:54:28 +0000
+++ b/mysql-test/t/wait_timeout.test	2010-11-14 12:19:57 +0000
@@ -137,6 +137,34 @@ disconnect con1;
 # The last connect is to keep tools checking the current test happy.
 connect (default,localhost,root,,test,,);
 
+--echo #
+--echo # Bug#54790: Use of non-blocking mode for sockets limits performance
+--echo #
+
+connect (con1,localhost,root,,);
+
+connection con1;
+
+LET $ID= `SELECT connection_id()`;
+SET @@SESSION.wait_timeout = 5;
+
+connection default;
+
+let $wait_condition=
+  SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.PROCESSLIST
+  WHERE ID = $ID;
+--source include/wait_condition.inc
+
+connection con1;
+
+--echo # CR_SERVER_LOST, CR_SERVER_GONE_ERROR
+--error 2006,2013
+SELECT 1;
+
+disconnect con1;
+
+connection default;
+
 # Wait till all disconnects are completed
 --source include/wait_until_count_sessions.inc
 

=== modified file 'sql-common/client.c'
--- a/sql-common/client.c	2010-11-10 15:21:51 +0000
+++ b/sql-common/client.c	2010-11-14 12:19:57 +0000
@@ -744,7 +744,7 @@ cli_safe_read(MYSQL *mysql)
     DBUG_PRINT("error",("Wrong connection or packet. fd: %s  len: %lu",
 			vio_description(net->vio),len));
 #ifdef MYSQL_SERVER
-    if (net->vio && vio_was_interrupted(net->vio))
+    if (net->vio && (net->last_errno == ER_NET_READ_INTERRUPTED))
       return (packet_error);
 #endif /*MYSQL_SERVER*/
     end_server(mysql);
@@ -3275,12 +3275,13 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
   /* Get version info */
   mysql->protocol_version= PROTOCOL_VERSION;	/* Assume this */
   if (mysql->options.connect_timeout &&
-      vio_poll_read(net->vio, mysql->options.connect_timeout))
+      (vio_io_wait(net->vio, VIO_IO_EVENT_READ,
+                   mysql->options.connect_timeout * 1000) < 1))
   {
     set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
                              ER(CR_SERVER_LOST_EXTENDED),
                              "waiting for initial communication packet",
-                             errno);
+                             socket_errno);
     goto error;
   }
 
@@ -3295,7 +3296,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
       set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
                                ER(CR_SERVER_LOST_EXTENDED),
                                "reading initial communication packet",
-                               errno);
+                               socket_errno);
     goto error;
   }
   pkt_end= (char*)net->read_pos + pkt_length;

=== modified file 'sql/net_serv.cc'
--- a/sql/net_serv.cc	2010-09-16 10:38:13 +0000
+++ b/sql/net_serv.cc	2010-11-14 12:19:57 +0000
@@ -61,29 +61,12 @@
   the client should have a bigger max_allowed_packet.
 */
 
-#if defined(__WIN__) || !defined(MYSQL_SERVER)
-  /* The following is because alarms doesn't work on windows. */
-#ifndef NO_ALARM
-#define NO_ALARM
-#endif
-#endif
-
-#ifndef NO_ALARM
-#include "my_pthread.h"
-void sql_print_error(const char *format,...);
-#else
-#define DONT_USE_THR_ALARM
-#endif /* NO_ALARM */
-
-#include "thr_alarm.h"
-
 #ifdef MYSQL_SERVER
 /*
   The following variables/functions should really not be declared
   extern, but as it's hard to include sql_priv.h here, we have to
   live with this for a while.
 */
-extern uint test_flags;
 extern ulong bytes_sent, bytes_received, net_big_packet_count;
 #ifndef MYSQL_INSTANCE_MANAGER
 #ifdef HAVE_QUERY_CACHE
@@ -100,11 +83,10 @@ extern void query_cache_insert(const cha
 #define thd_increment_bytes_sent(N)
 #endif
 
-#define TEST_BLOCKING		8
+#define VIO_SOCKET_ERROR  ((size_t) -1)
 #define MAX_PACKET_LENGTH (256L*256L*256L-1)
 
-static my_bool net_write_buff(NET *net,const uchar *packet,ulong len);
-
+static my_bool net_write_buff(NET *, const uchar *, ulong);
 
 /** Init with packet info. */
 
@@ -130,16 +112,10 @@ my_bool my_net_init(NET *net, Vio* vio)
   net->skip_big_packet= FALSE;
 #endif
 
-  if (vio != 0)					/* If real connection */
+  if (vio)
   {
-    net->fd  = vio_fd(vio);			/* For perl DBI/DBD */
-#if defined(MYSQL_SERVER) && !defined(__WIN__)
-    if (!(test_flags & TEST_BLOCKING))
-    {
-      my_bool old_mode;
-      vio_blocking(vio, FALSE, &old_mode);
-    }
-#endif
+    /* For perl DBI/DBD. */
+    net->fd= vio_fd(vio);
     vio_fastsend(vio);
   }
   DBUG_RETURN(0);
@@ -190,7 +166,7 @@ my_bool net_realloc(NET *net, size_t len
   /*
     We must allocate some extra bytes for the end 0 and to be able to
     read big compressed blocks + 1 safety byte since uint3korr() in
-    my_real_read() may actually read 4 bytes depending on build flags and
+    net_read_packet() may actually read 4 bytes depending on build flags and
     platform.
   */
   if (!(buff= (uchar*) my_realloc((char*) net->buff, pkt_length +
@@ -208,130 +184,28 @@ my_bool net_realloc(NET *net, size_t len
   DBUG_RETURN(0);
 }
 
-
-/**
-  Check if there is any data to be read from the socket.
-
-  @param sd   socket descriptor
-
-  @retval
-    0  No data to read
-  @retval
-    1  Data or EOF to read
-  @retval
-    -1   Don't know if data is ready or not
-*/
-
-#if !defined(EMBEDDED_LIBRARY)
-
-static int net_data_is_ready(my_socket sd)
-{
-#ifdef HAVE_POLL
-  struct pollfd ufds;
-  int res;
-
-  ufds.fd= sd;
-  ufds.events= POLLIN | POLLPRI;
-  if (!(res= poll(&ufds, 1, 0)))
-    return 0;
-  if (res < 0 || !(ufds.revents & (POLLIN | POLLPRI)))
-    return 0;
-  return 1;
-#else
-  fd_set sfds;
-  struct timeval tv;
-  int res;
-
-#ifndef __WIN__
-  /* Windows uses an _array_ of 64 fd's as default, so it's safe */
-  if (sd >= FD_SETSIZE)
-    return -1;
-#define NET_DATA_IS_READY_CAN_RETURN_MINUS_ONE
-#endif
-
-  FD_ZERO(&sfds);
-  FD_SET(sd, &sfds);
-
-  tv.tv_sec= tv.tv_usec= 0;
-
-  if ((res= select((int) (sd + 1), &sfds, NULL, NULL, &tv)) < 0)
-    return 0;
-  else
-    return test(res ? FD_ISSET(sd, &sfds) : 0);
-#endif /* HAVE_POLL */
-}
-
-#endif /* EMBEDDED_LIBRARY */
-
 /**
-  Remove unwanted characters from connection
-  and check if disconnected.
-
-    Read from socket until there is nothing more to read. Discard
-    what is read.
+  Clear (reinitialize) the NET structure for a new command.
 
-    If there is anything when to read 'net_clear' is called this
-    normally indicates an error in the protocol.
-
-    When connection is properly closed (for TCP it means with
-    a FIN packet), then select() considers a socket "ready to read",
-    in the sense that there's EOF to read, but read() returns 0.
-
-  @param net			NET handler
-  @param clear_buffer           if <> 0, then clear all data from comm buff
+  @param net  NET handler
+  @param check_connection  Whether to check the connection status.
 */
 
-void net_clear(NET *net, my_bool clear_buffer)
+void net_clear(NET *net, my_bool check_connection)
 {
-#if !defined(EMBEDDED_LIBRARY)
-  size_t count;
-  int ready;
-#endif
   DBUG_ENTER("net_clear");
 
 #if !defined(EMBEDDED_LIBRARY)
-  if (clear_buffer)
+  if (check_connection)
   {
-    while ((ready= net_data_is_ready(net->vio->sd)) > 0)
-    {
-      /* The socket is ready */
-      if ((long) (count= vio_read(net->vio, net->buff,
-                                  (size_t) net->max_packet)) > 0)
-      {
-        DBUG_PRINT("info",("skipped %ld bytes from file: %s",
-                           (long) count, vio_description(net->vio)));
-#if defined(EXTRA_DEBUG)
-        fprintf(stderr,"Note: net_clear() skipped %ld bytes from file: %s\n",
-                (long) count, vio_description(net->vio));
-#endif
-      }
-      else
-      {
-        DBUG_PRINT("info",("socket ready but only EOF to read - disconnected"));
-        net->error= 2;
-        break;
-      }
-    }
-#ifdef NET_DATA_IS_READY_CAN_RETURN_MINUS_ONE
-    /* 'net_data_is_ready' returned "don't know" */
-    if (ready == -1)
-    {
-      /* Read unblocking to clear net */
-      my_bool old_mode;
-      if (!vio_blocking(net->vio, FALSE, &old_mode))
-      {
-        while ((long) (count= vio_read(net->vio, net->buff,
-                                       (size_t) net->max_packet)) > 0)
-          DBUG_PRINT("info",("skipped %ld bytes from file: %s",
-                             (long) count, vio_description(net->vio)));
-        vio_blocking(net->vio, TRUE, &old_mode);
-      }
-    }
-#endif /* NET_DATA_IS_READY_CAN_RETURN_MINUS_ONE */
+    if (vio_is_connected(net->vio) == FALSE)
+      net->error= 2;
   }
 #endif /* EMBEDDED_LIBRARY */
-  net->pkt_nr=net->compress_pkt_nr=0;		/* Ready for new command */
-  net->write_pos=net->buff;
+
+  /* Ready for new command */
+  net->pkt_nr= net->compress_pkt_nr= 0;
+  net->write_pos= net->buff;
   DBUG_VOID_RETURN;
 }
 
@@ -344,9 +218,9 @@ my_bool net_flush(NET *net)
   DBUG_ENTER("net_flush");
   if (net->buff != net->write_pos)
   {
-    error=test(net_real_write(net, net->buff,
-			      (size_t) (net->write_pos - net->buff)));
-    net->write_pos=net->buff;
+    error= net_write_packet(net, net->buff,
+                            (size_t) (net->write_pos - net->buff));
+    net->write_pos= net->buff;
   }
   /* Sync packet number if using compression */
   if (net->compress)
@@ -355,6 +229,48 @@ my_bool net_flush(NET *net)
 }
 
 
+/**
+  Whether a I/O operation should be retried later.
+
+  @param net          NET handler.
+  @param retry_count  Maximum number of interrupted operations.
+
+  @retval TRUE    Operation should be retried.
+  @retval FALSE   Operation should not be retried. Fatal error.
+*/
+
+static my_bool
+net_should_retry(NET *net, uint *retry_count __attribute__((unused)))
+{
+  my_bool retry;
+
+#if defined(MYSQL_SERVER) && !defined(DONT_USE_THR_ALARM)
+  /*
+    In the server, interrupted I/O operations are not retried
+    if thread alarm is being used (DONT_USE_THR_ALARM is not
+    defined). In this scenario, pthread_kill is used to wake up
+    (interrupt) threads waiting for I/O.
+  */
+  retry= FALSE;
+#elif !defined(MYSQL_SERVER) && defined(THREAD_SAFE_CLIENT)
+  /*
+    In the thread safe client library, interrupted I/O operations
+    are always retried.  Otherwise, its either a timeout or a
+    unrecoverable error.
+  */
+  retry= vio_should_retry(net->vio);
+#else
+  /*
+    In the non-thread safe client library, or in the server without
+    alarm, interrupted I/O operations are retried up to a limit.
+  */
+  retry= vio_should_retry(net->vio) && ((*retry_count)++ < net->retry_count);
+#endif
+
+  return retry;
+}
+
+
 /*****************************************************************************
 ** Write something to server/client buffer
 *****************************************************************************/
@@ -362,15 +278,13 @@ my_bool net_flush(NET *net)
 /**
   Write a logical packet with packet header.
 
-  Format: Packet length (3 bytes), packet number(1 byte)
+  Format: Packet length (3 bytes), packet number (1 byte)
   When compression is used a 3 byte compression length is added
 
-  @note
-    If compression is used the original package is modified!
+  @note If compression is used the original packet is modified!
 */
 
-my_bool
-my_net_write(NET *net,const uchar *packet,size_t len)
+my_bool my_net_write(NET *net, const uchar *packet, size_t len)
 {
   uchar buff[NET_HEADER_SIZE];
   int rc;
@@ -507,7 +421,7 @@ net_write_command(NET *net,uchar command
   @note
     The cached buffer can be sent as it is with 'net_flush()'.
     In this code we have to be careful to not send a packet longer than
-    MAX_PACKET_LENGTH to net_real_write() if we are using the compressed
+    MAX_PACKET_LENGTH to net_write_packet() if we are using the compressed
     protocol as we store the length of the compressed packet in 3 bytes.
 
   @retval
@@ -533,9 +447,9 @@ net_write_buff(NET *net, const uchar *pa
     if (net->write_pos != net->buff)
     {
       /* Fill up already used packet and write it */
-      memcpy((char*) net->write_pos,packet,left_length);
-      if (net_real_write(net, net->buff, 
-			 (size_t) (net->write_pos - net->buff) + left_length))
+      memcpy(net->write_pos, packet, left_length);
+      if (net_write_packet(net, net->buff,
+                           (size_t) (net->write_pos - net->buff) + left_length))
 	return 1;
       net->write_pos= net->buff;
       packet+= left_length;
@@ -550,461 +464,364 @@ net_write_buff(NET *net, const uchar *pa
       left_length= MAX_PACKET_LENGTH;
       while (len > left_length)
       {
-	if (net_real_write(net, packet, left_length))
+	if (net_write_packet(net, packet, left_length))
 	  return 1;
 	packet+= left_length;
 	len-= left_length;
       }
     }
     if (len > net->max_packet)
-      return net_real_write(net, packet, len) ? 1 : 0;
+      return net_write_packet(net, packet, len);
     /* Send out rest of the blocks as full sized blocks */
   }
-  memcpy((char*) net->write_pos,packet,len);
+  memcpy(net->write_pos, packet, len);
   net->write_pos+= len;
   return 0;
 }
 
-
 /**
-  Read and write one packet using timeouts.
-  If needed, the packet is compressed before sending.
+  Write a determined number of bytes to a network handler.
 
-  @todo
-    - TODO is it needed to set this variable if we have no socket
+  @param  net     NET handler.
+  @param  buf     Buffer containing the data to be written.
+  @param  count   The length, in bytes, of the buffer.
+
+  @return TRUE on error, FALSE on success.
 */
 
-int
-net_real_write(NET *net,const uchar *packet, size_t len)
+static my_bool
+net_write_raw_loop(NET *net, const uchar *buf, size_t count)
 {
-  size_t length;
-  const uchar *pos,*end;
-  thr_alarm_t alarmed;
-#ifndef NO_ALARM
-  ALARM alarm_buff;
+  unsigned int retry_count= 0;
+
+  while (count)
+  {
+    size_t sentcnt= vio_write(net->vio, buf, count);
+
+    /* VIO_SOCKET_ERROR (-1) indicates an error. */
+    if (sentcnt == VIO_SOCKET_ERROR)
+    {
+      /* A recoverable I/O error occurred? */
+      if (net_should_retry(net, &retry_count))
+        continue;
+      else
+        break;
+    }
+
+    count-= sentcnt;
+    buf+= sentcnt;
+    update_statistics(thd_increment_bytes_sent(sentcnt));
+  }
+
+  /* On failure, propagate the error code. */
+  if (count)
+  {
+    /* Socket should be closed. */
+    net->error= 2;
+
+    /* Interrupted by a timeout? */
+    if (vio_was_timeout(net->vio))
+      net->last_errno= ER_NET_WRITE_INTERRUPTED;
+    else
+      net->last_errno= ER_NET_ERROR_ON_WRITE;
+
+#ifdef MYSQL_SERVER
+    my_error(net->last_errno, MYF(0));
 #endif
-  uint retry_count=0;
-  my_bool net_blocking = vio_is_blocking(net->vio);
-  DBUG_ENTER("net_real_write");
+  }
+
+  return test(count);
+}
+
+/**
+  Compress and encapsulate a packet into a compressed packet.
+
+  param           net      NET handler.
+  @param          packet   The packet to compress.
+  @param[in,out]  length   Length of the packet.
+
+  A compressed packet header is compromised of the packet
+  length (3 bytes), packet number (1 byte) and the length
+  of the original (uncompressed) packet.
+
+  @return Pointer to the (new) compressed packet.
+*/
+
+static uchar *
+compress_packet(NET *net, const uchar *packet, size_t *length)
+{
+  uchar *compr_packet;
+  size_t compr_length;
+  const uint header_length= NET_HEADER_SIZE + COMP_HEADER_SIZE;
+
+  compr_packet= (uchar *) my_malloc(*length + header_length, MYF(MY_WME));
+
+  if (compr_packet == NULL)
+    return NULL;
+
+  memcpy(compr_packet + header_length, packet, *length);
+
+  /* Compress the encapsulated packet. */
+  if (my_compress(compr_packet + header_length, length, &compr_length))
+  {
+    /*
+      If the length of the compressed packet is larger than the
+      original packet, the original packet is sent uncompressed.
+    */
+    compr_length= 0;
+  }
+
+  /* Length of the compressed (original) packet. */
+  int3store(&compr_packet[NET_HEADER_SIZE], compr_length);
+  /* Length of this packet. */
+  int3store(compr_packet, *length);
+  /* Packet number. */
+  compr_packet[3]= (uchar) (net->compress_pkt_nr++);
+
+  *length+= header_length;
+
+  return compr_packet;
+}
+
+/**
+  Write a MySQL protocol packet to the network handler.
+
+  @param  net     NET handler.
+  @param  packet  The packet to .
+  @param  lenght  Length of the packet.
+
+  @remark The packet might be encapsulated into a compressed packet.
+
+  @return TRUE on error, FALSE on success.
+*/
+
+my_bool
+net_write_packet(NET *net, const uchar *packet, size_t length)
+{
+  my_bool res;
+  DBUG_ENTER("net_write_packet");
 
 #if defined(MYSQL_SERVER) && defined(USE_QUERY_CACHE)
-  query_cache_insert((char*) packet, len, net->pkt_nr);
+  query_cache_insert((char*) packet, length, net->pkt_nr);
 #endif
 
+  /* Socket can't be used */
   if (net->error == 2)
-    DBUG_RETURN(-1);				/* socket can't be used */
+    DBUG_RETURN(TRUE);
+
+  net->reading_or_writing= 2;
 
-  net->reading_or_writing=2;
 #ifdef HAVE_COMPRESS
   if (net->compress)
   {
-    size_t complen;
-    uchar *b;
-    uint header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
-    if (!(b= (uchar*) my_malloc(len + NET_HEADER_SIZE +
-                                COMP_HEADER_SIZE, MYF(MY_WME))))
+    if ((packet= compress_packet(net, packet, &length)) == NULL)
     {
       net->error= 2;
       net->last_errno= ER_OUT_OF_RESOURCES;
-      /* In the server, the error is reported by MY_WME flag. */
+      /* In the server, allocation failure raises a error. */
       net->reading_or_writing= 0;
-      DBUG_RETURN(1);
+      DBUG_RETURN(TRUE);
     }
-    memcpy(b+header_length,packet,len);
-
-    if (my_compress(b+header_length, &len, &complen))
-      complen=0;
-    int3store(&b[NET_HEADER_SIZE],complen);
-    int3store(b,len);
-    b[3]=(uchar) (net->compress_pkt_nr++);
-    len+= header_length;
-    packet= b;
   }
 #endif /* HAVE_COMPRESS */
 
 #ifdef DEBUG_DATA_PACKETS
-  DBUG_DUMP("data", packet, len);
+  DBUG_DUMP("data", packet, length);
 #endif
 
-#ifndef NO_ALARM
-  thr_alarm_init(&alarmed);
-  if (net_blocking)
-    thr_alarm(&alarmed, net->write_timeout, &alarm_buff);
-#else
-  alarmed=0;
-  /* Write timeout is set in my_net_set_write_timeout */
-#endif /* NO_ALARM */
-
-  pos= packet;
-  end=pos+len;
-  while (pos != end)
-  {
-    if ((long) (length= vio_write(net->vio,pos,(size_t) (end-pos))) <= 0)
-    {
-      my_bool interrupted = vio_should_retry(net->vio);
-#if !defined(__WIN__)
-      if ((interrupted || length == 0) && !thr_alarm_in_use(&alarmed))
-      {
-        if (!thr_alarm(&alarmed, net->write_timeout, &alarm_buff))
-        {                                       /* Always true for client */
-	  my_bool old_mode;
-	  while (vio_blocking(net->vio, TRUE, &old_mode) < 0)
-	  {
-	    if (vio_should_retry(net->vio) && retry_count++ < net->retry_count)
-	      continue;
-#ifdef EXTRA_DEBUG
-	    fprintf(stderr,
-		    "%s: my_net_write: fcntl returned error %d, aborting thread\n",
-		    my_progname,vio_errno(net->vio));
-#endif /* EXTRA_DEBUG */
-	    net->error= 2;                     /* Close socket */
-            net->last_errno= ER_NET_PACKET_TOO_LARGE;
-#ifdef MYSQL_SERVER
-            my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
-#endif
-	    goto end;
-	  }
-	  retry_count=0;
-	  continue;
-	}
-      }
-      else
-#endif /* !defined(__WIN__) */
-	if (thr_alarm_in_use(&alarmed) && !thr_got_alarm(&alarmed) &&
-	    interrupted)
-      {
-	if (retry_count++ < net->retry_count)
-	    continue;
-#ifdef EXTRA_DEBUG
-	  fprintf(stderr, "%s: write looped, aborting thread\n",
-		  my_progname);
-#endif /* EXTRA_DEBUG */
-      }
-#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
-      if (vio_errno(net->vio) == SOCKET_EINTR)
-      {
-	DBUG_PRINT("warning",("Interrupted write. Retrying..."));
-	continue;
-      }
-#endif /* defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) */
-      net->error= 2;				/* Close socket */
-      net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
-                               ER_NET_ERROR_ON_WRITE);
-#ifdef MYSQL_SERVER
-      my_error(net->last_errno, MYF(0));
-#endif /* MYSQL_SERVER */
-      break;
-    }
-    pos+=length;
-    update_statistics(thd_increment_bytes_sent(length));
-  }
-#ifndef __WIN__
- end:
-#endif
+  res= net_write_raw_loop(net, packet, length);
+
 #ifdef HAVE_COMPRESS
   if (net->compress)
-    my_free((void*) packet);
+    my_free((void *) packet);
 #endif
-  if (thr_alarm_in_use(&alarmed))
-  {
-    my_bool old_mode;
-    thr_end_alarm(&alarmed);
-    vio_blocking(net->vio, net_blocking, &old_mode);
-  }
-  net->reading_or_writing=0;
-  DBUG_RETURN(((int) (pos != end)));
-}
 
+  net->reading_or_writing= 0;
+
+  DBUG_RETURN(res);
+}
 
 /*****************************************************************************
 ** Read something from server/clinet
 *****************************************************************************/
 
-#ifndef NO_ALARM
+/**
+  Read a determined number of bytes from a network handler.
+
+  @param  net     NET handler.
+  @param  count   The number of bytes to read.
 
-static my_bool net_safe_read(NET *net, uchar *buff, size_t length,
-			     thr_alarm_t *alarmed)
+  @return TRUE on error, FALSE on success.
+*/
+static my_bool net_read_raw_loop(NET *net, size_t count)
 {
-  uint retry_count=0;
-  while (length > 0)
+  unsigned int retry_count= 0;
+  uchar *buf= net->buff + net->where_b;
+
+  while (count)
   {
-    size_t tmp;
-    if ((long) (tmp= vio_read(net->vio, buff, length)) <= 0)
+    size_t recvcnt= vio_read(net->vio, buf, count);
+
+    /* VIO_SOCKET_ERROR (-1) indicates an error. */
+    if (recvcnt == VIO_SOCKET_ERROR)
     {
-      my_bool interrupted = vio_should_retry(net->vio);
-      if (!thr_got_alarm(alarmed) && interrupted)
-      {					/* Probably in MIT threads */
-	if (retry_count++ < net->retry_count)
-	  continue;
-      }
-      return 1;
+      /* A recoverable I/O error occurred? */
+      if (net_should_retry(net, &retry_count))
+        continue;
+      else
+        break;
     }
-    length-= tmp;
-    buff+= tmp;
+    /* Zero indicates end of file. */
+    else if (!recvcnt)
+      break;
+
+    count-= recvcnt;
+    buf+= recvcnt;
+    update_statistics(thd_increment_bytes_received(recvcnt));
   }
-  return 0;
+
+  /* On failure, propagate the error code. */
+  if (count)
+  {
+    /* Socket should be closed. */
+    net->error= 2;
+
+    /* Interrupted by a timeout? */
+    if (vio_was_timeout(net->vio))
+      net->last_errno= ER_NET_READ_INTERRUPTED;
+    else
+      net->last_errno= ER_NET_READ_ERROR;
+
+#ifdef MYSQL_SERVER
+    my_error(net->last_errno, MYF(0));
+#endif
+  }
+
+  return test(count);
 }
 
+
+
 /**
-  Help function to clear the commuication buffer when we get a too big packet.
+  Read the header of a packet. The MySQL protocol packet header
+  consists of the length, in bytes, of the payload (packet data)
+  and a serial number.
 
-  @param net		Communication handle
-  @param remain	Bytes to read
-  @param alarmed	Parameter for thr_alarm()
-  @param alarm_buff	Parameter for thr_alarm()
+  @remark The encoded length is the length of the packet payload,
+          which does not include the packet header.
 
-  @retval
-   0	Was able to read the whole packet
-  @retval
-   1	Got mailformed packet from client
-*/
+  @remark The serial number is used to ensure that the packets are
+          received in order. If the packet serial number does not
+          match the expected value, a error is returned.
+
+  @param  net  NET handler.
 
-static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed,
-				ALARM *alarm_buff)
+  @return TRUE on error, FALSE on success.
+*/
+static my_bool net_read_packet_header(NET *net)
 {
-  uint32 old=remain;
-  DBUG_ENTER("my_net_skip_rest");
-  DBUG_PRINT("enter",("bytes_to_skip: %u", (uint) remain));
+  uchar pkt_nr;
+  size_t count= NET_HEADER_SIZE;
 
-  /* The following is good for debugging */
-  update_statistics(thd_increment_net_big_packet_count(1));
+  if (net->compress)
+    count+= COMP_HEADER_SIZE;
 
-  if (!thr_alarm_in_use(alarmed))
-  {
-    my_bool old_mode;
-    if (thr_alarm(alarmed,net->read_timeout, alarm_buff) ||
-	vio_blocking(net->vio, TRUE, &old_mode) < 0)
-      DBUG_RETURN(1);				/* Can't setup, abort */
-  }
-  for (;;)
+  if (net_read_raw_loop(net, count))
+    return TRUE;
+
+  DBUG_DUMP("packet_header", net->buff + net->where_b, NET_HEADER_SIZE);
+
+  pkt_nr= net->buff[net->where_b + 3];
+
+  /*
+    Verify packet serial number against the truncated packet counter.
+    The local packet counter must be truncated since its not reset.
+  */
+  if (pkt_nr != (uchar) net->pkt_nr)
   {
-    while (remain > 0)
-    {
-      size_t length= min(remain, net->max_packet);
-      if (net_safe_read(net, net->buff, length, alarmed))
-	DBUG_RETURN(1);
-      update_statistics(thd_increment_bytes_received(length));
-      remain -= (uint32) length;
-    }
-    if (old != MAX_PACKET_LENGTH)
-      break;
-    if (net_safe_read(net, net->buff, NET_HEADER_SIZE, alarmed))
-      DBUG_RETURN(1);
-    old=remain= uint3korr(net->buff);
-    net->pkt_nr++;
+    /* Not a NET error on the client. XXX: why? */
+#if defined(MYSQL_SERVER)
+    my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0));
+#elif defined(EXTRA_DEBUG)
+    fprintf(stderr, "Error: packets out of order (found %u, expected %u)\n",
+            (uint) pkt_nr, net->pkt_nr);
+    DBUG_ASSERT(pkt_nr == net->pkt_nr);
+#endif
   }
-  DBUG_RETURN(0);
+
+  net->pkt_nr++;
+
+  return FALSE;
 }
-#endif /* NO_ALARM */
 
 
 /**
-  Reads one packet to net->buff + net->where_b.
-  Long packets are handled by my_net_read().
-  This function reallocates the net->buff buffer if necessary.
+  Read one (variable-length) MySQL protocol packet.
+  A MySQL packet consists of a header and a payload.
 
-  @return
-    Returns length of packet.
-*/
+  @remark Reads one packet to net->buff + net->where_b.
+  @remark Long packets are handled by my_net_read().
+  @remark The network buffer is expanded if necessary.
 
-static ulong
-my_real_read(NET *net, size_t *complen)
+  @return The length of the packet, or @packet_error on error.
+*/
+static ulong net_read_packet(NET *net, size_t *complen)
 {
-  uchar *pos;
-  size_t length;
-  uint i,retry_count=0;
-  ulong len=packet_error;
-  thr_alarm_t alarmed;
-#ifndef NO_ALARM
-  ALARM alarm_buff;
-#endif
-  my_bool net_blocking=vio_is_blocking(net->vio);
-  uint32 remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
-		  NET_HEADER_SIZE);
-  *complen = 0;
-
-  net->reading_or_writing=1;
-  thr_alarm_init(&alarmed);
-#ifndef NO_ALARM
-  if (net_blocking)
-    thr_alarm(&alarmed,net->read_timeout,&alarm_buff);
-#else
-  /* Read timeout is set in my_net_set_read_timeout */
-#endif /* NO_ALARM */
+  size_t pkt_len, pkt_data_len;
 
-    pos = net->buff + net->where_b;		/* net->packet -4 */
-    for (i=0 ; i < 2 ; i++)
-    {
-      while (remain > 0)
-      {
-	/* First read is done with non blocking mode */
-        if ((long) (length= vio_read(net->vio, pos, remain)) <= 0L)
-        {
-          my_bool interrupted = vio_should_retry(net->vio);
-
-	  DBUG_PRINT("info",("vio_read returned %ld  errno: %d",
-			     (long) length, vio_errno(net->vio)));
-#if !defined(__WIN__) || defined(MYSQL_SERVER)
-	  /*
-	    We got an error that there was no data on the socket. We now set up
-	    an alarm to not 'read forever', change the socket to non blocking
-	    mode and try again
-	  */
-	  if ((interrupted || length == 0) && !thr_alarm_in_use(&alarmed))
-	  {
-	    if (!thr_alarm(&alarmed,net->read_timeout,&alarm_buff)) /* Don't wait too long */
-	    {
-	      my_bool old_mode;
-	      while (vio_blocking(net->vio, TRUE, &old_mode) < 0)
-	      {
-		if (vio_should_retry(net->vio) &&
-		    retry_count++ < net->retry_count)
-		  continue;
-		DBUG_PRINT("error",
-			   ("fcntl returned error %d, aborting thread",
-			    vio_errno(net->vio)));
-#ifdef EXTRA_DEBUG
-		fprintf(stderr,
-			"%s: read: fcntl returned error %d, aborting thread\n",
-			my_progname,vio_errno(net->vio));
-#endif /* EXTRA_DEBUG */
-		len= packet_error;
-		net->error= 2;                 /* Close socket */
-	        net->last_errno= ER_NET_FCNTL_ERROR;
-#ifdef MYSQL_SERVER
-		my_error(ER_NET_FCNTL_ERROR, MYF(0));
-#endif
-		goto end;
-	      }
-	      retry_count=0;
-	      continue;
-	    }
-	  }
-#endif /* (!defined(__WIN__) || defined(MYSQL_SERVER) */
-	  if (thr_alarm_in_use(&alarmed) && !thr_got_alarm(&alarmed) &&
-	      interrupted)
-	  {					/* Probably in MIT threads */
-	    if (retry_count++ < net->retry_count)
-	      continue;
-#ifdef EXTRA_DEBUG
-	    fprintf(stderr, "%s: read looped with error %d, aborting thread\n",
-		    my_progname,vio_errno(net->vio));
-#endif /* EXTRA_DEBUG */
-	  }
-#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
-	  if (vio_errno(net->vio) == SOCKET_EINTR)
-	  {
-	    DBUG_PRINT("warning",("Interrupted read. Retrying..."));
-	    continue;
-	  }
-#endif
-	  DBUG_PRINT("error",("Couldn't read packet: remain: %u  errno: %d  length: %ld",
-			      remain, vio_errno(net->vio), (long) length));
-	  len= packet_error;
-	  net->error= 2;				/* Close socket */
-          net->last_errno= (vio_was_interrupted(net->vio) ?
-                                   ER_NET_READ_INTERRUPTED :
-                                   ER_NET_READ_ERROR);
-#ifdef MYSQL_SERVER
-          my_error(net->last_errno, MYF(0));
-#endif
-	  goto end;
-	}
-	remain -= (uint32) length;
-	pos+= length;
-	update_statistics(thd_increment_bytes_received(length));
-      }
-      if (i == 0)
-      {					/* First parts is packet length */
-	ulong helping;
-        DBUG_DUMP("packet_header", net->buff+net->where_b,
-                  NET_HEADER_SIZE);
-	if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)
-	{
-	  if (net->buff[net->where_b] != (uchar) 255)
-	  {
-	    DBUG_PRINT("error",
-		       ("Packets out of order (Found: %d, expected %u)",
-			(int) net->buff[net->where_b + 3],
-			net->pkt_nr));
-            /* 
-              We don't make noise server side, since the client is expected
-              to break the protocol for e.g. --send LOAD DATA .. LOCAL where
-              the server expects the client to send a file, but the client
-              may reply with a new command instead.
-            */
-#if defined (EXTRA_DEBUG) && !defined (MYSQL_SERVER)
-            fflush(stdout);
-	    fprintf(stderr,"Error: Packets out of order (Found: %d, expected %d)\n",
-		    (int) net->buff[net->where_b + 3],
-		    (uint) (uchar) net->pkt_nr);
-            fflush(stderr);
-            DBUG_ASSERT(0);
-#endif
-	  }
-	  len= packet_error;
-          /* Not a NET error on the client. XXX: why? */
-#ifdef MYSQL_SERVER
-	  my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0));
-#endif
-	  goto end;
-	}
-	net->compress_pkt_nr= ++net->pkt_nr;
-#ifdef HAVE_COMPRESS
-	if (net->compress)
-	{
-          /*
-            The following uint3korr() may read 4 bytes, so make sure we don't
-            read unallocated or uninitialized memory. The right-hand expression
-            must match the size of the buffer allocated in net_realloc().
-          */
-          DBUG_ASSERT(net->where_b + NET_HEADER_SIZE + sizeof(uint32) <=
-                      net->max_packet + NET_HEADER_SIZE + COMP_HEADER_SIZE + 1);
-	  /*
-	    If the packet is compressed then complen > 0 and contains the
-	    number of bytes in the uncompressed packet
-	  */
-	  *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
-	}
-#endif
+  *complen= 0;
 
-	len=uint3korr(net->buff+net->where_b);
-	if (!len)				/* End of big multi-packet */
-	  goto end;
-	helping = max(len,*complen) + net->where_b;
-	/* The necessary size of net->buff */
-	if (helping >= net->max_packet)
-	{
-	  if (net_realloc(net,helping))
-	  {
-#if defined(MYSQL_SERVER) && !defined(NO_ALARM)
-	    if (!net->compress &&
-                net->skip_big_packet &&
-		!my_net_skip_rest(net, (uint32) len, &alarmed, &alarm_buff))
-	      net->error= 3;		/* Successfully skiped packet */
-#endif
-	    len= packet_error;          /* Return error and close connection */
-	    goto end;
-	  }
-	}
-	pos=net->buff + net->where_b;
-	remain = (uint32) len;
-      }
-    }
+  net->reading_or_writing= 1;
 
-end:
-  if (thr_alarm_in_use(&alarmed))
+  /* Retrieve packet length and number. */
+  if (net_read_packet_header(net))
+    goto error;
+
+#ifdef HAVE_COMPRESS
+  if (net->compress)
   {
-    my_bool old_mode;
-    thr_end_alarm(&alarmed);
-    vio_blocking(net->vio, net_blocking, &old_mode);
+    net->compress_pkt_nr= net->pkt_nr;
+
+    /*
+      The following uint3korr() may read 4 bytes, so make sure we don't
+      read unallocated or uninitialized memory. The right-hand expression
+      must match the size of the buffer allocated in net_realloc().
+    */
+    DBUG_ASSERT(net->where_b + NET_HEADER_SIZE + sizeof(uint32) <=
+                net->max_packet + NET_HEADER_SIZE + COMP_HEADER_SIZE + 1);
+
+    /*
+      If the packet is compressed then complen > 0 and contains the
+      number of bytes in the uncompressed packet.
+    */
+    *complen= uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
   }
-  net->reading_or_writing=0;
-#ifdef DEBUG_DATA_PACKETS
-  if (len != packet_error)
-    DBUG_DUMP("data", net->buff+net->where_b, len);
 #endif
-  return(len);
+
+  /* The length of the packet that follows. */
+  pkt_len= uint3korr(net->buff+net->where_b);
+
+  /* End of big multi-packet. */
+  if (!pkt_len)
+    goto end;
+
+  pkt_data_len = max(pkt_len, *complen) + net->where_b;
+
+  /* Expand packet buffer if necessary. */
+  if ((pkt_data_len >= net->max_packet) && net_realloc(net, pkt_data_len))
+    goto error;
+
+  /* Read the packet data (payload). */
+  if (net_read_raw_loop(net, pkt_len))
+    goto error;
+
+end:
+  net->reading_or_writing= 0;
+  return pkt_len;
+
+error:
+  net->reading_or_writing= 0;
+  return packet_error;
 }
 
 
@@ -1035,7 +852,7 @@ my_net_read(NET *net)
   if (!net->compress)
   {
 #endif
-    len = my_real_read(net,&complen);
+    len= net_read_packet(net, &complen);
     if (len == MAX_PACKET_LENGTH)
     {
       /* First packet of a multi-packet.  Concatenate the packets */
@@ -1045,7 +862,7 @@ my_net_read(NET *net)
       {
 	net->where_b += len;
 	total_length += len;
-	len = my_real_read(net,&complen);
+	len= net_read_packet(net, &complen);
       } while (len == MAX_PACKET_LENGTH);
       if (len != packet_error)
 	len+= total_length;
@@ -1137,7 +954,7 @@ my_net_read(NET *net)
       }
 
       net->where_b=buf_length;
-      if ((packet_len = my_real_read(net,&complen)) == packet_error)
+      if ((packet_len= net_read_packet(net, &complen)) == packet_error)
       {
         MYSQL_NET_READ_DONE(1, 0);
 	return packet_error;
@@ -1175,10 +992,8 @@ void my_net_set_read_timeout(NET *net, u
   DBUG_ENTER("my_net_set_read_timeout");
   DBUG_PRINT("enter", ("timeout: %d", timeout));
   net->read_timeout= timeout;
-#ifdef NO_ALARM
   if (net->vio)
     vio_timeout(net->vio, 0, timeout);
-#endif
   DBUG_VOID_RETURN;
 }
 
@@ -1188,9 +1003,7 @@ void my_net_set_write_timeout(NET *net,
   DBUG_ENTER("my_net_set_write_timeout");
   DBUG_PRINT("enter", ("timeout: %d", timeout));
   net->write_timeout= timeout;
-#ifdef NO_ALARM
   if (net->vio)
     vio_timeout(net->vio, 1, timeout);
-#endif
   DBUG_VOID_RETURN;
 }

=== modified file 'sql/sql_cache.cc'
--- a/sql/sql_cache.cc	2010-10-12 10:07:13 +0000
+++ b/sql/sql_cache.cc	2010-11-14 12:19:57 +0000
@@ -275,14 +275,14 @@ functions:
        - Called before parsing and used to match a statement with the stored
          queries hash.
          If a match is found the cached result set is sent through repeated
-         calls to net_real_write. (note: calling thread doesn't have a regis-
+         calls to net_write_packet. (note: calling thread doesn't have a regis-
          tered result set writer: thd->net.query_cache_query=0)
  2. Query_cache::store_query
        - Called just before handle_select() and is used to register a result
          set writer to the statement currently being processed
          (thd->net.query_cache_query).
  3. query_cache_insert
-       - Called from net_real_write to append a result set to a cached query
+       - Called from net_write_packet to append a result set to a cached query
          if (and only if) this query has a registered result set writer
          (thd->net.query_cache_query).
  4. Query_cache::invalidate
@@ -1407,12 +1407,12 @@ send_data_in_chunks(NET *net, const ucha
 
   while (len > MAX_CHUNK_LENGTH)
   {
-    if (net_real_write(net, packet, MAX_CHUNK_LENGTH))
+    if (net_write_packet(net, packet, MAX_CHUNK_LENGTH))
       return TRUE;
     packet+= MAX_CHUNK_LENGTH;
     len-= MAX_CHUNK_LENGTH;
   }
-  if (len && net_real_write(net, packet, len))
+  if (len && net_write_packet(net, packet, len))
     return TRUE;
 
   return FALSE;

=== modified file 'vio/CMakeLists.txt'
--- a/vio/CMakeLists.txt	2010-08-12 15:19:57 +0000
+++ b/vio/CMakeLists.txt	2010-11-14 12:19:57 +0000
@@ -17,6 +17,6 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/
 ${SSL_INCLUDE_DIRS})
 ADD_DEFINITIONS(${SSL_DEFINES})
 
-SET(VIO_SOURCES  vio.c viosocket.c viossl.c viosslfactories.c)
+SET(VIO_SOURCES vio.c viosocket.c viossl.c viopipe.c vioshm.c viosslfactories.c)
 ADD_CONVENIENCE_LIBRARY(vio ${VIO_SOURCES})
 TARGET_LINK_LIBRARIES(vio ${LIBSOCKET})

=== modified file 'vio/Makefile.am'
--- a/vio/Makefile.am	2010-05-19 13:00:23 +0000
+++ b/vio/Makefile.am	2010-11-14 12:19:57 +0000
@@ -20,6 +20,7 @@ pkglib_LIBRARIES =	libvio.a
 
 noinst_HEADERS =	vio_priv.h
 
-libvio_a_SOURCES =	vio.c viosocket.c viossl.c viosslfactories.c
+libvio_a_SOURCES =	vio.c viosocket.c viossl.c viosslfactories.c \
+			viopipe.c vioshm.c
 
 EXTRA_DIST=		CMakeLists.txt

=== modified file 'vio/vio.c'
--- a/vio/vio.c	2010-08-16 12:50:27 +0000
+++ b/vio/vio.c	2010-11-14 12:19:57 +0000
@@ -22,39 +22,42 @@
 
 #include "vio_priv.h"
 
-#if defined(__WIN__) || defined(HAVE_SMEM)
+static my_bool has_no_data(Vio *vio __attribute__((unused)))
+{
+  return FALSE;
+}
+
+#ifdef _WIN32
 
 /**
-  Stub poll_read method that defaults to indicate that there
-  is data to read.
+  Stub io_wait method that defaults to indicate that
+  requested I/O event is ready.
 
   Used for named pipe and shared memory VIO types.
 
   @param vio      Unused.
+  @param event    Unused.
   @param timeout  Unused.
 
-  @retval FALSE   There is data to read.
+  @retval 1       The requested I/O event has occurred.
 */
 
-static my_bool no_poll_read(Vio *vio __attribute__((unused)),
-                            uint timeout __attribute__((unused)))
+static int no_io_wait(Vio *vio __attribute__((unused)),
+                      enum enum_vio_io_event event __attribute__((unused)),
+                      int timeout __attribute__((unused)))
 {
-  return FALSE;
+  return 1;
 }
 
 #endif
 
-static my_bool has_no_data(Vio *vio __attribute__((unused)))
-{
-  return FALSE;
-}
 
 /*
  * Helper to fill most of the Vio* with defaults.
  */
 
-static void vio_init(Vio* vio, enum enum_vio_type type,
-                     my_socket sd, HANDLE hPipe, uint flags)
+static void vio_init(Vio *vio, enum enum_vio_type type,
+                     my_socket sd, uint flags)
 {
   DBUG_ENTER("vio_init");
   DBUG_PRINT("enter", ("type: %d  sd: %d  flags: %d", type, sd, flags));
@@ -62,11 +65,11 @@ static void vio_init(Vio* vio, enum enum
 #ifndef HAVE_VIO_READ_BUFF
   flags&= ~VIO_BUFFERED_READ;
 #endif
-  bzero((char*) vio, sizeof(*vio));
+  memset(vio, 0, sizeof(*vio));
   vio->type	= type;
   vio->sd	= sd;
-  vio->hPipe	= hPipe;
   vio->localhost= flags & VIO_LOCALHOST;
+  vio->read_timeout= vio->write_timeout= -1;
   if ((flags & VIO_BUFFERED_READ) &&
       !(vio->read_buffer= (char*)my_malloc(VIO_READ_BUFFER_SIZE, MYF(MY_WME))))
     flags&= ~VIO_BUFFERED_READ;
@@ -80,25 +83,16 @@ static void vio_init(Vio* vio, enum enum
     vio->fastsend	=vio_fastsend;
     vio->viokeepalive	=vio_keepalive;
     vio->should_retry	=vio_should_retry;
-    vio->was_interrupted=vio_was_interrupted;
+    vio->was_timeout    =vio_was_timeout;
     vio->vioclose	=vio_close_pipe;
     vio->peer_addr	=vio_peer_addr;
-    vio->vioblocking	=vio_blocking;
-    vio->is_blocking	=vio_is_blocking;
-
-    vio->poll_read      =no_poll_read;
+    vio->io_wait        =no_io_wait;
     vio->is_connected   =vio_is_connected_pipe;
     vio->has_data       =has_no_data;
-
-    vio->timeout=vio_win32_timeout;
-    /* Set default timeout */
-    vio->read_timeout_ms= INFINITE;
-    vio->write_timeout_ms= INFINITE;
-    vio->pipe_overlapped.hEvent= CreateEvent(NULL, TRUE, FALSE, NULL);
     DBUG_VOID_RETURN;
   }
 #endif
-#ifdef HAVE_SMEM 
+#ifdef HAVE_SMEM
   if (type == VIO_TYPE_SHARED_MEMORY)
   {
     vio->viodelete	=vio_delete;
@@ -108,25 +102,16 @@ static void vio_init(Vio* vio, enum enum
     vio->fastsend	=vio_fastsend;
     vio->viokeepalive	=vio_keepalive;
     vio->should_retry	=vio_should_retry;
-    vio->was_interrupted=vio_was_interrupted;
+    vio->was_timeout    =vio_was_timeout;
     vio->vioclose	=vio_close_shared_memory;
     vio->peer_addr	=vio_peer_addr;
-    vio->vioblocking	=vio_blocking;
-    vio->is_blocking	=vio_is_blocking;
-
-    vio->poll_read      =no_poll_read;
+    vio->io_wait        =no_io_wait;
     vio->is_connected   =vio_is_connected_shared_memory;
     vio->has_data       =has_no_data;
-
-    /* Currently, shared memory is on Windows only, hence the below is ok*/
-    vio->timeout= vio_win32_timeout; 
-    /* Set default timeout */
-    vio->read_timeout_ms= INFINITE;
-    vio->write_timeout_ms= INFINITE;
     DBUG_VOID_RETURN;
   }
-#endif   
-#ifdef HAVE_OPENSSL 
+#endif
+#ifdef HAVE_OPENSSL
   if (type == VIO_TYPE_SSL)
   {
     vio->viodelete	=vio_ssl_delete;
@@ -136,15 +121,14 @@ static void vio_init(Vio* vio, enum enum
     vio->fastsend	=vio_fastsend;
     vio->viokeepalive	=vio_keepalive;
     vio->should_retry	=vio_should_retry;
-    vio->was_interrupted=vio_was_interrupted;
+    vio->was_timeout    =vio_was_timeout;
     vio->vioclose	=vio_ssl_close;
     vio->peer_addr	=vio_peer_addr;
-    vio->vioblocking	=vio_ssl_blocking;
-    vio->is_blocking	=vio_is_blocking;
-    vio->timeout	=vio_timeout;
-    vio->poll_read      =vio_poll_read;
+    vio->io_wait        =vio_io_wait;
     vio->is_connected   =vio_is_connected;
     vio->has_data       =vio_ssl_has_data;
+    vio->timeout        =vio_socket_timeout;
+    vio->ssl_error      =SSL_ERROR_NONE;
     DBUG_VOID_RETURN;
   }
 #endif /* HAVE_OPENSSL */
@@ -155,32 +139,65 @@ static void vio_init(Vio* vio, enum enum
   vio->fastsend         =vio_fastsend;
   vio->viokeepalive     =vio_keepalive;
   vio->should_retry     =vio_should_retry;
-  vio->was_interrupted  =vio_was_interrupted;
+  vio->was_timeout      =vio_was_timeout;
   vio->vioclose         =vio_close;
   vio->peer_addr        =vio_peer_addr;
-  vio->vioblocking      =vio_blocking;
-  vio->is_blocking      =vio_is_blocking;
-  vio->timeout          =vio_timeout;
-  vio->poll_read        =vio_poll_read;
+  vio->io_wait          =vio_io_wait;
   vio->is_connected     =vio_is_connected;
+  vio->timeout          =vio_socket_timeout;
   vio->has_data=        (flags & VIO_BUFFERED_READ) ?
                             vio_buff_has_data : has_no_data;
   DBUG_VOID_RETURN;
 }
 
 
-/* Reset initialized VIO to use with another transport type */
+#ifdef HAVE_OPENSSL
 
-void vio_reset(Vio* vio, enum enum_vio_type type,
-               my_socket sd, HANDLE hPipe, uint flags)
+/* Rebind an initialized VIO to the SSL transport type. */
+my_bool vio_rebind_ssl(Vio *vio, SSL *ssl)
 {
+  Vio old_vio= *vio;
+  my_bool ret= FALSE;
+  DBUG_ENTER("vio_new");
+
+  /* The only supported SSL rebind is from a connection-based socket. */
+  DBUG_ASSERT(vio->type == VIO_TYPE_TCPIP || vio->type == VIO_TYPE_SOCKET);
+
+  /* Already buffered inside the SSL layer. */
   my_free(vio->read_buffer);
-  vio_init(vio, type, sd, hPipe, flags);
+
+  vio_init(vio, VIO_TYPE_SSL, SSL_get_fd(ssl), 0);
+
+#ifdef _WIN32
+  vio->overlapped.hEvent= old_vio.overlapped.hEvent;
+#endif
+  vio->localhost= old_vio.localhost;
+  vio->ssl_arg= ssl;
+
+  ret|= test(vio_timeout(vio, 0, old_vio.read_timeout));
+  ret|= test(vio_timeout(vio, 1, old_vio.write_timeout));
+
+  DBUG_RETURN(ret);
 }
 
+#endif
 
-/* Open the socket or TCP/IP connection and read the fnctl() status */
 
+/* Create an object for event notification. */
+static my_bool vio_event_init(Vio *vio __attribute__((unused)))
+{
+#ifdef _WIN32
+  HANDLE hEvent= CreateEvent(NULL, FALSE, FALSE, NULL);
+  if (hEvent == NULL)
+    return TRUE;
+  vio->overlapped.hEvent= hEvent;
+#endif
+
+  return FALSE;
+}
+
+
+/* Create a new VIO for socket or TCP/IP connection. */
 Vio *vio_new(my_socket sd, enum enum_vio_type type, uint flags)
 {
   Vio *vio;
@@ -188,43 +205,21 @@ Vio *vio_new(my_socket sd, enum enum_vio
   DBUG_PRINT("enter", ("sd: %d", sd));
   if ((vio = (Vio*) my_malloc(sizeof(*vio),MYF(MY_WME))))
   {
-    vio_init(vio, type, sd, 0, flags);
+    vio_init(vio, type, sd, flags);
+    if (vio_event_init(vio))
+    {
+      my_free(vio);
+      DBUG_RETURN(NULL);
+    }
     sprintf(vio->desc,
 	    (vio->type == VIO_TYPE_SOCKET ? "socket (%d)" : "TCP/IP (%d)"),
 	    vio->sd);
-#if !defined(__WIN__)
-#if !defined(NO_FCNTL_NONBLOCK)
-    /*
-      We call fcntl() to set the flags and then immediately read them back
-      to make sure that we and the system are in agreement on the state of
-      things.
-
-      An example of why we need to do this is FreeBSD (and apparently some
-      other BSD-derived systems, like Mac OS X), where the system sometimes
-      reports that the socket is set for non-blocking when it really will
-      block.
-    */
-    fcntl(sd, F_SETFL, 0);
-    vio->fcntl_mode= fcntl(sd, F_GETFL);
-#elif defined(HAVE_SYS_IOCTL_H)			/* hpux */
-    /* Non blocking sockets doesn't work good on HPUX 11.0 */
-    (void) ioctl(sd,FIOSNBIO,0);
-    vio->fcntl_mode &= ~O_NONBLOCK;
-#endif
-#else /* !defined(__WIN__) */
-    {
-      /* set to blocking mode by default */
-      ulong arg=0, r;
-      r = ioctlsocket(sd,FIONBIO,(void*) &arg);
-      vio->fcntl_mode &= ~O_NONBLOCK;
-    }
-#endif
   }
   DBUG_RETURN(vio);
 }
 
 
-#ifdef __WIN__
+#ifdef _WIN32
 
 Vio *vio_new_win32pipe(HANDLE hPipe)
 {
@@ -232,7 +227,13 @@ Vio *vio_new_win32pipe(HANDLE hPipe)
   DBUG_ENTER("vio_new_handle");
   if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME))))
   {
-    vio_init(vio, VIO_TYPE_NAMEDPIPE, 0, hPipe, VIO_LOCALHOST);
+    vio_init(vio, VIO_TYPE_NAMEDPIPE, 0, VIO_LOCALHOST);
+    if (vio_event_init(vio))
+    {
+      my_free(vio);
+      DBUG_RETURN(NULL);
+    }
+    vio->hPipe= hPipe;
     strmov(vio->desc, "named pipe");
   }
   DBUG_RETURN(vio);
@@ -248,7 +249,7 @@ Vio *vio_new_win32shared_memory(HANDLE h
   DBUG_ENTER("vio_new_win32shared_memory");
   if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME))))
   {
-    vio_init(vio, VIO_TYPE_SHARED_MEMORY, 0, 0, VIO_LOCALHOST);
+    vio_init(vio, VIO_TYPE_SHARED_MEMORY, 0, VIO_LOCALHOST);
     vio->handle_file_map= handle_file_map;
     vio->handle_map= handle_map;
     vio->event_server_wrote= event_server_wrote;
@@ -266,6 +267,49 @@ Vio *vio_new_win32shared_memory(HANDLE h
 #endif
 
 
+/**
+  Set timeout for a network send or receive operation.
+
+  @remark A non-infinite timeout causes the socket to be
+          set to non-blocking mode. On infinite timeouts,
+          the socket is set to blocking mode.
+
+  @remark A negative timeout means an infinite timeout.
+
+  @param vio      A VIO object.
+  @param which    Whether timeout is for send (1) or receive (0).
+  @param timeout  Timeout interval in seconds.
+
+  @return
+*/
+
+int vio_timeout(Vio *vio, uint which, int timeout_sec)
+{
+  int timeout_ms;
+  my_bool old_mode;
+
+  /*
+    Vio timeouts are measured in milliseconds. Check for a possible
+    overflow. In case of overflow, set to infinite.
+  */
+  if (timeout_sec > INT_MAX/1000)
+    timeout_ms= -1;
+  else
+    timeout_ms= (int) (timeout_sec * 1000);
+
+  /* Deduce the current timeout status mode. */
+  old_mode= vio->write_timeout < 0 && vio->read_timeout < 0;
+
+  if (which)
+    vio->write_timeout= timeout_ms;
+  else
+    vio->read_timeout= timeout_ms;
+
+  /* VIO-specific timeout handling. */
+  return vio->timeout ? vio->timeout(vio, which, old_mode) : 0;
+}
+
+
 void vio_delete(Vio* vio)
 {
   if (!vio)

=== modified file 'vio/vio_priv.h'
--- a/vio/vio_priv.h	2010-06-07 14:01:39 +0000
+++ b/vio/vio_priv.h	2010-11-14 12:19:57 +0000
@@ -30,10 +30,6 @@
 #include <netdb.h>
 #endif
 
-#ifdef _WIN32
-void	vio_win32_timeout(Vio *vio, uint which, uint timeout);
-#endif
-
 #ifdef __WIN__
 size_t vio_read_pipe(Vio *vio, uchar * buf, size_t size);
 size_t vio_write_pipe(Vio *vio, const uchar * buf, size_t size);
@@ -48,7 +44,6 @@ my_bool vio_is_connected_shared_memory(V
 int vio_close_shared_memory(Vio * vio);
 #endif
 
-void	vio_timeout(Vio *vio,uint which, uint timeout);
 my_bool vio_buff_has_data(Vio *vio);
 
 #ifdef HAVE_OPENSSL
@@ -61,9 +56,11 @@ size_t	vio_ssl_write(Vio *vio,const ucha
 int vio_ssl_close(Vio *vio);
 void vio_ssl_delete(Vio *vio);
 
-int vio_ssl_blocking(Vio *vio, my_bool set_blocking_mode, my_bool *old_mode);
+int vio_socket_io_wait(Vio *vio, enum enum_vio_io_event event);
+int vio_socket_timeout(Vio *vio, uint which, my_bool old_mode);
 
 my_bool vio_ssl_has_data(Vio *vio);
+int vio_ssl_errno(Vio *vio);
 
 #endif /* HAVE_OPENSSL */
 #endif /* VIO_PRIV_INCLUDED */

=== added file 'vio/viopipe.c'
--- a/vio/viopipe.c	1970-01-01 00:00:00 +0000
+++ b/vio/viopipe.c	2010-11-14 12:19:57 +0000
@@ -0,0 +1,117 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
+
+#include "vio_priv.h"
+
+#ifdef _WIN32
+
+static size_t wait_overlapped_result(Vio *vio, int timeout)
+{
+  size_t ret= (size_t) -1;
+  DWORD transferred, wait_status, timeout_ms;
+
+  timeout_ms= timeout >= 0 ? timeout : INFINITE;
+
+  /* Wait for the overlapped operation to be completed. */
+  wait_status= WaitForSingleObject(vio->overlapped.hEvent, timeout_ms);
+
+  /* The operation might have completed, attempt to retrieve the result. */
+  if (wait_status == WAIT_OBJECT_0)
+  {
+    if (GetOverlappedResult(vio->hPipe, &vio->overlapped, &transferred, FALSE))
+      ret= transferred;
+  }
+  else
+  {
+    /* Error or timeout, cancel the pending I/O operation. */
+    CancelIo(vio->hPipe);
+
+    /* Set error code to indicate a timeout error. */
+    if (wait_status == WAIT_TIMEOUT)
+      WSASetLastError(SOCKET_ETIMEDOUT);
+  }
+
+  return ret;
+}
+
+
+size_t vio_read_pipe(Vio *vio, uchar *buf, size_t count)
+{
+  DWORD transferred;
+  size_t ret= (size_t) -1;
+  DBUG_ENTER("vio_read_pipe");
+
+  /* Attempt to read from the pipe (overlapped I/O). */
+  if (ReadFile(vio->hPipe, buf, count, &transferred, &vio->overlapped))
+  {
+    /* The operation completed immediately. */
+    ret= transferred;
+  }
+  /* Read operation is pending completion asynchronously? */
+  else if (GetLastError() == ERROR_IO_PENDING)
+    ret= wait_overlapped_result(vio, vio->read_timeout);
+
+  DBUG_RETURN(ret);
+}
+
+
+size_t vio_write_pipe(Vio *vio, const uchar *buf, size_t count)
+{
+  DWORD transferred;
+  size_t ret= (size_t) -1;
+  DBUG_ENTER("vio_write_pipe");
+
+  /* Attempt to write to the pipe (overlapped I/O). */
+  if (WriteFile(vio->hPipe, buf, count, &transferred, &vio->overlapped))
+  {
+    /* The operation completed immediately. */
+    ret= transferred;
+  }
+  /* Write operation is pending completion asynchronously? */
+  else if (GetLastError() == ERROR_IO_PENDING)
+    ret= wait_overlapped_result(vio, vio->write_timeout);
+
+  DBUG_RETURN(ret);
+}
+
+
+my_bool vio_is_connected_pipe(Vio *vio)
+{
+  if (PeekNamedPipe(vio->hPipe, NULL, 0, NULL, NULL, NULL))
+    return TRUE;
+  else
+    return (GetLastError() != ERROR_BROKEN_PIPE);
+}
+
+
+int vio_close_pipe(Vio *vio)
+{
+  BOOL ret;
+  DBUG_ENTER("vio_close_pipe");
+
+  CancelIo(vio->hPipe);
+  CloseHandle(vio->overlapped.hEvent);
+  DisconnectNamedPipe(vio->hPipe);
+  ret= CloseHandle(vio->hPipe);
+
+  vio->type= VIO_CLOSED;
+  vio->hPipe= NULL;
+  vio->sd= -1;
+
+  DBUG_RETURN(ret);
+}
+
+#endif
+

=== added file 'vio/vioshm.c'
--- a/vio/vioshm.c	1970-01-01 00:00:00 +0000
+++ b/vio/vioshm.c	2010-11-14 12:19:57 +0000
@@ -0,0 +1,200 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
+
+#include "vio_priv.h"
+
+#if defined(_WIN32) && defined(HAVE_SMEM)
+
+size_t vio_read_shared_memory(Vio * vio, uchar* buf, size_t size)
+{
+  size_t length;
+  size_t remain_local;
+  char *current_postion;
+  HANDLE events[2];
+  DWORD timeout;
+
+  DBUG_ENTER("vio_read_shared_memory");
+  DBUG_PRINT("enter", ("sd: %d  buf: 0x%lx  size: %d", vio->sd, (long) buf,
+                       size));
+
+  remain_local = size;
+  current_postion=buf;
+  timeout = vio->read_timeout >= 0 ? vio->read_timeout : INFINITE;
+
+  events[0]= vio->event_server_wrote;
+  events[1]= vio->event_conn_closed;
+
+  do
+  {
+    if (vio->shared_memory_remain == 0)
+    {
+      /*
+        WaitForMultipleObjects can return next values:
+         WAIT_OBJECT_0+0 - event from vio->event_server_wrote
+         WAIT_OBJECT_0+1 - event from vio->event_conn_closed. We can't read
+		           anything
+         WAIT_ABANDONED_0 and WAIT_TIMEOUT - fail.  We can't read anything
+      */
+      if (WaitForMultipleObjects(array_elements(events), events, FALSE,
+                                 timeout) != WAIT_OBJECT_0)
+      {
+        DBUG_RETURN(-1);
+      };
+
+      vio->shared_memory_pos = vio->handle_map;
+      vio->shared_memory_remain = uint4korr((ulong*)vio->shared_memory_pos);
+      vio->shared_memory_pos+=4;
+    }
+
+    length = size;
+
+    if (vio->shared_memory_remain < length)
+       length = vio->shared_memory_remain;
+    if (length > remain_local)
+       length = remain_local;
+
+    memcpy(current_postion,vio->shared_memory_pos,length);
+
+    vio->shared_memory_remain-=length;
+    vio->shared_memory_pos+=length;
+    current_postion+=length;
+    remain_local-=length;
+
+    if (!vio->shared_memory_remain)
+    {
+      if (!SetEvent(vio->event_client_read))
+        DBUG_RETURN(-1);
+    }
+  } while (remain_local);
+  length = size;
+
+  DBUG_PRINT("exit", ("%lu", (ulong) length));
+  DBUG_RETURN(length);
+}
+
+
+size_t vio_write_shared_memory(Vio * vio, const uchar* buf, size_t size)
+{
+  size_t length, remain, sz;
+  HANDLE pos;
+  const uchar *current_postion;
+  HANDLE events[2];
+  DWORD timeout;
+
+  DBUG_ENTER("vio_write_shared_memory");
+  DBUG_PRINT("enter", ("sd: %d  buf: 0x%lx  size: %d", vio->sd, (long) buf,
+                       size));
+
+  remain = size;
+  current_postion = buf;
+  timeout = vio->write_timeout >= 0 ? vio->write_timeout : INFINITE;
+
+  events[0]= vio->event_server_read;
+  events[1]= vio->event_conn_closed;
+
+  while (remain != 0)
+  {
+    if (WaitForMultipleObjects(array_elements(events), events, FALSE,
+                               timeout) != WAIT_OBJECT_0)
+    {
+      DBUG_RETURN((size_t) -1);
+    }
+
+    sz= (remain > shared_memory_buffer_length ? shared_memory_buffer_length :
+         remain);
+
+    int4store(vio->handle_map,sz);
+    pos = vio->handle_map + 4;
+    memcpy(pos,current_postion,sz);
+    remain-=sz;
+    current_postion+=sz;
+    if (!SetEvent(vio->event_client_wrote))
+      DBUG_RETURN((size_t) -1);
+  }
+  length = size;
+
+  DBUG_PRINT("exit", ("%lu", (ulong) length));
+  DBUG_RETURN(length);
+}
+
+
+my_bool vio_is_connected_shared_memory(Vio *vio)
+{
+  return (WaitForSingleObject(vio->event_conn_closed, 0) != WAIT_OBJECT_0);
+}
+
+
+/**
+ Close shared memory and DBUG_PRINT any errors that happen on closing.
+ @return Zero if all closing functions succeed, and nonzero otherwise.
+*/
+int vio_close_shared_memory(Vio * vio)
+{
+  int error_count= 0;
+  DBUG_ENTER("vio_close_shared_memory");
+  if (vio->type != VIO_CLOSED)
+  {
+    /*
+      Set event_conn_closed for notification of both client and server that
+      connection is closed
+    */
+    SetEvent(vio->event_conn_closed);
+    /*
+      Close all handlers. UnmapViewOfFile and CloseHandle return non-zero
+      result if they are success.
+    */
+    if (UnmapViewOfFile(vio->handle_map) == 0)
+    {
+      error_count++;
+      DBUG_PRINT("vio_error", ("UnmapViewOfFile() failed"));
+    }
+    if (CloseHandle(vio->event_server_wrote) == 0)
+    {
+      error_count++;
+      DBUG_PRINT("vio_error", ("CloseHandle(vio->esw) failed"));
+    }
+    if (CloseHandle(vio->event_server_read) == 0)
+    {
+      error_count++;
+      DBUG_PRINT("vio_error", ("CloseHandle(vio->esr) failed"));
+    }
+    if (CloseHandle(vio->event_client_wrote) == 0)
+    {
+      error_count++;
+      DBUG_PRINT("vio_error", ("CloseHandle(vio->ecw) failed"));
+    }
+    if (CloseHandle(vio->event_client_read) == 0)
+    {
+      error_count++;
+      DBUG_PRINT("vio_error", ("CloseHandle(vio->ecr) failed"));
+    }
+    if (CloseHandle(vio->handle_file_map) == 0)
+    {
+      error_count++;
+      DBUG_PRINT("vio_error", ("CloseHandle(vio->hfm) failed"));
+    }
+    if (CloseHandle(vio->event_conn_closed) == 0)
+    {
+      error_count++;
+      DBUG_PRINT("vio_error", ("CloseHandle(vio->ecc) failed"));
+    }
+  }
+  vio->type= VIO_CLOSED;
+  vio->sd=   -1;
+  DBUG_RETURN(error_count);
+}
+
+#endif /* #if defined(_WIN32) && defined(HAVE_SMEM) */
+

=== modified file 'vio/viosocket.c'
--- a/vio/viosocket.c	2010-08-16 12:50:27 +0000
+++ b/vio/viosocket.c	2010-11-14 12:19:57 +0000
@@ -24,33 +24,100 @@
 
 int vio_errno(Vio *vio __attribute__((unused)))
 {
-  return socket_errno;		/* On Win32 this mapped to WSAGetLastError() */
+#ifdef HAVE_OPENSSL
+  if (vio->type == VIO_TYPE_SSL)
+    return vio_ssl_errno(vio);
+#endif
+
+  /* Mapped to WSAGetLastError() on Win32. */
+  return socket_errno;
 }
 
 
-size_t vio_read(Vio * vio, uchar* buf, size_t size)
+/**
+  Attempt to wait for an I/O event on a socket.
+
+  @param vio      VIO object representing a connected socket.
+  @param event    The type of I/O event to wait for.
+
+  @remark Relies on the value of errno to determine whether to wait.
+
+  @see vio_read() and vio_write().
+
+  @return Return value is -1 on failure, 0 on success.
+*/
+
+int vio_socket_io_wait(Vio *vio, enum enum_vio_io_event event)
 {
-  size_t r;
+  int timeout, ret;
+
+  /* Choose an appropriate timeout. */
+  if (event == VIO_IO_EVENT_READ)
+    timeout= vio->read_timeout;
+  else
+    timeout= vio->write_timeout;
+
+  /* Wait for input data to become available. */
+  switch (vio_io_wait(vio, event, timeout))
+  {
+  case -1:
+    /* Upon failure, vio_read/write() shall return -1. */
+    ret= -1;
+    break;
+  case  0:
+    /* The wait timed out. */
+    ret= -1;
+    break;
+  default:
+    /* A positive value indicates an I/O event. */
+    ret= 0;
+    break;
+  }
+
+  return ret;
+}
+
+
+/*
+  Define a stub MSG_DONTWAIT if unavailable. In this case, fcntl
+  (or a equivalent) is used to enable non-blocking operations.
+  The flag must be supported in both send and recv operations.
+*/
+#if defined(__linux__)
+#define VIO_USE_DONTWAIT  1
+#define VIO_DONTWAIT      MSG_DONTWAIT
+#else
+#define VIO_DONTWAIT 0
+#endif
+
+
+size_t vio_read(Vio *vio, uchar *buf, size_t size)
+{
+  ssize_t ret;
+  int flags= 0;
   DBUG_ENTER("vio_read");
-  DBUG_PRINT("enter", ("sd: %d  buf: 0x%lx  size: %u", vio->sd, (long) buf,
-                       (uint) size));
 
-  /* Ensure nobody uses vio_read_buff and vio_read simultaneously */
+  /* Ensure nobody uses vio_read_buff and vio_read simultaneously. */
   DBUG_ASSERT(vio->read_end == vio->read_pos);
-#ifdef __WIN__
-  r = recv(vio->sd, buf, size,0);
-#else
-  errno=0;					/* For linux */
-  r = read(vio->sd, buf, size);
-#endif /* __WIN__ */
-#ifndef DBUG_OFF
-  if (r == (size_t) -1)
+
+  /* If timeout is enabled, do not block if data is unavailable. */
+  if (vio->read_timeout >= 0)
+    flags= VIO_DONTWAIT;
+
+  while ((ret= recv(vio->sd, buf, size, flags)) == -1)
   {
-    DBUG_PRINT("vio_error", ("Got error %d during read",errno));
+    int error= socket_errno;
+
+    /* The operation would block? */
+    if (error != SOCKET_EAGAIN && error != SOCKET_EWOULDBLOCK)
+      break;
+
+    /* Wait for input data to become available. */
+    if ((ret= vio_socket_io_wait(vio, VIO_IO_EVENT_READ)))
+      break;
   }
-#endif /* DBUG_OFF */
-  DBUG_PRINT("exit", ("%ld", (long) r));
-  DBUG_RETURN(r);
+
+  DBUG_RETURN(ret);
 }
 
 
@@ -98,97 +165,132 @@ size_t vio_read_buff(Vio *vio, uchar* bu
 #undef VIO_UNBUFFERED_READ_MIN_SIZE
 }
 
+
 my_bool vio_buff_has_data(Vio *vio)
 {
   return (vio->read_pos != vio->read_end);
 }
 
-size_t vio_write(Vio * vio, const uchar* buf, size_t size)
+
+size_t vio_write(Vio *vio, const uchar* buf, size_t size)
 {
-  size_t r;
+  ssize_t ret;
+  int flags= 0;
   DBUG_ENTER("vio_write");
-  DBUG_PRINT("enter", ("sd: %d  buf: 0x%lx  size: %u", vio->sd, (long) buf,
-                       (uint) size));
-#ifdef __WIN__
-  r = send(vio->sd, buf, size,0);
-#else
-  r = write(vio->sd, buf, size);
-#endif /* __WIN__ */
-#ifndef DBUG_OFF
-  if (r == (size_t) -1)
+
+  /* If timeout is enabled, do not block. */
+  if (vio->write_timeout >= 0)
+    flags= VIO_DONTWAIT;
+
+  while ((ret= send(vio->sd, buf, size, flags)) == -1)
   {
-    DBUG_PRINT("vio_error", ("Got error on write: %d",socket_errno));
+    int error= socket_errno;
+
+    /* The operation would block? */
+    if (error != SOCKET_EAGAIN && error != SOCKET_EWOULDBLOCK)
+      break;
+
+    /* Wait for the output buffer to become writable.*/
+    if ((ret= vio_socket_io_wait(vio, VIO_IO_EVENT_WRITE)))
+      break;
   }
-#endif /* DBUG_OFF */
-  DBUG_PRINT("exit", ("%u", (uint) r));
-  DBUG_RETURN(r);
+
+  DBUG_RETURN(ret);
 }
 
-int vio_blocking(Vio * vio __attribute__((unused)), my_bool set_blocking_mode,
-		 my_bool *old_mode)
+
+int vio_set_blocking(Vio *vio, my_bool status)
 {
-  int r=0;
-  DBUG_ENTER("vio_blocking");
+  DBUG_ENTER("vio_set_nonblocking");
 
-  *old_mode= test(!(vio->fcntl_mode & O_NONBLOCK));
-  DBUG_PRINT("enter", ("set_blocking_mode: %d  old_mode: %d",
-		       (int) set_blocking_mode, (int) *old_mode));
-
-#if !defined(__WIN__)
-#if !defined(NO_FCNTL_NONBLOCK)
-  if (vio->sd >= 0)
-  {
-    int old_fcntl=vio->fcntl_mode;
-    if (set_blocking_mode)
-      vio->fcntl_mode &= ~O_NONBLOCK; /* clear bit */
-    else
-      vio->fcntl_mode |= O_NONBLOCK; /* set bit */
-    if (old_fcntl != vio->fcntl_mode)
-    {
-      r= fcntl(vio->sd, F_SETFL, vio->fcntl_mode);
-      if (r == -1)
-      {
-        DBUG_PRINT("info", ("fcntl failed, errno %d", errno));
-        vio->fcntl_mode= old_fcntl;
-      }
-    }
+#ifdef _WIN32
+  if (vio->type != VIO_TYPE_NAMEDPIPE && vio->type != VIO_TYPE_SHARED_MEMORY)
+  {
+    int ret;
+    u_long arg= status ? 0 : 1;
+    ret= ioctlsocket(vio->sd, FIONBIO, &arg);
+    DBUG_RETURN(ret);
   }
 #else
-  r= set_blocking_mode ? 0 : 1;
-#endif /* !defined(NO_FCNTL_NONBLOCK) */
-#else /* !defined(__WIN__) */
-  if (vio->type != VIO_TYPE_NAMEDPIPE && vio->type != VIO_TYPE_SHARED_MEMORY)
-  { 
-    ulong arg;
-    int old_fcntl=vio->fcntl_mode;
-    if (set_blocking_mode)
-    {
-      arg = 0;
-      vio->fcntl_mode &= ~O_NONBLOCK; /* clear bit */
-    }
+  {
+    long flags;
+
+    if ((flags= fcntl(vio->sd, F_GETFL, NULL)) < 0)
+      DBUG_RETURN(-1);
+
+    if (status)
+      flags&= ~O_NONBLOCK;
     else
-    {
-      arg = 1;
-      vio->fcntl_mode |= O_NONBLOCK; /* set bit */
-    }
-    if (old_fcntl != vio->fcntl_mode)
-      r = ioctlsocket(vio->sd,FIONBIO,(void*) &arg);
+      flags|= O_NONBLOCK;
+
+    if (fcntl(vio->sd, F_SETFL, flags) == -1)
+      DBUG_RETURN(-1);
+  }
+#endif
+
+  DBUG_RETURN(0);
+}
+
+#ifdef _WIN32
+
+/**
+  Sets the timeout, in milliseconds, for blocking calls.
+
+  @param vio    The VIO object.
+  @param which  Send or receive.
+
+  @return Return value is zero on success.
+*/
+
+static int vio_win32_timeout(Vio *vio, uint which)
+{
+  int optname;
+  DWORD timeout;
+  const char *optval= (const char *) &timeout;
+
+  if (which)
+  {
+    optname= SO_SNDTIMEO;
+    timeout= vio->write_timeout >= 0 ? vio->write_timeout : INFINITE;
   }
   else
-    r=  test(!(vio->fcntl_mode & O_NONBLOCK)) != set_blocking_mode;
-#endif /* !defined(__WIN__) */
-  DBUG_PRINT("exit", ("%d", r));
-  DBUG_RETURN(r);
+  {
+    optname= SO_RCVTIMEO;
+    timeout= vio->read_timeout >= 0 ? vio->read_timeout : INFINITE;
+  }
+
+  return setsockopt(vio->sd, SOL_SOCKET, optname, optval, sizeof(timeout));
 }
 
-my_bool
-vio_is_blocking(Vio * vio)
+#endif
+
+int vio_socket_timeout(Vio *vio,
+                       uint which __attribute__((unused)),
+                       my_bool old_mode __attribute__((unused)))
 {
-  my_bool r;
-  DBUG_ENTER("vio_is_blocking");
-  r = !(vio->fcntl_mode & O_NONBLOCK);
-  DBUG_PRINT("exit", ("%d", (int) r));
-  DBUG_RETURN(r);
+  int ret= 0;
+  DBUG_ENTER("vio_socket_timeout");
+
+#if defined(_WIN32)
+  {
+    ret= vio_win32_timeout(vio, which);
+  }
+#else
+  /* Even if MSG_DONTWAIT is available, can't use it with SSL (API). */
+#ifdef VIO_USE_DONTWAIT
+  if (vio->type == VIO_TYPE_SSL)
+#endif
+  {
+    /* Deduce what should be the new blocking mode of the socket. */
+    my_bool new_mode= vio->write_timeout < 0 && vio->read_timeout < 0;
+
+    /* If necessary, update the blocking mode. */
+    if (new_mode != old_mode)
+      ret= vio_set_blocking(vio, new_mode);
+  }
+#endif
+
+  DBUG_RETURN(ret);
 }
 
 
@@ -243,33 +345,41 @@ int vio_keepalive(Vio* vio, my_bool set_
 }
 
 
+/**
+  Indicate whether a I/O operation must be retried later.
+
+  @param vio  A VIO object
+
+  @return Whether a I/O operation should be deferred.
+  @retval TRUE    Temporary failure, retry operation.
+  @retval FALSE   Indeterminate failure.
+*/
+
 my_bool
-vio_should_retry(Vio * vio)
+vio_should_retry(Vio *vio)
 {
-  int en = socket_errno;
-  /*
-    man 2 read write
-      EAGAIN or EWOULDBLOCK when a socket is a non-blocking mode means
-      that the read/write would block.
-    man 7 socket
-      EAGAIN or EWOULDBLOCK when a socket is in a blocking mode means
-      that the corresponding receiving or sending timeout was reached.
-  */
-  return  en == SOCKET_EINTR ||
-          (!vio_is_blocking(vio) &&
-            (en == SOCKET_EAGAIN || en == SOCKET_EWOULDBLOCK));
+  return (vio_errno(vio) == SOCKET_EINTR);
 }
 
 
+/**
+  Indicate whether a I/O operation timed out.
+
+  @param vio  A VIO object
+
+  @return Whether a I/O operation timed out.
+  @retval TRUE    Operation timed out.
+  @retval FALSE   Not a timeout failure.
+*/
+
 my_bool
-vio_was_interrupted(Vio *vio __attribute__((unused)))
+vio_was_timeout(Vio *vio)
 {
-  int en= socket_errno;
-  return (en == SOCKET_EAGAIN || en == SOCKET_EINTR ||
-	  en == SOCKET_EWOULDBLOCK || en == SOCKET_ETIMEDOUT);
+  return (vio_errno(vio) == SOCKET_ETIMEDOUT);
 }
 
 
+
 int vio_close(Vio * vio)
 {
   int r=0;
@@ -520,58 +630,6 @@ my_bool vio_peer_addr(Vio *vio, char *ip
 
 
 /**
-  Indicate whether there is data to read on a given socket.
-
-  @note An exceptional condition event and/or errors are
-        interpreted as if there is data to read.
-
-  @param sd       A connected socket.
-  @param timeout  Maximum time in seconds to poll.
-
-  @retval FALSE   There is data to read.
-  @retval TRUE    There is no data to read.
-*/
-
-static my_bool socket_poll_read(my_socket sd, uint timeout)
-{
-#ifdef __WIN__
-  int res;
-  my_socket fd= sd;
-  fd_set readfds, errorfds;
-  struct timeval tm;
-  DBUG_ENTER("socket_poll_read");
-  tm.tv_sec= timeout;
-  tm.tv_usec= 0;
-  FD_ZERO(&readfds);
-  FD_ZERO(&errorfds);
-  FD_SET(fd, &readfds);
-  FD_SET(fd, &errorfds);
-  /* The first argument is ignored on Windows, so a conversion to int is OK */
-  if ((res= select((int) fd, &readfds, NULL, &errorfds, &tm) <= 0))
-  {
-    DBUG_RETURN(res < 0 ? 0 : 1);
-  }
-  res= FD_ISSET(fd, &readfds) || FD_ISSET(fd, &errorfds);
-  DBUG_RETURN(!res);
-#elif defined(HAVE_POLL)
-  struct pollfd fds;
-  int res;
-  DBUG_ENTER("socket_poll_read");
-  fds.fd=sd;
-  fds.events=POLLIN;
-  fds.revents=0;
-  if ((res=poll(&fds,1,(int) timeout*1000)) <= 0)
-  {
-    DBUG_RETURN(res < 0 ? 0 : 1);		/* Don't return 1 on errors */
-  }
-  DBUG_RETURN(fds.revents & (POLLIN | POLLERR | POLLHUP) ? 0 : 1);
-#else
-  return 0;
-#endif
-}
-
-
-/**
   Retrieve the amount of data that can be read from a socket.
 
   @param vio          A VIO object.
@@ -583,7 +641,7 @@ static my_bool socket_poll_read(my_socke
 
 static my_bool socket_peek_read(Vio *vio, uint *bytes)
 {
-#ifdef __WIN__
+#ifdef _WIN32
   int len;
   if (ioctlsocket(vio->sd, FIONREAD, &len))
     return TRUE;
@@ -605,434 +663,236 @@ static my_bool socket_peek_read(Vio *vio
 #endif
 }
 
+#ifndef _WIN32
 
 /**
-  Indicate whether there is data to read on a given socket.
-
-  @remark Errors are interpreted as if there is data to read.
-
-  @param sd       A connected socket.
-  @param timeout  Maximum time in seconds to wait.
-
-  @retval FALSE   There is data (or EOF) to read. Also FALSE if error.
-  @retval TRUE    There is _NO_ data to read or timed out.
+  Set of event flags grouped by operations.
 */
 
-my_bool vio_poll_read(Vio *vio, uint timeout)
-{
-  my_socket sd= vio->sd;
-  DBUG_ENTER("vio_poll_read");
-#ifdef HAVE_OPENSSL
-  if (vio->type == VIO_TYPE_SSL)
-    sd= SSL_get_fd((SSL*) vio->ssl_arg);
+/* Linux specific flag for socket shutdown. */
+#ifndef POLLRDHUP
+#define POLLRDHUP 0
 #endif
-  DBUG_RETURN(socket_poll_read(sd, timeout));
-}
 
+/* Data may be read. */
+#define MY_POLL_SET_IN      (POLLIN | POLLPRI | POLLRDHUP)
+/* Data may be written. */
+#define MY_POLL_SET_OUT     (POLLOUT)
+/* An error or hangup. */
+#define MY_POLL_SET_ERR     (POLLERR | POLLHUP)
+
+#endif
 
 /**
-  Determine if the endpoint of a connection is still available.
+  Wait for an I/O event on a VIO socket.
 
-  @remark The socket is assumed to be disconnected if an EOF
-          condition is encountered.
+  @param vio      VIO object representing a connected socket.
+  @param event    The type of I/O event to wait for.
+  @param timeout  Interval (in milliseconds) to wait for an I/O event.
 
-  @param vio      The VIO object.
+  @remark sock_errno is set to SOCKET_ETIMEDOUT on timeout.
 
-  @retval TRUE    EOF condition not found.
-  @retval FALSE   EOF condition is signaled.
+  @return A three-state value which indicates the operation status.
+  @retval -1  Failure, socket_errno indicates the error.
+  @retval  0  The wait has timed out.
+  @retval  1  The requested I/O event has occurred.
 */
 
-my_bool vio_is_connected(Vio *vio)
+#ifdef HAVE_POLLaaaaaaaaaaaaa
+
+int vio_io_wait(Vio *vio, enum enum_vio_io_event event, int timeout)
 {
-  uint bytes= 0;
-  DBUG_ENTER("vio_is_connected");
+  int ret;
+  struct pollfd pfd;
+  my_socket sd= vio->sd;
+  short revents;
+  DBUG_ENTER("vio_io_wait");
+
+  memset(&pfd, 0, sizeof(pfd));
 
-  /* In the presence of errors the socket is assumed to be connected. */
+  pfd.fd= sd;
 
   /*
-    The first step of detecting a EOF condition is veryfing
-    whether there is data to read. Data in this case would
-    be the EOF.
+    Set the poll bitmask describing the type of events.
+    The error flags are only valid in the revents bitmask.
   */
-  if (vio_poll_read(vio, 0))
-    DBUG_RETURN(TRUE);
+  switch (event)
+  {
+  case VIO_IO_EVENT_READ:
+    pfd.events= MY_POLL_SET_IN;
+    revents= MY_POLL_SET_IN | MY_POLL_SET_ERR;
+    break;
+  case VIO_IO_EVENT_WRITE:
+    pfd.events= MY_POLL_SET_OUT;
+    revents= MY_POLL_SET_OUT | MY_POLL_SET_ERR;
+    break;
+  }
 
   /*
-    The second step is read() or recv() from the socket returning
-    0 (EOF). Unfortunelly, it's not possible to call read directly
-    as we could inadvertently read meaningful connection data.
-    Simulate a read by retrieving the number of bytes available to
-    read -- 0 meaning EOF.
+    Wait for the I/O event and return early in case of
+    error or timeout.
   */
-  if (socket_peek_read(vio, &bytes))
-    DBUG_RETURN(TRUE);
-
-#ifdef HAVE_OPENSSL
-  /* There might be buffered data at the SSL layer. */
-  if (!bytes && vio->type == VIO_TYPE_SSL)
-    bytes= SSL_pending((SSL*) vio->ssl_arg);
-#endif
-
-  DBUG_RETURN(bytes ? TRUE : FALSE);
-}
-
-
-void vio_timeout(Vio *vio, uint which, uint timeout)
-{
-#if defined(SO_SNDTIMEO) && defined(SO_RCVTIMEO)
-  int r;
-  DBUG_ENTER("vio_timeout");
-
+  switch ((ret= poll(&pfd, 1, timeout)))
   {
-#ifdef __WIN__
-  /* Windows expects time in milliseconds as int */
-  int wait_timeout= (int) timeout * 1000;
-#else
-  /* POSIX specifies time as struct timeval. */
-  struct timeval wait_timeout;
-  wait_timeout.tv_sec= timeout;
-  wait_timeout.tv_usec= 0;
-#endif
-
-  r= setsockopt(vio->sd, SOL_SOCKET, which ? SO_SNDTIMEO : SO_RCVTIMEO,
-                IF_WIN((const char*), (const void*))&wait_timeout,
-                sizeof(wait_timeout));
-
+  case -1:
+    /* On error, -1 is returned. */
+    break;
+  default:
+    /* Ensure that the requested I/O event has completed. */
+    if (pfd.revents & revents)
+      break;
+    /* Otherwise, treat it as a timeout. */
+    ret= 0;
+  case  0:
+    /* Set errno to indicate a timeout error. */
+    errno= SOCKET_ETIMEDOUT;
   }
 
-  if (r != 0)
-    DBUG_PRINT("error", ("setsockopt failed: %d, errno: %d", r, socket_errno));
-
-  DBUG_VOID_RETURN;
-#else
-/*
-  Platforms not suporting setting of socket timeout should either use
-  thr_alarm or just run without read/write timeout(s)
-*/
-#endif
+  DBUG_RETURN(ret);
 }
 
+#else
 
-#ifdef __WIN__
-
-/*
-  Finish pending IO on pipe. Honor wait timeout
-*/
-static size_t pipe_complete_io(Vio* vio, char* buf, size_t size, DWORD timeout_ms)
+int vio_io_wait(Vio *vio, enum enum_vio_io_event event, int timeout)
 {
-  DWORD length;
-  DWORD ret;
+  int ret;
+  my_socket fd= vio->sd;
+  struct timeval tm, *ptm= NULL;
+  fd_set readfds, writefds, exceptfds;
+  DBUG_ENTER("vio_io_wait");
 
-  DBUG_ENTER("pipe_complete_io");
-
-  ret= WaitForSingleObject(vio->pipe_overlapped.hEvent, timeout_ms);
   /*
-    WaitForSingleObjects will normally return WAIT_OBJECT_O (success, IO completed)
-    or WAIT_TIMEOUT.
+    Convert the timeout, in milliseconds, to seconds and microseconds.
+    Also, select may update the timeval argument to indicate how much
+    time was left.
   */
-  if(ret != WAIT_OBJECT_0)
-  {
-    CancelIo(vio->hPipe);
-    DBUG_PRINT("error",("WaitForSingleObject() returned  %d", ret));
-    DBUG_RETURN((size_t)-1);
-  }
-
-  if (!GetOverlappedResult(vio->hPipe,&(vio->pipe_overlapped),&length, FALSE))
+  if (timeout >= 0)
   {
-    DBUG_PRINT("error",("GetOverlappedResult() returned last error  %d", 
-      GetLastError()));
-    DBUG_RETURN((size_t)-1);
+    tm.tv_sec= timeout / 1000;
+    tm.tv_usec= (timeout % 1000) * 1000;
+    ptm= &tm;
   }
 
-  DBUG_RETURN(length);
-}
+#ifndef _WIN32
+  /*
+    FD_SET() with a value of fd that is negative or is equal to
+    or larger than FD_SETSIZE will result in undefined behavior.
+  */
+  DBUG_ASSERT(fd >= 0 && fd < FD_SETSIZE);
+#endif
 
+  /* Wait for file descriptor to become ready. */
+  while (1)
+  {
+    FD_ZERO(&readfds);
+    FD_ZERO(&writefds);
+    FD_ZERO(&exceptfds);
 
-size_t vio_read_pipe(Vio * vio, uchar *buf, size_t size)
-{
-  DWORD bytes_read;
-  size_t retval;
-  DBUG_ENTER("vio_read_pipe");
-  DBUG_PRINT("enter", ("sd: %d  buf: 0x%lx  size: %u", vio->sd, (long) buf,
-                       (uint) size));
+    /* Always receive notification of exceptions. */
+    FD_SET(fd, &exceptfds);
 
-  if (ReadFile(vio->hPipe, buf, (DWORD)size, &bytes_read,
-      &(vio->pipe_overlapped)))
-  {
-    retval= bytes_read;
-  }
-  else
-  {
-    if (GetLastError() != ERROR_IO_PENDING)
+    switch (event)
     {
-      DBUG_PRINT("error",("ReadFile() returned last error %d",
-        GetLastError()));
-      DBUG_RETURN((size_t)-1);
+    case VIO_IO_EVENT_READ:
+      /* Readiness for reading. */
+      FD_SET(fd, &readfds);
+      break;
+    case VIO_IO_EVENT_WRITE:
+      /* Readiness for writing. */
+      FD_SET(fd, &writefds);
+      break;
     }
-    retval= pipe_complete_io(vio, buf, size,vio->read_timeout_ms);
-  }
 
-  DBUG_PRINT("exit", ("%lld", (longlong)retval));
-  DBUG_RETURN(retval);
-}
+    /* The first argument is ignored on Windows. */
+    ret= select(IF_WIN(0, fd + 1), &readfds, &writefds, &exceptfds, ptm);
 
+    /* Error or timeout? */
+    if (ret <= 0)
+      break;
 
-size_t vio_write_pipe(Vio * vio, const uchar* buf, size_t size)
-{
-  DWORD bytes_written;
-  size_t retval;
-  DBUG_ENTER("vio_write_pipe");
-  DBUG_PRINT("enter", ("sd: %d  buf: 0x%lx  size: %u", vio->sd, (long) buf,
-                       (uint) size));
+    /* The requested I/O event is ready? */
+    switch (event)
+    {
+    case VIO_IO_EVENT_READ:
+      ret= FD_ISSET(fd, &readfds);
+      break;
+    case VIO_IO_EVENT_WRITE:
+      ret= FD_ISSET(fd, &writefds);
+      break;
+    }
 
-  if (WriteFile(vio->hPipe, buf, (DWORD)size, &bytes_written, 
-      &(vio->pipe_overlapped)))
-  {
-    retval= bytes_written;
-  }
-  else
-  {
-    if (GetLastError() != ERROR_IO_PENDING)
+    /* If not, resume the select. */
+    if (ret || FD_ISSET(fd, &exceptfds))
     {
-      DBUG_PRINT("vio_error",("WriteFile() returned last error %d",
-        GetLastError()));
-      DBUG_RETURN((size_t)-1);
+      ret= 1;
+      break;
     }
-    retval= pipe_complete_io(vio, (char *)buf, size, vio->write_timeout_ms);
   }
 
-  DBUG_PRINT("exit", ("%lld", (longlong)retval));
-  DBUG_RETURN(retval);
-}
-
-
-my_bool vio_is_connected_pipe(Vio *vio)
-{
-  if (PeekNamedPipe(vio->hPipe, NULL, 0, NULL, NULL, NULL))
-    return TRUE;
-  else
-    return (GetLastError() != ERROR_BROKEN_PIPE);
-}
-
-
-int vio_close_pipe(Vio * vio)
-{
-  int r;
-  DBUG_ENTER("vio_close_pipe");
-
-  CancelIo(vio->hPipe);
-  CloseHandle(vio->pipe_overlapped.hEvent);
-  DisconnectNamedPipe(vio->hPipe);
-  r= CloseHandle(vio->hPipe);
-  if (r)
+  /* Set error code to indicate a timeout error. */
+  if (ret == 0)
   {
-    DBUG_PRINT("vio_error", ("close() failed, error: %d",GetLastError()));
-    /* FIXME: error handling (not critical for MySQL) */
+#ifndef _WIN32
+    errno= SOCKET_ETIMEDOUT;
+#else
+    WSASetLastError(SOCKET_ETIMEDOUT);
+#endif
   }
-  vio->type= VIO_CLOSED;
-  vio->sd=   -1;
-  DBUG_RETURN(r);
-}
-
-
-void vio_win32_timeout(Vio *vio, uint which , uint timeout_sec)
-{
-    DWORD timeout_ms;
-    /*
-      Windows is measuring timeouts in milliseconds. Check for possible int 
-      overflow.
-    */
-    if (timeout_sec > UINT_MAX/1000)
-      timeout_ms= INFINITE;
-    else
-      timeout_ms= timeout_sec * 1000;
 
-    /* which == 1 means "write", which == 0 means "read".*/
-    if(which)
-      vio->write_timeout_ms= timeout_ms;
-    else
-      vio->read_timeout_ms= timeout_ms;
+  DBUG_RETURN(ret);
 }
 
+#endif /* HAVE_POLL */
 
-#ifdef HAVE_SMEM
 
-size_t vio_read_shared_memory(Vio * vio, uchar* buf, size_t size)
-{
-  size_t length;
-  size_t remain_local;
-  char *current_postion;
-  HANDLE events[2];
-
-  DBUG_ENTER("vio_read_shared_memory");
-  DBUG_PRINT("enter", ("sd: %d  buf: 0x%lx  size: %d", vio->sd, (long) buf,
-                       size));
-
-  remain_local = size;
-  current_postion=buf;
-
-  events[0]= vio->event_server_wrote;
-  events[1]= vio->event_conn_closed;
-
-  do
-  {
-    if (vio->shared_memory_remain == 0)
-    {
-      /*
-        WaitForMultipleObjects can return next values:
-         WAIT_OBJECT_0+0 - event from vio->event_server_wrote
-         WAIT_OBJECT_0+1 - event from vio->event_conn_closed. We can't read
-		           anything
-         WAIT_ABANDONED_0 and WAIT_TIMEOUT - fail.  We can't read anything
-      */
-      if (WaitForMultipleObjects(array_elements(events), events, FALSE,
-                                 vio->read_timeout_ms) != WAIT_OBJECT_0)
-      {
-        DBUG_RETURN(-1);
-      };
-
-      vio->shared_memory_pos = vio->handle_map;
-      vio->shared_memory_remain = uint4korr((ulong*)vio->shared_memory_pos);
-      vio->shared_memory_pos+=4;
-    }
-
-    length = size;
-
-    if (vio->shared_memory_remain < length)
-       length = vio->shared_memory_remain;
-    if (length > remain_local)
-       length = remain_local;
-
-    memcpy(current_postion,vio->shared_memory_pos,length);
-
-    vio->shared_memory_remain-=length;
-    vio->shared_memory_pos+=length;
-    current_postion+=length;
-    remain_local-=length;
+/**
+  Determine if the endpoint of a connection is still available.
 
-    if (!vio->shared_memory_remain)
-    {
-      if (!SetEvent(vio->event_client_read))
-        DBUG_RETURN(-1);
-    }
-  } while (remain_local);
-  length = size;
+  @remark The socket is assumed to be disconnected if an EOF
+          condition is encountered.
 
-  DBUG_PRINT("exit", ("%lu", (ulong) length));
-  DBUG_RETURN(length);
-}
+  @param vio      The VIO object.
 
+  @retval TRUE    EOF condition not found.
+  @retval FALSE   EOF condition is signaled.
+*/
 
-size_t vio_write_shared_memory(Vio * vio, const uchar* buf, size_t size)
+my_bool vio_is_connected(Vio *vio)
 {
-  size_t length, remain, sz;
-  HANDLE pos;
-  const uchar *current_postion;
-  HANDLE events[2];
-
-  DBUG_ENTER("vio_write_shared_memory");
-  DBUG_PRINT("enter", ("sd: %d  buf: 0x%lx  size: %d", vio->sd, (long) buf,
-                       size));
-
-  remain = size;
-  current_postion = buf;
+  uint bytes= 0;
+  DBUG_ENTER("vio_is_connected");
 
-  events[0]= vio->event_server_read;
-  events[1]= vio->event_conn_closed;
+  /*
+    The first step of detecting an EOF condition is verifying
+    whether there is data to read. Data in this case would be
+    the EOF. An exceptional condition event and/or errors are
+    interpreted as if there is data to read.
+  */
+  if (!vio_io_wait(vio, VIO_IO_EVENT_READ, 0))
+    DBUG_RETURN(TRUE);
 
-  while (remain != 0)
+  /*
+    The second step is read() or recv() from the socket returning
+    0 (EOF). Unfortunelly, it's not possible to call read directly
+    as we could inadvertently read meaningful connection data.
+    Simulate a read by retrieving the number of bytes available to
+    read -- 0 meaning EOF. In the presence of unrecoverable errors,
+    the socket is assumed to be disconnected.
+  */
+  while (socket_peek_read(vio, &bytes))
   {
-    if (WaitForMultipleObjects(array_elements(events), events, FALSE,
-                               vio->write_timeout_ms) != WAIT_OBJECT_0)
-    {
-      DBUG_RETURN((size_t) -1);
-    }
-
-    sz= (remain > shared_memory_buffer_length ? shared_memory_buffer_length :
-         remain);
-
-    int4store(vio->handle_map,sz);
-    pos = vio->handle_map + 4;
-    memcpy(pos,current_postion,sz);
-    remain-=sz;
-    current_postion+=sz;
-    if (!SetEvent(vio->event_client_wrote))
-      DBUG_RETURN((size_t) -1);
+    if (vio_errno(vio) != SOCKET_EINTR)
+      DBUG_RETURN(FALSE);
   }
-  length = size;
-
-  DBUG_PRINT("exit", ("%lu", (ulong) length));
-  DBUG_RETURN(length);
-}
-
-
-my_bool vio_is_connected_shared_memory(Vio *vio)
-{
-  return (WaitForSingleObject(vio->event_conn_closed, 0) != WAIT_OBJECT_0);
-}
 
+#ifdef HAVE_OPENSSL
+  /* There might be buffered data at the SSL layer. */
+  if (!bytes && vio->type == VIO_TYPE_SSL)
+    bytes= SSL_pending((SSL*) vio->ssl_arg);
+#endif
 
-/**
- Close shared memory and DBUG_PRINT any errors that happen on closing.
- @return Zero if all closing functions succeed, and nonzero otherwise.
-*/
-int vio_close_shared_memory(Vio * vio)
-{
-  int error_count= 0;
-  DBUG_ENTER("vio_close_shared_memory");
-  if (vio->type != VIO_CLOSED)
-  {
-    /*
-      Set event_conn_closed for notification of both client and server that
-      connection is closed
-    */
-    SetEvent(vio->event_conn_closed);
-    /*
-      Close all handlers. UnmapViewOfFile and CloseHandle return non-zero
-      result if they are success.
-    */
-    if (UnmapViewOfFile(vio->handle_map) == 0) 
-    {
-      error_count++;
-      DBUG_PRINT("vio_error", ("UnmapViewOfFile() failed"));
-    }
-    if (CloseHandle(vio->event_server_wrote) == 0)
-    {
-      error_count++;
-      DBUG_PRINT("vio_error", ("CloseHandle(vio->esw) failed"));
-    }
-    if (CloseHandle(vio->event_server_read) == 0)
-    {
-      error_count++;
-      DBUG_PRINT("vio_error", ("CloseHandle(vio->esr) failed"));
-    }
-    if (CloseHandle(vio->event_client_wrote) == 0)
-    {
-      error_count++;
-      DBUG_PRINT("vio_error", ("CloseHandle(vio->ecw) failed"));
-    }
-    if (CloseHandle(vio->event_client_read) == 0)
-    {
-      error_count++;
-      DBUG_PRINT("vio_error", ("CloseHandle(vio->ecr) failed"));
-    }
-    if (CloseHandle(vio->handle_file_map) == 0)
-    {
-      error_count++;
-      DBUG_PRINT("vio_error", ("CloseHandle(vio->hfm) failed"));
-    }
-    if (CloseHandle(vio->event_conn_closed) == 0)
-    {
-      error_count++;
-      DBUG_PRINT("vio_error", ("CloseHandle(vio->ecc) failed"));
-    }
-  }
-  vio->type= VIO_CLOSED;
-  vio->sd=   -1;
-  DBUG_RETURN(error_count);
+  DBUG_RETURN(bytes ? TRUE : FALSE);
 }
-#endif /* HAVE_SMEM */
-#endif /* __WIN__ */
 
 
 /**

=== modified file 'vio/viossl.c'
--- a/vio/viossl.c	2010-08-16 12:50:27 +0000
+++ b/vio/viossl.c	2010-11-14 12:19:57 +0000
@@ -24,6 +24,8 @@
 
 #ifdef HAVE_OPENSSL
 
+#include <errno.h>
+
 static void
 report_errors(SSL* ssl)
 {
@@ -52,37 +54,133 @@ report_errors(SSL* ssl)
 }
 
 
-size_t vio_ssl_read(Vio *vio, uchar* buf, size_t size)
+/**
+  Obtain the error status for the last SSL I/O operation.
+
+  @param vio The VIO object associated with the I/O operation.
+
+  @return A valid error number or zero if one cannot be obtained.
+*/
+
+int vio_ssl_errno(Vio *vio)
+{
+  int error;
+
+  switch (vio->ssl_error)
+  {
+  case SSL_ERROR_NONE:
+    error= 0;
+    break;
+  case SSL_ERROR_ZERO_RETURN:
+    error= SOCKET_ECONNRESET;
+    break;
+  case SSL_ERROR_WANT_READ:
+  case SSL_ERROR_WANT_WRITE:
+#ifdef SSL_ERROR_WANT_CONNECT
+  case SSL_ERROR_WANT_CONNECT:
+#endif
+#ifdef SSL_ERROR_WANT_ACCEPT
+  case SSL_ERROR_WANT_ACCEPT:
+#endif
+    error= SOCKET_EWOULDBLOCK;
+    break;
+  case SSL_ERROR_SSL:
+    /* Protocol error. */
+#ifdef EPROTO
+    error= EPROTO;
+#else
+    error= SOCKET_ECONNRESET;
+#endif
+    break;
+  case SSL_ERROR_SYSCALL:
+  default:
+    error= socket_errno;
+    break;
+  };
+
+  return error;
+}
+
+/**
+  Attempt to wait for an I/O event on a SSL connection.
+
+  @param vio  VIO object representing a connected socket.
+  @param ret  The return value from SSL_read or SSL_write.
+
+  @return Return value is -1 on failure, 0 on success.
+*/
+
+static int ssl_io_wait(Vio *vio, int ret)
 {
-  size_t r;
+  enum enum_vio_io_event event;
+
+  /* Retrieve the result for the SSL I/O operation. */
+  vio->ssl_error= SSL_get_error(vio->ssl_arg, ret);
+
+  /*
+    A TLS/SSL I/O operation (i.e. SSL_read, SSL_write) might
+    yield SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE at any
+    time when performing a SSL renegotiation.
+  */
+  if (vio->ssl_error == SSL_ERROR_WANT_WRITE)
+    event= VIO_IO_EVENT_WRITE;
+  else if (vio->ssl_error == SSL_ERROR_WANT_READ)
+    event= VIO_IO_EVENT_READ;
+  else
+    return -1;
+
+  if (vio_socket_io_wait(vio, event))
+  {
+    /* Some system-specific (special) error occurred. */
+    vio->ssl_error= SSL_ERROR_SYSCALL;
+    return -1;
+  }
+
+  return 0;
+}
+
+
+size_t vio_ssl_read(Vio *vio, uchar *buf, size_t size)
+{
+  int ret;
+  SSL *ssl= vio->ssl_arg;
   DBUG_ENTER("vio_ssl_read");
-  DBUG_PRINT("enter", ("sd: %d  buf: 0x%lx  size: %u  ssl: 0x%lx",
-		       vio->sd, (long) buf, (uint) size, (long) vio->ssl_arg));
 
-  r= SSL_read((SSL*) vio->ssl_arg, buf, size);
+  while ((ret= SSL_read(ssl, buf, size)) < 0)
+  {
+    /* Attempt to wait for an I/O event. */
+    if ((ret= ssl_io_wait(vio, ret)))
+      break;
+  }
+
 #ifndef DBUG_OFF
-  if (r == (size_t) -1)
-    report_errors((SSL*) vio->ssl_arg);
+  if (vio->ssl_error != SSL_ERROR_NONE)
+    report_errors(ssl);
 #endif
-  DBUG_PRINT("exit", ("%u", (uint) r));
-  DBUG_RETURN(r);
+
+  DBUG_RETURN(ret);
 }
 
 
-size_t vio_ssl_write(Vio *vio, const uchar* buf, size_t size)
+size_t vio_ssl_write(Vio *vio, const uchar *buf, size_t size)
 {
-  size_t r;
-  DBUG_ENTER("vio_ssl_write");
-  DBUG_PRINT("enter", ("sd: %d  buf: 0x%lx  size: %u", vio->sd,
-                       (long) buf, (uint) size));
+  int ret;
+  SSL *ssl= vio->ssl_arg;
+  DBUG_ENTER("vio_ssl_read");
+
+  while ((ret= SSL_write(ssl, buf, size)) < 0)
+  {
+    /* Attempt to wait for an I/O event. */
+    if ((ret= ssl_io_wait(vio, ret)))
+      break;
+  }
 
-  r= SSL_write((SSL*) vio->ssl_arg, buf, size);
 #ifndef DBUG_OFF
-  if (r == (size_t) -1)
-    report_errors((SSL*) vio->ssl_arg);
+  if (vio->ssl_error != SSL_ERROR_NONE)
+    report_errors(ssl);
 #endif
-  DBUG_PRINT("exit", ("%u", (uint) r));
-  DBUG_RETURN(r);
+
+  DBUG_RETURN(ret);
 }
 
 
@@ -143,25 +241,53 @@ void vio_ssl_delete(Vio *vio)
 }
 
 
+/** SSL handshake handler. */
+typedef int (*ssl_handshake_func_t)(SSL*);
+
+
+/**
+  Loop and wait until a SSL handshake is completed.
+
+  @param vio    VIO object representing a SSL connection.
+  @param ssl    SSL structure for the connection.
+  @param func   SSL handshake handler.
+
+  @return Return value is 1 on success.
+*/
+
+static int ssl_handshake_loop(Vio *vio, SSL *ssl, ssl_handshake_func_t func)
+{
+  int ret;
+
+  vio->ssl_arg= ssl;
+
+  /* Initiate the SSL handshake. */
+  while ((ret= func(ssl)) < 1)
+  {
+    /* Wait for I/O so that the handshake can proceed. */
+    if ((ret= ssl_io_wait(vio, ret)))
+      break;
+  }
+
+  vio->ssl_arg= NULL;
+
+  return ret;
+}
+
+
 static int ssl_do(struct st_VioSSLFd *ptr, Vio *vio, long timeout,
-                  int (*connect_accept_func)(SSL*))
+                  ssl_handshake_func_t func)
 {
   SSL *ssl;
-  my_bool unused;
-  my_bool was_blocking;
 
   DBUG_ENTER("ssl_do");
   DBUG_PRINT("enter", ("ptr: 0x%lx, sd: %d  ctx: 0x%lx",
                        (long) ptr, vio->sd, (long) ptr->ssl_context));
 
-  /* Set socket to blocking if not already set */
-  vio_blocking(vio, 1, &was_blocking);
-
   if (!(ssl= SSL_new(ptr->ssl_context)))
   {
     DBUG_PRINT("error", ("SSL_new failure"));
     report_errors(ssl);
-    vio_blocking(vio, was_blocking, &unused);
     DBUG_RETURN(1);
   }
   DBUG_PRINT("info", ("ssl: 0x%lx timeout: %ld", (long) ssl, timeout));
@@ -169,12 +295,11 @@ static int ssl_do(struct st_VioSSLFd *pt
   SSL_SESSION_set_timeout(SSL_get_session(ssl), timeout);
   SSL_set_fd(ssl, vio->sd);
 
-  if (connect_accept_func(ssl) < 1)
+  if (ssl_handshake_loop(vio, ssl, func) < 1)
   {
     DBUG_PRINT("error", ("SSL_connect/accept failure"));
     report_errors(ssl);
     SSL_free(ssl);
-    vio_blocking(vio, was_blocking, &unused);
     DBUG_RETURN(1);
   }
 
@@ -183,8 +308,8 @@ static int ssl_do(struct st_VioSSLFd *pt
     change type, set sd to the fd used when connecting
     and set pointer to the SSL structure
   */
-  vio_reset(vio, VIO_TYPE_SSL, SSL_get_fd(ssl), 0, 0);
-  vio->ssl_arg= (void*)ssl;
+  if (vio_rebind_ssl(vio, ssl))
+    DBUG_RETURN(1);
 
 #ifndef DBUG_OFF
   {
@@ -233,17 +358,6 @@ int sslconnect(struct st_VioSSLFd *ptr,
   DBUG_RETURN(ssl_do(ptr, vio, timeout, SSL_connect));
 }
 
-
-int vio_ssl_blocking(Vio *vio __attribute__((unused)),
-		     my_bool set_blocking_mode,
-		     my_bool *old_mode)
-{
-  /* Mode is always blocking */
-  *old_mode= 1;
-  /* Return error if we try to change to non_blocking mode */
-  return (set_blocking_mode ? 0 : 1);
-}
-
 my_bool vio_ssl_has_data(Vio *vio)
 {
   return SSL_pending(vio->ssl_arg) > 0 ? TRUE : FALSE;


Attachment: [text/bzr-bundle] bzr/davi.arnaut@oracle.com-20101114121957-lftktfpb6q7dfgig.bundle
Thread
bzr commit into mysql-5.5-runtime branch (davi:3184) Davi Arnaut14 Nov