~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to sql/net_serv.cc

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

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