~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/mysql_protocol/net_serv.cc

  • Committer: Lee
  • Date: 2008-10-30 22:02:01 UTC
  • mto: (572.1.2 devel)
  • mto: This revision was merged to the branch mainline in revision 573.
  • Revision ID: lbieber@lbieber-desktop-20081030220201-elb6qprbzpn7c5a4
add my name to the AUTHORS file

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