1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2010, Mathieu Parent <math.parent@gmail.com>
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  * Mathieu Parent <math.parent@gmail.com>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Mathieu Parent <math.parent@gmail.com>
27  *
28  *
29  * mod_skinny.c -- Skinny Call Control Protocol (SCCP) Endpoint Module
30  *
31  */
32 #include <switch.h>
33 #include "mod_skinny.h"
34 #include "skinny_protocol.h"
35 #include "skinny_server.h"
36 #include "skinny_tables.h"
37 #include "skinny_api.h"
38 
39 SWITCH_MODULE_LOAD_FUNCTION(mod_skinny_load);
40 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_skinny_shutdown);
41 
42 SWITCH_MODULE_DEFINITION(mod_skinny, mod_skinny_load, mod_skinny_shutdown, NULL);
43 
44 switch_endpoint_interface_t *skinny_endpoint_interface;
45 
46 skinny_globals_t skinny_globals;
47 
48 /*****************************************************************************/
49 /* SQL TABLES */
50 /*****************************************************************************/
51 static char devices_sql[] =
52 "CREATE TABLE skinny_devices (\n"
53 "   name             VARCHAR(16),\n"
54 "   user_id          INTEGER,\n"
55 "   instance         INTEGER,\n"
56 "   ip               VARCHAR(15),\n"
57 "   type             INTEGER,\n"
58 "   max_streams      INTEGER,\n"
59 "   port             INTEGER,\n"
60 "   codec_string     VARCHAR(255),\n"
61 "   headset          INTEGER,\n"
62 "   handset          INTEGER,\n"
63 "   speaker          INTEGER\n"
64 ");\n";
65 
66 static char lines_sql[] =
67 "CREATE TABLE skinny_lines (\n"
68 "   device_name          VARCHAR(16),\n"
69 "   device_instance      INTEGER,\n"
70 "   position             INTEGER,\n"
71 "   line_instance        INTEGER,\n"
72 "   label                VARCHAR(40),\n"
73 "   value                VARCHAR(24),\n"
74 "   caller_name          VARCHAR(44),\n"
75 "   ring_on_idle         INTEGER,\n"
76 "   ring_on_active       INTEGER,\n"
77 "   busy_trigger         INTEGER,\n"
78 "   forward_all          VARCHAR(255),\n"
79 "   forward_busy         VARCHAR(255),\n"
80 "   forward_noanswer     VARCHAR(255),\n"
81 "   noanswer_duration    INTEGER\n"
82 ");\n";
83 
84 static char buttons_sql[] =
85 "CREATE TABLE skinny_buttons (\n"
86 "   device_name      VARCHAR(16),\n"
87 "   device_instance  INTEGER,\n"
88 "   position         INTEGER,\n"
89 "   type             INTEGER,\n"
90 "   label            VARCHAR(40),\n"
91 "   value            VARCHAR(255),\n"
92 "   settings         VARCHAR(44)\n"
93 ");\n";
94 
95 static char active_lines_sql[] =
96 "CREATE TABLE skinny_active_lines (\n"
97 "   device_name      VARCHAR(16),\n"
98 "   device_instance  INTEGER,\n"
99 "   line_instance    INTEGER,\n"
100 "   channel_uuid     VARCHAR(256),\n"
101 "   call_id          INTEGER,\n"
102 "   call_state       INTEGER\n"
103 ");\n";
104 
105 /*****************************************************************************/
106 /* TEXT FUNCTIONS */
107 /*****************************************************************************/
skinny_format_message(const char * str)108 char *skinny_format_message(const char *str)
109 {
110 	char *tmp;
111 	switch_size_t i;
112 
113 	/* Look for \200, if found, next character indicates string id */
114 	char match = (char) 128;
115 
116 	tmp = switch_mprintf("");
117 
118 	if (zstr(str)) {
119 		return tmp;
120 	}
121 
122 	for (i=0; i<strlen(str); i++)
123 	{
124 		char *old = tmp;
125 
126 		if ( str[i] == match ) {
127 			if ( tmp[0] ) {
128 				tmp = switch_mprintf("%s [%s] ", old, skinny_textid2str(str[i+1]));
129 			} else {
130 				tmp = switch_mprintf("[%s] ", skinny_textid2str(str[i+1]));
131 			}
132 			switch_safe_free(old);
133 			i++;
134 		} else if ( !switch_isprint(str[i]) ) {
135 			tmp = switch_mprintf("%s\\x%.2X", old, str[i]);
136 			switch_safe_free(old);
137 		} else {
138 			tmp = switch_mprintf("%s%c", old, str[i]);
139 			switch_safe_free(old);
140 		}
141 	}
142 
143 	return tmp;
144 }
145 
146 /*****************************************************************************/
147 /* PROFILES FUNCTIONS */
148 /*****************************************************************************/
skinny_profile_dump(const skinny_profile_t * profile,switch_stream_handle_t * stream)149 switch_status_t skinny_profile_dump(const skinny_profile_t *profile, switch_stream_handle_t *stream)
150 {
151 	const char *line = "=================================================================================================";
152 	switch_assert(profile);
153 	stream->write_function(stream, "%s\n", line);
154 	/* prefs */
155 	stream->write_function(stream, "Name              \t%s\n", profile->name);
156 	stream->write_function(stream, "Domain Name       \t%s\n", profile->domain);
157 	stream->write_function(stream, "IP                \t%s\n", profile->ip);
158 	stream->write_function(stream, "Port              \t%d\n", profile->port);
159 	stream->write_function(stream, "Dialplan          \t%s\n", profile->dialplan);
160 	stream->write_function(stream, "Context           \t%s\n", profile->context);
161 	stream->write_function(stream, "Patterns-Dialplan \t%s\n", profile->patterns_dialplan);
162 	stream->write_function(stream, "Patterns-Context  \t%s\n", profile->patterns_context);
163 	stream->write_function(stream, "Keep-Alive        \t%d\n", profile->keep_alive);
164 	stream->write_function(stream, "Digit-Timeout     \t%d\n", profile->digit_timeout);
165 	stream->write_function(stream, "Date-Format       \t%s\n", profile->date_format);
166 	stream->write_function(stream, "DBName            \t%s\n", profile->dbname ? profile->dbname : switch_str_nil(profile->odbc_dsn));
167 	stream->write_function(stream, "Debug             \t%d\n", profile->debug);
168 	stream->write_function(stream, "Auto-Restart      \t%d\n", profile->auto_restart);
169 	stream->write_function(stream, "Non-Blocking      \t%d\n", profile->non_blocking);
170 	/* stats */
171 	stream->write_function(stream, "CALLS-IN          \t%d\n", profile->ib_calls);
172 	stream->write_function(stream, "FAILED-CALLS-IN   \t%d\n", profile->ib_failed_calls);
173 	stream->write_function(stream, "CALLS-OUT         \t%d\n", profile->ob_calls);
174 	stream->write_function(stream, "FAILED-CALLS-OUT  \t%d\n", profile->ob_failed_calls);
175 	/* listener */
176 	stream->write_function(stream, "Listener-Threads  \t%d\n", profile->listener_threads);
177 	stream->write_function(stream, "Ext-Voicemail     \t%s\n", profile->ext_voicemail);
178 	stream->write_function(stream, "Ext-Redial        \t%s\n", profile->ext_redial);
179 	stream->write_function(stream, "Ext-MeetMe        \t%s\n", profile->ext_meetme);
180 	stream->write_function(stream, "Ext-PickUp        \t%s\n", profile->ext_pickup);
181 	stream->write_function(stream, "Ext-CFwdAll       \t%s\n", profile->ext_cfwdall);
182 	stream->write_function(stream, "%s\n", line);
183 
184 	return SWITCH_STATUS_SUCCESS;
185 }
186 
187 
skinny_find_profile(const char * profile_name)188 skinny_profile_t *skinny_find_profile(const char *profile_name)
189 {
190 	skinny_profile_t *profile;
191 	switch_mutex_lock(skinny_globals.mutex);
192 	profile = (skinny_profile_t *) switch_core_hash_find(skinny_globals.profile_hash, profile_name);
193 	switch_mutex_unlock(skinny_globals.mutex);
194 	return profile;
195 }
196 
skinny_find_profile_by_domain(const char * domain_name)197 skinny_profile_t *skinny_find_profile_by_domain(const char *domain_name)
198 {
199 
200 	switch_hash_index_t *hi;
201 	void *val;
202 	skinny_profile_t *profile = NULL, *tmp_profile;
203 
204 	switch_mutex_lock(skinny_globals.mutex);
205 	for (hi = switch_core_hash_first(skinny_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
206 		switch_core_hash_this(hi, NULL, NULL, &val);
207 		tmp_profile = (skinny_profile_t *) val;
208 
209 		switch_mutex_lock(tmp_profile->listener_mutex);
210 		if (!strcmp(tmp_profile->domain, domain_name)) {
211 			profile = tmp_profile;
212 		}
213 		switch_mutex_unlock(tmp_profile->listener_mutex);
214 		if (profile) {
215 			break;
216 		}
217 	}
218 	switch_safe_free(hi);
219 	switch_mutex_unlock(skinny_globals.mutex);
220 
221 	return profile;
222 }
223 
skinny_profile_find_listener_by_device_name(skinny_profile_t * profile,const char * device_name,listener_t ** listener)224 switch_status_t skinny_profile_find_listener_by_device_name(skinny_profile_t *profile, const char *device_name, listener_t **listener)
225 {
226 	listener_t *l;
227 
228 	switch_mutex_lock(profile->listener_mutex);
229 	for (l = profile->listeners; l; l = l->next) {
230 		if (!strcmp(l->device_name, device_name)) {
231 			*listener = l;
232 		}
233 	}
234 	switch_mutex_unlock(profile->listener_mutex);
235 
236 	return SWITCH_STATUS_SUCCESS;
237 }
238 
skinny_profile_find_listener_by_device_name_and_instance(skinny_profile_t * profile,const char * device_name,uint32_t device_instance,listener_t ** listener)239 switch_status_t skinny_profile_find_listener_by_device_name_and_instance(skinny_profile_t *profile, const char *device_name, uint32_t device_instance, listener_t **listener)
240 {
241 	listener_t *l;
242 
243 	switch_mutex_lock(profile->listener_mutex);
244 	for (l = profile->listeners; l; l = l->next) {
245 		if (!strcmp(l->device_name, device_name) && (l->device_instance == device_instance)) {
246 			*listener = l;
247 		}
248 	}
249 	switch_mutex_unlock(profile->listener_mutex);
250 
251 	return SWITCH_STATUS_SUCCESS;
252 }
253 
254 struct skinny_profile_find_session_uuid_helper {
255 	skinny_profile_t *profile;
256 	char *channel_uuid;
257 	uint32_t line_instance;
258 };
259 
skinny_profile_find_session_uuid_callback(void * pArg,int argc,char ** argv,char ** columnNames)260 int skinny_profile_find_session_uuid_callback(void *pArg, int argc, char **argv, char **columnNames)
261 {
262 	struct skinny_profile_find_session_uuid_helper *helper = pArg;
263 
264 	char *channel_uuid = argv[0];
265 	uint32_t line_instance = atoi(argv[1]);
266 
267 	if(helper->channel_uuid == NULL) {
268 		helper->channel_uuid = switch_mprintf("%s", channel_uuid);
269 		helper->line_instance = line_instance;
270 	}
271 
272 	return 0;
273 }
274 
skinny_profile_find_session_uuid(skinny_profile_t * profile,listener_t * listener,uint32_t * line_instance_p,uint32_t call_id)275 char * skinny_profile_find_session_uuid(skinny_profile_t *profile, listener_t *listener, uint32_t *line_instance_p, uint32_t call_id)
276 {
277 	struct skinny_profile_find_session_uuid_helper helper = {0};
278 	char *sql;
279 	char *device_condition = NULL;
280 	char *line_instance_condition = NULL;
281 	char *call_id_condition = NULL;
282 
283 	switch_assert(profile);
284 	helper.profile = profile;
285 	helper.channel_uuid = NULL;
286 
287 	if(listener) {
288 		device_condition = switch_mprintf("device_name='%q' AND device_instance=%d",
289 				listener->device_name, listener->device_instance);
290 	} else {
291 		device_condition = switch_mprintf("1=1");
292 	}
293 	switch_assert(device_condition);
294 	if(*line_instance_p > 0) {
295 		line_instance_condition = switch_mprintf("line_instance=%d", *line_instance_p);
296 	} else {
297 		line_instance_condition = switch_mprintf("1=1");
298 	}
299 	switch_assert(line_instance_condition);
300 	if(call_id > 0) {
301 		call_id_condition = switch_mprintf("call_id=%d", call_id);
302 	} else {
303 		call_id_condition = switch_mprintf("1=1");
304 	}
305 	switch_assert(call_id_condition);
306 
307 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
308 					"Attempting to find active call with criteria (%s and %s and %s)\n",
309 					device_condition, line_instance_condition, call_id_condition);
310 
311 	if((sql = switch_mprintf(
312 					"SELECT channel_uuid, line_instance "
313 					"FROM skinny_active_lines "
314 					"WHERE %s AND %s AND %s "
315 					"ORDER BY call_state, channel_uuid", /* off hook first */
316 					device_condition, line_instance_condition, call_id_condition
317 				))) {
318 		skinny_execute_sql_callback(profile, profile->sql_mutex, sql,
319 				skinny_profile_find_session_uuid_callback, &helper);
320 		switch_safe_free(sql);
321 	}
322 	switch_safe_free(device_condition);
323 	switch_safe_free(line_instance_condition);
324 	switch_safe_free(call_id_condition);
325 	*line_instance_p = helper.line_instance;
326 	return helper.channel_uuid;
327 }
328 
329 #ifdef SWITCH_DEBUG_RWLOCKS
skinny_profile_perform_find_session(skinny_profile_t * profile,listener_t * listener,uint32_t * line_instance_p,uint32_t call_id,const char * file,const char * func,int line)330 switch_core_session_t * skinny_profile_perform_find_session(skinny_profile_t *profile, listener_t *listener, uint32_t *line_instance_p, uint32_t call_id, const char *file, const char *func, int line)
331 #else
332 switch_core_session_t * skinny_profile_find_session(skinny_profile_t *profile, listener_t *listener, uint32_t *line_instance_p, uint32_t call_id)
333 #endif
334 {
335 	char *uuid;
336 	switch_core_session_t *result = NULL;
337 	uuid = skinny_profile_find_session_uuid(profile, listener, line_instance_p, call_id);
338 
339 	if(!zstr(uuid)) {
340 #ifdef SWITCH_DEBUG_RWLOCKS
341 		result = switch_core_session_perform_locate(uuid, file, func, line);
342 #else
343 		result = switch_core_session_locate(uuid);
344 #endif
345 		if(!result) {
346 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
347 					"Unable to find session %s on %s:%d, line %d\n",
348 					uuid, listener->device_name, listener->device_instance, *line_instance_p);
349 		}
350 		switch_safe_free(uuid);
351 	}
352 	return result;
353 }
354 
355 /*****************************************************************************/
356 /* SQL FUNCTIONS */
357 /*****************************************************************************/
skinny_get_db_handle(skinny_profile_t * profile)358 switch_cache_db_handle_t *skinny_get_db_handle(skinny_profile_t *profile)
359 {
360 	switch_cache_db_handle_t *dbh = NULL;
361 	char *dsn;
362 
363 	if (!zstr(profile->odbc_dsn)) {
364 		dsn = profile->odbc_dsn;
365 	} else {
366 		dsn = profile->dbname;
367 	}
368 
369 	if (switch_cache_db_get_db_handle_dsn(&dbh, dsn) != SWITCH_STATUS_SUCCESS) {
370 		dbh = NULL;
371 	}
372 
373 	return dbh;
374 
375 }
376 
377 
skinny_execute_sql(skinny_profile_t * profile,char * sql,switch_mutex_t * mutex)378 switch_status_t skinny_execute_sql(skinny_profile_t *profile, char *sql, switch_mutex_t *mutex)
379 {
380 	switch_cache_db_handle_t *dbh = NULL;
381 	switch_status_t status = SWITCH_STATUS_FALSE;
382 
383 	if (mutex) {
384 		switch_mutex_lock(mutex);
385 	}
386 
387 	if (!(dbh = skinny_get_db_handle(profile))) {
388 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n");
389 		goto end;
390 	}
391 
392 	status = switch_cache_db_execute_sql(dbh, sql, NULL);
393 
394 end:
395 
396 	switch_cache_db_release_db_handle(&dbh);
397 
398 	if (mutex) {
399 		switch_mutex_unlock(mutex);
400 	}
401 
402 	return status;
403 }
404 
skinny_execute_sql_callback(skinny_profile_t * profile,switch_mutex_t * mutex,char * sql,switch_core_db_callback_func_t callback,void * pdata)405 switch_bool_t skinny_execute_sql_callback(skinny_profile_t *profile, switch_mutex_t *mutex, char *sql, switch_core_db_callback_func_t callback,
406 		void *pdata)
407 {
408 	switch_bool_t ret = SWITCH_FALSE;
409 	char *errmsg = NULL;
410 	switch_cache_db_handle_t *dbh = NULL;
411 
412 	if (mutex) {
413 		switch_mutex_lock(mutex);
414 	}
415 
416 	if (!(dbh = skinny_get_db_handle(profile))) {
417 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n");
418 		goto end;
419 	}
420 
421 	switch_cache_db_execute_sql_callback(dbh, sql, callback, pdata, &errmsg);
422 
423 	if (errmsg) {
424 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR: [%s] %s\n", sql, errmsg);
425 		free(errmsg);
426 	}
427 
428 end:
429 
430 	switch_cache_db_release_db_handle(&dbh);
431 
432 	if (mutex) {
433 		switch_mutex_unlock(mutex);
434 	}
435 
436 	return ret;
437 }
438 
439 /*****************************************************************************/
440 /* CHANNEL FUNCTIONS */
441 /*****************************************************************************/
skinny_line_perform_set_state(const char * file,const char * func,int line,listener_t * listener,uint32_t line_instance,uint32_t call_id,uint32_t call_state)442 void skinny_line_perform_set_state(const char *file, const char *func, int line, listener_t *listener, uint32_t line_instance, uint32_t call_id, uint32_t call_state)
443 {
444 	switch_event_t *event = NULL;
445 	switch_assert(listener);
446 
447 	skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_CALL_STATE);
448 	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Line-Instance", "%d", line_instance);
449 	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Call-Id", "%d", call_id);
450 	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Call-State", "%d", call_state);
451 	switch_event_fire(&event);
452 	send_call_state(listener, call_state, line_instance, call_id);
453 
454 	skinny_log_l_ffl(listener, file, func, line, SWITCH_LOG_DEBUG,
455 			"Line %d, Call %d Change State to %s (%d)\n",
456 			line_instance, call_id,
457 			skinny_call_state2str(call_state), call_state);
458 }
459 
460 
461 struct skinny_line_get_state_helper {
462 	uint32_t call_state;
463 };
464 
skinny_line_get_state_callback(void * pArg,int argc,char ** argv,char ** columnNames)465 int skinny_line_get_state_callback(void *pArg, int argc, char **argv, char **columnNames)
466 {
467 	struct skinny_line_get_state_helper *helper = pArg;
468 	if (helper->call_state == -1) {
469 		helper->call_state = atoi(argv[0]);
470 	}
471 	return 0;
472 }
473 
skinny_line_get_state(listener_t * listener,uint32_t line_instance,uint32_t call_id)474 uint32_t skinny_line_get_state(listener_t *listener, uint32_t line_instance, uint32_t call_id)
475 {
476 	char *line_instance_condition;
477 	char *call_id_condition;
478 	char *sql;
479 	struct skinny_line_get_state_helper helper = {0};
480 
481 	switch_assert(listener);
482 
483 	if(line_instance > 0) {
484 		line_instance_condition = switch_mprintf("line_instance=%d", line_instance);
485 	} else {
486 		line_instance_condition = switch_mprintf("1=1");
487 	}
488 	switch_assert(line_instance_condition);
489 	if(call_id > 0) {
490 		call_id_condition = switch_mprintf("call_id=%d", call_id);
491 	} else {
492 		call_id_condition = switch_mprintf("1=1");
493 	}
494 	switch_assert(call_id_condition);
495 
496 	helper.call_state = -1;
497 	if ((sql = switch_mprintf(
498 					"SELECT call_state FROM skinny_active_lines "
499 					"WHERE device_name='%q' AND device_instance=%d "
500 					"AND %s AND %s "
501 					"ORDER BY call_state, channel_uuid", /* off hook first */
502 					listener->device_name, listener->device_instance,
503 					line_instance_condition, call_id_condition
504 				 ))) {
505 		skinny_execute_sql_callback(listener->profile, listener->profile->sql_mutex, sql, skinny_line_get_state_callback, &helper);
506 		switch_safe_free(sql);
507 	}
508 	switch_safe_free(line_instance_condition);
509 	switch_safe_free(call_id_condition);
510 
511 	return helper.call_state;
512 }
513 
514 struct skinny_line_count_active_helper {
515 	uint32_t count;
516 };
517 
skinny_line_count_active_callback(void * pArg,int argc,char ** argv,char ** columnNames)518 int skinny_line_count_active_callback(void *pArg, int argc, char **argv, char **columnNames)
519 {
520 	struct skinny_line_count_active_helper *helper = pArg;
521 	helper->count++;
522 	return 0;
523 }
524 
skinny_line_count_active(listener_t * listener)525 uint32_t skinny_line_count_active(listener_t *listener)
526 {
527 	char *sql;
528 	struct skinny_line_count_active_helper helper = {0};
529 
530 	switch_assert(listener);
531 
532 	helper.count = 0;
533 	if ((sql = switch_mprintf(
534 			"SELECT call_state FROM skinny_active_lines "
535 			"WHERE device_name='%q' AND device_instance=%d "
536 			"AND call_state not in (%d,%d,%d)",
537 			listener->device_name, listener->device_instance,
538 			SKINNY_ON_HOOK, SKINNY_IN_USE_REMOTELY, SKINNY_HOLD
539 			))) {
540 
541 		skinny_execute_sql_callback(listener->profile, listener->profile->sql_mutex, sql, skinny_line_count_active_callback, &helper);
542 		switch_safe_free(sql);
543 	}
544 
545 	return helper.count;
546 }
547 
skinny_tech_set_codec(private_t * tech_pvt,int force)548 switch_status_t skinny_tech_set_codec(private_t *tech_pvt, int force)
549 {
550 	switch_status_t status = SWITCH_STATUS_SUCCESS;
551 	switch_channel_t *channel = switch_core_session_get_channel(tech_pvt->session);
552 	int resetting = 0;
553 
554 	if (!tech_pvt->iananame) {
555 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "No audio codec available\n");
556 		switch_goto_status(SWITCH_STATUS_FALSE, end);
557 	}
558 
559 	if (switch_core_codec_ready(&tech_pvt->read_codec)) {
560 		if (!force) {
561 			switch_goto_status(SWITCH_STATUS_SUCCESS, end);
562 		}
563 		if (strcasecmp(tech_pvt->read_impl.iananame, tech_pvt->iananame) ||
564 				tech_pvt->read_impl.samples_per_second != tech_pvt->rm_rate ||
565 				tech_pvt->codec_ms != (uint32_t)tech_pvt->read_impl.microseconds_per_packet / 1000) {
566 
567 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Changing Codec from %s@%dms to %s@%dms\n",
568 					tech_pvt->read_impl.iananame, tech_pvt->read_impl.microseconds_per_packet / 1000,
569 					tech_pvt->rm_encoding, tech_pvt->codec_ms);
570 
571 			switch_core_session_lock_codec_write(tech_pvt->session);
572 			switch_core_session_lock_codec_read(tech_pvt->session);
573 			resetting = 1;
574 			switch_core_codec_destroy(&tech_pvt->read_codec);
575 			switch_core_codec_destroy(&tech_pvt->write_codec);
576 		} else {
577 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Already using %s\n", tech_pvt->read_impl.iananame);
578 			switch_goto_status(SWITCH_STATUS_SUCCESS, end);
579 		}
580 	}
581 
582 	if (switch_core_codec_init(&tech_pvt->read_codec,
583 							   tech_pvt->iananame,
584 							   NULL,
585 							   tech_pvt->rm_fmtp,
586 							   tech_pvt->rm_rate,
587 							   tech_pvt->codec_ms,
588 							   1,
589 							   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | 0 /* TODO tech_pvt->profile->codec_flags */,
590 							   NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
591 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n");
592 		switch_goto_status(SWITCH_STATUS_FALSE, end);
593 	}
594 
595 	if (switch_core_codec_init(&tech_pvt->write_codec,
596 							   tech_pvt->iananame,
597 							   NULL,
598 							   tech_pvt->rm_fmtp,
599 							   tech_pvt->rm_rate,
600 							   tech_pvt->codec_ms,
601 							   1,
602 							   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | 0 /* TODO tech_pvt->profile->codec_flags */,
603 							   NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
604 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n");
605 		switch_goto_status(SWITCH_STATUS_FALSE, end);
606 	}
607 
608 	switch_assert(tech_pvt->read_codec.implementation);
609 	switch_assert(tech_pvt->write_codec.implementation);
610 
611 	tech_pvt->read_impl = *tech_pvt->read_codec.implementation;
612 	tech_pvt->write_impl = *tech_pvt->write_codec.implementation;
613 
614 	switch_core_session_set_read_impl(tech_pvt->session, tech_pvt->read_codec.implementation);
615 	switch_core_session_set_write_impl(tech_pvt->session, tech_pvt->write_codec.implementation);
616 
617 	if (switch_rtp_ready(tech_pvt->rtp_session)) {
618 		switch_assert(tech_pvt->read_codec.implementation);
619 
620 		if (switch_rtp_change_interval(tech_pvt->rtp_session,
621 					tech_pvt->read_impl.microseconds_per_packet,
622 					tech_pvt->read_impl.samples_per_packet
623 					) != SWITCH_STATUS_SUCCESS) {
624 			switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
625 			switch_goto_status(SWITCH_STATUS_FALSE, end);
626 		}
627 	}
628 
629 	tech_pvt->read_frame.rate = tech_pvt->rm_rate;
630 	//ms = tech_pvt->write_codec.implementation->microseconds_per_packet / 1000;
631 
632 	if (!switch_core_codec_ready(&tech_pvt->read_codec)) {
633 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Can't load codec?\n");
634 		switch_goto_status(SWITCH_STATUS_FALSE, end);
635 	}
636 
637 	switch_channel_set_flag(channel, CF_AUDIO);
638 
639 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Set Codec %s %s/%ld %d ms %d samples\n",
640 					  switch_channel_get_name(channel), tech_pvt->iananame, tech_pvt->rm_rate, tech_pvt->codec_ms,
641 			tech_pvt->read_impl.samples_per_packet);
642 	tech_pvt->read_frame.codec = &tech_pvt->read_codec;
643 
644 	tech_pvt->write_codec.agreed_pt = tech_pvt->agreed_pt;
645 	tech_pvt->read_codec.agreed_pt = tech_pvt->agreed_pt;
646 
647 	if (force != 2) {
648 		switch_core_session_set_read_codec(tech_pvt->session, &tech_pvt->read_codec);
649 		switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec);
650 	}
651 
652 	/* TODO
653 	   tech_pvt->fmtp_out = switch_core_session_strdup(tech_pvt->session, tech_pvt->write_codec.fmtp_out);
654 	 */
655 
656 	/* TODO
657 	   if (switch_rtp_ready(tech_pvt->rtp_session)) {
658 	   switch_rtp_set_default_payload(tech_pvt->rtp_session, tech_pvt->pt);
659 	   }
660 	 */
661 
662 end:
663 	if (resetting) {
664 		switch_core_session_unlock_codec_write(tech_pvt->session);
665 		switch_core_session_unlock_codec_read(tech_pvt->session);
666 	}
667 
668 	return status;
669 }
670 
tech_init(private_t * tech_pvt,skinny_profile_t * profile,switch_core_session_t * session)671 void tech_init(private_t *tech_pvt, skinny_profile_t *profile, switch_core_session_t *session)
672 {
673 	switch_assert(tech_pvt);
674 	switch_assert(session);
675 
676 	tech_pvt->read_frame.data = tech_pvt->databuf;
677 	tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf);
678 	switch_mutex_init(&tech_pvt->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
679 	switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
680 	tech_pvt->profile = profile;
681 	tech_pvt->call_id = ++profile->next_call_id;
682 	tech_pvt->party_id = tech_pvt->call_id;
683 	switch_core_session_set_private(session, tech_pvt);
684 	tech_pvt->session = session;
685 }
686 
687 /*
688    State methods they get called when the state changes to the specific state
689    returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
690    so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
691  */
channel_on_init(switch_core_session_t * session)692 switch_status_t channel_on_init(switch_core_session_t *session)
693 {
694 	switch_channel_t *channel = switch_core_session_get_channel(session);
695 
696 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL INIT\n", switch_channel_get_name(channel));
697 
698 	/* This does not set the state to routing like most modules do, this now happens in the default state handeler so return FALSE TO BLOCK IT*/
699 	return SWITCH_STATUS_FALSE;
700 }
701 
702 struct channel_on_routing_helper {
703 	private_t *tech_pvt;
704 	listener_t *listener;
705 	uint32_t line_instance;
706 };
707 
channel_on_routing_callback(void * pArg,int argc,char ** argv,char ** columnNames)708 int channel_on_routing_callback(void *pArg, int argc, char **argv, char **columnNames)
709 {
710 	struct channel_on_routing_helper *helper = pArg;
711 	listener_t *listener = NULL;
712 	char *label;
713 
714 	char *device_name = argv[0];
715 	uint32_t device_instance = atoi(argv[1]);
716 	/* uint32_t position = atoi(argv[2]); */
717 	uint32_t line_instance = atoi(argv[3]);
718 	/* char *label = argv[4]; */
719 	/* char *value = argv[5]; */
720 	/* char *caller_name = argv[6]; */
721 	/* uint32_t ring_on_idle = atoi(argv[7]); */
722 	/* uint32_t ring_on_active = atoi(argv[8]); */
723 	/* uint32_t busy_trigger = atoi(argv[9]); */
724 	/* char *forward_all = argv[10]; */
725 	/* char *forward_busy = argv[11]; */
726 	/* char *forward_noanswer = argv[12]; */
727 	/* uint32_t noanswer_duration = atoi(argv[13]); */
728 	/* char *channel_uuid = argv[14]; */
729 	/* uint32_t call_id = atoi(argv[15]); */
730 	/* uint32_t call_state = atoi(argv[16]); */
731 
732 	skinny_profile_find_listener_by_device_name_and_instance(helper->tech_pvt->profile, device_name, device_instance, &listener);
733 	if(listener) {
734 		if(!strcmp(device_name, helper->listener->device_name)
735 				&& (device_instance == helper->listener->device_instance)
736 				&& (line_instance == helper->line_instance)) {/* the calling line */
737 			helper->tech_pvt->caller_profile->dialplan = switch_core_strdup(helper->tech_pvt->caller_profile->pool, listener->profile->dialplan);
738 			helper->tech_pvt->caller_profile->context = switch_core_strdup(helper->tech_pvt->caller_profile->pool, listener->profile->context);
739 			send_dialed_number(listener, helper->tech_pvt->caller_profile->destination_number, line_instance, helper->tech_pvt->call_id);
740 			skinny_line_set_state(listener, line_instance, helper->tech_pvt->call_id, SKINNY_PROCEED);
741 			skinny_session_send_call_info(helper->tech_pvt->session, listener, line_instance);
742 			skinny_session_ring_out(helper->tech_pvt->session, listener, line_instance);
743 		} else {
744 			send_set_lamp(listener, SKINNY_BUTTON_LINE, line_instance, SKINNY_LAMP_ON);
745 			skinny_line_set_state(listener, line_instance, helper->tech_pvt->call_id, SKINNY_IN_USE_REMOTELY);
746 			send_select_soft_keys(listener, line_instance, helper->tech_pvt->call_id, SKINNY_KEY_SET_IN_USE_HINT, 0xffff);
747 
748 			label = skinny_textid2raw(SKINNY_TEXTID_IN_USE_REMOTE);
749 			send_display_prompt_status(listener, 0, label, line_instance, helper->tech_pvt->call_id);
750 			switch_safe_free(label);
751 
752 			skinny_session_send_call_info(helper->tech_pvt->session, listener, line_instance);
753 		}
754 	}
755 	return 0;
756 }
757 
channel_on_routing(switch_core_session_t * session)758 switch_status_t channel_on_routing(switch_core_session_t *session)
759 {
760 	switch_channel_t *channel = switch_core_session_get_channel(session);
761 	if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
762 		skinny_action_t action;
763 		private_t *tech_pvt = switch_core_session_get_private(session);
764 		char *data = NULL;
765 		listener_t *listener = NULL;
766 		struct channel_on_routing_helper helper = {0};
767 		int digit_timeout;
768 
769 		if(switch_test_flag(tech_pvt, TFLAG_FORCE_ROUTE)) {
770 			action = SKINNY_ACTION_PROCESS;
771 		} else {
772 			action = skinny_session_dest_match_pattern(session, &data);
773 		}
774 		switch(action) {
775 			case SKINNY_ACTION_PROCESS:
776 				skinny_profile_find_listener_by_device_name_and_instance(tech_pvt->profile,
777 						switch_channel_get_variable(channel, "skinny_device_name"),
778 						atoi(switch_channel_get_variable(channel, "skinny_device_instance")), &listener);
779 				if (listener) {
780 					helper.tech_pvt = tech_pvt;
781 					helper.listener = listener;
782 					helper.line_instance = atoi(switch_channel_get_variable(channel, "skinny_line_instance"));
783 					skinny_session_walk_lines(tech_pvt->profile, switch_core_session_get_uuid(session), channel_on_routing_callback, &helper);
784 
785 					/* clear digit timeout time */
786 					listener->digit_timeout_time = 0;
787 				} else {
788 					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Could not find listener %s:%s for Channel %s\n",
789 							switch_channel_get_variable(channel, "skinny_device_name"), switch_channel_get_variable(channel, "skinny_device_instance"),
790 							switch_channel_get_name(channel));
791 				}
792 
793 				/* Future bridge should go straight */
794 				switch_set_flag_locked(tech_pvt, TFLAG_FORCE_ROUTE);
795 				break;
796 			case SKINNY_ACTION_WAIT:
797 				/* for now, wait forever */
798 				switch_channel_set_state(channel, CS_HIBERNATE);
799 				skinny_profile_find_listener_by_device_name_and_instance(tech_pvt->profile,
800 						switch_channel_get_variable(channel, "skinny_device_name"),
801 						atoi(switch_channel_get_variable(channel, "skinny_device_instance")), &listener);
802 
803 				if (listener) {
804 					digit_timeout = listener->profile->digit_timeout;
805 					if (!zstr(data)) {
806 						digit_timeout = atoi(data);
807 						if ( digit_timeout < 100 ) {
808 							digit_timeout *= 1000;
809 						}
810 					}
811 
812 					listener->digit_timeout_time = switch_mono_micro_time_now() + digit_timeout * 1000;
813 				} else {
814 					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Could not find listener %s:%s for Channel %s\n",
815 							switch_channel_get_variable(channel, "skinny_device_name"), switch_channel_get_variable(channel, "skinny_device_instance"),
816 							switch_channel_get_name(channel));
817 
818 				}
819 
820 				break;
821 			case SKINNY_ACTION_DROP:
822 			default:
823 				switch_channel_hangup(channel, SWITCH_CAUSE_UNALLOCATED_NUMBER);
824 		}
825 	}
826 
827 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL ROUTING\n", switch_channel_get_name(channel));
828 
829 	return SWITCH_STATUS_SUCCESS;
830 }
831 
832 struct channel_on_execute_helper {
833 	private_t *tech_pvt;
834 	listener_t *listener;
835 	uint32_t line_instance;
836 };
837 
channel_on_execute_callback(void * pArg,int argc,char ** argv,char ** columnNames)838 int channel_on_execute_callback(void *pArg, int argc, char **argv, char **columnNames)
839 {
840 	struct channel_on_routing_helper *helper = pArg;
841 	listener_t *listener = NULL;
842 
843 	char *device_name = argv[0];
844 	uint32_t device_instance = atoi(argv[1]);
845 	/* uint32_t position = atoi(argv[2]); */
846 	uint32_t line_instance = atoi(argv[3]);
847 	/* char *label = argv[4]; */
848 	/* char *value = argv[5]; */
849 	/* char *caller_name = argv[6]; */
850 	/* uint32_t ring_on_idle = atoi(argv[7]); */
851 	/* uint32_t ring_on_active = atoi(argv[8]); */
852 	/* uint32_t busy_trigger = atoi(argv[9]); */
853 	/* char *forward_all = argv[10]; */
854 	/* char *forward_busy = argv[11]; */
855 	/* char *forward_noanswer = argv[12]; */
856 	/* uint32_t noanswer_duration = atoi(argv[13]); */
857 	/* char *channel_uuid = argv[14]; */
858 	/* uint32_t call_id = atoi(argv[15]); */
859 	/* uint32_t call_state = atoi(argv[16]); */
860 
861 	skinny_profile_find_listener_by_device_name_and_instance(helper->tech_pvt->profile, device_name, device_instance, &listener);
862 	if(listener) {
863 		if(!strcmp(device_name, helper->listener->device_name)
864 				&& (device_instance == helper->listener->device_instance)
865 				&& (line_instance == helper->line_instance)) {/* the calling line */
866 			helper->tech_pvt->caller_profile->dialplan = switch_core_strdup(helper->tech_pvt->caller_profile->pool, listener->profile->dialplan);
867 			helper->tech_pvt->caller_profile->context = switch_core_strdup(helper->tech_pvt->caller_profile->pool, listener->profile->context);
868 
869 			send_stop_tone(listener, line_instance, helper->tech_pvt->call_id);
870 		} else {
871 		}
872 	}
873 	return 0;
874 }
875 
channel_on_execute(switch_core_session_t * session)876 switch_status_t channel_on_execute(switch_core_session_t *session)
877 {
878 	switch_channel_t *channel = switch_core_session_get_channel(session);
879 
880 	if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
881 		private_t *tech_pvt = switch_core_session_get_private(session);
882 		listener_t *listener = NULL;
883 		struct channel_on_execute_helper helper = {0};
884 
885 		skinny_profile_find_listener_by_device_name_and_instance(tech_pvt->profile,
886 				switch_channel_get_variable(channel, "skinny_device_name"),
887 				atoi(switch_channel_get_variable(channel, "skinny_device_instance")), &listener);
888 		if (listener) {
889 			helper.tech_pvt = tech_pvt;
890 			helper.listener = listener;
891 			helper.line_instance = atoi(switch_channel_get_variable(channel, "skinny_line_instance"));
892 			skinny_session_walk_lines(tech_pvt->profile, switch_core_session_get_uuid(session), channel_on_execute_callback, &helper);
893 		} else {
894 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Could not find listener %s:%s for Channel %s\n",
895 					switch_channel_get_variable(channel, "skinny_device_name"), switch_channel_get_variable(channel, "skinny_device_instance"),
896 					switch_channel_get_name(channel));
897 		}
898 	}
899 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL EXECUTE\n", switch_channel_get_name(channel));
900 
901 	return SWITCH_STATUS_SUCCESS;
902 }
903 
channel_on_destroy(switch_core_session_t * session)904 switch_status_t channel_on_destroy(switch_core_session_t *session)
905 {
906 	switch_channel_t *channel = switch_core_session_get_channel(session);
907 	private_t *tech_pvt = switch_core_session_get_private(session);
908 
909 	if (tech_pvt) {
910 		if (switch_core_codec_ready(&tech_pvt->read_codec)) {
911 			switch_core_codec_destroy(&tech_pvt->read_codec);
912 		}
913 
914 		if (switch_core_codec_ready(&tech_pvt->write_codec)) {
915 			switch_core_codec_destroy(&tech_pvt->write_codec);
916 		}
917 
918 		if (switch_rtp_ready(tech_pvt->rtp_session)) {
919 			switch_rtp_destroy(&tech_pvt->rtp_session);
920 		}
921 	}
922 
923 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL DESTROY\n", switch_channel_get_name(channel));
924 
925 	return SWITCH_STATUS_SUCCESS;
926 }
927 
928 struct skinny_ring_active_calls_helper {
929 	private_t *tech_pvt;
930 	listener_t *listener;
931 };
932 
skinny_ring_active_calls_callback(void * pArg,int argc,char ** argv,char ** columnNames)933 int skinny_ring_active_calls_callback(void *pArg, int argc, char **argv, char **columnNames)
934 {
935 	struct skinny_ring_active_calls_helper *helper = pArg;
936 	switch_core_session_t *session;
937 
938 	/* char *device_name = argv[0]; */
939 	/* uint32_t device_instance = atoi(argv[1]); */
940 	/* uint32_t position = atoi(argv[2]); */
941 	uint32_t line_instance = atoi(argv[3]);
942 	/* char *label = argv[4]; */
943 	/* char *value = argv[5]; */
944 	/* char *caller_name = argv[6]; */
945 	uint32_t ring_on_idle = atoi(argv[7]);
946 	/* uint32_t ring_on_active = atoi(argv[8]); */
947 	/* uint32_t busy_trigger = atoi(argv[9]); */
948 	/* char *forward_all = argv[10]; */
949 	/* char *forward_busy = argv[11]; */
950 	/* char *forward_noanswer = argv[12]; */
951 	/* uint32_t noanswer_duration = atoi(argv[13]); */
952 	/* char *channel_uuid = argv[14]; */
953 	uint32_t call_id = atoi(argv[15]);
954 	/* uint32_t call_state = atoi(argv[16]); */
955 
956 	session = skinny_profile_find_session(helper->listener->profile, helper->listener, &line_instance, call_id);
957 
958 	if(session) {
959 		/* After going on-hook, start ringing if there is an active call in the SKINNY_RING_IN state */
960 		skinny_log_l(helper->listener, SWITCH_LOG_DEBUG, "Start Ringer for active Call ID (%d), Line Instance (%d), Line State (%d).\n", call_id, line_instance, skinny_line_get_state(helper->listener,line_instance, call_id));
961 
962 		send_set_lamp(helper->listener, SKINNY_BUTTON_LINE, line_instance, SKINNY_LAMP_BLINK);
963 
964 		if ( ring_on_idle ) {
965 			send_set_ringer(helper->listener, SKINNY_RING_INSIDE, SKINNY_RING_FOREVER, line_instance, call_id);
966 		} else {
967 			send_set_ringer(helper->listener, SKINNY_RING_FLASHONLY, SKINNY_RING_FOREVER, line_instance, call_id);
968 		}
969 
970 		switch_core_session_rwunlock(session);
971 	}
972 
973 	return 0;
974 }
975 
skinny_ring_active_calls(listener_t * listener)976 switch_status_t skinny_ring_active_calls(listener_t *listener)
977 /* Look for all SKINNY active calls in the SKINNY_RING_IN state and tell them to start ringing */
978 {
979 	struct skinny_ring_active_calls_helper helper = {0};
980 	char *sql;
981 
982 	helper.listener = listener;
983 
984 	if ((sql = switch_mprintf(
985                     "SELECT skinny_lines.*, channel_uuid, call_id, call_state "
986                     "FROM skinny_active_lines "
987                     "INNER JOIN skinny_lines "
988                     "ON skinny_active_lines.device_name = skinny_lines.device_name "
989                     "AND skinny_active_lines.device_instance = skinny_lines.device_instance "
990                     "AND skinny_active_lines.line_instance = skinny_lines.line_instance "
991                     "WHERE skinny_lines.device_name='%q' AND skinny_lines.device_instance=%d "
992                     "AND (call_state=%d)",
993                     listener->device_name, listener->device_instance, SKINNY_RING_IN))) {
994 		skinny_execute_sql_callback(listener->profile, listener->profile->sql_mutex, sql, skinny_ring_active_calls_callback, &helper);
995 		switch_safe_free(sql);
996 	}
997 
998 	return SWITCH_STATUS_SUCCESS;
999 }
1000 
1001 struct channel_on_hangup_helper {
1002 	private_t *tech_pvt;
1003 	switch_call_cause_t cause;
1004 };
1005 
channel_on_hangup_callback(void * pArg,int argc,char ** argv,char ** columnNames)1006 int channel_on_hangup_callback(void *pArg, int argc, char **argv, char **columnNames)
1007 {
1008 	struct channel_on_hangup_helper *helper = pArg;
1009 	listener_t *listener = NULL;
1010 	char *label;
1011 
1012 	char *device_name = argv[0];
1013 	uint32_t device_instance = atoi(argv[1]);
1014 	/* uint32_t position = atoi(argv[2]); */
1015 	uint32_t line_instance = atoi(argv[3]);
1016 	/* char *label = argv[4]; */
1017 	/* char *value = argv[5]; */
1018 	/* char *caller_name = argv[6]; */
1019 	/* uint32_t ring_on_idle = atoi(argv[7]); */
1020 	/* uint32_t ring_on_active = atoi(argv[8]); */
1021 	/* uint32_t busy_trigger = atoi(argv[9]); */
1022 	/* char *forward_all = argv[10]; */
1023 	/* char *forward_busy = argv[11]; */
1024 	/* char *forward_noanswer = argv[12]; */
1025 	/* uint32_t noanswer_duration = atoi(argv[13]); */
1026 	/* char *channel_uuid = argv[14]; */
1027 	uint32_t call_id = atoi(argv[15]);
1028 	uint32_t call_state = atoi(argv[16]);
1029 
1030 	skinny_profile_find_listener_by_device_name_and_instance(helper->tech_pvt->profile, device_name, device_instance, &listener);
1031 	if(listener) {
1032 		if((call_state == SKINNY_PROCEED) || (call_state == SKINNY_CONNECTED)) { /* calling parties */
1033 			send_stop_tone(listener, line_instance, call_id);
1034 			send_set_lamp(listener, SKINNY_BUTTON_LINE, line_instance, SKINNY_LAMP_OFF);
1035 			send_clear_prompt_status(listener, line_instance, call_id);
1036 		}
1037 		send_set_lamp(listener, SKINNY_BUTTON_LINE, line_instance, SKINNY_LAMP_OFF);
1038 
1039 		if((call_state == SKINNY_PROCEED) || (call_state == SKINNY_RING_OUT) || (call_state == SKINNY_CONNECTED)) { /* calling parties */
1040 			switch (helper->cause) {
1041 				case SWITCH_CAUSE_UNALLOCATED_NUMBER:
1042 					send_start_tone(listener, SKINNY_TONE_REORDER, 0, line_instance, call_id);
1043 					skinny_session_send_call_info(helper->tech_pvt->session, listener, line_instance);
1044 					label = skinny_textid2raw(SKINNY_TEXTID_UNKNOWN_NUMBER);
1045 					send_display_prompt_status(listener, 0, label, line_instance, call_id);
1046 					switch_safe_free(label);
1047 					break;
1048 				case SWITCH_CAUSE_USER_BUSY:
1049 					send_start_tone(listener, SKINNY_TONE_BUSYTONE, 0, line_instance, call_id);
1050 					label = skinny_textid2raw(SKINNY_TEXTID_BUSY);
1051 					send_display_prompt_status(listener, 0, label, line_instance, call_id);
1052 					switch_safe_free(label);
1053 					break;
1054 				case SWITCH_CAUSE_NORMAL_CLEARING:
1055 					send_clear_prompt_status(listener, line_instance, call_id);
1056 					break;
1057 				default:
1058 					send_display_prompt_status(listener, 0, switch_channel_cause2str(helper->cause), line_instance, call_id);
1059 			}
1060 
1061 			skinny_session_stop_media(helper->tech_pvt->session, listener, line_instance);
1062 		}
1063 
1064 		skinny_line_set_state(listener, line_instance, call_id, SKINNY_ON_HOOK);
1065 		send_select_soft_keys(listener, line_instance, call_id, SKINNY_KEY_SET_ON_HOOK, 0xffff);
1066 		send_define_current_time_date(listener);
1067 		listener->digit_timeout_time = 0;
1068 
1069 		skinny_log_ls(listener, helper->tech_pvt->session, SWITCH_LOG_DEBUG,
1070 			"channel_on_hangup_callback - cause=%s [%d], call_state = %s [%d]\n",
1071 			switch_channel_cause2str(helper->cause), helper->cause,
1072 			skinny_call_state2str(call_state), call_state);
1073 
1074 		if ( call_state == SKINNY_RING_OUT && helper->cause == SWITCH_CAUSE_USER_BUSY )
1075 		{
1076 			// don't hang up speaker here
1077 		}
1078 		else if((call_state == SKINNY_PROCEED) || (call_state == SKINNY_RING_OUT) || (call_state == SKINNY_CONNECTED)) { /* calling parties */
1079 			// This is NOT correct, but results in slightly better behavior than before
1080 			// leaving note here to revisit.
1081 
1082 			/* re-enabling for testing to bring back bad behavior */
1083 			send_set_speaker_mode(listener, SKINNY_SPEAKER_OFF);
1084 		}
1085 		send_set_ringer(listener, SKINNY_RING_OFF, SKINNY_RING_FOREVER, line_instance, call_id);
1086 
1087         /* After hanging up this call, activate the ringer for any other active incoming calls */
1088         skinny_ring_active_calls(listener);
1089 	}
1090 	return 0;
1091 }
1092 
channel_on_hangup(switch_core_session_t * session)1093 switch_status_t channel_on_hangup(switch_core_session_t *session)
1094 {
1095 	struct channel_on_hangup_helper helper = {0};
1096 	switch_channel_t *channel = switch_core_session_get_channel(session);
1097 	switch_call_cause_t cause = switch_channel_get_cause(channel);
1098 	private_t *tech_pvt = switch_core_session_get_private(session);
1099 	char *sql;
1100 
1101 	switch_clear_flag_locked(tech_pvt, TFLAG_IO);
1102 
1103 	skinny_log_s(session, SWITCH_LOG_DEBUG, "%s CHANNEL HANGUP [%s]\n",
1104 		switch_channel_get_name(channel), switch_channel_cause2str(cause));
1105 
1106 	helper.tech_pvt= tech_pvt;
1107 	helper.cause= cause;
1108 
1109 	skinny_session_walk_lines(tech_pvt->profile, switch_core_session_get_uuid(session), channel_on_hangup_callback, &helper);
1110 	if ((sql = switch_mprintf(
1111 					"DELETE FROM skinny_active_lines WHERE channel_uuid='%q'",
1112 					switch_core_session_get_uuid(session)
1113 				 ))) {
1114 		skinny_execute_sql(tech_pvt->profile, sql, tech_pvt->profile->sql_mutex);
1115 		switch_safe_free(sql);
1116 	}
1117 	return SWITCH_STATUS_SUCCESS;
1118 }
1119 
channel_kill_channel(switch_core_session_t * session,int sig)1120 switch_status_t channel_kill_channel(switch_core_session_t *session, int sig)
1121 {
1122 	switch_channel_t *channel = switch_core_session_get_channel(session);
1123 	private_t *tech_pvt = switch_core_session_get_private(session);
1124 
1125 	switch (sig) {
1126 		case SWITCH_SIG_KILL:
1127 			switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
1128 			break;
1129 		case SWITCH_SIG_BREAK:
1130 			if (switch_rtp_ready(tech_pvt->rtp_session)) {
1131 				switch_rtp_break(tech_pvt->rtp_session);
1132 			}
1133 			break;
1134 		default:
1135 			break;
1136 	}
1137 
1138 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL KILL %d\n", switch_channel_get_name(channel), sig);
1139 
1140 	return SWITCH_STATUS_SUCCESS;
1141 }
1142 
channel_on_exchange_media(switch_core_session_t * session)1143 switch_status_t channel_on_exchange_media(switch_core_session_t *session)
1144 {
1145 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "CHANNEL LOOPBACK\n");
1146 	return SWITCH_STATUS_SUCCESS;
1147 }
1148 
channel_on_soft_execute(switch_core_session_t * session)1149 switch_status_t channel_on_soft_execute(switch_core_session_t *session)
1150 {
1151 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "CHANNEL TRANSMIT\n");
1152 	return SWITCH_STATUS_SUCCESS;
1153 }
1154 
channel_send_dtmf(switch_core_session_t * session,const switch_dtmf_t * dtmf)1155 switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf)
1156 {
1157 	private_t *tech_pvt = switch_core_session_get_private(session);
1158 	switch_assert(tech_pvt != NULL);
1159 
1160 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "DTMF ON CALL %d [%c]\n", tech_pvt->call_id, dtmf->digit);
1161 
1162 	return SWITCH_STATUS_SUCCESS;
1163 }
1164 
channel_read_frame(switch_core_session_t * session,switch_frame_t ** frame,switch_io_flag_t flags,int stream_id)1165 switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
1166 {
1167 	switch_channel_t *channel = switch_core_session_get_channel(session);
1168 	private_t *tech_pvt = switch_core_session_get_private(session);
1169 
1170 	while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session))) {
1171 		if (switch_channel_ready(channel)) {
1172 			switch_yield(10000);
1173 		} else {
1174 			return SWITCH_STATUS_GENERR;
1175 		}
1176 	}
1177 
1178 	tech_pvt->read_frame.datalen = 0;
1179 	switch_set_flag_locked(tech_pvt, TFLAG_READING);
1180 
1181 	if (switch_test_flag(tech_pvt, TFLAG_IO)) {
1182 		switch_status_t status;
1183 
1184 		switch_assert(tech_pvt->rtp_session != NULL);
1185 		tech_pvt->read_frame.datalen = 0;
1186 
1187 
1188 		while (switch_test_flag(tech_pvt, TFLAG_IO) && tech_pvt->read_frame.datalen == 0) {
1189 			tech_pvt->read_frame.flags = SFF_NONE;
1190 
1191 			status = switch_rtp_zerocopy_read_frame(tech_pvt->rtp_session, &tech_pvt->read_frame, flags);
1192 			if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
1193 				return SWITCH_STATUS_FALSE;
1194 			}
1195 
1196 			//payload = tech_pvt->read_frame.payload;
1197 
1198 			if (switch_rtp_has_dtmf(tech_pvt->rtp_session)) {
1199 				switch_dtmf_t dtmf = { 0 };
1200 				switch_rtp_dequeue_dtmf(tech_pvt->rtp_session, &dtmf);
1201 				switch_channel_queue_dtmf(channel, &dtmf);
1202 			}
1203 
1204 
1205 			if (tech_pvt->read_frame.datalen > 0) {
1206 				size_t bytes = 0;
1207 				int frames = 1;
1208 
1209 				if (!switch_test_flag((&tech_pvt->read_frame), SFF_CNG)) {
1210 					if ((bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_packet)) {
1211 						frames = (tech_pvt->read_frame.datalen / bytes);
1212 					}
1213 					tech_pvt->read_frame.samples = (int) (frames * tech_pvt->read_codec.implementation->samples_per_packet);
1214 				}
1215 				break;
1216 			}
1217 		}
1218 	}
1219 
1220 	switch_clear_flag_locked(tech_pvt, TFLAG_READING);
1221 
1222 	if (tech_pvt->read_frame.datalen == 0) {
1223 		*frame = NULL;
1224 		return SWITCH_STATUS_GENERR;
1225 	}
1226 
1227 	*frame = &tech_pvt->read_frame;
1228 
1229 	return SWITCH_STATUS_SUCCESS;
1230 }
1231 
channel_write_frame(switch_core_session_t * session,switch_frame_t * frame,switch_io_flag_t flags,int stream_id)1232 switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
1233 {
1234 	private_t *tech_pvt = switch_core_session_get_private(session);
1235 	//switch_frame_t *pframe;
1236 	switch_status_t status = SWITCH_STATUS_SUCCESS;
1237 
1238 	if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
1239 		return SWITCH_STATUS_FALSE;
1240 	}
1241 	switch_set_flag_locked(tech_pvt, TFLAG_WRITING);
1242 
1243 	switch_rtp_write_frame(tech_pvt->rtp_session, frame);
1244 
1245 	switch_clear_flag_locked(tech_pvt, TFLAG_WRITING);
1246 
1247 	return status;
1248 
1249 }
1250 
channel_answer_channel(switch_core_session_t * session)1251 switch_status_t channel_answer_channel(switch_core_session_t *session)
1252 {
1253 	switch_channel_t *channel = switch_core_session_get_channel(session);
1254 	private_t *tech_pvt = switch_core_session_get_private(session);
1255 	listener_t *listener = NULL;
1256 
1257 	skinny_profile_find_listener_by_device_name_and_instance(tech_pvt->profile,
1258 			switch_channel_get_variable(channel, "skinny_device_name"),
1259 			atoi(switch_channel_get_variable(channel, "skinny_device_instance")), &listener);
1260 	if (listener) {
1261 		int x = 0;
1262 		skinny_session_start_media(session, listener, atoi(switch_channel_get_variable(channel, "skinny_line_instance")));
1263 		/* Wait for media */
1264 		while(!switch_test_flag(tech_pvt, TFLAG_IO)) {
1265 			switch_cond_next();
1266 			if (++x > 5000) {
1267 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Wait tooo long to answer %s:%s\n",
1268 						switch_channel_get_variable(channel, "skinny_device_name"), switch_channel_get_variable(channel, "skinny_device_instance"));
1269 				return SWITCH_STATUS_FALSE;
1270 			}
1271 		}
1272 	} else {
1273 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Unable to find listener to answer %s:%s\n",
1274 				switch_channel_get_variable(channel, "skinny_device_name"), switch_channel_get_variable(channel, "skinny_device_instance"));
1275 	}
1276 	return SWITCH_STATUS_SUCCESS;
1277 }
1278 
1279 
channel_receive_message(switch_core_session_t * session,switch_core_session_message_t * msg)1280 switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
1281 {
1282 	private_t *tech_pvt = switch_core_session_get_private(session);
1283 
1284 	switch (msg->message_id) {
1285 		case SWITCH_MESSAGE_INDICATE_ANSWER:
1286 			switch_clear_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
1287 			return channel_answer_channel(session);
1288 
1289 		case SWITCH_MESSAGE_INDICATE_DISPLAY:
1290 			skinny_session_send_call_info_all(session);
1291 			return SWITCH_STATUS_SUCCESS;
1292 
1293 		case SWITCH_MESSAGE_INDICATE_PROGRESS:
1294 			if (!switch_test_flag(tech_pvt, TFLAG_EARLY_MEDIA)) {
1295 				/* early media */
1296 				switch_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
1297 				return channel_answer_channel(session);
1298 			}
1299 			return SWITCH_STATUS_SUCCESS;
1300 
1301 		default:
1302 			return SWITCH_STATUS_SUCCESS;
1303 
1304 	}
1305 
1306 }
1307 
1308 /* Make sure when you have 2 sessions in the same scope that you pass the appropriate one to the routines
1309    that allocate memory or you will have 1 channel with memory allocated from another channel's pool!
1310  */
channel_outgoing_channel(switch_core_session_t * session,switch_event_t * var_event,switch_caller_profile_t * outbound_profile,switch_core_session_t ** new_session,switch_memory_pool_t ** pool,switch_originate_flag_t flags,switch_call_cause_t * cancel_cause)1311 switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
1312 		switch_caller_profile_t *outbound_profile,
1313 		switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags, switch_call_cause_t *cancel_cause)
1314 {
1315 	switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
1316 	switch_core_session_t *nsession = NULL;
1317 	private_t *tech_pvt;
1318 
1319 	char *profile_name, *dest;
1320 	skinny_profile_t *profile = NULL;
1321 	char *sql;
1322 	char name[128];
1323 	switch_channel_t *nchannel;
1324 	switch_caller_profile_t *caller_profile;
1325 
1326 	if (!outbound_profile || zstr(outbound_profile->destination_number)) {
1327 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Invalid Destination\n");
1328 		goto error;
1329 	}
1330 
1331 	if (!(nsession = switch_core_session_request(skinny_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, flags, pool))) {
1332 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Creating Session\n");
1333 		goto error;
1334 	}
1335 
1336 	if (!(tech_pvt = (struct private_object *) switch_core_session_alloc(nsession, sizeof(*tech_pvt)))) {
1337 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Error Creating Session private object\n");
1338 		goto error;
1339 	}
1340 
1341 	if(!(profile_name = switch_core_session_strdup(nsession, outbound_profile->destination_number))) {
1342 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Error Creating Session Info\n");
1343 		goto error;
1344 	}
1345 
1346 	if (!(dest = strchr(profile_name, '/'))) {
1347 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid Skinny URL. Should be skinny/<profile>/<number>.\n");
1348 		cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
1349 		goto error;
1350 	}
1351 	*dest++ = '\0';
1352 
1353 	if (!(profile = skinny_find_profile(profile_name))) {
1354 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid Profile %s\n", profile_name);
1355 		cause = SWITCH_CAUSE_UNALLOCATED_NUMBER;
1356 		goto error;
1357 	}
1358 
1359 	snprintf(name, sizeof(name), "SKINNY/%s/%s", profile->name, dest);
1360 
1361 	nchannel = switch_core_session_get_channel(nsession);
1362 	switch_channel_set_name(nchannel, name);
1363 
1364 	tech_init(tech_pvt, profile, nsession);
1365 
1366 	caller_profile = switch_caller_profile_clone(nsession, outbound_profile);
1367 	switch_channel_set_caller_profile(nchannel, caller_profile);
1368 	tech_pvt->caller_profile = caller_profile;
1369 
1370 	if ((sql = switch_mprintf(
1371 					"INSERT INTO skinny_active_lines "
1372 					"(device_name, device_instance, line_instance, channel_uuid, call_id, call_state) "
1373 					"SELECT device_name, device_instance, line_instance, '%q', %d, %d "
1374 					"FROM skinny_lines "
1375 					"WHERE value='%q'",
1376 					switch_core_session_get_uuid(nsession), tech_pvt->call_id, SKINNY_ON_HOOK, dest
1377 				 ))) {
1378 		skinny_execute_sql(profile, sql, profile->sql_mutex);
1379 		switch_safe_free(sql);
1380 	}
1381 
1382 	/* FIXME: ring_lines need BOND before switch_core_session_outgoing_channel() set it */
1383 	if (session) {
1384 		switch_channel_set_variable(switch_core_session_get_channel(session), SWITCH_SIGNAL_BOND_VARIABLE, switch_core_session_get_uuid(nsession));
1385 		switch_channel_set_variable(nchannel, SWITCH_SIGNAL_BOND_VARIABLE, switch_core_session_get_uuid(session));
1386 	}
1387 
1388 	cause = skinny_ring_lines(tech_pvt, session);
1389 
1390 	if(cause != SWITCH_CAUSE_SUCCESS) {
1391 		goto error;
1392 	}
1393 
1394 	*new_session = nsession;
1395 
1396 	/* ?? switch_channel_mark_ring_ready(channel); */
1397 
1398 	if (switch_channel_get_state(nchannel) == CS_NEW) {
1399 		switch_channel_set_state(nchannel, CS_INIT);
1400 	}
1401 
1402 	cause = SWITCH_CAUSE_SUCCESS;
1403 	goto done;
1404 
1405 error:
1406 	if (nsession) {
1407 		switch_core_session_destroy(&nsession);
1408 	}
1409 
1410 	if (pool) {
1411 		*pool = NULL;
1412 	}
1413 
1414 
1415 done:
1416 
1417 	if (profile) {
1418 		if (cause == SWITCH_CAUSE_SUCCESS) {
1419 			profile->ob_calls++;
1420 		} else {
1421 			profile->ob_failed_calls++;
1422 		}
1423 	}
1424 	return cause;
1425 }
1426 
channel_receive_event(switch_core_session_t * session,switch_event_t * event)1427 switch_status_t channel_receive_event(switch_core_session_t *session, switch_event_t *event)
1428 {
1429 	return SWITCH_STATUS_SUCCESS;
1430 }
1431 
1432 
1433 
1434 switch_state_handler_table_t skinny_state_handlers = {
1435 	/*.on_init */ channel_on_init,
1436 	/*.on_routing */ channel_on_routing,
1437 	/*.on_execute */ channel_on_execute,
1438 	/*.on_hangup */ channel_on_hangup,
1439 	/*.on_exchange_media */ channel_on_exchange_media,
1440 	/*.on_soft_execute */ channel_on_soft_execute,
1441 	/*.on_consume_media*/ NULL,
1442 	/*.on_hibernate*/ NULL,
1443 	/*.on_reset*/ NULL,
1444 	/*.on_park*/ NULL,
1445 	/*.on_reporting*/ NULL,
1446 	/*.on_destroy*/ channel_on_destroy
1447 
1448 };
1449 
1450 switch_io_routines_t skinny_io_routines = {
1451 	/*.outgoing_channel */ channel_outgoing_channel,
1452 	/*.read_frame */ channel_read_frame,
1453 	/*.write_frame */ channel_write_frame,
1454 	/*.kill_channel */ channel_kill_channel,
1455 	/*.send_dtmf */ channel_send_dtmf,
1456 	/*.receive_message */ channel_receive_message,
1457 	/*.receive_event */ channel_receive_event
1458 };
1459 
1460 /*****************************************************************************/
1461 /* LISTENER FUNCTIONS */
1462 /*****************************************************************************/
1463 
listener_is_ready(listener_t * listener)1464 uint8_t listener_is_ready(listener_t *listener)
1465 {
1466 	return skinny_globals.running
1467 		&& listener
1468 		&& listener->sock
1469 		&& switch_test_flag(listener, LFLAG_RUNNING)
1470 		&& switch_test_flag(listener->profile, PFLAG_LISTENER_READY)
1471 		&& !switch_test_flag(listener->profile, PFLAG_RESPAWN);
1472 }
1473 
add_listener(listener_t * listener)1474 static void add_listener(listener_t *listener)
1475 {
1476 	skinny_profile_t *profile;
1477 	switch_assert(listener);
1478 	assert(listener->profile);
1479 	profile = listener->profile;
1480 
1481 	switch_mutex_lock(profile->listener_mutex);
1482 	listener->next = profile->listeners;
1483 	profile->listeners = listener;
1484 	switch_mutex_unlock(profile->listener_mutex);
1485 }
1486 
remove_listener(listener_t * listener)1487 static void remove_listener(listener_t *listener)
1488 {
1489 	listener_t *l, *last = NULL;
1490 	skinny_profile_t *profile;
1491 	switch_assert(listener);
1492 	assert(listener->profile);
1493 	profile = listener->profile;
1494 
1495 	switch_mutex_lock(profile->listener_mutex);
1496 	for (l = profile->listeners; l; l = l->next) {
1497 		if (l == listener) {
1498 			if (last) {
1499 				last->next = l->next;
1500 			} else {
1501 				profile->listeners = l->next;
1502 			}
1503 		}
1504 		last = l;
1505 	}
1506 	switch_mutex_unlock(profile->listener_mutex);
1507 }
1508 
1509 
walk_listeners(skinny_listener_callback_func_t callback,void * pvt)1510 static void walk_listeners(skinny_listener_callback_func_t callback, void *pvt)
1511 {
1512 	switch_hash_index_t *hi;
1513 	void *val;
1514 	skinny_profile_t *profile;
1515 
1516 	/* walk listeners */
1517 	switch_mutex_lock(skinny_globals.mutex);
1518 	for (hi = switch_core_hash_first(skinny_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
1519 		switch_core_hash_this(hi, NULL, NULL, &val);
1520 		profile = (skinny_profile_t *) val;
1521 
1522 		profile_walk_listeners(profile, callback, pvt);
1523 	}
1524 	switch_mutex_unlock(skinny_globals.mutex);
1525 }
1526 
flush_listener_callback(void * pArg,int argc,char ** argv,char ** columnNames)1527 static int flush_listener_callback(void *pArg, int argc, char **argv, char **columnNames)
1528 {
1529 	char *profile_name = argv[0];
1530 	char *value = argv[1];
1531 	char *domain_name = argv[2];
1532 	char *device_name = argv[3];
1533 	char *device_instance = argv[4];
1534 
1535 	char *token = switch_mprintf("skinny/%q/%q/%q:%q", profile_name, value, device_name, device_instance);
1536 	switch_core_del_registration(value, domain_name, token);
1537 	switch_safe_free(token);
1538 
1539 	return 0;
1540 }
1541 
skinny_lock_device_name(listener_t * listener,char * device_name)1542 void skinny_lock_device_name(listener_t *listener, char *device_name)
1543 {
1544 	switch_time_t started = 0;
1545 	unsigned int elapsed = 0;
1546 	device_name_lock_t *dnl;
1547 
1548 	if ( listener->profile->debug >= 9 ) {
1549 		skinny_log_l(listener, SWITCH_LOG_DEBUG, "lock device name '%s'\n", device_name);
1550 	}
1551 
1552 	started = switch_micro_time_now();
1553 
1554 	/* global mutex on hash operations */
1555 	switch_mutex_lock(listener->profile->device_name_lock_mutex);
1556 
1557 	dnl = (device_name_lock_t *) switch_core_hash_find(listener->profile->device_name_lock_hash, device_name);
1558 	if ( ! dnl ) {
1559 		if ( listener->profile->debug >= 9 ) {
1560 			skinny_log_l(listener, SWITCH_LOG_DEBUG, "creating device name lock for device name '%s'\n", device_name);
1561 		}
1562 		dnl = switch_core_alloc(listener->profile->pool, sizeof(*dnl));
1563 		switch_mutex_init(&dnl->flag_mutex, SWITCH_MUTEX_NESTED, listener->profile->pool);
1564 		switch_core_hash_insert(listener->profile->device_name_lock_hash, device_name, dnl);
1565 	}
1566 
1567 	switch_mutex_unlock(listener->profile->device_name_lock_mutex);
1568 
1569 	if ( listener->profile->debug >= 9 ) {
1570 		skinny_log_l(listener, SWITCH_LOG_DEBUG, "setting device name lock for device name '%s'\n", device_name);
1571 	}
1572 	switch_set_flag_locked(dnl, DNLFLAG_INUSE);
1573 
1574 	if ((elapsed = (unsigned int) ((switch_micro_time_now() - started) / 1000)) > 5) {
1575 		skinny_log_l(listener, SWITCH_LOG_DEBUG, "device name lock took more than 5ms for '%s' (%d)\n", device_name, elapsed);
1576 	}
1577 
1578 	if ( listener->profile->debug >= 9 ) {
1579 		skinny_log_l(listener, SWITCH_LOG_DEBUG, "locked device name '%s'\n", device_name);
1580 	}
1581 }
1582 
skinny_unlock_device_name(listener_t * listener,char * device_name)1583 void skinny_unlock_device_name(listener_t *listener, char *device_name)
1584 {
1585 	switch_time_t started = 0;
1586 	unsigned int elapsed = 0;
1587 	device_name_lock_t *dnl;
1588 
1589 	if ( listener->profile->debug >= 9 ) {
1590 		skinny_log_l(listener, SWITCH_LOG_DEBUG, "unlock device name '%s'\n", device_name);
1591 	}
1592 
1593 	started = switch_micro_time_now();
1594 
1595 	/* global mutex on hash operations */
1596 	switch_mutex_lock(listener->profile->device_name_lock_mutex);
1597 	dnl = (device_name_lock_t *) switch_core_hash_find(listener->profile->device_name_lock_hash, device_name);
1598 	switch_mutex_unlock(listener->profile->device_name_lock_mutex);
1599 
1600 	if ( ! dnl ) {
1601 		skinny_log_l(listener, SWITCH_LOG_WARNING, "request to unlock and no lock structure for '%s'\n", device_name);
1602 		/* since it didn't exist, nothing to unlock, don't bother creating structure now */
1603 	} else {
1604 		if ( listener->profile->debug >= 9 ) {
1605 			skinny_log_l(listener, SWITCH_LOG_DEBUG, "clearing device name lock on '%s'\n", device_name);
1606 		}
1607 		switch_clear_flag_locked(dnl, DNLFLAG_INUSE);
1608 	}
1609 
1610 	/* Should we clean up the lock structure here, or does it ever get reclaimed? I don't think memory is released
1611 		so attempting to clear it up here likely would just result in a leak. */
1612 
1613 	if ((elapsed = (unsigned int) ((switch_micro_time_now() - started) / 1000)) > 5) {
1614 		skinny_log_l(listener, SWITCH_LOG_DEBUG, "device name unlock took more than 5ms for '%s' (%d)\n", device_name, elapsed);
1615 	}
1616 
1617 	if ( listener->profile->debug >= 9 ) {
1618 		skinny_log_l(listener, SWITCH_LOG_DEBUG, "unlocked device name '%s'\n", device_name);
1619 	}
1620 }
1621 
skinny_clean_device_from_db(listener_t * listener,char * device_name)1622 void skinny_clean_device_from_db(listener_t *listener, char *device_name)
1623 {
1624 	if(!zstr(device_name)) {
1625 		skinny_profile_t *profile = listener->profile;
1626 		char *sql;
1627 
1628 		skinny_log_l(listener, SWITCH_LOG_DEBUG,
1629 			"Clean device from DB with name '%s'\n",
1630 			device_name);
1631 
1632 		if ((sql = switch_mprintf(
1633 						"DELETE FROM skinny_devices "
1634 						"WHERE name='%q'",
1635 						device_name))) {
1636 			skinny_execute_sql(profile, sql, profile->sql_mutex);
1637 			switch_safe_free(sql);
1638 		}
1639 
1640 		if ((sql = switch_mprintf(
1641 						"DELETE FROM skinny_lines "
1642 						"WHERE device_name='%q'",
1643 						device_name))) {
1644 			skinny_execute_sql(profile, sql, profile->sql_mutex);
1645 			switch_safe_free(sql);
1646 		}
1647 
1648 		if ((sql = switch_mprintf(
1649 						"DELETE FROM skinny_buttons "
1650 						"WHERE device_name='%q'",
1651 						device_name))) {
1652 			skinny_execute_sql(profile, sql, profile->sql_mutex);
1653 			switch_safe_free(sql);
1654 		}
1655 
1656 		if ((sql = switch_mprintf(
1657 						"DELETE FROM skinny_active_lines "
1658 						"WHERE device_name='%q'",
1659 						device_name))) {
1660 			skinny_execute_sql(profile, sql, profile->sql_mutex);
1661 			switch_safe_free(sql);
1662 		}
1663 
1664 	} else {
1665 		skinny_log_l_msg(listener, SWITCH_LOG_DEBUG,
1666 			"Clean device from DB, missing device name.\n");
1667 	}
1668 }
1669 
skinny_clean_listener_from_db(listener_t * listener)1670 void skinny_clean_listener_from_db(listener_t *listener)
1671 {
1672 	if(!zstr(listener->device_name)) {
1673 		skinny_profile_t *profile = listener->profile;
1674 		char *sql;
1675 
1676 		skinny_log_l(listener, SWITCH_LOG_DEBUG,
1677 			"Clean listener from DB with name '%s' and instance '%d'\n",
1678 			listener->device_name, listener->device_instance);
1679 
1680 		if ((sql = switch_mprintf(
1681 						"DELETE FROM skinny_devices "
1682 						"WHERE name='%q' and instance=%d",
1683 						listener->device_name, listener->device_instance))) {
1684 			skinny_execute_sql(profile, sql, profile->sql_mutex);
1685 			switch_safe_free(sql);
1686 		}
1687 
1688 		if ((sql = switch_mprintf(
1689 						"DELETE FROM skinny_lines "
1690 						"WHERE device_name='%q' and device_instance=%d",
1691 						listener->device_name, listener->device_instance))) {
1692 			skinny_execute_sql(profile, sql, profile->sql_mutex);
1693 			switch_safe_free(sql);
1694 		}
1695 
1696 		if ((sql = switch_mprintf(
1697 						"DELETE FROM skinny_buttons "
1698 						"WHERE device_name='%q' and device_instance=%d",
1699 						listener->device_name, listener->device_instance))) {
1700 			skinny_execute_sql(profile, sql, profile->sql_mutex);
1701 			switch_safe_free(sql);
1702 		}
1703 
1704 		if ((sql = switch_mprintf(
1705 						"DELETE FROM skinny_active_lines "
1706 						"WHERE device_name='%q' and device_instance=%d",
1707 						listener->device_name, listener->device_instance))) {
1708 			skinny_execute_sql(profile, sql, profile->sql_mutex);
1709 			switch_safe_free(sql);
1710 		}
1711 
1712 	} else {
1713 		skinny_log_l_msg(listener, SWITCH_LOG_DEBUG,
1714 			"Clean listener from DB, missing device name.\n");
1715 	}
1716 }
1717 
flush_listener(listener_t * listener)1718 static void flush_listener(listener_t *listener)
1719 {
1720 
1721 	if(!zstr(listener->device_name)) {
1722 		skinny_profile_t *profile = listener->profile;
1723 		char *sql;
1724 
1725 		if ((sql = switch_mprintf(
1726 						"SELECT '%q', value, '%q', '%q', '%d' "
1727 						"FROM skinny_lines "
1728 						"WHERE device_name='%q' AND device_instance=%d "
1729 						"ORDER BY position",
1730 						profile->name, profile->domain, listener->device_name, listener->device_instance,
1731 						listener->device_name, listener->device_instance
1732 					 ))) {
1733 			skinny_execute_sql_callback(profile, profile->sql_mutex, sql, flush_listener_callback, NULL);
1734 			switch_safe_free(sql);
1735 		}
1736 
1737 		skinny_lock_device_name(listener, listener->device_name);
1738 		skinny_clean_listener_from_db(listener);
1739 		skinny_unlock_device_name(listener, listener->device_name);
1740 
1741 		strcpy(listener->device_name, "");
1742 	}
1743 }
1744 
dump_device_callback(void * pArg,int argc,char ** argv,char ** columnNames)1745 static int dump_device_callback(void *pArg, int argc, char **argv, char **columnNames)
1746 {
1747 	switch_stream_handle_t *stream = (switch_stream_handle_t *) pArg;
1748 
1749 	char *device_name = argv[0];
1750 	char *user_id = argv[1];
1751 	char *instance = argv[2];
1752 	char *ip = argv[3];
1753 	char *type = argv[4];
1754 	char *max_streams = argv[5];
1755 	char *port = argv[6];
1756 	char *codec_string = argv[7];
1757 	char *headset = argv[8];
1758 	char *handset = argv[9];
1759 	char *speaker = argv[10];
1760 
1761 	const char *line = "=================================================================================================";
1762 	stream->write_function(stream, "%s\n", line);
1763 	stream->write_function(stream, "DeviceName    \t%s\n", switch_str_nil(device_name));
1764 	stream->write_function(stream, "UserId        \t%s\n", user_id);
1765 	stream->write_function(stream, "Instance      \t%s\n", instance);
1766 	stream->write_function(stream, "IP            \t%s\n", ip);
1767 	stream->write_function(stream, "DeviceTypeId  \t%s\n", type);
1768 	stream->write_function(stream, "DeviceType    \t%s\n", skinny_device_type2str(atoi(type)));
1769 	stream->write_function(stream, "MaxStreams    \t%s\n", max_streams);
1770 	stream->write_function(stream, "Port          \t%s\n", port);
1771 	stream->write_function(stream, "Codecs        \t%s\n", codec_string);
1772 	stream->write_function(stream, "HeadsetId     \t%s\n", headset);
1773 	if (headset) {
1774 		stream->write_function(stream, "Headset       \t%s\n", skinny_accessory_state2str(atoi(headset)));
1775 	}
1776 	stream->write_function(stream, "HandsetId     \t%s\n", handset);
1777 	if (handset) {
1778 		stream->write_function(stream, "Handset       \t%s\n", skinny_accessory_state2str(atoi(handset)));
1779 	}
1780 	stream->write_function(stream, "SpeakerId     \t%s\n", speaker);
1781 	if (speaker) {
1782 		stream->write_function(stream, "Speaker       \t%s\n", skinny_accessory_state2str(atoi(speaker)));
1783 	}
1784 	stream->write_function(stream, "%s\n", line);
1785 
1786 	return 0;
1787 }
1788 
dump_device(skinny_profile_t * profile,const char * device_name,switch_stream_handle_t * stream)1789 switch_status_t dump_device(skinny_profile_t *profile, const char *device_name, switch_stream_handle_t *stream)
1790 {
1791 	char *sql;
1792 	if ((sql = switch_mprintf("SELECT name, user_id, instance, ip, type, max_streams, port, codec_string, headset, handset, speaker "
1793 					"FROM skinny_devices WHERE name='%q'",
1794 					device_name))) {
1795 		skinny_execute_sql_callback(profile, profile->sql_mutex, sql, dump_device_callback, stream);
1796 		switch_safe_free(sql);
1797 	}
1798 
1799 	return SWITCH_STATUS_SUCCESS;
1800 }
1801 
1802 
close_socket(switch_socket_t ** sock,skinny_profile_t * profile)1803 static void close_socket(switch_socket_t **sock, skinny_profile_t *profile)
1804 {
1805 	switch_mutex_lock(profile->sock_mutex);
1806 	if (*sock) {
1807 		switch_socket_shutdown(*sock, SWITCH_SHUTDOWN_READWRITE);
1808 		switch_socket_close(*sock);
1809 		*sock = NULL;
1810 	}
1811 	switch_mutex_unlock(profile->sock_mutex);
1812 }
1813 
kill_listener(listener_t * listener,void * pvt)1814 switch_status_t kill_listener(listener_t *listener, void *pvt)
1815 {
1816 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Killing listener %s:%d.\n",
1817 			listener->device_name, listener->device_instance);
1818 	switch_clear_flag_locked(listener, LFLAG_RUNNING);
1819 	close_socket(&listener->sock, listener->profile);
1820 	return SWITCH_STATUS_SUCCESS;
1821 }
1822 
keepalive_listener(listener_t * listener,void * pvt)1823 switch_status_t keepalive_listener(listener_t *listener, void *pvt)
1824 {
1825 	skinny_profile_t *profile;
1826 	switch_assert(listener);
1827 	assert(listener->profile);
1828 	profile = listener->profile;
1829 
1830 	listener->expire_time = switch_epoch_time_now(NULL)+profile->keep_alive*110/100;
1831 
1832 	return SWITCH_STATUS_SUCCESS;
1833 }
1834 
listener_digit_timeout(listener_t * listener)1835 switch_status_t listener_digit_timeout(listener_t *listener)
1836 {
1837 	switch_core_session_t *session = NULL;
1838 	uint32_t line_instance = 1;
1839 	uint32_t call_id = 0;
1840 	switch_channel_t *channel = NULL;
1841 	private_t *tech_pvt = NULL;
1842 
1843 	listener->digit_timeout_time = 0;
1844 
1845 	session = skinny_profile_find_session(listener->profile, listener, &line_instance, call_id);
1846 	if ( !session )
1847 	{
1848 		line_instance = 0;
1849 		session = skinny_profile_find_session(listener->profile, listener, &line_instance, 0);
1850 	}
1851 
1852 	if ( !session)
1853 		return SWITCH_STATUS_FALSE;
1854 
1855 	channel = switch_core_session_get_channel(session);
1856 	tech_pvt = switch_core_session_get_private(session);
1857 
1858 	if (channel && tech_pvt->session) {
1859 		switch_set_flag_locked(tech_pvt, TFLAG_FORCE_ROUTE);
1860 		switch_channel_set_state(channel, CS_ROUTING);
1861 		listener->digit_timeout_time = 0;
1862 	}
1863 
1864 	switch_core_session_rwunlock(session);
1865 
1866 	return SWITCH_STATUS_SUCCESS;
1867 }
1868 
listener_run(switch_thread_t * thread,void * obj)1869 static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj)
1870 {
1871 	listener_t *listener = (listener_t *) obj;
1872 	switch_status_t status;
1873 	skinny_message_t *request = NULL;
1874 	skinny_profile_t *profile;
1875 
1876 	switch_assert(listener);
1877 	assert(listener->profile);
1878 	profile = listener->profile;
1879 
1880 	switch_mutex_lock(profile->listener_mutex);
1881 	profile->listener_threads++;
1882 	switch_mutex_unlock(profile->listener_mutex);
1883 
1884 	switch_assert(listener != NULL);
1885 
1886 	if ( profile->non_blocking ) {
1887 		switch_socket_opt_set(listener->sock, SWITCH_SO_TCP_NODELAY, TRUE);
1888 		switch_socket_opt_set(listener->sock, SWITCH_SO_NONBLOCK, TRUE);
1889 	} else {
1890 		switch_socket_opt_set(listener->sock, SWITCH_SO_NONBLOCK, FALSE);
1891 	}
1892 
1893 	/* 200 ms to allow reasonably fast reaction on digit timeout */
1894 	switch_socket_timeout_set(listener->sock, 200000);
1895 
1896 	if (listener->profile->debug > 0) {
1897 		skinny_log_l_msg(listener, SWITCH_LOG_DEBUG, "Connection Open\n");
1898 	}
1899 
1900 	listener->connect_time = switch_epoch_time_now(NULL);
1901 
1902 	switch_set_flag_locked(listener, LFLAG_RUNNING);
1903 	keepalive_listener(listener, NULL);
1904 	add_listener(listener);
1905 
1906 	while (listener_is_ready(listener)) {
1907 		switch_safe_free(request);
1908 		status = skinny_read_packet(listener, &request);
1909 
1910 		if (status != SWITCH_STATUS_SUCCESS) {
1911 			switch(status) {
1912 				case SWITCH_STATUS_TIMEOUT:
1913 					if (listener->digit_timeout_time && listener->digit_timeout_time < switch_mono_micro_time_now()) {
1914 						listener_digit_timeout(listener);
1915 						continue;
1916 					}
1917 
1918 					skinny_log_l_msg(listener, SWITCH_LOG_DEBUG, "Communication Time Out\n");
1919 
1920 					if(listener->expire_time < switch_epoch_time_now(NULL)) {
1921 						switch_event_t *event = NULL;
1922 						/* skinny::expire event */
1923 						skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_EXPIRE);
1924 						switch_event_fire(&event);
1925 					}
1926 					break;
1927 				default:
1928 					skinny_log_l_msg(listener, SWITCH_LOG_DEBUG, "Communication Error\n");
1929 			}
1930 			switch_safe_free(request);
1931 			switch_clear_flag_locked(listener, LFLAG_RUNNING);
1932 			break;
1933 		}
1934 		if (!listener_is_ready(listener)) {
1935 			switch_safe_free(request);
1936 			break;
1937 		}
1938 
1939 		if (!request) {
1940 			continue;
1941 		}
1942 
1943 		if (skinny_handle_request(listener, request) != SWITCH_STATUS_SUCCESS) {
1944 			switch_safe_free(request);
1945 			switch_clear_flag_locked(listener, LFLAG_RUNNING);
1946 			break;
1947 		} else {
1948 			switch_safe_free(request);
1949 		}
1950 	}
1951 	switch_safe_free(request);
1952 
1953 	remove_listener(listener);
1954 
1955 	if (listener->profile->debug > 0) {
1956 		skinny_log_l_msg(listener, SWITCH_LOG_DEBUG, "Communication Complete\n");
1957 	}
1958 
1959 	switch_thread_rwlock_wrlock(listener->rwlock);
1960 	flush_listener(listener);
1961 
1962 	if (listener->sock) {
1963 		close_socket(&listener->sock, profile);
1964 	}
1965 
1966 	switch_thread_rwlock_unlock(listener->rwlock);
1967 
1968 	if (listener->profile->debug > 0) {
1969 		skinny_log_l_msg(listener, SWITCH_LOG_DEBUG, "Communication Closed\n");
1970 	}
1971 
1972 	if (listener->pool) {
1973 		switch_memory_pool_t *pool = listener->pool;
1974 		switch_core_destroy_memory_pool(&pool);
1975 	}
1976 
1977 	switch_mutex_lock(profile->listener_mutex);
1978 	profile->listener_threads--;
1979 	switch_mutex_unlock(profile->listener_mutex);
1980 
1981 	return NULL;
1982 }
1983 
1984 /* Create a thread for the socket and launch it */
launch_listener_thread(listener_t * listener)1985 static void launch_listener_thread(listener_t *listener)
1986 {
1987 	switch_thread_t *thread;
1988 	switch_threadattr_t *thd_attr = NULL;
1989 
1990 	switch_threadattr_create(&thd_attr, listener->pool);
1991 	switch_threadattr_detach_set(thd_attr, 1);
1992 	switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
1993 	switch_thread_create(&thread, thd_attr, listener_run, listener, listener->pool);
1994 }
1995 
skinny_profile_run(switch_thread_t * thread,void * obj)1996 static void *SWITCH_THREAD_FUNC skinny_profile_run(switch_thread_t *thread, void *obj)
1997 {
1998 	skinny_profile_t *profile = (skinny_profile_t *) obj;
1999 	switch_status_t rv;
2000 	switch_sockaddr_t *sa;
2001 	switch_socket_t *inbound_socket = NULL;
2002 	listener_t *listener;
2003 	switch_memory_pool_t *tmp_pool = NULL, *listener_pool = NULL;
2004 	uint32_t errs = 0;
2005 	switch_sockaddr_t *local_sa = NULL;
2006 	switch_sockaddr_t *remote_sa =NULL;
2007 
2008 	if (switch_core_new_memory_pool(&tmp_pool) != SWITCH_STATUS_SUCCESS) {
2009 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "OH OH no pool\n");
2010 		return NULL;
2011 	}
2012 
2013 new_socket:
2014 	while(skinny_globals.running && !profile->sock) {
2015 		char *listening_ip = NULL;
2016 		switch_clear_flag_locked(profile, PFLAG_RESPAWN);
2017 		rv = switch_sockaddr_info_get(&sa, profile->ip, SWITCH_UNSPEC, profile->port, 0, tmp_pool);
2018 		if (rv)
2019 			goto fail;
2020 		rv = switch_socket_create(&profile->sock, switch_sockaddr_get_family(sa), SOCK_STREAM, SWITCH_PROTO_TCP, tmp_pool);
2021 		if (rv)
2022 			goto sock_fail;
2023 		rv = switch_socket_opt_set(profile->sock, SWITCH_SO_REUSEADDR, 1);
2024 		if (rv)
2025 			goto sock_fail;
2026 		rv = switch_socket_bind(profile->sock, sa);
2027 		if (rv)
2028 			goto sock_fail;
2029 		rv = switch_socket_listen(profile->sock, 5);
2030 		if (rv)
2031 			goto sock_fail;
2032 		switch_sockaddr_ip_get(&listening_ip, sa);
2033 		if (!profile->ip || strcmp(listening_ip, profile->ip)) {
2034 			profile->ip = switch_core_strdup(profile->pool, listening_ip);
2035 		}
2036 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Socket up listening on %s:%u\n", profile->ip, profile->port);
2037 
2038 		break;
2039 sock_fail:
2040 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Error! Could not listen on %s:%u\n", profile->ip, profile->port);
2041 		if (profile->sock) {
2042 			close_socket(&profile->sock, profile);
2043 			profile->sock = NULL;
2044 		}
2045 		switch_yield(100000);
2046 	}
2047 
2048 	switch_set_flag_locked(profile, PFLAG_LISTENER_READY);
2049 
2050 	while(skinny_globals.running) {
2051 
2052 		if (switch_core_new_memory_pool(&listener_pool) != SWITCH_STATUS_SUCCESS) {
2053 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "OH OH no pool\n");
2054 			goto fail;
2055 		}
2056 
2057 		assert(profile->sock);
2058 
2059 		if ((rv = switch_socket_accept(&inbound_socket, profile->sock, listener_pool))) {
2060 			if (!skinny_globals.running) {
2061 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Shutting Down\n");
2062 				goto end;
2063 			} else if (switch_test_flag(profile, PFLAG_RESPAWN)) {
2064 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Respawn in progress. Waiting for socket to close.\n");
2065 				while (profile->sock) {
2066 					switch_cond_next();
2067 				}
2068 				goto new_socket;
2069 			} else {
2070 				/* I wish we could use strerror_r here but its not defined everywhere =/ */
2071 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Error [%s]\n", strerror(errno));
2072 				if (++errs > 100) {
2073 					goto end;
2074 				}
2075 			}
2076 		} else {
2077 			errs = 0;
2078 		}
2079 
2080 
2081 		if (!(listener = switch_core_alloc(listener_pool, sizeof(*listener)))) {
2082 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error\n");
2083 			break;
2084 		}
2085 
2086 		switch_thread_rwlock_create(&listener->rwlock, listener_pool);
2087 
2088 		listener->sock = inbound_socket;
2089 		listener->pool = listener_pool;
2090 		listener_pool = NULL;
2091 		strcpy(listener->device_name, "");
2092 		listener->profile = profile;
2093 
2094 		switch_mutex_init(&listener->flag_mutex, SWITCH_MUTEX_NESTED, listener->pool);
2095 
2096 		switch_socket_addr_get(&remote_sa, SWITCH_TRUE, listener->sock);
2097 		switch_get_addr(listener->remote_ip, sizeof(listener->remote_ip), remote_sa);
2098 		listener->remote_port = switch_sockaddr_get_port(remote_sa);
2099 
2100 		switch_socket_addr_get(&local_sa, SWITCH_FALSE, listener->sock);
2101 		switch_get_addr(listener->local_ip, sizeof(listener->local_ip), local_sa);
2102 		listener->local_port = switch_sockaddr_get_port(local_sa);
2103 
2104 		launch_listener_thread(listener);
2105 
2106 	}
2107 
2108 end:
2109 
2110 	close_socket(&profile->sock, profile);
2111 
2112 	if (tmp_pool) {
2113 		switch_core_destroy_memory_pool(&tmp_pool);
2114 	}
2115 
2116 	if (listener_pool) {
2117 		switch_core_destroy_memory_pool(&listener_pool);
2118 	}
2119 
2120 
2121 fail:
2122 	return NULL;
2123 }
2124 
2125 
launch_skinny_profile_thread(skinny_profile_t * profile)2126 void launch_skinny_profile_thread(skinny_profile_t *profile) {
2127 	switch_thread_t *thread;
2128 	switch_threadattr_t *thd_attr = NULL;
2129 
2130 	switch_threadattr_create(&thd_attr, profile->pool);
2131 	switch_threadattr_detach_set(thd_attr, 1);
2132 	switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
2133 	switch_thread_create(&thread, thd_attr, skinny_profile_run, profile, profile->pool);
2134 }
2135 
2136 /*****************************************************************************/
2137 /* MODULE FUNCTIONS */
2138 /*****************************************************************************/
skinny_get_endpoint_interface()2139 switch_endpoint_interface_t *skinny_get_endpoint_interface()
2140 {
2141 	return skinny_endpoint_interface;
2142 }
2143 
skinny_profile_respawn(skinny_profile_t * profile,int force)2144 switch_status_t skinny_profile_respawn(skinny_profile_t *profile, int force)
2145 {
2146 	if (force || switch_test_flag(profile, PFLAG_SHOULD_RESPAWN)) {
2147 		switch_clear_flag_locked(profile, PFLAG_SHOULD_RESPAWN);
2148 		switch_set_flag_locked(profile, PFLAG_RESPAWN);
2149 		switch_clear_flag_locked(profile, PFLAG_LISTENER_READY);
2150 		profile_walk_listeners(profile, kill_listener, NULL);
2151 		close_socket(&profile->sock, profile);
2152 	}
2153 	return SWITCH_STATUS_SUCCESS;
2154 }
2155 
skinny_profile_set(skinny_profile_t * profile,const char * var,const char * val)2156 switch_status_t skinny_profile_set(skinny_profile_t *profile, const char *var, const char *val)
2157 {
2158 	if (!var)
2159 		return SWITCH_STATUS_FALSE;
2160 
2161 	if (profile->sock && !strcasecmp(var, "odbc-dsn")) {
2162 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
2163 				"Skinny profile setting 'odbc-dsn' can't be changed while running\n");
2164 		return SWITCH_STATUS_FALSE;
2165 	}
2166 
2167 	if (!strcasecmp(var, "domain")) {
2168 		profile->domain = switch_core_strdup(profile->pool, val);
2169 	} else if (!strcasecmp(var, "ip")) {
2170 		if (!profile->ip || strcmp(val, profile->ip)) {
2171 			profile->ip = switch_core_strdup(profile->pool, zstr(val) ? NULL : val);
2172 			switch_set_flag_locked(profile, PFLAG_SHOULD_RESPAWN);
2173 		}
2174 	} else if (!strcasecmp(var, "port")) {
2175 		if (atoi(val) != profile->port) {
2176 			profile->port = atoi(val);
2177 			switch_set_flag_locked(profile, PFLAG_SHOULD_RESPAWN);
2178 		}
2179 	} else if (!strcasecmp(var, "patterns-dialplan")) {
2180 		profile->patterns_dialplan = switch_core_strdup(profile->pool, val);
2181 	} else if (!strcasecmp(var, "patterns-context")) {
2182 		profile->patterns_context = switch_core_strdup(profile->pool, val);
2183 	} else if (!strcasecmp(var, "dialplan")) {
2184 		profile->dialplan = switch_core_strdup(profile->pool, val);
2185 	} else if (!strcasecmp(var, "context")) {
2186 		profile->context = switch_core_strdup(profile->pool, val);
2187 	} else if (!strcasecmp(var, "keep-alive")) {
2188 		profile->keep_alive = atoi(val);
2189 	} else if (!strcasecmp(var, "digit-timeout")) {
2190 		profile->digit_timeout = atoi(val);
2191 	} else if (!strcasecmp(var, "date-format")) {
2192 		memcpy(profile->date_format, val, 6);
2193 	} else if (!strcasecmp(var, "odbc-dsn") && !zstr(val)) {
2194 		profile->odbc_dsn = switch_core_strdup(profile->pool, val);
2195 	} else if (!strcasecmp(var, "debug")) {
2196 		profile->debug = atoi(val);
2197 	} else if (!strcasecmp(var, "auto-restart")) {
2198 		profile->auto_restart = switch_true(val);
2199 	} else if (!strcasecmp(var, "non-blocking")) {
2200 		profile->non_blocking = switch_true(val);
2201 	} else if (!strcasecmp(var, "ext-voicemail")) {
2202 		if (!profile->ext_voicemail || strcmp(val, profile->ext_voicemail)) {
2203 			profile->ext_voicemail = switch_core_strdup(profile->pool, val);
2204 		}
2205 	} else if (!strcasecmp(var, "ext-redial")) {
2206 		if (!profile->ext_redial || strcmp(val, profile->ext_redial)) {
2207 			profile->ext_redial = switch_core_strdup(profile->pool, val);
2208 		}
2209 	} else if (!strcasecmp(var, "ext-meetme")) {
2210 		if (!profile->ext_meetme || strcmp(val, profile->ext_meetme)) {
2211 			profile->ext_meetme = switch_core_strdup(profile->pool, val);
2212 		}
2213 	} else if (!strcasecmp(var, "ext-pickup")) {
2214 		if (!profile->ext_pickup || strcmp(val, profile->ext_pickup)) {
2215 			profile->ext_pickup = switch_core_strdup(profile->pool, val);
2216 		}
2217 	} else if (!strcasecmp(var, "ext-cfwdall")) {
2218 		if (!profile->ext_cfwdall || strcmp(val, profile->ext_cfwdall)) {
2219 			profile->ext_cfwdall = switch_core_strdup(profile->pool, val);
2220 		}
2221 	} else {
2222 		return SWITCH_STATUS_FALSE;
2223 	}
2224 
2225 	return SWITCH_STATUS_SUCCESS;
2226 }
2227 
profile_walk_listeners(skinny_profile_t * profile,skinny_listener_callback_func_t callback,void * pvt)2228 void profile_walk_listeners(skinny_profile_t *profile, skinny_listener_callback_func_t callback, void *pvt)
2229 {
2230 	listener_t *l;
2231 
2232 	switch_mutex_lock(profile->listener_mutex);
2233 	for (l = profile->listeners; l; l = l->next) {
2234 		callback(l, pvt);
2235 	}
2236 	switch_mutex_unlock(profile->listener_mutex);
2237 }
2238 
load_skinny_config(void)2239 static switch_status_t load_skinny_config(void)
2240 {
2241 	char *cf = "skinny.conf";
2242 	switch_xml_t xcfg, xml, xprofiles, xprofile;
2243 	switch_cache_db_handle_t *dbh = NULL;
2244 
2245 	if (!(xml = switch_xml_open_cfg(cf, &xcfg, NULL))) {
2246 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", cf);
2247 		return SWITCH_STATUS_TERM;
2248 	}
2249 
2250 	switch_mutex_lock(skinny_globals.mutex);
2251 	if ((xprofiles = switch_xml_child(xcfg, "profiles"))) {
2252 		for (xprofile = switch_xml_child(xprofiles, "profile"); xprofile; xprofile = xprofile->next) {
2253 			char *profile_name = (char *) switch_xml_attr_soft(xprofile, "name");
2254 			switch_xml_t xsettings, xdevice_types, xsoft_key_set_sets;
2255 			if (zstr(profile_name)) {
2256 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
2257 						"<profile> is missing name attribute\n");
2258 				continue;
2259 			}
2260 			if ((xsettings = switch_xml_child(xprofile, "settings"))) {
2261 				switch_memory_pool_t *profile_pool = NULL;
2262 				char dbname[256];
2263 				skinny_profile_t *profile = NULL;
2264 				switch_xml_t param;
2265 
2266 				if (switch_core_new_memory_pool(&profile_pool) != SWITCH_STATUS_SUCCESS) {
2267 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "OH OH no pool\n");
2268 					return SWITCH_STATUS_TERM;
2269 				}
2270 				profile = switch_core_alloc(profile_pool, sizeof(skinny_profile_t));
2271 				profile->pool = profile_pool;
2272 				profile->name = switch_core_strdup(profile->pool, profile_name);
2273 				profile->auto_restart = SWITCH_TRUE;
2274 				profile->non_blocking = SWITCH_FALSE;
2275 				profile->digit_timeout = 10000; /* 10 seconds */
2276 				switch_mutex_init(&profile->sql_mutex, SWITCH_MUTEX_NESTED, profile->pool);
2277 				switch_mutex_init(&profile->listener_mutex, SWITCH_MUTEX_NESTED, profile->pool);
2278 				switch_mutex_init(&profile->sock_mutex, SWITCH_MUTEX_NESTED, profile->pool);
2279 				switch_mutex_init(&profile->flag_mutex, SWITCH_MUTEX_NESTED, profile->pool);
2280 
2281 				switch_mutex_init(&profile->device_name_lock_mutex, SWITCH_MUTEX_NESTED, profile->pool);
2282 
2283 				for (param = switch_xml_child(xsettings, "param"); param; param = param->next) {
2284 					char *var = (char *) switch_xml_attr_soft(param, "name");
2285 					char *val = (char *) switch_xml_attr_soft(param, "value");
2286 
2287 					if (skinny_profile_set(profile, var, val) != SWITCH_STATUS_SUCCESS) {
2288 						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
2289 								"Unable to set skinny setting '%s'. Does it exists?\n", var);
2290 					}
2291 				} /* param */
2292 
2293 				if (!profile->dialplan) {
2294 					skinny_profile_set(profile, "dialplan","XML");
2295 				}
2296 
2297 				if (!profile->context) {
2298 					skinny_profile_set(profile, "context","default");
2299 				}
2300 
2301 				if (!profile->patterns_dialplan) {
2302 					skinny_profile_set(profile, "patterns-dialplan","XML");
2303 				}
2304 
2305 				if (!profile->patterns_context) {
2306 					skinny_profile_set(profile, "patterns-context","skinny-patterns");
2307 				}
2308 
2309 				if (!profile->ext_voicemail) {
2310 					skinny_profile_set(profile, "ext-voicemail", "vmain");
2311 				}
2312 
2313 				if (!profile->ext_redial) {
2314 					skinny_profile_set(profile, "ext-redial", "redial");
2315 				}
2316 
2317 				if (!profile->ext_meetme) {
2318 					skinny_profile_set(profile, "ext-meetme", "conference");
2319 				}
2320 
2321 				if (!profile->ext_pickup) {
2322 					skinny_profile_set(profile, "ext-pickup", "pickup");
2323 				}
2324 
2325 				if (!profile->ext_cfwdall) {
2326 					skinny_profile_set(profile, "ext-pickup", "cfwdall");
2327 				}
2328 
2329 				if (profile->port == 0) {
2330 					profile->port = 2000;
2331 				}
2332 
2333 				/* Soft Key Set Sets */
2334 				switch_core_hash_init(&profile->soft_key_set_sets_hash);
2335 				if ((xsoft_key_set_sets = switch_xml_child(xprofile, "soft-key-set-sets"))) {
2336 					switch_xml_t xsoft_key_set_set;
2337 					for (xsoft_key_set_set = switch_xml_child(xsoft_key_set_sets, "soft-key-set-set"); xsoft_key_set_set; xsoft_key_set_set = xsoft_key_set_set->next) {
2338 						char *soft_key_set_set_name = (char *) switch_xml_attr_soft(xsoft_key_set_set, "name");
2339 						if (soft_key_set_set_name) {
2340 							switch_xml_t xsoft_key_set;
2341 							skinny_message_t *message;
2342 							message = switch_core_alloc(profile->pool, 12+sizeof(message->data.soft_key_set));
2343 							message->type = SOFT_KEY_SET_RES_MESSAGE;
2344 							message->length = 4 + sizeof(message->data.soft_key_set);
2345 							message->data.soft_key_set.soft_key_set_offset = 0;
2346 							message->data.soft_key_set.soft_key_set_count = 11;
2347 							message->data.soft_key_set.total_soft_key_set_count = 11;
2348 							for (xsoft_key_set = switch_xml_child(xsoft_key_set_set, "soft-key-set"); xsoft_key_set; xsoft_key_set = xsoft_key_set->next) {
2349 								uint32_t soft_key_set_id;
2350 								if ((soft_key_set_id = skinny_str2soft_key_set(switch_xml_attr_soft(xsoft_key_set, "name"))) != -1) {
2351 									char *val =switch_core_strdup(profile->pool, switch_xml_attr_soft(xsoft_key_set, "value"));
2352 									size_t string_len = strlen(val);
2353 									size_t string_pos, start = 0;
2354 									int field_no = 0;
2355 									if (zstr(val)) {
2356 										continue;
2357 									}
2358 									if (soft_key_set_id > 15) {
2359 										switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
2360 												"soft-key-set name '%s' is greater than 15 in soft-key-set-set '%s' in profile %s.\n",
2361 												switch_xml_attr_soft(xsoft_key_set, "name"), soft_key_set_set_name, profile->name);
2362 										continue;
2363 									}
2364 									for (string_pos = 0; string_pos <= string_len; string_pos++) {
2365 										if ((val[string_pos] == ',') || (string_pos == string_len)) {
2366 											val[string_pos] = '\0';
2367 											if (field_no > 15) {
2368 												switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
2369 														"soft-key-set name '%s' is limited to 16 buttons in soft-key-set-set '%s' in profile %s.\n",
2370 														switch_xml_attr_soft(xsoft_key_set, "name"), soft_key_set_set_name, profile->name);
2371 												break;
2372 											}
2373 											message->data.soft_key_set.soft_key_set[soft_key_set_id].soft_key_template_index[field_no++] = skinny_str2soft_key_event(&val[start]);
2374 											start = string_pos+1;
2375 										}
2376 									}
2377 								} else {
2378 									switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
2379 											"Unknown soft-key-set name '%s' in soft-key-set-set '%s' in profile %s.\n",
2380 											switch_xml_attr_soft(xsoft_key_set, "name"), soft_key_set_set_name, profile->name);
2381 								}
2382 							} /* soft-key-set */
2383 							switch_core_hash_insert(profile->soft_key_set_sets_hash, soft_key_set_set_name, message);
2384 						} else {
2385 							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
2386 									"<soft-key-set-set> is missing a name attribute in profile %s.\n", profile->name);
2387 						}
2388 					} /* soft-key-set-set */
2389 				} else {
2390 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
2391 							"<soft-key-set-sets> is missing in profile %s.\n", profile->name);
2392 				} /* soft-key-set-sets */
2393 				if (!switch_core_hash_find(profile->soft_key_set_sets_hash, "default")) {
2394 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
2395 							"Profile %s doesn't have a default <soft-key-set-set>. Profile ignored.\n", profile->name);
2396 					switch_core_destroy_memory_pool(&profile_pool);
2397 					continue;
2398 				}
2399 
2400 				/* Device Name Locks */
2401 				switch_core_hash_init(&profile->device_name_lock_hash);
2402 
2403 				/* Device types */
2404 				switch_core_hash_init(&profile->device_type_params_hash);
2405 				if ((xdevice_types = switch_xml_child(xprofile, "device-types"))) {
2406 					switch_xml_t xdevice_type;
2407 					for (xdevice_type = switch_xml_child(xdevice_types, "device-type"); xdevice_type; xdevice_type = xdevice_type->next) {
2408 						uint32_t id = skinny_str2device_type(switch_xml_attr_soft(xdevice_type, "id"));
2409 						if (id != 0) {
2410 							char *id_str = switch_mprintf("%d", id);
2411 							skinny_device_type_params_t *params = switch_core_alloc(profile->pool, sizeof(skinny_device_type_params_t));
2412 							for (param = switch_xml_child(xdevice_type, "param"); param; param = param->next) {
2413 								char *var = (char *) switch_xml_attr_soft(param, "name");
2414 								char *val = (char *) switch_xml_attr_soft(param, "value");
2415 
2416 								if (!strcasecmp(var, "firmware-version")) {
2417 									strncpy(params->firmware_version, val, 16);
2418 								}
2419 							} /* param */
2420 							switch_core_hash_insert(profile->device_type_params_hash, id_str, params);
2421 							switch_safe_free(id_str);
2422 						} else {
2423 							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
2424 									"Unknow device type %s in profile %s.\n", switch_xml_attr_soft(xdevice_type, "id"), profile->name);
2425 						}
2426 					}
2427 				}
2428 
2429 				/* Database */
2430 				switch_snprintf(dbname, sizeof(dbname), "skinny_%s", profile->name);
2431 				profile->dbname = switch_core_strdup(profile->pool, dbname);
2432 
2433 
2434 
2435 
2436 				if ((dbh = skinny_get_db_handle(profile))) {
2437 					switch_cache_db_test_reactive(dbh, "select count(*) from skinny_devices", NULL, devices_sql);
2438 					switch_cache_db_test_reactive(dbh, "select count(*) from skinny_lines", NULL, lines_sql);
2439 					switch_cache_db_test_reactive(dbh, "select count(*) from skinny_buttons", NULL, buttons_sql);
2440 					switch_cache_db_test_reactive(dbh, "select count(*) from skinny_active_lines", NULL, active_lines_sql);
2441 					switch_cache_db_release_db_handle(&dbh);
2442 				}
2443 
2444 				skinny_profile_respawn(profile, 0);
2445 
2446 				/* Register profile */
2447 				switch_core_hash_insert(skinny_globals.profile_hash, profile->name, profile);
2448 				profile = NULL;
2449 			} else {
2450 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
2451 						"Settings are missing from profile %s.\n", profile_name);
2452 			} /* settings */
2453 		} /* profile */
2454 	}
2455 	switch_xml_free(xml);
2456 	switch_mutex_unlock(skinny_globals.mutex);
2457 
2458 	return SWITCH_STATUS_SUCCESS;
2459 }
2460 
skinny_user_to_device_event_handler(switch_event_t * event)2461 static void skinny_user_to_device_event_handler(switch_event_t *event)
2462 {
2463 	char *profile_name = switch_event_get_header_nil(event, "Skinny-Profile-Name");
2464 	skinny_profile_t *profile;
2465 
2466 	if ((profile = skinny_find_profile(profile_name))) {
2467 		char *device_name = switch_event_get_header_nil(event, "Skinny-Device-Name");
2468 		uint32_t device_instance = atoi(switch_event_get_header_nil(event, "Skinny-Station-Instance"));
2469 		listener_t *listener = NULL;
2470 		skinny_profile_find_listener_by_device_name_and_instance(profile, device_name, device_instance, &listener);
2471 		if(listener) {
2472 			uint32_t message_type = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Message-Id"));
2473 			uint32_t application_id = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Application-Id"));
2474 			uint32_t line_instance = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Line-Instance"));
2475 			uint32_t call_id = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Call-Id"));
2476 			uint32_t transaction_id = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Transaction-Id"));
2477 			uint32_t data_length;
2478 			uint32_t sequence_flag = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Sequence-Flag"));
2479 			uint32_t display_priority = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Display-Priority"));
2480 			uint32_t conference_id = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Conference-Id"));
2481 			uint32_t app_instance_id = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-App-Instance-Id"));
2482 			uint32_t routing_id = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Routing-Id"));
2483 			char *data = switch_event_get_body(event);
2484 			if (message_type == 0) {
2485 				message_type = skinny_str2message_type(switch_event_get_header_nil(event, "Skinny-UserToDevice-Message-Id-String"));
2486 			}
2487 			switch(message_type) {
2488 				case USER_TO_DEVICE_DATA_MESSAGE:
2489 					data_length = strlen(data); /* we ignore data_length sent */
2490 					send_data(listener, message_type,
2491 							application_id, line_instance, call_id, transaction_id, data_length,
2492 							data);
2493 					break;
2494 				case USER_TO_DEVICE_DATA_VERSION1_MESSAGE:
2495 					data_length = strlen(data); /* we ignore data_length sent */
2496 					send_extended_data(listener, message_type,
2497 							application_id, line_instance, call_id, transaction_id, data_length,
2498 							sequence_flag, display_priority, conference_id, app_instance_id, routing_id,
2499 							data);
2500 					break;
2501 				default:
2502 					skinny_log_l(listener, SWITCH_LOG_WARNING, "Incorrect message type %s (%d).\n", skinny_message_type2str(message_type), message_type);
2503 			}
2504 		} else {
2505 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
2506 					"Device %s:%d in profile '%s' not found.\n", device_name, device_instance, profile_name);
2507 		}
2508 	} else {
2509 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
2510 				"Profile '%s' not found.\n", profile_name);
2511 	}
2512 }
2513 
skinny_call_state_event_handler(switch_event_t * event)2514 static void skinny_call_state_event_handler(switch_event_t *event)
2515 {
2516 	char *subclass;
2517 
2518 	if ((subclass = switch_event_get_header_nil(event, "Event-Subclass")) && !strcasecmp(subclass, SKINNY_EVENT_CALL_STATE)) {
2519 		char *profile_name = switch_event_get_header_nil(event, "Skinny-Profile-Name");
2520 		char *device_name = switch_event_get_header_nil(event, "Skinny-Device-Name");
2521 		uint32_t device_instance = atoi(switch_event_get_header_nil(event, "Skinny-Station-Instance"));
2522 		uint32_t line_instance = atoi(switch_event_get_header_nil(event, "Skinny-Line-Instance"));
2523 		uint32_t call_id = atoi(switch_event_get_header_nil(event, "Skinny-Call-Id"));
2524 		uint32_t call_state = atoi(switch_event_get_header_nil(event, "Skinny-Call-State"));
2525 		skinny_profile_t *profile;
2526 		listener_t *listener = NULL;
2527 		char *line_instance_condition, *call_id_condition;
2528 		char *sql;
2529 
2530 		if ((profile = skinny_find_profile(profile_name))) {
2531 			skinny_profile_find_listener_by_device_name_and_instance(profile, device_name, device_instance, &listener);
2532 			if(listener) {
2533 				if(line_instance > 0) {
2534 					line_instance_condition = switch_mprintf("line_instance=%d", line_instance);
2535 				} else {
2536 					line_instance_condition = switch_mprintf("1=1");
2537 				}
2538 				switch_assert(line_instance_condition);
2539 				if(call_id > 0) {
2540 					call_id_condition = switch_mprintf("call_id=%d", call_id);
2541 				} else {
2542 					call_id_condition = switch_mprintf("1=1");
2543 				}
2544 				switch_assert(call_id_condition);
2545 
2546 				if ((sql = switch_mprintf(
2547 								"UPDATE skinny_active_lines "
2548 								"SET call_state=%d "
2549 								"WHERE device_name='%q' AND device_instance=%d "
2550 								"AND %q AND %q",
2551 								call_state,
2552 								listener->device_name, listener->device_instance,
2553 								line_instance_condition, call_id_condition
2554 							 ))) {
2555 					skinny_execute_sql(listener->profile, sql, listener->profile->sql_mutex);
2556 					switch_safe_free(sql);
2557 				}
2558 				switch_safe_free(line_instance_condition);
2559 				switch_safe_free(call_id_condition);
2560 			} else {
2561 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
2562 						"Device %s:%d in profile '%s' not found.\n", device_name, device_instance, profile_name);
2563 			}
2564 		} else {
2565 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
2566 					"Profile '%s' not found.\n", profile_name);
2567 		}
2568 	}
2569 }
2570 
2571 struct skinny_message_waiting_event_handler_helper {
2572 	skinny_profile_t *profile;
2573 	switch_bool_t yn;
2574 	int total_new_messages;
2575 	int total_saved_messages;
2576 	int total_new_urgent_messages;
2577 	int total_saved_urgent_messages;
2578 };
2579 
skinny_message_waiting_event_handler_callback(void * pArg,int argc,char ** argv,char ** columnNames)2580 int skinny_message_waiting_event_handler_callback(void *pArg, int argc, char **argv, char **columnNames)
2581 {
2582 	char *device_name = argv[0];
2583 	uint32_t device_instance = atoi(argv[1]);
2584 
2585 	struct skinny_message_waiting_event_handler_helper *helper = pArg;
2586 	listener_t *listener = NULL;
2587 
2588 	skinny_profile_find_listener_by_device_name_and_instance(helper->profile,
2589 			device_name, device_instance, &listener);
2590 
2591 	if (listener) {
2592 		if (helper->yn == SWITCH_TRUE) {
2593 			char buffer[32];
2594 			char *label;
2595 			send_set_lamp(listener, SKINNY_BUTTON_VOICEMAIL, 0, SKINNY_LAMP_ON);
2596 
2597 			label = skinny_textid2raw(SKINNY_TEXTID_YOU_HAVE_VOICEMAIL);
2598 			sprintf(buffer, "%s: (%d/%d urgents)", label, helper->total_new_messages, helper->total_new_urgent_messages);
2599 			switch_safe_free(label);
2600 
2601 			send_display_pri_notify(listener, 5, 10, buffer);
2602 		} else {
2603 			send_set_lamp(listener, SKINNY_BUTTON_VOICEMAIL, 0, SKINNY_LAMP_OFF);
2604 			send_clear_prompt_status(listener, 0, 0);
2605 		}
2606 	}
2607 	return 0;
2608 }
2609 
skinny_message_waiting_event_handler(switch_event_t * event)2610 static void skinny_message_waiting_event_handler(switch_event_t *event)
2611 {
2612 	char *account, *dup_account, *yn, *host, *user, *count_str;
2613 	char *pname = NULL;
2614 	skinny_profile_t *profile = NULL;
2615 	char *sql;
2616 
2617 	if (!(account = switch_event_get_header(event, "mwi-message-account"))) {
2618 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing required Header 'MWI-Message-Account'\n");
2619 		return;
2620 	}
2621 
2622 	if (!strncmp("sip:", account, 4)) {
2623 		return;
2624 	}
2625 
2626 	if (!(yn = switch_event_get_header(event, "mwi-messages-waiting"))) {
2627 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing required Header 'MWI-Messages-Waiting'\n");
2628 		return;
2629 	}
2630 	dup_account = strdup(account);
2631 	switch_assert(dup_account != NULL);
2632 	switch_split_user_domain(dup_account, &user, &host);
2633 
2634 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "MWI Event received for account %s with messages waiting %s\n", account, yn);
2635 
2636 	if ((pname = switch_event_get_header(event, "skinny-profile"))) {
2637 		if (!(profile = skinny_find_profile(pname))) {
2638 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "No profile %s\n", pname);
2639 		}
2640 	}
2641 
2642 	if (!profile) {
2643 		if (!host || !(profile = skinny_find_profile_by_domain(host))) {
2644 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find profile with domain %s\n", switch_str_nil(host));
2645 			switch_safe_free(dup_account);
2646 			return;
2647 		}
2648 	}
2649 
2650 	count_str = switch_event_get_header(event, "mwi-voice-message");
2651 
2652 	if ((sql = switch_mprintf(
2653 					"SELECT device_name, device_instance FROM skinny_lines "
2654 					"WHERE value='%q' AND line_instance=1", user))) {
2655 		struct skinny_message_waiting_event_handler_helper helper = {0};
2656 		helper.profile = profile;
2657 		helper.yn = switch_true(yn);
2658 		if (count_str) {
2659 			sscanf(count_str,"%d/%d (%d/%d)",
2660 					&helper.total_new_messages, &helper.total_saved_messages,
2661 					&helper.total_new_urgent_messages, &helper.total_saved_urgent_messages);
2662 		}
2663 		skinny_execute_sql_callback(profile, profile->sql_mutex, sql,  skinny_message_waiting_event_handler_callback, &helper);
2664 		switch_safe_free(sql);
2665 	}
2666 
2667 	switch_safe_free(dup_account);
2668 }
2669 
2670 
skinny_trap_event_handler(switch_event_t * event)2671 static void skinny_trap_event_handler(switch_event_t *event)
2672 {
2673 	const char *cond = switch_event_get_header(event, "condition");
2674 
2675 
2676 	if (cond && !strcmp(cond, "network-address-change") && skinny_globals.auto_restart) {
2677 		const char *old_ip4 = switch_event_get_header_nil(event, "network-address-previous-v4");
2678 		const char *new_ip4 = switch_event_get_header_nil(event, "network-address-change-v4");
2679 		const char *old_ip6 = switch_event_get_header_nil(event, "network-address-previous-v6");
2680 		const char *new_ip6 = switch_event_get_header_nil(event, "network-address-change-v6");
2681 		switch_hash_index_t *hi;
2682 		const void *var;
2683 		void *val;
2684 		skinny_profile_t *profile;
2685 
2686 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "EVENT_TRAP: IP change detected\n");
2687 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "IP change detected [%s]->[%s] [%s]->[%s]\n", old_ip4, new_ip4, old_ip6, new_ip6);
2688 
2689 		switch_mutex_lock(skinny_globals.mutex);
2690 		if (skinny_globals.profile_hash) {
2691 			for (hi = switch_core_hash_first(skinny_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
2692 				switch_core_hash_this(hi, &var, NULL, &val);
2693 				if ((profile = (skinny_profile_t *) val) && profile->auto_restart) {
2694 					if (!strcmp(profile->ip, old_ip4)) {
2695 						skinny_profile_set(profile, "ip", new_ip4);
2696 					} else if (!strcmp(profile->ip, old_ip6)) {
2697 						skinny_profile_set(profile, "ip", new_ip6);
2698 					}
2699 					skinny_profile_respawn(profile, 0);
2700 				}
2701 			}
2702 		}
2703 		switch_mutex_unlock(skinny_globals.mutex);
2704 	}
2705 
2706 }
2707 
2708 /*****************************************************************************/
SWITCH_MODULE_LOAD_FUNCTION(mod_skinny_load)2709 SWITCH_MODULE_LOAD_FUNCTION(mod_skinny_load)
2710 {
2711 	switch_hash_index_t *hi;
2712 	/* skinny_globals init */
2713 	memset(&skinny_globals, 0, sizeof(skinny_globals));
2714 
2715 	if (switch_core_new_memory_pool(&skinny_globals.pool) != SWITCH_STATUS_SUCCESS) {
2716 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "OH OH no pool\n");
2717 		return SWITCH_STATUS_TERM;
2718 	}
2719 	switch_mutex_init(&skinny_globals.mutex, SWITCH_MUTEX_NESTED, skinny_globals.pool);
2720 
2721 	switch_mutex_lock(skinny_globals.mutex);
2722 	switch_core_hash_init(&skinny_globals.profile_hash);
2723 	skinny_globals.running = 1;
2724 	skinny_globals.auto_restart = SWITCH_TRUE;
2725 	switch_mutex_unlock(skinny_globals.mutex);
2726 
2727 	/* load_skinny_config does it's own locking */
2728 	load_skinny_config();
2729 
2730 	switch_mutex_lock(skinny_globals.mutex);
2731 
2732 	/* at least one profile */
2733 	if (switch_core_hash_empty( skinny_globals.profile_hash)) {
2734 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No profile found!\n");
2735 		return SWITCH_STATUS_TERM;
2736 	}
2737 	/* bind to events */
2738 	if ((switch_event_bind_removable(modname, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_CALL_STATE, skinny_call_state_event_handler, NULL, &skinny_globals.call_state_node) != SWITCH_STATUS_SUCCESS)) {
2739 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind our call_state handler!\n");
2740 		return SWITCH_STATUS_TERM;
2741 	}
2742 	if ((switch_event_bind_removable(modname, SWITCH_EVENT_MESSAGE_WAITING, NULL, skinny_message_waiting_event_handler, NULL, &skinny_globals.message_waiting_node) != SWITCH_STATUS_SUCCESS)) {
2743 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Couldn't bind our message waiting handler!\n");
2744 		/* Not such severe to prevent loading */
2745 	}
2746 	if ((switch_event_bind_removable(modname, SWITCH_EVENT_TRAP, NULL, skinny_trap_event_handler, NULL, &skinny_globals.trap_node) != SWITCH_STATUS_SUCCESS)) {
2747 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Couldn't bind our trap handler!\n");
2748 		/* Not such severe to prevent loading */
2749 	}
2750 	if ((switch_event_bind_removable(modname, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_USER_TO_DEVICE, skinny_user_to_device_event_handler, NULL, &skinny_globals.user_to_device_node) != SWITCH_STATUS_SUCCESS)) {
2751 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind our user_to_device handler!\n");
2752 		/* Not such severe to prevent loading */
2753 	}
2754 
2755 	/* reserve events */
2756 	if (switch_event_reserve_subclass(SKINNY_EVENT_REGISTER) != SWITCH_STATUS_SUCCESS) {
2757 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", SKINNY_EVENT_REGISTER);
2758 		return SWITCH_STATUS_TERM;
2759 	}
2760 	if (switch_event_reserve_subclass(SKINNY_EVENT_UNREGISTER) != SWITCH_STATUS_SUCCESS) {
2761 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", SKINNY_EVENT_UNREGISTER);
2762 		return SWITCH_STATUS_TERM;
2763 	}
2764 	if (switch_event_reserve_subclass(SKINNY_EVENT_EXPIRE) != SWITCH_STATUS_SUCCESS) {
2765 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", SKINNY_EVENT_EXPIRE);
2766 		return SWITCH_STATUS_TERM;
2767 	}
2768 	if (switch_event_reserve_subclass(SKINNY_EVENT_ALARM) != SWITCH_STATUS_SUCCESS) {
2769 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", SKINNY_EVENT_ALARM);
2770 		return SWITCH_STATUS_TERM;
2771 	}
2772 	if (switch_event_reserve_subclass(SKINNY_EVENT_CALL_STATE) != SWITCH_STATUS_SUCCESS) {
2773 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", SKINNY_EVENT_CALL_STATE);
2774 		return SWITCH_STATUS_TERM;
2775 	}
2776 	if (switch_event_reserve_subclass(SKINNY_EVENT_USER_TO_DEVICE) != SWITCH_STATUS_SUCCESS) {
2777 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", SKINNY_EVENT_USER_TO_DEVICE);
2778 		return SWITCH_STATUS_TERM;
2779 	}
2780 	if (switch_event_reserve_subclass(SKINNY_EVENT_DEVICE_TO_USER) != SWITCH_STATUS_SUCCESS) {
2781 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", SKINNY_EVENT_DEVICE_TO_USER);
2782 		return SWITCH_STATUS_TERM;
2783 	}
2784 
2785 	/* connect my internal structure to the blank pointer passed to me */
2786 	*module_interface = switch_loadable_module_create_module_interface(skinny_globals.pool, modname);
2787 	skinny_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
2788 	skinny_endpoint_interface->interface_name = "skinny";
2789 	skinny_endpoint_interface->io_routines = &skinny_io_routines;
2790 	skinny_endpoint_interface->state_handler = &skinny_state_handlers;
2791 
2792 	skinny_api_register(module_interface);
2793 
2794 	/* launch listeners */
2795 	for (hi = switch_core_hash_first(skinny_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
2796 		void *val;
2797 		skinny_profile_t *profile;
2798 
2799 		switch_core_hash_this(hi, NULL, NULL, &val);
2800 		profile = (skinny_profile_t *) val;
2801 
2802 		launch_skinny_profile_thread(profile);
2803 	}
2804 	switch_mutex_unlock(skinny_globals.mutex);
2805 
2806 	/* indicate that the module should continue to be loaded */
2807 	return SWITCH_STATUS_SUCCESS;
2808 }
2809 
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_skinny_shutdown)2810 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_skinny_shutdown)
2811 {
2812 	switch_hash_index_t *hi;
2813 	void *val;
2814 	switch_memory_pool_t *pool = skinny_globals.pool;
2815 	switch_mutex_t *mutex = skinny_globals.mutex;
2816 	int sanity = 0;
2817 
2818 	skinny_api_unregister();
2819 
2820 	/* release events */
2821 	switch_event_unbind(&skinny_globals.user_to_device_node);
2822 	switch_event_unbind(&skinny_globals.call_state_node);
2823 	switch_event_unbind(&skinny_globals.message_waiting_node);
2824 	switch_event_unbind(&skinny_globals.trap_node);
2825 	switch_event_free_subclass(SKINNY_EVENT_REGISTER);
2826 	switch_event_free_subclass(SKINNY_EVENT_UNREGISTER);
2827 	switch_event_free_subclass(SKINNY_EVENT_EXPIRE);
2828 	switch_event_free_subclass(SKINNY_EVENT_ALARM);
2829 	switch_event_free_subclass(SKINNY_EVENT_CALL_STATE);
2830 	switch_event_free_subclass(SKINNY_EVENT_USER_TO_DEVICE);
2831 	switch_event_free_subclass(SKINNY_EVENT_DEVICE_TO_USER);
2832 
2833 	switch_mutex_lock(mutex);
2834 
2835 	skinny_globals.running = 0;
2836 
2837 	/* kill listeners */
2838 	walk_listeners(kill_listener, NULL);
2839 
2840 	/* close sockets */
2841 	switch_mutex_lock(skinny_globals.mutex);
2842 	for (hi = switch_core_hash_first(skinny_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
2843 		skinny_profile_t *profile;
2844 		switch_core_hash_this(hi, NULL, NULL, &val);
2845 		profile = (skinny_profile_t *) val;
2846 
2847 		close_socket(&profile->sock, profile);
2848 
2849 		while (profile->listener_threads) {
2850 			switch_yield(100000);
2851 			walk_listeners(kill_listener, NULL);
2852 			if (++sanity >= 200) {
2853 				break;
2854 			}
2855 		}
2856 		switch_core_destroy_memory_pool(&profile->pool);
2857 	}
2858 	switch_mutex_unlock(skinny_globals.mutex);
2859 
2860 	switch_core_hash_destroy(&skinny_globals.profile_hash);
2861 	memset(&skinny_globals, 0, sizeof(skinny_globals));
2862 	switch_mutex_unlock(mutex);
2863 	switch_core_destroy_memory_pool(&pool);
2864 	return SWITCH_STATUS_SUCCESS;
2865 }
2866 
2867 /* For Emacs:
2868  * Local Variables:
2869  * mode:c
2870  * indent-tabs-mode:t
2871  * tab-width:4
2872  * c-basic-offset:4
2873  * End:
2874  * For VIM:
2875  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
2876  */
2877