2002-12-29 19:13:07 +00:00
/*
2005-09-14 20:46:50 +00:00
* Asterisk - - An open source telephony toolkit .
2002-12-29 19:13:07 +00:00
*
2006-02-10 20:40:00 +00:00
* Copyright ( C ) 1999 - 2006 , 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
*
2005-09-14 20:46:50 +00:00
* See http : //www.asterisk.org for more information about
* the Asterisk project . Please do not directly contact
* any of the maintainers of this project for assistance ;
* the project provides a web site , mailing lists and IRC
* channels for your use .
*
2002-12-29 19:13:07 +00:00
* This program is free software , distributed under the terms of
2005-09-14 20:46:50 +00:00
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree .
*/
2005-10-24 20:12:06 +00:00
/*! \file
2005-09-14 20:46:50 +00:00
*
2005-10-24 20:12:06 +00:00
* \ brief Implementation of Media Gateway Control Protocol
2005-12-30 21:18:06 +00:00
*
* \ author Mark Spencer < markster @ digium . com >
*
2005-11-06 15:09:47 +00:00
* \ par See also
* \ arg \ ref Config_mgcp
*
* \ ingroup channel_drivers
2002-12-29 19:13:07 +00:00
*/
2006-06-07 18:54:56 +00:00
# include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
2005-06-06 21:09:59 +00:00
# include <sys/socket.h>
# include <sys/ioctl.h>
# include <net/if.h>
# include <fcntl.h>
# include <netdb.h>
# include <sys/signal.h>
# include <signal.h>
2005-06-07 17:06:33 +00:00
# include <netinet/in.h>
2005-06-06 21:09:59 +00:00
# include <netinet/in_systm.h>
# include <netinet/ip.h>
2005-06-07 17:06:33 +00:00
# include <arpa/inet.h>
2005-06-06 21:09:59 +00:00
# include <ctype.h>
2005-04-21 06:02:45 +00:00
# include "asterisk/lock.h"
# include "asterisk/channel.h"
# include "asterisk/config.h"
# include "asterisk/module.h"
# include "asterisk/pbx.h"
# include "asterisk/sched.h"
# include "asterisk/io.h"
# include "asterisk/rtp.h"
# include "asterisk/acl.h"
# include "asterisk/callerid.h"
# include "asterisk/cli.h"
# include "asterisk/say.h"
# include "asterisk/cdr.h"
# include "asterisk/astdb.h"
# include "asterisk/features.h"
# include "asterisk/app.h"
# include "asterisk/musiconhold.h"
# include "asterisk/utils.h"
2007-04-30 16:16:26 +00:00
# include "asterisk/netsock.h"
2005-04-21 06:02:45 +00:00
# include "asterisk/causes.h"
# include "asterisk/dsp.h"
2006-01-21 05:15:56 +00:00
# include "asterisk/devicestate.h"
2006-02-01 23:05:28 +00:00
# include "asterisk/stringfields.h"
2006-06-01 16:47:28 +00:00
# include "asterisk/abstract_jb.h"
2007-04-28 21:01:44 +00:00
# include "asterisk/event.h"
2002-12-29 19:13:07 +00:00
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 .
*/
2005-01-06 08:16:43 +00:00
/* #define DLINK_BUGGY_FIRMWARE */
2004-07-25 01:20:16 +00:00
2002-12-29 19:13:07 +00:00
# define MGCPDUMPER
2005-01-06 08:16:43 +00:00
# define DEFAULT_EXPIRY 120
# define MAX_EXPIRY 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
2006-06-01 16:47:28 +00:00
/*! Global jitterbuffer configuration - by default, jb is disabled */
static struct ast_jb_conf default_jbconf =
{
. flags = 0 ,
. max_size = - 1 ,
. resync_threshold = - 1 ,
. impl = " "
} ;
static struct ast_jb_conf global_jbconf ;
2005-03-04 06:47:24 +00:00
static const char tdesc [ ] = " Media Gateway Control Protocol (MGCP) " ;
static const char config [ ] = " mgcp.conf " ;
2002-12-29 19:13:07 +00:00
2004-07-26 19:33:36 +00:00
# define MGCP_DTMF_RFC2833 (1 << 0)
2005-01-06 08:16:43 +00:00
# define MGCP_DTMF_INBAND (1 << 1)
2005-03-28 20:48:24 +00:00
# define MGCP_DTMF_HYBRID (1 << 2)
2004-07-26 19:33:36 +00:00
2006-07-19 20:44:39 +00:00
# define DEFAULT_MGCP_GW_PORT 2427 /*!< From RFC 2705 */
# define DEFAULT_MGCP_CA_PORT 2727 /*!< From RFC 2705 */
# define MGCP_MAX_PACKET 1500 /*!< Also from RFC 2543, should sub headers tho */
# 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
2006-07-19 20:44:39 +00:00
/*! MGCP rtp stream modes { */
2005-01-06 08:16:43 +00:00
# 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
2006-07-19 20:44:39 +00:00
/*! } */
2003-05-06 04:03:58 +00:00
static char * mgcp_cxmodes [ ] = {
2005-01-06 08:16:43 +00:00
" sendonly " ,
" recvonly " ,
" sendrecv " ,
" confrnce " ,
" inactive "
2003-05-06 04:03:58 +00:00
} ;
2006-07-19 20:44:39 +00:00
enum {
MGCP_CMD_EPCF ,
MGCP_CMD_CRCX ,
MGCP_CMD_MDCX ,
MGCP_CMD_DLCX ,
MGCP_CMD_RQNT ,
MGCP_CMD_NTFY ,
MGCP_CMD_AUEP ,
MGCP_CMD_AUCX ,
MGCP_CMD_RSIP
} ;
2004-03-19 22:57:08 +00:00
2003-05-06 04:03:58 +00:00
static char context [ AST_MAX_EXTENSION ] = " default " ;
static char language [ MAX_LANGUAGE ] = " " ;
2005-07-05 17:16:17 +00:00
static char musicclass [ MAX_MUSICCLASS ] = " " ;
2008-04-21 23:42:45 +00:00
static char parkinglot [ AST_MAX_CONTEXT ] ;
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 ;
2005-01-15 21:51:38 +00:00
static ast_group_t cur_callergroup = 0 ;
static ast_group_t cur_pickupgroup = 0 ;
2003-05-06 04:03:58 +00:00
2008-08-09 14:12:34 +00:00
static struct {
unsigned int tos ;
unsigned int tos_audio ;
unsigned int cos ;
unsigned int cos_audio ;
} qos = { 0 , 0 , 0 , 0 } ;
2003-07-30 20:49:23 +00:00
2003-05-06 04:03:58 +00:00
static int immediate = 0 ;
static int callwaiting = 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 ;
2006-07-19 20:44:39 +00:00
/*! This is for flashhook transfers */
2003-05-06 04:03:58 +00:00
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 ;
2005-05-25 17:18:05 +00:00
static char accountcode [ AST_MAX_ACCOUNT_CODE ] = " " ;
2003-05-06 04:03:58 +00:00
static char mailbox [ AST_MAX_EXTENSION ] ;
static int amaflags = 0 ;
static int adsi = 0 ;
2004-03-27 17:51:22 +00:00
static unsigned int oseq ;
2002-12-29 19:13:07 +00:00
2006-07-19 20:44:39 +00:00
/*! Wait up to 16 seconds for first digit (FXO logic) */
2003-05-06 04:03:58 +00:00
static int firstdigittimeout = 16000 ;
2006-07-19 20:44:39 +00:00
/*! How long to wait for following digits (FXO logic) */
2003-05-06 04:03:58 +00:00
static int gendigittimeout = 8000 ;
2006-07-19 20:44:39 +00:00
/*! How long to wait for an extra digit, if there is an ambiguous match */
2003-05-06 04:03:58 +00:00
static int matchdigittimeout = 3000 ;
2006-07-19 20:44:39 +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
2006-07-19 20:44:39 +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 ) ;
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
2005-05-08 16:44:25 +00:00
static char ourhost [ MAXHOSTNAMELEN ] ;
2002-12-29 19:13:07 +00:00
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 ;
2006-07-19 20:44:39 +00:00
/*! The private structures of the mgcp channels are linked for
! selecting outgoing channels */
2002-12-29 19:13:07 +00:00
2005-01-06 08:16:43 +00:00
# define MGCP_MAX_HEADERS 64
# define MGCP_MAX_LINES 64
2002-12-29 19:13:07 +00:00
struct mgcp_request {
int len ;
char * verb ;
char * identifier ;
char * endpoint ;
char * version ;
2006-01-21 05:15:56 +00:00
int headers ; /*!< MGCP Headers */
2002-12-29 19:13:07 +00:00
char * header [ MGCP_MAX_HEADERS ] ;
2006-01-21 05:15:56 +00:00
int lines ; /*!< SDP Content */
2002-12-29 19:13:07 +00:00
char * line [ MGCP_MAX_LINES ] ;
char data [ MGCP_MAX_PACKET ] ;
2006-07-19 20:44:39 +00:00
int cmd ; /*!< int version of verb = command */
unsigned int trid ; /*!< int version of identifier = transaction id */
struct mgcp_request * next ; /*!< next in the queue */
2002-12-29 19:13:07 +00:00
} ;
2006-01-21 05:15:56 +00:00
/*! \brief mgcp_message: MGCP message for queuing up */
2003-03-15 06:00:16 +00:00
struct mgcp_message {
2005-01-06 08:16:43 +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 ;
2005-05-15 03:21:51 +00:00
char buf [ 0 ] ;
2003-03-15 06:00:16 +00:00
} ;
2006-07-19 20:44:39 +00:00
# define RESPONSE_TIMEOUT 30 /*!< in seconds */
2004-05-21 06:05:20 +00:00
struct mgcp_response {
time_t whensent ;
int len ;
int seqno ;
struct mgcp_response * next ;
2005-05-15 03:21:51 +00:00
char buf [ 0 ] ;
2004-05-21 06:05:20 +00:00
} ;
2003-05-06 04:03:58 +00:00
# define MAX_SUBS 2
# define SUB_REAL 0
# define SUB_ALT 1
struct mgcp_subchannel {
2006-07-19 20:44:39 +00:00
/*! subchannel magic string.
2005-01-06 08:16:43 +00:00
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 .
*/
2004-03-19 22:57:08 +00:00
# define MGCP_SUBCHANNEL_MAGIC "!978!"
2005-01-06 08:16:43 +00:00
char magic [ 6 ] ;
2003-08-13 15:25:16 +00:00
ast_mutex_t lock ;
2005-01-06 08:16:43 +00:00
int id ;
struct ast_channel * owner ;
struct mgcp_endpoint * parent ;
struct ast_rtp * rtp ;
2003-05-06 04:03:58 +00:00
struct sockaddr_in tmpdest ;
2006-07-19 20:44:39 +00:00
char txident [ 80 ] ; /*! \todo FIXME txident is replaced by rqnt_ident in endpoint.
2005-01-06 08:16:43 +00:00
This should be obsoleted */
char cxident [ 80 ] ;
char callid [ 80 ] ;
int cxmode ;
2006-07-19 20:44:39 +00:00
struct mgcp_request * cx_queue ; /*!< pending CX commands */
ast_mutex_t cx_queue_lock ; /*!< CX queue lock */
2003-05-06 04:03:58 +00:00
int nat ;
2006-07-19 20:44:39 +00:00
int iseq ; /*!< Not used? RTP? */
2003-05-06 04:03:58 +00:00
int outgoing ;
int alreadygone ;
2006-07-19 20:44:39 +00:00
struct mgcp_subchannel * next ; /*!< for out circular linked list */
2003-05-06 04:03:58 +00:00
} ;
2005-01-06 08:16:43 +00:00
# define MGCP_ONHOOK 1
2003-05-06 04:03:58 +00:00
# define MGCP_OFFHOOK 2
2005-01-06 08:16:43 +00:00
# define TYPE_TRUNK 1
# define TYPE_LINE 2
2002-12-29 19:13:07 +00:00
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 ] ;
2006-01-21 05:15:56 +00:00
struct mgcp_subchannel * sub ; /*!< Pointer to our current connection, channel and stuff */
2005-05-25 17:18:05 +00:00
char accountcode [ AST_MAX_ACCOUNT_CODE ] ;
2006-01-21 05:15:56 +00:00
char exten [ AST_MAX_EXTENSION ] ; /*!< Extention where to start */
2002-12-29 19:13:07 +00:00
char context [ AST_MAX_EXTENSION ] ;
char language [ MAX_LANGUAGE ] ;
2006-01-21 05:15:56 +00:00
char cid_num [ AST_MAX_EXTENSION ] ; /*!< Caller*ID number */
char cid_name [ AST_MAX_EXTENSION ] ; /*!< Caller*ID name */
char lastcallerid [ AST_MAX_EXTENSION ] ; /*!< Last Caller*ID */
2007-06-04 22:39:10 +00:00
char dtmf_buf [ AST_MAX_EXTENSION ] ; /*!< place to collect digits be */
2006-01-21 05:15:56 +00:00
char call_forward [ AST_MAX_EXTENSION ] ; /*!< Last Caller*ID */
2005-07-05 17:16:17 +00:00
char musicclass [ MAX_MUSICCLASS ] ;
2006-01-21 05:15:56 +00:00
char curtone [ 80 ] ; /*!< Current tone */
2007-04-28 21:01:44 +00:00
char mailbox [ AST_MAX_EXTENSION ] ;
2008-04-21 23:42:45 +00:00
char parkinglot [ AST_MAX_CONTEXT ] ; /*!< Parkinglot */
2007-04-28 21:01:44 +00:00
struct ast_event_sub * mwi_event_sub ;
2005-01-15 21:51:38 +00:00
ast_group_t callgroup ;
ast_group_t pickupgroup ;
2003-05-06 04:03:58 +00:00
int callwaiting ;
2005-04-11 05:48:58 +00:00
int hascallwaiting ;
2005-01-06 08:16:43 +00:00
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 ;
2005-01-06 08:16:43 +00:00
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 ;
2006-01-21 05:15:56 +00:00
int slowsequence ; /*!< MS: Sequence the endpoint as a whole */
2002-12-29 19:13:07 +00:00
int group ;
2006-01-21 05:15:56 +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 ;
2005-01-06 08:16:43 +00:00
int onhooktime ;
2006-01-21 05:15:56 +00:00
int msgstate ; /*!< voicemail message state */
2005-01-06 08:16:43 +00:00
int immediate ;
int hookstate ;
int adsi ;
2006-07-19 20:44:39 +00:00
char rqnt_ident [ 80 ] ; /*!< request identifier */
struct mgcp_request * rqnt_queue ; /*!< pending RQNT commands */
2004-03-19 22:57:08 +00:00
ast_mutex_t rqnt_queue_lock ;
2006-07-19 20:44:39 +00:00
struct mgcp_request * cmd_queue ; /*!< pending commands other than RQNT */
2004-03-19 22:57:08 +00:00
ast_mutex_t cmd_queue_lock ;
2006-07-19 20:44:39 +00:00
int delme ; /*!< needed for reload */
int needaudit ; /*!< needed for reload */
2006-01-21 05:15:56 +00:00
struct ast_dsp * dsp ; /*!< XXX Should there be a dsp/subchannel? XXX */
2005-01-06 08:16:43 +00:00
/* owner is tracked on the subchannels, and the *sub indicates whos in charge */
2003-05-06 04:03:58 +00:00
/* struct ast_channel *owner; */
/* struct ast_rtp *rtp; */
/* struct sockaddr_in tmpdest; */
2005-01-06 08:16:43 +00:00
/* 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 ] ;
2006-07-19 20:44:39 +00:00
int isnamedottedip ; /*!< 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 ;
2006-01-21 05:15:56 +00:00
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 ;
2006-07-19 20:44:39 +00:00
/* obsolete
2005-01-06 08:16:43 +00:00
time_t lastouttime ;
int lastout ;
2004-03-19 22:57:08 +00:00
int messagepending ;
*/
2006-07-19 20:44:39 +00:00
/* Wildcard endpoint name */
2004-04-26 05:18:55 +00:00
char wcardep [ 30 ] ;
2006-07-19 20:44:39 +00:00
struct mgcp_message * msgs ; /*!< gw msg queue */
ast_mutex_t msgs_lock ; /*!< queue lock */
int retransid ; /*!< retrans timer id */
int delme ; /*!< 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 ;
2006-01-21 05:15:56 +00:00
/*! \brief gatelock: mutex for gateway/endpoint lists */
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 ) ;
2007-10-11 19:03:06 +00:00
static char * mgcp_reload ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a ) ;
2007-08-16 21:09:46 +00:00
static int reload_config ( int reload ) ;
2003-05-06 04:03:58 +00:00
2005-03-04 06:47:24 +00:00
static struct ast_channel * mgcp_request ( const char * type , int format , void * data , int * cause ) ;
static int mgcp_call ( struct ast_channel * ast , char * dest , int timeout ) ;
static int mgcp_hangup ( struct ast_channel * ast ) ;
static int mgcp_answer ( struct ast_channel * ast ) ;
static struct ast_frame * mgcp_read ( struct ast_channel * ast ) ;
static int mgcp_write ( struct ast_channel * ast , struct ast_frame * frame ) ;
2006-05-10 12:24:11 +00:00
static int mgcp_indicate ( struct ast_channel * ast , int ind , const void * data , size_t datalen ) ;
2005-03-04 06:47:24 +00:00
static int mgcp_fixup ( struct ast_channel * oldchan , struct ast_channel * newchan ) ;
2006-08-31 01:59:02 +00:00
static int mgcp_senddigit_begin ( struct ast_channel * ast , char digit ) ;
Merged revisions 51311 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged. So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio. However,
since there was no audio coming in, the DTMF_END was never generated. This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf). If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback. This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-01-19 18:06:03 +00:00
static int mgcp_senddigit_end ( struct ast_channel * ast , char digit , unsigned int duration ) ;
2006-01-21 05:15:56 +00:00
static int mgcp_devicestate ( void * data ) ;
2008-01-08 20:50:57 +00:00
static void add_header_offhook ( struct mgcp_subchannel * sub , struct mgcp_request * resp ) ;
2005-03-04 06:47:24 +00:00
static const struct ast_channel_tech mgcp_tech = {
2006-02-01 23:05:28 +00:00
. type = " MGCP " ,
2005-03-04 06:47:24 +00:00
. description = tdesc ,
. capabilities = AST_FORMAT_ULAW ,
2006-05-31 17:21:21 +00:00
. properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER ,
2005-03-04 06:47:24 +00:00
. requester = mgcp_request ,
2006-01-21 05:15:56 +00:00
. devicestate = mgcp_devicestate ,
2005-03-04 06:47:24 +00:00
. call = mgcp_call ,
. hangup = mgcp_hangup ,
. answer = mgcp_answer ,
. read = mgcp_read ,
. write = mgcp_write ,
. indicate = mgcp_indicate ,
. fixup = mgcp_fixup ,
2006-08-31 01:59:02 +00:00
. send_digit_begin = mgcp_senddigit_begin ,
. send_digit_end = mgcp_senddigit_end ,
2005-03-04 06:47:24 +00:00
. bridge = ast_rtp_bridge ,
} ;
2007-04-28 21:01:44 +00:00
static void mwi_event_cb ( const struct ast_event * event , void * userdata )
{
/* This module does not handle MWI in an event-based manner. However, it
* subscribes to MWI for each mailbox that is configured so that the core
* knows that we care about it . Then , chan_mgcp will get the MWI from the
* event cache instead of checking the mailbox directly . */
}
2003-05-06 04:03:58 +00:00
static int has_voicemail ( struct mgcp_endpoint * p )
{
2007-04-28 21:01:44 +00:00
int new_msgs ;
struct ast_event * event ;
2008-08-09 14:12:34 +00:00
char * mbox , * cntx ;
2007-08-09 17:07:36 +00:00
2008-08-09 14:12:34 +00:00
cntx = mbox = ast_strdupa ( p - > mailbox ) ;
strsep ( & cntx , " @ " ) ;
if ( ast_strlen_zero ( cntx ) )
cntx = " default " ;
2007-04-28 21:01:44 +00:00
event = ast_event_get_cached ( AST_EVENT_MWI ,
2008-08-09 14:12:34 +00:00
AST_EVENT_IE_MAILBOX , AST_EVENT_IE_PLTYPE_STR , mbox ,
AST_EVENT_IE_CONTEXT , AST_EVENT_IE_PLTYPE_STR , cntx ,
2007-04-28 21:01:44 +00:00
AST_EVENT_IE_NEWMSGS , AST_EVENT_IE_PLTYPE_EXISTS ,
AST_EVENT_IE_END ) ;
if ( event ) {
new_msgs = ast_event_get_ie_uint ( event , AST_EVENT_IE_NEWMSGS ) ;
ast_event_destroy ( event ) ;
} else
new_msgs = ast_app_has_voicemail ( p - > mailbox , NULL ) ;
return new_msgs ;
2003-05-06 04:03:58 +00:00
}
static int unalloc_sub ( struct mgcp_subchannel * sub )
{
2005-01-06 08:16:43 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2003-05-06 04:03:58 +00:00
if ( p - > sub = = sub ) {
ast_log ( LOG_WARNING , " Trying to unalloc the real channel %s@%s?!? \n " , p - > name , p - > parent - > name ) ;
return - 1 ;
}
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " Released sub %d of channel %s@%s \n " , sub - > id , p - > name , p - > parent - > name ) ;
2003-05-06 04:03:58 +00:00
sub - > owner = NULL ;
2005-05-04 19:17:09 +00:00
if ( ! ast_strlen_zero ( sub - > cxident ) ) {
2003-05-06 04:03:58 +00:00
transmit_connection_del ( sub ) ;
2005-01-06 08:16:43 +00:00
}
sub - > cxident [ 0 ] = ' \0 ' ;
sub - > callid [ 0 ] = ' \0 ' ;
sub - > cxmode = MGCP_CX_INACTIVE ;
2003-05-06 04:03:58 +00:00
sub - > outgoing = 0 ;
sub - > alreadygone = 0 ;
memset ( & sub - > tmpdest , 0 , sizeof ( sub - > tmpdest ) ) ;
if ( sub - > rtp ) {
ast_rtp_destroy ( sub - > rtp ) ;
sub - > rtp = NULL ;
}
2005-01-06 08:16:43 +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
2006-07-19 20:44:39 +00:00
/* modified for new transport mechanism */
2004-03-19 22:57:08 +00:00
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 )
2005-01-06 08:16:43 +00:00
res = sendto ( mgcpsock , data , len , 0 , ( struct sockaddr * ) & gw - > addr , sizeof ( struct sockaddr_in ) ) ;
2003-03-09 06:00:18 +00:00
else
2005-01-06 08:16:43 +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 )
{
2005-01-06 08:16:43 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2004-05-21 06:05:20 +00:00
int res ;
if ( mgcpdebug ) {
2006-07-21 17:31:28 +00:00
ast_verbose ( " Retransmitting: \n %s \n to %s:%d \n " , resp - > buf , ast_inet_ntoa ( p - > parent - > addr . sin_addr ) , ntohs ( p - > parent - > addr . sin_port ) ) ;
2005-01-06 08:16:43 +00:00
}
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
{
2005-01-06 08:16:43 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2002-12-29 19:13:07 +00:00
int res ;
2003-05-06 04:03:58 +00:00
if ( mgcpdebug ) {
2006-07-21 17:31:28 +00:00
ast_verbose ( " Transmitting: \n %s \n to %s:%d \n " , req - > data , ast_inet_ntoa ( p - > parent - > addr . sin_addr ) , ntohs ( p - > parent - > addr . sin_port ) ) ;
2005-01-06 08:16:43 +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 ;
}
2006-07-19 20:44:39 +00:00
/* modified for new transport framework */
2004-03-19 22:57:08 +00:00
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 ;
2005-01-06 08:16:43 +00:00
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-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
ast_log ( LOG_NOTICE , " Removing message from %s transaction %u \n " ,
gw - > name , cur - > seqno ) ;
w = cur ;
cur = cur - > next ;
if ( q ) {
w - > next = q ;
} else {
w - > next = NULL ;
}
q = w ;
} else {
prev = cur , cur = cur - > next ;
}
}
ast_mutex_unlock ( & gw - > msgs_lock ) ;
while ( q ) {
cur = q ;
q = q - > next ;
2007-06-03 06:10:27 +00:00
ast_free ( cur ) ;
2005-01-06 08:16:43 +00:00
}
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 ) {
2007-09-17 22:59:36 +00:00
if ( ! ast_channel_trylock ( sub - > owner ) ) {
2004-11-07 21:46:09 +00:00
ast_queue_frame ( sub - > owner , f ) ;
2007-09-17 22:59:36 +00:00
ast_channel_unlock ( sub - > owner ) ;
2004-11-17 14:48:16 +00:00
break ;
2004-11-07 21:46:09 +00:00
} else {
2008-05-29 17:35:19 +00:00
DEADLOCK_AVOIDANCE ( & sub - > lock ) ;
2004-11-07 21:46:09 +00:00
}
} else
break ;
}
}
static void mgcp_queue_hangup ( struct mgcp_subchannel * sub )
{
for ( ; ; ) {
if ( sub - > owner ) {
2007-09-17 22:59:36 +00:00
if ( ! ast_channel_trylock ( sub - > owner ) ) {
2008-05-22 16:29:54 +00:00
ast_queue_hangup ( sub - > owner ) ;
2007-09-17 22:59:36 +00:00
ast_channel_unlock ( sub - > owner ) ;
2004-11-17 14:48:16 +00:00
break ;
2004-11-07 21:46:09 +00:00
} else {
2008-05-29 17:35:19 +00:00
DEADLOCK_AVOIDANCE ( & sub - > lock ) ;
2004-11-07 21:46:09 +00:00
}
} 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 ) ;
}
2007-09-21 14:40:10 +00:00
static int retrans_pkt ( const void * data )
2004-03-19 22:57:08 +00:00
{
2005-01-06 08:16:43 +00:00
struct mgcp_gateway * gw = ( struct mgcp_gateway * ) data ;
2004-03-19 22:57:08 +00:00
struct mgcp_message * cur , * exq = NULL , * w , * prev ;
2005-01-06 08:16:43 +00:00
int res = 0 ;
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
/* find out expired msgs */
ast_mutex_lock ( & gw - > msgs_lock ) ;
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
prev = NULL , cur = gw - > msgs ;
while ( cur ) {
if ( cur - > retrans < MAX_RETRANS ) {
cur - > retrans + + ;
if ( mgcpdebug ) {
ast_verbose ( " Retransmitting #%d transaction %u on [%s] \n " ,
cur - > retrans , cur - > seqno , gw - > name ) ;
}
__mgcp_xmit ( gw , cur - > buf , cur - > len ) ;
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
prev = cur ;
cur = cur - > next ;
} else {
if ( prev )
prev - > next = cur - > next ;
else
gw - > msgs = cur - > next ;
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +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
2005-01-06 08:16:43 +00:00
w = cur ;
cur = cur - > next ;
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
if ( exq ) {
w - > next = exq ;
} else {
w - > next = NULL ;
}
exq = w ;
}
}
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
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 ;
2007-06-03 06:10:27 +00:00
ast_free ( cur ) ;
2005-01-06 08:16:43 +00:00
}
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
return res ;
2004-03-19 22:57:08 +00:00
}
2006-07-19 20:44:39 +00:00
/* modified for the new transaction mechanism */
2004-03-19 22:57:08 +00:00
static int mgcp_postrequest ( struct mgcp_endpoint * p , struct mgcp_subchannel * sub ,
2005-05-15 03:21:51 +00:00
char * data , int len , unsigned int seqno )
2003-03-15 06:00:16 +00:00
{
2007-06-06 21:20:11 +00:00
struct mgcp_message * msg ;
2003-03-15 06:00:16 +00:00
struct mgcp_message * cur ;
2007-06-06 21:20:11 +00:00
struct mgcp_gateway * gw ;
2008-08-09 14:12:34 +00:00
struct timeval now ;
2004-03-19 22:57:08 +00:00
2007-06-06 21:20:11 +00:00
msg = ast_malloc ( sizeof ( * msg ) + len ) ;
2003-05-06 04:03:58 +00:00
if ( ! msg ) {
2003-03-15 06:00:16 +00:00
return - 1 ;
2005-01-06 08:16:43 +00:00
}
2007-06-06 21:20:11 +00:00
gw = ( ( p & & p - > parent ) ? p - > parent : NULL ) ;
2005-01-06 08:16:43 +00:00
if ( ! gw ) {
2007-06-06 21:20:11 +00:00
ast_free ( msg ) ;
2005-01-06 08:16:43 +00:00
return - 1 ;
}
2004-03-19 22:57:08 +00:00
/* SC
2005-01-06 08:16:43 +00:00
time ( & t ) ;
if ( gw - > messagepending & & ( gw - > lastouttime + 20 < t ) ) {
ast_log ( LOG_NOTICE , " Timeout waiting for response to message:%d, lastouttime: %ld, now: %ld. Dumping pending queue \n " ,
gw - > msgs ? gw - > msgs - > seqno : - 1 , ( long ) gw - > lastouttime , ( long ) t ) ;
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
2005-01-06 08:16:43 +00:00
ast_mutex_lock ( & gw - > msgs_lock ) ;
2004-03-19 22:57:08 +00:00
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 ;
2005-01-06 08:16:43 +00:00
}
2004-03-19 22:57:08 +00:00
2008-08-09 14:12:34 +00:00
now = ast_tvnow ( ) ;
msg - > expire = now . tv_sec * 1000 + now . tv_usec / 1000 + DEFAULT_RETRANS ;
2004-03-19 22:57:08 +00:00
2007-07-18 19:47:20 +00:00
if ( gw - > retransid = = - 1 )
gw - > retransid = ast_sched_add ( sched , DEFAULT_RETRANS , retrans_pkt , ( void * ) gw ) ;
2005-01-06 08:16:43 +00:00
ast_mutex_unlock ( & gw - > msgs_lock ) ;
2004-03-19 22:57:08 +00:00
/* SC
if ( ! gw - > messagepending ) {
gw - > messagepending = 1 ;
gw - > lastout = seqno ;
2005-01-06 08:16:43 +00:00
gw - > lastouttime = t ;
2004-03-19 22:57:08 +00:00
*/
2005-01-06 08:16:43 +00:00
__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
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " 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 ;
}
2006-07-19 20:44:39 +00:00
/* modified for new transport */
2004-03-19 22:57:08 +00:00
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
{
2005-01-10 00:43:01 +00:00
int res = 0 ;
struct mgcp_request * * queue , * q , * r , * t ;
ast_mutex_t * l ;
2004-03-19 22:57:08 +00:00
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " Slow sequence is %d \n " , p - > slowsequence ) ;
2004-07-25 01:20:16 +00:00
if ( p - > slowsequence ) {
queue = & p - > cmd_queue ;
l = & p - > cmd_queue_lock ;
ast_mutex_lock ( l ) ;
2005-01-10 00:43:01 +00:00
} else {
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 ;
2007-06-03 06:10:27 +00:00
ast_free ( q ) ;
2005-01-10 00:43:01 +00:00
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 ;
}
}
2007-06-03 06:10:27 +00:00
r = ast_malloc ( sizeof ( * r ) ) ;
2005-01-10 00:43:01 +00:00
if ( ! r ) {
ast_log ( LOG_WARNING , " Cannot post MGCP request: insufficient memory \n " ) ;
ast_mutex_unlock ( l ) ;
return - 1 ;
}
2007-06-03 06:10:27 +00:00
memcpy ( r , req , sizeof ( * r ) ) ;
2005-01-10 00:43:01 +00:00
if ( ! ( * queue ) ) {
if ( mgcpdebug ) {
ast_verbose ( " Posting Request: \n %s to %s:%d \n " , req - > data ,
2006-07-21 17:31:28 +00:00
ast_inet_ntoa ( p - > parent - > addr . sin_addr ) , ntohs ( p - > parent - > addr . sin_port ) ) ;
2005-01-10 00:43:01 +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 ,
2006-07-21 17:31:28 +00:00
ast_inet_ntoa ( p - > parent - > addr . sin_addr ) , ntohs ( p - > parent - > addr . sin_port ) ) ;
2005-01-10 00:43:01 +00:00
}
}
2006-07-19 20:44:39 +00:00
/* XXX find tail. We could also keep tail in the data struct for faster access */
2005-01-10 00:43:01 +00:00
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 )
{
2005-01-10 00:43:01 +00:00
int res ;
struct mgcp_endpoint * p ;
struct mgcp_subchannel * sub ;
char tone [ 50 ] = " " ;
2005-12-03 19:25:33 +00:00
const char * distinctive_ring = NULL ;
2005-01-10 00:43:01 +00:00
struct varshead * headp ;
struct ast_var_t * current ;
if ( mgcpdebug ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " MGCP mgcp_call(%s) \n " , ast - > name ) ;
2005-01-10 00:43:01 +00:00
}
2005-03-04 06:47:24 +00:00
sub = ast - > tech_pvt ;
2005-01-10 00:43:01 +00:00
p = sub - > parent ;
headp = & ast - > varshead ;
AST_LIST_TRAVERSE ( headp , current , entries ) {
/* Check whether there is an ALERT_INFO variable */
if ( strcasecmp ( ast_var_name ( current ) , " ALERT_INFO " ) = = 0 ) {
distinctive_ring = ast_var_value ( current ) ;
}
}
ast_mutex_lock ( & sub - > lock ) ;
switch ( p - > hookstate ) {
case MGCP_OFFHOOK :
2005-10-27 02:19:37 +00:00
if ( ! ast_strlen_zero ( distinctive_ring ) ) {
2005-02-28 22:26:41 +00:00
snprintf ( tone , sizeof ( tone ) , " L/wt%s " , distinctive_ring ) ;
if ( mgcpdebug ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " MGCP distinctive callwait %s \n " , tone ) ;
2005-02-28 22:26:41 +00:00
}
} else {
2007-10-01 15:23:19 +00:00
ast_copy_string ( tone , " L/wt " , sizeof ( tone ) ) ;
2005-02-28 22:26:41 +00:00
if ( mgcpdebug ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " MGCP normal callwait %s \n " , tone ) ;
2005-02-28 22:26:41 +00:00
}
}
2005-01-10 00:43:01 +00:00
break ;
case MGCP_ONHOOK :
default :
2005-10-27 02:19:37 +00:00
if ( ! ast_strlen_zero ( distinctive_ring ) ) {
2005-01-10 00:43:01 +00:00
snprintf ( tone , sizeof ( tone ) , " L/r%s " , distinctive_ring ) ;
if ( mgcpdebug ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " MGCP distinctive ring %s \n " , tone ) ;
2005-01-10 00:43:01 +00:00
}
} else {
2007-10-01 15:23:19 +00:00
ast_copy_string ( tone , " L/rg " , sizeof ( tone ) ) ;
2005-01-10 00:43:01 +00:00
if ( mgcpdebug ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " MGCP default ring \n " ) ;
2005-01-10 00:43:01 +00:00
}
}
break ;
}
2003-05-06 04:03:58 +00:00
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 ;
2005-01-06 08:16:43 +00:00
sub - > cxmode = MGCP_CX_RECVONLY ;
2002-12-29 19:13:07 +00:00
if ( p - > type = = TYPE_LINE ) {
2005-01-06 08:16:43 +00:00
if ( ! sub - > rtp ) {
start_rtp ( sub ) ;
} else {
transmit_modify_request ( sub ) ;
}
2003-05-06 04:03:58 +00:00
2005-05-04 19:17:09 +00:00
if ( sub - > next - > owner & & ! ast_strlen_zero ( sub - > next - > cxident ) & & ! ast_strlen_zero ( sub - > next - > callid ) ) {
2005-01-06 08:16:43 +00:00
/* try to prevent a callwait from disturbing the other connection */
sub - > next - > cxmode = MGCP_CX_RECVONLY ;
transmit_modify_request ( sub - > next ) ;
}
2003-05-06 04:03:58 +00:00
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
2005-05-04 19:17:09 +00:00
if ( sub - > next - > owner & & ! ast_strlen_zero ( sub - > next - > cxident ) & & ! ast_strlen_zero ( sub - > next - > callid ) ) {
2005-01-06 08:16:43 +00:00
/* 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 )
{
2005-03-04 06:47:24 +00:00
struct mgcp_subchannel * sub = ast - > tech_pvt ;
2003-05-06 04:03:58 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " mgcp_hangup(%s) \n " , ast - > name ) ;
2005-03-04 06:47:24 +00:00
if ( ! ast - > tech_pvt ) {
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " Asked to hangup channel not connected \n " ) ;
2002-12-29 19:13:07 +00:00
return 0 ;
}
2005-01-01 00:59:54 +00:00
if ( strcmp ( sub - > magic , MGCP_SUBCHANNEL_MAGIC ) ) {
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " Invalid magic. MGCP subchannel freed up already. \n " ) ;
2004-03-19 22:57:08 +00:00
return 0 ;
2005-01-01 00:59:54 +00:00
}
ast_mutex_lock ( & sub - > lock ) ;
if ( mgcpdebug ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " MGCP mgcp_hangup(%s) on %s@%s \n " , ast - > name , p - > name , p - > parent - > name ) ;
2005-01-01 00:59:54 +00:00
}
2004-03-19 22:57:08 +00:00
2005-01-01 00:59:54 +00:00
if ( ( p - > dtmfmode & MGCP_DTMF_INBAND ) & & p - > dsp ) {
2006-07-19 20:44:39 +00:00
/* check whether other channel is active. */
2005-01-06 08:16:43 +00:00
if ( ! sub - > next - > owner ) {
2005-03-28 20:48:24 +00:00
if ( p - > dtmfmode & MGCP_DTMF_HYBRID )
p - > dtmfmode & = ~ MGCP_DTMF_INBAND ;
2005-01-06 08:16:43 +00:00
if ( mgcpdebug ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 2 , " MGCP free dsp on %s@%s \n " , p - > name , p - > parent - > name ) ;
2005-01-06 08:16:43 +00:00
}
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 ;
2005-05-04 19:17:09 +00:00
if ( ! ast_strlen_zero ( sub - > cxident ) ) {
2003-05-06 04:03:58 +00:00
transmit_connection_del ( sub ) ;
2005-01-01 00:59:54 +00:00
}
sub - > cxident [ 0 ] = ' \0 ' ;
2005-01-06 08:16:43 +00:00
if ( ( sub = = p - > sub ) & & sub - > next - > owner ) {
if ( p - > hookstate = = MGCP_OFFHOOK ) {
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 ) ;
}
} else {
/* set our other connection as the primary and swith over to it */
p - > sub = sub - > next ;
p - > sub - > cxmode = MGCP_CX_RECVONLY ;
transmit_modify_request ( p - > sub ) ;
if ( sub - > next - > owner & & 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
2005-01-06 08:16:43 +00:00
} else if ( ( sub = = p - > sub - > next ) & & p - > hookstate = = MGCP_OFFHOOK ) {
transmit_notify_request ( sub , " L/v " ) ;
} else if ( p - > hookstate = = MGCP_OFFHOOK ) {
transmit_notify_request ( sub , " L/ro " ) ;
} else {
transmit_notify_request ( sub , " " ) ;
}
2003-05-06 04:03:58 +00:00
2005-03-04 06:47:24 +00:00
ast - > tech_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 ' ;
2008-02-05 20:03:54 +00:00
if ( p ) {
memset ( p - > dtmf_buf , 0 , sizeof ( p - > dtmf_buf ) ) ;
}
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
2006-08-21 02:11:39 +00:00
ast_module_unref ( ast_module_info - > self ) ;
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
if ( ( p - > hookstate = = MGCP_ONHOOK ) & & ( ! sub - > next - > rtp ) ) {
2005-04-04 14:14:19 +00:00
p - > hidecallerid = 0 ;
2005-04-11 05:48:58 +00:00
if ( p - > hascallwaiting & & ! p - > callwaiting ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Enabling call waiting on %s \n " , ast - > name ) ;
2005-04-11 05:48:58 +00:00
p - > callwaiting = - 1 ;
}
2005-01-06 08:16:43 +00:00
if ( has_voicemail ( p ) ) {
if ( mgcpdebug ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " MGCP mgcp_hangup(%s) on %s@%s set vmwi(+) \n " ,
2005-01-06 08:16:43 +00:00
ast - > name , p - > name , p - > parent - > name ) ;
}
transmit_notify_request ( sub , " L/vmwi(+) " ) ;
} else {
if ( mgcpdebug ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " MGCP mgcp_hangup(%s) on %s@%s set vmwi(-) \n " ,
2005-01-06 08:16:43 +00:00
ast - > name , p - > name , p - > parent - > name ) ;
}
transmit_notify_request ( sub , " L/vmwi(-) " ) ;
}
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & sub - > lock ) ;
2002-12-29 19:13:07 +00:00
return 0 ;
}
2007-10-11 19:03:06 +00:00
static char * handle_mgcp_show_endpoints ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2002-12-29 19:13:07 +00:00
{
2007-10-11 19:03:06 +00:00
struct mgcp_gateway * mg ;
struct mgcp_endpoint * me ;
2002-12-29 19:13:07 +00:00
int hasendpoints = 0 ;
2005-01-06 08:16:43 +00:00
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " mgcp show endpoints " ;
e - > usage =
" Usage: mgcp show endpoints \n "
" Lists all endpoints known to the MGCP (Media Gateway Control Protocol) subsystem. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
if ( a - > argc ! = 3 )
return CLI_SHOWUSAGE ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & gatelock ) ;
2007-10-11 19:03:06 +00:00
mg = gateways ;
while ( mg ) {
me = mg - > endpoints ;
ast_cli ( a - > fd , " Gateway '%s' at %s (%s) \n " , mg - > name , mg - > addr . sin_addr . s_addr ? ast_inet_ntoa ( mg - > addr . sin_addr ) : ast_inet_ntoa ( mg - > defaddr . sin_addr ) , mg - > dynamic ? " Dynamic " : " Static " ) ;
while ( me ) {
2006-07-19 20:44:39 +00:00
/* Don't show wilcard endpoint */
2007-10-11 19:03:06 +00:00
if ( strcmp ( me - > name , mg - > wcardep ) ! = 0 )
ast_cli ( a - > fd , " -- '%s@%s in '%s' is %s \n " , me - > name , mg - > name , me - > context , me - > sub - > owner ? " active " : " idle " ) ;
2002-12-29 19:13:07 +00:00
hasendpoints = 1 ;
2007-10-11 19:03:06 +00:00
me = me - > next ;
2002-12-29 19:13:07 +00:00
}
if ( ! hasendpoints ) {
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " << No Endpoints Defined >> " ) ;
2002-12-29 19:13:07 +00:00
}
2007-10-11 19:03:06 +00:00
mg = mg - > next ;
2002-12-29 19:13:07 +00:00
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & gatelock ) ;
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
2002-12-29 19:13:07 +00:00
}
2007-10-11 19:03:06 +00:00
static char * handle_mgcp_audit_endpoint ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2003-04-11 19:17:05 +00:00
{
2007-10-11 19:03:06 +00:00
struct mgcp_gateway * mg ;
struct mgcp_endpoint * me ;
2003-04-11 19:17:05 +00:00
int found = 0 ;
2005-01-06 08:16:43 +00:00
char * ename , * gname , * c ;
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " mgcp audit endpoint " ;
e - > usage =
" Usage: mgcp audit endpoint <endpointid> \n "
" Lists the capabilities of an endpoint in the MGCP (Media Gateway Control Protocol) subsystem. \n "
" mgcp debug MUST be on to see the results of this command. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2003-04-11 19:17:05 +00:00
if ( ! mgcpdebug ) {
2007-10-11 19:03:06 +00:00
return CLI_SHOWUSAGE ;
2005-01-06 08:16:43 +00:00
}
2007-10-11 19:03:06 +00:00
if ( a - > argc ! = 4 )
return CLI_SHOWUSAGE ;
2005-01-06 08:16:43 +00:00
/* split the name into parts by null */
2007-10-11 19:03:06 +00:00
ename = a - > argv [ 3 ] ;
2005-01-06 08:16:43 +00:00
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 ) ;
2007-10-11 19:03:06 +00:00
mg = gateways ;
while ( mg ) {
if ( ! strcasecmp ( mg - > name , gname ) ) {
me = mg - > endpoints ;
while ( me ) {
if ( ! strcasecmp ( me - > name , ename ) ) {
2005-01-06 08:16:43 +00:00
found = 1 ;
2007-10-11 19:03:06 +00:00
transmit_audit_endpoint ( me ) ;
2005-01-06 08:16:43 +00:00
break ;
}
2007-10-11 19:03:06 +00:00
me = me - > next ;
2005-01-06 08:16:43 +00:00
}
if ( found ) {
break ;
}
}
2007-10-11 19:03:06 +00:00
mg = mg - > next ;
2005-01-06 08:16:43 +00:00
}
if ( ! found ) {
2007-10-11 19:03:06 +00:00
ast_cli ( a - > fd , " << Could not find endpoint >> " ) ;
2003-04-11 19:17:05 +00:00
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & gatelock ) ;
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
2003-04-11 19:17:05 +00:00
}
2008-02-08 21:26:32 +00:00
static char * handle_mgcp_set_debug ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2006-09-18 19:54:18 +00:00
{
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
2008-02-08 21:26:32 +00:00
e - > command = " mgcp set debug {on|off} " ;
2007-10-11 19:03:06 +00:00
e - > usage =
2008-02-08 21:26:32 +00:00
" Usage: mgcp set debug {on|off} \n "
" Enables/Disables dumping of MGCP packets for debugging purposes \n " ;
2007-10-11 19:03:06 +00:00
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2008-02-08 21:26:32 +00:00
if ( a - > argc ! = e - > args )
2007-10-11 19:03:06 +00:00
return CLI_SHOWUSAGE ;
2008-02-08 21:26:32 +00:00
if ( ! strncasecmp ( a - > argv [ e - > args - 1 ] , " on " , 2 ) ) {
mgcpdebug = 1 ;
ast_cli ( a - > fd , " MGCP Debugging Enabled \n " ) ;
} else if ( ! strncasecmp ( a - > argv [ 3 ] , " off " , 3 ) ) {
mgcpdebug = 0 ;
ast_cli ( a - > fd , " MGCP Debugging Disabled \n " ) ;
} else {
return CLI_SHOWUSAGE ;
}
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
2006-09-18 19:54:18 +00:00
}
2003-04-11 19:17:05 +00:00
2006-09-18 19:54:18 +00:00
static struct ast_cli_entry cli_mgcp [ ] = {
2007-10-22 20:05:18 +00:00
AST_CLI_DEFINE ( handle_mgcp_audit_endpoint , " Audit specified MGCP endpoint " ) ,
AST_CLI_DEFINE ( handle_mgcp_show_endpoints , " List defined MGCP endpoints " ) ,
2008-11-12 06:46:04 +00:00
AST_CLI_DEFINE ( handle_mgcp_set_debug , " Enable/Disable MGCP debugging " ) ,
2007-10-22 20:05:18 +00:00
AST_CLI_DEFINE ( mgcp_reload , " Reload MGCP configuration " ) ,
2006-09-18 19:54:18 +00:00
} ;
2003-04-11 19:17:05 +00:00
2002-12-29 19:13:07 +00:00
static int mgcp_answer ( struct ast_channel * ast )
{
int res = 0 ;
2005-03-04 06:47:24 +00:00
struct mgcp_subchannel * sub = ast - > tech_pvt ;
2003-05-06 04:03:58 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2005-01-06 08:16:43 +00:00
2004-11-07 21:46:09 +00:00
ast_mutex_lock ( & sub - > lock ) ;
2005-01-06 08:16:43 +00:00
sub - > cxmode = MGCP_CX_SENDRECV ;
if ( ! sub - > rtp ) {
start_rtp ( sub ) ;
} else {
transmit_modify_request ( sub ) ;
}
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " MGCP mgcp_answer(%s) on %s@%s-%d \n " ,
2005-01-06 08:16:43 +00:00
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 ) ;
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " 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 ;
2005-01-06 08:16:43 +00:00
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 ) )
2006-01-31 17:18:58 +00:00
return & ast_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 ) {
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " 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
}
2005-01-06 08:16:43 +00:00
/* Courtesy fearnor aka alex@pilosoft.com */
if ( ( sub - > parent - > dtmfmode & MGCP_DTMF_INBAND ) & & ( sub - > parent - > dsp ) ) {
2003-05-07 15:29:20 +00:00
#if 0
2005-01-06 08:16:43 +00:00
ast_log ( LOG_NOTICE , " MGCP ast_dsp_process \n " ) ;
2003-05-07 15:29:20 +00:00
# endif
2005-01-06 08:16:43 +00:00
f = ast_dsp_process ( sub - > owner , sub - > parent - > dsp , f ) ;
}
2003-02-12 13:59:15 +00:00
}
}
return f ;
}
2005-01-06 08:16:43 +00:00
static struct ast_frame * mgcp_read ( struct ast_channel * ast )
2002-12-29 19:13:07 +00:00
{
2004-10-26 02:57:18 +00:00
struct ast_frame * f ;
2005-03-04 06:47:24 +00:00
struct mgcp_subchannel * sub = ast - > tech_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 )
{
2005-03-04 06:47:24 +00:00
struct mgcp_subchannel * sub = ast - > tech_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
{
2005-03-04 06:47:24 +00:00
struct mgcp_subchannel * sub = newchan - > tech_pvt ;
2005-01-06 08:16:43 +00:00
2004-11-07 21:46:09 +00:00
ast_mutex_lock ( & sub - > lock ) ;
2005-01-06 08:16:43 +00:00
ast_log ( LOG_NOTICE , " mgcp_fixup(%s, %s) \n " , oldchan - > name , newchan - > name ) ;
2003-05-06 04:03:58 +00:00
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 ;
}
2006-08-31 01:59:02 +00:00
static int mgcp_senddigit_begin ( struct ast_channel * ast , char digit )
{
2008-01-08 20:50:57 +00:00
struct mgcp_subchannel * sub = ast - > tech_pvt ;
struct mgcp_endpoint * p = sub - > parent ;
int res = 0 ;
ast_mutex_lock ( & sub - > lock ) ;
if ( p - > dtmfmode & MGCP_DTMF_INBAND | | p - > dtmfmode & MGCP_DTMF_HYBRID ) {
ast_log ( LOG_DEBUG , " Sending DTMF using inband/hybrid \n " ) ;
res = - 1 ; /* Let asterisk play inband indications */
} else if ( p - > dtmfmode & MGCP_DTMF_RFC2833 ) {
ast_log ( LOG_DEBUG , " Sending DTMF using RFC2833 " ) ;
ast_rtp_senddigit_begin ( sub - > rtp , digit ) ;
} else {
ast_log ( LOG_ERROR , " Don't know about DTMF_MODE %d \n " , p - > dtmfmode ) ;
}
ast_mutex_unlock ( & sub - > lock ) ;
return res ;
2006-08-31 01:59:02 +00:00
}
Merged revisions 51311 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged. So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio. However,
since there was no audio coming in, the DTMF_END was never generated. This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf). If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback. This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-01-19 18:06:03 +00:00
static int mgcp_senddigit_end ( struct ast_channel * ast , char digit , unsigned int duration )
2002-12-29 19:13:07 +00:00
{
2005-03-04 06:47:24 +00:00
struct mgcp_subchannel * sub = ast - > tech_pvt ;
2008-01-08 20:50:57 +00:00
struct mgcp_endpoint * p = sub - > parent ;
int res = 0 ;
2004-08-12 20:26:40 +00:00
char tmp [ 4 ] ;
2005-01-06 08:16:43 +00:00
2004-11-07 21:46:09 +00:00
ast_mutex_lock ( & sub - > lock ) ;
2008-01-08 20:50:57 +00:00
if ( p - > dtmfmode & MGCP_DTMF_INBAND | | p - > dtmfmode & MGCP_DTMF_HYBRID ) {
ast_log ( LOG_DEBUG , " Stopping DTMF using inband/hybrid \n " ) ;
res = - 1 ; /* Tell Asterisk to stop inband indications */
} else if ( p - > dtmfmode & MGCP_DTMF_RFC2833 ) {
ast_log ( LOG_DEBUG , " Stopping DTMF using RFC2833 \n " ) ;
tmp [ 0 ] = ' D ' ;
tmp [ 1 ] = ' / ' ;
tmp [ 2 ] = digit ;
tmp [ 3 ] = ' \0 ' ;
transmit_notify_request ( sub , tmp ) ;
ast_rtp_senddigit_end ( sub - > rtp , digit ) ;
} else {
ast_log ( LOG_ERROR , " Don't know about DTMF_MODE %d \n " , p - > dtmfmode ) ;
}
2004-11-07 21:46:09 +00:00
ast_mutex_unlock ( & sub - > lock ) ;
2008-01-08 20:50:57 +00:00
return res ;
2002-12-29 19:13:07 +00:00
}
2006-01-21 05:15:56 +00:00
/*!
* \ brief mgcp_devicestate : channel callback for device status monitoring
* \ param data tech / resource name of MGCP device to query
*
* Callback for device state management in channel subsystem
* to obtain device status ( up / down ) of a specific MGCP endpoint
*
* \ return device status result ( from devicestate . h ) AST_DEVICE_INVALID ( not available ) or AST_DEVICE_UNKNOWN ( available but unknown state )
*/
static int mgcp_devicestate ( void * data )
{
struct mgcp_gateway * g ;
struct mgcp_endpoint * e = NULL ;
char * tmp , * endpt , * gw ;
int ret = AST_DEVICE_INVALID ;
endpt = ast_strdupa ( data ) ;
if ( ( tmp = strchr ( endpt , ' @ ' ) ) ) {
* tmp + + = ' \0 ' ;
gw = tmp ;
} else
goto error ;
ast_mutex_lock ( & gatelock ) ;
g = gateways ;
while ( g ) {
if ( strcasecmp ( g - > name , gw ) = = 0 ) {
e = g - > endpoints ;
break ;
}
g = g - > next ;
}
if ( ! e )
goto error ;
while ( e ) {
if ( strcasecmp ( e - > name , endpt ) = = 0 )
break ;
e = e - > next ;
}
if ( ! e )
goto error ;
/*
* As long as the gateway / endpoint is valid , we ' ll
* assume that the device is available and its state
* can be tracked .
*/
ret = AST_DEVICE_UNKNOWN ;
error :
ast_mutex_unlock ( & gatelock ) ;
return ret ;
}
2003-05-06 04:03:58 +00:00
static char * control2str ( int ind ) {
2005-01-06 08:16:43 +00:00
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 " ;
2003-05-06 04:03:58 +00:00
}
2006-05-10 12:24:11 +00:00
static int mgcp_indicate ( struct ast_channel * ast , int ind , const void * data , size_t datalen )
2002-12-29 19:13:07 +00:00
{
2005-03-04 06:47:24 +00:00
struct mgcp_subchannel * sub = ast - > tech_pvt ;
2004-11-07 21:46:09 +00:00
int res = 0 ;
2005-01-06 08:16:43 +00:00
if ( mgcpdebug ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " MGCP asked to indicate %d '%s' condition on channel %s \n " ,
2005-01-06 08:16:43 +00:00
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 ;
2006-07-19 20:44:39 +00:00
case AST_CONTROL_HOLD :
ast_moh_start ( ast , data , NULL ) ;
break ;
case AST_CONTROL_UNHOLD :
ast_moh_stop ( ast ) ;
break ;
2008-03-05 22:43:22 +00:00
case AST_CONTROL_SRCUPDATE :
ast_rtp_new_source ( sub - > rtp ) ;
break ;
2002-12-29 19:13:07 +00:00
case - 1 :
2003-05-06 04:03:58 +00:00
transmit_notify_request ( sub , " " ) ;
2006-07-19 20:44:39 +00:00
break ;
2002-12-29 19:13:07 +00:00
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 ;
2005-01-06 08:16:43 +00:00
struct mgcp_endpoint * i = sub - > parent ;
2002-12-29 19:13:07 +00:00
int fmt ;
2005-01-06 08:16:43 +00:00
2007-04-10 05:41:34 +00:00
tmp = ast_channel_alloc ( 1 , state , i - > cid_num , i - > cid_name , i - > accountcode , i - > exten , i - > context , i - > amaflags , " MGCP/%s@%s-%d " , i - > name , i - > parent - > name , sub - > id ) ;
2002-12-29 19:13:07 +00:00
if ( tmp ) {
2005-03-04 06:47:24 +00:00
tmp - > tech = & mgcp_tech ;
2002-12-29 19:13:07 +00:00
tmp - > nativeformats = i - > capability ;
if ( ! tmp - > nativeformats )
tmp - > nativeformats = capability ;
fmt = ast_best_codec ( tmp - > nativeformats ) ;
2006-02-01 23:05:28 +00:00
ast_string_field_build ( tmp , name , " MGCP/%s@%s-%d " , i - > name , i - > parent - > name , sub - > id ) ;
2003-05-06 04:03:58 +00:00
if ( sub - > rtp )
2007-08-08 21:44:58 +00:00
ast_channel_set_fd ( tmp , 0 , ast_rtp_fd ( sub - > rtp ) ) ;
2005-03-28 20:48:24 +00:00
if ( i - > dtmfmode & ( MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID ) ) {
2005-01-06 08:16:43 +00:00
i - > dsp = ast_dsp_new ( ) ;
2008-03-19 22:25:34 +00:00
ast_dsp_set_features ( i - > dsp , DSP_FEATURE_DIGIT_DETECT ) ;
2006-07-19 20:44:39 +00:00
/* this is to prevent clipping of dtmf tones during dsp processing */
2008-03-19 21:56:15 +00:00
ast_dsp_set_digitmode ( i - > dsp , DSP_DIGITMODE_NOQUELCH ) ;
2003-03-10 20:39:12 +00:00
} else {
2005-01-06 08:16:43 +00:00
i - > dsp = NULL ;
2003-03-10 20:39:12 +00:00
}
2002-12-29 19:13:07 +00:00
if ( state = = AST_STATE_RING )
tmp - > rings = 1 ;
tmp - > writeformat = fmt ;
2005-03-04 06:47:24 +00:00
tmp - > rawwriteformat = fmt ;
2002-12-29 19:13:07 +00:00
tmp - > readformat = fmt ;
2005-03-04 06:47:24 +00:00
tmp - > rawreadformat = fmt ;
tmp - > tech_pvt = sub ;
2005-05-04 19:17:09 +00:00
if ( ! ast_strlen_zero ( i - > language ) )
2006-02-01 23:05:28 +00:00
ast_string_field_set ( tmp , language , i - > language ) ;
2005-05-04 19:17:09 +00:00
if ( ! ast_strlen_zero ( i - > accountcode ) )
2006-02-01 23:05:28 +00:00
ast_string_field_set ( tmp , accountcode , i - > accountcode ) ;
2003-05-06 04:03:58 +00:00
if ( i - > amaflags )
tmp - > amaflags = i - > amaflags ;
sub - > owner = tmp ;
2006-08-21 02:11:39 +00:00
ast_module_ref ( ast_module_info - > self ) ;
2003-05-06 04:03:58 +00:00
tmp - > callgroup = i - > callgroup ;
tmp - > pickupgroup = i - > pickupgroup ;
2006-02-01 23:05:28 +00:00
ast_string_field_set ( tmp , call_forward , i - > call_forward ) ;
2006-04-21 18:34:38 +00:00
ast_copy_string ( tmp - > context , i - > context , sizeof ( tmp - > context ) ) ;
ast_copy_string ( tmp - > exten , i - > exten , sizeof ( tmp - > exten ) ) ;
2006-08-05 05:26:29 +00:00
/* Don't use ast_set_callerid() here because it will
2006-11-07 21:47:49 +00:00
* generate a needless NewCallerID event */
2006-08-05 05:26:29 +00:00
tmp - > cid . cid_ani = ast_strdup ( i - > cid_num ) ;
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 ;
2006-08-16 03:43:47 +00:00
if ( sub - > rtp )
ast_jb_configure ( tmp , & global_jbconf ) ;
2002-12-29 19:13:07 +00:00
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 ) ;
2006-06-23 16:49:12 +00:00
tmp = NULL ;
2002-12-29 19:13:07 +00:00
}
}
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " MGCP mgcp_new(%s) created in state: %s \n " ,
2005-01-06 08:16:43 +00:00
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 " ) ;
2005-01-06 08:16:43 +00:00
}
2002-12-29 19:13:07 +00:00
return tmp ;
}
2005-01-06 08:16:43 +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 " " ;
2003-03-12 06:00:18 +00:00
}
2005-01-06 08:16:43 +00:00
static char * get_sdp ( struct mgcp_request * req , char * name )
{
int x ;
int len = strlen ( name ) ;
char * r ;
2003-03-12 06:00:18 +00:00
2005-01-06 08:16:43 +00:00
for ( x = 0 ; x < req - > lines ; x + + ) {
r = get_sdp_by_line ( req - > line [ x ] , name , len ) ;
if ( r [ 0 ] ! = ' \0 ' ) return r ;
}
return " " ;
2003-03-12 06:00:18 +00:00
}
2005-01-06 08:16:43 +00:00
static void sdpLineNum_iterator_init ( int * iterator )
{
* iterator = 0 ;
2003-03-12 06:00:18 +00:00
}
2005-01-06 08:16:43 +00:00
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 ) & &
2005-01-06 08:16:43 +00:00
( req - > header [ x ] [ len ] = = ' : ' ) ) {
r = req - > header [ x ] + len + 1 ;
while ( * r & & ( * r < 33 ) )
r + + ;
* start = x + 1 ;
return r ;
2002-12-29 19:13:07 +00:00
}
}
/* 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 ) ;
}
2006-01-21 05:15:56 +00:00
/*! \brief get_csv: (SC:) get comma separated value */
2004-03-27 17:51:22 +00:00
static char * get_csv ( char * c , int * len , char * * next )
{
2005-01-06 08:16:43 +00:00
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-03-27 17:51:22 +00:00
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 ;
char tmp [ 256 ] = " " ;
2003-04-14 20:48:30 +00:00
char * at = NULL , * c ;
2005-01-06 08:16:43 +00:00
int found = 0 ;
2002-12-29 19:13:07 +00:00
if ( name ) {
2006-04-21 18:34:38 +00:00
ast_copy_string ( tmp , name , sizeof ( tmp ) ) ;
2002-12-29 19:13:07 +00:00
at = strchr ( tmp , ' @ ' ) ;
if ( ! at ) {
ast_log ( LOG_NOTICE , " Endpoint '%s' has no at sign! \n " , name ) ;
return NULL ;
}
2006-04-21 18:34:38 +00:00
* at + + = ' \0 ' ;
2002-12-29 19:13:07 +00:00
}
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 ) ) ;
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Registered MGCP gateway '%s' at %s port %d \n " , g - > name , ast_inet_ntoa ( g - > addr . sin_addr ) , ntohs ( g - > addr . sin_port ) ) ;
2003-03-09 06:00:18 +00:00
}
}
2006-07-19 20:44:39 +00:00
/* not dynamic, check if the name matches */
2005-01-06 08:16:43 +00:00
else if ( name ) {
if ( strcasecmp ( g - > name , at ) ) {
g = g - > next ;
continue ;
}
}
2006-07-19 20:44:39 +00:00
/* not dynamic, no name, check if the addr matches */
2005-01-06 08:16:43 +00:00
else if ( ! name & & sin ) {
2004-03-19 22:57:08 +00:00
if ( ( g - > addr . sin_addr . s_addr ! = sin - > sin_addr . s_addr ) | |
2005-01-06 08:16:43 +00:00
( 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 ) {
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " Searching on %s@%s for subchannel \n " ,
p - > name , g - > name ) ;
2005-01-06 08:16:43 +00:00
if ( msgid ) {
2006-07-19 20:44:39 +00:00
#if 0 /* new transport mech */
2005-01-06 08:16:43 +00:00
sub = p - > sub ;
do {
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " Searching on %s@%s-%d for subchannel with lastout: %d \n " ,
p - > name , g - > name , sub - > id , msgid ) ;
2005-01-06 08:16:43 +00:00
if ( sub - > lastout = = msgid ) {
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " Found subchannel sub%d to handle request %d sub->lastout: %d \n " ,
sub - > id , msgid , sub - > lastout ) ;
2005-01-06 08:16:43 +00:00
found = 1 ;
break ;
}
sub = sub - > next ;
} while ( sub ! = p - > sub ) ;
if ( found ) {
break ;
}
2004-03-19 22:57:08 +00:00
# endif
2005-01-06 08:16:43 +00:00
/* SC */
sub = p - > sub ;
found = 1 ;
/* SC */
break ;
} else if ( name & & ! strcasecmp ( p - > name , tmp ) ) {
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " Coundn't determine subchannel, assuming current master %s@%s-%d \n " ,
p - > name , g - > name , p - > sub - > id ) ;
2005-01-06 08:16:43 +00:00
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 ;
2005-01-06 08:16:43 +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 )
2005-01-06 08:16:43 +00:00
ast_log ( LOG_NOTICE , " Endpoint '%s' not found on gateway '%s' \n " , tmp , at ) ;
2002-12-29 19:13:07 +00:00
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
2005-05-04 19:17:09 +00:00
if ( ast_strlen_zero ( req - > header [ f ] ) ) {
2002-12-29 19:13:07 +00:00
/* 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 */
2005-05-04 19:17:09 +00:00
if ( ! ast_strlen_zero ( req - > header [ f ] ) )
2002-12-29 19:13:07 +00:00
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 */
2005-05-04 19:17:09 +00:00
if ( ! ast_strlen_zero ( req - > line [ f ] ) )
2002-12-29 19:13:07 +00:00
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 " ,
2005-01-06 08:16:43 +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 ;
2005-05-04 19:17:09 +00:00
int codec , codec_count = 0 ;
2003-03-12 06:00:18 +00:00
int iterator ;
2005-01-06 08:16:43 +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 " ) ;
2005-05-04 19:17:09 +00:00
if ( ast_strlen_zero ( m ) | | ast_strlen_zero ( c ) ) {
2002-12-29 19:13:07 +00:00
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
2006-07-21 17:31:28 +00:00
printf ( " Peer RTP is at port %s:%d \n " , ast_inet_ntoa ( 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: */
2005-01-06 08:16:43 +00:00
ast_rtp_pt_clear ( sub - > rtp ) ;
2005-05-04 19:17:09 +00:00
codecs = ast_strdupa ( m + len ) ;
2005-10-27 02:19:37 +00:00
while ( ! ast_strlen_zero ( codecs ) ) {
2005-05-04 19:17:09 +00:00
if ( sscanf ( codecs , " %d%n " , & codec , & len ) ! = 1 ) {
if ( codec_count )
break ;
ast_log ( LOG_WARNING , " Error in codec string '%s' at '%s' \n " , m , codecs ) ;
2002-12-29 19:13:07 +00:00
return - 1 ;
}
2003-05-06 04:03:58 +00:00
ast_rtp_set_m_type ( sub - > rtp , codec ) ;
2005-05-04 19:17:09 +00:00
codec_count + + ;
2002-12-29 19:13:07 +00:00
codecs + = len ;
}
2003-03-12 06:00:18 +00:00
2005-01-06 08:16:43 +00:00
/* Next, scan through each "a=rtpmap:" line, noting each */
/* specified RTP payload type (with corresponding MIME subtype): */
sdpLineNum_iterator_init ( & iterator ) ;
while ( ( a = get_sdp_iterate ( & iterator , req , " a " ) ) [ 0 ] ! = ' \0 ' ) {
2005-05-04 00:40:14 +00:00
char * mimeSubtype = ast_strdupa ( a ) ; /* ensures we have enough space */
2005-01-06 08:16:43 +00:00
if ( sscanf ( a , " rtpmap: %u %[^/]/ " , & codec , mimeSubtype ) ! = 2 )
continue ;
/* Note: should really look at the 'freq' and '#chans' params too */
2006-07-13 01:38:47 +00:00
ast_rtp_set_rtpmap_type ( sub - > rtp , codec , " audio " , mimeSubtype , 0 ) ;
2005-01-06 08:16:43 +00:00
}
2003-03-12 06:00:18 +00:00
2005-01-06 08:16:43 +00:00
/* Now gather all of the codecs that were asked for: */
ast_rtp_get_current_formats ( sub - > rtp , & 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 " ,
2005-01-06 08:16:43 +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 " ,
2005-01-06 08:16:43 +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 */
2007-10-01 15:23:19 +00:00
ast_copy_string ( req - > data + req - > len , " \r \n " , sizeof ( req - > data ) - req - > len ) ;
2002-12-29 19:13:07 +00:00
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 ;
2006-07-19 20:44:39 +00:00
/* check if we need brackets around the gw name */
2005-01-06 08:16:43 +00:00
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 ;
2005-01-06 08:16:43 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2004-05-21 06:05:20 +00:00
struct mgcp_response * mgr ;
2005-01-06 08:16:43 +00:00
2002-12-29 19:13:07 +00:00
respprep ( & resp , p , msg , req , msgrest ) ;
2007-06-03 06:10:27 +00:00
mgr = ast_calloc ( 1 , sizeof ( * mgr ) + resp . len + 1 ) ;
2004-05-21 06:05:20 +00:00
if ( mgr ) {
/* Store MGCP response in case we have to retransmit */
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 ] = " " ;
int x ;
struct sockaddr_in dest ;
2005-01-06 08:16:43 +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 ) {
2006-07-21 17:31:28 +00:00
ast_verbose ( " We're at %s port %d \n " , ast_inet_ntoa ( p - > parent - > ourip ) , ntohs ( sin . sin_port ) ) ;
2005-01-06 08:16:43 +00:00
}
2007-10-01 15:23:19 +00:00
ast_copy_string ( v , " v=0 \r \n " , sizeof ( v ) ) ;
2007-08-01 18:01:33 +00:00
snprintf ( o , sizeof ( o ) , " o=root %d %d IN IP4 %s \r \n " , ( int ) getpid ( ) , ( int ) getpid ( ) , ast_inet_ntoa ( dest . sin_addr ) ) ;
2007-10-01 15:23:19 +00:00
ast_copy_string ( s , " s=session \r \n " , sizeof ( s ) ) ;
2006-07-21 17:31:28 +00:00
snprintf ( c , sizeof ( c ) , " c=IN IP4 %s \r \n " , ast_inet_ntoa ( dest . sin_addr ) ) ;
2007-10-01 15:23:19 +00:00
ast_copy_string ( t , " t=0 0 \r \n " , sizeof ( t ) ) ;
2002-12-29 19:13:07 +00:00
snprintf ( m , sizeof ( m ) , " m=audio %d RTP/AVP " , ntohs ( dest . sin_port ) ) ;
2007-11-06 22:51:48 +00:00
for ( x = 1 ; x < = AST_FORMAT_AUDIO_MASK ; 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 ) ;
2005-01-06 08:16:43 +00:00
}
2003-05-06 04:03:58 +00:00
codec = ast_rtp_lookup_code ( sub - > rtp , 1 , x ) ;
2005-01-06 08:16:43 +00:00
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 ) ;
2006-07-13 01:38:47 +00:00
snprintf ( costr , sizeof ( costr ) , " a=rtpmap:%d %s/8000 \r \n " , codec , ast_rtp_lookup_mime_subtype ( 1 , x , 0 ) ) ;
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 ) {
2005-01-06 08:16:43 +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 ) ;
strncat ( m , costr , sizeof ( m ) - strlen ( m ) - 1 ) ;
2006-07-13 01:38:47 +00:00
snprintf ( costr , sizeof ( costr ) , " a=rtpmap:%d %s/8000 \r \n " , codec , ast_rtp_lookup_mime_subtype ( 0 , x , 0 ) ) ;
2005-01-06 08:16:43 +00:00
strncat ( a , costr , sizeof ( a ) - strlen ( a ) - 1 ) ;
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 ) ;
strncat ( a , costr , sizeof ( a ) - strlen ( a ) - 1 ) ;
}
}
}
}
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 ;
2005-01-06 08:16:43 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2005-05-04 19:17:09 +00:00
if ( ast_strlen_zero ( 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 ;
}
2007-10-01 15:23:19 +00:00
ast_copy_string ( local , " p:20 " , sizeof ( local ) ) ;
2007-11-06 22:51:48 +00:00
for ( x = 1 ; x < = AST_FORMAT_AUDIO_MASK ; x < < = 1 ) {
2004-08-03 17:00:54 +00:00
if ( p - > capability & x ) {
2006-07-13 01:38:47 +00:00
snprintf ( tmp , sizeof ( tmp ) , " , a:%s " , ast_rtp_lookup_mime_subtype ( 1 , x , 0 ) ) ;
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 ] ) ;
2006-07-19 20:44:39 +00:00
/* 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", "");*/
add_sdp ( & resp , sub , rtp ) ;
2006-07-19 20:44:39 +00:00
/* fill in new fields */
2005-01-06 08:16:43 +00:00
resp . cmd = MGCP_CMD_MDCX ;
resp . trid = oseq ;
2004-03-19 22:57:08 +00:00
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 ;
2005-01-06 08:16:43 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2003-05-06 04:03:58 +00:00
2007-10-01 15:23:19 +00:00
ast_copy_string ( local , " p:20 " , sizeof ( local ) ) ;
2007-11-06 22:51:48 +00:00
for ( x = 1 ; x < = AST_FORMAT_AUDIO_MASK ; x < < = 1 ) {
2002-12-29 19:13:07 +00:00
if ( p - > capability & x ) {
2006-07-13 01:38:47 +00:00
snprintf ( tmp , sizeof ( tmp ) , " , a:%s " , ast_rtp_lookup_mime_subtype ( 1 , x , 0 ) ) ;
2004-07-16 04:40:54 +00:00
strncat ( local , tmp , sizeof ( local ) - strlen ( local ) - 1 ) ;
2002-12-29 19:13:07 +00:00
}
}
2005-01-06 08:16:43 +00:00
if ( mgcpdebug ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Creating connection for %s@%s-%d in cxmode: %s callid: %s \n " ,
2005-01-06 08:16:43 +00:00
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 ] ) ;
2006-07-19 20:44:39 +00:00
/* 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", "");*/
add_sdp ( & resp , sub , rtp ) ;
2006-07-19 20:44:39 +00:00
/* fill in new fields */
2005-01-06 08:16:43 +00:00
resp . cmd = MGCP_CMD_CRCX ;
resp . trid = oseq ;
2004-03-19 22:57:08 +00:00
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 ;
2005-01-06 08:16:43 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2003-05-06 04:03:58 +00:00
2005-01-06 08:16:43 +00:00
if ( mgcpdebug ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " MGCP Asked to indicate tone: %s on %s@%s-%d in cxmode: %s \n " ,
2005-01-06 08:16:43 +00:00
tone , p - > name , p - > parent - > name , sub - > id , mgcp_cxmodes [ sub - > cxmode ] ) ;
}
2006-04-21 18:34:38 +00:00
ast_copy_string ( p - > curtone , tone , sizeof ( p - > curtone ) ) ;
2002-12-29 19:13:07 +00:00
reqprep ( & resp , p , " RQNT " ) ;
2004-03-19 22:57:08 +00:00
add_header ( & resp , " X " , p - > rqnt_ident ) ; /* SC */
2005-01-06 08:16:43 +00:00
switch ( p - > hookstate ) {
case MGCP_ONHOOK :
add_header ( & resp , " R " , " L/hd(N) " ) ;
break ;
case MGCP_OFFHOOK :
2008-01-08 20:50:57 +00:00
add_header_offhook ( sub , & resp ) ;
2005-01-06 08:16:43 +00:00
break ;
}
2005-05-04 19:17:09 +00:00
if ( ! ast_strlen_zero ( tone ) ) {
2005-01-06 08:16:43 +00:00
add_header ( & resp , " S " , tone ) ;
}
2006-07-19 20:44:39 +00:00
/* fill in new fields */
2005-01-06 08:16:43 +00:00
resp . cmd = MGCP_CMD_RQNT ;
resp . trid = oseq ;
2004-03-19 22:57:08 +00:00
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 ;
2007-07-18 19:47:20 +00:00
struct timeval t = ast_tvnow ( ) ;
struct ast_tm tm ;
2005-01-06 08:16:43 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2002-12-29 19:13:07 +00:00
2007-06-14 22:09:20 +00:00
ast_localtime ( & t , & tm , NULL ) ;
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
2005-01-06 08:16:43 +00:00
/* Keep track of last callerid for blacklist and callreturn */
2006-04-21 18:34:38 +00:00
ast_copy_string ( p - > lastcallerid , l , sizeof ( p - > lastcallerid ) ) ;
2003-05-06 04:03:58 +00:00
2003-03-24 21:46:06 +00:00
snprintf ( tone2 , sizeof ( tone2 ) , " %s,L/ci(%02d/%02d/%02d/%02d,%s,%s) " , tone ,
2005-01-06 08:16:43 +00:00
tm . tm_mon + 1 , tm . tm_mday , tm . tm_hour , tm . tm_min , l , n ) ;
2006-04-21 18:34:38 +00:00
ast_copy_string ( p - > curtone , tone , sizeof ( p - > curtone ) ) ;
2002-12-29 19:13:07 +00:00
reqprep ( & resp , p , " RQNT " ) ;
2004-03-19 22:57:08 +00:00
add_header ( & resp , " X " , p - > rqnt_ident ) ; /* SC */
2005-01-06 08:16:43 +00:00
switch ( p - > hookstate ) {
case MGCP_ONHOOK :
add_header ( & resp , " R " , " L/hd(N) " ) ;
break ;
case MGCP_OFFHOOK :
2008-01-08 20:50:57 +00:00
add_header_offhook ( sub , & resp ) ;
2005-01-06 08:16:43 +00:00
break ;
}
2005-05-04 19:17:09 +00:00
if ( ! ast_strlen_zero ( tone2 ) ) {
2005-01-06 08:16:43 +00:00
add_header ( & resp , " S " , tone2 ) ;
}
if ( mgcpdebug ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " MGCP Asked to indicate tone: %s on %s@%s-%d in cxmode: %s \n " ,
2005-01-06 08:16:43 +00:00
tone2 , p - > name , p - > parent - > name , sub - > id , mgcp_cxmodes [ sub - > cxmode ] ) ;
}
2006-07-19 20:44:39 +00:00
/* fill in new fields */
2005-01-06 08:16:43 +00:00
resp . cmd = MGCP_CMD_RQNT ;
resp . trid = oseq ;
2004-03-19 22:57:08 +00:00
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 ;
2005-01-06 08:16:43 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2005-05-04 19:17:09 +00:00
if ( ast_strlen_zero ( sub - > cxident ) ) {
2003-05-06 04:03:58 +00:00
/* We don't have a CXident yet, store the destination and
wait a bit */
return 0 ;
}
2005-01-06 08:16:43 +00:00
if ( mgcpdebug ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Modified %s@%s-%d with new mode: %s on callid: %s \n " ,
2005-01-06 08:16:43 +00:00
p - > name , p - > parent - > name , sub - > id , mgcp_cxmodes [ sub - > cxmode ] , sub - > callid ) ;
}
2003-05-06 04:03:58 +00:00
reqprep ( & resp , p , " MDCX " ) ;
add_header ( & resp , " C " , sub - > callid ) ;
add_header ( & resp , " M " , mgcp_cxmodes [ sub - > cxmode ] ) ;
2006-07-19 20:44:39 +00:00
/* 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 ) ;
2005-01-06 08:16:43 +00:00
switch ( sub - > parent - > hookstate ) {
case MGCP_ONHOOK :
add_header ( & resp , " R " , " L/hd(N) " ) ;
break ;
case MGCP_OFFHOOK :
2008-01-08 20:50:57 +00:00
add_header_offhook ( sub , & resp ) ;
2005-01-06 08:16:43 +00:00
break ;
}
2006-07-19 20:44:39 +00:00
/* fill in new fields */
2005-01-06 08:16:43 +00:00
resp . cmd = MGCP_CMD_MDCX ;
resp . trid = oseq ;
2004-03-19 22:57:08 +00:00
return send_request ( p , sub , & resp , oseq ) ; /* SC */
2003-05-06 04:03:58 +00:00
}
2008-01-08 20:50:57 +00:00
static void add_header_offhook ( struct mgcp_subchannel * sub , struct mgcp_request * resp )
{
struct mgcp_endpoint * p = sub - > parent ;
if ( p & & p - > sub & & p - > sub - > owner & & p - > sub - > owner - > _state > = AST_STATE_RINGING & & ( p - > dtmfmode & ( MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID ) ) )
add_header ( resp , " R " , " L/hu(N),L/hf(N) " ) ;
else
add_header ( resp , " R " , " L/hu(N),L/hf(N),D/[0-9#*](N) " ) ;
}
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 " ) ;
2006-07-19 20:44:39 +00:00
/* removed unknown param VS */
2005-01-06 08:16:43 +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 " ) ;
2006-07-19 20:44:39 +00:00
/* fill in new fields */
2005-01-06 08:16:43 +00:00
resp . cmd = MGCP_CMD_AUEP ;
resp . trid = oseq ;
2004-03-19 22:57:08 +00:00
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
{
2005-01-06 08:16:43 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2002-12-29 19:13:07 +00:00
struct mgcp_request resp ;
2005-01-06 08:16:43 +00:00
if ( mgcpdebug ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Delete connection %s %s@%s-%d with new mode: %s on callid: %s \n " ,
2005-01-06 08:16:43 +00:00
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 " ) ;
2006-07-19 20:44:39 +00:00
/* check if call id is avail */
2005-01-06 08:16:43 +00:00
if ( sub - > callid [ 0 ] )
add_header ( & resp , " C " , sub - > callid ) ;
2006-07-19 20:44:39 +00:00
/* X header should not be sent. kept for compatibility */
2003-05-06 04:03:58 +00:00
add_header ( & resp , " X " , sub - > txident ) ;
2006-07-19 20:44:39 +00:00
/* check if cxident is avail */
2005-01-06 08:16:43 +00:00
if ( sub - > cxident [ 0 ] )
add_header ( & resp , " I " , sub - > cxident ) ;
2006-07-19 20:44:39 +00:00
/* fill in new fields */
2005-01-06 08:16:43 +00:00
resp . cmd = MGCP_CMD_DLCX ;
resp . trid = oseq ;
2004-03-19 22:57:08 +00:00
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 ;
2005-01-06 08:16:43 +00:00
if ( mgcpdebug ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Delete connection %s %s@%s on callid: %s \n " ,
2005-01-06 08:16:43 +00:00
cxident ? cxident : " " , p - > name , p - > parent - > name , callid ? callid : " " ) ;
}
2004-03-27 17:51:22 +00:00
reqprep ( & resp , p , " DLCX " ) ;
2006-07-19 20:44:39 +00:00
/* check if call id is avail */
2005-01-06 08:16:43 +00:00
if ( callid & & * callid )
add_header ( & resp , " C " , callid ) ;
2006-07-19 20:44:39 +00:00
/* check if cxident is avail */
2005-01-06 08:16:43 +00:00
if ( cxident & & * cxident )
add_header ( & resp , " I " , cxident ) ;
2006-07-19 20:44:39 +00:00
/* fill in new fields */
2005-01-06 08:16:43 +00:00
resp . cmd = MGCP_CMD_DLCX ;
resp . trid = oseq ;
2004-03-27 17:51:22 +00:00
return send_request ( p , p - > sub , & resp , oseq ) ;
}
2006-01-21 05:15:56 +00:00
/*! \brief dump_cmd_queues: (SC:) cleanup pending commands */
2004-03-19 22:57:08 +00:00
static void dump_cmd_queues ( struct mgcp_endpoint * p , struct mgcp_subchannel * sub )
2002-12-29 19:13:07 +00:00
{
2005-01-06 08:16:43 +00:00
struct mgcp_request * t , * q ;
if ( p ) {
ast_mutex_lock ( & p - > rqnt_queue_lock ) ;
2007-06-03 06:10:27 +00:00
for ( q = p - > rqnt_queue ; q ; t = q - > next , ast_free ( q ) , q = t ) ;
2005-01-06 08:16:43 +00:00
p - > rqnt_queue = NULL ;
ast_mutex_unlock ( & p - > rqnt_queue_lock ) ;
ast_mutex_lock ( & p - > cmd_queue_lock ) ;
2007-06-03 06:10:27 +00:00
for ( q = p - > cmd_queue ; q ; t = q - > next , ast_free ( q ) , q = t ) ;
2005-01-06 08:16:43 +00:00
p - > cmd_queue = NULL ;
ast_mutex_unlock ( & p - > cmd_queue_lock ) ;
ast_mutex_lock ( & p - > sub - > cx_queue_lock ) ;
2007-06-03 06:10:27 +00:00
for ( q = p - > sub - > cx_queue ; q ; t = q - > next , ast_free ( q ) , q = t ) ;
2005-01-06 08:16:43 +00:00
p - > sub - > cx_queue = NULL ;
ast_mutex_unlock ( & p - > sub - > cx_queue_lock ) ;
ast_mutex_lock ( & p - > sub - > next - > cx_queue_lock ) ;
2007-06-03 06:10:27 +00:00
for ( q = p - > sub - > next - > cx_queue ; q ; t = q - > next , ast_free ( q ) , q = t ) ;
2005-01-06 08:16:43 +00:00
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 ) ;
2007-06-03 06:10:27 +00:00
for ( q = sub - > cx_queue ; q ; t = q - > next , ast_free ( q ) , q = t ) ;
2005-01-06 08:16:43 +00:00
sub - > cx_queue = NULL ;
ast_mutex_unlock ( & sub - > cx_queue_lock ) ;
}
2004-03-19 22:57:08 +00:00
}
2006-01-21 05:15:56 +00:00
/*! \brief find_command: (SC:) remove command transaction from queue */
2004-03-19 22:57:08 +00:00
static struct mgcp_request * find_command ( struct mgcp_endpoint * p , struct mgcp_subchannel * sub ,
struct mgcp_request * * queue , ast_mutex_t * l , int ident )
{
2005-01-06 08:16:43 +00:00
struct mgcp_request * prev , * req ;
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +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 ,
2006-07-21 17:31:28 +00:00
ast_inet_ntoa ( p - > parent - > addr . sin_addr ) , ntohs ( p - > parent - > addr . sin_port ) ) ;
2005-01-06 08:16:43 +00:00
}
mgcp_postrequest ( p , sub , ( * queue ) - > data , ( * queue ) - > len , ( * queue ) - > trid ) ;
}
break ;
}
}
ast_mutex_unlock ( l ) ;
return req ;
2004-03-19 22:57:08 +00:00
}
2006-07-19 20:44:39 +00:00
/* modified for new transport mechanism */
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
{
2005-01-06 08:16:43 +00:00
char * c ;
struct mgcp_request * req ;
struct mgcp_gateway * gw = p - > parent ;
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
if ( result < 200 ) {
/* provisional response */
return ;
}
2004-03-19 22:57:08 +00:00
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 )
2005-01-06 08:16:43 +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 ) ;
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
if ( ! req ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " No command found on [%s] for transaction %d. Ignoring... \n " ,
2005-01-06 08:16:43 +00:00
gw - > name , ident ) ;
return ;
}
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
if ( p & & ( result > = 400 ) & & ( result < = 599 ) ) {
switch ( result ) {
case 401 :
p - > hookstate = MGCP_OFFHOOK ;
break ;
case 402 :
p - > hookstate = MGCP_ONHOOK ;
break ;
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 ;
}
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 ) ;
mgcp_queue_hangup ( sub ) ;
}
} 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 ) ;
mgcp_queue_hangup ( p - > sub ) ;
}
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +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 ) ;
mgcp_queue_hangup ( p - > sub ) ;
}
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
dump_cmd_queues ( p , NULL ) ;
}
}
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
if ( resp ) {
if ( req - > cmd = = MGCP_CMD_CRCX ) {
if ( ( c = get_header ( resp , " I " ) ) ) {
2005-05-04 19:17:09 +00:00
if ( ! ast_strlen_zero ( c ) & & sub ) {
2006-07-19 20:44:39 +00:00
/* if we are hanging up do not process this conn. */
2005-01-06 08:16:43 +00:00
if ( sub - > owner ) {
2005-05-04 19:17:09 +00:00
if ( ! ast_strlen_zero ( sub - > cxident ) ) {
2005-01-06 08:16:43 +00:00
if ( strcasecmp ( c , sub - > cxident ) ) {
ast_log ( LOG_WARNING , " Subchannel already has a cxident. sub->cxident: %s requested %s \n " , sub - > cxident , c ) ;
}
}
2006-04-21 18:34:38 +00:00
ast_copy_string ( sub - > cxident , c , sizeof ( sub - > cxident ) ) ;
2005-01-06 08:16:43 +00:00
if ( sub - > tmpdest . sin_addr . s_addr ) {
transmit_modify_with_sdp ( sub , NULL , 0 ) ;
}
} else {
2006-07-19 20:44:39 +00:00
/* XXX delete this one
2005-01-06 08:16:43 +00:00
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 ) ;
}
}
}
}
2004-03-27 17:51:22 +00:00
2005-01-06 08:16:43 +00:00
if ( req - > cmd = = MGCP_CMD_AUEP ) {
2006-07-19 20:44:39 +00:00
/* check stale connection ids */
2005-01-06 08:16:43 +00:00
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 */
2006-08-16 18:58:43 +00:00
char cxident [ 80 ] = " " ;
if ( len > ( sizeof ( cxident ) - 1 ) )
len = sizeof ( cxident ) - 1 ;
ast_copy_string ( cxident , v , len ) ;
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Non existing connection id %s on %s@%s \n " ,
2006-08-16 18:58:43 +00:00
cxident , p - > name , gw - > name ) ;
2005-01-06 08:16:43 +00:00
transmit_connection_del_w_params ( p , NULL , cxident ) ;
}
}
c = n ;
}
}
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
/* Try to determine the hookstate returned from an audit endpoint command */
if ( ( c = get_header ( resp , " ES " ) ) ) {
2005-05-04 19:17:09 +00:00
if ( ! ast_strlen_zero ( c ) ) {
2005-01-06 08:16:43 +00:00
if ( strstr ( c , " hu " ) ) {
if ( p - > hookstate ! = MGCP_ONHOOK ) {
2006-07-19 20:44:39 +00:00
/* XXX cleanup if we think we are offhook XXX */
2005-01-06 08:16:43 +00:00
if ( ( p - > sub - > owner | | p - > sub - > next - > owner ) & &
p - > hookstate = = MGCP_OFFHOOK )
mgcp_queue_hangup ( sub ) ;
p - > hookstate = MGCP_ONHOOK ;
2006-07-19 20:44:39 +00:00
/* update the requested events according to the new hookstate */
2005-01-06 08:16:43 +00:00
transmit_notify_request ( p - > sub , " " ) ;
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Setting hookstate of %s@%s to ONHOOK \n " , p - > name , gw - > name ) ;
2005-01-06 08:16:43 +00:00
}
} else if ( strstr ( c , " hd " ) ) {
if ( p - > hookstate ! = MGCP_OFFHOOK ) {
p - > hookstate = MGCP_OFFHOOK ;
2006-07-19 20:44:39 +00:00
/* update the requested events according to the new hookstate */
2005-01-06 08:16:43 +00:00
transmit_notify_request ( p - > sub , " " ) ;
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Setting hookstate of %s@%s to OFFHOOK \n " , p - > name , gw - > name ) ;
2005-01-06 08:16:43 +00:00
}
}
}
}
}
if ( resp & & resp - > lines ) {
2006-07-19 20:44:39 +00:00
/* do not process sdp if we are hanging up. this may be a late response */
2005-01-06 08:16:43 +00:00
if ( sub & & sub - > owner ) {
if ( ! sub - > rtp )
start_rtp ( sub ) ;
if ( sub - > rtp )
process_sdp ( sub , resp ) ;
}
}
}
2004-03-19 22:57:08 +00:00
2007-06-03 06:10:27 +00:00
ast_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
{
2005-01-06 08:16:43 +00:00
ast_mutex_lock ( & sub - > lock ) ;
2006-07-19 20:44:39 +00:00
/* check again to be on the safe side */
2005-01-06 08:16:43 +00:00
if ( sub - > rtp ) {
ast_rtp_destroy ( sub - > rtp ) ;
sub - > rtp = NULL ;
}
/* Allocate the RTP now */
sub - > rtp = ast_rtp_new_with_bindaddr ( sched , io , 1 , 0 , bindaddr . sin_addr ) ;
if ( sub - > rtp & & sub - > owner )
2007-08-08 21:44:58 +00:00
ast_channel_set_fd ( sub - > owner , 0 , ast_rtp_fd ( sub - > rtp ) ) ;
2007-12-16 10:51:53 +00:00
if ( sub - > rtp ) {
2008-08-09 14:12:34 +00:00
ast_rtp_setqos ( sub - > rtp , qos . tos_audio , qos . cos_audio , " MGCP RTP " ) ;
2005-01-06 08:16:43 +00:00
ast_rtp_setnat ( sub - > rtp , sub - > nat ) ;
2007-12-16 10:51:53 +00:00
}
2003-02-12 13:59:15 +00:00
#if 0
2005-01-06 08:16:43 +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
2005-01-06 08:16:43 +00:00
/* Make a call*ID */
2006-04-05 17:44:44 +00:00
snprintf ( sub - > callid , sizeof ( sub - > callid ) , " %08lx%s " , ast_random ( ) , sub - > txident ) ;
2005-01-06 08:16:43 +00:00
/* Transmit the connection create */
transmit_connect_with_sdp ( sub , NULL ) ;
ast_mutex_unlock ( & sub - > lock ) ;
2002-12-29 19:13:07 +00:00
}
static void * mgcp_ss ( void * data )
{
struct ast_channel * chan = data ;
2005-03-04 06:47:24 +00:00
struct mgcp_subchannel * sub = chan - > tech_pvt ;
2003-05-06 04:03:58 +00:00
struct mgcp_endpoint * p = sub - > parent ;
2007-06-04 22:39:10 +00:00
/* char exten[AST_MAX_EXTENSION] = ""; */
2003-05-06 04:03:58 +00:00
int len = 0 ;
int timeout = firstdigittimeout ;
2007-06-04 22:39:10 +00:00
int res = 0 ;
2005-01-06 08:16:43 +00:00
int getforward = 0 ;
2007-06-04 22:39:10 +00:00
int loop_pause = 100 ;
len = strlen ( p - > dtmf_buf ) ;
2005-01-06 08:16:43 +00:00
while ( len < AST_MAX_EXTENSION - 1 ) {
2007-06-04 22:39:10 +00:00
res = 1 ; /* Assume that we will get a digit */
while ( strlen ( p - > dtmf_buf ) = = len ) {
ast_safe_sleep ( chan , loop_pause ) ;
timeout - = loop_pause ;
2007-12-03 21:00:44 +00:00
if ( timeout < = 0 ) {
2007-06-04 22:39:10 +00:00
res = 0 ;
break ;
}
res = 1 ;
2005-01-06 08:16:43 +00:00
}
2007-06-04 22:39:10 +00:00
timeout = 0 ;
len = strlen ( p - > dtmf_buf ) ;
if ( ! ast_ignore_pattern ( chan - > context , p - > dtmf_buf ) ) {
2005-01-06 08:16:43 +00:00
/*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
2003-05-06 04:03:58 +00:00
ast_indicate ( chan , - 1 ) ;
2005-01-06 08:16:43 +00:00
} else {
/* XXX Redundant? We should already be playing dialtone */
2008-06-12 17:27:55 +00:00
/*tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALTONE);*/
2005-01-06 08:16:43 +00:00
transmit_notify_request ( sub , " L/dl " ) ;
}
2007-06-04 22:39:10 +00:00
if ( ast_exists_extension ( chan , chan - > context , p - > dtmf_buf , 1 , p - > cid_num ) ) {
if ( ! res | | ! ast_matchmore_extension ( chan , chan - > context , p - > dtmf_buf , 1 , p - > cid_num ) ) {
2005-01-06 08:16:43 +00:00
if ( getforward ) {
/* Record this as the forwarding extension */
2007-06-04 22:39:10 +00:00
ast_copy_string ( p - > call_forward , p - > dtmf_buf , sizeof ( p - > call_forward ) ) ;
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Setting call forward to '%s' on channel %s \n " ,
2005-01-06 08:16:43 +00:00
p - > call_forward , chan - > name ) ;
2008-06-12 17:27:55 +00:00
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
2005-01-06 08:16:43 +00:00
transmit_notify_request ( sub , " L/sl " ) ;
if ( res )
break ;
usleep ( 500000 ) ;
/*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
ast_indicate ( chan , - 1 ) ;
sleep ( 1 ) ;
2007-06-04 22:39:10 +00:00
memset ( p - > dtmf_buf , 0 , sizeof ( p - > dtmf_buf ) ) ;
2008-06-12 17:27:55 +00:00
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALTONE);*/
2005-01-06 08:16:43 +00:00
transmit_notify_request ( sub , " L/dl " ) ;
len = 0 ;
getforward = 0 ;
} else {
/*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
ast_indicate ( chan , - 1 ) ;
2007-06-04 22:39:10 +00:00
ast_copy_string ( chan - > exten , p - > dtmf_buf , sizeof ( chan - > exten ) ) ;
memset ( p - > dtmf_buf , 0 , sizeof ( p - > dtmf_buf ) ) ;
2006-07-03 04:25:21 +00:00
ast_set_callerid ( chan ,
p - > hidecallerid ? " " : p - > cid_num ,
p - > hidecallerid ? " " : p - > cid_name ,
chan - > cid . cid_ani ? NULL : p - > cid_num ) ;
2005-01-06 08:16:43 +00:00
ast_setstate ( chan , AST_STATE_RING ) ;
2008-06-12 17:27:55 +00:00
/*dahdi_enable_ec(p);*/
2005-03-28 20:48:24 +00:00
if ( p - > dtmfmode & MGCP_DTMF_HYBRID ) {
p - > dtmfmode | = MGCP_DTMF_INBAND ;
ast_indicate ( chan , - 1 ) ;
}
2005-01-06 08:16:43 +00:00
res = ast_pbx_run ( chan ) ;
if ( res ) {
ast_log ( LOG_WARNING , " PBX exited non-zero \n " ) ;
2008-06-12 17:27:55 +00:00
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
2005-01-06 08:16:43 +00:00
/*transmit_notify_request(p, "nbz", 1);*/
transmit_notify_request ( sub , " G/cg " ) ;
}
return NULL ;
}
} else {
/* It's a match, but they just typed a digit, and there is an ambiguous match,
so just set the timeout to matchdigittimeout and wait some more */
timeout = matchdigittimeout ;
}
} else if ( res = = 0 ) {
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " not enough digits (and no ambiguous match)... \n " ) ;
2008-06-12 17:27:55 +00:00
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
2005-01-06 08:16:43 +00:00
transmit_notify_request ( sub , " G/cg " ) ;
2008-06-12 17:27:55 +00:00
/*dahdi_wait_event(p->subs[index].zfd);*/
2005-01-06 08:16:43 +00:00
ast_hangup ( chan ) ;
2007-11-30 00:16:45 +00:00
memset ( p - > dtmf_buf , 0 , sizeof ( p - > dtmf_buf ) ) ;
2005-01-06 08:16:43 +00:00
return NULL ;
2007-06-04 22:39:10 +00:00
} else if ( p - > hascallwaiting & & p - > callwaiting & & ! strcmp ( p - > dtmf_buf , " *70 " ) ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Disabling call waiting on %s \n " , chan - > name ) ;
2005-01-06 08:16:43 +00:00
/* Disable call waiting if enabled */
p - > callwaiting = 0 ;
2008-06-12 17:27:55 +00:00
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
2005-01-06 08:16:43 +00:00
transmit_notify_request ( sub , " L/sl " ) ;
len = 0 ;
2007-06-04 22:39:10 +00:00
memset ( p - > dtmf_buf , 0 , sizeof ( p - > dtmf_buf ) ) ;
2005-01-06 08:16:43 +00:00
timeout = firstdigittimeout ;
2007-06-04 22:39:10 +00:00
} else if ( ! strcmp ( p - > dtmf_buf , ast_pickup_ext ( ) ) ) {
2005-01-06 08:16:43 +00:00
/* 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 " ) ;
2008-06-12 17:27:55 +00:00
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
2005-01-06 08:16:43 +00:00
transmit_notify_request ( sub , " G/cg " ) ;
}
2007-06-04 22:39:10 +00:00
memset ( p - > dtmf_buf , 0 , sizeof ( p - > dtmf_buf ) ) ;
2005-01-06 08:16:43 +00:00
ast_hangup ( chan ) ;
return NULL ;
2007-06-04 22:39:10 +00:00
} else if ( ! p - > hidecallerid & & ! strcmp ( p - > dtmf_buf , " *67 " ) ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Disabling Caller*ID on %s \n " , chan - > name ) ;
2005-01-06 08:16:43 +00:00
/* Disable Caller*ID if enabled */
p - > hidecallerid = 1 ;
2006-07-03 04:25:21 +00:00
ast_set_callerid ( chan , " " , " " , NULL ) ;
2008-06-12 17:27:55 +00:00
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
2005-01-06 08:16:43 +00:00
transmit_notify_request ( sub , " L/sl " ) ;
len = 0 ;
2007-06-04 22:39:10 +00:00
memset ( p - > dtmf_buf , 0 , sizeof ( p - > dtmf_buf ) ) ;
2005-01-06 08:16:43 +00:00
timeout = firstdigittimeout ;
2007-06-04 22:39:10 +00:00
} else if ( p - > callreturn & & ! strcmp ( p - > dtmf_buf , " *69 " ) ) {
2005-01-06 08:16:43 +00:00
res = 0 ;
2005-05-04 19:17:09 +00:00
if ( ! ast_strlen_zero ( p - > lastcallerid ) ) {
2005-01-06 08:16:43 +00:00
res = ast_say_digit_str ( chan , p - > lastcallerid , " " , chan - > language ) ;
}
if ( ! res )
2008-06-12 17:27:55 +00:00
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
2005-01-06 08:16:43 +00:00
transmit_notify_request ( sub , " L/sl " ) ;
break ;
2007-06-04 22:39:10 +00:00
} else if ( ! strcmp ( p - > dtmf_buf , " *78 " ) ) {
2005-01-06 08:16:43 +00:00
/* Do not disturb */
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Enabled DND on channel %s \n " , chan - > name ) ;
2008-06-12 17:27:55 +00:00
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
2005-01-06 08:16:43 +00:00
transmit_notify_request ( sub , " L/sl " ) ;
p - > dnd = 1 ;
getforward = 0 ;
2007-06-04 22:39:10 +00:00
memset ( p - > dtmf_buf , 0 , sizeof ( p - > dtmf_buf ) ) ;
2005-01-06 08:16:43 +00:00
len = 0 ;
2007-06-04 22:39:10 +00:00
} else if ( ! strcmp ( p - > dtmf_buf , " *79 " ) ) {
2005-01-06 08:16:43 +00:00
/* Do not disturb */
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Disabled DND on channel %s \n " , chan - > name ) ;
2008-06-12 17:27:55 +00:00
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
2005-01-06 08:16:43 +00:00
transmit_notify_request ( sub , " L/sl " ) ;
p - > dnd = 0 ;
getforward = 0 ;
2007-06-04 22:39:10 +00:00
memset ( p - > dtmf_buf , 0 , sizeof ( p - > dtmf_buf ) ) ;
2005-01-06 08:16:43 +00:00
len = 0 ;
2007-06-04 22:39:10 +00:00
} else if ( p - > cancallforward & & ! strcmp ( p - > dtmf_buf , " *72 " ) ) {
2008-06-12 17:27:55 +00:00
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
2005-01-06 08:16:43 +00:00
transmit_notify_request ( sub , " L/sl " ) ;
getforward = 1 ;
2007-06-04 22:39:10 +00:00
memset ( p - > dtmf_buf , 0 , sizeof ( p - > dtmf_buf ) ) ;
2005-01-06 08:16:43 +00:00
len = 0 ;
2007-06-04 22:39:10 +00:00
} else if ( p - > cancallforward & & ! strcmp ( p - > dtmf_buf , " *73 " ) ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Cancelling call forwarding on channel %s \n " , chan - > name ) ;
2008-06-12 17:27:55 +00:00
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
2005-01-06 08:16:43 +00:00
transmit_notify_request ( sub , " L/sl " ) ;
memset ( p - > call_forward , 0 , sizeof ( p - > call_forward ) ) ;
getforward = 0 ;
2007-06-04 22:39:10 +00:00
memset ( p - > dtmf_buf , 0 , sizeof ( p - > dtmf_buf ) ) ;
2005-01-06 08:16:43 +00:00
len = 0 ;
2007-06-04 22:39:10 +00:00
} else if ( ! strcmp ( p - > dtmf_buf , ast_parking_ext ( ) ) & &
2005-01-06 08:16:43 +00:00
sub - > next - > owner & & ast_bridged_channel ( sub - > next - > owner ) ) {
/* This is a three way call, the main call being a real channel,
and we ' re parking the first call . */
ast_masq_park_call ( ast_bridged_channel ( sub - > next - > owner ) , chan , 0 , NULL ) ;
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Parking call to '%s' \n " , chan - > name ) ;
2005-01-06 08:16:43 +00:00
break ;
2007-06-04 22:39:10 +00:00
} else if ( ! ast_strlen_zero ( p - > lastcallerid ) & & ! strcmp ( p - > dtmf_buf , " *60 " ) ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Blacklisting number %s \n " , p - > lastcallerid ) ;
2005-01-06 08:16:43 +00:00
res = ast_db_put ( " blacklist " , p - > lastcallerid , " 1 " ) ;
if ( ! res ) {
2008-06-12 17:27:55 +00:00
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
2005-01-06 08:16:43 +00:00
transmit_notify_request ( sub , " L/sl " ) ;
2007-06-04 22:39:10 +00:00
memset ( p - > dtmf_buf , 0 , sizeof ( p - > dtmf_buf ) ) ;
2005-01-06 08:16:43 +00:00
len = 0 ;
}
2007-06-04 22:39:10 +00:00
} else if ( p - > hidecallerid & & ! strcmp ( p - > dtmf_buf , " *82 " ) ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Enabling Caller*ID on %s \n " , chan - > name ) ;
2005-01-06 08:16:43 +00:00
/* Enable Caller*ID if enabled */
p - > hidecallerid = 0 ;
2006-07-03 04:25:21 +00:00
ast_set_callerid ( chan , p - > cid_num , p - > cid_name , NULL ) ;
2008-06-12 17:27:55 +00:00
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
2005-01-06 08:16:43 +00:00
transmit_notify_request ( sub , " L/sl " ) ;
len = 0 ;
2007-06-04 22:39:10 +00:00
memset ( p - > dtmf_buf , 0 , sizeof ( p - > dtmf_buf ) ) ;
2005-01-06 08:16:43 +00:00
timeout = firstdigittimeout ;
2007-06-04 22:39:10 +00:00
} else if ( ! ast_canmatch_extension ( chan , chan - > context , p - > dtmf_buf , 1 , chan - > cid . cid_num ) & &
( ( p - > dtmf_buf [ 0 ] ! = ' * ' ) | | ( strlen ( p - > dtmf_buf ) > 2 ) ) ) {
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " Can't match %s from '%s' in context %s \n " , p - > dtmf_buf , chan - > cid . cid_num ? chan - > cid . cid_num : " <Unknown Caller> " , chan - > context ) ;
2005-01-06 08:16:43 +00:00
break ;
}
if ( ! timeout )
timeout = gendigittimeout ;
2007-06-04 22:39:10 +00:00
if ( len & & ! ast_ignore_pattern ( chan - > context , p - > dtmf_buf ) )
2005-01-06 08:16:43 +00:00
/*tone_zone_play_tone(p->subs[index].zfd, -1);*/
2003-05-06 04:03:58 +00:00
ast_indicate ( chan , - 1 ) ;
2005-01-06 08:16:43 +00:00
}
2003-05-06 04:03:58 +00:00
#if 0
2002-12-29 19:13:07 +00:00
for ( ; ; ) {
res = ast_waitfordigit ( chan , to ) ;
if ( ! res ) {
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " Timeout... \n " ) ;
2002-12-29 19:13:07 +00:00
break ;
}
if ( res < 0 ) {
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " Got hangup... \n " ) ;
2005-01-06 08:16:43 +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 ) ) {
2006-04-21 18:34:38 +00:00
ast_copy_string ( chan - > exten , exten , sizeof ( chan - > exten ) 1 ) ;
2005-01-06 08:16:43 +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 ) ;
2007-06-04 22:39:10 +00:00
} else {
memset ( p - > dtmf_buf , 0 , sizeof ( p - > dtmf_buf ) ) ;
2002-12-29 19:13:07 +00:00
return NULL ;
2007-06-04 22:39:10 +00:00
}
2002-12-29 19:13:07 +00:00
}
2003-05-06 04:03:58 +00:00
# endif
2002-12-29 19:13:07 +00:00
ast_hangup ( chan ) ;
2007-06-04 22:39:10 +00:00
memset ( p - > dtmf_buf , 0 , sizeof ( p - > dtmf_buf ) ) ;
2002-12-29 19:13:07 +00:00
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
{
2005-01-06 08:16:43 +00:00
/* *************************
* I hope this works .
* Copied out of chan_zap
* Cross your fingers
* * * * * * * * * * * * * * * * * * * * * * * * * */
2003-05-06 04:03:58 +00:00
/* 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 ) )
2006-07-19 20:44:39 +00:00
ast_queue_control ( p - > sub - > next - > owner , AST_CONTROL_UNHOLD ) ;
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 " ,
2005-01-06 08:16:43 +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
}
2006-07-19 20:44:39 +00:00
ast_queue_control ( p - > sub - > next - > owner , AST_CONTROL_UNHOLD ) ;
2004-10-23 12:19:47 +00:00
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 " ,
2005-01-06 08:16:43 +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);*/
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Swapping %d for %d on %s@%s \n " , p - > sub - > id , p - > sub - > next - > id , p - > name , p - > parent - > name ) ;
2005-01-06 08:16:43 +00:00
p - > sub = p - > sub - > next ;
2003-05-06 04:03:58 +00:00
unalloc_sub ( p - > sub - > next ) ;
/* Tell the caller not to hangup */
return 1 ;
} else {
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " Neither %s nor %s are in a bridge, nothing to transfer \n " ,
p - > sub - > owner - > name , p - > sub - > next - > owner - > name ) ;
2003-05-06 04:03:58 +00:00
p - > sub - > next - > owner - > _softhangup | = AST_SOFTHANGUP_DEV ;
2005-01-06 08:16:43 +00:00
if ( p - > sub - > next - > owner ) {
p - > sub - > next - > alreadygone = 1 ;
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 )
{
2005-01-06 08:16:43 +00:00
struct mgcp_endpoint * p = sub - > parent ;
struct ast_channel * c ;
2002-12-29 19:13:07 +00:00
pthread_t t ;
2003-05-06 04:03:58 +00:00
2005-01-06 08:16:43 +00:00
/* Off hook / answer */
if ( sub - > outgoing ) {
/* Answered */
if ( sub - > owner ) {
2006-07-19 20:44:39 +00:00
if ( ast_bridged_channel ( sub - > owner ) )
ast_queue_control ( sub - > owner , AST_CONTROL_UNHOLD ) ;
2005-01-06 08:16:43 +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 , " " ) ;
mgcp_queue_control ( sub , AST_CONTROL_ANSWER ) ;
}
} 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
2005-01-06 08:16:43 +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 ) ;
transmit_notify_request ( sub , " G/cg " ) ;
ast_hangup ( c ) ;
}
} else {
if ( has_voicemail ( p ) ) {
transmit_notify_request ( sub , " L/sl " ) ;
} else {
transmit_notify_request ( sub , " L/dl " ) ;
}
c = mgcp_new ( sub , AST_STATE_DOWN ) ;
if ( c ) {
2007-05-24 18:30:19 +00:00
if ( ast_pthread_create_detached ( & t , NULL , mgcp_ss , c ) ) {
2005-01-06 08:16:43 +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 ) {
ast_log ( LOG_WARNING , " Off hook, but already have owner on %s@%s \n " , p - > name , p - > parent - > name ) ;
} else {
ast_log ( LOG_WARNING , " On hook, but already have owner on %s@%s \n " , p - > name , p - > parent - > name ) ;
2006-09-28 18:09:01 +00:00
ast_log ( LOG_WARNING , " If we're onhook why are we here trying to handle a hd or hf? \n " ) ;
2005-01-06 08:16:43 +00:00
}
2006-07-19 20:44:39 +00:00
if ( ast_bridged_channel ( sub - > owner ) )
ast_queue_control ( sub - > owner , AST_CONTROL_UNHOLD ) ;
2005-01-06 08:16:43 +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 , " " ) ;
/*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 , } ;
2005-01-06 08:16:43 +00:00
struct mgcp_endpoint * p = sub - > parent ;
struct mgcp_gateway * g = NULL ;
int res ;
2003-05-06 04:03:58 +00:00
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 ) ;
2005-01-06 08:16:43 +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 " ) ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Received keepalive request from %s@%s \n " , p - > name , p - > parent - > name ) ;
2003-06-29 14:36:21 +00:00
transmit_response ( sub , " 200 " , req , " OK " ) ;
} else {
2004-03-19 22:57:08 +00:00
dump_queue ( p - > parent , p ) ;
2005-01-06 08:16:43 +00:00
dump_cmd_queues ( p , NULL ) ;
2004-04-26 05:18:55 +00:00
2007-07-26 15:49:18 +00:00
if ( ( strcmp ( p - > name , p - > parent - > wcardep ) ! = 0 ) ) {
ast_verb ( 3 , " Resetting interface %s@%s \n " , p - > name , p - > parent - > name ) ;
2004-04-26 05:18:55 +00:00
}
2006-07-19 20:44:39 +00:00
/* 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 ;
2005-01-06 08:16:43 +00:00
2004-04-26 05:18:55 +00:00
g = p - > parent ;
tmp_ep = g - > endpoints ;
while ( tmp_ep ) {
2005-01-06 08:16:43 +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 ;
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Resetting interface %s@%s \n " , tmp_ep - > name , p - > parent - > name ) ;
2004-04-26 05:18:55 +00:00
first_sub = tmp_ep - > sub ;
tmp_sub = tmp_ep - > sub ;
while ( tmp_sub ) {
2005-01-06 08:16:43 +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 ;
2005-01-06 08:16:43 +00:00
}
2004-04-26 05:18:55 +00:00
}
tmp_ep = tmp_ep - > next ;
}
} else if ( sub - > owner ) {
2005-01-06 08:16:43 +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 " ) ;
2006-07-19 20:44:39 +00:00
/* We dont send NTFY or AUEP to wildcard ep */
2004-04-26 05:18:55 +00:00
if ( strcmp ( p - > name , p - > parent - > wcardep ) ! = 0 ) {
transmit_notify_request ( sub , " " ) ;
2006-07-19 20:44:39 +00:00
/* Audit endpoint.
2004-04-26 05:18:55 +00:00
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 ;
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " 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 ) ;
2005-01-06 08:16:43 +00:00
}
2002-12-29 19:13:07 +00:00
if ( ! strcasecmp ( ev , " hd " ) ) {
2005-01-06 08:16:43 +00:00
p - > hookstate = MGCP_OFFHOOK ;
sub - > cxmode = MGCP_CX_SENDRECV ;
handle_hd_hf ( sub , ev ) ;
2003-05-06 04:03:58 +00:00
} else if ( ! strcasecmp ( ev , " hf " ) ) {
2005-01-06 08:16:43 +00:00
/* 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 ;
}
/* do not let * conference two down channels */
if ( sub - > owner & & sub - > owner - > _state = = AST_STATE_DOWN & & ! sub - > next - > owner )
return - 1 ;
if ( p - > callwaiting | | p - > transfer | | p - > threewaycalling ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Swapping %d for %d on %s@%s \n " , p - > sub - > id , p - > sub - > next - > id , p - > name , p - > parent - > name ) ;
2005-01-06 08:16:43 +00:00
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 ;
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " MGCP Muting %d on %s@%s \n " , sub - > id , p - > name , p - > parent - > name ) ;
2005-01-06 08:16:43 +00:00
transmit_modify_request ( sub ) ;
2006-07-19 20:44:39 +00:00
if ( sub - > owner & & ast_bridged_channel ( sub - > owner ) )
ast_queue_control ( sub - > owner , AST_CONTROL_HOLD ) ;
2005-01-06 08:16:43 +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 */
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " MGCP Conferencing %d and %d on %s@%s \n " ,
2005-01-06 08:16:43 +00:00
sub - > id , sub - > next - > id , p - > name , p - > parent - > name ) ;
sub - > cxmode = MGCP_CX_CONF ;
sub - > next - > cxmode = MGCP_CX_CONF ;
2006-07-19 20:44:39 +00:00
if ( ast_bridged_channel ( sub - > next - > owner ) )
ast_queue_control ( sub - > next - > owner , AST_CONTROL_UNHOLD ) ;
2005-01-06 08:16:43 +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 */
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " We didn't make one of the calls FLIPFLOP %d and %d on %s@%s \n " ,
2005-01-06 08:16:43 +00:00
sub - > id , sub - > next - > id , p - > name , p - > parent - > name ) ;
sub - > cxmode = MGCP_CX_MUTE ;
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " MGCP Muting %d on %s@%s \n " , sub - > id , p - > name , p - > parent - > name ) ;
2005-01-06 08:16:43 +00:00
transmit_modify_request ( sub ) ;
2006-07-19 20:44:39 +00:00
if ( ast_bridged_channel ( sub - > owner ) )
ast_queue_control ( sub - > owner , AST_CONTROL_HOLD ) ;
2004-10-23 12:19:47 +00:00
2005-01-06 08:16:43 +00:00
if ( ast_bridged_channel ( sub - > next - > owner ) )
2006-07-19 20:44:39 +00:00
ast_queue_control ( sub - > next - > owner , AST_CONTROL_HOLD ) ;
2004-10-23 12:19:47 +00:00
2005-01-06 08:16:43 +00:00
handle_hd_hf ( sub - > next , ev ) ;
}
} 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 ;
}
2006-07-19 20:44:39 +00:00
if ( ast_bridged_channel ( p - > sub - > owner ) )
ast_queue_control ( p - > sub - > owner , AST_CONTROL_UNHOLD ) ;
2005-01-06 08:16:43 +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 ) ;
}
2002-12-29 19:13:07 +00:00
} else if ( ! strcasecmp ( ev , " hu " ) ) {
2005-01-06 08:16:43 +00:00
p - > hookstate = MGCP_ONHOOK ;
sub - > cxmode = MGCP_CX_RECVONLY ;
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " MGCP %s@%s Went on hook \n " , p - > name , p - > parent - > name ) ;
2006-07-19 20:44:39 +00:00
/* Do we need to send MDCX before a DLCX ?
2005-01-06 08:16:43 +00:00
if ( sub - > rtp ) {
transmit_modify_request ( sub ) ;
}
*/
if ( p - > transfer & & ( sub - > owner & & sub - > next - > owner ) & & ( ( ! sub - > outgoing ) | | ( ! sub - > next - > outgoing ) ) ) {
/* We're allowed to transfer, we have two avtive calls and */
/* we made at least one of the calls. Let's try and transfer */
2004-11-07 21:46:09 +00:00
ast_mutex_lock ( & p - > sub - > next - > lock ) ;
res = attempt_transfer ( p ) ;
2005-01-06 08:16:43 +00:00
if ( res < 0 ) {
if ( p - > sub - > next - > owner ) {
sub - > next - > alreadygone = 1 ;
mgcp_queue_hangup ( sub - > next ) ;
}
} 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 ) ;
2005-01-06 08:16:43 +00:00
return - 1 ;
}
2004-11-07 21:46:09 +00:00
ast_mutex_unlock ( & p - > sub - > next - > lock ) ;
2005-01-06 08:16:43 +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 ;
mgcp_queue_hangup ( sub ) ;
} else {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " MGCP handle_request(%s@%s-%d) ast_channel already destroyed, resending DLCX. \n " ,
2005-01-10 00:43:01 +00:00
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 ) ;
2005-01-06 08:16:43 +00:00
}
}
if ( ( p - > hookstate = = MGCP_ONHOOK ) & & ( ! sub - > rtp ) & & ( ! sub - > next - > rtp ) ) {
2005-04-11 05:48:58 +00:00
p - > hidecallerid = 0 ;
if ( p - > hascallwaiting & & ! p - > callwaiting ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Enabling call waiting on MGCP/%s@%s-%d \n " , p - > name , p - > parent - > name , sub - > id ) ;
2005-04-11 05:48:58 +00:00
p - > callwaiting = - 1 ;
}
2005-01-06 08:16:43 +00:00
if ( has_voicemail ( p ) ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " MGCP handle_request(%s@%s) set vmwi(+) \n " , p - > name , p - > parent - > name ) ;
2005-01-06 08:16:43 +00:00
transmit_notify_request ( sub , " L/vmwi(+) " ) ;
} else {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " MGCP handle_request(%s@%s) set vmwi(-) \n " , p - > name , p - > parent - > name ) ;
2005-01-06 08:16:43 +00:00
transmit_notify_request ( sub , " L/vmwi(-) " ) ;
}
}
2002-12-29 19:13:07 +00:00
} else if ( ( strlen ( ev ) = = 1 ) & &
2005-01-06 08:16:43 +00:00
( ( ( ev [ 0 ] > = ' 0 ' ) & & ( ev [ 0 ] < = ' 9 ' ) ) | |
( ( ev [ 0 ] > = ' A ' ) & & ( ev [ 0 ] < = ' D ' ) ) | |
( ev [ 0 ] = = ' * ' ) | | ( ev [ 0 ] = = ' # ' ) ) ) {
2007-08-21 15:23:12 +00:00
if ( sub & & sub - > owner & & ( sub - > owner - > _state > = AST_STATE_UP ) ) {
2007-06-04 22:39:10 +00:00
f . frametype = AST_FRAME_DTMF ;
f . subclass = ev [ 0 ] ;
f . src = " mgcp " ;
2007-08-21 15:23:12 +00:00
/* XXX MUST queue this frame to all subs in threeway call if threeway call is active */
mgcp_queue_frame ( sub , & f ) ;
ast_mutex_lock ( & sub - > next - > lock ) ;
if ( sub - > next - > owner )
mgcp_queue_frame ( sub - > next , & f ) ;
ast_mutex_unlock ( & sub - > next - > lock ) ;
2007-06-04 22:39:10 +00:00
if ( strstr ( p - > curtone , " wt " ) & & ( ev [ 0 ] = = ' A ' ) ) {
memset ( p - > curtone , 0 , sizeof ( p - > curtone ) ) ;
}
} else {
p - > dtmf_buf [ strlen ( p - > dtmf_buf ) ] = ev [ 0 ] ;
p - > dtmf_buf [ strlen ( p - > dtmf_buf ) ] = ' \0 ' ;
2005-01-06 08:16:43 +00:00
}
} else if ( ! strcasecmp ( ev , " T " ) ) {
2002-12-29 19:13:07 +00:00
/* Digit timeout -- unimportant */
2005-01-06 08:16:43 +00:00
} else if ( ! strcasecmp ( ev , " ping " ) ) {
2004-07-30 18:02:18 +00:00
/* 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 {
2006-07-21 17:31:28 +00:00
ast_log ( LOG_WARNING , " Unknown verb '%s' received from %s \n " , req - > verb , ast_inet_ntoa ( sin - > sin_addr ) ) ;
2003-05-06 04:03:58 +00:00
transmit_response ( sub , " 510 " , req , " Unknown verb " ) ;
2002-12-29 19:13:07 +00:00
}
return 0 ;
}
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 ;
2007-06-03 06:10:27 +00:00
ast_free ( cur ) ;
2004-05-21 06:05:20 +00:00
} 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 ;
2005-05-15 03:21:51 +00:00
socklen_t len ;
2002-12-29 19:13:07 +00:00
int result ;
int ident ;
len = sizeof ( sin ) ;
memset ( & req , 0 , sizeof ( req ) ) ;
res = recvfrom ( mgcpsock , req . data , sizeof ( req . data ) - 1 , 0 , ( struct sockaddr * ) & sin , & len ) ;
if ( res < 0 ) {
if ( errno ! = ECONNREFUSED )
ast_log ( LOG_WARNING , " Recv error: %s \n " , strerror ( errno ) ) ;
return 1 ;
}
req . data [ res ] = ' \0 ' ;
req . len = res ;
2003-05-06 04:03:58 +00:00
if ( mgcpdebug ) {
2006-07-21 17:31:28 +00:00
ast_verbose ( " MGCP read: \n %s \n from %s:%d \n " , req . data , ast_inet_ntoa ( sin . sin_addr ) , ntohs ( sin . sin_port ) ) ;
2005-01-06 08:16:43 +00:00
}
2002-12-29 19:13:07 +00:00
parse ( & req ) ;
if ( req . headers < 1 ) {
/* Must have at least one header */
return 1 ;
}
2005-10-27 02:19:37 +00:00
if ( ast_strlen_zero ( req . identifier ) ) {
2006-07-21 17:31:28 +00:00
ast_log ( LOG_NOTICE , " Message from %s missing identifier \n " , ast_inet_ntoa ( sin . sin_addr ) ) ;
2002-12-29 19:13:07 +00:00
return 1 ;
}
2005-01-06 08:16:43 +00:00
if ( sscanf ( req . verb , " %d " , & result ) & & sscanf ( req . identifier , " %d " , & ident ) ) {
2002-12-29 19:13:07 +00:00
/* 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 ) {
2005-01-06 08:16:43 +00:00
struct mgcp_gateway * gw = sub - > parent - > parent ;
struct mgcp_message * cur , * prev ;
2004-03-19 22:57:08 +00:00
2004-11-07 21:46:09 +00:00
ast_mutex_unlock ( & sub - > lock ) ;
2005-01-06 08:16:43 +00:00
ast_mutex_lock ( & gw - > msgs_lock ) ;
for ( prev = NULL , cur = gw - > msgs ; cur ; prev = cur , cur = cur - > next ) {
if ( cur - > seqno = = ident ) {
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " Got response back on transaction %d \n " , ident ) ;
2005-01-06 08:16:43 +00:00
if ( prev )
prev - > next = cur - > next ;
else
gw - > msgs = cur - > next ;
break ;
}
}
2003-05-06 04:03:58 +00:00
2005-01-06 08:16:43 +00:00
/* stop retrans timer if the queue is empty */
2008-01-27 22:35:29 +00:00
if ( ! gw - > msgs ) {
AST_SCHED_DEL ( sched , gw - > retransid ) ;
2005-01-06 08:16:43 +00:00
}
2003-05-06 04:03:58 +00:00
2005-01-06 08:16:43 +00:00
ast_mutex_unlock ( & gw - > msgs_lock ) ;
if ( cur ) {
handle_response ( cur - > owner_ep , cur - > owner_sub , result , ident , & req ) ;
2007-06-03 06:10:27 +00:00
ast_free ( cur ) ;
2005-01-06 08:16:43 +00:00
return 1 ;
}
2003-05-06 04:03:58 +00:00
2005-01-06 08:16:43 +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 {
2005-10-27 02:19:37 +00:00
if ( ast_strlen_zero ( req . endpoint ) | |
ast_strlen_zero ( req . version ) | |
ast_strlen_zero ( req . verb ) ) {
2002-12-29 19:13:07 +00:00
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 ) )
2005-01-06 08:16:43 +00:00
/* pass the request off to the currently mastering subchannel */
2004-05-21 06:05:20 +00:00
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 ;
2005-01-06 08:16:43 +00:00
/*struct mgcp_gateway *g;*/
/*struct mgcp_endpoint *e;*/
2003-05-06 04:03:58 +00:00
/*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 ( ; ; ) {
2005-01-06 08:16:43 +00:00
/* Check for a reload request */
2004-03-19 22:57:08 +00:00
ast_mutex_lock ( & mgcp_reload_lock ) ;
reloading = mgcp_reloading ;
mgcp_reloading = 0 ;
ast_mutex_unlock ( & mgcp_reload_lock ) ;
if ( reloading ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 1 , " Reloading MGCP \n " ) ;
2007-08-16 21:09:46 +00:00
reload_config ( 1 ) ;
2004-07-16 21:22:55 +00:00
/* Add an I/O event to our UDP socket */
2008-10-28 21:38:26 +00:00
if ( mgcpsock > - 1 & & ! mgcpsock_read_id ) {
2004-07-16 21:22:55 +00:00
mgcpsock_read_id = ast_io_add ( io , mgcpsock , mgcpsock_read , AST_IO_IN , NULL ) ;
2008-10-28 21:38:26 +00:00
}
2004-03-19 22:57:08 +00:00
}
2005-01-06 08:16:43 +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
#if 0
2005-01-06 08:16:43 +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 */
lastpass = thispass ;
thispass = time ( NULL ) ;
g = gateways ;
while ( g ) {
if ( thispass ! = lastpass ) {
e = g - > endpoints ;
while ( e ) {
if ( e - > type = = TYPE_LINE ) {
res = has_voicemail ( e ) ;
if ( ( e - > msgstate ! = res ) & & ( e - > hookstate = = MGCP_ONHOOK ) & & ( ! e - > rtp ) ) {
if ( res ) {
transmit_notify_request ( e , " L/vmwi(+) " ) ;
} else {
transmit_notify_request ( e , " L/vmwi(-) " ) ;
}
e - > msgstate = res ;
e - > onhooktime = thispass ;
}
}
e = e - > next ;
}
}
g = g - > next ;
}
2003-05-06 04:03:58 +00:00
# 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 ) ;
2006-07-19 20:44:39 +00:00
/* copied from chan_sip.c */
2004-03-19 22:57:08 +00:00
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 )
{
/* 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 */
2006-10-04 19:51:38 +00:00
if ( ast_pthread_create_background ( & monitor_thread , NULL , 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 ;
}
2006-04-21 18:34:38 +00:00
ast_copy_string ( tmp , dest , sizeof ( tmp ) ) ;
2005-05-04 19:17:09 +00:00
if ( ast_strlen_zero ( tmp ) ) {
2002-12-29 19:13:07 +00:00
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
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " MGCP mgcp_request(%s) \n " , tmp ) ;
ast_verb ( 3 , " MGCP cw: %d, dnd: %d, so: %d, sno: %d \n " ,
2005-01-06 08:16:43 +00:00
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 ) ) ) | |
2005-01-06 08:16:43 +00:00
( ( ! sub - > parent - > callwaiting ) & & ( sub - > owner ) ) | |
2005-05-04 19:17:09 +00:00
( sub - > parent - > dnd & & ( ast_strlen_zero ( sub - > parent - > call_forward ) ) ) ) {
2005-01-06 08:16:43 +00:00
if ( sub - > parent - > hookstate = = MGCP_ONHOOK ) {
if ( has_voicemail ( sub - > parent ) ) {
transmit_notify_request ( sub , " L/vmwi(+) " ) ;
} else {
transmit_notify_request ( sub , " L/vmwi(-) " ) ;
}
}
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 ;
2005-01-06 08:16:43 +00:00
}
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 ;
}
2006-07-19 20:44:39 +00:00
/* modified for reload support */
2006-01-21 05:15:56 +00:00
/*! \brief build_gateway: parse mgcp.conf and create gateway/endpoint structures */
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 ;
2005-01-06 08:16:43 +00:00
struct mgcp_subchannel * sub ;
/*char txident[80];*/
int i = 0 , y = 0 ;
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
2006-07-19 20:44:39 +00:00
/* locate existing gateway */
2005-01-06 08:16:43 +00:00
gw = gateways ;
while ( gw ) {
if ( ! strcasecmp ( cat , gw - > name ) ) {
/* gateway already exists */
gw - > delme = 0 ;
gw_reload = 1 ;
break ;
}
gw = gw - > next ;
}
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
if ( ! gw )
2007-06-03 06:10:27 +00:00
gw = ast_calloc ( 1 , sizeof ( * gw ) ) ;
2004-03-19 22:57:08 +00:00
2002-12-29 19:13:07 +00:00
if ( gw ) {
2005-01-06 08:16:43 +00:00
if ( ! gw_reload ) {
gw - > expire = - 1 ;
gw - > retransid = - 1 ; /* SC */
ast_mutex_init ( & gw - > msgs_lock ) ;
2006-04-21 18:34:38 +00:00
ast_copy_string ( gw - > name , cat , sizeof ( gw - > name ) ) ;
2006-07-19 20:44:39 +00:00
/* check if the name is numeric ip */
2005-01-06 08:16:43 +00:00
if ( ( strchr ( gw - > name , ' . ' ) ) & & inet_addr ( gw - > name ) ! = INADDR_NONE )
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 */
2008-01-27 22:35:29 +00:00
AST_SCHED_DEL ( sched , gw - > expire ) ;
2003-03-09 06:00:18 +00:00
gw - > dynamic = 0 ;
if ( ast_get_ip ( & gw - > addr , v - > value ) ) {
2005-01-06 08:16:43 +00:00
if ( ! gw_reload ) {
ast_mutex_destroy ( & gw - > msgs_lock ) ;
2007-06-03 06:10:27 +00:00
ast_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 ) ) {
2005-01-06 08:16:43 +00:00
if ( ! gw_reload ) {
ast_mutex_destroy ( & gw - > msgs_lock ) ;
2007-06-03 06:10:27 +00:00
ast_free ( gw ) ;
2005-01-06 08:16:43 +00:00
}
2002-12-29 19:13:07 +00:00
return NULL ;
}
} else if ( ! strcasecmp ( v - > name , " permit " ) | |
2005-01-06 08:16:43 +00:00
! strcasecmp ( v - > name , " deny " ) ) {
2007-01-01 19:20:46 +00:00
gw - > ha = ast_append_ha ( v - > name , v - > value , gw - > ha , NULL ) ;
2002-12-29 19:13:07 +00:00
} else if ( ! strcasecmp ( v - > name , " port " ) ) {
gw - > addr . sin_port = htons ( atoi ( v - > value ) ) ;
} else if ( ! strcasecmp ( v - > name , " context " ) ) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( context , v - > value , sizeof ( context ) ) ;
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 ;
2005-03-28 20:48:24 +00:00
else if ( ! strcasecmp ( v - > value , " hybrid " ) )
dtmfmode = MGCP_DTMF_HYBRID ;
2004-07-26 19:33:36 +00:00
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 " ) ) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( language , v - > value , sizeof ( language ) ) ;
2005-01-06 08:16:43 +00:00
} else if ( ! strcasecmp ( v - > name , " accountcode " ) ) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( accountcode , v - > value , sizeof ( accountcode ) ) ;
2005-01-06 08:16:43 +00:00
} 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 " ) ) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( musicclass , v - > value , sizeof ( musicclass ) ) ;
2008-04-21 23:42:45 +00:00
} else if ( ! strcasecmp ( v - > name , " parkinglot " ) ) {
ast_copy_string ( parkinglot , v - > value , sizeof ( parkinglot ) ) ;
2005-01-06 08:16:43 +00:00
} else if ( ! strcasecmp ( v - > name , " callgroup " ) ) {
cur_callergroup = ast_get_group ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " pickupgroup " ) ) {
cur_pickupgroup = ast_get_group ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " immediate " ) ) {
immediate = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " cancallforward " ) ) {
cancallforward = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " singlepath " ) ) {
singlepath = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " canreinvite " ) ) {
canreinvite = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " mailbox " ) ) {
2006-10-25 14:44:50 +00:00
ast_copy_string ( mailbox , v - > value , sizeof ( mailbox ) ) ;
2008-06-16 19:57:05 +00:00
} else if ( ! strcasecmp ( v - > name , " hasvoicemail " ) ) {
if ( ast_true ( v - > value ) & & ast_strlen_zero ( mailbox ) ) {
ast_copy_string ( mailbox , gw - > name , sizeof ( mailbox ) ) ;
}
2005-01-06 08:16:43 +00:00
} 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 ) ;
} else if ( ! strcasecmp ( v - > name , " slowsequence " ) ) {
slowsequence = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " transfer " ) ) {
transfer = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " threewaycalling " ) ) {
threewaycalling = ast_true ( v - > value ) ;
2004-04-26 05:18:55 +00:00
} else if ( ! strcasecmp ( v - > name , " wcardep " ) ) {
2006-07-19 20:44:39 +00:00
/* locate existing endpoint */
2005-01-06 08:16:43 +00:00
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 ) {
/* Allocate wildcard endpoint */
2007-06-03 06:10:27 +00:00
e = ast_calloc ( 1 , sizeof ( * e ) ) ;
2005-01-06 08:16:43 +00:00
ep_reload = 0 ;
}
2004-04-26 05:18:55 +00:00
if ( e ) {
if ( ! ep_reload ) {
2005-01-06 08:16:43 +00:00
memset ( e , 0 , sizeof ( struct mgcp_endpoint ) ) ;
ast_mutex_init ( & e - > lock ) ;
ast_mutex_init ( & e - > rqnt_queue_lock ) ;
ast_mutex_init ( & e - > cmd_queue_lock ) ;
2006-10-25 14:44:50 +00:00
ast_copy_string ( e - > name , v - > value , sizeof ( e - > name ) ) ;
2005-01-06 08:16:43 +00:00
e - > needaudit = 1 ;
}
2006-10-25 14:44:50 +00:00
ast_copy_string ( gw - > wcardep , v - > value , sizeof ( gw - > wcardep ) ) ;
2004-04-26 05:18:55 +00:00
/* XXX Should we really check for uniqueness?? XXX */
2006-10-25 14:44:50 +00:00
ast_copy_string ( e - > accountcode , accountcode , sizeof ( e - > accountcode ) ) ;
ast_copy_string ( e - > context , context , sizeof ( e - > context ) ) ;
ast_copy_string ( e - > cid_num , cid_num , sizeof ( e - > cid_num ) ) ;
ast_copy_string ( e - > cid_name , cid_name , sizeof ( e - > cid_name ) ) ;
ast_copy_string ( e - > language , language , sizeof ( e - > language ) ) ;
ast_copy_string ( e - > musicclass , musicclass , sizeof ( e - > musicclass ) ) ;
ast_copy_string ( e - > mailbox , mailbox , sizeof ( e - > mailbox ) ) ;
2008-04-21 23:42:45 +00:00
ast_copy_string ( e - > parkinglot , parkinglot , sizeof ( e - > parkinglot ) ) ;
2007-04-28 21:01:44 +00:00
if ( ! ast_strlen_zero ( e - > mailbox ) ) {
2008-08-09 14:12:34 +00:00
char * mbox , * cntx ;
cntx = mbox = ast_strdupa ( e - > mailbox ) ;
strsep ( & cntx , " @ " ) ;
if ( ast_strlen_zero ( cntx ) )
cntx = " default " ;
2007-04-28 21:01:44 +00:00
e - > mwi_event_sub = ast_event_subscribe ( AST_EVENT_MWI , mwi_event_cb , NULL ,
2008-08-09 14:12:34 +00:00
AST_EVENT_IE_MAILBOX , AST_EVENT_IE_PLTYPE_STR , mbox ,
AST_EVENT_IE_CONTEXT , AST_EVENT_IE_PLTYPE_STR , cntx ,
2007-04-28 21:01:44 +00:00
AST_EVENT_IE_NEWMSGS , AST_EVENT_IE_PLTYPE_EXISTS ,
AST_EVENT_IE_END ) ;
}
2006-04-05 17:44:44 +00:00
snprintf ( e - > rqnt_ident , sizeof ( e - > rqnt_ident ) , " %08lx " , ast_random ( ) ) ;
2005-01-06 08:16:43 +00:00
e - > msgstate = - 1 ;
2005-04-05 21:40:37 +00:00
e - > amaflags = amaflags ;
2004-04-26 05:18:55 +00:00
e - > capability = capability ;
e - > parent = gw ;
2004-07-26 19:33:36 +00:00
e - > dtmfmode = dtmfmode ;
2005-03-29 06:16:49 +00:00
if ( ! ep_reload & & e - > sub & & e - > sub - > rtp )
2005-03-28 20:48:24 +00:00
e - > dtmfmode | = MGCP_DTMF_INBAND ;
2004-04-26 05:18:55 +00:00
e - > adsi = adsi ;
e - > type = TYPE_LINE ;
2005-01-06 08:16:43 +00:00
e - > immediate = immediate ;
e - > callgroup = cur_callergroup ;
e - > pickupgroup = cur_pickupgroup ;
e - > callreturn = callreturn ;
e - > cancallforward = cancallforward ;
e - > singlepath = singlepath ;
e - > canreinvite = canreinvite ;
e - > callwaiting = callwaiting ;
2005-04-11 05:48:58 +00:00
e - > hascallwaiting = callwaiting ;
2005-01-06 08:16:43 +00:00
e - > slowsequence = slowsequence ;
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 ) {
2006-04-05 17:44:44 +00:00
/*snprintf(txident, sizeof(txident), "%08lx", ast_random());*/
2004-08-01 21:25:35 +00:00
for ( i = 0 ; i < MAX_SUBS ; i + + ) {
2007-06-03 06:10:27 +00:00
sub = ast_calloc ( 1 , sizeof ( * sub ) ) ;
2004-08-01 21:25:35 +00:00
if ( sub ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Allocating subchannel '%d' on %s@%s \n " , i , e - > name , gw - > name ) ;
2004-08-01 21:25:35 +00:00
ast_mutex_init ( & sub - > lock ) ;
ast_mutex_init ( & sub - > cx_queue_lock ) ;
sub - > parent = e ;
sub - > id = i ;
2006-04-05 17:44:44 +00:00
snprintf ( sub - > txident , sizeof ( sub - > txident ) , " %08lx " , ast_random ( ) ) ;
2004-08-01 21:25:35 +00:00
/*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 */
2006-09-28 18:09:01 +00:00
ast_log ( LOG_WARNING , " Out of memory allocating subchannel \n " ) ;
2004-08-01 21:25:35 +00:00
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
2006-07-19 20:44:39 +00:00
/* locate existing endpoint */
2005-01-06 08:16:43 +00:00
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 ) {
2007-06-03 06:10:27 +00:00
e = ast_calloc ( 1 , sizeof ( * e ) ) ;
2005-01-06 08:16:43 +00:00
ep_reload = 0 ;
}
2004-03-19 22:57:08 +00:00
2002-12-29 19:13:07 +00:00
if ( e ) {
2005-01-06 08:16:43 +00:00
if ( ! ep_reload ) {
ast_mutex_init ( & e - > lock ) ;
ast_mutex_init ( & e - > rqnt_queue_lock ) ;
ast_mutex_init ( & e - > cmd_queue_lock ) ;
2006-10-25 14:44:50 +00:00
ast_copy_string ( e - > name , v - > value , sizeof ( e - > name ) ) ;
2005-01-06 08:16:43 +00:00
e - > needaudit = 1 ;
}
2002-12-29 19:13:07 +00:00
/* XXX Should we really check for uniqueness?? XXX */
2006-10-25 14:44:50 +00:00
ast_copy_string ( e - > accountcode , accountcode , sizeof ( e - > accountcode ) ) ;
ast_copy_string ( e - > context , context , sizeof ( e - > context ) ) ;
ast_copy_string ( e - > cid_num , cid_num , sizeof ( e - > cid_num ) ) ;
ast_copy_string ( e - > cid_name , cid_name , sizeof ( e - > cid_name ) ) ;
ast_copy_string ( e - > language , language , sizeof ( e - > language ) ) ;
ast_copy_string ( e - > musicclass , musicclass , sizeof ( e - > musicclass ) ) ;
ast_copy_string ( e - > mailbox , mailbox , sizeof ( e - > mailbox ) ) ;
2008-04-21 23:42:45 +00:00
ast_copy_string ( e - > parkinglot , parkinglot , sizeof ( e - > parkinglot ) ) ;
2005-05-04 19:17:09 +00:00
if ( ! ast_strlen_zero ( mailbox ) ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Setting mailbox '%s' on %s@%s \n " , mailbox , gw - > name , e - > name ) ;
2005-01-06 08:16:43 +00:00
}
if ( ! ep_reload ) {
2006-07-19 20:44:39 +00:00
/* XXX potential issue due to reload */
2005-01-06 08:16:43 +00:00
e - > msgstate = - 1 ;
e - > parent = gw ;
}
2005-04-05 21:40:37 +00:00
e - > amaflags = amaflags ;
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
2005-01-06 08:16:43 +00:00
e - > immediate = immediate ;
e - > callgroup = cur_callergroup ;
e - > pickupgroup = cur_pickupgroup ;
e - > callreturn = callreturn ;
e - > cancallforward = cancallforward ;
e - > canreinvite = canreinvite ;
e - > singlepath = singlepath ;
e - > callwaiting = callwaiting ;
2005-04-11 05:48:58 +00:00
e - > hascallwaiting = callwaiting ;
2005-01-06 08:16:43 +00:00
e - > slowsequence = slowsequence ;
e - > transfer = transfer ;
e - > threewaycalling = threewaycalling ;
if ( ! ep_reload ) {
e - > onhooktime = time ( NULL ) ;
/* ASSUME we're onhook */
e - > hookstate = MGCP_ONHOOK ;
2006-04-05 17:44:44 +00:00
snprintf ( e - > rqnt_ident , sizeof ( e - > rqnt_ident ) , " %08lx " , ast_random ( ) ) ;
2005-01-06 08:16:43 +00:00
}
for ( i = 0 , sub = NULL ; i < MAX_SUBS ; i + + ) {
if ( ! ep_reload ) {
2007-06-03 06:10:27 +00:00
sub = ast_calloc ( 1 , sizeof ( * sub ) ) ;
2005-01-06 08:16:43 +00:00
} else {
if ( ! sub )
sub = e - > sub ;
else
sub = sub - > next ;
}
if ( sub ) {
if ( ! ep_reload ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Allocating subchannel '%d' on %s@%s \n " , i , e - > name , gw - > name ) ;
2005-01-06 08:16:43 +00:00
ast_mutex_init ( & sub - > lock ) ;
ast_mutex_init ( & sub - > cx_queue_lock ) ;
2006-10-25 14:44:50 +00:00
ast_copy_string ( sub - > magic , MGCP_SUBCHANNEL_MAGIC , sizeof ( sub - > magic ) ) ;
2005-01-06 08:16:43 +00:00
sub - > parent = e ;
sub - > id = i ;
2006-04-05 17:44:44 +00:00
snprintf ( sub - > txident , sizeof ( sub - > txident ) , " %08lx " , ast_random ( ) ) ;
2005-01-06 08:16:43 +00:00
sub - > cxmode = MGCP_CX_INACTIVE ;
sub - > next = e - > sub ;
e - > sub = sub ;
}
sub - > nat = nat ;
} else {
/* XXX Should find a way to clean up our memory */
2006-09-28 18:09:01 +00:00
ast_log ( LOG_WARNING , " Out of memory allocating subchannel \n " ) ;
2005-01-06 08:16:43 +00:00
return NULL ;
}
}
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 ;
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 ) ;
2005-01-06 08:16:43 +00:00
if ( ! gw_reload ) {
ast_mutex_destroy ( & gw - > msgs_lock ) ;
2007-06-03 06:10:27 +00:00
ast_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
}
2006-08-28 17:37:56 +00:00
static enum ast_rtp_get_result mgcp_get_rtp_peer ( struct ast_channel * chan , struct ast_rtp * * rtp )
2003-02-16 06:00:12 +00:00
{
2006-08-28 17:37:56 +00:00
struct mgcp_subchannel * sub = NULL ;
if ( ! ( sub = chan - > tech_pvt ) | | ! ( sub - > rtp ) )
return AST_RTP_GET_FAILED ;
* rtp = sub - > rtp ;
if ( sub - > parent - > canreinvite )
return AST_RTP_TRY_NATIVE ;
else
return AST_RTP_TRY_PARTIAL ;
2003-02-16 06:00:12 +00:00
}
2007-02-16 13:35:44 +00:00
static int mgcp_set_rtp_peer ( struct ast_channel * chan , struct ast_rtp * rtp , struct ast_rtp * vrtp , struct ast_rtp * trtp , int codecs , int nat_active )
2003-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 ;
2005-03-04 06:47:24 +00:00
sub = chan - > tech_pvt ;
2005-12-20 17:52:31 +00:00
if ( sub & & ! sub - > alreadygone ) {
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 = {
2006-02-01 23:05:28 +00:00
. type = " MGCP " ,
2005-03-04 06:47:24 +00:00
. get_rtp_info = mgcp_get_rtp_peer ,
. set_rtp_peer = mgcp_set_rtp_peer ,
2003-02-16 06:00:12 +00:00
} ;
2004-03-19 22:57:08 +00:00
static void destroy_endpoint ( struct mgcp_endpoint * e )
{
2005-01-06 08:16:43 +00:00
struct mgcp_subchannel * sub = e - > sub - > next , * s ;
int i ;
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
for ( i = 0 ; i < MAX_SUBS ; i + + ) {
ast_mutex_lock ( & sub - > lock ) ;
2005-05-04 19:17:09 +00:00
if ( ! ast_strlen_zero ( sub - > cxident ) ) {
2005-01-06 08:16:43 +00:00
transmit_connection_del ( sub ) ;
}
if ( sub - > rtp ) {
ast_rtp_destroy ( sub - > rtp ) ;
sub - > rtp = NULL ;
}
memset ( sub - > magic , 0 , sizeof ( sub - > magic ) ) ;
mgcp_queue_hangup ( sub ) ;
dump_cmd_queues ( NULL , sub ) ;
ast_mutex_unlock ( & sub - > lock ) ;
sub = sub - > next ;
}
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
if ( e - > dsp ) {
ast_dsp_free ( e - > dsp ) ;
}
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
dump_queue ( e - > parent , e ) ;
dump_cmd_queues ( e , NULL ) ;
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
sub = e - > sub ;
for ( i = 0 ; ( i < MAX_SUBS ) & & sub ; i + + ) {
s = sub ;
sub = sub - > next ;
ast_mutex_destroy ( & s - > lock ) ;
ast_mutex_destroy ( & s - > cx_queue_lock ) ;
2007-06-03 06:10:27 +00:00
ast_free ( s ) ;
2005-01-06 08:16:43 +00:00
}
2007-04-28 21:01:44 +00:00
if ( e - > mwi_event_sub )
ast_event_unsubscribe ( e - > mwi_event_sub ) ;
2005-01-06 08:16:43 +00:00
ast_mutex_destroy ( & e - > lock ) ;
ast_mutex_destroy ( & e - > rqnt_queue_lock ) ;
ast_mutex_destroy ( & e - > cmd_queue_lock ) ;
2007-06-03 06:10:27 +00:00
ast_free ( e ) ;
2004-03-19 22:57:08 +00:00
}
static void destroy_gateway ( struct mgcp_gateway * g )
{
2005-01-06 08:16:43 +00:00
if ( g - > ha )
ast_free_ha ( g - > ha ) ;
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
dump_queue ( g , NULL ) ;
2004-03-19 22:57:08 +00:00
2007-06-03 06:10:27 +00:00
ast_free ( g ) ;
2004-03-19 22:57:08 +00:00
}
static void prune_gateways ( void )
{
2005-01-06 08:16:43 +00:00
struct mgcp_gateway * g , * z , * r ;
struct mgcp_endpoint * e , * p , * t ;
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
ast_mutex_lock ( & gatelock ) ;
2004-03-19 22:57:08 +00:00
2005-01-06 08:16:43 +00:00
/* 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 ) ;
2004-03-19 22:57:08 +00:00
}
2007-08-16 21:09:46 +00:00
static int reload_config ( int reload )
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 ;
2002-12-29 19:13:07 +00:00
char * cat ;
2005-01-06 08:16:43 +00:00
struct ast_hostent ahp ;
struct hostent * hp ;
2002-12-29 19:13:07 +00:00
int format ;
2007-08-16 21:09:46 +00:00
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 } ;
2002-12-29 19:13:07 +00:00
2005-05-08 16:44:25 +00:00
if ( gethostname ( ourhost , sizeof ( ourhost ) - 1 ) ) {
2002-12-29 19:13:07 +00:00
ast_log ( LOG_WARNING , " Unable to get hostname, MGCP disabled \n " ) ;
return 0 ;
}
2007-08-16 21:09:46 +00:00
cfg = ast_config_load ( config , config_flags ) ;
2002-12-29 19:13:07 +00:00
/* 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 ;
2008-09-12 23:30:03 +00:00
} else if ( cfg = = CONFIG_STATUS_FILEUNCHANGED ) {
2007-08-16 21:09:46 +00:00
return 0 ;
2008-09-12 23:30:03 +00:00
} else if ( cfg = = CONFIG_STATUS_FILEINVALID ) {
ast_log ( LOG_ERROR , " Config file %s is in an invalid format. Aborting. \n " , config ) ;
return 0 ;
}
2007-08-16 21:09:46 +00:00
2002-12-29 19:13:07 +00:00
memset ( & bindaddr , 0 , sizeof ( bindaddr ) ) ;
2004-07-26 19:37:11 +00:00
dtmfmode = 0 ;
2006-06-01 16:47:28 +00:00
/* Copy the default jb config over global_jbconf */
memcpy ( & global_jbconf , & default_jbconf , sizeof ( struct ast_jb_conf ) ) ;
2002-12-29 19:13:07 +00:00
v = ast_variable_browse ( cfg , " general " ) ;
2006-06-01 16:47:28 +00:00
while ( v ) {
/* handle jb conf */
if ( ! ast_jb_read_conf ( & global_jbconf , v - > name , v - > value ) ) {
v = v - > next ;
continue ;
}
2002-12-29 19:13:07 +00:00
/* 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 " ) ) {
2008-08-09 14:12:34 +00:00
if ( ast_str2tos ( v - > value , & qos . tos ) )
2007-12-16 10:51:53 +00:00
ast_log ( LOG_WARNING , " Invalid tos value at line %d, refer to QoS documentation \n " , v - > lineno ) ;
} else if ( ! strcasecmp ( v - > name , " tos_audio " ) ) {
2008-08-09 14:12:34 +00:00
if ( ast_str2tos ( v - > value , & qos . tos_audio ) )
2007-12-16 10:51:53 +00:00
ast_log ( LOG_WARNING , " Invalid tos_audio value at line %d, refer to QoS documentation \n " , v - > lineno ) ;
2007-04-30 16:16:26 +00:00
} else if ( ! strcasecmp ( v - > name , " cos " ) ) {
2008-08-09 14:12:34 +00:00
if ( ast_str2cos ( v - > value , & qos . cos ) )
2007-12-16 10:51:53 +00:00
ast_log ( LOG_WARNING , " Invalid cos value at line %d, refer to QoS documentation \n " , v - > lineno ) ;
} else if ( ! strcasecmp ( v - > name , " cos_audio " ) ) {
2008-08-09 14:12:34 +00:00
if ( ast_str2cos ( v - > value , & qos . cos_audio ) )
2007-12-16 10:51:53 +00:00
ast_log ( LOG_WARNING , " Invalid cos_audio value at line %d, refer to QoS documentation \n " , v - > lineno ) ;
2002-12-29 19:13:07 +00:00
} else if ( ! strcasecmp ( v - > name , " port " ) ) {
2005-04-29 17:00:33 +00:00
if ( sscanf ( v - > value , " %d " , & ourport ) = = 1 ) {
2002-12-29 19:13:07 +00:00
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
2006-07-19 20:44:39 +00:00
/* mark existing entries for deletion */
2005-01-06 08:16:43 +00:00
ast_mutex_lock ( & gatelock ) ;
g = gateways ;
while ( g ) {
g - > delme = 1 ;
2004-03-19 22:57:08 +00:00
e = g - > endpoints ;
2005-01-06 08:16:43 +00:00
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 " ) ) {
2005-01-06 08:16:43 +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 ) {
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Added gateway '%s' \n " , g - > name ) ;
2004-04-27 21:18:02 +00:00
g - > next = gateways ;
gateways = g ;
}
2005-01-06 08:16:43 +00:00
ast_mutex_unlock ( & gatelock ) ;
2004-04-27 21:18:02 +00:00
/* 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
2006-07-19 20:44:39 +00:00
/* prune deleted entries etc. */
2004-04-27 21:18:02 +00:00
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 " ) ;
2005-01-25 06:10:20 +00:00
ast_config_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 " ,
2006-07-21 17:31:28 +00:00
ast_inet_ntoa ( bindaddr . sin_addr ) , ntohs ( bindaddr . sin_port ) ,
2005-01-06 08:16:43 +00:00
strerror ( errno ) ) ;
2002-12-29 19:13:07 +00:00
close ( mgcpsock ) ;
mgcpsock = - 1 ;
2003-07-30 20:49:23 +00:00
} else {
2007-07-26 15:49:18 +00:00
ast_verb ( 2 , " MGCP Listening on %s:%d \n " ,
2006-07-21 17:31:28 +00:00
ast_inet_ntoa ( bindaddr . sin_addr ) , ntohs ( bindaddr . sin_port ) ) ;
2008-08-09 14:12:34 +00:00
ast_netsock_set_qos ( mgcpsock , qos . tos , qos . cos , " MGCP " ) ;
2005-01-06 08:16:43 +00:00
}
2002-12-29 19:13:07 +00:00
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & netlock ) ;
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2002-12-29 19:13:07 +00:00
2006-07-19 20:44:39 +00:00
/* send audit only to the new endpoints */
2005-01-06 08:16:43 +00:00
g = gateways ;
while ( g ) {
2003-05-06 04:03:58 +00:00
e = g - > endpoints ;
2005-01-06 08:16:43 +00:00
while ( e & & e - > needaudit ) {
e - > needaudit = 0 ;
transmit_audit_endpoint ( e ) ;
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " MGCP Auditing endpoint %s@%s for hookstate \n " , e - > name , g - > name ) ;
2005-01-06 08:16:43 +00:00
e = e - > next ;
}
g = g - > next ;
}
2003-05-06 04:03:58 +00:00
2002-12-29 19:13:07 +00:00
return 0 ;
}
2006-01-21 05:15:56 +00:00
/*! \brief load_module: PBX load module - initialization ---*/
2006-08-21 02:11:39 +00:00
static int load_module ( void )
2004-03-19 22:57:08 +00:00
{
2006-09-21 22:14:31 +00:00
if ( ! ( sched = sched_context_create ( ) ) ) {
2004-03-19 22:57:08 +00:00
ast_log ( LOG_WARNING , " Unable to create schedule context \n " ) ;
2006-09-21 22:14:31 +00:00
return AST_MODULE_LOAD_FAILURE ;
2004-03-19 22:57:08 +00:00
}
2006-09-21 22:14:31 +00:00
if ( ! ( io = io_context_create ( ) ) ) {
2004-03-19 22:57:08 +00:00
ast_log ( LOG_WARNING , " Unable to create I/O context \n " ) ;
2006-09-21 22:14:31 +00:00
sched_context_destroy ( sched ) ;
return AST_MODULE_LOAD_FAILURE ;
2004-03-19 22:57:08 +00:00
}
2007-08-16 21:09:46 +00:00
if ( reload_config ( 0 ) )
2006-08-31 21:00:20 +00:00
return AST_MODULE_LOAD_DECLINE ;
2004-03-19 22:57:08 +00:00
2006-09-21 22:14:31 +00:00
/* Make sure we can register our mgcp channel type */
if ( ast_channel_register ( & mgcp_tech ) ) {
ast_log ( LOG_ERROR , " Unable to register channel class 'MGCP' \n " ) ;
io_context_destroy ( io ) ;
sched_context_destroy ( sched ) ;
return AST_MODULE_LOAD_FAILURE ;
}
ast_rtp_proto_register ( & mgcp_rtp ) ;
ast_cli_register_multiple ( cli_mgcp , sizeof ( cli_mgcp ) / sizeof ( struct ast_cli_entry ) ) ;
/* And start the monitor for the first time */
restart_monitor ( ) ;
return AST_MODULE_LOAD_SUCCESS ;
2004-03-19 22:57:08 +00:00
}
2007-10-11 19:03:06 +00:00
static char * mgcp_reload ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2004-03-19 22:57:08 +00:00
{
2006-11-02 23:16:09 +00:00
static int deprecated = 0 ;
2007-10-11 19:03:06 +00:00
if ( e ) {
switch ( cmd ) {
case CLI_INIT :
e - > command = " mgcp reload " ;
e - > usage =
" Usage: mgcp reload \n "
" 'mgcp reload' is deprecated. Please use 'reload chan_mgcp.so' instead. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
}
if ( ! deprecated & & a & & a - > argc > 0 ) {
2006-11-02 23:16:09 +00:00
ast_log ( LOG_WARNING , " 'mgcp reload' is deprecated. Please use 'reload chan_mgcp.so' instead. \n " ) ;
deprecated = 1 ;
}
2004-03-19 22:57:08 +00:00
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 ( ) ;
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
2004-03-19 22:57:08 +00:00
}
2006-08-21 02:11:39 +00:00
static int reload ( void )
2004-03-19 22:57:08 +00:00
{
2007-10-11 19:03:06 +00:00
mgcp_reload ( NULL , 0 , NULL ) ;
2005-01-06 08:16:43 +00:00
return 0 ;
2004-03-19 22:57:08 +00:00
}
2006-08-21 02:11:39 +00:00
static int unload_module ( void )
2002-12-29 19:13:07 +00:00
{
2005-05-04 00:40:14 +00:00
struct mgcp_endpoint * e ;
struct mgcp_gateway * g ;
/* Check to see if we're reloading */
if ( ast_mutex_trylock ( & mgcp_reload_lock ) ) {
ast_log ( LOG_WARNING , " MGCP is currently reloading. Unable to remove module. \n " ) ;
2002-12-29 19:13:07 +00:00
return - 1 ;
2005-05-04 00:40:14 +00:00
} else {
mgcp_reloading = 1 ;
ast_mutex_unlock ( & mgcp_reload_lock ) ;
2002-12-29 19:13:07 +00:00
}
2005-05-04 00:40:14 +00:00
/* First, take us out of the channel loop */
ast_channel_unregister ( & mgcp_tech ) ;
/* Shut down the monitoring thread */
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 " ) ;
2005-05-04 00:40:14 +00:00
/* We always want to leave this in a consistent state */
ast_channel_register ( & mgcp_tech ) ;
mgcp_reloading = 0 ;
2007-10-11 19:03:06 +00:00
mgcp_reload ( NULL , 0 , NULL ) ;
2002-12-29 19:13:07 +00:00
return - 1 ;
}
2005-05-04 00:40:14 +00:00
if ( ! ast_mutex_lock ( & gatelock ) ) {
2006-07-19 20:44:39 +00:00
for ( g = gateways ; g ; g = g - > next ) {
2005-05-04 00:40:14 +00:00
g - > delme = 1 ;
2006-07-19 20:44:39 +00:00
for ( e = g - > endpoints ; e ; e = e - > next )
2005-05-04 00:40:14 +00:00
e - > delme = 1 ;
2002-12-29 19:13:07 +00:00
}
2005-05-04 00:40:14 +00:00
prune_gateways ( ) ;
ast_mutex_unlock ( & gatelock ) ;
2002-12-29 19:13:07 +00:00
} else {
2005-05-04 00:40:14 +00:00
ast_log ( LOG_WARNING , " Unable to lock the gateways list. \n " ) ;
/* We always want to leave this in a consistent state */
ast_channel_register ( & mgcp_tech ) ;
/* Allow the monitor to restart */
monitor_thread = AST_PTHREADT_NULL ;
mgcp_reloading = 0 ;
2007-10-11 19:03:06 +00:00
mgcp_reload ( NULL , 0 , NULL ) ;
2002-12-29 19:13:07 +00:00
return - 1 ;
}
2005-05-04 00:40:14 +00:00
close ( mgcpsock ) ;
ast_rtp_proto_unregister ( & mgcp_rtp ) ;
2006-09-18 19:54:18 +00:00
ast_cli_unregister_multiple ( cli_mgcp , sizeof ( cli_mgcp ) / sizeof ( struct ast_cli_entry ) ) ;
2006-02-11 19:31:11 +00:00
sched_context_destroy ( sched ) ;
2005-05-04 00:40:14 +00:00
return 0 ;
2002-12-29 19:13:07 +00:00
}
2006-08-21 02:11:39 +00:00
AST_MODULE_INFO ( ASTERISK_GPL_KEY , AST_MODFLAG_DEFAULT , " Media Gateway Control Protocol (MGCP) " ,
. load = load_module ,
. unload = unload_module ,
. reload = reload ,
) ;