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