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