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
21
#include <drizzled/global.h>
22
#include <drizzled/session.h>
23
#include "libdrizzle.h"
24
#include "libdrizzle_priv.h"
33
#include <sys/socket.h>
40
The following handles the differences when this is linked between the
41
client and the server.
43
This gives an error if a too big packet is found
44
The server can change this with the -O switch, but because the client
45
can't normally do this the client should have a bigger max_allowed_packet.
49
#define MAX_PACKET_LENGTH (256L*256L*256L-1)
51
static bool net_write_buff(NET *net, const unsigned char *packet, uint32_t len);
53
void drizzleclient_net_local_init(NET *net)
55
net->max_packet= (uint32_t) global_system_variables.net_buffer_length;
57
drizzleclient_net_set_read_timeout(net,
58
(uint32_t)global_system_variables.net_read_timeout);
59
drizzleclient_net_set_write_timeout(net,
60
(uint32_t)global_system_variables.net_write_timeout);
62
net->retry_count= (uint32_t) global_system_variables.net_retry_count;
63
net->max_packet_size= cmax(global_system_variables.net_buffer_length,
64
global_system_variables.max_allowed_packet);
67
/** Init with packet info. */
69
bool drizzleclient_net_init(NET *net, Vio* vio)
72
drizzleclient_net_local_init(net); /* Set some limits */
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 = drizzleclient_vio_fd(vio); /* For perl DBI/DBD */
89
drizzleclient_vio_fastsend(vio);
94
bool drizzleclient_net_init_sock(NET * net, int sock, int flags)
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))
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_should_close(NET *net)
152
return net->error || (net->vio == 0);
155
bool drizzleclient_net_more_data(NET *net)
157
return (net->vio == 0 || net->vio->read_pos < net->vio->read_end);
160
/** Realloc the packet buffer. */
162
bool drizzleclient_net_realloc(NET *net, size_t length)
167
if (length >= net->max_packet_size)
169
/* @todo: 1 and 2 codes are identical. */
171
net->last_errno= CR_NET_PACKET_TOO_LARGE;
174
pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
176
We must allocate some extra bytes for the end 0 and to be able to
177
read big compressed blocks
179
if (!(buff= (unsigned char*) realloc((char*) net->buff, pkt_length +
180
NET_HEADER_SIZE + COMP_HEADER_SIZE)))
182
/* @todo: 1 and 2 codes are identical. */
184
net->last_errno= CR_OUT_OF_MEMORY;
185
/* In the server the error is reported by MY_WME flag. */
188
net->buff=net->write_pos=buff;
189
net->buff_end=buff+(net->max_packet= (uint32_t) pkt_length);
195
Check if there is any data to be read from the socket.
197
@param sd socket descriptor
202
1 Data or EOF to read
204
-1 Don't know if data is ready or not
207
static bool net_data_is_ready(int sd)
213
ufds.events= POLLIN | POLLPRI;
214
if (!(res= poll(&ufds, 1, 0)))
216
if (res < 0 || !(ufds.revents & (POLLIN | POLLPRI)))
222
Remove unwanted characters from connection
223
and check if disconnected.
225
Read from socket until there is nothing more to read. Discard
228
If there is anything when to read 'drizzleclient_net_clear' is called this
229
normally indicates an error in the protocol.
231
When connection is properly closed (for TCP it means with
232
a FIN packet), then select() considers a socket "ready to read",
233
in the sense that there's EOF to read, but read() returns 0.
235
@param net NET handler
236
@param clear_buffer if <> 0, then clear all data from comm buff
239
void drizzleclient_net_clear(NET *net, bool clear_buffer)
243
while (net_data_is_ready(net->vio->sd) > 0)
245
/* The socket is ready */
246
if (drizzleclient_vio_read(net->vio, net->buff,
247
(size_t) net->max_packet) <= 0)
254
net->pkt_nr=net->compress_pkt_nr=0; /* Ready for new command */
255
net->write_pos=net->buff;
260
/** Flush write_buffer if not empty. */
262
bool drizzleclient_net_flush(NET *net)
265
if (net->buff != net->write_pos)
267
error=drizzleclient_net_real_write(net, net->buff,
268
(size_t) (net->write_pos - net->buff)) ? 1 : 0;
269
net->write_pos=net->buff;
271
/* Sync packet number if using compression */
273
net->pkt_nr=net->compress_pkt_nr;
278
/*****************************************************************************
279
** Write something to server/client buffer
280
*****************************************************************************/
283
Write a logical packet with packet header.
285
Format: Packet length (3 bytes), packet number(1 byte)
286
When compression is used a 3 byte compression length is added
289
If compression is used the original package is modified!
293
drizzleclient_net_write(NET *net,const unsigned char *packet,size_t len)
295
unsigned char buff[NET_HEADER_SIZE];
296
if (unlikely(!net->vio)) /* nowhere to write */
299
Big packets are handled by splitting them in packets of MAX_PACKET_LENGTH
300
length. The last packet is always a packet that is < MAX_PACKET_LENGTH.
301
(The last packet may even have a length of 0)
303
while (len >= MAX_PACKET_LENGTH)
305
const uint32_t z_size = MAX_PACKET_LENGTH;
306
int3store(buff, z_size);
307
buff[3]= (unsigned char) net->pkt_nr++;
308
if (net_write_buff(net, buff, NET_HEADER_SIZE) ||
309
net_write_buff(net, packet, z_size))
314
/* Write last packet */
316
buff[3]= (unsigned char) net->pkt_nr++;
317
if (net_write_buff(net, buff, NET_HEADER_SIZE))
319
return net_write_buff(net,packet,len) ? 1 : 0;
323
Send a command to the server.
325
The reason for having both header and packet is so that libdrizzle
326
can easy add a header to a special command (like prepared statements)
327
without having to re-alloc the string.
329
As the command is part of the first data packet, we have to do some data
330
juggling to put the command in there, without having to create a new
333
This function will split big packets into sub-packets if needed.
334
(Each sub packet can only be 2^24 bytes)
336
@param net NET handler
337
@param command Command in MySQL server (enum enum_server_command)
338
@param header Header to write after command
339
@param head_len Length of header
340
@param packet Query or parameter to query
341
@param len Length of packet
350
drizzleclient_net_write_command(NET *net,unsigned char command,
351
const unsigned char *header, size_t head_len,
352
const unsigned char *packet, size_t len)
354
uint32_t length=len+1+head_len; /* 1 extra byte for command */
355
unsigned char buff[NET_HEADER_SIZE+1];
356
uint32_t header_size=NET_HEADER_SIZE+1;
358
buff[4]=command; /* For first packet */
360
if (length >= MAX_PACKET_LENGTH)
362
/* Take into account that we have the command in the first header */
363
len= MAX_PACKET_LENGTH - 1 - head_len;
366
int3store(buff, MAX_PACKET_LENGTH);
367
buff[3]= (unsigned char) net->pkt_nr++;
368
if (net_write_buff(net, buff, header_size) ||
369
net_write_buff(net, header, head_len) ||
370
net_write_buff(net, packet, len))
373
length-= MAX_PACKET_LENGTH;
374
len= MAX_PACKET_LENGTH;
376
header_size= NET_HEADER_SIZE;
377
} while (length >= MAX_PACKET_LENGTH);
378
len=length; /* Data left to be written */
380
int3store(buff,length);
381
buff[3]= (unsigned char) net->pkt_nr++;
382
return((net_write_buff(net, buff, header_size) ||
383
(head_len && net_write_buff(net, header, head_len)) ||
384
net_write_buff(net, packet, len) || drizzleclient_net_flush(net)) ? 1 : 0 );
388
Caching the data in a local buffer before sending it.
390
Fill up net->buffer and send it to the client when full.
392
If the rest of the to-be-sent-packet is bigger than buffer,
393
send it in one big block (to avoid copying to internal buffer).
394
If not, copy the rest of the data to the buffer and return without
397
@param net Network handler
398
@param packet Packet to send
399
@param len Length of packet
402
The cached buffer can be sent as it is with 'drizzleclient_net_flush()'.
403
In this code we have to be careful to not send a packet longer than
404
MAX_PACKET_LENGTH to drizzleclient_net_real_write() if we are using the compressed
405
protocol as we store the length of the compressed packet in 3 bytes.
414
net_write_buff(NET *net, const unsigned char *packet, uint32_t len)
416
uint32_t left_length;
417
if (net->compress && net->max_packet > MAX_PACKET_LENGTH)
418
left_length= MAX_PACKET_LENGTH - (net->write_pos - net->buff);
420
left_length= (uint32_t) (net->buff_end - net->write_pos);
422
if (len > left_length)
424
if (net->write_pos != net->buff)
426
/* Fill up already used packet and write it */
427
memcpy(net->write_pos,packet,left_length);
428
if (drizzleclient_net_real_write(net, net->buff,
429
(size_t) (net->write_pos - net->buff) + left_length))
431
net->write_pos= net->buff;
432
packet+= left_length;
438
We can't have bigger packets than 16M with compression
439
Because the uncompressed length is stored in 3 bytes
441
left_length= MAX_PACKET_LENGTH;
442
while (len > left_length)
444
if (drizzleclient_net_real_write(net, packet, left_length))
446
packet+= left_length;
450
if (len > net->max_packet)
451
return drizzleclient_net_real_write(net, packet, len) ? 1 : 0;
452
/* Send out rest of the blocks as full sized blocks */
454
memcpy(net->write_pos,packet,len);
455
net->write_pos+= len;
461
Read and write one packet using timeouts.
462
If needed, the packet is compressed before sending.
465
- TODO is it needed to set this variable if we have no socket
469
TODO: rewrite this in a manner to do non-block writes. If a write can not be made, and we are
470
in the server, yield to another process and come back later.
473
drizzleclient_net_real_write(NET *net, const unsigned char *packet, size_t len)
476
const unsigned char *pos, *end;
477
uint32_t retry_count= 0;
479
/* Backup of the original SO_RCVTIMEO timeout */
482
return(-1); /* socket can't be used */
484
net->reading_or_writing=2;
489
const uint32_t header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
490
if (!(b= (unsigned char*) malloc(len + NET_HEADER_SIZE +
494
net->last_errno= CR_OUT_OF_MEMORY;
495
/* In the server, the error is reported by MY_WME flag. */
496
net->reading_or_writing= 0;
499
memcpy(b+header_length,packet,len);
501
complen= len * 120 / 100 + 12;
502
unsigned char * compbuf= (unsigned char *) malloc(complen);
505
uLongf tmp_complen= complen;
506
int res= compress((Bytef*) compbuf, &tmp_complen,
507
(Bytef*) (b+header_length),
509
complen= tmp_complen;
513
if ((res != Z_OK) || (complen >= len))
517
size_t tmplen= complen;
526
int3store(&b[NET_HEADER_SIZE],complen);
528
b[3]=(unsigned char) (net->compress_pkt_nr++);
535
/* Loop until we have read everything */
539
if ((long) (length= drizzleclient_vio_write(net->vio, pos, (size_t) (end-pos))) <= 0)
541
const bool interrupted= drizzleclient_vio_should_retry(net->vio);
543
If we read 0, or we were interrupted this means that
544
we need to switch to blocking mode and wait until the timeout
545
on the socket kicks in.
547
if ((interrupted || length == 0))
551
while (drizzleclient_vio_blocking(net->vio, true, &old_mode) < 0)
553
if (drizzleclient_vio_should_retry(net->vio) && retry_count++ < net->retry_count)
555
net->error= 2; /* Close socket */
556
net->last_errno= CR_NET_PACKET_TOO_LARGE;
564
if (retry_count++ < net->retry_count)
568
if (drizzleclient_vio_errno(net->vio) == EINTR)
572
net->error= 2; /* Close socket */
573
net->last_errno= (interrupted ? CR_NET_WRITE_INTERRUPTED :
574
CR_NET_ERROR_ON_WRITE);
580
if ((net->compress) && (packet != NULL))
581
free((char*) packet);
582
net->reading_or_writing=0;
584
return(((int) (pos != end)));
589
Reads one packet to net->buff + net->where_b.
590
Long packets are handled by drizzleclient_net_read().
591
This function reallocates the net->buff buffer if necessary.
594
Returns length of packet.
598
my_real_read(NET *net, size_t *complen)
602
uint32_t i,retry_count=0;
603
size_t len=packet_error;
604
uint32_t remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
609
net->reading_or_writing= 1;
610
/* Read timeout is set in drizzleclient_net_set_read_timeout */
612
pos = net->buff + net->where_b; /* net->packet -4 */
614
for (i= 0; i < 2 ; i++)
618
/* First read is done with non blocking mode */
619
if ((long) (length= drizzleclient_vio_read(net->vio, pos, remain)) <= 0L)
621
const bool interrupted = drizzleclient_vio_should_retry(net->vio);
624
{ /* Probably in MIT threads */
625
if (retry_count++ < net->retry_count)
628
if (drizzleclient_vio_errno(net->vio) == EINTR)
633
net->error= 2; /* Close socket */
634
net->last_errno= (drizzleclient_vio_was_interrupted(net->vio) ?
635
CR_NET_READ_INTERRUPTED :
640
remain -= (uint32_t) length;
644
{ /* First parts is packet length */
647
if (net->buff[net->where_b + 3] != (unsigned char) net->pkt_nr)
650
/* Not a NET error on the client. XXX: why? */
653
net->compress_pkt_nr= ++net->pkt_nr;
657
If the packet is compressed then complen > 0 and contains the
658
number of bytes in the uncompressed packet
660
*complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
663
len=uint3korr(net->buff+net->where_b);
664
if (!len) /* End of big multi-packet */
666
helping = max(len,*complen) + net->where_b;
667
/* The necessary size of net->buff */
668
if (helping >= net->max_packet)
670
if (drizzleclient_net_realloc(net,helping))
672
len= packet_error; /* Return error and close connection */
676
pos=net->buff + net->where_b;
677
remain = (uint32_t) len;
682
net->reading_or_writing= 0;
689
Read a packet from the client/server and return it without the internal
692
If the packet is the first packet of a multi-packet packet
693
(which is indicated by the length of the packet = 0xffffff) then
694
all sub packets are read and concatenated.
696
If the packet was compressed, its uncompressed and the length of the
697
uncompressed packet is returned.
700
The function returns the length of the found packet or packet_error.
701
net->read_pos points to the read data.
705
drizzleclient_net_read(NET *net)
711
len = my_real_read(net,&complen);
712
if (len == MAX_PACKET_LENGTH)
714
/* First packet of a multi-packet. Concatenate the packets */
715
uint32_t save_pos = net->where_b;
716
size_t total_length= 0;
721
len = my_real_read(net,&complen);
722
} while (len == MAX_PACKET_LENGTH);
723
if (len != packet_error)
725
net->where_b = save_pos;
727
net->read_pos = net->buff + net->where_b;
728
if (len != packet_error)
729
net->read_pos[len]=0; /* Safeguard for drizzleclient_use_result */
734
/* We are using the compressed protocol */
737
uint32_t start_of_packet;
738
uint32_t first_packet_offset;
739
uint32_t read_length, multi_byte_packet=0;
741
if (net->remain_in_buf)
743
buf_length= net->buf_length; /* Data left in old packet */
744
first_packet_offset= start_of_packet= (net->buf_length -
746
/* Restore the character that was overwritten by the end 0 */
747
net->buff[start_of_packet]= net->save_char;
751
/* reuse buffer, as there is nothing in it that we need */
752
buf_length= start_of_packet= first_packet_offset= 0;
758
if (buf_length - start_of_packet >= NET_HEADER_SIZE)
760
read_length = uint3korr(net->buff+start_of_packet);
763
/* End of multi-byte packet */
764
start_of_packet += NET_HEADER_SIZE;
767
if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet)
769
if (multi_byte_packet)
771
/* Remove packet header for second packet */
772
memmove(net->buff + first_packet_offset + start_of_packet,
773
net->buff + first_packet_offset + start_of_packet +
775
buf_length - start_of_packet);
776
start_of_packet += read_length;
777
buf_length -= NET_HEADER_SIZE;
780
start_of_packet+= read_length + NET_HEADER_SIZE;
782
if (read_length != MAX_PACKET_LENGTH) /* last package */
784
multi_byte_packet= 0; /* No last zero len packet */
787
multi_byte_packet= NET_HEADER_SIZE;
788
/* Move data down to read next data packet after current one */
789
if (first_packet_offset)
791
memmove(net->buff,net->buff+first_packet_offset,
792
buf_length-first_packet_offset);
793
buf_length-=first_packet_offset;
794
start_of_packet -= first_packet_offset;
795
first_packet_offset=0;
800
/* Move data down to read next data packet after current one */
801
if (first_packet_offset)
803
memmove(net->buff,net->buff+first_packet_offset,
804
buf_length-first_packet_offset);
805
buf_length-=first_packet_offset;
806
start_of_packet -= first_packet_offset;
807
first_packet_offset=0;
810
net->where_b=buf_length;
811
if ((packet_len = my_real_read(net,&complen)) == packet_error)
816
unsigned char * compbuf= (unsigned char *) malloc(complen);
819
uLongf tmp_complen= complen;
820
int error= uncompress((Bytef*) compbuf, &tmp_complen,
821
(Bytef*) (net->buff + net->where_b),
823
complen= tmp_complen;
827
net->error= 2; /* caller will close socket */
828
net->last_errno= CR_NET_UNCOMPRESS_ERROR;
832
memcpy((net->buff + net->where_b), compbuf, complen);
841
buf_length+= complen;
843
net->read_pos= net->buff+ first_packet_offset + NET_HEADER_SIZE;
844
net->buf_length= buf_length;
845
net->remain_in_buf= (uint32_t) (buf_length - start_of_packet);
846
len = ((uint32_t) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE -
848
net->save_char= net->read_pos[len]; /* Must be saved */
849
net->read_pos[len]=0; /* Safeguard for drizzleclient_use_result */
855
void drizzleclient_net_set_read_timeout(NET *net, uint32_t timeout)
857
net->read_timeout= timeout;
860
drizzleclient_vio_timeout(net->vio, 0, timeout);
866
void drizzleclient_net_set_write_timeout(NET *net, uint32_t timeout)
868
net->write_timeout= timeout;
871
drizzleclient_vio_timeout(net->vio, 1, timeout);
876
Clear possible error state of struct NET
878
@param net clear the state of the argument
881
void drizzleclient_drizzleclient_net_clear_error(NET *net)
884
net->last_error[0]= '\0';
885
strcpy(net->sqlstate, drizzleclient_sqlstate_get_not_error());