~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/oldlibdrizzle/net_serv.cc

  • Committer: Monty Taylor
  • Date: 2009-04-25 19:24:49 UTC
  • mto: (997.2.5 mordred)
  • mto: This revision was merged to the branch mainline in revision 1003.
  • Revision ID: mordred@inaugust.com-20090425192449-0htujbt2r9jzupn5
Moved heap.

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