1 /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2 2012-2016 SkySQL AB, MariaDB Corporation AB
3 This library is free software; you can redistribute it and/or
4 modify it under the terms of the GNU Library General Public
5 License as published by the Free Software Foundation; either
6 version 2 of the License, or (at your option) any later version.
7
8 This library 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 GNU
11 Library General Public License for more details.
12
13 You should have received a copy of the GNU Library General Public
14 License along with this library; if not, write to the Free
15 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16 MA 02111-1301, USA */
17
18 /* Write and read of logical packets to/from socket
19 ** Writes are cached into net_buffer_length big packets.
20 ** Read packets are reallocated dynamically when reading big packets.
21 ** Each logical packet has the following pre-info:
22 ** 3 byte length & 1 byte package-number.
23 */
24
25
26 #include <ma_global.h>
27 #include <mysql.h>
28 #include <ma_pvio.h>
29 #include <ma_sys.h>
30 #include <ma_string.h>
31 #include "mysql.h"
32 #include "ma_server_error.h"
33 #include <signal.h>
34 #include <errno.h>
35 #include <sys/types.h>
36 #include <ma_pvio.h>
37 #include <ma_common.h>
38 #ifndef _WIN32
39 #include <poll.h>
40 #endif
41
42 #define MAX_PACKET_LENGTH (256L*256L*256L-1)
43
44 /* net_buffer_length and max_allowed_packet are defined in mysql.h
45 See bug conc-57
46 */
47 #undef net_buffer_length
48
49 #undef max_allowed_packet
50 ulong max_allowed_packet=1024L * 1024L * 1024L;
51 ulong net_read_timeout= NET_READ_TIMEOUT;
52 ulong net_write_timeout= NET_WRITE_TIMEOUT;
53 ulong net_buffer_length= 8192; /* Default length. Enlarged if necessary */
54
55 #if !defined(_WIN32)
56 #include <sys/socket.h>
57 #else
58 #undef MYSQL_SERVER /* Win32 can't handle interrupts */
59 #endif
60 #if !defined(_WIN32) && !defined(HAVE_BROKEN_NETINET_INCLUDES) && !defined(__BEOS__)
61 #include <netinet/in_systm.h>
62 #include <netinet/in.h>
63 #include <netinet/ip.h>
64 #if !defined(alpha_linux_port)
65 #include <netinet/tcp.h>
66 #endif
67 #endif
68
69
70 /*
71 ** Give error if a too big packet is found
72 ** The server can change this with the -O switch, but because the client
73 ** can't normally do this the client should have a bigger max-buffer.
74 */
75
76 static int ma_net_write_buff(NET *net,const char *packet, size_t len);
77
78
79 /* Init with packet info */
80
ma_net_init(NET * net,MARIADB_PVIO * pvio)81 int ma_net_init(NET *net, MARIADB_PVIO* pvio)
82 {
83 if (!(net->buff=(uchar*) malloc(net_buffer_length)))
84 return 1;
85 if (!net->extension)
86 return 1;
87
88 memset(net->buff, 0, net_buffer_length);
89
90 net->max_packet_size= MAX(net_buffer_length, max_allowed_packet);
91 net->buff_end=net->buff+(net->max_packet=net_buffer_length);
92 net->pvio = pvio;
93 net->error=0; net->return_status=0;
94 net->read_timeout=(uint) net_read_timeout; /* Timeout for read */
95 net->compress_pkt_nr= net->pkt_nr= 0;
96 net->write_pos=net->read_pos = net->buff;
97 net->last_error[0]= net->sqlstate[0] =0;
98
99 net->compress=0; net->reading_or_writing=0;
100 net->where_b = net->remain_in_buf=0;
101 net->last_errno=0;
102
103 if (pvio != 0) /* If real connection */
104 {
105 ma_pvio_get_handle(pvio, &net->fd);
106 ma_pvio_blocking(pvio, 1, 0);
107 ma_pvio_fast_send(pvio);
108 }
109 return 0;
110 }
111
ma_net_end(NET * net)112 void ma_net_end(NET *net)
113 {
114 free(net->buff);
115 net->buff=0;
116 }
117
118 /* Realloc the packet buffer */
119
net_realloc(NET * net,size_t length)120 static my_bool net_realloc(NET *net, size_t length)
121 {
122 uchar *buff;
123 size_t pkt_length;
124
125 if (length >= net->max_packet_size)
126 {
127 net->error=1;
128 net->last_errno=ER_NET_PACKET_TOO_LARGE;
129 return(1);
130 }
131 pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
132 /* reallocate buffer:
133 size= pkt_length + NET_HEADER_SIZE + COMP_HEADER_SIZE */
134 if (!(buff=(uchar*) realloc(net->buff,
135 pkt_length + NET_HEADER_SIZE + COMP_HEADER_SIZE)))
136 {
137 net->error=1;
138 return(1);
139 }
140 net->buff=net->write_pos=buff;
141 net->buff_end=buff+(net->max_packet=(unsigned long)pkt_length);
142 return(0);
143 }
144
145 /* Remove unwanted characters from connection */
ma_net_clear(NET * net)146 void ma_net_clear(NET *net)
147 {
148 if (net->extension->multi_status > COM_MULTI_OFF)
149 return;
150 net->compress_pkt_nr= net->pkt_nr=0; /* Ready for new command */
151 net->write_pos=net->buff;
152 return;
153 }
154
155 /* Flush write_buffer if not empty. */
ma_net_flush(NET * net)156 int ma_net_flush(NET *net)
157 {
158 int error=0;
159
160 /* don't flush if pipelined query is in progress */
161 if (net->extension->multi_status > COM_MULTI_OFF)
162 return 0;
163
164 if (net->buff != net->write_pos)
165 {
166 error=ma_net_real_write(net,(char*) net->buff,
167 (size_t) (net->write_pos - net->buff));
168 net->write_pos=net->buff;
169 }
170 if (net->compress)
171 net->pkt_nr= net->compress_pkt_nr;
172 return(error);
173 }
174
175 /*****************************************************************************
176 ** Write something to server/client buffer
177 *****************************************************************************/
178
179 /*
180 ** Write a logical packet with packet header
181 ** Format: Packet length (3 bytes), packet number(1 byte)
182 ** When compression is used a 3 byte compression length is added
183 ** NOTE: If compression is used the original package is destroyed!
184 */
185
ma_net_write(NET * net,const uchar * packet,size_t len)186 int ma_net_write(NET *net, const uchar *packet, size_t len)
187 {
188 uchar buff[NET_HEADER_SIZE];
189 while (len >= MAX_PACKET_LENGTH)
190 {
191 const ulong max_len= MAX_PACKET_LENGTH;
192 int3store(buff,max_len);
193 buff[3]= (uchar)net->pkt_nr++;
194 if (ma_net_write_buff(net,(char*) buff,NET_HEADER_SIZE) ||
195 ma_net_write_buff(net, (char *)packet, max_len))
196 return 1;
197 packet+= max_len;
198 len-= max_len;
199 }
200 /* write last remaining packet, size can be zero */
201 int3store(buff, len);
202 buff[3]= (uchar)net->pkt_nr++;
203 if (ma_net_write_buff(net,(char*) buff,NET_HEADER_SIZE) ||
204 ma_net_write_buff(net, (char *)packet, len))
205 return 1;
206 return 0;
207 }
208
ma_net_write_command(NET * net,uchar command,const char * packet,size_t len,my_bool disable_flush)209 int ma_net_write_command(NET *net, uchar command,
210 const char *packet, size_t len,
211 my_bool disable_flush)
212 {
213 uchar buff[NET_HEADER_SIZE+1];
214 size_t buff_size= NET_HEADER_SIZE + 1;
215 size_t length= 1 + len; /* 1 extra byte for command */
216 int rc;
217
218 buff[NET_HEADER_SIZE]= 0;
219 buff[4]=command;
220
221 if (length >= MAX_PACKET_LENGTH)
222 {
223 len= MAX_PACKET_LENGTH - 1;
224 do
225 {
226 int3store(buff, MAX_PACKET_LENGTH);
227 buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
228
229 if (ma_net_write_buff(net, (char *)buff, buff_size) ||
230 ma_net_write_buff(net, packet, len))
231 return(1);
232 packet+= len;
233 length-= MAX_PACKET_LENGTH;
234 len= MAX_PACKET_LENGTH;
235 buff_size= NET_HEADER_SIZE; /* don't send command for further packets */
236 } while (length >= MAX_PACKET_LENGTH);
237 len= length;
238 }
239 int3store(buff,length);
240 buff[3]= (net->compress) ? 0 :(uchar) (net->pkt_nr++);
241 rc= test (ma_net_write_buff(net,(char *)buff, buff_size) ||
242 ma_net_write_buff(net,packet,len));
243 if (!rc && !disable_flush)
244 return test(ma_net_flush(net));
245 return rc;
246 }
247
248
ma_net_write_buff(NET * net,const char * packet,size_t len)249 static int ma_net_write_buff(NET *net,const char *packet, size_t len)
250 {
251 size_t left_length;
252
253 if (!len)
254 return 0;
255
256 if (net->max_packet > MAX_PACKET_LENGTH &&
257 net->compress)
258 left_length= (size_t)(MAX_PACKET_LENGTH - (net->write_pos - net->buff));
259 else
260 left_length=(size_t) (net->buff_end - net->write_pos);
261
262 if (len > left_length)
263 {
264 if (net->write_pos != net->buff)
265 {
266 memcpy((char*) net->write_pos,packet,left_length);
267 if (ma_net_real_write(net,(char*) net->buff,
268 (size_t)(net->write_pos - net->buff) + left_length))
269 return 1;
270 packet+=left_length;
271 len-=left_length;
272 net->write_pos= net->buff;
273 }
274 if (net->compress)
275 {
276 /* uncompressed length is stored in 3 bytes,so
277 packet can't be > 0xFFFFFF */
278 left_length= MAX_PACKET_LENGTH;
279 while (len > left_length)
280 {
281 if (ma_net_real_write(net, packet, left_length))
282 return 1;
283 packet+= left_length;
284 len-= left_length;
285 }
286 }
287 if (len > net->max_packet)
288 return(test(ma_net_real_write(net, packet, len)));
289 }
290 memcpy((char*) net->write_pos,packet,len);
291 net->write_pos+=len;
292 return 0;
293 }
294
295 unsigned char *mysql_net_store_length(unsigned char *packet, size_t length);
296
297 /* Read and write using timeouts */
298
ma_net_real_write(NET * net,const char * packet,size_t len)299 int ma_net_real_write(NET *net, const char *packet, size_t len)
300 {
301 ssize_t length;
302 char *pos,*end;
303
304 if (net->error == 2)
305 return(-1); /* socket can't be used */
306
307 net->reading_or_writing=2;
308 #ifdef HAVE_COMPRESS
309 if (net->compress)
310 {
311 size_t complen;
312 uchar *b;
313 uint header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
314 if (!(b=(uchar*) malloc(len + NET_HEADER_SIZE + COMP_HEADER_SIZE + 1)))
315 {
316 net->last_errno=ER_OUT_OF_RESOURCES;
317 net->error=2;
318 net->reading_or_writing=0;
319 return(1);
320 }
321 memcpy(b+header_length,packet,len);
322
323 if (_mariadb_compress((unsigned char*) b+header_length,&len,&complen))
324 {
325 complen=0;
326 }
327 int3store(&b[NET_HEADER_SIZE],complen);
328 int3store(b,len);
329 b[3]=(uchar) (net->compress_pkt_nr++);
330 len+= header_length;
331 packet= (char*) b;
332 }
333 #endif /* HAVE_COMPRESS */
334
335 pos=(char*) packet; end=pos+len;
336 while (pos != end)
337 {
338 if ((length=ma_pvio_write(net->pvio,(uchar *)pos,(size_t) (end-pos))) <= 0)
339 {
340 net->error=2; /* Close socket */
341 net->last_errno= ER_NET_ERROR_ON_WRITE;
342 net->reading_or_writing=0;
343 #ifdef HAVE_COMPRESS
344 if (net->compress)
345 free((char*) packet);
346 #endif
347 return(1);
348 }
349 pos+=length;
350 }
351 #ifdef HAVE_COMPRESS
352 if (net->compress)
353 free((char*) packet);
354 #endif
355 net->reading_or_writing=0;
356 return(((int) (pos != end)));
357 }
358
359 /*****************************************************************************
360 ** Read something from server/clinet
361 *****************************************************************************/
ma_real_read(NET * net,size_t * complen)362 static ulong ma_real_read(NET *net, size_t *complen)
363 {
364 uchar *pos;
365 ssize_t length;
366 uint i;
367 ulong len=packet_error;
368 size_t remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
369 NET_HEADER_SIZE);
370 *complen = 0;
371
372 net->reading_or_writing=1;
373
374 pos = net->buff + net->where_b; /* net->packet -4 */
375 for (i=0 ; i < 2 ; i++)
376 {
377 while (remain > 0)
378 {
379 /* First read is done with non blocking mode */
380 if ((length=ma_pvio_cache_read(net->pvio, pos,remain)) <= 0L)
381 {
382 len= packet_error;
383 net->error=2; /* Close socket */
384 goto end;
385 }
386 remain -= (ulong) length;
387 pos+= (ulong) length;
388 }
389
390 if (i == 0)
391 { /* First parts is packet length */
392 ulong helping;
393 net->pkt_nr= net->buff[net->where_b + 3];
394 net->compress_pkt_nr= ++net->pkt_nr;
395 #ifdef HAVE_COMPRESS
396 if (net->compress)
397 {
398 /* complen is > 0 if package is really compressed */
399 *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
400 }
401 #endif
402
403 len=uint3korr(net->buff+net->where_b);
404 if (!len)
405 goto end;
406 helping = max(len,(ulong)*complen) + net->where_b;
407 /* The necessary size of net->buff */
408 if (helping >= net->max_packet)
409 {
410 if (net_realloc(net, helping))
411 {
412 len= packet_error; /* Return error */
413 goto end;
414 }
415 }
416 pos=net->buff + net->where_b;
417 remain = len;
418 }
419 }
420
421 end:
422 net->reading_or_writing=0;
423 return(len);
424 }
425
ma_net_read(NET * net)426 ulong ma_net_read(NET *net)
427 {
428 size_t len,complen;
429
430 #ifdef HAVE_COMPRESS
431 if (!net->compress)
432 {
433 #endif
434 len = ma_real_read (net,(size_t *)&complen);
435 if (len == MAX_PACKET_LENGTH)
436 {
437 /* multi packet read */
438 size_t length= 0;
439 ulong last_pos= net->where_b;
440
441 do
442 {
443 length+= len;
444 net->where_b+= (unsigned long)len;
445 len= ma_real_read(net, &complen);
446 } while (len == MAX_PACKET_LENGTH);
447 net->where_b= last_pos;
448 if (len != packet_error)
449 len+= length;
450 }
451 net->read_pos = net->buff + net->where_b;
452 if (len != packet_error)
453 net->read_pos[len]=0; /* Safeguard for mysql_use_result */
454 return (ulong)len;
455 #ifdef HAVE_COMPRESS
456 }
457 else
458 {
459 /*
460 compressed protocol:
461
462 --------------------------------------
463 packet_length 3
464 sequence_id 1
465 uncompressed_length 3
466 --------------------------------------
467 compressed data packet_length - 7
468 --------------------------------------
469
470 Another packet will follow if:
471 packet_length == MAX_PACKET_LENGTH
472
473 Last package will be identified by
474 - packet_length is zero (special case)
475 - packet_length < MAX_PACKET_LENGTH
476 */
477
478 size_t packet_length,
479 buffer_length;
480 size_t current= 0, start= 0;
481 my_bool is_multi_packet= 0;
482
483 /* check if buffer is empty */
484 if (!net->remain_in_buf)
485 {
486 buffer_length= 0;
487 }
488 else
489 {
490 /* save position and restore \0 character */
491 buffer_length= net->buf_length;
492 current= net->buf_length - net->remain_in_buf;
493 start= current;
494 net->buff[net->buf_length - net->remain_in_buf]=net->save_char;
495 }
496 for (;;)
497 {
498 if (buffer_length - current >= 4)
499 {
500 uchar *pos= net->buff + current;
501 packet_length= uint3korr(pos);
502
503 /* check if we have last package (special case: zero length) */
504 if (!packet_length)
505 {
506 current+= 4; /* length + sequence_id,
507 no more data will follow */
508 break;
509 }
510 if (packet_length + 4 <= buffer_length - current)
511 {
512 if (!is_multi_packet)
513 {
514 current= current + packet_length + 4;
515 }
516 else
517 {
518 /* remove packet_header */
519 memmove(net->buff + current,
520 net->buff + current + 4,
521 buffer_length - current);
522 buffer_length-= 4;
523 current+= packet_length;
524 }
525 /* do we have last packet ? */
526 if (packet_length != MAX_PACKET_LENGTH)
527 {
528 is_multi_packet= 0;
529 break;
530 }
531 else
532 is_multi_packet= 1;
533 if (start)
534 {
535 memmove(net->buff, net->buff + start,
536 buffer_length - start);
537 /* decrease buflen*/
538 buffer_length-= start;
539 start= 0;
540 }
541 continue;
542 }
543 }
544 if (start)
545 {
546 memmove(net->buff, net->buff + start, buffer_length - start);
547 /* decrease buflen and current */
548 current -= start;
549 buffer_length-= start;
550 start= 0;
551 }
552
553 net->where_b=(unsigned long)buffer_length;
554
555 if ((packet_length = ma_real_read(net,(size_t *)&complen)) == packet_error)
556 return packet_error;
557 if (_mariadb_uncompress((unsigned char*) net->buff + net->where_b, &packet_length, &complen))
558 {
559 net->error=2; /* caller will close socket */
560 net->last_errno=ER_NET_UNCOMPRESS_ERROR;
561 break;
562 return packet_error;
563 }
564 buffer_length+= complen;
565 }
566 /* set values */
567 net->buf_length= (unsigned long)buffer_length;
568 net->remain_in_buf= (unsigned long)(buffer_length - current);
569 net->read_pos= net->buff + start + 4;
570 len= current - start - 4;
571 if (is_multi_packet)
572 len-= 4;
573 net->save_char= net->read_pos[len]; /* Must be saved */
574 net->read_pos[len]=0; /* Safeguard for mysql_use_result */
575 }
576 #endif
577 return (ulong)len;
578 }
579
net_add_multi_command(NET * net,uchar command,const uchar * packet,size_t length)580 int net_add_multi_command(NET *net, uchar command, const uchar *packet,
581 size_t length)
582 {
583 if (net->extension->multi_status == COM_MULTI_OFF)
584 {
585 return(1);
586 }
587 /* don't increase packet number */
588 net->compress_pkt_nr= net->pkt_nr= 0;
589 return ma_net_write_command(net, command, (const char *)packet, length, 1);
590 }
591
592