2002-12-29 19:13:07 +00:00
/*
* Asterisk - - A telephony toolkit for Linux .
*
* Implementation of Media Gateway Control Protocol
*
2004-09-17 20:08:40 +00:00
* Copyright ( C ) 1999 - 2004 , Digium , Inc .
2002-12-29 19:13:07 +00:00
*
2004-09-17 20:08:40 +00:00
* Mark Spencer < markster @ digium . com >
2002-12-29 19:13:07 +00:00
*
* This program is free software , distributed under the terms of
* the GNU General Public License
*/
2004-04-26 05:18:55 +00:00
/* JS: Changes
- - add support for the wildcard endpoint
- - seteable wildcard with wcardep on mgcp . conf
- - added package indicator on RQNT , i . e " dl " - - > " L/dl "
- - removed MDCX just before DLCX , do we need this ?
*/
/* JS: TODO
- - reload for wildcard endpoint probably buggy
- - when hf is notified we ' re sending CRCX after MDCX , without waiting for
OK on the MDCX which fails on Cisco IAD 24 XX
- - honour codec order , by now the lowest codec number in " allow " is the prefered
*/
2004-03-19 22:57:08 +00:00
/* SC: Changes
- - packet retransmit mechanism ( simplistic )
- - per endpoint / subchannel mgcp command sequencing .
- - better transaction handling
- - fixed some mem leaks
- - run - time configuration reload
- - distinguish CA and GW default MGCP ports
- - prevent clipping of DTMF tones in an established call
- - fixed a few crash scenarios in 3 - way
- - fix for a few cases where asterisk and MGW end - up in conflicting ep states
- - enclose numeric IP in [ ] for outgoing requests
*/
/* SC: TODO
- - piggyback support
- - responseAck support
- - enhance retransmit mechanism ( RTO calc . etc . )
- - embedded command support
*/
2004-04-27 21:18:02 +00:00
/* FS: Changes
* - - fixed reload_config ( ) / do_monitor to stay responsive during reloads
*/
2004-03-19 22:57:08 +00:00
2002-12-29 19:13:07 +00:00
# include <stdio.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>
2004-07-17 20:58:01 +00:00
# include <asterisk/features.h>
2003-05-06 04:03:58 +00:00
# include <asterisk/app.h>
# include <asterisk/musiconhold.h>
2004-05-09 08:22:15 +00:00
# include <asterisk/utils.h>
2004-10-26 22:25:43 +00:00
# include <asterisk/causes.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>
2004-02-02 06:38:08 +00:00
# include <signal.h>
2003-07-30 20:49:23 +00:00
# include <netinet/in_systm.h>
# include <netinet/ip.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
2003-07-30 20:49:23 +00:00
# ifndef IPTOS_MINCOST
# define IPTOS_MINCOST 0x02
# endif
2004-07-25 01:20:16 +00:00
/*
* Define to work around buggy dlink MGCP phone firmware which
* appears not to know that " rt " is part of the " G " package .
*/
/* #define DLINK_BUGGY_FIRMWARE */
2002-12-29 19:13:07 +00:00
# define MGCPDUMPER
# define DEFAULT_EXPIREY 120
# define MAX_EXPIREY 3600
2003-08-19 15:13:54 +00:00
# define CANREINVITE 1
2002-12-29 19:13:07 +00:00
2004-12-14 23:36:30 +00:00
# ifndef INADDR_NONE
# define INADDR_NONE (in_addr_t)(-1)
# endif
2002-12-29 19:13:07 +00:00
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 " ;
2004-07-26 19:33:36 +00:00
# define MGCP_DTMF_RFC2833 (1 << 0)
# define MGCP_DTMF_INBAND (1 << 1)
2004-03-19 22:57:08 +00:00
# define DEFAULT_MGCP_GW_PORT 2427 /* From RFC 2705 */
# define DEFAULT_MGCP_CA_PORT 2727 /* From RFC 2705 */
2002-12-29 19:13:07 +00:00
# define MGCP_MAX_PACKET 1500 /* Also from RFC 2543, should sub headers tho */
2004-03-19 22:57:08 +00:00
# define DEFAULT_RETRANS 1000 /* How frequently to retransmit */
# define MAX_RETRANS 5 /* Try only 5 times for retransmissions */
2002-12-29 19:13:07 +00:00
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 "
} ;
2004-03-19 22:57:08 +00:00
/* SC: MGCP commands */
# define MGCP_CMD_EPCF 0
# define MGCP_CMD_CRCX 1
# define MGCP_CMD_MDCX 2
# define MGCP_CMD_DLCX 3
# define MGCP_CMD_RQNT 4
# define MGCP_CMD_NTFY 5
# define MGCP_CMD_AUEP 6
# define MGCP_CMD_AUCX 7
# define MGCP_CMD_RSIP 8
2003-05-06 04:03:58 +00:00
static char context [ AST_MAX_EXTENSION ] = " default " ;
static char language [ MAX_LANGUAGE ] = " " ;
static char musicclass [ MAX_LANGUAGE ] = " " ;
2004-10-02 00:58:31 +00:00
static char cid_num [ AST_MAX_EXTENSION ] = " " ;
static char cid_name [ AST_MAX_EXTENSION ] = " " ;
2003-05-06 04:03:58 +00:00
2004-07-26 19:33:36 +00:00
static int dtmfmode = 0 ;
2003-05-06 04:03:58 +00:00
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 */
2004-07-26 19:33:36 +00:00
/* dtmfmode is actually hooked up. */
2003-05-06 04:03:58 +00:00
/* static int relaxdtmf = 0; */
2003-07-30 20:49:23 +00:00
static int tos = 0 ;
2003-05-06 04:03:58 +00:00
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 ;
2004-07-25 01:20:16 +00:00
static int slowsequence = 0 ;
2003-05-06 04:03:58 +00:00
static int threewaycalling = 0 ;
/* This is for flashhook transfers */
static int transfer = 0 ;
static int cancallforward = 0 ;
2004-08-02 04:32:37 +00:00
static int singlepath = 0 ;
2003-08-19 15:13:54 +00:00
static int canreinvite = CANREINVITE ;
2003-05-06 04:03:58 +00:00
/*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 ;
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( usecnt_lock ) ;
2004-03-27 17:51:22 +00:00
/* SC: transaction id should always be positive */
static unsigned int oseq ;
2002-12-29 19:13:07 +00:00
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 . */
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( netlock ) ;
2002-12-29 19:13:07 +00:00
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( monlock ) ;
2002-12-29 19:13:07 +00:00
/* This is the thread for the monitor which checks for input on the channels
which are not currently in use . */
2004-03-15 07:51:22 +00:00
static pthread_t monitor_thread = AST_PTHREADT_NULL ;
2002-12-29 19:13:07 +00:00
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 ] ;
2004-03-19 22:57:08 +00:00
int cmd ; /* SC: int version of verb = command */
2004-03-27 17:51:22 +00:00
unsigned int trid ; /* SC: int version of identifier = transaction id */
2004-03-19 22:57:08 +00:00
struct mgcp_request * next ; /* SC: next in the queue */
2002-12-29 19:13:07 +00:00
} ;
2004-03-19 22:57:08 +00:00
/* SC: obsolete
2002-12-29 19:13:07 +00:00
static struct mgcp_pkt {
int retrans ;
struct mgcp_endpoint * owner ;
int packetlen ;
char data [ MGCP_MAX_PACKET ] ;
struct mgcp_pkt * next ;
} * packets = NULL ;
2004-03-19 22:57:08 +00:00
*/
2002-12-29 19:13:07 +00:00
2003-03-15 06:00:16 +00:00
/* MGCP message for queuing up */
struct mgcp_message {
2004-03-19 22:57:08 +00:00
struct mgcp_endpoint * owner_ep ;
struct mgcp_subchannel * owner_sub ;
int retrans ;
unsigned long expire ;
2003-03-15 06:00:16 +00:00
unsigned int seqno ;
int len ;
struct mgcp_message * next ;
unsigned char buf [ 0 ] ;
} ;
2004-05-21 06:05:20 +00:00
# define RESPONSE_TIMEOUT 30 /* in seconds */
struct mgcp_response {
time_t whensent ;
int len ;
int seqno ;
struct mgcp_response * 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 {
2004-03-19 22:57:08 +00:00
/* SC: subchannel magic string.
Needed to prove that any subchannel pointer passed by asterisk
really points to a valid subchannel memory area .
Ugly . . But serves the purpose for the time being .
*/
# define MGCP_SUBCHANNEL_MAGIC "!978!"
char magic [ 6 ] ;
2003-08-13 15:25:16 +00:00
ast_mutex_t lock ;
2003-05-06 04:03:58 +00:00
int id ;
struct ast_channel * owner ;
struct mgcp_endpoint * parent ;
struct ast_rtp * rtp ;
struct sockaddr_in tmpdest ;
2004-03-19 22:57:08 +00:00
char txident [ 80 ] ; /* FIXME SC: txident is replaced by rqnt_ident in endpoint.
This should be obsoleted */
2003-05-06 04:03:58 +00:00
char cxident [ 80 ] ;
char callid [ 80 ] ;
2004-03-19 22:57:08 +00:00
/* SC: obsolete
2003-05-06 04:03:58 +00:00
time_t lastouttime ;
int lastout ;
2004-03-19 22:57:08 +00:00
*/
2003-05-06 04:03:58 +00:00
int cxmode ;
2004-03-19 22:57:08 +00:00
struct mgcp_request * cx_queue ; /* SC: pending CX commands */
ast_mutex_t cx_queue_lock ; /* SC: CX queue lock */
2003-05-06 04:03:58 +00:00
int nat ;
int iseq ; /* Not used? RTP? */
int outgoing ;
int alreadygone ;
2004-03-19 22:57:08 +00:00
/* SC: obsolete
2003-05-06 04:03:58 +00:00
int messagepending ;
2004-03-19 22:57:08 +00:00
struct mgcp_message * msgs ;
*/
2003-05-06 04:03:58 +00:00
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 {
2003-08-13 15:25:16 +00:00
ast_mutex_t lock ;
2002-12-29 19:13:07 +00:00
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 ] ;
2004-10-02 00:58:31 +00:00
char cid_num [ AST_MAX_EXTENSION ] ; /* Caller*ID */
char cid_name [ AST_MAX_EXTENSION ] ; /* Caller*ID */
2003-05-06 04:03:58 +00:00
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 ;
2004-08-02 04:32:37 +00:00
int singlepath ;
2003-05-06 04:03:58 +00:00
int cancallforward ;
2003-08-19 15:13:54 +00:00
int canreinvite ;
2003-05-06 04:03:58 +00:00
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 ;
2004-07-26 19:33:36 +00:00
int dtmfmode ;
2002-12-29 19:13:07 +00:00
int amaflags ;
int type ;
2004-07-25 01:20:16 +00:00
int slowsequence ; /* MS: Sequence the endpoint as a whole */
2002-12-29 19:13:07 +00:00
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 ;
2004-03-19 22:57:08 +00:00
char rqnt_ident [ 80 ] ; /* SC: request identifier */
struct mgcp_request * rqnt_queue ; /* SC: pending RQNT commands */
ast_mutex_t rqnt_queue_lock ;
struct mgcp_request * cmd_queue ; /* SC: pending commands other than RQNT */
ast_mutex_t cmd_queue_lock ;
int delme ; /* SC: needed for reload */
int needaudit ; /* SC: needed for reload */
2003-05-06 04:03:58 +00:00
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 ] ;
2004-03-19 22:57:08 +00:00
int isnamedottedip ; /* SC: is the name FQDN or dotted ip */
2002-12-29 19:13:07 +00:00
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 ;
2004-03-19 22:57:08 +00:00
/* SC: obsolete
time_t lastouttime ;
int lastout ;
int messagepending ;
*/
2004-04-26 05:18:55 +00:00
/* JS: Wildcard endpoint name */
char wcardep [ 30 ] ;
2004-03-19 22:57:08 +00:00
struct mgcp_message * msgs ; /* SC: gw msg queue */
ast_mutex_t msgs_lock ; /* SC: queue lock */
int retransid ; /* SC: retrans timer id */
int delme ; /* SC: needed for reload */
2004-05-21 06:05:20 +00:00
struct mgcp_response * responses ;
2002-12-29 19:13:07 +00:00
struct mgcp_gateway * next ;
} * gateways ;
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( mgcp_reload_lock ) ;
2004-03-19 22:57:08 +00:00
static int mgcp_reloading = 0 ;
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( gatelock ) ;
2002-12-29 19:13:07 +00:00
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 ) ;
2004-10-02 00:58:31 +00:00
static int transmit_notify_request_with_callerid ( struct mgcp_subchannel * sub , char * tone , char * callernum , char * callername ) ;
2004-05-27 04:18:46 +00:00
static int transmit_modify_with_sdp ( struct mgcp_subchannel * sub , struct ast_rtp * rtp , int codecs ) ;
2003-05-06 04:03:58 +00:00
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 ) ;
2004-03-19 22:57:08 +00:00
static void handle_response ( struct mgcp_endpoint * p , struct mgcp_subchannel * sub ,
2004-03-27 17:51:22 +00:00
int result , unsigned int ident , struct mgcp_request * resp ) ;
2004-03-19 22:57:08 +00:00
static void dump_cmd_queues ( struct mgcp_endpoint * p , struct mgcp_subchannel * sub ) ;
static int mgcp_do_reload ( void ) ;
static int mgcp_reload ( int fd , int argc , char * argv [ ] ) ;
2003-05-06 04:03:58 +00:00
static int has_voicemail ( struct mgcp_endpoint * p )
{
2004-10-03 21:18:27 +00:00
return ast_app_has_voicemail ( p - > mailbox , NULL ) ;
2003-05-06 04:03:58 +00:00
}
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 ;
}
2004-03-19 22:57:08 +00:00
dump_cmd_queues ( NULL , sub ) ; /* SC */
2003-05-06 04:03:58 +00:00
return 0 ;
}
2002-12-29 19:13:07 +00:00
2004-03-19 22:57:08 +00:00
/* SC: modified for new transport mechanism */
static int __mgcp_xmit ( struct mgcp_gateway * gw , char * data , int len )
2002-12-29 19:13:07 +00:00
{
int res ;
2004-03-19 22:57:08 +00:00
if ( gw - > addr . sin_addr . s_addr )
res = sendto ( mgcpsock , data , len , 0 , ( struct sockaddr * ) & gw - > addr , sizeof ( struct sockaddr_in ) ) ;
2003-03-09 06:00:18 +00:00
else
2004-03-19 22:57:08 +00:00
res = sendto ( mgcpsock , data , len , 0 , ( struct sockaddr * ) & gw - > 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 ;
}
2004-05-21 06:05:20 +00:00
static int resend_response ( struct mgcp_subchannel * sub , struct mgcp_response * resp )
{
struct mgcp_endpoint * p = sub - > parent ;
int res ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2004-05-21 06:05:20 +00:00
if ( mgcpdebug ) {
2004-06-29 12:56:46 +00:00
ast_verbose ( " Retransmitting: \n %s \n to %s:%d \n " , resp - > buf , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > parent - > addr . sin_addr ) , ntohs ( p - > parent - > addr . sin_port ) ) ;
2004-05-21 06:05:20 +00:00
}
res = __mgcp_xmit ( p - > parent , resp - > buf , resp - > len ) ;
if ( res > 0 )
res = 0 ;
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 ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-05-06 04:03:58 +00:00
if ( mgcpdebug ) {
2004-06-29 12:56:46 +00:00
ast_verbose ( " Transmitting: \n %s \n to %s:%d \n " , req - > data , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > parent - > addr . sin_addr ) , ntohs ( p - > parent - > addr . sin_port ) ) ;
2003-05-06 04:03:58 +00:00
}
2004-03-19 22:57:08 +00:00
res = __mgcp_xmit ( p - > parent , req - > data , req - > len ) ;
2002-12-29 19:13:07 +00:00
if ( res > 0 )
res = 0 ;
return res ;
}
2004-03-19 22:57:08 +00:00
/* SC: modified for new transport framework */
static void dump_queue ( struct mgcp_gateway * gw , struct mgcp_endpoint * p )
2003-03-15 06:00:16 +00:00
{
2004-03-19 22:57:08 +00:00
struct mgcp_message * cur , * q = NULL , * w , * prev ;
ast_mutex_lock ( & gw - > msgs_lock ) ;
prev = NULL , cur = gw - > msgs ;
while ( cur ) {
if ( ! p | | cur - > owner_ep = = p ) {
if ( prev )
prev - > next = cur - > next ;
else
gw - > msgs = cur - > next ;
2004-04-26 05:18:55 +00:00
ast_log ( LOG_NOTICE , " Removing message from %s transaction %u \n " ,
2004-03-19 22:57:08 +00:00
gw - > name , cur - > seqno ) ;
w = cur ;
cur = cur - > next ;
if ( q ) {
w - > next = q ;
}
else {
w - > next = NULL ;
}
q = w ;
2003-05-06 04:03:58 +00:00
}
2004-03-19 22:57:08 +00:00
else {
prev = cur , cur = cur - > next ;
}
}
ast_mutex_unlock ( & gw - > msgs_lock ) ;
while ( q ) {
cur = q ;
q = q - > next ;
free ( cur ) ;
}
2003-03-15 06:00:16 +00:00
}
2004-11-07 21:46:09 +00:00
static void mgcp_queue_frame ( struct mgcp_subchannel * sub , struct ast_frame * f )
{
for ( ; ; ) {
if ( sub - > owner ) {
if ( ! ast_mutex_trylock ( & sub - > owner - > lock ) ) {
ast_queue_frame ( sub - > owner , f ) ;
ast_mutex_unlock ( & sub - > owner - > lock ) ;
2004-11-17 14:48:16 +00:00
break ;
2004-11-07 21:46:09 +00:00
} else {
ast_mutex_unlock ( & sub - > lock ) ;
usleep ( 1 ) ;
ast_mutex_lock ( & sub - > lock ) ;
}
} else
break ;
}
}
static void mgcp_queue_hangup ( struct mgcp_subchannel * sub )
{
for ( ; ; ) {
if ( sub - > owner ) {
if ( ! ast_mutex_trylock ( & sub - > owner - > lock ) ) {
ast_queue_hangup ( sub - > owner ) ;
ast_mutex_unlock ( & sub - > owner - > lock ) ;
2004-11-17 14:48:16 +00:00
break ;
2004-11-07 21:46:09 +00:00
} else {
ast_mutex_unlock ( & sub - > lock ) ;
usleep ( 1 ) ;
ast_mutex_lock ( & sub - > lock ) ;
}
} else
break ;
}
}
static void mgcp_queue_control ( struct mgcp_subchannel * sub , int control )
{
struct ast_frame f = { AST_FRAME_CONTROL , } ;
f . subclass = control ;
return mgcp_queue_frame ( sub , & f ) ;
}
2004-03-19 22:57:08 +00:00
static int retrans_pkt ( void * data )
{
struct mgcp_gateway * gw = ( struct mgcp_gateway * ) data ;
struct mgcp_message * cur , * exq = NULL , * w , * prev ;
struct timeval tv ;
unsigned long t ;
int res = 0 ;
if ( gettimeofday ( & tv , NULL ) < 0 ) {
/* This shouldn't ever happen, but let's be sure */
ast_log ( LOG_NOTICE , " gettimeofday() failed! \n " ) ;
return 0 ;
}
t = tv . tv_sec * 1000 + tv . tv_usec / 1000 ;
/* find out expired msgs */
ast_mutex_lock ( & gw - > msgs_lock ) ;
prev = NULL , cur = gw - > msgs ;
while ( cur ) {
if ( cur - > retrans < MAX_RETRANS ) {
cur - > retrans + + ;
if ( mgcpdebug ) {
2004-03-27 17:51:22 +00:00
ast_verbose ( " Retransmitting #%d transaction %u on [%s] \n " , cur - > retrans , cur - > seqno , gw - > name ) ;
2004-03-19 22:57:08 +00:00
}
__mgcp_xmit ( gw , cur - > buf , cur - > len ) ;
prev = cur ;
cur = cur - > next ;
}
else {
if ( prev )
prev - > next = cur - > next ;
else
gw - > msgs = cur - > next ;
2004-03-27 17:51:22 +00:00
ast_log ( LOG_WARNING , " Maximum retries exceeded for transaction %u on [%s] \n " , cur - > seqno , gw - > name ) ;
2004-03-19 22:57:08 +00:00
w = cur ;
cur = cur - > next ;
if ( exq ) {
w - > next = exq ;
}
else {
w - > next = NULL ;
}
exq = w ;
}
}
if ( ! gw - > msgs ) {
gw - > retransid = - 1 ;
res = 0 ;
}
else {
res = 1 ;
}
ast_mutex_unlock ( & gw - > msgs_lock ) ;
while ( exq ) {
cur = exq ;
/* time-out transaction */
handle_response ( cur - > owner_ep , cur - > owner_sub , 406 , cur - > seqno , NULL ) ;
exq = exq - > next ;
free ( cur ) ;
}
return res ;
}
/* SC: modified for the new transaction mechanism */
static int mgcp_postrequest ( struct mgcp_endpoint * p , 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 ;
2004-03-19 22:57:08 +00:00
struct mgcp_gateway * gw = ( ( p & & p - > parent ) ? p - > parent : NULL ) ;
struct timeval tv ;
2003-05-06 04:03:58 +00:00
if ( ! msg ) {
2003-03-15 06:00:16 +00:00
return - 1 ;
2003-05-06 04:03:58 +00:00
}
2004-03-19 22:57:08 +00:00
if ( ! gw ) {
return - 1 ;
}
/* SC
2003-05-06 04:03:58 +00:00
time ( & t ) ;
2004-03-19 22:57:08 +00:00
if ( gw - > messagepending & & ( gw - > 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 " ,
2004-03-19 22:57:08 +00:00
gw - > msgs ? gw - > msgs - > seqno : - 1 , ( long ) gw - > lastouttime , ( long ) t ) ;
2003-05-06 04:03:58 +00:00
dump_queue ( sub - > parent ) ;
}
2004-03-19 22:57:08 +00:00
*/
msg - > owner_sub = sub ;
msg - > owner_ep = p ;
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 ;
2004-03-19 22:57:08 +00:00
msg - > retrans = 0 ;
2003-03-15 06:00:16 +00:00
memcpy ( msg - > buf , data , msg - > len ) ;
2004-03-19 22:57:08 +00:00
ast_mutex_lock ( & gw - > msgs_lock ) ;
cur = gw - > 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 {
2004-03-19 22:57:08 +00:00
gw - > msgs = msg ;
2003-05-06 04:03:58 +00:00
}
2004-03-19 22:57:08 +00:00
if ( gettimeofday ( & tv , NULL ) < 0 ) {
/* This shouldn't ever happen, but let's be sure */
ast_log ( LOG_NOTICE , " gettimeofday() failed! \n " ) ;
}
else {
msg - > expire = tv . tv_sec * 1000 + tv . tv_usec / 1000 + DEFAULT_RETRANS ;
if ( gw - > retransid = = - 1 )
gw - > retransid = ast_sched_add ( sched , DEFAULT_RETRANS , retrans_pkt , ( void * ) gw ) ;
}
ast_mutex_unlock ( & gw - > msgs_lock ) ;
/* SC
if ( ! gw - > messagepending ) {
gw - > messagepending = 1 ;
gw - > lastout = seqno ;
gw - > lastouttime = t ;
*/
__mgcp_xmit ( gw , msg - > buf , msg - > len ) ;
2003-03-15 06:00:16 +00:00
/* XXX Should schedule retransmission XXX */
2004-03-19 22:57:08 +00:00
/* SC
2003-03-15 06:00:16 +00:00
} else
ast_log ( LOG_DEBUG , " Deferring transmission of transaction %d \n " , seqno ) ;
2004-03-19 22:57:08 +00:00
*/
2003-03-15 06:00:16 +00:00
return 0 ;
}
2004-03-19 22:57:08 +00:00
/* SC: modified for new transport */
static int send_request ( struct mgcp_endpoint * p , struct mgcp_subchannel * sub ,
struct mgcp_request * req , unsigned int seqno )
2002-12-29 19:13:07 +00:00
{
2004-03-19 22:57:08 +00:00
int res = 0 ;
struct mgcp_request * * queue , * q , * r , * t ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2004-03-19 22:57:08 +00:00
ast_mutex_t * l ;
2004-07-25 01:20:16 +00:00
ast_log ( LOG_DEBUG , " Slow sequence is %d \n " , p - > slowsequence ) ;
if ( p - > slowsequence ) {
queue = & p - > cmd_queue ;
l = & p - > cmd_queue_lock ;
ast_mutex_lock ( l ) ;
} else
2004-03-19 22:57:08 +00:00
switch ( req - > cmd ) {
case MGCP_CMD_DLCX :
queue = & sub - > cx_queue ;
l = & sub - > cx_queue_lock ;
ast_mutex_lock ( l ) ;
q = sub - > cx_queue ;
/* delete pending cx cmds */
while ( q ) {
r = q - > next ;
free ( q ) ;
q = r ;
}
* queue = NULL ;
break ;
case MGCP_CMD_CRCX :
case MGCP_CMD_MDCX :
queue = & sub - > cx_queue ;
l = & sub - > cx_queue_lock ;
ast_mutex_lock ( l ) ;
break ;
case MGCP_CMD_RQNT :
queue = & p - > rqnt_queue ;
l = & p - > rqnt_queue_lock ;
ast_mutex_lock ( l ) ;
break ;
default :
queue = & p - > cmd_queue ;
l = & p - > cmd_queue_lock ;
ast_mutex_lock ( l ) ;
break ;
2003-05-06 04:03:58 +00:00
}
2004-03-19 22:57:08 +00:00
r = ( struct mgcp_request * ) malloc ( sizeof ( struct mgcp_request ) ) ;
if ( ! r ) {
ast_log ( LOG_WARNING , " Cannot post MGCP request: insufficient memory \n " ) ;
ast_mutex_unlock ( l ) ;
return - 1 ;
}
memcpy ( r , req , sizeof ( struct mgcp_request ) ) ;
if ( ! ( * queue ) ) {
if ( mgcpdebug ) {
ast_verbose ( " Posting Request: \n %s to %s:%d \n " , req - > data ,
2004-06-29 12:56:46 +00:00
ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > parent - > addr . sin_addr ) , ntohs ( p - > parent - > addr . sin_port ) ) ;
2004-03-19 22:57:08 +00:00
}
res = mgcp_postrequest ( p , sub , req - > data , req - > len , seqno ) ;
}
else {
if ( mgcpdebug ) {
ast_verbose ( " Queueing Request: \n %s to %s:%d \n " , req - > data ,
2004-06-29 12:56:46 +00:00
ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > parent - > addr . sin_addr ) , ntohs ( p - > parent - > addr . sin_port ) ) ;
2004-03-19 22:57:08 +00:00
}
}
/* XXX SC: find tail. We could also keep tail in the data struct for faster access */
for ( t = * queue ; t & & t - > next ; t = t - > next ) ;
r - > next = NULL ;
if ( t )
t - > next = r ;
else
* queue = r ;
ast_mutex_unlock ( l ) ;
return res ;
2002-12-29 19:13:07 +00:00
}
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 ;
2004-11-07 21:46:09 +00:00
ast_mutex_lock ( & sub - > lock ) ;
2003-05-06 04:03:58 +00:00
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 ) ;
2004-11-07 21:46:09 +00:00
ast_mutex_unlock ( & sub - > lock ) ;
2002-12-29 19:13:07 +00:00
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 ) ;
}
2004-10-02 00:58:31 +00:00
transmit_notify_request_with_callerid ( sub , tone , ast - > cid . cid_num , ast - > cid . cid_name ) ;
2002-12-29 19:13:07 +00:00
ast_setstate ( ast , AST_STATE_RINGING ) ;
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 ;
}
2004-11-07 21:46:09 +00:00
ast_mutex_unlock ( & sub - > lock ) ;
2004-11-15 00:35:49 +00:00
ast_queue_control ( ast , AST_CONTROL_RINGING ) ;
2002-12-29 19:13:07 +00:00
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 ;
2005-01-01 00:59:54 +00:00
if ( option_debug ) {
2002-12-29 19:13:07 +00:00
ast_log ( LOG_DEBUG , " mgcp_hangup(%s) \n " , ast - > name ) ;
2005-01-01 00:59:54 +00:00
}
2002-12-29 19:13:07 +00:00
if ( ! ast - > pvt - > pvt ) {
ast_log ( LOG_DEBUG , " Asked to hangup channel not connected \n " ) ;
return 0 ;
}
2005-01-01 00:59:54 +00:00
if ( strcmp ( sub - > magic , MGCP_SUBCHANNEL_MAGIC ) ) {
2004-03-19 22:57:08 +00:00
ast_log ( LOG_DEBUG , " Invalid magic. MGCP subchannel freed up already. \n " ) ;
return 0 ;
2005-01-01 00:59:54 +00:00
}
ast_mutex_lock ( & sub - > lock ) ;
if ( mgcpdebug ) {
ast_verbose ( VERBOSE_PREFIX_3 " MGCP mgcp_hangup(%s) on %s@%s \n " , ast - > name , p - > name , p - > parent - > name ) ;
}
2004-03-19 22:57:08 +00:00
2005-01-01 00:59:54 +00:00
if ( ( p - > dtmfmode & MGCP_DTMF_INBAND ) & & p - > dsp ) {
2004-03-19 22:57:08 +00:00
/* SC: check whether other channel is active. */
2005-01-01 00:59:54 +00:00
if ( ! sub - > next - > owner ) {
2004-03-19 22:57:08 +00:00
if ( mgcpdebug ) {
ast_verbose ( VERBOSE_PREFIX_2 " MGCP free dsp on %s@%s \n " , p - > name , p - > parent - > name ) ;
}
ast_dsp_free ( p - > dsp ) ;
p - > dsp = NULL ;
}
2005-01-01 00:59:54 +00:00
}
2003-05-06 04:03:58 +00:00
sub - > owner = NULL ;
if ( strlen ( sub - > cxident ) ) {
transmit_connection_del ( sub ) ;
2005-01-01 00:59:54 +00:00
}
sub - > cxident [ 0 ] = ' \0 ' ;
2003-05-06 04:03:58 +00:00
if ( ( sub = = p - > sub ) & & sub - > next - > owner ) {
if ( p - > hookstate = = MGCP_OFFHOOK ) {
2004-10-23 12:19:47 +00:00
if ( sub - > next - > owner & & ast_bridged_channel ( sub - > next - > owner ) ) {
transmit_notify_request_with_callerid ( p - > sub , " L/wt " , ast_bridged_channel ( sub - > next - > owner ) - > cid . cid_num , ast_bridged_channel ( sub - > next - > owner ) - > cid . cid_name ) ;
2003-05-06 04:03:58 +00:00
}
} 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 ) ;
2004-10-23 12:19:47 +00:00
if ( sub - > next - > owner & & ast_bridged_channel ( sub - > next - > owner ) ) {
transmit_notify_request_with_callerid ( p - > sub , " L/rg " , ast_bridged_channel ( sub - > next - > owner ) - > cid . cid_num , ast_bridged_channel ( sub - > next - > owner ) - > cid . cid_name ) ;
2003-05-06 04:03:58 +00:00
}
}
} else if ( ( sub = = p - > sub - > next ) & & p - > hookstate = = MGCP_OFFHOOK ) {
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/v " ) ;
2003-05-06 04:03:58 +00:00
} else if ( p - > hookstate = = MGCP_OFFHOOK ) {
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/ro " ) ;
2003-05-06 04:03:58 +00:00
} 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 ;
2004-07-16 04:40:54 +00:00
sub - > callid [ 0 ] = ' \0 ' ;
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
2004-03-19 22:57:08 +00:00
/* SC: Decrement use count */
ast_mutex_lock ( & usecnt_lock ) ;
usecnt - - ;
ast_mutex_unlock ( & usecnt_lock ) ;
ast_update_use_count ( ) ;
/* SC: Decrement use count */
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 ) ;
}
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/vmwi(+) " ) ;
2003-05-06 04:03:58 +00:00
} 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 ) ;
}
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/vmwi(-) " ) ;
2003-05-06 04:03:58 +00:00
}
}
2003-08-13 15:25:16 +00:00
ast_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 ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2002-12-29 19:13:07 +00:00
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & gatelock ) ;
2002-12-29 19:13:07 +00:00
g = gateways ;
while ( g ) {
e = g - > endpoints ;
2004-06-29 12:56:46 +00:00
ast_cli ( fd , " Gateway '%s' at %s (%s) \n " , g - > name , g - > addr . sin_addr . s_addr ? ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , g - > addr . sin_addr ) : ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , g - > defaddr . sin_addr ) , g - > dynamic ? " Dynamic " : " Static " ) ;
2002-12-29 19:13:07 +00:00
while ( e ) {
2004-12-19 21:13:41 +00:00
/* JS: Don't show wilcard endpoint */
2004-04-26 05:18:55 +00:00
if ( strcmp ( e - > name , g - > wcardep ) ! = 0 )
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 ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & gatelock ) ;
2002-12-29 19:13:07 +00:00
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-08-13 15:25:16 +00:00
ast_mutex_lock ( & gatelock ) ;
2003-04-11 19:17:05 +00:00
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 >> " ) ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & gatelock ) ;
2003-04-11 19:17:05 +00:00
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 ;
2004-11-07 21:46:09 +00:00
ast_mutex_lock ( & sub - > lock ) ;
2003-05-06 04:03:58 +00:00
sub - > cxmode = MGCP_CX_SENDRECV ;
if ( ! sub - > rtp ) {
start_rtp ( sub ) ;
} else {
transmit_modify_request ( sub ) ;
}
2004-03-19 22:57:08 +00:00
/* SC: verbose level check */
if ( option_verbose > 2 ) {
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
}
2004-11-07 21:46:09 +00:00
ast_mutex_unlock ( & sub - > lock ) ;
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 ;
2004-10-26 02:57:18 +00:00
static struct ast_frame null_frame = { AST_FRAME_NULL , } ;
2003-05-06 04:03:58 +00:00
f = ast_rtp_read ( sub - > rtp ) ;
2004-10-26 02:57:18 +00:00
/* Don't send RFC2833 if we're not supposed to */
if ( f & & ( f - > frametype = = AST_FRAME_DTMF ) & & ! ( sub - > parent - > dtmfmode & MGCP_DTMF_RFC2833 ) )
return & null_frame ;
2003-05-06 04:03:58 +00:00
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 ;
2004-04-06 22:17:32 +00:00
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 */
2004-10-26 02:57:18 +00:00
if ( ( sub - > parent - > dtmfmode & MGCP_DTMF_INBAND ) & & ( sub - > parent - > dsp ) ) {
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
2004-04-06 22:17:32 +00:00
f = ast_dsp_process ( sub - > owner , sub - > parent - > dsp , f ) ;
2003-05-06 04:03:58 +00:00
}
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 )
{
2004-10-26 02:57:18 +00:00
struct ast_frame * f ;
2003-05-06 04:03:58 +00:00
struct mgcp_subchannel * sub = ast - > pvt - > pvt ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & sub - > lock ) ;
2004-10-26 02:57:18 +00:00
f = mgcp_rtp_read ( sub ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & sub - > lock ) ;
2004-10-26 02:57:18 +00:00
return f ;
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 ) {
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & sub - > lock ) ;
2004-09-17 20:08:40 +00:00
if ( ( sub - > parent - > sub = = sub ) | | ! sub - > parent - > singlepath ) {
if ( sub - > rtp ) {
res = ast_rtp_write ( sub - > rtp , frame ) ;
}
2002-12-29 19:13:07 +00:00
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & sub - > lock ) ;
2002-12-29 19:13:07 +00:00
}
return res ;
}
2004-04-06 22:17:32 +00:00
static int mgcp_fixup ( struct ast_channel * oldchan , struct ast_channel * newchan )
2002-12-29 19:13:07 +00:00
{
2003-05-06 04:03:58 +00:00
struct mgcp_subchannel * sub = newchan - > pvt - > pvt ;
2004-11-07 21:46:09 +00:00
ast_mutex_lock ( & sub - > lock ) ;
2003-05-06 04:03:58 +00:00
ast_log ( LOG_NOTICE , " mgcp_fixup(%s, %s) \n " , oldchan - > name , newchan - > name ) ;
if ( sub - > owner ! = oldchan ) {
2004-11-07 21:46:09 +00:00
ast_mutex_unlock ( & sub - > lock ) ;
2003-05-06 04:03:58 +00:00
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 ;
2004-11-07 21:46:09 +00:00
ast_mutex_unlock ( & sub - > lock ) ;
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 ;
2004-08-12 20:26:40 +00:00
char tmp [ 4 ] ;
tmp [ 0 ] = ' D ' ;
tmp [ 1 ] = ' / ' ;
tmp [ 2 ] = digit ;
tmp [ 3 ] = ' \0 ' ;
2004-11-07 21:46:09 +00:00
ast_mutex_lock ( & sub - > lock ) ;
2003-05-06 04:03:58 +00:00
transmit_notify_request ( sub , tmp ) ;
2004-11-07 21:46:09 +00:00
ast_mutex_unlock ( & sub - > lock ) ;
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 ;
2004-11-07 21:46:09 +00:00
int res = 0 ;
2003-05-06 04:03:58 +00:00
if ( mgcpdebug ) {
ast_verbose ( VERBOSE_PREFIX_3 " MGCP asked to indicate %d '%s' condition on channel %s \n " , ind , control2str ( ind ) , ast - > name ) ;
}
2004-11-07 21:46:09 +00:00
ast_mutex_lock ( & sub - > lock ) ;
2002-12-29 19:13:07 +00:00
switch ( ind ) {
case AST_CONTROL_RINGING :
2004-07-25 01:20:16 +00:00
# ifdef DLINK_BUGGY_FIRMWARE
transmit_notify_request ( sub , " rt " ) ;
# else
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " G/rt " ) ;
2004-07-25 01:20:16 +00:00
# endif
2002-12-29 19:13:07 +00:00
break ;
case AST_CONTROL_BUSY :
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/bz " ) ;
2002-12-29 19:13:07 +00:00
break ;
case AST_CONTROL_CONGESTION :
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " G/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 ) ;
2004-11-07 21:46:09 +00:00
res = - 1 ;
2002-12-29 19:13:07 +00:00
}
2004-11-07 21:46:09 +00:00
ast_mutex_unlock ( & sub - > lock ) ;
return res ;
2002-12-29 19:13:07 +00:00
}
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 ;
2004-07-26 19:33:36 +00:00
if ( i - > dtmfmode & MGCP_DTMF_INBAND ) {
2003-05-06 04:03:58 +00:00
i - > dsp = ast_dsp_new ( ) ;
ast_dsp_set_features ( i - > dsp , DSP_FEATURE_DTMF_DETECT ) ;
2004-03-19 22:57:08 +00:00
/* SC: this is to prevent clipping of dtmf tones during dsp processing */
ast_dsp_digitmode ( i - > dsp , DSP_DIGITMODE_NOQUELCH ) ;
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 ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & usecnt_lock ) ;
2002-12-29 19:13:07 +00:00
usecnt + + ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & usecnt_lock ) ;
2002-12-29 19:13:07 +00:00
ast_update_use_count ( ) ;
2003-05-06 04:03:58 +00:00
tmp - > callgroup = i - > callgroup ;
tmp - > pickupgroup = i - > pickupgroup ;
2004-07-16 04:40:54 +00:00
strncpy ( tmp - > call_forward , i - > call_forward , sizeof ( tmp - > call_forward ) - 1 ) ;
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 ) ;
2004-10-02 00:58:31 +00:00
if ( ! ast_strlen_zero ( i - > cid_num ) )
tmp - > cid . cid_num = strdup ( i - > cid_num ) ;
if ( ! ast_strlen_zero ( i - > cid_name ) )
tmp - > cid . cid_name = strdup ( i - > cid_name ) ;
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 ;
}
}
2004-03-19 22:57:08 +00:00
/* SC: verbose level check */
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " MGCP mgcp_new(%s) created in state: %s \n " , tmp - > name , ast_state2str ( state ) ) ;
}
2003-05-06 04:03:58 +00:00
} 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 ) ;
}
2004-03-27 17:51:22 +00:00
/* SC: get comma separated value */
static char * get_csv ( char * c , int * len , char * * next )
{
char * s ;
* next = NULL , * len = 0 ;
if ( ! c ) return NULL ;
while ( * c & & ( * c < 33 | | * c = = ' , ' ) )
c + + ;
s = c ;
while ( * c & & ( * c > = 33 & & * c ! = ' , ' ) )
c + + , ( * len ) + + ;
* next = c ;
if ( * len = = 0 )
s = NULL , * next = NULL ;
return s ;
}
2004-11-07 21:46:09 +00:00
static struct mgcp_subchannel * find_subchannel_and_lock ( 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 ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2002-12-29 19:13:07 +00:00
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 + + ;
}
2003-08-13 15:25:16 +00:00
ast_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 */
2003-12-05 16:50:30 +00:00
if ( sin & & g - > dynamic & & name ) {
2003-03-09 06:00:18 +00:00
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 )
2004-06-29 12:56:46 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Registered MGCP gateway '%s' at %s port %d \n " , g - > name , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , g - > addr . sin_addr ) , ntohs ( g - > addr . sin_port ) ) ;
2003-03-09 06:00:18 +00:00
}
}
2004-03-19 22:57:08 +00:00
/* SC: not dynamic, check if the name matches */
else if ( name ) {
if ( strcasecmp ( g - > name , at ) ) {
g = g - > next ;
continue ;
}
}
/* SC: not dynamic, no name, check if the addr matches */
else if ( ! name & & sin ) {
if ( ( g - > addr . sin_addr . s_addr ! = sin - > sin_addr . s_addr ) | |
( g - > addr . sin_port ! = sin - > sin_port ) ) {
g = g - > next ;
continue ;
}
}
else {
g = g - > next ;
continue ;
}
/* SC */
2002-12-29 19:13:07 +00:00
p = g - > endpoints ;
while ( p ) {
2003-12-09 00:02:06 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Searching on %s@%s for subchannel \n " , p - > name , g - > name ) ;
2003-05-06 04:03:58 +00:00
if ( msgid ) {
2004-03-19 22:57:08 +00:00
#if 0 /* SC: new transport mech */
2003-05-06 04:03:58 +00:00
sub = p - > sub ;
do {
2003-12-09 00:02:06 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Searching on %s@%s-%d for subchannel with lastout: %d \n " , p - > name , g - > name , sub - > id , msgid ) ;
2003-05-06 04:03:58 +00:00
if ( sub - > lastout = = msgid ) {
2003-12-09 00:02:06 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Found subchannel sub%d to handle request %d sub->lastout: %d \n " , sub - > id , msgid , sub - > lastout ) ;
2003-05-06 04:03:58 +00:00
found = 1 ;
break ;
}
sub = sub - > next ;
} while ( sub ! = p - > sub ) ;
if ( found ) {
break ;
}
2004-03-19 22:57:08 +00:00
# endif
/* SC */
sub = p - > sub ;
found = 1 ;
/* SC */
break ;
2003-05-06 04:03:58 +00:00
} 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 ) {
2004-11-07 21:46:09 +00:00
ast_mutex_lock ( & sub - > lock ) ;
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 ;
}
2003-08-13 15:25:16 +00:00
ast_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 ;
2004-04-22 00:20:34 +00:00
struct ast_hostent ahp ; struct hostent * hp ;
2002-12-29 19:13:07 +00:00
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 */
2004-04-22 00:20:34 +00:00
hp = ast_gethostbyname ( host , & ahp ) ;
2002-12-29 19:13:07 +00:00
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
2004-06-29 12:56:46 +00:00
printf ( " Peer RTP is at port %s:%d \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , sin . sin_addr ) , ntohs ( sin . sin_port ) ) ;
2002-12-29 19:13:07 +00:00
# endif
2004-12-19 21:13:41 +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
2004-12-19 21:13:41 +00:00
/* Next, scan through each "a=rtpmap:" line, noting each */
/* specified RTP payload type (with corresponding MIME subtype): */
2003-03-12 06:00:18 +00:00
sdpLineNum_iterator_init ( & iterator ) ;
while ( ( a = get_sdp_iterate ( & iterator , req , " a " ) ) [ 0 ] ! = ' \0 ' ) {
2004-12-19 21:13:41 +00:00
char * mimeSubtype = strdup ( a ) ; /* ensures we have enough space */
2003-03-12 06:00:18 +00:00
if ( sscanf ( a , " rtpmap: %u %[^/]/ " , & codec , mimeSubtype ) ! = 2 ) continue ;
2004-12-19 21:13:41 +00:00
/* 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 ) ;
}
2004-12-19 21:13:41 +00:00
/* 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 ;
2004-03-19 22:57:08 +00:00
/* SC: check if we need brackets around the gw name */
if ( p - > parent - > isnamedottedip )
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 ) ;
else
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 ) ;
2002-12-29 19:13:07 +00:00
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 + + ;
2004-05-20 16:30:10 +00:00
if ( oseq > 999999999 )
oseq = 1 ;
2002-12-29 19:13:07 +00:00
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 ;
2004-05-21 06:05:20 +00:00
struct mgcp_response * mgr ;
2002-12-29 19:13:07 +00:00
respprep ( & resp , p , msg , req , msgrest ) ;
2004-05-21 06:05:20 +00:00
mgr = malloc ( sizeof ( struct mgcp_response ) + resp . len + 1 ) ;
if ( mgr ) {
/* Store MGCP response in case we have to retransmit */
memset ( mgr , 0 , sizeof ( struct mgcp_response ) ) ;
sscanf ( req - > identifier , " %d " , & mgr - > seqno ) ;
time ( & mgr - > whensent ) ;
mgr - > len = resp . len ;
memcpy ( mgr - > buf , resp . data , resp . len ) ;
mgr - > buf [ resp . len ] = ' \0 ' ;
mgr - > next = p - > parent - > responses ;
2004-05-24 15:07:08 +00:00
p - > parent - > responses = mgr ;
2004-05-21 06:05:20 +00:00
}
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 ] ;
2004-07-16 04:40:54 +00:00
char m [ 256 ] = " " ;
2002-12-29 19:13:07 +00:00
char a [ 1024 ] = " " ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2002-12-29 19:13:07 +00:00
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
2004-04-22 00:20:34 +00:00
peer doesn ' t have to ast_gethostbyname ( ) us XXX */
2002-12-29 19:13:07 +00:00
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 ) {
2004-06-29 12:56:46 +00:00
ast_verbose ( " We're at %s port %d \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , 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 " ) ;
2004-06-29 12:56:46 +00:00
snprintf ( o , sizeof ( o ) , " o=root %d %d IN IP4 %s \r \n " , getpid ( ) , getpid ( ) , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , dest . sin_addr ) ) ;
2002-12-29 19:13:07 +00:00
snprintf ( s , sizeof ( s ) , " s=session \r \n " ) ;
2004-06-29 12:56:46 +00:00
snprintf ( c , sizeof ( c ) , " c=IN IP4 %s \r \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , dest . sin_addr ) ) ;
2002-12-29 19:13:07 +00:00
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 ) ;
2004-07-16 04:40:54 +00:00
strncat ( m , costr , sizeof ( m ) - strlen ( m ) - 1 ) ;
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 ) ) ;
2004-07-16 04:40:54 +00:00
strncat ( a , costr , sizeof ( a ) - strlen ( a ) - 1 ) ;
2002-12-29 19:13:07 +00:00
}
}
}
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 ) ;
2004-07-16 04:40:54 +00:00
strncat ( m , costr , sizeof ( m ) - strlen ( m ) - 1 ) ;
2003-05-06 04:03:58 +00:00
snprintf ( costr , sizeof ( costr ) , " a=rtpmap:%d %s/8000 \r \n " , codec , ast_rtp_lookup_mime_subtype ( 0 , x ) ) ;
2004-07-16 04:40:54 +00:00
strncat ( a , costr , sizeof ( a ) - strlen ( a ) - 1 ) ;
2003-05-06 04:03:58 +00:00
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 ) ;
2004-07-16 04:40:54 +00:00
strncat ( a , costr , sizeof ( a ) - strlen ( a ) - 1 ) ;
2003-05-06 04:03:58 +00:00
}
}
2003-03-12 06:00:18 +00:00
}
2003-05-06 04:03:58 +00:00
}
2004-07-16 04:40:54 +00:00
strncat ( m , " \r \n " , sizeof ( m ) - strlen ( m ) - 1 ) ;
2002-12-29 19:13:07 +00:00
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 ;
}
2004-05-27 04:18:46 +00:00
static int transmit_modify_with_sdp ( struct mgcp_subchannel * sub , struct ast_rtp * rtp , int codecs )
2002-12-29 19:13:07 +00:00
{
struct mgcp_request resp ;
char local [ 256 ] ;
char tmp [ 80 ] ;
int x ;
2004-05-27 04:18:46 +00:00
int capability ;
2003-05-06 04:03:58 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2004-05-27 04:18:46 +00:00
capability = p - > capability ;
if ( codecs )
capability = codecs ;
2003-05-06 04:03:58 +00:00
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 ) {
2004-08-03 17:00:54 +00:00
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 ) ) ;
2004-07-16 04:40:54 +00:00
strncat ( local , tmp , sizeof ( local ) - strlen ( local ) - 1 ) ;
2002-12-29 19:13:07 +00:00
}
}
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 ] ) ;
2004-03-19 22:57:08 +00:00
/* SC: X header should not be sent. kept for compatibility */
2003-05-06 04:03:58 +00:00
add_header ( & resp , " X " , sub - > txident ) ;
add_header ( & resp , " I " , sub - > cxident ) ;
/*add_header(&resp, "S", "");*/
2004-10-12 21:51:08 +00:00
ast_rtp_offered_from_local ( sub - > rtp , 0 ) ;
2003-05-06 04:03:58 +00:00
add_sdp ( & resp , sub , rtp ) ;
2004-03-19 22:57:08 +00:00
/* SC: fill in new fields */
resp . cmd = MGCP_CMD_MDCX ;
resp . trid = oseq ;
return send_request ( p , sub , & resp , oseq ) ; /* SC */
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 ) ) ;
2004-07-16 04:40:54 +00:00
strncat ( local , tmp , sizeof ( local ) - strlen ( local ) - 1 ) ;
2002-12-29 19:13:07 +00:00
}
}
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 ] ) ;
2004-03-19 22:57:08 +00:00
/* SC: X header should not be sent. kept for compatibility */
2003-05-06 04:03:58 +00:00
add_header ( & resp , " X " , sub - > txident ) ;
/*add_header(&resp, "S", "");*/
2004-10-12 21:51:08 +00:00
ast_rtp_offered_from_local ( sub - > rtp , 1 ) ;
2003-05-06 04:03:58 +00:00
add_sdp ( & resp , sub , rtp ) ;
2004-03-19 22:57:08 +00:00
/* SC: fill in new fields */
resp . cmd = MGCP_CMD_CRCX ;
resp . trid = oseq ;
return send_request ( p , sub , & resp , oseq ) ; /* SC */
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 " ) ;
2004-03-19 22:57:08 +00:00
add_header ( & resp , " X " , p - > rqnt_ident ) ; /* SC */
2003-05-06 04:03:58 +00:00
switch ( p - > hookstate ) {
case MGCP_ONHOOK :
2004-04-26 05:18:55 +00:00
add_header ( & resp , " R " , " L/hd(N) " ) ;
2003-05-06 04:03:58 +00:00
break ;
case MGCP_OFFHOOK :
2004-09-24 19:21:24 +00:00
add_header ( & resp , " R " , ( sub - > rtp & & ( p - > dtmfmode & MGCP_DTMF_INBAND ) ) ? " L/hu(N),L/hf(N) " : " L/hu(N),L/hf(N),D/[0-9#*](N) " ) ;
2003-05-06 04:03:58 +00:00
break ;
}
if ( strlen ( tone ) ) {
add_header ( & resp , " S " , tone ) ;
}
2004-03-19 22:57:08 +00:00
/* SC: fill in new fields */
resp . cmd = MGCP_CMD_RQNT ;
resp . trid = oseq ;
return send_request ( p , NULL , & resp , oseq ) ; /* SC */
2002-12-29 19:13:07 +00:00
}
2004-10-02 00:58:31 +00:00
static int transmit_notify_request_with_callerid ( struct mgcp_subchannel * sub , char * tone , char * callernum , char * callername )
2002-12-29 19:13:07 +00:00
{
struct mgcp_request resp ;
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 ) ;
2004-10-02 00:58:31 +00:00
n = callername ;
l = callernum ;
2002-12-29 19:13:07 +00:00
if ( ! n )
2004-03-19 22:57:08 +00:00
n = " " ;
2002-12-29 19:13:07 +00:00
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 " ) ;
2004-03-19 22:57:08 +00:00
add_header ( & resp , " X " , p - > rqnt_ident ) ; /* SC */
2003-05-06 04:03:58 +00:00
switch ( p - > hookstate ) {
case MGCP_ONHOOK :
add_header ( & resp , " R " , " L/hd(N) " ) ;
break ;
case MGCP_OFFHOOK :
2004-09-24 19:21:24 +00:00
add_header ( & resp , " R " , ( sub - > rtp & & ( p - > dtmfmode & MGCP_DTMF_INBAND ) ) ? " L/hu(N),L/hf(N) " : " L/hu(N),L/hf(N),D/[0-9#*](N) " ) ;
2003-05-06 04:03:58 +00:00
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 ] ) ;
}
2004-03-19 22:57:08 +00:00
/* SC: fill in new fields */
resp . cmd = MGCP_CMD_RQNT ;
resp . trid = oseq ;
return send_request ( p , NULL , & resp , oseq ) ; /* SC */
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 ] ) ;
2004-03-19 22:57:08 +00:00
/* SC: X header should not be sent. kept for compatibility */
2003-05-06 04:03:58 +00:00
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 :
2004-09-24 19:21:24 +00:00
add_header ( & resp , " R " , ( sub - > rtp & & ( p - > dtmfmode & MGCP_DTMF_INBAND ) ) ? " L/hu(N), L/hf(N) " : " L/hu(N),L/hf(N),D/[0-9#*](N) " ) ;
2003-05-06 04:03:58 +00:00
break ;
}
2004-03-19 22:57:08 +00:00
/* SC: fill in new fields */
resp . cmd = MGCP_CMD_MDCX ;
resp . trid = oseq ;
return send_request ( p , sub , & resp , oseq ) ; /* SC */
2003-05-06 04:03:58 +00:00
}
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 " ) ;
2004-03-19 22:57:08 +00:00
/* SC: removed unknown param VS */
2004-12-19 21:13:41 +00:00
/*add_header(&resp, "F", "A,R,D,S,X,N,I,T,O,ES,E,MD,M"); */
2004-04-26 05:18:55 +00:00
add_header ( & resp , " F " , " A " ) ;
2004-03-19 22:57:08 +00:00
/* SC: fill in new fields */
resp . cmd = MGCP_CMD_AUEP ;
resp . trid = oseq ;
return send_request ( p , NULL , & resp , oseq ) ; /* SC */
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 " ) ;
2004-03-19 22:57:08 +00:00
/* SC: check if call id is avail */
if ( sub - > callid [ 0 ] )
add_header ( & resp , " C " , sub - > callid ) ;
/* SC: X header should not be sent. kept for compatibility */
2003-05-06 04:03:58 +00:00
add_header ( & resp , " X " , sub - > txident ) ;
2004-03-19 22:57:08 +00:00
/* SC: check if cxident is avail */
if ( sub - > cxident [ 0 ] )
add_header ( & resp , " I " , sub - > cxident ) ;
/* SC: fill in new fields */
resp . cmd = MGCP_CMD_DLCX ;
resp . trid = oseq ;
return send_request ( p , sub , & resp , oseq ) ; /* SC */
2002-12-29 19:13:07 +00:00
}
2004-03-27 17:51:22 +00:00
static int transmit_connection_del_w_params ( struct mgcp_endpoint * p , char * callid , char * cxident )
{
struct mgcp_request resp ;
if ( mgcpdebug ) {
ast_verbose ( VERBOSE_PREFIX_3 " Delete connection %s %s@%s on callid: %s \n " ,
cxident ? cxident : " " , p - > name , p - > parent - > name , callid ? callid : " " ) ;
}
reqprep ( & resp , p , " DLCX " ) ;
/* SC: check if call id is avail */
if ( callid & & * callid )
add_header ( & resp , " C " , callid ) ;
/* SC: check if cxident is avail */
if ( cxident & & * cxident )
add_header ( & resp , " I " , cxident ) ;
/* SC: fill in new fields */
resp . cmd = MGCP_CMD_DLCX ;
resp . trid = oseq ;
return send_request ( p , p - > sub , & resp , oseq ) ;
}
2004-03-19 22:57:08 +00:00
/* SC: cleanup pendng commands */
static void dump_cmd_queues ( struct mgcp_endpoint * p , struct mgcp_subchannel * sub )
2002-12-29 19:13:07 +00:00
{
2004-03-19 22:57:08 +00:00
struct mgcp_request * t , * q ;
if ( p ) {
ast_mutex_lock ( & p - > rqnt_queue_lock ) ;
for ( q = p - > rqnt_queue ; q ; t = q - > next , free ( q ) , q = t ) ;
p - > rqnt_queue = NULL ;
ast_mutex_unlock ( & p - > rqnt_queue_lock ) ;
ast_mutex_lock ( & p - > cmd_queue_lock ) ;
for ( q = p - > cmd_queue ; q ; t = q - > next , free ( q ) , q = t ) ;
p - > cmd_queue = NULL ;
ast_mutex_unlock ( & p - > cmd_queue_lock ) ;
ast_mutex_lock ( & p - > sub - > cx_queue_lock ) ;
for ( q = p - > sub - > cx_queue ; q ; t = q - > next , free ( q ) , q = t ) ;
p - > sub - > cx_queue = NULL ;
ast_mutex_unlock ( & p - > sub - > cx_queue_lock ) ;
ast_mutex_lock ( & p - > sub - > next - > cx_queue_lock ) ;
for ( q = p - > sub - > next - > cx_queue ; q ; t = q - > next , free ( q ) , q = t ) ;
p - > sub - > next - > cx_queue = NULL ;
ast_mutex_unlock ( & p - > sub - > next - > cx_queue_lock ) ;
}
else if ( sub ) {
ast_mutex_lock ( & sub - > cx_queue_lock ) ;
for ( q = sub - > cx_queue ; q ; t = q - > next , free ( q ) , q = t ) ;
sub - > cx_queue = NULL ;
ast_mutex_unlock ( & sub - > cx_queue_lock ) ;
}
}
/* SC: remove command transaction from queue */
static struct mgcp_request * find_command ( struct mgcp_endpoint * p , struct mgcp_subchannel * sub ,
struct mgcp_request * * queue , ast_mutex_t * l , int ident )
{
struct mgcp_request * prev , * req ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2004-03-19 22:57:08 +00:00
ast_mutex_lock ( l ) ;
for ( prev = NULL , req = * queue ; req ; prev = req , req = req - > next ) {
if ( req - > trid = = ident ) {
/* remove from queue */
if ( ! prev )
* queue = req - > next ;
else
prev - > next = req - > next ;
/* send next pending command */
if ( * queue ) {
if ( mgcpdebug ) {
ast_verbose ( " Posting Queued Request: \n %s to %s:%d \n " , ( * queue ) - > data ,
2004-06-29 12:56:46 +00:00
ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > parent - > addr . sin_addr ) , ntohs ( p - > parent - > addr . sin_port ) ) ;
2004-03-19 22:57:08 +00:00
}
mgcp_postrequest ( p , sub , ( * queue ) - > data , ( * queue ) - > len , ( * queue ) - > trid ) ;
}
break ;
2003-05-06 04:03:58 +00:00
}
2004-03-19 22:57:08 +00:00
}
ast_mutex_unlock ( l ) ;
return req ;
}
/* SC: modified for new transport mechanism */
static void handle_response ( struct mgcp_endpoint * p , struct mgcp_subchannel * sub ,
2004-03-27 17:51:22 +00:00
int result , unsigned int ident , struct mgcp_request * resp )
2004-03-19 22:57:08 +00:00
{
char * c ;
struct mgcp_request * req ;
struct mgcp_gateway * gw = p - > parent ;
if ( result < 200 ) {
/* provisional response */
return ;
}
2004-07-25 01:20:16 +00:00
if ( p - > slowsequence )
req = find_command ( p , sub , & p - > cmd_queue , & p - > cmd_queue_lock , ident ) ;
else if ( sub )
2004-03-19 22:57:08 +00:00
req = find_command ( p , sub , & sub - > cx_queue , & sub - > cx_queue_lock , ident ) ;
else if ( ! ( req = find_command ( p , sub , & p - > rqnt_queue , & p - > rqnt_queue_lock , ident ) ) )
req = find_command ( p , sub , & p - > cmd_queue , & p - > cmd_queue_lock , ident ) ;
if ( ! req ) {
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " No command found on [%s] for transaction %d. Ignoring... \n " ,
gw - > name , ident ) ;
}
return ;
}
if ( p & & ( result > = 400 ) & & ( result < = 599 ) ) {
2003-05-06 04:03:58 +00:00
switch ( result ) {
case 401 :
p - > hookstate = MGCP_OFFHOOK ;
break ;
case 402 :
p - > hookstate = MGCP_ONHOOK ;
break ;
2004-03-19 22:57:08 +00:00
case 406 :
ast_log ( LOG_NOTICE , " Transaction %d timed out \n " , ident ) ;
break ;
case 407 :
ast_log ( LOG_NOTICE , " Transaction %d aborted \n " , ident ) ;
break ;
2003-05-06 04:03:58 +00:00
}
2004-03-19 22:57:08 +00:00
if ( sub )
{
if ( sub - > owner ) {
ast_log ( LOG_NOTICE , " Terminating on result %d from %s@%s-%d \n " ,
result , p - > name , p - > parent - > name , sub ? sub - > id : - 1 ) ;
2004-11-14 17:23:06 +00:00
mgcp_queue_hangup ( sub ) ;
2004-03-19 22:57:08 +00:00
}
}
else {
if ( p - > sub - > next - > owner ) {
ast_log ( LOG_NOTICE , " Terminating on result %d from %s@%s-%d \n " ,
result , p - > name , p - > parent - > name , sub ? sub - > id : - 1 ) ;
2004-11-15 14:29:15 +00:00
mgcp_queue_hangup ( p - > sub ) ;
2004-03-19 22:57:08 +00:00
}
if ( p - > sub - > owner ) {
ast_log ( LOG_NOTICE , " Terminating on result %d from %s@%s-%d \n " ,
result , p - > name , p - > parent - > name , sub ? sub - > id : - 1 ) ;
2004-11-15 14:29:15 +00:00
mgcp_queue_hangup ( p - > sub ) ;
2004-03-19 22:57:08 +00:00
}
dump_cmd_queues ( p , NULL ) ;
}
}
if ( resp ) {
if ( req - > cmd = = MGCP_CMD_CRCX ) {
if ( ( c = get_header ( resp , " I " ) ) ) {
2004-07-26 19:33:36 +00:00
if ( strlen ( c ) & & sub ) {
2004-03-19 22:57:08 +00:00
/* SC: if we are hanging up do not process this conn. */
if ( sub - > owner ) {
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 ) {
2004-05-27 04:18:46 +00:00
transmit_modify_with_sdp ( sub , NULL , 0 ) ;
2004-03-19 22:57:08 +00:00
}
}
else {
/* XXX SC: delete this one
callid and conn id may already be lost .
so the following del conn may have a side effect of
cleaning up the next subchannel */
transmit_connection_del ( sub ) ;
}
}
}
}
if ( req - > cmd = = MGCP_CMD_AUEP ) {
2004-03-27 17:51:22 +00:00
/* SC: check stale connection ids */
if ( ( c = get_header ( resp , " I " ) ) ) {
char * v , * n ;
int len ;
while ( ( v = get_csv ( c , & len , & n ) ) ) {
if ( len ) {
if ( strncasecmp ( v , p - > sub - > cxident , len ) & &
strncasecmp ( v , p - > sub - > next - > cxident , len ) ) {
/* connection id not found. delete it */
char cxident [ 80 ] ;
memcpy ( cxident , v , len ) ;
cxident [ len ] = ' \0 ' ;
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " Non existing connection id %s on %s@%s \n " ,
cxident , p - > name , gw - > name ) ;
}
transmit_connection_del_w_params ( p , NULL , cxident ) ;
}
}
c = n ;
}
}
2004-03-19 22:57:08 +00:00
/* Try to determine the hookstate returned from an audit endpoint command */
if ( ( c = get_header ( resp , " ES " ) ) ) {
if ( strlen ( c ) ) {
if ( strstr ( c , " hu " ) ) {
if ( p - > hookstate ! = MGCP_ONHOOK ) {
/* SC: XXX cleanup if we think we are offhook XXX */
if ( ( p - > sub - > owner | | p - > sub - > next - > owner ) & &
p - > hookstate = = MGCP_OFFHOOK )
2004-11-14 17:23:06 +00:00
mgcp_queue_hangup ( sub ) ;
2004-03-19 22:57:08 +00:00
p - > hookstate = MGCP_ONHOOK ;
/* SC: update the requested events according to the new hookstate */
transmit_notify_request ( p - > sub , " " ) ;
/* SC: verbose level check */
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " Setting hookstate of %s@%s to ONHOOK \n " , p - > name , gw - > name ) ;
}
}
} else if ( strstr ( c , " hd " ) ) {
if ( p - > hookstate ! = MGCP_OFFHOOK ) {
p - > hookstate = MGCP_OFFHOOK ;
/* SC: update the requested events according to the new hookstate */
transmit_notify_request ( p - > sub , " " ) ;
/* SC: verbose level check */
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " Setting hookstate of %s@%s to OFFHOOK \n " , p - > name , gw - > name ) ;
}
}
}
}
2004-03-27 17:51:22 +00:00
}
2004-03-19 22:57:08 +00:00
}
if ( resp & & resp - > lines ) {
/* SC: do not process sdp if we are hanging up. this may be a late response */
if ( sub & & sub - > owner ) {
if ( ! sub - > rtp )
start_rtp ( sub ) ;
if ( sub - > rtp )
process_sdp ( sub , resp ) ;
}
}
}
free ( req ) ;
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-08-13 15:25:16 +00:00
ast_mutex_lock ( & sub - > lock ) ;
2004-03-19 22:57:08 +00:00
/* SC: check again to be on the safe side */
if ( sub - > rtp ) {
ast_rtp_destroy ( sub - > rtp ) ;
sub - > rtp = NULL ;
}
2002-12-29 19:13:07 +00:00
/* Allocate the RTP now */
2004-10-06 15:52:01 +00:00
sub - > rtp = ast_rtp_new_with_bindaddr ( sched , io , 1 , 0 , bindaddr . sin_addr ) ;
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 ) ;
2003-08-13 15:25:16 +00:00
ast_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);*/
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/dl " ) ;
2003-05-06 04:03:58 +00:00
}
2004-10-02 00:58:31 +00:00
if ( ast_exists_extension ( chan , chan - > context , exten , 1 , p - > cid_num ) ) {
if ( ! res | | ! ast_matchmore_extension ( chan , chan - > context , exten , 1 , p - > cid_num ) ) {
2003-05-06 04:03:58 +00:00
if ( getforward ) {
/* Record this as the forwarding extension */
2004-07-16 04:40:54 +00:00
strncpy ( p - > call_forward , exten , sizeof ( p - > call_forward ) - 1 ) ;
2003-05-06 04:03:58 +00:00
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);*/
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/sl " ) ;
2003-05-06 04:03:58 +00:00
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);*/
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/dl " ) ;
2003-05-06 04:03:58 +00:00
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 ) ;
2004-10-02 00:58:31 +00:00
if ( ! ast_strlen_zero ( p - > cid_num ) ) {
2004-03-19 22:57:08 +00:00
if ( ! p - > hidecallerid ) {
/* SC: free existing chan->callerid */
2004-10-02 00:58:31 +00:00
if ( chan - > cid . cid_num )
free ( chan - > cid . cid_num ) ;
chan - > cid . cid_num = strdup ( p - > cid_num ) ;
/* SC: free existing chan->callerid */
if ( chan - > cid . cid_name )
free ( chan - > cid . cid_name ) ;
chan - > cid . cid_name = strdup ( p - > cid_name ) ;
2004-03-19 22:57:08 +00:00
}
2004-10-02 00:58:31 +00:00
if ( chan - > cid . cid_ani )
free ( chan - > cid . cid_ani ) ;
chan - > cid . cid_ani = strdup ( p - > cid_num ) ;
2003-05-06 04:03:58 +00:00
}
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);*/
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " G/cg " ) ;
2003-05-06 04:03:58 +00:00
}
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);*/
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " G/cg " ) ;
2003-05-06 04:03:58 +00:00
/*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);*/
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/sl " ) ;
2003-05-06 04:03:58 +00:00
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);*/
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " G/cg " ) ;
2003-05-06 04:03:58 +00:00
}
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 ;
2004-10-02 00:58:31 +00:00
if ( chan - > cid . cid_num )
free ( chan - > cid . cid_num ) ;
chan - > cid . cid_num = NULL ;
if ( chan - > cid . cid_name )
free ( chan - > cid . cid_name ) ;
chan - > cid . cid_name = NULL ;
2003-05-06 04:03:58 +00:00
/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/sl " ) ;
2003-05-06 04:03:58 +00:00
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);*/
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/sl " ) ;
2003-05-06 04:03:58 +00:00
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);*/
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/sl " ) ;
2003-05-06 04:03:58 +00:00
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);*/
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/sl " ) ;
2003-05-06 04:03:58 +00:00
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);*/
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/sl " ) ;
2003-05-06 04:03:58 +00:00
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);*/
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/sl " ) ;
2003-05-06 04:03:58 +00:00
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 & &
2004-10-23 12:19:47 +00:00
ast_bridged_channel ( sub - > next - > owner ) ) {
2003-05-06 04:03:58 +00:00
/* This is a three way call, the main call being a real channel,
and we ' re parking the first call . */
2004-10-23 12:19:47 +00:00
ast_masq_park_call ( ast_bridged_channel ( sub - > next - > owner ) , chan , 0 , NULL ) ;
2003-05-06 04:03:58 +00:00
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " Parking call to '%s' \n " , chan - > name ) ;
}
break ;
2004-09-13 21:34:47 +00:00
} else if ( strlen ( p - > lastcallerid ) & & ! strcmp ( exten , " *60 " ) ) {
2003-05-06 04:03:58 +00:00
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);*/
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/sl " ) ;
2003-05-06 04:03:58 +00:00
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 ;
2004-10-02 00:58:31 +00:00
if ( chan - > cid . cid_num )
free ( chan - > cid . cid_num ) ;
if ( ! ast_strlen_zero ( p - > cid_num ) )
chan - > cid . cid_num = strdup ( p - > cid_num ) ;
if ( chan - > cid . cid_name )
free ( chan - > cid . cid_name ) ;
if ( ! ast_strlen_zero ( p - > cid_name ) )
chan - > cid . cid_name = strdup ( p - > cid_name ) ;
2003-05-06 04:03:58 +00:00
/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/sl " ) ;
2003-05-06 04:03:58 +00:00
len = 0 ;
memset ( exten , 0 , sizeof ( exten ) ) ;
timeout = firstdigittimeout ;
2004-10-02 00:58:31 +00:00
} else if ( ! ast_canmatch_extension ( chan , chan - > context , exten , 1 , chan - > cid . cid_num ) & &
2003-05-06 04:03:58 +00:00
( ( exten [ 0 ] ! = ' * ' ) | | ( strlen ( exten ) > 2 ) ) ) {
if ( option_debug )
2004-10-02 00:58:31 +00:00
ast_log ( LOG_DEBUG , " Can't match %s from '%s' in context %s \n " , exten , chan - > cid . cid_num ? chan - > cid . cid_num : " <Unknown Caller> " , chan - > context ) ;
2003-05-06 04:03:58 +00:00
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 ? ) */
2004-10-23 12:19:47 +00:00
if ( ast_bridged_channel ( p - > sub - > owner ) ) {
2003-05-06 04:03:58 +00:00
/* The three-way person we're about to transfer to could still be in MOH, so
stop if now if appropriate */
2004-10-23 12:19:47 +00:00
if ( ast_bridged_channel ( p - > sub - > next - > owner ) )
ast_moh_stop ( ast_bridged_channel ( p - > sub - > next - > owner ) ) ;
2003-05-06 04:03:58 +00:00
if ( p - > sub - > owner - > _state = = AST_STATE_RINGING ) {
2004-10-23 12:19:47 +00:00
ast_indicate ( ast_bridged_channel ( p - > sub - > next - > owner ) , AST_CONTROL_RINGING ) ;
2003-05-06 04:03:58 +00:00
}
2004-10-23 12:19:47 +00:00
if ( ast_channel_masquerade ( p - > sub - > next - > owner , ast_bridged_channel ( p - > sub - > owner ) ) ) {
2003-05-06 04:03:58 +00:00
ast_log ( LOG_WARNING , " Unable to masquerade %s as %s \n " ,
2004-10-23 12:19:47 +00:00
ast_bridged_channel ( p - > sub - > owner ) - > name , p - > sub - > next - > owner - > name ) ;
2003-05-06 04:03:58 +00:00
return - 1 ;
}
/* Orphan the channel */
unalloc_sub ( p - > sub - > next ) ;
2004-10-23 12:19:47 +00:00
} else if ( ast_bridged_channel ( p - > sub - > next - > owner ) ) {
2003-05-06 04:03:58 +00:00
if ( p - > sub - > owner - > _state = = AST_STATE_RINGING ) {
2004-10-23 12:19:47 +00:00
ast_indicate ( ast_bridged_channel ( p - > sub - > next - > owner ) , AST_CONTROL_RINGING ) ;
2003-05-06 04:03:58 +00:00
}
2004-10-23 12:19:47 +00:00
ast_moh_stop ( ast_bridged_channel ( p - > sub - > next - > owner ) ) ;
if ( ast_channel_masquerade ( p - > sub - > owner , ast_bridged_channel ( p - > sub - > next - > owner ) ) ) {
2003-05-06 04:03:58 +00:00
ast_log ( LOG_WARNING , " Unable to masquerade %s as %s \n " ,
2004-10-23 12:19:47 +00:00
ast_bridged_channel ( p - > sub - > next - > owner ) - > name , p - > sub - > owner - > name ) ;
2003-05-06 04:03:58 +00:00
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 ;
2004-11-07 21:46:09 +00:00
mgcp_queue_hangup ( p - > sub - > next ) ;
2003-05-06 04:03:58 +00:00
}
}
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 ;
2004-02-02 00:46:59 +00:00
pthread_attr_t attr ;
pthread_attr_init ( & attr ) ;
pthread_attr_setdetachstate ( & attr , PTHREAD_CREATE_DETACHED ) ;
2003-05-06 04:03:58 +00:00
/* Off hook / answer */
if ( sub - > outgoing ) {
/* Answered */
if ( sub - > owner ) {
2004-10-23 12:19:47 +00:00
if ( ast_bridged_channel ( sub - > owner ) ) {
ast_moh_stop ( ast_bridged_channel ( sub - > owner ) ) ;
2003-05-06 04:03:58 +00:00
}
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 , " " ) ;
2004-11-07 21:46:09 +00:00
mgcp_queue_control ( sub , AST_CONTROL_ANSWER ) ;
2003-05-06 04:03:58 +00:00
}
} 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 */
2004-07-25 01:20:16 +00:00
# ifdef DLINK_BUGGY_FIRMWARE
transmit_notify_request ( sub , " rt " ) ;
# else
transmit_notify_request ( sub , " G/rt " ) ;
# endif
2003-05-06 04:03:58 +00:00
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 ) ;
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " G/cg " ) ;
2003-05-06 04:03:58 +00:00
ast_hangup ( c ) ;
}
} else {
if ( has_voicemail ( p ) ) {
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/sl " ) ;
2003-05-06 04:03:58 +00:00
} else {
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/dl " ) ;
2003-05-06 04:03:58 +00:00
}
c = mgcp_new ( sub , AST_STATE_DOWN ) ;
if ( c ) {
2004-08-08 17:15:02 +00:00
if ( ast_pthread_create ( & t , & attr , mgcp_ss , c ) ) {
2003-05-06 04:03:58 +00:00
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 ) {
2004-08-03 06:31:20 +00:00
ast_log ( LOG_WARNING , " Off hook, but already have owner on %s@%s \n " , p - > name , p - > parent - > name ) ;
2003-05-06 04:03:58 +00:00
} else {
2004-08-03 06:31:20 +00:00
ast_log ( LOG_WARNING , " On hook, but already have owner on %s@%s \n " , p - > name , p - > parent - > name ) ;
2003-05-06 04:03:58 +00:00
ast_log ( LOG_WARNING , " If we're onhook why are we here trying to handle a hd or hf? " ) ;
}
2004-10-23 12:19:47 +00:00
if ( ast_bridged_channel ( sub - > owner ) ) {
ast_moh_stop ( ast_bridged_channel ( sub - > owner ) ) ;
2003-05-06 04:03:58 +00:00
}
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 , " " ) ;
2004-04-06 22:17:32 +00:00
/*ast_queue_control(sub->owner, AST_CONTROL_ANSWER);*/
2003-05-06 04:03:58 +00:00
}
}
}
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 ;
2004-04-26 05:18:55 +00:00
struct mgcp_gateway * g = NULL ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-05-06 04:03:58 +00:00
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 {
2004-03-19 22:57:08 +00:00
dump_queue ( p - > parent , p ) ;
dump_cmd_queues ( p , NULL ) ;
2004-04-26 05:18:55 +00:00
if ( option_verbose > 2 & & ( strcmp ( p - > name , p - > parent - > wcardep ) ! = 0 ) ) {
ast_verbose ( VERBOSE_PREFIX_3 " Resetting interface %s@%s \n " , p - > name , p - > parent - > name ) ;
}
2004-12-19 21:13:41 +00:00
/* JS: For RSIP on wildcard we reset all endpoints */
2004-04-26 05:18:55 +00:00
if ( ! strcmp ( p - > name , p - > parent - > wcardep ) ) {
/* Reset all endpoints */
struct mgcp_endpoint * tmp_ep ;
g = p - > parent ;
tmp_ep = g - > endpoints ;
while ( tmp_ep ) {
2004-12-19 21:18:17 +00:00
/*if ((strcmp(tmp_ep->name, "*") != 0) && (strcmp(tmp_ep->name, "aaln/" "*") != 0)) { */
2004-04-26 05:18:55 +00:00
if ( strcmp ( tmp_ep - > name , g - > wcardep ) ! = 0 ) {
struct mgcp_subchannel * tmp_sub , * first_sub ;
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " Resetting interface %s@%s \n " , tmp_ep - > name , p - > parent - > name ) ;
}
first_sub = tmp_ep - > sub ;
tmp_sub = tmp_ep - > sub ;
while ( tmp_sub ) {
2004-11-14 17:23:06 +00:00
mgcp_queue_hangup ( tmp_sub ) ;
2004-04-26 05:18:55 +00:00
tmp_sub = tmp_sub - > next ;
if ( tmp_sub = = first_sub )
break ;
}
}
tmp_ep = tmp_ep - > next ;
}
} else if ( sub - > owner ) {
2004-11-14 17:23:06 +00:00
mgcp_queue_hangup ( sub ) ;
2004-04-26 05:18:55 +00:00
}
2003-06-29 14:36:21 +00:00
transmit_response ( sub , " 200 " , req , " OK " ) ;
2004-04-26 05:18:55 +00:00
/* JS: We dont send NTFY or AUEP to wildcard ep */
if ( strcmp ( p - > name , p - > parent - > wcardep ) ! = 0 ) {
transmit_notify_request ( sub , " " ) ;
/* SC: Audit endpoint.
Idea is to prevent lost lines due to race conditions
*/
transmit_audit_endpoint ( p ) ;
}
2003-06-29 14:36:21 +00:00
}
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 */
2004-08-05 21:36:33 +00:00
if ( strcasecmp ( ev , " hu " ) & & strcasecmp ( ev , " hd " ) & & strcasecmp ( ev , " ping " ) ) {
2003-05-06 04:03:58 +00:00
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 ;
}
2004-08-03 06:31:20 +00:00
/* do not let * confrnce two down channels */
if ( sub - > owner & & sub - > owner - > _state = = AST_STATE_DOWN & & ! sub - > next - > owner ) return - 1 ;
2003-08-19 15:13:54 +00:00
2003-05-06 04:03:58 +00:00
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 ) ;
2004-10-23 12:19:47 +00:00
if ( sub - > owner & & ast_bridged_channel ( sub - > owner ) ) {
ast_moh_start ( ast_bridged_channel ( sub - > owner ) , NULL ) ;
2003-05-06 04:03:58 +00:00
}
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 ;
2004-10-23 12:19:47 +00:00
if ( ast_bridged_channel ( sub - > next - > owner ) )
ast_moh_stop ( ast_bridged_channel ( sub - > next - > owner ) ) ;
2003-05-06 04:03:58 +00:00
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 ) ;
2004-10-23 12:19:47 +00:00
if ( ast_bridged_channel ( sub - > owner ) )
ast_moh_start ( ast_bridged_channel ( sub - > owner ) , NULL ) ;
if ( ast_bridged_channel ( sub - > next - > owner ) )
ast_moh_stop ( ast_bridged_channel ( sub - > next - > owner ) ) ;
2003-05-06 04:03:58 +00:00
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 ;
}
2004-10-23 12:19:47 +00:00
if ( ast_bridged_channel ( p - > sub - > owner ) ) {
ast_moh_stop ( ast_bridged_channel ( p - > sub - > owner ) ) ;
2003-05-06 04:03:58 +00:00
}
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 ) ;
2004-04-26 05:18:55 +00:00
/* JS: Do we need to send MDCX before a DLCX ?
2003-05-06 04:03:58 +00:00
if ( sub - > rtp ) {
transmit_modify_request ( sub ) ;
}
2004-04-26 05:18:55 +00:00
*/
2003-05-06 04:03:58 +00:00
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 */
2004-11-07 21:46:09 +00:00
ast_mutex_lock ( & p - > sub - > next - > lock ) ;
res = attempt_transfer ( p ) ;
if ( res < 0 ) {
2003-05-06 04:03:58 +00:00
if ( p - > sub - > next - > owner ) {
sub - > next - > alreadygone = 1 ;
2004-11-07 21:46:09 +00:00
mgcp_queue_hangup ( sub - > next ) ;
2003-05-06 04:03:58 +00:00
}
} else if ( res ) {
ast_log ( LOG_WARNING , " Transfer attempt failed \n " ) ;
2004-11-07 21:46:09 +00:00
ast_mutex_unlock ( & p - > sub - > next - > lock ) ;
2003-05-06 04:03:58 +00:00
return - 1 ;
}
2004-11-07 21:46:09 +00:00
ast_mutex_unlock ( & p - > sub - > next - > lock ) ;
2003-05-06 04:03:58 +00:00
} 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 ;
2004-11-07 21:46:09 +00:00
mgcp_queue_hangup ( sub ) ;
2003-05-06 04:03:58 +00:00
} else {
2004-03-19 22:57:08 +00:00
/* SC: verbose level check */
if ( option_verbose > 2 ) {
2004-12-18 23:32:42 +00:00
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " MGCP handle_request(%s@%s-%d) ast_channel already destroyed, resending DLCX. \n " ,
p - > name , p - > parent - > name , sub - > id ) ;
}
/* Instruct the other side to remove the connection since it apparently *
* still thinks the channel is active . *
* For Cisco IAD2421 / BAK / */
transmit_connection_del ( sub ) ;
2004-03-19 22:57:08 +00:00
}
2003-05-06 04:03:58 +00:00
}
}
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 ) ;
}
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/vmwi(+) " ) ;
2003-05-06 04:03:58 +00:00
} else {
if ( option_verbose > 2 ) {
ast_verbose ( VERBOSE_PREFIX_3 " MGCP handle_request(%s@%s) set vmwi(-) \n " , p - > name , p - > parent - > name ) ;
}
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/vmwi(-) " ) ;
2003-05-06 04:03:58 +00:00
}
}
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 */
2004-11-07 21:46:09 +00:00
mgcp_queue_frame ( sub , & f ) ;
ast_mutex_lock ( & sub - > next - > lock ) ;
2003-05-06 04:03:58 +00:00
if ( sub - > next - > owner ) {
2004-11-07 21:46:09 +00:00
mgcp_queue_frame ( sub - > next , & f ) ;
2003-05-06 04:03:58 +00:00
}
2004-11-07 21:46:09 +00:00
ast_mutex_unlock ( & sub - > next - > lock ) ;
2003-05-06 04:03:58 +00:00
}
if ( strstr ( p - > curtone , " wt " ) & & ( ev [ 0 ] = = ' A ' ) ) {
memset ( p - > curtone , 0 , sizeof ( p - > curtone ) ) ;
}
2004-07-30 18:02:18 +00:00
}
else if ( ! strcasecmp ( ev , " T " ) ) {
2002-12-29 19:13:07 +00:00
/* Digit timeout -- unimportant */
2004-07-30 18:02:18 +00:00
}
else if ( ! strcasecmp ( ev , " ping " ) ) {
/* ping -- unimportant */
2002-12-29 19:13:07 +00:00
} else {
ast_log ( LOG_NOTICE , " Received unknown event '%s' from %s@%s \n " , ev , p - > name , p - > parent - > name ) ;
}
} else {
2004-06-29 12:56:46 +00:00
ast_log ( LOG_WARNING , " Unknown verb '%s' received from %s \n " , req - > verb , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , 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 ;
}
2004-05-21 06:05:20 +00:00
static int find_and_retrans ( struct mgcp_subchannel * sub , struct mgcp_request * req )
{
int seqno = 0 ;
time_t now ;
struct mgcp_response * prev = NULL , * cur , * next , * answer = NULL ;
time ( & now ) ;
if ( sscanf ( req - > identifier , " %d " , & seqno ) ! = 1 )
seqno = 0 ;
cur = sub - > parent - > parent - > responses ;
while ( cur ) {
next = cur - > next ;
if ( now - cur - > whensent > RESPONSE_TIMEOUT ) {
/* Delete this entry */
if ( prev )
prev - > next = next ;
else
sub - > parent - > parent - > responses = next ;
free ( cur ) ;
} else {
if ( seqno = = cur - > seqno )
answer = cur ;
prev = cur ;
}
cur = next ;
}
if ( answer ) {
resend_response ( sub , answer ) ;
return 1 ;
}
return 0 ;
}
2002-12-29 19:13:07 +00:00
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
int res ;
int len ;
int result ;
int ident ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2002-12-29 19:13:07 +00:00
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 ) {
2004-10-11 03:36:43 +00:00
ast_verbose ( " MGCP read: \n %s \n from %s:%d \n " , req . data , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , 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 ) ) {
2004-06-29 12:56:46 +00:00
ast_log ( LOG_NOTICE , " Message from %s missing identifier \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , sin . sin_addr ) ) ;
2002-12-29 19:13:07 +00:00
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 */
2004-11-07 21:46:09 +00:00
sub = find_subchannel_and_lock ( NULL , ident , & sin ) ;
2003-05-06 04:03:58 +00:00
if ( sub ) {
2004-03-19 22:57:08 +00:00
struct mgcp_gateway * gw = sub - > parent - > parent ;
struct mgcp_message * cur , * prev ;
2004-11-07 21:46:09 +00:00
ast_mutex_unlock ( & sub - > lock ) ;
2004-03-19 22:57:08 +00:00
ast_mutex_lock ( & gw - > msgs_lock ) ;
for ( prev = NULL , cur = gw - > msgs ; cur ; prev = cur , cur = cur - > next ) {
if ( cur - > seqno = = ident ) {
2004-05-21 06:05:20 +00:00
ast_log ( LOG_DEBUG , " Got response back on transaction %d \n " , ident ) ;
2004-03-19 22:57:08 +00:00
if ( prev )
prev - > next = cur - > next ;
else
gw - > msgs = cur - > next ;
break ;
2003-05-06 04:03:58 +00:00
}
}
2004-03-19 22:57:08 +00:00
/* stop retrans timer if the queue is empty */
if ( ! gw - > msgs & & ( gw - > retransid ! = - 1 ) ) {
ast_sched_del ( sched , gw - > retransid ) ;
gw - > retransid = - 1 ;
}
2003-05-06 04:03:58 +00:00
2004-03-19 22:57:08 +00:00
ast_mutex_unlock ( & gw - > msgs_lock ) ;
if ( cur ) {
handle_response ( cur - > owner_ep , cur - > owner_sub , result , ident , & req ) ;
free ( cur ) ;
return 1 ;
}
2003-05-06 04:03:58 +00:00
2004-03-19 22:57:08 +00:00
ast_log ( LOG_NOTICE , " Got response back on [%s] for transaction %d we aren't sending? \n " ,
gw - > name , ident ) ;
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 */
2004-11-07 21:46:09 +00:00
sub = find_subchannel_and_lock ( req . endpoint , 0 , & sin ) ;
2003-05-06 04:03:58 +00:00
if ( sub ) {
2004-05-21 06:05:20 +00:00
/* look first to find a matching response in the queue */
if ( ! find_and_retrans ( sub , & req ) )
/* pass the request off to the currently mastering subchannel */
handle_request ( sub , & req , & sin ) ;
2004-11-07 21:46:09 +00:00
ast_mutex_unlock ( & sub - > lock ) ;
2002-12-29 19:13:07 +00:00
}
}
return 1 ;
}
2004-04-27 21:18:02 +00:00
static int * mgcpsock_read_id = NULL ;
2002-12-29 19:13:07 +00:00
static void * do_monitor ( void * data )
{
int res ;
2004-03-19 22:57:08 +00:00
int reloading ;
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
/* Add an I/O event to our UDP socket */
if ( mgcpsock > - 1 )
2004-04-27 21:18:02 +00:00
mgcpsock_read_id = ast_io_add ( io , mgcpsock , mgcpsock_read , AST_IO_IN , NULL ) ;
2002-12-29 19:13:07 +00:00
/* 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 ( ; ; ) {
2004-03-19 22:57:08 +00:00
/* Check for a reload request */
ast_mutex_lock ( & mgcp_reload_lock ) ;
reloading = mgcp_reloading ;
mgcp_reloading = 0 ;
ast_mutex_unlock ( & mgcp_reload_lock ) ;
if ( reloading ) {
if ( option_verbose > 0 )
ast_verbose ( VERBOSE_PREFIX_1 " Reloading MGCP \n " ) ;
mgcp_do_reload ( ) ;
2004-07-16 21:22:55 +00:00
/* Add an I/O event to our UDP socket */
if ( mgcpsock > - 1 )
mgcpsock_read_id = ast_io_add ( io , mgcpsock , mgcpsock_read , AST_IO_IN , NULL ) ;
2004-03-19 22:57:08 +00:00
}
/* Check for interfaces needing to be killed */
2002-12-29 19:13:07 +00:00
/* 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 . */
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & monlock ) ;
2002-12-29 19:13:07 +00:00
/* Lock the network interface */
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & netlock ) ;
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 ) {
2004-04-26 05:18:55 +00:00
transmit_notify_request ( e , " L/vmwi(+) " ) ;
2003-05-06 04:03:58 +00:00
} else {
2004-04-26 05:18:55 +00:00
transmit_notify_request ( e , " L/vmwi(-) " ) ;
2003-05-06 04:03:58 +00:00
}
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 */
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & netlock ) ;
2002-12-29 19:13:07 +00:00
/* And from now on, we're okay to be killed, so release the monitor lock as well */
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & monlock ) ;
2002-12-29 19:13:07 +00:00
pthread_testcancel ( ) ;
/* Wait for sched or io */
res = ast_sched_wait ( sched ) ;
2004-03-19 22:57:08 +00:00
/* SC: copied from chan_sip.c */
if ( ( res < 0 ) | | ( res > 1000 ) )
res = 1000 ;
2002-12-29 19:13:07 +00:00
res = ast_io_wait ( io , res ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & monlock ) ;
2002-12-29 19:13:07 +00:00
if ( res > = 0 )
ast_sched_runq ( sched ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & monlock ) ;
2002-12-29 19:13:07 +00:00
}
/* Never reached */
return NULL ;
}
static int restart_monitor ( void )
{
2004-02-02 00:46:59 +00:00
pthread_attr_t attr ;
pthread_attr_init ( & attr ) ;
pthread_attr_setdetachstate ( & attr , PTHREAD_CREATE_DETACHED ) ;
2002-12-29 19:13:07 +00:00
/* If we're supposed to be stopped -- stay stopped */
2004-03-15 07:51:22 +00:00
if ( monitor_thread = = AST_PTHREADT_STOP )
2002-12-29 19:13:07 +00:00
return 0 ;
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & monlock ) ) {
2002-12-29 19:13:07 +00:00
ast_log ( LOG_WARNING , " Unable to lock monitor \n " ) ;
return - 1 ;
}
if ( monitor_thread = = pthread_self ( ) ) {
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & monlock ) ;
2002-12-29 19:13:07 +00:00
ast_log ( LOG_WARNING , " Cannot kill myself \n " ) ;
return - 1 ;
}
2004-03-15 09:14:16 +00:00
if ( monitor_thread ! = AST_PTHREADT_NULL ) {
2002-12-29 19:13:07 +00:00
/* Wake up the thread */
pthread_kill ( monitor_thread , SIGURG ) ;
} else {
/* Start a new monitor */
2004-08-08 17:15:02 +00:00
if ( ast_pthread_create ( & monitor_thread , & attr , do_monitor , NULL ) < 0 ) {
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & monlock ) ;
2002-12-29 19:13:07 +00:00
ast_log ( LOG_ERROR , " Unable to start monitor thread. \n " ) ;
return - 1 ;
}
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & monlock ) ;
2002-12-29 19:13:07 +00:00
return 0 ;
}
2004-10-26 22:25:43 +00:00
static struct ast_channel * mgcp_request ( const char * type , int format , void * data , int * cause )
2002-12-29 19:13:07 +00:00
{
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 ;
}
2004-11-07 21:46:09 +00:00
sub = find_subchannel_and_lock ( tmp , 0 , NULL ) ;
2003-05-06 04:03:58 +00:00
if ( ! sub ) {
2002-12-29 19:13:07 +00:00
ast_log ( LOG_WARNING , " Unable to find MGCP endpoint '%s' \n " , tmp ) ;
2004-10-26 22:25:43 +00:00
* cause = AST_CAUSE_UNREGISTERED ;
2002-12-29 19:13:07 +00:00
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 ) ) {
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/vmwi(+) " ) ;
2003-05-06 04:03:58 +00:00
} else {
2004-04-26 05:18:55 +00:00
transmit_notify_request ( sub , " L/vmwi(-) " ) ;
2003-05-06 04:03:58 +00:00
}
}
2004-10-26 22:25:43 +00:00
* cause = AST_CAUSE_BUSY ;
2004-11-07 21:46:09 +00:00
ast_mutex_unlock ( & sub - > lock ) ;
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 ) ;
2004-11-07 21:46:09 +00:00
ast_mutex_unlock ( & sub - > lock ) ;
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 ;
}
2004-03-19 22:57:08 +00:00
/* SC: modified for reload support */
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 ;
2004-03-19 22:57:08 +00:00
int gw_reload = 0 ;
int ep_reload = 0 ;
2003-08-19 15:13:54 +00:00
canreinvite = CANREINVITE ;
2004-03-19 22:57:08 +00:00
/* SC: locate existing gateway */
gw = gateways ;
while ( gw ) {
if ( ! strcasecmp ( cat , gw - > name ) ) {
/* gateway already exists */
gw - > delme = 0 ;
gw_reload = 1 ;
break ;
}
gw = gw - > next ;
}
if ( ! gw )
gw = malloc ( sizeof ( struct mgcp_gateway ) ) ;
2002-12-29 19:13:07 +00:00
if ( gw ) {
2004-03-19 22:57:08 +00:00
if ( ! gw_reload ) {
memset ( gw , 0 , sizeof ( struct mgcp_gateway ) ) ;
gw - > expire = - 1 ;
gw - > retransid = - 1 ; /* SC */
ast_mutex_init ( & gw - > msgs_lock ) ;
strncpy ( gw - > name , cat , sizeof ( gw - > name ) - 1 ) ;
/* SC: check if the name is numeric ip */
2004-08-01 18:26:41 +00:00
if ( ( strchr ( gw - > name , ' . ' ) ) & & inet_addr ( gw - > name ) ! = INADDR_NONE )
2004-03-19 22:57:08 +00:00
gw - > isnamedottedip = 1 ;
}
2002-12-29 19:13:07 +00:00
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 ) ) {
2004-06-22 17:42:14 +00:00
if ( ! gw_reload ) {
ast_mutex_destroy ( & gw - > msgs_lock ) ;
2004-03-19 22:57:08 +00:00
free ( gw ) ;
2004-06-22 17:42:14 +00:00
}
2003-03-09 06:00:18 +00:00
return NULL ;
}
}
} else if ( ! strcasecmp ( v - > name , " defaultip " ) ) {
if ( ast_get_ip ( & gw - > defaddr , v - > value ) ) {
2004-06-22 17:42:14 +00:00
if ( ! gw_reload ) {
ast_mutex_destroy ( & gw - > msgs_lock ) ;
2004-03-19 22:57:08 +00:00
free ( gw ) ;
2004-06-22 17:42:14 +00:00
}
2002-12-29 19:13:07 +00:00
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 ) ;
2004-07-26 19:33:36 +00:00
} else if ( ! strcasecmp ( v - > name , " dtmfmode " ) ) {
if ( ! strcasecmp ( v - > value , " inband " ) )
dtmfmode = MGCP_DTMF_INBAND ;
else if ( ! strcasecmp ( v - > value , " rfc2833 " ) )
dtmfmode = MGCP_DTMF_RFC2833 ;
else if ( ! strcasecmp ( v - > value , " none " ) )
dtmfmode = 0 ;
else
ast_log ( LOG_WARNING , " '%s' is not a valid DTMF mode at line %d \n " , v - > value , v - > lineno ) ;
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 " ) ) {
2004-10-02 00:58:31 +00:00
if ( ! strcasecmp ( v - > value , " asreceived " ) ) {
cid_num [ 0 ] = ' \0 ' ;
cid_name [ 0 ] = ' \0 ' ;
} else {
ast_callerid_split ( v - > value , cid_name , sizeof ( cid_name ) , cid_num , sizeof ( cid_num ) ) ;
}
2002-12-29 19:13:07 +00:00
} 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 ) ;
2004-08-02 04:32:37 +00:00
} else if ( ! strcasecmp ( v - > name , " singlepath " ) ) {
singlepath = ast_true ( v - > value ) ;
2003-08-19 15:13:54 +00:00
} else if ( ! strcasecmp ( v - > name , " canreinvite " ) ) {
canreinvite = ast_true ( v - > value ) ;
2003-05-06 04:03:58 +00:00
} 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 , " callwaiting " ) ) {
callwaiting = ast_true ( v - > value ) ;
2004-07-25 01:20:16 +00:00
} else if ( ! strcasecmp ( v - > name , " slowsequence " ) ) {
slowsequence = ast_true ( v - > value ) ;
2003-05-06 04:03:58 +00:00
} else if ( ! strcasecmp ( v - > name , " transfer " ) ) {
transfer = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " threewaycalling " ) ) {
threewaycalling = ast_true ( v - > value ) ;
2004-04-26 05:18:55 +00:00
} else if ( ! strcasecmp ( v - > name , " wcardep " ) ) {
/* SC: locate existing endpoint */
e = gw - > endpoints ;
while ( e ) {
if ( ! strcasecmp ( v - > value , e - > name ) ) {
/* endpoint already exists */
e - > delme = 0 ;
ep_reload = 1 ;
break ;
}
e = e - > next ;
}
2003-05-06 04:03:58 +00:00
2004-04-26 05:18:55 +00:00
if ( ! e ) {
2004-06-22 17:42:14 +00:00
/* Allocate wildcard endpoint */
2004-04-26 05:18:55 +00:00
e = malloc ( sizeof ( struct mgcp_endpoint ) ) ;
ep_reload = 0 ;
}
if ( e ) {
if ( ! ep_reload ) {
memset ( e , 0 , sizeof ( struct mgcp_endpoint ) ) ;
2004-06-22 17:42:14 +00:00
ast_mutex_init ( & e - > lock ) ;
ast_mutex_init ( & e - > rqnt_queue_lock ) ;
ast_mutex_init ( & e - > cmd_queue_lock ) ;
2004-04-26 05:18:55 +00:00
strncpy ( e - > name , v - > value , sizeof ( e - > name ) - 1 ) ;
e - > needaudit = 1 ;
}
strncpy ( gw - > wcardep , v - > value , sizeof ( gw - > wcardep ) - 1 ) ;
2004-12-19 21:18:17 +00:00
/*strncpy(e->name, "aaln/" "*", sizeof(e->name) - 1); */
2004-04-26 05:18:55 +00:00
/* XXX Should we really check for uniqueness?? XXX */
strncpy ( e - > context , context , sizeof ( e - > context ) - 1 ) ;
2004-10-02 00:58:31 +00:00
strncpy ( e - > cid_num , cid_num , sizeof ( e - > cid_num ) - 1 ) ;
strncpy ( e - > cid_name , cid_name , sizeof ( e - > cid_name ) - 1 ) ;
2004-04-26 05:18:55 +00:00
strncpy ( e - > language , language , sizeof ( e - > language ) - 1 ) ;
strncpy ( e - > musicclass , musicclass , sizeof ( e - > musicclass ) - 1 ) ;
strncpy ( e - > mailbox , mailbox , sizeof ( e - > mailbox ) - 1 ) ;
2004-08-05 21:36:33 +00:00
snprintf ( e - > rqnt_ident , sizeof ( e - > rqnt_ident ) , " %08x " , rand ( ) ) ;
2004-04-26 05:18:55 +00:00
e - > msgstate = - 1 ;
e - > capability = capability ;
e - > parent = gw ;
2004-07-26 19:33:36 +00:00
e - > dtmfmode = dtmfmode ;
2004-04-26 05:18:55 +00:00
e - > adsi = adsi ;
e - > type = TYPE_LINE ;
e - > immediate = immediate ;
e - > callgroup = cur_callergroup ;
e - > pickupgroup = cur_pickupgroup ;
e - > callreturn = callreturn ;
e - > cancallforward = cancallforward ;
2004-08-02 04:32:37 +00:00
e - > singlepath = singlepath ;
2004-04-26 05:18:55 +00:00
e - > canreinvite = canreinvite ;
e - > callwaiting = callwaiting ;
2004-07-25 01:20:16 +00:00
e - > slowsequence = slowsequence ;
2004-04-26 05:18:55 +00:00
e - > transfer = transfer ;
e - > threewaycalling = threewaycalling ;
e - > onhooktime = time ( NULL ) ;
/* ASSUME we're onhook */
e - > hookstate = MGCP_ONHOOK ;
2004-08-01 03:59:13 +00:00
if ( ! ep_reload ) {
2004-08-01 21:25:35 +00:00
/*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 ) ) ;
ast_mutex_init ( & sub - > lock ) ;
ast_mutex_init ( & sub - > cx_queue_lock ) ;
sub - > parent = e ;
sub - > id = i ;
snprintf ( sub - > txident , sizeof ( sub - > txident ) , " %08x " , rand ( ) ) ;
/*stnrcpy(sub->txident, txident, sizeof(sub->txident) - 1);*/
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 ;
}
}
2004-08-01 03:59:13 +00:00
/* 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 ;
e - > next = gw - > endpoints ;
gw - > endpoints = e ;
}
2004-04-26 05:18:55 +00:00
}
2002-12-29 19:13:07 +00:00
} else if ( ! strcasecmp ( v - > name , " trunk " ) | |
! strcasecmp ( v - > name , " line " ) ) {
2004-03-19 22:57:08 +00:00
/* SC: locate existing endpoint */
e = gw - > endpoints ;
while ( e ) {
if ( ! strcasecmp ( v - > value , e - > name ) ) {
/* endpoint already exists */
e - > delme = 0 ;
ep_reload = 1 ;
break ;
}
e = e - > next ;
}
if ( ! e ) {
e = malloc ( sizeof ( struct mgcp_endpoint ) ) ;
ep_reload = 0 ;
}
2002-12-29 19:13:07 +00:00
if ( e ) {
2004-03-19 22:57:08 +00:00
if ( ! ep_reload ) {
memset ( e , 0 , sizeof ( struct mgcp_endpoint ) ) ;
2004-06-22 17:42:14 +00:00
ast_mutex_init ( & e - > lock ) ;
ast_mutex_init ( & e - > rqnt_queue_lock ) ;
ast_mutex_init ( & e - > cmd_queue_lock ) ;
2004-03-19 22:57:08 +00:00
strncpy ( e - > name , v - > value , sizeof ( e - > name ) - 1 ) ;
e - > needaudit = 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 ) ;
2004-10-02 00:58:31 +00:00
strncpy ( e - > cid_num , cid_num , sizeof ( e - > cid_num ) - 1 ) ;
strncpy ( e - > cid_name , cid_name , sizeof ( e - > cid_name ) - 1 ) ;
2002-12-29 19:13:07 +00:00
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 ) ;
}
2004-03-19 22:57:08 +00:00
if ( ! ep_reload ) {
/* XXX SC: potential issue due to reload */
e - > msgstate = - 1 ;
e - > parent = gw ;
}
2002-12-29 19:13:07 +00:00
e - > capability = capability ;
2004-07-26 19:33:36 +00:00
e - > dtmfmode = dtmfmode ;
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 ;
2003-08-19 15:13:54 +00:00
e - > canreinvite = canreinvite ;
2004-09-17 20:08:40 +00:00
e - > singlepath = singlepath ;
2003-05-06 04:03:58 +00:00
e - > callwaiting = callwaiting ;
2004-07-25 01:20:16 +00:00
e - > slowsequence = slowsequence ;
2003-05-06 04:03:58 +00:00
e - > transfer = transfer ;
e - > threewaycalling = threewaycalling ;
2004-03-19 22:57:08 +00:00
if ( ! ep_reload ) {
e - > onhooktime = time ( NULL ) ;
/* ASSUME we're onhook */
e - > hookstate = MGCP_ONHOOK ;
snprintf ( e - > rqnt_ident , sizeof ( e - > rqnt_ident ) , " %08x " , rand ( ) ) ;
}
for ( i = 0 , sub = NULL ; i < MAX_SUBS ; i + + ) {
if ( ! ep_reload ) {
sub = malloc ( sizeof ( struct mgcp_subchannel ) ) ;
}
else {
if ( ! sub )
sub = e - > sub ;
else
sub = sub - > next ;
}
2003-05-06 04:03:58 +00:00
if ( sub ) {
2004-03-19 22:57:08 +00:00
if ( ! ep_reload ) {
ast_verbose ( VERBOSE_PREFIX_3 " Allocating subchannel '%d' on %s@%s \n " , i , e - > name , gw - > name ) ;
memset ( sub , 0 , sizeof ( struct mgcp_subchannel ) ) ;
2004-06-22 17:42:14 +00:00
ast_mutex_init ( & sub - > lock ) ;
ast_mutex_init ( & sub - > cx_queue_lock ) ;
2004-03-19 22:57:08 +00:00
strncpy ( sub - > magic , MGCP_SUBCHANNEL_MAGIC , sizeof ( sub - > magic ) - 1 ) ;
sub - > parent = e ;
sub - > id = i ;
snprintf ( sub - > txident , sizeof ( sub - > txident ) , " %08x " , rand ( ) ) ;
sub - > cxmode = MGCP_CX_INACTIVE ;
sub - > next = e - > sub ;
e - > sub = sub ;
}
2003-05-06 04:03:58 +00:00
sub - > nat = nat ;
} else {
/* XXX Should find a way to clean up our memory */
ast_log ( LOG_WARNING , " Out of memory allocating subchannel " ) ;
return NULL ;
}
}
2004-03-19 22:57:08 +00:00
if ( ! ep_reload ) {
/* 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 ;
2003-05-06 04:03:58 +00:00
2004-03-19 22:57:08 +00:00
e - > next = gw - > endpoints ;
gw - > endpoints = e ;
}
2002-12-29 19:13:07 +00:00
}
} 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 ) ;
2004-06-22 17:42:14 +00:00
if ( ! gw_reload ) {
ast_mutex_destroy ( & gw - > msgs_lock ) ;
2004-03-19 22:57:08 +00:00
free ( gw ) ;
2004-06-22 17:42:14 +00:00
}
2003-03-09 06:00:18 +00:00
return NULL ;
}
2004-11-17 19:11:33 +00:00
gw - > defaddr . sin_family = AF_INET ;
gw - > addr . sin_family = AF_INET ;
2003-03-09 06:00:18 +00:00
if ( gw - > defaddr . sin_addr . s_addr & & ! ntohs ( gw - > defaddr . sin_port ) )
2004-03-19 22:57:08 +00:00
gw - > defaddr . sin_port = htons ( DEFAULT_MGCP_GW_PORT ) ;
2003-03-09 06:00:18 +00:00
if ( gw - > addr . sin_addr . s_addr & & ! ntohs ( gw - > addr . sin_port ) )
2004-03-19 22:57:08 +00:00
gw - > addr . sin_port = htons ( DEFAULT_MGCP_GW_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 ) ) ;
2004-03-19 22:57:08 +00:00
return ( gw_reload ? NULL : gw ) ;
2002-12-29 19:13:07 +00:00
}
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 ;
2003-08-19 15:13:54 +00:00
if ( sub & & sub - > rtp & & sub - > parent - > canreinvite )
2003-05-06 04:03:58 +00:00
return sub - > rtp ;
2003-02-16 06:00:12 +00:00
return NULL ;
}
2004-05-27 04:18:46 +00:00
static int mgcp_set_rtp_peer ( struct ast_channel * chan , struct ast_rtp * rtp , struct ast_rtp * vrtp , int codecs )
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 ) {
2004-05-27 04:18:46 +00:00
transmit_modify_with_sdp ( sub , rtp , codecs ) ;
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 " ;
2004-03-19 22:57:08 +00:00
static char mgcp_reload_usage [ ] =
" Usage: mgcp reload \n "
" Reloads MGCP configuration from mgcp.conf \n " ;
2003-03-09 06:00:18 +00:00
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 } ;
2004-03-19 22:57:08 +00:00
static struct ast_cli_entry cli_mgcp_reload =
{ { " mgcp " , " reload " , NULL } , mgcp_reload , " Reload MGCP configuration " , mgcp_reload_usage } ;
2003-03-09 06:00:18 +00:00
2004-03-19 22:57:08 +00:00
static void destroy_endpoint ( struct mgcp_endpoint * e )
{
struct mgcp_subchannel * sub = e - > sub - > next , * s ;
int i ;
for ( i = 0 ; i < MAX_SUBS ; i + + ) {
ast_mutex_lock ( & sub - > lock ) ;
if ( strlen ( sub - > cxident ) ) {
transmit_connection_del ( sub ) ;
}
if ( sub - > rtp ) {
ast_rtp_destroy ( sub - > rtp ) ;
sub - > rtp = NULL ;
}
memset ( sub - > magic , 0 , sizeof ( sub - > magic ) ) ;
2004-11-14 17:23:06 +00:00
mgcp_queue_hangup ( sub ) ;
2004-03-19 22:57:08 +00:00
dump_cmd_queues ( NULL , sub ) ;
ast_mutex_unlock ( & sub - > lock ) ;
sub = sub - > next ;
}
if ( e - > dsp ) {
ast_dsp_free ( e - > dsp ) ;
}
dump_queue ( e - > parent , e ) ;
dump_cmd_queues ( e , NULL ) ;
sub = e - > sub ;
for ( i = 0 ; ( i < MAX_SUBS ) & & sub ; i + + ) {
s = sub ;
sub = sub - > next ;
2004-06-22 17:42:14 +00:00
ast_mutex_destroy ( & s - > lock ) ;
ast_mutex_destroy ( & s - > cx_queue_lock ) ;
2004-03-19 22:57:08 +00:00
free ( s ) ;
}
2004-06-22 17:42:14 +00:00
ast_mutex_destroy ( & e - > lock ) ;
ast_mutex_destroy ( & e - > rqnt_queue_lock ) ;
ast_mutex_destroy ( & e - > cmd_queue_lock ) ;
2004-03-19 22:57:08 +00:00
free ( e ) ;
}
static void destroy_gateway ( struct mgcp_gateway * g )
{
if ( g - > ha )
ast_free_ha ( g - > ha ) ;
dump_queue ( g , NULL ) ;
free ( g ) ;
}
static void prune_gateways ( void )
{
struct mgcp_gateway * g , * z , * r ;
struct mgcp_endpoint * e , * p , * t ;
ast_mutex_lock ( & gatelock ) ;
/* prune gateways */
for ( z = NULL , g = gateways ; g ; ) {
/* prune endpoints */
for ( p = NULL , e = g - > endpoints ; e ; ) {
if ( e - > delme | | g - > delme ) {
t = e ;
e = e - > next ;
if ( ! p )
g - > endpoints = e ;
else
p - > next = e ;
destroy_endpoint ( t ) ;
}
else {
p = e ;
e = e - > next ;
}
}
if ( g - > delme ) {
r = g ;
g = g - > next ;
if ( ! z )
gateways = g ;
else
z - > next = g ;
destroy_gateway ( r ) ;
}
else {
z = g ;
g = g - > next ;
}
}
ast_mutex_unlock ( & gatelock ) ;
}
static int reload_config ( void )
2002-12-29 19:13:07 +00:00
{
struct ast_config * cfg ;
struct ast_variable * v ;
struct mgcp_gateway * g ;
2003-05-06 04:03:58 +00:00
struct mgcp_endpoint * e ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2002-12-29 19:13:07 +00:00
char * cat ;
2004-04-22 00:20:34 +00:00
struct ast_hostent ahp ; struct hostent * hp ;
2002-12-29 19:13:07 +00:00
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 ) ) ;
2004-07-26 19:37:11 +00:00
dtmfmode = 0 ;
2002-12-29 19:13:07 +00:00
v = ast_variable_browse ( cfg , " general " ) ;
while ( v ) {
/* Create the interface list */
if ( ! strcasecmp ( v - > name , " bindaddr " ) ) {
2004-04-22 00:20:34 +00:00
if ( ! ( hp = ast_gethostbyname ( v - > value , & ahp ) ) ) {
2002-12-29 19:13:07 +00:00
ast_log ( LOG_WARNING , " Invalid address: %s \n " , v - > value ) ;
} else {
memcpy ( & bindaddr . sin_addr , hp - > h_addr , sizeof ( bindaddr . sin_addr ) ) ;
}
} else if ( ! strcasecmp ( v - > name , " 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 ;
2003-07-30 20:49:23 +00:00
} else if ( ! strcasecmp ( v - > name , " tos " ) ) {
if ( sscanf ( v - > value , " %i " , & format ) = = 1 )
tos = format & 0xff ;
else if ( ! strcasecmp ( v - > value , " lowdelay " ) )
tos = IPTOS_LOWDELAY ;
else if ( ! strcasecmp ( v - > value , " throughput " ) )
tos = IPTOS_THROUGHPUT ;
else if ( ! strcasecmp ( v - > value , " reliability " ) )
tos = IPTOS_RELIABILITY ;
else if ( ! strcasecmp ( v - > value , " mincost " ) )
tos = IPTOS_MINCOST ;
else if ( ! strcasecmp ( v - > value , " none " ) )
tos = 0 ;
else
ast_log ( LOG_WARNING , " Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', 'mincost', or 'none' \n " , v - > lineno ) ;
2002-12-29 19:13:07 +00:00
} 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 ;
}
2004-03-19 22:57:08 +00:00
/* SC: mark existing entries for deletion */
ast_mutex_lock ( & gatelock ) ;
g = gateways ;
while ( g ) {
g - > delme = 1 ;
e = g - > endpoints ;
while ( e ) {
e - > delme = 1 ;
e = e - > next ;
}
g = g - > next ;
}
ast_mutex_unlock ( & gatelock ) ;
2002-12-29 19:13:07 +00:00
cat = ast_category_browse ( cfg , NULL ) ;
while ( cat ) {
if ( strcasecmp ( cat , " general " ) ) {
2004-04-27 21:18:02 +00:00
ast_mutex_lock ( & gatelock ) ;
2002-12-29 19:13:07 +00:00
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 ) ;
2004-04-27 21:18:02 +00:00
}
g - > next = gateways ;
gateways = g ;
}
ast_mutex_unlock ( & gatelock ) ;
/* FS: process queue and IO */
if ( monitor_thread = = pthread_self ( ) ) {
if ( sched ) ast_sched_runq ( sched ) ;
if ( io ) ast_io_wait ( io , 10 ) ;
2002-12-29 19:13:07 +00:00
}
}
cat = ast_category_browse ( cfg , cat ) ;
}
2004-03-19 22:57:08 +00:00
2004-04-27 21:18:02 +00:00
/* SC: prune deleted entries etc. */
prune_gateways ( ) ;
2004-03-19 22:57:08 +00:00
2002-12-29 19:13:07 +00:00
if ( ntohl ( bindaddr . sin_addr . s_addr ) ) {
2003-08-02 05:46:32 +00:00
memcpy ( & __ourip , & bindaddr . sin_addr , sizeof ( __ourip ) ) ;
2002-12-29 19:13:07 +00:00
} else {
2004-04-22 00:20:34 +00:00
hp = ast_gethostbyname ( ourhost , & ahp ) ;
2002-12-29 19:13:07 +00:00
if ( ! hp ) {
ast_log ( LOG_WARNING , " Unable to get our IP address, MGCP disabled \n " ) ;
2004-03-19 22:57:08 +00:00
ast_destroy ( cfg ) ;
2002-12-29 19:13:07 +00:00
return 0 ;
}
memcpy ( & __ourip , hp - > h_addr , sizeof ( __ourip ) ) ;
}
if ( ! ntohs ( bindaddr . sin_port ) )
2004-03-19 22:57:08 +00:00
bindaddr . sin_port = ntohs ( DEFAULT_MGCP_CA_PORT ) ;
2002-12-29 19:13:07 +00:00
bindaddr . sin_family = AF_INET ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & netlock ) ;
2002-12-29 19:13:07 +00:00
if ( mgcpsock > - 1 )
close ( mgcpsock ) ;
2004-04-27 21:18:02 +00:00
if ( mgcpsock_read_id ! = NULL )
2004-04-28 04:23:14 +00:00
ast_io_remove ( io , mgcpsock_read_id ) ;
mgcpsock_read_id = NULL ;
2004-04-27 21:18:02 +00:00
2002-12-29 19:13:07 +00:00
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 " ,
2004-06-29 12:56:46 +00:00
ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , bindaddr . sin_addr ) , ntohs ( bindaddr . sin_port ) ,
2002-12-29 19:13:07 +00:00
strerror ( errno ) ) ;
close ( mgcpsock ) ;
mgcpsock = - 1 ;
2003-07-30 20:49:23 +00:00
} else {
if ( option_verbose > 1 ) {
ast_verbose ( VERBOSE_PREFIX_2 " MGCP Listening on %s:%d \n " ,
2004-06-29 12:56:46 +00:00
ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , bindaddr . sin_addr ) , ntohs ( bindaddr . sin_port ) ) ;
2003-07-30 20:49:23 +00:00
ast_verbose ( VERBOSE_PREFIX_2 " Using TOS bits %d \n " , tos ) ;
}
if ( setsockopt ( mgcpsock , IPPROTO_IP , IP_TOS , & tos , sizeof ( tos ) ) )
ast_log ( LOG_WARNING , " Unable to set TOS to %d \n " , tos ) ;
2003-05-06 04:03:58 +00:00
}
2002-12-29 19:13:07 +00:00
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & netlock ) ;
2002-12-29 19:13:07 +00:00
ast_destroy ( cfg ) ;
2004-03-19 22:57:08 +00:00
/* SC: send audit only to the new endpoints */
2003-05-06 04:03:58 +00:00
g = gateways ;
while ( g ) {
e = g - > endpoints ;
2004-03-19 22:57:08 +00:00
while ( e & & e - > needaudit ) {
e - > needaudit = 0 ;
2003-05-06 04:03:58 +00:00
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 ;
}
2004-03-19 22:57:08 +00:00
int load_module ( )
{
int res ;
sched = sched_context_create ( ) ;
if ( ! sched ) {
ast_log ( LOG_WARNING , " Unable to create schedule context \n " ) ;
return - 1 ;
}
io = io_context_create ( ) ;
if ( ! io ) {
ast_log ( LOG_WARNING , " Unable to create I/O context \n " ) ;
return - 1 ;
}
if ( ! ( res = reload_config ( ) ) ) {
/* 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 ) ;
return - 1 ;
}
mgcp_rtp . type = type ;
ast_rtp_proto_register ( & mgcp_rtp ) ;
ast_cli_register ( & cli_show_endpoints ) ;
ast_cli_register ( & cli_audit_endpoint ) ;
ast_cli_register ( & cli_debug ) ;
ast_cli_register ( & cli_no_debug ) ;
ast_cli_register ( & cli_mgcp_reload ) ;
/* And start the monitor for the first time */
restart_monitor ( ) ;
}
return res ;
}
static int mgcp_do_reload ( void )
{
reload_config ( ) ;
return 0 ;
}
static int mgcp_reload ( int fd , int argc , char * argv [ ] )
{
ast_mutex_lock ( & mgcp_reload_lock ) ;
if ( mgcp_reloading ) {
ast_verbose ( " Previous mgcp reload not yet done \n " ) ;
} else
mgcp_reloading = 1 ;
ast_mutex_unlock ( & mgcp_reload_lock ) ;
restart_monitor ( ) ;
return 0 ;
}
int reload ( void )
{
mgcp_reload ( 0 , 0 , NULL ) ;
return 0 ;
}
2002-12-29 19:13:07 +00:00
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 ) ;
2003-08-13 15:25:16 +00:00
if ( ! ast_mutex_lock ( & gatelock ) ) {
2002-12-29 19:13:07 +00:00
/* Hangup all interfaces if they have an owner */
p = iflist ;
while ( p ) {
2004-11-14 17:23:06 +00:00
mgcp_queue_hangup ( p ) ;
2002-12-29 19:13:07 +00:00
p = p - > next ;
}
iflist = NULL ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & iflock ) ;
2002-12-29 19:13:07 +00:00
} else {
ast_log ( LOG_WARNING , " Unable to lock the monitor \n " ) ;
return - 1 ;
}
2003-08-13 15:25:16 +00:00
if ( ! ast_mutex_lock ( & monlock ) ) {
2004-03-15 07:51:22 +00:00
if ( monitor_thread & & ( monitor_thread ! = AST_PTHREADT_STOP ) ) {
2002-12-29 19:13:07 +00:00
pthread_cancel ( monitor_thread ) ;
pthread_kill ( monitor_thread , SIGURG ) ;
pthread_join ( monitor_thread , NULL ) ;
}
2004-03-15 07:51:22 +00:00
monitor_thread = AST_PTHREADT_STOP ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & monlock ) ;
2002-12-29 19:13:07 +00:00
} else {
ast_log ( LOG_WARNING , " Unable to lock the monitor \n " ) ;
return - 1 ;
}
2003-08-13 15:25:16 +00:00
if ( ! ast_mutex_lock ( & iflock ) ) {
2002-12-29 19:13:07 +00:00
/* Destroy all the interfaces and free their memory */
p = iflist ;
while ( p ) {
pl = p ;
p = p - > next ;
/* Free associated memory */
2004-06-22 17:42:14 +00:00
ast_mutex_destroy ( & pl - > lock ) ;
ast_mutex_destroy ( & pl - > rqnt_queue_lock ) ;
ast_mutex_destroy ( & pl - > cmd_queue_lock ) ;
2002-12-29 19:13:07 +00:00
free ( pl ) ;
}
iflist = NULL ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & iflock ) ;
2002-12-29 19:13:07 +00:00
} else {
ast_log ( LOG_WARNING , " Unable to lock the monitor \n " ) ;
return - 1 ;
}
# endif
return - 1 ;
}
int usecount ( )
{
int res ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & usecnt_lock ) ;
2002-12-29 19:13:07 +00:00
res = usecnt ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & usecnt_lock ) ;
2002-12-29 19:13:07 +00:00
return res ;
}
char * key ( )
{
return ASTERISK_GPL_KEY ;
}
char * description ( )
{
return desc ;
}