~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/mysql_protocol/net_serv.cc

  • Committer: Mark Atwood
  • Date: 2008-10-16 11:33:16 UTC
  • mto: (520.1.13 drizzle)
  • mto: This revision was merged to the branch mainline in revision 530.
  • Revision ID: mark@fallenpegasus.com-20081016113316-ff6jdt31ck90sjdh
an implemention of the errmsg plugin

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