summaryrefslogtreecommitdiff
path: root/sql/net_serv.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/net_serv.cc')
-rw-r--r--sql/net_serv.cc265
1 files changed, 188 insertions, 77 deletions
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index ea66bb53394..90a5da6a927 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -34,6 +34,7 @@
HFTODO this must be hidden if we don't want client capabilities in
embedded library
*/
+
#include <my_global.h>
#include <mysql.h>
#include <mysql_com.h>
@@ -43,7 +44,6 @@
#include <my_net.h>
#include <violite.h>
#include <signal.h>
-#include <errno.h>
#include "probes_mysql.h"
#ifdef EMBEDDED_LIBRARY
@@ -108,26 +108,30 @@ extern void query_cache_insert(const char *packet, ulong length,
unsigned pkt_nr);
#endif // HAVE_QUERY_CACHE
#define update_statistics(A) A
+extern my_bool thd_net_is_killed();
+/* Additional instrumentation hooks for the server */
+#include "mysql_com_server.h"
#else
#define update_statistics(A)
+#define thd_net_is_killed() 0
#endif
#define TEST_BLOCKING 8
#define MAX_PACKET_LENGTH (256L*256L*256L-1)
-static my_bool net_write_buff(NET *net,const uchar *packet,ulong len);
-
+static my_bool net_write_buff(NET *, const uchar *, ulong);
/** Init with packet info. */
-my_bool my_net_init(NET *net, Vio* vio)
+my_bool my_net_init(NET *net, Vio* vio, uint my_flags)
{
DBUG_ENTER("my_net_init");
+ DBUG_PRINT("enter", ("my_flags: %u", my_flags));
net->vio = vio;
my_net_local_init(net); /* Set some limits */
if (!(net->buff=(uchar*) my_malloc((size_t) net->max_packet+
NET_HEADER_SIZE + COMP_HEADER_SIZE +1,
- MYF(MY_WME))))
+ MYF(MY_WME | my_flags))))
DBUG_RETURN(1);
net->buff_end=net->buff+net->max_packet;
net->error=0; net->return_status=0;
@@ -139,10 +143,15 @@ my_bool my_net_init(NET *net, Vio* vio)
net->net_skip_rest_factor= 0;
net->last_errno=0;
net->unused= 0;
+ net->thread_specific_malloc= MY_TEST(my_flags & MY_THREAD_SPECIFIC);
+#ifdef MYSQL_SERVER
+ net->extension= NULL;
+#endif
- if (vio != 0) /* If real connection */
+ if (vio)
{
- net->fd = vio_fd(vio); /* For perl DBI/DBD */
+ /* For perl DBI/DBD. */
+ net->fd= vio_fd(vio);
#if defined(MYSQL_SERVER) && !defined(__WIN__)
if (!(test_flags & TEST_BLOCKING))
{
@@ -193,7 +202,9 @@ my_bool net_realloc(NET *net, size_t length)
*/
if (!(buff= (uchar*) my_realloc((char*) net->buff, pkt_length +
NET_HEADER_SIZE + COMP_HEADER_SIZE + 1,
- MYF(MY_WME))))
+ MYF(MY_WME |
+ (net->thread_specific_malloc ?
+ MY_THREAD_SPECIFIC : 0)))))
{
/* @todo: 1 and 2 codes are identical. */
net->error= 1;
@@ -255,14 +266,17 @@ static int net_data_is_ready(my_socket sd)
if ((res= select((int) (sd + 1), &sfds, NULL, NULL, &tv)) < 0)
return 0;
else
- return test(res ? FD_ISSET(sd, &sfds) : 0);
+ return MY_TEST(res ? FD_ISSET(sd, &sfds) : 0);
#endif /* HAVE_POLL */
}
#endif /* EMBEDDED_LIBRARY */
/**
- Intialize NET handler for new reads:
+ Clear (reinitialize) the NET structure for a new command.
+
+ @remark Performs debug checking of the socket buffer to
+ ensure that the protocol sequence is correct.
- Read from socket until there is nothing more to read. Discard
what is read.
@@ -295,7 +309,7 @@ void net_clear(NET *net, my_bool clear_buffer __attribute__((unused)))
{
size_t count;
int ready;
- while ((ready= net_data_is_ready(net->vio->sd)) > 0)
+ while ((ready= net_data_is_ready(vio_fd(net->vio))) > 0)
{
/* The socket is ready */
if ((long) (count= vio_read(net->vio, net->buff,
@@ -345,9 +359,9 @@ my_bool net_flush(NET *net)
DBUG_ENTER("net_flush");
if (net->buff != net->write_pos)
{
- error=test(net_real_write(net, net->buff,
- (size_t) (net->write_pos - net->buff)));
- net->write_pos=net->buff;
+ error= MY_TEST(net_real_write(net, net->buff,
+ (size_t) (net->write_pos - net->buff)));
+ net->write_pos= net->buff;
}
/* Sync packet number if using compression */
if (net->compress)
@@ -363,15 +377,13 @@ my_bool net_flush(NET *net)
/**
Write a logical packet with packet header.
- Format: Packet length (3 bytes), packet number(1 byte)
- When compression is used a 3 byte compression length is added
+ Format: Packet length (3 bytes), packet number (1 byte)
+ When compression is used, a 3 byte compression length is added.
- @note
- If compression is used the original package is modified!
+ @note If compression is used, the original packet is modified!
*/
-my_bool
-my_net_write(NET *net,const uchar *packet,size_t len)
+my_bool my_net_write(NET *net, const uchar *packet, size_t len)
{
uchar buff[NET_HEADER_SIZE];
int rc;
@@ -411,11 +423,12 @@ my_net_write(NET *net,const uchar *packet,size_t len)
#ifndef DEBUG_DATA_PACKETS
DBUG_DUMP("packet_header", buff, NET_HEADER_SIZE);
#endif
- rc= test(net_write_buff(net,packet,len));
+ rc= MY_TEST(net_write_buff(net, packet, len));
MYSQL_NET_WRITE_DONE(rc);
return rc;
}
+
/**
Send a command to the server.
@@ -484,9 +497,9 @@ net_write_command(NET *net,uchar command,
}
int3store(buff,length);
buff[3]= (uchar) net->pkt_nr++;
- 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));
+ rc= MY_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);
DBUG_RETURN(rc);
}
@@ -527,7 +540,7 @@ net_write_buff(NET *net, const uchar *packet, ulong len)
left_length= (ulong) (net->buff_end - net->write_pos);
#ifdef DEBUG_DATA_PACKETS
- DBUG_DUMP("data", packet, len);
+ DBUG_DUMP("data_written", packet, len);
#endif
if (len > left_length)
{
@@ -603,7 +616,10 @@ net_real_write(NET *net,const uchar *packet, size_t len)
uchar *b;
uint header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
if (!(b= (uchar*) my_malloc(len + NET_HEADER_SIZE +
- COMP_HEADER_SIZE + 1, MYF(MY_WME))))
+ COMP_HEADER_SIZE + 1,
+ MYF(MY_WME |
+ (net->thread_specific_malloc ?
+ MY_THREAD_SPECIFIC : 0)))))
{
net->error= 2;
net->last_errno= ER_OUT_OF_RESOURCES;
@@ -613,7 +629,8 @@ net_real_write(NET *net,const uchar *packet, size_t len)
}
memcpy(b+header_length,packet,len);
- if (my_compress(b+header_length, &len, &complen))
+ /* Don't compress error packets (compress == 2) */
+ if (net->compress == 2 || my_compress(b+header_length, &len, &complen))
complen=0;
int3store(&b[NET_HEADER_SIZE],complen);
int3store(b,len);
@@ -624,7 +641,7 @@ net_real_write(NET *net,const uchar *packet, size_t len)
#endif /* HAVE_COMPRESS */
#ifdef DEBUG_DATA_PACKETS
- DBUG_DUMP("data", packet, len);
+ DBUG_DUMP("data_written", packet, len);
#endif
#ifndef NO_ALARM
@@ -775,7 +792,7 @@ static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed,
{
while (remain > 0)
{
- size_t length= min(remain, net->max_packet);
+ size_t length= MY_MIN(remain, net->max_packet);
if (net_safe_read(net, net->buff, length, alarmed))
DBUG_RETURN(1);
update_statistics(thd_increment_bytes_received(length));
@@ -807,12 +824,14 @@ static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed,
*/
static ulong
-my_real_read(NET *net, size_t *complen)
+my_real_read(NET *net, size_t *complen,
+ my_bool header __attribute__((unused)))
{
uchar *pos;
size_t length;
uint i,retry_count=0;
ulong len=packet_error;
+ my_bool expect_error_packet __attribute__((unused))= 0;
thr_alarm_t alarmed;
#ifndef NO_ALARM
ALARM alarm_buff;
@@ -820,6 +839,21 @@ my_real_read(NET *net, size_t *complen)
my_bool net_blocking=vio_is_blocking(net->vio);
uint32 remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
NET_HEADER_SIZE);
+#ifdef MYSQL_SERVER
+ size_t count= remain;
+ struct st_net_server *server_extension= 0;
+
+ if (header)
+ {
+ server_extension= static_cast<st_net_server*> (net->extension);
+ if (server_extension != NULL)
+ {
+ void *user_data= server_extension->m_user_data;
+ server_extension->m_before_header(net, user_data, count);
+ }
+ }
+#endif
+
*complen = 0;
net->reading_or_writing=1;
@@ -843,6 +877,17 @@ my_real_read(NET *net, size_t *complen)
DBUG_PRINT("info",("vio_read returned %ld errno: %d",
(long) length, vio_errno(net->vio)));
+
+ if (i== 0 && thd_net_is_killed())
+ {
+ DBUG_PRINT("info", ("thd is killed"));
+ len= packet_error;
+ net->error= 0;
+ net->last_errno= ER_CONNECTION_KILLED;
+ MYSQL_SERVER_my_error(net->last_errno, MYF(0));
+ goto end;
+ }
+
#if !defined(__WIN__) && defined(MYSQL_SERVER)
/*
We got an error that there was no data on the socket. We now set up
@@ -885,7 +930,7 @@ my_real_read(NET *net, size_t *complen)
my_progname,vio_errno(net->vio));
}
#ifndef MYSQL_SERVER
- if ((long)length < 0 && vio_errno(net->vio) == SOCKET_EINTR)
+ if (length != 0 && vio_errno(net->vio) == SOCKET_EINTR)
{
DBUG_PRINT("warning",("Interrupted read. Retrying..."));
continue;
@@ -895,7 +940,7 @@ my_real_read(NET *net, size_t *complen)
remain, vio_errno(net->vio), (long) length));
len= packet_error;
net->error= 2; /* Close socket */
- net->last_errno= (vio_was_interrupted(net->vio) ?
+ net->last_errno= (vio_was_timeout(net->vio) ?
ER_NET_READ_INTERRUPTED :
ER_NET_READ_ERROR);
MYSQL_SERVER_my_error(net->last_errno, MYF(0));
@@ -905,39 +950,34 @@ my_real_read(NET *net, size_t *complen)
pos+= length;
update_statistics(thd_increment_bytes_received(length));
}
+
+#ifdef DEBUG_DATA_PACKETS
+ DBUG_DUMP("data_read", net->buff+net->where_b, length);
+#endif
if (i == 0)
{ /* First parts is packet length */
ulong helping;
+#ifndef DEBUG_DATA_PACKETS
DBUG_DUMP("packet_header", net->buff+net->where_b,
NET_HEADER_SIZE);
+#endif
if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)
- {
- if (net->buff[net->where_b] != (uchar) 255)
- {
- DBUG_PRINT("error",
- ("Packets out of order (Found: %d, expected %u)",
- (int) net->buff[net->where_b + 3],
- net->pkt_nr));
- /*
- 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.
- */
+ {
#ifndef MYSQL_SERVER
- EXTRA_DEBUG_fflush(stdout);
- EXTRA_DEBUG_fprintf(stderr,"Error: Packets out of order (Found: %d, expected %d)\n",
- (int) net->buff[net->where_b + 3],
- (uint) (uchar) net->pkt_nr);
- EXTRA_DEBUG_fflush(stderr);
+ if (net->buff[net->where_b + 3] == (uchar) (net->pkt_nr -1))
+ {
+ /*
+ If the server was killed then the server may have missed the
+ last sent client packet and the packet numbering may be one off.
+ */
+ DBUG_PRINT("warning", ("Found possible out of order packets"));
+ expect_error_packet= 1;
+ }
+ else
#endif
- }
- len= packet_error;
- /* Not a NET error on the client. XXX: why? */
- MYSQL_SERVER_my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0));
- goto end;
- }
- net->compress_pkt_nr= ++net->pkt_nr;
+ goto packets_out_of_order;
+ }
+ net->compress_pkt_nr= ++net->pkt_nr;
#ifdef HAVE_COMPRESS
if (net->compress)
{
@@ -959,7 +999,7 @@ my_real_read(NET *net, size_t *complen)
len=uint3korr(net->buff+net->where_b);
if (!len) /* End of big multi-packet */
goto end;
- helping = max(len,*complen) + net->where_b;
+ helping = MY_MAX(len,*complen) + net->where_b;
/* The necessary size of net->buff */
if (helping >= net->max_packet)
{
@@ -976,7 +1016,30 @@ my_real_read(NET *net, size_t *complen)
}
pos=net->buff + net->where_b;
remain = (uint32) len;
+#ifdef MYSQL_SERVER
+ if (server_extension != NULL)
+ {
+ void *user_data= server_extension->m_user_data;
+ server_extension->m_after_header(net, user_data, count, 0);
+ server_extension= NULL;
+ }
+#endif
+ }
+#ifndef MYSQL_SERVER
+ else if (expect_error_packet)
+ {
+ /*
+ This check is safe both for compressed and not compressed protocol
+ as for the compressed protocol errors are not compressed anymore.
+ */
+ if (net->buff[net->where_b] != (uchar) 255)
+ {
+ /* Restore pkt_nr to original value */
+ net->pkt_nr--;
+ goto packets_out_of_order;
+ }
}
+#endif
}
end:
@@ -990,9 +1053,53 @@ end:
net->reading_or_writing=0;
#ifdef DEBUG_DATA_PACKETS
if (len != packet_error)
- DBUG_DUMP("data", net->buff+net->where_b, len);
+ DBUG_DUMP("data_read", net->buff+net->where_b, len);
+#endif
+#ifdef MYSQL_SERVER
+ if (server_extension != NULL)
+ {
+ void *user_data= server_extension->m_user_data;
+ server_extension->m_after_header(net, user_data, count, 1);
+ DBUG_ASSERT(len == packet_error || len == 0);
+ }
#endif
return(len);
+
+packets_out_of_order:
+ {
+ DBUG_PRINT("error",
+ ("Packets out of order (Found: %d, expected %u)",
+ (int) net->buff[net->where_b + 3],
+ net->pkt_nr));
+ DBUG_ASSERT(0);
+ /*
+ 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.
+ */
+#ifndef MYSQL_SERVER
+ EXTRA_DEBUG_fflush(stdout);
+ EXTRA_DEBUG_fprintf(stderr,"Error: Packets out of order (Found: %d, expected %d)\n",
+ (int) net->buff[net->where_b + 3],
+ (uint) (uchar) net->pkt_nr);
+ EXTRA_DEBUG_fflush(stderr);
+#endif
+ len= packet_error;
+ MYSQL_SERVER_my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0));
+ goto end;
+ }
+}
+
+
+
+/* Old interface. See my_net_read_packet() for function description */
+
+#undef my_net_read
+
+ulong my_net_read(NET *net)
+{
+ return my_net_read_packet(net, 0);
}
@@ -1007,13 +1114,17 @@ end:
If the packet was compressed, its uncompressed and the length of the
uncompressed packet is returned.
+ read_from_server is set when the server is reading a new command
+ from the client.
+
@return
The function returns the length of the found packet or packet_error.
net->read_pos points to the read data.
*/
+
ulong
-my_net_read(NET *net)
+my_net_read_packet(NET *net, my_bool read_from_server)
{
size_t len, complen;
@@ -1023,7 +1134,7 @@ my_net_read(NET *net)
if (!net->compress)
{
#endif
- len = my_real_read(net,&complen);
+ len = my_real_read(net,&complen, read_from_server);
if (len == MAX_PACKET_LENGTH)
{
/* First packet of a multi-packet. Concatenate the packets */
@@ -1033,7 +1144,7 @@ my_net_read(NET *net)
{
net->where_b += len;
total_length += len;
- len = my_real_read(net,&complen);
+ len = my_real_read(net,&complen, 0);
} while (len == MAX_PACKET_LENGTH);
if (len != packet_error)
len+= total_length;
@@ -1125,11 +1236,13 @@ my_net_read(NET *net)
}
net->where_b=buf_length;
- if ((packet_len = my_real_read(net,&complen)) == packet_error)
+ if ((packet_len = my_real_read(net,&complen, read_from_server))
+ == packet_error)
{
MYSQL_NET_READ_DONE(1, 0);
return packet_error;
}
+ read_from_server= 0;
if (my_uncompress(net->buff + net->where_b, packet_len,
&complen))
{
@@ -1160,13 +1273,12 @@ void my_net_set_read_timeout(NET *net, uint timeout)
{
DBUG_ENTER("my_net_set_read_timeout");
DBUG_PRINT("enter", ("timeout: %d", timeout));
- if (net->read_timeout == timeout)
- DBUG_VOID_RETURN;
- net->read_timeout= timeout;
-#ifdef NO_ALARM
- if (net->vio)
- vio_timeout(net->vio, 0, timeout);
-#endif
+ if (net->read_timeout != timeout)
+ {
+ net->read_timeout= timeout;
+ if (net->vio)
+ vio_timeout(net->vio, 0, timeout);
+ }
DBUG_VOID_RETURN;
}
@@ -1175,12 +1287,11 @@ void my_net_set_write_timeout(NET *net, uint timeout)
{
DBUG_ENTER("my_net_set_write_timeout");
DBUG_PRINT("enter", ("timeout: %d", timeout));
- if (net->write_timeout == timeout)
- DBUG_VOID_RETURN;
- net->write_timeout= timeout;
-#ifdef NO_ALARM
- if (net->vio)
- vio_timeout(net->vio, 1, timeout);
-#endif
+ if (net->write_timeout != timeout)
+ {
+ net->write_timeout= timeout;
+ if (net->vio)
+ vio_timeout(net->vio, 1, timeout);
+ }
DBUG_VOID_RETURN;
}