2003-03-31 07:13:36 +00:00
/*
2005-09-15 15:44:26 +00:00
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2005
2003-03-31 07:13:36 +00:00
*
* OpenH323 Channel Driver for ASTERISK PBX.
* By Jeremy McNamara
2006-09-19 17:07:22 +00:00
* For The NuFone Network
2003-03-31 07:13:36 +00:00
*
2004-09-30 19:36:46 +00:00
* chan_h323 has been derived from code created by
* Michael Manousos and Mark Spencer
2003-03-31 07:13:36 +00:00
*
2005-09-15 15:44:26 +00:00
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
2003-03-31 07:13:36 +00:00
*
2005-09-15 15:44:26 +00:00
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
2005-10-24 20:12:06 +00:00
/*! \file
2003-03-31 07:13:36 +00:00
*
2005-10-24 20:12:06 +00:00
* \brief This file is part of the chan_h323 driver for Asterisk
2003-03-31 07:13:36 +00:00
*
2005-12-30 21:18:06 +00:00
* \author Jeremy McNamara
*
2005-11-06 15:09:47 +00:00
* \par See also
* \arg Config_h323
2007-03-12 09:37:13 +00:00
* \extref OpenH323 http://www.voxgratia.org/
2005-11-06 15:09:47 +00:00
*
* \ingroup channel_drivers
2003-03-31 07:13:36 +00:00
*/
2006-04-24 17:11:45 +00:00
/*** MODULEINFO
2006-09-19 17:07:22 +00:00
<depend>openh323</depend>
2007-02-01 11:16:00 +00:00
<defaultenabled>yes</defaultenabled>
2006-04-24 17:11:45 +00:00
***/
2006-06-07 18:54:56 +00:00
#ifdef __cplusplus
extern "C" {
2006-09-19 17:07:22 +00:00
#endif
2006-06-07 18:54:56 +00:00
#include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , "$Revision$" )
#ifdef __cplusplus
}
#endif
2007-12-27 17:34:00 +00:00
#include <sys/types.h>
2004-06-26 03:50:14 +00:00
#include <sys/socket.h>
#include <sys/signal.h>
#include <sys/param.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netdb.h>
#include <fcntl.h>
2006-06-07 18:54:56 +00:00
2004-06-26 03:50:14 +00:00
#ifdef __cplusplus
extern "C" {
2006-09-19 17:07:22 +00:00
#endif
2005-06-06 21:09:59 +00:00
2005-04-21 06:02:45 +00:00
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
2006-09-19 17:07:22 +00:00
#include "asterisk/musiconhold.h"
2005-04-21 06:02:45 +00:00
#include "asterisk/pbx.h"
#include "asterisk/utils.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/rtp.h"
#include "asterisk/acl.h"
#include "asterisk/callerid.h"
#include "asterisk/cli.h"
#include "asterisk/dsp.h"
#include "asterisk/causes.h"
2006-04-03 18:36:30 +00:00
#include "asterisk/stringfields.h"
2006-06-01 16:47:28 +00:00
#include "asterisk/abstract_jb.h"
2006-09-19 17:07:22 +00:00
#include "asterisk/astobj.h"
2006-06-07 18:54:56 +00:00
2004-06-26 03:50:14 +00:00
#ifdef __cplusplus
}
2004-04-19 08:11:51 +00:00
#endif
2006-06-07 18:54:56 +00:00
2003-08-16 17:00:22 +00:00
#include "h323/chan_h323.h"
2003-03-31 07:13:36 +00:00
2006-09-19 17:07:22 +00:00
receive_digit_cb on_receive_digit ;
on_rtp_cb on_external_rtp_create ;
start_rtp_cb on_start_rtp_channel ;
2004-09-30 19:36:46 +00:00
setup_incoming_cb on_incoming_call ;
2006-09-19 17:07:22 +00:00
setup_outbound_cb on_outgoing_call ;
2004-09-30 19:36:46 +00:00
chan_ringing_cb on_chan_ringing ;
con_established_cb on_connection_established ;
clear_con_cb on_connection_cleared ;
answer_call_cb on_answer_call ;
2004-12-15 23:24:13 +00:00
progress_cb on_progress ;
rfc2833_cb on_set_rfc2833_payload ;
2005-04-04 15:54:34 +00:00
hangup_cb on_hangup ;
2005-05-19 19:13:19 +00:00
setcapabilities_cb on_setcapabilities ;
2006-09-19 17:07:22 +00:00
setpeercapabilities_cb on_setpeercapabilities ;
2006-09-28 10:41:38 +00:00
onhold_cb on_hold ;
2004-09-30 19:36:46 +00:00
2007-02-24 20:29:41 +00:00
int h323debug ; /*!< global debug flag */
2004-06-26 03:50:14 +00:00
2007-02-24 20:29:41 +00:00
/*! \brief Global jitterbuffer configuration - by default, jb is disabled */
2006-06-01 16:47:28 +00:00
static struct ast_jb_conf default_jbconf =
{
. flags = 0 ,
. max_size = - 1 ,
. resync_threshold = - 1 ,
. impl = ""
};
static struct ast_jb_conf global_jbconf ;
2004-09-30 19:36:46 +00:00
/** Variables required by Asterisk */
2006-09-19 17:07:22 +00:00
static const char tdesc [] = "The NuFone Network's Open H.323 Channel Driver" ;
2005-03-04 06:47:24 +00:00
static const char config [] = "h323.conf" ;
2005-07-10 23:49:57 +00:00
static char default_context [ AST_MAX_CONTEXT ] = "default" ;
2004-12-15 23:24:13 +00:00
static struct sockaddr_in bindaddr ;
2003-03-31 07:13:36 +00:00
2006-09-21 18:48:53 +00:00
#define GLOBAL_CAPABILITY (AST_FORMAT_G723_1 | AST_FORMAT_GSM | AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_G729A | AST_FORMAT_G726_AAL2 | AST_FORMAT_H261)
2006-04-03 18:36:30 +00:00
2003-03-31 07:13:36 +00:00
/** H.323 configuration values */
2004-10-04 10:13:01 +00:00
static int h323_signalling_port = 1720 ;
2003-03-31 07:13:36 +00:00
static char gatekeeper [ 100 ];
2004-09-30 19:36:46 +00:00
static int gatekeeper_disable = 1 ;
static int gatekeeper_discover = 0 ;
static int gkroute = 0 ;
/* Find user by alias (h.323 id) is default, alternative is the incomming call's source IP address*/
2004-10-28 06:06:58 +00:00
static int userbyalias = 1 ;
2006-09-19 17:07:22 +00:00
static int acceptAnonymous = 1 ;
2007-04-30 16:16:26 +00:00
static unsigned int tos = 0 ;
static unsigned int cos = 0 ;
2003-03-31 07:13:36 +00:00
static char secret [ 50 ];
2005-05-11 13:27:49 +00:00
static unsigned int unique = 0 ;
2003-03-31 07:13:36 +00:00
2004-12-15 23:24:13 +00:00
static call_options_t global_options ;
2007-02-24 20:29:41 +00:00
/*! \brief Private structure of a OpenH323 channel */
2003-03-31 07:13:36 +00:00
struct oh323_pvt {
2007-02-24 20:29:41 +00:00
ast_mutex_t lock ; /*!< Channel private lock */
call_options_t options ; /*!<!< Options to be used during call setup */
int alreadygone ; /*!< Whether or not we've already been destroyed by our peer */
int needdestroy ; /*!< if we need to be destroyed */
call_details_t cd ; /*!< Call details */
struct ast_channel * owner ; /*!< Who owns us */
struct sockaddr_in sa ; /*!< Our peer */
struct sockaddr_in redirip ; /*!< Where our RTP should be going if not to us */
int nonCodecCapability ; /*!< non-audio capability */
int outgoing ; /*!< Outgoing or incoming call? */
char exten [ AST_MAX_EXTENSION ]; /*!< Requested extension */
char context [ AST_MAX_CONTEXT ]; /*!< Context where to start */
char accountcode [ 256 ]; /*!< Account code */
char rdnis [ 80 ]; /*!< Referring DNIS, if available */
int amaflags ; /*!< AMA Flags */
struct ast_rtp * rtp ; /*!< RTP Session */
struct ast_dsp * vad ; /*!< Used for in-band DTMF detection */
int nativeformats ; /*!< Codec formats supported by a channel */
int needhangup ; /*!< Send hangup when Asterisk is ready */
int hangupcause ; /*!< Hangup cause from OpenH323 layer */
int newstate ; /*!< Pending state change */
int newcontrol ; /*!< Pending control to send */
int newdigit ; /*!< Pending DTMF digit to send */
int newduration ; /*!< Pending DTMF digit duration to send */
int pref_codec ; /*!< Preferred codec */
int peercapability ; /*!< Capabilities learned from peer */
int jointcapability ; /*!< Common capabilities for local and remote side */
struct ast_codec_pref peer_prefs ; /*!< Preferenced list of codecs which remote side supports */
int dtmf_pt [ 2 ]; /*!< Payload code used for RFC2833/CISCO messages */
int curDTMF ; /*!< DTMF tone being generated to Asterisk side */
int DTMFsched ; /*!< Scheduler descriptor for DTMF */
int update_rtp_info ; /*!< Configuration of fd's array is pending */
int recvonly ; /*!< Peer isn't wish to receive our voice stream */
int txDtmfDigit ; /*!< DTMF digit being to send to H.323 side */
int noInbandDtmf ; /*!< Inband DTMF processing by DSP isn't available */
int connection_established ; /*!< Call got CONNECT message */
int got_progress ; /*!< Call got PROGRESS message, pass inband audio */
struct oh323_pvt * next ; /*!< Next channel in list */
2003-03-31 07:13:36 +00:00
} * iflist = NULL ;
2007-02-24 20:29:41 +00:00
/*! \brief H323 User list */
static struct h323_user_list {
2006-09-19 17:07:22 +00:00
ASTOBJ_CONTAINER_COMPONENTS ( struct oh323_user );
2004-06-12 03:44:51 +00:00
} userl ;
2003-03-31 07:13:36 +00:00
2007-02-24 20:29:41 +00:00
/*! \brief H323 peer list */
static struct h323_peer_list {
2006-09-19 17:07:22 +00:00
ASTOBJ_CONTAINER_COMPONENTS ( struct oh323_peer );
2004-06-12 03:44:51 +00:00
} peerl ;
2003-03-31 07:13:36 +00:00
2007-02-24 20:29:41 +00:00
/*! \brief H323 alias list */
static struct h323_alias_list {
2006-09-19 17:07:22 +00:00
ASTOBJ_CONTAINER_COMPONENTS ( struct oh323_alias );
2004-06-12 03:44:51 +00:00
} aliasl ;
2003-03-31 07:13:36 +00:00
2007-02-24 20:29:41 +00:00
/* Asterisk RTP stuff */
2003-03-31 07:13:36 +00:00
static struct sched_context * sched ;
static struct io_context * io ;
2007-02-24 20:29:41 +00:00
AST_MUTEX_DEFINE_STATIC ( iflock ); /*!< Protect the interface list (oh323_pvt) */
2003-03-31 07:13:36 +00:00
2007-02-24 20:29:41 +00:00
/*! \brief Protect the H.323 monitoring thread, so only one process can kill or start it, and not
2003-03-31 07:13:36 +00:00
when it's doing something critical. */
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( monlock );
2003-03-31 07:13:36 +00:00
2007-02-24 20:29:41 +00:00
/*! \brief Protect the H.323 capabilities list, to avoid more than one channel to set the capabilities simultaneaously in the h323 stack. */
2004-07-30 20:01:58 +00:00
AST_MUTEX_DEFINE_STATIC ( caplock );
2007-02-24 20:29:41 +00:00
/*! \brief Protect the reload process */
2004-10-15 07:07:50 +00:00
AST_MUTEX_DEFINE_STATIC ( h323_reload_lock );
static int h323_reloading = 0 ;
2007-02-24 20:29:41 +00:00
/*! \brief This is the thread for the monitor which checks for input on the channels
2006-09-19 17:07:22 +00:00
which are not currently in use. */
2004-03-15 07:51:22 +00:00
static pthread_t monitor_thread = AST_PTHREADT_NULL ;
2003-03-31 07:13:36 +00:00
static int restart_monitor ( void );
2004-10-15 07:07:50 +00:00
static int h323_do_reload ( void );
2003-03-31 07:13:36 +00:00
2007-08-20 00:37:12 +00:00
static void delete_users ( void );
static void delete_aliases ( void );
static void prune_peers ( void );
2005-03-04 06:47:24 +00:00
static struct ast_channel * oh323_request ( const char * type , int format , void * data , int * cause );
2006-08-31 01:59:02 +00:00
static int oh323_digit_begin ( struct ast_channel * c , char digit );
2007-01-19 18:06:03 +00:00
static int oh323_digit_end ( struct ast_channel * c , char digit , unsigned int duration );
2005-03-04 06:47:24 +00:00
static int oh323_call ( struct ast_channel * c , char * dest , int timeout );
static int oh323_hangup ( struct ast_channel * c );
static int oh323_answer ( struct ast_channel * c );
static struct ast_frame * oh323_read ( struct ast_channel * c );
static int oh323_write ( struct ast_channel * c , struct ast_frame * frame );
2006-05-10 15:00:33 +00:00
static int oh323_indicate ( struct ast_channel * c , int condition , const void * data , size_t datalen );
2005-03-04 06:47:24 +00:00
static int oh323_fixup ( struct ast_channel * oldchan , struct ast_channel * newchan );
static const struct ast_channel_tech oh323_tech = {
2006-04-03 18:36:30 +00:00
. type = "H323" ,
2005-03-04 06:47:24 +00:00
. description = tdesc ,
2007-11-06 22:51:48 +00:00
. capabilities = AST_FORMAT_AUDIO_MASK ,
2006-05-31 17:21:21 +00:00
. properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER ,
2005-03-04 06:47:24 +00:00
. requester = oh323_request ,
2006-08-31 01:59:02 +00:00
. send_digit_begin = oh323_digit_begin ,
. send_digit_end = oh323_digit_end ,
2005-03-04 06:47:24 +00:00
. call = oh323_call ,
. hangup = oh323_hangup ,
. answer = oh323_answer ,
. read = oh323_read ,
. write = oh323_write ,
. indicate = oh323_indicate ,
. fixup = oh323_fixup ,
. bridge = ast_rtp_bridge ,
};
2006-09-19 17:07:22 +00:00
static const char * redirectingreason2str ( int redirectingreason )
{
switch ( redirectingreason ) {
case 0 :
return "UNKNOWN" ;
case 1 :
return "BUSY" ;
case 2 :
return "NO_REPLY" ;
case 0xF :
return "UNCONDITIONAL" ;
default :
return "NOREDIRECT" ;
}
}
static void oh323_destroy_alias ( struct oh323_alias * alias )
{
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Destroying alias '%s' \n " , alias -> name );
2007-06-03 06:10:27 +00:00
ast_free ( alias );
2006-09-19 17:07:22 +00:00
}
static void oh323_destroy_user ( struct oh323_user * user )
{
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Destroying user '%s' \n " , user -> name );
2006-09-19 17:07:22 +00:00
ast_free_ha ( user -> ha );
2007-06-03 06:10:27 +00:00
ast_free ( user );
2006-09-19 17:07:22 +00:00
}
static void oh323_destroy_peer ( struct oh323_peer * peer )
{
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Destroying peer '%s' \n " , peer -> name );
2006-09-19 17:07:22 +00:00
ast_free_ha ( peer -> ha );
2007-06-03 06:10:27 +00:00
ast_free ( peer );
2006-09-19 17:07:22 +00:00
}
2007-09-21 14:40:10 +00:00
static int oh323_simulate_dtmf_end ( const void * data )
2006-09-19 17:07:22 +00:00
{
2007-09-21 14:40:10 +00:00
struct oh323_pvt * pvt = ( struct oh323_pvt * ) data ;
2006-09-19 17:07:22 +00:00
if ( pvt ) {
ast_mutex_lock ( & pvt -> lock );
/* Don't hold pvt lock while trying to lock the channel */
while ( pvt -> owner && ast_channel_trylock ( pvt -> owner )) {
2008-06-25 02:34:11 +00:00
DEADLOCK_AVOIDANCE ( & pvt -> lock );
2006-09-19 17:07:22 +00:00
}
if ( pvt -> owner ) {
struct ast_frame f = {
. frametype = AST_FRAME_DTMF_END ,
. subclass = pvt -> curDTMF ,
. samples = 0 ,
. src = "SIMULATE_DTMF_END" ,
};
ast_queue_frame ( pvt -> owner , & f );
ast_channel_unlock ( pvt -> owner );
}
pvt -> DTMFsched = - 1 ;
ast_mutex_unlock ( & pvt -> lock );
}
return 0 ;
}
2007-02-24 20:29:41 +00:00
/*! \brief Channel and private structures should be already locked */
2005-05-11 13:27:49 +00:00
static void __oh323_update_info ( struct ast_channel * c , struct oh323_pvt * pvt )
2005-04-04 15:54:34 +00:00
{
if ( c -> nativeformats != pvt -> nativeformats ) {
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Preparing %s for new native format \n " , c -> name );
2005-04-04 15:54:34 +00:00
c -> nativeformats = pvt -> nativeformats ;
ast_set_read_format ( c , c -> readformat );
ast_set_write_format ( c , c -> writeformat );
}
if ( pvt -> needhangup ) {
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Process pending hangup for %s \n " , c -> name );
2005-04-04 15:54:34 +00:00
c -> _softhangup |= AST_SOFTHANGUP_DEV ;
c -> hangupcause = pvt -> hangupcause ;
2008-05-22 16:29:54 +00:00
ast_queue_hangup_with_cause ( c , pvt -> hangupcause );
2005-04-04 15:54:34 +00:00
pvt -> needhangup = 0 ;
2006-09-19 17:07:22 +00:00
pvt -> newstate = pvt -> newcontrol = pvt -> newdigit = pvt -> DTMFsched = - 1 ;
2005-07-27 04:45:11 +00:00
}
if ( pvt -> newstate >= 0 ) {
ast_setstate ( c , pvt -> newstate );
pvt -> newstate = - 1 ;
}
if ( pvt -> newcontrol >= 0 ) {
ast_queue_control ( c , pvt -> newcontrol );
pvt -> newcontrol = - 1 ;
2005-04-04 15:54:34 +00:00
}
2006-08-15 14:55:30 +00:00
if ( pvt -> newdigit >= 0 ) {
2006-08-15 17:14:20 +00:00
struct ast_frame f = {
2006-09-19 17:07:22 +00:00
. frametype = AST_FRAME_DTMF_END ,
2006-08-15 17:14:20 +00:00
. subclass = pvt -> newdigit ,
2006-09-19 17:07:22 +00:00
. samples = pvt -> newduration * 8 ,
2007-02-10 09:23:09 +00:00
. len = pvt -> newduration ,
2006-08-15 17:14:20 +00:00
. src = "UPDATE_INFO" ,
};
2006-09-19 17:07:22 +00:00
if ( pvt -> newdigit == ' ' ) { /* signalUpdate message */
f . subclass = pvt -> curDTMF ;
if ( pvt -> DTMFsched >= 0 ) {
2008-01-27 22:35:29 +00:00
AST_SCHED_DEL ( sched , pvt -> DTMFsched );
2006-09-19 17:07:22 +00:00
}
} else { /* Regular input or signal message */
if ( pvt -> newduration ) { /* This is a signal, signalUpdate follows */
f . frametype = AST_FRAME_DTMF_BEGIN ;
2008-01-27 22:35:29 +00:00
AST_SCHED_DEL ( sched , pvt -> DTMFsched );
2006-09-19 17:07:22 +00:00
pvt -> DTMFsched = ast_sched_add ( sched , pvt -> newduration , oh323_simulate_dtmf_end , pvt );
if ( h323debug )
ast_log ( LOG_DTMF , "Scheduled DTMF END simulation for %d ms, id=%d \n " , pvt -> newduration , pvt -> DTMFsched );
}
pvt -> curDTMF = pvt -> newdigit ;
}
2006-08-15 14:55:30 +00:00
ast_queue_frame ( c , & f );
pvt -> newdigit = - 1 ;
}
2006-09-19 17:07:22 +00:00
if ( pvt -> update_rtp_info > 0 ) {
if ( pvt -> rtp ) {
ast_jb_configure ( c , & global_jbconf );
2007-08-08 21:44:58 +00:00
ast_channel_set_fd ( c , 0 , ast_rtp_fd ( pvt -> rtp ));
ast_channel_set_fd ( c , 1 , ast_rtcp_fd ( pvt -> rtp ));
2006-09-19 17:07:22 +00:00
ast_queue_frame ( pvt -> owner , & ast_null_frame ); /* Tell Asterisk to apply changes */
}
pvt -> update_rtp_info = - 1 ;
}
2005-05-11 13:27:49 +00:00
}
2007-02-24 20:29:41 +00:00
/*! \brief Only channel structure should be locked */
2005-05-11 13:27:49 +00:00
static void oh323_update_info ( struct ast_channel * c )
{
struct oh323_pvt * pvt = c -> tech_pvt ;
if ( pvt ) {
ast_mutex_lock ( & pvt -> lock );
__oh323_update_info ( c , pvt );
ast_mutex_unlock ( & pvt -> lock );
}
2005-04-04 15:54:34 +00:00
}
2006-09-19 17:07:22 +00:00
static void cleanup_call_details ( call_details_t * cd )
{
if ( cd -> call_token ) {
2007-06-03 06:10:27 +00:00
ast_free ( cd -> call_token );
2006-09-19 17:07:22 +00:00
cd -> call_token = NULL ;
}
if ( cd -> call_source_aliases ) {
2007-06-03 06:10:27 +00:00
ast_free ( cd -> call_source_aliases );
2006-09-19 17:07:22 +00:00
cd -> call_source_aliases = NULL ;
}
if ( cd -> call_dest_alias ) {
2007-06-03 06:10:27 +00:00
ast_free ( cd -> call_dest_alias );
2006-09-19 17:07:22 +00:00
cd -> call_dest_alias = NULL ;
}
if ( cd -> call_source_name ) {
2007-06-03 06:10:27 +00:00
ast_free ( cd -> call_source_name );
2006-09-19 17:07:22 +00:00
cd -> call_source_name = NULL ;
}
if ( cd -> call_source_e164 ) {
2007-06-03 06:10:27 +00:00
ast_free ( cd -> call_source_e164 );
2006-09-19 17:07:22 +00:00
cd -> call_source_e164 = NULL ;
}
if ( cd -> call_dest_e164 ) {
2007-06-03 06:10:27 +00:00
ast_free ( cd -> call_dest_e164 );
2006-09-19 17:07:22 +00:00
cd -> call_dest_e164 = NULL ;
}
if ( cd -> sourceIp ) {
2007-06-03 06:10:27 +00:00
ast_free ( cd -> sourceIp );
2006-09-19 17:07:22 +00:00
cd -> sourceIp = NULL ;
}
if ( cd -> redirect_number ) {
2007-06-03 06:10:27 +00:00
ast_free ( cd -> redirect_number );
2006-09-19 17:07:22 +00:00
cd -> redirect_number = NULL ;
}
2005-04-04 15:54:34 +00:00
}
2005-05-11 13:27:49 +00:00
static void __oh323_destroy ( struct oh323_pvt * pvt )
2003-03-31 07:13:36 +00:00
{
struct oh323_pvt * cur , * prev = NULL ;
2006-09-19 17:07:22 +00:00
2008-01-27 22:35:29 +00:00
AST_SCHED_DEL ( sched , pvt -> DTMFsched );
2006-09-19 17:07:22 +00:00
2005-05-11 13:27:49 +00:00
if ( pvt -> rtp ) {
ast_rtp_destroy ( pvt -> rtp );
2003-03-31 07:13:36 +00:00
}
2006-09-19 17:07:22 +00:00
2005-04-04 15:54:34 +00:00
/* Free dsp used for in-band DTMF detection */
2005-05-11 13:27:49 +00:00
if ( pvt -> vad ) {
ast_dsp_free ( pvt -> vad );
2005-04-04 15:54:34 +00:00
}
2005-05-11 13:27:49 +00:00
cleanup_call_details ( & pvt -> cd );
2005-04-04 15:54:34 +00:00
2003-03-31 07:13:36 +00:00
/* Unlink us from the owner if we have one */
2005-05-11 13:27:49 +00:00
if ( pvt -> owner ) {
2006-09-19 17:07:22 +00:00
ast_channel_lock ( pvt -> owner );
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Detaching from %s \n " , pvt -> owner -> name );
2005-05-11 13:27:49 +00:00
pvt -> owner -> tech_pvt = NULL ;
2006-09-19 17:07:22 +00:00
ast_channel_unlock ( pvt -> owner );
2003-03-31 07:13:36 +00:00
}
cur = iflist ;
while ( cur ) {
2005-05-11 13:27:49 +00:00
if ( cur == pvt ) {
2003-03-31 07:13:36 +00:00
if ( prev )
prev -> next = cur -> next ;
else
iflist = cur -> next ;
break ;
}
prev = cur ;
cur = cur -> next ;
}
if ( ! cur ) {
ast_log ( LOG_WARNING , "%p is not in list?!?! \n " , cur );
2004-06-22 17:42:14 +00:00
} else {
2006-09-19 17:07:22 +00:00
ast_mutex_unlock ( & pvt -> lock );
2005-05-11 13:27:49 +00:00
ast_mutex_destroy ( & pvt -> lock );
2007-06-03 06:10:27 +00:00
ast_free ( pvt );
2005-05-11 13:27:49 +00:00
}
2003-03-31 07:13:36 +00:00
}
2005-05-11 13:27:49 +00:00
static void oh323_destroy ( struct oh323_pvt * pvt )
2003-03-31 07:13:36 +00:00
{
2006-09-19 17:07:22 +00:00
if ( h323debug ) {
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Destroying channel %s \n " , ( pvt -> owner ? pvt -> owner -> name : "<unknown>" ));
2006-09-19 17:07:22 +00:00
}
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & iflock );
2006-09-19 17:07:22 +00:00
ast_mutex_lock ( & pvt -> lock );
2005-05-11 13:27:49 +00:00
__oh323_destroy ( pvt );
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & iflock );
2003-03-31 07:13:36 +00:00
}
2006-09-19 17:07:22 +00:00
static int oh323_digit_begin ( struct ast_channel * c , char digit )
2006-08-31 01:59:02 +00:00
{
2006-09-19 17:07:22 +00:00
struct oh323_pvt * pvt = ( struct oh323_pvt * ) c -> tech_pvt ;
char * token ;
if ( ! pvt ) {
ast_log ( LOG_ERROR , "No private structure?! This is bad \n " );
return - 1 ;
}
ast_mutex_lock ( & pvt -> lock );
2006-09-25 09:03:14 +00:00
if ( pvt -> rtp &&
((( pvt -> options . dtmfmode & H323_DTMF_RFC2833 ) && pvt -> dtmf_pt [ 0 ])
/*|| ((pvt->options.dtmfmode & H323_DTMF_CISCO) && pvt->dtmf_pt[1]))*/ )) {
2006-09-19 17:07:22 +00:00
/* out-of-band DTMF */
if ( h323debug ) {
ast_log ( LOG_DTMF , "Begin sending out-of-band digit %c on %s \n " , digit , c -> name );
}
ast_rtp_senddigit_begin ( pvt -> rtp , digit );
ast_mutex_unlock ( & pvt -> lock );
} else if ( pvt -> txDtmfDigit != digit ) {
/* in-band DTMF */
if ( h323debug ) {
ast_log ( LOG_DTMF , "Begin sending inband digit %c on %s \n " , digit , c -> name );
}
pvt -> txDtmfDigit = digit ;
2007-06-14 23:01:01 +00:00
token = pvt -> cd . call_token ? ast_strdup ( pvt -> cd . call_token ) : NULL ;
2006-09-19 17:07:22 +00:00
ast_mutex_unlock ( & pvt -> lock );
h323_send_tone ( token , digit );
if ( token ) {
2007-06-03 06:10:27 +00:00
ast_free ( token );
2006-09-19 17:07:22 +00:00
}
} else
ast_mutex_unlock ( & pvt -> lock );
oh323_update_info ( c );
2006-08-31 01:59:02 +00:00
return 0 ;
}
2007-02-24 20:29:41 +00:00
/*! \brief
2003-03-31 07:13:36 +00:00
* Send (play) the specified digit to the channel.
2006-09-19 17:07:22 +00:00
*
2003-03-31 07:13:36 +00:00
*/
2007-01-19 18:06:03 +00:00
static int oh323_digit_end ( struct ast_channel * c , char digit , unsigned int duration )
2003-03-31 07:13:36 +00:00
{
2005-05-11 13:27:49 +00:00
struct oh323_pvt * pvt = ( struct oh323_pvt * ) c -> tech_pvt ;
2005-04-29 04:22:47 +00:00
char * token ;
2005-09-15 03:26:02 +00:00
if ( ! pvt ) {
2005-09-15 17:08:52 +00:00
ast_log ( LOG_ERROR , "No private structure?! This is bad \n " );
2005-04-04 15:54:34 +00:00
return - 1 ;
2005-09-15 03:26:02 +00:00
}
2005-05-11 13:27:49 +00:00
ast_mutex_lock ( & pvt -> lock );
2006-09-25 09:03:14 +00:00
if ( pvt -> rtp && ( pvt -> options . dtmfmode & H323_DTMF_RFC2833 ) && (( pvt -> dtmf_pt [ 0 ] > 0 ) || ( pvt -> dtmf_pt [ 0 ] > 0 ))) {
2005-09-15 03:26:02 +00:00
/* out-of-band DTMF */
if ( h323debug ) {
2007-02-10 09:23:09 +00:00
ast_log ( LOG_DTMF , "End sending out-of-band digit %c on %s, duration %d \n " , digit , c -> name , duration );
2005-09-15 03:26:02 +00:00
}
2006-09-19 17:07:22 +00:00
ast_rtp_senddigit_end ( pvt -> rtp , digit );
2006-08-15 14:55:30 +00:00
ast_mutex_unlock ( & pvt -> lock );
2005-09-15 03:26:02 +00:00
} else {
/* in-band DTMF */
if ( h323debug ) {
2007-02-10 09:23:09 +00:00
ast_log ( LOG_DTMF , "End sending inband digit %c on %s, duration %d \n " , digit , c -> name , duration );
2005-09-15 03:26:02 +00:00
}
2006-09-19 17:07:22 +00:00
pvt -> txDtmfDigit = ' ' ;
2007-06-14 23:01:01 +00:00
token = pvt -> cd . call_token ? ast_strdup ( pvt -> cd . call_token ) : NULL ;
2006-08-15 14:55:30 +00:00
ast_mutex_unlock ( & pvt -> lock );
2006-09-19 17:07:22 +00:00
h323_send_tone ( token , ' ' );
2005-09-15 03:26:02 +00:00
if ( token ) {
2007-06-03 06:10:27 +00:00
ast_free ( token );
2005-09-15 03:26:02 +00:00
}
2003-03-31 07:13:36 +00:00
}
2005-09-15 03:14:21 +00:00
oh323_update_info ( c );
2003-03-31 07:13:36 +00:00
return 0 ;
}
2007-02-24 20:29:41 +00:00
/*! \brief
2006-09-19 17:07:22 +00:00
* Make a call over the specified channel to the specified
2004-10-04 10:13:01 +00:00
* destination.
* Returns -1 on error, 0 on success.
2003-03-31 07:13:36 +00:00
*/
static int oh323_call ( struct ast_channel * c , char * dest , int timeout )
2006-09-19 17:07:22 +00:00
{
2005-05-11 13:27:49 +00:00
int res = 0 ;
struct oh323_pvt * pvt = ( struct oh323_pvt * ) c -> tech_pvt ;
2006-09-19 17:07:22 +00:00
const char * addr ;
2005-05-11 13:27:49 +00:00
char called_addr [ 1024 ];
if ( h323debug ) {
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Calling to %s on %s \n " , dest , c -> name );
2005-05-11 13:27:49 +00:00
}
2005-04-04 15:54:34 +00:00
if (( c -> _state != AST_STATE_DOWN ) && ( c -> _state != AST_STATE_RESERVED )) {
2005-05-11 13:27:49 +00:00
ast_log ( LOG_WARNING , "Line is already in use (%s) \n " , c -> name );
return - 1 ;
}
ast_mutex_lock ( & pvt -> lock );
2006-09-19 17:07:22 +00:00
if ( ! gatekeeper_disable ) {
2005-05-11 13:27:49 +00:00
if ( ast_strlen_zero ( pvt -> exten )) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( called_addr , dest , sizeof ( called_addr ));
2005-05-11 13:27:49 +00:00
} else {
snprintf ( called_addr , sizeof ( called_addr ), "%s@%s" , pvt -> exten , dest );
}
} else {
res = htons ( pvt -> sa . sin_port );
2006-09-19 17:07:22 +00:00
addr = ast_inet_ntoa ( pvt -> sa . sin_addr );
2005-05-11 13:27:49 +00:00
if ( ast_strlen_zero ( pvt -> exten )) {
snprintf ( called_addr , sizeof ( called_addr ), "%s:%d" , addr , res );
} else {
snprintf ( called_addr , sizeof ( called_addr ), "%s@%s:%d" , pvt -> exten , addr , res );
2005-04-04 15:54:34 +00:00
}
2004-12-16 02:03:19 +00:00
}
2005-04-04 15:54:34 +00:00
/* make sure null terminated */
2006-09-19 17:07:22 +00:00
called_addr [ sizeof ( called_addr ) - 1 ] = '\0' ;
2004-12-16 02:03:19 +00:00
2006-09-19 17:07:22 +00:00
if ( c -> cid . cid_num )
2006-10-25 14:44:50 +00:00
ast_copy_string ( pvt -> options . cid_num , c -> cid . cid_num , sizeof ( pvt -> options . cid_num ));
2006-09-19 17:07:22 +00:00
if ( c -> cid . cid_name )
2006-10-25 14:44:50 +00:00
ast_copy_string ( pvt -> options . cid_name , c -> cid . cid_name , sizeof ( pvt -> options . cid_name ));
2006-09-19 17:07:22 +00:00
if ( c -> cid . cid_rdnis ) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( pvt -> options . cid_rdnis , c -> cid . cid_rdnis , sizeof ( pvt -> options . cid_rdnis ));
2004-12-16 02:03:19 +00:00
}
2006-09-29 18:35:44 +00:00
pvt -> options . presentation = c -> cid . cid_pres ;
pvt -> options . type_of_number = c -> cid . cid_ton ;
2006-09-19 17:07:22 +00:00
if (( addr = pbx_builtin_getvar_helper ( c , "PRIREDIRECTREASON" ))) {
if ( ! strcasecmp ( addr , "UNKNOWN" ))
pvt -> options . redirect_reason = 0 ;
else if ( ! strcasecmp ( addr , "BUSY" ))
pvt -> options . redirect_reason = 1 ;
else if ( ! strcasecmp ( addr , "NO_REPLY" ))
pvt -> options . redirect_reason = 2 ;
else if ( ! strcasecmp ( addr , "UNCONDITIONAL" ))
pvt -> options . redirect_reason = 15 ;
else
pvt -> options . redirect_reason = - 1 ;
} else
pvt -> options . redirect_reason = - 1 ;
2006-10-07 14:48:32 +00:00
pvt -> options . transfer_capability = c -> transfercapability ;
2004-11-11 21:30:30 +00:00
/* indicate that this is an outgoing call */
2004-10-04 10:13:01 +00:00
pvt -> outgoing = 1 ;
2004-11-11 21:30:30 +00:00
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , "Requested transfer capability: 0x%.2x - %s \n " , c -> transfercapability , ast_transfercapability2str ( c -> transfercapability ));
2006-09-19 17:07:22 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Placing outgoing call to %s, %d/%d \n " , called_addr , pvt -> options . dtmfcodec [ 0 ], pvt -> options . dtmfcodec [ 1 ]);
2005-05-11 13:27:49 +00:00
ast_mutex_unlock ( & pvt -> lock );
2004-12-15 23:24:13 +00:00
res = h323_make_call ( called_addr , & ( pvt -> cd ), & pvt -> options );
2003-03-31 07:13:36 +00:00
if ( res ) {
2003-05-12 00:55:52 +00:00
ast_log ( LOG_NOTICE , "h323_make_call failed(%s) \n " , c -> name );
2003-03-31 07:13:36 +00:00
return - 1 ;
}
2005-04-04 15:54:34 +00:00
oh323_update_info ( c );
2003-03-31 07:13:36 +00:00
return 0 ;
}
static int oh323_answer ( struct ast_channel * c )
{
int res ;
2005-03-04 06:47:24 +00:00
struct oh323_pvt * pvt = ( struct oh323_pvt * ) c -> tech_pvt ;
2005-04-04 15:54:34 +00:00
char * token ;
2003-03-31 07:13:36 +00:00
2005-04-04 15:54:34 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Answering on %s \n " , c -> name );
2005-04-04 15:54:34 +00:00
ast_mutex_lock ( & pvt -> lock );
2007-06-14 23:01:01 +00:00
token = pvt -> cd . call_token ? ast_strdup ( pvt -> cd . call_token ) : NULL ;
2005-04-04 15:54:34 +00:00
ast_mutex_unlock ( & pvt -> lock );
res = h323_answering_call ( token , 0 );
if ( token )
2007-06-03 06:10:27 +00:00
ast_free ( token );
2005-04-04 15:54:34 +00:00
oh323_update_info ( c );
2004-10-28 06:06:58 +00:00
if ( c -> _state != AST_STATE_UP ) {
2003-03-31 07:13:36 +00:00
ast_setstate ( c , AST_STATE_UP );
2004-10-28 06:06:58 +00:00
}
2003-03-31 07:13:36 +00:00
return res ;
}
static int oh323_hangup ( struct ast_channel * c )
{
2005-03-04 06:47:24 +00:00
struct oh323_pvt * pvt = ( struct oh323_pvt * ) c -> tech_pvt ;
2004-12-16 04:25:49 +00:00
int q931cause = AST_CAUSE_NORMAL_CLEARING ;
2005-04-04 15:54:34 +00:00
char * call_token ;
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Hanging up and scheduling destroy of call %s \n " , c -> name );
2004-12-16 04:25:49 +00:00
2005-03-04 06:47:24 +00:00
if ( ! c -> tech_pvt ) {
2006-09-19 17:07:22 +00:00
ast_log ( LOG_WARNING , "Asked to hangup channel not connected \n " );
2003-03-31 07:13:36 +00:00
return 0 ;
}
2004-10-04 10:13:01 +00:00
ast_mutex_lock ( & pvt -> lock );
2003-03-31 07:13:36 +00:00
/* Determine how to disconnect */
2004-10-04 10:13:01 +00:00
if ( pvt -> owner != c ) {
2003-03-31 07:13:36 +00:00
ast_log ( LOG_WARNING , "Huh? We aren't the owner? \n " );
2004-10-04 10:13:01 +00:00
ast_mutex_unlock ( & pvt -> lock );
2003-03-31 07:13:36 +00:00
return 0 ;
}
2006-09-19 17:07:22 +00:00
2004-10-04 10:13:01 +00:00
pvt -> owner = NULL ;
2005-03-04 06:47:24 +00:00
c -> tech_pvt = NULL ;
2003-03-31 07:13:36 +00:00
2004-12-16 04:25:49 +00:00
if ( c -> hangupcause ) {
q931cause = c -> hangupcause ;
} else {
2006-04-03 18:36:30 +00:00
const char * cause = pbx_builtin_getvar_helper ( c , "DIALSTATUS" );
2004-12-16 04:25:49 +00:00
if ( cause ) {
if ( ! strcmp ( cause , "CONGESTION" )) {
q931cause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION ;
} else if ( ! strcmp ( cause , "BUSY" )) {
q931cause = AST_CAUSE_USER_BUSY ;
} else if ( ! strcmp ( cause , "CHANISUNVAIL" )) {
q931cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL ;
} else if ( ! strcmp ( cause , "NOANSWER" )) {
q931cause = AST_CAUSE_NO_ANSWER ;
} else if ( ! strcmp ( cause , "CANCEL" )) {
q931cause = AST_CAUSE_CALL_REJECTED ;
}
}
}
2003-03-31 07:13:36 +00:00
/* Start the process if it's not already started */
2005-04-04 15:54:34 +00:00
if ( ! pvt -> alreadygone && ! pvt -> hangupcause ) {
2007-06-14 23:01:01 +00:00
call_token = pvt -> cd . call_token ? ast_strdup ( pvt -> cd . call_token ) : NULL ;
2005-04-04 15:54:34 +00:00
if ( call_token ) {
/* Release lock to eliminate deadlock */
ast_mutex_unlock ( & pvt -> lock );
2006-09-19 17:07:22 +00:00
if ( h323_clear_call ( call_token , q931cause )) {
ast_log ( LOG_WARNING , "ClearCall failed. \n " );
2005-04-04 15:54:34 +00:00
}
2007-06-03 06:10:27 +00:00
ast_free ( call_token );
2005-04-04 15:54:34 +00:00
ast_mutex_lock ( & pvt -> lock );
2004-01-06 16:51:34 +00:00
}
2006-09-19 17:07:22 +00:00
}
2005-04-04 15:54:34 +00:00
pvt -> needdestroy = 1 ;
2006-09-19 17:07:22 +00:00
ast_mutex_unlock ( & pvt -> lock );
2003-03-31 07:13:36 +00:00
2003-04-23 21:52:46 +00:00
/* Update usage counter */
2006-09-19 17:07:22 +00:00
ast_module_unref ( ast_module_info -> self );
2003-03-31 07:13:36 +00:00
return 0 ;
}
2007-02-24 20:29:41 +00:00
/*! \brief Retrieve audio/etc from channel. Assumes pvt->lock is already held. */
2004-10-04 10:13:01 +00:00
static struct ast_frame * oh323_rtp_read ( struct oh323_pvt * pvt )
2003-03-31 07:13:36 +00:00
{
struct ast_frame * f ;
2003-09-22 06:21:03 +00:00
2005-05-21 17:09:30 +00:00
/* Only apply it for the first packet, we just need the correct ip/port */
if ( pvt -> options . nat ) {
ast_rtp_setnat ( pvt -> rtp , pvt -> options . nat );
pvt -> options . nat = 0 ;
}
2003-09-22 06:21:03 +00:00
2004-10-04 10:13:01 +00:00
f = ast_rtp_read ( pvt -> rtp );
2003-03-31 07:13:36 +00:00
/* Don't send RFC2833 if we're not supposed to */
2006-09-25 09:03:14 +00:00
if ( f && ( f -> frametype == AST_FRAME_DTMF ) && ! ( pvt -> options . dtmfmode & ( H323_DTMF_RFC2833 | H323_DTMF_CISCO ))) {
2006-01-31 17:18:58 +00:00
return & ast_null_frame ;
2004-10-28 06:06:58 +00:00
}
2004-10-04 10:13:01 +00:00
if ( pvt -> owner ) {
2003-03-31 07:13:36 +00:00
/* We already hold the channel lock */
if ( f -> frametype == AST_FRAME_VOICE ) {
2004-10-04 10:13:01 +00:00
if ( f -> subclass != pvt -> owner -> nativeformats ) {
2005-04-04 15:54:34 +00:00
/* Try to avoid deadlock */
2006-09-19 17:07:22 +00:00
if ( ast_channel_trylock ( pvt -> owner )) {
2005-04-04 15:54:34 +00:00
ast_log ( LOG_NOTICE , "Format changed but channel is locked. Ignoring frame... \n " );
2006-01-31 17:18:58 +00:00
return & ast_null_frame ;
2005-04-04 15:54:34 +00:00
}
2006-09-19 17:07:22 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Oooh, format changed to %d \n " , f -> subclass );
2004-10-04 10:13:01 +00:00
pvt -> owner -> nativeformats = f -> subclass ;
2005-04-04 15:54:34 +00:00
pvt -> nativeformats = f -> subclass ;
2004-10-04 10:13:01 +00:00
ast_set_read_format ( pvt -> owner , pvt -> owner -> readformat );
ast_set_write_format ( pvt -> owner , pvt -> owner -> writeformat );
2006-09-19 17:07:22 +00:00
ast_channel_unlock ( pvt -> owner );
}
2003-03-31 07:13:36 +00:00
/* Do in-band DTMF detection */
2005-05-21 17:09:30 +00:00
if (( pvt -> options . dtmfmode & H323_DTMF_INBAND ) && pvt -> vad ) {
2006-09-19 17:07:22 +00:00
if (( pvt -> nativeformats & ( AST_FORMAT_SLINEAR | AST_FORMAT_ALAW | AST_FORMAT_ULAW ))) {
if ( ! ast_channel_trylock ( pvt -> owner )) {
f = ast_dsp_process ( pvt -> owner , pvt -> vad , f );
ast_channel_unlock ( pvt -> owner );
}
else
ast_log ( LOG_NOTICE , "Unable to process inband DTMF while channel is locked \n " );
} else if ( pvt -> nativeformats && ! pvt -> noInbandDtmf ) {
ast_log ( LOG_NOTICE , "Inband DTMF is not supported on codec %s. Use RFC2833 \n " , ast_getformatname ( f -> subclass ));
pvt -> noInbandDtmf = 1 ;
2005-07-27 04:45:11 +00:00
}
2005-02-13 07:45:40 +00:00
if ( f && ( f -> frametype == AST_FRAME_DTMF )) {
2006-09-19 17:07:22 +00:00
if ( h323debug )
ast_log ( LOG_DTMF , "Received in-band digit %c. \n " , f -> subclass );
2005-07-27 04:45:11 +00:00
}
2004-10-04 10:13:01 +00:00
}
2003-03-31 07:13:36 +00:00
}
}
return f ;
}
2005-07-27 04:45:11 +00:00
static struct ast_frame * oh323_read ( struct ast_channel * c )
2003-03-31 07:13:36 +00:00
{
struct ast_frame * fr ;
2005-03-04 06:47:24 +00:00
struct oh323_pvt * pvt = ( struct oh323_pvt * ) c -> tech_pvt ;
2004-10-04 10:13:01 +00:00
ast_mutex_lock ( & pvt -> lock );
2005-05-11 13:27:49 +00:00
__oh323_update_info ( c , pvt );
2006-09-19 17:07:22 +00:00
switch ( c -> fdno ) {
case 0 :
fr = oh323_rtp_read ( pvt );
break ;
case 1 :
if ( pvt -> rtp )
fr = ast_rtcp_read ( pvt -> rtp );
else
fr = & ast_null_frame ;
break ;
default :
ast_log ( LOG_ERROR , "Unable to handle fd %d on channel %s \n " , c -> fdno , c -> name );
fr = & ast_null_frame ;
break ;
}
2004-10-04 10:13:01 +00:00
ast_mutex_unlock ( & pvt -> lock );
2003-03-31 07:13:36 +00:00
return fr ;
}
static int oh323_write ( struct ast_channel * c , struct ast_frame * frame )
{
2005-03-04 06:47:24 +00:00
struct oh323_pvt * pvt = ( struct oh323_pvt * ) c -> tech_pvt ;
2003-03-31 07:13:36 +00:00
int res = 0 ;
if ( frame -> frametype != AST_FRAME_VOICE ) {
2004-10-28 06:06:58 +00:00
if ( frame -> frametype == AST_FRAME_IMAGE ) {
2003-03-31 07:13:36 +00:00
return 0 ;
2004-10-28 06:06:58 +00:00
} else {
2003-03-31 07:13:36 +00:00
ast_log ( LOG_WARNING , "Can't send %d type frames with H323 write \n " , frame -> frametype );
return 0 ;
}
} else {
if ( ! ( frame -> subclass & c -> nativeformats )) {
2003-12-24 22:38:24 +00:00
ast_log ( LOG_WARNING , "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d) \n " ,
frame -> subclass , c -> nativeformats , c -> readformat , c -> writeformat );
2005-04-04 15:54:34 +00:00
return 0 ;
2003-03-31 07:13:36 +00:00
}
}
2004-10-04 10:13:01 +00:00
if ( pvt ) {
ast_mutex_lock ( & pvt -> lock );
2006-09-19 17:07:22 +00:00
if ( pvt -> rtp && ! pvt -> recvonly )
res = ast_rtp_write ( pvt -> rtp , frame );
2005-07-27 04:45:11 +00:00
__oh323_update_info ( c , pvt );
2004-10-04 10:13:01 +00:00
ast_mutex_unlock ( & pvt -> lock );
2003-03-31 07:13:36 +00:00
}
return res ;
}
2006-05-10 15:00:33 +00:00
static int oh323_indicate ( struct ast_channel * c , int condition , const void * data , size_t datalen )
2003-03-31 07:13:36 +00:00
{
2005-03-04 06:47:24 +00:00
struct oh323_pvt * pvt = ( struct oh323_pvt * ) c -> tech_pvt ;
2005-04-04 15:54:34 +00:00
char * token = ( char * ) NULL ;
2006-10-01 19:40:00 +00:00
int res = - 1 ;
int got_progress ;
2004-12-15 23:24:13 +00:00
2005-04-04 15:54:34 +00:00
ast_mutex_lock ( & pvt -> lock );
2007-06-14 23:01:01 +00:00
token = ( pvt -> cd . call_token ? ast_strdup ( pvt -> cd . call_token ) : NULL );
2006-10-01 19:40:00 +00:00
got_progress = pvt -> got_progress ;
if ( condition == AST_CONTROL_PROGRESS )
pvt -> got_progress = 1 ;
2006-10-02 18:57:49 +00:00
else if (( condition == AST_CONTROL_BUSY ) || ( condition == AST_CONTROL_CONGESTION ))
pvt -> alreadygone = 1 ;
2005-04-04 15:54:34 +00:00
ast_mutex_unlock ( & pvt -> lock );
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "OH323: Indicating %d on %s (%s) \n " , condition , token , c -> name );
2004-12-15 23:24:13 +00:00
2003-03-31 07:13:36 +00:00
switch ( condition ) {
case AST_CONTROL_RINGING :
2004-05-20 07:07:18 +00:00
if ( c -> _state == AST_STATE_RING || c -> _state == AST_STATE_RINGING ) {
2005-04-04 15:54:34 +00:00
h323_send_alerting ( token );
2006-10-01 19:40:00 +00:00
res = ( got_progress ? 0 : - 1 ); /* Do not simulate any audio tones if we got PROGRESS message */
2006-09-19 17:07:22 +00:00
}
2006-10-02 18:57:49 +00:00
break ;
2004-05-20 07:07:18 +00:00
case AST_CONTROL_PROGRESS :
if ( c -> _state != AST_STATE_UP ) {
2006-10-01 19:40:00 +00:00
/* Do not send PROGRESS message more than once */
if ( ! got_progress )
h323_send_progress ( token );
2006-10-02 18:57:49 +00:00
res = 0 ;
2003-03-31 07:13:36 +00:00
}
2006-10-02 18:57:49 +00:00
break ;
2003-03-31 07:13:36 +00:00
case AST_CONTROL_BUSY :
if ( c -> _state != AST_STATE_UP ) {
2005-04-04 15:54:34 +00:00
h323_answering_call ( token , 1 );
2006-09-19 17:07:22 +00:00
ast_softhangup_nolock ( c , AST_SOFTHANGUP_DEV );
2006-10-02 18:57:49 +00:00
res = 0 ;
2003-03-31 07:13:36 +00:00
}
2006-10-02 18:57:49 +00:00
break ;
2003-03-31 07:13:36 +00:00
case AST_CONTROL_CONGESTION :
if ( c -> _state != AST_STATE_UP ) {
2005-04-04 15:54:34 +00:00
h323_answering_call ( token , 1 );
2004-05-20 07:07:18 +00:00
ast_softhangup_nolock ( c , AST_SOFTHANGUP_DEV );
2006-10-02 18:57:49 +00:00
res = 0 ;
2003-03-31 07:13:36 +00:00
}
2006-10-02 18:57:49 +00:00
break ;
2006-07-19 20:44:39 +00:00
case AST_CONTROL_HOLD :
2006-09-28 10:41:38 +00:00
h323_hold_call ( token , 1 );
/* We should start MOH only if remote party isn't provide audio for us */
2006-07-19 20:44:39 +00:00
ast_moh_start ( c , data , NULL );
2006-10-02 18:57:49 +00:00
res = 0 ;
break ;
2006-07-19 20:44:39 +00:00
case AST_CONTROL_UNHOLD :
2006-09-28 10:41:38 +00:00
h323_hold_call ( token , 0 );
2006-07-19 20:44:39 +00:00
ast_moh_stop ( c );
2006-10-02 18:57:49 +00:00
res = 0 ;
break ;
2008-03-05 22:43:22 +00:00
case AST_CONTROL_SRCUPDATE :
ast_rtp_new_source ( pvt -> rtp );
res = 0 ;
break ;
2004-06-14 21:18:52 +00:00
case AST_CONTROL_PROCEEDING :
2003-03-31 07:13:36 +00:00
case - 1 :
2006-10-02 18:57:49 +00:00
break ;
2003-03-31 07:13:36 +00:00
default :
2006-10-02 18:57:49 +00:00
ast_log ( LOG_WARNING , "OH323: Don't know how to indicate condition %d on %s \n " , condition , token );
break ;
2003-03-31 07:13:36 +00:00
}
2005-04-04 15:54:34 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "OH323: Indicated %d on %s, res=%d \n " , condition , token , res );
2005-04-04 15:54:34 +00:00
if ( token )
2007-06-03 06:10:27 +00:00
ast_free ( token );
2005-04-04 15:54:34 +00:00
oh323_update_info ( c );
2006-10-01 19:40:00 +00:00
return res ;
2003-03-31 07:13:36 +00:00
}
2004-04-08 19:19:24 +00:00
static int oh323_fixup ( struct ast_channel * oldchan , struct ast_channel * newchan )
2003-03-31 07:13:36 +00:00
{
2005-03-04 06:47:24 +00:00
struct oh323_pvt * pvt = ( struct oh323_pvt * ) newchan -> tech_pvt ;
2003-03-31 07:13:36 +00:00
2004-10-04 10:13:01 +00:00
ast_mutex_lock ( & pvt -> lock );
if ( pvt -> owner != oldchan ) {
ast_log ( LOG_WARNING , "old channel wasn't %p but was %p \n " , oldchan , pvt -> owner );
2003-03-31 07:13:36 +00:00
return - 1 ;
}
2004-10-04 10:13:01 +00:00
pvt -> owner = newchan ;
ast_mutex_unlock ( & pvt -> lock );
2003-03-31 07:13:36 +00:00
return 0 ;
}
2006-09-19 17:07:22 +00:00
static int __oh323_rtp_create ( struct oh323_pvt * pvt )
{
struct in_addr our_addr ;
if ( pvt -> rtp )
return 0 ;
if ( ast_find_ourip ( & our_addr , bindaddr )) {
ast_mutex_unlock ( & pvt -> lock );
ast_log ( LOG_ERROR , "Unable to locate local IP address for RTP stream \n " );
return - 1 ;
}
pvt -> rtp = ast_rtp_new_with_bindaddr ( sched , io , 1 , 0 , our_addr );
if ( ! pvt -> rtp ) {
ast_mutex_unlock ( & pvt -> lock );
ast_log ( LOG_WARNING , "Unable to create RTP session: %s \n " , strerror ( errno ));
return - 1 ;
}
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Created RTP channel \n " );
2006-09-19 17:07:22 +00:00
2007-12-16 10:51:53 +00:00
ast_rtp_setqos ( pvt -> rtp , tos , cos , "H323 RTP" );
2006-09-19 17:07:22 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Setting NAT on RTP to %d \n " , pvt -> options . nat );
2006-09-19 17:07:22 +00:00
ast_rtp_setnat ( pvt -> rtp , pvt -> options . nat );
2006-09-25 09:03:14 +00:00
if ( pvt -> dtmf_pt [ 0 ] > 0 )
ast_rtp_set_rtpmap_type ( pvt -> rtp , pvt -> dtmf_pt [ 0 ], "audio" , "telephone-event" , 0 );
if ( pvt -> dtmf_pt [ 1 ] > 0 )
ast_rtp_set_rtpmap_type ( pvt -> rtp , pvt -> dtmf_pt [ 1 ], "audio" , "cisco-telephone-event" , 0 );
2006-09-19 17:07:22 +00:00
2006-09-20 16:24:00 +00:00
if ( pvt -> peercapability )
ast_rtp_codec_setpref ( pvt -> rtp , & pvt -> peer_prefs );
2006-09-19 17:07:22 +00:00
if ( pvt -> owner && ! ast_channel_trylock ( pvt -> owner )) {
ast_jb_configure ( pvt -> owner , & global_jbconf );
2007-08-08 21:44:58 +00:00
ast_channel_set_fd ( pvt -> owner , 0 , ast_rtp_fd ( pvt -> rtp ));
ast_channel_set_fd ( pvt -> owner , 1 , ast_rtcp_fd ( pvt -> rtp ));
2006-09-19 17:07:22 +00:00
ast_queue_frame ( pvt -> owner , & ast_null_frame ); /* Tell Asterisk to apply changes */
ast_channel_unlock ( pvt -> owner );
} else
pvt -> update_rtp_info = 1 ;
return 0 ;
}
2007-02-24 20:29:41 +00:00
/*! \brief Private structure should be locked on a call */
2005-05-11 13:27:49 +00:00
static struct ast_channel * __oh323_new ( struct oh323_pvt * pvt , int state , const char * host )
2003-03-31 07:13:36 +00:00
{
2003-08-16 17:00:22 +00:00
struct ast_channel * ch ;
2006-11-07 21:47:49 +00:00
char * cid_num , * cid_name ;
2003-03-31 07:13:36 +00:00
int fmt ;
2006-09-19 17:07:22 +00:00
2006-11-07 21:47:49 +00:00
if ( ! ast_strlen_zero ( pvt -> options . cid_num ))
cid_num = pvt -> options . cid_num ;
else
cid_num = pvt -> cd . call_source_e164 ;
if ( ! ast_strlen_zero ( pvt -> options . cid_name ))
cid_name = pvt -> options . cid_name ;
else
cid_name = pvt -> cd . call_source_name ;
2004-10-22 19:04:02 +00:00
/* Don't hold a oh323_pvt lock while we allocate a chanel */
ast_mutex_unlock ( & pvt -> lock );
2007-04-10 05:41:34 +00:00
ch = ast_channel_alloc ( 1 , state , cid_num , cid_name , pvt -> accountcode , pvt -> exten , pvt -> context , pvt -> amaflags , "H323/%s" , host );
2006-06-23 16:49:12 +00:00
/* Update usage counter */
2006-09-19 17:07:22 +00:00
ast_module_ref ( ast_module_info -> self );
2004-10-22 19:04:02 +00:00
ast_mutex_lock ( & pvt -> lock );
2003-08-16 17:00:22 +00:00
if ( ch ) {
2005-03-08 23:11:23 +00:00
ch -> tech = & oh323_tech ;
2006-09-19 17:07:22 +00:00
if ( ! ( fmt = pvt -> jointcapability ) && ! ( fmt = pvt -> options . capability ))
fmt = global_options . capability ;
ch -> nativeformats = ast_codec_choose ( & pvt -> options . prefs , fmt , 1 ) /* | (pvt->jointcapability & AST_FORMAT_VIDEO_MASK)*/ ;
2005-04-04 15:54:34 +00:00
pvt -> nativeformats = ch -> nativeformats ;
2003-08-16 17:00:22 +00:00
fmt = ast_best_codec ( ch -> nativeformats );
ch -> writeformat = fmt ;
2005-03-04 06:47:24 +00:00
ch -> rawwriteformat = fmt ;
2003-08-16 17:00:22 +00:00
ch -> readformat = fmt ;
2005-03-04 06:47:24 +00:00
ch -> rawreadformat = fmt ;
2008-01-23 15:23:51 +00:00
if ( ! pvt -> rtp )
__oh323_rtp_create ( pvt );
2006-09-19 17:07:22 +00:00
#if 0
2007-08-08 21:44:58 +00:00
ast_channel_set_fd(ch, 0, ast_rtp_fd(pvt->rtp));
ast_channel_set_fd(ch, 1, ast_rtcp_fd(pvt->rtp));
2006-09-19 17:07:22 +00:00
#endif
#ifdef VIDEO_SUPPORT
if ( pvt -> vrtp ) {
2007-08-08 21:44:58 +00:00
ast_channel_set_fd ( ch , 2 , ast_rtp_fd ( pvt -> vrtp ));
ast_channel_set_fd ( ch , 3 , ast_rtcp_fd ( pvt -> vrtp ));
2006-09-19 17:07:22 +00:00
}
#endif
#ifdef T38_SUPPORT
if ( pvt -> udptl ) {
2007-08-08 21:44:58 +00:00
ast_channel_set_fd ( ch , 4 , ast_udptl_fd ( pvt -> udptl ));
2006-09-19 17:07:22 +00:00
}
#endif
if ( state == AST_STATE_RING ) {
ch -> rings = 1 ;
}
2003-03-31 07:13:36 +00:00
/* Allocate dsp for in-band DTMF support */
2005-05-21 17:09:30 +00:00
if ( pvt -> options . dtmfmode & H323_DTMF_INBAND ) {
2004-10-04 10:13:01 +00:00
pvt -> vad = ast_dsp_new ();
2008-03-19 22:25:34 +00:00
ast_dsp_set_features ( pvt -> vad , DSP_FEATURE_DIGIT_DETECT );
2006-09-19 17:07:22 +00:00
}
2004-10-22 19:04:02 +00:00
/* Register channel functions. */
2005-03-04 06:47:24 +00:00
ch -> tech_pvt = pvt ;
2006-09-19 17:07:22 +00:00
/* Set the owner of this channel */
2004-10-04 10:13:01 +00:00
pvt -> owner = ch ;
2006-09-19 17:07:22 +00:00
2006-10-25 14:44:50 +00:00
ast_copy_string ( ch -> context , pvt -> context , sizeof ( ch -> context ));
ast_copy_string ( ch -> exten , pvt -> exten , sizeof ( ch -> exten ));
2003-08-16 17:00:22 +00:00
ch -> priority = 1 ;
2004-10-22 19:04:02 +00:00
if ( ! ast_strlen_zero ( pvt -> accountcode )) {
2006-04-03 18:36:30 +00:00
ast_string_field_set ( ch , accountcode , pvt -> accountcode );
2004-10-22 19:04:02 +00:00
}
if ( pvt -> amaflags ) {
2004-10-04 10:13:01 +00:00
ch -> amaflags = pvt -> amaflags ;
2004-10-22 19:04:02 +00:00
}
2006-09-19 17:07:22 +00:00
2006-08-05 05:26:29 +00:00
/* Don't use ast_set_callerid() here because it will
2006-11-07 21:47:49 +00:00
* generate a needless NewCallerID event */
ch -> cid . cid_ani = ast_strdup ( cid_num );
2006-09-19 17:07:22 +00:00
if ( pvt -> cd . redirect_reason >= 0 ) {
ch -> cid . cid_rdnis = ast_strdup ( pvt -> cd . redirect_number );
pbx_builtin_setvar_helper ( ch , "PRIREDIRECTREASON" , redirectingreason2str ( pvt -> cd . redirect_reason ));
}
2006-09-29 18:35:44 +00:00
ch -> cid . cid_pres = pvt -> cd . presentation ;
ch -> cid . cid_ton = pvt -> cd . type_of_number ;
2006-09-19 17:07:22 +00:00
2004-10-22 19:04:02 +00:00
if ( ! ast_strlen_zero ( pvt -> exten ) && strcmp ( pvt -> exten , "s" )) {
2007-06-14 23:01:01 +00:00
ch -> cid . cid_dnid = ast_strdup ( pvt -> exten );
2004-10-22 19:04:02 +00:00
}
2006-10-07 14:48:32 +00:00
if ( pvt -> cd . transfer_capability >= 0 )
ch -> transfercapability = pvt -> cd . transfer_capability ;
2003-03-31 07:13:36 +00:00
if ( state != AST_STATE_DOWN ) {
2003-08-16 17:00:22 +00:00
if ( ast_pbx_start ( ch )) {
ast_log ( LOG_WARNING , "Unable to start PBX on %s \n " , ch -> name );
ast_hangup ( ch );
2006-06-23 16:49:12 +00:00
ch = NULL ;
2003-03-31 07:13:36 +00:00
}
}
2006-09-19 17:07:22 +00:00
} else {
2003-03-31 07:13:36 +00:00
ast_log ( LOG_WARNING , "Unable to allocate channel structure \n " );
2004-10-22 19:04:02 +00:00
}
2003-08-16 17:00:22 +00:00
return ch ;
2003-03-31 07:13:36 +00:00
}
static struct oh323_pvt * oh323_alloc ( int callid )
{
2004-10-04 10:13:01 +00:00
struct oh323_pvt * pvt ;
2003-03-31 07:13:36 +00:00
2007-06-03 06:10:27 +00:00
pvt = ast_calloc ( 1 , sizeof ( * pvt ));
2004-10-04 10:13:01 +00:00
if ( ! pvt ) {
2003-03-31 07:13:36 +00:00
ast_log ( LOG_ERROR , "Couldn't allocate private structure. This is bad \n " );
return NULL ;
}
2006-09-19 17:07:22 +00:00
pvt -> cd . redirect_reason = - 1 ;
2006-10-07 14:48:32 +00:00
pvt -> cd . transfer_capability = - 1 ;
2006-09-19 17:07:22 +00:00
/* Ensure the call token is allocated for outgoing call */
if ( ! callid ) {
if (( pvt -> cd ). call_token == NULL ) {
2007-06-03 06:10:27 +00:00
( pvt -> cd ). call_token = ast_calloc ( 1 , 128 );
2006-09-19 17:07:22 +00:00
}
if ( ! pvt -> cd . call_token ) {
ast_log ( LOG_ERROR , "Not enough memory to alocate call token \n " );
ast_rtp_destroy ( pvt -> rtp );
2007-06-03 06:10:27 +00:00
ast_free ( pvt );
2006-09-19 17:07:22 +00:00
return NULL ;
}
memset (( char * )( pvt -> cd ). call_token , 0 , 128 );
pvt -> cd . call_reference = callid ;
2004-10-01 04:50:34 +00:00
}
2005-05-21 17:09:30 +00:00
memcpy ( & pvt -> options , & global_options , sizeof ( pvt -> options ));
2006-09-19 17:07:22 +00:00
pvt -> jointcapability = pvt -> options . capability ;
2006-09-25 09:03:14 +00:00
if ( pvt -> options . dtmfmode & ( H323_DTMF_RFC2833 | H323_DTMF_CISCO )) {
2004-10-04 10:13:01 +00:00
pvt -> nonCodecCapability |= AST_RTP_DTMF ;
2005-05-21 17:09:30 +00:00
} else {
pvt -> nonCodecCapability &= ~ AST_RTP_DTMF ;
2004-10-01 04:50:34 +00:00
}
2006-10-25 14:44:50 +00:00
ast_copy_string ( pvt -> context , default_context , sizeof ( pvt -> context ));
2006-09-19 17:07:22 +00:00
pvt -> newstate = pvt -> newcontrol = pvt -> newdigit = pvt -> update_rtp_info = pvt -> DTMFsched = - 1 ;
ast_mutex_init ( & pvt -> lock );
2003-03-31 07:13:36 +00:00
/* Add to interface list */
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & iflock );
2004-10-04 10:13:01 +00:00
pvt -> next = iflist ;
iflist = pvt ;
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & iflock );
2004-10-04 10:13:01 +00:00
return pvt ;
2003-03-31 07:13:36 +00:00
}
2005-05-11 13:27:49 +00:00
static struct oh323_pvt * find_call_locked ( int call_reference , const char * token )
2006-09-19 17:07:22 +00:00
{
2005-05-11 13:27:49 +00:00
struct oh323_pvt * pvt ;
2003-03-31 07:13:36 +00:00
2004-10-01 04:50:34 +00:00
ast_mutex_lock ( & iflock );
2006-09-19 17:07:22 +00:00
pvt = iflist ;
2005-05-11 13:27:49 +00:00
while ( pvt ) {
if ( ! pvt -> needdestroy && (( signed int ) pvt -> cd . call_reference == call_reference )) {
2006-09-19 17:07:22 +00:00
/* Found the call */
2008-04-14 18:34:17 +00:00
if (( token != NULL ) && ( pvt -> cd . call_token != NULL ) && ( ! strcmp ( pvt -> cd . call_token , token ))) {
2005-05-11 13:27:49 +00:00
ast_mutex_lock ( & pvt -> lock );
ast_mutex_unlock ( & iflock );
return pvt ;
} else if ( token == NULL ) {
ast_log ( LOG_WARNING , "Call Token is NULL \n " );
ast_mutex_lock ( & pvt -> lock );
ast_mutex_unlock ( & iflock );
return pvt ;
}
}
2006-09-19 17:07:22 +00:00
pvt = pvt -> next ;
2005-05-11 13:27:49 +00:00
}
ast_mutex_unlock ( & iflock );
2004-09-19 16:53:01 +00:00
return NULL ;
2003-03-31 07:13:36 +00:00
}
2005-07-27 04:45:11 +00:00
static int update_state ( struct oh323_pvt * pvt , int state , int signal )
{
if ( ! pvt )
return 0 ;
2006-09-19 17:07:22 +00:00
if ( pvt -> owner && ! ast_channel_trylock ( pvt -> owner )) {
2005-07-27 04:45:11 +00:00
if ( state >= 0 )
ast_setstate ( pvt -> owner , state );
if ( signal >= 0 )
ast_queue_control ( pvt -> owner , signal );
2006-09-19 17:07:22 +00:00
ast_channel_unlock ( pvt -> owner );
2005-07-27 04:45:11 +00:00
return 1 ;
}
else {
if ( state >= 0 )
pvt -> newstate = state ;
if ( signal >= 0 )
2005-08-02 03:25:28 +00:00
pvt -> newcontrol = signal ;
2005-07-27 04:45:11 +00:00
return 0 ;
}
}
2006-09-19 17:07:22 +00:00
static struct oh323_alias * build_alias ( const char * name , struct ast_variable * v , struct ast_variable * alt , int realtime )
2004-10-04 10:13:01 +00:00
{
2006-09-19 17:07:22 +00:00
struct oh323_alias * alias ;
int found = 0 ;
alias = ASTOBJ_CONTAINER_FIND_UNLINK_FULL ( & aliasl , name , name , 0 , 0 , strcasecmp );
if ( alias )
found ++ ;
else {
2007-06-03 06:10:27 +00:00
if ( ! ( alias = ast_calloc ( 1 , sizeof ( * alias ))))
2006-09-19 17:07:22 +00:00
return NULL ;
ASTOBJ_INIT ( alias );
}
if ( ! found && name )
2006-10-25 14:44:50 +00:00
ast_copy_string ( alias -> name , name , sizeof ( alias -> name ));
2006-09-19 17:07:22 +00:00
for (; v || (( v = alt ) && ! ( alt = NULL )); v = v -> next ) {
if ( ! strcasecmp ( v -> name , "e164" )) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( alias -> e164 , v -> value , sizeof ( alias -> e164 ));
2006-09-19 17:07:22 +00:00
} else if ( ! strcasecmp ( v -> name , "prefix" )) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( alias -> prefix , v -> value , sizeof ( alias -> prefix ));
2006-09-19 17:07:22 +00:00
} else if ( ! strcasecmp ( v -> name , "context" )) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( alias -> context , v -> value , sizeof ( alias -> context ));
2006-09-19 17:07:22 +00:00
} else if ( ! strcasecmp ( v -> name , "secret" )) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( alias -> secret , v -> value , sizeof ( alias -> secret ));
2006-09-19 17:07:22 +00:00
} else {
if ( strcasecmp ( v -> value , "h323" )) {
ast_log ( LOG_WARNING , "Keyword %s does not make sense in type=h323 \n " , v -> name );
2004-10-04 10:13:01 +00:00
}
}
}
2006-09-19 17:07:22 +00:00
ASTOBJ_UNMARK ( alias );
return alias ;
2004-10-04 10:13:01 +00:00
}
2006-09-19 17:07:22 +00:00
static struct oh323_alias * realtime_alias ( const char * alias )
2004-10-04 10:13:01 +00:00
{
2006-09-19 17:07:22 +00:00
struct ast_variable * var , * tmp ;
struct oh323_alias * a ;
2004-10-04 10:13:01 +00:00
2006-09-19 17:07:22 +00:00
var = ast_load_realtime ( "h323" , "name" , alias , NULL );
if ( ! var )
return NULL ;
for ( tmp = var ; tmp ; tmp = tmp -> next ) {
if ( ! strcasecmp ( tmp -> name , "type" ) &&
! ( ! strcasecmp ( tmp -> value , "alias" ) || ! strcasecmp ( tmp -> value , "h323" ))) {
ast_variables_destroy ( var );
return NULL ;
2004-10-04 10:13:01 +00:00
}
}
2006-09-19 17:07:22 +00:00
a = build_alias ( alias , var , NULL , 1 );
ast_variables_destroy ( var );
return a ;
2004-10-04 10:13:01 +00:00
}
2006-09-19 17:07:22 +00:00
static int update_common_options ( struct ast_variable * v , struct call_options * options )
2003-03-31 07:13:36 +00:00
{
2006-09-19 17:07:22 +00:00
int tmp ;
2006-09-24 18:59:38 +00:00
char * val , * opt ;
2004-09-30 19:36:46 +00:00
2006-09-19 17:07:22 +00:00
if ( ! strcasecmp ( v -> name , "allow" )) {
ast_parse_allow_disallow ( & options -> prefs , & options -> capability , v -> value , 1 );
} else if ( ! strcasecmp ( v -> name , "disallow" )) {
ast_parse_allow_disallow ( & options -> prefs , & options -> capability , v -> value , 0 );
} else if ( ! strcasecmp ( v -> name , "dtmfmode" )) {
2006-09-27 12:32:06 +00:00
val = ast_strdupa ( v -> value );
2006-09-24 18:59:38 +00:00
if (( opt = strchr ( val , ':' )) != ( char * ) NULL ) {
* opt ++ = '\0' ;
tmp = atoi ( opt );
}
2006-09-19 17:07:22 +00:00
if ( ! strcasecmp ( v -> value , "inband" )) {
2006-09-24 18:53:44 +00:00
options -> dtmfmode |= H323_DTMF_INBAND ;
2006-09-24 18:59:38 +00:00
} else if ( ! strcasecmp ( val , "rfc2833" )) {
2006-09-24 18:53:44 +00:00
options -> dtmfmode |= H323_DTMF_RFC2833 ;
2006-09-25 09:03:14 +00:00
if ( ! opt ) {
options -> dtmfcodec [ 0 ] = H323_DTMF_RFC2833_PT ;
} else if (( tmp >= 96 ) && ( tmp < 128 )) {
options -> dtmfcodec [ 0 ] = tmp ;
} else {
options -> dtmfcodec [ 0 ] = H323_DTMF_RFC2833_PT ;
ast_log ( LOG_WARNING , "Unknown rfc2833 payload %s specified at line %d, using default %d \n " , opt , v -> lineno , options -> dtmfcodec [ 0 ]);
}
} else if ( ! strcasecmp ( val , "cisco" )) {
options -> dtmfmode |= H323_DTMF_CISCO ;
if ( ! opt ) {
options -> dtmfcodec [ 1 ] = H323_DTMF_CISCO_PT ;
} else if (( tmp >= 96 ) && ( tmp < 128 )) {
options -> dtmfcodec [ 1 ] = tmp ;
} else {
options -> dtmfcodec [ 1 ] = H323_DTMF_CISCO_PT ;
ast_log ( LOG_WARNING , "Unknown Cisco DTMF payload %s specified at line %d, using default %d \n " , opt , v -> lineno , options -> dtmfcodec [ 1 ]);
2006-09-24 18:59:38 +00:00
}
2006-09-25 09:03:14 +00:00
} else if ( ! strcasecmp ( v -> value , "h245-signal" )) {
options -> dtmfmode |= H323_DTMF_SIGNAL ;
2006-09-19 17:07:22 +00:00
} else {
2006-09-25 09:03:14 +00:00
ast_log ( LOG_WARNING , "Unknown dtmf mode '%s' at line %d \n " , v -> value , v -> lineno );
2004-09-30 19:36:46 +00:00
}
2006-09-19 17:07:22 +00:00
} else if ( ! strcasecmp ( v -> name , "dtmfcodec" )) {
2006-09-24 18:59:38 +00:00
ast_log ( LOG_NOTICE , "Option %s at line %d is deprecated. Use dtmfmode=rfc2833[:<payload>] instead. \n " , v -> name , v -> lineno );
2006-09-19 17:07:22 +00:00
tmp = atoi ( v -> value );
if ( tmp < 96 )
ast_log ( LOG_WARNING , "Invalid %s value %s at line %d \n " , v -> name , v -> value , v -> lineno );
else
2006-09-25 09:03:14 +00:00
options -> dtmfcodec [ 0 ] = tmp ;
2006-09-19 17:07:22 +00:00
} else if ( ! strcasecmp ( v -> name , "bridge" )) {
options -> bridge = ast_true ( v -> value );
} else if ( ! strcasecmp ( v -> name , "nat" )) {
options -> nat = ast_true ( v -> value );
} else if ( ! strcasecmp ( v -> name , "fastStart" )) {
options -> fastStart = ast_true ( v -> value );
} else if ( ! strcasecmp ( v -> name , "h245Tunneling" )) {
options -> h245Tunneling = ast_true ( v -> value );
} else if ( ! strcasecmp ( v -> name , "silenceSuppression" )) {
options -> silenceSuppression = ast_true ( v -> value );
} else if ( ! strcasecmp ( v -> name , "progress_setup" )) {
tmp = atoi ( v -> value );
if (( tmp != 0 ) && ( tmp != 1 ) && ( tmp != 3 ) && ( tmp != 8 )) {
ast_log ( LOG_WARNING , "Invalid value %s for %s at line %d, assuming 0 \n " , v -> value , v -> name , v -> lineno );
tmp = 0 ;
}
options -> progress_setup = tmp ;
} else if ( ! strcasecmp ( v -> name , "progress_alert" )) {
tmp = atoi ( v -> value );
if (( tmp != 0 ) && ( tmp != 1 ) && ( tmp != 8 )) {
ast_log ( LOG_WARNING , "Invalid value %s for %s at line %d, assuming 0 \n " , v -> value , v -> name , v -> lineno );
tmp = 0 ;
}
options -> progress_alert = tmp ;
} else if ( ! strcasecmp ( v -> name , "progress_audio" )) {
options -> progress_audio = ast_true ( v -> value );
} else if ( ! strcasecmp ( v -> name , "callerid" )) {
ast_callerid_split ( v -> value , options -> cid_name , sizeof ( options -> cid_name ), options -> cid_num , sizeof ( options -> cid_num ));
} else if ( ! strcasecmp ( v -> name , "fullname" )) {
ast_copy_string ( options -> cid_name , v -> value , sizeof ( options -> cid_name ));
} else if ( ! strcasecmp ( v -> name , "cid_number" )) {
ast_copy_string ( options -> cid_num , v -> value , sizeof ( options -> cid_num ));
} else if ( ! strcasecmp ( v -> name , "tunneling" )) {
if ( ! strcasecmp ( v -> value , "none" ))
options -> tunnelOptions = 0 ;
else if ( ! strcasecmp ( v -> value , "cisco" ))
options -> tunnelOptions |= H323_TUNNEL_CISCO ;
else if ( ! strcasecmp ( v -> value , "qsig" ))
options -> tunnelOptions |= H323_TUNNEL_QSIG ;
else
ast_log ( LOG_WARNING , "Invalid value %s for %s at line %d \n " , v -> value , v -> name , v -> lineno );
2006-09-28 10:41:38 +00:00
} else if ( ! strcasecmp ( v -> name , "hold" )) {
if ( ! strcasecmp ( v -> value , "none" ))
options -> holdHandling = ~ 0 ;
else if ( ! strcasecmp ( v -> value , "notify" ))
options -> holdHandling |= H323_HOLD_NOTIFY ;
else if ( ! strcasecmp ( v -> value , "q931only" ))
options -> holdHandling |= H323_HOLD_NOTIFY | H323_HOLD_Q931ONLY ;
else if ( ! strcasecmp ( v -> value , "h450" ))
options -> holdHandling |= H323_HOLD_H450 ;
else
ast_log ( LOG_WARNING , "Invalid value %s for %s at line %d \n " , v -> value , v -> name , v -> lineno );
2006-09-19 17:07:22 +00:00
} else
return 1 ;
return 0 ;
}
2007-11-15 15:21:04 +00:00
static struct oh323_user * build_user ( const char * name , struct ast_variable * v , struct ast_variable * alt , int realtime )
2006-09-19 17:07:22 +00:00
{
struct oh323_user * user ;
struct ast_ha * oldha ;
int found = 0 ;
int format ;
user = ASTOBJ_CONTAINER_FIND_UNLINK_FULL ( & userl , name , name , 0 , 0 , strcmp );
if ( user )
found ++ ;
else {
2007-06-03 06:10:27 +00:00
if ( ! ( user = ast_calloc ( 1 , sizeof ( * user ))))
2006-09-19 17:07:22 +00:00
return NULL ;
ASTOBJ_INIT ( user );
}
oldha = user -> ha ;
user -> ha = ( struct ast_ha * ) NULL ;
memcpy ( & user -> options , & global_options , sizeof ( user -> options ));
2006-09-24 18:53:44 +00:00
user -> options . dtmfmode = 0 ;
2006-09-28 10:41:38 +00:00
user -> options . holdHandling = 0 ;
2006-09-19 17:07:22 +00:00
/* Set default context */
2006-10-25 14:44:50 +00:00
ast_copy_string ( user -> context , default_context , sizeof ( user -> context ));
2006-09-19 17:07:22 +00:00
if ( user && ! found )
2006-10-25 14:44:50 +00:00
ast_copy_string ( user -> name , name , sizeof ( user -> name ));
2006-09-19 17:07:22 +00:00
#if 0 /* XXX Port channel variables functionality from chan_sip XXX */
if (user->chanvars) {
ast_variables_destroy(user->chanvars);
user->chanvars = NULL;
}
#endif
for (; v || (( v = alt ) && ! ( alt = NULL )); v = v -> next ) {
if ( ! update_common_options ( v , & user -> options ))
continue ;
if ( ! strcasecmp ( v -> name , "context" )) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( user -> context , v -> value , sizeof ( user -> context ));
2006-09-19 17:07:22 +00:00
} else if ( ! strcasecmp ( v -> name , "secret" )) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( user -> secret , v -> value , sizeof ( user -> secret ));
2006-09-19 17:07:22 +00:00
} else if ( ! strcasecmp ( v -> name , "accountcode" )) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( user -> accountcode , v -> value , sizeof ( user -> accountcode ));
2006-09-19 17:07:22 +00:00
} else if ( ! strcasecmp ( v -> name , "host" )) {
if ( ! strcasecmp ( v -> value , "dynamic" )) {
ast_log ( LOG_ERROR , "A dynamic host on a type=user does not make any sense \n " );
ASTOBJ_UNREF ( user , oh323_destroy_user );
return NULL ;
} else if ( ast_get_ip ( & user -> addr , v -> value )) {
ASTOBJ_UNREF ( user , oh323_destroy_user );
return NULL ;
}
/* Let us know we need to use ip authentication */
user -> host = 1 ;
} else if ( ! strcasecmp ( v -> name , "amaflags" )) {
format = ast_cdr_amaflags2int ( v -> value );
if ( format < 0 ) {
ast_log ( LOG_WARNING , "Invalid AMA Flags: %s at line %d \n " , v -> value , v -> lineno );
} else {
user -> amaflags = format ;
}
} else if ( ! strcasecmp ( v -> name , "permit" ) ||
! strcasecmp ( v -> name , "deny" )) {
2007-01-18 06:59:22 +00:00
int ha_error = 0 ;
user -> ha = ast_append_ha ( v -> name , v -> value , user -> ha , & ha_error );
if ( ha_error )
ast_log ( LOG_ERROR , "Bad ACL entry in configuration line %d : %s \n " , v -> lineno , v -> value );
2006-09-19 17:07:22 +00:00
}
}
2006-09-24 18:53:44 +00:00
if ( ! user -> options . dtmfmode )
user -> options . dtmfmode = global_options . dtmfmode ;
2006-09-28 10:41:38 +00:00
if ( user -> options . holdHandling == ~ 0 )
user -> options . holdHandling = 0 ;
else if ( ! user -> options . holdHandling )
user -> options . holdHandling = global_options . holdHandling ;
2006-09-19 17:07:22 +00:00
ASTOBJ_UNMARK ( user );
ast_free_ha ( oldha );
return user ;
}
static struct oh323_user * realtime_user ( const call_details_t * cd )
{
struct ast_variable * var , * tmp ;
struct oh323_user * user ;
2007-11-15 15:21:04 +00:00
const char * username ;
2006-09-19 17:07:22 +00:00
if ( userbyalias )
var = ast_load_realtime ( "h323" , "name" , username = cd -> call_source_aliases , NULL );
else {
username = ( char * ) NULL ;
var = ast_load_realtime ( "h323" , "host" , cd -> sourceIp , NULL );
}
if ( ! var )
return NULL ;
for ( tmp = var ; tmp ; tmp = tmp -> next ) {
if ( ! strcasecmp ( tmp -> name , "type" ) &&
! ( ! strcasecmp ( tmp -> value , "user" ) || ! strcasecmp ( tmp -> value , "friend" ))) {
ast_variables_destroy ( var );
return NULL ;
} else if ( ! username && ! strcasecmp ( tmp -> name , "name" ))
username = tmp -> value ;
}
if ( ! username ) {
ast_log ( LOG_WARNING , "Cannot determine user name for IP address %s \n " , cd -> sourceIp );
ast_variables_destroy ( var );
return NULL ;
}
user = build_user ( username , var , NULL , 1 );
ast_variables_destroy ( var );
return user ;
}
static struct oh323_peer * build_peer ( const char * name , struct ast_variable * v , struct ast_variable * alt , int realtime )
{
struct oh323_peer * peer ;
struct ast_ha * oldha ;
int found = 0 ;
peer = ASTOBJ_CONTAINER_FIND_UNLINK_FULL ( & peerl , name , name , 0 , 0 , strcmp );
if ( peer )
found ++ ;
else {
2007-06-03 06:10:27 +00:00
if ( ! ( peer = ast_calloc ( 1 , sizeof ( * peer ))))
2006-09-19 17:07:22 +00:00
return NULL ;
ASTOBJ_INIT ( peer );
}
oldha = peer -> ha ;
peer -> ha = NULL ;
memcpy ( & peer -> options , & global_options , sizeof ( peer -> options ));
2006-09-24 18:53:44 +00:00
peer -> options . dtmfmode = 0 ;
2006-09-28 10:41:38 +00:00
peer -> options . holdHandling = 0 ;
2006-09-19 17:07:22 +00:00
peer -> addr . sin_port = htons ( h323_signalling_port );
peer -> addr . sin_family = AF_INET ;
if ( ! found && name )
2006-10-25 14:44:50 +00:00
ast_copy_string ( peer -> name , name , sizeof ( peer -> name ));
2006-09-19 17:07:22 +00:00
#if 0 /* XXX Port channel variables functionality from chan_sip XXX */
if (peer->chanvars) {
ast_variables_destroy(peer->chanvars);
peer->chanvars = NULL;
}
#endif
/* Default settings for mailbox */
peer -> mailbox [ 0 ] = '\0' ;
for (; v || (( v = alt ) && ! ( alt = NULL )); v = v -> next ) {
if ( ! update_common_options ( v , & peer -> options ))
continue ;
if ( ! strcasecmp ( v -> name , "host" )) {
if ( ! strcasecmp ( v -> value , "dynamic" )) {
ast_log ( LOG_ERROR , "Dynamic host configuration not implemented. \n " );
ASTOBJ_UNREF ( peer , oh323_destroy_peer );
return NULL ;
}
if ( ast_get_ip ( & peer -> addr , v -> value )) {
ast_log ( LOG_ERROR , "Could not determine IP for %s \n " , v -> value );
ASTOBJ_UNREF ( peer , oh323_destroy_peer );
return NULL ;
}
} else if ( ! strcasecmp ( v -> name , "port" )) {
peer -> addr . sin_port = htons ( atoi ( v -> value ));
} else if ( ! strcasecmp ( v -> name , "permit" ) ||
! strcasecmp ( v -> name , "deny" )) {
2007-01-18 06:59:22 +00:00
int ha_error = 0 ;
peer -> ha = ast_append_ha ( v -> name , v -> value , peer -> ha , & ha_error );
if ( ha_error )
ast_log ( LOG_ERROR , "Bad ACL entry in configuration line %d : %s \n " , v -> lineno , v -> value );
2006-09-19 17:07:22 +00:00
} else if ( ! strcasecmp ( v -> name , "mailbox" )) {
ast_copy_string ( peer -> mailbox , v -> value , sizeof ( peer -> mailbox ));
2008-06-16 19:57:05 +00:00
} else if ( ! strcasecmp ( v -> name , "hasvoicemail" )) {
if ( ast_true ( v -> value ) && ast_strlen_zero ( peer -> mailbox )) {
ast_copy_string ( peer -> mailbox , name , sizeof ( peer -> mailbox ));
}
2006-09-19 17:07:22 +00:00
}
}
2006-09-24 18:53:44 +00:00
if ( ! peer -> options . dtmfmode )
peer -> options . dtmfmode = global_options . dtmfmode ;
2006-09-28 10:41:38 +00:00
if ( peer -> options . holdHandling == ~ 0 )
peer -> options . holdHandling = 0 ;
else if ( ! peer -> options . holdHandling )
peer -> options . holdHandling = global_options . holdHandling ;
2006-09-19 17:07:22 +00:00
ASTOBJ_UNMARK ( peer );
ast_free_ha ( oldha );
return peer ;
}
static struct oh323_peer * realtime_peer ( const char * peername , struct sockaddr_in * sin )
{
struct oh323_peer * peer ;
struct ast_variable * var ;
struct ast_variable * tmp ;
2008-05-07 18:24:51 +00:00
const char * addr = NULL ;
2006-09-19 17:07:22 +00:00
/* First check on peer name */
if ( peername )
2008-05-07 18:24:51 +00:00
var = ast_load_realtime ( "h323" , "name" , peername , NULL );
2006-09-19 17:07:22 +00:00
else if ( sin ) /* Then check on IP address for dynamic peers */
var = ast_load_realtime ( "h323" , "host" , addr = ast_inet_ntoa ( sin -> sin_addr ), NULL );
else
return NULL ;
if ( ! var )
return NULL ;
for ( tmp = var ; tmp ; tmp = tmp -> next ) {
/* If this is type=user, then skip this object. */
if ( ! strcasecmp ( tmp -> name , "type" ) &&
! ( ! strcasecmp ( tmp -> value , "peer" ) || ! strcasecmp ( tmp -> value , "friend" ))) {
ast_variables_destroy ( var );
return NULL ;
} else if ( ! peername && ! strcasecmp ( tmp -> name , "name" )) {
peername = tmp -> value ;
}
}
if ( ! peername ) { /* Did not find peer in realtime */
ast_log ( LOG_WARNING , "Cannot determine peer name for IP address %s \n " , addr );
ast_variables_destroy ( var );
return NULL ;
}
/* Peer found in realtime, now build it in memory */
peer = build_peer ( peername , var , NULL , 1 );
ast_variables_destroy ( var );
return peer ;
}
static int oh323_addrcmp_str ( struct in_addr inaddr , char * addr )
{
return strcmp ( ast_inet_ntoa ( inaddr ), addr );
}
static struct oh323_user * find_user ( const call_details_t * cd , int realtime )
{
struct oh323_user * u ;
if ( userbyalias )
u = ASTOBJ_CONTAINER_FIND ( & userl , cd -> call_source_aliases );
else
u = ASTOBJ_CONTAINER_FIND_FULL ( & userl , cd -> sourceIp , addr . sin_addr , 0 , 0 , oh323_addrcmp_str );
if ( ! u && realtime )
u = realtime_user ( cd );
if ( ! u && h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Could not find user by name %s or address %s \n " , cd -> call_source_aliases , cd -> sourceIp );
2006-09-19 17:07:22 +00:00
return u ;
}
static int oh323_addrcmp ( struct sockaddr_in addr , struct sockaddr_in * sin )
{
int res ;
if ( ! sin )
res = - 1 ;
else
res = inaddrcmp ( & addr , sin );
return res ;
}
static struct oh323_peer * find_peer ( const char * peer , struct sockaddr_in * sin , int realtime )
{
struct oh323_peer * p ;
if ( peer )
p = ASTOBJ_CONTAINER_FIND ( & peerl , peer );
else
p = ASTOBJ_CONTAINER_FIND_FULL ( & peerl , sin , addr , 0 , 0 , oh323_addrcmp );
if ( ! p && realtime )
p = realtime_peer ( peer , sin );
if ( ! p && h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Could not find peer by name %s or address %s \n " , ( peer ? peer : "<NONE>" ), ( sin ? ast_inet_ntoa ( sin -> sin_addr ) : "<NONE>" ));
2006-09-19 17:07:22 +00:00
return p ;
}
static int create_addr ( struct oh323_pvt * pvt , char * opeer )
{
struct hostent * hp ;
struct ast_hostent ahp ;
struct oh323_peer * p ;
int portno ;
int found = 0 ;
char * port ;
char * hostn ;
char peer [ 256 ] = "" ;
2006-10-25 14:44:50 +00:00
ast_copy_string ( peer , opeer , sizeof ( peer ));
2006-09-19 17:07:22 +00:00
port = strchr ( peer , ':' );
if ( port ) {
* port = '\0' ;
port ++ ;
}
pvt -> sa . sin_family = AF_INET ;
p = find_peer ( peer , NULL , 1 );
if ( p ) {
found ++ ;
memcpy ( & pvt -> options , & p -> options , sizeof ( pvt -> options ));
pvt -> jointcapability = pvt -> options . capability ;
if ( pvt -> options . dtmfmode ) {
if ( pvt -> options . dtmfmode & H323_DTMF_RFC2833 ) {
pvt -> nonCodecCapability |= AST_RTP_DTMF ;
} else {
pvt -> nonCodecCapability &= ~ AST_RTP_DTMF ;
}
}
if ( p -> addr . sin_addr . s_addr ) {
pvt -> sa . sin_addr = p -> addr . sin_addr ;
pvt -> sa . sin_port = p -> addr . sin_port ;
}
ASTOBJ_UNREF ( p , oh323_destroy_peer );
}
if ( ! p && ! found ) {
2004-10-01 04:50:34 +00:00
hostn = peer ;
if ( port ) {
portno = atoi ( port );
} else {
2004-10-04 10:13:01 +00:00
portno = h323_signalling_port ;
2006-09-19 17:07:22 +00:00
}
2004-10-01 04:50:34 +00:00
hp = ast_gethostbyname ( hostn , & ahp );
if ( hp ) {
2004-10-04 10:13:01 +00:00
memcpy ( & pvt -> sa . sin_addr , hp -> h_addr , sizeof ( pvt -> sa . sin_addr ));
pvt -> sa . sin_port = htons ( portno );
2006-09-19 17:07:22 +00:00
/* Look peer by address */
p = find_peer ( NULL , & pvt -> sa , 1 );
memcpy ( & pvt -> options , ( p ? & p -> options : & global_options ), sizeof ( pvt -> options ));
pvt -> jointcapability = pvt -> options . capability ;
if ( p ) {
ASTOBJ_UNREF ( p , oh323_destroy_peer );
}
if ( pvt -> options . dtmfmode ) {
if ( pvt -> options . dtmfmode & H323_DTMF_RFC2833 ) {
pvt -> nonCodecCapability |= AST_RTP_DTMF ;
} else {
pvt -> nonCodecCapability &= ~ AST_RTP_DTMF ;
}
}
return 0 ;
2004-10-01 04:50:34 +00:00
} else {
ast_log ( LOG_WARNING , "No such host: %s \n " , peer );
return - 1 ;
}
2006-09-19 17:07:22 +00:00
} else if ( ! found ) {
2004-10-01 04:50:34 +00:00
return - 1 ;
2006-09-19 17:07:22 +00:00
} else {
2004-10-04 10:13:01 +00:00
return 0 ;
}
2004-09-30 19:36:46 +00:00
}
2004-12-15 23:24:13 +00:00
static struct ast_channel * oh323_request ( const char * type , int format , void * data , int * cause )
2004-09-30 19:36:46 +00:00
{
2003-03-31 07:13:36 +00:00
int oldformat ;
2004-10-04 10:13:01 +00:00
struct oh323_pvt * pvt ;
2003-03-31 07:13:36 +00:00
struct ast_channel * tmpc = NULL ;
2004-09-30 19:36:46 +00:00
char * dest = ( char * ) data ;
2003-03-31 07:13:36 +00:00
char * ext , * host ;
2003-06-03 07:11:52 +00:00
char * h323id = NULL ;
2005-05-11 13:27:49 +00:00
char tmp [ 256 ], tmp1 [ 256 ];
2006-09-19 17:07:22 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "type=%s, format=%d, data=%s. \n " , type , format , ( char * ) data );
2006-09-19 17:07:22 +00:00
2004-10-04 10:13:01 +00:00
pvt = oh323_alloc ( 0 );
if ( ! pvt ) {
ast_log ( LOG_WARNING , "Unable to build pvt data for '%s' \n " , ( char * ) data );
return NULL ;
2006-09-19 17:07:22 +00:00
}
2003-03-31 07:13:36 +00:00
oldformat = format ;
2007-11-06 22:51:48 +00:00
format &= AST_FORMAT_AUDIO_MASK ;
2003-03-31 07:13:36 +00:00
if ( ! format ) {
ast_log ( LOG_NOTICE , "Asked to get a channel of unsupported format '%d' \n " , format );
2006-09-19 17:07:22 +00:00
oh323_destroy ( pvt );
if ( cause )
* cause = AST_CAUSE_INCOMPATIBLE_DESTINATION ;
2003-03-31 07:13:36 +00:00
return NULL ;
}
2006-10-25 14:44:50 +00:00
ast_copy_string ( tmp , dest , sizeof ( tmp ));
2003-03-31 07:13:36 +00:00
host = strchr ( tmp , '@' );
if ( host ) {
* host = '\0' ;
host ++ ;
ext = tmp ;
} else {
2006-09-19 17:07:22 +00:00
ext = strrchr ( tmp , '/' );
if ( ext )
* ext ++ = '\0' ;
2003-03-31 07:13:36 +00:00
host = tmp ;
}
2006-09-19 17:07:22 +00:00
strtok_r ( host , "/" , & ( h323id ));
2005-10-27 02:19:37 +00:00
if ( ! ast_strlen_zero ( h323id )) {
2003-06-03 07:11:52 +00:00
h323_set_id ( h323id );
}
2004-01-11 17:51:35 +00:00
if ( ext ) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( pvt -> exten , ext , sizeof ( pvt -> exten ));
2004-01-11 17:51:35 +00:00
}
2006-09-19 17:07:22 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Extension: %s Host: %s \n " , pvt -> exten , host );
2006-09-19 17:07:22 +00:00
if ( gatekeeper_disable ) {
2004-10-04 10:13:01 +00:00
if ( create_addr ( pvt , host )) {
oh323_destroy ( pvt );
2006-09-19 17:07:22 +00:00
if ( cause )
* cause = AST_CAUSE_DESTINATION_OUT_OF_ORDER ;
2004-10-04 10:13:01 +00:00
return NULL ;
}
2004-09-30 19:36:46 +00:00
}
2005-05-21 17:09:30 +00:00
else {
2005-04-29 04:22:47 +00:00
memcpy ( & pvt -> options , & global_options , sizeof ( pvt -> options ));
2006-09-19 17:07:22 +00:00
pvt -> jointcapability = pvt -> options . capability ;
2005-05-21 17:09:30 +00:00
if ( pvt -> options . dtmfmode ) {
if ( pvt -> options . dtmfmode & H323_DTMF_RFC2833 ) {
pvt -> nonCodecCapability |= AST_RTP_DTMF ;
} else {
pvt -> nonCodecCapability &= ~ AST_RTP_DTMF ;
}
}
}
2004-12-15 23:24:13 +00:00
2004-10-14 05:21:12 +00:00
ast_mutex_lock ( & caplock );
2005-05-11 13:27:49 +00:00
/* Generate unique channel identifier */
snprintf ( tmp1 , sizeof ( tmp1 ) - 1 , "%s-%u" , host , ++ unique );
tmp1 [ sizeof ( tmp1 ) - 1 ] = '\0' ;
2004-10-14 05:21:12 +00:00
ast_mutex_unlock ( & caplock );
2005-05-11 13:27:49 +00:00
2004-10-04 10:13:01 +00:00
ast_mutex_lock ( & pvt -> lock );
2005-05-11 13:27:49 +00:00
tmpc = __oh323_new ( pvt , AST_STATE_DOWN , tmp1 );
2004-10-04 10:13:01 +00:00
ast_mutex_unlock ( & pvt -> lock );
2004-09-30 19:36:46 +00:00
if ( ! tmpc ) {
2004-10-04 10:13:01 +00:00
oh323_destroy ( pvt );
2006-09-19 17:07:22 +00:00
if ( cause )
* cause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE ;
2004-09-30 19:36:46 +00:00
}
ast_update_use_count ();
2003-03-31 07:13:36 +00:00
restart_monitor ();
return tmpc ;
}
2007-02-24 20:29:41 +00:00
/*! \brief Find a call by alias */
2006-09-19 17:07:22 +00:00
static struct oh323_alias * find_alias ( const char * source_aliases , int realtime )
2003-03-31 07:13:36 +00:00
{
2003-12-24 22:38:24 +00:00
struct oh323_alias * a ;
2003-03-31 07:13:36 +00:00
2006-09-19 17:07:22 +00:00
a = ASTOBJ_CONTAINER_FIND ( & aliasl , source_aliases );
if ( ! a && realtime )
a = realtime_alias ( source_aliases );
2003-12-24 22:38:24 +00:00
return a ;
2003-03-31 07:13:36 +00:00
}
2007-02-24 20:29:41 +00:00
/*! \brief
2003-03-31 07:13:36 +00:00
* Callback for sending digits from H.323 up to asterisk
*
*/
2006-09-19 17:07:22 +00:00
static int receive_digit ( unsigned call_reference , char digit , const char * token , int duration )
2003-03-31 07:13:36 +00:00
{
2004-10-04 10:13:01 +00:00
struct oh323_pvt * pvt ;
2005-05-11 13:27:49 +00:00
int res ;
2003-03-31 07:13:36 +00:00
2006-09-19 17:07:22 +00:00
pvt = find_call_locked ( call_reference , token );
2004-10-04 10:13:01 +00:00
if ( ! pvt ) {
2006-09-19 17:07:22 +00:00
ast_log ( LOG_ERROR , "Received digit '%c' (%u ms) for call %s without private structure \n " , digit , duration , token );
2003-03-31 07:13:36 +00:00
return - 1 ;
}
2006-09-19 17:07:22 +00:00
if ( h323debug )
ast_log ( LOG_DTMF , "Received %s digit '%c' (%u ms) for call %s \n " , ( digit == ' ' ? "update for" : "new" ), ( digit == ' ' ? pvt -> curDTMF : digit ), duration , token );
if ( pvt -> owner && ! ast_channel_trylock ( pvt -> owner )) {
if ( digit == '!' )
res = ast_queue_control ( pvt -> owner , AST_CONTROL_FLASH );
else {
struct ast_frame f = {
. frametype = AST_FRAME_DTMF_END ,
. subclass = digit ,
. samples = duration * 8 ,
2007-02-10 09:23:09 +00:00
. len = duration ,
2006-09-19 17:07:22 +00:00
. src = "SEND_DIGIT" ,
};
if ( digit == ' ' ) { /* signalUpdate message */
f . subclass = pvt -> curDTMF ;
2008-01-27 22:35:29 +00:00
AST_SCHED_DEL ( sched , pvt -> DTMFsched );
2006-09-19 17:07:22 +00:00
} else { /* Regular input or signal message */
2007-02-10 09:23:09 +00:00
if ( pvt -> DTMFsched >= 0 ) {
/* We still don't send DTMF END from previous event, send it now */
2008-01-27 22:35:29 +00:00
AST_SCHED_DEL ( sched , pvt -> DTMFsched );
2007-02-10 09:23:09 +00:00
f . subclass = pvt -> curDTMF ;
f . samples = f . len = 0 ;
ast_queue_frame ( pvt -> owner , & f );
/* Restore values */
f . subclass = digit ;
f . samples = duration * 8 ;
f . len = duration ;
}
2006-09-19 17:07:22 +00:00
if ( duration ) { /* This is a signal, signalUpdate follows */
f . frametype = AST_FRAME_DTMF_BEGIN ;
pvt -> DTMFsched = ast_sched_add ( sched , duration , oh323_simulate_dtmf_end , pvt );
if ( h323debug )
ast_log ( LOG_DTMF , "Scheduled DTMF END simulation for %d ms, id=%d \n " , duration , pvt -> DTMFsched );
}
pvt -> curDTMF = digit ;
}
res = ast_queue_frame ( pvt -> owner , & f );
}
ast_channel_unlock ( pvt -> owner );
2006-08-15 14:55:30 +00:00
} else {
2006-09-19 17:07:22 +00:00
if ( digit == '!' )
pvt -> newcontrol = AST_CONTROL_FLASH ;
else {
pvt -> newduration = duration ;
pvt -> newdigit = digit ;
}
2006-08-15 14:55:30 +00:00
res = 0 ;
}
2005-05-11 13:27:49 +00:00
ast_mutex_unlock ( & pvt -> lock );
return res ;
2003-03-31 07:13:36 +00:00
}
2007-02-24 20:29:41 +00:00
/*! \brief
2004-10-10 12:20:18 +00:00
* Callback function used to inform the H.323 stack of the local rtp ip/port details
2003-03-31 07:13:36 +00:00
*
2007-02-24 20:29:41 +00:00
* \return Returns the local RTP information
2003-03-31 07:13:36 +00:00
*/
2006-09-19 17:07:22 +00:00
static struct rtp_info * external_rtp_create ( unsigned call_reference , const char * token )
{
2004-10-04 10:13:01 +00:00
struct oh323_pvt * pvt ;
2003-03-31 07:13:36 +00:00
struct sockaddr_in us ;
2003-08-25 09:54:36 +00:00
struct rtp_info * info ;
2003-03-31 07:13:36 +00:00
2007-06-03 06:10:27 +00:00
info = ast_calloc ( 1 , sizeof ( * info ));
2004-10-10 12:20:18 +00:00
if ( ! info ) {
ast_log ( LOG_ERROR , "Unable to allocated info structure, this is very bad \n " );
return NULL ;
}
2006-09-19 17:07:22 +00:00
pvt = find_call_locked ( call_reference , token );
2004-10-04 10:13:01 +00:00
if ( ! pvt ) {
2007-06-03 06:10:27 +00:00
ast_free ( info );
2004-10-10 12:20:18 +00:00
ast_log ( LOG_ERROR , "Unable to find call %s(%d) \n " , token , call_reference );
2003-08-25 09:54:36 +00:00
return NULL ;
2003-03-31 07:13:36 +00:00
}
2006-09-19 17:07:22 +00:00
if ( ! pvt -> rtp )
__oh323_rtp_create ( pvt );
if ( ! pvt -> rtp ) {
ast_mutex_unlock ( & pvt -> lock );
2007-06-03 06:10:27 +00:00
ast_free ( info );
2006-09-19 17:07:22 +00:00
ast_log ( LOG_ERROR , "No RTP stream is available for call %s (%d)" , token , call_reference );
return NULL ;
}
2004-10-14 05:21:12 +00:00
/* figure out our local RTP port and tell the H.323 stack about it */
2004-10-04 10:13:01 +00:00
ast_rtp_get_us ( pvt -> rtp , & us );
2005-04-04 15:54:34 +00:00
ast_mutex_unlock ( & pvt -> lock );
2005-07-27 04:39:53 +00:00
2006-10-25 14:44:50 +00:00
ast_copy_string ( info -> addr , ast_inet_ntoa ( us . sin_addr ), sizeof ( info -> addr ));
2003-08-25 09:54:36 +00:00
info -> port = ntohs ( us . sin_port );
2005-05-11 13:27:49 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Sending RTP 'US' %s:%d \n " , info -> addr , info -> port );
2003-08-25 09:54:36 +00:00
return info ;
2003-03-31 07:13:36 +00:00
}
2007-06-07 23:07:25 +00:00
/*
2004-12-21 00:07:56 +00:00
* Definition taken from rtp.c for rtpPayloadType because we need it here.
*/
2007-06-07 23:07:25 +00:00
2004-12-21 00:07:56 +00:00
struct rtpPayloadType {
2006-09-19 17:07:22 +00:00
int isAstFormat ; /* whether the following code is an AST_FORMAT */
2004-12-21 00:07:56 +00:00
int code ;
};
2007-02-24 20:29:41 +00:00
/*! \brief
2006-09-19 17:07:22 +00:00
* Call-back function passing remote ip/port information from H.323 to asterisk
2004-10-10 12:20:18 +00:00
*
2006-09-19 17:07:22 +00:00
* Returns nothing
2004-10-10 12:20:18 +00:00
*/
2006-09-19 17:07:22 +00:00
static void setup_rtp_connection ( unsigned call_reference , const char * remoteIp , int remotePort , const char * token , int pt )
2004-10-10 12:20:18 +00:00
{
2005-05-11 13:27:49 +00:00
struct oh323_pvt * pvt ;
2004-10-10 12:20:18 +00:00
struct sockaddr_in them ;
2004-12-21 00:07:56 +00:00
struct rtpPayloadType rtptype ;
2006-09-19 17:07:22 +00:00
int nativeformats_changed ;
enum { NEED_NONE , NEED_HOLD , NEED_UNHOLD } rtp_change = NEED_NONE ;
2004-10-10 12:20:18 +00:00
2005-04-04 15:54:34 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Setting up RTP connection for %s \n " , token );
2005-05-11 13:27:49 +00:00
2004-10-10 12:20:18 +00:00
/* Find the call or allocate a private structure if call not found */
2006-09-19 17:07:22 +00:00
pvt = find_call_locked ( call_reference , token );
2004-10-10 12:20:18 +00:00
if ( ! pvt ) {
ast_log ( LOG_ERROR , "Something is wrong: rtp \n " );
return ;
}
2005-04-04 15:54:34 +00:00
if ( pvt -> alreadygone ) {
ast_mutex_unlock ( & pvt -> lock );
return ;
}
2006-09-19 17:07:22 +00:00
if ( ! pvt -> rtp )
__oh323_rtp_create ( pvt );
2004-12-21 00:07:56 +00:00
2006-09-21 18:48:53 +00:00
if (( pt == 2 ) && ( pvt -> jointcapability & AST_FORMAT_G726_AAL2 )) {
ast_rtp_set_rtpmap_type ( pvt -> rtp , pt , "audio" , "G726-32" , AST_RTP_OPT_G726_NONSTANDARD );
}
2004-10-10 12:20:18 +00:00
them . sin_family = AF_INET ;
2004-10-28 06:06:58 +00:00
/* only works for IPv4 */
2006-09-19 17:07:22 +00:00
them . sin_addr . s_addr = inet_addr ( remoteIp );
2004-10-10 12:20:18 +00:00
them . sin_port = htons ( remotePort );
2004-12-15 23:24:13 +00:00
2006-09-19 17:07:22 +00:00
if ( them . sin_addr . s_addr ) {
ast_rtp_set_peer ( pvt -> rtp , & them );
if ( pvt -> recvonly ) {
pvt -> recvonly = 0 ;
rtp_change = NEED_UNHOLD ;
}
} else {
ast_rtp_stop ( pvt -> rtp );
if ( ! pvt -> recvonly ) {
pvt -> recvonly = 1 ;
rtp_change = NEED_HOLD ;
}
}
/* Change native format to reflect information taken from OLC/OLCAck */
nativeformats_changed = 0 ;
if ( pt != 128 && pvt -> rtp ) { /* Payload type is invalid, so try to use previously decided */
rtptype = ast_rtp_lookup_pt ( pvt -> rtp , pt );
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Native format is set to %d from %d by RTP payload type %d \n " , rtptype . code , pvt -> nativeformats , pt );
2006-09-19 17:07:22 +00:00
if ( pvt -> nativeformats != rtptype . code ) {
pvt -> nativeformats = rtptype . code ;
nativeformats_changed = 1 ;
}
} else if ( h323debug )
ast_log ( LOG_NOTICE , "Payload type is unknown, formats isn't changed \n " );
/* Don't try to lock the channel if nothing changed */
if ( nativeformats_changed || pvt -> options . progress_audio || ( rtp_change != NEED_NONE )) {
if ( pvt -> owner && ! ast_channel_trylock ( pvt -> owner )) {
/* Re-build translation path only if native format(s) has been changed */
if ( pvt -> owner -> nativeformats != pvt -> nativeformats ) {
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Native format changed to %d from %d, read format is %d, write format is %d \n " , pvt -> nativeformats , pvt -> owner -> nativeformats , pvt -> owner -> readformat , pvt -> owner -> writeformat );
2006-09-19 17:07:22 +00:00
pvt -> owner -> nativeformats = pvt -> nativeformats ;
ast_set_read_format ( pvt -> owner , pvt -> owner -> readformat );
ast_set_write_format ( pvt -> owner , pvt -> owner -> writeformat );
}
if ( pvt -> options . progress_audio )
ast_queue_control ( pvt -> owner , AST_CONTROL_PROGRESS );
switch ( rtp_change ) {
case NEED_HOLD :
ast_queue_control ( pvt -> owner , AST_CONTROL_HOLD );
break ;
case NEED_UNHOLD :
ast_queue_control ( pvt -> owner , AST_CONTROL_UNHOLD );
break ;
default :
break ;
}
ast_channel_unlock ( pvt -> owner );
}
else {
if ( pvt -> options . progress_audio )
pvt -> newcontrol = AST_CONTROL_PROGRESS ;
else if ( rtp_change == NEED_HOLD )
pvt -> newcontrol = AST_CONTROL_HOLD ;
else if ( rtp_change == NEED_UNHOLD )
pvt -> newcontrol = AST_CONTROL_UNHOLD ;
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "RTP connection preparation for %s is pending... \n " , token );
2006-09-19 17:07:22 +00:00
}
}
2005-07-27 04:45:11 +00:00
ast_mutex_unlock ( & pvt -> lock );
2005-04-04 15:54:34 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "RTP connection prepared for %s \n " , token );
2004-12-21 00:07:56 +00:00
2004-10-10 12:20:18 +00:00
return ;
}
2007-02-24 20:29:41 +00:00
/*! \brief
2006-09-19 17:07:22 +00:00
* Call-back function to signal asterisk that the channel has been answered
2004-10-10 12:20:18 +00:00
* Returns nothing
*/
2006-09-19 17:07:22 +00:00
static void connection_made ( unsigned call_reference , const char * token )
2004-10-10 12:20:18 +00:00
{
2005-05-11 13:27:49 +00:00
struct oh323_pvt * pvt ;
2005-04-04 15:54:34 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Call %s answered \n " , token );
2005-05-11 13:27:49 +00:00
2006-09-19 17:07:22 +00:00
pvt = find_call_locked ( call_reference , token );
2004-10-10 12:20:18 +00:00
if ( ! pvt ) {
ast_log ( LOG_ERROR , "Something is wrong: connection \n " );
return ;
}
2005-04-04 15:54:34 +00:00
/* Inform asterisk about remote party connected only on outgoing calls */
if ( ! pvt -> outgoing ) {
ast_mutex_unlock ( & pvt -> lock );
return ;
}
2006-09-19 17:07:22 +00:00
/* Do not send ANSWER message more than once */
if ( ! pvt -> connection_established ) {
pvt -> connection_established = 1 ;
update_state ( pvt , - 1 , AST_CONTROL_ANSWER );
}
2005-04-04 15:54:34 +00:00
ast_mutex_unlock ( & pvt -> lock );
2004-10-10 12:20:18 +00:00
return ;
}
2006-09-19 17:07:22 +00:00
static int progress ( unsigned call_reference , const char * token , int inband )
2004-12-15 23:24:13 +00:00
{
2005-05-11 13:27:49 +00:00
struct oh323_pvt * pvt ;
2004-12-15 23:24:13 +00:00
2006-09-19 17:07:22 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Received ALERT/PROGRESS message for %s tones \n " , ( inband ? "inband" : "self-generated" ));
2004-12-15 23:24:13 +00:00
2005-05-11 13:27:49 +00:00
pvt = find_call_locked ( call_reference , token );
if ( ! pvt ) {
2004-12-15 23:24:13 +00:00
ast_log ( LOG_ERROR , "Private structure not found in progress. \n " );
return - 1 ;
}
2005-05-11 13:27:49 +00:00
if ( ! pvt -> owner ) {
ast_mutex_unlock ( & pvt -> lock );
2004-12-15 23:24:13 +00:00
ast_log ( LOG_ERROR , "No Asterisk channel associated with private structure. \n " );
return - 1 ;
}
2006-09-19 17:07:22 +00:00
update_state ( pvt , - 1 , ( inband ? AST_CONTROL_PROGRESS : AST_CONTROL_RINGING ));
2005-05-11 13:27:49 +00:00
ast_mutex_unlock ( & pvt -> lock );
2004-12-15 23:24:13 +00:00
return 0 ;
}
2007-02-24 20:29:41 +00:00
/*! \brief
2003-03-31 07:13:36 +00:00
* Call-back function for incoming calls
*
* Returns 1 on success
*/
2006-09-19 17:07:22 +00:00
static call_options_t * setup_incoming_call ( call_details_t * cd )
2003-03-31 07:13:36 +00:00
{
2005-05-11 13:27:49 +00:00
struct oh323_pvt * pvt ;
2003-03-31 07:13:36 +00:00
struct oh323_user * user = NULL ;
struct oh323_alias * alias = NULL ;
2005-04-04 15:54:34 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Setting up incoming call for %s \n " , cd -> call_token );
2005-04-04 15:54:34 +00:00
2003-03-31 07:13:36 +00:00
/* allocate the call*/
2005-05-19 16:17:08 +00:00
pvt = oh323_alloc ( cd -> call_reference );
2003-03-31 07:13:36 +00:00
2004-10-04 10:13:01 +00:00
if ( ! pvt ) {
2003-03-31 07:13:36 +00:00
ast_log ( LOG_ERROR , "Unable to allocate private structure, this is bad. \n " );
2006-09-19 17:07:22 +00:00
cleanup_call_details ( cd );
2004-12-15 23:24:13 +00:00
return NULL ;
2003-03-31 07:13:36 +00:00
}
/* Populate the call details in the private structure */
2005-05-19 16:17:08 +00:00
memcpy ( & pvt -> cd , cd , sizeof ( pvt -> cd ));
memcpy ( & pvt -> options , & global_options , sizeof ( pvt -> options ));
2006-09-19 17:07:22 +00:00
pvt -> jointcapability = pvt -> options . capability ;
2003-03-31 07:13:36 +00:00
if ( h323debug ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , "Setting up Call \n " );
ast_verb ( 3 , " \t Call token: [%s] \n " , pvt -> cd . call_token );
ast_verb ( 3 , " \t Calling party name: [%s] \n " , pvt -> cd . call_source_name );
ast_verb ( 3 , " \t Calling party number: [%s] \n " , pvt -> cd . call_source_e164 );
ast_verb ( 3 , " \t Called party name: [%s] \n " , pvt -> cd . call_dest_alias );
ast_verb ( 3 , " \t Called party number: [%s] \n " , pvt -> cd . call_dest_e164 );
2006-09-19 17:07:22 +00:00
if ( pvt -> cd . redirect_reason >= 0 )
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " \t Redirecting party number: [%s] (reason %d) \n " , pvt -> cd . redirect_number , pvt -> cd . redirect_reason );
ast_verb ( 3 , " \t Calling party IP: [%s] \n " , pvt -> cd . sourceIp );
2003-03-31 07:13:36 +00:00
}
/* Decide if we are allowing Gatekeeper routed calls*/
2006-09-19 17:07:22 +00:00
if (( ! strcasecmp ( cd -> sourceIp , gatekeeper )) && ( gkroute == - 1 ) && ! gatekeeper_disable ) {
2005-05-19 16:17:08 +00:00
if ( ! ast_strlen_zero ( cd -> call_dest_e164 )) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( pvt -> exten , cd -> call_dest_e164 , sizeof ( pvt -> exten ));
ast_copy_string ( pvt -> context , default_context , sizeof ( pvt -> context ));
2003-03-31 07:13:36 +00:00
} else {
2006-09-19 17:07:22 +00:00
alias = find_alias ( cd -> call_dest_alias , 1 );
2003-03-31 07:13:36 +00:00
if ( ! alias ) {
2005-05-19 16:17:08 +00:00
ast_log ( LOG_ERROR , "Call for %s rejected, alias not found \n " , cd -> call_dest_alias );
2006-09-19 17:07:22 +00:00
oh323_destroy ( pvt );
2004-12-15 23:24:13 +00:00
return NULL ;
2003-03-31 07:13:36 +00:00
}
2006-10-25 14:44:50 +00:00
ast_copy_string ( pvt -> exten , alias -> name , sizeof ( pvt -> exten ));
ast_copy_string ( pvt -> context , alias -> context , sizeof ( pvt -> context ));
2003-03-31 07:13:36 +00:00
}
2005-05-11 13:27:49 +00:00
} else {
2006-09-19 17:07:22 +00:00
/* Either this call is not from the Gatekeeper
2003-03-31 07:13:36 +00:00
or we are not allowing gk routed calls */
2006-09-19 17:07:22 +00:00
user = find_user ( cd , 1 );
2003-03-31 07:13:36 +00:00
if ( ! user ) {
2006-09-19 17:07:22 +00:00
if ( ! acceptAnonymous ) {
ast_log ( LOG_NOTICE , "Anonymous call from '%s@%s' rejected \n " , pvt -> cd . call_source_aliases , pvt -> cd . sourceIp );
oh323_destroy ( pvt );
return NULL ;
2003-03-31 07:13:36 +00:00
}
2004-05-03 22:19:03 +00:00
if ( ast_strlen_zero ( default_context )) {
2006-09-19 17:07:22 +00:00
ast_log ( LOG_ERROR , "Call from '%s@%s' rejected due to no default context \n " , pvt -> cd . call_source_aliases , pvt -> cd . sourceIp );
oh323_destroy ( pvt );
2004-12-15 23:24:13 +00:00
return NULL ;
2003-03-31 07:13:36 +00:00
}
2006-10-25 14:44:50 +00:00
ast_copy_string ( pvt -> context , default_context , sizeof ( pvt -> context ));
2006-09-19 17:07:22 +00:00
if ( ! ast_strlen_zero ( pvt -> cd . call_dest_e164 )) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( pvt -> exten , cd -> call_dest_e164 , sizeof ( pvt -> exten ));
2006-09-19 17:07:22 +00:00
} else {
2006-10-25 14:44:50 +00:00
ast_copy_string ( pvt -> exten , cd -> call_dest_alias , sizeof ( pvt -> exten ));
2006-09-19 17:07:22 +00:00
}
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Sending %s@%s to context [%s] extension %s \n " , cd -> call_source_aliases , cd -> sourceIp , pvt -> context , pvt -> exten );
2005-05-19 16:17:08 +00:00
} else {
2003-03-31 20:26:08 +00:00
if ( user -> host ) {
2006-09-19 17:07:22 +00:00
if ( strcasecmp ( cd -> sourceIp , ast_inet_ntoa ( user -> addr . sin_addr ))) {
2004-05-20 21:56:12 +00:00
if ( ast_strlen_zero ( user -> context )) {
2005-05-11 13:27:49 +00:00
if ( ast_strlen_zero ( default_context )) {
2005-05-19 16:17:08 +00:00
ast_log ( LOG_ERROR , "Call from '%s' rejected due to non-matching IP address (%s) and no default context \n " , user -> name , cd -> sourceIp );
2006-09-19 17:07:22 +00:00
oh323_destroy ( pvt );
ASTOBJ_UNREF ( user , oh323_destroy_user );
return NULL ;
2004-05-20 21:56:12 +00:00
}
2006-10-25 14:44:50 +00:00
ast_copy_string ( pvt -> context , default_context , sizeof ( pvt -> context ));
2004-05-20 21:56:12 +00:00
} else {
2006-10-25 14:44:50 +00:00
ast_copy_string ( pvt -> context , user -> context , sizeof ( pvt -> context ));
2003-04-11 20:28:25 +00:00
}
2004-10-04 10:13:01 +00:00
pvt -> exten [ 0 ] = 'i' ;
pvt -> exten [ 1 ] = '\0' ;
2005-05-19 16:17:08 +00:00
ast_log ( LOG_ERROR , "Call from '%s' rejected due to non-matching IP address (%s)s \n " , user -> name , cd -> sourceIp );
2006-09-19 17:07:22 +00:00
oh323_destroy ( pvt );
ASTOBJ_UNREF ( user , oh323_destroy_user );
2005-05-19 16:17:08 +00:00
return NULL ; /* XXX: Hmmm... Why to setup context if we drop connection immediately??? */
2003-03-31 20:26:08 +00:00
}
2003-03-31 19:26:15 +00:00
}
2006-10-25 14:44:50 +00:00
ast_copy_string ( pvt -> context , user -> context , sizeof ( pvt -> context ));
2005-05-11 13:27:49 +00:00
memcpy ( & pvt -> options , & user -> options , sizeof ( pvt -> options ));
2006-09-19 17:07:22 +00:00
pvt -> jointcapability = pvt -> options . capability ;
2004-10-04 10:13:01 +00:00
if ( ! ast_strlen_zero ( pvt -> cd . call_dest_e164 )) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( pvt -> exten , cd -> call_dest_e164 , sizeof ( pvt -> exten ));
2003-03-31 07:13:36 +00:00
} else {
2006-10-25 14:44:50 +00:00
ast_copy_string ( pvt -> exten , cd -> call_dest_alias , sizeof ( pvt -> exten ));
2003-03-31 07:13:36 +00:00
}
2004-05-03 22:19:03 +00:00
if ( ! ast_strlen_zero ( user -> accountcode )) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( pvt -> accountcode , user -> accountcode , sizeof ( pvt -> accountcode ));
2006-09-19 17:07:22 +00:00
}
2004-10-22 19:04:02 +00:00
if ( user -> amaflags ) {
pvt -> amaflags = user -> amaflags ;
2006-09-19 17:07:22 +00:00
}
ASTOBJ_UNREF ( user , oh323_destroy_user );
}
2003-03-31 07:13:36 +00:00
}
2005-05-11 13:27:49 +00:00
return & pvt -> options ;
2004-06-15 20:56:06 +00:00
}
2003-03-31 07:13:36 +00:00
2007-02-24 20:29:41 +00:00
/*! \brief
2004-06-15 20:56:06 +00:00
* Call-back function to start PBX when OpenH323 ready to serve incoming call
*
* Returns 1 on success
*/
2004-09-19 16:53:01 +00:00
static int answer_call ( unsigned call_reference , const char * token )
2004-06-15 20:56:06 +00:00
{
2005-05-11 13:27:49 +00:00
struct oh323_pvt * pvt ;
2004-06-15 20:56:06 +00:00
struct ast_channel * c = NULL ;
2006-09-19 17:07:22 +00:00
enum { ext_original , ext_s , ext_i , ext_notexists } try_exten ;
char tmp_exten [ sizeof ( pvt -> exten )];
2004-09-19 16:53:01 +00:00
2005-04-04 15:54:34 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Preparing Asterisk to answer for %s \n " , token );
2005-04-04 15:54:34 +00:00
2004-06-15 20:56:06 +00:00
/* Find the call or allocate a private structure if call not found */
2006-09-19 17:07:22 +00:00
pvt = find_call_locked ( call_reference , token );
2004-10-04 10:13:01 +00:00
if ( ! pvt ) {
2004-06-15 20:56:06 +00:00
ast_log ( LOG_ERROR , "Something is wrong: answer_call \n " );
return 0 ;
}
2006-09-19 17:07:22 +00:00
/* Check if requested extension@context pair exists in the dialplan */
2006-10-25 14:44:50 +00:00
ast_copy_string ( tmp_exten , pvt -> exten , sizeof ( tmp_exten ));
2006-09-19 17:07:22 +00:00
/* Try to find best extension in specified context */
if (( tmp_exten [ 0 ] != '\0' ) && ( tmp_exten [ 1 ] == '\0' )) {
if ( tmp_exten [ 0 ] == 's' )
try_exten = ext_s ;
else if ( tmp_exten [ 0 ] == 'i' )
try_exten = ext_i ;
else
try_exten = ext_original ;
} else
try_exten = ext_original ;
do {
if ( ast_exists_extension ( NULL , pvt -> context , tmp_exten , 1 , NULL ))
break ;
switch ( try_exten ) {
case ext_original :
tmp_exten [ 0 ] = 's' ;
tmp_exten [ 1 ] = '\0' ;
try_exten = ext_s ;
break ;
case ext_s :
tmp_exten [ 0 ] = 'i' ;
try_exten = ext_i ;
break ;
case ext_i :
try_exten = ext_notexists ;
break ;
default :
break ;
}
} while ( try_exten != ext_notexists );
/* Drop the call if we don't have <exten>, s and i extensions */
if ( try_exten == ext_notexists ) {
ast_log ( LOG_NOTICE , "Dropping call because extensions '%s', 's' and 'i' doesn't exists in context [%s] \n " , pvt -> exten , pvt -> context );
ast_mutex_unlock ( & pvt -> lock );
h323_clear_call ( token , AST_CAUSE_UNALLOCATED );
return 0 ;
} else if (( try_exten != ext_original ) && ( strcmp ( pvt -> exten , tmp_exten ) != 0 )) {
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Going to extension %s@%s because %s@%s isn't exists \n " , tmp_exten , pvt -> context , pvt -> exten , pvt -> context );
2006-10-25 14:44:50 +00:00
ast_copy_string ( pvt -> exten , tmp_exten , sizeof ( pvt -> exten ));
2006-09-19 17:07:22 +00:00
}
2004-06-15 20:56:06 +00:00
/* allocate a channel and tell asterisk about it */
2005-05-11 13:27:49 +00:00
c = __oh323_new ( pvt , AST_STATE_RINGING , pvt -> cd . call_token );
2005-02-09 21:15:44 +00:00
/* And release when done */
ast_mutex_unlock ( & pvt -> lock );
2004-06-15 20:56:06 +00:00
if ( ! c ) {
ast_log ( LOG_ERROR , "Couldn't create channel. This is bad \n " );
return 0 ;
}
2003-12-24 22:38:24 +00:00
return 1 ;
2003-03-31 07:13:36 +00:00
}
2007-02-24 20:29:41 +00:00
/*! \brief
2003-03-31 07:13:36 +00:00
* Call-back function to establish an outgoing H.323 call
2006-09-19 17:07:22 +00:00
*
* Returns 1 on success
2003-03-31 07:13:36 +00:00
*/
2006-09-19 17:07:22 +00:00
static int setup_outgoing_call ( call_details_t * cd )
2005-05-19 16:17:08 +00:00
{
/* Use argument here or free it immediately */
cleanup_call_details ( cd );
2003-03-31 07:13:36 +00:00
return 1 ;
}
2007-02-24 20:29:41 +00:00
/*! \brief
2004-05-20 07:07:18 +00:00
* Call-back function to signal asterisk that the channel is ringing
* Returns nothing
*/
2006-09-19 17:07:22 +00:00
static void chan_ringing ( unsigned call_reference , const char * token )
2004-05-20 07:07:18 +00:00
{
2005-05-19 16:17:08 +00:00
struct oh323_pvt * pvt ;
2004-05-20 07:07:18 +00:00
2005-04-04 15:54:34 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Ringing on %s \n " , token );
2005-04-04 15:54:34 +00:00
2006-09-19 17:07:22 +00:00
pvt = find_call_locked ( call_reference , token );
2005-07-27 04:45:11 +00:00
if ( ! pvt ) {
ast_log ( LOG_ERROR , "Something is wrong: ringing \n " );
return ;
2004-05-20 07:07:18 +00:00
}
2005-05-19 16:17:08 +00:00
if ( ! pvt -> owner ) {
ast_mutex_unlock ( & pvt -> lock );
ast_log ( LOG_ERROR , "Channel has no owner \n " );
return ;
}
2006-09-19 17:07:22 +00:00
update_state ( pvt , AST_STATE_RINGING , AST_CONTROL_RINGING );
2005-05-19 16:17:08 +00:00
ast_mutex_unlock ( & pvt -> lock );
return ;
2004-05-20 07:07:18 +00:00
}
2007-02-24 20:29:41 +00:00
/*! \brief
2003-03-31 07:13:36 +00:00
* Call-back function to cleanup communication
* Returns nothing,
*/
2005-05-19 16:17:08 +00:00
static void cleanup_connection ( unsigned call_reference , const char * call_token )
2006-09-19 17:07:22 +00:00
{
2005-05-11 13:27:49 +00:00
struct oh323_pvt * pvt ;
2005-04-04 15:54:34 +00:00
2006-09-19 17:07:22 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Cleaning connection to %s \n " , call_token );
2006-09-19 17:07:22 +00:00
2005-04-04 15:54:34 +00:00
while ( 1 ) {
2006-09-19 17:07:22 +00:00
pvt = find_call_locked ( call_reference , call_token );
2005-04-04 15:54:34 +00:00
if ( ! pvt ) {
2005-05-11 13:27:49 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "No connection for %s \n " , call_token );
2005-04-04 15:54:34 +00:00
return ;
}
2006-09-19 17:07:22 +00:00
if ( ! pvt -> owner || ! ast_channel_trylock ( pvt -> owner ))
2005-04-04 15:54:34 +00:00
break ;
#if 1
2005-05-19 16:17:08 +00:00
ast_log ( LOG_NOTICE , "Avoiding H.323 destory deadlock on %s \n " , call_token );
2007-11-24 13:57:46 +00:00
#ifdef DEBUG_THREADS
/* XXX to be completed
* If we want to print more info on who is holding the lock,
* implement the relevant code in lock.h and use the routines
* supplied there.
*/
2005-04-04 15:54:34 +00:00
#endif
#endif
ast_mutex_unlock ( & pvt -> lock );
usleep ( 1 );
2003-03-31 07:13:36 +00:00
}
2004-10-04 10:13:01 +00:00
if ( pvt -> rtp ) {
2003-03-31 07:13:36 +00:00
/* Immediately stop RTP */
2005-05-19 16:17:08 +00:00
ast_rtp_destroy ( pvt -> rtp );
pvt -> rtp = NULL ;
2003-03-31 07:13:36 +00:00
}
2005-04-04 15:54:34 +00:00
/* Free dsp used for in-band DTMF detection */
if ( pvt -> vad ) {
ast_dsp_free ( pvt -> vad );
pvt -> vad = NULL ;
}
cleanup_call_details ( & pvt -> cd );
2004-10-04 10:13:01 +00:00
pvt -> alreadygone = 1 ;
2006-09-19 17:07:22 +00:00
/* Send hangup */
2004-10-04 10:13:01 +00:00
if ( pvt -> owner ) {
2005-04-04 15:54:34 +00:00
pvt -> owner -> _softhangup |= AST_SOFTHANGUP_DEV ;
2008-05-22 16:29:54 +00:00
ast_queue_hangup ( pvt -> owner );
2006-09-19 17:07:22 +00:00
ast_channel_unlock ( pvt -> owner );
2005-04-04 15:54:34 +00:00
}
2004-10-04 10:13:01 +00:00
ast_mutex_unlock ( & pvt -> lock );
2005-05-11 13:27:49 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Connection to %s cleaned \n " , call_token );
2006-09-19 17:07:22 +00:00
return ;
2003-03-31 07:13:36 +00:00
}
2005-04-04 15:54:34 +00:00
static void hangup_connection ( unsigned int call_reference , const char * token , int cause )
{
2005-05-11 13:27:49 +00:00
struct oh323_pvt * pvt ;
2005-04-04 15:54:34 +00:00
2007-06-14 19:39:12 +00:00
if ( h323debug )
ast_debug ( 1 , "Hanging up connection to %s with cause %d \n " , token , cause );
2006-09-19 17:07:22 +00:00
pvt = find_call_locked ( call_reference , token );
2005-04-04 15:54:34 +00:00
if ( ! pvt ) {
2007-06-14 19:39:12 +00:00
if ( h323debug )
ast_debug ( 1 , "Connection to %s already cleared \n " , token );
2005-04-04 15:54:34 +00:00
return ;
}
2006-09-19 17:07:22 +00:00
if ( pvt -> owner && ! ast_channel_trylock ( pvt -> owner )) {
2005-04-04 15:54:34 +00:00
pvt -> owner -> _softhangup |= AST_SOFTHANGUP_DEV ;
pvt -> owner -> hangupcause = pvt -> hangupcause = cause ;
2008-05-22 16:29:54 +00:00
ast_queue_hangup_with_cause ( pvt -> owner , cause );
2006-09-19 17:07:22 +00:00
ast_channel_unlock ( pvt -> owner );
2005-04-04 15:54:34 +00:00
}
else {
pvt -> needhangup = 1 ;
pvt -> hangupcause = cause ;
2006-09-19 17:07:22 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Hangup for %s is pending \n " , token );
2005-04-04 15:54:34 +00:00
}
ast_mutex_unlock ( & pvt -> lock );
}
2006-09-25 09:03:14 +00:00
static void set_dtmf_payload ( unsigned call_reference , const char * token , int payload , int is_cisco )
2004-12-15 23:24:13 +00:00
{
2005-05-11 13:27:49 +00:00
struct oh323_pvt * pvt ;
2004-12-15 23:24:13 +00:00
2005-04-04 15:54:34 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Setting %s DTMF payload to %d on %s \n " , ( is_cisco ? "Cisco" : "RFC2833" ), payload , token );
2005-04-04 15:54:34 +00:00
2005-05-11 13:27:49 +00:00
pvt = find_call_locked ( call_reference , token );
2004-12-15 23:24:13 +00:00
if ( ! pvt ) {
return ;
}
if ( pvt -> rtp ) {
2006-09-25 09:03:14 +00:00
ast_rtp_set_rtpmap_type ( pvt -> rtp , payload , "audio" , ( is_cisco ? "cisco-telephone-event" : "telephone-event" ), 0 );
2004-12-15 23:24:13 +00:00
}
2006-09-25 09:03:14 +00:00
pvt -> dtmf_pt [ is_cisco ? 1 : 0 ] = payload ;
2004-12-15 23:24:13 +00:00
ast_mutex_unlock ( & pvt -> lock );
2005-04-04 15:54:34 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "DTMF payload on %s set to %d \n " , token , payload );
2004-12-15 23:24:13 +00:00
}
2006-09-20 16:24:00 +00:00
static void set_peer_capabilities ( unsigned call_reference , const char * token , int capabilities , struct ast_codec_pref * prefs )
2006-09-19 17:07:22 +00:00
{
struct oh323_pvt * pvt ;
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Got remote capabilities from connection %s \n " , token );
2006-09-19 17:07:22 +00:00
pvt = find_call_locked ( call_reference , token );
if ( ! pvt )
return ;
pvt -> peercapability = capabilities ;
pvt -> jointcapability = pvt -> options . capability & capabilities ;
2006-09-20 16:24:00 +00:00
if ( prefs ) {
memcpy ( & pvt -> peer_prefs , prefs , sizeof ( pvt -> peer_prefs ));
if ( h323debug ) {
int i ;
for ( i = 0 ; i < 32 ; ++ i ) {
2007-02-10 09:23:09 +00:00
if ( ! prefs -> order [ i ])
break ;
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "prefs[%d]=%s:%d \n " , i , ( prefs -> order [ i ] ? ast_getformatname ( 1 << ( prefs -> order [ i ] - 1 )) : "<none>" ), prefs -> framing [ i ]);
2006-09-20 16:24:00 +00:00
}
}
if ( pvt -> rtp )
ast_rtp_codec_setpref ( pvt -> rtp , & pvt -> peer_prefs );
}
2006-09-19 17:07:22 +00:00
ast_mutex_unlock ( & pvt -> lock );
}
2005-05-19 19:13:19 +00:00
static void set_local_capabilities ( unsigned call_reference , const char * token )
{
struct oh323_pvt * pvt ;
2006-09-19 17:07:22 +00:00
int capability , dtmfmode , pref_codec ;
struct ast_codec_pref prefs ;
2005-05-19 19:13:19 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Setting capabilities for connection %s \n " , token );
2005-05-19 19:13:19 +00:00
pvt = find_call_locked ( call_reference , token );
if ( ! pvt )
return ;
2006-09-19 17:07:22 +00:00
capability = ( pvt -> jointcapability ) ? pvt -> jointcapability : pvt -> options . capability ;
2005-05-21 17:09:30 +00:00
dtmfmode = pvt -> options . dtmfmode ;
2006-09-19 17:07:22 +00:00
prefs = pvt -> options . prefs ;
pref_codec = pvt -> pref_codec ;
2005-05-19 19:13:19 +00:00
ast_mutex_unlock ( & pvt -> lock );
2006-09-19 17:07:22 +00:00
h323_set_capabilities ( token , capability , dtmfmode , & prefs , pref_codec );
2005-05-19 19:13:19 +00:00
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Capabilities for connection %s is set \n " , token );
2005-05-19 19:13:19 +00:00
}
2006-09-28 10:41:38 +00:00
static void remote_hold ( unsigned call_reference , const char * token , int is_hold )
{
struct oh323_pvt * pvt ;
if ( h323debug )
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , "Setting %shold status for connection %s \n " , ( is_hold ? "" : "un" ), token );
2006-09-28 10:41:38 +00:00
pvt = find_call_locked ( call_reference , token );
if ( ! pvt )
return ;
if ( pvt -> owner && ! ast_channel_trylock ( pvt -> owner )) {
if ( is_hold )
ast_queue_control ( pvt -> owner , AST_CONTROL_HOLD );
else
ast_queue_control ( pvt -> owner , AST_CONTROL_UNHOLD );
ast_channel_unlock ( pvt -> owner );
}
else {
if ( is_hold )
pvt -> newcontrol = AST_CONTROL_HOLD ;
else
pvt -> newcontrol = AST_CONTROL_UNHOLD ;
}
ast_mutex_unlock ( & pvt -> lock );
}
2003-03-31 07:13:36 +00:00
static void * do_monitor ( void * data )
{
int res ;
2004-10-15 07:07:50 +00:00
int reloading ;
2003-03-31 07:13:36 +00:00
struct oh323_pvt * oh323 = NULL ;
2006-09-19 17:07:22 +00:00
2004-10-22 19:04:02 +00:00
for (;;) {
2005-05-19 16:17:08 +00:00
/* Check for a reload request */
ast_mutex_lock ( & h323_reload_lock );
reloading = h323_reloading ;
h323_reloading = 0 ;
ast_mutex_unlock ( & h323_reload_lock );
if ( reloading ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 1 , "Reloading H.323 \n " );
2005-05-19 16:17:08 +00:00
h323_do_reload ();
}
2003-03-31 07:13:36 +00:00
/* Check for interfaces needing to be killed */
2006-09-23 18:28:23 +00:00
if ( ! ast_mutex_trylock ( & iflock )) {
2006-09-19 17:07:22 +00:00
#if 1
2006-09-23 18:28:23 +00:00
do {
for ( oh323 = iflist ; oh323 ; oh323 = oh323 -> next ) {
if ( ! ast_mutex_trylock ( & oh323 -> lock )) {
if ( oh323 -> needdestroy ) {
__oh323_destroy ( oh323 );
break ;
}
ast_mutex_unlock ( & oh323 -> lock );
}
}
} while ( /*oh323*/ 0 );
#else
restartsearch :
oh323 = iflist ;
while ( oh323 ) {
2006-09-19 17:07:22 +00:00
if ( ! ast_mutex_trylock ( & oh323 -> lock )) {
if ( oh323 -> needdestroy ) {
__oh323_destroy ( oh323 );
2006-09-23 18:28:23 +00:00
goto restartsearch ;
2006-09-19 17:07:22 +00:00
}
ast_mutex_unlock ( & oh323 -> lock );
2006-09-23 18:28:23 +00:00
oh323 = oh323 -> next ;
2006-09-19 17:07:22 +00:00
}
}
#endif
2006-09-23 18:28:23 +00:00
ast_mutex_unlock ( & iflock );
} else
oh323 = ( struct oh323_pvt * ) 1 ; /* Force fast loop */
2004-10-15 07:07:50 +00:00
pthread_testcancel ();
2003-03-31 07:13:36 +00:00
/* Wait for sched or io */
res = ast_sched_wait ( sched );
2004-10-15 07:07:50 +00:00
if (( res < 0 ) || ( res > 1000 )) {
2003-03-31 07:13:36 +00:00
res = 1000 ;
2004-10-15 07:07:50 +00:00
}
2006-09-19 17:07:22 +00:00
/* Do not wait if some channel(s) is destroyed, probably, more available too */
if ( oh323 )
res = 1 ;
2003-03-31 07:13:36 +00:00
res = ast_io_wait ( io , res );
2005-04-04 15:54:34 +00:00
pthread_testcancel ();
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & monlock );
2004-10-15 07:07:50 +00:00
if ( res >= 0 ) {
2003-03-31 07:13:36 +00:00
ast_sched_runq ( sched );
2004-10-15 07:07:50 +00:00
}
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & monlock );
2003-03-31 07:13:36 +00:00
}
/* Never reached */
return NULL ;
}
static int restart_monitor ( void )
{
/* If we're supposed to be stopped -- stay stopped */
2003-08-14 06:56:11 +00:00
if ( ast_mutex_lock ( & monlock )) {
2003-03-31 07:13:36 +00:00
ast_log ( LOG_WARNING , "Unable to lock monitor \n " );
return - 1 ;
}
2006-09-19 17:07:22 +00:00
if ( monitor_thread == AST_PTHREADT_STOP ) {
ast_mutex_unlock ( & monlock );
return 0 ;
}
2003-03-31 07:13:36 +00:00
if ( monitor_thread == pthread_self ()) {
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & monlock );
2003-03-31 07:13:36 +00:00
ast_log ( LOG_WARNING , "Cannot kill myself \n " );
return - 1 ;
}
2004-03-15 09:14:16 +00:00
if ( monitor_thread && ( monitor_thread != AST_PTHREADT_NULL )) {
2003-03-31 07:13:36 +00:00
/* Wake up the thread */
pthread_kill ( monitor_thread , SIGURG );
2006-09-19 17:07:22 +00:00
} else {
/* Start a new monitor */
2007-05-24 18:30:19 +00:00
if ( ast_pthread_create_detached_background ( & monitor_thread , NULL , do_monitor , NULL ) < 0 ) {
2006-09-19 17:07:22 +00:00
monitor_thread = AST_PTHREADT_NULL ;
ast_mutex_unlock ( & monlock );
ast_log ( LOG_ERROR , "Unable to start monitor thread. \n " );
return - 1 ;
}
2003-03-31 07:13:36 +00:00
}
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & monlock );
2003-03-31 07:13:36 +00:00
return 0 ;
}
2007-10-19 18:01:00 +00:00
static char * handle_cli_h323_set_trace ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
{
switch ( cmd ) {
case CLI_INIT :
2008-09-28 23:32:14 +00:00
e -> command = "h323 set trace [on|off]" ;
2007-10-19 18:01:00 +00:00
e -> usage =
2008-09-28 23:32:14 +00:00
"Usage: h323 set trace (on|off|<trace level>) \n "
2007-10-19 18:01:00 +00:00
" Enable/Disable H.323 stack tracing for debugging purposes \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
2004-01-11 02:20:01 +00:00
}
2003-03-31 07:13:36 +00:00
2008-09-28 23:32:14 +00:00
if ( a -> argc != e -> args )
2007-10-19 18:01:00 +00:00
return CLI_SHOWUSAGE ;
if ( ! strcasecmp ( a -> argv [ 3 ], "off" )) {
h323_debug ( 0 , 0 );
ast_cli ( a -> fd , "H.323 Trace Disabled \n " );
2008-10-09 17:01:24 +00:00
} else if ( ! strcasecmp ( a -> argv [ 3 ], "on" )) {
h323_debug ( 1 , 1 );
ast_cli ( a -> fd , "H.323 Trace Enabled \n " );
2007-10-19 18:01:00 +00:00
} else {
int tracelevel = atoi ( a -> argv [ 3 ]);
h323_debug ( 1 , tracelevel );
ast_cli ( a -> fd , "H.323 Trace Enabled (Trace Level: %d) \n " , tracelevel );
2004-01-11 02:20:01 +00:00
}
2007-10-19 18:01:00 +00:00
return CLI_SUCCESS ;
2003-03-31 07:13:36 +00:00
}
2007-10-19 18:01:00 +00:00
static char * handle_cli_h323_set_debug ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2003-03-31 07:13:36 +00:00
{
2007-10-19 18:01:00 +00:00
switch ( cmd ) {
case CLI_INIT :
2008-09-28 23:32:14 +00:00
e -> command = "h323 set debug [on|off]" ;
2007-10-19 18:01:00 +00:00
e -> usage =
2008-09-28 23:32:14 +00:00
"Usage: h323 set debug [on|off] \n "
2007-10-19 18:01:00 +00:00
" Enable/Disable H.323 debugging output \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
2004-01-11 02:20:01 +00:00
}
2003-03-31 07:13:36 +00:00
2008-09-28 23:32:14 +00:00
if ( a -> argc != e -> args )
2007-10-19 18:01:00 +00:00
return CLI_SHOWUSAGE ;
2008-09-28 23:32:14 +00:00
if ( strcasecmp ( a -> argv [ 3 ], "on" ) && strcasecmp ( a -> argv [ 3 ], "off" ))
2007-10-19 18:01:00 +00:00
return CLI_SHOWUSAGE ;
2008-09-28 23:32:14 +00:00
h323debug = ( strcasecmp ( a -> argv [ 3 ], "on" )) ? 0 : 1 ;
2007-10-19 18:01:00 +00:00
ast_cli ( a -> fd , "H.323 Debugging %s \n " , h323debug ? "Enabled" : "Disabled" );
return CLI_SUCCESS ;
2003-03-31 07:13:36 +00:00
}
2007-10-19 18:01:00 +00:00
static char * handle_cli_h323_cycle_gk ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2003-03-31 07:13:36 +00:00
{
2007-10-19 18:01:00 +00:00
switch ( cmd ) {
case CLI_INIT :
e -> command = "h323 cycle gk" ;
e -> usage =
"Usage: h323 cycle gk \n "
" Manually re-register with the Gatekeper (Currently Disabled) \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
2006-09-19 17:07:22 +00:00
}
2007-10-19 18:01:00 +00:00
if ( a -> argc != 3 )
return CLI_SHOWUSAGE ;
2003-03-31 07:13:36 +00:00
h323_gk_urq ();
2006-09-19 17:07:22 +00:00
2003-03-31 07:13:36 +00:00
/* Possibly register with a GK */
2004-01-11 02:20:01 +00:00
if ( ! gatekeeper_disable ) {
2004-01-13 09:24:26 +00:00
if ( h323_set_gk ( gatekeeper_discover , gatekeeper , secret )) {
2003-03-31 07:13:36 +00:00
ast_log ( LOG_ERROR , "Gatekeeper registration failed. \n " );
}
}
2007-10-19 18:01:00 +00:00
return CLI_SUCCESS ;
2003-03-31 07:13:36 +00:00
}
2007-10-19 18:01:00 +00:00
static char * handle_cli_h323_hangup ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2004-01-06 16:51:34 +00:00
{
2007-10-19 18:01:00 +00:00
switch ( cmd ) {
case CLI_INIT :
e -> command = "h323 hangup" ;
e -> usage =
"Usage: h323 hangup <token> \n "
" Manually try to hang up the call identified by <token> \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
2004-01-11 02:20:01 +00:00
}
2007-10-19 18:01:00 +00:00
if ( a -> argc != 3 )
return CLI_SHOWUSAGE ;
if ( h323_soft_hangup ( a -> argv [ 2 ])) {
ast_verb ( 3 , "Hangup succeeded on %s \n " , a -> argv [ 2 ]);
2006-09-19 17:07:22 +00:00
} else {
2007-10-19 18:01:00 +00:00
ast_verb ( 3 , "Hangup failed for %s \n " , a -> argv [ 2 ]);
2004-01-06 16:51:34 +00:00
}
2007-10-19 18:01:00 +00:00
return CLI_SUCCESS ;
2004-01-06 16:51:34 +00:00
}
2007-10-19 18:01:00 +00:00
static char * handle_cli_h323_show_tokens ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2004-01-06 16:51:34 +00:00
{
2007-10-19 18:01:00 +00:00
switch ( cmd ) {
case CLI_INIT :
e -> command = "h323 show tokens" ;
e -> usage =
"Usage: h323 show tokens \n "
" Print out all active call tokens \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
2004-01-11 02:20:01 +00:00
}
2003-03-31 07:13:36 +00:00
2007-10-19 18:01:00 +00:00
if ( a -> argc != 3 )
return CLI_SHOWUSAGE ;
2004-01-06 16:51:34 +00:00
2007-10-19 18:01:00 +00:00
h323_show_tokens ();
2006-09-18 19:54:18 +00:00
2007-10-19 18:01:00 +00:00
return CLI_SUCCESS ;
}
2006-09-22 20:33:47 +00:00
static struct ast_cli_entry cli_h323 [] = {
2007-10-22 20:05:18 +00:00
AST_CLI_DEFINE ( handle_cli_h323_set_trace , "Enable/Disable H.323 Stack Tracing" ),
AST_CLI_DEFINE ( handle_cli_h323_set_debug , "Enable/Disable H.323 Debugging" ),
AST_CLI_DEFINE ( handle_cli_h323_cycle_gk , "Manually re-register with the Gatekeper" ),
AST_CLI_DEFINE ( handle_cli_h323_hangup , "Manually try to hang up a call" ),
AST_CLI_DEFINE ( handle_cli_h323_show_tokens , "Show all active call tokens" ),
2006-09-18 19:54:18 +00:00
};
2004-03-20 14:25:39 +00:00
2007-12-13 00:18:04 +00:00
static void delete_users ( void )
{
int pruned = 0 ;
/* Delete all users */
ASTOBJ_CONTAINER_WRLOCK ( & userl );
ASTOBJ_CONTAINER_TRAVERSE ( & userl , 1 , do {
ASTOBJ_RDLOCK ( iterator );
ASTOBJ_MARK ( iterator );
++ pruned ;
ASTOBJ_UNLOCK ( iterator );
} while ( 0 ) );
if ( pruned ) {
ASTOBJ_CONTAINER_PRUNE_MARKED ( & userl , oh323_destroy_user );
}
ASTOBJ_CONTAINER_UNLOCK ( & userl );
ASTOBJ_CONTAINER_WRLOCK ( & peerl );
ASTOBJ_CONTAINER_TRAVERSE ( & peerl , 1 , do {
ASTOBJ_RDLOCK ( iterator );
ASTOBJ_MARK ( iterator );
ASTOBJ_UNLOCK ( iterator );
} while ( 0 ) );
ASTOBJ_CONTAINER_UNLOCK ( & peerl );
}
static void delete_aliases ( void )
{
int pruned = 0 ;
/* Delete all aliases */
ASTOBJ_CONTAINER_WRLOCK ( & aliasl );
ASTOBJ_CONTAINER_TRAVERSE ( & aliasl , 1 , do {
ASTOBJ_RDLOCK ( iterator );
ASTOBJ_MARK ( iterator );
++ pruned ;
ASTOBJ_UNLOCK ( iterator );
} while ( 0 ) );
if ( pruned ) {
ASTOBJ_CONTAINER_PRUNE_MARKED ( & aliasl , oh323_destroy_alias );
}
ASTOBJ_CONTAINER_UNLOCK ( & aliasl );
}
static void prune_peers ( void )
{
/* Prune peers who still are supposed to be deleted */
ASTOBJ_CONTAINER_PRUNE_MARKED ( & peerl , oh323_destroy_peer );
}
2006-09-19 17:07:22 +00:00
static int reload_config ( int is_reload )
2005-05-13 20:24:30 +00:00
{
2006-09-19 17:07:22 +00:00
struct ast_config * cfg , * ucfg ;
2003-03-31 07:13:36 +00:00
struct ast_variable * v ;
2006-09-19 17:07:22 +00:00
struct oh323_peer * peer = NULL ;
struct oh323_user * user = NULL ;
2003-03-31 07:13:36 +00:00
struct oh323_alias * alias = NULL ;
2004-04-22 00:20:34 +00:00
struct ast_hostent ahp ; struct hostent * hp ;
2003-03-31 07:13:36 +00:00
char * cat ;
2006-09-22 20:00:31 +00:00
const char * utype ;
2006-09-19 17:07:22 +00:00
int is_user , is_peer , is_alias ;
char _gatekeeper [ 100 ];
int gk_discover , gk_disable , gk_changed ;
2007-08-16 21:09:46 +00:00
struct ast_flags config_flags = { is_reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
2006-09-19 17:07:22 +00:00
2007-08-16 21:09:46 +00:00
cfg = ast_config_load ( config , config_flags );
2003-03-31 07:13:36 +00:00
/* We *must* have a config file otherwise stop immediately */
if ( ! cfg ) {
ast_log ( LOG_NOTICE , "Unable to load config %s, H.323 disabled \n " , config );
2003-10-21 13:12:30 +00:00
return 1 ;
2007-08-16 21:09:46 +00:00
} else if ( cfg == CONFIG_STATUS_FILEUNCHANGED ) {
ucfg = ast_config_load ( "users.conf" , config_flags );
2008-09-12 23:30:03 +00:00
if ( ucfg == CONFIG_STATUS_FILEUNCHANGED ) {
2007-08-16 21:09:46 +00:00
return 0 ;
2008-09-12 23:30:03 +00:00
} else if ( ucfg == CONFIG_STATUS_FILEINVALID ) {
ast_log ( LOG_ERROR , "Config file users.conf is in an invalid format. Aborting. \n " );
return 0 ;
}
2007-08-16 21:09:46 +00:00
ast_clear_flag ( & config_flags , CONFIG_FLAG_FILEUNCHANGED );
2008-09-12 23:30:03 +00:00
if (( cfg = ast_config_load ( config , config_flags ))) {
ast_log ( LOG_ERROR , "Config file %s is in an invalid format. Aborting. \n " , config );
ast_config_destroy ( ucfg );
return 0 ;
}
} else if ( cfg == CONFIG_STATUS_FILEINVALID ) {
ast_log ( LOG_ERROR , "Config file %s is in an invalid format. Aborting. \n " , config );
return 0 ;
2007-08-16 21:09:46 +00:00
} else {
ast_clear_flag ( & config_flags , CONFIG_FLAG_FILEUNCHANGED );
2008-09-12 23:30:03 +00:00
if (( ucfg = ast_config_load ( "users.conf" , config_flags )) == CONFIG_STATUS_FILEINVALID ) {
ast_log ( LOG_ERROR , "Config file users.conf is in an invalid format. Aborting. \n " );
ast_config_destroy ( cfg );
return 0 ;
}
2003-03-31 07:13:36 +00:00
}
2006-09-19 17:07:22 +00:00
2007-08-18 13:52:44 +00:00
if ( is_reload ) {
delete_users ();
delete_aliases ();
prune_peers ();
}
2006-09-19 17:07:22 +00:00
/* fire up the H.323 Endpoint */
2003-12-18 19:48:42 +00:00
if ( ! h323_end_point_exist ()) {
2006-09-19 17:07:22 +00:00
h323_end_point_create ();
2003-12-18 19:48:42 +00:00
}
2006-10-25 14:44:50 +00:00
ast_copy_string ( _gatekeeper , gatekeeper , sizeof ( _gatekeeper ));
2006-09-19 17:07:22 +00:00
gk_discover = gatekeeper_discover ;
gk_disable = gatekeeper_disable ;
2003-03-31 07:13:36 +00:00
memset ( & bindaddr , 0 , sizeof ( bindaddr ));
2004-12-15 23:24:13 +00:00
memset ( & global_options , 0 , sizeof ( global_options ));
2006-09-19 17:07:22 +00:00
global_options . fastStart = 1 ;
global_options . h245Tunneling = 1 ;
2006-09-25 09:03:14 +00:00
global_options . dtmfcodec [ 0 ] = H323_DTMF_RFC2833_PT ;
global_options . dtmfcodec [ 1 ] = H323_DTMF_CISCO_PT ;
2006-09-24 18:53:44 +00:00
global_options . dtmfmode = 0 ;
2006-09-28 10:41:38 +00:00
global_options . holdHandling = 0 ;
2006-04-03 18:36:30 +00:00
global_options . capability = GLOBAL_CAPABILITY ;
2005-05-21 17:09:30 +00:00
global_options . bridge = 1 ; /* Do native bridging by default */
2006-10-25 14:44:50 +00:00
strcpy ( default_context , "default" );
2006-09-19 17:07:22 +00:00
h323_signalling_port = 1720 ;
gatekeeper_disable = 1 ;
gatekeeper_discover = 0 ;
gkroute = 0 ;
userbyalias = 1 ;
acceptAnonymous = 1 ;
tos = 0 ;
2007-04-30 16:16:26 +00:00
cos = 0 ;
2006-06-01 16:47:28 +00:00
/* Copy the default jb config over global_jbconf */
memcpy ( & global_jbconf , & default_jbconf , sizeof ( struct ast_jb_conf ));
2006-09-19 17:07:22 +00:00
if ( ucfg ) {
struct ast_variable * gen ;
int genhas_h323 ;
2006-09-22 20:00:31 +00:00
const char * has_h323 ;
2006-09-19 17:07:22 +00:00
genhas_h323 = ast_true ( ast_variable_retrieve ( ucfg , "general" , "hash323" ));
gen = ast_variable_browse ( ucfg , "general" );
for ( cat = ast_category_browse ( ucfg , NULL ); cat ; cat = ast_category_browse ( ucfg , cat )) {
if ( strcasecmp ( cat , "general" )) {
has_h323 = ast_variable_retrieve ( ucfg , cat , "hash323" );
if ( ast_true ( has_h323 ) || ( ! has_h323 && genhas_h323 )) {
user = build_user ( cat , gen , ast_variable_browse ( ucfg , cat ), 0 );
if ( user ) {
ASTOBJ_CONTAINER_LINK ( & userl , user );
ASTOBJ_UNREF ( user , oh323_destroy_user );
}
2007-06-25 14:15:05 +00:00
peer = build_peer ( cat , gen , ast_variable_browse ( ucfg , cat ), 0 );
if ( peer ) {
ASTOBJ_CONTAINER_LINK ( & peerl , peer );
ASTOBJ_UNREF ( peer , oh323_destroy_peer );
}
2006-09-19 17:07:22 +00:00
}
}
2006-06-01 16:47:28 +00:00
}
2006-09-19 17:07:22 +00:00
ast_config_destroy ( ucfg );
}
2006-06-01 16:47:28 +00:00
2006-09-19 17:07:22 +00:00
for ( v = ast_variable_browse ( cfg , "general" ); v ; v = v -> next ) {
/* handle jb conf */
if ( ! ast_jb_read_conf ( & global_jbconf , v -> name , v -> value ))
continue ;
2003-03-31 07:13:36 +00:00
/* Create the interface list */
2003-05-31 18:42:09 +00:00
if ( ! strcasecmp ( v -> name , "port" )) {
2004-10-04 10:13:01 +00:00
h323_signalling_port = ( int ) strtol ( v -> value , NULL , 10 );
2003-03-31 07:13:36 +00:00
} else if ( ! strcasecmp ( v -> name , "bindaddr" )) {
2004-04-22 00:20:34 +00:00
if ( ! ( hp = ast_gethostbyname ( v -> value , & ahp ))) {
2003-03-31 07:13:36 +00:00
ast_log ( LOG_WARNING , "Invalid address: %s \n " , v -> value );
} else {
memcpy ( & bindaddr . sin_addr , hp -> h_addr , sizeof ( bindaddr . sin_addr ));
}
2007-12-16 10:51:53 +00:00
} else if ( ! strcasecmp ( v -> name , "tos" )) { /* Needs to be removed in next release */
ast_log ( LOG_WARNING , "The \" tos \" setting is deprecated in this version of Asterisk. Please change to \" tos_audio \" . \n " );
2007-04-30 16:16:26 +00:00
if ( ast_str2tos ( v -> value , & tos )) {
2007-12-16 10:51:53 +00:00
ast_log ( LOG_WARNING , "Invalid tos_audio value at line %d, refer to QoS documentation \n " , v -> lineno );
2007-04-30 16:16:26 +00:00
}
2007-12-16 10:51:53 +00:00
} else if ( ! strcasecmp ( v -> name , "tos_audio" )) {
if ( ast_str2tos ( v -> value , & tos )) {
ast_log ( LOG_WARNING , "Invalid tos_audio value at line %d, refer to QoS documentation \n " , v -> lineno );
}
} else if ( ! strcasecmp ( v -> name , "cos" )) {
ast_log ( LOG_WARNING , "The \" cos \" setting is deprecated in this version of Asterisk. Please change to \" cos_audio \" . \n " );
if ( ast_str2cos ( v -> value , & cos )) {
ast_log ( LOG_WARNING , "Invalid cos_audio value at line %d, refer to QoS documentation \n " , v -> lineno );
}
} else if ( ! strcasecmp ( v -> name , "cos_audio" )) {
2007-04-30 16:16:26 +00:00
if ( ast_str2cos ( v -> value , & cos )) {
2007-12-16 10:51:53 +00:00
ast_log ( LOG_WARNING , "Invalid cos_audio value at line %d, refer to QoS documentation \n " , v -> lineno );
2004-10-22 19:04:02 +00:00
}
2003-03-31 07:13:36 +00:00
} else if ( ! strcasecmp ( v -> name , "gatekeeper" )) {
if ( ! strcasecmp ( v -> value , "DISABLE" )) {
gatekeeper_disable = 1 ;
} else if ( ! strcasecmp ( v -> value , "DISCOVER" )) {
gatekeeper_disable = 0 ;
gatekeeper_discover = 1 ;
} else {
gatekeeper_disable = 0 ;
2006-10-25 14:44:50 +00:00
ast_copy_string ( gatekeeper , v -> value , sizeof ( gatekeeper ));
2003-03-31 07:13:36 +00:00
}
} else if ( ! strcasecmp ( v -> name , "secret" )) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( secret , v -> value , sizeof ( secret ));
2003-03-31 07:13:36 +00:00
} else if ( ! strcasecmp ( v -> name , "AllowGKRouted" )) {
2004-10-28 06:06:58 +00:00
gkroute = ast_true ( v -> value );
2003-03-31 07:13:36 +00:00
} else if ( ! strcasecmp ( v -> name , "context" )) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( default_context , v -> value , sizeof ( default_context ));
2007-07-26 15:49:18 +00:00
ast_verb ( 2 , "Setting default context to %s \n " , default_context );
2003-12-09 05:14:23 +00:00
} else if ( ! strcasecmp ( v -> name , "UserByAlias" )) {
2005-05-02 18:46:36 +00:00
userbyalias = ast_true ( v -> value );
2006-09-19 17:07:22 +00:00
} else if ( ! strcasecmp ( v -> name , "AcceptAnonymous" )) {
acceptAnonymous = ast_true ( v -> value );
2005-05-21 17:09:30 +00:00
} else if ( ! update_common_options ( v , & global_options )) {
/* dummy */
2004-07-17 19:38:30 +00:00
}
2003-03-31 07:13:36 +00:00
}
2006-09-24 18:53:44 +00:00
if ( ! global_options . dtmfmode )
global_options . dtmfmode = H323_DTMF_RFC2833 ;
2006-09-28 10:41:38 +00:00
if ( global_options . holdHandling == ~ 0 )
global_options . holdHandling = 0 ;
else if ( ! global_options . holdHandling )
global_options . holdHandling = H323_HOLD_H450 ;
2006-09-19 17:07:22 +00:00
for ( cat = ast_category_browse ( cfg , NULL ); cat ; cat = ast_category_browse ( cfg , cat )) {
2003-03-31 07:13:36 +00:00
if ( strcasecmp ( cat , "general" )) {
utype = ast_variable_retrieve ( cfg , cat , "type" );
if ( utype ) {
2006-09-19 17:07:22 +00:00
is_user = is_peer = is_alias = 0 ;
if ( ! strcasecmp ( utype , "user" ))
is_user = 1 ;
else if ( ! strcasecmp ( utype , "peer" ))
is_peer = 1 ;
else if ( ! strcasecmp ( utype , "friend" ))
is_user = is_peer = 1 ;
else if ( ! strcasecmp ( utype , "h323" ) || ! strcasecmp ( utype , "alias" ))
is_alias = 1 ;
else {
ast_log ( LOG_WARNING , "Unknown type '%s' for '%s' in %s \n " , utype , cat , config );
continue ;
}
if ( is_user ) {
user = build_user ( cat , ast_variable_browse ( cfg , cat ), NULL , 0 );
2005-05-02 18:46:36 +00:00
if ( user ) {
2006-09-19 17:07:22 +00:00
ASTOBJ_CONTAINER_LINK ( & userl , user );
ASTOBJ_UNREF ( user , oh323_destroy_user );
2005-05-02 18:46:36 +00:00
}
2006-09-19 17:07:22 +00:00
}
if ( is_peer ) {
peer = build_peer ( cat , ast_variable_browse ( cfg , cat ), NULL , 0 );
2003-03-31 07:13:36 +00:00
if ( peer ) {
2006-09-19 17:07:22 +00:00
ASTOBJ_CONTAINER_LINK ( & peerl , peer );
ASTOBJ_UNREF ( peer , oh323_destroy_peer );
2003-03-31 07:13:36 +00:00
}
2006-09-19 17:07:22 +00:00
}
if ( is_alias ) {
alias = build_alias ( cat , ast_variable_browse ( cfg , cat ), NULL , 0 );
2003-03-31 07:13:36 +00:00
if ( alias ) {
2006-09-19 17:07:22 +00:00
ASTOBJ_CONTAINER_LINK ( & aliasl , alias );
ASTOBJ_UNREF ( alias , oh323_destroy_alias );
2003-03-31 07:13:36 +00:00
}
}
2004-10-28 06:06:58 +00:00
} else {
2003-03-31 07:13:36 +00:00
ast_log ( LOG_WARNING , "Section '%s' lacks type \n " , cat );
2004-10-28 06:06:58 +00:00
}
2003-03-31 07:13:36 +00:00
}
}
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg );
2003-03-31 07:13:36 +00:00
/* Register our H.323 aliases if any*/
2006-09-19 17:07:22 +00:00
ASTOBJ_CONTAINER_WRLOCK ( & aliasl );
ASTOBJ_CONTAINER_TRAVERSE ( & aliasl , 1 , do {
ASTOBJ_RDLOCK ( iterator );
if ( h323_set_alias ( iterator )) {
2003-03-31 07:13:36 +00:00
ast_log ( LOG_ERROR , "Alias %s rejected by endpoint \n " , alias -> name );
2006-09-19 17:07:22 +00:00
ASTOBJ_UNLOCK ( iterator );
continue ;
}
ASTOBJ_UNLOCK ( iterator );
} while ( 0 ) );
ASTOBJ_CONTAINER_UNLOCK ( & aliasl );
/* Don't touch GK if nothing changed because URQ will drop all existing calls */
gk_changed = 0 ;
if ( gatekeeper_disable != gk_disable )
gk_changed = is_reload ;
else if ( ! gatekeeper_disable && ( gatekeeper_discover != gk_discover ))
gk_changed = is_reload ;
else if ( ! gatekeeper_disable && ( strncmp ( _gatekeeper , gatekeeper , sizeof ( _gatekeeper )) != 0 ))
gk_changed = is_reload ;
if ( gk_changed ) {
if ( ! gk_disable )
h323_gk_urq ();
if ( ! gatekeeper_disable ) {
if ( h323_set_gk ( gatekeeper_discover , gatekeeper , secret )) {
ast_log ( LOG_ERROR , "Gatekeeper registration failed. \n " );
gatekeeper_disable = 1 ;
}
}
2003-03-31 07:13:36 +00:00
}
return 0 ;
}
2007-10-19 18:01:00 +00:00
static int h323_reload ( void )
2004-10-15 07:07:50 +00:00
{
ast_mutex_lock ( & h323_reload_lock );
2005-05-13 20:24:30 +00:00
if ( h323_reloading ) {
ast_verbose ( "Previous H.323 reload not yet done \n " );
} else {
h323_reloading = 1 ;
}
2004-10-15 07:07:50 +00:00
ast_mutex_unlock ( & h323_reload_lock );
2005-05-13 20:24:30 +00:00
restart_monitor ();
return 0 ;
2004-10-15 07:07:50 +00:00
}
2007-10-19 18:01:00 +00:00
static char * handle_cli_h323_reload ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
{
switch ( cmd ) {
case CLI_INIT :
e -> command = "h323 reload" ;
e -> usage =
"Usage: h323 reload \n "
" Reloads H.323 configuration from h323.conf \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
if ( a -> argc != 2 )
return CLI_SHOWUSAGE ;
h323_reload ();
return CLI_SUCCESS ;
}
2004-10-15 07:07:50 +00:00
static int h323_do_reload ( void )
2003-03-31 07:13:36 +00:00
{
2006-09-19 17:07:22 +00:00
reload_config ( 1 );
2005-05-13 20:24:30 +00:00
return 0 ;
2004-10-15 07:07:50 +00:00
}
2003-03-31 07:13:36 +00:00
2006-09-19 17:07:22 +00:00
static int reload ( void )
2004-10-15 07:07:50 +00:00
{
2007-07-18 15:26:52 +00:00
if ( ! sched || ! io ) {
ast_log ( LOG_NOTICE , "Unload and load chan_h323.so again in order to receive configuration changes. \n " );
return 0 ;
}
2007-10-19 18:01:00 +00:00
return h323_reload ();
2003-03-31 07:13:36 +00:00
}
2006-09-22 20:33:47 +00:00
static struct ast_cli_entry cli_h323_reload =
2007-10-22 20:05:18 +00:00
AST_CLI_DEFINE ( handle_cli_h323_reload , "Reload H.323 configuration" );
2006-09-22 20:33:47 +00:00
2006-09-19 17:07:22 +00:00
static enum ast_rtp_get_result oh323_get_rtp_peer ( struct ast_channel * chan , struct ast_rtp ** rtp )
2003-03-31 07:13:36 +00:00
{
2005-05-11 13:27:49 +00:00
struct oh323_pvt * pvt ;
2008-02-20 22:29:47 +00:00
enum ast_rtp_get_result res = AST_RTP_TRY_PARTIAL ;
2006-09-19 17:07:22 +00:00
if ( ! ( pvt = ( struct oh323_pvt * ) chan -> tech_pvt ))
2008-02-20 22:29:47 +00:00
return AST_RTP_GET_FAILED ;
2006-09-19 17:07:22 +00:00
ast_mutex_lock ( & pvt -> lock );
2008-04-09 18:05:40 +00:00
* rtp = pvt -> rtp ;
#if 0
if (pvt->options.bridge) {
2006-09-19 17:07:22 +00:00
res = AST_RTP_TRY_NATIVE;
2003-08-25 09:54:36 +00:00
}
2008-04-09 18:05:40 +00:00
#endif
2006-09-19 17:07:22 +00:00
ast_mutex_unlock ( & pvt -> lock );
return res ;
2003-03-31 07:13:36 +00:00
}
2006-09-19 17:07:22 +00:00
static enum ast_rtp_get_result oh323_get_vrtp_peer ( struct ast_channel * chan , struct ast_rtp ** rtp )
2003-03-31 07:13:36 +00:00
{
2006-09-19 17:07:22 +00:00
return AST_RTP_GET_FAILED ;
2003-07-01 19:11:37 +00:00
}
2003-08-25 09:54:36 +00:00
static char * convertcap ( int cap )
{
switch ( cap ) {
case AST_FORMAT_G723_1 :
return "G.723" ;
case AST_FORMAT_GSM :
return "GSM" ;
case AST_FORMAT_ULAW :
return "ULAW" ;
case AST_FORMAT_ALAW :
return "ALAW" ;
2006-10-25 00:32:23 +00:00
case AST_FORMAT_G722 :
return "G.722" ;
2003-08-25 09:54:36 +00:00
case AST_FORMAT_ADPCM :
return "G.728" ;
case AST_FORMAT_G729A :
return "G.729" ;
case AST_FORMAT_SPEEX :
return "SPEEX" ;
case AST_FORMAT_ILBC :
return "ILBC" ;
default :
ast_log ( LOG_NOTICE , "Don't know how to deal with mode %d \n " , cap );
return NULL ;
}
}
2007-02-18 19:09:29 +00:00
static int oh323_set_rtp_peer ( struct ast_channel * chan , struct ast_rtp * rtp , struct ast_rtp * vrtp , struct ast_rtp * trtp , int codecs , int nat_active )
2003-07-01 19:11:37 +00:00
{
/* XXX Deal with Video */
2005-05-11 13:27:49 +00:00
struct oh323_pvt * pvt ;
2003-03-31 07:13:36 +00:00
struct sockaddr_in them ;
struct sockaddr_in us ;
2003-08-25 09:54:36 +00:00
char * mode ;
2003-08-14 08:02:33 +00:00
if ( ! rtp ) {
2003-03-31 07:13:36 +00:00
return 0 ;
2003-08-14 08:02:33 +00:00
}
2003-08-25 09:54:36 +00:00
2006-09-19 17:07:22 +00:00
mode = convertcap ( chan -> writeformat );
2005-05-11 13:27:49 +00:00
pvt = ( struct oh323_pvt * ) chan -> tech_pvt ;
if ( ! pvt ) {
2003-03-31 07:13:36 +00:00
ast_log ( LOG_ERROR , "No Private Structure, this is bad \n " );
return - 1 ;
}
2006-09-19 17:07:22 +00:00
ast_rtp_get_peer ( rtp , & them );
2003-08-25 09:54:36 +00:00
ast_rtp_get_us ( rtp , & us );
2006-09-19 17:07:22 +00:00
#if 0 /* Native bridge still isn't ready */
h323_native_bridge(pvt->cd.call_token, ast_inet_ntoa(them.sin_addr), mode);
#endif
2003-03-31 07:13:36 +00:00
return 0 ;
}
static struct ast_rtp_protocol oh323_rtp = {
2006-04-03 18:36:30 +00:00
. type = "H323" ,
2005-03-04 06:47:24 +00:00
. get_rtp_info = oh323_get_rtp_peer ,
. get_vrtp_info = oh323_get_vrtp_peer ,
2006-09-19 17:07:22 +00:00
. set_rtp_peer = oh323_set_rtp_peer ,
2003-03-31 07:13:36 +00:00
};
2006-09-19 17:07:22 +00:00
static enum ast_module_load_result load_module ( void )
2003-03-31 07:13:36 +00:00
{
int res ;
2006-09-19 17:07:22 +00:00
h323debug = 0 ;
2004-10-15 07:07:50 +00:00
sched = sched_context_create ();
if ( ! sched ) {
ast_log ( LOG_WARNING , "Unable to create schedule context \n " );
2006-09-19 17:07:22 +00:00
return AST_MODULE_LOAD_FAILURE ;
2004-10-15 07:07:50 +00:00
}
io = io_context_create ();
if ( ! io ) {
ast_log ( LOG_WARNING , "Unable to create I/O context \n " );
2006-09-19 17:07:22 +00:00
return AST_MODULE_LOAD_FAILURE ;
2004-10-15 07:07:50 +00:00
}
2006-09-19 17:07:22 +00:00
ast_cli_register ( & cli_h323_reload );
ASTOBJ_CONTAINER_INIT ( & userl );
ASTOBJ_CONTAINER_INIT ( & peerl );
ASTOBJ_CONTAINER_INIT ( & aliasl );
res = reload_config ( 0 );
2003-12-10 23:34:47 +00:00
if ( res ) {
2007-01-23 06:56:26 +00:00
/* No config entry */
ast_log ( LOG_NOTICE , "Unload and load chan_h323.so again in order to receive configuration changes. \n " );
2006-09-20 16:24:00 +00:00
ast_cli_unregister ( & cli_h323_reload );
io_context_destroy ( io );
2007-01-23 06:56:26 +00:00
io = NULL ;
2006-09-20 16:24:00 +00:00
sched_context_destroy ( sched );
2007-01-23 06:56:26 +00:00
sched = NULL ;
2006-09-20 16:24:00 +00:00
ASTOBJ_CONTAINER_DESTROY ( & userl );
ASTOBJ_CONTAINER_DESTROY ( & peerl );
ASTOBJ_CONTAINER_DESTROY ( & aliasl );
2007-01-23 06:56:26 +00:00
return AST_MODULE_LOAD_DECLINE ;
2003-12-10 23:34:47 +00:00
} else {
/* Make sure we can register our channel type */
2005-03-04 06:47:24 +00:00
if ( ast_channel_register ( & oh323_tech )) {
2006-04-03 18:36:30 +00:00
ast_log ( LOG_ERROR , "Unable to register channel class 'H323' \n " );
2006-09-19 17:07:22 +00:00
ast_cli_unregister ( & cli_h323_reload );
2003-03-31 07:13:36 +00:00
h323_end_process ();
2006-09-19 17:07:22 +00:00
io_context_destroy ( io );
sched_context_destroy ( sched );
ASTOBJ_CONTAINER_DESTROYALL ( & userl , oh323_destroy_user );
ASTOBJ_CONTAINER_DESTROY ( & userl );
ASTOBJ_CONTAINER_DESTROYALL ( & peerl , oh323_destroy_peer );
ASTOBJ_CONTAINER_DESTROY ( & peerl );
ASTOBJ_CONTAINER_DESTROYALL ( & aliasl , oh323_destroy_alias );
ASTOBJ_CONTAINER_DESTROY ( & aliasl );
return AST_MODULE_LOAD_FAILURE ;
2003-03-31 07:13:36 +00:00
}
2006-09-18 19:54:18 +00:00
ast_cli_register_multiple ( cli_h323 , sizeof ( cli_h323 ) / sizeof ( struct ast_cli_entry ));
2004-03-20 14:25:39 +00:00
2003-03-31 07:13:36 +00:00
ast_rtp_proto_register ( & oh323_rtp );
/* Register our callback functions */
2006-09-19 17:07:22 +00:00
h323_callback_register ( setup_incoming_call ,
setup_outgoing_call ,
external_rtp_create ,
setup_rtp_connection ,
cleanup_connection ,
2005-05-11 13:27:49 +00:00
chan_ringing ,
2006-09-19 17:07:22 +00:00
connection_made ,
receive_digit ,
2005-05-11 13:27:49 +00:00
answer_call ,
progress ,
set_dtmf_payload ,
2005-05-19 19:13:19 +00:00
hangup_connection ,
2006-09-19 17:07:22 +00:00
set_local_capabilities ,
2006-09-28 10:41:38 +00:00
set_peer_capabilities ,
remote_hold );
2003-03-31 07:13:36 +00:00
/* start the h.323 listener */
2004-10-04 10:13:01 +00:00
if ( h323_start_listener ( h323_signalling_port , bindaddr )) {
2003-03-31 07:13:36 +00:00
ast_log ( LOG_ERROR , "Unable to create H323 listener. \n " );
2006-09-19 17:07:22 +00:00
ast_rtp_proto_unregister ( & oh323_rtp );
ast_cli_unregister_multiple ( cli_h323 , sizeof ( cli_h323 ) / sizeof ( struct ast_cli_entry ));
ast_cli_unregister ( & cli_h323_reload );
h323_end_process ();
io_context_destroy ( io );
sched_context_destroy ( sched );
ASTOBJ_CONTAINER_DESTROYALL ( & userl , oh323_destroy_user );
ASTOBJ_CONTAINER_DESTROY ( & userl );
ASTOBJ_CONTAINER_DESTROYALL ( & peerl , oh323_destroy_peer );
ASTOBJ_CONTAINER_DESTROY ( & peerl );
ASTOBJ_CONTAINER_DESTROYALL ( & aliasl , oh323_destroy_alias );
ASTOBJ_CONTAINER_DESTROY ( & aliasl );
return AST_MODULE_LOAD_FAILURE ;
2003-03-31 07:13:36 +00:00
}
/* Possibly register with a GK */
2004-10-28 06:06:58 +00:00
if ( ! gatekeeper_disable ) {
2003-03-31 07:13:36 +00:00
if ( h323_set_gk ( gatekeeper_discover , gatekeeper , secret )) {
ast_log ( LOG_ERROR , "Gatekeeper registration failed. \n " );
2006-09-19 17:07:22 +00:00
gatekeeper_disable = 1 ;
2006-09-20 16:24:00 +00:00
res = AST_MODULE_LOAD_SUCCESS ;
2003-03-31 07:13:36 +00:00
}
}
/* And start the monitor for the first time */
restart_monitor ();
}
return res ;
}
2004-01-11 02:20:01 +00:00
2006-09-19 17:07:22 +00:00
static int unload_module ( void )
2003-03-31 07:13:36 +00:00
{
struct oh323_pvt * p , * pl ;
2004-10-22 19:04:02 +00:00
/* unregister commands */
2006-09-18 19:54:18 +00:00
ast_cli_unregister_multiple ( cli_h323 , sizeof ( cli_h323 ) / sizeof ( struct ast_cli_entry ));
2006-09-19 17:07:22 +00:00
ast_cli_unregister ( & cli_h323_reload );
2005-03-04 06:47:24 +00:00
ast_channel_unregister ( & oh323_tech );
2006-09-19 17:07:22 +00:00
ast_rtp_proto_unregister ( & oh323_rtp );
2003-08-14 06:56:11 +00:00
if ( ! ast_mutex_lock ( & iflock )) {
2004-10-22 19:04:02 +00:00
/* hangup all interfaces if they have an owner */
p = iflist ;
while ( p ) {
if ( p -> owner ) {
ast_softhangup ( p -> owner , AST_SOFTHANGUP_APPUNLOAD );
}
p = p -> next ;
}
iflist = NULL ;
ast_mutex_unlock ( & iflock );
2003-03-31 07:13:36 +00:00
} else {
ast_log ( LOG_WARNING , "Unable to lock the interface list \n " );
return - 1 ;
}
2004-01-13 03:07:15 +00:00
if ( ! ast_mutex_lock ( & monlock )) {
2006-09-19 17:07:22 +00:00
if (( monitor_thread != AST_PTHREADT_STOP ) && ( monitor_thread != AST_PTHREADT_NULL )) {
2005-05-11 13:27:49 +00:00
/* this causes a seg, anyone know why? */
2006-09-19 17:07:22 +00:00
if ( monitor_thread != pthread_self ())
pthread_cancel ( monitor_thread );
2005-05-11 13:27:49 +00:00
pthread_kill ( monitor_thread , SIGURG );
pthread_join ( monitor_thread , NULL );
}
monitor_thread = AST_PTHREADT_STOP ;
ast_mutex_unlock ( & monlock );
} else {
ast_log ( LOG_WARNING , "Unable to lock the monitor \n " );
return - 1 ;
}
2003-08-14 06:56:11 +00:00
if ( ! ast_mutex_lock ( & iflock )) {
2003-03-31 07:13:36 +00:00
/* destroy all the interfaces and free their memory */
p = iflist ;
while ( p ) {
pl = p ;
p = p -> next ;
/* free associated memory */
2004-06-22 17:42:14 +00:00
ast_mutex_destroy ( & pl -> lock );
2007-06-03 06:10:27 +00:00
ast_free ( pl );
2003-03-31 07:13:36 +00:00
}
iflist = NULL ;
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & iflock );
2003-03-31 07:13:36 +00:00
} else {
ast_log ( LOG_WARNING , "Unable to lock the interface list \n " );
return - 1 ;
}
2006-09-19 17:07:22 +00:00
if ( ! gatekeeper_disable )
h323_gk_urq ();
2003-03-31 07:13:36 +00:00
h323_end_process ();
2007-01-23 06:56:26 +00:00
if ( io )
io_context_destroy ( io );
if ( sched )
sched_context_destroy ( sched );
2006-09-19 17:07:22 +00:00
ASTOBJ_CONTAINER_DESTROYALL ( & userl , oh323_destroy_user );
ASTOBJ_CONTAINER_DESTROY ( & userl );
ASTOBJ_CONTAINER_DESTROYALL ( & peerl , oh323_destroy_peer );
ASTOBJ_CONTAINER_DESTROY ( & peerl );
ASTOBJ_CONTAINER_DESTROYALL ( & aliasl , oh323_destroy_alias );
ASTOBJ_CONTAINER_DESTROY ( & aliasl );
return 0 ;
}
2003-03-31 07:13:36 +00:00
2006-08-21 02:11:39 +00:00
AST_MODULE_INFO ( ASTERISK_GPL_KEY , AST_MODFLAG_DEFAULT , "The NuFone Network's OpenH323 Channel Driver" ,
. load = load_module ,
. unload = unload_module ,
. reload = reload ,
2006-09-19 17:07:22 +00:00
);