diff options
-rw-r--r-- | client/mysqltest.cc | 38 | ||||
-rw-r--r-- | include/violite.h | 17 | ||||
-rw-r--r-- | mysql-test/t/named_pipe.test | 5 | ||||
-rw-r--r-- | mysql-test/t/shm.test | 10 | ||||
-rw-r--r-- | sql/item_func.cc | 2 | ||||
-rw-r--r-- | sql/sql_class.cc | 24 | ||||
-rw-r--r-- | sql/sql_class.h | 7 | ||||
-rw-r--r-- | vio/vio.c | 30 | ||||
-rw-r--r-- | vio/vio_priv.h | 14 | ||||
-rw-r--r-- | vio/viosocket.c | 123 |
10 files changed, 223 insertions, 47 deletions
diff --git a/client/mysqltest.cc b/client/mysqltest.cc index b62d101e884..93e6e58e221 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -4859,6 +4859,8 @@ do_handle_error: <opts> - options to use for the connection * SSL - use SSL if available * COMPRESS - use compression if available + * SHM - use shared memory if available + * PIPE - use named pipe if available */ @@ -4867,6 +4869,7 @@ void do_connect(struct st_command *command) int con_port= opt_port; char *con_options; my_bool con_ssl= 0, con_compress= 0; + my_bool con_pipe= 0, con_shm= 0; struct st_connection* con_slot; static DYNAMIC_STRING ds_connection_name; @@ -4877,6 +4880,9 @@ void do_connect(struct st_command *command) static DYNAMIC_STRING ds_port; static DYNAMIC_STRING ds_sock; static DYNAMIC_STRING ds_options; +#ifdef HAVE_SMEM + static DYNAMIC_STRING ds_shm; +#endif const struct command_arg connect_args[] = { { "connection name", ARG_STRING, TRUE, &ds_connection_name, "Name of the connection" }, { "host", ARG_STRING, TRUE, &ds_host, "Host to connect to" }, @@ -4904,6 +4910,11 @@ void do_connect(struct st_command *command) die("Illegal argument for port: '%s'", ds_port.str); } +#ifdef HAVE_SMEM + /* Shared memory */ + init_dynamic_string(&ds_shm, ds_sock.str, 0, 0); +#endif + /* Sock */ if (ds_sock.length) { @@ -4942,6 +4953,10 @@ void do_connect(struct st_command *command) con_ssl= 1; else if (!strncmp(con_options, "COMPRESS", 8)) con_compress= 1; + else if (!strncmp(con_options, "PIPE", 4)) + con_pipe= 1; + else if (!strncmp(con_options, "SHM", 3)) + con_shm= 1; else die("Illegal option to connect: %.*s", (int) (end - con_options), con_options); @@ -4994,6 +5009,26 @@ void do_connect(struct st_command *command) } #endif +#ifdef __WIN__ + if (con_pipe) + { + uint protocol= MYSQL_PROTOCOL_PIPE; + mysql_options(&con_slot->mysql, MYSQL_OPT_PROTOCOL, &protocol); + } +#endif + +#ifdef HAVE_SMEM + if (con_shm) + { + uint protocol= MYSQL_PROTOCOL_MEMORY; + if (!ds_shm.length) + die("Missing shared memory base name"); + mysql_options(&con_slot->mysql, MYSQL_OPT_PROTOCOL, &protocol); + mysql_options(&con_slot->mysql, MYSQL_SHARED_MEMORY_BASE_NAME, ds_shm.str); + } +#endif + + /* Use default db name */ if (ds_database.length == 0) dynstr_set(&ds_database, opt_db); @@ -5026,6 +5061,9 @@ void do_connect(struct st_command *command) dynstr_free(&ds_port); dynstr_free(&ds_sock); dynstr_free(&ds_options); +#ifdef HAVE_SMEM + dynstr_free(&ds_shm); +#endif DBUG_VOID_RETURN; } diff --git a/include/violite.h b/include/violite.h index 0e07e1c69ca..395feb4e0df 100644 --- a/include/violite.h +++ b/include/violite.h @@ -51,9 +51,6 @@ Vio* vio_new_win32shared_memory(NET *net,HANDLE handle_file_map, HANDLE event_client_wrote, HANDLE event_client_read, HANDLE event_conn_closed); -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); -int vio_close_pipe(Vio * vio); #else #define HANDLE void * #endif /* __WIN__ */ @@ -87,8 +84,8 @@ my_socket vio_fd(Vio*vio); my_bool vio_peer_addr(Vio* vio, char *buf, uint16 *port); /* Remotes in_addr */ void vio_in_addr(Vio *vio, struct in_addr *in); -my_bool vio_poll_read(Vio *vio,uint timeout); -my_bool vio_peek_read(Vio *vio, uint *bytes); +my_bool vio_poll_read(Vio *vio, uint timeout); +my_bool vio_is_connected(Vio *vio); #ifdef HAVE_OPENSSL #include <openssl/opensslv.h> @@ -137,12 +134,6 @@ struct st_VioSSLFd void free_vio_ssl_acceptor_fd(struct st_VioSSLFd *fd); #endif /* HAVE_OPENSSL */ -#ifdef HAVE_SMEM -size_t vio_read_shared_memory(Vio *vio, uchar * buf, size_t size); -size_t vio_write_shared_memory(Vio *vio, const uchar * buf, size_t size); -int vio_close_shared_memory(Vio * vio); -#endif - void vio_end(void); #ifdef __cplusplus @@ -165,6 +156,8 @@ void vio_end(void); #define vio_peer_addr(vio, buf, prt) (vio)->peer_addr(vio, buf, prt) #define vio_in_addr(vio, in) (vio)->in_addr(vio, in) #define vio_timeout(vio, which, seconds) (vio)->timeout(vio, which, seconds) +#define vio_poll_read(vio, timeout) (vio)->poll_read(vio, timeout) +#define vio_is_connected(vio) (vio)->is_connected(vio) #endif /* !defined(DONT_MAP_VIO) */ /* This enumerator is used in parser - should be always visible */ @@ -209,6 +202,8 @@ struct st_vio my_bool (*was_interrupted)(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*); #ifdef HAVE_OPENSSL void *ssl_arg; #endif diff --git a/mysql-test/t/named_pipe.test b/mysql-test/t/named_pipe.test index e3dfd24bb52..e88fd8e1ef8 100644 --- a/mysql-test/t/named_pipe.test +++ b/mysql-test/t/named_pipe.test @@ -9,6 +9,11 @@ if (`SELECT '$nmp' != 'ON'`){ skip No named pipe support; } +# Connect using named pipe for testing +connect(pipe_con,localhost,root,,,,,PIPE); + # Source select test case -- source include/common-tests.inc +connection default; +disconnect pipe_con; diff --git a/mysql-test/t/shm.test b/mysql-test/t/shm.test index 88e96ae7b45..567caa4989a 100644 --- a/mysql-test/t/shm.test +++ b/mysql-test/t/shm.test @@ -7,10 +7,17 @@ let $shm= query_get_value("SHOW VARIABLES LIKE 'shared_memory'", Value, 1); if (`SELECT '$shm' != 'ON'`){ skip No shm support; } +let $shm_name= query_get_value("SHOW GLOBAL VARIABLES LIKE 'shared_memory_base_name'", Value, 1); + +# Connect using SHM for testing +connect(shm_con,localhost,root,,,,$shm_name,SHM); # Source select test case -- source include/common-tests.inc +connection default; +disconnect shm_con; + # # Bug #24924: shared-memory-base-name that is too long causes buffer overflow # @@ -20,7 +27,6 @@ if (`SELECT '$shm' != 'ON'`){ # Bug #33899: Deadlock in mysql_real_query with shared memory connections # -let $name= query_get_value("SHOW GLOBAL VARIABLES LIKE 'shared_memory_base_name'", Value, 1); let $stmt= `SELECT REPEAT('a', 2048)`; SET @max_allowed_packet= @@global.max_allowed_packet; @@ -30,7 +36,7 @@ SET GLOBAL max_allowed_packet= 1024; SET GLOBAL net_buffer_length= 1024; --error 1 ---exec echo SELECT '$stmt'| $MYSQL --protocol=memory --shared-memory-base-name=$name 2>&1 +--exec echo SELECT '$stmt'| $MYSQL --protocol=memory --shared-memory-base-name=$shm_name 2>&1 SET GLOBAL max_allowed_packet= @max_allowed_packet; SET GLOBAL net_buffer_length= @net_buffer_length; diff --git a/sql/item_func.cc b/sql/item_func.cc index 8f2739f8e77..c466dcc5cb9 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3471,7 +3471,7 @@ static int interruptible_wait(THD *thd, pthread_cond_t *cond, if (error == ETIMEDOUT || error == ETIME) { /* Return error if timed out or connection is broken. */ - if (!timeout || !thd->vio_is_connected()) + if (!timeout || !thd->is_connected()) break; } } while (error && timeout); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index e765d892884..212d727b7f1 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1618,30 +1618,6 @@ void THD::rollback_item_tree_changes() } -#ifndef EMBEDDED_LIBRARY - -/** - Check that the endpoint is still available. -*/ - -bool THD::vio_is_connected() -{ - uint bytes= 0; - - /* End of input is signaled by poll if the socket is aborted. */ - if (vio_poll_read(net.vio, 0)) - return TRUE; - - /* Socket is aborted if signaled but no data is available. */ - if (vio_peek_read(net.vio, &bytes)) - return TRUE; - - return bytes ? TRUE : FALSE; -} - -#endif - - /***************************************************************************** ** Functions to provide a interface to select results *****************************************************************************/ diff --git a/sql/sql_class.h b/sql/sql_class.h index 5117304a26f..87dcf361aa3 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1962,11 +1962,14 @@ public: } inline bool vio_ok() const { return net.vio != 0; } /** Return FALSE if connection to client is broken. */ - bool vio_is_connected(); + bool is_connected() + { + return vio_ok() ? vio_is_connected(net.vio) : FALSE; + } #else void clear_error(); inline bool vio_ok() const { return TRUE; } - inline bool vio_is_connected() { return TRUE; } + inline bool is_connected() { return TRUE; } #endif /** Mark the current error as fatal. Warning: this does not diff --git a/vio/vio.c b/vio/vio.c index e088687098b..5eca4bd1dc6 100644 --- a/vio/vio.c +++ b/vio/vio.c @@ -22,6 +22,28 @@ #include "vio_priv.h" +#if defined(__WIN__) || defined(HAVE_SMEM) + +/** + Stub poll_read method that defaults to indicate that there + is data to read. + + Used for named pipe and shared memory VIO types. + + @param vio Unused. + @param timeout Unused. + + @retval FALSE There is data to read. +*/ + +static my_bool no_poll_read(Vio *vio __attribute__((unused)), + uint timeout __attribute__((unused))) +{ + return FALSE; +} + +#endif + /* * Helper to fill most of the Vio* with defaults. */ @@ -60,6 +82,8 @@ static void vio_init(Vio* vio, enum enum_vio_type type, vio->vioblocking =vio_blocking; vio->is_blocking =vio_is_blocking; vio->timeout =vio_ignore_timeout; + vio->poll_read =no_poll_read; + vio->is_connected =vio_is_connected_pipe; } else /* default is VIO_TYPE_TCPIP */ #endif @@ -80,6 +104,8 @@ static void vio_init(Vio* vio, enum enum_vio_type type, vio->vioblocking =vio_blocking; vio->is_blocking =vio_is_blocking; vio->timeout =vio_ignore_timeout; + vio->poll_read =no_poll_read; + vio->is_connected =vio_is_connected_shared_memory; } else #endif @@ -100,6 +126,8 @@ static void vio_init(Vio* vio, enum enum_vio_type type, vio->vioblocking =vio_ssl_blocking; vio->is_blocking =vio_is_blocking; vio->timeout =vio_timeout; + vio->poll_read =vio_poll_read; + vio->is_connected =vio_is_connected; } else /* default is VIO_TYPE_TCPIP */ #endif /* HAVE_OPENSSL */ @@ -118,6 +146,8 @@ static void vio_init(Vio* vio, enum enum_vio_type type, vio->vioblocking =vio_blocking; vio->is_blocking =vio_is_blocking; vio->timeout =vio_timeout; + vio->poll_read =vio_poll_read; + vio->is_connected =vio_is_connected; } DBUG_VOID_RETURN; } diff --git a/vio/vio_priv.h b/vio/vio_priv.h index 792fad4cc66..c32d973393f 100644 --- a/vio/vio_priv.h +++ b/vio/vio_priv.h @@ -25,6 +25,20 @@ #include <m_string.h> #include <violite.h> +#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); +my_bool vio_is_connected_pipe(Vio *vio); +int vio_close_pipe(Vio * vio); +#endif + +#ifdef HAVE_SMEM +size_t vio_read_shared_memory(Vio *vio, uchar * buf, size_t size); +size_t vio_write_shared_memory(Vio *vio, const uchar * buf, size_t size); +my_bool vio_is_connected_shared_memory(Vio *vio); +int vio_close_shared_memory(Vio * vio); +#endif + void vio_ignore_timeout(Vio *vio, uint which, uint timeout); void vio_timeout(Vio *vio,uint which, uint timeout); diff --git a/vio/viosocket.c b/vio/viosocket.c index e83559729b9..055112f944e 100644 --- a/vio/viosocket.c +++ b/vio/viosocket.c @@ -356,15 +356,26 @@ void vio_in_addr(Vio *vio, struct in_addr *in) } -/* Return 0 if there is data to be read */ +/** + 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. -my_bool vio_poll_read(Vio *vio,uint timeout) + @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, fd= vio->sd; + my_socket fd= sd; fd_set readfds, errorfds; struct timeval tm; - DBUG_ENTER("vio_poll"); + DBUG_ENTER("socket_poll_read"); tm.tv_sec= timeout; tm.tv_usec= 0; FD_ZERO(&readfds); @@ -380,8 +391,8 @@ my_bool vio_poll_read(Vio *vio,uint timeout) #elif defined(HAVE_POLL) struct pollfd fds; int res; - DBUG_ENTER("vio_poll"); - fds.fd=vio->sd; + DBUG_ENTER("socket_poll_read"); + fds.fd=sd; fds.events=POLLIN; fds.revents=0; if ((res=poll(&fds,1,(int) timeout*1000)) <= 0) @@ -395,7 +406,17 @@ my_bool vio_poll_read(Vio *vio,uint timeout) } -my_bool vio_peek_read(Vio *vio, uint *bytes) +/** + Retrieve the amount of data that can be read from a socket. + + @param vio A VIO object. + @param bytes[out] The amount of bytes available. + + @retval FALSE Success. + @retval TRUE Failure. +*/ + +static my_bool socket_peek_read(Vio *vio, uint *bytes) { #ifdef __WIN__ int len; @@ -419,6 +440,78 @@ my_bool vio_peek_read(Vio *vio, uint *bytes) #endif } + +/** + 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. +*/ + +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); +#endif + DBUG_RETURN(socket_poll_read(sd, timeout)); +} + + +/** + Determine if the endpoint of a connection is still available. + + @remark The socket is assumed to be disconnected if an EOF + condition is encountered. + + @param vio The VIO object. + + @retval TRUE EOF condition not found. + @retval FALSE EOF condition is signaled. +*/ + +my_bool vio_is_connected(Vio *vio) +{ + uint bytes= 0; + DBUG_ENTER("vio_is_connected"); + + /* In the presence of errors the socket is assumed to be connected. */ + + /* + The first step of detecting a EOF condition is veryfing + whether there is data to read. Data in this case would + be the EOF. + */ + if (vio_poll_read(vio, 0)) + DBUG_RETURN(TRUE); + + /* + 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. + */ + 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) @@ -487,6 +580,16 @@ size_t vio_write_pipe(Vio * vio, const uchar* buf, size_t size) DBUG_RETURN((size_t) length); } + +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; @@ -625,6 +728,12 @@ size_t vio_write_shared_memory(Vio * vio, const uchar* buf, size_t size) } +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. |