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(¶ms, 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(¶ms);
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(¶ms, 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(¶ms);
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