File: | mod/endpoints/mod_verto/mod_verto.c |
Warning: | line 1053, column 28 Null pointer passed as an argument to a 'nonnull' parameter |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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)switch_status_t mod_verto_shutdown (void); | |||
39 | SWITCH_MODULE_LOAD_FUNCTION(mod_verto_load)switch_status_t mod_verto_load (switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool); | |||
40 | SWITCH_MODULE_RUNTIME_FUNCTION(mod_verto_runtime)switch_status_t mod_verto_runtime (void); | |||
41 | ||||
42 | SWITCH_MODULE_DEFINITION(mod_verto, mod_verto_load, mod_verto_shutdown, mod_verto_runtime)static const char modname[] = "mod_verto" ; __attribute__((visibility ("default"))) switch_loadable_module_function_table_t mod_verto_module_interface = { 5, mod_verto_load, mod_verto_shutdown, mod_verto_runtime , SMODF_NONE }; | |||
43 | ||||
44 | #define EP_NAME"verto.rtc" "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(*__errno_location ()), buf, len) strerror_s(buf, len, errno(*__errno_location ())) | |||
63 | #endif | |||
64 | ||||
65 | #define log_and_exit(severity, ...)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 65, ((void*)0), (severity), ...); goto error switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 65, ((void*)0), (severity), __VA_ARGS__); goto error | |||
66 | #define die(...)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 66, ((void*)0), (SWITCH_LOG_WARNING), ...); goto error log_and_exit(SWITCH_LOG_WARNING, __VA_ARGS__)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 66, ((void*)0), (SWITCH_LOG_WARNING), __VA_ARGS__ ); goto error | |||
67 | #define die_errno(fmt)do { char errbuf[8192] = {0}; strerror_r((*__errno_location ( )), (char *)&errbuf, sizeof(errbuf)); switch_log_printf(SWITCH_CHANNEL_ID_LOG , "mod_verto.c", (const char *)__func__, 67, ((void*)0), (SWITCH_LOG_WARNING ), fmt ", errno=%d, %s\n", (*__errno_location ()), (char *)& errbuf); goto error; } while(0) do { char errbuf[BUFSIZ8192] = {0}; strerror_r(errno(*__errno_location ()), (char *)&errbuf, sizeof(errbuf)); die(fmt ", errno=%d, %s\n", errno, (char *)&errbuf)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 67, ((void*)0), (SWITCH_LOG_WARNING), fmt ", errno=%d, %s\n" , (*__errno_location ()), (char *)&errbuf); goto error; } while(0) | |||
68 | #define die_errnof(fmt, ...)do { char errbuf[8192] = {0}; strerror_r((*__errno_location ( )), (char *)&errbuf, sizeof(errbuf)); switch_log_printf(SWITCH_CHANNEL_ID_LOG , "mod_verto.c", (const char *)__func__, 68, ((void*)0), (SWITCH_LOG_WARNING ), fmt ", errno=%d, %s\n", ..., (*__errno_location ()), (char *)&errbuf); goto error; } while(0) do { char errbuf[BUFSIZ8192] = {0}; strerror_r(errno(*__errno_location ()), (char *)&errbuf, sizeof(errbuf)); die(fmt ", errno=%d, %s\n", __VA_ARGS__, errno, (char *)&errbuf)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 68, ((void*)0), (SWITCH_LOG_WARNING), fmt ", errno=%d, %s\n" , __VA_ARGS__, (*__errno_location ()), (char *)&errbuf); goto error; } 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 | ||||
99 | static void json_cleanup(void) | |||
100 | { | |||
101 | switch_hash_index_t *hi = NULL((void*)0); | |||
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((void*)0), &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)if (hi) {free(hi);hi=((void*)0);}; | |||
121 | ||||
122 | switch_mutex_unlock(json_GLOBALS.store_mutex); | |||
123 | ||||
124 | } | |||
125 | ||||
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 | ||||
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((void*)0); | |||
151 | } | |||
152 | } | |||
153 | ||||
154 | static void close_file(ws_socket_t *sock) | |||
155 | { | |||
156 | if (*sock != ws_sock_invalid(ws_socket_t)-1) { | |||
157 | #ifndef WIN32 | |||
158 | close(*sock); | |||
159 | #else | |||
160 | closesocket(*sock); | |||
161 | #endif | |||
162 | *sock = ws_sock_invalid(ws_socket_t)-1; | |||
163 | } | |||
164 | } | |||
165 | ||||
166 | static void close_socket(ws_socket_t *sock) | |||
167 | { | |||
168 | if (*sock != ws_sock_invalid(ws_socket_t)-1) { | |||
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 | ||||
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_methodTLS_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)((profile->ssl_ctx) ? (void) (0) : __assert_fail ("profile->ssl_ctx" , "mod_verto.c", 184, __extension__ __PRETTY_FUNCTION__)); | |||
185 | ||||
186 | /* Disable SSLv2 */ | |||
187 | SSL_CTX_set_options(profile->ssl_ctx, SSL_OP_NO_SSLv20x0); | |||
188 | /* Disable SSLv3 */ | |||
189 | SSL_CTX_set_options(profile->ssl_ctx, SSL_OP_NO_SSLv30x02000000U); | |||
190 | /* Disable TLSv1 */ | |||
191 | SSL_CTX_set_options(profile->ssl_ctx, SSL_OP_NO_TLSv10x04000000U); | |||
192 | /* Disable Compression CRIME (Compression Ratio Info-leak Made Easy) */ | |||
193 | SSL_CTX_set_options(profile->ssl_ctx, SSL_OP_NO_COMPRESSION0x00020000U); | |||
194 | ||||
195 | /* set the local certificate from CertFile */ | |||
196 | if (!zstr(profile->chain)_zstr(profile->chain)) { | |||
197 | if (switch_file_exists(profile->chain, NULL((void*)0)) != 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((void*)0)) != 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_PEM1)) { | |||
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((void*)0)) != 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_PEM1)) { | |||
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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 241, ((void*)0), 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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 248, ((void*)0), 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 | ||||
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((void*)0), *np, *last = NULL((void*)0); | |||
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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 297, ((void*)0), SWITCH_LOG_DEBUG, "UNSUBBING %s [%s]\n", thisnp->jsock->name, thisnp->head->event_channel); | |||
298 | } | |||
299 | ||||
300 | thisnp->jsock = NULL((void*)0); | |||
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 | ||||
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((void*)0); | |||
322 | ||||
323 | for (hi = switch_core_hash_first(verto_globals.event_channel_hash)switch_core_hash_first_iter(verto_globals.event_channel_hash, ((void*)0)); hi;) { | |||
324 | switch_core_hash_this(hi, NULL((void*)0), NULL((void*)0), &val); | |||
325 | head = (jsock_sub_node_head_t *) val; | |||
326 | jsock_unsub_head(NULL((void*)0), 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)if (hi) {free(hi);hi=((void*)0);}; | |||
331 | goto top; | |||
332 | } | |||
333 | ||||
334 | switch_thread_rwlock_unlock(verto_globals.event_channel_rwlock); | |||
335 | } | |||
336 | ||||
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)switch_core_hash_first_iter(verto_globals.event_channel_hash, ((void*)0)); hi; hi = switch_core_hash_next(&hi)) { | |||
349 | switch_core_hash_this(hi, NULL((void*)0), NULL((void*)0), &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 | ||||
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((void*)0); | |||
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)switch_core_session_perform_locate(m->val, "mod_verto.c", ( const char *)__func__, 389))) { | |||
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_event_create_subclass_detailed("mod_verto.c", (const char * )(const char *)__func__, 393, &event, SWITCH_EVENT_CHANNEL_CALLSTATE , ((void*)0)) == 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)switch_event_fire_detailed("mod_verto.c", (const char * )(const char *)__func__, 399, &event, ((void*)0)); | |||
400 | } | |||
401 | ||||
402 | switch_core_session_rwunlock(session); | |||
403 | } | |||
404 | } | |||
405 | ||||
406 | switch_console_free_matches(&matches); | |||
407 | } | |||
408 | } | |||
409 | ||||
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))(void)((((head = switch_calloc(1, (sizeof(*head))))) ? (void) (0) : __assert_fail ("(head = switch_calloc(1, (sizeof(*head))))" , "mod_verto.c", 419, __extension__ __PRETTY_FUNCTION__)),head ); | |||
420 | head->event_channel = strdup(event_channel); | |||
421 | switch_core_hash_insert(verto_globals.event_channel_hash, event_channel, head)switch_core_hash_insert_destructor(verto_globals.event_channel_hash , event_channel, head, ((void*)0)); | |||
422 | ||||
423 | switch_zmalloc(node, sizeof(*node))(void)((((node = switch_calloc(1, (sizeof(*node))))) ? (void) (0) : __assert_fail ("(node = switch_calloc(1, (sizeof(*node))))" , "mod_verto.c", 423, __extension__ __PRETTY_FUNCTION__)),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))(void)((((node = switch_calloc(1, (sizeof(*node))))) ? (void) (0) : __assert_fail ("(node = switch_calloc(1, (sizeof(*node))))" , "mod_verto.c", 440, __extension__ __PRETTY_FUNCTION__)),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 | ||||
466 | static void del_jsock(jsock_t *jsock) | |||
467 | { | |||
468 | jsock_t *p, *last = NULL((void*)0); | |||
469 | ||||
470 | jsock_unsub_channel(jsock, NULL((void*)0)); | |||
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 | ||||
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 | ||||
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 | ||||
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 | ||||
525 | static cJSON *jrpc_new_req(const char *method, const char *call_id, cJSON **paramsP) | |||
526 | { | |||
527 | cJSON *msg, *params = NULL((void*)0); | |||
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 | ||||
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)_zstr(idstr) ? cJSON_CreateNull() : cJSON_CreateString(idstr)); | |||
560 | } else { | |||
561 | cJSON_AddItemToObject(obj, "id", cJSON_CreateNumber(id)); | |||
562 | } | |||
563 | } | |||
564 | ||||
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 | ||||
577 | static void jrpc_add_result(cJSON *obj, cJSON *result) | |||
578 | { | |||
579 | if (result) { | |||
580 | cJSON_AddItemToObject(obj, "result", result); | |||
581 | } | |||
582 | } | |||
583 | ||||
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)((json) ? (void) (0) : __assert_fail ("json", "mod_verto.c", 589 , __extension__ __PRETTY_FUNCTION__)); | |||
590 | ||||
591 | if (!*json) { | |||
592 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 592, ((void*)0), SWITCH_LOG_ALERT, "WRITE NULL JS ERROR %" SWITCH_SIZE_T_FMT"ld" "\n", r); | |||
593 | return r; | |||
594 | } | |||
595 | ||||
596 | if (!zstr(jsock->uuid_str)_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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 607, ((void*)0), 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)if (json_text) {free(json_text);json_text=((void*)0);}; | |||
614 | } | |||
615 | ||||
616 | if (destroy) { | |||
617 | cJSON_Delete(*json); | |||
618 | *json = NULL((void*)0); | |||
619 | } | |||
620 | ||||
621 | if (r <= 0) { | |||
622 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 622, ((void*)0), SWITCH_LOG_ALERT, "WRITE RETURNED ERROR %" SWITCH_SIZE_T_FMT"ld" " \n", r); | |||
623 | jsock->drop = 1; | |||
624 | jsock->ready = 0; | |||
625 | } | |||
626 | ||||
627 | return r; | |||
628 | } | |||
629 | ||||
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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 647, ((void*)0), SWITCH_LOG_CRIT, "Lost %d json events!\n", le); | |||
648 | } | |||
649 | } else { | |||
650 | if (++jsock->lost_events > MAX_MISSED500) { | |||
651 | jsock->drop++; | |||
652 | } | |||
653 | ||||
654 | if (!destroy) { | |||
655 | cJSON_Delete(jp); | |||
656 | jp = NULL((void*)0); | |||
657 | } | |||
658 | } | |||
659 | ||||
660 | if (destroy) { | |||
661 | *json = NULL((void*)0); | |||
662 | } | |||
663 | ||||
664 | return status; | |||
665 | } | |||
666 | ||||
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((void*)0), *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((void*)0), ¶ms); | |||
681 | jsock_queue_event(np->jsock, &msg, SWITCH_TRUE); | |||
682 | } | |||
683 | } | |||
684 | } | |||
685 | } | |||
686 | ||||
687 | static void jsock_send_event(cJSON *event) | |||
688 | { | |||
689 | ||||
690 | const char *event_channel, *session_uuid = NULL((void*)0); | |||
691 | jsock_t *use_jsock = NULL((void*)0); | |||
692 | switch_core_session_t *session = NULL((void*)0); | |||
693 | ||||
694 | if (!(event_channel = cJSON_GetObjectCstr(event, "eventChannel"))) { | |||
695 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 695, ((void*)0), SWITCH_LOG_ERROR, "NO EVENT CHANNEL SPECIFIED\n"); | |||
696 | return; | |||
697 | } | |||
698 | ||||
699 | ||||
700 | if ((session = switch_core_session_locate(event_channel)switch_core_session_perform_locate(event_channel, "mod_verto.c" , (const char *)__func__, 700))) { | |||
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")switch_channel_get_variable_dup(channel, "jsock_uuid_str", SWITCH_TRUE , -1); | |||
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((void*)0), *params; | |||
711 | params = cJSON_Duplicate(event, 1); | |||
712 | msg = jrpc_new_req("verto.event", NULL((void*)0), ¶ms); | |||
713 | jsock_queue_event(use_jsock, &msg, SWITCH_TRUE); | |||
714 | switch_thread_rwlock_unlock(use_jsock->rwlock); | |||
715 | use_jsock = NULL((void*)0); | |||
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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 722, ((void*)0), 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)((main_channel) ? (void) (0) : __assert_fail ("main_channel", "mod_verto.c", 732, __extension__ __PRETTY_FUNCTION__)); | |||
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((void*)0); | |||
743 | } | |||
744 | } | |||
745 | ||||
746 | static jrpc_func_t jrpc_get_func(jsock_t *jsock, const char *method) | |||
747 | { | |||
748 | jrpc_func_t func = NULL((void*)0); | |||
749 | char *main_method = NULL((void*)0); | |||
750 | ||||
751 | switch_assert(method)((method) ? (void) (0) : __assert_fail ("method", "mod_verto.c" , 751, __extension__ __PRETTY_FUNCTION__)); | |||
752 | ||||
753 | if (jsock->allowed_methods) { | |||
754 | if (strchr(method, '.')) { | |||
755 | char *p; | |||
756 | main_method = strdup(method); | |||
757 | switch_assert(main_method)((main_method) ? (void) (0) : __assert_fail ("main_method", "mod_verto.c" , 757, __extension__ __PRETTY_FUNCTION__)); | |||
758 | if ((p = strchr(main_method, '.'))) { | |||
759 | *p = '\0'; | |||
760 | } | |||
761 | } | |||
762 | ||||
763 | if (!(switch_event_get_header(jsock->allowed_methods, method)switch_event_get_header_idx(jsock->allowed_methods, method , -1) || (main_method && switch_event_get_header(jsock->allowed_methods, main_method)switch_event_get_header_idx(jsock->allowed_methods, main_method , -1)))) { | |||
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)if (main_method) {free(main_method);main_method=((void*)0);}; | |||
775 | ||||
776 | return func; | |||
777 | } | |||
778 | ||||
779 | ||||
780 | static void jrpc_add_func(const char *method, jrpc_func_t func) | |||
781 | { | |||
782 | switch_assert(method)((method) ? (void) (0) : __assert_fail ("method", "mod_verto.c" , 782, __extension__ __PRETTY_FUNCTION__)); | |||
783 | switch_assert(func)((func) ? (void) (0) : __assert_fail ("func", "mod_verto.c", 783 , __extension__ __PRETTY_FUNCTION__)); | |||
784 | ||||
785 | switch_mutex_lock(verto_globals.method_mutex); | |||
786 | switch_core_hash_insert(verto_globals.method_hash, method, (void *) (intptr_t) func)switch_core_hash_insert_destructor(verto_globals.method_hash, method, (void *) (intptr_t) func, ((void*)0)); | |||
787 | switch_mutex_unlock(verto_globals.method_mutex); | |||
788 | } | |||
789 | ||||
790 | static char *MARKER = "X"; | |||
791 | ||||
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)_zstr(str)) { | |||
800 | if (!strcasecmp(str, "__ANY__")) { | |||
801 | return; | |||
802 | } | |||
803 | } | |||
804 | ||||
805 | switch_event_create(event, SWITCH_EVENT_REQUEST_PARAMS)switch_event_create_subclass_detailed("mod_verto.c", (const char * )(const char *)__func__, 805, event, SWITCH_EVENT_REQUEST_PARAMS , ((void*)0)); | |||
806 | ||||
807 | if (!zstr(str)_zstr(str)) { | |||
808 | edup = strdup(str); | |||
809 | switch_assert(edup)((edup) ? (void) (0) : __assert_fail ("edup", "mod_verto.c", 809 , __extension__ __PRETTY_FUNCTION__)); | |||
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)if (edup) {free(edup);edup=((void*)0);}; | |||
826 | ||||
827 | } | |||
828 | } | |||
829 | ||||
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((void*)0), *allowed_jsapi = NULL((void*)0), *allowed_fsapi = NULL((void*)0), *allowed_event_channels = NULL((void*)0); | |||
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(val) || zstr(var)_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 | ||||
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_event_create_subclass_detailed("mod_verto.c", (const char * )(const char *)__func__, 876, &s_event, SWITCH_EVENT_CUSTOM , "verto::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)switch_event_fire_detailed("mod_verto.c", (const char * )(const char *)__func__, 887, &s_event, ((void*)0)); | |||
888 | } | |||
889 | } | |||
890 | ||||
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((void*)0); | |||
895 | const char *login = NULL((void*)0); | |||
896 | cJSON *json_ptr = NULL((void*)0); | |||
897 | char *input = NULL((void*)0); | |||
898 | char *a1_hash = NULL((void*)0); | |||
899 | char a1_hash_buff[33] = ""; | |||
900 | ||||
901 | if (!params) { | |||
902 | *code = CODE_AUTH_FAILED-32001; | |||
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)_zstr(login)) { | |||
911 | goto end; | |||
912 | } | |||
913 | ||||
914 | if (zstr(passwd)_zstr(passwd)) { | |||
915 | *code = CODE_AUTH_FAILED-32001; | |||
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-32001; | |||
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)_zstr(jsock->profile->userauth)) { | |||
930 | switch_xml_t x_user = NULL((void*)0); | |||
931 | char *id = NULL((void*)0), *domain = NULL((void*)0); | |||
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)switch_core_perform_strdup(jsock->pool, login, "mod_verto.c" , (const char *)__func__, 938); | |||
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-32001; | |||
952 | switch_snprintf(message, mlen, "Missing or improper credentials"); | |||
953 | goto end; | |||
954 | } | |||
955 | ||||
956 | switch_event_create(&req_params, SWITCH_EVENT_REQUEST_PARAMS)switch_event_create_subclass_detailed("mod_verto.c", (const char * )(const char *)__func__, 956, &req_params, SWITCH_EVENT_REQUEST_PARAMS , ((void*)0)); | |||
957 | switch_assert(req_params)((req_params) ? (void) (0) : __assert_fail ("req_params", "mod_verto.c" , 957, __extension__ __PRETTY_FUNCTION__)); | |||
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(1 << 1)) { | |||
964 | switch_event_add_header_string(req_params, SWITCH_STACK_BOTTOM, i->string, "true"); | |||
965 | } else if (i->type == cJSON_False(1 << 0)) { | |||
966 | switch_event_add_header_string(req_params, SWITCH_STACK_BOTTOM, i->string, "false"); | |||
967 | } else if (!zstr(i->string)_zstr(i->string) && !zstr(i->valuestring)_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(1 << 1)) { | |||
979 | switch_event_add_header_string(jsock->user_vars, SWITCH_STACK_BOTTOM, i->string, "true"); | |||
980 | } else if (i->type == cJSON_False(1 << 0)) { | |||
981 | switch_event_add_header_string(jsock->user_vars, SWITCH_STACK_BOTTOM, i->string, "false"); | |||
982 | } else if (!zstr(i->string)_zstr(i->string) && !zstr(i->valuestring)_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((void*)0), &x_user, req_params) != SWITCH_STATUS_SUCCESS && !jsock->profile->blind_reg) { | |||
991 | *code = CODE_AUTH_FAILED-32001; | |||
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((void*)0), *verto_context = NULL((void*)0), *verto_dialplan = NULL((void*)0); | |||
997 | ||||
998 | jsock->id = switch_core_strdup(jsock->pool, id)switch_core_perform_strdup(jsock->pool, id, "mod_verto.c", (const char *)__func__, 998); | |||
999 | jsock->domain = switch_core_strdup(jsock->pool, domain)switch_core_perform_strdup(jsock->pool, domain, "mod_verto.c" , (const char *)__func__, 999); | |||
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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1023, ((void*)0), SWITCH_LOG_DEBUG,"a1-hash-plain = '%s' a1-hash-md5 = '%s'\n", input, a1_hash); | |||
1024 | switch_safe_free(input)if (input) {free(input);input=((void*)0);}; | |||
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)_zstr(verto_dialplan)) { | |||
1045 | jsock->dialplan = switch_core_strdup(jsock->pool, verto_dialplan)switch_core_perform_strdup(jsock->pool, verto_dialplan, "mod_verto.c" , (const char *)__func__, 1045); | |||
1046 | } | |||
1047 | ||||
1048 | if (!zstr(verto_context)_zstr(verto_context)) { | |||
1049 | jsock->context = switch_core_strdup(jsock->pool, verto_context)switch_core_perform_strdup(jsock->pool, verto_context, "mod_verto.c" , (const char *)__func__, 1049); | |||
1050 | } | |||
1051 | ||||
1052 | ||||
1053 | if (zstr(use_passwd)_zstr(use_passwd) || strcmp(a1_hash ? a1_hash : passwd, use_passwd)) { | |||
| ||||
1054 | r = SWITCH_FALSE; | |||
1055 | *code = CODE_AUTH_FAILED-32001; | |||
1056 | switch_snprintf(message, mlen, "Authentication Failure"); | |||
1057 | jsock->uid = NULL((void*)0); | |||
1058 | login_fire_custom_event(jsock, params, 0, "Authentication Failure"); | |||
1059 | } else { | |||
1060 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1060, ((void*)0), 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 | ||||
1079 | static void set_call_params(cJSON *params, verto_pvt_t *tech_pvt) { | |||
1080 | const char *caller_id_name = NULL((void*)0); | |||
1081 | const char *caller_id_number = NULL((void*)0); | |||
1082 | const char *callee_id_name = NULL((void*)0); | |||
1083 | const char *callee_id_number = NULL((void*)0); | |||
1084 | const char *prefix = "verto_h_"; | |||
1085 | switch_event_header_t *var = NULL((void*)0); | |||
1086 | ||||
1087 | caller_id_name = switch_channel_get_variable(tech_pvt->channel, "caller_id_name")switch_channel_get_variable_dup(tech_pvt->channel, "caller_id_name" , SWITCH_TRUE, -1); | |||
1088 | caller_id_number = switch_channel_get_variable(tech_pvt->channel, "caller_id_number")switch_channel_get_variable_dup(tech_pvt->channel, "caller_id_number" , SWITCH_TRUE, -1); | |||
1089 | callee_id_name = switch_channel_get_variable(tech_pvt->channel, "callee_id_name")switch_channel_get_variable_dup(tech_pvt->channel, "callee_id_name" , SWITCH_TRUE, -1); | |||
1090 | callee_id_number = switch_channel_get_variable(tech_pvt->channel, "callee_id_number")switch_channel_get_variable_dup(tech_pvt->channel, "callee_id_number" , SWITCH_TRUE, -1); | |||
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 | ||||
1112 | static jsock_t *get_jsock(const char *uuid) | |||
1113 | { | |||
1114 | jsock_t *jsock = NULL((void*)0); | |||
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((void*)0); | |||
1120 | } | |||
1121 | } | |||
1122 | switch_mutex_unlock(verto_globals.jsock_mutex); | |||
1123 | ||||
1124 | return jsock; | |||
1125 | } | |||
1126 | ||||
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)((jsock) ? (void) (0) : __assert_fail ("jsock", "mod_verto.c" , 1134, __extension__ __PRETTY_FUNCTION__)); | |||
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((void*)0); | |||
1141 | cJSON *msg = NULL((void*)0); | |||
1142 | msg = jrpc_new_req("verto.punt", NULL((void*)0), ¶ms); | |||
1143 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1143, ((void*)0), 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)switch_core_hash_insert_destructor(verto_globals.jsock_hash, jsock ->uuid_str, jsock, ((void*)0)); | |||
1154 | } | |||
1155 | ||||
1156 | switch_mutex_unlock(verto_globals.jsock_mutex); | |||
1157 | } | |||
1158 | ||||
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 | ||||
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 | ||||
1197 | static void tech_reattach(verto_pvt_t *tech_pvt, jsock_t *jsock) | |||
1198 | { | |||
1199 | cJSON *params = NULL((void*)0); | |||
1200 | cJSON *msg = NULL((void*)0); | |||
1201 | ||||
1202 | tech_pvt->detach_time = 0; | |||
1203 | verto_globals.detached--; | |||
1204 | attach_wake(); | |||
1205 | switch_set_flag(tech_pvt, TFLAG_ATTACH_REQ)(tech_pvt)->flags |= (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)switch_channel_set_flag_value(tech_pvt->channel, CF_REINVITE , 1); | |||
1209 | switch_channel_set_flag(tech_pvt->channel, CF_RECOVERING)switch_channel_set_flag_value(tech_pvt->channel, CF_RECOVERING , 1); | |||
1210 | switch_core_media_gen_local_sdp(tech_pvt->session, SDP_TYPE_REQUEST, NULL((void*)0), 0, NULL((void*)0), 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)_switch_core_session_request_video_refresh(tech_pvt->session , 0, "mod_verto.c", (const char *)__func__, 1213); | |||
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_CHANNEL_ID_SESSION, "mod_verto.c", (const char *)__func__ , 1216, (const char*)(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 | ||||
1223 | static void drop_detached(void) | |||
1224 | { | |||
1225 | verto_pvt_t *tech_pvt; | |||
1226 | switch_time_t now = switch_epoch_time_now(NULL((void*)0)); | |||
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)(switch_channel_get_state(tech_pvt->channel) < CS_HANGUP )) { | |||
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)switch_channel_perform_hangup(tech_pvt->channel, "mod_verto.c" , (const char *)__func__, 1235, SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE ); | |||
1236 | } | |||
1237 | } | |||
1238 | switch_thread_rwlock_unlock(verto_globals.tech_rwlock); | |||
1239 | } | |||
1240 | ||||
1241 | static void attach_calls(jsock_t *jsock) | |||
1242 | { | |||
1243 | verto_pvt_t *tech_pvt; | |||
1244 | cJSON *msg = NULL((void*)0); | |||
1245 | cJSON *params = NULL((void*)0); | |||
1246 | cJSON *reattached_sessions = NULL((void*)0); | |||
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)(switch_channel_get_state(tech_pvt->channel) < CS_HANGUP )) { | |||
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((void*)0), ¶ms); | |||
1264 | cJSON_AddItemToObject(params, "reattached_sessions", reattached_sessions); | |||
1265 | jsock_queue_event(jsock, &msg, SWITCH_TRUE); | |||
1266 | } | |||
1267 | ||||
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)(switch_channel_get_state(tech_pvt->channel) < CS_HANGUP )) { | |||
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)switch_channel_perform_hangup(tech_pvt->channel, "mod_verto.c" , (const char *)__func__, 1281, 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)switch_channel_perform_hangup(tech_pvt->channel, "mod_verto.c" , (const char *)__func__, 1286, 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((void*)0)); | |||
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 | ||||
1301 | static void process_jrpc_response(jsock_t *jsock, cJSON *json) | |||
1302 | { | |||
1303 | } | |||
1304 | ||||
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)_zstr(uuid)) { | |||
1310 | switch_set_string(jsock->uuid_str, uuid)switch_copy_string(jsock->uuid_str, uuid, sizeof(jsock-> uuid_str)); | |||
1311 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1311, ((void*)0), 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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1314, ((void*)0), SWITCH_LOG_DEBUG, "%s new RPC session %s\n", jsock->name, jsock->uuid_str); | |||
1315 | } | |||
1316 | ||||
1317 | attach_jsock(jsock); | |||
1318 | ||||
1319 | } | |||
1320 | ||||
1321 | static cJSON *process_jrpc(jsock_t *jsock, cJSON *json) | |||
1322 | { | |||
1323 | cJSON *reply = NULL((void*)0), *echo = NULL((void*)0), *id = NULL((void*)0), *params = NULL((void*)0), *response = NULL((void*)0), *result; | |||
1324 | const char *method = NULL((void*)0), *version = NULL((void*)0), *sessid = NULL((void*)0); | |||
1325 | jrpc_func_t func = NULL((void*)0); | |||
1326 | ||||
1327 | switch_assert(json)((json) ? (void) (0) : __assert_fail ("json", "mod_verto.c", 1327 , __extension__ __PRETTY_FUNCTION__)); | |||
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)((jsock)->flags & JPFLAG_INIT)) { | |||
1339 | set_session_id(jsock, sessid); | |||
1340 | switch_set_flag(jsock, JPFLAG_INIT)(jsock)->flags |= (JPFLAG_INIT); | |||
1341 | } | |||
1342 | ||||
1343 | if (zstr(version)_zstr(version) || strcmp(version, "2.0")) { | |||
1344 | reply = jrpc_new(0); | |||
1345 | jrpc_add_error(reply, CODE_INVALID-32600, "Invalid message", id); | |||
1346 | goto end; | |||
1347 | } | |||
1348 | ||||
1349 | if (result) { | |||
1350 | process_jrpc_response(jsock, json); | |||
1351 | return NULL((void*)0); | |||
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)->flags & JPFLAG_AUTHED) && (jsock->profile->userauth || jsock->profile->root_passwd)) { | |||
1359 | int code = CODE_AUTH_REQUIRED-32000; | |||
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)(jsock)->flags |= (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(1 << 1) || (echo->type == cJSON_String(1 << 4) && 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 | ||||
1400 | static switch_status_t process_input(jsock_t *jsock, uint8_t *data, switch_ssize_t bytes) | |||
1401 | { | |||
1402 | cJSON *json = NULL((void*)0), *reply = NULL((void*)0); | |||
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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1414, ((void*)0), SWITCH_LOG_DEBUG, "READ %s [%s]\n", jsock->name, log_text); | |||
1415 | free(log_text); | |||
1416 | } | |||
1417 | ||||
1418 | if (json->type == cJSON_Array(1 << 5)) { /* 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((void*)0)); | |||
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 | ||||
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!!! */ | |||
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((void*)0); | |||
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((void*)0); | |||
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((void*)0); | |||
1493 | } | |||
1494 | ||||
1495 | r->bytes_read += *len; | |||
1496 | ||||
1497 | return (uint8_t *)wsh->buffer; | |||
1498 | } | |||
1499 | ||||
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 | ||||
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)__builtin_va_start(ap, fmt); | |||
1517 | ret = switch_vasprintf(&data, fmt, ap); | |||
1518 | va_end(ap)__builtin_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)if (data) {free(data);data=((void*)0);}; | |||
1525 | } | |||
1526 | ||||
1527 | return ret ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; | |||
1528 | } | |||
1529 | ||||
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((void*)0)) == SWITCH_STATUS_SUCCESS) { | |||
1549 | switch_snprintf(path, sizeof(path), "%s%s%s%s", | |||
1550 | vhost->root, request->uri, end_of(path)*(*path == '\0' ? path : path + strlen(path) - 1) == '/' ? "" : 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((void*)0)) == SWITCH_STATUS_SUCCESS && | |||
1562 | switch_file_open(&fd, path, SWITCH_FOPEN_READ0x00001, SWITCH_FPROT_UREAD0x0400, 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"ld" "\r\n\r\n", | |||
1572 | switch_event_get_header(request->headers, "Event-Date-GMT")switch_event_get_header_idx(request->headers, "Event-Date-GMT" , -1), | |||
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 | ||||
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((void*)0); | |||
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_event_create_subclass_detailed("mod_verto.c", (const char * )(const char *)__func__, 1612, &stream.param_event, SWITCH_EVENT_CHANNEL_DATA , ((void*)0)) != 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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1622, ((void*)0), SWITCH_LOG_DEBUG, "%s [%4" SWITCH_SIZE_T_FMT"ld" "] %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")switch_event_get_header_idx(request.headers, "Event-Date-GMT" , -1), | |||
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((void*)0); | |||
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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1664, ((void*)0), SWITCH_LOG_ERROR, "Read error %" SWITCH_SSIZE_T_FMT"ld""\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)((jsock)->flags & JPFLAG_AUTHED) && vhost->auth_realm) { | |||
1693 | int code = CODE_AUTH_REQUIRED-32000; | |||
1694 | char message[128] = "Authentication Required"; | |||
1695 | cJSON *params = NULL((void*)0); | |||
1696 | char *www_auth; | |||
1697 | char auth_buffer[512]; | |||
1698 | char *auth_user = NULL((void*)0), *auth_pass = NULL((void*)0); | |||
1699 | ||||
1700 | www_auth = switch_event_get_header(request.headers, "Authorization")switch_event_get_header_idx(request.headers, "Authorization", -1); | |||
1701 | ||||
1702 | if (zstr(www_auth)_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)(jsock)->flags |= (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((void*)0); | |||
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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1765, ((void*)0), 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((void*)0), &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)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1812, ((void*)0), (SWITCH_LOG_WARNING), "%s Dropping Connection\n" , jsock->name); goto error; } | |||
1813 | if (pflags < 0 && (errno(*__errno_location ()) != EINTR4)) { die_errnof("%s POLL FAILED with %d", jsock->name, pflags)do { char errbuf[8192] = {0}; strerror_r((*__errno_location ( )), (char *)&errbuf, sizeof(errbuf)); switch_log_printf(SWITCH_CHANNEL_ID_LOG , "mod_verto.c", (const char *)__func__, 1813, ((void*)0), (SWITCH_LOG_WARNING ), "%s POLL FAILED with %d" ", errno=%d, %s\n", jsock->name , pflags, (*__errno_location ()), (char *)&errbuf); goto error ; } while(0); } | |||
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)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1815, ((void*)0), (SWITCH_LOG_INFO), "%s POLL HANGUP DETECTED (peer closed its end of socket)\n" , jsock->name); goto error; } | |||
1816 | if (pflags > 0 && (pflags & SWITCH_POLL_ERROR)) { die("%s POLL ERROR\n", jsock->name)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1816, ((void*)0), (SWITCH_LOG_WARNING), "%s POLL ERROR\n" , jsock->name); goto error; } | |||
1817 | if (pflags > 0 && (pflags & SWITCH_POLL_INVALID)) { die("%s POLL INVALID SOCKET (not opened or already closed)\n", jsock->name)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1817, ((void*)0), (SWITCH_LOG_WARNING), "%s POLL INVALID SOCKET (not opened or already closed)\n" , jsock->name); goto error; } | |||
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)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1824, ((void*)0), (SWITCH_LOG_WARNING), "%s BAD READ %" "ld" "\n", jsock->name, bytes); goto error; | |||
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)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1832, ((void*)0), (SWITCH_LOG_WARNING), "%s BAD READ %" "ld" "\n", jsock->name, bytes); goto error; | |||
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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1845, ((void*)0), 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 | ||||
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((void*)0), 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)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1874, ((void*)0), (SWITCH_LOG_NOTICE), "%s WS SETUP FAILED\n" , jsock->name); goto error; | |||
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)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1887, ((void*)0), (SWITCH_LOG_WARNING), "%s Dropping Connection\n" , jsock->name); goto error; } | |||
1888 | if (pflags < 0 && (errno(*__errno_location ()) != EINTR4)) { die_errnof("%s POLL FAILED with %d", jsock->name, pflags)do { char errbuf[8192] = {0}; strerror_r((*__errno_location ( )), (char *)&errbuf, sizeof(errbuf)); switch_log_printf(SWITCH_CHANNEL_ID_LOG , "mod_verto.c", (const char *)__func__, 1888, ((void*)0), (SWITCH_LOG_WARNING ), "%s POLL FAILED with %d" ", errno=%d, %s\n", jsock->name , pflags, (*__errno_location ()), (char *)&errbuf); goto error ; } while(0); } | |||
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)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1890, ((void*)0), (SWITCH_LOG_INFO), "%s POLL HANGUP DETECTED (peer closed its end of socket)\n" , jsock->name); goto error; } | |||
1891 | if (pflags > 0 && (pflags & SWITCH_POLL_ERROR)) { die("%s POLL ERROR\n", jsock->name)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1891, ((void*)0), (SWITCH_LOG_WARNING), "%s POLL ERROR\n" , jsock->name); goto error; } | |||
1892 | if (pflags > 0 && (pflags & SWITCH_POLL_INVALID)) { die("%s POLL INVALID SOCKET (not opened or already closed)\n", jsock->name)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1892, ((void*)0), (SWITCH_LOG_WARNING), "%s POLL INVALID SOCKET (not opened or already closed)\n" , jsock->name); goto error; } | |||
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)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1902, ((void*)0), (SWITCH_LOG_INFO), "%s Client sent close request\n" , jsock->name); goto error; | |||
1903 | } else { | |||
1904 | die("%s BAD READ %" SWITCH_SSIZE_T_FMT "\n", jsock->name, bytes)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1904, ((void*)0), (SWITCH_LOG_WARNING), "%s BAD READ %" "ld" "\n", jsock->name, bytes); goto error; | |||
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)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 1974, ((void*)0), (SWITCH_LOG_WARNING), "%s Input Error\n" , jsock->name); goto error; | |||
1975 | } | |||
1976 | ||||
1977 | if (!switch_test_flag(jsock, JPFLAG_CHECK_ATTACH)((jsock)->flags & JPFLAG_CHECK_ATTACH) && switch_test_flag(jsock, JPFLAG_AUTHED)((jsock)->flags & JPFLAG_AUTHED)) { | |||
1978 | attach_calls(jsock); | |||
1979 | switch_set_flag(jsock, JPFLAG_CHECK_ATTACH)(jsock)->flags |= (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 | ||||
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 | ||||
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)switch_event_create_subclass_detailed("mod_verto.c", (const char * )(const char *)__func__, 2011, &jsock->params, SWITCH_EVENT_CHANNEL_DATA , ((void*)0)); | |||
2012 | switch_event_create(&jsock->vars, SWITCH_EVENT_CHANNEL_DATA)switch_event_create_subclass_detailed("mod_verto.c", (const char * )(const char *)__func__, 2012, &jsock->vars, SWITCH_EVENT_CHANNEL_DATA , ((void*)0)); | |||
2013 | switch_event_create(&jsock->user_vars, SWITCH_EVENT_CHANNEL_DATA)switch_event_create_subclass_detailed("mod_verto.c", (const char * )(const char *)__func__, 2013, &jsock->user_vars, SWITCH_EVENT_CHANNEL_DATA , ((void*)0)); | |||
2014 | ||||
2015 | ||||
2016 | add_jsock(jsock); | |||
2017 | ||||
2018 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 2018, ((void*)0), 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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 2023, ((void*)0), 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(ws_socket_t)-1) { | |||
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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 2045, ((void*)0), 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_event_create_subclass_detailed("mod_verto.c", (const char * )(const char *)__func__, 2046, &s_event, SWITCH_EVENT_CUSTOM , "verto::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)(jsock->uid ? jsock->uid : "")); | |||
2050 | switch_event_fire(&s_event)switch_event_fire_detailed("mod_verto.c", (const char * )(const char *)__func__, 2050, &s_event, ((void*)0)); | |||
2051 | } | |||
2052 | switch_thread_rwlock_wrlock(jsock->rwlock); | |||
2053 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 2053, ((void*)0), SWITCH_LOG_DEBUG, "%s Thread ended\n", jsock->name); | |||
2054 | switch_thread_rwlock_unlock(jsock->rwlock); | |||
2055 | ||||
2056 | return NULL((void*)0); | |||
2057 | } | |||
2058 | ||||
2059 | ||||
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((void*)0) }; | |||
2064 | int x = 0; | |||
2065 | char *dup_arg = NULL((void*)0); | |||
2066 | char *next = NULL((void*)0); | |||
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)switch_event_get_header_idx(jsock->allowed_fsapi, check_cmd , -1)) { | |||
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)if (dup_arg) {free(dup_arg);dup_arg=((void*)0);}; | |||
2087 | dup_arg = strdup(arg); | |||
2088 | switch_assert(dup_arg)((dup_arg) ? (void) (0) : __assert_fail ("dup_arg", "mod_verto.c" , 2088, __extension__ __PRETTY_FUNCTION__)); | |||
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)if (dup_arg) {free(dup_arg);dup_arg=((void*)0);}; | |||
2116 | return ok; | |||
2117 | ||||
2118 | } | |||
2119 | ||||
2120 | //// VERTO | |||
2121 | ||||
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)(tech_pvt)->flags |= (TFLAG_TRACKED); | |||
2128 | switch_thread_rwlock_unlock(verto_globals.tech_rwlock); | |||
2129 | } | |||
2130 | ||||
2131 | static void untrack_pvt(verto_pvt_t *tech_pvt) | |||
2132 | { | |||
2133 | verto_pvt_t *p, *last = NULL((void*)0); | |||
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)((tech_pvt)->flags & TFLAG_TRACKED)) { | |||
2145 | switch_clear_flag(tech_pvt, TFLAG_TRACKED)(tech_pvt)->flags &= ~(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((void*)0); | |||
2166 | ||||
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)if (verto_endpoint_interface) {switch_mutex_lock(verto_endpoint_interface ->reflock); verto_endpoint_interface->refs--; verto_endpoint_interface ->parent->refs--; switch_mutex_unlock(verto_endpoint_interface ->reflock); switch_thread_rwlock_unlock(verto_endpoint_interface ->rwlock); switch_thread_rwlock_unlock(verto_endpoint_interface ->parent->rwlock);}; | |||
2175 | return SWITCH_STATUS_SUCCESS; | |||
2176 | } | |||
2177 | ||||
2178 | static switch_status_t verto_on_hangup(switch_core_session_t *session) | |||
2179 | { | |||
2180 | jsock_t *jsock = NULL((void*)0); | |||
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((void*)0); | |||
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")switch_channel_set_variable_var_check(tech_pvt->channel, "verto_hangup_disposition" , "send_bye", SWITCH_TRUE); | |||
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 | ||||
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((void*)0); | |||
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((void*)0); | |||
2214 | cJSON *msg = NULL((void*)0); | |||
2215 | const char *var = NULL((void*)0); | |||
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)switch_channel_set_variable_var_check(tech_pvt->channel, "verto_user" , jsock->uid, SWITCH_TRUE); | |||
2222 | switch_channel_set_variable(tech_pvt->channel, "presence_id", jsock->uid)switch_channel_set_variable_var_check(tech_pvt->channel, "presence_id" , jsock->uid, SWITCH_TRUE); | |||
2223 | switch_channel_set_variable(tech_pvt->channel, "verto_client_address", jsock->name)switch_channel_set_variable_var_check(tech_pvt->channel, "verto_client_address" , jsock->name, SWITCH_TRUE); | |||
2224 | switch_channel_set_variable(tech_pvt->channel, "chat_proto", VERTO_CHAT_PROTO)switch_channel_set_variable_var_check(tech_pvt->channel, "chat_proto" , "verto", SWITCH_TRUE); | |||
2225 | switch_channel_set_variable(tech_pvt->channel, "verto_host", jsock->domain)switch_channel_set_variable_var_check(tech_pvt->channel, "verto_host" , jsock->domain, SWITCH_TRUE); | |||
2226 | ||||
2227 | for (hp = jsock->user_vars->headers; hp; hp = hp->next) { | |||
2228 | switch_channel_set_variable(tech_pvt->channel, hp->name, hp->value)switch_channel_set_variable_var_check(tech_pvt->channel, hp ->name, hp->value, SWITCH_TRUE); | |||
2229 | } | |||
2230 | ||||
2231 | if ((var = switch_event_get_header(jsock->params, "caller-id-name")switch_event_get_header_idx(jsock->params, "caller-id-name" , -1))) { | |||
2232 | caller_profile->callee_id_name = switch_core_strdup(caller_profile->pool, var)switch_core_perform_strdup(caller_profile->pool, var, "mod_verto.c" , (const char *)__func__, 2232); | |||
2233 | } | |||
2234 | ||||
2235 | if ((var = switch_event_get_header(jsock->params, "caller-id-number")switch_event_get_header_idx(jsock->params, "caller-id-number" , -1))) { | |||
2236 | caller_profile->callee_id_number = switch_core_strdup(caller_profile->pool, var)switch_core_perform_strdup(caller_profile->pool, var, "mod_verto.c" , (const char *)__func__, 2236); | |||
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")switch_channel_set_variable_var_check(tech_pvt->channel, "media_webrtc" , "true", SWITCH_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)switch_channel_set_variable_var_check(tech_pvt->channel, "verto_profile_name" , jsock->profile->name, SWITCH_TRUE); | |||
2253 | ||||
2254 | if (!switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING)) { | |||
2255 | switch_channel_set_variable(tech_pvt->channel, "codec_string", NULL)switch_channel_set_variable_var_check(tech_pvt->channel, "codec_string" , ((void*)0), SWITCH_TRUE); | |||
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((void*)0), 0, NULL((void*)0), 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_CHANNEL_ID_SESSION, "mod_verto.c", (const char *)__func__ , 2271, (const char*)(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 | ||||
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)((tech_pvt != ((void*)0)) ? (void) (0) : __assert_fail ("tech_pvt != ((void*)0)" , "mod_verto.c", 2294, __extension__ __PRETTY_FUNCTION__)); | |||
2295 | switch_assert(r_sdp != NULL)((r_sdp != ((void*)0)) ? (void) (0) : __assert_fail ("r_sdp != ((void*)0)" , "mod_verto.c", 2295, __extension__ __PRETTY_FUNCTION__)); | |||
2296 | ||||
2297 | if (zstr(r_sdp)_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 | ||||
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)(tech_pvt)->flags |= (TFLAG_ATTACH_REQ); | |||
2337 | break; | |||
2338 | } else if (status == SWITCH_STATUS_BREAK) { | |||
2339 | switch_yield(1000000)switch_sleep(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)switch_channel_perform_hangup(tech_pvt->channel, "mod_verto.c" , (const char *)__func__, 2348, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ); | |||
2349 | status = SWITCH_STATUS_FALSE; | |||
2350 | } | |||
2351 | ||||
2352 | switch_channel_set_flag(tech_pvt->channel, CF_VIDEO_BREAK)switch_channel_set_flag_value(tech_pvt->channel, CF_VIDEO_BREAK , 1); | |||
2353 | switch_core_session_kill_channel(tech_pvt->session, SWITCH_SIG_BREAK)switch_core_session_perform_kill_channel(tech_pvt->session , "mod_verto.c", (const char *)__func__, 2353, SWITCH_SIG_BREAK ); | |||
2354 | ||||
2355 | tries = 500; | |||
2356 | while(--tries > 0 && switch_test_flag(tech_pvt, TFLAG_ATTACH_REQ)((tech_pvt)->flags & TFLAG_ATTACH_REQ)) { | |||
2357 | switch_yield(10000)switch_sleep(10000);; | |||
2358 | } | |||
2359 | ||||
2360 | switch_core_session_request_video_refresh(session)_switch_core_session_request_video_refresh(session, 0, "mod_verto.c" , (const char *)__func__, 2360); | |||
2361 | switch_channel_set_flag(tech_pvt->channel, CF_VIDEO_BREAK)switch_channel_set_flag_value(tech_pvt->channel, CF_VIDEO_BREAK , 1); | |||
2362 | switch_core_session_kill_channel(tech_pvt->session, SWITCH_SIG_BREAK)switch_core_session_perform_kill_channel(tech_pvt->session , "mod_verto.c", (const char *)__func__, 2362, 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)switch_channel_perform_hangup(tech_pvt->channel, "mod_verto.c" , (const char *)__func__, 2369, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ); | |||
2370 | } else { | |||
2371 | switch_channel_mark_ring_ready(tech_pvt->channel)switch_channel_perform_mark_ring_ready_value(tech_pvt->channel , SWITCH_RING_READY_RINGING, "mod_verto.c", (const char *)__func__ , 2371); | |||
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((void*)0), | |||
2388 | /*.on_execute */ NULL((void*)0), | |||
2389 | /*.on_hangup */ verto_on_hangup, | |||
2390 | /*.on_exchange_media */ NULL((void*)0), | |||
2391 | /*.on_soft_execute */ NULL((void*)0), | |||
2392 | /*.on_consume_media */ NULL((void*)0), | |||
2393 | /*.on_hibernate */ NULL((void*)0), | |||
2394 | /*.on_reset */ NULL((void*)0), | |||
2395 | /*.on_park */ NULL((void*)0), | |||
2396 | /*.on_reporting */ NULL((void*)0), | |||
2397 | /*.on_destroy */ verto_on_destroy, | |||
2398 | SSH_FLAG_STICKY | |||
2399 | }; | |||
2400 | ||||
2401 | ||||
2402 | ||||
2403 | ||||
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])_zstr(profile->rtpip[profile->rtpip_cur])) { | |||
2411 | tech_pvt->mparams->rtpip4 = switch_core_session_strdup(tech_pvt->session, profile->rtpip[profile->rtpip_cur++])switch_core_perform_session_strdup(tech_pvt->session, profile ->rtpip[profile->rtpip_cur++], "mod_verto.c", (const char *)__func__, 2411); | |||
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])_zstr(profile->rtpip6[profile->rtpip_cur6])) { | |||
2419 | tech_pvt->mparams->rtpip6 = switch_core_session_strdup(tech_pvt->session, profile->rtpip6[profile->rtpip_cur6++])switch_core_perform_session_strdup(tech_pvt->session, profile ->rtpip6[profile->rtpip_cur6++], "mod_verto.c", (const char *)__func__, 2419); | |||
2420 | ||||
2421 | if (zstr(tech_pvt->mparams->rtpip)_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)_zstr(tech_pvt->mparams->rtpip)) { | |||
2432 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session)SWITCH_CHANNEL_ID_SESSION, "mod_verto.c", (const char *)__func__ , 2432, (const char*)(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)switch_channel_set_flag_value(tech_pvt->channel, CF_TRACKABLE , 1); | |||
2442 | switch_channel_set_variable(tech_pvt->channel, "secondary_recovery_module", modname)switch_channel_set_variable_var_check(tech_pvt->channel, "secondary_recovery_module" , modname, SWITCH_TRUE); | |||
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)switch_channel_set_cap_value(tech_pvt->channel, CC_BYPASS_MEDIA , 1); | |||
2448 | //switch_channel_set_cap(tech_pvt->channel, CC_PROXY_MEDIA); | |||
2449 | switch_channel_set_cap(tech_pvt->channel, CC_JITTERBUFFER)switch_channel_set_cap_value(tech_pvt->channel, CC_JITTERBUFFER , 1); | |||
2450 | switch_channel_set_cap(tech_pvt->channel, CC_FS_RTP)switch_channel_set_cap_value(tech_pvt->channel, CC_FS_RTP, 1); | |||
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)switch_core_perform_session_strdup(tech_pvt->session, profile ->inbound_codec_string, "mod_verto.c", (const char *)__func__ , 2455); | |||
2456 | tech_pvt->mparams->outbound_codec_string = switch_core_session_strdup(tech_pvt->session, profile->outbound_codec_string)switch_core_perform_session_strdup(tech_pvt->session, profile ->outbound_codec_string, "mod_verto.c", (const char *)__func__ , 2456); | |||
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)switch_core_perform_session_strdup(tech_pvt->session, profile ->local_network, "mod_verto.c", (const char *)__func__, 2467 ); | |||
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 | ||||
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")switch_channel_set_variable_var_check(tech_pvt->channel, "endpoint_disposition" , "CODEC NEGOTIATION ERROR", SWITCH_TRUE); | |||
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)switch_channel_perform_hangup(tech_pvt->channel, "mod_verto.c" , (const char *)__func__, 2507, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ); | |||
2508 | return status; | |||
2509 | } | |||
2510 | ||||
2511 | switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL((void*)0), 0, NULL((void*)0), 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)switch_channel_perform_hangup(tech_pvt->channel, "mod_verto.c" , (const char *)__func__, 2514, 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_CHANNEL_ID_SESSION, "mod_verto.c", (const char *)__func__ , 2518, (const char*)(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 | ||||
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((void*)0); | |||
2533 | ||||
2534 | if (switch_test_flag(tech_pvt, TFLAG_SENT_MEDIA)((tech_pvt)->flags & 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)switch_channel_get_variable_dup(tech_pvt->channel, "switch_m_sdp" , SWITCH_TRUE, -1))) { | |||
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((void*)0); | |||
2548 | ||||
2549 | if (!(jsock = get_jsock(tech_pvt->jsock_uuid))) { | |||
2550 | status = SWITCH_STATUS_FALSE; | |||
2551 | } else { | |||
2552 | cJSON *params = NULL((void*)0); | |||
2553 | cJSON *msg = jrpc_new_req(method, tech_pvt->call_id, ¶ms); | |||
2554 | if (!switch_test_flag(tech_pvt, TFLAG_SENT_MEDIA)((tech_pvt)->flags & 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)(tech_pvt)->flags |= (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)switch_channel_perform_hangup(tech_pvt->channel, "mod_verto.c" , (const char *)__func__, 2561, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ); | |||
2562 | } | |||
2563 | ||||
2564 | switch_thread_rwlock_unlock(jsock->rwlock); | |||
2565 | } | |||
2566 | } | |||
2567 | ||||
2568 | return status; | |||
2569 | } | |||
2570 | ||||
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((void*)0), *params = NULL((void*)0); | |||
2581 | jsock_t *jsock = NULL((void*)0); | |||
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)switch_channel_set_variable_var_check(tech_pvt->channel, "last_sent_display_name" , name, SWITCH_TRUE); | |||
2591 | switch_channel_set_variable(tech_pvt->channel, "last_sent_display_number", number)switch_channel_set_variable_var_check(tech_pvt->channel, "last_sent_display_number" , number, SWITCH_TRUE); | |||
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((void*)0); | |||
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 | ||||
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((void*)0); | |||
2635 | verto_profile_t *profile = NULL((void*)0); | |||
2636 | const char *profile_name = NULL((void*)0), *jsock_uuid_str = NULL((void*)0); | |||
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)if (verto_endpoint_interface) {switch_thread_rwlock_rdlock(verto_endpoint_interface ->parent->rwlock); switch_thread_rwlock_rdlock(verto_endpoint_interface ->rwlock); switch_mutex_lock(verto_endpoint_interface-> reflock); verto_endpoint_interface->refs++; verto_endpoint_interface ->parent->refs++; switch_mutex_unlock(verto_endpoint_interface ->reflock);}; | |||
2644 | ||||
2645 | profile_name = switch_channel_get_variable(channel, "verto_profile_name")switch_channel_get_variable_dup(channel, "verto_profile_name" , SWITCH_TRUE, -1); | |||
2646 | jsock_uuid_str = switch_channel_get_variable(channel, "jsock_uuid_str")switch_channel_get_variable_dup(channel, "jsock_uuid_str", SWITCH_TRUE , -1); | |||
2647 | ||||
2648 | if (!(profile_name && jsock_uuid_str && (profile = find_profile(profile_name)))) { | |||
2649 | UNPROTECT_INTERFACE(verto_endpoint_interface)if (verto_endpoint_interface) {switch_mutex_lock(verto_endpoint_interface ->reflock); verto_endpoint_interface->refs--; verto_endpoint_interface ->parent->refs--; switch_mutex_unlock(verto_endpoint_interface ->reflock); switch_thread_rwlock_unlock(verto_endpoint_interface ->rwlock); switch_thread_rwlock_unlock(verto_endpoint_interface ->parent->rwlock);}; | |||
2650 | return 0; | |||
2651 | } | |||
2652 | ||||
2653 | tech_pvt = switch_core_session_alloc(session, sizeof(*tech_pvt))switch_core_perform_session_alloc(session, sizeof(*tech_pvt), "mod_verto.c", (const char *)__func__, 2653); | |||
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))switch_core_perform_session_strdup(session, switch_core_session_get_uuid (session), "mod_verto.c", (const char *)__func__, 2661); | |||
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)if (verto_endpoint_interface) {switch_mutex_lock(verto_endpoint_interface ->reflock); verto_endpoint_interface->refs--; verto_endpoint_interface ->parent->refs--; switch_mutex_unlock(verto_endpoint_interface ->reflock); switch_thread_rwlock_unlock(verto_endpoint_interface ->rwlock); switch_thread_rwlock_unlock(verto_endpoint_interface ->parent->rwlock);}; | |||
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 | ||||
2690 | static void pass_sdp(verto_pvt_t *tech_pvt) | |||
2691 | { | |||
2692 | switch_core_session_t *other_session = NULL((void*)0); | |||
2693 | switch_channel_t *other_channel = NULL((void*)0); | |||
2694 | ||||
2695 | if (switch_core_session_get_partner(tech_pvt->session, &other_session)switch_core_session_perform_get_partner(tech_pvt->session, &other_session, "mod_verto.c", (const char *)__func__, 2695 ) == 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)switch_channel_set_flag_value(other_channel, CF_PROXY_MODE, 1 ); | |||
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 zstr(_A)_zstr(_A) ? _B : _A | |||
2709 | ||||
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((void*)0); | |||
2715 | const char *call_id = NULL((void*)0), *sdp = NULL((void*)0); | |||
2716 | int err = 0; | |||
2717 | const char *callee_id_name = NULL((void*)0), *callee_id_number = NULL((void*)0); | |||
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)switch_core_session_perform_locate(call_id, "mod_verto.c", (const char *)__func__, 2745))) { | |||
2746 | verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY); | |||
2747 | switch_core_session_t *other_session = NULL((void*)0); | |||
2748 | ||||
2749 | tech_pvt->r_sdp = switch_core_session_strdup(session, sdp)switch_core_perform_session_strdup(session, sdp, "mod_verto.c" , (const char *)__func__, 2749); | |||
2750 | switch_channel_set_variable(tech_pvt->channel, SWITCH_R_SDP_VARIABLE, sdp)switch_channel_set_variable_var_check(tech_pvt->channel, "switch_r_sdp" , sdp, SWITCH_TRUE); | |||
2751 | switch_channel_set_variable(tech_pvt->channel, "verto_client_address", jsock->name)switch_channel_set_variable_var_check(tech_pvt->channel, "verto_client_address" , jsock->name, SWITCH_TRUE); | |||
2752 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_verto.c", (const char *)__func__ , 2752, (const char*)(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_core_session_perform_get_partner(tech_pvt->session, &other_session, "mod_verto.c", (const char *)__func__, 2757 ) == 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)switch_channel_set_variable_var_check(other_channel, "switch_m_sdp" , sdp, SWITCH_TRUE); | |||
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")switch_channel_set_variable_var_check(tech_pvt->channel, "endpoint_disposition" , "CODEC NEGOTIATION ERROR", SWITCH_TRUE); | |||
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)switch_channel_perform_hangup(tech_pvt->channel, "mod_verto.c" , (const char *)__func__, 2773, 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)switch_channel_perform_mark_answered(tech_pvt->channel, "mod_verto.c" , (const char *)__func__, 2786); | |||
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-32002)); | |||
2802 | ||||
2803 | ||||
2804 | return SWITCH_FALSE; | |||
2805 | ||||
2806 | } | |||
2807 | ||||
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((void*)0); | |||
2811 | switch_core_session_t *session; | |||
2812 | cJSON *dialog = NULL((void*)0); | |||
2813 | const char *call_id = NULL((void*)0), *cause_str = NULL((void*)0); | |||
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((void*)0); | |||
2846 | ||||
2847 | if (!zstr(causeObj->valuestring)_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)_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)switch_core_session_perform_locate(call_id, "mod_verto.c", (const char *)__func__, 2862))) { | |||
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")switch_channel_set_variable_var_check(tech_pvt->channel, "verto_hangup_disposition" , "recv_bye", SWITCH_TRUE); | |||
2866 | switch_channel_hangup(tech_pvt->channel, cause)switch_channel_perform_hangup(tech_pvt->channel, "mod_verto.c" , (const char *)__func__, 2866, 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-32002)); | |||
2884 | ||||
2885 | ||||
2886 | return SWITCH_FALSE; | |||
2887 | } | |||
2888 | ||||
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")switch_channel_get_variable_dup(channel, "att_xfer_kill_uuid" , SWITCH_TRUE, -1); | |||
2897 | ||||
2898 | if (uuid && (ksession = switch_core_session_force_locate(uuid)switch_core_session_perform_force_locate(uuid, "mod_verto.c", (const char *)__func__, 2898))) { | |||
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)(switch_channel_check_signal(kchannel, SWITCH_TRUE) || switch_channel_get_state (kchannel) < CS_HANGUP)) { | |||
2904 | switch_channel_hangup(kchannel, SWITCH_CAUSE_NORMAL_CLEARING)switch_channel_perform_hangup(kchannel, "mod_verto.c", (const char *)__func__, 2904, 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 | ||||
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)switch_core_session_perform_locate(br_b, "mod_verto.c", (const char *)__func__, 2928)) ) { | |||
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((void*)0)), | |||
2943 | cp->uuid_str, | |||
2944 | switch_channel_get_variable(channel, uvar1)switch_channel_get_variable_dup(channel, uvar1, SWITCH_TRUE, - 1), | |||
2945 | switch_channel_get_variable(channel, dvar1)switch_channel_get_variable_dup(channel, dvar1, SWITCH_TRUE, - 1), | |||
2946 | switch_channel_get_variable(br_b_channel, uvar2)switch_channel_get_variable_dup(br_b_channel, uvar2, SWITCH_TRUE , -1), | |||
2947 | switch_channel_get_variable(br_b_channel, dvar2)switch_channel_get_variable_dup(br_b_channel, dvar2, SWITCH_TRUE , -1)); | |||
2948 | ||||
2949 | switch_channel_add_variable_var_check(br_b_channel, SWITCH_TRANSFER_HISTORY_VARIABLE"transfer_history", cp->transfer_source, SWITCH_FALSE, SWITCH_STACK_PUSH); | |||
2950 | switch_channel_set_variable(br_b_channel, SWITCH_TRANSFER_SOURCE_VARIABLE, cp->transfer_source)switch_channel_set_variable_var_check(br_b_channel, "transfer_source" , cp->transfer_source, SWITCH_TRUE); | |||
2951 | ||||
2952 | switch_core_session_rwunlock(br_b_session); | |||
2953 | } | |||
2954 | ||||
2955 | ||||
2956 | ||||
2957 | if ((br_a_session = switch_core_session_locate(br_a)switch_core_session_perform_locate(br_a, "mod_verto.c", (const char *)__func__, 2957)) ) { | |||
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((void*)0)), | |||
2972 | cp->uuid_str, | |||
2973 | switch_channel_get_variable(channel, uvar1)switch_channel_get_variable_dup(channel, uvar1, SWITCH_TRUE, - 1), | |||
2974 | switch_channel_get_variable(channel, dvar1)switch_channel_get_variable_dup(channel, dvar1, SWITCH_TRUE, - 1), | |||
2975 | switch_channel_get_variable(br_a_channel, uvar2)switch_channel_get_variable_dup(br_a_channel, uvar2, SWITCH_TRUE , -1), | |||
2976 | switch_channel_get_variable(br_a_channel, dvar2)switch_channel_get_variable_dup(br_a_channel, dvar2, SWITCH_TRUE , -1)); | |||
2977 | ||||
2978 | switch_channel_add_variable_var_check(br_a_channel, SWITCH_TRANSFER_HISTORY_VARIABLE"transfer_history", cp->transfer_source, SWITCH_FALSE, SWITCH_STACK_PUSH); | |||
2979 | switch_channel_set_variable(br_a_channel, SWITCH_TRANSFER_SOURCE_VARIABLE, cp->transfer_source)switch_channel_set_variable_var_check(br_a_channel, "transfer_source" , cp->transfer_source, SWITCH_TRUE); | |||
2980 | ||||
2981 | switch_core_session_rwunlock(br_a_session); | |||
2982 | } | |||
2983 | ||||
2984 | ||||
2985 | } | |||
2986 | ||||
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((void*)0), *b_tech_pvt = NULL((void*)0); | |||
2989 | switch_bool_t result = SWITCH_FALSE; | |||
2990 | const char *br_a = NULL((void*)0), *br_b = NULL((void*)0); | |||
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))switch_channel_set_variable_var_check(tech_pvt->channel, "refer_uuid" , switch_core_session_get_uuid(b_tech_pvt->session), SWITCH_TRUE ); | |||
2997 | switch_channel_set_variable(tech_pvt->channel, "transfer_disposition", "recv_replace")switch_channel_set_variable_var_check(tech_pvt->channel, "transfer_disposition" , "recv_replace", SWITCH_TRUE); | |||
2998 | switch_channel_set_variable(b_tech_pvt->channel, "transfer_disposition", "replaced")switch_channel_set_variable_var_check(b_tech_pvt->channel, "transfer_disposition", "replaced", SWITCH_TRUE); | |||
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((void*)0); | |||
3005 | } | |||
3006 | ||||
3007 | if (!switch_ivr_uuid_exists(br_b)) { | |||
3008 | br_b = NULL((void*)0); | |||
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_CHANNEL_ID_SESSION, "mod_verto.c", (const char *)__func__ , 3015, (const char*)(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")switch_channel_set_variable_var_check(b_tech_pvt->channel, "endpoint_disposition", "ATTENDED_TRANSFER", SWITCH_TRUE); | |||
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)switch_channel_set_variable_var_check(b_tech_pvt->channel, "holding_uuid", br_a, SWITCH_TRUE); | |||
3027 | switch_channel_set_flag(b_tech_pvt->channel, CF_XFER_ZOMBIE)switch_channel_set_flag_value(b_tech_pvt->channel, CF_XFER_ZOMBIE , 1); | |||
3028 | switch_channel_set_flag(b_tech_pvt->channel, CF_TRANSFER)switch_channel_set_flag_value(b_tech_pvt->channel, CF_TRANSFER , 1); | |||
3029 | ||||
3030 | ||||
3031 | if ((a_session = switch_core_session_locate(br_a)switch_core_session_perform_locate(br_a, "mod_verto.c", (const char *)__func__, 3031))) { | |||
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))switch_channel_set_variable_var_check(a_channel, "att_xfer_kill_uuid" , switch_core_session_get_uuid(b_session), SWITCH_TRUE); | |||
3039 | switch_channel_set_variable(a_channel, "att_xfer_destination_number", prof->destination_number)switch_channel_set_variable_var_check(a_channel, "att_xfer_destination_number" , prof->destination_number, SWITCH_TRUE); | |||
3040 | switch_channel_set_variable(a_channel, "att_xfer_callee_id_name", prof->callee_id_name)switch_channel_set_variable_var_check(a_channel, "att_xfer_callee_id_name" , prof->callee_id_name, SWITCH_TRUE); | |||
3041 | switch_channel_set_variable(a_channel, "att_xfer_callee_id_number", prof->callee_id_number)switch_channel_set_variable_var_check(a_channel, "att_xfer_callee_id_number" , prof->callee_id_number, SWITCH_TRUE); | |||
3042 | ||||
3043 | if ((tmp = switch_channel_get_hold_music(a_channel))) { | |||
3044 | moh = tmp; | |||
3045 | } | |||
3046 | ||||
3047 | if (!zstr(moh)_zstr(moh) && !strcasecmp(moh, "silence")) { | |||
3048 | moh = NULL((void*)0); | |||
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((void*)0)); | |||
3055 | } else { | |||
3056 | switch_ivr_session_transfer(a_session, "park", "inline", NULL((void*)0)); | |||
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)switch_channel_perform_hangup(b_tech_pvt->channel, "mod_verto.c" , (const char *)__func__, 3063, 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((void*)0); | |||
3070 | ||||
3071 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_verto.c", (const char *)__func__ , 3071, (const char*)(session), SWITCH_LOG_NOTICE, "Attended Transfer [%s][%s]\n", | |||
3072 | switch_str_nil(br_a)(br_a ? br_a : ""), switch_str_nil(br_b)(br_b ? br_b : "")); | |||
3073 | ||||
3074 | if ((tmp = switch_core_session_locate(br_b)switch_core_session_perform_locate(br_b, "mod_verto.c", (const char *)__func__, 3074))) { | |||
3075 | switch_channel_t *tchannel = switch_core_session_get_channel(tmp); | |||
3076 | ||||
3077 | switch_channel_set_variable(tchannel, "transfer_disposition", "bridge")switch_channel_set_variable_var_check(tchannel, "transfer_disposition" , "bridge", SWITCH_TRUE); | |||
3078 | ||||
3079 | switch_channel_set_flag(tchannel, CF_ATTENDED_TRANSFER)switch_channel_set_flag_value(tchannel, CF_ATTENDED_TRANSFER, 1); | |||
3080 | switch_core_session_rwunlock(tmp); | |||
3081 | } | |||
3082 | ||||
3083 | if (switch_true(switch_channel_get_variable(tech_pvt->channel, "recording_follow_transfer")switch_channel_get_variable_dup(tech_pvt->channel, "recording_follow_transfer" , SWITCH_TRUE, -1)) && | |||
3084 | (tmp = switch_core_session_locate(br_a)switch_core_session_perform_locate(br_a, "mod_verto.c", (const char *)__func__, 3084))) { | |||
3085 | switch_channel_set_variable(switch_core_session_get_channel(tmp), "transfer_disposition", "bridge")switch_channel_set_variable_var_check(switch_core_session_get_channel (tmp), "transfer_disposition", "bridge", SWITCH_TRUE); | |||
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")switch_channel_get_variable_dup(b_tech_pvt->channel, "recording_follow_transfer" , SWITCH_TRUE, -1)) && | |||
3092 | (tmp = switch_core_session_locate(br_b)switch_core_session_perform_locate(br_b, "mod_verto.c", (const char *)__func__, 3092))) { | |||
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")switch_channel_set_variable_var_check(b_tech_pvt->channel, "endpoint_disposition", "ATTENDED_TRANSFER", SWITCH_TRUE); | |||
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")switch_channel_set_variable_var_check(b_tech_pvt->channel, "park_timeout", "2:attended_transfer", SWITCH_TRUE); | |||
3108 | switch_channel_set_state(b_tech_pvt->channel, CS_PARK)switch_channel_perform_set_state(b_tech_pvt->channel, "mod_verto.c" , (const char *)__func__, 3108, CS_PARK); | |||
3109 | ||||
3110 | } else { | |||
3111 | if (!br_a && !br_b) { | |||
3112 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_verto.c", (const char *)__func__ , 3112, (const char*)(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)switch_core_session_perform_locate(br_a, "mod_verto.c", (const char *)__func__, 3121); | |||
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)switch_core_session_perform_locate(br_b, "mod_verto.c", (const char *)__func__, 3126); | |||
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)switch_channel_perform_hangup(b_tech_pvt->channel, "mod_verto.c" , (const char *)__func__, 3130, 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")switch_channel_get_variable_dup(hup_channel, "inline_destination" , SWITCH_TRUE, -1); | |||
3136 | ext = switch_channel_get_variable(hup_channel, "destination_number")switch_channel_get_variable_dup(hup_channel, "destination_number" , SWITCH_TRUE, -1); | |||
3137 | ||||
3138 | if (switch_true(switch_channel_get_variable(hup_channel, "recording_follow_transfer")switch_channel_get_variable_dup(hup_channel, "recording_follow_transfer" , SWITCH_TRUE, -1))) { | |||
3139 | switch_ivr_transfer_recordings(hup_session, t_session); | |||
3140 | } | |||
3141 | ||||
3142 | if (idest) { | |||
3143 | switch_ivr_session_transfer(t_session, idest, "inline", NULL((void*)0)); | |||
3144 | } else { | |||
3145 | switch_ivr_session_transfer(t_session, ext, NULL((void*)0), NULL((void*)0)); | |||
3146 | } | |||
3147 | ||||
3148 | result = SWITCH_TRUE; | |||
3149 | switch_channel_hangup(hup_channel, SWITCH_CAUSE_ATTENDED_TRANSFER)switch_channel_perform_hangup(hup_channel, "mod_verto.c", (const char *)__func__, 3149, 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 | ||||
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((void*)0); | |||
3166 | const char *call_id = NULL((void*)0), *destination = NULL((void*)0), *action = NULL((void*)0); | |||
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)switch_core_session_perform_locate(call_id, "mod_verto.c", (const char *)__func__, 3195))) { | |||
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((void*)0); | |||
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_core_session_perform_get_partner(tech_pvt->session, &other_session, "mod_verto.c", (const char *)__func__, 3206 ) == SWITCH_STATUS_SUCCESS) { | |||
3207 | switch_ivr_session_transfer(other_session, destination, NULL((void*)0), NULL((void*)0)); | |||
3208 | cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CALL TRANSFERRED")); | |||
3209 | switch_channel_set_variable(tech_pvt->channel, "transfer_disposition", "recv_replace")switch_channel_set_variable_var_check(tech_pvt->channel, "transfer_disposition" , "recv_replace", SWITCH_TRUE); | |||
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((void*)0); | |||
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)switch_core_session_perform_locate(replace_call_id, "mod_verto.c" , (const char *)__func__, 3225))) { | |||
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-32002)); | |||
3261 | ||||
3262 | ||||
3263 | return SWITCH_FALSE; | |||
3264 | } | |||
3265 | ||||
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((void*)0); | |||
3270 | int err = 0; | |||
3271 | cJSON *dialog; | |||
3272 | verto_pvt_t *tech_pvt = NULL((void*)0); | |||
3273 | const char *call_id = NULL((void*)0), *sdp = NULL((void*)0); | |||
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)switch_core_session_perform_locate(call_id, "mod_verto.c", (const char *)__func__, 3298))) { | |||
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)switch_core_perform_session_strdup(session, sdp, "mod_verto.c" , (const char *)__func__, 3304); | |||
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)switch_channel_perform_hangup(tech_pvt->channel, "mod_verto.c" , (const char *)__func__, 3308, 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)switch_channel_set_variable_var_check(tech_pvt->channel, "switch_r_sdp" , tech_pvt->r_sdp, SWITCH_TRUE); | |||
3315 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_verto.c", (const char *)__func__ , 3315, (const char*)(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)switch_channel_set_flag_value(tech_pvt->channel, CF_REINVITE , 1); | |||
3320 | switch_channel_set_flag(tech_pvt->channel, CF_RECOVERING)switch_channel_set_flag_value(tech_pvt->channel, CF_RECOVERING , 1); | |||
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")switch_channel_set_variable_var_check(tech_pvt->channel, "endpoint_disposition" , "MEDIA ERROR", SWITCH_TRUE); | |||
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")switch_channel_set_variable_var_check(tech_pvt->channel, "endpoint_disposition" , "CODEC NEGOTIATION ERROR", SWITCH_TRUE); | |||
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)(tech_pvt)->flags &= ~(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)switch_channel_set_flag_value(tech_pvt->channel, CF_CONFERENCE_ADV , 1); | |||
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)switch_channel_perform_hangup(tech_pvt->channel, "mod_verto.c" , (const char *)__func__, 3358, SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL ); | |||
3359 | } | |||
3360 | ||||
3361 | ||||
3362 | cJSON_AddItemToObject(obj, "code", cJSON_CreateNumber(CODE_SESSION_ERROR-32002)); | |||
3363 | ||||
3364 | return SWITCH_FALSE; | |||
3365 | } | |||
3366 | ||||
3367 | static void parse_user_vars(cJSON *obj, switch_core_session_t *session) | |||
3368 | { | |||
3369 | cJSON *json_ptr; | |||
3370 | ||||
3371 | switch_assert(obj)((obj) ? (void) (0) : __assert_fail ("obj", "mod_verto.c", 3371 , __extension__ __PRETTY_FUNCTION__)); | |||
3372 | switch_assert(session)((session) ? (void) (0) : __assert_fail ("session", "mod_verto.c" , 3372, __extension__ __PRETTY_FUNCTION__)); | |||
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(1 << 1)) { | |||
3382 | switch_channel_set_variable(channel, varname, "true")switch_channel_set_variable_var_check(channel, varname, "true" , SWITCH_TRUE); | |||
3383 | } else if (i->type == cJSON_False(1 << 0)) { | |||
3384 | switch_channel_set_variable(channel, varname, "false")switch_channel_set_variable_var_check(channel, varname, "false" , SWITCH_TRUE); | |||
3385 | } else if (!zstr(i->string)_zstr(i->string) && !zstr(i->valuestring)_zstr(i->valuestring)) { | |||
3386 | switch_channel_set_variable(channel, varname, i->valuestring)switch_channel_set_variable_var_check(channel, varname, i-> valuestring, SWITCH_TRUE); | |||
3387 | } | |||
3388 | } | |||
3389 | } | |||
3390 | } | |||
3391 | ||||
3392 | static switch_bool_t verto__info_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response) | |||
3393 | { | |||
3394 | cJSON *msg = NULL((void*)0), *dialog = NULL((void*)0), *txt = NULL((void*)0); | |||
3395 | const char *call_id = NULL((void*)0), *dtmf = NULL((void*)0); | |||
3396 | switch_bool_t r = SWITCH_TRUE; | |||
3397 | char *proto = VERTO_CHAT_PROTO"verto"; | |||
3398 | char *pproto = NULL((void*)0); | |||
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((void*)0); | |||
3410 | ||||
3411 | if ((session = switch_core_session_locate(call_id)switch_core_session_perform_locate(call_id, "mod_verto.c", (const char *)__func__, 3411))) { | |||
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((void*)0); | |||
3428 | ||||
3429 | if (switch_core_session_get_partner(tech_pvt->session, &other_session)switch_core_session_perform_get_partner(tech_pvt->session, &other_session, "mod_verto.c", (const char *)__func__, 3429 ) == 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)switch_core_session_perform_locate(call_id, "mod_verto.c", (const char *)__func__, 3447))) { | |||
3448 | verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY); | |||
3449 | char charbuf[2] = ""; | |||
3450 | char *chardata = NULL((void*)0); | |||
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(1 << 1) || (indialog->type == cJSON_String(1 << 4) && switch_true(indialog->valuestring))); | |||
3491 | ||||
3492 | if (!zstr(to)_zstr(to)) { | |||
3493 | if (strchr(to, '+')) { | |||
3494 | pproto = strdup(to); | |||
3495 | switch_assert(pproto)((pproto) ? (void) (0) : __assert_fail ("pproto", "mod_verto.c" , 3495, __extension__ __PRETTY_FUNCTION__)); | |||
3496 | if ((to = strchr(pproto, '+'))) { | |||
3497 | *to++ = '\0'; | |||
3498 | } | |||
3499 | proto = pproto; | |||
3500 | } | |||
3501 | } | |||
3502 | ||||
3503 | if (!zstr(to)_zstr(to) && !zstr(body)_zstr(body) && switch_event_create(&event, SWITCH_EVENT_MESSAGE)switch_event_create_subclass_detailed("mod_verto.c", (const char * )(const char *)__func__, 3503, &event, SWITCH_EVENT_MESSAGE , ((void*)0)) == SWITCH_STATUS_SUCCESS) { | |||
3504 | switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", VERTO_CHAT_PROTO"verto"); | |||
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->string) && !zstr(i->valuestring)_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"verto")) { | |||
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((void*)0); | |||
3536 | ||||
3537 | if ((session = switch_core_session_locate(call_id)switch_core_session_perform_locate(call_id, "mod_verto.c", (const char *)__func__, 3537))) { | |||
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)if (pproto) {free(pproto);pproto=((void*)0);}; | |||
3561 | } | |||
3562 | ||||
3563 | cleanup: | |||
3564 | ||||
3565 | if (!err) return r; | |||
3566 | ||||
3567 | cJSON_AddItemToObject(*response, "code", cJSON_CreateNumber(CODE_SESSION_ERROR-32002)); | |||
3568 | ||||
3569 | return SWITCH_FALSE; | |||
3570 | } | |||
3571 | ||||
3572 | ||||
3573 | ||||
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((void*)0), *dedEnc = NULL((void*)0), *mirrorInput, *bandwidth = NULL((void*)0), *canvas = NULL((void*)0); | |||
3577 | switch_core_session_t *session = NULL((void*)0); | |||
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((void*)0), *sdp = NULL((void*)0), | |||
3587 | *caller_id_name = NULL((void*)0), *caller_id_number = NULL((void*)0), *remote_caller_id_name = NULL((void*)0), *remote_caller_id_number = NULL((void*)0),*context = NULL((void*)0); | |||
3588 | switch_event_header_t *hp; | |||
3589 | ||||
3590 | *response = obj; | |||
3591 | ||||
3592 | PROTECT_INTERFACE(verto_endpoint_interface)if (verto_endpoint_interface) {switch_thread_rwlock_rdlock(verto_endpoint_interface ->parent->rwlock); switch_thread_rwlock_rdlock(verto_endpoint_interface ->rwlock); switch_mutex_lock(verto_endpoint_interface-> reflock); verto_endpoint_interface->refs++; verto_endpoint_interface ->parent->refs++; switch_mutex_unlock(verto_endpoint_interface ->reflock);}; | |||
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((void*)0), var_event, "rtc", | |||
3621 | NULL((void*)0), &session, NULL((void*)0), 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))switch_core_perform_session_alloc(session, sizeof(*tech_pvt), "mod_verto.c", (const char *)__func__, 3629); | |||
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)switch_core_perform_session_strdup(session, jsock->uuid_str , "mod_verto.c", (const char *)__func__, 3633); | |||
3634 | tech_pvt->r_sdp = switch_core_session_strdup(session, sdp)switch_core_perform_session_strdup(session, sdp, "mod_verto.c" , (const char *)__func__, 3634); | |||
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)switch_core_perform_session_strdup(session, call_id, "mod_verto.c" , (const char *)__func__, 3638); | |||
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(1 << 1)) { | |||
3659 | switch_channel_set_variable(channel, "video_screen_share", "true")switch_channel_set_variable_var_check(channel, "video_screen_share" , "true", SWITCH_TRUE); | |||
3660 | switch_channel_set_flag(channel, CF_VIDEO_ONLY)switch_channel_set_flag_value(channel, CF_VIDEO_ONLY, 1); | |||
3661 | } | |||
3662 | ||||
3663 | if ((dedEnc = cJSON_GetObjectItem(dialog, "dedEnc")) && dedEnc->type == cJSON_True(1 << 1)) { | |||
3664 | switch_channel_set_variable(channel, "video_use_dedicated_encoder", "true")switch_channel_set_variable_var_check(channel, "video_use_dedicated_encoder" , "true", SWITCH_TRUE); | |||
3665 | } | |||
3666 | ||||
3667 | if ((mirrorInput = cJSON_GetObjectItem(dialog, "mirrorInput")) && mirrorInput->type == cJSON_True(1 << 1)) { | |||
3668 | switch_channel_set_variable(channel, "video_mirror_input", "true")switch_channel_set_variable_var_check(channel, "video_mirror_input" , "true", SWITCH_TRUE); | |||
3669 | switch_channel_set_flag(channel, CF_VIDEO_MIRROR_INPUT)switch_channel_set_flag_value(channel, CF_VIDEO_MIRROR_INPUT, 1); | |||
3670 | } | |||
3671 | ||||
3672 | if ((canvas = cJSON_GetObjectItem(dialog, "conferenceCanvasID"))) { | |||
3673 | int canvas_id = 0; | |||
3674 | ||||
3675 | if (!zstr(canvas->valuestring)_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")switch_channel_set_variable_var_check(channel, "video_second_screen" , "true", SWITCH_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)_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)_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)switch_channel_set_variable_var_check(channel, "jsock_uuid_str" , jsock->uuid_str, SWITCH_TRUE); | |||
3733 | switch_channel_set_variable(channel, "verto_user", jsock->uid)switch_channel_set_variable_var_check(channel, "verto_user", jsock ->uid, SWITCH_TRUE); | |||
3734 | switch_channel_set_variable(channel, "presence_id", jsock->uid)switch_channel_set_variable_var_check(channel, "presence_id", jsock->uid, SWITCH_TRUE); | |||
3735 | switch_channel_set_variable(channel, "verto_client_address", jsock->name)switch_channel_set_variable_var_check(channel, "verto_client_address" , jsock->name, SWITCH_TRUE); | |||
3736 | switch_channel_set_variable(channel, "chat_proto", VERTO_CHAT_PROTO)switch_channel_set_variable_var_check(channel, "chat_proto", "verto" , SWITCH_TRUE); | |||
3737 | switch_channel_set_variable(channel, "verto_host", jsock->domain)switch_channel_set_variable_var_check(channel, "verto_host", jsock ->domain, SWITCH_TRUE); | |||
3738 | switch_channel_set_variable(channel, "event_channel_cookie", tech_pvt->jsock_uuid)switch_channel_set_variable_var_check(channel, "event_channel_cookie" , tech_pvt->jsock_uuid, SWITCH_TRUE); | |||
3739 | switch_channel_set_variable(channel, "verto_profile_name", jsock->profile->name)switch_channel_set_variable_var_check(channel, "verto_profile_name" , jsock->profile->name, SWITCH_TRUE); | |||
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)_zstr(caller_id_name)) { | |||
3748 | if ((var = switch_event_get_header(jsock->params, "caller-id-name")switch_event_get_header_idx(jsock->params, "caller-id-name" , -1))) { | |||
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)_zstr(caller_id_number)) { | |||
3756 | if ((var = switch_event_get_header(jsock->params, "caller-id-number")switch_event_get_header_idx(jsock->params, "caller-id-number" , -1))) { | |||
3757 | caller_id_number = var; | |||
3758 | } | |||
3759 | } | |||
3760 | ||||
3761 | if (!(context = switch_event_get_header(jsock->vars, "user_context")switch_event_get_header_idx(jsock->vars, "user_context", - 1))) { | |||
3762 | context = switch_either(jsock->context, jsock->profile->context)_zstr(jsock->context) ? jsock->profile->context : jsock ->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)_zstr(jsock->dialplan) ? jsock->profile->dialplan : jsock ->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)switch_channel_set_variable_var_check(channel, hp->name, hp ->value, SWITCH_TRUE); | |||
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)switch_channel_set_variable_var_check(channel, "verto_remote_caller_id_name" , remote_caller_id_name, SWITCH_TRUE); | |||
3794 | switch_channel_set_variable(channel, "verto_remote_caller_id_number", remote_caller_id_number)switch_channel_set_variable_var_check(channel, "verto_remote_caller_id_number" , remote_caller_id_number, SWITCH_TRUE); | |||
3795 | ||||
3796 | ||||
3797 | ||||
3798 | switch_channel_set_variable(channel, SWITCH_R_SDP_VARIABLE, sdp)switch_channel_set_variable_var_check(channel, "switch_r_sdp" , sdp, SWITCH_TRUE); | |||
3799 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_verto.c", (const char *)__func__ , 3799, (const char*)(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)switch_channel_perform_set_state(channel, "mod_verto.c", (const char *)__func__, 3806, 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)if (verto_endpoint_interface) {switch_mutex_lock(verto_endpoint_interface ->reflock); verto_endpoint_interface->refs--; verto_endpoint_interface ->parent->refs--; switch_mutex_unlock(verto_endpoint_interface ->reflock); switch_thread_rwlock_unlock(verto_endpoint_interface ->rwlock); switch_thread_rwlock_unlock(verto_endpoint_interface ->parent->rwlock);}; | |||
3819 | ||||
3820 | if (session) { | |||
3821 | switch_core_session_destroy(&session)switch_core_session_perform_destroy(&session, "mod_verto.c" , (const char *)__func__, 3821); | |||
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-32002)); | |||
3828 | ||||
3829 | return SWITCH_FALSE; | |||
3830 | ||||
3831 | } | |||
3832 | ||||
3833 | static switch_bool_t event_channel_check_auth(jsock_t *jsock, const char *event_channel) | |||
3834 | { | |||
3835 | ||||
3836 | char *main_event_channel = NULL((void*)0); | |||
3837 | switch_bool_t ok = SWITCH_TRUE, pre_ok = SWITCH_FALSE; | |||
3838 | switch_core_session_t *session = NULL((void*)0); | |||
3839 | ||||
3840 | switch_assert(event_channel)((event_channel) ? (void) (0) : __assert_fail ("event_channel" , "mod_verto.c", 3840, __extension__ __PRETTY_FUNCTION__)); | |||
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)switch_core_session_perform_locate(event_channel, "mod_verto.c" , (const char *)__func__, 3844))) { | |||
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")switch_channel_get_variable_dup(channel, "jsock_uuid_str", SWITCH_TRUE , -1); | |||
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)((main_event_channel) ? (void) (0) : __assert_fail ("main_event_channel" , "mod_verto.c", 3863, __extension__ __PRETTY_FUNCTION__)); | |||
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)switch_event_get_header_idx(jsock->allowed_event_channels, event_channel, -1) || | |||
3871 | (main_event_channel && switch_event_get_header(jsock->allowed_event_channels, main_event_channel)switch_event_get_header_idx(jsock->allowed_event_channels, main_event_channel, -1)))) { | |||
3872 | ok = SWITCH_FALSE; | |||
3873 | } | |||
3874 | } | |||
3875 | ||||
3876 | switch_safe_free(main_event_channel)if (main_event_channel) {free(main_event_channel);main_event_channel =((void*)0);}; | |||
3877 | return ok; | |||
3878 | ||||
3879 | } | |||
3880 | ||||
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 | ||||
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((void*)0), *errs = NULL((void*)0), *exist = NULL((void*)0); | |||
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(1 << 4)) { | |||
3922 | parse_subs(jsock, jchannel->valuestring, &subs, &errs, &exist); | |||
3923 | } else if (jchannel->type == cJSON_Array(1 << 5)) { | |||
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(1 << 4)) { | |||
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 | ||||
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 | ||||
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((void*)0), *errs = NULL((void*)0); | |||
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(1 << 4)) { | |||
3982 | do_unsub(jsock, jchannel->valuestring, &subs, &errs); | |||
3983 | } else if (jchannel->type == cJSON_Array(1 << 5)) { | |||
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(1 << 4)) { | |||
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 | ||||
4011 | static switch_bool_t verto__broadcast_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response) | |||
4012 | { | |||
4013 | char *json_text = NULL((void*)0); | |||
4014 | const char *event_channel = cJSON_GetObjectCstr(params, "eventChannel"); | |||
4015 | cJSON *jevent, *broadcast; | |||
4016 | const char *display = NULL((void*)0); | |||
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-32002)); | |||
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-32002)); | |||
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")switch_event_get_header_idx(jsock->params, "caller-id-name" , -1); | |||
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(1 << 1)) { | |||
4046 | write_event(event_channel, NULL((void*)0), 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(ws_socket_t)-1) { | |||
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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4055, ((void*)0), SWITCH_LOG_ERROR, "multicast socket send error! %s\n", strerror(errno(*__errno_location ()))); | |||
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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4062, ((void*)0), SWITCH_LOG_DEBUG, "MCAST Data Sent: %s\n",json_text); | |||
4063 | } | |||
4064 | } | |||
4065 | free(json_text); | |||
4066 | json_text = NULL((void*)0); | |||
4067 | } else { | |||
4068 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4068, ((void*)0), SWITCH_LOG_ERROR, "JSON ERROR!\n"); | |||
4069 | } | |||
4070 | } | |||
4071 | ||||
4072 | end: | |||
4073 | ||||
4074 | return SWITCH_TRUE; | |||
4075 | } | |||
4076 | ||||
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 | ||||
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-32002)); | |||
4098 | ||||
4099 | return SWITCH_FALSE; | |||
4100 | } | |||
4101 | ||||
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)switch_event_get_header_idx(jsock->allowed_jsapi, function , -1)) { | |||
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(1 << 4) && cmd->valuestring && | |||
4120 | !auth_api_command(jsock, cmd->valuestring, arg ? arg->valuestring : NULL((void*)0))) { | |||
4121 | return SWITCH_FALSE; | |||
4122 | } | |||
4123 | } | |||
4124 | } | |||
4125 | } | |||
4126 | } | |||
4127 | } | |||
4128 | ||||
4129 | switch_json_api_execute(params, NULL((void*)0), response); | |||
4130 | ||||
4131 | return *response ? SWITCH_TRUE : SWITCH_FALSE; | |||
4132 | } | |||
4133 | ||||
4134 | static switch_bool_t fsapi_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response) | |||
4135 | { | |||
4136 | cJSON *cmd = NULL((void*)0), *arg = NULL((void*)0), *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(1 << 4) && cmd->valuestring && !auth_api_command(jsock, cmd->valuestring, arg ? arg->valuestring : NULL((void*)0))) { | |||
4147 | return SWITCH_FALSE; | |||
4148 | } | |||
4149 | } | |||
4150 | ||||
4151 | if (cmd && !cmd->valuestring) { | |||
4152 | cmd = NULL((void*)0); | |||
4153 | } | |||
4154 | ||||
4155 | if (arg && !arg->valuestring) { | |||
4156 | arg = NULL((void*)0); | |||
4157 | } | |||
4158 | ||||
4159 | reply = cJSON_CreateObject(); | |||
4160 | ||||
4161 | SWITCH_STANDARD_STREAM(stream)memset(&stream, 0, sizeof(stream)); stream.data = malloc( 1024); ((stream.data) ? (void) (0) : __assert_fail ("stream.data" , "mod_verto.c", 4161, __extension__ __PRETTY_FUNCTION__)); memset (stream.data, 0, 1024); stream.end = stream.data; stream.data_size = 1024; stream.write_function = switch_console_stream_write; stream.raw_write_function = switch_console_stream_raw_write; stream.alloc_len = 1024; stream.alloc_chunk = 1024; | |||
4162 | ||||
4163 | if (cmd && (status = switch_api_execute(cmd->valuestring, arg ? arg->valuestring : NULL((void*)0), NULL((void*)0), &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)if (stream.data) {free(stream.data);stream.data=((void*)0);}; | |||
4170 | ||||
4171 | if (reply) { | |||
4172 | *response = reply; | |||
4173 | return SWITCH_TRUE; | |||
4174 | } | |||
4175 | ||||
4176 | return SWITCH_FALSE; | |||
4177 | } | |||
4178 | ||||
4179 | //// | |||
4180 | ||||
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 | ||||
4203 | static int start_jsock(verto_profile_t *profile, ws_socket_t sock, int family) | |||
4204 | { | |||
4205 | jsock_t *jsock = NULL((void*)0); | |||
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)switch_core_perform_new_memory_pool(&pool, "mod_verto.c", (const char *)__func__, 4218); | |||
4219 | ||||
4220 | ||||
4221 | jsock = (jsock_t *) switch_core_alloc(pool, sizeof(*jsock))switch_core_perform_alloc(pool, sizeof(*jsock), "mod_verto.c" , (const char *)__func__, 4221); | |||
4222 | jsock->pool = pool; | |||
4223 | jsock->family = family; | |||
4224 | ||||
4225 | if (family == PF_INET2) { | |||
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")do { char errbuf[8192] = {0}; strerror_r((*__errno_location ( )), (char *)&errbuf, sizeof(errbuf)); switch_log_printf(SWITCH_CHANNEL_ID_LOG , "mod_verto.c", (const char *)__func__, 4229, ((void*)0), (SWITCH_LOG_WARNING ), "ACCEPT FAILED" ", errno=%d, %s\n", (*__errno_location ()) , (char *)&errbuf); goto error; } while(0); | |||
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")do { char errbuf[8192] = {0}; strerror_r((*__errno_location ( )), (char *)&errbuf, sizeof(errbuf)); switch_log_printf(SWITCH_CHANNEL_ID_LOG , "mod_verto.c", (const char *)__func__, 4235, ((void*)0), (SWITCH_LOG_WARNING ), "ACCEPT FAILED" ", errno=%d, %s\n", (*__errno_location ()) , (char *)&errbuf); goto error; } while(0); | |||
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)_zstr(jsock->name)) { | |||
4252 | if (family == PF_INET2) { | |||
4253 | jsock->remote_port = ntohs(jsock->remote_addr.sin_port)__bswap_16 (jsock->remote_addr.sin_port); | |||
4254 | inet_ntop(AF_INET2, &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)__bswap_16 (jsock->remote_addr6.sin6_port); | |||
4258 | inet_ntop(AF_INET610, &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])switch_check_network_list_ip_token(jsock->remote_host, profile ->conn_acl[i], ((void*)0))) { | |||
4267 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4267, ((void*)0), 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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4273, ((void*)0), 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_event_create_subclass_detailed("mod_verto.c", (const char * )(const char *)__func__, 4276, &s_event, SWITCH_EVENT_CUSTOM , "verto::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)switch_event_fire_detailed("mod_verto.c", (const char * )(const char *)__func__, 4279, &s_event, ((void*)0)); | |||
4280 | } | |||
4281 | ||||
4282 | /* no nagle please */ | |||
4283 | setsockopt(jsock->client_socket, IPPROTO_TCPIPPROTO_TCP, TCP_NODELAY1, (char *)&flag, sizeof(flag)); | |||
4284 | ||||
4285 | ||||
4286 | #if defined(SO_KEEPALIVE9) | |||
4287 | setsockopt(jsock->client_socket, SOL_SOCKET1, SO_KEEPALIVE9, (void *)&flag, sizeof(flag)); | |||
4288 | #endif | |||
4289 | flag = 30; | |||
4290 | #if defined(TCP_KEEPIDLE4) | |||
4291 | setsockopt(jsock->client_socket, IPPROTO_TCPIPPROTO_TCP, TCP_KEEPIDLE4, (void *)&flag, sizeof(flag)); | |||
4292 | #endif | |||
4293 | #if defined(TCP_KEEPINTVL5) | |||
4294 | setsockopt(jsock->client_socket, IPPROTO_TCPIPPROTO_TCP, TCP_KEEPINTVL5, (void *)&flag, sizeof(flag)); | |||
4295 | #endif | |||
4296 | ||||
4297 | td = switch_core_alloc(jsock->pool, sizeof(*td))switch_core_perform_alloc(jsock->pool, sizeof(*td), "mod_verto.c" , (const char *)__func__, 4297); | |||
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_NESTED0x1, jsock->pool); | |||
4305 | switch_mutex_init(&jsock->filter_mutex, SWITCH_MUTEX_NESTED0x1, jsock->pool); | |||
4306 | switch_queue_create(&jsock->event_queue, MAX_QUEUE_LEN100000, 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(ws_socket_t)-1) { | |||
4316 | close_socket(&jsock->client_socket); | |||
4317 | } | |||
4318 | ||||
4319 | switch_core_destroy_memory_pool(&pool)switch_core_perform_destroy_memory_pool(&pool, "mod_verto.c" , (const char *)__func__, 4319); | |||
4320 | } | |||
4321 | ||||
4322 | return -1; | |||
4323 | } | |||
4324 | ||||
4325 | static ws_socket_t prepare_socket(ips_t *ips) | |||
4326 | { | |||
4327 | ws_socket_t sock = ws_sock_invalid(ws_socket_t)-1; | |||
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_INET610; | |||
4339 | } else { | |||
4340 | family = PF_INET2; | |||
4341 | } | |||
4342 | ||||
4343 | if ((sock = socket(family, SOCK_STREAMSOCK_STREAM, IPPROTO_TCPIPPROTO_TCP)) < 0) { | |||
4344 | die_errno("Socket Error!")do { char errbuf[8192] = {0}; strerror_r((*__errno_location ( )), (char *)&errbuf, sizeof(errbuf)); switch_log_printf(SWITCH_CHANNEL_ID_LOG , "mod_verto.c", (const char *)__func__, 4344, ((void*)0), (SWITCH_LOG_WARNING ), "Socket Error!" ", errno=%d, %s\n", (*__errno_location ()) , (char *)&errbuf); goto error; } while(0); | |||
4345 | } | |||
4346 | ||||
4347 | if ( setsockopt(sock, SOL_SOCKET1, SO_REUSEADDR2, &reuse_addr, sizeof(reuse_addr)) < 0 ) { | |||
4348 | die_errno("Socket setsockopt Error!")do { char errbuf[8192] = {0}; strerror_r((*__errno_location ( )), (char *)&errbuf, sizeof(errbuf)); switch_log_printf(SWITCH_CHANNEL_ID_LOG , "mod_verto.c", (const char *)__func__, 4348, ((void*)0), (SWITCH_LOG_WARNING ), "Socket setsockopt Error!" ", errno=%d, %s\n", (*__errno_location ()), (char *)&errbuf); goto error; } while(0); | |||
4349 | } | |||
4350 | ||||
4351 | if (family == PF_INET2) { | |||
4352 | memset(&addr, 0, sizeof(addr)); | |||
4353 | addr.sin_family = AF_INET2; | |||
4354 | addr.sin_addr.s_addr = inet_addr(ips->local_ip); | |||
4355 | addr.sin_port = htons(ips->local_port)__bswap_16 (ips->local_port); | |||
4356 | if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { | |||
4357 | die_errno("Bind Error!")do { char errbuf[8192] = {0}; strerror_r((*__errno_location ( )), (char *)&errbuf, sizeof(errbuf)); switch_log_printf(SWITCH_CHANNEL_ID_LOG , "mod_verto.c", (const char *)__func__, 4357, ((void*)0), (SWITCH_LOG_WARNING ), "Bind Error!" ", errno=%d, %s\n", (*__errno_location ()), ( char *)&errbuf); goto error; } while(0); | |||
4358 | } | |||
4359 | } else { | |||
4360 | memset(&addr6, 0, sizeof(addr6)); | |||
4361 | addr6.sin6_family = AF_INET610; | |||
4362 | addr6.sin6_port = htons(ips->local_port)__bswap_16 (ips->local_port); | |||
4363 | inet_pton(AF_INET610, ips->local_ip, &(addr6.sin6_addr)); | |||
4364 | if (bind(sock, (struct sockaddr *) &addr6, sizeof(addr6)) < 0) { | |||
4365 | die_errno("Bind Error!")do { char errbuf[8192] = {0}; strerror_r((*__errno_location ( )), (char *)&errbuf, sizeof(errbuf)); switch_log_printf(SWITCH_CHANNEL_ID_LOG , "mod_verto.c", (const char *)__func__, 4365, ((void*)0), (SWITCH_LOG_WARNING ), "Bind Error!" ", errno=%d, %s\n", (*__errno_location ()), ( char *)&errbuf); goto error; } while(0); | |||
4366 | } | |||
4367 | } | |||
4368 | ||||
4369 | if (listen(sock, MAXPENDING10000) < 0) { | |||
4370 | die_errno("Listen error")do { char errbuf[8192] = {0}; strerror_r((*__errno_location ( )), (char *)&errbuf, sizeof(errbuf)); switch_log_printf(SWITCH_CHANNEL_ID_LOG , "mod_verto.c", (const char *)__func__, 4370, ((void*)0), (SWITCH_LOG_WARNING ), "Listen error" ", errno=%d, %s\n", (*__errno_location ()), (char *)&errbuf); goto error; } while(0); | |||
4371 | } | |||
4372 | ||||
4373 | ips->family = family; | |||
4374 | ||||
4375 | return sock; | |||
4376 | ||||
4377 | error: | |||
4378 | ||||
4379 | close_file(&sock); | |||
4380 | ||||
4381 | return ws_sock_invalid(ws_socket_t)-1; | |||
4382 | } | |||
4383 | ||||
4384 | static void handle_mcast_sub(verto_profile_t *profile) | |||
4385 | { | |||
4386 | int bytes; | |||
4387 | ||||
4388 | if (profile->mcast_sub.sock == ws_sock_invalid(ws_socket_t)-1) { | |||
4389 | return; | |||
4390 | } | |||
4391 | ||||
4392 | bytes = (int)mcast_socket_recv(&profile->mcast_sub, NULL((void*)0), 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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4403, ((void*)0), 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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4407, ((void*)0), SWITCH_LOG_ERROR, "%s MCAST INVALID READ %d\n", profile->name, bytes); | |||
4408 | } | |||
4409 | ||||
4410 | } | |||
4411 | ||||
4412 | static int profile_one_loop(verto_profile_t *profile) | |||
4413 | { | |||
4414 | switch_waitlist_t pfds[MAX_BIND25+4]; | |||
4415 | int res, x = 0; | |||
4416 | int i = 0; | |||
4417 | int max = 2; | |||
4418 | ||||
4419 | memset(&pfds[0], 0, sizeof(pfds[0]) * MAX_BIND25+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(*__errno_location ()) != EINTR4) { | |||
4435 | die_errnof("%s POLL FAILED with %d", profile->name, res)do { char errbuf[8192] = {0}; strerror_r((*__errno_location ( )), (char *)&errbuf, sizeof(errbuf)); switch_log_printf(SWITCH_CHANNEL_ID_LOG , "mod_verto.c", (const char *)__func__, 4435, ((void*)0), (SWITCH_LOG_WARNING ), "%s POLL FAILED with %d" ", errno=%d, %s\n", profile->name , res, (*__errno_location ()), (char *)&errbuf); goto error ; } while(0); | |||
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)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4445, ((void*)0), (SWITCH_LOG_INFO), "%s POLL HANGUP DETECTED (peer closed its end of socket)\n" , profile->name); goto error; } | |||
4446 | if (pfds[x].revents & SWITCH_POLL_ERROR) { die("%s POLL ERROR\n", profile->name)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4446, ((void*)0), (SWITCH_LOG_WARNING), "%s POLL ERROR\n" , profile->name); goto error; } | |||
4447 | if (pfds[x].revents & SWITCH_POLL_INVALID) { die("%s POLL INVALID SOCKET (not opened or already closed)\n", profile->name)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4447, ((void*)0), (SWITCH_LOG_WARNING), "%s POLL INVALID SOCKET (not opened or already closed)\n" , profile->name); goto error; } | |||
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 | ||||
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 | ||||
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)switch_sleep(100000);; | |||
4515 | } | |||
4516 | } | |||
4517 | ||||
4518 | ||||
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(ws_socket_t)-1) { | |||
4527 | listeners++; | |||
4528 | } | |||
4529 | } | |||
4530 | ||||
4531 | if (!listeners) { | |||
4532 | die("%s Client Socket Error! No Listeners!\n", profile->name)switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4532, ((void*)0), (SWITCH_LOG_WARNING), "%s Client Socket Error! No Listeners!\n" , profile->name); goto error; | |||
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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4548, ((void*)0), 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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4550, ((void*)0), 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(ws_socket_t)-1) { | |||
4564 | mcast_socket_close(&profile->mcast_sub); | |||
4565 | } | |||
4566 | ||||
4567 | if (profile->mcast_pub.sock != ws_sock_invalid(ws_socket_t)-1) { | |||
4568 | mcast_socket_close(&profile->mcast_pub); | |||
4569 | } | |||
4570 | ||||
4571 | } | |||
4572 | ||||
4573 | static void do_shutdown(void) | |||
4574 | { | |||
4575 | verto_globals.running = 0; | |||
4576 | ||||
4577 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4577, ((void*)0), 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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4583, ((void*)0), SWITCH_LOG_INFO, "Done\n"); | |||
4584 | } | |||
4585 | ||||
4586 | ||||
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)(*input == '\0' ? input : input + strlen(input) - 1)) { | |||
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((void*)0)) { | |||
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((void*)0)) { | |||
4618 | if (hent->h_addrtype == AF_INET2) { | |||
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 | ||||
4630 | static verto_profile_t *find_profile(const char *name) | |||
4631 | { | |||
4632 | verto_profile_t *p, *r = NULL((void*)0); | |||
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((void*)0); | |||
4643 | } | |||
4644 | ||||
4645 | if (r && switch_thread_rwlock_tryrdlock(r->rwlock) != SWITCH_STATUS_SUCCESS) { | |||
4646 | r = NULL((void*)0); | |||
4647 | } | |||
4648 | switch_mutex_unlock(verto_globals.mutex); | |||
4649 | ||||
4650 | return r; | |||
4651 | } | |||
4652 | ||||
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 | ||||
4670 | static void del_profile(verto_profile_t *profile) | |||
4671 | { | |||
4672 | verto_profile_t *p, *last = NULL((void*)0); | |||
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 | ||||
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 | ||||
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((void*)0)))) { | |||
4720 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4720, ((void*)0), 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)_zstr(name)) { | |||
4731 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4731, ((void*)0), SWITCH_LOG_ERROR, "Required field name missing\n"); | |||
4732 | continue; | |||
4733 | } | |||
4734 | ||||
4735 | if (profile_exists(name)) { | |||
4736 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4736, ((void*)0), SWITCH_LOG_ERROR, "Profile %s already exists\n", name); | |||
4737 | continue; | |||
4738 | } | |||
4739 | ||||
4740 | ||||
4741 | switch_core_new_memory_pool(&pool)switch_core_perform_new_memory_pool(&pool, "mod_verto.c", (const char *)__func__, 4741); | |||
4742 | profile = switch_core_alloc(pool, sizeof(*profile))switch_core_perform_alloc(pool, sizeof(*profile), "mod_verto.c" , (const char *)__func__, 4742); | |||
4743 | profile->pool = pool; | |||
4744 | profile->name = switch_core_strdup(profile->pool, name)switch_core_perform_strdup(profile->pool, name, "mod_verto.c" , (const char *)__func__, 4744); | |||
4745 | switch_mutex_init(&profile->mutex, SWITCH_MUTEX_NESTED0x1, 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(ws_socket_t)-1; | |||
4752 | profile->mcast_pub.sock = ws_sock_invalid(ws_socket_t)-1; | |||
4753 | ||||
4754 | ||||
4755 | for (param = switch_xml_child(xprofile, "param"); param; param = param->next) { | |||
4756 | char *var = NULL((void*)0); | |||
4757 | char *val = NULL((void*)0); | |||
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_BIND25) { | |||
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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4771, ((void*)0), 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)strncpy(profile->cert, val, sizeof(profile->cert)-1); | |||
4777 | set_string(profile->key, val)strncpy(profile->key, val, sizeof(profile->key)-1); | |||
4778 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4778, ((void*)0), SWITCH_LOG_INFO, "Secure key and cert specified\n"); | |||
4779 | } else if (!strcasecmp(var, "secure-cert")) { | |||
4780 | set_string(profile->cert, val)strncpy(profile->cert, val, sizeof(profile->cert)-1); | |||
4781 | } else if (!strcasecmp(var, "secure-key")) { | |||
4782 | set_string(profile->key, val)strncpy(profile->key, val, sizeof(profile->key)-1); | |||
4783 | } else if (!strcasecmp(var, "secure-chain")) { | |||
4784 | set_string(profile->chain, val)strncpy(profile->chain, val, sizeof(profile->chain)-1); | |||
4785 | } else if (!strcasecmp(var, "inbound-codec-string") && !zstr(val)_zstr(val)) { | |||
4786 | profile->inbound_codec_string = switch_core_strdup(profile->pool, val)switch_core_perform_strdup(profile->pool, val, "mod_verto.c" , (const char *)__func__, 4786); | |||
4787 | } else if (!strcasecmp(var, "outbound-codec-string") && !zstr(val)_zstr(val)) { | |||
4788 | profile->outbound_codec_string = switch_core_strdup(profile->pool, val)switch_core_perform_strdup(profile->pool, val, "mod_verto.c" , (const char *)__func__, 4788); | |||
4789 | } else if (!strcasecmp(var, "auto-jitterbuffer-msec") && !zstr(val)_zstr(val)) { | |||
4790 | profile->jb_msec = switch_core_strdup(profile->pool, val)switch_core_perform_strdup(profile->pool, val, "mod_verto.c" , (const char *)__func__, 4790); | |||
4791 | } else if (!strcasecmp(var, "blind-reg") && !zstr(val)_zstr(val)) { | |||
4792 | profile->blind_reg = switch_true(val); | |||
4793 | } else if (!strcasecmp(var, "userauth") && !zstr(val)_zstr(val)) { | |||
4794 | profile->userauth = switch_core_strdup(profile->pool, val)switch_core_perform_strdup(profile->pool, val, "mod_verto.c" , (const char *)__func__, 4794); | |||
4795 | } else if (!strcasecmp(var, "root-password") && !zstr(val)_zstr(val)) { | |||
4796 | profile->root_passwd = switch_core_strdup(profile->pool, val)switch_core_perform_strdup(profile->pool, val, "mod_verto.c" , (const char *)__func__, 4796); | |||
4797 | } else if (!strcasecmp(var, "context") && !zstr(val)_zstr(val)) { | |||
4798 | profile->context = switch_core_strdup(profile->pool, val)switch_core_perform_strdup(profile->pool, val, "mod_verto.c" , (const char *)__func__, 4798); | |||
4799 | } else if (!strcasecmp(var, "dialplan") && !zstr(val)_zstr(val)) { | |||
4800 | profile->dialplan = switch_core_strdup(profile->pool, val)switch_core_perform_strdup(profile->pool, val, "mod_verto.c" , (const char *)__func__, 4800); | |||
4801 | } else if (!strcasecmp(var, "mcast-ip") && val) { | |||
4802 | profile->mcast_ip = switch_core_strdup(profile->pool, val)switch_core_perform_strdup(profile->pool, val, "mod_verto.c" , (const char *)__func__, 4802); | |||
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)_zstr(var)) { | |||
4806 | profile->timer_name = switch_core_strdup(profile->pool, val)switch_core_perform_strdup(profile->pool, val, "mod_verto.c" , (const char *)__func__, 4806); | |||
4807 | } else if (!strcasecmp(var, "force-register-domain") && !zstr(val)_zstr(val)) { | |||
4808 | profile->register_domain = switch_core_strdup(profile->pool, val)switch_core_perform_strdup(profile->pool, val, "mod_verto.c" , (const char *)__func__, 4808); | |||
4809 | } else if (!strcasecmp(var, "local-network") && !zstr(val)_zstr(val)) { | |||
4810 | profile->local_network = switch_core_strdup(profile->pool, val)switch_core_perform_strdup(profile->pool, val, "mod_verto.c" , (const char *)__func__, 4810); | |||
4811 | } else if (!strcasecmp(var, "apply-candidate-acl")) { | |||
4812 | if (profile->cand_acl_count < SWITCH_MAX_CAND_ACL25) { | |||
4813 | profile->cand_acl[profile->cand_acl_count++] = switch_core_strdup(profile->pool, val)switch_core_perform_strdup(profile->pool, val, "mod_verto.c" , (const char *)__func__, 4813); | |||
4814 | } else { | |||
4815 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4815, ((void*)0), SWITCH_LOG_ERROR, "Max acl records of %d reached\n", SWITCH_MAX_CAND_ACL25); | |||
4816 | } | |||
4817 | } else if (!strcasecmp(var, "apply-connection-acl")) { | |||
4818 | if (profile->conn_acl_count < SWITCH_MAX_CAND_ACL25) { | |||
4819 | profile->conn_acl[profile->conn_acl_count++] = switch_core_strdup(profile->pool, val)switch_core_perform_strdup(profile->pool, val, "mod_verto.c" , (const char *)__func__, 4819); | |||
4820 | } else { | |||
4821 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4821, ((void*)0), SWITCH_LOG_ERROR, "Max acl records of %d reached\n", SWITCH_MAX_CAND_ACL25); | |||
4822 | } | |||
4823 | } else if (!strcasecmp(var, "rtp-ip")) { | |||
4824 | if (zstr(val)_zstr(val)) { | |||
4825 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4825, ((void*)0), SWITCH_LOG_WARNING, "Invalid RTP IP.\n"); | |||
4826 | } else { | |||
4827 | if (strchr(val, ':')) { | |||
4828 | if (profile->rtpip_index6 < MAX_RTPIP25 -1) { | |||
4829 | profile->rtpip6[profile->rtpip_index6++] = switch_core_strdup(profile->pool, val)switch_core_perform_strdup(profile->pool, val, "mod_verto.c" , (const char *)__func__, 4829); | |||
4830 | } else { | |||
4831 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4831, ((void*)0), SWITCH_LOG_WARNING, "Too many RTP IP.\n"); | |||
4832 | } | |||
4833 | } else { | |||
4834 | if (profile->rtpip_index < MAX_RTPIP25 -1) { | |||
4835 | profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, val)switch_core_perform_strdup(profile->pool, val, "mod_verto.c" , (const char *)__func__, 4835); | |||
4836 | } else { | |||
4837 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4837, ((void*)0), SWITCH_LOG_WARNING, "Too many RTP IP.\n"); | |||
4838 | } | |||
4839 | } | |||
4840 | } | |||
4841 | } else if (!strcasecmp(var, "ext-rtp-ip")) { | |||
4842 | if (zstr(val)_zstr(val)) { | |||
4843 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4843, ((void*)0), 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)_zstr(profile->outbound_codec_string)) { | |||
4855 | profile->outbound_codec_string = "opus,vp8"; | |||
4856 | } | |||
4857 | ||||
4858 | if (zstr(profile->inbound_codec_string)_zstr(profile->inbound_codec_string)) { | |||
4859 | profile->inbound_codec_string = profile->outbound_codec_string; | |||
4860 | } | |||
4861 | ||||
4862 | if (zstr(profile->jb_msec)_zstr(profile->jb_msec)) { | |||
4863 | profile->jb_msec = "1p:50p"; | |||
4864 | } | |||
4865 | ||||
4866 | if (zstr(profile->timer_name)_zstr(profile->timer_name)) { | |||
4867 | profile->timer_name = "soft"; | |||
4868 | } | |||
4869 | ||||
4870 | if (zstr(profile->dialplan)_zstr(profile->dialplan)) { | |||
4871 | profile->dialplan = "XML"; | |||
4872 | } | |||
4873 | ||||
4874 | if (zstr(profile->context)_zstr(profile->context)) { | |||
4875 | profile->context = "default"; | |||
4876 | } | |||
4877 | ||||
4878 | if (zstr(profile->ip[0].local_ip)_zstr(profile->ip[0].local_ip) ) switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4878, ((void*)0), SWITCH_LOG_ERROR, "%s: local_ip bad\n", profile->name); | |||
4879 | if (profile->ip[0].local_port <= 0 ) switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4879, ((void*)0), SWITCH_LOG_ERROR, "%s: local_port bad\n", profile->name); | |||
4880 | ||||
4881 | if (zstr(profile->ip[0].local_ip)_zstr(profile->ip[0].local_ip) || profile->ip[0].local_port <= 0) { | |||
4882 | del_profile(profile); | |||
4883 | switch_core_destroy_memory_pool(&pool)switch_core_perform_destroy_memory_pool(&pool, "mod_verto.c" , (const char *)__func__, 4883); | |||
4884 | } else { | |||
4885 | int i; | |||
4886 | ||||
4887 | for (i = 0; i < profile->i; i++) { | |||
4888 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4888, ((void*)0), 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((void*)0); | |||
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)_zstr(domain)) { | |||
4904 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 4904, ((void*)0), SWITCH_LOG_ERROR, "Required field domain missing\n"); | |||
4905 | continue; | |||
4906 | } | |||
4907 | ||||
4908 | vhost = switch_core_alloc(profile->pool, sizeof(*vhost))switch_core_perform_alloc(profile->pool, sizeof(*vhost), "mod_verto.c" , (const char *)__func__, 4908); | |||
4909 | memset(vhost, 0, sizeof(*vhost)); | |||
4910 | vhost->pool = profile->pool; | |||
4911 | vhost->domain = switch_core_strdup(profile->pool, domain)switch_core_perform_strdup(profile->pool, domain, "mod_verto.c" , (const char *)__func__, 4911); | |||
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((void*)0); | |||
4923 | char *val = NULL((void*)0); | |||
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)switch_core_perform_strdup(vhost->pool, val, "mod_verto.c" , (const char *)__func__, 4929); | |||
4930 | } else if (!strcasecmp(var, "root")) { | |||
4931 | vhost->root = switch_core_strdup(vhost->pool, val)switch_core_perform_strdup(vhost->pool, val, "mod_verto.c" , (const char *)__func__, 4931); | |||
4932 | } else if (!strcasecmp(var, "script-root")) { | |||
4933 | vhost->script_root = switch_core_strdup(vhost->pool, val)switch_core_perform_strdup(vhost->pool, val, "mod_verto.c" , (const char *)__func__, 4933); | |||
4934 | } else if (!strcasecmp(var, "index")) { | |||
4935 | vhost->index = switch_core_strdup(vhost->pool, val)switch_core_perform_strdup(vhost->pool, val, "mod_verto.c" , (const char *)__func__, 4935); | |||
4936 | } else if (!strcasecmp(var, "auth-realm")) { | |||
4937 | vhost->auth_realm = switch_core_strdup(vhost->pool, val)switch_core_perform_strdup(vhost->pool, val, "mod_verto.c" , (const char *)__func__, 4937); | |||
4938 | } else if (!strcasecmp(var, "auth-user")) { | |||
4939 | vhost->auth_user = switch_core_strdup(vhost->pool, val)switch_core_perform_strdup(vhost->pool, val, "mod_verto.c" , (const char *)__func__, 4939); | |||
4940 | } else if (!strcasecmp(var, "auth-pass")) { | |||
4941 | vhost->auth_pass = switch_core_strdup(vhost->pool, val)switch_core_perform_strdup(vhost->pool, val, "mod_verto.c" , (const char *)__func__, 4941); | |||
4942 | } | |||
4943 | } | |||
4944 | ||||
4945 | if (zstr(vhost->root)_zstr(vhost->root)) { | |||
4946 | vhost->root = SWITCH_GLOBAL_dirs.htdocs_dir; | |||
4947 | } | |||
4948 | ||||
4949 | if (zstr(vhost->script_root)_zstr(vhost->script_root)) { | |||
4950 | vhost->script_root = SWITCH_GLOBAL_dirs.script_dir; | |||
4951 | } | |||
4952 | ||||
4953 | if (zstr(vhost->index)_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_event_create_subclass_detailed("mod_verto.c", (const char * )(const char *)__func__, 4958, &vhost->rewrites, SWITCH_EVENT_CLONE , ((void*)0)) == SWITCH_STATUS_SUCCESS) { | |||
4959 | for (rule = switch_xml_child(rewrites, "rule"); rule; rule = rule->next) { | |||
4960 | char *expr = NULL((void*)0); | |||
4961 | char *val = NULL((void*)0); | |||
4962 | ||||
4963 | expr = (char *) switch_xml_attr_soft(rule, "expression"); | |||
4964 | val = (char *) switch_xml_attr_soft(rule, "value"); | |||
4965 | ||||
4966 | if (zstr(expr)_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((void*)0); | |||
4980 | char *val = NULL((void*)0); | |||
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 | ||||
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); | |||
5047 | static switch_status_t cmd_status(char **argv, int argc, switch_stream_handle_t *stream) | |||
5048 | { | |||
5049 | verto_profile_t *profile = NULL((void*)0); | |||
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(ws_socket_t)-1) ? "RUNNING" : "DOWN"); | |||
5066 | switch_safe_free(tmpurl)if (tmpurl) {free(tmpurl);tmpurl=((void*)0);}; | |||
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)if (tmpname) {free(tmpname);tmpname=((void*)0);}; | |||
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)_zstr(jsock->uid)) ? "CONN_REG" : "CONN_NO_REG", (jsock->ptype & PTYPE_CLIENT_SSL) ? "WSS": "WS"); | |||
5080 | cc++; | |||
5081 | switch_safe_free(tmpname)if (tmpname) {free(tmpname);tmpname=((void*)0);}; | |||
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 | ||||
5093 | static switch_status_t cmd_xml_status(char **argv, int argc, switch_stream_handle_t *stream) | |||
5094 | { | |||
5095 | verto_profile_t *profile = NULL((void*)0); | |||
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)if (tmpurl) {free(tmpurl);tmpurl=((void*)0);}; | |||
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)_zstr(jsock->uid)) ? "CONN_REG" : "CONN_NO_REG", (jsock->ptype & PTYPE_CLIENT_SSL) ? "WSS": "WS"); | |||
5119 | cc++; | |||
5120 | switch_safe_free(tmpname)if (tmpname) {free(tmpname);tmpname=((void*)0);}; | |||
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 | ||||
5129 | SWITCH_STANDARD_API(verto_function)static switch_status_t verto_function ( const char *cmd, switch_core_session_t *session, switch_stream_handle_t *stream) | |||
5130 | { | |||
5131 | char *argv[1024] = { 0 }; | |||
5132 | int argc = 0; | |||
5133 | char *mycmd = NULL((void*)0); | |||
5134 | switch_status_t status = SWITCH_STATUS_SUCCESS; | |||
5135 | verto_command_t func = NULL((void*)0); | |||
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)_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)if (mycmd) {free(mycmd);mycmd=((void*)0);}; | |||
5175 | return status; | |||
5176 | ||||
5177 | } | |||
5178 | ||||
5179 | ||||
5180 | ||||
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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 5197, ((void*)0), 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)switch_sleep(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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 5208, ((void*)0), 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((void*)0); | |||
5217 | ||||
5218 | } | |||
5219 | ||||
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))switch_core_perform_alloc(profile->pool, sizeof(*td), "mod_verto.c" , (const char *)__func__, 5223); | |||
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 | ||||
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((void*)0), | |||
5265 | /*.read_frame */ NULL((void*)0), | |||
5266 | /*.write_frame */ NULL((void*)0), | |||
5267 | /*.kill_channel */ NULL((void*)0), | |||
5268 | /*.send_dtmf */ NULL((void*)0), | |||
5269 | /*.receive_message */ NULL((void*)0), | |||
5270 | /*.receive_event */ NULL((void*)0), | |||
5271 | /*.state_change */ NULL((void*)0), | |||
5272 | /*.read_video_frame */ NULL((void*)0), | |||
5273 | /*.write_video_frame */ NULL((void*)0), | |||
5274 | /*.read_text_frame */ verto_read_text_frame, | |||
5275 | /*.write_text_frame */ verto_write_text_frame, | |||
5276 | /*.state_run*/ NULL((void*)0), | |||
5277 | /*.get_jb*/ NULL((void*)0) | |||
5278 | }; | |||
5279 | ||||
5280 | ||||
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 | ||||
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_LEN16384] = ""; | |||
5328 | ||||
5329 | if ((datalen = switch_buffer_read(tech_pvt->text_write_buffer, data, 100))) { | |||
5330 | cJSON *obj = NULL((void*)0), *txt = NULL((void*)0), *params = NULL((void*)0); | |||
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((void*)0)); | |||
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 | ||||
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_NESTED0x1, tech_pvt->pool); | |||
5366 | switch_mutex_init(&tech_pvt->text_write_mutex, SWITCH_MUTEX_NESTED0x1, tech_pvt->pool); | |||
5367 | switch_mutex_init(&tech_pvt->text_cond_mutex, SWITCH_MUTEX_NESTED0x1, 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)switch_channel_set_flag_value(switch_core_session_get_channel (session), CF_HAS_TEXT, 1); | |||
5374 | switch_core_session_start_text_thread(session); | |||
5375 | } | |||
5376 | } | |||
5377 | ||||
5378 | ||||
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((void*)0), stream = { 0 }; | |||
5384 | char *gen_uid = NULL((void*)0); | |||
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)memset(&stream, 0, sizeof(stream)); stream.data = malloc( 1024); ((stream.data) ? (void) (0) : __assert_fail ("stream.data" , "mod_verto.c", 5395, __extension__ __PRETTY_FUNCTION__)); memset (stream.data, 0, 1024); stream.end = stream.data; stream.data_size = 1024; stream.write_function = switch_console_stream_write; stream.raw_write_function = switch_console_stream_raw_write; stream.alloc_len = 1024; stream.alloc_chunk = 1024; | |||
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(jsock->uid) && !zstr(uid)_zstr(uid) && !strcmp(uid, jsock->uid)) { | |||
5406 | use_stream->write_function(use_stream, "%s/u:%s,", EP_NAME"verto.rtc", 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)if (gen_uid) {free(gen_uid);gen_uid=((void*)0);}; | |||
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)*(*p == '\0' ? p : p + strlen(p) - 1) == ',') { | |||
5424 | end_of(p)*(*p == '\0' ? p : p + strlen(p) - 1) = '\0'; | |||
5425 | } | |||
5426 | } | |||
5427 | ||||
5428 | return use_stream->data; | |||
5429 | } | |||
5430 | ||||
5431 | SWITCH_STANDARD_API(verto_contact_function)static switch_status_t verto_contact_function ( const char *cmd , switch_core_session_t *session, switch_stream_handle_t *stream ) | |||
5432 | { | |||
5433 | char *uid = (char *) cmd; | |||
5434 | ||||
5435 | if (!zstr(uid)_zstr(uid)) { | |||
5436 | verto_get_dial_string(uid, stream); | |||
5437 | } | |||
5438 | ||||
5439 | return SWITCH_STATUS_SUCCESS; | |||
5440 | } | |||
5441 | ||||
5442 | ||||
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((void*)0); | |||
5453 | ||||
5454 | PROTECT_INTERFACE(verto_endpoint_interface)if (verto_endpoint_interface) {switch_thread_rwlock_rdlock(verto_endpoint_interface ->parent->rwlock); switch_thread_rwlock_rdlock(verto_endpoint_interface ->rwlock); switch_mutex_lock(verto_endpoint_interface-> reflock); verto_endpoint_interface->refs++; verto_endpoint_interface ->parent->refs++; switch_mutex_unlock(verto_endpoint_interface ->reflock);}; | |||
5455 | ||||
5456 | if (!zstr(outbound_profile->destination_number)_zstr(outbound_profile->destination_number)) { | |||
5457 | dest = strdup(outbound_profile->destination_number); | |||
5458 | } | |||
5459 | ||||
5460 | if (zstr(dest)_zstr(dest)) { | |||
5461 | goto end; | |||
5462 | } | |||
5463 | ||||
5464 | if (!switch_stristr("u:", dest)) { | |||
5465 | char *dial_str = verto_get_dial_string(dest, NULL((void*)0)); | |||
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"))_zstr(switch_event_get_header_idx(var_event, "origination_callee_id_number" , -1))) { | |||
5469 | char *p; | |||
5470 | char *trimmed_dest = strdup(dest); | |||
5471 | switch_assert(trimmed_dest)((trimmed_dest) ? (void) (0) : __assert_fail ("trimmed_dest", "mod_verto.c", 5471, __extension__ __PRETTY_FUNCTION__)); | |||
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((void*)0), | |||
5492 | NULL((void*)0), NULL((void*)0), outbound_profile, var_event, myflags, cancel_cause, NULL((void*)0)) == 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")switch_event_get_header_idx(var_event, "dialed_user", -1); | |||
5502 | const char *dialed_domain = switch_event_get_header(var_event, "dialed_domain")switch_event_get_header_idx(var_event, "dialed_domain", -1); | |||
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"))_zstr(switch_event_get_header_idx(var_event, "origination_callee_id_number" , -1))) { | |||
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)switch_core_perform_strdup(outbound_profile->pool, dialed_user , "mod_verto.c", (const char *)__func__, 5512)); | |||
5513 | } | |||
5514 | } | |||
5515 | } | |||
5516 | ||||
5517 | if ((cause = switch_core_session_outgoing_channel(session, var_event, "rtc", | |||
5518 | outbound_profile, new_session, NULL((void*)0), 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((void*)0); | |||
5523 | char name[512]; | |||
5524 | ||||
5525 | tech_pvt = switch_core_session_alloc(*new_session, sizeof(*tech_pvt))switch_core_perform_session_alloc(*new_session, sizeof(*tech_pvt ), "mod_verto.c", (const char *)__func__, 5525); | |||
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)switch_core_perform_session_strdup(*new_session, jsock_uuid_str , "mod_verto.c", (const char *)__func__, 5529); | |||
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)switch_channel_get_variable_dup(ochannel, "bypass_media", SWITCH_TRUE , -1))) { | |||
5537 | switch_channel_set_flag(channel, CF_PROXY_MODE)switch_channel_set_flag_value(channel, CF_PROXY_MODE, 1); | |||
5538 | switch_channel_set_flag(ochannel, CF_PROXY_MODE)switch_channel_set_flag_value(ochannel, CF_PROXY_MODE, 1); | |||
5539 | switch_channel_set_cap(channel, CC_BYPASS_MEDIA)switch_channel_set_cap_value(channel, CC_BYPASS_MEDIA, 1); | |||
5540 | } | |||
5541 | } | |||
5542 | ||||
5543 | tech_pvt->call_id = switch_core_session_strdup(*new_session, switch_core_session_get_uuid(*new_session))switch_core_perform_session_strdup(*new_session, switch_core_session_get_uuid (*new_session), "mod_verto.c", (const char *)__func__, 5543); | |||
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)switch_channel_set_variable_var_check(channel, "jsock_uuid_str" , tech_pvt->jsock_uuid, SWITCH_TRUE); | |||
5551 | switch_channel_set_variable(channel, "event_channel_cookie", tech_pvt->jsock_uuid)switch_channel_set_variable_var_check(channel, "event_channel_cookie" , tech_pvt->jsock_uuid, SWITCH_TRUE); | |||
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)switch_channel_perform_set_state(channel, "mod_verto.c", (const char *)__func__, 5560, CS_INIT); | |||
5561 | //track_pvt(tech_pvt); | |||
5562 | } | |||
5563 | ||||
5564 | end: | |||
5565 | ||||
5566 | if (cause != SWITCH_CAUSE_SUCCESS) { | |||
5567 | UNPROTECT_INTERFACE(verto_endpoint_interface)if (verto_endpoint_interface) {switch_mutex_lock(verto_endpoint_interface ->reflock); verto_endpoint_interface->refs--; verto_endpoint_interface ->parent->refs--; switch_mutex_unlock(verto_endpoint_interface ->reflock); switch_thread_rwlock_unlock(verto_endpoint_interface ->rwlock); switch_thread_rwlock_unlock(verto_endpoint_interface ->parent->rwlock);}; | |||
5568 | } | |||
5569 | ||||
5570 | switch_safe_free(dest)if (dest) {free(dest);dest=((void*)0);}; | |||
5571 | ||||
5572 | return cause; | |||
5573 | } | |||
5574 | ||||
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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 5580, ((void*)0), 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 | ||||
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)switch_core_session_perform_locate(call_id, "mod_verto.c", (const char *)__func__, 5602))) { | |||
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)_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 | ||||
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")switch_event_get_header_idx(message_event, "to", -1); | |||
5645 | const char *from = switch_event_get_header(message_event, "from")switch_event_get_header_idx(message_event, "from", -1); | |||
5646 | const char *body = switch_event_get_body(message_event); | |||
5647 | const char *call_id = switch_event_get_header(message_event, "call_id")switch_event_get_header_idx(message_event, "call_id", -1); | |||
5648 | ||||
5649 | //DUMP_EVENT(message_event); | |||
5650 | ||||
5651 | ||||
5652 | if (!zstr(to)_zstr(to) && !zstr(body)_zstr(body) && !zstr(from)_zstr(from)) { | |||
5653 | cJSON *obj = NULL((void*)0), *msg = NULL((void*)0), *params = NULL((void*)0); | |||
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((void*)0)); | |||
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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 5672, ((void*)0), SWITCH_LOG_ERROR, "INVALID EVENT\n"); | |||
5673 | DUMP_EVENT(message_event){char *event_str;switch_event_serialize(message_event, &event_str , SWITCH_FALSE);switch_log_printf(SWITCH_CHANNEL_ID_LOG, "mod_verto.c" , (const char *)__func__, 5673, ((void*)0), SWITCH_LOG_CRIT, "DUMP\n%s\n" , event_str);free(event_str);}; | |||
5674 | status = SWITCH_STATUS_FALSE; | |||
5675 | } | |||
5676 | ||||
5677 | ||||
5678 | return status; | |||
5679 | } | |||
5680 | ||||
5681 | ||||
5682 | ||||
5683 | static switch_cache_db_handle_t *json_get_db_handle(void) | |||
5684 | { | |||
5685 | ||||
5686 | switch_cache_db_handle_t *dbh = NULL((void*)0); | |||
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_cache_db_get_db_handle_dsn(&dbh, dsn, "mod_verto.c" , (const char *)__func__, 5695) != SWITCH_STATUS_SUCCESS) { | |||
5696 | dbh = NULL((void*)0); | |||
5697 | } | |||
5698 | ||||
5699 | return dbh; | |||
5700 | } | |||
5701 | ||||
5702 | ||||
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 | ||||
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((void*)0); | |||
5719 | cJSON *json = NULL((void*)0); | |||
5720 | ||||
5721 | if (!check_name(name)) { | |||
5722 | return NULL((void*)0); | |||
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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 5735, ((void*)0), 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)if (ascii) {free(ascii);ascii=((void*)0);}; | |||
5747 | ||||
5748 | return json; | |||
5749 | ||||
5750 | } | |||
5751 | ||||
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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 5779, ((void*)0), 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_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 5785, ((void*)0), 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)if (sql) {free(sql);sql=((void*)0);}; | |||
5793 | switch_safe_free(ascii)if (ascii) {free(ascii);ascii=((void*)0);}; | |||
5794 | ||||
5795 | switch_cache_db_release_db_handle(&dbh); | |||
5796 | ||||
5797 | return SWITCH_TRUE; | |||
5798 | } | |||
5799 | ||||
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((void*)0); | |||
5805 | char *ascii = NULL((void*)0); | |||
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)switch_channel_set_variable_var_check(channel, "json_store_data" , ascii, SWITCH_TRUE); | |||
5811 | free(ascii); | |||
5812 | } | |||
5813 | cJSON_Delete(session_store->JSON_STORE); | |||
5814 | session_store->JSON_STORE = NULL((void*)0); | |||
5815 | switch_channel_set_private(channel, "_json_store_", NULL((void*)0)); | |||
5816 | } | |||
5817 | switch_core_event_hook_remove_state_change(session, json_hanguphook); | |||
5818 | } | |||
5819 | ||||
5820 | return SWITCH_STATUS_SUCCESS; | |||
5821 | } | |||
5822 | ||||
5823 | SWITCH_STANDARD_JSON_API(json_store_function)static switch_status_t json_store_function (const cJSON *json , switch_core_session_t *session, cJSON **json_reply) | |||
5824 | { | |||
5825 | cJSON *JSON_STORE = NULL((void*)0), *reply = NULL((void*)0), *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((void*)0), *message = NULL((void*)0); | |||
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((void*)0); | |||
5837 | switch_core_session_t *tsession = NULL((void*)0); | |||
5838 | switch_channel_t *tchannel = NULL((void*)0); | |||
5839 | json_store_t *session_store = NULL((void*)0); | |||
5840 | ||||
5841 | reply = cJSON_CreateObject(); | |||
5842 | ||||
5843 | if (uuid) { | |||
5844 | if ((tsession = switch_core_session_locate(uuid)switch_core_session_perform_locate(uuid, "mod_verto.c", (const char *)__func__, 5844))) { | |||
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)_zstr(storename)) { | |||
5852 | storename = "global"; | |||
5853 | } | |||
5854 | } | |||
5855 | ||||
5856 | ||||
5857 | if (zstr(cmd_attr)_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)_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)_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))switch_core_perform_session_alloc(tsession, sizeof(*session_store ), "mod_verto.c", (const char *)__func__, 5897); | |||
5898 | switch_mutex_init(&session_store->mutex, SWITCH_MUTEX_NESTED0x1, 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)switch_core_hash_insert_destructor(json_GLOBALS.store_hash, storename , JSON_STORE, ((void*)0)); | |||
5913 | } | |||
5914 | use_store = &JSON_STORE; | |||
5915 | } | |||
5916 | ||||
5917 | switch(cmd) { | |||
5918 | case CMD_RETRIEVE: | |||
5919 | obj = json_retrieve(file, NULL((void*)0)); | |||
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)_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)_zstr(error)) { | |||
6023 | cJSON_AddItemToObject(reply, "errorMessage", cJSON_CreateString(error)); | |||
6024 | } | |||
6025 | ||||
6026 | if (!zstr(message)_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_idx(event, _ename, -1))) { cJSON_AddItemToObject(data, _name, cJSON_CreateString(tmp)); } if ((tmp = switch_event_get_header(event, _ename)switch_event_get_header_idx(event, _ename, -1))) { cJSON_AddItemToObject(data, _name, cJSON_CreateString(tmp));} | |||
6041 | ||||
6042 | static void presence_event_handler(switch_event_t *event) | |||
6043 | { | |||
6044 | cJSON *msg = NULL((void*)0), *data = NULL((void*)0); | |||
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")switch_event_get_header_idx(event, "channel-presence-id", -1); | |||
6049 | ||||
6050 | if (!verto_globals.running) { | |||
6051 | return; | |||
6052 | } | |||
6053 | ||||
6054 | if (!verto_globals.enable_presence || zstr(presence_id)_zstr(presence_id)) { | |||
6055 | return; | |||
6056 | } | |||
6057 | ||||
6058 | msg = cJSON_CreateObject(); | |||
6059 | data = json_add_child_obj(msg, "data", NULL((void*)0)); | |||
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")if ((tmp = switch_event_get_header_idx(event, "channel-call-state" , -1))) { cJSON_AddItemToObject(data, "channelCallState", cJSON_CreateString (tmp));}; | |||
6065 | add_it("originalChannelCallState", "original-channel-call-state")if ((tmp = switch_event_get_header_idx(event, "original-channel-call-state" , -1))) { cJSON_AddItemToObject(data, "originalChannelCallState" , cJSON_CreateString(tmp));}; | |||
6066 | add_it("channelState", "channel-state")if ((tmp = switch_event_get_header_idx(event, "channel-state" , -1))) { cJSON_AddItemToObject(data, "channelState", cJSON_CreateString (tmp));}; | |||
6067 | ||||
6068 | add_it("callerUserName", "caller-username")if ((tmp = switch_event_get_header_idx(event, "caller-username" , -1))) { cJSON_AddItemToObject(data, "callerUserName", cJSON_CreateString (tmp));}; | |||
6069 | add_it("callerIDName", "caller-caller-id-name")if ((tmp = switch_event_get_header_idx(event, "caller-caller-id-name" , -1))) { cJSON_AddItemToObject(data, "callerIDName", cJSON_CreateString (tmp));}; | |||
6070 | add_it("callerIDNumber", "caller-caller-id-number")if ((tmp = switch_event_get_header_idx(event, "caller-caller-id-number" , -1))) { cJSON_AddItemToObject(data, "callerIDNumber", cJSON_CreateString (tmp));}; | |||
6071 | add_it("calleeIDName", "caller-callee-id-name")if ((tmp = switch_event_get_header_idx(event, "caller-callee-id-name" , -1))) { cJSON_AddItemToObject(data, "calleeIDName", cJSON_CreateString (tmp));}; | |||
6072 | add_it("calleeIDNumber", "caller-callee-id-number")if ((tmp = switch_event_get_header_idx(event, "caller-callee-id-number" , -1))) { cJSON_AddItemToObject(data, "calleeIDNumber", cJSON_CreateString (tmp));}; | |||
6073 | add_it("channelUUID", "unique-id")if ((tmp = switch_event_get_header_idx(event, "unique-id", -1 ))) { cJSON_AddItemToObject(data, "channelUUID", cJSON_CreateString (tmp));}; | |||
6074 | ||||
6075 | add_it("presenceCallDirection", "presence-call-direction")if ((tmp = switch_event_get_header_idx(event, "presence-call-direction" , -1))) { cJSON_AddItemToObject(data, "presenceCallDirection" , cJSON_CreateString(tmp));}; | |||
6076 | add_it("channelPresenceID", "channel-presence-id")if ((tmp = switch_event_get_header_idx(event, "channel-presence-id" , -1))) { cJSON_AddItemToObject(data, "channelPresenceID", cJSON_CreateString (tmp));}; | |||
6077 | add_it("channelPresenceData", "channel-presence-data")if ((tmp = switch_event_get_header_idx(event, "channel-presence-data" , -1))) { cJSON_AddItemToObject(data, "channelPresenceData", cJSON_CreateString (tmp));}; | |||
6078 | ||||
6079 | for(hp = event->headers; hp; hp = hp->next) { | |||
6080 | if (!strncasecmp(hp->name, "PD-", 3)) { | |||
6081 | add_it(hp->name, hp->name)if ((tmp = switch_event_get_header_idx(event, hp->name, -1 ))) { cJSON_AddItemToObject(data, hp->name, cJSON_CreateString (tmp));}; | |||
6082 | } | |||
6083 | } | |||
6084 | ||||
6085 | switch_event_channel_broadcast(event_channel, &msg, __FILE__"mod_verto.c", NO_EVENT_CHANNEL_ID0); | |||
6086 | ||||
6087 | free(event_channel); | |||
6088 | ||||
6089 | } | |||
6090 | ||||
6091 | static void event_handler(switch_event_t *event) | |||
6092 | { | |||
6093 | cJSON *msg = NULL((void*)0), *data = NULL((void*)0); | |||
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")switch_event_get_header_idx(event, "Event-Subclass", -1); | |||
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__"mod_verto.c", NO_EVENT_CHANNEL_ID0, NULL((void*)0));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) */ | |||
6125 | SWITCH_MODULE_LOAD_FUNCTION(mod_verto_load)switch_status_t mod_verto_load (switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) | |||
6126 | { | |||
6127 | switch_api_interface_t *api_interface = NULL((void*)0); | |||
6128 | switch_chat_interface_t *chat_interface = NULL((void*)0); | |||
6129 | switch_json_api_interface_t *json_api_interface = NULL((void*)0); | |||
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_event_reserve_subclass_detailed("mod_verto.c", "verto::login" ) != SWITCH_STATUS_SUCCESS) { | |||
6136 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 6136, ((void*)0), SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_LOGIN"verto::login"); | |||
6137 | return SWITCH_STATUS_TERM; | |||
6138 | } | |||
6139 | ||||
6140 | if (switch_event_reserve_subclass(MY_EVENT_CLIENT_DISCONNECT)switch_event_reserve_subclass_detailed("mod_verto.c", "verto::client_disconnect" ) != SWITCH_STATUS_SUCCESS) { | |||
6141 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 6141, ((void*)0), SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_CLIENT_DISCONNECT"verto::client_disconnect"); | |||
6142 | return SWITCH_STATUS_TERM; | |||
6143 | } | |||
6144 | ||||
6145 | if (switch_event_reserve_subclass(MY_EVENT_CLIENT_CONNECT)switch_event_reserve_subclass_detailed("mod_verto.c", "verto::client_connect" ) != SWITCH_STATUS_SUCCESS) { | |||
6146 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 6146, ((void*)0), SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_CLIENT_CONNECT"verto::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 = SIGUSR110; | |||
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_NESTED0x1, verto_globals.pool); | |||
6159 | ||||
6160 | switch_mutex_init(&verto_globals.method_mutex, SWITCH_MUTEX_NESTED0x1, verto_globals.pool); | |||
6161 | switch_core_hash_init(&verto_globals.method_hash)switch_core_hash_init_case(&verto_globals.method_hash, SWITCH_TRUE ); | |||
6162 | ||||
6163 | switch_thread_rwlock_create(&verto_globals.event_channel_rwlock, verto_globals.pool); | |||
6164 | switch_core_hash_init(&verto_globals.event_channel_hash)switch_core_hash_init_case(&verto_globals.event_channel_hash , SWITCH_TRUE); | |||
6165 | ||||
6166 | switch_mutex_init(&verto_globals.jsock_mutex, SWITCH_MUTEX_NESTED0x1, verto_globals.pool); | |||
6167 | switch_core_hash_init(&verto_globals.jsock_hash)switch_core_hash_init_case(&verto_globals.jsock_hash, SWITCH_TRUE ); | |||
6168 | ||||
6169 | switch_thread_rwlock_create(&verto_globals.tech_rwlock, verto_globals.pool); | |||
6170 | ||||
6171 | switch_mutex_init(&verto_globals.detach_mutex, SWITCH_MUTEX_NESTED0x1, verto_globals.pool); | |||
6172 | switch_mutex_init(&verto_globals.detach2_mutex, SWITCH_MUTEX_NESTED0x1, 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_NESTED0x1, pool); | |||
6181 | switch_core_hash_init(&json_GLOBALS.store_hash)switch_core_hash_init_case(&json_GLOBALS.store_hash, SWITCH_TRUE ); | |||
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"__global__", verto_broadcast, &verto_globals.event_channel_id, NULL((void*)0)); | |||
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")for (;;) { api_interface = (switch_api_interface_t *)switch_loadable_module_create_interface (*module_interface, SWITCH_API_INTERFACE); api_interface-> interface_name = "verto"; api_interface->desc = "Verto API" ; api_interface->function = verto_function; api_interface-> syntax = "syntax"; break; }; | |||
6203 | SWITCH_ADD_API(api_interface, "verto_contact", "Generate a verto endpoint dialstring", verto_contact_function, "user@domain")for (;;) { api_interface = (switch_api_interface_t *)switch_loadable_module_create_interface (*module_interface, SWITCH_API_INTERFACE); api_interface-> interface_name = "verto_contact"; api_interface->desc = "Generate a verto endpoint dialstring" ; api_interface->function = verto_contact_function; api_interface ->syntax = "user@domain"; break; }; | |||
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, "")for (;;) { json_api_interface = (switch_json_api_interface_t * )switch_loadable_module_create_interface(*module_interface, SWITCH_JSON_API_INTERFACE ); json_api_interface->interface_name = "store"; json_api_interface ->desc = "JSON store"; json_api_interface->function = json_store_function ; json_api_interface->syntax = ""; break; }; | |||
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"verto.rtc"; | |||
6212 | verto_endpoint_interface->io_routines = &verto_io_routines; | |||
6213 | ||||
6214 | SWITCH_ADD_CHAT(chat_interface, VERTO_CHAT_PROTO, chat_send)for (;;) { chat_interface = (switch_chat_interface_t *)switch_loadable_module_create_interface (*module_interface, SWITCH_CHAT_INTERFACE); chat_interface-> chat_send = chat_send; chat_interface->interface_name = "verto" ; break; }; | |||
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((void*)0), presence_event_handler, NULL((void*)0)); | |||
6220 | } | |||
6221 | ||||
6222 | if (verto_globals.enable_fs_events) { | |||
6223 | if (switch_event_bind(modname, SWITCH_EVENT_ALL, SWITCH_EVENT_SUBCLASS_ANY((void*)0), event_handler, NULL((void*)0)) != SWITCH_STATUS_SUCCESS) { | |||
6224 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_verto.c", (const char *)__func__, 6224, ((void*)0), 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() */ | |||
6238 | SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_verto_shutdown)switch_status_t mod_verto_shutdown (void) | |||
6239 | { | |||
6240 | ||||
6241 | switch_event_free_subclass(MY_EVENT_LOGIN)switch_event_free_subclass_detailed("mod_verto.c", "verto::login" ); | |||
6242 | switch_event_free_subclass(MY_EVENT_CLIENT_DISCONNECT)switch_event_free_subclass_detailed("mod_verto.c", "verto::client_disconnect" ); | |||
6243 | switch_event_free_subclass(MY_EVENT_CLIENT_CONNECT)switch_event_free_subclass_detailed("mod_verto.c", "verto::client_connect" ); | |||
6244 | ||||
6245 | json_cleanup(); | |||
6246 | switch_core_hash_destroy(&json_GLOBALS.store_hash); | |||
6247 | ||||
6248 | switch_event_channel_unbind(NULL((void*)0), verto_broadcast, NULL((void*)0)); | |||
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 | ||||
6264 | SWITCH_MODULE_RUNTIME_FUNCTION(mod_verto_runtime)switch_status_t mod_verto_runtime (void) | |||
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)switch_sleep(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 | */ |