diff options
author | Michael Widenius <monty@askmonty.org> | 2012-08-14 17:23:34 +0300 |
---|---|---|
committer | Michael Widenius <monty@askmonty.org> | 2012-08-14 17:23:34 +0300 |
commit | 60589aeee03949033c66da5c1eae70d4342179fc (patch) | |
tree | 1cd399dbed17c5c7b4ed16eb7b872dc979af1c93 /vio/vio.c | |
parent | b39e6e3d093b45f792959ef06fea1c175263ae1a (diff) | |
download | mariadb-git-60589aeee03949033c66da5c1eae70d4342179fc.tar.gz |
Next part of merge. See TODO for details
Diffstat (limited to 'vio/vio.c')
-rw-r--r-- | vio/vio.c | 248 |
1 files changed, 156 insertions, 92 deletions
diff --git a/vio/vio.c b/vio/vio.c index aed99e72d54..e2a3b9dcf50 100644 --- a/vio/vio.c +++ b/vio/vio.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2012, Monty Program Ab This program is free software; you can redistribute it and/or modify @@ -23,24 +23,26 @@ #include "vio_priv.h" -#if defined(__WIN__) || defined(HAVE_SMEM) +#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 @@ -73,8 +75,8 @@ int vio_pipe_shutdown(Vio *vio, int how) * 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)); @@ -82,11 +84,12 @@ static void vio_init(Vio* vio, enum enum_vio_type type, #ifndef HAVE_VIO_READ_BUFF flags&= ~VIO_BUFFERED_READ; #endif - bzero((char*) vio, sizeof(*vio)); - vio->type = type; - vio->sd = sd; - vio->hPipe = hPipe; + memset(vio, 0, sizeof(*vio)); + vio->type= type; + vio->mysql_socket= MYSQL_INVALID_SOCKET; + mysql_socket_setfd(&vio->mysql_socket, sd); 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; @@ -100,26 +103,17 @@ static void vio_init(Vio* vio, enum enum_vio_type type, 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->shutdown =vio_pipe_shutdown; - - 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; @@ -129,26 +123,17 @@ static void vio_init(Vio* vio, enum enum_vio_type type, 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 =vio_shared_memory_has_data; vio->shutdown =vio_shared_memory_shutdown; - - /* 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; @@ -158,16 +143,14 @@ static void vio_init(Vio* vio, enum enum_vio_type type, 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->shutdown =vio_socket_shutdown; + vio->timeout =vio_socket_timeout; DBUG_VOID_RETURN; } #endif /* HAVE_OPENSSL */ @@ -178,77 +161,107 @@ static void vio_init(Vio* vio, enum enum_vio_type type, 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->shutdown =vio_socket_shutdown; - vio->has_data= (flags & VIO_BUFFERED_READ) ? - vio_buff_has_data : has_no_data; + 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 */ +/** + Reinitialize an existing Vio object. + + @remark Used to rebind an initialized socket-based Vio object + to another socket-based transport type. For example, + rebind a TCP/IP transport to SSL. + + @param vio A VIO object. + @param type A socket-based transport type. + @param sd The socket. + @param ssl An optional SSL structure. + @param flags Flags passed to vio_init. -void vio_reset(Vio* vio, enum enum_vio_type type, - my_socket sd, HANDLE hPipe, uint flags) + @return Return value is zero on success. +*/ + +my_bool vio_reset(Vio* vio, enum enum_vio_type type, + my_socket sd, void *ssl __attribute__((unused)), uint flags) { + int ret= FALSE; + Vio old_vio= *vio; + DBUG_ENTER("vio_reset"); + + /* The only supported rebind is from a socket-based transport type. */ + DBUG_ASSERT(vio->type == VIO_TYPE_TCPIP || vio->type == VIO_TYPE_SOCKET); + + /* + Will be reinitialized depending on the flags. + Nonetheless, already buffered inside the SSL layer. + */ my_free(vio->read_buffer); - vio_init(vio, type, sd, hPipe, flags); + + vio_init(vio, type, sd, flags); + + /* Preserve perfschema info for this connection */ + vio->mysql_socket.m_psi= old_vio.mysql_socket.m_psi; + +#ifdef HAVE_OPENSSL + vio->ssl_arg= ssl; +#endif + + /* + Propagate the timeout values. Necessary to also propagate + the underlying proprieties associated with the timeout, + such as the socket blocking mode. + */ + if (old_vio.read_timeout >= 0) + ret|= vio_timeout(vio, 0, old_vio.read_timeout); + + if (old_vio.write_timeout >= 0) + ret|= vio_timeout(vio, 1, old_vio.write_timeout); + + DBUG_RETURN(test(ret)); } -/* Open the socket or TCP/IP connection and read the fnctl() status */ +/* Create a new VIO for socket or TCP/IP connection. */ -Vio *vio_new(my_socket sd, enum enum_vio_type type, uint flags) +Vio *mysql_socket_vio_new(MYSQL_SOCKET mysql_socket, enum enum_vio_type type, uint flags) { Vio *vio; - DBUG_ENTER("vio_new"); + my_socket sd= mysql_socket_getfd(mysql_socket); + DBUG_ENTER("mysql_socket_vio_new"); DBUG_PRINT("enter", ("sd: %d", sd)); if ((vio = (Vio*) my_malloc(sizeof(*vio),MYF(MY_WME)))) { - vio_init(vio, type, sd, 0, flags); - 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 + vio_init(vio, type, sd, flags); + vio->mysql_socket= mysql_socket; } DBUG_RETURN(vio); } +/* Open the socket or TCP/IP connection and read the fnctl() status */ + +Vio *vio_new(my_socket sd, enum enum_vio_type type, uint flags) +{ + Vio *vio; + MYSQL_SOCKET mysql_socket= MYSQL_INVALID_SOCKET; + DBUG_ENTER("vio_new"); + DBUG_PRINT("enter", ("sd: %d", sd)); + + mysql_socket_setfd(&mysql_socket, sd); + vio = mysql_socket_vio_new(mysql_socket, type, flags); -#ifdef __WIN__ + DBUG_RETURN(vio); +} + +#ifdef _WIN32 Vio *vio_new_win32pipe(HANDLE hPipe) { @@ -256,7 +269,15 @@ 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); + /* Create an object for event notification. */ + vio->overlapped.hEvent= CreateEvent(NULL, FALSE, FALSE, NULL); + if (vio->overlapped.hEvent == NULL) + { + my_free(vio); + DBUG_RETURN(NULL); + } + vio->hPipe= hPipe; strmov(vio->desc, "named pipe"); } DBUG_RETURN(vio); @@ -272,7 +293,7 @@ Vio *vio_new_win32shared_memory(HANDLE handle_file_map, HANDLE handle_map, 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; @@ -290,6 +311,49 @@ Vio *vio_new_win32shared_memory(HANDLE handle_file_map, HANDLE handle_map, #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 FALSE on success, TRUE otherwise. +*/ + +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. Might change the blocking mode. */ + return vio->timeout ? vio->timeout(vio, which, old_mode) : 0; +} + + void vio_delete(Vio* vio) { if (!vio) |