~ubuntu-branches/ubuntu/saucy/drizzle/saucy-proposed

« back to all changes in this revision

Viewing changes to plugin/mysql_protocol/net_serv.cc

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-03-18 12:12:31 UTC
  • Revision ID: james.westby@ubuntu.com-20100318121231-k6g1xe6cshbwa0f8
Tags: upstream-2010.03.1347
ImportĀ upstreamĀ versionĀ 2010.03.1347

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
21
#include "config.h"
 
22
#include <drizzled/session.h>
 
23
 
 
24
#include <assert.h>
 
25
#include <stdio.h>
 
26
#include <stdlib.h>
 
27
#include <string.h>
 
28
#include <signal.h>
 
29
#include <errno.h>
 
30
#include <sys/socket.h>
 
31
#include <sys/poll.h>
 
32
#include <zlib.h>
 
33
#include <algorithm>
 
34
 
 
35
#include "errmsg.h"
 
36
#include "vio.h"
 
37
#include "net_serv.h"
 
38
 
 
39
using namespace std;
 
40
 
 
41
/*
 
42
  The following handles the differences when this is linked between the
 
43
  client and the server.
 
44
 
 
45
  This gives an error if a too big packet is found
 
46
  The server can change this with the -O switch, but because the client
 
47
  can't normally do this the client should have a bigger max_allowed_packet.
 
48
*/
 
49
 
 
50
  /* Constants when using compression */
 
51
#define NET_HEADER_SIZE 4               /* standard header size */
 
52
#define COMP_HEADER_SIZE 3              /* compression header extra size */
 
53
 
 
54
#define MAX_PACKET_LENGTH (256L*256L*256L-1)
 
55
const char  *not_error_sqlstate= "00000";
 
56
 
 
57
static bool net_write_buff(NET *net, const unsigned char *packet, uint32_t len);
 
58
static int drizzleclient_net_real_write(NET *net, const unsigned char *packet, size_t len);
 
59
 
 
60
/** Init with packet info. */
 
61
 
 
62
bool drizzleclient_net_init(NET *net, Vio* vio, uint32_t buffer_length)
 
63
{
 
64
  net->vio = vio;
 
65
  net->max_packet= (uint32_t) buffer_length;
 
66
  net->max_packet_size= max(buffer_length, drizzled::global_system_variables.max_allowed_packet);
 
67
 
 
68
  if (!(net->buff=(unsigned char*) malloc((size_t) net->max_packet+
 
69
                                          NET_HEADER_SIZE + COMP_HEADER_SIZE)))
 
70
    return(1);
 
71
  net->buff_end=net->buff+net->max_packet;
 
72
  net->error=0; net->return_status=0;
 
73
  net->pkt_nr=net->compress_pkt_nr=0;
 
74
  net->write_pos=net->read_pos = net->buff;
 
75
  net->last_error[0]=0;
 
76
  net->compress=0; net->reading_or_writing=0;
 
77
  net->where_b = net->remain_in_buf=0;
 
78
  net->last_errno=0;
 
79
  net->unused= 0;
 
80
 
 
81
  if (vio != 0)                    /* If real connection */
 
82
  {
 
83
    net->fd  = drizzleclient_vio_fd(vio);            /* For perl DBI/DBD */
 
84
    drizzleclient_vio_fastsend(vio);
 
85
  }
 
86
  return(0);
 
87
}
 
88
 
 
89
bool drizzleclient_net_init_sock(NET * net, int sock, int flags,
 
90
                                 uint32_t buffer_length)
 
91
{
 
92
 
 
93
  Vio *drizzleclient_vio_tmp= drizzleclient_vio_new(sock, VIO_TYPE_TCPIP, flags);
 
94
  if (drizzleclient_vio_tmp == NULL)
 
95
    return true;
 
96
  else
 
97
    if (drizzleclient_net_init(net, drizzleclient_vio_tmp, buffer_length))
 
98
    {
 
99
      /* Only delete the temporary vio if we didn't already attach it to the
 
100
       * NET object.
 
101
       */
 
102
      if (drizzleclient_vio_tmp && (net->vio != drizzleclient_vio_tmp))
 
103
        drizzleclient_vio_delete(drizzleclient_vio_tmp);
 
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
  {
 
126
    drizzleclient_vio_delete(net->vio);
 
127
    net->vio= 0;
 
128
  }
 
129
}
 
130
 
 
131
bool drizzleclient_net_peer_addr(NET *net, char *buf, uint16_t *port, size_t buflen)
 
132
{
 
133
  return drizzleclient_vio_peer_addr(net->vio, buf, port, buflen);
 
134
}
 
135
 
 
136
void drizzleclient_net_keepalive(NET *net, bool flag)
 
137
{
 
138
  drizzleclient_vio_keepalive(net->vio, flag);
 
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;
 
162
    net->last_errno= CR_NET_PACKET_TOO_LARGE;
 
163
    return(1);
 
164
  }
 
165
  pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
 
166
  /*
 
167
    We must allocate some extra bytes for the end 0 and to be able to
 
168
    read big compressed blocks
 
169
  */
 
170
  if (!(buff= (unsigned char*) realloc((char*) net->buff, pkt_length +
 
171
                               NET_HEADER_SIZE + COMP_HEADER_SIZE)))
 
172
  {
 
173
    /* @todo: 1 and 2 codes are identical. */
 
174
    net->error= 1;
 
175
    net->last_errno= CR_OUT_OF_MEMORY;
 
176
    /* In the server the error is reported by MY_WME flag. */
 
177
    return(1);
 
178
  }
 
179
  net->buff=net->write_pos=buff;
 
180
  net->buff_end=buff+(net->max_packet= (uint32_t) pkt_length);
 
181
  return(0);
 
182
}
 
183
 
 
184
 
 
185
/**
 
186
   Check if there is any data to be read from the socket.
 
187
 
 
188
   @param sd   socket descriptor
 
189
 
 
190
   @retval
 
191
   0  No data to read
 
192
   @retval
 
193
   1  Data or EOF to read
 
194
   @retval
 
195
   -1   Don't know if data is ready or not
 
196
*/
 
197
 
 
198
static bool net_data_is_ready(int sd)
 
199
{
 
200
  struct pollfd ufds;
 
201
  int res;
 
202
 
 
203
  ufds.fd= sd;
 
204
  ufds.events= POLLIN | POLLPRI;
 
205
  if (!(res= poll(&ufds, 1, 0)))
 
206
    return 0;
 
207
  if (res < 0 || !(ufds.revents & (POLLIN | POLLPRI)))
 
208
    return 0;
 
209
  return 1;
 
210
}
 
211
 
 
212
/**
 
213
   Remove unwanted characters from connection
 
214
   and check if disconnected.
 
215
 
 
216
   Read from socket until there is nothing more to read. Discard
 
217
   what is read.
 
218
 
 
219
   If there is anything when to read 'drizzleclient_net_clear' is called this
 
220
   normally indicates an error in the protocol.
 
221
 
 
222
   When connection is properly closed (for TCP it means with
 
223
   a FIN packet), then select() considers a socket "ready to read",
 
224
   in the sense that there's EOF to read, but read() returns 0.
 
225
 
 
226
   @param net            NET handler
 
227
   @param clear_buffer           if <> 0, then clear all data from comm buff
 
228
*/
 
229
 
 
230
void drizzleclient_net_clear(NET *net, bool clear_buffer)
 
231
{
 
232
  if (clear_buffer)
 
233
  {
 
234
    while (net_data_is_ready(net->vio->sd) > 0)
 
235
    {
 
236
      /* The socket is ready */
 
237
      if (drizzleclient_vio_read(net->vio, net->buff,
 
238
                   (size_t) net->max_packet) <= 0)
 
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);
 
530
    if ((long) (length= drizzleclient_vio_write(net->vio, pos, (size_t) (end-pos))) <= 0)
 
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
      
 
540
      const bool interrupted= drizzleclient_vio_should_retry(net->vio);
 
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
 
 
550
        while (drizzleclient_vio_blocking(net->vio, true, &old_mode) < 0)
 
551
        {
 
552
          if (drizzleclient_vio_should_retry(net->vio) && retry_count++ < net->retry_count)
 
553
            continue;
 
554
          net->error= 2;                     /* Close socket */
 
555
          net->last_errno= CR_NET_PACKET_TOO_LARGE;
 
556
          goto end;
 
557
        }
 
558
        retry_count=0;
 
559
        continue;
 
560
      }
 
561
      else
 
562
      {
 
563
        if (retry_count++ < net->retry_count)
 
564
          continue;
 
565
      }
 
566
 
 
567
      if (drizzleclient_vio_errno(net->vio) == EINTR)
 
568
      {
 
569
        continue;
 
570
      }
 
571
      net->error= 2;                /* Close socket */
 
572
      net->last_errno= (interrupted ? CR_NET_WRITE_INTERRUPTED :
 
573
                        CR_NET_ERROR_ON_WRITE);
 
574
      break;
 
575
    }
 
576
    pos+=length;
 
577
  }
 
578
end:
 
579
  if ((net->compress) && (packet != NULL))
 
580
    free((char*) packet);
 
581
  net->reading_or_writing=0;
 
582
 
 
583
  return(((int) (pos != end)));
 
584
}
 
585
 
 
586
 
 
587
/**
 
588
   Reads one packet to net->buff + net->where_b.
 
589
   Long packets are handled by drizzleclient_net_read().
 
590
   This function reallocates the net->buff buffer if necessary.
 
591
 
 
592
   @return
 
593
   Returns length of packet.
 
594
*/
 
595
 
 
596
static uint32_t
 
597
my_real_read(NET *net, size_t *complen)
 
598
{
 
599
  unsigned char *pos;
 
600
  size_t length;
 
601
  uint32_t i,retry_count=0;
 
602
  size_t len=packet_error;
 
603
  uint32_t remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
 
604
                    NET_HEADER_SIZE);
 
605
 
 
606
  *complen = 0;
 
607
 
 
608
  net->reading_or_writing= 1;
 
609
  /* Read timeout is set in drizzleclient_net_set_read_timeout */
 
610
 
 
611
  pos = net->buff + net->where_b;        /* net->packet -4 */
 
612
 
 
613
  for (i= 0; i < 2 ; i++)
 
614
  {
 
615
    while (remain > 0)
 
616
    {
 
617
      /* First read is done with non blocking mode */
 
618
      if ((long) (length= drizzleclient_vio_read(net->vio, pos, remain)) <= 0L)
 
619
      {
 
620
        if (net->vio == NULL)
 
621
          goto end;
 
622
 
 
623
        const bool interrupted = drizzleclient_vio_should_retry(net->vio);
 
624
 
 
625
        if (interrupted)
 
626
        {                    /* Probably in MIT threads */
 
627
          if (retry_count++ < net->retry_count)
 
628
            continue;
 
629
        }
 
630
        if (drizzleclient_vio_errno(net->vio) == EINTR)
 
631
        {
 
632
          continue;
 
633
        }
 
634
        len= packet_error;
 
635
        net->error= 2;                /* Close socket */
 
636
        net->last_errno= (drizzleclient_vio_was_interrupted(net->vio) ?
 
637
                          CR_NET_READ_INTERRUPTED :
 
638
                          CR_NET_READ_ERROR);
 
639
        ER(net->last_errno);
 
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? */
 
653
        goto end;
 
654
      }
 
655
      net->compress_pkt_nr= ++net->pkt_nr;
 
656
      if (net->compress)
 
657
      {
 
658
        /*
 
659
          If the packet is compressed then complen > 0 and contains the
 
660
          number of bytes in the uncompressed packet
 
661
        */
 
662
        *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
 
663
      }
 
664
 
 
665
      len=uint3korr(net->buff+net->where_b);
 
666
      if (!len)                /* End of big multi-packet */
 
667
        goto end;
 
668
      helping = max(len,*complen) + net->where_b;
 
669
      /* The necessary size of net->buff */
 
670
      if (helping >= net->max_packet)
 
671
      {
 
672
        if (drizzleclient_net_realloc(net,helping))
 
673
        {
 
674
          len= packet_error;          /* Return error and close connection */
 
675
          goto end;
 
676
        }
 
677
      }
 
678
      pos=net->buff + net->where_b;
 
679
      remain = (uint32_t) len;
 
680
    }
 
681
  }
 
682
 
 
683
end:
 
684
  net->reading_or_writing= 0;
 
685
 
 
686
  return(len);
 
687
}
 
688
 
 
689
 
 
690
/**
 
691
   Read a packet from the client/server and return it without the internal
 
692
   package header.
 
693
 
 
694
   If the packet is the first packet of a multi-packet packet
 
695
   (which is indicated by the length of the packet = 0xffffff) then
 
696
   all sub packets are read and concatenated.
 
697
 
 
698
   If the packet was compressed, its uncompressed and the length of the
 
699
   uncompressed packet is returned.
 
700
 
 
701
   @return
 
702
   The function returns the length of the found packet or packet_error.
 
703
   net->read_pos points to the read data.
 
704
*/
 
705
 
 
706
uint32_t
 
707
drizzleclient_net_read(NET *net)
 
708
{
 
709
  size_t len, complen;
 
710
 
 
711
  if (!net->compress)
 
712
  {
 
713
    len = my_real_read(net,&complen);
 
714
    if (len == MAX_PACKET_LENGTH)
 
715
    {
 
716
      /* First packet of a multi-packet.  Concatenate the packets */
 
717
      uint32_t save_pos = net->where_b;
 
718
      size_t total_length= 0;
 
719
      do
 
720
      {
 
721
        net->where_b += len;
 
722
        total_length += len;
 
723
        len = my_real_read(net,&complen);
 
724
      } while (len == MAX_PACKET_LENGTH);
 
725
      if (len != packet_error)
 
726
        len+= total_length;
 
727
      net->where_b = save_pos;
 
728
    }
 
729
    net->read_pos = net->buff + net->where_b;
 
730
    if (len != packet_error)
 
731
      net->read_pos[len]=0;        /* Safeguard for drizzleclient_use_result */
 
732
    return len;
 
733
  }
 
734
  else
 
735
  {
 
736
    /* We are using the compressed protocol */
 
737
 
 
738
    uint32_t buf_length;
 
739
    uint32_t start_of_packet;
 
740
    uint32_t first_packet_offset;
 
741
    uint32_t read_length, multi_byte_packet=0;
 
742
 
 
743
    if (net->remain_in_buf)
 
744
    {
 
745
      buf_length= net->buf_length;        /* Data left in old packet */
 
746
      first_packet_offset= start_of_packet= (net->buf_length -
 
747
                                             net->remain_in_buf);
 
748
      /* Restore the character that was overwritten by the end 0 */
 
749
      net->buff[start_of_packet]= net->save_char;
 
750
    }
 
751
    else
 
752
    {
 
753
      /* reuse buffer, as there is nothing in it that we need */
 
754
      buf_length= start_of_packet= first_packet_offset= 0;
 
755
    }
 
756
    for (;;)
 
757
    {
 
758
      uint32_t packet_len;
 
759
 
 
760
      if (buf_length - start_of_packet >= NET_HEADER_SIZE)
 
761
      {
 
762
        read_length = uint3korr(net->buff+start_of_packet);
 
763
        if (!read_length)
 
764
        {
 
765
          /* End of multi-byte packet */
 
766
          start_of_packet += NET_HEADER_SIZE;
 
767
          break;
 
768
        }
 
769
        if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet)
 
770
        {
 
771
          if (multi_byte_packet)
 
772
          {
 
773
            /* Remove packet header for second packet */
 
774
            memmove(net->buff + first_packet_offset + start_of_packet,
 
775
                    net->buff + first_packet_offset + start_of_packet +
 
776
                    NET_HEADER_SIZE,
 
777
                    buf_length - start_of_packet);
 
778
            start_of_packet += read_length;
 
779
            buf_length -= NET_HEADER_SIZE;
 
780
          }
 
781
          else
 
782
            start_of_packet+= read_length + NET_HEADER_SIZE;
 
783
 
 
784
          if (read_length != MAX_PACKET_LENGTH)    /* last package */
 
785
          {
 
786
            multi_byte_packet= 0;        /* No last zero len packet */
 
787
            break;
 
788
          }
 
789
          multi_byte_packet= NET_HEADER_SIZE;
 
790
          /* Move data down to read next data packet after current one */
 
791
          if (first_packet_offset)
 
792
          {
 
793
            memmove(net->buff,net->buff+first_packet_offset,
 
794
                    buf_length-first_packet_offset);
 
795
            buf_length-=first_packet_offset;
 
796
            start_of_packet -= first_packet_offset;
 
797
            first_packet_offset=0;
 
798
          }
 
799
          continue;
 
800
        }
 
801
      }
 
802
      /* Move data down to read next data packet after current one */
 
803
      if (first_packet_offset)
 
804
      {
 
805
        memmove(net->buff,net->buff+first_packet_offset,
 
806
                buf_length-first_packet_offset);
 
807
        buf_length-=first_packet_offset;
 
808
        start_of_packet -= first_packet_offset;
 
809
        first_packet_offset=0;
 
810
      }
 
811
 
 
812
      net->where_b=buf_length;
 
813
      if ((packet_len = my_real_read(net,&complen)) == packet_error)
 
814
        return packet_error;
 
815
 
 
816
      if (complen)
 
817
      {
 
818
        unsigned char * compbuf= (unsigned char *) malloc(complen);
 
819
        if (compbuf != NULL)
 
820
        {
 
821
          uLongf tmp_complen= complen;
 
822
          int error= uncompress((Bytef*) compbuf, &tmp_complen,
 
823
                                (Bytef*) (net->buff + net->where_b),
 
824
                                (uLong)packet_len);
 
825
          complen= tmp_complen;
 
826
 
 
827
          if (error != Z_OK)
 
828
          {
 
829
            net->error= 2;            /* caller will close socket */
 
830
            net->last_errno= CR_NET_UNCOMPRESS_ERROR;
 
831
          }
 
832
          else
 
833
          {
 
834
            memcpy((net->buff + net->where_b), compbuf, complen);
 
835
          }
 
836
          free(compbuf);
 
837
        }
 
838
      }
 
839
      else
 
840
        complen= packet_len;
 
841
 
 
842
    }
 
843
    buf_length+= complen;
 
844
 
 
845
    net->read_pos=      net->buff+ first_packet_offset + NET_HEADER_SIZE;
 
846
    net->buf_length=    buf_length;
 
847
    net->remain_in_buf= (uint32_t) (buf_length - start_of_packet);
 
848
    len = ((uint32_t) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE -
 
849
           multi_byte_packet);
 
850
    net->save_char= net->read_pos[len];    /* Must be saved */
 
851
    net->read_pos[len]=0;        /* Safeguard for drizzleclient_use_result */
 
852
  }
 
853
  return len;
 
854
  }
 
855
 
 
856
 
 
857
void drizzleclient_net_set_read_timeout(NET *net, uint32_t timeout)
 
858
{
 
859
  net->read_timeout= timeout;
 
860
#ifndef __sun
 
861
  if (net->vio)
 
862
    drizzleclient_vio_timeout(net->vio, 0, timeout);
 
863
#endif
 
864
  return;
 
865
}
 
866
 
 
867
 
 
868
void drizzleclient_net_set_write_timeout(NET *net, uint32_t timeout)
 
869
{
 
870
  net->write_timeout= timeout;
 
871
#ifndef __sun
 
872
  if (net->vio)
 
873
    drizzleclient_vio_timeout(net->vio, 1, timeout);
 
874
#endif
 
875
  return;
 
876
}
 
877
/**
 
878
  Clear possible error state of struct NET
 
879
 
 
880
  @param net  clear the state of the argument
 
881
*/
 
882
 
 
883
void drizzleclient_drizzleclient_net_clear_error(NET *net)
 
884
{
 
885
  net->last_errno= 0;
 
886
  net->last_error[0]= '\0';
 
887
  strcpy(net->sqlstate, not_error_sqlstate);
 
888
}
 
889