net_serv.cc 32.5 KB
Newer Older
1
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
2

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
3 4
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
7
   This program is distributed in the hope that it will be useful,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
9 10
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
11

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
12 13 14
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
15

16 17 18
/**
  @file

19
  This file is the net layer API for the MySQL client/server protocol.
20

21
  Write and read of logical packets to/from socket.
bk@work.mysql.com's avatar
bk@work.mysql.com committed
22

23 24 25 26
  Writes are cached into net_buffer_length big packets.
  Read packets are reallocated dynamicly when reading big packets.
  Each logical packet has the following pre-info:
  3 byte length & 1 byte package-number.
27 28 29

  This file needs to be written in C as it's used by the libmysql client as a
  C file.
30
*/
31

hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
32 33 34 35
/*
  HFTODO this must be hidden if we don't want client capabilities in 
  embedded library
 */
36
#include <my_global.h>
37
#include <mysql.h>
tonu@hundin.mysql.fi's avatar
tonu@hundin.mysql.fi committed
38
#include <mysql_com.h>
39
#include <mysqld_error.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
40 41
#include <my_sys.h>
#include <m_string.h>
42 43
#include <my_net.h>
#include <violite.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
44 45
#include <signal.h>
#include <errno.h>
46
#include "probes_mysql.h"
kent@mysql.com's avatar
kent@mysql.com committed
47

hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
48
#ifdef EMBEDDED_LIBRARY
49
#undef MYSQL_SERVER
50
#undef MYSQL_CLIENT
51
#define MYSQL_CLIENT
hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
52 53 54
#endif /*EMBEDDED_LIBRARY */


55 56 57 58
/*
  The following handles the differences when this is linked between the
  client and the server.

59 60 61
  This gives an error if a too big packet is found.
  The server can change this, but because the client can't normally do this
  the client should have a bigger max_allowed_packet.
62 63
*/

64 65
#if defined(__WIN__) || !defined(MYSQL_SERVER)
  /* The following is because alarms doesn't work on windows. */
66
#ifndef NO_ALARM
67
#define NO_ALARM
bk@work.mysql.com's avatar
bk@work.mysql.com committed
68
#endif
69
#endif
70

71
#ifndef NO_ALARM
bk@work.mysql.com's avatar
bk@work.mysql.com committed
72 73 74
#include "my_pthread.h"
void sql_print_error(const char *format,...);
#else
75
#define DONT_USE_THR_ALARM
76
#endif /* NO_ALARM */
77 78

#include "thr_alarm.h"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
79

80
#ifdef MYSQL_SERVER
81 82
/*
  The following variables/functions should really not be declared
83
  extern, but as it's hard to include sql_priv.h here, we have to
84 85
  live with this for a while.
*/
86
extern uint test_flags;
87
extern ulong bytes_sent, bytes_received, net_big_packet_count;
88
#ifndef MYSQL_INSTANCE_MANAGER
89
#ifdef HAVE_QUERY_CACHE
90
#define USE_QUERY_CACHE
91 92
extern void query_cache_insert(const char *packet, ulong length,
                               unsigned pkt_nr);
93
#endif // HAVE_QUERY_CACHE
94
#define update_statistics(A) A
95 96 97 98
#endif /* MYSQL_INSTANCE_MANGER */
#endif /* defined(MYSQL_SERVER) && !defined(MYSQL_INSTANCE_MANAGER) */

#if !defined(MYSQL_SERVER) || defined(MYSQL_INSTANCE_MANAGER)
99
#define update_statistics(A)
pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
100
#define thd_increment_bytes_sent(N)
101 102
#endif

bk@work.mysql.com's avatar
bk@work.mysql.com committed
103
#define TEST_BLOCKING		8
104
#define MAX_PACKET_LENGTH (256L*256L*256L-1)
105

106
static my_bool net_write_buff(NET *net,const uchar *packet,ulong len);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
107 108


109
/** Init with packet info. */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
110

111
my_bool my_net_init(NET *net, Vio* vio)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
112
{
113
  DBUG_ENTER("my_net_init");
114
  net->vio = vio;
115
  my_net_local_init(net);			/* Set some limits */
116
  if (!(net->buff=(uchar*) my_malloc((size_t) net->max_packet+
117 118
				     NET_HEADER_SIZE + COMP_HEADER_SIZE,
				     MYF(MY_WME))))
119
    DBUG_RETURN(1);
120
  net->buff_end=net->buff+net->max_packet;
121
  net->error=0; net->return_status=0;
122
  net->pkt_nr=net->compress_pkt_nr=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
123
  net->write_pos=net->read_pos = net->buff;
124
  net->last_error[0]=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
125 126
  net->compress=0; net->reading_or_writing=0;
  net->where_b = net->remain_in_buf=0;
127
  net->last_errno=0;
128
  net->unused= 0;
129 130 131
#if defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY)
  net->skip_big_packet= FALSE;
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
132 133 134 135

  if (vio != 0)					/* If real connection */
  {
    net->fd  = vio_fd(vio);			/* For perl DBI/DBD */
136
#if defined(MYSQL_SERVER) && !defined(__WIN__)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
137
    if (!(test_flags & TEST_BLOCKING))
138 139 140 141
    {
      my_bool old_mode;
      vio_blocking(vio, FALSE, &old_mode);
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
142
#endif
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
143
    vio_fastsend(vio);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
144
  }
145
  DBUG_RETURN(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
146 147
}

148

bk@work.mysql.com's avatar
bk@work.mysql.com committed
149 150
void net_end(NET *net)
{
151
  DBUG_ENTER("net_end");
152
  my_free(net->buff);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
153
  net->buff=0;
154
  DBUG_VOID_RETURN;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
155 156
}

157

158
/** Realloc the packet buffer. */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
159

160
my_bool net_realloc(NET *net, size_t length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
161 162
{
  uchar *buff;
163
  size_t pkt_length;
164
  DBUG_ENTER("net_realloc");
165
  DBUG_PRINT("enter",("length: %lu", (ulong) length));
166

167 168 169 170 171 172 173 174 175 176 177
  /*
    When compression is off, net->where_b is always 0.
    With compression turned on, net->where_b may indicate
    that we still have a piece of the previous logical
    packet in the buffer, unprocessed. Take it into account
    when checking that max_allowed_packet is not exceeded.
    This ensures that the client treats max_allowed_packet
    limit identically, regardless of compression being on
    or off.
  */
  if (length >= (net->max_packet_size + net->where_b))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
178
  {
179
    DBUG_PRINT("error", ("Packet too large. Max size: %lu",
180
                         net->max_packet_size));
181
    /* @todo: 1 and 2 codes are identical. */
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
182
    net->error= 1;
183
    net->last_errno= ER_NET_PACKET_TOO_LARGE;
184 185 186
#ifdef MYSQL_SERVER
    my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
#endif
187
    DBUG_RETURN(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
188
  }
189
  pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1); 
190 191
  /*
    We must allocate some extra bytes for the end 0 and to be able to
192 193 194
    read big compressed blocks + 1 safety byte since uint3korr() in
    my_real_read() may actually read 4 bytes depending on build flags and
    platform.
195
  */
196
  if (!(buff= (uchar*) my_realloc((char*) net->buff, pkt_length +
Alexey Kopytov's avatar
Alexey Kopytov committed
197
                                  NET_HEADER_SIZE + COMP_HEADER_SIZE + 1,
198
                                  MYF(MY_WME))))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
199
  {
200
    /* @todo: 1 and 2 codes are identical. */
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
201
    net->error= 1;
202
    net->last_errno= ER_OUT_OF_RESOURCES;
203
    /* In the server the error is reported by MY_WME flag. */
204
    DBUG_RETURN(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
205 206
  }
  net->buff=net->write_pos=buff;
207
  net->buff_end=buff+(net->max_packet= (ulong) pkt_length);
208
  DBUG_RETURN(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
209 210
}

211

212 213
/**
  Check if there is any data to be read from the socket.
214

215
  @param sd   socket descriptor
216

217 218 219 220 221 222
  @retval
    0  No data to read
  @retval
    1  Data or EOF to read
  @retval
    -1   Don't know if data is ready or not
223 224
*/

225 226
#if !defined(EMBEDDED_LIBRARY)

227
static int net_data_is_ready(my_socket sd)
228
{
229 230 231 232 233 234 235 236 237 238 239 240
#ifdef HAVE_POLL
  struct pollfd ufds;
  int res;

  ufds.fd= sd;
  ufds.events= POLLIN | POLLPRI;
  if (!(res= poll(&ufds, 1, 0)))
    return 0;
  if (res < 0 || !(ufds.revents & (POLLIN | POLLPRI)))
    return 0;
  return 1;
#else
241 242 243 244
  fd_set sfds;
  struct timeval tv;
  int res;

245 246
#ifndef __WIN__
  /* Windows uses an _array_ of 64 fd's as default, so it's safe */
247 248
  if (sd >= FD_SETSIZE)
    return -1;
249
#define NET_DATA_IS_READY_CAN_RETURN_MINUS_ONE
250
#endif
251

252 253 254 255 256
  FD_ZERO(&sfds);
  FD_SET(sd, &sfds);

  tv.tv_sec= tv.tv_usec= 0;

257
  if ((res= select((int) (sd + 1), &sfds, NULL, NULL, &tv)) < 0)
258
    return 0;
259 260
  else
    return test(res ? FD_ISSET(sd, &sfds) : 0);
261
#endif /* HAVE_POLL */
262 263
}

264
#endif /* EMBEDDED_LIBRARY */
265

266
/**
267
  Remove unwanted characters from connection
268
  and check if disconnected.
269 270 271 272 273 274 275 276 277 278 279

    Read from socket until there is nothing more to read. Discard
    what is read.

    If there is anything when to read 'net_clear' is called this
    normally indicates an error in the protocol.

    When connection is properly closed (for TCP it means with
    a FIN packet), then select() considers a socket "ready to read",
    in the sense that there's EOF to read, but read() returns 0.

280 281
  @param net			NET handler
  @param clear_buffer           if <> 0, then clear all data from comm buff
282
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
283

284
void net_clear(NET *net, my_bool clear_buffer)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
285
{
286
#if !defined(EMBEDDED_LIBRARY)
287 288
  size_t count;
  int ready;
289
#endif
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
290
  DBUG_ENTER("net_clear");
291

292
#if !defined(EMBEDDED_LIBRARY)
293
  if (clear_buffer)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
294
  {
295
    while ((ready= net_data_is_ready(net->vio->sd)) > 0)
296
    {
297
      /* The socket is ready */
298 299
      if ((long) (count= vio_read(net->vio, net->buff,
                                  (size_t) net->max_packet)) > 0)
300
      {
301 302
        DBUG_PRINT("info",("skipped %ld bytes from file: %s",
                           (long) count, vio_description(net->vio)));
303
#if defined(EXTRA_DEBUG)
304 305
        fprintf(stderr,"Note: net_clear() skipped %ld bytes from file: %s\n",
                (long) count, vio_description(net->vio));
306
#endif
307 308 309 310 311 312 313
      }
      else
      {
        DBUG_PRINT("info",("socket ready but only EOF to read - disconnected"));
        net->error= 2;
        break;
      }
314
    }
315
#ifdef NET_DATA_IS_READY_CAN_RETURN_MINUS_ONE
316 317
    /* 'net_data_is_ready' returned "don't know" */
    if (ready == -1)
318
    {
319 320 321 322
      /* Read unblocking to clear net */
      my_bool old_mode;
      if (!vio_blocking(net->vio, FALSE, &old_mode))
      {
323 324 325 326
        while ((long) (count= vio_read(net->vio, net->buff,
                                       (size_t) net->max_packet)) > 0)
          DBUG_PRINT("info",("skipped %ld bytes from file: %s",
                             (long) count, vio_description(net->vio)));
327 328
        vio_blocking(net->vio, TRUE, &old_mode);
      }
329
    }
330
#endif /* NET_DATA_IS_READY_CAN_RETURN_MINUS_ONE */
331
  }
332
#endif /* EMBEDDED_LIBRARY */
333
  net->pkt_nr=net->compress_pkt_nr=0;		/* Ready for new command */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
334
  net->write_pos=net->buff;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
335
  DBUG_VOID_RETURN;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
336 337
}

338

339
/** Flush write_buffer if not empty. */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
340

341
my_bool net_flush(NET *net)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
342
{
343
  my_bool error= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
344 345 346
  DBUG_ENTER("net_flush");
  if (net->buff != net->write_pos)
  {
347 348
    error=test(net_real_write(net, net->buff,
			      (size_t) (net->write_pos - net->buff)));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
349 350
    net->write_pos=net->buff;
  }
351 352 353
  /* Sync packet number if using compression */
  if (net->compress)
    net->pkt_nr=net->compress_pkt_nr;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
354 355 356 357 358 359 360 361
  DBUG_RETURN(error);
}


/*****************************************************************************
** Write something to server/client buffer
*****************************************************************************/

362 363 364
/**
  Write a logical packet with packet header.

365 366 367
  Format: Packet length (3 bytes), packet number(1 byte)
  When compression is used a 3 byte compression length is added

368
  @note
369
    If compression is used the original package is modified!
bk@work.mysql.com's avatar
bk@work.mysql.com committed
370 371
*/

372
my_bool
373
my_net_write(NET *net,const uchar *packet,size_t len)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
374 375
{
  uchar buff[NET_HEADER_SIZE];
376 377
  int rc;

378
  if (unlikely(!net->vio)) /* nowhere to write */
379
    return 0;
380 381 382

  MYSQL_NET_WRITE_START(len);

383
  /*
384 385 386
    Big packets are handled by splitting them in packets of MAX_PACKET_LENGTH
    length. The last packet is always a packet that is < MAX_PACKET_LENGTH.
    (The last packet may even have a length of 0)
387
  */
388
  while (len >= MAX_PACKET_LENGTH)
389
  {
390
    const ulong z_size = MAX_PACKET_LENGTH;
391
    int3store(buff, z_size);
392
    buff[3]= (uchar) net->pkt_nr++;
393
    if (net_write_buff(net, buff, NET_HEADER_SIZE) ||
394
	net_write_buff(net, packet, z_size))
395 396
    {
      MYSQL_NET_WRITE_DONE(1);
397
      return 1;
398
    }
399 400 401 402
    packet += z_size;
    len-=     z_size;
  }
  /* Write last packet */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
403
  int3store(buff,len);
404
  buff[3]= (uchar) net->pkt_nr++;
405
  if (net_write_buff(net, buff, NET_HEADER_SIZE))
406 407
  {
    MYSQL_NET_WRITE_DONE(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
408
    return 1;
409
  }
monty@mysql.com's avatar
monty@mysql.com committed
410
#ifndef DEBUG_DATA_PACKETS
411
  DBUG_DUMP("packet_header", buff, NET_HEADER_SIZE);
monty@mysql.com's avatar
monty@mysql.com committed
412
#endif
413 414 415
  rc= test(net_write_buff(net,packet,len));
  MYSQL_NET_WRITE_DONE(rc);
  return rc;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
416 417
}

418
/**
419
  Send a command to the server.
420 421 422 423 424 425 426 427

    The reason for having both header and packet is so that libmysql
    can easy add a header to a special command (like prepared statements)
    without having to re-alloc the string.

    As the command is part of the first data packet, we have to do some data
    juggling to put the command in there, without having to create a new
    packet.
428
  
429 430 431
    This function will split big packets into sub-packets if needed.
    (Each sub packet can only be 2^24 bytes)

432 433 434 435 436 437 438 439
  @param net		NET handler
  @param command	Command in MySQL server (enum enum_server_command)
  @param header	Header to write after command
  @param head_len	Length of header
  @param packet	Query or parameter to query
  @param len		Length of packet

  @retval
440
    0	ok
441
  @retval
442
    1	error
443 444
*/

445 446
my_bool
net_write_command(NET *net,uchar command,
447 448
		  const uchar *header, size_t head_len,
		  const uchar *packet, size_t len)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
449
{
450
  size_t length=len+1+head_len;			/* 1 extra byte for command */
451 452
  uchar buff[NET_HEADER_SIZE+1];
  uint header_size=NET_HEADER_SIZE+1;
453
  int rc;
454
  DBUG_ENTER("net_write_command");
455
  DBUG_PRINT("enter",("length: %lu", (ulong) len));
456

457 458
  MYSQL_NET_WRITE_START(length);

459
  buff[4]=command;				/* For first packet */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
460

461
  if (length >= MAX_PACKET_LENGTH)
462 463
  {
    /* Take into account that we have the command in the first header */
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
464
    len= MAX_PACKET_LENGTH - 1 - head_len;
465 466
    do
    {
467
      int3store(buff, MAX_PACKET_LENGTH);
468
      buff[3]= (uchar) net->pkt_nr++;
469
      if (net_write_buff(net, buff, header_size) ||
470 471
	  net_write_buff(net, header, head_len) ||
	  net_write_buff(net, packet, len))
472 473
      {
        MYSQL_NET_WRITE_DONE(1);
474
	DBUG_RETURN(1);
475
      }
476
      packet+= len;
477 478
      length-= MAX_PACKET_LENGTH;
      len= MAX_PACKET_LENGTH;
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
479
      head_len= 0;
480 481
      header_size= NET_HEADER_SIZE;
    } while (length >= MAX_PACKET_LENGTH);
482 483
    len=length;					/* Data left to be written */
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
484
  int3store(buff,length);
485
  buff[3]= (uchar) net->pkt_nr++;
486 487 488 489
  rc= test(net_write_buff(net, buff, header_size) ||
           (head_len && net_write_buff(net, header, head_len)) ||
           net_write_buff(net, packet, len) || net_flush(net));
  MYSQL_NET_WRITE_DONE(rc);
490
  DBUG_RETURN(rc);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
491 492
}

493
/**
494
  Caching the data in a local buffer before sending it.
495

496
   Fill up net->buffer and send it to the client when full.
497 498 499 500 501 502

    If the rest of the to-be-sent-packet is bigger than buffer,
    send it in one big block (to avoid copying to internal buffer).
    If not, copy the rest of the data to the buffer and return without
    sending data.

503 504 505
  @param net		Network handler
  @param packet	Packet to send
  @param len		Length of packet
506

507 508
  @note
    The cached buffer can be sent as it is with 'net_flush()'.
509
    In this code we have to be careful to not send a packet longer than
510 511
    MAX_PACKET_LENGTH to net_real_write() if we are using the compressed
    protocol as we store the length of the compressed packet in 3 bytes.
512

513 514 515 516
  @retval
    0	ok
  @retval
    1
517
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
518

519
static my_bool
520
net_write_buff(NET *net, const uchar *packet, ulong len)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
521
{
522 523
  ulong left_length;
  if (net->compress && net->max_packet > MAX_PACKET_LENGTH)
524
    left_length= (ulong) (MAX_PACKET_LENGTH - (net->write_pos - net->buff));
525 526
  else
    left_length= (ulong) (net->buff_end - net->write_pos);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
527

monty@mysql.com's avatar
monty@mysql.com committed
528 529 530
#ifdef DEBUG_DATA_PACKETS
  DBUG_DUMP("data", packet, len);
#endif
531
  if (len > left_length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
532
  {
533
    if (net->write_pos != net->buff)
534
    {
535 536
      /* Fill up already used packet and write it */
      memcpy((char*) net->write_pos,packet,left_length);
537 538
      if (net_real_write(net, net->buff, 
			 (size_t) (net->write_pos - net->buff) + left_length))
539
	return 1;
540
      net->write_pos= net->buff;
541 542 543
      packet+= left_length;
      len-= left_length;
    }
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
    if (net->compress)
    {
      /*
	We can't have bigger packets than 16M with compression
	Because the uncompressed length is stored in 3 bytes
      */
      left_length= MAX_PACKET_LENGTH;
      while (len > left_length)
      {
	if (net_real_write(net, packet, left_length))
	  return 1;
	packet+= left_length;
	len-= left_length;
      }
    }
    if (len > net->max_packet)
      return net_real_write(net, packet, len) ? 1 : 0;
    /* Send out rest of the blocks as full sized blocks */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
562 563
  }
  memcpy((char*) net->write_pos,packet,len);
564
  net->write_pos+= len;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
565 566 567
  return 0;
}

568

569
/**
570 571
  Read and write one packet using timeouts.
  If needed, the packet is compressed before sending.
572 573 574

  @todo
    - TODO is it needed to set this variable if we have no socket
575
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
576 577

int
578
net_real_write(NET *net,const uchar *packet, size_t len)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
579
{
580 581
  size_t length;
  const uchar *pos,*end;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
582
  thr_alarm_t alarmed;
583
#ifndef NO_ALARM
bk@work.mysql.com's avatar
bk@work.mysql.com committed
584 585 586 587 588 589
  ALARM alarm_buff;
#endif
  uint retry_count=0;
  my_bool net_blocking = vio_is_blocking(net->vio);
  DBUG_ENTER("net_real_write");

590
#if defined(MYSQL_SERVER) && defined(USE_QUERY_CACHE)
591
  query_cache_insert((char*) packet, len, net->pkt_nr);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
592 593
#endif

bk@work.mysql.com's avatar
bk@work.mysql.com committed
594 595 596 597 598 599 600
  if (net->error == 2)
    DBUG_RETURN(-1);				/* socket can't be used */

  net->reading_or_writing=2;
#ifdef HAVE_COMPRESS
  if (net->compress)
  {
601
    size_t complen;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
602 603
    uchar *b;
    uint header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
604 605
    if (!(b= (uchar*) my_malloc(len + NET_HEADER_SIZE +
                                COMP_HEADER_SIZE, MYF(MY_WME))))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
606
    {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
607
      net->error= 2;
608
      net->last_errno= ER_OUT_OF_RESOURCES;
609
      /* In the server, the error is reported by MY_WME flag. */
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
610
      net->reading_or_writing= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
611 612 613 614
      DBUG_RETURN(1);
    }
    memcpy(b+header_length,packet,len);

615
    if (my_compress(b+header_length, &len, &complen))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
616 617 618
      complen=0;
    int3store(&b[NET_HEADER_SIZE],complen);
    int3store(b,len);
619
    b[3]=(uchar) (net->compress_pkt_nr++);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
620
    len+= header_length;
621
    packet= b;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
622 623 624
  }
#endif /* HAVE_COMPRESS */

625
#ifdef DEBUG_DATA_PACKETS
626
  DBUG_DUMP("data", packet, len);
627 628
#endif

629
#ifndef NO_ALARM
bk@work.mysql.com's avatar
bk@work.mysql.com committed
630 631
  thr_alarm_init(&alarmed);
  if (net_blocking)
632
    thr_alarm(&alarmed, net->write_timeout, &alarm_buff);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
633 634
#else
  alarmed=0;
635
  /* Write timeout is set in my_net_set_write_timeout */
636
#endif /* NO_ALARM */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
637

638 639
  pos= packet;
  end=pos+len;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
640 641
  while (pos != end)
  {
642
    if ((long) (length= vio_write(net->vio,pos,(size_t) (end-pos))) <= 0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
643 644
    {
      my_bool interrupted = vio_should_retry(net->vio);
645
#if !defined(__WIN__)
646
      if ((interrupted || length == 0) && !thr_alarm_in_use(&alarmed))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
647
      {
648
        if (!thr_alarm(&alarmed, net->write_timeout, &alarm_buff))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
649
        {                                       /* Always true for client */
650 651
	  my_bool old_mode;
	  while (vio_blocking(net->vio, TRUE, &old_mode) < 0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
652
	  {
653
	    if (vio_should_retry(net->vio) && retry_count++ < net->retry_count)
654
	      continue;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
655
#ifdef EXTRA_DEBUG
656 657 658
	    fprintf(stderr,
		    "%s: my_net_write: fcntl returned error %d, aborting thread\n",
		    my_progname,vio_errno(net->vio));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
659
#endif /* EXTRA_DEBUG */
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
660
	    net->error= 2;                     /* Close socket */
661
            net->last_errno= ER_NET_PACKET_TOO_LARGE;
662 663 664
#ifdef MYSQL_SERVER
            my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
#endif
665
	    goto end;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
666 667 668 669 670 671
	  }
	  retry_count=0;
	  continue;
	}
      }
      else
672
#endif /* !defined(__WIN__) */
673
	if (thr_alarm_in_use(&alarmed) && !thr_got_alarm(&alarmed) &&
bk@work.mysql.com's avatar
bk@work.mysql.com committed
674 675
	    interrupted)
      {
676
	if (retry_count++ < net->retry_count)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
677 678 679 680 681 682 683
	    continue;
#ifdef EXTRA_DEBUG
	  fprintf(stderr, "%s: write looped, aborting thread\n",
		  my_progname);
#endif /* EXTRA_DEBUG */
      }
#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
684
      if (vio_errno(net->vio) == SOCKET_EINTR)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
685 686 687 688 689
      {
	DBUG_PRINT("warning",("Interrupted write. Retrying..."));
	continue;
      }
#endif /* defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) */
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
690
      net->error= 2;				/* Close socket */
691
      net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
692
                               ER_NET_ERROR_ON_WRITE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
693
#ifdef MYSQL_SERVER
694
      my_error(net->last_errno, MYF(0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
695 696 697 698
#endif /* MYSQL_SERVER */
      break;
    }
    pos+=length;
699
    update_statistics(thd_increment_bytes_sent(length));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
700 701 702 703 704 705
  }
#ifndef __WIN__
 end:
#endif
#ifdef HAVE_COMPRESS
  if (net->compress)
706
    my_free((void*) packet);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
707
#endif
708
  if (thr_alarm_in_use(&alarmed))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
709
  {
710
    my_bool old_mode;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
711
    thr_end_alarm(&alarmed);
712
    vio_blocking(net->vio, net_blocking, &old_mode);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
713 714 715 716 717 718 719 720 721 722
  }
  net->reading_or_writing=0;
  DBUG_RETURN(((int) (pos != end)));
}


/*****************************************************************************
** Read something from server/clinet
*****************************************************************************/

723
#ifndef NO_ALARM
bk@work.mysql.com's avatar
bk@work.mysql.com committed
724

725
static my_bool net_safe_read(NET *net, uchar *buff, size_t length,
726
			     thr_alarm_t *alarmed)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
727 728
{
  uint retry_count=0;
729
  while (length > 0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
730
  {
731 732
    size_t tmp;
    if ((long) (tmp= vio_read(net->vio, buff, length)) <= 0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
733 734
    {
      my_bool interrupted = vio_should_retry(net->vio);
735
      if (!thr_got_alarm(alarmed) && interrupted)
736
      {					/* Probably in MIT threads */
737
	if (retry_count++ < net->retry_count)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
738 739
	  continue;
      }
740
      return 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
741
    }
742
    length-= tmp;
743
    buff+= tmp;
744 745 746 747
  }
  return 0;
}

748
/**
749 750
  Help function to clear the commuication buffer when we get a too big packet.

751 752 753 754
  @param net		Communication handle
  @param remain	Bytes to read
  @param alarmed	Parameter for thr_alarm()
  @param alarm_buff	Parameter for thr_alarm()
755

756
  @retval
757
   0	Was able to read the whole packet
758
  @retval
759 760 761 762 763 764 765 766 767 768
   1	Got mailformed packet from client
*/

static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed,
				ALARM *alarm_buff)
{
  uint32 old=remain;
  DBUG_ENTER("my_net_skip_rest");
  DBUG_PRINT("enter",("bytes_to_skip: %u", (uint) remain));

769
  /* The following is good for debugging */
770
  update_statistics(thd_increment_net_big_packet_count(1));
771

772
  if (!thr_alarm_in_use(alarmed))
773 774
  {
    my_bool old_mode;
775
    if (thr_alarm(alarmed,net->read_timeout, alarm_buff) ||
776 777 778 779 780 781
	vio_blocking(net->vio, TRUE, &old_mode) < 0)
      DBUG_RETURN(1);				/* Can't setup, abort */
  }
  for (;;)
  {
    while (remain > 0)
782
    {
783 784
      size_t length= min(remain, net->max_packet);
      if (net_safe_read(net, net->buff, length, alarmed))
785
	DBUG_RETURN(1);
786
      update_statistics(thd_increment_bytes_received(length));
787
      remain -= (uint32) length;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
788
    }
789 790
    if (old != MAX_PACKET_LENGTH)
      break;
791
    if (net_safe_read(net, net->buff, NET_HEADER_SIZE, alarmed))
792 793 794
      DBUG_RETURN(1);
    old=remain= uint3korr(net->buff);
    net->pkt_nr++;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
795
  }
796
  DBUG_RETURN(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
797
}
798
#endif /* NO_ALARM */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
799 800


801 802 803
/**
  Reads one packet to net->buff + net->where_b.
  Long packets are handled by my_net_read().
804
  This function reallocates the net->buff buffer if necessary.
805 806 807

  @return
    Returns length of packet.
808 809
*/

810
static ulong
811
my_real_read(NET *net, size_t *complen)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
812 813
{
  uchar *pos;
814
  size_t length;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
815 816 817
  uint i,retry_count=0;
  ulong len=packet_error;
  thr_alarm_t alarmed;
818
#ifndef NO_ALARM
bk@work.mysql.com's avatar
bk@work.mysql.com committed
819 820 821
  ALARM alarm_buff;
#endif
  my_bool net_blocking=vio_is_blocking(net->vio);
822 823
  uint32 remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
		  NET_HEADER_SIZE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
824 825 826 827
  *complen = 0;

  net->reading_or_writing=1;
  thr_alarm_init(&alarmed);
828
#ifndef NO_ALARM
bk@work.mysql.com's avatar
bk@work.mysql.com committed
829
  if (net_blocking)
830
    thr_alarm(&alarmed,net->read_timeout,&alarm_buff);
831
#else
832
  /* Read timeout is set in my_net_set_read_timeout */
833
#endif /* NO_ALARM */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
834 835 836 837 838 839 840

    pos = net->buff + net->where_b;		/* net->packet -4 */
    for (i=0 ; i < 2 ; i++)
    {
      while (remain > 0)
      {
	/* First read is done with non blocking mode */
841
        if ((long) (length= vio_read(net->vio, pos, remain)) <= 0L)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
842 843 844
        {
          my_bool interrupted = vio_should_retry(net->vio);

845
	  DBUG_PRINT("info",("vio_read returned %ld  errno: %d",
846
			     (long) length, vio_errno(net->vio)));
847
#if !defined(__WIN__) || defined(MYSQL_SERVER)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
848 849 850 851 852
	  /*
	    We got an error that there was no data on the socket. We now set up
	    an alarm to not 'read forever', change the socket to non blocking
	    mode and try again
	  */
853
	  if ((interrupted || length == 0) && !thr_alarm_in_use(&alarmed))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
854
	  {
855
	    if (!thr_alarm(&alarmed,net->read_timeout,&alarm_buff)) /* Don't wait too long */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
856
	    {
857 858 859 860
	      my_bool old_mode;
	      while (vio_blocking(net->vio, TRUE, &old_mode) < 0)
	      {
		if (vio_should_retry(net->vio) &&
861
		    retry_count++ < net->retry_count)
862 863 864 865
		  continue;
		DBUG_PRINT("error",
			   ("fcntl returned error %d, aborting thread",
			    vio_errno(net->vio)));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
866
#ifdef EXTRA_DEBUG
867 868 869
		fprintf(stderr,
			"%s: read: fcntl returned error %d, aborting thread\n",
			my_progname,vio_errno(net->vio));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
870
#endif /* EXTRA_DEBUG */
871
		len= packet_error;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
872
		net->error= 2;                 /* Close socket */
873
	        net->last_errno= ER_NET_FCNTL_ERROR;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
874
#ifdef MYSQL_SERVER
875
		my_error(ER_NET_FCNTL_ERROR, MYF(0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
876
#endif
877 878
		goto end;
	      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
879 880 881 882
	      retry_count=0;
	      continue;
	    }
	  }
883
#endif /* (!defined(__WIN__) || defined(MYSQL_SERVER) */
884
	  if (thr_alarm_in_use(&alarmed) && !thr_got_alarm(&alarmed) &&
bk@work.mysql.com's avatar
bk@work.mysql.com committed
885 886
	      interrupted)
	  {					/* Probably in MIT threads */
887
	    if (retry_count++ < net->retry_count)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
888 889 890 891 892 893 894
	      continue;
#ifdef EXTRA_DEBUG
	    fprintf(stderr, "%s: read looped with error %d, aborting thread\n",
		    my_progname,vio_errno(net->vio));
#endif /* EXTRA_DEBUG */
	  }
#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
895
	  if (vio_errno(net->vio) == SOCKET_EINTR)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
896 897 898 899 900
	  {
	    DBUG_PRINT("warning",("Interrupted read. Retrying..."));
	    continue;
	  }
#endif
901
	  DBUG_PRINT("error",("Couldn't read packet: remain: %u  errno: %d  length: %ld",
902
			      remain, vio_errno(net->vio), (long) length));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
903
	  len= packet_error;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
904
	  net->error= 2;				/* Close socket */
905
          net->last_errno= (vio_was_interrupted(net->vio) ?
906 907
                                   ER_NET_READ_INTERRUPTED :
                                   ER_NET_READ_ERROR);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
908
#ifdef MYSQL_SERVER
909
          my_error(net->last_errno, MYF(0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
910 911 912
#endif
	  goto end;
	}
913
	remain -= (uint32) length;
914
	pos+= length;
915
	update_statistics(thd_increment_bytes_received(length));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
916 917 918 919
      }
      if (i == 0)
      {					/* First parts is packet length */
	ulong helping;
920
        DBUG_DUMP("packet_header", net->buff+net->where_b,
monty@mysql.com's avatar
monty@mysql.com committed
921
                  NET_HEADER_SIZE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
922 923 924 925 926
	if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)
	{
	  if (net->buff[net->where_b] != (uchar) 255)
	  {
	    DBUG_PRINT("error",
927
		       ("Packets out of order (Found: %d, expected %u)",
bk@work.mysql.com's avatar
bk@work.mysql.com committed
928
			(int) net->buff[net->where_b + 3],
929
			net->pkt_nr));
930 931 932 933 934 935 936
            /* 
              We don't make noise server side, since the client is expected
              to break the protocol for e.g. --send LOAD DATA .. LOCAL where
              the server expects the client to send a file, but the client
              may reply with a new command instead.
            */
#if defined (EXTRA_DEBUG) && !defined (MYSQL_SERVER)
937
            fflush(stdout);
938
	    fprintf(stderr,"Error: Packets out of order (Found: %d, expected %d)\n",
bk@work.mysql.com's avatar
bk@work.mysql.com committed
939 940
		    (int) net->buff[net->where_b + 3],
		    (uint) (uchar) net->pkt_nr);
941 942
            fflush(stderr);
            DBUG_ASSERT(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
943 944 945
#endif
	  }
	  len= packet_error;
946
          /* Not a NET error on the client. XXX: why? */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
947
#ifdef MYSQL_SERVER
948
	  my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
949 950 951
#endif
	  goto end;
	}
952
	net->compress_pkt_nr= ++net->pkt_nr;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
953 954 955
#ifdef HAVE_COMPRESS
	if (net->compress)
	{
956 957 958 959 960 961 962
          /*
            The following uint3korr() may read 4 bytes, so make sure we don't
            read unallocated or uninitialized memory. The right-hand expression
            must match the size of the buffer allocated in net_realloc().
          */
          DBUG_ASSERT(net->where_b + NET_HEADER_SIZE + sizeof(uint32) <=
                      net->max_packet + NET_HEADER_SIZE + COMP_HEADER_SIZE + 1);
963 964 965 966
	  /*
	    If the packet is compressed then complen > 0 and contains the
	    number of bytes in the uncompressed packet
	  */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
967 968 969 970 971
	  *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
	}
#endif

	len=uint3korr(net->buff+net->where_b);
972 973
	if (!len)				/* End of big multi-packet */
	  goto end;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
974 975 976 977
	helping = max(len,*complen) + net->where_b;
	/* The necessary size of net->buff */
	if (helping >= net->max_packet)
	{
978
	  if (net_realloc(net,helping))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
979
	  {
980 981
#if defined(MYSQL_SERVER) && !defined(NO_ALARM)
	    if (!net->compress &&
982
                net->skip_big_packet &&
983 984
		!my_net_skip_rest(net, (uint32) len, &alarmed, &alarm_buff))
	      net->error= 3;		/* Successfully skiped packet */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
985
#endif
986
	    len= packet_error;          /* Return error and close connection */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
987 988 989 990
	    goto end;
	  }
	}
	pos=net->buff + net->where_b;
991
	remain = (uint32) len;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
992 993 994 995
      }
    }

end:
996
  if (thr_alarm_in_use(&alarmed))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
997
  {
998
    my_bool old_mode;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
999
    thr_end_alarm(&alarmed);
1000
    vio_blocking(net->vio, net_blocking, &old_mode);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1001 1002
  }
  net->reading_or_writing=0;
monty@mysql.com's avatar
monty@mysql.com committed
1003 1004
#ifdef DEBUG_DATA_PACKETS
  if (len != packet_error)
1005
    DBUG_DUMP("data", net->buff+net->where_b, len);
monty@mysql.com's avatar
monty@mysql.com committed
1006
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1007 1008 1009
  return(len);
}

1010

1011
/**
1012 1013
  Read a packet from the client/server and return it without the internal
  package header.
1014

1015 1016 1017
  If the packet is the first packet of a multi-packet packet
  (which is indicated by the length of the packet = 0xffffff) then
  all sub packets are read and concatenated.
1018

1019 1020 1021
  If the packet was compressed, its uncompressed and the length of the
  uncompressed packet is returned.

1022
  @return
1023 1024 1025 1026 1027
  The function returns the length of the found packet or packet_error.
  net->read_pos points to the read data.
*/

ulong
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1028 1029
my_net_read(NET *net)
{
1030
  size_t len, complen;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1031

1032 1033
  MYSQL_NET_READ_START();

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1034 1035 1036 1037
#ifdef HAVE_COMPRESS
  if (!net->compress)
  {
#endif
1038
    len = my_real_read(net,&complen);
1039
    if (len == MAX_PACKET_LENGTH)
1040 1041
    {
      /* First packet of a multi-packet.  Concatenate the packets */
1042
      ulong save_pos = net->where_b;
1043
      size_t total_length= 0;
1044 1045 1046 1047
      do
      {
	net->where_b += len;
	total_length += len;
1048
	len = my_real_read(net,&complen);
1049
      } while (len == MAX_PACKET_LENGTH);
1050 1051 1052 1053
      if (len != packet_error)
	len+= total_length;
      net->where_b = save_pos;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1054 1055 1056
    net->read_pos = net->buff + net->where_b;
    if (len != packet_error)
      net->read_pos[len]=0;		/* Safeguard for mysql_use_result */
1057
    MYSQL_NET_READ_DONE(0, len);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1058 1059 1060
    return len;
#ifdef HAVE_COMPRESS
  }
1061
  else
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1062
  {
1063 1064
    /* We are using the compressed protocol */

1065 1066 1067
    ulong buf_length;
    ulong start_of_packet;
    ulong first_packet_offset;
1068 1069
    uint read_length, multi_byte_packet=0;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1070 1071
    if (net->remain_in_buf)
    {
1072
      buf_length= net->buf_length;		/* Data left in old packet */
1073 1074
      first_packet_offset= start_of_packet= (net->buf_length -
					     net->remain_in_buf);
1075
      /* Restore the character that was overwritten by the end 0 */
1076
      net->buff[start_of_packet]= net->save_char;
1077 1078 1079
    }
    else
    {
1080
      /* reuse buffer, as there is nothing in it that we need */
1081
      buf_length= start_of_packet= first_packet_offset= 0;
1082 1083 1084 1085
    }
    for (;;)
    {
      ulong packet_len;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1086

1087
      if (buf_length - start_of_packet >= NET_HEADER_SIZE)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1088
      {
1089 1090 1091 1092 1093 1094 1095 1096
	read_length = uint3korr(net->buff+start_of_packet);
	if (!read_length)
	{ 
	  /* End of multi-byte packet */
	  start_of_packet += NET_HEADER_SIZE;
	  break;
	}
	if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1097
	{
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
	  if (multi_byte_packet)
	  {
	    /* Remove packet header for second packet */
	    memmove(net->buff + first_packet_offset + start_of_packet,
		    net->buff + first_packet_offset + start_of_packet +
		    NET_HEADER_SIZE,
		    buf_length - start_of_packet);
	    start_of_packet += read_length;
	    buf_length -= NET_HEADER_SIZE;
	  }
	  else
	    start_of_packet+= read_length + NET_HEADER_SIZE;

1111
	  if (read_length != MAX_PACKET_LENGTH)	/* last package */
1112
	  {
1113
	    multi_byte_packet= 0;		/* No last zero len packet */
1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126
	    break;
	  }
	  multi_byte_packet= NET_HEADER_SIZE;
	  /* Move data down to read next data packet after current one */
	  if (first_packet_offset)
	  {
	    memmove(net->buff,net->buff+first_packet_offset,
		    buf_length-first_packet_offset);
	    buf_length-=first_packet_offset;
	    start_of_packet -= first_packet_offset;
	    first_packet_offset=0;
	  }
	  continue;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1127 1128 1129
	}
      }
      /* Move data down to read next data packet after current one */
1130
      if (first_packet_offset)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1131
      {
1132 1133 1134 1135 1136
	memmove(net->buff,net->buff+first_packet_offset,
		buf_length-first_packet_offset);
	buf_length-=first_packet_offset;
	start_of_packet -= first_packet_offset;
	first_packet_offset=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1137 1138
      }

1139 1140
      net->where_b=buf_length;
      if ((packet_len = my_real_read(net,&complen)) == packet_error)
1141 1142
      {
        MYSQL_NET_READ_DONE(1, 0);
1143
	return packet_error;
1144
      }
1145
      if (my_uncompress(net->buff + net->where_b, packet_len,
1146 1147
			&complen))
      {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1148
	net->error= 2;			/* caller will close socket */
1149
        net->last_errno= ER_NET_UNCOMPRESS_ERROR;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1150
#ifdef MYSQL_SERVER
1151
	my_error(ER_NET_UNCOMPRESS_ERROR, MYF(0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1152
#endif
1153
        MYSQL_NET_READ_DONE(1, 0);
1154 1155
	return packet_error;
      }
1156
      buf_length+= complen;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1157
    }
1158 1159 1160

    net->read_pos=      net->buff+ first_packet_offset + NET_HEADER_SIZE;
    net->buf_length=    buf_length;
1161 1162
    net->remain_in_buf= (ulong) (buf_length - start_of_packet);
    len = ((ulong) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE -
1163
           multi_byte_packet);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1164 1165 1166
    net->save_char= net->read_pos[len];	/* Must be saved */
    net->read_pos[len]=0;		/* Safeguard for mysql_use_result */
  }
1167
#endif /* HAVE_COMPRESS */
1168
  MYSQL_NET_READ_DONE(0, len);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1169 1170
  return len;
}
1171

1172

1173
void my_net_set_read_timeout(NET *net, uint timeout)
1174
{
1175
  DBUG_ENTER("my_net_set_read_timeout");
1176 1177 1178
  DBUG_PRINT("enter", ("timeout: %d", timeout));
  net->read_timeout= timeout;
#ifdef NO_ALARM
1179 1180
  if (net->vio)
    vio_timeout(net->vio, 0, timeout);
1181 1182 1183 1184 1185
#endif
  DBUG_VOID_RETURN;
}


1186
void my_net_set_write_timeout(NET *net, uint timeout)
1187
{
1188
  DBUG_ENTER("my_net_set_write_timeout");
1189 1190 1191
  DBUG_PRINT("enter", ("timeout: %d", timeout));
  net->write_timeout= timeout;
#ifdef NO_ALARM
1192 1193
  if (net->vio)
    vio_timeout(net->vio, 1, timeout);
1194 1195 1196
#endif
  DBUG_VOID_RETURN;
}