~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
/*
17
  HFTODO this must be hidden if we don't want client capabilities in 
18
  embedded library
19
 */
212.5.39 by Monty Taylor
Phew. Moved my_base and my_global.
20
#include <drizzled/global.h>
77.1.39 by Monty Taylor
More mysql->drizzle renaming.
21
#include <drizzle.h>
212.5.42 by Monty Taylor
Ding dong include is dead.
22
#include <drizzled/error.h>
212.5.39 by Monty Taylor
Phew. Moved my_base and my_global.
23
#include <mysys/my_sys.h>
212.5.18 by Monty Taylor
Moved m_ctype, m_string and my_bitmap. Removed t_ctype.
24
#include <mystrings/m_string.h>
212.5.45 by Monty Taylor
Removed excess AM_CPPFLAGS from the tree. Now the only thing that should be in the include path should be -I${top_srcdir} and -I${top_builddir}w
25
#include <vio/violite.h>
1 by brian
clean slate
26
#include <signal.h>
27
#include <errno.h>
212.5.30 by Monty Taylor
Removed my_net.h. Pointless.
28
#include <sys/poll.h>
1 by brian
clean slate
29
30
/*
31
  The following handles the differences when this is linked between the
32
  client and the server.
33
34
  This gives an error if a too big packet is found
35
  The server can change this with the -O switch, but because the client
36
  can't normally do this the client should have a bigger max_allowed_packet.
37
*/
38
39
40
#define DONT_USE_THR_ALARM
41
212.5.45 by Monty Taylor
Removed excess AM_CPPFLAGS from the tree. Now the only thing that should be in the include path should be -I${top_srcdir} and -I${top_builddir}w
42
#include <mysys/thr_alarm.h>
1 by brian
clean slate
43
44
45
#define update_statistics(A)
46
#define thd_increment_bytes_sent(N)
47
48
#define TEST_BLOCKING		8
49
#define MAX_PACKET_LENGTH (256L*256L*256L-1)
50
164 by Brian Aker
Commit cleanup of export types.
51
static bool net_write_buff(NET *net, const unsigned char *packet, uint32_t len);
1 by brian
clean slate
52
53
54
/** Init with packet info. */
55
164 by Brian Aker
Commit cleanup of export types.
56
bool my_net_init(NET *net, Vio* vio)
1 by brian
clean slate
57
{
58
  net->vio = vio;
59
  my_net_local_init(net);			/* Set some limits */
60
  if (!(net->buff=(uchar*) my_malloc((size_t) net->max_packet+
61
				     NET_HEADER_SIZE + COMP_HEADER_SIZE,
62
				     MYF(MY_WME))))
51.3.6 by Jay Pipes
Removal of DBUG from libdrizzle/ - Round 2
63
    return(1);
1 by brian
clean slate
64
  net->buff_end=net->buff+net->max_packet;
65
  net->error=0; net->return_status=0;
66
  net->pkt_nr=net->compress_pkt_nr=0;
67
  net->write_pos=net->read_pos = net->buff;
68
  net->last_error[0]=0;
69
  net->compress=0; net->reading_or_writing=0;
70
  net->where_b = net->remain_in_buf=0;
71
  net->last_errno=0;
72
  net->unused= 0;
73
74
  if (vio != 0)					/* If real connection */
75
  {
76
    net->fd  = vio_fd(vio);			/* For perl DBI/DBD */
77
    vio_fastsend(vio);
78
  }
51.3.6 by Jay Pipes
Removal of DBUG from libdrizzle/ - Round 2
79
  return(0);
1 by brian
clean slate
80
}
81
82
83
void net_end(NET *net)
84
{
85
  my_free(net->buff,MYF(MY_ALLOW_ZERO_PTR));
86
  net->buff=0;
51.3.6 by Jay Pipes
Removal of DBUG from libdrizzle/ - Round 2
87
  return;
1 by brian
clean slate
88
}
89
90
91
/** Realloc the packet buffer. */
92
164 by Brian Aker
Commit cleanup of export types.
93
bool net_realloc(NET *net, size_t length)
1 by brian
clean slate
94
{
95
  uchar *buff;
96
  size_t pkt_length;
97
98
  if (length >= net->max_packet_size)
99
  {
100
    /* @todo: 1 and 2 codes are identical. */
101
    net->error= 1;
102
    net->last_errno= ER_NET_PACKET_TOO_LARGE;
51.3.6 by Jay Pipes
Removal of DBUG from libdrizzle/ - Round 2
103
    return(1);
1 by brian
clean slate
104
  }
105
  pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1); 
106
  /*
107
    We must allocate some extra bytes for the end 0 and to be able to
108
    read big compressed blocks
109
  */
110
  if (!(buff= (uchar*) my_realloc((char*) net->buff, pkt_length +
111
                                  NET_HEADER_SIZE + COMP_HEADER_SIZE,
112
                                  MYF(MY_WME))))
113
  {
114
    /* @todo: 1 and 2 codes are identical. */
115
    net->error= 1;
116
    net->last_errno= ER_OUT_OF_RESOURCES;
117
    /* In the server the error is reported by MY_WME flag. */
51.3.6 by Jay Pipes
Removal of DBUG from libdrizzle/ - Round 2
118
    return(1);
1 by brian
clean slate
119
  }
120
  net->buff=net->write_pos=buff;
294 by Brian Aker
libdrizzle has ulong removed.
121
  net->buff_end=buff+(net->max_packet= (uint32_t) pkt_length);
51.3.6 by Jay Pipes
Removal of DBUG from libdrizzle/ - Round 2
122
  return(0);
1 by brian
clean slate
123
}
124
125
126
/**
127
  Check if there is any data to be read from the socket.
128
129
  @param sd   socket descriptor
130
131
  @retval
132
    0  No data to read
133
  @retval
134
    1  Data or EOF to read
135
  @retval
136
    -1   Don't know if data is ready or not
137
*/
138
266.7.8 by Andy Lester
const happy
139
static bool net_data_is_ready(int sd)
1 by brian
clean slate
140
{
141
  struct pollfd ufds;
142
  int res;
143
144
  ufds.fd= sd;
145
  ufds.events= POLLIN | POLLPRI;
146
  if (!(res= poll(&ufds, 1, 0)))
147
    return 0;
148
  if (res < 0 || !(ufds.revents & (POLLIN | POLLPRI)))
149
    return 0;
150
  return 1;
151
}
152
153
/**
154
  Remove unwanted characters from connection
155
  and check if disconnected.
156
157
    Read from socket until there is nothing more to read. Discard
158
    what is read.
159
160
    If there is anything when to read 'net_clear' is called this
161
    normally indicates an error in the protocol.
162
163
    When connection is properly closed (for TCP it means with
164
    a FIN packet), then select() considers a socket "ready to read",
165
    in the sense that there's EOF to read, but read() returns 0.
166
167
  @param net			NET handler
168
  @param clear_buffer           if <> 0, then clear all data from comm buff
169
*/
170
164 by Brian Aker
Commit cleanup of export types.
171
void net_clear(NET *net, bool clear_buffer)
1 by brian
clean slate
172
{
173
  if (clear_buffer)
174
  {
266.7.8 by Andy Lester
const happy
175
    while (net_data_is_ready(net->vio->sd) > 0)
1 by brian
clean slate
176
    {
177
      /* The socket is ready */
266.7.8 by Andy Lester
const happy
178
      if (vio_read(net->vio, net->buff,
179
                                  (size_t) net->max_packet) <= 0)
51.3.6 by Jay Pipes
Removal of DBUG from libdrizzle/ - Round 2
180
      {
1 by brian
clean slate
181
        net->error= 2;
182
        break;
183
      }
184
    }
185
  }
186
  net->pkt_nr=net->compress_pkt_nr=0;		/* Ready for new command */
187
  net->write_pos=net->buff;
51.3.6 by Jay Pipes
Removal of DBUG from libdrizzle/ - Round 2
188
  return;
1 by brian
clean slate
189
}
190
191
192
/** Flush write_buffer if not empty. */
193
164 by Brian Aker
Commit cleanup of export types.
194
bool net_flush(NET *net)
1 by brian
clean slate
195
{
277 by Brian Aker
Cleanup of my_bool from extra and libdrizzle
196
  bool error= 0;
1 by brian
clean slate
197
  if (net->buff != net->write_pos)
198
  {
199
    error=test(net_real_write(net, net->buff,
200
			      (size_t) (net->write_pos - net->buff)));
201
    net->write_pos=net->buff;
202
  }
203
  /* Sync packet number if using compression */
204
  if (net->compress)
205
    net->pkt_nr=net->compress_pkt_nr;
51.3.6 by Jay Pipes
Removal of DBUG from libdrizzle/ - Round 2
206
  return(error);
1 by brian
clean slate
207
}
208
209
210
/*****************************************************************************
211
** Write something to server/client buffer
212
*****************************************************************************/
213
214
/**
215
  Write a logical packet with packet header.
216
217
  Format: Packet length (3 bytes), packet number(1 byte)
218
  When compression is used a 3 byte compression length is added
219
220
  @note
221
    If compression is used the original package is modified!
222
*/
223
164 by Brian Aker
Commit cleanup of export types.
224
bool
1 by brian
clean slate
225
my_net_write(NET *net,const uchar *packet,size_t len)
226
{
227
  uchar buff[NET_HEADER_SIZE];
228
  if (unlikely(!net->vio)) /* nowhere to write */
229
    return 0;
230
  /*
231
    Big packets are handled by splitting them in packets of MAX_PACKET_LENGTH
232
    length. The last packet is always a packet that is < MAX_PACKET_LENGTH.
233
    (The last packet may even have a length of 0)
234
  */
235
  while (len >= MAX_PACKET_LENGTH)
236
  {
294 by Brian Aker
libdrizzle has ulong removed.
237
    const uint32_t z_size = MAX_PACKET_LENGTH;
1 by brian
clean slate
238
    int3store(buff, z_size);
239
    buff[3]= (uchar) net->pkt_nr++;
240
    if (net_write_buff(net, buff, NET_HEADER_SIZE) ||
241
	net_write_buff(net, packet, z_size))
242
      return 1;
243
    packet += z_size;
244
    len-=     z_size;
245
  }
246
  /* Write last packet */
247
  int3store(buff,len);
248
  buff[3]= (uchar) net->pkt_nr++;
249
  if (net_write_buff(net, buff, NET_HEADER_SIZE))
250
    return 1;
251
  return test(net_write_buff(net,packet,len));
252
}
253
254
/**
255
  Send a command to the server.
256
206.3.1 by Patrick Galbraith
Most everything working with client rename
257
    The reason for having both header and packet is so that libdrizzle
1 by brian
clean slate
258
    can easy add a header to a special command (like prepared statements)
259
    without having to re-alloc the string.
260
261
    As the command is part of the first data packet, we have to do some data
262
    juggling to put the command in there, without having to create a new
263
    packet.
264
  
265
    This function will split big packets into sub-packets if needed.
266
    (Each sub packet can only be 2^24 bytes)
267
268
  @param net		NET handler
269
  @param command	Command in MySQL server (enum enum_server_command)
270
  @param header	Header to write after command
271
  @param head_len	Length of header
272
  @param packet	Query or parameter to query
273
  @param len		Length of packet
274
275
  @retval
276
    0	ok
277
  @retval
278
    1	error
279
*/
280
164 by Brian Aker
Commit cleanup of export types.
281
bool
1 by brian
clean slate
282
net_write_command(NET *net,uchar command,
283
		  const uchar *header, size_t head_len,
284
		  const uchar *packet, size_t len)
285
{
294 by Brian Aker
libdrizzle has ulong removed.
286
  uint32_t length=len+1+head_len;			/* 1 extra byte for command */
1 by brian
clean slate
287
  uchar buff[NET_HEADER_SIZE+1];
288
  uint header_size=NET_HEADER_SIZE+1;
289
290
  buff[4]=command;				/* For first packet */
291
292
  if (length >= MAX_PACKET_LENGTH)
293
  {
294
    /* Take into account that we have the command in the first header */
295
    len= MAX_PACKET_LENGTH - 1 - head_len;
296
    do
297
    {
298
      int3store(buff, MAX_PACKET_LENGTH);
299
      buff[3]= (uchar) net->pkt_nr++;
300
      if (net_write_buff(net, buff, header_size) ||
301
	  net_write_buff(net, header, head_len) ||
302
	  net_write_buff(net, packet, len))
51.3.6 by Jay Pipes
Removal of DBUG from libdrizzle/ - Round 2
303
	return(1);
1 by brian
clean slate
304
      packet+= len;
305
      length-= MAX_PACKET_LENGTH;
306
      len= MAX_PACKET_LENGTH;
307
      head_len= 0;
308
      header_size= NET_HEADER_SIZE;
309
    } while (length >= MAX_PACKET_LENGTH);
310
    len=length;					/* Data left to be written */
311
  }
312
  int3store(buff,length);
313
  buff[3]= (uchar) net->pkt_nr++;
51.3.6 by Jay Pipes
Removal of DBUG from libdrizzle/ - Round 2
314
  return(test(net_write_buff(net, buff, header_size) ||
1 by brian
clean slate
315
                   (head_len && net_write_buff(net, header, head_len)) ||
316
                   net_write_buff(net, packet, len) || net_flush(net)));
317
}
318
319
/**
320
  Caching the data in a local buffer before sending it.
321
322
   Fill up net->buffer and send it to the client when full.
323
324
    If the rest of the to-be-sent-packet is bigger than buffer,
325
    send it in one big block (to avoid copying to internal buffer).
326
    If not, copy the rest of the data to the buffer and return without
327
    sending data.
328
329
  @param net		Network handler
330
  @param packet	Packet to send
331
  @param len		Length of packet
332
333
  @note
334
    The cached buffer can be sent as it is with 'net_flush()'.
335
    In this code we have to be careful to not send a packet longer than
336
    MAX_PACKET_LENGTH to net_real_write() if we are using the compressed
337
    protocol as we store the length of the compressed packet in 3 bytes.
338
339
  @retval
340
    0	ok
341
  @retval
342
    1
343
*/
344
164 by Brian Aker
Commit cleanup of export types.
345
static bool
346
net_write_buff(NET *net, const unsigned char *packet, uint32_t len)
1 by brian
clean slate
347
{
294 by Brian Aker
libdrizzle has ulong removed.
348
  uint32_t left_length;
1 by brian
clean slate
349
  if (net->compress && net->max_packet > MAX_PACKET_LENGTH)
350
    left_length= MAX_PACKET_LENGTH - (net->write_pos - net->buff);
351
  else
294 by Brian Aker
libdrizzle has ulong removed.
352
    left_length= (uint32_t) (net->buff_end - net->write_pos);
1 by brian
clean slate
353
354
  if (len > left_length)
355
  {
356
    if (net->write_pos != net->buff)
357
    {
358
      /* Fill up already used packet and write it */
212.6.16 by Mats Kindahl
Removing redundant use of casts in libdrizzle/ for memcmp(), memcpy(), memset(), and memmove().
359
      memcpy(net->write_pos,packet,left_length);
1 by brian
clean slate
360
      if (net_real_write(net, net->buff, 
361
			 (size_t) (net->write_pos - net->buff) + left_length))
362
	return 1;
363
      net->write_pos= net->buff;
364
      packet+= left_length;
365
      len-= left_length;
366
    }
367
    if (net->compress)
368
    {
369
      /*
370
	We can't have bigger packets than 16M with compression
371
	Because the uncompressed length is stored in 3 bytes
372
      */
373
      left_length= MAX_PACKET_LENGTH;
374
      while (len > left_length)
375
      {
376
	if (net_real_write(net, packet, left_length))
377
	  return 1;
378
	packet+= left_length;
379
	len-= left_length;
380
      }
381
    }
382
    if (len > net->max_packet)
383
      return net_real_write(net, packet, len) ? 1 : 0;
384
    /* Send out rest of the blocks as full sized blocks */
385
  }
212.6.16 by Mats Kindahl
Removing redundant use of casts in libdrizzle/ for memcmp(), memcpy(), memset(), and memmove().
386
  memcpy(net->write_pos,packet,len);
1 by brian
clean slate
387
  net->write_pos+= len;
388
  return 0;
389
}
390
391
392
/**
393
  Read and write one packet using timeouts.
394
  If needed, the packet is compressed before sending.
395
396
  @todo
397
    - TODO is it needed to set this variable if we have no socket
398
*/
399
174 by Brian Aker
Removed alarm timeouts on writes.
400
/*
401
  TODO: rewrite this in a manner to do non-block writes. If a write can not be made, and we are
402
  in the server, yield to another process and come back later.
403
*/
1 by brian
clean slate
404
int
405
net_real_write(NET *net,const uchar *packet, size_t len)
406
{
407
  size_t length;
408
  const uchar *pos,*end;
174 by Brian Aker
Removed alarm timeouts on writes.
409
  uint retry_count= 0;
1 by brian
clean slate
410
178 by Brian Aker
Set timeouts for writes as well.
411
  /* Backup of the original SO_RCVTIMEO timeout */
412
  struct timeval backtime;
413
  int error;
414
1 by brian
clean slate
415
  if (net->error == 2)
51.3.6 by Jay Pipes
Removal of DBUG from libdrizzle/ - Round 2
416
    return(-1);				/* socket can't be used */
1 by brian
clean slate
417
418
  net->reading_or_writing=2;
419
  if (net->compress)
420
  {
421
    size_t complen;
422
    uchar *b;
266.7.8 by Andy Lester
const happy
423
    const uint header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
1 by brian
clean slate
424
    if (!(b= (uchar*) my_malloc(len + NET_HEADER_SIZE +
425
                                COMP_HEADER_SIZE, MYF(MY_WME))))
426
    {
427
      net->error= 2;
428
      net->last_errno= ER_OUT_OF_RESOURCES;
429
      /* In the server, the error is reported by MY_WME flag. */
430
      net->reading_or_writing= 0;
51.3.6 by Jay Pipes
Removal of DBUG from libdrizzle/ - Round 2
431
      return(1);
1 by brian
clean slate
432
    }
433
    memcpy(b+header_length,packet,len);
434
435
    if (my_compress(b+header_length, &len, &complen))
436
      complen=0;
437
    int3store(&b[NET_HEADER_SIZE],complen);
438
    int3store(b,len);
439
    b[3]=(uchar) (net->compress_pkt_nr++);
440
    len+= header_length;
441
    packet= b;
442
  }
443
178 by Brian Aker
Set timeouts for writes as well.
444
  /* Check for error, currently assert */
445
  if (net->write_timeout)
446
  {
447
    struct timeval waittime;
448
    socklen_t length;
449
450
    waittime.tv_sec= net->write_timeout;
451
    waittime.tv_usec= 0;
452
453
    memset(&backtime, 0, sizeof(struct timeval));
454
    length= sizeof(struct timeval);
455
    error= getsockopt(net->vio->sd, SOL_SOCKET, SO_RCVTIMEO, 
456
                      &backtime, &length);
457
    if (error != 0)
458
    {
459
      perror("getsockopt");
460
      assert(error == 0);
461
    }
462
    error= setsockopt(net->vio->sd, SOL_SOCKET, SO_RCVTIMEO, 
463
                      &waittime, (socklen_t)sizeof(struct timeval));
464
    assert(error == 0);
465
  }
1 by brian
clean slate
466
  pos= packet;
467
  end=pos+len;
174 by Brian Aker
Removed alarm timeouts on writes.
468
  /* Loop until we have read everything */
1 by brian
clean slate
469
  while (pos != end)
470
  {
471
    if ((long) (length= vio_write(net->vio,pos,(size_t) (end-pos))) <= 0)
472
    {
266.7.8 by Andy Lester
const happy
473
      const bool interrupted= vio_should_retry(net->vio);
174 by Brian Aker
Removed alarm timeouts on writes.
474
      /* 
475
        If we read 0, or we were interrupted this means that 
476
        we need to switch to blocking mode and wait until the timeout 
477
        on the socket kicks in.
478
      */
479
      if ((interrupted || length == 0))
1 by brian
clean slate
480
      {
174 by Brian Aker
Removed alarm timeouts on writes.
481
        bool old_mode;
482
483
        while (vio_blocking(net->vio, true, &old_mode) < 0)
484
        {
485
          if (vio_should_retry(net->vio) && retry_count++ < net->retry_count)
486
            continue;
487
          net->error= 2;                     /* Close socket */
488
          net->last_errno= ER_NET_PACKET_TOO_LARGE;
489
          goto end;
490
        }
491
        retry_count=0;
492
        continue;
1 by brian
clean slate
493
      }
494
      else
495
      {
174 by Brian Aker
Removed alarm timeouts on writes.
496
        if (retry_count++ < net->retry_count)
497
          continue;
1 by brian
clean slate
498
      }
174 by Brian Aker
Removed alarm timeouts on writes.
499
      
1 by brian
clean slate
500
      if (vio_errno(net->vio) == SOCKET_EINTR)
501
      {
174 by Brian Aker
Removed alarm timeouts on writes.
502
        continue;
1 by brian
clean slate
503
      }
504
      net->error= 2;				/* Close socket */
505
      net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
174 by Brian Aker
Removed alarm timeouts on writes.
506
                        ER_NET_ERROR_ON_WRITE);
1 by brian
clean slate
507
      break;
508
    }
509
    pos+=length;
510
    update_statistics(thd_increment_bytes_sent(length));
511
  }
512
 end:
513
  if (net->compress)
514
    my_free((char*) packet,MYF(0));
515
  net->reading_or_writing=0;
174 by Brian Aker
Removed alarm timeouts on writes.
516
178 by Brian Aker
Set timeouts for writes as well.
517
  if (net->write_timeout)
518
    error= setsockopt(net->vio->sd, SOL_SOCKET, SO_RCVTIMEO, 
519
                      &backtime, (socklen_t)sizeof(struct timeval));
520
51.3.6 by Jay Pipes
Removal of DBUG from libdrizzle/ - Round 2
521
  return(((int) (pos != end)));
1 by brian
clean slate
522
}
523
524
525
/**
526
  Reads one packet to net->buff + net->where_b.
527
  Long packets are handled by my_net_read().
528
  This function reallocates the net->buff buffer if necessary.
529
530
  @return
531
    Returns length of packet.
532
*/
533
294 by Brian Aker
libdrizzle has ulong removed.
534
static uint32_t
1 by brian
clean slate
535
my_real_read(NET *net, size_t *complen)
536
{
537
  uchar *pos;
538
  size_t length;
539
  uint i,retry_count=0;
294 by Brian Aker
libdrizzle has ulong removed.
540
  uint32_t len=packet_error;
205 by Brian Aker
uint32 -> uin32_t
541
  uint32_t remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
173 by Brian Aker
Removed thd alarm around socket, we now use timeouts.
542
                  NET_HEADER_SIZE);
543
  /* Backup of the original SO_RCVTIMEO timeout */
544
  struct timeval backtime;
236.2.2 by rbradfor
Using correct coding standards for variable initialization
545
  int error= 0;
173 by Brian Aker
Removed thd alarm around socket, we now use timeouts.
546
1 by brian
clean slate
547
  *complen = 0;
548
173 by Brian Aker
Removed thd alarm around socket, we now use timeouts.
549
  net->reading_or_writing= 1;
1 by brian
clean slate
550
  /* Read timeout is set in my_net_set_read_timeout */
551
173 by Brian Aker
Removed thd alarm around socket, we now use timeouts.
552
  pos = net->buff + net->where_b;		/* net->packet -4 */
553
554
555
  /* Check for error, currently assert */
175 by Brian Aker
If a read timeout exists, then set it up, otherwise just let the blocking
556
  if (net->read_timeout)
173 by Brian Aker
Removed thd alarm around socket, we now use timeouts.
557
  {
558
    struct timeval waittime;
559
    socklen_t length;
560
561
    waittime.tv_sec= net->read_timeout;
562
    waittime.tv_usec= 0;
563
564
    memset(&backtime, 0, sizeof(struct timeval));
177 by brian
Fix for call (missed in the review the initial length setting).
565
    length= sizeof(struct timeval);
173 by Brian Aker
Removed thd alarm around socket, we now use timeouts.
566
    error= getsockopt(net->vio->sd, SOL_SOCKET, SO_RCVTIMEO, 
567
                      &backtime, &length);
177 by brian
Fix for call (missed in the review the initial length setting).
568
    if (error != 0)
569
    {
570
      perror("getsockopt");
571
      assert(error == 0);
572
    }
173 by Brian Aker
Removed thd alarm around socket, we now use timeouts.
573
    error= setsockopt(net->vio->sd, SOL_SOCKET, SO_RCVTIMEO, 
574
                      &waittime, (socklen_t)sizeof(struct timeval));
575
    assert(error == 0);
576
  }
577
578
  for (i= 0; i < 2 ; i++)
579
  {
580
    while (remain > 0)
1 by brian
clean slate
581
    {
173 by Brian Aker
Removed thd alarm around socket, we now use timeouts.
582
      /* First read is done with non blocking mode */
583
      if ((long) (length= vio_read(net->vio, pos, remain)) <= 0L)
584
      {
266.7.8 by Andy Lester
const happy
585
        const bool interrupted = vio_should_retry(net->vio);
173 by Brian Aker
Removed thd alarm around socket, we now use timeouts.
586
587
        if (interrupted)
588
        {					/* Probably in MIT threads */
589
          if (retry_count++ < net->retry_count)
590
            continue;
591
        }
592
        if (vio_errno(net->vio) == SOCKET_EINTR)
593
        {
594
          continue;
595
        }
596
        len= packet_error;
597
        net->error= 2;				/* Close socket */
598
        net->last_errno= (vio_was_interrupted(net->vio) ?
599
                          ER_NET_READ_INTERRUPTED :
600
                          ER_NET_READ_ERROR);
266.3.1 by Andrew Garner
error was not flagged if client aborted
601
        my_error(net->last_errno, MYF(0));
173 by Brian Aker
Removed thd alarm around socket, we now use timeouts.
602
        goto end;
603
      }
205 by Brian Aker
uint32 -> uin32_t
604
      remain -= (uint32_t) length;
173 by Brian Aker
Removed thd alarm around socket, we now use timeouts.
605
      pos+= length;
606
      update_statistics(thd_increment_bytes_received(length));
607
    }
608
    if (i == 0)
609
    {					/* First parts is packet length */
294 by Brian Aker
libdrizzle has ulong removed.
610
      uint32_t helping;
173 by Brian Aker
Removed thd alarm around socket, we now use timeouts.
611
612
      if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)
613
      {
614
        len= packet_error;
615
        /* Not a NET error on the client. XXX: why? */
616
        goto end;
617
      }
618
      net->compress_pkt_nr= ++net->pkt_nr;
619
      if (net->compress)
620
      {
621
        /*
622
          If the packet is compressed then complen > 0 and contains the
623
          number of bytes in the uncompressed packet
624
        */
625
        *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
626
      }
627
628
      len=uint3korr(net->buff+net->where_b);
629
      if (!len)				/* End of big multi-packet */
630
        goto end;
631
      helping = max(len,*complen) + net->where_b;
632
      /* The necessary size of net->buff */
633
      if (helping >= net->max_packet)
634
      {
635
        if (net_realloc(net,helping))
636
        {
637
          len= packet_error;          /* Return error and close connection */
638
          goto end;
639
        }
640
      }
641
      pos=net->buff + net->where_b;
205 by Brian Aker
uint32 -> uin32_t
642
      remain = (uint32_t) len;
173 by Brian Aker
Removed thd alarm around socket, we now use timeouts.
643
    }
644
  }
1 by brian
clean slate
645
646
end:
175 by Brian Aker
If a read timeout exists, then set it up, otherwise just let the blocking
647
  if  (net->read_timeout)
648
    error= setsockopt(net->vio->sd, SOL_SOCKET, SO_RCVTIMEO, 
649
                      &backtime, (socklen_t)sizeof(struct timeval));
173 by Brian Aker
Removed thd alarm around socket, we now use timeouts.
650
  assert(error == 0);
651
  net->reading_or_writing= 0;
652
1 by brian
clean slate
653
  return(len);
654
}
655
656
657
/**
658
  Read a packet from the client/server and return it without the internal
659
  package header.
660
661
  If the packet is the first packet of a multi-packet packet
662
  (which is indicated by the length of the packet = 0xffffff) then
663
  all sub packets are read and concatenated.
664
665
  If the packet was compressed, its uncompressed and the length of the
666
  uncompressed packet is returned.
667
668
  @return
669
  The function returns the length of the found packet or packet_error.
670
  net->read_pos points to the read data.
671
*/
672
164 by Brian Aker
Commit cleanup of export types.
673
uint32_t
1 by brian
clean slate
674
my_net_read(NET *net)
675
{
676
  size_t len, complen;
677
678
  if (!net->compress)
679
  {
680
    len = my_real_read(net,&complen);
681
    if (len == MAX_PACKET_LENGTH)
682
    {
683
      /* First packet of a multi-packet.  Concatenate the packets */
294 by Brian Aker
libdrizzle has ulong removed.
684
      uint32_t save_pos = net->where_b;
1 by brian
clean slate
685
      size_t total_length= 0;
686
      do
687
      {
688
	net->where_b += len;
689
	total_length += len;
690
	len = my_real_read(net,&complen);
691
      } while (len == MAX_PACKET_LENGTH);
692
      if (len != packet_error)
693
	len+= total_length;
694
      net->where_b = save_pos;
695
    }
696
    net->read_pos = net->buff + net->where_b;
697
    if (len != packet_error)
206.3.1 by Patrick Galbraith
Most everything working with client rename
698
      net->read_pos[len]=0;		/* Safeguard for drizzle_use_result */
1 by brian
clean slate
699
    return len;
700
  }
701
  else
702
  {
703
    /* We are using the compressed protocol */
704
294 by Brian Aker
libdrizzle has ulong removed.
705
    uint32_t buf_length;
706
    uint32_t start_of_packet;
707
    uint32_t first_packet_offset;
1 by brian
clean slate
708
    uint read_length, multi_byte_packet=0;
709
710
    if (net->remain_in_buf)
711
    {
712
      buf_length= net->buf_length;		/* Data left in old packet */
713
      first_packet_offset= start_of_packet= (net->buf_length -
714
					     net->remain_in_buf);
715
      /* Restore the character that was overwritten by the end 0 */
716
      net->buff[start_of_packet]= net->save_char;
717
    }
718
    else
719
    {
720
      /* reuse buffer, as there is nothing in it that we need */
721
      buf_length= start_of_packet= first_packet_offset= 0;
722
    }
723
    for (;;)
724
    {
294 by Brian Aker
libdrizzle has ulong removed.
725
      uint32_t packet_len;
1 by brian
clean slate
726
727
      if (buf_length - start_of_packet >= NET_HEADER_SIZE)
728
      {
729
	read_length = uint3korr(net->buff+start_of_packet);
730
	if (!read_length)
731
	{ 
732
	  /* End of multi-byte packet */
733
	  start_of_packet += NET_HEADER_SIZE;
734
	  break;
735
	}
736
	if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet)
737
	{
738
	  if (multi_byte_packet)
739
	  {
740
	    /* Remove packet header for second packet */
741
	    memmove(net->buff + first_packet_offset + start_of_packet,
742
		    net->buff + first_packet_offset + start_of_packet +
743
		    NET_HEADER_SIZE,
744
		    buf_length - start_of_packet);
745
	    start_of_packet += read_length;
746
	    buf_length -= NET_HEADER_SIZE;
747
	  }
748
	  else
749
	    start_of_packet+= read_length + NET_HEADER_SIZE;
750
751
	  if (read_length != MAX_PACKET_LENGTH)	/* last package */
752
	  {
753
	    multi_byte_packet= 0;		/* No last zero len packet */
754
	    break;
755
	  }
756
	  multi_byte_packet= NET_HEADER_SIZE;
757
	  /* Move data down to read next data packet after current one */
758
	  if (first_packet_offset)
759
	  {
760
	    memmove(net->buff,net->buff+first_packet_offset,
761
		    buf_length-first_packet_offset);
762
	    buf_length-=first_packet_offset;
763
	    start_of_packet -= first_packet_offset;
764
	    first_packet_offset=0;
765
	  }
766
	  continue;
767
	}
768
      }
769
      /* Move data down to read next data packet after current one */
770
      if (first_packet_offset)
771
      {
772
	memmove(net->buff,net->buff+first_packet_offset,
773
		buf_length-first_packet_offset);
774
	buf_length-=first_packet_offset;
775
	start_of_packet -= first_packet_offset;
776
	first_packet_offset=0;
777
      }
778
779
      net->where_b=buf_length;
780
      if ((packet_len = my_real_read(net,&complen)) == packet_error)
781
	return packet_error;
782
      if (my_uncompress(net->buff + net->where_b, packet_len,
783
			&complen))
784
      {
785
	net->error= 2;			/* caller will close socket */
786
        net->last_errno= ER_NET_UNCOMPRESS_ERROR;
787
	return packet_error;
788
      }
789
      buf_length+= complen;
790
    }
791
792
    net->read_pos=      net->buff+ first_packet_offset + NET_HEADER_SIZE;
793
    net->buf_length=    buf_length;
294 by Brian Aker
libdrizzle has ulong removed.
794
    net->remain_in_buf= (uint32_t) (buf_length - start_of_packet);
795
    len = ((uint32_t) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE -
1 by brian
clean slate
796
           multi_byte_packet);
797
    net->save_char= net->read_pos[len];	/* Must be saved */
206.3.1 by Patrick Galbraith
Most everything working with client rename
798
    net->read_pos[len]=0;		/* Safeguard for drizzle_use_result */
1 by brian
clean slate
799
  }
800
  return len;
801
}
802
803
804
void my_net_set_read_timeout(NET *net, uint timeout)
805
{
806
  net->read_timeout= timeout;
807
  if (net->vio)
808
    vio_timeout(net->vio, 0, timeout);
51.3.6 by Jay Pipes
Removal of DBUG from libdrizzle/ - Round 2
809
  return;
1 by brian
clean slate
810
}
811
812
813
void my_net_set_write_timeout(NET *net, uint timeout)
814
{
815
  net->write_timeout= timeout;
816
  if (net->vio)
817
    vio_timeout(net->vio, 1, timeout);
51.3.6 by Jay Pipes
Removal of DBUG from libdrizzle/ - Round 2
818
  return;
1 by brian
clean slate
819
}