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
42static 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
51static my_bool has_no_data(Vio *vio __attribute__((unused)))
52{
53 return FALSE;
54}
55
56#ifdef _WIN32
57my_bool vio_shared_memory_has_data(Vio *vio)
58{
59 return (vio->shared_memory_remain > 0);
60}
61
62int 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
69int 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
79static 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
202my_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
247Vio *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
264Vio *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
279Vio *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
300Vio *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
343int 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
370void 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*/
387void 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