~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/oldlibdrizzle/net_serv.cc

  • Committer: Monty Taylor
  • Date: 2009-10-06 19:40:45 UTC
  • mto: This revision was merged to the branch mainline in revision 1184.
  • Revision ID: mordred@inaugust.com-20091006194045-ojptaq2sx6ck6q63
No more server_includes.h in headers.

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
  net->max_packet_size= max(global_system_variables.net_buffer_length,
 
59
                             global_system_variables.max_allowed_packet);
 
60
}
 
61
 
 
62
/** Init with packet info. */
 
63
 
 
64
bool drizzleclient_net_init(NET *net, Vio* vio)
 
65
{
 
66
  net->vio = vio;
 
67
  drizzleclient_net_local_init(net);            /* Set some limits */
 
68
  if (!(net->buff=(unsigned char*) malloc((size_t) net->max_packet+
 
69
                                          NET_HEADER_SIZE + COMP_HEADER_SIZE)))
 
70
    return(1);
 
71
  net->buff_end=net->buff+net->max_packet;
 
72
  net->error=0; net->return_status=0;
 
73
  net->pkt_nr=net->compress_pkt_nr=0;
 
74
  net->write_pos=net->read_pos = net->buff;
 
75
  net->last_error[0]=0;
 
76
  net->compress=0; net->reading_or_writing=0;
 
77
  net->where_b = net->remain_in_buf=0;
 
78
  net->last_errno=0;
 
79
  net->unused= 0;
 
80
 
 
81
  if (vio != 0)                    /* If real connection */
 
82
  {
 
83
    net->fd  = drizzleclient_vio_fd(vio);            /* For perl DBI/DBD */
 
84
    drizzleclient_vio_fastsend(vio);
 
85
  }
 
86
  return(0);
 
87
}
 
88
 
 
89
bool drizzleclient_net_init_sock(NET * net, int sock, int flags)
 
90
{
 
91
 
 
92
  Vio *drizzleclient_vio_tmp= drizzleclient_vio_new(sock, VIO_TYPE_TCPIP, flags);
 
93
  if (drizzleclient_vio_tmp == NULL)
 
94
    return true;
 
95
  else
 
96
    if (drizzleclient_net_init(net, drizzleclient_vio_tmp))
 
97
    {
 
98
      /* Only delete the temporary vio if we didn't already attach it to the
 
99
       * NET object.
 
100
       */
 
101
      if (drizzleclient_vio_tmp && (net->vio != drizzleclient_vio_tmp))
 
102
        drizzleclient_vio_delete(drizzleclient_vio_tmp);
 
103
      else
 
104
      {
 
105
        (void) shutdown(sock, SHUT_RDWR);
 
106
        (void) close(sock);
 
107
      }
 
108
      return true;
 
109
    }
 
110
  return false;
 
111
}
 
112
 
 
113
void drizzleclient_net_end(NET *net)
 
114
{
 
115
  if (net->buff != NULL)
 
116
    free(net->buff);
 
117
  net->buff= NULL;
 
118
  return;
 
119
}
 
120
 
 
121
void drizzleclient_net_close(NET *net)
 
122
{
 
123
  if (net->vio != NULL)
 
124
  {
 
125
    drizzleclient_vio_delete(net->vio);
 
126
    net->vio= 0;
 
127
  }
 
128
}
 
129
 
 
130
bool drizzleclient_net_peer_addr(NET *net, char *buf, uint16_t *port, size_t buflen)
 
131
{
 
132
  return drizzleclient_vio_peer_addr(net->vio, buf, port, buflen);
 
133
}
 
134
 
 
135
void drizzleclient_net_keepalive(NET *net, bool flag)
 
136
{
 
137
  drizzleclient_vio_keepalive(net->vio, flag);
 
138
}
 
139
 
 
140
int drizzleclient_net_get_sd(NET *net)
 
141
{
 
142
  return net->vio->sd;
 
143
}
 
144
 
 
145
bool drizzleclient_net_should_close(NET *net)
 
146
{
 
147
  return net->error || (net->vio == 0);
 
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
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
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
      const bool interrupted= drizzleclient_vio_should_retry(net->vio);
 
537
      /*
 
538
        If we read 0, or we were interrupted this means that
 
539
        we need to switch to blocking mode and wait until the timeout
 
540
        on the socket kicks in.
 
541
      */
 
542
      if ((interrupted || length == 0))
 
543
      {
 
544
        bool old_mode;
 
545
 
 
546
        while (drizzleclient_vio_blocking(net->vio, true, &old_mode) < 0)
 
547
        {
 
548
          if (drizzleclient_vio_should_retry(net->vio) && retry_count++ < net->retry_count)
 
549
            continue;
 
550
          net->error= 2;                     /* Close socket */
 
551
          net->last_errno= CR_NET_PACKET_TOO_LARGE;
 
552
          goto end;
 
553
        }
 
554
        retry_count=0;
 
555
        continue;
 
556
      }
 
557
      else
 
558
      {
 
559
        if (retry_count++ < net->retry_count)
 
560
          continue;
 
561
      }
 
562
 
 
563
      if (drizzleclient_vio_errno(net->vio) == EINTR)
 
564
      {
 
565
        continue;
 
566
      }
 
567
      net->error= 2;                /* Close socket */
 
568
      net->last_errno= (interrupted ? CR_NET_WRITE_INTERRUPTED :
 
569
                        CR_NET_ERROR_ON_WRITE);
 
570
      break;
 
571
    }
 
572
    pos+=length;
 
573
  }
 
574
end:
 
575
  if ((net->compress) && (packet != NULL))
 
576
    free((char*) packet);
 
577
  net->reading_or_writing=0;
 
578
 
 
579
  return(((int) (pos != end)));
 
580
}
 
581
 
 
582
 
 
583
/**
 
584
   Reads one packet to net->buff + net->where_b.
 
585
   Long packets are handled by drizzleclient_net_read().
 
586
   This function reallocates the net->buff buffer if necessary.
 
587
 
 
588
   @return
 
589
   Returns length of packet.
 
590
*/
 
591
 
 
592
static uint32_t
 
593
my_real_read(NET *net, size_t *complen)
 
594
{
 
595
  unsigned char *pos;
 
596
  size_t length;
 
597
  uint32_t i,retry_count=0;
 
598
  size_t len=packet_error;
 
599
  uint32_t remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
 
600
                    NET_HEADER_SIZE);
 
601
 
 
602
  *complen = 0;
 
603
 
 
604
  net->reading_or_writing= 1;
 
605
  /* Read timeout is set in drizzleclient_net_set_read_timeout */
 
606
 
 
607
  pos = net->buff + net->where_b;        /* net->packet -4 */
 
608
 
 
609
  for (i= 0; i < 2 ; i++)
 
610
  {
 
611
    while (remain > 0)
 
612
    {
 
613
      /* First read is done with non blocking mode */
 
614
      if ((long) (length= drizzleclient_vio_read(net->vio, pos, remain)) <= 0L)
 
615
      {
 
616
        const bool interrupted = drizzleclient_vio_should_retry(net->vio);
 
617
 
 
618
        if (interrupted)
 
619
        {                    /* Probably in MIT threads */
 
620
          if (retry_count++ < net->retry_count)
 
621
            continue;
 
622
        }
 
623
        if (drizzleclient_vio_errno(net->vio) == EINTR)
 
624
        {
 
625
          continue;
 
626
        }
 
627
        len= packet_error;
 
628
        net->error= 2;                /* Close socket */
 
629
        net->last_errno= (drizzleclient_vio_was_interrupted(net->vio) ?
 
630
                          CR_NET_READ_INTERRUPTED :
 
631
                          CR_NET_READ_ERROR);
 
632
        ER(net->last_errno);
 
633
        goto end;
 
634
      }
 
635
      remain -= (uint32_t) length;
 
636
      pos+= length;
 
637
    }
 
638
    if (i == 0)
 
639
    {                    /* First parts is packet length */
 
640
      uint32_t helping;
 
641
 
 
642
      if (net->buff[net->where_b + 3] != (unsigned char) net->pkt_nr)
 
643
      {
 
644
        len= packet_error;
 
645
        /* Not a NET error on the client. XXX: why? */
 
646
        goto end;
 
647
      }
 
648
      net->compress_pkt_nr= ++net->pkt_nr;
 
649
      if (net->compress)
 
650
      {
 
651
        /*
 
652
          If the packet is compressed then complen > 0 and contains the
 
653
          number of bytes in the uncompressed packet
 
654
        */
 
655
        *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
 
656
      }
 
657
 
 
658
      len=uint3korr(net->buff+net->where_b);
 
659
      if (!len)                /* End of big multi-packet */
 
660
        goto end;
 
661
      helping = max(len,*complen) + net->where_b;
 
662
      /* The necessary size of net->buff */
 
663
      if (helping >= net->max_packet)
 
664
      {
 
665
        if (drizzleclient_net_realloc(net,helping))
 
666
        {
 
667
          len= packet_error;          /* Return error and close connection */
 
668
          goto end;
 
669
        }
 
670
      }
 
671
      pos=net->buff + net->where_b;
 
672
      remain = (uint32_t) len;
 
673
    }
 
674
  }
 
675
 
 
676
end:
 
677
  net->reading_or_writing= 0;
 
678
 
 
679
  return(len);
 
680
}
 
681
 
 
682
 
 
683
/**
 
684
   Read a packet from the client/server and return it without the internal
 
685
   package header.
 
686
 
 
687
   If the packet is the first packet of a multi-packet packet
 
688
   (which is indicated by the length of the packet = 0xffffff) then
 
689
   all sub packets are read and concatenated.
 
690
 
 
691
   If the packet was compressed, its uncompressed and the length of the
 
692
   uncompressed packet is returned.
 
693
 
 
694
   @return
 
695
   The function returns the length of the found packet or packet_error.
 
696
   net->read_pos points to the read data.
 
697
*/
 
698
 
 
699
uint32_t
 
700
drizzleclient_net_read(NET *net)
 
701
{
 
702
  size_t len, complen;
 
703
 
 
704
  if (!net->compress)
 
705
  {
 
706
    len = my_real_read(net,&complen);
 
707
    if (len == MAX_PACKET_LENGTH)
 
708
    {
 
709
      /* First packet of a multi-packet.  Concatenate the packets */
 
710
      uint32_t save_pos = net->where_b;
 
711
      size_t total_length= 0;
 
712
      do
 
713
      {
 
714
        net->where_b += len;
 
715
        total_length += len;
 
716
        len = my_real_read(net,&complen);
 
717
      } while (len == MAX_PACKET_LENGTH);
 
718
      if (len != packet_error)
 
719
        len+= total_length;
 
720
      net->where_b = save_pos;
 
721
    }
 
722
    net->read_pos = net->buff + net->where_b;
 
723
    if (len != packet_error)
 
724
      net->read_pos[len]=0;        /* Safeguard for drizzleclient_use_result */
 
725
    return len;
 
726
  }
 
727
  else
 
728
  {
 
729
    /* We are using the compressed protocol */
 
730
 
 
731
    uint32_t buf_length;
 
732
    uint32_t start_of_packet;
 
733
    uint32_t first_packet_offset;
 
734
    uint32_t read_length, multi_byte_packet=0;
 
735
 
 
736
    if (net->remain_in_buf)
 
737
    {
 
738
      buf_length= net->buf_length;        /* Data left in old packet */
 
739
      first_packet_offset= start_of_packet= (net->buf_length -
 
740
                                             net->remain_in_buf);
 
741
      /* Restore the character that was overwritten by the end 0 */
 
742
      net->buff[start_of_packet]= net->save_char;
 
743
    }
 
744
    else
 
745
    {
 
746
      /* reuse buffer, as there is nothing in it that we need */
 
747
      buf_length= start_of_packet= first_packet_offset= 0;
 
748
    }
 
749
    for (;;)
 
750
    {
 
751
      uint32_t packet_len;
 
752
 
 
753
      if (buf_length - start_of_packet >= NET_HEADER_SIZE)
 
754
      {
 
755
        read_length = uint3korr(net->buff+start_of_packet);
 
756
        if (!read_length)
 
757
        {
 
758
          /* End of multi-byte packet */
 
759
          start_of_packet += NET_HEADER_SIZE;
 
760
          break;
 
761
        }
 
762
        if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet)
 
763
        {
 
764
          if (multi_byte_packet)
 
765
          {
 
766
            /* Remove packet header for second packet */
 
767
            memmove(net->buff + first_packet_offset + start_of_packet,
 
768
                    net->buff + first_packet_offset + start_of_packet +
 
769
                    NET_HEADER_SIZE,
 
770
                    buf_length - start_of_packet);
 
771
            start_of_packet += read_length;
 
772
            buf_length -= NET_HEADER_SIZE;
 
773
          }
 
774
          else
 
775
            start_of_packet+= read_length + NET_HEADER_SIZE;
 
776
 
 
777
          if (read_length != MAX_PACKET_LENGTH)    /* last package */
 
778
          {
 
779
            multi_byte_packet= 0;        /* No last zero len packet */
 
780
            break;
 
781
          }
 
782
          multi_byte_packet= NET_HEADER_SIZE;
 
783
          /* Move data down to read next data packet after current one */
 
784
          if (first_packet_offset)
 
785
          {
 
786
            memmove(net->buff,net->buff+first_packet_offset,
 
787
                    buf_length-first_packet_offset);
 
788
            buf_length-=first_packet_offset;
 
789
            start_of_packet -= first_packet_offset;
 
790
            first_packet_offset=0;
 
791
          }
 
792
          continue;
 
793
        }
 
794
      }
 
795
      /* Move data down to read next data packet after current one */
 
796
      if (first_packet_offset)
 
797
      {
 
798
        memmove(net->buff,net->buff+first_packet_offset,
 
799
                buf_length-first_packet_offset);
 
800
        buf_length-=first_packet_offset;
 
801
        start_of_packet -= first_packet_offset;
 
802
        first_packet_offset=0;
 
803
      }
 
804
 
 
805
      net->where_b=buf_length;
 
806
      if ((packet_len = my_real_read(net,&complen)) == packet_error)
 
807
        return packet_error;
 
808
 
 
809
      if (complen)
 
810
      {
 
811
        unsigned char * compbuf= (unsigned char *) malloc(complen);
 
812
        if (compbuf != NULL)
 
813
        {
 
814
          uLongf tmp_complen= complen;
 
815
          int error= uncompress((Bytef*) compbuf, &tmp_complen,
 
816
                                (Bytef*) (net->buff + net->where_b),
 
817
                                (uLong)packet_len);
 
818
          complen= tmp_complen;
 
819
 
 
820
          if (error != Z_OK)
 
821
          {
 
822
            net->error= 2;            /* caller will close socket */
 
823
            net->last_errno= CR_NET_UNCOMPRESS_ERROR;
 
824
          }
 
825
          else
 
826
          {
 
827
            memcpy((net->buff + net->where_b), compbuf, complen);
 
828
          }
 
829
          free(compbuf);
 
830
        }
 
831
      }
 
832
      else
 
833
        complen= packet_len;
 
834
 
 
835
    }
 
836
    buf_length+= complen;
 
837
 
 
838
    net->read_pos=      net->buff+ first_packet_offset + NET_HEADER_SIZE;
 
839
    net->buf_length=    buf_length;
 
840
    net->remain_in_buf= (uint32_t) (buf_length - start_of_packet);
 
841
    len = ((uint32_t) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE -
 
842
           multi_byte_packet);
 
843
    net->save_char= net->read_pos[len];    /* Must be saved */
 
844
    net->read_pos[len]=0;        /* Safeguard for drizzleclient_use_result */
 
845
  }
 
846
  return len;
 
847
  }
 
848
 
 
849
 
 
850
void drizzleclient_net_set_read_timeout(NET *net, uint32_t timeout)
 
851
{
 
852
  net->read_timeout= timeout;
 
853
#ifndef __sun
 
854
  if (net->vio)
 
855
    drizzleclient_vio_timeout(net->vio, 0, timeout);
 
856
#endif
 
857
  return;
 
858
}
 
859
 
 
860
 
 
861
void drizzleclient_net_set_write_timeout(NET *net, uint32_t timeout)
 
862
{
 
863
  net->write_timeout= timeout;
 
864
#ifndef __sun
 
865
  if (net->vio)
 
866
    drizzleclient_vio_timeout(net->vio, 1, timeout);
 
867
#endif
 
868
  return;
 
869
}
 
870
/**
 
871
  Clear possible error state of struct NET
 
872
 
 
873
  @param net  clear the state of the argument
 
874
*/
 
875
 
 
876
void drizzleclient_drizzleclient_net_clear_error(NET *net)
 
877
{
 
878
  net->last_errno= 0;
 
879
  net->last_error[0]= '\0';
 
880
  strcpy(net->sqlstate, drizzleclient_sqlstate_get_not_error());
 
881
}
 
882