~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/drizzle_protocol/net_serv.cc

  • Committer: lbieber
  • Date: 2010-10-02 19:48:35 UTC
  • mfrom: (1730.6.19 drizzle-make-lcov)
  • Revision ID: lbieber@orisndriz08-20101002194835-q5zd9qc4lvx1xnfo
Merge Hartmut - clean up lex, now require flex to build, also "make lcov" improvements

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 */