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
*
* \ 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 >
< defaultenabled > no < / 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
2004-06-26 03:50:14 +00:00
# include <sys/socket.h>
# include <sys/signal.h>
# include <sys/param.h>
# if defined(BSD)
# ifndef IPTOS_MINCOST
# define IPTOS_MINCOST 0x02
# endif
# endif
# include <arpa/inet.h>
# include <net/if.h>
# include <netinet/in.h>
# include <netinet/in_systm.h>
# include <netinet/ip.h>
# include <unistd.h>
# include <stdlib.h>
# include <netdb.h>
2003-03-31 07:13:36 +00:00
# include <stdio.h>
# include <string.h>
2004-06-26 03:50:14 +00:00
# include <errno.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/logger.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/options.h"
# include "asterisk/utils.h"
# include "asterisk/lock.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 ;
2004-09-30 19:36:46 +00:00
/* global debug flag */
2004-06-26 03:50:14 +00:00
int h323debug ;
2006-06-01 16:47:28 +00:00
/*! Global jitterbuffer configuration - by default, jb is disabled */
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 ;
2003-03-31 07:13:36 +00:00
static int tos = 0 ;
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 ;
2003-03-31 07:13:36 +00:00
/** Private structure of a OpenH323 channel */
struct oh323_pvt {
2003-08-14 06:56:11 +00:00
ast_mutex_t lock ; /* Channel private lock */
2006-09-19 17:07:22 +00:00
call_options_t options ; /* Options to be used during call setup */
2004-05-18 10:33:46 +00:00
int alreadygone ; /* Whether or not we've already been destroyed by our peer */
2004-04-05 20:45:14 +00:00
int needdestroy ; /* if we need to be destroyed */
call_details_t cd ; /* Call details */
2006-09-19 17:07:22 +00:00
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 */
2004-04-05 20:45:14 +00:00
int outgoing ; /* Outgoing or incoming call? */
2006-09-19 17:07:22 +00:00
char exten [ AST_MAX_EXTENSION ] ; /* Requested extension */
char context [ AST_MAX_CONTEXT ] ; /* Context where to start */
char accountcode [ 256 ] ; /* Account code */
2004-12-16 02:03:19 +00:00
char rdnis [ 80 ] ; /* Referring DNIS, if available */
2004-04-05 20:45:14 +00:00
int amaflags ; /* AMA Flags */
2006-09-19 17:07:22 +00:00
struct ast_rtp * rtp ; /* RTP Session */
struct ast_dsp * vad ; /* Used for in-band DTMF detection */
2005-04-04 15:54:34 +00:00
int nativeformats ; /* Codec formats supported by a channel */
int needhangup ; /* Send hangup when Asterisk is ready */
int hangupcause ; /* Hangup cause from OpenH323 layer */
2005-07-27 04:45:11 +00:00
int newstate ; /* Pending state change */
int newcontrol ; /* Pending control to send */
2006-08-15 14:55:30 +00:00
int newdigit ; /* Pending DTMF digit to send */
2006-09-19 17:07:22 +00:00
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 */
2006-09-20 16:24:00 +00:00
struct ast_codec_pref peer_prefs ; /* Preferenced list of codecs which remote side supports */
2006-09-25 09:03:14 +00:00
int dtmf_pt [ 2 ] ; /* Payload code used for RFC2833/CISCO messages */
2006-09-19 17:07:22 +00:00
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 */
2005-07-27 04:45:11 +00:00
struct oh323_pvt * next ; /* Next channel in list */
2003-03-31 07:13:36 +00:00
} * iflist = NULL ;
static struct ast_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
static struct ast_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
static struct ast_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
2004-09-30 19:36:46 +00:00
/** Asterisk RTP stuff */
2003-03-31 07:13:36 +00:00
static struct sched_context * sched ;
static struct io_context * io ;
2004-09-30 19:36:46 +00:00
/** Protect the interface list (oh323_pvt) */
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( iflock ) ;
2003-03-31 07:13:36 +00:00
/* Protect the monitoring thread, so only one process can kill or start it, and not
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
2004-09-30 19:36:46 +00:00
/* 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 ) ;
2004-10-15 07:07:50 +00:00
/* Protect the reload process */
AST_MUTEX_DEFINE_STATIC ( h323_reload_lock ) ;
static int h323_reloading = 0 ;
2003-03-31 07:13:36 +00:00
/* 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
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 ) ;
static int oh323_digit_end ( struct ast_channel * c , char digit ) ;
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 ,
2006-04-03 18:36:30 +00:00
. capabilities = ( ( AST_FORMAT_MAX_AUDIO < < 1 ) - 1 ) ,
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 ,
/* disable, for now */
#if 0
. bridge = ast_rtp_bridge ,
# endif
} ;
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 )
ast_log ( LOG_DEBUG , " Destroying alias '%s' \n " , alias - > name ) ;
free ( alias ) ;
}
static void oh323_destroy_user ( struct oh323_user * user )
{
if ( h323debug )
ast_log ( LOG_DEBUG , " Destroying user '%s' \n " , user - > name ) ;
ast_free_ha ( user - > ha ) ;
free ( user ) ;
}
static void oh323_destroy_peer ( struct oh323_peer * peer )
{
if ( h323debug )
ast_log ( LOG_DEBUG , " Destroying peer '%s' \n " , peer - > name ) ;
ast_free_ha ( peer - > ha ) ;
free ( peer ) ;
}
static int oh323_simulate_dtmf_end ( void * data )
{
struct oh323_pvt * pvt = data ;
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 ) ) {
ast_mutex_unlock ( & pvt - > lock ) ;
usleep ( 1 ) ;
ast_mutex_lock ( & pvt - > lock ) ;
}
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 ;
}
2005-05-11 13:27:49 +00:00
/* Channel and private structures should be already locked */
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 )
ast_log ( LOG_DEBUG , " Preparing %s for new native format \n " , c - > name ) ;
c - > nativeformats = pvt - > nativeformats ;
ast_set_read_format ( c , c - > readformat ) ;
ast_set_write_format ( c , c - > writeformat ) ;
}
if ( pvt - > needhangup ) {
if ( h323debug )
ast_log ( LOG_DEBUG , " Process pending hangup for %s \n " , c - > name ) ;
c - > _softhangup | = AST_SOFTHANGUP_DEV ;
c - > hangupcause = pvt - > hangupcause ;
ast_queue_hangup ( c ) ;
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 ,
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 ) {
ast_sched_del ( sched , pvt - > DTMFsched ) ;
pvt - > DTMFsched = - 1 ;
}
} else { /* Regular input or signal message */
if ( pvt - > newduration ) { /* This is a signal, signalUpdate follows */
f . frametype = AST_FRAME_DTMF_BEGIN ;
if ( pvt - > DTMFsched > = 0 )
ast_sched_del ( sched , pvt - > DTMFsched ) ;
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 ) ;
c - > fds [ 0 ] = ast_rtp_fd ( pvt - > rtp ) ;
c - > fds [ 1 ] = ast_rtcp_fd ( pvt - > rtp ) ;
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
}
/* Only channel structure should be locked */
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 ) {
free ( cd - > call_token ) ;
cd - > call_token = NULL ;
}
if ( cd - > call_source_aliases ) {
free ( cd - > call_source_aliases ) ;
cd - > call_source_aliases = NULL ;
}
if ( cd - > call_dest_alias ) {
free ( cd - > call_dest_alias ) ;
cd - > call_dest_alias = NULL ;
}
if ( cd - > call_source_name ) {
free ( cd - > call_source_name ) ;
cd - > call_source_name = NULL ;
}
if ( cd - > call_source_e164 ) {
free ( cd - > call_source_e164 ) ;
cd - > call_source_e164 = NULL ;
}
if ( cd - > call_dest_e164 ) {
free ( cd - > call_dest_e164 ) ;
cd - > call_dest_e164 = NULL ;
}
if ( cd - > sourceIp ) {
free ( cd - > sourceIp ) ;
cd - > sourceIp = NULL ;
}
if ( cd - > redirect_number ) {
free ( cd - > redirect_number ) ;
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
if ( pvt - > DTMFsched > = 0 ) {
ast_sched_del ( sched , pvt - > DTMFsched ) ;
pvt - > DTMFsched = - 1 ;
}
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 )
ast_log ( LOG_DEBUG , " 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 ) ;
free ( pvt ) ;
}
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 ) {
ast_log ( LOG_DEBUG , " Destroying channel %s \n " , ( pvt - > owner ? pvt - > owner - > name : " <unknown> " ) ) ;
}
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 ;
token = pvt - > cd . call_token ? strdup ( pvt - > cd . call_token ) : NULL ;
ast_mutex_unlock ( & pvt - > lock ) ;
h323_send_tone ( token , digit ) ;
if ( token ) {
free ( token ) ;
}
} else
ast_mutex_unlock ( & pvt - > lock ) ;
oh323_update_info ( c ) ;
2006-08-31 01:59:02 +00:00
return 0 ;
}
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
*/
2006-08-31 01:59:02 +00:00
static int oh323_digit_end ( struct ast_channel * c , char digit )
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 ) {
2006-09-19 17:07:22 +00:00
ast_log ( LOG_DTMF , " End sending out-of-band digit %c on %s \n " , digit , c - > name ) ;
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 ) {
2006-09-19 17:07:22 +00:00
ast_log ( LOG_DTMF , " End sending inband digit %c on %s \n " , digit , c - > name ) ;
2005-09-15 03:26:02 +00:00
}
2006-09-19 17:07:22 +00:00
pvt - > txDtmfDigit = ' ' ;
2005-09-15 03:26:02 +00:00
token = pvt - > cd . call_token ? 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 ) {
free ( token ) ;
}
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 ;
}
/**
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 ) {
ast_log ( LOG_DEBUG , " Calling to %s on %s \n " , dest , c - > name ) ;
}
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 ) ) {
strncpy ( called_addr , dest , sizeof ( called_addr ) ) ;
} 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 )
2004-12-16 02:03:19 +00:00
strncpy ( 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 )
2004-12-16 02:03:19 +00:00
strncpy ( 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 ) {
strncpy ( pvt - > options . cid_rdnis , c - > cid . cid_rdnis , sizeof ( pvt - > options . cid_rdnis ) ) ;
2004-12-16 02:03:19 +00:00
}
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 ;
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
2006-09-19 17:07:22 +00:00
if ( h323debug )
2006-09-25 09:03:14 +00:00
ast_log ( LOG_DEBUG , " 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 )
ast_log ( LOG_DEBUG , " Answering on %s \n " , c - > name ) ;
ast_mutex_lock ( & pvt - > lock ) ;
token = pvt - > cd . call_token ? strdup ( pvt - > cd . call_token ) : NULL ;
ast_mutex_unlock ( & pvt - > lock ) ;
res = h323_answering_call ( token , 0 ) ;
if ( token )
free ( token ) ;
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 )
2006-09-19 17:07:22 +00:00
ast_log ( LOG_DEBUG , " 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 ) {
call_token = pvt - > cd . call_token ? strdup ( pvt - > cd . call_token ) : NULL ;
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
}
free ( call_token ) ;
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 ;
}
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
{
2006-09-19 17:07:22 +00:00
/* Retrieve audio/etc from channel. Assumes pvt->lock is already held. */
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 )
ast_log ( LOG_DEBUG , " 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 ;
2004-12-15 23:24:13 +00:00
2005-04-04 15:54:34 +00:00
ast_mutex_lock ( & pvt - > lock ) ;
token = ( pvt - > cd . call_token ? strdup ( pvt - > cd . call_token ) : NULL ) ;
ast_mutex_unlock ( & pvt - > lock ) ;
if ( h323debug )
ast_log ( LOG_DEBUG , " OH323: Indicating %d on %s \n " , condition , token ) ;
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-09-19 17:07:22 +00:00
break ;
}
if ( token )
free ( token ) ;
2004-05-20 07:07:18 +00:00
return - 1 ;
case AST_CONTROL_PROGRESS :
if ( c - > _state ! = AST_STATE_UP ) {
2005-04-04 15:54:34 +00:00
h323_send_progress ( token ) ;
2004-05-20 07:07:18 +00:00
break ;
2003-03-31 07:13:36 +00:00
}
2005-04-04 15:54:34 +00:00
if ( token )
free ( token ) ;
2004-05-20 07:07:18 +00:00
return - 1 ;
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 ) ;
2005-05-11 13:27:49 +00:00
ast_mutex_lock ( & pvt - > lock ) ;
pvt - > alreadygone = 1 ;
ast_mutex_unlock ( & pvt - > lock ) ;
2006-09-19 17:07:22 +00:00
ast_softhangup_nolock ( c , AST_SOFTHANGUP_DEV ) ;
2003-03-31 07:13:36 +00:00
break ;
}
2005-04-04 15:54:34 +00:00
if ( token )
free ( token ) ;
2004-05-20 07:07:18 +00:00
return - 1 ;
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 ) ;
2005-05-11 13:27:49 +00:00
ast_mutex_lock ( & pvt - > lock ) ;
2004-10-04 10:13:01 +00:00
pvt - > alreadygone = 1 ;
2005-05-11 13:27:49 +00:00
ast_mutex_unlock ( & pvt - > lock ) ;
2004-05-20 07:07:18 +00:00
ast_softhangup_nolock ( c , AST_SOFTHANGUP_DEV ) ;
2003-03-31 07:13:36 +00:00
break ;
}
2005-04-04 15:54:34 +00:00
if ( token )
free ( token ) ;
2004-05-20 07:07:18 +00:00
return - 1 ;
2006-07-19 20:44:39 +00:00
case AST_CONTROL_HOLD :
ast_moh_start ( c , data , NULL ) ;
if ( token )
free ( token ) ;
return 0 ;
case AST_CONTROL_UNHOLD :
ast_moh_stop ( c ) ;
if ( token )
free ( token ) ;
return 0 ;
2004-06-14 21:18:52 +00:00
case AST_CONTROL_PROCEEDING :
2003-03-31 07:13:36 +00:00
case - 1 :
2005-04-04 15:54:34 +00:00
if ( token )
free ( token ) ;
2003-12-24 22:38:24 +00:00
return - 1 ;
2003-03-31 07:13:36 +00:00
default :
2005-04-04 15:54:34 +00:00
ast_log ( LOG_WARNING , " Don't know how to indicate condition %d on %s \n " , condition , token ) ;
if ( token )
free ( token ) ;
2003-03-31 07:13:36 +00:00
return - 1 ;
}
2005-04-04 15:54:34 +00:00
if ( h323debug )
ast_log ( LOG_DEBUG , " OH323: Indicated %d on %s \n " , condition , token ) ;
if ( token )
free ( token ) ;
oh323_update_info ( c ) ;
2004-12-15 23:24:13 +00:00
return - 1 ;
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 )
ast_log ( LOG_DEBUG , " Created RTP channel \n " ) ;
ast_rtp_settos ( pvt - > rtp , tos ) ;
if ( h323debug )
ast_log ( LOG_DEBUG , " Setting NAT on RTP to %d \n " , pvt - > options . nat ) ;
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 ) ;
pvt - > owner - > fds [ 0 ] = ast_rtp_fd ( pvt - > rtp ) ;
pvt - > owner - > fds [ 1 ] = ast_rtcp_fd ( pvt - > rtp ) ;
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 ;
}
2005-05-11 13:27:49 +00:00
/* Private structure should be locked on a call */
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 ;
2003-03-31 07:13:36 +00:00
int fmt ;
2006-09-19 17:07:22 +00:00
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 ) ;
ch = ast_channel_alloc ( 1 ) ;
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-04-03 18:36:30 +00:00
ast_string_field_build ( ch , name , " H323/%s " , host ) ;
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 ;
2006-09-19 17:07:22 +00:00
#if 0
ch - > fds [ 0 ] = ast_rtp_fd ( pvt - > rtp ) ;
ch - > fds [ 1 ] = ast_rtcp_fd ( pvt - > rtp ) ;
# endif
# ifdef VIDEO_SUPPORT
if ( pvt - > vrtp ) {
ch - > fds [ 2 ] = ast_rtp_fd ( pvt - > vrtp ) ;
ch - > fds [ 3 ] = ast_rtcp_fd ( pvt - > vrtp ) ;
}
# endif
# ifdef T38_SUPPORT
if ( pvt - > udptl ) {
ch - > fds [ 4 ] = ast_udptl_fd ( pvt - > udptl ) ;
}
# 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 ( ) ;
ast_dsp_set_features ( pvt - > vad , DSP_FEATURE_DTMF_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
2004-10-04 10:13:01 +00:00
strncpy ( ch - > context , pvt - > context , sizeof ( ch - > context ) - 1 ) ;
2006-09-19 17:07:22 +00:00
strncpy ( ch - > exten , pvt - > exten , sizeof ( ch - > exten ) - 1 ) ;
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
* generate a NewCallerID event before the NewChannel event */
2006-09-19 17:07:22 +00:00
if ( ! ast_strlen_zero ( pvt - > options . cid_num ) ) {
ch - > cid . cid_num = ast_strdup ( pvt - > options . cid_num ) ;
ch - > cid . cid_ani = ast_strdup ( pvt - > options . cid_num ) ;
2006-08-05 05:26:29 +00:00
} else {
ch - > cid . cid_num = ast_strdup ( pvt - > cd . call_source_e164 ) ;
ch - > cid . cid_ani = ast_strdup ( pvt - > cd . call_source_e164 ) ;
2004-10-22 19:04:02 +00:00
}
2006-09-19 17:07:22 +00:00
if ( ! ast_strlen_zero ( pvt - > options . cid_name ) )
ch - > cid . cid_name = ast_strdup ( pvt - > options . cid_name ) ;
else
ch - > cid . cid_name = ast_strdup ( pvt - > cd . call_source_name ) ;
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 ) ) ;
}
2004-10-22 19:04:02 +00:00
if ( ! ast_strlen_zero ( pvt - > exten ) & & strcmp ( pvt - > exten , " s " ) ) {
ch - > cid . cid_dnid = strdup ( pvt - > exten ) ;
}
2004-04-28 14:35:20 +00:00
ast_setstate ( ch , state ) ;
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
2004-10-04 10:13:01 +00:00
pvt = ( struct oh323_pvt * ) malloc ( sizeof ( struct oh323_pvt ) ) ;
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 ;
}
2004-10-04 10:13:01 +00:00
memset ( pvt , 0 , sizeof ( struct oh323_pvt ) ) ;
2006-09-19 17:07:22 +00:00
pvt - > cd . redirect_reason = - 1 ;
/* Ensure the call token is allocated for outgoing call */
if ( ! callid ) {
if ( ( pvt - > cd ) . call_token = = NULL ) {
( pvt - > cd ) . call_token = ( char * ) malloc ( 128 ) ;
}
if ( ! pvt - > cd . call_token ) {
ast_log ( LOG_ERROR , " Not enough memory to alocate call token \n " ) ;
ast_rtp_destroy ( pvt - > rtp ) ;
free ( pvt ) ;
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
}
2004-10-04 10:13:01 +00:00
strncpy ( pvt - > context , default_context , sizeof ( pvt - > context ) - 1 ) ;
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 */
2005-05-11 13:27:49 +00:00
if ( ( token ! = NULL ) & & ( ! strcmp ( pvt - > cd . call_token , token ) ) ) {
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 {
if ( ! ( alias = ( struct oh323_alias * ) calloc ( 1 , sizeof ( * alias ) ) ) )
return NULL ;
ASTOBJ_INIT ( alias ) ;
}
if ( ! found & & name )
strncpy ( alias - > name , name , sizeof ( alias - > name ) - 1 ) ;
for ( ; v | | ( ( v = alt ) & & ! ( alt = NULL ) ) ; v = v - > next ) {
if ( ! strcasecmp ( v - > name , " e164 " ) ) {
strncpy ( alias - > e164 , v - > value , sizeof ( alias - > e164 ) - 1 ) ;
} else if ( ! strcasecmp ( v - > name , " prefix " ) ) {
strncpy ( alias - > prefix , v - > value , sizeof ( alias - > prefix ) - 1 ) ;
} else if ( ! strcasecmp ( v - > name , " context " ) ) {
strncpy ( alias - > context , v - > value , sizeof ( alias - > context ) - 1 ) ;
} else if ( ! strcasecmp ( v - > name , " secret " ) ) {
strncpy ( alias - > secret , v - > value , sizeof ( alias - > secret ) - 1 ) ;
} 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 ) ;
} else
return 1 ;
return 0 ;
}
static struct oh323_user * build_user ( char * name , struct ast_variable * v , struct ast_variable * alt , int realtime )
{
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 {
if ( ! ( user = ( struct oh323_user * ) calloc ( 1 , sizeof ( * user ) ) ) )
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-19 17:07:22 +00:00
/* Set default context */
strncpy ( user - > context , default_context , sizeof ( user - > context ) - 1 ) ;
if ( user & & ! found )
strncpy ( user - > name , name , sizeof ( user - > name ) - 1 ) ;
#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 " ) ) {
strncpy ( user - > context , v - > value , sizeof ( user - > context ) - 1 ) ;
} else if ( ! strcasecmp ( v - > name , " secret " ) ) {
strncpy ( user - > secret , v - > value , sizeof ( user - > secret ) - 1 ) ;
} else if ( ! strcasecmp ( v - > name , " accountcode " ) ) {
strncpy ( user - > accountcode , v - > value , sizeof ( user - > accountcode ) - 1 ) ;
} 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 " ) ) {
user - > ha = ast_append_ha ( v - > name , v - > value , user - > ha ) ;
}
}
2006-09-24 18:53:44 +00:00
if ( ! user - > options . dtmfmode )
user - > options . dtmfmode = global_options . dtmfmode ;
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 ;
char * username ;
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 {
if ( ! ( peer = ( struct oh323_peer * ) calloc ( 1 , sizeof ( * peer ) ) ) )
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-19 17:07:22 +00:00
peer - > addr . sin_port = htons ( h323_signalling_port ) ;
peer - > addr . sin_family = AF_INET ;
if ( ! found & & name )
strncpy ( peer - > name , name , sizeof ( peer - > name ) - 1 ) ;
#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 " ) ) {
peer - > ha = ast_append_ha ( v - > name , v - > value , peer - > ha ) ;
} else if ( ! strcasecmp ( v - > name , " mailbox " ) ) {
ast_copy_string ( peer - > mailbox , v - > value , sizeof ( peer - > mailbox ) ) ;
}
}
2006-09-24 18:53:44 +00:00
if ( ! peer - > options . dtmfmode )
peer - > options . dtmfmode = global_options . dtmfmode ;
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 ;
const char * addr ;
/* First check on peer name */
if ( peername )
var = ast_load_realtime ( " h323 " , " name " , peername , addr = NULL ) ;
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 )
ast_log ( LOG_DEBUG , " Could not find user by name %s or address %s \n " , cd - > call_source_aliases , cd - > sourceIp ) ;
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 )
ast_log ( LOG_DEBUG , " Could not find peer by name %s or address %s \n " , ( peer ? peer : " <NONE> " ) , ( sin ? ast_inet_ntoa ( sin - > sin_addr ) : " <NONE> " ) ) ;
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 ] = " " ;
strncpy ( peer , opeer , sizeof ( peer ) - 1 ) ;
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 )
ast_log ( LOG_DEBUG , " type=%s, format=%d, data=%s. \n " , type , format , ( char * ) data ) ;
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 ;
2004-10-01 04:50:34 +00:00
format & = ( ( AST_FORMAT_MAX_AUDIO < < 1 ) - 1 ) ;
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-09-19 17:07:22 +00:00
strncpy ( tmp , dest , sizeof ( tmp ) - 1 ) ;
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 ) {
2004-11-11 21:30:30 +00:00
strncpy ( pvt - > exten , ext , sizeof ( pvt - > exten ) - 1 ) ;
2004-01-11 17:51:35 +00:00
}
2006-09-19 17:07:22 +00:00
if ( h323debug )
ast_log ( LOG_DEBUG , " Extension: %s Host: %s \n " , pvt - > exten , host ) ;
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 ;
}
2004-10-22 19:04:02 +00:00
/** 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
}
/**
* 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 ,
. src = " SEND_DIGIT " ,
} ;
if ( digit = = ' ' ) { /* signalUpdate message */
f . subclass = pvt - > curDTMF ;
if ( pvt - > DTMFsched > = 0 ) {
ast_sched_del ( sched , pvt - > DTMFsched ) ;
pvt - > DTMFsched = - 1 ;
}
} else { /* Regular input or signal message */
if ( duration ) { /* This is a signal, signalUpdate follows */
f . frametype = AST_FRAME_DTMF_BEGIN ;
if ( pvt - > DTMFsched > = 0 )
ast_sched_del ( sched , pvt - > DTMFsched ) ;
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
}
/**
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
*
2003-08-25 09:54:36 +00:00
* 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
2004-10-10 12:20:18 +00:00
info = ( struct rtp_info * ) malloc ( sizeof ( struct rtp_info ) ) ;
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 ) {
2005-05-03 18:58:50 +00:00
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 ) ;
free ( info ) ;
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-09-19 17:07:22 +00:00
strncpy ( info - > addr , ast_inet_ntoa ( us . sin_addr ) , sizeof ( info - > addr ) ) ;
info - > addr [ sizeof ( info - > addr ) - 1 ] = ' \0 ' ;
2003-08-25 09:54:36 +00:00
info - > port = ntohs ( us . sin_port ) ;
2005-05-11 13:27:49 +00:00
if ( h323debug )
ast_log ( LOG_DEBUG , " 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
}
2004-12-21 00:07:56 +00:00
/**
* Definition taken from rtp . c for rtpPayloadType because we need it here .
*/
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 ;
} ;
2004-10-10 12:20:18 +00:00
/**
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 )
ast_log ( LOG_DEBUG , " 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 )
ast_log ( LOG_DEBUG , " Native format is set to %d from %d by RTP payload type %d \n " , rtptype . code , pvt - > nativeformats , pt ) ;
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 )
ast_log ( LOG_DEBUG , " 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 ) ;
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 )
ast_log ( LOG_DEBUG , " RTP connection preparation for %s is pending... \n " , token ) ;
}
}
2005-07-27 04:45:11 +00:00
ast_mutex_unlock ( & pvt - > lock ) ;
2005-04-04 15:54:34 +00:00
if ( h323debug )
ast_log ( LOG_DEBUG , " RTP connection prepared for %s \n " , token ) ;
2004-12-21 00:07:56 +00:00
2004-10-10 12:20:18 +00:00
return ;
}
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 )
ast_log ( LOG_DEBUG , " 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 )
ast_log ( LOG_DEBUG , " 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 ;
}
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 )
2005-05-19 16:17:08 +00:00
ast_log ( LOG_DEBUG , " 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 ) {
2003-12-24 22:38:24 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Setting up Call \n " ) ;
2006-09-19 17:07:22 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " \t Call token: [%s] \n " , pvt - > cd . call_token ) ;
ast_verbose ( VERBOSE_PREFIX_3 " \t Calling party name: [%s] \n " , pvt - > cd . call_source_name ) ;
ast_verbose ( VERBOSE_PREFIX_3 " \t Calling party number: [%s] \n " , pvt - > cd . call_source_e164 ) ;
ast_verbose ( VERBOSE_PREFIX_3 " \t Called party name: [%s] \n " , pvt - > cd . call_dest_alias ) ;
ast_verbose ( VERBOSE_PREFIX_3 " \t Called party number: [%s] \n " , pvt - > cd . call_dest_e164 ) ;
if ( pvt - > cd . redirect_reason > = 0 )
ast_verbose ( VERBOSE_PREFIX_3 " \t Redirecting party number: [%s] (reason %d) \n " , pvt - > cd . redirect_number , pvt - > cd . redirect_reason ) ;
ast_verbose ( VERBOSE_PREFIX_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 ) ) {
strncpy ( pvt - > exten , cd - > call_dest_e164 , sizeof ( pvt - > exten ) - 1 ) ;
2006-09-19 17:07:22 +00:00
strncpy ( pvt - > context , default_context , sizeof ( pvt - > context ) - 1 ) ;
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
}
2004-10-04 10:13:01 +00:00
strncpy ( pvt - > exten , alias - > name , sizeof ( pvt - > exten ) - 1 ) ;
strncpy ( pvt - > context , alias - > context , sizeof ( pvt - > context ) - 1 ) ;
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
}
2004-10-04 10:13:01 +00:00
strncpy ( pvt - > context , default_context , sizeof ( pvt - > context ) - 1 ) ;
2006-09-19 17:07:22 +00:00
if ( ! ast_strlen_zero ( pvt - > cd . call_dest_e164 ) ) {
strncpy ( pvt - > exten , cd - > call_dest_e164 , sizeof ( pvt - > exten ) - 1 ) ;
} else {
strncpy ( pvt - > exten , cd - > call_dest_alias , sizeof ( pvt - > exten ) - 1 ) ;
}
if ( h323debug )
ast_log ( LOG_DEBUG , " 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
}
2004-10-04 10:13:01 +00:00
strncpy ( pvt - > context , default_context , sizeof ( pvt - > context ) - 1 ) ;
2004-05-20 21:56:12 +00:00
} else {
2004-10-04 10:13:01 +00:00
strncpy ( pvt - > context , user - > context , sizeof ( pvt - > context ) - 1 ) ;
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
}
2004-10-04 10:13:01 +00:00
strncpy ( pvt - > context , user - > context , sizeof ( pvt - > context ) - 1 ) ;
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 ) ) {
2005-05-19 16:17:08 +00:00
strncpy ( pvt - > exten , cd - > call_dest_e164 , sizeof ( pvt - > exten ) - 1 ) ;
2003-03-31 07:13:36 +00:00
} else {
2005-05-19 16:17:08 +00:00
strncpy ( pvt - > exten , cd - > call_dest_alias , sizeof ( pvt - > exten ) - 1 ) ;
2003-03-31 07:13:36 +00:00
}
2004-05-03 22:19:03 +00:00
if ( ! ast_strlen_zero ( user - > accountcode ) ) {
2004-10-04 10:13:01 +00:00
strncpy ( pvt - > accountcode , user - > accountcode , sizeof ( pvt - > accountcode ) - 1 ) ;
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
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 )
ast_log ( LOG_DEBUG , " Preparing Asterisk to answer for %s \n " , token ) ;
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 */
strncpy ( tmp_exten , pvt - > exten , sizeof ( tmp_exten ) ) ;
/* 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 )
ast_log ( LOG_DEBUG , " Going to extension %s@%s because %s@%s isn't exists \n " , tmp_exten , pvt - > context , pvt - > exten , pvt - > context ) ;
strncpy ( pvt - > exten , tmp_exten , sizeof ( pvt - > exten ) ) ;
}
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
}
/**
* 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 ;
}
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 )
ast_log ( LOG_DEBUG , " Ringing on %s \n " , token ) ;
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
}
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 )
ast_log ( LOG_DEBUG , " Cleaning connection to %s \n " , call_token ) ;
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 )
2005-05-19 16:17:08 +00:00
ast_log ( LOG_DEBUG , " 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
# ifdef DEBUG_THREADS
2006-04-03 18:36:30 +00:00
ast_log ( LOG_NOTICE , " Avoiding H.323 destory deadlock on %s, locked at %ld/%d by %s (%s:%d) \n " , call_token , pvt - > owner - > lock . thread [ 0 ] , pvt - > owner - > lock . reentrancy , pvt - > owner - > lock . func [ 0 ] , pvt - > owner - > lock . file [ 0 ] , pvt - > owner - > lock . lineno [ 0 ] ) ;
2005-04-04 15:54:34 +00:00
# else
2005-05-19 16:17:08 +00:00
ast_log ( LOG_NOTICE , " Avoiding H.323 destory deadlock on %s \n " , call_token ) ;
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 ;
2004-10-04 10:13:01 +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 )
2005-05-19 16:17:08 +00:00
ast_log ( LOG_DEBUG , " 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
2006-09-19 17:07:22 +00:00
if ( h323debug ) {
ast_log ( LOG_DEBUG , " Hanging up connection to %s with cause %d \n " , token , cause ) ;
}
pvt = find_call_locked ( call_reference , token ) ;
2005-04-04 15:54:34 +00:00
if ( ! pvt ) {
2006-09-19 17:07:22 +00:00
if ( h323debug ) {
ast_log ( LOG_DEBUG , " 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 ;
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
}
else {
pvt - > needhangup = 1 ;
pvt - > hangupcause = cause ;
2006-09-19 17:07:22 +00:00
if ( h323debug )
ast_log ( LOG_DEBUG , " 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 )
2006-09-25 09:03:14 +00:00
ast_log ( LOG_DEBUG , " 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 )
ast_log ( LOG_DEBUG , " 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 )
ast_log ( LOG_DEBUG , " Got remote capabilities from connection %s \n " , token ) ;
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 ) {
ast_log ( LOG_DEBUG , " prefs[%d]=%s:%d \n " , i , ( prefs - > order [ i ] ? ast_getformatname ( 1 < < ( prefs - > order [ i ] - 1 ) ) : " <none> " ) , prefs - > framing [ i ] ) ;
}
}
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 )
ast_log ( LOG_DEBUG , " Setting capabilities for connection %s \n " , token ) ;
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 )
ast_log ( LOG_DEBUG , " Capabilities for connection %s is set \n " , token ) ;
}
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 ) {
if ( option_verbose > 0 ) {
ast_verbose ( VERBOSE_PREFIX_1 " Reloading H.323 \n " ) ;
2004-10-15 07:07:50 +00:00
}
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 )
{
2004-10-15 07:07:50 +00:00
pthread_attr_t attr ;
2003-03-31 07:13:36 +00:00
/* 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 {
pthread_attr_init ( & attr ) ;
pthread_attr_setdetachstate ( & attr , PTHREAD_CREATE_DETACHED ) ;
/* Start a new monitor */
if ( ast_pthread_create ( & monitor_thread , & attr , do_monitor , NULL ) < 0 ) {
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 ;
}
static int h323_do_trace ( int fd , int argc , char * argv [ ] )
{
2004-01-11 02:20:01 +00:00
if ( argc ! = 3 ) {
2003-03-31 07:13:36 +00:00
return RESULT_SHOWUSAGE ;
2004-01-11 02:20:01 +00:00
}
2003-03-31 07:13:36 +00:00
h323_debug ( 1 , atoi ( argv [ 2 ] ) ) ;
ast_cli ( fd , " H.323 trace set to level %s \n " , argv [ 2 ] ) ;
return RESULT_SUCCESS ;
}
static int h323_no_trace ( int fd , int argc , char * argv [ ] )
{
2004-01-11 02:20:01 +00:00
if ( argc ! = 3 ) {
2003-03-31 07:13:36 +00:00
return RESULT_SHOWUSAGE ;
2004-01-11 02:20:01 +00:00
}
2003-03-31 07:13:36 +00:00
h323_debug ( 0 , 0 ) ;
ast_cli ( fd , " H.323 trace disabled \n " ) ;
return RESULT_SUCCESS ;
}
static int h323_do_debug ( int fd , int argc , char * argv [ ] )
{
2004-01-11 02:20:01 +00:00
if ( argc ! = 2 ) {
2003-03-31 07:13:36 +00:00
return RESULT_SHOWUSAGE ;
2004-01-11 02:20:01 +00:00
}
2003-03-31 07:13:36 +00:00
h323debug = 1 ;
2006-09-19 17:07:22 +00:00
ast_cli ( fd , " H.323 debug enabled \n " ) ;
2003-03-31 07:13:36 +00:00
return RESULT_SUCCESS ;
}
static int h323_no_debug ( int fd , int argc , char * argv [ ] )
{
2004-01-11 02:20:01 +00:00
if ( argc ! = 3 ) {
2003-03-31 07:13:36 +00:00
return RESULT_SHOWUSAGE ;
2004-01-11 02:20:01 +00:00
}
2003-03-31 07:13:36 +00:00
h323debug = 0 ;
2006-09-19 17:07:22 +00:00
ast_cli ( fd , " H.323 debug disabled \n " ) ;
2003-03-31 07:13:36 +00:00
return RESULT_SUCCESS ;
}
static int h323_gk_cycle ( int fd , int argc , char * argv [ ] )
{
2004-01-11 02:20:01 +00:00
if ( argc ! = 3 ) {
2003-03-31 07:13:36 +00:00
return RESULT_SHOWUSAGE ;
2006-09-19 17:07:22 +00:00
}
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 " ) ;
}
}
2005-05-11 13:27:49 +00:00
return RESULT_SUCCESS ;
2003-03-31 07:13:36 +00:00
}
2004-01-06 16:51:34 +00:00
static int h323_ep_hangup ( int fd , int argc , char * argv [ ] )
{
2006-09-19 17:07:22 +00:00
if ( argc ! = 3 ) {
return RESULT_SHOWUSAGE ;
2004-01-11 02:20:01 +00:00
}
2004-01-06 16:51:34 +00:00
if ( h323_soft_hangup ( argv [ 2 ] ) ) {
ast_verbose ( VERBOSE_PREFIX_3 " Hangup succeeded on %s \n " , argv [ 2 ] ) ;
2006-09-19 17:07:22 +00:00
} else {
2004-01-06 16:51:34 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Hangup failed for %s \n " , argv [ 2 ] ) ;
}
return RESULT_SUCCESS ;
}
static int h323_tokens_show ( int fd , int argc , char * argv [ ] )
{
2006-09-19 17:07:22 +00:00
if ( argc ! = 3 ) {
return RESULT_SHOWUSAGE ;
2004-01-11 02:20:01 +00:00
}
2004-01-06 16:51:34 +00:00
h323_show_tokens ( ) ;
return RESULT_SUCCESS ;
}
2006-09-19 17:07:22 +00:00
static char trace_usage [ ] =
2006-09-22 20:33:47 +00:00
" Usage: h323 trace <level num> \n "
2003-03-31 07:13:36 +00:00
" Enables H.323 stack tracing for debugging purposes \n " ;
2006-09-19 17:07:22 +00:00
static char no_trace_usage [ ] =
2006-09-22 20:33:47 +00:00
" Usage: h323 no trace \n "
2003-03-31 07:13:36 +00:00
" Disables H.323 stack tracing for debugging purposes \n " ;
2006-09-19 17:07:22 +00:00
static char debug_usage [ ] =
2006-09-22 20:33:47 +00:00
" Usage: h323 debug \n "
2004-10-28 06:06:58 +00:00
" Enables H.323 debug output \n " ;
2003-03-31 07:13:36 +00:00
2006-09-19 17:07:22 +00:00
static char no_debug_usage [ ] =
2006-09-22 20:33:47 +00:00
" Usage: h323 no debug \n "
2004-10-28 06:06:58 +00:00
" Disables H.323 debug output \n " ;
2003-03-31 07:13:36 +00:00
2006-09-19 17:07:22 +00:00
static char show_cycle_usage [ ] =
2006-09-22 20:33:47 +00:00
" Usage: h323 gk cycle \n "
2004-10-28 06:06:58 +00:00
" Manually re-register with the Gatekeper (Currently Disabled) \n " ;
2003-03-31 07:13:36 +00:00
2006-09-19 17:07:22 +00:00
static char show_hangup_usage [ ] =
2006-09-22 20:33:47 +00:00
" Usage: h323 hangup <token> \n "
2004-01-06 16:51:34 +00:00
" Manually try to hang up call identified by <token> \n " ;
2006-09-19 17:07:22 +00:00
static char show_tokens_usage [ ] =
2006-09-22 20:33:47 +00:00
" Usage: h323 show tokens \n "
2004-01-06 16:51:34 +00:00
" Print out all active call tokens \n " ;
2003-03-31 07:13:36 +00:00
2004-10-15 07:07:50 +00:00
static char h323_reload_usage [ ] =
" Usage: h323 reload \n "
2006-09-19 17:07:22 +00:00
" Reloads H.323 configuration from h323.conf \n " ;
2004-10-15 07:07:50 +00:00
2006-09-22 20:33:47 +00:00
static struct ast_cli_entry cli_h323_trace_deprecated =
2006-09-18 19:54:18 +00:00
{ { " h.323 " , " trace " , NULL } ,
h323_do_trace , " Enable H.323 Stack Tracing " ,
2006-09-22 20:33:47 +00:00
trace_usage } ;
2006-09-18 19:54:18 +00:00
2006-09-22 20:33:47 +00:00
static struct ast_cli_entry cli_h323_no_trace_deprecated =
2006-09-18 19:54:18 +00:00
{ { " h.323 " , " no " , " trace " , NULL } ,
h323_no_trace , " Disable H.323 Stack Tracing " ,
2006-09-22 20:33:47 +00:00
no_trace_usage } ;
2006-09-18 19:54:18 +00:00
2006-09-22 20:33:47 +00:00
static struct ast_cli_entry cli_h323_debug_deprecated =
2006-09-18 19:54:18 +00:00
{ { " h.323 " , " debug " , NULL } ,
h323_do_debug , " Enable H.323 debug " ,
2006-09-22 20:33:47 +00:00
debug_usage } ;
2006-09-18 19:54:18 +00:00
2006-09-22 20:33:47 +00:00
static struct ast_cli_entry cli_h323_no_debug_deprecated =
2006-09-18 19:54:18 +00:00
{ { " h.323 " , " no " , " debug " , NULL } ,
h323_no_debug , " Disable H.323 debug " ,
2006-09-22 20:33:47 +00:00
no_debug_usage } ;
2006-09-18 19:54:18 +00:00
2006-09-22 20:33:47 +00:00
static struct ast_cli_entry cli_h323_gk_cycle_deprecated =
2006-09-18 19:54:18 +00:00
{ { " h.323 " , " gk " , " cycle " , NULL } ,
h323_gk_cycle , " Manually re-register with the Gatekeper " ,
2006-09-22 20:33:47 +00:00
show_cycle_usage } ;
2006-09-18 19:54:18 +00:00
2006-09-22 20:33:47 +00:00
static struct ast_cli_entry cli_h323_hangup_deprecated =
2006-09-18 19:54:18 +00:00
{ { " h.323 " , " hangup " , NULL } ,
h323_ep_hangup , " Manually try to hang up a call " ,
2006-09-22 20:33:47 +00:00
show_hangup_usage } ;
2006-09-18 19:54:18 +00:00
2006-09-22 20:33:47 +00:00
static struct ast_cli_entry cli_h323_show_tokens_deprecated =
2006-09-18 19:54:18 +00:00
{ { " h.323 " , " show " , " tokens " , NULL } ,
h323_tokens_show , " Show all active call tokens " ,
2006-09-22 20:33:47 +00:00
show_tokens_usage } ;
static struct ast_cli_entry cli_h323 [ ] = {
{ { " h323 " , " trace " , NULL } ,
h323_do_trace , " Enable H.323 Stack Tracing " ,
trace_usage , NULL , & cli_h323_trace_deprecated } ,
{ { " h323 " , " no " , " trace " , NULL } ,
h323_no_trace , " Disable H.323 Stack Tracing " ,
no_trace_usage , NULL , & cli_h323_no_trace_deprecated } ,
{ { " h323 " , " debug " , NULL } ,
h323_do_debug , " Enable H.323 debug " ,
debug_usage , NULL , & cli_h323_debug_deprecated } ,
{ { " h323 " , " no " , " debug " , NULL } ,
h323_no_debug , " Disable H.323 debug " ,
no_debug_usage , NULL , & cli_h323_no_debug_deprecated } ,
{ { " h323 " , " gk " , " cycle " , NULL } ,
h323_gk_cycle , " Manually re-register with the Gatekeper " ,
show_cycle_usage , NULL , & cli_h323_gk_cycle_deprecated } ,
{ { " h323 " , " hangup " , NULL } ,
h323_ep_hangup , " Manually try to hang up a call " ,
show_hangup_usage , NULL , & cli_h323_hangup_deprecated } ,
{ { " h323 " , " show " , " tokens " , NULL } ,
h323_tokens_show , " Show all active call tokens " ,
show_tokens_usage , NULL , & cli_h323_show_tokens_deprecated } ,
2006-09-18 19:54:18 +00:00
} ;
2004-03-20 14:25:39 +00:00
2006-09-19 17:07:22 +00:00
static int reload_config ( int is_reload )
2005-05-13 20:24:30 +00:00
{
2003-03-31 07:13:36 +00:00
int format ;
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 ;
2005-01-25 06:10:20 +00:00
cfg = ast_config_load ( config ) ;
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 ;
2003-03-31 07:13:36 +00:00
}
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-09-19 17:07:22 +00:00
strncpy ( _gatekeeper , gatekeeper , sizeof ( _gatekeeper ) ) ;
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-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-09-19 17:07:22 +00:00
strncpy ( default_context , " default " , sizeof ( default_context ) - 1 ) ;
h323_signalling_port = 1720 ;
gatekeeper_disable = 1 ;
gatekeeper_discover = 0 ;
gkroute = 0 ;
userbyalias = 1 ;
acceptAnonymous = 1 ;
tos = 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
/* Load configuration from users.conf */
ucfg = ast_config_load ( " users.conf " ) ;
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 ) ;
}
}
}
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 ) ) ;
}
} else if ( ! strcasecmp ( v - > name , " tos " ) ) {
2005-04-29 17:00:33 +00:00
if ( sscanf ( v - > value , " %d " , & format ) ) {
2003-03-31 07:13:36 +00:00
tos = format & 0xff ;
2004-10-22 19:04:02 +00:00
} else if ( ! strcasecmp ( v - > value , " lowdelay " ) ) {
2003-03-31 07:13:36 +00:00
tos = IPTOS_LOWDELAY ;
2004-10-22 19:04:02 +00:00
} else if ( ! strcasecmp ( v - > value , " throughput " ) ) {
2003-03-31 07:13:36 +00:00
tos = IPTOS_THROUGHPUT ;
2004-10-22 19:04:02 +00:00
} else if ( ! strcasecmp ( v - > value , " reliability " ) ) {
2003-03-31 07:13:36 +00:00
tos = IPTOS_RELIABILITY ;
2004-10-22 19:04:02 +00:00
} else if ( ! strcasecmp ( v - > value , " mincost " ) ) {
2003-03-31 07:13:36 +00:00
tos = IPTOS_MINCOST ;
2004-10-22 19:04:02 +00:00
} else if ( ! strcasecmp ( v - > value , " none " ) ) {
2003-03-31 07:13:36 +00:00
tos = 0 ;
2004-10-22 19:04:02 +00:00
} else {
2003-03-31 07:13:36 +00:00
ast_log ( LOG_WARNING , " Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', 'mincost', or 'none' \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 ;
2004-10-04 10:13:01 +00:00
strncpy ( gatekeeper , v - > value , sizeof ( gatekeeper ) - 1 ) ;
2003-03-31 07:13:36 +00:00
}
} else if ( ! strcasecmp ( v - > name , " secret " ) ) {
2004-10-28 06:06:58 +00:00
strncpy ( secret , v - > value , sizeof ( secret ) - 1 ) ;
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 " ) ) {
2004-10-04 10:13:01 +00:00
strncpy ( default_context , v - > value , sizeof ( default_context ) - 1 ) ;
2006-09-19 17:07:22 +00:00
ast_verbose ( VERBOSE_PREFIX_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-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 ;
}
2006-09-19 17:07:22 +00:00
static void delete_users ( void )
2003-03-31 07:13:36 +00:00
{
2006-09-19 17:07:22 +00:00
int pruned = 0 ;
2003-03-31 07:13:36 +00:00
/* Delete all users */
2006-09-19 17:07:22 +00:00
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 ) ;
2003-03-31 07:13:36 +00:00
}
2006-09-19 17:07:22 +00:00
ASTOBJ_CONTAINER_UNLOCK ( & aliasl ) ;
2003-03-31 07:13:36 +00:00
}
2006-09-19 17:07:22 +00:00
static void prune_peers ( void )
2003-03-31 07:13:36 +00:00
{
/* Prune peers who still are supposed to be deleted */
2006-09-19 17:07:22 +00:00
ASTOBJ_CONTAINER_PRUNE_MARKED ( & peerl , oh323_destroy_peer ) ;
2003-03-31 07:13:36 +00:00
}
2004-10-15 07:07:50 +00:00
static int h323_reload ( int fd , int argc , char * argv [ ] )
{
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
}
static int h323_do_reload ( void )
2003-03-31 07:13:36 +00:00
{
delete_users ( ) ;
2005-05-13 20:24:30 +00:00
delete_aliases ( ) ;
prune_peers ( ) ;
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
{
return h323_reload ( 0 , 0 , NULL ) ;
2003-03-31 07:13:36 +00:00
}
2006-09-22 20:33:47 +00:00
static struct ast_cli_entry cli_h323_reload_deprecated =
2006-09-19 17:07:22 +00:00
{ { " h.323 " , " reload " , NULL } ,
h323_reload , " Reload H.323 configuration " ,
h323_reload_usage
} ;
2006-09-22 20:33:47 +00:00
static struct ast_cli_entry cli_h323_reload =
{ { " h323 " , " reload " , NULL } ,
h323_reload , " Reload H.323 configuration " ,
h323_reload_usage , NULL , & cli_h323_reload_deprecated
} ;
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 ;
2006-09-19 17:07:22 +00:00
enum ast_rtp_get_result res = AST_RTP_GET_FAILED ;
if ( ! ( pvt = ( struct oh323_pvt * ) chan - > tech_pvt ) )
return res ;
ast_mutex_lock ( & pvt - > lock ) ;
if ( pvt - > rtp & & pvt - > options . bridge ) {
* rtp = pvt - > rtp ;
res = AST_RTP_TRY_NATIVE ;
2003-08-25 09:54:36 +00:00
}
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 " ;
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 ;
}
}
2006-04-03 18:36:30 +00:00
static int oh323_set_rtp_peer ( struct ast_channel * chan , struct ast_rtp * rtp , struct ast_rtp * vrtp , 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 ) {
2006-09-20 16:24:00 +00:00
ast_cli_unregister ( & cli_h323_reload ) ;
io_context_destroy ( io ) ;
sched_context_destroy ( sched ) ;
ASTOBJ_CONTAINER_DESTROY ( & userl ) ;
ASTOBJ_CONTAINER_DESTROY ( & peerl ) ;
ASTOBJ_CONTAINER_DESTROY ( & aliasl ) ;
return /*AST_MODULE_LOAD_DECLINE*/ AST_MODULE_LOAD_FAILURE ;
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 ,
set_peer_capabilities ) ;
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 ) ;
2003-03-31 07:13:36 +00:00
free ( pl ) ;
}
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 ( ) ;
2005-04-29 04:22:47 +00:00
io_context_destroy ( io ) ;
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
) ;