~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/drizzle_protocol/net_serv.cc

  • Committer: Brian Aker
  • Date: 2010-11-19 19:42:44 UTC
  • mto: (1945.2.1 quick)
  • mto: This revision was merged to the branch mainline in revision 1944.
  • Revision ID: brian@tangent.org-20101119194244-7vx6u5vwzvu9uvex
Remove dead getShare() call which should have been a call on the cache
directly.

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
 
  }
582
 
end:
583
 
  if ((net->compress) && (packet != NULL))
584
 
    free((char*) packet);
585
 
  net->reading_or_writing=0;
586
 
 
587
 
  return(((int) (pos != end)));
588
 
}
589
 
 
590
 
 
591
 
/**
592
 
   Reads one packet to net->buff + net->where_b.
593
 
   Long packets are handled by drizzleclient_net_read().
594
 
   This function reallocates the net->buff buffer if necessary.
595
 
 
596
 
   @return
597
 
   Returns length of packet.
598
 
*/
599
 
 
600
 
static uint32_t
601
 
my_real_read(NET *net, size_t *complen)
602
 
{
603
 
  unsigned char *pos;
604
 
  size_t length;
605
 
  uint32_t i,retry_count=0;
606
 
  size_t len=packet_error;
607
 
  uint32_t remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
608
 
                    NET_HEADER_SIZE);
609
 
 
610
 
  *complen = 0;
611
 
 
612
 
  net->reading_or_writing= 1;
613
 
  /* Read timeout is set in drizzleclient_net_set_read_timeout */
614
 
 
615
 
  pos = net->buff + net->where_b;        /* net->packet -4 */
616
 
 
617
 
  for (i= 0; i < 2 ; i++)
618
 
  {
619
 
    while (remain > 0)
620
 
    {
621
 
      /* First read is done with non blocking mode */
622
 
      if ((long) (length= drizzleclient_vio_read(net->vio, pos, remain)) <= 0L)
623
 
      {
624
 
        if (net->vio == NULL)
625
 
          goto end;
626
 
 
627
 
        const bool interrupted = drizzleclient_vio_should_retry(net->vio);
628
 
 
629
 
        if (interrupted)
630
 
        {                    /* Probably in MIT threads */
631
 
          if (retry_count++ < net->retry_count)
632
 
            continue;
633
 
        }
634
 
        if (drizzleclient_vio_errno(net->vio) == EINTR)
635
 
        {
636
 
          continue;
637
 
        }
638
 
        len= packet_error;
639
 
        net->error= 2;                /* Close socket */
640
 
        net->last_errno= (drizzleclient_vio_was_interrupted(net->vio) ?
641
 
                          CR_NET_READ_INTERRUPTED :
642
 
                          CR_NET_READ_ERROR);
643
 
        ER(net->last_errno);
644
 
        goto end;
645
 
      }
646
 
      remain -= (uint32_t) length;
647
 
      pos+= length;
648
 
    }
649
 
    if (i == 0)
650
 
    {                    /* First parts is packet length */
651
 
      uint32_t helping;
652
 
 
653
 
      if (net->buff[net->where_b + 3] != (unsigned char) net->pkt_nr)
654
 
      {
655
 
        len= packet_error;
656
 
        /* Not a NET error on the client. XXX: why? */
657
 
        goto end;
658
 
      }
659
 
      net->compress_pkt_nr= ++net->pkt_nr;
660
 
      if (net->compress)
661
 
      {
662
 
        /*
663
 
          If the packet is compressed then complen > 0 and contains the
664
 
          number of bytes in the uncompressed packet
665
 
        */
666
 
        *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
667
 
      }
668
 
 
669
 
      len=uint3korr(net->buff+net->where_b);
670
 
      if (!len)                /* End of big multi-packet */
671
 
        goto end;
672
 
      helping = max(len,*complen) + net->where_b;
673
 
      /* The necessary size of net->buff */
674
 
      if (helping >= net->max_packet)
675
 
      {
676
 
        if (drizzleclient_net_realloc(net,helping))
677
 
        {
678
 
          len= packet_error;          /* Return error and close connection */
679
 
          goto end;
680
 
        }
681
 
      }
682
 
      pos=net->buff + net->where_b;
683
 
      remain = (uint32_t) len;
684
 
    }
685
 
  }
686
 
 
687
 
end:
688
 
  net->reading_or_writing= 0;
689
 
 
690
 
  return(len);
691
 
}
692
 
 
693
 
 
694
 
/**
695
 
   Read a packet from the client/server and return it without the internal
696
 
   package header.
697
 
 
698
 
   If the packet is the first packet of a multi-packet packet
699
 
   (which is indicated by the length of the packet = 0xffffff) then
700
 
   all sub packets are read and concatenated.
701
 
 
702
 
   If the packet was compressed, its uncompressed and the length of the
703
 
   uncompressed packet is returned.
704
 
 
705
 
   @return
706
 
   The function returns the length of the found packet or packet_error.
707
 
   net->read_pos points to the read data.
708
 
*/
709
 
 
710
 
uint32_t
711
 
drizzleclient_net_read(NET *net)
712
 
{
713
 
  size_t len, complen;
714
 
 
715
 
  if (!net->compress)
716
 
  {
717
 
    len = my_real_read(net,&complen);
718
 
    if (len == MAX_PACKET_LENGTH)
719
 
    {
720
 
      /* First packet of a multi-packet.  Concatenate the packets */
721
 
      uint32_t save_pos = net->where_b;
722
 
      size_t total_length= 0;
723
 
      do
724
 
      {
725
 
        net->where_b += len;
726
 
        total_length += len;
727
 
        len = my_real_read(net,&complen);
728
 
      } while (len == MAX_PACKET_LENGTH);
729
 
      if (len != packet_error)
730
 
        len+= total_length;
731
 
      net->where_b = save_pos;
732
 
    }
733
 
    net->read_pos = net->buff + net->where_b;
734
 
    if (len != packet_error)
735
 
      net->read_pos[len]=0;        /* Safeguard for drizzleclient_use_result */
736
 
    return len;
737
 
  }
738
 
  else
739
 
  {
740
 
    /* We are using the compressed protocol */
741
 
 
742
 
    uint32_t buf_length;
743
 
    uint32_t start_of_packet;
744
 
    uint32_t first_packet_offset;
745
 
    uint32_t read_length, multi_byte_packet=0;
746
 
 
747
 
    if (net->remain_in_buf)
748
 
    {
749
 
      buf_length= net->buf_length;        /* Data left in old packet */
750
 
      first_packet_offset= start_of_packet= (net->buf_length -
751
 
                                             net->remain_in_buf);
752
 
      /* Restore the character that was overwritten by the end 0 */
753
 
      net->buff[start_of_packet]= net->save_char;
754
 
    }
755
 
    else
756
 
    {
757
 
      /* reuse buffer, as there is nothing in it that we need */
758
 
      buf_length= start_of_packet= first_packet_offset= 0;
759
 
    }
760
 
    for (;;)
761
 
    {
762
 
      uint32_t packet_len;
763
 
 
764
 
      if (buf_length - start_of_packet >= NET_HEADER_SIZE)
765
 
      {
766
 
        read_length = uint3korr(net->buff+start_of_packet);
767
 
        if (!read_length)
768
 
        {
769
 
          /* End of multi-byte packet */
770
 
          start_of_packet += NET_HEADER_SIZE;
771
 
          break;
772
 
        }
773
 
        if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet)
774
 
        {
775
 
          if (multi_byte_packet)
776
 
          {
777
 
            /* Remove packet header for second packet */
778
 
            memmove(net->buff + first_packet_offset + start_of_packet,
779
 
                    net->buff + first_packet_offset + start_of_packet +
780
 
                    NET_HEADER_SIZE,
781
 
                    buf_length - start_of_packet);
782
 
            start_of_packet += read_length;
783
 
            buf_length -= NET_HEADER_SIZE;
784
 
          }
785
 
          else
786
 
            start_of_packet+= read_length + NET_HEADER_SIZE;
787
 
 
788
 
          if (read_length != MAX_PACKET_LENGTH)    /* last package */
789
 
          {
790
 
            multi_byte_packet= 0;        /* No last zero len packet */
791
 
            break;
792
 
          }
793
 
          multi_byte_packet= NET_HEADER_SIZE;
794
 
          /* Move data down to read next data packet after current one */
795
 
          if (first_packet_offset)
796
 
          {
797
 
            memmove(net->buff,net->buff+first_packet_offset,
798
 
                    buf_length-first_packet_offset);
799
 
            buf_length-=first_packet_offset;
800
 
            start_of_packet -= first_packet_offset;
801
 
            first_packet_offset=0;
802
 
          }
803
 
          continue;
804
 
        }
805
 
      }
806
 
      /* Move data down to read next data packet after current one */
807
 
      if (first_packet_offset)
808
 
      {
809
 
        memmove(net->buff,net->buff+first_packet_offset,
810
 
                buf_length-first_packet_offset);
811
 
        buf_length-=first_packet_offset;
812
 
        start_of_packet -= first_packet_offset;
813
 
        first_packet_offset=0;
814
 
      }
815
 
 
816
 
      net->where_b=buf_length;
817
 
      if ((packet_len = my_real_read(net,&complen)) == packet_error)
818
 
        return packet_error;
819
 
 
820
 
      if (complen)
821
 
      {
822
 
        unsigned char * compbuf= (unsigned char *) malloc(complen);
823
 
        if (compbuf != NULL)
824
 
        {
825
 
          uLongf tmp_complen= complen;
826
 
          int error= uncompress((Bytef*) compbuf, &tmp_complen,
827
 
                                (Bytef*) (net->buff + net->where_b),
828
 
                                (uLong)packet_len);
829
 
          complen= tmp_complen;
830
 
 
831
 
          if (error != Z_OK)
832
 
          {
833
 
            net->error= 2;            /* caller will close socket */
834
 
            net->last_errno= CR_NET_UNCOMPRESS_ERROR;
835
 
          }
836
 
          else
837
 
          {
838
 
            memcpy((net->buff + net->where_b), compbuf, complen);
839
 
          }
840
 
          free(compbuf);
841
 
        }
842
 
      }
843
 
      else
844
 
        complen= packet_len;
845
 
 
846
 
    }
847
 
    buf_length+= complen;
848
 
 
849
 
    net->read_pos=      net->buff+ first_packet_offset + NET_HEADER_SIZE;
850
 
    net->buf_length=    buf_length;
851
 
    net->remain_in_buf= (uint32_t) (buf_length - start_of_packet);
852
 
    len = ((uint32_t) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE -
853
 
           multi_byte_packet);
854
 
    net->save_char= net->read_pos[len];    /* Must be saved */
855
 
    net->read_pos[len]=0;        /* Safeguard for drizzleclient_use_result */
856
 
  }
857
 
  return len;
858
 
  }
859
 
 
860
 
 
861
 
void drizzleclient_net_set_read_timeout(NET *net, uint32_t timeout)
862
 
{
863
 
  net->read_timeout= timeout;
864
 
#ifndef __sun
865
 
  if (net->vio)
866
 
    drizzleclient_vio_timeout(net->vio, 0, timeout);
867
 
#endif
868
 
  return;
869
 
}
870
 
 
871
 
 
872
 
void drizzleclient_net_set_write_timeout(NET *net, uint32_t timeout)
873
 
{
874
 
  net->write_timeout= timeout;
875
 
#ifndef __sun
876
 
  if (net->vio)
877
 
    drizzleclient_vio_timeout(net->vio, 1, timeout);
878
 
#endif
879
 
  return;
880
 
}
881
 
/**
882
 
  Clear possible error state of struct NET
883
 
 
884
 
  @param net  clear the state of the argument
885
 
*/
886
 
 
887
 
void drizzleclient_drizzleclient_net_clear_error(NET *net)
888
 
{
889
 
  net->last_errno= 0;
890
 
  net->last_error[0]= '\0';
891
 
  strcpy(net->sqlstate, not_error_sqlstate);
892
 
}
893
 
 
894
 
} /* namespace drizzle_protocol */