~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/mysql_protocol/net_serv.cc

  • Committer: Eric Day
  • Date: 2009-11-10 21:50:22 UTC
  • mto: This revision was merged to the branch mainline in revision 1218.
  • Revision ID: eday@oddments.org-20091110215022-0b2nqmurv7b2l6wo
Duplicated oldlibdrizzle module, one for Drizzle protocol and one for MySQL, per Brian's request from merge proposal. Port options are now --drizzle-protocol-port and --mysql-protocol-port.

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