1/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#include "vio_priv.h"
17
18#if defined(_WIN32) && defined(HAVE_SMEM)
19
20size_t vio_read_shared_memory(Vio *vio, uchar *buf, size_t size)
21{
22 size_t length;
23 size_t remain_local;
24 char *current_position;
25 HANDLE events[2];
26 DWORD timeout;
27 DBUG_ENTER("vio_read_shared_memory");
28
29 remain_local= size;
30 current_position= buf;
31 timeout= vio->read_timeout >= 0 ? vio->read_timeout : INFINITE;
32
33 events[0]= vio->event_server_wrote;
34 events[1]= vio->event_conn_closed;
35
36 do
37 {
38 if (vio->shared_memory_remain == 0)
39 {
40 DWORD wait_status;
41
42 wait_status= WaitForMultipleObjects(array_elements(events), events,
43 FALSE, timeout);
44
45 /*
46 WaitForMultipleObjects can return next values:
47 WAIT_OBJECT_0+0 - event from vio->event_server_wrote
48 WAIT_OBJECT_0+1 - event from vio->event_conn_closed.
49 We can't read anything
50 WAIT_ABANDONED_0 and WAIT_TIMEOUT - fail. We can't read anything
51 */
52 if (wait_status != WAIT_OBJECT_0)
53 {
54 /*
55 If wait_status is WAIT_TIMEOUT, set error code to indicate a
56 timeout error. If vio->event_conn_closed was set, use an EOF
57 condition (return value of zero) to indicate that the operation
58 has been aborted.
59 */
60 if (wait_status == WAIT_TIMEOUT)
61 SetLastError(SOCKET_ETIMEDOUT);
62 else if (wait_status == (WAIT_OBJECT_0 + 1))
63 DBUG_RETURN(0);
64
65 DBUG_RETURN(-1);
66 }
67
68 vio->shared_memory_pos= vio->handle_map;
69 vio->shared_memory_remain= uint4korr((ulong*)vio->shared_memory_pos);
70 vio->shared_memory_pos+= 4;
71 }
72
73 length= size;
74
75 if (vio->shared_memory_remain < length)
76 length= vio->shared_memory_remain;
77 if (length > remain_local)
78 length= remain_local;
79
80 memcpy(current_position, vio->shared_memory_pos, length);
81
82 vio->shared_memory_remain-= length;
83 vio->shared_memory_pos+= length;
84 current_position+= length;
85 remain_local-= length;
86
87 if (!vio->shared_memory_remain)
88 {
89 if (!SetEvent(vio->event_client_read))
90 DBUG_RETURN(-1);
91 }
92 } while (remain_local);
93 length= size;
94
95 DBUG_RETURN(length);
96}
97
98
99size_t vio_write_shared_memory(Vio *vio, const uchar *buf, size_t size)
100{
101 size_t length, remain, sz;
102 HANDLE pos;
103 const uchar *current_position;
104 HANDLE events[2];
105 DWORD timeout;
106 DBUG_ENTER("vio_write_shared_memory");
107
108 remain= size;
109 current_position= buf;
110 timeout= vio->write_timeout >= 0 ? vio->write_timeout : INFINITE;
111
112 events[0]= vio->event_server_read;
113 events[1]= vio->event_conn_closed;
114
115 while (remain != 0)
116 {
117 DWORD wait_status;
118
119 wait_status= WaitForMultipleObjects(array_elements(events), events,
120 FALSE, timeout);
121
122 if (wait_status != WAIT_OBJECT_0)
123 {
124 /* Set error code to indicate a timeout error or disconnect. */
125 if (wait_status == WAIT_TIMEOUT)
126 SetLastError(SOCKET_ETIMEDOUT);
127 else
128 SetLastError(ERROR_GRACEFUL_DISCONNECT);
129
130 DBUG_RETURN((size_t) -1);
131 }
132
133 sz= (remain > shared_memory_buffer_length ? shared_memory_buffer_length :
134 remain);
135
136 int4store(vio->handle_map, sz);
137 pos= vio->handle_map + 4;
138 memcpy(pos, current_position, sz);
139 remain-= sz;
140 current_position+= sz;
141 if (!SetEvent(vio->event_client_wrote))
142 DBUG_RETURN((size_t) -1);
143 }
144 length= size;
145
146 DBUG_RETURN(length);
147}
148
149
150my_bool vio_is_connected_shared_memory(Vio *vio)
151{
152 return (WaitForSingleObject(vio->event_conn_closed, 0) != WAIT_OBJECT_0);
153}
154
155
156/**
157 Close shared memory and DBUG_PRINT any errors that happen on closing.
158 @return Zero if all closing functions succeed, and nonzero otherwise.
159*/
160int vio_close_shared_memory(Vio * vio)
161{
162 int error_count= 0;
163 DBUG_ENTER("vio_close_shared_memory");
164 if (vio->type != VIO_CLOSED)
165 {
166 /*
167 Set event_conn_closed for notification of both client and server that
168 connection is closed
169 */
170 SetEvent(vio->event_conn_closed);
171 /*
172 Close all handlers. UnmapViewOfFile and CloseHandle return non-zero
173 result if they are success.
174 */
175 if (UnmapViewOfFile(vio->handle_map) == 0)
176 {
177 error_count++;
178 DBUG_PRINT("vio_error", ("UnmapViewOfFile() failed"));
179 }
180 if (CloseHandle(vio->event_server_wrote) == 0)
181 {
182 error_count++;
183 DBUG_PRINT("vio_error", ("CloseHandle(vio->esw) failed"));
184 }
185 if (CloseHandle(vio->event_server_read) == 0)
186 {
187 error_count++;
188 DBUG_PRINT("vio_error", ("CloseHandle(vio->esr) failed"));
189 }
190 if (CloseHandle(vio->event_client_wrote) == 0)
191 {
192 error_count++;
193 DBUG_PRINT("vio_error", ("CloseHandle(vio->ecw) failed"));
194 }
195 if (CloseHandle(vio->event_client_read) == 0)
196 {
197 error_count++;
198 DBUG_PRINT("vio_error", ("CloseHandle(vio->ecr) failed"));
199 }
200 if (CloseHandle(vio->handle_file_map) == 0)
201 {
202 error_count++;
203 DBUG_PRINT("vio_error", ("CloseHandle(vio->hfm) failed"));
204 }
205 if (CloseHandle(vio->event_conn_closed) == 0)
206 {
207 error_count++;
208 DBUG_PRINT("vio_error", ("CloseHandle(vio->ecc) failed"));
209 }
210 }
211 vio->type= VIO_CLOSED;
212 vio->mysql_socket= MYSQL_INVALID_SOCKET;
213 DBUG_RETURN(error_count);
214}
215
216#endif /* #if defined(_WIN32) && defined(HAVE_SMEM) */
217
218