2003-03-31 07:13:36 +00:00
/*
2003-06-20 06:03:34 +00:00
* chan_h323 . c
2003-03-31 07:13:36 +00:00
*
* OpenH323 Channel Driver for ASTERISK PBX .
* By Jeremy McNamara
* For The NuFone Network
*
2003-07-23 19:55:13 +00:00
* This code has been derived from code created by
* Michael Manousos and Mark Spencer
2003-03-31 07:13:36 +00:00
*
* This file is part of the chan_h323 driver for Asterisk
*
* chan_h323 is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* chan_h323 is distributed WITHOUT ANY WARRANTY ; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE . See the GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*
2003-08-25 09:54:36 +00:00
* Version Info : $ Id $
2003-03-31 07:13:36 +00:00
*/
# include <stdio.h>
# include <pthread.h>
# include <string.h>
# include <asterisk/lock.h>
# include <asterisk/logger.h>
# include <asterisk/channel.h>
# include <asterisk/channel_pvt.h>
# include <asterisk/config.h>
# include <asterisk/module.h>
# include <asterisk/pbx.h>
# include <asterisk/options.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>
2003-12-23 23:01:24 +00:00
# include <asterisk/translate.h>
2003-03-31 07:13:36 +00:00
# include <sys/socket.h>
# include <net/if.h>
# include <errno.h>
# include <unistd.h>
# include <stdlib.h>
# include <fcntl.h>
# include <netdb.h>
# include <sys/signal.h>
# include <netinet/ip.h>
2003-08-16 17:00:22 +00:00
# include "h323/chan_h323.h"
2003-03-31 07:13:36 +00:00
2003-12-23 23:01:24 +00:00
# define TRUE 1
# define FALSE 0
/* from rtp.c to translate RTP's payload type to Asterisk's frame subcode */
struct rtpPayloadType {
int isAstFormat ; // whether the following code is an AST_FORMAT
int code ;
} ;
call_options_t global_options ;
static struct sockaddr_in bindaddr ;
2003-03-31 07:13:36 +00:00
/** String variables required by ASTERISK */
static char * type = " H323 " ;
static char * desc = " The NuFone Network's Open H.323 Channel Driver " ;
static char * tdesc = " The NuFone Network's Open H.323 Channel Driver " ;
static char * config = " h323.conf " ;
static char default_context [ AST_MAX_EXTENSION ] ;
/** H.323 configuration values */
static char gatekeeper [ 100 ] ;
static int gatekeeper_disable = 1 ;
static int gatekeeper_discover = 0 ;
static int usingGk ;
static int port = 1720 ;
static int gkroute = 0 ;
2003-12-09 05:14:23 +00:00
/* to find user by alias is default, alternative is the incomming call's source IP
address */
static int userbyalias = 1 ;
static int bridge_default = 1 ;
2003-03-31 07:13:36 +00:00
/* Just about everybody seems to support ulaw, so make it a nice default */
static int capability = AST_FORMAT_ULAW ;
/* TOS flag */
static int tos = 0 ;
static int dtmfmode = H323_DTMF_RFC2833 ;
static char secret [ 50 ] ;
/** Private structure of a OpenH323 channel */
struct oh323_pvt {
2003-08-14 06:56:11 +00:00
ast_mutex_t lock ; /* Channel private lock */
2003-07-23 02:00:28 +00:00
call_options_t calloptions ; /* Options to be used during call setup */
2003-03-31 07:13:36 +00:00
int alreadygone ; /* Whether or not we've already been destroyed by or peer */
int needdestroy ; /* if we need to be destroyed */
call_details_t cd ; /* Call details */
struct ast_channel * owner ; /* Who owns us */
int capability ; /* Special capability */
int nonCodecCapability ;
int outgoing ; /* Outgoing or incoming call? */
int nat ; /* Are we talking to a NAT EP?*/
int bridge ; /* Determine of we should native bridge or not*/
char exten [ AST_MAX_EXTENSION ] ; /* Requested extension */
char context [ AST_MAX_EXTENSION ] ; /* Context where to start */
2003-12-23 23:01:24 +00:00
char dnid [ AST_MAX_EXTENSION ] ; /* Called number */
char rdnis [ AST_MAX_EXTENSION ] ; /* Redirecting number */
2003-03-31 07:13:36 +00:00
char username [ 81 ] ; /* H.323 alias using this channel */
char accountcode [ 256 ] ; /* Account code */
int amaflags ; /* AMA Flags */
char callerid [ 80 ] ; /* Caller*ID if available */
struct ast_rtp * rtp ; /* RTP Session */
int dtmfmode ;
struct ast_dsp * vad ; /* Used for in-band DTMF detection */
struct oh323_pvt * next ; /* Next channel in list */
} * iflist = NULL ;
static struct ast_user_list {
struct oh323_user * users ;
2003-08-14 06:56:11 +00:00
ast_mutex_t lock ;
2003-03-31 07:13:36 +00:00
} userl = { NULL , AST_MUTEX_INITIALIZER } ;
static struct ast_peer_list {
struct oh323_peer * peers ;
2003-08-14 06:56:11 +00:00
ast_mutex_t lock ;
2003-03-31 07:13:36 +00:00
} peerl = { NULL , AST_MUTEX_INITIALIZER } ;
static struct ast_alias_list {
struct oh323_alias * aliases ;
2003-08-14 06:56:11 +00:00
ast_mutex_t lock ;
2003-03-31 07:13:36 +00:00
} aliasl = { NULL , AST_MUTEX_INITIALIZER } ;
/** Asterisk RTP stuff*/
static struct sched_context * sched ;
static struct io_context * io ;
/** Protect the interface list (of oh323_pvt's) */
2003-08-14 06:56:11 +00:00
static ast_mutex_t iflock = AST_MUTEX_INITIALIZER ;
2003-03-31 07:13:36 +00:00
/** Usage counter and associated lock */
static int usecnt = 0 ;
2003-08-14 06:56:11 +00:00
static ast_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER ;
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 . */
2003-08-14 06:56:11 +00:00
static ast_mutex_t monlock = AST_MUTEX_INITIALIZER ;
2003-03-31 07:13:36 +00:00
/* This is the thread for the monitor which checks for input on the channels
which are not currently in use . */
static pthread_t monitor_thread = 0 ;
static int restart_monitor ( void ) ;
static void __oh323_destroy ( struct oh323_pvt * p )
{
struct oh323_pvt * cur , * prev = NULL ;
if ( p - > rtp ) {
ast_rtp_destroy ( p - > rtp ) ;
}
/* Unlink us from the owner if we have one */
if ( p - > owner ) {
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & p - > owner - > lock ) ;
2003-03-31 07:13:36 +00:00
ast_log ( LOG_DEBUG , " Detaching from %s \n " , p - > owner - > name ) ;
p - > owner - > pvt - > pvt = NULL ;
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & p - > owner - > lock ) ;
2003-03-31 07:13:36 +00:00
}
cur = iflist ;
while ( cur ) {
if ( cur = = p ) {
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 ) ;
} else
free ( p ) ;
}
static void oh323_destroy ( struct oh323_pvt * p )
{
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & iflock ) ;
2003-03-31 07:13:36 +00:00
__oh323_destroy ( p ) ;
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & iflock ) ;
2003-03-31 07:13:36 +00:00
}
static struct oh323_alias * build_alias ( char * name , struct ast_variable * v )
{
struct oh323_alias * alias ;
alias = ( struct oh323_alias * ) malloc ( sizeof ( struct oh323_alias ) ) ;
if ( alias ) {
memset ( alias , 0 , sizeof ( struct oh323_alias ) ) ;
strncpy ( alias - > name , name , sizeof ( alias - > name ) - 1 ) ;
while ( v ) {
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 " ) ) {
2003-05-31 18:42:09 +00:00
strncpy ( alias - > secret , v - > value , sizeof ( alias - > secret ) - 1 ) ;
2003-12-03 20:08:58 +00:00
} else {
2003-12-18 19:48:42 +00:00
if ( strcasecmp ( v - > value , " h323 " ) ) {
2003-12-03 20:08:58 +00:00
ast_log ( LOG_WARNING , " Keyword %s does not make sense in type=h323 \n " , v - > value ) ;
2003-12-18 18:24:36 +00:00
}
2003-03-31 07:13:36 +00:00
}
v = v - > next ;
}
}
return alias ;
}
static struct oh323_user * build_user ( char * name , struct ast_variable * v )
{
struct oh323_user * user ;
int format ;
user = ( struct oh323_user * ) malloc ( sizeof ( struct oh323_user ) ) ;
if ( user ) {
memset ( user , 0 , sizeof ( struct oh323_user ) ) ;
strncpy ( user - > name , name , sizeof ( user - > name ) - 1 ) ;
/* set the usage flag to a sane starting value*/
user - > inUse = 0 ;
/* Assume we can native bridge */
2003-12-09 05:14:23 +00:00
user - > bridge = bridge_default ;
2003-03-31 07:13:36 +00:00
while ( v ) {
if ( ! strcasecmp ( v - > name , " context " ) ) {
strncpy ( user - > context , v - > value , sizeof ( user - > context ) - 1 ) ;
} else if ( ! strcasecmp ( v - > name , " bridge " ) ) {
user - > bridge = ast_true ( v - > value ) ;
2003-09-22 06:21:03 +00:00
} else if ( ! strcasecmp ( v - > name , " nat " ) ) {
user - > nat = ast_true ( v - > value ) ;
2003-03-31 07:13:36 +00:00
} else if ( ! strcasecmp ( v - > name , " noFastStart " ) ) {
2003-12-23 23:01:24 +00:00
user - > call_options . noFastStart = ast_true ( v - > value ) ;
2003-03-31 07:13:36 +00:00
} else if ( ! strcasecmp ( v - > name , " noH245Tunneling " ) ) {
2003-12-23 23:01:24 +00:00
user - > call_options . noH245Tunnelling = ast_true ( v - > value ) ;
2003-03-31 07:13:36 +00:00
} else if ( ! strcasecmp ( v - > name , " noSilenceSuppression " ) ) {
2003-12-23 23:01:24 +00:00
user - > call_options . noSilenceSuppression = ast_true ( v - > value ) ;
2003-03-31 07:13:36 +00:00
} else if ( ! strcasecmp ( v - > name , " secret " ) ) {
strncpy ( user - > secret , v - > value , sizeof ( user - > secret ) - 1 ) ;
2003-07-23 19:55:13 +00:00
} else if ( ! strcasecmp ( v - > name , " callerid " ) ) {
strncpy ( user - > callerid , v - > value , sizeof ( user - > callerid ) - 1 ) ;
2003-03-31 07:13:36 +00:00
} else if ( ! strcasecmp ( v - > name , " accountcode " ) ) {
strncpy ( user - > accountcode , v - > value , sizeof ( user - > accountcode ) - 1 ) ;
2003-12-23 23:01:24 +00:00
} else if ( ! strcasecmp ( v - > name , " progress_setup " ) ) {
int progress_setup = atoi ( v - > value ) ;
if ( ( progress_setup ! = 0 ) & &
( progress_setup ! = 1 ) & &
( progress_setup ! = 3 ) & &
( progress_setup ! = 8 ) ) {
ast_log ( LOG_WARNING , " Invalid value %d for progress_setup at line %d, assuming 0 \n " , progress_setup , v - > lineno ) ;
progress_setup = 0 ;
}
user - > call_options . progress_setup = progress_setup ;
} else if ( ! strcasecmp ( v - > name , " progress_alert " ) ) {
int progress_alert = atoi ( v - > value ) ;
if ( ( progress_alert ! = 0 ) & &
( progress_alert ! = 8 ) ) {
ast_log ( LOG_WARNING , " Invalid value %d for progress_alert at line %d, assuming 0 \n " , progress_alert , v - > lineno ) ;
progress_alert = 0 ;
}
user - > call_options . progress_alert = progress_alert ;
} else if ( ! strcasecmp ( v - > name , " progress_audio " ) ) {
user - > call_options . progress_audio = ast_true ( v - > value ) ;
2003-03-31 07:13:36 +00:00
} else if ( ! strcasecmp ( v - > name , " incominglimit " ) ) {
user - > incominglimit = atoi ( v - > value ) ;
if ( user - > incominglimit < 0 )
user - > incominglimit = 0 ;
} else if ( ! strcasecmp ( v - > name , " host " ) ) {
if ( ! strcasecmp ( v - > value , " dynamic " ) ) {
ast_log ( LOG_ERROR , " Dynamic host configuration not implemented, yet! \n " ) ;
free ( user ) ;
return NULL ;
} else if ( ast_get_ip ( & user - > addr , v - > value ) ) {
free ( user ) ;
return NULL ;
}
2003-03-31 20:26:08 +00:00
/* Let us know we need to use ip authentication */
user - > host = 1 ;
2003-03-31 07:13:36 +00:00
} 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 ;
}
}
v = v - > next ;
}
}
return user ;
}
static struct oh323_peer * build_peer ( char * name , struct ast_variable * v )
{
struct oh323_peer * peer ;
struct oh323_peer * prev ;
int found = 0 ;
prev = NULL ;
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & peerl . lock ) ;
2003-03-31 07:13:36 +00:00
peer = peerl . peers ;
while ( peer ) {
if ( ! strcasecmp ( peer - > name , name ) ) {
break ;
}
prev = peer ;
peer = peer - > next ;
}
if ( peer ) {
found + + ;
/* Already in the list, remove it and it will be added back (or FREE'd) */
if ( prev ) {
prev - > next = peer - > next ;
} else {
peerl . peers = peer - > next ;
}
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & peerl . lock ) ;
2003-03-31 07:13:36 +00:00
} else {
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & peerl . lock ) ;
2003-03-31 07:13:36 +00:00
peer = malloc ( sizeof ( struct oh323_peer ) ) ;
memset ( peer , 0 , sizeof ( struct oh323_peer ) ) ;
}
if ( peer ) {
if ( ! found ) {
strncpy ( peer - > name , name , sizeof ( peer - > name ) - 1 ) ;
}
/* set the usage flag to a sane starting value*/
peer - > inUse = 0 ;
while ( v ) {
if ( ! strcasecmp ( v - > name , " context " ) ) {
strncpy ( peer - > context , v - > value , sizeof ( peer - > context ) - 1 ) ;
} else if ( ! strcasecmp ( v - > name , " bridge " ) ) {
peer - > bridge = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " noFastStart " ) ) {
2003-12-23 23:01:24 +00:00
peer - > call_options . noFastStart = ast_true ( v - > value ) ;
2003-03-31 07:13:36 +00:00
} else if ( ! strcasecmp ( v - > name , " noH245Tunneling " ) ) {
2003-12-23 23:01:24 +00:00
peer - > call_options . noH245Tunnelling = ast_true ( v - > value ) ;
2003-03-31 07:13:36 +00:00
} else if ( ! strcasecmp ( v - > name , " noSilenceSuppression " ) ) {
2003-12-23 23:01:24 +00:00
peer - > call_options . noSilenceSuppression = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " progress_setup " ) ) {
int progress_setup = atoi ( v - > value ) ;
if ( ( progress_setup ! = 0 ) & &
( progress_setup ! = 1 ) & &
( progress_setup ! = 3 ) & &
( progress_setup ! = 8 ) ) {
ast_log ( LOG_WARNING , " Invalid value %d for progress_setup at line %d, assuming 0 \n " , progress_setup , v - > lineno ) ;
progress_setup = 0 ;
}
peer - > call_options . progress_setup = progress_setup ;
} else if ( ! strcasecmp ( v - > name , " progress_alert " ) ) {
int progress_alert = atoi ( v - > value ) ;
if ( ( progress_alert ! = 0 ) & &
( progress_alert ! = 8 ) ) {
ast_log ( LOG_WARNING , " Invalid value %d for progress_alert at line %d, assuming 0 \n " , progress_alert , v - > lineno ) ;
progress_alert = 0 ;
}
peer - > call_options . progress_alert = progress_alert ;
} else if ( ! strcasecmp ( v - > name , " progress_audio " ) ) {
peer - > call_options . progress_audio = ast_true ( v - > value ) ;
2003-03-31 07:13:36 +00:00
} else if ( ! strcasecmp ( v - > name , " outgoinglimit " ) ) {
peer - > outgoinglimit = atoi ( v - > value ) ;
if ( peer - > outgoinglimit > 0 )
peer - > outgoinglimit = 0 ;
} else if ( ! strcasecmp ( v - > name , " host " ) ) {
if ( ! strcasecmp ( v - > value , " dynamic " ) ) {
ast_log ( LOG_ERROR , " Dynamic host configuration not implemented, yet! \n " ) ;
free ( peer ) ;
return NULL ;
}
if ( ast_get_ip ( & peer - > addr , v - > value ) ) {
free ( peer ) ;
return NULL ;
}
}
v = v - > next ;
}
}
return peer ;
}
/**
* Send ( play ) the specified digit to the channel .
*
*/
static int oh323_digit ( struct ast_channel * c , char digit )
{
struct oh323_pvt * p = c - > pvt - > pvt ;
if ( p & & p - > rtp & & ( p - > dtmfmode & H323_DTMF_RFC2833 ) ) {
ast_rtp_senddigit ( p - > rtp , digit ) ;
}
/* If in-band DTMF is desired, send that */
if ( p - > dtmfmode & H323_DTMF_INBAND )
h323_send_tone ( p - > cd . call_token , digit ) ;
return 0 ;
}
/**
* Make a call over the specified channel to the specified
* destination . This function will parse the destination string
* and determine the address - number to call .
* Return - 1 on error , 0 on success .
*/
static int oh323_call ( struct ast_channel * c , char * dest , int timeout )
{
int res ;
struct oh323_pvt * p = c - > pvt - > pvt ;
char called_addr [ 256 ] ;
2003-06-03 07:11:52 +00:00
char * tmp ;
2003-03-31 07:13:36 +00:00
2003-06-03 07:11:52 +00:00
strtok_r ( dest , " / " , & ( tmp ) ) ;
2003-03-31 07:13:36 +00:00
ast_log ( LOG_DEBUG , " dest=%s, timeout=%d. \n " , dest , timeout ) ;
if ( ( c - > _state ! = AST_STATE_DOWN ) & & ( c - > _state ! = AST_STATE_RESERVED ) ) {
ast_log ( LOG_WARNING , " Line is already in use (%s) \n " , c - > name ) ;
return - 1 ;
}
/* outgoing call */
p - > outgoing = 1 ;
/* Clear the call token */
if ( ( p - > cd ) . call_token = = NULL )
( p - > cd ) . call_token = ( char * ) malloc ( 128 ) ;
memset ( ( char * ) ( p - > cd ) . call_token , 0 , 128 ) ;
if ( p - > cd . call_token = = NULL ) {
ast_log ( LOG_ERROR , " Not enough memory. \n " ) ;
return - 1 ;
}
/* Build the address to call */
memset ( called_addr , 0 , sizeof ( dest ) ) ;
memcpy ( called_addr , dest , sizeof ( called_addr ) ) ;
2003-07-23 02:00:28 +00:00
/* Copy callerid, if there is any */
2003-07-31 06:28:51 +00:00
if ( c - > callerid ) {
2003-08-09 20:18:54 +00:00
char * tmp = strchr ( c - > callerid , ' " ' ) ;
if ( ! tmp ) {
p - > calloptions . callerid = malloc ( 80 ) ; // evil
// sprintf(p->calloptions.callerid, "\"%s\"", c->callerid);
sprintf ( p - > calloptions . callerid , " \" \" <%s> " , c - > callerid ) ;
} else {
p - > calloptions . callerid = strdup ( c - > callerid ) ;
}
2003-12-23 23:01:24 +00:00
}
2003-07-24 21:26:24 +00:00
2003-12-23 23:01:24 +00:00
res = h323_make_call ( called_addr , & ( p - > cd ) , & p - > calloptions ) ;
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 ;
}
2003-12-23 23:01:24 +00:00
ast_setstate ( c , AST_STATE_RING ) ;
2003-03-31 07:13:36 +00:00
return 0 ;
}
static int oh323_answer ( struct ast_channel * c )
{
int res ;
struct oh323_pvt * p = c - > pvt - > pvt ;
res = h323_answering_call ( p - > cd . call_token , 0 ) ;
if ( c - > _state ! = AST_STATE_UP )
ast_setstate ( c , AST_STATE_UP ) ;
return res ;
}
static int oh323_hangup ( struct ast_channel * c )
{
struct oh323_pvt * p = c - > pvt - > pvt ;
int needcancel = 0 ;
if ( h323debug )
ast_log ( LOG_DEBUG , " oh323_hangup(%s) \n " , c - > name ) ;
if ( ! c - > pvt - > pvt ) {
ast_log ( LOG_DEBUG , " Asked to hangup channel not connected \n " ) ;
return 0 ;
}
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & p - > lock ) ;
2003-03-31 07:13:36 +00:00
/* Determine how to disconnect */
if ( p - > owner ! = c ) {
ast_log ( LOG_WARNING , " Huh? We aren't the owner? \n " ) ;
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2003-03-31 07:13:36 +00:00
return 0 ;
}
if ( ! c | | ( c - > _state ! = AST_STATE_UP ) )
needcancel = 1 ;
/* Disconnect */
p = c - > pvt - > pvt ;
/* Free dsp used for in-band DTMF detection */
if ( p - > vad ) {
ast_dsp_free ( p - > vad ) ;
}
p - > owner = NULL ;
c - > pvt - > pvt = NULL ;
/* Start the process if it's not already started */
if ( ! p - > alreadygone ) {
if ( h323_clear_call ( ( p - > cd ) . call_token ) )
ast_log ( LOG_DEBUG , " ClearCall failed. \n " ) ;
p - > needdestroy = 1 ;
}
2003-04-23 21:52:46 +00:00
/* Update usage counter */
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & usecnt_lock ) ;
2003-04-23 21:52:46 +00:00
usecnt - - ;
if ( usecnt < 0 )
ast_log ( LOG_WARNING , " Usecnt < 0 \n " ) ;
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & usecnt_lock ) ;
2003-04-23 21:52:46 +00:00
ast_update_use_count ( ) ;
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2003-03-31 07:13:36 +00:00
return 0 ;
}
2003-12-23 23:01:24 +00:00
/* Pass channel struct too to allow RTCP handling */
static struct ast_frame * oh323_rtp_read ( struct ast_channel * c , struct oh323_pvt * p )
2003-03-31 07:13:36 +00:00
{
/* Retrieve audio/etc from channel. Assumes p->lock is already held. */
struct ast_frame * f ;
static struct ast_frame null_frame = { AST_FRAME_NULL , } ;
2003-09-22 06:21:03 +00:00
2003-12-23 23:01:24 +00:00
/* Only apply it for the first packet, we just need the correct ip/port */
if ( p - > nat )
{
ast_rtp_setnat ( p - > rtp , p - > nat ) ;
p - > nat = 0 ;
}
switch ( c - > fdno ) {
case 0 : /* RTP stream */
f = ast_rtp_read ( p - > rtp ) ;
break ;
case 1 : /* RTCP stream */
f = ast_rtcp_read ( p - > rtp ) ;
break ;
default :
f = & null_frame ;
}
2003-09-22 06:21:03 +00:00
2003-03-31 07:13:36 +00:00
/* Don't send RFC2833 if we're not supposed to */
if ( f & & ( f - > frametype = = AST_FRAME_DTMF ) & & ! ( p - > dtmfmode & H323_DTMF_RFC2833 ) )
return & null_frame ;
if ( p - > owner ) {
/* We already hold the channel lock */
if ( f - > frametype = = AST_FRAME_VOICE ) {
if ( f - > subclass ! = p - > owner - > nativeformats ) {
2003-12-23 23:01:24 +00:00
/* Must be handled on opening logical channel */
2003-03-31 07:13:36 +00:00
ast_log ( LOG_DEBUG , " Oooh, format changed to %d \n " , f - > subclass ) ;
p - > owner - > nativeformats = f - > subclass ;
ast_set_read_format ( p - > owner , p - > owner - > readformat ) ;
2003-12-23 23:01:24 +00:00
/* Don't set write format because it will be set up when channel started */
// ast_set_write_format(p->owner, p->owner->writeformat);
2003-03-31 07:13:36 +00:00
}
/* Do in-band DTMF detection */
if ( p - > dtmfmode & H323_DTMF_INBAND ) {
f = ast_dsp_process ( p - > owner , p - > vad , f , 0 ) ;
if ( f - > frametype = = AST_FRAME_DTMF )
ast_log ( LOG_DEBUG , " Got in-band digit %c. \n " , f - > subclass ) ;
}
}
}
return f ;
}
static struct ast_frame * oh323_read ( struct ast_channel * c )
{
struct ast_frame * fr ;
struct oh323_pvt * p = c - > pvt - > pvt ;
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & p - > lock ) ;
2003-12-23 23:01:24 +00:00
/* Pass channel structure to handle other streams than just RTP */
fr = oh323_rtp_read ( c , p ) ;
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2003-03-31 07:13:36 +00:00
return fr ;
}
static int oh323_write ( struct ast_channel * c , struct ast_frame * frame )
{
struct oh323_pvt * p = c - > pvt - > pvt ;
int res = 0 ;
2003-12-23 23:01:24 +00:00
int need_frfree = 0 ; /* Does ast_frfree() call required? */
2003-03-31 07:13:36 +00:00
if ( frame - > frametype ! = AST_FRAME_VOICE ) {
if ( frame - > frametype = = AST_FRAME_IMAGE )
return 0 ;
else {
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-23 23:01:24 +00:00
if ( ! ( frame - > subclass & c - > writeformat ) ) { /* Someone sent frame with old format */
ast_log ( LOG_WARNING , " Asked to transmit frame type %s from %s by '%s', while native formats is %s (read/write = %s/%s) \n " ,
ast_getformatname ( frame - > subclass ) , frame - > src , c - > name , ast_getformatname ( c - > nativeformats ) , ast_getformatname ( c - > readformat ) , ast_getformatname ( c - > writeformat ) ) ;
return ( c - > nativeformats ? 0 : - 1 ) ;
} else {
/* Frame goes from RTP is not in our native
* format - try to translate it . . . Or we must
* just drop it ?
*/
/* Sometimes translation table isn't set
* correctly but writeformat is invalid ,
* so force required translation allocation
*/
ast_set_write_format ( c , c - > nativeformats ) ;
ast_set_write_format ( c , frame - > subclass ) ;
/* Translate it on-the-fly */
if ( c - > pvt - > writetrans ) {
struct ast_frame * frame1 ;
ast_log ( LOG_WARNING , " Asked to transmit frame type %s from %s by '%s', while native formats is %s (read/write = %s/%s) - 2 TRANSLATE \n " ,
ast_getformatname ( frame - > subclass ) , frame - > src , c - > name , ast_getformatname ( c - > nativeformats ) , ast_getformatname ( c - > readformat ) , ast_getformatname ( c - > writeformat ) ) ;
/* Allocate new frame with translated context.
* Don ' t free frame because it will be freed on
* upper layer ( RTP ) .
*/
frame1 = ast_translate ( c - > pvt - > writetrans , frame , 0 ) ;
if ( frame1 ) {
/* Substitute passed frame with translated and
mark it for freeing before return */
frame = frame1 ;
need_frfree = 1 ;
}
else
ast_log ( LOG_WARNING , " Unable to translate frame type %s to %s \n " , ast_getformatname ( frame - > subclass ) , ast_getformatname ( c - > nativeformats ) ) ;
} else {
ast_log ( LOG_WARNING , " Asked to transmit frame type %s from %s by '%s', while native formats is %s (read/write = %s/%s) \n " ,
ast_getformatname ( frame - > subclass ) , frame - > src , c - > name , ast_getformatname ( c - > nativeformats ) , ast_getformatname ( c - > readformat ) , ast_getformatname ( c - > writeformat ) ) ;
return - 1 ;
}
}
2003-03-31 07:13:36 +00:00
}
}
if ( p ) {
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & p - > lock ) ;
2003-03-31 07:13:36 +00:00
if ( p - > rtp ) {
res = ast_rtp_write ( p - > rtp , frame ) ;
}
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2003-03-31 07:13:36 +00:00
}
2003-12-23 23:01:24 +00:00
/* Free translated frame */
if ( need_frfree )
ast_frfree ( frame ) ;
2003-03-31 07:13:36 +00:00
return res ;
}
/** FIXME: Can I acutally use this or does Open H.323 take care of everything? */
static int oh323_indicate ( struct ast_channel * c , int condition )
{
struct oh323_pvt * p = c - > pvt - > pvt ;
switch ( condition ) {
case AST_CONTROL_RINGING :
if ( c - > _state = = AST_STATE_RING ) {
// transmit_response(p, "180 Ringing", &p->initreq);
break ;
}
2003-09-29 09:01:51 +00:00
return 0 ;
2003-03-31 07:13:36 +00:00
case AST_CONTROL_BUSY :
if ( c - > _state ! = AST_STATE_UP ) {
// transmit_response(p, "600 Busy everywhere", &p->initreq);
p - > alreadygone = 1 ;
ast_softhangup ( c , AST_SOFTHANGUP_DEV ) ;
break ;
}
2003-09-29 09:01:51 +00:00
return 0 ;
2003-03-31 07:13:36 +00:00
case AST_CONTROL_CONGESTION :
if ( c - > _state ! = AST_STATE_UP ) {
// transmit_response(p, "486 Busy here", &p->initreq);
p - > alreadygone = 1 ;
ast_softhangup ( c , AST_SOFTHANGUP_DEV ) ;
break ;
}
2003-09-29 09:01:51 +00:00
return 0 ;
2003-03-31 07:13:36 +00:00
case - 1 :
2003-12-23 23:01:24 +00:00
return 0 ;
2003-03-31 07:13:36 +00:00
default :
ast_log ( LOG_WARNING , " Don't know how to indicate condition %d \n " , condition ) ;
return - 1 ;
}
return 0 ;
}
// FIXME: WTF is this? Do I need this???
static int oh323_fixup ( struct ast_channel * oldchan , struct ast_channel * newchan )
{
struct oh323_pvt * p = newchan - > pvt - > pvt ;
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & p - > lock ) ;
2003-03-31 07:13:36 +00:00
if ( p - > owner ! = oldchan ) {
ast_log ( LOG_WARNING , " old channel wasn't %p but was %p \n " , oldchan , p - > owner ) ;
return - 1 ;
}
p - > owner = newchan ;
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2003-03-31 07:13:36 +00:00
return 0 ;
}
static struct ast_channel * oh323_new ( struct oh323_pvt * i , int state , const char * host )
{
2003-08-16 17:00:22 +00:00
struct ast_channel * ch ;
2003-03-31 07:13:36 +00:00
int fmt ;
2003-08-16 17:00:22 +00:00
ch = ast_channel_alloc ( 1 ) ;
2003-03-31 07:13:36 +00:00
2003-08-16 17:00:22 +00:00
if ( ch ) {
2003-03-31 07:13:36 +00:00
2003-12-23 23:01:24 +00:00
// snprintf(ch->name, sizeof(ch->name)-1, "H323/%s-%04x", host, rand() & 0xffff);
2003-08-16 17:00:22 +00:00
snprintf ( ch - > name , sizeof ( ch - > name ) - 1 , " H323/%s " , host ) ;
ch - > nativeformats = i - > capability ;
if ( ! ch - > nativeformats )
ch - > nativeformats = capability ;
fmt = ast_best_codec ( ch - > nativeformats ) ;
ch - > type = type ;
2003-12-23 23:01:24 +00:00
/* RTP stream */
2003-08-16 17:00:22 +00:00
ch - > fds [ 0 ] = ast_rtp_fd ( i - > rtp ) ;
2003-12-23 23:01:24 +00:00
/* RTCP stream */
ch - > fds [ 1 ] = ast_rtcp_fd ( i - > rtp ) ;
2003-08-16 17:00:22 +00:00
ast_setstate ( ch , state ) ;
2003-03-31 07:13:36 +00:00
if ( state = = AST_STATE_RING )
2003-08-16 17:00:22 +00:00
ch - > rings = 1 ;
2003-03-31 07:13:36 +00:00
2003-08-16 17:00:22 +00:00
ch - > writeformat = fmt ;
ch - > pvt - > rawwriteformat = fmt ;
ch - > readformat = fmt ;
ch - > pvt - > rawreadformat = fmt ;
2003-03-31 07:13:36 +00:00
/* Allocate dsp for in-band DTMF support */
if ( i - > dtmfmode & H323_DTMF_INBAND ) {
i - > vad = ast_dsp_new ( ) ;
ast_dsp_set_features ( i - > vad , DSP_FEATURE_DTMF_DETECT ) ;
2003-08-16 17:00:22 +00:00
}
2003-03-31 07:13:36 +00:00
/* Register the OpenH323 channel's functions. */
2003-08-16 17:00:22 +00:00
ch - > pvt - > pvt = i ;
ch - > pvt - > send_digit = oh323_digit ;
ch - > pvt - > call = oh323_call ;
ch - > pvt - > hangup = oh323_hangup ;
ch - > pvt - > answer = oh323_answer ;
ch - > pvt - > read = oh323_read ;
ch - > pvt - > write = oh323_write ;
ch - > pvt - > indicate = oh323_indicate ;
ch - > pvt - > fixup = oh323_fixup ;
2003-08-25 09:54:36 +00:00
// ch->pvt->bridge = ast_rtp_bridge;
2003-03-31 07:13:36 +00:00
/* Set the owner of this channel */
2003-08-16 17:00:22 +00:00
i - > owner = ch ;
2003-03-31 07:13:36 +00:00
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & usecnt_lock ) ;
2003-03-31 07:13:36 +00:00
usecnt + + ;
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & usecnt_lock ) ;
2003-03-31 07:13:36 +00:00
ast_update_use_count ( ) ;
2003-08-16 17:00:22 +00:00
strncpy ( ch - > context , i - > context , sizeof ( ch - > context ) - 1 ) ;
strncpy ( ch - > exten , i - > exten , sizeof ( ch - > exten ) - 1 ) ;
ch - > priority = 1 ;
2003-03-31 07:13:36 +00:00
if ( strlen ( i - > callerid ) )
2003-08-16 17:00:22 +00:00
ch - > callerid = strdup ( i - > callerid ) ;
2003-12-23 23:01:24 +00:00
if ( strlen ( i - > dnid ) )
ch - > dnid = strdup ( i - > dnid ) ;
if ( strlen ( i - > rdnis ) )
ch - > rdnis = strdup ( i - > rdnis ) ;
2003-04-11 04:07:22 +00:00
if ( strlen ( i - > accountcode ) )
2003-08-16 17:00:22 +00:00
strncpy ( ch - > accountcode , i - > accountcode , sizeof ( ch - > accountcode ) - 1 ) ;
2003-04-11 04:07:22 +00:00
if ( i - > amaflags )
2003-08-16 17:00:22 +00:00
ch - > amaflags = i - > amaflags ;
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 ) ;
ch = NULL ;
2003-03-31 07:13:36 +00:00
}
}
} else
ast_log ( LOG_WARNING , " Unable to allocate channel structure \n " ) ;
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 )
{
struct oh323_pvt * p ;
p = malloc ( sizeof ( struct oh323_pvt ) ) ;
if ( ! p ) {
ast_log ( LOG_ERROR , " Couldn't allocate private structure. This is bad \n " ) ;
return NULL ;
}
/* Keep track of stuff */
memset ( p , 0 , sizeof ( struct oh323_pvt ) ) ;
2003-07-01 19:11:37 +00:00
p - > rtp = ast_rtp_new ( sched , io , 1 , 0 ) ;
2003-03-31 07:13:36 +00:00
if ( ! p - > rtp ) {
ast_log ( LOG_WARNING , " Unable to create RTP session: %s \n " , strerror ( errno ) ) ;
free ( p ) ;
return NULL ;
}
ast_rtp_settos ( p - > rtp , tos ) ;
2003-08-14 06:56:11 +00:00
ast_mutex_init ( & p - > lock ) ;
2003-03-31 07:13:36 +00:00
p - > cd . call_reference = callid ;
2003-12-09 05:14:23 +00:00
p - > bridge = bridge_default ;
2003-12-23 23:01:24 +00:00
memcpy ( & p - > calloptions , & global_options , sizeof ( global_options ) ) ;
2003-03-31 07:13:36 +00:00
p - > dtmfmode = dtmfmode ;
if ( p - > dtmfmode & H323_DTMF_RFC2833 )
p - > nonCodecCapability | = AST_RTP_DTMF ;
/* Add to interface list */
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & iflock ) ;
2003-03-31 07:13:36 +00:00
p - > next = iflist ;
iflist = p ;
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & iflock ) ;
2003-03-31 07:13:36 +00:00
return p ;
}
static struct oh323_pvt * find_call ( int call_reference )
{
struct oh323_pvt * p ;
2003-12-23 23:01:24 +00:00
ast_mutex_lock ( & iflock ) ;
2003-03-31 07:13:36 +00:00
p = iflist ;
while ( p ) {
if ( p - > cd . call_reference = = call_reference ) {
/* Found the call */
2003-12-23 23:01:24 +00:00
ast_mutex_unlock ( & iflock ) ;
return p ;
2003-03-31 07:13:36 +00:00
}
p = p - > next ;
}
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & iflock ) ;
2003-12-23 23:01:24 +00:00
return NULL ;
2003-03-31 07:13:36 +00:00
}
static struct ast_channel * oh323_request ( char * type , int format , void * data )
{
int oldformat ;
struct oh323_pvt * p ;
struct ast_channel * tmpc = NULL ;
char * dest = data ;
char * ext , * host ;
2003-06-03 07:11:52 +00:00
char * h323id = NULL ;
2003-03-31 07:13:36 +00:00
char tmp [ 256 ] ;
2003-06-03 07:11:52 +00:00
2003-03-31 07:13:36 +00:00
ast_log ( LOG_DEBUG , " type=%s, format=%d, data=%s. \n " , type , format , ( char * ) data ) ;
oldformat = format ;
format & = capability ;
if ( ! format ) {
ast_log ( LOG_NOTICE , " Asked to get a channel of unsupported format '%d' \n " , format ) ;
return NULL ;
}
strncpy ( tmp , dest , sizeof ( tmp ) - 1 ) ;
2003-06-03 07:11:52 +00:00
2003-03-31 07:13:36 +00:00
host = strchr ( tmp , ' @ ' ) ;
if ( host ) {
* host = ' \0 ' ;
host + + ;
ext = tmp ;
} else {
host = tmp ;
ext = NULL ;
}
2003-04-08 18:22:39 +00:00
2003-06-03 07:11:52 +00:00
strtok_r ( host , " / " , & ( h323id ) ) ;
if ( * h323id ) {
h323_set_id ( h323id ) ;
}
2003-03-31 07:13:36 +00:00
p = oh323_alloc ( 0 ) ;
if ( ! p ) {
ast_log ( LOG_WARNING , " Unable to build pvt data for '%s' \n " , ( char * ) data ) ;
return NULL ;
}
/* Assign a default capability */
p - > capability = capability ;
if ( p - > dtmfmode ) {
if ( p - > dtmfmode & H323_DTMF_RFC2833 )
p - > nonCodecCapability | = AST_RTP_DTMF ;
else
p - > nonCodecCapability & = ~ AST_RTP_DTMF ;
}
ast_log ( LOG_DEBUG , " Host: %s \t Username: %s \n " , host , p - > username ) ;
if ( ext )
strncpy ( p - > username , ext , sizeof ( p - > username ) - 1 ) ;
tmpc = oh323_new ( p , AST_STATE_DOWN , host ) ;
if ( ! tmpc )
oh323_destroy ( p ) ;
restart_monitor ( ) ;
return tmpc ;
}
2003-12-23 23:01:24 +00:00
struct oh323_alias * find_alias ( call_details_t cd )
2003-03-31 07:13:36 +00:00
{
2003-12-23 23:01:24 +00:00
struct oh323_alias * a , * a_e164 = NULL , * a_pfx = NULL ;
char * s , * p ;
int a_pfxlen , numlen ;
2003-03-31 07:13:36 +00:00
a = aliasl . aliases ;
2003-12-23 23:01:24 +00:00
a_pfxlen = 0 ;
numlen = strlen ( cd . call_dest_e164 ) ;
2003-03-31 07:13:36 +00:00
while ( a ) {
2003-12-23 23:01:24 +00:00
if ( ! strcasecmp ( a - > name , cd . call_dest_alias ) ) {
2003-03-31 07:13:36 +00:00
break ;
}
2003-12-23 23:01:24 +00:00
/* Check for match of E164 number */
if ( ! strcasecmp ( a - > e164 , cd . call_dest_e164 ) )
a_e164 = a ;
else { /* Check for match called number with prefixes */
for ( s = a - > prefix ; * s ; ) {
for ( ; * s = = ' ' ; + + s ) ;
if ( ! ( p = strchr ( s , ' , ' ) ) )
p = s + strlen ( s ) ;
if ( ( p - s > a_pfxlen ) & & ( numlen > = p - s ) & & ( strncasecmp ( s , cd . call_dest_e164 , p - s ) = = 0 ) ) {
a_pfxlen = p - s ;
a_pfx = a ;
}
s = p ;
if ( * s = = ' , ' )
+ + s ;
}
}
2003-03-31 07:13:36 +00:00
a = a - > next ;
}
2003-12-23 23:01:24 +00:00
if ( a )
return a ;
if ( a_e164 )
return a_e164 ;
return a_pfx ;
2003-03-31 07:13:36 +00:00
}
2003-12-09 05:14:23 +00:00
struct oh323_user * find_user ( const call_details_t cd )
2003-03-31 07:13:36 +00:00
{
struct oh323_user * u ;
u = userl . users ;
2003-12-09 05:14:23 +00:00
if ( userbyalias = = 1 ) {
while ( u ) {
if ( ! strcasecmp ( u - > name , cd . call_source_aliases ) ) {
break ;
}
u = u - > next ;
}
2003-03-31 07:13:36 +00:00
2003-12-09 05:14:23 +00:00
} else {
while ( u ) {
if ( ! strcasecmp ( cd . sourceIp , inet_ntoa ( u - > addr . sin_addr ) ) ) {
break ;
}
u = u - > next ;
2003-03-31 07:13:36 +00:00
}
2003-12-09 05:14:23 +00:00
2003-03-31 07:13:36 +00:00
}
return u ;
}
struct oh323_peer * find_peer ( char * dest_peer )
{
struct oh323_peer * p ;
p = peerl . peers ;
while ( p ) {
if ( ! strcasecmp ( p - > name , dest_peer ) ) {
break ;
}
p = p - > next ;
}
return p ;
}
2003-12-23 23:01:24 +00:00
static int progress ( unsigned call_reference , int inband )
{
struct oh323_pvt * p ;
ast_log ( LOG_DEBUG , " Received ALERT/PROGRESS message for %s tones \n " , ( inband ? " inband " : " self-generated " ) ) ;
p = find_call ( call_reference ) ;
if ( ! p ) {
ast_log ( LOG_ERROR , " Private structure not found in send_digit. \n " ) ;
return - 1 ;
}
if ( ! p - > owner ) {
ast_log ( LOG_ERROR , " No asterisk's channel associated with private structure. \n " ) ;
return - 1 ;
}
ast_queue_control ( p - > owner , ( inband ? AST_CONTROL_PROGRESS : AST_CONTROL_RINGING ) , 0 ) ;
return 0 ;
}
2003-03-31 07:13:36 +00:00
/**
* Callback for sending digits from H .323 up to asterisk
*
*/
int send_digit ( unsigned call_reference , char digit )
{
struct oh323_pvt * p ;
struct ast_frame f ;
ast_log ( LOG_DEBUG , " Recieved Digit: %c \n " , digit ) ;
p = find_call ( call_reference ) ;
if ( ! p ) {
ast_log ( LOG_ERROR , " Private structure not found in send_digit. \n " ) ;
return - 1 ;
}
memset ( & f , 0 , sizeof ( f ) ) ;
f . frametype = AST_FRAME_DTMF ;
2003-12-23 23:01:24 +00:00
f . subclass = digit ;
f . datalen = 0 ;
f . samples = 300 ;
2003-03-31 07:13:36 +00:00
f . offset = 0 ;
f . data = NULL ;
2003-12-23 23:01:24 +00:00
f . mallocd = 0 ;
f . src = " SEND_DIGIT " ;
2003-03-31 07:13:36 +00:00
return ast_queue_frame ( p - > owner , & f , 1 ) ;
}
/**
* Call - back function that gets called when any H .323 connection is made
*
2003-08-25 09:54:36 +00:00
* Returns the local RTP information
2003-03-31 07:13:36 +00:00
*/
2003-08-25 09:54:36 +00:00
struct rtp_info * create_connection ( unsigned call_reference )
2003-03-31 07:13:36 +00:00
{
struct oh323_pvt * p ;
struct sockaddr_in us ;
2003-08-25 09:54:36 +00:00
struct sockaddr_in them ;
struct rtp_info * info ;
info = malloc ( sizeof ( struct rtp_info ) ) ;
2003-03-31 07:13:36 +00:00
p = find_call ( call_reference ) ;
if ( ! p ) {
ast_log ( LOG_ERROR , " Unable to allocate private structure, this is very bad. \n " ) ;
2003-08-25 09:54:36 +00:00
return NULL ;
2003-03-31 07:13:36 +00:00
}
/* figure out our local RTP port and tell the H.323 stack about it*/
ast_rtp_get_us ( p - > rtp , & us ) ;
2003-08-25 09:54:36 +00:00
ast_rtp_get_peer ( p - > rtp , & them ) ;
info - > addr = inet_ntoa ( us . sin_addr ) ;
info - > port = ntohs ( us . sin_port ) ;
2003-09-29 09:18:56 +00:00
2003-08-25 09:54:36 +00:00
return info ;
2003-03-31 07:13:36 +00:00
}
/**
* Call - back function for incoming calls
*
* Returns 1 on success
*/
2003-12-23 23:01:24 +00:00
call_options_t * setup_incoming_call ( call_details_t cd )
2003-03-31 07:13:36 +00:00
{
struct oh323_pvt * p = NULL ;
struct ast_channel * c = NULL ;
struct oh323_user * user = NULL ;
struct oh323_alias * alias = NULL ;
2003-12-23 23:01:24 +00:00
call_options_t * call_options = NULL ;
2003-03-31 07:13:36 +00:00
/* allocate the call*/
p = oh323_alloc ( cd . call_reference ) ;
if ( ! p ) {
ast_log ( LOG_ERROR , " Unable to allocate private structure, this is bad. \n " ) ;
2003-12-23 23:01:24 +00:00
return NULL ;
2003-03-31 07:13:36 +00:00
}
/* Populate the call details in the private structure */
p - > cd . call_token = cd . call_token ;
p - > cd . call_source_aliases = cd . call_source_aliases ;
p - > cd . call_dest_alias = cd . call_dest_alias ;
p - > cd . call_source_e164 = cd . call_source_e164 ;
p - > cd . call_dest_e164 = cd . call_dest_e164 ;
if ( h323debug ) {
2003-12-23 23:01:24 +00:00
ast_verbose ( VERBOSE_PREFIX_2 " Setting up Call \n " ) ;
ast_verbose ( VERBOSE_PREFIX_3 " Calling party name: [%s] \n " , p - > cd . call_source_aliases ) ;
ast_verbose ( VERBOSE_PREFIX_3 " Calling party number: [%s] \n " , p - > cd . call_source_e164 ) ;
ast_verbose ( VERBOSE_PREFIX_3 " Called party name: [%s] \n " , p - > cd . call_dest_alias ) ;
ast_verbose ( VERBOSE_PREFIX_3 " Called party number: [%s] \n " , p - > cd . call_dest_e164 ) ;
ast_verbose ( VERBOSE_PREFIX_3 " Redirecting party number: [%s] \n " , p - > cd . call_redir_e164 ) ;
2003-03-31 07:13:36 +00:00
}
/* Decide if we are allowing Gatekeeper routed calls*/
if ( ( ! strcasecmp ( cd . sourceIp , gatekeeper ) ) & & ( gkroute = = - 1 ) & & ( usingGk = = 1 ) ) {
if ( strlen ( cd . call_dest_e164 ) ) {
2003-12-23 23:01:24 +00:00
char * ctx ;
alias = find_alias ( cd ) ;
ctx = alias ? alias - > context : default_context ;
strncpy ( p - > dnid , cd . call_dest_e164 , sizeof ( p - > dnid ) - 1 ) ;
strncpy ( p - > exten , cd . call_dest_e164 , sizeof ( p - > exten ) - 1 ) ;
strncpy ( p - > context , ctx , sizeof ( p - > context ) - 1 ) ;
2003-03-31 07:13:36 +00:00
} else {
2003-12-23 23:01:24 +00:00
alias = find_alias ( cd ) ;
2003-03-31 07:13:36 +00:00
if ( ! alias ) {
ast_log ( LOG_ERROR , " Call for %s rejected, alias not found \n " , cd . call_dest_alias ) ;
return 0 ;
}
strncpy ( p - > exten , alias - > name , sizeof ( p - > exten ) - 1 ) ;
strncpy ( p - > context , alias - > context , sizeof ( p - > context ) - 1 ) ;
}
2003-12-23 23:01:24 +00:00
/* Asterisk prefers user name to be quoted */
sprintf ( p - > callerid , " \" %s \" <%s> " , p - > cd . call_source_aliases , p - > cd . call_source_e164 ) ;
2003-03-31 07:13:36 +00:00
} else {
/* Either this call is not from the Gatekeeper
or we are not allowing gk routed calls */
2003-08-25 09:54:36 +00:00
2003-12-09 05:14:23 +00:00
user = find_user ( cd ) ;
2003-08-25 09:54:36 +00:00
2003-03-31 07:13:36 +00:00
if ( ! user ) {
2003-12-23 23:01:24 +00:00
/* Asterisk prefers user name to be quoted */
sprintf ( p - > callerid , " \" %s \" <%s> " , p - > cd . call_source_aliases , p - > cd . call_source_e164 ) ;
2003-03-31 07:13:36 +00:00
if ( strlen ( p - > cd . call_dest_e164 ) ) {
2003-12-23 23:01:24 +00:00
strncpy ( p - > dnid , cd . call_dest_e164 , sizeof ( p - > dnid ) - 1 ) ;
2003-03-31 07:13:36 +00:00
strncpy ( p - > exten , cd . call_dest_e164 , sizeof ( p - > exten ) - 1 ) ;
} else {
2003-12-23 23:01:24 +00:00
strncpy ( p - > exten , cd . call_dest_alias , sizeof ( p - > exten ) - 1 ) ;
2003-03-31 07:13:36 +00:00
}
if ( ! strlen ( default_context ) ) {
ast_log ( LOG_ERROR , " Call from user '%s' rejected due to no default context \n " , p - > cd . call_source_aliases ) ;
return 0 ;
}
strncpy ( p - > context , default_context , sizeof ( p - > context ) - 1 ) ;
ast_log ( LOG_DEBUG , " Sending %s to context [%s] \n " , cd . call_source_aliases , p - > context ) ;
2003-12-23 23:01:24 +00:00
} else {
call_options = & user - > call_options ;
2003-03-31 20:26:08 +00:00
if ( user - > host ) {
if ( strcasecmp ( cd . sourceIp , inet_ntoa ( user - > addr . sin_addr ) ) ) {
2003-04-11 20:28:25 +00:00
if ( ! strlen ( default_context ) ) {
ast_log ( LOG_ERROR , " Call from user '%s' rejected due to non-matching IP address of '%s' \n " , user - > name , cd . sourceIp ) ;
2003-12-23 23:01:24 +00:00
return NULL ;
2003-04-11 20:28:25 +00:00
}
2003-08-25 09:54:36 +00:00
2003-04-11 20:28:25 +00:00
strncpy ( p - > context , default_context , sizeof ( p - > context ) - 1 ) ;
sprintf ( p - > exten , " i " ) ;
2003-08-25 09:54:36 +00:00
2003-04-11 20:28:25 +00:00
goto exit ;
2003-03-31 20:26:08 +00:00
}
2003-03-31 19:26:15 +00:00
}
2003-03-31 07:13:36 +00:00
if ( user - > incominglimit > 0 ) {
if ( user - > inUse > = user - > incominglimit ) {
ast_log ( LOG_ERROR , " Call from user '%s' rejected due to usage limit of %d \n " , user - > name , user - > incominglimit ) ;
2003-12-23 23:01:24 +00:00
return NULL ;
2003-03-31 07:13:36 +00:00
}
}
strncpy ( p - > context , user - > context , sizeof ( p - > context ) - 1 ) ;
p - > bridge = user - > bridge ;
2003-12-23 23:01:24 +00:00
p - > nat = user - > nat ;
2003-03-31 07:13:36 +00:00
2003-07-23 20:00:48 +00:00
if ( strlen ( user - > callerid ) )
2003-03-31 07:13:36 +00:00
strncpy ( p - > callerid , user - > callerid , sizeof ( p - > callerid ) - 1 ) ;
else
2003-07-24 17:24:34 +00:00
sprintf ( p - > callerid , " %s <%s> " , p - > cd . call_source_aliases , p - > cd . call_source_e164 ) ;
2003-08-25 09:54:36 +00:00
2003-03-31 07:13:36 +00:00
if ( strlen ( p - > cd . call_dest_e164 ) ) {
strncpy ( p - > exten , cd . call_dest_e164 , sizeof ( p - > exten ) - 1 ) ;
} else {
strncpy ( p - > exten , cd . call_dest_alias , sizeof ( p - > exten ) - 1 ) ;
}
if ( strlen ( user - > accountcode ) ) {
strncpy ( p - > accountcode , user - > accountcode , sizeof ( p - > accountcode ) - 1 ) ;
2003-04-11 04:07:22 +00:00
}
2003-04-11 03:28:31 +00:00
2003-03-31 07:13:36 +00:00
/* Increment the usage counter */
user - > inUse + + ;
}
}
2003-04-11 20:28:25 +00:00
/* I know this is horrid, don't kill me saddam */
exit :
2003-12-24 03:02:17 +00:00
// if(strlen(p->cd.call_redir_e164))
// strncpy(p->rdnis, cd.call_redir_e164, sizeof(p->rdnis)-1);
2003-03-31 07:13:36 +00:00
/* allocate a channel and tell asterisk about it */
c = oh323_new ( p , AST_STATE_RINGING , cd . call_token ) ;
if ( ! c ) {
ast_log ( LOG_ERROR , " Couldn't create channel. This is bad \n " ) ;
2003-12-23 23:01:24 +00:00
return NULL ;
2003-03-31 07:13:36 +00:00
}
2003-12-23 23:01:24 +00:00
ast_queue_control ( c , AST_CONTROL_RINGING , 0 ) ;
if ( ! call_options )
return & global_options ;
return call_options ;
2003-03-31 07:13:36 +00:00
}
/**
* Call - back function to establish an outgoing H .323 call
*
* Returns 1 on success
*/
int setup_outgoing_call ( call_details_t cd )
{
return 1 ;
}
#if 0
if ( p - > inUse > = p - > outgoinglimit ) {
ast_log ( LOG_ERROR , " Call to %s rejected due to usage limit of %d outgoing channels \n " , p - > name , p - > inUse ) ;
return 0 ;
}
if ( ! p ) {
ast_log ( LOG_ERROR , " Rejecting call: peer %s not found \n " , dest_peer ) ;
return 0 ;
}
# endif
/**
* Call - back function that gets called for each rtp channel opened
*
* Returns nothing
*/
2003-12-23 23:01:24 +00:00
void setup_rtp_connection ( unsigned call_reference , const char * remoteIp , int remotePort , int direction , int payloadType )
2003-03-31 07:13:36 +00:00
{
struct oh323_pvt * p = NULL ;
struct sockaddr_in them ;
2003-12-23 23:01:24 +00:00
struct rtpPayloadType payload ;
struct ast_channel * chan ;
2003-03-31 07:13:36 +00:00
/* Find the call or allocate a private structure if call not found */
p = find_call ( call_reference ) ;
if ( ! p ) {
ast_log ( LOG_ERROR , " Something is wrong: rtp \n " ) ;
return ;
}
them . sin_family = AF_INET ;
them . sin_addr . s_addr = inet_addr ( remoteIp ) ; // only works for IPv4
them . sin_port = htons ( remotePort ) ;
2003-12-23 23:01:24 +00:00
/* Find RTP payload <=> asterisk's subcode association */
payload = ast_rtp_lookup_pt ( p - > rtp , payloadType ) ;
ast_log ( LOG_DEBUG , " Setting up %sbound RTP connection for %s:%d with payload %s (RTP code %d) \n " , ( direction ? " out " : " in " ) , inet_ntoa ( them . sin_addr ) , remotePort , ast_getformatname ( payload . code ) , payloadType ) ;
/* Set channel's native codec and prepare translation table
* for given direction and currently used format
*/
if ( ( chan = p - > owner ) ) {
if ( payload . isAstFormat ) {
/* Don't allow any transmission until codec is changed */
// ast_mutex_lock(&chan->lock);
chan - > nativeformats = payload . code ;
if ( direction )
ast_set_write_format ( chan , chan - > writeformat ) ;
else
ast_set_read_format ( chan , chan - > readformat ) ;
// ast_mutex_unlock(&chan->lock);
}
}
2003-03-31 07:13:36 +00:00
ast_rtp_set_peer ( p - > rtp , & them ) ;
2003-12-23 23:01:24 +00:00
if ( p - > calloptions . progress_audio )
progress ( call_reference , TRUE ) ;
2003-03-31 07:13:36 +00:00
return ;
}
2003-12-23 23:01:24 +00:00
/* Not used for now - set RTP peer's address */
void setup_rtp_peer ( unsigned call_reference , const char * remoteIp , int remotePort )
{
struct oh323_pvt * p = NULL ;
struct sockaddr_in them ;
/* Find the call or allocate a private structure if call not found */
p = find_call ( call_reference ) ;
if ( ! p ) {
ast_log ( LOG_ERROR , " Something is wrong: rtp \n " ) ;
return ;
}
them . sin_family = AF_INET ;
them . sin_addr . s_addr = inet_addr ( remoteIp ) ; // only works for IPv4
them . sin_port = htons ( remotePort ) ;
ast_rtp_set_peer ( p - > rtp , & them ) ;
}
2003-03-31 07:13:36 +00:00
/**
* Call - back function to signal asterisk that the channel has been answered
* Returns nothing
*/
void connection_made ( unsigned call_reference )
{
struct ast_channel * c = NULL ;
struct oh323_pvt * p = NULL ;
p = find_call ( call_reference ) ;
if ( ! p )
ast_log ( LOG_ERROR , " Something is wrong: connection \n " ) ;
if ( ! p - > owner ) {
2003-12-18 18:48:47 +00:00
ast_log ( LOG_ERROR , " Channel has no owner \n " ) ;
2003-03-31 07:13:36 +00:00
return ;
}
c = p - > owner ;
ast_setstate ( c , AST_STATE_UP ) ;
return ;
}
/**
* Call - back function to cleanup communication
* Returns nothing ,
*/
void cleanup_connection ( call_details_t cd )
{
struct oh323_pvt * p = NULL ;
// struct oh323_peer *peer = NULL;
struct oh323_user * user = NULL ;
struct ast_rtp * rtp = NULL ;
ast_log ( LOG_DEBUG , " Cleaning up our mess \n " ) ;
p = find_call ( cd . call_reference ) ;
if ( ! p ) {
return ;
}
/* Decrement usage counter */
if ( ! p - > outgoing ) {
2003-12-09 05:14:23 +00:00
user = find_user ( cd ) ;
2003-03-31 07:13:36 +00:00
if ( user )
user - > inUse - - ;
}
#if 0
if ( p - > outgoing ) {
peer = find_peer ( cd . call_dest_alias ) ;
peer - > inUse - - ;
} else {
2003-12-09 05:14:23 +00:00
user = find_user ( cd ) ;
2003-03-31 07:13:36 +00:00
user - > inUse - - ;
}
# endif
if ( p - > rtp ) {
rtp = p - > rtp ;
p - > rtp = NULL ;
/* Immediately stop RTP */
ast_rtp_destroy ( rtp ) ;
}
p - > alreadygone = 1 ;
/* Send hangup */
if ( p - > owner )
ast_queue_hangup ( p - > owner , 1 ) ;
p = NULL ;
return ;
}
static void * do_monitor ( void * data )
{
int res ;
struct oh323_pvt * oh323 = NULL ;
for ( ; ; ) {
/* Check for interfaces needing to be killed */
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & iflock ) ;
2003-03-31 07:13:36 +00:00
restartsearch :
oh323 = iflist ;
while ( oh323 ) {
if ( oh323 - > needdestroy ) {
__oh323_destroy ( oh323 ) ;
goto restartsearch ;
}
oh323 = oh323 - > next ;
}
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & iflock ) ;
2003-03-31 07:13:36 +00:00
/* Wait for sched or io */
res = ast_sched_wait ( sched ) ;
if ( ( res < 0 ) | | ( res > 1000 ) )
res = 1000 ;
res = ast_io_wait ( io , res ) ;
2003-12-23 23:01:24 +00:00
/* Check for thread cancellation */
pthread_testcancel ( ) ;
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & monlock ) ;
2003-03-31 07:13:36 +00:00
if ( res > = 0 )
ast_sched_runq ( sched ) ;
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & monlock ) ;
2003-03-31 07:13:36 +00:00
}
/* Never reached */
return NULL ;
}
static int restart_monitor ( void )
{
/* If we're supposed to be stopped -- stay stopped */
if ( monitor_thread = = - 2 )
return 0 ;
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 ;
}
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 ;
}
if ( monitor_thread ) {
/* Wake up the thread */
pthread_kill ( monitor_thread , SIGURG ) ;
} else {
/* Start a new monitor */
if ( pthread_create ( & monitor_thread , NULL , do_monitor , NULL ) < 0 ) {
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & monlock ) ;
2003-03-31 07:13:36 +00:00
ast_log ( LOG_ERROR , " Unable to start monitor thread. \n " ) ;
return - 1 ;
}
}
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 [ ] )
{
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
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 [ ] )
{
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
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 [ ] )
{
if ( argc ! = 2 )
return RESULT_SHOWUSAGE ;
h323debug = 1 ;
ast_cli ( fd , " H323 debug enabled \n " ) ;
return RESULT_SUCCESS ;
}
static int h323_no_debug ( int fd , int argc , char * argv [ ] )
{
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
h323debug = 0 ;
ast_cli ( fd , " H323 Debug disabled \n " ) ;
return RESULT_SUCCESS ;
}
static int h323_gk_cycle ( int fd , int argc , char * argv [ ] )
{
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
h323_gk_urq ( ) ;
/* Possibly register with a GK */
2003-04-07 14:53:49 +00:00
if ( gatekeeper_disable = = 0 ) {
2003-03-31 07:13:36 +00:00
if ( h323_set_gk ( gatekeeper_discover , gatekeeper , secret ) ) {
ast_log ( LOG_ERROR , " Gatekeeper registration failed. \n " ) ;
h323_end_process ( ) ;
}
}
return RESULT_SUCCESS ;
}
static char trace_usage [ ] =
" Usage: h.323 trace <level num> \n "
" Enables H.323 stack tracing for debugging purposes \n " ;
static char no_trace_usage [ ] =
" Usage: h.323 no trace \n "
" Disables H.323 stack tracing for debugging purposes \n " ;
static char debug_usage [ ] =
" Usage: h.323 debug \n "
" Enables chan_h323 debug output \n " ;
static char no_debug_usage [ ] =
" Usage: h.323 no debug \n "
" Disables chan_h323 debug output \n " ;
static char show_codec_usage [ ] =
" Usage: h.323 show codec \n "
" Shows all enabled codecs \n " ;
static char show_cycle_usage [ ] =
" Usage: h.323 gk cycle \n "
" Manually re-register with the Gatekeper \n " ;
static struct ast_cli_entry cli_trace =
{ { " h.323 " , " trace " , NULL } , h323_do_trace , " Enable H.323 Stack Tracing " , trace_usage } ;
static struct ast_cli_entry cli_no_trace =
{ { " h.323 " , " no " , " trace " , NULL } , h323_no_trace , " Disable H.323 Stack Tracing " , no_trace_usage } ;
static struct ast_cli_entry cli_debug =
{ { " h.323 " , " debug " , NULL } , h323_do_debug , " Enable chan_h323 debug " , debug_usage } ;
static struct ast_cli_entry cli_no_debug =
{ { " h.323 " , " no " , " debug " , NULL } , h323_no_debug , " Disable chan_h323 debug " , no_debug_usage } ;
static struct ast_cli_entry cli_show_codecs =
{ { " h.323 " , " show " , " codecs " , NULL } , h323_show_codec , " Show enabled codecs " , show_codec_usage } ;
static struct ast_cli_entry cli_gk_cycle =
{ { " h.323 " , " gk " , " cycle " , NULL } , h323_gk_cycle , " Manually re-register with the Gatekeper " , show_cycle_usage } ;
2003-09-27 02:52:05 +00:00
int reload_config ( void )
2003-03-31 07:13:36 +00:00
{
int format ;
struct ast_config * cfg ;
struct ast_variable * v ;
struct oh323_peer * peer = NULL ;
struct oh323_user * user = NULL ;
struct oh323_alias * alias = NULL ;
struct hostent * hp ;
char * cat ;
2003-12-23 23:01:24 +00:00
char * utype ;
2003-03-31 07:13:36 +00:00
cfg = ast_load ( config ) ;
/* 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
}
2003-12-18 19:48:42 +00:00
/* fire up the H.323 Endpoint */
if ( ! h323_end_point_exist ( ) ) {
h323_end_point_create ( ) ;
}
2003-03-31 07:13:36 +00:00
h323debug = 0 ;
dtmfmode = H323_DTMF_RFC2833 ;
2003-12-23 23:01:24 +00:00
/* Fill global variables with pre-determined values */
memset ( & global_options , 0 , sizeof ( global_options ) ) ;
2003-03-31 07:13:36 +00:00
memset ( & bindaddr , 0 , sizeof ( bindaddr ) ) ;
v = ast_variable_browse ( cfg , " general " ) ;
while ( v ) {
/* Create the interface list */
2003-05-31 18:42:09 +00:00
if ( ! strcasecmp ( v - > name , " port " ) ) {
2003-03-31 07:13:36 +00:00
port = ( int ) strtol ( v - > value , NULL , 10 ) ;
} else if ( ! strcasecmp ( v - > name , " bindaddr " ) ) {
if ( ! ( hp = gethostbyname ( v - > value ) ) ) {
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 , " allow " ) ) {
format = ast_getformatbyname ( v - > value ) ;
if ( format < 1 )
ast_log ( LOG_WARNING , " Cannot allow unknown format '%s' \n " , v - > value ) ;
else
capability | = format ;
} else if ( ! strcasecmp ( v - > name , " disallow " ) ) {
format = ast_getformatbyname ( v - > value ) ;
if ( format < 1 )
ast_log ( LOG_WARNING , " Cannot disallow unknown format '%s' \n " , v - > value ) ;
else
capability & = ~ format ;
} else if ( ! strcasecmp ( v - > name , " tos " ) ) {
if ( sscanf ( v - > value , " %i " , & format ) = = 1 )
tos = format & 0xff ;
else if ( ! strcasecmp ( v - > value , " lowdelay " ) )
tos = IPTOS_LOWDELAY ;
else if ( ! strcasecmp ( v - > value , " throughput " ) )
tos = IPTOS_THROUGHPUT ;
else if ( ! strcasecmp ( v - > value , " reliability " ) )
tos = IPTOS_RELIABILITY ;
else if ( ! strcasecmp ( v - > value , " mincost " ) )
tos = IPTOS_MINCOST ;
else if ( ! strcasecmp ( v - > value , " none " ) )
tos = 0 ;
else
ast_log ( LOG_WARNING , " Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', 'mincost', or 'none' \n " , v - > lineno ) ;
} else if ( ! strcasecmp ( v - > name , " gatekeeper " ) ) {
if ( ! strcasecmp ( v - > value , " DISABLE " ) ) {
gatekeeper_disable = 1 ;
usingGk = 0 ;
} else if ( ! strcasecmp ( v - > value , " DISCOVER " ) ) {
gatekeeper_disable = 0 ;
gatekeeper_discover = 1 ;
usingGk = 1 ;
} else {
gatekeeper_disable = 0 ;
usingGk = 1 ;
strncpy ( gatekeeper , v - > value , sizeof ( gatekeeper ) - 1 ) ;
}
} else if ( ! strcasecmp ( v - > name , " secret " ) ) {
strncpy ( secret , v - > value , sizeof ( secret ) - 1 ) ;
} else if ( ! strcasecmp ( v - > name , " AllowGKRouted " ) ) {
gkroute = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " context " ) ) {
strncpy ( default_context , v - > value , sizeof ( default_context ) - 1 ) ;
2003-12-18 18:48:47 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " == Setting default context to %s \n " , default_context ) ;
2003-03-31 07:13:36 +00:00
} else if ( ! strcasecmp ( v - > name , " dtmfmode " ) ) {
if ( ! strcasecmp ( v - > value , " inband " ) )
dtmfmode = H323_DTMF_INBAND ;
else if ( ! strcasecmp ( v - > value , " rfc2833 " ) )
dtmfmode = H323_DTMF_RFC2833 ;
else {
ast_log ( LOG_WARNING , " Unknown dtmf mode '%s', using rfc2833 \n " , v - > value ) ;
dtmfmode = H323_DTMF_RFC2833 ;
}
2003-12-23 23:01:24 +00:00
/* Setup global parameters */
} else if ( ! strcasecmp ( v - > name , " noFastStart " ) ) {
global_options . noFastStart = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " noH245Tunneling " ) ) {
global_options . noH245Tunnelling = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " noSilenceSuppression " ) ) {
global_options . noSilenceSuppression = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " progress_setup " ) ) {
int progress_setup = atoi ( v - > value ) ;
if ( ( progress_setup ! = 0 ) & &
( progress_setup ! = 1 ) & &
( progress_setup ! = 3 ) & &
( progress_setup ! = 8 ) ) {
ast_log ( LOG_WARNING , " Invalid value %d for progress_setup at line %d, assuming 0 \n " , progress_setup , v - > lineno ) ;
progress_setup = 0 ;
}
global_options . progress_setup = progress_setup ;
} else if ( ! strcasecmp ( v - > name , " progress_alert " ) ) {
int progress_alert = atoi ( v - > value ) ;
if ( ( progress_alert ! = 0 ) & &
( progress_alert ! = 8 ) ) {
ast_log ( LOG_WARNING , " Invalid value %d for progress_alert at line %d, assuming 0 \n " , progress_alert , v - > lineno ) ;
progress_alert = 0 ;
}
global_options . progress_alert = progress_alert ;
} else if ( ! strcasecmp ( v - > name , " progress_audio " ) ) {
global_options . progress_audio = ast_true ( v - > value ) ;
2003-12-09 05:14:23 +00:00
} else if ( ! strcasecmp ( v - > name , " UserByAlias " ) ) {
userbyalias = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " bridge " ) ) {
bridge_default = ast_true ( v - > value ) ;
}
2003-03-31 07:13:36 +00:00
v = v - > next ;
}
cat = ast_category_browse ( cfg , NULL ) ;
while ( cat ) {
if ( strcasecmp ( cat , " general " ) ) {
utype = ast_variable_retrieve ( cfg , cat , " type " ) ;
if ( utype ) {
if ( ! strcasecmp ( utype , " user " ) | | ! strcasecmp ( utype , " friend " ) ) {
user = build_user ( cat , ast_variable_browse ( cfg , cat ) ) ;
if ( user ) {
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & userl . lock ) ;
2003-03-31 07:13:36 +00:00
user - > next = userl . users ;
userl . users = user ;
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & userl . lock ) ;
2003-03-31 07:13:36 +00:00
}
} else if ( ! strcasecmp ( utype , " peer " ) | | ! strcasecmp ( utype , " friend " ) ) {
peer = build_peer ( cat , ast_variable_browse ( cfg , cat ) ) ;
if ( peer ) {
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & peerl . lock ) ;
2003-03-31 07:13:36 +00:00
peer - > next = peerl . peers ;
peerl . peers = peer ;
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & peerl . lock ) ;
2003-03-31 07:13:36 +00:00
}
} else if ( ! strcasecmp ( utype , " h323 " ) ) {
alias = build_alias ( cat , ast_variable_browse ( cfg , cat ) ) ;
if ( alias ) {
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & aliasl . lock ) ;
2003-03-31 07:13:36 +00:00
alias - > next = aliasl . aliases ;
aliasl . aliases = alias ;
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & aliasl . lock ) ;
2003-03-31 07:13:36 +00:00
}
} else {
ast_log ( LOG_WARNING , " Unknown type '%s' for '%s' in %s \n " , utype , cat , config ) ;
}
} else
ast_log ( LOG_WARNING , " Section '%s' lacks type \n " , cat ) ;
}
cat = ast_category_browse ( cfg , cat ) ;
}
/* Register our H.323 aliases if any*/
while ( alias ) {
if ( h323_set_alias ( alias ) ) {
ast_log ( LOG_ERROR , " Alias %s rejected by endpoint \n " , alias - > name ) ;
return - 1 ;
}
alias = alias - > next ;
}
/* Add some capabilities */
if ( h323_set_capability ( capability , dtmfmode ) ) {
ast_log ( LOG_ERROR , " Capabilities failure, this is bad. \n " ) ;
return - 1 ;
}
ast_destroy ( cfg ) ;
return 0 ;
}
void delete_users ( void )
{
struct oh323_user * user , * userlast ;
struct oh323_peer * peer ;
/* Delete all users */
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & userl . lock ) ;
2003-03-31 07:13:36 +00:00
for ( user = userl . users ; user ; ) {
userlast = user ;
user = user - > next ;
free ( userlast ) ;
}
userl . users = NULL ;
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & userl . lock ) ;
ast_mutex_lock ( & peerl . lock ) ;
2003-03-31 07:13:36 +00:00
for ( peer = peerl . peers ; peer ; ) {
/* Assume all will be deleted, and we'll find out for sure later */
peer - > delme = 1 ;
peer = peer - > next ;
}
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & peerl . lock ) ;
2003-03-31 07:13:36 +00:00
}
void delete_aliases ( void )
{
struct oh323_alias * alias , * aliaslast ;
/* Delete all users */
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & aliasl . lock ) ;
2003-03-31 07:13:36 +00:00
for ( alias = aliasl . aliases ; alias ; ) {
aliaslast = alias ;
alias = alias - > next ;
free ( aliaslast ) ;
}
aliasl . aliases = NULL ;
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & aliasl . lock ) ;
2003-03-31 07:13:36 +00:00
}
void prune_peers ( void )
{
/* Prune peers who still are supposed to be deleted */
struct oh323_peer * peer , * peerlast , * peernext ;
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & peerl . lock ) ;
2003-03-31 07:13:36 +00:00
peerlast = NULL ;
for ( peer = peerl . peers ; peer ; ) {
peernext = peer - > next ;
if ( peer - > delme ) {
free ( peer ) ;
if ( peerlast )
peerlast - > next = peernext ;
else
peerl . peers = peernext ;
} else
peerlast = peer ;
peer = peernext ;
}
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & peerl . lock ) ;
2003-03-31 07:13:36 +00:00
}
int reload ( void )
{
delete_users ( ) ;
delete_aliases ( ) ;
prune_peers ( ) ;
2003-12-23 23:01:24 +00:00
reload_config ( ) ;
#if 0
This code causes seg on - r
2003-03-31 07:13:36 +00:00
if ( strlen ( gatekeeper ) ) {
h323_gk_urq ( ) ;
}
/* Possibly register with a GK */
2003-12-23 23:01:24 +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 " ) ;
2003-06-25 06:48:08 +00:00
h323_end_process ( ) ;
2003-03-31 07:13:36 +00:00
return - 1 ;
}
}
2003-09-24 10:59:24 +00:00
# endif
2003-12-23 23:01:24 +00:00
2003-03-31 07:13:36 +00:00
restart_monitor ( ) ;
return 0 ;
}
static struct ast_rtp * oh323_get_rtp_peer ( struct ast_channel * chan )
{
struct oh323_pvt * p ;
p = chan - > pvt - > pvt ;
2003-08-25 09:54:36 +00:00
if ( p & & p - > rtp & & p - > bridge ) {
2003-03-31 07:13:36 +00:00
return p - > rtp ;
2003-08-25 09:54:36 +00:00
}
2003-03-31 07:13:36 +00:00
return NULL ;
}
2003-07-01 19:11:37 +00:00
static struct ast_rtp * oh323_get_vrtp_peer ( struct ast_channel * chan )
2003-03-31 07:13:36 +00:00
{
2003-07-01 19:11:37 +00:00
return NULL ;
}
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 ;
}
}
2003-07-01 19:11:37 +00:00
static int oh323_set_rtp_peer ( struct ast_channel * chan , struct ast_rtp * rtp , struct ast_rtp * vrtp )
{
/* XXX Deal with Video */
2003-03-31 07:13:36 +00:00
struct oh323_pvt * p ;
struct sockaddr_in them ;
struct sockaddr_in us ;
2003-08-25 09:54:36 +00:00
char * mode ;
mode = convertcap ( chan - > writeformat ) ;
2003-03-31 07:13:36 +00:00
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
2003-03-31 07:13:36 +00:00
p = chan - > pvt - > pvt ;
if ( ! p ) {
ast_log ( LOG_ERROR , " No Private Structure, this is bad \n " ) ;
return - 1 ;
}
ast_rtp_get_peer ( rtp , & them ) ;
2003-08-25 09:54:36 +00:00
ast_rtp_get_us ( rtp , & us ) ;
2003-03-31 07:13:36 +00:00
2003-08-25 09:54:36 +00:00
h323_native_bridge ( p - > cd . call_token , inet_ntoa ( them . sin_addr ) , mode ) ;
2003-03-31 07:13:36 +00:00
return 0 ;
}
static struct ast_rtp_protocol oh323_rtp = {
get_rtp_info : oh323_get_rtp_peer ,
2003-07-01 19:11:37 +00:00
get_vrtp_info : oh323_get_vrtp_peer ,
2003-03-31 07:13:36 +00:00
set_rtp_peer : oh323_set_rtp_peer ,
} ;
2003-07-01 19:11:37 +00:00
2003-03-31 07:13:36 +00:00
int load_module ( )
{
int res ;
res = reload_config ( ) ;
2003-12-10 23:34:47 +00:00
if ( res ) {
return 0 ;
} else {
/* Make sure we can register our channel type */
2003-03-31 07:13:36 +00:00
if ( ast_channel_register ( type , tdesc , capability , oh323_request ) ) {
ast_log ( LOG_ERROR , " Unable to register channel class %s \n " , type ) ;
h323_end_process ( ) ;
return - 1 ;
}
ast_cli_register ( & cli_debug ) ;
ast_cli_register ( & cli_no_debug ) ;
ast_cli_register ( & cli_trace ) ;
ast_cli_register ( & cli_no_trace ) ;
ast_cli_register ( & cli_show_codecs ) ;
ast_cli_register ( & cli_gk_cycle ) ;
oh323_rtp . type = type ;
ast_rtp_proto_register ( & oh323_rtp ) ;
sched = sched_context_create ( ) ;
if ( ! sched ) {
ast_log ( LOG_WARNING , " Unable to create schedule context \n " ) ;
}
io = io_context_create ( ) ;
if ( ! io ) {
ast_log ( LOG_WARNING , " Unable to create I/O context \n " ) ;
}
/* Register our callback functions */
h323_callback_register ( setup_incoming_call ,
2003-09-22 06:21:03 +00:00
setup_outgoing_call ,
2003-03-31 07:13:36 +00:00
create_connection ,
setup_rtp_connection ,
cleanup_connection ,
2003-12-23 23:01:24 +00:00
connection_made ,
send_digit ,
progress ) ;
2003-03-31 07:13:36 +00:00
2003-09-06 20:29:25 +00:00
2003-03-31 07:13:36 +00:00
/* start the h.323 listener */
2003-05-31 18:42:09 +00:00
if ( h323_start_listener ( port , bindaddr ) ) {
2003-03-31 07:13:36 +00:00
ast_log ( LOG_ERROR , " Unable to create H323 listener. \n " ) ;
2003-05-14 04:39:15 +00:00
// h323_end_process();
2003-03-31 07:13:36 +00:00
return - 1 ;
}
/* Possibly register with a GK */
2003-04-07 14:53:49 +00:00
if ( gatekeeper_disable = = 0 ) {
2003-03-31 07:13:36 +00:00
if ( h323_set_gk ( gatekeeper_discover , gatekeeper , secret ) ) {
ast_log ( LOG_ERROR , " Gatekeeper registration failed. \n " ) ;
2003-05-14 04:39:15 +00:00
// h323_end_process();
2003-10-21 13:12:30 +00:00
return 0 ;
2003-03-31 07:13:36 +00:00
}
}
/* And start the monitor for the first time */
restart_monitor ( ) ;
}
return res ;
}
int unload_module ( )
{
struct oh323_pvt * p , * pl ;
2003-08-14 06:56:11 +00:00
if ( ! ast_mutex_lock ( & iflock ) ) {
2003-03-31 07:13:36 +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 ;
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 ;
}
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 */
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 ;
}
h323_gk_urq ( ) ;
2003-12-23 23:01:24 +00:00
h323_debug ( 0 , 0 ) ;
2003-03-31 07:13:36 +00:00
h323_end_process ( ) ;
2003-05-12 00:55:52 +00:00
/* unregister rtp */
ast_rtp_proto_unregister ( & oh323_rtp ) ;
/* unregister commands */
ast_cli_unregister ( & cli_debug ) ;
ast_cli_unregister ( & cli_no_debug ) ;
ast_cli_unregister ( & cli_trace ) ;
ast_cli_unregister ( & cli_no_trace ) ;
ast_cli_unregister ( & cli_show_codecs ) ;
ast_cli_unregister ( & cli_gk_cycle ) ;
2003-03-31 07:13:36 +00:00
/* unregister channel type */
ast_channel_unregister ( type ) ;
return 0 ;
}
int usecount ( )
{
int res ;
2003-08-14 06:56:11 +00:00
ast_mutex_lock ( & usecnt_lock ) ;
2003-03-31 07:13:36 +00:00
res = usecnt ;
2003-08-14 06:56:11 +00:00
ast_mutex_unlock ( & usecnt_lock ) ;
2003-03-31 07:13:36 +00:00
return res ;
}
char * description ( )
{
return desc ;
}
char * key ( )
{
return ASTERISK_GPL_KEY ;
}