From e767c70acb7a944a3afc6b1d26a15707f9ec7296 Mon Sep 17 00:00:00 2001 From: Massimiliano Pinto Date: Fri, 21 Jun 2013 13:05:51 +0200 Subject: [PATCH] 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 --- core/gateway_mysql_protocol.c | 3 -- modules/protocol/mysql_backend.c | 90 +++++++++++++++++++++++--------- modules/protocol/mysql_client.c | 78 ++++++++++++++++----------- modules/protocol/mysql_common.c | 78 +-------------------------- 4 files changed, 113 insertions(+), 136 deletions(-) diff --git a/core/gateway_mysql_protocol.c b/core/gateway_mysql_protocol.c index 482363ff6..dab20fd8e 100644 --- a/core/gateway_mysql_protocol.c +++ b/core/gateway_mysql_protocol.c @@ -41,9 +41,6 @@ #include #include -#define MYSQL_CONN_DEBUG -//#undef MYSQL_CONN_DEBUG - /* * mysql_send_ok * diff --git a/modules/protocol/mysql_backend.c b/modules/protocol/mysql_backend.c index 13ea697df..15944475d 100644 --- a/modules/protocol/mysql_backend.c +++ b/modules/protocol/mysql_backend.c @@ -15,8 +15,7 @@ * * Copyright SkySQL Ab 2013 */ -#include -#include + #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); } diff --git a/modules/protocol/mysql_client.c b/modules/protocol/mysql_client.c index bef625a66..938e2bb7c 100644 --- a/modules/protocol/mysql_client.c +++ b/modules/protocol/mysql_client.c @@ -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); +} diff --git a/modules/protocol/mysql_common.c b/modules/protocol/mysql_common.c index 5c7f8f60e..4d1af7618 100644 --- a/modules/protocol/mysql_common.c +++ b/modules/protocol/mysql_common.c @@ -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; -} -*/