1931 lines
		
	
	
		
			60 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1931 lines
		
	
	
		
			60 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * 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 config.c  - Read the gateway.cnf configuration file
 | 
						|
 *
 | 
						|
 * @verbatim
 | 
						|
 * Revision History
 | 
						|
 *
 | 
						|
 * Date		Who			Description
 | 
						|
 * 21/06/13	Mark Riddoch		Initial implementation
 | 
						|
 * 08/07/13	Mark Riddoch		Addition on monitor module support
 | 
						|
 * 23/07/13	Mark Riddoch		Addition on default monitor password
 | 
						|
 * 06/02/14	Massimiliano Pinto	Added support for enable/disable root user in services
 | 
						|
 * 14/02/14	Massimiliano Pinto	Added enable_root_user in the service_params list
 | 
						|
 * 11/03/14	Massimiliano Pinto	Added Unix socket support
 | 
						|
 * 11/05/14	Massimiliano Pinto	Added version_string support to service
 | 
						|
 * 19/05/14	Mark Riddoch		Added unique names from section headers
 | 
						|
 * 29/05/14	Mark Riddoch		Addition of filter definition
 | 
						|
 * 23/05/14	Massimiliano Pinto	Added automatic set of maxscale-id: first listening ipv4_raw + port + pid
 | 
						|
 * 28/05/14	Massimiliano Pinto	Added detect_replication_lag parameter
 | 
						|
 * 28/08/14	Massimiliano Pinto	Added detect_stale_master parameter
 | 
						|
 * 09/09/14	Massimiliano Pinto	Added localhost_match_wildcard_host parameter
 | 
						|
 * 12/09/14	Mark Riddoch		Addition of checks on servers list and
 | 
						|
 *					internal router suppression of messages
 | 
						|
 * 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
 | 
						|
 *
 | 
						|
 * @endverbatim
 | 
						|
 */
 | 
						|
#include <my_config.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <string.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <ctype.h>
 | 
						|
#include <ini.h>
 | 
						|
#include <config.h>
 | 
						|
#include <service.h>
 | 
						|
#include <server.h>
 | 
						|
#include <users.h>
 | 
						|
#include <monitor.h>
 | 
						|
#include <skygw_utils.h>
 | 
						|
#include <log_manager.h>
 | 
						|
#include <mysql.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;
 | 
						|
 | 
						|
extern int setipaddress(struct in_addr *, char *);
 | 
						|
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	int	handle_global_item(const char *, const char *);
 | 
						|
static	void	global_defaults();
 | 
						|
static	void	check_config_objects(CONFIG_CONTEXT *context);
 | 
						|
static int	internalService(char *router);
 | 
						|
 | 
						|
static	char		*config_file = NULL;
 | 
						|
static	GATEWAY_CONF	gateway;
 | 
						|
char			*version_string = NULL;
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * Trim whitespace from the front and rear of a string
 | 
						|
 *
 | 
						|
 * @param str		String to trim
 | 
						|
 * @return	Trimmed string, changes are done in situ
 | 
						|
 */
 | 
						|
static char *
 | 
						|
trim(char *str)
 | 
						|
{
 | 
						|
char	*ptr;
 | 
						|
 | 
						|
	while (isspace(*str))
 | 
						|
		str++;
 | 
						|
 | 
						|
	/* Point to last character of the string */
 | 
						|
	ptr = str + strlen(str) - 1;
 | 
						|
	while (ptr > str && isspace(*ptr))
 | 
						|
		*ptr-- = 0;
 | 
						|
 | 
						|
	return str;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Config item handler for the ini file reader
 | 
						|
 *
 | 
						|
 * @param userdata	The config context element
 | 
						|
 * @param section	The config file section
 | 
						|
 * @param name		The Parameter name
 | 
						|
 * @param value		The Parameter value
 | 
						|
 * @return zero on error
 | 
						|
 */
 | 
						|
static int
 | 
						|
handler(void *userdata, const char *section, const char *name, const char *value)
 | 
						|
{
 | 
						|
CONFIG_CONTEXT		*cntxt = (CONFIG_CONTEXT *)userdata;
 | 
						|
CONFIG_CONTEXT		*ptr = cntxt;
 | 
						|
CONFIG_PARAMETER	*param, *p1;
 | 
						|
 | 
						|
	if (strcmp(section, "gateway") == 0 || strcasecmp(section, "MaxScale") == 0)
 | 
						|
	{
 | 
						|
		return handle_global_item(name, value);
 | 
						|
	}
 | 
						|
	/*
 | 
						|
	 * If we already have some parameters for the object
 | 
						|
	 * add the parameters to that object. If not create
 | 
						|
	 * a new object.
 | 
						|
	 */
 | 
						|
	while (ptr && strcmp(ptr->object, section) != 0)
 | 
						|
		ptr = ptr->next;
 | 
						|
	if (!ptr)
 | 
						|
	{
 | 
						|
		if ((ptr = (CONFIG_CONTEXT *)malloc(sizeof(CONFIG_CONTEXT))) == NULL)
 | 
						|
			return 0;
 | 
						|
		ptr->object = strdup(section);
 | 
						|
		ptr->parameters = NULL;
 | 
						|
		ptr->next = cntxt->next;
 | 
						|
		ptr->element = NULL;
 | 
						|
		cntxt->next = ptr;
 | 
						|
	}
 | 
						|
	/* Check to see if the parameter already exists for the section */
 | 
						|
	p1 = ptr->parameters;
 | 
						|
	while (p1)
 | 
						|
	{
 | 
						|
		if (!strcmp(p1->name, name))
 | 
						|
		{
 | 
						|
			LOGIF(LE, (skygw_log_write_flush(
 | 
						|
                                LOGFILE_ERROR,
 | 
						|
                                "Error : Configuration object '%s' has multiple "
 | 
						|
				"parameters names '%s'.",
 | 
						|
                                ptr->object, name)));
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
		p1 = p1->next;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
	if ((param = (CONFIG_PARAMETER *)malloc(sizeof(CONFIG_PARAMETER))) == NULL)
 | 
						|
		return 0;
 | 
						|
	param->name = strdup(name);
 | 
						|
	param->value = strdup(value);
 | 
						|
	param->next = ptr->parameters;
 | 
						|
	ptr->parameters = param;
 | 
						|
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Load the configuration file for the MaxScale
 | 
						|
 *
 | 
						|
 * @param file	The filename of the configuration file
 | 
						|
 * @return A zero return indicates a fatal error reading the configuration
 | 
						|
 */
 | 
						|
int
 | 
						|
config_load(char *file)
 | 
						|
{
 | 
						|
CONFIG_CONTEXT	config;
 | 
						|
int		rval;
 | 
						|
 | 
						|
	MYSQL *conn;
 | 
						|
	conn = mysql_init(NULL);
 | 
						|
	if (conn) {
 | 
						|
		if (mysql_real_connect(conn, NULL, NULL, NULL, NULL, 0, NULL, 0)) {
 | 
						|
			char *ptr;
 | 
						|
			version_string = (char *)mysql_get_server_info(conn);
 | 
						|
			ptr = strstr(version_string, "-embedded");
 | 
						|
			if (ptr) {
 | 
						|
				*ptr = '\0';
 | 
						|
			}
 | 
						|
		}
 | 
						|
		mysql_close(conn);
 | 
						|
	}
 | 
						|
 | 
						|
	global_defaults();
 | 
						|
 | 
						|
	config.object = "";
 | 
						|
	config.next = NULL;
 | 
						|
 | 
						|
	if (ini_parse(file, handler, &config) < 0)
 | 
						|
		return 0;
 | 
						|
 | 
						|
	config_file = file;
 | 
						|
 | 
						|
	check_config_objects(config.next);
 | 
						|
	rval = process_config_context(config.next);
 | 
						|
	free_config_context(config.next);
 | 
						|
 | 
						|
	return rval;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Reload the configuration file for the MaxScale
 | 
						|
 *
 | 
						|
 * @return A zero return indicates a fatal error reading the configuration
 | 
						|
 */
 | 
						|
int
 | 
						|
config_reload()
 | 
						|
{
 | 
						|
CONFIG_CONTEXT	config;
 | 
						|
int		rval;
 | 
						|
 | 
						|
	if (!config_file)
 | 
						|
		return 0;
 | 
						|
 | 
						|
	if (gateway.version_string)
 | 
						|
		free(gateway.version_string);
 | 
						|
 | 
						|
	global_defaults();
 | 
						|
 | 
						|
	config.object = "";
 | 
						|
	config.next = NULL;
 | 
						|
 | 
						|
	if (ini_parse(config_file, handler, &config) < 0)
 | 
						|
		return 0;
 | 
						|
 | 
						|
	rval = process_config_update(config.next);
 | 
						|
	free_config_context(config.next);
 | 
						|
 | 
						|
	return rval;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Process a configuration context and turn it into the set of object
 | 
						|
 * we need.
 | 
						|
 *
 | 
						|
 * @param context	The configuration data
 | 
						|
 * @return A zero result indicates a fatal error
 | 
						|
 */
 | 
						|
static	int
 | 
						|
process_config_context(CONFIG_CONTEXT *context)
 | 
						|
{
 | 
						|
CONFIG_CONTEXT		*obj;
 | 
						|
int			error_count = 0;
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Process the data and create the services and servers defined
 | 
						|
	 * in the data.
 | 
						|
	 */
 | 
						|
	obj = context;
 | 
						|
	while (obj)
 | 
						|
	{
 | 
						|
		char *type = config_get_value(obj->parameters, "type");
 | 
						|
		if (type == NULL)
 | 
						|
		{
 | 
						|
			LOGIF(LE, (skygw_log_write_flush(
 | 
						|
                                LOGFILE_ERROR,
 | 
						|
                                "Error : Configuration object '%s' has no type.",
 | 
						|
                                obj->object)));
 | 
						|
			error_count++;
 | 
						|
		}
 | 
						|
		else if (!strcmp(type, "service"))
 | 
						|
		{
 | 
						|
                        char *router = config_get_value(obj->parameters,
 | 
						|
                                                        "router");
 | 
						|
                        if (router)
 | 
						|
                        {
 | 
						|
                                char* max_slave_conn_str;
 | 
						|
                                char* max_slave_rlag_str;
 | 
						|
				char *user;
 | 
						|
				char *auth;
 | 
						|
				char *enable_root_user;
 | 
						|
				char *connection_timeout;
 | 
						|
                char *auth_all_servers;
 | 
						|
				char *strip_db_esc;
 | 
						|
				char *weightby;
 | 
						|
				char *version_string;
 | 
						|
				bool  is_rwsplit = false;
 | 
						|
				bool  is_schemarouter = false;
 | 
						|
				char *allow_localhost_match_wildcard_host;
 | 
						|
 | 
						|
				obj->element = service_alloc(obj->object, router);
 | 
						|
				user = config_get_value(obj->parameters, "user");
 | 
						|
				auth = config_get_value(obj->parameters, "passwd");
 | 
						|
				enable_root_user = config_get_value(
 | 
						|
							obj->parameters, 
 | 
						|
							"enable_root_user");
 | 
						|
 | 
						|
				connection_timeout = 
 | 
						|
                    config_get_value(
 | 
						|
                                     obj->parameters,
 | 
						|
                                     "connection_timeout");
 | 
						|
 | 
						|
                auth_all_servers = 
 | 
						|
                    config_get_value(
 | 
						|
                                     obj->parameters, 
 | 
						|
                                     "auth_all_servers");
 | 
						|
 | 
						|
				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");
 | 
						|
 | 
						|
				weightby = config_get_value(obj->parameters, "weightby");
 | 
						|
			
 | 
						|
				version_string = config_get_value(obj->parameters, 
 | 
						|
								  "version_string");
 | 
						|
				/** flag for rwsplit-specific parameters */
 | 
						|
				if (strncmp(router, "readwritesplit", strlen("readwritesplit")+1) == 0)
 | 
						|
				{
 | 
						|
					is_rwsplit = true;
 | 
						|
				}
 | 
						|
 | 
						|
				allow_localhost_match_wildcard_host =
 | 
						|
                                        config_get_value(obj->parameters, "localhost_match_wildcard_host");
 | 
						|
 | 
						|
                                if (obj->element == NULL) /*< if module load failed */
 | 
						|
                                {
 | 
						|
					LOGIF(LE, (skygw_log_write_flush(
 | 
						|
                                                LOGFILE_ERROR,
 | 
						|
                                                "Error : Reading configuration "
 | 
						|
                                                "for router service '%s' failed. "
 | 
						|
                                                "Router %s is not loaded.",
 | 
						|
                                                obj->object,
 | 
						|
                                                obj->object)));
 | 
						|
                                        obj = obj->next;
 | 
						|
                                        continue; /*< process next obj */
 | 
						|
                                }
 | 
						|
 | 
						|
                                if (version_string) {
 | 
						|
					((SERVICE *)(obj->element))->version_string = strdup(version_string);
 | 
						|
				} else {
 | 
						|
					if (gateway.version_string)
 | 
						|
						((SERVICE *)(obj->element))->version_string = strdup(gateway.version_string);
 | 
						|
				}
 | 
						|
                                max_slave_conn_str = 
 | 
						|
                                        config_get_value(obj->parameters, 
 | 
						|
                                                         "max_slave_connections");
 | 
						|
                                        
 | 
						|
                                max_slave_rlag_str = 
 | 
						|
                                        config_get_value(obj->parameters, 
 | 
						|
                                                         "max_slave_replication_lag");
 | 
						|
                                        
 | 
						|
				if (enable_root_user)
 | 
						|
					serviceEnableRootUser(
 | 
						|
                                                obj->element, 
 | 
						|
                                                config_truth_value(enable_root_user));
 | 
						|
 | 
						|
				if (connection_timeout)
 | 
						|
					serviceSetTimeout(
 | 
						|
                                      obj->element, 
 | 
						|
                                      atoi(connection_timeout));
 | 
						|
 | 
						|
                if(auth_all_servers)
 | 
						|
                    serviceAuthAllServers(obj->element, 
 | 
						|
                                          config_truth_value(auth_all_servers));
 | 
						|
				if(strip_db_esc)
 | 
						|
                    serviceStripDbEsc(obj->element, 
 | 
						|
                                      config_truth_value(strip_db_esc));
 | 
						|
				if (weightby)
 | 
						|
					serviceWeightBy(obj->element, weightby);
 | 
						|
 | 
						|
				if (allow_localhost_match_wildcard_host)
 | 
						|
					serviceEnableLocalhostMatchWildcardHost(
 | 
						|
						obj->element,
 | 
						|
						config_truth_value(allow_localhost_match_wildcard_host));
 | 
						|
 | 
						|
				if (!auth)
 | 
						|
					auth = config_get_value(obj->parameters, 
 | 
						|
                                                                "auth");
 | 
						|
 | 
						|
				if (obj->element && user && auth)
 | 
						|
				{
 | 
						|
					serviceSetUser(obj->element, 
 | 
						|
                                                       user, 
 | 
						|
                                                       auth);
 | 
						|
				}
 | 
						|
				else if (user && auth == NULL)
 | 
						|
				{
 | 
						|
					LOGIF(LE, (skygw_log_write_flush(
 | 
						|
		                                LOGFILE_ERROR,
 | 
						|
               			                "Error : Service '%s' has a "
 | 
						|
						"user defined but no "
 | 
						|
						"corresponding password.",
 | 
						|
		                                obj->object)));
 | 
						|
				}
 | 
						|
				/** Read, validate and set max_slave_connections */
 | 
						|
				if (max_slave_conn_str != NULL)
 | 
						|
                                {
 | 
						|
                                        CONFIG_PARAMETER* param;
 | 
						|
                                        bool              succp;
 | 
						|
                                        
 | 
						|
                                        param = config_get_param(obj->parameters, 
 | 
						|
                                                                 "max_slave_connections");
 | 
						|
                                        
 | 
						|
					if (param == NULL)
 | 
						|
					{
 | 
						|
						succp = false;
 | 
						|
					}
 | 
						|
					else
 | 
						|
					{
 | 
						|
						succp = service_set_param_value(
 | 
						|
								obj->element,
 | 
						|
								param,
 | 
						|
								max_slave_conn_str, 
 | 
						|
								COUNT_ATMOST,
 | 
						|
								(COUNT_TYPE|PERCENT_TYPE));
 | 
						|
					}
 | 
						|
					
 | 
						|
                                        if (!succp)
 | 
						|
                                        {
 | 
						|
                                                LOGIF(LM, (skygw_log_write(
 | 
						|
                                                        LOGFILE_MESSAGE,
 | 
						|
                                                        "* Warning : invalid value type "
 | 
						|
                                                        "for parameter \'%s.%s = %s\'\n\tExpected "
 | 
						|
                                                        "type is either <int> for slave connection "
 | 
						|
                                                        "count or\n\t<int>%% for specifying the "
 | 
						|
                                                        "maximum percentage of available the "
 | 
						|
                                                        "slaves that will be connected.",
 | 
						|
                                                        ((SERVICE*)obj->element)->name,
 | 
						|
                                                        param->name,
 | 
						|
                                                        param->value)));
 | 
						|
                                        }
 | 
						|
                                }
 | 
						|
                                /** Read, validate and set max_slave_replication_lag */
 | 
						|
                                if (max_slave_rlag_str != NULL)
 | 
						|
                                {
 | 
						|
                                        CONFIG_PARAMETER* param;
 | 
						|
                                        bool              succp;
 | 
						|
                                        
 | 
						|
                                        param = config_get_param(
 | 
						|
                                                obj->parameters, 
 | 
						|
                                                "max_slave_replication_lag");
 | 
						|
                                        
 | 
						|
					if (param == NULL)
 | 
						|
					{
 | 
						|
						succp = false;
 | 
						|
					}
 | 
						|
					else
 | 
						|
					{
 | 
						|
						succp = service_set_param_value(
 | 
						|
							obj->element,
 | 
						|
							param,
 | 
						|
							max_slave_rlag_str,
 | 
						|
							COUNT_ATMOST,
 | 
						|
							COUNT_TYPE);
 | 
						|
					}
 | 
						|
					
 | 
						|
                                        if (!succp)
 | 
						|
                                        {
 | 
						|
                                                LOGIF(LM, (skygw_log_write(
 | 
						|
                                                        LOGFILE_MESSAGE,
 | 
						|
                                                        "* Warning : invalid value type "
 | 
						|
                                                        "for parameter \'%s.%s = %s\'\n\tExpected "
 | 
						|
                                                        "type is <int> for maximum "
 | 
						|
                                                        "slave replication lag.",
 | 
						|
                                                        ((SERVICE*)obj->element)->name,
 | 
						|
                                                        param->name,
 | 
						|
                                                        param->value)));
 | 
						|
                                        }
 | 
						|
                                }
 | 
						|
                                /** Parameters for rwsplit router only */
 | 
						|
                                if (is_rwsplit)
 | 
						|
				{
 | 
						|
					CONFIG_PARAMETER* param;
 | 
						|
					char*             use_sql_variables_in;
 | 
						|
					bool              succp;
 | 
						|
					
 | 
						|
					use_sql_variables_in = 
 | 
						|
						config_get_value(obj->parameters,
 | 
						|
								 "use_sql_variables_in");
 | 
						|
					
 | 
						|
					if (use_sql_variables_in != NULL)
 | 
						|
					{
 | 
						|
						param = config_get_param(
 | 
						|
								obj->parameters,
 | 
						|
								"use_sql_variables_in");
 | 
						|
						
 | 
						|
						if (param == NULL)
 | 
						|
						{
 | 
						|
							succp = false;
 | 
						|
						}
 | 
						|
						else
 | 
						|
						{
 | 
						|
							succp = service_set_param_value(obj->element,
 | 
						|
											param,
 | 
						|
											use_sql_variables_in,
 | 
						|
											COUNT_NONE,
 | 
						|
											SQLVAR_TARGET_TYPE);
 | 
						|
						}
 | 
						|
						
 | 
						|
						if (!succp)
 | 
						|
						{
 | 
						|
							if(param){
 | 
						|
							LOGIF(LM, (skygw_log_write(
 | 
						|
								LOGFILE_MESSAGE,
 | 
						|
								"* Warning : invalid value type "
 | 
						|
								"for parameter \'%s.%s = %s\'\n\tExpected "
 | 
						|
								"type is [master|all] for "
 | 
						|
								"use sql variables in.",
 | 
						|
								((SERVICE*)obj->element)->name,
 | 
						|
								param->name,
 | 
						|
								param->value)));
 | 
						|
							}else{
 | 
						|
								LOGIF(LE, (skygw_log_write(
 | 
						|
								LOGFILE_ERROR,
 | 
						|
								"Error : parameter was NULL")));
 | 
						|
							
 | 
						|
							}
 | 
						|
						}
 | 
						|
					}
 | 
						|
				} /*< if (rw_split) */
 | 
						|
			} /*< if (router) */
 | 
						|
			else
 | 
						|
			{
 | 
						|
				obj->element = NULL;
 | 
						|
				LOGIF(LE, (skygw_log_write_flush(
 | 
						|
                                        LOGFILE_ERROR,
 | 
						|
                                        "Error : No router defined for service "
 | 
						|
                                        "'%s'\n",
 | 
						|
                                        obj->object)));
 | 
						|
				error_count++;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else if (!strcmp(type, "server"))
 | 
						|
		{
 | 
						|
                        char *address;
 | 
						|
			char *port;
 | 
						|
			char *protocol;
 | 
						|
			char *monuser;
 | 
						|
			char *monpw;
 | 
						|
 | 
						|
                        address = config_get_value(obj->parameters, "address");
 | 
						|
			port = config_get_value(obj->parameters, "port");
 | 
						|
			protocol = config_get_value(obj->parameters, "protocol");
 | 
						|
			monuser = config_get_value(obj->parameters,
 | 
						|
                                                   "monitoruser");
 | 
						|
			monpw = config_get_value(obj->parameters, "monitorpw");
 | 
						|
 | 
						|
			if (address && port && protocol)
 | 
						|
			{
 | 
						|
				obj->element = server_alloc(address,
 | 
						|
                                                            protocol,
 | 
						|
                                                            atoi(port));
 | 
						|
				server_set_unique_name(obj->element, obj->object);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				obj->element = NULL;
 | 
						|
				LOGIF(LE, (skygw_log_write_flush(
 | 
						|
                                        LOGFILE_ERROR,
 | 
						|
                                        "Error : Server '%s' is missing a "
 | 
						|
                                        "required configuration parameter. A "
 | 
						|
                                        "server must "
 | 
						|
                                        "have address, port and protocol "
 | 
						|
                                        "defined.",
 | 
						|
                                        obj->object)));
 | 
						|
				error_count++;
 | 
						|
			}
 | 
						|
			if (obj->element && monuser && monpw)
 | 
						|
				serverAddMonUser(obj->element, monuser, monpw);
 | 
						|
			else if (monuser && monpw == NULL)
 | 
						|
			{
 | 
						|
				LOGIF(LE, (skygw_log_write_flush(
 | 
						|
	                                LOGFILE_ERROR,
 | 
						|
					"Error : Server '%s' has a monitoruser"
 | 
						|
					"defined but no corresponding password.",
 | 
						|
                                        obj->object)));
 | 
						|
			}
 | 
						|
			if (obj->element)
 | 
						|
			{
 | 
						|
				CONFIG_PARAMETER *params = obj->parameters;
 | 
						|
				while (params)
 | 
						|
				{
 | 
						|
					if (strcmp(params->name, "address")
 | 
						|
						&& strcmp(params->name, "port")
 | 
						|
						&& strcmp(params->name,
 | 
						|
								"protocol")
 | 
						|
						&& strcmp(params->name,
 | 
						|
								"monitoruser")
 | 
						|
						&& strcmp(params->name,
 | 
						|
								"monitorpw")
 | 
						|
						&& strcmp(params->name,
 | 
						|
								"type")
 | 
						|
						)
 | 
						|
					{
 | 
						|
						serverAddParameter(obj->element,
 | 
						|
							params->name,
 | 
						|
							params->value);
 | 
						|
					}
 | 
						|
					params = params->next;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else if (!strcmp(type, "filter"))
 | 
						|
		{
 | 
						|
                        char *module = config_get_value(obj->parameters,
 | 
						|
						"module");
 | 
						|
                        char *options = config_get_value(obj->parameters,
 | 
						|
						"options");
 | 
						|
 | 
						|
			if (module)
 | 
						|
			{
 | 
						|
				obj->element = filter_alloc(obj->object, module);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				LOGIF(LE, (skygw_log_write_flush(
 | 
						|
	                                LOGFILE_ERROR,
 | 
						|
					"Error: Filter '%s' has no module "
 | 
						|
					"defined defined to load.",
 | 
						|
                                        obj->object)));
 | 
						|
				error_count++;
 | 
						|
			}
 | 
						|
			if (obj->element && options)
 | 
						|
			{
 | 
						|
				char *lasts;
 | 
						|
				char *s = strtok_r(options, ",", &lasts);
 | 
						|
				while (s)
 | 
						|
				{
 | 
						|
					filterAddOption(obj->element, s);
 | 
						|
					s = strtok_r(NULL, ",", &lasts);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			if (obj->element)
 | 
						|
			{
 | 
						|
				CONFIG_PARAMETER *params = obj->parameters;
 | 
						|
				while (params)
 | 
						|
				{
 | 
						|
					if (strcmp(params->name, "module")
 | 
						|
						&& strcmp(params->name,
 | 
						|
							"options"))
 | 
						|
					{
 | 
						|
						filterAddParameter(obj->element,
 | 
						|
							params->name,
 | 
						|
							params->value);
 | 
						|
					}
 | 
						|
					params = params->next;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		obj = obj->next;
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Now we have the services we can add the servers to the services
 | 
						|
	 * add the protocols to the services
 | 
						|
	 */
 | 
						|
	obj = context;
 | 
						|
	while (obj)
 | 
						|
	{
 | 
						|
		char *type = config_get_value(obj->parameters, "type");
 | 
						|
		if (type == NULL)
 | 
						|
			;
 | 
						|
		else if (!strcmp(type, "service"))
 | 
						|
		{
 | 
						|
                        char *servers;
 | 
						|
			char *roptions;
 | 
						|
			char *router;
 | 
						|
                        char *filters = config_get_value(obj->parameters,
 | 
						|
                                                        "filters");
 | 
						|
			servers = config_get_value(obj->parameters, "servers");
 | 
						|
			roptions = config_get_value(obj->parameters,
 | 
						|
                                                    "router_options");
 | 
						|
			router = config_get_value(obj->parameters, "router");
 | 
						|
			if (servers && obj->element)
 | 
						|
			{
 | 
						|
				char *lasts;
 | 
						|
				char *s = strtok_r(servers, ",", &lasts);
 | 
						|
				while (s)
 | 
						|
				{
 | 
						|
					CONFIG_CONTEXT *obj1 = context;
 | 
						|
					int	found = 0;
 | 
						|
					while (obj1)
 | 
						|
					{
 | 
						|
						if (strcmp(trim(s), obj1->object) == 0 &&
 | 
						|
                                                    obj->element && obj1->element)
 | 
						|
                                                {
 | 
						|
							found = 1;
 | 
						|
							serviceAddBackend(
 | 
						|
                                                                obj->element,
 | 
						|
                                                                obj1->element);
 | 
						|
                                                }
 | 
						|
						obj1 = obj1->next;
 | 
						|
					}
 | 
						|
					if (!found)
 | 
						|
					{
 | 
						|
						LOGIF(LE, (skygw_log_write_flush(
 | 
						|
		                                        LOGFILE_ERROR,
 | 
						|
							"Error: Unable to find "
 | 
						|
							"server '%s' that is "
 | 
						|
							"configured as part of "
 | 
						|
							"service '%s'.",
 | 
						|
							s, obj->object)));
 | 
						|
					}
 | 
						|
					s = strtok_r(NULL, ",", &lasts);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			else if (servers == NULL && internalService(router) == 0)
 | 
						|
			{
 | 
						|
				LOGIF(LE, (skygw_log_write_flush(
 | 
						|
                                        LOGFILE_ERROR,
 | 
						|
                                        "Warning: The service '%s' is missing a "
 | 
						|
                                        "definition of the servers that provide "
 | 
						|
                                        "the service.",
 | 
						|
                                        obj->object)));
 | 
						|
			}
 | 
						|
			if (roptions && obj->element)
 | 
						|
			{
 | 
						|
				char *lasts;
 | 
						|
				char *s = strtok_r(roptions, ",", &lasts);
 | 
						|
				while (s)
 | 
						|
				{
 | 
						|
					serviceAddRouterOption(obj->element, s);
 | 
						|
					s = strtok_r(NULL, ",", &lasts);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			if (filters && obj->element)
 | 
						|
			{
 | 
						|
				serviceSetFilters(obj->element, filters);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else if (!strcmp(type, "listener"))
 | 
						|
		{
 | 
						|
                        char *service;
 | 
						|
			char *address;
 | 
						|
			char *port;
 | 
						|
			char *protocol;
 | 
						|
			char *socket;
 | 
						|
			struct sockaddr_in serv_addr;
 | 
						|
 | 
						|
                        service = config_get_value(obj->parameters, "service");
 | 
						|
			port = config_get_value(obj->parameters, "port");
 | 
						|
			address = config_get_value(obj->parameters, "address");
 | 
						|
			protocol = config_get_value(obj->parameters, "protocol");
 | 
						|
			socket = config_get_value(obj->parameters, "socket");
 | 
						|
 | 
						|
			/* 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 + 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++;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (service && port && protocol) {
 | 
						|
				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++;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			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++;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else if (!strcmp(type, "monitor"))
 | 
						|
		{
 | 
						|
                        char *module;
 | 
						|
			char *servers;
 | 
						|
			char *user;
 | 
						|
			char *passwd;
 | 
						|
			unsigned long interval = 0;
 | 
						|
			int replication_heartbeat = 0;
 | 
						|
			int detect_stale_master = 0;
 | 
						|
			int disable_master_failback = 0;
 | 
						|
			int connect_timeout = 0;
 | 
						|
			int read_timeout = 0;
 | 
						|
			int write_timeout = 0;
 | 
						|
 | 
						|
                        module = config_get_value(obj->parameters, "module");
 | 
						|
			servers = config_get_value(obj->parameters, "servers");
 | 
						|
			user = config_get_value(obj->parameters, "user");
 | 
						|
			passwd = config_get_value(obj->parameters, "passwd");
 | 
						|
			if (config_get_value(obj->parameters, "monitor_interval")) {
 | 
						|
				interval = strtoul(config_get_value(obj->parameters, "monitor_interval"), NULL, 10);
 | 
						|
			}
 | 
						|
 | 
						|
			if (config_get_value(obj->parameters, "detect_replication_lag")) {
 | 
						|
				replication_heartbeat = atoi(config_get_value(obj->parameters, "detect_replication_lag"));
 | 
						|
			}
 | 
						|
 | 
						|
			if (config_get_value(obj->parameters, "detect_stale_master")) {
 | 
						|
				detect_stale_master = atoi(config_get_value(obj->parameters, "detect_stale_master"));
 | 
						|
			}
 | 
						|
 | 
						|
			if (config_get_value(obj->parameters, "disable_master_failback")) {
 | 
						|
				disable_master_failback = atoi(config_get_value(obj->parameters, "disable_master_failback"));
 | 
						|
			}
 | 
						|
 | 
						|
			if (config_get_value(obj->parameters, "backend_connect_timeout")) {
 | 
						|
				connect_timeout = atoi(config_get_value(obj->parameters, "backend_connect_timeout"));
 | 
						|
			}
 | 
						|
			if (config_get_value(obj->parameters, "backend_read_timeout")) {
 | 
						|
				read_timeout = atoi(config_get_value(obj->parameters, "backend_read_timeout"));
 | 
						|
			}
 | 
						|
			if (config_get_value(obj->parameters, "backend_write_timeout")) {
 | 
						|
				write_timeout = atoi(config_get_value(obj->parameters, "backend_write_timeout"));
 | 
						|
			}
 | 
						|
			
 | 
						|
                        if (module)
 | 
						|
			{
 | 
						|
				obj->element = monitor_alloc(obj->object, module);
 | 
						|
				if (servers && obj->element)
 | 
						|
				{
 | 
						|
					char *s, *lasts;
 | 
						|
 | 
						|
					/* if id is not set, compute it now with pid only */
 | 
						|
					if (gateway.id == 0) {
 | 
						|
						gateway.id = getpid();
 | 
						|
					}
 | 
						|
 | 
						|
					/* add the maxscale-id to monitor data */
 | 
						|
					monitorSetId(obj->element, gateway.id);
 | 
						|
 | 
						|
					/* set monitor interval */
 | 
						|
					if (interval > 0)
 | 
						|
						monitorSetInterval(obj->element, interval);
 | 
						|
 | 
						|
					/* set replication heartbeat */
 | 
						|
					if(replication_heartbeat == 1)
 | 
						|
						monitorSetReplicationHeartbeat(obj->element, replication_heartbeat);
 | 
						|
 | 
						|
					/* detect stale master */
 | 
						|
					if(detect_stale_master == 1)
 | 
						|
						monitorDetectStaleMaster(obj->element, detect_stale_master);
 | 
						|
 | 
						|
					/* disable master failback */
 | 
						|
					if(disable_master_failback == 1)
 | 
						|
						monitorDisableMasterFailback(obj->element, disable_master_failback);
 | 
						|
 | 
						|
					/* set timeouts */
 | 
						|
					if (connect_timeout > 0)
 | 
						|
						monitorSetNetworkTimeout(obj->element, MONITOR_CONNECT_TIMEOUT, connect_timeout);
 | 
						|
					if (read_timeout > 0)
 | 
						|
						monitorSetNetworkTimeout(obj->element, MONITOR_READ_TIMEOUT, read_timeout);
 | 
						|
					if (write_timeout > 0)
 | 
						|
						monitorSetNetworkTimeout(obj->element, MONITOR_WRITE_TIMEOUT, write_timeout);
 | 
						|
 | 
						|
					/* get the servers to monitor */
 | 
						|
					s = strtok_r(servers, ",", &lasts);
 | 
						|
					while (s)
 | 
						|
					{
 | 
						|
						CONFIG_CONTEXT *obj1 = context;
 | 
						|
						int		found = 0;
 | 
						|
						while (obj1)
 | 
						|
						{
 | 
						|
							if (strcmp(trim(s), obj1->object) == 0 &&
 | 
						|
                                                            obj->element && obj1->element)
 | 
						|
                                                        {
 | 
						|
								found = 1;
 | 
						|
								monitorAddServer(
 | 
						|
                                                                        obj->element,
 | 
						|
                                                                        obj1->element);
 | 
						|
                                                        }
 | 
						|
							obj1 = obj1->next;
 | 
						|
						}
 | 
						|
						if (!found)
 | 
						|
							LOGIF(LE,
 | 
						|
							(skygw_log_write_flush(
 | 
						|
		                                        LOGFILE_ERROR,
 | 
						|
							"Error: Unable to find "
 | 
						|
							"server '%s' that is "
 | 
						|
							"configured in the "
 | 
						|
							"monitor '%s'.",
 | 
						|
							s, obj->object)));
 | 
						|
 | 
						|
						s = strtok_r(NULL, ",", &lasts);
 | 
						|
					}
 | 
						|
				}
 | 
						|
				if (obj->element && user && passwd)
 | 
						|
				{
 | 
						|
					monitorAddUser(obj->element,
 | 
						|
                                                       user,
 | 
						|
                                                       passwd);
 | 
						|
				}
 | 
						|
				else if (obj->element && user)
 | 
						|
				{
 | 
						|
					LOGIF(LE, (skygw_log_write_flush(
 | 
						|
						LOGFILE_ERROR, "Error: "
 | 
						|
						"Monitor '%s' defines a "
 | 
						|
						"username with no password.",
 | 
						|
						obj->object)));
 | 
						|
					error_count++;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				obj->element = NULL;
 | 
						|
				LOGIF(LE, (skygw_log_write_flush(
 | 
						|
                                        LOGFILE_ERROR,
 | 
						|
                                        "Error : Monitor '%s' is missing a "
 | 
						|
                                        "require module parameter.",
 | 
						|
                                        obj->object)));
 | 
						|
				error_count++;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else if (strcmp(type, "server") != 0
 | 
						|
			&& strcmp(type, "filter") != 0)
 | 
						|
		{
 | 
						|
			LOGIF(LE, (skygw_log_write_flush(
 | 
						|
                                LOGFILE_ERROR,
 | 
						|
                                "Error : Configuration object '%s' has an "
 | 
						|
                                "invalid type specified.",
 | 
						|
                                obj->object)));
 | 
						|
			error_count++;
 | 
						|
		}
 | 
						|
 | 
						|
		obj = obj->next;
 | 
						|
	} /*< while */
 | 
						|
	/** TODO: consistency check function */
 | 
						|
        
 | 
						|
        /**
 | 
						|
         * error_count += consistency_checks();
 | 
						|
         */
 | 
						|
 | 
						|
	if (error_count)
 | 
						|
	{
 | 
						|
		LOGIF(LE, (skygw_log_write_flush(
 | 
						|
                        LOGFILE_ERROR,
 | 
						|
                        "Error : %d errors where encountered processing the "
 | 
						|
                        "configuration file '%s'.",
 | 
						|
                        error_count,
 | 
						|
                        config_file)));
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Get the value of a config parameter
 | 
						|
 *
 | 
						|
 * @param params	The linked list of config parameters
 | 
						|
 * @param name		The parameter to return
 | 
						|
 * @return the parameter value or NULL if not found
 | 
						|
 */
 | 
						|
static char *
 | 
						|
config_get_value(CONFIG_PARAMETER *params, const char *name)
 | 
						|
{
 | 
						|
	while (params)
 | 
						|
	{
 | 
						|
		if (!strcmp(params->name, name))
 | 
						|
			return params->value;
 | 
						|
		params = params->next;
 | 
						|
	}
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
CONFIG_PARAMETER* config_get_param(
 | 
						|
        CONFIG_PARAMETER* params, 
 | 
						|
        const char*       name)
 | 
						|
{
 | 
						|
        while (params)
 | 
						|
        {
 | 
						|
                if (!strcmp(params->name, name))
 | 
						|
                        return params;
 | 
						|
                params = params->next;
 | 
						|
        }
 | 
						|
        return NULL;
 | 
						|
}
 | 
						|
 | 
						|
config_param_type_t config_get_paramtype(
 | 
						|
        CONFIG_PARAMETER* param)
 | 
						|
{
 | 
						|
        return param->qfd_param_type;
 | 
						|
}
 | 
						|
 | 
						|
bool config_get_valint(
 | 
						|
	int*                val,
 | 
						|
        CONFIG_PARAMETER*   param,
 | 
						|
        const char*         name, /*< if NULL examine current param only */
 | 
						|
        config_param_type_t ptype)
 | 
						|
{       
 | 
						|
	bool succp = false;;
 | 
						|
	
 | 
						|
	ss_dassert((ptype == COUNT_TYPE || ptype == PERCENT_TYPE) && param != NULL);
 | 
						|
        
 | 
						|
        while (param)
 | 
						|
        {
 | 
						|
                if (name == NULL || !strncmp(param->name, name, MAX_PARAM_LEN))
 | 
						|
                {
 | 
						|
                        switch (ptype) {
 | 
						|
                                case COUNT_TYPE:
 | 
						|
                                        *val = param->qfd.valcount;
 | 
						|
					succp = true;
 | 
						|
                                        goto return_succp;
 | 
						|
                                        
 | 
						|
                                case PERCENT_TYPE:
 | 
						|
                                        *val = param->qfd.valpercent;
 | 
						|
					succp  =true;
 | 
						|
                                        goto return_succp;
 | 
						|
 | 
						|
				default:
 | 
						|
                                        goto return_succp;
 | 
						|
                        }
 | 
						|
                } 
 | 
						|
                param = param->next;
 | 
						|
        }
 | 
						|
return_succp:
 | 
						|
        return succp;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool config_get_valbool(
 | 
						|
	bool*               val,
 | 
						|
	CONFIG_PARAMETER*   param,
 | 
						|
	const char*         name,
 | 
						|
	config_param_type_t ptype)
 | 
						|
{
 | 
						|
	bool succp;
 | 
						|
	
 | 
						|
	ss_dassert(ptype == BOOL_TYPE);
 | 
						|
	ss_dassert(param != NULL);
 | 
						|
	
 | 
						|
	if (ptype != BOOL_TYPE || param == NULL)
 | 
						|
	{
 | 
						|
		succp = false;
 | 
						|
		goto return_succp;
 | 
						|
	}
 | 
						|
	
 | 
						|
	while (param)
 | 
						|
	{
 | 
						|
		if (name == NULL || !strncmp(param->name, name, MAX_PARAM_LEN))
 | 
						|
		{
 | 
						|
			*val = param->qfd.valbool;
 | 
						|
			succp = true;
 | 
						|
			goto return_succp;
 | 
						|
		} 
 | 
						|
		param = param->next;
 | 
						|
	}
 | 
						|
	succp = false;
 | 
						|
	
 | 
						|
return_succp:
 | 
						|
	return succp;
 | 
						|
		
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool config_get_valtarget(
 | 
						|
	target_t*           val,
 | 
						|
	CONFIG_PARAMETER*   param,
 | 
						|
	const char*         name,
 | 
						|
	config_param_type_t ptype)
 | 
						|
{
 | 
						|
	bool succp;
 | 
						|
	
 | 
						|
	ss_dassert(ptype == SQLVAR_TARGET_TYPE);
 | 
						|
	ss_dassert(param != NULL);
 | 
						|
	
 | 
						|
	if (ptype != SQLVAR_TARGET_TYPE || param == NULL)
 | 
						|
	{
 | 
						|
		succp = false;
 | 
						|
		goto return_succp;
 | 
						|
	}
 | 
						|
	
 | 
						|
	while (param)
 | 
						|
	{
 | 
						|
		if (name == NULL || !strncmp(param->name, name, MAX_PARAM_LEN))
 | 
						|
		{
 | 
						|
			*val = param->qfd.valtarget;
 | 
						|
			succp = true;
 | 
						|
			goto return_succp;
 | 
						|
		} 
 | 
						|
		param = param->next;
 | 
						|
	}
 | 
						|
	succp = false;
 | 
						|
	
 | 
						|
return_succp:
 | 
						|
	return succp;
 | 
						|
	
 | 
						|
}
 | 
						|
 | 
						|
CONFIG_PARAMETER* config_clone_param(
 | 
						|
        CONFIG_PARAMETER* param)
 | 
						|
{
 | 
						|
        CONFIG_PARAMETER* p2;
 | 
						|
        
 | 
						|
        p2 = (CONFIG_PARAMETER*) malloc(sizeof(CONFIG_PARAMETER));
 | 
						|
        
 | 
						|
        if (p2 == NULL)
 | 
						|
        {
 | 
						|
                goto return_p2;
 | 
						|
        }
 | 
						|
        memcpy(p2, param, sizeof(CONFIG_PARAMETER));
 | 
						|
        p2->name = strndup(param->name, MAX_PARAM_LEN);
 | 
						|
        p2->value = strndup(param->value, MAX_PARAM_LEN);
 | 
						|
        
 | 
						|
        if (param->qfd_param_type == STRING_TYPE)
 | 
						|
        {
 | 
						|
                p2->qfd.valstr = strndup(param->qfd.valstr, MAX_PARAM_LEN);
 | 
						|
        }
 | 
						|
                        
 | 
						|
return_p2:
 | 
						|
        return p2;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Free a config tree
 | 
						|
 *
 | 
						|
 * @param context	The configuration data
 | 
						|
 */
 | 
						|
static	void
 | 
						|
free_config_context(CONFIG_CONTEXT *context)
 | 
						|
{
 | 
						|
CONFIG_CONTEXT		*obj;
 | 
						|
CONFIG_PARAMETER	*p1, *p2;
 | 
						|
 | 
						|
	while (context)
 | 
						|
	{
 | 
						|
		free(context->object);
 | 
						|
		p1 = context->parameters;
 | 
						|
		while (p1)
 | 
						|
		{
 | 
						|
			free(p1->name);
 | 
						|
			free(p1->value);
 | 
						|
			p2 = p1->next;
 | 
						|
			free(p1);
 | 
						|
			p1 = p2;
 | 
						|
		}
 | 
						|
		obj = context->next;
 | 
						|
		free(context);
 | 
						|
		context = obj;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Return the number of configured threads
 | 
						|
 *
 | 
						|
 * @return The number of threads configured in the config file
 | 
						|
 */
 | 
						|
int
 | 
						|
config_threadcount()
 | 
						|
{
 | 
						|
	return gateway.n_threads;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Return the number of non-blocking polls to be done before a blocking poll
 | 
						|
 * is issued.
 | 
						|
 *
 | 
						|
 * @return The number of blocking poll calls to make before a blocking call
 | 
						|
 */
 | 
						|
unsigned int
 | 
						|
config_nbpolls()
 | 
						|
{
 | 
						|
	return gateway.n_nbpoll;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Return the configured number of milliseconds for which we wait when we do
 | 
						|
 * a blocking poll call.
 | 
						|
 *
 | 
						|
 * @return The number of milliseconds to sleep in a blocking poll call
 | 
						|
 */
 | 
						|
unsigned int
 | 
						|
config_pollsleep()
 | 
						|
{
 | 
						|
	return gateway.pollsleep;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static struct {
 | 
						|
	char		*logname;
 | 
						|
	logfile_id_t	logfile;
 | 
						|
} lognames[] = {
 | 
						|
	{ "log_messages", LOGFILE_MESSAGE },
 | 
						|
	{ "log_trace", LOGFILE_TRACE },
 | 
						|
	{ "log_debug", LOGFILE_DEBUG },
 | 
						|
	{ NULL, 0 }
 | 
						|
};
 | 
						|
/**
 | 
						|
 * Configuration handler for items in the global [MaxScale] section
 | 
						|
 *
 | 
						|
 * @param name	The item name
 | 
						|
 * @param value	The item value
 | 
						|
 * @return 0 on error
 | 
						|
 */
 | 
						|
static	int
 | 
						|
handle_global_item(const char *name, const char *value)
 | 
						|
{
 | 
						|
int i;
 | 
						|
	if (strcmp(name, "threads") == 0)
 | 
						|
	{
 | 
						|
		gateway.n_threads = atoi(value);
 | 
						|
	}
 | 
						|
	else if (strcmp(name, "non_blocking_polls") == 0)
 | 
						|
	{ 
 | 
						|
		gateway.n_nbpoll = atoi(value);
 | 
						|
	}
 | 
						|
	else if (strcmp(name, "poll_sleep") == 0)
 | 
						|
	{
 | 
						|
		gateway.pollsleep = atoi(value);
 | 
						|
        }
 | 
						|
	else if (strcmp(name, "ms_timestamp") == 0)
 | 
						|
	{
 | 
						|
	    skygw_set_highp(atoi(value));
 | 
						|
        }
 | 
						|
	else
 | 
						|
	{
 | 
						|
		for (i = 0; lognames[i].logname; i++)
 | 
						|
		{
 | 
						|
			if (strcasecmp(name, lognames[i].logname) == 0)
 | 
						|
			{
 | 
						|
				if (atoi(value))
 | 
						|
					skygw_log_enable(lognames[i].logfile);
 | 
						|
				else
 | 
						|
					skygw_log_disable(lognames[i].logfile);
 | 
						|
			}
 | 
						|
		}
 | 
						|
        }
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Set the defaults for the global configuration options
 | 
						|
 */
 | 
						|
static void
 | 
						|
global_defaults()
 | 
						|
{
 | 
						|
	gateway.n_threads = 1;
 | 
						|
	gateway.n_nbpoll = DEFAULT_NBPOLLS;
 | 
						|
	gateway.pollsleep = DEFAULT_POLLSLEEP;
 | 
						|
	if (version_string != NULL)
 | 
						|
		gateway.version_string = strdup(version_string);
 | 
						|
	else
 | 
						|
		gateway.version_string = NULL;
 | 
						|
	gateway.id=0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Process a configuration context update and turn it into the set of object
 | 
						|
 * we need.
 | 
						|
 *
 | 
						|
 * @param context	The configuration data
 | 
						|
 */
 | 
						|
static	int
 | 
						|
process_config_update(CONFIG_CONTEXT *context)
 | 
						|
{
 | 
						|
CONFIG_CONTEXT		*obj;
 | 
						|
SERVICE			*service;
 | 
						|
SERVER			*server;
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Process the data and create the services and servers defined
 | 
						|
	 * in the data.
 | 
						|
	 */
 | 
						|
	obj = context;
 | 
						|
	while (obj)
 | 
						|
	{
 | 
						|
		char *type = config_get_value(obj->parameters, "type");
 | 
						|
		if (type == NULL)
 | 
						|
                {
 | 
						|
                    LOGIF(LE,
 | 
						|
                          (skygw_log_write_flush(
 | 
						|
                                  LOGFILE_ERROR,
 | 
						|
                                  "Error : Configuration object %s has no type.",
 | 
						|
                                  obj->object)));
 | 
						|
                }
 | 
						|
		else if (!strcmp(type, "service"))
 | 
						|
		{
 | 
						|
			char *router = config_get_value(obj->parameters,
 | 
						|
                                                        "router");
 | 
						|
			if (router)
 | 
						|
			{
 | 
						|
				if ((service = service_find(obj->object)) != NULL)
 | 
						|
				{
 | 
						|
                                        char *user;
 | 
						|
					char *auth;
 | 
						|
					char *enable_root_user;
 | 
						|
 | 
						|
					char *connection_timeout;
 | 
						|
 | 
						|
                    char* auth_all_servers;
 | 
						|
					char* strip_db_esc;
 | 
						|
                    char* max_slave_conn_str;
 | 
						|
                    char* max_slave_rlag_str;
 | 
						|
					char *version_string;
 | 
						|
					char *allow_localhost_match_wildcard_host;
 | 
						|
 | 
						|
					enable_root_user = config_get_value(obj->parameters, "enable_root_user");
 | 
						|
 | 
						|
					connection_timeout = config_get_value(obj->parameters, "connection_timeout");
 | 
						|
					
 | 
						|
                    user = config_get_value(obj->parameters,
 | 
						|
                                                                "user");
 | 
						|
					auth = config_get_value(obj->parameters,
 | 
						|
                                                                "passwd");
 | 
						|
                    
 | 
						|
                    auth_all_servers = config_get_value(obj->parameters, "auth_all_servers");
 | 
						|
                    strip_db_esc = config_get_value(obj->parameters, "strip_db_esc");
 | 
						|
					version_string = config_get_value(obj->parameters, "version_string");
 | 
						|
					allow_localhost_match_wildcard_host = config_get_value(obj->parameters, "localhost_match_wildcard_host");
 | 
						|
 | 
						|
					if (version_string) {
 | 
						|
						if (service->version_string) {
 | 
						|
							free(service->version_string);
 | 
						|
						}
 | 
						|
						service->version_string = strdup(version_string);
 | 
						|
					}
 | 
						|
 | 
						|
					if (user && auth) {
 | 
						|
						service_update(service, router,
 | 
						|
                                                               user,
 | 
						|
                                                               auth);
 | 
						|
						if (enable_root_user)
 | 
						|
							serviceEnableRootUser(service, atoi(enable_root_user));
 | 
						|
 | 
						|
						if (connection_timeout)
 | 
						|
							serviceSetTimeout(service, atoi(connection_timeout));
 | 
						|
 | 
						|
 | 
						|
                                                if(auth_all_servers)
 | 
						|
                                                    serviceAuthAllServers(service, atoi(auth_all_servers));
 | 
						|
						if(strip_db_esc)
 | 
						|
                                                    serviceStripDbEsc(service, atoi(strip_db_esc));
 | 
						|
 | 
						|
						if (allow_localhost_match_wildcard_host)
 | 
						|
							serviceEnableLocalhostMatchWildcardHost(
 | 
						|
								service,
 | 
						|
								atoi(allow_localhost_match_wildcard_host));
 | 
						|
                                                
 | 
						|
                                                /** Read, validate and set max_slave_connections */        
 | 
						|
                                                max_slave_conn_str = 
 | 
						|
                                                        config_get_value(
 | 
						|
                                                                obj->parameters, 
 | 
						|
                                                                "max_slave_connections");
 | 
						|
 | 
						|
                                                if (max_slave_conn_str != NULL)
 | 
						|
                                                {
 | 
						|
                                                        CONFIG_PARAMETER* param;
 | 
						|
                                                        bool              succp;
 | 
						|
                                                        
 | 
						|
                                                        param = config_get_param(obj->parameters, 
 | 
						|
                                                                        "max_slave_connections");
 | 
						|
                                                        
 | 
						|
							if (param == NULL)
 | 
						|
							{
 | 
						|
								succp = false;
 | 
						|
							}
 | 
						|
							else 
 | 
						|
							{
 | 
						|
								succp = service_set_param_value(
 | 
						|
										service,
 | 
						|
										param,
 | 
						|
										max_slave_conn_str, 
 | 
						|
										COUNT_ATMOST,
 | 
						|
										(PERCENT_TYPE|COUNT_TYPE));
 | 
						|
							}
 | 
						|
							
 | 
						|
                                                        if (!succp && param != NULL)
 | 
						|
                                                        {
 | 
						|
                                                                LOGIF(LM, (skygw_log_write(
 | 
						|
                                                                        LOGFILE_MESSAGE,
 | 
						|
                                                                        "* Warning : invalid value type "
 | 
						|
                                                                        "for parameter \'%s.%s = %s\'\n\tExpected "
 | 
						|
                                                                        "type is either <int> for slave connection "
 | 
						|
                                                                        "count or\n\t<int>%% for specifying the "
 | 
						|
                                                                        "maximum percentage of available the "
 | 
						|
                                                                        "slaves that will be connected.",
 | 
						|
                                                                        ((SERVICE*)obj->element)->name,
 | 
						|
                                                                                                param->name,
 | 
						|
                                                                                                param->value)));
 | 
						|
                                                        }
 | 
						|
                                                }
 | 
						|
                                                /** Read, validate and set max_slave_replication_lag */
 | 
						|
                                                max_slave_rlag_str = 
 | 
						|
                                                        config_get_value(obj->parameters, 
 | 
						|
                                                                 "max_slave_replication_lag");
 | 
						|
                                                
 | 
						|
                                                if (max_slave_rlag_str != NULL)
 | 
						|
                                                {
 | 
						|
                                                        CONFIG_PARAMETER* param;
 | 
						|
                                                        bool              succp;
 | 
						|
                                                        
 | 
						|
                                                        param = config_get_param(
 | 
						|
                                                                        obj->parameters, 
 | 
						|
                                                                        "max_slave_replication_lag");
 | 
						|
                                                        
 | 
						|
							if (param == NULL)
 | 
						|
							{
 | 
						|
								succp = false;
 | 
						|
							}
 | 
						|
							else 
 | 
						|
							{
 | 
						|
								succp = service_set_param_value(
 | 
						|
										service,
 | 
						|
										param,
 | 
						|
										max_slave_rlag_str,
 | 
						|
										COUNT_ATMOST,
 | 
						|
										COUNT_TYPE);
 | 
						|
							}
 | 
						|
							
 | 
						|
                                                        if (!succp)
 | 
						|
                                                        {
 | 
						|
															if(param){
 | 
						|
                                                                LOGIF(LM, (skygw_log_write(
 | 
						|
                                                                        LOGFILE_MESSAGE,
 | 
						|
                                                                        "* Warning : invalid value type "
 | 
						|
                                                                        "for parameter \'%s.%s = %s\'\n\tExpected "
 | 
						|
                                                                        "type is <int> for maximum "
 | 
						|
                                                                        "slave replication lag.",
 | 
						|
                                                                        ((SERVICE*)obj->element)->name,
 | 
						|
                                                                        param->name,
 | 
						|
                                                                        param->value)));                                                                
 | 
						|
															}else{
 | 
						|
                                                                LOGIF(LE, (skygw_log_write(
 | 
						|
                                                                        LOGFILE_ERROR,
 | 
						|
                                                                        "Error : parameter was NULL")));                                                                
 | 
						|
															}
 | 
						|
                                                        }
 | 
						|
                                                }
 | 
						|
					}
 | 
						|
 | 
						|
					obj->element = service;
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
                    char *user;
 | 
						|
					char *auth;
 | 
						|
					char *enable_root_user;
 | 
						|
					char *connection_timeout;
 | 
						|
					char *allow_localhost_match_wildcard_host;
 | 
						|
                    char *auth_all_servers;
 | 
						|
                    char *strip_db_esc;
 | 
						|
 | 
						|
					enable_root_user = 
 | 
						|
                                                config_get_value(obj->parameters, 
 | 
						|
                                                                 "enable_root_user");
 | 
						|
					
 | 
						|
 | 
						|
					connection_timeout = config_get_value(obj->parameters,
 | 
						|
                                                          "connection_timeout");
 | 
						|
					
 | 
						|
					auth_all_servers = 
 | 
						|
                                                config_get_value(obj->parameters, 
 | 
						|
                                                                 "auth_all_servers");
 | 
						|
					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");
 | 
						|
                    
 | 
						|
                    user = config_get_value(obj->parameters,
 | 
						|
                                            "user");
 | 
						|
					auth = config_get_value(obj->parameters,
 | 
						|
                                            "passwd");
 | 
						|
					obj->element = service_alloc(obj->object,
 | 
						|
                                                 router);
 | 
						|
                    
 | 
						|
					if (obj->element && user && auth)
 | 
						|
                                        {
 | 
						|
						serviceSetUser(obj->element,
 | 
						|
                                                               user,
 | 
						|
                                                               auth);
 | 
						|
						if (enable_root_user)
 | 
						|
							serviceEnableRootUser(obj->element, atoi(enable_root_user));
 | 
						|
 | 
						|
						if (connection_timeout)
 | 
						|
							serviceSetTimeout(obj->element, atoi(connection_timeout));
 | 
						|
 | 
						|
						if (allow_localhost_match_wildcard_host)
 | 
						|
							serviceEnableLocalhostMatchWildcardHost(
 | 
						|
								obj->element,
 | 
						|
								atoi(allow_localhost_match_wildcard_host));
 | 
						|
                                        }
 | 
						|
				}
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				obj->element = NULL;
 | 
						|
				LOGIF(LE, (skygw_log_write_flush(
 | 
						|
                                        LOGFILE_ERROR,
 | 
						|
                                        "Error : No router defined for service "
 | 
						|
                                        "'%s'.",
 | 
						|
                                        obj->object)));
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else if (!strcmp(type, "server"))
 | 
						|
		{
 | 
						|
                        char *address;
 | 
						|
			char *port;
 | 
						|
			char *protocol;
 | 
						|
			char *monuser;
 | 
						|
			char *monpw;
 | 
						|
                        
 | 
						|
			address = config_get_value(obj->parameters, "address");
 | 
						|
			port = config_get_value(obj->parameters, "port");
 | 
						|
			protocol = config_get_value(obj->parameters, "protocol");
 | 
						|
			monuser = config_get_value(obj->parameters,
 | 
						|
                                                   "monitoruser");
 | 
						|
			monpw = config_get_value(obj->parameters, "monitorpw");
 | 
						|
 | 
						|
                        if (address && port && protocol)
 | 
						|
			{
 | 
						|
				if ((server =
 | 
						|
                                     server_find(address, atoi(port))) != NULL)
 | 
						|
				{
 | 
						|
					server_update(server,
 | 
						|
                                                      protocol,
 | 
						|
                                                      monuser,
 | 
						|
                                                      monpw);
 | 
						|
					obj->element = server;
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					obj->element = server_alloc(address,
 | 
						|
                                                                    protocol,
 | 
						|
                                                                    atoi(port));
 | 
						|
					if (obj->element && monuser && monpw)
 | 
						|
                                        {
 | 
						|
						serverAddMonUser(obj->element,
 | 
						|
                                                                 monuser,
 | 
						|
                                                                 monpw);
 | 
						|
                                        }
 | 
						|
				}
 | 
						|
			}
 | 
						|
			else
 | 
						|
                        {
 | 
						|
				LOGIF(LE, (skygw_log_write_flush(
 | 
						|
                                        LOGFILE_ERROR,
 | 
						|
                                        "Error : Server '%s' is missing a "
 | 
						|
                                        "required "
 | 
						|
                                        "configuration parameter. A server must "
 | 
						|
                                        "have address, port and protocol "
 | 
						|
                                        "defined.",
 | 
						|
                                        obj->object)));
 | 
						|
                        }
 | 
						|
		}
 | 
						|
		obj = obj->next;
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Now we have the services we can add the servers to the services
 | 
						|
	 * add the protocols to the services
 | 
						|
	 */
 | 
						|
	obj = context;
 | 
						|
	while (obj)
 | 
						|
	{
 | 
						|
		char *type = config_get_value(obj->parameters, "type");
 | 
						|
		if (type == NULL)
 | 
						|
			;
 | 
						|
		else if (!strcmp(type, "service"))
 | 
						|
		{
 | 
						|
                        char *servers;
 | 
						|
			char *roptions;
 | 
						|
			char *filters;
 | 
						|
                        
 | 
						|
			servers = config_get_value(obj->parameters, "servers");
 | 
						|
			roptions = config_get_value(obj->parameters,
 | 
						|
                                                    "router_options");
 | 
						|
			filters = config_get_value(obj->parameters, "filters");
 | 
						|
			if (servers && obj->element)
 | 
						|
			{
 | 
						|
				char *lasts;
 | 
						|
				char *s = strtok_r(servers, ",", &lasts);
 | 
						|
				while (s)
 | 
						|
				{
 | 
						|
					CONFIG_CONTEXT *obj1 = context;
 | 
						|
					int		found = 0;
 | 
						|
					while (obj1)
 | 
						|
					{
 | 
						|
						if (strcmp(trim(s), obj1->object) == 0 &&
 | 
						|
                                                    obj->element && obj1->element)
 | 
						|
                                                {
 | 
						|
							found = 1;
 | 
						|
							if (!serviceHasBackend(obj->element, obj1->element))
 | 
						|
                                                        {
 | 
						|
								serviceAddBackend(
 | 
						|
                                                                        obj->element,
 | 
						|
                                                                        obj1->element);
 | 
						|
                                                        }
 | 
						|
                                                }
 | 
						|
						obj1 = obj1->next;
 | 
						|
					}
 | 
						|
					if (!found)
 | 
						|
					{
 | 
						|
						LOGIF(LE, (skygw_log_write_flush(
 | 
						|
		                                        LOGFILE_ERROR,
 | 
						|
							"Error: Unable to find "
 | 
						|
							"server '%s' that is "
 | 
						|
							"configured as part of "
 | 
						|
							"service '%s'.",
 | 
						|
							s, obj->object)));
 | 
						|
					}
 | 
						|
					s = strtok_r(NULL, ",", &lasts);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			if (roptions && obj->element)
 | 
						|
			{
 | 
						|
				char *lasts;
 | 
						|
				char *s = strtok_r(roptions, ",", &lasts);
 | 
						|
				serviceClearRouterOptions(obj->element);
 | 
						|
				while (s)
 | 
						|
				{
 | 
						|
					serviceAddRouterOption(obj->element, s);
 | 
						|
					s = strtok_r(NULL, ",", &lasts);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			if (filters && obj->element)
 | 
						|
				serviceSetFilters(obj->element, filters);
 | 
						|
		}
 | 
						|
		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));
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else if (strcmp(type, "server") != 0 &&
 | 
						|
                         strcmp(type, "monitor") != 0 &&
 | 
						|
			 strcmp(type, "filter") != 0)
 | 
						|
		{
 | 
						|
			LOGIF(LE, (skygw_log_write_flush(
 | 
						|
                                LOGFILE_ERROR,
 | 
						|
                                "Error : Configuration object %s has an invalid "
 | 
						|
                                "type specified.",
 | 
						|
                                obj->object)));
 | 
						|
		}
 | 
						|
		obj = obj->next;
 | 
						|
	}
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
 | 
						|
static char *service_params[] =
 | 
						|
	{
 | 
						|
                "type",
 | 
						|
                "router",
 | 
						|
                "router_options",
 | 
						|
                "servers",
 | 
						|
                "user",
 | 
						|
                "passwd",
 | 
						|
                "enable_root_user",
 | 
						|
                "connection_timeout",
 | 
						|
                "auth_all_servers",
 | 
						|
                "strip_db_esc",
 | 
						|
                "localhost_match_wildcard_host",
 | 
						|
                "max_slave_connections",
 | 
						|
                "max_slave_replication_lag",
 | 
						|
                "use_sql_variables_in",		/*< rwsplit only */
 | 
						|
                "subservices",
 | 
						|
                "version_string",
 | 
						|
                "filters",
 | 
						|
                "weightby",
 | 
						|
                NULL
 | 
						|
        };
 | 
						|
 | 
						|
static char *listener_params[] =
 | 
						|
	{
 | 
						|
                "type",
 | 
						|
                "service",
 | 
						|
                "protocol",
 | 
						|
                "port",
 | 
						|
                "address",
 | 
						|
                "socket",
 | 
						|
                NULL
 | 
						|
        };
 | 
						|
 | 
						|
static char *monitor_params[] =
 | 
						|
	{
 | 
						|
                "type",
 | 
						|
                "module",
 | 
						|
                "servers",
 | 
						|
                "user",
 | 
						|
                "passwd",
 | 
						|
		"monitor_interval",
 | 
						|
		"detect_replication_lag",
 | 
						|
		"detect_stale_master",
 | 
						|
		"disable_master_failback",
 | 
						|
		"backend_connect_timeout",
 | 
						|
		"backend_read_timeout",
 | 
						|
		"backend_write_timeout",
 | 
						|
                NULL
 | 
						|
        };
 | 
						|
/**
 | 
						|
 * Check the configuration objects have valid parameters
 | 
						|
 */
 | 
						|
static void
 | 
						|
check_config_objects(CONFIG_CONTEXT *context)
 | 
						|
{
 | 
						|
CONFIG_CONTEXT		*obj;
 | 
						|
CONFIG_PARAMETER 	*params;
 | 
						|
char			*type, **param_set;
 | 
						|
int			i;
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Process the data and create the services and servers defined
 | 
						|
	 * in the data.
 | 
						|
	 */
 | 
						|
	obj = context;
 | 
						|
	while (obj)
 | 
						|
	{
 | 
						|
		param_set = NULL;
 | 
						|
		if (obj->parameters &&
 | 
						|
			(type = config_get_value(obj->parameters, "type")))
 | 
						|
		{
 | 
						|
			if (!strcmp(type, "service"))
 | 
						|
				param_set = service_params;
 | 
						|
			else if (!strcmp(type, "listener"))
 | 
						|
				param_set = listener_params;
 | 
						|
			else if (!strcmp(type, "monitor"))
 | 
						|
				param_set = monitor_params;
 | 
						|
		}
 | 
						|
		if (param_set != NULL)
 | 
						|
		{
 | 
						|
			params = obj->parameters;
 | 
						|
			while (params)
 | 
						|
			{
 | 
						|
				int found = 0;
 | 
						|
				for (i = 0; param_set[i]; i++)
 | 
						|
					if (!strcmp(params->name, param_set[i]))
 | 
						|
						found = 1;
 | 
						|
				if (found == 0)
 | 
						|
					LOGIF(LE, (skygw_log_write_flush(
 | 
						|
                                                LOGFILE_ERROR,
 | 
						|
                                                "Error : Unexpected parameter "
 | 
						|
                                                "'%s' for object '%s' of type "
 | 
						|
                                                "'%s'.",
 | 
						|
						params->name,
 | 
						|
                                                obj->object,
 | 
						|
                                                type)));
 | 
						|
				params = params->next;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		obj = obj->next;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Set qualified parameter value to CONFIG_PARAMETER struct.
 | 
						|
 */
 | 
						|
bool config_set_qualified_param(
 | 
						|
        CONFIG_PARAMETER* param, 
 | 
						|
        void* val, 
 | 
						|
        config_param_type_t type)
 | 
						|
{
 | 
						|
        bool succp;
 | 
						|
        
 | 
						|
        switch (type) {
 | 
						|
                case STRING_TYPE:
 | 
						|
                        param->qfd.valstr = strndup((const char *)val, MAX_PARAM_LEN);
 | 
						|
                        succp = true;
 | 
						|
                        break;
 | 
						|
 | 
						|
                case COUNT_TYPE:
 | 
						|
                        param->qfd.valcount = *(int *)val;
 | 
						|
                        succp = true;
 | 
						|
                        break;
 | 
						|
                        
 | 
						|
                case PERCENT_TYPE:
 | 
						|
                        param->qfd.valpercent = *(int *)val;
 | 
						|
                        succp = true;
 | 
						|
                        break;
 | 
						|
                        
 | 
						|
                case BOOL_TYPE:
 | 
						|
                        param->qfd.valbool = *(bool *)val;
 | 
						|
                        succp = true;
 | 
						|
                        break;
 | 
						|
 | 
						|
		case SQLVAR_TARGET_TYPE:
 | 
						|
			param->qfd.valtarget = *(target_t *)val;
 | 
						|
			succp = true;
 | 
						|
			break;
 | 
						|
                default:
 | 
						|
                        succp = false;
 | 
						|
                        break;
 | 
						|
        }
 | 
						|
        
 | 
						|
        if (succp)
 | 
						|
        {
 | 
						|
                param->qfd_param_type = type;
 | 
						|
        }
 | 
						|
        return succp;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Used for boolean settings where values may be 1, yes or true
 | 
						|
 * to enable a setting or -, no, false to disable a setting.
 | 
						|
 *
 | 
						|
 * @param	str	String to convert to a boolean
 | 
						|
 * @return	Truth value
 | 
						|
 */
 | 
						|
int
 | 
						|
config_truth_value(char *str)
 | 
						|
{
 | 
						|
	if (strcasecmp(str, "true") == 0 || strcasecmp(str, "on") == 0 || strcasecmp(str, "yes") == 0)
 | 
						|
	{
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
	if (strcasecmp(str, "false") == 0 || strcasecmp(str, "off") == 0 || strcasecmp(str, "no") == 0)
 | 
						|
	{
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	return atoi(str);
 | 
						|
}
 | 
						|
 | 
						|
static char *InternalRouters[] = {
 | 
						|
	"debugcli",
 | 
						|
	"cli",
 | 
						|
	NULL
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Determine if the router is one of the special internal services that
 | 
						|
 * MaxScale offers.
 | 
						|
 *
 | 
						|
 * @param router	The router name
 | 
						|
 * @return	Non-zero if the router is in the InternalRouters table
 | 
						|
 */
 | 
						|
static int
 | 
						|
internalService(char *router)
 | 
						|
{
 | 
						|
int	i;
 | 
						|
 | 
						|
	if (router)
 | 
						|
	{
 | 
						|
		for (i = 0; InternalRouters[i]; i++)
 | 
						|
			if (strcmp(router, InternalRouters[i]) == 0)
 | 
						|
				return 1;
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 |