📄 chan_mgcp.c
字号:
/* * Asterisk -- An open source telephony toolkit. * * Copyright (C) 1999 - 2006, Digium, Inc. * * Mark Spencer <markster@digium.com> * * 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. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2. See the LICENSE file * at the top of the source tree. *//*! \file * * \brief Implementation of Media Gateway Control Protocol * * \author Mark Spencer <markster@digium.com> * * \par See also * \arg \ref Config_mgcp * * \ingroup channel_drivers *//*** MODULEINFO <depend>res_features</depend> ***/#include "asterisk.h"ASTERISK_FILE_VERSION(__FILE__, "$Revision: 123113 $")#include <stdio.h>#include <string.h>#include <unistd.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <net/if.h>#include <errno.h>#include <stdlib.h>#include <fcntl.h>#include <netdb.h>#include <sys/signal.h>#include <signal.h>#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/ip.h>#include <arpa/inet.h>#include <ctype.h>#include "asterisk/lock.h"#include "asterisk/channel.h"#include "asterisk/config.h"#include "asterisk/logger.h"#include "asterisk/module.h"#include "asterisk/pbx.h"#include "asterisk/options.h"#include "asterisk/lock.h"#include "asterisk/sched.h"#include "asterisk/io.h"#include "asterisk/rtp.h"#include "asterisk/acl.h"#include "asterisk/callerid.h"#include "asterisk/cli.h"#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"#include "asterisk/causes.h"#include "asterisk/dsp.h"#include "asterisk/devicestate.h"#include "asterisk/stringfields.h"#include "asterisk/abstract_jb.h"#ifndef IPTOS_MINCOST#define IPTOS_MINCOST 0x02#endif/* * Define to work around buggy dlink MGCP phone firmware which * appears not to know that "rt" is part of the "G" package. *//* #define DLINK_BUGGY_FIRMWARE */#define MGCPDUMPER#define DEFAULT_EXPIRY 120#define MAX_EXPIRY 3600#define CANREINVITE 1#ifndef INADDR_NONE#define INADDR_NONE (in_addr_t)(-1)#endif/*! 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;static const char tdesc[] = "Media Gateway Control Protocol (MGCP)";static const char config[] = "mgcp.conf";#define MGCP_DTMF_RFC2833 (1 << 0)#define MGCP_DTMF_INBAND (1 << 1)#define MGCP_DTMF_HYBRID (1 << 2)#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 *//*! MGCP rtp stream modes { */#define MGCP_CX_SENDONLY 0#define MGCP_CX_RECVONLY 1#define MGCP_CX_SENDRECV 2#define MGCP_CX_CONF 3#define MGCP_CX_CONFERENCE 3#define MGCP_CX_MUTE 4#define MGCP_CX_INACTIVE 4/*! } */static char *mgcp_cxmodes[] = { "sendonly", "recvonly", "sendrecv", "confrnce", "inactive"};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};static char context[AST_MAX_EXTENSION] = "default";static char language[MAX_LANGUAGE] = "";static char musicclass[MAX_MUSICCLASS] = "";static char cid_num[AST_MAX_EXTENSION] = "";static char cid_name[AST_MAX_EXTENSION] = "";static int dtmfmode = 0;static int nat = 0;static ast_group_t cur_callergroup = 0;static ast_group_t cur_pickupgroup = 0;static int tos = 0;static int immediate = 0;static int callwaiting = 0;static int callreturn = 0;static int slowsequence = 0;static int threewaycalling = 0;/*! This is for flashhook transfers */static int transfer = 0;static int cancallforward = 0;static int singlepath = 0;static int canreinvite = CANREINVITE;static char accountcode[AST_MAX_ACCOUNT_CODE] = "";static char mailbox[AST_MAX_EXTENSION];static int amaflags = 0;static int adsi = 0;static unsigned int oseq;/*! Wait up to 16 seconds for first digit (FXO logic) */static int firstdigittimeout = 16000;/*! How long to wait for following digits (FXO logic) */static int gendigittimeout = 8000;/*! How long to wait for an extra digit, if there is an ambiguous match */static int matchdigittimeout = 3000;/*! Protect the monitoring thread, so only one process can kill or start it, and not when it's doing something critical. */AST_MUTEX_DEFINE_STATIC(netlock);AST_MUTEX_DEFINE_STATIC(monlock);/*! This is the thread for the monitor which checks for input on the channels which are not currently in use. */static pthread_t monitor_thread = AST_PTHREADT_NULL;static int restart_monitor(void);static int capability = AST_FORMAT_ULAW;static int nonCodecCapability = AST_RTP_DTMF;static char ourhost[MAXHOSTNAMELEN];static struct in_addr __ourip;static int ourport;static int mgcpdebug = 0;static struct sched_context *sched;static struct io_context *io;/*! The private structures of the mgcp channels are linked for ! selecting outgoing channels */ #define MGCP_MAX_HEADERS 64#define MGCP_MAX_LINES 64struct mgcp_request { int len; char *verb; char *identifier; char *endpoint; char *version; int headers; /*!< MGCP Headers */ char *header[MGCP_MAX_HEADERS]; int lines; /*!< SDP Content */ char *line[MGCP_MAX_LINES]; char data[MGCP_MAX_PACKET]; int cmd; /*!< int version of verb = command */ unsigned int trid; /*!< int version of identifier = transaction id */ struct mgcp_request *next; /*!< next in the queue */};/*! \brief mgcp_message: MGCP message for queuing up */struct mgcp_message { struct mgcp_endpoint *owner_ep; struct mgcp_subchannel *owner_sub; int retrans; unsigned long expire; unsigned int seqno; int len; struct mgcp_message *next; char buf[0];};#define RESPONSE_TIMEOUT 30 /*!< in seconds */struct mgcp_response { time_t whensent; int len; int seqno; struct mgcp_response *next; char buf[0];};#define MAX_SUBS 2#define SUB_REAL 0#define SUB_ALT 1struct mgcp_subchannel { /*! subchannel magic string. Needed to prove that any subchannel pointer passed by asterisk really points to a valid subchannel memory area. Ugly.. But serves the purpose for the time being. */#define MGCP_SUBCHANNEL_MAGIC "!978!" char magic[6]; ast_mutex_t lock; int id; struct ast_channel *owner; struct mgcp_endpoint *parent; struct ast_rtp *rtp; struct sockaddr_in tmpdest; char txident[80]; /*! \todo FIXME txident is replaced by rqnt_ident in endpoint. This should be obsoleted */ char cxident[80]; char callid[80]; int cxmode; struct mgcp_request *cx_queue; /*!< pending CX commands */ ast_mutex_t cx_queue_lock; /*!< CX queue lock */ int nat; int iseq; /*!< Not used? RTP? */ int outgoing; int alreadygone; struct mgcp_subchannel *next; /*!< for out circular linked list */};#define MGCP_ONHOOK 1#define MGCP_OFFHOOK 2#define TYPE_TRUNK 1#define TYPE_LINE 2struct mgcp_endpoint { ast_mutex_t lock; char name[80]; struct mgcp_subchannel *sub; /*!< Pointer to our current connection, channel and stuff */ char accountcode[AST_MAX_ACCOUNT_CODE]; char exten[AST_MAX_EXTENSION]; /*!< Extention where to start */ char context[AST_MAX_EXTENSION]; char language[MAX_LANGUAGE]; 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 */ char call_forward[AST_MAX_EXTENSION]; /*!< Last Caller*ID */ char mailbox[AST_MAX_EXTENSION]; char musicclass[MAX_MUSICCLASS]; char curtone[80]; /*!< Current tone */ char dtmf_buf[AST_MAX_EXTENSION]; /*!< place to collect digits be */ ast_group_t callgroup; ast_group_t pickupgroup; int callwaiting; int hascallwaiting; int transfer; int threewaycalling; int singlepath; int cancallforward; int canreinvite; int callreturn; int dnd; /* How does this affect callwait? Do we just deny a mgcp_request if we're dnd? */ int hascallerid; int hidecallerid; int dtmfmode; int amaflags; int type; int slowsequence; /*!< MS: Sequence the endpoint as a whole */ int group; int iseq; /*!< Not used? */ int lastout; /*!< tracking this on the subchannels. Is it needed here? */ int needdestroy; /*!< Not used? */ int capability; int nonCodecCapability; int onhooktime; int msgstate; /*!< voicemail message state */ int immediate; int hookstate; int adsi; char rqnt_ident[80]; /*!< request identifier */ struct mgcp_request *rqnt_queue; /*!< pending RQNT commands */ ast_mutex_t rqnt_queue_lock; struct mgcp_request *cmd_queue; /*!< pending commands other than RQNT */ ast_mutex_t cmd_queue_lock; int delme; /*!< needed for reload */ int needaudit; /*!< needed for reload */ struct ast_dsp *dsp; /*!< XXX Should there be a dsp/subchannel? XXX */ /* owner is tracked on the subchannels, and the *sub indicates whos in charge */ /* struct ast_channel *owner; */ /* struct ast_rtp *rtp; */ /* struct sockaddr_in tmpdest; */ /* message go the the endpoint and not the channel so they stay here */ struct mgcp_endpoint *next; struct mgcp_gateway *parent;};static struct mgcp_gateway { /* A gateway containing one or more endpoints */ char name[80]; int isnamedottedip; /*!< is the name FQDN or dotted ip */ struct sockaddr_in addr; struct sockaddr_in defaddr; struct in_addr ourip; int dynamic; int expire; /*!< XXX Should we ever expire dynamic registrations? XXX */ struct mgcp_endpoint *endpoints; struct ast_ha *ha;/* obsolete time_t lastouttime; int lastout; int messagepending;*//* Wildcard endpoint name */ char wcardep[30]; struct mgcp_message *msgs; /*!< gw msg queue */ ast_mutex_t msgs_lock; /*!< queue lock */ int retransid; /*!< retrans timer id */ int delme; /*!< needed for reload */ struct mgcp_response *responses; struct mgcp_gateway *next;} *gateways;AST_MUTEX_DEFINE_STATIC(mgcp_reload_lock);static int mgcp_reloading = 0;/*! \brief gatelock: mutex for gateway/endpoint lists */AST_MUTEX_DEFINE_STATIC(gatelock);static int mgcpsock = -1;static struct sockaddr_in bindaddr;static struct ast_frame *mgcp_read(struct ast_channel *ast);static int transmit_response(struct mgcp_subchannel *sub, char *msg, struct mgcp_request *req, char *msgrest);static int transmit_notify_request(struct mgcp_subchannel *sub, char *tone);static int transmit_modify_request(struct mgcp_subchannel *sub);static int transmit_notify_request_with_callerid(struct mgcp_subchannel *sub, char *tone, char *callernum, char *callername);static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp *rtp, int codecs);static int transmit_connection_del(struct mgcp_subchannel *sub);static int transmit_audit_endpoint(struct mgcp_endpoint *p);static void start_rtp(struct mgcp_subchannel *sub);static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub, int result, unsigned int ident, struct mgcp_request *resp);static void dump_cmd_queues(struct mgcp_endpoint *p, struct mgcp_subchannel *sub);static int mgcp_do_reload(void);static int mgcp_reload(int fd, int argc, char *argv[]);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);static int mgcp_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen);static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);static int mgcp_senddigit_begin(struct ast_channel *ast, char digit);static int mgcp_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);static int mgcp_devicestate(void *data);static void add_header_offhook(struct mgcp_subchannel *sub, struct mgcp_request *resp);static const struct ast_channel_tech mgcp_tech = { .type = "MGCP", .description = tdesc, .capabilities = AST_FORMAT_ULAW, .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER, .requester = mgcp_request, .devicestate = mgcp_devicestate, .call = mgcp_call, .hangup = mgcp_hangup, .answer = mgcp_answer, .read = mgcp_read, .write = mgcp_write, .indicate = mgcp_indicate, .fixup = mgcp_fixup, .send_digit_begin = mgcp_senddigit_begin, .send_digit_end = mgcp_senddigit_end, .bridge = ast_rtp_bridge,};static int has_voicemail(struct mgcp_endpoint *p){ return ast_app_has_voicemail(p->mailbox, NULL);}static int unalloc_sub(struct mgcp_subchannel *sub){ struct mgcp_endpoint *p = sub->parent; if (p->sub == sub) { ast_log(LOG_WARNING, "Trying to unalloc the real channel %s@%s?!?\n", p->name, p->parent->name); return -1; } ast_log(LOG_DEBUG, "Released sub %d of channel %s@%s\n", sub->id, p->name, p->parent->name); sub->owner = NULL; if (!ast_strlen_zero(sub->cxident)) { transmit_connection_del(sub); } sub->cxident[0] = '\0';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -