moved mysql_send_custom_error to mysql_common.c
The failed backend auth now forces the closeSession and also sets thre router session = NULL This will be changed introducing another state in the session struct
This commit is contained in:
parent
e8ee2a3e9b
commit
740a001d01
@ -122,7 +122,7 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
backend_protocol = (MySQLProtocol *) dcb->protocol;
|
||||
current_session = (MYSQL_session *)dcb->session->data;
|
||||
|
||||
//fprintf(stderr, ">>> backend EPOLLIN from %i, protocol state [%s]\n", dcb->fd, gw_mysql_protocol_state2string(backend_protocol->state));
|
||||
fprintf(stderr, ">>> backend EPOLLIN from %i, protocol state [%s]\n", dcb->fd, gw_mysql_protocol_state2string(backend_protocol->state));
|
||||
|
||||
// backend is connected: read server handshake and write auth request and return
|
||||
if (backend_protocol->state == MYSQL_CONNECTED) {
|
||||
@ -135,15 +135,36 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
|
||||
// ready to check the authentication reply
|
||||
if (backend_protocol->state == MYSQL_AUTH_RECV) {
|
||||
ROUTER_OBJECT *router = NULL;
|
||||
ROUTER *router_instance = NULL;
|
||||
void *rsession = NULL;
|
||||
int rv = -1;
|
||||
SESSION *session = dcb->session;
|
||||
|
||||
if (session) {
|
||||
router = session->service->router;
|
||||
router_instance = session->service->router_instance;
|
||||
rsession = session->router_session;
|
||||
}
|
||||
|
||||
rv = gw_receive_backend_auth(backend_protocol);
|
||||
|
||||
switch (rv) {
|
||||
case MYSQL_FAILED_AUTHENTICATION:
|
||||
fprintf(stderr, ">>>> Backend Auth failed for %i\n", dcb->fd);
|
||||
|
||||
backend_protocol->state = MYSQL_AUTH_FAILED;
|
||||
|
||||
// this will close the opened backend socket
|
||||
dcb_close(dcb);
|
||||
/* send an error to the client */
|
||||
mysql_send_custom_error(dcb->session->client, 1, 0, "Connection to backend lost right now");
|
||||
|
||||
/* close the active session */
|
||||
router->closeSession(router_instance, rsession);
|
||||
|
||||
/* force the router_session to NULL
|
||||
* Later we will implement a proper status for the session
|
||||
*/
|
||||
session->router_session = NULL;
|
||||
|
||||
return 1;
|
||||
|
||||
@ -152,7 +173,7 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
|
||||
backend_protocol->state = MYSQL_IDLE;
|
||||
|
||||
// check the delay queue
|
||||
/* check the delay queue and flush the data */
|
||||
if(dcb->delayq) {
|
||||
backend_write_delayqueue(dcb);
|
||||
spinlock_release(&dcb->authlock);
|
||||
@ -163,20 +184,20 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
return 1;
|
||||
|
||||
default:
|
||||
// no other authentication state here right now, so just return
|
||||
/* no other authentication state here right now, so just return */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// reading MySQL command output from backend and writing to the client
|
||||
/* reading MySQL command output from backend and writing to the client */
|
||||
|
||||
if ((client_protocol->state == MYSQL_WAITING_RESULT) || (client_protocol->state == MYSQL_IDLE)) {
|
||||
GWBUF *head = NULL;
|
||||
|
||||
// read data
|
||||
/* read available backend data */
|
||||
dcb_read(dcb, &head);
|
||||
|
||||
// write the gwbuffer to client
|
||||
/* and write the gwbuffer to client */
|
||||
dcb->session->client->func.write(dcb->session->client, head);
|
||||
|
||||
return 1;
|
||||
@ -194,7 +215,12 @@ static int gw_read_backend_event(DCB *dcb) {
|
||||
static int gw_write_backend_event(DCB *dcb) {
|
||||
MySQLProtocol *backend_protocol = dcb->protocol;
|
||||
|
||||
//fprintf(stderr, ">>> backend EPOLLOUT %i, protocol state [%s]\n", backend_protocol->fd, gw_mysql_protocol_state2string(backend_protocol->state));
|
||||
fprintf(stderr, ">>> backend EPOLLOUT %i, protocol state [%s]\n", backend_protocol->fd, gw_mysql_protocol_state2string(backend_protocol->state));
|
||||
|
||||
if (backend_protocol->state == MYSQL_AUTH_FAILED) {
|
||||
fprintf(stderr, ">>> Backend epollout auth failed, EXIT\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// spinlock_acquire(&dcb->connectlock);
|
||||
|
||||
@ -224,11 +250,17 @@ gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue)
|
||||
{
|
||||
MySQLProtocol *backend_protocol = dcb->protocol;
|
||||
|
||||
if (backend_protocol->state == MYSQL_AUTH_FAILED) {
|
||||
fprintf(stderr, ">>> backend %i auth failed, EXIT\n", dcb->fd);
|
||||
dcb_close(dcb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
spinlock_acquire(&dcb->authlock);
|
||||
|
||||
// put incoming data to the delay queue unless backend is connected with auth ok
|
||||
if (backend_protocol->state != MYSQL_IDLE) {
|
||||
fprintf(stderr, ">>> Writing in the backend %i delay queue\n", dcb->fd);
|
||||
//fprintf(stderr, ">>> Writing in the backend %i delay queue\n", dcb->fd);
|
||||
|
||||
backend_set_delayqueue(dcb, queue);
|
||||
spinlock_release(&dcb->authlock);
|
||||
@ -315,7 +347,7 @@ static int gw_create_backend_connection(DCB *backend, SERVER *server, SESSION *s
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(stderr, "--> Backend conn added [%i], in the client session [%i]\n", backend->fd, session->client->fd);
|
||||
fprintf(stderr, ">>> Backend [%s:%i] added [%i], in the client session [%i]\n", server->name, server->port, backend->fd, session->client->fd);
|
||||
|
||||
backend->state = DCB_STATE_POLLING;
|
||||
|
||||
|
@ -180,7 +180,7 @@ mysql_send_ok(DCB *dcb, int packet_number, int in_affected_rows, const char* mys
|
||||
}
|
||||
|
||||
/**
|
||||
* mysql_send_auth_error
|
||||
* mysql_send_custom_error
|
||||
*
|
||||
* Send a MySQL protocol Generic ERR message, to the dcb
|
||||
* Note the errno and state are still fixed now
|
||||
@ -542,8 +542,6 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) {
|
||||
fprintf(stderr, "<<< Client is NOT connected with db\n");
|
||||
}
|
||||
|
||||
fprintf(stderr, "HERE auth token len is %i\n", auth_token_len);
|
||||
|
||||
// allocate memory for token only if auth_token_len > 0
|
||||
if (auth_token_len) {
|
||||
auth_token = (uint8_t *)malloc(auth_token_len);
|
||||
@ -558,10 +556,8 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) {
|
||||
if (auth_token)
|
||||
free(auth_token);
|
||||
|
||||
if (auth_ret == 0) {
|
||||
fprintf(stderr, "<<< CLIENT AUTH is OK\n");
|
||||
} else {
|
||||
fprintf(stderr, "<<< CLIENT AUTH FAILED\n");
|
||||
if (auth_ret != 0) {
|
||||
fprintf(stderr, "<<< CLIENT AUTH FAILEDi for user [%s]\n", username);
|
||||
}
|
||||
|
||||
return auth_ret;
|
||||
@ -586,7 +582,6 @@ static int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_pas
|
||||
fprintf(stderr, ">>> MYSQL user NOT FOUND: %s\n", username);
|
||||
return 1;
|
||||
}
|
||||
fprintf(stderr, ">>> MYSQL user FOUND !!!!: [%s]:[%s]\n", username, user_password);
|
||||
|
||||
// convert hex data (40 bytes) to binary (20 bytes)
|
||||
// gateway_password represents the SHA1(SHA1(real_password))
|
||||
@ -618,16 +613,14 @@ static int gw_check_mysql_scramble_data(DCB *dcb, uint8_t *token, unsigned int t
|
||||
if (ret_val) {
|
||||
fprintf(stderr, "<<<< User [%s] was not found\n", username);
|
||||
return 1;
|
||||
} else {
|
||||
fprintf(stderr, "<<<< User [%s] OK\n", username);
|
||||
}
|
||||
|
||||
if (token && token_len) {
|
||||
fprintf(stderr, ">>> continue with auth\n");
|
||||
// convert in hex format: this is the content of mysql.user table, field password without the '*' prefix
|
||||
// an it is 40 bytes long
|
||||
// and it is 40 bytes long
|
||||
gw_bin2hex(hex_double_sha1, password, SHA_DIGEST_LENGTH);
|
||||
} else {
|
||||
// check if the password is not set in the user table
|
||||
if (!strlen((char *)password)) {
|
||||
fprintf(stderr, ">>> continue WITHOUT auth, no password\n");
|
||||
return 0;
|
||||
@ -673,14 +666,12 @@ static int gw_check_mysql_scramble_data(DCB *dcb, uint8_t *token, unsigned int t
|
||||
gw_sha1_str(step2, SHA_DIGEST_LENGTH, check_hash);
|
||||
|
||||
|
||||
fprintf(stderr, "<<<< Client_SHA1 [%20s]\n", stage1_hash);
|
||||
|
||||
#ifdef GW_DEBUG_CLIENT_AUTH
|
||||
{
|
||||
char inpass[128]="";
|
||||
gw_bin2hex(inpass, check_hash, SHA_DIGEST_LENGTH);
|
||||
|
||||
//fprintf(stderr, "The CLIENT hex(SHA1(SHA1(password))) for \"%s\" is [%s]", username, inpass);
|
||||
fprintf(stderr, "The CLIENT hex(SHA1(SHA1(password))) for \"%s\" is [%s]", username, inpass);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -865,6 +856,8 @@ int gw_read_client_event(DCB* dcb) {
|
||||
int ret = -1;
|
||||
|
||||
session = dcb->session;
|
||||
|
||||
// get the backend session, if available
|
||||
if (session) {
|
||||
router = session->service->router;
|
||||
router_instance = session->service->router_instance;
|
||||
@ -877,65 +870,66 @@ int gw_read_client_event(DCB* dcb) {
|
||||
if ((ret = gw_read_gwbuff(dcb, &gw_buffer, b)) != 0)
|
||||
return ret;
|
||||
|
||||
// Now assuming in the first buffer there is the information form mysql command
|
||||
/* Now, we are assuming in the first buffer there is the information form mysql command */
|
||||
|
||||
// following code is only for debug now
|
||||
queue = gw_buffer;
|
||||
len = GWBUF_LENGTH(queue);
|
||||
|
||||
ptr_buff = GWBUF_DATA(queue);
|
||||
|
||||
// get mysql commang
|
||||
/* get mysql commang at fourth byte */
|
||||
if (ptr_buff)
|
||||
mysql_command = ptr_buff[4];
|
||||
|
||||
if (mysql_command == '\x03') {
|
||||
/// this is a query !!!!
|
||||
//fprintf(stderr, "<<< MySQL Query from Client %i bytes: [%s]\n", len, ptr_buff+5);
|
||||
//else
|
||||
//fprintf(stderr, "<<< Reading from Client %i bytes: [%s]\n", len, ptr_buff);
|
||||
/// this is a standard MySQL query !!!!
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Routing Client input to Backend
|
||||
*/
|
||||
|
||||
/* Do not route the query without session! */
|
||||
if(!rsession) {
|
||||
|
||||
if (mysql_command == '\x01') {
|
||||
fprintf(stderr, "COM_QUIT received with no connected backends\n");
|
||||
/* COM_QUIT handling */
|
||||
fprintf(stderr, "COM_QUIT received with no connected backends from %i\n", dcb->fd);
|
||||
(dcb->func).close(dcb);
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
/* Send a custom error as MySQL command reply */
|
||||
mysql_send_custom_error(dcb, 1, 0, "Connection to backend lost");
|
||||
|
||||
protocol->state = MYSQL_IDLE;
|
||||
|
||||
return 1;
|
||||
}
|
||||
mysql_send_custom_error(dcb, 1, 0, "Connection to backend lost");
|
||||
protocol->state = MYSQL_IDLE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
// Handling the COM_QUIT
|
||||
//////////////////////////
|
||||
if (mysql_command == '\x01') {
|
||||
fprintf(stderr, "COM_QUIT received\n");
|
||||
// uncomment the following lines for closing
|
||||
// client and backend conns
|
||||
// dcb still to be freed
|
||||
|
||||
/* We can route the query */
|
||||
|
||||
// this will propagate COM_QUIT to backends
|
||||
/* COM_QUIT handling */
|
||||
if (mysql_command == '\x01') {
|
||||
fprintf(stderr, "COM_QUIT received for %i\n", dcb->fd);
|
||||
|
||||
/* this will propagate COM_QUIT to backend(s) */
|
||||
fprintf(stderr, "<<< Routing the COM_QUIT ...\n");
|
||||
router->routeQuery(router_instance, rsession, queue);
|
||||
// close client
|
||||
|
||||
/* close client connection */
|
||||
(dcb->func).close(dcb);
|
||||
// call errors, it will be removed after tests
|
||||
//(dcb->func).error(dcb);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* MySQL Command Routing */
|
||||
|
||||
protocol->state = MYSQL_ROUTING;
|
||||
|
||||
///////////////////////////////////////
|
||||
// writing in the backend buffer queue, via routeQuery
|
||||
///////////////////////////////////////
|
||||
/* writing in the backend buffer queue, via routeQuery */
|
||||
|
||||
fprintf(stderr, "<<< Routing the Query ...\n");
|
||||
router->routeQuery(router_instance, rsession, queue);
|
||||
|
||||
protocol->state = MYSQL_WAITING_RESULT;
|
||||
@ -1085,7 +1079,6 @@ int gw_MySQLAccept(DCB *listener) {
|
||||
|
||||
if (c_sock == -1) {
|
||||
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
|
||||
fprintf(stderr, ">>>> NO MORE conns for MySQL Listener: errno is %i for %i\n", errno, listener->fd);
|
||||
/* We have processed all incoming connections. */
|
||||
break;
|
||||
} else {
|
||||
|
@ -22,9 +22,7 @@
|
||||
* Revision History
|
||||
* Date Who Description
|
||||
* 17/06/2013 Massimiliano Pinto Common MySQL protocol routines
|
||||
* 02/07/2013 Massimiliano Pinto MySQL connect asynchronous phases
|
||||
* 04/07/2013 Massimiliano Pinto MySQL connect routine supports EAGAIN
|
||||
* Added gw_mysql_protocol_state2string for printing MySQL the protocol status
|
||||
* 02/06/2013 Massimiliano Pinto MySQL connect asynchronous phases
|
||||
*/
|
||||
|
||||
#include "mysql_client_server_protocol.h"
|
||||
@ -464,7 +462,7 @@ int gw_do_connect_to_backend(char *host, int port, MySQLProtocol *conn) {
|
||||
if ((rv = connect(so, (struct sockaddr *)&serv_addr, sizeof(serv_addr))) < 0) {
|
||||
// If connection is not yet completed just return 1
|
||||
if (errno == EINPROGRESS) {
|
||||
fprintf(stderr, ">>> Connection not yet completed for backend server [%s:%i]: errno %i, %s: RV = [%i]\n", host, port, errno, strerror(errno), rv);
|
||||
fprintf(stderr, ">>> Connection is not yet completed for backend server [%s:%i]: errno %i, %s: RV = [%i]\n", host, port, errno, strerror(errno), rv);
|
||||
return 1;
|
||||
} else {
|
||||
// this is a real error
|
||||
@ -510,4 +508,84 @@ gw_mysql_protocol_state2string (int state) {
|
||||
return "MySQL (unknown protocol state)";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* mysql_send_custom_error
|
||||
*
|
||||
* Send a MySQL protocol Generic ERR message, to the dcb
|
||||
* Note the errno and state are still fixed now
|
||||
*
|
||||
* @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
|
||||
gw_backend_send_custom_error (DCB *dcb, int packet_number, int in_affected_rows, const char* mysql_message) {
|
||||
uint8_t *outbuf = NULL;
|
||||
uint8_t mysql_payload_size = 0;
|
||||
uint8_t mysql_packet_header[4];
|
||||
uint8_t *mysql_payload = NULL;
|
||||
uint8_t field_count = 0;
|
||||
uint8_t mysql_err[2];
|
||||
uint8_t mysql_statemsg[6];
|
||||
unsigned int mysql_errno = 0;
|
||||
const char *mysql_error_msg = NULL;
|
||||
const char *mysql_state = NULL;
|
||||
|
||||
GWBUF *buf;
|
||||
|
||||
mysql_errno = 2003;
|
||||
mysql_error_msg = "An errorr occurred ...";
|
||||
mysql_state = "HY000";
|
||||
|
||||
field_count = 0xff;
|
||||
gw_mysql_set_byte2(mysql_err, mysql_errno);
|
||||
mysql_statemsg[0]='#';
|
||||
memcpy(mysql_statemsg+1, mysql_state, 5);
|
||||
|
||||
if (mysql_message != NULL) {
|
||||
mysql_error_msg = mysql_message;
|
||||
}
|
||||
|
||||
mysql_payload_size = sizeof(field_count) + sizeof(mysql_err) + sizeof(mysql_statemsg) + strlen(mysql_error_msg);
|
||||
|
||||
// allocate memory for packet header + payload
|
||||
if ((buf = gwbuf_alloc(sizeof(mysql_packet_header) + mysql_payload_size)) == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
outbuf = GWBUF_DATA(buf);
|
||||
|
||||
// write packet header with packet number
|
||||
gw_mysql_set_byte3(mysql_packet_header, mysql_payload_size);
|
||||
mysql_packet_header[3] = packet_number;
|
||||
|
||||
// write header
|
||||
memcpy(outbuf, mysql_packet_header, sizeof(mysql_packet_header));
|
||||
|
||||
mysql_payload = outbuf + sizeof(mysql_packet_header);
|
||||
|
||||
// write field
|
||||
memcpy(mysql_payload, &field_count, sizeof(field_count));
|
||||
mysql_payload = mysql_payload + sizeof(field_count);
|
||||
|
||||
// write errno
|
||||
memcpy(mysql_payload, mysql_err, sizeof(mysql_err));
|
||||
mysql_payload = mysql_payload + sizeof(mysql_err);
|
||||
|
||||
// write sqlstate
|
||||
memcpy(mysql_payload, mysql_statemsg, sizeof(mysql_statemsg));
|
||||
mysql_payload = mysql_payload + sizeof(mysql_statemsg);
|
||||
|
||||
// write err messg
|
||||
memcpy(mysql_payload, mysql_error_msg, strlen(mysql_error_msg));
|
||||
|
||||
// writing data in the Client buffer queue
|
||||
dcb->func.write(dcb, buf);
|
||||
|
||||
return sizeof(mysql_packet_header) + mysql_payload_size;
|
||||
}
|
||||
/////
|
||||
|
Loading…
x
Reference in New Issue
Block a user