~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
40
using namespace std;
1302.4.4 by Eric Day
Updates for handshake testing.
41
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.
42
43
/*
44
  The following handles the differences when this is linked between the
45
  client and the server.
46
47
  This gives an error if a too big packet is found
48
  The server can change this with the -O switch, but because the client
49
  can't normally do this the client should have a bigger max_allowed_packet.
50
*/
51
1241.9.22 by Monty Taylor
Removed some bits from drizzled/common.h.
52
  /* Constants when using compression */
53
#define NET_HEADER_SIZE 4		/* standard header size */
54
#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.
55
56
#define MAX_PACKET_LENGTH (256L*256L*256L-1)
57
const char  *not_error_sqlstate= "00000";
58
59
static bool net_write_buff(NET *net, const unsigned char *packet, uint32_t len);
60
static int drizzleclient_net_real_write(NET *net, const unsigned char *packet, size_t len);
61
62
/** Init with packet info. */
63
64
bool drizzleclient_net_init(NET *net, Vio* vio, uint32_t buffer_length)
65
{
66
  net->vio = vio;
67
  net->max_packet= (uint32_t) buffer_length;
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
68
  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.
69
70
  if (!(net->buff=(unsigned char*) malloc((size_t) net->max_packet+
71
                                          NET_HEADER_SIZE + COMP_HEADER_SIZE)))
72
    return(1);
73
  net->buff_end=net->buff+net->max_packet;
74
  net->error=0; net->return_status=0;
75
  net->pkt_nr=net->compress_pkt_nr=0;
76
  net->write_pos=net->read_pos = net->buff;
77
  net->last_error[0]=0;
78
  net->compress=0; net->reading_or_writing=0;
79
  net->where_b = net->remain_in_buf=0;
80
  net->last_errno=0;
81
  net->unused= 0;
82
83
  if (vio != 0)                    /* If real connection */
84
  {
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.
85
    net->fd  = vio_fd(vio);            /* For perl DBI/DBD */
86
    vio_fastsend(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.
87
  }
88
  return(0);
89
}
90
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.
91
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.
92
{
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.
93
  Vio *vio_tmp= mysql_protocol_vio_new(sock);
94
  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.
95
    return true;
96
  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.
97
    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.
98
    {
99
      /* Only delete the temporary vio if we didn't already attach it to the
100
       * NET object.
101
       */
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.
102
      if (vio_tmp && (net->vio != vio_tmp))
103
        vio_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.
104
      else
105
      {
106
        (void) shutdown(sock, SHUT_RDWR);
107
        (void) close(sock);
108
      }
109
      return true;
110
    }
111
  return false;
112
}
113
114
void drizzleclient_net_end(NET *net)
115
{
116
  if (net->buff != NULL)
117
    free(net->buff);
118
  net->buff= NULL;
119
  return;
120
}
121
122
void drizzleclient_net_close(NET *net)
123
{
124
  if (net->vio != NULL)
125
  {
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.
126
    vio_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.
127
    net->vio= 0;
128
  }
129
}
130
131
bool drizzleclient_net_peer_addr(NET *net, char *buf, uint16_t *port, size_t buflen)
132
{
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.
133
  return vio_peer_addr(net->vio, 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.
134
}
135
136
void drizzleclient_net_keepalive(NET *net, bool flag)
137
{
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.
138
  vio_keepalive(net->vio, 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.
139
}
140
141
int drizzleclient_net_get_sd(NET *net)
142
{
143
  return net->vio->sd;
144
}
145
146
bool drizzleclient_net_more_data(NET *net)
147
{
148
  return (net->vio == 0 || net->vio->read_pos < net->vio->read_end);
149
}
150
151
/** Realloc the packet buffer. */
152
153
static bool drizzleclient_net_realloc(NET *net, size_t length)
154
{
155
  unsigned char *buff;
156
  size_t pkt_length;
157
158
  if (length >= net->max_packet_size)
159
  {
160
    /* @todo: 1 and 2 codes are identical. */
161
    net->error= 1;
1302.4.4 by Eric Day
Updates for handshake testing.
162
    net->last_errno= ER_NET_PACKET_TOO_LARGE;
163
    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.
164
    return(1);
165
  }
166
  pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
167
  /*
168
    We must allocate some extra bytes for the end 0 and to be able to
169
    read big compressed blocks
170
  */
171
  if (!(buff= (unsigned char*) realloc((char*) net->buff, pkt_length +
172
                               NET_HEADER_SIZE + COMP_HEADER_SIZE)))
173
  {
174
    /* @todo: 1 and 2 codes are identical. */
175
    net->error= 1;
176
    net->last_errno= CR_OUT_OF_MEMORY;
177
    /* In the server the error is reported by MY_WME flag. */
178
    return(1);
179
  }
180
  net->buff=net->write_pos=buff;
181
  net->buff_end=buff+(net->max_packet= (uint32_t) pkt_length);
182
  return(0);
183
}
184
185
186
/**
187
   Check if there is any data to be read from the socket.
188
189
   @param sd   socket descriptor
190
191
   @retval
192
   0  No data to read
193
   @retval
194
   1  Data or EOF to read
195
   @retval
196
   -1   Don't know if data is ready or not
197
*/
198
199
static bool net_data_is_ready(int sd)
200
{
201
  struct pollfd ufds;
202
  int res;
203
204
  ufds.fd= sd;
205
  ufds.events= POLLIN | POLLPRI;
206
  if (!(res= poll(&ufds, 1, 0)))
207
    return 0;
208
  if (res < 0 || !(ufds.revents & (POLLIN | POLLPRI)))
209
    return 0;
210
  return 1;
211
}
212
213
/**
214
   Remove unwanted characters from connection
215
   and check if disconnected.
216
217
   Read from socket until there is nothing more to read. Discard
218
   what is read.
219
220
   If there is anything when to read 'drizzleclient_net_clear' is called this
221
   normally indicates an error in the protocol.
222
223
   When connection is properly closed (for TCP it means with
224
   a FIN packet), then select() considers a socket "ready to read",
225
   in the sense that there's EOF to read, but read() returns 0.
226
227
   @param net            NET handler
228
   @param clear_buffer           if <> 0, then clear all data from comm buff
229
*/
230
231
void drizzleclient_net_clear(NET *net, bool clear_buffer)
232
{
233
  if (clear_buffer)
234
  {
235
    while (net_data_is_ready(net->vio->sd) > 0)
236
    {
237
      /* The socket is ready */
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.
238
      if (vio_read(net->vio, 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.
239
      {
240
        net->error= 2;
241
        break;
242
      }
243
    }
244
  }
245
  net->pkt_nr=net->compress_pkt_nr=0;        /* Ready for new command */
246
  net->write_pos=net->buff;
247
  return;
248
}
249
250
251
/** Flush write_buffer if not empty. */
252
253
bool drizzleclient_net_flush(NET *net)
254
{
255
  bool error= 0;
256
  if (net->buff != net->write_pos)
257
  {
258
    error=drizzleclient_net_real_write(net, net->buff,
259
                         (size_t) (net->write_pos - net->buff)) ? 1 : 0;
260
    net->write_pos=net->buff;
261
  }
262
  /* Sync packet number if using compression */
263
  if (net->compress)
264
    net->pkt_nr=net->compress_pkt_nr;
265
  return(error);
266
}
267
268
269
/*****************************************************************************
270
 ** Write something to server/client buffer
271
 *****************************************************************************/
272
273
/**
274
   Write a logical packet with packet header.
275
276
   Format: Packet length (3 bytes), packet number(1 byte)
277
   When compression is used a 3 byte compression length is added
278
279
   @note
280
   If compression is used the original package is modified!
281
*/
282
283
bool
284
drizzleclient_net_write(NET *net,const unsigned char *packet,size_t len)
285
{
286
  unsigned char buff[NET_HEADER_SIZE];
287
  if (unlikely(!net->vio)) /* nowhere to write */
288
    return 0;
289
  /*
290
    Big packets are handled by splitting them in packets of MAX_PACKET_LENGTH
291
    length. The last packet is always a packet that is < MAX_PACKET_LENGTH.
292
    (The last packet may even have a length of 0)
293
  */
294
  while (len >= MAX_PACKET_LENGTH)
295
  {
296
    const uint32_t z_size = MAX_PACKET_LENGTH;
297
    int3store(buff, z_size);
298
    buff[3]= (unsigned char) net->pkt_nr++;
299
    if (net_write_buff(net, buff, NET_HEADER_SIZE) ||
300
        net_write_buff(net, packet, z_size))
301
      return 1;
302
    packet += z_size;
303
    len-=     z_size;
304
  }
305
  /* Write last packet */
306
  int3store(buff,len);
307
  buff[3]= (unsigned char) net->pkt_nr++;
308
  if (net_write_buff(net, buff, NET_HEADER_SIZE))
309
    return 1;
310
  return net_write_buff(net,packet,len) ? 1 : 0;
311
}
312
313
/**
314
   Send a command to the server.
315
316
   The reason for having both header and packet is so that libdrizzle
317
   can easy add a header to a special command (like prepared statements)
318
   without having to re-alloc the string.
319
320
   As the command is part of the first data packet, we have to do some data
321
   juggling to put the command in there, without having to create a new
322
   packet.
323
324
   This function will split big packets into sub-packets if needed.
325
   (Each sub packet can only be 2^24 bytes)
326
327
   @param net        NET handler
328
   @param command    Command in MySQL server (enum enum_server_command)
329
   @param header    Header to write after command
330
   @param head_len    Length of header
331
   @param packet    Query or parameter to query
332
   @param len        Length of packet
333
334
   @retval
335
   0    ok
336
   @retval
337
   1    error
338
*/
339
340
bool
341
drizzleclient_net_write_command(NET *net,unsigned char command,
342
                  const unsigned char *header, size_t head_len,
343
                  const unsigned char *packet, size_t len)
344
{
345
  uint32_t length=len+1+head_len;            /* 1 extra byte for command */
346
  unsigned char buff[NET_HEADER_SIZE+1];
347
  uint32_t header_size=NET_HEADER_SIZE+1;
348
349
  buff[4]=command;                /* For first packet */
350
351
  if (length >= MAX_PACKET_LENGTH)
352
  {
353
    /* Take into account that we have the command in the first header */
354
    len= MAX_PACKET_LENGTH - 1 - head_len;
355
    do
356
    {
357
      int3store(buff, MAX_PACKET_LENGTH);
358
      buff[3]= (unsigned char) net->pkt_nr++;
359
      if (net_write_buff(net, buff, header_size) ||
360
          net_write_buff(net, header, head_len) ||
361
          net_write_buff(net, packet, len))
362
        return(1);
363
      packet+= len;
364
      length-= MAX_PACKET_LENGTH;
365
      len= MAX_PACKET_LENGTH;
366
      head_len= 0;
367
      header_size= NET_HEADER_SIZE;
368
    } while (length >= MAX_PACKET_LENGTH);
369
    len=length;                    /* Data left to be written */
370
  }
371
  int3store(buff,length);
372
  buff[3]= (unsigned char) net->pkt_nr++;
373
  return((net_write_buff(net, buff, header_size) ||
374
          (head_len && net_write_buff(net, header, head_len)) ||
375
          net_write_buff(net, packet, len) || drizzleclient_net_flush(net)) ? 1 : 0 );
376
}
377
378
/**
379
   Caching the data in a local buffer before sending it.
380
381
   Fill up net->buffer and send it to the client when full.
382
383
   If the rest of the to-be-sent-packet is bigger than buffer,
384
   send it in one big block (to avoid copying to internal buffer).
385
   If not, copy the rest of the data to the buffer and return without
386
   sending data.
387
388
   @param net        Network handler
389
   @param packet    Packet to send
390
   @param len        Length of packet
391
392
   @note
393
   The cached buffer can be sent as it is with 'drizzleclient_net_flush()'.
394
   In this code we have to be careful to not send a packet longer than
395
   MAX_PACKET_LENGTH to drizzleclient_net_real_write() if we are using the compressed
396
   protocol as we store the length of the compressed packet in 3 bytes.
397
398
   @retval
399
   0    ok
400
   @retval
401
   1
402
*/
403
404
static bool
405
net_write_buff(NET *net, const unsigned char *packet, uint32_t len)
406
{
407
  uint32_t left_length;
408
  if (net->compress && net->max_packet > MAX_PACKET_LENGTH)
409
    left_length= MAX_PACKET_LENGTH - (net->write_pos - net->buff);
410
  else
411
    left_length= (uint32_t) (net->buff_end - net->write_pos);
412
413
  if (len > left_length)
414
  {
415
    if (net->write_pos != net->buff)
416
    {
417
      /* Fill up already used packet and write it */
418
      memcpy(net->write_pos,packet,left_length);
419
      if (drizzleclient_net_real_write(net, net->buff,
420
                         (size_t) (net->write_pos - net->buff) + left_length))
421
        return 1;
422
      net->write_pos= net->buff;
423
      packet+= left_length;
424
      len-= left_length;
425
    }
426
    if (net->compress)
427
    {
428
      /*
429
        We can't have bigger packets than 16M with compression
430
        Because the uncompressed length is stored in 3 bytes
431
      */
432
      left_length= MAX_PACKET_LENGTH;
433
      while (len > left_length)
434
      {
435
        if (drizzleclient_net_real_write(net, packet, left_length))
436
          return 1;
437
        packet+= left_length;
438
        len-= left_length;
439
      }
440
    }
441
    if (len > net->max_packet)
442
      return drizzleclient_net_real_write(net, packet, len) ? 1 : 0;
443
    /* Send out rest of the blocks as full sized blocks */
444
  }
445
  memcpy(net->write_pos,packet,len);
446
  net->write_pos+= len;
447
  return 0;
448
}
449
450
451
/**
452
   Read and write one packet using timeouts.
453
   If needed, the packet is compressed before sending.
454
455
   @todo
456
   - TODO is it needed to set this variable if we have no socket
457
*/
458
459
/*
460
  TODO: rewrite this in a manner to do non-block writes. If a write can not be made, and we are
461
  in the server, yield to another process and come back later.
462
*/
463
static int
464
drizzleclient_net_real_write(NET *net, const unsigned char *packet, size_t len)
465
{
466
  size_t length;
467
  const unsigned char *pos, *end;
468
  uint32_t retry_count= 0;
469
470
  /* Backup of the original SO_RCVTIMEO timeout */
471
472
  if (net->error == 2)
473
    return(-1);                /* socket can't be used */
474
475
  net->reading_or_writing=2;
476
  if (net->compress)
477
  {
478
    size_t complen;
479
    unsigned char *b;
480
    const uint32_t header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
481
    if (!(b= (unsigned char*) malloc(len + NET_HEADER_SIZE +
482
                             COMP_HEADER_SIZE)))
483
    {
484
      net->error= 2;
485
      net->last_errno= CR_OUT_OF_MEMORY;
486
      /* In the server, the error is reported by MY_WME flag. */
487
      net->reading_or_writing= 0;
488
      return(1);
489
    }
490
    memcpy(b+header_length,packet,len);
491
492
    complen= len * 120 / 100 + 12;
493
    unsigned char * compbuf= (unsigned char *) malloc(complen);
494
    if (compbuf != NULL)
495
    {
496
      uLongf tmp_complen= complen;
497
      int res= compress((Bytef*) compbuf, &tmp_complen,
498
                        (Bytef*) (b+header_length),
499
                        len);
500
      complen= tmp_complen;
501
502
      free(compbuf);
503
504
      if ((res != Z_OK) || (complen >= len))
505
        complen= 0;
506
      else
507
      {
508
        size_t tmplen= complen;
509
        complen= len;
510
        len= tmplen;
511
      }
512
    }
513
    else
514
    {
515
      complen=0;
516
    }
517
    int3store(&b[NET_HEADER_SIZE],complen);
518
    int3store(b,len);
519
    b[3]=(unsigned char) (net->compress_pkt_nr++);
520
    len+= header_length;
521
    packet= b;
522
  }
523
524
  pos= packet;
525
  end=pos+len;
526
  /* Loop until we have read everything */
527
  while (pos != end)
528
  {
529
    assert(pos);
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.
530
    if ((long) (length= vio_write(net->vio, 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.
531
    {
532
     /*
533
      * We could end up here with net->vio == NULL
534
      * See LP bug#436685
535
      * If that is the case, we exit the while loop
536
      */
537
      if (net->vio == NULL)
538
        break;
539
      
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.
540
      const bool interrupted= vio_should_retry(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.
541
      /*
542
        If we read 0, or we were interrupted this means that
543
        we need to switch to blocking mode and wait until the timeout
544
        on the socket kicks in.
545
      */
546
      if ((interrupted || length == 0))
547
      {
548
        bool old_mode;
549
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.
550
        while (vio_blocking(net->vio, 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.
551
        {
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.
552
          if (vio_should_retry(net->vio) && 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.
553
            continue;
554
          net->error= 2;                     /* Close socket */
1302.4.4 by Eric Day
Updates for handshake testing.
555
          net->last_errno= ER_NET_PACKET_TOO_LARGE;
556
          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.
557
          goto end;
558
        }
559
        retry_count=0;
560
        continue;
561
      }
562
      else
563
      {
564
        if (retry_count++ < net->retry_count)
565
          continue;
566
      }
567
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.
568
      if (vio_errno(net->vio) == 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.
569
      {
570
        continue;
571
      }
572
      net->error= 2;                /* Close socket */
573
      net->last_errno= (interrupted ? CR_NET_WRITE_INTERRUPTED :
574
                        CR_NET_ERROR_ON_WRITE);
575
      break;
576
    }
577
    pos+=length;
1537.1.1 by Joe Daly
add bytes_sent and bytes_received counters
578
    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.
579
  }
580
end:
581
  if ((net->compress) && (packet != NULL))
582
    free((char*) packet);
583
  net->reading_or_writing=0;
584
585
  return(((int) (pos != end)));
586
}
587
588
589
/**
590
   Reads one packet to net->buff + net->where_b.
591
   Long packets are handled by drizzleclient_net_read().
592
   This function reallocates the net->buff buffer if necessary.
593
594
   @return
595
   Returns length of packet.
596
*/
597
598
static uint32_t
599
my_real_read(NET *net, size_t *complen)
600
{
601
  unsigned char *pos;
602
  size_t length;
603
  uint32_t i,retry_count=0;
604
  size_t len=packet_error;
605
  uint32_t remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
606
                    NET_HEADER_SIZE);
607
608
  *complen = 0;
609
610
  net->reading_or_writing= 1;
611
  /* Read timeout is set in drizzleclient_net_set_read_timeout */
612
613
  pos = net->buff + net->where_b;        /* net->packet -4 */
614
615
  for (i= 0; i < 2 ; i++)
616
  {
617
    while (remain > 0)
618
    {
619
      /* First read is done with non blocking mode */
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.
620
      if ((long) (length= vio_read(net->vio, 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.
621
      {
622
        if (net->vio == NULL)
623
          goto end;
624
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.
625
        const bool interrupted = vio_should_retry(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.
626
627
        if (interrupted)
628
        {                    /* Probably in MIT threads */
629
          if (retry_count++ < net->retry_count)
630
            continue;
631
        }
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.
632
        if (vio_errno(net->vio) == 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.
633
        {
634
          continue;
635
        }
636
        len= packet_error;
637
        net->error= 2;                /* Close socket */
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.
638
        net->last_errno= (vio_was_interrupted(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.
639
                          CR_NET_READ_INTERRUPTED :
640
                          CR_NET_READ_ERROR);
641
        goto end;
642
      }
643
      remain -= (uint32_t) length;
644
      pos+= length;
1537.1.1 by Joe Daly
add bytes_sent and bytes_received counters
645
      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.
646
    }
647
    if (i == 0)
648
    {                    /* First parts is packet length */
649
      uint32_t helping;
650
651
      if (net->buff[net->where_b + 3] != (unsigned char) net->pkt_nr)
652
      {
653
        len= packet_error;
654
        /* Not a NET error on the client. XXX: why? */
1302.4.4 by Eric Day
Updates for handshake testing.
655
        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.
656
        goto end;
657
      }
658
      net->compress_pkt_nr= ++net->pkt_nr;
659
      if (net->compress)
660
      {
661
        /*
662
          If the packet is compressed then complen > 0 and contains the
663
          number of bytes in the uncompressed packet
664
        */
665
        *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
666
      }
667
668
      len=uint3korr(net->buff+net->where_b);
669
      if (!len)                /* End of big multi-packet */
670
        goto end;
671
      helping = max(len,*complen) + net->where_b;
672
      /* The necessary size of net->buff */
673
      if (helping >= net->max_packet)
674
      {
675
        if (drizzleclient_net_realloc(net,helping))
676
        {
677
          len= packet_error;          /* Return error and close connection */
678
          goto end;
679
        }
680
      }
681
      pos=net->buff + net->where_b;
682
      remain = (uint32_t) len;
683
    }
684
  }
685
686
end:
687
  net->reading_or_writing= 0;
688
689
  return(len);
690
}
691
692
693
/**
694
   Read a packet from the client/server and return it without the internal
695
   package header.
696
697
   If the packet is the first packet of a multi-packet packet
698
   (which is indicated by the length of the packet = 0xffffff) then
699
   all sub packets are read and concatenated.
700
701
   If the packet was compressed, its uncompressed and the length of the
702
   uncompressed packet is returned.
703
704
   @return
705
   The function returns the length of the found packet or packet_error.
706
   net->read_pos points to the read data.
707
*/
708
709
uint32_t
710
drizzleclient_net_read(NET *net)
711
{
712
  size_t len, complen;
713
714
  if (!net->compress)
715
  {
716
    len = my_real_read(net,&complen);
717
    if (len == MAX_PACKET_LENGTH)
718
    {
719
      /* First packet of a multi-packet.  Concatenate the packets */
720
      uint32_t save_pos = net->where_b;
721
      size_t total_length= 0;
722
      do
723
      {
724
        net->where_b += len;
725
        total_length += len;
726
        len = my_real_read(net,&complen);
727
      } while (len == MAX_PACKET_LENGTH);
728
      if (len != packet_error)
729
        len+= total_length;
730
      net->where_b = save_pos;
731
    }
732
    net->read_pos = net->buff + net->where_b;
733
    if (len != packet_error)
734
      net->read_pos[len]=0;        /* Safeguard for drizzleclient_use_result */
735
    return len;
736
  }
737
  else
738
  {
739
    /* We are using the compressed protocol */
740
741
    uint32_t buf_length;
742
    uint32_t start_of_packet;
743
    uint32_t first_packet_offset;
744
    uint32_t read_length, multi_byte_packet=0;
745
746
    if (net->remain_in_buf)
747
    {
748
      buf_length= net->buf_length;        /* Data left in old packet */
749
      first_packet_offset= start_of_packet= (net->buf_length -
750
                                             net->remain_in_buf);
751
      /* Restore the character that was overwritten by the end 0 */
752
      net->buff[start_of_packet]= net->save_char;
753
    }
754
    else
755
    {
756
      /* reuse buffer, as there is nothing in it that we need */
757
      buf_length= start_of_packet= first_packet_offset= 0;
758
    }
759
    for (;;)
760
    {
761
      uint32_t packet_len;
762
763
      if (buf_length - start_of_packet >= NET_HEADER_SIZE)
764
      {
765
        read_length = uint3korr(net->buff+start_of_packet);
766
        if (!read_length)
767
        {
768
          /* End of multi-byte packet */
769
          start_of_packet += NET_HEADER_SIZE;
770
          break;
771
        }
772
        if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet)
773
        {
774
          if (multi_byte_packet)
775
          {
776
            /* Remove packet header for second packet */
777
            memmove(net->buff + first_packet_offset + start_of_packet,
778
                    net->buff + first_packet_offset + start_of_packet +
779
                    NET_HEADER_SIZE,
780
                    buf_length - start_of_packet);
781
            start_of_packet += read_length;
782
            buf_length -= NET_HEADER_SIZE;
783
          }
784
          else
785
            start_of_packet+= read_length + NET_HEADER_SIZE;
786
787
          if (read_length != MAX_PACKET_LENGTH)    /* last package */
788
          {
789
            multi_byte_packet= 0;        /* No last zero len packet */
790
            break;
791
          }
792
          multi_byte_packet= NET_HEADER_SIZE;
793
          /* Move data down to read next data packet after current one */
794
          if (first_packet_offset)
795
          {
796
            memmove(net->buff,net->buff+first_packet_offset,
797
                    buf_length-first_packet_offset);
798
            buf_length-=first_packet_offset;
799
            start_of_packet -= first_packet_offset;
800
            first_packet_offset=0;
801
          }
802
          continue;
803
        }
804
      }
805
      /* Move data down to read next data packet after current one */
806
      if (first_packet_offset)
807
      {
808
        memmove(net->buff,net->buff+first_packet_offset,
809
                buf_length-first_packet_offset);
810
        buf_length-=first_packet_offset;
811
        start_of_packet -= first_packet_offset;
812
        first_packet_offset=0;
813
      }
814
815
      net->where_b=buf_length;
816
      if ((packet_len = my_real_read(net,&complen)) == packet_error)
817
        return packet_error;
818
819
      if (complen)
820
      {
821
        unsigned char * compbuf= (unsigned char *) malloc(complen);
822
        if (compbuf != NULL)
823
        {
824
          uLongf tmp_complen= complen;
825
          int error= uncompress((Bytef*) compbuf, &tmp_complen,
826
                                (Bytef*) (net->buff + net->where_b),
827
                                (uLong)packet_len);
828
          complen= tmp_complen;
829
830
          if (error != Z_OK)
831
          {
832
            net->error= 2;            /* caller will close socket */
833
            net->last_errno= CR_NET_UNCOMPRESS_ERROR;
834
          }
835
          else
836
          {
837
            memcpy((net->buff + net->where_b), compbuf, complen);
838
          }
839
          free(compbuf);
840
        }
841
      }
842
      else
843
        complen= packet_len;
844
845
    }
846
    buf_length+= complen;
847
848
    net->read_pos=      net->buff+ first_packet_offset + NET_HEADER_SIZE;
849
    net->buf_length=    buf_length;
850
    net->remain_in_buf= (uint32_t) (buf_length - start_of_packet);
851
    len = ((uint32_t) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE -
852
           multi_byte_packet);
853
    net->save_char= net->read_pos[len];    /* Must be saved */
854
    net->read_pos[len]=0;        /* Safeguard for drizzleclient_use_result */
855
  }
856
  return len;
857
  }
858
859
860
void drizzleclient_net_set_read_timeout(NET *net, uint32_t timeout)
861
{
862
  net->read_timeout= timeout;
863
#ifndef __sun
864
  if (net->vio)
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.
865
    vio_timeout(net->vio, 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.
866
#endif
867
  return;
868
}
869
870
871
void drizzleclient_net_set_write_timeout(NET *net, uint32_t timeout)
872
{
873
  net->write_timeout= timeout;
874
#ifndef __sun
875
  if (net->vio)
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.
876
    vio_timeout(net->vio, 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.
877
#endif
878
  return;
879
}
880
/**
881
  Clear possible error state of struct NET
882
883
  @param net  clear the state of the argument
884
*/
885
886
void drizzleclient_drizzleclient_net_clear_error(NET *net)
887
{
888
  net->last_errno= 0;
889
  net->last_error[0]= '\0';
890
  strcpy(net->sqlstate, not_error_sqlstate);
891
}