Skip to content

Commit 5932fa7

Browse files
committed
Fixed "Packets out of order" warning message on stdout in clients,
compiled for debugging, when the server goes down This happens in the following scenario: - Server gets a shutdown message - Servers sends error ER_CONNECTION_KILLED to the clients connection - The client sends a query to the server, before the server has time to close the connection to the client - Client reads the ER_CONNECTION_KILLED error message In the above case, the packet number for the reply is one less than what the client expected and the client prints "Packets out of order". Fixed the following way: - The client accepts now error packages with a packet number one less than expected. - To ensure that this issue can be detected early in my_real_read(), error messages sent to the client are not compressed, even when compressed protocol is used.
1 parent 6f31dd0 commit 5932fa7

File tree

6 files changed

+84
-36
lines changed

6 files changed

+84
-36
lines changed

include/mysql.h.pp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
char save_char;
2828
char net_skip_rest_factor;
2929
my_bool thread_specific_malloc;
30-
my_bool compress;
30+
unsigned char compress;
3131
my_bool unused3;
3232
unsigned char *unused;
3333
unsigned int last_errno;

include/mysql_com.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ typedef struct st_net {
386386
char save_char;
387387
char net_skip_rest_factor;
388388
my_bool thread_specific_malloc;
389-
my_bool compress;
389+
unsigned char compress;
390390
my_bool unused3; /* Please remove with the next incompatible ABI change. */
391391
/*
392392
Pointer to query object in query cache, do not equal NULL (0) for

mysql-test/include/wait_until_connected_again.inc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ while ($mysql_errno)
1414
# Strangely enough, the server might return "Too many connections"
1515
# while being shutdown, thus 1040 is an "allowed" error
1616
# See BUG#36228
17-
--error 0,1040,1053,2002,2003,2005,2006,2013
17+
--error 0,1040,1053,2002,2003,2005,2006,2013,1927
1818
show status;
1919

2020
dec $counter;

mysql-test/include/wait_until_disconnected.inc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ while (!$mysql_errno)
1212
# Strangely enough, the server might return "Too many connections"
1313
# while being shutdown, thus 1040 is an "allowed" error.
1414
# See BUG#36228.
15-
--error 0,1040,1053,2002,2003,2005,2006,2013
15+
--error 0,1040,1053,2002,2003,2005,2006,2013,1927
1616
show status;
1717

1818
dec $counter;

sql/net_serv.cc

Lines changed: 68 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ net_write_buff(NET *net, const uchar *packet, ulong len)
540540
left_length= (ulong) (net->buff_end - net->write_pos);
541541

542542
#ifdef DEBUG_DATA_PACKETS
543-
DBUG_DUMP("data", packet, len);
543+
DBUG_DUMP("data_written", packet, len);
544544
#endif
545545
if (len > left_length)
546546
{
@@ -629,7 +629,8 @@ net_real_write(NET *net,const uchar *packet, size_t len)
629629
}
630630
memcpy(b+header_length,packet,len);
631631

632-
if (my_compress(b+header_length, &len, &complen))
632+
/* Don't compress error packets (compress == 2) */
633+
if (net->compress == 2 || my_compress(b+header_length, &len, &complen))
633634
complen=0;
634635
int3store(&b[NET_HEADER_SIZE],complen);
635636
int3store(b,len);
@@ -640,7 +641,7 @@ net_real_write(NET *net,const uchar *packet, size_t len)
640641
#endif /* HAVE_COMPRESS */
641642

642643
#ifdef DEBUG_DATA_PACKETS
643-
DBUG_DUMP("data", packet, len);
644+
DBUG_DUMP("data_written", packet, len);
644645
#endif
645646

646647
#ifndef NO_ALARM
@@ -830,6 +831,7 @@ my_real_read(NET *net, size_t *complen,
830831
size_t length;
831832
uint i,retry_count=0;
832833
ulong len=packet_error;
834+
my_bool expect_error_packet __attribute((unused))= 0;
833835
thr_alarm_t alarmed;
834836
#ifndef NO_ALARM
835837
ALARM alarm_buff;
@@ -878,6 +880,7 @@ my_real_read(NET *net, size_t *complen,
878880

879881
if (i== 0 && thd_net_is_killed())
880882
{
883+
DBUG_PRINT("info", ("thd is killed"));
881884
len= packet_error;
882885
net->error= 0;
883886
net->last_errno= ER_CONNECTION_KILLED;
@@ -947,39 +950,34 @@ my_real_read(NET *net, size_t *complen,
947950
pos+= length;
948951
update_statistics(thd_increment_bytes_received(length));
949952
}
953+
954+
#ifdef DEBUG_DATA_PACKETS
955+
DBUG_DUMP("data_read", net->buff+net->where_b, length);
956+
#endif
950957
if (i == 0)
951958
{/* First parts is packet length */
952959
ulong helping;
960+
#ifndef DEBUG_DATA_PACKETS
953961
DBUG_DUMP("packet_header", net->buff+net->where_b,
954962
NET_HEADER_SIZE);
963+
#endif
955964
if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)
956-
{
957-
if (net->buff[net->where_b] != (uchar) 255)
958-
{
959-
DBUG_PRINT("error",
960-
("Packets out of order (Found: %d, expected %u)",
961-
(int) net->buff[net->where_b + 3],
962-
net->pkt_nr));
963-
/*
964-
We don't make noise server side, since the client is expected
965-
to break the protocol for e.g. --send LOAD DATA .. LOCAL where
966-
the server expects the client to send a file, but the client
967-
may reply with a new command instead.
968-
*/
965+
{
969966
#ifndef MYSQL_SERVER
970-
EXTRA_DEBUG_fflush(stdout);
971-
EXTRA_DEBUG_fprintf(stderr,"Error: Packets out of order (Found: %d, expected %d)\n",
972-
(int) net->buff[net->where_b + 3],
973-
(uint) (uchar) net->pkt_nr);
974-
EXTRA_DEBUG_fflush(stderr);
967+
if (net->buff[net->where_b + 3] == (uchar) (net->pkt_nr -1))
968+
{
969+
/*
970+
If the server was killed then the server may have missed the
971+
last sent client packet and the packet numbering may be one off.
972+
*/
973+
DBUG_PRINT("warning", ("Found possible out of order packets"));
974+
expect_error_packet= 1;
975+
}
976+
else
975977
#endif
976-
}
977-
len= packet_error;
978-
/* Not a NET error on the client. XXX: why? */
979-
MYSQL_SERVER_my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0));
980-
goto end;
981-
}
982-
net->compress_pkt_nr= ++net->pkt_nr;
978+
goto packets_out_of_order;
979+
}
980+
net->compress_pkt_nr= ++net->pkt_nr;
983981
#ifdef HAVE_COMPRESS
984982
if (net->compress)
985983
{
@@ -1027,6 +1025,21 @@ my_real_read(NET *net, size_t *complen,
10271025
}
10281026
#endif
10291027
}
1028+
#ifndef MYSQL_SERVER
1029+
else if (expect_error_packet)
1030+
{
1031+
/*
1032+
This check is safe both for compressed and not compressed protocol
1033+
as for the compressed protocol errors are not compressed anymore.
1034+
*/
1035+
if (net->buff[net->where_b] != (uchar) 255)
1036+
{
1037+
/* Restore pkt_nr to original value */
1038+
net->pkt_nr--;
1039+
goto packets_out_of_order;
1040+
}
1041+
}
1042+
#endif
10301043
}
10311044

10321045
end:
@@ -1040,7 +1053,7 @@ my_real_read(NET *net, size_t *complen,
10401053
net->reading_or_writing=0;
10411054
#ifdef DEBUG_DATA_PACKETS
10421055
if (len != packet_error)
1043-
DBUG_DUMP("data", net->buff+net->where_b, len);
1056+
DBUG_DUMP("data_read", net->buff+net->where_b, len);
10441057
#endif
10451058
#ifdef MYSQL_SERVER
10461059
if (server_extension != NULL)
@@ -1051,9 +1064,35 @@ my_real_read(NET *net, size_t *complen,
10511064
}
10521065
#endif
10531066
return(len);
1067+
1068+
packets_out_of_order:
1069+
{
1070+
DBUG_PRINT("error",
1071+
("Packets out of order (Found: %d, expected %u)",
1072+
(int) net->buff[net->where_b + 3],
1073+
net->pkt_nr));
1074+
DBUG_ASSERT(0);
1075+
/*
1076+
We don't make noise server side, since the client is expected
1077+
to break the protocol for e.g. --send LOAD DATA .. LOCAL where
1078+
the server expects the client to send a file, but the client
1079+
may reply with a new command instead.
1080+
*/
1081+
#ifndef MYSQL_SERVER
1082+
EXTRA_DEBUG_fflush(stdout);
1083+
EXTRA_DEBUG_fprintf(stderr,"Error: Packets out of order (Found: %d, expected %d)\n",
1084+
(int) net->buff[net->where_b + 3],
1085+
(uint) (uchar) net->pkt_nr);
1086+
EXTRA_DEBUG_fflush(stderr);
1087+
#endif
1088+
len= packet_error;
1089+
MYSQL_SERVER_my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0));
1090+
goto end;
1091+
}
10541092
}
10551093

10561094

1095+
10571096
/* Old interface. See my_net_read_packet() for function description */
10581097

10591098
#undef my_net_read

sql/protocol.cc

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,8 @@ bool net_send_error_packet(THD *thd, uint sql_errno, const char *err,
373373
uint error;
374374
char converted_err[MYSQL_ERRMSG_SIZE];
375375
char buff[2+1+SQLSTATE_LENGTH+MYSQL_ERRMSG_SIZE], *pos;
376-
376+
my_bool ret;
377+
uint8 save_compress;
377378
DBUG_ENTER("send_error_packet");
378379

379380
if (net->vio == 0)
@@ -401,8 +402,16 @@ bool net_send_error_packet(THD *thd, uint sql_errno, const char *err,
401402
/* Converted error message is always null-terminated. */
402403
length= (uint) (strmake(pos, converted_err, MYSQL_ERRMSG_SIZE - 1) - buff);
403404

404-
DBUG_RETURN(net_write_command(net,(uchar) 255, (uchar*) "", 0, (uchar*) buff,
405-
length));
405+
/*
406+
Ensure that errors are not compressed. This is to ensure we can
407+
detect out of bands error messages in the client
408+
*/
409+
if ((save_compress= net->compress))
410+
net->compress= 2;
411+
ret= net_write_command(net,(uchar) 255, (uchar*) "", 0, (uchar*) buff,
412+
length);
413+
net->compress= save_compress;
414+
DBUG_RETURN(ret);
406415
}
407416

408417
#endif /* EMBEDDED_LIBRARY */

0 commit comments

Comments
 (0)