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