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 #define KZ_DEFAULT_STREAM_PRE_ALLOCATE 8192
42 
43 #define KAZOO_DECLARE_GLOBAL_STRING_FUNC(fname, vname) static void __attribute__((__unused__)) fname(const char *string) { if (!string) return;\
44 		if (vname) {free(vname); vname = NULL;}vname = strdup(string);} static void fname(const char *string)
45 
46 KAZOO_DECLARE_GLOBAL_STRING_FUNC(set_pref_ip, kazoo_globals.ip);
47 KAZOO_DECLARE_GLOBAL_STRING_FUNC(set_pref_ei_cookie, kazoo_globals.ei_cookie);
48 KAZOO_DECLARE_GLOBAL_STRING_FUNC(set_pref_ei_nodename, kazoo_globals.ei_nodename);
49 //KAZOO_DECLARE_GLOBAL_STRING_FUNC(set_pref_kazoo_var_prefix, kazoo_globals.kazoo_var_prefix);
50 
read_cookie_from_file(char * filename)51 static int read_cookie_from_file(char *filename) {
52 	int fd;
53 	char cookie[MAXATOMLEN + 1];
54 	char *end;
55 	struct stat buf;
56 	ssize_t res;
57 
58 	if (!stat(filename, &buf)) {
59 		if ((buf.st_mode & S_IRWXG) || (buf.st_mode & S_IRWXO)) {
60 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s must only be accessible by owner only.\n", filename);
61 			return 2;
62 		}
63 		if (buf.st_size > MAXATOMLEN) {
64 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s contains a cookie larger than the maximum atom size of %d.\n", filename, MAXATOMLEN);
65 			return 2;
66 		}
67 		fd = open(filename, O_RDONLY);
68 		if (fd < 1) {
69 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to open cookie file %s : %d.\n", filename, errno);
70 			return 2;
71 		}
72 
73 		if ((res = read(fd, cookie, MAXATOMLEN)) < 1) {
74 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to read cookie file %s : %d.\n", filename, errno);
75 		}
76 
77 		cookie[MAXATOMLEN] = '\0';
78 
79 		/* replace any end of line characters with a null */
80 		if ((end = strchr(cookie, '\n'))) {
81 			*end = '\0';
82 		}
83 
84 		if ((end = strchr(cookie, '\r'))) {
85 			*end = '\0';
86 		}
87 
88 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set cookie from file %s: %s\n", filename, cookie);
89 
90 		set_pref_ei_cookie(cookie);
91 		return 0;
92 	} else {
93 		/* don't error here, because we might be blindly trying to read $HOME/.erlang.cookie, and that can fail silently */
94 		return 1;
95 	}
96 }
97 
kz_set_hostname()98 void kz_set_hostname()
99 {
100 	if (kazoo_globals.hostname == NULL) {
101 		char hostname[NODENAME_MAX];
102 		memcpy(hostname, switch_core_get_hostname(), NODENAME_MAX);
103 		kazoo_globals.hostname_ent = gethostbyname(hostname);
104 		if(kazoo_globals.hostname_ent != NULL) {
105 			kazoo_globals.hostname = switch_core_strdup(kazoo_globals.pool, kazoo_globals.hostname_ent->h_name);
106 		} else {
107 			kazoo_globals.hostname = switch_core_strdup(kazoo_globals.pool, hostname);
108 		}
109 	}
110 }
111 
kazoo_ei_config(switch_xml_t cfg)112 switch_status_t kazoo_ei_config(switch_xml_t cfg) {
113 	switch_xml_t child, param;
114 	char* kazoo_var_prefix = NULL;
115 	char* profile_vars_prefix = NULL;
116 	char* sep_array[KZ_MAX_SEPARATE_STRINGS];
117 	int array_len, i;
118 	kazoo_globals.send_all_headers = 0;
119 	kazoo_globals.send_all_private_headers = 1;
120 	kazoo_globals.connection_timeout = 500;
121 	kazoo_globals.ei_receive_timeout = 200;
122 	kazoo_globals.receive_msg_preallocate = 2000;
123 	kazoo_globals.event_stream_preallocate = KZ_DEFAULT_STREAM_PRE_ALLOCATE;
124 	kazoo_globals.send_msg_batch = 10;
125 	kazoo_globals.event_stream_framing = 2;
126 	kazoo_globals.event_stream_keepalive = 1;
127 	kazoo_globals.event_stream_queue_timeout = 200000;
128 	kazoo_globals.node_receiver_queue_timeout = 100000;
129 	kazoo_globals.node_sender_queue_timeout = 0;
130 	kazoo_globals.port = 0;
131 	kazoo_globals.io_fault_tolerance = 3;
132 	kazoo_globals.io_fault_tolerance_sleep = 100000; // 100 ms
133 	kazoo_globals.json_encoding = ERLANG_TUPLE;
134 	kazoo_globals.delay_before_initial_fetch = 10000000;
135 
136 	kazoo_globals.legacy_events = SWITCH_FALSE;
137 	kazoo_globals.expand_headers_on_fetch = SWITCH_TRUE;
138 
139 	kz_set_tweak(KZ_TWEAK_INTERACTION_ID);
140 	kz_set_tweak(KZ_TWEAK_EXPORT_VARS);
141 	kz_set_tweak(KZ_TWEAK_SWITCH_URI);
142 	kz_set_tweak(KZ_TWEAK_REPLACES_CALL_ID);
143 	kz_set_tweak(KZ_TWEAK_LOOPBACK_VARS);
144 	kz_set_tweak(KZ_TWEAK_CALLER_ID);
145 	kz_set_tweak(KZ_TWEAK_TRANSFERS);
146 	kz_set_tweak(KZ_TWEAK_BRIDGE);
147 	kz_set_tweak(KZ_TWEAK_BRIDGE_REPLACES_ALEG);
148 	kz_set_tweak(KZ_TWEAK_BRIDGE_REPLACES_CALL_ID);
149 	kz_set_tweak(KZ_TWEAK_BRIDGE_VARIABLES);
150 	kz_set_tweak(KZ_TWEAK_RESTORE_CALLER_ID_ON_BLIND_XFER);
151 
152 
153 
154 	if ((child = switch_xml_child(cfg, "settings"))) {
155 		for (param = switch_xml_child(child, "param"); param; param = param->next) {
156 			char *var = (char *) switch_xml_attr_soft(param, "name");
157 			char *val = (char *) switch_xml_attr_soft(param, "value");
158 
159 			if (!strcmp(var, "listen-ip")) {
160 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set bind ip address: %s\n", val);
161 				set_pref_ip(val);
162 			} else if (!strcmp(var, "listen-port")) {
163 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set bind port: %s\n", val);
164 				kazoo_globals.port = atoi(val);
165 			} else if (!strcmp(var, "cookie")) {
166 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set cookie: %s\n", val);
167 				set_pref_ei_cookie(val);
168 			} else if (!strcmp(var, "cookie-file")) {
169 				if (read_cookie_from_file(val) == 1) {
170 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to read cookie from %s\n", val);
171 				}
172 			} else if (!strcmp(var, "nodename")) {
173 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set node name: %s\n", val);
174 				set_pref_ei_nodename(val);
175 			} else if (!strcmp(var, "shortname")) {
176 				kazoo_globals.ei_shortname = switch_true(val);
177 			} else if (!strcmp(var, "kazoo-var-prefix")) {
178 				kazoo_var_prefix = switch_core_strdup(kazoo_globals.pool, val);
179 			} else if (!strcmp(var, "set-profile-vars-prefix")) {
180 				profile_vars_prefix = switch_core_strdup(kazoo_globals.pool, val);
181 			} else if (!strcmp(var, "compat-rel")) {
182 				if (atoi(val) >= 7)
183 					kazoo_globals.ei_compat_rel = atoi(val);
184 				else
185 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid compatibility release '%s' specified\n", val);
186 			} else if (!strcmp(var, "nat-map")) {
187 				kazoo_globals.nat_map = switch_true(val);
188 			} else if (!strcmp(var, "send-all-headers")) {
189 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set send-all-headers: %s\n", val);
190 				kazoo_globals.send_all_headers = switch_true(val);
191 			} else if (!strcmp(var, "send-all-private-headers")) {
192 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set send-all-private-headers: %s\n", val);
193 				kazoo_globals.send_all_private_headers = switch_true(val);
194 			} else if (!strcmp(var, "connection-timeout")) {
195 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set connection-timeout: %s\n", val);
196 				kazoo_globals.connection_timeout = atoi(val);
197 			} else if (!strcmp(var, "receive-timeout")) {
198 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set receive-timeout: %s\n", val);
199 				kazoo_globals.ei_receive_timeout = atoi(val);
200 			} else if (!strcmp(var, "receive-msg-preallocate")) {
201 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set receive-msg-preallocate: %s\n", val);
202 				kazoo_globals.receive_msg_preallocate = atoi(val);
203 			} else if (!strcmp(var, "event-stream-preallocate")) {
204 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set event-stream-preallocate: %s\n", val);
205 				kazoo_globals.event_stream_preallocate = atoi(val);
206 			} else if (!strcmp(var, "send-msg-batch-size")) {
207 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set send-msg-batch-size: %s\n", val);
208 				kazoo_globals.send_msg_batch = atoi(val);
209 			} else if (!strcmp(var, "event-stream-framing")) {
210 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set event-stream-framing: %s\n", val);
211 				kazoo_globals.event_stream_framing = atoi(val);
212 
213 			} else if (!strcmp(var, "event-stream-keep-alive")) {
214 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set event-stream-keep-alive: %s\n", val);
215 				kazoo_globals.event_stream_keepalive = switch_true(val);
216 
217 			} else if (!strcmp(var, "io-fault-tolerance")) {
218 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set io-fault-tolerance: %s\n", val);
219 				kazoo_globals.io_fault_tolerance = atoi(val);
220 			} else if (!strcmp(var, "io-fault-tolerance-sleep-micro")) {
221 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set %s : %s\n", var, val);
222 				kazoo_globals.io_fault_tolerance_sleep = atoi(val);
223 			} else if (!strcmp(var, "io-fault-tolerance-sleep-ms")) {
224 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set %s : %s\n", var, val);
225 				kazoo_globals.io_fault_tolerance_sleep = atoi(val) * 1000;
226 			} else if (!strcmp(var, "io-fault-tolerance-sleep-sec")) {
227 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set %s : %s\n", var, val);
228 				kazoo_globals.io_fault_tolerance_sleep = atoi(val) * 1000000;
229 
230 
231 			} else if (!strcmp(var, "node-worker-threads")) {
232 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set node-worker-threads: %s\n", val);
233 				kazoo_globals.node_worker_threads = atoi(val);
234 			} else if (!strcmp(var, "json-term-encoding")) {
235 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set json-term-encoding: %s\n", val);
236 				if(!strcmp(val, "map")) {
237 					kazoo_globals.json_encoding = ERLANG_MAP;
238 				}
239 			} else if (!strcmp(var, "legacy-events")) {
240 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set legacy-events: %s\n", val);
241 				kazoo_globals.legacy_events = switch_true(val);
242 			} else if (!strcmp(var, "expand-headers-on-fetch")) {
243 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set expand-headers-on-fetch: %s\n", val);
244 				kazoo_globals.expand_headers_on_fetch = switch_true(val);
245 			} else if (!strcmp(var, "node-receiver-queue-timeout")) {
246 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set %s : %s\n", var, val);
247 				kazoo_globals.node_receiver_queue_timeout = atoi(val);
248 			} else if (!strcmp(var, "node-sender-queue-timeout")) {
249 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set %s : %s\n", var, val);
250 				kazoo_globals.node_sender_queue_timeout = atoi(val);
251 			} else if (!strcmp(var, "event-stream-queue-timeout")) {
252 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set %s : %s\n", var, val);
253 				kazoo_globals.event_stream_queue_timeout = atoi(val);
254 			} else if (!strcmp(var, "delay-before-initial-fetch-micro")) {
255 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set %s : %s\n", var, val);
256 				kazoo_globals.delay_before_initial_fetch = atoi(val);
257 			} else if (!strcmp(var, "delay-before-initial-fetch-ms")) {
258 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set %s : %s\n", var, val);
259 				kazoo_globals.delay_before_initial_fetch = atoi(val) * 1000;
260 			} else if (!strcmp(var, "delay-before-initial-fetch-sec")) {
261 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set %s : %s\n", var, val);
262 				kazoo_globals.delay_before_initial_fetch = atoi(val) * 1000000;
263 			} else {
264 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "unknown config option %s : %s\n", var, val);
265 			}
266 		}
267 	}
268 
269 	if ((child = switch_xml_child(cfg, "tweaks"))) {
270 		char *default_tweaks = (char *) switch_xml_attr_soft(child, "default");
271 		if (default_tweaks && !zstr(default_tweaks)) {
272 			int i, v = switch_true(default_tweaks) ? 1 : 0;
273 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set tweak default : %s\n", default_tweaks);
274 			for (i = 0; i < KZ_TWEAK_MAX; i++) kazoo_globals.tweaks[i] = v;
275 		}
276 		for (param = switch_xml_child(child, "tweak"); param; param = param->next) {
277 			kz_tweak_t tweak = KZ_TWEAK_MAX;
278 			char *var = (char *) switch_xml_attr_soft(param, "name");
279 			char *val = (char *) switch_xml_attr_soft(param, "value");
280 			if(var && val && kz_name_tweak(var, &tweak) == SWITCH_STATUS_SUCCESS) {
281 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set tweak %s : %s\n", var, val);
282 				if(switch_true(val)) {
283 					kz_set_tweak(tweak);
284 				} else {
285 					kz_clear_tweak(tweak);
286 				}
287 			}
288 		}
289 	}
290 
291 	if ((child = switch_xml_child(cfg, "variables"))) {
292 		for (param = switch_xml_child(child, "variable"); param; param = param->next) {
293 			char *var = (char *) switch_xml_attr_soft(param, "name");
294 			char *val = (char *) switch_xml_attr_soft(param, "value");
295 			if(var && val) {
296 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set core variable %s : %s\n", var, val);
297 				switch_core_set_variable(var, val);
298 			}
299 		}
300 	}
301 
302 	if ((child = switch_xml_child(cfg, "event-filter"))) {
303 		switch_hash_t *filter;
304 
305 		switch_core_hash_init(&filter);
306 		for (param = switch_xml_child(child, "header"); param; param = param->next) {
307 			char *var = (char *) switch_xml_attr_soft(param, "name");
308 			switch_core_hash_insert(filter, var, "1");
309 		}
310 		kazoo_globals.event_filter = filter;
311 	}
312 
313 	if (kazoo_globals.receive_msg_preallocate < 0) {
314 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid receive message preallocate value, disabled\n");
315 		kazoo_globals.receive_msg_preallocate = 0;
316 	}
317 
318 	if (kazoo_globals.event_stream_preallocate < 0) {
319 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid event stream preallocate value, disabled\n");
320 		kazoo_globals.event_stream_preallocate = 0;
321 	}
322 
323 	if (kazoo_globals.send_msg_batch < 1) {
324 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid send message batch size, reverting to default\n");
325 		kazoo_globals.send_msg_batch = 10;
326 	}
327 
328 	if (kazoo_globals.io_fault_tolerance < 1) {
329 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid I/O fault tolerance, reverting to default\n");
330 		kazoo_globals.io_fault_tolerance = 10;
331 	}
332 
333 	if (!kazoo_globals.event_filter) {
334 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Event filter not found in configuration, using default\n");
335 		kazoo_globals.event_filter = create_default_filter();
336 	}
337 
338 	if (kazoo_globals.event_stream_framing < 1 || kazoo_globals.event_stream_framing > 4) {
339 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid event stream framing value, using default\n");
340 		kazoo_globals.event_stream_framing = 2;
341 	}
342 
343 	if (zstr(kazoo_var_prefix)) {
344 		kazoo_var_prefix = switch_core_strdup(kazoo_globals.pool, "ecallmgr_;cav_");
345 	}
346 
347 	if (zstr(profile_vars_prefix)) {
348 		profile_vars_prefix = switch_core_strdup(kazoo_globals.pool, "effective_;origination_");
349 	}
350 
351 	kazoo_globals.kazoo_var_prefixes = switch_core_alloc(kazoo_globals.pool, sizeof(char*) * KZ_MAX_SEPARATE_STRINGS);
352 	array_len = switch_separate_string(kazoo_var_prefix, ';', sep_array, KZ_MAX_SEPARATE_STRINGS - 1);
353 	for(i=0; i < array_len; i++) {
354 		char var[100];
355 		sprintf(var, "variable_%s", sep_array[i]);
356 		kazoo_globals.kazoo_var_prefixes[i] = switch_core_strdup(kazoo_globals.pool, var);
357 	}
358 
359 	kazoo_globals.profile_vars_prefixes = switch_core_alloc(kazoo_globals.pool, sizeof(char*) * KZ_MAX_SEPARATE_STRINGS);
360 	array_len = switch_separate_string(profile_vars_prefix, ';', sep_array, KZ_MAX_SEPARATE_STRINGS - 1);
361 	for(i=0; i < array_len; i++) {
362 		kazoo_globals.profile_vars_prefixes[i] = switch_core_strdup(kazoo_globals.pool, sep_array[i]);
363 	}
364 
365 	if (!kazoo_globals.node_worker_threads) {
366 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Number of node worker threads not found in configuration, using default\n");
367 		kazoo_globals.node_worker_threads = 10;
368 	}
369 
370 	if (zstr(kazoo_globals.ip)) {
371 		set_pref_ip("0.0.0.0");
372 	}
373 
374 	if (zstr(kazoo_globals.ei_cookie)) {
375 		int res;
376 		char *home_dir = getenv("HOME");
377 		char path_buf[1024];
378 
379 		if (!zstr(home_dir)) {
380 			/* $HOME/.erlang.cookie */
381 			switch_snprintf(path_buf, sizeof (path_buf), "%s%s%s", home_dir, SWITCH_PATH_SEPARATOR, ".erlang.cookie");
382 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Checking for cookie at path: %s\n", path_buf);
383 
384 			res = read_cookie_from_file(path_buf);
385 			if (res) {
386 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No cookie or valid cookie file specified, using default cookie\n");
387 				set_pref_ei_cookie("ClueCon");
388 			}
389 		}
390 	}
391 
392 	if (!kazoo_globals.ei_nodename) {
393 		set_pref_ei_nodename("freeswitch");
394 	}
395 
396 	if (!kazoo_globals.nat_map) {
397 		kazoo_globals.nat_map = 0;
398 	}
399 
400 	return SWITCH_STATUS_SUCCESS;
401 }
402 
kazoo_config_handlers(switch_xml_t cfg)403 switch_status_t kazoo_config_handlers(switch_xml_t cfg)
404 {
405 		switch_xml_t def = NULL;
406 		switch_xml_t child, param;
407 		char* xml = NULL;
408 		kazoo_config_ptr definitions = NULL, fetch_handlers = NULL, event_handlers = NULL;
409 		kazoo_event_profile_ptr events = NULL;
410 
411 		xml = strndup(kz_default_config, kz_default_config_size);
412 		def = switch_xml_parse_str_dup(xml);
413 
414 		kz_xml_process(def);
415 		kz_xml_process(cfg);
416 
417 		if ((child = switch_xml_child(cfg, "variables"))) {
418 			for (param = switch_xml_child(child, "variable"); param; param = param->next) {
419 				char *var = (char *) switch_xml_attr_soft(param, "name");
420 				char *val = (char *) switch_xml_attr_soft(param, "value");
421 				if(var && val) {
422 					switch_core_set_variable(var, val);
423 				}
424 			}
425 		} else if ((child = switch_xml_child(def, "variables"))) {
426 			for (param = switch_xml_child(child, "variable"); param; param = param->next) {
427 				char *var = (char *) switch_xml_attr_soft(param, "name");
428 				char *val = (char *) switch_xml_attr_soft(param, "value");
429 				if(var && val) {
430 					switch_core_set_variable(var, val);
431 				}
432 			}
433 		}
434 
435 		definitions = kazoo_config_definitions(cfg);
436 		if(definitions == NULL) {
437 			if(kazoo_globals.definitions == NULL) {
438 				definitions = kazoo_config_definitions(def);
439 			} else {
440 				definitions = kazoo_globals.definitions;
441 			}
442 		}
443 
444 		fetch_handlers = kazoo_config_fetch_handlers(definitions, cfg);
445 		if(fetch_handlers == NULL) {
446 			if(kazoo_globals.fetch_handlers == NULL) {
447 				fetch_handlers = kazoo_config_fetch_handlers(definitions, def);
448 			} else {
449 				fetch_handlers = kazoo_globals.fetch_handlers;
450 			}
451 		}
452 
453 		event_handlers = kazoo_config_event_handlers(definitions, cfg);
454 		if(event_handlers == NULL) {
455 			if(kazoo_globals.event_handlers == NULL) {
456 				event_handlers = kazoo_config_event_handlers(definitions, def);
457 			} else {
458 				event_handlers = kazoo_globals.event_handlers;
459 			}
460 		}
461 
462 		if(event_handlers != NULL) {
463 			events = (kazoo_event_profile_ptr) switch_core_hash_find(event_handlers->hash, "default");
464 		}
465 
466 		if(events == NULL) {
467 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to get default handler for events\n");
468 			destroy_config(&event_handlers);
469 			event_handlers = kazoo_config_event_handlers(definitions, def);
470 			events = (kazoo_event_profile_ptr) switch_core_hash_find(event_handlers->hash, "default");
471 		}
472 
473 		if(kazoo_globals.events != events) {
474 			bind_event_profiles(events->events);
475 			kazoo_globals.events = events;
476 		}
477 
478 		if(kazoo_globals.event_handlers != event_handlers) {
479 			kazoo_config_ptr tmp = kazoo_globals.event_handlers;
480 			kazoo_globals.event_handlers = event_handlers;
481 			destroy_config(&tmp);
482 		}
483 
484 		if(kazoo_globals.fetch_handlers != fetch_handlers) {
485 			kazoo_config_ptr tmp = kazoo_globals.fetch_handlers;
486 			kazoo_globals.fetch_handlers = fetch_handlers;
487 			rebind_fetch_profiles(fetch_handlers);
488 			destroy_config(&tmp);
489 		}
490 
491 		if(kazoo_globals.definitions != definitions) {
492 			kazoo_config_ptr tmp = kazoo_globals.definitions;
493 			kazoo_globals.definitions = definitions;
494 			destroy_config(&tmp);
495 		}
496 
497 
498 		switch_xml_free(def);
499 		switch_safe_free(xml);
500 
501 	return SWITCH_STATUS_SUCCESS;
502 }
503 
kazoo_load_config()504 switch_status_t kazoo_load_config()
505 {
506 	char *cf = "kazoo.conf";
507 	switch_xml_t cfg, xml;
508 	if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
509 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to open configuration file %s\n", cf);
510 		return SWITCH_STATUS_FALSE;
511 	} else {
512 		kazoo_ei_config(cfg);
513 		kazoo_config_handlers(cfg);
514 		switch_xml_free(xml);
515 	}
516 
517 	return SWITCH_STATUS_SUCCESS;
518 }
519 
kazoo_destroy_config()520 void kazoo_destroy_config()
521 {
522 	destroy_config(&kazoo_globals.event_handlers);
523 	destroy_config(&kazoo_globals.fetch_handlers);
524 	destroy_config(&kazoo_globals.definitions);
525 }
526 
kazoo_config_events(kazoo_config_ptr definitions,switch_memory_pool_t * pool,switch_xml_t cfg,kazoo_event_profile_ptr profile)527 switch_status_t kazoo_config_events(kazoo_config_ptr definitions, switch_memory_pool_t *pool, switch_xml_t cfg, kazoo_event_profile_ptr profile)
528 {
529 	switch_xml_t events, event;
530 	kazoo_event_ptr prv = NULL, cur = NULL;
531 
532 
533 	if ((events = switch_xml_child(cfg, "events")) != NULL) {
534 		for (event = switch_xml_child(events, "event"); event; event = event->next) {
535 			const char *var = switch_xml_attr(event, "name");
536 			cur = (kazoo_event_ptr) switch_core_alloc(pool, sizeof(kazoo_event_t));
537 			memset(cur, 0, sizeof(kazoo_event_t));
538 			if(prv == NULL) {
539 				profile->events = prv = cur;
540 			} else {
541 				prv->next = cur;
542 				prv = cur;
543 			}
544 			cur->profile = profile;
545 			cur->name = switch_core_strdup(pool, var);
546 			kazoo_config_filters(pool, event, &cur->filter);
547 			kazoo_config_fields(definitions, pool, event, &cur->fields);
548 			if (switch_xml_child(event, "logging") != NULL) {
549 				kazoo_config_loglevels(pool, event, &cur->logging);
550 			}
551 		}
552 	}
553 
554 	return SWITCH_STATUS_SUCCESS;
555 
556 }
557 
558 
kazoo_config_fetch_handler(kazoo_config_ptr definitions,kazoo_config_ptr root,switch_xml_t cfg,kazoo_fetch_profile_ptr * ptr)559 switch_status_t kazoo_config_fetch_handler(kazoo_config_ptr definitions, kazoo_config_ptr root, switch_xml_t cfg, kazoo_fetch_profile_ptr *ptr)
560 {
561 	kazoo_fetch_profile_ptr profile = NULL;
562 	switch_xml_t params, param;
563 	switch_xml_section_t fetch_section;
564 	int fetch_timeout = 2000000;
565 	switch_memory_pool_t *pool = NULL;
566 
567 	char *name = (char *) switch_xml_attr_soft(cfg, "name");
568 	if (zstr(name)) {
569 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "missing name in profile\n");
570 		return SWITCH_STATUS_GENERR;
571 	}
572 
573 	if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
574 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error allocation pool for new profile : %s\n", name);
575 		return SWITCH_STATUS_GENERR;
576 	}
577 
578 	profile = switch_core_alloc(pool, sizeof(kazoo_fetch_profile_t));
579 	profile->pool = pool;
580 	profile->root = root;
581 	profile->name = switch_core_strdup(profile->pool, name);
582 
583 	fetch_section = switch_xml_parse_section_string(name);
584 
585 	if ((params = switch_xml_child(cfg, "params")) != NULL) {
586 		for (param = switch_xml_child(params, "param"); param; param = param->next) {
587 			char *var = (char *) switch_xml_attr_soft(param, "name");
588 			char *val = (char *) switch_xml_attr_soft(param, "value");
589 
590 			if (!var) {
591 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Profile[%s] param missing 'name' attribute\n", name);
592 				continue;
593 			}
594 
595 			if (!val) {
596 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Profile[%s] param[%s] missing 'value' attribute\n", name, var);
597 				continue;
598 			}
599 
600 			if (!strncmp(var, "fetch-timeout", 13)) {
601 				fetch_timeout = atoi(val);
602 			} else if (!strncmp(var, "fetch-section", 13)) {
603 				fetch_section = switch_xml_parse_section_string(val);
604 			}
605 		}
606 	}
607 
608 	if (fetch_section == SWITCH_XML_SECTION_RESULT) {
609 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Fetch Profile[%s] invalid fetch-section: %s\n", name, switch_xml_toxml(cfg, SWITCH_FALSE));
610 		goto err;
611 	}
612 
613 
614 	profile->fetch_timeout = fetch_timeout;
615 	profile->section = fetch_section;
616 	kazoo_config_fields(definitions, pool, cfg, &profile->fields);
617 	kazoo_config_loglevels(pool, cfg, &profile->logging);
618 
619 	if(root) {
620 		if ( switch_core_hash_insert(root->hash, name, (void *) profile) != SWITCH_STATUS_SUCCESS) {
621 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to insert new fetch profile [%s] into kazoo profile hash\n", name);
622 			goto err;
623 		}
624 	}
625 
626 	if(ptr)
627 		*ptr = profile;
628 
629 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "fetch handler profile %s successfully configured\n", name);
630 	return SWITCH_STATUS_SUCCESS;
631 
632  err:
633 	/* Cleanup */
634     if(pool) {
635     	switch_core_destroy_memory_pool(&pool);
636     }
637 	return SWITCH_STATUS_GENERR;
638 
639 }
640 
kazoo_config_event_handler(kazoo_config_ptr definitions,kazoo_config_ptr root,switch_xml_t cfg,kazoo_event_profile_ptr * ptr)641 switch_status_t kazoo_config_event_handler(kazoo_config_ptr definitions, kazoo_config_ptr root, switch_xml_t cfg, kazoo_event_profile_ptr *ptr)
642 {
643 	kazoo_event_profile_ptr profile = NULL;
644 	switch_memory_pool_t *pool = NULL;
645 
646 	char *name = (char *) switch_xml_attr_soft(cfg, "name");
647 	if (zstr(name)) {
648 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "missing name in profile\n");
649 		return SWITCH_STATUS_GENERR;
650 	}
651 
652 	if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
653 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error allocation pool for new profile : %s\n", name);
654 		return SWITCH_STATUS_GENERR;
655 	}
656 
657 	profile = switch_core_alloc(pool, sizeof(kazoo_event_profile_t));
658 	profile->pool = pool;
659 	profile->root = root;
660 	profile->name = switch_core_strdup(profile->pool, name);
661 
662 	kazoo_config_filters(pool, cfg, &profile->filter);
663 	kazoo_config_fields(definitions, pool, cfg, &profile->fields);
664 	kazoo_config_events(definitions, pool, cfg, profile);
665 	kazoo_config_loglevels(pool, cfg, &profile->logging);
666 
667 	if(root) {
668 		if ( switch_core_hash_insert(root->hash, name, (void *) profile) != SWITCH_STATUS_SUCCESS) {
669 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to insert new profile [%s] into kazoo profile hash\n", name);
670 			goto err;
671 		}
672 	}
673 
674 	if(ptr)
675 		*ptr = profile;
676 
677 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "event handler profile %s successfully configured\n", name);
678 	return SWITCH_STATUS_SUCCESS;
679 
680  err:
681 	/* Cleanup */
682     if(pool) {
683     	switch_core_destroy_memory_pool(&pool);
684     }
685 	return SWITCH_STATUS_GENERR;
686 
687 }
688 
689 
690 
691 /* For Emacs:
692  * Local Variables:
693  * mode:c
694  * indent-tabs-mode:t
695  * tab-width:4
696  * c-basic-offset:4
697  * End:
698  * For VIM:
699  * vim:set softtabstop=4 shiftwidth=4 tabstop=4
700  */
701