Added backend connections via session_alloc called after AUTH_OK

the newSession calls connect_dcb and then the connect() in mysql_backend.c

The selected backend is always the last  one ath the moment.

For the transparent Authentication dcb->data is used to store MySQL session data before starting the session.

This could be revisited.


Please note the COM_QUIT in mysql_client.c has the close functionalities but they are now disabled for testing/debug
This commit is contained in:
Massimiliano Pinto 2013-06-21 13:05:51 +02:00
parent ccf658d905
commit e767c70acb
4 changed files with 113 additions and 136 deletions

View File

@ -41,9 +41,6 @@
#include <buffer.h>
#include <openssl/sha.h>
#define MYSQL_CONN_DEBUG
//#undef MYSQL_CONN_DEBUG
/*
* mysql_send_ok
*

View File

@ -15,8 +15,7 @@
*
* Copyright SkySQL Ab 2013
*/
#include <session.h>
#include <server.h>
#include "mysql_client_server_protocol.h"
/*
@ -31,11 +30,12 @@
static char *version_str = "V1.0.0";
int gw_create_backend_connection(DCB *client_dcb, SERVER *server, SESSION *in_session);
int gw_read_backend_event(DCB* dcb);
int gw_write_backend_event(DCB *dcb);
int gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue);
int gw_error_backend_event(DCB *dcb);
static int mysql_backend_connect(DCB *dcb, SERVER *server, SESSION *session);
static int gw_backend_close(DCB *dcb);
static GWPROTOCOL MyObject = {
gw_read_backend_event, /* Read - EPOLLIN handler */
@ -44,8 +44,8 @@ static GWPROTOCOL MyObject = {
gw_error_backend_event, /* Error - EPOLLERR handler */
NULL, /* HangUp - EPOLLHUP handler */
NULL, /* Accept */
NULL, /* Connect */
NULL, /* Close */
gw_create_backend_connection, /* Connect */
gw_backend_close, /* Close */
NULL /* Listen */
};
@ -266,36 +266,74 @@ int gw_error_backend_event(DCB *dcb) {
}
}
/**
* Connect to a database server
/*
* Create a new MySQL backend connection.
*
* @param dcb The DCB for the new connection
* @param server The server we are connecting to
* @param session The client session
* @return The file descriptor we conencted with
* This routine performs the MySQL connection to the backend and fills the session->backends of the callier dcb
* with the new allocatetd dcb and adds the new socket to the poll set
*
* - backend dcb allocation
* - MySQL session data fetch
* - backend connection using data in MySQL session
*
* @param client_dcb The client DCB struct
* @return 0 on Success or 1 on Failure.
*/
static int
mysql_backend_connect(DCB *dcb, SERVER *server, SESSION *session)
{
MySQLProtocol *ptr_proto = NULL;
MySQLProtocol *client_protocol = NULL;
MYSQL_session *s_data = NULL;
dcb->protocol = (MySQLProtocol *)gw_mysql_init(NULL);
/*
* This function cannot work as it will be called from mysql_client.c but it needs function pointers from mysql_backend.c
* They are modules loaded separately!!
*/
ptr_proto = (MySQLProtocol *)dcb->protocol;
int gw_create_backend_connection(DCB *backend, SERVER *server, SESSION *session) {
MySQLProtocol *ptr_proto = NULL;
MYSQL_session *s_data = NULL;
s_data = (MYSQL_session *)session->data;
fprintf(stderr, "HERE new backend dcb fd is %i, state %i\n", backend->fd, backend->state);
fprintf(stderr, "HERE, the server to connect is [%s]:[%i]\n", server->name, server->port);
backend->protocol = (MySQLProtocol *) calloc(1, sizeof(MySQLProtocol));
ptr_proto = (MySQLProtocol *)backend->protocol;
s_data = (MYSQL_session *)session->client->data;
fprintf(stderr, "HERE before connect, s_data is [%p]\n", s_data);
fprintf(stderr, "HERE before connect, username is [%s]\n", s_data->user);
// this is blocking until auth done
if (gw_mysql_connect(server->name, server->port, s_data->db, s_data->user, s_data->client_sha1, dcb->protocol) == 0) {
fprintf(stderr, "Connected to backend mysql server\n");
dcb->fd = ptr_proto->fd;
setnonblocking(dcb->fd);
if (gw_mysql_connect(server->name, server->port, s_data->db, s_data->user, s_data->client_sha1, backend->protocol) == 0) {
memcpy(&backend->fd, &ptr_proto->fd, sizeof(backend->fd));
setnonblocking(backend->fd);
fprintf(stderr, "Connected to backend mysql server. fd is %i\n", backend->fd);
} else {
fprintf(stderr, "<<<< NOT Connected to backend mysql server!!!\n");
dcb->fd = -1;
backend->fd = -1;
}
return dcb->fd;
// if connected, it will be addeed to the epoll from the caller of connect()
if (backend->fd <= 0) {
perror("ERROR: epoll_ctl: backend sock");
return 1;
} else {
fprintf(stderr, "--> Backend conn added, bk_fd [%i], scramble [%s], is session with client_fd [%i]\n", backend->fd, ptr_proto->scramble, session->client->fd);
backend->state = DCB_STATE_POLLING;
//(backend->func).read = gw_read_backend_event;
//(backend->func).write = gw_MySQLWrite_backend;
//(backend->func).write_ready = gw_write_backend_event;
//(backend->func).error = gw_error_backend_event;
return backend->fd;
}
return -1;
}
static int
gw_backend_close(DCB *dcb)
{
dcb_close(dcb);
}

View File

@ -29,7 +29,6 @@
*/
#include "mysql_client_server_protocol.h"
#include "poll.h"
static char *version_str = "V1.0.0";
@ -39,6 +38,7 @@ static int gw_read_client_event(DCB* dcb);
static int gw_write_client_event(DCB *dcb);
static int gw_MySQLWrite_client(DCB *dcb, GWBUF *queue);
static int gw_error_client_event(DCB *dcb);
static int gw_client_close(DCB *dcb);
static int gw_check_mysql_scramble_data(uint8_t *token, unsigned int token_len, uint8_t *scramble, unsigned int scramble_len, char *username, uint8_t *stage1_hash);
static int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password, void *repository);
@ -58,7 +58,7 @@ static GWPROTOCOL MyObject = {
NULL, /* HangUp - EPOLLHUP handler */
gw_MySQLAccept, /* Accept */
NULL, /* Connect */
NULL, /* Close */
gw_client_close, /* Close */
gw_MySQLListener /* Listen */
};
@ -443,7 +443,9 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) {
protocol = DCB_PROTOCOL(dcb, MySQLProtocol);
session = DCB_SESSION(dcb);
client_data = (MYSQL_session *)session->data;
client_data = (MYSQL_session *)calloc(1, sizeof(MYSQL_session));
dcb->data = client_data;
stage1_hash = client_data->client_sha1;
username = client_data->user;
@ -663,6 +665,10 @@ int w, saved_errno = 0;
* @return TRUE on error
*/
int gw_read_client_event(DCB* dcb) {
SESSION *session = NULL;
ROUTER_OBJECT *router = NULL;
ROUTER *router_instance = NULL;
void *rsession = NULL;
MySQLProtocol *protocol = NULL;
uint8_t buffer[MAX_BUFFER_SIZE] = "";
int n = 0;
@ -736,6 +742,11 @@ int gw_read_client_event(DCB* dcb) {
uint8_t *ptr_buff = NULL;
int mysql_command = -1;
int ret = -1;
session = dcb->session;
router = session->service->router;
router_instance = session->service->router_instance;
rsession = session->router_session;
//////////////////////////////////////////////////////
// read and handle errors & close, or return if busy
@ -767,11 +778,20 @@ int gw_read_client_event(DCB* dcb) {
//////////////////////////
if (mysql_command == '\x01') {
fprintf(stderr, "COM_QUIT received\n");
if (dcb->session->backends) {
dcb->session->backends->func.write(dcb, queue);
(dcb->session->backends->func).error(dcb->session->backends);
}
(dcb->func).error(dcb);
// uncomment the following lines for closing
// client and backend conns
// dcb still to be freed
// this will propagate COM_QUIT to backends
//router->routeQuery(router_instance, rsession, queue);
// close client
//(dcb->func).close(dcb);
// remove dcb
//poll_remove_dcb(dcb);
// close the session
//router->closeSession(router_instance, rsession);
// call errors, it will be removed after tests
//(dcb->func).error(dcb);
return 1;
}
@ -779,9 +799,10 @@ int gw_read_client_event(DCB* dcb) {
protocol->state = MYSQL_ROUTING;
///////////////////////////////////////
// writing in the backend buffer queue
// writing in the backend buffer queue, via routeQuery
///////////////////////////////////////
dcb->session->backends->func.write(dcb->session->backends, queue);
router->routeQuery(router_instance, rsession, queue);
protocol->state = MYSQL_WAITING_RESULT;
@ -819,29 +840,20 @@ int gw_write_client_event(DCB *dcb) {
return 1;
}
if (dcb->session) {
} else {
fprintf(stderr, "DCB session is NULL, return\n");
return 1;
}
if (dcb->session->backends) {
} else {
fprintf(stderr, "DCB backend is NULL, continue\n");
}
if(protocol->state == MYSQL_AUTH_RECV) {
SESSION *session = NULL;
MYSQL_session *s_data = dcb->data;
//write to client mysql AUTH_OK packet, packet n. is 2
//write to client mysql AUTH_OK packet, packet n. is 2
mysql_send_ok(dcb, 2, 0, NULL);
// create one backend connection
// This is not working now, as the backend dcb functions are in the mysql_protocol.c
// and it will loaded separately
//gw_create_backend_connection(dcb);
// start a new session, and connect to backends
session = session_alloc(dcb->service, dcb);
protocol->state = MYSQL_IDLE;
session->data = (MYSQL_session *)dcb->data;
return 0;
}
@ -850,8 +862,6 @@ int gw_write_client_event(DCB *dcb) {
mysql_send_auth_error(dcb, 2, 0, "Authorization failed");
dcb->func.error(dcb);
if (dcb->session->backends)
dcb->session->backends->func.error(dcb->session->backends);
return 0;
}
@ -981,6 +991,8 @@ int gw_MySQLListener(DCB *listener, char *config_bind) {
listener->state = DCB_STATE_LISTENING;
fprintf(stderr, "HERE listening\n");
return 0;
}
@ -1025,10 +1037,10 @@ int gw_MySQLAccept(DCB *listener) {
setnonblocking(c_sock);
client = alloc_dcb();
client->service = listener->session->service;
client->fd = c_sock;
client->remote = strdup(inet_ntoa(local.sin_addr));
session = session_alloc(listener->session->service, client);
client->session = session;
protocol = (MySQLProtocol *) calloc(1, sizeof(MySQLProtocol));
@ -1039,8 +1051,6 @@ int gw_MySQLAccept(DCB *listener) {
protocol->descriptor = client;
protocol->fd = c_sock;
session->backends = NULL;
// assign function poiters to "func" field
memcpy(&client->func, &MyObject, sizeof(GWPROTOCOL));
@ -1117,3 +1127,9 @@ static int gw_error_client_event(DCB *dcb) {
return 1;
}
static int
gw_client_close(DCB *dcb)
{
dcb_close(dcb);
}

View File

@ -28,9 +28,8 @@
static char *version_str = "V1.0.0";
//static int gw_create_backend_connection(DCB *client_dcb, int efd);
static MySQLProtocol *gw_mysql_init(MySQLProtocol *data);
static void gw_mysql_close(MySQLProtocol **ptr);
MySQLProtocol *gw_mysql_init(MySQLProtocol *data);
void gw_mysql_close(MySQLProtocol **ptr);
extern gw_read_backend_event(DCB* dcb);
extern gw_write_backend_event(DCB *dcb);
@ -97,76 +96,3 @@ void gw_mysql_close(MySQLProtocol **ptr) {
#endif
}
/*
* Create a new MySQL backend connection.
*
* This routine performs the MySQL connection to the backend and fills the session->backends of the callier dcb
* with the new allocatetd dcb and adds the new socket to the poll set
*
* - backend dcb allocation
* - MySQL session data fetch
* - backend connection using data in MySQL session
*
* @param client_dcb The client DCB struct
* @return 0 on Success or 1 on Failure.
*/
/*
* This function cannot work as it will be called from mysql_client.c but it needs function pointers from mysql_backend.c
* They are modules loaded separately!!
*
int gw_create_backend_connection(DCB *client_dcb) {
DCB *backend = NULL;
MySQLProtocol *ptr_proto = NULL;
MySQLProtocol *client_protocol = NULL;
SESSION *session = NULL;
MYSQL_session *s_data = NULL;
backend = (DCB *) calloc(1, sizeof(DCB));
backend->state = DCB_STATE_ALLOC;
backend->session = NULL;
backend->protocol = (MySQLProtocol *)gw_mysql_init(NULL);
ptr_proto = (MySQLProtocol *)backend->protocol;
client_protocol = (MySQLProtocol *)client_dcb->protocol;
session = DCB_SESSION(client_dcb);
s_data = (MYSQL_session *)session->data;
// this is blocking until auth done
if (gw_mysql_connect("127.0.0.1", 3306, s_data->db, s_data->user, s_data->client_sha1, backend->protocol) == 0) {
fprintf(stderr, "Connected to backend mysql server\n");
backend->fd = ptr_proto->fd;
setnonblocking(backend->fd);
} else {
fprintf(stderr, "<<<< NOT Connected to backend mysql server!!!\n");
backend->fd = -1;
}
// edge triggering flag added
ee.events = EPOLLIN | EPOLLET | EPOLLOUT;
ee.data.ptr = backend;
// if connected, add it to the epoll
if (backend->fd > 0) {
if (epoll_ctl(efd, EPOLL_CTL_ADD, backend->fd, &ee) == -1) {
perror("epoll_ctl: backend sock");
} else {
fprintf(stderr, "--> Backend conn added, bk_fd [%i], scramble [%s], is session with client_fd [%i]\n", ptr_proto->fd, ptr_proto->scramble, client_dcb->fd);
backend->state = DCB_STATE_POLLING;
backend->session = DCB_SESSION(client_dcb);
(backend->func).read = gw_read_backend_event;
(backend->func).write = gw_MySQLWrite_backend;
(backend->func).write_ready = gw_write_backend_event;
(backend->func).error = gw_error_backend_event;
// assume here one backend only.
// in session.h
// struct dcb *backends;
// instead of a list **backends;
client_dcb->session->backends = backend;
}
return 0;
}
return 1;
}
*/