1 /* Copyright (c) 2000, 2021, Oracle and/or its affiliates.
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, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 Without limiting anything contained in the foregoing, this file,
15 which is part of C Driver for MySQL (Connector/C), is also subject to the
16 Universal FOSS Exception, version 1.0, a copy of which can be found at
17 http://oss.oracle.com/licenses/universal-foss-exception.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License, version 2.0, for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
27
28 /*
29 Note that we can't have assertion on file descriptors; The reason for
30 this is that during mysql shutdown, another thread can close a file
31 we are working on. In this case we should just return read errors from
32 the file descriptior.
33 */
34
35 #include "vio_priv.h"
36
37 #ifdef HAVE_OPENSSL
38 PSI_memory_key key_memory_vio_ssl_fd;
39 #endif
40
41 PSI_memory_key key_memory_vio;
42 PSI_memory_key key_memory_vio_read_buffer;
43 PSI_memory_key key_memory_vio_proxy_networks;
44
45 #ifdef HAVE_PSI_INTERFACE
46 static PSI_memory_info all_vio_memory[]=
47 {
48 #ifdef HAVE_OPENSSL
49 {&key_memory_vio_ssl_fd, "ssl_fd", 0},
50 #endif
51
52 {&key_memory_vio, "vio", 0},
53 {&key_memory_vio_read_buffer, "read_buffer", 0},
54 {&key_memory_vio_proxy_networks, "proxy_networks", 0},
55 };
56
init_vio_psi_keys()57 void init_vio_psi_keys()
58 {
59 const char* category= "vio";
60 int count;
61
62 count= array_elements(all_vio_memory);
63 mysql_memory_register(category, all_vio_memory, count);
64 }
65 #endif
66
67 #ifdef _WIN32
68
69 /**
70 Stub io_wait method that defaults to indicate that
71 requested I/O event is ready.
72
73 Used for named pipe and shared memory VIO types.
74
75 @param vio Unused.
76 @param event Unused.
77 @param timeout Unused.
78
79 @retval 1 The requested I/O event has occurred.
80 */
81
no_io_wait(Vio * vio MY_ATTRIBUTE ((unused)),enum enum_vio_io_event event MY_ATTRIBUTE ((unused)),int timeout MY_ATTRIBUTE ((unused)))82 static int no_io_wait(Vio *vio MY_ATTRIBUTE((unused)),
83 enum enum_vio_io_event event MY_ATTRIBUTE((unused)),
84 int timeout MY_ATTRIBUTE((unused)))
85 {
86 return 1;
87 }
88
89 #endif
90
has_no_data(Vio * vio MY_ATTRIBUTE ((unused)))91 static my_bool has_no_data(Vio *vio MY_ATTRIBUTE((unused)))
92 {
93 return FALSE;
94 }
95
96 #ifdef _WIN32
vio_shared_memory_has_data(Vio * vio)97 my_bool vio_shared_memory_has_data(Vio *vio)
98 {
99 return (vio->shared_memory_remain > 0);
100 }
101 #endif
102
103 /*
104 * Helper to fill most of the Vio* with defaults.
105 */
106
vio_init(Vio * vio,enum enum_vio_type type,my_socket sd,uint flags)107 static void vio_init(Vio *vio, enum enum_vio_type type,
108 my_socket sd, uint flags)
109 {
110 DBUG_ENTER("vio_init");
111 DBUG_PRINT("enter", ("type: %d sd: %d flags: %d", type, sd, flags));
112
113 memset(vio, 0, sizeof(*vio));
114 vio->type= type;
115 vio->mysql_socket= MYSQL_INVALID_SOCKET;
116 vio->force_skip_proxy= FALSE;
117 mysql_socket_setfd(&vio->mysql_socket, sd);
118 vio->localhost= flags & VIO_LOCALHOST;
119 vio->read_timeout= vio->write_timeout= -1;
120 if ((flags & VIO_BUFFERED_READ) &&
121 !(vio->read_buffer= (char*)my_malloc(key_memory_vio_read_buffer,
122 VIO_READ_BUFFER_SIZE, MYF(MY_WME))))
123 flags&= ~VIO_BUFFERED_READ;
124 #ifdef _WIN32
125 if (type == VIO_TYPE_NAMEDPIPE)
126 {
127 vio->viodelete =vio_delete;
128 vio->vioerrno =vio_errno;
129 vio->read =vio_read_pipe;
130 vio->write =vio_write_pipe;
131 vio->fastsend =vio_fastsend;
132 vio->viokeepalive =vio_keepalive;
133 vio->should_retry =vio_should_retry;
134 vio->was_timeout =vio_was_timeout;
135 vio->vioshutdown =vio_shutdown_pipe;
136 vio->viocancel =vio_cancel_pipe;
137 vio->peer_addr =vio_peer_addr;
138 vio->io_wait =no_io_wait;
139 vio->is_connected =vio_is_connected_pipe;
140 vio->has_data =has_no_data;
141 DBUG_VOID_RETURN;
142 }
143 #ifndef EMBEDDED_LIBRARY
144 if (type == VIO_TYPE_SHARED_MEMORY)
145 {
146 vio->viodelete =vio_delete_shared_memory;
147 vio->vioerrno =vio_errno;
148 vio->read =vio_read_shared_memory;
149 vio->write =vio_write_shared_memory;
150 vio->fastsend =vio_fastsend;
151 vio->viokeepalive =vio_keepalive;
152 vio->should_retry =vio_should_retry;
153 vio->was_timeout =vio_was_timeout;
154 vio->vioshutdown =vio_shutdown_shared_memory;
155 vio->viocancel =vio_cancel_shared_memory;
156 vio->peer_addr =vio_peer_addr;
157 vio->io_wait =no_io_wait;
158 vio->is_connected =vio_is_connected_shared_memory;
159 vio->has_data =vio_shared_memory_has_data;
160 DBUG_VOID_RETURN;
161 }
162 #endif /* !EMBEDDED_LIBRARY */
163 #endif /* _WIN32 */
164 #ifdef HAVE_OPENSSL
165 if (type == VIO_TYPE_SSL)
166 {
167 vio->viodelete =vio_ssl_delete;
168 vio->vioerrno =vio_errno;
169 vio->read =vio_ssl_read;
170 vio->write =vio_ssl_write;
171 vio->fastsend =vio_fastsend;
172 vio->viokeepalive =vio_keepalive;
173 vio->should_retry =vio_should_retry;
174 vio->was_timeout =vio_was_timeout;
175 vio->vioshutdown =vio_ssl_shutdown;
176 vio->viocancel =vio_cancel;
177 vio->peer_addr =vio_peer_addr;
178 vio->io_wait =vio_io_wait;
179 vio->is_connected =vio_is_connected;
180 vio->has_data =vio_ssl_has_data;
181 vio->timeout =vio_socket_timeout;
182 DBUG_VOID_RETURN;
183 }
184 #endif /* HAVE_OPENSSL */
185 vio->viodelete =vio_delete;
186 vio->vioerrno =vio_errno;
187 vio->read= (flags & VIO_BUFFERED_READ) ? vio_read_buff : vio_read;
188 vio->write =vio_write;
189 vio->fastsend =vio_fastsend;
190 vio->viokeepalive =vio_keepalive;
191 vio->should_retry =vio_should_retry;
192 vio->was_timeout =vio_was_timeout;
193 vio->vioshutdown =vio_shutdown;
194 vio->viocancel =vio_cancel;
195 vio->peer_addr =vio_peer_addr;
196 vio->io_wait =vio_io_wait;
197 vio->is_connected =vio_is_connected;
198 vio->timeout =vio_socket_timeout;
199 vio->has_data= (flags & VIO_BUFFERED_READ) ?
200 vio_buff_has_data : has_no_data;
201 DBUG_VOID_RETURN;
202 }
203
204
205 /**
206 Reinitialize an existing Vio object.
207
208 @remark Used to rebind an initialized socket-based Vio object
209 to another socket-based transport type. For example,
210 rebind a TCP/IP transport to SSL.
211
212 @remark If new socket handle passed to vio_reset() is not equal
213 to the socket handle stored in Vio then socket handle will
214 be closed before storing new value. If handles are equal
215 then old socket is not closed. This is important for
216 vio_reset() usage in ssl_do().
217
218 @remark If any error occurs then Vio members won't be altered thus
219 preserving socket handle stored in Vio and not taking
220 ownership over socket handle passed as parameter.
221
222 @param vio A VIO object.
223 @param type A socket-based transport type.
224 @param sd The socket.
225 @param ssl An optional SSL structure.
226 @param flags Flags passed to vio_init.
227
228 @return Return value is zero on success.
229 */
230
vio_reset(Vio * vio,enum enum_vio_type type,my_socket sd,void * ssl MY_ATTRIBUTE ((unused)),uint flags)231 my_bool vio_reset(Vio* vio, enum enum_vio_type type,
232 my_socket sd, void *ssl MY_ATTRIBUTE((unused)), uint flags)
233 {
234 int ret= FALSE;
235 Vio new_vio;
236 DBUG_ENTER("vio_reset");
237
238 /* The only supported rebind is from a socket-based transport type. */
239 assert(vio->type == VIO_TYPE_TCPIP || vio->type == VIO_TYPE_SOCKET);
240
241 vio_init(&new_vio, type, sd, flags);
242
243 /* Preserve perfschema info for this connection */
244 new_vio.mysql_socket.m_psi= vio->mysql_socket.m_psi;
245
246 #ifdef HAVE_OPENSSL
247 new_vio.ssl_arg= ssl;
248 #endif
249
250 /*
251 Propagate the timeout values. Necessary to also propagate
252 the underlying proprieties associated with the timeout,
253 such as the socket blocking mode.
254 */
255 if (vio->read_timeout >= 0)
256 ret|= vio_timeout(&new_vio, 0, vio->read_timeout / 1000);
257
258 if (vio->write_timeout >= 0)
259 ret|= vio_timeout(&new_vio, 1, vio->write_timeout / 1000);
260
261 if (ret)
262 {
263 /*
264 vio_reset() failed
265 free resources allocated by vio_init
266 */
267 my_free(new_vio.read_buffer);
268 }
269 else
270 {
271 /*
272 vio_reset() succeeded
273 free old resources and then overwrite VIO structure
274 */
275
276 /*
277 Close socket only when it is not equal to the new one.
278 */
279 if (sd != mysql_socket_getfd(vio->mysql_socket))
280 if (vio->inactive == FALSE)
281 vio->vioshutdown(vio, SHUT_RDWR);
282
283 my_free(vio->read_buffer);
284
285 *vio= new_vio;
286 }
287
288 DBUG_RETURN(MY_TEST(ret));
289 }
290
291
292 /* Create a new VIO for socket or TCP/IP connection. */
293
mysql_socket_vio_new(MYSQL_SOCKET mysql_socket,enum enum_vio_type type,uint flags)294 Vio *mysql_socket_vio_new(MYSQL_SOCKET mysql_socket, enum enum_vio_type type, uint flags)
295 {
296 Vio *vio;
297 my_socket sd= mysql_socket_getfd(mysql_socket);
298 DBUG_ENTER("mysql_socket_vio_new");
299 DBUG_PRINT("enter", ("sd: %d", sd));
300 if ((vio = (Vio*) my_malloc(key_memory_vio,
301 sizeof(*vio),MYF(MY_WME))))
302 {
303 vio_init(vio, type, sd, flags);
304 vio->mysql_socket= mysql_socket;
305 }
306 DBUG_RETURN(vio);
307 }
308
309 /* Open the socket or TCP/IP connection and read the fnctl() status */
310
vio_new(my_socket sd,enum enum_vio_type type,uint flags)311 Vio *vio_new(my_socket sd, enum enum_vio_type type, uint flags)
312 {
313 Vio *vio;
314 MYSQL_SOCKET mysql_socket= MYSQL_INVALID_SOCKET;
315 DBUG_ENTER("vio_new");
316 DBUG_PRINT("enter", ("sd: %d", sd));
317
318 mysql_socket_setfd(&mysql_socket, sd);
319 vio = mysql_socket_vio_new(mysql_socket, type, flags);
320
321 DBUG_RETURN(vio);
322 }
323
324 #ifdef _WIN32
325
vio_new_win32pipe(HANDLE hPipe)326 Vio *vio_new_win32pipe(HANDLE hPipe)
327 {
328 Vio *vio;
329 DBUG_ENTER("vio_new_handle");
330 if ((vio = (Vio*) my_malloc(key_memory_vio,
331 sizeof(Vio),MYF(MY_WME))))
332 {
333 vio_init(vio, VIO_TYPE_NAMEDPIPE, 0, VIO_LOCALHOST);
334 /* Create an object for event notification. */
335 vio->overlapped.hEvent= CreateEvent(NULL, FALSE, FALSE, NULL);
336 if (vio->overlapped.hEvent == NULL)
337 {
338 my_free(vio);
339 DBUG_RETURN(NULL);
340 }
341 vio->hPipe= hPipe;
342 my_stpcpy(vio->desc, "named pipe");
343 }
344 DBUG_RETURN(vio);
345 }
346
347 #ifndef EMBEDDED_LIBRARY
vio_new_win32shared_memory(HANDLE handle_file_map,HANDLE handle_map,HANDLE event_server_wrote,HANDLE event_server_read,HANDLE event_client_wrote,HANDLE event_client_read,HANDLE event_conn_closed)348 Vio *vio_new_win32shared_memory(HANDLE handle_file_map, HANDLE handle_map,
349 HANDLE event_server_wrote, HANDLE event_server_read,
350 HANDLE event_client_wrote, HANDLE event_client_read,
351 HANDLE event_conn_closed)
352 {
353 Vio *vio;
354 DBUG_ENTER("vio_new_win32shared_memory");
355 if ((vio = (Vio*) my_malloc(key_memory_vio,
356 sizeof(Vio),MYF(MY_WME))))
357 {
358 vio_init(vio, VIO_TYPE_SHARED_MEMORY, 0, VIO_LOCALHOST);
359 vio->handle_file_map= handle_file_map;
360 vio->handle_map= handle_map;
361 vio->event_server_wrote= event_server_wrote;
362 vio->event_server_read= event_server_read;
363 vio->event_client_wrote= event_client_wrote;
364 vio->event_client_read= event_client_read;
365 vio->event_conn_closed= event_conn_closed;
366 vio->shared_memory_remain= 0;
367 vio->shared_memory_pos= handle_map;
368 my_stpcpy(vio->desc, "shared memory");
369 }
370 DBUG_RETURN(vio);
371 }
372 #endif
373 #endif
374
375
376 /**
377 Set timeout for a network send or receive operation.
378
379 @remark A non-infinite timeout causes the socket to be
380 set to non-blocking mode. On infinite timeouts,
381 the socket is set to blocking mode.
382
383 @remark A negative timeout means an infinite timeout.
384
385 @param vio A VIO object.
386 @param which Whether timeout is for send (1) or receive (0).
387 @param timeout Timeout interval in seconds.
388
389 @return FALSE on success, TRUE otherwise.
390 */
391
vio_timeout(Vio * vio,uint which,int timeout_sec)392 int vio_timeout(Vio *vio, uint which, int timeout_sec)
393 {
394 int timeout_ms;
395 my_bool old_mode;
396
397 /*
398 Vio timeouts are measured in milliseconds. Check for a possible
399 overflow. In case of overflow, set to infinite.
400 */
401 if (timeout_sec > INT_MAX/1000)
402 timeout_ms= -1;
403 else
404 timeout_ms= (int) (timeout_sec * 1000);
405
406 /* Deduce the current timeout status mode. */
407 old_mode= vio->write_timeout < 0 && vio->read_timeout < 0;
408
409 if (which)
410 vio->write_timeout= timeout_ms;
411 else
412 vio->read_timeout= timeout_ms;
413
414 /* VIO-specific timeout handling. Might change the blocking mode. */
415 return vio->timeout ? vio->timeout(vio, which, old_mode) : 0;
416 }
417
418
vio_delete(Vio * vio)419 void vio_delete(Vio* vio)
420 {
421 if (!vio)
422 return; /* It must be safe to delete null pointers. */
423
424 if (vio->inactive == FALSE)
425 vio->vioshutdown(vio, SHUT_RDWR);
426 my_free(vio->read_buffer);
427 my_free(vio);
428 }
429
430
431 /*
432 Cleanup memory allocated by vio or the
433 components below it when application finish
434
435 */
vio_end(void)436 void vio_end(void)
437 {
438 #if defined(HAVE_OPENSSL)
439 vio_ssl_end();
440 #endif
441 vio_proxy_cleanup();
442 }
443
444 struct vio_string
445 {
446 const char * m_str;
447 int m_len;
448 };
449 typedef struct vio_string vio_string;
450
451 /**
452 Names for each VIO TYPE.
453 Indexed by enum_vio_type.
454 If you add more, please update audit_log.cc
455 */
456 static const vio_string vio_type_names[] =
457 {
458 { "", 0},
459 { C_STRING_WITH_LEN("TCP/IP") },
460 { C_STRING_WITH_LEN("Socket") },
461 { C_STRING_WITH_LEN("Named Pipe") },
462 { C_STRING_WITH_LEN("SSL/TLS") },
463 { C_STRING_WITH_LEN("Shared Memory") },
464 { C_STRING_WITH_LEN("Internal") },
465 { C_STRING_WITH_LEN("Plugin") }
466 };
467
get_vio_type_name(enum enum_vio_type vio_type,const char ** str,int * len)468 void get_vio_type_name(enum enum_vio_type vio_type, const char ** str, int * len)
469 {
470 int index;
471
472 if ((vio_type >= FIRST_VIO_TYPE) && (vio_type <= LAST_VIO_TYPE))
473 {
474 index= vio_type;
475 }
476 else
477 {
478 index= 0;
479 }
480 *str= vio_type_names[index].m_str;
481 *len= vio_type_names[index].m_len;
482 return;
483 }
484
485