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