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