~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/mysql_protocol/net_serv.cc

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

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