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>
30
#include <sys/socket.h>
41
namespace drizzle_protocol
45
The following handles the differences when this is linked between the
46
client and the server.
48
This gives an error if a too big packet is found
49
The server can change this with the -O switch, but because the client
50
can't normally do this the client should have a bigger max_allowed_packet.
53
/* Constants when using compression */
54
#define NET_HEADER_SIZE 4 /* standard header size */
55
#define COMP_HEADER_SIZE 3 /* compression header extra size */
57
#define MAX_PACKET_LENGTH (256L*256L*256L-1)
58
const char *not_error_sqlstate= "00000";
60
static bool net_write_buff(NET *net, const unsigned char *packet, uint32_t len);
61
static int drizzleclient_net_real_write(NET *net, const unsigned char *packet, size_t len);
63
/** Init with packet info. */
65
bool drizzleclient_net_init(NET *net, Vio* vio, uint32_t buffer_length)
68
net->max_packet= (uint32_t) buffer_length;
69
net->max_packet_size= max(buffer_length,
70
drizzled::global_system_variables.max_allowed_packet);
72
if (!(net->buff=(unsigned char*) malloc((size_t) net->max_packet+
73
NET_HEADER_SIZE + COMP_HEADER_SIZE)))
75
net->buff_end=net->buff+net->max_packet;
76
net->error=0; net->return_status=0;
77
net->pkt_nr=net->compress_pkt_nr=0;
78
net->write_pos=net->read_pos = net->buff;
80
net->compress=0; net->reading_or_writing=0;
81
net->where_b = net->remain_in_buf=0;
85
if (vio != 0) /* If real connection */
87
net->fd = drizzleclient_vio_fd(vio); /* For perl DBI/DBD */
88
drizzleclient_vio_fastsend(vio);
93
bool drizzleclient_net_init_sock(NET * net, int sock, int flags,
94
uint32_t buffer_length)
97
Vio *drizzleclient_vio_tmp= drizzleclient_vio_new(sock, VIO_TYPE_TCPIP, flags);
98
if (drizzleclient_vio_tmp == NULL)
101
if (drizzleclient_net_init(net, drizzleclient_vio_tmp, buffer_length))
103
/* Only delete the temporary vio if we didn't already attach it to the
106
if (drizzleclient_vio_tmp && (net->vio != drizzleclient_vio_tmp))
107
drizzleclient_vio_delete(drizzleclient_vio_tmp);
110
(void) shutdown(sock, SHUT_RDWR);
118
void drizzleclient_net_end(NET *net)
120
if (net->buff != NULL)
126
void drizzleclient_net_close(NET *net)
128
if (net->vio != NULL)
130
drizzleclient_vio_delete(net->vio);
135
bool drizzleclient_net_peer_addr(NET *net, char *buf, uint16_t *port, size_t buflen)
137
return drizzleclient_vio_peer_addr(net->vio, buf, port, buflen);
140
void drizzleclient_net_keepalive(NET *net, bool flag)
142
drizzleclient_vio_keepalive(net->vio, flag);
145
int drizzleclient_net_get_sd(NET *net)
150
bool drizzleclient_net_more_data(NET *net)
152
return (net->vio == 0 || net->vio->read_pos < net->vio->read_end);
155
/** Realloc the packet buffer. */
157
static bool drizzleclient_net_realloc(NET *net, size_t length)
162
if (length >= net->max_packet_size)
164
/* @todo: 1 and 2 codes are identical. */
166
net->last_errno= CR_NET_PACKET_TOO_LARGE;
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->sd) > 0)
240
/* The socket is ready */
241
if (drizzleclient_vio_read(net->vio, net->buff,
242
(size_t) net->max_packet) <= 0)
249
net->pkt_nr=net->compress_pkt_nr=0; /* Ready for new command */
250
net->write_pos=net->buff;
255
/** Flush write_buffer if not empty. */
257
bool drizzleclient_net_flush(NET *net)
260
if (net->buff != net->write_pos)
262
error=drizzleclient_net_real_write(net, net->buff,
263
(size_t) (net->write_pos - net->buff)) ? 1 : 0;
264
net->write_pos=net->buff;
266
/* Sync packet number if using compression */
268
net->pkt_nr=net->compress_pkt_nr;
273
/*****************************************************************************
274
** Write something to server/client buffer
275
*****************************************************************************/
278
Write a logical packet with packet header.
280
Format: Packet length (3 bytes), packet number(1 byte)
281
When compression is used a 3 byte compression length is added
284
If compression is used the original package is modified!
288
drizzleclient_net_write(NET *net,const unsigned char *packet,size_t len)
290
unsigned char buff[NET_HEADER_SIZE];
291
if (unlikely(!net->vio)) /* nowhere to write */
294
Big packets are handled by splitting them in packets of MAX_PACKET_LENGTH
295
length. The last packet is always a packet that is < MAX_PACKET_LENGTH.
296
(The last packet may even have a length of 0)
298
while (len >= MAX_PACKET_LENGTH)
300
const uint32_t z_size = MAX_PACKET_LENGTH;
301
int3store(buff, z_size);
302
buff[3]= (unsigned char) net->pkt_nr++;
303
if (net_write_buff(net, buff, NET_HEADER_SIZE) ||
304
net_write_buff(net, packet, z_size))
309
/* Write last packet */
311
buff[3]= (unsigned char) net->pkt_nr++;
312
if (net_write_buff(net, buff, NET_HEADER_SIZE))
314
return net_write_buff(net,packet,len) ? 1 : 0;
318
Send a command to the server.
320
The reason for having both header and packet is so that libdrizzle
321
can easy add a header to a special command (like prepared statements)
322
without having to re-alloc the string.
324
As the command is part of the first data packet, we have to do some data
325
juggling to put the command in there, without having to create a new
328
This function will split big packets into sub-packets if needed.
329
(Each sub packet can only be 2^24 bytes)
331
@param net NET handler
332
@param command Command in MySQL server (enum enum_server_command)
333
@param header Header to write after command
334
@param head_len Length of header
335
@param packet Query or parameter to query
336
@param len Length of packet
345
drizzleclient_net_write_command(NET *net,unsigned char command,
346
const unsigned char *header, size_t head_len,
347
const unsigned char *packet, size_t len)
349
uint32_t length=len+1+head_len; /* 1 extra byte for command */
350
unsigned char buff[NET_HEADER_SIZE+1];
351
uint32_t header_size=NET_HEADER_SIZE+1;
353
buff[4]=command; /* For first packet */
355
if (length >= MAX_PACKET_LENGTH)
357
/* Take into account that we have the command in the first header */
358
len= MAX_PACKET_LENGTH - 1 - head_len;
361
int3store(buff, MAX_PACKET_LENGTH);
362
buff[3]= (unsigned char) net->pkt_nr++;
363
if (net_write_buff(net, buff, header_size) ||
364
net_write_buff(net, header, head_len) ||
365
net_write_buff(net, packet, len))
368
length-= MAX_PACKET_LENGTH;
369
len= MAX_PACKET_LENGTH;
371
header_size= NET_HEADER_SIZE;
372
} while (length >= MAX_PACKET_LENGTH);
373
len=length; /* Data left to be written */
375
int3store(buff,length);
376
buff[3]= (unsigned char) net->pkt_nr++;
377
return((net_write_buff(net, buff, header_size) ||
378
(head_len && net_write_buff(net, header, head_len)) ||
379
net_write_buff(net, packet, len) || drizzleclient_net_flush(net)) ? 1 : 0 );
383
Caching the data in a local buffer before sending it.
385
Fill up net->buffer and send it to the client when full.
387
If the rest of the to-be-sent-packet is bigger than buffer,
388
send it in one big block (to avoid copying to internal buffer).
389
If not, copy the rest of the data to the buffer and return without
392
@param net Network handler
393
@param packet Packet to send
394
@param len Length of packet
397
The cached buffer can be sent as it is with 'drizzleclient_net_flush()'.
398
In this code we have to be careful to not send a packet longer than
399
MAX_PACKET_LENGTH to drizzleclient_net_real_write() if we are using the compressed
400
protocol as we store the length of the compressed packet in 3 bytes.
409
net_write_buff(NET *net, const unsigned char *packet, uint32_t len)
411
uint32_t left_length;
412
if (net->compress && net->max_packet > MAX_PACKET_LENGTH)
413
left_length= MAX_PACKET_LENGTH - (net->write_pos - net->buff);
415
left_length= (uint32_t) (net->buff_end - net->write_pos);
417
if (len > left_length)
419
if (net->write_pos != net->buff)
421
/* Fill up already used packet and write it */
422
memcpy(net->write_pos,packet,left_length);
423
if (drizzleclient_net_real_write(net, net->buff,
424
(size_t) (net->write_pos - net->buff) + left_length))
426
net->write_pos= net->buff;
427
packet+= left_length;
433
We can't have bigger packets than 16M with compression
434
Because the uncompressed length is stored in 3 bytes
436
left_length= MAX_PACKET_LENGTH;
437
while (len > left_length)
439
if (drizzleclient_net_real_write(net, packet, left_length))
441
packet+= left_length;
445
if (len > net->max_packet)
446
return drizzleclient_net_real_write(net, packet, len) ? 1 : 0;
447
/* Send out rest of the blocks as full sized blocks */
449
memcpy(net->write_pos,packet,len);
450
net->write_pos+= len;
456
Read and write one packet using timeouts.
457
If needed, the packet is compressed before sending.
460
- TODO is it needed to set this variable if we have no socket
464
TODO: rewrite this in a manner to do non-block writes. If a write can not be made, and we are
465
in the server, yield to another process and come back later.
468
drizzleclient_net_real_write(NET *net, const unsigned char *packet, size_t len)
471
const unsigned char *pos, *end;
472
uint32_t retry_count= 0;
474
/* Backup of the original SO_RCVTIMEO timeout */
477
return(-1); /* socket can't be used */
479
net->reading_or_writing=2;
484
const uint32_t header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
485
if (!(b= (unsigned char*) malloc(len + NET_HEADER_SIZE +
489
net->last_errno= CR_OUT_OF_MEMORY;
490
/* In the server, the error is reported by MY_WME flag. */
491
net->reading_or_writing= 0;
494
memcpy(b+header_length,packet,len);
496
complen= len * 120 / 100 + 12;
497
unsigned char * compbuf= (unsigned char *) malloc(complen);
500
uLongf tmp_complen= complen;
501
int res= compress((Bytef*) compbuf, &tmp_complen,
502
(Bytef*) (b+header_length),
504
complen= tmp_complen;
508
if ((res != Z_OK) || (complen >= len))
512
size_t tmplen= complen;
521
int3store(&b[NET_HEADER_SIZE],complen);
523
b[3]=(unsigned char) (net->compress_pkt_nr++);
530
/* Loop until we have read everything */
534
if ((long) (length= drizzleclient_vio_write(net->vio, 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= drizzleclient_vio_should_retry(net->vio);
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 (drizzleclient_vio_blocking(net->vio, true, &old_mode) < 0)
556
if (drizzleclient_vio_should_retry(net->vio) && retry_count++ < net->retry_count)
558
net->error= 2; /* Close socket */
559
net->last_errno= CR_NET_PACKET_TOO_LARGE;
567
if (retry_count++ < net->retry_count)
571
if (drizzleclient_vio_errno(net->vio) == EINTR)
575
net->error= 2; /* Close socket */
576
net->last_errno= (interrupted ? CR_NET_WRITE_INTERRUPTED :
577
CR_NET_ERROR_ON_WRITE);
583
if ((net->compress) && (packet != NULL))
584
free((char*) packet);
585
net->reading_or_writing=0;
587
return(((int) (pos != end)));
592
Reads one packet to net->buff + net->where_b.
593
Long packets are handled by drizzleclient_net_read().
594
This function reallocates the net->buff buffer if necessary.
597
Returns length of packet.
601
my_real_read(NET *net, size_t *complen)
605
uint32_t i,retry_count=0;
606
size_t len=packet_error;
607
uint32_t remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
612
net->reading_or_writing= 1;
613
/* Read timeout is set in drizzleclient_net_set_read_timeout */
615
pos = net->buff + net->where_b; /* net->packet -4 */
617
for (i= 0; i < 2 ; i++)
621
/* First read is done with non blocking mode */
622
if ((long) (length= drizzleclient_vio_read(net->vio, pos, remain)) <= 0L)
624
if (net->vio == NULL)
627
const bool interrupted = drizzleclient_vio_should_retry(net->vio);
630
{ /* Probably in MIT threads */
631
if (retry_count++ < net->retry_count)
634
if (drizzleclient_vio_errno(net->vio) == EINTR)
639
net->error= 2; /* Close socket */
640
net->last_errno= (drizzleclient_vio_was_interrupted(net->vio) ?
641
CR_NET_READ_INTERRUPTED :
646
remain -= (uint32_t) length;
650
{ /* First parts is packet length */
653
if (net->buff[net->where_b + 3] != (unsigned char) net->pkt_nr)
656
/* Not a NET error on the client. XXX: why? */
659
net->compress_pkt_nr= ++net->pkt_nr;
663
If the packet is compressed then complen > 0 and contains the
664
number of bytes in the uncompressed packet
666
*complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
669
len=uint3korr(net->buff+net->where_b);
670
if (!len) /* End of big multi-packet */
672
helping = max(len,*complen) + net->where_b;
673
/* The necessary size of net->buff */
674
if (helping >= net->max_packet)
676
if (drizzleclient_net_realloc(net,helping))
678
len= packet_error; /* Return error and close connection */
682
pos=net->buff + net->where_b;
683
remain = (uint32_t) len;
688
net->reading_or_writing= 0;
695
Read a packet from the client/server and return it without the internal
698
If the packet is the first packet of a multi-packet packet
699
(which is indicated by the length of the packet = 0xffffff) then
700
all sub packets are read and concatenated.
702
If the packet was compressed, its uncompressed and the length of the
703
uncompressed packet is returned.
706
The function returns the length of the found packet or packet_error.
707
net->read_pos points to the read data.
711
drizzleclient_net_read(NET *net)
717
len = my_real_read(net,&complen);
718
if (len == MAX_PACKET_LENGTH)
720
/* First packet of a multi-packet. Concatenate the packets */
721
uint32_t save_pos = net->where_b;
722
size_t total_length= 0;
727
len = my_real_read(net,&complen);
728
} while (len == MAX_PACKET_LENGTH);
729
if (len != packet_error)
731
net->where_b = save_pos;
733
net->read_pos = net->buff + net->where_b;
734
if (len != packet_error)
735
net->read_pos[len]=0; /* Safeguard for drizzleclient_use_result */
740
/* We are using the compressed protocol */
743
uint32_t start_of_packet;
744
uint32_t first_packet_offset;
745
uint32_t read_length, multi_byte_packet=0;
747
if (net->remain_in_buf)
749
buf_length= net->buf_length; /* Data left in old packet */
750
first_packet_offset= start_of_packet= (net->buf_length -
752
/* Restore the character that was overwritten by the end 0 */
753
net->buff[start_of_packet]= net->save_char;
757
/* reuse buffer, as there is nothing in it that we need */
758
buf_length= start_of_packet= first_packet_offset= 0;
764
if (buf_length - start_of_packet >= NET_HEADER_SIZE)
766
read_length = uint3korr(net->buff+start_of_packet);
769
/* End of multi-byte packet */
770
start_of_packet += NET_HEADER_SIZE;
773
if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet)
775
if (multi_byte_packet)
777
/* Remove packet header for second packet */
778
memmove(net->buff + first_packet_offset + start_of_packet,
779
net->buff + first_packet_offset + start_of_packet +
781
buf_length - start_of_packet);
782
start_of_packet += read_length;
783
buf_length -= NET_HEADER_SIZE;
786
start_of_packet+= read_length + NET_HEADER_SIZE;
788
if (read_length != MAX_PACKET_LENGTH) /* last package */
790
multi_byte_packet= 0; /* No last zero len packet */
793
multi_byte_packet= NET_HEADER_SIZE;
794
/* Move data down to read next data packet after current one */
795
if (first_packet_offset)
797
memmove(net->buff,net->buff+first_packet_offset,
798
buf_length-first_packet_offset);
799
buf_length-=first_packet_offset;
800
start_of_packet -= first_packet_offset;
801
first_packet_offset=0;
806
/* Move data down to read next data packet after current one */
807
if (first_packet_offset)
809
memmove(net->buff,net->buff+first_packet_offset,
810
buf_length-first_packet_offset);
811
buf_length-=first_packet_offset;
812
start_of_packet -= first_packet_offset;
813
first_packet_offset=0;
816
net->where_b=buf_length;
817
if ((packet_len = my_real_read(net,&complen)) == packet_error)
822
unsigned char * compbuf= (unsigned char *) malloc(complen);
825
uLongf tmp_complen= complen;
826
int error= uncompress((Bytef*) compbuf, &tmp_complen,
827
(Bytef*) (net->buff + net->where_b),
829
complen= tmp_complen;
833
net->error= 2; /* caller will close socket */
834
net->last_errno= CR_NET_UNCOMPRESS_ERROR;
838
memcpy((net->buff + net->where_b), compbuf, complen);
847
buf_length+= complen;
849
net->read_pos= net->buff+ first_packet_offset + NET_HEADER_SIZE;
850
net->buf_length= buf_length;
851
net->remain_in_buf= (uint32_t) (buf_length - start_of_packet);
852
len = ((uint32_t) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE -
854
net->save_char= net->read_pos[len]; /* Must be saved */
855
net->read_pos[len]=0; /* Safeguard for drizzleclient_use_result */
861
void drizzleclient_net_set_read_timeout(NET *net, uint32_t timeout)
863
net->read_timeout= timeout;
866
drizzleclient_vio_timeout(net->vio, 0, timeout);
872
void drizzleclient_net_set_write_timeout(NET *net, uint32_t timeout)
874
net->write_timeout= timeout;
877
drizzleclient_vio_timeout(net->vio, 1, timeout);
882
Clear possible error state of struct NET
884
@param net clear the state of the argument
887
void drizzleclient_drizzleclient_net_clear_error(NET *net)
890
net->last_error[0]= '\0';
891
strcpy(net->sqlstate, not_error_sqlstate);
894
} /* namespace drizzle_protocol */