Manual merge from master to develop. Incliding fix for bug #425 http://bugs.skysql.com/show_bug.cgi?id=425

This commit is contained in:
VilhoRaatikka
2014-05-21 15:41:39 +03:00
parent c5ec3cbc57
commit c28052d5a4
7 changed files with 186 additions and 102 deletions

View File

@ -33,10 +33,9 @@
* If current user is authenticated the new users' table will replace the old one
* 28/02/2014 Massimiliano Pinto Added: client IPv4 in dcb->ipv4 and inet_ntop for string representation
* 11/03/2014 Massimiliano Pinto Added: Unix socket support
* 07/05/2014 Massimiliano Pinto Added: specific version string in server handshake
* 07/05/2014 Massimiliano Pinto Added: specific version string in server handshake
*
*/
#include <skygw_utils.h>
#include <log_manager.h>
#include <mysql_client_server_protocol.h>
@ -257,7 +256,7 @@ MySQLSendHandshake(DCB* dcb)
memcpy(mysql_plugin_data, server_scramble + 8, 12);
mysql_payload_size = sizeof(mysql_protocol_version) + (len_version_string + 1) + sizeof(mysql_thread_id) + 8 + sizeof(mysql_filler) + sizeof(mysql_server_capabilities_one) + sizeof(mysql_server_language) + sizeof(mysql_server_status) + sizeof(mysql_server_capabilities_two) + sizeof(mysql_scramble_len) + sizeof(mysql_filler_ten) + 12 + sizeof(mysql_last_byte) + strlen("mysql_native_password") + sizeof(mysql_last_byte);
mysql_payload_size = sizeof(mysql_protocol_version) + (len_version_string + 1) + sizeof(mysql_thread_id) + 8 + sizeof(mysql_filler) + sizeof(mysql_server_capabilities_one) + sizeof(mysql_server_language) + sizeof(mysql_server_status) + sizeof(mysql_server_capabilities_two) + sizeof(mysql_scramble_len) + sizeof(mysql_filler_ten) + 12 + sizeof(mysql_last_byte) + strlen("mysql_native_password") + sizeof(mysql_last_byte);
// allocate memory for packet header + payload
if ((buf = gwbuf_alloc(sizeof(mysql_packet_header) + mysql_payload_size)) == NULL)
@ -282,9 +281,9 @@ MySQLSendHandshake(DCB* dcb)
memcpy(mysql_handshake_payload, &mysql_protocol_version, sizeof(mysql_protocol_version));
mysql_handshake_payload = mysql_handshake_payload + sizeof(mysql_protocol_version);
// write server version plus 0 filler
strcpy((char *)mysql_handshake_payload, version_string);
mysql_handshake_payload = mysql_handshake_payload + len_version_string;
// write server version plus 0 filler
strcpy((char *)mysql_handshake_payload, version_string);
mysql_handshake_payload = mysql_handshake_payload + len_version_string;
*mysql_handshake_payload = 0x00;
@ -507,9 +506,10 @@ int gw_read_client_event(DCB* dcb) {
ROUTER *router_instance = NULL;
void *rsession = NULL;
MySQLProtocol *protocol = NULL;
GWBUF *read_buffer = NULL;
int b = -1;
int rc = 0;
int nbytes_read = 0;
CHK_DCB(dcb);
protocol = DCB_PROTOCOL(dcb, MySQLProtocol);
CHK_PROTOCOL(protocol);
@ -536,7 +536,6 @@ int gw_read_client_event(DCB* dcb) {
/*
* Handle the closed client socket.
*/
if (b == 0) {
char c;
int l_errno = 0;
@ -561,41 +560,80 @@ int gw_read_client_event(DCB* dcb) {
goto return_rc;
}
rc = gw_read_gwbuff(dcb, &read_buffer, b);
if (rc != 0) {
goto return_rc;
}
nbytes_read = gwbuf_length(read_buffer);
ss_dassert(nbytes_read > 0);
/**
* if read queue existed appent read to it.
* if length of read buffer is less than 3 or less than mysql packet
* then return.
* else copy mysql packets to separate buffers from read buffer and
* continue.
* else
* if read queue didn't exist, length of read is less than 3 or less
* than mysql packet then
* create read queue and append to it and return.
* if length read is less than mysql packet length append to read queue
* append to it and return.
* else (complete packet was read) continue.
*/
if (dcb->dcb_readqueue)
{
uint8_t* data = (uint8_t *)GWBUF_DATA(read_buffer);
read_buffer = gwbuf_append(dcb->dcb_readqueue, read_buffer);
nbytes_read = gwbuf_length(read_buffer);
if (nbytes_read < 3 || nbytes_read < MYSQL_GET_PACKET_LEN(data))
{
rc = 0;
goto return_rc;
}
else
{
/**
* There is at least one complete mysql packet read
*/
read_buffer = dcb->dcb_readqueue;
dcb->dcb_readqueue = NULL;
}
}
else
{
uint8_t* data = (uint8_t *)GWBUF_DATA(read_buffer);
size_t packetlen = MYSQL_GET_PACKET_LEN(data)+4;
if (nbytes_read < 3 || nbytes_read < packetlen)
{
gwbuf_append(dcb->dcb_readqueue, read_buffer);
rc = 0;
goto return_rc;
}
}
/**
* Now there should be at least one complete mysql packet in read_buffer.
*/
switch (protocol->state) {
case MYSQL_AUTH_SENT:
/*
* Read all the data that is available into a chain of buffers
*/
{
int len = -1;
GWBUF *queue = NULL;
GWBUF *gw_buffer = NULL;
int auth_val = -1;
//////////////////////////////////////////////////////
// read and handle errors & close, or return if busy
// note: if b == 0 error handling is not
// triggered, just return
// without closing
//////////////////////////////////////////////////////
rc = gw_read_gwbuff(dcb, &gw_buffer, b);
if (rc != 0) {
goto return_rc;
}
// example with consume, assuming one buffer only ...
queue = gw_buffer;
len = GWBUF_LENGTH(queue);
ss_dassert(len > 0);
auth_val = gw_mysql_do_authentication(dcb, queue);
auth_val = gw_mysql_do_authentication(dcb, read_buffer);
// Data handled withot the dcb->func.write
// so consume it now
// be sure to consume it all
queue = gwbuf_consume(queue, len);
read_buffer = gwbuf_consume(read_buffer, nbytes_read);
if (auth_val == 0)
{
@ -638,9 +676,7 @@ int gw_read_client_event(DCB* dcb) {
* Read all the data that is available into a chain of buffers
*/
{
int len = -1;
uint8_t cap = 0;
GWBUF *read_buffer = NULL;
uint8_t *ptr_buff = NULL;
int mysql_command = -1;
bool stmt_input; /*< router input type */
@ -655,22 +691,14 @@ int gw_read_client_event(DCB* dcb) {
session->service->router_instance;
rsession = session->router_session;
}
//////////////////////////////////////////////////////
// read and handle errors & close, or return if busy
//////////////////////////////////////////////////////
rc = gw_read_gwbuff(dcb, &read_buffer, b);
if (rc != 0) {
goto return_rc;
}
/* Now, we are assuming in the first buffer there is
* the information form mysql command */
len = GWBUF_LENGTH(read_buffer);
ptr_buff = GWBUF_DATA(read_buffer);
/* get mysql commang at fifth byte */
if (ptr_buff) {
ss_dassert(nbytes_read >= 5);
mysql_command = ptr_buff[4];
}
/**
@ -701,7 +729,7 @@ int gw_read_client_event(DCB* dcb) {
}
rc = 1;
/** Free buffer */
read_buffer = gwbuf_consume(read_buffer, len);
read_buffer = gwbuf_consume(read_buffer, nbytes_read);
goto return_rc;
}
/** Ask what type of input the router expects */
@ -758,7 +786,12 @@ int gw_read_client_event(DCB* dcb) {
rc = route_by_statement(router_instance,
router,
rsession,
read_buffer);
read_buffer);
if (read_buffer != NULL)
{
/** add incomplete mysql packet to read queue */
gwbuf_append(dcb->dcb_readqueue, read_buffer);
}
}
else
{
@ -1228,11 +1261,11 @@ return_rc:
static int gw_error_client_event(
DCB* dcb)
{
{
int rc;
CHK_DCB(dcb);
rc = dcb->func.close(dcb);
return rc;
@ -1289,11 +1322,11 @@ static int
gw_client_hangup_event(DCB *dcb)
{
int rc;
CHK_DCB(dcb);
rc = dcb->func.close(dcb);
return rc;
return rc;
}
@ -1301,6 +1334,10 @@ gw_client_hangup_event(DCB *dcb)
* Detect if buffer includes partial mysql packet or multiple packets.
* Store partial packet to pendingqueue. Send complete packets one by one
* to router.
*
* It is assumed readbuf includes at least one complete packet.
* Return 1 in success. If the last packet is incomplete return success but
* leave incomplete packet to readbuf.
*/
static int route_by_statement(
ROUTER* router_instance,
@ -1309,26 +1346,26 @@ static int route_by_statement(
GWBUF* readbuf)
{
int rc = -1;
DCB* master_dcb;
GWBUF* stmtbuf;
uint8_t* payload;
static size_t len;
GWBUF* packetbuf;
do
{
stmtbuf = gw_MySQL_get_next_stmt(&readbuf);
ss_dassert(stmtbuf != NULL);
CHK_GWBUF(stmtbuf);
payload = (uint8_t *)GWBUF_DATA(stmtbuf);
/**
* If message is longer than read data, suspend routing and
* add statement buffer to wait queue.
*/
rc = router->routeQuery(router_instance, rsession, stmtbuf);
packetbuf = gw_MySQL_get_next_packet(&readbuf);
if (packetbuf != NULL)
{
CHK_GWBUF(packetbuf);
rc = router->routeQuery(router_instance, rsession, packetbuf);
}
else
{
rc = 1;
goto return_rc;
}
}
while (readbuf != NULL);
return_rc:
return rc;
}