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