diff options
author | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2009-06-30 16:40:38 +0000 |
---|---|---|
committer | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2009-06-30 16:40:38 +0000 |
commit | e9d15cbea7a98184521c851500176da7aa424012 (patch) | |
tree | d3d6aa7ea86d11ecaa6e88efbc46a5dde1c63ea5 /addons/chan_ooh323.c | |
parent | b85bdd32a783a8f07004d41db8a696645685a331 (diff) |
Move Asterisk-addons modules into the main Asterisk source tree.
Someone asked yesterday, "is there a good reason why we can't just put these
modules in Asterisk?". After a brief discussion, as long as the modules are
clearly set aside in their own directory and not enabled by default, it is
perfectly fine.
For more information about why a module goes in addons, see README-addons.txt.
chan_ooh323 does not currently compile as it is behind some trunk API updates.
However, it will not build by default, so it should be okay for now.
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@204413 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'addons/chan_ooh323.c')
-rw-r--r-- | addons/chan_ooh323.c | 3162 |
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"); |