Add new parameter type MXS_MODULE_PARAM_SERVERLIST

This is a list of servers, separated by commas. When queried as a
config setting, returns a null-terminated array of SERVER*:s. The
commit includes a serverlist parsing function, which should probably
be used anywhere a similarly formed string is parsed.
This commit is contained in:
Esa Korhonen 2017-03-14 11:19:00 +02:00
parent dd82c46596
commit 3129efb3f7
6 changed files with 168 additions and 0 deletions

View File

@ -205,6 +205,17 @@ struct service* config_get_service(const MXS_CONFIG_PARAMETER *params, const cha
*/
struct server* config_get_server(const MXS_CONFIG_PARAMETER *params, const char *key);
/**
* @brief Get an array of servers. The caller should free the returned array, but not
* the array elements.
*
* @param params List of configuration parameters
* @param key Parameter name
*
* @return Pointer to a null-terminated array of servers, or null if none found.
*/
struct server** config_get_serverlist(const MXS_CONFIG_PARAMETER *params, const char *key);
/**
* @brief Get copy of parameter value if it is defined
*

View File

@ -79,6 +79,7 @@ enum mxs_module_param_type
MXS_MODULE_PARAM_PATH, /**< Path to a file or a directory */
MXS_MODULE_PARAM_SERVICE, /**< Service name */
MXS_MODULE_PARAM_SERVER, /**< Server name */
MXS_MODULE_PARAM_SERVERLIST /**< List of server names, separated by ',' */
};
/** Maximum and minimum values for integer types */

View File

@ -256,6 +256,7 @@ bool server_remove_parameter(SERVER *server, const char *name);
extern int server_free(SERVER *server);
extern SERVER *server_find_by_unique_name(const char *name);
extern SERVER** server_find_by_unique_names(char **server_names, int size);
extern SERVER *server_find(const char *servname, unsigned short port);
extern char *server_status(const SERVER *);
extern void server_clear_set_status(SERVER *server, int specified_bits, int bits_to_set);

View File

@ -1057,6 +1057,24 @@ SERVER* config_get_server(const MXS_CONFIG_PARAMETER *params, const char *key)
return server_find_by_unique_name(value);
}
SERVER** config_get_serverlist(const MXS_CONFIG_PARAMETER *params, const char *key)
{
const char *value = config_get_value_string(params, key);
char **server_names = NULL;
SERVER **servers = NULL;
int n_names = config_parse_server_list(value, &server_names);
if (n_names > 0)
{
servers = server_find_by_unique_names(server_names, n_names);
for (int i = 0; i < n_names; i++)
{
MXS_FREE(server_names[i]);
}
MXS_FREE(server_names);
}
return servers;
}
char* config_copy_string(const MXS_CONFIG_PARAMETER *params, const char *key)
{
const char *value = config_get_value_string(params, key);
@ -3413,6 +3431,30 @@ bool config_param_is_valid(const MXS_MODULE_PARAM *params, const char *key,
}
break;
case MXS_MODULE_PARAM_SERVERLIST:
if (context)
{
valid = true;
char **server_names = NULL;
int n_serv = config_parse_server_list(value, &server_names);
if (n_serv > 0)
{
/* Check that every server name in the list is found in the config. */
for (int i = 0; i < n_serv; i++)
{
if (valid &&
!config_contains_type(context, server_names[i], "server"))
{
valid = false;
}
MXS_FREE(server_names[i]);
}
MXS_FREE(server_names);
}
break;
}
case MXS_MODULE_PARAM_PATH:
valid = check_path_parameter(&params[i], value);
break;
@ -3427,3 +3469,70 @@ bool config_param_is_valid(const MXS_MODULE_PARAM *params, const char *key,
return valid;
}
static int config_parse_server_list(const char *servers, char ***output_array)
{
ss_dassert(servers);
/* First, check the string for the maximum amount of servers it
* might contain by counting the commas. */
int out_arr_size = 1;
const char *pos = servers;
while ((pos = strchr(pos, ',')) != NULL)
{
pos++;
out_arr_size++;
}
char **results = MXS_CALLOC(out_arr_size, sizeof(char*));
if (!results)
{
return -1;
}
/* Parse the server names from the list. They are separated by ',' and will
* be trimmed of whitespace. */
char srv_list_tmp[strlen(servers) + 1];
strcpy(srv_list_tmp, servers);
trim(srv_list_tmp);
bool error = false;
int output_ind = 0;
char *lasts;
char *s = strtok_r(srv_list_tmp, ",", &lasts);
while (s)
{
char srv_name_tmp[strlen(s) + 1];
strcpy(srv_name_tmp, s);
trim(srv_name_tmp);
if (strlen(srv_name_tmp) > 0)
{
results[output_ind] = MXS_STRDUP(srv_name_tmp);
if (!results[output_ind])
{
error = true;
break;
}
output_ind++;
}
s = strtok_r(NULL, ",", &lasts);
}
if (error)
{
int i = 0;
while (results[i])
{
MXS_FREE(results[i]);
i++;
}
output_ind = 0;
}
if (output_ind == 0)
{
MXS_FREE(results);
results = NULL;
}
*output_array = results;
return output_ind;
}

View File

@ -111,4 +111,15 @@ SSL_LISTENER *make_ssl_structure(CONFIG_CONTEXT *obj, bool require_cert, int *er
*/
bool config_have_required_ssl_params(CONFIG_CONTEXT *obj);
/**
* Parses a list of server names and writes the results in an array of strings
* with one server in each. The output array and its elements should be deallocated
* by the caller. The server names are not checked to be valid servers.
*
* @param servers A list of server names.
* @param output_array Save location for the array of server names. Set to null if none found.
* @return How many servers were found and set into the array.
*/
static int config_parse_server_list(const char *servers, char ***output_array);
MXS_END_DECLS

View File

@ -296,6 +296,41 @@ SERVER * server_find_by_unique_name(const char *name)
return server;
}
/**
* Find several servers with the names specified in an array with a given size.
* The returned array (but not the elements) should be freed by the caller, and
* is null-terminated.
*
* @param servers An array of server names
* @param size number of elements in the server names array
* @return A null-terminated array of SERVERs. May contain less elements than
* requested if some server names are not found.
*/
SERVER** server_find_by_unique_names(char **server_names, int size)
{
ss_dassert(server_names);
SERVER **results = MXS_CALLOC(size + 1, sizeof(SERVER*)); // +1 for null
if (!results)
{
return NULL;
}
int res_ind = 0;
for (int i = 0; server_names[i] != NULL; i++)
{
SERVER *serv = server_find_by_unique_name(server_names[i]);
if (serv)
{
results[res_ind] = serv;
res_ind++;
}
}
return results;
}
/**
* Find an existing server
*