1 /*
2    Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
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, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    Without limiting anything contained in the foregoing, this file,
16    which is part of C Driver for MySQL (Connector/C), is also subject to the
17    Universal FOSS Exception, version 1.0, a copy of which can be found at
18    http://oss.oracle.com/licenses/universal-foss-exception.
19 
20    This program is distributed in the hope that it will be useful,
21    but WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23    GNU General Public License, version 2.0, for more details.
24 
25    You should have received a copy of the GNU General Public License
26    along with this program; if not, write to the Free Software
27    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
28    02110-1301  USA */
29 
30 /*
31   Note that we can't have assertion on file descriptors;  The reason for
32   this is that during mysql shutdown, another thread can close a file
33   we are working on.  In this case we should just return read errors from
34   the file descriptior.
35 */
36 
37 #include "vio_priv.h"
38 
39 #ifdef FIONREAD_IN_SYS_FILIO
40 # include <sys/filio.h>
41 #endif
42 
vio_errno(Vio * vio MY_ATTRIBUTE ((unused)))43 int vio_errno(Vio *vio MY_ATTRIBUTE((unused)))
44 {
45   /* These transport types are not Winsock based. */
46 #ifdef _WIN32
47   if (vio->type == VIO_TYPE_NAMEDPIPE ||
48       vio->type == VIO_TYPE_SHARED_MEMORY)
49     return GetLastError();
50 #endif
51 
52   /* Mapped to WSAGetLastError() on Win32. */
53   return socket_errno;
54 }
55 
56 
57 /**
58   Attempt to wait for an I/O event on a socket.
59 
60   @param vio      VIO object representing a connected socket.
61   @param event    The type of I/O event (read or write) to wait for.
62 
63   @return Return value is -1 on failure, 0 on success.
64 */
65 
vio_socket_io_wait(Vio * vio,enum enum_vio_io_event event)66 int vio_socket_io_wait(Vio *vio, enum enum_vio_io_event event)
67 {
68   int timeout, ret;
69 
70   DBUG_ASSERT(event == VIO_IO_EVENT_READ || event == VIO_IO_EVENT_WRITE);
71 
72   /* Choose an appropriate timeout. */
73   if (event == VIO_IO_EVENT_READ)
74     timeout= vio->read_timeout;
75   else
76     timeout= vio->write_timeout;
77 
78   /* Wait for input data to become available. */
79   switch (vio_io_wait(vio, event, timeout))
80   {
81   case -1:
82     /* Upon failure, vio_read/write() shall return -1. */
83     ret= -1;
84     break;
85   case  0:
86     /* The wait timed out. */
87     ret= -1;
88     break;
89   default:
90     /* A positive value indicates an I/O event. */
91     ret= 0;
92     break;
93   }
94 
95   return ret;
96 }
97 
98 
99 /*
100   Define a stub MSG_DONTWAIT if unavailable. In this case, fcntl
101   (or a equivalent) is used to enable non-blocking operations.
102   The flag must be supported in both send and recv operations.
103 */
104 #if defined(__linux__)
105 #define VIO_USE_DONTWAIT  1
106 #define VIO_DONTWAIT      MSG_DONTWAIT
107 #else
108 #define VIO_DONTWAIT 0
109 #endif
110 
111 
vio_read(Vio * vio,uchar * buf,size_t size)112 size_t vio_read(Vio *vio, uchar *buf, size_t size)
113 {
114   ssize_t ret;
115   int flags= 0;
116   DBUG_ENTER("vio_read");
117 
118   /* Ensure nobody uses vio_read_buff and vio_read simultaneously. */
119   DBUG_ASSERT(vio->read_end == vio->read_pos);
120 
121   /* If timeout is enabled, do not block if data is unavailable. */
122   if (vio->read_timeout >= 0)
123     flags= VIO_DONTWAIT;
124 
125   while ((ret= mysql_socket_recv(vio->mysql_socket, (SOCKBUF_T *)buf, size, flags)) == -1)
126   {
127     int error= socket_errno;
128 
129     /* The operation would block? */
130     if (error != SOCKET_EAGAIN && error != SOCKET_EWOULDBLOCK)
131       break;
132 
133     /* Wait for input data to become available. */
134     if ((ret= vio_socket_io_wait(vio, VIO_IO_EVENT_READ)))
135       break;
136   }
137 
138   DBUG_RETURN(ret);
139 }
140 
141 
142 /*
143   Buffered read: if average read size is small it may
144   reduce number of syscalls.
145 */
146 
vio_read_buff(Vio * vio,uchar * buf,size_t size)147 size_t vio_read_buff(Vio *vio, uchar* buf, size_t size)
148 {
149   size_t rc;
150 #define VIO_UNBUFFERED_READ_MIN_SIZE 2048
151   DBUG_ENTER("vio_read_buff");
152   DBUG_PRINT("enter", ("sd: %d  buf: 0x%lx  size: %u",
153              mysql_socket_getfd(vio->mysql_socket), (long)buf, (uint)size));
154 
155   if (vio->read_pos < vio->read_end)
156   {
157     rc= MY_MIN((size_t) (vio->read_end - vio->read_pos), size);
158     memcpy(buf, vio->read_pos, rc);
159     vio->read_pos+= rc;
160     /*
161       Do not try to read from the socket now even if rc < size:
162       vio_read can return -1 due to an error or non-blocking mode, and
163       the safest way to handle it is to move to a separate branch.
164     */
165   }
166   else if (size < VIO_UNBUFFERED_READ_MIN_SIZE)
167   {
168     rc= vio_read(vio, (uchar*) vio->read_buffer, VIO_READ_BUFFER_SIZE);
169     if (rc != 0 && rc != (size_t) -1)
170     {
171       if (rc > size)
172       {
173         vio->read_pos= vio->read_buffer + size;
174         vio->read_end= vio->read_buffer + rc;
175         rc= size;
176       }
177       memcpy(buf, vio->read_buffer, rc);
178     }
179   }
180   else
181     rc= vio_read(vio, buf, size);
182   DBUG_RETURN(rc);
183 #undef VIO_UNBUFFERED_READ_MIN_SIZE
184 }
185 
186 
vio_buff_has_data(Vio * vio)187 my_bool vio_buff_has_data(Vio *vio)
188 {
189   return (vio->read_pos != vio->read_end);
190 }
191 
192 
vio_write(Vio * vio,const uchar * buf,size_t size)193 size_t vio_write(Vio *vio, const uchar* buf, size_t size)
194 {
195   ssize_t ret;
196   int flags= 0;
197   DBUG_ENTER("vio_write");
198 
199   /* If timeout is enabled, do not block. */
200   if (vio->write_timeout >= 0)
201     flags= VIO_DONTWAIT;
202 
203   while ((ret= mysql_socket_send(vio->mysql_socket, (SOCKBUF_T *)buf, size, flags)) == -1)
204   {
205     int error= socket_errno;
206 
207     /* The operation would block? */
208     if (error != SOCKET_EAGAIN && error != SOCKET_EWOULDBLOCK)
209       break;
210 
211     /* Wait for the output buffer to become writable.*/
212     if ((ret= vio_socket_io_wait(vio, VIO_IO_EVENT_WRITE)))
213       break;
214   }
215 
216   DBUG_RETURN(ret);
217 }
218 
219 //WL#4896: Not covered
vio_set_blocking(Vio * vio,my_bool status)220 static int vio_set_blocking(Vio *vio, my_bool status)
221 {
222   DBUG_ENTER("vio_set_blocking");
223 
224 #ifdef _WIN32
225   DBUG_ASSERT(vio->type != VIO_TYPE_NAMEDPIPE);
226   DBUG_ASSERT(vio->type != VIO_TYPE_SHARED_MEMORY);
227   {
228     int ret;
229     u_long arg= status ? 0 : 1;
230     ret= ioctlsocket(mysql_socket_getfd(vio->mysql_socket), FIONBIO, &arg);
231     DBUG_RETURN(ret);
232   }
233 #else
234   {
235     int flags;
236 
237     if ((flags= fcntl(mysql_socket_getfd(vio->mysql_socket), F_GETFL, NULL)) < 0)
238       DBUG_RETURN(-1);
239 
240     /*
241       Always set/clear the flag to avoid inheritance issues. This is
242       a issue mainly on Mac OS X Tiger (version 10.4) where although
243       the O_NONBLOCK flag is inherited from the parent socket, the
244       actual non-blocking behavior is not inherited.
245     */
246     if (status)
247       flags&= ~O_NONBLOCK;
248     else
249       flags|= O_NONBLOCK;
250 
251     if (fcntl(mysql_socket_getfd(vio->mysql_socket), F_SETFL, flags) == -1)
252       DBUG_RETURN(-1);
253   }
254 #endif
255 
256   DBUG_RETURN(0);
257 }
258 
259 
vio_socket_timeout(Vio * vio,uint which MY_ATTRIBUTE ((unused)),my_bool old_mode MY_ATTRIBUTE ((unused)))260 int vio_socket_timeout(Vio *vio,
261                        uint which MY_ATTRIBUTE((unused)),
262                        my_bool old_mode MY_ATTRIBUTE((unused)))
263 {
264   int ret= 0;
265   DBUG_ENTER("vio_socket_timeout");
266 
267 #if defined(_WIN32)
268   {
269     int optname;
270     DWORD timeout= 0;
271     const char *optval= (const char *) &timeout;
272 
273     /*
274       The default socket timeout value is zero, which means an infinite
275       timeout. Values less than 500 milliseconds are interpreted to be of
276       500 milliseconds. Hence, the VIO behavior for zero timeout, which is
277       intended to cause the send or receive operation to fail immediately
278       if no data is available, is not supported on WIN32 and neither is
279       necessary as it's not possible to set the VIO timeout value to zero.
280 
281       Assert that the VIO timeout is either positive or set to infinite.
282     */
283     DBUG_ASSERT(which || vio->read_timeout);
284     DBUG_ASSERT(!which || vio->write_timeout);
285 
286     if (which)
287     {
288       optname= SO_SNDTIMEO;
289       if (vio->write_timeout > 0)
290         timeout= vio->write_timeout;
291     }
292     else
293     {
294       optname= SO_RCVTIMEO;
295       if (vio->read_timeout > 0)
296         timeout= vio->read_timeout;
297     }
298 
299     ret= mysql_socket_setsockopt(vio->mysql_socket, SOL_SOCKET, optname,
300 	                             optval, sizeof(timeout));
301   }
302 #else
303   /*
304     The MSG_DONTWAIT trick is not used with SSL sockets as the send and
305     receive I/O operations are wrapped through SSL-specific functions
306     (SSL_read and SSL_write) which are not equivalent to the standard
307     recv(2) and send(2) used in vio_read() and vio_write(). Hence, the
308     socket blocking mode is changed and vio_io_wait() is used to wait
309     for I/O or timeout.
310   */
311 #ifdef VIO_USE_DONTWAIT
312   if (vio->type == VIO_TYPE_SSL)
313 #endif
314   {
315     /* Deduce what should be the new blocking mode of the socket. */
316     my_bool new_mode= vio->write_timeout < 0 && vio->read_timeout < 0;
317 
318     /* If necessary, update the blocking mode. */
319     if (new_mode != old_mode)
320       ret= vio_set_blocking(vio, new_mode);
321   }
322 #endif
323 
324   DBUG_RETURN(ret);
325 }
326 
327 
vio_fastsend(Vio * vio MY_ATTRIBUTE ((unused)))328 int vio_fastsend(Vio * vio MY_ATTRIBUTE((unused)))
329 {
330   int r=0;
331   DBUG_ENTER("vio_fastsend");
332 
333 #if defined(IPTOS_THROUGHPUT)
334   {
335     int tos = IPTOS_THROUGHPUT;
336     r= mysql_socket_setsockopt(vio->mysql_socket, IPPROTO_IP, IP_TOS,
337 	                           (void *)&tos, sizeof(tos));
338   }
339 #endif                                    /* IPTOS_THROUGHPUT */
340   if (!r)
341   {
342 #ifdef __WIN__
343     BOOL nodelay= 1;
344 #else
345     int nodelay = 1;
346 #endif
347 
348     r= mysql_socket_setsockopt(vio->mysql_socket, IPPROTO_TCP, TCP_NODELAY,
349                   IF_WIN((const char*), (void*)) &nodelay,
350                   sizeof(nodelay));
351 
352   }
353   if (r)
354   {
355     DBUG_PRINT("warning", ("Couldn't set socket option for fast send"));
356     r= -1;
357   }
358   DBUG_PRINT("exit", ("%d", r));
359   DBUG_RETURN(r);
360 }
361 
vio_keepalive(Vio * vio,my_bool set_keep_alive)362 int vio_keepalive(Vio* vio, my_bool set_keep_alive)
363 {
364   int r=0;
365   uint opt = 0;
366   DBUG_ENTER("vio_keepalive");
367   DBUG_PRINT("enter", ("sd: %d  set_keep_alive: %d",
368              mysql_socket_getfd(vio->mysql_socket), (int)set_keep_alive));
369   if (vio->type != VIO_TYPE_NAMEDPIPE)
370   {
371     if (set_keep_alive)
372       opt = 1;
373     r = mysql_socket_setsockopt(vio->mysql_socket, SOL_SOCKET, SO_KEEPALIVE,
374 	                            (char *)&opt, sizeof(opt));
375   }
376   DBUG_RETURN(r);
377 }
378 
379 
380 /**
381   Indicate whether a I/O operation must be retried later.
382 
383   @param vio  A VIO object
384 
385   @return Whether a I/O operation should be deferred.
386   @retval TRUE    Temporary failure, retry operation.
387   @retval FALSE   Indeterminate failure.
388 */
389 
390 my_bool
vio_should_retry(Vio * vio)391 vio_should_retry(Vio *vio)
392 {
393   return (vio_errno(vio) == SOCKET_EINTR);
394 }
395 
396 
397 /**
398   Indicate whether a I/O operation timed out.
399 
400   @param vio  A VIO object
401 
402   @return Whether a I/O operation timed out.
403   @retval TRUE    Operation timed out.
404   @retval FALSE   Not a timeout failure.
405 */
406 
407 my_bool
vio_was_timeout(Vio * vio)408 vio_was_timeout(Vio *vio)
409 {
410   return (vio_errno(vio) == SOCKET_ETIMEDOUT);
411 }
412 
413 
vio_shutdown(Vio * vio)414 int vio_shutdown(Vio * vio)
415 {
416   int r=0;
417   DBUG_ENTER("vio_shutdown");
418 
419  if (vio->inactive == FALSE)
420   {
421     DBUG_ASSERT(vio->type ==  VIO_TYPE_TCPIP ||
422       vio->type == VIO_TYPE_SOCKET ||
423       vio->type == VIO_TYPE_SSL);
424 
425     DBUG_ASSERT(mysql_socket_getfd(vio->mysql_socket) >= 0);
426     if (mysql_socket_shutdown(vio->mysql_socket, SHUT_RDWR))
427       r= -1;
428     if (mysql_socket_close(vio->mysql_socket))
429       r= -1;
430   }
431   if (r)
432   {
433     DBUG_PRINT("vio_error", ("close() failed, error: %d",socket_errno));
434     /* FIXME: error handling (not critical for MySQL) */
435   }
436   vio->inactive= TRUE;
437   vio->mysql_socket= MYSQL_INVALID_SOCKET;
438   DBUG_RETURN(r);
439 }
440 
441 
vio_description(Vio * vio)442 const char *vio_description(Vio * vio)
443 {
444   if (!vio->desc[0])
445   {
446     my_snprintf(vio->desc, VIO_DESCRIPTION_SIZE,
447                 (vio->type == VIO_TYPE_SOCKET ? "socket (%d)" : "TCP/IP (%d)"),
448                 mysql_socket_getfd(vio->mysql_socket));
449   }
450   return vio->desc;
451 }
452 
vio_type(Vio * vio)453 enum enum_vio_type vio_type(Vio* vio)
454 {
455   return vio->type;
456 }
457 
vio_fd(Vio * vio)458 my_socket vio_fd(Vio* vio)
459 {
460   return mysql_socket_getfd(vio->mysql_socket);
461 }
462 
463 /**
464   Convert a sock-address (AF_INET or AF_INET6) into the "normalized" form,
465   which is the IPv4 form for IPv4-mapped or IPv4-compatible IPv6 addresses.
466 
467   @note Background: when IPv4 and IPv6 are used simultaneously, IPv4
468   addresses may be written in a form of IPv4-mapped or IPv4-compatible IPv6
469   addresses. That means, one address (a.b.c.d) can be written in three forms:
470     - IPv4: a.b.c.d;
471     - IPv4-compatible IPv6: ::a.b.c.d;
472     - IPv4-mapped IPv4: ::ffff:a.b.c.d;
473 
474   Having three forms of one address makes it a little difficult to compare
475   addresses with each other (the IPv4-compatible IPv6-address of foo.bar
476   will be different from the IPv4-mapped IPv6-address of foo.bar).
477 
478   @note This function can be made public when it's needed.
479 
480   @param src        [in] source IP address (AF_INET or AF_INET6).
481   @param src_length [in] length of the src.
482   @param dst        [out] a buffer to store normalized IP address
483                           (sockaddr_storage).
484   @param dst_length [out] actual length of the normalized IP address.
485 */
vio_get_normalized_ip(const struct sockaddr * src,int src_length,struct sockaddr * dst,int * dst_length)486 static void vio_get_normalized_ip(const struct sockaddr *src,
487                                   int src_length,
488                                   struct sockaddr *dst,
489                                   int *dst_length)
490 {
491   switch (src->sa_family) {
492   case AF_INET:
493     memcpy(dst, src, src_length);
494     *dst_length= src_length;
495     break;
496 
497 #ifdef HAVE_IPV6
498   case AF_INET6:
499   {
500     const struct sockaddr_in6 *src_addr6= (const struct sockaddr_in6 *) src;
501     const struct in6_addr *src_ip6= &(src_addr6->sin6_addr);
502     const uint32 *src_ip6_int32= (uint32 *) src_ip6->s6_addr;
503 
504     if (IN6_IS_ADDR_V4MAPPED(src_ip6) || IN6_IS_ADDR_V4COMPAT(src_ip6))
505     {
506       struct sockaddr_in *dst_ip4= (struct sockaddr_in *) dst;
507 
508       /*
509         This is an IPv4-mapped or IPv4-compatible IPv6 address. It should
510         be converted to the IPv4 form.
511       */
512 
513       *dst_length= sizeof (struct sockaddr_in);
514 
515       memset(dst_ip4, 0, *dst_length);
516       dst_ip4->sin_family= AF_INET;
517       dst_ip4->sin_port= src_addr6->sin6_port;
518 
519       /*
520         In an IPv4 mapped or compatible address, the last 32 bits represent
521         the IPv4 address. The byte orders for IPv6 and IPv4 addresses are
522         the same, so a simple copy is possible.
523       */
524       dst_ip4->sin_addr.s_addr= src_ip6_int32[3];
525     }
526     else
527     {
528       /* This is a "native" IPv6 address. */
529 
530       memcpy(dst, src, src_length);
531       *dst_length= src_length;
532     }
533 
534     break;
535   }
536 #endif /* HAVE_IPV6 */
537   }
538 }
539 
540 
541 /**
542   Return the normalized IP address string for a sock-address.
543 
544   The idea is to return an IPv4-address for an IPv4-mapped and
545   IPv4-compatible IPv6 address.
546 
547   The function writes the normalized IP address to the given buffer.
548   The buffer should have enough space, otherwise error flag is returned.
549   The system constant INET6_ADDRSTRLEN can be used to reserve buffers of
550   the right size.
551 
552   @param addr           [in]  sockaddr object (AF_INET or AF_INET6).
553   @param addr_length    [in]  length of the addr.
554   @param ip_string      [out] buffer to write normalized IP address.
555   @param ip_string_size [in]  size of the ip_string.
556 
557   @return Error status.
558   @retval TRUE in case of error (the ip_string buffer is not enough).
559   @retval FALSE on success.
560 */
561 
vio_get_normalized_ip_string(const struct sockaddr * addr,int addr_length,char * ip_string,size_t ip_string_size)562 my_bool vio_get_normalized_ip_string(const struct sockaddr *addr,
563                                      int addr_length,
564                                      char *ip_string,
565                                      size_t ip_string_size)
566 {
567   struct sockaddr_storage norm_addr_storage;
568   struct sockaddr *norm_addr= (struct sockaddr *) &norm_addr_storage;
569   int norm_addr_length;
570   int err_code;
571 
572   vio_get_normalized_ip(addr, addr_length, norm_addr, &norm_addr_length);
573 
574   err_code= vio_getnameinfo(norm_addr, ip_string, ip_string_size, NULL, 0,
575                             NI_NUMERICHOST);
576 
577   if (!err_code)
578     return FALSE;
579 
580   DBUG_PRINT("error", ("getnameinfo() failed with %d (%s).",
581                        (int) err_code,
582                        (const char *) gai_strerror(err_code)));
583   return TRUE;
584 }
585 
586 
587 /**
588   Return IP address and port of a VIO client socket.
589 
590   The function returns an IPv4 address if IPv6 support is disabled.
591 
592   The function returns an IPv4 address if the client socket is associated
593   with an IPv4-compatible or IPv4-mapped IPv6 address. Otherwise, the native
594   IPv6 address is returned.
595 */
596 
vio_peer_addr(Vio * vio,char * ip_buffer,uint16 * port,size_t ip_buffer_size)597 my_bool vio_peer_addr(Vio *vio, char *ip_buffer, uint16 *port,
598                       size_t ip_buffer_size)
599 {
600   DBUG_ENTER("vio_peer_addr");
601   DBUG_PRINT("enter", ("Client socked fd: %d",
602             (int)mysql_socket_getfd(vio->mysql_socket)));
603 
604   if (vio->localhost)
605   {
606     /*
607       Initialize vio->remote and vio->addLen. Set vio->remote to IPv4 loopback
608       address.
609     */
610     struct in_addr *ip4= &((struct sockaddr_in *) &(vio->remote))->sin_addr;
611 
612     vio->remote.ss_family= AF_INET;
613     vio->addrLen= sizeof (struct sockaddr_in);
614 
615     ip4->s_addr= htonl(INADDR_LOOPBACK);
616 
617     /* Initialize ip_buffer and port. */
618 
619     strmov(ip_buffer, "127.0.0.1");
620     *port= 0;
621   }
622   else
623   {
624     int err_code;
625     char port_buffer[NI_MAXSERV];
626 
627     struct sockaddr_storage addr_storage;
628     struct sockaddr *addr= (struct sockaddr *) &addr_storage;
629     size_socket addr_length= sizeof (addr_storage);
630 
631     /* Get sockaddr by socked fd. */
632 
633     err_code= mysql_socket_getpeername(vio->mysql_socket, addr, &addr_length);
634 
635     if (err_code)
636     {
637       DBUG_PRINT("exit", ("getpeername() gave error: %d", socket_errno));
638       DBUG_RETURN(TRUE);
639     }
640 
641     /* Normalize IP address. */
642 
643     vio_get_normalized_ip(addr, addr_length,
644                           (struct sockaddr *) &vio->remote, &vio->addrLen);
645 
646     /* Get IP address & port number. */
647 
648     err_code= vio_getnameinfo((struct sockaddr *) &vio->remote,
649                               ip_buffer, ip_buffer_size,
650                               port_buffer, NI_MAXSERV,
651                               NI_NUMERICHOST | NI_NUMERICSERV);
652 
653     if (err_code)
654     {
655       DBUG_PRINT("exit", ("getnameinfo() gave error: %s",
656                           gai_strerror(err_code)));
657       DBUG_RETURN(TRUE);
658     }
659 
660     *port= (uint16) strtol(port_buffer, NULL, 10);
661   }
662 
663   DBUG_PRINT("exit", ("Client IP address: %s; port: %d",
664                       (const char *) ip_buffer,
665                       (int) *port));
666   DBUG_RETURN(FALSE);
667 }
668 
669 
670 /**
671   Retrieve the amount of data that can be read from a socket.
672 
673   @param vio          A VIO object.
674   @param bytes[out]   The amount of bytes available.
675 
676   @retval FALSE   Success.
677   @retval TRUE    Failure.
678 */
679 // WL#4896: Not covered
socket_peek_read(Vio * vio,uint * bytes)680 static my_bool socket_peek_read(Vio *vio, uint *bytes)
681 {
682   my_socket sd= mysql_socket_getfd(vio->mysql_socket);
683 #if defined(_WIN32)
684   int len;
685   if (ioctlsocket(sd, FIONREAD, &len))
686     return TRUE;
687   *bytes= len;
688   return FALSE;
689 #elif defined(FIONREAD_IN_SYS_IOCTL) || defined(FIONREAD_IN_SYS_FILIO)
690   int len;
691   if (ioctl(sd, FIONREAD, &len) < 0)
692     return TRUE;
693   *bytes= len;
694   return FALSE;
695 #else
696   char buf[1024];
697   ssize_t res= recv(sd, &buf, sizeof(buf), MSG_PEEK);
698   if (res < 0)
699     return TRUE;
700   *bytes= res;
701   return FALSE;
702 #endif
703 }
704 
705 #ifndef _WIN32
706 
707 /**
708   Set of event flags grouped by operations.
709 */
710 
711 /*
712   Linux specific flag used to detect connection shutdown. The flag is
713   also used for half-closed notification, which here is interpreted as
714   if there is data available to be read from the socket.
715 */
716 #ifndef POLLRDHUP
717 #define POLLRDHUP 0
718 #endif
719 
720 /* Data may be read. */
721 #define MY_POLL_SET_IN      (POLLIN | POLLPRI)
722 /* Data may be written. */
723 #define MY_POLL_SET_OUT     (POLLOUT)
724 /* An error or hangup. */
725 #define MY_POLL_SET_ERR     (POLLERR | POLLHUP | POLLNVAL)
726 
727 #endif
728 
729 /**
730   Wait for an I/O event on a VIO socket.
731 
732   @param vio      VIO object representing a connected socket.
733   @param event    The type of I/O event to wait for.
734   @param timeout  Interval (in milliseconds) to wait for an I/O event.
735                   A negative timeout value means an infinite timeout.
736 
737   @remark sock_errno is set to SOCKET_ETIMEDOUT on timeout.
738 
739   @return A three-state value which indicates the operation status.
740   @retval -1  Failure, socket_errno indicates the error.
741   @retval  0  The wait has timed out.
742   @retval  1  The requested I/O event has occurred.
743 */
744 
745 #if !defined(_WIN32) && !defined(__APPLE__)
vio_io_wait(Vio * vio,enum enum_vio_io_event event,int timeout)746 int vio_io_wait(Vio *vio, enum enum_vio_io_event event, int timeout)
747 {
748   int ret;
749   short revents MY_ATTRIBUTE((unused)) = 0;
750   struct pollfd pfd;
751   my_socket sd= mysql_socket_getfd(vio->mysql_socket);
752   MYSQL_SOCKET_WAIT_VARIABLES(locker, state) /* no ';' */
753   DBUG_ENTER("vio_io_wait");
754 
755   memset(&pfd, 0, sizeof(pfd));
756 
757   pfd.fd= sd;
758 
759   /*
760     Set the poll bitmask describing the type of events.
761     The error flags are only valid in the revents bitmask.
762   */
763   switch (event)
764   {
765   case VIO_IO_EVENT_READ:
766     pfd.events= MY_POLL_SET_IN;
767     revents= MY_POLL_SET_IN | MY_POLL_SET_ERR | POLLRDHUP;
768     break;
769   case VIO_IO_EVENT_WRITE:
770   case VIO_IO_EVENT_CONNECT:
771     pfd.events= MY_POLL_SET_OUT;
772     revents= MY_POLL_SET_OUT | MY_POLL_SET_ERR;
773     break;
774   }
775 
776   MYSQL_START_SOCKET_WAIT(locker, &state, vio->mysql_socket, PSI_SOCKET_SELECT, 0);
777 
778   /*
779     Wait for the I/O event and return early in case of
780     error or timeout.
781   */
782   switch ((ret= poll(&pfd, 1, timeout)))
783   {
784   case -1:
785     /* On error, -1 is returned. */
786     break;
787   case 0:
788     /*
789       Set errno to indicate a timeout error.
790       (This is not compiled in on WIN32.)
791     */
792     errno= SOCKET_ETIMEDOUT;
793     break;
794   default:
795     /* Ensure that the requested I/O event has completed. */
796     DBUG_ASSERT(pfd.revents & revents);
797     break;
798   }
799 
800   MYSQL_END_SOCKET_WAIT(locker, 0);
801   DBUG_RETURN(ret);
802 }
803 
804 #else
805 
vio_io_wait(Vio * vio,enum enum_vio_io_event event,int timeout)806 int vio_io_wait(Vio *vio, enum enum_vio_io_event event, int timeout)
807 {
808   int ret;
809   struct timeval tm;
810   my_socket fd;
811   fd_set readfds, writefds, exceptfds;
812   MYSQL_SOCKET_WAIT_VARIABLES(locker, state) /* no ';' */
813   DBUG_ENTER("vio_io_wait");
814 
815   fd= mysql_socket_getfd(vio->mysql_socket);
816 
817   if (fd == INVALID_SOCKET)
818     DBUG_RETURN(-1);
819 
820   /* Convert the timeout, in milliseconds, to seconds and microseconds. */
821   if (timeout >= 0)
822   {
823     tm.tv_sec= timeout / 1000;
824     tm.tv_usec= (timeout % 1000) * 1000;
825   }
826 
827   FD_ZERO(&readfds);
828   FD_ZERO(&writefds);
829   FD_ZERO(&exceptfds);
830 
831   /* Always receive notification of exceptions. */
832   FD_SET(fd, &exceptfds);
833 
834   switch (event)
835   {
836   case VIO_IO_EVENT_READ:
837     /* Readiness for reading. */
838     FD_SET(fd, &readfds);
839     break;
840   case VIO_IO_EVENT_WRITE:
841   case VIO_IO_EVENT_CONNECT:
842     /* Readiness for writing. */
843     FD_SET(fd, &writefds);
844     break;
845   }
846 
847   MYSQL_START_SOCKET_WAIT(locker, &state, vio->mysql_socket, PSI_SOCKET_SELECT, 0);
848 
849   /* The first argument is ignored on Windows. */
850   ret= select(fd + 1, &readfds, &writefds, &exceptfds,
851               (timeout >= 0) ? &tm : NULL);
852 
853   MYSQL_END_SOCKET_WAIT(locker, 0);
854 
855   /* Set error code to indicate a timeout error. */
856   if (ret == 0)
857 #if defined(_WIN32)
858     WSASetLastError(SOCKET_ETIMEDOUT);
859 #elif defined(__APPLE__)
860     errno= SOCKET_ETIMEDOUT;
861 #else
862 #error Oops...Wrong OS
863 #endif
864 
865   /* Error or timeout? */
866   if (ret <= 0)
867     DBUG_RETURN(ret);
868 
869   /* The requested I/O event is ready? */
870   switch (event)
871   {
872   case VIO_IO_EVENT_READ:
873     ret= MY_TEST(FD_ISSET(fd, &readfds));
874     break;
875   case VIO_IO_EVENT_WRITE:
876   case VIO_IO_EVENT_CONNECT:
877     ret= MY_TEST(FD_ISSET(fd, &writefds));
878     break;
879   }
880 
881   /* Error conditions pending? */
882   ret|= MY_TEST(FD_ISSET(fd, &exceptfds));
883 
884   /* Not a timeout, ensure that a condition was met. */
885   DBUG_ASSERT(ret);
886 
887   DBUG_RETURN(ret);
888 }
889 
890 #endif /* _WIN32 */
891 
892 
893 /**
894   Connect to a peer address.
895 
896   @param vio       A VIO object.
897   @param addr      Socket address containing the peer address.
898   @param len       Length of socket address.
899   @param timeout   Interval (in milliseconds) to wait until a
900                    connection is established.
901 
902   @retval FALSE   A connection was successfully established.
903   @retval TRUE    A fatal error. See socket_errno.
904 */
905 
906 my_bool
vio_socket_connect(Vio * vio,struct sockaddr * addr,socklen_t len,int timeout)907 vio_socket_connect(Vio *vio, struct sockaddr *addr, socklen_t len, int timeout)
908 {
909   int ret, wait;
910   DBUG_ENTER("vio_socket_connect");
911 
912   /* Only for socket-based transport types. */
913   DBUG_ASSERT(vio->type == VIO_TYPE_SOCKET || vio->type == VIO_TYPE_TCPIP);
914 
915   /* If timeout is not infinite, set socket to non-blocking mode. */
916   if ((timeout > -1) && vio_set_blocking(vio, FALSE))
917     DBUG_RETURN(TRUE);
918 
919   /* Initiate the connection. */
920   ret= mysql_socket_connect(vio->mysql_socket, addr, len);
921 
922 #ifdef _WIN32
923   wait= (ret == SOCKET_ERROR) &&
924         (WSAGetLastError() == WSAEINPROGRESS ||
925          WSAGetLastError() == WSAEWOULDBLOCK);
926 #else
927   wait= (ret == -1) && (errno == EINPROGRESS || errno == EALREADY);
928 #endif
929 
930   /*
931     The connection is in progress. The vio_io_wait() call can be used
932     to wait up to a specified period of time for the connection to
933     succeed.
934 
935     If vio_io_wait() returns 0 (after waiting however many seconds),
936     the socket never became writable (host is probably unreachable.)
937     Otherwise, if vio_io_wait() returns 1, then one of two conditions
938     exist:
939 
940     1. An error occurred. Use getsockopt() to check for this.
941     2. The connection was set up successfully: getsockopt() will
942        return 0 as an error.
943   */
944   if (wait && (vio_io_wait(vio, VIO_IO_EVENT_CONNECT, timeout) == 1))
945   {
946     int error;
947     IF_WIN(int, socklen_t) optlen= sizeof(error);
948     IF_WIN(char, void) *optval= (IF_WIN(char, void) *) &error;
949 
950     /*
951       At this point, we know that something happened on the socket.
952       But this does not means that everything is alright. The connect
953       might have failed. We need to retrieve the error code from the
954       socket layer. We must return success only if we are sure that
955       it was really a success. Otherwise we might prevent the caller
956       from trying another address to connect to.
957     */
958     if (!(ret= mysql_socket_getsockopt(vio->mysql_socket, SOL_SOCKET, SO_ERROR, optval, &optlen)))
959     {
960 #ifdef _WIN32
961       WSASetLastError(error);
962 #else
963       errno= error;
964 #endif
965       ret= MY_TEST(error);
966     }
967   }
968 
969   /* If necessary, restore the blocking mode, but only if connect succeeded. */
970   if ((timeout > -1) && (ret == 0))
971   {
972     if (vio_set_blocking(vio, TRUE))
973       DBUG_RETURN(TRUE);
974   }
975 
976   DBUG_RETURN(MY_TEST(ret));
977 }
978 
979 
980 /**
981   Determine if the endpoint of a connection is still available.
982 
983   @remark The socket is assumed to be disconnected if an EOF
984           condition is encountered.
985 
986   @param vio      The VIO object.
987 
988   @retval TRUE    EOF condition not found.
989   @retval FALSE   EOF condition is signaled.
990 */
991 
vio_is_connected(Vio * vio)992 my_bool vio_is_connected(Vio *vio)
993 {
994   uint bytes= 0;
995   DBUG_ENTER("vio_is_connected");
996 
997   /*
998     The first step of detecting an EOF condition is verifying
999     whether there is data to read. Data in this case would be
1000     the EOF. An exceptional condition event and/or errors are
1001     interpreted as if there is data to read.
1002   */
1003   if (!vio_io_wait(vio, VIO_IO_EVENT_READ, 0))
1004     DBUG_RETURN(TRUE);
1005 
1006   /*
1007     The second step is read() or recv() from the socket returning
1008     0 (EOF). Unfortunately, it's not possible to call read directly
1009     as we could inadvertently read meaningful connection data.
1010     Simulate a read by retrieving the number of bytes available to
1011     read -- 0 meaning EOF. In the presence of unrecoverable errors,
1012     the socket is assumed to be disconnected.
1013   */
1014   while (socket_peek_read(vio, &bytes))
1015   {
1016     if (socket_errno != SOCKET_EINTR)
1017       DBUG_RETURN(FALSE);
1018   }
1019 
1020 #ifdef HAVE_OPENSSL
1021   /* There might be buffered data at the SSL layer. */
1022   if (!bytes && vio->type == VIO_TYPE_SSL)
1023     bytes= SSL_pending((SSL*) vio->ssl_arg);
1024 #endif
1025 
1026   DBUG_RETURN(bytes ? TRUE : FALSE);
1027 }
1028 
1029 #ifndef DBUG_OFF
1030 
1031 /**
1032   Number of bytes in the read or socket buffer
1033 
1034   @remark An EOF condition might count as one readable byte.
1035 
1036   @return number of bytes in one of the buffers or < 0 if error.
1037 */
1038 
vio_pending(Vio * vio)1039 ssize_t vio_pending(Vio *vio)
1040 {
1041   uint bytes= 0;
1042 
1043   /* Data pending on the read buffer. */
1044   if (vio->read_pos < vio->read_end)
1045     return vio->read_end - vio->read_pos;
1046 
1047   /* Skip non-socket based transport types. */
1048   if (vio->type == VIO_TYPE_TCPIP || vio->type == VIO_TYPE_SOCKET)
1049   {
1050     /* Obtain number of readable bytes in the socket buffer. */
1051     if (socket_peek_read(vio, &bytes))
1052       return -1;
1053   }
1054 
1055   return (ssize_t) bytes;
1056 }
1057 
1058 #endif
1059 
1060 /**
1061   Checks if the error code, returned by vio_getnameinfo(), means it was the
1062   "No-name" error.
1063 
1064   Windows-specific note: getnameinfo() returns WSANO_DATA instead of
1065   EAI_NODATA or EAI_NONAME when no reverse mapping is available at the host
1066   (i.e. Windows can't get hostname by IP-address). This error should be
1067   treated as EAI_NONAME.
1068 
1069   @return if the error code is actually EAI_NONAME.
1070   @retval true if the error code is EAI_NONAME.
1071   @retval false otherwise.
1072 */
1073 
vio_is_no_name_error(int err_code)1074 my_bool vio_is_no_name_error(int err_code)
1075 {
1076 #ifdef _WIN32
1077 
1078   return err_code == WSANO_DATA || err_code == EAI_NONAME;
1079 
1080 #else
1081 
1082   return err_code == EAI_NONAME;
1083 
1084 #endif
1085 }
1086 
1087 
1088 /**
1089   This is a wrapper for the system getnameinfo(), because different OS
1090   differ in the getnameinfo() implementation:
1091     - Solaris 10 requires that the 2nd argument (salen) must match the
1092       actual size of the struct sockaddr_storage passed to it;
1093     - Mac OS X has sockaddr_in::sin_len and sockaddr_in6::sin6_len and
1094       requires them to be filled.
1095 */
1096 
vio_getnameinfo(const struct sockaddr * sa,char * hostname,size_t hostname_size,char * port,size_t port_size,int flags)1097 int vio_getnameinfo(const struct sockaddr *sa,
1098                     char *hostname, size_t hostname_size,
1099                     char *port, size_t port_size,
1100                     int flags)
1101 {
1102   int sa_length= 0;
1103 
1104   switch (sa->sa_family) {
1105   case AF_INET:
1106     sa_length= sizeof (struct sockaddr_in);
1107 #ifdef HAVE_SOCKADDR_IN_SIN_LEN
1108     ((struct sockaddr_in *) sa)->sin_len= sa_length;
1109 #endif /* HAVE_SOCKADDR_IN_SIN_LEN */
1110     break;
1111 
1112 #ifdef HAVE_IPV6
1113   case AF_INET6:
1114     sa_length= sizeof (struct sockaddr_in6);
1115 # ifdef HAVE_SOCKADDR_IN6_SIN6_LEN
1116     ((struct sockaddr_in6 *) sa)->sin6_len= sa_length;
1117 # endif /* HAVE_SOCKADDR_IN6_SIN6_LEN */
1118     break;
1119 #endif /* HAVE_IPV6 */
1120   }
1121 
1122   return getnameinfo(sa, sa_length,
1123                      hostname, hostname_size,
1124                      port, port_size,
1125                      flags);
1126 }
1127