1 | /* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. |
2 | Copyright (c) 2012, Monty Program Ab |
3 | |
4 | This program is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by |
6 | the Free Software Foundation; version 2 of the License. |
7 | |
8 | This program is distributed in the hope that it will be useful, |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | GNU General Public License for more details. |
12 | |
13 | You should have received a copy of the GNU General Public License |
14 | along with this program; if not, write to the Free Software |
15 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
16 | |
17 | /* |
18 | Note that we can't have assertion on file descriptors; The reason for |
19 | this is that during mysql shutdown, another thread can close a file |
20 | we are working on. In this case we should just return read errors from |
21 | the file descriptior. |
22 | */ |
23 | |
24 | #include "vio_priv.h" |
25 | #include "ssl_compat.h" |
26 | |
27 | #ifdef _WIN32 |
28 | |
29 | /** |
30 | Stub io_wait method that defaults to indicate that |
31 | requested I/O event is ready. |
32 | |
33 | Used for named pipe and shared memory VIO types. |
34 | |
35 | @param vio Unused. |
36 | @param event Unused. |
37 | @param timeout Unused. |
38 | |
39 | @retval 1 The requested I/O event has occurred. |
40 | */ |
41 | |
42 | static int no_io_wait(Vio *vio __attribute__((unused)), |
43 | enum enum_vio_io_event event __attribute__((unused)), |
44 | int timeout __attribute__((unused))) |
45 | { |
46 | return 1; |
47 | } |
48 | |
49 | #endif |
50 | |
51 | static my_bool has_no_data(Vio *vio __attribute__((unused))) |
52 | { |
53 | return FALSE; |
54 | } |
55 | |
56 | #ifdef _WIN32 |
57 | my_bool vio_shared_memory_has_data(Vio *vio) |
58 | { |
59 | return (vio->shared_memory_remain > 0); |
60 | } |
61 | |
62 | int vio_shared_memory_shutdown(Vio *vio, int how) |
63 | { |
64 | SetEvent(vio->event_conn_closed); |
65 | SetEvent(vio->event_server_wrote); |
66 | return 0; |
67 | } |
68 | |
69 | int vio_pipe_shutdown(Vio *vio, int how) |
70 | { |
71 | return CancelIoEx(vio->hPipe, NULL); |
72 | } |
73 | #endif |
74 | |
75 | /* |
76 | * Helper to fill most of the Vio* with defaults. |
77 | */ |
78 | |
79 | static void vio_init(Vio *vio, enum enum_vio_type type, |
80 | my_socket sd, uint flags) |
81 | { |
82 | DBUG_ENTER("vio_init" ); |
83 | DBUG_PRINT("enter" , ("type: %d sd: %d flags: %d" , type, (int)sd, flags)); |
84 | |
85 | #ifndef HAVE_VIO_READ_BUFF |
86 | flags&= ~VIO_BUFFERED_READ; |
87 | #endif |
88 | memset(vio, 0, sizeof(*vio)); |
89 | vio->type= type; |
90 | vio->mysql_socket= MYSQL_INVALID_SOCKET; |
91 | mysql_socket_setfd(&vio->mysql_socket, sd); |
92 | vio->localhost= flags & VIO_LOCALHOST; |
93 | vio->read_timeout= vio->write_timeout= -1; |
94 | if ((flags & VIO_BUFFERED_READ) && |
95 | !(vio->read_buffer= (char*)my_malloc(VIO_READ_BUFFER_SIZE, MYF(MY_WME)))) |
96 | flags&= ~VIO_BUFFERED_READ; |
97 | #ifdef _WIN32 |
98 | if (type == VIO_TYPE_NAMEDPIPE) |
99 | { |
100 | vio->viodelete =vio_delete; |
101 | vio->vioerrno =vio_errno; |
102 | vio->read =vio_read_pipe; |
103 | vio->write =vio_write_pipe; |
104 | vio->fastsend =vio_fastsend; |
105 | vio->viokeepalive =vio_keepalive; |
106 | vio->should_retry =vio_should_retry; |
107 | vio->was_timeout =vio_was_timeout; |
108 | vio->vioclose =vio_close_pipe; |
109 | vio->peer_addr =vio_peer_addr; |
110 | vio->vioblocking =vio_blocking; |
111 | vio->is_blocking =vio_is_blocking; |
112 | vio->io_wait =no_io_wait; |
113 | vio->is_connected =vio_is_connected_pipe; |
114 | vio->has_data =has_no_data; |
115 | vio->shutdown =vio_pipe_shutdown; |
116 | DBUG_VOID_RETURN; |
117 | } |
118 | #endif |
119 | #ifdef HAVE_SMEM |
120 | if (type == VIO_TYPE_SHARED_MEMORY) |
121 | { |
122 | vio->viodelete =vio_delete; |
123 | vio->vioerrno =vio_errno; |
124 | vio->read =vio_read_shared_memory; |
125 | vio->write =vio_write_shared_memory; |
126 | vio->fastsend =vio_fastsend; |
127 | vio->viokeepalive =vio_keepalive; |
128 | vio->should_retry =vio_should_retry; |
129 | vio->was_timeout =vio_was_timeout; |
130 | vio->vioclose =vio_close_shared_memory; |
131 | vio->peer_addr =vio_peer_addr; |
132 | vio->vioblocking =vio_blocking; |
133 | vio->is_blocking =vio_is_blocking; |
134 | vio->io_wait =no_io_wait; |
135 | vio->is_connected =vio_is_connected_shared_memory; |
136 | vio->has_data =vio_shared_memory_has_data; |
137 | vio->shutdown =vio_shared_memory_shutdown; |
138 | DBUG_VOID_RETURN; |
139 | } |
140 | #endif |
141 | #ifdef HAVE_OPENSSL |
142 | if (type == VIO_TYPE_SSL) |
143 | { |
144 | vio->viodelete =vio_ssl_delete; |
145 | vio->vioerrno =vio_errno; |
146 | vio->read =vio_ssl_read; |
147 | vio->write =vio_ssl_write; |
148 | vio->fastsend =vio_fastsend; |
149 | vio->viokeepalive =vio_keepalive; |
150 | vio->should_retry =vio_should_retry; |
151 | vio->was_timeout =vio_was_timeout; |
152 | vio->vioclose =vio_ssl_close; |
153 | vio->peer_addr =vio_peer_addr; |
154 | vio->vioblocking =vio_ssl_blocking; |
155 | vio->is_blocking =vio_is_blocking; |
156 | vio->io_wait =vio_io_wait; |
157 | vio->is_connected =vio_is_connected; |
158 | vio->has_data =vio_ssl_has_data; |
159 | vio->shutdown =vio_socket_shutdown; |
160 | vio->timeout =vio_socket_timeout; |
161 | DBUG_VOID_RETURN; |
162 | } |
163 | #endif /* HAVE_OPENSSL */ |
164 | vio->viodelete =vio_delete; |
165 | vio->vioerrno =vio_errno; |
166 | vio->read= (flags & VIO_BUFFERED_READ) ? vio_read_buff : vio_read; |
167 | vio->write =vio_write; |
168 | vio->fastsend =vio_fastsend; |
169 | vio->viokeepalive =vio_keepalive; |
170 | vio->should_retry =vio_should_retry; |
171 | vio->was_timeout =vio_was_timeout; |
172 | vio->vioclose =vio_close; |
173 | vio->peer_addr =vio_peer_addr; |
174 | vio->vioblocking =vio_blocking; |
175 | vio->is_blocking =vio_is_blocking; |
176 | vio->io_wait =vio_io_wait; |
177 | vio->is_connected =vio_is_connected; |
178 | vio->shutdown =vio_socket_shutdown; |
179 | vio->timeout =vio_socket_timeout; |
180 | vio->has_data = ((flags & VIO_BUFFERED_READ) ? |
181 | vio_buff_has_data : has_no_data); |
182 | DBUG_VOID_RETURN; |
183 | } |
184 | |
185 | |
186 | /** |
187 | Reinitialize an existing Vio object. |
188 | |
189 | @remark Used to rebind an initialized socket-based Vio object |
190 | to another socket-based transport type. For example, |
191 | rebind a TCP/IP transport to SSL. |
192 | |
193 | @param vio A VIO object. |
194 | @param type A socket-based transport type. |
195 | @param sd The socket. |
196 | @param ssl An optional SSL structure. |
197 | @param flags Flags passed to vio_init. |
198 | |
199 | @return Return value is zero on success. |
200 | */ |
201 | |
202 | my_bool vio_reset(Vio* vio, enum enum_vio_type type, |
203 | my_socket sd, void *ssl __attribute__((unused)), uint flags) |
204 | { |
205 | int ret= FALSE; |
206 | Vio old_vio= *vio; |
207 | DBUG_ENTER("vio_reset" ); |
208 | |
209 | /* The only supported rebind is from a socket-based transport type. */ |
210 | DBUG_ASSERT(vio->type == VIO_TYPE_TCPIP || vio->type == VIO_TYPE_SOCKET); |
211 | |
212 | /* |
213 | Will be reinitialized depending on the flags. |
214 | Nonetheless, already buffered inside the SSL layer. |
215 | */ |
216 | my_free(vio->read_buffer); |
217 | |
218 | vio_init(vio, type, sd, flags); |
219 | |
220 | /* Preserve perfschema info for this connection */ |
221 | vio->mysql_socket.m_psi= old_vio.mysql_socket.m_psi; |
222 | |
223 | #ifdef HAVE_OPENSSL |
224 | vio->ssl_arg= ssl; |
225 | #endif |
226 | |
227 | /* |
228 | Propagate the timeout values. Necessary to also propagate |
229 | the underlying proprieties associated with the timeout, |
230 | such as the socket blocking mode. |
231 | |
232 | note: old_vio.read_timeout/old_vio.write_timeout is stored in ms |
233 | but vio_timeout() takes seconds as argument, hence the / 1000 |
234 | */ |
235 | if (old_vio.read_timeout >= 0) |
236 | ret|= vio_timeout(vio, 0, old_vio.read_timeout / 1000); |
237 | |
238 | if (old_vio.write_timeout >= 0) |
239 | ret|= vio_timeout(vio, 1, old_vio.write_timeout / 1000); |
240 | |
241 | DBUG_RETURN(MY_TEST(ret)); |
242 | } |
243 | |
244 | |
245 | /* Create a new VIO for socket or TCP/IP connection. */ |
246 | |
247 | Vio *mysql_socket_vio_new(MYSQL_SOCKET mysql_socket, enum enum_vio_type type, uint flags) |
248 | { |
249 | Vio *vio; |
250 | my_socket sd= mysql_socket_getfd(mysql_socket); |
251 | DBUG_ENTER("mysql_socket_vio_new" ); |
252 | DBUG_PRINT("enter" , ("sd: %d" , (int)sd)); |
253 | if ((vio = (Vio*) my_malloc(sizeof(*vio),MYF(MY_WME)))) |
254 | { |
255 | vio_init(vio, type, sd, flags); |
256 | vio->desc= (vio->type == VIO_TYPE_SOCKET ? "socket" : "TCP/IP" ); |
257 | vio->mysql_socket= mysql_socket; |
258 | } |
259 | DBUG_RETURN(vio); |
260 | } |
261 | |
262 | /* Open the socket or TCP/IP connection and read the fnctl() status */ |
263 | |
264 | Vio *vio_new(my_socket sd, enum enum_vio_type type, uint flags) |
265 | { |
266 | Vio *vio; |
267 | MYSQL_SOCKET mysql_socket= MYSQL_INVALID_SOCKET; |
268 | DBUG_ENTER("vio_new" ); |
269 | DBUG_PRINT("enter" , ("sd: %d" , (int)sd)); |
270 | |
271 | mysql_socket_setfd(&mysql_socket, sd); |
272 | vio = mysql_socket_vio_new(mysql_socket, type, flags); |
273 | |
274 | DBUG_RETURN(vio); |
275 | } |
276 | |
277 | #ifdef _WIN32 |
278 | |
279 | Vio *vio_new_win32pipe(HANDLE hPipe) |
280 | { |
281 | Vio *vio; |
282 | DBUG_ENTER("vio_new_handle" ); |
283 | if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME)))) |
284 | { |
285 | vio_init(vio, VIO_TYPE_NAMEDPIPE, 0, VIO_LOCALHOST); |
286 | vio->desc= "named pipe" ; |
287 | /* Create an object for event notification. */ |
288 | vio->overlapped.hEvent= CreateEvent(NULL, FALSE, FALSE, NULL); |
289 | if (vio->overlapped.hEvent == NULL) |
290 | { |
291 | my_free(vio); |
292 | DBUG_RETURN(NULL); |
293 | } |
294 | vio->hPipe= hPipe; |
295 | } |
296 | DBUG_RETURN(vio); |
297 | } |
298 | |
299 | #ifdef HAVE_SMEM |
300 | Vio *vio_new_win32shared_memory(HANDLE handle_file_map, HANDLE handle_map, |
301 | HANDLE event_server_wrote, HANDLE event_server_read, |
302 | HANDLE event_client_wrote, HANDLE event_client_read, |
303 | HANDLE event_conn_closed) |
304 | { |
305 | Vio *vio; |
306 | DBUG_ENTER("vio_new_win32shared_memory" ); |
307 | if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME)))) |
308 | { |
309 | vio_init(vio, VIO_TYPE_SHARED_MEMORY, 0, VIO_LOCALHOST); |
310 | vio->desc= "shared memory" ; |
311 | vio->handle_file_map= handle_file_map; |
312 | vio->handle_map= handle_map; |
313 | vio->event_server_wrote= event_server_wrote; |
314 | vio->event_server_read= event_server_read; |
315 | vio->event_client_wrote= event_client_wrote; |
316 | vio->event_client_read= event_client_read; |
317 | vio->event_conn_closed= event_conn_closed; |
318 | vio->shared_memory_remain= 0; |
319 | vio->shared_memory_pos= handle_map; |
320 | } |
321 | DBUG_RETURN(vio); |
322 | } |
323 | #endif |
324 | #endif |
325 | |
326 | |
327 | /** |
328 | Set timeout for a network send or receive operation. |
329 | |
330 | @remark A non-infinite timeout causes the socket to be |
331 | set to non-blocking mode. On infinite timeouts, |
332 | the socket is set to blocking mode. |
333 | |
334 | @remark A negative timeout means an infinite timeout. |
335 | |
336 | @param vio A VIO object. |
337 | @param which Whether timeout is for send (1) or receive (0). |
338 | @param timeout Timeout interval in seconds. |
339 | |
340 | @return FALSE on success, TRUE otherwise. |
341 | */ |
342 | |
343 | int vio_timeout(Vio *vio, uint which, int timeout_sec) |
344 | { |
345 | int timeout_ms; |
346 | my_bool old_mode; |
347 | |
348 | /* |
349 | Vio timeouts are measured in milliseconds. Check for a possible |
350 | overflow. In case of overflow, set to infinite. |
351 | */ |
352 | if (timeout_sec > INT_MAX/1000) |
353 | timeout_ms= -1; |
354 | else |
355 | timeout_ms= (int) (timeout_sec * 1000); |
356 | |
357 | /* Deduce the current timeout status mode. */ |
358 | old_mode= vio->write_timeout < 0 && vio->read_timeout < 0; |
359 | |
360 | if (which) |
361 | vio->write_timeout= timeout_ms; |
362 | else |
363 | vio->read_timeout= timeout_ms; |
364 | |
365 | /* VIO-specific timeout handling. Might change the blocking mode. */ |
366 | return vio->timeout ? vio->timeout(vio, which, old_mode) : 0; |
367 | } |
368 | |
369 | |
370 | void vio_delete(Vio* vio) |
371 | { |
372 | if (!vio) |
373 | return; /* It must be safe to delete null pointers. */ |
374 | |
375 | if (vio->type != VIO_CLOSED) |
376 | vio->vioclose(vio); |
377 | my_free(vio->read_buffer); |
378 | my_free(vio); |
379 | } |
380 | |
381 | |
382 | /* |
383 | Cleanup memory allocated by vio or the |
384 | components below it when application finish |
385 | |
386 | */ |
387 | void vio_end(void) |
388 | { |
389 | #ifdef HAVE_YASSL |
390 | yaSSL_CleanUp(); |
391 | #elif defined(HAVE_OPENSSL) |
392 | // This one is needed on the client side |
393 | ERR_remove_state(0); |
394 | ERR_free_strings(); |
395 | EVP_cleanup(); |
396 | CRYPTO_cleanup_all_ex_data(); |
397 | #endif |
398 | } |
399 | |