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  * Contributor(s):
25  *
26  * Anthony Minessale II <anthm@freeswitch.org>
27  * Andrew Thompson <andrew@hijacked.us>
28  * Rob Charlton <rob.charlton@savageminds.com>
29  * Karl Anderson <karl@2600hz.com>
30  *
31  * Original from mod_erlang_event.
32  * ei_helpers.c -- helper functions for ei
33  *
34  */
35 #include "mod_kazoo.h"
36 
37 /* Stolen from code added to ei in R12B-5.
38  * Since not everyone has this version yet;
39  * provide our own version.
40  * */
41 
42 #define put8(s,n) do {							\
43         (s)[0] = (char)((n) & 0xff);			\
44         (s) += 1;								\
45 	} while (0)
46 
47 #define put32be(s,n) do {						\
48         (s)[0] = ((n) >>  24) & 0xff;			\
49         (s)[1] = ((n) >>  16) & 0xff;			\
50         (s)[2] = ((n) >>  8) & 0xff;			\
51         (s)[3] = (n) & 0xff;					\
52         (s) += 4;								\
53 	} while (0)
54 
55 #ifdef EI_DEBUG
ei_x_print_reg_msg(ei_x_buff * buf,char * dest,int send)56 static void ei_x_print_reg_msg(ei_x_buff *buf, char *dest, int send) {
57 	char *mbuf = NULL;
58 	int i = 1;
59 
60 	ei_s_print_term(&mbuf, buf->buff, &i);
61 
62 	if (send) {
63 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Encoded term %s to '%s'\n", mbuf, dest);
64 	} else {
65 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Decoded term %s for '%s'\n", mbuf, dest);
66 	}
67 
68 	free(mbuf);
69 }
70 
ei_x_print_msg(ei_x_buff * buf,erlang_pid * pid,int send)71 static void ei_x_print_msg(ei_x_buff *buf, erlang_pid *pid, int send) {
72 	char *pbuf = NULL;
73 	int i = 0;
74 	ei_x_buff pidbuf;
75 
76 	ei_x_new(&pidbuf);
77 	ei_x_encode_pid(&pidbuf, pid);
78 
79 	ei_s_print_term(&pbuf, pidbuf.buff, &i);
80 
81 	ei_x_print_reg_msg(buf, pbuf, send);
82 	free(pbuf);
83 }
84 #endif
85 
ei_encode_switch_event_headers(ei_x_buff * ebuf,switch_event_t * event)86 void ei_encode_switch_event_headers(ei_x_buff *ebuf, switch_event_t *event)
87 {
88 	ei_encode_switch_event_headers_2(ebuf, event, 1);
89 }
90 
ei_encode_switch_event_headers_2(ei_x_buff * ebuf,switch_event_t * event,int encode)91 void ei_encode_switch_event_headers_2(ei_x_buff *ebuf, switch_event_t *event, int encode)
92 {
93 	switch_event_header_t *hp;
94 	char *uuid = switch_event_get_header(event, "unique-id");
95 	int i;
96 
97 	for (i = 0, hp = event->headers; hp; hp = hp->next, i++)
98 		;
99 
100 	if (event->body)
101 		i++;
102 
103 	ei_x_encode_list_header(ebuf, i + 1);
104 
105 	if (uuid) {
106 		char *unique_id = switch_event_get_header(event, "unique-id");
107 		ei_x_encode_binary(ebuf, unique_id, strlen(unique_id));
108 	} else {
109 		ei_x_encode_atom(ebuf, "undefined");
110 	}
111 
112 	for (hp = event->headers; hp; hp = hp->next) {
113 		ei_x_encode_tuple_header(ebuf, 2);
114 		ei_x_encode_binary(ebuf, hp->name, strlen(hp->name));
115 		if (encode) {
116 			switch_url_decode(hp->value);
117 		}
118 		ei_x_encode_binary(ebuf, hp->value, strlen(hp->value));
119 	}
120 
121 	if (event->body) {
122 		ei_x_encode_tuple_header(ebuf, 2);
123 		ei_x_encode_binary(ebuf, "body", strlen("body"));
124 		ei_x_encode_binary(ebuf, event->body, strlen(event->body));
125 	}
126 
127 	ei_x_encode_empty_list(ebuf);
128 }
129 
ei_json_child_count(cJSON * JObj)130 int ei_json_child_count(cJSON *JObj)
131 {
132 	int mask = cJSON_False | cJSON_True | cJSON_NULL | cJSON_Number | cJSON_String | cJSON_Array | cJSON_Object | cJSON_Raw;
133 
134 	cJSON *item = JObj->child;
135 	int i = 0;
136 	while (item) {
137 		if (item->type & mask)
138 			i++;
139 		item = item->next;
140 	}
141 	return i;
142 
143 }
144 
ei_encode_json_array(ei_x_buff * ebuf,cJSON * JObj)145 void ei_encode_json_array(ei_x_buff *ebuf, cJSON *JObj)
146 {
147 	cJSON *item;
148 	int count = ei_json_child_count(JObj);
149 
150 	ei_x_encode_list_header(ebuf, count);
151 	if (count == 0)
152 		return;
153 
154 	item = JObj->child;
155 	while (item) {
156 		switch (item->type){
157 		case cJSON_String:
158 			ei_x_encode_binary(ebuf, item->valuestring, strlen(item->valuestring));
159 			break;
160 
161 		case cJSON_Number:
162 			if ((fabs(((double) item->valueint) - item->valuedouble) <= DBL_EPSILON) && (item->valuedouble <= INT_MAX) && (item->valuedouble >= INT_MIN)) {
163 				ei_x_encode_longlong(ebuf, item->valueint);
164 			} else {
165 				if (fmod(item->valuedouble, 1) == 0) {
166 					ei_x_encode_ulonglong(ebuf, item->valuedouble);
167 				} else {
168 					ei_x_encode_double(ebuf, item->valuedouble);
169 				}
170 			}
171 			break;
172 
173 		case cJSON_True:
174 			ei_x_encode_boolean(ebuf, 1);
175 			break;
176 
177 		case cJSON_False:
178 			ei_x_encode_boolean(ebuf, 0);
179 			break;
180 
181 		case cJSON_Object:
182 			ei_encode_json(ebuf, item);
183 			break;
184 
185 		case cJSON_Array:
186 			ei_encode_json_array(ebuf, item);
187 			break;
188 
189 		case cJSON_Raw: {
190 			cJSON *Decoded = cJSON_Parse(item->valuestring);
191 			if (!Decoded) {
192 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR DECODING RAW JSON %s\n", item->valuestring);
193 				ei_x_encode_tuple_header(ebuf, 0);
194 			} else {
195 				ei_encode_json(ebuf, Decoded);
196 				cJSON_Delete(Decoded);
197 			}
198 			break;
199 		}
200 
201 		case cJSON_NULL:
202 			ei_x_encode_atom(ebuf, "null");
203 			break;
204 
205 		default:
206 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NOT ENCODED %i\n", item->type);
207 			break;
208 
209 		}
210 		item = item->next;
211 	}
212 
213 	ei_x_encode_empty_list(ebuf);
214 
215 }
216 
ei_encode_json(ei_x_buff * ebuf,cJSON * JObj)217 void ei_encode_json(ei_x_buff *ebuf, cJSON *JObj)
218 {
219 	cJSON *item;
220 	int count = ei_json_child_count(JObj);
221 
222 	if (kazoo_globals.json_encoding == ERLANG_TUPLE) {
223 		ei_x_encode_tuple_header(ebuf, 1);
224 		ei_x_encode_list_header(ebuf, count);
225 	} else {
226 		ei_x_encode_map_header(ebuf, count);
227 	}
228 
229 	if (count == 0)
230 		return;
231 
232 	item = JObj->child;
233 	while (item) {
234 		if (kazoo_globals.json_encoding == ERLANG_TUPLE) {
235 			ei_x_encode_tuple_header(ebuf, 2);
236 		}
237 		ei_x_encode_binary(ebuf, item->string, strlen(item->string));
238 
239 		switch (item->type){
240 		case cJSON_String:
241 			ei_x_encode_binary(ebuf, item->valuestring, strlen(item->valuestring));
242 			break;
243 
244 		case cJSON_Number:
245 			if ((fabs(((double) item->valueint) - item->valuedouble) <= DBL_EPSILON) && (item->valuedouble <= INT_MAX) && (item->valuedouble >= INT_MIN)) {
246 				ei_x_encode_longlong(ebuf, item->valueint);
247 			} else {
248 				if (fmod(item->valuedouble, 1) == 0) {
249 					ei_x_encode_ulonglong(ebuf, item->valuedouble);
250 				} else {
251 					ei_x_encode_double(ebuf, item->valuedouble);
252 				}
253 			}
254 			break;
255 
256 		case cJSON_True:
257 			ei_x_encode_boolean(ebuf, 1);
258 			break;
259 
260 		case cJSON_False:
261 			ei_x_encode_boolean(ebuf, 0);
262 			break;
263 
264 		case cJSON_Object:
265 			ei_encode_json(ebuf, item);
266 			break;
267 
268 		case cJSON_Array:
269 			ei_encode_json_array(ebuf, item);
270 			break;
271 
272 		case cJSON_Raw: {
273 			cJSON *Decoded = cJSON_Parse(item->valuestring);
274 			if (!Decoded) {
275 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR DECODING RAW JSON %s\n", item->valuestring);
276 				ei_x_encode_tuple_header(ebuf, 0);
277 			} else {
278 				ei_encode_json(ebuf, Decoded);
279 				cJSON_Delete(Decoded);
280 			}
281 			break;
282 		}
283 
284 		case cJSON_NULL:
285 			ei_x_encode_atom(ebuf, "null");
286 			break;
287 
288 		default:
289 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NOT ENCODED %i\n", item->type);
290 			break;
291 
292 		}
293 		item = item->next;
294 	}
295 
296 	if (kazoo_globals.json_encoding == ERLANG_TUPLE) {
297 		ei_x_encode_empty_list(ebuf);
298 	}
299 
300 }
301 
close_socket(switch_socket_t ** sock)302 void close_socket(switch_socket_t ** sock)
303 {
304 	if (*sock) {
305 		switch_socket_shutdown(*sock, SWITCH_SHUTDOWN_READWRITE);
306 		switch_socket_close(*sock);
307 		*sock = NULL;
308 	}
309 }
310 
close_socketfd(int * sockfd)311 void close_socketfd(int *sockfd)
312 {
313 	if (*sockfd) {
314 		shutdown(*sockfd, SHUT_RDWR);
315 		close(*sockfd);
316 	}
317 }
318 
create_socket_with_port(switch_memory_pool_t * pool,switch_port_t port)319 switch_socket_t *create_socket_with_port(switch_memory_pool_t *pool, switch_port_t port)
320 {
321 	switch_sockaddr_t *sa;
322 	switch_socket_t *socket;
323 
324 	if (switch_sockaddr_info_get(&sa, kazoo_globals.ip, SWITCH_UNSPEC, port, 0, pool)) {
325 		return NULL;
326 	}
327 
328 	if (switch_socket_create(&socket, switch_sockaddr_get_family(sa), SOCK_STREAM, SWITCH_PROTO_TCP, pool)) {
329 		return NULL;
330 	}
331 
332 	if (switch_socket_opt_set(socket, SWITCH_SO_REUSEADDR, 1)) {
333 		return NULL;
334 	}
335 
336 	if (switch_socket_bind(socket, sa)) {
337 		return NULL;
338 	}
339 
340 	if (switch_socket_listen(socket, 5)) {
341 		return NULL;
342 	}
343 
344 	if (kazoo_globals.nat_map && switch_nat_get_type()) {
345 		switch_nat_add_mapping(port, SWITCH_NAT_TCP, NULL, SWITCH_FALSE);
346 	}
347 
348 	return socket;
349 }
350 
create_socket(switch_memory_pool_t * pool)351 switch_socket_t *create_socket(switch_memory_pool_t *pool)
352 {
353 	return create_socket_with_port(pool, 0);
354 
355 }
356 
create_ei_cnode(const char * ip_addr,const char * name,struct ei_cnode_s * ei_cnode)357 switch_status_t create_ei_cnode(const char *ip_addr, const char *name, struct ei_cnode_s *ei_cnode)
358 {
359 	char hostname[EI_MAXHOSTNAMELEN + 1];
360 	char nodename[MAXNODELEN + 1];
361 	char cnodename[EI_MAXALIVELEN + 1];
362 	char *atsign;
363 
364 	/* copy the erlang interface nodename into something we can modify */
365 	strncpy(cnodename, name, EI_MAXALIVELEN);
366 
367 	if ((atsign = strchr(cnodename, '@'))) {
368 		/* we got a qualified node name, don't guess the host/domain */
369 		snprintf(nodename, MAXNODELEN + 1, "%s", name);
370 		/* truncate the alivename at the @ */
371 		*atsign++ = '\0';
372 		strncpy(hostname, atsign, EI_MAXHOSTNAMELEN);
373 	} else {
374 		strncpy(hostname, kazoo_globals.hostname, EI_MAXHOSTNAMELEN);
375 		snprintf(nodename, MAXNODELEN + 1, "%s@%s", name, hostname);
376 	}
377 
378 	if (kazoo_globals.ei_shortname) {
379 		char *off;
380 		if ((off = strchr(nodename, '.'))) {
381 			*off = '\0';
382 		}
383 	}
384 
385 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "creating nodename: %s\n", nodename);
386 
387 	/* init the ec stuff */
388 	if (ei_connect_xinit(ei_cnode, hostname, cnodename, nodename, (Erl_IpAddr) ip_addr, kazoo_globals.ei_cookie, 0) < 0) {
389 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to initialize the erlang interface connection structure\n");
390 		return SWITCH_STATUS_FALSE;
391 	}
392 
393 	return SWITCH_STATUS_SUCCESS;
394 }
395 
ei_compare_pids(const erlang_pid * pid1,const erlang_pid * pid2)396 switch_status_t ei_compare_pids(const erlang_pid *pid1, const erlang_pid *pid2)
397 {
398 	if ((!strcmp(pid1->node, pid2->node)) && pid1->creation == pid2->creation && pid1->num == pid2->num && pid1->serial == pid2->serial) {
399 		return SWITCH_STATUS_SUCCESS;
400 	} else {
401 		return SWITCH_STATUS_FALSE;
402 	}
403 }
404 
ei_link(ei_node_t * ei_node,erlang_pid * from,erlang_pid * to)405 void ei_link(ei_node_t *ei_node, erlang_pid * from, erlang_pid * to)
406 {
407 	char msgbuf[2048];
408 	char *s;
409 	int index = 0;
410 
411 	index = 5; /* max sizes: */
412 	ei_encode_version(msgbuf, &index); /*   1 */
413 	ei_encode_tuple_header(msgbuf, &index, 3);
414 	ei_encode_long(msgbuf, &index, ERL_LINK);
415 	ei_encode_pid(msgbuf, &index, from); /* 268 */
416 	ei_encode_pid(msgbuf, &index, to); /* 268 */
417 
418 	/* 5 byte header missing */
419 	s = msgbuf;
420 	put32be(s, index - 4); /*   4 */
421 	put8(s, ERL_PASS_THROUGH); /*   1 */
422 	/* sum:  542 */
423 
424 	if (write(ei_node->nodefd, msgbuf, index) == -1) {
425 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to link to process on %s\n", ei_node->peer_nodename);
426 	}
427 }
428 
ei_encode_switch_event(ei_x_buff * ebuf,switch_event_t * event)429 void ei_encode_switch_event(ei_x_buff *ebuf, switch_event_t *event)
430 {
431 	ei_x_encode_tuple_header(ebuf, 2);
432 	ei_x_encode_atom(ebuf, "event");
433 	ei_encode_switch_event_headers(ebuf, event);
434 }
435 
ei_helper_send(ei_node_t * ei_node,erlang_pid * to,ei_x_buff * buf)436 int ei_helper_send(ei_node_t *ei_node, erlang_pid *to, ei_x_buff *buf)
437 {
438 	int ret = 0;
439 
440 	if (ei_node->nodefd) {
441 #ifdef EI_DEBUG
442 		ei_x_print_msg(buf, to, 1);
443 #endif
444 		ret = ei_send(ei_node->nodefd, to, buf->buff, buf->index);
445 	}
446 
447 	return ret;
448 }
449 
ei_decode_atom_safe(char * buf,int * index,char * dst)450 int ei_decode_atom_safe(char *buf, int *index, char *dst)
451 {
452 	int type, size;
453 
454 	ei_get_type(buf, index, &type, &size);
455 
456 	if (type != ERL_ATOM_EXT) {
457 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unexpected erlang term type %d (size %d), needed atom\n", type, size);
458 		return -1;
459 	} else if (size > MAXATOMLEN) {
460 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Requested decoding of atom with size %d into a buffer of size %d\n", size, MAXATOMLEN);
461 		return -1;
462 	} else {
463 		return ei_decode_atom(buf, index, dst);
464 	}
465 }
466 
ei_decode_string_or_binary(char * buf,int * index,char ** dst)467 int ei_decode_string_or_binary(char *buf, int *index, char **dst)
468 {
469 	int type, size, res;
470 	long len;
471 
472 	ei_get_type(buf, index, &type, &size);
473 
474 	if (type != ERL_STRING_EXT && type != ERL_BINARY_EXT && type != ERL_LIST_EXT && type != ERL_NIL_EXT) {
475 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unexpected erlang term type %d (size %d), needed binary or string\n", type, size);
476 		return -1;
477 	}
478 
479 	*dst = malloc(size + 1);
480 
481 	if (type == ERL_NIL_EXT) {
482 		res = 0;
483 		**dst = '\0';
484 	} else if (type == ERL_BINARY_EXT) {
485 		res = ei_decode_binary(buf, index, *dst, &len);
486 		(*dst)[len] = '\0';
487 	} else {
488 		res = ei_decode_string(buf, index, *dst);
489 	}
490 
491 	return res;
492 }
493 
ei_decode_string_or_binary_limited(char * buf,int * index,int maxsize,char * dst)494 int ei_decode_string_or_binary_limited(char *buf, int *index, int maxsize, char *dst)
495 {
496 	int type, size, res;
497 	long len;
498 
499 	ei_get_type(buf, index, &type, &size);
500 
501 	if (type != ERL_STRING_EXT && type != ERL_BINARY_EXT && type != ERL_LIST_EXT && type != ERL_NIL_EXT) {
502 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unexpected erlang term type %d (size %d), needed binary or string\n", type, size);
503 		return -1;
504 	}
505 
506 	if (size > maxsize) {
507 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Requested decoding of %s with size %d into a buffer of size %d\n",
508 		                  type == ERL_BINARY_EXT ? "binary" : "string", size, maxsize);
509 		return -1;
510 	}
511 
512 	if (type == ERL_NIL_EXT) {
513 		res = 0;
514 		*dst = '\0';
515 	} else if (type == ERL_BINARY_EXT) {
516 		res = ei_decode_binary(buf, index, dst, &len);
517 		dst[len] = '\0'; /* binaries aren't null terminated */
518 	} else {
519 		res = ei_decode_string(buf, index, dst);
520 	}
521 
522 	return res;
523 }
524 
create_acceptor()525 switch_status_t create_acceptor()
526 {
527 	switch_sockaddr_t *sa;
528 	uint16_t port;
529 	char ipbuf[48];
530 	const char *ip_addr;
531 
532 	/* if the config has specified an erlang release compatibility then pass that along to the erlang interface */
533 	if (kazoo_globals.ei_compat_rel) {
534 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Compatability with OTP R%d requested\n", kazoo_globals.ei_compat_rel);
535 		ei_set_compat_rel(kazoo_globals.ei_compat_rel);
536 	}
537 
538 	if (!(kazoo_globals.acceptor = create_socket_with_port(kazoo_globals.pool, kazoo_globals.port))) {
539 		return SWITCH_STATUS_SOCKERR;
540 	}
541 
542 	switch_socket_addr_get(&sa, SWITCH_FALSE, kazoo_globals.acceptor);
543 
544 	port = switch_sockaddr_get_port(sa);
545 	ip_addr = switch_get_addr(ipbuf, sizeof(ipbuf), sa);
546 
547 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Erlang connection acceptor listening on %s:%u\n", ip_addr, port);
548 
549 	/* try to initialize the erlang interface */
550 	if (create_ei_cnode(ip_addr, kazoo_globals.ei_nodename, &kazoo_globals.ei_cnode) != SWITCH_STATUS_SUCCESS) {
551 		return SWITCH_STATUS_SOCKERR;
552 	}
553 
554 	/* tell the erlang port manager where we can be reached.  this returns a file descriptor pointing to epmd or -1 */
555 	if ((kazoo_globals.epmdfd = ei_publish(&kazoo_globals.ei_cnode, port)) == -1) {
556 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to publish port to epmd, trying to start epmd via system()\n");
557 		if (system("fs_epmd -daemon")) {
558 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
559 			                  "Failed to start epmd manually! Is epmd in $PATH? If not, start it yourself or run an erl shell with -sname or -name\n");
560 			return SWITCH_STATUS_SOCKERR;
561 		}
562 		switch_yield(100000);
563 		if ((kazoo_globals.epmdfd = ei_publish(&kazoo_globals.ei_cnode, port)) == -1) {
564 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to publish port to epmd AGAIN\n");
565 			return SWITCH_STATUS_SOCKERR;
566 		}
567 	}
568 
569 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connected to epmd and published erlang cnode name %s at port %d\n", kazoo_globals.ei_cnode.thisnodename,
570 	                  port);
571 
572 	return SWITCH_STATUS_SUCCESS;
573 }
574 
create_default_filter()575 switch_hash_t *create_default_filter()
576 {
577 	switch_hash_t *filter;
578 
579 	switch_core_hash_init(&filter);
580 
581 	switch_core_hash_insert(filter, "Acquired-UUID", "1");
582 	switch_core_hash_insert(filter, "action", "1");
583 	switch_core_hash_insert(filter, "Action", "1");
584 	switch_core_hash_insert(filter, "alt_event_type", "1");
585 	switch_core_hash_insert(filter, "Answer-State", "1");
586 	switch_core_hash_insert(filter, "Application", "1");
587 	switch_core_hash_insert(filter, "Application-Data", "1");
588 	switch_core_hash_insert(filter, "Application-Name", "1");
589 	switch_core_hash_insert(filter, "Application-Response", "1");
590 	switch_core_hash_insert(filter, "att_xfer_replaced_by", "1");
591 	switch_core_hash_insert(filter, "Auth-Method", "1");
592 	switch_core_hash_insert(filter, "Auth-Realm", "1");
593 	switch_core_hash_insert(filter, "Auth-User", "1");
594 	switch_core_hash_insert(filter, "Bridge-A-Unique-ID", "1");
595 	switch_core_hash_insert(filter, "Bridge-B-Unique-ID", "1");
596 	switch_core_hash_insert(filter, "Call-Direction", "1");
597 	switch_core_hash_insert(filter, "Caller-Callee-ID-Name", "1");
598 	switch_core_hash_insert(filter, "Caller-Callee-ID-Number", "1");
599 	switch_core_hash_insert(filter, "Caller-Caller-ID-Name", "1");
600 	switch_core_hash_insert(filter, "Caller-Caller-ID-Number", "1");
601 	switch_core_hash_insert(filter, "Caller-Screen-Bit", "1");
602 	switch_core_hash_insert(filter, "Caller-Privacy-Hide-Name", "1");
603 	switch_core_hash_insert(filter, "Caller-Privacy-Hide-Number", "1");
604 	switch_core_hash_insert(filter, "Caller-Context", "1");
605 	switch_core_hash_insert(filter, "Caller-Controls", "1");
606 	switch_core_hash_insert(filter, "Caller-Destination-Number", "1");
607 	switch_core_hash_insert(filter, "Caller-Dialplan", "1");
608 	switch_core_hash_insert(filter, "Caller-Network-Addr", "1");
609 	switch_core_hash_insert(filter, "Caller-Unique-ID", "1");
610 	switch_core_hash_insert(filter, "Call-ID", "1");
611 	switch_core_hash_insert(filter, "Channel-Call-State", "1");
612 	switch_core_hash_insert(filter, "Channel-Call-UUID", "1");
613 	switch_core_hash_insert(filter, "Channel-Presence-ID", "1");
614 	switch_core_hash_insert(filter, "Channel-State", "1");
615 	switch_core_hash_insert(filter, "Chat-Permissions", "1");
616 	switch_core_hash_insert(filter, "Conference-Name", "1");
617 	switch_core_hash_insert(filter, "Conference-Profile-Name", "1");
618 	switch_core_hash_insert(filter, "Conference-Unique-ID", "1");
619 	switch_core_hash_insert(filter, "contact", "1");
620 	switch_core_hash_insert(filter, "Detected-Tone", "1");
621 	switch_core_hash_insert(filter, "dialog_state", "1");
622 	switch_core_hash_insert(filter, "direction", "1");
623 	switch_core_hash_insert(filter, "Distributed-From", "1");
624 	switch_core_hash_insert(filter, "DTMF-Digit", "1");
625 	switch_core_hash_insert(filter, "DTMF-Duration", "1");
626 	switch_core_hash_insert(filter, "Event-Date-Timestamp", "1");
627 	switch_core_hash_insert(filter, "Event-Name", "1");
628 	switch_core_hash_insert(filter, "Event-Subclass", "1");
629 	switch_core_hash_insert(filter, "expires", "1");
630 	switch_core_hash_insert(filter, "Expires", "1");
631 	switch_core_hash_insert(filter, "Ext-SIP-IP", "1");
632 	switch_core_hash_insert(filter, "File", "1");
633 	switch_core_hash_insert(filter, "FreeSWITCH-Hostname", "1");
634 	switch_core_hash_insert(filter, "from", "1");
635 	switch_core_hash_insert(filter, "Hunt-Destination-Number", "1");
636 	switch_core_hash_insert(filter, "ip", "1");
637 	switch_core_hash_insert(filter, "Message-Account", "1");
638 	switch_core_hash_insert(filter, "metadata", "1");
639 	switch_core_hash_insert(filter, "old_node_channel_uuid", "1");
640 	switch_core_hash_insert(filter, "Other-Leg-Callee-ID-Name", "1");
641 	switch_core_hash_insert(filter, "Other-Leg-Callee-ID-Number", "1");
642 	switch_core_hash_insert(filter, "Other-Leg-Caller-ID-Name", "1");
643 	switch_core_hash_insert(filter, "Other-Leg-Caller-ID-Number", "1");
644 	switch_core_hash_insert(filter, "Other-Leg-Destination-Number", "1");
645 	switch_core_hash_insert(filter, "Other-Leg-Direction", "1");
646 	switch_core_hash_insert(filter, "Other-Leg-Unique-ID", "1");
647 	switch_core_hash_insert(filter, "Other-Leg-Channel-Name", "1");
648 	switch_core_hash_insert(filter, "Participant-Type", "1");
649 	switch_core_hash_insert(filter, "Path", "1");
650 	switch_core_hash_insert(filter, "profile_name", "1");
651 	switch_core_hash_insert(filter, "Profiles", "1");
652 	switch_core_hash_insert(filter, "proto-specific-event-name", "1");
653 	switch_core_hash_insert(filter, "Raw-Application-Data", "1");
654 	switch_core_hash_insert(filter, "realm", "1");
655 	switch_core_hash_insert(filter, "Resigning-UUID", "1");
656 	switch_core_hash_insert(filter, "set", "1");
657 	switch_core_hash_insert(filter, "sip_auto_answer", "1");
658 	switch_core_hash_insert(filter, "sip_auth_method", "1");
659 	switch_core_hash_insert(filter, "sip_from_host", "1");
660 	switch_core_hash_insert(filter, "sip_from_user", "1");
661 	switch_core_hash_insert(filter, "sip_to_host", "1");
662 	switch_core_hash_insert(filter, "sip_to_user", "1");
663 	switch_core_hash_insert(filter, "sub-call-id", "1");
664 	switch_core_hash_insert(filter, "technology", "1");
665 	switch_core_hash_insert(filter, "to", "1");
666 	switch_core_hash_insert(filter, "Unique-ID", "1");
667 	switch_core_hash_insert(filter, "URL", "1");
668 	switch_core_hash_insert(filter, "username", "1");
669 	switch_core_hash_insert(filter, "variable_channel_is_moving", "1");
670 	switch_core_hash_insert(filter, "variable_collected_digits", "1");
671 	switch_core_hash_insert(filter, "variable_current_application", "1");
672 	switch_core_hash_insert(filter, "variable_current_application_data", "1");
673 	switch_core_hash_insert(filter, "variable_domain_name", "1");
674 	switch_core_hash_insert(filter, "variable_effective_caller_id_name", "1");
675 	switch_core_hash_insert(filter, "variable_effective_caller_id_number", "1");
676 	switch_core_hash_insert(filter, "variable_holding_uuid", "1");
677 	switch_core_hash_insert(filter, "variable_hold_music", "1");
678 	switch_core_hash_insert(filter, "variable_media_group_id", "1");
679 	switch_core_hash_insert(filter, "variable_originate_disposition", "1");
680 	switch_core_hash_insert(filter, "variable_origination_uuid", "1");
681 	switch_core_hash_insert(filter, "variable_playback_terminator_used", "1");
682 	switch_core_hash_insert(filter, "variable_presence_id", "1");
683 	switch_core_hash_insert(filter, "variable_record_ms", "1");
684 	switch_core_hash_insert(filter, "variable_recovered", "1");
685 	switch_core_hash_insert(filter, "variable_silence_hits_exhausted", "1");
686 	switch_core_hash_insert(filter, "variable_sip_auth_realm", "1");
687 	switch_core_hash_insert(filter, "variable_sip_from_host", "1");
688 	switch_core_hash_insert(filter, "variable_sip_from_user", "1");
689 	switch_core_hash_insert(filter, "variable_sip_from_tag", "1");
690 	switch_core_hash_insert(filter, "variable_sip_h_X-AUTH-IP", "1");
691 	switch_core_hash_insert(filter, "variable_sip_received_ip", "1");
692 	switch_core_hash_insert(filter, "variable_sip_to_host", "1");
693 	switch_core_hash_insert(filter, "variable_sip_to_user", "1");
694 	switch_core_hash_insert(filter, "variable_sip_to_tag", "1");
695 	switch_core_hash_insert(filter, "variable_sofia_profile_name", "1");
696 	switch_core_hash_insert(filter, "variable_transfer_history", "1");
697 	switch_core_hash_insert(filter, "variable_user_name", "1");
698 	switch_core_hash_insert(filter, "variable_endpoint_disposition", "1");
699 	switch_core_hash_insert(filter, "variable_originate_disposition", "1");
700 	switch_core_hash_insert(filter, "variable_bridge_hangup_cause", "1");
701 	switch_core_hash_insert(filter, "variable_hangup_cause", "1");
702 	switch_core_hash_insert(filter, "variable_last_bridge_proto_specific_hangup_cause", "1");
703 	switch_core_hash_insert(filter, "variable_proto_specific_hangup_cause", "1");
704 	switch_core_hash_insert(filter, "VM-Call-ID", "1");
705 	switch_core_hash_insert(filter, "VM-sub-call-id", "1");
706 	switch_core_hash_insert(filter, "whistle_application_name", "1");
707 	switch_core_hash_insert(filter, "whistle_application_response", "1");
708 	switch_core_hash_insert(filter, "whistle_event_name", "1");
709 	switch_core_hash_insert(filter, "kazoo_application_name", "1");
710 	switch_core_hash_insert(filter, "kazoo_application_response", "1");
711 	switch_core_hash_insert(filter, "kazoo_event_name", "1");
712 	switch_core_hash_insert(filter, "sip_auto_answer_notify", "1");
713 	switch_core_hash_insert(filter, "eavesdrop_group", "1");
714 	switch_core_hash_insert(filter, "origination_caller_id_name", "1");
715 	switch_core_hash_insert(filter, "origination_caller_id_number", "1");
716 	switch_core_hash_insert(filter, "origination_callee_id_name", "1");
717 	switch_core_hash_insert(filter, "origination_callee_id_number", "1");
718 	switch_core_hash_insert(filter, "sip_auth_username", "1");
719 	switch_core_hash_insert(filter, "sip_auth_password", "1");
720 	switch_core_hash_insert(filter, "effective_caller_id_name", "1");
721 	switch_core_hash_insert(filter, "effective_caller_id_number", "1");
722 	switch_core_hash_insert(filter, "effective_callee_id_name", "1");
723 	switch_core_hash_insert(filter, "effective_callee_id_number", "1");
724 	switch_core_hash_insert(filter, "variable_destination_number", "1");
725 	switch_core_hash_insert(filter, "variable_effective_callee_id_name", "1");
726 	switch_core_hash_insert(filter, "variable_effective_callee_id_number", "1");
727 	switch_core_hash_insert(filter, "variable_record_silence_hits", "1");
728 	switch_core_hash_insert(filter, "variable_refer_uuid", "1");
729 	switch_core_hash_insert(filter, "variable_sip_call_id", "1");
730 	switch_core_hash_insert(filter, "variable_sip_h_Referred-By", "1");
731 	switch_core_hash_insert(filter, "variable_sip_h_X-AUTH-PORT", "1");
732 	switch_core_hash_insert(filter, "variable_sip_loopback_req_uri", "1");
733 	switch_core_hash_insert(filter, "variable_sip_received_port", "1");
734 	switch_core_hash_insert(filter, "variable_sip_refer_to", "1");
735 	switch_core_hash_insert(filter, "variable_sip_req_host", "1");
736 	switch_core_hash_insert(filter, "variable_sip_req_uri", "1");
737 	switch_core_hash_insert(filter, "variable_transfer_source", "1");
738 	switch_core_hash_insert(filter, "variable_uuid", "1");
739 
740 	/* Registration headers */
741 	switch_core_hash_insert(filter, "call-id", "1");
742 	switch_core_hash_insert(filter, "profile-name", "1");
743 	switch_core_hash_insert(filter, "from-user", "1");
744 	switch_core_hash_insert(filter, "from-host", "1");
745 	switch_core_hash_insert(filter, "presence-hosts", "1");
746 	switch_core_hash_insert(filter, "contact", "1");
747 	switch_core_hash_insert(filter, "rpid", "1");
748 	switch_core_hash_insert(filter, "status", "1");
749 	switch_core_hash_insert(filter, "expires", "1");
750 	switch_core_hash_insert(filter, "to-user", "1");
751 	switch_core_hash_insert(filter, "to-host", "1");
752 	switch_core_hash_insert(filter, "network-ip", "1");
753 	switch_core_hash_insert(filter, "network-port", "1");
754 	switch_core_hash_insert(filter, "username", "1");
755 	switch_core_hash_insert(filter, "realm", "1");
756 	switch_core_hash_insert(filter, "user-agent", "1");
757 
758 	switch_core_hash_insert(filter, "Hangup-Cause", "1");
759 	switch_core_hash_insert(filter, "Unique-ID", "1");
760 	switch_core_hash_insert(filter, "variable_switch_r_sdp", "1");
761 	switch_core_hash_insert(filter, "variable_rtp_local_sdp_str", "1");
762 	switch_core_hash_insert(filter, "variable_sip_to_uri", "1");
763 	switch_core_hash_insert(filter, "variable_sip_from_uri", "1");
764 	switch_core_hash_insert(filter, "variable_sip_user_agent", "1");
765 	switch_core_hash_insert(filter, "variable_duration", "1");
766 	switch_core_hash_insert(filter, "variable_billsec", "1");
767 	switch_core_hash_insert(filter, "variable_billmsec", "1");
768 	switch_core_hash_insert(filter, "variable_progresssec", "1");
769 	switch_core_hash_insert(filter, "variable_progress_uepoch", "1");
770 	switch_core_hash_insert(filter, "variable_progress_media_uepoch", "1");
771 	switch_core_hash_insert(filter, "variable_start_uepoch", "1");
772 	switch_core_hash_insert(filter, "variable_digits_dialed", "1");
773 	switch_core_hash_insert(filter, "Member-ID", "1");
774 	switch_core_hash_insert(filter, "Floor", "1");
775 	switch_core_hash_insert(filter, "Video", "1");
776 	switch_core_hash_insert(filter, "Hear", "1");
777 	switch_core_hash_insert(filter, "Speak", "1");
778 	switch_core_hash_insert(filter, "Talking", "1");
779 	switch_core_hash_insert(filter, "Current-Energy", "1");
780 	switch_core_hash_insert(filter, "Energy-Level", "1");
781 	switch_core_hash_insert(filter, "Mute-Detect", "1");
782 
783 	/* RTMP headers */
784 	switch_core_hash_insert(filter, "RTMP-Session-ID", "1");
785 	switch_core_hash_insert(filter, "RTMP-Profile", "1");
786 	switch_core_hash_insert(filter, "RTMP-Flash-Version", "1");
787 	switch_core_hash_insert(filter, "RTMP-SWF-URL", "1");
788 	switch_core_hash_insert(filter, "RTMP-TC-URL", "1");
789 	switch_core_hash_insert(filter, "RTMP-Page-URL", "1");
790 	switch_core_hash_insert(filter, "User", "1");
791 	switch_core_hash_insert(filter, "Domain", "1");
792 
793 	/* Fax headers */
794 	switch_core_hash_insert(filter, "variable_fax_bad_rows", "1");
795 	switch_core_hash_insert(filter, "variable_fax_document_total_pages", "1");
796 	switch_core_hash_insert(filter, "variable_fax_document_transferred_pages", "1");
797 	switch_core_hash_insert(filter, "variable_fax_ecm_used", "1");
798 	switch_core_hash_insert(filter, "variable_fax_result_code", "1");
799 	switch_core_hash_insert(filter, "variable_fax_result_text", "1");
800 	switch_core_hash_insert(filter, "variable_fax_success", "1");
801 	switch_core_hash_insert(filter, "variable_fax_transfer_rate", "1");
802 	switch_core_hash_insert(filter, "variable_fax_local_station_id", "1");
803 	switch_core_hash_insert(filter, "variable_fax_remote_station_id", "1");
804 	switch_core_hash_insert(filter, "variable_fax_remote_country", "1");
805 	switch_core_hash_insert(filter, "variable_fax_remote_vendor", "1");
806 	switch_core_hash_insert(filter, "variable_fax_remote_model", "1");
807 	switch_core_hash_insert(filter, "variable_fax_image_resolution", "1");
808 	switch_core_hash_insert(filter, "variable_fax_file_image_resolution", "1");
809 	switch_core_hash_insert(filter, "variable_fax_image_size", "1");
810 	switch_core_hash_insert(filter, "variable_fax_image_pixel_size", "1");
811 	switch_core_hash_insert(filter, "variable_fax_file_image_pixel_size", "1");
812 	switch_core_hash_insert(filter, "variable_fax_longest_bad_row_run", "1");
813 	switch_core_hash_insert(filter, "variable_fax_encoding", "1");
814 	switch_core_hash_insert(filter, "variable_fax_encoding_name", "1");
815 	switch_core_hash_insert(filter, "variable_fax_header", "1");
816 	switch_core_hash_insert(filter, "variable_fax_ident", "1");
817 	switch_core_hash_insert(filter, "variable_fax_timezone", "1");
818 	switch_core_hash_insert(filter, "variable_fax_doc_id", "1");
819 	switch_core_hash_insert(filter, "variable_fax_doc_database", "1");
820 	switch_core_hash_insert(filter, "variable_has_t38", "1");
821 
822 	/* Secure headers */
823 	switch_core_hash_insert(filter, "variable_sdp_secure_savp_only", "1");
824 	switch_core_hash_insert(filter, "variable_rtp_has_crypto", "1");
825 	switch_core_hash_insert(filter, "variable_rtp_secure_media", "1");
826 	switch_core_hash_insert(filter, "variable_rtp_secure_media_confirmed", "1");
827 	switch_core_hash_insert(filter, "variable_rtp_secure_media_confirmed_audio", "1");
828 	switch_core_hash_insert(filter, "variable_rtp_secure_media_confirmed_video", "1");
829 	switch_core_hash_insert(filter, "variable_zrtp_secure_media", "1");
830 	switch_core_hash_insert(filter, "variable_zrtp_secure_media_confirmed", "1");
831 	switch_core_hash_insert(filter, "variable_zrtp_secure_media_confirmed_audio", "1");
832 	switch_core_hash_insert(filter, "variable_zrtp_secure_media_confirmed_video", "1");
833 	switch_core_hash_insert(filter, "sdp_secure_savp_only", "1");
834 	switch_core_hash_insert(filter, "rtp_has_crypto", "1");
835 	switch_core_hash_insert(filter, "rtp_secure_media", "1");
836 	switch_core_hash_insert(filter, "rtp_secure_media_confirmed", "1");
837 	switch_core_hash_insert(filter, "rtp_secure_media_confirmed_audio", "1");
838 	switch_core_hash_insert(filter, "rtp_secure_media_confirmed_video", "1");
839 	switch_core_hash_insert(filter, "zrtp_secure_media", "1");
840 	switch_core_hash_insert(filter, "zrtp_secure_media_confirmed", "1");
841 	switch_core_hash_insert(filter, "zrtp_secure_media_confirmed_audio", "1");
842 	switch_core_hash_insert(filter, "zrtp_secure_media_confirmed_video", "1");
843 
844 	/* Device Redirect headers */
845 	switch_core_hash_insert(filter, "variable_last_bridge_hangup_cause", "1");
846 	switch_core_hash_insert(filter, "variable_sip_redirected_by", "1");
847 	switch_core_hash_insert(filter, "intercepted_by", "1");
848 	switch_core_hash_insert(filter, "variable_bridge_uuid", "1");
849 	switch_core_hash_insert(filter, "Record-File-Path", "1");
850 
851 	/* Loopback headers */
852 	switch_core_hash_insert(filter, "variable_loopback_bowout_on_execute", "1");
853 	switch_core_hash_insert(filter, "variable_loopback_bowout", "1");
854 	switch_core_hash_insert(filter, "variable_other_loopback_leg_uuid", "1");
855 	switch_core_hash_insert(filter, "variable_loopback_leg", "1");
856 	switch_core_hash_insert(filter, "variable_is_loopback", "1");
857 
858 	// SMS
859 	switch_core_hash_insert(filter, "Message-ID", "1");
860 	switch_core_hash_insert(filter, "Delivery-Failure", "1");
861 	switch_core_hash_insert(filter, "Delivery-Result-Code", "1");
862 
863 	return filter;
864 }
865 
fetch_config_filters(switch_memory_pool_t * pool)866 static void fetch_config_filters(switch_memory_pool_t *pool)
867 {
868 	char *cf = "kazoo.conf";
869 	switch_xml_t cfg, xml, child, param;
870 	switch_event_t *params;
871 
872 	switch_event_create(&params, SWITCH_EVENT_REQUEST_PARAMS);
873 	switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "Action", "request-filter");
874 
875 	if (!(xml = switch_xml_open_cfg(cf, &cfg, params))) {
876 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to open configuration file %s\n", cf);
877 	} else {
878 		if ((child = switch_xml_child(cfg, "event-filter"))) {
879 			switch_hash_t *filter;
880 			switch_hash_t *old_filter;
881 
882 			switch_core_hash_init(&filter);
883 			for (param = switch_xml_child(child, "header"); param; param = param->next) {
884 				char *var = (char *) switch_xml_attr_soft(param, "name");
885 				switch_core_hash_insert(filter, var, "1");
886 			}
887 
888 			old_filter = kazoo_globals.event_filter;
889 			kazoo_globals.event_filter = filter;
890 			if (old_filter) {
891 				switch_core_hash_destroy(&old_filter);
892 			}
893 		}
894 
895 		kazoo_globals.config_fetched = 1;
896 		switch_xml_free(xml);
897 	}
898 	switch_event_destroy(&params);
899 
900 }
901 
fetch_config_handlers(switch_memory_pool_t * pool)902 static void fetch_config_handlers(switch_memory_pool_t *pool)
903 {
904 	char *cf = "kazoo.conf";
905 	switch_xml_t cfg, xml;
906 	switch_event_t *params;
907 
908 	switch_event_create(&params, SWITCH_EVENT_REQUEST_PARAMS);
909 	switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "Action", "request-handlers");
910 
911 	if (!(xml = switch_xml_open_cfg(cf, &cfg, params))) {
912 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to open configuration file %s\n", cf);
913 	} else {
914 		kazoo_config_handlers(cfg);
915 		kazoo_globals.config_fetched = 1;
916 		switch_xml_free(xml);
917 	}
918 	switch_event_destroy(&params);
919 
920 }
921 
fetch_config_exec(switch_thread_t * thread,void * obj)922 static void *SWITCH_THREAD_FUNC fetch_config_exec(switch_thread_t *thread, void *obj)
923 {
924 	switch_memory_pool_t *pool = (switch_memory_pool_t *) obj;
925 	ei_node_t *node;
926 	int fetch_filters = 0, fetch_handlers = 0;
927 
928 	// give some time for node initialization
929 	switch_sleep(kazoo_globals.delay_before_initial_fetch);
930 
931 	for (node = kazoo_globals.ei_nodes; node != NULL; node = node->next) {
932 		if (node->legacy ) {
933 			fetch_filters++;
934 		} else {
935 			fetch_handlers++;
936 		}
937 	}
938 
939 	if (fetch_filters) {
940 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "fetching filters for kazoo\n");
941 		fetch_config_filters(pool);
942 	}
943 
944 	if (fetch_handlers) {
945 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "fetching kazoo handlers\n");
946 		fetch_config_handlers(pool);
947 	}
948 
949 	kazoo_globals.config_fetched = 1;
950 
951 	return NULL;
952 }
953 
fetch_config()954 void fetch_config()
955 {
956 	switch_memory_pool_t *pool;
957 	switch_thread_t *thread;
958 	switch_threadattr_t *thd_attr = NULL;
959 	switch_uuid_t uuid;
960 
961 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "scheduling fetch for kazoo config\n");
962 
963 	switch_core_new_memory_pool(&pool);
964 
965 	switch_threadattr_create(&thd_attr, pool);
966 	switch_threadattr_detach_set(thd_attr, 1);
967 	switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
968 
969 	switch_uuid_get(&uuid);
970 	switch_thread_create(&thread, thd_attr, fetch_config_exec, pool, pool);
971 
972 }
973 
974 #ifdef WITH_KAZOO_ERL_SHUTDOWN
975 #if (ERLANG_MAJOR == 10 && ERLANG_MINOR >= 3) || ERLANG_MAJOR >= 11
976 typedef struct ei_mutex_s {
977 #ifdef __WIN32__
978 	HANDLE lock;
979 #elif VXWORKS
980 	SEM_ID lock;
981 #else /* unix */
982 #if defined(HAVE_MIT_PTHREAD_H) || defined(HAVE_PTHREAD_H)
983 	pthread_mutex_t *lock;
984 #else /* ! (HAVE_MIT_PTHREAD_H || HAVE_PTHREAD_H) */
985 	void *dummy; /* Actually never used */
986 #endif /* ! (HAVE_MIT_PTHREAD_H || HAVE_PTHREAD_H) */
987 #endif /* unix */
988 }ei_mutex_t;
989 
990 typedef struct ei_socket_info_s {
991 	int socket;
992 	ei_socket_callbacks *cbs;
993 	void *ctx;
994 	int dist_version;
995 	ei_cnode cnode; /* A copy, not a pointer. We don't know when freed */
996 	char cookie[EI_MAX_COOKIE_SIZE+1];
997 }ei_socket_info;
998 
999 extern ei_socket_info *ei_sockets;
1000 extern ei_mutex_t* ei_sockets_lock;
1001 extern int ei_n_sockets;
1002 extern int ei_sz_sockets;
1003 
1004 int ei_mutex_free(ei_mutex_t *l, int nblock);
1005 
1006 #endif
1007 #endif
1008 
kz_erl_init()1009 void kz_erl_init()
1010 {
1011 #if (ERLANG_MAJOR == 10 && ERLANG_MINOR >= 3) || ERLANG_MAJOR >= 11
1012 	ei_init();
1013 #endif
1014 }
1015 
kz_erl_shutdown()1016 void kz_erl_shutdown()
1017 {
1018 #ifdef WITH_KAZOO_ERL_SHUTDOWN
1019 #if (ERLANG_MAJOR == 10 && ERLANG_MINOR >= 3) || ERLANG_MAJOR >= 11
1020 	ei_mutex_free(ei_sockets_lock, 1);
1021 	ei_sockets_lock = NULL;
1022 	free(ei_sockets);
1023 	ei_sockets = NULL;
1024 	ei_n_sockets = ei_sz_sockets = 0;
1025 #endif
1026 #endif
1027 }
1028 
SWITCH_MODULE_RUNTIME_FUNCTION(mod_kazoo_runtime)1029 SWITCH_MODULE_RUNTIME_FUNCTION(mod_kazoo_runtime)
1030 {
1031 	switch_os_socket_t os_socket;
1032 
1033 	if (create_acceptor() != SWITCH_STATUS_SUCCESS) {
1034 		// TODO: what would we need to clean up here
1035 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to create erlang connection acceptor!\n");
1036 		close_socket(&kazoo_globals.acceptor);
1037 		return SWITCH_STATUS_TERM;
1038 	}
1039 
1040 	switch_atomic_inc(&kazoo_globals.threads);
1041 	switch_os_sock_get(&os_socket, kazoo_globals.acceptor);
1042 
1043 	while (switch_test_flag(&kazoo_globals, LFLAG_RUNNING)) {
1044 		int nodefd;
1045 		ErlConnect conn;
1046 
1047 		/* zero out errno because ei_accept doesn't differentiate between a */
1048 		/* failed authentication or a socket failure, or a client version */
1049 		/* mismatch or a godzilla attack (and a godzilla attack is highly likely) */
1050 		errno = 0;
1051 
1052 		/* wait here for an erlang node to connect, timming out to check if our module is still running every now-and-again */
1053 		if ((nodefd = ei_accept_tmo(&kazoo_globals.ei_cnode, (int) os_socket, &conn, kazoo_globals.connection_timeout)) == ERL_ERROR) {
1054 			if (erl_errno == ETIMEDOUT) {
1055 				continue;
1056 			} else if (errno) {
1057 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Erlang connection acceptor socket error %d %d\n", erl_errno, errno);
1058 			} else {
1059 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
1060 				                  "Erlang node connection failed - ensure your cookie matches '%s' and you are using a good nodename\n", kazoo_globals.ei_cookie);
1061 			}
1062 			continue;
1063 		}
1064 
1065 		if (!switch_test_flag(&kazoo_globals, LFLAG_RUNNING)) {
1066 			break;
1067 		}
1068 
1069 		/* NEW ERLANG NODE CONNECTION! Hello friend! */
1070 		new_kazoo_node(nodefd, &conn);
1071 	}
1072 
1073 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Erlang connection acceptor shut down\n");
1074 
1075 	switch_atomic_dec(&kazoo_globals.threads);
1076 
1077 	return SWITCH_STATUS_TERM;
1078 }
1079 
ei_queue_pop(switch_queue_t * queue,void ** data,switch_interval_time_t timeout)1080 SWITCH_DECLARE(switch_status_t) ei_queue_pop(switch_queue_t *queue, void **data, switch_interval_time_t timeout)
1081 {
1082 	if (timeout == 0) {
1083 		return switch_queue_trypop(queue, data);
1084 	} else {
1085 		return switch_queue_pop_timeout(queue, data, timeout);
1086 	}
1087 }
1088 /* For Emacs:
1089  * Local Variables:
1090  * mode:c
1091  * indent-tabs-mode:t
1092  * tab-width:4
1093  * c-basic-offset:4
1094  * End:
1095  * For VIM:
1096  * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
1097  */
1098