~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;
578
  }
579
end:
580
  if ((net->compress) && (packet != NULL))
581
    free((char*) packet);
582
  net->reading_or_writing=0;
583
584
  return(((int) (pos != end)));
585
}
586
587
588
/**
589
   Reads one packet to net->buff + net->where_b.
590
   Long packets are handled by drizzleclient_net_read().
591
   This function reallocates the net->buff buffer if necessary.
592
593
   @return
594
   Returns length of packet.
595
*/
596
597
static uint32_t
598
my_real_read(NET *net, size_t *complen)
599
{
600
  unsigned char *pos;
601
  size_t length;
602
  uint32_t i,retry_count=0;
603
  size_t len=packet_error;
604
  uint32_t remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
605
                    NET_HEADER_SIZE);
606
607
  *complen = 0;
608
609
  net->reading_or_writing= 1;
610
  /* Read timeout is set in drizzleclient_net_set_read_timeout */
611
612
  pos = net->buff + net->where_b;        /* net->packet -4 */
613
614
  for (i= 0; i < 2 ; i++)
615
  {
616
    while (remain > 0)
617
    {
618
      /* 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.
619
      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.
620
      {
621
        if (net->vio == NULL)
622
          goto end;
623
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.
624
        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.
625
626
        if (interrupted)
627
        {                    /* Probably in MIT threads */
628
          if (retry_count++ < net->retry_count)
629
            continue;
630
        }
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.
631
        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.
632
        {
633
          continue;
634
        }
635
        len= packet_error;
636
        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.
637
        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.
638
                          CR_NET_READ_INTERRUPTED :
639
                          CR_NET_READ_ERROR);
640
        goto end;
641
      }
642
      remain -= (uint32_t) length;
643
      pos+= length;
644
    }
645
    if (i == 0)
646
    {                    /* First parts is packet length */
647
      uint32_t helping;
648
649
      if (net->buff[net->where_b + 3] != (unsigned char) net->pkt_nr)
650
      {
651
        len= packet_error;
652
        /* Not a NET error on the client. XXX: why? */
1302.4.4 by Eric Day
Updates for handshake testing.
653
        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.
654
        goto end;
655
      }
656
      net->compress_pkt_nr= ++net->pkt_nr;
657
      if (net->compress)
658
      {
659
        /*
660
          If the packet is compressed then complen > 0 and contains the
661
          number of bytes in the uncompressed packet
662
        */
663
        *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
664
      }
665
666
      len=uint3korr(net->buff+net->where_b);
667
      if (!len)                /* End of big multi-packet */
668
        goto end;
669
      helping = max(len,*complen) + net->where_b;
670
      /* The necessary size of net->buff */
671
      if (helping >= net->max_packet)
672
      {
673
        if (drizzleclient_net_realloc(net,helping))
674
        {
675
          len= packet_error;          /* Return error and close connection */
676
          goto end;
677
        }
678
      }
679
      pos=net->buff + net->where_b;
680
      remain = (uint32_t) len;
681
    }
682
  }
683
684
end:
685
  net->reading_or_writing= 0;
686
687
  return(len);
688
}
689
690
691
/**
692
   Read a packet from the client/server and return it without the internal
693
   package header.
694
695
   If the packet is the first packet of a multi-packet packet
696
   (which is indicated by the length of the packet = 0xffffff) then
697
   all sub packets are read and concatenated.
698
699
   If the packet was compressed, its uncompressed and the length of the
700
   uncompressed packet is returned.
701
702
   @return
703
   The function returns the length of the found packet or packet_error.
704
   net->read_pos points to the read data.
705
*/
706
707
uint32_t
708
drizzleclient_net_read(NET *net)
709
{
710
  size_t len, complen;
711
712
  if (!net->compress)
713
  {
714
    len = my_real_read(net,&complen);
715
    if (len == MAX_PACKET_LENGTH)
716
    {
717
      /* First packet of a multi-packet.  Concatenate the packets */
718
      uint32_t save_pos = net->where_b;
719
      size_t total_length= 0;
720
      do
721
      {
722
        net->where_b += len;
723
        total_length += len;
724
        len = my_real_read(net,&complen);
725
      } while (len == MAX_PACKET_LENGTH);
726
      if (len != packet_error)
727
        len+= total_length;
728
      net->where_b = save_pos;
729
    }
730
    net->read_pos = net->buff + net->where_b;
731
    if (len != packet_error)
732
      net->read_pos[len]=0;        /* Safeguard for drizzleclient_use_result */
733
    return len;
734
  }
735
  else
736
  {
737
    /* We are using the compressed protocol */
738
739
    uint32_t buf_length;
740
    uint32_t start_of_packet;
741
    uint32_t first_packet_offset;
742
    uint32_t read_length, multi_byte_packet=0;
743
744
    if (net->remain_in_buf)
745
    {
746
      buf_length= net->buf_length;        /* Data left in old packet */
747
      first_packet_offset= start_of_packet= (net->buf_length -
748
                                             net->remain_in_buf);
749
      /* Restore the character that was overwritten by the end 0 */
750
      net->buff[start_of_packet]= net->save_char;
751
    }
752
    else
753
    {
754
      /* reuse buffer, as there is nothing in it that we need */
755
      buf_length= start_of_packet= first_packet_offset= 0;
756
    }
757
    for (;;)
758
    {
759
      uint32_t packet_len;
760
761
      if (buf_length - start_of_packet >= NET_HEADER_SIZE)
762
      {
763
        read_length = uint3korr(net->buff+start_of_packet);
764
        if (!read_length)
765
        {
766
          /* End of multi-byte packet */
767
          start_of_packet += NET_HEADER_SIZE;
768
          break;
769
        }
770
        if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet)
771
        {
772
          if (multi_byte_packet)
773
          {
774
            /* Remove packet header for second packet */
775
            memmove(net->buff + first_packet_offset + start_of_packet,
776
                    net->buff + first_packet_offset + start_of_packet +
777
                    NET_HEADER_SIZE,
778
                    buf_length - start_of_packet);
779
            start_of_packet += read_length;
780
            buf_length -= NET_HEADER_SIZE;
781
          }
782
          else
783
            start_of_packet+= read_length + NET_HEADER_SIZE;
784
785
          if (read_length != MAX_PACKET_LENGTH)    /* last package */
786
          {
787
            multi_byte_packet= 0;        /* No last zero len packet */
788
            break;
789
          }
790
          multi_byte_packet= NET_HEADER_SIZE;
791
          /* Move data down to read next data packet after current one */
792
          if (first_packet_offset)
793
          {
794
            memmove(net->buff,net->buff+first_packet_offset,
795
                    buf_length-first_packet_offset);
796
            buf_length-=first_packet_offset;
797
            start_of_packet -= first_packet_offset;
798
            first_packet_offset=0;
799
          }
800
          continue;
801
        }
802
      }
803
      /* Move data down to read next data packet after current one */
804
      if (first_packet_offset)
805
      {
806
        memmove(net->buff,net->buff+first_packet_offset,
807
                buf_length-first_packet_offset);
808
        buf_length-=first_packet_offset;
809
        start_of_packet -= first_packet_offset;
810
        first_packet_offset=0;
811
      }
812
813
      net->where_b=buf_length;
814
      if ((packet_len = my_real_read(net,&complen)) == packet_error)
815
        return packet_error;
816
817
      if (complen)
818
      {
819
        unsigned char * compbuf= (unsigned char *) malloc(complen);
820
        if (compbuf != NULL)
821
        {
822
          uLongf tmp_complen= complen;
823
          int error= uncompress((Bytef*) compbuf, &tmp_complen,
824
                                (Bytef*) (net->buff + net->where_b),
825
                                (uLong)packet_len);
826
          complen= tmp_complen;
827
828
          if (error != Z_OK)
829
          {
830
            net->error= 2;            /* caller will close socket */
831
            net->last_errno= CR_NET_UNCOMPRESS_ERROR;
832
          }
833
          else
834
          {
835
            memcpy((net->buff + net->where_b), compbuf, complen);
836
          }
837
          free(compbuf);
838
        }
839
      }
840
      else
841
        complen= packet_len;
842
843
    }
844
    buf_length+= complen;
845
846
    net->read_pos=      net->buff+ first_packet_offset + NET_HEADER_SIZE;
847
    net->buf_length=    buf_length;
848
    net->remain_in_buf= (uint32_t) (buf_length - start_of_packet);
849
    len = ((uint32_t) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE -
850
           multi_byte_packet);
851
    net->save_char= net->read_pos[len];    /* Must be saved */
852
    net->read_pos[len]=0;        /* Safeguard for drizzleclient_use_result */
853
  }
854
  return len;
855
  }
856
857
858
void drizzleclient_net_set_read_timeout(NET *net, uint32_t timeout)
859
{
860
  net->read_timeout= timeout;
861
#ifndef __sun
862
  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.
863
    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.
864
#endif
865
  return;
866
}
867
868
869
void drizzleclient_net_set_write_timeout(NET *net, uint32_t timeout)
870
{
871
  net->write_timeout= timeout;
872
#ifndef __sun
873
  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.
874
    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.
875
#endif
876
  return;
877
}
878
/**
879
  Clear possible error state of struct NET
880
881
  @param net  clear the state of the argument
882
*/
883
884
void drizzleclient_drizzleclient_net_clear_error(NET *net)
885
{
886
  net->last_errno= 0;
887
  net->last_error[0]= '\0';
888
  strcpy(net->sqlstate, not_error_sqlstate);
889
}