diff options
Diffstat (limited to 'vio')
-rw-r--r-- | vio/vio.c | 30 | ||||
-rw-r--r-- | vio/vio_priv.h | 14 | ||||
-rw-r--r-- | vio/viosocket.c | 123 |
3 files changed, 160 insertions, 7 deletions
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. |