/* Copyright (c) 2010, 2011, 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_position; HANDLE events[2]; DWORD timeout; DBUG_ENTER("vio_read_shared_memory"); remain_local= size; current_position= 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) { DWORD wait_status; wait_status= WaitForMultipleObjects(array_elements(events), events, FALSE, timeout); /* 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 (wait_status != WAIT_OBJECT_0) { /* If wait_status is WAIT_TIMEOUT, set error code to indicate a timeout error. If vio->event_conn_closed was set, use an EOF condition (return value of zero) to indicate that the operation has been aborted. */ if (wait_status == WAIT_TIMEOUT) SetLastError(SOCKET_ETIMEDOUT); else if (wait_status == (WAIT_OBJECT_0 + 1)) DBUG_RETURN(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_position, vio->shared_memory_pos, length); vio->shared_memory_remain-= length; vio->shared_memory_pos+= length; current_position+= length; remain_local-= length; if (!vio->shared_memory_remain) { if (!SetEvent(vio->event_client_read)) DBUG_RETURN(-1); } } while (remain_local); length= size; 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_position; HANDLE events[2]; DWORD timeout; DBUG_ENTER("vio_write_shared_memory"); remain= size; current_position= 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) { DWORD wait_status; wait_status= WaitForMultipleObjects(array_elements(events), events, FALSE, timeout); if (wait_status != WAIT_OBJECT_0) { /* Set error code to indicate a timeout error or disconnect. */ if (wait_status == WAIT_TIMEOUT) SetLastError(SOCKET_ETIMEDOUT); else SetLastError(ERROR_GRACEFUL_DISCONNECT); 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_position, sz); remain-= sz; current_position+= sz; if (!SetEvent(vio->event_client_wrote)) DBUG_RETURN((size_t) -1); } length= size; 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->mysql_socket= MYSQL_INVALID_SOCKET; DBUG_RETURN(error_count); } #endif /* #if defined(_WIN32) && defined(HAVE_SMEM) */