~skinny.moey/drizzle/innodb-replication

« back to all changes in this revision

Viewing changes to plugin/drizzle_protocol/net_serv.cc

  • Committer: Brian Aker
  • Date: 2010-11-08 22:35:57 UTC
  • mfrom: (1802.1.114 trunk)
  • Revision ID: brian@tangent.org-20101108223557-w3xzwp9hjjtjhtc1
MergeĀ inĀ trunk.

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