Merge branch 'MXS-544' into develop-MXS-544-merge
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
add_library(maxscale-common SHARED adminusers.c atomic.c buffer.c config.c dbusers.c dcb.c filter.c externcmd.c gwbitmask.c gwdirs.c gw_utils.c hashtable.c hint.c housekeeper.c load_utils.c log_manager.cc maxscale_pcre2.c memlog.c misc.c mlist.c modutil.c monitor.c query_classifier.c poll.c random_jkiss.c resultset.c secrets.c server.c service.c session.c slist.c spinlock.c thread.c users.c utils.c ${CMAKE_SOURCE_DIR}/utils/skygw_utils.cc statistics.c)
|
||||
add_library(maxscale-common SHARED adminusers.c atomic.c buffer.c config.c dbusers.c dcb.c filter.c externcmd.c gwbitmask.c gwdirs.c gw_utils.c hashtable.c hint.c housekeeper.c load_utils.c log_manager.cc maxscale_pcre2.c memlog.c misc.c mlist.c modutil.c monitor.c query_classifier.c poll.c random_jkiss.c resultset.c secrets.c server.c service.c session.c slist.c spinlock.c thread.c users.c utils.c ${CMAKE_SOURCE_DIR}/utils/skygw_utils.cc statistics.c listener.c gw_ssl.c)
|
||||
|
||||
target_link_libraries(maxscale-common ${MARIADB_CONNECTOR_LIBRARIES} ${LZMA_LINK_FLAGS} ${PCRE2_LIBRARIES} ${CURL_LIBRARIES} ssl aio pthread crypt dl crypto inih z rt m stdc++)
|
||||
|
||||
|
@ -43,7 +43,8 @@
|
||||
* 20/02/15 Markus Mäkelä Added connection_timeout parameter for services
|
||||
* 05/03/15 Massimiliano Pinto Added notification_feedback support
|
||||
* 20/04/15 Guillaume Lefranc Added available_when_donor parameter
|
||||
* 22/04/15 Martin Brampton Added disable_master_role_setting parameter
|
||||
* 22/04/15 Martin Brampton Added disable_master_role_setting parameter
|
||||
* 26/01/16 Martin Brampton Transfer SSL processing to listener
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
@ -90,6 +91,8 @@ static void global_defaults();
|
||||
static void feedback_defaults();
|
||||
static void check_config_objects(CONFIG_CONTEXT *context);
|
||||
static int maxscale_getline(char** dest, int* size, FILE* file);
|
||||
static SSL_LISTENER *make_ssl_structure(CONFIG_CONTEXT *obj, bool require_cert, int *error_count);
|
||||
|
||||
int config_truth_value(char *str);
|
||||
int config_get_ifaddr(unsigned char *output);
|
||||
int config_get_release_string(char* release);
|
||||
@ -99,7 +102,7 @@ bool config_has_duplicate_sections(const char* config);
|
||||
int create_new_service(CONFIG_CONTEXT *obj);
|
||||
int create_new_server(CONFIG_CONTEXT *obj);
|
||||
int create_new_monitor(CONFIG_CONTEXT *context, CONFIG_CONTEXT *obj, HASHTABLE* monitorhash);
|
||||
int create_new_listener(CONFIG_CONTEXT *obj);
|
||||
int create_new_listener(CONFIG_CONTEXT *obj, bool startnow);
|
||||
int create_new_filter(CONFIG_CONTEXT *obj);
|
||||
int configure_new_service(CONFIG_CONTEXT *context, CONFIG_CONTEXT *obj);
|
||||
|
||||
@ -130,12 +133,6 @@ static char *service_params[] =
|
||||
"version_string",
|
||||
"filters",
|
||||
"weightby",
|
||||
"ssl_cert",
|
||||
"ssl_ca_cert",
|
||||
"ssl",
|
||||
"ssl_key",
|
||||
"ssl_version",
|
||||
"ssl_cert_verify_depth",
|
||||
"ignore_databases",
|
||||
"ignore_databases_regex",
|
||||
"log_auth_warnings",
|
||||
@ -150,6 +147,13 @@ static char *listener_params[] =
|
||||
"port",
|
||||
"address",
|
||||
"socket",
|
||||
"authenticator",
|
||||
"ssl_cert",
|
||||
"ssl_ca_cert",
|
||||
"ssl",
|
||||
"ssl_key",
|
||||
"ssl_version",
|
||||
"ssl_cert_verify_depth",
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -186,6 +190,14 @@ static char *server_params[] =
|
||||
"monitorpw",
|
||||
"persistpoolmax",
|
||||
"persistmaxtime",
|
||||
/* The following, or something similar, will be needed for backend SSL
|
||||
"ssl_cert",
|
||||
"ssl_ca_cert",
|
||||
"ssl",
|
||||
"ssl_key",
|
||||
"ssl_version",
|
||||
"ssl_cert_verify_depth",
|
||||
*/
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -547,7 +559,7 @@ process_config_context(CONFIG_CONTEXT *context)
|
||||
}
|
||||
else if (!strcmp(type, "listener"))
|
||||
{
|
||||
error_count += create_new_listener(obj);
|
||||
error_count += create_new_listener(obj, false);
|
||||
}
|
||||
else if (!strcmp(type, "monitor"))
|
||||
{
|
||||
@ -876,6 +888,7 @@ static struct
|
||||
{ "log_info", LOG_INFO, NULL },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
/**
|
||||
* Configuration handler for items in the global [MaxScale] section
|
||||
*
|
||||
@ -1005,6 +1018,127 @@ handle_global_item(const char *name, const char *value)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form an SSL structure from listener section parameters
|
||||
*
|
||||
* @param obj The configuration object for the item being created
|
||||
* @param require_cert Whether a certificate and key are required
|
||||
* @param *error_count An error count which may be incremented
|
||||
* @return SSL_LISTENER structure or NULL
|
||||
*/
|
||||
static SSL_LISTENER *
|
||||
make_ssl_structure (CONFIG_CONTEXT *obj, bool require_cert, int *error_count)
|
||||
{
|
||||
char *ssl, *ssl_version, *ssl_cert, *ssl_key, *ssl_ca_cert, *ssl_cert_verify_depth;
|
||||
int local_errors = 0;
|
||||
SSL_LISTENER *new_ssl;
|
||||
|
||||
ssl = config_get_value(obj->parameters, "ssl");
|
||||
if (ssl && !strcmp(ssl, "required"))
|
||||
{
|
||||
if ((new_ssl = malloc(sizeof(SSL_LISTENER))) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
new_ssl->ssl_method_type = SERVICE_SSL_TLS_MAX;
|
||||
ssl_cert = config_get_value(obj->parameters, "ssl_cert");
|
||||
ssl_key = config_get_value(obj->parameters, "ssl_key");
|
||||
ssl_ca_cert = config_get_value(obj->parameters, "ssl_ca_cert");
|
||||
ssl_version = config_get_value(obj->parameters, "ssl_version");
|
||||
ssl_cert_verify_depth = config_get_value(obj->parameters, "ssl_cert_verify_depth");
|
||||
new_ssl->ssl_init_done = false;
|
||||
|
||||
if (ssl_version)
|
||||
{
|
||||
if (listener_set_ssl_version(new_ssl, ssl_version) != 0)
|
||||
{
|
||||
MXS_ERROR("Unknown parameter value for 'ssl_version' for"
|
||||
" service '%s': %s", obj->object, ssl_version);
|
||||
local_errors++;
|
||||
}
|
||||
}
|
||||
|
||||
if (ssl_cert_verify_depth)
|
||||
{
|
||||
new_ssl->ssl_cert_verify_depth = atoi(ssl_cert_verify_depth);
|
||||
if (new_ssl->ssl_cert_verify_depth < 0)
|
||||
{
|
||||
MXS_ERROR("Invalid parameter value for 'ssl_cert_verify_depth"
|
||||
" for service '%s': %s", obj->object, ssl_cert_verify_depth);
|
||||
new_ssl->ssl_cert_verify_depth = 0;
|
||||
local_errors++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
* Default of 9 as per Linux man page
|
||||
*/
|
||||
new_ssl->ssl_cert_verify_depth = 9;
|
||||
}
|
||||
|
||||
listener_set_certificates(new_ssl, ssl_cert, ssl_key, ssl_ca_cert);
|
||||
|
||||
if (require_cert && new_ssl->ssl_cert == NULL)
|
||||
{
|
||||
local_errors++;
|
||||
MXS_ERROR("Server certificate missing for service '%s'."
|
||||
"Please provide the path to the server certificate by adding "
|
||||
"the ssl_cert=<path> parameter", obj->object);
|
||||
}
|
||||
|
||||
if (new_ssl->ssl_ca_cert == NULL)
|
||||
{
|
||||
local_errors++;
|
||||
MXS_ERROR("CA Certificate missing for service '%s'."
|
||||
"Please provide the path to the certificate authority "
|
||||
"certificate by adding the ssl_ca_cert=<path> parameter",
|
||||
obj->object);
|
||||
}
|
||||
|
||||
if (require_cert && new_ssl->ssl_key == NULL)
|
||||
{
|
||||
local_errors++;
|
||||
MXS_ERROR("Server private key missing for service '%s'. "
|
||||
"Please provide the path to the server certificate key by "
|
||||
"adding the ssl_key=<path> parameter",
|
||||
obj->object);
|
||||
}
|
||||
|
||||
if (access(new_ssl->ssl_ca_cert, F_OK) != 0)
|
||||
{
|
||||
MXS_ERROR("Certificate authority file for service '%s' not found: %s",
|
||||
obj->object,
|
||||
new_ssl->ssl_ca_cert);
|
||||
local_errors++;
|
||||
}
|
||||
|
||||
if (require_cert && access(new_ssl->ssl_cert, F_OK) != 0)
|
||||
{
|
||||
MXS_ERROR("Server certificate file for service '%s' not found: %s",
|
||||
obj->object,
|
||||
new_ssl->ssl_cert);
|
||||
local_errors++;
|
||||
}
|
||||
|
||||
if (require_cert && access(new_ssl->ssl_key, F_OK) != 0)
|
||||
{
|
||||
MXS_ERROR("Server private key file for service '%s' not found: %s",
|
||||
obj->object,
|
||||
new_ssl->ssl_key);
|
||||
local_errors++;
|
||||
}
|
||||
|
||||
if (0 == local_errors)
|
||||
{
|
||||
return new_ssl;
|
||||
}
|
||||
*error_count += local_errors;
|
||||
free(new_ssl);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration handler for items in the feedback [feedback] section
|
||||
*
|
||||
@ -1375,52 +1509,7 @@ process_config_update(CONFIG_CONTEXT *context)
|
||||
}
|
||||
else if (!strcmp(type, "listener"))
|
||||
{
|
||||
char *service;
|
||||
char *port;
|
||||
char *protocol;
|
||||
char *address;
|
||||
char *socket;
|
||||
|
||||
service = config_get_value(obj->parameters, "service");
|
||||
address = config_get_value(obj->parameters, "address");
|
||||
port = config_get_value(obj->parameters, "port");
|
||||
protocol = config_get_value(obj->parameters, "protocol");
|
||||
socket = config_get_value(obj->parameters, "socket");
|
||||
|
||||
if (service && socket && protocol)
|
||||
{
|
||||
CONFIG_CONTEXT *ptr = context;
|
||||
while (ptr && strcmp(ptr->object, service) != 0)
|
||||
{
|
||||
ptr = ptr->next;
|
||||
}
|
||||
|
||||
if (ptr &&
|
||||
ptr->element &&
|
||||
serviceHasProtocol(ptr->element, protocol, 0) == 0)
|
||||
{
|
||||
serviceAddProtocol(ptr->element, protocol, socket, 0);
|
||||
serviceStartProtocol(ptr->element, protocol, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (service && port && protocol)
|
||||
{
|
||||
CONFIG_CONTEXT *ptr = context;
|
||||
|
||||
while (ptr && strcmp(ptr->object, service) != 0)
|
||||
{
|
||||
ptr = ptr->next;
|
||||
}
|
||||
|
||||
if (ptr &&
|
||||
ptr->element &&
|
||||
serviceHasProtocol(ptr->element, protocol, atoi(port)) == 0)
|
||||
{
|
||||
serviceAddProtocol(ptr->element, protocol, address, atoi(port));
|
||||
serviceStartProtocol(ptr->element, protocol, atoi(port));
|
||||
}
|
||||
}
|
||||
create_new_listener(obj, true);
|
||||
}
|
||||
else if (strcmp(type, "server") != 0 &&
|
||||
strcmp(type, "monitor") != 0 &&
|
||||
@ -2239,6 +2328,7 @@ int create_new_service(CONFIG_CONTEXT *obj)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
char *ssl = config_get_value(obj->parameters, "ssl");
|
||||
if (ssl)
|
||||
{
|
||||
@ -2282,6 +2372,7 @@ int create_new_service(CONFIG_CONTEXT *obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/** Parameters for rwsplit router only */
|
||||
if (strcmp(router, "readwritesplit") == 0)
|
||||
@ -2414,6 +2505,8 @@ int create_new_server(CONFIG_CONTEXT *obj)
|
||||
|
||||
CONFIG_PARAMETER *params = obj->parameters;
|
||||
|
||||
server->server_ssl = make_ssl_structure(obj, false, &error_count);
|
||||
|
||||
while (params)
|
||||
{
|
||||
if (!is_normal_server_parameter(params->name))
|
||||
@ -2634,9 +2727,10 @@ int create_new_monitor(CONFIG_CONTEXT *context, CONFIG_CONTEXT *obj, HASHTABLE*
|
||||
/**
|
||||
* Create a new listener for a service
|
||||
* @param obj Listener configuration context
|
||||
* @param startnow If true, start the listener now
|
||||
* @return Number of errors
|
||||
*/
|
||||
int create_new_listener(CONFIG_CONTEXT *obj)
|
||||
int create_new_listener(CONFIG_CONTEXT *obj, bool startnow)
|
||||
{
|
||||
int error_count = 0;
|
||||
char *service_name = config_get_value(obj->parameters, "service");
|
||||
@ -2644,20 +2738,52 @@ int create_new_listener(CONFIG_CONTEXT *obj)
|
||||
char *address = config_get_value(obj->parameters, "address");
|
||||
char *protocol = config_get_value(obj->parameters, "protocol");
|
||||
char *socket = config_get_value(obj->parameters, "socket");
|
||||
char *authenticator = config_get_value(obj->parameters, "authenticator");
|
||||
|
||||
if (service_name && protocol && (socket || port))
|
||||
{
|
||||
SERVICE *service = service_find(service_name);
|
||||
if (service)
|
||||
{
|
||||
SSL_LISTENER *ssl_info = make_ssl_structure(obj, true, &error_count);
|
||||
if (socket)
|
||||
{
|
||||
serviceAddProtocol(service, protocol, socket, 0);
|
||||
if (serviceHasProtocol(service, protocol, 0))
|
||||
{
|
||||
MXS_ERROR("Listener '%s', for service '%s', socket %s, already have socket.",
|
||||
obj->object,
|
||||
service_name,
|
||||
socket);
|
||||
error_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
serviceAddProtocol(service, protocol, socket, 0, authenticator, ssl_info);
|
||||
if (startnow)
|
||||
{
|
||||
serviceStartProtocol(service, protocol, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (port)
|
||||
{
|
||||
serviceAddProtocol(service, protocol, address, atoi(port));
|
||||
if (serviceHasProtocol(service, protocol, atoi(port)))
|
||||
{
|
||||
MXS_ERROR("Listener '%s', for service '%s', already have port %s.",
|
||||
obj->object,
|
||||
service_name,
|
||||
port);
|
||||
error_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
serviceAddProtocol(service, protocol, address, atoi(port), authenticator, ssl_info);
|
||||
if (startnow)
|
||||
{
|
||||
serviceStartProtocol(service, protocol, atoi(port));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -61,6 +61,8 @@
|
||||
* 17/10/2015 Martin Brampton Add hangup for each and bitmask display MaxAdmin
|
||||
* 15/12/2015 Martin Brampton Merge most of SSL write code into non-SSL,
|
||||
* enhance SSL code
|
||||
* 07/02/2016 Martin Brampton Make dcb_read_SSL & dcb_create_SSL internal,
|
||||
* further small SSL logic changes
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
@ -111,6 +113,8 @@ static bool dcb_maybe_add_persistent(DCB *);
|
||||
static inline bool dcb_write_parameter_check(DCB *dcb, GWBUF *queue);
|
||||
static int dcb_bytes_readable(DCB *dcb);
|
||||
static int dcb_read_no_bytes_available(DCB *dcb, int nreadtotal);
|
||||
static int dcb_create_SSL(DCB* dcb);
|
||||
static int dcb_read_SSL(DCB *dcb, GWBUF **head);
|
||||
static GWBUF *dcb_basic_read(DCB *dcb, int bytesavailable, int maxbytes, int nreadtotal, int *nsingleread);
|
||||
static GWBUF *dcb_basic_read_SSL(DCB *dcb, int *nsingleread);
|
||||
#if defined(FAKE_CODE)
|
||||
@ -118,7 +122,6 @@ static inline void dcb_write_fake_code(DCB *dcb);
|
||||
#endif
|
||||
static void dcb_log_write_failure(DCB *dcb, GWBUF *queue, int eno);
|
||||
static inline void dcb_write_tidy_up(DCB *dcb, bool below_water);
|
||||
static void dcb_log_ssl_read_error(DCB *dcb, int ssl_errno, int rc);
|
||||
static int gw_write(DCB *dcb, bool *stop_writing);
|
||||
static int gw_write_SSL(DCB *dcb, bool *stop_writing);
|
||||
static void dcb_log_errors_SSL (DCB *dcb, const char *called_by, int ret);
|
||||
@ -223,6 +226,9 @@ dcb_alloc(dcb_role_t role)
|
||||
newdcb->callbacks = NULL;
|
||||
newdcb->data = NULL;
|
||||
|
||||
newdcb->listen_ssl = NULL;
|
||||
newdcb->ssl_state = SSL_HANDSHAKE_UNKNOWN;
|
||||
|
||||
newdcb->remote = NULL;
|
||||
newdcb->user = NULL;
|
||||
newdcb->flags = 0;
|
||||
@ -279,6 +285,8 @@ dcb_clone(DCB *orig)
|
||||
clonedcb->flags |= DCBF_CLONE;
|
||||
clonedcb->state = orig->state;
|
||||
clonedcb->data = orig->data;
|
||||
clonedcb->listen_ssl = orig->listen_ssl;
|
||||
clonedcb->ssl_state = orig->ssl_state;
|
||||
if (orig->remote)
|
||||
{
|
||||
clonedcb->remote = strdup(orig->remote);
|
||||
@ -310,8 +318,6 @@ dcb_clone(DCB *orig)
|
||||
static void
|
||||
dcb_final_free(DCB *dcb)
|
||||
{
|
||||
DCB_CALLBACK *cb;
|
||||
|
||||
CHK_DCB(dcb);
|
||||
ss_info_dassert(dcb->state == DCB_STATE_DISCONNECTED ||
|
||||
dcb->state == DCB_STATE_ALLOC,
|
||||
@ -360,22 +366,35 @@ dcb_final_free(DCB *dcb)
|
||||
SESSION *local_session = dcb->session;
|
||||
dcb->session = NULL;
|
||||
CHK_SESSION(local_session);
|
||||
/**
|
||||
* Set session's client pointer NULL so that other threads
|
||||
* won't try to call dcb_close for client DCB
|
||||
* after this call.
|
||||
*/
|
||||
if (local_session->client == dcb)
|
||||
{
|
||||
spinlock_acquire(&local_session->ses_lock);
|
||||
local_session->client = NULL;
|
||||
spinlock_release(&local_session->ses_lock);
|
||||
}
|
||||
if (SESSION_STATE_DUMMY != local_session->state)
|
||||
{
|
||||
session_free(local_session);
|
||||
|
||||
if (local_session->client_dcb == dcb)
|
||||
{
|
||||
/** The client DCB is freed once all other DCBs that the session
|
||||
* uses have been freed. This will guarantee that the authentication
|
||||
* data will be usable for all DCBs even if the client DCB has already
|
||||
* been closed. */
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
dcb_free_all_memory(dcb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the memory belonging to a DCB
|
||||
*
|
||||
* NB The DCB is fully detached from all links except perhaps the session
|
||||
* dcb_client link.
|
||||
*
|
||||
* @param dcb The DCB to free
|
||||
*/
|
||||
void
|
||||
dcb_free_all_memory(DCB *dcb)
|
||||
{
|
||||
DCB_CALLBACK *cb_dcb;
|
||||
|
||||
if (dcb->protocol && (!DCB_IS_CLONE(dcb)))
|
||||
{
|
||||
@ -412,10 +431,10 @@ dcb_final_free(DCB *dcb)
|
||||
}
|
||||
|
||||
spinlock_acquire(&dcb->cb_lock);
|
||||
while ((cb = dcb->callbacks) != NULL)
|
||||
while ((cb_dcb = dcb->callbacks) != NULL)
|
||||
{
|
||||
dcb->callbacks = cb->next;
|
||||
free(cb);
|
||||
dcb->callbacks = cb_dcb->next;
|
||||
free(cb_dcb);
|
||||
}
|
||||
spinlock_release(&dcb->cb_lock);
|
||||
if (dcb->ssl)
|
||||
@ -771,8 +790,8 @@ dcb_connect(SERVER *server, SESSION *session, const char *protocol)
|
||||
server->name,
|
||||
server->port,
|
||||
dcb,
|
||||
session->client,
|
||||
session->client->fd);
|
||||
session->client_dcb,
|
||||
session->client_dcb->fd);
|
||||
dcb->state = DCB_STATE_DISCONNECTED;
|
||||
dcb_final_free(dcb);
|
||||
return NULL;
|
||||
@ -785,8 +804,8 @@ dcb_connect(SERVER *server, SESSION *session, const char *protocol)
|
||||
server->name,
|
||||
server->port,
|
||||
dcb,
|
||||
session->client,
|
||||
session->client->fd);
|
||||
session->client_dcb,
|
||||
session->client_dcb->fd);
|
||||
}
|
||||
/**
|
||||
* Successfully connected to backend. Assign file descriptor to dcb
|
||||
@ -848,6 +867,11 @@ int dcb_read(DCB *dcb,
|
||||
int nsingleread = 0;
|
||||
int nreadtotal = 0;
|
||||
|
||||
if (SSL_HANDSHAKE_DONE == dcb->ssl_state || SSL_ESTABLISHED == dcb->ssl_state)
|
||||
{
|
||||
return dcb_read_SSL(dcb, head);
|
||||
}
|
||||
|
||||
CHK_DCB(dcb);
|
||||
|
||||
if (dcb->fd <= 0)
|
||||
@ -1043,7 +1067,7 @@ dcb_basic_read(DCB *dcb, int bytesavailable, int maxbytes, int nreadtotal, int *
|
||||
* @param head Pointer to linked list to append data to
|
||||
* @return -1 on error, otherwise the total number of bytes read
|
||||
*/
|
||||
int
|
||||
static int
|
||||
dcb_read_SSL(DCB *dcb, GWBUF **head)
|
||||
{
|
||||
GWBUF *buffer = NULL;
|
||||
@ -1070,7 +1094,7 @@ dcb_read_SSL(DCB *dcb, GWBUF **head)
|
||||
nreadtotal += nsingleread;
|
||||
*head = gwbuf_append(*head, buffer);
|
||||
|
||||
while (buffer || SSL_pending(dcb->ssl))
|
||||
while (SSL_pending(dcb->ssl))
|
||||
{
|
||||
dcb->last_read = hkheartbeat;
|
||||
buffer = dcb_basic_read_SSL(dcb, &nsingleread);
|
||||
@ -1219,14 +1243,17 @@ dcb_log_errors_SSL (DCB *dcb, const char *called_by, int ret)
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
unsigned long ssl_errno;
|
||||
|
||||
MXS_ERROR("SSL operation failed in %s, dcb %p in state "
|
||||
"%s fd %d. More details may follow.",
|
||||
called_by,
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd);
|
||||
|
||||
ssl_errno = ERR_get_error();
|
||||
if (ret || ssl_errno)
|
||||
{
|
||||
MXS_ERROR("SSL operation failed in %s, dcb %p in state "
|
||||
"%s fd %d return code %d. More details may follow.",
|
||||
called_by,
|
||||
dcb,
|
||||
STRDCBSTATE(dcb->state),
|
||||
dcb->fd,
|
||||
ret);
|
||||
}
|
||||
if (ret && !ssl_errno)
|
||||
{
|
||||
int local_errno = errno;
|
||||
@ -1455,8 +1482,6 @@ dcb_log_write_failure(DCB *dcb, GWBUF *queue, int eno)
|
||||
static inline void
|
||||
dcb_write_tidy_up(DCB *dcb, bool below_water)
|
||||
{
|
||||
spinlock_release(&dcb->writeqlock);
|
||||
|
||||
if (dcb->high_water && dcb->writeqlen > dcb->high_water && below_water)
|
||||
{
|
||||
atomic_add(&dcb->stats.n_high_water, 1);
|
||||
@ -2116,9 +2141,9 @@ dcb_isclient(DCB *dcb)
|
||||
{
|
||||
if (dcb->state != DCB_STATE_LISTENING && dcb->session)
|
||||
{
|
||||
if (dcb->session->client)
|
||||
if (dcb->session->client_dcb)
|
||||
{
|
||||
return (dcb->session && dcb == dcb->session->client);
|
||||
return (dcb->session && dcb == dcb->session->client_dcb);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2826,14 +2851,15 @@ dcb_count_by_usage(DCB_USAGE usage)
|
||||
* @param dcb
|
||||
* @return -1 on error, 0 otherwise.
|
||||
*/
|
||||
int dcb_create_SSL(DCB* dcb)
|
||||
static int
|
||||
dcb_create_SSL(DCB* dcb)
|
||||
{
|
||||
if (serviceInitSSL(dcb->service) != 0)
|
||||
if (NULL == dcb->listen_ssl || listener_init_SSL(dcb->listen_ssl) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((dcb->ssl = SSL_new(dcb->service->ctx)) == NULL)
|
||||
if ((dcb->ssl = SSL_new(dcb->listen_ssl->ctx)) == NULL)
|
||||
{
|
||||
MXS_ERROR("Failed to initialize SSL for connection.");
|
||||
return -1;
|
||||
@ -2862,42 +2888,58 @@ int dcb_create_SSL(DCB* dcb)
|
||||
int dcb_accept_SSL(DCB* dcb)
|
||||
{
|
||||
int ssl_rval;
|
||||
char *remote;
|
||||
char *user;
|
||||
|
||||
if (dcb->ssl == NULL && dcb_create_SSL(dcb) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
remote = dcb->remote ? dcb->remote : "";
|
||||
user = dcb->user ? dcb->user : "";
|
||||
|
||||
ssl_rval = SSL_accept(dcb->ssl);
|
||||
|
||||
switch (SSL_get_error(dcb->ssl, ssl_rval))
|
||||
{
|
||||
case SSL_ERROR_NONE:
|
||||
MXS_DEBUG("SSL_accept done for %s", dcb->remote);
|
||||
MXS_DEBUG("SSL_accept done for %s@%s", user, remote);
|
||||
dcb->ssl_state = SSL_ESTABLISHED;
|
||||
dcb->ssl_read_want_write = false;
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_READ:
|
||||
MXS_DEBUG("SSL_accept ongoing want read for %s", dcb->remote);
|
||||
MXS_DEBUG("SSL_accept ongoing want read for %s@%s", user, remote);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
MXS_DEBUG("SSL_accept ongoing want write for %s", dcb->remote);
|
||||
MXS_DEBUG("SSL_accept ongoing want write for %s@%s", user, remote);
|
||||
dcb->ssl_read_want_write = true;
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
MXS_DEBUG("SSL error, shut down cleanly during SSL accept %s", dcb->remote);
|
||||
MXS_DEBUG("SSL error, shut down cleanly during SSL accept %s@%s", user, remote);
|
||||
dcb_log_errors_SSL(dcb, __func__, 0);
|
||||
poll_fake_hangup_event(dcb);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SSL_ERROR_SYSCALL:
|
||||
MXS_DEBUG("SSL connection SSL_ERROR_SYSCALL error during accept %s", dcb->remote);
|
||||
MXS_DEBUG("SSL connection SSL_ERROR_SYSCALL error during accept %s@%s", user, remote);
|
||||
dcb_log_errors_SSL(dcb, __func__, ssl_rval);
|
||||
dcb->ssl_state = SSL_HANDSHAKE_FAILED;
|
||||
poll_fake_hangup_event(dcb);
|
||||
return -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
MXS_DEBUG("SSL connection shut down with error during SSL accept %s", dcb->remote);
|
||||
MXS_DEBUG("SSL connection shut down with error during SSL accept %s@%s", user, remote);
|
||||
dcb_log_errors_SSL(dcb, __func__, 0);
|
||||
dcb->ssl_state = SSL_HANDSHAKE_FAILED;
|
||||
poll_fake_hangup_event(dcb);
|
||||
return -1;
|
||||
break;
|
||||
@ -2924,38 +2966,32 @@ int dcb_connect_SSL(DCB* dcb)
|
||||
case SSL_ERROR_NONE:
|
||||
MXS_DEBUG("SSL_connect done for %s", dcb->remote);
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_READ:
|
||||
MXS_DEBUG("SSL_connect ongoing want read for %s", dcb->remote);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
MXS_DEBUG("SSL_connect ongoing want write for %s", dcb->remote);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
MXS_DEBUG("SSL error, shut down cleanly during SSL connect %s", dcb->remote);
|
||||
dcb_log_errors_SSL(dcb, __func__, 0);
|
||||
poll_fake_hangup_event(dcb);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SSL_ERROR_SYSCALL:
|
||||
MXS_DEBUG("SSL connection shut down with SSL_ERROR_SYSCALL during SSL connect %s", dcb->remote);
|
||||
dcb_log_errors_SSL(dcb, __func__, ssl_rval);
|
||||
poll_fake_hangup_event(dcb);
|
||||
return -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
MXS_DEBUG("SSL connection shut down with error during SSL connect %s", dcb->remote);
|
||||
dcb_log_errors_SSL(dcb, __func__, 0);
|
||||
poll_fake_hangup_event(dcb);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2993,3 +3029,4 @@ dcb_role_name(DCB *dcb)
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
82
server/core/doxygen.c
Normal file
82
server/core/doxygen.c
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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 2014
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file doxygen.c - The MaxScale model for Doxygen directed comment blocks
|
||||
*
|
||||
* This file is not built in to MaxScale at all, it exists only as a model
|
||||
* and is intended to have parts of it copied into new code, or existing
|
||||
* code that is being upgraded.
|
||||
*
|
||||
* @verbatim
|
||||
* Revision History
|
||||
*
|
||||
* Date Who Description
|
||||
* 05/02/2016 Martin Brampton Initial implementation
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Example showing how to document a function with Doxygen.
|
||||
*
|
||||
* Description of what the function does. This part may refer to the parameters
|
||||
* of the function, like @p param1 or @p param2. A word of code can also be
|
||||
* inserted like @c this which is equivalent to <tt>this</tt> and can be useful
|
||||
* to say that the function returns a @c void or an @c int. If you want to have
|
||||
* more than one word in typewriter font, then just use @<tt@>.
|
||||
* We can also include text verbatim,
|
||||
* @verbatim like this@endverbatim
|
||||
* Sometimes it is also convenient to include an example of usage:
|
||||
* @code
|
||||
* BoxStruct *out = Box_The_Function_Name(param1, param2);
|
||||
* printf("something...\n");
|
||||
* @endcode
|
||||
* Or,
|
||||
* @code{.py}
|
||||
* pyval = python_func(arg1, arg2)
|
||||
* print pyval
|
||||
* @endcode
|
||||
* when the language is not the one used in the current source file (but
|
||||
* <b>be careful</b> as this may be supported only by recent versions
|
||||
* of Doxygen). By the way, <b>this is how you write bold text</b> or,
|
||||
* if it is just one word, then you can just do @b this.
|
||||
* @param param1 Description of the first parameter of the function.
|
||||
* @param param2 The second one, which follows @p param1.
|
||||
* @return Describe what the function returns.
|
||||
* @see Box_The_Second_Function
|
||||
* @see Box_The_Last_One
|
||||
* @see http://website/
|
||||
* @note Something to note.
|
||||
* @warning Warning.
|
||||
*/
|
||||
BOXEXPORT BoxStruct *
|
||||
Box_The_Function_Name(BoxParamType1 param1, BoxParamType2 param2 /*, ...*/);
|
||||
|
||||
/**
|
||||
* @brief A simple stub function to show how links do work.
|
||||
*
|
||||
* Links are generated automatically for webpages (like http://www.google.co.uk)
|
||||
* and for structures, like BoxStruct_struct. For typedef-ed types use
|
||||
* #BoxStruct.
|
||||
* For functions, automatic links are generated when the parenthesis () follow
|
||||
* the name of the function, like Box_The_Function_Name().
|
||||
* Alternatively, you can use #Box_The_Function_Name.
|
||||
* @return @c NULL is always returned.
|
||||
*/
|
||||
BOXEXPORT void *
|
||||
Box_The_Second_Function(void);
|
187
server/core/gw_ssl.c
Normal file
187
server/core/gw_ssl.c
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* 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-2014
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file gw_ssl.c - SSL generic functions
|
||||
*
|
||||
* SSL is intended to be available in conjunction with a variety of protocols
|
||||
* on either the client or server side.
|
||||
*
|
||||
* @verbatim
|
||||
* Revision History
|
||||
*
|
||||
* Date Who Description
|
||||
* 02/02/16 Martin Brampton Initial implementation
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <dcb.h>
|
||||
#include <service.h>
|
||||
#include <log_manager.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
/**
|
||||
* @brief Check client's SSL capability and start SSL if appropriate.
|
||||
*
|
||||
* The protocol should determine whether the client is SSL capable and pass
|
||||
* the result as the second parameter. If the listener requires SSL but the
|
||||
* client is not SSL capable, an error message is recorded and failure return
|
||||
* given. If both sides want SSL, and SSL is not already established, the
|
||||
* process is triggered by calling dcb_accept_SSL.
|
||||
*
|
||||
* @param dcb Request handler DCB connected to the client
|
||||
* @param is_capable Indicates if the client can handle SSL
|
||||
* @return 0 if ok, >0 if a problem - see return codes defined in gw_ssl.h
|
||||
*/
|
||||
int ssl_authenticate_client(DCB *dcb, const char *user, bool is_capable)
|
||||
{
|
||||
char *remote = dcb->remote ? dcb->remote : "";
|
||||
char *service = (dcb->service && dcb->service->name) ? dcb->service->name : "";
|
||||
|
||||
if (NULL == dcb->listen_ssl)
|
||||
{
|
||||
/* Not an SSL connection on account of listener configuration */
|
||||
return SSL_AUTH_CHECKS_OK;
|
||||
}
|
||||
/* Now we require an SSL connection */
|
||||
if (!is_capable)
|
||||
{
|
||||
/* Should be SSL, but client is not SSL capable */
|
||||
MXS_INFO("User %s@%s connected to service '%s' without SSL when SSL was required.",
|
||||
user, remote, service);
|
||||
return SSL_ERROR_CLIENT_NOT_SSL;
|
||||
}
|
||||
/* Now we know SSL is required and client is capable */
|
||||
if (dcb->ssl_state != SSL_HANDSHAKE_DONE && dcb->ssl_state != SSL_ESTABLISHED)
|
||||
{
|
||||
int return_code;
|
||||
/** Do the SSL Handshake */
|
||||
if (SSL_HANDSHAKE_UNKNOWN == dcb->ssl_state)
|
||||
{
|
||||
dcb->ssl_state = SSL_HANDSHAKE_REQUIRED;
|
||||
}
|
||||
/**
|
||||
* Note that this will often fail to achieve its result, because further
|
||||
* reading (or possibly writing) of SSL related information is needed.
|
||||
* When that happens, there is a call in poll.c so that an EPOLLIN
|
||||
* event that arrives while the SSL state is SSL_HANDSHAKE_REQUIRED
|
||||
* will trigger dcb_accept_SSL. This situation does not result in a
|
||||
* negative return code - that indicates a real failure.
|
||||
*/
|
||||
return_code = dcb_accept_SSL(dcb);
|
||||
if (return_code < 0)
|
||||
{
|
||||
MXS_INFO("User %s@%s failed to connect to service '%s' with SSL.",
|
||||
user, remote, service);
|
||||
return SSL_ERROR_ACCEPT_FAILED;
|
||||
}
|
||||
else if (MXS_LOG_PRIORITY_IS_ENABLED(LOG_INFO))
|
||||
{
|
||||
if (1 == return_code)
|
||||
{
|
||||
MXS_INFO("User %s@%s connected to service '%s' with SSL.",
|
||||
user, remote, service);
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_INFO("User %s@%s connect to service '%s' with SSL in progress.",
|
||||
user, remote, service);
|
||||
}
|
||||
}
|
||||
}
|
||||
return SSL_AUTH_CHECKS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief If an SSL connection is required, check that it has been established.
|
||||
*
|
||||
* This is called at the end of the authentication of a new connection.
|
||||
* If the result is not true, the data packet is abandoned with further
|
||||
* data expected from the client.
|
||||
*
|
||||
* @param dcb Request handler DCB connected to the client
|
||||
* @return Boolean to indicate whether connection is healthy
|
||||
*/
|
||||
bool
|
||||
ssl_is_connection_healthy(DCB *dcb)
|
||||
{
|
||||
/**
|
||||
* If SSL was never expected, or if the connection has state SSL_ESTABLISHED
|
||||
* then everything is as we wish. Otherwise, either there is a problem or
|
||||
* more to be done.
|
||||
*/
|
||||
return (NULL == dcb->listen_ssl || dcb->ssl_state == SSL_ESTABLISHED);
|
||||
}
|
||||
|
||||
/* Looks to be redundant - can remove include for ioctl too */
|
||||
bool
|
||||
ssl_check_data_to_process(DCB *dcb)
|
||||
{
|
||||
/** SSL authentication is still going on, we need to call dcb_accept_SSL
|
||||
* until it return 1 for success or -1 for error */
|
||||
if (dcb->ssl_state == SSL_HANDSHAKE_REQUIRED && 1 == dcb_accept_SSL(dcb))
|
||||
{
|
||||
int b = 0;
|
||||
ioctl(dcb->fd,FIONREAD,&b);
|
||||
if (b != 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_DEBUG("[gw_read_client_event] No data in socket after SSL auth");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check whether a DCB requires SSL.
|
||||
*
|
||||
* This is a very simple test, but is placed in an SSL function so that
|
||||
* the knowledge of the SSL process is removed from the more general
|
||||
* handling of a connection in the protocols.
|
||||
*
|
||||
* @param dcb Request handler DCB connected to the client
|
||||
* @return Boolean indicating whether SSL is required.
|
||||
*/
|
||||
bool
|
||||
ssl_required_by_dcb(DCB *dcb)
|
||||
{
|
||||
return NULL != dcb->listen_ssl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check whether a DCB requires SSL, but SSL is not yet negotiated.
|
||||
*
|
||||
* This is a very simple test, but is placed in an SSL function so that
|
||||
* the knowledge of the SSL process is removed from the more general
|
||||
* handling of a connection in the protocols.
|
||||
*
|
||||
* @param dcb Request handler DCB connected to the client
|
||||
* @return Boolean indicating whether SSL is required and not negotiated.
|
||||
*/
|
||||
bool
|
||||
ssl_required_but_not_negotiated(DCB *dcb)
|
||||
{
|
||||
return (NULL != dcb->listen_ssl && SSL_HANDSHAKE_UNKNOWN == dcb->ssl_state);
|
||||
}
|
294
server/core/listener.c
Normal file
294
server/core/listener.c
Normal file
@ -0,0 +1,294 @@
|
||||
/*
|
||||
* 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-2014
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file listener.c - Listener generic functions
|
||||
*
|
||||
* Listeners wait for new client connections and, if the connection is successful
|
||||
* a new session is created. A listener typically knows about a port or a socket,
|
||||
* and a few other things. It may know about SSL if it is expecting an SSL
|
||||
* connection.
|
||||
*
|
||||
* @verbatim
|
||||
* Revision History
|
||||
*
|
||||
* Date Who Description
|
||||
* 26/01/16 Martin Brampton Initial implementation
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <listener.h>
|
||||
#include <gw_ssl.h>
|
||||
#include <gw_protocol.h>
|
||||
#include <log_manager.h>
|
||||
|
||||
static RSA *rsa_512 = NULL;
|
||||
static RSA *rsa_1024 = NULL;
|
||||
|
||||
static RSA *tmp_rsa_callback(SSL *s, int is_export, int keylength);
|
||||
|
||||
/**
|
||||
* Create a new listener structure
|
||||
*
|
||||
* @param protocol The name of the protocol module
|
||||
* @param address The address to listen with
|
||||
* @param port The port to listen on
|
||||
* @param authenticator Name of the authenticator to be used
|
||||
* @param ssl SSL configuration
|
||||
* @return New listener object or NULL if unable to allocate
|
||||
*/
|
||||
SERV_LISTENER *
|
||||
listener_alloc(char *protocol, char *address, unsigned short port, char *authenticator, SSL_LISTENER *ssl)
|
||||
{
|
||||
SERV_LISTENER *proto = NULL;
|
||||
if ((proto = (SERV_LISTENER *)malloc(sizeof(SERV_LISTENER))) != NULL)
|
||||
{
|
||||
proto->listener = NULL;
|
||||
proto->protocol = strdup(protocol);
|
||||
proto->address = address ? strdup(address) : NULL;
|
||||
proto->port = port;
|
||||
proto->authenticator = authenticator ? strdup(authenticator) : NULL;
|
||||
proto->ssl = ssl;
|
||||
}
|
||||
return proto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum SSL/TLS version the listener will support
|
||||
* @param ssl_listener Listener data to configure
|
||||
* @param version SSL/TLS version string
|
||||
* @return 0 on success, -1 on invalid version string
|
||||
*/
|
||||
int
|
||||
listener_set_ssl_version(SSL_LISTENER *ssl_listener, char* version)
|
||||
{
|
||||
if (strcasecmp(version,"SSLV3") == 0)
|
||||
{
|
||||
ssl_listener->ssl_method_type = SERVICE_SSLV3;
|
||||
}
|
||||
else if (strcasecmp(version,"TLSV10") == 0)
|
||||
{
|
||||
ssl_listener->ssl_method_type = SERVICE_TLS10;
|
||||
}
|
||||
#ifdef OPENSSL_1_0
|
||||
else if (strcasecmp(version,"TLSV11") == 0)
|
||||
{
|
||||
ssl_listener->ssl_method_type = SERVICE_TLS11;
|
||||
}
|
||||
else if (strcasecmp(version,"TLSV12") == 0)
|
||||
{
|
||||
ssl_listener->ssl_method_type = SERVICE_TLS12;
|
||||
}
|
||||
#endif
|
||||
else if (strcasecmp(version,"MAX") == 0)
|
||||
{
|
||||
ssl_listener->ssl_method_type = SERVICE_SSL_TLS_MAX;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the locations of the listener's SSL certificate, listener's private key
|
||||
* and the CA certificate which both the client and the listener should trust.
|
||||
* @param ssl_listener Listener data to configure
|
||||
* @param cert SSL certificate
|
||||
* @param key SSL private key
|
||||
* @param ca_cert SSL CA certificate
|
||||
*/
|
||||
void
|
||||
listener_set_certificates(SSL_LISTENER *ssl_listener, char* cert, char* key, char* ca_cert)
|
||||
{
|
||||
free(ssl_listener->ssl_cert);
|
||||
ssl_listener->ssl_cert = cert ? strdup(cert) : NULL;
|
||||
|
||||
free(ssl_listener->ssl_key);
|
||||
ssl_listener->ssl_key = key ? strdup(key) : NULL;
|
||||
|
||||
free(ssl_listener->ssl_ca_cert);
|
||||
ssl_listener->ssl_ca_cert = ca_cert ? strdup(ca_cert) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the listener's SSL context. This sets up the generated RSA
|
||||
* encryption keys, chooses the listener encryption level and configures the
|
||||
* listener certificate, private key and certificate authority file.
|
||||
* @param ssl_listener Listener data to initialize
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
listener_init_SSL(SSL_LISTENER *ssl_listener)
|
||||
{
|
||||
DH* dh;
|
||||
RSA* rsa;
|
||||
|
||||
if (!ssl_listener->ssl_init_done)
|
||||
{
|
||||
switch(ssl_listener->ssl_method_type)
|
||||
{
|
||||
case SERVICE_SSLV3:
|
||||
ssl_listener->method = (SSL_METHOD*)SSLv3_server_method();
|
||||
break;
|
||||
case SERVICE_TLS10:
|
||||
ssl_listener->method = (SSL_METHOD*)TLSv1_server_method();
|
||||
break;
|
||||
#ifdef OPENSSL_1_0
|
||||
case SERVICE_TLS11:
|
||||
ssl_listener->method = (SSL_METHOD*)TLSv1_1_server_method();
|
||||
break;
|
||||
case SERVICE_TLS12:
|
||||
ssl_listener->method = (SSL_METHOD*)TLSv1_2_server_method();
|
||||
break;
|
||||
#endif
|
||||
/** Rest of these use the maximum available SSL/TLS methods */
|
||||
case SERVICE_SSL_MAX:
|
||||
ssl_listener->method = (SSL_METHOD*)SSLv23_server_method();
|
||||
break;
|
||||
case SERVICE_TLS_MAX:
|
||||
ssl_listener->method = (SSL_METHOD*)SSLv23_server_method();
|
||||
break;
|
||||
case SERVICE_SSL_TLS_MAX:
|
||||
ssl_listener->method = (SSL_METHOD*)SSLv23_server_method();
|
||||
break;
|
||||
default:
|
||||
ssl_listener->method = (SSL_METHOD*)SSLv23_server_method();
|
||||
break;
|
||||
}
|
||||
|
||||
if ((ssl_listener->ctx = SSL_CTX_new(ssl_listener->method)) == NULL)
|
||||
{
|
||||
MXS_ERROR("SSL context initialization failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Enable all OpenSSL bug fixes */
|
||||
SSL_CTX_set_options(ssl_listener->ctx,SSL_OP_ALL);
|
||||
|
||||
/** Generate the 512-bit and 1024-bit RSA keys */
|
||||
if (rsa_512 == NULL)
|
||||
{
|
||||
rsa_512 = RSA_generate_key(512,RSA_F4,NULL,NULL);
|
||||
if (rsa_512 == NULL)
|
||||
{
|
||||
MXS_ERROR("512-bit RSA key generation failed.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (rsa_1024 == NULL)
|
||||
{
|
||||
rsa_1024 = RSA_generate_key(1024,RSA_F4,NULL,NULL);
|
||||
if (rsa_1024 == NULL)
|
||||
{
|
||||
MXS_ERROR("1024-bit RSA key generation failed.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (rsa_512 != NULL && rsa_1024 != NULL)
|
||||
{
|
||||
SSL_CTX_set_tmp_rsa_callback(ssl_listener->ctx,tmp_rsa_callback);
|
||||
}
|
||||
|
||||
/** Load the server certificate */
|
||||
if (SSL_CTX_use_certificate_file(ssl_listener->ctx, ssl_listener->ssl_cert, SSL_FILETYPE_PEM) <= 0)
|
||||
{
|
||||
MXS_ERROR("Failed to set server SSL certificate.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Load the private-key corresponding to the server certificate */
|
||||
if (SSL_CTX_use_PrivateKey_file(ssl_listener->ctx, ssl_listener->ssl_key, SSL_FILETYPE_PEM) <= 0)
|
||||
{
|
||||
MXS_ERROR("Failed to set server SSL key.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check if the server certificate and private-key matches */
|
||||
if (!SSL_CTX_check_private_key(ssl_listener->ctx))
|
||||
{
|
||||
MXS_ERROR("Server SSL certificate and key do not match.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Load the RSA CA certificate into the SSL_CTX structure */
|
||||
if (!SSL_CTX_load_verify_locations(ssl_listener->ctx, ssl_listener->ssl_ca_cert, NULL))
|
||||
{
|
||||
MXS_ERROR("Failed to set Certificate Authority file.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set to require peer (client) certificate verification */
|
||||
SSL_CTX_set_verify(ssl_listener->ctx,SSL_VERIFY_PEER,NULL);
|
||||
|
||||
/* Set the verification depth */
|
||||
SSL_CTX_set_verify_depth(ssl_listener->ctx,ssl_listener->ssl_cert_verify_depth);
|
||||
ssl_listener->ssl_init_done = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The RSA key generation callback function for OpenSSL.
|
||||
* @param s SSL structure
|
||||
* @param is_export Not used
|
||||
* @param keylength Length of the key
|
||||
* @return Pointer to RSA structure
|
||||
*/
|
||||
static RSA *
|
||||
tmp_rsa_callback(SSL *s, int is_export, int keylength)
|
||||
{
|
||||
RSA *rsa_tmp=NULL;
|
||||
|
||||
switch (keylength) {
|
||||
case 512:
|
||||
if (rsa_512)
|
||||
{
|
||||
rsa_tmp = rsa_512;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* generate on the fly, should not happen in this example */
|
||||
rsa_tmp = RSA_generate_key(keylength,RSA_F4,NULL,NULL);
|
||||
rsa_512 = rsa_tmp; /* Remember for later reuse */
|
||||
}
|
||||
break;
|
||||
case 1024:
|
||||
if (rsa_1024)
|
||||
{
|
||||
rsa_tmp=rsa_1024;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Generating a key on the fly is very costly, so use what is there */
|
||||
if (rsa_1024)
|
||||
{
|
||||
rsa_tmp=rsa_1024;
|
||||
}
|
||||
else
|
||||
{
|
||||
rsa_tmp=rsa_512; /* Use at least a shorter key */
|
||||
}
|
||||
}
|
||||
return(rsa_tmp);
|
||||
}
|
@ -73,7 +73,8 @@ int max_poll_sleep;
|
||||
* processing.
|
||||
* 07/07/15 Martin Brampton Simplified add and remove DCB, improve error handling.
|
||||
* 23/08/15 Martin Brampton Added test so only DCB with a session link can be added to the poll list
|
||||
*
|
||||
* 07/02/16 Martin Brampton Added a small piece of SSL logic to EPOLLIN
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
@ -986,7 +987,17 @@ process_pollq(int thread_id)
|
||||
|
||||
if (poll_dcb_session_check(dcb, "read"))
|
||||
{
|
||||
dcb->func.read(dcb);
|
||||
int return_code = 1;
|
||||
/** SSL authentication is still going on, we need to call dcb_accept_SSL
|
||||
* until it return 1 for success or -1 for error */
|
||||
if (dcb->ssl_state == SSL_HANDSHAKE_REQUIRED)
|
||||
{
|
||||
return_code = dcb_accept_SSL(dcb);
|
||||
}
|
||||
if (1 == return_code)
|
||||
{
|
||||
dcb->func.read(dcb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,8 @@
|
||||
#include <errno.h>
|
||||
#include <session.h>
|
||||
#include <service.h>
|
||||
#include <gw_protocol.h>
|
||||
#include <listener.h>
|
||||
#include <server.h>
|
||||
#include <router.h>
|
||||
#include <spinlock.h>
|
||||
@ -68,9 +70,6 @@
|
||||
#include <math.h>
|
||||
#include <version.h>
|
||||
|
||||
static RSA *rsa_512 = NULL;
|
||||
static RSA *rsa_1024 = NULL;
|
||||
|
||||
/** To be used with configuration type checks */
|
||||
typedef struct typelib_st
|
||||
{
|
||||
@ -219,7 +218,7 @@ service_isvalid(SERVICE *service)
|
||||
* @return The number of listeners started
|
||||
*/
|
||||
static int
|
||||
serviceStartPort(SERVICE *service, SERV_PROTOCOL *port)
|
||||
serviceStartPort(SERVICE *service, SERV_LISTENER *port)
|
||||
{
|
||||
int listeners = 0;
|
||||
char config_bind[40];
|
||||
@ -233,6 +232,13 @@ serviceStartPort(SERVICE *service, SERV_PROTOCOL *port)
|
||||
goto retblock;
|
||||
}
|
||||
|
||||
port->listener->listen_ssl = port->ssl;
|
||||
|
||||
if (port->ssl)
|
||||
{
|
||||
listener_init_SSL(port->ssl);
|
||||
}
|
||||
|
||||
if (strcmp(port->protocol, "MySQLClient") == 0)
|
||||
{
|
||||
int loaded;
|
||||
@ -421,7 +427,7 @@ retblock:
|
||||
*/
|
||||
int serviceStartAllPorts(SERVICE* service)
|
||||
{
|
||||
SERV_PROTOCOL *port = service->ports;
|
||||
SERV_LISTENER *port = service->ports;
|
||||
int listeners = 0;
|
||||
while (!service->svc_do_shutdown && port)
|
||||
{
|
||||
@ -468,24 +474,15 @@ serviceStart(SERVICE *service)
|
||||
|
||||
if (check_service_permissions(service))
|
||||
{
|
||||
if (service->ssl_mode == SSL_DISABLED ||
|
||||
(service->ssl_mode != SSL_DISABLED && serviceInitSSL(service) == 0))
|
||||
if ((service->router_instance = service->router->createInstance(
|
||||
service,service->routerOptions)))
|
||||
{
|
||||
if ((service->router_instance = service->router->createInstance(
|
||||
service,service->routerOptions)))
|
||||
{
|
||||
listeners += serviceStartAllPorts(service);
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("%s: Failed to create router instance for service. Service not started.",
|
||||
service->name);
|
||||
service->state = SERVICE_STATE_FAILED;
|
||||
}
|
||||
listeners += serviceStartAllPorts(service);
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("%s: SSL initialization failed. Service not started.", service->name);
|
||||
MXS_ERROR("%s: Failed to create router instance for service. Service not started.",
|
||||
service->name);
|
||||
service->state = SERVICE_STATE_FAILED;
|
||||
}
|
||||
}
|
||||
@ -508,7 +505,7 @@ serviceStart(SERVICE *service)
|
||||
void
|
||||
serviceStartProtocol(SERVICE *service, char *protocol, int port)
|
||||
{
|
||||
SERV_PROTOCOL *ptr;
|
||||
SERV_LISTENER *ptr;
|
||||
|
||||
ptr = service->ports;
|
||||
while (ptr)
|
||||
@ -561,7 +558,7 @@ serviceStartAll()
|
||||
int
|
||||
serviceStop(SERVICE *service)
|
||||
{
|
||||
SERV_PROTOCOL *port;
|
||||
SERV_LISTENER *port;
|
||||
int listeners = 0;
|
||||
|
||||
port = service->ports;
|
||||
@ -593,7 +590,7 @@ serviceStop(SERVICE *service)
|
||||
int
|
||||
serviceRestart(SERVICE *service)
|
||||
{
|
||||
SERV_PROTOCOL *port;
|
||||
SERV_LISTENER *port;
|
||||
int listeners = 0;
|
||||
|
||||
port = service->ports;
|
||||
@ -684,34 +681,25 @@ service_free(SERVICE *service)
|
||||
* @param protocol The name of the protocol module
|
||||
* @param address The address to listen with
|
||||
* @param port The port to listen on
|
||||
* @param authenticator Name of the authenticator to be used
|
||||
* @param ssl SSL configuration
|
||||
* @return TRUE if the protocol/port could be added
|
||||
*/
|
||||
int
|
||||
serviceAddProtocol(SERVICE *service, char *protocol, char *address, unsigned short port)
|
||||
serviceAddProtocol(SERVICE *service, char *protocol, char *address, unsigned short port, char *authenticator, SSL_LISTENER *ssl)
|
||||
{
|
||||
SERV_PROTOCOL *proto;
|
||||
SERV_LISTENER *proto;
|
||||
|
||||
if ((proto = (SERV_PROTOCOL *)malloc(sizeof(SERV_PROTOCOL))) == NULL)
|
||||
if ((proto = listener_alloc(protocol, address, port, authenticator, ssl)) != NULL)
|
||||
{
|
||||
return 0;
|
||||
spinlock_acquire(&service->spin);
|
||||
proto->next = service->ports;
|
||||
service->ports = proto;
|
||||
spinlock_release(&service->spin);
|
||||
return 1;
|
||||
}
|
||||
proto->listener = NULL;
|
||||
proto->protocol = strdup(protocol);
|
||||
if (address)
|
||||
{
|
||||
proto->address = strdup(address);
|
||||
}
|
||||
else
|
||||
{
|
||||
proto->address = NULL;
|
||||
}
|
||||
proto->port = port;
|
||||
spinlock_acquire(&service->spin);
|
||||
proto->next = service->ports;
|
||||
service->ports = proto;
|
||||
spinlock_release(&service->spin);
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -725,7 +713,7 @@ serviceAddProtocol(SERVICE *service, char *protocol, char *address, unsigned sho
|
||||
int
|
||||
serviceHasProtocol(SERVICE *service, char *protocol, unsigned short port)
|
||||
{
|
||||
SERV_PROTOCOL *proto;
|
||||
SERV_LISTENER *proto;
|
||||
|
||||
spinlock_acquire(&service->spin);
|
||||
proto = service->ports;
|
||||
@ -1458,7 +1446,7 @@ void
|
||||
dListListeners(DCB *dcb)
|
||||
{
|
||||
SERVICE *service;
|
||||
SERV_PROTOCOL *lptr;
|
||||
SERV_LISTENER *lptr;
|
||||
|
||||
spinlock_acquire(&service_spin);
|
||||
service = allServices;
|
||||
@ -1931,7 +1919,7 @@ serviceListenerRowCallback(RESULTSET *set, void *data)
|
||||
char buf[20];
|
||||
RESULT_ROW *row;
|
||||
SERVICE *service;
|
||||
SERV_PROTOCOL *lptr = NULL;
|
||||
SERV_LISTENER *lptr = NULL;
|
||||
|
||||
spinlock_acquire(&service_spin);
|
||||
service = allServices;
|
||||
@ -2051,7 +2039,7 @@ serviceRowCallback(RESULTSET *set, void *data)
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a resultset that has the current set of services in it
|
||||
* Return a result set that has the current set of services in it
|
||||
*
|
||||
* @return A Result set
|
||||
*/
|
||||
@ -2079,167 +2067,6 @@ serviceGetList()
|
||||
return set;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The RSA ket generation callback function for OpenSSL.
|
||||
* @param s SSL structure
|
||||
* @param is_export Not used
|
||||
* @param keylength Length of the key
|
||||
* @return Pointer to RSA structure
|
||||
*/
|
||||
RSA *tmp_rsa_callback(SSL *s, int is_export, int keylength)
|
||||
{
|
||||
RSA *rsa_tmp=NULL;
|
||||
|
||||
switch (keylength) {
|
||||
case 512:
|
||||
if (rsa_512)
|
||||
{
|
||||
rsa_tmp = rsa_512;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* generate on the fly, should not happen in this example */
|
||||
rsa_tmp = RSA_generate_key(keylength,RSA_F4,NULL,NULL);
|
||||
rsa_512 = rsa_tmp; /* Remember for later reuse */
|
||||
}
|
||||
break;
|
||||
case 1024:
|
||||
if (rsa_1024)
|
||||
{
|
||||
rsa_tmp=rsa_1024;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Generating a key on the fly is very costly, so use what is there */
|
||||
if (rsa_1024)
|
||||
{
|
||||
rsa_tmp=rsa_1024;
|
||||
}
|
||||
else
|
||||
{
|
||||
rsa_tmp=rsa_512; /* Use at least a shorter key */
|
||||
}
|
||||
}
|
||||
return(rsa_tmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the service's SSL context. This sets up the generated RSA
|
||||
* encryption keys, chooses the server encryption level and configures the server
|
||||
* certificate, private key and certificate authority file.
|
||||
* @param service Service to initialize
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int serviceInitSSL(SERVICE* service)
|
||||
{
|
||||
DH* dh;
|
||||
RSA* rsa;
|
||||
|
||||
if (!service->ssl_init_done)
|
||||
{
|
||||
switch(service->ssl_method_type)
|
||||
{
|
||||
case SERVICE_SSLV3:
|
||||
service->method = (SSL_METHOD*)SSLv3_server_method();
|
||||
break;
|
||||
case SERVICE_TLS10:
|
||||
service->method = (SSL_METHOD*)TLSv1_server_method();
|
||||
break;
|
||||
#ifdef OPENSSL_1_0
|
||||
case SERVICE_TLS11:
|
||||
service->method = (SSL_METHOD*)TLSv1_1_server_method();
|
||||
break;
|
||||
case SERVICE_TLS12:
|
||||
service->method = (SSL_METHOD*)TLSv1_2_server_method();
|
||||
break;
|
||||
#endif
|
||||
/** Rest of these use the maximum available SSL/TLS methods */
|
||||
case SERVICE_SSL_MAX:
|
||||
service->method = (SSL_METHOD*)SSLv23_server_method();
|
||||
break;
|
||||
case SERVICE_TLS_MAX:
|
||||
service->method = (SSL_METHOD*)SSLv23_server_method();
|
||||
break;
|
||||
case SERVICE_SSL_TLS_MAX:
|
||||
service->method = (SSL_METHOD*)SSLv23_server_method();
|
||||
break;
|
||||
default:
|
||||
service->method = (SSL_METHOD*)SSLv23_server_method();
|
||||
break;
|
||||
}
|
||||
|
||||
if ((service->ctx = SSL_CTX_new(service->method)) == NULL)
|
||||
{
|
||||
MXS_ERROR("SSL context initialization failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Enable all OpenSSL bug fixes */
|
||||
SSL_CTX_set_options(service->ctx,SSL_OP_ALL);
|
||||
|
||||
/** Generate the 512-bit and 1024-bit RSA keys */
|
||||
if (rsa_512 == NULL)
|
||||
{
|
||||
rsa_512 = RSA_generate_key(512,RSA_F4,NULL,NULL);
|
||||
if (rsa_512 == NULL)
|
||||
{
|
||||
MXS_ERROR("512-bit RSA key generation failed.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (rsa_1024 == NULL)
|
||||
{
|
||||
rsa_1024 = RSA_generate_key(1024,RSA_F4,NULL,NULL);
|
||||
if (rsa_1024 == NULL)
|
||||
{
|
||||
MXS_ERROR("1024-bit RSA key generation failed.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (rsa_512 != NULL && rsa_1024 != NULL)
|
||||
{
|
||||
SSL_CTX_set_tmp_rsa_callback(service->ctx,tmp_rsa_callback);
|
||||
}
|
||||
|
||||
/** Load the server sertificate */
|
||||
if (SSL_CTX_use_certificate_file(service->ctx, service->ssl_cert, SSL_FILETYPE_PEM) <= 0)
|
||||
{
|
||||
MXS_ERROR("Failed to set server SSL certificate.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Load the private-key corresponding to the server certificate */
|
||||
if (SSL_CTX_use_PrivateKey_file(service->ctx, service->ssl_key, SSL_FILETYPE_PEM) <= 0)
|
||||
{
|
||||
MXS_ERROR("Failed to set server SSL key.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check if the server certificate and private-key matches */
|
||||
if (!SSL_CTX_check_private_key(service->ctx))
|
||||
{
|
||||
MXS_ERROR("Server SSL certificate and key do not match.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Load the RSA CA certificate into the SSL_CTX structure */
|
||||
if (!SSL_CTX_load_verify_locations(service->ctx, service->ssl_ca_cert, NULL))
|
||||
{
|
||||
MXS_ERROR("Failed to set Certificate Authority file.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set to require peer (client) certificate verification */
|
||||
SSL_CTX_set_verify(service->ctx,SSL_VERIFY_PEER,NULL);
|
||||
|
||||
/* Set the verification depth */
|
||||
SSL_CTX_set_verify_depth(service->ctx,service->ssl_cert_verify_depth);
|
||||
service->ssl_init_done = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* Function called by the housekeeper thread to retry starting of a service
|
||||
* @param data Service to restart
|
||||
|
@ -65,6 +65,8 @@ static SPINLOCK timeout_lock = SPINLOCK_INIT;
|
||||
static int session_setup_filters(SESSION *session);
|
||||
static void session_simple_free(SESSION *session, DCB *dcb);
|
||||
|
||||
static void mysql_auth_free_client_data(DCB *dcb);
|
||||
|
||||
/**
|
||||
* Allocate a new session for a new client of the specified service.
|
||||
*
|
||||
@ -91,23 +93,6 @@ session_alloc(SERVICE *service, DCB *client_dcb)
|
||||
"session object due error %d, %s.",
|
||||
errno,
|
||||
strerror_r(errno, errbuf, sizeof(errbuf)));
|
||||
/* Does this possibly need a lock? */
|
||||
/*
|
||||
* This is really not the right way to do this. The data in a DCB is
|
||||
* router specific and should be freed by a function in the relevant
|
||||
* router. This would be better achieved by placing a function reference
|
||||
* in the DCB and having dcb_final_free call it to dispose of the data
|
||||
* at the final destruction of the DCB. However, this piece of code is
|
||||
* only run following a calloc failure, so the system is probably on
|
||||
* the point of crashing anyway.
|
||||
*
|
||||
*/
|
||||
if (client_dcb->data && !DCB_IS_CLONE(client_dcb))
|
||||
{
|
||||
void * clientdata = client_dcb->data;
|
||||
client_dcb->data = NULL;
|
||||
free(clientdata);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#if defined(SS_DEBUG)
|
||||
@ -117,7 +102,7 @@ session_alloc(SERVICE *service, DCB *client_dcb)
|
||||
session->ses_is_child = (bool) DCB_IS_CLONE(client_dcb);
|
||||
spinlock_init(&session->ses_lock);
|
||||
session->service = service;
|
||||
session->client = client_dcb;
|
||||
session->client_dcb = client_dcb;
|
||||
session->n_filters = 0;
|
||||
memset(&session->stats, 0, sizeof(SESSION_STATS));
|
||||
session->stats.connect = time(0);
|
||||
@ -129,7 +114,6 @@ session_alloc(SERVICE *service, DCB *client_dcb)
|
||||
* session has not been made available to the other threads at this
|
||||
* point.
|
||||
*/
|
||||
session->data = client_dcb->data;
|
||||
session->refcount = 1;
|
||||
/*<
|
||||
* This indicates that session is ready to be shared with backend
|
||||
@ -190,7 +174,7 @@ session_alloc(SERVICE *service, DCB *client_dcb)
|
||||
{
|
||||
session->state = SESSION_STATE_ROUTER_READY;
|
||||
|
||||
if (session->client->user == NULL)
|
||||
if (session->client_dcb->user == NULL)
|
||||
{
|
||||
MXS_INFO("Started session [%lu] for %s service ",
|
||||
session->ses_id,
|
||||
@ -201,8 +185,8 @@ session_alloc(SERVICE *service, DCB *client_dcb)
|
||||
MXS_INFO("Started %s client session [%lu] for '%s' from %s",
|
||||
service->name,
|
||||
session->ses_id,
|
||||
session->client->user,
|
||||
session->client->remote);
|
||||
session->client_dcb->user,
|
||||
session->client_dcb->remote);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -211,8 +195,8 @@ session_alloc(SERVICE *service, DCB *client_dcb)
|
||||
"closed as soon as all related DCBs have been closed.",
|
||||
service->name,
|
||||
session->ses_id,
|
||||
session->client->user,
|
||||
session->client->remote);
|
||||
session->client_dcb->user,
|
||||
session->client_dcb->remote);
|
||||
}
|
||||
spinlock_acquire(&session_spin);
|
||||
/** Assign a session id and increase, insert session into list */
|
||||
@ -249,12 +233,11 @@ session_set_dummy(DCB *client_dcb)
|
||||
session->ses_is_child = false;
|
||||
spinlock_init(&session->ses_lock);
|
||||
session->service = NULL;
|
||||
session->client = NULL;
|
||||
session->client_dcb = NULL;
|
||||
session->n_filters = 0;
|
||||
memset(&session->stats, 0, sizeof(SESSION_STATS));
|
||||
session->stats.connect = 0;
|
||||
session->state = SESSION_STATE_DUMMY;
|
||||
session->data = NULL;
|
||||
session->refcount = 1;
|
||||
session->ses_id = 0;
|
||||
session->next = NULL;
|
||||
@ -268,12 +251,12 @@ session_set_dummy(DCB *client_dcb)
|
||||
* counter.
|
||||
* Generic logging setting has precedence over session-specific setting.
|
||||
*
|
||||
* @param ses session
|
||||
* @param session session
|
||||
* @param priority syslog priority
|
||||
*/
|
||||
void session_enable_log_priority(SESSION* ses, int priority)
|
||||
void session_enable_log_priority(SESSION* session, int priority)
|
||||
{
|
||||
ses->enabled_log_priorities |= (1 << priority);
|
||||
session->enabled_log_priorities |= (1 << priority);
|
||||
atomic_add((int *)&mxs_log_session_count[priority], 1);
|
||||
}
|
||||
|
||||
@ -282,14 +265,14 @@ void session_enable_log_priority(SESSION* ses, int priority)
|
||||
* counter.
|
||||
* Generic logging setting has precedence over session-specific setting.
|
||||
*
|
||||
* @param ses session
|
||||
* @param session session
|
||||
* @param priority syslog priority
|
||||
*/
|
||||
void session_disable_log_priority(SESSION* ses, int priority)
|
||||
void session_disable_log_priority(SESSION* session, int priority)
|
||||
{
|
||||
if (ses->enabled_log_priorities & (1 << priority))
|
||||
if (session->enabled_log_priorities & (1 << priority))
|
||||
{
|
||||
ses->enabled_log_priorities &= ~(1 << priority);
|
||||
session->enabled_log_priorities &= ~(1 << priority);
|
||||
atomic_add((int *)&mxs_log_session_count[priority], -1);
|
||||
}
|
||||
}
|
||||
@ -341,9 +324,9 @@ int session_unlink_dcb(SESSION* session,
|
||||
|
||||
if (dcb != NULL)
|
||||
{
|
||||
if (session->client == dcb)
|
||||
if (session->client_dcb == dcb)
|
||||
{
|
||||
session->client = NULL;
|
||||
session->client_dcb = NULL;
|
||||
}
|
||||
dcb->session = NULL;
|
||||
}
|
||||
@ -435,6 +418,17 @@ session_free(SESSION *session)
|
||||
spinlock_release(&session_spin);
|
||||
atomic_add(&session->service->stats.n_current, -1);
|
||||
|
||||
/***
|
||||
*
|
||||
*/
|
||||
if (session->client_dcb)
|
||||
{
|
||||
if (!DCB_IS_CLONE(session->client_dcb))
|
||||
{
|
||||
mysql_auth_free_client_data(session->client_dcb);
|
||||
}
|
||||
dcb_free_all_memory(session->client_dcb);
|
||||
}
|
||||
/**
|
||||
* If session is not child of some other session, free router_session.
|
||||
* Otherwise let the parent free it.
|
||||
@ -477,11 +471,6 @@ session_free(SESSION *session)
|
||||
if (!session->ses_is_child)
|
||||
{
|
||||
session->state = SESSION_STATE_FREE;
|
||||
|
||||
if (session->data)
|
||||
{
|
||||
free(session->data);
|
||||
}
|
||||
free(session);
|
||||
}
|
||||
return true;
|
||||
@ -496,19 +485,19 @@ session_free(SESSION *session)
|
||||
int
|
||||
session_isvalid(SESSION *session)
|
||||
{
|
||||
SESSION *ptr;
|
||||
SESSION *list_session;
|
||||
int rval = 0;
|
||||
|
||||
spinlock_acquire(&session_spin);
|
||||
ptr = allSessions;
|
||||
while (ptr)
|
||||
list_session = allSessions;
|
||||
while (list_session)
|
||||
{
|
||||
if (ptr == session)
|
||||
if (list_session == session)
|
||||
{
|
||||
rval = 1;
|
||||
break;
|
||||
}
|
||||
ptr = ptr->next;
|
||||
list_session = list_session->next;
|
||||
}
|
||||
spinlock_release(&session_spin);
|
||||
|
||||
@ -529,7 +518,7 @@ printSession(SESSION *session)
|
||||
printf("Session %p\n", session);
|
||||
printf("\tState: %s\n", session_state(session->state));
|
||||
printf("\tService: %s (%p)\n", session->service->name, session->service);
|
||||
printf("\tClient DCB: %p\n", session->client);
|
||||
printf("\tClient DCB: %p\n", session->client_dcb);
|
||||
printf("\tConnected: %s",
|
||||
asctime_r(localtime_r(&session->stats.connect, &result), timebuf));
|
||||
}
|
||||
@ -543,14 +532,14 @@ printSession(SESSION *session)
|
||||
void
|
||||
printAllSessions()
|
||||
{
|
||||
SESSION *ptr;
|
||||
SESSION *list_session;
|
||||
|
||||
spinlock_acquire(&session_spin);
|
||||
ptr = allSessions;
|
||||
while (ptr)
|
||||
list_session = allSessions;
|
||||
while (list_session)
|
||||
{
|
||||
printSession(ptr);
|
||||
ptr = ptr->next;
|
||||
printSession(list_session);
|
||||
list_session = list_session->next;
|
||||
}
|
||||
spinlock_release(&session_spin);
|
||||
}
|
||||
@ -565,29 +554,29 @@ printAllSessions()
|
||||
void
|
||||
CheckSessions()
|
||||
{
|
||||
SESSION *ptr;
|
||||
SESSION *list_session;
|
||||
int noclients = 0;
|
||||
int norouter = 0;
|
||||
|
||||
spinlock_acquire(&session_spin);
|
||||
ptr = allSessions;
|
||||
while (ptr)
|
||||
list_session = allSessions;
|
||||
while (list_session)
|
||||
{
|
||||
if (ptr->state != SESSION_STATE_LISTENER ||
|
||||
ptr->state != SESSION_STATE_LISTENER_STOPPED)
|
||||
if (list_session->state != SESSION_STATE_LISTENER ||
|
||||
list_session->state != SESSION_STATE_LISTENER_STOPPED)
|
||||
{
|
||||
if (ptr->client == NULL && ptr->refcount)
|
||||
if (list_session->client_dcb == NULL && list_session->refcount)
|
||||
{
|
||||
if (noclients == 0)
|
||||
{
|
||||
printf("Sessions without a client DCB.\n");
|
||||
printf("==============================\n");
|
||||
}
|
||||
printSession(ptr);
|
||||
printSession(list_session);
|
||||
noclients++;
|
||||
}
|
||||
}
|
||||
ptr = ptr->next;
|
||||
list_session = list_session->next;
|
||||
}
|
||||
spinlock_release(&session_spin);
|
||||
if (noclients)
|
||||
@ -595,24 +584,24 @@ CheckSessions()
|
||||
printf("%d Sessions have no clients\n", noclients);
|
||||
}
|
||||
spinlock_acquire(&session_spin);
|
||||
ptr = allSessions;
|
||||
while (ptr)
|
||||
list_session = allSessions;
|
||||
while (list_session)
|
||||
{
|
||||
if (ptr->state != SESSION_STATE_LISTENER ||
|
||||
ptr->state != SESSION_STATE_LISTENER_STOPPED)
|
||||
if (list_session->state != SESSION_STATE_LISTENER ||
|
||||
list_session->state != SESSION_STATE_LISTENER_STOPPED)
|
||||
{
|
||||
if (ptr->router_session == NULL && ptr->refcount)
|
||||
if (list_session->router_session == NULL && list_session->refcount)
|
||||
{
|
||||
if (norouter == 0)
|
||||
{
|
||||
printf("Sessions without a router session.\n");
|
||||
printf("==================================\n");
|
||||
}
|
||||
printSession(ptr);
|
||||
printSession(list_session);
|
||||
norouter++;
|
||||
}
|
||||
}
|
||||
ptr = ptr->next;
|
||||
list_session = list_session->next;
|
||||
}
|
||||
spinlock_release(&session_spin);
|
||||
if (norouter)
|
||||
@ -634,36 +623,36 @@ dprintAllSessions(DCB *dcb)
|
||||
{
|
||||
struct tm result;
|
||||
char timebuf[40];
|
||||
SESSION *ptr;
|
||||
SESSION *list_session;
|
||||
|
||||
spinlock_acquire(&session_spin);
|
||||
ptr = allSessions;
|
||||
while (ptr)
|
||||
list_session = allSessions;
|
||||
while (list_session)
|
||||
{
|
||||
dcb_printf(dcb, "Session %d (%p)\n",ptr->ses_id, ptr);
|
||||
dcb_printf(dcb, "\tState: %s\n", session_state(ptr->state));
|
||||
dcb_printf(dcb, "\tService: %s (%p)\n", ptr->service->name, ptr->service);
|
||||
dcb_printf(dcb, "\tClient DCB: %p\n", ptr->client);
|
||||
dcb_printf(dcb, "Session %d (%p)\n",list_session->ses_id, list_session);
|
||||
dcb_printf(dcb, "\tState: %s\n", session_state(list_session->state));
|
||||
dcb_printf(dcb, "\tService: %s (%p)\n", list_session->service->name, list_session->service);
|
||||
dcb_printf(dcb, "\tClient DCB: %p\n", list_session->client_dcb);
|
||||
|
||||
if (ptr->client && ptr->client->remote)
|
||||
if (list_session->client_dcb && list_session->client_dcb->remote)
|
||||
{
|
||||
dcb_printf(dcb, "\tClient Address: %s%s%s\n",
|
||||
ptr->client->user?ptr->client->user:"",
|
||||
ptr->client->user?"@":"",
|
||||
ptr->client->remote);
|
||||
list_session->client_dcb->user?list_session->client_dcb->user:"",
|
||||
list_session->client_dcb->user?"@":"",
|
||||
list_session->client_dcb->remote);
|
||||
}
|
||||
|
||||
dcb_printf(dcb, "\tConnected: %s",
|
||||
asctime_r(localtime_r(&ptr->stats.connect, &result), timebuf));
|
||||
asctime_r(localtime_r(&list_session->stats.connect, &result), timebuf));
|
||||
|
||||
if (ptr->client && ptr->client->state == DCB_STATE_POLLING)
|
||||
if (list_session->client_dcb && list_session->client_dcb->state == DCB_STATE_POLLING)
|
||||
{
|
||||
double idle = (hkheartbeat - ptr->client->last_read);
|
||||
double idle = (hkheartbeat - list_session->client_dcb->last_read);
|
||||
idle = idle > 0 ? idle/10.0:0;
|
||||
dcb_printf(dcb, "\tIdle: %.0f seconds\n",idle);
|
||||
}
|
||||
|
||||
ptr = ptr->next;
|
||||
list_session = list_session->next;
|
||||
}
|
||||
spinlock_release(&session_spin);
|
||||
}
|
||||
@ -675,43 +664,43 @@ dprintAllSessions(DCB *dcb)
|
||||
* to display all active sessions within the gateway
|
||||
*
|
||||
* @param dcb The DCB to print to
|
||||
* @param ptr The session to print
|
||||
* @param print_session The session to print
|
||||
*/
|
||||
void
|
||||
dprintSession(DCB *dcb, SESSION *ptr)
|
||||
dprintSession(DCB *dcb, SESSION *print_session)
|
||||
{
|
||||
struct tm result;
|
||||
char buf[30];
|
||||
int i;
|
||||
|
||||
dcb_printf(dcb, "Session %d (%p)\n",ptr->ses_id, ptr);
|
||||
dcb_printf(dcb, "\tState: %s\n", session_state(ptr->state));
|
||||
dcb_printf(dcb, "\tService: %s (%p)\n", ptr->service->name, ptr->service);
|
||||
dcb_printf(dcb, "\tClient DCB: %p\n", ptr->client);
|
||||
if (ptr->client && ptr->client->remote)
|
||||
dcb_printf(dcb, "Session %d (%p)\n",print_session->ses_id, print_session);
|
||||
dcb_printf(dcb, "\tState: %s\n", session_state(print_session->state));
|
||||
dcb_printf(dcb, "\tService: %s (%p)\n", print_session->service->name, print_session->service);
|
||||
dcb_printf(dcb, "\tClient DCB: %p\n", print_session->client_dcb);
|
||||
if (print_session->client_dcb && print_session->client_dcb->remote)
|
||||
{
|
||||
double idle = (hkheartbeat - ptr->client->last_read);
|
||||
double idle = (hkheartbeat - print_session->client_dcb->last_read);
|
||||
idle = idle > 0 ? idle/10.f : 0;
|
||||
dcb_printf(dcb, "\tClient Address: %s%s%s\n",
|
||||
ptr->client->user?ptr->client->user:"",
|
||||
ptr->client->user?"@":"",
|
||||
ptr->client->remote);
|
||||
print_session->client_dcb->user?print_session->client_dcb->user:"",
|
||||
print_session->client_dcb->user?"@":"",
|
||||
print_session->client_dcb->remote);
|
||||
dcb_printf(dcb, "\tConnected: %s\n",
|
||||
asctime_r(localtime_r(&ptr->stats.connect, &result), buf));
|
||||
if (ptr->client->state == DCB_STATE_POLLING)
|
||||
asctime_r(localtime_r(&print_session->stats.connect, &result), buf));
|
||||
if (print_session->client_dcb->state == DCB_STATE_POLLING)
|
||||
{
|
||||
dcb_printf(dcb, "\tIdle: %.0f seconds\n",idle);
|
||||
}
|
||||
|
||||
}
|
||||
if (ptr->n_filters)
|
||||
if (print_session->n_filters)
|
||||
{
|
||||
for (i = 0; i < ptr->n_filters; i++)
|
||||
for (i = 0; i < print_session->n_filters; i++)
|
||||
{
|
||||
dcb_printf(dcb, "\tFilter: %s\n",
|
||||
ptr->filters[i].filter->name);
|
||||
ptr->filters[i].filter->obj->diagnostics(ptr->filters[i].instance,
|
||||
ptr->filters[i].session,
|
||||
print_session->filters[i].filter->name);
|
||||
print_session->filters[i].filter->obj->diagnostics(print_session->filters[i].instance,
|
||||
print_session->filters[i].session,
|
||||
dcb);
|
||||
}
|
||||
}
|
||||
@ -728,26 +717,26 @@ dprintSession(DCB *dcb, SESSION *ptr)
|
||||
void
|
||||
dListSessions(DCB *dcb)
|
||||
{
|
||||
SESSION *ptr;
|
||||
SESSION *list_session;
|
||||
|
||||
spinlock_acquire(&session_spin);
|
||||
ptr = allSessions;
|
||||
if (ptr)
|
||||
list_session = allSessions;
|
||||
if (list_session)
|
||||
{
|
||||
dcb_printf(dcb, "Sessions.\n");
|
||||
dcb_printf(dcb, "-----------------+-----------------+----------------+--------------------------\n");
|
||||
dcb_printf(dcb, "Session | Client | Service | State\n");
|
||||
dcb_printf(dcb, "-----------------+-----------------+----------------+--------------------------\n");
|
||||
}
|
||||
while (ptr)
|
||||
while (list_session)
|
||||
{
|
||||
dcb_printf(dcb, "%-16p | %-15s | %-14s | %s\n", ptr,
|
||||
((ptr->client && ptr->client->remote)
|
||||
? ptr->client->remote : ""),
|
||||
(ptr->service && ptr->service->name ? ptr->service->name
|
||||
dcb_printf(dcb, "%-16p | %-15s | %-14s | %s\n", list_session,
|
||||
((list_session->client_dcb && list_session->client_dcb->remote)
|
||||
? list_session->client_dcb->remote : ""),
|
||||
(list_session->service && list_session->service->name ? list_session->service->name
|
||||
: ""),
|
||||
session_state(ptr->state));
|
||||
ptr = ptr->next;
|
||||
session_state(list_session->state));
|
||||
list_session = list_session->next;
|
||||
}
|
||||
if (allSessions)
|
||||
{
|
||||
@ -901,7 +890,7 @@ session_reply(void *instance, void *session, GWBUF *data)
|
||||
{
|
||||
SESSION *the_session = (SESSION *)session;
|
||||
|
||||
return the_session->client->func.write(the_session->client, data);
|
||||
return the_session->client_dcb->func.write(the_session->client_dcb, data);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -912,9 +901,9 @@ session_reply(void *instance, void *session, GWBUF *data)
|
||||
char *
|
||||
session_get_remote(SESSION *session)
|
||||
{
|
||||
if (session && session->client)
|
||||
if (session && session->client_dcb)
|
||||
{
|
||||
return session->client->remote;
|
||||
return session->client_dcb->remote;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -954,7 +943,7 @@ return_succp:
|
||||
char *
|
||||
session_getUser(SESSION *session)
|
||||
{
|
||||
return (session && session->client) ? session->client->user : NULL;
|
||||
return (session && session->client_dcb) ? session->client_dcb->user : NULL;
|
||||
}
|
||||
/**
|
||||
* Return the pointer to the list of all sessions.
|
||||
@ -992,17 +981,17 @@ void process_idle_sessions()
|
||||
* check for it once per second. One heartbeat is 100 milliseconds. */
|
||||
next_timeout_check = hkheartbeat + 10;
|
||||
spinlock_acquire(&session_spin);
|
||||
SESSION *ses = get_all_sessions();
|
||||
SESSION *all_session = get_all_sessions();
|
||||
|
||||
while (ses)
|
||||
while (all_session)
|
||||
{
|
||||
if (ses->service && ses->client && ses->client->state == DCB_STATE_POLLING &&
|
||||
hkheartbeat - ses->client->last_read > ses->service->conn_idle_timeout * 10)
|
||||
if (all_session->service && all_session->client_dcb && all_session->client_dcb->state == DCB_STATE_POLLING &&
|
||||
hkheartbeat - all_session->client_dcb->last_read > all_session->service->conn_idle_timeout * 10)
|
||||
{
|
||||
dcb_close(ses->client);
|
||||
dcb_close(all_session->client_dcb);
|
||||
}
|
||||
|
||||
ses = ses->next;
|
||||
all_session = all_session->next;
|
||||
}
|
||||
spinlock_release(&session_spin);
|
||||
}
|
||||
@ -1033,20 +1022,20 @@ sessionRowCallback(RESULTSET *set, void *data)
|
||||
int i = 0;
|
||||
char buf[20];
|
||||
RESULT_ROW *row;
|
||||
SESSION *ptr;
|
||||
SESSION *list_session;
|
||||
|
||||
spinlock_acquire(&session_spin);
|
||||
ptr = allSessions;
|
||||
list_session = allSessions;
|
||||
/* Skip to the first non-listener if not showing listeners */
|
||||
while (ptr && cbdata->filter == SESSION_LIST_CONNECTION &&
|
||||
ptr->state == SESSION_STATE_LISTENER)
|
||||
while (list_session && cbdata->filter == SESSION_LIST_CONNECTION &&
|
||||
list_session->state == SESSION_STATE_LISTENER)
|
||||
{
|
||||
ptr = ptr->next;
|
||||
list_session = list_session->next;
|
||||
}
|
||||
while (i < cbdata->index && ptr)
|
||||
while (i < cbdata->index && list_session)
|
||||
{
|
||||
if (cbdata->filter == SESSION_LIST_CONNECTION &&
|
||||
ptr->state != SESSION_STATE_LISTENER)
|
||||
list_session->state != SESSION_STATE_LISTENER)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
@ -1054,15 +1043,15 @@ sessionRowCallback(RESULTSET *set, void *data)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
ptr = ptr->next;
|
||||
list_session = list_session->next;
|
||||
}
|
||||
/* Skip to the next non-listener if not showing listeners */
|
||||
while (ptr && cbdata->filter == SESSION_LIST_CONNECTION &&
|
||||
ptr->state == SESSION_STATE_LISTENER)
|
||||
while (list_session && cbdata->filter == SESSION_LIST_CONNECTION &&
|
||||
list_session->state == SESSION_STATE_LISTENER)
|
||||
{
|
||||
ptr = ptr->next;
|
||||
list_session = list_session->next;
|
||||
}
|
||||
if (ptr == NULL)
|
||||
if (list_session == NULL)
|
||||
{
|
||||
spinlock_release(&session_spin);
|
||||
free(data);
|
||||
@ -1070,14 +1059,14 @@ sessionRowCallback(RESULTSET *set, void *data)
|
||||
}
|
||||
cbdata->index++;
|
||||
row = resultset_make_row(set);
|
||||
snprintf(buf,19, "%p", ptr);
|
||||
snprintf(buf,19, "%p", list_session);
|
||||
buf[19] = '\0';
|
||||
resultset_row_set(row, 0, buf);
|
||||
resultset_row_set(row, 1, ((ptr->client && ptr->client->remote)
|
||||
? ptr->client->remote : ""));
|
||||
resultset_row_set(row, 2, (ptr->service && ptr->service->name
|
||||
? ptr->service->name : ""));
|
||||
resultset_row_set(row, 3, session_state(ptr->state));
|
||||
resultset_row_set(row, 1, ((list_session->client_dcb && list_session->client_dcb->remote)
|
||||
? list_session->client_dcb->remote : ""));
|
||||
resultset_row_set(row, 2, (list_session->service && list_session->service->name
|
||||
? list_session->service->name : ""));
|
||||
resultset_row_set(row, 3, session_state(list_session->state));
|
||||
spinlock_release(&session_spin);
|
||||
return row;
|
||||
}
|
||||
@ -1111,3 +1100,21 @@ sessionGetList(SESSIONLISTFILTER filter)
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free the client data pointed to by the passed DCB.
|
||||
*
|
||||
* Currently all that is required is to free the storage pointed to by
|
||||
* dcb->data. But this is intended to be implemented as part of the
|
||||
* authentication API at which time this code will be moved into the
|
||||
* MySQL authenticator. If the data structure were to become more complex
|
||||
* the mechanism would still work and be the responsibility of the authenticator.
|
||||
* The DCB should not know authenticator implementation details.
|
||||
*
|
||||
* @param dcb Request handler DCB connected to the client
|
||||
*/
|
||||
static void
|
||||
mysql_auth_free_client_data(DCB *dcb)
|
||||
{
|
||||
free(dcb->data);
|
||||
}
|
@ -58,7 +58,7 @@ init_test_env(NULL);
|
||||
|
||||
/* Service tests */
|
||||
ss_dfprintf(stderr,
|
||||
"testservice : creating service called MyService with router nonexistent");
|
||||
"testservice : creating service called MyService with router nonexistent");
|
||||
service = service_alloc("MyService", "non-existent");
|
||||
mxs_log_flush_sync();
|
||||
ss_info_dassert(NULL == service, "New service with invalid router should be null");
|
||||
@ -70,7 +70,7 @@ init_test_env(NULL);
|
||||
ss_info_dassert(0 != service_isvalid(service), "Service must be valid after creation");
|
||||
ss_info_dassert(0 == strcmp("MyService", service_get_name(service)), "Service must have given name");
|
||||
ss_dfprintf(stderr, "\t..done\nAdding protocol testprotocol.");
|
||||
ss_info_dassert(0 != serviceAddProtocol(service, "testprotocol", "localhost", 9876), "Add Protocol should succeed");
|
||||
ss_info_dassert(0 != serviceAddProtocol(service, "testprotocol", "localhost", 9876, "MySQL", NULL), "Add Protocol should succeed");
|
||||
ss_info_dassert(0 != serviceHasProtocol(service, "testprotocol", 9876), "Service should have new protocol as requested");
|
||||
serviceStartProtocol(service, "testprotocol", 9876);
|
||||
mxs_log_flush_sync();
|
||||
@ -90,7 +90,7 @@ init_test_env(NULL);
|
||||
ss_dfprintf(stderr, "\t..done\n");
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
Reference in New Issue
Block a user