FreeSWITCH API Documentation  1.7.0
switch_xml_config.c
Go to the documentation of this file.
1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Mathieu Rene <mathieu.rene@gmail.com>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Mathieu Rene <mathieu.rene@gmail.com>
27  *
28  *
29  * switch_xml_config.c - Generic configuration parser
30  *
31  */
32 
33 #include <switch.h>
34 
36 
38  {"int", SWITCH_CONFIG_INT},
39  {"switch_atomic_t", SWITCH_CONFIG_INT},
40  {"string", SWITCH_CONFIG_STRING},
41  {"bool", SWITCH_CONFIG_BOOL},
42  {"custom", SWITCH_CONFIG_CUSTOM},
43  {"enum", SWITCH_CONFIG_ENUM},
44  {"flag", SWITCH_CONFIG_FLAG},
45  {"flagarray", SWITCH_CONFIG_FLAGARRAY},
46  {NULL, 0}
47 };
48 
49 SWITCH_DECLARE(switch_size_t) switch_event_import_xml(switch_xml_t xml, const char *keyname, const char *valuename, switch_event_t **event)
50 {
51  switch_xml_t node;
52  switch_size_t count = 0;
53 
54  if (!*event) {
55  /* SWITCH_EVENT_CLONE will not insert any generic event headers */
57  switch_assert(*event);
58  }
59 
60  for (node = xml; node; node = node->next) {
61  const char *key = switch_xml_attr_soft(node, keyname);
62  const char *value = switch_xml_attr_soft(node, valuename);
63  if (key && value) {
65  count++;
66  }
67  }
68 
69  return count;
70 }
71 
73 {
74  switch_xml_t cfg, xml, settings;
76 
77  if (!(xml = switch_xml_open_cfg(file, &cfg, NULL))) {
78  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not open %s\n", file);
79  return SWITCH_STATUS_FALSE;
80  }
81 
82  if ((settings = switch_xml_child(cfg, "settings"))) {
83  status = switch_xml_config_parse(switch_xml_child(settings, "param"), reload, instructions);
84  }
85 
86  switch_xml_free(xml);
87 
88  return status;
89 }
90 
92 {
93  if (item->syntax && item->helptext) {
94  switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, level, "Item name: [%s]\nType: %s (%s)\nSyntax: %s\nHelp: %s\n\n",
95  item->key, switch_xml_config_enum_int2str(switch_config_types_enum, item->type),
96  switch_test_flag(item, CONFIG_REQUIRED) ? "required" : "optional", item->syntax, item->helptext);
97  }
98 }
99 
101 {
102  switch_event_t *event = NULL;
103  switch_status_t result;
104  int count = (int)switch_event_import_xml(xml, "name", "value", &event);
105 
106  result = switch_xml_config_parse_event(event, count, reload, instructions);
107 
108  if (event) {
109  switch_event_destroy(&event);
110  }
111 
112  return result;
113 }
114 
116 {
117  for (; enum_options->key; enum_options++) {
118  if (!strcasecmp(value, enum_options->key)) {
119  *out = enum_options->value;
120  return SWITCH_STATUS_SUCCESS;
121  }
122  }
123 
124  return SWITCH_STATUS_FALSE;
125 }
126 
128 {
129  for (; enum_options->key; enum_options++) {
130  if (value == enum_options->value) {
131  return enum_options->key;
132  }
133  }
134  return NULL;
135 }
136 
138  switch_xml_config_item_t *instructions)
139 {
141  int matched_count = 0;
142 
143  for (item = instructions; item->key; item++) {
144  const char *value = switch_event_get_header(event, item->key);
145  switch_bool_t changed = SWITCH_FALSE;
147  void *ptr = item->ptr;
148 
149  //switch_assert(ptr);
150 
151  if (value) {
152  matched_count++;
153  }
154 
155  if (reload && !switch_test_flag(item, CONFIG_RELOADABLE)) {
156  continue;
157  }
158 
159  if (!value && switch_test_flag(item, CONFIG_REQUIRED)) {
160  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Required parameter [%s] is missing\n", item->key);
161  return SWITCH_STATUS_FALSE;
162  }
163 
164  switch (item->type) {
165  case SWITCH_CONFIG_INT:
166  {
168  int *dest = (int *) ptr;
169  int intval;
170  if (value) {
171  if (switch_is_number(value)) {
172  intval = atoi(value);
173  } else {
174  intval = (int) (intptr_t) item->defaultvalue;
175  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid value [%s] for parameter [%s], setting default [%d]\n",
176  value, item->key, intval);
177  }
178 
179  if (int_options) {
180  /* Enforce validation options */
181  if ((int_options->enforce_min && !(intval >= int_options->min)) || (int_options->enforce_max && !(intval <= int_options->max))) {
182  /* Validation failed, set default */
183  intval = (int) (intptr_t) item->defaultvalue;
184  /* Then complain */
185  if (int_options->enforce_min && int_options->enforce_max) {
187  "Invalid value [%s] for parameter [%s], should be between [%d] and [%d], setting default [%d]\n", value,
188  item->key, int_options->min, int_options->max, intval);
189  } else {
191  "Invalid value [%s] for parameter [%s], should be %s [%d], setting default [%d]\n", value, item->key,
192  int_options->enforce_min ? "at least" : "at max",
193  int_options->enforce_min ? int_options->min : int_options->max, intval);
194  }
195  }
196  }
197  } else {
198  intval = (int) (intptr_t) item->defaultvalue;
199  }
200 
201  if (*dest != intval) {
202  *dest = intval;
203  changed = SWITCH_TRUE;
204  }
205  }
206  break;
208  {
210  switch_atomic_t *dest = (switch_atomic_t *) ptr;
211  uint32_t uintval;
212  if (value) {
213  if (switch_is_number(value)) {
214  uintval = (uint32_t) strtol(value, NULL, 10);
215  } else {
216  uintval = (uint32_t) (uintptr_t) item->defaultvalue;
217  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid value [%s] for parameter [%s], setting default [%u]\n",
218  value, item->key, uintval);
219  }
220 
221  if (atomic_options) {
222  /* Enforce validation options */
223  if ((atomic_options->enforce_min && !(uintval >= atomic_options->min)) || (atomic_options->enforce_max && !(uintval <= atomic_options->max))) {
224  /* Validation failed, set default */
225  uintval = (uint32_t) (uintptr_t) item->defaultvalue;
226  /* Then complain */
227  if (atomic_options->enforce_min && atomic_options->enforce_max) {
229  "Invalid value [%s] for parameter [%s], should be between [%u] and [%u], setting default [%u]\n", value,
230  item->key, atomic_options->min, atomic_options->max, uintval);
231  } else {
233  "Invalid value [%s] for parameter [%s], should be %s [%u], setting default [%u]\n", value, item->key,
234  atomic_options->enforce_min ? "at least" : "at max",
235  atomic_options->enforce_min ? atomic_options->min : atomic_options->max, uintval);
236  }
237  }
238  }
239  } else {
240  uintval = (uint32_t) (uintptr_t) item->defaultvalue;
241  }
242 
243  if (switch_atomic_read(dest) != uintval) {
244  switch_atomic_set(dest, uintval);
245  changed = SWITCH_TRUE;
246  }
247  }
248  break;
250  {
251  switch_xml_config_string_options_t string_options_default = { 0 };
252  switch_xml_config_string_options_t *string_options =
253  item->data ? (switch_xml_config_string_options_t *) item->data : &string_options_default;
254  const char *newstring = NULL;
255 
256  /* Perform validation */
257  if (value) {
258  if (!zstr(string_options->validation_regex)) {
259  if (switch_regex_match(value, string_options->validation_regex) == SWITCH_STATUS_SUCCESS) {
260  newstring = value; /* Regex match, accept value */
261  } else {
262  newstring = (char *) item->defaultvalue; /* Regex failed */
263  if (newstring) {
264  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid value [%s] for parameter [%s], setting default [%s]\n",
265  value, item->key, newstring);
266  } else {
267  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid value [%s] for parameter [%s]\n", value, item->key);
268  }
270  }
271  } else {
272  newstring = value; /* No validation */
273  }
274  } else {
275  newstring = (char *) item->defaultvalue;
276  }
277 
278  if (string_options->length > 0) {
279  /* We have a preallocated buffer */
280  char *dest = (char *) ptr;
281 
282  if (newstring) {
283  if (strncasecmp(dest, newstring, string_options->length)) {
284  switch_copy_string(dest, newstring, string_options->length);
285  changed = SWITCH_TRUE;
286  }
287  } else {
288  if (*dest != '\0') {
289  *dest = '\0';
290  changed = SWITCH_TRUE;
291  }
292  }
293  } else if (string_options->pool) {
294  /* Pool-allocated buffer */
295  char **dest = (char **) ptr;
296 
297  if (newstring) {
298  if (!*dest || strcmp(*dest, newstring)) {
299  *dest = switch_core_strdup(string_options->pool, newstring);
300  }
301  } else {
302  if (*dest) {
303  changed = SWITCH_TRUE;
304  *dest = NULL;
305  }
306  }
307  } else {
308  /* Dynamically allocated buffer */
309  char **dest = (char **) ptr;
310 
311  if (newstring) {
312  if (!*dest || strcmp(*dest, newstring)) {
313  switch_safe_free(*dest);
314  *dest = strdup(newstring);
315  changed = SWITCH_TRUE;
316  }
317  } else {
318  if (*dest) {
319  switch_safe_free(*dest);
320  changed = SWITCH_TRUE;
321  }
322  }
323  }
324  }
325  break;
326  case SWITCH_CONFIG_BOOL:
327  {
328  switch_bool_t *dest = (switch_bool_t *) ptr;
329  switch_bool_t newval = SWITCH_FALSE;
330 
331  if (value && switch_true(value)) {
332  newval = SWITCH_TRUE;
333  } else if (value && switch_false(value)) {
334  newval = SWITCH_FALSE;
335  } else if (value) {
336  /* Value isnt true or false */
337  newval = (switch_bool_t) (intptr_t) item->defaultvalue;
338  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid value [%s] for parameter [%s], setting default [%s]\n",
339  value, item->key, newval ? "true" : "false");
341  } else {
342  newval = (switch_bool_t) (intptr_t) item->defaultvalue;
343  }
344 
345  if (*dest != newval) {
346  *dest = newval;
347  changed = SWITCH_TRUE;
348  }
349  }
350  break;
352  break;
353  case SWITCH_CONFIG_ENUM:
354  {
356  int *dest = (int *) ptr;
357  int newval = 0;
358  switch_status_t lookup_result = SWITCH_STATUS_SUCCESS;
359 
360  if (value) {
361  lookup_result = switch_xml_config_enum_str2int(enum_options, value, &newval);
362  } else {
363  newval = (int) (intptr_t) item->defaultvalue;
364  }
365 
366  if (lookup_result != SWITCH_STATUS_SUCCESS) {
367  newval = (int) (intptr_t) item->defaultvalue;
368  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid value [%s] for parameter [%s]\n", value, item->key);
370  }
371 
372  if (*dest != newval) {
373  changed = SWITCH_TRUE;
374  *dest = newval;
375  }
376  }
377  break;
378  case SWITCH_CONFIG_FLAG:
379  {
380  int32_t *dest = (int32_t *) ptr;
381  int index = (int) (intptr_t) item->data;
382  int8_t currentval = (int8_t) ! !(*dest & index);
383  int newval = 0;
384 
385  if (value) {
386  newval = switch_true(value);
387  } else {
388  newval = (switch_bool_t) (intptr_t) item->defaultvalue;
389  }
390 
391  if (newval != currentval) {
392  changed = SWITCH_TRUE;
393  if (newval) {
394  *dest |= (1 << index);
395  } else {
396  *dest &= ~(1 << index);
397  }
398  }
399  }
400  break;
402  {
403  int8_t *dest = (int8_t *) ptr;
404  unsigned int index = (unsigned int) (intptr_t) item->data;
405  int8_t newval = value ? !!switch_true(value) : (int8_t) ((intptr_t) item->defaultvalue);
406  if (dest[index] != newval) {
407  changed = SWITCH_TRUE;
408  dest[index] = newval;
409  }
410  }
411  break;
412  case SWITCH_CONFIG_LAST:
413  break;
414  default:
415  break;
416  }
417 
418  if (callback) {
419  callback(item, value, (reload ? CONFIG_RELOAD : CONFIG_LOAD), changed);
420  }
421  }
422 
423  if (count != matched_count) {
424  /* User made a mistake, find it */
425  switch_event_header_t *header;
426  for (header = event->headers; header; header = header->next) {
427  switch_bool_t found = SWITCH_FALSE;
428  for (item = instructions; item->key; item++) {
429  if (!strcasecmp(header->name, item->key)) {
430  found = SWITCH_TRUE;
431  break;
432  }
433  }
434 
435  if (!found) {
436  /* Tell the user */
438  "Configuration parameter [%s] is unfortunately not valid, you might want to double-check that.\n", header->name);
439  }
440  }
441  }
442 
443  return SWITCH_STATUS_SUCCESS;
444 }
445 
446 
448 {
450 
451  for (item = instructions; item->key; item++) {
453 
454  switch (item->type) {
456  {
457  char **ptr = (char **) item->ptr;
459  /* if (using_strdup) */
460  if (string_options && !string_options->pool && !string_options->length) {
461  switch_safe_free(*ptr);
462  }
463  }
464  break;
465  default:
466  break;
467  }
468 
469  if (callback) {
470  callback(item, NULL, CONFIG_SHUTDOWN, SWITCH_FALSE);
471  }
472 
473  }
474 }
475 
476 
478  const void *defaultvalue, void *data, switch_xml_config_callback_t function, const char *syntax,
479  const char *helptext)
480 {
481  item->key = key;
482  item->type = type;
483  item->flags = flags;
484  item->ptr = ptr;
485  item->defaultvalue = defaultvalue;
486  item->data = data;
487  item->function = function;
488  item->syntax = syntax;
489  item->helptext = helptext;
490 }
491 
492 
493 /* For Emacs:
494  * Local Variables:
495  * mode:c
496  * indent-tabs-mode:t
497  * tab-width:4
498  * c-basic-offset:4
499  * End:
500  * For VIM:
501  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
502  */
void switch_xml_free(_In_opt_ switch_xml_t xml)
frees the memory allocated for an switch_xml structure
const char * switch_xml_attr_soft(_In_ switch_xml_t xml, _In_z_ const char *attr)
returns the value of the requested tag attribute, or "" if not found
#define SWITCH_CHANNEL_LOG
static switch_xml_config_enum_item_t switch_config_types_enum[]
switch_status_t switch_xml_config_parse_event(switch_event_t *event, int count, switch_bool_t reload, switch_xml_config_item_t *instructions)
Parses all of an event's elements, following a ruleset defined by an array of switch_xml_config_item_...
void switch_xml_config_item_print_doc(int level, switch_xml_config_item_t *item)
Prints out an item's documentation on the console.
switch_bool_t
Definition: switch_types.h:405
#define switch_core_strdup(_pool, _todup)
Copy a string using memory allocation from a given pool.
Definition: switch_core.h:729
void switch_xml_config_cleanup(switch_xml_config_item_t *instructions)
Free any memory allocated by the configuration.
Representation of an event.
Definition: switch_event.h:80
An event Header.
Definition: switch_event.h:65
switch_bool_t switch_is_number(const char *str)
#define SWITCH_DECLARE_DATA
void switch_config_perform_set_item(switch_xml_config_item_t *item, const char *key, switch_xml_config_type_t type, int flags, void *ptr, const void *defaultvalue, void *data, switch_xml_config_callback_t function, const char *syntax, const char *helptext)
A representation of an XML tree.
Definition: switch_xml.h:76
switch_xml_config_type_t type
static int switch_true(const char *expr)
Evaluate the truthfullness of a string expression.
Definition: switch_utils.h:450
#define zstr(x)
Definition: switch_utils.h:281
A configuration instruction read by switch_xml_config_parse.
if((uint32_t)(unpack->cur-unpack->buf) > unpack->buflen)
switch_xml_t next
Definition: switch_xml.h:88
switch_status_t switch_xml_config_parse(switch_xml_t xml, switch_bool_t reload, switch_xml_config_item_t *instructions)
Parses all the xml elements, following a ruleset defined by an array of switch_xml_config_item_t.
switch_xml_config_callback_t function
const char * switch_xml_config_enum_int2str(switch_xml_config_enum_item_t *enum_options, int value)
Gets the string representation of an enum.
void switch_atomic_set(volatile switch_atomic_t *mem, uint32_t val)
Definition: switch_apr.c:1280
switch_status_t switch_event_add_header_string(switch_event_t *event, switch_stack_t stack, const char *header_name, const char *data)
Add a string header to an event.
#define switch_safe_free(it)
Free a pointer and set it to NULL unless it already is NULL.
Definition: switch_utils.h:789
switch_xml_config_string_options_t switch_config_string_strdup
#define SWITCH_CHANNEL_LOG_CLEAN
switch_xml_config_type_t
Type of value to parse.
uintptr_t switch_size_t
char * switch_copy_string(_Out_z_cap_(dst_size) char *dst, _In_z_ const char *src, _In_ switch_size_t dst_size)
uint32_t switch_atomic_t
Definition: switch_apr.h:380
switch_size_t switch_event_import_xml(switch_xml_t xml, const char *keyname, const char *valuename, switch_event_t **event)
Parses a list of xml elements into an event.
switch_status_t
Common return values.
switch_status_t switch_xml_config_enum_str2int(switch_xml_config_enum_item_t *enum_options, const char *value, int *out)
Gets the int representation of an enum.
struct switch_event_header * next
Definition: switch_event.h:76
switch_xml_t switch_xml_open_cfg(_In_z_ const char *file_path, _Out_ switch_xml_t *node, _In_opt_ switch_event_t *params)
open a config in the core registry
Main Library Header.
#define switch_event_create(event, id)
Create a new event assuming it will not be custom event and therefore hiding the unused parameters...
Definition: switch_event.h:383
#define SWITCH_DECLARE(type)
#define switch_event_get_header(_e, _h)
Definition: switch_event.h:172
switch_xml_t switch_xml_child(_In_ switch_xml_t xml, _In_z_ const char *name)
returns the first child tag (one level deeper) with the given name or NULL \ if not found ...
#define switch_test_flag(obj, flag)
Test for the existance of a flag on an arbitary object.
Definition: switch_utils.h:624
void switch_log_printf(_In_ switch_text_channel_t channel, _In_z_ const char *file, _In_z_ const char *func, _In_ int line, _In_opt_z_ const char *userdata, _In_ switch_log_level_t level, _In_z_ _Printf_format_string_ const char *fmt,...) PRINTF_FUNCTION(7
Write log data to the logging engine.
uint32_t switch_atomic_read(volatile switch_atomic_t *mem)
Definition: switch_apr.c:1271
static int switch_false(const char *expr)
Evaluate the falsefullness of a string expression.
Definition: switch_utils.h:482
void switch_event_destroy(switch_event_t **event)
Destroy an event.
#define switch_assert(expr)
switch_status_t(* switch_xml_config_callback_t)(switch_xml_config_item_t *item, const char *newvalue, switch_config_callback_type_t callback_type, switch_bool_t changed)
switch_status_t switch_regex_match(const char *target, const char *expression)
Function to evaluate an expression against a string.
Definition: switch_regex.c:295
switch_status_t switch_xml_config_parse_module_settings(const char *file, switch_bool_t reload, switch_xml_config_item_t *instructions)
Parses a module's settings.