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