~drizzle-trunk/drizzle/development

971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 *
4
 *  Copyright (C) 2008 Sun Microsystems, Inc.
5
 *
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.
10
 *
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.
15
 *
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
19
 */
20
1241.9.1 by Monty Taylor
Removed global.h. Fixed all the headers.
21
#include "config.h"
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
22
#include <drizzled/session.h>
1302.4.4 by Eric Day
Updates for handshake testing.
23
#include <drizzled/error.h>
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
24
25
#include <assert.h>
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <string.h>
29
#include <signal.h>
30
#include <errno.h>
31
#include <sys/socket.h>
32
#include <sys/poll.h>
33
#include <zlib.h>
34
#include <algorithm>
35
36
#include "errmsg.h"
37
#include "vio.h"
38
#include "net_serv.h"
39
1964.2.9 by Monty Taylor
All protocol stuff except for the buffer_length. WTF?
40
namespace drizzle_plugin
41
{
42
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
43
using namespace std;
1302.4.4 by Eric Day
Updates for handshake testing.
44
using namespace drizzled;
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
45
46
/*
47
  The following handles the differences when this is linked between the
48
  client and the server.
49
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.
53
*/
54
1241.9.22 by Monty Taylor
Removed some bits from drizzled/common.h.
55
  /* Constants when using compression */
56
#define NET_HEADER_SIZE 4		/* standard header size */
57
#define COMP_HEADER_SIZE 3		/* compression header extra size */
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
58
59
#define MAX_PACKET_LENGTH (256L*256L*256L-1)
60
const char  *not_error_sqlstate= "00000";
61
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);
64
65
/** Init with packet info. */
66
67
bool drizzleclient_net_init(NET *net, Vio* vio, uint32_t buffer_length)
68
{
69
  net->vio = vio;
70
  net->max_packet= (uint32_t) buffer_length;
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
71
  net->max_packet_size= max(buffer_length, drizzled::global_system_variables.max_allowed_packet);
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
72
73
  if (!(net->buff=(unsigned char*) malloc((size_t) net->max_packet+
74
                                          NET_HEADER_SIZE + COMP_HEADER_SIZE)))
75
    return(1);
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;
80
  net->last_error[0]=0;
81
  net->compress=0; net->reading_or_writing=0;
82
  net->where_b = net->remain_in_buf=0;
83
  net->last_errno=0;
84
  net->unused= 0;
85
86
  if (vio != 0)                    /* If real connection */
87
  {
1878.6.1 by Thomi Richards
Converted the vio_st struct to the Vio class.
88
    net->fd  = vio->get_fd();            /* For perl DBI/DBD */
89
    vio->fastsend();
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
90
  }
91
  return(0);
92
}
93
1337.4.1 by Eric Day
Removed unused functions and extra complexity in MySQL module. Not rewriting any code here (yet?), just reshuffling to make it easier to manage.
94
bool drizzleclient_net_init_sock(NET * net, int sock, uint32_t buffer_length)
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
95
{
1878.6.1 by Thomi Richards
Converted the vio_st struct to the Vio class.
96
  Vio *vio_tmp= new Vio(sock);
1337.4.1 by Eric Day
Removed unused functions and extra complexity in MySQL module. Not rewriting any code here (yet?), just reshuffling to make it easier to manage.
97
  if (vio_tmp == NULL)
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
98
    return true;
99
  else
1337.4.1 by Eric Day
Removed unused functions and extra complexity in MySQL module. Not rewriting any code here (yet?), just reshuffling to make it easier to manage.
100
    if (drizzleclient_net_init(net, vio_tmp, buffer_length))
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
101
    {
102
      /* Only delete the temporary vio if we didn't already attach it to the
103
       * NET object.
104
       */
1337.4.1 by Eric Day
Removed unused functions and extra complexity in MySQL module. Not rewriting any code here (yet?), just reshuffling to make it easier to manage.
105
      if (vio_tmp && (net->vio != vio_tmp))
1878.6.1 by Thomi Richards
Converted the vio_st struct to the Vio class.
106
        delete vio_tmp;
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
107
      else
108
      {
109
        (void) shutdown(sock, SHUT_RDWR);
110
        (void) close(sock);
111
      }
112
      return true;
113
    }
114
  return false;
115
}
116
117
void drizzleclient_net_end(NET *net)
118
{
119
  if (net->buff != NULL)
120
    free(net->buff);
121
  net->buff= NULL;
122
  return;
123
}
124
125
void drizzleclient_net_close(NET *net)
126
{
127
  if (net->vio != NULL)
128
  {
1878.6.1 by Thomi Richards
Converted the vio_st struct to the Vio class.
129
    delete net->vio;
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
130
    net->vio= 0;
131
  }
132
}
133
134
bool drizzleclient_net_peer_addr(NET *net, char *buf, uint16_t *port, size_t buflen)
135
{
1878.6.1 by Thomi Richards
Converted the vio_st struct to the Vio class.
136
  return net->vio->peer_addr(buf, port, buflen);
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
137
}
138
139
void drizzleclient_net_keepalive(NET *net, bool flag)
140
{
1878.6.1 by Thomi Richards
Converted the vio_st struct to the Vio class.
141
  net->vio->keepalive(flag);
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
142
}
143
144
int drizzleclient_net_get_sd(NET *net)
145
{
1878.6.1 by Thomi Richards
Converted the vio_st struct to the Vio class.
146
  return net->vio->get_fd();
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
147
}
148
149
bool drizzleclient_net_more_data(NET *net)
150
{
1878.6.1 by Thomi Richards
Converted the vio_st struct to the Vio class.
151
  return (net->vio == 0 || net->vio->get_read_pos() < net->vio->get_read_end());
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
152
}
153
154
/** Realloc the packet buffer. */
155
156
static bool drizzleclient_net_realloc(NET *net, size_t length)
157
{
158
  unsigned char *buff;
159
  size_t pkt_length;
160
161
  if (length >= net->max_packet_size)
162
  {
163
    /* @todo: 1 and 2 codes are identical. */
1877.1.2 by Andrew Hutchings
Clear buffer so that max_allowed_packet error can be sent back to client
164
    net->error= 3;
1302.4.4 by Eric Day
Updates for handshake testing.
165
    net->last_errno= ER_NET_PACKET_TOO_LARGE;
166
    my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
167
    return(1);
168
  }
169
  pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
170
  /*
171
    We must allocate some extra bytes for the end 0 and to be able to
172
    read big compressed blocks
173
  */
174
  if (!(buff= (unsigned char*) realloc((char*) net->buff, pkt_length +
175
                               NET_HEADER_SIZE + COMP_HEADER_SIZE)))
176
  {
177
    /* @todo: 1 and 2 codes are identical. */
178
    net->error= 1;
179
    net->last_errno= CR_OUT_OF_MEMORY;
180
    /* In the server the error is reported by MY_WME flag. */
181
    return(1);
182
  }
183
  net->buff=net->write_pos=buff;
184
  net->buff_end=buff+(net->max_packet= (uint32_t) pkt_length);
185
  return(0);
186
}
187
188
189
/**
190
   Check if there is any data to be read from the socket.
191
192
   @param sd   socket descriptor
193
194
   @retval
195
   0  No data to read
196
   @retval
197
   1  Data or EOF to read
198
   @retval
199
   -1   Don't know if data is ready or not
200
*/
201
202
static bool net_data_is_ready(int sd)
203
{
204
  struct pollfd ufds;
205
  int res;
206
207
  ufds.fd= sd;
208
  ufds.events= POLLIN | POLLPRI;
209
  if (!(res= poll(&ufds, 1, 0)))
210
    return 0;
211
  if (res < 0 || !(ufds.revents & (POLLIN | POLLPRI)))
212
    return 0;
213
  return 1;
214
}
215
216
/**
217
   Remove unwanted characters from connection
218
   and check if disconnected.
219
220
   Read from socket until there is nothing more to read. Discard
221
   what is read.
222
223
   If there is anything when to read 'drizzleclient_net_clear' is called this
224
   normally indicates an error in the protocol.
225
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.
229
230
   @param net            NET handler
231
   @param clear_buffer           if <> 0, then clear all data from comm buff
232
*/
233
234
void drizzleclient_net_clear(NET *net, bool clear_buffer)
235
{
236
  if (clear_buffer)
237
  {
1878.6.1 by Thomi Richards
Converted the vio_st struct to the Vio class.
238
    while (net_data_is_ready(net->vio->get_fd()) > 0)
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
239
    {
240
      /* The socket is ready */
1878.6.1 by Thomi Richards
Converted the vio_st struct to the Vio class.
241
      if (net->vio->read(net->buff, (size_t) net->max_packet) <= 0)
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
242
      {
243
        net->error= 2;
244
        break;
245
      }
246
    }
247
  }
248
  net->pkt_nr=net->compress_pkt_nr=0;        /* Ready for new command */
249
  net->write_pos=net->buff;
250
  return;
251
}
252
253
254
/** Flush write_buffer if not empty. */
255
256
bool drizzleclient_net_flush(NET *net)
257
{
258
  bool error= 0;
259
  if (net->buff != net->write_pos)
260
  {
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;
264
  }
265
  /* Sync packet number if using compression */
266
  if (net->compress)
267
    net->pkt_nr=net->compress_pkt_nr;
268
  return(error);
269
}
270
271
272
/*****************************************************************************
273
 ** Write something to server/client buffer
274
 *****************************************************************************/
275
276
/**
277
   Write a logical packet with packet header.
278
279
   Format: Packet length (3 bytes), packet number(1 byte)
280
   When compression is used a 3 byte compression length is added
281
282
   @note
283
   If compression is used the original package is modified!
284
*/
285
286
bool
287
drizzleclient_net_write(NET *net,const unsigned char *packet,size_t len)
288
{
289
  unsigned char buff[NET_HEADER_SIZE];
290
  if (unlikely(!net->vio)) /* nowhere to write */
291
    return 0;
292
  /*
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)
296
  */
297
  while (len >= MAX_PACKET_LENGTH)
298
  {
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))
304
      return 1;
305
    packet += z_size;
306
    len-=     z_size;
307
  }
308
  /* Write last packet */
309
  int3store(buff,len);
310
  buff[3]= (unsigned char) net->pkt_nr++;
311
  if (net_write_buff(net, buff, NET_HEADER_SIZE))
312
    return 1;
313
  return net_write_buff(net,packet,len) ? 1 : 0;
314
}
315
316
/**
317
   Send a command to the server.
318
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.
322
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
325
   packet.
326
327
   This function will split big packets into sub-packets if needed.
328
   (Each sub packet can only be 2^24 bytes)
329
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
336
337
   @retval
338
   0    ok
339
   @retval
340
   1    error
341
*/
342
343
bool
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)
347
{
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;
351
352
  buff[4]=command;                /* For first packet */
353
354
  if (length >= MAX_PACKET_LENGTH)
355
  {
356
    /* Take into account that we have the command in the first header */
357
    len= MAX_PACKET_LENGTH - 1 - head_len;
358
    do
359
    {
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))
365
        return(1);
366
      packet+= len;
367
      length-= MAX_PACKET_LENGTH;
368
      len= MAX_PACKET_LENGTH;
369
      head_len= 0;
370
      header_size= NET_HEADER_SIZE;
371
    } while (length >= MAX_PACKET_LENGTH);
372
    len=length;                    /* Data left to be written */
373
  }
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 );
379
}
380
381
/**
382
   Caching the data in a local buffer before sending it.
383
384
   Fill up net->buffer and send it to the client when full.
385
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
389
   sending data.
390
391
   @param net        Network handler
392
   @param packet    Packet to send
393
   @param len        Length of packet
394
395
   @note
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.
400
401
   @retval
402
   0    ok
403
   @retval
404
   1
405
*/
406
407
static bool
408
net_write_buff(NET *net, const unsigned char *packet, uint32_t len)
409
{
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);
413
  else
414
    left_length= (uint32_t) (net->buff_end - net->write_pos);
415
416
  if (len > left_length)
417
  {
418
    if (net->write_pos != net->buff)
419
    {
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))
424
        return 1;
425
      net->write_pos= net->buff;
426
      packet+= left_length;
427
      len-= left_length;
428
    }
429
    if (net->compress)
430
    {
431
      /*
432
        We can't have bigger packets than 16M with compression
433
        Because the uncompressed length is stored in 3 bytes
434
      */
435
      left_length= MAX_PACKET_LENGTH;
436
      while (len > left_length)
437
      {
438
        if (drizzleclient_net_real_write(net, packet, left_length))
439
          return 1;
440
        packet+= left_length;
441
        len-= left_length;
442
      }
443
    }
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 */
447
  }
448
  memcpy(net->write_pos,packet,len);
449
  net->write_pos+= len;
450
  return 0;
451
}
452
453
454
/**
455
   Read and write one packet using timeouts.
456
   If needed, the packet is compressed before sending.
457
458
   @todo
459
   - TODO is it needed to set this variable if we have no socket
460
*/
461
462
/*
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.
465
*/
466
static int
467
drizzleclient_net_real_write(NET *net, const unsigned char *packet, size_t len)
468
{
469
  size_t length;
470
  const unsigned char *pos, *end;
471
  uint32_t retry_count= 0;
472
473
  /* Backup of the original SO_RCVTIMEO timeout */
474
475
  if (net->error == 2)
476
    return(-1);                /* socket can't be used */
477
478
  net->reading_or_writing=2;
479
  if (net->compress)
480
  {
481
    size_t complen;
482
    unsigned char *b;
483
    const uint32_t header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
484
    if (!(b= (unsigned char*) malloc(len + NET_HEADER_SIZE +
485
                             COMP_HEADER_SIZE)))
486
    {
487
      net->error= 2;
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;
491
      return(1);
492
    }
493
    memcpy(b+header_length,packet,len);
494
495
    complen= len * 120 / 100 + 12;
496
    unsigned char * compbuf= (unsigned char *) malloc(complen);
497
    if (compbuf != NULL)
498
    {
499
      uLongf tmp_complen= complen;
500
      int res= compress((Bytef*) compbuf, &tmp_complen,
501
                        (Bytef*) (b+header_length),
502
                        len);
503
      complen= tmp_complen;
504
505
      free(compbuf);
506
507
      if ((res != Z_OK) || (complen >= len))
508
        complen= 0;
509
      else
510
      {
511
        size_t tmplen= complen;
512
        complen= len;
513
        len= tmplen;
514
      }
515
    }
516
    else
517
    {
518
      complen=0;
519
    }
520
    int3store(&b[NET_HEADER_SIZE],complen);
521
    int3store(b,len);
522
    b[3]=(unsigned char) (net->compress_pkt_nr++);
523
    len+= header_length;
524
    packet= b;
525
  }
526
527
  pos= packet;
528
  end=pos+len;
529
  /* Loop until we have read everything */
530
  while (pos != end)
531
  {
532
    assert(pos);
1878.6.1 by Thomi Richards
Converted the vio_st struct to the Vio class.
533
    // TODO - see bug comment below - will we crash now?
534
    if ((long) (length= net->vio->write( pos, (size_t) (end-pos))) <= 0)
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
535
    {
536
     /*
537
      * We could end up here with net->vio == NULL
538
      * See LP bug#436685
539
      * If that is the case, we exit the while loop
540
      */
541
      if (net->vio == NULL)
542
        break;
543
      
1878.6.1 by Thomi Richards
Converted the vio_st struct to the Vio class.
544
      const bool interrupted= net->vio->should_retry();
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
545
      /*
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.
549
      */
550
      if ((interrupted || length == 0))
551
      {
552
        bool old_mode;
553
1878.6.1 by Thomi Richards
Converted the vio_st struct to the Vio class.
554
        while (net->vio->blocking(true, &old_mode) < 0)
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
555
        {
1878.6.1 by Thomi Richards
Converted the vio_st struct to the Vio class.
556
          if (net->vio->should_retry() && retry_count++ < net->retry_count)
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
557
            continue;
558
          net->error= 2;                     /* Close socket */
1302.4.4 by Eric Day
Updates for handshake testing.
559
          net->last_errno= ER_NET_PACKET_TOO_LARGE;
560
          my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
561
          goto end;
562
        }
563
        retry_count=0;
564
        continue;
565
      }
566
      else
567
      {
568
        if (retry_count++ < net->retry_count)
569
          continue;
570
      }
571
1878.6.1 by Thomi Richards
Converted the vio_st struct to the Vio class.
572
      if (net->vio->get_errno() == EINTR)
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
573
      {
574
        continue;
575
      }
576
      net->error= 2;                /* Close socket */
577
      net->last_errno= (interrupted ? CR_NET_WRITE_INTERRUPTED :
578
                        CR_NET_ERROR_ON_WRITE);
579
      break;
580
    }
581
    pos+=length;
2039.2.1 by Andrew Hutchings
When spawning many sessions it is possible to hit "ulimit -u" (I didn't even realise this affected thread counts).
582
583
    /* If this is an error we may not have a current_session any more */
584
    if (current_session)
585
      current_session->status_var.bytes_sent+= length;
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
586
  }
587
end:
588
  if ((net->compress) && (packet != NULL))
589
    free((char*) packet);
590
  net->reading_or_writing=0;
591
592
  return(((int) (pos != end)));
593
}
594
595
596
/**
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.
600
601
   @return
602
   Returns length of packet.
603
*/
604
605
static uint32_t
606
my_real_read(NET *net, size_t *complen)
607
{
608
  unsigned char *pos;
1877.1.2 by Andrew Hutchings
Clear buffer so that max_allowed_packet error can be sent back to client
609
  size_t length= 0;
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
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 :
613
                    NET_HEADER_SIZE);
614
615
  *complen = 0;
616
617
  net->reading_or_writing= 1;
618
  /* Read timeout is set in drizzleclient_net_set_read_timeout */
619
620
  pos = net->buff + net->where_b;        /* net->packet -4 */
621
622
  for (i= 0; i < 2 ; i++)
623
  {
624
    while (remain > 0)
625
    {
626
      /* First read is done with non blocking mode */
1878.6.1 by Thomi Richards
Converted the vio_st struct to the Vio class.
627
      if ((long) (length= net->vio->read(pos, remain)) <= 0L)
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
628
      {
629
        if (net->vio == NULL)
630
          goto end;
631
1878.6.1 by Thomi Richards
Converted the vio_st struct to the Vio class.
632
        const bool interrupted = net->vio->should_retry();
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
633
634
        if (interrupted)
635
        {                    /* Probably in MIT threads */
636
          if (retry_count++ < net->retry_count)
637
            continue;
638
        }
1878.6.1 by Thomi Richards
Converted the vio_st struct to the Vio class.
639
        if (net->vio->get_errno() == EINTR)
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
640
        {
641
          continue;
642
        }
643
        len= packet_error;
644
        net->error= 2;                /* Close socket */
1878.6.1 by Thomi Richards
Converted the vio_st struct to the Vio class.
645
        net->last_errno= (net->vio->was_interrupted() ?
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
646
                          CR_NET_READ_INTERRUPTED :
647
                          CR_NET_READ_ERROR);
648
        goto end;
649
      }
650
      remain -= (uint32_t) length;
651
      pos+= length;
1537.1.1 by Joe Daly
add bytes_sent and bytes_received counters
652
      current_session->status_var.bytes_received+= length;
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
653
    }
654
    if (i == 0)
655
    {                    /* First parts is packet length */
656
      uint32_t helping;
657
658
      if (net->buff[net->where_b + 3] != (unsigned char) net->pkt_nr)
659
      {
660
        len= packet_error;
661
        /* Not a NET error on the client. XXX: why? */
1302.4.4 by Eric Day
Updates for handshake testing.
662
        my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0));
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
663
        goto end;
664
      }
665
      net->compress_pkt_nr= ++net->pkt_nr;
666
      if (net->compress)
667
      {
668
        /*
669
          If the packet is compressed then complen > 0 and contains the
670
          number of bytes in the uncompressed packet
671
        */
672
        *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
673
      }
674
675
      len=uint3korr(net->buff+net->where_b);
676
      if (!len)                /* End of big multi-packet */
677
        goto end;
678
      helping = max(len,*complen) + net->where_b;
679
      /* The necessary size of net->buff */
680
      if (helping >= net->max_packet)
681
      {
682
        if (drizzleclient_net_realloc(net,helping))
683
        {
1877.1.2 by Andrew Hutchings
Clear buffer so that max_allowed_packet error can be sent back to client
684
          /* Clear the buffer so libdrizzle doesn't keep retrying */
685
          while (len > 0)
686
          {
1878.6.2 by Thomi Richards
fixed merge conflict.
687
            length= read(net->vio->get_fd(), net->buff, min((size_t)net->max_packet, len));
1877.1.2 by Andrew Hutchings
Clear buffer so that max_allowed_packet error can be sent back to client
688
            assert((long)length > 0L);
689
            len-= length;
690
          }
691
            
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
692
          len= packet_error;          /* Return error and close connection */
693
          goto end;
694
        }
695
      }
696
      pos=net->buff + net->where_b;
697
      remain = (uint32_t) len;
698
    }
699
  }
700
701
end:
702
  net->reading_or_writing= 0;
703
704
  return(len);
705
}
706
707
708
/**
709
   Read a packet from the client/server and return it without the internal
710
   package header.
711
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.
715
716
   If the packet was compressed, its uncompressed and the length of the
717
   uncompressed packet is returned.
718
719
   @return
720
   The function returns the length of the found packet or packet_error.
721
   net->read_pos points to the read data.
722
*/
723
724
uint32_t
725
drizzleclient_net_read(NET *net)
726
{
727
  size_t len, complen;
728
729
  if (!net->compress)
730
  {
731
    len = my_real_read(net,&complen);
732
    if (len == MAX_PACKET_LENGTH)
733
    {
734
      /* First packet of a multi-packet.  Concatenate the packets */
735
      uint32_t save_pos = net->where_b;
736
      size_t total_length= 0;
737
      do
738
      {
739
        net->where_b += len;
740
        total_length += len;
741
        len = my_real_read(net,&complen);
742
      } while (len == MAX_PACKET_LENGTH);
743
      if (len != packet_error)
744
        len+= total_length;
745
      net->where_b = save_pos;
746
    }
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 */
750
    return len;
751
  }
752
  else
753
  {
754
    /* We are using the compressed protocol */
755
756
    uint32_t buf_length;
757
    uint32_t start_of_packet;
758
    uint32_t first_packet_offset;
759
    uint32_t read_length, multi_byte_packet=0;
760
761
    if (net->remain_in_buf)
762
    {
763
      buf_length= net->buf_length;        /* Data left in old packet */
764
      first_packet_offset= start_of_packet= (net->buf_length -
765
                                             net->remain_in_buf);
766
      /* Restore the character that was overwritten by the end 0 */
767
      net->buff[start_of_packet]= net->save_char;
768
    }
769
    else
770
    {
771
      /* reuse buffer, as there is nothing in it that we need */
772
      buf_length= start_of_packet= first_packet_offset= 0;
773
    }
774
    for (;;)
775
    {
776
      uint32_t packet_len;
777
778
      if (buf_length - start_of_packet >= NET_HEADER_SIZE)
779
      {
780
        read_length = uint3korr(net->buff+start_of_packet);
781
        if (!read_length)
782
        {
783
          /* End of multi-byte packet */
784
          start_of_packet += NET_HEADER_SIZE;
785
          break;
786
        }
787
        if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet)
788
        {
789
          if (multi_byte_packet)
790
          {
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 +
794
                    NET_HEADER_SIZE,
795
                    buf_length - start_of_packet);
796
            start_of_packet += read_length;
797
            buf_length -= NET_HEADER_SIZE;
798
          }
799
          else
800
            start_of_packet+= read_length + NET_HEADER_SIZE;
801
802
          if (read_length != MAX_PACKET_LENGTH)    /* last package */
803
          {
804
            multi_byte_packet= 0;        /* No last zero len packet */
805
            break;
806
          }
807
          multi_byte_packet= NET_HEADER_SIZE;
808
          /* Move data down to read next data packet after current one */
809
          if (first_packet_offset)
810
          {
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;
816
          }
817
          continue;
818
        }
819
      }
820
      /* Move data down to read next data packet after current one */
821
      if (first_packet_offset)
822
      {
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;
828
      }
829
830
      net->where_b=buf_length;
831
      if ((packet_len = my_real_read(net,&complen)) == packet_error)
832
        return packet_error;
833
834
      if (complen)
835
      {
836
        unsigned char * compbuf= (unsigned char *) malloc(complen);
837
        if (compbuf != NULL)
838
        {
839
          uLongf tmp_complen= complen;
840
          int error= uncompress((Bytef*) compbuf, &tmp_complen,
841
                                (Bytef*) (net->buff + net->where_b),
842
                                (uLong)packet_len);
843
          complen= tmp_complen;
844
845
          if (error != Z_OK)
846
          {
847
            net->error= 2;            /* caller will close socket */
848
            net->last_errno= CR_NET_UNCOMPRESS_ERROR;
849
          }
850
          else
851
          {
852
            memcpy((net->buff + net->where_b), compbuf, complen);
853
          }
854
          free(compbuf);
855
        }
856
      }
857
      else
858
        complen= packet_len;
859
860
    }
861
    buf_length+= complen;
862
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 -
867
           multi_byte_packet);
868
    net->save_char= net->read_pos[len];    /* Must be saved */
869
    net->read_pos[len]=0;        /* Safeguard for drizzleclient_use_result */
870
  }
871
  return len;
872
  }
873
874
875
void drizzleclient_net_set_read_timeout(NET *net, uint32_t timeout)
876
{
877
  net->read_timeout= timeout;
878
#ifndef __sun
879
  if (net->vio)
1878.6.1 by Thomi Richards
Converted the vio_st struct to the Vio class.
880
    net->vio->timeout(0, timeout);
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
881
#endif
882
  return;
883
}
884
885
886
void drizzleclient_net_set_write_timeout(NET *net, uint32_t timeout)
887
{
888
  net->write_timeout= timeout;
889
#ifndef __sun
890
  if (net->vio)
1878.6.1 by Thomi Richards
Converted the vio_st struct to the Vio class.
891
    net->vio->timeout(1, timeout);
971.7.10 by Eric Day
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.
892
#endif
893
  return;
894
}
895
/**
896
  Clear possible error state of struct NET
897
898
  @param net  clear the state of the argument
899
*/
900
901
void drizzleclient_drizzleclient_net_clear_error(NET *net)
902
{
903
  net->last_errno= 0;
904
  net->last_error[0]= '\0';
905
  strcpy(net->sqlstate, not_error_sqlstate);
906
}
1964.2.9 by Monty Taylor
All protocol stuff except for the buffer_length. WTF?
907
908
} /* namespace drizzle_plugin */