2010-02-24 11:57:37 +00:00
/*
* FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
* Copyright ( C ) 2010 , Mathieu Parent < math . parent @ gmail . com >
*
* Version : MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 ( the " License " ) ; you may not use this file except in compliance with
* the License . You may obtain a copy of the License at
* http : //www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an " AS IS " basis ,
* WITHOUT WARRANTY OF ANY KIND , either express or implied . See the License
* for the specific language governing rights and limitations under the
* License .
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
*
* The Initial Developer of the Original Code is
* Mathieu Parent < math . parent @ gmail . com >
* Portions created by the Initial Developer are Copyright ( C )
* the Initial Developer . All Rights Reserved .
*
* Contributor ( s ) :
*
* Mathieu Parent < math . parent @ gmail . com >
*
*
* mod_skinny . c - - Skinny Call Control Protocol ( SCCP ) Endpoint Module
*
*/
# include <switch.h>
2010-02-24 12:04:56 +00:00
# include "mod_skinny.h"
# include "skinny_protocol.h"
2010-02-24 11:57:37 +00:00
SWITCH_MODULE_LOAD_FUNCTION ( mod_skinny_load ) ;
SWITCH_MODULE_SHUTDOWN_FUNCTION ( mod_skinny_shutdown ) ;
SWITCH_MODULE_RUNTIME_FUNCTION ( mod_skinny_runtime ) ;
SWITCH_MODULE_DEFINITION ( mod_skinny , mod_skinny_load , mod_skinny_shutdown , mod_skinny_runtime ) ;
switch_endpoint_interface_t * skinny_endpoint_interface ;
static switch_memory_pool_t * module_pool = NULL ;
2010-02-24 12:04:56 +00:00
skinny_globals_t globals ;
2010-02-24 11:57:37 +00:00
SWITCH_DECLARE_GLOBAL_STRING_FUNC ( set_global_codec_string , globals . codec_string ) ;
SWITCH_DECLARE_GLOBAL_STRING_FUNC ( set_global_codec_rates_string , globals . codec_rates_string ) ;
2010-02-24 11:59:41 +00:00
/*****************************************************************************/
2010-02-24 12:04:56 +00:00
/* SQL TABLES */
2010-02-24 11:59:41 +00:00
/*****************************************************************************/
static char devices_sql [ ] =
" CREATE TABLE skinny_devices ( \n "
2010-02-24 12:00:45 +00:00
" name VARCHAR(16), \n "
2010-02-24 11:59:41 +00:00
" user_id INTEGER, \n "
" instance INTEGER, \n "
" ip VARCHAR(255), \n "
2010-02-24 12:00:45 +00:00
" type INTEGER, \n "
2010-02-24 11:59:41 +00:00
" max_streams INTEGER, \n "
" port INTEGER, \n "
" codec_string VARCHAR(255) \n "
" ); \n " ;
2010-02-24 12:00:45 +00:00
static char buttons_sql [ ] =
" CREATE TABLE skinny_buttons ( \n "
2010-02-24 11:59:41 +00:00
" device_name VARCHAR(16), \n "
2010-02-24 12:00:45 +00:00
" position INTEGER, \n "
" type VARCHAR(10), \n "
" label VARCHAR(40), \n "
" value VARCHAR(24), \n "
" settings VARCHAR(44) \n "
2010-02-24 11:59:41 +00:00
" ); \n " ;
2010-02-24 11:59:49 +00:00
/*****************************************************************************/
/* PROFILES FUNCTIONS */
/*****************************************************************************/
static switch_status_t dump_profile ( const skinny_profile_t * profile , switch_stream_handle_t * stream )
{
const char * line = " ================================================================================================= " ;
switch_assert ( profile ) ;
stream - > write_function ( stream , " %s \n " , line ) ;
2010-02-24 12:00:11 +00:00
/* prefs */
2010-02-24 11:59:49 +00:00
stream - > write_function ( stream , " Name \t %s \n " , profile - > name ) ;
stream - > write_function ( stream , " Domain Name \t %s \n " , profile - > domain ) ;
stream - > write_function ( stream , " IP \t %s \n " , profile - > ip ) ;
stream - > write_function ( stream , " Port \t %d \n " , profile - > port ) ;
stream - > write_function ( stream , " Dialplan \t %s \n " , profile - > dialplan ) ;
2010-02-24 12:04:36 +00:00
stream - > write_function ( stream , " Context \t %s \n " , profile - > context ) ;
2010-02-24 11:59:49 +00:00
stream - > write_function ( stream , " Keep-Alive \t %d \n " , profile - > keep_alive ) ;
stream - > write_function ( stream , " Date-Format \t %s \n " , profile - > date_format ) ;
2010-02-24 12:00:11 +00:00
/* db */
2010-02-24 11:59:49 +00:00
stream - > write_function ( stream , " DBName \t %s \n " , profile - > dbname ? profile - > dbname : switch_str_nil ( profile - > odbc_dsn ) ) ;
2010-02-24 12:00:11 +00:00
/* stats */
stream - > write_function ( stream , " CALLS-IN \t %d \n " , profile - > ib_calls ) ;
stream - > write_function ( stream , " FAILED-CALLS-IN \t %d \n " , profile - > ib_failed_calls ) ;
stream - > write_function ( stream , " CALLS-OUT \t %d \n " , profile - > ob_calls ) ;
stream - > write_function ( stream , " FAILED-CALLS-OUT \t %d \n " , profile - > ob_failed_calls ) ;
/* listener */
2010-02-24 11:59:49 +00:00
stream - > write_function ( stream , " Listener-Threads \t %d \n " , profile - > listener_threads ) ;
stream - > write_function ( stream , " %s \n " , line ) ;
return SWITCH_STATUS_SUCCESS ;
}
2010-02-24 12:00:11 +00:00
static skinny_profile_t * skinny_find_profile ( const char * profile_name )
2010-02-24 11:59:49 +00:00
{
return ( skinny_profile_t * ) switch_core_hash_find ( globals . profile_hash , profile_name ) ;
}
2010-02-24 12:04:25 +00:00
struct skinny_profile_find_listener_helper {
skinny_profile_t * profile ;
listener_t * listener ;
uint32_t line ;
} ;
static int skinny_profile_find_listener_callback ( void * pArg , int argc , char * * argv , char * * columnNames )
{
struct skinny_profile_find_listener_helper * helper = pArg ;
skinny_profile_t * profile = helper - > profile ;
char * device_name = argv [ 0 ] ;
/* uint32_t position = atoi(argv[1]); */
uint32_t relative_position = atoi ( argv [ 2 ] ) ;
switch_mutex_lock ( profile - > listener_mutex ) ;
for ( listener_t * l = profile - > listeners ; l ; l = l - > next ) {
if ( ! strcmp ( l - > device_name , device_name ) ) {
helper - > listener = l ;
}
}
switch_mutex_unlock ( profile - > listener_mutex ) ;
if ( helper - > listener ) {
helper - > line = relative_position ;
}
return 0 ;
}
static switch_status_t skinny_profile_find_listener ( skinny_profile_t * profile , const char * dest , listener_t * * l , uint32_t * line )
{
char * sql ;
struct skinny_profile_find_listener_helper helper = { 0 } ;
helper . profile = profile ;
if ( ( sql = switch_mprintf ( " SELECT device_name, position, "
" (SELECT count(*) from skinny_buttons sb2 "
" WHERE sb2.device_name= sb1.device_name AND sb2.type='line' AND sb2.position <= sb1.position) AS relative_position "
" FROM skinny_buttons sb1 WHERE type='line' and value='%s' " ,
dest ) ) ) {
skinny_execute_sql_callback ( profile , profile - > listener_mutex , sql , skinny_profile_find_listener_callback , & helper ) ;
switch_safe_free ( sql ) ;
}
* line = helper . line ;
* l = helper . listener ;
return SWITCH_STATUS_SUCCESS ;
}
2010-02-24 11:59:41 +00:00
/*****************************************************************************/
/* SQL FUNCTIONS */
/*****************************************************************************/
2010-02-24 12:04:56 +00:00
void skinny_execute_sql ( skinny_profile_t * profile , char * sql , switch_mutex_t * mutex )
2010-02-24 11:59:41 +00:00
{
switch_core_db_t * db ;
if ( mutex ) {
switch_mutex_lock ( mutex ) ;
}
if ( switch_odbc_available ( ) & & profile - > odbc_dsn ) {
switch_odbc_statement_handle_t stmt ;
2010-02-24 11:59:56 +00:00
if ( switch_odbc_handle_exec ( profile - > master_odbc , sql , & stmt , NULL ) ! = SWITCH_ODBC_SUCCESS ) {
2010-02-24 11:59:41 +00:00
char * err_str ;
err_str = switch_odbc_handle_get_error ( profile - > master_odbc , stmt ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " ERR: [%s] \n [%s] \n " , sql , switch_str_nil ( err_str ) ) ;
switch_safe_free ( err_str ) ;
}
switch_odbc_statement_handle_free ( & stmt ) ;
} else {
if ( ! ( db = switch_core_db_open_file ( profile - > dbname ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Error Opening DB %s \n " , profile - > dbname ) ;
goto end ;
}
2010-02-24 11:59:49 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " SQL: %s \n " , sql ) ;
2010-02-24 11:59:41 +00:00
switch_core_db_persistant_execute ( db , sql , 1 ) ;
switch_core_db_close ( db ) ;
}
end :
if ( mutex ) {
switch_mutex_unlock ( mutex ) ;
}
}
2010-02-24 12:04:56 +00:00
switch_bool_t skinny_execute_sql_callback ( skinny_profile_t * profile ,
2010-02-24 11:59:41 +00:00
switch_mutex_t * mutex , char * sql , switch_core_db_callback_func_t callback , void * pdata )
{
switch_bool_t ret = SWITCH_FALSE ;
switch_core_db_t * db ;
char * errmsg = NULL ;
if ( mutex ) {
switch_mutex_lock ( mutex ) ;
}
if ( switch_odbc_available ( ) & & profile - > odbc_dsn ) {
switch_odbc_handle_callback_exec ( profile - > master_odbc , sql , callback , pdata , NULL ) ;
} else {
if ( ! ( db = switch_core_db_open_file ( profile - > dbname ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Error Opening DB %s \n " , profile - > dbname ) ;
goto end ;
}
2010-02-24 11:59:49 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " SQL: %s \n " , sql ) ;
2010-02-24 11:59:41 +00:00
switch_core_db_exec ( db , sql , callback , pdata , & errmsg ) ;
if ( errmsg ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " SQL ERR: [%s] %s \n " , sql , errmsg ) ;
free ( errmsg ) ;
}
if ( db ) {
switch_core_db_close ( db ) ;
}
}
end :
if ( mutex ) {
switch_mutex_unlock ( mutex ) ;
}
return ret ;
}
2010-02-24 11:58:07 +00:00
/*****************************************************************************/
/* CHANNEL FUNCTIONS */
/*****************************************************************************/
2010-02-24 12:05:26 +00:00
uint32_t skinny_line_perform_set_state ( listener_t * listener , const char * file , const char * func , int line , uint32_t instance , uint32_t state , uint32_t call_id )
{
switch_assert ( listener ) ;
2010-02-24 12:05:34 +00:00
switch_log_printf ( SWITCH_CHANNEL_ID_LOG , file , func , line , NULL , SWITCH_LOG_DEBUG ,
" Device %s, line %d State Change %s (%d) -> %s (%d) (no session) \n " ,
listener - > device_name , instance ,
skinny_soft_key_set2str ( listener - > line_state [ instance ] ) , listener - > line_state [ instance ] ,
skinny_soft_key_set2str ( state ) , state ) ;
2010-02-24 12:05:26 +00:00
send_select_soft_keys ( listener , instance , call_id , state , 0xffff ) ;
listener - > line_state [ instance ] = state ;
return listener - > line_state [ instance ] ;
}
uint32_t skinny_line_get_state ( listener_t * listener , uint32_t instance )
{
switch_assert ( listener ) ;
2010-02-24 11:58:07 +00:00
2010-02-24 12:05:26 +00:00
return listener - > line_state [ instance ] ;
}
2010-02-24 12:04:56 +00:00
switch_status_t skinny_tech_set_codec ( private_t * tech_pvt , int force )
2010-02-24 12:04:08 +00:00
{
int ms ;
switch_status_t status = SWITCH_STATUS_SUCCESS ;
int resetting = 0 ;
if ( ! tech_pvt - > iananame ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( tech_pvt - > session ) , SWITCH_LOG_ERROR , " No audio codec available \n " ) ;
switch_goto_status ( SWITCH_STATUS_FALSE , end ) ;
}
if ( switch_core_codec_ready ( & tech_pvt - > read_codec ) ) {
if ( ! force ) {
switch_goto_status ( SWITCH_STATUS_SUCCESS , end ) ;
}
if ( strcasecmp ( tech_pvt - > read_impl . iananame , tech_pvt - > iananame ) | |
tech_pvt - > read_impl . samples_per_second ! = tech_pvt - > rm_rate | |
tech_pvt - > codec_ms ! = ( uint32_t ) tech_pvt - > read_impl . microseconds_per_packet / 1000 ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( tech_pvt - > session ) , SWITCH_LOG_DEBUG , " Changing Codec from %s@%dms to %s@%dms \n " ,
tech_pvt - > read_impl . iananame , tech_pvt - > read_impl . microseconds_per_packet / 1000 ,
tech_pvt - > rm_encoding , tech_pvt - > codec_ms ) ;
switch_core_session_lock_codec_write ( tech_pvt - > session ) ;
switch_core_session_lock_codec_read ( tech_pvt - > session ) ;
resetting = 1 ;
switch_core_codec_destroy ( & tech_pvt - > read_codec ) ;
switch_core_codec_destroy ( & tech_pvt - > write_codec ) ;
} else {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( tech_pvt - > session ) , SWITCH_LOG_DEBUG , " Already using %s \n " , tech_pvt - > read_impl . iananame ) ;
switch_goto_status ( SWITCH_STATUS_SUCCESS , end ) ;
}
}
if ( switch_core_codec_init ( & tech_pvt - > read_codec ,
tech_pvt - > iananame ,
tech_pvt - > rm_fmtp ,
tech_pvt - > rm_rate ,
tech_pvt - > codec_ms ,
1 ,
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | 0 /* TODO tech_pvt->profile->codec_flags */ ,
NULL , switch_core_session_get_pool ( tech_pvt - > session ) ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( tech_pvt - > session ) , SWITCH_LOG_ERROR , " Can't load codec? \n " ) ;
switch_goto_status ( SWITCH_STATUS_FALSE , end ) ;
}
if ( switch_core_codec_init ( & tech_pvt - > write_codec ,
tech_pvt - > iananame ,
tech_pvt - > rm_fmtp ,
tech_pvt - > rm_rate ,
tech_pvt - > codec_ms ,
1 ,
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | 0 /* TODO tech_pvt->profile->codec_flags */ ,
NULL , switch_core_session_get_pool ( tech_pvt - > session ) ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( tech_pvt - > session ) , SWITCH_LOG_ERROR , " Can't load codec? \n " ) ;
switch_goto_status ( SWITCH_STATUS_FALSE , end ) ;
}
switch_assert ( tech_pvt - > read_codec . implementation ) ;
switch_assert ( tech_pvt - > write_codec . implementation ) ;
tech_pvt - > read_impl = * tech_pvt - > read_codec . implementation ;
tech_pvt - > write_impl = * tech_pvt - > write_codec . implementation ;
switch_core_session_set_read_impl ( tech_pvt - > session , tech_pvt - > read_codec . implementation ) ;
switch_core_session_set_write_impl ( tech_pvt - > session , tech_pvt - > write_codec . implementation ) ;
if ( switch_rtp_ready ( tech_pvt - > rtp_session ) ) {
switch_assert ( tech_pvt - > read_codec . implementation ) ;
if ( switch_rtp_change_interval ( tech_pvt - > rtp_session ,
tech_pvt - > read_impl . microseconds_per_packet ,
tech_pvt - > read_impl . samples_per_packet
) ! = SWITCH_STATUS_SUCCESS ) {
/* TODO
switch_channel_hangup ( tech_pvt - > channel , SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ) ;
*/
switch_goto_status ( SWITCH_STATUS_FALSE , end ) ;
}
}
tech_pvt - > read_frame . rate = tech_pvt - > rm_rate ;
ms = tech_pvt - > write_codec . implementation - > microseconds_per_packet / 1000 ;
if ( ! switch_core_codec_ready ( & tech_pvt - > read_codec ) ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( tech_pvt - > session ) , SWITCH_LOG_ERROR , " Can't load codec? \n " ) ;
switch_goto_status ( SWITCH_STATUS_FALSE , end ) ;
}
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( tech_pvt - > session ) , SWITCH_LOG_DEBUG , " Set Codec %s %s/%ld %d ms %d samples \n " ,
" " /* TODO switch_channel_get_name(tech_pvt->channel)*/ , tech_pvt - > iananame , tech_pvt - > rm_rate , tech_pvt - > codec_ms ,
tech_pvt - > read_impl . samples_per_packet ) ;
tech_pvt - > read_frame . codec = & tech_pvt - > read_codec ;
tech_pvt - > write_codec . agreed_pt = tech_pvt - > agreed_pt ;
tech_pvt - > read_codec . agreed_pt = tech_pvt - > agreed_pt ;
if ( force ! = 2 ) {
switch_core_session_set_read_codec ( tech_pvt - > session , & tech_pvt - > read_codec ) ;
switch_core_session_set_write_codec ( tech_pvt - > session , & tech_pvt - > write_codec ) ;
}
/* TODO
tech_pvt - > fmtp_out = switch_core_session_strdup ( tech_pvt - > session , tech_pvt - > write_codec . fmtp_out ) ;
*/
/* TODO
if ( switch_rtp_ready ( tech_pvt - > rtp_session ) ) {
switch_rtp_set_default_payload ( tech_pvt - > rtp_session , tech_pvt - > pt ) ;
}
*/
end :
if ( resetting ) {
switch_core_session_unlock_codec_write ( tech_pvt - > session ) ;
switch_core_session_unlock_codec_read ( tech_pvt - > session ) ;
}
return status ;
}
2010-02-24 12:04:56 +00:00
void tech_init ( private_t * tech_pvt , switch_core_session_t * session )
2010-02-24 11:57:37 +00:00
{
tech_pvt - > read_frame . data = tech_pvt - > databuf ;
tech_pvt - > read_frame . buflen = sizeof ( tech_pvt - > databuf ) ;
switch_mutex_init ( & tech_pvt - > mutex , SWITCH_MUTEX_NESTED , switch_core_session_get_pool ( session ) ) ;
switch_mutex_init ( & tech_pvt - > flag_mutex , SWITCH_MUTEX_NESTED , switch_core_session_get_pool ( session ) ) ;
2010-02-24 12:04:08 +00:00
tech_pvt - > call_id = 12345 ; /* TODO */
2010-02-24 11:57:37 +00:00
switch_core_session_set_private ( session , tech_pvt ) ;
tech_pvt - > session = session ;
}
/*
State methods they get called when the state changes to the specific state
returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it .
*/
2010-02-24 12:04:56 +00:00
switch_status_t channel_on_init ( switch_core_session_t * session )
2010-02-24 11:57:37 +00:00
{
switch_channel_t * channel ;
private_t * tech_pvt = NULL ;
tech_pvt = switch_core_session_get_private ( session ) ;
assert ( tech_pvt ! = NULL ) ;
channel = switch_core_session_get_channel ( session ) ;
assert ( channel ! = NULL ) ;
switch_set_flag_locked ( tech_pvt , TFLAG_IO ) ;
/* Move channel's state machine to ROUTING. This means the call is trying
to get from the initial start where the call because , to the point
where a destination has been identified . If the channel is simply
left in the initial state , nothing will happen . */
switch_channel_set_state ( channel , CS_ROUTING ) ;
2010-02-24 11:59:41 +00:00
switch_mutex_lock ( globals . calls_mutex ) ;
2010-02-24 11:57:37 +00:00
globals . calls + + ;
2010-02-24 11:59:41 +00:00
switch_mutex_unlock ( globals . calls_mutex ) ;
2010-02-24 11:57:37 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " %s CHANNEL INIT \n " , switch_channel_get_name ( channel ) ) ;
return SWITCH_STATUS_SUCCESS ;
}
2010-02-24 12:04:56 +00:00
switch_status_t channel_on_routing ( switch_core_session_t * session )
2010-02-24 11:57:37 +00:00
{
switch_channel_t * channel = NULL ;
private_t * tech_pvt = NULL ;
channel = switch_core_session_get_channel ( session ) ;
assert ( channel ! = NULL ) ;
tech_pvt = switch_core_session_get_private ( session ) ;
assert ( tech_pvt ! = NULL ) ;
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " %s CHANNEL ROUTING \n " , switch_channel_get_name ( channel ) ) ;
return SWITCH_STATUS_SUCCESS ;
}
2010-02-24 12:04:56 +00:00
switch_status_t channel_on_execute ( switch_core_session_t * session )
2010-02-24 11:57:37 +00:00
{
switch_channel_t * channel = NULL ;
private_t * tech_pvt = NULL ;
channel = switch_core_session_get_channel ( session ) ;
assert ( channel ! = NULL ) ;
tech_pvt = switch_core_session_get_private ( session ) ;
assert ( tech_pvt ! = NULL ) ;
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " %s CHANNEL EXECUTE \n " , switch_channel_get_name ( channel ) ) ;
return SWITCH_STATUS_SUCCESS ;
}
2010-02-24 12:04:56 +00:00
switch_status_t channel_on_destroy ( switch_core_session_t * session )
2010-02-24 11:57:37 +00:00
{
switch_channel_t * channel = NULL ;
private_t * tech_pvt = NULL ;
channel = switch_core_session_get_channel ( session ) ;
assert ( channel ! = NULL ) ;
tech_pvt = switch_core_session_get_private ( session ) ;
if ( tech_pvt ) {
if ( switch_core_codec_ready ( & tech_pvt - > read_codec ) ) {
switch_core_codec_destroy ( & tech_pvt - > read_codec ) ;
}
if ( switch_core_codec_ready ( & tech_pvt - > write_codec ) ) {
switch_core_codec_destroy ( & tech_pvt - > write_codec ) ;
}
}
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " %s CHANNEL DESTROY \n " , switch_channel_get_name ( channel ) ) ;
return SWITCH_STATUS_SUCCESS ;
}
2010-02-24 12:04:56 +00:00
switch_status_t channel_on_hangup ( switch_core_session_t * session )
2010-02-24 11:57:37 +00:00
{
switch_channel_t * channel = NULL ;
private_t * tech_pvt = NULL ;
2010-02-24 12:04:08 +00:00
listener_t * listener = NULL ;
2010-02-24 11:57:37 +00:00
channel = switch_core_session_get_channel ( session ) ;
assert ( channel ! = NULL ) ;
tech_pvt = switch_core_session_get_private ( session ) ;
assert ( tech_pvt ! = NULL ) ;
2010-02-24 12:04:08 +00:00
listener = tech_pvt - > listener ;
assert ( listener ! = NULL ) ;
2010-02-24 11:57:37 +00:00
switch_clear_flag_locked ( tech_pvt , TFLAG_IO ) ;
switch_clear_flag_locked ( tech_pvt , TFLAG_VOICE ) ;
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " %s CHANNEL HANGUP \n " , switch_channel_get_name ( channel ) ) ;
2010-02-24 12:04:08 +00:00
2010-02-24 12:04:36 +00:00
listener - > session [ tech_pvt - > line ] = NULL ;
2010-02-24 12:04:08 +00:00
stop_tone ( listener , tech_pvt - > line , tech_pvt - > call_id ) ;
set_lamp ( listener , SKINNY_BUTTON_LINE , tech_pvt - > line , SKINNY_LAMP_OFF ) ;
clear_prompt_status ( listener , tech_pvt - > line , tech_pvt - > call_id ) ;
close_receive_channel ( listener ,
tech_pvt - > call_id , /* uint32_t conference_id, */
tech_pvt - > party_id , /* uint32_t pass_thru_party_id, */
tech_pvt - > call_id /* uint32_t conference_id2, */
) ;
stop_media_transmission ( listener ,
tech_pvt - > call_id , /* uint32_t conference_id, */
tech_pvt - > party_id , /* uint32_t pass_thru_party_id, */
tech_pvt - > call_id /* uint32_t conference_id2, */
) ;
send_call_state ( listener ,
SKINNY_ON_HOOK ,
tech_pvt - > line ,
tech_pvt - > call_id ) ;
2010-02-24 12:05:34 +00:00
skinny_line_set_state ( listener , tech_pvt - > line , SKINNY_KEY_SET_ON_HOOK , tech_pvt - > call_id ) ;
2010-02-24 12:04:08 +00:00
/* TODO: DefineTimeDate */
set_speaker_mode ( listener , SKINNY_SPEAKER_OFF ) ;
set_ringer ( listener , SKINNY_RING_OFF , SKINNY_RING_FOREVER , 0 ) ;
2010-02-24 11:59:41 +00:00
switch_mutex_lock ( globals . calls_mutex ) ;
2010-02-24 11:57:37 +00:00
globals . calls - - ;
if ( globals . calls < 0 ) {
globals . calls = 0 ;
}
2010-02-24 11:59:41 +00:00
switch_mutex_unlock ( globals . calls_mutex ) ;
2010-02-24 11:57:37 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2010-02-24 12:04:56 +00:00
switch_status_t channel_kill_channel ( switch_core_session_t * session , int sig )
2010-02-24 11:57:37 +00:00
{
switch_channel_t * channel = NULL ;
private_t * tech_pvt = NULL ;
channel = switch_core_session_get_channel ( session ) ;
assert ( channel ! = NULL ) ;
tech_pvt = switch_core_session_get_private ( session ) ;
assert ( tech_pvt ! = NULL ) ;
switch ( sig ) {
case SWITCH_SIG_KILL :
switch_clear_flag_locked ( tech_pvt , TFLAG_IO ) ;
switch_clear_flag_locked ( tech_pvt , TFLAG_VOICE ) ;
switch_channel_hangup ( channel , SWITCH_CAUSE_NORMAL_CLEARING ) ;
break ;
case SWITCH_SIG_BREAK :
switch_set_flag_locked ( tech_pvt , TFLAG_BREAK ) ;
break ;
default :
break ;
}
2010-02-24 12:04:08 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " %s CHANNEL KILL %d \n " , switch_channel_get_name ( channel ) , sig ) ;
2010-02-24 11:57:37 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2010-02-24 12:04:56 +00:00
switch_status_t channel_on_exchange_media ( switch_core_session_t * session )
2010-02-24 11:57:37 +00:00
{
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " CHANNEL LOOPBACK \n " ) ;
return SWITCH_STATUS_SUCCESS ;
}
2010-02-24 12:04:56 +00:00
switch_status_t channel_on_soft_execute ( switch_core_session_t * session )
2010-02-24 11:57:37 +00:00
{
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " CHANNEL TRANSMIT \n " ) ;
return SWITCH_STATUS_SUCCESS ;
}
2010-02-24 12:04:56 +00:00
switch_status_t channel_send_dtmf ( switch_core_session_t * session , const switch_dtmf_t * dtmf )
2010-02-24 11:57:37 +00:00
{
private_t * tech_pvt = switch_core_session_get_private ( session ) ;
switch_assert ( tech_pvt ! = NULL ) ;
2010-02-24 12:04:16 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " DTMF ON CALL %d [%c] \n " , tech_pvt - > call_id , dtmf - > digit ) ;
2010-02-24 11:57:37 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2010-02-24 12:04:56 +00:00
switch_status_t channel_read_frame ( switch_core_session_t * session , switch_frame_t * * frame , switch_io_flag_t flags , int stream_id )
2010-02-24 11:57:37 +00:00
{
switch_channel_t * channel = NULL ;
private_t * tech_pvt = NULL ;
2010-02-24 12:04:08 +00:00
int payload = 0 ;
2010-02-24 11:57:37 +00:00
channel = switch_core_session_get_channel ( session ) ;
assert ( channel ! = NULL ) ;
tech_pvt = switch_core_session_get_private ( session ) ;
assert ( tech_pvt ! = NULL ) ;
2010-02-24 12:04:08 +00:00
while ( ! ( tech_pvt - > read_codec . implementation & & switch_rtp_ready ( tech_pvt - > rtp_session ) ) ) {
if ( switch_channel_ready ( channel ) ) {
switch_yield ( 10000 ) ;
} else {
return SWITCH_STATUS_GENERR ;
2010-02-24 11:57:37 +00:00
}
2010-02-24 12:04:08 +00:00
}
tech_pvt - > read_frame . datalen = 0 ;
switch_set_flag_locked ( tech_pvt , TFLAG_READING ) ;
if ( switch_test_flag ( tech_pvt , TFLAG_IO ) ) {
switch_status_t status ;
switch_assert ( tech_pvt - > rtp_session ! = NULL ) ;
tech_pvt - > read_frame . datalen = 0 ;
2010-02-24 11:57:37 +00:00
2010-02-24 12:04:08 +00:00
while ( switch_test_flag ( tech_pvt , TFLAG_IO ) & & tech_pvt - > read_frame . datalen = = 0 ) {
tech_pvt - > read_frame . flags = SFF_NONE ;
status = switch_rtp_zerocopy_read_frame ( tech_pvt - > rtp_session , & tech_pvt - > read_frame , flags ) ;
if ( status ! = SWITCH_STATUS_SUCCESS & & status ! = SWITCH_STATUS_BREAK ) {
return SWITCH_STATUS_FALSE ;
2010-02-24 11:57:37 +00:00
}
2010-02-24 12:04:08 +00:00
payload = tech_pvt - > read_frame . payload ;
if ( switch_rtp_has_dtmf ( tech_pvt - > rtp_session ) ) {
switch_dtmf_t dtmf = { 0 } ;
switch_rtp_dequeue_dtmf ( tech_pvt - > rtp_session , & dtmf ) ;
switch_channel_queue_dtmf ( channel , & dtmf ) ;
2010-02-24 11:57:37 +00:00
}
2010-02-24 12:04:08 +00:00
if ( tech_pvt - > read_frame . datalen > 0 ) {
size_t bytes = 0 ;
int frames = 1 ;
if ( ! switch_test_flag ( ( & tech_pvt - > read_frame ) , SFF_CNG ) ) {
if ( ( bytes = tech_pvt - > read_codec . implementation - > encoded_bytes_per_packet ) ) {
frames = ( tech_pvt - > read_frame . datalen / bytes ) ;
}
tech_pvt - > read_frame . samples = ( int ) ( frames * tech_pvt - > read_codec . implementation - > samples_per_packet ) ;
}
break ;
}
}
2010-02-24 11:57:37 +00:00
}
2010-02-24 12:04:08 +00:00
switch_clear_flag_locked ( tech_pvt , TFLAG_READING ) ;
2010-02-24 11:57:37 +00:00
2010-02-24 12:04:08 +00:00
if ( tech_pvt - > read_frame . datalen = = 0 ) {
* frame = NULL ;
return SWITCH_STATUS_GENERR ;
}
2010-02-24 11:57:37 +00:00
* frame = & tech_pvt - > read_frame ;
2010-02-24 12:04:08 +00:00
return SWITCH_STATUS_SUCCESS ;
2010-02-24 11:57:37 +00:00
}
2010-02-24 12:04:56 +00:00
switch_status_t channel_write_frame ( switch_core_session_t * session , switch_frame_t * frame , switch_io_flag_t flags , int stream_id )
2010-02-24 11:57:37 +00:00
{
switch_channel_t * channel = NULL ;
private_t * tech_pvt = NULL ;
//switch_frame_t *pframe;
2010-02-24 12:04:08 +00:00
switch_status_t status = SWITCH_STATUS_SUCCESS ;
2010-02-24 11:57:37 +00:00
channel = switch_core_session_get_channel ( session ) ;
assert ( channel ! = NULL ) ;
tech_pvt = switch_core_session_get_private ( session ) ;
assert ( tech_pvt ! = NULL ) ;
if ( ! switch_test_flag ( tech_pvt , TFLAG_IO ) ) {
return SWITCH_STATUS_FALSE ;
}
# if SWITCH_BYTE_ORDER == __BIG_ENDIAN
if ( switch_test_flag ( tech_pvt , TFLAG_LINEAR ) ) {
switch_swap_linear ( frame - > data , ( int ) frame - > datalen / 2 ) ;
}
# endif
2010-02-24 12:04:08 +00:00
switch_set_flag_locked ( tech_pvt , TFLAG_WRITING ) ;
2010-02-24 11:57:37 +00:00
2010-02-24 12:04:08 +00:00
switch_rtp_write_frame ( tech_pvt - > rtp_session , frame ) ;
switch_clear_flag_locked ( tech_pvt , TFLAG_WRITING ) ;
return status ;
2010-02-24 11:57:37 +00:00
}
2010-02-24 12:04:56 +00:00
switch_status_t channel_answer_channel ( switch_core_session_t * session )
2010-02-24 11:57:37 +00:00
{
private_t * tech_pvt ;
switch_channel_t * channel = NULL ;
channel = switch_core_session_get_channel ( session ) ;
assert ( channel ! = NULL ) ;
tech_pvt = switch_core_session_get_private ( session ) ;
assert ( tech_pvt ! = NULL ) ;
return SWITCH_STATUS_SUCCESS ;
}
2010-02-24 12:04:56 +00:00
switch_status_t channel_receive_message ( switch_core_session_t * session , switch_core_session_message_t * msg )
2010-02-24 11:57:37 +00:00
{
switch_channel_t * channel ;
private_t * tech_pvt ;
channel = switch_core_session_get_channel ( session ) ;
assert ( channel ! = NULL ) ;
tech_pvt = ( private_t * ) switch_core_session_get_private ( session ) ;
assert ( tech_pvt ! = NULL ) ;
switch ( msg - > message_id ) {
case SWITCH_MESSAGE_INDICATE_ANSWER :
{
channel_answer_channel ( session ) ;
}
break ;
default :
break ;
}
return SWITCH_STATUS_SUCCESS ;
}
/* Make sure when you have 2 sessions in the same scope that you pass the appropriate one to the routines
that allocate memory or you will have 1 channel with memory allocated from another channel ' s pool !
*/
2010-02-24 12:04:56 +00:00
switch_call_cause_t channel_outgoing_channel ( switch_core_session_t * session , switch_event_t * var_event ,
2010-02-24 11:57:37 +00:00
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 )
{
2010-02-24 12:00:11 +00:00
switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ;
switch_core_session_t * nsession = NULL ;
private_t * tech_pvt ;
char * profile_name , * dest ;
skinny_profile_t * profile = NULL ;
char name [ 128 ] ;
switch_channel_t * channel ;
switch_caller_profile_t * caller_profile ;
2010-02-24 11:57:37 +00:00
2010-02-24 12:00:11 +00:00
if ( ! outbound_profile | | zstr ( outbound_profile - > destination_number ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CRIT , " Invalid Destination \n " ) ;
goto error ;
}
2010-02-24 11:57:37 +00:00
2010-02-24 12:00:11 +00:00
if ( ! ( nsession = switch_core_session_request ( skinny_endpoint_interface , SWITCH_CALL_DIRECTION_OUTBOUND , pool ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CRIT , " Error Creating Session \n " ) ;
goto error ;
}
2010-02-24 11:57:37 +00:00
2010-02-24 12:00:11 +00:00
if ( ! ( tech_pvt = ( struct private_object * ) switch_core_session_alloc ( nsession , sizeof ( * tech_pvt ) ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_CRIT , " Error Creating Session private object \n " ) ;
goto error ;
}
2010-02-24 11:57:37 +00:00
2010-02-24 12:00:11 +00:00
tech_init ( tech_pvt , nsession ) ;
if ( ! ( profile_name = switch_core_session_strdup ( nsession , outbound_profile - > destination_number ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_CRIT , " Error Creating Session Info \n " ) ;
goto error ;
}
2010-02-24 11:57:37 +00:00
2010-02-24 12:00:11 +00:00
if ( ! ( dest = strchr ( profile_name , ' / ' ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Invalid Skinny URL. Should be skinny/<profile>/<number>. \n " ) ;
cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT ;
goto error ;
}
* dest + + = ' \0 ' ;
2010-02-24 11:57:37 +00:00
2010-02-24 12:00:11 +00:00
profile = skinny_find_profile ( profile_name ) ;
if ( ! ( profile = skinny_find_profile ( profile_name ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Invalid Profile %s \n " , profile_name ) ;
cause = SWITCH_CAUSE_UNALLOCATED_NUMBER ;
goto error ;
2010-02-24 11:57:37 +00:00
}
2010-02-24 12:00:11 +00:00
snprintf ( name , sizeof ( name ) , " SKINNY/%s/%s " , profile - > name , dest ) ;
channel = switch_core_session_get_channel ( nsession ) ;
switch_channel_set_name ( channel , name ) ;
caller_profile = switch_caller_profile_clone ( nsession , outbound_profile ) ;
switch_channel_set_caller_profile ( channel , caller_profile ) ;
tech_pvt - > caller_profile = caller_profile ;
2010-02-24 11:57:37 +00:00
2010-02-24 12:00:11 +00:00
switch_channel_set_flag ( channel , CF_OUTBOUND ) ;
switch_set_flag_locked ( tech_pvt , TFLAG_OUTBOUND ) ;
2010-02-24 11:57:37 +00:00
2010-02-24 12:04:25 +00:00
if ( ( skinny_profile_find_listener ( profile , dest , & tech_pvt - > listener , & tech_pvt - > line ) ! = SWITCH_STATUS_SUCCESS ) ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Problem while retrieving listener and line for destination %s in profile %s \n " , dest , profile_name ) ;
cause = SWITCH_CAUSE_UNALLOCATED_NUMBER ;
goto error ;
}
2010-02-24 12:04:08 +00:00
if ( ! tech_pvt - > listener ) {
2010-02-24 12:04:25 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Invalid destination or phone not registred %s in profile %s \n " , dest , profile_name ) ;
2010-02-24 12:04:08 +00:00
cause = SWITCH_CAUSE_UNALLOCATED_NUMBER ;
2010-02-24 12:00:11 +00:00
goto error ;
}
2010-02-24 12:04:08 +00:00
2010-02-24 12:04:25 +00:00
if ( tech_pvt - > line = = 0 ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Invalid destination or phone not registred %s in profile %s \n " , dest , profile_name ) ;
cause = SWITCH_CAUSE_UNALLOCATED_NUMBER ;
goto error ;
}
2010-02-24 12:00:11 +00:00
2010-02-24 12:04:25 +00:00
if ( tech_pvt - > listener - > session [ tech_pvt - > line ] ) { /* Line is busy */
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Device line is busy %s in profile %s \n " , dest , profile_name ) ;
cause = SWITCH_CAUSE_USER_BUSY ;
goto error ;
}
tech_pvt - > listener - > session [ tech_pvt - > line ] = nsession ;
2010-02-24 12:04:08 +00:00
send_call_state ( tech_pvt - > listener , SKINNY_RING_IN , tech_pvt - > line , tech_pvt - > call_id ) ;
2010-02-24 12:05:34 +00:00
skinny_line_set_state ( tech_pvt - > listener , tech_pvt - > line , SKINNY_KEY_SET_RING_IN , tech_pvt - > call_id ) ;
2010-02-24 12:04:08 +00:00
display_prompt_status ( tech_pvt - > listener , 0 , " \200 \027 tel " , tech_pvt - > line , tech_pvt - > call_id ) ;
/* displayprinotifiymessage */
2010-02-24 12:04:36 +00:00
skinny_send_call_info ( nsession ) ;
2010-02-24 12:04:08 +00:00
set_lamp ( tech_pvt - > listener , SKINNY_BUTTON_LINE , tech_pvt - > line , SKINNY_LAMP_BLINK ) ;
set_ringer ( tech_pvt - > listener , SKINNY_RING_OUTSIDE , SKINNY_RING_FOREVER , 0 ) ;
2010-02-24 12:00:11 +00:00
* new_session = nsession ;
2010-02-24 12:04:08 +00:00
/* ?? switch_channel_mark_ring_ready(channel); */
if ( switch_channel_get_state ( channel ) = = CS_NEW ) {
switch_channel_set_state ( channel , CS_INIT ) ;
}
2010-02-24 12:00:11 +00:00
cause = SWITCH_CAUSE_SUCCESS ;
goto done ;
error :
if ( nsession ) {
switch_core_session_destroy ( & nsession ) ;
}
* pool = NULL ;
done :
if ( profile ) {
if ( cause = = SWITCH_CAUSE_SUCCESS ) {
profile - > ob_calls + + ;
} else {
profile - > ob_failed_calls + + ;
}
}
return cause ;
2010-02-24 11:57:37 +00:00
}
2010-02-24 12:04:56 +00:00
switch_status_t channel_receive_event ( switch_core_session_t * session , switch_event_t * event )
2010-02-24 11:57:37 +00:00
{
struct private_object * tech_pvt = switch_core_session_get_private ( session ) ;
char * body = switch_event_get_body ( event ) ;
switch_assert ( tech_pvt ! = NULL ) ;
if ( ! body ) {
body = " " ;
}
return SWITCH_STATUS_SUCCESS ;
}
switch_state_handler_table_t skinny_state_handlers = {
/*.on_init */ channel_on_init ,
/*.on_routing */ channel_on_routing ,
/*.on_execute */ channel_on_execute ,
/*.on_hangup */ channel_on_hangup ,
/*.on_exchange_media */ channel_on_exchange_media ,
/*.on_soft_execute */ channel_on_soft_execute ,
/*.on_consume_media*/ NULL ,
/*.on_hibernate*/ NULL ,
/*.on_reset*/ NULL ,
/*.on_park*/ NULL ,
/*.on_reporting*/ NULL ,
/*.on_destroy*/ channel_on_destroy
} ;
switch_io_routines_t skinny_io_routines = {
/*.outgoing_channel */ channel_outgoing_channel ,
/*.read_frame */ channel_read_frame ,
/*.write_frame */ channel_write_frame ,
/*.kill_channel */ channel_kill_channel ,
/*.send_dtmf */ channel_send_dtmf ,
/*.receive_message */ channel_receive_message ,
/*.receive_event */ channel_receive_event
} ;
2010-02-24 11:57:45 +00:00
/*****************************************************************************/
2010-02-24 12:04:56 +00:00
/* LISTENER FUNCTIONS */
2010-02-24 11:57:45 +00:00
/*****************************************************************************/
2010-02-24 12:04:56 +00:00
static void add_listener ( listener_t * listener )
2010-02-24 11:58:36 +00:00
{
2010-02-24 12:04:56 +00:00
skinny_profile_t * profile ;
switch_assert ( listener ) ;
assert ( listener - > profile ) ;
profile = listener - > profile ;
switch_mutex_lock ( profile - > listener_mutex ) ;
listener - > next = profile - > listeners ;
profile - > listeners = listener ;
switch_mutex_unlock ( profile - > listener_mutex ) ;
2010-02-24 11:58:36 +00:00
}
2010-02-24 12:04:56 +00:00
static void remove_listener ( listener_t * listener )
2010-02-24 11:57:45 +00:00
{
2010-02-24 12:04:56 +00:00
listener_t * l , * last = NULL ;
skinny_profile_t * profile ;
switch_assert ( listener ) ;
assert ( listener - > profile ) ;
profile = listener - > profile ;
2010-02-24 11:57:45 +00:00
2010-02-24 12:04:56 +00:00
switch_mutex_lock ( profile - > listener_mutex ) ;
for ( l = profile - > listeners ; l ; l = l - > next ) {
if ( l = = listener ) {
if ( last ) {
last - > next = l - > next ;
} else {
profile - > listeners = l - > next ;
}
}
last = l ;
2010-02-24 11:57:45 +00:00
}
2010-02-24 12:04:56 +00:00
switch_mutex_unlock ( profile - > listener_mutex ) ;
}
2010-02-24 11:57:45 +00:00
2010-02-24 12:04:56 +00:00
static void walk_listeners ( skinny_listener_callback_func_t callback , void * pvt )
{
switch_hash_index_t * hi ;
void * val ;
skinny_profile_t * profile ;
listener_t * l ;
/* walk listeners */
for ( hi = switch_hash_first ( NULL , globals . profile_hash ) ; hi ; hi = switch_hash_next ( hi ) ) {
switch_hash_this ( hi , NULL , NULL , & val ) ;
profile = ( skinny_profile_t * ) val ;
2010-02-24 11:57:45 +00:00
2010-02-24 12:04:56 +00:00
switch_mutex_lock ( profile - > listener_mutex ) ;
for ( l = profile - > listeners ; l ; l = l - > next ) {
callback ( l , pvt ) ;
2010-02-24 11:57:45 +00:00
}
2010-02-24 12:04:56 +00:00
switch_mutex_unlock ( profile - > listener_mutex ) ;
2010-02-24 11:57:45 +00:00
}
}
2010-02-24 12:04:56 +00:00
static void flush_listener ( listener_t * listener , switch_bool_t flush_log , switch_bool_t flush_events )
{
/* TODO */
}
static int dump_device_callback ( void * pArg , int argc , char * * argv , char * * columnNames )
2010-02-24 11:59:49 +00:00
{
2010-02-24 12:04:56 +00:00
switch_stream_handle_t * stream = ( switch_stream_handle_t * ) pArg ;
2010-02-24 11:59:49 +00:00
char * device_name = argv [ 0 ] ;
char * user_id = argv [ 1 ] ;
char * instance = argv [ 2 ] ;
char * ip = argv [ 3 ] ;
2010-02-24 12:04:56 +00:00
char * type = argv [ 4 ] ;
2010-02-24 11:59:49 +00:00
char * max_streams = argv [ 5 ] ;
char * port = argv [ 6 ] ;
char * codec_string = argv [ 7 ] ;
2010-02-24 12:04:56 +00:00
const char * line = " ================================================================================================= " ;
stream - > write_function ( stream , " %s \n " , line ) ;
stream - > write_function ( stream , " DeviceName \t %s \n " , switch_str_nil ( device_name ) ) ;
stream - > write_function ( stream , " UserId \t %s \n " , user_id ) ;
stream - > write_function ( stream , " Instance \t %s \n " , instance ) ;
stream - > write_function ( stream , " IP \t %s \n " , ip ) ;
stream - > write_function ( stream , " DeviceType \t %s \n " , type ) ;
stream - > write_function ( stream , " MaxStreams \t %s \n " , max_streams ) ;
stream - > write_function ( stream , " Port \t %s \n " , port ) ;
stream - > write_function ( stream , " Codecs \t %s \n " , codec_string ) ;
stream - > write_function ( stream , " %s \n " , line ) ;
2010-02-24 11:59:49 +00:00
return 0 ;
2010-02-24 11:58:15 +00:00
}
2010-02-24 11:59:49 +00:00
static switch_status_t dump_device ( skinny_profile_t * profile , const char * device_name , switch_stream_handle_t * stream )
2010-02-24 11:58:15 +00:00
{
2010-02-24 11:59:49 +00:00
char * sql ;
2010-02-24 12:00:45 +00:00
if ( ( sql = switch_mprintf ( " SELECT * FROM skinny_devices WHERE name LIKE '%s' " ,
2010-02-24 11:59:49 +00:00
device_name ) ) ) {
skinny_execute_sql_callback ( profile , profile - > listener_mutex , sql , dump_device_callback , stream ) ;
switch_safe_free ( sql ) ;
2010-02-24 11:58:15 +00:00
}
2010-02-24 11:59:49 +00:00
2010-02-24 11:58:15 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2010-02-24 11:59:49 +00:00
2010-02-24 12:00:19 +00:00
static void close_socket ( switch_socket_t * * sock , skinny_profile_t * profile )
2010-02-24 11:57:45 +00:00
{
2010-02-24 11:59:41 +00:00
switch_mutex_lock ( profile - > sock_mutex ) ;
2010-02-24 11:57:45 +00:00
if ( * sock ) {
switch_socket_shutdown ( * sock , SWITCH_SHUTDOWN_READWRITE ) ;
switch_socket_close ( * sock ) ;
* sock = NULL ;
}
2010-02-24 11:59:41 +00:00
switch_mutex_unlock ( profile - > sock_mutex ) ;
2010-02-24 11:57:45 +00:00
}
2010-02-24 11:58:15 +00:00
static switch_status_t kill_listener ( listener_t * listener , void * pvt )
2010-02-24 11:57:45 +00:00
{
2010-02-24 11:58:07 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " Killing listener. \n " ) ;
2010-02-24 11:57:45 +00:00
switch_clear_flag ( listener , LFLAG_RUNNING ) ;
2010-02-24 12:00:19 +00:00
close_socket ( & listener - > sock , listener - > profile ) ;
2010-02-24 11:57:45 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2010-02-24 11:58:15 +00:00
static switch_status_t kill_expired_listener ( listener_t * listener , void * pvt )
2010-02-24 11:58:07 +00:00
{
2010-02-24 11:59:18 +00:00
switch_event_t * event = NULL ;
2010-02-24 11:58:07 +00:00
if ( listener - > expire_time < switch_epoch_time_now ( NULL ) ) {
2010-02-24 11:59:18 +00:00
/* skinny::expire event */
skinny_device_event ( listener , & event , SWITCH_EVENT_CUSTOM , SKINNY_EVENT_EXPIRE ) ;
switch_event_fire ( & event ) ;
2010-02-24 11:58:15 +00:00
return kill_listener ( listener , pvt ) ;
2010-02-24 11:58:07 +00:00
}
return SWITCH_STATUS_SUCCESS ;
}
2010-02-24 12:04:56 +00:00
switch_status_t keepalive_listener ( listener_t * listener , void * pvt )
2010-02-24 11:58:07 +00:00
{
2010-02-24 11:59:41 +00:00
skinny_profile_t * profile ;
2010-02-24 11:58:07 +00:00
switch_assert ( listener ) ;
2010-02-24 11:59:41 +00:00
assert ( listener - > profile ) ;
profile = listener - > profile ;
2010-02-24 11:58:07 +00:00
2010-02-24 11:59:41 +00:00
listener - > expire_time = switch_epoch_time_now ( NULL ) + profile - > keep_alive * 110 / 100 ;
2010-02-24 11:58:07 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2010-02-24 11:57:45 +00:00
static void * SWITCH_THREAD_FUNC listener_run ( switch_thread_t * thread , void * obj )
{
listener_t * listener = ( listener_t * ) obj ;
switch_status_t status ;
skinny_message_t * request = NULL ;
2010-02-24 11:59:41 +00:00
skinny_profile_t * profile ;
2010-02-24 12:04:25 +00:00
int destroy_pool = 1 ;
2010-02-24 11:59:41 +00:00
switch_assert ( listener ) ;
assert ( listener - > profile ) ;
profile = listener - > profile ;
2010-02-24 11:57:45 +00:00
2010-02-24 11:59:41 +00:00
switch_mutex_lock ( profile - > listener_mutex ) ;
profile - > listener_threads + + ;
switch_mutex_unlock ( profile - > listener_mutex ) ;
2010-02-24 11:57:45 +00:00
switch_assert ( listener ! = NULL ) ;
switch_socket_opt_set ( listener - > sock , SWITCH_SO_TCP_NODELAY , TRUE ) ;
switch_socket_opt_set ( listener - > sock , SWITCH_SO_NONBLOCK , TRUE ) ;
if ( globals . debug > 0 ) {
if ( zstr ( listener - > remote_ip ) ) {
2010-02-24 12:04:25 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Connection Open \n " ) ;
2010-02-24 11:57:45 +00:00
} else {
2010-02-24 12:04:25 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Connection Open from %s:%d \n " , listener - > remote_ip , listener - > remote_port ) ;
2010-02-24 11:57:45 +00:00
}
}
switch_socket_opt_set ( listener - > sock , SWITCH_SO_NONBLOCK , TRUE ) ;
switch_set_flag_locked ( listener , LFLAG_RUNNING ) ;
2010-02-24 11:58:15 +00:00
keepalive_listener ( listener , NULL ) ;
2010-02-24 11:57:45 +00:00
add_listener ( listener ) ;
2010-02-24 11:59:41 +00:00
while ( globals . running & & switch_test_flag ( listener , LFLAG_RUNNING ) & & profile - > listener_ready ) {
2010-02-24 11:58:07 +00:00
status = skinny_read_packet ( listener , & request ) ;
2010-02-24 11:57:45 +00:00
if ( status ! = SWITCH_STATUS_SUCCESS ) {
2010-02-24 12:04:25 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CRIT , " Socket Error! \n " ) ;
2010-02-24 11:57:45 +00:00
switch_clear_flag_locked ( listener , LFLAG_RUNNING ) ;
break ;
}
if ( ! request ) {
continue ;
}
2010-02-24 11:58:43 +00:00
if ( skinny_handle_request ( listener , request ) ! = SWITCH_STATUS_SUCCESS ) {
2010-02-24 11:57:45 +00:00
switch_clear_flag_locked ( listener , LFLAG_RUNNING ) ;
break ;
}
}
remove_listener ( listener ) ;
if ( globals . debug > 0 ) {
2010-02-24 12:04:25 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Session complete, waiting for children \n " ) ;
2010-02-24 11:57:45 +00:00
}
switch_thread_rwlock_wrlock ( listener - > rwlock ) ;
flush_listener ( listener , SWITCH_TRUE , SWITCH_TRUE ) ;
if ( listener - > sock ) {
2010-02-24 12:00:19 +00:00
close_socket ( & listener - > sock , profile ) ;
2010-02-24 11:57:45 +00:00
}
switch_thread_rwlock_unlock ( listener - > rwlock ) ;
if ( globals . debug > 0 ) {
2010-02-24 12:04:25 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Connection Closed \n " ) ;
2010-02-24 11:57:45 +00:00
}
2010-02-24 12:04:25 +00:00
for ( int line = 0 ; line < SKINNY_MAX_BUTTON_COUNT ; line + + ) {
if ( listener - > session [ line ] ) {
switch_channel_clear_flag ( switch_core_session_get_channel ( listener - > session [ line ] ) , CF_CONTROLLED ) ;
//TODO switch_clear_flag_locked(listener, LFLAG_SESSION);
switch_core_session_rwunlock ( listener - > session [ line ] ) ;
destroy_pool = 0 ;
}
}
if ( destroy_pool = = 0 ) {
goto no_destroy_pool ;
}
if ( listener - > pool ) {
2010-02-24 11:57:45 +00:00
switch_memory_pool_t * pool = listener - > pool ;
switch_core_destroy_memory_pool ( & pool ) ;
}
2010-02-24 12:04:25 +00:00
no_destroy_pool :
2010-02-24 11:59:41 +00:00
switch_mutex_lock ( profile - > listener_mutex ) ;
profile - > listener_threads - - ;
switch_mutex_unlock ( profile - > listener_mutex ) ;
2010-02-24 11:57:45 +00:00
return NULL ;
}
/* Create a thread for the socket and launch it */
static void launch_listener_thread ( listener_t * listener )
{
switch_thread_t * thread ;
switch_threadattr_t * thd_attr = NULL ;
switch_threadattr_create ( & thd_attr , listener - > pool ) ;
switch_threadattr_detach_set ( thd_attr , 1 ) ;
switch_threadattr_stacksize_set ( thd_attr , SWITCH_THREAD_STACKSIZE ) ;
switch_thread_create ( & thread , thd_attr , listener_run , listener , listener - > pool ) ;
}
2010-02-24 11:59:41 +00:00
int skinny_socket_create_and_bind ( skinny_profile_t * profile )
2010-02-24 11:57:45 +00:00
{
switch_status_t rv ;
switch_sockaddr_t * sa ;
switch_socket_t * inbound_socket = NULL ;
listener_t * listener ;
switch_memory_pool_t * pool = NULL , * listener_pool = NULL ;
uint32_t errs = 0 ;
if ( switch_core_new_memory_pool ( & pool ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " OH OH no pool \n " ) ;
return SWITCH_STATUS_TERM ;
}
2010-02-24 11:59:41 +00:00
while ( globals . running ) {
rv = switch_sockaddr_info_get ( & sa , profile - > ip , SWITCH_INET , profile - > port , 0 , pool ) ;
2010-02-24 11:57:45 +00:00
if ( rv )
goto fail ;
2010-02-24 11:59:41 +00:00
rv = switch_socket_create ( & profile - > sock , switch_sockaddr_get_family ( sa ) , SOCK_STREAM , SWITCH_PROTO_TCP , pool ) ;
2010-02-24 11:57:45 +00:00
if ( rv )
goto sock_fail ;
2010-02-24 11:59:41 +00:00
rv = switch_socket_opt_set ( profile - > sock , SWITCH_SO_REUSEADDR , 1 ) ;
2010-02-24 11:57:45 +00:00
if ( rv )
goto sock_fail ;
2010-02-24 11:59:41 +00:00
rv = switch_socket_bind ( profile - > sock , sa ) ;
2010-02-24 11:57:45 +00:00
if ( rv )
goto sock_fail ;
2010-02-24 11:59:41 +00:00
rv = switch_socket_listen ( profile - > sock , 5 ) ;
2010-02-24 11:57:45 +00:00
if ( rv )
goto sock_fail ;
2010-02-24 11:59:49 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " Socket up listening on %s:%u \n " , profile - > ip , profile - > port ) ;
2010-02-24 11:57:45 +00:00
break ;
sock_fail :
2010-02-24 11:59:41 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Socket Error! Could not listen on %s:%u \n " , profile - > ip , profile - > port ) ;
2010-02-24 11:57:45 +00:00
switch_yield ( 100000 ) ;
}
2010-02-24 11:59:41 +00:00
profile - > listener_ready = 1 ;
2010-02-24 11:57:45 +00:00
2010-02-24 11:59:41 +00:00
while ( globals . running ) {
2010-02-24 11:57:45 +00:00
if ( switch_core_new_memory_pool ( & listener_pool ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " OH OH no pool \n " ) ;
goto fail ;
}
2010-02-24 11:59:41 +00:00
if ( ( rv = switch_socket_accept ( & inbound_socket , profile - > sock , listener_pool ) ) ) {
if ( ! globals . running ) {
2010-02-24 11:57:45 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_NOTICE , " Shutting Down \n " ) ;
goto end ;
} else {
/* I wish we could use strerror_r here but its not defined everywhere =/ */
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Socket Error [%s] \n " , strerror ( errno ) ) ;
if ( + + errs > 100 ) {
goto end ;
}
}
} else {
errs = 0 ;
}
if ( ! ( listener = switch_core_alloc ( listener_pool , sizeof ( * listener ) ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Memory Error \n " ) ;
break ;
}
switch_thread_rwlock_create ( & listener - > rwlock , listener_pool ) ;
listener - > sock = inbound_socket ;
listener - > pool = listener_pool ;
listener_pool = NULL ;
2010-02-24 11:59:49 +00:00
strcpy ( listener - > device_name , " " ) ;
2010-02-24 11:59:41 +00:00
listener - > profile = profile ;
2010-02-24 11:57:45 +00:00
switch_mutex_init ( & listener - > flag_mutex , SWITCH_MUTEX_NESTED , listener - > pool ) ;
switch_socket_addr_get ( & listener - > sa , SWITCH_TRUE , listener - > sock ) ;
switch_get_addr ( listener - > remote_ip , sizeof ( listener - > remote_ip ) , listener - > sa ) ;
listener - > remote_port = switch_sockaddr_get_port ( listener - > sa ) ;
launch_listener_thread ( listener ) ;
}
end :
2010-02-24 12:00:19 +00:00
close_socket ( & profile - > sock , profile ) ;
2010-02-24 11:57:45 +00:00
if ( pool ) {
switch_core_destroy_memory_pool ( & pool ) ;
}
if ( listener_pool ) {
switch_core_destroy_memory_pool ( & listener_pool ) ;
}
fail :
return SWITCH_STATUS_TERM ;
}
/*****************************************************************************/
/* MODULE FUNCTIONS */
/*****************************************************************************/
2010-02-24 12:04:56 +00:00
switch_endpoint_interface_t * skinny_get_endpoint_interface ( )
{
return skinny_endpoint_interface ;
}
2010-02-24 11:59:41 +00:00
static void skinny_profile_set ( skinny_profile_t * profile , char * var , char * val )
{
if ( ! var )
return ;
if ( ! strcasecmp ( var , " domain " ) ) {
profile - > domain = switch_core_strdup ( module_pool , val ) ;
} else if ( ! strcasecmp ( var , " ip " ) ) {
profile - > ip = switch_core_strdup ( module_pool , val ) ;
} else if ( ! strcasecmp ( var , " dialplan " ) ) {
profile - > dialplan = switch_core_strdup ( module_pool , val ) ;
2010-02-24 12:04:36 +00:00
} else if ( ! strcasecmp ( var , " context " ) ) {
profile - > context = switch_core_strdup ( module_pool , val ) ;
2010-02-24 11:59:41 +00:00
} else if ( ! strcasecmp ( var , " odbc-dsn " ) & & ! zstr ( val ) ) {
if ( switch_odbc_available ( ) ) {
profile - > odbc_dsn = switch_core_strdup ( module_pool , val ) ;
if ( ( profile - > odbc_user = strchr ( profile - > odbc_dsn , ' : ' ) ) ) {
* profile - > odbc_user + + = ' \0 ' ;
if ( ( profile - > odbc_pass = strchr ( profile - > odbc_user , ' : ' ) ) ) {
* profile - > odbc_pass + + = ' \0 ' ;
}
}
} else {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " ODBC IS NOT AVAILABLE! \n " ) ;
}
}
}
2010-02-24 11:57:37 +00:00
static switch_status_t load_skinny_config ( void )
{
char * cf = " skinny.conf " ;
2010-02-24 11:59:41 +00:00
switch_xml_t xcfg , xml , xsettings , xprofiles , xprofile , xparam ;
2010-02-24 11:57:37 +00:00
memset ( & globals , 0 , sizeof ( globals ) ) ;
2010-02-24 11:59:41 +00:00
globals . running = 1 ;
switch_core_hash_init ( & globals . profile_hash , module_pool ) ;
switch_mutex_init ( & globals . calls_mutex , SWITCH_MUTEX_NESTED , module_pool ) ;
if ( ! ( xml = switch_xml_open_cfg ( cf , & xcfg , NULL ) ) ) {
2010-02-24 11:57:37 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Open of %s failed \n " , cf ) ;
return SWITCH_STATUS_TERM ;
}
2010-02-24 11:59:41 +00:00
if ( ( xsettings = switch_xml_child ( xcfg , " settings " ) ) ) {
for ( xparam = switch_xml_child ( xsettings , " param " ) ; xparam ; xparam = xparam - > next ) {
char * var = ( char * ) switch_xml_attr_soft ( xparam , " name " ) ;
char * val = ( char * ) switch_xml_attr_soft ( xparam , " value " ) ;
2010-02-24 11:57:37 +00:00
if ( ! strcmp ( var , " debug " ) ) {
globals . debug = atoi ( val ) ;
} else if ( ! strcmp ( var , " codec-prefs " ) ) {
set_global_codec_string ( val ) ;
globals . codec_order_last = switch_separate_string ( globals . codec_string , ' , ' , globals . codec_order , SWITCH_MAX_CODECS ) ;
} else if ( ! strcmp ( var , " codec-master " ) ) {
if ( ! strcasecmp ( val , " us " ) ) {
switch_set_flag ( & globals , GFLAG_MY_CODEC_PREFS ) ;
}
} else if ( ! strcmp ( var , " codec-rates " ) ) {
set_global_codec_rates_string ( val ) ;
globals . codec_rates_last = switch_separate_string ( globals . codec_rates_string , ' , ' , globals . codec_rates , SWITCH_MAX_CODECS ) ;
}
2010-02-24 11:59:41 +00:00
} /* param */
} /* settings */
if ( ( xprofiles = switch_xml_child ( xcfg , " profiles " ) ) ) {
for ( xprofile = switch_xml_child ( xprofiles , " profile " ) ; xprofile ; xprofile = xprofile - > next ) {
char * profile_name = ( char * ) switch_xml_attr_soft ( xprofile , " name " ) ;
switch_xml_t xsettings = switch_xml_child ( xprofile , " settings " ) ;
if ( zstr ( profile_name ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR ,
" <profile> is missing name attribute \n " ) ;
continue ;
}
if ( xsettings ) {
char dbname [ 256 ] ;
switch_core_db_t * db ;
skinny_profile_t * profile = NULL ;
switch_xml_t param ;
profile = switch_core_alloc ( module_pool , sizeof ( skinny_profile_t ) ) ;
profile - > name = profile_name ;
for ( param = switch_xml_child ( xsettings , " param " ) ; param ; param = param - > next ) {
char * var = ( char * ) switch_xml_attr_soft ( param , " name " ) ;
char * val = ( char * ) switch_xml_attr_soft ( param , " value " ) ;
if ( ! strcmp ( var , " domain " ) ) {
skinny_profile_set ( profile , " domain " , val ) ;
} else if ( ! strcmp ( var , " ip " ) ) {
skinny_profile_set ( profile , " ip " , val ) ;
} else if ( ! strcmp ( var , " port " ) ) {
profile - > port = atoi ( val ) ;
} else if ( ! strcmp ( var , " dialplan " ) ) {
skinny_profile_set ( profile , " dialplan " , val ) ;
2010-02-24 12:04:36 +00:00
} else if ( ! strcmp ( var , " context " ) ) {
skinny_profile_set ( profile , " context " , val ) ;
2010-02-24 11:59:41 +00:00
} else if ( ! strcmp ( var , " keep-alive " ) ) {
profile - > keep_alive = atoi ( val ) ;
} else if ( ! strcmp ( var , " date-format " ) ) {
memcpy ( profile - > date_format , val , 6 ) ;
}
} /* param */
if ( ! profile - > dialplan ) {
skinny_profile_set ( profile , " dialplan " , " default " ) ;
}
2010-02-24 11:57:37 +00:00
2010-02-24 12:04:36 +00:00
if ( ! profile - > context ) {
skinny_profile_set ( profile , " context " , " public " ) ;
}
2010-02-24 11:59:41 +00:00
if ( ! profile - > port ) {
profile - > port = 2000 ;
}
2010-02-24 11:57:37 +00:00
2010-02-24 11:59:41 +00:00
switch_snprintf ( dbname , sizeof ( dbname ) , " skinny_%s " , profile - > name ) ;
profile - > dbname = switch_core_strdup ( module_pool , dbname ) ;
if ( switch_odbc_available ( ) & & profile - > odbc_dsn ) {
if ( ! ( profile - > master_odbc = switch_odbc_handle_new ( profile - > odbc_dsn , profile - > odbc_user , profile - > odbc_pass ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CRIT , " Cannot Open ODBC Database! \n " ) ;
continue ;
}
if ( switch_odbc_handle_connect ( profile - > master_odbc ) ! = SWITCH_ODBC_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CRIT , " Cannot Open ODBC Database! \n " ) ;
continue ;
}
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " Connected ODBC DSN: %s \n " , profile - > odbc_dsn ) ;
2010-02-24 11:59:56 +00:00
switch_odbc_handle_exec ( profile - > master_odbc , devices_sql , NULL , NULL ) ;
2010-02-24 12:00:45 +00:00
switch_odbc_handle_exec ( profile - > master_odbc , buttons_sql , NULL , NULL ) ;
2010-02-24 11:59:41 +00:00
} else {
if ( ( db = switch_core_db_open_file ( profile - > dbname ) ) ) {
2010-02-24 11:59:56 +00:00
switch_core_db_test_reactive ( db , " SELECT * FROM skinny_devices " , NULL , devices_sql ) ;
2010-02-24 12:00:45 +00:00
switch_core_db_test_reactive ( db , " SELECT * FROM skinny_buttons " , NULL , buttons_sql ) ;
2010-02-24 11:59:41 +00:00
} else {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CRIT , " Cannot Open SQL Database! \n " ) ;
continue ;
}
switch_core_db_close ( db ) ;
}
2010-02-24 12:00:28 +00:00
skinny_execute_sql_callback ( profile , profile - > listener_mutex , " DELETE FROM skinny_devices " , NULL , NULL ) ;
2010-02-24 12:00:45 +00:00
skinny_execute_sql_callback ( profile , profile - > listener_mutex , " DELETE FROM skinny_buttons " , NULL , NULL ) ;
2010-02-24 12:00:28 +00:00
2010-02-24 12:01:47 +00:00
switch_core_hash_init ( & profile - > session_hash , module_pool ) ;
2010-02-24 11:59:41 +00:00
switch_core_hash_insert ( globals . profile_hash , profile - > name , profile ) ;
profile = NULL ;
} else {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR ,
" Settings are missing from profile %s. \n " , profile_name ) ;
} /* settings */
} /* profile */
}
2010-02-24 11:57:37 +00:00
switch_xml_free ( xml ) ;
return SWITCH_STATUS_SUCCESS ;
}
2010-02-24 11:59:49 +00:00
static switch_status_t cmd_status_profile ( const char * profile_name , switch_stream_handle_t * stream )
2010-02-24 11:58:15 +00:00
{
2010-02-24 11:59:49 +00:00
skinny_profile_t * profile ;
2010-02-24 12:00:11 +00:00
if ( ( profile = skinny_find_profile ( profile_name ) ) ) {
2010-02-24 11:59:49 +00:00
dump_profile ( profile , stream ) ;
} else {
stream - > write_function ( stream , " Profile not found! \n " ) ;
2010-02-24 11:58:15 +00:00
}
2010-02-24 11:59:49 +00:00
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t cmd_status_profile_device ( const char * profile_name , const char * device_name , switch_stream_handle_t * stream )
{
skinny_profile_t * profile ;
2010-02-24 12:00:11 +00:00
if ( ( profile = skinny_find_profile ( profile_name ) ) ) {
2010-02-24 11:59:49 +00:00
dump_device ( profile , device_name , stream ) ;
2010-02-24 11:58:15 +00:00
} else {
2010-02-24 11:59:49 +00:00
stream - > write_function ( stream , " Profile not found! \n " ) ;
2010-02-24 11:58:15 +00:00
}
2010-02-24 11:59:49 +00:00
2010-02-24 11:58:15 +00:00
return SWITCH_STATUS_SUCCESS ;
}
SWITCH_STANDARD_API ( skinny_function )
{
char * argv [ 1024 ] = { 0 } ;
int argc = 0 ;
char * mycmd = NULL ;
switch_status_t status = SWITCH_STATUS_SUCCESS ;
const char * usage_string = " USAGE: \n "
" -------------------------------------------------------------------------------- \n "
" skinny help \n "
2010-02-24 11:59:49 +00:00
" skinny status profile <profile_name> \n "
" skinny status profile <profile_name> device <device_name> \n "
2010-02-24 11:58:15 +00:00
" -------------------------------------------------------------------------------- \n " ;
if ( session ) {
return SWITCH_STATUS_FALSE ;
}
if ( zstr ( cmd ) ) {
stream - > write_function ( stream , " %s " , usage_string ) ;
goto done ;
}
if ( ! ( mycmd = strdup ( cmd ) ) ) {
status = SWITCH_STATUS_MEMERR ;
goto done ;
}
if ( ! ( argc = switch_separate_string ( mycmd , ' ' , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ) | | ! argv [ 0 ] ) {
stream - > write_function ( stream , " %s " , usage_string ) ;
goto done ;
}
2010-02-24 11:59:49 +00:00
if ( argc = = 3 & & ! strcasecmp ( argv [ 0 ] , " status " ) & & ! strcasecmp ( argv [ 1 ] , " profile " ) ) {
status = cmd_status_profile ( argv [ 2 ] , stream ) ;
} else if ( argc = = 5 & & ! strcasecmp ( argv [ 0 ] , " status " ) & & ! strcasecmp ( argv [ 1 ] , " profile " ) & & ! strcasecmp ( argv [ 3 ] , " device " ) ) {
status = cmd_status_profile_device ( argv [ 2 ] , argv [ 4 ] , stream ) ;
2010-02-24 11:58:15 +00:00
} else if ( ! strcasecmp ( argv [ 0 ] , " help " ) ) {
stream - > write_function ( stream , " %s " , usage_string ) ;
goto done ;
} else {
stream - > write_function ( stream , " Unknown Command [%s] \n " , argv [ 0 ] ) ;
}
2010-02-24 11:59:49 +00:00
done :
2010-02-24 11:58:15 +00:00
switch_safe_free ( mycmd ) ;
return status ;
}
2010-02-24 11:57:37 +00:00
static void event_handler ( switch_event_t * event )
{
2010-02-24 11:57:45 +00:00
if ( event - > event_id = = SWITCH_EVENT_HEARTBEAT ) {
2010-02-24 11:58:15 +00:00
walk_listeners ( kill_expired_listener , NULL ) ;
2010-02-24 11:57:37 +00:00
}
}
2010-02-24 11:59:49 +00:00
static switch_status_t skinny_list_profiles ( const char * line , const char * cursor , switch_console_callback_match_t * * matches )
2010-02-24 11:58:15 +00:00
{
switch_console_callback_match_t * my_matches = NULL ;
switch_status_t status = SWITCH_STATUS_FALSE ;
2010-02-24 11:59:41 +00:00
switch_hash_index_t * hi ;
void * val ;
skinny_profile_t * profile ;
2010-02-24 11:59:49 +00:00
/* walk profiles */
2010-02-24 11:59:41 +00:00
for ( hi = switch_hash_first ( NULL , globals . profile_hash ) ; hi ; hi = switch_hash_next ( hi ) ) {
switch_hash_this ( hi , NULL , NULL , & val ) ;
profile = ( skinny_profile_t * ) val ;
2010-02-24 11:59:49 +00:00
switch_console_push_match ( & my_matches , profile - > name ) ;
}
if ( my_matches ) {
* matches = my_matches ;
status = SWITCH_STATUS_SUCCESS ;
}
return status ;
}
2010-02-24 12:00:04 +00:00
struct match_helper {
switch_console_callback_match_t * my_matches ;
} ;
2010-02-24 11:59:49 +00:00
static int skinny_list_devices_callback ( void * pArg , int argc , char * * argv , char * * columnNames )
{
2010-02-24 12:00:04 +00:00
struct match_helper * h = ( struct match_helper * ) pArg ;
2010-02-24 11:59:49 +00:00
char * device_name = argv [ 0 ] ;
2010-02-24 12:00:04 +00:00
switch_console_push_match ( & h - > my_matches , device_name ) ;
2010-02-24 11:59:49 +00:00
return 0 ;
}
static switch_status_t skinny_list_devices ( const char * line , const char * cursor , switch_console_callback_match_t * * matches )
{
2010-02-24 12:00:04 +00:00
struct match_helper h = { 0 } ;
2010-02-24 11:59:49 +00:00
switch_status_t status = SWITCH_STATUS_FALSE ;
skinny_profile_t * profile ;
char * sql ;
char * myline ;
char * argv [ 1024 ] = { 0 } ;
int argc = 0 ;
if ( ! ( myline = strdup ( line ) ) ) {
status = SWITCH_STATUS_MEMERR ;
return status ;
}
if ( ! ( argc = switch_separate_string ( myline , ' ' , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ) | | argc ! = 5 ) {
return status ;
}
2010-02-24 12:00:11 +00:00
if ( ( profile = skinny_find_profile ( argv [ 3 ] ) ) ) {
2010-02-24 12:00:45 +00:00
if ( ( sql = switch_mprintf ( " SELECT name FROM skinny_devices " ) ) ) {
2010-02-24 12:00:04 +00:00
skinny_execute_sql_callback ( profile , profile - > listener_mutex , sql , skinny_list_devices_callback , & h ) ;
2010-02-24 11:59:49 +00:00
switch_safe_free ( sql ) ;
2010-02-24 11:58:15 +00:00
}
}
2010-02-24 11:59:41 +00:00
2010-02-24 12:00:04 +00:00
if ( h . my_matches ) {
* matches = h . my_matches ;
2010-02-24 11:58:15 +00:00
status = SWITCH_STATUS_SUCCESS ;
}
return status ;
}
2010-02-24 11:57:37 +00:00
SWITCH_MODULE_LOAD_FUNCTION ( mod_skinny_load )
{
2010-02-24 11:59:41 +00:00
switch_hash_index_t * hi ;
void * val ;
skinny_profile_t * profile ;
2010-02-24 11:58:15 +00:00
switch_api_interface_t * api_interface ;
2010-02-24 11:57:37 +00:00
module_pool = pool ;
load_skinny_config ( ) ;
2010-02-24 11:59:41 +00:00
/* init listeners */
for ( hi = switch_hash_first ( NULL , globals . profile_hash ) ; hi ; hi = switch_hash_next ( hi ) ) {
switch_hash_this ( hi , NULL , NULL , & val ) ;
profile = ( skinny_profile_t * ) val ;
switch_mutex_init ( & profile - > listener_mutex , SWITCH_MUTEX_NESTED , module_pool ) ;
switch_mutex_init ( & profile - > sock_mutex , SWITCH_MUTEX_NESTED , module_pool ) ;
2010-02-24 11:57:45 +00:00
2010-02-24 11:59:41 +00:00
}
2010-02-24 11:57:45 +00:00
if ( ( switch_event_bind_removable ( modname , SWITCH_EVENT_HEARTBEAT , NULL , event_handler , NULL , & globals . heartbeat_node ) ! = SWITCH_STATUS_SUCCESS ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Couldn't bind our heartbeat handler! \n " ) ;
/* Not such severe to prevent loading */
}
2010-02-24 11:58:54 +00:00
if ( switch_event_reserve_subclass ( SKINNY_EVENT_REGISTER ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Couldn't register subclass %s! \n " , SKINNY_EVENT_REGISTER ) ;
return SWITCH_STATUS_TERM ;
}
2010-02-24 11:57:37 +00:00
/* connect my internal structure to the blank pointer passed to me */
* module_interface = switch_loadable_module_create_module_interface ( pool , modname ) ;
skinny_endpoint_interface = switch_loadable_module_create_interface ( * module_interface , SWITCH_ENDPOINT_INTERFACE ) ;
skinny_endpoint_interface - > interface_name = " skinny " ;
skinny_endpoint_interface - > io_routines = & skinny_io_routines ;
skinny_endpoint_interface - > state_handler = & skinny_state_handlers ;
2010-02-24 11:58:15 +00:00
SWITCH_ADD_API ( api_interface , " skinny " , " Skinny Controls " , skinny_function , " <cmd> <args> " ) ;
switch_console_set_complete ( " add skinny help " ) ;
2010-02-24 11:59:49 +00:00
switch_console_set_complete ( " add skinny status profile ::skinny::list_profiles " ) ;
switch_console_set_complete ( " add skinny status profile ::skinny::list_profiles device ::skinny::list_devices " ) ;
2010-02-24 11:58:15 +00:00
2010-02-24 11:59:49 +00:00
switch_console_add_complete_func ( " ::skinny::list_profiles " , skinny_list_profiles ) ;
2010-02-24 11:58:15 +00:00
switch_console_add_complete_func ( " ::skinny::list_devices " , skinny_list_devices ) ;
2010-02-24 11:57:37 +00:00
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS ;
}
SWITCH_MODULE_RUNTIME_FUNCTION ( mod_skinny_runtime )
{
2010-02-24 11:59:41 +00:00
switch_status_t status = SWITCH_STATUS_SUCCESS ;
switch_hash_index_t * hi ;
void * val ;
skinny_profile_t * profile ;
/* launch listeners */
for ( hi = switch_hash_first ( NULL , globals . profile_hash ) ; hi ; hi = switch_hash_next ( hi ) ) {
switch_hash_this ( hi , NULL , NULL , & val ) ;
profile = ( skinny_profile_t * ) val ;
status = skinny_socket_create_and_bind ( profile ) ;
if ( status ! = SWITCH_STATUS_SUCCESS ) {
return status ;
}
}
return status ;
2010-02-24 11:57:37 +00:00
}
SWITCH_MODULE_SHUTDOWN_FUNCTION ( mod_skinny_shutdown )
{
2010-02-24 11:59:41 +00:00
switch_hash_index_t * hi ;
void * val ;
skinny_profile_t * profile ;
2010-02-24 11:57:45 +00:00
int sanity = 0 ;
2010-02-24 11:58:54 +00:00
switch_event_free_subclass ( SKINNY_EVENT_REGISTER ) ;
2010-02-24 11:57:45 +00:00
switch_event_unbind ( & globals . heartbeat_node ) ;
2010-02-24 11:57:37 +00:00
2010-02-24 11:59:41 +00:00
globals . running = 0 ;
2010-02-24 11:57:37 +00:00
2010-02-24 12:00:11 +00:00
/* kill listeners */
2010-02-24 11:58:15 +00:00
walk_listeners ( kill_listener , NULL ) ;
2010-02-24 11:57:37 +00:00
2010-02-24 12:00:11 +00:00
/* close sockets */
2010-02-24 11:59:41 +00:00
for ( hi = switch_hash_first ( NULL , globals . profile_hash ) ; hi ; hi = switch_hash_next ( hi ) ) {
switch_hash_this ( hi , NULL , NULL , & val ) ;
profile = ( skinny_profile_t * ) val ;
2010-02-24 11:57:45 +00:00
2010-02-24 12:00:19 +00:00
close_socket ( & profile - > sock , profile ) ;
2010-02-24 11:59:41 +00:00
while ( profile - > listener_threads ) {
switch_yield ( 100000 ) ;
walk_listeners ( kill_listener , NULL ) ;
if ( + + sanity > = 200 ) {
break ;
}
2010-02-24 11:57:37 +00:00
}
}
2010-02-24 11:57:45 +00:00
2010-02-24 11:57:37 +00:00
switch_safe_free ( globals . codec_string ) ;
switch_safe_free ( globals . codec_rates_string ) ;
return SWITCH_STATUS_SUCCESS ;
}
/* For Emacs:
* Local Variables :
* mode : c
* indent - tabs - mode : t
* tab - width : 4
* c - basic - offset : 4
* End :
* For VIM :
* vim : set softtabstop = 4 shiftwidth = 4 tabstop = 4 :
*/