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