fix parse session track info out of packet boundary

This commit is contained in:
Dapeng Huang 2018-01-21 18:27:00 +08:00
parent 768296741a
commit 8ce7683a0a
3 changed files with 231 additions and 20 deletions

View File

@ -25,6 +25,7 @@ add_executable(test_trxcompare test_trxcompare.cc ../../../query_classifier/test
add_executable(test_trxtracking test_trxtracking.cc)
add_executable(test_users test_users.cc)
add_executable(test_utils test_utils.cc)
add_executable(test_session_track test_session_track.cc)
target_link_libraries(profile_trxboundaryparser maxscale-common)
target_link_libraries(test_adminusers maxscale-common)
@ -53,6 +54,7 @@ target_link_libraries(test_trxcompare maxscale-common)
target_link_libraries(test_trxtracking maxscale-common)
target_link_libraries(test_users maxscale-common)
target_link_libraries(test_utils maxscale-common)
target_link_libraries(test_session_track mysqlcommon)
add_test(test_adminusers test_adminusers)
add_test(test_atomic test_atomic)
@ -88,5 +90,6 @@ add_test(test_trxcompare_maxscale test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/..
add_test(test_trxtracking test_trxtracking)
add_test(test_users test_users)
add_test(test_utils test_utils)
add_test(test_session_track test_session_track)
add_subdirectory(rest-api)

View File

@ -0,0 +1,187 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <maxscale/alloc.h>
#include <maxscale/buffer.h>
#include <maxscale/protocol/mysql.h>
static const uint8_t resultset1[] =
{
/* BEGIN;*/
0x29, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03,
0x40, 0x00, 0x00, 0x00, 0x20, 0x05, 0x09, 0x08,
0x54, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F,
0x04, 0x13, 0x12, 0x53, 0x54, 0x41, 0x52, 0x54,
0x20, 0x54, 0x52, 0x41, 0x4E, 0x53, 0x41, 0x43,
0x54, 0x49, 0x4F, 0x4E, 0x3B,
/* COMMIT;*/
0x17, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
0x40, 0x00, 0x00, 0x00, 0x0E, 0x05, 0x09, 0x08,
0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F,
0x04, 0x01, 0x00,
/* START TRANSACTION;*/
0x29, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03,
0x40, 0x00, 0x00, 0x00, 0x20, 0x05, 0x09, 0x08,
0x54, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F,
0x04, 0x13, 0x12, 0x53, 0x54, 0x41, 0x52, 0x54,
0x20, 0x54, 0x52, 0x41, 0x4E, 0x53, 0x41, 0x43,
0x54, 0x49, 0x4F, 0x4E, 0x3B,
/* START TRANSACTION READ ONLY;*/
0x28, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03,
0x60, 0x00, 0x00, 0x00, 0x1F, 0x04, 0x1D, 0x1C,
0x53, 0x54, 0x41, 0x52, 0x54, 0x20, 0x54, 0x52,
0x41, 0x4E, 0x53, 0x41, 0x43, 0x54, 0x49, 0x4F,
0x4E, 0x20, 0x52, 0x45, 0x41, 0x44, 0x20, 0x4F,
0x4E, 0x4C, 0x59, 0x3B,
/* COMMIT;*/
0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00,
/* SET AUTOCOMMIT=0;*/
0x1D, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0F, 0x0A,
0x61, 0x75, 0x74, 0x6F, 0x63, 0x6F, 0x6D, 0x6D,
0x69, 0x74, 0x03, 0x4F, 0x46, 0x46, 0x02, 0x01,
0x31,
/* INSERT INTO t1 VALUES(1);*/
0x14, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
0x40, 0x00, 0x00, 0x00, 0x0B, 0x05, 0x09, 0x08,
0x49, 0x5F, 0x5F, 0x5F, 0x57, 0x5F, 0x5F, 0x5F,
/* COMMIT;*/
0x14, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x0B, 0x05, 0x09, 0x08,
0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F
};
#define PACKET_HDR_LEN 4
#define PACKET_1_IDX 0
#define PACKET_1_LEN (PACKET_HDR_LEN + 0x29)
#define PACKET_2_IDX (PACKET_1_IDX + PACKET_1_LEN)
#define PACKET_2_LEN (PACKET_HDR_LEN + 0x17)
#define PACKET_3_IDX (PACKET_2_IDX + PACKET_2_LEN)
#define PACKET_3_LEN (PACKET_HDR_LEN + 0x29)
#define PACKET_4_IDX (PACKET_3_IDX + PACKET_3_LEN)
#define PACKET_4_LEN (PACKET_HDR_LEN + 0x28)
#define PACKET_5_IDX (PACKET_4_IDX + PACKET_4_LEN)
#define PACKET_5_LEN (PACKET_HDR_LEN + 0x07)
#define PACKET_6_IDX (PACKET_5_IDX + PACKET_5_LEN)
#define PACKET_6_LEN (PACKET_HDR_LEN + 0x1D)
#define PACKET_7_IDX (PACKET_6_IDX + PACKET_6_LEN)
#define PACKET_7_LEN (PACKET_HDR_LEN + 0x14)
#define PACKET_8_IDX (PACKET_7_IDX + PACKET_7_LEN)
#define PACKET_8_LEN (PACKET_HDR_LEN + 0x14)
/* multi statments;*/
static const uint8_t resultset2[] =
{
/**
* set autocommit=0;
* create table t1(id int);
* insert into t1 select seq from seq_0_to_20;
* select '' from t1;
**/
0x1D, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0F, 0x0A,
0x61, 0x75, 0x74, 0x6F, 0x63, 0x6F, 0x6D, 0x6D,
0x69, 0x74, 0x03, 0x4F, 0x46, 0x46, 0x02, 0x01,
0x31, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x01,
0x00, 0x15, 0x00, 0x21, 0x40, 0x00, 0x00, 0x27,
0x52, 0x65, 0x63, 0x6F, 0x72, 0x64, 0x73, 0x3A,
0x20, 0x32, 0x31, 0x20, 0x20, 0x44, 0x75, 0x70,
0x6C, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x3A,
0x20, 0x30, 0x20, 0x20, 0x57, 0x61, 0x72, 0x6E,
0x69, 0x6E, 0x67, 0x73, 0x3A, 0x20, 0x30, 0x0B,
0x05, 0x09, 0x08, 0x49, 0x5F, 0x52, 0x5F, 0x57,
0x5F, 0x5F, 0x5F, 0x01, 0x00, 0x00, 0x01, 0x01,
0x16, 0x00, 0x00, 0x02, 0x03, 0x64, 0x65, 0x66,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x21, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFD, 0x01, 0x00, 0x27,
0x00, 0x00, 0x05, 0x00, 0x00, 0x03, 0xFE, 0x00,
0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x04, 0x00,
0x01, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00,
0x06, 0x00, 0x01, 0x00, 0x00, 0x07, 0x00, 0x01,
0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x09,
0x00, 0x01, 0x00, 0x00, 0x0A, 0x00, 0x01, 0x00,
0x00, 0x0B, 0x00, 0x01, 0x00, 0x00, 0x0C, 0x00,
0x01, 0x00, 0x00, 0x0D, 0x00, 0x01, 0x00, 0x00,
0x0E, 0x00, 0x01, 0x00, 0x00, 0x0F, 0x00, 0x01,
0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x11,
0x00, 0x01, 0x00, 0x00, 0x12, 0x00, 0x01, 0x00,
0x00, 0x13, 0x00, 0x01, 0x00, 0x00, 0x14, 0x00,
0x01, 0x00, 0x00, 0x15, 0x00, 0x01, 0x00, 0x00,
0x16, 0x00, 0x01, 0x00, 0x00, 0x17, 0x00, 0x01,
0x00, 0x00, 0x18, 0x00, 0x05, 0x00, 0x00, 0x19,
0xFE, 0x00, 0x00, 0x21, 0x40
};
/* functional test , test packet by packet */
void test1()
{
GWBUF *buffer;
uint32_t server_capabilities = GW_MYSQL_CAPABILITIES_SESSION_TRACK;
ss_dfprintf(stderr,"test_session_track : Functional tests.\n");
//BEGIN
buffer = gwbuf_alloc_and_load(PACKET_1_LEN, resultset1+PACKET_1_IDX);
mxs_mysql_get_session_track_info(buffer, server_capabilities);
ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_state"), "T_______", 8) == 0);
gwbuf_free(buffer);
//COMMIT
buffer = gwbuf_alloc_and_load(PACKET_2_LEN, resultset1+PACKET_2_IDX);
mxs_mysql_get_session_track_info(buffer, server_capabilities);
ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_state"), "________", 8) == 0);
gwbuf_free(buffer);
//START TRANSACTION
buffer = gwbuf_alloc_and_load(PACKET_3_LEN, resultset1+PACKET_3_IDX);
mxs_mysql_get_session_track_info(buffer, server_capabilities);
ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_state"), "T_______", 8) == 0);
gwbuf_free(buffer);
//START TRANSACTION READ ONLY
buffer = gwbuf_alloc_and_load(PACKET_4_LEN, resultset1+PACKET_4_IDX);
mxs_mysql_get_session_track_info(buffer, server_capabilities);
ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_characteristics"),
"START TRANSACTION READ ONLY;", 28) == 0);
gwbuf_free(buffer);
//COMMIT
buffer = gwbuf_alloc_and_load(PACKET_5_LEN, resultset1+PACKET_5_IDX);
mxs_mysql_get_session_track_info(buffer, server_capabilities);
ss_dassert(gwbuf_get_property(buffer, (char *)"trx_characteristics") == NULL);
ss_dassert(gwbuf_get_property(buffer, (char *)"trx_state") == NULL);
gwbuf_free(buffer);
//SET AUTOCOMMIT=0;
buffer = gwbuf_alloc_and_load(PACKET_6_LEN, resultset1+PACKET_6_IDX);
mxs_mysql_get_session_track_info(buffer, server_capabilities);
ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"autocommit"), "OFF", 3) == 0);
gwbuf_free(buffer);
//INSERT INTO t1 VALUES(1);
buffer = gwbuf_alloc_and_load(PACKET_7_LEN, resultset1+PACKET_7_IDX);
mxs_mysql_get_session_track_info(buffer, server_capabilities);
ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_state"), "I___W___", 8) == 0);
gwbuf_free(buffer);
//COMMIT
buffer = gwbuf_alloc_and_load(PACKET_8_LEN, resultset1+PACKET_8_IDX);
mxs_mysql_get_session_track_info(buffer, server_capabilities);
ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_state"), "________", 8) == 0);
gwbuf_free(buffer);
}
/* multi results combine in one buffer, test for check boundary handle properly */
void test2()
{
GWBUF *buffer;
uint32_t server_capabilities = GW_MYSQL_CAPABILITIES_SESSION_TRACK;
ss_dfprintf(stderr, "test_session_track : multi results test\n");
buffer = gwbuf_alloc_and_load(sizeof(resultset2), resultset2);
mxs_mysql_get_session_track_info(buffer, server_capabilities);
ss_dassert(strncmp(gwbuf_get_property(buffer, (char *)"trx_state"), "I_R_W___", 8) == 0);
gwbuf_free(buffer);
}
int main(int argc, char **argv)
{
test1();
test2();
return 0;
}

View File

@ -1769,27 +1769,21 @@ void mxs_mysql_execute_kill_user(MXS_SESSION* issuer, const char* user, kill_typ
}
/**
* Decode ok packet and get session track info
*
* @param buffer Buffer contain ok packet
* @param server_capabilities Server capabilities
*
* Parse ok packet to get session track info, save to buff properties
* @param buff Buffer contain multi compelte packets
* @param packet_offset Ok packet offset in this buff
* @param packet_len Ok packet lengh
*/
void mxs_mysql_get_session_track_info(GWBUF *buff, uint32_t server_capabilities)
void mxs_mysql_parse_ok_packet(GWBUF *buff,
size_t packet_offset,
size_t packet_len,
uint32_t server_capabilities)
{
ss_dassert(buff);
char *trx_info, *var_name, *var_value;
size_t len = GWBUF_LENGTH(buff);
uint8_t local_buf[len];
uint8_t local_buf[packet_len];
uint8_t *ptr = local_buf;
if (len < MYSQL_OK_PACKET_MIN_LEN || !mxs_mysql_is_ok_packet(buff))
{
return;
}
char *trx_info, *var_name, *var_value;
gwbuf_copy_data(buff, 0, len, local_buf);
buff->gwbuf_type |= GWBUF_TYPE_REPLY_OK;
gwbuf_copy_data(buff, packet_offset, packet_len, local_buf);
ptr += (MYSQL_HEADER_LEN + 1); // Header and Command type
mxs_leint_consume(&ptr); // Affected rows
mxs_leint_consume(&ptr); // Last insert-id
@ -1799,15 +1793,19 @@ void mxs_mysql_get_session_track_info(GWBUF *buff, uint32_t server_capabilities)
if (server_capabilities & GW_MYSQL_CAPABILITIES_SESSION_TRACK)
{
if (ptr < (local_buf + len))
if (ptr < (local_buf + packet_len))
{
ptr += mxs_leint_consume(&ptr); // info
if (server_status & SERVER_SESSION_STATE_CHANGED)
{
mxs_leint_consume(&ptr); // total SERVER_SESSION_STATE_CHANGED length
while (ptr < (local_buf + len))
while (ptr < (local_buf + packet_len))
{
enum_session_state_type type = (enum enum_session_state_type)mxs_leint_consume(&ptr);
enum_session_state_type type =
(enum enum_session_state_type)mxs_leint_consume(&ptr);
#if defined(SS_DEBUG)
ss_dassert(type <= SESSION_TRACK_TRANSACTION_TYPE);
#endif
switch (type)
{
case SESSION_TRACK_STATE_CHANGE:
@ -1849,6 +1847,29 @@ void mxs_mysql_get_session_track_info(GWBUF *buff, uint32_t server_capabilities)
}
}
/**
* Check every packet type, if is ok packet then parse it
* @param buff Buffer contain multi compelte packets
* @param server_capabilities Server capabilities
*/
void mxs_mysql_get_session_track_info(GWBUF *buff, uint32_t server_capabilities)
{
size_t offset = 0;
uint8_t header_and_command[MYSQL_HEADER_LEN+1];
while(gwbuf_copy_data(buff, offset, MYSQL_HEADER_LEN+1, header_and_command) == (MYSQL_HEADER_LEN+1))
{
size_t packet_len = gw_mysql_get_byte3(header_and_command) + MYSQL_HEADER_LEN;
uint8_t cmd = header_and_command[MYSQL_COM_OFFSET];
if (packet_len > MYSQL_OK_PACKET_MIN_LEN && cmd == MYSQL_REPLY_OK)
{
buff->gwbuf_type |= GWBUF_TYPE_REPLY_OK;
mxs_mysql_parse_ok_packet(buff, offset, packet_len, server_capabilities);
}
offset += packet_len;
}
}
/***
* As described in https://dev.mysql.com/worklog/task/?id=6631
* When session transation state changed