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