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>
42
The following handles the differences when this is linked between the
43
client and the server.
45
This gives an error if a too big packet is found
46
The server can change this with the -O switch, but because the client
47
can't normally do this the client should have a bigger max_allowed_packet.
51
#define MAX_PACKET_LENGTH (256L*256L*256L-1)
53
static bool net_write_buff(NET *net, const unsigned char *packet, uint32_t len);
55
void drizzleclient_net_local_init(NET *net)
57
net->max_packet= (uint32_t) global_system_variables.net_buffer_length;
58
net->max_packet_size= max(global_system_variables.net_buffer_length,
59
global_system_variables.max_allowed_packet);
62
/** Init with packet info. */
64
bool drizzleclient_net_init(NET *net, Vio* vio)
67
drizzleclient_net_local_init(net); /* Set some limits */
68
if (!(net->buff=(unsigned char*) malloc((size_t) net->max_packet+
69
NET_HEADER_SIZE + COMP_HEADER_SIZE)))
71
net->buff_end=net->buff+net->max_packet;
72
net->error=0; net->return_status=0;
73
net->pkt_nr=net->compress_pkt_nr=0;
74
net->write_pos=net->read_pos = net->buff;
76
net->compress=0; net->reading_or_writing=0;
77
net->where_b = net->remain_in_buf=0;
81
if (vio != 0) /* If real connection */
83
net->fd = drizzleclient_vio_fd(vio); /* For perl DBI/DBD */
84
drizzleclient_vio_fastsend(vio);
89
bool drizzleclient_net_init_sock(NET * net, int sock, int flags)
92
Vio *drizzleclient_vio_tmp= drizzleclient_vio_new(sock, VIO_TYPE_TCPIP, flags);
93
if (drizzleclient_vio_tmp == NULL)
96
if (drizzleclient_net_init(net, drizzleclient_vio_tmp))
98
/* Only delete the temporary vio if we didn't already attach it to the
101
if (drizzleclient_vio_tmp && (net->vio != drizzleclient_vio_tmp))
102
drizzleclient_vio_delete(drizzleclient_vio_tmp);
105
(void) shutdown(sock, SHUT_RDWR);
113
void drizzleclient_net_end(NET *net)
115
if (net->buff != NULL)
121
void drizzleclient_net_close(NET *net)
123
if (net->vio != NULL)
125
drizzleclient_vio_delete(net->vio);
130
bool drizzleclient_net_peer_addr(NET *net, char *buf, uint16_t *port, size_t buflen)
132
return drizzleclient_vio_peer_addr(net->vio, buf, port, buflen);
135
void drizzleclient_net_keepalive(NET *net, bool flag)
137
drizzleclient_vio_keepalive(net->vio, flag);
140
int drizzleclient_net_get_sd(NET *net)
145
bool drizzleclient_net_should_close(NET *net)
147
return net->error || (net->vio == 0);
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
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)
536
const bool interrupted= drizzleclient_vio_should_retry(net->vio);
538
If we read 0, or we were interrupted this means that
539
we need to switch to blocking mode and wait until the timeout
540
on the socket kicks in.
542
if ((interrupted || length == 0))
546
while (drizzleclient_vio_blocking(net->vio, true, &old_mode) < 0)
548
if (drizzleclient_vio_should_retry(net->vio) && retry_count++ < net->retry_count)
550
net->error= 2; /* Close socket */
551
net->last_errno= CR_NET_PACKET_TOO_LARGE;
559
if (retry_count++ < net->retry_count)
563
if (drizzleclient_vio_errno(net->vio) == EINTR)
567
net->error= 2; /* Close socket */
568
net->last_errno= (interrupted ? CR_NET_WRITE_INTERRUPTED :
569
CR_NET_ERROR_ON_WRITE);
575
if ((net->compress) && (packet != NULL))
576
free((char*) packet);
577
net->reading_or_writing=0;
579
return(((int) (pos != end)));
584
Reads one packet to net->buff + net->where_b.
585
Long packets are handled by drizzleclient_net_read().
586
This function reallocates the net->buff buffer if necessary.
589
Returns length of packet.
593
my_real_read(NET *net, size_t *complen)
597
uint32_t i,retry_count=0;
598
size_t len=packet_error;
599
uint32_t remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
604
net->reading_or_writing= 1;
605
/* Read timeout is set in drizzleclient_net_set_read_timeout */
607
pos = net->buff + net->where_b; /* net->packet -4 */
609
for (i= 0; i < 2 ; i++)
613
/* First read is done with non blocking mode */
614
if ((long) (length= drizzleclient_vio_read(net->vio, pos, remain)) <= 0L)
616
const bool interrupted = drizzleclient_vio_should_retry(net->vio);
619
{ /* Probably in MIT threads */
620
if (retry_count++ < net->retry_count)
623
if (drizzleclient_vio_errno(net->vio) == EINTR)
628
net->error= 2; /* Close socket */
629
net->last_errno= (drizzleclient_vio_was_interrupted(net->vio) ?
630
CR_NET_READ_INTERRUPTED :
635
remain -= (uint32_t) length;
639
{ /* First parts is packet length */
642
if (net->buff[net->where_b + 3] != (unsigned char) net->pkt_nr)
645
/* Not a NET error on the client. XXX: why? */
648
net->compress_pkt_nr= ++net->pkt_nr;
652
If the packet is compressed then complen > 0 and contains the
653
number of bytes in the uncompressed packet
655
*complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
658
len=uint3korr(net->buff+net->where_b);
659
if (!len) /* End of big multi-packet */
661
helping = max(len,*complen) + net->where_b;
662
/* The necessary size of net->buff */
663
if (helping >= net->max_packet)
665
if (drizzleclient_net_realloc(net,helping))
667
len= packet_error; /* Return error and close connection */
671
pos=net->buff + net->where_b;
672
remain = (uint32_t) len;
677
net->reading_or_writing= 0;
684
Read a packet from the client/server and return it without the internal
687
If the packet is the first packet of a multi-packet packet
688
(which is indicated by the length of the packet = 0xffffff) then
689
all sub packets are read and concatenated.
691
If the packet was compressed, its uncompressed and the length of the
692
uncompressed packet is returned.
695
The function returns the length of the found packet or packet_error.
696
net->read_pos points to the read data.
700
drizzleclient_net_read(NET *net)
706
len = my_real_read(net,&complen);
707
if (len == MAX_PACKET_LENGTH)
709
/* First packet of a multi-packet. Concatenate the packets */
710
uint32_t save_pos = net->where_b;
711
size_t total_length= 0;
716
len = my_real_read(net,&complen);
717
} while (len == MAX_PACKET_LENGTH);
718
if (len != packet_error)
720
net->where_b = save_pos;
722
net->read_pos = net->buff + net->where_b;
723
if (len != packet_error)
724
net->read_pos[len]=0; /* Safeguard for drizzleclient_use_result */
729
/* We are using the compressed protocol */
732
uint32_t start_of_packet;
733
uint32_t first_packet_offset;
734
uint32_t read_length, multi_byte_packet=0;
736
if (net->remain_in_buf)
738
buf_length= net->buf_length; /* Data left in old packet */
739
first_packet_offset= start_of_packet= (net->buf_length -
741
/* Restore the character that was overwritten by the end 0 */
742
net->buff[start_of_packet]= net->save_char;
746
/* reuse buffer, as there is nothing in it that we need */
747
buf_length= start_of_packet= first_packet_offset= 0;
753
if (buf_length - start_of_packet >= NET_HEADER_SIZE)
755
read_length = uint3korr(net->buff+start_of_packet);
758
/* End of multi-byte packet */
759
start_of_packet += NET_HEADER_SIZE;
762
if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet)
764
if (multi_byte_packet)
766
/* Remove packet header for second packet */
767
memmove(net->buff + first_packet_offset + start_of_packet,
768
net->buff + first_packet_offset + start_of_packet +
770
buf_length - start_of_packet);
771
start_of_packet += read_length;
772
buf_length -= NET_HEADER_SIZE;
775
start_of_packet+= read_length + NET_HEADER_SIZE;
777
if (read_length != MAX_PACKET_LENGTH) /* last package */
779
multi_byte_packet= 0; /* No last zero len packet */
782
multi_byte_packet= NET_HEADER_SIZE;
783
/* Move data down to read next data packet after current one */
784
if (first_packet_offset)
786
memmove(net->buff,net->buff+first_packet_offset,
787
buf_length-first_packet_offset);
788
buf_length-=first_packet_offset;
789
start_of_packet -= first_packet_offset;
790
first_packet_offset=0;
795
/* Move data down to read next data packet after current one */
796
if (first_packet_offset)
798
memmove(net->buff,net->buff+first_packet_offset,
799
buf_length-first_packet_offset);
800
buf_length-=first_packet_offset;
801
start_of_packet -= first_packet_offset;
802
first_packet_offset=0;
805
net->where_b=buf_length;
806
if ((packet_len = my_real_read(net,&complen)) == packet_error)
811
unsigned char * compbuf= (unsigned char *) malloc(complen);
814
uLongf tmp_complen= complen;
815
int error= uncompress((Bytef*) compbuf, &tmp_complen,
816
(Bytef*) (net->buff + net->where_b),
818
complen= tmp_complen;
822
net->error= 2; /* caller will close socket */
823
net->last_errno= CR_NET_UNCOMPRESS_ERROR;
827
memcpy((net->buff + net->where_b), compbuf, complen);
836
buf_length+= complen;
838
net->read_pos= net->buff+ first_packet_offset + NET_HEADER_SIZE;
839
net->buf_length= buf_length;
840
net->remain_in_buf= (uint32_t) (buf_length - start_of_packet);
841
len = ((uint32_t) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE -
843
net->save_char= net->read_pos[len]; /* Must be saved */
844
net->read_pos[len]=0; /* Safeguard for drizzleclient_use_result */
850
void drizzleclient_net_set_read_timeout(NET *net, uint32_t timeout)
852
net->read_timeout= timeout;
855
drizzleclient_vio_timeout(net->vio, 0, timeout);
861
void drizzleclient_net_set_write_timeout(NET *net, uint32_t timeout)
863
net->write_timeout= timeout;
866
drizzleclient_vio_timeout(net->vio, 1, timeout);
871
Clear possible error state of struct NET
873
@param net clear the state of the argument
876
void drizzleclient_drizzleclient_net_clear_error(NET *net)
879
net->last_error[0]= '\0';
880
strcpy(net->sqlstate, drizzleclient_sqlstate_get_not_error());