~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to libdrizzleclient/net_serv.cc

Merged Padraig.

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