aboutsummaryrefslogtreecommitdiffstats
path: root/addons/chan_ooh323.c
diff options
context:
space:
mode:
Diffstat (limited to 'addons/chan_ooh323.c')
-rw-r--r--addons/chan_ooh323.c3162
1 files changed, 3162 insertions, 0 deletions
diff --git a/addons/chan_ooh323.c b/addons/chan_ooh323.c
new file mode 100644
index 000000000..70c0f0209
--- /dev/null
+++ b/addons/chan_ooh323.c
@@ -0,0 +1,3162 @@
+/*
+ * Copyright (C) 2004-2005 by Objective Systems, Inc.
+ *
+ * This software is furnished under an open source license and may be
+ * used and copied only in accordance with the terms of this license.
+ * The text of the license may generally be found in the root
+ * directory of this installation in the COPYING file. It
+ * can also be viewed online at the following URL:
+ *
+ * http://www.obj-sys.com/open/license.html
+ *
+ * Any redistributions of this file including modified versions must
+ * maintain this copyright notice.
+ *
+ *****************************************************************************/
+
+
+#include "chan_ooh323.h"
+
+/*** MODULEINFO
+ <defaultenabled>no</defaultenabled>
+ ***/
+
+/* Defaults */
+#define DEFAULT_CONTEXT "default"
+#define DEFAULT_H323ID "Asterisk PBX"
+#define DEFAULT_LOGFILE "/var/log/asterisk/h323_log"
+#define DEFAULT_H323ACCNT "ast_h323"
+
+/* Flags */
+#define H323_SILENCESUPPRESSION (1<<0)
+#define H323_GKROUTED (1<<1)
+#define H323_TUNNELING (1<<2)
+#define H323_FASTSTART (1<<3)
+#define H323_OUTGOING (1<<4)
+#define H323_ALREADYGONE (1<<5)
+#define H323_NEEDDESTROY (1<<6)
+#define H323_DISABLEGK (1<<7)
+
+/* Channel description */
+static const char type[] = "OOH323";
+static const char tdesc[] = "Objective Systems H323 Channel Driver";
+static const char config[] = "ooh323.conf";
+
+
+/* Channel Definition */
+static struct ast_channel *ooh323_request(const char *type, int format,
+ void *data, int *cause);
+static int ooh323_digit_begin(struct ast_channel *ast, char digit);
+static int ooh323_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
+static int ooh323_call(struct ast_channel *ast, char *dest, int timeout);
+static int ooh323_hangup(struct ast_channel *ast);
+static int ooh323_answer(struct ast_channel *ast);
+static struct ast_frame *ooh323_read(struct ast_channel *ast);
+static int ooh323_write(struct ast_channel *ast, struct ast_frame *f);
+static int ooh323_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
+static int ooh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
+
+static enum ast_rtp_get_result ooh323_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
+static enum ast_rtp_get_result ooh323_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
+static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp,
+ struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active);
+
+static void print_codec_to_cli(int fd, struct ast_codec_pref *pref);
+
+#if 0
+static void ast_ooh323c_exit();
+#endif
+
+static const struct ast_channel_tech ooh323_tech = {
+ .type = type,
+ .description = tdesc,
+ .capabilities = -1,
+ .requester = ooh323_request,
+ .send_digit_begin = ooh323_digit_begin,
+ .send_digit_end = ooh323_digit_end,
+ .call = ooh323_call,
+ .hangup = ooh323_hangup,
+ .answer = ooh323_answer,
+ .read = ooh323_read,
+ .write = ooh323_write,
+ .exception = ooh323_read,
+ .indicate = ooh323_indicate,
+ .fixup = ooh323_fixup,
+ .send_html = 0,
+ .bridge = ast_rtp_bridge,
+};
+
+static struct ast_rtp_protocol ooh323_rtp = {
+ .type = type,
+ .get_rtp_info = ooh323_get_rtp_peer,
+ .get_vrtp_info = ooh323_get_vrtp_peer,
+ .set_rtp_peer = ooh323_set_rtp_peer
+};
+
+/* H.323 channel private structure */
+static struct ooh323_pvt {
+ ast_mutex_t lock; /* Channel private lock */
+ struct ast_rtp *rtp;
+ struct ast_rtp *vrtp; /* Placeholder for now */
+ struct ast_channel *owner; /* Master Channel */
+ time_t lastrtptx;
+ time_t lastrtprx;
+ unsigned int flags;
+ unsigned int call_reference;
+ char *callToken;
+ char *username;
+ char *host;
+ char *callerid_name;
+ char *callerid_num;
+ char caller_h323id[AST_MAX_EXTENSION];
+ char caller_dialedDigits[AST_MAX_EXTENSION];
+ char caller_email[AST_MAX_EXTENSION];
+ char caller_url[256];
+ char callee_h323id[AST_MAX_EXTENSION];
+ char callee_dialedDigits[AST_MAX_EXTENSION];
+ char callee_email[AST_MAX_EXTENSION];
+ char callee_url[AST_MAX_EXTENSION];
+
+ int port;
+ int readformat; /* negotiated read format */
+ int writeformat; /* negotiated write format */
+ int capability;
+ struct ast_codec_pref prefs;
+ int dtmfmode;
+ char exten[AST_MAX_EXTENSION]; /* Requested extension */
+ char context[AST_MAX_EXTENSION]; /* Context where to start */
+ char accountcode[256]; /* Account code */
+ int nat;
+ int amaflags;
+ struct ast_dsp *vad;
+ struct ooh323_pvt *next; /* Next entity */
+} *iflist = NULL;
+
+/* Protect the channel/interface list (ooh323_pvt) */
+AST_MUTEX_DEFINE_STATIC(iflock);
+
+/* Profile of H.323 user registered with PBX*/
+struct ooh323_user{
+ ast_mutex_t lock;
+ char name[256];
+ char context[AST_MAX_EXTENSION];
+ int incominglimit;
+ unsigned inUse;
+ char accountcode[20];
+ int amaflags;
+ int capability;
+ struct ast_codec_pref prefs;
+ int dtmfmode;
+ int rtptimeout;
+ int mUseIP; /* Use IP address or H323-ID to search user */
+ char mIP[20];
+ struct ooh323_user *next;
+};
+
+/* Profile of valid asterisk peers */
+struct ooh323_peer{
+ ast_mutex_t lock;
+ char name[256];
+ unsigned outgoinglimit;
+ unsigned outUse;
+ int capability;
+ struct ast_codec_pref prefs;
+ char accountcode[20];
+ int amaflags;
+ int dtmfmode;
+ int mFriend; /* indicates defined as friend */
+ char ip[20];
+ int port;
+ char *h323id; /* H323-ID alias, which asterisk will register with gk to reach this peer*/
+ char *email; /* Email alias, which asterisk will register with gk to reach this peer*/
+ char *url; /* url alias, which asterisk will register with gk to reach this peer*/
+ char *e164; /* e164 alias, which asterisk will register with gk to reach this peer*/
+ int rtptimeout;
+ struct ooh323_peer *next;
+};
+
+
+/* List of H.323 users known to PBX */
+static struct ast_user_list {
+ struct ooh323_user *users;
+ ast_mutex_t lock;
+} userl;
+
+static struct ast_peer_list {
+ struct ooh323_peer *peers;
+ ast_mutex_t lock;
+} peerl;
+
+/* Mutex to protect H.323 reload process */
+static int h323_reloading = 0;
+AST_MUTEX_DEFINE_STATIC(h323_reload_lock);
+
+/* Mutex to protect usage counter */
+static int usecnt = 0;
+AST_MUTEX_DEFINE_STATIC(usecnt_lock);
+
+AST_MUTEX_DEFINE_STATIC(ooh323c_cmd_lock);
+
+/* stack callbacks */
+int onAlerting(ooCallData *call);
+int onNewCallCreated(ooCallData *call);
+int onCallEstablished(ooCallData *call);
+int onCallCleared(ooCallData *call);
+
+static char gLogFile[256] = DEFAULT_LOGFILE;
+static int gPort = 1720;
+static char gIP[20];
+static char gCallerID[AST_MAX_EXTENSION] = DEFAULT_H323ID;
+static struct ooAliases *gAliasList;
+static int gCapability = AST_FORMAT_ULAW;
+static struct ast_codec_pref gPrefs;
+static int gDTMFMode = H323_DTMF_RFC2833;
+static char gGatekeeper[100];
+static enum RasGatekeeperMode gRasGkMode = RasNoGatekeeper;
+
+static int gIsGateway = 0;
+static int gFastStart = 1;
+static int gTunneling = 1;
+static int gMediaWaitForConnect = 0;
+static int gTOS = 0;
+static int gRTPTimeout = 60;
+static char gAccountcode[80] = DEFAULT_H323ACCNT;
+static int gAMAFLAGS;
+static char gContext[AST_MAX_EXTENSION] = DEFAULT_CONTEXT;
+static int gIncomingLimit = 4;
+static int gOutgoingLimit = 4;
+OOBOOL gH323Debug = FALSE;
+
+static struct ooh323_config
+{
+ int mTCPPortStart;
+ int mTCPPortEnd;
+} ooconfig;
+
+/** Asterisk RTP stuff*/
+static struct sched_context *sched;
+static struct io_context *io;
+
+/* 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);
+
+
+/* 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 struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state,
+ const char *host)
+{
+ struct ast_channel *ch = NULL;
+ int fmt;
+ if (gH323Debug)
+ ast_verbose("--- ooh323_new - %s\n", host);
+
+
+ /* Don't hold a h323 pvt lock while we allocate a channel */
+ ast_mutex_unlock(&i->lock);
+ ch = ast_channel_alloc(1, state, i->callerid_num, i->callerid_name, i->accountcode, i->exten, i->context, i->amaflags, "OOH323/%s-%08x", host, (unsigned int)(unsigned long) i);
+ ast_mutex_lock(&i->lock);
+
+ if (ch) {
+ ast_channel_lock(ch);
+ ch->tech = &ooh323_tech;
+
+ ch->nativeformats = i->capability;
+
+ fmt = ast_best_codec(ch->nativeformats);
+
+ ch->fds[0] = ast_rtp_fd(i->rtp);
+ ch->fds[1] = ast_rtcp_fd(i->rtp);
+
+ if (state == AST_STATE_RING)
+ ch->rings = 1;
+
+ ch->adsicpe = AST_ADSI_UNAVAILABLE;
+ ch->writeformat = fmt;
+ ch->rawwriteformat = fmt;
+ ch->readformat = fmt;
+ ch->rawreadformat = fmt;
+ ch->tech_pvt = i;
+ i->owner = ch;
+
+ /* Allocate dsp for in-band DTMF support */
+ if (i->dtmfmode & H323_DTMF_INBAND) {
+ i->vad = ast_dsp_new();
+ ast_dsp_set_features(i->vad, DSP_FEATURE_DIGIT_DETECT);
+ }
+
+ ast_mutex_lock(&usecnt_lock);
+ usecnt++;
+ ast_mutex_unlock(&usecnt_lock);
+
+ /* Notify the module monitors that use count for resource has changed*/
+ ast_update_use_count();
+
+ ast_copy_string(ch->context, i->context, sizeof(ch->context));
+ ast_copy_string(ch->exten, i->exten, sizeof(ch->exten));
+
+ ch->priority = 1;
+ if (i->callerid_name) {
+ ch->cid.cid_name = strdup(i->callerid_name);
+ }
+ if (i->callerid_num) {
+
+ ch->cid.cid_num = strdup(i->callerid_num);
+ }
+
+ if (!ast_test_flag(i, H323_OUTGOING)) {
+
+ if (!ast_strlen_zero(i->caller_h323id)) {
+ pbx_builtin_setvar_helper(ch, "_CALLER_H323ID", i->caller_h323id);
+
+ }
+ if (!ast_strlen_zero(i->caller_dialedDigits)) {
+ pbx_builtin_setvar_helper(ch, "_CALLER_H323DIALEDDIGITS",
+ i->caller_dialedDigits);
+ }
+ if (!ast_strlen_zero(i->caller_email)) {
+ pbx_builtin_setvar_helper(ch, "_CALLER_H323EMAIL",
+ i->caller_email);
+ }
+ if (!ast_strlen_zero(i->caller_url)) {
+ pbx_builtin_setvar_helper(ch, "_CALLER_H323URL", i->caller_url);
+ }
+ }
+
+ if (!ast_strlen_zero(i->accountcode))
+ ast_string_field_set(ch, accountcode, i->accountcode);
+
+ if (i->amaflags)
+ ch->amaflags = i->amaflags;
+
+ ast_setstate(ch, state);
+ if (state != AST_STATE_DOWN) {
+ if (ast_pbx_start(ch)) {
+ ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ch->name);
+ ast_channel_unlock(ch);
+ ast_hangup(ch);
+ ch = NULL;
+ }
+ }
+ } else
+ ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
+
+
+ if (ch)
+ ast_channel_unlock(ch);
+
+ if (gH323Debug)
+ ast_verbose("+++ h323_new\n");
+
+ return ch;
+}
+
+
+
+static struct ooh323_pvt *ooh323_alloc(int callref, char *callToken)
+{
+ struct ooh323_pvt *pvt = NULL;
+ struct in_addr ipAddr;
+ if (gH323Debug)
+ ast_verbose("--- ooh323_alloc\n");
+
+ if (!(pvt = ast_calloc(1, sizeof(*pvt)))) {
+ ast_log(LOG_ERROR, "Couldn't allocate private ooh323 structure\n");
+ return NULL;
+ }
+
+ ast_mutex_init(&pvt->lock);
+ ast_mutex_lock(&pvt->lock);
+
+ if (!inet_aton(gIP, &ipAddr)) {
+ ast_log(LOG_ERROR, "Invalid OOH323 driver ip address\n");
+ ast_mutex_unlock(&pvt->lock);
+ ast_mutex_destroy(&pvt->lock);
+ free(pvt);
+ return NULL;
+ }
+
+ if (!(pvt->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, ipAddr))) {
+ ast_log(LOG_WARNING, "Unable to create RTP session: %s\n",
+ strerror(errno));
+ ast_mutex_unlock(&pvt->lock);
+ ast_mutex_destroy(&pvt->lock);
+ free(pvt);
+ return NULL;
+ }
+
+ ast_rtp_setqos(pvt->rtp, gTOS, 0, "ooh323");
+
+ pvt->call_reference = callref;
+ if (callToken)
+ pvt->callToken = strdup(callToken);
+
+ /* whether to use gk for this call */
+ if (gRasGkMode == RasNoGatekeeper)
+ OO_SETFLAG(pvt->flags, H323_DISABLEGK);
+
+ pvt->dtmfmode = gDTMFMode;
+ ast_copy_string(pvt->context, gContext, sizeof(pvt->context));
+ ast_copy_string(pvt->accountcode, gAccountcode, sizeof(pvt->accountcode));
+ pvt->amaflags = gAMAFLAGS;
+ pvt->capability = gCapability;
+ memcpy(&pvt->prefs, &gPrefs, sizeof(pvt->prefs));
+
+ ast_mutex_unlock(&pvt->lock);
+ /* Add to interface list */
+ ast_mutex_lock(&iflock);
+ pvt->next = iflist;
+ iflist = pvt;
+ ast_mutex_unlock(&iflock);
+
+ if (gH323Debug)
+ ast_verbose("+++ ooh323_alloc\n");
+
+ return pvt;
+}
+
+
+/*
+ Possible data values - peername, exten/peername, exten@ip
+ */
+static struct ast_channel *ooh323_request(const char *type, int format,
+ void *data, int *cause)
+{
+ struct ast_channel *chan = NULL;
+ struct ooh323_pvt *p = NULL;
+ struct ooh323_peer *peer = NULL;
+ char *dest = NULL;
+ char *ext = NULL;
+ char tmp[256];
+ char formats[512];
+ int oldformat;
+ int port = 0;
+
+ if (gH323Debug)
+ ast_verbose("--- ooh323_request - data %s format %s\n", (char*)data,
+ ast_getformatname_multiple(formats,512,format));
+
+ oldformat = format;
+ format &= AST_FORMAT_AUDIO_MASK;
+ if (!format) {
+ ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format "
+ "'%d'\n", format);
+ return NULL;
+ }
+
+ p = ooh323_alloc(0,0); /* Initial callRef is zero */
+
+ if (!p) {
+ ast_log(LOG_WARNING, "Unable to build pvt data for '%s'\n", (char*)data);
+ return NULL;
+ }
+ ast_mutex_lock(&p->lock);
+
+ /* This is an outgoing call, since ooh323_request is called */
+ ast_set_flag(p, H323_OUTGOING);
+
+ ast_copy_string(tmp, data, sizeof(data));
+
+ dest = strchr(tmp, '/');
+
+ if (dest) {
+ *dest = '\0';
+ dest++;
+ ext = tmp;
+ } else if ((dest = strchr(tmp, '@'))) {
+ *dest = '\0';
+ dest++;
+ ext = tmp;
+ } else {
+ dest = tmp;
+ ext = NULL;
+ }
+
+#if 0
+ if ((sport = strchr(dest, ':'))) {
+ *sport = '\0';
+ sport++;
+ port = atoi(sport);
+ }
+#endif
+
+ if (dest) {
+ peer = find_peer(dest, port);
+ } else{
+ ast_log(LOG_ERROR, "Destination format is not supported\n");
+ return NULL;
+ }
+
+ if (peer) {
+ p->username = strdup(peer->name);
+ p->host = strdup(peer->ip);
+ p->port = peer->port;
+ /* Disable gk as we are going to call a known peer*/
+ OO_SETFLAG(p->flags, H323_DISABLEGK);
+
+ if (ext)
+ ast_copy_string(p->exten, ext, sizeof(p->exten));
+
+ if (peer->capability & format) {
+ p->capability = peer->capability & format;
+ } else {
+ p->capability = peer->capability;
+ }
+ memcpy(&p->prefs, &peer->prefs, sizeof(struct ast_codec_pref));
+ p->dtmfmode = peer->dtmfmode;
+ ast_copy_string(p->accountcode, peer->accountcode, sizeof(p->accountcode));
+ p->amaflags = peer->amaflags;
+ } else {
+ p->dtmfmode = gDTMFMode;
+ p->capability = gCapability;
+
+ memcpy(&p->prefs, &gPrefs, sizeof(struct ast_codec_pref));
+ p->username = strdup(dest);
+
+ p->host = strdup(dest);
+ if (port > 0) {
+ p->port = port;
+ }
+ if (ext) {
+ ast_copy_string(p->exten, ext, sizeof(p->exten));
+ }
+ }
+
+
+ chan = ooh323_new(p, AST_STATE_DOWN, p->username);
+
+ ast_mutex_unlock(&p->lock);
+
+ if (!chan) {
+ ast_mutex_lock(&iflock);
+ ooh323_destroy(p);
+ ast_mutex_unlock(&iflock);
+ }
+
+ restart_monitor();
+ if (gH323Debug)
+ ast_verbose("+++ ooh323_request\n");
+
+ return chan;
+
+}
+
+
+static struct ooh323_pvt* find_call(ooCallData *call)
+{
+ struct ooh323_pvt *p;
+
+ if (gH323Debug)
+ ast_verbose("--- find_call\n");
+
+ ast_mutex_lock(&iflock);
+
+ for (p = iflist; p; p = p->next) {
+ if (p->callToken && !strcmp(p->callToken, call->callToken)) {
+ break;
+ }
+ }
+ ast_mutex_unlock(&iflock);
+
+ if (gH323Debug)
+ ast_verbose("+++ find_call\n");
+
+ return p;
+}
+
+struct ooh323_user *find_user(const char * name, const char* ip)
+{
+ struct ooh323_user *user;
+
+ if (gH323Debug)
+ ast_verbose("--- find_user\n");
+
+ ast_mutex_lock(&userl.lock);
+ for (user = userl.users; user; user = user->next) {
+ if (ip && user->mUseIP && !strcmp(user->mIP, ip)) {
+ break;
+ }
+ if (name && !strcmp(user->name, name)) {
+ break;
+ }
+ }
+ ast_mutex_unlock(&userl.lock);
+
+ if (gH323Debug)
+ ast_verbose("+++ find_user\n");
+
+ return user;
+}
+
+struct ooh323_peer *find_friend(const char *name, int port)
+{
+ struct ooh323_peer *peer;
+
+ if (gH323Debug)
+ ast_verbose("--- find_friend \"%s\"\n", name);
+
+
+ ast_mutex_lock(&peerl.lock);
+ for (peer = peerl.peers; peer; peer = peer->next) {
+ if (gH323Debug) {
+ ast_verbose(" comparing with \"%s\"\n", peer->ip);
+ }
+ if (!strcmp(peer->ip, name)) {
+ if (port <= 0 || (port > 0 && peer->port == port)) {
+ break;
+ }
+ }
+ }
+ ast_mutex_unlock(&peerl.lock);
+
+ if (gH323Debug) {
+ if (peer) {
+ ast_verbose(" found matching friend\n");
+ }
+ ast_verbose("+++ find_friend \"%s\"\n", name);
+ }
+
+ return peer;
+}
+
+
+struct ooh323_peer *find_peer(const char * name, int port)
+{
+ struct ooh323_peer *peer;
+
+ if (gH323Debug)
+ ast_verbose("--- find_peer \"%s\"\n", name);
+
+ ast_mutex_lock(&peerl.lock);
+ for (peer = peerl.peers; peer; peer = peer->next) {
+ if (gH323Debug) {
+ ast_verbose(" comparing with \"%s\"\n", peer->ip);
+ }
+ if (!strcasecmp(peer->name, name))
+ break;
+ if (peer->h323id && !strcasecmp(peer->h323id, name))
+ break;
+ if (peer->e164 && !strcasecmp(peer->e164, name))
+ break;
+ /*
+ if (!strcmp(peer->ip, name)) {
+ if (port > 0 && peer->port == port) { break; }
+ else if (port <= 0) { break; }
+ }
+ */
+ }
+ ast_mutex_unlock(&peerl.lock);
+
+ if (gH323Debug) {
+ if (peer) {
+ ast_verbose(" found matching peer\n");
+ }
+ ast_verbose("+++ find_peer \"%s\"\n", name);
+ }
+
+ return peer;
+}
+
+static int ooh323_digit_begin(struct ast_channel *chan, char digit)
+{
+ char dtmf[2];
+ struct ooh323_pvt *p = (struct ooh323_pvt *) chan->tech_pvt;
+
+ if (gH323Debug)
+ ast_verbose("--- ooh323_digit_begin\n");
+
+ if (!p) {
+ ast_log(LOG_ERROR, "No private structure for call\n");
+ return -1;
+ }
+ ast_mutex_lock(&p->lock);
+ if (p->rtp && (p->dtmfmode & H323_DTMF_RFC2833)) {
+ ast_rtp_senddigit_begin(p->rtp, digit);
+ } else if (((p->dtmfmode & H323_DTMF_Q931) ||
+ (p->dtmfmode & H323_DTMF_H245ALPHANUMERIC) ||
+ (p->dtmfmode & H323_DTMF_H245SIGNAL))) {
+ dtmf[0] = digit;
+ dtmf[1] = '\0';
+ ast_mutex_lock(&ooh323c_cmd_lock);
+ ooSendDTMFDigit(p->callToken, dtmf);
+ ast_mutex_unlock(&ooh323c_cmd_lock);
+ }
+ ast_mutex_unlock(&p->lock);
+ if (gH323Debug)
+ ast_verbose("+++ ooh323_digit_begin\n");
+
+ return 0;
+}
+
+static int ooh323_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
+{
+ struct ooh323_pvt *p = (struct ooh323_pvt *) chan->tech_pvt;
+
+ if (gH323Debug)
+ ast_verbose("--- ooh323_digit_end\n");
+
+ if (!p) {
+ ast_log(LOG_ERROR, "No private structure for call\n");
+ return -1;
+ }
+ ast_mutex_lock(&p->lock);
+ if (p->rtp && (p->dtmfmode & H323_DTMF_RFC2833))
+ ast_rtp_senddigit_end(p->rtp, digit);
+
+ ast_mutex_unlock(&p->lock);
+ if (gH323Debug)
+ ast_verbose("+++ ooh323_digit_end\n");
+
+ return 0;
+}
+
+
+static int ooh323_call(struct ast_channel *ast, char *dest, int timeout)
+{
+ struct ooh323_pvt *p = ast->tech_pvt;
+ char destination[256];
+ int res = 0;
+ const char *val = NULL;
+ ooCallOptions opts = {
+ .fastStart = TRUE,
+ .tunneling = TRUE,
+ .disableGk = TRUE,
+ .callMode = OO_CALLMODE_AUDIOCALL
+ };
+ if (gH323Debug)
+ ast_verbose("--- ooh323_call- %s\n", dest);
+
+ if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
+ ast_log(LOG_WARNING, "ooh323_call called on %s, neither down nor "
+ "reserved\n", ast->name);
+ return -1;
+ }
+ ast_mutex_lock(&p->lock);
+ ast_set_flag(p, H323_OUTGOING);
+ if (ast->cid.cid_num) {
+ if (p->callerid_num) {
+ free(p->callerid_num);
+ }
+ p->callerid_num = strdup(ast->cid.cid_num);
+ }
+
+ if (ast->cid.cid_name) {
+ if (p->callerid_name) {
+ free(p->callerid_name);
+ }
+ p->callerid_name = strdup(ast->cid.cid_name);
+ }
+ else{
+ ast->cid.cid_name = strdup(gCallerID);
+ if (p->callerid_name) {
+ free(p->callerid_name);
+ }
+ p->callerid_name = strdup(ast->cid.cid_name);
+ }
+
+ /* Retrieve vars */
+
+
+ if ((val = pbx_builtin_getvar_helper(ast, "CALLER_H323ID"))) {
+ ast_copy_string(p->caller_h323id, val, sizeof(p->caller_h323id));
+ }
+
+ if ((val = pbx_builtin_getvar_helper(ast, "CALLER_H323DIALEDDIGITS"))) {
+ ast_copy_string(p->caller_dialedDigits, val, sizeof(p->caller_dialedDigits));
+ if (!p->callerid_num) {
+ p->callerid_num = strdup(val);
+ }
+ }
+
+ if ((val = pbx_builtin_getvar_helper(ast, "CALLER_H323EMAIL"))) {
+ ast_copy_string(p->caller_email, val, sizeof(p->caller_email));
+ }
+
+ if ((val = pbx_builtin_getvar_helper(ast, "CALLER_H323URL"))) {
+ ast_copy_string(p->caller_url, val, sizeof(p->caller_url));
+ }
+
+
+ if (!(p->callToken = (char*)malloc(AST_MAX_EXTENSION))) {
+ ast_mutex_unlock(&p->lock);
+ ast_log(LOG_ERROR, "Failed to allocate memory for callToken\n");
+ return -1; /* TODO: need to clean/hangup?? */
+ }
+
+ if (p->host && p->port != 0)
+ snprintf(destination, sizeof(destination), "%s:%d", p->host, p->port);
+ else if (p->host)
+ snprintf(destination, sizeof(destination), "%s", p->host);
+ else
+ ast_copy_string(destination, dest, sizeof(destination));
+
+ ast_mutex_lock(&ooh323c_cmd_lock);
+ if (OO_TESTFLAG(p->flags, H323_DISABLEGK))
+ res = ooMakeCall(destination, p->callToken, AST_MAX_EXTENSION, &opts);
+ else
+ res = ooMakeCall(destination, p->callToken, AST_MAX_EXTENSION, NULL);
+ ast_mutex_unlock(&ooh323c_cmd_lock);
+
+ ast_mutex_unlock(&p->lock);
+ if (res != OO_OK) {
+ ast_log(LOG_ERROR, "Failed to make call\n");
+ return -1; /* TODO: cleanup */
+ }
+ if (gH323Debug)
+ ast_verbose("+++ ooh323_call\n");
+
+ return 0;
+}
+
+static int ooh323_hangup(struct ast_channel *ast)
+{
+ struct ooh323_pvt *p = ast->tech_pvt;
+
+ if (gH323Debug)
+ ast_verbose("--- ooh323_hangup\n");
+
+ if (p) {
+ ast_mutex_lock(&p->lock);
+
+ if (gH323Debug)
+ ast_verbose(" hanging %s\n", p->username);
+ ast->tech_pvt = NULL;
+ if (!ast_test_flag(p, H323_ALREADYGONE)) {
+ ast_mutex_lock(&ooh323c_cmd_lock);
+ ooHangCall(p->callToken,
+ ooh323_convert_hangupcause_asteriskToH323(p->owner->hangupcause));
+ ast_mutex_unlock(&ooh323c_cmd_lock);
+ ast_set_flag(p, H323_ALREADYGONE);
+ /* ast_mutex_unlock(&p->lock); */
+ } else {
+ ast_set_flag(p, H323_NEEDDESTROY);
+ }
+ /* detach channel here */
+ if (p->owner) {
+ p->owner->tech_pvt = NULL;
+ p->owner = NULL;
+ }
+
+ ast_mutex_unlock(&p->lock);
+ ast_mutex_lock(&usecnt_lock);
+ usecnt--;
+ ast_mutex_unlock(&usecnt_lock);
+
+ /* Notify the module monitors that use count for resource has changed */
+ ast_update_use_count();
+
+ } else {
+ ast_log(LOG_ERROR, "No call to hangup\n" );
+ return -1;
+ }
+
+ if (gH323Debug)
+ ast_verbose("+++ ooh323_hangup\n");
+
+ return 0;
+}
+
+static int ooh323_answer(struct ast_channel *ast)
+{
+ struct ooh323_pvt *p = ast->tech_pvt;
+
+ if (gH323Debug)
+ ast_verbose("--- ooh323_answer\n");
+
+ ast_mutex_lock(&p->lock);
+ if (ast->_state != AST_STATE_UP) {
+ ast_channel_lock(ast);
+ ast_setstate(ast, AST_STATE_UP);
+ ast_debug(1, "ooh323_answer(%s)\n", ast->name);
+ ast_channel_unlock(ast);
+ ast_mutex_lock(&ooh323c_cmd_lock);
+ ooAnswerCall(p->callToken);
+ ast_mutex_unlock(&ooh323c_cmd_lock);
+ }
+ ast_mutex_unlock(&p->lock);
+
+ if (gH323Debug)
+ ast_verbose("+++ ooh323_answer\n");
+
+ return 0;
+}
+
+static struct ast_frame *ooh323_read(struct ast_channel *ast)
+{
+ struct ast_frame *fr;
+ static struct ast_frame null_frame = { AST_FRAME_NULL, };
+ struct ooh323_pvt *p = ast->tech_pvt;
+
+ ast_mutex_lock(&p->lock);
+ if (p->rtp)
+ fr = ooh323_rtp_read(ast, p);
+ else
+ fr = &null_frame;
+ /* time(&p->lastrtprx); */
+ ast_mutex_unlock(&p->lock);
+ return fr;
+}
+
+static int ooh323_write(struct ast_channel *ast, struct ast_frame *f)
+{
+ struct ooh323_pvt *p = ast->tech_pvt;
+ int res = 0;
+
+ if (f->frametype == AST_FRAME_VOICE) {
+ if (!(f->subclass & ast->nativeformats)) {
+ ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native "
+ "formats is %d (read/write = %d/%d)\n",
+ f->subclass, ast->nativeformats, ast->readformat,
+ ast->writeformat);
+ return 0;
+ }
+ if (p) {
+ ast_mutex_lock(&p->lock);
+ if (p->rtp)
+ res = ast_rtp_write(p->rtp, f);
+ ast_mutex_unlock(&p->lock);
+ }
+ } else if (f->frametype == AST_FRAME_IMAGE) {
+ return 0;
+ } else {
+ ast_log(LOG_WARNING, "Can't send %d type frames with SIP write\n",
+ f->frametype);
+ return 0;
+ }
+
+ return res;
+}
+
+static int ooh323_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
+{
+
+ struct ooh323_pvt *p = (struct ooh323_pvt *) ast->tech_pvt;
+ char *callToken = (char *)NULL;
+
+ ast_mutex_lock(&p->lock);
+ callToken = (p->callToken ? strdup(p->callToken) : NULL);
+ ast_mutex_unlock(&p->lock);
+
+ if (!callToken) {
+ if (gH323Debug)
+ ast_verbose(" ooh323_indicate - No callToken\n");
+ return -1;
+ }
+
+ if (gH323Debug)
+ ast_verbose("----- ooh323_indicate %d on call %s\n", condition, callToken);
+
+
+ switch (condition) {
+ case AST_CONTROL_CONGESTION:
+ if (!ast_test_flag(p, H323_ALREADYGONE)) {
+ ast_mutex_lock(&ooh323c_cmd_lock);
+ ooHangCall(callToken, OO_REASON_LOCAL_CONGESTED);
+ ast_mutex_unlock(&ooh323c_cmd_lock);
+ ast_set_flag(p, H323_ALREADYGONE);
+ }
+ break;
+ case AST_CONTROL_BUSY:
+ if (!ast_test_flag(p, H323_ALREADYGONE)) {
+ ast_mutex_lock(&ooh323c_cmd_lock);
+ ooHangCall(callToken, OO_REASON_LOCAL_BUSY);
+ ast_mutex_unlock(&ooh323c_cmd_lock);
+ ast_set_flag(p, H323_ALREADYGONE);
+ }
+ break;
+ case AST_CONTROL_HOLD:
+ ast_moh_start(ast, data, NULL);
+ break;
+ case AST_CONTROL_UNHOLD:
+ ast_moh_stop(ast);
+ break;
+ case AST_CONTROL_PROCEEDING:
+ case AST_CONTROL_RINGING:
+ case AST_CONTROL_PROGRESS:
+ case -1:
+ break;
+ default:
+ ast_log(LOG_WARNING, "Don't know how to indicate condition %d on %s\n",
+ condition, callToken);
+ }
+
+ if (gH323Debug)
+ ast_verbose("++++ ooh323_indicate %d on %s\n", condition, callToken);
+
+
+ return -1;
+}
+
+static int ooh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
+{
+ struct ooh323_pvt *p = newchan->tech_pvt;
+
+ if (gH323Debug)
+ ast_verbose("--- ooh323c ooh323_fixup\n");
+
+ ast_mutex_lock(&p->lock);
+ if (p->owner != oldchan) {
+ ast_log(LOG_WARNING, "Old channel wasn't %p but was %p\n", oldchan, p->owner);
+ ast_mutex_unlock(&p->lock);
+ return -1;
+ }
+
+ if (p->owner == oldchan) {
+ p->owner = newchan;
+ } else {
+ p->owner = oldchan;
+ }
+
+ ast_mutex_unlock(&p->lock);
+
+ if (gH323Debug)
+ ast_verbose("+++ ooh323c ooh323_fixup \n");
+
+ return 0;
+}
+
+
+void ooh323_set_write_format(ooCallData *call, int fmt)
+{
+#if 0
+ struct ooh323_pvt *p = NULL;
+ char formats[512];
+#ifdef print_debug
+ printf("--- ooh323_update_writeformat %s\n",
+ ast_getformatname_multiple(formats,512, fmt));
+#endif
+
+ p = find_call(call);
+ if (!p) {
+ ast_log(LOG_ERROR, "No matching call found for %s\n", call->callToken);
+ return;
+ }
+
+ ast_mutex_lock(&p->lock);
+
+ p->writeformat = fmt;
+ ast_mutex_unlock(&p->lock);
+
+ if (p->owner) {
+ printf("Writeformat before update %s\n",
+ ast_getformatname_multiple(formats,512, p->owner->writeformat));
+ ast_set_write_format(p->owner, fmt);
+ }
+ else
+ ast_log(LOG_ERROR, "No owner found\n");
+
+
+#ifdef print_debug
+ printf("+++ ooh323_update_writeformat\n");
+#endif
+#endif
+}
+
+
+void ooh323_set_read_format(ooCallData *call, int fmt)
+{
+#if 0
+ struct ooh323_pvt *p = NULL;
+ char formats[512];
+#ifdef print_debug
+ printf("--- ooh323_update_readformat %s\n",
+ ast_getformatname_multiple(formats,512, fmt));
+#endif
+
+ p = find_call(call);
+ if (!p) {
+ ast_log(LOG_ERROR, "No matching call found for %s\n", call->callToken);
+ return;
+ }
+
+ ast_mutex_lock(&p->lock);
+ p->readformat = fmt;
+ ast_mutex_unlock(&p->lock);
+ ast_set_read_format(p->owner, fmt);
+
+#ifdef print_debug
+ printf("+++ ooh323_update_readformat\n");
+#endif
+#endif
+}
+
+int onAlerting(ooCallData *call)
+{
+ struct ooh323_pvt *p = NULL;
+ struct ast_channel *c = NULL;
+
+ if (gH323Debug)
+ ast_verbose("--- onAlerting %s\n", call->callToken);
+
+ if (!(p = find_call(call))) {
+ ast_log(LOG_ERROR, "No matching call found\n");
+ return -1;
+ }
+ ast_mutex_lock(&p->lock);
+ if (!ast_test_flag(p, H323_OUTGOING)) {
+ if (!(c = ooh323_new(p, AST_STATE_RING, p->username))) {
+ ast_mutex_unlock(&p->lock);
+ ast_log(LOG_ERROR, "Could not create ast_channel\n");
+ return -1;
+ }
+ ast_mutex_unlock(&p->lock);
+ } else {
+ if (!p->owner) {
+ ast_mutex_unlock(&p->lock);
+ ast_log(LOG_ERROR, "Channel has no owner\n");
+ return 0;
+ }
+ c = p->owner;
+ ast_mutex_unlock(&p->lock);
+ ast_channel_lock(c);
+ ast_setstate(c, AST_STATE_RINGING);
+ ast_channel_unlock(c);
+ ast_queue_control(c, AST_CONTROL_RINGING);
+ }
+
+ if (gH323Debug)
+ ast_verbose("+++ onAlerting %s\n", call->callToken);
+
+ return OO_OK;
+}
+
+/**
+ * Callback for sending digits from H.323 up to asterisk
+ *
+ */
+int ooh323_onReceivedDigit(OOH323CallData *call, const char *digit)
+{
+ struct ooh323_pvt *p = NULL;
+ struct ast_frame f;
+ int res;
+
+ ast_debug(1, "Received Digit: %c\n", digit[0]);
+ p = find_call(call);
+ if (!p) {
+ ast_log(LOG_ERROR, "Failed to find a matching call.\n");
+ return -1;
+ }
+ if (!p->owner) {
+ ast_log(LOG_ERROR, "Channel has no owner\n");
+ return -1;
+ }
+ ast_mutex_lock(&p->lock);
+ memset(&f, 0, sizeof(f));
+ f.frametype = AST_FRAME_DTMF;
+ f.subclass = digit[0];
+ f.datalen = 0;
+ f.samples = 800;
+ f.offset = 0;
+ f.data.ptr = NULL;
+ f.mallocd = 0;
+ f.src = "SEND_DIGIT";
+ ast_mutex_unlock(&p->lock);
+ res = ast_queue_frame(p->owner, &f);
+ return res;
+}
+
+int ooh323_onReceivedSetup(ooCallData *call, Q931Message *pmsg)
+{
+ struct ooh323_pvt *p = NULL;
+ struct ooh323_user *user = NULL;
+ ooAliases *alias = NULL;
+ char *at = NULL;
+ char number [OO_MAX_NUMBER_LENGTH];
+
+ if (gH323Debug)
+ ast_verbose("--- ooh323_onReceivedSetup %s\n", call->callToken);
+
+
+ if (!(p = ooh323_alloc(call->callReference, call->callToken))) {
+ ast_log(LOG_ERROR, "Failed to create a new call.\n");
+ return -1;
+ }
+ ast_mutex_lock(&p->lock);
+ ast_clear_flag(p, H323_OUTGOING);
+
+
+ if (call->remoteDisplayName) {
+ p->callerid_name = strdup(call->remoteDisplayName);
+ }
+
+ if (ooCallGetCallingPartyNumber(call, number, OO_MAX_NUMBER_LENGTH) == OO_OK) {
+ p->callerid_num = strdup(number);
+ }
+
+ if (call->remoteAliases) {
+ for (alias = call->remoteAliases; alias; alias = alias->next) {
+ if (alias->type == T_H225AliasAddress_h323_ID) {
+ if (!p->callerid_name) {
+ p->callerid_name = strdup(alias->value);
+ }
+ ast_copy_string(p->caller_h323id, alias->value, sizeof(p->caller_h323id));
+ } else if (alias->type == T_H225AliasAddress_dialedDigits) {
+ if (!p->callerid_num) {
+ p->callerid_num = strdup(alias->value);
+ }
+ ast_copy_string(p->caller_dialedDigits, alias->value,
+ sizeof(p->caller_dialedDigits));
+ } else if (alias->type == T_H225AliasAddress_email_ID) {
+ ast_copy_string(p->caller_email, alias->value, sizeof(p->caller_email));
+ } else if (alias->type == T_H225AliasAddress_url_ID) {
+ ast_copy_string(p->caller_url, alias->value, sizeof(p->caller_url));
+ }
+ }
+ }
+
+ number[0] = '\0';
+ if (ooCallGetCalledPartyNumber(call, number, OO_MAX_NUMBER_LENGTH) == OO_OK) {
+ ast_copy_string(p->exten, number, sizeof(p->exten));
+ } else {
+ update_our_aliases(call, p);
+ if (!ast_strlen_zero(p->callee_dialedDigits)) {
+ ast_copy_string(p->exten, p->callee_dialedDigits, sizeof(p->exten));
+ } else if (!ast_strlen_zero(p->callee_h323id)) {
+ ast_copy_string(p->exten, p->callee_h323id, sizeof(p->exten));
+ } else if (!ast_strlen_zero(p->callee_email)) {
+ ast_copy_string(p->exten, p->callee_email, sizeof(p->exten));
+ if ((at = strchr(p->exten, '@'))) {
+ *at = '\0';
+ }
+ }
+ }
+
+ /* if no extension found, set to default 's' */
+ if (ast_strlen_zero(p->exten)) {
+ ast_copy_string(p->exten, "s", sizeof(p->exten));
+ }
+
+ if (!p->callerid_name) {
+ p->callerid_name = strdup(call->remoteIP);
+ }
+
+ if (p->callerid_name) {
+ if ((user = find_user(p->callerid_name, call->remoteIP))) {
+ ast_mutex_lock(&user->lock);
+ p->username = strdup(user->name);
+ ast_copy_string(p->context, user->context, sizeof(p->context));
+ ast_copy_string(p->accountcode, user->accountcode, sizeof(p->accountcode));
+ p->amaflags = user->amaflags;
+ p->capability = user->capability;
+ memcpy(&p->prefs, &user->prefs, sizeof(struct ast_codec_pref));
+ p->dtmfmode = user->dtmfmode;
+ /* Since, call is coming from a pbx user, no need to use gk */
+ OO_SETFLAG(p->flags, H323_DISABLEGK);
+ OO_SETFLAG(call->flags, OO_M_DISABLEGK);
+ ast_mutex_unlock(&user->lock);
+ }
+ }
+
+
+ ooh323c_set_capability_for_call(call, &p->prefs, p->capability, p->dtmfmode);
+ configure_local_rtp(p, call);
+
+ ast_mutex_unlock(&p->lock);
+
+ if (gH323Debug)
+ ast_verbose("+++ ooh323_onReceivedSetup - Determined context %s, "
+ "extension %s\n", p->context, p->exten);
+
+ return OO_OK;
+}
+
+
+
+int onNewCallCreated(ooCallData *call)
+{
+ struct ooh323_pvt *p = NULL;
+ int i = 0;
+
+ if (gH323Debug)
+ ast_verbose("--- onNewCallCreated %s\n", call->callToken);
+
+ if (!strcmp(call->callType, "outgoing")) {
+ p = find_call(call);
+ if (!p) {
+ ast_log(LOG_ERROR, "No matching call found for outgoing call\n");
+ return -1;
+ }
+ ast_mutex_lock(&p->lock);
+ if (p->callerid_name) {
+ ooCallSetCallerId(call, p->callerid_name);
+ }
+ if (p->callerid_num) {
+ i = 0;
+ while (*(p->callerid_num + i) != '\0') {
+ if (!isdigit(*(p->callerid_num + i))) {
+ break;
+ }
+ i++;
+ }
+ if (*(p->callerid_num + i) == '\0') {
+ ooCallSetCallingPartyNumber(call, p->callerid_num);
+ } else {
+ if (!p->callerid_name) {
+ ooCallSetCallerId(call, p->callerid_num);
+ }
+ }
+ }
+
+ if (!ast_strlen_zero(p->caller_h323id))
+ ooCallAddAliasH323ID(call, p->caller_h323id);
+
+ if (!ast_strlen_zero(p->caller_dialedDigits)) {
+ if (gH323Debug) {
+ ast_verbose("Setting dialed digits %s\n", p->caller_dialedDigits);
+ }
+ ooCallAddAliasDialedDigits(call, p->caller_dialedDigits);
+ } else if (p->callerid_num) {
+ if (ooIsDailedDigit(p->callerid_num)) {
+ if (gH323Debug) {
+ ast_verbose("setting callid number %s\n", p->callerid_num);
+ }
+ ooCallAddAliasDialedDigits(call, p->callerid_num);
+ } else if (ast_strlen_zero(p->caller_h323id)) {
+ ooCallAddAliasH323ID(call, p->callerid_num);
+ }
+ }
+
+
+ if (!ast_strlen_zero(p->exten)) {
+ if (ooIsDailedDigit(p->exten)) {
+ ooCallSetCalledPartyNumber(call, p->exten);
+ ooCallAddRemoteAliasDialedDigits(call, p->exten);
+ } else {
+ ooCallAddRemoteAliasH323ID(call, p->exten);
+ }
+ }
+
+ if (gH323Debug) {
+ char prefsBuf[256];
+ ast_codec_pref_string(&p->prefs, prefsBuf, sizeof(prefsBuf));
+ ast_verbose(" Outgoing call %s(%s) - Codec prefs - %s\n",
+ p->username?p->username:"NULL", call->callToken, prefsBuf);
+ }
+
+ ooh323c_set_capability_for_call(call, &p->prefs, p->capability, p->dtmfmode);
+
+ configure_local_rtp(p, call);
+ ast_mutex_unlock(&p->lock);
+ }
+ if (gH323Debug)
+ ast_verbose("+++ onNewCallCreated %s\n", call->callToken);
+
+ return OO_OK;
+}
+
+int onCallEstablished(ooCallData *call)
+{
+ struct ooh323_pvt *p = NULL;
+
+ if (gH323Debug)
+ ast_verbose("--- onCallEstablished %s\n", call->callToken);
+
+ if (!(p = find_call(call))) {
+ ast_log(LOG_ERROR, "Failed to find a matching call.\n");
+ return -1;
+ }
+ ast_mutex_lock(&p->lock);
+ if (!p->owner) {
+ ast_mutex_unlock(&p->lock);
+ ast_log(LOG_ERROR, "Channel has no owner\n");
+ return -1;
+ }
+
+ while (ast_channel_trylock(p->owner)) {
+ ast_debug(1,"Failed to grab lock, trying again\n");
+ ast_mutex_unlock(&p->lock);
+ usleep(1);
+ ast_mutex_lock(&p->lock);
+ }
+ if (p->owner->_state != AST_STATE_UP) {
+ ast_setstate(p->owner, AST_STATE_UP);
+ }
+ ast_channel_unlock(p->owner);
+ if (ast_test_flag(p, H323_OUTGOING)) {
+ struct ast_channel* c = p->owner;
+ ast_mutex_unlock(&p->lock);
+ ast_queue_control(c, AST_CONTROL_ANSWER);
+ } else {
+ ast_mutex_unlock(&p->lock);
+ }
+
+ if (gH323Debug)
+ ast_verbose("+++ onCallEstablished %s\n", call->callToken);
+
+ return OO_OK;
+}
+
+int onCallCleared(ooCallData *call)
+{
+ struct ooh323_pvt *p = NULL;
+ int ownerLock = 0;
+
+ if (gH323Debug)
+ ast_verbose("--- onCallCleared %s \n", call->callToken);
+
+ p = find_call(call);
+ if (!p) {
+ return 0;
+ }
+ ast_mutex_lock(&p->lock);
+
+ while (p->owner) {
+ if (ast_channel_trylock(p->owner)) {
+ ooTrace(OOTRCLVLINFO, "Failed to grab lock, trying again\n");
+ ast_debug(1,"Failed to grab lock, trying again\n");
+ ast_mutex_unlock(&p->lock);
+ usleep(1);
+ ast_mutex_lock(&p->lock);
+ } else {
+ ownerLock = 1;
+ break;
+ }
+ }
+
+ if (ownerLock) {
+ if (!ast_test_flag(p, H323_ALREADYGONE)) {
+
+ /* NOTE: Channel is not detached yet */
+ ast_set_flag(p, H323_ALREADYGONE);
+ p->owner->hangupcause =
+ ooh323_convert_hangupcause_h323ToAsterisk(call->callEndReason);
+ p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+ ast_channel_unlock(p->owner);
+ ast_queue_hangup(p->owner);
+ ast_mutex_unlock(&p->lock);
+ return OO_OK;
+ }
+ ast_channel_unlock(p->owner);
+ }
+ ast_set_flag(p, H323_NEEDDESTROY);
+ ast_mutex_unlock(&p->lock);
+
+ if (gH323Debug)
+ ast_verbose("+++ onCallCleared\n");
+
+ return OO_OK;
+}
+
+#if 0
+static void ooh323_delete_user(struct ooh323_user *user)
+{
+ struct ooh323_user *prev = NULL, *cur = NULL;
+
+ if (gH323Debug)
+ ast_verbose("--- ooh323_delete_user\n");
+
+ if (user) {
+ cur = userl.users;
+ ast_mutex_lock(&userl.lock);
+ while (cur) {
+ if (cur == user) break;
+ prev = cur;
+ cur = cur->next;
+ }
+
+ if (cur) {
+ if (prev)
+ prev->next = cur->next;
+ else
+ userl.users = cur->next;
+ }
+ ast_mutex_unlock(&userl.lock);
+
+ free(user);
+ }
+
+ if (gH323Debug)
+ ast_verbose("+++ ooh323_delete_user\n");
+
+}
+#endif
+
+void ooh323_delete_peer(struct ooh323_peer *peer)
+{
+ struct ooh323_peer *prev = NULL, *cur = NULL;
+
+ if (gH323Debug)
+ ast_verbose("--- ooh323_delete_peer\n");
+
+ if (peer) {
+ ast_mutex_lock(&peerl.lock);
+ for (cur = peerl.peers; cur; prev = cur, cur = cur->next) {
+ if (cur == peer) {
+ break;
+ }
+ }
+
+ if (cur) {
+ if (prev) {
+ prev->next = cur->next;
+ } else {
+ peerl.peers = cur->next;
+ }
+ }
+ ast_mutex_unlock(&peerl.lock);
+
+ if (peer->h323id)
+ free(peer->h323id);
+ if (peer->email)
+ free(peer->email);
+ if (peer->url)
+ free(peer->url);
+ if (peer->e164)
+ free(peer->e164);
+
+ free(peer);
+ }
+
+ if (gH323Debug)
+ ast_verbose("+++ ooh323_delete_peer\n");
+}
+
+
+
+static struct ooh323_user *build_user(const char *name, struct ast_variable *v)
+{
+ struct ooh323_user *user = NULL;
+
+ if (gH323Debug)
+ ast_verbose("--- build_user\n");
+
+ user = ast_calloc(1, sizeof(*user));
+ if (user) {
+ ast_mutex_init(&user->lock);
+ ast_copy_string(user->name, name, sizeof(user->name));
+ user->capability = gCapability;
+ memcpy(&user->prefs, &gPrefs, sizeof(user->prefs));
+ user->rtptimeout = gRTPTimeout;
+ user->dtmfmode = gDTMFMode;
+ /* set default context */
+ ast_copy_string(user->context, gContext, sizeof(user->context));
+ ast_copy_string(user->accountcode, gAccountcode, sizeof(user->accountcode));
+ user->amaflags = gAMAFLAGS;
+
+ while (v) {
+ if (!strcasecmp(v->name, "context")) {
+ ast_copy_string(user->context, v->value, sizeof(user->context));
+ } else if (!strcasecmp(v->name, "incominglimit")) {
+ user->incominglimit = atoi(v->value);
+ if (user->incominglimit < 0)
+ user->incominglimit = 0;
+ } else if (!strcasecmp(v->name, "accountcode")) {
+ ast_copy_string(user->accountcode, v->value, sizeof(user->accountcode));
+ } else if (!strcasecmp(v->name, "rtptimeout")) {
+ user->rtptimeout = atoi(v->value);
+ if (user->rtptimeout < 0)
+ user->rtptimeout = gRTPTimeout;
+ } else if (!strcasecmp(v->name, "disallow")) {
+ ast_parse_allow_disallow(&user->prefs, &user->capability,
+ v->value, 0);
+ } else if (!strcasecmp(v->name, "allow")) {
+ const char* tcodecs = v->value;
+ if (!strcasecmp(v->value, "all")) {
+ tcodecs = "ulaw,alaw,g729,g723,gsm";
+ }
+ ast_parse_allow_disallow(&user->prefs, &user->capability,
+ tcodecs, 1);
+ } else if (!strcasecmp(v->name, "amaflags")) {
+ user->amaflags = ast_cdr_amaflags2int(v->value);
+ } else if (!strcasecmp(v->name, "ip")) {
+ ast_copy_string(user->mIP, v->value, sizeof(user->mIP));
+ user->mUseIP = 1;
+ } else if (!strcasecmp(v->name, "dtmfmode")) {
+ if (!strcasecmp(v->value, "rfc2833"))
+ user->dtmfmode = H323_DTMF_RFC2833;
+ else if (!strcasecmp(v->value, "q931keypad"))
+ user->dtmfmode = H323_DTMF_Q931;
+ else if (!strcasecmp(v->value, "h245alphanumeric"))
+ user->dtmfmode = H323_DTMF_H245ALPHANUMERIC;
+ else if (!strcasecmp(v->value, "h245signal"))
+ user->dtmfmode = H323_DTMF_H245SIGNAL;
+ }
+ v = v->next;
+ }
+ }
+
+ if (gH323Debug)
+ ast_verbose("+++ build_user\n");
+
+ return user;
+}
+
+static struct ooh323_peer *build_peer(const char *name, struct ast_variable *v, int friend_type)
+{
+ struct ooh323_peer *peer = NULL;
+
+ if (gH323Debug)
+ ast_verbose("--- build_peer\n");
+
+ peer = ast_calloc(1, sizeof(*peer));
+ if (peer) {
+ memset(peer, 0, sizeof(struct ooh323_peer));
+ ast_mutex_init(&peer->lock);
+ ast_copy_string(peer->name, name, sizeof(peer->name));
+ peer->capability = gCapability;
+ memcpy(&peer->prefs, &gPrefs, sizeof(struct ast_codec_pref));
+ peer->rtptimeout = gRTPTimeout;
+ ast_copy_string(peer->accountcode, gAccountcode, sizeof(peer->accountcode));
+ peer->amaflags = gAMAFLAGS;
+ peer->dtmfmode = gDTMFMode;
+ if (0 == friend_type) {
+ peer->mFriend = 1;
+ }
+
+ while (v) {
+ if (!strcasecmp(v->name, "h323id")) {
+ if (!(peer->h323id = ast_strdup(v->value))) {
+ ast_log(LOG_ERROR, "Could not allocate memory for h323id of "
+ "peer %s\n", name);
+ ooh323_delete_peer(peer);
+ return NULL;
+ }
+ } else if (!strcasecmp(v->name, "e164")) {
+ if (!(peer->e164 = ast_strdup(v->value))) {
+ ast_log(LOG_ERROR, "Could not allocate memory for e164 of "
+ "peer %s\n", name);
+ ooh323_delete_peer(peer);
+ return NULL;
+ }
+ } else if (!strcasecmp(v->name, "email")) {
+ if (!(peer->email = ast_strdup(v->value))) {
+ ast_log(LOG_ERROR, "Could not allocate memory for email of "
+ "peer %s\n", name);
+ ooh323_delete_peer(peer);
+ return NULL;
+ }
+ } else if (!strcasecmp(v->name, "url")) {
+ if (!(peer->url = ast_strdup(v->value))) {
+ ast_log(LOG_ERROR, "Could not allocate memory for h323id of "
+ "peer %s\n", name);
+ ooh323_delete_peer(peer);
+ return NULL;
+ }
+ } else if (!strcasecmp(v->name, "port")) {
+ peer->port = atoi(v->value);
+ } else if (!strcasecmp(v->name, "ip")) {
+ ast_copy_string(peer->ip, v->value, sizeof(peer->ip));
+ } else if (!strcasecmp(v->name, "outgoinglimit")) {
+ if ((peer->outgoinglimit = atoi(v->value)) < 0) {
+ peer->outgoinglimit = 0;
+ }
+ } else if (!strcasecmp(v->name, "accountcode")) {
+ ast_copy_string(peer->accountcode, v->value, sizeof(peer->accountcode));
+ } else if (!strcasecmp(v->name, "rtptimeout")) {
+ if ((peer->rtptimeout = atoi(v->value)) < 0) {
+ peer->rtptimeout = gRTPTimeout;
+ }
+ } else if (!strcasecmp(v->name, "disallow")) {
+ ast_parse_allow_disallow(&peer->prefs, &peer->capability,
+ v->value, 0);
+ } else if (!strcasecmp(v->name, "allow")) {
+ const char* tcodecs = v->value;
+ if (!strcasecmp(v->value, "all")) {
+ tcodecs = "ulaw,alaw,g729,g723,gsm";
+ }
+ ast_parse_allow_disallow(&peer->prefs, &peer->capability,
+ tcodecs, 1);
+ } else if (!strcasecmp(v->name, "amaflags")) {
+ peer->amaflags = ast_cdr_amaflags2int(v->value);
+ } else if (!strcasecmp(v->name, "dtmfmode")) {
+ if (!strcasecmp(v->value, "rfc2833"))
+ peer->dtmfmode = H323_DTMF_RFC2833;
+ else if (!strcasecmp(v->value, "q931keypad"))
+ peer->dtmfmode = H323_DTMF_Q931;
+ else if (!strcasecmp(v->value, "h245alphanumeric"))
+ peer->dtmfmode = H323_DTMF_H245ALPHANUMERIC;
+ else if (!strcasecmp(v->value, "h245signal"))
+ peer->dtmfmode = H323_DTMF_H245SIGNAL;
+ }
+ v = v->next;
+ }
+ }
+
+ if (gH323Debug)
+ ast_verbose("+++ build_peer\n");
+
+ return peer;
+}
+
+static int ooh323_do_reload(void)
+{
+ if (gH323Debug) {
+ ast_verbose("--- ooh323_do_reload\n");
+ }
+
+ reload_config(1);
+
+ if (gH323Debug) {
+ ast_verbose("+++ ooh323_do_reload\n");
+ }
+
+ return 0;
+}
+
+#if 0
+/*--- h323_reload: Force reload of module from cli ---*/
+static int ooh323_reload(int fd, int argc, char *argv[])
+{
+
+ if (gH323Debug)
+ ast_verbose("--- ooh323_reload\n");
+
+ ast_mutex_lock(&h323_reload_lock);
+ if (h323_reloading) {
+ ast_verbose("Previous OOH323 reload not yet done\n");
+ }
+ else {
+ h323_reloading = 1;
+ }
+ ast_mutex_unlock(&h323_reload_lock);
+ restart_monitor();
+
+ if (gH323Debug)
+ ast_verbose("+++ ooh323_reload\n");
+
+ return 0;
+}
+#endif
+
+#if 0
+static int reload(void *mod)
+{
+ return ooh323_reload(0, 0, NULL);
+}
+#endif
+
+int reload_config(int reload)
+{
+ int format;
+ struct ooAliases *pNewAlias = NULL;
+ struct ast_config *cfg;
+ struct ast_variable *v;
+ struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+ struct ooh323_user *user = NULL;
+ struct ooh323_peer *peer = NULL;
+ char *cat;
+ const char *utype;
+
+ if (gH323Debug)
+ ast_verbose("--- reload_config\n");
+
+ cfg = ast_config_load((char*)config, config_flags);
+
+ /* We *must* have a config file otherwise stop immediately */
+ if (!cfg) {
+ ast_log(LOG_NOTICE, "Unable to load config %s, OOH323 disabled\n", config);
+ return 1;
+ } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
+ return RESULT_SUCCESS;
+
+ if (reload) {
+ delete_users();
+ delete_peers();
+ }
+
+ /* Inintialize everything to default */
+ strcpy(gLogFile, DEFAULT_LOGFILE);
+ gPort = 1720;
+ gIP[0] = '\0';
+ strcpy(gCallerID, DEFAULT_H323ID);
+ gCapability = AST_FORMAT_ULAW;
+ memset(&gPrefs, 0, sizeof(struct ast_codec_pref));
+ gDTMFMode = H323_DTMF_RFC2833;
+ gRasGkMode = RasNoGatekeeper;
+ gGatekeeper[0] = '\0';
+ gRTPTimeout = 60;
+ strcpy(gAccountcode, DEFAULT_H323ACCNT);
+ gFastStart = 1;
+ gTunneling = 1;
+ gTOS = 0;
+ strcpy(gContext, DEFAULT_CONTEXT);
+ gAliasList = NULL;
+ gMediaWaitForConnect = 0;
+ ooconfig.mTCPPortStart = 12030;
+ ooconfig.mTCPPortEnd = 12230;
+
+ v = ast_variable_browse(cfg, "general");
+ while (v) {
+
+ if (!strcasecmp(v->name, "port")) {
+ gPort = (int)strtol(v->value, NULL, 10);
+ } else if (!strcasecmp(v->name, "bindaddr")) {
+ ast_copy_string(gIP, v->value, sizeof(gIP));
+ } else if (!strcasecmp(v->name, "h225portrange")) {
+ char* endlimit = 0;
+ char temp[256];
+ ast_copy_string(temp, v->value, sizeof(temp));
+ endlimit = strchr(temp, ',');
+ if (endlimit) {
+ *endlimit = '\0';
+ endlimit++;
+ ooconfig.mTCPPortStart = atoi(temp);
+ ooconfig.mTCPPortEnd = atoi(endlimit);
+
+ if (ooH323EpSetTCPPortRange(ooconfig.mTCPPortStart,
+ ooconfig.mTCPPortEnd) == OO_FAILED) {
+ ast_log(LOG_ERROR, "h225portrange: Failed to set range\n");
+ }
+ } else {
+ ast_log(LOG_ERROR, "h225portrange: Invalid format, separate port range with \",\"\n");
+ }
+ } else if (!strcasecmp(v->name, "gateway")) {
+ gIsGateway = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "faststart")) {
+ gFastStart = ast_true(v->value);
+ if (gFastStart)
+ ooH323EpEnableFastStart();
+ else
+ ooH323EpDisableFastStart();
+ } else if (!strcasecmp(v->name, "mediawaitforconnect")) {
+ gMediaWaitForConnect = ast_true(v->value);
+ if (gMediaWaitForConnect)
+ ooH323EpEnableMediaWaitForConnect();
+ else
+ ooH323EpDisableMediaWaitForConnect();
+ } else if (!strcasecmp(v->name, "h245tunneling")) {
+ gTunneling = ast_true(v->value);
+ if (gTunneling)
+ ooH323EpEnableH245Tunneling();
+ else
+ ooH323EpDisableH245Tunneling();
+ } else if (!strcasecmp(v->name, "h323id")) {
+ pNewAlias = malloc(sizeof(*pNewAlias));
+ if (!pNewAlias) {
+ ast_log(LOG_ERROR, "Failed to allocate memory for h323id alias\n");
+ return 1;
+ }
+ pNewAlias->type = T_H225AliasAddress_h323_ID;
+ pNewAlias->value = strdup(v->value);
+ pNewAlias->next = gAliasList;
+ gAliasList = pNewAlias;
+ pNewAlias = NULL;
+ } else if (!strcasecmp(v->name, "e164")) {
+ pNewAlias = malloc(sizeof(*pNewAlias));
+ if (!pNewAlias) {
+ ast_log(LOG_ERROR, "Failed to allocate memory for e164 alias\n");
+ return 1;
+ }
+ pNewAlias->type = T_H225AliasAddress_dialedDigits;
+ pNewAlias->value = strdup(v->value);
+ pNewAlias->next = gAliasList;
+ gAliasList = pNewAlias;
+ pNewAlias = NULL;
+ } else if (!strcasecmp(v->name, "email")) {
+ pNewAlias = malloc(sizeof(*pNewAlias));
+ if (!pNewAlias) {
+ ast_log(LOG_ERROR, "Failed to allocate memory for email alias\n");
+ return 1;
+ }
+ pNewAlias->type = T_H225AliasAddress_email_ID;
+ pNewAlias->value = strdup(v->value);
+ pNewAlias->next = gAliasList;
+ gAliasList = pNewAlias;
+ pNewAlias = NULL;
+ } else if (!strcasecmp(v->name, "callerid")) {
+ ast_copy_string(gCallerID, v->value, sizeof(gCallerID));
+ } else if (!strcasecmp(v->name, "incominglimit")) {
+ gIncomingLimit = atoi(v->value);
+ } else if (!strcasecmp(v->name, "outgoinglimit")) {
+ gOutgoingLimit = atoi(v->value);
+ } else if (!strcasecmp(v->name, "gatekeeper")) {
+ if (!strcasecmp(v->value, "DISABLE")) {
+ gRasGkMode = RasNoGatekeeper;
+ } else if (!strcasecmp(v->value, "DISCOVER")) {
+ gRasGkMode = RasDiscoverGatekeeper;
+ } else {
+ gRasGkMode = RasUseSpecificGatekeeper;
+ ast_copy_string(gGatekeeper, v->value, sizeof(gGatekeeper));
+ }
+ } else if (!strcasecmp(v->name, "logfile")) {
+ ast_copy_string(gLogFile, v->value, sizeof(gLogFile));
+ } else if (!strcasecmp(v->name, "context")) {
+ ast_copy_string(gContext, v->value, sizeof(gContext));
+ ast_verb(3, " == Setting default context to %s\n", gContext);
+ } else if (!strcasecmp(v->name, "rtptimeout")) {
+ gRTPTimeout = atoi(v->value);
+ if (gRTPTimeout <= 0)
+ gRTPTimeout = 60;
+ } else if (!strcasecmp(v->name, "tos")) {
+ if (sscanf(v->value, "%i", &format) == 1)
+ gTOS = format & 0xff;
+ else if (!strcasecmp(v->value, "lowdelay"))
+ gTOS = IPTOS_LOWDELAY;
+ else if (!strcasecmp(v->value, "throughput"))
+ gTOS = IPTOS_THROUGHPUT;
+ else if (!strcasecmp(v->value, "reliability"))
+ gTOS = IPTOS_RELIABILITY;
+ else if (!strcasecmp(v->value, "mincost"))
+ gTOS = IPTOS_MINCOST;
+ else if (!strcasecmp(v->value, "none"))
+ gTOS = 0;
+ else
+ ast_log(LOG_WARNING, "Invalid tos value at line %d, should be "
+ "'lowdelay', 'throughput', 'reliability', "
+ "'mincost', or 'none'\n", v->lineno);
+ } else if (!strcasecmp(v->name, "amaflags")) {
+ gAMAFLAGS = ast_cdr_amaflags2int(v->value);
+ } else if (!strcasecmp(v->name, "accountcode")) {
+ ast_copy_string(gAccountcode, v->value, sizeof(gAccountcode)-1);
+ } else if (!strcasecmp(v->name, "disallow")) {
+ ast_parse_allow_disallow(&gPrefs, &gCapability, v->value, 0);
+ } else if (!strcasecmp(v->name, "allow")) {
+ const char* tcodecs = v->value;
+ if (!strcasecmp(v->value, "all")) {
+ tcodecs = "ulaw,alaw,g729,g723,gsm";
+ }
+ ast_parse_allow_disallow(&gPrefs, &gCapability, tcodecs, 1);
+ } else if (!strcasecmp(v->name, "dtmfmode")) {
+ if (!strcasecmp(v->value, "inband"))
+ gDTMFMode = H323_DTMF_INBAND;
+ else if (!strcasecmp(v->value, "rfc2833"))
+ gDTMFMode = H323_DTMF_RFC2833;
+ else if (!strcasecmp(v->value, "q931keypad"))
+ gDTMFMode = H323_DTMF_Q931;
+ else if (!strcasecmp(v->value, "h245alphanumeric"))
+ gDTMFMode = H323_DTMF_H245ALPHANUMERIC;
+ else if (!strcasecmp(v->value, "h245signal"))
+ gDTMFMode = H323_DTMF_H245SIGNAL;
+ else {
+ ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value);
+ gDTMFMode = H323_DTMF_RFC2833;
+ }
+ }
+ v = v->next;
+ }
+
+ for (cat = ast_category_browse(cfg, NULL); cat; cat = ast_category_browse(cfg, cat)) {
+ if (strcasecmp(cat, "general")) {
+ int friend_type = 0;
+ utype = ast_variable_retrieve(cfg, cat, "type");
+ if (utype) {
+ friend_type = strcasecmp(utype, "friend");
+ if (!strcmp(utype, "user") || 0 == friend_type) {
+ user = build_user(cat, ast_variable_browse(cfg, cat));
+ if (user) {
+ ast_mutex_lock(&userl.lock);
+ user->next = userl.users;
+ userl.users = user;
+ ast_mutex_unlock(&userl.lock);
+ } else {
+ ast_log(LOG_WARNING, "Failed to build user %s\n", cat);
+ }
+ }
+ if (!strcasecmp(utype, "peer") || 0 == friend_type) {
+ peer = build_peer(cat, ast_variable_browse(cfg, cat), friend_type);
+ if (peer) {
+ ast_mutex_lock(&peerl.lock);
+ peer->next = peerl.peers;
+ peerl.peers = peer;
+ ast_mutex_unlock(&peerl.lock);
+ } else {
+ ast_log(LOG_WARNING, "Failed to build peer %s\n", cat);
+ }
+ }
+ }
+ }
+ }
+ ast_config_destroy(cfg);
+
+
+ /* Determine ip address if neccessary */
+ if (ast_strlen_zero(gIP)) {
+ ooGetLocalIPAddress(gIP);
+ if (!strcmp(gIP, "127.0.0.1")) {
+ ast_log(LOG_NOTICE, "Failed to determine local ip address. Please "
+ "specify it in ooh323.conf. OOH323 Disabled\n");
+ return 1;
+ }
+ }
+
+ if (gH323Debug)
+ ast_verbose("+++ reload_config\n");
+
+ return 0;
+}
+
+static char *handle_cli_ooh323_show_peer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ char ip_port[30];
+ struct ooh323_peer *prev = NULL, *peer = NULL;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ooh323 show peer";
+ e->usage =
+ "Usage: ooh323 show peer <name>\n"
+ " List details of specific OOH323 peer.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc != 4)
+ return CLI_SHOWUSAGE;
+
+ ast_mutex_lock(&peerl.lock);
+ peer = peerl.peers;
+ while (peer) {
+ ast_mutex_lock(&peer->lock);
+ if (!strcmp(peer->name, a->argv[3]))
+ break;
+ else {
+ prev = peer;
+ peer = peer->next;
+ ast_mutex_unlock(&prev->lock);
+ }
+ }
+
+ if (peer) {
+ snprintf(ip_port, sizeof(ip_port), "%s:%d", peer->ip, peer->port);
+ ast_cli(a->fd, "%-15.15s%s\n", "Name: ", peer->name);
+ ast_cli(a->fd, "%-15.15s%s", "Format Prefs: ", "(");
+ print_codec_to_cli(a->fd, &peer->prefs);
+ ast_cli(a->fd, ")\n");
+ ast_cli(a->fd, "%-15.15s", "DTMF Mode: ");
+ if (peer->dtmfmode & H323_DTMF_RFC2833)
+ ast_cli(a->fd, "%s\n", "rfc2833");
+ else if (peer->dtmfmode & H323_DTMF_Q931)
+ ast_cli(a->fd, "%s\n", "q931keypad");
+ else if (peer->dtmfmode & H323_DTMF_H245ALPHANUMERIC)
+ ast_cli(a->fd, "%s\n", "h245alphanumeric");
+ else if (peer->dtmfmode & H323_DTMF_H245SIGNAL)
+ ast_cli(a->fd, "%s\n", "h245signal");
+ else
+ ast_cli(a->fd, "%s\n", "unknown");
+ ast_cli(a->fd, "%-15.15s%s\n", "AccountCode: ", peer->accountcode);
+ ast_cli(a->fd, "%-15.15s%s\n", "AMA flags: ",
+ ast_cdr_flags2str(peer->amaflags));
+ ast_cli(a->fd, "%-15.15s%s\n", "Ip:Port: ", ip_port);
+ ast_cli(a->fd, "%-15.15s%d\n", "OutgoingLimit: ", peer->outgoinglimit);
+ ast_cli(a->fd, "%-15.15s%d\n", "rtptimeout: ", peer->rtptimeout);
+ ast_mutex_unlock(&peer->lock);
+ } else {
+ ast_cli(a->fd, "Peer %s not found\n", a->argv[3]);
+ ast_cli(a->fd, "\n");
+ }
+ ast_mutex_unlock(&peerl.lock);
+
+ return CLI_SUCCESS;
+}
+
+static char *handle_cli_ooh323_show_peers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ char ip_port[30];
+ char formats[512];
+ struct ooh323_peer *prev = NULL, *peer = NULL;
+
+#define FORMAT "%-15.15s %-15.15s %-23.23s %-s\n"
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ooh323 show peers";
+ e->usage =
+ "Usage: ooh323 show peers\n"
+ " Lists all known OOH323 peers.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc != 3)
+ return CLI_SHOWUSAGE;
+
+ ast_cli(a->fd, FORMAT, "Name", "Accountcode", "ip:port", "Formats");
+
+ ast_mutex_lock(&peerl.lock);
+ peer = peerl.peers;
+ while (peer) {
+ ast_mutex_lock(&peer->lock);
+ snprintf(ip_port, sizeof(ip_port), "%s:%d", peer->ip, peer->port);
+ ast_cli(a->fd, FORMAT, peer->name,
+ peer->accountcode,
+ ip_port,
+ ast_getformatname_multiple(formats, sizeof(formats), peer->capability));
+ prev = peer;
+ peer = peer->next;
+ ast_mutex_unlock(&prev->lock);
+ }
+ ast_mutex_unlock(&peerl.lock);
+
+#undef FORMAT
+
+ return CLI_SUCCESS;
+}
+
+/*! \brief Print codec list from preference to CLI/manager */
+static void print_codec_to_cli(int fd, struct ast_codec_pref *pref)
+{
+ int x, codec;
+
+ for (x = 0; x < 32; x++) {
+ codec = ast_codec_pref_index(pref, x);
+ if (!codec)
+ break;
+ ast_cli(fd, "%s", ast_getformatname(codec));
+ ast_cli(fd, ":%d", pref->framing[x]);
+ if (x < 31 && ast_codec_pref_index(pref, x + 1))
+ ast_cli(fd, ",");
+ }
+ if (!x)
+ ast_cli(fd, "none");
+}
+
+static char *handle_cli_ooh323_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ struct ooh323_user *prev = NULL, *user = NULL;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ooh323 show user";
+ e->usage =
+ "Usage: ooh323 show user <name>\n"
+ " List details of specific OOH323 user.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc != 4)
+ return CLI_SHOWUSAGE;
+
+ ast_mutex_lock(&userl.lock);
+ user = userl.users;
+ while (user) {
+ ast_mutex_lock(&user->lock);
+ if (!strcmp(user->name, a->argv[3]))
+ break;
+ else {
+ prev = user;
+ user = user->next;
+ ast_mutex_unlock(&prev->lock);
+ }
+ }
+
+ if (user) {
+ ast_cli(a->fd, "%-15.15s%s\n", "Name: ", user->name);
+ ast_cli(a->fd, "%-15.15s%s", "Format Prefs: ", "(");
+ print_codec_to_cli(a->fd, &user->prefs);
+ ast_cli(a->fd, ")\n");
+ ast_cli(a->fd, "%-15.15s", "DTMF Mode: ");
+ if (user->dtmfmode & H323_DTMF_RFC2833)
+ ast_cli(a->fd, "%s\n", "rfc2833");
+ else if (user->dtmfmode & H323_DTMF_Q931)
+ ast_cli(a->fd, "%s\n", "q931keypad");
+ else if (user->dtmfmode & H323_DTMF_H245ALPHANUMERIC)
+ ast_cli(a->fd, "%s\n", "h245alphanumeric");
+ else if (user->dtmfmode & H323_DTMF_H245SIGNAL)
+ ast_cli(a->fd, "%s\n", "h245signal");
+ else
+ ast_cli(a->fd, "%s\n", "unknown");
+ ast_cli(a->fd, "%-15.15s%s\n", "AccountCode: ", user->accountcode);
+ ast_cli(a->fd, "%-15.15s%s\n", "AMA flags: ", ast_cdr_flags2str(user->amaflags));
+ ast_cli(a->fd, "%-15.15s%s\n", "Context: ", user->context);
+ ast_cli(a->fd, "%-15.15s%d\n", "IncomingLimit: ", user->incominglimit);
+ ast_cli(a->fd, "%-15.15s%d\n", "rtptimeout: ", user->rtptimeout);
+ ast_mutex_unlock(&user->lock);
+ } else {
+ ast_cli(a->fd, "User %s not found\n", a->argv[3]);
+ ast_cli(a->fd, "\n");
+ }
+ ast_mutex_unlock(&userl.lock);
+
+ return CLI_SUCCESS;
+}
+
+static char *handle_cli_ooh323_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ char formats[512];
+ struct ooh323_user *prev = NULL, *user = NULL;
+
+#define FORMAT1 "%-15.15s %-15.15s %-15.15s %-s\n"
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ooh323 show users";
+ e->usage =
+ "Usage: ooh323 show users \n"
+ " Lists all known OOH323 users.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc != 3)
+ return CLI_SHOWUSAGE;
+
+ ast_cli(a->fd, FORMAT1, "Username", "Accountcode", "Context", "Formats");
+
+ ast_mutex_lock(&userl.lock);
+ user = userl.users;
+ while (user) {
+ ast_mutex_lock(&user->lock);
+ ast_cli(a->fd, FORMAT1, user->name,
+ user->accountcode, user->context,
+ ast_getformatname_multiple(formats, 512, user->capability));
+ prev = user;
+ user = user->next;
+ ast_mutex_unlock(&prev->lock);
+ }
+ ast_mutex_unlock(&userl.lock);
+
+#undef FORMAT1
+
+ return CLI_SUCCESS;
+}
+
+static char *handle_cli_ooh323_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ooh323 set debug [off]";
+ e->usage =
+ "Usage: ooh323 set debug [off]\n"
+ " Enables/Disables debugging of OOH323 channel driver\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc < 3 || a->argc > 4)
+ return CLI_SHOWUSAGE;
+ if (a->argc == 4 && strcasecmp(a->argv[3], "off"))
+ return CLI_SHOWUSAGE;
+
+ gH323Debug = (a->argc == 4) ? FALSE : TRUE;
+ ast_cli(a->fd, "OOH323 Debugging %s\n", gH323Debug ? "Enabled" : "Disabled");
+
+ return CLI_SUCCESS;
+}
+
+#if 0
+static int ooh323_show_channels(int fd, int argc, char *argv[])
+{
+ return RESULT_SUCCESS;
+}
+#endif
+
+static char *handle_cli_ooh323_show_config(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ char value[512];
+ ooAliases *pAlias = NULL, *pAliasNext = NULL;;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ooh323 show config";
+ e->usage =
+ "Usage: ooh323 show config\n"
+ " Shows global configuration of H.323 channel driver\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc != 3)
+ return CLI_SHOWUSAGE;
+
+ snprintf(value, sizeof(value), "%s:%d", gIP, gPort);
+ ast_cli(a->fd, "\nObjective Open H.323 Channel Driver's Config:\n");
+ ast_cli(a->fd, "%-20s%s\n", "IP:Port: ", value);
+ ast_cli(a->fd, "%-20s%s\n", "FastStart", gFastStart?"yes":"no");
+ ast_cli(a->fd, "%-20s%s\n", "Tunneling", gTunneling?"yes":"no");
+ ast_cli(a->fd, "%-20s%s\n", "CallerId", gCallerID);
+ ast_cli(a->fd, "%-20s%s\n", "MediaWaitForConnect", gMediaWaitForConnect ? "yes" : "no");
+
+#if 0
+ {
+ extern OOH323EndPoint gH323ep;
+
+ ast_cli(a->fd, "%-20s%s\n", "FASTSTART",
+ (OO_TESTFLAG(gH323ep.flags, OO_M_FASTSTART) != 0) ? "yes" : "no");
+ ast_cli(a->fd, "%-20s%s\n", "TUNNELING",
+ (OO_TESTFLAG(gH323ep.flags, OO_M_TUNNELING) != 0) ? "yes" : "no");
+ ast_cli(a->fd, "%-20s%s\n", "MEDIAWAITFORCONN",
+ (OO_TESTFLAG(gH323ep.flags, OO_M_MEDIAWAITFORCONN) != 0) ? "yes" : "no");
+ }
+#endif
+
+ if (gRasGkMode == RasNoGatekeeper)
+ snprintf(value, sizeof(value), "%s", "No Gatekeeper");
+ else if (gRasGkMode == RasDiscoverGatekeeper)
+ snprintf(value, sizeof(value), "%s", "Discover");
+ else
+ snprintf(value, sizeof(value), "%s", gGatekeeper);
+
+ ast_cli(a->fd, "%-20s%s\n", "Gatekeeper:", value);
+ ast_cli(a->fd, "%-20s%s\n", "H.323 LogFile:", gLogFile);
+ ast_cli(a->fd, "%-20s%s\n", "Context:", gContext);
+ ast_cli(a->fd, "%-20s%s\n", "Capability:", ast_getformatname_multiple(value, sizeof(value), gCapability));
+ ast_cli(a->fd, "%-20s", "DTMF Mode: ");
+ if (gDTMFMode & H323_DTMF_RFC2833)
+ ast_cli(a->fd, "%s\n", "rfc2833");
+ else if (gDTMFMode & H323_DTMF_Q931)
+ ast_cli(a->fd, "%s\n", "q931keypad");
+ else if (gDTMFMode & H323_DTMF_H245ALPHANUMERIC)
+ ast_cli(a->fd, "%s\n", "h245alphanumeric");
+ else if (gDTMFMode & H323_DTMF_H245SIGNAL)
+ ast_cli(a->fd, "%s\n", "h245signal");
+ else
+ ast_cli(a->fd, "%s\n", "unknown");
+ ast_cli(a->fd, "%-20s%s\n", "AccountCode: ", gAccountcode);
+ ast_cli(a->fd, "%-20s%s\n", "AMA flags: ", ast_cdr_flags2str(gAMAFLAGS));
+
+ pAlias = gAliasList;
+ if (pAlias)
+ ast_cli(a->fd, "%-20s\n", "Aliases: ");
+ while (pAlias) {
+ pAliasNext = pAlias->next;
+ if (pAliasNext) {
+ ast_cli(a->fd, "\t%-30s\t%-30s\n", pAlias->value, pAliasNext->value);
+ pAlias = pAliasNext->next;
+ } else {
+ ast_cli(a->fd, "\t%-30s\n", pAlias->value);
+ pAlias = pAlias->next;
+ }
+ }
+
+ return CLI_SUCCESS;
+}
+
+static struct ast_cli_entry cli_ooh323[] = {
+ AST_CLI_DEFINE(handle_cli_ooh323_set_debug, "Enable/Disable OOH323 debugging"),
+ AST_CLI_DEFINE(handle_cli_ooh323_show_config, "Show details on global configuration of H.323 channel driver"),
+ AST_CLI_DEFINE(handle_cli_ooh323_show_peer, "Show details on specific OOH323 peer"),
+ AST_CLI_DEFINE(handle_cli_ooh323_show_peers, "Show defined OOH323 peers"),
+ AST_CLI_DEFINE(handle_cli_ooh323_show_user, "Show details on specific OOH323 user"),
+ AST_CLI_DEFINE(handle_cli_ooh323_show_users, "Show defined OOH323 users"),
+};
+
+static int load_module(void)
+{
+ int res;
+ struct ooAliases * pNewAlias = NULL;
+ struct ooh323_peer *peer = NULL;
+ OOH225MsgCallbacks h225Callbacks = {0, 0, 0, 0};
+
+ OOH323CALLBACKS h323Callbacks = {
+ .onNewCallCreated = onNewCallCreated,
+ .onAlerting = onAlerting,
+ .onIncomingCall = NULL,
+ .onOutgoingCall = NULL,
+ .onCallEstablished = onCallEstablished,
+ .onCallCleared = onCallCleared,
+ .openLogicalChannels = NULL,
+ .onReceivedDTMF = &ooh323_onReceivedDigit
+ };
+
+ ast_log(LOG_NOTICE,
+ "---------------------------------------------------------------------------------\n"
+ "--- ******* IMPORTANT NOTE ***********\n"
+ "---\n"
+ "--- This module is currently unsupported. Use it at your own risk.\n"
+ "---\n"
+ "---------------------------------------------------------------------------------\n");
+
+ h225Callbacks.onReceivedSetup = &ooh323_onReceivedSetup;
+
+ userl.users = NULL;
+ ast_mutex_init(&userl.lock);
+ peerl.peers = NULL;
+ ast_mutex_init(&peerl.lock);
+
+#if 0
+ ast_register_atexit(&ast_ooh323c_exit);
+#endif
+
+ if (!(sched = sched_context_create())) {
+ ast_log(LOG_WARNING, "Unable to create schedule context\n");
+ }
+ if (!(io = io_context_create())) {
+ ast_log(LOG_WARNING, "Unable to create I/O context\n");
+ }
+
+
+ if (!(res = reload_config(0))) {
+ /* Make sure we can register our OOH323 channel type */
+ if (ast_channel_register(&ooh323_tech)) {
+ ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
+ return 0;
+ }
+ ast_rtp_proto_register(&ooh323_rtp);
+ ast_cli_register_multiple(cli_ooh323, sizeof(cli_ooh323) / sizeof(struct ast_cli_entry));
+
+ /* fire up the H.323 Endpoint */
+ if (OO_OK != ooH323EpInitialize(OO_CALLMODE_AUDIOCALL, gLogFile)) {
+ ast_log(LOG_ERROR, "Failed to initialize OOH323 endpoint-OOH323 Disabled\n");
+ return 1;
+ }
+
+ if (gIsGateway)
+ ooH323EpSetAsGateway();
+
+ ooH323EpDisableAutoAnswer();
+ ooH323EpSetH225MsgCallbacks(h225Callbacks);
+ ooH323EpSetTraceLevel(OOTRCLVLDBGC);
+ ooH323EpSetLocalAddress(gIP, gPort);
+ ooH323EpSetCallerID(gCallerID);
+
+ /* Set aliases if any */
+ for (pNewAlias = gAliasList; pNewAlias; pNewAlias = pNewAlias->next) {
+ switch (pNewAlias->type) {
+ case T_H225AliasAddress_h323_ID:
+ ooH323EpAddAliasH323ID(pNewAlias->value);
+ break;
+ case T_H225AliasAddress_dialedDigits:
+ ooH323EpAddAliasDialedDigits(pNewAlias->value);
+ break;
+ case T_H225AliasAddress_email_ID:
+ ooH323EpAddAliasEmailID(pNewAlias->value);
+ break;
+ }
+ }
+
+ ast_mutex_lock(&peerl.lock);
+ peer = peerl.peers;
+ while (peer) {
+ if (peer->h323id)
+ ooH323EpAddAliasH323ID(peer->h323id);
+ if (peer->email)
+ ooH323EpAddAliasEmailID(peer->email);
+ if (peer->e164)
+ ooH323EpAddAliasDialedDigits(peer->e164);
+ if (peer->url)
+ ooH323EpAddAliasURLID(peer->url);
+ peer = peer->next;
+ }
+ ast_mutex_unlock(&peerl.lock);
+
+
+ if (gMediaWaitForConnect)
+ ooH323EpEnableMediaWaitForConnect();
+ else
+ ooH323EpDisableMediaWaitForConnect();
+
+ /* Fast start and tunneling options */
+ if (gFastStart)
+ ooH323EpEnableFastStart();
+ else
+ ooH323EpDisableFastStart();
+
+ if (!gTunneling)
+ ooH323EpDisableH245Tunneling();
+
+ /* Gatekeeper */
+ if (gRasGkMode == RasUseSpecificGatekeeper)
+ ooGkClientInit(gRasGkMode, gGatekeeper, 0);
+ else if (gRasGkMode == RasDiscoverGatekeeper)
+ ooGkClientInit(gRasGkMode, 0, 0);
+
+ /* Register callbacks */
+ ooH323EpSetH323Callbacks(h323Callbacks);
+
+ /* Add endpoint capabilities */
+ if (ooh323c_set_capability(&gPrefs, gCapability, gDTMFMode) < 0) {
+ ast_log(LOG_ERROR, "Capabilities failure for OOH323. OOH323 Disabled.\n");
+ return 1;
+ }
+
+
+ /* Create H.323 listener */
+ if (ooCreateH323Listener() != OO_OK) {
+ ast_log(LOG_ERROR, "OOH323 Listener Creation failure. OOH323 DISABLED\n");
+
+ ooH323EpDestroy();
+ return 1;
+ }
+
+ if (ooh323c_start_stack_thread() < 0) {
+ ast_log(LOG_ERROR, "Failed to start OOH323 stack thread. OOH323 DISABLED\n");
+ ooH323EpDestroy();
+ return 1;
+ }
+ /* And start the monitor for the first time */
+ restart_monitor();
+ }
+
+ return 0;
+}
+
+
+static void *do_monitor(void *data)
+{
+ int res;
+ int reloading;
+ struct ooh323_pvt *h323 = NULL;
+ time_t t;
+
+ for (;;) {
+ struct ooh323_pvt *h323_next;
+ /* Check for a reload request */
+ ast_mutex_lock(&h323_reload_lock);
+ reloading = h323_reloading;
+ h323_reloading = 0;
+ ast_mutex_unlock(&h323_reload_lock);
+ if (reloading) {
+ ast_verb(1, "Reloading H.323\n");
+ ooh323_do_reload();
+ }
+ /* Check for interfaces needing to be killed */
+ ast_mutex_lock(&iflock);
+ time(&t);
+ h323 = iflist;
+ while (h323) {
+ h323_next = h323->next;
+
+ /* TODO: Need to add rtptimeout keepalive support */
+ if (ast_test_flag(h323, H323_NEEDDESTROY)) {
+ ooh323_destroy (h323);
+ }
+ h323 = h323_next;
+ }
+ ast_mutex_unlock(&iflock);
+ pthread_testcancel();
+ /* Wait for sched or io */
+ res = ast_sched_wait(sched);
+ if ((res < 0) || (res > 1000)) {
+ res = 1000;
+ }
+ res = ast_io_wait(io, res);
+ pthread_testcancel();
+ ast_mutex_lock(&monlock);
+ if (res >= 0) {
+ ast_sched_runq(sched);
+ }
+ ast_mutex_unlock(&monlock);
+ }
+ /* Never reached */
+ return NULL;
+}
+
+int restart_monitor(void)
+{
+ pthread_attr_t attr;
+
+ /* If we're supposed to be stopped -- stay stopped */
+ if (monitor_thread == AST_PTHREADT_STOP)
+ return 0;
+ if (ast_mutex_lock(&monlock)) {
+ ast_log(LOG_WARNING, "Unable to lock monitor\n");
+ return -1;
+ }
+ if (monitor_thread == pthread_self()) {
+ ast_mutex_unlock(&monlock);
+ ast_log(LOG_WARNING, "Cannot kill myself\n");
+ return -1;
+ }
+ if (monitor_thread != AST_PTHREADT_NULL) {
+ /* Wake up the thread */
+ pthread_kill(monitor_thread, SIGURG);
+ } else {
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ /* Start a new monitor */
+ if (ast_pthread_create(&monitor_thread, &attr, do_monitor, NULL) < 0) {
+ ast_mutex_unlock(&monlock);
+ ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
+ return -1;
+ }
+ }
+ ast_mutex_unlock(&monlock);
+ return 0;
+}
+
+
+
+int ooh323_destroy(struct ooh323_pvt *p)
+{
+ /* NOTE: Assumes iflock already acquired */
+ struct ooh323_pvt *prev = NULL, *cur = NULL;
+
+
+ if (gH323Debug) {
+ ast_verbose("--- ooh323_destroy \n");
+
+ if (p)
+ ast_verbose(" Destroying %s\n", p->username);
+ }
+
+ cur = iflist;
+ while (cur) {
+ if (cur == p) { break; }
+ prev = cur;
+ cur = cur->next;
+ }
+
+ if (cur) {
+ ast_mutex_lock(&cur->lock);
+ if (prev)
+ prev->next = cur->next;
+ else
+ iflist = cur->next;
+
+ if (cur->callToken) {
+ free(cur->callToken);
+ cur->callToken = 0;
+ }
+
+ if (cur->username) {
+ free(cur->username);
+ cur->username = 0;
+ }
+
+ if (cur->host) {
+ free(cur->host);
+ cur->host = 0;
+ }
+
+ if (cur->callerid_name) {
+ free(cur->callerid_name);
+ cur->callerid_name = 0;
+ }
+
+ if (cur->callerid_num) {
+ free(cur->callerid_num);
+ cur->callerid_num = 0;
+ }
+
+
+ if (cur->rtp) {
+ ast_rtp_destroy(cur->rtp);
+ cur->rtp = 0;
+ }
+
+ /* Unlink us from the owner if we have one */
+ if (cur->owner) {
+ ast_channel_lock(cur->owner);
+ ast_debug(1, "Detaching from %s\n", cur->owner->name);
+ cur->owner->tech_pvt = NULL;
+ ast_channel_unlock(cur->owner);
+ cur->owner = NULL;
+ }
+
+ if (cur->vad) {
+ ast_dsp_free(cur->vad);
+ cur->vad = NULL;
+ }
+ ast_mutex_unlock(&cur->lock);
+ ast_mutex_destroy(&cur->lock);
+
+ free(cur);
+ }
+
+ if (gH323Debug)
+ ast_verbose("+++ ooh323_destroy\n");
+
+ return 0;
+}
+
+int delete_peers()
+{
+ struct ooh323_peer *cur = NULL, *prev = NULL;
+ ast_mutex_lock(&peerl.lock);
+ cur = peerl.peers;
+ while (cur) {
+ prev = cur;
+ cur = cur->next;
+
+ ast_mutex_destroy(&prev->lock);
+ if (prev->h323id)
+ free(prev->h323id);
+ if (prev->email)
+ free(prev->email);
+ if (prev->url)
+ free(prev->url);
+ if (prev->e164)
+ free(prev->e164);
+ free(prev);
+
+ if (cur == peerl.peers) {
+ break;
+ }
+ }
+ peerl.peers = NULL;
+ ast_mutex_unlock(&peerl.lock);
+ return 0;
+}
+
+int delete_users()
+{
+ struct ooh323_user *cur = NULL, *prev = NULL;
+ ast_mutex_lock(&userl.lock);
+ cur = userl.users;
+ while (cur) {
+ prev = cur;
+ cur = cur->next;
+ ast_mutex_destroy(&prev->lock);
+ free(prev);
+ if (cur == userl.users) {
+ break;
+ }
+ }
+ userl.users = NULL;
+ ast_mutex_unlock(&userl.lock);
+ return 0;
+}
+
+static int unload_module(void)
+{
+ struct ooh323_pvt *p;
+ struct ooAliases *cur = NULL, *prev = NULL;
+
+ if (gH323Debug) {
+ ast_verbose("--- ooh323 unload_module \n");
+ }
+ /* First, take us out of the channel loop */
+ ast_cli_unregister_multiple(cli_ooh323, sizeof(cli_ooh323) / sizeof(struct ast_cli_entry));
+ ast_rtp_proto_unregister(&ooh323_rtp);
+ ast_channel_unregister(&ooh323_tech);
+
+#if 0
+ ast_unregister_atexit(&ast_ooh323c_exit);
+#endif
+
+ if (gH323Debug) {
+ ast_verbose(" unload_module - hanging up all interfaces\n");
+ }
+ if (!ast_mutex_lock(&iflock)) {
+ /* Hangup all interfaces if they have an owner */
+ p = iflist;
+ while (p) {
+ if (p->owner) {
+ ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
+ }
+ p = p->next;
+ }
+ iflist = NULL;
+ ast_mutex_unlock(&iflock);
+ } else {
+ ast_log(LOG_WARNING, "Unable to lock the interface list\n");
+ return -1;
+ }
+
+
+ if (gH323Debug) {
+ ast_verbose(" unload_module - stopping monitor thread\n");
+ }
+ if (monitor_thread != AST_PTHREADT_NULL) {
+ if (!ast_mutex_lock(&monlock)) {
+ if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP)) {
+ pthread_cancel(monitor_thread);
+ pthread_kill(monitor_thread, SIGURG);
+ pthread_join(monitor_thread, NULL);
+ }
+ monitor_thread = AST_PTHREADT_STOP;
+ ast_mutex_unlock(&monlock);
+ } else {
+ ast_log(LOG_WARNING, "Unable to lock the monitor\n");
+ return -1;
+ }
+ }
+
+
+ if (gH323Debug) {
+ ast_verbose(" unload_module - stopping stack thread\n");
+ }
+ ooh323c_stop_stack_thread();
+
+
+ if (gH323Debug) {
+ ast_verbose(" unload_module - freeing up memory used by interfaces\n");
+ }
+ if (!ast_mutex_lock(&iflock)) {
+ struct ooh323_pvt *pl;
+
+ /* Destroy all the interfaces and free their memory */
+ p = iflist;
+ while (p) {
+ pl = p;
+ p = p->next;
+ /* Free associated memory */
+ ooh323_destroy(pl);
+ }
+ iflist = NULL;
+ ast_mutex_unlock(&iflock);
+ } else {
+ ast_log(LOG_WARNING, "Unable to lock the interface list\n");
+ return -1;
+ }
+
+
+ if (gH323Debug) {
+ ast_verbose(" unload_module - deleting users\n");
+ }
+ delete_users();
+
+
+ if (gH323Debug) {
+ ast_verbose(" unload_module - deleting peers\n");
+ }
+ delete_peers();
+
+
+ if (gH323Debug) {
+ ast_verbose(" unload_module - Freeing up alias list\n");
+ }
+ cur = gAliasList;
+ while (cur) {
+ prev = cur;
+ cur = cur->next;
+ free(prev->value);
+ free(prev);
+ }
+ gAliasList = NULL;
+
+
+ if (gH323Debug) {
+ ast_verbose(" unload_module- destroying OOH323 endpoint \n");
+ }
+ ooH323EpDestroy();
+
+ if (gH323Debug) {
+ ast_verbose("+++ ooh323 unload_module \n");
+ }
+
+ return 0;
+}
+
+
+
+static enum ast_rtp_get_result ooh323_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
+{
+ struct ooh323_pvt *p = NULL;
+ enum ast_rtp_get_result res = AST_RTP_TRY_PARTIAL;
+
+ if (!(p = (struct ooh323_pvt *) chan->tech_pvt))
+ return AST_RTP_GET_FAILED;
+
+ *rtp = p->rtp;
+
+ if (!(p->rtp)) {
+ return AST_RTP_GET_FAILED;
+ }
+ res = AST_RTP_TRY_NATIVE;
+
+ return res;
+}
+
+static enum ast_rtp_get_result ooh323_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
+{
+ struct ooh323_pvt *p = NULL;
+ enum ast_rtp_get_result res = AST_RTP_TRY_PARTIAL;
+
+ if (!(p = (struct ooh323_pvt *) chan->tech_pvt))
+ return AST_RTP_GET_FAILED;
+
+ *rtp = p->vrtp;
+
+ if (!(p->rtp)) {
+ return AST_RTP_GET_FAILED;
+ }
+ res = AST_RTP_TRY_NATIVE;
+
+ return res;
+}
+
+
+int ooh323_update_capPrefsOrderForCall
+ (ooCallData *call, struct ast_codec_pref *prefs)
+{
+ int i = 0;
+ int codec = ast_codec_pref_index(prefs, i);
+
+ ooResetCapPrefs(call);
+ while (codec) {
+ ooAppendCapToCapPrefs(call, ooh323_convertAsteriskCapToH323Cap(codec));
+ codec = ast_codec_pref_index(prefs, ++i);
+ }
+
+ return 0;
+}
+
+
+int ooh323_convertAsteriskCapToH323Cap(int cap)
+{
+ char formats[512];
+ switch (cap) {
+ case AST_FORMAT_ULAW:
+ return OO_G711ULAW64K;
+ case AST_FORMAT_ALAW:
+ return OO_G711ALAW64K;
+ case AST_FORMAT_GSM:
+ return OO_GSMFULLRATE;
+ case AST_FORMAT_G729A:
+ return OO_G729A;
+ case AST_FORMAT_G723_1:
+ return OO_G7231;
+ case AST_FORMAT_H263:
+ return OO_H263VIDEO;
+ default:
+ ast_log(LOG_NOTICE, "Don't know how to deal with mode %s\n",
+ ast_getformatname_multiple(formats, sizeof(formats), cap));
+ return -1;
+ }
+}
+
+static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp,
+ struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active)
+{
+ /* XXX Deal with Video */
+ struct ooh323_pvt *p;
+ struct sockaddr_in them;
+ struct sockaddr_in us;
+ int mode;
+
+ if (gH323Debug)
+ ast_verbose("--- ooh323_set_peer - %s\n", chan->name);
+
+ if (!rtp) {
+ return 0;
+ }
+
+ mode = ooh323_convertAsteriskCapToH323Cap(chan->writeformat);
+ p = (struct ooh323_pvt *) chan->tech_pvt;
+ if (!p) {
+ ast_log(LOG_ERROR, "No Private Structure, this is bad\n");
+ return -1;
+ }
+ ast_rtp_get_peer(rtp, &them);
+ ast_rtp_get_us(rtp, &us);
+ return 0;
+}
+
+
+
+
+int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call)
+{
+ struct sockaddr_in us;
+ ooMediaInfo mediaInfo;
+ int x, format = 0;
+
+ if (gH323Debug)
+ ast_verbose("--- configure_local_rtp\n");
+
+ if (p->rtp) {
+ ast_rtp_codec_setpref(p->rtp, &p->prefs);
+ }
+
+ /* figure out our local RTP port and tell the H.323 stack about it*/
+ ast_rtp_get_us(p->rtp, &us);
+
+ ast_copy_string(mediaInfo.lMediaIP, ast_inet_ntoa(us.sin_addr), sizeof(mediaInfo.lMediaIP));
+ mediaInfo.lMediaPort = ntohs(us.sin_port);
+ mediaInfo.lMediaCntrlPort = mediaInfo.lMediaPort +1;
+ for (x = 0; 0 != (format = ast_codec_pref_index(&p->prefs, x)); x++) {
+ strcpy(mediaInfo.dir, "transmit");
+ mediaInfo.cap = ooh323_convertAsteriskCapToH323Cap(format);
+ ooAddMediaInfo(call, mediaInfo);
+ strcpy(mediaInfo.dir, "receive");
+ ooAddMediaInfo(call, mediaInfo);
+ if (mediaInfo.cap == OO_G729A) {
+ strcpy(mediaInfo.dir, "transmit");
+ mediaInfo.cap = OO_G729;
+ ooAddMediaInfo(call, mediaInfo);
+ strcpy(mediaInfo.dir, "receive");
+ ooAddMediaInfo(call, mediaInfo);
+ }
+ }
+
+ if (gH323Debug)
+ ast_verbose("+++ configure_local_rtp\n");
+
+ return 1;
+}
+
+void setup_rtp_connection(ooCallData *call, const char *remoteIp,
+ int remotePort)
+{
+ struct ooh323_pvt *p = NULL;
+ struct sockaddr_in them;
+
+ if (gH323Debug)
+ ast_verbose("--- setup_rtp_connection\n");
+
+ /* Find the call or allocate a private structure if call not found */
+ p = find_call(call);
+
+ if (!p) {
+ ast_log(LOG_ERROR, "Something is wrong: rtp\n");
+ return;
+ }
+
+ them.sin_family = AF_INET;
+ them.sin_addr.s_addr = inet_addr(remoteIp); /* only works for IPv4 */
+ them.sin_port = htons(remotePort);
+ ast_rtp_set_peer(p->rtp, &them);
+
+ if (gH323Debug) {
+ ast_verbose("+++ setup_rtp_connection\n");
+ }
+
+ return;
+}
+
+void close_rtp_connection(ooCallData *call)
+{
+ struct ooh323_pvt *p = NULL;
+
+ if (gH323Debug) {
+ ast_verbose("--- close_rtp_connection\n");
+ }
+
+ p = find_call(call);
+ if (!p) {
+ ast_log(LOG_ERROR, "Couldn't find matching call to close rtp connection\n");
+ return;
+ }
+ ast_mutex_lock(&p->lock);
+ if (p->rtp) {
+ ast_rtp_stop(p->rtp);
+ }
+ ast_mutex_unlock(&p->lock);
+
+ if (gH323Debug) {
+ ast_verbose("+++ close_rtp_connection\n");
+ }
+
+ return;
+}
+
+
+int update_our_aliases(ooCallData *call, struct ooh323_pvt *p)
+{
+ int updated = -1;
+ ooAliases *psAlias = NULL;
+
+ if (!call->ourAliases)
+ return updated;
+ for (psAlias = call->ourAliases; psAlias; psAlias = psAlias->next) {
+ if (psAlias->type == T_H225AliasAddress_h323_ID) {
+ ast_copy_string(p->callee_h323id, psAlias->value, sizeof(p->callee_h323id));
+ updated = 1;
+ }
+ if (psAlias->type == T_H225AliasAddress_dialedDigits) {
+ ast_copy_string(p->callee_dialedDigits, psAlias->value, sizeof(p->callee_dialedDigits));
+ updated = 1;
+ }
+ if (psAlias->type == T_H225AliasAddress_url_ID) {
+ ast_copy_string(p->callee_url, psAlias->value, sizeof(p->callee_url));
+ updated = 1;
+ }
+ if (psAlias->type == T_H225AliasAddress_email_ID) {
+ ast_copy_string(p->callee_email, psAlias->value, sizeof(p->callee_email));
+ updated = 1;
+ }
+ }
+ return updated;
+}
+
+struct ast_frame *ooh323_rtp_read(struct ast_channel *ast, struct ooh323_pvt *p)
+{
+ /* Retrieve audio/etc from channel. Assumes p->lock is already held. */
+ struct ast_frame *f;
+ static struct ast_frame null_frame = { AST_FRAME_NULL, };
+ switch (ast->fdno) {
+ case 0:
+ f = ast_rtp_read(p->rtp); /* RTP Audio */
+ break;
+ case 1:
+ f = ast_rtcp_read(p->rtp); /* RTCP Control Channel */
+ break;
+ case 2:
+ f = ast_rtp_read(p->vrtp); /* RTP Video */
+ break;
+ case 3:
+ f = ast_rtcp_read(p->vrtp); /* RTCP Control Channel for video */
+ break;
+ default:
+ f = &null_frame;
+ }
+ /* Don't send RFC2833 if we're not supposed to */
+ if (f && (f->frametype == AST_FRAME_DTMF) && !(p->dtmfmode & H323_DTMF_RFC2833)) {
+ return &null_frame;
+ }
+ if (p->owner) {
+ /* We already hold the channel lock */
+ if (f->frametype == AST_FRAME_VOICE) {
+ if (f->subclass != p->owner->nativeformats) {
+ ast_debug(1, "Oooh, format changed to %d\n", f->subclass);
+ p->owner->nativeformats = f->subclass;
+ ast_set_read_format(p->owner, p->owner->readformat);
+ ast_set_write_format(p->owner, p->owner->writeformat);
+ }
+ if ((p->dtmfmode & H323_DTMF_INBAND) && p->vad) {
+ f = ast_dsp_process(p->owner, p->vad, f);
+ if (f && (f->frametype == AST_FRAME_DTMF)) {
+ ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass);
+ }
+ }
+ }
+ }
+ return f;
+}
+
+
+int ooh323_convert_hangupcause_asteriskToH323(int cause)
+{
+ switch (cause) {
+ case AST_CAUSE_CALL_REJECTED:
+ return OO_REASON_REMOTE_REJECTED;
+ case AST_CAUSE_UNALLOCATED:
+ return OO_REASON_NOUSER;
+ case AST_CAUSE_BUSY:
+ return OO_REASON_REMOTE_BUSY;
+ case AST_CAUSE_BEARERCAPABILITY_NOTAVAIL:
+ return OO_REASON_NOCOMMON_CAPABILITIES;
+ case AST_CAUSE_CONGESTION:
+ return OO_REASON_REMOTE_BUSY;
+ case AST_CAUSE_NO_ANSWER:
+ return OO_REASON_REMOTE_NOANSWER;
+ case AST_CAUSE_NORMAL:
+ return OO_REASON_REMOTE_CLEARED;
+ case AST_CAUSE_FAILURE:
+ default:
+ return OO_REASON_UNKNOWN;
+ }
+
+ return 0;
+}
+
+int ooh323_convert_hangupcause_h323ToAsterisk(int cause)
+{
+ switch (cause) {
+ case OO_REASON_REMOTE_REJECTED:
+ return AST_CAUSE_CALL_REJECTED;
+ case OO_REASON_NOUSER:
+ return AST_CAUSE_UNALLOCATED;
+ case OO_REASON_REMOTE_BUSY:
+ case OO_REASON_LOCAL_BUSY:
+ return AST_CAUSE_BUSY;
+ case OO_REASON_NOCOMMON_CAPABILITIES: /* No codecs approved */
+ return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
+ case OO_REASON_REMOTE_CONGESTED:
+ case OO_REASON_LOCAL_CONGESTED:
+ return AST_CAUSE_CONGESTION;
+ case OO_REASON_REMOTE_NOANSWER:
+ return AST_CAUSE_NO_ANSWER;
+ case OO_REASON_UNKNOWN:
+ case OO_REASON_INVALIDMESSAGE:
+ case OO_REASON_TRANSPORTFAILURE:
+ return AST_CAUSE_FAILURE;
+ case OO_REASON_REMOTE_CLEARED:
+ return AST_CAUSE_NORMAL;
+ default:
+ return AST_CAUSE_NORMAL;
+ }
+ /* Never reached */
+ return 0;
+}
+
+#if 0
+void ast_ooh323c_exit()
+{
+ ooGkClientDestroy();
+}
+#endif
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Objective Systems H323 Channel");