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