Merge branch 'develop' into 1.2.1-binlog_router

Conflicts:
	server/core/server.c
	server/include/server.h
	server/modules/include/blr.h
	server/modules/routing/binlog/blr.c
	server/modules/routing/binlog/blr_file.c
	server/modules/routing/binlog/blr_master.c
	server/modules/routing/binlog/blr_slave.c
This commit is contained in:
root
2015-08-04 07:59:44 -04:00
181 changed files with 9740 additions and 4538 deletions

View File

@ -1,5 +1,5 @@
if(BUILD_TESTS OR BUILD_TOOLS)
add_library(fullcore STATIC adminusers.c atomic.c config.c buffer.c dbusers.c dcb.c filter.c gwbitmask.c gw_utils.c hashtable.c hint.c housekeeper.c load_utils.c memlog.c modutil.c monitor.c poll.c resultset.c secrets.c server.c service.c session.c spinlock.c thread.c users.c utils.c)
add_library(fullcore STATIC adminusers.c atomic.c config.c buffer.c dbusers.c dcb.c filter.c gwbitmask.c gw_utils.c hashtable.c hint.c housekeeper.c load_utils.c memlog.c modutil.c monitor.c poll.c resultset.c secrets.c server.c service.c session.c spinlock.c thread.c users.c utils.c gwdirs.c externcmd.c)
if(WITH_JEMALLOC)
target_link_libraries(fullcore ${JEMALLOC_LIBRARIES})
elseif(WITH_TCMALLOC)
@ -12,7 +12,7 @@ add_executable(maxscale atomic.c buffer.c spinlock.c gateway.c
gw_utils.c utils.c dcb.c load_utils.c session.c service.c server.c
poll.c config.c users.c hashtable.c dbusers.c thread.c gwbitmask.c
monitor.c adminusers.c secrets.c filter.c modutil.c hint.c
housekeeper.c memlog.c resultset.c)
housekeeper.c memlog.c resultset.c gwdirs.c externcmd.c)
if(WITH_JEMALLOC)
target_link_libraries(maxscale ${JEMALLOC_LIBRARIES})
@ -21,15 +21,15 @@ elseif(WITH_TCMALLOC)
endif()
target_link_libraries(maxscale ${EMBEDDED_LIB} ${PCRE_LINK_FLAGS} ${CURL_LIBRARIES} log_manager utils ssl aio pthread crypt dl crypto inih z rt m stdc++)
install(TARGETS maxscale DESTINATION bin)
install(TARGETS maxscale DESTINATION ${MAXSCALE_BINDIR})
add_executable(maxkeys maxkeys.c secrets.c utils.c)
add_executable(maxkeys maxkeys.c secrets.c utils.c gwdirs.c)
target_link_libraries(maxkeys log_manager utils pthread crypt crypto)
install(TARGETS maxkeys DESTINATION bin)
install(TARGETS maxkeys DESTINATION ${MAXSCALE_BINDIR})
add_executable(maxpasswd maxpasswd.c secrets.c utils.c)
add_executable(maxpasswd maxpasswd.c secrets.c utils.c gwdirs.c)
target_link_libraries(maxpasswd log_manager utils pthread crypt crypto)
install(TARGETS maxpasswd DESTINATION bin)
install(TARGETS maxpasswd DESTINATION ${MAXSCALE_BINDIR})
if(BUILD_TESTS)
add_subdirectory(test)

View File

@ -19,13 +19,16 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define _XOPEN_SOURCE
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 700
#endif
#include <unistd.h>
#include <crypt.h>
#include <users.h>
#include <adminusers.h>
#include <skygw_utils.h>
#include <log_manager.h>
#include <gwdirs.h>
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
@ -119,12 +122,7 @@ char fname[1024], *home;
char uname[80], passwd[80];
initialise();
if ((home = getenv("MAXSCALE_HOME")) != NULL && strlen(home) < 1024){
sprintf(fname, "%s/etc/passwd", home);
}
else{
sprintf(fname, "/usr/local/mariadb-maxscale/etc/passwd");
}
sprintf(fname, "%s/passwd", get_datadir());
if ((fp = fopen(fname, "r")) == NULL)
return NULL;
if ((rval = users_alloc()) == NULL)
@ -155,12 +153,7 @@ FILE *fp;
char fname[1024], *home, *cpasswd;
initialise();
if ((home = getenv("MAXSCALE_HOME")) != NULL && strlen(home) < 1024){
sprintf(fname, "%s/etc/passwd", home);
}
else{
sprintf(fname, "/usr/local/mariadb-maxscale/etc/passwd");
}
sprintf(fname, "%s/passwd", get_datadir());
if (users == NULL)
{
@ -253,15 +246,8 @@ char* admin_remove_user(
/**
* Open passwd file and remove user from the file.
*/
if ((home = getenv("MAXSCALE_HOME")) != NULL &&
strnlen(home,PATH_MAX) < PATH_MAX &&
strnlen(home,PATH_MAX) > 0) {
sprintf(fname, "%s/etc/passwd", home);
sprintf(fname_tmp, "%s/etc/passwd_tmp", home);
} else {
sprintf(fname, "/usr/local/mariadb-maxscale/etc/passwd");
sprintf(fname_tmp, "/usr/local/mariadb-maxscale/etc/passwd_tmp");
}
sprintf(fname, "%s/passwd", get_datadir());
sprintf(fname_tmp, "%s/passwd_tmp", get_datadir());
/**
* Rewrite passwd file from memory.
*/

View File

@ -197,6 +197,7 @@ GWBUF *rval;
rval->gwbuf_info = buf->gwbuf_info;
rval->gwbuf_bufobj = buf->gwbuf_bufobj;
rval->tail = rval;
rval->next = NULL;
CHK_GWBUF(rval);
return rval;
}

View File

@ -41,9 +41,9 @@
* 30/10/14 Massimiliano Pinto Added disable_master_failback parameter
* 07/11/14 Massimiliano Pinto Addition of monitor timeouts for connect/read/write
* 20/02/15 Markus Mäkelä Added connection_timeout parameter for services
* 05/03/15 Massimiliano Pinto Added notification_feedback support
* 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
*
* @endverbatim
*/
@ -85,6 +85,7 @@ static int process_config_context(CONFIG_CONTEXT *);
static int process_config_update(CONFIG_CONTEXT *);
static void free_config_context(CONFIG_CONTEXT *);
static char *config_get_value(CONFIG_PARAMETER *, const char *);
static const char *config_get_value_string(CONFIG_PARAMETER *, const char *);
static int handle_global_item(const char *, const char *);
static int handle_feedback_item(const char *, const char *);
static void global_defaults();
@ -300,18 +301,18 @@ int rval;
static int
process_config_context(CONFIG_CONTEXT *context)
{
CONFIG_CONTEXT *obj;
int error_count = 0;
HASHTABLE* monitorhash;
CONFIG_CONTEXT *obj;
int error_count = 0;
HASHTABLE* monitorhash;
if((monitorhash = hashtable_alloc(5,simple_str_hash,strcmp)) == NULL)
{
skygw_log_write(LOGFILE_ERROR,"Error: Failed to allocate ,onitor configuration check hashtable.");
return 0;
}
if((monitorhash = hashtable_alloc(5,simple_str_hash,strcmp)) == NULL)
{
skygw_log_write(LOGFILE_ERROR,"Error: Failed to allocate ,monitor configuration check hashtable.");
return 0;
}
hashtable_memory_fns(monitorhash,(HASHMEMORYFN)strdup,NULL,(HASHMEMORYFN)free,NULL);
hashtable_memory_fns(monitorhash,strdup,NULL,free,NULL);
/**
/**
* Process the data and create the services and servers defined
* in the data.
*/
@ -345,6 +346,8 @@ hashtable_memory_fns(monitorhash,strdup,NULL,free,NULL);
char *weightby;
char *version_string;
char *subservices;
char *ssl,*ssl_cert,*ssl_key,*ssl_ca_cert,*ssl_version;
char* ssl_cert_verify_depth;
bool is_rwsplit = false;
bool is_schemarouter = false;
char *allow_localhost_match_wildcard_host;
@ -353,6 +356,12 @@ hashtable_memory_fns(monitorhash,strdup,NULL,free,NULL);
user = config_get_value(obj->parameters, "user");
auth = config_get_value(obj->parameters, "passwd");
subservices = config_get_value(obj->parameters, "subservices");
ssl = config_get_value(obj->parameters, "ssl");
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");
enable_root_user = config_get_value(
obj->parameters,
"enable_root_user");
@ -443,7 +452,84 @@ hashtable_memory_fns(monitorhash,strdup,NULL,free,NULL);
max_slave_rlag_str =
config_get_value(obj->parameters,
"max_slave_replication_lag");
if(ssl)
{
if(ssl_cert == NULL)
{
error_count++;
skygw_log_write(LE,"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(ssl_ca_cert == NULL)
{
error_count++;
skygw_log_write(LE,"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(ssl_key == NULL)
{
error_count++;
skygw_log_write(LE,"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(ssl_ca_cert,F_OK) != 0)
{
skygw_log_write(LE,"Error: Certificate authority file for service '%s' not found: %s",
obj->object,
ssl_ca_cert);
error_count++;
}
if(access(ssl_cert,F_OK) != 0)
{
skygw_log_write(LE,"Error: Server certificate file for service '%s' not found: %s",
obj->object,
ssl_cert);
error_count++;
}
if(access(ssl_key,F_OK) != 0)
{
skygw_log_write(LE,"Error: Server private key file for service '%s' not found: %s",
obj->object,
ssl_key);
error_count++;
}
if(error_count == 0)
{
if(serviceSetSSL(obj->element,ssl) != 0)
{
skygw_log_write(LE,"Error: Unknown parameter for service '%s': %s",obj->object,ssl);
error_count++;
}
else
{
serviceSetCertificates(obj->element,ssl_cert,ssl_key,ssl_ca_cert);
if(ssl_version)
{
if(serviceSetSSLVersion(obj->element,ssl_version) != 0)
{
skygw_log_write(LE,"Error: Unknown parameter value for 'ssl_version' for service '%s': %s",obj->object,ssl_version);
error_count++;
}
}
if(ssl_cert_verify_depth)
{
if(serviceSetSSLVerifyDepth(obj->element,atoi(ssl_cert_verify_depth)) != 0)
{
skygw_log_write(LE,"Error: Invalid parameter value for 'ssl_cert_verify_depth' for service '%s': %s",obj->object,ssl_cert_verify_depth);
error_count++;
}
}
}
}
}
if (enable_root_user)
serviceEnableRootUser(
obj->element,
@ -678,6 +764,9 @@ hashtable_memory_fns(monitorhash,strdup,NULL,free,NULL);
}
if (obj->element)
{
SERVER *server = obj->element;
server->persistpoolmax = strtol(config_get_value_string(obj->parameters, "persistpoolmax"), NULL, 0);
server->persistmaxtime = strtol(config_get_value_string(obj->parameters, "persistmaxtime"), NULL, 0);
CONFIG_PARAMETER *params = obj->parameters;
while (params)
{
@ -691,6 +780,10 @@ hashtable_memory_fns(monitorhash,strdup,NULL,free,NULL);
"monitorpw")
&& strcmp(params->name,
"type")
&& strcmp(params->name,
"persistpoolmax")
&& strcmp(params->name,
"persistmaxtime")
)
{
serverAddParameter(obj->element,
@ -847,62 +940,69 @@ hashtable_memory_fns(monitorhash,strdup,NULL,free,NULL);
/* if id is not set, do it now */
if (gateway.id == 0) {
setipaddress(&serv_addr.sin_addr, (address == NULL) ? "0.0.0.0" : address);
gateway.id = (unsigned long) (serv_addr.sin_addr.s_addr + port != NULL ? atoi(port) : 0 + getpid());
}
if (service && socket && protocol) {
CONFIG_CONTEXT *ptr = context;
while (ptr && strcmp(ptr->object, service) != 0)
ptr = ptr->next;
if (ptr && ptr->element)
{
serviceAddProtocol(ptr->element,
protocol,
socket,
0);
} else {
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Listener '%s', "
"service '%s' not found. "
"Listener will not execute for socket %s.",
obj->object, service, socket)));
error_count++;
}
gateway.id = (unsigned long) (serv_addr.sin_addr.s_addr + (port != NULL ? atoi(port) : 0 + getpid()));
}
if (service && port && protocol) {
if(service && protocol && (socket || port))
{
if (socket)
{
CONFIG_CONTEXT *ptr = context;
while (ptr && strcmp(ptr->object, service) != 0)
ptr = ptr->next;
ptr = ptr->next;
if (ptr && ptr->element)
{
serviceAddProtocol(ptr->element,
protocol,
address,
atoi(port));
serviceAddProtocol(ptr->element,
protocol,
socket,
0);
}
else
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Listener '%s', "
"service '%s' not found. "
"Listener will not execute for socket %s.",
obj->object, service, socket)));
error_count++;
}
}
if (port)
{
CONFIG_CONTEXT *ptr = context;
while (ptr && strcmp(ptr->object, service) != 0)
ptr = ptr->next;
if (ptr && ptr->element)
{
serviceAddProtocol(ptr->element,
protocol,
address,
atoi(port));
}
else
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Listener '%s', "
"service '%s' not found. "
"Listener will not execute.",
obj->object, service)));
error_count++;
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Listener '%s', "
"service '%s' not found. "
"Listener will not execute.",
obj->object, service)));
error_count++;
}
}
}
else
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Listener '%s' is misisng a "
"required "
"parameter. A Listener must have a "
"service, port and protocol defined.",
obj->object)));
error_count++;
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Listener '%s' is missing a "
"required "
"parameter. A Listener must have a "
"service, port and protocol defined.",
obj->object)));
error_count++;
}
}
else if (!strcmp(type, "monitor"))
@ -1081,6 +1181,25 @@ config_get_value(CONFIG_PARAMETER *params, const char *name)
return NULL;
}
/**
* Get the value of a config parameter as a string
*
* @param params The linked list of config parameters
* @param name The parameter to return
* @return the parameter value or null string if not found
*/
static const char *
config_get_value_string(CONFIG_PARAMETER *params, const char *name)
{
while (params)
{
if (!strcmp(params->name, name))
return (const char *)params->value;
params = params->next;
}
return "";
}
CONFIG_PARAMETER* config_get_param(
CONFIG_PARAMETER* params,
@ -1339,7 +1458,7 @@ int i;
}
else if (strcmp(name, "ms_timestamp") == 0)
{
skygw_set_highp(config_truth_value(value));
skygw_set_highp(config_truth_value((char*)value));
}
else
{
@ -1347,7 +1466,7 @@ int i;
{
if (strcasecmp(name, lognames[i].logname) == 0)
{
if (config_truth_value(value))
if (config_truth_value((char*)value))
skygw_log_enable(lognames[i].logfile);
else
skygw_log_disable(lognames[i].logfile);
@ -1645,9 +1764,6 @@ SERVER *server;
char *enable_root_user;
char *connection_timeout;
char *allow_localhost_match_wildcard_host;
char *auth_all_servers;
char *optimize_wildcard;
char *strip_db_esc;
enable_root_user =
config_get_value(obj->parameters,
@ -1655,16 +1771,6 @@ SERVER *server;
connection_timeout = config_get_value(obj->parameters,
"connection_timeout");
auth_all_servers =
config_get_value(obj->parameters,
"auth_all_servers");
optimize_wildcard =
config_get_value(obj->parameters,
"optimize_wildcard");
strip_db_esc =
config_get_value(obj->parameters,
"strip_db_esc");
allow_localhost_match_wildcard_host =
config_get_value(obj->parameters, "localhost_match_wildcard_host");
@ -1735,6 +1841,9 @@ SERVER *server;
obj->element = server_alloc(address,
protocol,
atoi(port));
server_set_unique_name(obj->element, obj->object);
if (obj->element && monuser && monpw)
{
serverAddMonUser(obj->element,
@ -1922,6 +2031,12 @@ static char *service_params[] =
"version_string",
"filters",
"weightby",
"ssl_cert",
"ssl_ca_cert",
"ssl",
"ssl_key",
"ssl_version",
"ssl_cert_verify_depth",
NULL
};
@ -1943,6 +2058,9 @@ static char *monitor_params[] =
"servers",
"user",
"passwd",
"script",
"events",
"mysql51_replication",
"monitor_interval",
"detect_replication_lag",
"detect_stale_master",

View File

@ -210,7 +210,7 @@ HASHTABLE *oldresources;
oldusers = service->users;
/* digest compare */
if (memcmp(oldusers->cksum, newusers->cksum, SHA_DIGEST_LENGTH) == 0) {
if (oldusers != NULL && memcmp(oldusers->cksum, newusers->cksum, SHA_DIGEST_LENGTH) == 0) {
/* same data, nothing to do */
LOGIF(LD, (skygw_log_write_flush(
LOGFILE_DEBUG,
@ -234,7 +234,7 @@ HASHTABLE *oldresources;
spinlock_release(&service->spin);
if (i) {
if (i && oldusers) {
/* free the old table */
users_free(oldusers);
}
@ -974,7 +974,7 @@ getAllUsers(SERVICE *service, USERS *users)
}
}
if(service->optimize_wildcard && havedb && wildcard_db_grant(dbnm))
if(havedb && wildcard_db_grant(dbnm) && service->optimize_wildcard)
{
rc = add_wildcard_users(users, row[0], row[1], password, row[4], dbnm, service->resources);
skygw_log_write(LOGFILE_DEBUG|LOGFILE_TRACE,"%s: Converted '%s' to %d individual database grants.",service->name,dbnm,rc);
@ -984,9 +984,9 @@ getAllUsers(SERVICE *service, USERS *users)
rc = add_mysql_users_with_host_ipv4(users, row[0], row[1], password, row[4], havedb ? dbnm : NULL);
}
skygw_log_write(LOGFILE_DEBUG,"%s: Adding user:%s host:%s anydb:%s db:%s.",
LOGIF(LD,(skygw_log_write(LOGFILE_DEBUG,"%s: Adding user:%s host:%s anydb:%s db:%s.",
service->name,row[0],row[1],row[4],
havedb ? dbnm : NULL);
havedb ? dbnm : NULL)));
} else {
/* we don't have dbgrants, simply set ANY DB for the user */
rc = add_mysql_users_with_host_ipv4(users, row[0], row[1], password, "Y", NULL);
@ -1033,8 +1033,8 @@ getAllUsers(SERVICE *service, USERS *users)
} else if(rc == -1) {
/** Duplicate user*/
LOGIF(LE,(skygw_log_write(LT|LE,
"Warning: Duplicate MySQL user found for service [%s]: %s@%s%s%s",
LOGIF(LT,(skygw_log_write(LT,
"Duplicate MySQL user found for service [%s]: %s@%s%s%s",
service->name,
row[0],row[1],havedb?" for database: ":"",
havedb ?dbnm:"")));
@ -1118,6 +1118,7 @@ getUsers(SERVICE *service, USERS *users)
MYSQL_DATABASE_MAXLEN;
int dbnames = 0;
int db_grants = 0;
char dbnm[MYSQL_DATABASE_MAXLEN+1];
if (serviceGetUser(service, &service_user, &service_passwd) == 0)
{
@ -1474,16 +1475,40 @@ getUsers(SERVICE *service, USERS *users)
*/
if (db_grants) {
/* we have dbgrants, store them */
bool havedb = false;
/* we have dbgrants, store them */
if(row[5]){
unsigned long *rowlen = mysql_fetch_lengths(result);
memcpy(dbnm,row[5],rowlen[5]);
memset(dbnm + rowlen[5],0,1);
havedb = true;
if(service->strip_db_esc) {
strip_escape_chars(dbnm);
LOGIF(LD, (skygw_log_write(
LOGFILE_DEBUG,
"[%s]: %s -> %s",
service->name,
row[5],
dbnm)));
}
}
if(service->optimize_wildcard && wildcard_db_grant(row[5]))
if(havedb && wildcard_db_grant(row[5]))
{
rc = add_wildcard_users(users, row[0], row[1], password, row[4], row[5], service->resources);
skygw_log_write(LOGFILE_DEBUG|LOGFILE_TRACE,"%s: Converted '%s' to %d individual database grants.",service->name,row[5],rc);
if(service->optimize_wildcard)
{
rc = add_wildcard_users(users, row[0], row[1], password, row[4], dbnm, service->resources);
skygw_log_write(LOGFILE_DEBUG|LOGFILE_TRACE,"%s: Converted '%s' to %d individual database grants.",service->name,row[5],rc);
}
else
{
/** Use ANYDB for wildcard grants */
rc = add_mysql_users_with_host_ipv4(users, row[0], row[1], password, "Y", NULL);
}
}
else
{
rc = add_mysql_users_with_host_ipv4(users, row[0], row[1], password, row[4], row[5]);
rc = add_mysql_users_with_host_ipv4(users, row[0], row[1], password, row[4], havedb ? dbnm : NULL);
}
} else {
@ -1683,6 +1708,41 @@ static int uh_cmpfun( void* v1, void* v2) {
return 0;
}
if(hu2->resource && strlen(hu2->resource) && strchr(hu2->resource,'%') != NULL)
{
regex_t re;
char db[MYSQL_DATABASE_MAXLEN*2 +1];
strcpy(db,hu2->resource);
int len = strlen(db);
char* ptr = strrchr(db,'%');
if(ptr == NULL)
{
return 1;
}
while(ptr)
{
memmove(ptr+1,ptr,(len - (ptr - db)) + 1);
*ptr = '.';
*(ptr + 1) = '*';
len = strlen(db);
ptr = strrchr(db,'%');
}
if((regcomp(&re,db,REG_ICASE|REG_NOSUB)))
{
return 1;
}
if(regexec(&re,hu1->resource,0,NULL,0) == 0)
{
regfree(&re);
return 0;
}
regfree(&re);
}
/* no matches, deny auth */
return 1;
}
@ -1792,18 +1852,6 @@ char *mysql_format_user_entry(void *data)
return mysql_user;
}
/*
* The hash function we use for storing MySQL database names.
*
* @param key The key value
* @return The hash key
*/
int
resource_hash(char *key)
{
return (*key + *(key + 1));
}
/**
* Remove the resources table
*
@ -1827,7 +1875,7 @@ resource_alloc()
{
HASHTABLE *resources;
if ((resources = hashtable_alloc(10, resource_hash, strcmp)) == NULL)
if ((resources = hashtable_alloc(10, simple_str_hash, strcmp)) == NULL)
{
return NULL;
}

File diff suppressed because it is too large Load Diff

169
server/core/externcmd.c Normal file
View File

@ -0,0 +1,169 @@
#include <externcmd.h>
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
extern size_t log_ses_count[];
extern __thread log_info_t tls_log_info;
/**
* Tokenize a string into arguments suitable for a execvp call.
* @param args Argument string
* @param argv Array of char pointers to be filled with tokenized arguments
* @return 0 on success, -1 on error
*/
int tokenize_arguments(char* args, char** argv)
{
int i = 0;
bool quoted = false;
bool read = false;
bool escaped = false;
char *ptr,*start;
char qc;
start = args;
ptr = start;
while(*ptr != '\0' && i < MAXSCALE_EXTCMD_ARG_MAX)
{
if(escaped)
{
escaped = false;
}
else
{
if(*ptr == '\\')
{
escaped = true;
}
else if(quoted && !escaped && *ptr == qc) /** End of quoted string */
{
*ptr = '\0';
argv[i++] = strdup(start);
read = false;
quoted = false;
}
else if (!quoted)
{
if(isspace(*ptr))
{
*ptr = '\0';
if(read) /** New token */
{
argv[i++] = strdup(start);
read = false;
}
}
else if( *ptr == '\"' || *ptr == '\'')
{
/** New quoted token, strip quotes */
quoted = true;
qc = *ptr;
start = ptr + 1;
}
else if(!read)
{
start = ptr;
read = true;
}
}
}
ptr++;
}
if(read)
argv[i++] = strdup(start);
argv[i] = NULL;
return 0;
}
/**
* Allocate a new external command.
* The name and parameters are copied into the external command structure so
* the original memory can be freed if needed.
* @param command Command to execute with the parameters
* @return Pointer to new external command struct or NULL if an error occurred
*/
EXTERNCMD* externcmd_allocate(char* argstr)
{
EXTERNCMD* cmd;
if(argstr == NULL)
return NULL;
if((cmd = (EXTERNCMD*)malloc(sizeof(EXTERNCMD))) != NULL)
{
if(tokenize_arguments(argstr,cmd->parameters) == -1)
{
free(cmd);
return NULL;
}
if(access(cmd->parameters[0],F_OK) != 0)
{
skygw_log_write(LE,
"Error: Cannot find file: %s",
cmd->parameters[0]);
externcmd_free(cmd);
return NULL;
}
if(access(cmd->parameters[0],X_OK) != 0)
{
skygw_log_write(LE,
"Error: Cannot execute file: %s",
cmd->parameters[0]);
externcmd_free(cmd);
return NULL;
}
}
return cmd;
}
/**
* Free a previously allocated external command.
* @param cmd Command to free
*/
void externcmd_free(EXTERNCMD* cmd)
{
int i;
for(i = 0;cmd->parameters[i] != NULL;i++)
{
free(cmd->parameters[i]);
}
free(cmd);
}
/**
*Execute a command in a separate process.
*@param cmd Command to execute
*@return 0 on success, -1 on error.
*/
int externcmd_execute(EXTERNCMD* cmd)
{
int rval = 0;
pid_t pid;
pid = fork();
if(pid < 0)
{
skygw_log_write(LOGFILE_ERROR,"Error: Failed to execute command '%s', fork failed: [%d] %s",
cmd->parameters[0],errno,strerror(errno));
rval = -1;
}
else if(pid == 0)
{
/** Child process, execute command */
execvp(cmd->parameters[0],cmd->parameters);
_exit(1);
}
else
{
cmd->child = pid;
cmd->n_exec++;
LOGIF(LD,skygw_log_write(LD,"[monitor_exec_cmd] Forked child process %d : %s.",pid,cmd));
}
return rval;
}

File diff suppressed because it is too large Load Diff

29
server/core/gwdirs.c Normal file
View File

@ -0,0 +1,29 @@
#include <gwdirs.h>
/**
* Get the directory with all the modules.
* @return The module directory
*/
char* get_libdir()
{
return libdir?libdir:(char*)default_libdir;
}
/**
* Get the service cache directory
* @return The path to the cache directory
*/
char* get_cachedir()
{
return cachedir?cachedir:(char*)default_cachedir;
}
/**
* Get the service cache directory
* @return The path to the cache directory
*/
char* get_datadir()
{
return maxscaledatadir?maxscaledatadir:(char*)default_datadir;
}

View File

@ -170,6 +170,9 @@ hashtable_free(HASHTABLE *table)
int i;
HASHENTRIES *entry, *ptr;
if(table == NULL)
return;
hashtable_write_lock(table);
for (i = 0; i < table->hashsize; i++)
{
@ -235,7 +238,7 @@ hashtable_add(HASHTABLE *table, void *key, void *value)
unsigned int hashkey;
HASHENTRIES *entry;
if (key == NULL || value == NULL)
if (table == NULL || key == NULL || value == NULL)
return 0;
if (table->hashsize <= 0) {
@ -308,9 +311,13 @@ hashtable_add(HASHTABLE *table, void *key, void *value)
int
hashtable_delete(HASHTABLE *table, void *key)
{
unsigned int hashkey = table->hashfn(key) % table->hashsize;
unsigned int hashkey;
HASHENTRIES *entry, *ptr;
if(table == NULL || key == NULL)
return 0;
hashkey = table->hashfn(key) % table->hashsize;
hashtable_write_lock(table);
entry = table->entries[hashkey % table->hashsize];
while (entry && entry->key && table->cmpfn(key, entry->key) != 0)
@ -369,9 +376,13 @@ HASHENTRIES *entry, *ptr;
void *
hashtable_fetch(HASHTABLE *table, void *key)
{
unsigned int hashkey = table->hashfn(key) % table->hashsize;
unsigned int hashkey;
HASHENTRIES *entry;
if(table == NULL || key == NULL)
return NULL;
hashkey = table->hashfn(key) % table->hashsize;
hashtable_read_lock(table);
entry = table->entries[hashkey % table->hashsize];
while (entry && entry->key && table->cmpfn(key, entry->key) != 0)
@ -401,6 +412,9 @@ hashtable_stats(HASHTABLE *table)
int total, longest, i, j;
HASHENTRIES *entries;
if(table == NULL)
return;
printf("Hashtable: %p, size %d\n", table, table->hashsize);
total = 0;
longest = 0;
@ -606,6 +620,9 @@ hashtable_next(HASHITERATOR *iter)
int i;
HASHENTRIES *entries;
if(iter == NULL)
return NULL;
iter->depth++;
while (iter->chain < iter->table->hashsize)
{

View File

@ -48,6 +48,8 @@
#include <curl/curl.h>
#include <sys/utsname.h>
#include <openssl/sha.h>
#include <gw.h>
#include <gwdirs.h>
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
@ -104,21 +106,10 @@ WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
return realsize;
}
char* get_maxscale_home(void)
{
char* home = getenv("MAXSCALE_HOME");
if (home == NULL)
{
home = "/usr/local/mariadb-maxscale";
}
return home;
}
/**
* Load the dynamic library related to a gateway module. The routine
* will look for library files in the current directory,
* $MAXSCALE_HOME/modules and /usr/local/mariadb-maxscale/modules.
* the configured folder and /usr/lib64/maxscale.
*
* @param module Name of the module to load
* @param type Type of module, used purely for registration
@ -142,22 +133,17 @@ MODULE_INFO *mod_info = NULL;
*
* Search of the shared object.
*/
snprintf(fname,MAXPATHLEN+1, "./lib%s.so", module);
snprintf(fname, MAXPATHLEN+1,"%s/lib%s.so", get_libdir(), module);
if (access(fname, F_OK) == -1)
{
home = get_maxscale_home ();
snprintf(fname, MAXPATHLEN+1,"%s/modules/lib%s.so", home, module);
if (access(fname, F_OK) == -1)
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Unable to find library for "
"module: %s.",
module)));
return NULL;
}
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Unable to find library for "
"module: %s. Module dir: %s",
module, get_libdir())));
return NULL;
}
if ((dlhandle = dlopen(fname, RTLD_NOW|RTLD_LOCAL)) == NULL)

View File

@ -31,19 +31,25 @@
#include <secrets.h>
#include <skygw_utils.h>
#include <log_manager.h>
#include <gwdirs.h>
int main(int argc, char **argv)
{
int arg_count = 6;
int arg_count = 4;
char *home;
char *keyfile;
char** arg_vector;
int rval = 0;
if (argc != 2)
if (argc < 2)
{
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
return 1;
keyfile = "/var/lib/maxscale/";
fprintf(stderr, "Generating .secrets file in /var/lib/maxscale/ ...\n");
}
else
{
keyfile = argv[1];
}
arg_vector = malloc(sizeof(char*)*(arg_count + 1));
if(arg_vector == NULL)
@ -54,26 +60,14 @@ int main(int argc, char **argv)
arg_vector[0] = "logmanager";
arg_vector[1] = "-j";
if ((home = getenv("MAXSCALE_HOME")) != NULL)
{
arg_vector[2] = (char*)malloc((strlen(home) + strlen("/log"))*sizeof(char));
sprintf(arg_vector[2],"%s/log",home);
}
else
{
arg_vector[2] = strdup("/usr/local/mariadb-maxscale/log");
}
arg_vector[3] = "-o";
arg_vector[4] = "-l";
arg_vector[5] = "LOGFILE_ERROR";
arg_vector[6] = NULL;
arg_vector[2] = "/var/log/maxscale/maxkeys";
arg_vector[3] = "-o";
arg_vector[4] = NULL;
skygw_logmanager_init(arg_count,arg_vector);
free(arg_vector[2]);
free(arg_vector);
if (secrets_writeKeys(argv[1]))
if (secrets_writeKeys(keyfile))
{
fprintf(stderr, "Failed to encode the password\n");
rval = 1;

View File

@ -46,9 +46,9 @@ main(int argc, char **argv)
char** arg_vector;
int rval = 0;
if (argc != 2)
if (argc != 3)
{
fprintf(stderr, "Usage: %s <password>\n", argv[0]);
fprintf(stderr, "Usage: %s <file> <password>\n", argv[0]);
return 1;
}
@ -60,18 +60,9 @@ main(int argc, char **argv)
return 1;
}
arg_vector[0] = "logmanager";
arg_vector[1] = "-j";
if ((home = getenv("MAXSCALE_HOME")) != NULL)
{
arg_vector[2] = (char*)malloc((strlen(home) + strlen("/log"))*sizeof(char));
sprintf(arg_vector[2],"%s/log",home);
}
else
{
arg_vector[2] = strdup("/usr/local/mariadb-maxscale/log");
}
arg_vector[0] = strdup("logmanager");
arg_vector[1] = strdup("-j");
arg_vector[2] = strdup("/var/log/maxscale");
arg_vector[3] = "-o";
arg_vector[4] = "-l";
@ -88,9 +79,9 @@ main(int argc, char **argv)
return 1;
}
strncpy(pw,argv[1],80);
strncpy(pw,argv[2],80);
if ((enc = encryptPassword(pw)) != NULL){
if ((enc = encryptPassword(argv[1],pw)) != NULL){
printf("%s\n", enc);
}else{
fprintf(stderr, "Failed to encode the password\n");

View File

@ -31,6 +31,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
static MEMLOG *memlogs = NULL;
static SPINLOCK memlock = SPINLOCK_INIT;
@ -133,7 +134,7 @@ memlog_log(MEMLOG *log, void *value)
switch (log->type)
{
case ML_INT:
((int *)(log->values))[log->offset] = (int)value;
((int *)(log->values))[log->offset] = (intptr_t)value;
break;
case ML_LONG:
((long *)(log->values))[log->offset] = (long)value;

View File

@ -540,7 +540,7 @@ GWBUF* modutil_get_complete_packets(GWBUF** p_readbuf)
{
GWBUF *buff = NULL, *packet;
uint8_t *ptr;
int len,blen,total = 0;
uint32_t len,blen,total = 0;
if(p_readbuf == NULL || (*p_readbuf) == NULL ||
gwbuf_length(*p_readbuf) < 3)
@ -841,4 +841,4 @@ int modutil_count_statements(GWBUF* buffer)
}
return num;
}
}

View File

@ -28,6 +28,7 @@
* and monitor id
* 30/10/14 Massimiliano Pinto Addition of disable_master_failback parameter
* 07/11/14 Massimiliano Pinto Addition of monitor network timeouts
* 08/05/15 Markus Makela Moved common monitor variables to MONITOR struct
*
* @endverbatim
*/
@ -65,8 +66,6 @@ MONITOR *mon;
{
return NULL;
}
mon->state = MONITOR_STATE_ALLOC;
mon->name = strdup(name);
if ((mon->module = load_module(module, MODULE_MONITOR)) == NULL)
{
@ -74,13 +73,21 @@ MONITOR *mon;
LOGFILE_ERROR,
"Error : Unable to load monitor module '%s'.",
name)));
free(mon->name);
free(mon);
return NULL;
}
mon->state = MONITOR_STATE_ALLOC;
mon->name = strdup(name);
mon->handle = NULL;
mon->databases = NULL;
mon->password = NULL;
mon->user = NULL;
mon->password = NULL;
mon->read_timeout = DEFAULT_READ_TIMEOUT;
mon->write_timeout = DEFAULT_WRITE_TIMEOUT;
mon->connect_timeout = DEFAULT_CONNECT_TIMEOUT;
mon->interval = MONITOR_INTERVAL;
spinlock_init(&mon->lock);
spinlock_acquire(&monLock);
mon->next = allMonitors;
allMonitors = mon;
@ -100,7 +107,7 @@ monitor_free(MONITOR *mon)
{
MONITOR *ptr;
mon->module->stopMonitor(mon->handle);
mon->module->stopMonitor(mon);
mon->state = MONITOR_STATE_FREED;
spinlock_acquire(&monLock);
if (allMonitors == mon)
@ -127,8 +134,10 @@ MONITOR *ptr;
void
monitorStart(MONITOR *monitor, void* params)
{
monitor->handle = (*monitor->module->startMonitor)(monitor->handle,params);
spinlock_acquire(&monitor->lock);
monitor->handle = (*monitor->module->startMonitor)(monitor,params);
monitor->state = MONITOR_STATE_RUNNING;
spinlock_release(&monitor->lock);
}
/**
@ -142,7 +151,7 @@ monitorStop(MONITOR *monitor)
if(monitor->state != MONITOR_STATE_STOPPED)
{
monitor->state = MONITOR_STATE_STOPPING;
monitor->module->stopMonitor(monitor->handle);
monitor->module->stopMonitor(monitor);
monitor->state = MONITOR_STATE_STOPPED;
}
}
@ -175,7 +184,32 @@ MONITOR *ptr;
void
monitorAddServer(MONITOR *mon, SERVER *server)
{
mon->module->registerServer(mon->handle, server);
MONITOR_SERVERS *ptr, *db;
if ((db = (MONITOR_SERVERS *)malloc(sizeof(MONITOR_SERVERS))) == NULL)
return;
db->server = server;
db->con = NULL;
db->next = NULL;
db->mon_err_count = 0;
db->log_version_err = true;
/** Server status is uninitialized */
db->mon_prev_status = -1;
/* pending status is updated by get_replication_tree */
db->pending_status = 0;
spinlock_acquire(&mon->lock);
if (mon->databases == NULL)
mon->databases = db;
else
{
ptr = mon->databases;
while (ptr->next != NULL)
ptr = ptr->next;
ptr->next = db;
}
spinlock_release(&mon->lock);
}
/**
@ -189,7 +223,8 @@ monitorAddServer(MONITOR *mon, SERVER *server)
void
monitorAddUser(MONITOR *mon, char *user, char *passwd)
{
mon->module->defaultUser(mon->handle, user, passwd);
mon->user = strdup(user);
mon->password = strdup(passwd);
}
/**
@ -209,7 +244,7 @@ MONITOR *ptr;
dcb_printf(dcb, "Monitor: %p\n", ptr);
dcb_printf(dcb, "\tName: %s\n", ptr->name);
if (ptr->module->diagnostics)
ptr->module->diagnostics(dcb, ptr->handle);
ptr->module->diagnostics(dcb, ptr);
ptr = ptr->next;
}
spinlock_release(&monLock);
@ -227,7 +262,7 @@ monitorShow(DCB *dcb, MONITOR *monitor)
dcb_printf(dcb, "Monitor: %p\n", monitor);
dcb_printf(dcb, "\tName: %s\n", monitor->name);
if (monitor->module->diagnostics)
monitor->module->diagnostics(dcb, monitor->handle);
monitor->module->diagnostics(dcb, monitor);
}
/**
@ -288,10 +323,7 @@ MONITOR *ptr;
void
monitorSetInterval (MONITOR *mon, unsigned long interval)
{
if (mon->module->setInterval != NULL) {
mon->interval = interval;
mon->module->setInterval(mon->handle, interval);
}
mon->interval = interval;
}
/**
@ -303,9 +335,55 @@ monitorSetInterval (MONITOR *mon, unsigned long interval)
*/
void
monitorSetNetworkTimeout(MONITOR *mon, int type, int value) {
if (mon->module->setNetworkTimeout != NULL) {
mon->module->setNetworkTimeout(mon->handle, type, value);
int max_timeout = (int)(mon->interval/1000);
int new_timeout = max_timeout -1;
if (new_timeout <= 0)
new_timeout = DEFAULT_CONNECT_TIMEOUT;
switch(type) {
case MONITOR_CONNECT_TIMEOUT:
if (value < max_timeout) {
memcpy(&mon->connect_timeout, &value, sizeof(int));
} else {
memcpy(&mon->connect_timeout, &new_timeout, sizeof(int));
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"warning : Monitor Connect Timeout %i is greater than monitor interval ~%i seconds"
", lowering to %i seconds", value, max_timeout, new_timeout)));
}
break;
case MONITOR_READ_TIMEOUT:
if (value < max_timeout) {
memcpy(&mon->read_timeout, &value, sizeof(int));
} else {
memcpy(&mon->read_timeout, &new_timeout, sizeof(int));
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"warning : Monitor Read Timeout %i is greater than monitor interval ~%i seconds"
", lowering to %i seconds", value, max_timeout, new_timeout)));
}
break;
case MONITOR_WRITE_TIMEOUT:
if (value < max_timeout) {
memcpy(&mon->write_timeout, &value, sizeof(int));
} else {
memcpy(&mon->write_timeout, &new_timeout, sizeof(int));
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"warning : Monitor Write Timeout %i is greater than monitor interval ~%i seconds"
", lowering to %i seconds", value, max_timeout, new_timeout)));
}
break;
default:
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Monitor setNetworkTimeout received an unsupported action type %i", type)));
break;
}
}
/**

View File

@ -15,10 +15,12 @@
*
* Copyright MariaDB Corporation Ab 2013-2014
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/epoll.h>
#include <errno.h>
#include <poll.h>
@ -71,6 +73,7 @@ int max_poll_sleep;
* in the loop after the epoll_wait. This allows for better
* thread utilisaiton and fairer scheduling of the event
* processing.
* 07/07/15 Martin Brampton Simplified add and remove DCB, improve error handling.
*
* @endverbatim
*/
@ -186,6 +189,11 @@ static struct {
*/
static void poll_loadav(void *);
/**
* Function to analyse error return from epoll_ctl
*/
static int poll_resolve_error(DCB *, int, bool);
/**
* Initialise the polling system we are using for the gateway.
*
@ -247,7 +255,7 @@ int
poll_add_dcb(DCB *dcb)
{
int rc = -1;
dcb_state_t old_state = DCB_STATE_UNDEFINED;
dcb_state_t old_state = dcb->state;
dcb_state_t new_state;
struct epoll_event ev;
@ -263,58 +271,67 @@ poll_add_dcb(DCB *dcb)
/*<
* Choose new state according to the role of dcb.
*/
spinlock_acquire(&dcb->dcb_initlock);
if (dcb->dcb_role == DCB_ROLE_REQUEST_HANDLER) {
new_state = DCB_STATE_POLLING;
} else {
ss_dassert(dcb->dcb_role == DCB_ROLE_SERVICE_LISTENER);
new_state = DCB_STATE_LISTENING;
}
/*<
* If dcb is in unexpected state, state change fails indicating that dcb
* is not polling anymore.
/*
* Check DCB current state seems sensible
*/
if (dcb_set_state(dcb, new_state, &old_state)) {
rc = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, dcb->fd, &ev);
if (rc != 0) {
int eno = errno;
errno = 0;
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Adding dcb %p in state %s "
"to poll set failed. epoll_ctl failed due "
"%d, %s.",
dcb,
STRDCBSTATE(dcb->state),
eno,
strerror(eno))));
} else {
LOGIF(LD, (skygw_log_write(
LOGFILE_DEBUG,
"%lu [poll_add_dcb] Added dcb %p in state %s to "
"poll set.",
pthread_self(),
dcb,
STRDCBSTATE(dcb->state))));
}
ss_info_dassert(rc == 0, "Unable to add poll"); /*< trap in debug */
} else {
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : Unable to set new state for dcb %p "
"in state %s. Adding to poll set failed.",
dcb,
STRDCBSTATE(dcb->state))));
if (DCB_STATE_DISCONNECTED == dcb->state
|| DCB_STATE_ZOMBIE == dcb->state
|| DCB_STATE_UNDEFINED == dcb->state)
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"%lu [poll_add_dcb] Error : existing state of dcb %p "
"is %s, but this should be impossible, crashing.",
pthread_self(),
dcb,
STRDCBSTATE(dcb->state))));
raise(SIGABRT);
}
if (DCB_STATE_POLLING == dcb->state
|| DCB_STATE_LISTENING == dcb->state)
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"%lu [poll_add_dcb] Error : existing state of dcb %p "
"is %s, but this is probably an error, not crashing.",
pthread_self(),
dcb,
STRDCBSTATE(dcb->state))));
}
dcb->state = new_state;
spinlock_release(&dcb->dcb_initlock);
/*
* The only possible failure that will not cause a crash is
* running out of system resources.
*/
rc = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, dcb->fd, &ev);
if (rc)
{
rc = poll_resolve_error(dcb, errno, true);
}
if (0 == rc)
{
LOGIF(LD, (skygw_log_write(
LOGFILE_DEBUG,
"%lu [poll_add_dcb] Added dcb %p in state %s to poll set.",
pthread_self(),
dcb,
STRDCBSTATE(dcb->state))));
}
else dcb->state = old_state;
return rc;
}
/**
* Remove a descriptor from the set of descriptors within the
* polling environment.
* The state change command may fail because concurrent threads may call
* dcb_set_state simultaneously and the conflict is prevented in dcb_set_state.
*
* @param dcb The descriptor to remove
* @return -1 on error or 0 on success
@ -322,63 +339,127 @@ poll_add_dcb(DCB *dcb)
int
poll_remove_dcb(DCB *dcb)
{
struct epoll_event ev;
int rc = -1;
dcb_state_t old_state = DCB_STATE_UNDEFINED;
dcb_state_t new_state = DCB_STATE_NOPOLLING;
struct epoll_event ev;
CHK_DCB(dcb);
spinlock_acquire(&dcb->dcb_initlock);
/*< It is possible that dcb has already been removed from the set */
if (dcb->state != DCB_STATE_POLLING)
{
if (dcb->state == DCB_STATE_NOPOLLING ||
dcb->state == DCB_STATE_ZOMBIE)
{
rc = 0;
}
goto return_rc;
if (dcb->state == DCB_STATE_NOPOLLING ||
dcb->state == DCB_STATE_ZOMBIE)
{
spinlock_release(&dcb->dcb_initlock);
return 0;
}
if (DCB_STATE_POLLING != dcb->state
&& DCB_STATE_LISTENING != dcb->state)
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"%lu [poll_remove_dcb] Error : existing state of dcb %p "
"is %s, but this is probably an error, not crashing.",
pthread_self(),
dcb,
STRDCBSTATE(dcb->state))));
}
/*<
* Set state to NOPOLLING and remove dcb from poll set.
*/
if (dcb_set_state(dcb, new_state, &old_state))
{
/**
* Only positive fds can be removed from epoll set.
*/
if (dcb->fd > 0)
{
rc = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, dcb->fd, &ev);
dcb->state = DCB_STATE_NOPOLLING;
spinlock_release(&dcb->dcb_initlock);
if (rc != 0) {
int eno = errno;
errno = 0;
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"Error : epoll_ctl failed due %d, %s.",
eno,
strerror(eno))));
}
ss_dassert(rc == 0); /*< trap in debug */
}
}
/*<
* This call was redundant, but the end result is correct.
*/
else if (old_state == new_state)
/**
* Only positive fds can be removed from epoll set.
* Cloned DCBs can have a state of DCB_STATE_POLLING but are not in
* the epoll set and do not have a valid file descriptor. Hence the
* only action for them is already done - the change of state to
* DCB_STATE_NOPOLLING.
*/
spinlock_release(&dcb->dcb_initlock);
if (dcb->fd > 0)
{
rc = 0;
goto return_rc;
rc = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, dcb->fd, &ev);
/**
* The poll_resolve_error function will always
* return 0 or crash. So if it returns non-zero result,
* things have gone wrong and we crash.
*/
if (rc) rc = poll_resolve_error(dcb, errno, false);
if (rc) raise(SIGABRT);
/*< Set bit for each maxscale thread */
bitmask_copy(&dcb->memdata.bitmask, poll_bitmask());
}
/*< Set bit for each maxscale thread */
bitmask_copy(&dcb->memdata.bitmask, poll_bitmask());
rc = 0;
return_rc:
return rc;
}
/**
* Check error returns from epoll_ctl. Most result in a crash since they
* are "impossible". Adding when already present is assumed non-fatal.
* Likewise, removing when not present is assumed non-fatal.
* It is assumed that callers to poll routines can handle the failure
* that results from hitting system limit, although an error is written
* here to record the problem.
*
* @param errornum The errno set by epoll_ctl
* @param adding True for adding to poll list, false for removing
* @return -1 on error or 0 for possibly revised return code
*/
static int
poll_resolve_error(DCB *dcb, int errornum, bool adding)
{
if (adding)
{
if (EEXIST == errornum)
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"%lu [poll_resolve_error] Error : epoll_ctl could not add, "
"already exists for DCB %p.",
pthread_self(),
dcb)));
// Assume another thread added and no serious harm done
return 0;
}
if (ENOSPC == errornum)
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"%lu [poll_resolve_error] The limit imposed by "
"/proc/sys/fs/epoll/max_user_watches was "
"encountered while trying to register (EPOLL_CTL_ADD) a new "
"file descriptor on an epoll instance for dcb %p.",
pthread_self(),
dcb)));
/* Failure - assume handled by callers */
return -1;
}
}
else
{
/* Must be removing */
if (ENOENT == errornum)
{
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
"%lu [poll_resolve_error] Error : epoll_ctl could not remove, "
"not found, for dcb %p.",
pthread_self(),
dcb)));
// Assume another thread removed and no serious harm done
return 0;
}
}
/* Common checks for add or remove - crash MaxScale */
if (EBADF == errornum) raise(SIGABRT);
if (EINVAL == errornum) raise(SIGABRT);
if (ENOMEM == errornum) raise(SIGABRT);
if (EPERM == errornum) raise(SIGABRT);
/* Undocumented error number */
raise(SIGABRT);
/* The following statement should never be reached, but avoids compiler warning */
return -1;
}
#define BLOCKINGPOLL 0 /*< Set BLOCKING POLL to 1 if using a single thread and to make
* debugging easier.
*/
@ -440,7 +521,6 @@ poll_waitevents(void *arg)
struct epoll_event events[MAX_EVENTS];
int i, nfds, timeout_bias = 1;
intptr_t thread_id = (intptr_t)arg;
DCB *zombies = NULL;
int poll_spins = 0;
/** Add this thread to the bitmask of running polling threads */
@ -611,7 +691,7 @@ int poll_spins = 0;
if (thread_data)
thread_data[thread_id].state = THREAD_ZPROCESSING;
zombies = dcb_process_zombies(thread_id);
dcb_process_zombies(thread_id);
if (thread_data)
thread_data[thread_id].state = THREAD_IDLE;
@ -796,16 +876,6 @@ unsigned long qtime;
eno = gw_getsockerrno(dcb->fd);
if (eno == 0) {
#if MUTEX_BLOCK
simple_mutex_lock(&dcb->dcb_write_lock, true);
ss_info_dassert(!dcb->dcb_write_active,
"Write already active");
dcb->dcb_write_active = TRUE;
atomic_add(&pollStats.n_write, 1);
dcb->func.write_ready(dcb);
dcb->dcb_write_active = FALSE;
simple_mutex_unlock(&dcb->dcb_write_lock);
#else
atomic_add(&pollStats.n_write, 1);
/** Read session id to thread's local storage */
LOGIF_MAYBE(LT, (dcb_get_ses_log_info(
@ -813,7 +883,6 @@ unsigned long qtime;
&tls_log_info.li_sesid,
&tls_log_info.li_enabled_logs)));
dcb->func.write_ready(dcb);
#endif
} else {
LOGIF(LD, (skygw_log_write(
LOGFILE_DEBUG,
@ -829,12 +898,6 @@ unsigned long qtime;
}
if (ev & EPOLLIN)
{
#if MUTEX_BLOCK
simple_mutex_lock(&dcb->dcb_read_lock, true);
ss_info_dassert(!dcb->dcb_read_active, "Read already active");
dcb->dcb_read_active = TRUE;
#endif
if (dcb->state == DCB_STATE_LISTENING)
{
LOGIF(LD, (skygw_log_write(
@ -868,11 +931,6 @@ unsigned long qtime;
&tls_log_info.li_enabled_logs)));
dcb->func.read(dcb);
}
#if MUTEX_BLOCK
dcb->dcb_read_active = FALSE;
simple_mutex_unlock(
&dcb->dcb_read_lock);
#endif
}
if (ev & EPOLLERR)
{
@ -1604,7 +1662,7 @@ RESULT_ROW *row;
}
/**
* 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
*/

View File

@ -22,6 +22,7 @@
#include <log_manager.h>
#include <ctype.h>
#include <mysql_client_server_protocol.h>
#include <gwdirs.h>
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
@ -52,31 +53,26 @@ int i;
}
/**
* secrets_readKeys
*
* This routine reads data from a binary file and extracts the AES encryption key
* and the AES Init Vector
*
* This routine reads data from a binary file named ".secrets" and extracts the AES encryption key
* and the AES Init Vector.
* If the path parameter is not null the custom path is interpreted as a folder
* containing the .secrets file. Otherwise the default location is used.
* @return The keys structure or NULL on error
*/
static MAXKEYS *
secrets_readKeys()
secrets_readKeys(char* path)
{
char secret_file[255];
char secret_file[PATH_MAX+1];
char *home;
MAXKEYS *keys;
struct stat secret_stats;
int fd;
int len;
static int reported = 0;
home = getenv("MAXSCALE_HOME");
if (home == NULL) {
home = "/usr/local/mariadb-maxscale";
}
snprintf(secret_file, 255, "%s/etc/.secrets", home);
if(path != NULL)
snprintf(secret_file, PATH_MAX, "%s/.secrets", path);
else
snprintf(secret_file, PATH_MAX, "%s/.secrets", get_datadir());
/* Try to access secrets file */
if (access(secret_file, R_OK) == -1)
{
@ -225,11 +221,20 @@ static int reported = 0;
* @param secret_file The file with secret keys
* @return 0 on success and 1 on failure
*/
int secrets_writeKeys(char *secret_file)
int secrets_writeKeys(char *path)
{
int fd,randfd;
unsigned int randval;
MAXKEYS key;
char secret_file[PATH_MAX + 10];
if(strlen(path) > PATH_MAX)
{
skygw_log_write(LOGFILE_ERROR,"Error: Pathname too long.");
return 1;
}
sprintf(secret_file,"%s/.secrets",path);
/* Open for writing | Create | Truncate the file for writing */
if ((fd = open(secret_file, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR)) < 0)
@ -332,7 +337,7 @@ char *ptr;
unsigned char encrypted[80];
int enlen;
keys = secrets_readKeys();
keys = secrets_readKeys(NULL);
if (!keys)
return strdup(crypt);
/*
@ -369,12 +374,12 @@ int enlen;
* Encrypt a password that can be stored in the MaxScale configuration file.
*
* Note the return is always a malloc'd string that the caller must free
*
* @param path Path the the .secrets file
* @param password The password to encrypt
* @return The encrypted password
*/
char *
encryptPassword(char *password)
encryptPassword(char* path, char *password)
{
MAXKEYS *keys;
AES_KEY aeskey;
@ -383,7 +388,7 @@ char *hex_output;
unsigned char padded_passwd[80];
unsigned char encrypted[80];
if ((keys = secrets_readKeys()) == NULL)
if ((keys = secrets_readKeys(path)) == NULL)
return NULL;
memset(padded_passwd, 0, 80);

View File

@ -33,6 +33,7 @@
* 30/08/14 Massimiliano Pinto Addition of new service status description
* 30/10/14 Massimiliano Pinto Addition of SERVER_MASTER_STICKINESS description
* 01/06/15 Massimiliano Pinto Addition of server_update_address/port
* 19/06/15 Martin Brampton Extra code for persistent connections
*
* @endverbatim
*/
@ -43,6 +44,7 @@
#include <server.h>
#include <spinlock.h>
#include <dcb.h>
#include <poll.h>
#include <skygw_utils.h>
#include <log_manager.h>
@ -54,6 +56,8 @@ extern __thread log_info_t tls_log_info;
static SPINLOCK server_spin = SPINLOCK_INIT;
static SERVER *allServers = NULL;
static void spin_reporter(void *, char *, int);
/**
* Allocate a new server withn the gateway
*
@ -71,6 +75,10 @@ SERVER *server;
if ((server = (SERVER *)calloc(1, sizeof(SERVER))) == NULL)
return NULL;
#if defined(SS_DEBUG)
server->server_chk_top = CHK_NUM_SERVER;
server->server_chk_tail = CHK_NUM_SERVER;
#endif
server->name = strdup(servname);
server->protocol = strdup(protocol);
server->port = port;
@ -79,6 +87,9 @@ SERVER *server;
server->rlag = -2;
server->master_id = -1;
server->depth = -1;
server->persistent = NULL;
server->persistmax = 0;
spinlock_init(&server->persistlock);
spinlock_acquire(&server_spin);
server->next = allServers;
@ -96,39 +107,104 @@ SERVER *server;
* @return Returns true if the server was freed
*/
int
server_free(SERVER *server)
server_free(SERVER *tofreeserver)
{
SERVER *ptr;
SERVER *server;
/* First of all remove from the linked list */
spinlock_acquire(&server_spin);
if (allServers == server)
if (allServers == tofreeserver)
{
allServers = server->next;
allServers = tofreeserver->next;
}
else
{
ptr = allServers;
while (ptr && ptr->next != server)
server = allServers;
while (server && server->next != tofreeserver)
{
ptr = ptr->next;
server = server->next;
}
if (ptr)
ptr->next = server->next;
if (server)
server->next = tofreeserver->next;
}
spinlock_release(&server_spin);
/* Clean up session and free the memory */
free(server->name);
free(server->protocol);
if (server->unique_name)
free(server->unique_name);
if (server->server_string)
free(server->server_string);
free(server);
free(tofreeserver->name);
free(tofreeserver->protocol);
if (tofreeserver->unique_name)
free(tofreeserver->unique_name);
if (tofreeserver->server_string)
free(tofreeserver->server_string);
if (tofreeserver->persistent)
dcb_persistent_clean_count(tofreeserver->persistent, true);
free(tofreeserver);
return 1;
}
/**
* Get a DCB from the persistent connection pool, if possible
*
* @param server The server to set the name on
* @param user The name of the user needing the connection
* @param protocol The name of the protocol needed for the connection
*/
DCB *
server_get_persistent(SERVER *server, char *user, const char *protocol)
{
DCB *dcb, *previous = NULL;
if (server->persistent && dcb_persistent_clean_count(server->persistent, false) && server->persistent)
{
spinlock_acquire(&server->persistlock);
dcb = server->persistent;
while (dcb) {
if (dcb->user
&& dcb->protoname
&& !dcb-> dcb_errhandle_called
&& !(dcb->flags & DCBF_HUNG)
&& 0 == strcmp(dcb->user, user)
&& 0 == strcmp(dcb->protoname, protocol))
{
if (NULL == previous)
{
server->persistent = dcb->nextpersistent;
}
else
{
previous->nextpersistent = dcb->nextpersistent;
}
free(dcb->user);
dcb->user = NULL;
spinlock_release(&server->persistlock);
atomic_add(&server->stats.n_persistent, -1);
atomic_add(&server->stats.n_current, 1);
return dcb;
}
else
{
LOGIF(LD, (skygw_log_write_flush(
LOGFILE_DEBUG,
"%lu [server_get_persistent] Rejected dcb "
"%p from pool, user %s looking for %s, protocol %s "
"looking for %s, hung flag %s, error handle called %s.",
pthread_self(),
dcb,
dcb->user ? dcb->user : "NULL",
user,
dcb->protoname ? dcb->protoname : "NULL",
protocol,
(dcb->flags & DCBF_HUNG) ? "true" : "false",
dcb-> dcb_errhandle_called ? "true" : "false")));
}
previous = dcb;
dcb = dcb->nextpersistent;
}
spinlock_release(&server->persistlock);
}
return NULL;
}
/**
* Set a unique name for the server
*
@ -204,6 +280,8 @@ printServer(SERVER *server)
printf("\tPort: %d\n", server->port);
printf("\tTotal connections: %d\n", server->stats.n_connections);
printf("\tCurrent connections: %d\n", server->stats.n_current);
printf("\tPersistent connections: %d\n", server->stats.n_persistent);
printf("\tPersistent actual max: %d\n", server->persistmax);
}
/**
@ -215,14 +293,14 @@ printServer(SERVER *server)
void
printAllServers()
{
SERVER *ptr;
SERVER *server;
spinlock_acquire(&server_spin);
ptr = allServers;
while (ptr)
server = allServers;
while (server)
{
printServer(ptr);
ptr = ptr->next;
printServer(server);
server = server->next;
}
spinlock_release(&server_spin);
}
@ -236,60 +314,73 @@ SERVER *ptr;
void
dprintAllServers(DCB *dcb)
{
SERVER *ptr;
SERVER *server;
char *stat;
spinlock_acquire(&server_spin);
ptr = allServers;
while (ptr)
server = allServers;
while (server)
{
dcb_printf(dcb, "Server %p (%s)\n", ptr, ptr->unique_name);
dcb_printf(dcb, "Server %p (%s)\n", server, server->unique_name);
dcb_printf(dcb, "\tServer: %s\n",
ptr->name);
stat = server_status(ptr);
server->name);
stat = server_status(server);
dcb_printf(dcb, "\tStatus: %s\n",
stat);
free(stat);
dcb_printf(dcb, "\tProtocol: %s\n",
ptr->protocol);
server->protocol);
dcb_printf(dcb, "\tPort: %d\n",
ptr->port);
if (ptr->server_string)
server->port);
if (server->server_string)
dcb_printf(dcb, "\tServer Version:\t\t\t%s\n",
ptr->server_string);
server->server_string);
dcb_printf(dcb, "\tNode Id: %d\n",
ptr->node_id);
server->node_id);
dcb_printf(dcb, "\tMaster Id: %d\n",
ptr->master_id);
if (ptr->slaves) {
server->master_id);
if (server->slaves) {
int i;
dcb_printf(dcb, "\tSlave Ids: ");
for (i = 0; ptr->slaves[i]; i++)
for (i = 0; server->slaves[i]; i++)
{
if (i == 0)
dcb_printf(dcb, "%li", ptr->slaves[i]);
dcb_printf(dcb, "%li", server->slaves[i]);
else
dcb_printf(dcb, ", %li ", ptr->slaves[i]);
dcb_printf(dcb, ", %li ", server->slaves[i]);
}
dcb_printf(dcb, "\n");
}
dcb_printf(dcb, "\tRepl Depth: %d\n",
ptr->depth);
if (SERVER_IS_SLAVE(ptr) || SERVER_IS_RELAY_SERVER(ptr)) {
if (ptr->rlag >= 0) {
dcb_printf(dcb, "\tSlave delay:\t\t%d\n", ptr->rlag);
server->depth);
if (SERVER_IS_SLAVE(server) || SERVER_IS_RELAY_SERVER(server)) {
if (server->rlag >= 0) {
dcb_printf(dcb, "\tSlave delay:\t\t%d\n", server->rlag);
}
}
if (ptr->node_ts > 0) {
dcb_printf(dcb, "\tLast Repl Heartbeat:\t%lu\n", ptr->node_ts);
if (server->node_ts > 0) {
dcb_printf(dcb, "\tLast Repl Heartbeat:\t%lu\n", server->node_ts);
}
dcb_printf(dcb, "\tNumber of connections: %d\n",
ptr->stats.n_connections);
server->stats.n_connections);
dcb_printf(dcb, "\tCurrent no. of conns: %d\n",
ptr->stats.n_current);
server->stats.n_current);
dcb_printf(dcb, "\tCurrent no. of operations: %d\n",
ptr->stats.n_current_ops);
ptr = ptr->next;
server->stats.n_current_ops);
if (server->persistpoolmax)
{
dcb_printf(dcb, "\tPersistent pool size: %d\n",
server->stats.n_persistent);
dcb_printf(dcb, "\tPersistent measured pool size: %d\n",
dcb_persistent_clean_count(server->persistent, false));
dcb_printf(dcb, "\tPersistent max size achieved: %d\n",
server->persistmax);
dcb_printf(dcb, "\tPersistent pool size limit: %d\n",
server->persistpoolmax);
dcb_printf(dcb, "\tPersistent max time (secs): %d\n",
server->persistmaxtime);
}
server = server->next;
}
spinlock_release(&server_spin);
}
@ -303,74 +394,74 @@ char *stat;
void
dprintAllServersJson(DCB *dcb)
{
SERVER *ptr;
SERVER *server;
char *stat;
int len = 0;
int el = 1;
spinlock_acquire(&server_spin);
ptr = allServers;
while (ptr)
server = allServers;
while (server)
{
ptr = ptr->next;
server = server->next;
len++;
}
ptr = allServers;
server = allServers;
dcb_printf(dcb, "[\n");
while (ptr)
while (server)
{
dcb_printf(dcb, " {\n \"server\": \"%s\",\n",
ptr->name);
stat = server_status(ptr);
server->name);
stat = server_status(server);
dcb_printf(dcb, " \"status\": \"%s\",\n",
stat);
free(stat);
dcb_printf(dcb, " \"protocol\": \"%s\",\n",
ptr->protocol);
server->protocol);
dcb_printf(dcb, " \"port\": \"%d\",\n",
ptr->port);
if (ptr->server_string)
server->port);
if (server->server_string)
dcb_printf(dcb, " \"version\": \"%s\",\n",
ptr->server_string);
server->server_string);
dcb_printf(dcb, " \"nodeId\": \"%d\",\n",
ptr->node_id);
server->node_id);
dcb_printf(dcb, " \"masterId\": \"%d\",\n",
ptr->master_id);
if (ptr->slaves) {
server->master_id);
if (server->slaves) {
int i;
dcb_printf(dcb, " \"slaveIds\": [ ");
for (i = 0; ptr->slaves[i]; i++)
for (i = 0; server->slaves[i]; i++)
{
if (i == 0)
dcb_printf(dcb, "%li", ptr->slaves[i]);
dcb_printf(dcb, "%li", server->slaves[i]);
else
dcb_printf(dcb, ", %li ", ptr->slaves[i]);
dcb_printf(dcb, ", %li ", server->slaves[i]);
}
dcb_printf(dcb, "],\n");
}
dcb_printf(dcb, " \"replDepth\": \"%d\",\n",
ptr->depth);
if (SERVER_IS_SLAVE(ptr) || SERVER_IS_RELAY_SERVER(ptr)) {
if (ptr->rlag >= 0) {
dcb_printf(dcb, " \"slaveDelay\": \"%d\",\n", ptr->rlag);
server->depth);
if (SERVER_IS_SLAVE(server) || SERVER_IS_RELAY_SERVER(server)) {
if (server->rlag >= 0) {
dcb_printf(dcb, " \"slaveDelay\": \"%d\",\n", server->rlag);
}
}
if (ptr->node_ts > 0) {
dcb_printf(dcb, " \"lastReplHeartbeat\": \"%lu\",\n", ptr->node_ts);
if (server->node_ts > 0) {
dcb_printf(dcb, " \"lastReplHeartbeat\": \"%lu\",\n", server->node_ts);
}
dcb_printf(dcb, " \"totalConnections\": \"%d\",\n",
ptr->stats.n_connections);
server->stats.n_connections);
dcb_printf(dcb, " \"currentConnections\": \"%d\",\n",
ptr->stats.n_current);
server->stats.n_current);
dcb_printf(dcb, " \"currentOps\": \"%d\"\n",
ptr->stats.n_current_ops);
server->stats.n_current_ops);
if (el < len) {
dcb_printf(dcb, " },\n");
}
else {
dcb_printf(dcb, " }\n");
}
ptr = ptr->next;
server = server->next;
el++;
}
dcb_printf(dcb, "]\n");
@ -440,6 +531,57 @@ SERVER_PARAM *param;
dcb_printf(dcb, "\tCurrent no. of conns: %d\n",
server->stats.n_current);
dcb_printf(dcb, "\tCurrent no. of operations: %d\n", server->stats.n_current_ops);
if (server->persistpoolmax)
{
dcb_printf(dcb, "\tPersistent pool size: %d\n",
server->stats.n_persistent);
dcb_printf(dcb, "\tPersistent measured pool size: %d\n",
dcb_persistent_clean_count(server->persistent, false));
dcb_printf(dcb, "\tPersistent actual size max: %d\n",
server->persistmax);
dcb_printf(dcb, "\tPersistent pool size limit: %d\n",
server->persistpoolmax);
dcb_printf(dcb, "\tPersistent max time (secs): %d\n",
server->persistmaxtime);
}
}
/**
* Display an entry from the spinlock statistics data
*
* @param dcb The DCB to print to
* @param desc Description of the statistic
* @param value The statistic value
*/
static void
spin_reporter(void *dcb, char *desc, int value)
{
dcb_printf((DCB *)dcb, "\t\t%-40s %d\n", desc, value);
}
/**
* Diagnostic to print all DCBs in persistent pool for a server
*
* @param pdcb DCB to print results to
* @param server SERVER for which DCBs are to be printed
*/
void
dprintPersistentDCBs(DCB *pdcb, SERVER *server)
{
DCB *dcb;
spinlock_acquire(&server->persistlock);
#if SPINLOCK_PROFILE
dcb_printf(pdcb, "DCB List Spinlock Statistics:\n");
spinlock_stats(&server->persistlock, spin_reporter, pdcb);
#endif
dcb = server->persistent;
while (dcb)
{
dprintOneDCB(pdcb, dcb);
dcb = dcb->nextpersistent;
}
spinlock_release(&server->persistlock);
}
/**
@ -449,12 +591,12 @@ SERVER_PARAM *param;
void
dListServers(DCB *dcb)
{
SERVER *ptr;
SERVER *server;
char *stat;
spinlock_acquire(&server_spin);
ptr = allServers;
if (ptr)
server = allServers;
if (server)
{
dcb_printf(dcb, "Servers.\n");
dcb_printf(dcb, "-------------------+-----------------+-------+-------------+--------------------\n");
@ -462,15 +604,15 @@ char *stat;
"Server", "Address", "Status");
dcb_printf(dcb, "-------------------+-----------------+-------+-------------+--------------------\n");
}
while (ptr)
while (server)
{
stat = server_status(ptr);
stat = server_status(server);
dcb_printf(dcb, "%-18s | %-15s | %5d | %11d | %s\n",
ptr->unique_name, ptr->name,
ptr->port,
ptr->stats.n_current, stat);
server->unique_name, server->name,
server->port,
server->stats.n_current, stat);
free(stat);
ptr = ptr->next;
server = server->next;
}
if (allServers)
dcb_printf(dcb, "-------------------+-----------------+-------+-------------+--------------------\n");
@ -489,7 +631,7 @@ server_status(SERVER *server)
{
char *status = NULL;
if ((status = (char *)malloc(256)) == NULL)
if (NULL == server || (status = (char *)malloc(256)) == NULL)
return NULL;
status[0] = 0;
if (server->status & SERVER_MAINT)
@ -641,7 +783,7 @@ SERVER_PARAM *param;
}
/**
* Retreive a parameter value from a server
* Retrieve a parameter value from a server
*
* @param server The server we are looking for a parameter of
* @param name The name of the parameter we require
@ -675,16 +817,16 @@ int *rowno = (int *)data;
int i = 0;;
char *stat, buf[20];
RESULT_ROW *row;
SERVER *ptr;
SERVER *server;
spinlock_acquire(&server_spin);
ptr = allServers;
while (i < *rowno && ptr)
server = allServers;
while (i < *rowno && server)
{
i++;
ptr = ptr->next;
server = server->next;
}
if (ptr == NULL)
if (server == NULL)
{
spinlock_release(&server_spin);
free(data);
@ -692,13 +834,13 @@ SERVER *ptr;
}
(*rowno)++;
row = resultset_make_row(set);
resultset_row_set(row, 0, ptr->unique_name);
resultset_row_set(row, 1, ptr->name);
sprintf(buf, "%d", ptr->port);
resultset_row_set(row, 0, server->unique_name);
resultset_row_set(row, 1, server->name);
sprintf(buf, "%d", server->port);
resultset_row_set(row, 2, buf);
sprintf(buf, "%d", ptr->stats.n_current);
sprintf(buf, "%d", server->stats.n_current);
resultset_row_set(row, 3, buf);
stat = server_status(ptr);
stat = server_status(server);
resultset_row_set(row, 4, stat);
free(stat);
spinlock_release(&server_spin);

View File

@ -36,7 +36,8 @@
* 06/02/15 Mark Riddoch Added caching of authentication data
* 18/02/15 Mark Riddoch Added result set management
* 03/03/15 Massimiliano Pinto Added config_enable_feedback_task() call in serviceStartAll
*
* 19/06/15 Martin Brampton More meaningful names for temp variables
* @endverbatim
*/
#include <stdio.h>
@ -61,12 +62,17 @@
#include <sys/types.h>
#include <housekeeper.h>
#include <resultset.h>
#include <gw.h>
#include <gwdirs.h>
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
extern size_t log_ses_count[];
extern __thread log_info_t tls_log_info;
static RSA *rsa_512 = NULL;
static RSA *rsa_1024 = NULL;
/** To be used with configuration type checks */
typedef struct typelib_st {
int tl_nelems;
@ -112,7 +118,7 @@ SERVICE *service;
return NULL;
if ((service->router = load_module(router, MODULE_ROUTER)) == NULL)
{
char* home = get_maxscale_home();
char* home = get_libdir();
char* ldpath = getenv("LD_LIBRARY_PATH");
LOGIF(LE, (skygw_log_write_flush(
@ -120,12 +126,13 @@ SERVICE *service;
"Error : Unable to load %s module \"%s\".\n\t\t\t"
" Ensure that lib%s.so exists in one of the "
"following directories :\n\t\t\t "
"- %s/modules\n\t\t\t - %s",
"- %s\n%s%s",
MODULE_ROUTER,
router,
router,
home,
ldpath)));
ldpath?"\t\t\t - ":"",
ldpath?ldpath:"")));
free(service);
return NULL;
}
@ -133,7 +140,14 @@ SERVICE *service;
service->routerModule = strdup(router);
service->users_from_all = false;
service->resources = NULL;
service->ssl_mode = SSL_DISABLED;
service->ssl_init_done = false;
service->ssl_ca_cert = NULL;
service->ssl_cert = NULL;
service->ssl_key = NULL;
service->ssl_cert_verify_depth = DEFAULT_SSL_CERT_VERIFY_DEPTH;
/** Support the highest possible SSL/TLS methods available as the default */
service->ssl_method_type = SERVICE_SSL_TLS_MAX;
if (service->name == NULL || service->routerModule == NULL)
{
if (service->name)
@ -163,19 +177,19 @@ SERVICE *service;
int
service_isvalid(SERVICE *service)
{
SERVICE *ptr;
SERVICE *checkservice;
int rval = 0;
spinlock_acquire(&service_spin);
ptr = allServices;
while (ptr)
checkservice = allServices;
while (checkservice)
{
if (ptr == service)
if (checkservice == service)
{
rval = 1;
break;
}
ptr = ptr->next;
checkservice = checkservice->next;
}
spinlock_release(&service_spin);
return rval;
@ -229,11 +243,7 @@ GWPROTOCOL *funcs;
{
/* Try loading authentication data from file cache */
char *ptr, path[4097];
strcpy(path, "/usr/local/mariadb-maxscale");
if ((ptr = getenv("MAXSCALE_HOME")) != NULL)
{
strncpy(path, ptr, 4096);
}
strcpy(path, get_cachedir());
strncat(path, "/", 4096);
strncat(path, service->name, 4096);
strncat(path, "/.cache/dbusers", 4096);
@ -249,7 +259,7 @@ GWPROTOCOL *funcs;
{
hashtable_free(service->users->data);
free(service->users);
dcb_free(port->listener);
dcb_close(port->listener);
port->listener = NULL;
goto retblock;
}
@ -257,15 +267,11 @@ GWPROTOCOL *funcs;
else
{
/* Save authentication data to file cache */
char *ptr, path[4097];
char *ptr, path[PATH_MAX + 1];
int mkdir_rval = 0;
strcpy(path, "/usr/local/mariadb-maxscale");
if ((ptr = getenv("MAXSCALE_HOME")) != NULL)
{
strncpy(path, ptr, 4096);
}
strncpy(path, get_cachedir(),PATH_MAX);
strncat(path, "/", 4096);
strncat(path, service->name, 4096);
strncat(path, service->name, PATH_MAX);
if (access(path, R_OK) == -1)
{
mkdir_rval = mkdir(path, 0777);
@ -273,14 +279,17 @@ GWPROTOCOL *funcs;
if(mkdir_rval)
{
skygw_log_write(LOGFILE_ERROR,"Error : Failed to create directory '%s': [%d] %s",
path,
errno,
strerror(errno));
if(errno != EEXIST)
{
skygw_log_write(LOGFILE_ERROR,"Error : Failed to create directory '%s': [%d] %s",
path,
errno,
strerror(errno));
}
mkdir_rval = 0;
}
strncat(path, "/.cache", 4096);
strncat(path, "/.cache", PATH_MAX);
if (access(path, R_OK) == -1)
{
mkdir_rval = mkdir(path, 0777);
@ -288,13 +297,16 @@ GWPROTOCOL *funcs;
if(mkdir_rval)
{
skygw_log_write(LOGFILE_ERROR,"Error : Failed to create directory '%s': [%d] %s",
path,
errno,
strerror(errno));
if(errno != EEXIST)
{
skygw_log_write(LOGFILE_ERROR,"Error : Failed to create directory '%s': [%d] %s",
path,
errno,
strerror(errno));
}
mkdir_rval = 0;
}
strncat(path, "/dbusers", 4096);
strncat(path, "/dbusers", PATH_MAX);
dbusers_save(service->users, path);
}
if (loaded == 0)
@ -318,7 +330,7 @@ GWPROTOCOL *funcs;
"Loaded %d MySQL Users for service [%s].",
loaded, service->name)));
}
}
}
else
{
if (service->users == NULL) {
@ -330,12 +342,8 @@ GWPROTOCOL *funcs;
if ((funcs=(GWPROTOCOL *)load_module(port->protocol, MODULE_PROTOCOL))
== NULL)
{
if (service->users->data)
{
hashtable_free(service->users->data);
}
free(service->users);
dcb_free(port->listener);
users_free(service->users);
dcb_close(port->listener);
port->listener = NULL;
LOGIF(LE, (skygw_log_write_flush(
LOGFILE_ERROR,
@ -369,11 +377,7 @@ GWPROTOCOL *funcs;
"Error : Failed to create session to service %s.",
service->name)));
if (service->users->data)
{
hashtable_free(service->users->data);
}
free(service->users);
users_free(service->users);
dcb_close(port->listener);
port->listener = NULL;
goto retblock;
@ -387,11 +391,7 @@ GWPROTOCOL *funcs;
port->port,
port->protocol,
service->name)));
if (service->users->data)
{
hashtable_free(service->users->data);
}
free(service->users);
users_free(service->users);
dcb_close(port->listener);
port->listener = NULL;
}
@ -417,6 +417,17 @@ serviceStart(SERVICE *service)
SERV_PROTOCOL *port;
int listeners = 0;
if(service->ssl_mode != SSL_DISABLED)
{
if(serviceInitSSL(service) != 0)
{
LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR,
"%s: SSL initialization failed. Service not started.",
service->name)));
service->state = SERVICE_STATE_FAILED;
return 0;
}
}
if ((service->router_instance = service->router->createInstance(service,
service->routerOptions)) == NULL)
{
@ -518,11 +529,16 @@ int listeners = 0;
port = service->ports;
while (port)
{
poll_remove_dcb(port->listener);
port->listener->session->state = SESSION_STATE_LISTENER_STOPPED;
listeners++;
port = port->next;
if(port->listener &&
port->listener->session->state == SESSION_STATE_LISTENER)
{
if(poll_remove_dcb(port->listener) == 0)
{
port->listener->session->state = SESSION_STATE_LISTENER_STOPPED;
listeners++;
}
}
port = port->next;
}
service->state = SERVICE_STATE_STOPPED;
@ -546,13 +562,18 @@ int listeners = 0;
port = service->ports;
while (port)
{
if (poll_add_dcb(port->listener) == 0) {
port->listener->session->state = SESSION_STATE_LISTENER;
listeners++;
}
port = port->next;
if(port->listener &&
port->listener->session->state == SESSION_STATE_LISTENER_STOPPED)
{
if(poll_add_dcb(port->listener) == 0)
{
port->listener->session->state = SESSION_STATE_LISTENER;
listeners++;
}
}
port = port->next;
}
service->state = SERVICE_STATE_STARTED;
return listeners;
}
@ -860,6 +881,99 @@ serviceOptimizeWildcard(SERVICE *service, int action)
return 1;
}
/**
* Set the locations of the server's SSL certificate, server's private key and the CA
* certificate which both the client and the server should trust.
* @param service Service to configure
* @param cert SSL certificate
* @param key SSL private key
* @param ca_cert SSL CA certificate
*/
void
serviceSetCertificates(SERVICE *service, char* cert,char* key, char* ca_cert)
{
if(service->ssl_cert)
free(service->ssl_cert);
service->ssl_cert = strdup(cert);
if(service->ssl_key)
free(service->ssl_key);
service->ssl_key = strdup(key);
if(service->ssl_ca_cert)
free(service->ssl_ca_cert);
service->ssl_ca_cert = strdup(ca_cert);
}
/**
* Set the maximum SSL/TLS version the service will support
* @param service Service to configure
* @param version SSL/TLS version string
* @return 0 on success, -1 on invalid version string
*/
int
serviceSetSSLVersion(SERVICE *service, char* version)
{
if(strcasecmp(version,"SSLV3") == 0)
service->ssl_method_type = SERVICE_SSLV3;
else if(strcasecmp(version,"TLSV10") == 0)
service->ssl_method_type = SERVICE_TLS10;
#ifdef OPENSSL_1_0
else if(strcasecmp(version,"TLSV11") == 0)
service->ssl_method_type = SERVICE_TLS11;
else if(strcasecmp(version,"TLSV12") == 0)
service->ssl_method_type = SERVICE_TLS12;
#endif
else if(strcasecmp(version,"MAX") == 0)
service->ssl_method_type = SERVICE_SSL_TLS_MAX;
else return -1;
return 0;
}
/**
* Set the service's SSL certificate verification depth. Depth of 0 means the peer
* certificate, 1 is the CA and 2 is a higher CA and so on.
* @param service Service to configure
* @param depth Certificate verification depth
* @return 0 on success, -1 on incorrect depth value
*/
int serviceSetSSLVerifyDepth(SERVICE* service, int depth)
{
if(depth < 0)
return -1;
service->ssl_cert_verify_depth = depth;
return 0;
}
/**
* Enable or disable the service SSL capability of a service.
* The SSL mode string passed as a parameter should be one of required, enabled
* or disabled. Required requires all connections to use SSL encryption, enabled
* allows both SSL and non-SSL connections and disabled does not use SSL encryption.
* If the service SSL mode is set to enabled, then the client will decide whether
* SSL encryption is used.
* @param service Service to configure
* @param action Mode string. One of required, enabled or disabled.
* @return 0 on success, -1 on error
*/
int
serviceSetSSL(SERVICE *service, char* action)
{
int rval = 0;
if(strcasecmp(action,"required") == 0)
service->ssl_mode = SSL_REQUIRED;
else if(strcasecmp(action,"enabled") == 0)
service->ssl_mode = SSL_ENABLED;
else if(strcasecmp(action,"disabled") == 0)
service->ssl_mode = SSL_DISABLED;
else
rval = -1;
return rval;
}
/**
* Whether to strip escape characters from the name of the database the client
* is connecting to.
@ -1023,6 +1137,8 @@ int i;
printf("\tUsers data: %p\n", (void *)service->users);
printf("\tTotal connections: %d\n", service->stats.n_sessions);
printf("\tCurrently connected: %d\n", service->stats.n_current);
printf("\tSSL: %s\n", service->ssl_mode == SSL_DISABLED ? "Disabled":
(service->ssl_mode == SSL_ENABLED ? "Enabled":"Required"));
}
/**
@ -1132,6 +1248,8 @@ int i;
service->stats.n_sessions);
dcb_printf(dcb, "\tCurrently connected: %d\n",
service->stats.n_current);
dcb_printf(dcb,"\tSSL: %s\n", service->ssl_mode == SSL_DISABLED ? "Disabled":
(service->ssl_mode == SSL_ENABLED ? "Enabled":"Required"));
}
/**
@ -1142,11 +1260,11 @@ int i;
void
dListServices(DCB *dcb)
{
SERVICE *ptr;
SERVICE *service;
spinlock_acquire(&service_spin);
ptr = allServices;
if (ptr)
service = allServices;
if (service)
{
dcb_printf(dcb, "Services.\n");
dcb_printf(dcb, "--------------------------+----------------------+--------+---------------\n");
@ -1154,13 +1272,13 @@ SERVICE *ptr;
"Service Name", "Router Module");
dcb_printf(dcb, "--------------------------+----------------------+--------+---------------\n");
}
while (ptr)
while (service)
{
ss_dassert(ptr->stats.n_current >= 0);
ss_dassert(service->stats.n_current >= 0);
dcb_printf(dcb, "%-25s | %-20s | %6d | %5d\n",
ptr->name, ptr->routerModule,
ptr->stats.n_current, ptr->stats.n_sessions);
ptr = ptr->next;
service->name, service->routerModule,
service->stats.n_current, service->stats.n_sessions);
service = service->next;
}
if (allServices)
dcb_printf(dcb, "--------------------------+----------------------+--------+---------------\n\n");
@ -1175,12 +1293,12 @@ SERVICE *ptr;
void
dListListeners(DCB *dcb)
{
SERVICE *ptr;
SERVICE *service;
SERV_PROTOCOL *lptr;
spinlock_acquire(&service_spin);
ptr = allServices;
if (ptr)
service = allServices;
if (service)
{
dcb_printf(dcb, "Listeners.\n");
dcb_printf(dcb, "---------------------+--------------------+-----------------+-------+--------\n");
@ -1188,13 +1306,13 @@ SERV_PROTOCOL *lptr;
"Service Name", "Protocol Module", "Address");
dcb_printf(dcb, "---------------------+--------------------+-----------------+-------+--------\n");
}
while (ptr)
while (service)
{
lptr = ptr->ports;
lptr = service->ports;
while (lptr)
{
dcb_printf(dcb, "%-20s | %-18s | %-15s | %5d | %s\n",
ptr->name, lptr->protocol,
service->name, lptr->protocol,
(lptr && lptr->address) ? lptr->address : "*",
lptr->port,
(!lptr->listener ||
@ -1205,7 +1323,7 @@ SERV_PROTOCOL *lptr;
lptr = lptr->next;
}
ptr = ptr->next;
service = service->next;
}
if (allServices)
dcb_printf(dcb, "---------------------+--------------------+-----------------+-------+--------\n\n");
@ -1260,7 +1378,14 @@ void *router_obj;
}
}
/**
* Refresh the database users for the service
* This function replaces the MySQL users used by the service with the latest
* version found on the backend servers. There is a limit on how often the users
* can be reloaded and if this limit is exceeded, the reload will fail.
* @param service Service to reload
* @return 0 on success and 1 on error
*/
int service_refresh_users(SERVICE *service) {
int ret = 1;
/* check for another running getUsers request */
@ -1613,15 +1738,15 @@ void service_shutdown()
int
serviceSessionCountAll()
{
SERVICE *ptr;
SERVICE *service;
int rval = 0;
spinlock_acquire(&service_spin);
ptr = allServices;
while (ptr)
service = allServices;
while (service)
{
rval += ptr->stats.n_current;
ptr = ptr->next;
rval += service->stats.n_current;
service = service->next;
}
spinlock_release(&service_spin);
return rval;
@ -1642,16 +1767,16 @@ int *rowno = (int *)data;
int i = 0;;
char buf[20];
RESULT_ROW *row;
SERVICE *ptr;
SERVICE *service;
SERV_PROTOCOL *lptr = NULL;
spinlock_acquire(&service_spin);
ptr = allServices;
if (ptr)
lptr = ptr->ports;
while (i < *rowno && ptr)
service = allServices;
if (service)
lptr = service->ports;
while (i < *rowno && service)
{
lptr = ptr->ports;
lptr = service->ports;
while (i < *rowno && lptr)
{
if ((lptr = lptr->next) != NULL)
@ -1659,8 +1784,8 @@ SERV_PROTOCOL *lptr = NULL;
}
if (i < *rowno)
{
ptr = ptr->next;
if (ptr && (lptr = ptr->ports) != NULL)
service = service->next;
if (service && (lptr = service->ports) != NULL)
i++;
}
}
@ -1672,7 +1797,7 @@ SERV_PROTOCOL *lptr = NULL;
}
(*rowno)++;
row = resultset_make_row(set);
resultset_row_set(row, 0, ptr->name);
resultset_row_set(row, 0, service->name);
resultset_row_set(row, 1, lptr->protocol);
resultset_row_set(row, 2, (lptr && lptr->address) ? lptr->address : "*");
sprintf(buf, "%d", lptr->port);
@ -1727,16 +1852,16 @@ int *rowno = (int *)data;
int i = 0;;
char buf[20];
RESULT_ROW *row;
SERVICE *ptr;
SERVICE *service;
spinlock_acquire(&service_spin);
ptr = allServices;
while (i < *rowno && ptr)
service = allServices;
while (i < *rowno && service)
{
i++;
ptr = ptr->next;
service = service->next;
}
if (ptr == NULL)
if (service == NULL)
{
spinlock_release(&service_spin);
free(data);
@ -1744,11 +1869,11 @@ SERVICE *ptr;
}
(*rowno)++;
row = resultset_make_row(set);
resultset_row_set(row, 0, ptr->name);
resultset_row_set(row, 1, ptr->routerModule);
sprintf(buf, "%d", ptr->stats.n_current);
resultset_row_set(row, 0, service->name);
resultset_row_set(row, 1, service->routerModule);
sprintf(buf, "%d", service->stats.n_current);
resultset_row_set(row, 2, buf);
sprintf(buf, "%d", ptr->stats.n_sessions);
sprintf(buf, "%d", service->stats.n_sessions);
resultset_row_set(row, 3, buf);
spinlock_release(&service_spin);
return row;
@ -1780,3 +1905,140 @@ int *data;
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 servce'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
* @return
*/
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;
}
service->ctx = SSL_CTX_new(service->method);
/** 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)
skygw_log_write(LE,"Error: 512-bit RSA key generation failed.");
}
if(rsa_1024 == NULL)
{
rsa_1024 = RSA_generate_key(1024,RSA_F4,NULL,NULL);
if (rsa_1024 == NULL)
skygw_log_write(LE,"Error: 1024-bit RSA key generation failed.");
}
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) {
skygw_log_write(LE,"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) {
skygw_log_write(LE,"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)) {
skygw_log_write(LE,"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)) {
skygw_log_write(LE,"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;
}

View File

@ -962,7 +962,7 @@ void session_close_timeouts(void* data)
ses->service->conn_timeout > 0 &&
hkheartbeat - ses->client->last_read > ses->service->conn_timeout * 10)
{
ses->client->func.hangup(ses->client);
dcb_close(ses->client);
}
spinlock_acquire(&session_spin);

View File

@ -44,19 +44,4 @@ add_test(Internal-TestUsers test_users)
add_test(Internal-TestAdminUsers test_adminusers)
add_test(Internal-TestMemlog testmemlog)
add_test(TestFeedback testfeedback)
set_tests_properties(Internal-TestMySQLUsers
Internal-TestHash
Internal-TestHint
Internal-TestSpinlock
Internal-TestFilter
Internal-TestBuffer
Internal-TestDCB
Internal-TestModutil
Internal-TestPoll
Internal-TestService
Internal-TestServer
Internal-TestUsers
Internal-TestAdminUsers
Internal-TestMemlog
TestFeedback PROPERTIES ENVIRONMENT MAXSCALE_HOME=${CMAKE_BINARY_DIR}/)
set_tests_properties(TestFeedback PROPERTIES TIMEOUT 30)

View File

@ -30,7 +30,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gwdirs.h>
#include <adminusers.h>
@ -40,7 +40,7 @@
* Test that the username password admin/mariadb is accepted if no users
* have been created and that no other users are accepted
*
* WARNING: $MAXSCALE_HOME/etc/passwd must be removed before this test is run
* WARNING: The passwd file must be removed before this test is run
*/
static int
test1()
@ -269,9 +269,8 @@ int result = 0;
char *home, buf[1024];
/* Unlink any existing password file before running this test */
if ((home = getenv("MAXSCALE_HOME")) == NULL || strlen(home) >= 1024)
home = "/usr/local/mariadb-maxscale";
sprintf(buf, "%s/etc/passwd", home);
sprintf(buf, "%s/passwd", default_cachedir);
if(!is_valid_posix_path(buf))
exit(1);
if (strcmp(buf, "/etc/passwd") != 0)

View File

@ -64,7 +64,7 @@ int buflen;
ss_info_dassert(!dcb_isvalid(dcb), "Freed DCB must not be valid");
ss_dfprintf(stderr, "\t..done\nMake clone DCB a zombie");
clone->state = DCB_STATE_NOPOLLING;
dcb_add_to_zombieslist(clone);
dcb_close(clone);
ss_info_dassert(dcb_get_zombies() == clone, "Clone DCB must be start of zombie list now");
ss_dfprintf(stderr, "\t..done\nProcess the zombies list");
dcb_process_zombies(0);

View File

@ -73,17 +73,8 @@ int main(int argc, char** argv)
char* cnf;
hkinit();
home = getenv("MAXSCALE_HOME");
if(home == NULL)
{
FAILTEST("MAXSCALE_HOME was not defined.");
}
printf("Home: %s\n",home);
cnf = malloc(strlen(home) + strlen("/etc/MaxScale.cnf") + 1);
strcpy(cnf,home);
strcat(cnf,"/etc/MaxScale.cnf");
cnf = strdup("/etc/MaxScale.cnf");
printf("Config: %s\n",cnf);
@ -116,4 +107,4 @@ int main(int argc, char** argv)
}
mysql_library_end();
return 0;
}
}

View File

@ -20,6 +20,7 @@
#include <string.h>
#include <users.h>
#include <atomic.h>
#include <log_manager.h>
/**
* @file users.c User table maintenance routines
@ -59,12 +60,16 @@ users_alloc()
USERS *rval;
if ((rval = calloc(1, sizeof(USERS))) == NULL)
return NULL;
{
skygw_log_write(LE,"[%s:%d] Error: Memory allocation failed.",__FUNCTION__,__LINE__);
return NULL;
}
if ((rval->data = hashtable_alloc(USERS_HASHTABLE_DEFAULT_SIZE, user_hash, strcmp)) == NULL)
{
free(rval);
return NULL;
skygw_log_write(LE,"[%s:%d] Error: Memory allocation failed.",__FUNCTION__,__LINE__);
free(rval);
return NULL;
}
hashtable_memory_fns(rval->data, (HASHMEMORYFN)strdup, (HASHMEMORYFN)strdup, (HASHMEMORYFN)free, (HASHMEMORYFN)free);
@ -80,8 +85,15 @@ USERS *rval;
void
users_free(USERS *users)
{
if(users == NULL)
{
skygw_log_write(LE,"[%s:%d] Error: NULL parameter.",__FUNCTION__,__LINE__);
return;
}
if(users->data)
hashtable_free(users->data);
free(users);
free(users);
}
/**