diff --git a/server/modules/include/plainprotocol.h b/server/modules/include/plainprotocol.h new file mode 100644 index 000000000..35ecd1cd0 --- /dev/null +++ b/server/modules/include/plainprotocol.h @@ -0,0 +1,260 @@ +#ifndef _MYSQL_PROTOCOL_H +#define _MYSQL_PROTOCOL_H +/* + * This file is distributed as part of the MariaDB Corporation MaxScale. It is free + * software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, + * version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright MariaDB Corporation Ab 2013-2015 + */ + +/* + * Revision History + * + * Date Who Description + * 24-03-2015 Markus Makela Initial implementation + + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define GW_MYSQL_VERSION "MaxScale " MAXSCALE_VERSION +#define GW_MYSQL_LOOP_TIMEOUT 300000000 +#define GW_MYSQL_READ 0 +#define GW_MYSQL_WRITE 1 +#define MYSQL_HEADER_LEN 4L + +#define GW_MYSQL_PROTOCOL_VERSION 10 // version is 10 +#define GW_MYSQL_HANDSHAKE_FILLER 0x00 +#define GW_MYSQL_SERVER_CAPABILITIES_BYTE1 0xff +#define GW_MYSQL_SERVER_CAPABILITIES_BYTE2 0xf7 +#define GW_MYSQL_SERVER_LANGUAGE 0x08 +#define GW_MYSQL_MAX_PACKET_LEN 0xffffffL; +#define GW_MYSQL_SCRAMBLE_SIZE 20 +#define GW_SCRAMBLE_LENGTH_323 8 + +#ifndef MYSQL_SCRAMBLE_LEN +# define MYSQL_SCRAMBLE_LEN GW_MYSQL_SCRAMBLE_SIZE +#endif + +#define GW_NOINTR_CALL(A) do { errno = 0; A; } while (errno == EINTR) +#define SMALL_CHUNK 1024 +#define MAX_CHUNK SMALL_CHUNK * 8 * 4 +#define ToHex(Y) (Y>='0'&&Y<='9'?Y-'0':Y-'A'+10) +struct dcb; + +/** Protocol packing macros. */ +#define gw_mysql_set_byte2(__buffer, __int) do { \ + (__buffer)[0]= (uint8_t)((__int) & 0xFF); \ + (__buffer)[1]= (uint8_t)(((__int) >> 8) & 0xFF); } while (0) +#define gw_mysql_set_byte3(__buffer, __int) do { \ + (__buffer)[0]= (uint8_t)((__int) & 0xFF); \ + (__buffer)[1]= (uint8_t)(((__int) >> 8) & 0xFF); \ + (__buffer)[2]= (uint8_t)(((__int) >> 16) & 0xFF); } while (0) +#define gw_mysql_set_byte4(__buffer, __int) do { \ + (__buffer)[0]= (uint8_t)((__int) & 0xFF); \ + (__buffer)[1]= (uint8_t)(((__int) >> 8) & 0xFF); \ + (__buffer)[2]= (uint8_t)(((__int) >> 16) & 0xFF); \ + (__buffer)[3]= (uint8_t)(((__int) >> 24) & 0xFF); } while (0) + +/** Protocol unpacking macros. */ +#define gw_mysql_get_byte2(__buffer) \ + (uint16_t)((__buffer)[0] | \ + ((__buffer)[1] << 8)) +#define gw_mysql_get_byte3(__buffer) \ + (uint32_t)((__buffer)[0] | \ + ((__buffer)[1] << 8) | \ + ((__buffer)[2] << 16)) +#define gw_mysql_get_byte4(__buffer) \ + (uint32_t)((__buffer)[0] | \ + ((__buffer)[1] << 8) | \ + ((__buffer)[2] << 16) | \ + ((__buffer)[3] << 24)) +#define gw_mysql_get_byte8(__buffer) \ + ((uint64_t)(__buffer)[0] | \ + ((uint64_t)(__buffer)[1] << 8) | \ + ((uint64_t)(__buffer)[2] << 16) | \ + ((uint64_t)(__buffer)[3] << 24) | \ + ((uint64_t)(__buffer)[4] << 32) | \ + ((uint64_t)(__buffer)[5] << 40) | \ + ((uint64_t)(__buffer)[6] << 48) | \ + ((uint64_t)(__buffer)[7] << 56)) + +/** MySQL protocol constants */ +typedef enum +{ + GW_MYSQL_CAPABILITIES_NONE= 0, + GW_MYSQL_CAPABILITIES_LONG_PASSWORD= (1 << 0), + GW_MYSQL_CAPABILITIES_FOUND_ROWS= (1 << 1), + GW_MYSQL_CAPABILITIES_LONG_FLAG= (1 << 2), + GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB= (1 << 3), + GW_MYSQL_CAPABILITIES_NO_SCHEMA= (1 << 4), + GW_MYSQL_CAPABILITIES_COMPRESS= (1 << 5), + GW_MYSQL_CAPABILITIES_ODBC= (1 << 6), + GW_MYSQL_CAPABILITIES_LOCAL_FILES= (1 << 7), + GW_MYSQL_CAPABILITIES_IGNORE_SPACE= (1 << 8), + GW_MYSQL_CAPABILITIES_PROTOCOL_41= (1 << 9), + GW_MYSQL_CAPABILITIES_INTERACTIVE= (1 << 10), + GW_MYSQL_CAPABILITIES_SSL= (1 << 11), + GW_MYSQL_CAPABILITIES_IGNORE_SIGPIPE= (1 << 12), + GW_MYSQL_CAPABILITIES_TRANSACTIONS= (1 << 13), + GW_MYSQL_CAPABILITIES_RESERVED= (1 << 14), + GW_MYSQL_CAPABILITIES_SECURE_CONNECTION= (1 << 15), + GW_MYSQL_CAPABILITIES_MULTI_STATEMENTS= (1 << 16), + GW_MYSQL_CAPABILITIES_MULTI_RESULTS= (1 << 17), + GW_MYSQL_CAPABILITIES_PS_MULTI_RESULTS= (1 << 18), + GW_MYSQL_CAPABILITIES_PLUGIN_AUTH= (1 << 19), + GW_MYSQL_CAPABILITIES_SSL_VERIFY_SERVER_CERT= (1 << 30), + GW_MYSQL_CAPABILITIES_REMEMBER_OPTIONS= (1 << 31), + GW_MYSQL_CAPABILITIES_CLIENT= (GW_MYSQL_CAPABILITIES_LONG_PASSWORD | + GW_MYSQL_CAPABILITIES_FOUND_ROWS | + GW_MYSQL_CAPABILITIES_LONG_FLAG | + GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB | + GW_MYSQL_CAPABILITIES_LOCAL_FILES | + GW_MYSQL_CAPABILITIES_PLUGIN_AUTH | + GW_MYSQL_CAPABILITIES_TRANSACTIONS | + GW_MYSQL_CAPABILITIES_PROTOCOL_41 | + GW_MYSQL_CAPABILITIES_MULTI_STATEMENTS | + GW_MYSQL_CAPABILITIES_MULTI_RESULTS | + GW_MYSQL_CAPABILITIES_PS_MULTI_RESULTS | + GW_MYSQL_CAPABILITIES_SECURE_CONNECTION), + GW_MYSQL_CAPABILITIES_CLIENT_COMPRESS= (GW_MYSQL_CAPABILITIES_LONG_PASSWORD | + GW_MYSQL_CAPABILITIES_FOUND_ROWS | + GW_MYSQL_CAPABILITIES_LONG_FLAG | + GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB | + GW_MYSQL_CAPABILITIES_LOCAL_FILES | + GW_MYSQL_CAPABILITIES_PLUGIN_AUTH | + GW_MYSQL_CAPABILITIES_TRANSACTIONS | + GW_MYSQL_CAPABILITIES_PROTOCOL_41 | + GW_MYSQL_CAPABILITIES_MULTI_STATEMENTS | + GW_MYSQL_CAPABILITIES_MULTI_RESULTS | + GW_MYSQL_CAPABILITIES_PS_MULTI_RESULTS | + GW_MYSQL_CAPABILITIES_COMPRESS + ), +} gw_mysql_capabilities_t; + +/** Copy from enum in mariadb-5.5 mysql_com.h */ +typedef enum mysql_server_cmd { + MYSQL_COM_UNDEFINED = -1, + MYSQL_COM_SLEEP = 0, + MYSQL_COM_QUIT, + MYSQL_COM_INIT_DB, + MYSQL_COM_QUERY, + MYSQL_COM_FIELD_LIST, + MYSQL_COM_CREATE_DB, + MYSQL_COM_DROP_DB, + MYSQL_COM_REFRESH, + MYSQL_COM_SHUTDOWN, + MYSQL_COM_STATISTICS, + MYSQL_COM_PROCESS_INFO, + MYSQL_COM_CONNECT, + MYSQL_COM_PROCESS_KILL, + MYSQL_COM_DEBUG, + MYSQL_COM_PING, + MYSQL_COM_TIME, + MYSQL_COM_DELAYED_INSERT, + MYSQL_COM_CHANGE_USER, + MYSQL_COM_BINLOG_DUMP, + MYSQL_COM_TABLE_DUMP, + MYSQL_COM_CONNECT_OUT, + MYSQL_COM_REGISTER_SLAVE, + MYSQL_COM_STMT_PREPARE, + MYSQL_COM_STMT_EXECUTE, + MYSQL_COM_STMT_SEND_LONG_DATA, + MYSQL_COM_STMT_CLOSE, + MYSQL_COM_STMT_RESET, + MYSQL_COM_SET_OPTION, + MYSQL_COM_STMT_FETCH, + MYSQL_COM_DAEMON, + MYSQL_COM_END /*< Must be the last */ +} mysql_server_cmd_t; + +/** + * MySQL Protocol specific state data. + * + * Protocol carries information from client side to backend side, such as + * MySQL session command information and history of earlier session commands. + */ +typedef struct { +#if defined(SS_DEBUG) + skygw_chk_t protocol_chk_top; +#endif + int fd; /*< The socket descriptor */ + struct dcb *owner_dcb; /*< The DCB of the socket + * we are running on */ + SPINLOCK protocol_lock; + uint8_t scramble[MYSQL_SCRAMBLE_LEN]; /*< server scramble, + * created or received */ + uint32_t server_capabilities; /*< server capabilities, + * created or received */ + uint32_t client_capabilities; /*< client capabilities, + * created or received */ + unsigned long tid; /*< MySQL Thread ID, in + * handshake */ + unsigned int charset; /*< MySQL character set at connect time */ +#if defined(SS_DEBUG) + skygw_chk_t protocol_chk_tail; +#endif +} PlainProtocol; + + + +#define MYSQL_GET_COMMAND(payload) (payload[4]) +#define MYSQL_GET_PACKET_NO(payload) (payload[3]) +#define MYSQL_GET_PACKET_LEN(payload) (gw_mysql_get_byte3(payload)) +#define MYSQL_GET_ERRCODE(payload) (gw_mysql_get_byte2(&payload[5])) +#define MYSQL_GET_STMTOK_NPARAM(payload) (gw_mysql_get_byte2(&payload[9])) +#define MYSQL_GET_STMTOK_NATTR(payload) (gw_mysql_get_byte2(&payload[11])) +#define MYSQL_IS_ERROR_PACKET(payload) (MYSQL_GET_COMMAND(payload)==0xff) +#define MYSQL_IS_COM_QUIT(payload) (MYSQL_GET_COMMAND(payload)==0x01) +#define MYSQL_IS_COM_INIT_DB(payload) (MYSQL_GET_COMMAND(payload)==0x02) +#define MYSQL_IS_CHANGE_USER(payload) (MYSQL_GET_COMMAND(payload)==0x11) +#define MYSQL_GET_NATTR(payload) ((int)payload[4]) + +#endif /** _MYSQL_PROTOCOL_H */ + +PlainProtocol* mysql_protocol_init(DCB* dcb, int fd); +void mysql_protocol_done (DCB* dcb); +PlainProtocol *gw_mysql_init(PlainProtocol *data); +int gw_receive_backend_auth(PlainProtocol *protocol); +int gw_decode_mysql_server_handshake(PlainProtocol *protocol, uint8_t *payload); +int gw_read_backend_handshake(PlainProtocol *protocol); +int gw_send_authentication_to_backend( + char *dbname, + char *user, + uint8_t *passwd, + PlainProtocol *protocol); + +int plain_do_connect_to_backend(char *host, int port, int* fd); diff --git a/server/modules/protocol/mongo_backend.c b/server/modules/protocol/mongo_backend.c index 4fe1ff0b8..b52663b6a 100644 --- a/server/modules/protocol/mongo_backend.c +++ b/server/modules/protocol/mongo_backend.c @@ -16,12 +16,14 @@ * Copyright MariaDB Corporation Ab 2013-2014 */ -#include "mysql_client_server_protocol.h" +#include #include #include #include #include +#define PLAIN_BACKEND_SO_SNDBUF (128 * 1024) +#define PLAIN_BACKEND_SO_RCVBUF (128 * 1024) /* * MySQL Protocol module for handling the protocol between the gateway * and the backend MySQL database. @@ -51,7 +53,7 @@ MODULE_INFO info = { MODULE_API_PROTOCOL, MODULE_GA, GWPROTOCOL_VERSION, - "The MySQL to backend server protocol" + "The plain protocol" }; /** Defined in log_manager.cc */ @@ -60,38 +62,32 @@ extern size_t log_ses_count[]; extern __thread log_info_t tls_log_info; static char *version_str = "V2.0.0"; -static int gw_create_backend_connection(DCB *backend, SERVER *server, SESSION *in_session); -static int gw_read_backend_event(DCB* dcb); -static int gw_write_backend_event(DCB *dcb); -static int gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue); -static int gw_error_backend_event(DCB *dcb); -static int gw_backend_close(DCB *dcb); -static int gw_backend_hangup(DCB *dcb); +static int plain_create_backend_connection(DCB *backend, SERVER *server, SESSION *in_session); +static int plain_read_backend_event(DCB* dcb); +static int plain_write_ready_backend_event(DCB *dcb); +static int plain_write_backend(DCB *dcb, GWBUF *queue); +static int plain_error_backend_event(DCB *dcb); +static int plain_backend_close(DCB *dcb); +static int plain_backend_hangup(DCB *dcb); static int backend_write_delayqueue(DCB *dcb); static void backend_set_delayqueue(DCB *dcb, GWBUF *queue); -static int gw_change_user(DCB *backend_dcb, SERVER *server, SESSION *in_session, GWBUF *queue); +static int plain_change_user(DCB *backend_dcb, SERVER *server, SESSION *in_session, GWBUF *queue); static GWBUF* process_response_data (DCB* dcb, GWBUF* readbuf, int nbytes_to_process); extern char* create_auth_failed_msg( GWBUF* readbuf, char* hostaddr, uint8_t* sha1); extern char* create_auth_fail_str(char *username, char *hostaddr, char *sha1, char *db); static bool sescmd_response_complete(DCB* dcb); - -#if defined(NOT_USED) - static int gw_session(DCB *backend_dcb, void *data); -#endif -static MYSQL_session* gw_get_shared_session_auth_info(DCB* dcb); - static GWPROTOCOL MyObject = { - gw_read_backend_event, /* Read - EPOLLIN handler */ - gw_MySQLWrite_backend, /* Write - data from gateway */ - gw_write_backend_event, /* WriteReady - EPOLLOUT handler */ - gw_error_backend_event, /* Error - EPOLLERR handler */ - gw_backend_hangup, /* HangUp - EPOLLHUP handler */ + plain_read_backend_event, /* Read - EPOLLIN handler */ + plain_write_backend, /* Write - data from gateway */ + plain_write_ready_backend_event, /* WriteReady - EPOLLOUT handler */ + plain_error_backend_event, /* Error - EPOLLERR handler */ + plain_backend_hangup, /* HangUp - EPOLLHUP handler */ NULL, /* Accept */ - gw_create_backend_connection, /* Connect */ - gw_backend_close, /* Close */ + plain_create_backend_connection, /* Connect */ + plain_backend_close, /* Close */ NULL, /* Listen */ - gw_change_user, /* Authentication */ + NULL, /* Authentication */ NULL /* Session */ }; @@ -130,43 +126,63 @@ GetModuleObject() } -static MYSQL_session* gw_get_shared_session_auth_info( - DCB* dcb) +/** + * Creates MySQL protocol structure + * + * @param dcb * Must be non-NULL. + * @param fd + * + * @return + * + * + * @details Protocol structure does not have fd because dcb is not + * connected yet. + * + */ +PlainProtocol* plain_protocol_init( + DCB* dcb, + int fd) { - MYSQL_session* auth_info = NULL; - CHK_DCB(dcb); - CHK_SESSION(dcb->session); + PlainProtocol* p; - spinlock_acquire(&dcb->session->ses_lock); + p = (PlainProtocol *) calloc(1, sizeof(PlainProtocol)); + ss_dassert(p != NULL); - if (dcb->session->state != SESSION_STATE_ALLOC) { - auth_info = dcb->session->data; - } else { - LOGIF(LE, (skygw_log_write_flush( - LOGFILE_ERROR, - "%lu [gw_get_shared_session_auth_info] Couldn't get " - "session authentication info. Session in a wrong state %d.", - pthread_self(), - dcb->session->state))); + if (p == NULL) { + int eno = errno; + errno = 0; + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "%lu [mysql_init_protocol] MySQL protocol init failed : " + "memory allocation due error %d, %s.", + pthread_self(), + eno, + strerror(eno)))); + goto return_p; } - spinlock_release(&dcb->session->ses_lock); - return auth_info; + /*< Assign fd with protocol */ + p->fd = fd; + p->owner_dcb = dcb; + +return_p: + return p; } + /** * Backend Read Event for EPOLLIN on the MySQL backend protocol module * @param dcb The backend Descriptor Control Block * @return 1 on operation, 0 for no action */ -static int gw_read_backend_event(DCB *dcb) { - MySQLProtocol *client_protocol = NULL; - MySQLProtocol *backend_protocol = NULL; - MYSQL_session *current_session = NULL; +static int plain_read_backend_event(DCB *dcb) { + PlainProtocol *client_protocol = NULL; + PlainProtocol *backend_protocol = NULL; + int rc = 0; - backend_protocol = (MySQLProtocol *) dcb->protocol; + backend_protocol = (PlainProtocol *) dcb->protocol; CHK_PROTOCOL(backend_protocol); @@ -226,58 +242,12 @@ static int gw_read_backend_event(DCB *dcb) { ss_dassert(read_buffer != NULL || dcb->dcb_readqueue != NULL); } - /** Packet prefix was read earlier */ - if (dcb->dcb_readqueue) - { - if (read_buffer != NULL) - { - read_buffer = gwbuf_append(dcb->dcb_readqueue, read_buffer); - } - else - { - read_buffer = dcb->dcb_readqueue; - } - nbytes_read = gwbuf_length(read_buffer); - - if (nbytes_read < 5) /*< read at least command type */ - { - rc = 0; - LOGIF(LD, (skygw_log_write_flush( - LOGFILE_DEBUG, - "%p [gw_read_backend_event] Read %d bytes " - "from DCB %p, fd %d, session %s. " - "Returning to poll wait.\n", - pthread_self(), - nbytes_read, - dcb, - dcb->fd, - dcb->session))); - goto return_rc; - } - /** There is at least length and command type. */ - else - { - dcb->dcb_readqueue = NULL; - } - } - /** This may be either short prefix of a packet, or the tail of it. */ - else - { - if (nbytes_read < 5) - { - dcb->dcb_readqueue = gwbuf_append(dcb->dcb_readqueue, read_buffer); - rc = 0; - goto return_rc; - } - } - - if (dcb->session->state == SESSION_STATE_ROUTER_READY && dcb->session->client != NULL && dcb->session->client->state == DCB_STATE_POLLING) { client_protocol = SESSION_PROTOCOL(dcb->session, - MySQLProtocol); + PlainProtocol); { gwbuf_set_type(read_buffer, GWBUF_TYPE_MYSQL); @@ -305,9 +275,9 @@ return_with_lock: * @param dcb The descriptor control block * @return 1 in success, 0 in case of failure, */ -static int gw_write_backend_event(DCB *dcb) { +static int plain_write_ready_backend_event(DCB *dcb) { int rc = 0; - MySQLProtocol *backend_protocol = dcb->protocol; + PlainProtocol *backend_protocol = dcb->protocol; /*< * Don't write to backend if backend_dcb is not in poll set anymore. @@ -343,6 +313,138 @@ return_rc: return rc; } + +/** + * plain_do_connect_to_backend + * + * This routine creates socket and connects to a backend server. + * Connect it non-blocking operation. If connect fails, socket is closed. + * + * @param host The host to connect to + * @param port The host TCP/IP port + * @param *fd where connected fd is copied + * @return 0/1 on success and -1 on failure + * If successful, fd has file descriptor to socket which is connected to + * backend server. In failure, fd == -1 and socket is closed. + * + */ +int plain_do_connect_to_backend( + char *host, + int port, + int *fd) +{ + struct sockaddr_in serv_addr; + int rv; + int so = 0; + int bufsize; + + memset(&serv_addr, 0, sizeof serv_addr); + serv_addr.sin_family = AF_INET; + so = socket(AF_INET,SOCK_STREAM,0); + + if (so < 0) { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error: Establishing connection to backend server " + "%s:%d failed.\n\t\t Socket creation failed " + "due %d, %s.", + host, + port, + errno, + strerror(errno)))); + rv = -1; + goto return_rv; + } + /* prepare for connect */ + setipaddress(&serv_addr.sin_addr, host); + serv_addr.sin_port = htons(port); + bufsize = PLAIN_BACKEND_SO_SNDBUF; + + if(setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize)) != 0) + { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error: Failed to set socket options " + "%s:%d failed.\n\t\t Socket configuration failed " + "due %d, %s.", + host, + port, + errno, + strerror(errno)))); + rv = -1; + /** Close socket */ + goto close_so; + } + bufsize = PLAIN_BACKEND_SO_RCVBUF; + + if(setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize)) != 0) + { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error: Failed to set socket options " + "%s:%d failed.\n\t\t Socket configuration failed " + "due %d, %s.", + host, + port, + errno, + strerror(errno)))); + rv = -1; + /** Close socket */ + goto close_so; + } + + /* set socket to as non-blocking here */ + setnonblocking(so); + rv = connect(so, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); + + if (rv != 0) + { + if (errno == EINPROGRESS) + { + rv = 1; + } + else + { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error: Failed to connect backend server %s:%d, " + "due %d, %s.", + host, + port, + errno, + strerror(errno)))); + /** Close socket */ + goto close_so; + } + } + *fd = so; + LOGIF(LD, (skygw_log_write_flush( + LOGFILE_DEBUG, + "%lu [plain_do_connect_to_backend] Connected to backend server " + "%s:%d, fd %d.", + pthread_self(), + host, + port, + so))); + +return_rv: + return rv; + +close_so: + /*< Close newly created socket. */ + if (close(so) != 0) + { + LOGIF(LE, (skygw_log_write_flush( + LOGFILE_ERROR, + "Error: Failed to " + "close socket %d due %d, %s.", + so, + errno, + strerror(errno)))); + } + goto return_rv; +} + /* * Write function for backend DCB. Store command to protocol. * @@ -351,15 +453,13 @@ return_rc: * @return 0 on failure, 1 on success */ static int -gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue) +plain_write_backend(DCB *dcb, GWBUF *queue) { - MySQLProtocol *backend_protocol = dcb->protocol; + PlainProtocol *backend_protocol = dcb->protocol; int rc = 0; rc = dcb_write(dcb, queue); - -return_rc: return rc; } @@ -370,7 +470,7 @@ return_rc: * closed and call DCB close function which triggers closing router session * and related backends (if any exists. */ -static int gw_error_backend_event(DCB *dcb) +static int plain_error_backend_event(DCB *dcb) { SESSION* session; void* rsession; @@ -414,11 +514,7 @@ static int gw_error_backend_event(DCB *dcb) } return 1; } - errbuf = mysql_create_custom_error( - 1, - 0, - "Lost connection to backend server."); - + spinlock_acquire(&session->ses_lock); ses_state = session->state; spinlock_release(&session->ses_lock); @@ -501,12 +597,12 @@ retblock: * backend server. Positive fd is copied to protocol and to dcb. * If fails, fd == -1 and socket is closed. */ -static int gw_create_backend_connection( +static int plain_create_backend_connection( DCB *backend_dcb, SERVER *server, SESSION *session) { - MySQLProtocol *protocol = NULL; + PlainProtocol *protocol = NULL; int rv = -1; int fd = -1; @@ -527,7 +623,8 @@ static int gw_create_backend_connection( } /*< if succeed, fd > 0, -1 otherwise */ - rv = gw_do_connect_to_backend(server->name, server->port, &fd); + + rv = plain_do_connect_to_backend(server->name, server->port, &fd); /*< Assign protocol with backend_dcb */ backend_dcb->protocol = protocol; @@ -536,7 +633,7 @@ static int gw_create_backend_connection( case 0: ss_dassert(fd > 0); protocol->fd = fd; - protocol->protocol_auth_state = MYSQL_CONNECTED; + LOGIF(LD, (skygw_log_write( LOGFILE_DEBUG, "%lu [gw_create_backend_connection] Established " @@ -551,7 +648,7 @@ static int gw_create_backend_connection( case 1: ss_dassert(fd > 0); - protocol->protocol_auth_state = MYSQL_PENDING_CONNECT; + protocol->fd = fd; LOGIF(LD, (skygw_log_write( LOGFILE_DEBUG, @@ -566,7 +663,7 @@ static int gw_create_backend_connection( default: ss_dassert(fd == -1); - ss_dassert(protocol->protocol_auth_state == MYSQL_ALLOC); + LOGIF(LD, (skygw_log_write( LOGFILE_DEBUG, "%lu [gw_create_backend_connection] Connection " @@ -595,7 +692,7 @@ return_fd: * @return 1 always */ static int -gw_backend_hangup(DCB *dcb) +plain_backend_hangup(DCB *dcb) { SESSION* session; void* rsession; @@ -612,12 +709,7 @@ gw_backend_hangup(DCB *dcb) rsession = session->router_session; router = session->service->router; router_instance = session->service->router_instance; - - errbuf = mysql_create_custom_error( - 1, - 0, - "Lost connection to backend server."); - + spinlock_acquire(&session->ses_lock); ses_state = session->state; spinlock_release(&session->ses_lock); @@ -695,7 +787,7 @@ retblock: * @return 1 always */ static int -gw_backend_close(DCB *dcb) +plain_backend_close(DCB *dcb) { DCB* client_dcb; SESSION* session; @@ -705,17 +797,6 @@ gw_backend_close(DCB *dcb) session = dcb->session; CHK_SESSION(session); - LOGIF(LD, (skygw_log_write(LOGFILE_DEBUG, - "%lu [gw_backend_close]", - pthread_self()))); - - quitbuf = mysql_create_com_quit(NULL, 0); - gwbuf_set_type(quitbuf, GWBUF_TYPE_MYSQL); - - /** Send COM_QUIT to the backend being closed */ - mysql_send_com_quit(dcb, 0, quitbuf); - - mysql_protocol_done(dcb); /** * The lock is needed only to protect the read of session->state and * session->client values. Client's state may change by other thread @@ -796,409 +877,18 @@ static int backend_write_delayqueue(DCB *dcb) } else { - localq = dcb->delayq; - dcb->delayq = NULL; - spinlock_release(&dcb->delayqlock); - - if (MYSQL_IS_CHANGE_USER(((uint8_t *)GWBUF_DATA(localq)))) - { - MYSQL_session* mses; - GWBUF* new_packet; - - mses = (MYSQL_session *)dcb->session->client->data; - new_packet = gw_create_change_user_packet( - mses, - (MySQLProtocol *)dcb->protocol); - /** - * Remove previous packet which lacks scramble - * and append the new. - */ - localq = gwbuf_consume(localq, GWBUF_LENGTH(localq)); - localq = gwbuf_append(localq, new_packet); - } + rc = dcb_write(dcb, localq); } if (rc == 0) { - GWBUF* errbuf; - bool succp; - ROUTER_OBJECT *router = NULL; - ROUTER *router_instance = NULL; - void *rsession = NULL; - SESSION *session = dcb->session; - - CHK_SESSION(session); - - if (session != NULL) - { - router = session->service->router; - router_instance = session->service->router_instance; - rsession = session->router_session; #if defined(SS_DEBUG) LOGIF(LE, (skygw_log_write_flush( LOGFILE_ERROR, "Backend write delayqueue error handling."))); #endif - errbuf = mysql_create_custom_error( - 1, - 0, - "Failed to write buffered data to back-end server. " - "Buffer was empty or back-end was disconnected during " - "operation. Attempting to find a new backend."); - - router->handleError(router_instance, - rsession, - errbuf, - dcb, - ERRACT_NEW_CONNECTION, - &succp); - gwbuf_free(errbuf); - - if (!succp) - { - spinlock_acquire(&session->ses_lock); - session->state = SESSION_STATE_STOPPING; - spinlock_release(&session->ses_lock); - ss_dassert(dcb->dcb_errhandle_called); - dcb_close(dcb); - } - } + } return rc; } - -/** - * This routine handles the COM_CHANGE_USER command - * - * @param dcb The current backend DCB - * @param server The backend server pointer - * @param in_session The current session data (MYSQL_session) - * @param queue The GWBUF containing the COM_CHANGE_USER receveid - * @return 1 on success and 0 on failure - */ -static int gw_change_user( - DCB *backend, - SERVER *server, - SESSION *in_session, - GWBUF *queue) -{ - MYSQL_session *current_session = NULL; - MySQLProtocol *backend_protocol = NULL; - MySQLProtocol *client_protocol = NULL; - char username[MYSQL_USER_MAXLEN+1]=""; - char database[MYSQL_DATABASE_MAXLEN+1]=""; - char current_database[MYSQL_DATABASE_MAXLEN+1]=""; - uint8_t client_sha1[MYSQL_SCRAMBLE_LEN]=""; - uint8_t *client_auth_packet = GWBUF_DATA(queue); - unsigned int auth_token_len = 0; - uint8_t *auth_token = NULL; - int rv = -1; - int auth_ret = 1; - - current_session = (MYSQL_session *)in_session->client->data; - backend_protocol = backend->protocol; - client_protocol = in_session->client->protocol; - - /* now get the user, after 4 bytes header and 1 byte command */ - client_auth_packet += 5; - strncpy(username, (char *)client_auth_packet,MYSQL_USER_MAXLEN); - client_auth_packet += strlen(username) + 1; - - /* get the auth token len */ - memcpy(&auth_token_len, client_auth_packet, 1); - - client_auth_packet++; - - /* allocate memory for token only if auth_token_len > 0 */ - if (auth_token_len > 0) { - auth_token = (uint8_t *)malloc(auth_token_len); - ss_dassert(auth_token != NULL); - - if (auth_token == NULL) - return rv; - memcpy(auth_token, client_auth_packet, auth_token_len); - client_auth_packet += auth_token_len; - } - - /* get new database name */ - strncpy(database, (char *)client_auth_packet,MYSQL_DATABASE_MAXLEN); - - /* get character set */ - if (strlen(database)) { - client_auth_packet += strlen(database) + 1; - } else { - client_auth_packet++; - } - - if (client_auth_packet && *client_auth_packet) - memcpy(&backend_protocol->charset, client_auth_packet, sizeof(int)); - - /* save current_database name */ - strncpy(current_database, current_session->db,MYSQL_DATABASE_MAXLEN); - - /* - * Now clear database name in dcb as we don't do local authentication on db name for change user. - * Local authentication only for user@host and if successful the database name change is sent to backend. - */ - strcpy(current_session->db, ""); - - /* - * decode the token and check the password. - * Note: if auth_token_len == 0 && auth_token == NULL, user is without password - */ - auth_ret = gw_check_mysql_scramble_data(backend->session->client, - auth_token, - auth_token_len, - client_protocol->scramble, - sizeof(client_protocol->scramble), - username, - client_sha1); - - if (auth_ret != 0) { - if (!service_refresh_users(backend->session->client->service)) { - /* Try authentication again with new repository data */ - /* Note: if no auth client authentication will fail */ - auth_ret = gw_check_mysql_scramble_data( - backend->session->client, - auth_token, auth_token_len, - client_protocol->scramble, - sizeof(client_protocol->scramble), - username, - client_sha1); - } - } - - /* copy back current datbase to client session */ - strcpy(current_session->db, current_database); - - /* let's free the auth_token now */ - if (auth_token) - free(auth_token); - - if (auth_ret != 0) { - char *password_set = NULL; - char *message = NULL; - GWBUF* buf; - - if (auth_token_len > 0) - password_set = (char *)client_sha1; - else - password_set = ""; - - /** - * Create an error message and make it look like legit reply - * from backend server. Then make it look like an incoming event - * so that thread gets new task of it, calls clientReply - * which filters out duplicate errors from same cause and forward - * reply to the client. - */ - message = create_auth_fail_str(username, - backend->session->client->remote, - password_set, - ""); - if (message == NULL) - { - LOGIF(LE, (skygw_log_write_flush( - LOGFILE_ERROR, - "Error : Creating error message failed."))); - rv = 0; - goto retblock; - } - /** - * Add command to backend's protocol, create artificial reply - * packet and add it to client's read buffer. - */ - protocol_add_srv_command((MySQLProtocol*)backend->protocol, - MYSQL_COM_CHANGE_USER); - modutil_reply_auth_error(backend, message, 0); - rv = 1; - } else { - rv = gw_send_change_user_to_backend(database, username, client_sha1, backend_protocol); - /* - * Now copy new data into user session - */ - strcpy(current_session->user, username); - strcpy(current_session->db, database); - memcpy(current_session->client_sha1, client_sha1, sizeof(current_session->client_sha1)); - } - -retblock: - gwbuf_free(queue); - - return rv; -} - - -/** - * Move packets or parts of packets from readbuf to outbuf as the packet headers - * and lengths have been noticed and counted. - * Session commands need to be marked so that they can be handled properly in - * the router's clientReply. - * - * @param dcb Backend's DCB where data was read from - * @param readbuf GWBUF where data was read to - * @param nbytes_to_process Number of bytes that has been read and need to be processed - * - * @return GWBUF which includes complete MySQL packet - */ -static GWBUF* process_response_data ( - DCB* dcb, - GWBUF* readbuf, - int nbytes_to_process) -{ - int npackets_left = 0; /*< response's packet count */ - ssize_t nbytes_left = 0; /*< nbytes to be read for the packet */ - MySQLProtocol* p; - GWBUF* outbuf = NULL; - - /** Get command which was stored in gw_MySQLWrite_backend */ - p = DCB_PROTOCOL(dcb, MySQLProtocol); - if (!DCB_IS_CLONE(dcb)) CHK_PROTOCOL(p); - - /** All buffers processed here are sescmd responses */ - gwbuf_set_type(readbuf, GWBUF_TYPE_SESCMD_RESPONSE); - - /** - * Now it is known how many packets there should be and how much - * is read earlier. - */ - while (nbytes_to_process != 0) - { - mysql_server_cmd_t srvcmd; - bool succp; - - srvcmd = protocol_get_srv_command(p, false); - - LOGIF(LD, (skygw_log_write( - LOGFILE_DEBUG, - "%lu [process_response_data] Read command %s for DCB %p fd %d.", - pthread_self(), - STRPACKETTYPE(srvcmd), - dcb, - dcb->fd))); - /** - * Read values from protocol structure, fails if values are - * uninitialized. - */ - if (npackets_left == 0) - { - succp = protocol_get_response_status(p, &npackets_left, &nbytes_left); - - if (!succp || npackets_left == 0) - { - /** - * Examine command type and the readbuf. Conclude response - * packet count from the command type or from the first - * packet content. Fails if read buffer doesn't include - * enough data to read the packet length. - */ - init_response_status(readbuf, srvcmd, &npackets_left, &nbytes_left); - } - } - /** Only session commands with responses should be processed */ - ss_dassert(npackets_left > 0); - - /** Read incomplete packet. */ - if (nbytes_left > nbytes_to_process) - { - /** Includes length info so it can be processed */ - if (nbytes_to_process >= 5) - { - /** discard source buffer */ - readbuf = gwbuf_consume(readbuf, GWBUF_LENGTH(readbuf)); - nbytes_left -= nbytes_to_process; - } - nbytes_to_process = 0; - } - /** Packet was read. All bytes belonged to the last packet. */ - else if (nbytes_left == nbytes_to_process) - { - nbytes_left = 0; - nbytes_to_process = 0; - ss_dassert(npackets_left > 0); - npackets_left -= 1; - outbuf = gwbuf_append(outbuf, readbuf); - readbuf = NULL; - } - /** - * Packet was read. There should be more since bytes were - * left over. - * Move the next packet to its own buffer and add that next - * to the prev packet's buffer. - */ - else /*< nbytes_left < nbytes_to_process */ - { - ss_dassert(nbytes_left >= 0); - nbytes_to_process -= nbytes_left; - - /** Move the prefix of the buffer to outbuf from redbuf */ - outbuf = gwbuf_append(outbuf, - gwbuf_clone_portion(readbuf, 0, (size_t)nbytes_left)); - readbuf = gwbuf_consume(readbuf, (size_t)nbytes_left); - ss_dassert(npackets_left > 0); - npackets_left -= 1; - nbytes_left = 0; - } - - /** Store new status to protocol structure */ - protocol_set_response_status(p, npackets_left, nbytes_left); - - /** A complete packet was read */ - if (nbytes_left == 0) - { - /** No more packets in this response */ - if (npackets_left == 0 && outbuf != NULL) - { - GWBUF* b = outbuf; - - while (b->next != NULL) - { - b = b->next; - } - /** Mark last as end of response */ - gwbuf_set_type(b, GWBUF_TYPE_RESPONSE_END); - - /** Archive the command */ - protocol_archive_srv_command(p); - } - /** Read next packet */ - else - { - uint8_t* data; - - /** Read next packet length */ - data = GWBUF_DATA(readbuf); - nbytes_left = MYSQL_GET_PACKET_LEN(data)+MYSQL_HEADER_LEN; - /** Store new status to protocol structure */ - protocol_set_response_status(p, npackets_left, nbytes_left); - } - } - } - return outbuf; -} - - -static bool sescmd_response_complete( - DCB* dcb) -{ - int npackets_left; - ssize_t nbytes_left; - MySQLProtocol* p; - bool succp; - - p = DCB_PROTOCOL(dcb, MySQLProtocol); - if (!DCB_IS_CLONE(dcb)) CHK_PROTOCOL(p); - - protocol_get_response_status(p, &npackets_left, &nbytes_left); - - if (npackets_left == 0) - { - succp = true; - } - else - { - succp = false; - } - return succp; -} diff --git a/server/modules/protocol/mongo_client.c b/server/modules/protocol/mongo_client.c index 1de7d237d..450634e12 100644 --- a/server/modules/protocol/mongo_client.c +++ b/server/modules/protocol/mongo_client.c @@ -30,14 +30,13 @@ #include #include #include - -#include +#include MODULE_INFO info = { MODULE_API_PROTOCOL, MODULE_GA, GWPROTOCOL_VERSION, - "The client to plain protocol implementation" + "The plain client protocol" }; /** Defined in log_manager.cc */ @@ -107,201 +106,6 @@ GetModuleObject() return &MyObject; } -/** - * mysql_send_ok - * - * Send a MySQL protocol OK message to the dcb (client) - * - * @param dcb Descriptor Control Block for the connection to which the OK is sent - * @param packet_number - * @param in_affected_rows - * @param mysql_message - * @return packet length - * - */ -int -mysql_send_ok(DCB *dcb, int packet_number, int in_affected_rows, const char* mysql_message) { - return 1; -} - -/** - * MySQLSendHandshake - * - * @param dcb The descriptor control block to use for sending the handshake request - * @return The packet length sent - */ -int -MySQLSendHandshake(DCB* dcb) -{ - return 1; -} - -/** - * gw_mysql_do_authentication - * - * Performs the MySQL protocol 4.1 authentication, using data in GWBUF *queue - * - * (MYSQL_session*)client_data including: user, db, client_sha1 are copied into - * the dcb->data and later to dcb->session->data. - * - * client_capabilitiesa are copied into the dcb->protocol - * - * @param dcb Descriptor Control Block of the client - * @param queue The GWBUF with data from client - * @return 0 If succeed, otherwise non-zero value - * - * @note in case of failure, dcb->data is freed before returning. If succeed, - * dcb->data is freed in session.c:session_free. - */ -static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) { - MySQLProtocol *protocol = NULL; - /* int compress = -1; */ - int connect_with_db = -1; - uint8_t *client_auth_packet = GWBUF_DATA(queue); - int client_auth_packet_size = 0; - char *username = NULL; - char *database = NULL; - unsigned int auth_token_len = 0; - uint8_t *auth_token = NULL; - uint8_t *stage1_hash = NULL; - int auth_ret = -1; - MYSQL_session *client_data = NULL; - - CHK_DCB(dcb); - - protocol = DCB_PROTOCOL(dcb, MySQLProtocol); - CHK_PROTOCOL(protocol); - client_data = (MYSQL_session *)calloc(1, sizeof(MYSQL_session)); -#if defined(SS_DEBUG) - client_data->myses_chk_top = CHK_NUM_MYSQLSES; - client_data->myses_chk_tail = CHK_NUM_MYSQLSES; -#endif - /** - * Assign authentication structure with client DCB. - */ - dcb->data = client_data; - - stage1_hash = client_data->client_sha1; - username = client_data->user; - - client_auth_packet_size = gwbuf_length(queue); - - /* For clients supporting CLIENT_PROTOCOL_41 - * the Handshake Response Packet is: - * - * 4 bytes mysql protocol heade - * 4 bytes capability flags - * 4 max-packet size - * 1 byte character set - * string[23] reserved (all [0]) - * ... - * ... - */ - - /* Detect now if there are enough bytes to continue */ - if (client_auth_packet_size < (4 + 4 + 4 + 1 + 23)) - { - return 1; - } - - memcpy(&protocol->client_capabilities, client_auth_packet + 4, 4); - - connect_with_db = - GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB & gw_mysql_get_byte4( - (uint32_t *)&protocol->client_capabilities); - /* - compress = - GW_MYSQL_CAPABILITIES_COMPRESS & gw_mysql_get_byte4( - &protocol->client_capabilities); - */ - - username = get_username_from_auth(username, client_auth_packet); - - if (username == NULL) - { - return 1; - } - - /* get charset */ - memcpy(&protocol->charset, client_auth_packet + 4 + 4 + 4, sizeof (int)); - - /* get the auth token len */ - memcpy(&auth_token_len, - client_auth_packet + 4 + 4 + 4 + 1 + 23 + strlen(username) + 1, - 1); - - /* - * Note: some clients may pass empty database, connect_with_db !=0 but database ="" - */ - if (connect_with_db) { - database = client_data->db; - strncpy(database, - (char *)(client_auth_packet + 4 + 4 + 4 + 1 + 23 + strlen(username) + - 1 + 1 + auth_token_len), MYSQL_DATABASE_MAXLEN); - } - - /* allocate memory for token only if auth_token_len > 0 */ - if (auth_token_len) { - auth_token = (uint8_t *)malloc(auth_token_len); - memcpy(auth_token, - client_auth_packet + 4 + 4 + 4 + 1 + 23 + strlen(username) + 1 + 1, - auth_token_len); - } - - /* - * Decode the token and check the password - * Note: if auth_token_len == 0 && auth_token == NULL, user is without password - */ - - auth_ret = gw_check_mysql_scramble_data(dcb, - auth_token, - auth_token_len, - protocol->scramble, - sizeof(protocol->scramble), - username, - stage1_hash); - - /* check for database name match in resource hashtable */ - auth_ret = check_db_name_after_auth(dcb, database, auth_ret); - - /* On failed auth try to load users' table from backend database */ - if (auth_ret != 0) { - if (!service_refresh_users(dcb->service)) { - /* Try authentication again with new repository data */ - /* Note: if no auth client authentication will fail */ - auth_ret = gw_check_mysql_scramble_data( - dcb, - auth_token, - auth_token_len, - protocol->scramble, - sizeof(protocol->scramble), - username, - stage1_hash); - } - else - { - LOGIF(LM, (skygw_log_write(LOGFILE_MESSAGE, - "%s: login attempt for user %s, user not " - "found.", - dcb->service->name, username))); - } - } - - /* Do again the database check */ - auth_ret = check_db_name_after_auth(dcb, database, auth_ret); - - /* on succesful auth set user into dcb field */ - if (auth_ret == 0) { - dcb->user = strdup(client_data->user); - } - - /* let's free the auth_token now */ - if (auth_token) { - free(auth_token); - } - - return auth_ret; -} /** * Write function for client DCB: writes data from MaxScale to Client @@ -328,7 +132,7 @@ int plain_read( ROUTER_OBJECT *router = NULL; ROUTER *router_instance = NULL; void *rsession = NULL; - MySQLProtocol *protocol = NULL; + PlainProtocol *protocol = NULL; GWBUF *read_buffer = NULL; int rc = 0; int nbytes_read = 0; @@ -336,7 +140,7 @@ int plain_read( bool stmt_input = false; /*< router input type */ CHK_DCB(dcb); - protocol = DCB_PROTOCOL(dcb, MySQLProtocol); + protocol = DCB_PROTOCOL(dcb, PlainProtocol); CHK_PROTOCOL(protocol); rc = dcb_read(dcb, &read_buffer); @@ -383,7 +187,7 @@ return_rc: */ int plain_write_ready(DCB *dcb) { - MySQLProtocol *protocol = NULL; + PlainProtocol *protocol = NULL; CHK_DCB(dcb); @@ -400,7 +204,7 @@ int plain_write_ready(DCB *dcb) if (dcb->protocol == NULL) { goto return_1; } - protocol = (MySQLProtocol *)dcb->protocol; + protocol = (PlainProtocol *)dcb->protocol; dcb_drain_writeq(dcb); @@ -575,7 +379,7 @@ int plain_accept(DCB *listener) { int rc = 0; DCB *client_dcb; - MySQLProtocol *protocol; + PlainProtocol *protocol; int c_sock; struct sockaddr client_conn; socklen_t client_len = sizeof(struct sockaddr_storage); @@ -591,24 +395,12 @@ int plain_accept(DCB *listener) retry_accept: -#if defined(FAKE_CODE) - if (fail_next_accept > 0) - { - c_sock = -1; - eno = fail_accept_errno; - fail_next_accept -= 1; - } else { - fail_accept_errno = 0; -#endif /* FAKE_CODE */ // new connection from client c_sock = accept(listener->fd, (struct sockaddr *) &client_conn, &client_len); eno = errno; errno = 0; -#if defined(FAKE_CODE) - } -#endif /* FAKE_CODE */ if (c_sock == -1) { @@ -687,9 +479,7 @@ int plain_accept(DCB *listener) pthread_self(), c_sock))); #endif /* SS_DEBUG */ -#if defined(FAKE_CODE) - conn_open[c_sock] = true; -#endif /* FAKE_CODE */ + /* set nonblocking */ sendbuf = GW_CLIENT_SO_SNDBUF; @@ -762,9 +552,7 @@ int plain_accept(DCB *listener) // assign function poiters to "func" field memcpy(&client_dcb->func, &MyObject, sizeof(GWPROTOCOL)); - // client protocol state change - protocol->protocol_auth_state = MYSQL_IDLE; - + /** * Set new descriptor to event set. At the same time, * change state to DCB_STATE_POLLING so that @@ -773,12 +561,7 @@ int plain_accept(DCB *listener) if (poll_add_dcb(client_dcb) == -1) { /* Send a custom error as MySQL command reply */ - mysql_send_custom_error( - client_dcb, - 1, - 0, - "MaxScale internal error."); - + /** close client_dcb */ dcb_close(client_dcb); @@ -807,7 +590,7 @@ int plain_accept(DCB *listener) #if defined(SS_DEBUG) if (rc == 0) { CHK_DCB(client_dcb); - CHK_PROTOCOL(((MySQLProtocol *)client_dcb->protocol)); + CHK_PROTOCOL(((PlainProtocol *)client_dcb->protocol)); } #endif return_rc: @@ -851,7 +634,7 @@ plain_client_close(DCB *dcb) ROUTER_OBJECT* router; void* router_instance; #if defined(SS_DEBUG) - MySQLProtocol* protocol = (MySQLProtocol *)dcb->protocol; + PlainProtocol* protocol = (PlainProtocol *)dcb->protocol; if (dcb->state == DCB_STATE_POLLING || dcb->state == DCB_STATE_NOPOLLING || dcb->state == DCB_STATE_ZOMBIE) @@ -929,76 +712,3 @@ retblock: return 1; } - -/** - * Detect if buffer includes partial mysql packet or multiple packets. - * Store partial packet to dcb_readqueue. 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. - * - * @param session Session pointer - * @param p_readbuf Pointer to the address of GWBUF including the query - * - * @return 1 if succeed, - */ -static int route_by_statement( - SESSION* session, - GWBUF** p_readbuf) -{ - int rc; - GWBUF* packetbuf; -#if defined(SS_DEBUG) - GWBUF* tmpbuf; - - tmpbuf = *p_readbuf; - while (tmpbuf != NULL) - { - ss_dassert(GWBUF_IS_TYPE_MYSQL(tmpbuf)); - tmpbuf=tmpbuf->next; - } -#endif - do - { - ss_dassert(GWBUF_IS_TYPE_MYSQL((*p_readbuf))); - - /** - * Collect incoming bytes to a buffer until complete packet has - * arrived and then return the buffer. - */ - packetbuf = gw_MySQL_get_next_packet(p_readbuf); - - if (packetbuf != NULL) - { - CHK_GWBUF(packetbuf); - ss_dassert(GWBUF_IS_TYPE_MYSQL(packetbuf)); - /** - * This means that buffer includes exactly one MySQL - * statement. - * backend func.write uses the information. MySQL backend - * protocol, for example, stores the command identifier - * to protocol structure. When some other thread reads - * the corresponding response the command tells how to - * handle response. - * - * Set it here instead of plain_read to make - * sure it is set to each (MySQL) packet. - */ - gwbuf_set_type(packetbuf, GWBUF_TYPE_SINGLE_STMT); - /** Route query */ - rc = SESSION_ROUTE_QUERY(session, packetbuf); - } - else - { - rc = 1; - goto return_rc; - } - } - while (rc == 1 && *p_readbuf != NULL); - -return_rc: - return rc; -} -