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