1 /*
2 * Freeswitch Modular Media Switching Software Library / Soft-Switch Application
3 * Copyright (C) 2005-2014, 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 * Seven Du <dujinfang@gmail.com>
28 *
29 * mod_verto.c -- HTML5 Verto interface
30 *
31 */
32 #include <switch.h>
33 #include <switch_json.h>
34 #include <switch_stun.h>
35
36
37 /* Prototypes */
38 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_verto_shutdown);
39 SWITCH_MODULE_LOAD_FUNCTION(mod_verto_load);
40 SWITCH_MODULE_RUNTIME_FUNCTION(mod_verto_runtime);
41
42 SWITCH_MODULE_DEFINITION(mod_verto, mod_verto_load, mod_verto_shutdown, mod_verto_runtime);
43
44 #define EP_NAME "verto.rtc"
45 //#define WSS_STANDALONE 1
46 #include "ws.h"
47
48 //////////////////////////
49 #include <mod_verto.h>
50 #ifndef WIN32
51 #include <sys/param.h>
52 #endif
53 #include <sys/stat.h>
54 #include <fcntl.h>
55 #ifndef WIN32
56 #include <sys/file.h>
57 #endif
58 #include <ctype.h>
59 #include <sys/stat.h>
60
61 #ifdef WIN32
62 #define strerror_r(errno, buf, len) strerror_s(buf, len, errno)
63 #endif
64
65 #define log_and_exit(severity, ...) switch_log_printf(SWITCH_CHANNEL_LOG, (severity), __VA_ARGS__); goto error
66 #define die(...) log_and_exit(SWITCH_LOG_WARNING, __VA_ARGS__)
67 #define die_errno(fmt) do { char errbuf[BUFSIZ] = {0}; strerror_r(errno, (char *)&errbuf, sizeof(errbuf)); die(fmt ", errno=%d, %s\n", errno, (char *)&errbuf); } while(0)
68 #define die_errnof(fmt, ...) do { char errbuf[BUFSIZ] = {0}; strerror_r(errno, (char *)&errbuf, sizeof(errbuf)); die(fmt ", errno=%d, %s\n", __VA_ARGS__, errno, (char *)&errbuf); } while(0)
69
70 static struct globals_s verto_globals;
71
72
73 static struct {
74 switch_mutex_t *store_mutex;
75 switch_hash_t *store_hash;
76 } json_GLOBALS;
77
78
79 const char json_sql[] =
80 "create table json_store (\n"
81 " name varchar(255) not null,\n"
82 " data text\n"
83 ");\n";
84
85
86 typedef enum {
87 CMD_ADD,
88 CMD_DEL,
89 CMD_DUMP,
90 CMD_COMMIT,
91 CMD_RETRIEVE
92 } store_cmd_t;
93
94 typedef struct {
95 switch_mutex_t *mutex;
96 cJSON *JSON_STORE;
97 } json_store_t;
98
json_cleanup(void)99 static void json_cleanup(void)
100 {
101 switch_hash_index_t *hi = NULL;
102 void *val;
103 const void *var;
104 cJSON *json;
105
106 if (!json_GLOBALS.store_hash) {
107 return;
108 }
109
110 switch_mutex_lock(json_GLOBALS.store_mutex);
111 top:
112
113 for (hi = switch_core_hash_first_iter(json_GLOBALS.store_hash, hi); hi;) {
114 switch_core_hash_this(hi, &var, NULL, &val);
115 json = (cJSON *) val;
116 cJSON_Delete(json);
117 switch_core_hash_delete(json_GLOBALS.store_hash, var);
118 goto top;
119 }
120 switch_safe_free(hi);
121
122 switch_mutex_unlock(json_GLOBALS.store_mutex);
123
124 }
125
check_name(const char * name)126 static switch_bool_t check_name(const char *name)
127 {
128 const char *p;
129
130 for(p = name; p && *p; p++) {
131 if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '-' || *p == '_') continue;
132 return SWITCH_FALSE;
133 }
134
135 return SWITCH_TRUE;
136 }
137
138
139 static switch_status_t verto_read_text_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
140 static switch_status_t verto_write_text_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
141 static void set_text_funcs(switch_core_session_t *session);
142
143 static verto_profile_t *find_profile(const char *name);
144 static jsock_t *get_jsock(const char *uuid);
145
verto_deinit_ssl(verto_profile_t * profile)146 static void verto_deinit_ssl(verto_profile_t *profile)
147 {
148 if (profile->ssl_ctx) {
149 SSL_CTX_free(profile->ssl_ctx);
150 profile->ssl_ctx = NULL;
151 }
152 }
153
close_file(ws_socket_t * sock)154 static void close_file(ws_socket_t *sock)
155 {
156 if (*sock != ws_sock_invalid) {
157 #ifndef WIN32
158 close(*sock);
159 #else
160 closesocket(*sock);
161 #endif
162 *sock = ws_sock_invalid;
163 }
164 }
165
close_socket(ws_socket_t * sock)166 static void close_socket(ws_socket_t *sock)
167 {
168 if (*sock != ws_sock_invalid) {
169 shutdown(*sock, 2);
170 close_file(sock);
171 }
172 }
173
174 void verto_broadcast(const char *event_channel, cJSON *json, const char *key, switch_event_channel_id_t id, void *user_data);
175
verto_init_ssl(verto_profile_t * profile)176 static int verto_init_ssl(verto_profile_t *profile)
177 {
178 const char *err = "";
179 int i = 0;
180
181 profile->ssl_method = SSLv23_server_method(); /* create server instance */
182 profile->ssl_ctx = SSL_CTX_new(profile->ssl_method); /* create context */
183 profile->ssl_ready = 1;
184 assert(profile->ssl_ctx);
185
186 /* Disable SSLv2 */
187 SSL_CTX_set_options(profile->ssl_ctx, SSL_OP_NO_SSLv2);
188 /* Disable SSLv3 */
189 SSL_CTX_set_options(profile->ssl_ctx, SSL_OP_NO_SSLv3);
190 /* Disable TLSv1 */
191 SSL_CTX_set_options(profile->ssl_ctx, SSL_OP_NO_TLSv1);
192 /* Disable Compression CRIME (Compression Ratio Info-leak Made Easy) */
193 SSL_CTX_set_options(profile->ssl_ctx, SSL_OP_NO_COMPRESSION);
194
195 /* set the local certificate from CertFile */
196 if (!zstr(profile->chain)) {
197 if (switch_file_exists(profile->chain, NULL) != SWITCH_STATUS_SUCCESS) {
198 err = "SUPPLIED CHAIN FILE NOT FOUND\n";
199 goto fail;
200 }
201
202 if (!SSL_CTX_use_certificate_chain_file(profile->ssl_ctx, profile->chain)) {
203 err = "CERT CHAIN FILE ERROR";
204 goto fail;
205 }
206 }
207
208 if (switch_file_exists(profile->cert, NULL) != SWITCH_STATUS_SUCCESS) {
209 err = "SUPPLIED CERT FILE NOT FOUND\n";
210 goto fail;
211 }
212
213 if (!SSL_CTX_use_certificate_file(profile->ssl_ctx, profile->cert, SSL_FILETYPE_PEM)) {
214 err = "CERT FILE ERROR";
215 goto fail;
216 }
217
218 /* set the private key from KeyFile */
219
220 if (switch_file_exists(profile->key, NULL) != SWITCH_STATUS_SUCCESS) {
221 err = "SUPPLIED KEY FILE NOT FOUND\n";
222 goto fail;
223 }
224
225 if (!SSL_CTX_use_PrivateKey_file(profile->ssl_ctx, profile->key, SSL_FILETYPE_PEM)) {
226 err = "PRIVATE KEY FILE ERROR";
227 goto fail;
228 }
229
230 /* verify private key */
231 if ( !SSL_CTX_check_private_key(profile->ssl_ctx) ) {
232 err = "PRIVATE KEY FILE ERROR";
233 goto fail;
234 }
235
236 SSL_CTX_set_cipher_list(profile->ssl_ctx, "HIGH:!DSS:!aNULL@STRENGTH");
237
238 return 1;
239
240 fail:
241 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SSL ERR: %s\n", err);
242
243 profile->ssl_ready = 0;
244 verto_deinit_ssl(profile);
245
246 for (i = 0; i < profile->i; i++) {
247 if (profile->ip[i].secure) {
248 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SSL NOT ENABLED FOR LISTENER %s:%d. REVERTING TO WS\n",
249 profile->ip[i].local_ip, profile->ip[i].local_port);
250 profile->ip[i].secure = 0;
251 }
252 }
253
254 return 0;
255
256 }
257
258
259 struct jsock_sub_node_head_s;
260
261 typedef struct jsock_sub_node_s {
262 jsock_t *jsock;
263 uint32_t serno;
264 struct jsock_sub_node_head_s *head;
265 struct jsock_sub_node_s *next;
266 } jsock_sub_node_t;
267
268 typedef struct jsock_sub_node_head_s {
269 jsock_sub_node_t *node;
270 jsock_sub_node_t *tail;
271 char *event_channel;
272 } jsock_sub_node_head_t;
273
jsock_unsub_head(jsock_t * jsock,jsock_sub_node_head_t * head)274 static uint32_t jsock_unsub_head(jsock_t *jsock, jsock_sub_node_head_t *head)
275 {
276 uint32_t x = 0;
277
278 jsock_sub_node_t *thisnp = NULL, *np, *last = NULL;
279
280 np = head->tail = head->node;
281
282 while (np) {
283
284 thisnp = np;
285 np = np->next;
286
287 if (!jsock || thisnp->jsock == jsock) {
288 x++;
289
290 if (last) {
291 last->next = np;
292 } else {
293 head->node = np;
294 }
295
296 if (thisnp->jsock->profile->debug || verto_globals.debug) {
297 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "UNSUBBING %s [%s]\n", thisnp->jsock->name, thisnp->head->event_channel);
298 }
299
300 thisnp->jsock = NULL;
301 free(thisnp);
302 } else {
303 last = thisnp;
304 head->tail = last;
305 }
306 }
307
308 return x;
309 }
310
311 static void detach_calls(jsock_t *jsock);
312
unsub_all_jsock(void)313 static void unsub_all_jsock(void)
314 {
315 switch_hash_index_t *hi;
316 void *val;
317 jsock_sub_node_head_t *head;
318
319 switch_thread_rwlock_wrlock(verto_globals.event_channel_rwlock);
320 top:
321 head = NULL;
322
323 for (hi = switch_core_hash_first(verto_globals.event_channel_hash); hi;) {
324 switch_core_hash_this(hi, NULL, NULL, &val);
325 head = (jsock_sub_node_head_t *) val;
326 jsock_unsub_head(NULL, head);
327 switch_core_hash_delete(verto_globals.event_channel_hash, head->event_channel);
328 free(head->event_channel);
329 free(head);
330 switch_safe_free(hi);
331 goto top;
332 }
333
334 switch_thread_rwlock_unlock(verto_globals.event_channel_rwlock);
335 }
336
jsock_unsub_channel(jsock_t * jsock,const char * event_channel)337 static uint32_t jsock_unsub_channel(jsock_t *jsock, const char *event_channel)
338 {
339 jsock_sub_node_head_t *head;
340 uint32_t x = 0;
341
342 switch_thread_rwlock_wrlock(verto_globals.event_channel_rwlock);
343
344 if (!event_channel) {
345 switch_hash_index_t *hi;
346 void *val;
347
348 for (hi = switch_core_hash_first(verto_globals.event_channel_hash); hi; hi = switch_core_hash_next(&hi)) {
349 switch_core_hash_this(hi, NULL, NULL, &val);
350
351 if (val) {
352 head = (jsock_sub_node_head_t *) val;
353 x += jsock_unsub_head(jsock, head);
354 }
355 }
356
357 } else {
358 if ((head = switch_core_hash_find(verto_globals.event_channel_hash, event_channel))) {
359 x += jsock_unsub_head(jsock, head);
360 }
361 }
362
363 switch_thread_rwlock_unlock(verto_globals.event_channel_rwlock);
364
365 return x;
366 }
367
presence_ping(const char * event_channel)368 static void presence_ping(const char *event_channel)
369 {
370 switch_console_callback_match_t *matches;
371 const char *val = event_channel;
372
373 if (val) {
374 if (!strcasecmp(val, "presence")) {
375 val = NULL;
376 } else {
377 char *p;
378 if ((p = strchr(val, '.'))) {
379 val = (p+1);
380 }
381 }
382 }
383
384 if ((matches = switch_core_session_findall_matching_var("presence_id", val))) {
385 switch_console_callback_match_node_t *m;
386 switch_core_session_t *session;
387
388 for (m = matches->head; m; m = m->next) {
389 if ((session = switch_core_session_locate(m->val))) {
390 switch_channel_t *channel = switch_core_session_get_channel(session);
391 switch_event_t *event;
392
393 if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_CALLSTATE) == SWITCH_STATUS_SUCCESS) {
394 switch_channel_callstate_t callstate = switch_channel_get_callstate(channel);
395
396 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Original-Channel-Call-State", switch_channel_callstate2str(callstate));
397 switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Channel-Call-State-Number", "%d", callstate);
398 switch_channel_event_set_data(channel, event);
399 switch_event_fire(&event);
400 }
401
402 switch_core_session_rwunlock(session);
403 }
404 }
405
406 switch_console_free_matches(&matches);
407 }
408 }
409
jsock_sub_channel(jsock_t * jsock,const char * event_channel)410 static switch_status_t jsock_sub_channel(jsock_t *jsock, const char *event_channel)
411 {
412 jsock_sub_node_t *node, *np;
413 jsock_sub_node_head_t *head;
414 switch_status_t status = SWITCH_STATUS_FALSE;
415
416 switch_thread_rwlock_wrlock(verto_globals.event_channel_rwlock);
417
418 if (!(head = switch_core_hash_find(verto_globals.event_channel_hash, event_channel))) {
419 switch_zmalloc(head, sizeof(*head));
420 head->event_channel = strdup(event_channel);
421 switch_core_hash_insert(verto_globals.event_channel_hash, event_channel, head);
422
423 switch_zmalloc(node, sizeof(*node));
424 node->jsock = jsock;
425 node->head = head;
426 head->node = node;
427 head->tail = node;
428 status = SWITCH_STATUS_SUCCESS;
429 } else {
430 int exist = 0;
431
432 for (np = head->node; np; np = np->next) {
433 if (np->jsock == jsock) {
434 exist = 1;
435 break;
436 }
437 }
438
439 if (!exist) {
440 switch_zmalloc(node, sizeof(*node));
441 node->jsock = jsock;
442 node->head = head;
443
444 if (!head->node) {
445 head->node = node;
446 head->tail = node;
447 } else {
448 head->tail->next = node;
449 head->tail = head->tail->next;
450 }
451 status = SWITCH_STATUS_SUCCESS;
452 }
453 }
454
455 switch_thread_rwlock_unlock(verto_globals.event_channel_rwlock);
456
457 if (status == SWITCH_STATUS_SUCCESS && !strncasecmp(event_channel, "presence", 8)) {
458 presence_ping(event_channel);
459 }
460
461 return status;
462 }
463
464 static uint32_t ID = 1;
465
del_jsock(jsock_t * jsock)466 static void del_jsock(jsock_t *jsock)
467 {
468 jsock_t *p, *last = NULL;
469
470 jsock_unsub_channel(jsock, NULL);
471 switch_event_channel_permission_clear(jsock->uuid_str);
472
473 switch_mutex_lock(jsock->profile->mutex);
474 for(p = jsock->profile->jsock_head; p; p = p->next) {
475 if (p == jsock) {
476 if (last) {
477 last->next = p->next;
478 } else {
479 jsock->profile->jsock_head = p->next;
480 }
481 jsock->profile->jsock_count--;
482 break;
483 }
484
485 last = p;
486 }
487 switch_mutex_unlock(jsock->profile->mutex);
488
489 }
490
add_jsock(jsock_t * jsock)491 static void add_jsock(jsock_t *jsock)
492 {
493
494 switch_mutex_lock(jsock->profile->mutex);
495 jsock->next = jsock->profile->jsock_head;
496 jsock->profile->jsock_head = jsock;
497 jsock->profile->jsock_count++;
498 switch_mutex_unlock(jsock->profile->mutex);
499
500 }
501
next_id(void)502 static uint32_t next_id(void)
503 {
504 uint32_t id;
505
506 switch_mutex_lock(verto_globals.mutex);
507 id = ID++;
508 switch_mutex_unlock(verto_globals.mutex);
509
510 return id;
511 }
512
jrpc_new(uint32_t id)513 static cJSON *jrpc_new(uint32_t id)
514 {
515 cJSON *obj = cJSON_CreateObject();
516 cJSON_AddItemToObject(obj, "jsonrpc", cJSON_CreateString("2.0"));
517
518 if (id) {
519 cJSON_AddItemToObject(obj, "id", cJSON_CreateNumber(id));
520 }
521
522 return obj;
523 }
524
jrpc_new_req(const char * method,const char * call_id,cJSON ** paramsP)525 static cJSON *jrpc_new_req(const char *method, const char *call_id, cJSON **paramsP)
526 {
527 cJSON *msg, *params = NULL;
528 uint32_t id = next_id();
529
530 msg = jrpc_new(id);
531
532 if (paramsP && *paramsP) {
533 params = *paramsP;
534 }
535
536 if (!params) {
537 params = cJSON_CreateObject();
538 }
539
540 cJSON_AddItemToObject(msg, "method", cJSON_CreateString(method));
541 cJSON_AddItemToObject(msg, "params", params);
542
543 if (call_id) {
544 cJSON_AddItemToObject(params, "callID", cJSON_CreateString(call_id));
545 }
546
547 if (paramsP) {
548 *paramsP = params;
549 }
550
551 return msg;
552 }
553
jrpc_add_id(cJSON * obj,cJSON * jid,const char * idstr,int id)554 static void jrpc_add_id(cJSON *obj, cJSON *jid, const char *idstr, int id)
555 {
556 if (jid) {
557 cJSON_AddItemToObject(obj, "id", cJSON_Duplicate(jid, 1));
558 } else if (idstr) {
559 cJSON_AddItemToObject(obj, "id", zstr(idstr) ? cJSON_CreateNull() : cJSON_CreateString(idstr));
560 } else {
561 cJSON_AddItemToObject(obj, "id", cJSON_CreateNumber(id));
562 }
563 }
564
jrpc_add_error(cJSON * obj,int code,const char * message,cJSON * jid)565 static void jrpc_add_error(cJSON *obj, int code, const char *message, cJSON *jid)
566 {
567 cJSON *error = cJSON_CreateObject();
568
569 cJSON_AddItemToObject(obj, "error", error);
570 cJSON_AddItemToObject(error, "code", cJSON_CreateNumber(code));
571 cJSON_AddItemToObject(error, "message", cJSON_CreateString(message));
572 if (!cJSON_GetObjectItem(obj, "id")) {
573 jrpc_add_id(obj, jid, "", 0);
574 }
575 }
576
jrpc_add_result(cJSON * obj,cJSON * result)577 static void jrpc_add_result(cJSON *obj, cJSON *result)
578 {
579 if (result) {
580 cJSON_AddItemToObject(obj, "result", result);
581 }
582 }
583
ws_write_json(jsock_t * jsock,cJSON ** json,switch_bool_t destroy)584 static switch_ssize_t ws_write_json(jsock_t *jsock, cJSON **json, switch_bool_t destroy)
585 {
586 char *json_text;
587 switch_ssize_t r = -1;
588
589 switch_assert(json);
590
591 if (!*json) {
592 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ALERT, "WRITE NULL JS ERROR %" SWITCH_SIZE_T_FMT "\n", r);
593 return r;
594 }
595
596 if (!zstr(jsock->uuid_str)) {
597 cJSON *result = cJSON_GetObjectItem(*json, "result");
598
599 if (result) {
600 cJSON_AddItemToObject(result, "sessid", cJSON_CreateString(jsock->uuid_str));
601 }
602 }
603
604 if ((json_text = cJSON_PrintUnformatted(*json))) {
605 if (jsock->profile->debug || verto_globals.debug) {
606 char *log_text = cJSON_Print(*json);
607 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "WRITE %s [%s]\n", jsock->name, log_text);
608 free(log_text);
609 }
610 switch_mutex_lock(jsock->write_mutex);
611 r = ws_write_frame(&jsock->ws, WSOC_TEXT, json_text, strlen(json_text));
612 switch_mutex_unlock(jsock->write_mutex);
613 switch_safe_free(json_text);
614 }
615
616 if (destroy) {
617 cJSON_Delete(*json);
618 *json = NULL;
619 }
620
621 if (r <= 0) {
622 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ALERT, "WRITE RETURNED ERROR %" SWITCH_SIZE_T_FMT " \n", r);
623 jsock->drop = 1;
624 jsock->ready = 0;
625 }
626
627 return r;
628 }
629
jsock_queue_event(jsock_t * jsock,cJSON ** json,switch_bool_t destroy)630 static switch_status_t jsock_queue_event(jsock_t *jsock, cJSON **json, switch_bool_t destroy)
631 {
632 switch_status_t status = SWITCH_STATUS_FALSE;
633 cJSON *jp;
634
635 if (destroy) {
636 jp = *json;
637 } else {
638 jp = cJSON_Duplicate(*json, 1);
639 }
640
641 if (switch_queue_trypush(jsock->event_queue, jp) == SWITCH_STATUS_SUCCESS) {
642 status = SWITCH_STATUS_SUCCESS;
643
644 if (jsock->lost_events) {
645 int le = jsock->lost_events;
646 jsock->lost_events = 0;
647 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Lost %d json events!\n", le);
648 }
649 } else {
650 if (++jsock->lost_events > MAX_MISSED) {
651 jsock->drop++;
652 }
653
654 if (!destroy) {
655 cJSON_Delete(jp);
656 jp = NULL;
657 }
658 }
659
660 if (destroy) {
661 *json = NULL;
662 }
663
664 return status;
665 }
666
write_event(const char * event_channel,jsock_t * use_jsock,cJSON * event)667 static void write_event(const char *event_channel, jsock_t *use_jsock, cJSON *event)
668 {
669 jsock_sub_node_head_t *head;
670
671 if ((head = switch_core_hash_find(verto_globals.event_channel_hash, event_channel))) {
672 jsock_sub_node_t *np;
673
674 for(np = head->node; np; np = np->next) {
675 cJSON *msg = NULL, *params;
676
677 if (!use_jsock || use_jsock == np->jsock) {
678 params = cJSON_Duplicate(event, 1);
679 cJSON_AddItemToObject(params, "eventSerno", cJSON_CreateNumber(np->serno++));
680 msg = jrpc_new_req("verto.event", NULL, ¶ms);
681 jsock_queue_event(np->jsock, &msg, SWITCH_TRUE);
682 }
683 }
684 }
685 }
686
jsock_send_event(cJSON * event)687 static void jsock_send_event(cJSON *event)
688 {
689
690 const char *event_channel, *session_uuid = NULL;
691 jsock_t *use_jsock = NULL;
692 switch_core_session_t *session = NULL;
693
694 if (!(event_channel = cJSON_GetObjectCstr(event, "eventChannel"))) {
695 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NO EVENT CHANNEL SPECIFIED\n");
696 return;
697 }
698
699
700 if ((session = switch_core_session_locate(event_channel))) {
701 switch_channel_t *channel = switch_core_session_get_channel(session);
702 const char *jsock_uuid_str = switch_channel_get_variable(channel, "jsock_uuid_str");
703 if (jsock_uuid_str) {
704 use_jsock = get_jsock(jsock_uuid_str);
705 }
706 switch_core_session_rwunlock(session);
707 }
708
709 if (use_jsock || (use_jsock = get_jsock(event_channel))) { /* implicit subscription to channel identical to the connection uuid or session uuid */
710 cJSON *msg = NULL, *params;
711 params = cJSON_Duplicate(event, 1);
712 msg = jrpc_new_req("verto.event", NULL, ¶ms);
713 jsock_queue_event(use_jsock, &msg, SWITCH_TRUE);
714 switch_thread_rwlock_unlock(use_jsock->rwlock);
715 use_jsock = NULL;
716 return;
717 }
718
719
720 if ((session_uuid = cJSON_GetObjectCstr(event, "sessid"))) {
721 if (!(use_jsock = get_jsock(session_uuid))) {
722 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Socket %s not connected\n", session_uuid);
723 return;
724 }
725 }
726
727 switch_thread_rwlock_rdlock(verto_globals.event_channel_rwlock);
728 write_event(event_channel, use_jsock, event);
729 if (strchr(event_channel, '.')) {
730 char *main_channel = strdup(event_channel);
731 char *p;
732 switch_assert(main_channel);
733 p = strchr(main_channel, '.');
734 if (p) *p = '\0';
735 write_event(main_channel, use_jsock, event);
736 free(main_channel);
737 }
738 switch_thread_rwlock_unlock(verto_globals.event_channel_rwlock);
739
740 if (use_jsock) {
741 switch_thread_rwlock_unlock(use_jsock->rwlock);
742 use_jsock = NULL;
743 }
744 }
745
jrpc_get_func(jsock_t * jsock,const char * method)746 static jrpc_func_t jrpc_get_func(jsock_t *jsock, const char *method)
747 {
748 jrpc_func_t func = NULL;
749 char *main_method = NULL;
750
751 switch_assert(method);
752
753 if (jsock->allowed_methods) {
754 if (strchr(method, '.')) {
755 char *p;
756 main_method = strdup(method);
757 switch_assert(main_method);
758 if ((p = strchr(main_method, '.'))) {
759 *p = '\0';
760 }
761 }
762
763 if (!(switch_event_get_header(jsock->allowed_methods, method) || (main_method && switch_event_get_header(jsock->allowed_methods, main_method)))) {
764 goto end;
765 }
766 }
767
768 switch_mutex_lock(verto_globals.method_mutex);
769 func = (jrpc_func_t) (intptr_t) switch_core_hash_find(verto_globals.method_hash, method);
770 switch_mutex_unlock(verto_globals.method_mutex);
771
772 end:
773
774 switch_safe_free(main_method);
775
776 return func;
777 }
778
779
jrpc_add_func(const char * method,jrpc_func_t func)780 static void jrpc_add_func(const char *method, jrpc_func_t func)
781 {
782 switch_assert(method);
783 switch_assert(func);
784
785 switch_mutex_lock(verto_globals.method_mutex);
786 switch_core_hash_insert(verto_globals.method_hash, method, (void *) (intptr_t) func);
787 switch_mutex_unlock(verto_globals.method_mutex);
788 }
789
790 static char *MARKER = "X";
791
set_perm(const char * str,switch_event_t ** event)792 static void set_perm(const char *str, switch_event_t **event)
793 {
794 char delim = ',';
795 char *cur, *next;
796 int count = 0;
797 char *edup;
798
799 if (!zstr(str)) {
800 if (!strcasecmp(str, "__ANY__")) {
801 return;
802 }
803 }
804
805 switch_event_create(event, SWITCH_EVENT_REQUEST_PARAMS);
806
807 if (!zstr(str)) {
808 edup = strdup(str);
809 switch_assert(edup);
810
811 if (strchr(edup, ' ')) {
812 delim = ' ';
813 }
814
815 for (cur = edup; cur; count++) {
816 if ((next = strchr(cur, delim))) {
817 *next++ = '\0';
818 }
819
820 switch_event_add_header_string(*event, SWITCH_STACK_BOTTOM, cur, MARKER);
821
822 cur = next;
823 }
824
825 switch_safe_free(edup);
826
827 }
828 }
829
check_permissions(jsock_t * jsock,switch_xml_t x_user,cJSON * params)830 static void check_permissions(jsock_t *jsock, switch_xml_t x_user, cJSON *params)
831 {
832 switch_xml_t x_param, x_params;
833 const char *allowed_methods = NULL, *allowed_jsapi = NULL, *allowed_fsapi = NULL, *allowed_event_channels = NULL;
834
835 if ((x_params = switch_xml_child(x_user, "params"))) {
836 for (x_param = switch_xml_child(x_params, "param"); x_param; x_param = x_param->next) {
837 const char *var = switch_xml_attr(x_param, "name");
838 const char *val = switch_xml_attr(x_param, "value");
839
840 if (zstr(val) || zstr(var)) {
841 continue;
842 }
843
844 if (!strcasecmp(var, "jsonrpc-allowed-methods")) {
845 allowed_methods = val;
846 }
847
848 if (!strcasecmp(var, "jsonrpc-allowed-jsapi")) {
849 allowed_jsapi = val;
850 }
851
852 if (!strcasecmp(var, "jsonrpc-allowed-fsapi")) {
853 allowed_fsapi = val;
854 }
855
856 if (!strcasecmp(var, "jsonrpc-allowed-event-channels")) {
857 allowed_event_channels = val;
858 }
859 }
860 }
861
862
863 set_perm(allowed_methods, &jsock->allowed_methods);
864 set_perm(allowed_jsapi, &jsock->allowed_jsapi);
865 set_perm(allowed_fsapi, &jsock->allowed_fsapi);
866 set_perm(allowed_event_channels, &jsock->allowed_event_channels);
867
868 switch_event_add_header_string(jsock->allowed_methods, SWITCH_STACK_BOTTOM, "login", MARKER);
869
870 }
871
login_fire_custom_event(jsock_t * jsock,cJSON * params,int success,const char * result_txt)872 static void login_fire_custom_event(jsock_t *jsock, cJSON *params, int success, const char *result_txt)
873 {
874 switch_event_t *s_event;
875
876 if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_LOGIN) == SWITCH_STATUS_SUCCESS) {
877 switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "verto_profile_name", jsock->profile->name);
878 switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "verto_client_address", jsock->name);
879 if (params) {
880 switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "verto_login", cJSON_GetObjectCstr(params, "login"));
881 if (success) {
882 switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "verto_sessid", cJSON_GetObjectCstr(params, "sessid"));
883 }
884 }
885 switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "verto_success", "%d", success);
886 switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "verto_result_txt", result_txt);
887 switch_event_fire(&s_event);
888 }
889 }
890
check_auth(jsock_t * jsock,cJSON * params,int * code,char * message,switch_size_t mlen)891 static switch_bool_t check_auth(jsock_t *jsock, cJSON *params, int *code, char *message, switch_size_t mlen)
892 {
893 switch_bool_t r = SWITCH_FALSE;
894 const char *passwd = NULL;
895 const char *login = NULL;
896 cJSON *json_ptr = NULL;
897 char *input = NULL;
898 char *a1_hash = NULL;
899 char a1_hash_buff[33] = "";
900
901 if (!params) {
902 *code = CODE_AUTH_FAILED;
903 switch_snprintf(message, mlen, "Missing params");
904 goto end;
905 }
906
907 login = cJSON_GetObjectCstr(params, "login");
908 passwd = cJSON_GetObjectCstr(params, "passwd");
909
910 if (zstr(login)) {
911 goto end;
912 }
913
914 if (zstr(passwd)) {
915 *code = CODE_AUTH_FAILED;
916 switch_snprintf(message, mlen, "Missing passwd");
917 login_fire_custom_event(jsock, params, 0, "Missing passwd");
918 goto end;
919 }
920
921
922 if (!strcmp(login, "root") && jsock->profile->root_passwd) {
923 if (!(r = !strcmp(passwd, jsock->profile->root_passwd))) {
924 *code = CODE_AUTH_FAILED;
925 switch_snprintf(message, mlen, "Authentication Failure");
926 login_fire_custom_event(jsock, params, 0, "Authentication Failure");
927 }
928
929 } else if (!zstr(jsock->profile->userauth)) {
930 switch_xml_t x_user = NULL;
931 char *id = NULL, *domain = NULL;
932 switch_event_t *req_params;
933
934 if (*jsock->profile->userauth == '@') {
935 domain = jsock->profile->userauth + 1;
936 id = (char *) login;
937 } else if (switch_true(jsock->profile->userauth)) {
938 id = switch_core_strdup(jsock->pool, login);
939
940 if ((domain = strchr(id, '@'))) {
941 *domain++ = '\0';
942 }
943
944 }
945
946 if (jsock->profile->register_domain) {
947 domain = jsock->profile->register_domain;
948 }
949
950 if (!(id && domain)) {
951 *code = CODE_AUTH_FAILED;
952 switch_snprintf(message, mlen, "Missing or improper credentials");
953 goto end;
954 }
955
956 switch_event_create(&req_params, SWITCH_EVENT_REQUEST_PARAMS);
957 switch_assert(req_params);
958
959 if ((json_ptr = cJSON_GetObjectItem(params, "loginParams"))) {
960 cJSON * i;
961
962 for(i = json_ptr->child; i; i = i->next) {
963 if (i->type == cJSON_True) {
964 switch_event_add_header_string(req_params, SWITCH_STACK_BOTTOM, i->string, "true");
965 } else if (i->type == cJSON_False) {
966 switch_event_add_header_string(req_params, SWITCH_STACK_BOTTOM, i->string, "false");
967 } else if (!zstr(i->string) && !zstr(i->valuestring)) {
968 switch_event_add_header_string(req_params, SWITCH_STACK_BOTTOM, i->string, i->valuestring);
969 }
970 }
971 }
972
973
974 if ((json_ptr = cJSON_GetObjectItem(params, "userVariables"))) {
975 cJSON * i;
976
977 for(i = json_ptr->child; i; i = i->next) {
978 if (i->type == cJSON_True) {
979 switch_event_add_header_string(jsock->user_vars, SWITCH_STACK_BOTTOM, i->string, "true");
980 } else if (i->type == cJSON_False) {
981 switch_event_add_header_string(jsock->user_vars, SWITCH_STACK_BOTTOM, i->string, "false");
982 } else if (!zstr(i->string) && !zstr(i->valuestring)) {
983 switch_event_add_header_string(jsock->user_vars, SWITCH_STACK_BOTTOM, i->string, i->valuestring);
984 }
985 }
986 }
987
988 switch_event_add_header_string(req_params, SWITCH_STACK_BOTTOM, "action", "jsonrpc-authenticate");
989
990 if (switch_xml_locate_user_merged("id", id, domain, NULL, &x_user, req_params) != SWITCH_STATUS_SUCCESS && !jsock->profile->blind_reg) {
991 *code = CODE_AUTH_FAILED;
992 switch_snprintf(message, mlen, "Login Incorrect");
993 login_fire_custom_event(jsock, params, 0, "Login Incorrect");
994 } else {
995 switch_xml_t x_param, x_params;
996 const char *use_passwd = NULL, *verto_context = NULL, *verto_dialplan = NULL;
997
998 jsock->id = switch_core_strdup(jsock->pool, id);
999 jsock->domain = switch_core_strdup(jsock->pool, domain);
1000 jsock->uid = switch_core_sprintf(jsock->pool, "%s@%s", id, domain);
1001 jsock->ready = 1;
1002
1003 if (!x_user) {
1004 switch_event_destroy(&req_params);
1005 r = SWITCH_TRUE;
1006 goto end;
1007 }
1008
1009 if ((x_params = switch_xml_child(x_user, "params"))) {
1010 for (x_param = switch_xml_child(x_params, "param"); x_param; x_param = x_param->next) {
1011 const char *var = switch_xml_attr_soft(x_param, "name");
1012 const char *val = switch_xml_attr_soft(x_param, "value");
1013
1014 if (!use_passwd && !strcasecmp(var, "password")) {
1015 use_passwd = val;
1016 } else if (!strcasecmp(var, "jsonrpc-password")) {
1017 use_passwd = val;
1018 } else if (!strcasecmp(var, "a1-hash")) {
1019 use_passwd = val;
1020 input = switch_mprintf("%s:%s:%s", id, domain, passwd);
1021 switch_md5_string(a1_hash_buff, (void *) input, strlen(input));
1022 a1_hash = a1_hash_buff;
1023 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"a1-hash-plain = '%s' a1-hash-md5 = '%s'\n", input, a1_hash);
1024 switch_safe_free(input);
1025 } else if (!strcasecmp(var, "verto-context")) {
1026 verto_context = val;
1027 } else if (!strcasecmp(var, "verto-dialplan")) {
1028 verto_dialplan = val;
1029 }
1030
1031 switch_event_add_header_string(jsock->params, SWITCH_STACK_BOTTOM, var, val);
1032 }
1033 }
1034
1035 if ((x_params = switch_xml_child(x_user, "variables"))) {
1036 for (x_param = switch_xml_child(x_params, "variable"); x_param; x_param = x_param->next) {
1037 const char *var = switch_xml_attr_soft(x_param, "name");
1038 const char *val = switch_xml_attr_soft(x_param, "value");
1039
1040 switch_event_add_header_string(jsock->vars, SWITCH_STACK_BOTTOM, var, val);
1041 }
1042 }
1043
1044 if (!zstr(verto_dialplan)) {
1045 jsock->dialplan = switch_core_strdup(jsock->pool, verto_dialplan);
1046 }
1047
1048 if (!zstr(verto_context)) {
1049 jsock->context = switch_core_strdup(jsock->pool, verto_context);
1050 }
1051
1052
1053 if (zstr(use_passwd) || strcmp(a1_hash ? a1_hash : passwd, use_passwd)) {
1054 r = SWITCH_FALSE;
1055 *code = CODE_AUTH_FAILED;
1056 switch_snprintf(message, mlen, "Authentication Failure");
1057 jsock->uid = NULL;
1058 login_fire_custom_event(jsock, params, 0, "Authentication Failure");
1059 } else {
1060 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"auth using %s\n",a1_hash ? "a1-hash" : "username & password");
1061 r = SWITCH_TRUE;
1062 check_permissions(jsock, x_user, params);
1063 }
1064
1065
1066
1067 switch_xml_free(x_user);
1068 }
1069
1070 switch_event_destroy(&req_params);
1071 }
1072
1073 end:
1074
1075 return r;
1076
1077 }
1078
set_call_params(cJSON * params,verto_pvt_t * tech_pvt)1079 static void set_call_params(cJSON *params, verto_pvt_t *tech_pvt) {
1080 const char *caller_id_name = NULL;
1081 const char *caller_id_number = NULL;
1082 const char *callee_id_name = NULL;
1083 const char *callee_id_number = NULL;
1084 const char *prefix = "verto_h_";
1085 switch_event_header_t *var = NULL;
1086
1087 caller_id_name = switch_channel_get_variable(tech_pvt->channel, "caller_id_name");
1088 caller_id_number = switch_channel_get_variable(tech_pvt->channel, "caller_id_number");
1089 callee_id_name = switch_channel_get_variable(tech_pvt->channel, "callee_id_name");
1090 callee_id_number = switch_channel_get_variable(tech_pvt->channel, "callee_id_number");
1091
1092 if (caller_id_name) cJSON_AddItemToObject(params, "caller_id_name", cJSON_CreateString(caller_id_name));
1093 if (caller_id_number) cJSON_AddItemToObject(params, "caller_id_number", cJSON_CreateString(caller_id_number));
1094
1095 if (callee_id_name) cJSON_AddItemToObject(params, "callee_id_name", cJSON_CreateString(callee_id_name));
1096 if (callee_id_number) cJSON_AddItemToObject(params, "callee_id_number", cJSON_CreateString(callee_id_number));
1097
1098 cJSON_AddItemToObject(params, "display_direction",
1099 cJSON_CreateString(switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_OUTBOUND ? "outbound" : "inbound"));
1100
1101 for (var = switch_channel_variable_first(tech_pvt->channel); var; var = var->next) {
1102 const char *name = (char *) var->name;
1103 char *value = (char *) var->value;
1104 if (!strncasecmp(name, prefix, strlen(prefix))) {
1105 cJSON_AddItemToObject(params, name, cJSON_CreateString(value));
1106 }
1107 }
1108 switch_channel_variable_last(tech_pvt->channel);
1109
1110 }
1111
get_jsock(const char * uuid)1112 static jsock_t *get_jsock(const char *uuid)
1113 {
1114 jsock_t *jsock = NULL;
1115
1116 switch_mutex_lock(verto_globals.jsock_mutex);
1117 if ((jsock = switch_core_hash_find(verto_globals.jsock_hash, uuid))) {
1118 if (switch_thread_rwlock_tryrdlock(jsock->rwlock) != SWITCH_STATUS_SUCCESS) {
1119 jsock = NULL;
1120 }
1121 }
1122 switch_mutex_unlock(verto_globals.jsock_mutex);
1123
1124 return jsock;
1125 }
1126
attach_jsock(jsock_t * jsock)1127 static void attach_jsock(jsock_t *jsock)
1128 {
1129 jsock_t *jp;
1130 int proceed = 1;
1131
1132 switch_mutex_lock(verto_globals.jsock_mutex);
1133
1134 switch_assert(jsock);
1135
1136 if ((jp = switch_core_hash_find(verto_globals.jsock_hash, jsock->uuid_str))) {
1137 if (jp == jsock) {
1138 proceed = 0;
1139 } else {
1140 cJSON *params = NULL;
1141 cJSON *msg = NULL;
1142 msg = jrpc_new_req("verto.punt", NULL, ¶ms);
1143 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "New connection for session %s dropping previous connection.\n", jsock->uuid_str);
1144 switch_core_hash_delete(verto_globals.jsock_hash, jsock->uuid_str);
1145 ws_write_json(jp, &msg, SWITCH_TRUE);
1146 cJSON_Delete(msg);
1147 jp->nodelete = 1;
1148 jp->drop = 1;
1149 }
1150 }
1151
1152 if (proceed) {
1153 switch_core_hash_insert(verto_globals.jsock_hash, jsock->uuid_str, jsock);
1154 }
1155
1156 switch_mutex_unlock(verto_globals.jsock_mutex);
1157 }
1158
detach_jsock(jsock_t * jsock)1159 static void detach_jsock(jsock_t *jsock)
1160 {
1161 if (jsock->nodelete) {
1162 return;
1163 }
1164
1165 switch_mutex_lock(verto_globals.jsock_mutex);
1166 switch_core_hash_delete(verto_globals.jsock_hash, jsock->uuid_str);
1167 switch_mutex_unlock(verto_globals.jsock_mutex);
1168 }
1169
attach_wake(void)1170 static int attach_wake(void)
1171 {
1172 switch_status_t status;
1173 int tries = 0;
1174
1175 top:
1176
1177 status = switch_mutex_trylock(verto_globals.detach_mutex);
1178
1179 if (status == SWITCH_STATUS_SUCCESS) {
1180 switch_thread_cond_signal(verto_globals.detach_cond);
1181 switch_mutex_unlock(verto_globals.detach_mutex);
1182 return 1;
1183 } else {
1184 if (switch_mutex_trylock(verto_globals.detach2_mutex) == SWITCH_STATUS_SUCCESS) {
1185 switch_mutex_unlock(verto_globals.detach2_mutex);
1186 } else {
1187 if (++tries < 10) {
1188 switch_cond_next();
1189 goto top;
1190 }
1191 }
1192 }
1193
1194 return 0;
1195 }
1196
tech_reattach(verto_pvt_t * tech_pvt,jsock_t * jsock)1197 static void tech_reattach(verto_pvt_t *tech_pvt, jsock_t *jsock)
1198 {
1199 cJSON *params = NULL;
1200 cJSON *msg = NULL;
1201
1202 tech_pvt->detach_time = 0;
1203 verto_globals.detached--;
1204 attach_wake();
1205 switch_set_flag(tech_pvt, TFLAG_ATTACH_REQ);
1206 msg = jrpc_new_req("verto.attach", tech_pvt->call_id, ¶ms);
1207
1208 switch_channel_set_flag(tech_pvt->channel, CF_REINVITE);
1209 switch_channel_set_flag(tech_pvt->channel, CF_RECOVERING);
1210 switch_core_media_gen_local_sdp(tech_pvt->session, SDP_TYPE_REQUEST, NULL, 0, NULL, 0);
1211 switch_channel_clear_flag(tech_pvt->channel, CF_REINVITE);
1212 switch_channel_clear_flag(tech_pvt->channel, CF_RECOVERING);
1213 switch_core_session_request_video_refresh(tech_pvt->session);
1214
1215 cJSON_AddItemToObject(params, "sdp", cJSON_CreateString(tech_pvt->mparams->local_sdp_str));
1216 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Local attach SDP %s:\n%s\n",
1217 switch_channel_get_name(tech_pvt->channel),
1218 tech_pvt->mparams->local_sdp_str);
1219 set_call_params(params, tech_pvt);
1220 jsock_queue_event(jsock, &msg, SWITCH_TRUE);
1221 }
1222
drop_detached(void)1223 static void drop_detached(void)
1224 {
1225 verto_pvt_t *tech_pvt;
1226 switch_time_t now = switch_epoch_time_now(NULL);
1227
1228 switch_thread_rwlock_rdlock(verto_globals.tech_rwlock);
1229 for(tech_pvt = verto_globals.tech_head; tech_pvt; tech_pvt = tech_pvt->next) {
1230 if (!switch_channel_up_nosig(tech_pvt->channel)) {
1231 continue;
1232 }
1233
1234 if (tech_pvt->detach_time && (now - tech_pvt->detach_time) > verto_globals.detach_timeout) {
1235 switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE);
1236 }
1237 }
1238 switch_thread_rwlock_unlock(verto_globals.tech_rwlock);
1239 }
1240
attach_calls(jsock_t * jsock)1241 static void attach_calls(jsock_t *jsock)
1242 {
1243 verto_pvt_t *tech_pvt;
1244 cJSON *msg = NULL;
1245 cJSON *params = NULL;
1246 cJSON *reattached_sessions = NULL;
1247
1248 reattached_sessions = cJSON_CreateArray();
1249
1250 switch_thread_rwlock_rdlock(verto_globals.tech_rwlock);
1251 for(tech_pvt = verto_globals.tech_head; tech_pvt; tech_pvt = tech_pvt->next) {
1252 if (tech_pvt->detach_time && !strcmp(tech_pvt->jsock_uuid, jsock->uuid_str)) {
1253 if (!switch_channel_up_nosig(tech_pvt->channel)) {
1254 continue;
1255 }
1256
1257 tech_reattach(tech_pvt, jsock);
1258 cJSON_AddItemToArray(reattached_sessions, cJSON_CreateString(jsock->uuid_str));
1259 }
1260 }
1261 switch_thread_rwlock_unlock(verto_globals.tech_rwlock);
1262
1263 msg = jrpc_new_req("verto.clientReady", NULL, ¶ms);
1264 cJSON_AddItemToObject(params, "reattached_sessions", reattached_sessions);
1265 jsock_queue_event(jsock, &msg, SWITCH_TRUE);
1266 }
1267
detach_calls(jsock_t * jsock)1268 static void detach_calls(jsock_t *jsock)
1269 {
1270 verto_pvt_t *tech_pvt;
1271 int wake = 0;
1272
1273 switch_thread_rwlock_rdlock(verto_globals.tech_rwlock);
1274 for(tech_pvt = verto_globals.tech_head; tech_pvt; tech_pvt = tech_pvt->next) {
1275 if (!strcmp(tech_pvt->jsock_uuid, jsock->uuid_str)) {
1276 if (!switch_channel_up_nosig(tech_pvt->channel)) {
1277 continue;
1278 }
1279
1280 if (!switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED)) {
1281 switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
1282 continue;
1283 }
1284
1285 if (switch_channel_test_flag(tech_pvt->channel, CF_VIDEO_ONLY)) {
1286 switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_NORMAL_CLEARING);
1287 continue;
1288 }
1289
1290 switch_core_session_stop_media(tech_pvt->session);
1291 tech_pvt->detach_time = switch_epoch_time_now(NULL);
1292 verto_globals.detached++;
1293 wake = 1;
1294 }
1295 }
1296 switch_thread_rwlock_unlock(verto_globals.tech_rwlock);
1297
1298 if (wake) attach_wake();
1299 }
1300
process_jrpc_response(jsock_t * jsock,cJSON * json)1301 static void process_jrpc_response(jsock_t *jsock, cJSON *json)
1302 {
1303 }
1304
set_session_id(jsock_t * jsock,const char * uuid)1305 static void set_session_id(jsock_t *jsock, const char *uuid)
1306 {
1307 //cJSON *params, *msg = jrpc_new(0);
1308
1309 if (!zstr(uuid)) {
1310 switch_set_string(jsock->uuid_str, uuid);
1311 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s re-connecting session %s\n", jsock->name, jsock->uuid_str);
1312 } else {
1313 switch_uuid_str(jsock->uuid_str, sizeof(jsock->uuid_str));
1314 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s new RPC session %s\n", jsock->name, jsock->uuid_str);
1315 }
1316
1317 attach_jsock(jsock);
1318
1319 }
1320
process_jrpc(jsock_t * jsock,cJSON * json)1321 static cJSON *process_jrpc(jsock_t *jsock, cJSON *json)
1322 {
1323 cJSON *reply = NULL, *echo = NULL, *id = NULL, *params = NULL, *response = NULL, *result;
1324 const char *method = NULL, *version = NULL, *sessid = NULL;
1325 jrpc_func_t func = NULL;
1326
1327 switch_assert(json);
1328
1329 method = cJSON_GetObjectCstr(json, "method");
1330 result = cJSON_GetObjectItem(json, "result");
1331 version = cJSON_GetObjectCstr(json, "jsonrpc");
1332 id = cJSON_GetObjectItem(json, "id");
1333
1334 if ((params = cJSON_GetObjectItem(json, "params"))) {
1335 sessid = cJSON_GetObjectCstr(params, "sessid");
1336 }
1337
1338 if (!switch_test_flag(jsock, JPFLAG_INIT)) {
1339 set_session_id(jsock, sessid);
1340 switch_set_flag(jsock, JPFLAG_INIT);
1341 }
1342
1343 if (zstr(version) || strcmp(version, "2.0")) {
1344 reply = jrpc_new(0);
1345 jrpc_add_error(reply, CODE_INVALID, "Invalid message", id);
1346 goto end;
1347 }
1348
1349 if (result) {
1350 process_jrpc_response(jsock, json);
1351 return NULL;
1352 }
1353
1354 reply = jrpc_new(0);
1355
1356 jrpc_add_id(reply, id, "", 0);
1357
1358 if (!switch_test_flag(jsock, JPFLAG_AUTHED) && (jsock->profile->userauth || jsock->profile->root_passwd)) {
1359 int code = CODE_AUTH_REQUIRED;
1360 char message[128] = "Authentication Required";
1361
1362 if (!check_auth(jsock, params, &code, message, sizeof(message))) {
1363 jrpc_add_error(reply, code, message, id);
1364 goto end;
1365 }
1366 switch_set_flag(jsock, JPFLAG_AUTHED);
1367 }
1368
1369 if (!method || !(func = jrpc_get_func(jsock, method))) {
1370 jrpc_add_error(reply, -32601, "Invalid Method, Missing Method or Permission Denied", id);
1371 } else {
1372 if (func(method, params, jsock, &response) == SWITCH_TRUE) {
1373
1374 if (params) {
1375 echo = cJSON_GetObjectItem(params, "echoParams");
1376 }
1377 if (echo) {
1378 if ((echo->type == cJSON_True || (echo->type == cJSON_String && switch_true(echo->valuestring)))) {
1379 cJSON_AddItemToObject(response, "requestParams", cJSON_Duplicate(params, 1));
1380 } else {
1381 cJSON_AddItemToObject(response, "requestParams", cJSON_Duplicate(echo, 1));
1382 }
1383 }
1384
1385 jrpc_add_result(reply, response);
1386 } else {
1387 if (response) {
1388 cJSON_AddItemToObject(reply, "error", response);
1389 } else {
1390 jrpc_add_error(reply, -32602, "Permission Denied", id);
1391 }
1392 }
1393 }
1394
1395 end:
1396
1397 return reply;
1398 }
1399
process_input(jsock_t * jsock,uint8_t * data,switch_ssize_t bytes)1400 static switch_status_t process_input(jsock_t *jsock, uint8_t *data, switch_ssize_t bytes)
1401 {
1402 cJSON *json = NULL, *reply = NULL;
1403 char *ascii = (char *) data;
1404 switch_status_t status = SWITCH_STATUS_SUCCESS;
1405
1406 if (ascii) {
1407 json = cJSON_Parse(ascii);
1408 }
1409
1410 if (json) {
1411
1412 if (jsock->profile->debug || verto_globals.debug) {
1413 char *log_text = cJSON_Print(json);
1414 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "READ %s [%s]\n", jsock->name, log_text);
1415 free(log_text);
1416 }
1417
1418 if (json->type == cJSON_Array) { /* batch mode */
1419 int i, len = cJSON_GetArraySize(json);
1420
1421 reply = cJSON_CreateArray();
1422
1423 for(i = 0; i < len; i++) {
1424 cJSON *obj, *item = cJSON_GetArrayItem(json, i);
1425
1426 if ((obj = process_jrpc(jsock, item))) {
1427 cJSON_AddItemToArray(reply, obj);
1428 }
1429 }
1430 } else {
1431 reply = process_jrpc(jsock, json);
1432 }
1433 } else {
1434 reply = jrpc_new(0);
1435 jrpc_add_error(reply, -32600, "Invalid Request", NULL);
1436 }
1437
1438 if (reply) {
1439 ws_write_json(jsock, &reply, SWITCH_TRUE);
1440 }
1441
1442 if (json) {
1443 cJSON_Delete(json);
1444 }
1445
1446 return status;
1447 }
1448
jsock_check_event_queue(jsock_t * jsock)1449 static void jsock_check_event_queue(jsock_t *jsock)
1450 {
1451 void *pop;
1452 int this_pass = switch_queue_size(jsock->event_queue);
1453
1454 switch_mutex_lock(jsock->write_mutex);
1455 while(this_pass-- > 0 && switch_queue_trypop(jsock->event_queue, &pop) == SWITCH_STATUS_SUCCESS) {
1456 cJSON *json = (cJSON *) pop;
1457 ws_write_json(jsock, &json, SWITCH_TRUE);
1458 }
1459 switch_mutex_unlock(jsock->write_mutex);
1460 }
1461
1462 /* DO NOT use this unless you know what you are doing, you are WARNNED!!! */
http_stream_read(switch_stream_handle_t * handle,int * len)1463 static uint8_t *http_stream_read(switch_stream_handle_t *handle, int *len)
1464 {
1465 switch_http_request_t *r = (switch_http_request_t *) handle->data;
1466 jsock_t *jsock = r->user_data;
1467 wsh_t *wsh = &jsock->ws;
1468
1469 if (!jsock->profile->running) {
1470 *len = 0;
1471 return NULL;
1472 }
1473
1474 *len = (int)(r->bytes_buffered - r->bytes_read);
1475
1476 if (*len > 0) { // we already read part of the body
1477 uint8_t *data = (uint8_t *)wsh->buffer + r->bytes_read;
1478 r->bytes_read = r->bytes_buffered;
1479 return data;
1480 }
1481
1482 if (r->content_length && (r->bytes_read - r->bytes_header) >= r->content_length) {
1483 *len = 0;
1484 return NULL;
1485 }
1486
1487 *len = (int)(r->content_length - (r->bytes_read - r->bytes_header));
1488 *len = *len > sizeof(wsh->buffer) ? wsh->buflen : *len;
1489
1490 if ((*len = (int)ws_raw_read(wsh, wsh->buffer, *len, wsh->block)) < 0) {
1491 *len = 0;
1492 return NULL;
1493 }
1494
1495 r->bytes_read += *len;
1496
1497 return (uint8_t *)wsh->buffer;
1498 }
1499
http_stream_raw_write(switch_stream_handle_t * handle,uint8_t * data,switch_size_t datalen)1500 static switch_status_t http_stream_raw_write(switch_stream_handle_t *handle, uint8_t *data, switch_size_t datalen)
1501 {
1502 switch_http_request_t *r = (switch_http_request_t *) handle->data;
1503 jsock_t *jsock = r->user_data;
1504
1505 return ws_raw_write(&jsock->ws, data, (uint32_t)datalen) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
1506 }
1507
http_stream_write(switch_stream_handle_t * handle,const char * fmt,...)1508 static switch_status_t http_stream_write(switch_stream_handle_t *handle, const char *fmt, ...)
1509 {
1510 switch_http_request_t *r = (switch_http_request_t *) handle->data;
1511 jsock_t *jsock = r->user_data;
1512 int ret = 1;
1513 char *data;
1514 va_list ap;
1515
1516 va_start(ap, fmt);
1517 ret = switch_vasprintf(&data, fmt, ap);
1518 va_end(ap);
1519
1520 if (data) {
1521 if (ret) {
1522 ret =(int) ws_raw_write(&jsock->ws, data, (uint32_t)strlen(data));
1523 }
1524 switch_safe_free(data);
1525 }
1526
1527 return ret ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
1528 }
1529
http_static_handler(switch_http_request_t * request,verto_vhost_t * vhost)1530 static void http_static_handler(switch_http_request_t *request, verto_vhost_t *vhost)
1531 {
1532 jsock_t *jsock = request->user_data;
1533 char path[512];
1534 switch_file_t *fd;
1535 char *ext;
1536 uint8_t chunk[4096];
1537 const char *mime_type = "text/html", *new_type;
1538
1539 if (strncmp(request->method, "GET", 3) && strncmp(request->method, "HEAD", 4)) {
1540 char *data = "HTTP/1.1 415 Method Not Allowed\r\n"
1541 "Content-Length: 0\r\n\r\n";
1542 ws_raw_write(&jsock->ws, data, strlen(data));
1543 return;
1544 }
1545
1546 switch_snprintf(path, sizeof(path), "%s%s", vhost->root, request->uri);
1547
1548 if (switch_directory_exists(path, NULL) == SWITCH_STATUS_SUCCESS) {
1549 switch_snprintf(path, sizeof(path), "%s%s%s%s",
1550 vhost->root, request->uri, end_of(path) == '/' ? "" : SWITCH_PATH_SEPARATOR, vhost->index);
1551 // printf("local path: %s\n", path);
1552 }
1553
1554 if ((ext = strrchr(path, '.'))) {
1555 ext++;
1556 if ((new_type = switch_core_mime_ext2type(ext))) {
1557 mime_type = new_type;
1558 }
1559 }
1560
1561 if (switch_file_exists(path, NULL) == SWITCH_STATUS_SUCCESS &&
1562 switch_file_open(&fd, path, SWITCH_FOPEN_READ, SWITCH_FPROT_UREAD, jsock->pool) == SWITCH_STATUS_SUCCESS) {
1563
1564 switch_size_t flen = switch_file_get_size(fd);
1565
1566 switch_snprintf((char *)chunk, sizeof(chunk),
1567 "HTTP/1.1 200 OK\r\n"
1568 "Date: %s\r\n"
1569 "Server: FreeSWITCH-%s-mod_verto\r\n"
1570 "Content-Type: %s\r\n"
1571 "Content-Length: %" SWITCH_SIZE_T_FMT "\r\n\r\n",
1572 switch_event_get_header(request->headers, "Event-Date-GMT"),
1573 switch_version_full(),
1574 mime_type,
1575 flen);
1576
1577 ws_raw_write(&jsock->ws, chunk, strlen((char *)chunk));
1578
1579 for (;;) {
1580 switch_status_t status;
1581
1582 flen = sizeof(chunk);
1583 status = switch_file_read(fd, chunk, &flen);
1584
1585 if (status != SWITCH_STATUS_SUCCESS || flen == 0) {
1586 break;
1587 }
1588
1589 ws_raw_write(&jsock->ws, chunk, flen);
1590 }
1591 switch_file_close(fd);
1592 } else {
1593 char *data = "HTTP/1.1 404 Not Found\r\n"
1594 "Content-Length: 0\r\n\r\n";
1595 ws_raw_write(&jsock->ws, data, strlen(data));
1596 }
1597 }
1598
http_run(jsock_t * jsock)1599 static void http_run(jsock_t *jsock)
1600 {
1601 switch_http_request_t request = { 0 };
1602 switch_stream_handle_t stream = { 0 };
1603 char *err = NULL;
1604 char *ext;
1605 verto_vhost_t *vhost;
1606 switch_bool_t keepalive;
1607
1608 new_req:
1609
1610 request.user_data = jsock;
1611
1612 if (switch_event_create(&stream.param_event, SWITCH_EVENT_CHANNEL_DATA) != SWITCH_STATUS_SUCCESS) {
1613 goto err;
1614 }
1615
1616 request.headers = stream.param_event;
1617 if (switch_http_parse_header(jsock->ws.buffer, (uint32_t)jsock->ws.datalen, &request) != SWITCH_STATUS_SUCCESS) {
1618 switch_event_destroy(&stream.param_event);
1619 goto err;
1620 }
1621
1622 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s [%4" SWITCH_SIZE_T_FMT "] %s\n", jsock->name, jsock->ws.datalen, request.uri);
1623
1624 if (!strncmp(request.method, "OPTIONS", 7)) {
1625 char data[512];
1626 switch_snprintf(data, sizeof(data),
1627 "HTTP/1.1 200 OK\r\n"
1628 "Content-Length: 0\r\n"
1629 "Date: %s\r\n"
1630 "Allow: HEAD,GET,POST,PUT,DELETE,PATCH,OPTIONS\r\n"
1631 "Server: FreeSWITCH-%s-mod_verto\r\n\r\n",
1632 switch_event_get_header(request.headers, "Event-Date-GMT"),
1633 switch_version_full());
1634
1635 ws_raw_write(&jsock->ws, data, strlen(data));
1636 goto done;
1637 }
1638
1639 if (!strncmp(request.method, "POST", 4) && request.content_length && request.content_type &&
1640 !strncmp(request.content_type, "application/x-www-form-urlencoded", 33)) {
1641
1642 char *buffer = NULL;
1643 switch_ssize_t len = 0, bytes = 0;
1644
1645 if (request.content_length > 2 * 1024 * 1024 - 1) {
1646 char *data = "HTTP/1.1 413 Request Entity Too Large\r\n"
1647 "Content-Length: 0\r\n\r\n";
1648 ws_raw_write(&jsock->ws, data, strlen(data));
1649 goto done;
1650 }
1651
1652 if (!(buffer = malloc(2 * 1024 * 1024))) {
1653 goto request_err;
1654 }
1655
1656 if ((bytes = request.bytes_buffered - request.bytes_read) > 0) {
1657 memcpy(buffer, jsock->ws.buffer + request.bytes_read, bytes);
1658 }
1659
1660 while(bytes < (switch_ssize_t)request.content_length) {
1661 len = request.content_length - bytes;
1662
1663 if ((len = ws_raw_read(&jsock->ws, buffer + bytes, len, jsock->ws.block)) < 0) {
1664 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Read error %" SWITCH_SSIZE_T_FMT"\n", len);
1665 goto done;
1666 }
1667
1668 bytes += len;
1669 }
1670
1671 *(buffer + bytes) = '\0';
1672
1673 switch_http_parse_qs(&request, buffer);
1674 free(buffer);
1675 }
1676
1677 // switch_http_dump_request(&request);
1678
1679 stream.data = &request;
1680 stream.read_function = http_stream_read;
1681 stream.write_function = http_stream_write;
1682 stream.raw_write_function = http_stream_raw_write;
1683
1684 switch_event_add_header_string(request.headers, SWITCH_STACK_BOTTOM, "Request-Method", request.method);
1685 switch_event_add_header_string(request.headers, SWITCH_STACK_BOTTOM, "HTTP-Request-URI", request.uri);
1686
1687 if (!jsock->profile->vhosts) goto err;
1688
1689 /* only one vhost supported for now */
1690 vhost = jsock->profile->vhosts;
1691
1692 if (!switch_test_flag(jsock, JPFLAG_AUTHED) && vhost->auth_realm) {
1693 int code = CODE_AUTH_REQUIRED;
1694 char message[128] = "Authentication Required";
1695 cJSON *params = NULL;
1696 char *www_auth;
1697 char auth_buffer[512];
1698 char *auth_user = NULL, *auth_pass = NULL;
1699
1700 www_auth = switch_event_get_header(request.headers, "Authorization");
1701
1702 if (zstr(www_auth)) {
1703 switch_snprintf(auth_buffer, sizeof(auth_buffer),
1704 "HTTP/1.1 401 Authentication Required\r\n"
1705 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
1706 "Content-Length: 0\r\n\r\n",
1707 vhost->auth_realm);
1708 ws_raw_write(&jsock->ws, auth_buffer, strlen(auth_buffer));
1709 goto done;
1710 }
1711
1712 if (strncasecmp(www_auth, "Basic ", 6)) goto err;
1713
1714 www_auth += 6;
1715
1716 switch_b64_decode(www_auth, auth_buffer, sizeof(auth_buffer));
1717
1718 auth_user = auth_buffer;
1719
1720 if ((auth_pass = strchr(auth_user, ':'))) {
1721 *auth_pass++ = '\0';
1722 }
1723
1724 if (vhost->auth_user && vhost->auth_pass && auth_pass &&
1725 !strcmp(vhost->auth_user, auth_user) &&
1726 !strcmp(vhost->auth_pass, auth_pass)) {
1727 goto authed;
1728 }
1729
1730 if (!(params = cJSON_CreateObject())) {
1731 goto request_err;
1732 }
1733
1734 cJSON_AddItemToObject(params, "login", cJSON_CreateString(auth_user));
1735 cJSON_AddItemToObject(params, "passwd", cJSON_CreateString(auth_pass));
1736
1737 if (!check_auth(jsock, params, &code, message, sizeof(message))) {
1738 switch_snprintf(auth_buffer, sizeof(auth_buffer),
1739 "HTTP/1.1 401 Authentication Required\r\n"
1740 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
1741 "Content-Length: 0\r\n\r\n",
1742 vhost->auth_realm);
1743 ws_raw_write(&jsock->ws, auth_buffer, strlen(auth_buffer));
1744 cJSON_Delete(params);
1745 goto done;
1746 } else {
1747 cJSON_Delete(params);
1748 }
1749
1750 authed:
1751 switch_set_flag(jsock, JPFLAG_AUTHED);
1752 switch_event_add_header_string(request.headers, SWITCH_STACK_BOTTOM, "HTTP-USER", auth_user);
1753 }
1754
1755 if (vhost->rewrites) {
1756 switch_event_header_t *rule = vhost->rewrites->headers;
1757 switch_regex_t *re = NULL;
1758 int ovector[30];
1759 int proceed;
1760
1761 while(rule) {
1762 char *expression = rule->name;
1763
1764 if ((proceed = switch_regex_perform(request.uri, expression, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
1765 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
1766 "%d request [%s] matched expr [%s]\n", proceed, request.uri, expression);
1767 request.uri = rule->value;
1768 break;
1769 }
1770
1771 rule = rule->next;
1772 }
1773 }
1774
1775 switch_event_add_header_string(request.headers, SWITCH_STACK_BOTTOM, "HTTP-URI", request.uri);
1776
1777 if ((ext = strrchr(request.uri, '.'))) {
1778 char path[1024];
1779
1780 if (!strncmp(ext, ".lua", 4)) {
1781 switch_snprintf(path, sizeof(path), "%s%s", vhost->script_root, request.uri);
1782 switch_api_execute("lua", path, NULL, &stream);
1783 } else {
1784 http_static_handler(&request, vhost);
1785 }
1786
1787 } else {
1788 http_static_handler(&request, vhost);
1789 }
1790
1791 done:
1792
1793 keepalive = request.keepalive;
1794 switch_http_free_request(&request);
1795
1796 if (keepalive) {
1797 wsh_t *wsh = &jsock->ws;
1798
1799 memset(&request, 0, sizeof(request));
1800 wsh->datalen = 0;
1801 *wsh->buffer = '\0';
1802
1803 while(jsock->profile->running) {
1804 int pflags;
1805
1806 if (wsh->ssl && SSL_pending(wsh->ssl) > 0) {
1807 pflags = SWITCH_POLL_READ;
1808 } else {
1809 pflags = switch_wait_sock(jsock->client_socket, 3000, SWITCH_POLL_READ | SWITCH_POLL_ERROR | SWITCH_POLL_HUP);
1810 }
1811
1812 if (jsock->drop) { die("%s Dropping Connection\n", jsock->name); }
1813 if (pflags < 0 && (errno != EINTR)) { die_errnof("%s POLL FAILED with %d", jsock->name, pflags); }
1814 if (pflags == 0) { /* keepalive socket poll timeout */ break; }
1815 if (pflags > 0 && (pflags & SWITCH_POLL_HUP)) { log_and_exit(SWITCH_LOG_INFO, "%s POLL HANGUP DETECTED (peer closed its end of socket)\n", jsock->name); }
1816 if (pflags > 0 && (pflags & SWITCH_POLL_ERROR)) { die("%s POLL ERROR\n", jsock->name); }
1817 if (pflags > 0 && (pflags & SWITCH_POLL_INVALID)) { die("%s POLL INVALID SOCKET (not opened or already closed)\n", jsock->name); }
1818 if (pflags > 0 && (pflags & SWITCH_POLL_READ)) {
1819 ssize_t bytes;
1820
1821 bytes = ws_raw_read(wsh, wsh->buffer + wsh->datalen, wsh->buflen - wsh->datalen - 1, wsh->block);
1822
1823 if (bytes < 0) {
1824 die("%s BAD READ %" SWITCH_SIZE_T_FMT "\n", jsock->name, bytes);
1825 break;
1826 }
1827
1828 if (bytes == 0) {
1829 bytes = ws_raw_read(wsh, wsh->buffer + wsh->datalen, wsh->buflen - wsh->datalen - 1, wsh->block);
1830
1831 if (bytes < 0) {
1832 die("%s BAD READ %" SWITCH_SIZE_T_FMT "\n", jsock->name, bytes);
1833 break;
1834 }
1835
1836 if (bytes == 0) { // socket broken ?
1837 break;
1838 }
1839 }
1840
1841 wsh->datalen += bytes;
1842 *(wsh->buffer + wsh->datalen) = '\0';
1843
1844 if (strstr(wsh->buffer, "\r\n\r\n") || strstr(wsh->buffer, "\n\n")) {
1845 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "socket %s is going to handle a new request\n", jsock->name);
1846 goto new_req;
1847 }
1848 }
1849 }
1850 }
1851
1852 return;
1853
1854 request_err:
1855 switch_http_free_request(&request);
1856
1857 err:
1858 err = "HTTP/1.1 500 Internal Server Error\r\n"
1859 "Content-Length: 0\r\n\r\n";
1860 ws_raw_write(&jsock->ws, err, strlen(err));
1861
1862 error:
1863 return;
1864 }
1865
client_run(jsock_t * jsock)1866 static void client_run(jsock_t *jsock)
1867 {
1868 if (ws_init(&jsock->ws, jsock->client_socket, (jsock->ptype & PTYPE_CLIENT_SSL) ? jsock->profile->ssl_ctx : NULL, 0, 1, !!jsock->profile->vhosts) < 0) {
1869 if (jsock->profile->vhosts) {
1870 http_run(jsock);
1871 ws_close(&jsock->ws, WS_NONE);
1872 goto error;
1873 } else {
1874 log_and_exit(SWITCH_LOG_NOTICE, "%s WS SETUP FAILED\n", jsock->name);
1875 }
1876 }
1877
1878 while(jsock->profile->running) {
1879 int pflags;
1880
1881 if (jsock->ws.ssl && SSL_pending(jsock->ws.ssl) > 0) {
1882 pflags = SWITCH_POLL_READ;
1883 } else {
1884 pflags = switch_wait_sock(jsock->client_socket, 50, SWITCH_POLL_READ | SWITCH_POLL_ERROR | SWITCH_POLL_HUP);
1885 }
1886
1887 if (jsock->drop) { die("%s Dropping Connection\n", jsock->name); }
1888 if (pflags < 0 && (errno != EINTR)) { die_errnof("%s POLL FAILED with %d", jsock->name, pflags); }
1889 if (pflags == 0) {/* socket poll timeout */ jsock_check_event_queue(jsock); }
1890 if (pflags > 0 && (pflags & SWITCH_POLL_HUP)) { log_and_exit(SWITCH_LOG_INFO, "%s POLL HANGUP DETECTED (peer closed its end of socket)\n", jsock->name); }
1891 if (pflags > 0 && (pflags & SWITCH_POLL_ERROR)) { die("%s POLL ERROR\n", jsock->name); }
1892 if (pflags > 0 && (pflags & SWITCH_POLL_INVALID)) { die("%s POLL INVALID SOCKET (not opened or already closed)\n", jsock->name); }
1893 if (pflags > 0 && (pflags & SWITCH_POLL_READ)) {
1894 switch_ssize_t bytes;
1895 ws_opcode_t oc;
1896 uint8_t *data;
1897
1898 bytes = ws_read_frame(&jsock->ws, &oc, &data);
1899
1900 if (bytes < 0) {
1901 if (bytes == -WS_RECV_CLOSE) {
1902 log_and_exit(SWITCH_LOG_INFO, "%s Client sent close request\n", jsock->name);
1903 } else {
1904 die("%s BAD READ %" SWITCH_SSIZE_T_FMT "\n", jsock->name, bytes);
1905 }
1906 }
1907
1908 if (bytes) {
1909 char *s = (char *) data;
1910
1911 if (*s == '#') {
1912 char repl[2048] = "";
1913 switch_time_t a, b;
1914
1915 if (s[1] == 'S' && s[2] == 'P') {
1916
1917 if (s[3] == 'U') {
1918 int i, size = 0;
1919 char *p = s+4;
1920 int loops = 0;
1921 int rem = 0;
1922 int dur = 0, j = 0;
1923
1924 if ((size = atoi(p)) <= 0) {
1925 continue;
1926 }
1927
1928 a = switch_time_now();
1929 do {
1930 bytes = ws_read_frame(&jsock->ws, &oc, &data);
1931 s = (char *) data;
1932 } while (bytes && data && s[0] == '#' && s[3] == 'B');
1933 b = switch_time_now();
1934
1935 if (!bytes || !data) continue;
1936
1937 if (s[0] != '#') goto nm;
1938
1939 switch_snprintf(repl, sizeof(repl), "#SPU %ld", (long)((b - a) / 1000));
1940 ws_write_frame(&jsock->ws, WSOC_TEXT, repl, strlen(repl));
1941 loops = size / 1024;
1942 rem = size % 1024;
1943 switch_snprintf(repl, sizeof(repl), "#SPB ");
1944 memset(repl+4, '.', 1024);
1945
1946 for (j = 0; j < 10 ; j++) {
1947 int ddur = 0;
1948 a = switch_time_now();
1949 for (i = 0; i < loops; i++) {
1950 ws_write_frame(&jsock->ws, WSOC_TEXT, repl, 1024);
1951 }
1952 if (rem) {
1953 ws_write_frame(&jsock->ws, WSOC_TEXT, repl, rem);
1954 }
1955 b = switch_time_now();
1956 ddur += (int)((b - a) / 1000);
1957 dur += ddur;
1958
1959 }
1960
1961 dur /= j+1;
1962
1963 switch_snprintf(repl, sizeof(repl), "#SPD %d", dur);
1964 ws_write_frame(&jsock->ws, WSOC_TEXT, repl, strlen(repl));
1965 }
1966 }
1967
1968 continue;
1969 }
1970
1971 nm:
1972
1973 if (process_input(jsock, data, bytes) != SWITCH_STATUS_SUCCESS) {
1974 die("%s Input Error\n", jsock->name);
1975 }
1976
1977 if (!switch_test_flag(jsock, JPFLAG_CHECK_ATTACH) && switch_test_flag(jsock, JPFLAG_AUTHED)) {
1978 attach_calls(jsock);
1979 switch_set_flag(jsock, JPFLAG_CHECK_ATTACH);
1980 }
1981 }
1982 }
1983 }
1984
1985 error:
1986
1987 detach_jsock(jsock);
1988 ws_destroy(&jsock->ws);
1989
1990 return;
1991 }
1992
jsock_flush(jsock_t * jsock)1993 static void jsock_flush(jsock_t *jsock)
1994 {
1995 void *pop;
1996
1997 switch_mutex_lock(jsock->write_mutex);
1998 while(switch_queue_trypop(jsock->event_queue, &pop) == SWITCH_STATUS_SUCCESS) {
1999 cJSON *json = (cJSON *) pop;
2000 cJSON_Delete(json);
2001 }
2002 switch_mutex_unlock(jsock->write_mutex);
2003 }
2004
client_thread(switch_thread_t * thread,void * obj)2005 static void *SWITCH_THREAD_FUNC client_thread(switch_thread_t *thread, void *obj)
2006 {
2007 switch_event_t *s_event;
2008
2009 jsock_t *jsock = (jsock_t *) obj;
2010
2011 switch_event_create(&jsock->params, SWITCH_EVENT_CHANNEL_DATA);
2012 switch_event_create(&jsock->vars, SWITCH_EVENT_CHANNEL_DATA);
2013 switch_event_create(&jsock->user_vars, SWITCH_EVENT_CHANNEL_DATA);
2014
2015
2016 add_jsock(jsock);
2017
2018 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Starting client thread.\n", jsock->name);
2019
2020 if ((jsock->ptype & PTYPE_CLIENT) || (jsock->ptype & PTYPE_CLIENT_SSL)) {
2021 client_run(jsock);
2022 } else {
2023 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s Ending client thread.\n", jsock->name);
2024 }
2025
2026 detach_calls(jsock);
2027
2028 del_jsock(jsock);
2029
2030 switch_event_destroy(&jsock->params);
2031 switch_event_destroy(&jsock->vars);
2032 switch_event_destroy(&jsock->user_vars);
2033
2034 if (jsock->client_socket != ws_sock_invalid) {
2035 close_socket(&jsock->client_socket);
2036 }
2037
2038 switch_event_destroy(&jsock->allowed_methods);
2039 switch_event_destroy(&jsock->allowed_fsapi);
2040 switch_event_destroy(&jsock->allowed_jsapi);
2041 switch_event_destroy(&jsock->allowed_event_channels);
2042
2043 jsock_flush(jsock);
2044
2045 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Ending client thread.\n", jsock->name);
2046 if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_CLIENT_DISCONNECT) == SWITCH_STATUS_SUCCESS) {
2047 switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "verto_profile_name", jsock->profile->name);
2048 switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "verto_client_address", jsock->name);
2049 switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "verto_login", switch_str_nil(jsock->uid));
2050 switch_event_fire(&s_event);
2051 }
2052 switch_thread_rwlock_wrlock(jsock->rwlock);
2053 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Thread ended\n", jsock->name);
2054 switch_thread_rwlock_unlock(jsock->rwlock);
2055
2056 return NULL;
2057 }
2058
2059
auth_api_command(jsock_t * jsock,const char * api_cmd,const char * arg)2060 static switch_bool_t auth_api_command(jsock_t *jsock, const char *api_cmd, const char *arg)
2061 {
2062 const char *check_cmd = api_cmd;
2063 char *sneaky_commands[] = { "bgapi", "sched_api", "eval", "expand", "xml_wrap", NULL };
2064 int x = 0;
2065 char *dup_arg = NULL;
2066 char *next = NULL;
2067 switch_bool_t ok = SWITCH_TRUE;
2068
2069 top:
2070
2071 if (!jsock->allowed_fsapi) {
2072 ok = SWITCH_FALSE;
2073 goto end;
2074 }
2075
2076 if (!switch_event_get_header(jsock->allowed_fsapi, check_cmd)) {
2077 ok = SWITCH_FALSE;
2078 goto end;
2079 }
2080
2081 while (check_cmd) {
2082 for (x = 0; sneaky_commands[x]; x++) {
2083 if (!strcasecmp(sneaky_commands[x], check_cmd)) {
2084 if (check_cmd == api_cmd) {
2085 if (arg) {
2086 switch_safe_free(dup_arg);
2087 dup_arg = strdup(arg);
2088 switch_assert(dup_arg);
2089 check_cmd = dup_arg;
2090 if ((next = strchr(check_cmd, ' '))) {
2091 *next++ = '\0';
2092 }
2093 } else {
2094 break;
2095 }
2096 } else {
2097 if (next) {
2098 check_cmd = next;
2099 } else {
2100 check_cmd = dup_arg;
2101 }
2102
2103 if ((next = strchr(check_cmd, ' '))) {
2104 *next++ = '\0';
2105 }
2106 }
2107 goto top;
2108 }
2109 }
2110 break;
2111 }
2112
2113 end:
2114
2115 switch_safe_free(dup_arg);
2116 return ok;
2117
2118 }
2119
2120 //// VERTO
2121
track_pvt(verto_pvt_t * tech_pvt)2122 static void track_pvt(verto_pvt_t *tech_pvt)
2123 {
2124 switch_thread_rwlock_wrlock(verto_globals.tech_rwlock);
2125 tech_pvt->next = verto_globals.tech_head;
2126 verto_globals.tech_head = tech_pvt;
2127 switch_set_flag(tech_pvt, TFLAG_TRACKED);
2128 switch_thread_rwlock_unlock(verto_globals.tech_rwlock);
2129 }
2130
untrack_pvt(verto_pvt_t * tech_pvt)2131 static void untrack_pvt(verto_pvt_t *tech_pvt)
2132 {
2133 verto_pvt_t *p, *last = NULL;
2134 int wake = 0;
2135
2136 switch_thread_rwlock_wrlock(verto_globals.tech_rwlock);
2137
2138 if (tech_pvt->detach_time) {
2139 verto_globals.detached--;
2140 tech_pvt->detach_time = 0;
2141 wake = 1;
2142 }
2143
2144 if (switch_test_flag(tech_pvt, TFLAG_TRACKED)) {
2145 switch_clear_flag(tech_pvt, TFLAG_TRACKED);
2146 for(p = verto_globals.tech_head; p; p = p->next) {
2147 if (p == tech_pvt) {
2148 if (last) {
2149 last->next = p->next;
2150 } else {
2151 verto_globals.tech_head = p->next;
2152 }
2153 break;
2154 }
2155
2156 last = p;
2157 }
2158 }
2159
2160 switch_thread_rwlock_unlock(verto_globals.tech_rwlock);
2161
2162 if (wake) attach_wake();
2163 }
2164
2165 switch_endpoint_interface_t *verto_endpoint_interface = NULL;
2166
verto_on_destroy(switch_core_session_t * session)2167 static switch_status_t verto_on_destroy(switch_core_session_t *session)
2168 {
2169 verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY);
2170
2171 switch_buffer_destroy(&tech_pvt->text_read_buffer);
2172 switch_buffer_destroy(&tech_pvt->text_write_buffer);
2173
2174 UNPROTECT_INTERFACE(verto_endpoint_interface);
2175 return SWITCH_STATUS_SUCCESS;
2176 }
2177
verto_on_hangup(switch_core_session_t * session)2178 static switch_status_t verto_on_hangup(switch_core_session_t *session)
2179 {
2180 jsock_t *jsock = NULL;
2181 verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY);
2182
2183 untrack_pvt(tech_pvt);
2184
2185 // get the jsock and send hangup notice
2186 if (!tech_pvt->remote_hangup_cause && (jsock = get_jsock(tech_pvt->jsock_uuid))) {
2187 cJSON *params = NULL;
2188 cJSON *msg = jrpc_new_req("verto.bye", tech_pvt->call_id, ¶ms);
2189 switch_call_cause_t cause = switch_channel_get_cause(tech_pvt->channel);
2190 switch_channel_set_variable(tech_pvt->channel, "verto_hangup_disposition", "send_bye");
2191
2192 cJSON_AddItemToObject(params, "causeCode", cJSON_CreateNumber(cause));
2193 cJSON_AddItemToObject(params, "cause", cJSON_CreateString(switch_channel_cause2str(cause)));
2194 jsock_queue_event(jsock, &msg, SWITCH_TRUE);
2195
2196 switch_thread_rwlock_unlock(jsock->rwlock);
2197 }
2198
2199 return SWITCH_STATUS_SUCCESS;
2200 }
2201
2202 static switch_status_t verto_set_media_options(verto_pvt_t *tech_pvt, verto_profile_t *profile);
2203
verto_connect(switch_core_session_t * session,const char * method)2204 static switch_status_t verto_connect(switch_core_session_t *session, const char *method)
2205 {
2206 switch_status_t status = SWITCH_STATUS_SUCCESS;
2207 jsock_t *jsock = NULL;
2208 verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY);
2209
2210 if (!(jsock = get_jsock(tech_pvt->jsock_uuid))) {
2211 status = SWITCH_STATUS_BREAK;
2212 } else {
2213 cJSON *params = NULL;
2214 cJSON *msg = NULL;
2215 const char *var = NULL;
2216 switch_caller_profile_t *caller_profile = switch_channel_get_caller_profile(tech_pvt->channel);
2217 switch_event_header_t *hp;
2218
2219 //DUMP_EVENT(jsock->params);
2220
2221 switch_channel_set_variable(tech_pvt->channel, "verto_user", jsock->uid);
2222 switch_channel_set_variable(tech_pvt->channel, "presence_id", jsock->uid);
2223 switch_channel_set_variable(tech_pvt->channel, "verto_client_address", jsock->name);
2224 switch_channel_set_variable(tech_pvt->channel, "chat_proto", VERTO_CHAT_PROTO);
2225 switch_channel_set_variable(tech_pvt->channel, "verto_host", jsock->domain);
2226
2227 for (hp = jsock->user_vars->headers; hp; hp = hp->next) {
2228 switch_channel_set_variable(tech_pvt->channel, hp->name, hp->value);
2229 }
2230
2231 if ((var = switch_event_get_header(jsock->params, "caller-id-name"))) {
2232 caller_profile->callee_id_name = switch_core_strdup(caller_profile->pool, var);
2233 }
2234
2235 if ((var = switch_event_get_header(jsock->params, "caller-id-number"))) {
2236 caller_profile->callee_id_number = switch_core_strdup(caller_profile->pool, var);
2237 }
2238
2239 if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE)) {
2240 switch_core_media_absorb_sdp(session);
2241 } else {
2242 switch_channel_set_variable(tech_pvt->channel, "media_webrtc", "true");
2243 switch_core_session_set_ice(tech_pvt->session);
2244
2245 if (verto_set_media_options(tech_pvt, jsock->profile) != SWITCH_STATUS_SUCCESS) {
2246 status = SWITCH_STATUS_FALSE;
2247 switch_thread_rwlock_unlock(jsock->rwlock);
2248 return status;
2249 }
2250
2251
2252 switch_channel_set_variable(tech_pvt->channel, "verto_profile_name", jsock->profile->name);
2253
2254 if (!switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING)) {
2255 switch_channel_set_variable(tech_pvt->channel, "codec_string", NULL);
2256 switch_core_media_prepare_codecs(tech_pvt->session, SWITCH_TRUE);
2257
2258 if ((status = switch_core_media_choose_ports(tech_pvt->session, SWITCH_TRUE, SWITCH_TRUE)) != SWITCH_STATUS_SUCCESS) {
2259 //if ((status = switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0)) != SWITCH_STATUS_SUCCESS) {
2260 switch_thread_rwlock_unlock(jsock->rwlock);
2261 return status;
2262 }
2263 }
2264
2265 switch_core_media_gen_local_sdp(session, SDP_TYPE_REQUEST, NULL, 0, NULL, 0);
2266 }
2267
2268 msg = jrpc_new_req(method, tech_pvt->call_id, ¶ms);
2269
2270 if (tech_pvt->mparams->local_sdp_str) {
2271 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Local %s SDP %s:\n%s\n",
2272 method,
2273 switch_channel_get_name(tech_pvt->channel),
2274 tech_pvt->mparams->local_sdp_str);
2275
2276 cJSON_AddItemToObject(params, "sdp", cJSON_CreateString(tech_pvt->mparams->local_sdp_str));
2277 set_call_params(params, tech_pvt);
2278
2279 jsock_queue_event(jsock, &msg, SWITCH_TRUE);
2280 } else {
2281 status = SWITCH_STATUS_FALSE;
2282 }
2283
2284 switch_thread_rwlock_unlock(jsock->rwlock);
2285 }
2286
2287 return status;
2288 }
2289
verto_tech_media(verto_pvt_t * tech_pvt,const char * r_sdp,switch_sdp_type_t sdp_type)2290 switch_status_t verto_tech_media(verto_pvt_t *tech_pvt, const char *r_sdp, switch_sdp_type_t sdp_type)
2291 {
2292 uint8_t match = 0, p = 0;
2293
2294 switch_assert(tech_pvt != NULL);
2295 switch_assert(r_sdp != NULL);
2296
2297 if (zstr(r_sdp)) {
2298 return SWITCH_STATUS_FALSE;
2299 }
2300
2301 if ((match = switch_core_media_negotiate_sdp(tech_pvt->session, r_sdp, &p, sdp_type))) {
2302 if (switch_core_media_choose_ports(tech_pvt->session, SWITCH_TRUE, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
2303 //if (switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0) != SWITCH_STATUS_SUCCESS) {
2304 return SWITCH_STATUS_FALSE;
2305 }
2306
2307 if (switch_core_media_activate_rtp(tech_pvt->session) != SWITCH_STATUS_SUCCESS) {
2308 return SWITCH_STATUS_FALSE;
2309 }
2310 //if (!switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED)) {
2311 // switch_channel_set_variable(tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "EARLY MEDIA");
2312 // switch_channel_mark_pre_answered(tech_pvt->channel);
2313 //}
2314 return SWITCH_STATUS_SUCCESS;
2315 }
2316
2317
2318 return SWITCH_STATUS_FALSE;
2319 }
2320
verto_on_init(switch_core_session_t * session)2321 static switch_status_t verto_on_init(switch_core_session_t *session)
2322 {
2323 switch_status_t status = SWITCH_STATUS_SUCCESS;
2324 verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY);
2325
2326 if (switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING_BRIDGE) || switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING)) {
2327 int tries = 120;
2328
2329 switch_core_session_clear_crypto(session);
2330
2331 while(--tries > 0) {
2332
2333 status = verto_connect(session, "verto.attach");
2334
2335 if (status == SWITCH_STATUS_SUCCESS) {
2336 switch_set_flag(tech_pvt, TFLAG_ATTACH_REQ);
2337 break;
2338 } else if (status == SWITCH_STATUS_BREAK) {
2339 switch_yield(1000000);
2340 continue;
2341 } else {
2342 tries = 0;
2343 break;
2344 }
2345 }
2346
2347 if (!tries) {
2348 switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
2349 status = SWITCH_STATUS_FALSE;
2350 }
2351
2352 switch_channel_set_flag(tech_pvt->channel, CF_VIDEO_BREAK);
2353 switch_core_session_kill_channel(tech_pvt->session, SWITCH_SIG_BREAK);
2354
2355 tries = 500;
2356 while(--tries > 0 && switch_test_flag(tech_pvt, TFLAG_ATTACH_REQ)) {
2357 switch_yield(10000);
2358 }
2359
2360 switch_core_session_request_video_refresh(session);
2361 switch_channel_set_flag(tech_pvt->channel, CF_VIDEO_BREAK);
2362 switch_core_session_kill_channel(tech_pvt->session, SWITCH_SIG_BREAK);
2363
2364 goto end;
2365 }
2366
2367 if (switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
2368 if ((status = verto_connect(tech_pvt->session, "verto.invite")) != SWITCH_STATUS_SUCCESS) {
2369 switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
2370 } else {
2371 switch_channel_mark_ring_ready(tech_pvt->channel);
2372 }
2373 }
2374
2375 end:
2376
2377 if (status == SWITCH_STATUS_SUCCESS) {
2378 track_pvt(tech_pvt);
2379 }
2380
2381 return status;
2382 }
2383
2384
2385 static switch_state_handler_table_t verto_state_handlers = {
2386 /*.on_init */ verto_on_init,
2387 /*.on_routing */ NULL,
2388 /*.on_execute */ NULL,
2389 /*.on_hangup */ verto_on_hangup,
2390 /*.on_exchange_media */ NULL,
2391 /*.on_soft_execute */ NULL,
2392 /*.on_consume_media */ NULL,
2393 /*.on_hibernate */ NULL,
2394 /*.on_reset */ NULL,
2395 /*.on_park */ NULL,
2396 /*.on_reporting */ NULL,
2397 /*.on_destroy */ verto_on_destroy,
2398 SSH_FLAG_STICKY
2399 };
2400
2401
2402
2403
verto_set_media_options(verto_pvt_t * tech_pvt,verto_profile_t * profile)2404 static switch_status_t verto_set_media_options(verto_pvt_t *tech_pvt, verto_profile_t *profile)
2405 {
2406 uint32_t i;
2407
2408
2409 switch_mutex_lock(profile->mutex);
2410 if (!zstr(profile->rtpip[profile->rtpip_cur])) {
2411 tech_pvt->mparams->rtpip4 = switch_core_session_strdup(tech_pvt->session, profile->rtpip[profile->rtpip_cur++]);
2412 tech_pvt->mparams->rtpip = tech_pvt->mparams->rtpip4;
2413 if (profile->rtpip_cur == profile->rtpip_index) {
2414 profile->rtpip_cur = 0;
2415 }
2416 }
2417
2418 if (!zstr(profile->rtpip6[profile->rtpip_cur6])) {
2419 tech_pvt->mparams->rtpip6 = switch_core_session_strdup(tech_pvt->session, profile->rtpip6[profile->rtpip_cur6++]);
2420
2421 if (zstr(tech_pvt->mparams->rtpip)) {
2422 tech_pvt->mparams->rtpip = tech_pvt->mparams->rtpip6;
2423 }
2424
2425 if (profile->rtpip_cur6 == profile->rtpip_index6) {
2426 profile->rtpip_cur6 = 0;
2427 }
2428 }
2429 switch_mutex_unlock(profile->mutex);
2430
2431 if (zstr(tech_pvt->mparams->rtpip)) {
2432 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "%s has no media ip, check your configuration\n",
2433 switch_channel_get_name(tech_pvt->channel));
2434 //switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2435 return SWITCH_STATUS_FALSE;
2436 }
2437
2438 tech_pvt->mparams->extrtpip = tech_pvt->mparams->extsipip = profile->extrtpip;
2439
2440 //tech_pvt->mparams->dtmf_type = tech_pvt->profile->dtmf_type;
2441 switch_channel_set_flag(tech_pvt->channel, CF_TRACKABLE);
2442 switch_channel_set_variable(tech_pvt->channel, "secondary_recovery_module", modname);
2443
2444 switch_core_media_check_dtmf_type(tech_pvt->session);
2445
2446 //switch_channel_set_cap(tech_pvt->channel, CC_MEDIA_ACK);
2447 switch_channel_set_cap(tech_pvt->channel, CC_BYPASS_MEDIA);
2448 //switch_channel_set_cap(tech_pvt->channel, CC_PROXY_MEDIA);
2449 switch_channel_set_cap(tech_pvt->channel, CC_JITTERBUFFER);
2450 switch_channel_set_cap(tech_pvt->channel, CC_FS_RTP);
2451
2452 //switch_channel_set_cap(tech_pvt->channel, CC_QUEUEABLE_DTMF_DELAY);
2453 //tech_pvt->mparams->ndlb = tech_pvt->profile->mndlb;
2454
2455 tech_pvt->mparams->inbound_codec_string = switch_core_session_strdup(tech_pvt->session, profile->inbound_codec_string);
2456 tech_pvt->mparams->outbound_codec_string = switch_core_session_strdup(tech_pvt->session, profile->outbound_codec_string);
2457
2458 tech_pvt->mparams->jb_msec = profile->jb_msec;
2459 switch_media_handle_set_media_flag(tech_pvt->smh, SCMF_SUPPRESS_CNG);
2460
2461 //tech_pvt->mparams->auto_rtp_bugs = profile->auto_rtp_bugs;
2462 tech_pvt->mparams->timer_name = profile->timer_name;
2463 //tech_pvt->mparams->vflags = profile->vflags;
2464 //tech_pvt->mparams->manual_rtp_bugs = profile->manual_rtp_bugs;
2465 //tech_pvt->mparams->manual_video_rtp_bugs = profile->manual_video_rtp_bugs;
2466
2467 tech_pvt->mparams->local_network = switch_core_session_strdup(tech_pvt->session, profile->local_network);
2468
2469
2470 //tech_pvt->mparams->rtcp_audio_interval_msec = profile->rtpp_audio_interval_msec;
2471 //tech_pvt->mparams->rtcp_video_interval_msec = profile->rtpp_video_interval_msec;
2472 //tech_pvt->mparams->sdp_username = profile->sdp_username;
2473 //tech_pvt->mparams->cng_pt = tech_pvt->cng_pt;
2474 //tech_pvt->mparams->rtc_timeout_sec = profile->rtp_timeout_sec;
2475 //tech_pvt->mparams->rtc_hold_timeout_sec = profile->rtp_hold_timeout_sec;
2476 //switch_media_handle_set_media_flags(tech_pvt->media_handle, tech_pvt->profile->media_flags);
2477
2478
2479 for(i = 0; i < profile->cand_acl_count; i++) {
2480 switch_core_media_add_ice_acl(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, profile->cand_acl[i]);
2481 switch_core_media_add_ice_acl(tech_pvt->session, SWITCH_MEDIA_TYPE_VIDEO, profile->cand_acl[i]);
2482 }
2483
2484 if (profile->enable_text && !tech_pvt->text_read_buffer) {
2485 set_text_funcs(tech_pvt->session);
2486 }
2487
2488 return SWITCH_STATUS_SUCCESS;
2489 }
2490
verto_media(switch_core_session_t * session)2491 static switch_status_t verto_media(switch_core_session_t *session)
2492 {
2493 verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY);
2494 switch_status_t status = SWITCH_STATUS_SUCCESS;
2495
2496 switch_core_media_prepare_codecs(tech_pvt->session, SWITCH_TRUE);
2497
2498 if (tech_pvt->r_sdp) {
2499 if (verto_tech_media(tech_pvt, tech_pvt->r_sdp, SDP_TYPE_REQUEST) != SWITCH_STATUS_SUCCESS) {
2500 switch_channel_set_variable(tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
2501 return SWITCH_STATUS_FALSE;
2502 }
2503 }
2504
2505 if ((status = switch_core_media_choose_ports(tech_pvt->session, SWITCH_TRUE, SWITCH_FALSE)) != SWITCH_STATUS_SUCCESS) {
2506 //if ((status = switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0)) != SWITCH_STATUS_SUCCESS) {
2507 switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
2508 return status;
2509 }
2510
2511 switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0);
2512
2513 if (switch_core_media_activate_rtp(tech_pvt->session) != SWITCH_STATUS_SUCCESS) {
2514 switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
2515 }
2516
2517 if (tech_pvt->mparams->local_sdp_str) {
2518 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Local SDP %s:\n%s\n", switch_channel_get_name(tech_pvt->channel),
2519 tech_pvt->mparams->local_sdp_str);
2520 } else {
2521 status = SWITCH_STATUS_FALSE;
2522 }
2523
2524 return status;
2525 }
2526
2527
verto_send_media_indication(switch_core_session_t * session,const char * method)2528 static switch_status_t verto_send_media_indication(switch_core_session_t *session, const char *method)
2529 {
2530 switch_status_t status = SWITCH_STATUS_FALSE;
2531 verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY);
2532 const char *proxy_sdp = NULL;
2533
2534 if (switch_test_flag(tech_pvt, TFLAG_SENT_MEDIA)) {
2535 status = SWITCH_STATUS_SUCCESS;
2536 }
2537
2538 if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE)) {
2539 if ((proxy_sdp = switch_channel_get_variable(tech_pvt->channel, SWITCH_B_SDP_VARIABLE))) {
2540 status = SWITCH_STATUS_SUCCESS;
2541 switch_core_media_set_local_sdp(session, proxy_sdp, SWITCH_TRUE);
2542 }
2543 }
2544
2545
2546 if (status == SWITCH_STATUS_SUCCESS || (status = verto_media(session)) == SWITCH_STATUS_SUCCESS) {
2547 jsock_t *jsock = NULL;
2548
2549 if (!(jsock = get_jsock(tech_pvt->jsock_uuid))) {
2550 status = SWITCH_STATUS_FALSE;
2551 } else {
2552 cJSON *params = NULL;
2553 cJSON *msg = jrpc_new_req(method, tech_pvt->call_id, ¶ms);
2554 if (!switch_test_flag(tech_pvt, TFLAG_SENT_MEDIA)) {
2555 cJSON_AddItemToObject(params, "sdp", cJSON_CreateString(tech_pvt->mparams->local_sdp_str));
2556 }
2557
2558 switch_set_flag(tech_pvt, TFLAG_SENT_MEDIA);
2559
2560 if (jsock_queue_event(jsock, &msg, SWITCH_TRUE) != SWITCH_STATUS_SUCCESS) {
2561 switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
2562 }
2563
2564 switch_thread_rwlock_unlock(jsock->rwlock);
2565 }
2566 }
2567
2568 return status;
2569 }
2570
messagehook(switch_core_session_t * session,switch_core_session_message_t * msg)2571 static switch_status_t messagehook (switch_core_session_t *session, switch_core_session_message_t *msg)
2572 {
2573 switch_status_t r = SWITCH_STATUS_SUCCESS;
2574 verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY);
2575
2576 switch(msg->message_id) {
2577 case SWITCH_MESSAGE_INDICATE_DISPLAY:
2578 {
2579 const char *name, *number;
2580 cJSON *jmsg = NULL, *params = NULL;
2581 jsock_t *jsock = NULL;
2582
2583 if ((jsock = get_jsock(tech_pvt->jsock_uuid))) {
2584 name = msg->string_array_arg[0];
2585 number = msg->string_array_arg[1];
2586
2587 if (name || number) {
2588 jmsg = jrpc_new_req("verto.display", tech_pvt->call_id, ¶ms);
2589 switch_ivr_eavesdrop_update_display(session, name, number);
2590 switch_channel_set_variable(tech_pvt->channel, "last_sent_display_name", name);
2591 switch_channel_set_variable(tech_pvt->channel, "last_sent_display_number", number);
2592 cJSON_AddItemToObject(params, "display_name", cJSON_CreateString(name));
2593 cJSON_AddItemToObject(params, "display_number", cJSON_CreateString(number));
2594 set_call_params(params, tech_pvt);
2595 jsock_queue_event(jsock, &jmsg, SWITCH_TRUE);
2596 }
2597
2598 switch_thread_rwlock_unlock(jsock->rwlock);
2599 }
2600
2601 }
2602 break;
2603 case SWITCH_MESSAGE_INDICATE_MEDIA_RENEG:
2604 {
2605 jsock_t *jsock = NULL;
2606
2607 if ((jsock = get_jsock(tech_pvt->jsock_uuid))) {
2608 switch_core_session_stop_media(session);
2609 detach_calls(jsock);
2610 tech_reattach(tech_pvt, jsock);
2611 switch_thread_rwlock_unlock(jsock->rwlock);
2612 }
2613 }
2614 break;
2615 case SWITCH_MESSAGE_INDICATE_ANSWER:
2616 r = verto_send_media_indication(session, "verto.answer");
2617 break;
2618 case SWITCH_MESSAGE_INDICATE_PROGRESS:
2619 r = verto_send_media_indication(session, "verto.media");
2620 break;
2621 default:
2622 break;
2623 }
2624
2625 return r;
2626 }
2627
2628
2629
verto_recover_callback(switch_core_session_t * session)2630 static int verto_recover_callback(switch_core_session_t *session)
2631 {
2632 int r = 0;
2633 char name[512];
2634 verto_pvt_t *tech_pvt = NULL;
2635 verto_profile_t *profile = NULL;
2636 const char *profile_name = NULL, *jsock_uuid_str = NULL;
2637 switch_channel_t *channel = switch_core_session_get_channel(session);
2638
2639 if (switch_channel_test_flag(channel, CF_VIDEO_ONLY)) {
2640 return 0;
2641 }
2642
2643 PROTECT_INTERFACE(verto_endpoint_interface);
2644
2645 profile_name = switch_channel_get_variable(channel, "verto_profile_name");
2646 jsock_uuid_str = switch_channel_get_variable(channel, "jsock_uuid_str");
2647
2648 if (!(profile_name && jsock_uuid_str && (profile = find_profile(profile_name)))) {
2649 UNPROTECT_INTERFACE(verto_endpoint_interface);
2650 return 0;
2651 }
2652
2653 tech_pvt = switch_core_session_alloc(session, sizeof(*tech_pvt));
2654 tech_pvt->pool = switch_core_session_get_pool(session);
2655 tech_pvt->session = session;
2656 tech_pvt->channel = channel;
2657 tech_pvt->jsock_uuid = (char *) jsock_uuid_str;
2658 switch_core_session_set_private_class(session, tech_pvt, SWITCH_PVT_SECONDARY);
2659
2660
2661 tech_pvt->call_id = switch_core_session_strdup(session, switch_core_session_get_uuid(session));
2662
2663 switch_snprintf(name, sizeof(name), "verto.rtc/%s", tech_pvt->jsock_uuid);
2664 switch_channel_set_name(channel, name);
2665
2666 if ((tech_pvt->smh = switch_core_session_get_media_handle(session))) {
2667 tech_pvt->mparams = switch_core_media_get_mparams(tech_pvt->smh);
2668 if (verto_set_media_options(tech_pvt, profile) != SWITCH_STATUS_SUCCESS) {
2669 UNPROTECT_INTERFACE(verto_endpoint_interface);
2670 return 0;
2671 }
2672 }
2673
2674 switch_channel_add_state_handler(channel, &verto_state_handlers);
2675 switch_core_event_hook_add_receive_message(session, messagehook);
2676
2677 //track_pvt(tech_pvt);
2678
2679 //switch_channel_clear_flag(tech_pvt->channel, CF_ANSWERED);
2680 //switch_channel_clear_flag(tech_pvt->channel, CF_EARLY_MEDIA);
2681
2682 switch_thread_rwlock_unlock(profile->rwlock);
2683
2684 r++;
2685
2686 return r;
2687 }
2688
2689
pass_sdp(verto_pvt_t * tech_pvt)2690 static void pass_sdp(verto_pvt_t *tech_pvt)
2691 {
2692 switch_core_session_t *other_session = NULL;
2693 switch_channel_t *other_channel = NULL;
2694
2695 if (switch_core_session_get_partner(tech_pvt->session, &other_session) == SWITCH_STATUS_SUCCESS) {
2696 other_channel = switch_core_session_get_channel(other_session);
2697 switch_channel_pass_sdp(tech_pvt->channel, other_channel, tech_pvt->r_sdp);
2698
2699 switch_channel_set_flag(other_channel, CF_PROXY_MODE);
2700 switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER);
2701 switch_core_session_rwunlock(other_session);
2702 }
2703 }
2704
2705
2706 //// METHODS
2707
2708 #define switch_either(_A, _B) zstr(_A) ? _B : _A
2709
verto__answer_func(const char * method,cJSON * params,jsock_t * jsock,cJSON ** response)2710 static switch_bool_t verto__answer_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response)
2711 {
2712 cJSON *obj = cJSON_CreateObject();
2713 switch_core_session_t *session;
2714 cJSON *dialog = NULL;
2715 const char *call_id = NULL, *sdp = NULL;
2716 int err = 0;
2717 const char *callee_id_name = NULL, *callee_id_number = NULL;
2718
2719 *response = obj;
2720
2721 if (!params) {
2722 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Params data missing"));
2723 err = 1; goto cleanup;
2724 }
2725
2726 if (!(dialog = cJSON_GetObjectItem(params, "dialogParams"))) {
2727 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Dialog data missing"));
2728 err = 1; goto cleanup;
2729 }
2730
2731 if (!(call_id = cJSON_GetObjectCstr(dialog, "callID"))) {
2732 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CallID missing"));
2733 err = 1; goto cleanup;
2734 }
2735
2736 if (!(sdp = cJSON_GetObjectCstr(params, "sdp"))) {
2737 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("SDP missing"));
2738 err = 1; goto cleanup;
2739 }
2740
2741 callee_id_name = cJSON_GetObjectCstr(dialog, "callee_id_name");
2742 callee_id_number = cJSON_GetObjectCstr(dialog, "callee_id_number");
2743
2744
2745 if ((session = switch_core_session_locate(call_id))) {
2746 verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY);
2747 switch_core_session_t *other_session = NULL;
2748
2749 tech_pvt->r_sdp = switch_core_session_strdup(session, sdp);
2750 switch_channel_set_variable(tech_pvt->channel, SWITCH_R_SDP_VARIABLE, sdp);
2751 switch_channel_set_variable(tech_pvt->channel, "verto_client_address", jsock->name);
2752 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Remote SDP %s:\n%s\n", switch_channel_get_name(tech_pvt->channel), sdp);
2753 switch_core_media_set_sdp_codec_string(session, sdp, SDP_TYPE_RESPONSE);
2754
2755 switch_ivr_set_user(session, jsock->uid);
2756
2757 if (switch_core_session_get_partner(tech_pvt->session, &other_session) == SWITCH_STATUS_SUCCESS) {
2758 switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
2759 switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, sdp);
2760 switch_core_session_rwunlock(other_session);
2761 }
2762
2763 if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE)) {
2764 pass_sdp(tech_pvt);
2765 } else {
2766 if (verto_tech_media(tech_pvt, tech_pvt->r_sdp, SDP_TYPE_RESPONSE) != SWITCH_STATUS_SUCCESS) {
2767 switch_channel_set_variable(tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
2768 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CODEC ERROR"));
2769 err = 1;
2770 }
2771
2772 if (!err && switch_core_media_activate_rtp(tech_pvt->session) != SWITCH_STATUS_SUCCESS) {
2773 switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
2774 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("MEDIA ERROR"));
2775 err = 1;
2776 }
2777 }
2778
2779 if (!err) {
2780 if (callee_id_name) {
2781 switch_channel_set_profile_var(tech_pvt->channel, "callee_id_name", callee_id_name);
2782 }
2783 if (callee_id_number) {
2784 switch_channel_set_profile_var(tech_pvt->channel, "callee_id_number", callee_id_number);
2785 }
2786 switch_channel_mark_answered(tech_pvt->channel);
2787 }
2788
2789 switch_core_session_rwunlock(session);
2790 } else {
2791 err = 1;
2792 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CALL DOES NOT EXIST"));
2793 }
2794
2795 cleanup:
2796
2797
2798 if (!err) return SWITCH_TRUE;
2799
2800
2801 cJSON_AddItemToObject(obj, "code", cJSON_CreateNumber(CODE_SESSION_ERROR));
2802
2803
2804 return SWITCH_FALSE;
2805
2806 }
2807
verto__bye_func(const char * method,cJSON * params,jsock_t * jsock,cJSON ** response)2808 static switch_bool_t verto__bye_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response)
2809 {
2810 cJSON *obj = cJSON_CreateObject(), *causeObj = NULL;
2811 switch_core_session_t *session;
2812 cJSON *dialog = NULL;
2813 const char *call_id = NULL, *cause_str = NULL;
2814 int err = 0, got_cause = 0;
2815 switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
2816
2817 *response = obj;
2818
2819 if (!params) {
2820 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Params data missing"));
2821 err = 1; goto cleanup;
2822 }
2823
2824 if (!(dialog = cJSON_GetObjectItem(params, "dialogParams"))) {
2825 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Dialog data missing"));
2826 err = 1; goto cleanup;
2827 }
2828
2829 if (!(call_id = cJSON_GetObjectCstr(dialog, "callID"))) {
2830 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CallID missing"));
2831 err = 1; goto cleanup;
2832 }
2833
2834 if ((cause_str = cJSON_GetObjectCstr(params, "cause"))) {
2835 switch_call_cause_t check = switch_channel_str2cause(cause_str);
2836
2837 if (check != SWITCH_CAUSE_NONE) {
2838 cause = check;
2839 got_cause = 1;
2840 }
2841 }
2842
2843 if (!got_cause && (causeObj = cJSON_GetObjectItem(params, "causeCode"))) {
2844 int check = 0;
2845 const char *cause_str = NULL;
2846
2847 if (!zstr(causeObj->valuestring)) {
2848 check = atoi(causeObj->valuestring);
2849 } else if (causeObj->valueint) {
2850 check = causeObj->valueint;
2851 }
2852
2853 cause_str = switch_channel_cause2str((switch_call_cause_t)check);
2854
2855 if (!zstr(cause_str) && strcasecmp(cause_str, "unknown")) {
2856 cause = (switch_call_cause_t) check;
2857 }
2858 }
2859
2860 cJSON_AddItemToObject(obj, "callID", cJSON_CreateString(call_id));
2861
2862 if ((session = switch_core_session_locate(call_id))) {
2863 verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY);
2864 tech_pvt->remote_hangup_cause = cause;
2865 switch_channel_set_variable(tech_pvt->channel, "verto_hangup_disposition", "recv_bye");
2866 switch_channel_hangup(tech_pvt->channel, cause);
2867
2868 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CALL ENDED"));
2869 cJSON_AddItemToObject(obj, "causeCode", cJSON_CreateNumber(cause));
2870 cJSON_AddItemToObject(obj, "cause", cJSON_CreateString(switch_channel_cause2str(cause)));
2871 switch_core_session_rwunlock(session);
2872 } else {
2873 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CALL DOES NOT EXIST"));
2874 err = 1;
2875 }
2876
2877 cleanup:
2878
2879
2880 if (!err) return SWITCH_TRUE;
2881
2882
2883 cJSON_AddItemToObject(obj, "code", cJSON_CreateNumber(CODE_SESSION_ERROR));
2884
2885
2886 return SWITCH_FALSE;
2887 }
2888
xfer_hanguphook(switch_core_session_t * session)2889 static switch_status_t xfer_hanguphook(switch_core_session_t *session)
2890 {
2891 switch_channel_t *channel = switch_core_session_get_channel(session);
2892 switch_channel_state_t state = switch_channel_get_state(channel);
2893
2894 if (state == CS_HANGUP) {
2895 switch_core_session_t *ksession;
2896 const char *uuid = switch_channel_get_variable(channel, "att_xfer_kill_uuid");
2897
2898 if (uuid && (ksession = switch_core_session_force_locate(uuid))) {
2899 switch_channel_t *kchannel = switch_core_session_get_channel(ksession);
2900
2901 switch_channel_clear_flag(kchannel, CF_XFER_ZOMBIE);
2902 switch_channel_clear_flag(kchannel, CF_TRANSFER);
2903 if (switch_channel_up(kchannel)) {
2904 switch_channel_hangup(kchannel, SWITCH_CAUSE_NORMAL_CLEARING);
2905 }
2906
2907 switch_core_session_rwunlock(ksession);
2908 }
2909
2910 switch_core_event_hook_remove_state_change(session, xfer_hanguphook);
2911
2912 }
2913
2914 return SWITCH_STATUS_SUCCESS;
2915 }
2916
mark_transfer_record(switch_core_session_t * session,const char * br_a,const char * br_b)2917 static void mark_transfer_record(switch_core_session_t *session, const char *br_a, const char *br_b)
2918 {
2919 switch_core_session_t *br_b_session, *br_a_session;
2920 switch_channel_t *channel;
2921 const char *uvar1, *dvar1, *uvar2, *dvar2;
2922
2923 channel = switch_core_session_get_channel(session);
2924
2925 uvar1 = "verto_user";
2926 dvar1 = "verto_host";
2927
2928 if ((br_b_session = switch_core_session_locate(br_b)) ) {
2929 switch_channel_t *br_b_channel = switch_core_session_get_channel(br_b_session);
2930 switch_caller_profile_t *cp = switch_channel_get_caller_profile(br_b_channel);
2931
2932 if (switch_channel_direction(br_b_channel) == SWITCH_CALL_DIRECTION_INBOUND) {
2933 uvar2 = "sip_from_user";
2934 dvar2 = "sip_from_host";
2935 } else {
2936 uvar2 = "sip_to_user";
2937 dvar2 = "sip_to_host";
2938 }
2939
2940 cp->transfer_source = switch_core_sprintf(cp->pool,
2941 "%ld:%s:att_xfer:%s@%s/%s@%s",
2942 (long) switch_epoch_time_now(NULL),
2943 cp->uuid_str,
2944 switch_channel_get_variable(channel, uvar1),
2945 switch_channel_get_variable(channel, dvar1),
2946 switch_channel_get_variable(br_b_channel, uvar2),
2947 switch_channel_get_variable(br_b_channel, dvar2));
2948
2949 switch_channel_add_variable_var_check(br_b_channel, SWITCH_TRANSFER_HISTORY_VARIABLE, cp->transfer_source, SWITCH_FALSE, SWITCH_STACK_PUSH);
2950 switch_channel_set_variable(br_b_channel, SWITCH_TRANSFER_SOURCE_VARIABLE, cp->transfer_source);
2951
2952 switch_core_session_rwunlock(br_b_session);
2953 }
2954
2955
2956
2957 if ((br_a_session = switch_core_session_locate(br_a)) ) {
2958 switch_channel_t *br_a_channel = switch_core_session_get_channel(br_a_session);
2959 switch_caller_profile_t *cp = switch_channel_get_caller_profile(br_a_channel);
2960
2961 if (switch_channel_direction(br_a_channel) == SWITCH_CALL_DIRECTION_INBOUND) {
2962 uvar2 = "sip_from_user";
2963 dvar2 = "sip_from_host";
2964 } else {
2965 uvar2 = "sip_to_user";
2966 dvar2 = "sip_to_host";
2967 }
2968
2969 cp->transfer_source = switch_core_sprintf(cp->pool,
2970 "%ld:%s:att_xfer:%s@%s/%s@%s",
2971 (long) switch_epoch_time_now(NULL),
2972 cp->uuid_str,
2973 switch_channel_get_variable(channel, uvar1),
2974 switch_channel_get_variable(channel, dvar1),
2975 switch_channel_get_variable(br_a_channel, uvar2),
2976 switch_channel_get_variable(br_a_channel, dvar2));
2977
2978 switch_channel_add_variable_var_check(br_a_channel, SWITCH_TRANSFER_HISTORY_VARIABLE, cp->transfer_source, SWITCH_FALSE, SWITCH_STACK_PUSH);
2979 switch_channel_set_variable(br_a_channel, SWITCH_TRANSFER_SOURCE_VARIABLE, cp->transfer_source);
2980
2981 switch_core_session_rwunlock(br_a_session);
2982 }
2983
2984
2985 }
2986
attended_transfer(switch_core_session_t * session,switch_core_session_t * b_session)2987 static switch_bool_t attended_transfer(switch_core_session_t *session, switch_core_session_t *b_session) {
2988 verto_pvt_t *tech_pvt = NULL, *b_tech_pvt = NULL;
2989 switch_bool_t result = SWITCH_FALSE;
2990 const char *br_a = NULL, *br_b = NULL;
2991
2992 tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY);
2993 b_tech_pvt = switch_core_session_get_private_class(b_session, SWITCH_PVT_SECONDARY);
2994
2995 if (tech_pvt && b_tech_pvt) {
2996 switch_channel_set_variable(tech_pvt->channel, "refer_uuid", switch_core_session_get_uuid(b_tech_pvt->session));
2997 switch_channel_set_variable(tech_pvt->channel, "transfer_disposition", "recv_replace");
2998 switch_channel_set_variable(b_tech_pvt->channel, "transfer_disposition", "replaced");
2999
3000 br_a = switch_channel_get_partner_uuid(tech_pvt->channel);
3001 br_b = switch_channel_get_partner_uuid(b_tech_pvt->channel);
3002
3003 if (!switch_ivr_uuid_exists(br_a)) {
3004 br_a = NULL;
3005 }
3006
3007 if (!switch_ivr_uuid_exists(br_b)) {
3008 br_b = NULL;
3009 }
3010 }
3011
3012 if (tech_pvt && b_tech_pvt && switch_channel_test_flag(b_tech_pvt->channel, CF_ORIGINATOR)) {
3013 switch_core_session_t *a_session;
3014
3015 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE,
3016 "Attended Transfer on originating session %s\n", switch_core_session_get_uuid(b_session));
3017
3018
3019
3020 switch_channel_set_variable_printf(b_tech_pvt->channel, "transfer_to", "satt:%s", br_a);
3021
3022 switch_channel_set_variable(b_tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER");
3023
3024
3025 switch_channel_clear_flag(b_tech_pvt->channel, CF_LEG_HOLDING);
3026 switch_channel_set_variable(b_tech_pvt->channel, SWITCH_HOLDING_UUID_VARIABLE, br_a);
3027 switch_channel_set_flag(b_tech_pvt->channel, CF_XFER_ZOMBIE);
3028 switch_channel_set_flag(b_tech_pvt->channel, CF_TRANSFER);
3029
3030
3031 if ((a_session = switch_core_session_locate(br_a))) {
3032 const char *moh = "local_stream://moh";
3033 switch_channel_t *a_channel = switch_core_session_get_channel(a_session);
3034 switch_caller_profile_t *prof = switch_channel_get_caller_profile(b_tech_pvt->channel);
3035 const char *tmp;
3036
3037 switch_core_event_hook_add_state_change(a_session, xfer_hanguphook);
3038 switch_channel_set_variable(a_channel, "att_xfer_kill_uuid", switch_core_session_get_uuid(b_session));
3039 switch_channel_set_variable(a_channel, "att_xfer_destination_number", prof->destination_number);
3040 switch_channel_set_variable(a_channel, "att_xfer_callee_id_name", prof->callee_id_name);
3041 switch_channel_set_variable(a_channel, "att_xfer_callee_id_number", prof->callee_id_number);
3042
3043 if ((tmp = switch_channel_get_hold_music(a_channel))) {
3044 moh = tmp;
3045 }
3046
3047 if (!zstr(moh) && !strcasecmp(moh, "silence")) {
3048 moh = NULL;
3049 }
3050
3051 if (moh) {
3052 char *xdest;
3053 xdest = switch_core_session_sprintf(a_session, "m:\":endless_playback:%s\"park", moh);
3054 switch_ivr_session_transfer(a_session, xdest, "inline", NULL);
3055 } else {
3056 switch_ivr_session_transfer(a_session, "park", "inline", NULL);
3057 }
3058
3059 switch_core_session_rwunlock(a_session);
3060
3061 result = SWITCH_TRUE;
3062
3063 switch_channel_hangup(b_tech_pvt->channel, SWITCH_CAUSE_NORMAL_CLEARING);
3064 } else {
3065 result = SWITCH_FALSE;
3066 }
3067
3068 } else if (br_a && br_b) {
3069 switch_core_session_t *tmp = NULL;
3070
3071 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Attended Transfer [%s][%s]\n",
3072 switch_str_nil(br_a), switch_str_nil(br_b));
3073
3074 if ((tmp = switch_core_session_locate(br_b))) {
3075 switch_channel_t *tchannel = switch_core_session_get_channel(tmp);
3076
3077 switch_channel_set_variable(tchannel, "transfer_disposition", "bridge");
3078
3079 switch_channel_set_flag(tchannel, CF_ATTENDED_TRANSFER);
3080 switch_core_session_rwunlock(tmp);
3081 }
3082
3083 if (switch_true(switch_channel_get_variable(tech_pvt->channel, "recording_follow_transfer")) &&
3084 (tmp = switch_core_session_locate(br_a))) {
3085 switch_channel_set_variable(switch_core_session_get_channel(tmp), "transfer_disposition", "bridge");
3086 switch_ivr_transfer_recordings(session, tmp);
3087 switch_core_session_rwunlock(tmp);
3088 }
3089
3090
3091 if (switch_true(switch_channel_get_variable(b_tech_pvt->channel, "recording_follow_transfer")) &&
3092 (tmp = switch_core_session_locate(br_b))) {
3093 switch_ivr_transfer_recordings(b_session, tmp);
3094 switch_core_session_rwunlock(tmp);
3095 }
3096
3097 switch_channel_set_variable_printf(tech_pvt->channel, "transfer_to", "att:%s", br_b);
3098
3099 mark_transfer_record(session, br_a, br_b);
3100
3101 switch_ivr_uuid_bridge(br_a, br_b);
3102 switch_channel_set_variable(b_tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER");
3103
3104 result = SWITCH_TRUE;
3105
3106 switch_channel_clear_flag(b_tech_pvt->channel, CF_LEG_HOLDING);
3107 switch_channel_set_variable(b_tech_pvt->channel, "park_timeout", "2:attended_transfer");
3108 switch_channel_set_state(b_tech_pvt->channel, CS_PARK);
3109
3110 } else {
3111 if (!br_a && !br_b) {
3112 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
3113 "Cannot transfer channels that are not in a bridge.\n");
3114 result = SWITCH_FALSE;
3115 } else {
3116 switch_core_session_t *t_session, *hup_session;
3117 switch_channel_t *hup_channel;
3118 const char *ext;
3119
3120 if (br_a && !br_b) {
3121 t_session = switch_core_session_locate(br_a);
3122 hup_channel = b_tech_pvt->channel;
3123 hup_session = b_session;
3124 } else {
3125 verto_pvt_t *h_tech_pvt = (verto_pvt_t *) switch_core_session_get_private_class(b_session, SWITCH_PVT_SECONDARY);
3126 t_session = switch_core_session_locate(br_b);
3127 hup_channel = tech_pvt->channel;
3128 hup_session = session;
3129 switch_channel_clear_flag(h_tech_pvt->channel, CF_LEG_HOLDING);
3130 switch_channel_hangup(b_tech_pvt->channel, SWITCH_CAUSE_ATTENDED_TRANSFER);
3131 }
3132
3133 if (t_session) {
3134 //switch_channel_t *t_channel = switch_core_session_get_channel(t_session);
3135 const char *idest = switch_channel_get_variable(hup_channel, "inline_destination");
3136 ext = switch_channel_get_variable(hup_channel, "destination_number");
3137
3138 if (switch_true(switch_channel_get_variable(hup_channel, "recording_follow_transfer"))) {
3139 switch_ivr_transfer_recordings(hup_session, t_session);
3140 }
3141
3142 if (idest) {
3143 switch_ivr_session_transfer(t_session, idest, "inline", NULL);
3144 } else {
3145 switch_ivr_session_transfer(t_session, ext, NULL, NULL);
3146 }
3147
3148 result = SWITCH_TRUE;
3149 switch_channel_hangup(hup_channel, SWITCH_CAUSE_ATTENDED_TRANSFER);
3150 switch_core_session_rwunlock(t_session);
3151 } else {
3152 result = SWITCH_FALSE;
3153 }
3154 }
3155 }
3156
3157 return result;
3158 }
3159
3160
verto__modify_func(const char * method,cJSON * params,jsock_t * jsock,cJSON ** response)3161 static switch_bool_t verto__modify_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response)
3162 {
3163 cJSON *obj = cJSON_CreateObject();
3164 switch_core_session_t *session;
3165 cJSON *dialog = NULL;
3166 const char *call_id = NULL, *destination = NULL, *action = NULL;
3167 int err = 0;
3168
3169 *response = obj;
3170
3171 if (!params) {
3172 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Params data missing"));
3173 err = 1; goto cleanup;
3174 }
3175
3176 if (!(dialog = cJSON_GetObjectItem(params, "dialogParams"))) {
3177 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Dialog data missing"));
3178 err = 1; goto cleanup;
3179 }
3180
3181 if (!(call_id = cJSON_GetObjectCstr(dialog, "callID"))) {
3182 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CallID missing"));
3183 err = 1; goto cleanup;
3184 }
3185
3186 if (!(action = cJSON_GetObjectCstr(params, "action"))) {
3187 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("action missing"));
3188 err = 1; goto cleanup;
3189 }
3190
3191 cJSON_AddItemToObject(obj, "callID", cJSON_CreateString(call_id));
3192 cJSON_AddItemToObject(obj, "action", cJSON_CreateString(action));
3193
3194
3195 if ((session = switch_core_session_locate(call_id))) {
3196 verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY);
3197
3198 if (!strcasecmp(action, "transfer")) {
3199 switch_core_session_t *other_session = NULL;
3200
3201 if (!(destination = cJSON_GetObjectCstr(params, "destination"))) {
3202 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("destination missing"));
3203 err = 1; goto rwunlock;
3204 }
3205
3206 if (switch_core_session_get_partner(tech_pvt->session, &other_session) == SWITCH_STATUS_SUCCESS) {
3207 switch_ivr_session_transfer(other_session, destination, NULL, NULL);
3208 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CALL TRANSFERRED"));
3209 switch_channel_set_variable(tech_pvt->channel, "transfer_disposition", "recv_replace");
3210 switch_core_session_rwunlock(other_session);
3211 } else {
3212 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("call is not bridged"));
3213 err = 1; goto rwunlock;
3214 }
3215
3216 } else if (!strcasecmp(action, "replace")) {
3217 const char *replace_call_id;
3218 switch_core_session_t *b_session = NULL;
3219
3220 if (!(replace_call_id = cJSON_GetObjectCstr(params, "replaceCallID"))) {
3221 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("replaceCallID missing"));
3222 err = 1; goto rwunlock;
3223 }
3224
3225 if ((b_session = switch_core_session_locate(replace_call_id))) {
3226 err = (int) attended_transfer(session, b_session);
3227 if (err) {
3228 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("transfer failed"));
3229 }
3230 switch_core_session_rwunlock(b_session);
3231 } else {
3232 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("invalid transfer leg"));
3233 err = 1; goto rwunlock;
3234 }
3235 } else if (!strcasecmp(action, "hold")) {
3236 switch_core_media_toggle_hold(session, 1);
3237 } else if (!strcasecmp(action, "unhold")) {
3238 switch_core_media_toggle_hold(session, 0);
3239 } else if (!strcasecmp(action, "toggleHold")) {
3240 switch_core_media_toggle_hold(session, !!!switch_channel_test_flag(tech_pvt->channel, CF_PROTO_HOLD));
3241 }
3242
3243 cJSON_AddItemToObject(obj, "holdState", cJSON_CreateString(switch_channel_test_flag(tech_pvt->channel, CF_PROTO_HOLD) ? "held" : "active"));
3244
3245
3246 rwunlock:
3247
3248 switch_core_session_rwunlock(session);
3249 } else {
3250 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CALL DOES NOT EXIST"));
3251 err = 1;
3252 }
3253
3254 cleanup:
3255
3256
3257 if (!err) return SWITCH_TRUE;
3258
3259
3260 cJSON_AddItemToObject(obj, "code", cJSON_CreateNumber(CODE_SESSION_ERROR));
3261
3262
3263 return SWITCH_FALSE;
3264 }
3265
verto__attach_func(const char * method,cJSON * params,jsock_t * jsock,cJSON ** response)3266 static switch_bool_t verto__attach_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response)
3267 {
3268 cJSON *obj = cJSON_CreateObject();
3269 switch_core_session_t *session = NULL;
3270 int err = 0;
3271 cJSON *dialog;
3272 verto_pvt_t *tech_pvt = NULL;
3273 const char *call_id = NULL, *sdp = NULL;
3274 uint8_t match = 0, p = 0;
3275
3276 *response = obj;
3277
3278 if (!params) {
3279 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Params data missing"));
3280 err = 1; goto cleanup;
3281 }
3282
3283 if (!(dialog = cJSON_GetObjectItem(params, "dialogParams"))) {
3284 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Dialog data missing"));
3285 err = 1; goto cleanup;
3286 }
3287
3288 if (!(sdp = cJSON_GetObjectCstr(params, "sdp"))) {
3289 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("SDP missing"));
3290 err = 1; goto cleanup;
3291 }
3292
3293 if (!(call_id = cJSON_GetObjectCstr(dialog, "callID"))) {
3294 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CallID missing"));
3295 err = 1; goto cleanup;
3296 }
3297
3298 if (!(session = switch_core_session_locate(call_id))) {
3299 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CALL DOES NOT EXIST"));
3300 err = 1; goto cleanup;
3301 }
3302
3303 tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY);
3304 tech_pvt->r_sdp = switch_core_session_strdup(session, sdp);
3305
3306
3307 if (!switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED)) {
3308 switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
3309 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Cannot attach to a call that has not been answered."));
3310 err = 1; goto cleanup;
3311 }
3312
3313
3314 switch_channel_set_variable(tech_pvt->channel, SWITCH_R_SDP_VARIABLE, tech_pvt->r_sdp);
3315 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Remote SDP %s:\n%s\n",
3316 switch_channel_get_name(tech_pvt->channel), tech_pvt->r_sdp);
3317
3318 switch_core_media_clear_ice(tech_pvt->session);
3319 switch_channel_set_flag(tech_pvt->channel, CF_REINVITE);
3320 switch_channel_set_flag(tech_pvt->channel, CF_RECOVERING);
3321
3322 //switch_channel_audio_sync(tech_pvt->channel);
3323 //switch_channel_set_flag(tech_pvt->channel, CF_VIDEO_BREAK);
3324 //switch_core_session_kill_channel(tech_pvt->session, SWITCH_SIG_BREAK);
3325
3326 if ((match = switch_core_media_negotiate_sdp(tech_pvt->session, tech_pvt->r_sdp, &p, SDP_TYPE_RESPONSE))) {
3327 if (switch_core_media_activate_rtp(tech_pvt->session) != SWITCH_STATUS_SUCCESS) {
3328 switch_channel_set_variable(tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "MEDIA ERROR");
3329 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("MEDIA ERROR"));
3330 err = 1; goto cleanup;
3331 }
3332 } else {
3333 switch_channel_set_variable(tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
3334 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CODEC NEGOTIATION ERROR"));
3335 err = 1; goto cleanup;
3336 }
3337
3338 cleanup:
3339
3340 if (tech_pvt) {
3341 switch_channel_clear_flag(tech_pvt->channel, CF_REINVITE);
3342 switch_channel_clear_flag(tech_pvt->channel, CF_RECOVERING);
3343 switch_clear_flag(tech_pvt, TFLAG_ATTACH_REQ);
3344 if (switch_channel_test_flag(tech_pvt->channel, CF_CONFERENCE)) {
3345 switch_channel_set_flag(tech_pvt->channel, CF_CONFERENCE_ADV);
3346 }
3347 }
3348
3349 if (session) {
3350 switch_core_session_rwunlock(session);
3351 }
3352
3353 if (!err) {
3354 return SWITCH_TRUE;
3355 }
3356
3357 if (tech_pvt && tech_pvt->channel) {
3358 switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL);
3359 }
3360
3361
3362 cJSON_AddItemToObject(obj, "code", cJSON_CreateNumber(CODE_SESSION_ERROR));
3363
3364 return SWITCH_FALSE;
3365 }
3366
parse_user_vars(cJSON * obj,switch_core_session_t * session)3367 static void parse_user_vars(cJSON *obj, switch_core_session_t *session)
3368 {
3369 cJSON *json_ptr;
3370
3371 switch_assert(obj);
3372 switch_assert(session);
3373
3374 if ((json_ptr = cJSON_GetObjectItem(obj, "userVariables"))) {
3375 cJSON * i;
3376 switch_channel_t *channel = switch_core_session_get_channel(session);
3377
3378 for(i = json_ptr->child; i; i = i->next) {
3379 char *varname = switch_core_session_sprintf(session, "verto_dvar_%s", i->string);
3380
3381 if (i->type == cJSON_True) {
3382 switch_channel_set_variable(channel, varname, "true");
3383 } else if (i->type == cJSON_False) {
3384 switch_channel_set_variable(channel, varname, "false");
3385 } else if (!zstr(i->string) && !zstr(i->valuestring)) {
3386 switch_channel_set_variable(channel, varname, i->valuestring);
3387 }
3388 }
3389 }
3390 }
3391
verto__info_func(const char * method,cJSON * params,jsock_t * jsock,cJSON ** response)3392 static switch_bool_t verto__info_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response)
3393 {
3394 cJSON *msg = NULL, *dialog = NULL, *txt = NULL;
3395 const char *call_id = NULL, *dtmf = NULL;
3396 switch_bool_t r = SWITCH_TRUE;
3397 char *proto = VERTO_CHAT_PROTO;
3398 char *pproto = NULL;
3399 int err = 0;
3400
3401 *response = cJSON_CreateObject();
3402
3403 if (!params) {
3404 cJSON_AddItemToObject(*response, "message", cJSON_CreateString("Params data missing"));
3405 err = 1; goto cleanup;
3406 }
3407
3408 if ((dialog = cJSON_GetObjectItem(params, "dialogParams")) && (call_id = cJSON_GetObjectCstr(dialog, "callID"))) {
3409 switch_core_session_t *session = NULL;
3410
3411 if ((session = switch_core_session_locate(call_id))) {
3412
3413 parse_user_vars(dialog, session);
3414
3415 if ((dtmf = cJSON_GetObjectCstr(params, "dtmf"))) {
3416 verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY);
3417 char *send;
3418
3419 if (!tech_pvt) {
3420 cJSON_AddItemToObject(*response, "message", cJSON_CreateString("Invalid channel"));
3421 err = 1; goto cleanup;
3422 }
3423
3424 send = switch_mprintf("~%s", dtmf);
3425
3426 if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE)) {
3427 switch_core_session_t *other_session = NULL;
3428
3429 if (switch_core_session_get_partner(tech_pvt->session, &other_session) == SWITCH_STATUS_SUCCESS) {
3430 switch_core_session_send_dtmf_string(other_session, send);
3431 switch_core_session_rwunlock(other_session);
3432 }
3433 } else {
3434 switch_channel_queue_dtmf_string(tech_pvt->channel, send);
3435 }
3436 free(send);
3437 cJSON_AddItemToObject(*response, "message", cJSON_CreateString("SENT"));
3438 }
3439
3440 switch_core_session_rwunlock(session);
3441 }
3442 }
3443
3444 if ((txt = cJSON_GetObjectItem(params, "txt"))) {
3445 switch_core_session_t *session;
3446
3447 if ((session = switch_core_session_locate(call_id))) {
3448 verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY);
3449 char charbuf[2] = "";
3450 char *chardata = NULL;
3451 cJSON *data;
3452
3453 if (tech_pvt->text_read_buffer) {
3454 if ((data = cJSON_GetObjectItem(txt, "code"))) {
3455 charbuf[0] = data->valueint;
3456 chardata = charbuf;
3457 } else if ((data = cJSON_GetObjectItem(txt, "chars"))) {
3458 if (data->valuestring) {
3459 chardata = data->valuestring;
3460 } else if (data->valueint) {
3461 charbuf[0] = data->valueint;
3462 chardata = charbuf;
3463 }
3464 }
3465
3466
3467 if (chardata) {
3468 switch_mutex_lock(tech_pvt->text_read_mutex);
3469 switch_buffer_write(tech_pvt->text_read_buffer, chardata, strlen(chardata));
3470 switch_mutex_unlock(tech_pvt->text_read_mutex);
3471
3472 if ((switch_mutex_trylock(tech_pvt->text_cond_mutex) == SWITCH_STATUS_SUCCESS)) {
3473 switch_thread_cond_signal(tech_pvt->text_cond);
3474 switch_mutex_unlock(tech_pvt->text_cond_mutex);
3475 }
3476 }
3477
3478 }
3479
3480 switch_core_session_rwunlock(session);
3481 }
3482 }
3483
3484 if ((msg = cJSON_GetObjectItem(params, "msg"))) {
3485 switch_event_t *event;
3486 char *to = (char *) cJSON_GetObjectCstr(msg, "to");
3487 //char *from = (char *) cJSON_GetObjectCstr(msg, "from");
3488 cJSON *i, *indialog = cJSON_GetObjectItem(msg, "inDialog");
3489 const char *body = cJSON_GetObjectCstr(msg, "body");
3490 switch_bool_t is_dialog = indialog && (indialog->type == cJSON_True || (indialog->type == cJSON_String && switch_true(indialog->valuestring)));
3491
3492 if (!zstr(to)) {
3493 if (strchr(to, '+')) {
3494 pproto = strdup(to);
3495 switch_assert(pproto);
3496 if ((to = strchr(pproto, '+'))) {
3497 *to++ = '\0';
3498 }
3499 proto = pproto;
3500 }
3501 }
3502
3503 if (!zstr(to) && !zstr(body) && switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
3504 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", VERTO_CHAT_PROTO);
3505
3506 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from", jsock->uid);
3507 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from_user", jsock->id);
3508 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from_host", jsock->domain);
3509
3510
3511 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "to", to);
3512 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "type", "text/plain");
3513 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from_full", jsock->id);
3514 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "verto_profile", jsock->profile->name);
3515 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "verto_jsock_uuid", jsock->uuid_str);
3516
3517 for(i = msg->child; i; i = i->next) {
3518 if (!zstr(i->string) && !zstr(i->valuestring) && (!strncasecmp(i->string, "from_", 5) || !strncasecmp(i->string, "to_", 3))) {
3519 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, i->string, i->valuestring);
3520 }
3521 }
3522
3523 if (is_dialog) {
3524 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call_id", call_id);
3525 }
3526
3527 switch_event_add_body(event, "%s", body);
3528
3529 if (strcasecmp(proto, VERTO_CHAT_PROTO)) {
3530 switch_core_chat_send(proto, event);
3531 }
3532
3533 if (is_dialog) {
3534 if ((dialog = cJSON_GetObjectItem(params, "dialogParams")) && (call_id = cJSON_GetObjectCstr(dialog, "callID"))) {
3535 switch_core_session_t *session = NULL;
3536
3537 if ((session = switch_core_session_locate(call_id))) {
3538 switch_core_session_queue_event(session, &event);
3539 switch_core_session_rwunlock(session);
3540 }
3541 }
3542
3543 } else {
3544 switch_core_chat_send("GLOBAL", event);
3545 }
3546
3547 if (event) {
3548 switch_event_destroy(&event);
3549 }
3550
3551 cJSON_AddItemToObject(*response, "message", cJSON_CreateString("SENT"));
3552 r = SWITCH_TRUE;
3553
3554 } else {
3555 r = SWITCH_FALSE;
3556 cJSON_AddItemToObject(*response, "message", cJSON_CreateString("INVALID MESSAGE to and body params required"));
3557 }
3558
3559
3560 switch_safe_free(pproto);
3561 }
3562
3563 cleanup:
3564
3565 if (!err) return r;
3566
3567 cJSON_AddItemToObject(*response, "code", cJSON_CreateNumber(CODE_SESSION_ERROR));
3568
3569 return SWITCH_FALSE;
3570 }
3571
3572
3573
verto__invite_func(const char * method,cJSON * params,jsock_t * jsock,cJSON ** response)3574 static switch_bool_t verto__invite_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response)
3575 {
3576 cJSON *obj = cJSON_CreateObject(), *screenShare = NULL, *dedEnc = NULL, *mirrorInput, *bandwidth = NULL, *canvas = NULL;
3577 switch_core_session_t *session = NULL;
3578 switch_channel_t *channel;
3579 switch_event_t *var_event;
3580 switch_call_cause_t reason = SWITCH_CAUSE_INVALID_MSG_UNSPECIFIED, cancel_cause = 0;
3581 switch_caller_profile_t *caller_profile;
3582 int err = 0;
3583 cJSON *dialog;
3584 verto_pvt_t *tech_pvt;
3585 char name[512];
3586 const char *var, *destination_number, *call_id = NULL, *sdp = NULL,
3587 *caller_id_name = NULL, *caller_id_number = NULL, *remote_caller_id_name = NULL, *remote_caller_id_number = NULL,*context = NULL;
3588 switch_event_header_t *hp;
3589
3590 *response = obj;
3591
3592 PROTECT_INTERFACE(verto_endpoint_interface);
3593
3594 if (!params) {
3595 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Params data missing"));
3596 err = 1; goto cleanup;
3597 }
3598
3599 if (switch_event_create_plain(&var_event, SWITCH_EVENT_CHANNEL_DATA) != SWITCH_STATUS_SUCCESS) {
3600 err=1; goto cleanup;
3601 }
3602
3603 if (!(dialog = cJSON_GetObjectItem(params, "dialogParams"))) {
3604 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Dialog data missing"));
3605 err = 1; goto cleanup;
3606 }
3607
3608 if (!(call_id = cJSON_GetObjectCstr(dialog, "callID"))) {
3609 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CallID missing"));
3610 err = 1; goto cleanup;
3611 }
3612
3613 if (!(sdp = cJSON_GetObjectCstr(params, "sdp"))) {
3614 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("SDP missing"));
3615 err = 1; goto cleanup;
3616 }
3617
3618 switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "origination_uuid", call_id);
3619
3620 if ((reason = switch_core_session_outgoing_channel(NULL, var_event, "rtc",
3621 NULL, &session, NULL, SOF_NONE, &cancel_cause)) != SWITCH_CAUSE_SUCCESS) {
3622 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Cannot create channel"));
3623 err = 1; goto cleanup;
3624 }
3625
3626 channel = switch_core_session_get_channel(session);
3627 switch_channel_set_direction(channel, SWITCH_CALL_DIRECTION_INBOUND);
3628
3629 tech_pvt = switch_core_session_alloc(session, sizeof(*tech_pvt));
3630 tech_pvt->session = session;
3631 tech_pvt->pool = switch_core_session_get_pool(session);
3632 tech_pvt->channel = channel;
3633 tech_pvt->jsock_uuid = switch_core_session_strdup(session, jsock->uuid_str);
3634 tech_pvt->r_sdp = switch_core_session_strdup(session, sdp);
3635 switch_core_media_set_sdp_codec_string(session, sdp, SDP_TYPE_REQUEST);
3636 switch_core_session_set_private_class(session, tech_pvt, SWITCH_PVT_SECONDARY);
3637
3638 tech_pvt->call_id = switch_core_session_strdup(session, call_id);
3639
3640 if (!(destination_number = cJSON_GetObjectCstr(dialog, "destination_number"))) {
3641 destination_number = "service";
3642 }
3643
3644 switch_snprintf(name, sizeof(name), "verto.rtc/%s", destination_number);
3645 switch_channel_set_name(channel, name);
3646
3647 if ((tech_pvt->smh = switch_core_session_get_media_handle(session))) {
3648 tech_pvt->mparams = switch_core_media_get_mparams(tech_pvt->smh);
3649 if (verto_set_media_options(tech_pvt, jsock->profile) != SWITCH_STATUS_SUCCESS) {
3650 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Cannot set media options"));
3651 err = 1; goto cleanup;
3652 }
3653 } else {
3654 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Cannot create media handle"));
3655 err = 1; goto cleanup;
3656 }
3657
3658 if ((screenShare = cJSON_GetObjectItem(dialog, "screenShare")) && screenShare->type == cJSON_True) {
3659 switch_channel_set_variable(channel, "video_screen_share", "true");
3660 switch_channel_set_flag(channel, CF_VIDEO_ONLY);
3661 }
3662
3663 if ((dedEnc = cJSON_GetObjectItem(dialog, "dedEnc")) && dedEnc->type == cJSON_True) {
3664 switch_channel_set_variable(channel, "video_use_dedicated_encoder", "true");
3665 }
3666
3667 if ((mirrorInput = cJSON_GetObjectItem(dialog, "mirrorInput")) && mirrorInput->type == cJSON_True) {
3668 switch_channel_set_variable(channel, "video_mirror_input", "true");
3669 switch_channel_set_flag(channel, CF_VIDEO_MIRROR_INPUT);
3670 }
3671
3672 if ((canvas = cJSON_GetObjectItem(dialog, "conferenceCanvasID"))) {
3673 int canvas_id = 0;
3674
3675 if (!zstr(canvas->valuestring)) {
3676 canvas_id = atoi(canvas->valuestring);
3677 } else if (canvas->valueint) {
3678 canvas_id = canvas->valueint;
3679 }
3680
3681 if (canvas_id >= 0) {
3682 switch_channel_set_variable_printf(channel, "video_initial_watching_canvas", "%d", canvas_id);
3683 switch_channel_set_variable(channel, "video_second_screen", "true");
3684 }
3685 }
3686
3687 if ((bandwidth = cJSON_GetObjectItem(dialog, "outgoingBandwidth"))) {
3688 int core_bw = 0, bwval = 0;
3689 const char *val;
3690
3691 if ((val = switch_channel_get_variable_dup(channel, "rtp_video_max_bandwidth_in", SWITCH_FALSE, -1))) {
3692 core_bw = switch_parse_bandwidth_string(val);
3693 }
3694
3695 if (!zstr(bandwidth->valuestring) && strcasecmp(bandwidth->valuestring, "default")) {
3696 bwval = atoi(bandwidth->valuestring);
3697 } else if (bandwidth->valueint) {
3698 bwval = bandwidth->valueint;
3699 }
3700
3701 if (bwval < 0) bwval = 0;
3702
3703 if (core_bw && bwval && bwval < core_bw) {
3704 switch_channel_set_variable_printf(channel, "rtp_video_max_bandwidth_in", "%d", bwval);
3705 }
3706 }
3707
3708 if ((bandwidth = cJSON_GetObjectItem(dialog, "incomingBandwidth"))) {
3709 int core_bw = 0, bwval = 0;
3710 const char *val;
3711
3712 if ((val = switch_channel_get_variable_dup(channel, "rtp_video_max_bandwidth_out", SWITCH_FALSE, -1))) {
3713 core_bw = switch_parse_bandwidth_string(val);
3714 }
3715
3716 if (!zstr(bandwidth->valuestring) && strcasecmp(bandwidth->valuestring, "default")) {
3717 bwval = atoi(bandwidth->valuestring);
3718 } else if (bandwidth->valueint) {
3719 bwval = bandwidth->valueint;
3720 }
3721
3722 if (bwval < 0) bwval = 0;
3723
3724 if (core_bw && bwval && bwval < core_bw) {
3725 switch_channel_set_variable_printf(channel, "rtp_video_max_bandwidth_out", "%d", bwval);
3726 }
3727 }
3728
3729 parse_user_vars(dialog, session);
3730
3731
3732 switch_channel_set_variable(channel, "jsock_uuid_str", jsock->uuid_str);
3733 switch_channel_set_variable(channel, "verto_user", jsock->uid);
3734 switch_channel_set_variable(channel, "presence_id", jsock->uid);
3735 switch_channel_set_variable(channel, "verto_client_address", jsock->name);
3736 switch_channel_set_variable(channel, "chat_proto", VERTO_CHAT_PROTO);
3737 switch_channel_set_variable(channel, "verto_host", jsock->domain);
3738 switch_channel_set_variable(channel, "event_channel_cookie", tech_pvt->jsock_uuid);
3739 switch_channel_set_variable(channel, "verto_profile_name", jsock->profile->name);
3740
3741 caller_id_name = cJSON_GetObjectCstr(dialog, "caller_id_name");
3742 caller_id_number = cJSON_GetObjectCstr(dialog, "caller_id_number");
3743
3744 remote_caller_id_name = cJSON_GetObjectCstr(dialog, "remote_caller_id_name");
3745 remote_caller_id_number = cJSON_GetObjectCstr(dialog, "remote_caller_id_number");
3746
3747 if (zstr(caller_id_name)) {
3748 if ((var = switch_event_get_header(jsock->params, "caller-id-name"))) {
3749 caller_id_name = var;
3750 }
3751 } else if (caller_id_name) {
3752 switch_event_add_header_string(jsock->params, SWITCH_STACK_BOTTOM, "caller-id-name", caller_id_name);
3753 }
3754
3755 if (zstr(caller_id_number)) {
3756 if ((var = switch_event_get_header(jsock->params, "caller-id-number"))) {
3757 caller_id_number = var;
3758 }
3759 }
3760
3761 if (!(context = switch_event_get_header(jsock->vars, "user_context"))) {
3762 context = switch_either(jsock->context, jsock->profile->context);
3763 }
3764
3765 if ((caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session),
3766 jsock->uid,
3767 switch_either(jsock->dialplan, jsock->profile->dialplan),
3768 caller_id_name,
3769 caller_id_number,
3770 jsock->remote_host,
3771 cJSON_GetObjectCstr(dialog, "ani"),
3772 cJSON_GetObjectCstr(dialog, "aniii"),
3773 cJSON_GetObjectCstr(dialog, "rdnis"),
3774 modname,
3775 context,
3776 destination_number))) {
3777
3778 switch_channel_set_caller_profile(channel, caller_profile);
3779
3780 }
3781
3782 switch_ivr_set_user(session, jsock->uid);
3783
3784 for (hp = jsock->user_vars->headers; hp; hp = hp->next) {
3785 switch_channel_set_variable(channel, hp->name, hp->value);
3786 }
3787
3788
3789 switch_channel_set_profile_var(channel, "callee_id_name", remote_caller_id_name);
3790 switch_channel_set_profile_var(channel, "callee_id_number", remote_caller_id_number);
3791
3792
3793 switch_channel_set_variable(channel, "verto_remote_caller_id_name", remote_caller_id_name);
3794 switch_channel_set_variable(channel, "verto_remote_caller_id_number", remote_caller_id_number);
3795
3796
3797
3798 switch_channel_set_variable(channel, SWITCH_R_SDP_VARIABLE, sdp);
3799 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Remote SDP %s:\n%s\n", switch_channel_get_name(tech_pvt->channel), sdp);
3800
3801 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CALL CREATED"));
3802 cJSON_AddItemToObject(obj, "callID", cJSON_CreateString(tech_pvt->call_id));
3803
3804 switch_channel_add_state_handler(channel, &verto_state_handlers);
3805 switch_core_event_hook_add_receive_message(session, messagehook);
3806 switch_channel_set_state(channel, CS_INIT);
3807 //track_pvt(tech_pvt);
3808 switch_core_session_thread_launch(session);
3809
3810 cleanup:
3811
3812 switch_event_destroy(&var_event);
3813
3814 if (!err) {
3815 return SWITCH_TRUE;
3816 }
3817
3818 UNPROTECT_INTERFACE(verto_endpoint_interface);
3819
3820 if (session) {
3821 switch_core_session_destroy(&session);
3822 }
3823
3824 cJSON_AddItemToObject(obj, "causeCode", cJSON_CreateNumber(reason));
3825 cJSON_AddItemToObject(obj, "cause", cJSON_CreateString(switch_channel_cause2str(reason)));
3826 cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CALL ERROR"));
3827 cJSON_AddItemToObject(obj, "code", cJSON_CreateNumber(CODE_SESSION_ERROR));
3828
3829 return SWITCH_FALSE;
3830
3831 }
3832
event_channel_check_auth(jsock_t * jsock,const char * event_channel)3833 static switch_bool_t event_channel_check_auth(jsock_t *jsock, const char *event_channel)
3834 {
3835
3836 char *main_event_channel = NULL;
3837 switch_bool_t ok = SWITCH_TRUE, pre_ok = SWITCH_FALSE;
3838 switch_core_session_t *session = NULL;
3839
3840 switch_assert(event_channel);
3841
3842 pre_ok = switch_event_channel_permission_verify(jsock->uuid_str, event_channel);
3843
3844 if (!pre_ok && (session = switch_core_session_locate(event_channel))) {
3845 switch_channel_t *channel = switch_core_session_get_channel(session);
3846 const char *jsock_uuid_str = switch_channel_get_variable(channel, "jsock_uuid_str");
3847
3848 if (jsock_uuid_str && !strcmp(jsock_uuid_str, jsock->uuid_str)) {
3849 pre_ok = SWITCH_TRUE;
3850 }
3851
3852 switch_core_session_rwunlock(session);
3853 }
3854
3855 if (pre_ok) {
3856 return pre_ok;
3857 }
3858
3859 if (jsock->allowed_event_channels) {
3860 if (strchr(event_channel, '.')) {
3861 char *p;
3862 main_event_channel = strdup(event_channel);
3863 switch_assert(main_event_channel);
3864 if ((p = strchr(main_event_channel, '.'))) {
3865 *p = '\0';
3866 }
3867 }
3868
3869 if ((!verto_globals.enable_fs_events && (!strcasecmp(event_channel, "FSevent") || (main_event_channel && !strcasecmp(main_event_channel, "FSevent")))) ||
3870 !(switch_event_get_header(jsock->allowed_event_channels, event_channel) ||
3871 (main_event_channel && switch_event_get_header(jsock->allowed_event_channels, main_event_channel)))) {
3872 ok = SWITCH_FALSE;
3873 }
3874 }
3875
3876 switch_safe_free(main_event_channel);
3877 return ok;
3878
3879 }
3880
parse_subs(jsock_t * jsock,const char * event_channel,cJSON ** sub_list,cJSON ** err_list,cJSON ** exist_list)3881 static switch_bool_t parse_subs(jsock_t *jsock, const char *event_channel, cJSON **sub_list, cJSON **err_list, cJSON **exist_list)
3882 {
3883 switch_bool_t r = SWITCH_FALSE;
3884
3885 if (event_channel_check_auth(jsock, event_channel)) {
3886 if (!*sub_list) {
3887 *sub_list = cJSON_CreateArray();
3888 }
3889
3890 if (jsock_sub_channel(jsock, event_channel) == SWITCH_STATUS_SUCCESS) {
3891 cJSON_AddItemToArray(*sub_list, cJSON_CreateString(event_channel));
3892 } else {
3893 if (!*exist_list) {
3894 *exist_list = cJSON_CreateArray();
3895 }
3896 cJSON_AddItemToArray(*exist_list, cJSON_CreateString(event_channel));
3897 }
3898
3899 r = SWITCH_TRUE;
3900 } else {
3901 if (!*err_list) {
3902 *err_list = cJSON_CreateArray();
3903 }
3904 cJSON_AddItemToArray(*err_list, cJSON_CreateString(event_channel));
3905 }
3906
3907 return r;
3908 }
3909
verto__subscribe_func(const char * method,cJSON * params,jsock_t * jsock,cJSON ** response)3910 static switch_bool_t verto__subscribe_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response)
3911 {
3912 switch_bool_t r = SWITCH_TRUE;
3913 cJSON *subs = NULL, *errs = NULL, *exist = NULL;
3914
3915 *response = cJSON_CreateObject();
3916
3917 if (params) {
3918 cJSON *jchannel = cJSON_GetObjectItem(params, "eventChannel");
3919
3920 if (jchannel) {
3921 if (jchannel->type == cJSON_String) {
3922 parse_subs(jsock, jchannel->valuestring, &subs, &errs, &exist);
3923 } else if (jchannel->type == cJSON_Array) {
3924 int i, len = cJSON_GetArraySize(jchannel);
3925
3926 for(i = 0; i < len; i++) {
3927 cJSON *str = cJSON_GetArrayItem(jchannel, i);
3928 if (str->type == cJSON_String) {
3929 parse_subs(jsock, str->valuestring, &subs, &errs, &exist);
3930 }
3931 }
3932 }
3933 }
3934 }
3935
3936 if (subs) {
3937 cJSON_AddItemToObject(*response, "subscribedChannels", subs);
3938 }
3939
3940 if (errs) {
3941 cJSON_AddItemToObject(*response, "unauthorizedChannels", errs);
3942 }
3943
3944 if (exist) {
3945 cJSON_AddItemToObject(*response, "alreadySubscribedChannels", exist);
3946 }
3947
3948 if (!subs) {
3949 r = SWITCH_FALSE;
3950 }
3951
3952 return r;
3953 }
3954
do_unsub(jsock_t * jsock,const char * event_channel,cJSON ** subs,cJSON ** errs)3955 static void do_unsub(jsock_t *jsock, const char *event_channel, cJSON **subs, cJSON **errs)
3956 {
3957 if (jsock_unsub_channel(jsock, event_channel)) {
3958 if (!*subs) {
3959 *subs = cJSON_CreateArray();
3960 }
3961 cJSON_AddItemToArray(*subs, cJSON_CreateString(event_channel));
3962 } else {
3963 if (!*errs) {
3964 *errs = cJSON_CreateArray();
3965 }
3966 cJSON_AddItemToArray(*errs, cJSON_CreateString(event_channel));
3967 }
3968 }
3969
verto__unsubscribe_func(const char * method,cJSON * params,jsock_t * jsock,cJSON ** response)3970 static switch_bool_t verto__unsubscribe_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response)
3971 {
3972 switch_bool_t r = SWITCH_TRUE;
3973 cJSON *subs = NULL, *errs = NULL;
3974
3975 *response = cJSON_CreateObject();
3976
3977 if (params) {
3978 cJSON *jchannel = cJSON_GetObjectItem(params, "eventChannel");
3979
3980 if (jchannel) {
3981 if (jchannel->type == cJSON_String) {
3982 do_unsub(jsock, jchannel->valuestring, &subs, &errs);
3983 } else if (jchannel->type == cJSON_Array) {
3984 int i, len = cJSON_GetArraySize(jchannel);
3985
3986 for(i = 0; i < len; i++) {
3987 cJSON *str = cJSON_GetArrayItem(jchannel, i);
3988 if (str->type == cJSON_String) {
3989 do_unsub(jsock, str->valuestring, &subs, &errs);
3990 }
3991 }
3992 }
3993 }
3994 }
3995
3996 if (subs) {
3997 cJSON_AddItemToObject(*response, "unsubscribedChannels", subs);
3998 }
3999
4000 if (errs) {
4001 cJSON_AddItemToObject(*response, "notSubscribedChannels", errs);
4002 }
4003
4004 if (errs && !subs) {
4005 r = SWITCH_FALSE;
4006 }
4007
4008 return r;
4009 }
4010
verto__broadcast_func(const char * method,cJSON * params,jsock_t * jsock,cJSON ** response)4011 static switch_bool_t verto__broadcast_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response)
4012 {
4013 char *json_text = NULL;
4014 const char *event_channel = cJSON_GetObjectCstr(params, "eventChannel");
4015 cJSON *jevent, *broadcast;
4016 const char *display = NULL;
4017
4018 *response = cJSON_CreateObject();
4019
4020
4021 if (!event_channel) {
4022 cJSON_AddItemToObject(*response, "message", cJSON_CreateString("eventChannel not specified."));
4023 cJSON_AddItemToObject(*response, "code", cJSON_CreateNumber(CODE_SESSION_ERROR));
4024 goto end;
4025 }
4026
4027 if (!event_channel_check_auth(jsock, event_channel)) {
4028 cJSON_AddItemToObject(*response, "message", cJSON_CreateString("Permission Denied."));
4029 cJSON_AddItemToObject(*response, "code", cJSON_CreateNumber(CODE_SESSION_ERROR));
4030 goto end;
4031 }
4032
4033
4034 cJSON_AddItemToObject(params, "userid", cJSON_CreateString(jsock->uid));
4035
4036 display = switch_event_get_header(jsock->params, "caller-id-name");
4037 if (display) {
4038 cJSON_AddItemToObject(params, "fromDisplay", cJSON_CreateString(display));
4039 }
4040
4041 jevent = cJSON_Duplicate(params, 1);
4042
4043 broadcast = cJSON_GetObjectItem(params, "localBroadcast");
4044
4045 if (broadcast && broadcast->type == cJSON_True) {
4046 write_event(event_channel, NULL, jevent);
4047 } else {
4048 switch_event_channel_broadcast(event_channel, &jevent, modname, verto_globals.event_channel_id);
4049 }
4050
4051 if (jsock->profile->mcast_pub.sock != ws_sock_invalid) {
4052 if ((json_text = cJSON_PrintUnformatted(params))) {
4053
4054 if (mcast_socket_send(&jsock->profile->mcast_pub, json_text, strlen(json_text) + 1) <= 0) {
4055 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "multicast socket send error! %s\n", strerror(errno));
4056 //r = SWITCH_FALSE;
4057 //cJSON_AddItemToObject(*response, "message", cJSON_CreateString("MCAST Data Send failure!"));
4058 } else {
4059 //r = SWITCH_TRUE;
4060 //cJSON_AddItemToObject(*response, "message", cJSON_CreateString("MCAST Data Sent"));
4061 if (verto_globals.debug > 0) {
4062 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "MCAST Data Sent: %s\n",json_text);
4063 }
4064 }
4065 free(json_text);
4066 json_text = NULL;
4067 } else {
4068 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "JSON ERROR!\n");
4069 }
4070 }
4071
4072 end:
4073
4074 return SWITCH_TRUE;
4075 }
4076
login_func(const char * method,cJSON * params,jsock_t * jsock,cJSON ** response)4077 static switch_bool_t login_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response)
4078 {
4079 *response = cJSON_CreateObject();
4080 cJSON_AddItemToObject(*response, "message", cJSON_CreateString("logged in"));
4081
4082 login_fire_custom_event(jsock, params, 1, "Logged in");
4083
4084 return SWITCH_TRUE;
4085 }
4086
echo_func(const char * method,cJSON * params,jsock_t * jsock,cJSON ** response)4087 static switch_bool_t echo_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response)
4088 {
4089 if (params) {
4090 *response = cJSON_Duplicate(params, 1);
4091 return SWITCH_TRUE;
4092 }
4093
4094 *response = cJSON_CreateObject();
4095
4096 cJSON_AddItemToObject(*response, "message", cJSON_CreateString("Params data missing"));
4097 cJSON_AddItemToObject(*response, "code", cJSON_CreateNumber(CODE_SESSION_ERROR));
4098
4099 return SWITCH_FALSE;
4100 }
4101
jsapi_func(const char * method,cJSON * params,jsock_t * jsock,cJSON ** response)4102 static switch_bool_t jsapi_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response)
4103 {
4104 if (jsock->allowed_jsapi) {
4105 const char *function;
4106
4107 if (params) {
4108 if ((function = cJSON_GetObjectCstr(params, "command"))) {
4109 if (!switch_event_get_header(jsock->allowed_jsapi, function)) {
4110 return SWITCH_FALSE;
4111 }
4112
4113 if (jsock->allowed_fsapi && !strcmp(function, "fsapi")) {
4114 cJSON *data = cJSON_GetObjectItem(params, "data");
4115 if (data) {
4116 cJSON *cmd = cJSON_GetObjectItem(data, "cmd");
4117 cJSON *arg = cJSON_GetObjectItem(data, "arg");
4118
4119 if (cmd && cmd->type == cJSON_String && cmd->valuestring &&
4120 !auth_api_command(jsock, cmd->valuestring, arg ? arg->valuestring : NULL)) {
4121 return SWITCH_FALSE;
4122 }
4123 }
4124 }
4125 }
4126 }
4127 }
4128
4129 switch_json_api_execute(params, NULL, response);
4130
4131 return *response ? SWITCH_TRUE : SWITCH_FALSE;
4132 }
4133
fsapi_func(const char * method,cJSON * params,jsock_t * jsock,cJSON ** response)4134 static switch_bool_t fsapi_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response)
4135 {
4136 cJSON *cmd = NULL, *arg = NULL, *reply;
4137 switch_stream_handle_t stream = { 0 };
4138 switch_status_t status = SWITCH_STATUS_SUCCESS;
4139
4140 if (params) {
4141 cmd = cJSON_GetObjectItem(params, "cmd");
4142 arg = cJSON_GetObjectItem(params, "arg");
4143 }
4144
4145 if (cmd && jsock->allowed_fsapi) {
4146 if (cmd->type == cJSON_String && cmd->valuestring && !auth_api_command(jsock, cmd->valuestring, arg ? arg->valuestring : NULL)) {
4147 return SWITCH_FALSE;
4148 }
4149 }
4150
4151 if (cmd && !cmd->valuestring) {
4152 cmd = NULL;
4153 }
4154
4155 if (arg && !arg->valuestring) {
4156 arg = NULL;
4157 }
4158
4159 reply = cJSON_CreateObject();
4160
4161 SWITCH_STANDARD_STREAM(stream);
4162
4163 if (cmd && (status = switch_api_execute(cmd->valuestring, arg ? arg->valuestring : NULL, NULL, &stream)) == SWITCH_STATUS_SUCCESS) {
4164 cJSON_AddItemToObject(reply, "message", cJSON_CreateString((char *) stream.data));
4165 } else {
4166 cJSON_AddItemToObject(reply, "message", cJSON_CreateString("INVALID CALL"));
4167 }
4168
4169 switch_safe_free(stream.data);
4170
4171 if (reply) {
4172 *response = reply;
4173 return SWITCH_TRUE;
4174 }
4175
4176 return SWITCH_FALSE;
4177 }
4178
4179 ////
4180
jrpc_init(void)4181 static void jrpc_init(void)
4182 {
4183 jrpc_add_func("echo", echo_func);
4184 jrpc_add_func("jsapi", jsapi_func);
4185 jrpc_add_func("fsapi", fsapi_func);
4186 jrpc_add_func("login", login_func);
4187
4188 jrpc_add_func("verto.invite", verto__invite_func);
4189 jrpc_add_func("verto.info", verto__info_func);
4190 jrpc_add_func("verto.attach", verto__attach_func);
4191 jrpc_add_func("verto.bye", verto__bye_func);
4192 jrpc_add_func("verto.answer", verto__answer_func);
4193 jrpc_add_func("verto.subscribe", verto__subscribe_func);
4194 jrpc_add_func("verto.unsubscribe", verto__unsubscribe_func);
4195 jrpc_add_func("verto.broadcast", verto__broadcast_func);
4196 jrpc_add_func("verto.modify", verto__modify_func);
4197
4198 }
4199
4200
4201
4202
start_jsock(verto_profile_t * profile,ws_socket_t sock,int family)4203 static int start_jsock(verto_profile_t *profile, ws_socket_t sock, int family)
4204 {
4205 jsock_t *jsock = NULL;
4206 int flag = 1;
4207 int i;
4208 #ifndef WIN32
4209 unsigned int len;
4210 #else
4211 int len;
4212 #endif
4213 jsock_type_t ptype = PTYPE_CLIENT;
4214 switch_thread_data_t *td;
4215 switch_memory_pool_t *pool;
4216 switch_event_t *s_event;
4217
4218 switch_core_new_memory_pool(&pool);
4219
4220
4221 jsock = (jsock_t *) switch_core_alloc(pool, sizeof(*jsock));
4222 jsock->pool = pool;
4223 jsock->family = family;
4224
4225 if (family == PF_INET) {
4226 len = sizeof(jsock->remote_addr);
4227
4228 if ((jsock->client_socket = accept(sock, (struct sockaddr *) &jsock->remote_addr, &len)) < 0) {
4229 die_errno("ACCEPT FAILED");
4230 }
4231 } else {
4232 len = sizeof(jsock->remote_addr6);
4233
4234 if ((jsock->client_socket = accept(sock, (struct sockaddr *) &jsock->remote_addr6, &len)) < 0) {
4235 die_errno("ACCEPT FAILED");
4236 }
4237 }
4238
4239 for (i = 0; i < profile->i; i++) {
4240 if ( profile->server_socket[i] == sock ) {
4241 if (profile->ip[i].secure) {
4242 ptype = PTYPE_CLIENT_SSL;
4243 }
4244 break;
4245 }
4246 }
4247
4248 jsock->local_sock = sock;
4249 jsock->profile = profile;
4250
4251 if (zstr(jsock->name)) {
4252 if (family == PF_INET) {
4253 jsock->remote_port = ntohs(jsock->remote_addr.sin_port);
4254 inet_ntop(AF_INET, &jsock->remote_addr.sin_addr, jsock->remote_host, sizeof(jsock->remote_host));
4255 jsock->name = switch_core_sprintf(pool, "%s:%d", jsock->remote_host, jsock->remote_port);
4256 } else {
4257 jsock->remote_port = ntohs(jsock->remote_addr6.sin6_port);
4258 inet_ntop(AF_INET6, &jsock->remote_addr6.sin6_addr, jsock->remote_host, sizeof(jsock->remote_host));
4259 jsock->name = switch_core_sprintf(pool, "[%s]:%d", jsock->remote_host, jsock->remote_port);
4260 }
4261 }
4262
4263 jsock->ptype = ptype;
4264
4265 for(i = 0; i < profile->conn_acl_count; i++) {
4266 if (!switch_check_network_list_ip(jsock->remote_host, profile->conn_acl[i])) {
4267 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Client Connect from %s:%d refused by ACL %s\n",
4268 jsock->name, jsock->remote_host, jsock->remote_port, profile->conn_acl[i]);
4269 goto error;
4270 }
4271 }
4272
4273 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Client Connect from %s:%d accepted\n",
4274 jsock->name, jsock->remote_host, jsock->remote_port);
4275
4276 if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_CLIENT_CONNECT) == SWITCH_STATUS_SUCCESS) {
4277 switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "verto_profile_name", profile->name);
4278 switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "verto_client_address", "%s", jsock->name);
4279 switch_event_fire(&s_event);
4280 }
4281
4282 /* no nagle please */
4283 setsockopt(jsock->client_socket, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag));
4284
4285
4286 #if defined(SO_KEEPALIVE)
4287 setsockopt(jsock->client_socket, SOL_SOCKET, SO_KEEPALIVE, (void *)&flag, sizeof(flag));
4288 #endif
4289 flag = 30;
4290 #if defined(TCP_KEEPIDLE)
4291 setsockopt(jsock->client_socket, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&flag, sizeof(flag));
4292 #endif
4293 #if defined(TCP_KEEPINTVL)
4294 setsockopt(jsock->client_socket, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&flag, sizeof(flag));
4295 #endif
4296
4297 td = switch_core_alloc(jsock->pool, sizeof(*td));
4298
4299 td->alloc = 0;
4300 td->func = client_thread;
4301 td->obj = jsock;
4302 td->pool = pool;
4303
4304 switch_mutex_init(&jsock->write_mutex, SWITCH_MUTEX_NESTED, jsock->pool);
4305 switch_mutex_init(&jsock->filter_mutex, SWITCH_MUTEX_NESTED, jsock->pool);
4306 switch_queue_create(&jsock->event_queue, MAX_QUEUE_LEN, jsock->pool);
4307 switch_thread_rwlock_create(&jsock->rwlock, jsock->pool);
4308 switch_thread_pool_launch_thread(&td);
4309
4310 return 0;
4311
4312 error:
4313
4314 if (jsock) {
4315 if (jsock->client_socket != ws_sock_invalid) {
4316 close_socket(&jsock->client_socket);
4317 }
4318
4319 switch_core_destroy_memory_pool(&pool);
4320 }
4321
4322 return -1;
4323 }
4324
prepare_socket(ips_t * ips)4325 static ws_socket_t prepare_socket(ips_t *ips)
4326 {
4327 ws_socket_t sock = ws_sock_invalid;
4328 #ifndef WIN32
4329 int reuse_addr = 1;
4330 #else
4331 char reuse_addr = 1;
4332 #endif
4333 int family;
4334 struct sockaddr_in addr;
4335 struct sockaddr_in6 addr6;
4336
4337 if (strchr(ips->local_ip, ':')) {
4338 family = PF_INET6;
4339 } else {
4340 family = PF_INET;
4341 }
4342
4343 if ((sock = socket(family, SOCK_STREAM, IPPROTO_TCP)) < 0) {
4344 die_errno("Socket Error!");
4345 }
4346
4347 if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)) < 0 ) {
4348 die_errno("Socket setsockopt Error!");
4349 }
4350
4351 if (family == PF_INET) {
4352 memset(&addr, 0, sizeof(addr));
4353 addr.sin_family = AF_INET;
4354 addr.sin_addr.s_addr = inet_addr(ips->local_ip);
4355 addr.sin_port = htons(ips->local_port);
4356 if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
4357 die_errno("Bind Error!");
4358 }
4359 } else {
4360 memset(&addr6, 0, sizeof(addr6));
4361 addr6.sin6_family = AF_INET6;
4362 addr6.sin6_port = htons(ips->local_port);
4363 inet_pton(AF_INET6, ips->local_ip, &(addr6.sin6_addr));
4364 if (bind(sock, (struct sockaddr *) &addr6, sizeof(addr6)) < 0) {
4365 die_errno("Bind Error!");
4366 }
4367 }
4368
4369 if (listen(sock, MAXPENDING) < 0) {
4370 die_errno("Listen error");
4371 }
4372
4373 ips->family = family;
4374
4375 return sock;
4376
4377 error:
4378
4379 close_file(&sock);
4380
4381 return ws_sock_invalid;
4382 }
4383
handle_mcast_sub(verto_profile_t * profile)4384 static void handle_mcast_sub(verto_profile_t *profile)
4385 {
4386 int bytes;
4387
4388 if (profile->mcast_sub.sock == ws_sock_invalid) {
4389 return;
4390 }
4391
4392 bytes = (int)mcast_socket_recv(&profile->mcast_sub, NULL, 0, 0);
4393
4394 if (bytes > 0) {
4395 cJSON *json;
4396
4397 profile->mcast_sub.buffer[bytes] = '\0';
4398
4399 if ((json = cJSON_Parse((char *)profile->mcast_sub.buffer))) {
4400 jsock_send_event(json);
4401 cJSON_Delete(json);
4402 } else {
4403 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s MCAST JSON PARSE ERR: %s\n", profile->name, (char *)profile->mcast_sub.buffer);
4404 }
4405
4406 } else {
4407 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s MCAST INVALID READ %d\n", profile->name, bytes);
4408 }
4409
4410 }
4411
profile_one_loop(verto_profile_t * profile)4412 static int profile_one_loop(verto_profile_t *profile)
4413 {
4414 switch_waitlist_t pfds[MAX_BIND+4];
4415 int res, x = 0;
4416 int i = 0;
4417 int max = 2;
4418
4419 memset(&pfds[0], 0, sizeof(pfds[0]) * MAX_BIND+2);
4420
4421 for (i = 0; i < profile->i; i++) {
4422 pfds[i].sock = profile->server_socket[i];
4423 pfds[i].events = SWITCH_POLL_READ|SWITCH_POLL_ERROR;
4424 }
4425
4426 if (profile->mcast_ip) {
4427 pfds[i].sock = profile->mcast_sub.sock;
4428 pfds[i++].events = SWITCH_POLL_READ|SWITCH_POLL_ERROR;
4429 }
4430
4431 max = i;
4432
4433 if ((res = switch_wait_socklist(pfds, max, 100)) < 0) {
4434 if (errno != EINTR) {
4435 die_errnof("%s POLL FAILED with %d", profile->name, res);
4436 }
4437 return 0;
4438 }
4439
4440 if (res == 0) {
4441 return 0;
4442 }
4443
4444 for (x = 0; x < max; x++) {
4445 if (pfds[x].revents & SWITCH_POLL_HUP) { log_and_exit(SWITCH_LOG_INFO, "%s POLL HANGUP DETECTED (peer closed its end of socket)\n", profile->name); }
4446 if (pfds[x].revents & SWITCH_POLL_ERROR) { die("%s POLL ERROR\n", profile->name); }
4447 if (pfds[x].revents & SWITCH_POLL_INVALID) { die("%s POLL INVALID SOCKET (not opened or already closed)\n", profile->name); }
4448 if (pfds[x].revents & SWITCH_POLL_READ) {
4449 if (profile->mcast_ip && pfds[x].sock == (switch_os_socket_t)profile->mcast_sub.sock) {
4450 handle_mcast_sub(profile);
4451 } else {
4452 start_jsock(profile, pfds[x].sock, profile->ip[x].family);
4453 }
4454 }
4455 }
4456
4457 return res;
4458
4459 error:
4460 return -1;
4461 }
4462
4463
kill_profile(verto_profile_t * profile)4464 static void kill_profile(verto_profile_t *profile)
4465 {
4466 jsock_t *p;
4467 verto_vhost_t *h;
4468 int i;
4469
4470 profile->running = 0;
4471
4472 //if (switch_thread_rwlock_tryrdlock(profile->rwlock) != SWITCH_STATUS_SUCCESS) {
4473 // return;
4474 //}
4475
4476 switch_mutex_lock(profile->mutex);
4477 for (i = 0; i < profile->i; i++) {
4478 close_socket(&profile->server_socket[i]);
4479 }
4480
4481 for(p = profile->jsock_head; p; p = p->next) {
4482 close_socket(&p->client_socket);
4483 }
4484
4485 h = profile->vhosts;
4486 while(h) {
4487 if (h->rewrites) {
4488 switch_event_destroy(&h->rewrites);
4489 }
4490
4491 h = h->next;
4492 }
4493
4494 switch_mutex_unlock(profile->mutex);
4495
4496
4497
4498 //switch_thread_rwlock_unlock(profile->rwlock);
4499 }
4500
kill_profiles(void)4501 static void kill_profiles(void)
4502 {
4503 verto_profile_t *pp;
4504 int sanity = 50;
4505
4506 switch_mutex_lock(verto_globals.mutex);
4507 for(pp = verto_globals.profile_head; pp; pp = pp->next) {
4508 kill_profile(pp);
4509 }
4510 switch_mutex_unlock(verto_globals.mutex);
4511
4512
4513 while(--sanity > 0 && verto_globals.profile_threads > 0) {
4514 switch_yield(100000);
4515 }
4516 }
4517
4518
runtime(verto_profile_t * profile)4519 static void runtime(verto_profile_t *profile)
4520 {
4521 int i;
4522 int listeners = 0;
4523
4524 for (i = 0; i < profile->i; i++) {
4525 //if ((profile->server_socket[i] = prepare_socket(profile->ip[i].local_ip_addr, profile->ip[i].local_port)) < 0) {
4526 if ((profile->server_socket[i] = prepare_socket(&profile->ip[i])) != ws_sock_invalid) {
4527 listeners++;
4528 }
4529 }
4530
4531 if (!listeners) {
4532 die("%s Client Socket Error! No Listeners!\n", profile->name);
4533 }
4534
4535 if (profile->mcast_ip) {
4536 int ok = 1;
4537
4538 if (mcast_socket_create(profile->mcast_ip, profile->mcast_port, &profile->mcast_sub, MCAST_RECV | MCAST_TTL_HOST) < 0) {
4539 ok++;
4540 }
4541
4542 if (mcast_socket_create(profile->mcast_ip, profile->mcast_port + 1, &profile->mcast_pub, MCAST_SEND | MCAST_TTL_HOST) > 0) {
4543 mcast_socket_close(&profile->mcast_sub);
4544 ok = 0;
4545 }
4546
4547 if (ok) {
4548 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s MCAST Bound to %s:%d/%d\n", profile->name, profile->mcast_ip, profile->mcast_port, profile->mcast_port + 1);
4549 } else {
4550 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s MCAST Disabled\n", profile->name);
4551 }
4552 }
4553
4554
4555 while(profile->running) {
4556 if (profile_one_loop(profile) < 0) {
4557 goto error;
4558 }
4559 }
4560
4561 error:
4562
4563 if (profile->mcast_sub.sock != ws_sock_invalid) {
4564 mcast_socket_close(&profile->mcast_sub);
4565 }
4566
4567 if (profile->mcast_pub.sock != ws_sock_invalid) {
4568 mcast_socket_close(&profile->mcast_pub);
4569 }
4570
4571 }
4572
do_shutdown(void)4573 static void do_shutdown(void)
4574 {
4575 verto_globals.running = 0;
4576
4577 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Shutting down (SIG %d)\n", verto_globals.sig);
4578
4579 kill_profiles();
4580
4581 unsub_all_jsock();
4582
4583 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Done\n");
4584 }
4585
4586
parse_ip(char * host,switch_size_t host_len,uint16_t * port,char * input)4587 static void parse_ip(char *host, switch_size_t host_len, uint16_t *port, char *input)
4588 {
4589 char *p;
4590 //struct hostent *hent;
4591
4592 if ((p = strchr(input, '['))) {
4593 char *end = switch_find_end_paren(p, '[', ']');
4594 if (end) {
4595 p++;
4596 strncpy(host, p, end - p);
4597 if (*(end+1) == ':' && end + 2 < end_of_p(input)) {
4598 end += 2;
4599 if (*end) {
4600 *port = (uint16_t)atoi(end);
4601 }
4602 }
4603 } else {
4604 strncpy(host, "::", host_len);
4605 }
4606 } else {
4607 strncpy(host, input, host_len);
4608 if ((p = strrchr(host, ':')) != NULL) {
4609 *p++ = '\0';
4610 *port = (uint16_t)atoi(p);
4611 }
4612 }
4613
4614 #if 0
4615 if ( host[0] < '0' || host[0] > '9' ) {
4616 // Non-numeric host (at least it doesn't start with one). Convert it to ip addr first
4617 if ((hent = gethostbyname(host)) != NULL) {
4618 if (hent->h_addrtype == AF_INET) {
4619 memcpy(addr, hent->h_addr_list[0], 4);
4620 }
4621 }
4622
4623 } else {
4624 *addr = inet_addr(host);
4625 }
4626 #endif
4627 }
4628
4629
find_profile(const char * name)4630 static verto_profile_t *find_profile(const char *name)
4631 {
4632 verto_profile_t *p, *r = NULL;
4633 switch_mutex_lock(verto_globals.mutex);
4634 for(p = verto_globals.profile_head; p; p = p->next) {
4635 if (!strcmp(name, p->name)) {
4636 r = p;
4637 break;
4638 }
4639 }
4640
4641 if (r && (!r->in_thread || !r->running)) {
4642 r = NULL;
4643 }
4644
4645 if (r && switch_thread_rwlock_tryrdlock(r->rwlock) != SWITCH_STATUS_SUCCESS) {
4646 r = NULL;
4647 }
4648 switch_mutex_unlock(verto_globals.mutex);
4649
4650 return r;
4651 }
4652
profile_exists(const char * name)4653 static switch_bool_t profile_exists(const char *name)
4654 {
4655 switch_bool_t r = SWITCH_FALSE;
4656 verto_profile_t *p;
4657
4658 switch_mutex_lock(verto_globals.mutex);
4659 for(p = verto_globals.profile_head; p; p = p->next) {
4660 if (!strcmp(p->name, name)) {
4661 r = SWITCH_TRUE;
4662 break;
4663 }
4664 }
4665 switch_mutex_unlock(verto_globals.mutex);
4666
4667 return r;
4668 }
4669
del_profile(verto_profile_t * profile)4670 static void del_profile(verto_profile_t *profile)
4671 {
4672 verto_profile_t *p, *last = NULL;
4673
4674 switch_mutex_lock(verto_globals.mutex);
4675 for(p = verto_globals.profile_head; p; p = p->next) {
4676 if (p == profile) {
4677 if (last) {
4678 last->next = p->next;
4679 } else {
4680 verto_globals.profile_head = p->next;
4681 }
4682 verto_globals.profile_count--;
4683 break;
4684 }
4685
4686 last = p;
4687 }
4688 switch_mutex_unlock(verto_globals.mutex);
4689 }
4690
add_profile(verto_profile_t * profile)4691 static switch_status_t add_profile(verto_profile_t *profile)
4692 {
4693 switch_status_t status = SWITCH_STATUS_FALSE;
4694
4695 switch_mutex_lock(verto_globals.mutex);
4696
4697 if (!profile_exists(profile->name)) {
4698 status = SWITCH_STATUS_SUCCESS;
4699 }
4700
4701 if (status == SWITCH_STATUS_SUCCESS) {
4702 profile->next = verto_globals.profile_head;
4703 verto_globals.profile_head = profile;
4704 verto_globals.profile_count++;
4705 }
4706
4707 switch_mutex_unlock(verto_globals.mutex);
4708
4709 return status;
4710 }
4711
parse_config(const char * cf)4712 static switch_status_t parse_config(const char *cf)
4713 {
4714
4715 switch_xml_t cfg, xml, settings, param, xprofile, xprofiles;
4716 switch_xml_t xvhosts, xvhost, rewrites, rule;
4717 switch_status_t status = SWITCH_STATUS_SUCCESS;
4718
4719 if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
4720 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", cf);
4721 return SWITCH_STATUS_TERM;
4722 }
4723
4724 if ((xprofiles = switch_xml_child(cfg, "profiles"))) {
4725 for (xprofile = switch_xml_child(xprofiles, "profile"); xprofile; xprofile = xprofile->next) {
4726 verto_profile_t *profile;
4727 switch_memory_pool_t *pool;
4728 const char *name = switch_xml_attr(xprofile, "name");
4729
4730 if (zstr(name)) {
4731 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Required field name missing\n");
4732 continue;
4733 }
4734
4735 if (profile_exists(name)) {
4736 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Profile %s already exists\n", name);
4737 continue;
4738 }
4739
4740
4741 switch_core_new_memory_pool(&pool);
4742 profile = switch_core_alloc(pool, sizeof(*profile));
4743 profile->pool = pool;
4744 profile->name = switch_core_strdup(profile->pool, name);
4745 switch_mutex_init(&profile->mutex, SWITCH_MUTEX_NESTED, profile->pool);
4746 switch_thread_rwlock_create(&profile->rwlock, profile->pool);
4747 add_profile(profile);
4748
4749 profile->local_network = "localnet.auto";
4750
4751 profile->mcast_sub.sock = ws_sock_invalid;
4752 profile->mcast_pub.sock = ws_sock_invalid;
4753
4754
4755 for (param = switch_xml_child(xprofile, "param"); param; param = param->next) {
4756 char *var = NULL;
4757 char *val = NULL;
4758
4759 var = (char *) switch_xml_attr_soft(param, "name");
4760 val = (char *) switch_xml_attr_soft(param, "value");
4761
4762 if (!strcasecmp(var, "bind-local")) {
4763 const char *secure = switch_xml_attr_soft(param, "secure");
4764 if (profile->i < MAX_BIND) {
4765 parse_ip(profile->ip[profile->i].local_ip, sizeof(profile->ip[profile->i].local_ip), &profile->ip[profile->i].local_port, val);
4766 if (switch_true(secure)) {
4767 profile->ip[profile->i].secure = 1;
4768 }
4769 profile->i++;
4770 } else {
4771 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max Bindings Reached!\n");
4772 }
4773 } else if (!strcasecmp(var, "enable-text")) {
4774 profile->enable_text = 1;
4775 } else if (!strcasecmp(var, "secure-combined")) {
4776 set_string(profile->cert, val);
4777 set_string(profile->key, val);
4778 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Secure key and cert specified\n");
4779 } else if (!strcasecmp(var, "secure-cert")) {
4780 set_string(profile->cert, val);
4781 } else if (!strcasecmp(var, "secure-key")) {
4782 set_string(profile->key, val);
4783 } else if (!strcasecmp(var, "secure-chain")) {
4784 set_string(profile->chain, val);
4785 } else if (!strcasecmp(var, "inbound-codec-string") && !zstr(val)) {
4786 profile->inbound_codec_string = switch_core_strdup(profile->pool, val);
4787 } else if (!strcasecmp(var, "outbound-codec-string") && !zstr(val)) {
4788 profile->outbound_codec_string = switch_core_strdup(profile->pool, val);
4789 } else if (!strcasecmp(var, "auto-jitterbuffer-msec") && !zstr(val)) {
4790 profile->jb_msec = switch_core_strdup(profile->pool, val);
4791 } else if (!strcasecmp(var, "blind-reg") && !zstr(val)) {
4792 profile->blind_reg = switch_true(val);
4793 } else if (!strcasecmp(var, "userauth") && !zstr(val)) {
4794 profile->userauth = switch_core_strdup(profile->pool, val);
4795 } else if (!strcasecmp(var, "root-password") && !zstr(val)) {
4796 profile->root_passwd = switch_core_strdup(profile->pool, val);
4797 } else if (!strcasecmp(var, "context") && !zstr(val)) {
4798 profile->context = switch_core_strdup(profile->pool, val);
4799 } else if (!strcasecmp(var, "dialplan") && !zstr(val)) {
4800 profile->dialplan = switch_core_strdup(profile->pool, val);
4801 } else if (!strcasecmp(var, "mcast-ip") && val) {
4802 profile->mcast_ip = switch_core_strdup(profile->pool, val);
4803 } else if (!strcasecmp(var, "mcast-port") && val) {
4804 profile->mcast_port = (switch_port_t) atoi(val);
4805 } else if (!strcasecmp(var, "timer-name") && !zstr(var)) {
4806 profile->timer_name = switch_core_strdup(profile->pool, val);
4807 } else if (!strcasecmp(var, "force-register-domain") && !zstr(val)) {
4808 profile->register_domain = switch_core_strdup(profile->pool, val);
4809 } else if (!strcasecmp(var, "local-network") && !zstr(val)) {
4810 profile->local_network = switch_core_strdup(profile->pool, val);
4811 } else if (!strcasecmp(var, "apply-candidate-acl")) {
4812 if (profile->cand_acl_count < SWITCH_MAX_CAND_ACL) {
4813 profile->cand_acl[profile->cand_acl_count++] = switch_core_strdup(profile->pool, val);
4814 } else {
4815 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max acl records of %d reached\n", SWITCH_MAX_CAND_ACL);
4816 }
4817 } else if (!strcasecmp(var, "apply-connection-acl")) {
4818 if (profile->conn_acl_count < SWITCH_MAX_CAND_ACL) {
4819 profile->conn_acl[profile->conn_acl_count++] = switch_core_strdup(profile->pool, val);
4820 } else {
4821 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max acl records of %d reached\n", SWITCH_MAX_CAND_ACL);
4822 }
4823 } else if (!strcasecmp(var, "rtp-ip")) {
4824 if (zstr(val)) {
4825 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid RTP IP.\n");
4826 } else {
4827 if (strchr(val, ':')) {
4828 if (profile->rtpip_index6 < MAX_RTPIP -1) {
4829 profile->rtpip6[profile->rtpip_index6++] = switch_core_strdup(profile->pool, val);
4830 } else {
4831 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Too many RTP IP.\n");
4832 }
4833 } else {
4834 if (profile->rtpip_index < MAX_RTPIP -1) {
4835 profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, val);
4836 } else {
4837 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Too many RTP IP.\n");
4838 }
4839 }
4840 }
4841 } else if (!strcasecmp(var, "ext-rtp-ip")) {
4842 if (zstr(val)) {
4843 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid External RTP IP.\n");
4844 } else {
4845 switch_stun_ip_lookup(&profile->extrtpip, val, profile->pool);
4846 }
4847 } else if (!strcasecmp(var, "debug")) {
4848 if (val) {
4849 profile->debug = atoi(val);
4850 }
4851 }
4852 }
4853
4854 if (zstr(profile->outbound_codec_string)) {
4855 profile->outbound_codec_string = "opus,vp8";
4856 }
4857
4858 if (zstr(profile->inbound_codec_string)) {
4859 profile->inbound_codec_string = profile->outbound_codec_string;
4860 }
4861
4862 if (zstr(profile->jb_msec)) {
4863 profile->jb_msec = "1p:50p";
4864 }
4865
4866 if (zstr(profile->timer_name)) {
4867 profile->timer_name = "soft";
4868 }
4869
4870 if (zstr(profile->dialplan)) {
4871 profile->dialplan = "XML";
4872 }
4873
4874 if (zstr(profile->context)) {
4875 profile->context = "default";
4876 }
4877
4878 if (zstr(profile->ip[0].local_ip) ) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s: local_ip bad\n", profile->name);
4879 if (profile->ip[0].local_port <= 0 ) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s: local_port bad\n", profile->name);
4880
4881 if (zstr(profile->ip[0].local_ip) || profile->ip[0].local_port <= 0) {
4882 del_profile(profile);
4883 switch_core_destroy_memory_pool(&pool);
4884 } else {
4885 int i;
4886
4887 for (i = 0; i < profile->i; i++) {
4888 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
4889 strchr(profile->ip[i].local_ip, ':') ? "%s Bound to [%s]:%d\n" : "%s Bound to %s:%d\n",
4890 profile->name, profile->ip[i].local_ip, profile->ip[i].local_port);
4891 }
4892 }
4893
4894 /* parse vhosts */
4895 /* WARNNING: Experimental feature, DO NOT use until we remove this warnning!! */
4896 if ((xvhosts = switch_xml_child(xprofile, "vhosts"))) {
4897 verto_vhost_t *vhost_tail = NULL;
4898
4899 for (xvhost = switch_xml_child(xvhosts, "vhost"); xvhost; xvhost = xvhost->next) {
4900 verto_vhost_t *vhost;
4901 const char *domain = switch_xml_attr(xvhost, "domain");
4902
4903 if (zstr(domain)) {
4904 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Required field domain missing\n");
4905 continue;
4906 }
4907
4908 vhost = switch_core_alloc(profile->pool, sizeof(*vhost));
4909 memset(vhost, 0, sizeof(*vhost));
4910 vhost->pool = profile->pool;
4911 vhost->domain = switch_core_strdup(profile->pool, domain);
4912
4913 if (!vhost_tail) {
4914 profile->vhosts = vhost;
4915 } else {
4916 vhost_tail->next = vhost;
4917 }
4918
4919 vhost_tail = vhost;
4920
4921 for (param = switch_xml_child(xvhost, "param"); param; param = param->next) {
4922 char *var = NULL;
4923 char *val = NULL;
4924
4925 var = (char *) switch_xml_attr_soft(param, "name");
4926 val = (char *) switch_xml_attr_soft(param, "value");
4927
4928 if (!strcasecmp(var, "alias")) {
4929 vhost->alias = switch_core_strdup(vhost->pool, val);
4930 } else if (!strcasecmp(var, "root")) {
4931 vhost->root = switch_core_strdup(vhost->pool, val);
4932 } else if (!strcasecmp(var, "script-root")) {
4933 vhost->script_root = switch_core_strdup(vhost->pool, val);
4934 } else if (!strcasecmp(var, "index")) {
4935 vhost->index = switch_core_strdup(vhost->pool, val);
4936 } else if (!strcasecmp(var, "auth-realm")) {
4937 vhost->auth_realm = switch_core_strdup(vhost->pool, val);
4938 } else if (!strcasecmp(var, "auth-user")) {
4939 vhost->auth_user = switch_core_strdup(vhost->pool, val);
4940 } else if (!strcasecmp(var, "auth-pass")) {
4941 vhost->auth_pass = switch_core_strdup(vhost->pool, val);
4942 }
4943 }
4944
4945 if (zstr(vhost->root)) {
4946 vhost->root = SWITCH_GLOBAL_dirs.htdocs_dir;
4947 }
4948
4949 if (zstr(vhost->script_root)) {
4950 vhost->script_root = SWITCH_GLOBAL_dirs.script_dir;
4951 }
4952
4953 if (zstr(vhost->index)) {
4954 vhost->index = "index.html";
4955 }
4956
4957 if ((rewrites = switch_xml_child(xvhost, "rewrites"))) {
4958 if (switch_event_create(&vhost->rewrites, SWITCH_EVENT_CLONE) == SWITCH_STATUS_SUCCESS) {
4959 for (rule = switch_xml_child(rewrites, "rule"); rule; rule = rule->next) {
4960 char *expr = NULL;
4961 char *val = NULL;
4962
4963 expr = (char *) switch_xml_attr_soft(rule, "expression");
4964 val = (char *) switch_xml_attr_soft(rule, "value");
4965
4966 if (zstr(expr)) continue;
4967
4968 switch_event_add_header_string(vhost->rewrites, SWITCH_STACK_BOTTOM, expr, val);
4969 }
4970 }
4971 } // rewrites
4972 } // xvhost
4973 } // xvhosts
4974 } // xprofile
4975 } // xprofiles
4976
4977 if ((settings = switch_xml_child(cfg, "settings"))) {
4978 for (param = switch_xml_child(settings, "param"); param; param = param->next) {
4979 char *var = NULL;
4980 char *val = NULL;
4981
4982 var = (char *) switch_xml_attr_soft(param, "name");
4983 val = (char *) switch_xml_attr_soft(param, "value");
4984
4985
4986 if (!strcasecmp(var, "debug")) {
4987 if (val) {
4988 verto_globals.debug = atoi(val);
4989 }
4990 } else if (!strcasecmp(var, "enable-presence") && val) {
4991 verto_globals.enable_presence = switch_true(val);
4992 } else if (!strcasecmp(var, "enable-fs-events") && val) {
4993 verto_globals.enable_fs_events = switch_true(val);
4994 } else if (!strcasecmp(var, "detach-timeout-sec") && val) {
4995 int tmp = atoi(val);
4996 if (tmp > 0) {
4997 verto_globals.detach_timeout = tmp;
4998 }
4999 }
5000 }
5001 }
5002
5003 switch_xml_free(xml);
5004
5005 return status;
5006 }
5007
init(void)5008 static int init(void)
5009 {
5010 verto_profile_t *p;
5011
5012 parse_config("verto.conf");
5013
5014 switch_mutex_lock(verto_globals.mutex);
5015 for(p = verto_globals.profile_head; p; p = p->next) {
5016 verto_init_ssl(p);
5017 }
5018 switch_mutex_unlock(verto_globals.mutex);
5019
5020 verto_globals.running = 1;
5021
5022 return 0;
5023 }
5024
5025
5026 #if 0
5027 static void print_status(verto_profile_t *profile, switch_stream_handle_t *stream)
5028 {
5029 jsock_t *p;
5030
5031 stream->write_function(stream, "REMOTE\t\t\tLOCAL\n");
5032
5033 for(p = profile->jsock_head; p; p = p->next) {
5034 if (p->ptype & PTYPE_CLIENT) {
5035 int i;
5036
5037 for (i = 0; i < profile->i; i++) {
5038 if (profile->server_socket[i] == p->local_sock) {
5039 stream->write_function(stream, "%s\t%s:%d\n", p->name, profile->ip[i].local_ip, profile->ip[i].local_port);
5040 }
5041 }
5042 }
5043 }
5044 }
5045 #endif
5046 typedef switch_status_t (*verto_command_t) (char **argv, int argc, switch_stream_handle_t *stream);
cmd_status(char ** argv,int argc,switch_stream_handle_t * stream)5047 static switch_status_t cmd_status(char **argv, int argc, switch_stream_handle_t *stream)
5048 {
5049 verto_profile_t *profile = NULL;
5050 jsock_t *jsock;
5051 verto_vhost_t *vhost;
5052 int cp = 0;
5053 int cc = 0;
5054 const char *line = "=================================================================================================";
5055 int i;
5056
5057 stream->write_function(stream, "%25s\t%s\t %40s\t%s\n", "Name", " Type", "Data", "State");
5058 stream->write_function(stream, "%s\n", line);
5059
5060 switch_mutex_lock(verto_globals.mutex);
5061 for(profile = verto_globals.profile_head; profile; profile = profile->next) {
5062 for (i = 0; i < profile->i; i++) {
5063 char *tmpurl = switch_mprintf(strchr(profile->ip[i].local_ip, ':') ? "%s:[%s]:%d" : "%s:%s:%d",
5064 (profile->ip[i].secure == 1) ? "wss" : "ws", profile->ip[i].local_ip, profile->ip[i].local_port);
5065 stream->write_function(stream, "%25s\t%s\t %40s\t%s\n", profile->name, "profile", tmpurl, (profile->server_socket[i] != ws_sock_invalid) ? "RUNNING" : "DOWN");
5066 switch_safe_free(tmpurl);
5067 }
5068 cp++;
5069
5070 switch_mutex_lock(profile->mutex);
5071 for (vhost = profile->vhosts; vhost; vhost = vhost->next) {
5072 char *tmpname = switch_mprintf("%s::%s", profile->name, vhost->domain);
5073 stream->write_function(stream, "%25s\t%s\t %40s\t%s (%s)\n", tmpname, "vhost", vhost->root, vhost->auth_user ? "AUTH" : "NOAUTH", vhost->auth_user ? vhost->auth_user : "");
5074 switch_safe_free(tmpname);
5075 }
5076
5077 for (jsock = profile->jsock_head; jsock; jsock = jsock->next) {
5078 char *tmpname = switch_mprintf("%s::%s@%s", profile->name, jsock->id, jsock->domain);
5079 stream->write_function(stream, "%25s\t%s\t %40s\t%s (%s)\n", tmpname, "client", jsock->name, (!zstr(jsock->uid)) ? "CONN_REG" : "CONN_NO_REG", (jsock->ptype & PTYPE_CLIENT_SSL) ? "WSS": "WS");
5080 cc++;
5081 switch_safe_free(tmpname);
5082 }
5083 switch_mutex_unlock(profile->mutex);
5084 }
5085 switch_mutex_unlock(verto_globals.mutex);
5086
5087 stream->write_function(stream, "%s\n", line);
5088 stream->write_function(stream, "%d profile%s , %d client%s\n", cp, cp == 1 ? "" : "s", cc, cc == 1 ? "" : "s");
5089
5090 return SWITCH_STATUS_SUCCESS;
5091 }
5092
cmd_xml_status(char ** argv,int argc,switch_stream_handle_t * stream)5093 static switch_status_t cmd_xml_status(char **argv, int argc, switch_stream_handle_t *stream)
5094 {
5095 verto_profile_t *profile = NULL;
5096 jsock_t *jsock;
5097 int cp = 0;
5098 int cc = 0;
5099 const char *header = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>";
5100 int i;
5101
5102 stream->write_function(stream, "%s\n", header);
5103 stream->write_function(stream, "<profiles>\n");
5104 switch_mutex_lock(verto_globals.mutex);
5105 for(profile = verto_globals.profile_head; profile; profile = profile->next) {
5106 for (i = 0; i < profile->i; i++) {
5107 char *tmpurl = switch_mprintf(strchr(profile->ip[i].local_ip, ':') ? "%s:[%s]:%d" : "%s:%s:%d",
5108 (profile->ip[i].secure == 1) ? "wss" : "ws", profile->ip[i].local_ip, profile->ip[i].local_port);
5109 stream->write_function(stream, "<profile>\n<name>%s</name>\n<type>%s</type>\n<data>%s</data>\n<state>%s</state>\n</profile>\n", profile->name, "profile", tmpurl, (profile->running) ? "RUNNING" : "DOWN");
5110 switch_safe_free(tmpurl);
5111 }
5112 cp++;
5113
5114 switch_mutex_lock(profile->mutex);
5115 for(jsock = profile->jsock_head; jsock; jsock = jsock->next) {
5116 char *tmpname = switch_mprintf("%s@%s", jsock->id, jsock->domain);
5117 stream->write_function(stream, "<client>\n<profile>%s</profile>\n<name>%s</name>\n<type>%s</type>\n<data>%s</data>\n<state>%s (%s)</state>\n</client>\n", profile->name, tmpname, "client", jsock->name,
5118 (!zstr(jsock->uid)) ? "CONN_REG" : "CONN_NO_REG", (jsock->ptype & PTYPE_CLIENT_SSL) ? "WSS": "WS");
5119 cc++;
5120 switch_safe_free(tmpname);
5121 }
5122 switch_mutex_unlock(profile->mutex);
5123 }
5124 switch_mutex_unlock(verto_globals.mutex);
5125 stream->write_function(stream, "</profiles>\n");
5126 return SWITCH_STATUS_SUCCESS;
5127 }
5128
SWITCH_STANDARD_API(verto_function)5129 SWITCH_STANDARD_API(verto_function)
5130 {
5131 char *argv[1024] = { 0 };
5132 int argc = 0;
5133 char *mycmd = NULL;
5134 switch_status_t status = SWITCH_STATUS_SUCCESS;
5135 verto_command_t func = NULL;
5136 int lead = 1;
5137 static const char usage_string[] = "USAGE:\n"
5138 "--------------------------------------------------------------------------------\n"
5139 "verto [status|xmlstatus]\n"
5140 "verto help\n"
5141 "--------------------------------------------------------------------------------\n";
5142
5143 if (zstr(cmd)) {
5144 stream->write_function(stream, "%s", usage_string);
5145 goto done;
5146 }
5147
5148 if (!(mycmd = strdup(cmd))) {
5149 status = SWITCH_STATUS_MEMERR;
5150 goto done;
5151 }
5152
5153 if (!(argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) || !argv[0]) {
5154 stream->write_function(stream, "%s", usage_string);
5155 goto done;
5156 }
5157
5158 if (!strcasecmp(argv[0], "help")) {
5159 stream->write_function(stream, "%s", usage_string);
5160 goto done;
5161 } else if (!strcasecmp(argv[0], "status")) {
5162 func = cmd_status;
5163 } else if (!strcasecmp(argv[0], "xmlstatus")) {
5164 func = cmd_xml_status;
5165 }
5166
5167 if (func) {
5168 status = func(&argv[lead], argc - lead, stream);
5169 } else {
5170 stream->write_function(stream, "Unknown Command [%s]\n", argv[0]);
5171 }
5172
5173 done:
5174 switch_safe_free(mycmd);
5175 return status;
5176
5177 }
5178
5179
5180
profile_thread(switch_thread_t * thread,void * obj)5181 static void *SWITCH_THREAD_FUNC profile_thread(switch_thread_t *thread, void *obj)
5182 {
5183 verto_profile_t *profile = (verto_profile_t *) obj;
5184 int sanity = 50;
5185
5186 switch_mutex_lock(verto_globals.mutex);
5187 verto_globals.profile_threads++;
5188 switch_mutex_unlock(verto_globals.mutex);
5189
5190 profile->in_thread = 1;
5191 profile->running = 1;
5192
5193
5194 runtime(profile);
5195 profile->running = 0;
5196
5197 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "profile %s shutdown, Waiting for %d threads\n", profile->name, profile->jsock_count);
5198
5199 while(--sanity > 0 && profile->jsock_count > 0) {
5200 switch_yield(100000);
5201 }
5202
5203 verto_deinit_ssl(profile);
5204
5205 del_profile(profile);
5206
5207 switch_thread_rwlock_wrlock(profile->rwlock);
5208 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Thread ending\n", profile->name);
5209 switch_thread_rwlock_unlock(profile->rwlock);
5210 profile->in_thread = 0;
5211
5212 switch_mutex_lock(verto_globals.mutex);
5213 verto_globals.profile_threads--;
5214 switch_mutex_unlock(verto_globals.mutex);
5215
5216 return NULL;
5217
5218 }
5219
run_profile_thread(verto_profile_t * profile)5220 static void run_profile_thread(verto_profile_t *profile) {
5221 switch_thread_data_t *td;
5222
5223 td = switch_core_alloc(profile->pool, sizeof(*td));
5224
5225 td->alloc = 0;
5226 td->func = profile_thread;
5227 td->obj = profile;
5228 td->pool = profile->pool;
5229
5230 switch_thread_pool_launch_thread(&td);
5231 }
5232
run_profiles(void)5233 static void run_profiles(void)
5234 {
5235 verto_profile_t *p;
5236
5237 switch_mutex_lock(verto_globals.mutex);
5238 for(p = verto_globals.profile_head; p; p = p->next) {
5239 if (!p->in_thread) {
5240 run_profile_thread(p);
5241 }
5242 }
5243 switch_mutex_unlock(verto_globals.mutex);
5244
5245 }
5246
5247
5248 //// ENDPOINT
5249
5250
5251 static switch_call_cause_t verto_outgoing_channel(switch_core_session_t *session,
5252 switch_event_t *var_event,
5253 switch_caller_profile_t *outbound_profile,
5254 switch_core_session_t **new_session,
5255 switch_memory_pool_t **pool,
5256 switch_originate_flag_t flags,
5257 switch_call_cause_t *cancel_cause);
5258 switch_io_routines_t verto_io_routines = {
5259 /*.outgoing_channel */ verto_outgoing_channel
5260 };
5261
5262
5263 switch_io_routines_t verto_io_override = {
5264 /*.outgoing_channel */ NULL,
5265 /*.read_frame */ NULL,
5266 /*.write_frame */ NULL,
5267 /*.kill_channel */ NULL,
5268 /*.send_dtmf */ NULL,
5269 /*.receive_message */ NULL,
5270 /*.receive_event */ NULL,
5271 /*.state_change */ NULL,
5272 /*.read_video_frame */ NULL,
5273 /*.write_video_frame */ NULL,
5274 /*.read_text_frame */ verto_read_text_frame,
5275 /*.write_text_frame */ verto_write_text_frame,
5276 /*.state_run*/ NULL,
5277 /*.get_jb*/ NULL
5278 };
5279
5280
verto_read_text_frame(switch_core_session_t * session,switch_frame_t ** frame,switch_io_flag_t flags,int stream_id)5281 static switch_status_t verto_read_text_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
5282 {
5283 verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY);
5284 switch_status_t status;
5285
5286 if (!tech_pvt->text_read_buffer) {
5287 return SWITCH_STATUS_FALSE;
5288 }
5289
5290 switch_mutex_lock(tech_pvt->text_cond_mutex);
5291
5292 switch_thread_cond_timedwait(tech_pvt->text_cond, tech_pvt->text_cond_mutex, 100000);
5293 switch_mutex_unlock(tech_pvt->text_cond_mutex);
5294
5295 *frame = &tech_pvt->text_read_frame;
5296 (*frame)->flags = 0;
5297
5298 switch_mutex_lock(tech_pvt->text_read_mutex);
5299 if (switch_buffer_inuse(tech_pvt->text_read_buffer)) {
5300 status = SWITCH_STATUS_SUCCESS;
5301 tech_pvt->text_read_frame.datalen = switch_buffer_read(tech_pvt->text_read_buffer, tech_pvt->text_read_frame.data, 100);
5302 } else {
5303 (*frame)->flags |= SFF_CNG;
5304 tech_pvt->text_read_frame.datalen = 2;
5305 status = SWITCH_STATUS_BREAK;
5306 }
5307 switch_mutex_unlock(tech_pvt->text_read_mutex);
5308
5309
5310
5311 return status;
5312 }
5313
verto_write_text_frame(switch_core_session_t * session,switch_frame_t * frame,switch_io_flag_t flags,int stream_id)5314 static switch_status_t verto_write_text_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
5315 {
5316 verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY);
5317
5318 switch_mutex_lock(tech_pvt->text_write_mutex);
5319
5320
5321 if (frame) {
5322 switch_buffer_write(tech_pvt->text_write_buffer, frame->data, frame->datalen);
5323 }
5324
5325 if (switch_buffer_inuse(tech_pvt->text_write_buffer)) {
5326 uint32_t datalen;
5327 switch_byte_t data[SWITCH_RTP_MAX_BUF_LEN] = "";
5328
5329 if ((datalen = switch_buffer_read(tech_pvt->text_write_buffer, data, 100))) {
5330 cJSON *obj = NULL, *txt = NULL, *params = NULL;
5331 jsock_t *jsock;
5332
5333 obj = jrpc_new_req("verto.info", tech_pvt->call_id, ¶ms);
5334 txt = json_add_child_obj(params, "txt", NULL);
5335 cJSON_AddItemToObject(txt, "chars", cJSON_CreateString((char *)data));
5336
5337 if ((jsock = get_jsock(tech_pvt->jsock_uuid))) {
5338 jsock_queue_event(jsock, &obj, SWITCH_TRUE);
5339 switch_thread_rwlock_unlock(jsock->rwlock);
5340 } else {
5341 cJSON_Delete(obj);
5342 }
5343 }
5344 }
5345
5346
5347 switch_mutex_unlock(tech_pvt->text_write_mutex);
5348
5349 return SWITCH_STATUS_SUCCESS;
5350 }
5351
5352
5353
set_text_funcs(switch_core_session_t * session)5354 static void set_text_funcs(switch_core_session_t *session)
5355 {
5356 verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY);
5357
5358 if (!tech_pvt || tech_pvt->text_read_buffer) {
5359 return;
5360 }
5361
5362 if ((switch_core_session_override_io_routines(session, &verto_io_override) == SWITCH_STATUS_SUCCESS)) {
5363 tech_pvt->text_read_frame.data = tech_pvt->text_read_frame_data;
5364
5365 switch_mutex_init(&tech_pvt->text_read_mutex, SWITCH_MUTEX_NESTED, tech_pvt->pool);
5366 switch_mutex_init(&tech_pvt->text_write_mutex, SWITCH_MUTEX_NESTED, tech_pvt->pool);
5367 switch_mutex_init(&tech_pvt->text_cond_mutex, SWITCH_MUTEX_NESTED, tech_pvt->pool);
5368 switch_thread_cond_create(&tech_pvt->text_cond, tech_pvt->pool);
5369
5370 switch_buffer_create_dynamic(&tech_pvt->text_read_buffer, 512, 1024, 0);
5371 switch_buffer_create_dynamic(&tech_pvt->text_write_buffer, 512, 1024, 0);
5372
5373 switch_channel_set_flag(switch_core_session_get_channel(session), CF_HAS_TEXT);
5374 switch_core_session_start_text_thread(session);
5375 }
5376 }
5377
5378
verto_get_dial_string(const char * uid,switch_stream_handle_t * rstream)5379 static char *verto_get_dial_string(const char *uid, switch_stream_handle_t *rstream)
5380 {
5381 jsock_t *jsock;
5382 verto_profile_t *profile;
5383 switch_stream_handle_t *use_stream = NULL, stream = { 0 };
5384 char *gen_uid = NULL;
5385 int hits = 0;
5386
5387 if (!strchr(uid, '@')) {
5388 gen_uid = switch_mprintf("%s@%s", uid, switch_core_get_domain(SWITCH_FALSE));
5389 uid = gen_uid;
5390 }
5391
5392 if (rstream) {
5393 use_stream = rstream;
5394 } else {
5395 SWITCH_STANDARD_STREAM(stream);
5396 use_stream = &stream;
5397 }
5398
5399 switch_mutex_lock(verto_globals.mutex);
5400 for(profile = verto_globals.profile_head; profile; profile = profile->next) {
5401
5402 switch_mutex_lock(profile->mutex);
5403
5404 for(jsock = profile->jsock_head; jsock; jsock = jsock->next) {
5405 if (jsock->ready && !zstr(jsock->uid) && !zstr(uid) && !strcmp(uid, jsock->uid)) {
5406 use_stream->write_function(use_stream, "%s/u:%s,", EP_NAME, jsock->uuid_str);
5407 hits++;
5408 }
5409 }
5410
5411 switch_mutex_unlock(profile->mutex);
5412 }
5413 switch_mutex_unlock(verto_globals.mutex);
5414
5415 switch_safe_free(gen_uid);
5416
5417 if (!hits) {
5418 use_stream->write_function(use_stream, "error/user_not_registered");
5419 }
5420
5421 if (use_stream->data) {
5422 char *p = use_stream->data;
5423 if (end_of(p) == ',') {
5424 end_of(p) = '\0';
5425 }
5426 }
5427
5428 return use_stream->data;
5429 }
5430
SWITCH_STANDARD_API(verto_contact_function)5431 SWITCH_STANDARD_API(verto_contact_function)
5432 {
5433 char *uid = (char *) cmd;
5434
5435 if (!zstr(uid)) {
5436 verto_get_dial_string(uid, stream);
5437 }
5438
5439 return SWITCH_STATUS_SUCCESS;
5440 }
5441
5442
verto_outgoing_channel(switch_core_session_t * session,switch_event_t * var_event,switch_caller_profile_t * outbound_profile,switch_core_session_t ** new_session,switch_memory_pool_t ** pool,switch_originate_flag_t flags,switch_call_cause_t * cancel_cause)5443 static switch_call_cause_t verto_outgoing_channel(switch_core_session_t *session,
5444 switch_event_t *var_event,
5445 switch_caller_profile_t *outbound_profile,
5446 switch_core_session_t **new_session,
5447 switch_memory_pool_t **pool,
5448 switch_originate_flag_t flags,
5449 switch_call_cause_t *cancel_cause)
5450 {
5451 switch_call_cause_t cause = SWITCH_CAUSE_CHANNEL_UNACCEPTABLE;
5452 char *dest = NULL;
5453
5454 PROTECT_INTERFACE(verto_endpoint_interface);
5455
5456 if (!zstr(outbound_profile->destination_number)) {
5457 dest = strdup(outbound_profile->destination_number);
5458 }
5459
5460 if (zstr(dest)) {
5461 goto end;
5462 }
5463
5464 if (!switch_stristr("u:", dest)) {
5465 char *dial_str = verto_get_dial_string(dest, NULL);
5466
5467 switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "verto_orig_dest", dest);
5468 if (zstr(switch_event_get_header(var_event, "origination_callee_id_number"))) {
5469 char *p;
5470 char *trimmed_dest = strdup(dest);
5471 switch_assert(trimmed_dest);
5472 p = strchr(trimmed_dest, '@');
5473 if (p) *p = '\0';
5474 switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "origination_callee_id_number", trimmed_dest);
5475 free(trimmed_dest);
5476 }
5477
5478 cause = SWITCH_CAUSE_USER_NOT_REGISTERED;
5479
5480 if (dial_str) {
5481 switch_originate_flag_t myflags = SOF_NONE;
5482
5483 if ((flags & SOF_NO_LIMITS)) {
5484 myflags |= SOF_NO_LIMITS;
5485 }
5486
5487 if ((flags & SOF_FORKED_DIAL)) {
5488 myflags |= SOF_NOBLOCK;
5489 }
5490
5491 if (switch_ivr_originate(session, new_session, &cause, dial_str, 0, NULL,
5492 NULL, NULL, outbound_profile, var_event, myflags, cancel_cause, NULL) == SWITCH_STATUS_SUCCESS) {
5493 switch_core_session_rwunlock(*new_session);
5494 }
5495
5496 free(dial_str);
5497 }
5498
5499 return cause;
5500 } else {
5501 const char *dialed_user = switch_event_get_header(var_event, "dialed_user");
5502 const char *dialed_domain = switch_event_get_header(var_event, "dialed_domain");
5503
5504 if (dialed_user) {
5505 if (dialed_domain) {
5506 switch_event_add_header(var_event, SWITCH_STACK_BOTTOM, "verto_orig_dest", "%s@%s", dialed_user, dialed_domain);
5507 } else {
5508 switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "verto_orig_dest", dialed_user);
5509 }
5510 if (zstr(switch_event_get_header(var_event, "origination_callee_id_number"))) {
5511 switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "origination_callee_id_number", dialed_user);
5512 outbound_profile->callee_id_number = switch_sanitize_number(switch_core_strdup(outbound_profile->pool, dialed_user));
5513 }
5514 }
5515 }
5516
5517 if ((cause = switch_core_session_outgoing_channel(session, var_event, "rtc",
5518 outbound_profile, new_session, NULL, SOF_NONE, cancel_cause)) == SWITCH_CAUSE_SUCCESS) {
5519 switch_channel_t *channel = switch_core_session_get_channel(*new_session);
5520 char *jsock_uuid_str = outbound_profile->destination_number + 2;
5521 switch_caller_profile_t *caller_profile;
5522 verto_pvt_t *tech_pvt = NULL;
5523 char name[512];
5524
5525 tech_pvt = switch_core_session_alloc(*new_session, sizeof(*tech_pvt));
5526 tech_pvt->pool = switch_core_session_get_pool(*new_session);
5527 tech_pvt->session = *new_session;
5528 tech_pvt->channel = channel;
5529 tech_pvt->jsock_uuid = switch_core_session_strdup(*new_session, jsock_uuid_str);
5530
5531 switch_core_session_set_private_class(*new_session, tech_pvt, SWITCH_PVT_SECONDARY);
5532
5533 if (session) {
5534 switch_channel_t *ochannel = switch_core_session_get_channel(session);
5535
5536 if (switch_true(switch_channel_get_variable(ochannel, SWITCH_BYPASS_MEDIA_VARIABLE))) {
5537 switch_channel_set_flag(channel, CF_PROXY_MODE);
5538 switch_channel_set_flag(ochannel, CF_PROXY_MODE);
5539 switch_channel_set_cap(channel, CC_BYPASS_MEDIA);
5540 }
5541 }
5542
5543 tech_pvt->call_id = switch_core_session_strdup(*new_session, switch_core_session_get_uuid(*new_session));
5544 if ((tech_pvt->smh = switch_core_session_get_media_handle(*new_session))) {
5545 tech_pvt->mparams = switch_core_media_get_mparams(tech_pvt->smh);
5546 }
5547
5548 switch_snprintf(name, sizeof(name), "verto.rtc/%s", tech_pvt->jsock_uuid);
5549 switch_channel_set_name(channel, name);
5550 switch_channel_set_variable(channel, "jsock_uuid_str", tech_pvt->jsock_uuid);
5551 switch_channel_set_variable(channel, "event_channel_cookie", tech_pvt->jsock_uuid);
5552
5553
5554 if ((caller_profile = switch_caller_profile_dup(switch_core_session_get_pool(*new_session), outbound_profile))) {
5555 switch_channel_set_caller_profile(channel, caller_profile);
5556 }
5557
5558 switch_channel_add_state_handler(channel, &verto_state_handlers);
5559 switch_core_event_hook_add_receive_message(*new_session, messagehook);
5560 switch_channel_set_state(channel, CS_INIT);
5561 //track_pvt(tech_pvt);
5562 }
5563
5564 end:
5565
5566 if (cause != SWITCH_CAUSE_SUCCESS) {
5567 UNPROTECT_INTERFACE(verto_endpoint_interface);
5568 }
5569
5570 switch_safe_free(dest);
5571
5572 return cause;
5573 }
5574
verto_broadcast(const char * event_channel,cJSON * json,const char * key,switch_event_channel_id_t id,void * user_data)5575 void verto_broadcast(const char *event_channel, cJSON *json, const char *key, switch_event_channel_id_t id, void *user_data)
5576 {
5577 if (verto_globals.debug > 9) {
5578 char *json_text;
5579 if ((json_text = cJSON_Print(json))) {
5580 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "EVENT BROADCAST %s %s\n", event_channel, json_text);
5581 free(json_text);
5582 }
5583 }
5584
5585 jsock_send_event(json);
5586 }
5587
5588
verto_send_chat(const char * uid,const char * call_id,cJSON * msg)5589 static int verto_send_chat(const char *uid, const char *call_id, cJSON *msg)
5590 {
5591 jsock_t *jsock;
5592 verto_profile_t *profile;
5593 int hits = 0;
5594 int done = 0;
5595
5596 if (!strchr(uid, '@')) {
5597 return 0;
5598 }
5599
5600 if (call_id) {
5601 switch_core_session_t *session;
5602 if ((session = switch_core_session_locate(call_id))) {
5603 verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY);
5604
5605 if ((jsock = get_jsock(tech_pvt->jsock_uuid))) {
5606 jsock_queue_event(jsock, &msg, SWITCH_FALSE);
5607 //if (ws_write_json(jsock, &msg, SWITCH_FALSE) <= 0) {
5608 // switch_channel_hangup(switch_core_session_get_channel(session), SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
5609 //}
5610 switch_thread_rwlock_unlock(jsock->rwlock);
5611 done = 1;
5612 }
5613
5614 switch_core_session_rwunlock(session);
5615 }
5616 }
5617
5618 if (done) {
5619 return 1;
5620 }
5621
5622 switch_mutex_lock(verto_globals.mutex);
5623 for(profile = verto_globals.profile_head; profile; profile = profile->next) {
5624
5625 switch_mutex_lock(profile->mutex);
5626
5627 for(jsock = profile->jsock_head; jsock; jsock = jsock->next) {
5628 if (jsock->ready && !zstr(jsock->uid) && !strcmp(uid, jsock->uid)) {
5629 jsock_queue_event(jsock, &msg, SWITCH_FALSE);
5630 hits++;
5631 }
5632 }
5633
5634 switch_mutex_unlock(profile->mutex);
5635 }
5636 switch_mutex_unlock(verto_globals.mutex);
5637
5638 return hits;
5639 }
5640
chat_send(switch_event_t * message_event)5641 static switch_status_t chat_send(switch_event_t *message_event)
5642 {
5643 switch_status_t status = SWITCH_STATUS_SUCCESS;
5644 const char *to = switch_event_get_header(message_event, "to");
5645 const char *from = switch_event_get_header(message_event, "from");
5646 const char *body = switch_event_get_body(message_event);
5647 const char *call_id = switch_event_get_header(message_event, "call_id");
5648
5649 //DUMP_EVENT(message_event);
5650
5651
5652 if (!zstr(to) && !zstr(body) && !zstr(from)) {
5653 cJSON *obj = NULL, *msg = NULL, *params = NULL;
5654 switch_event_header_t *eh;
5655
5656 obj = jrpc_new_req("verto.info", call_id, ¶ms);
5657 msg = json_add_child_obj(params, "msg", NULL);
5658
5659 cJSON_AddItemToObject(msg, "from", cJSON_CreateString(from));
5660 cJSON_AddItemToObject(msg, "to", cJSON_CreateString(to));
5661 cJSON_AddItemToObject(msg, "body", cJSON_CreateString(body));
5662
5663 for (eh = message_event->headers; eh; eh = eh->next) {
5664 if (!strncasecmp(eh->name, "from_", 5) || !strncasecmp(eh->name, "to_", 3)) {
5665 cJSON_AddItemToObject(msg, eh->name, cJSON_CreateString(eh->value));
5666 }
5667 }
5668
5669 verto_send_chat(to, call_id, obj);
5670 cJSON_Delete(obj);
5671 } else {
5672 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "INVALID EVENT\n");
5673 DUMP_EVENT(message_event);
5674 status = SWITCH_STATUS_FALSE;
5675 }
5676
5677
5678 return status;
5679 }
5680
5681
5682
json_get_db_handle(void)5683 static switch_cache_db_handle_t *json_get_db_handle(void)
5684 {
5685
5686 switch_cache_db_handle_t *dbh = NULL;
5687 const char *dsn;
5688
5689
5690 if (!(dsn = switch_core_get_variable("json_db_handle"))) {
5691 dsn = "json";
5692 }
5693
5694
5695 if (switch_cache_db_get_db_handle_dsn(&dbh, dsn) != SWITCH_STATUS_SUCCESS) {
5696 dbh = NULL;
5697 }
5698
5699 return dbh;
5700 }
5701
5702
jcallback(void * pArg,int argc,char ** argv,char ** columnNames)5703 static int jcallback(void *pArg, int argc, char **argv, char **columnNames)
5704 {
5705 char **data = (char **) pArg;
5706
5707 if (argv[0] && !*data) {
5708 *data = strdup(argv[0]);
5709 }
5710
5711 return 0;
5712 }
5713
json_retrieve(const char * name,switch_mutex_t * mutex)5714 static cJSON *json_retrieve(const char *name, switch_mutex_t *mutex)
5715 {
5716 char *sql, *errmsg;
5717 switch_cache_db_handle_t *dbh;
5718 char *ascii = NULL;
5719 cJSON *json = NULL;
5720
5721 if (!check_name(name)) {
5722 return NULL;
5723 }
5724
5725 sql = switch_mprintf("select data from json_store where name='%q'", name);
5726
5727 dbh = json_get_db_handle();
5728
5729 if (mutex) switch_mutex_lock(mutex);
5730 switch_cache_db_execute_sql_callback(dbh, sql, jcallback, &ascii, &errmsg);
5731
5732 switch_cache_db_release_db_handle(&dbh);
5733
5734 if (errmsg) {
5735 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR: [%s] %s\n", sql, errmsg);
5736 free(errmsg);
5737 } else {
5738 if (ascii) {
5739 json = cJSON_Parse(ascii);
5740 }
5741 }
5742
5743 if (mutex) switch_mutex_unlock(mutex);
5744
5745
5746 switch_safe_free(ascii);
5747
5748 return json;
5749
5750 }
5751
json_commit(cJSON * json,const char * name,switch_mutex_t * mutex)5752 static switch_bool_t json_commit(cJSON *json, const char *name, switch_mutex_t *mutex)
5753 {
5754 char *ascii;
5755 char *sql;
5756 char del_sql[128] = "";
5757 switch_cache_db_handle_t *dbh;
5758 char *err;
5759
5760 if (!check_name(name)) {
5761 return SWITCH_FALSE;
5762 }
5763
5764 if (!(ascii = cJSON_PrintUnformatted(json))) {
5765 return SWITCH_FALSE;
5766 }
5767
5768
5769 sql = switch_mprintf("insert into json_store (name,data) values('%q','%q')", name, ascii);
5770 switch_snprintfv(del_sql, sizeof(del_sql), "delete from json_store where name='%q'", name);
5771
5772 dbh = json_get_db_handle();
5773
5774
5775 if (mutex) switch_mutex_lock(mutex);
5776 switch_cache_db_execute_sql(dbh, del_sql, &err);
5777
5778 if (err) {
5779 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "sql err [%s]\n", err);
5780 free(err);
5781 } else {
5782 switch_cache_db_execute_sql(dbh, sql, &err);
5783
5784 if (err) {
5785 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "sql err [%s]\n", err);
5786 free(err);
5787 }
5788 }
5789
5790 if (mutex) switch_mutex_unlock(mutex);
5791
5792 switch_safe_free(sql);
5793 switch_safe_free(ascii);
5794
5795 switch_cache_db_release_db_handle(&dbh);
5796
5797 return SWITCH_TRUE;
5798 }
5799
json_hanguphook(switch_core_session_t * session)5800 static switch_status_t json_hanguphook(switch_core_session_t *session)
5801 {
5802 switch_channel_t *channel = switch_core_session_get_channel(session);
5803 switch_channel_state_t state = switch_channel_get_state(channel);
5804 json_store_t *session_store = NULL;
5805 char *ascii = NULL;
5806
5807 if (state == CS_HANGUP) {
5808 if ((session_store = (json_store_t *) switch_channel_get_private(channel, "_json_store_"))) {
5809 if ((ascii = cJSON_PrintUnformatted(session_store->JSON_STORE))) {
5810 switch_channel_set_variable(channel, "json_store_data", ascii);
5811 free(ascii);
5812 }
5813 cJSON_Delete(session_store->JSON_STORE);
5814 session_store->JSON_STORE = NULL;
5815 switch_channel_set_private(channel, "_json_store_", NULL);
5816 }
5817 switch_core_event_hook_remove_state_change(session, json_hanguphook);
5818 }
5819
5820 return SWITCH_STATUS_SUCCESS;
5821 }
5822
SWITCH_STANDARD_JSON_API(json_store_function)5823 SWITCH_STANDARD_JSON_API(json_store_function)
5824 {
5825 cJSON *JSON_STORE = NULL, *reply = NULL, *data = cJSON_GetObjectItem(json, "data");
5826 switch_status_t status = SWITCH_STATUS_FALSE;
5827 const char *cmd_attr = cJSON_GetObjectCstr(data, "cmd");
5828 const char *uuid = cJSON_GetObjectCstr(data, "uuid");
5829 const char *error = NULL, *message = NULL;
5830 store_cmd_t cmd;
5831 const char *key = cJSON_GetObjectCstr(data, "key");
5832 const char *verbose = cJSON_GetObjectCstr(data, "verbose");
5833 const char *commit = cJSON_GetObjectCstr(data, "commit");
5834 const char *file = cJSON_GetObjectCstr(data, "file");
5835 const char *storename = cJSON_GetObjectCstr(data, "storeName");
5836 cJSON *obj, **use_store = NULL;
5837 switch_core_session_t *tsession = NULL;
5838 switch_channel_t *tchannel = NULL;
5839 json_store_t *session_store = NULL;
5840
5841 reply = cJSON_CreateObject();
5842
5843 if (uuid) {
5844 if ((tsession = switch_core_session_locate(uuid))) {
5845 tchannel = switch_core_session_get_channel(tsession);
5846 } else {
5847 error = "Invalid INPUT, Missing UUID";
5848 goto end;
5849 }
5850 } else {
5851 if (zstr(storename)) {
5852 storename = "global";
5853 }
5854 }
5855
5856
5857 if (zstr(cmd_attr)) {
5858 error = "INVALID INPUT, Command not supplied";
5859 goto end;
5860 }
5861
5862
5863 if (!strcasecmp(cmd_attr, "add")) {
5864 cmd = CMD_ADD;
5865 } else if (!strcasecmp(cmd_attr, "del")) {
5866 cmd = CMD_DEL;
5867 } else if (!strcasecmp(cmd_attr, "dump")) {
5868 cmd = CMD_DUMP;
5869 } else if (!strcasecmp(cmd_attr, "commit")) {
5870 cmd = CMD_COMMIT;
5871 } else if (!strcasecmp(cmd_attr, "retrieve")) {
5872 cmd = CMD_RETRIEVE;
5873 } else {
5874 error = "INVALID INPUT, Unknown Command";
5875 goto end;
5876 }
5877
5878
5879 if (cmd == CMD_ADD) {
5880 if (zstr(key)) {
5881 error = "INVALID INPUT, No key supplied";
5882 goto end;
5883 }
5884 }
5885
5886
5887 if (cmd == CMD_RETRIEVE || cmd == CMD_COMMIT) {
5888 if (zstr(file)) {
5889 error = "INVALID INPUT, No file specified";
5890 goto end;
5891 }
5892 }
5893
5894 switch_mutex_lock(json_GLOBALS.store_mutex);
5895 if (tsession) {
5896 if (!(session_store = (json_store_t *) switch_channel_get_private(tchannel, "_json_store_"))) {
5897 session_store = switch_core_session_alloc(tsession, sizeof(*session_store));
5898 switch_mutex_init(&session_store->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(tsession));
5899 session_store->JSON_STORE = cJSON_CreateObject();
5900 switch_channel_set_private(tchannel, "_json_store_", session_store);
5901 switch_core_event_hook_add_state_change(tsession, json_hanguphook);
5902 }
5903
5904 use_store = &session_store->JSON_STORE;
5905 switch_mutex_lock(session_store->mutex);
5906 switch_mutex_unlock(json_GLOBALS.store_mutex);
5907 } else {
5908 JSON_STORE = switch_core_hash_find(json_GLOBALS.store_hash, storename);
5909
5910 if (!JSON_STORE) {
5911 JSON_STORE = cJSON_CreateObject();
5912 switch_core_hash_insert(json_GLOBALS.store_hash, storename, JSON_STORE);
5913 }
5914 use_store = &JSON_STORE;
5915 }
5916
5917 switch(cmd) {
5918 case CMD_RETRIEVE:
5919 obj = json_retrieve(file, NULL);
5920
5921 if (!obj) {
5922 error = "CANNOT LOAD DATA";
5923
5924 if (session_store) {
5925 switch_mutex_unlock(session_store->mutex);
5926 } else {
5927 switch_mutex_unlock(json_GLOBALS.store_mutex);
5928 }
5929
5930 goto end;
5931 }
5932
5933 cJSON_Delete(*use_store);
5934 *use_store = obj;
5935 message = "Store Loaded";
5936
5937 break;
5938 case CMD_ADD:
5939
5940 if (!(obj = cJSON_GetObjectItem(data, key))) {
5941 error = "INVALID INPUT";
5942
5943 if (session_store) {
5944 switch_mutex_unlock(session_store->mutex);
5945 } else {
5946 switch_mutex_unlock(json_GLOBALS.store_mutex);
5947 }
5948
5949 goto end;
5950 }
5951
5952 cJSON_DeleteItemFromObject(*use_store, key);
5953 obj = cJSON_Duplicate(obj, 1);
5954 cJSON_AddItemToObject(*use_store, key, obj);
5955 message = "Item Added";
5956 break;
5957
5958 case CMD_DEL:
5959
5960 if (!key) {
5961 cJSON_Delete(*use_store);
5962 *use_store = cJSON_CreateObject();
5963 message = "Store Deleted";
5964 } else {
5965 cJSON_DeleteItemFromObject(*use_store, key);
5966 message = "Item Deleted";
5967 }
5968 break;
5969
5970 default:
5971 break;
5972 }
5973
5974
5975 if (switch_true(verbose) || cmd == CMD_DUMP) {
5976 cJSON *dump;
5977
5978 if (key) {
5979 dump = cJSON_GetObjectItem(*use_store, key);
5980 } else {
5981 dump = *use_store;
5982 }
5983
5984 if (dump) {
5985 dump = cJSON_Duplicate(dump, 1);
5986 cJSON_AddItemToObject(reply, "data", dump);
5987 message = "Data Dumped";
5988 } else {
5989 error = "Key not found";
5990 }
5991 }
5992
5993 if (session_store) {
5994 switch_mutex_unlock(session_store->mutex);
5995 } else {
5996 switch_mutex_unlock(json_GLOBALS.store_mutex);
5997 }
5998
5999 if (cmd == CMD_COMMIT || commit) {
6000 switch_bool_t ok;
6001
6002 if (commit && zstr(file)) {
6003 file = commit;
6004 }
6005
6006 if (session_store) {
6007 ok = json_commit(session_store->JSON_STORE, file, session_store->mutex);
6008 } else {
6009 ok = json_commit(JSON_STORE, file, json_GLOBALS.store_mutex);
6010 }
6011
6012 cJSON_AddItemToObject(reply, "commitStatus", cJSON_CreateString(ok ? "success" : "fail"));
6013 if (!message) {
6014 message = "Message Comitted";
6015 }
6016 status = SWITCH_STATUS_SUCCESS;
6017 }
6018
6019
6020 end:
6021
6022 if (!zstr(error)) {
6023 cJSON_AddItemToObject(reply, "errorMessage", cJSON_CreateString(error));
6024 }
6025
6026 if (!zstr(message)) {
6027 cJSON_AddItemToObject(reply, "message", cJSON_CreateString(message));
6028 status = SWITCH_STATUS_SUCCESS;
6029 }
6030
6031 *json_reply = reply;
6032
6033 if (tsession) {
6034 switch_core_session_rwunlock(tsession);
6035 }
6036
6037 return status;
6038 }
6039
6040 #define add_it(_name, _ename) if ((tmp = switch_event_get_header(event, _ename))) { cJSON_AddItemToObject(data, _name, cJSON_CreateString(tmp));}
6041
presence_event_handler(switch_event_t * event)6042 static void presence_event_handler(switch_event_t *event)
6043 {
6044 cJSON *msg = NULL, *data = NULL;
6045 const char *tmp;
6046 switch_event_header_t *hp;
6047 char *event_channel;
6048 const char *presence_id = switch_event_get_header(event, "channel-presence-id");
6049
6050 if (!verto_globals.running) {
6051 return;
6052 }
6053
6054 if (!verto_globals.enable_presence || zstr(presence_id)) {
6055 return;
6056 }
6057
6058 msg = cJSON_CreateObject();
6059 data = json_add_child_obj(msg, "data", NULL);
6060
6061 event_channel = switch_mprintf("presence.%s", presence_id);
6062
6063 cJSON_AddItemToObject(msg, "eventChannel", cJSON_CreateString(event_channel));
6064 add_it("channelCallState", "channel-call-state");
6065 add_it("originalChannelCallState", "original-channel-call-state");
6066 add_it("channelState", "channel-state");
6067
6068 add_it("callerUserName", "caller-username");
6069 add_it("callerIDName", "caller-caller-id-name");
6070 add_it("callerIDNumber", "caller-caller-id-number");
6071 add_it("calleeIDName", "caller-callee-id-name");
6072 add_it("calleeIDNumber", "caller-callee-id-number");
6073 add_it("channelUUID", "unique-id");
6074
6075 add_it("presenceCallDirection", "presence-call-direction");
6076 add_it("channelPresenceID", "channel-presence-id");
6077 add_it("channelPresenceData", "channel-presence-data");
6078
6079 for(hp = event->headers; hp; hp = hp->next) {
6080 if (!strncasecmp(hp->name, "PD-", 3)) {
6081 add_it(hp->name, hp->name);
6082 }
6083 }
6084
6085 switch_event_channel_broadcast(event_channel, &msg, __FILE__, NO_EVENT_CHANNEL_ID);
6086
6087 free(event_channel);
6088
6089 }
6090
event_handler(switch_event_t * event)6091 static void event_handler(switch_event_t *event)
6092 {
6093 cJSON *msg = NULL, *data = NULL;
6094 char *event_channel;
6095
6096 if (!verto_globals.enable_fs_events) {
6097 return;
6098 }
6099
6100 switch_event_serialize_json_obj(event, &data);
6101
6102 msg = cJSON_CreateObject();
6103
6104 if (event->event_id == SWITCH_EVENT_CUSTOM) {
6105 const char *subclass = switch_event_get_header(event, "Event-Subclass");
6106 event_channel = switch_mprintf("FSevent.%s::%s", switch_event_name(event->event_id), subclass);
6107 switch_tolower_max(event_channel + 8);
6108 } else {
6109 event_channel = switch_mprintf("FSevent.%s", switch_event_name(event->event_id));
6110 switch_tolower_max(event_channel + 8);
6111 }
6112
6113 cJSON_AddItemToObject(msg, "eventChannel", cJSON_CreateString(event_channel));
6114 cJSON_AddItemToObject(msg, "data", data);
6115
6116 /* comment broadcasting globally and change to only within the module cos FS events are heavy */
6117 //switch_event_channel_broadcast(event_channel, &msg, __FILE__, NO_EVENT_CHANNEL_ID);
6118 verto_broadcast(event_channel, msg, __FILE__, NO_EVENT_CHANNEL_ID, NULL);cJSON_Delete(msg);
6119
6120 free(event_channel);
6121
6122 }
6123
6124 /* Macro expands to: switch_status_t mod_verto_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
SWITCH_MODULE_LOAD_FUNCTION(mod_verto_load)6125 SWITCH_MODULE_LOAD_FUNCTION(mod_verto_load)
6126 {
6127 switch_api_interface_t *api_interface = NULL;
6128 switch_chat_interface_t *chat_interface = NULL;
6129 switch_json_api_interface_t *json_api_interface = NULL;
6130 int r;
6131 switch_cache_db_handle_t *dbh;
6132 //switch_application_interface_t *app_interface = NULL;
6133
6134
6135 if (switch_event_reserve_subclass(MY_EVENT_LOGIN) != SWITCH_STATUS_SUCCESS) {
6136 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_LOGIN);
6137 return SWITCH_STATUS_TERM;
6138 }
6139
6140 if (switch_event_reserve_subclass(MY_EVENT_CLIENT_DISCONNECT) != SWITCH_STATUS_SUCCESS) {
6141 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_CLIENT_DISCONNECT);
6142 return SWITCH_STATUS_TERM;
6143 }
6144
6145 if (switch_event_reserve_subclass(MY_EVENT_CLIENT_CONNECT) != SWITCH_STATUS_SUCCESS) {
6146 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_CLIENT_CONNECT);
6147 return SWITCH_STATUS_TERM;
6148 }
6149
6150 memset(&verto_globals, 0, sizeof(verto_globals));
6151 verto_globals.pool = pool;
6152 #ifndef WIN32
6153 verto_globals.ready = SIGUSR1;
6154 #endif
6155 verto_globals.enable_presence = SWITCH_TRUE;
6156 verto_globals.enable_fs_events = SWITCH_FALSE;
6157
6158 switch_mutex_init(&verto_globals.mutex, SWITCH_MUTEX_NESTED, verto_globals.pool);
6159
6160 switch_mutex_init(&verto_globals.method_mutex, SWITCH_MUTEX_NESTED, verto_globals.pool);
6161 switch_core_hash_init(&verto_globals.method_hash);
6162
6163 switch_thread_rwlock_create(&verto_globals.event_channel_rwlock, verto_globals.pool);
6164 switch_core_hash_init(&verto_globals.event_channel_hash);
6165
6166 switch_mutex_init(&verto_globals.jsock_mutex, SWITCH_MUTEX_NESTED, verto_globals.pool);
6167 switch_core_hash_init(&verto_globals.jsock_hash);
6168
6169 switch_thread_rwlock_create(&verto_globals.tech_rwlock, verto_globals.pool);
6170
6171 switch_mutex_init(&verto_globals.detach_mutex, SWITCH_MUTEX_NESTED, verto_globals.pool);
6172 switch_mutex_init(&verto_globals.detach2_mutex, SWITCH_MUTEX_NESTED, verto_globals.pool);
6173 switch_thread_cond_create(&verto_globals.detach_cond, verto_globals.pool);
6174 verto_globals.detach_timeout = 120;
6175
6176
6177
6178
6179 memset(&json_GLOBALS, 0, sizeof(json_GLOBALS));
6180 switch_mutex_init(&json_GLOBALS.store_mutex, SWITCH_MUTEX_NESTED, pool);
6181 switch_core_hash_init(&json_GLOBALS.store_hash);
6182
6183
6184 dbh = json_get_db_handle();
6185 switch_cache_db_test_reactive(dbh, "select name from json_store where name=''", "drop table json_store", json_sql);
6186 switch_cache_db_release_db_handle(&dbh);
6187
6188
6189
6190 switch_event_channel_bind(SWITCH_EVENT_CHANNEL_GLOBAL, verto_broadcast, &verto_globals.event_channel_id, NULL);
6191
6192
6193 r = init();
6194
6195 if (r) return SWITCH_STATUS_TERM;
6196
6197 jrpc_init();
6198
6199 /* connect my internal structure to the blank pointer passed to me */
6200 *module_interface = switch_loadable_module_create_module_interface(pool, modname);
6201
6202 SWITCH_ADD_API(api_interface, "verto", "Verto API", verto_function, "syntax");
6203 SWITCH_ADD_API(api_interface, "verto_contact", "Generate a verto endpoint dialstring", verto_contact_function, "user@domain");
6204 switch_console_set_complete("add verto help");
6205 switch_console_set_complete("add verto status");
6206 switch_console_set_complete("add verto xmlstatus");
6207
6208 SWITCH_ADD_JSON_API(json_api_interface, "store", "JSON store", json_store_function, "");
6209
6210 verto_endpoint_interface = (switch_endpoint_interface_t *) switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
6211 verto_endpoint_interface->interface_name = EP_NAME;
6212 verto_endpoint_interface->io_routines = &verto_io_routines;
6213
6214 SWITCH_ADD_CHAT(chat_interface, VERTO_CHAT_PROTO, chat_send);
6215
6216 switch_core_register_secondary_recover_callback(modname, verto_recover_callback);
6217
6218 if (verto_globals.enable_presence) {
6219 switch_event_bind(modname, SWITCH_EVENT_CHANNEL_CALLSTATE, SWITCH_EVENT_SUBCLASS_ANY, presence_event_handler, NULL);
6220 }
6221
6222 if (verto_globals.enable_fs_events) {
6223 if (switch_event_bind(modname, SWITCH_EVENT_ALL, SWITCH_EVENT_SUBCLASS_ANY, event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
6224 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
6225 return SWITCH_STATUS_GENERR;
6226 }
6227 }
6228
6229 run_profiles();
6230
6231 /* indicate that the module should continue to be loaded */
6232 return SWITCH_STATUS_SUCCESS;
6233 }
6234
6235 /*
6236 Called when the system shuts down
6237 Macro expands to: switch_status_t mod_verto_shutdown() */
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_verto_shutdown)6238 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_verto_shutdown)
6239 {
6240
6241 switch_event_free_subclass(MY_EVENT_LOGIN);
6242 switch_event_free_subclass(MY_EVENT_CLIENT_DISCONNECT);
6243 switch_event_free_subclass(MY_EVENT_CLIENT_CONNECT);
6244
6245 json_cleanup();
6246 switch_core_hash_destroy(&json_GLOBALS.store_hash);
6247
6248 switch_event_channel_unbind(NULL, verto_broadcast, NULL);
6249 switch_event_unbind_callback(presence_event_handler);
6250 switch_event_unbind_callback(event_handler);
6251
6252 switch_core_unregister_secondary_recover_callback(modname);
6253 do_shutdown();
6254 attach_wake();
6255 attach_wake();
6256
6257 switch_core_hash_destroy(&verto_globals.method_hash);
6258 switch_core_hash_destroy(&verto_globals.event_channel_hash);
6259 switch_core_hash_destroy(&verto_globals.jsock_hash);
6260
6261 return SWITCH_STATUS_SUCCESS;
6262 }
6263
SWITCH_MODULE_RUNTIME_FUNCTION(mod_verto_runtime)6264 SWITCH_MODULE_RUNTIME_FUNCTION(mod_verto_runtime)
6265 {
6266 switch_mutex_lock(verto_globals.detach_mutex);
6267
6268 while(verto_globals.running) {
6269 if (verto_globals.detached) {
6270 drop_detached();
6271 switch_yield(1000000);
6272 } else {
6273 switch_mutex_lock(verto_globals.detach2_mutex);
6274 if (verto_globals.running) {
6275 switch_thread_cond_wait(verto_globals.detach_cond, verto_globals.detach_mutex);
6276 }
6277 switch_mutex_unlock(verto_globals.detach2_mutex);
6278 }
6279 }
6280
6281 switch_mutex_unlock(verto_globals.detach_mutex);
6282
6283 return SWITCH_STATUS_TERM;
6284 }
6285
6286
6287 /* For Emacs:
6288 * Local Variables:
6289 * mode:c
6290 * indent-tabs-mode:t
6291 * tab-width:4
6292 * c-basic-offset:4
6293 * End:
6294 * For VIM:
6295 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet
6296 */
6297