1 /*
2 * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3 * Copyright (C) 2005-2012, 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 * Anthony Minessale II <anthm@freeswitch.org>
21 * Portions created by the Initial Developer are Copyright (C)
22 * the Initial Developer. All Rights Reserved.
23 *
24 * Based on mod_skel by
25 * Anthony Minessale II <anthm@freeswitch.org>
26 *
27 * Contributor(s):
28 *
29 * Daniel Bryars <danb@aeriandi.com>
30 * Tim Brown <tim.brown@aeriandi.com>
31 * Anthony Minessale II <anthm@freeswitch.org>
32 * William King <william.king@quentustech.com>
33 * Mike Jerris <mike@jerris.com>
34 *
35 * kazoo.c -- Sends FreeSWITCH events to an AMQP broker
36 *
37 */
38 
39 #include "mod_kazoo.h"
40 
41 static const char *LOG_LEVEL_NAMES[] = {
42 		"SWITCH_LOG_DEBUG10",
43 		"SWITCH_LOG_DEBUG9",
44 		"SWITCH_LOG_DEBUG8",
45 		"SWITCH_LOG_DEBUG7",
46 		"SWITCH_LOG_DEBUG6",
47 		"SWITCH_LOG_DEBUG5",
48 		"SWITCH_LOG_DEBUG4",
49 		"SWITCH_LOG_DEBUG3",
50 		"SWITCH_LOG_DEBUG2",
51 		"SWITCH_LOG_DEBUG1",
52 		"SWITCH_LOG_DEBUG",
53 		"SWITCH_LOG_INFO",
54 		"SWITCH_LOG_NOTICE",
55 		"SWITCH_LOG_WARNING",
56 		"SWITCH_LOG_ERROR",
57 		"SWITCH_LOG_CRIT",
58 		"SWITCH_LOG_ALERT",
59 		"SWITCH_LOG_CONSOLE",
60 		"SWITCH_LOG_INVALID",
61 		"SWITCH_LOG_UNINIT",
62 		NULL
63 };
64 
65 static const switch_log_level_t LOG_LEVEL_VALUES[] = {
66 		SWITCH_LOG_DEBUG10,
67 		SWITCH_LOG_DEBUG9,
68 		SWITCH_LOG_DEBUG8,
69 		SWITCH_LOG_DEBUG7,
70 		SWITCH_LOG_DEBUG6,
71 		SWITCH_LOG_DEBUG5,
72 		SWITCH_LOG_DEBUG4,
73 		SWITCH_LOG_DEBUG3,
74 		SWITCH_LOG_DEBUG2,
75 		SWITCH_LOG_DEBUG1,
76 		SWITCH_LOG_DEBUG,
77 		SWITCH_LOG_INFO,
78 		SWITCH_LOG_NOTICE,
79 		SWITCH_LOG_WARNING,
80 		SWITCH_LOG_ERROR,
81 		SWITCH_LOG_CRIT,
82 		SWITCH_LOG_ALERT,
83 		SWITCH_LOG_CONSOLE,
84 		SWITCH_LOG_INVALID,
85 		SWITCH_LOG_UNINIT
86 };
87 
log_str2level(const char * str)88 switch_log_level_t log_str2level(const char *str)
89 {
90 	int x = 0;
91 	switch_log_level_t level = SWITCH_LOG_INVALID;
92 
93 	if (switch_is_number(str)) {
94 		x = atoi(str);
95 
96 		if (x > SWITCH_LOG_INVALID) {
97 			return SWITCH_LOG_INVALID - 1;
98 		} else if (x < 0) {
99 			return 0;
100 		} else {
101 			return x;
102 		}
103 	}
104 
105 
106 	for (x = 0;; x++) {
107 		if (!LOG_LEVEL_NAMES[x]) {
108 			break;
109 		}
110 
111 		if (!strcasecmp(LOG_LEVEL_NAMES[x], str)) {
112 			level = LOG_LEVEL_VALUES[x]; //(switch_log_level_t) x;
113 			break;
114 		}
115 	}
116 
117 	return level;
118 }
119 
kazoo_config_loglevels(switch_memory_pool_t * pool,switch_xml_t cfg,kazoo_loglevels_ptr * ptr)120 switch_status_t kazoo_config_loglevels(switch_memory_pool_t *pool, switch_xml_t cfg, kazoo_loglevels_ptr *ptr)
121 {
122 	switch_xml_t xml_level, xml_logging;
123 	kazoo_loglevels_ptr loglevels = (kazoo_loglevels_ptr) switch_core_alloc(pool, sizeof(kazoo_loglevels_t));
124 
125 	loglevels->failed_log_level = SWITCH_LOG_ALERT;
126 	loglevels->filtered_event_log_level = SWITCH_LOG_DEBUG1;
127 	loglevels->filtered_field_log_level = SWITCH_LOG_DEBUG1;
128 	loglevels->info_log_level = SWITCH_LOG_INFO;
129 	loglevels->warn_log_level = SWITCH_LOG_WARNING;
130 	loglevels->success_log_level = SWITCH_LOG_DEBUG;
131 	loglevels->time_log_level = SWITCH_LOG_DEBUG1;
132 	loglevels->trace_log_level = SWITCH_LOG_DEBUG1;
133 	loglevels->debug_log_level = SWITCH_LOG_DEBUG;
134 	loglevels->error_log_level = SWITCH_LOG_ERROR;
135 	loglevels->hashing_log_level = SWITCH_LOG_DEBUG1;
136 
137 	if ((xml_logging = switch_xml_child(cfg, "logging")) != NULL) {
138 		for (xml_level = switch_xml_child(xml_logging, "log"); xml_level; xml_level = xml_level->next) {
139 			char *var = (char *) switch_xml_attr_soft(xml_level, "name");
140 			char *val = (char *) switch_xml_attr_soft(xml_level, "value");
141 
142 			if (!var) {
143 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "logging param missing 'name' attribute\n");
144 				continue;
145 			}
146 
147 			if (!val) {
148 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "logging param[%s] missing 'value' attribute\n", var);
149 				continue;
150 			}
151 
152 			if (!strncmp(var, "success", 7)) {
153 				loglevels->success_log_level = log_str2level(val);
154 			} else if (!strncmp(var, "failed", 6)) {
155 				loglevels->failed_log_level = log_str2level(val);
156 			} else if (!strncmp(var, "info", 4)) {
157 				loglevels->info_log_level = log_str2level(val);
158 			} else if (!strncmp(var, "warn", 4)) {
159 				loglevels->warn_log_level = log_str2level(val);
160 			} else if (!strncmp(var, "time", 4)) {
161 				loglevels->time_log_level = log_str2level(val);
162 			} else if (!strncmp(var, "filtered-event", 14)) {
163 				loglevels->filtered_event_log_level = log_str2level(val);
164 			} else if (!strncmp(var, "filtered-field", 14)) {
165 				loglevels->filtered_field_log_level = log_str2level(val);
166 			} else if (!strncmp(var, "trace", 5)) {
167 				loglevels->trace_log_level = log_str2level(val);
168 			} else if (!strncmp(var, "debug", 5)) {
169 				loglevels->debug_log_level = log_str2level(val);
170 			} else if (!strncmp(var, "error", 5)) {
171 				loglevels->error_log_level = log_str2level(val);
172 			} else if (!strncmp(var, "hashing", 7)) {
173 				loglevels->hashing_log_level = log_str2level(val);
174 			}
175 		} /* xml_level for loop */
176 	}
177 
178 	*ptr = loglevels;
179 	return SWITCH_STATUS_SUCCESS;
180 
181 }
182 
kazoo_config_filters(switch_memory_pool_t * pool,switch_xml_t cfg,kazoo_filter_ptr * ptr)183 switch_status_t kazoo_config_filters(switch_memory_pool_t *pool, switch_xml_t cfg, kazoo_filter_ptr *ptr)
184 {
185 	switch_xml_t filters, filter;
186 //	char *routing_key = NULL;
187 	kazoo_filter_ptr root = NULL, prv = NULL, cur = NULL;
188 
189 
190 	if ((filters = switch_xml_child(cfg, "filters")) != NULL) {
191 		for (filter = switch_xml_child(filters, "filter"); filter; filter = filter->next) {
192 			const char *var = switch_xml_attr(filter, "name");
193 			const char *val = switch_xml_attr(filter, "value");
194 			const char *type = switch_xml_attr(filter, "type");
195 			const char *compare = switch_xml_attr(filter, "compare");
196 			cur = (kazoo_filter_ptr) switch_core_alloc(pool, sizeof(kazoo_filter));
197 			memset(cur, 0, sizeof(kazoo_filter));
198 			if(prv == NULL) {
199 				root = prv = cur;
200 			} else {
201 				prv->next = cur;
202 				prv = cur;
203 			}
204 			cur->type = FILTER_EXCLUDE;
205 			cur->compare = FILTER_COMPARE_VALUE;
206 
207 			if(var)
208 				cur->name = switch_core_strdup(pool, var);
209 
210 			if(val)
211 				cur->value = switch_core_strdup(pool, val);
212 
213 			if(type) {
214 				if (!strncmp(type, "exclude", 7)) {
215 					cur->type = FILTER_EXCLUDE;
216 				} else if (!strncmp(type, "include", 7)) {
217 						cur->type = FILTER_INCLUDE;
218 				}
219 			}
220 
221 			if(compare) {
222 				if (!strncmp(compare, "value", 7)) {
223 					cur->compare = FILTER_COMPARE_VALUE;
224 				} else if (!strncmp(compare, "prefix", 6)) {
225 						cur->compare = FILTER_COMPARE_PREFIX;
226 				} else if (!strncmp(compare, "list", 4)) {
227 						cur->compare = FILTER_COMPARE_LIST;
228 				} else if (!strncmp(compare, "exists", 6)) {
229 						cur->compare = FILTER_COMPARE_EXISTS;
230 				} else if (!strncmp(compare, "regex", 5)) {
231 						cur->compare = FILTER_COMPARE_REGEX;
232 				} else if (!strncmp(compare, "field", 5)) {
233 						cur->compare = FILTER_COMPARE_FIELD;
234 				}
235 			}
236 
237 			if(cur->value == NULL)
238 				cur->compare = FILTER_COMPARE_EXISTS;
239 
240 			if(cur->compare == FILTER_COMPARE_LIST) {
241 				cur->list.size = switch_separate_string(cur->value, '|', cur->list.value, MAX_LIST_FIELDS);
242 			}
243 
244 		}
245 
246 	}
247 
248 	*ptr = root;
249 
250 	return SWITCH_STATUS_SUCCESS;
251 
252 }
253 
kazoo_config_field(kazoo_config_ptr definitions,switch_memory_pool_t * pool,switch_xml_t cfg,kazoo_field_ptr * ptr)254 switch_status_t kazoo_config_field(kazoo_config_ptr definitions, switch_memory_pool_t *pool, switch_xml_t cfg, kazoo_field_ptr *ptr)
255 {
256 	const char *var = switch_xml_attr(cfg, "name");
257 	const char *val = switch_xml_attr(cfg, "value");
258 	const char *as = switch_xml_attr(cfg, "as");
259 	const char *type = switch_xml_attr(cfg, "type");
260 	const char *exclude_prefix = switch_xml_attr(cfg, "exclude-prefix");
261 	const char *serialize_as = switch_xml_attr(cfg, "serialize-as");
262 	const char *as_array = switch_xml_attr(cfg, "as-array");
263 	kazoo_field_ptr cur = (kazoo_field_ptr) switch_core_alloc(pool, sizeof(kazoo_field));
264 	cur->in_type = FIELD_NONE;
265 	cur->out_type = JSON_NONE;
266 
267 	if(var)
268 		cur->name = switch_core_strdup(pool, var);
269 
270 	if(val)
271 		cur->value = switch_core_strdup(pool, val);
272 
273 	if(as)
274 		cur->as = switch_core_strdup(pool, as);
275 
276 	if(type) {
277 		if (!strncmp(type, "copy", 4)) {
278 			cur->in_type = FIELD_COPY;
279 		} else if (!strncmp(type, "static", 6)) {
280 			cur->in_type = FIELD_STATIC;
281 		} else if (!strncmp(type, "first-of", 8)) {
282 			cur->in_type = FIELD_FIRST_OF;
283 		} else if (!strncmp(type, "expand", 6)) {
284 			cur->in_type = FIELD_EXPAND;
285 		} else if (!strncmp(type, "prefix", 10)) {
286 			cur->in_type = FIELD_PREFIX;
287 		} else if (!strncmp(type, "group", 5)) {
288 			cur->in_type = FIELD_GROUP;
289 		} else if (!strncmp(type, "reference", 9)) {
290 			cur->in_type = FIELD_REFERENCE;
291 		}
292 	}
293 
294 	if(serialize_as) {
295 		if (!strncmp(serialize_as, "string", 5)) {
296 			cur->out_type = JSON_STRING;
297 		} else if (!strncmp(serialize_as, "number", 6)) {
298 			cur->out_type = JSON_NUMBER;
299 		} else if (!strncmp(serialize_as, "boolean", 7)) {
300 			cur->out_type = JSON_BOOLEAN;
301 		} else if (!strncmp(serialize_as, "object", 6)) {
302 			cur->out_type = JSON_OBJECT;
303 		} else if (!strncmp(serialize_as, "raw", 6)) {
304 			cur->out_type = JSON_RAW;
305 		}
306 	}
307 
308 	if(as_array) {
309 		cur->out_type_as_array = switch_true(as_array);
310 	}
311 
312 	if(exclude_prefix)
313 		cur->exclude_prefix = switch_true(exclude_prefix);
314 
315 	kazoo_config_filters(pool, cfg, &cur->filter);
316 	kazoo_config_fields(definitions, pool, cfg, &cur->children);
317 
318 	if(cur->children != NULL
319 			&& (cur->in_type == FIELD_STATIC)
320 			&& (cur->out_type == JSON_NONE)
321 			) {
322 		cur->out_type = JSON_OBJECT;
323 	}
324 	if(cur->in_type == FIELD_NONE) {
325 		cur->in_type = FIELD_COPY;
326 	}
327 
328 	if(cur->out_type == JSON_NONE) {
329 		cur->out_type = JSON_STRING;
330 	}
331 
332 	if(cur->in_type == FIELD_FIRST_OF) {
333 		cur->list.size = switch_separate_string(cur->value, '|', cur->list.value, MAX_LIST_FIELDS);
334 	}
335 
336 	if(cur->in_type == FIELD_REFERENCE) {
337 		cur->ref = (kazoo_definition_ptr)switch_core_hash_find(definitions->hash, cur->name);
338 		if(cur->ref == NULL) {
339 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "referenced field %s not found\n", cur->name);
340 		}
341 	}
342 
343 	*ptr = cur;
344 
345 	return SWITCH_STATUS_SUCCESS;
346 
347 }
348 
kazoo_config_fields_loop(kazoo_config_ptr definitions,switch_memory_pool_t * pool,switch_xml_t cfg,kazoo_field_ptr * ptr)349 switch_status_t kazoo_config_fields_loop(kazoo_config_ptr definitions, switch_memory_pool_t *pool, switch_xml_t cfg, kazoo_field_ptr *ptr)
350 {
351 	switch_xml_t field;
352 	kazoo_field_ptr root = NULL, prv = NULL;
353 
354 
355 	for (field = switch_xml_child(cfg, "field"); field; field = field->next) {
356 		kazoo_field_ptr cur = NULL;
357 		kazoo_config_field(definitions, pool, field, &cur);
358 		if(root == NULL) {
359 			root = prv = cur;
360 		} else {
361 			prv->next = cur;
362 			prv = cur;
363 		}
364 	}
365 
366 	*ptr = root;
367 
368 	return SWITCH_STATUS_SUCCESS;
369 
370 }
371 
kazoo_config_fields(kazoo_config_ptr definitions,switch_memory_pool_t * pool,switch_xml_t cfg,kazoo_fields_ptr * ptr)372 switch_status_t kazoo_config_fields(kazoo_config_ptr definitions, switch_memory_pool_t *pool, switch_xml_t cfg, kazoo_fields_ptr *ptr)
373 {
374 	switch_xml_t fields;
375 	kazoo_fields_ptr root = NULL;
376 
377 
378 	if ((fields = switch_xml_child(cfg, "fields")) != NULL) {
379 		const char *verbose = switch_xml_attr(fields, "verbose");
380 		root = (kazoo_fields_ptr) switch_core_alloc(pool, sizeof(kazoo_fields));
381 		root->verbose = SWITCH_TRUE;
382 		if(verbose) {
383 			root->verbose = switch_true(verbose);
384 		}
385 
386 		kazoo_config_fields_loop(definitions, pool, fields, &root->head);
387 
388 	}
389 
390 	*ptr = root;
391 
392 	return SWITCH_STATUS_SUCCESS;
393 
394 }
395 
kazoo_config_event_handlers(kazoo_config_ptr definitions,switch_xml_t cfg)396 kazoo_config_ptr kazoo_config_event_handlers(kazoo_config_ptr definitions, switch_xml_t cfg)
397 {
398 	switch_xml_t xml_profiles = NULL, xml_profile = NULL;
399 	kazoo_config_ptr profiles = NULL;
400 	switch_memory_pool_t *pool = NULL;
401 
402 	if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
403 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "error creating memory pool for producers\n");
404 		return NULL;
405 	}
406 
407 	profiles = switch_core_alloc(pool, sizeof(kazoo_config));
408 	profiles->pool = pool;
409 	switch_core_hash_init(&profiles->hash);
410 
411 	if ((xml_profiles = switch_xml_child(cfg, "event-handlers"))) {
412 		if ((xml_profile = switch_xml_child(xml_profiles, "profile"))) {
413 			for (; xml_profile; xml_profile = xml_profile->next) {
414 				const char *name = switch_xml_attr(xml_profile, "name");
415 				if(name == NULL) {
416 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "missing attr name\n" );
417 					continue;
418 				}
419 				kazoo_config_event_handler(definitions, profiles, xml_profile, NULL);
420 			}
421 		} else {
422 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "unable to locate a event-handler profile for kazoo\n" );
423 		}
424 	} else {
425 		destroy_config(&profiles);
426 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "unable to locate event-handlers section for kazoo, using default\n" );
427 	}
428 
429 	return profiles;
430 
431 }
432 
kazoo_config_fetch_handlers(kazoo_config_ptr definitions,switch_xml_t cfg)433 kazoo_config_ptr kazoo_config_fetch_handlers(kazoo_config_ptr definitions, switch_xml_t cfg)
434 {
435 	switch_xml_t xml_profiles = NULL, xml_profile = NULL;
436 	kazoo_config_ptr profiles = NULL;
437 	switch_memory_pool_t *pool = NULL;
438 
439 	if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
440 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "error creating memory pool for producers\n");
441 		return NULL;
442 	}
443 
444 	profiles = switch_core_alloc(pool, sizeof(kazoo_config));
445 	profiles->pool = pool;
446 	switch_core_hash_init(&profiles->hash);
447 
448 	if ((xml_profiles = switch_xml_child(cfg, "fetch-handlers"))) {
449 		if ((xml_profile = switch_xml_child(xml_profiles, "profile"))) {
450 			for (; xml_profile; xml_profile = xml_profile->next) {
451 				const char *name = switch_xml_attr(xml_profile, "name");
452 				if(name == NULL) {
453 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "missing attr name\n" );
454 					continue;
455 				}
456 				kazoo_config_fetch_handler(definitions, profiles, xml_profile, NULL);
457 			}
458 		} else {
459 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "unable to locate a fetch-handler profile for kazoo\n" );
460 		}
461 	} else {
462 		destroy_config(&profiles);
463 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "unable to locate fetch-handlers section for kazoo, using default\n" );
464 	}
465 
466 	return profiles;
467 
468 }
469 
470 
kazoo_config_definition(kazoo_config_ptr root,switch_xml_t cfg)471 switch_status_t kazoo_config_definition(kazoo_config_ptr root, switch_xml_t cfg)
472 {
473 	kazoo_definition_ptr definition = NULL;
474 	char *name = (char *) switch_xml_attr_soft(cfg, "name");
475 
476 	if (zstr(name)) {
477 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to load kazoo profile, check definition missing name attr\n");
478 		return SWITCH_STATUS_GENERR;
479 	}
480 
481 	definition = switch_core_alloc(root->pool, sizeof(kazoo_definition));
482 	definition->name = switch_core_strdup(root->pool, name);
483 
484 	kazoo_config_filters(root->pool, cfg, &definition->filter);
485 	kazoo_config_fields_loop(root, root->pool, cfg, &definition->head);
486 
487 	if ( switch_core_hash_insert(root->hash, name, (void *) definition) != SWITCH_STATUS_SUCCESS) {
488 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to insert new definition [%s] into kazoo definitions hash\n", name);
489 		return SWITCH_STATUS_GENERR;
490 	}
491 
492 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "definition[%s] successfully configured\n", definition->name);
493 	return SWITCH_STATUS_SUCCESS;
494 }
495 
kazoo_config_definitions(switch_xml_t cfg)496 kazoo_config_ptr kazoo_config_definitions(switch_xml_t cfg)
497 {
498 	switch_xml_t xml_definitions = NULL, xml_definition = NULL;
499 	kazoo_config_ptr definitions = NULL;
500 	switch_memory_pool_t *pool = NULL;
501 
502 	if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
503 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "error creating memory pool for definitions\n");
504 		return NULL;
505 	}
506 
507 	definitions = switch_core_alloc(pool, sizeof(kazoo_config));
508 	definitions->pool = pool;
509 	switch_core_hash_init(&definitions->hash);
510 
511 	if ((xml_definitions = switch_xml_child(cfg, "definitions"))) {
512 		if ((xml_definition = switch_xml_child(xml_definitions, "definition"))) {
513 			for (; xml_definition; xml_definition = xml_definition->next)	{
514 				kazoo_config_definition(definitions, xml_definition);
515 			}
516 		} else {
517 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "no definitions for kazoo\n" );
518 		}
519 	} else {
520 		destroy_config(&definitions);
521 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "unable to locate definitions section for kazoo, using default\n" );
522 	}
523 
524 	return definitions;
525 }
526 
destroy_config(kazoo_config_ptr * ptr)527 void destroy_config(kazoo_config_ptr *ptr)
528 {
529 	kazoo_config_ptr config = NULL;
530 	switch_memory_pool_t *pool;
531 
532 	if (!ptr || !*ptr) {
533 		return;
534 	}
535 	config = *ptr;
536 	pool = config->pool;
537 
538 	switch_core_hash_destroy(&(config->hash));
539 	switch_core_destroy_memory_pool(&pool);
540 
541 	*ptr = NULL;
542 }
543 
544 /* For Emacs:
545  * Local Variables:
546  * mode:c
547  * indent-tabs-mode:t
548  * tab-width:4
549  * c-basic-offset:4
550  * End:
551  * For VIM:
552  * vim:set softtabstop=4 shiftwidth=4 tabstop=4
553  */
554