📄 chan_h323.c
字号:
/* * Asterisk -- An open source telephony toolkit. * * Copyright (C) 1999 - 2005 * * OpenH323 Channel Driver for ASTERISK PBX. * By Jeremy McNamara * For The NuFone Network * * chan_h323 has been derived from code created by * Michael Manousos and Mark Spencer * * 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 This file is part of the chan_h323 driver for Asterisk * * \author Jeremy McNamara * * \par See also * \arg Config_h323 * * \ingroup channel_drivers *//*** MODULEINFO <depend>openh323</depend> <defaultenabled>yes</defaultenabled> ***/#ifdef __cplusplusextern "C" {#endif#include "asterisk.h"ASTERISK_FILE_VERSION(__FILE__, "$Revision: 123113 $")#ifdef __cplusplus}#endif#include <sys/types.h>#include <sys/socket.h>#include <sys/signal.h>#include <sys/param.h>#if defined(BSD) || defined(SOLARIS)#ifndef IPTOS_MINCOST#define IPTOS_MINCOST 0x02#endif#endif#include <arpa/inet.h>#include <net/if.h>#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/ip.h>#include <unistd.h>#include <stdlib.h>#include <netdb.h>#include <stdio.h>#include <string.h>#include <errno.h>#include <fcntl.h>#ifdef __cplusplusextern "C" {#endif#include "asterisk/lock.h"#include "asterisk/logger.h"#include "asterisk/channel.h"#include "asterisk/config.h"#include "asterisk/module.h"#include "asterisk/musiconhold.h"#include "asterisk/pbx.h"#include "asterisk/options.h"#include "asterisk/utils.h"#include "asterisk/lock.h"#include "asterisk/sched.h"#include "asterisk/io.h"#include "asterisk/rtp.h"#include "asterisk/acl.h"#include "asterisk/callerid.h"#include "asterisk/cli.h"#include "asterisk/dsp.h"#include "asterisk/causes.h"#include "asterisk/stringfields.h"#include "asterisk/abstract_jb.h"#include "asterisk/astobj.h"#ifdef __cplusplus}#endif#include "h323/chan_h323.h"receive_digit_cb on_receive_digit;on_rtp_cb on_external_rtp_create;start_rtp_cb on_start_rtp_channel;setup_incoming_cb on_incoming_call;setup_outbound_cb on_outgoing_call;chan_ringing_cb on_chan_ringing;con_established_cb on_connection_established;clear_con_cb on_connection_cleared;answer_call_cb on_answer_call;progress_cb on_progress;rfc2833_cb on_set_rfc2833_payload;hangup_cb on_hangup;setcapabilities_cb on_setcapabilities;setpeercapabilities_cb on_setpeercapabilities;/* global debug flag */int h323debug;/*! 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;/** Variables required by Asterisk */static const char tdesc[] = "The NuFone Network's Open H.323 Channel Driver";static const char config[] = "h323.conf";static char default_context[AST_MAX_CONTEXT] = "default";static struct sockaddr_in bindaddr;#define GLOBAL_CAPABILITY (AST_FORMAT_G723_1 | AST_FORMAT_GSM | AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_G729A | AST_FORMAT_H261)/** H.323 configuration values */static int h323_signalling_port = 1720;static char gatekeeper[100];static int gatekeeper_disable = 1;static int gatekeeper_discover = 0;static int gkroute = 0;/* Find user by alias (h.323 id) is default, alternative is the incomming call's source IP address*/static int userbyalias = 1;static int acceptAnonymous = 1;static int tos = 0;static char secret[50];static unsigned int unique = 0;static call_options_t global_options;/** Private structure of a OpenH323 channel */struct oh323_pvt { ast_mutex_t lock; /* Channel private lock */ call_options_t options; /* Options to be used during call setup */ int alreadygone; /* Whether or not we've already been destroyed by our peer */ int needdestroy; /* if we need to be destroyed */ call_details_t cd; /* Call details */ struct ast_channel *owner; /* Who owns us */ struct sockaddr_in sa; /* Our peer */ struct sockaddr_in redirip; /* Where our RTP should be going if not to us */ int nonCodecCapability; /* non-audio capability */ int outgoing; /* Outgoing or incoming call? */ char exten[AST_MAX_EXTENSION]; /* Requested extension */ char context[AST_MAX_CONTEXT]; /* Context where to start */ char accountcode[256]; /* Account code */ char rdnis[80]; /* Referring DNIS, if available */ int amaflags; /* AMA Flags */ struct ast_rtp *rtp; /* RTP Session */ struct ast_dsp *vad; /* Used for in-band DTMF detection */ int nativeformats; /* Codec formats supported by a channel */ int needhangup; /* Send hangup when Asterisk is ready */ int hangupcause; /* Hangup cause from OpenH323 layer */ int newstate; /* Pending state change */ int newcontrol; /* Pending control to send */ int newdigit; /* Pending DTMF digit to send */ int newduration; /* Pending DTMF digit duration to send */ int pref_codec; /* Preferred codec */ int peercapability; /* Capabilities learned from peer */ int jointcapability; /* Common capabilities for local and remote side */ struct ast_codec_pref peer_prefs; /* Preferenced list of codecs which remote side supports */ int dtmf_pt; /* Payload code used for RFC2833 messages */ int curDTMF; /* DTMF tone being generated to Asterisk side */ int DTMFsched; /* Scheduler descriptor for DTMF */ int update_rtp_info; /* Configuration of fd's array is pending */ int recvonly; /* Peer isn't wish to receive our voice stream */ int txDtmfDigit; /* DTMF digit being to send to H.323 side */ int noInbandDtmf; /* Inband DTMF processing by DSP isn't available */ int connection_established; /* Call got CONNECT message */ int got_progress; /* Call got PROGRESS message, pass inband audio */ struct oh323_pvt *next; /* Next channel in list */} *iflist = NULL;static struct ast_user_list { ASTOBJ_CONTAINER_COMPONENTS(struct oh323_user);} userl;static struct ast_peer_list { ASTOBJ_CONTAINER_COMPONENTS(struct oh323_peer);} peerl;static struct ast_alias_list { ASTOBJ_CONTAINER_COMPONENTS(struct oh323_alias);} aliasl;/** Asterisk RTP stuff */static struct sched_context *sched;static struct io_context *io;/** Protect the interface list (oh323_pvt) */AST_MUTEX_DEFINE_STATIC(iflock);/* 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(monlock);/* Protect the H.323 capabilities list, to avoid more than one channel to set the capabilities simultaneaously in the h323 stack. */AST_MUTEX_DEFINE_STATIC(caplock);/* Protect the reload process */AST_MUTEX_DEFINE_STATIC(h323_reload_lock);static int h323_reloading = 0;/* 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 h323_do_reload(void);static struct ast_channel *oh323_request(const char *type, int format, void *data, int *cause);static int oh323_digit_begin(struct ast_channel *c, char digit);static int oh323_digit_end(struct ast_channel *c, char digit, unsigned int duration);static int oh323_call(struct ast_channel *c, char *dest, int timeout);static int oh323_hangup(struct ast_channel *c);static int oh323_answer(struct ast_channel *c);static struct ast_frame *oh323_read(struct ast_channel *c);static int oh323_write(struct ast_channel *c, struct ast_frame *frame);static int oh323_indicate(struct ast_channel *c, int condition, const void *data, size_t datalen);static int oh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);static const struct ast_channel_tech oh323_tech = { .type = "H323", .description = tdesc, .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1), .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER, .requester = oh323_request, .send_digit_begin = oh323_digit_begin, .send_digit_end = oh323_digit_end, .call = oh323_call, .hangup = oh323_hangup, .answer = oh323_answer, .read = oh323_read, .write = oh323_write, .indicate = oh323_indicate, .fixup = oh323_fixup, /* disable, for now */#if 0 .bridge = ast_rtp_bridge,#endif};static const char* redirectingreason2str(int redirectingreason){ switch (redirectingreason) { case 0: return "UNKNOWN"; case 1: return "BUSY"; case 2: return "NO_REPLY"; case 0xF: return "UNCONDITIONAL"; default: return "NOREDIRECT"; }}static void oh323_destroy_alias(struct oh323_alias *alias){ if (h323debug) ast_log(LOG_DEBUG, "Destroying alias '%s'\n", alias->name); free(alias);}static void oh323_destroy_user(struct oh323_user *user){ if (h323debug) ast_log(LOG_DEBUG, "Destroying user '%s'\n", user->name); ast_free_ha(user->ha); free(user);}static void oh323_destroy_peer(struct oh323_peer *peer){ if (h323debug) ast_log(LOG_DEBUG, "Destroying peer '%s'\n", peer->name); ast_free_ha(peer->ha); free(peer);}static int oh323_simulate_dtmf_end(const void *data){ struct oh323_pvt *pvt = (struct oh323_pvt *)data; if (pvt) { ast_mutex_lock(&pvt->lock); /* Don't hold pvt lock while trying to lock the channel */ while(pvt->owner && ast_channel_trylock(pvt->owner)) { ast_mutex_unlock(&pvt->lock); usleep(1); ast_mutex_lock(&pvt->lock); } if (pvt->owner) { struct ast_frame f = { .frametype = AST_FRAME_DTMF_END, .subclass = pvt->curDTMF, .samples = 0, .src = "SIMULATE_DTMF_END", }; ast_queue_frame(pvt->owner, &f); ast_channel_unlock(pvt->owner); } pvt->DTMFsched = -1; ast_mutex_unlock(&pvt->lock); } return 0;}/* Channel and private structures should be already locked */static void __oh323_update_info(struct ast_channel *c, struct oh323_pvt *pvt){ if (c->nativeformats != pvt->nativeformats) { if (h323debug) ast_log(LOG_DEBUG, "Preparing %s for new native format\n", c->name); c->nativeformats = pvt->nativeformats; ast_set_read_format(c, c->readformat); ast_set_write_format(c, c->writeformat); } if (pvt->needhangup) { if (h323debug) ast_log(LOG_DEBUG, "Process pending hangup for %s\n", c->name); c->_softhangup |= AST_SOFTHANGUP_DEV; c->hangupcause = pvt->hangupcause; ast_queue_hangup(c); pvt->needhangup = 0; pvt->newstate = pvt->newcontrol = pvt->newdigit = pvt->DTMFsched = -1; } if (pvt->newstate >= 0) { ast_setstate(c, pvt->newstate); pvt->newstate = -1; } if (pvt->newcontrol >= 0) { ast_queue_control(c, pvt->newcontrol); pvt->newcontrol = -1; } if (pvt->newdigit >= 0) { struct ast_frame f = { .frametype = AST_FRAME_DTMF_END, .subclass = pvt->newdigit, .samples = pvt->newduration * 8, .len = pvt->newduration, .src = "UPDATE_INFO", }; if (pvt->newdigit == ' ') { /* signalUpdate message */ f.subclass = pvt->curDTMF; if (pvt->DTMFsched >= 0) { AST_SCHED_DEL(sched, pvt->DTMFsched); } } else { /* Regular input or signal message */ if (pvt->newduration) { /* This is a signal, signalUpdate follows */ f.frametype = AST_FRAME_DTMF_BEGIN; AST_SCHED_DEL(sched, pvt->DTMFsched); pvt->DTMFsched = ast_sched_add(sched, pvt->newduration, oh323_simulate_dtmf_end, pvt); if (h323debug) ast_log(LOG_DTMF, "Scheduled DTMF END simulation for %d ms, id=%d\n", pvt->newduration, pvt->DTMFsched); } pvt->curDTMF = pvt->newdigit; } ast_queue_frame(c, &f); pvt->newdigit = -1; } if (pvt->update_rtp_info > 0) { if (pvt->rtp) { ast_jb_configure(c, &global_jbconf); c->fds[0] = ast_rtp_fd(pvt->rtp); c->fds[1] = ast_rtcp_fd(pvt->rtp); ast_queue_frame(pvt->owner, &ast_null_frame); /* Tell Asterisk to apply changes */ } pvt->update_rtp_info = -1; }}/* Only channel structure should be locked */static void oh323_update_info(struct ast_channel *c){ struct oh323_pvt *pvt = c->tech_pvt; if (pvt) { ast_mutex_lock(&pvt->lock); __oh323_update_info(c, pvt); ast_mutex_unlock(&pvt->lock); }}static void cleanup_call_details(call_details_t *cd){ if (cd->call_token) { free(cd->call_token); cd->call_token = NULL; } if (cd->call_source_aliases) { free(cd->call_source_aliases); cd->call_source_aliases = NULL; } if (cd->call_dest_alias) { free(cd->call_dest_alias); cd->call_dest_alias = NULL; } if (cd->call_source_name) { free(cd->call_source_name); cd->call_source_name = NULL; } if (cd->call_source_e164) { free(cd->call_source_e164); cd->call_source_e164 = NULL; } if (cd->call_dest_e164) { free(cd->call_dest_e164); cd->call_dest_e164 = NULL; } if (cd->sourceIp) { free(cd->sourceIp); cd->sourceIp = NULL; } if (cd->redirect_number) { free(cd->redirect_number);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -