1/************************************************************************************
2 Copyright (C) 2015,2016 MariaDB Corporation AB,
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with this library; if not see <http://www.gnu.org/licenses>
16 or write to the Free Software Foundation, Inc.,
17 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
18*************************************************************************************/
19
20/*
21 MariaDB virtual IO plugin for socket communication:
22
23 The plugin handles connections via unix and network sockets. it is enabled by
24 default and compiled into Connector/C.
25*/
26
27#include <ma_global.h>
28#include <ma_sys.h>
29#include <errmsg.h>
30#include <mysql.h>
31#include <mysql/client_plugin.h>
32#include <ma_context.h>
33#include <mariadb_async.h>
34#include <ma_common.h>
35#include <string.h>
36#include <time.h>
37#ifndef _WIN32
38#ifdef HAVE_SYS_UN_H
39#include <sys/un.h>
40#endif
41#ifdef HAVE_POLL
42#include <sys/poll.h>
43#endif
44#ifdef HAVE_SYS_IOCTL_H
45#include <sys/ioctl.h>
46#endif
47#ifdef HAVE_FCNTL_H
48#include <fcntl.h>
49#endif
50#include <netinet/in_systm.h>
51#include <netinet/in.h>
52#include <netinet/ip.h>
53#include <netdb.h>
54#include <netinet/tcp.h>
55#define IS_SOCKET_EINTR(err) (err == SOCKET_EINTR)
56#else
57#include <ws2tcpip.h>
58#define O_NONBLOCK 1
59#define MSG_DONTWAIT 0
60#define IS_SOCKET_EINTR(err) 0
61#endif
62
63#ifndef SOCKET_ERROR
64#define SOCKET_ERROR -1
65#endif
66
67#ifndef INVALID_SOCKET
68#define INVALID_SOCKET -1
69#endif
70
71#define DNS_TIMEOUT 30
72
73#ifndef O_NONBLOCK
74#if defined(O_NDELAY)
75#define O_NONBLOCK O_NODELAY
76#elif defined (O_FNDELAY)
77#define O_NONBLOCK O_FNDELAY
78#else
79#error socket blocking is not supported on this platform
80#endif
81#endif
82
83#if SOCKET_EAGAIN != SOCKET_EWOULDBLOCK
84#define HAVE_SOCKET_EWOULDBLOCK 1
85#endif
86
87/* Function prototypes */
88my_bool pvio_socket_set_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type, int timeout);
89int pvio_socket_get_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type);
90ssize_t pvio_socket_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length);
91ssize_t pvio_socket_async_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length);
92ssize_t pvio_socket_async_write(MARIADB_PVIO *pvio, const uchar *buffer, size_t length);
93ssize_t pvio_socket_write(MARIADB_PVIO *pvio, const uchar *buffer, size_t length);
94int pvio_socket_wait_io_or_timeout(MARIADB_PVIO *pvio, my_bool is_read, int timeout);
95int pvio_socket_blocking(MARIADB_PVIO *pvio, my_bool value, my_bool *old_value);
96my_bool pvio_socket_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo);
97my_bool pvio_socket_close(MARIADB_PVIO *pvio);
98int pvio_socket_fast_send(MARIADB_PVIO *pvio);
99int pvio_socket_keepalive(MARIADB_PVIO *pvio);
100my_bool pvio_socket_get_handle(MARIADB_PVIO *pvio, void *handle);
101my_bool pvio_socket_is_blocking(MARIADB_PVIO *pvio);
102my_bool pvio_socket_is_alive(MARIADB_PVIO *pvio);
103my_bool pvio_socket_has_data(MARIADB_PVIO *pvio, ssize_t *data_len);
104int pvio_socket_shutdown(MARIADB_PVIO *pvio);
105
106static int pvio_socket_init(char *unused1,
107 size_t unused2,
108 int unused3,
109 va_list);
110static int pvio_socket_end(void);
111static ssize_t ma_send(my_socket socket, const uchar *buffer, size_t length, int flags);
112static ssize_t ma_recv(my_socket socket, uchar *buffer, size_t length, int flags);
113
114struct st_ma_pvio_methods pvio_socket_methods= {
115 pvio_socket_set_timeout,
116 pvio_socket_get_timeout,
117 pvio_socket_read,
118 pvio_socket_async_read,
119 pvio_socket_write,
120 pvio_socket_async_write,
121 pvio_socket_wait_io_or_timeout,
122 pvio_socket_blocking,
123 pvio_socket_connect,
124 pvio_socket_close,
125 pvio_socket_fast_send,
126 pvio_socket_keepalive,
127 pvio_socket_get_handle,
128 pvio_socket_is_blocking,
129 pvio_socket_is_alive,
130 pvio_socket_has_data,
131 pvio_socket_shutdown
132};
133
134#ifndef PLUGIN_DYNAMIC
135MARIADB_PVIO_PLUGIN pvio_socket_client_plugin=
136#else
137MARIADB_PVIO_PLUGIN _mysql_client_plugin_declaration_
138#endif
139{
140 MARIADB_CLIENT_PVIO_PLUGIN,
141 MARIADB_CLIENT_PVIO_PLUGIN_INTERFACE_VERSION,
142 "pvio_socket",
143 "Georg Richter",
144 "MariaDB virtual IO plugin for socket communication",
145 {1, 0, 0},
146 "LGPL",
147 NULL,
148 &pvio_socket_init,
149 &pvio_socket_end,
150 NULL,
151 &pvio_socket_methods
152};
153
154struct st_pvio_socket {
155 my_socket socket;
156 int fcntl_mode;
157 MYSQL *mysql;
158};
159
160static my_bool pvio_socket_initialized= FALSE;
161
162static int pvio_socket_init(char *errmsg __attribute__((unused)),
163 size_t errmsg_length __attribute__((unused)),
164 int unused __attribute__((unused)),
165 va_list va __attribute__((unused)))
166{
167 pvio_socket_initialized= TRUE;
168 return 0;
169}
170
171static int pvio_socket_end(void)
172{
173 if (!pvio_socket_initialized)
174 return 1;
175 return 0;
176}
177
178my_bool pvio_socket_change_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type, int timeout)
179{
180 struct timeval tm;
181 int rc= 0;
182 struct st_pvio_socket *csock= NULL;
183 if (!pvio)
184 return 1;
185 if (!(csock= (struct st_pvio_socket *)pvio->data))
186 return 1;
187 tm.tv_sec= timeout / 1000;
188 tm.tv_usec= (timeout % 1000) * 1000;
189 switch(type)
190 {
191 case PVIO_WRITE_TIMEOUT:
192#ifndef _WIN32
193 rc= setsockopt(csock->socket, SOL_SOCKET, SO_SNDTIMEO, (const char *)&tm, sizeof(tm));
194#else
195 rc= setsockopt(csock->socket, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout, sizeof(int));
196#endif
197 break;
198 case PVIO_READ_TIMEOUT:
199#ifndef _WIN32
200 rc= setsockopt(csock->socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tm, sizeof(tm));
201#else
202 rc= setsockopt(csock->socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(int));
203#endif
204 break;
205 default:
206 break;
207 }
208 return rc;
209}
210
211/* {{{ pvio_socket_set_timeout */
212/*
213 set timeout value
214
215 SYNOPSIS
216 pvio_socket_set_timeout
217 pvio PVIO
218 type timeout type (connect, read, write)
219 timeout timeout in seconds
220
221 DESCRIPTION
222 Sets timeout values for connection-, read or write time out.
223 PVIO internally stores all timeout values in milliseconds, but
224 accepts and returns all time values in seconds (like api does).
225
226 RETURNS
227 0 Success
228 1 Error
229*/
230my_bool pvio_socket_set_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type, int timeout)
231{
232 struct st_pvio_socket *csock= NULL;
233 if (!pvio)
234 return 1;
235 csock= (struct st_pvio_socket *)pvio->data;
236 pvio->timeout[type]= (timeout > 0) ? timeout * 1000 : -1;
237 if (csock)
238 return pvio_socket_change_timeout(pvio, type, timeout * 1000);
239 return 0;
240}
241/* }}} */
242
243/* {{{ pvio_socket_get_timeout */
244/*
245 get timeout value
246
247 SYNOPSIS
248 pvio_socket_get_timeout
249 pvio PVIO
250 type timeout type (connect, read, write)
251
252 DESCRIPTION
253 Returns timeout values for connection-, read or write time out.
254 PVIO internally stores all timeout values in milliseconds, but
255 accepts and returns all time values in seconds (like api does).
256
257 RETURNS
258 0...n time out value
259 -1 error
260*/
261int pvio_socket_get_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type)
262{
263 if (!pvio)
264 return -1;
265 return pvio->timeout[type] / 1000;
266}
267/* }}} */
268
269/* {{{ pvio_socket_read */
270/*
271 read from socket
272
273 SYNOPSIS
274 pvio_socket_read()
275 pvio PVIO
276 buffer read buffer
277 length buffer length
278
279 DESCRIPTION
280 reads up to length bytes into specified buffer. In the event of an
281 error erno is set to indicate it.
282
283 RETURNS
284 1..n number of bytes read
285 0 peer has performed shutdown
286 -1 on error
287
288*/
289ssize_t pvio_socket_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length)
290{
291 ssize_t r;
292 int read_flags= MSG_DONTWAIT;
293 struct st_pvio_socket *csock;
294 int timeout;
295
296 if (!pvio || !pvio->data)
297 return -1;
298
299 csock= (struct st_pvio_socket *)pvio->data;
300 timeout = pvio->timeout[PVIO_READ_TIMEOUT];
301
302 while ((r = ma_recv(csock->socket, (void *)buffer, length, read_flags)) == -1)
303 {
304 int err = socket_errno;
305 if ((err != SOCKET_EAGAIN
306#ifdef HAVE_SOCKET_EWOULDBLOCK
307 && err != SOCKET_EWOULDBLOCK
308#endif
309 ) || timeout == 0)
310 return r;
311
312 if (pvio_socket_wait_io_or_timeout(pvio, TRUE, timeout) < 1)
313 return -1;
314 }
315 return r;
316}
317/* }}} */
318
319/* {{{ pvio_socket_async_read */
320/*
321 read from socket
322
323 SYNOPSIS
324 pvio_socket_async_read()
325 pvio PVIO
326 buffer read buffer
327 length buffer length
328
329 DESCRIPTION
330 reads up to length bytes into specified buffer. In the event of an
331 error erno is set to indicate it.
332
333 RETURNS
334 1..n number of bytes read
335 0 peer has performed shutdown
336 -1 on error
337
338*/
339ssize_t pvio_socket_async_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length)
340{
341 ssize_t r= -1;
342#ifndef _WIN32
343 int read_flags= MSG_DONTWAIT;
344#endif
345 struct st_pvio_socket *csock= NULL;
346
347 if (!pvio || !pvio->data)
348 return -1;
349
350 csock= (struct st_pvio_socket *)pvio->data;
351
352#ifndef _WIN32
353 r= recv(csock->socket,(void *)buffer, length, read_flags);
354#else
355 /* Windows doesn't support MSG_DONTWAIT, so we need to set
356 socket to non blocking */
357 pvio_socket_blocking(pvio, 0, 0);
358 r= recv(csock->socket, (char *)buffer, (int)length, 0);
359#endif
360 return r;
361}
362/* }}} */
363
364static ssize_t ma_send(my_socket socket, const uchar *buffer, size_t length, int flags)
365{
366 ssize_t r;
367#if !defined(MSG_NOSIGNAL) && !defined(SO_NOSIGPIPE) && !defined(_WIN32)
368 struct sigaction act, oldact;
369 act.sa_handler= SIG_IGN;
370 sigaction(SIGPIPE, &act, &oldact);
371#endif
372 do {
373 r = send(socket, (const char *)buffer, IF_WIN((int)length,length), flags);
374 }
375 while (r == -1 && IS_SOCKET_EINTR(socket_errno));
376#if !defined(MSG_NOSIGNAL) && !defined(SO_NOSIGPIPE) && !defined(_WIN32)
377 sigaction(SIGPIPE, &oldact, NULL);
378#endif
379 return r;
380}
381
382static ssize_t ma_recv(my_socket socket, uchar *buffer, size_t length, int flags)
383{
384 ssize_t r;
385 do {
386 r = recv(socket, (char*) buffer, IF_WIN((int)length, length), flags);
387 }
388 while (r == -1 && IS_SOCKET_EINTR(socket_errno));
389 return r;
390}
391
392/* {{{ pvio_socket_async_write */
393/*
394 write to socket
395
396 SYNOPSIS
397 pvio_socket_async_write()
398 pvio PVIO
399 buffer read buffer
400 length buffer length
401
402 DESCRIPTION
403 writes up to length bytes to socket. In the event of an
404 error erno is set to indicate it.
405
406 RETURNS
407 1..n number of bytes read
408 0 peer has performed shutdown
409 -1 on error
410
411*/
412ssize_t pvio_socket_async_write(MARIADB_PVIO *pvio, const uchar *buffer, size_t length)
413{
414 ssize_t r= -1;
415 struct st_pvio_socket *csock= NULL;
416#ifndef _WIN32
417 int write_flags= MSG_DONTWAIT;
418#ifdef MSG_NOSIGNAL
419 write_flags|= MSG_NOSIGNAL;
420#endif
421#endif
422
423 if (!pvio || !pvio->data)
424 return -1;
425
426 csock= (struct st_pvio_socket *)pvio->data;
427
428#ifndef WIN32
429 r= ma_send(csock->socket, buffer, length, write_flags);
430#else
431 /* Windows doesn't support MSG_DONTWAIT, so we need to set
432 socket to non blocking */
433 pvio_socket_blocking(pvio, 0, 0);
434 r= send(csock->socket, (const char *)buffer, (int)length, 0);
435#endif
436
437 return r;
438}
439/* }}} */
440
441/* {{{ pvio_socket_write */
442/*
443 write to socket
444
445 SYNOPSIS
446 pvio_socket_write()
447 pvio PVIO
448 buffer read buffer
449 length buffer length
450
451 DESCRIPTION
452 writes up to length bytes to socket. In the event of an
453 error erno is set to indicate it.
454
455 RETURNS
456 1..n number of bytes read
457 0 peer has performed shutdown
458 -1 on error
459
460*/
461ssize_t pvio_socket_write(MARIADB_PVIO *pvio, const uchar *buffer, size_t length)
462{
463 ssize_t r;
464 struct st_pvio_socket *csock;
465 int timeout;
466 int send_flags= MSG_DONTWAIT;
467#ifdef MSG_NOSIGNAL
468 send_flags|= MSG_NOSIGNAL;
469#endif
470 if (!pvio || !pvio->data)
471 return -1;
472
473 csock= (struct st_pvio_socket *)pvio->data;
474 timeout = pvio->timeout[PVIO_WRITE_TIMEOUT];
475
476 while ((r = ma_send(csock->socket, (void *)buffer, length,send_flags)) == -1)
477 {
478 int err = socket_errno;
479 if ((err != SOCKET_EAGAIN
480#ifdef HAVE_SOCKET_EWOULDBLOCK
481 && err != SOCKET_EWOULDBLOCK
482#endif
483 )|| timeout == 0)
484 return r;
485 if (pvio_socket_wait_io_or_timeout(pvio, FALSE, timeout) < 1)
486 return -1;
487 }
488 return r;
489}
490/* }}} */
491
492int pvio_socket_wait_io_or_timeout(MARIADB_PVIO *pvio, my_bool is_read, int timeout)
493{
494 int rc;
495 struct st_pvio_socket *csock= NULL;
496
497#ifndef _WIN32
498 struct pollfd p_fd;
499#else
500 struct timeval tv= {0,0};
501 fd_set fds, exc_fds;
502#endif
503
504 if (!pvio || !pvio->data)
505 return 0;
506
507 if (pvio->mysql->options.extension &&
508 pvio->mysql->options.extension->io_wait != NULL) {
509 my_socket handle;
510 if (pvio_socket_get_handle(pvio, &handle))
511 return 0;
512 return pvio->mysql->options.extension->io_wait(handle, is_read, timeout);
513 }
514
515 csock= (struct st_pvio_socket *)pvio->data;
516 {
517#ifndef _WIN32
518 memset(&p_fd, 0, sizeof(p_fd));
519 p_fd.fd= csock->socket;
520 p_fd.events= (is_read) ? POLLIN : POLLOUT;
521
522 if (!timeout)
523 timeout= -1;
524
525 do {
526 rc= poll(&p_fd, 1, timeout);
527 } while (rc == -1 && errno == EINTR);
528
529 if (rc == 0)
530 errno= ETIMEDOUT;
531#else
532 FD_ZERO(&fds);
533 FD_ZERO(&exc_fds);
534
535 FD_SET(csock->socket, &fds);
536 FD_SET(csock->socket, &exc_fds);
537
538 if (timeout >= 0)
539 {
540 tv.tv_sec= timeout / 1000;
541 tv.tv_usec= (timeout % 1000) * 1000;
542 }
543
544 rc= select(0, (is_read) ? &fds : NULL,
545 (is_read) ? NULL : &fds,
546 &exc_fds,
547 (timeout >= 0) ? &tv : NULL);
548
549 if (rc == SOCKET_ERROR)
550 {
551 errno= WSAGetLastError();
552 }
553 else if (rc == 0)
554 {
555 rc= SOCKET_ERROR;
556 WSASetLastError(WSAETIMEDOUT);
557 errno= ETIMEDOUT;
558 }
559 else if (FD_ISSET(csock->socket, &exc_fds))
560 {
561 int err;
562 int len = sizeof(int);
563 if (getsockopt(csock->socket, SOL_SOCKET, SO_ERROR, (char *)&err, &len) != SOCKET_ERROR)
564 {
565 WSASetLastError(err);
566 errno= err;
567 }
568 rc= SOCKET_ERROR;
569 }
570
571#endif
572 }
573 return rc;
574}
575
576int pvio_socket_blocking(MARIADB_PVIO *pvio, my_bool block, my_bool *previous_mode)
577{
578 my_bool is_blocking;
579 struct st_pvio_socket *csock;
580 int new_fcntl_mode;
581
582 if (!pvio || !pvio->data)
583 return 1;
584
585 csock = (struct st_pvio_socket *)pvio->data;
586
587 is_blocking = !(csock->fcntl_mode & O_NONBLOCK);
588 if (previous_mode)
589 *previous_mode = is_blocking;
590
591 if (is_blocking == block)
592 return 0;
593
594 if (block)
595 new_fcntl_mode = csock->fcntl_mode & ~O_NONBLOCK;
596 else
597 new_fcntl_mode = csock->fcntl_mode | O_NONBLOCK;
598
599#ifdef _WIN32
600 {
601 ulong arg = block ? 0 : 1;
602 if (ioctlsocket(csock->socket, FIONBIO, (void *)&arg))
603 {
604 return(WSAGetLastError());
605 }
606 }
607#else
608 if (fcntl(csock->socket, F_SETFL, new_fcntl_mode) == -1)
609 {
610 return errno;
611 }
612#endif
613 csock->fcntl_mode = new_fcntl_mode;
614 return 0;
615}
616
617static int pvio_socket_internal_connect(MARIADB_PVIO *pvio,
618 const struct sockaddr *name,
619 size_t namelen)
620{
621 int rc= 0;
622 struct st_pvio_socket *csock= NULL;
623 int timeout;
624
625 if (!pvio || !pvio->data)
626 return 1;
627
628 csock= (struct st_pvio_socket *)pvio->data;
629 timeout= pvio->timeout[PVIO_CONNECT_TIMEOUT];
630
631 /* set non blocking */
632 pvio_socket_blocking(pvio, 0, 0);
633
634#ifndef _WIN32
635 do {
636 rc= connect(csock->socket, (struct sockaddr*) name, (int)namelen);
637 } while (rc == -1 && (errno == EINTR || errno == EAGAIN));
638 /* in case a timeout values was set we need to check error values
639 EINPROGRESS */
640 if (timeout != 0 && rc == -1 && errno == EINPROGRESS)
641 {
642 rc= pvio_socket_wait_io_or_timeout(pvio, FALSE, timeout);
643 if (rc < 1)
644 return -1;
645 {
646 int error;
647 socklen_t error_len= sizeof(error);
648 if ((rc = getsockopt(csock->socket, SOL_SOCKET, SO_ERROR,
649 (char *)&error, &error_len)) < 0)
650 return errno;
651 else if (error)
652 return error;
653 }
654 }
655#ifdef __APPLE__
656 if (csock->socket)
657 {
658 int val= 1;
659 setsockopt(csock->socket, SOL_SOCKET, SO_NOSIGPIPE, (void *)&val, sizeof(int));
660 }
661#endif
662#else
663 rc= connect(csock->socket, (struct sockaddr*) name, (int)namelen);
664 if (rc == SOCKET_ERROR)
665 {
666 if (WSAGetLastError() == WSAEWOULDBLOCK)
667 {
668 if (pvio_socket_wait_io_or_timeout(pvio, FALSE, timeout) < 0)
669 return -1;
670 rc= 0;
671 }
672 }
673#endif
674 return rc;
675}
676
677int pvio_socket_keepalive(MARIADB_PVIO *pvio)
678{
679 int opt= 1;
680 struct st_pvio_socket *csock= NULL;
681
682 if (!pvio || !pvio->data)
683 return 1;
684
685 csock= (struct st_pvio_socket *)pvio->data;
686
687 return setsockopt(csock->socket, SOL_SOCKET, SO_KEEPALIVE,
688#ifndef _WIN32
689 (const void *)&opt, sizeof(opt));
690#else
691 (char *)&opt, (int)sizeof(opt));
692#endif
693}
694
695int pvio_socket_fast_send(MARIADB_PVIO *pvio)
696{
697 int r= 0;
698 struct st_pvio_socket *csock= NULL;
699
700 if (!pvio || !pvio->data)
701 return 1;
702
703 csock= (struct st_pvio_socket *)pvio->data;
704
705/* Setting IP_TOS is not recommended on Windows. See
706 http://msdn.microsoft.com/en-us/library/windows/desktop/ms738586(v=vs.85).aspx
707*/
708#if !defined(_WIN32) && defined(IPTOS_THROUGHPUT)
709 {
710 int tos = IPTOS_THROUGHPUT;
711 r= setsockopt(csock->socket, IPPROTO_IP, IP_TOS,
712 (const void *)&tos, sizeof(tos));
713 }
714#endif /* !_WIN32 && IPTOS_THROUGHPUT */
715 if (!r)
716 {
717 int opt = 1;
718 /* turn off nagle algorithm */
719 r= setsockopt(csock->socket, IPPROTO_TCP, TCP_NODELAY,
720#ifdef _WIN32
721 (const char *)&opt, (int)sizeof(opt));
722#else
723 (const void *)&opt, sizeof(opt));
724#endif
725 }
726 return r;
727}
728
729static int
730pvio_socket_connect_sync_or_async(MARIADB_PVIO *pvio,
731 const struct sockaddr *name, uint namelen)
732{
733 MYSQL *mysql= pvio->mysql;
734 if (mysql->options.extension && mysql->options.extension->async_context &&
735 mysql->options.extension->async_context->active)
736 {
737 /* even if we are not connected yet, application needs to check socket
738 * via mysql_get_socket api call, so we need to assign pvio */
739 mysql->options.extension->async_context->pvio= pvio;
740 pvio_socket_blocking(pvio, 0, 0);
741 return my_connect_async(pvio, name, namelen, pvio->timeout[PVIO_CONNECT_TIMEOUT]);
742 }
743
744 return pvio_socket_internal_connect(pvio, name, namelen);
745}
746
747my_bool pvio_socket_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo)
748{
749 struct st_pvio_socket *csock= NULL;
750 MYSQL *mysql;
751
752 if (!pvio || !cinfo)
753 return 1;
754
755 if (!(csock= (struct st_pvio_socket *)calloc(1, sizeof(struct st_pvio_socket))))
756 {
757 PVIO_SET_ERROR(cinfo->mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0, "");
758 return 1;
759 }
760 pvio->data= (void *)csock;
761 csock->socket= INVALID_SOCKET;
762 mysql= pvio->mysql= cinfo->mysql;
763 pvio->type= cinfo->type;
764
765 if (cinfo->type == PVIO_TYPE_UNIXSOCKET)
766 {
767#ifndef _WIN32
768#ifdef HAVE_SYS_UN_H
769 size_t port_length;
770 struct sockaddr_un UNIXaddr;
771 if ((csock->socket = socket(AF_UNIX,SOCK_STREAM,0)) == INVALID_SOCKET ||
772 (port_length=strlen(cinfo->unix_socket)) >= (sizeof(UNIXaddr.sun_path)))
773 {
774 PVIO_SET_ERROR(cinfo->mysql, CR_SOCKET_CREATE_ERROR, unknown_sqlstate, 0, errno);
775 goto error;
776 }
777 memset((char*) &UNIXaddr, 0, sizeof(UNIXaddr));
778 UNIXaddr.sun_family = AF_UNIX;
779#if defined(__linux__)
780 /* Abstract socket */
781 if (cinfo->unix_socket[0] == '@')
782 {
783 strncpy(UNIXaddr.sun_path + 1, cinfo->unix_socket + 1, 106);
784 port_length+= offsetof(struct sockaddr_un, sun_path);
785 }
786 else
787#endif
788 {
789 strcpy(UNIXaddr.sun_path, cinfo->unix_socket);
790 port_length= sizeof(UNIXaddr);
791 }
792 if (pvio_socket_connect_sync_or_async(pvio, (struct sockaddr *) &UNIXaddr, port_length))
793 {
794 PVIO_SET_ERROR(cinfo->mysql, CR_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
795 ER(CR_CONNECTION_ERROR), cinfo->unix_socket, socket_errno);
796 goto error;
797 }
798 if (pvio_socket_blocking(pvio, 1, 0) == SOCKET_ERROR)
799 {
800 goto error;
801 }
802#else
803/* todo: error, not supported */
804#endif
805#endif
806 } else if (cinfo->type == PVIO_TYPE_SOCKET)
807 {
808 struct addrinfo hints, *save_res= 0, *bind_res= 0, *res= 0, *bres= 0;
809 char server_port[NI_MAXSERV];
810 int gai_rc;
811 int rc= 0;
812 time_t start_t= time(NULL);
813#ifdef _WIN32
814 DWORD wait_gai;
815#else
816 unsigned int wait_gai;
817#endif
818
819 memset(&server_port, 0, NI_MAXSERV);
820 snprintf(server_port, NI_MAXSERV, "%d", cinfo->port);
821
822 /* set hints for getaddrinfo */
823 memset(&hints, 0, sizeof(hints));
824 hints.ai_protocol= IPPROTO_TCP; /* TCP connections only */
825 hints.ai_family= AF_UNSPEC; /* includes: IPv4, IPv6 or hostname */
826 hints.ai_socktype= SOCK_STREAM;
827
828 /* if client has multiple interfaces, we will bind socket to given
829 * bind_address */
830 if (cinfo->mysql->options.bind_address)
831 {
832 wait_gai= 1;
833 while ((gai_rc= getaddrinfo(cinfo->mysql->options.bind_address, 0,
834 &hints, &bind_res)) == EAI_AGAIN)
835 {
836 unsigned int timeout= mysql->options.connect_timeout ?
837 mysql->options.connect_timeout : DNS_TIMEOUT;
838 if (time(NULL) - start_t > (time_t)timeout)
839 break;
840#ifndef _WIN32
841 usleep(wait_gai);
842#else
843 Sleep(wait_gai);
844#endif
845 wait_gai*= 2;
846 }
847 if (gai_rc != 0 || !bind_res)
848 {
849 PVIO_SET_ERROR(cinfo->mysql, CR_BIND_ADDR_FAILED, SQLSTATE_UNKNOWN,
850 CER(CR_BIND_ADDR_FAILED), cinfo->mysql->options.bind_address, gai_rc);
851 goto error;
852 }
853 }
854 /* Get the address information for the server using getaddrinfo() */
855 wait_gai= 1;
856 while ((gai_rc= getaddrinfo(cinfo->host, server_port,
857 &hints, &res)) == EAI_AGAIN)
858 {
859 unsigned int timeout= mysql->options.connect_timeout ?
860 mysql->options.connect_timeout : DNS_TIMEOUT;
861 if (time(NULL) - start_t > (time_t)timeout)
862 break;
863#ifndef _WIN32
864 usleep(wait_gai);
865#else
866 Sleep(wait_gai);
867#endif
868 wait_gai*= 2;
869 }
870 if (gai_rc != 0 || !res)
871 {
872 PVIO_SET_ERROR(cinfo->mysql, CR_UNKNOWN_HOST, SQLSTATE_UNKNOWN,
873 ER(CR_UNKNOWN_HOST), cinfo->host, gai_rc);
874 if (bind_res)
875 freeaddrinfo(bind_res);
876 goto error;
877 }
878
879 /* res is a linked list of addresses for the given hostname. We loop until
880 we are able to connect to one address or all connect attempts failed */
881 for (save_res= res; save_res; save_res= save_res->ai_next)
882 {
883 /* CONC-364: Avoid leak of open sockets */
884 if (csock->socket != INVALID_SOCKET)
885 closesocket(csock->socket);
886 csock->socket= socket(save_res->ai_family, save_res->ai_socktype,
887 save_res->ai_protocol);
888 if (csock->socket == INVALID_SOCKET)
889 /* Errors will be handled after loop finished */
890 continue;
891
892 if (bind_res)
893 {
894 for (bres= bind_res; bres; bres= bres->ai_next)
895 {
896 if (!(rc= bind(csock->socket, bres->ai_addr, (int)bres->ai_addrlen)))
897 break;
898 }
899 if (rc)
900 {
901 closesocket(csock->socket);
902 csock->socket= INVALID_SOCKET;
903 continue;
904 }
905 }
906
907 rc= pvio_socket_connect_sync_or_async(pvio, save_res->ai_addr, (uint)save_res->ai_addrlen);
908 if (!rc)
909 {
910 MYSQL *mysql= pvio->mysql;
911 if (mysql->options.extension && mysql->options.extension->async_context &&
912 mysql->options.extension->async_context->active)
913 break;
914 if (pvio_socket_blocking(pvio, 0, 0) == SOCKET_ERROR)
915 {
916 closesocket(csock->socket);
917 csock->socket= INVALID_SOCKET;
918 continue;
919 }
920 break; /* success! */
921 }
922 }
923
924 freeaddrinfo(res);
925 if (bind_res)
926 freeaddrinfo(bind_res);
927
928 if (csock->socket == INVALID_SOCKET)
929 {
930 PVIO_SET_ERROR(cinfo->mysql, CR_IPSOCK_ERROR, SQLSTATE_UNKNOWN, ER(CR_IPSOCK_ERROR),
931 socket_errno);
932 goto error;
933 }
934
935 /* last call to connect 2 failed */
936 if (rc)
937 {
938 PVIO_SET_ERROR(cinfo->mysql, CR_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
939 ER(CR_CONN_HOST_ERROR), cinfo->host,
940#ifdef _WIN32
941 errno);
942#else
943 socket_errno);
944#endif
945 goto error;
946 }
947 if (pvio_socket_blocking(pvio, 1, 0) == SOCKET_ERROR)
948 goto error;
949 }
950 /* apply timeouts */
951 if (pvio->timeout[PVIO_CONNECT_TIMEOUT] > 0)
952 {
953 if (pvio_socket_change_timeout(pvio, PVIO_READ_TIMEOUT, pvio->timeout[PVIO_CONNECT_TIMEOUT]) ||
954 pvio_socket_change_timeout(pvio, PVIO_WRITE_TIMEOUT, pvio->timeout[PVIO_CONNECT_TIMEOUT]))
955 goto error;
956 }
957 else
958 {
959 if (pvio->timeout[PVIO_WRITE_TIMEOUT] > 0)
960 if (pvio_socket_change_timeout(pvio, PVIO_WRITE_TIMEOUT, pvio->timeout[PVIO_WRITE_TIMEOUT]))
961 goto error;
962 if (pvio->timeout[PVIO_READ_TIMEOUT] > 0)
963 if (pvio_socket_change_timeout(pvio, PVIO_READ_TIMEOUT, pvio->timeout[PVIO_READ_TIMEOUT]))
964 goto error;
965 }
966 return 0;
967error:
968 /* close socket: MDEV-10891 */
969 if (csock->socket != INVALID_SOCKET)
970 {
971 closesocket(csock->socket);
972 csock->socket= INVALID_SOCKET;
973 }
974 if (pvio->data)
975 {
976 free((gptr)pvio->data);
977 pvio->data= NULL;
978 }
979 return 1;
980}
981
982/* {{{ my_bool pvio_socket_close() */
983my_bool pvio_socket_close(MARIADB_PVIO *pvio)
984{
985 struct st_pvio_socket *csock= NULL;
986 int r= 0;
987
988 if (!pvio)
989 return 1;
990
991 if (pvio->data)
992 {
993 csock= (struct st_pvio_socket *)pvio->data;
994 if (csock && csock->socket != INVALID_SOCKET)
995 {
996 r= closesocket(csock->socket);
997 csock->socket= INVALID_SOCKET;
998 }
999 free((gptr)pvio->data);
1000 pvio->data= NULL;
1001 }
1002 return r;
1003}
1004/* }}} */
1005
1006/* {{{ my_socket pvio_socket_get_handle */
1007my_bool pvio_socket_get_handle(MARIADB_PVIO *pvio, void *handle)
1008{
1009 if (pvio && pvio->data && handle)
1010 {
1011 *(my_socket *)handle= ((struct st_pvio_socket *)pvio->data)->socket;
1012 return 0;
1013 }
1014 return 1;
1015}
1016/* }}} */
1017
1018/* {{{ my_bool pvio_socket_is_blocking(MARIADB_PVIO *pvio) */
1019my_bool pvio_socket_is_blocking(MARIADB_PVIO *pvio)
1020{
1021 struct st_pvio_socket *csock= NULL;
1022 my_bool r;
1023
1024 if (!pvio || !pvio->data)
1025 return 0;
1026
1027 csock= (struct st_pvio_socket *)pvio->data;
1028 r = !(csock->fcntl_mode & O_NONBLOCK);
1029 return r;
1030}
1031/* }}} */
1032
1033/* {{{ my_bool pvio_socket_is_alive(MARIADB_PVIO *pvio) */
1034my_bool pvio_socket_is_alive(MARIADB_PVIO *pvio)
1035{
1036 struct st_pvio_socket *csock= NULL;
1037 #ifndef _WIN32
1038 struct pollfd poll_fd;
1039#else
1040 FD_SET sfds;
1041 struct timeval tv= {0,0};
1042#endif
1043 int res;
1044
1045 if (!pvio || !pvio->data)
1046 return 0;
1047
1048 csock= (struct st_pvio_socket *)pvio->data;
1049#ifndef _WIN32
1050 memset(&poll_fd, 0, sizeof(struct pollfd));
1051 poll_fd.events= POLLPRI | POLLIN;
1052 poll_fd.fd= csock->socket;
1053
1054 res= poll(&poll_fd, 1, 0);
1055 if (res <= 0) /* timeout or error */
1056 return FALSE;
1057 if (!(poll_fd.revents & (POLLIN | POLLPRI)))
1058 return FALSE;
1059 return TRUE;
1060#else
1061 /* We can't use the WSAPoll function, it's broken :-(
1062 (see Windows 8 Bugs 309411 - WSAPoll does not report failed connections)
1063 Instead we need to use select function:
1064 If TIMEVAL is initialized to {0, 0}, select will return immediately;
1065 this is used to poll the state of the selected sockets.
1066 */
1067 FD_ZERO(&sfds);
1068 FD_SET(csock->socket, &sfds);
1069
1070 res= select((int)csock->socket + 1, &sfds, NULL, NULL, &tv);
1071 if (res > 0 && FD_ISSET(csock->socket, &sfds))
1072 return TRUE;
1073 return FALSE;
1074#endif
1075}
1076/* }}} */
1077
1078/* {{{ my_boool pvio_socket_has_data */
1079my_bool pvio_socket_has_data(MARIADB_PVIO *pvio, ssize_t *data_len)
1080{
1081 struct st_pvio_socket *csock= NULL;
1082 char tmp_buf;
1083 ssize_t len;
1084 my_bool mode;
1085
1086 if (!pvio || !pvio->data)
1087 return 0;
1088
1089 csock= (struct st_pvio_socket *)pvio->data;
1090 /* MSG_PEEK: Peeks at the incoming data. The data is copied into the buffer,
1091 but is not removed from the input queue.
1092 */
1093 pvio_socket_blocking(pvio, 0, &mode);
1094 len= recv(csock->socket, &tmp_buf, sizeof(tmp_buf), MSG_PEEK);
1095 pvio_socket_blocking(pvio, mode, 0);
1096 if (len < 0)
1097 return 1;
1098 *data_len= len;
1099 return 0;
1100}
1101/* }}} */
1102
1103int pvio_socket_shutdown(MARIADB_PVIO *pvio)
1104{
1105 if (pvio && pvio->data)
1106 {
1107 my_socket s = ((struct st_pvio_socket *)pvio->data)->socket;
1108#ifdef _WIN32
1109 shutdown(s, SD_BOTH);
1110 CancelIoEx((HANDLE)s, NULL);
1111#else
1112 shutdown(s, SHUT_RDWR);
1113#endif
1114 }
1115 return -1;
1116}
1117