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:
@ -41,9 +41,6 @@
|
|||||||
#include <buffer.h>
|
#include <buffer.h>
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
|
|
||||||
#define MYSQL_CONN_DEBUG
|
|
||||||
//#undef MYSQL_CONN_DEBUG
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* mysql_send_ok
|
* mysql_send_ok
|
||||||
*
|
*
|
||||||
|
@ -15,8 +15,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright SkySQL Ab 2013
|
* Copyright SkySQL Ab 2013
|
||||||
*/
|
*/
|
||||||
#include <session.h>
|
|
||||||
#include <server.h>
|
|
||||||
#include "mysql_client_server_protocol.h"
|
#include "mysql_client_server_protocol.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -31,11 +30,12 @@
|
|||||||
|
|
||||||
static char *version_str = "V1.0.0";
|
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_read_backend_event(DCB* dcb);
|
||||||
int gw_write_backend_event(DCB *dcb);
|
int gw_write_backend_event(DCB *dcb);
|
||||||
int gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue);
|
int gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue);
|
||||||
int gw_error_backend_event(DCB *dcb);
|
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 = {
|
static GWPROTOCOL MyObject = {
|
||||||
gw_read_backend_event, /* Read - EPOLLIN handler */
|
gw_read_backend_event, /* Read - EPOLLIN handler */
|
||||||
@ -44,8 +44,8 @@ static GWPROTOCOL MyObject = {
|
|||||||
gw_error_backend_event, /* Error - EPOLLERR handler */
|
gw_error_backend_event, /* Error - EPOLLERR handler */
|
||||||
NULL, /* HangUp - EPOLLHUP handler */
|
NULL, /* HangUp - EPOLLHUP handler */
|
||||||
NULL, /* Accept */
|
NULL, /* Accept */
|
||||||
NULL, /* Connect */
|
gw_create_backend_connection, /* Connect */
|
||||||
NULL, /* Close */
|
gw_backend_close, /* Close */
|
||||||
NULL /* Listen */
|
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
|
* This routine performs the MySQL connection to the backend and fills the session->backends of the callier dcb
|
||||||
* @param server The server we are connecting to
|
* with the new allocatetd dcb and adds the new socket to the poll set
|
||||||
* @param session The client session
|
*
|
||||||
* @return The file descriptor we conencted with
|
* - 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)
|
/*
|
||||||
{
|
* 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 *backend, SERVER *server, SESSION *session) {
|
||||||
MySQLProtocol *ptr_proto = NULL;
|
MySQLProtocol *ptr_proto = NULL;
|
||||||
MySQLProtocol *client_protocol = NULL;
|
|
||||||
MYSQL_session *s_data = NULL;
|
MYSQL_session *s_data = NULL;
|
||||||
|
|
||||||
dcb->protocol = (MySQLProtocol *)gw_mysql_init(NULL);
|
fprintf(stderr, "HERE new backend dcb fd is %i, state %i\n", backend->fd, backend->state);
|
||||||
|
|
||||||
ptr_proto = (MySQLProtocol *)dcb->protocol;
|
fprintf(stderr, "HERE, the server to connect is [%s]:[%i]\n", server->name, server->port);
|
||||||
|
|
||||||
s_data = (MYSQL_session *)session->data;
|
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
|
// 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) {
|
if (gw_mysql_connect(server->name, server->port, s_data->db, s_data->user, s_data->client_sha1, backend->protocol) == 0) {
|
||||||
fprintf(stderr, "Connected to backend mysql server\n");
|
memcpy(&backend->fd, &ptr_proto->fd, sizeof(backend->fd));
|
||||||
dcb->fd = ptr_proto->fd;
|
|
||||||
setnonblocking(dcb->fd);
|
setnonblocking(backend->fd);
|
||||||
|
fprintf(stderr, "Connected to backend mysql server. fd is %i\n", backend->fd);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "<<<< NOT Connected to backend mysql server!!!\n");
|
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);
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "mysql_client_server_protocol.h"
|
#include "mysql_client_server_protocol.h"
|
||||||
#include "poll.h"
|
|
||||||
|
|
||||||
static char *version_str = "V1.0.0";
|
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_write_client_event(DCB *dcb);
|
||||||
static int gw_MySQLWrite_client(DCB *dcb, GWBUF *queue);
|
static int gw_MySQLWrite_client(DCB *dcb, GWBUF *queue);
|
||||||
static int gw_error_client_event(DCB *dcb);
|
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_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);
|
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 */
|
NULL, /* HangUp - EPOLLHUP handler */
|
||||||
gw_MySQLAccept, /* Accept */
|
gw_MySQLAccept, /* Accept */
|
||||||
NULL, /* Connect */
|
NULL, /* Connect */
|
||||||
NULL, /* Close */
|
gw_client_close, /* Close */
|
||||||
gw_MySQLListener /* Listen */
|
gw_MySQLListener /* Listen */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -443,7 +443,9 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) {
|
|||||||
protocol = DCB_PROTOCOL(dcb, MySQLProtocol);
|
protocol = DCB_PROTOCOL(dcb, MySQLProtocol);
|
||||||
|
|
||||||
session = DCB_SESSION(dcb);
|
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;
|
stage1_hash = client_data->client_sha1;
|
||||||
username = client_data->user;
|
username = client_data->user;
|
||||||
@ -663,6 +665,10 @@ int w, saved_errno = 0;
|
|||||||
* @return TRUE on error
|
* @return TRUE on error
|
||||||
*/
|
*/
|
||||||
int gw_read_client_event(DCB* dcb) {
|
int gw_read_client_event(DCB* dcb) {
|
||||||
|
SESSION *session = NULL;
|
||||||
|
ROUTER_OBJECT *router = NULL;
|
||||||
|
ROUTER *router_instance = NULL;
|
||||||
|
void *rsession = NULL;
|
||||||
MySQLProtocol *protocol = NULL;
|
MySQLProtocol *protocol = NULL;
|
||||||
uint8_t buffer[MAX_BUFFER_SIZE] = "";
|
uint8_t buffer[MAX_BUFFER_SIZE] = "";
|
||||||
int n = 0;
|
int n = 0;
|
||||||
@ -737,6 +743,11 @@ int gw_read_client_event(DCB* dcb) {
|
|||||||
int mysql_command = -1;
|
int mysql_command = -1;
|
||||||
int ret = -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
|
// read and handle errors & close, or return if busy
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
@ -767,11 +778,20 @@ int gw_read_client_event(DCB* dcb) {
|
|||||||
//////////////////////////
|
//////////////////////////
|
||||||
if (mysql_command == '\x01') {
|
if (mysql_command == '\x01') {
|
||||||
fprintf(stderr, "COM_QUIT received\n");
|
fprintf(stderr, "COM_QUIT received\n");
|
||||||
if (dcb->session->backends) {
|
// uncomment the following lines for closing
|
||||||
dcb->session->backends->func.write(dcb, queue);
|
// client and backend conns
|
||||||
(dcb->session->backends->func).error(dcb->session->backends);
|
// dcb still to be freed
|
||||||
}
|
|
||||||
(dcb->func).error(dcb);
|
// 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;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -779,9 +799,10 @@ int gw_read_client_event(DCB* dcb) {
|
|||||||
protocol->state = MYSQL_ROUTING;
|
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;
|
protocol->state = MYSQL_WAITING_RESULT;
|
||||||
|
|
||||||
@ -819,29 +840,20 @@ int gw_write_client_event(DCB *dcb) {
|
|||||||
return 1;
|
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) {
|
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);
|
mysql_send_ok(dcb, 2, 0, NULL);
|
||||||
|
|
||||||
// create one backend connection
|
// start a new session, and connect to backends
|
||||||
// This is not working now, as the backend dcb functions are in the mysql_protocol.c
|
session = session_alloc(dcb->service, dcb);
|
||||||
// and it will loaded separately
|
|
||||||
//gw_create_backend_connection(dcb);
|
|
||||||
|
|
||||||
protocol->state = MYSQL_IDLE;
|
protocol->state = MYSQL_IDLE;
|
||||||
|
|
||||||
|
session->data = (MYSQL_session *)dcb->data;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -850,8 +862,6 @@ int gw_write_client_event(DCB *dcb) {
|
|||||||
mysql_send_auth_error(dcb, 2, 0, "Authorization failed");
|
mysql_send_auth_error(dcb, 2, 0, "Authorization failed");
|
||||||
|
|
||||||
dcb->func.error(dcb);
|
dcb->func.error(dcb);
|
||||||
if (dcb->session->backends)
|
|
||||||
dcb->session->backends->func.error(dcb->session->backends);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -981,6 +991,8 @@ int gw_MySQLListener(DCB *listener, char *config_bind) {
|
|||||||
|
|
||||||
listener->state = DCB_STATE_LISTENING;
|
listener->state = DCB_STATE_LISTENING;
|
||||||
|
|
||||||
|
fprintf(stderr, "HERE listening\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1025,10 +1037,10 @@ int gw_MySQLAccept(DCB *listener) {
|
|||||||
setnonblocking(c_sock);
|
setnonblocking(c_sock);
|
||||||
|
|
||||||
client = alloc_dcb();
|
client = alloc_dcb();
|
||||||
|
client->service = listener->session->service;
|
||||||
client->fd = c_sock;
|
client->fd = c_sock;
|
||||||
client->remote = strdup(inet_ntoa(local.sin_addr));
|
client->remote = strdup(inet_ntoa(local.sin_addr));
|
||||||
|
|
||||||
session = session_alloc(listener->session->service, client);
|
|
||||||
client->session = session;
|
client->session = session;
|
||||||
|
|
||||||
protocol = (MySQLProtocol *) calloc(1, sizeof(MySQLProtocol));
|
protocol = (MySQLProtocol *) calloc(1, sizeof(MySQLProtocol));
|
||||||
@ -1039,8 +1051,6 @@ int gw_MySQLAccept(DCB *listener) {
|
|||||||
protocol->descriptor = client;
|
protocol->descriptor = client;
|
||||||
protocol->fd = c_sock;
|
protocol->fd = c_sock;
|
||||||
|
|
||||||
session->backends = NULL;
|
|
||||||
|
|
||||||
// assign function poiters to "func" field
|
// assign function poiters to "func" field
|
||||||
memcpy(&client->func, &MyObject, sizeof(GWPROTOCOL));
|
memcpy(&client->func, &MyObject, sizeof(GWPROTOCOL));
|
||||||
|
|
||||||
@ -1117,3 +1127,9 @@ static int gw_error_client_event(DCB *dcb) {
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
gw_client_close(DCB *dcb)
|
||||||
|
{
|
||||||
|
dcb_close(dcb);
|
||||||
|
}
|
||||||
|
@ -28,9 +28,8 @@
|
|||||||
|
|
||||||
static char *version_str = "V1.0.0";
|
static char *version_str = "V1.0.0";
|
||||||
|
|
||||||
//static int gw_create_backend_connection(DCB *client_dcb, int efd);
|
MySQLProtocol *gw_mysql_init(MySQLProtocol *data);
|
||||||
static MySQLProtocol *gw_mysql_init(MySQLProtocol *data);
|
void gw_mysql_close(MySQLProtocol **ptr);
|
||||||
static void gw_mysql_close(MySQLProtocol **ptr);
|
|
||||||
|
|
||||||
extern gw_read_backend_event(DCB* dcb);
|
extern gw_read_backend_event(DCB* dcb);
|
||||||
extern gw_write_backend_event(DCB *dcb);
|
extern gw_write_backend_event(DCB *dcb);
|
||||||
@ -97,76 +96,3 @@ void gw_mysql_close(MySQLProtocol **ptr) {
|
|||||||
#endif
|
#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;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
Reference in New Issue
Block a user