1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2008 Sun Microsystems, Inc.
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22
#include <drizzled/session.h>
23
#include <drizzled/error.h>
31
#include <sys/socket.h>
40
namespace drizzle_plugin
44
using namespace drizzled;
47
The following handles the differences when this is linked between the
48
client and the server.
50
This gives an error if a too big packet is found
51
The server can change this with the -O switch, but because the client
52
can't normally do this the client should have a bigger max_allowed_packet.
55
/* Constants when using compression */
56
#define NET_HEADER_SIZE 4 /* standard header size */
57
#define COMP_HEADER_SIZE 3 /* compression header extra size */
59
#define MAX_PACKET_LENGTH (256L*256L*256L-1)
60
const char *not_error_sqlstate= "00000";
62
static bool net_write_buff(NET *net, const unsigned char *packet, uint32_t len);
63
static int drizzleclient_net_real_write(NET *net, const unsigned char *packet, size_t len);
65
/** Init with packet info. */
67
bool drizzleclient_net_init(NET *net, Vio* vio, uint32_t buffer_length)
70
net->max_packet= (uint32_t) buffer_length;
71
net->max_packet_size= max(buffer_length, drizzled::global_system_variables.max_allowed_packet);
73
if (!(net->buff=(unsigned char*) malloc((size_t) net->max_packet+
74
NET_HEADER_SIZE + COMP_HEADER_SIZE)))
76
net->buff_end=net->buff+net->max_packet;
77
net->error=0; net->return_status=0;
78
net->pkt_nr=net->compress_pkt_nr=0;
79
net->write_pos=net->read_pos = net->buff;
81
net->compress=0; net->reading_or_writing=0;
82
net->where_b = net->remain_in_buf=0;
86
if (vio != 0) /* If real connection */
88
net->fd = vio->get_fd(); /* For perl DBI/DBD */
94
bool drizzleclient_net_init_sock(NET * net, int sock, uint32_t buffer_length)
96
Vio *vio_tmp= new Vio(sock);
100
if (drizzleclient_net_init(net, vio_tmp, buffer_length))
102
/* Only delete the temporary vio if we didn't already attach it to the
105
if (vio_tmp && (net->vio != vio_tmp))
109
(void) shutdown(sock, SHUT_RDWR);
117
void drizzleclient_net_end(NET *net)
119
if (net->buff != NULL)
125
void drizzleclient_net_close(NET *net)
127
if (net->vio != NULL)
134
bool drizzleclient_net_peer_addr(NET *net, char *buf, uint16_t *port, size_t buflen)
136
return net->vio->peer_addr(buf, port, buflen);
139
void drizzleclient_net_keepalive(NET *net, bool flag)
141
net->vio->keepalive(flag);
144
int drizzleclient_net_get_sd(NET *net)
146
return net->vio->get_fd();
149
bool drizzleclient_net_more_data(NET *net)
151
return (net->vio == 0 || net->vio->get_read_pos() < net->vio->get_read_end());
154
/** Realloc the packet buffer. */
156
static bool drizzleclient_net_realloc(NET *net, size_t length)
161
if (length >= net->max_packet_size)
163
/* @todo: 1 and 2 codes are identical. */
165
net->last_errno= ER_NET_PACKET_TOO_LARGE;
166
my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
169
pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
171
We must allocate some extra bytes for the end 0 and to be able to
172
read big compressed blocks
174
if (!(buff= (unsigned char*) realloc((char*) net->buff, pkt_length +
175
NET_HEADER_SIZE + COMP_HEADER_SIZE)))
177
/* @todo: 1 and 2 codes are identical. */
179
net->last_errno= CR_OUT_OF_MEMORY;
180
/* In the server the error is reported by MY_WME flag. */
183
net->buff=net->write_pos=buff;
184
net->buff_end=buff+(net->max_packet= (uint32_t) pkt_length);
190
Check if there is any data to be read from the socket.
192
@param sd socket descriptor
197
1 Data or EOF to read
199
-1 Don't know if data is ready or not
202
static bool net_data_is_ready(int sd)
208
ufds.events= POLLIN | POLLPRI;
209
if (!(res= poll(&ufds, 1, 0)))
211
if (res < 0 || !(ufds.revents & (POLLIN | POLLPRI)))
217
Remove unwanted characters from connection
218
and check if disconnected.
220
Read from socket until there is nothing more to read. Discard
223
If there is anything when to read 'drizzleclient_net_clear' is called this
224
normally indicates an error in the protocol.
226
When connection is properly closed (for TCP it means with
227
a FIN packet), then select() considers a socket "ready to read",
228
in the sense that there's EOF to read, but read() returns 0.
230
@param net NET handler
231
@param clear_buffer if <> 0, then clear all data from comm buff
234
void drizzleclient_net_clear(NET *net, bool clear_buffer)
238
while (net_data_is_ready(net->vio->get_fd()) > 0)
240
/* The socket is ready */
241
if (net->vio->read(net->buff, (size_t) net->max_packet) <= 0)
248
net->pkt_nr=net->compress_pkt_nr=0; /* Ready for new command */
249
net->write_pos=net->buff;
254
/** Flush write_buffer if not empty. */
256
bool drizzleclient_net_flush(NET *net)
259
if (net->buff != net->write_pos)
261
error=drizzleclient_net_real_write(net, net->buff,
262
(size_t) (net->write_pos - net->buff)) ? 1 : 0;
263
net->write_pos=net->buff;
265
/* Sync packet number if using compression */
267
net->pkt_nr=net->compress_pkt_nr;
272
/*****************************************************************************
273
** Write something to server/client buffer
274
*****************************************************************************/
277
Write a logical packet with packet header.
279
Format: Packet length (3 bytes), packet number(1 byte)
280
When compression is used a 3 byte compression length is added
283
If compression is used the original package is modified!
287
drizzleclient_net_write(NET *net,const unsigned char *packet,size_t len)
289
unsigned char buff[NET_HEADER_SIZE];
290
if (unlikely(!net->vio)) /* nowhere to write */
293
Big packets are handled by splitting them in packets of MAX_PACKET_LENGTH
294
length. The last packet is always a packet that is < MAX_PACKET_LENGTH.
295
(The last packet may even have a length of 0)
297
while (len >= MAX_PACKET_LENGTH)
299
const uint32_t z_size = MAX_PACKET_LENGTH;
300
int3store(buff, z_size);
301
buff[3]= (unsigned char) net->pkt_nr++;
302
if (net_write_buff(net, buff, NET_HEADER_SIZE) ||
303
net_write_buff(net, packet, z_size))
308
/* Write last packet */
310
buff[3]= (unsigned char) net->pkt_nr++;
311
if (net_write_buff(net, buff, NET_HEADER_SIZE))
313
return net_write_buff(net,packet,len) ? 1 : 0;
317
Send a command to the server.
319
The reason for having both header and packet is so that libdrizzle
320
can easy add a header to a special command (like prepared statements)
321
without having to re-alloc the string.
323
As the command is part of the first data packet, we have to do some data
324
juggling to put the command in there, without having to create a new
327
This function will split big packets into sub-packets if needed.
328
(Each sub packet can only be 2^24 bytes)
330
@param net NET handler
331
@param command Command in MySQL server (enum enum_server_command)
332
@param header Header to write after command
333
@param head_len Length of header
334
@param packet Query or parameter to query
335
@param len Length of packet
344
drizzleclient_net_write_command(NET *net,unsigned char command,
345
const unsigned char *header, size_t head_len,
346
const unsigned char *packet, size_t len)
348
uint32_t length=len+1+head_len; /* 1 extra byte for command */
349
unsigned char buff[NET_HEADER_SIZE+1];
350
uint32_t header_size=NET_HEADER_SIZE+1;
352
buff[4]=command; /* For first packet */
354
if (length >= MAX_PACKET_LENGTH)
356
/* Take into account that we have the command in the first header */
357
len= MAX_PACKET_LENGTH - 1 - head_len;
360
int3store(buff, MAX_PACKET_LENGTH);
361
buff[3]= (unsigned char) net->pkt_nr++;
362
if (net_write_buff(net, buff, header_size) ||
363
net_write_buff(net, header, head_len) ||
364
net_write_buff(net, packet, len))
367
length-= MAX_PACKET_LENGTH;
368
len= MAX_PACKET_LENGTH;
370
header_size= NET_HEADER_SIZE;
371
} while (length >= MAX_PACKET_LENGTH);
372
len=length; /* Data left to be written */
374
int3store(buff,length);
375
buff[3]= (unsigned char) net->pkt_nr++;
376
return((net_write_buff(net, buff, header_size) ||
377
(head_len && net_write_buff(net, header, head_len)) ||
378
net_write_buff(net, packet, len) || drizzleclient_net_flush(net)) ? 1 : 0 );
382
Caching the data in a local buffer before sending it.
384
Fill up net->buffer and send it to the client when full.
386
If the rest of the to-be-sent-packet is bigger than buffer,
387
send it in one big block (to avoid copying to internal buffer).
388
If not, copy the rest of the data to the buffer and return without
391
@param net Network handler
392
@param packet Packet to send
393
@param len Length of packet
396
The cached buffer can be sent as it is with 'drizzleclient_net_flush()'.
397
In this code we have to be careful to not send a packet longer than
398
MAX_PACKET_LENGTH to drizzleclient_net_real_write() if we are using the compressed
399
protocol as we store the length of the compressed packet in 3 bytes.
408
net_write_buff(NET *net, const unsigned char *packet, uint32_t len)
410
uint32_t left_length;
411
if (net->compress && net->max_packet > MAX_PACKET_LENGTH)
412
left_length= MAX_PACKET_LENGTH - (net->write_pos - net->buff);
414
left_length= (uint32_t) (net->buff_end - net->write_pos);
416
if (len > left_length)
418
if (net->write_pos != net->buff)
420
/* Fill up already used packet and write it */
421
memcpy(net->write_pos,packet,left_length);
422
if (drizzleclient_net_real_write(net, net->buff,
423
(size_t) (net->write_pos - net->buff) + left_length))
425
net->write_pos= net->buff;
426
packet+= left_length;
432
We can't have bigger packets than 16M with compression
433
Because the uncompressed length is stored in 3 bytes
435
left_length= MAX_PACKET_LENGTH;
436
while (len > left_length)
438
if (drizzleclient_net_real_write(net, packet, left_length))
440
packet+= left_length;
444
if (len > net->max_packet)
445
return drizzleclient_net_real_write(net, packet, len) ? 1 : 0;
446
/* Send out rest of the blocks as full sized blocks */
448
memcpy(net->write_pos,packet,len);
449
net->write_pos+= len;
455
Read and write one packet using timeouts.
456
If needed, the packet is compressed before sending.
459
- TODO is it needed to set this variable if we have no socket
463
TODO: rewrite this in a manner to do non-block writes. If a write can not be made, and we are
464
in the server, yield to another process and come back later.
467
drizzleclient_net_real_write(NET *net, const unsigned char *packet, size_t len)
470
const unsigned char *pos, *end;
471
uint32_t retry_count= 0;
473
/* Backup of the original SO_RCVTIMEO timeout */
476
return(-1); /* socket can't be used */
478
net->reading_or_writing=2;
483
const uint32_t header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
484
if (!(b= (unsigned char*) malloc(len + NET_HEADER_SIZE +
488
net->last_errno= CR_OUT_OF_MEMORY;
489
/* In the server, the error is reported by MY_WME flag. */
490
net->reading_or_writing= 0;
493
memcpy(b+header_length,packet,len);
495
complen= len * 120 / 100 + 12;
496
unsigned char * compbuf= (unsigned char *) malloc(complen);
499
uLongf tmp_complen= complen;
500
int res= compress((Bytef*) compbuf, &tmp_complen,
501
(Bytef*) (b+header_length),
503
complen= tmp_complen;
507
if ((res != Z_OK) || (complen >= len))
511
size_t tmplen= complen;
520
int3store(&b[NET_HEADER_SIZE],complen);
522
b[3]=(unsigned char) (net->compress_pkt_nr++);
529
/* Loop until we have read everything */
533
// TODO - see bug comment below - will we crash now?
534
if ((long) (length= net->vio->write( pos, (size_t) (end-pos))) <= 0)
537
* We could end up here with net->vio == NULL
539
* If that is the case, we exit the while loop
541
if (net->vio == NULL)
544
const bool interrupted= net->vio->should_retry();
546
If we read 0, or we were interrupted this means that
547
we need to switch to blocking mode and wait until the timeout
548
on the socket kicks in.
550
if ((interrupted || length == 0))
554
while (net->vio->blocking(true, &old_mode) < 0)
556
if (net->vio->should_retry() && retry_count++ < net->retry_count)
558
net->error= 2; /* Close socket */
559
net->last_errno= ER_NET_PACKET_TOO_LARGE;
560
my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
568
if (retry_count++ < net->retry_count)
572
if (net->vio->get_errno() == EINTR)
576
net->error= 2; /* Close socket */
577
net->last_errno= (interrupted ? CR_NET_WRITE_INTERRUPTED :
578
CR_NET_ERROR_ON_WRITE);
583
/* If this is an error we may not have a current_session any more */
585
current_session->status_var.bytes_sent+= length;
588
if ((net->compress) && (packet != NULL))
589
free((char*) packet);
590
net->reading_or_writing=0;
592
return(((int) (pos != end)));
597
Reads one packet to net->buff + net->where_b.
598
Long packets are handled by drizzleclient_net_read().
599
This function reallocates the net->buff buffer if necessary.
602
Returns length of packet.
606
my_real_read(NET *net, size_t *complen)
610
uint32_t i,retry_count=0;
611
size_t len=packet_error;
612
uint32_t remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
617
net->reading_or_writing= 1;
618
/* Read timeout is set in drizzleclient_net_set_read_timeout */
620
pos = net->buff + net->where_b; /* net->packet -4 */
622
for (i= 0; i < 2 ; i++)
626
/* First read is done with non blocking mode */
627
if ((long) (length= net->vio->read(pos, remain)) <= 0L)
629
if (net->vio == NULL)
632
const bool interrupted = net->vio->should_retry();
635
{ /* Probably in MIT threads */
636
if (retry_count++ < net->retry_count)
639
if (net->vio->get_errno() == EINTR)
644
net->error= 2; /* Close socket */
645
net->last_errno= (net->vio->was_interrupted() ?
646
CR_NET_READ_INTERRUPTED :
650
remain -= (uint32_t) length;
652
current_session->status_var.bytes_received+= length;
655
{ /* First parts is packet length */
658
if (net->buff[net->where_b + 3] != (unsigned char) net->pkt_nr)
661
/* Not a NET error on the client. XXX: why? */
662
my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0));
665
net->compress_pkt_nr= ++net->pkt_nr;
669
If the packet is compressed then complen > 0 and contains the
670
number of bytes in the uncompressed packet
672
*complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
675
len=uint3korr(net->buff+net->where_b);
676
if (!len) /* End of big multi-packet */
678
helping = max(len,*complen) + net->where_b;
679
/* The necessary size of net->buff */
680
if (helping >= net->max_packet)
682
if (drizzleclient_net_realloc(net,helping))
684
/* Clear the buffer so libdrizzle doesn't keep retrying */
687
length= read(net->vio->get_fd(), net->buff, min((size_t)net->max_packet, len));
688
assert((long)length > 0L);
692
len= packet_error; /* Return error and close connection */
696
pos=net->buff + net->where_b;
697
remain = (uint32_t) len;
702
net->reading_or_writing= 0;
709
Read a packet from the client/server and return it without the internal
712
If the packet is the first packet of a multi-packet packet
713
(which is indicated by the length of the packet = 0xffffff) then
714
all sub packets are read and concatenated.
716
If the packet was compressed, its uncompressed and the length of the
717
uncompressed packet is returned.
720
The function returns the length of the found packet or packet_error.
721
net->read_pos points to the read data.
725
drizzleclient_net_read(NET *net)
731
len = my_real_read(net,&complen);
732
if (len == MAX_PACKET_LENGTH)
734
/* First packet of a multi-packet. Concatenate the packets */
735
uint32_t save_pos = net->where_b;
736
size_t total_length= 0;
741
len = my_real_read(net,&complen);
742
} while (len == MAX_PACKET_LENGTH);
743
if (len != packet_error)
745
net->where_b = save_pos;
747
net->read_pos = net->buff + net->where_b;
748
if (len != packet_error)
749
net->read_pos[len]=0; /* Safeguard for drizzleclient_use_result */
754
/* We are using the compressed protocol */
757
uint32_t start_of_packet;
758
uint32_t first_packet_offset;
759
uint32_t read_length, multi_byte_packet=0;
761
if (net->remain_in_buf)
763
buf_length= net->buf_length; /* Data left in old packet */
764
first_packet_offset= start_of_packet= (net->buf_length -
766
/* Restore the character that was overwritten by the end 0 */
767
net->buff[start_of_packet]= net->save_char;
771
/* reuse buffer, as there is nothing in it that we need */
772
buf_length= start_of_packet= first_packet_offset= 0;
778
if (buf_length - start_of_packet >= NET_HEADER_SIZE)
780
read_length = uint3korr(net->buff+start_of_packet);
783
/* End of multi-byte packet */
784
start_of_packet += NET_HEADER_SIZE;
787
if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet)
789
if (multi_byte_packet)
791
/* Remove packet header for second packet */
792
memmove(net->buff + first_packet_offset + start_of_packet,
793
net->buff + first_packet_offset + start_of_packet +
795
buf_length - start_of_packet);
796
start_of_packet += read_length;
797
buf_length -= NET_HEADER_SIZE;
800
start_of_packet+= read_length + NET_HEADER_SIZE;
802
if (read_length != MAX_PACKET_LENGTH) /* last package */
804
multi_byte_packet= 0; /* No last zero len packet */
807
multi_byte_packet= NET_HEADER_SIZE;
808
/* Move data down to read next data packet after current one */
809
if (first_packet_offset)
811
memmove(net->buff,net->buff+first_packet_offset,
812
buf_length-first_packet_offset);
813
buf_length-=first_packet_offset;
814
start_of_packet -= first_packet_offset;
815
first_packet_offset=0;
820
/* Move data down to read next data packet after current one */
821
if (first_packet_offset)
823
memmove(net->buff,net->buff+first_packet_offset,
824
buf_length-first_packet_offset);
825
buf_length-=first_packet_offset;
826
start_of_packet -= first_packet_offset;
827
first_packet_offset=0;
830
net->where_b=buf_length;
831
if ((packet_len = my_real_read(net,&complen)) == packet_error)
836
unsigned char * compbuf= (unsigned char *) malloc(complen);
839
uLongf tmp_complen= complen;
840
int error= uncompress((Bytef*) compbuf, &tmp_complen,
841
(Bytef*) (net->buff + net->where_b),
843
complen= tmp_complen;
847
net->error= 2; /* caller will close socket */
848
net->last_errno= CR_NET_UNCOMPRESS_ERROR;
852
memcpy((net->buff + net->where_b), compbuf, complen);
861
buf_length+= complen;
863
net->read_pos= net->buff+ first_packet_offset + NET_HEADER_SIZE;
864
net->buf_length= buf_length;
865
net->remain_in_buf= (uint32_t) (buf_length - start_of_packet);
866
len = ((uint32_t) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE -
868
net->save_char= net->read_pos[len]; /* Must be saved */
869
net->read_pos[len]=0; /* Safeguard for drizzleclient_use_result */
875
void drizzleclient_net_set_read_timeout(NET *net, uint32_t timeout)
877
net->read_timeout= timeout;
880
net->vio->timeout(0, timeout);
886
void drizzleclient_net_set_write_timeout(NET *net, uint32_t timeout)
888
net->write_timeout= timeout;
891
net->vio->timeout(1, timeout);
896
Clear possible error state of struct NET
898
@param net clear the state of the argument
901
void drizzleclient_drizzleclient_net_clear_error(NET *net)
904
net->last_error[0]= '\0';
905
strcpy(net->sqlstate, not_error_sqlstate);
908
} /* namespace drizzle_plugin */