~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/oldlibdrizzle/net_serv.cc

pandora-build v0.42 - Started splitting out plugin system into pandora-build

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