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 | |
20 | size_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 | |
99 | size_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 | |
150 | my_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 | */ |
160 | int 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 | |