1 /* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    Without limiting anything contained in the foregoing, this file,
15    which is part of C Driver for MySQL (Connector/C), is also subject to the
16    Universal FOSS Exception, version 1.0, a copy of which can be found at
17    http://oss.oracle.com/licenses/universal-foss-exception.
18 
19    This program is distributed in the hope that it will be useful,
20    but WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22    GNU General Public License, version 2.0, for more details.
23 
24    You should have received a copy of the GNU General Public License
25    along with this program; if not, write to the Free Software
26    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
27 
28 /**
29   @file
30 
31   This file is the net layer API for the MySQL client/server protocol.
32 
33   Write and read of logical packets to/from socket.
34 
35   Writes are cached into net_buffer_length big packets.
36   Read packets are reallocated dynamicly when reading big packets.
37   Each logical packet has the following pre-info:
38   3 byte length & 1 byte package-number.
39 
40   This file needs to be written in C as it's used by the libmysql client as a
41   C file.
42 */
43 
44 /*
45   HFTODO this must be hidden if we don't want client capabilities in
46   embedded library
47  */
48 #include <my_global.h>
49 #include <mysql.h>
50 #include <mysql_com.h>
51 #include <mysqld_error.h>
52 #include <my_sys.h>
53 #include <m_string.h>
54 #include <my_net.h>
55 #include <violite.h>
56 #include <signal.h>
57 #include <errno.h>
58 #include "probes_mysql.h"
59 
60 #include <algorithm>
61 
62 using std::min;
63 using std::max;
64 
65 #ifdef EMBEDDED_LIBRARY
66 #undef MYSQL_SERVER
67 #undef MYSQL_CLIENT
68 #define MYSQL_CLIENT
69 #endif /*EMBEDDED_LIBRARY */
70 
71 // Workaround for compiler bug
72 // ld.so.1: mysqld: fatal: relocation error: file sql/mysqld:
73 //          symbol OPENSSL_sk_new_null: referenced symbol not found
74 // openssl/safestack.h has lots of pragma weak <function>
75 // Taking the address of the function solves the problem.
76 // (note, do not make it static, it may be optimized away)
77 #if defined(HAVE_TLSv13) && defined(__SUNPRO_CC)
78 #include <openssl/ssl.h>
79 void *address_of_sk_new_null = &OPENSSL_sk_new_null;
80 #endif
81 
82 /*
83   The following handles the differences when this is linked between the
84   client and the server.
85 
86   This gives an error if a too big packet is found.
87   The server can change this, but because the client can't normally do this
88   the client should have a bigger max_allowed_packet.
89 */
90 
91 #ifdef MYSQL_SERVER
92 /*
93   The following variables/functions should really not be declared
94   extern, but as it's hard to include sql_priv.h here, we have to
95   live with this for a while.
96 */
97 #ifdef HAVE_QUERY_CACHE
98 #define USE_QUERY_CACHE
99 extern void query_cache_insert(const char *packet, ulong length,
100                                unsigned pkt_nr);
101 #endif /* HAVE_QUERY_CACHE */
102 #define update_statistics(A) A
103 #else /* MYSQL_SERVER */
104 #define update_statistics(A)
105 #define thd_increment_bytes_sent(N)
106 #endif
107 
108 #ifdef MYSQL_SERVER
109 /* Additional instrumentation hooks for the server */
110 #include "mysql_com_server.h"
111 #endif
112 
113 #define VIO_SOCKET_ERROR  ((size_t) -1)
114 #define MAX_PACKET_LENGTH (256L*256L*256L-1)
115 
116 static my_bool net_write_buff(NET *, const uchar *, ulong);
117 
118 /** Init with packet info. */
119 
my_net_init(NET * net,Vio * vio)120 my_bool my_net_init(NET *net, Vio* vio)
121 {
122   DBUG_ENTER("my_net_init");
123   net->vio = vio;
124   my_net_local_init(net);			/* Set some limits */
125   if (!(net->buff=(uchar*) my_malloc((size_t) net->max_packet+
126              NET_HEADER_SIZE + COMP_HEADER_SIZE,
127              MYF(MY_WME))))
128     DBUG_RETURN(1);
129   net->buff_end=net->buff+net->max_packet;
130   net->error=0; net->return_status=0;
131   net->pkt_nr=net->compress_pkt_nr=0;
132   net->write_pos=net->read_pos = net->buff;
133   net->last_error[0]=0;
134   net->compress=0; net->reading_or_writing=0;
135   net->where_b = net->remain_in_buf=0;
136   net->last_errno=0;
137   net->unused= 0;
138 #ifdef MYSQL_SERVER
139   net->extension= NULL;
140 #endif
141 
142   if (vio)
143   {
144     /* For perl DBI/DBD. */
145     net->fd= vio_fd(vio);
146     vio_fastsend(vio);
147   }
148   DBUG_RETURN(0);
149 }
150 
151 
net_end(NET * net)152 void net_end(NET *net)
153 {
154   DBUG_ENTER("net_end");
155   my_free(net->buff);
156   net->buff=0;
157   DBUG_VOID_RETURN;
158 }
159 
160 
161 /** Realloc the packet buffer. */
162 
net_realloc(NET * net,size_t length)163 my_bool net_realloc(NET *net, size_t length)
164 {
165   uchar *buff;
166   size_t pkt_length;
167   DBUG_ENTER("net_realloc");
168   DBUG_PRINT("enter",("length: %lu", (ulong) length));
169 
170   if (length >= net->max_packet_size)
171   {
172     DBUG_PRINT("error", ("Packet too large. Max size: %lu",
173                          net->max_packet_size));
174     /* @todo: 1 and 2 codes are identical. */
175     net->error= 1;
176     net->last_errno= ER_NET_PACKET_TOO_LARGE;
177 #ifdef MYSQL_SERVER
178     my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
179 #endif
180     DBUG_RETURN(1);
181   }
182   pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
183   /*
184      We must allocate some extra bytes for the end 0 and to be able to
185      read big compressed blocks in net_read_packet().
186   */
187   if (!(buff= (uchar*) my_realloc((char*) net->buff, pkt_length +
188                                   NET_HEADER_SIZE + COMP_HEADER_SIZE,
189                                   MYF(MY_WME))))
190   {
191     /* @todo: 1 and 2 codes are identical. */
192     net->error= 1;
193     net->last_errno= ER_OUT_OF_RESOURCES;
194     /* In the server the error is reported by MY_WME flag. */
195     DBUG_RETURN(1);
196   }
197   net->buff=net->write_pos=buff;
198   net->buff_end=buff+(net->max_packet= (ulong) pkt_length);
199   DBUG_RETURN(0);
200 }
201 
202 
203 /**
204   Clear (reinitialize) the NET structure for a new command.
205 
206   @remark Performs debug checking of the socket buffer to
207           ensure that the protocol sequence is correct.
208 
209   @param net          NET handler
210   @param check_buffer  Whether to check the socket buffer.
211 */
212 
net_clear(NET * net,my_bool check_buffer MY_ATTRIBUTE ((unused)))213 void net_clear(NET *net,
214                my_bool check_buffer MY_ATTRIBUTE((unused)))
215 {
216   DBUG_ENTER("net_clear");
217 
218   DBUG_EXECUTE_IF("simulate_bad_field_length_1", {
219     net->pkt_nr= net->compress_pkt_nr= 0;
220     net->write_pos= net->buff;
221     DBUG_VOID_RETURN;
222   });
223   DBUG_EXECUTE_IF("simulate_bad_field_length_2", {
224     net->pkt_nr= net->compress_pkt_nr= 0;
225     net->write_pos= net->buff;
226     DBUG_VOID_RETURN;
227   });
228 
229 #if !defined(EMBEDDED_LIBRARY)
230   /* Ensure the socket buffer is empty, except for an EOF (at least 1). */
231   DBUG_ASSERT(!check_buffer || (vio_pending(net->vio) <= 1));
232 #endif
233 
234   /* Ready for new command */
235   net->pkt_nr= net->compress_pkt_nr= 0;
236   net->write_pos= net->buff;
237 
238   DBUG_VOID_RETURN;
239 }
240 
241 
242 /** Flush write_buffer if not empty. */
243 
net_flush(NET * net)244 my_bool net_flush(NET *net)
245 {
246   my_bool error= 0;
247   DBUG_ENTER("net_flush");
248   if (net->buff != net->write_pos)
249   {
250     error= net_write_packet(net, net->buff,
251                             (size_t) (net->write_pos - net->buff));
252     net->write_pos= net->buff;
253   }
254   /* Sync packet number if using compression */
255   if (net->compress)
256     net->pkt_nr=net->compress_pkt_nr;
257   DBUG_RETURN(error);
258 }
259 
260 
261 /**
262   Whether a I/O operation should be retried later.
263 
264   @param net          NET handler.
265   @param retry_count  Maximum number of interrupted operations.
266 
267   @retval TRUE    Operation should be retried.
268   @retval FALSE   Operation should not be retried. Fatal error.
269 */
270 
271 static my_bool
net_should_retry(NET * net,uint * retry_count MY_ATTRIBUTE ((unused)))272 net_should_retry(NET *net, uint *retry_count MY_ATTRIBUTE((unused)))
273 {
274   my_bool retry;
275 
276 #ifndef MYSQL_SERVER
277   /*
278     In the  client library, interrupted I/O operations are always retried.
279     Otherwise, it's either a timeout or an unrecoverable error.
280   */
281   retry= vio_should_retry(net->vio);
282 #else
283   /*
284     In the server, interrupted I/O operations are retried up to a limit.
285     In this scenario, pthread_kill can be used to wake up
286     (interrupt) threads waiting for I/O.
287   */
288   retry= vio_should_retry(net->vio) && ((*retry_count)++ < net->retry_count);
289 #endif
290 
291   return retry;
292 }
293 
294 
295 /*****************************************************************************
296 ** Write something to server/client buffer
297 *****************************************************************************/
298 
299 /**
300   Write a logical packet with packet header.
301 
302   Format: Packet length (3 bytes), packet number (1 byte)
303   When compression is used, a 3 byte compression length is added.
304 
305   @note If compression is used, the original packet is modified!
306 */
307 
my_net_write(NET * net,const uchar * packet,size_t len)308 my_bool my_net_write(NET *net, const uchar *packet, size_t len)
309 {
310   uchar buff[NET_HEADER_SIZE];
311   int rc;
312 
313   if (unlikely(!net->vio)) /* nowhere to write */
314     return 0;
315 
316   MYSQL_NET_WRITE_START(len);
317 
318   DBUG_EXECUTE_IF("simulate_net_write_failure", {
319                   my_error(ER_NET_ERROR_ON_WRITE, MYF(0));
320                   return 1;
321                   };
322                  );
323 
324   /*
325     Big packets are handled by splitting them in packets of MAX_PACKET_LENGTH
326     length. The last packet is always a packet that is < MAX_PACKET_LENGTH.
327     (The last packet may even have a length of 0)
328   */
329   while (len >= MAX_PACKET_LENGTH)
330   {
331     const ulong z_size = MAX_PACKET_LENGTH;
332     int3store(buff, z_size);
333     buff[3]= (uchar) net->pkt_nr++;
334     if (net_write_buff(net, buff, NET_HEADER_SIZE) ||
335         net_write_buff(net, packet, z_size))
336     {
337       MYSQL_NET_WRITE_DONE(1);
338       return 1;
339     }
340     packet += z_size;
341     len-=     z_size;
342   }
343   /* Write last packet */
344   int3store(buff,len);
345   buff[3]= (uchar) net->pkt_nr++;
346   if (net_write_buff(net, buff, NET_HEADER_SIZE))
347   {
348     MYSQL_NET_WRITE_DONE(1);
349     return 1;
350   }
351 #ifndef DEBUG_DATA_PACKETS
352   DBUG_DUMP("packet_header", buff, NET_HEADER_SIZE);
353 #endif
354   rc= MY_TEST(net_write_buff(net,packet,len));
355   MYSQL_NET_WRITE_DONE(rc);
356   return rc;
357 }
358 
359 
360 /**
361   Send a command to the server.
362 
363     The reason for having both header and packet is so that libmysql
364     can easy add a header to a special command (like prepared statements)
365     without having to re-alloc the string.
366 
367     As the command is part of the first data packet, we have to do some data
368     juggling to put the command in there, without having to create a new
369     packet.
370 
371     This function will split big packets into sub-packets if needed.
372     (Each sub packet can only be 2^24 bytes)
373 
374   @param net		NET handler
375   @param command	Command in MySQL server (enum enum_server_command)
376   @param header	Header to write after command
377   @param head_len	Length of header
378   @param packet	Query or parameter to query
379   @param len		Length of packet
380 
381   @retval
382     0	ok
383   @retval
384     1	error
385 */
386 
387 my_bool
net_write_command(NET * net,uchar command,const uchar * header,size_t head_len,const uchar * packet,size_t len)388 net_write_command(NET *net,uchar command,
389       const uchar *header, size_t head_len,
390       const uchar *packet, size_t len)
391 {
392   size_t length=len+1+head_len;			/* 1 extra byte for command */
393   uchar buff[NET_HEADER_SIZE+1];
394   uint header_size=NET_HEADER_SIZE+1;
395   int rc;
396   DBUG_ENTER("net_write_command");
397   DBUG_PRINT("enter",("length: %lu", (ulong) len));
398 
399   MYSQL_NET_WRITE_START(length);
400 
401   buff[4]=command;				/* For first packet */
402 
403   if (length >= MAX_PACKET_LENGTH)
404   {
405     /* Take into account that we have the command in the first header */
406     len= MAX_PACKET_LENGTH - 1 - head_len;
407     do
408     {
409       int3store(buff, MAX_PACKET_LENGTH);
410       buff[3]= (uchar) net->pkt_nr++;
411       if (net_write_buff(net, buff, header_size) ||
412           net_write_buff(net, header, head_len) ||
413           net_write_buff(net, packet, len))
414       {
415         MYSQL_NET_WRITE_DONE(1);
416         DBUG_RETURN(1);
417       }
418       packet+= len;
419       length-= MAX_PACKET_LENGTH;
420       len= MAX_PACKET_LENGTH;
421       head_len= 0;
422       header_size= NET_HEADER_SIZE;
423     } while (length >= MAX_PACKET_LENGTH);
424     len=length;         /* Data left to be written */
425   }
426   int3store(buff,length);
427   buff[3]= (uchar) net->pkt_nr++;
428   rc= MY_TEST(net_write_buff(net, buff, header_size) ||
429               (head_len && net_write_buff(net, header, head_len)) ||
430               net_write_buff(net, packet, len) || net_flush(net));
431   MYSQL_NET_WRITE_DONE(rc);
432   DBUG_RETURN(rc);
433 }
434 
435 
436 /**
437   Caching the data in a local buffer before sending it.
438 
439    Fill up net->buffer and send it to the client when full.
440 
441     If the rest of the to-be-sent-packet is bigger than buffer,
442     send it in one big block (to avoid copying to internal buffer).
443     If not, copy the rest of the data to the buffer and return without
444     sending data.
445 
446   @param net		Network handler
447   @param packet	Packet to send
448   @param len		Length of packet
449 
450   @note
451     The cached buffer can be sent as it is with 'net_flush()'.
452     In this code we have to be careful to not send a packet longer than
453     MAX_PACKET_LENGTH to net_write_packet() if we are using the compressed
454     protocol as we store the length of the compressed packet in 3 bytes.
455 
456   @retval
457     0	ok
458   @retval
459     1
460 */
461 
462 static my_bool
net_write_buff(NET * net,const uchar * packet,ulong len)463 net_write_buff(NET *net, const uchar *packet, ulong len)
464 {
465   ulong left_length;
466   if (net->compress && net->max_packet > MAX_PACKET_LENGTH)
467     left_length= (ulong) (MAX_PACKET_LENGTH - (net->write_pos - net->buff));
468   else
469     left_length= (ulong) (net->buff_end - net->write_pos);
470 
471 #ifdef DEBUG_DATA_PACKETS
472   DBUG_DUMP("data", packet, len);
473 #endif
474   if (len > left_length)
475   {
476     if (net->write_pos != net->buff)
477     {
478       /* Fill up already used packet and write it */
479       memcpy(net->write_pos, packet, left_length);
480       if (net_write_packet(net, net->buff,
481                            (size_t) (net->write_pos - net->buff) + left_length))
482         return 1;
483       net->write_pos= net->buff;
484       packet+= left_length;
485       len-= left_length;
486     }
487     if (net->compress)
488     {
489       /*
490         We can't have bigger packets than 16M with compression
491         Because the uncompressed length is stored in 3 bytes
492       */
493       left_length= MAX_PACKET_LENGTH;
494       while (len > left_length)
495       {
496         if (net_write_packet(net, packet, left_length))
497           return 1;
498         packet+= left_length;
499         len-= left_length;
500       }
501     }
502     if (len > net->max_packet)
503       return net_write_packet(net, packet, len);
504     /* Send out rest of the blocks as full sized blocks */
505   }
506   memcpy(net->write_pos, packet, len);
507   net->write_pos+= len;
508   return 0;
509 }
510 
511 
512 /**
513   Write a determined number of bytes to a network handler.
514 
515   @param  net     NET handler.
516   @param  buf     Buffer containing the data to be written.
517   @param  count   The length, in bytes, of the buffer.
518 
519   @return TRUE on error, FALSE on success.
520 */
521 
522 static my_bool
net_write_raw_loop(NET * net,const uchar * buf,size_t count)523 net_write_raw_loop(NET *net, const uchar *buf, size_t count)
524 {
525   unsigned int retry_count= 0;
526 
527   while (count)
528   {
529     size_t sentcnt= vio_write(net->vio, buf, count);
530 
531     /* VIO_SOCKET_ERROR (-1) indicates an error. */
532     if (sentcnt == VIO_SOCKET_ERROR)
533     {
534       /* A recoverable I/O error occurred? */
535       if (net_should_retry(net, &retry_count))
536         continue;
537       else
538         break;
539     }
540 
541     count-= sentcnt;
542     buf+= sentcnt;
543     update_statistics(thd_increment_bytes_sent(sentcnt));
544   }
545 
546   /* On failure, propagate the error code. */
547   if (count)
548   {
549     /* Socket should be closed. */
550     net->error= 2;
551 
552     /* Interrupted by a timeout? */
553     if (vio_was_timeout(net->vio))
554       net->last_errno= ER_NET_WRITE_INTERRUPTED;
555     else
556       net->last_errno= ER_NET_ERROR_ON_WRITE;
557 
558 #ifdef MYSQL_SERVER
559     my_error(net->last_errno, MYF(0));
560 #endif
561   }
562 
563   return MY_TEST(count);
564 }
565 
566 
567 /**
568   Compress and encapsulate a packet into a compressed packet.
569 
570   @param          net      NET handler.
571   @param          packet   The packet to compress.
572   @param[in,out]  length   Length of the packet.
573 
574   A compressed packet header is compromised of the packet
575   length (3 bytes), packet number (1 byte) and the length
576   of the original (uncompressed) packet.
577 
578   @return Pointer to the (new) compressed packet.
579 */
580 
581 static uchar *
compress_packet(NET * net,const uchar * packet,size_t * length)582 compress_packet(NET *net, const uchar *packet, size_t *length)
583 {
584   uchar *compr_packet;
585   size_t compr_length;
586   const uint header_length= NET_HEADER_SIZE + COMP_HEADER_SIZE;
587 
588   compr_packet= (uchar *) my_malloc(*length + header_length, MYF(MY_WME));
589 
590   if (compr_packet == NULL)
591     return NULL;
592 
593   memcpy(compr_packet + header_length, packet, *length);
594 
595   /* Compress the encapsulated packet. */
596   if (my_compress(compr_packet + header_length, length, &compr_length))
597   {
598     /*
599       If the length of the compressed packet is larger than the
600       original packet, the original packet is sent uncompressed.
601     */
602     compr_length= 0;
603   }
604 
605   /* Length of the compressed (original) packet. */
606   int3store(&compr_packet[NET_HEADER_SIZE], compr_length);
607   /* Length of this packet. */
608   int3store(compr_packet, *length);
609   /* Packet number. */
610   compr_packet[3]= (uchar) (net->compress_pkt_nr++);
611 
612   *length+= header_length;
613 
614   return compr_packet;
615 }
616 
617 
618 /**
619   Write a MySQL protocol packet to the network handler.
620 
621   @param  net     NET handler.
622   @param  packet  The packet to write.
623   @param  length  Length of the packet.
624 
625   @remark The packet might be encapsulated into a compressed packet.
626 
627   @return TRUE on error, FALSE on success.
628 */
629 
630 my_bool
net_write_packet(NET * net,const uchar * packet,size_t length)631 net_write_packet(NET *net, const uchar *packet, size_t length)
632 {
633   my_bool res;
634   DBUG_ENTER("net_write_packet");
635 
636 #if defined(MYSQL_SERVER) && defined(USE_QUERY_CACHE)
637   query_cache_insert((char*) packet, length, net->pkt_nr);
638 #endif
639 
640   /* Socket can't be used */
641   if (net->error == 2)
642     DBUG_RETURN(TRUE);
643 
644   net->reading_or_writing= 2;
645 
646 #ifdef HAVE_COMPRESS
647   const bool do_compress= net->compress;
648   if (do_compress)
649   {
650     if ((packet= compress_packet(net, packet, &length)) == NULL)
651     {
652       net->error= 2;
653       net->last_errno= ER_OUT_OF_RESOURCES;
654       /* In the server, allocation failure raises a error. */
655       net->reading_or_writing= 0;
656       DBUG_RETURN(TRUE);
657     }
658   }
659 #endif /* HAVE_COMPRESS */
660 
661 #ifdef DEBUG_DATA_PACKETS
662   DBUG_DUMP("data", packet, length);
663 #endif
664 
665   res= net_write_raw_loop(net, packet, length);
666 
667 #ifdef HAVE_COMPRESS
668   if (do_compress)
669     my_free((void *) packet);
670 #endif
671 
672   net->reading_or_writing= 0;
673 
674   DBUG_RETURN(res);
675 }
676 
677 /*****************************************************************************
678 ** Read something from server/clinet
679 *****************************************************************************/
680 
681 /**
682   Read a determined number of bytes from a network handler.
683 
684   @param  net     NET handler.
685   @param  count   The number of bytes to read.
686 
687   @return TRUE on error, FALSE on success.
688 */
689 
net_read_raw_loop(NET * net,size_t count)690 static my_bool net_read_raw_loop(NET *net, size_t count)
691 {
692   bool eof= false;
693   unsigned int retry_count= 0;
694   uchar *buf= net->buff + net->where_b;
695 
696   while (count)
697   {
698     size_t recvcnt= vio_read(net->vio, buf, count);
699 
700     /* VIO_SOCKET_ERROR (-1) indicates an error. */
701     if (recvcnt == VIO_SOCKET_ERROR)
702     {
703       /* A recoverable I/O error occurred? */
704       if (net_should_retry(net, &retry_count))
705         continue;
706       else
707         break;
708     }
709     /* Zero indicates end of file. */
710     else if (!recvcnt)
711     {
712       eof= true;
713       break;
714     }
715 
716     count-= recvcnt;
717     buf+= recvcnt;
718     update_statistics(thd_increment_bytes_received(recvcnt));
719   }
720 
721   /* On failure, propagate the error code. */
722   if (count)
723   {
724     /* Socket should be closed. */
725     net->error= 2;
726 
727     /* Interrupted by a timeout? */
728     if (!eof && vio_was_timeout(net->vio))
729       net->last_errno= ER_NET_READ_INTERRUPTED;
730     else
731       net->last_errno= ER_NET_READ_ERROR;
732 
733 #ifdef MYSQL_SERVER
734     my_error(net->last_errno, MYF(0));
735 #endif
736   }
737 
738   return MY_TEST(count);
739 }
740 
741 
742 /**
743   Read the header of a packet. The MySQL protocol packet header
744   consists of the length, in bytes, of the payload (packet data)
745   and a serial number.
746 
747   @remark The encoded length is the length of the packet payload,
748           which does not include the packet header.
749 
750   @remark The serial number is used to ensure that the packets are
751           received in order. If the packet serial number does not
752           match the expected value, a error is returned.
753 
754   @param  net  NET handler.
755 
756   @return TRUE on error, FALSE on success.
757 */
758 
net_read_packet_header(NET * net)759 static my_bool net_read_packet_header(NET *net)
760 {
761   uchar pkt_nr;
762   size_t count= NET_HEADER_SIZE;
763   my_bool rc;
764 
765   if (net->compress)
766     count+= COMP_HEADER_SIZE;
767 
768 #ifdef MYSQL_SERVER
769   struct st_net_server *server_extension;
770 
771   server_extension= static_cast<st_net_server*> (net->extension);
772 
773   if (server_extension != NULL)
774   {
775     void *user_data= server_extension->m_user_data;
776     DBUG_ASSERT(server_extension->m_before_header != NULL);
777     DBUG_ASSERT(server_extension->m_after_header != NULL);
778 
779     server_extension->m_before_header(net, user_data, count);
780     rc= net_read_raw_loop(net, count);
781     server_extension->m_after_header(net, user_data, count, rc);
782   }
783   else
784 #endif
785   {
786     rc= net_read_raw_loop(net, count);
787   }
788 
789   if (rc)
790     return TRUE;
791 
792   DBUG_DUMP("packet_header", net->buff + net->where_b, NET_HEADER_SIZE);
793 
794   pkt_nr= net->buff[net->where_b + 3];
795 
796   /*
797     Verify packet serial number against the truncated packet counter.
798     The local packet counter must be truncated since its not reset.
799   */
800   if (pkt_nr != (uchar) net->pkt_nr)
801   {
802     /* Not a NET error on the client. XXX: why? */
803 #if defined(MYSQL_SERVER)
804     my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0));
805 #elif defined(EXTRA_DEBUG)
806     /*
807       We don't make noise server side, since the client is expected
808       to break the protocol for e.g. --send LOAD DATA .. LOCAL where
809       the server expects the client to send a file, but the client
810       may reply with a new command instead.
811     */
812     fprintf(stderr, "Error: packets out of order (found %u, expected %u)\n",
813             (uint) pkt_nr, net->pkt_nr);
814     DBUG_ASSERT(pkt_nr == net->pkt_nr);
815 #endif
816     return TRUE;
817   }
818 
819   net->pkt_nr++;
820 
821   return FALSE;
822 }
823 
824 
825 /**
826   Read one (variable-length) MySQL protocol packet.
827   A MySQL packet consists of a header and a payload.
828 
829   @remark Reads one packet to net->buff + net->where_b.
830   @remark Long packets are handled by my_net_read().
831   @remark The network buffer is expanded if necessary.
832 
833   @return The length of the packet, or @packet_error on error.
834 */
835 
net_read_packet(NET * net,size_t * complen)836 static ulong net_read_packet(NET *net, size_t *complen)
837 {
838   size_t pkt_len, pkt_data_len;
839 
840   *complen= 0;
841 
842   net->reading_or_writing= 1;
843 
844   /* Retrieve packet length and number. */
845   if (net_read_packet_header(net))
846     goto error;
847 
848   net->compress_pkt_nr= net->pkt_nr;
849 
850 #ifdef HAVE_COMPRESS
851   if (net->compress)
852   {
853     /*
854       The right-hand expression must match the size of the buffer
855       allocated in net_realloc().
856     */
857     DBUG_ASSERT(net->where_b + NET_HEADER_SIZE + sizeof(uint32) <=
858                 net->max_packet + NET_HEADER_SIZE + COMP_HEADER_SIZE);
859 
860     /*
861       If the packet is compressed then complen > 0 and contains the
862       number of bytes in the uncompressed packet.
863     */
864     *complen= uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
865   }
866 #endif
867 
868   /* The length of the packet that follows. */
869   pkt_len= uint3korr(net->buff+net->where_b);
870 
871   /* End of big multi-packet. */
872   if (!pkt_len)
873     goto end;
874 
875   pkt_data_len = max(pkt_len, *complen) + net->where_b;
876 
877   /* Expand packet buffer if necessary. */
878   if ((pkt_data_len >= net->max_packet) && net_realloc(net, pkt_data_len))
879     goto error;
880 
881   /* Read the packet data (payload). */
882   if (net_read_raw_loop(net, pkt_len))
883     goto error;
884 
885 end:
886   net->reading_or_writing= 0;
887   return pkt_len;
888 
889 error:
890   net->reading_or_writing= 0;
891   return packet_error;
892 }
893 
894 
895 /**
896   Read a packet from the client/server and return it without the internal
897   package header.
898 
899   If the packet is the first packet of a multi-packet packet
900   (which is indicated by the length of the packet = 0xffffff) then
901   all sub packets are read and concatenated.
902 
903   If the packet was compressed, its uncompressed and the length of the
904   uncompressed packet is returned.
905 
906   @return
907   The function returns the length of the found packet or packet_error.
908   net->read_pos points to the read data.
909 */
910 
911 ulong
my_net_read(NET * net)912 my_net_read(NET *net)
913 {
914   size_t len, complen;
915 
916   MYSQL_NET_READ_START();
917 
918 #ifdef HAVE_COMPRESS
919   if (!net->compress)
920   {
921 #endif
922     len= net_read_packet(net, &complen);
923     if (len == MAX_PACKET_LENGTH)
924     {
925       /* First packet of a multi-packet.  Concatenate the packets */
926       ulong save_pos = net->where_b;
927       size_t total_length= 0;
928       do
929       {
930         net->where_b += len;
931         total_length += len;
932         len= net_read_packet(net, &complen);
933       } while (len == MAX_PACKET_LENGTH);
934       if (len != packet_error)
935         len+= total_length;
936       net->where_b = save_pos;
937     }
938     net->read_pos = net->buff + net->where_b;
939     if (len != packet_error)
940       net->read_pos[len]=0;		/* Safeguard for mysql_use_result */
941     MYSQL_NET_READ_DONE(0, len);
942     return len;
943 #ifdef HAVE_COMPRESS
944   }
945   else
946   {
947     /* We are using the compressed protocol */
948 
949     ulong buf_length;
950     ulong start_of_packet;
951     ulong first_packet_offset;
952     uint read_length, multi_byte_packet=0;
953 
954     if (net->remain_in_buf)
955     {
956       buf_length= net->buf_length;		/* Data left in old packet */
957       first_packet_offset= start_of_packet= (net->buf_length -
958                                              net->remain_in_buf);
959       /* Restore the character that was overwritten by the end 0 */
960       net->buff[start_of_packet]= net->save_char;
961     }
962     else
963     {
964       /* reuse buffer, as there is nothing in it that we need */
965       buf_length= start_of_packet= first_packet_offset= 0;
966     }
967     for (;;)
968     {
969       ulong packet_len;
970 
971       if (buf_length - start_of_packet >= NET_HEADER_SIZE)
972       {
973         read_length = uint3korr(net->buff+start_of_packet);
974         if (!read_length)
975         {
976           /* End of multi-byte packet */
977           start_of_packet += NET_HEADER_SIZE;
978           break;
979         }
980         if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet)
981         {
982           if (multi_byte_packet)
983           {
984             /* Remove packet header for second packet */
985             memmove(net->buff + first_packet_offset + start_of_packet,
986               net->buff + first_packet_offset + start_of_packet +
987               NET_HEADER_SIZE,
988               buf_length - start_of_packet);
989             start_of_packet += read_length;
990             buf_length -= NET_HEADER_SIZE;
991           }
992           else
993             start_of_packet+= read_length + NET_HEADER_SIZE;
994 
995           if (read_length != MAX_PACKET_LENGTH)	/* last package */
996           {
997             multi_byte_packet= 0;		/* No last zero len packet */
998             break;
999           }
1000           multi_byte_packet= NET_HEADER_SIZE;
1001           /* Move data down to read next data packet after current one */
1002           if (first_packet_offset)
1003           {
1004             memmove(net->buff,net->buff+first_packet_offset,
1005               buf_length-first_packet_offset);
1006             buf_length-=first_packet_offset;
1007             start_of_packet -= first_packet_offset;
1008             first_packet_offset=0;
1009           }
1010           continue;
1011         }
1012       }
1013       /* Move data down to read next data packet after current one */
1014       if (first_packet_offset)
1015       {
1016         memmove(net->buff,net->buff+first_packet_offset,
1017           buf_length-first_packet_offset);
1018         buf_length-=first_packet_offset;
1019         start_of_packet -= first_packet_offset;
1020         first_packet_offset=0;
1021       }
1022 
1023       net->where_b=buf_length;
1024       if ((packet_len= net_read_packet(net, &complen)) == packet_error)
1025       {
1026         MYSQL_NET_READ_DONE(1, 0);
1027         return packet_error;
1028       }
1029       if (my_uncompress(net->buff + net->where_b, packet_len,
1030                         &complen))
1031       {
1032         net->error= 2;			/* caller will close socket */
1033         net->last_errno= ER_NET_UNCOMPRESS_ERROR;
1034 #ifdef MYSQL_SERVER
1035         my_error(ER_NET_UNCOMPRESS_ERROR, MYF(0));
1036 #endif
1037         MYSQL_NET_READ_DONE(1, 0);
1038         return packet_error;
1039       }
1040       buf_length+= complen;
1041     }
1042 
1043     net->read_pos=      net->buff+ first_packet_offset + NET_HEADER_SIZE;
1044     net->buf_length=    buf_length;
1045     net->remain_in_buf= (ulong) (buf_length - start_of_packet);
1046     len = ((ulong) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE -
1047            multi_byte_packet);
1048     net->save_char= net->read_pos[len];	/* Must be saved */
1049     net->read_pos[len]=0;		/* Safeguard for mysql_use_result */
1050   }
1051 #endif /* HAVE_COMPRESS */
1052   MYSQL_NET_READ_DONE(0, len);
1053   return len;
1054 }
1055 
1056 
my_net_set_read_timeout(NET * net,uint timeout)1057 void my_net_set_read_timeout(NET *net, uint timeout)
1058 {
1059   DBUG_ENTER("my_net_set_read_timeout");
1060   DBUG_PRINT("enter", ("timeout: %d", timeout));
1061   if (net->read_timeout == timeout)
1062     DBUG_VOID_RETURN;
1063   net->read_timeout= timeout;
1064   if (net->vio)
1065     vio_timeout(net->vio, 0, timeout);
1066   DBUG_VOID_RETURN;
1067 }
1068 
1069 
my_net_set_write_timeout(NET * net,uint timeout)1070 void my_net_set_write_timeout(NET *net, uint timeout)
1071 {
1072   DBUG_ENTER("my_net_set_write_timeout");
1073   DBUG_PRINT("enter", ("timeout: %d", timeout));
1074   if (net->write_timeout == timeout)
1075     DBUG_VOID_RETURN;
1076   net->write_timeout= timeout;
1077   if (net->vio)
1078     vio_timeout(net->vio, 1, timeout);
1079   DBUG_VOID_RETURN;
1080 }
1081 
1082 #if defined(EXPORT_SYMVER16)
1083 #ifndef EMBEDDED_LIBRARY
1084 C_MODE_START
1085 
1086 // Hack to provide Fedora symbols
1087 
mysql_net_realloc(NET * net,size_t length)1088 my_bool mysql_net_realloc(NET *net, size_t length)
1089 {
1090   return net_realloc(net, length);
1091 }
1092 
1093 C_MODE_END
1094 #endif
1095 #endif  // EXPORT_SYMVER16
1096