2002-12-29 19:13:07 +00:00
/*
* Asterisk - - A telephony toolkit for Linux .
*
* Implementation of Media Gateway Control Protocol
*
* Copyright ( C ) 1999 , Mark Spencer
*
* Mark Spencer < markster @ linux - support . net >
*
* This program is free software , distributed under the terms of
* the GNU General Public License
*/
# include <stdio.h>
# include <pthread.h>
# include <string.h>
# include <asterisk/lock.h>
# include <asterisk/channel.h>
# include <asterisk/channel_pvt.h>
# include <asterisk/config.h>
# include <asterisk/logger.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>
2003-05-06 04:03:58 +00:00
# include <asterisk/say.h>
# include <asterisk/cdr.h>
# include <asterisk/astdb.h>
# include <asterisk/parking.h>
# include <asterisk/app.h>
# include <asterisk/musiconhold.h>
2002-12-29 19:13:07 +00:00
# include <sys/socket.h>
# include <sys/ioctl.h>
# include <net/if.h>
# include <errno.h>
# include <unistd.h>
# include <stdlib.h>
# include <fcntl.h>
# include <netdb.h>
# include <arpa/inet.h>
# include <sys/signal.h>
2003-03-10 20:39:12 +00:00
# include <asterisk/dsp.h>
2003-03-12 06:00:18 +00:00
# include <ctype.h>
2002-12-29 19:13:07 +00:00
# define MGCPDUMPER
# define DEFAULT_EXPIREY 120
# define MAX_EXPIREY 3600
static char * desc = " Media Gateway Control Protocol (MGCP) " ;
static char * type = " MGCP " ;
static char * tdesc = " Media Gateway Control Protocol (MGCP) " ;
static char * config = " mgcp.conf " ;
# define DEFAULT_MGCP_PORT 2427 /* From RFC 2705 */
# define MGCP_MAX_PACKET 1500 /* Also from RFC 2543, should sub headers tho */
2003-05-06 04:03:58 +00:00
/* MGCP rtp stream modes */
# define MGCP_CX_SENDONLY 0
# define MGCP_CX_RECVONLY 1
# define MGCP_CX_SENDRECV 2
# define MGCP_CX_CONF 3
# define MGCP_CX_CONFERENCE 3
# define MGCP_CX_MUTE 4
# define MGCP_CX_INACTIVE 4
static char * mgcp_cxmodes [ ] = {
" sendonly " ,
" recvonly " ,
" sendrecv " ,
" confrnce " ,
" inactive "
} ;
static char context [ AST_MAX_EXTENSION ] = " default " ;
static char language [ MAX_LANGUAGE ] = " " ;
static char musicclass [ MAX_LANGUAGE ] = " " ;
static char callerid [ AST_MAX_EXTENSION ] = " " ;
static int inbanddtmf = 0 ;
static int nat = 0 ;
/* Not used. Dosn't hurt for us to always send cid */
/* to the mgcp box. */
/* static int use_callerid = 1;*/
/*static int cur_signalling = -1;*/
/*static unsigned int cur_group = 0;*/
static unsigned int cur_callergroup = 0 ;
static unsigned int cur_pickupgroup = 0 ;
/* XXX Is this needed? */
/* Doesn't look like the dsp stuff for */
/* inbanddtmf is actually hooked up. */
/* static int relaxdtmf = 0; */
static int immediate = 0 ;
static int callwaiting = 0 ;
/* Not used. Dosn't hurt for us to always send cid */
/* to the mgcp box. */
/*static int callwaitingcallerid = 0;*/
/*static int hidecallerid = 0;*/
static int callreturn = 0 ;
static int threewaycalling = 0 ;
/* This is for flashhook transfers */
static int transfer = 0 ;
static int cancallforward = 0 ;
/*static int busycount = 3;*/
/*static int callprogress = 0;*/
static char accountcode [ 20 ] = " " ;
static char mailbox [ AST_MAX_EXTENSION ] ;
static int amaflags = 0 ;
static int adsi = 0 ;
2002-12-29 19:13:07 +00:00
static int usecnt = 0 ;
static pthread_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER ;
static int oseq ;
2003-05-06 04:03:58 +00:00
/* Wait up to 16 seconds for first digit (FXO logic) */
static int firstdigittimeout = 16000 ;
/* How long to wait for following digits (FXO logic) */
static int gendigittimeout = 8000 ;
/* How long to wait for an extra digit, if there is an ambiguous match */
static int matchdigittimeout = 3000 ;
2002-12-29 19:13:07 +00:00
/* Protect the monitoring thread, so only one process can kill or start it, and not
when it ' s doing something critical . */
static pthread_mutex_t netlock = AST_MUTEX_INITIALIZER ;
static pthread_mutex_t monlock = AST_MUTEX_INITIALIZER ;
/* 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 ) ;
/* Just about everybody seems to support ulaw, so make it a nice default */
static int capability = AST_FORMAT_ULAW ;
2003-03-12 06:00:18 +00:00
static int nonCodecCapability = AST_RTP_DTMF ;
2002-12-29 19:13:07 +00:00
static char ourhost [ 256 ] ;
static struct in_addr __ourip ;
static int ourport ;
2003-03-09 06:00:18 +00:00
static int mgcpdebug = 0 ;
2002-12-29 19:13:07 +00:00
static struct sched_context * sched ;
static struct io_context * io ;
/* The private structures of the mgcp channels are linked for
selecting outgoing channels */
# define MGCP_MAX_HEADERS 64
# define MGCP_MAX_LINES 64
struct mgcp_request {
int len ;
char * verb ;
char * identifier ;
char * endpoint ;
char * version ;
int headers ; /* MGCP Headers */
char * header [ MGCP_MAX_HEADERS ] ;
int lines ; /* SDP Content */
char * line [ MGCP_MAX_LINES ] ;
char data [ MGCP_MAX_PACKET ] ;
} ;
static struct mgcp_pkt {
int retrans ;
struct mgcp_endpoint * owner ;
int packetlen ;
char data [ MGCP_MAX_PACKET ] ;
struct mgcp_pkt * next ;
} * packets = NULL ;
2003-03-15 06:00:16 +00:00
/* MGCP message for queuing up */
struct mgcp_message {
unsigned int seqno ;
int len ;
struct mgcp_message * next ;
unsigned char buf [ 0 ] ;
} ;
2003-05-06 04:03:58 +00:00
# define MAX_SUBS 2
# define SUB_REAL 0
# define SUB_ALT 1
struct mgcp_subchannel {
pthread_mutex_t lock ;
int id ;
struct ast_channel * owner ;
struct mgcp_endpoint * parent ;
struct ast_rtp * rtp ;
struct sockaddr_in tmpdest ;
char txident [ 80 ] ;
char cxident [ 80 ] ;
char callid [ 80 ] ;
time_t lastouttime ;
int lastout ;
int cxmode ;
int nat ;
int iseq ; /* Not used? RTP? */
int outgoing ;
int alreadygone ;
int messagepending ;
struct mgcp_message * msgs ; /* Message queue */
struct mgcp_subchannel * next ; /* for out circular linked list */
} ;
# define MGCP_ONHOOK 1
# define MGCP_OFFHOOK 2
2002-12-29 19:13:07 +00:00
# define TYPE_TRUNK 1
# define TYPE_LINE 2
struct mgcp_endpoint {
pthread_mutex_t lock ;
char name [ 80 ] ;
2003-05-07 15:29:20 +00:00
struct mgcp_subchannel * sub ; /* pointer to our current connection, channel and stuff */
2002-12-29 19:13:07 +00:00
char accountcode [ 80 ] ;
char exten [ AST_MAX_EXTENSION ] ; /* Extention where to start */
char context [ AST_MAX_EXTENSION ] ;
char language [ MAX_LANGUAGE ] ;
2003-05-06 04:03:58 +00:00
char callerid [ AST_MAX_EXTENSION ] ; /* Caller*ID */
char lastcallerid [ AST_MAX_EXTENSION ] ; /* Last Caller*ID */
char call_forward [ AST_MAX_EXTENSION ] ; /* Last Caller*ID */
char mailbox [ AST_MAX_EXTENSION ] ;
char musicclass [ MAX_LANGUAGE ] ;
2002-12-29 19:13:07 +00:00
char curtone [ 80 ] ; /* Current tone */
2003-05-06 04:03:58 +00:00
unsigned int callgroup ;
unsigned int pickupgroup ;
int callwaiting ;
int transfer ;
int threewaycalling ;
int cancallforward ;
int callreturn ;
int dnd ; /* How does this affect callwait? Do we just deny a mgcp_request if we're dnd? */
2002-12-29 19:13:07 +00:00
int hascallerid ;
2003-05-06 04:03:58 +00:00
int hidecallerid ;
2003-03-10 20:39:12 +00:00
int dtmfinband ;
2002-12-29 19:13:07 +00:00
int amaflags ;
int type ;
int group ;
2003-05-06 04:03:58 +00:00
int iseq ; /* Not used? */
int lastout ; /* tracking this on the subchannels. Is it needed here? */
int needdestroy ; /* Not used? */
2002-12-29 19:13:07 +00:00
int capability ;
2003-03-12 06:00:18 +00:00
int nonCodecCapability ;
2003-05-06 04:03:58 +00:00
int onhooktime ;
int msgstate ; /* voicemail message state */
int immediate ;
int hookstate ;
int adsi ;
struct ast_dsp * dsp ; /* XXX Should there be a dsp/subchannel? XXX */
/* owner is tracked on the subchannels, and the *sub indicates whos in charge */
/* struct ast_channel *owner; */
/* struct ast_rtp *rtp; */
/* struct sockaddr_in tmpdest; */
/* message go the the endpoint and not the channel so they stay here */
2002-12-29 19:13:07 +00:00
struct mgcp_endpoint * next ;
struct mgcp_gateway * parent ;
} ;
2003-04-27 21:34:27 +00:00
static struct mgcp_gateway {
2002-12-29 19:13:07 +00:00
/* A gateway containing one or more endpoints */
char name [ 80 ] ;
struct sockaddr_in addr ;
2003-03-09 06:00:18 +00:00
struct sockaddr_in defaddr ;
2002-12-29 19:13:07 +00:00
struct in_addr ourip ;
2003-03-09 06:00:18 +00:00
int dynamic ;
int expire ; /* XXX Should we ever expire dynamic registrations? XXX */
2002-12-29 19:13:07 +00:00
struct mgcp_endpoint * endpoints ;
struct ast_ha * ha ;
struct mgcp_gateway * next ;
} * gateways ;
static pthread_mutex_t gatelock = AST_MUTEX_INITIALIZER ;
static int mgcpsock = - 1 ;
static struct sockaddr_in bindaddr ;
static struct ast_frame * mgcp_read ( struct ast_channel * ast ) ;
2003-05-06 04:03:58 +00:00
static int transmit_response ( struct mgcp_subchannel * sub , char * msg , struct mgcp_request * req , char * msgrest ) ;
static int transmit_notify_request ( struct mgcp_subchannel * sub , char * tone ) ;
static int transmit_modify_request ( struct mgcp_subchannel * sub ) ;
static int transmit_notify_request_with_callerid ( struct mgcp_subchannel * sub , char * tone , char * callerid ) ;
static int transmit_modify_with_sdp ( struct mgcp_subchannel * sub , struct ast_rtp * rtp ) ;
static int transmit_connection_del ( struct mgcp_subchannel * sub ) ;
2003-04-11 19:17:05 +00:00
static int transmit_audit_endpoint ( struct mgcp_endpoint * p ) ;
2003-05-06 04:03:58 +00:00
static void start_rtp ( struct mgcp_subchannel * sub ) ;
static int has_voicemail ( struct mgcp_endpoint * p )
{
return ast_app_has_voicemail ( p - > mailbox ) ;
}
static int unalloc_sub ( struct mgcp_subchannel * sub )
{
struct mgcp_endpoint * p = sub - > parent ;
if ( p - > sub = = sub ) {
ast_log ( LOG_WARNING , " Trying to unalloc the real channel %s@%s?!? \n " , p - > name , p - > parent - > name ) ;
return - 1 ;
}
ast_log ( LOG_DEBUG , " Released sub %d of channel %s@%s \n " , sub - > id , p - > name , p - > parent - > name ) ;
sub - > owner = NULL ;
if ( strlen ( sub - > cxident ) ) {
transmit_connection_del ( sub ) ;
}
sub - > cxident [ 0 ] = ' \0 ' ;
sub - > callid [ 0 ] = ' \0 ' ;
sub - > cxmode = MGCP_CX_INACTIVE ;
sub - > outgoing = 0 ;
sub - > alreadygone = 0 ;
memset ( & sub - > tmpdest , 0 , sizeof ( sub - > tmpdest ) ) ;
if ( sub - > rtp ) {
ast_rtp_destroy ( sub - > rtp ) ;
sub - > rtp = NULL ;
}
return 0 ;
}
2002-12-29 19:13:07 +00:00
2003-05-06 04:03:58 +00:00
static int __mgcp_xmit ( struct mgcp_subchannel * sub , char * data , int len )
2002-12-29 19:13:07 +00:00
{
2003-05-06 04:03:58 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2002-12-29 19:13:07 +00:00
int res ;
2003-03-09 06:00:18 +00:00
if ( p - > parent - > addr . sin_addr . s_addr )
res = sendto ( mgcpsock , data , len , 0 , ( struct sockaddr * ) & p - > parent - > addr , sizeof ( struct sockaddr_in ) ) ;
else
res = sendto ( mgcpsock , data , len , 0 , ( struct sockaddr * ) & p - > parent - > defaddr , sizeof ( struct sockaddr_in ) ) ;
2002-12-29 19:13:07 +00:00
if ( res ! = len ) {
ast_log ( LOG_WARNING , " mgcp_xmit returned %d: %s \n " , res , strerror ( errno ) ) ;
}
return res ;
}
2003-05-06 04:03:58 +00:00
static int send_response ( struct mgcp_subchannel * sub , struct mgcp_request * req )
2002-12-29 19:13:07 +00:00
{
2003-05-06 04:03:58 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2002-12-29 19:13:07 +00:00
int res ;
2003-05-06 04:03:58 +00:00
if ( mgcpdebug ) {
2003-03-09 06:00:18 +00:00
ast_verbose ( " Transmitting: \n %s \n to %s:%d \n " , req - > data , inet_ntoa ( p - > parent - > addr . sin_addr ) , ntohs ( p - > parent - > addr . sin_port ) ) ;
2003-05-06 04:03:58 +00:00
}
res = __mgcp_xmit ( sub , req - > data , req - > len ) ;
2002-12-29 19:13:07 +00:00
if ( res > 0 )
res = 0 ;
return res ;
}
2003-03-15 06:00:16 +00:00
static void dump_queue ( struct mgcp_endpoint * p )
{
struct mgcp_message * cur ;
2003-05-06 04:03:58 +00:00
struct mgcp_subchannel * sub = p - > sub ;
do {
while ( sub - > msgs ) {
cur = sub - > msgs ;
sub - > msgs = sub - > msgs - > next ;
ast_log ( LOG_NOTICE , " Removing message from %s@%s-%d tansaction %d \n " , p - > name , p - > parent - > name , sub - > id , cur - > seqno ) ;
free ( cur ) ;
}
sub - > messagepending = 0 ;
sub - > msgs = NULL ;
sub = sub - > next ;
} while ( sub ! = p - > sub ) ;
2003-03-15 06:00:16 +00:00
}
2003-05-06 04:03:58 +00:00
static int mgcp_postrequest ( struct mgcp_subchannel * sub , unsigned char * data , int len , unsigned int seqno )
2003-03-15 06:00:16 +00:00
{
struct mgcp_message * msg = malloc ( sizeof ( struct mgcp_message ) + len ) ;
struct mgcp_message * cur ;
2003-05-06 04:03:58 +00:00
time_t t ;
if ( ! msg ) {
2003-03-15 06:00:16 +00:00
return - 1 ;
2003-05-06 04:03:58 +00:00
}
time ( & t ) ;
if ( sub - > messagepending & & ( sub - > lastouttime + 20 < t ) ) {
2003-06-27 23:02:52 +00:00
ast_log ( LOG_NOTICE , " Timeout waiting for response to message:%d, lastouttime: %ld, now: %ld. Dumping pending queue \n " ,
2003-05-06 04:03:58 +00:00
sub - > msgs ? sub - > msgs - > seqno : - 1 , sub - > lastouttime , t ) ;
dump_queue ( sub - > parent ) ;
}
2003-03-15 06:00:16 +00:00
msg - > seqno = seqno ;
msg - > next = NULL ;
2003-05-06 04:03:58 +00:00
msg - > len = len ;
2003-03-15 06:00:16 +00:00
memcpy ( msg - > buf , data , msg - > len ) ;
2003-05-06 04:03:58 +00:00
cur = sub - > msgs ;
2003-03-15 06:00:16 +00:00
if ( cur ) {
while ( cur - > next )
cur = cur - > next ;
cur - > next = msg ;
2003-05-06 04:03:58 +00:00
} else {
sub - > msgs = msg ;
}
if ( ! sub - > messagepending ) {
sub - > messagepending = 1 ;
sub - > lastout = seqno ;
sub - > lastouttime = t ;
__mgcp_xmit ( sub , msg - > buf , msg - > len ) ;
2003-03-15 06:00:16 +00:00
/* XXX Should schedule retransmission XXX */
} else
ast_log ( LOG_DEBUG , " Deferring transmission of transaction %d \n " , seqno ) ;
return 0 ;
}
2003-05-06 04:03:58 +00:00
static int send_request ( struct mgcp_subchannel * sub , struct mgcp_request * req , unsigned int seqno )
2002-12-29 19:13:07 +00:00
{
int res ;
2003-05-06 04:03:58 +00:00
struct mgcp_endpoint * p = sub - > parent ;
if ( mgcpdebug ) {
ast_verbose ( " Posting Request: \n %s to %s:%d \n " , req - > data ,
inet_ntoa ( p - > parent - > addr . sin_addr ) , ntohs ( p - > parent - > addr . sin_port ) ) ;
}
2003-03-15 06:00:16 +00:00
2003-05-06 04:03:58 +00:00
res = mgcp_postrequest ( sub , req - > data , req - > len , seqno ) ;
2002-12-29 19:13:07 +00:00
return res ;
}
static int mgcp_call ( struct ast_channel * ast , char * dest , int timeout )
{
int res ;
struct mgcp_endpoint * p ;
2003-05-06 04:03:58 +00:00
struct mgcp_subchannel * sub ;
char * tone ;
if ( mgcpdebug ) {
ast_verbose ( VERBOSE_PREFIX_3 " MGCP mgcp_call(%s) \n " , ast - > name ) ;
}
sub = ast - > pvt - > pvt ;
p = sub - > parent ;
switch ( p - > hookstate ) {
case MGCP_OFFHOOK :
tone = " L/wt " ;
break ;
case MGCP_ONHOOK :
default :
tone = " L/rg " ;
break ;
}
2002-12-29 19:13:07 +00:00
if ( ( ast - > _state ! = AST_STATE_DOWN ) & & ( ast - > _state ! = AST_STATE_RESERVED ) ) {
ast_log ( LOG_WARNING , " mgcp_call called on %s, neither down nor reserved \n " , ast - > name ) ;
return - 1 ;
}
res = 0 ;
2003-05-06 04:03:58 +00:00
sub - > outgoing = 1 ;
sub - > cxmode = MGCP_CX_RECVONLY ;
2002-12-29 19:13:07 +00:00
if ( p - > type = = TYPE_LINE ) {
2003-05-06 04:03:58 +00:00
if ( ! sub - > rtp ) {
start_rtp ( sub ) ;
} else {
transmit_modify_request ( sub ) ;
}
if ( sub - > next - > owner & & strlen ( sub - > next - > cxident ) & & strlen ( sub - > next - > callid ) ) {
/* try to prevent a callwait from disturbing the other connection */
sub - > next - > cxmode = MGCP_CX_RECVONLY ;
transmit_modify_request ( sub - > next ) ;
}
transmit_notify_request_with_callerid ( sub , tone , ast - > callerid ) ;
2002-12-29 19:13:07 +00:00
ast_setstate ( ast , AST_STATE_RINGING ) ;
ast_queue_control ( ast , AST_CONTROL_RINGING , 0 ) ;
2003-05-06 04:03:58 +00:00
if ( sub - > next - > owner & & strlen ( sub - > next - > cxident ) & & strlen ( sub - > next - > callid ) ) {
/* Put the connection back in sendrecv */
sub - > next - > cxmode = MGCP_CX_SENDRECV ;
transmit_modify_request ( sub - > next ) ;
}
2002-12-29 19:13:07 +00:00
} else {
ast_log ( LOG_NOTICE , " Don't know how to dial on trunks yet \n " ) ;
res = - 1 ;
}
return res ;
}
static int mgcp_hangup ( struct ast_channel * ast )
{
2003-05-06 04:03:58 +00:00
struct mgcp_subchannel * sub = ast - > pvt - > pvt ;
struct mgcp_endpoint * p = sub - > parent ;
if ( mgcpdebug ) {
ast_verbose ( VERBOSE_PREFIX_3 " MGCP mgcp_hangup(%s) on %s@%s \n " , ast - > name , p - > name , p - > parent - > name ) ;
}
2002-12-29 19:13:07 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " mgcp_hangup(%s) \n " , ast - > name ) ;
if ( ! ast - > pvt - > pvt ) {
ast_log ( LOG_DEBUG , " Asked to hangup channel not connected \n " ) ;
return 0 ;
}
2003-05-06 04:03:58 +00:00
if ( ( p - > dtmfinband ) & & ( p - > dsp ! = NULL ) ) {
ast_dsp_free ( p - > dsp ) ;
2003-03-10 20:39:12 +00:00
}
2003-05-06 04:03:58 +00:00
ast_pthread_mutex_lock ( & sub - > lock ) ;
sub - > owner = NULL ;
if ( strlen ( sub - > cxident ) ) {
transmit_connection_del ( sub ) ;
}
strcpy ( sub - > cxident , " " ) ;
if ( ( sub = = p - > sub ) & & sub - > next - > owner ) {
if ( p - > hookstate = = MGCP_OFFHOOK ) {
if ( sub - > next - > owner & & sub - > next - > owner - > bridge ) {
transmit_notify_request_with_callerid ( p - > sub , " L/wt " , sub - > next - > owner - > bridge - > callerid ) ;
}
} else {
/* set our other connection as the primary and swith over to it */
p - > sub = sub - > next ;
p - > sub - > cxmode = MGCP_CX_RECVONLY ;
transmit_modify_request ( p - > sub ) ;
if ( sub - > next - > owner & & sub - > next - > owner - > bridge ) {
transmit_notify_request_with_callerid ( p - > sub , " L/rg " , sub - > next - > owner - > callerid ) ;
}
}
} else if ( ( sub = = p - > sub - > next ) & & p - > hookstate = = MGCP_OFFHOOK ) {
transmit_notify_request ( sub , " v " ) ;
} else if ( p - > hookstate = = MGCP_OFFHOOK ) {
transmit_notify_request ( sub , " ro " ) ;
} else {
transmit_notify_request ( sub , " " ) ;
}
2002-12-29 19:13:07 +00:00
ast - > pvt - > pvt = NULL ;
2003-05-06 04:03:58 +00:00
sub - > alreadygone = 0 ;
sub - > outgoing = 0 ;
sub - > cxmode = MGCP_CX_INACTIVE ;
strcpy ( sub - > callid , " " ) ;
2003-02-16 06:00:12 +00:00
/* Reset temporary destination */
2003-05-06 04:03:58 +00:00
memset ( & sub - > tmpdest , 0 , sizeof ( sub - > tmpdest ) ) ;
if ( sub - > rtp ) {
ast_rtp_destroy ( sub - > rtp ) ;
sub - > rtp = NULL ;
2002-12-29 19:13:07 +00:00
}
2003-05-06 04:03:58 +00:00
if ( ( p - > hookstate = = MGCP_ONHOOK ) & & ( ! sub - > next - > rtp ) ) {
if ( has_voicemail ( p ) ) {
if ( mgcpdebug ) {
ast_verbose ( VERBOSE_PREFIX_3 " MGCP mgcp_hangup(%s) on %s@%s set vmwi(+) \n " , ast - > name , p - > name , p - > parent - > name ) ;
}
transmit_notify_request ( sub , " vmwi(+) " ) ;
} else {
if ( mgcpdebug ) {
ast_verbose ( VERBOSE_PREFIX_3 " MGCP mgcp_hangup(%s) on %s@%s set vmwi(-) \n " , ast - > name , p - > name , p - > parent - > name ) ;
}
transmit_notify_request ( sub , " vmwi(-) " ) ;
}
}
ast_pthread_mutex_unlock ( & sub - > lock ) ;
2002-12-29 19:13:07 +00:00
return 0 ;
}
static int mgcp_show_endpoints ( int fd , int argc , char * argv [ ] )
{
struct mgcp_gateway * g ;
struct mgcp_endpoint * e ;
int hasendpoints = 0 ;
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
ast_pthread_mutex_lock ( & gatelock ) ;
g = gateways ;
while ( g ) {
e = g - > endpoints ;
2003-03-09 06:00:18 +00:00
ast_cli ( fd , " Gateway '%s' at %s (%s) \n " , g - > name , g - > addr . sin_addr . s_addr ? inet_ntoa ( g - > addr . sin_addr ) : inet_ntoa ( g - > defaddr . sin_addr ) , g - > dynamic ? " Dynamic " : " Static " ) ;
2002-12-29 19:13:07 +00:00
while ( e ) {
2003-05-06 04:03:58 +00:00
ast_cli ( fd , " -- '%s@%s in '%s' is %s \n " , e - > name , g - > name , e - > context , e - > sub - > owner ? " active " : " idle " ) ;
2002-12-29 19:13:07 +00:00
hasendpoints = 1 ;
e = e - > next ;
}
if ( ! hasendpoints ) {
ast_cli ( fd , " << No Endpoints Defined >> " ) ;
}
g = g - > next ;
}
ast_pthread_mutex_unlock ( & gatelock ) ;
return RESULT_SUCCESS ;
}
static char show_endpoints_usage [ ] =
" Usage: mgcp show endpoints \n "
" Lists all endpoints known to the MGCP (Media Gateawy Control Protocol) subsystem. \n " ;
static struct ast_cli_entry cli_show_endpoints =
{ { " mgcp " , " show " , " endpoints " , NULL } , mgcp_show_endpoints , " Show defined MGCP endpoints " , show_endpoints_usage } ;
2003-04-11 19:17:05 +00:00
static int mgcp_audit_endpoint ( int fd , int argc , char * argv [ ] )
{
struct mgcp_gateway * g ;
struct mgcp_endpoint * e ;
int found = 0 ;
2003-04-14 20:48:30 +00:00
char * ename , * gname , * c ;
2003-04-11 19:17:05 +00:00
if ( ! mgcpdebug ) {
return RESULT_SHOWUSAGE ;
}
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
/* split the name into parts by null */
ename = argv [ 3 ] ;
gname = ename ;
while ( * gname ) {
if ( * gname = = ' @ ' ) {
* gname = 0 ;
gname + + ;
break ;
}
gname + + ;
}
2003-04-14 20:48:30 +00:00
if ( gname [ 0 ] = = ' [ ' )
gname + + ;
if ( ( c = strrchr ( gname , ' ] ' ) ) )
* c = ' \0 ' ;
2003-04-11 19:17:05 +00:00
ast_pthread_mutex_lock ( & gatelock ) ;
g = gateways ;
while ( g ) {
if ( ! strcasecmp ( g - > name , gname ) ) {
e = g - > endpoints ;
while ( e ) {
if ( ! strcasecmp ( e - > name , ename ) ) {
found = 1 ;
transmit_audit_endpoint ( e ) ;
break ;
}
e = e - > next ;
}
if ( found ) {
break ;
}
}
g = g - > next ;
}
if ( ! found ) {
ast_cli ( fd , " << Could not find endpoint >> " ) ;
}
ast_pthread_mutex_unlock ( & gatelock ) ;
return RESULT_SUCCESS ;
}
static char audit_endpoint_usage [ ] =
" Usage: mgcp audit endpoint <endpointid> \n "
" List the capabilities of an endpoint in the MGCP (Media Gateawy Control Protocol) subsystem. \n "
" mgcp debug MUST be on to see the results of this command. \n " ;
static struct ast_cli_entry cli_audit_endpoint =
{ { " mgcp " , " audit " , " endpoint " , NULL } , mgcp_audit_endpoint , " Audit specified MGCP endpoint " , audit_endpoint_usage } ;
2002-12-29 19:13:07 +00:00
static int mgcp_answer ( struct ast_channel * ast )
{
int res = 0 ;
2003-05-06 04:03:58 +00:00
struct mgcp_subchannel * sub = ast - > pvt - > pvt ;
struct mgcp_endpoint * p = sub - > parent ;
sub - > cxmode = MGCP_CX_SENDRECV ;
if ( ! sub - > rtp ) {
start_rtp ( sub ) ;
} else {
transmit_modify_request ( sub ) ;
}
ast_verbose ( VERBOSE_PREFIX_3 " MGCP mgcp_answer(%s) on %s@%s-%d \n " , ast - > name , p - > name , p - > parent - > name , sub - > id ) ;
2002-12-29 19:13:07 +00:00
if ( ast - > _state ! = AST_STATE_UP ) {
ast_setstate ( ast , AST_STATE_UP ) ;
if ( option_debug )
ast_log ( LOG_DEBUG , " mgcp_answer(%s) \n " , ast - > name ) ;
2003-05-06 04:03:58 +00:00
transmit_notify_request ( sub , " " ) ;
transmit_modify_request ( sub ) ;
2002-12-29 19:13:07 +00:00
}
return res ;
}
2003-05-06 04:03:58 +00:00
static struct ast_frame * mgcp_rtp_read ( struct mgcp_subchannel * sub )
2003-02-12 13:59:15 +00:00
{
2003-05-06 04:03:58 +00:00
/* Retrieve audio/etc from channel. Assumes sub->lock is already held. */
2003-02-12 13:59:15 +00:00
struct ast_frame * f ;
2003-05-06 04:03:58 +00:00
f = ast_rtp_read ( sub - > rtp ) ;
if ( sub - > owner ) {
2003-02-12 13:59:15 +00:00
/* We already hold the channel lock */
if ( f - > frametype = = AST_FRAME_VOICE ) {
2003-05-06 04:03:58 +00:00
if ( f - > subclass ! = sub - > owner - > nativeformats ) {
2003-02-12 13:59:15 +00:00
ast_log ( LOG_DEBUG , " Oooh, format changed to %d \n " , f - > subclass ) ;
2003-05-06 04:03:58 +00:00
sub - > owner - > nativeformats = f - > subclass ;
ast_set_read_format ( sub - > owner , sub - > owner - > readformat ) ;
ast_set_write_format ( sub - > owner , sub - > owner - > writeformat ) ;
2003-02-12 13:59:15 +00:00
}
2003-05-06 04:03:58 +00:00
/* Courtesy fearnor aka alex@pilosoft.com */
if ( sub - > parent - > dtmfinband ) {
2003-05-07 15:29:20 +00:00
#if 0
2003-05-06 04:03:58 +00:00
ast_log ( LOG_NOTICE , " MGCP ast_dsp_process \n " ) ;
2003-05-07 15:29:20 +00:00
# endif
2003-05-06 04:03:58 +00:00
f = ast_dsp_process ( sub - > owner , sub - > parent - > dsp , f , 0 ) ;
}
2003-02-12 13:59:15 +00:00
}
}
return f ;
}
2002-12-29 19:13:07 +00:00
static struct ast_frame * mgcp_read ( struct ast_channel * ast )
{
2003-02-12 13:59:15 +00:00
struct ast_frame * fr ;
2003-05-06 04:03:58 +00:00
struct mgcp_subchannel * sub = ast - > pvt - > pvt ;
ast_pthread_mutex_lock ( & sub - > lock ) ;
fr = mgcp_rtp_read ( sub ) ;
ast_pthread_mutex_unlock ( & sub - > lock ) ;
2003-02-12 13:59:15 +00:00
return fr ;
2002-12-29 19:13:07 +00:00
}
static int mgcp_write ( struct ast_channel * ast , struct ast_frame * frame )
{
2003-05-06 04:03:58 +00:00
struct mgcp_subchannel * sub = ast - > pvt - > pvt ;
2002-12-29 19:13:07 +00:00
int res = 0 ;
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 MGCP write \n " , frame - > frametype ) ;
return 0 ;
}
} else {
if ( ! ( frame - > subclass & ast - > nativeformats ) ) {
ast_log ( LOG_WARNING , " Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d) \n " ,
frame - > subclass , ast - > nativeformats , ast - > readformat , ast - > writeformat ) ;
return - 1 ;
}
}
2003-05-06 04:03:58 +00:00
if ( sub ) {
ast_pthread_mutex_lock ( & sub - > lock ) ;
if ( sub - > rtp ) {
res = ast_rtp_write ( sub - > rtp , frame ) ;
2002-12-29 19:13:07 +00:00
}
2003-05-06 04:03:58 +00:00
ast_pthread_mutex_unlock ( & sub - > lock ) ;
2002-12-29 19:13:07 +00:00
}
return res ;
}
static int mgcp_fixup ( struct ast_channel * oldchan , struct ast_channel * newchan )
{
2003-05-06 04:03:58 +00:00
struct mgcp_subchannel * sub = newchan - > pvt - > pvt ;
ast_log ( LOG_NOTICE , " mgcp_fixup(%s, %s) \n " , oldchan - > name , newchan - > name ) ;
if ( sub - > owner ! = oldchan ) {
ast_log ( LOG_WARNING , " old channel wasn't %p but was %p \n " , oldchan , sub - > owner ) ;
2002-12-29 19:13:07 +00:00
return - 1 ;
}
2003-05-06 04:03:58 +00:00
sub - > owner = newchan ;
2002-12-29 19:13:07 +00:00
return 0 ;
}
static int mgcp_senddigit ( struct ast_channel * ast , char digit )
{
2003-05-06 04:03:58 +00:00
struct mgcp_subchannel * sub = ast - > pvt - > pvt ;
2002-12-29 19:13:07 +00:00
char tmp [ 2 ] ;
tmp [ 0 ] = digit ;
tmp [ 1 ] = ' \0 ' ;
2003-05-06 04:03:58 +00:00
transmit_notify_request ( sub , tmp ) ;
2002-12-29 19:13:07 +00:00
return - 1 ;
}
2003-05-06 04:03:58 +00:00
static char * control2str ( int ind ) {
switch ( ind ) {
case AST_CONTROL_HANGUP :
return " Other end has hungup " ;
case AST_CONTROL_RING :
return " Local ring " ;
case AST_CONTROL_RINGING :
return " Remote end is ringing " ;
case AST_CONTROL_ANSWER :
return " Remote end has answered " ;
case AST_CONTROL_BUSY :
return " Remote end is busy " ;
case AST_CONTROL_TAKEOFFHOOK :
return " Make it go off hook " ;
case AST_CONTROL_OFFHOOK :
return " Line is off hook " ;
case AST_CONTROL_CONGESTION :
return " Congestion (circuits busy) " ;
case AST_CONTROL_FLASH :
return " Flash hook " ;
case AST_CONTROL_WINK :
return " Wink " ;
case AST_CONTROL_OPTION :
return " Set a low-level option " ;
case AST_CONTROL_RADIO_KEY :
return " Key Radio " ;
case AST_CONTROL_RADIO_UNKEY :
return " Un-Key Radio " ;
}
return " UNKNOWN " ;
}
2002-12-29 19:13:07 +00:00
static int mgcp_indicate ( struct ast_channel * ast , int ind )
{
2003-05-06 04:03:58 +00:00
struct mgcp_subchannel * sub = ast - > pvt - > pvt ;
if ( mgcpdebug ) {
ast_verbose ( VERBOSE_PREFIX_3 " MGCP asked to indicate %d '%s' condition on channel %s \n " , ind , control2str ( ind ) , ast - > name ) ;
}
2002-12-29 19:13:07 +00:00
switch ( ind ) {
case AST_CONTROL_RINGING :
2003-05-06 04:03:58 +00:00
transmit_notify_request ( sub , " rt " ) ;
2002-12-29 19:13:07 +00:00
break ;
case AST_CONTROL_BUSY :
2003-05-06 04:03:58 +00:00
transmit_notify_request ( sub , " bz " ) ;
2002-12-29 19:13:07 +00:00
break ;
case AST_CONTROL_CONGESTION :
2003-05-06 04:03:58 +00:00
transmit_notify_request ( sub , " cg " ) ;
2002-12-29 19:13:07 +00:00
break ;
case - 1 :
2003-05-06 04:03:58 +00:00
transmit_notify_request ( sub , " " ) ;
2002-12-29 19:13:07 +00:00
break ;
default :
ast_log ( LOG_WARNING , " Don't know how to indicate condition %d \n " , ind ) ;
return - 1 ;
}
return 0 ;
}
2003-05-06 04:03:58 +00:00
static struct ast_channel * mgcp_new ( struct mgcp_subchannel * sub , int state )
2002-12-29 19:13:07 +00:00
{
struct ast_channel * tmp ;
2003-05-06 04:03:58 +00:00
struct mgcp_endpoint * i = sub - > parent ;
2002-12-29 19:13:07 +00:00
int fmt ;
2003-05-06 04:03:58 +00:00
i = sub - > parent ;
2002-12-29 19:13:07 +00:00
tmp = ast_channel_alloc ( 1 ) ;
if ( tmp ) {
tmp - > nativeformats = i - > capability ;
if ( ! tmp - > nativeformats )
tmp - > nativeformats = capability ;
fmt = ast_best_codec ( tmp - > nativeformats ) ;
2003-05-06 04:03:58 +00:00
snprintf ( tmp - > name , sizeof ( tmp - > name ) , " MGCP/%s@%s-%d " , i - > name , i - > parent - > name , sub - > id ) ;
if ( sub - > rtp )
tmp - > fds [ 0 ] = ast_rtp_fd ( sub - > rtp ) ;
2002-12-29 19:13:07 +00:00
tmp - > type = type ;
2003-03-10 20:39:12 +00:00
if ( i - > dtmfinband ) {
2003-05-06 04:03:58 +00:00
i - > dsp = ast_dsp_new ( ) ;
ast_dsp_set_features ( i - > dsp , DSP_FEATURE_DTMF_DETECT ) ;
2003-03-10 20:39:12 +00:00
} else {
2003-05-06 04:03:58 +00:00
i - > dsp = NULL ;
2003-03-10 20:39:12 +00:00
}
2002-12-29 19:13:07 +00:00
ast_setstate ( tmp , state ) ;
if ( state = = AST_STATE_RING )
tmp - > rings = 1 ;
tmp - > writeformat = fmt ;
tmp - > pvt - > rawwriteformat = fmt ;
tmp - > readformat = fmt ;
tmp - > pvt - > rawreadformat = fmt ;
2003-05-06 04:03:58 +00:00
tmp - > pvt - > pvt = sub ;
2002-12-29 19:13:07 +00:00
tmp - > pvt - > call = mgcp_call ;
tmp - > pvt - > hangup = mgcp_hangup ;
tmp - > pvt - > answer = mgcp_answer ;
tmp - > pvt - > read = mgcp_read ;
tmp - > pvt - > write = mgcp_write ;
tmp - > pvt - > indicate = mgcp_indicate ;
tmp - > pvt - > fixup = mgcp_fixup ;
tmp - > pvt - > send_digit = mgcp_senddigit ;
2003-02-16 06:00:12 +00:00
tmp - > pvt - > bridge = ast_rtp_bridge ;
2002-12-29 19:13:07 +00:00
if ( strlen ( i - > language ) )
strncpy ( tmp - > language , i - > language , sizeof ( tmp - > language ) - 1 ) ;
2003-05-06 04:03:58 +00:00
if ( strlen ( i - > accountcode ) )
strncpy ( tmp - > accountcode , i - > accountcode , sizeof ( tmp - > accountcode ) - 1 ) ;
if ( i - > amaflags )
tmp - > amaflags = i - > amaflags ;
sub - > owner = tmp ;
2002-12-29 19:13:07 +00:00
ast_pthread_mutex_lock ( & usecnt_lock ) ;
usecnt + + ;
ast_pthread_mutex_unlock ( & usecnt_lock ) ;
ast_update_use_count ( ) ;
2003-05-06 04:03:58 +00:00
tmp - > callgroup = i - > callgroup ;
tmp - > pickupgroup = i - > pickupgroup ;
strncpy ( tmp - > call_forward , i - > call_forward , sizeof ( tmp - > call_forward ) ) ;
2002-12-29 19:13:07 +00:00
strncpy ( tmp - > context , i - > context , sizeof ( tmp - > context ) - 1 ) ;
strncpy ( tmp - > exten , i - > exten , sizeof ( tmp - > exten ) - 1 ) ;
if ( strlen ( i - > callerid ) )
tmp - > callerid = strdup ( i - > callerid ) ;
2003-05-06 04:03:58 +00:00
if ( ! i - > adsi )
tmp - > adsicpe = AST_ADSI_UNAVAILABLE ;
2002-12-29 19:13:07 +00:00
tmp - > priority = 1 ;
if ( state ! = AST_STATE_DOWN ) {
if ( ast_pbx_start ( tmp ) ) {
ast_log ( LOG_WARNING , " Unable to start PBX on %s \n " , tmp - > name ) ;
ast_hangup ( tmp ) ;
tmp = NULL ;
}
}
2003-05-06 04:03:58 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " MGCP mgcp_new(%s) created in state: %s \n " , tmp - > name , ast_state2str ( state ) ) ;
} else {
2002-12-29 19:13:07 +00:00
ast_log ( LOG_WARNING , " Unable to allocate channel structure \n " ) ;
2003-05-06 04:03:58 +00:00
}
2002-12-29 19:13:07 +00:00
return tmp ;
}
2003-03-12 06:00:18 +00:00
static char * get_sdp_by_line ( char * line , char * name , int nameLen ) {
if ( strncasecmp ( line , name , nameLen ) = = 0 & & line [ nameLen ] = = ' = ' ) {
char * r = line + nameLen + 1 ;
while ( * r & & ( * r < 33 ) ) + + r ;
return r ;
}
return " " ;
}
static char * get_sdp ( struct mgcp_request * req , char * name ) {
int x ;
int len = strlen ( name ) ;
char * r ;
for ( x = 0 ; x < req - > lines ; x + + ) {
r = get_sdp_by_line ( req - > line [ x ] , name , len ) ;
if ( r [ 0 ] ! = ' \0 ' ) return r ;
}
return " " ;
}
static void sdpLineNum_iterator_init ( int * iterator ) {
* iterator = 0 ;
}
static char * get_sdp_iterate ( int * iterator ,
struct mgcp_request * req , char * name ) {
int len = strlen ( name ) ;
char * r ;
while ( * iterator < req - > lines ) {
r = get_sdp_by_line ( req - > line [ ( * iterator ) + + ] , name , len ) ;
if ( r [ 0 ] ! = ' \0 ' ) return r ;
}
return " " ;
2002-12-29 19:13:07 +00:00
}
static char * __get_header ( struct mgcp_request * req , char * name , int * start )
{
int x ;
int len = strlen ( name ) ;
char * r ;
for ( x = * start ; x < req - > headers ; x + + ) {
if ( ! strncasecmp ( req - > header [ x ] , name , len ) & &
( req - > header [ x ] [ len ] = = ' : ' ) ) {
r = req - > header [ x ] + len + 1 ;
while ( * r & & ( * r < 33 ) )
r + + ;
* start = x + 1 ;
return r ;
}
}
/* Don't return NULL, so get_header is always a valid pointer */
return " " ;
}
static char * get_header ( struct mgcp_request * req , char * name )
{
int start = 0 ;
return __get_header ( req , name , & start ) ;
}
2003-02-12 13:59:15 +00:00
#if 0
2002-12-29 19:13:07 +00:00
static int rtpready ( struct ast_rtp * rtp , struct ast_frame * f , void * data )
{
/* Just deliver the audio directly */
struct mgcp_endpoint * p = data ;
ast_pthread_mutex_lock ( & p - > lock ) ;
if ( p - > owner ) {
/* Generally, you lock in the order channel lock, followed by private
lock . Since here we are doing the reverse , there is the possibility
of deadlock . As a result , in the case of a deadlock , we simply fail out
here . */
if ( ! pthread_mutex_trylock ( & p - > owner - > lock ) ) {
if ( f - > frametype = = AST_FRAME_VOICE ) {
if ( f - > subclass ! = p - > owner - > nativeformats ) {
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 ) ;
ast_set_write_format ( p - > owner , p - > owner - > writeformat ) ;
}
2003-03-10 20:39:12 +00:00
if ( p - > dtmfinband ) {
2003-05-06 04:03:58 +00:00
f = ast_dsp_process ( p - > owner , p - > dsp , f , 0 ) ;
2003-03-10 20:39:12 +00:00
}
2002-12-29 19:13:07 +00:00
}
ast_queue_frame ( p - > owner , f , 0 ) ;
pthread_mutex_unlock ( & p - > owner - > lock ) ;
}
}
ast_pthread_mutex_unlock ( & p - > lock ) ;
return 0 ;
}
2003-02-12 13:59:15 +00:00
# endif
2002-12-29 19:13:07 +00:00
2003-05-06 04:03:58 +00:00
static struct mgcp_subchannel * find_subchannel ( char * name , int msgid , struct sockaddr_in * sin )
2002-12-29 19:13:07 +00:00
{
struct mgcp_endpoint * p = NULL ;
2003-05-06 04:03:58 +00:00
struct mgcp_subchannel * sub = NULL ;
2002-12-29 19:13:07 +00:00
struct mgcp_gateway * g ;
char tmp [ 256 ] = " " ;
2003-04-14 20:48:30 +00:00
char * at = NULL , * c ;
2003-05-06 04:03:58 +00:00
int found = 0 ;
2002-12-29 19:13:07 +00:00
if ( name ) {
strncpy ( tmp , name , sizeof ( tmp ) - 1 ) ;
at = strchr ( tmp , ' @ ' ) ;
if ( ! at ) {
ast_log ( LOG_NOTICE , " Endpoint '%s' has no at sign! \n " , name ) ;
return NULL ;
}
* at = ' \0 ' ;
at + + ;
}
ast_pthread_mutex_lock ( & gatelock ) ;
2003-04-14 20:48:30 +00:00
if ( at & & ( at [ 0 ] = = ' [ ' ) ) {
at + + ;
c = strrchr ( at , ' ] ' ) ;
if ( c )
* c = ' \0 ' ;
}
2002-12-29 19:13:07 +00:00
g = gateways ;
while ( g ) {
2003-03-09 06:00:18 +00:00
if ( ( ! name | | ! strcasecmp ( g - > name , at ) ) & &
( sin | | g - > addr . sin_addr . s_addr | | g - > defaddr . sin_addr . s_addr ) ) {
/* Found the gateway. If it's dynamic, save it's address -- now for the endpoint */
if ( sin & & g - > dynamic ) {
if ( ( g - > addr . sin_addr . s_addr ! = sin - > sin_addr . s_addr ) | |
( g - > addr . sin_port ! = sin - > sin_port ) ) {
memcpy ( & g - > addr , sin , sizeof ( g - > addr ) ) ;
2003-05-04 05:52:52 +00:00
if ( ast_ouraddrfor ( & g - > addr . sin_addr , & g - > ourip ) )
memcpy ( & g - > ourip , & __ourip , sizeof ( g - > ourip ) ) ;
2003-03-09 06:00:18 +00:00
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Registered MGCP gateway '%s' at %s port %d \n " , g - > name , inet_ntoa ( g - > addr . sin_addr ) , ntohs ( g - > addr . sin_port ) ) ;
}
}
2002-12-29 19:13:07 +00:00
p = g - > endpoints ;
while ( p ) {
2003-05-06 04:03:58 +00:00
ast_log ( LOG_DEBUG , " Searching on %s@%s for subchannel \n " , p - > name , g - > name ) ;
if ( msgid ) {
sub = p - > sub ;
do {
ast_log ( LOG_DEBUG , " Searching on %s@%s-%d for subchannel with lastout: %d \n " , p - > name , g - > name , sub - > id , msgid ) ;
if ( sub - > lastout = = msgid ) {
ast_log ( LOG_DEBUG , " Found subchannel sub%d to handle request %d sub->lastout: %d \n " , sub - > id , msgid , sub - > lastout ) ;
found = 1 ;
break ;
}
sub = sub - > next ;
} while ( sub ! = p - > sub ) ;
if ( found ) {
break ;
}
} else if ( name & & ! strcasecmp ( p - > name , tmp ) ) {
ast_log ( LOG_DEBUG , " Coundn't determine subchannel, assuming current master %s@%s-%d \n " ,
p - > name , g - > name , p - > sub - > id ) ;
sub = p - > sub ;
found = 1 ;
break ;
}
p = p - > next ;
2002-12-29 19:13:07 +00:00
}
2003-05-06 04:03:58 +00:00
if ( sub & & found ) {
2002-12-29 19:13:07 +00:00
break ;
2003-05-06 04:03:58 +00:00
}
2002-12-29 19:13:07 +00:00
}
g = g - > next ;
}
ast_pthread_mutex_unlock ( & gatelock ) ;
2003-05-06 04:03:58 +00:00
if ( ! sub ) {
2002-12-29 19:13:07 +00:00
if ( name ) {
if ( g )
ast_log ( LOG_NOTICE , " Endpoint '%s' not found on gateway '%s' \n " , tmp , at ) ;
else
ast_log ( LOG_NOTICE , " Gateway '%s' (and thus its endpoint '%s') does not exist \n " , at , tmp ) ;
}
}
2003-05-06 04:03:58 +00:00
return sub ;
2002-12-29 19:13:07 +00:00
}
static void parse ( struct mgcp_request * req )
{
/* Divide fields by NULL's */
char * c ;
int f = 0 ;
c = req - > data ;
/* First header starts immediately */
req - > header [ f ] = c ;
while ( * c ) {
if ( * c = = ' \n ' ) {
/* We've got a new header */
* c = 0 ;
#if 0
printf ( " Header: %s (%d) \n " , req - > header [ f ] , strlen ( req - > header [ f ] ) ) ;
# endif
if ( ! strlen ( req - > header [ f ] ) ) {
/* Line by itself means we're now in content */
c + + ;
break ;
}
if ( f > = MGCP_MAX_HEADERS - 1 ) {
ast_log ( LOG_WARNING , " Too many MGCP headers... \n " ) ;
} else
f + + ;
req - > header [ f ] = c + 1 ;
} else if ( * c = = ' \r ' ) {
/* Ignore but eliminate \r's */
* c = 0 ;
}
c + + ;
}
/* Check for last header */
if ( strlen ( req - > header [ f ] ) )
f + + ;
req - > headers = f ;
/* Now we process any mime content */
f = 0 ;
req - > line [ f ] = c ;
while ( * c ) {
if ( * c = = ' \n ' ) {
/* We've got a new line */
* c = 0 ;
#if 0
printf ( " Line: %s (%d) \n " , req - > line [ f ] , strlen ( req - > line [ f ] ) ) ;
# endif
if ( f > = MGCP_MAX_LINES - 1 ) {
ast_log ( LOG_WARNING , " Too many SDP lines... \n " ) ;
} else
f + + ;
req - > line [ f ] = c + 1 ;
} else if ( * c = = ' \r ' ) {
/* Ignore and eliminate \r's */
* c = 0 ;
}
c + + ;
}
/* Check for last line */
if ( strlen ( req - > line [ f ] ) )
f + + ;
req - > lines = f ;
/* Parse up the initial header */
c = req - > header [ 0 ] ;
while ( * c & & * c < 33 ) c + + ;
/* First the verb */
req - > verb = c ;
while ( * c & & ( * c > 32 ) ) c + + ;
if ( * c ) {
* c = ' \0 ' ;
c + + ;
while ( * c & & ( * c < 33 ) ) c + + ;
req - > identifier = c ;
while ( * c & & ( * c > 32 ) ) c + + ;
if ( * c ) {
* c = ' \0 ' ;
c + + ;
while ( * c & & ( * c < 33 ) ) c + + ;
req - > endpoint = c ;
while ( * c & & ( * c > 32 ) ) c + + ;
if ( * c ) {
* c = ' \0 ' ;
c + + ;
while ( * c & & ( * c < 33 ) ) c + + ;
req - > version = c ;
while ( * c & & ( * c > 32 ) ) c + + ;
while ( * c & & ( * c < 33 ) ) c + + ;
while ( * c & & ( * c > 32 ) ) c + + ;
* c = ' \0 ' ;
}
}
}
2003-03-09 06:00:18 +00:00
if ( mgcpdebug ) {
ast_verbose ( " Verb: '%s', Identifier: '%s', Endpoint: '%s', Version: '%s' \n " ,
2003-05-06 04:03:58 +00:00
req - > verb , req - > identifier , req - > endpoint , req - > version ) ;
2003-03-09 06:00:18 +00:00
ast_verbose ( " %d headers, %d lines \n " , req - > headers , req - > lines ) ;
}
2002-12-29 19:13:07 +00:00
if ( * c )
ast_log ( LOG_WARNING , " Odd content, extra stuff left over ('%s') \n " , c ) ;
}
2003-05-06 04:03:58 +00:00
static int process_sdp ( struct mgcp_subchannel * sub , struct mgcp_request * req )
2002-12-29 19:13:07 +00:00
{
char * m ;
char * c ;
2003-03-12 06:00:18 +00:00
char * a ;
2002-12-29 19:13:07 +00:00
char host [ 258 ] ;
int len ;
int portno ;
2003-03-12 06:00:18 +00:00
int peercapability , peerNonCodecCapability ;
2002-12-29 19:13:07 +00:00
struct sockaddr_in sin ;
char * codecs ;
struct hostent * hp ;
int codec ;
2003-03-12 06:00:18 +00:00
int iterator ;
2003-05-06 04:03:58 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2003-03-12 06:00:18 +00:00
2002-12-29 19:13:07 +00:00
/* Get codec and RTP info from SDP */
m = get_sdp ( req , " m " ) ;
c = get_sdp ( req , " c " ) ;
if ( ! strlen ( m ) | | ! strlen ( c ) ) {
ast_log ( LOG_WARNING , " Insufficient information for SDP (m = '%s', c = '%s') \n " , m , c ) ;
return - 1 ;
}
if ( sscanf ( c , " IN IP4 %256s " , host ) ! = 1 ) {
ast_log ( LOG_WARNING , " Invalid host in c= line, '%s' \n " , c ) ;
return - 1 ;
}
/* XXX This could block for a long time, and block the main thread! XXX */
hp = gethostbyname ( host ) ;
if ( ! hp ) {
ast_log ( LOG_WARNING , " Unable to lookup host in c= line, '%s' \n " , c ) ;
return - 1 ;
}
if ( sscanf ( m , " audio %d RTP/AVP %n " , & portno , & len ) ! = 1 ) {
ast_log ( LOG_WARNING , " Unable to determine port number for RTP in '%s' \n " , m ) ;
return - 1 ;
}
sin . sin_family = AF_INET ;
memcpy ( & sin . sin_addr , hp - > h_addr , sizeof ( sin . sin_addr ) ) ;
sin . sin_port = htons ( portno ) ;
2003-05-06 04:03:58 +00:00
ast_rtp_set_peer ( sub - > rtp , & sin ) ;
2002-12-29 19:13:07 +00:00
#if 0
printf ( " Peer RTP is at port %s:%d \n " , inet_ntoa ( sin . sin_addr ) , ntohs ( sin . sin_port ) ) ;
# endif
2003-03-12 06:00:18 +00:00
// Scan through the RTP payload types specified in a "m=" line:
2003-05-06 04:03:58 +00:00
ast_rtp_pt_clear ( sub - > rtp ) ;
2002-12-29 19:13:07 +00:00
codecs = m + len ;
while ( strlen ( codecs ) ) {
if ( sscanf ( codecs , " %d %n " , & codec , & len ) ! = 1 ) {
ast_log ( LOG_WARNING , " Error in codec string '%s' \n " , codecs ) ;
return - 1 ;
}
2003-05-06 04:03:58 +00:00
ast_rtp_set_m_type ( sub - > rtp , codec ) ;
2002-12-29 19:13:07 +00:00
codecs + = len ;
}
2003-03-12 06:00:18 +00:00
// Next, scan through each "a=rtpmap:" line, noting each
// specified RTP payload type (with corresponding MIME subtype):
sdpLineNum_iterator_init ( & iterator ) ;
while ( ( a = get_sdp_iterate ( & iterator , req , " a " ) ) [ 0 ] ! = ' \0 ' ) {
char * mimeSubtype = strdup ( a ) ; // ensures we have enough space
if ( sscanf ( a , " rtpmap: %u %[^/]/ " , & codec , mimeSubtype ) ! = 2 ) continue ;
// Note: should really look at the 'freq' and '#chans' params too
2003-05-06 04:03:58 +00:00
ast_rtp_set_rtpmap_type ( sub - > rtp , codec , " audio " , mimeSubtype ) ;
2003-03-12 06:00:18 +00:00
free ( mimeSubtype ) ;
}
// Now gather all of the codecs that were asked for:
2003-05-06 04:03:58 +00:00
ast_rtp_get_current_formats ( sub - > rtp ,
2003-03-12 06:00:18 +00:00
& peercapability , & peerNonCodecCapability ) ;
2002-12-29 19:13:07 +00:00
p - > capability = capability & peercapability ;
2003-03-12 06:00:18 +00:00
if ( mgcpdebug ) {
2003-03-09 06:00:18 +00:00
ast_verbose ( " Capabilities: us - %d, them - %d, combined - %d \n " ,
2003-05-06 04:03:58 +00:00
capability , peercapability , p - > capability ) ;
2003-03-12 06:00:18 +00:00
ast_verbose ( " Non-codec capabilities: us - %d, them - %d, combined - %d \n " ,
2003-05-06 04:03:58 +00:00
nonCodecCapability , peerNonCodecCapability , p - > nonCodecCapability ) ;
2003-03-12 06:00:18 +00:00
}
2002-12-29 19:13:07 +00:00
if ( ! p - > capability ) {
ast_log ( LOG_WARNING , " No compatible codecs! \n " ) ;
return - 1 ;
}
return 0 ;
}
static int add_header ( struct mgcp_request * req , char * var , char * value )
{
if ( req - > len > = sizeof ( req - > data ) - 4 ) {
ast_log ( LOG_WARNING , " Out of space, can't add anymore \n " ) ;
return - 1 ;
}
if ( req - > lines ) {
ast_log ( LOG_WARNING , " Can't add more headers when lines have been added \n " ) ;
return - 1 ;
}
req - > header [ req - > headers ] = req - > data + req - > len ;
snprintf ( req - > header [ req - > headers ] , sizeof ( req - > data ) - req - > len , " %s: %s \r \n " , var , value ) ;
req - > len + = strlen ( req - > header [ req - > headers ] ) ;
if ( req - > headers < MGCP_MAX_HEADERS )
req - > headers + + ;
else {
ast_log ( LOG_WARNING , " Out of header space \n " ) ;
return - 1 ;
}
return 0 ;
}
static int add_line ( struct mgcp_request * req , char * line )
{
if ( req - > len > = sizeof ( req - > data ) - 4 ) {
ast_log ( LOG_WARNING , " Out of space, can't add anymore \n " ) ;
return - 1 ;
}
if ( ! req - > lines ) {
/* Add extra empty return */
snprintf ( req - > data + req - > len , sizeof ( req - > data ) - req - > len , " \r \n " ) ;
req - > len + = strlen ( req - > data + req - > len ) ;
}
req - > line [ req - > lines ] = req - > data + req - > len ;
snprintf ( req - > line [ req - > lines ] , sizeof ( req - > data ) - req - > len , " %s " , line ) ;
req - > len + = strlen ( req - > line [ req - > lines ] ) ;
if ( req - > lines < MGCP_MAX_LINES )
req - > lines + + ;
else {
ast_log ( LOG_WARNING , " Out of line space \n " ) ;
return - 1 ;
}
return 0 ;
}
static int init_resp ( struct mgcp_request * req , char * resp , struct mgcp_request * orig , char * resprest )
{
/* Initialize a response */
if ( req - > headers | | req - > len ) {
ast_log ( LOG_WARNING , " Request already initialized?!? \n " ) ;
return - 1 ;
}
req - > header [ req - > headers ] = req - > data + req - > len ;
snprintf ( req - > header [ req - > headers ] , sizeof ( req - > data ) - req - > len , " %s %s %s \r \n " , resp , orig - > identifier , resprest ) ;
req - > len + = strlen ( req - > header [ req - > headers ] ) ;
if ( req - > headers < MGCP_MAX_HEADERS )
req - > headers + + ;
else
ast_log ( LOG_WARNING , " Out of header space \n " ) ;
return 0 ;
}
static int init_req ( struct mgcp_endpoint * p , struct mgcp_request * req , char * verb )
{
/* Initialize a response */
if ( req - > headers | | req - > len ) {
ast_log ( LOG_WARNING , " Request already initialized?!? \n " ) ;
return - 1 ;
}
req - > header [ req - > headers ] = req - > data + req - > len ;
snprintf ( req - > header [ req - > headers ] , sizeof ( req - > data ) - req - > len , " %s %d %s@%s MGCP 1.0 \r \n " , verb , oseq , p - > name , p - > parent - > name ) ;
req - > len + = strlen ( req - > header [ req - > headers ] ) ;
if ( req - > headers < MGCP_MAX_HEADERS )
req - > headers + + ;
else
ast_log ( LOG_WARNING , " Out of header space \n " ) ;
return 0 ;
}
static int respprep ( struct mgcp_request * resp , struct mgcp_endpoint * p , char * msg , struct mgcp_request * req , char * msgrest )
{
memset ( resp , 0 , sizeof ( * resp ) ) ;
init_resp ( resp , msg , req , msgrest ) ;
return 0 ;
}
static int reqprep ( struct mgcp_request * req , struct mgcp_endpoint * p , char * verb )
{
memset ( req , 0 , sizeof ( struct mgcp_request ) ) ;
oseq + + ;
init_req ( p , req , verb ) ;
return 0 ;
}
2003-05-06 04:03:58 +00:00
static int transmit_response ( struct mgcp_subchannel * sub , char * msg , struct mgcp_request * req , char * msgrest )
2002-12-29 19:13:07 +00:00
{
struct mgcp_request resp ;
2003-05-06 04:03:58 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2002-12-29 19:13:07 +00:00
respprep ( & resp , p , msg , req , msgrest ) ;
2003-05-06 04:03:58 +00:00
return send_response ( sub , & resp ) ;
2002-12-29 19:13:07 +00:00
}
2003-05-06 04:03:58 +00:00
static int add_sdp ( struct mgcp_request * resp , struct mgcp_subchannel * sub , struct ast_rtp * rtp )
2002-12-29 19:13:07 +00:00
{
int len ;
int codec ;
char costr [ 80 ] ;
struct sockaddr_in sin ;
char v [ 256 ] ;
char s [ 256 ] ;
char o [ 256 ] ;
char c [ 256 ] ;
char t [ 256 ] ;
char m [ 256 ] ;
char a [ 1024 ] = " " ;
int x ;
struct sockaddr_in dest ;
2003-05-06 04:03:58 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2002-12-29 19:13:07 +00:00
/* XXX We break with the "recommendation" and send our IP, in order that our
peer doesn ' t have to gethostbyname ( ) us XXX */
len = 0 ;
2003-05-06 04:03:58 +00:00
if ( ! sub - > rtp ) {
2002-12-29 19:13:07 +00:00
ast_log ( LOG_WARNING , " No way to add SDP without an RTP structure \n " ) ;
return - 1 ;
}
2003-05-06 04:03:58 +00:00
ast_rtp_get_us ( sub - > rtp , & sin ) ;
2002-12-29 19:13:07 +00:00
if ( rtp ) {
ast_rtp_get_peer ( rtp , & dest ) ;
} else {
2003-05-06 04:03:58 +00:00
if ( sub - > tmpdest . sin_addr . s_addr ) {
dest . sin_addr = sub - > tmpdest . sin_addr ;
dest . sin_port = sub - > tmpdest . sin_port ;
2003-02-16 06:00:12 +00:00
/* Reset temporary destination */
2003-05-06 04:03:58 +00:00
memset ( & sub - > tmpdest , 0 , sizeof ( sub - > tmpdest ) ) ;
2003-02-16 06:00:12 +00:00
} else {
dest . sin_addr = p - > parent - > ourip ;
dest . sin_port = sin . sin_port ;
}
2002-12-29 19:13:07 +00:00
}
2003-05-06 04:03:58 +00:00
if ( mgcpdebug ) {
2003-03-09 06:00:18 +00:00
ast_verbose ( " We're at %s port %d \n " , inet_ntoa ( p - > parent - > ourip ) , ntohs ( sin . sin_port ) ) ;
2003-05-06 04:03:58 +00:00
}
2002-12-29 19:13:07 +00:00
snprintf ( v , sizeof ( v ) , " v=0 \r \n " ) ;
snprintf ( o , sizeof ( o ) , " o=root %d %d IN IP4 %s \r \n " , getpid ( ) , getpid ( ) , inet_ntoa ( dest . sin_addr ) ) ;
snprintf ( s , sizeof ( s ) , " s=session \r \n " ) ;
snprintf ( c , sizeof ( c ) , " c=IN IP4 %s \r \n " , inet_ntoa ( dest . sin_addr ) ) ;
snprintf ( t , sizeof ( t ) , " t=0 0 \r \n " ) ;
snprintf ( m , sizeof ( m ) , " m=audio %d RTP/AVP " , ntohs ( dest . sin_port ) ) ;
2003-03-12 06:00:18 +00:00
for ( x = 1 ; x < = AST_FORMAT_MAX_AUDIO ; x < < = 1 ) {
2002-12-29 19:13:07 +00:00
if ( p - > capability & x ) {
2003-05-06 04:03:58 +00:00
if ( mgcpdebug ) {
2003-03-09 06:00:18 +00:00
ast_verbose ( " Answering with capability %d \n " , x ) ;
2003-05-06 04:03:58 +00:00
}
codec = ast_rtp_lookup_code ( sub - > rtp , 1 , x ) ;
if ( codec > - 1 ) {
2002-12-29 19:13:07 +00:00
snprintf ( costr , sizeof ( costr ) , " %d " , codec ) ;
strcat ( m , costr ) ;
2003-03-13 06:00:20 +00:00
snprintf ( costr , sizeof ( costr ) , " a=rtpmap:%d %s/8000 \r \n " , codec , ast_rtp_lookup_mime_subtype ( 1 , x ) ) ;
2002-12-29 19:13:07 +00:00
strcat ( a , costr ) ;
}
}
}
2003-03-12 06:00:18 +00:00
for ( x = 1 ; x < = AST_RTP_MAX ; x < < = 1 ) {
2003-05-06 04:03:58 +00:00
if ( p - > nonCodecCapability & x ) {
if ( mgcpdebug ) {
ast_verbose ( " Answering with non-codec capability %d \n " , x ) ;
}
codec = ast_rtp_lookup_code ( sub - > rtp , 0 , x ) ;
if ( codec > - 1 ) {
snprintf ( costr , sizeof ( costr ) , " %d " , codec ) ;
strcat ( m , costr ) ;
snprintf ( costr , sizeof ( costr ) , " a=rtpmap:%d %s/8000 \r \n " , codec , ast_rtp_lookup_mime_subtype ( 0 , x ) ) ;
strcat ( a , costr ) ;
if ( x = = AST_RTP_DTMF ) {
/* Indicate we support DTMF... Not sure about 16, but MSN supports it so dang it, we will too... */
snprintf ( costr , sizeof costr , " a=fmtp:%d 0-16 \r \n " , codec ) ;
strcat ( a , costr ) ;
}
}
2003-03-12 06:00:18 +00:00
}
2003-05-06 04:03:58 +00:00
}
2002-12-29 19:13:07 +00:00
strcat ( m , " \r \n " ) ;
len = strlen ( v ) + strlen ( s ) + strlen ( o ) + strlen ( c ) + strlen ( t ) + strlen ( m ) + strlen ( a ) ;
snprintf ( costr , sizeof ( costr ) , " %d " , len ) ;
add_line ( resp , v ) ;
add_line ( resp , o ) ;
add_line ( resp , s ) ;
add_line ( resp , c ) ;
add_line ( resp , t ) ;
add_line ( resp , m ) ;
add_line ( resp , a ) ;
return 0 ;
}
2003-05-06 04:03:58 +00:00
static int transmit_modify_with_sdp ( struct mgcp_subchannel * sub , struct ast_rtp * rtp )
2002-12-29 19:13:07 +00:00
{
struct mgcp_request resp ;
char local [ 256 ] ;
char tmp [ 80 ] ;
int x ;
2003-05-06 04:03:58 +00:00
struct mgcp_endpoint * p = sub - > parent ;
if ( ! strlen ( sub - > cxident ) & & rtp ) {
2003-02-16 06:00:12 +00:00
/* We don't have a CXident yet, store the destination and
wait a bit */
2003-05-06 04:03:58 +00:00
ast_rtp_get_peer ( rtp , & sub - > tmpdest ) ;
2003-02-16 06:00:12 +00:00
return 0 ;
}
2002-12-29 19:13:07 +00:00
snprintf ( local , sizeof ( local ) , " p:20 " ) ;
for ( x = 1 ; x < = AST_FORMAT_MAX_AUDIO ; x < < = 1 ) {
if ( p - > capability & x ) {
2003-03-13 06:00:20 +00:00
snprintf ( tmp , sizeof ( tmp ) , " , a:%s " , ast_rtp_lookup_mime_subtype ( 1 , x ) ) ;
2002-12-29 19:13:07 +00:00
strcat ( local , tmp ) ;
}
}
reqprep ( & resp , p , " MDCX " ) ;
2003-05-06 04:03:58 +00:00
add_header ( & resp , " C " , sub - > callid ) ;
2002-12-29 19:13:07 +00:00
add_header ( & resp , " L " , local ) ;
2003-05-06 04:03:58 +00:00
add_header ( & resp , " M " , mgcp_cxmodes [ sub - > cxmode ] ) ;
add_header ( & resp , " X " , sub - > txident ) ;
add_header ( & resp , " I " , sub - > cxident ) ;
/*add_header(&resp, "S", "");*/
add_sdp ( & resp , sub , rtp ) ;
return send_request ( sub , & resp , oseq ) ;
2002-12-29 19:13:07 +00:00
}
2003-05-06 04:03:58 +00:00
static int transmit_connect_with_sdp ( struct mgcp_subchannel * sub , struct ast_rtp * rtp )
2002-12-29 19:13:07 +00:00
{
struct mgcp_request resp ;
char local [ 256 ] ;
char tmp [ 80 ] ;
int x ;
2003-05-06 04:03:58 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2002-12-29 19:13:07 +00:00
snprintf ( local , sizeof ( local ) , " p:20 " ) ;
for ( x = 1 ; x < = AST_FORMAT_MAX_AUDIO ; x < < = 1 ) {
if ( p - > capability & x ) {
2003-03-13 06:00:20 +00:00
snprintf ( tmp , sizeof ( tmp ) , " , a:%s " , ast_rtp_lookup_mime_subtype ( 1 , x ) ) ;
2002-12-29 19:13:07 +00:00
strcat ( local , tmp ) ;
}
}
2003-05-06 04:03:58 +00:00
if ( mgcpdebug ) {
ast_verbose ( VERBOSE_PREFIX_3 " Creating connection for %s@%s-%d in cxmode: %s callid: %s \n " ,
p - > name , p - > parent - > name , sub - > id , mgcp_cxmodes [ sub - > cxmode ] , sub - > callid ) ;
}
2002-12-29 19:13:07 +00:00
reqprep ( & resp , p , " CRCX " ) ;
2003-05-06 04:03:58 +00:00
add_header ( & resp , " C " , sub - > callid ) ;
2002-12-29 19:13:07 +00:00
add_header ( & resp , " L " , local ) ;
2003-05-06 04:03:58 +00:00
add_header ( & resp , " M " , mgcp_cxmodes [ sub - > cxmode ] ) ;
add_header ( & resp , " X " , sub - > txident ) ;
/*add_header(&resp, "S", "");*/
add_sdp ( & resp , sub , rtp ) ;
return send_request ( sub , & resp , oseq ) ;
2002-12-29 19:13:07 +00:00
}
2003-05-06 04:03:58 +00:00
static int transmit_notify_request ( struct mgcp_subchannel * sub , char * tone )
2002-12-29 19:13:07 +00:00
{
struct mgcp_request resp ;
2003-05-06 04:03:58 +00:00
struct mgcp_endpoint * p = sub - > parent ;
if ( mgcpdebug ) {
ast_verbose ( VERBOSE_PREFIX_3 " MGCP Asked to indicate tone: %s on %s@%s-%d in cxmode: %s \n " ,
tone , p - > name , p - > parent - > name , sub - > id , mgcp_cxmodes [ sub - > cxmode ] ) ;
}
2002-12-29 19:13:07 +00:00
strncpy ( p - > curtone , tone , sizeof ( p - > curtone ) - 1 ) ;
reqprep ( & resp , p , " RQNT " ) ;
2003-05-06 04:03:58 +00:00
add_header ( & resp , " X " , sub - > txident ) ;
switch ( p - > hookstate ) {
case MGCP_ONHOOK :
add_header ( & resp , " R " , " hd(N) " ) ;
break ;
case MGCP_OFFHOOK :
add_header ( & resp , " R " , " hu(N), hf(N), D/[0-9#*](N) " ) ;
break ;
}
if ( strlen ( tone ) ) {
add_header ( & resp , " S " , tone ) ;
}
return send_request ( sub , & resp , oseq ) ;
2002-12-29 19:13:07 +00:00
}
2003-05-06 04:03:58 +00:00
static int transmit_notify_request_with_callerid ( struct mgcp_subchannel * sub , char * tone , char * callerid )
2002-12-29 19:13:07 +00:00
{
struct mgcp_request resp ;
char cid [ 256 ] ;
char tone2 [ 256 ] ;
char * l , * n ;
time_t t ;
2003-03-31 03:19:34 +00:00
struct tm tm ;
2003-05-06 04:03:58 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2002-12-29 19:13:07 +00:00
time ( & t ) ;
2003-03-31 03:19:34 +00:00
localtime_r ( & t , & tm ) ;
2002-12-29 19:13:07 +00:00
if ( callerid )
strncpy ( cid , callerid , sizeof ( cid ) - 1 ) ;
else
strcpy ( cid , " " ) ;
ast_callerid_parse ( cid , & n , & l ) ;
if ( l ) {
ast_shrink_phone_number ( l ) ;
if ( ! ast_isphonenumber ( l ) ) {
n = l ;
l = " " ;
}
}
if ( ! n )
n = " O " ;
if ( ! l )
l = " " ;
2003-05-06 04:03:58 +00:00
/* Keep track of last callerid for blacklist and callreturn */
strncpy ( p - > lastcallerid , l , sizeof ( p - > lastcallerid ) - 1 ) ;
2003-03-24 21:46:06 +00:00
snprintf ( tone2 , sizeof ( tone2 ) , " %s,L/ci(%02d/%02d/%02d/%02d,%s,%s) " , tone ,
2003-03-31 03:19:34 +00:00
tm . tm_mon + 1 , tm . tm_mday , tm . tm_hour , tm . tm_min , l , n ) ;
2002-12-29 19:13:07 +00:00
strncpy ( p - > curtone , tone , sizeof ( p - > curtone ) - 1 ) ;
reqprep ( & resp , p , " RQNT " ) ;
2003-05-06 04:03:58 +00:00
add_header ( & resp , " X " , sub - > txident ) ;
switch ( p - > hookstate ) {
case MGCP_ONHOOK :
add_header ( & resp , " R " , " L/hd(N) " ) ;
break ;
case MGCP_OFFHOOK :
add_header ( & resp , " R " , " L/hu(N),L/hf(N),D/[0-9#*](N) " ) ;
break ;
}
if ( strlen ( tone2 ) ) {
add_header ( & resp , " S " , tone2 ) ;
}
if ( mgcpdebug ) {
ast_verbose ( VERBOSE_PREFIX_3 " MGCP Asked to indicate tone: %s on %s@%s-%d in cxmode: %s \n " ,
tone2 , p - > name , p - > parent - > name , sub - > id , mgcp_cxmodes [ sub - > cxmode ] ) ;
}
return send_request ( sub , & resp , oseq ) ;
2002-12-29 19:13:07 +00:00
}
2003-04-11 19:17:05 +00:00
2003-05-06 04:03:58 +00:00
static int transmit_modify_request ( struct mgcp_subchannel * sub )
{
struct mgcp_request resp ;
struct mgcp_endpoint * p = sub - > parent ;
if ( ! strlen ( sub - > cxident ) ) {
/* We don't have a CXident yet, store the destination and
wait a bit */
return 0 ;
}
if ( mgcpdebug ) {
ast_verbose ( VERBOSE_PREFIX_3 " Modified %s@%s-%d with new mode: %s on callid: %s \n " ,
p - > name , p - > parent - > name , sub - > id , mgcp_cxmodes [ sub - > cxmode ] , sub - > callid ) ;
}
reqprep ( & resp , p , " MDCX " ) ;
add_header ( & resp , " C " , sub - > callid ) ;
add_header ( & resp , " M " , mgcp_cxmodes [ sub - > cxmode ] ) ;
add_header ( & resp , " X " , sub - > txident ) ;
add_header ( & resp , " I " , sub - > cxident ) ;
switch ( sub - > parent - > hookstate ) {
case MGCP_ONHOOK :
add_header ( & resp , " R " , " L/hd(N) " ) ;
break ;
case MGCP_OFFHOOK :
add_header ( & resp , " R " , " L/hu(N),L/hf(N),D/[0-9#*](N) " ) ;
break ;
}
return send_request ( sub , & resp , oseq ) ;
}
2003-04-11 19:17:05 +00:00
static int transmit_audit_endpoint ( struct mgcp_endpoint * p )
{
struct mgcp_request resp ;
reqprep ( & resp , p , " AUEP " ) ;
2003-05-06 04:03:58 +00:00
add_header ( & resp , " F " , " A,R,D,S,X,N,I,T,O,ES,VS,E,MD,M " ) ;
return send_request ( p - > sub , & resp , oseq ) ;
2003-04-11 19:17:05 +00:00
}
2003-05-06 04:03:58 +00:00
static int transmit_connection_del ( struct mgcp_subchannel * sub )
2002-12-29 19:13:07 +00:00
{
2003-05-06 04:03:58 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2002-12-29 19:13:07 +00:00
struct mgcp_request resp ;
2003-05-06 04:03:58 +00:00
if ( mgcpdebug ) {
ast_verbose ( VERBOSE_PREFIX_3 " Delete connection %s %s@%s-%d with new mode: %s on callid: %s \n " ,
sub - > cxident , p - > name , p - > parent - > name , sub - > id , mgcp_cxmodes [ sub - > cxmode ] , sub - > callid ) ;
}
2002-12-29 19:13:07 +00:00
reqprep ( & resp , p , " DLCX " ) ;
2003-05-06 04:03:58 +00:00
add_header ( & resp , " C " , sub - > callid ) ;
add_header ( & resp , " X " , sub - > txident ) ;
add_header ( & resp , " I " , sub - > cxident ) ;
return send_request ( sub , & resp , oseq ) ;
2002-12-29 19:13:07 +00:00
}
2003-05-06 04:03:58 +00:00
static void handle_response ( struct mgcp_subchannel * sub , int result , int ident )
2002-12-29 19:13:07 +00:00
{
2003-03-15 06:00:16 +00:00
struct mgcp_message * cur ;
2003-05-06 04:03:58 +00:00
struct mgcp_endpoint * p = sub - > parent ;
time_t t ;
time ( & t ) ;
#if 0
ast_verbose ( VERBOSE_PREFIX_3 " Got response back on sub%d for transaction %d our last send was %d) \n " ,
sub - > id , ident , sub - > msgs ? sub - > msgs - > seqno : - 1 ) ;
ast_verbose ( VERBOSE_PREFIX_3 " Here's out outher chan sub%d for transaction %d our last send was %d) \n " ,
sub - > next - > id , ident , sub - > next - > msgs ? sub - > next - > msgs - > seqno : - 1 ) ;
# endif
if ( sub - > msgs & & ( sub - > msgs - > seqno = = ident ) ) {
2003-03-15 06:00:16 +00:00
ast_log ( LOG_DEBUG , " Got response back on tansaction %d \n " , ident ) ;
2003-05-06 04:03:58 +00:00
cur = sub - > msgs ;
sub - > msgs = sub - > msgs - > next ;
ast_log ( LOG_DEBUG , " Removing message from %s@%s-%d tansaction %d \n " , sub - > parent - > name , sub - > parent - > parent - > name , sub - > id , ident ) ;
2003-03-15 06:00:16 +00:00
free ( cur ) ;
2003-05-06 04:03:58 +00:00
if ( sub - > msgs ) {
2003-03-15 06:00:16 +00:00
/* Send next pending message if appropriate */
2003-05-06 04:03:58 +00:00
sub - > messagepending = 1 ;
sub - > lastout = sub - > msgs - > seqno ;
sub - > lastouttime = t ;
__mgcp_xmit ( sub , sub - > msgs - > buf , sub - > msgs - > len ) ;
2003-03-15 06:00:16 +00:00
/* XXX Should schedule retransmission XXX */
2003-05-06 04:03:58 +00:00
} else {
sub - > messagepending = 0 ;
}
2003-03-15 06:00:16 +00:00
} else {
2003-05-06 04:03:58 +00:00
ast_log ( LOG_NOTICE , " Got response back on %s@%s-%d for transaction %d we aren't sending? (current = %d) \n " ,
sub - > parent - > name , sub - > parent - > parent - > name , sub - > id , ident , sub - > msgs ? sub - > msgs - > seqno : - 1 ) ;
2003-03-15 06:00:16 +00:00
}
2002-12-29 19:13:07 +00:00
if ( ( result > = 400 ) & & ( result < = 499 ) ) {
2003-05-06 04:03:58 +00:00
switch ( result ) {
case 401 :
p - > hookstate = MGCP_OFFHOOK ;
break ;
case 402 :
p - > hookstate = MGCP_ONHOOK ;
break ;
}
ast_log ( LOG_NOTICE , " Terminating on result %d from %s@%s-%d \n " , result , p - > name , p - > parent - > name , sub - > id ) ;
if ( sub - > owner )
ast_softhangup ( sub - > owner , AST_SOFTHANGUP_DEV ) ;
2002-12-29 19:13:07 +00:00
}
}
2003-05-06 04:03:58 +00:00
static void start_rtp ( struct mgcp_subchannel * sub )
2002-12-29 19:13:07 +00:00
{
2003-05-06 04:03:58 +00:00
ast_pthread_mutex_lock ( & sub - > lock ) ;
2002-12-29 19:13:07 +00:00
/* Allocate the RTP now */
2003-06-28 16:40:02 +00:00
sub - > rtp = ast_rtp_new ( sched , io , 1 , 0 ) ;
2003-05-06 04:03:58 +00:00
if ( sub - > rtp & & sub - > owner )
sub - > owner - > fds [ 0 ] = ast_rtp_fd ( sub - > rtp ) ;
if ( sub - > rtp )
ast_rtp_setnat ( sub - > rtp , sub - > nat ) ;
2003-02-12 13:59:15 +00:00
#if 0
2002-12-29 19:13:07 +00:00
ast_rtp_set_callback ( p - > rtp , rtpready ) ;
ast_rtp_set_data ( p - > rtp , p ) ;
2003-02-12 13:59:15 +00:00
# endif
2002-12-29 19:13:07 +00:00
/* Make a call*ID */
2003-05-06 04:03:58 +00:00
snprintf ( sub - > callid , sizeof ( sub - > callid ) , " %08x%s " , rand ( ) , sub - > txident ) ;
2002-12-29 19:13:07 +00:00
/* Transmit the connection create */
2003-05-06 04:03:58 +00:00
transmit_connect_with_sdp ( sub , NULL ) ;
ast_pthread_mutex_unlock ( & sub - > lock ) ;
2002-12-29 19:13:07 +00:00
}
static void * mgcp_ss ( void * data )
{
struct ast_channel * chan = data ;
2003-05-06 04:03:58 +00:00
struct mgcp_subchannel * sub = chan - > pvt - > pvt ;
struct mgcp_endpoint * p = sub - > parent ;
2002-12-29 19:13:07 +00:00
char exten [ AST_MAX_EXTENSION ] = " " ;
2003-05-06 04:03:58 +00:00
int len = 0 ;
int timeout = firstdigittimeout ;
2002-12-29 19:13:07 +00:00
int res ;
2003-05-06 04:03:58 +00:00
int getforward = 0 ;
while ( len < AST_MAX_EXTENSION - 1 ) {
res = ast_waitfordigit ( chan , timeout ) ;
timeout = 0 ;
if ( res < 0 ) {
ast_log ( LOG_DEBUG , " waitfordigit returned < 0... \n " ) ;
/*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
ast_indicate ( chan , - 1 ) ;
ast_hangup ( chan ) ;
return NULL ;
} else if ( res ) {
exten [ len + + ] = res ;
exten [ len ] = ' \0 ' ;
}
if ( ! ast_ignore_pattern ( chan - > context , exten ) ) {
/*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
ast_indicate ( chan , - 1 ) ;
} else {
/* XXX Redundant? We should already be playing dialtone */
/*tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALTONE);*/
transmit_notify_request ( sub , " dl " ) ;
}
if ( ast_exists_extension ( chan , chan - > context , exten , 1 , p - > callerid ) ) {
if ( ! res | | ! ast_matchmore_extension ( chan , chan - > context , exten , 1 , p - > callerid ) ) {
if ( getforward ) {
/* Record this as the forwarding extension */
strncpy ( p - > call_forward , exten , sizeof ( p - > call_forward ) ) ;
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " Setting call forward to '%s' on channel %s \n " ,
p - > call_forward , chan - > name ) ;
}
/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
transmit_notify_request ( sub , " sl " ) ;
if ( res )
break ;
usleep ( 500000 ) ;
/*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
ast_indicate ( chan , - 1 ) ;
sleep ( 1 ) ;
memset ( exten , 0 , sizeof ( exten ) ) ;
/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALTONE);*/
transmit_notify_request ( sub , " dl " ) ;
len = 0 ;
getforward = 0 ;
} else {
/*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
ast_indicate ( chan , - 1 ) ;
strncpy ( chan - > exten , exten , sizeof ( chan - > exten ) - 1 ) ;
if ( strlen ( p - > callerid ) ) {
if ( ! p - > hidecallerid )
chan - > callerid = strdup ( p - > callerid ) ;
chan - > ani = strdup ( p - > callerid ) ;
}
ast_setstate ( chan , AST_STATE_RING ) ;
/*zt_enable_ec(p);*/
res = ast_pbx_run ( chan ) ;
if ( res ) {
ast_log ( LOG_WARNING , " PBX exited non-zero \n " ) ;
/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);*/
/*transmit_notify_request(p, "nbz", 1);*/
transmit_notify_request ( sub , " cg " ) ;
}
return NULL ;
}
} else {
/* It's a match, but they just typed a digit, and there is an ambiguous match,
so just set the timeout to matchdigittimeout and wait some more */
timeout = matchdigittimeout ;
}
} else if ( res = = 0 ) {
ast_log ( LOG_DEBUG , " not enough digits (and no ambiguous match)... \n " ) ;
/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);*/
transmit_notify_request ( sub , " cg " ) ;
/*zt_wait_event(p->subs[index].zfd);*/
ast_hangup ( chan ) ;
return NULL ;
} else if ( p - > callwaiting & & ! strcmp ( exten , " *70 " ) ) {
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " Disabling call waiting on %s \n " , chan - > name ) ;
}
/* Disable call waiting if enabled */
p - > callwaiting = 0 ;
/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
transmit_notify_request ( sub , " sl " ) ;
len = 0 ;
memset ( exten , 0 , sizeof ( exten ) ) ;
timeout = firstdigittimeout ;
} else if ( ! strcmp ( exten , ast_pickup_ext ( ) ) ) {
/* Scan all channels and see if any there
* ringing channqels with that have call groups
* that equal this channels pickup group
*/
if ( ast_pickup_call ( chan ) ) {
ast_log ( LOG_WARNING , " No call pickup possible... \n " ) ;
/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);*/
transmit_notify_request ( sub , " cg " ) ;
}
ast_hangup ( chan ) ;
return NULL ;
} else if ( ! p - > hidecallerid & & ! strcmp ( exten , " *67 " ) ) {
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " Disabling Caller*ID on %s \n " , chan - > name ) ;
}
/* Disable Caller*ID if enabled */
p - > hidecallerid = 1 ;
if ( chan - > callerid )
free ( chan - > callerid ) ;
chan - > callerid = NULL ;
/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
transmit_notify_request ( sub , " sl " ) ;
len = 0 ;
memset ( exten , 0 , sizeof ( exten ) ) ;
timeout = firstdigittimeout ;
} else if ( p - > callreturn & & ! strcmp ( exten , " *69 " ) ) {
res = 0 ;
if ( strlen ( p - > lastcallerid ) ) {
res = ast_say_digit_str ( chan , p - > lastcallerid , " " , chan - > language ) ;
}
if ( ! res )
/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
transmit_notify_request ( sub , " sl " ) ;
break ;
} else if ( ! strcmp ( exten , " *78 " ) ) {
/* Do not disturb */
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " Enabled DND on channel %s \n " , chan - > name ) ;
}
/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
transmit_notify_request ( sub , " sl " ) ;
p - > dnd = 1 ;
getforward = 0 ;
memset ( exten , 0 , sizeof ( exten ) ) ;
len = 0 ;
} else if ( ! strcmp ( exten , " *79 " ) ) {
/* Do not disturb */
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " Disabled DND on channel %s \n " , chan - > name ) ;
}
/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
transmit_notify_request ( sub , " sl " ) ;
p - > dnd = 0 ;
getforward = 0 ;
memset ( exten , 0 , sizeof ( exten ) ) ;
len = 0 ;
} else if ( p - > cancallforward & & ! strcmp ( exten , " *72 " ) ) {
/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
transmit_notify_request ( sub , " sl " ) ;
getforward = 1 ;
memset ( exten , 0 , sizeof ( exten ) ) ;
len = 0 ;
} else if ( p - > cancallforward & & ! strcmp ( exten , " *73 " ) ) {
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " Cancelling call forwarding on channel %s \n " , chan - > name ) ;
}
/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
transmit_notify_request ( sub , " sl " ) ;
memset ( p - > call_forward , 0 , sizeof ( p - > call_forward ) ) ;
getforward = 0 ;
memset ( exten , 0 , sizeof ( exten ) ) ;
len = 0 ;
} else if ( ! strcmp ( exten , ast_parking_ext ( ) ) & &
sub - > next - > owner & &
sub - > next - > owner - > bridge ) {
/* This is a three way call, the main call being a real channel,
and we ' re parking the first call . */
ast_masq_park_call ( sub - > next - > owner - > bridge , chan , 0 , NULL ) ;
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " Parking call to '%s' \n " , chan - > name ) ;
}
break ;
} else if ( strlen ( p - > lastcallerid ) & & ! strcmp ( exten , " *80 " ) ) {
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " Blacklisting number %s \n " , p - > lastcallerid ) ;
}
res = ast_db_put ( " blacklist " , p - > lastcallerid , " 1 " ) ;
if ( ! res ) {
/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
transmit_notify_request ( sub , " sl " ) ;
memset ( exten , 0 , sizeof ( exten ) ) ;
len = 0 ;
}
} else if ( p - > hidecallerid & & ! strcmp ( exten , " *82 " ) ) {
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " Enabling Caller*ID on %s \n " , chan - > name ) ;
}
/* Enable Caller*ID if enabled */
p - > hidecallerid = 0 ;
if ( chan - > callerid )
free ( chan - > callerid ) ;
if ( strlen ( p - > callerid ) )
chan - > callerid = strdup ( p - > callerid ) ;
/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
transmit_notify_request ( sub , " sl " ) ;
len = 0 ;
memset ( exten , 0 , sizeof ( exten ) ) ;
timeout = firstdigittimeout ;
} else if ( ! ast_canmatch_extension ( chan , chan - > context , exten , 1 , chan - > callerid ) & &
( ( exten [ 0 ] ! = ' * ' ) | | ( strlen ( exten ) > 2 ) ) ) {
if ( option_debug )
ast_log ( LOG_DEBUG , " Can't match %s from '%s' in context %s \n " , exten , chan - > callerid ? chan - > callerid : " <Unknown Caller> " , chan - > context ) ;
break ;
}
if ( ! timeout )
timeout = gendigittimeout ;
if ( len & & ! ast_ignore_pattern ( chan - > context , exten ) )
/*tone_zone_play_tone(p->subs[index].zfd, -1);*/
ast_indicate ( chan , - 1 ) ;
}
#if 0
2002-12-29 19:13:07 +00:00
for ( ; ; ) {
res = ast_waitfordigit ( chan , to ) ;
if ( ! res ) {
ast_log ( LOG_DEBUG , " Timeout... \n " ) ;
break ;
}
if ( res < 0 ) {
ast_log ( LOG_DEBUG , " Got hangup... \n " ) ;
2003-05-06 04:03:58 +00:00
ast_hangup ( chan ) ;
2002-12-29 19:13:07 +00:00
break ;
}
exten [ pos + + ] = res ;
if ( ! ast_ignore_pattern ( chan - > context , exten ) )
ast_indicate ( chan , - 1 ) ;
if ( ast_matchmore_extension ( chan , chan - > context , exten , 1 , chan - > callerid ) ) {
if ( ast_exists_extension ( chan , chan - > context , exten , 1 , chan - > callerid ) )
to = 3000 ;
else
to = 8000 ;
} else
break ;
}
if ( ast_exists_extension ( chan , chan - > context , exten , 1 , chan - > callerid ) ) {
strncpy ( chan - > exten , exten , sizeof ( chan - > exten ) - 1 ) ;
2003-05-06 04:03:58 +00:00
if ( ! p - > rtp ) {
start_rtp ( p ) ;
}
2002-12-29 19:13:07 +00:00
ast_setstate ( chan , AST_STATE_RING ) ;
chan - > rings = 1 ;
if ( ast_pbx_run ( chan ) ) {
ast_log ( LOG_WARNING , " Unable to launch PBX on %s \n " , chan - > name ) ;
} else
return NULL ;
}
2003-05-06 04:03:58 +00:00
# endif
2002-12-29 19:13:07 +00:00
ast_hangup ( chan ) ;
return NULL ;
}
2003-05-06 04:03:58 +00:00
static int attempt_transfer ( struct mgcp_endpoint * p )
2002-12-29 19:13:07 +00:00
{
2003-05-06 04:03:58 +00:00
/* *************************
* I hope this works .
* Copied out of chan_zap
* Cross your fingers
* * * * * * * * * * * * * * * * * * * * * * * * * */
/* In order to transfer, we need at least one of the channels to
actually be in a call bridge . We can ' t conference two applications
together ( but then , why would we want to ? ) */
if ( p - > sub - > owner - > bridge ) {
/* The three-way person we're about to transfer to could still be in MOH, so
stop if now if appropriate */
if ( p - > sub - > next - > owner - > bridge )
ast_moh_stop ( p - > sub - > next - > owner - > bridge ) ;
if ( p - > sub - > owner - > _state = = AST_STATE_RINGING ) {
ast_indicate ( p - > sub - > next - > owner - > bridge , AST_CONTROL_RINGING ) ;
}
if ( ast_channel_masquerade ( p - > sub - > next - > owner , p - > sub - > owner - > bridge ) ) {
ast_log ( LOG_WARNING , " Unable to masquerade %s as %s \n " ,
p - > sub - > owner - > bridge - > name , p - > sub - > next - > owner - > name ) ;
return - 1 ;
}
/* Orphan the channel */
unalloc_sub ( p - > sub - > next ) ;
} else if ( p - > sub - > next - > owner - > bridge ) {
if ( p - > sub - > owner - > _state = = AST_STATE_RINGING ) {
ast_indicate ( p - > sub - > next - > owner - > bridge , AST_CONTROL_RINGING ) ;
}
ast_moh_stop ( p - > sub - > next - > owner - > bridge ) ;
if ( ast_channel_masquerade ( p - > sub - > owner , p - > sub - > next - > owner - > bridge ) ) {
ast_log ( LOG_WARNING , " Unable to masquerade %s as %s \n " ,
p - > sub - > next - > owner - > bridge - > name , p - > sub - > owner - > name ) ;
return - 1 ;
}
/*swap_subs(p, SUB_THREEWAY, SUB_REAL);*/
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " Swapping %d for %d on %s@%s \n " , p - > sub - > id , p - > sub - > next - > id , p - > name , p - > parent - > name ) ;
}
p - > sub = p - > sub - > next ;
unalloc_sub ( p - > sub - > next ) ;
/* Tell the caller not to hangup */
return 1 ;
} else {
ast_log ( LOG_DEBUG , " Neither %s nor %s are in a bridge, nothing to transfer \n " ,
p - > sub - > owner - > name , p - > sub - > next - > owner - > name ) ;
p - > sub - > next - > owner - > _softhangup | = AST_SOFTHANGUP_DEV ;
if ( p - > sub - > next - > owner ) {
p - > sub - > next - > alreadygone = 1 ;
ast_queue_hangup ( p - > sub - > next - > owner , 1 ) ;
}
}
return 0 ;
}
static void handle_hd_hf ( struct mgcp_subchannel * sub , char * ev )
{
struct mgcp_endpoint * p = sub - > parent ;
struct ast_channel * c ;
2002-12-29 19:13:07 +00:00
pthread_t t ;
2003-05-06 04:03:58 +00:00
/* Off hook / answer */
if ( sub - > outgoing ) {
/* Answered */
if ( sub - > owner ) {
if ( sub - > owner - > bridge ) {
ast_moh_stop ( sub - > owner - > bridge ) ;
}
sub - > cxmode = MGCP_CX_SENDRECV ;
if ( ! sub - > rtp ) {
start_rtp ( sub ) ;
} else {
transmit_modify_request ( sub ) ;
}
/*transmit_notify_request(sub, "aw");*/
transmit_notify_request ( sub , " " ) ;
ast_queue_control ( sub - > owner , AST_CONTROL_ANSWER , 1 ) ;
}
} else {
/* Start switch */
/*sub->cxmode = MGCP_CX_SENDRECV;*/
if ( ! sub - > owner ) {
if ( ! sub - > rtp ) {
start_rtp ( sub ) ;
} else {
transmit_modify_request ( sub ) ;
}
if ( p - > immediate ) {
/* The channel is immediately up. Start right away */
transmit_notify_request ( sub , " rt " ) ;
c = mgcp_new ( sub , AST_STATE_RING ) ;
if ( ! c ) {
ast_log ( LOG_WARNING , " Unable to start PBX on channel %s@%s \n " , p - > name , p - > parent - > name ) ;
transmit_notify_request ( sub , " cg " ) ;
ast_hangup ( c ) ;
}
} else {
if ( has_voicemail ( p ) ) {
transmit_notify_request ( sub , " sl " ) ;
} else {
transmit_notify_request ( sub , " dl " ) ;
}
c = mgcp_new ( sub , AST_STATE_DOWN ) ;
if ( c ) {
if ( pthread_create ( & t , NULL , mgcp_ss , c ) ) {
ast_log ( LOG_WARNING , " Unable to create switch thread: %s \n " , strerror ( errno ) ) ;
ast_hangup ( c ) ;
}
} else {
ast_log ( LOG_WARNING , " Unable to create channel for %s@%s \n " , p - > name , p - > parent - > name ) ;
}
}
} else {
if ( p - > hookstate = = MGCP_OFFHOOK ) {
ast_log ( LOG_WARNING , " Off hook, but alreaedy have owner on %s@%s \n " , p - > name , p - > parent - > name ) ;
} else {
ast_log ( LOG_WARNING , " On hook, but alreaedy have owner on %s@%s \n " , p - > name , p - > parent - > name ) ;
ast_log ( LOG_WARNING , " If we're onhook why are we here trying to handle a hd or hf? " ) ;
}
if ( sub - > owner - > bridge ) {
ast_moh_stop ( sub - > owner - > bridge ) ;
}
sub - > cxmode = MGCP_CX_SENDRECV ;
if ( ! sub - > rtp ) {
start_rtp ( sub ) ;
} else {
transmit_modify_request ( sub ) ;
}
/*transmit_notify_request(sub, "aw");*/
transmit_notify_request ( sub , " " ) ;
/*ast_queue_control(sub->owner, AST_CONTROL_ANSWER, 1);*/
}
}
}
static int handle_request ( struct mgcp_subchannel * sub , struct mgcp_request * req , struct sockaddr_in * sin )
{
char * ev , * s ;
2002-12-29 19:13:07 +00:00
struct ast_frame f = { 0 , } ;
2003-05-06 04:03:58 +00:00
struct mgcp_endpoint * p = sub - > parent ;
int res ;
if ( mgcpdebug ) {
2003-03-09 06:00:18 +00:00
ast_verbose ( " Handling request '%s' on %s@%s \n " , req - > verb , p - > name , p - > parent - > name ) ;
2003-05-06 04:03:58 +00:00
}
2002-12-29 19:13:07 +00:00
/* Clear out potential response */
if ( ! strcasecmp ( req - > verb , " RSIP " ) ) {
2003-06-29 14:36:21 +00:00
/* Test if this RSIP request is just a keepalive */
if ( ! strcasecmp ( get_header ( req , " RM " ) , " X-keepalive " ) ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Received keepalive request from %s@%s \n " , p - > name , p - > parent - > name ) ;
transmit_response ( sub , " 200 " , req , " OK " ) ;
} else {
dump_queue ( p ) ;
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " Resetting interface %s@%s \n " , p - > name , p - > parent - > name ) ;
}
if ( sub - > owner ) {
ast_softhangup ( sub - > owner , AST_SOFTHANGUP_DEV ) ;
}
transmit_response ( sub , " 200 " , req , " OK " ) ;
transmit_notify_request ( sub , " " ) ;
}
2002-12-29 19:13:07 +00:00
} else if ( ! strcasecmp ( req - > verb , " NTFY " ) ) {
/* Acknowledge and be sure we keep looking for the same things */
2003-05-06 04:03:58 +00:00
transmit_response ( sub , " 200 " , req , " OK " ) ;
2002-12-29 19:13:07 +00:00
/* Notified of an event */
ev = get_header ( req , " O " ) ;
s = strchr ( ev , ' / ' ) ;
if ( s ) ev = s + 1 ;
2003-05-06 04:03:58 +00:00
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " Endpoint '%s@%s-%d' observed '%s' \n " , p - > name , p - > parent - > name , sub - > id , ev ) ;
}
2002-12-29 19:13:07 +00:00
/* Keep looking for events unless this was a hangup */
2003-05-06 04:03:58 +00:00
if ( strcasecmp ( ev , " hu " ) & & strcasecmp ( ev , " hd " ) ) {
transmit_notify_request ( sub , p - > curtone ) ;
}
2002-12-29 19:13:07 +00:00
if ( ! strcasecmp ( ev , " hd " ) ) {
2003-05-06 04:03:58 +00:00
p - > hookstate = MGCP_OFFHOOK ;
sub - > cxmode = MGCP_CX_SENDRECV ;
handle_hd_hf ( sub , ev ) ;
} else if ( ! strcasecmp ( ev , " hf " ) ) {
/* We can assume we are offhook if we received a hookflash */
/* First let's just do call wait and ignore threeway */
/* We're currently in charge */
if ( p - > hookstate ! = MGCP_OFFHOOK ) {
/* Cisco c7940 sends hf even if the phone is onhook */
/* Thanks to point on IRC for pointing this out */
return - 1 ;
}
if ( p - > callwaiting | | p - > transfer | | p - > threewaycalling ) {
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " Swapping %d for %d on %s@%s \n " , p - > sub - > id , p - > sub - > next - > id , p - > name , p - > parent - > name ) ;
}
p - > sub = p - > sub - > next ;
/* transfer control to our next subchannel */
if ( ! sub - > next - > owner ) {
/* plave the first call on hold and start up a new call */
sub - > cxmode = MGCP_CX_MUTE ;
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " MGCP Muting %d on %s@%s \n " , sub - > id , p - > name , p - > parent - > name ) ;
}
transmit_modify_request ( sub ) ;
if ( sub - > owner & & sub - > owner - > bridge ) {
ast_moh_start ( sub - > owner - > bridge , NULL ) ;
}
sub - > next - > cxmode = MGCP_CX_RECVONLY ;
handle_hd_hf ( sub - > next , ev ) ;
} else if ( sub - > owner & & sub - > next - > owner ) {
/* We've got two active calls lets decide whether or not to conference or just flip flop */
if ( ( ! sub - > outgoing ) & & ( ! sub - > next - > outgoing ) ) {
/* We made both calls lets conferenct */
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " MGCP Conferencing %d and %d on %s@%s \n " ,
sub - > id , sub - > next - > id , p - > name , p - > parent - > name ) ;
}
sub - > cxmode = MGCP_CX_CONF ;
sub - > next - > cxmode = MGCP_CX_CONF ;
if ( sub - > next - > owner - > bridge ) {
ast_moh_stop ( sub - > next - > owner - > bridge ) ;
}
transmit_modify_request ( sub ) ;
transmit_modify_request ( sub - > next ) ;
} else {
/* Let's flipflop between calls */
/* XXX Need to check for state up ??? */
/* XXX Need a way to indicate the current call, or maybe the call that's waiting */
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " We didn't make one of the calls FLIPFLOP %d and %d on %s@%s \n " ,
sub - > id , sub - > next - > id , p - > name , p - > parent - > name ) ;
}
sub - > cxmode = MGCP_CX_MUTE ;
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " MGCP Muting %d on %s@%s \n " , sub - > id , p - > name , p - > parent - > name ) ;
}
transmit_modify_request ( sub ) ;
if ( sub - > owner - > bridge ) {
ast_moh_start ( sub - > owner - > bridge , NULL ) ;
}
if ( sub - > next - > owner - > bridge ) {
ast_moh_stop ( sub - > next - > owner - > bridge ) ;
}
handle_hd_hf ( sub - > next , ev ) ;
#if 0
if ( sub - > next - > owner & & ( sub - > next - > owner - > _state ! = AST_STATE_UP ) ) {
handle_hd_hf ( sub - > next , ev ) ;
} else {
ast_verbose ( VERBOSE_PREFIX_3 " MGCP Unmuting %d on %s@%s \n " , sub - > next - > id , p - > name , p - > parent - > name ) ;
sub - > next - > cxmode = MGCP_CX_SENDRECV ;
transmit_modify_request ( sub - > next ) ;
}
# endif
}
} else {
/* We've most likely lost one of our calls find an active call and bring it up */
if ( sub - > owner ) {
p - > sub = sub ;
} else if ( sub - > next - > owner ) {
p - > sub = sub - > next ;
} else {
/* We seem to have lost both our calls */
/* XXX - What do we do now? */
return - 1 ;
}
if ( p - > sub - > owner - > bridge ) {
ast_moh_stop ( p - > sub - > owner - > bridge ) ;
}
p - > sub - > cxmode = MGCP_CX_SENDRECV ;
transmit_modify_request ( p - > sub ) ;
}
} else {
ast_log ( LOG_WARNING , " Callwaiting, call transfer or threeway calling not enabled on endpoint %s@%s \n " ,
p - > name , p - > parent - > name ) ;
}
/* ast_moh_stop(sub->owner->bridge); */
2002-12-29 19:13:07 +00:00
} else if ( ! strcasecmp ( ev , " hu " ) ) {
2003-05-06 04:03:58 +00:00
p - > hookstate = MGCP_ONHOOK ;
sub - > cxmode = MGCP_CX_RECVONLY ;
ast_log ( LOG_DEBUG , " MGCP %s@%s Went on hook \n " , p - > name , p - > parent - > name ) ;
if ( sub - > rtp ) {
transmit_modify_request ( sub ) ;
}
if ( p - > transfer & & ( sub - > owner & & sub - > next - > owner ) & & ( ( ! sub - > outgoing ) | | ( ! sub - > next - > outgoing ) ) ) {
/* We're allowed to transfer, we have two avtive calls and */
/* we made at least one of the calls. Let's try and transfer */
if ( ( res = attempt_transfer ( p ) ) < 0 ) {
if ( p - > sub - > next - > owner ) {
sub - > next - > alreadygone = 1 ;
ast_queue_hangup ( sub - > next - > owner , 1 ) ;
}
} else if ( res ) {
ast_log ( LOG_WARNING , " Transfer attempt failed \n " ) ;
return - 1 ;
}
} else {
/* Hangup the current call */
/* If there is another active call, mgcp_hangup will ring the phone with the other call */
if ( sub - > owner ) {
sub - > alreadygone = 1 ;
ast_queue_hangup ( sub - > owner , 1 ) ;
} else {
ast_verbose ( VERBOSE_PREFIX_3 " MGCP handle_request(%s@%s-%d) ast_channel already destroyed \n " ,
p - > name , p - > parent - > name , sub - > id ) ;
}
}
if ( ( p - > hookstate = = MGCP_ONHOOK ) & & ( ! sub - > rtp ) & & ( ! sub - > next - > rtp ) ) {
if ( has_voicemail ( p ) ) {
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " MGCP handle_request(%s@%s) set vmwi(+) \n " , p - > name , p - > parent - > name ) ;
}
transmit_notify_request ( sub , " vmwi(+) " ) ;
} else {
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " MGCP handle_request(%s@%s) set vmwi(-) \n " , p - > name , p - > parent - > name ) ;
}
transmit_notify_request ( sub , " vmwi(-) " ) ;
}
}
2002-12-29 19:13:07 +00:00
} else if ( ( strlen ( ev ) = = 1 ) & &
( ( ( ev [ 0 ] > = ' 0 ' ) & & ( ev [ 0 ] < = ' 9 ' ) ) | |
( ( ev [ 0 ] > = ' A ' ) & & ( ev [ 0 ] < = ' D ' ) ) | |
( ev [ 0 ] = = ' * ' ) | | ( ev [ 0 ] = = ' # ' ) ) ) {
f . frametype = AST_FRAME_DTMF ;
f . subclass = ev [ 0 ] ;
f . src = " mgcp " ;
2003-05-06 04:03:58 +00:00
if ( sub - > owner ) {
/* XXX MUST queue this frame to all subs in threeway call if threeway call is active */
ast_queue_frame ( sub - > owner , & f , 1 ) ;
if ( sub - > next - > owner ) {
ast_queue_frame ( sub - > next - > owner , & f , 1 ) ;
}
}
if ( strstr ( p - > curtone , " wt " ) & & ( ev [ 0 ] = = ' A ' ) ) {
memset ( p - > curtone , 0 , sizeof ( p - > curtone ) ) ;
}
2002-12-29 19:13:07 +00:00
} else if ( ! strcasecmp ( ev , " T " ) ) {
/* Digit timeout -- unimportant */
} else {
ast_log ( LOG_NOTICE , " Received unknown event '%s' from %s@%s \n " , ev , p - > name , p - > parent - > name ) ;
}
} else {
ast_log ( LOG_WARNING , " Unknown verb '%s' received from %s \n " , req - > verb , inet_ntoa ( sin - > sin_addr ) ) ;
2003-05-06 04:03:58 +00:00
transmit_response ( sub , " 510 " , req , " Unknown verb " ) ;
2002-12-29 19:13:07 +00:00
}
return 0 ;
}
static int mgcpsock_read ( int * id , int fd , short events , void * ignore )
{
struct mgcp_request req ;
struct sockaddr_in sin ;
2003-05-06 04:03:58 +00:00
struct mgcp_subchannel * sub ;
2002-12-29 19:13:07 +00:00
char * c ;
int res ;
int len ;
int result ;
int ident ;
len = sizeof ( sin ) ;
memset ( & req , 0 , sizeof ( req ) ) ;
res = recvfrom ( mgcpsock , req . data , sizeof ( req . data ) - 1 , 0 , ( struct sockaddr * ) & sin , & len ) ;
if ( res < 0 ) {
if ( errno ! = ECONNREFUSED )
ast_log ( LOG_WARNING , " Recv error: %s \n " , strerror ( errno ) ) ;
return 1 ;
}
req . data [ res ] = ' \0 ' ;
req . len = res ;
2003-05-06 04:03:58 +00:00
if ( mgcpdebug ) {
2003-03-09 06:00:18 +00:00
ast_verbose ( " MGCP read: \n %s \n from %s:%d " , req . data , inet_ntoa ( sin . sin_addr ) , ntohs ( sin . sin_port ) ) ;
2003-05-06 04:03:58 +00:00
}
2002-12-29 19:13:07 +00:00
parse ( & req ) ;
if ( req . headers < 1 ) {
/* Must have at least one header */
return 1 ;
}
if ( ! req . identifier | | ! strlen ( req . identifier ) ) {
ast_log ( LOG_NOTICE , " Message from %s missing identifier \n " , inet_ntoa ( sin . sin_addr ) ) ;
return 1 ;
}
if ( sscanf ( req . verb , " %d " , & result ) & &
sscanf ( req . identifier , " %d " , & ident ) ) {
/* Try to find who this message is for, if it's important */
2003-05-06 04:03:58 +00:00
sub = find_subchannel ( NULL , ident , & sin ) ;
if ( sub ) {
#if 0
if ( ( c = get_header ( & req , " X " ) ) ) {
if ( strlen ( c ) ) {
if ( ( strcasecmp ( sub - > txident , c ) ) & & ( ! strcasecmp ( sub - > next - > txident , c ) ) ) {
ast_log ( LOG_WARNING , " Response on sub%d message %d appears to have come from out other subchannel " , sub - > id , ident ) ;
}
}
}
# endif
handle_response ( sub , result , ident ) ;
2003-02-16 06:00:12 +00:00
if ( ( c = get_header ( & req , " I " ) ) ) {
if ( strlen ( c ) ) {
2003-05-06 04:03:58 +00:00
if ( strlen ( sub - > cxident ) ) {
if ( strcasecmp ( c , sub - > cxident ) ) {
ast_log ( LOG_WARNING , " Subchannel already has a cxident. sub->cxident: %s requested %s \n " , sub - > cxident , c ) ;
}
}
strncpy ( sub - > cxident , c , sizeof ( sub - > cxident ) - 1 ) ;
if ( sub - > tmpdest . sin_addr . s_addr ) {
transmit_modify_with_sdp ( sub , NULL ) ;
2003-02-16 06:00:12 +00:00
}
}
}
2003-05-06 04:03:58 +00:00
/* Try to determine the hookstate returned from an audit endpoint command */
if ( ( c = get_header ( & req , " ES " ) ) ) {
if ( strlen ( c ) ) {
if ( strstr ( c , " hu " ) ) {
sub - > parent - > hookstate = MGCP_ONHOOK ;
ast_verbose ( VERBOSE_PREFIX_3 " Setting hookstate of %s@%s to ONHOOK \n " , sub - > parent - > name , sub - > parent - > parent - > name ) ;
} else if ( strstr ( c , " hd " ) ) {
sub - > parent - > hookstate = MGCP_OFFHOOK ;
ast_verbose ( VERBOSE_PREFIX_3 " Setting hookstate of %s@%s to OFFHOOK \n " , sub - > parent - > name , sub - > parent - > parent - > name ) ;
}
}
}
2003-03-15 06:00:16 +00:00
if ( req . lines ) {
2003-05-06 04:03:58 +00:00
if ( ! sub - > rtp )
start_rtp ( sub ) ;
if ( sub - > rtp )
process_sdp ( sub , & req ) ;
2003-03-15 06:00:16 +00:00
}
2003-05-06 04:03:58 +00:00
2002-12-29 19:13:07 +00:00
}
} else {
if ( ! req . endpoint | | ! strlen ( req . endpoint ) | |
! req . version | | ! strlen ( req . version ) | |
! req . verb | | ! strlen ( req . verb ) ) {
ast_log ( LOG_NOTICE , " Message must have a verb, an idenitifier, version, and endpoint \n " ) ;
return 1 ;
}
/* Process request, with iflock held */
2003-05-06 04:03:58 +00:00
sub = find_subchannel ( req . endpoint , 0 , & sin ) ;
if ( sub ) {
/* pass the request off to the currently mastering subchannel */
handle_request ( sub , & req , & sin ) ;
2002-12-29 19:13:07 +00:00
}
}
return 1 ;
}
static void * do_monitor ( void * data )
{
int res ;
struct mgcp_pkt * p ;
2003-05-06 04:03:58 +00:00
/* struct mgcp_gateway *g; */
/* struct mgcp_endpoint *e; */
/*time_t thispass = 0, lastpass = 0;*/
2002-12-29 19:13:07 +00:00
sched = sched_context_create ( ) ;
if ( ! sched ) {
ast_log ( LOG_WARNING , " Unable to create schedule context \n " ) ;
return NULL ;
}
io = io_context_create ( ) ;
if ( ! io ) {
ast_log ( LOG_WARNING , " Unable to create I/O context \n " ) ;
return NULL ;
}
/* Add an I/O event to our UDP socket */
if ( mgcpsock > - 1 )
ast_io_add ( io , mgcpsock , mgcpsock_read , AST_IO_IN , NULL ) ;
/* This thread monitors all the frame relay interfaces which are not yet in use
( and thus do not have a separate thread ) indefinitely */
/* From here on out, we die whenever asked */
for ( ; ; ) {
/* Check for interfaces needing to be killed */
/* Don't let anybody kill us right away. Nobody should lock the interface list
and wait for the monitor list , but the other way around is okay . */
ast_pthread_mutex_lock ( & monlock ) ;
/* Lock the network interface */
ast_pthread_mutex_lock ( & netlock ) ;
p = packets ;
while ( p ) {
/* Handle any retransmissions */
p = p - > next ;
}
2003-05-06 04:03:58 +00:00
/* XXX THIS IS COMPLETELY HOSED */
/* The gateway goes into a state of panic */
/* If the vmwi indicator is sent while it is reseting interfaces */
#if 0
lastpass = thispass ;
thispass = time ( NULL ) ;
g = gateways ;
while ( g ) {
if ( thispass ! = lastpass ) {
e = g - > endpoints ;
while ( e ) {
if ( e - > type = = TYPE_LINE ) {
res = has_voicemail ( e ) ;
if ( ( e - > msgstate ! = res ) & & ( e - > hookstate = = MGCP_ONHOOK ) & & ( ! e - > rtp ) ) {
if ( res ) {
transmit_notify_request ( e , " vmwi(+) " ) ;
} else {
transmit_notify_request ( e , " vmwi(-) " ) ;
}
e - > msgstate = res ;
e - > onhooktime = thispass ;
}
}
e = e - > next ;
}
}
g = g - > next ;
}
# endif
2002-12-29 19:13:07 +00:00
/* Okay, now that we know what to do, release the network lock */
ast_pthread_mutex_unlock ( & netlock ) ;
/* And from now on, we're okay to be killed, so release the monitor lock as well */
ast_pthread_mutex_unlock ( & monlock ) ;
pthread_testcancel ( ) ;
/* Wait for sched or io */
res = ast_sched_wait ( sched ) ;
res = ast_io_wait ( io , res ) ;
ast_pthread_mutex_lock ( & monlock ) ;
if ( res > = 0 )
ast_sched_runq ( sched ) ;
ast_pthread_mutex_unlock ( & monlock ) ;
}
/* Never reached */
return NULL ;
}
static int restart_monitor ( void )
{
/* If we're supposed to be stopped -- stay stopped */
if ( monitor_thread = = - 2 )
return 0 ;
if ( ast_pthread_mutex_lock ( & monlock ) ) {
ast_log ( LOG_WARNING , " Unable to lock monitor \n " ) ;
return - 1 ;
}
if ( monitor_thread = = pthread_self ( ) ) {
ast_pthread_mutex_unlock ( & monlock ) ;
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 ) {
ast_pthread_mutex_unlock ( & monlock ) ;
ast_log ( LOG_ERROR , " Unable to start monitor thread. \n " ) ;
return - 1 ;
}
}
ast_pthread_mutex_unlock ( & monlock ) ;
return 0 ;
}
static struct ast_channel * mgcp_request ( char * type , int format , void * data )
{
int oldformat ;
2003-05-06 04:03:58 +00:00
struct mgcp_subchannel * sub ;
2002-12-29 19:13:07 +00:00
struct ast_channel * tmpc = NULL ;
char tmp [ 256 ] ;
char * dest = 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 ) ;
if ( ! strlen ( tmp ) ) {
ast_log ( LOG_NOTICE , " MGCP Channels require an endpoint \n " ) ;
return NULL ;
}
2003-05-06 04:03:58 +00:00
sub = find_subchannel ( tmp , 0 , NULL ) ;
if ( ! sub ) {
2002-12-29 19:13:07 +00:00
ast_log ( LOG_WARNING , " Unable to find MGCP endpoint '%s' \n " , tmp ) ;
return NULL ;
}
2003-03-09 06:00:18 +00:00
2003-05-06 04:03:58 +00:00
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " MGCP mgcp_request(%s) \n " , tmp ) ;
ast_verbose ( VERBOSE_PREFIX_3 " MGCP cw: %d, dnd: %d, so: %d, sno: %d \n " ,
sub - > parent - > callwaiting , sub - > parent - > dnd , sub - > owner ? 1 : 0 , sub - > next - > owner ? 1 : 0 ) ;
}
2002-12-29 19:13:07 +00:00
/* Must be busy */
2003-05-06 04:03:58 +00:00
if ( ( ( sub - > parent - > callwaiting ) & & ( ( sub - > owner ) & & ( sub - > next - > owner ) ) ) | |
( ( ! sub - > parent - > callwaiting ) & & ( sub - > owner ) ) | |
( sub - > parent - > dnd & & ( ! strlen ( sub - > parent - > call_forward ) ) ) ) {
if ( sub - > parent - > hookstate = = MGCP_ONHOOK ) {
if ( has_voicemail ( sub - > parent ) ) {
transmit_notify_request ( sub , " vmwi(+) " ) ;
} else {
transmit_notify_request ( sub , " vmwi(-) " ) ;
}
}
2002-12-29 19:13:07 +00:00
return NULL ;
2003-05-06 04:03:58 +00:00
}
tmpc = mgcp_new ( sub - > owner ? sub - > next : sub , AST_STATE_DOWN ) ;
2002-12-29 19:13:07 +00:00
if ( ! tmpc )
ast_log ( LOG_WARNING , " Unable to make channel for '%s' \n " , tmp ) ;
restart_monitor ( ) ;
return tmpc ;
}
2003-04-27 21:34:27 +00:00
static struct mgcp_gateway * build_gateway ( char * cat , struct ast_variable * v )
2002-12-29 19:13:07 +00:00
{
struct mgcp_gateway * gw ;
struct mgcp_endpoint * e ;
2003-05-06 04:03:58 +00:00
struct mgcp_subchannel * sub ;
/*char txident[80];*/
int i = 0 , y = 0 ;
2002-12-29 19:13:07 +00:00
gw = malloc ( sizeof ( struct mgcp_gateway ) ) ;
if ( gw ) {
memset ( gw , 0 , sizeof ( struct mgcp_gateway ) ) ;
2003-03-09 06:00:18 +00:00
gw - > expire = - 1 ;
2002-12-29 19:13:07 +00:00
strncpy ( gw - > name , cat , sizeof ( gw - > name ) - 1 ) ;
while ( v ) {
if ( ! strcasecmp ( v - > name , " host " ) ) {
2003-03-09 06:00:18 +00:00
if ( ! strcasecmp ( v - > value , " dynamic " ) ) {
/* They'll register with us */
gw - > dynamic = 1 ;
memset ( & gw - > addr . sin_addr , 0 , 4 ) ;
if ( gw - > addr . sin_port ) {
/* If we've already got a port, make it the default rather than absolute */
gw - > defaddr . sin_port = gw - > addr . sin_port ;
gw - > addr . sin_port = 0 ;
}
} else {
/* Non-dynamic. Make sure we become that way if we're not */
if ( gw - > expire > - 1 )
ast_sched_del ( sched , gw - > expire ) ;
gw - > expire = - 1 ;
gw - > dynamic = 0 ;
if ( ast_get_ip ( & gw - > addr , v - > value ) ) {
free ( gw ) ;
return NULL ;
}
}
} else if ( ! strcasecmp ( v - > name , " defaultip " ) ) {
if ( ast_get_ip ( & gw - > defaddr , v - > value ) ) {
2002-12-29 19:13:07 +00:00
free ( gw ) ;
return NULL ;
}
} else if ( ! strcasecmp ( v - > name , " permit " ) | |
! strcasecmp ( v - > name , " deny " ) ) {
gw - > ha = ast_append_ha ( v - > name , v - > value , gw - > ha ) ;
} else if ( ! strcasecmp ( v - > name , " port " ) ) {
gw - > addr . sin_port = htons ( atoi ( v - > value ) ) ;
} else if ( ! strcasecmp ( v - > name , " context " ) ) {
strncpy ( context , v - > value , sizeof ( context ) - 1 ) ;
2003-03-10 20:39:12 +00:00
} else if ( ! strcasecmp ( v - > name , " inbanddtmf " ) ) {
inbanddtmf = atoi ( v - > value ) ;
2003-03-07 06:00:13 +00:00
} else if ( ! strcasecmp ( v - > name , " nat " ) ) {
nat = ast_true ( v - > value ) ;
2002-12-29 19:13:07 +00:00
} else if ( ! strcasecmp ( v - > name , " callerid " ) ) {
if ( ! strcasecmp ( v - > value , " asreceived " ) )
strcpy ( callerid , " " ) ;
else
strncpy ( callerid , v - > value , sizeof ( callerid ) - 1 ) ;
} else if ( ! strcasecmp ( v - > name , " language " ) ) {
strncpy ( language , v - > value , sizeof ( language ) - 1 ) ;
2003-05-06 04:03:58 +00:00
} else if ( ! strcasecmp ( v - > name , " accountcode " ) ) {
strncpy ( accountcode , v - > value , sizeof ( accountcode ) - 1 ) ;
} else if ( ! strcasecmp ( v - > name , " amaflags " ) ) {
y = ast_cdr_amaflags2int ( v - > value ) ;
if ( y < 0 ) {
ast_log ( LOG_WARNING , " Invalid AMA flags: %s at line %d \n " , v - > value , v - > lineno ) ;
} else {
amaflags = y ;
}
} else if ( ! strcasecmp ( v - > name , " musiconhold " ) ) {
strncpy ( musicclass , v - > value , sizeof ( musicclass ) - 1 ) ;
} else if ( ! strcasecmp ( v - > name , " callgroup " ) ) {
cur_callergroup = ast_get_group ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " pickupgroup " ) ) {
cur_pickupgroup = ast_get_group ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " immediate " ) ) {
immediate = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " cancallforward " ) ) {
cancallforward = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " mailbox " ) ) {
strncpy ( mailbox , v - > value , sizeof ( mailbox ) - 1 ) ;
} else if ( ! strcasecmp ( v - > name , " adsi " ) ) {
adsi = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " callreturn " ) ) {
callreturn = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " immediate " ) ) {
immediate = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " callwaiting " ) ) {
callwaiting = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " transfer " ) ) {
transfer = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " threewaycalling " ) ) {
threewaycalling = ast_true ( v - > value ) ;
2002-12-29 19:13:07 +00:00
} else if ( ! strcasecmp ( v - > name , " trunk " ) | |
! strcasecmp ( v - > name , " line " ) ) {
e = malloc ( sizeof ( struct mgcp_endpoint ) ) ;
if ( e ) {
memset ( e , 0 , sizeof ( struct mgcp_endpoint ) ) ;
2003-05-06 04:03:58 +00:00
strncpy ( e - > name , v - > value , sizeof ( e - > name ) - 1 ) ;
2002-12-29 19:13:07 +00:00
/* XXX Should we really check for uniqueness?? XXX */
strncpy ( e - > context , context , sizeof ( e - > context ) - 1 ) ;
strncpy ( e - > callerid , callerid , sizeof ( e - > callerid ) - 1 ) ;
strncpy ( e - > language , language , sizeof ( e - > language ) - 1 ) ;
2003-05-06 04:03:58 +00:00
strncpy ( e - > musicclass , musicclass , sizeof ( e - > musicclass ) - 1 ) ;
strncpy ( e - > mailbox , mailbox , sizeof ( e - > mailbox ) - 1 ) ;
if ( strlen ( mailbox ) ) {
ast_verbose ( VERBOSE_PREFIX_3 " Setting mailbox '%s' on %s@%s \n " , mailbox , gw - > name , e - > name ) ;
}
e - > msgstate = - 1 ;
2002-12-29 19:13:07 +00:00
e - > capability = capability ;
e - > parent = gw ;
2003-03-10 20:39:12 +00:00
e - > dtmfinband = inbanddtmf ;
2003-05-06 04:03:58 +00:00
e - > adsi = adsi ;
2002-12-29 19:13:07 +00:00
if ( ! strcasecmp ( v - > name , " trunk " ) )
e - > type = TYPE_TRUNK ;
else
e - > type = TYPE_LINE ;
2003-05-06 04:03:58 +00:00
e - > immediate = immediate ;
e - > callgroup = cur_callergroup ;
e - > pickupgroup = cur_pickupgroup ;
e - > callreturn = callreturn ;
e - > cancallforward = cancallforward ;
e - > callwaiting = callwaiting ;
e - > transfer = transfer ;
e - > threewaycalling = threewaycalling ;
e - > onhooktime = time ( NULL ) ;
/* ASSUME we're onhook */
e - > hookstate = MGCP_ONHOOK ;
/*snprintf(txident, sizeof(txident), "%08x", rand());*/
for ( i = 0 ; i < MAX_SUBS ; i + + ) {
sub = malloc ( sizeof ( struct mgcp_subchannel ) ) ;
if ( sub ) {
ast_verbose ( VERBOSE_PREFIX_3 " Allocating subchannel '%d' on %s@%s \n " , i , e - > name , gw - > name ) ;
memset ( sub , 0 , sizeof ( struct mgcp_subchannel ) ) ;
sub - > parent = e ;
sub - > id = i ;
snprintf ( sub - > txident , sizeof ( sub - > txident ) , " %08x " , rand ( ) ) ;
/*strcpy(sub->txident, txident);*/
sub - > cxmode = MGCP_CX_INACTIVE ;
sub - > nat = nat ;
sub - > next = e - > sub ;
e - > sub = sub ;
} else {
/* XXX Should find a way to clean up our memory */
ast_log ( LOG_WARNING , " Out of memory allocating subchannel " ) ;
return NULL ;
}
}
/* Make out subs a circular linked list so we can always sping through the whole bunch */
sub = e - > sub ;
/* find the end of the list */
while ( sub - > next ) {
sub = sub - > next ;
}
/* set the last sub->next to the first sub */
sub - > next = e - > sub ;
2002-12-29 19:13:07 +00:00
e - > next = gw - > endpoints ;
gw - > endpoints = e ;
}
} else
ast_log ( LOG_WARNING , " Don't know keyword '%s' at line %d \n " , v - > name , v - > lineno ) ;
v = v - > next ;
}
}
2003-03-09 06:00:18 +00:00
if ( ! ntohl ( gw - > addr . sin_addr . s_addr ) & & ! gw - > dynamic ) {
ast_log ( LOG_WARNING , " Gateway '%s' lacks IP address and isn't dynamic \n " , gw - > name ) ;
2002-12-29 19:13:07 +00:00
free ( gw ) ;
2003-03-09 06:00:18 +00:00
return NULL ;
}
if ( gw - > defaddr . sin_addr . s_addr & & ! ntohs ( gw - > defaddr . sin_port ) )
gw - > defaddr . sin_port = htons ( DEFAULT_MGCP_PORT ) ;
if ( gw - > addr . sin_addr . s_addr & & ! ntohs ( gw - > addr . sin_port ) )
2002-12-29 19:13:07 +00:00
gw - > addr . sin_port = htons ( DEFAULT_MGCP_PORT ) ;
2003-03-09 06:00:18 +00:00
if ( gw - > addr . sin_addr . s_addr )
2003-05-04 05:52:52 +00:00
if ( ast_ouraddrfor ( & gw - > addr . sin_addr , & gw - > ourip ) )
memcpy ( & gw - > ourip , & __ourip , sizeof ( gw - > ourip ) ) ;
2002-12-29 19:13:07 +00:00
return gw ;
}
2003-02-16 06:00:12 +00:00
static struct ast_rtp * mgcp_get_rtp_peer ( struct ast_channel * chan )
{
2003-05-06 04:03:58 +00:00
struct mgcp_subchannel * sub ;
sub = chan - > pvt - > pvt ;
if ( sub & & sub - > rtp )
return sub - > rtp ;
2003-02-16 06:00:12 +00:00
return NULL ;
}
2003-06-28 16:40:02 +00:00
static int mgcp_set_rtp_peer ( struct ast_channel * chan , struct ast_rtp * rtp , struct ast_rtp * vrtp )
2003-02-16 06:00:12 +00:00
{
2003-06-28 16:40:02 +00:00
/* XXX Is there such thing as video support with MGCP? XXX */
2003-05-06 04:03:58 +00:00
struct mgcp_subchannel * sub ;
sub = chan - > pvt - > pvt ;
if ( sub ) {
transmit_modify_with_sdp ( sub , rtp ) ;
2003-02-16 06:00:12 +00:00
return 0 ;
}
return - 1 ;
}
static struct ast_rtp_protocol mgcp_rtp = {
get_rtp_info : mgcp_get_rtp_peer ,
set_rtp_peer : mgcp_set_rtp_peer ,
} ;
2003-03-09 06:00:18 +00:00
static int mgcp_do_debug ( int fd , int argc , char * argv [ ] )
{
if ( argc ! = 2 )
return RESULT_SHOWUSAGE ;
mgcpdebug = 1 ;
ast_cli ( fd , " MGCP Debugging Enabled \n " ) ;
return RESULT_SUCCESS ;
}
static int mgcp_no_debug ( int fd , int argc , char * argv [ ] )
{
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
mgcpdebug = 0 ;
ast_cli ( fd , " MGCP Debugging Disabled \n " ) ;
return RESULT_SUCCESS ;
}
static char debug_usage [ ] =
" Usage: mgcp debug \n "
" Enables dumping of MGCP packets for debugging purposes \n " ;
static char no_debug_usage [ ] =
" Usage: mgcp no debug \n "
" Disables dumping of MGCP packets for debugging purposes \n " ;
static struct ast_cli_entry cli_debug =
{ { " mgcp " , " debug " , NULL } , mgcp_do_debug , " Enable MGCP debugging " , debug_usage } ;
static struct ast_cli_entry cli_no_debug =
{ { " mgcp " , " no " , " debug " , NULL } , mgcp_no_debug , " Disable MGCP debugging " , no_debug_usage } ;
2002-12-29 19:13:07 +00:00
int load_module ( )
{
struct ast_config * cfg ;
struct ast_variable * v ;
struct mgcp_gateway * g ;
2003-05-06 04:03:58 +00:00
struct mgcp_endpoint * e ;
2002-12-29 19:13:07 +00:00
char * cat ;
struct hostent * hp ;
int format ;
if ( gethostname ( ourhost , sizeof ( ourhost ) ) ) {
ast_log ( LOG_WARNING , " Unable to get hostname, MGCP disabled \n " ) ;
return 0 ;
}
cfg = ast_load ( config ) ;
/* We *must* have a config file otherwise stop immediately */
if ( ! cfg ) {
ast_log ( LOG_NOTICE , " Unable to load config %s, MGCP disabled \n " , config ) ;
return 0 ;
}
memset ( & bindaddr , 0 , sizeof ( bindaddr ) ) ;
v = ast_variable_browse ( cfg , " general " ) ;
while ( v ) {
/* Create the interface list */
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 , " port " ) ) {
if ( sscanf ( v - > value , " %i " , & ourport ) = = 1 ) {
bindaddr . sin_port = htons ( ourport ) ;
} else {
ast_log ( LOG_WARNING , " Invalid port number '%s' at line %d of %s \n " , v - > value , v - > lineno , config ) ;
}
}
v = v - > next ;
}
cat = ast_category_browse ( cfg , NULL ) ;
while ( cat ) {
if ( strcasecmp ( cat , " general " ) ) {
g = build_gateway ( cat , ast_variable_browse ( cfg , cat ) ) ;
if ( g ) {
2003-05-06 04:03:58 +00:00
if ( option_verbose > 2 ) {
2002-12-29 19:13:07 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Added gateway '%s' \n " , g - > name ) ;
2003-05-06 04:03:58 +00:00
}
2002-12-29 19:13:07 +00:00
ast_pthread_mutex_lock ( & gatelock ) ;
g - > next = gateways ;
gateways = g ;
ast_pthread_mutex_unlock ( & gatelock ) ;
}
}
cat = ast_category_browse ( cfg , cat ) ;
}
if ( ntohl ( bindaddr . sin_addr . s_addr ) ) {
memcpy ( & __ourip , & bindaddr , sizeof ( __ourip ) ) ;
} else {
hp = gethostbyname ( ourhost ) ;
if ( ! hp ) {
ast_log ( LOG_WARNING , " Unable to get our IP address, MGCP disabled \n " ) ;
return 0 ;
}
memcpy ( & __ourip , hp - > h_addr , sizeof ( __ourip ) ) ;
}
if ( ! ntohs ( bindaddr . sin_port ) )
bindaddr . sin_port = ntohs ( DEFAULT_MGCP_PORT ) ;
bindaddr . sin_family = AF_INET ;
pthread_mutex_lock ( & netlock ) ;
if ( mgcpsock > - 1 )
close ( mgcpsock ) ;
mgcpsock = socket ( AF_INET , SOCK_DGRAM , 0 ) ;
if ( mgcpsock < 0 ) {
ast_log ( LOG_WARNING , " Unable to create MGCP socket: %s \n " , strerror ( errno ) ) ;
} else {
if ( bind ( mgcpsock , ( struct sockaddr * ) & bindaddr , sizeof ( bindaddr ) ) < 0 ) {
ast_log ( LOG_WARNING , " Failed to bind to %s:%d: %s \n " ,
inet_ntoa ( bindaddr . sin_addr ) , ntohs ( bindaddr . sin_port ) ,
strerror ( errno ) ) ;
close ( mgcpsock ) ;
mgcpsock = - 1 ;
2003-05-06 04:03:58 +00:00
} else if ( option_verbose > 1 ) {
2002-12-29 19:13:07 +00:00
ast_verbose ( VERBOSE_PREFIX_2 " MGCP Listening on %s:%d \n " ,
inet_ntoa ( bindaddr . sin_addr ) , ntohs ( bindaddr . sin_port ) ) ;
2003-05-06 04:03:58 +00:00
}
2002-12-29 19:13:07 +00:00
}
pthread_mutex_unlock ( & netlock ) ;
ast_destroy ( cfg ) ;
/* Make sure we can register our mgcp channel type */
if ( ast_channel_register ( type , tdesc , capability , mgcp_request ) ) {
ast_log ( LOG_ERROR , " Unable to register channel class %s \n " , type ) ;
ast_destroy ( cfg ) ;
return - 1 ;
}
2003-02-16 06:00:12 +00:00
mgcp_rtp . type = type ;
ast_rtp_proto_register ( & mgcp_rtp ) ;
2002-12-29 19:13:07 +00:00
ast_cli_register ( & cli_show_endpoints ) ;
2003-04-11 19:17:05 +00:00
ast_cli_register ( & cli_audit_endpoint ) ;
2003-03-09 06:00:18 +00:00
ast_cli_register ( & cli_debug ) ;
ast_cli_register ( & cli_no_debug ) ;
2002-12-29 19:13:07 +00:00
/* And start the monitor for the first time */
restart_monitor ( ) ;
2003-05-06 04:03:58 +00:00
g = gateways ;
while ( g ) {
e = g - > endpoints ;
while ( e ) {
transmit_audit_endpoint ( e ) ;
ast_verbose ( VERBOSE_PREFIX_3 " MGCP Auditing endpoint %s@%s for hookstate \n " , e - > name , g - > name ) ;
e = e - > next ;
}
g = g - > next ;
}
2002-12-29 19:13:07 +00:00
return 0 ;
}
int unload_module ( )
{
#if 0
2003-03-16 22:37:31 +00:00
struct mgcp_endpoint * p , * pl ;
2002-12-29 19:13:07 +00:00
/* First, take us out of the channel loop */
ast_channel_unregister ( type ) ;
if ( ! ast_pthread_mutex_lock ( & gatelock ) ) {
/* 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_pthread_mutex_unlock ( & iflock ) ;
} else {
ast_log ( LOG_WARNING , " Unable to lock the monitor \n " ) ;
return - 1 ;
}
if ( ! ast_pthread_mutex_lock ( & monlock ) ) {
if ( monitor_thread ) {
pthread_cancel ( monitor_thread ) ;
pthread_kill ( monitor_thread , SIGURG ) ;
pthread_join ( monitor_thread , NULL ) ;
}
monitor_thread = - 2 ;
ast_pthread_mutex_unlock ( & monlock ) ;
} else {
ast_log ( LOG_WARNING , " Unable to lock the monitor \n " ) ;
return - 1 ;
}
if ( ! ast_pthread_mutex_lock ( & iflock ) ) {
/* Destroy all the interfaces and free their memory */
p = iflist ;
while ( p ) {
pl = p ;
p = p - > next ;
/* Free associated memory */
free ( pl ) ;
}
iflist = NULL ;
ast_pthread_mutex_unlock ( & iflock ) ;
} else {
ast_log ( LOG_WARNING , " Unable to lock the monitor \n " ) ;
return - 1 ;
}
# endif
return - 1 ;
}
int usecount ( )
{
int res ;
ast_pthread_mutex_lock ( & usecnt_lock ) ;
res = usecnt ;
ast_pthread_mutex_unlock ( & usecnt_lock ) ;
return res ;
}
char * key ( )
{
return ASTERISK_GPL_KEY ;
}
char * description ( )
{
return desc ;
}