1/* Copyright (c) 2000, 2016, Oracle and/or its affiliates.
2 Copyright (c) 2012, 2018, MariaDB Corporation.
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 as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
16
17/**
18 @file
19
20 This file is the net layer API for the MySQL client/server protocol.
21
22 Write and read of logical packets to/from socket.
23
24 Writes are cached into net_buffer_length big packets.
25 Read packets are reallocated dynamicly when reading big packets.
26 Each logical packet has the following pre-info:
27 3 byte length & 1 byte package-number.
28
29 This file needs to be written in C as it's used by the libmysql client as a
30 C file.
31*/
32
33/*
34 HFTODO this must be hidden if we don't want client capabilities in
35 embedded library
36 */
37
38#include "mariadb.h"
39#include <mysql.h>
40#include <mysql_com.h>
41#include <mysqld_error.h>
42#include <my_sys.h>
43#include <m_string.h>
44#include <my_net.h>
45#include <violite.h>
46#include <signal.h>
47#include "probes_mysql.h"
48#include "proxy_protocol.h"
49
50/*
51 to reduce the number of ifdef's in the code
52*/
53#ifdef EXTRA_DEBUG
54#define EXTRA_DEBUG_fprintf fprintf
55#define EXTRA_DEBUG_fflush fflush
56#define EXTRA_DEBUG_ASSERT DBUG_ASSERT
57#else
58static void inline EXTRA_DEBUG_fprintf(...) {}
59#ifndef MYSQL_SERVER
60static int inline EXTRA_DEBUG_fflush(...) { return 0; }
61#endif
62#endif /* EXTRA_DEBUG */
63
64#ifdef MYSQL_SERVER
65#include <sql_class.h>
66#include <sql_connect.h>
67#define MYSQL_SERVER_my_error my_error
68#else
69static void inline MYSQL_SERVER_my_error(...) {}
70#endif
71
72#ifndef EXTRA_DEBUG_ASSERT
73# define EXTRA_DEBUG_ASSERT(X) do {} while(0)
74#endif
75
76/*
77 The following handles the differences when this is linked between the
78 client and the server.
79
80 This gives an error if a too big packet is found.
81 The server can change this, but because the client can't normally do this
82 the client should have a bigger max_allowed_packet.
83*/
84
85#if defined(__WIN__) || !defined(MYSQL_SERVER)
86 /* The following is because alarms doesn't work on windows. */
87#ifndef NO_ALARM
88#define NO_ALARM
89#endif
90#endif
91
92#ifndef NO_ALARM
93#include "my_pthread.h"
94void sql_print_error(const char *format,...);
95#else
96#define DONT_USE_THR_ALARM
97#endif /* NO_ALARM */
98
99#include "thr_alarm.h"
100
101#ifdef MYSQL_SERVER
102/*
103 The following variables/functions should really not be declared
104 extern, but as it's hard to include sql_priv.h here, we have to
105 live with this for a while.
106*/
107extern uint test_flags;
108extern ulong bytes_sent, bytes_received, net_big_packet_count;
109#ifdef HAVE_QUERY_CACHE
110#define USE_QUERY_CACHE
111extern void query_cache_insert(void *thd, const char *packet, size_t length,
112 unsigned pkt_nr);
113#endif // HAVE_QUERY_CACHE
114#define update_statistics(A) A
115extern my_bool thd_net_is_killed(THD *thd);
116/* Additional instrumentation hooks for the server */
117#include "mysql_com_server.h"
118#else
119#define update_statistics(A)
120#define thd_net_is_killed(A) 0
121#endif
122
123
124static my_bool net_write_buff(NET *, const uchar *, size_t len);
125
126my_bool net_allocate_new_packet(NET *net, void *thd, uint my_flags);
127
128/** Init with packet info. */
129
130my_bool my_net_init(NET *net, Vio *vio, void *thd, uint my_flags)
131{
132 DBUG_ENTER("my_net_init");
133 DBUG_PRINT("enter", ("my_flags: %u", my_flags));
134 net->vio = vio;
135 my_net_local_init(net); /* Set some limits */
136
137 if (net_allocate_new_packet(net, thd, my_flags))
138 DBUG_RETURN(1);
139
140 net->error=0; net->return_status=0;
141 net->pkt_nr=net->compress_pkt_nr=0;
142 net->last_error[0]=0;
143 net->compress=0; net->reading_or_writing=0;
144 net->where_b = net->remain_in_buf=0;
145 net->net_skip_rest_factor= 0;
146 net->last_errno=0;
147 net->thread_specific_malloc= MY_TEST(my_flags & MY_THREAD_SPECIFIC);
148 net->thd= 0;
149#ifdef MYSQL_SERVER
150 net->extension= NULL;
151 net->thd= thd;
152#endif
153
154 if (vio)
155 {
156 /* For perl DBI/DBD. */
157 net->fd= vio_fd(vio);
158#if defined(MYSQL_SERVER) && !defined(__WIN__)
159 if (!(test_flags & TEST_BLOCKING))
160 {
161 my_bool old_mode;
162 vio_blocking(vio, FALSE, &old_mode);
163 }
164#endif
165 vio_fastsend(vio);
166 }
167 DBUG_RETURN(0);
168}
169
170my_bool net_allocate_new_packet(NET *net, void *thd, uint my_flags)
171{
172 DBUG_ENTER("net_allocate_new_packet");
173 if (!(net->buff=(uchar*) my_malloc((size_t) net->max_packet+
174 NET_HEADER_SIZE + COMP_HEADER_SIZE +1,
175 MYF(MY_WME | my_flags))))
176 DBUG_RETURN(1);
177 net->buff_end=net->buff+net->max_packet;
178 net->write_pos=net->read_pos = net->buff;
179 DBUG_RETURN(0);
180}
181
182
183void net_end(NET *net)
184{
185 DBUG_ENTER("net_end");
186 my_free(net->buff);
187 net->buff=0;
188 DBUG_VOID_RETURN;
189}
190
191
192/** Realloc the packet buffer. */
193
194my_bool net_realloc(NET *net, size_t length)
195{
196 uchar *buff;
197 size_t pkt_length;
198 DBUG_ENTER("net_realloc");
199 DBUG_PRINT("enter",("length: %lu", (ulong) length));
200
201 if (length >= net->max_packet_size)
202 {
203 DBUG_PRINT("error", ("Packet too large. Max size: %lu",
204 net->max_packet_size));
205 /* @todo: 1 and 2 codes are identical. */
206 net->error= 1;
207 net->last_errno= ER_NET_PACKET_TOO_LARGE;
208 MYSQL_SERVER_my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
209 DBUG_RETURN(1);
210 }
211 pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
212 /*
213 We must allocate some extra bytes for the end 0 and to be able to
214 read big compressed blocks + 1 safety byte since uint3korr() in
215 my_real_read() may actually read 4 bytes depending on build flags and
216 platform.
217 */
218 if (!(buff= (uchar*) my_realloc((char*) net->buff, pkt_length +
219 NET_HEADER_SIZE + COMP_HEADER_SIZE + 1,
220 MYF(MY_WME |
221 (net->thread_specific_malloc ?
222 MY_THREAD_SPECIFIC : 0)))))
223 {
224 /* @todo: 1 and 2 codes are identical. */
225 net->error= 1;
226 net->last_errno= ER_OUT_OF_RESOURCES;
227 /* In the server the error is reported by MY_WME flag. */
228 DBUG_RETURN(1);
229 }
230 net->buff=net->write_pos=buff;
231 net->buff_end=buff+(net->max_packet= (ulong) pkt_length);
232 DBUG_RETURN(0);
233}
234
235
236/**
237 Check if there is any data to be read from the socket.
238
239 @param sd socket descriptor
240
241 @retval
242 0 No data to read
243 @retval
244 1 Data or EOF to read
245 @retval
246 -1 Don't know if data is ready or not
247*/
248
249#if !defined(EMBEDDED_LIBRARY) && defined(DBUG_OFF)
250
251static int net_data_is_ready(my_socket sd)
252{
253#ifdef HAVE_POLL
254 struct pollfd ufds;
255 int res;
256
257 ufds.fd= sd;
258 ufds.events= POLLIN | POLLPRI;
259 if (!(res= poll(&ufds, 1, 0)))
260 return 0;
261 if (res < 0 || !(ufds.revents & (POLLIN | POLLPRI)))
262 return 0;
263 return 1;
264#else
265 fd_set sfds;
266 struct timeval tv;
267 int res;
268
269#ifndef __WIN__
270 /* Windows uses an _array_ of 64 fd's as default, so it's safe */
271 if (sd >= FD_SETSIZE)
272 return -1;
273#define NET_DATA_IS_READY_CAN_RETURN_MINUS_ONE
274#endif
275
276 FD_ZERO(&sfds);
277 FD_SET(sd, &sfds);
278
279 tv.tv_sec= tv.tv_usec= 0;
280
281 if ((res= select((int) (sd + 1), &sfds, NULL, NULL, &tv)) < 0)
282 return 0;
283 else
284 return MY_TEST(res ? FD_ISSET(sd, &sfds) : 0);
285#endif /* HAVE_POLL */
286}
287
288#endif /* EMBEDDED_LIBRARY */
289
290/**
291 Clear (reinitialize) the NET structure for a new command.
292
293 @remark Performs debug checking of the socket buffer to
294 ensure that the protocol sequence is correct.
295
296 - Read from socket until there is nothing more to read. Discard
297 what is read.
298 - Initialize net for new net_read/net_write calls.
299
300 If there is anything when to read 'net_clear' is called this
301 normally indicates an error in the protocol. Normally one should not
302 need to do clear the communication buffer. If one compiles without
303 -DUSE_NET_CLEAR then one wins one read call / query.
304
305 When connection is properly closed (for TCP it means with
306 a FIN packet), then select() considers a socket "ready to read",
307 in the sense that there's EOF to read, but read() returns 0.
308
309 @param net NET handler
310 @param clear_buffer if <> 0, then clear all data from comm buff
311*/
312
313void net_clear(NET *net, my_bool clear_buffer __attribute__((unused)))
314{
315 DBUG_ENTER("net_clear");
316
317/*
318 We don't do a clear in case of not DBUG_OFF to catch bugs in the
319 protocol handling.
320*/
321
322#if (!defined(EMBEDDED_LIBRARY) && defined(DBUG_OFF)) || defined(USE_NET_CLEAR)
323 if (clear_buffer)
324 {
325 size_t count;
326 int ready;
327 while ((ready= net_data_is_ready(vio_fd(net->vio))) > 0)
328 {
329 /* The socket is ready */
330 if ((long) (count= vio_read(net->vio, net->buff,
331 (size_t) net->max_packet)) > 0)
332 {
333 DBUG_PRINT("info",("skipped %ld bytes from file: %s",
334 (long) count, vio_description(net->vio)));
335 EXTRA_DEBUG_fprintf(stderr,"Note: net_clear() skipped %ld bytes from file: %s\n",
336 (long) count, vio_description(net->vio));
337 }
338 else
339 {
340 DBUG_PRINT("info",("socket ready but only EOF to read - disconnected"));
341 net->error= 2;
342 break;
343 }
344 }
345#ifdef NET_DATA_IS_READY_CAN_RETURN_MINUS_ONE
346 /* 'net_data_is_ready' returned "don't know" */
347 if (ready == -1)
348 {
349 /* Read unblocking to clear net */
350 my_bool old_mode;
351 if (!vio_blocking(net->vio, FALSE, &old_mode))
352 {
353 while ((long) (count= vio_read(net->vio, net->buff,
354 (size_t) net->max_packet)) > 0)
355 DBUG_PRINT("info",("skipped %ld bytes from file: %s",
356 (long) count, vio_description(net->vio)));
357 vio_blocking(net->vio, TRUE, &old_mode);
358 }
359 }
360#endif /* NET_DATA_IS_READY_CAN_RETURN_MINUS_ONE */
361 }
362#endif /* EMBEDDED_LIBRARY */
363 net->pkt_nr=net->compress_pkt_nr=0; /* Ready for new command */
364 net->write_pos=net->buff;
365 DBUG_VOID_RETURN;
366}
367
368
369/** Flush write_buffer if not empty. */
370
371my_bool net_flush(NET *net)
372{
373 my_bool error= 0;
374 DBUG_ENTER("net_flush");
375 if (net->buff != net->write_pos)
376 {
377 error= MY_TEST(net_real_write(net, net->buff,
378 (size_t) (net->write_pos - net->buff)));
379 net->write_pos= net->buff;
380 }
381 /* Sync packet number if using compression */
382 if (net->compress)
383 net->pkt_nr=net->compress_pkt_nr;
384 DBUG_RETURN(error);
385}
386
387
388/*****************************************************************************
389** Write something to server/client buffer
390*****************************************************************************/
391
392/**
393 Write a logical packet with packet header.
394
395 Format: Packet length (3 bytes), packet number (1 byte)
396 When compression is used, a 3 byte compression length is added.
397
398 @note If compression is used, the original packet is modified!
399*/
400
401my_bool my_net_write(NET *net, const uchar *packet, size_t len)
402{
403 uchar buff[NET_HEADER_SIZE];
404 int rc;
405
406 if (unlikely(!net->vio)) /* nowhere to write */
407 return 0;
408
409 MYSQL_NET_WRITE_START(len);
410
411 /*
412 Big packets are handled by splitting them in packets of MAX_PACKET_LENGTH
413 length. The last packet is always a packet that is < MAX_PACKET_LENGTH.
414 (The last packet may even have a length of 0)
415 */
416 while (len >= MAX_PACKET_LENGTH)
417 {
418 const ulong z_size = MAX_PACKET_LENGTH;
419 int3store(buff, z_size);
420 buff[3]= (uchar) net->pkt_nr++;
421 if (net_write_buff(net, buff, NET_HEADER_SIZE) ||
422 net_write_buff(net, packet, z_size))
423 {
424 MYSQL_NET_WRITE_DONE(1);
425 return 1;
426 }
427 packet += z_size;
428 len-= z_size;
429 }
430 /* Write last packet */
431 int3store(buff,len);
432 buff[3]= (uchar) net->pkt_nr++;
433 if (net_write_buff(net, buff, NET_HEADER_SIZE))
434 {
435 MYSQL_NET_WRITE_DONE(1);
436 return 1;
437 }
438#ifndef DEBUG_DATA_PACKETS
439 DBUG_DUMP("packet_header", buff, NET_HEADER_SIZE);
440#endif
441 rc= MY_TEST(net_write_buff(net, packet, len));
442 MYSQL_NET_WRITE_DONE(rc);
443 return rc;
444}
445
446
447/**
448 Send a command to the server.
449
450 The reason for having both header and packet is so that libmysql
451 can easy add a header to a special command (like prepared statements)
452 without having to re-alloc the string.
453
454 As the command is part of the first data packet, we have to do some data
455 juggling to put the command in there, without having to create a new
456 packet.
457
458 This function will split big packets into sub-packets if needed.
459 (Each sub packet can only be 2^24 bytes)
460
461 @param net NET handler
462 @param command Command in MySQL server (enum enum_server_command)
463 @param header Header to write after command
464 @param head_len Length of header
465 @param packet Query or parameter to query
466 @param len Length of packet
467
468 @retval
469 0 ok
470 @retval
471 1 error
472*/
473
474my_bool
475net_write_command(NET *net,uchar command,
476 const uchar *header, size_t head_len,
477 const uchar *packet, size_t len)
478{
479 size_t length=len+1+head_len; /* 1 extra byte for command */
480 uchar buff[NET_HEADER_SIZE+1];
481 uint header_size=NET_HEADER_SIZE+1;
482 int rc;
483 DBUG_ENTER("net_write_command");
484 DBUG_PRINT("enter",("length: %lu", (ulong) len));
485
486 MYSQL_NET_WRITE_START(length);
487
488 buff[4]=command; /* For first packet */
489
490 if (length >= MAX_PACKET_LENGTH)
491 {
492 /* Take into account that we have the command in the first header */
493 len= MAX_PACKET_LENGTH - 1 - head_len;
494 do
495 {
496 int3store(buff, MAX_PACKET_LENGTH);
497 buff[3]= (uchar) net->pkt_nr++;
498 if (net_write_buff(net, buff, header_size) ||
499 net_write_buff(net, header, head_len) ||
500 net_write_buff(net, packet, len))
501 {
502 MYSQL_NET_WRITE_DONE(1);
503 DBUG_RETURN(1);
504 }
505 packet+= len;
506 length-= MAX_PACKET_LENGTH;
507 len= MAX_PACKET_LENGTH;
508 head_len= 0;
509 header_size= NET_HEADER_SIZE;
510 } while (length >= MAX_PACKET_LENGTH);
511 len=length; /* Data left to be written */
512 }
513 int3store(buff,length);
514 buff[3]= (uchar) net->pkt_nr++;
515 rc= MY_TEST(net_write_buff(net, buff, header_size) ||
516 (head_len && net_write_buff(net, header, head_len)) ||
517 net_write_buff(net, packet, len) || net_flush(net));
518 MYSQL_NET_WRITE_DONE(rc);
519 DBUG_RETURN(rc);
520}
521
522/**
523 Caching the data in a local buffer before sending it.
524
525 Fill up net->buffer and send it to the client when full.
526
527 If the rest of the to-be-sent-packet is bigger than buffer,
528 send it in one big block (to avoid copying to internal buffer).
529 If not, copy the rest of the data to the buffer and return without
530 sending data.
531
532 @param net Network handler
533 @param packet Packet to send
534 @param len Length of packet
535
536 @note
537 The cached buffer can be sent as it is with 'net_flush()'.
538 In this code we have to be careful to not send a packet longer than
539 MAX_PACKET_LENGTH to net_real_write() if we are using the compressed
540 protocol as we store the length of the compressed packet in 3 bytes.
541
542 @retval
543 0 ok
544 @retval
545 1
546*/
547
548static my_bool
549net_write_buff(NET *net, const uchar *packet, size_t len)
550{
551 size_t left_length;
552 if (net->compress && net->max_packet > MAX_PACKET_LENGTH)
553 left_length= (MAX_PACKET_LENGTH - (net->write_pos - net->buff));
554 else
555 left_length= (net->buff_end - net->write_pos);
556
557#ifdef DEBUG_DATA_PACKETS
558 DBUG_DUMP("data_written", packet, len);
559#endif
560 if (len > left_length)
561 {
562 if (net->write_pos != net->buff)
563 {
564 /* Fill up already used packet and write it */
565 memcpy((char*) net->write_pos,packet,left_length);
566 if (net_real_write(net, net->buff,
567 (size_t) (net->write_pos - net->buff) + left_length))
568 return 1;
569 net->write_pos= net->buff;
570 packet+= left_length;
571 len-= left_length;
572 }
573 if (net->compress)
574 {
575 /*
576 We can't have bigger packets than 16M with compression
577 Because the uncompressed length is stored in 3 bytes
578 */
579 left_length= MAX_PACKET_LENGTH;
580 while (len > left_length)
581 {
582 if (net_real_write(net, packet, left_length))
583 return 1;
584 packet+= left_length;
585 len-= left_length;
586 }
587 }
588 if (len > net->max_packet)
589 return net_real_write(net, packet, len) ? 1 : 0;
590 /* Send out rest of the blocks as full sized blocks */
591 }
592 memcpy((char*) net->write_pos,packet,len);
593 net->write_pos+= len;
594 return 0;
595}
596
597
598/**
599 Read and write one packet using timeouts.
600 If needed, the packet is compressed before sending.
601
602 @todo
603 - TODO is it needed to set this variable if we have no socket
604*/
605
606int
607net_real_write(NET *net,const uchar *packet, size_t len)
608{
609 size_t length;
610 const uchar *pos,*end;
611 thr_alarm_t alarmed;
612#ifndef NO_ALARM
613 ALARM alarm_buff;
614#endif
615 uint retry_count=0;
616 my_bool net_blocking = vio_is_blocking(net->vio);
617 DBUG_ENTER("net_real_write");
618
619#if defined(MYSQL_SERVER) && defined(USE_QUERY_CACHE)
620 query_cache_insert(net->thd, (char*) packet, len, net->pkt_nr);
621#endif
622
623 if (unlikely(net->error == 2))
624 DBUG_RETURN(-1); /* socket can't be used */
625
626 net->reading_or_writing=2;
627#ifdef HAVE_COMPRESS
628 if (net->compress)
629 {
630 size_t complen;
631 uchar *b;
632 uint header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
633 if (!(b= (uchar*) my_malloc(len + NET_HEADER_SIZE +
634 COMP_HEADER_SIZE + 1,
635 MYF(MY_WME |
636 (net->thread_specific_malloc ?
637 MY_THREAD_SPECIFIC : 0)))))
638 {
639 net->error= 2;
640 net->last_errno= ER_OUT_OF_RESOURCES;
641 /* In the server, the error is reported by MY_WME flag. */
642 net->reading_or_writing= 0;
643 DBUG_RETURN(1);
644 }
645 memcpy(b+header_length,packet,len);
646
647 /* Don't compress error packets (compress == 2) */
648 if (net->compress == 2 || my_compress(b+header_length, &len, &complen))
649 complen=0;
650 int3store(&b[NET_HEADER_SIZE],complen);
651 int3store(b,len);
652 b[3]=(uchar) (net->compress_pkt_nr++);
653 len+= header_length;
654 packet= b;
655 }
656#endif /* HAVE_COMPRESS */
657
658#ifdef DEBUG_DATA_PACKETS
659 DBUG_DUMP("data_written", packet, len);
660#endif
661
662#ifndef NO_ALARM
663 thr_alarm_init(&alarmed);
664 if (net_blocking)
665 thr_alarm(&alarmed, net->write_timeout, &alarm_buff);
666#else
667 alarmed=0;
668 /* Write timeout is set in my_net_set_write_timeout */
669#endif /* NO_ALARM */
670
671 pos= packet;
672 end=pos+len;
673 while (pos != end)
674 {
675 if ((long) (length= vio_write(net->vio,pos,(size_t) (end-pos))) <= 0)
676 {
677 my_bool interrupted = vio_should_retry(net->vio);
678#if !defined(__WIN__)
679 if ((interrupted || length == 0) && !thr_alarm_in_use(&alarmed))
680 {
681 if (!thr_alarm(&alarmed, net->write_timeout, &alarm_buff))
682 { /* Always true for client */
683 my_bool old_mode;
684 while (vio_blocking(net->vio, TRUE, &old_mode) < 0)
685 {
686 if (vio_should_retry(net->vio) && retry_count++ < net->retry_count)
687 continue;
688 EXTRA_DEBUG_fprintf(stderr,
689 "%s: my_net_write: fcntl returned error %d, aborting thread\n",
690 my_progname,vio_errno(net->vio));
691 net->error= 2; /* Close socket */
692 net->last_errno= ER_NET_PACKET_TOO_LARGE;
693 MYSQL_SERVER_my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
694 goto end;
695 }
696 retry_count=0;
697 continue;
698 }
699 }
700 else
701#endif /* !defined(__WIN__) */
702 if (thr_alarm_in_use(&alarmed) && !thr_got_alarm(&alarmed) &&
703 interrupted)
704 {
705 if (retry_count++ < net->retry_count)
706 continue;
707 EXTRA_DEBUG_fprintf(stderr, "%s: write looped, aborting thread\n",
708 my_progname);
709 }
710#ifndef MYSQL_SERVER
711 if (vio_errno(net->vio) == SOCKET_EINTR)
712 {
713 DBUG_PRINT("warning",("Interrupted write. Retrying..."));
714 continue;
715 }
716#endif /* !defined(MYSQL_SERVER) */
717 net->error= 2; /* Close socket */
718 net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
719 ER_NET_ERROR_ON_WRITE);
720 MYSQL_SERVER_my_error(net->last_errno, MYF(0));
721 break;
722 }
723 pos+=length;
724 update_statistics(thd_increment_bytes_sent(net->thd, length));
725 }
726#ifndef __WIN__
727 end:
728#endif
729#ifdef HAVE_COMPRESS
730 if (net->compress)
731 my_free((void*) packet);
732#endif
733 if (thr_alarm_in_use(&alarmed))
734 {
735 my_bool old_mode;
736 thr_end_alarm(&alarmed);
737 if (!net_blocking)
738 vio_blocking(net->vio, net_blocking, &old_mode);
739 }
740 net->reading_or_writing=0;
741 DBUG_RETURN(((int) (pos != end)));
742}
743
744
745/*****************************************************************************
746** Read something from server/clinet
747*****************************************************************************/
748
749#ifndef NO_ALARM
750
751static my_bool net_safe_read(NET *net, uchar *buff, size_t length,
752 thr_alarm_t *alarmed)
753{
754 uint retry_count=0;
755 while (length > 0)
756 {
757 size_t tmp;
758 if ((long) (tmp= vio_read(net->vio, buff, length)) <= 0)
759 {
760 my_bool interrupted = vio_should_retry(net->vio);
761 if (!thr_got_alarm(alarmed) && interrupted)
762 { /* Probably in MIT threads */
763 if (retry_count++ < net->retry_count)
764 continue;
765 }
766 return 1;
767 }
768 length-= tmp;
769 buff+= tmp;
770 }
771 return 0;
772}
773
774/**
775 Help function to clear the commuication buffer when we get a too big packet.
776
777 @param net Communication handle
778 @param remain Bytes to read
779 @param alarmed Parameter for thr_alarm()
780 @param alarm_buff Parameter for thr_alarm()
781
782 @retval
783 0 Was able to read the whole packet
784 @retval
785 1 Got mailformed packet from client
786*/
787
788static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed,
789 ALARM *alarm_buff)
790{
791 longlong limit= net->max_packet_size*net->net_skip_rest_factor;
792 uint32 old=remain;
793 DBUG_ENTER("my_net_skip_rest");
794 DBUG_PRINT("enter",("bytes_to_skip: %u", (uint) remain));
795
796 /* The following is good for debugging */
797 update_statistics(thd_increment_net_big_packet_count(net->thd, 1));
798
799 if (!thr_alarm_in_use(alarmed))
800 {
801 my_bool old_mode;
802 if (thr_alarm(alarmed,net->read_timeout, alarm_buff) ||
803 vio_blocking(net->vio, TRUE, &old_mode) < 0)
804 DBUG_RETURN(1); /* Can't setup, abort */
805 }
806 for (;;)
807 {
808 while (remain > 0)
809 {
810 size_t length= MY_MIN(remain, net->max_packet);
811 if (net_safe_read(net, net->buff, length, alarmed))
812 DBUG_RETURN(1);
813 update_statistics(thd_increment_bytes_received(net->thd, length));
814 remain -= (uint32) length;
815 limit-= length;
816 if (limit < 0)
817 DBUG_RETURN(1);
818 }
819 if (old != MAX_PACKET_LENGTH)
820 break;
821 if (net_safe_read(net, net->buff, NET_HEADER_SIZE, alarmed))
822 DBUG_RETURN(1);
823 limit-= NET_HEADER_SIZE;
824 old=remain= uint3korr(net->buff);
825 net->pkt_nr++;
826 }
827 DBUG_RETURN(0);
828}
829#endif /* NO_ALARM */
830
831
832/**
833 Try to parse and process proxy protocol header.
834
835 This function is called in case MySQL packet header cannot be parsed.
836 It checks if proxy header was sent, and that it was send from allowed remote
837 host, as defined by proxy-protocol-networks parameter.
838
839 If proxy header is parsed, then THD and ACL structures and changed to indicate
840 the new peer address and port.
841
842 Note, that proxy header can only be sent either when the connection is established,
843 or as the client reply packet to
844*/
845#undef IGNORE /* for Windows */
846typedef enum { RETRY, ABORT, IGNORE} handle_proxy_header_result;
847static handle_proxy_header_result handle_proxy_header(NET *net)
848{
849#if !defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY)
850 return IGNORE;
851#else
852 THD *thd= (THD *)net->thd;
853
854 if (!has_proxy_protocol_header(net) || !thd ||
855 thd->get_command() != COM_CONNECT)
856 return IGNORE;
857
858 /*
859 Proxy information found in the first 4 bytes received so far.
860 Read and parse proxy header , change peer ip address and port in THD.
861 */
862 proxy_peer_info peer_info;
863
864 if (!thd->net.vio)
865 {
866 DBUG_ASSERT(0);
867 return ABORT;
868 }
869
870 if (!is_proxy_protocol_allowed((sockaddr *)&(thd->net.vio->remote)))
871 {
872 /* proxy-protocol-networks variable needs to be set to allow this remote address */
873 my_printf_error(ER_HOST_NOT_PRIVILEGED, "Proxy header is not accepted from %s",
874 MYF(0), thd->main_security_ctx.ip);
875 return ABORT;
876 }
877
878 if (parse_proxy_protocol_header(net, &peer_info))
879 {
880 /* Failed to parse proxy header*/
881 my_printf_error(ER_UNKNOWN_ERROR, "Failed to parse proxy header", MYF(0));
882 return ABORT;
883 }
884
885 if (peer_info.is_local_command)
886 /* proxy header indicates LOCAL connection, no action necessary */
887 return RETRY;
888 /* Change peer address in THD and ACL structures.*/
889 uint host_errors;
890 return (handle_proxy_header_result)thd_set_peer_addr(thd,
891 &(peer_info.peer_addr), NULL, peer_info.port,
892 false, &host_errors);
893#endif
894}
895
896/**
897 Reads one packet to net->buff + net->where_b.
898 Long packets are handled by my_net_read().
899 This function reallocates the net->buff buffer if necessary.
900
901 @return
902 Returns length of packet.
903*/
904
905static ulong
906my_real_read(NET *net, size_t *complen,
907 my_bool header __attribute__((unused)))
908{
909 uchar *pos;
910 size_t length;
911 uint i,retry_count=0;
912 ulong len=packet_error;
913 my_bool expect_error_packet __attribute__((unused))= 0;
914 thr_alarm_t alarmed;
915#ifndef NO_ALARM
916 ALARM alarm_buff;
917#endif
918
919retry:
920
921 my_bool net_blocking=vio_is_blocking(net->vio);
922 uint32 remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
923 NET_HEADER_SIZE);
924#ifdef MYSQL_SERVER
925 size_t count= remain;
926 struct st_net_server *server_extension= 0;
927
928 if (header)
929 {
930 server_extension= static_cast<st_net_server*> (net->extension);
931 if (server_extension != NULL)
932 {
933 void *user_data= server_extension->m_user_data;
934 server_extension->m_before_header(net, user_data, count);
935 }
936 }
937#endif
938
939 *complen = 0;
940
941 net->reading_or_writing=1;
942 thr_alarm_init(&alarmed);
943#ifndef NO_ALARM
944 if (net_blocking)
945 thr_alarm(&alarmed,net->read_timeout,&alarm_buff);
946#else
947 /* Read timeout is set in my_net_set_read_timeout */
948#endif /* NO_ALARM */
949
950 pos = net->buff + net->where_b; /* net->packet -4 */
951 for (i=0 ; i < 2 ; i++)
952 {
953 while (remain > 0)
954 {
955 /* First read is done with non blocking mode */
956 if ((long) (length= vio_read(net->vio, pos, remain)) <= 0L)
957 {
958 my_bool interrupted = vio_should_retry(net->vio);
959
960 DBUG_PRINT("info",("vio_read returned %ld errno: %d",
961 (long) length, vio_errno(net->vio)));
962
963 if (i== 0 && unlikely(thd_net_is_killed((THD*) net->thd)))
964 {
965 DBUG_PRINT("info", ("thd is killed"));
966 len= packet_error;
967 net->error= 0;
968 net->last_errno= ER_CONNECTION_KILLED;
969 MYSQL_SERVER_my_error(net->last_errno, MYF(0));
970 goto end;
971 }
972
973#if !defined(__WIN__) && defined(MYSQL_SERVER)
974 /*
975 We got an error that there was no data on the socket. We now set up
976 an alarm to not 'read forever', change the socket to the blocking
977 mode and try again
978 */
979 if ((interrupted || length == 0) && !thr_alarm_in_use(&alarmed))
980 {
981 if (!thr_alarm(&alarmed,net->read_timeout,&alarm_buff)) /* Don't wait too long */
982 {
983 my_bool old_mode;
984 while (vio_blocking(net->vio, TRUE, &old_mode) < 0)
985 {
986 if (vio_should_retry(net->vio) &&
987 retry_count++ < net->retry_count)
988 continue;
989 DBUG_PRINT("error",
990 ("fcntl returned error %d, aborting thread",
991 vio_errno(net->vio)));
992 EXTRA_DEBUG_fprintf(stderr,
993 "%s: read: fcntl returned error %d, aborting thread\n",
994 my_progname,vio_errno(net->vio));
995 len= packet_error;
996 net->error= 2; /* Close socket */
997 net->last_errno= ER_NET_FCNTL_ERROR;
998 MYSQL_SERVER_my_error(ER_NET_FCNTL_ERROR, MYF(0));
999 goto end;
1000 }
1001 retry_count=0;
1002 continue;
1003 }
1004 }
1005#endif /* (!defined(__WIN__) && defined(MYSQL_SERVER) */
1006 if (thr_alarm_in_use(&alarmed) && !thr_got_alarm(&alarmed) &&
1007 interrupted)
1008 { /* Probably in MIT threads */
1009 if (retry_count++ < net->retry_count)
1010 continue;
1011 EXTRA_DEBUG_fprintf(stderr, "%s: read looped with error %d, aborting thread\n",
1012 my_progname,vio_errno(net->vio));
1013 }
1014#ifndef MYSQL_SERVER
1015 if (length != 0 && vio_errno(net->vio) == SOCKET_EINTR)
1016 {
1017 DBUG_PRINT("warning",("Interrupted read. Retrying..."));
1018 continue;
1019 }
1020#endif
1021 DBUG_PRINT("error",("Couldn't read packet: remain: %u errno: %d length: %ld",
1022 remain, vio_errno(net->vio), (long) length));
1023 len= packet_error;
1024 net->error= 2; /* Close socket */
1025 net->last_errno= (vio_was_timeout(net->vio) ?
1026 ER_NET_READ_INTERRUPTED :
1027 ER_NET_READ_ERROR);
1028 MYSQL_SERVER_my_error(net->last_errno, MYF(0));
1029 goto end;
1030 }
1031 remain -= (uint32) length;
1032 pos+= length;
1033 update_statistics(thd_increment_bytes_received(net->thd, length));
1034 }
1035
1036#ifdef DEBUG_DATA_PACKETS
1037 DBUG_DUMP("data_read", net->buff+net->where_b, length);
1038#endif
1039 if (i == 0)
1040 { /* First parts is packet length */
1041 size_t helping;
1042#ifndef DEBUG_DATA_PACKETS
1043 DBUG_DUMP("packet_header", net->buff+net->where_b,
1044 NET_HEADER_SIZE);
1045#endif
1046 if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)
1047 {
1048#ifndef MYSQL_SERVER
1049 if (net->buff[net->where_b + 3] == (uchar) (net->pkt_nr -1))
1050 {
1051 /*
1052 If the server was killed then the server may have missed the
1053 last sent client packet and the packet numbering may be one off.
1054 */
1055 DBUG_PRINT("warning", ("Found possible out of order packets"));
1056 expect_error_packet= 1;
1057 }
1058 else
1059#endif
1060 goto packets_out_of_order;
1061 }
1062 net->compress_pkt_nr= ++net->pkt_nr;
1063#ifdef HAVE_COMPRESS
1064 if (net->compress)
1065 {
1066 /*
1067 The following uint3korr() may read 4 bytes, so make sure we don't
1068 read unallocated or uninitialized memory. The right-hand expression
1069 must match the size of the buffer allocated in net_realloc().
1070 */
1071 DBUG_ASSERT(net->where_b + NET_HEADER_SIZE + sizeof(uint32) <=
1072 net->max_packet + NET_HEADER_SIZE + COMP_HEADER_SIZE + 1);
1073 /*
1074 If the packet is compressed then complen > 0 and contains the
1075 number of bytes in the uncompressed packet
1076 */
1077 *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
1078 }
1079#endif
1080
1081 len=uint3korr(net->buff+net->where_b);
1082 if (!len) /* End of big multi-packet */
1083 goto end;
1084 helping = MY_MAX(len,*complen) + net->where_b;
1085 /* The necessary size of net->buff */
1086 if (helping >= net->max_packet)
1087 {
1088 if (net_realloc(net,helping))
1089 {
1090#if defined(MYSQL_SERVER) && !defined(NO_ALARM)
1091 if (!net->compress &&
1092 !my_net_skip_rest(net, (uint32) len, &alarmed, &alarm_buff))
1093 net->error= 3; /* Successfully skiped packet */
1094#endif
1095 len= packet_error; /* Return error and close connection */
1096 goto end;
1097 }
1098 }
1099 pos=net->buff + net->where_b;
1100 remain = (uint32) len;
1101#ifdef MYSQL_SERVER
1102 if (server_extension != NULL)
1103 {
1104 void *user_data= server_extension->m_user_data;
1105 server_extension->m_after_header(net, user_data, count, 0);
1106 server_extension= NULL;
1107 }
1108#endif
1109 }
1110#ifndef MYSQL_SERVER
1111 else if (expect_error_packet)
1112 {
1113 /*
1114 This check is safe both for compressed and not compressed protocol
1115 as for the compressed protocol errors are not compressed anymore.
1116 */
1117 if (net->buff[net->where_b] != (uchar) 255)
1118 {
1119 /* Restore pkt_nr to original value */
1120 net->pkt_nr--;
1121 goto packets_out_of_order;
1122 }
1123 }
1124#endif
1125 }
1126
1127end:
1128 if (thr_alarm_in_use(&alarmed))
1129 {
1130 my_bool old_mode;
1131 thr_end_alarm(&alarmed);
1132 if (!net_blocking)
1133 vio_blocking(net->vio, net_blocking, &old_mode);
1134 }
1135 net->reading_or_writing=0;
1136#ifdef DEBUG_DATA_PACKETS
1137 if (len != packet_error)
1138 DBUG_DUMP("data_read", net->buff+net->where_b, len);
1139#endif
1140#ifdef MYSQL_SERVER
1141 if (server_extension != NULL)
1142 {
1143 void *user_data= server_extension->m_user_data;
1144 server_extension->m_after_header(net, user_data, count, 1);
1145 DBUG_ASSERT(len == packet_error || len == 0);
1146 }
1147#endif
1148 return(len);
1149
1150packets_out_of_order:
1151 {
1152 switch (handle_proxy_header(net)) {
1153 case ABORT:
1154 /* error happened, message is already written. */
1155 len= packet_error;
1156 goto end;
1157 case RETRY:
1158 goto retry;
1159 case IGNORE:
1160 break;
1161 }
1162
1163 DBUG_PRINT("error",
1164 ("Packets out of order (Found: %d, expected %u)",
1165 (int) net->buff[net->where_b + 3],
1166 net->pkt_nr));
1167 EXTRA_DEBUG_ASSERT(0);
1168 /*
1169 We don't make noise server side, since the client is expected
1170 to break the protocol for e.g. --send LOAD DATA .. LOCAL where
1171 the server expects the client to send a file, but the client
1172 may reply with a new command instead.
1173 */
1174#ifndef MYSQL_SERVER
1175 EXTRA_DEBUG_fflush(stdout);
1176 EXTRA_DEBUG_fprintf(stderr,"Error: Packets out of order (Found: %d, expected %d)\n",
1177 (int) net->buff[net->where_b + 3],
1178 (uint) (uchar) net->pkt_nr);
1179 EXTRA_DEBUG_fflush(stderr);
1180#endif
1181 len= packet_error;
1182 MYSQL_SERVER_my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0));
1183 goto end;
1184 }
1185}
1186
1187
1188
1189/* Old interface. See my_net_read_packet() for function description */
1190
1191#undef my_net_read
1192
1193ulong my_net_read(NET *net)
1194{
1195 return my_net_read_packet(net, 0);
1196}
1197
1198
1199/**
1200 Read a packet from the client/server and return it without the internal
1201 package header.
1202
1203 If the packet is the first packet of a multi-packet packet
1204 (which is indicated by the length of the packet = 0xffffff) then
1205 all sub packets are read and concatenated.
1206
1207 If the packet was compressed, its uncompressed and the length of the
1208 uncompressed packet is returned.
1209
1210 read_from_server is set when the server is reading a new command
1211 from the client.
1212
1213 @return
1214 The function returns the length of the found packet or packet_error.
1215 net->read_pos points to the read data.
1216*/
1217ulong
1218my_net_read_packet(NET *net, my_bool read_from_server)
1219{
1220 ulong reallen = 0;
1221 return my_net_read_packet_reallen(net, read_from_server, &reallen);
1222}
1223
1224
1225ulong
1226my_net_read_packet_reallen(NET *net, my_bool read_from_server, ulong* reallen)
1227{
1228 size_t len, complen;
1229
1230 MYSQL_NET_READ_START();
1231
1232 *reallen = 0;
1233#ifdef HAVE_COMPRESS
1234 if (!net->compress)
1235 {
1236#endif
1237 len = my_real_read(net,&complen, read_from_server);
1238 if (len == MAX_PACKET_LENGTH)
1239 {
1240 /* First packet of a multi-packet. Concatenate the packets */
1241 ulong save_pos = net->where_b;
1242 size_t total_length= 0;
1243 do
1244 {
1245 net->where_b += (ulong)len;
1246 total_length += len;
1247 len = my_real_read(net,&complen, 0);
1248 } while (len == MAX_PACKET_LENGTH);
1249 if (likely(len != packet_error))
1250 len+= total_length;
1251 net->where_b = save_pos;
1252 }
1253
1254 net->read_pos = net->buff + net->where_b;
1255 if (likely(len != packet_error))
1256 {
1257 net->read_pos[len]=0; /* Safeguard for mysql_use_result */
1258 *reallen = (ulong)len;
1259 }
1260 MYSQL_NET_READ_DONE(0, len);
1261 return (ulong)len;
1262#ifdef HAVE_COMPRESS
1263 }
1264 else
1265 {
1266 /* We are using the compressed protocol */
1267
1268 ulong buf_length;
1269 ulong start_of_packet;
1270 ulong first_packet_offset;
1271 uint read_length, multi_byte_packet=0;
1272
1273 if (net->remain_in_buf)
1274 {
1275 buf_length= net->buf_length; /* Data left in old packet */
1276 first_packet_offset= start_of_packet= (net->buf_length -
1277 net->remain_in_buf);
1278 /* Restore the character that was overwritten by the end 0 */
1279 net->buff[start_of_packet]= net->save_char;
1280 }
1281 else
1282 {
1283 /* reuse buffer, as there is nothing in it that we need */
1284 buf_length= start_of_packet= first_packet_offset= 0;
1285 }
1286 for (;;)
1287 {
1288 ulong packet_len;
1289
1290 if (buf_length - start_of_packet >= NET_HEADER_SIZE)
1291 {
1292 read_length = uint3korr(net->buff+start_of_packet);
1293 if (!read_length)
1294 {
1295 /* End of multi-byte packet */
1296 start_of_packet += NET_HEADER_SIZE;
1297 break;
1298 }
1299 if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet)
1300 {
1301 if (multi_byte_packet)
1302 {
1303 /* Remove packet header for second packet */
1304 memmove(net->buff + first_packet_offset + start_of_packet,
1305 net->buff + first_packet_offset + start_of_packet +
1306 NET_HEADER_SIZE,
1307 buf_length - start_of_packet);
1308 start_of_packet += read_length;
1309 buf_length -= NET_HEADER_SIZE;
1310 }
1311 else
1312 start_of_packet+= read_length + NET_HEADER_SIZE;
1313
1314 if (read_length != MAX_PACKET_LENGTH) /* last package */
1315 {
1316 multi_byte_packet= 0; /* No last zero len packet */
1317 break;
1318 }
1319 multi_byte_packet= NET_HEADER_SIZE;
1320 /* Move data down to read next data packet after current one */
1321 if (first_packet_offset)
1322 {
1323 memmove(net->buff,net->buff+first_packet_offset,
1324 buf_length-first_packet_offset);
1325 buf_length-=first_packet_offset;
1326 start_of_packet -= first_packet_offset;
1327 first_packet_offset=0;
1328 }
1329 continue;
1330 }
1331 }
1332 /* Move data down to read next data packet after current one */
1333 if (first_packet_offset)
1334 {
1335 memmove(net->buff,net->buff+first_packet_offset,
1336 buf_length-first_packet_offset);
1337 buf_length-=first_packet_offset;
1338 start_of_packet -= first_packet_offset;
1339 first_packet_offset=0;
1340 }
1341
1342 net->where_b=buf_length;
1343 if ((packet_len = my_real_read(net,&complen, read_from_server))
1344 == packet_error)
1345 {
1346 MYSQL_NET_READ_DONE(1, 0);
1347 return packet_error;
1348 }
1349 read_from_server= 0;
1350 if (my_uncompress(net->buff + net->where_b, packet_len,
1351 &complen))
1352 {
1353 net->error= 2; /* caller will close socket */
1354 net->last_errno= ER_NET_UNCOMPRESS_ERROR;
1355 MYSQL_SERVER_my_error(ER_NET_UNCOMPRESS_ERROR, MYF(0));
1356 MYSQL_NET_READ_DONE(1, 0);
1357 return packet_error;
1358 }
1359 buf_length+= (ulong)complen;
1360 *reallen += packet_len;
1361 }
1362
1363 net->read_pos= net->buff+ first_packet_offset + NET_HEADER_SIZE;
1364 net->buf_length= buf_length;
1365 net->remain_in_buf= (ulong) (buf_length - start_of_packet);
1366 len = ((ulong) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE -
1367 multi_byte_packet);
1368 net->save_char= net->read_pos[len]; /* Must be saved */
1369 net->read_pos[len]=0; /* Safeguard for mysql_use_result */
1370 }
1371#endif /* HAVE_COMPRESS */
1372 MYSQL_NET_READ_DONE(0, len);
1373 return (ulong)len;
1374}
1375
1376
1377void my_net_set_read_timeout(NET *net, uint timeout)
1378{
1379 DBUG_ENTER("my_net_set_read_timeout");
1380 DBUG_PRINT("enter", ("timeout: %d", timeout));
1381 if (net->read_timeout != timeout)
1382 {
1383 net->read_timeout= timeout;
1384 if (net->vio)
1385 vio_timeout(net->vio, 0, timeout);
1386 }
1387 DBUG_VOID_RETURN;
1388}
1389
1390
1391void my_net_set_write_timeout(NET *net, uint timeout)
1392{
1393 DBUG_ENTER("my_net_set_write_timeout");
1394 DBUG_PRINT("enter", ("timeout: %d", timeout));
1395 if (net->write_timeout != timeout)
1396 {
1397 net->write_timeout= timeout;
1398 if (net->vio)
1399 vio_timeout(net->vio, 1, timeout);
1400 }
1401 DBUG_VOID_RETURN;
1402}
1403