diff options
Diffstat (limited to 'addons/chan_ooh323.c')
-rw-r--r-- | addons/chan_ooh323.c | 2112 |
1 files changed, 1585 insertions, 527 deletions
diff --git a/addons/chan_ooh323.c b/addons/chan_ooh323.c index 4aa26c92e..697758beb 100644 --- a/addons/chan_ooh323.c +++ b/addons/chan_ooh323.c @@ -16,10 +16,9 @@ #include "chan_ooh323.h" +#include <math.h> -/*** MODULEINFO - <defaultenabled>no</defaultenabled> - ***/ +#define FORMAT_STRING_SIZE 512 /* Defaults */ #define DEFAULT_CONTEXT "default" @@ -36,17 +35,33 @@ #define H323_ALREADYGONE (1<<5) #define H323_NEEDDESTROY (1<<6) #define H323_DISABLEGK (1<<7) +#define H323_NEEDSTART (1<<8) + +#define MAXT30 240 +#define T38TOAUDIOTIMEOUT 30 +#define T38_DISABLED 0 +#define T38_ENABLED 1 +#define T38_FAXGW 1 /* Channel description */ static const char type[] = "OOH323"; static const char tdesc[] = "Objective Systems H323 Channel Driver"; -static const char config[] = "chan_ooh323.conf"; -static const char config_old[] = "ooh323.conf"; +static const char config[] = "ooh323.conf"; + +struct ast_module *myself; +static struct ast_jb_conf default_jbconf = +{ + .flags = 0, + .max_size = -1, + .resync_threshold = -1, + .impl = "" +}; +static struct ast_jb_conf global_jbconf; /* Channel Definition */ static struct ast_channel *ooh323_request(const char *type, int format, - void *data, int *cause); + const struct ast_channel *requestor, 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); @@ -55,18 +70,21 @@ 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_queryoption(struct ast_channel *ast, int option, void *data, int *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 enum ast_rtp_glue_result ooh323_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **rtp); +static enum ast_rtp_glue_result ooh323_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp_instance **rtp); +static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, + struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, int codecs, int nat_active); + +static struct ast_udptl *ooh323_get_udptl_peer(struct ast_channel *chan); +static int ooh323_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl); static void print_codec_to_cli(int fd, struct ast_codec_pref *pref); -#if 0 -static void ast_ooh323c_exit(); -#endif +struct ooh323_peer *find_friend(const char *name, int port); + static const struct ast_channel_tech ooh323_tech = { .type = type, @@ -84,22 +102,50 @@ static const struct ast_channel_tech ooh323_tech = { .indicate = ooh323_indicate, .fixup = ooh323_fixup, .send_html = 0, - .bridge = ast_rtp_bridge, + .queryoption = ooh323_queryoption, + .bridge = ast_rtp_instance_bridge, /* XXX chan unlocked ? */ + .early_bridge = ast_rtp_instance_early_bridge, + }; -static struct ast_rtp_protocol ooh323_rtp = { +static struct ast_rtp_glue 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 + .update_peer = ooh323_set_rtp_peer, +}; + +static struct ast_udptl_protocol ooh323_udptl = { + type: "H323", + get_udptl_info: ooh323_get_udptl_peer, + set_udptl_peer: ooh323_set_udptl_peer, }; + + +struct ooh323_user; + /* 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_rtp_instance *rtp; + struct ast_rtp_instance *vrtp; /* Placeholder for now */ + + int t38support; /* T.38 mode - disable, transparent, faxgw */ + int rtptimeout; + struct ast_udptl *udptl; + int faxmode; + int t38_tx_enable; + int t38_init; + struct sockaddr_in udptlredirip; + time_t lastTxT38; + int chmodepend; + struct ast_channel *owner; /* Master Channel */ + union { + char *user; /* cooperating user/peer */ + char *peer; + } neighbor; time_t lastrtptx; time_t lastrtprx; unsigned int flags; @@ -124,12 +170,16 @@ static struct ooh323_pvt { int capability; struct ast_codec_pref prefs; int dtmfmode; + int dtmfcodec; 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; + int progsent; /* progress is sent */ struct ast_dsp *vad; + struct OOH323Regex *rtpmask; /* rtp ip regexp */ + char rtpmaskstr[120]; struct ooh323_pvt *next; /* Next entity */ } *iflist = NULL; @@ -148,9 +198,13 @@ struct ooh323_user{ int capability; struct ast_codec_pref prefs; int dtmfmode; + int dtmfcodec; + int t38support; int rtptimeout; int mUseIP; /* Use IP address or H323-ID to search user */ char mIP[20]; + struct OOH323Regex *rtpmask; + char rtpmaskstr[120]; struct ooh323_user *next; }; @@ -165,6 +219,8 @@ struct ooh323_peer{ char accountcode[20]; int amaflags; int dtmfmode; + int dtmfcodec; + int t38support; int mFriend; /* indicates defined as friend */ char ip[20]; int port; @@ -173,6 +229,8 @@ struct ooh323_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 OOH323Regex *rtpmask; + char rtpmaskstr[120]; struct ooh323_peer *next; }; @@ -198,35 +256,51 @@ AST_MUTEX_DEFINE_STATIC(usecnt_lock); AST_MUTEX_DEFINE_STATIC(ooh323c_cmd_lock); +static long callnumber = 0; +AST_MUTEX_DEFINE_STATIC(ooh323c_cn_lock); + /* stack callbacks */ int onAlerting(ooCallData *call); +int onProgress(ooCallData *call); int onNewCallCreated(ooCallData *call); +int onOutgoingCall(ooCallData *call); int onCallEstablished(ooCallData *call); int onCallCleared(ooCallData *call); +void onModeChanged(ooCallData *call, int t38mode); static char gLogFile[256] = DEFAULT_LOGFILE; static int gPort = 1720; static char gIP[20]; -static char gCallerID[AST_MAX_EXTENSION] = DEFAULT_H323ID; +static char gCallerID[AST_MAX_EXTENSION] = ""; static struct ooAliases *gAliasList; static int gCapability = AST_FORMAT_ULAW; static struct ast_codec_pref gPrefs; static int gDTMFMode = H323_DTMF_RFC2833; +static int gDTMFCodec = 101; +static int gT38Support = T38_FAXGW; static char gGatekeeper[100]; static enum RasGatekeeperMode gRasGkMode = RasNoGatekeeper; static int gIsGateway = 0; static int gFastStart = 1; static int gTunneling = 1; +static int gBeMaster = 0; 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; +static int gIncomingLimit = 1024; +static int gOutgoingLimit = 1024; OOBOOL gH323Debug = FALSE; +static int gTRCLVL = OOTRCLVLERR; + +static int t35countrycode = 0; +static int t35extensions = 0; +static int manufacturer = 0; +static char vendor[AST_MAX_EXTENSION] = ""; +static char version[AST_MAX_EXTENSION] = ""; static struct ooh323_config { @@ -249,45 +323,63 @@ static pthread_t monitor_thread = AST_PTHREADT_NULL; static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state, - const char *host) + const char *host, int capability, const char *linkedid) { struct ast_channel *ch = NULL; - int fmt; + int fmt = 0; if (gH323Debug) - ast_verbose("--- ooh323_new - %s\n", host); + ast_verbose("--- ooh323_new - %s, %d\n", host, capability); /* 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); + ch = ast_channel_alloc(1, state, i->callerid_num, i->callerid_name, + i->accountcode, i->exten, i->context, linkedid, i->amaflags, + "OOH323/%s-%ld", host, callnumber); + ast_mutex_lock(&ooh323c_cn_lock); + callnumber++; + ast_mutex_unlock(&ooh323c_cn_lock); + ast_mutex_lock(&i->lock); if (ch) { ast_channel_lock(ch); ch->tech = &ooh323_tech; - ch->nativeformats = i->capability; + if (capability) + fmt = ast_best_codec(capability); + if (!fmt) + fmt = ast_codec_pref_index(&i->prefs, 0); + + ch->nativeformats = ch->rawwriteformat = ch->rawreadformat = fmt; - fmt = ast_best_codec(ch->nativeformats); + ast_channel_set_fd(ch, 0, ast_rtp_instance_fd(i->rtp, 0)); + ast_channel_set_fd(ch, 1, ast_rtp_instance_fd(i->rtp, 1)); + ast_channel_set_fd(ch, 5, ast_udptl_fd(i->udptl)); - ch->fds[0] = ast_rtp_fd(i->rtp); - ch->fds[1] = ast_rtcp_fd(i->rtp); + ast_jb_configure(ch, &global_jbconf); 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; + ast_set_write_format(ch, fmt); + ast_set_read_format(ch, fmt); ch->tech_pvt = i; i->owner = ch; + ast_module_ref(myself); /* 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_dsp_set_features(i->vad, + DSP_FEATURE_DIGIT_DETECT | DSP_FEATURE_FAX_DETECT); + ast_dsp_set_faxmode(i->vad, + DSP_FAXMODE_DETECT_CNG | DSP_FAXMODE_DETECT_CED); + + if (i->dtmfmode & H323_DTMF_INBANDRELAX) + ast_dsp_set_digitmode(i->vad, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF); } ast_mutex_lock(&usecnt_lock); @@ -301,15 +393,8 @@ static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state, 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_test_flag(i, H323_OUTGOING)) { if (!ast_strlen_zero(i->caller_h323id)) { pbx_builtin_setvar_helper(ch, "_CALLER_H323ID", i->caller_h323id); @@ -336,19 +421,21 @@ static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state, ast_setstate(ch, state); if (state != AST_STATE_DOWN) { - if (ast_pbx_start(ch)) { + if (ast_pbx_start(ch)) { ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ch->name); - ast_channel_unlock(ch); + ast_channel_unlock(ch); ast_hangup(ch); ch = NULL; - } - } + } + } + + manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate", "Channel: %s\r\nChanneltype: %s\r\n" + "CallRef: %d\r\n", ch->name, "OOH323", i->call_reference); } else ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); - if (ch) - ast_channel_unlock(ch); + if(ch) ast_channel_unlock(ch); if (gH323Debug) ast_verbose("+++ h323_new\n"); @@ -361,6 +448,7 @@ static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state, static struct ooh323_pvt *ooh323_alloc(int callref, char *callToken) { struct ooh323_pvt *pvt = NULL; + struct sockaddr_in ouraddr; struct in_addr ipAddr; if (gH323Debug) ast_verbose("--- ooh323_alloc\n"); @@ -373,24 +461,40 @@ static struct ooh323_pvt *ooh323_alloc(int callref, char *callToken) 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); + ast_free(pvt); return NULL; } - if (!(pvt->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, ipAddr))) { + ouraddr.sin_addr = ipAddr; + if (!(pvt->rtp = ast_rtp_instance_new("asterisk", sched, &ouraddr, NULL))) { 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); + ast_free(pvt); return NULL; } - ast_rtp_setqos(pvt->rtp, gTOS, 0, "ooh323"); + ast_rtp_instance_set_qos(pvt->rtp, gTOS, 0, "ooh323-rtp"); + + if (!(pvt->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, ipAddr))) { + ast_log(LOG_WARNING, "Unable to create UDPTL session: %s\n", + strerror(errno)); + ast_mutex_unlock(&pvt->lock); + ast_mutex_destroy(&pvt->lock); + ast_free(pvt); + return NULL; + } + + ast_udptl_set_error_correction_scheme(pvt->udptl, UDPTL_ERROR_CORRECTION_NONE); + pvt->faxmode = 0; + pvt->t38support = gT38Support; + pvt->rtptimeout = gRTPTimeout; pvt->call_reference = callref; if (callToken) @@ -401,8 +505,10 @@ static struct ooh323_pvt *ooh323_alloc(int callref, char *callToken) OO_SETFLAG(pvt->flags, H323_DISABLEGK); pvt->dtmfmode = gDTMFMode; + pvt->dtmfcodec = gDTMFCodec; 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)); @@ -424,8 +530,9 @@ static struct ooh323_pvt *ooh323_alloc(int callref, char *callToken) /* Possible data values - peername, exten/peername, exten@ip */ -static struct ast_channel *ooh323_request(const char *type, int format, const struct ast_channel *requestor, - void *data, int *cause) +static struct ast_channel *ooh323_request(const char *type, int format, + const struct ast_channel *requestor, void *data, int *cause) + { struct ast_channel *chan = NULL; struct ooh323_pvt *p = NULL; @@ -433,13 +540,13 @@ static struct ast_channel *ooh323_request(const char *type, int format, const st char *dest = NULL; char *ext = NULL; char tmp[256]; - char formats[512]; + char formats[FORMAT_STRING_SIZE]; int oldformat; int port = 0; if (gH323Debug) ast_verbose("--- ooh323_request - data %s format %s\n", (char*)data, - ast_getformatname_multiple(formats,512,format)); + ast_getformatname_multiple(formats,FORMAT_STRING_SIZE,format)); oldformat = format; format &= AST_FORMAT_AUDIO_MASK; @@ -460,14 +567,16 @@ static struct ast_channel *ooh323_request(const char *type, int format, const st /* This is an outgoing call, since ooh323_request is called */ ast_set_flag(p, H323_OUTGOING); - ast_copy_string(tmp, data, sizeof(data)); + + ast_copy_string(tmp, data, sizeof(tmp)); dest = strchr(tmp, '/'); if (dest) { *dest = '\0'; dest++; - ext = tmp; + ext = dest; + dest = tmp; } else if ((dest = strchr(tmp, '@'))) { *dest = '\0'; dest++; @@ -497,22 +606,28 @@ static struct ast_channel *ooh323_request(const char *type, int format, const st 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); + /* 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; - } + p->capability = peer->capability; memcpy(&p->prefs, &peer->prefs, sizeof(struct ast_codec_pref)); - p->dtmfmode = peer->dtmfmode; + p->dtmfmode |= peer->dtmfmode; + p->dtmfcodec = peer->dtmfcodec; + p->t38support = peer->t38support; + p->rtptimeout = peer->rtptimeout; + if (peer->rtpmask && peer->rtpmaskstr[0]) { + p->rtpmask = peer->rtpmask; + ast_copy_string(p->rtpmaskstr, peer->rtpmaskstr, sizeof(p->rtpmaskstr)); + } ast_copy_string(p->accountcode, peer->accountcode, sizeof(p->accountcode)); p->amaflags = peer->amaflags; } else { p->dtmfmode = gDTMFMode; + p->dtmfcodec = gDTMFCodec; + p->t38support = gT38Support; + p->rtptimeout = gRTPTimeout; p->capability = gCapability; memcpy(&p->prefs, &gPrefs, sizeof(struct ast_codec_pref)); @@ -528,7 +643,8 @@ static struct ast_channel *ooh323_request(const char *type, int format, const st } - chan = ooh323_new(p, AST_STATE_DOWN, p->username); + chan = ooh323_new(p, AST_STATE_DOWN, p->username, format, + requestor ? requestor->linkedid : NULL); ast_mutex_unlock(&p->lock); @@ -536,6 +652,23 @@ static struct ast_channel *ooh323_request(const char *type, int format, const st ast_mutex_lock(&iflock); ooh323_destroy(p); ast_mutex_unlock(&iflock); + } else { + ast_mutex_lock(&p->lock); + p->callToken = (char*)ast_malloc(AST_MAX_EXTENSION); + if(!p->callToken) + { + ast_mutex_unlock(&p->lock); + ast_mutex_lock(&iflock); + ooh323_destroy(p); + ast_mutex_unlock(&iflock); + ast_log(LOG_ERROR, "Failed to allocate memory for callToken\n"); + return NULL; + } + + ast_mutex_unlock(&p->lock); + ast_mutex_lock(&ooh323c_cmd_lock); + ooMakeCall(data, p->callToken, AST_MAX_EXTENSION, NULL); + ast_mutex_unlock(&ooh323c_cmd_lock); } restart_monitor(); @@ -574,9 +707,10 @@ struct ooh323_user *find_user(const char * name, const char* ip) struct ooh323_user *user; if (gH323Debug) - ast_verbose("--- find_user\n"); + ast_verbose("--- find_user: %s, %s\n",name,ip); ast_mutex_lock(&userl.lock); + for (user = userl.users; user; user = user->next) { if (ip && user->mUseIP && !strcmp(user->mIP, ip)) { break; @@ -585,6 +719,7 @@ struct ooh323_user *find_user(const char * name, const char* ip) break; } } + ast_mutex_unlock(&userl.lock); if (gH323Debug) @@ -632,6 +767,7 @@ struct ooh323_peer *find_peer(const char * name, int port) if (gH323Debug) ast_verbose("--- find_peer \"%s\"\n", name); + ast_mutex_lock(&peerl.lock); for (peer = peerl.peers; peer; peer = peer->next) { if (gH323Debug) { @@ -675,16 +811,25 @@ static int ooh323_digit_begin(struct ast_channel *chan, char digit) return -1; } ast_mutex_lock(&p->lock); - if (p->rtp && (p->dtmfmode & H323_DTMF_RFC2833)) { - ast_rtp_senddigit_begin(p->rtp, digit); + + + if (digit == 'e' && !p->faxmode && p->t38support != T38_DISABLED) { + if (!p->chmodepend) { + if (gH323Debug) + ast_verbose("request to change %s to t.38 because fax cng\n", + p->callToken); + p->chmodepend = 1; + ooRequestChangeMode(p->callToken, 1); + } + + } else if (p->rtp && ((p->dtmfmode & H323_DTMF_RFC2833) || (p->dtmfmode & H323_DTMF_CISCO))) { + ast_rtp_instance_dtmf_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) @@ -705,8 +850,8 @@ static int ooh323_digit_end(struct ast_channel *chan, char digit, unsigned int d return -1; } ast_mutex_lock(&p->lock); - if (p->rtp && (p->dtmfmode & H323_DTMF_RFC2833)) - ast_rtp_senddigit_end(p->rtp, digit); + if (p->rtp && ((p->dtmfmode & H323_DTMF_RFC2833) || (p->dtmfmode & H323_DTMF_CISCO)) ) + ast_rtp_instance_dtmf_end(p->rtp, digit); ast_mutex_unlock(&p->lock); if (gH323Debug) @@ -720,43 +865,42 @@ 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; + int res=0, i; const char *val = NULL; ooCallOptions opts = { .fastStart = TRUE, .tunneling = TRUE, .disableGk = TRUE, - .callMode = OO_CALLMODE_AUDIOCALL + .callMode = OO_CALLMODE_AUDIOCALL, + .transfercap = 0 }; + if (gH323Debug) ast_verbose("--- ooh323_call- %s\n", dest); - if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) { + + 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->connected.id.number) { + if(p->callerid_num) free(p->callerid_num); + p->callerid_num = strdup(ast->connected.id.number); } - if (ast->cid.cid_name) { - if (p->callerid_name) { + if (ast->connected.id.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) { + p->callerid_name = strdup(ast->connected.id.name); + } else { + ast->connected.id.name = strdup(gCallerID); + if(p->callerid_name) free(p->callerid_name); - } - p->callerid_name = strdup(ast->cid.cid_name); + p->callerid_name = strdup(ast->connected.id.name); } /* Retrieve vars */ @@ -768,9 +912,8 @@ static int ooh323_call(struct ast_channel *ast, char *dest, int timeout) if ((val = pbx_builtin_getvar_helper(ast, "CALLER_H323DIALEDDIGITS"))) { ast_copy_string(p->caller_dialedDigits, val, sizeof(p->caller_dialedDigits)); - if (!p->callerid_num) { + if(!p->callerid_num) p->callerid_num = strdup(val); - } } if ((val = pbx_builtin_getvar_helper(ast, "CALLER_H323EMAIL"))) { @@ -781,13 +924,6 @@ static int ooh323_call(struct ast_channel *ast, char *dest, int timeout) 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) @@ -795,17 +931,22 @@ static int ooh323_call(struct ast_channel *ast, char *dest, int timeout) 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); + destination[sizeof(destination)-1]='\0'; + + opts.transfercap = ast->transfercapability; + + for (i=0;i<480 && !isRunning(p->callToken);i++) usleep(12000); + + if(OO_TESTFLAG(p->flags, H323_DISABLEGK)) { + res = ooRunCall(destination, p->callToken, AST_MAX_EXTENSION, &opts); + } else { + res = ooRunCall(destination, p->callToken, AST_MAX_EXTENSION, NULL); + } ast_mutex_unlock(&p->lock); if (res != OO_OK) { ast_log(LOG_ERROR, "Failed to make call\n"); - return -1; /* TODO: cleanup */ + return -1; /* ToDO: cleanup */ } if (gH323Debug) ast_verbose("+++ ooh323_call\n"); @@ -816,6 +957,7 @@ static int ooh323_call(struct ast_channel *ast, char *dest, int timeout) static int ooh323_hangup(struct ast_channel *ast) { struct ooh323_pvt *p = ast->tech_pvt; + int q931cause = AST_CAUSE_NORMAL_CLEARING; if (gH323Debug) ast_verbose("--- ooh323_hangup\n"); @@ -823,23 +965,42 @@ static int ooh323_hangup(struct ast_channel *ast) if (p) { ast_mutex_lock(&p->lock); + if (ast->hangupcause) { + q931cause = ast->hangupcause; + } else { + const char *cause = pbx_builtin_getvar_helper(ast, "DIALSTATUS"); + if (cause) { + if (!strcmp(cause, "CONGESTION")) { + q931cause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION; + } else if (!strcmp(cause, "BUSY")) { + q931cause = AST_CAUSE_USER_BUSY; + } else if (!strcmp(cause, "CHANISUNVAIL")) { + q931cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL; + } else if (!strcmp(cause, "NOANSWER")) { + q931cause = AST_CAUSE_NO_ANSWER; + } else if (!strcmp(cause, "CANCEL")) { + q931cause = AST_CAUSE_CALL_REJECTED; + } + } + } + + + if (gH323Debug) - ast_verbose(" hanging %s\n", p->username); + ast_verbose(" hanging %s with cause: %d\n", p->username, q931cause); 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); + ooHangCall(p->callToken, + ooh323_convert_hangupcause_asteriskToH323(q931cause), q931cause); ast_set_flag(p, H323_ALREADYGONE); /* ast_mutex_unlock(&p->lock); */ - } else { + } else ast_set_flag(p, H323_NEEDDESTROY); - } /* detach channel here */ if (p->owner) { p->owner->tech_pvt = NULL; p->owner = NULL; + ast_module_unref(myself); } ast_mutex_unlock(&p->lock); @@ -851,8 +1012,7 @@ static int ooh323_hangup(struct ast_channel *ast) ast_update_use_count(); } else { - ast_log(LOG_ERROR, "No call to hangup\n" ); - return -1; + ast_log(LOG_DEBUG, "No call to hangup\n" ); } if (gH323Debug) @@ -868,17 +1028,19 @@ static int ooh323_answer(struct ast_channel *ast) 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); + if (p) { + + ast_mutex_lock(&p->lock); + if (ast->_state != AST_STATE_UP) { + ast_channel_lock(ast); + ast_setstate(ast, AST_STATE_UP); + if (option_debug) + ast_debug(1, "ooh323_answer(%s)\n", ast->name); + ast_channel_unlock(ast); + ooAnswerCall(p->callToken); + } + ast_mutex_unlock(&p->lock); } - ast_mutex_unlock(&p->lock); if (gH323Debug) ast_verbose("+++ ooh323_answer\n"); @@ -892,6 +1054,8 @@ static struct ast_frame *ooh323_read(struct ast_channel *ast) static struct ast_frame null_frame = { AST_FRAME_NULL, }; struct ooh323_pvt *p = ast->tech_pvt; + if (!p) return &null_frame; + ast_mutex_lock(&p->lock); if (p->rtp) fr = ooh323_rtp_read(ast, p); @@ -907,26 +1071,59 @@ 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, + if (p) { + ast_mutex_lock(&p->lock); + + if (f->frametype == AST_FRAME_MODEM) { + ast_debug(1, "Send UDPTL %d/%d len %d for %s\n", + f->frametype, f->subclass, f->datalen, ast->name); + if (p->udptl) + res = ast_udptl_write(p->udptl, f); + ast_mutex_unlock(&p->lock); + return res; + } + + + if (f->frametype == AST_FRAME_VOICE) { +/* sending progress for first */ + if (!ast_test_flag(p, H323_OUTGOING) && !p->progsent && + p->callToken) { + ooManualProgress(p->callToken); + p->progsent = 1; + } + + + if (!(f->subclass & ast->nativeformats)) { + if (ast->nativeformats != 0) { + 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); + ast_set_write_format(ast, f->subclass); + } else { + /* ast_set_write_format(ast, f->subclass); + ast->nativeformats = f->subclass; */ + } + ast_mutex_unlock(&p->lock); return 0; - } - if (p) { - ast_mutex_lock(&p->lock); - if (p->rtp) - res = ast_rtp_write(p->rtp, f); + } + + if (p->rtp) + res = ast_rtp_instance_write(p->rtp, f); + + ast_mutex_unlock(&p->lock); + + } else if (f->frametype == AST_FRAME_IMAGE) { 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", + return 0; + } else { + ast_log(LOG_WARNING, "Can't send %d type frames with OOH323 write\n", f->frametype); - return 0; + ast_mutex_unlock(&p->lock); + return 0; + } + } return res; @@ -938,6 +1135,8 @@ static int ooh323_indicate(struct ast_channel *ast, int condition, const void *d struct ooh323_pvt *p = (struct ooh323_pvt *) ast->tech_pvt; char *callToken = (char *)NULL; + if (!p) return -1; + ast_mutex_lock(&p->lock); callToken = (p->callToken ? strdup(p->callToken) : NULL); ast_mutex_unlock(&p->lock); @@ -951,21 +1150,18 @@ static int ooh323_indicate(struct ast_channel *ast, int condition, const void *d if (gH323Debug) ast_verbose("----- ooh323_indicate %d on call %s\n", condition, callToken); - + ast_mutex_lock(&p->lock); 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); + ooHangCall(callToken, OO_REASON_LOCAL_CONGESTED, + AST_CAUSE_SWITCH_CONGESTION); 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); + ooHangCall(callToken, OO_REASON_LOCAL_BUSY, AST_CAUSE_USER_BUSY); ast_set_flag(p, H323_ALREADYGONE); } break; @@ -975,9 +1171,74 @@ static int ooh323_indicate(struct ast_channel *ast, int condition, const void *d case AST_CONTROL_UNHOLD: ast_moh_stop(ast); break; - case AST_CONTROL_PROCEEDING: - case AST_CONTROL_RINGING: case AST_CONTROL_PROGRESS: + if (ast->_state != AST_STATE_UP) { + if (!p->progsent) { + if (gH323Debug) + ast_log(LOG_DEBUG,"Sending manual progress for %s, res = %d\n", callToken, + ooManualProgress(callToken)); + else + ooManualProgress(callToken); + p->progsent = 1; + } + } + break; + case AST_CONTROL_RINGING: + if (ast->_state == AST_STATE_RING || ast->_state == AST_STATE_RINGING) { + if (gH323Debug) + ast_log(LOG_DEBUG,"Sending manual ringback for %s, res = %d\n", + callToken, + ooManualRingback(callToken)); + else + ooManualRingback(callToken); + } + break; + case AST_CONTROL_SRCUPDATE: + ast_rtp_instance_new_source(p->rtp); + break; + + case AST_CONTROL_T38_PARAMETERS: + if (p->t38support != T38_ENABLED) { + struct ast_control_t38_parameters parameters = { .request_response = 0 }; + parameters.request_response = AST_T38_REFUSED; + ast_queue_control_data(ast, AST_CONTROL_T38_PARAMETERS, + ¶meters, sizeof(parameters)); + break; + } + if (datalen != sizeof(struct ast_control_t38_parameters)) { + ast_log(LOG_ERROR, "Invalid datalen for AST_CONTROL_T38. " + "Expected %d, got %d\n", + (int)sizeof(enum ast_control_t38), (int)datalen); + } else { + const struct ast_control_t38_parameters *parameters = data; + enum ast_control_t38 message = parameters->request_response; + switch (message) { + + case AST_T38_REQUEST_NEGOTIATE: + + if (!p->chmodepend && !p->faxmode) { + ooRequestChangeMode(p->callToken, 1); + p->chmodepend = 1; + } + break; + + case AST_T38_REQUEST_TERMINATE: + + if (!p->chmodepend && p->faxmode) { + ooRequestChangeMode(p->callToken, 0); + p->chmodepend = 1; + } + break; + + + default: + ; + + } + + } + break; + case AST_CONTROL_PROCEEDING: case -1: break; default: @@ -985,13 +1246,76 @@ static int ooh323_indicate(struct ast_channel *ast, int condition, const void *d condition, callToken); } + ast_mutex_unlock(&p->lock); + if (gH323Debug) ast_verbose("++++ ooh323_indicate %d on %s\n", condition, callToken); - + free(callToken); return -1; } +static int ooh323_queryoption(struct ast_channel *ast, int option, void *data, int *datalen) +{ + + struct ooh323_pvt *p = (struct ooh323_pvt *) ast->tech_pvt; + int res = -1; + enum ast_t38_state state = T38_STATE_UNAVAILABLE; + char* cp; + + if (!p) return -1; + + ast_mutex_lock(&p->lock); + + if (gH323Debug) + ast_verbose("----- ooh323_queryoption %d on channel %s\n", option, ast->name); + + switch (option) { + + case AST_OPTION_T38_STATE: + + if (*datalen != sizeof(enum ast_t38_state)) { + ast_log(LOG_ERROR, "Invalid datalen for AST_OPTION_T38_STATE option." + " Expected %d, got %d\n", (int)sizeof(enum ast_t38_state), *datalen); + break; + } + if (p->t38support != T38_DISABLED) + state = T38_STATE_UNKNOWN; + if (p->faxmode) + state = (p->chmodepend) ? T38_STATE_UNKNOWN : T38_STATE_NEGOTIATED; + else if (p->chmodepend) + state = T38_STATE_NEGOTIATING; + + + *((enum ast_t38_state *) data) = state; + res = 0; + break; + + + case AST_OPTION_DIGIT_DETECT: + + cp = (char *) data; + *cp = p->vad ? 1 : 0; + ast_debug(1, "Reporting digit detection %sabled on %s\n", + *cp ? "en" : "dis", ast->name); + + res = 0; + break; + + default: ; + + } + + if (gH323Debug) + ast_verbose("+++++ ooh323_queryoption %d on channel %s\n", option, ast->name); + + ast_mutex_unlock(&p->lock); + + return res; +} + + + static int ooh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) { struct ooh323_pvt *p = newchan->tech_pvt; @@ -1021,15 +1345,14 @@ static int ooh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan } -void ooh323_set_write_format(ooCallData *call, int fmt) +void ooh323_set_write_format(ooCallData *call, int fmt, int txframes) { -#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 + char formats[FORMAT_STRING_SIZE]; + + if (gH323Debug) + ast_verbose("--- ooh323_update_writeformat %s/%d\n", + ast_getformatname_multiple(formats,FORMAT_STRING_SIZE, fmt), txframes); p = find_call(call); if (!p) { @@ -1040,34 +1363,56 @@ void ooh323_set_write_format(ooCallData *call, int fmt) 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"); + while (p->owner && ast_channel_trylock(p->owner)) { + ast_debug(1,"Failed to grab lock, trying again\n"); + DEADLOCK_AVOIDANCE(&p->lock); + } + if (!p->owner) { + ast_mutex_unlock(&p->lock); + ast_log(LOG_ERROR, "Channel has no owner\n"); + return; + } + if (gH323Debug) + ast_verbose("Writeformat before update %s/%s\n", + ast_getformatname_multiple(formats,FORMAT_STRING_SIZE, p->owner->writeformat), + ast_getformatname_multiple(formats,FORMAT_STRING_SIZE, p->owner->nativeformats)); + if (txframes) + ast_codec_pref_setsize(&p->prefs, fmt, txframes); + ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &p->prefs); + if (p->dtmfmode & H323_DTMF_RFC2833 && p->dtmfcodec) { + ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), + p->rtp, p->dtmfcodec, "audio", "telephone-event", 0); + } + if (p->dtmfmode & H323_DTMF_CISCO && p->dtmfcodec) { + ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), + p->rtp, p->dtmfcodec, "audio", "cisco-telephone-event", 0); + } + p->owner->nativeformats = fmt; + ast_set_write_format(p->owner, p->owner->writeformat); + ast_set_read_format(p->owner, p->owner->readformat); + ast_channel_unlock(p->owner); + } else + ast_log(LOG_ERROR, "No owner found\n"); -#ifdef print_debug - printf("+++ ooh323_update_writeformat\n"); -#endif -#endif -} + ast_mutex_unlock(&p->lock); + + if (gH323Debug) + ast_verbose("+++ ooh323_update_writeformat\n"); +} 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 + char formats[FORMAT_STRING_SIZE]; + if (gH323Debug) + ast_verbose("--- ooh323_update_readformat %s\n", + ast_getformatname_multiple(formats,FORMAT_STRING_SIZE, fmt)); + p = find_call(call); if (!p) { ast_log(LOG_ERROR, "No matching call found for %s\n", call->callToken); @@ -1075,16 +1420,37 @@ void ooh323_set_read_format(ooCallData *call, int fmt) } ast_mutex_lock(&p->lock); + p->readformat = fmt; + + + if (p->owner) { + while (p->owner && ast_channel_trylock(p->owner)) { + ast_debug(1,"Failed to grab lock, trying again\n"); + DEADLOCK_AVOIDANCE(&p->lock); + } + if (!p->owner) { + ast_mutex_unlock(&p->lock); + ast_log(LOG_ERROR, "Channel has no owner\n"); + return; + } + + if (gH323Debug) + ast_verbose("Readformat before update %s\n", + ast_getformatname_multiple(formats,FORMAT_STRING_SIZE, p->owner->readformat)); + p->owner->nativeformats = fmt; + ast_set_read_format(p->owner, p->owner->readformat); + ast_channel_unlock(p->owner); + } else + ast_log(LOG_ERROR, "No owner found\n"); + ast_mutex_unlock(&p->lock); - ast_set_read_format(p->owner, fmt); - -#ifdef print_debug - printf("+++ ooh323_update_readformat\n"); -#endif -#endif + + if (gH323Debug) + ast_verbose("+++ ooh323_update_readformat\n"); } + int onAlerting(ooCallData *call) { struct ooh323_pvt *p = NULL; @@ -1093,31 +1459,34 @@ int onAlerting(ooCallData *call) if (gH323Debug) ast_verbose("--- onAlerting %s\n", call->callToken); - if (!(p = find_call(call))) { + p = find_call(call); + + if(!p) { 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; - } + if (!p->owner) { 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_log(LOG_ERROR, "Channel has no owner\n"); + return 0; + } + while (p->owner && ast_channel_trylock(p->owner)) { + ast_debug(1,"Failed to grab lock, trying again\n"); + DEADLOCK_AVOIDANCE(&p->lock); + } + if (!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); + ast_log(LOG_ERROR, "Channel has no owner\n"); + return 0; } + c = p->owner; + if (c->_state != AST_STATE_UP) + ast_setstate(c, AST_STATE_RINGING); + + ast_queue_control(c, AST_CONTROL_RINGING); + ast_channel_unlock(c); + ast_mutex_unlock(&p->lock); if (gH323Debug) ast_verbose("+++ onAlerting %s\n", call->callToken); @@ -1125,6 +1494,49 @@ int onAlerting(ooCallData *call) return OO_OK; } +int onProgress(ooCallData *call) +{ + struct ooh323_pvt *p = NULL; + struct ast_channel *c = NULL; + + if (gH323Debug) + ast_verbose("--- onProgress %s\n", call->callToken); + + p = find_call(call); + + if(!p) { + ast_log(LOG_ERROR, "No matching call found\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 0; + } + while (p->owner && ast_channel_trylock(p->owner)) { + ast_debug(1,"Failed to grab lock, trying again\n"); + DEADLOCK_AVOIDANCE(&p->lock); + } + if (!p->owner) { + ast_mutex_unlock(&p->lock); + ast_log(LOG_ERROR, "Channel has no owner\n"); + return 0; + } + c = p->owner; + if (c->_state != AST_STATE_UP) + ast_setstate(c, AST_STATE_RINGING); + + ast_queue_control(c, AST_CONTROL_PROGRESS); + ast_channel_unlock(c); + ast_mutex_unlock(&p->lock); + + if (gH323Debug) + ast_verbose("+++ onProgress %s\n", call->callToken); + + return OO_OK; +} + /** * Callback for sending digits from H.323 up to asterisk * @@ -1155,8 +1567,19 @@ int ooh323_onReceivedDigit(OOH323CallData *call, const char *digit) f.data.ptr = NULL; f.mallocd = 0; f.src = "SEND_DIGIT"; - ast_mutex_unlock(&p->lock); + + while (p->owner && ast_channel_trylock(p->owner)) { + ast_debug(1,"Failed to grab lock, trying again\n"); + DEADLOCK_AVOIDANCE(&p->lock); + } + if (!p->owner) { + ast_mutex_unlock(&p->lock); + ast_log(LOG_ERROR, "Channel has no owner\n"); + return 0; + } res = ast_queue_frame(p->owner, &f); + ast_channel_unlock(p->owner); + ast_mutex_unlock(&p->lock); return res; } @@ -1164,6 +1587,7 @@ int ooh323_onReceivedSetup(ooCallData *call, Q931Message *pmsg) { struct ooh323_pvt *p = NULL; struct ooh323_user *user = NULL; + struct ast_channel *c = NULL; ooAliases *alias = NULL; char *at = NULL; char number [OO_MAX_NUMBER_LENGTH]; @@ -1195,30 +1619,35 @@ int ooh323_onReceivedSetup(ooCallData *call, Q931Message *pmsg) 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); } + 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) { + } + 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) { + } + 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 { + if(ooCallGetCalledPartyNumber(call, number, OO_MAX_NUMBER_LENGTH)== OO_OK) { + strncpy(p->exten, number, sizeof(p->exten)-1); + } 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_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)) { + } 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'; @@ -1228,34 +1657,58 @@ int ooh323_onReceivedSetup(ooCallData *call, Q931Message *pmsg) /* if no extension found, set to default 's' */ if (ast_strlen_zero(p->exten)) { - ast_copy_string(p->exten, "s", sizeof(p->exten)); + p->exten[0]='s'; + p->exten[1]='\0'; } - 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); + user = find_user(p->callerid_name, call->remoteIP); + if(user && (user->incominglimit == 0 || user->inUse < user->incominglimit)) { + ast_mutex_lock(&user->lock); + p->username = strdup(user->name); + p->neighbor.user = user->mUseIP ? ast_strdup(user->mIP) : + ast_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; + p->dtmfcodec = user->dtmfcodec; + p->t38support = user->t38support; + p->rtptimeout = user->rtptimeout; + if (user->rtpmask && user->rtpmaskstr[0]) { + p->rtpmask = user->rtpmask; + ast_copy_string(p->rtpmaskstr, user->rtpmaskstr, + sizeof(p->rtpmaskstr)); } + if (user->incominglimit) user->inUse++; + ast_mutex_unlock(&user->lock); + } else { + if (!OO_TESTFLAG(p->flags,H323_DISABLEGK)) { + p->username = strdup(call->remoteIP); + } else { + ast_mutex_unlock(&p->lock); + ast_log(LOG_ERROR, "Unacceptable ip %s\n", call->remoteIP); + if (!user) + ooHangCall(call->callToken, ooh323_convert_hangupcause_asteriskToH323(AST_CAUSE_CALL_REJECTED), AST_CAUSE_CALL_REJECTED); + else + ooHangCall(call->callToken, ooh323_convert_hangupcause_asteriskToH323(AST_CAUSE_NORMAL_CIRCUIT_CONGESTION), AST_CAUSE_NORMAL_CIRCUIT_CONGESTION); + ast_set_flag(p, H323_NEEDDESTROY); + return -1; + } } - - ooh323c_set_capability_for_call(call, &p->prefs, p->capability, p->dtmfmode); + ooh323c_set_capability_for_call(call, &p->prefs, p->capability, p->dtmfmode, p->dtmfcodec, + p->t38support); configure_local_rtp(p, call); +/* Incoming call */ + c = ooh323_new(p, AST_STATE_RING, p->username, 0, NULL); + if(!c) { + ast_mutex_unlock(&p->lock); + ast_log(LOG_ERROR, "Could not create ast_channel\n"); + return -1; + } ast_mutex_unlock(&p->lock); if (gH323Debug) @@ -1267,38 +1720,112 @@ int ooh323_onReceivedSetup(ooCallData *call, Q931Message *pmsg) +int onOutgoingCall(ooCallData *call) +{ + struct ooh323_pvt *p = NULL; + int i = 0; + + if (gH323Debug) + ast_verbose("--- onOutgoingCall %lx: %s\n", (long unsigned int) call, call->callToken); + + if (!strcmp(call->callType, "outgoing")) { + p = find_call(call); + if (!p) { + ast_log(LOG_ERROR, "Failed to find a matching call.\n"); + return -1; + } + ast_mutex_lock(&p->lock); + + if (!ast_strlen_zero(p->callerid_name)) { + ooCallSetCallerId(call, p->callerid_name); + } + if (!ast_strlen_zero(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 (!ast_strlen_zero(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 (p->rtpmask && p->rtpmaskstr[0]) { + call->rtpMask = p->rtpmask; + ast_mutex_lock(&call->rtpMask->lock); + call->rtpMask->inuse++; + ast_mutex_unlock(&call->rtpMask->lock); + ast_copy_string(call->rtpMaskStr, p->rtpmaskstr, sizeof(call->rtpMaskStr)); + } + + ast_mutex_unlock(&p->lock); + } + + if (gH323Debug) + ast_verbose("+++ onOutgoingCall %s\n", call->callToken); + return OO_OK; +} + + int onNewCallCreated(ooCallData *call) { struct ooh323_pvt *p = NULL; int i = 0; if (gH323Debug) - ast_verbose("--- onNewCallCreated %s\n", call->callToken); + ast_verbose("--- onNewCallCreated %lx: %s\n", (long unsigned int) call, call->callToken); + + ast_mutex_lock(&call->Lock); + if (ooh323c_start_call_thread(call)) { + ast_log(LOG_ERROR,"Failed to create call thread.\n"); + ast_mutex_unlock(&call->Lock); + return -1; + } if (!strcmp(call->callType, "outgoing")) { p = find_call(call); if (!p) { - ast_log(LOG_ERROR, "No matching call found for outgoing call\n"); + ast_log(LOG_ERROR, "Failed to find a matching call.\n"); + ast_mutex_unlock(&call->Lock); 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; - } + if(!isdigit(*(p->callerid_num+i))) { break; } i++; } - if (*(p->callerid_num + i) == '\0') { + if(*(p->callerid_num+i) == '\0') ooCallSetCallingPartyNumber(call, p->callerid_num); - } else { - if (!p->callerid_name) { + else { + if(!p->callerid_name) ooCallSetCallerId(call, p->callerid_num); - } } } @@ -1335,17 +1862,19 @@ int onNewCallCreated(ooCallData *call) 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); + p->username?p->username:"NULL", call->callToken, prefsBuf); } - ooh323c_set_capability_for_call(call, &p->prefs, p->capability, p->dtmfmode); + ooh323c_set_capability_for_call(call, &p->prefs, p->capability, + p->dtmfmode, p->dtmfcodec, p->t38support); configure_local_rtp(p, call); ast_mutex_unlock(&p->lock); } + + ast_mutex_unlock(&call->Lock); if (gH323Debug) ast_verbose("+++ onNewCallCreated %s\n", call->callToken); - return OO_OK; } @@ -1356,33 +1885,33 @@ int onCallEstablished(ooCallData *call) 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); + + if(ast_test_flag(p, H323_OUTGOING)) { 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 { + if (!p->owner) { + ast_mutex_unlock(&p->lock); + ast_log(LOG_ERROR, "Channel has no owner\n"); + return -1; + } + + while (p->owner && ast_channel_trylock(p->owner)) { + ast_debug(1,"Failed to grab lock, trying again\n"); + DEADLOCK_AVOIDANCE(&p->lock); + } + if (p->owner) { + struct ast_channel* c = p->owner; + ast_queue_control(c, AST_CONTROL_ANSWER); + ast_channel_unlock(p->owner); + manager_event(EVENT_FLAG_SYSTEM,"ChannelUpdate","Channel: %s\r\nChanneltype: %s\r\n" + "CallRef: %d\r\n", c->name, "OOH323", p->call_reference); + } ast_mutex_unlock(&p->lock); + } if (gH323Debug) @@ -1399,42 +1928,47 @@ int onCallCleared(ooCallData *call) if (gH323Debug) ast_verbose("--- onCallCleared %s \n", call->callToken); - p = find_call(call); - if (!p) { - return 0; - } + + if ((p = find_call(call))) { 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); + ast_log(LOG_DEBUG,"Failed to grab lock, trying again\n"); + DEADLOCK_AVOIDANCE(&p->lock); } else { - ownerLock = 1; - break; + 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->hangupcause = call->q931cause; 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_queue_hangup_with_cause(p->owner,call->q931cause); } + } + + if(p->owner) { + p->owner->tech_pvt = NULL; ast_channel_unlock(p->owner); + p->owner = NULL; + ast_module_unref(myself); } + ast_set_flag(p, H323_NEEDDESTROY); + + ooh323c_stop_call_thread(call); + ast_mutex_unlock(&p->lock); + ast_mutex_lock(&usecnt_lock); + usecnt--; + ast_mutex_unlock(&usecnt_lock); + + } if (gH323Debug) ast_verbose("+++ onCallCleared\n"); @@ -1442,8 +1976,7 @@ int onCallCleared(ooCallData *call) return OO_OK; } -#if 0 -static void ooh323_delete_user(struct ooh323_user *user) +/* static void ooh323_delete_user(struct ooh323_user *user) { struct ooh323_user *prev = NULL, *cur = NULL; @@ -1473,8 +2006,7 @@ static void ooh323_delete_user(struct ooh323_user *user) if (gH323Debug) ast_verbose("+++ ooh323_delete_user\n"); -} -#endif +} */ void ooh323_delete_peer(struct ooh323_peer *peer) { @@ -1484,36 +2016,33 @@ void ooh323_delete_peer(struct ooh323_peer *peer) ast_verbose("--- ooh323_delete_peer\n"); if (peer) { + cur = peerl.peers; ast_mutex_lock(&peerl.lock); - for (cur = peerl.peers; cur; prev = cur, cur = cur->next) { - if (cur == peer) { - break; - } + while(cur) { + if(cur==peer) break; + prev = cur; + cur = cur->next; } if (cur) { - if (prev) { + if(prev) prev->next = cur->next; - } else { + 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); + 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"); + } @@ -1525,14 +2054,17 @@ static struct ooh323_user *build_user(const char *name, struct ast_variable *v) if (gH323Debug) ast_verbose("--- build_user\n"); - user = ast_calloc(1, sizeof(*user)); + user = ast_calloc(1,sizeof(struct ooh323_user)); if (user) { + memset(user, 0, sizeof(struct ooh323_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; + user->dtmfcodec = gDTMFCodec; + user->t38support = gT38Support; /* set default context */ ast_copy_string(user->context, gContext, sizeof(user->context)); ast_copy_string(user->accountcode, gAccountcode, sizeof(user->accountcode)); @@ -1546,35 +2078,65 @@ static struct ooh323_user *build_user(const char *name, struct ast_variable *v) if (user->incominglimit < 0) user->incominglimit = 0; } else if (!strcasecmp(v->name, "accountcode")) { - ast_copy_string(user->accountcode, v->value, sizeof(user->accountcode)); + strncpy(user->accountcode, v->value, + sizeof(user->accountcode)-1); } else if (!strcasecmp(v->name, "rtptimeout")) { user->rtptimeout = atoi(v->value); if (user->rtptimeout < 0) user->rtptimeout = gRTPTimeout; + } else if (!strcasecmp(v->name, "rtpmask")) { + if ((user->rtpmask = malloc(sizeof(struct OOH323Regex))) && + (regcomp(&user->rtpmask->regex, v->value, REG_EXTENDED) + == 0)) { + ast_mutex_init(&user->rtpmask->lock); + user->rtpmask->inuse = 1; + ast_copy_string(user->rtpmaskstr, v->value, + sizeof(user->rtpmaskstr)); + } else user->rtpmask = NULL; } else if (!strcasecmp(v->name, "disallow")) { - ast_parse_allow_disallow(&user->prefs, &user->capability, - v->value, 0); + 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); + 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)); + strncpy(user->mIP, v->value, sizeof(user->mIP)-1); + user->mUseIP = 1; + } else if (!strcasecmp(v->name, "host")) { + strncpy(user->mIP, v->value, sizeof(user->mIP)-1); user->mUseIP = 1; - } else if (!strcasecmp(v->name, "dtmfmode")) { + } else if (!strcasecmp(v->name, "dtmfmode")) { if (!strcasecmp(v->value, "rfc2833")) user->dtmfmode = H323_DTMF_RFC2833; + if (!strcasecmp(v->value, "cisco")) + user->dtmfmode = H323_DTMF_CISCO; 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; + else if (!strcasecmp(v->value, "inband")) + user->dtmfmode = H323_DTMF_INBAND; + } else if (!strcasecmp(v->name, "relaxdtmf")) { + user->dtmfmode |= ast_true(v->value) ? H323_DTMF_INBANDRELAX : 0; + } else if (!strcasecmp(v->name, "dtmfcodec") && atoi(v->value)) { + user->dtmfcodec = atoi(v->value); + } else if (!strcasecmp(v->name, "t38support")) { + if (!strcasecmp(v->value, "disabled")) + user->t38support = T38_DISABLED; + if (!strcasecmp(v->value, "no")) + user->t38support = T38_DISABLED; + else if (!strcasecmp(v->value, "faxgw")) + user->t38support = T38_FAXGW; + else if (!strcasecmp(v->value, "yes")) + user->t38support = T38_ENABLED; } v = v->next; } @@ -1599,18 +2161,21 @@ static struct ooh323_peer *build_peer(const char *name, struct ast_variable *v, 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)); + memcpy(&peer->prefs, &gPrefs, sizeof(peer->prefs)); peer->rtptimeout = gRTPTimeout; ast_copy_string(peer->accountcode, gAccountcode, sizeof(peer->accountcode)); peer->amaflags = gAMAFLAGS; peer->dtmfmode = gDTMFMode; + peer->dtmfcodec = gDTMFCodec; + peer->t38support = gT38Support; + peer->port = 1720; if (0 == friend_type) { peer->mFriend = 1; } while (v) { if (!strcasecmp(v->name, "h323id")) { - if (!(peer->h323id = ast_strdup(v->value))) { + 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); @@ -1641,16 +2206,27 @@ static struct ooh323_peer *build_peer(const char *name, struct ast_variable *v, 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, "host")) { + 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 = atoi(v->value); + if (peer->outgoinglimit < 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 = atoi(v->value); + if(peer->rtptimeout < 0) peer->rtptimeout = gRTPTimeout; - } + } else if (!strcasecmp(v->name, "rtpmask")) { + if ((peer->rtpmask = malloc(sizeof(struct OOH323Regex))) && + (regcomp(&peer->rtpmask->regex, v->value, REG_EXTENDED) + == 0)) { + ast_mutex_init(&peer->rtpmask->lock); + peer->rtpmask->inuse = 1; + ast_copy_string(peer->rtpmaskstr, v->value, + sizeof(peer->rtpmaskstr)); + } else peer->rtpmask = NULL; } else if (!strcasecmp(v->name, "disallow")) { ast_parse_allow_disallow(&peer->prefs, &peer->capability, v->value, 0); @@ -1666,12 +2242,29 @@ static struct ooh323_peer *build_peer(const char *name, struct ast_variable *v, } else if (!strcasecmp(v->name, "dtmfmode")) { if (!strcasecmp(v->value, "rfc2833")) peer->dtmfmode = H323_DTMF_RFC2833; + if (!strcasecmp(v->value, "cisco")) + peer->dtmfmode = H323_DTMF_CISCO; 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; + else if (!strcasecmp(v->value, "inband")) + peer->dtmfmode = H323_DTMF_INBAND; + } else if (!strcasecmp(v->name, "relaxdtmf")) { + peer->dtmfmode |= ast_true(v->value) ? H323_DTMF_INBANDRELAX : 0; + } else if (!strcasecmp(v->name, "dtmfcodec") && atoi(v->value)) { + peer->dtmfcodec = atoi(v->value); + } else if (!strcasecmp(v->name, "t38support")) { + if (!strcasecmp(v->value, "disabled")) + peer->t38support = T38_DISABLED; + if (!strcasecmp(v->value, "no")) + peer->t38support = T38_DISABLED; + else if (!strcasecmp(v->value, "faxgw")) + peer->t38support = T38_FAXGW; + else if (!strcasecmp(v->value, "yes")) + peer->t38support = T38_ENABLED; } v = v->next; } @@ -1689,7 +2282,7 @@ static int ooh323_do_reload(void) ast_verbose("--- ooh323_do_reload\n"); } - reload_config(1); + reload_config(1); if (gH323Debug) { ast_verbose("+++ ooh323_do_reload\n"); @@ -1698,19 +2291,32 @@ static int ooh323_do_reload(void) return 0; } -#if 0 /*--- h323_reload: Force reload of module from cli ---*/ -static int ooh323_reload(int fd, int argc, char *argv[]) + +char *handle_cli_ooh323_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { + switch (cmd) { + case CLI_INIT: + e->command = "ooh323 reload"; + e->usage = + "Usage: ooh323 reload\n" + " Reload OOH323 config.\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + + if (a->argc != 2) + return CLI_SHOWUSAGE; + 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 { + } else { h323_reloading = 1; } ast_mutex_unlock(&h323_reload_lock); @@ -1721,19 +2327,11 @@ static int ooh323_reload(int fd, int argc, char *argv[]) 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 ooAliases *pNewAlias = NULL, *cur, *prev; struct ast_config *cfg; struct ast_variable *v; struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; @@ -1745,10 +2343,7 @@ int reload_config(int reload) if (gH323Debug) ast_verbose("--- reload_config\n"); - cfg = ast_config_load(config, config_flags); - if (!cfg) { - cfg = ast_config_load(config_old, config_flags); - } + cfg = ast_config_load((char*)config, config_flags); /* We *must* have a config file otherwise stop immediately */ if (!cfg) { @@ -1760,6 +2355,17 @@ int reload_config(int reload) if (reload) { delete_users(); delete_peers(); + if (gH323Debug) { + ast_verbose(" reload_config - Freeing up alias list\n"); + } + cur = gAliasList; + while (cur) { + prev = cur; + cur = cur->next; + free(prev->value); + free(prev); + } + gAliasList = NULL; } /* Inintialize everything to default */ @@ -1767,9 +2373,12 @@ int reload_config(int reload) gPort = 1720; gIP[0] = '\0'; strcpy(gCallerID, DEFAULT_H323ID); - gCapability = AST_FORMAT_ULAW; + gCapability = AST_FORMAT_ALAW; memset(&gPrefs, 0, sizeof(struct ast_codec_pref)); gDTMFMode = H323_DTMF_RFC2833; + gDTMFCodec = 101; + gT38Support = T38_FAXGW; + gTRCLVL = OOTRCLVLERR; gRasGkMode = RasNoGatekeeper; gGatekeeper[0] = '\0'; gRTPTimeout = 60; @@ -1782,9 +2391,15 @@ int reload_config(int reload) gMediaWaitForConnect = 0; ooconfig.mTCPPortStart = 12030; ooconfig.mTCPPortEnd = 12230; + memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf)); v = ast_variable_browse(cfg, "general"); while (v) { + + if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) { + v = v->next; + continue; + } if (!strcasecmp(v->name, "port")) { gPort = (int)strtol(v->value, NULL, 10); @@ -1792,7 +2407,7 @@ int reload_config(int reload) ast_copy_string(gIP, v->value, sizeof(gIP)); } else if (!strcasecmp(v->name, "h225portrange")) { char* endlimit = 0; - char temp[256]; + char temp[512]; ast_copy_string(temp, v->value, sizeof(temp)); endlimit = strchr(temp, ','); if (endlimit) { @@ -1801,16 +2416,12 @@ int reload_config(int reload) 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")) { + } else if (!strcasecmp(v->name, "faststart")) { gFastStart = ast_true(v->value); if (gFastStart) ooH323EpEnableFastStart(); @@ -1828,19 +2439,28 @@ int reload_config(int reload) ooH323EpEnableH245Tunneling(); else ooH323EpDisableH245Tunneling(); + } else if (!strcasecmp(v->name, "trybemaster")) { + gBeMaster = ast_true(v->value); + if (gBeMaster) + ooH323EpTryBeMaster(1); + else + ooH323EpTryBeMaster(0); } else if (!strcasecmp(v->name, "h323id")) { - pNewAlias = malloc(sizeof(*pNewAlias)); + pNewAlias = malloc(sizeof(struct ooAliases)); if (!pNewAlias) { ast_log(LOG_ERROR, "Failed to allocate memory for h323id alias\n"); return 1; } + if (gAliasList == NULL) { /* first h323id - set as callerid if callerid is not set */ + ast_copy_string(gCallerID, v->value, sizeof(gCallerID)); + } 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)); + pNewAlias = malloc(sizeof(struct ooAliases)); if (!pNewAlias) { ast_log(LOG_ERROR, "Failed to allocate memory for e164 alias\n"); return 1; @@ -1851,7 +2471,7 @@ int reload_config(int reload) gAliasList = pNewAlias; pNewAlias = NULL; } else if (!strcasecmp(v->name, "email")) { - pNewAlias = malloc(sizeof(*pNewAlias)); + pNewAlias = malloc(sizeof(struct ooAliases)); if (!pNewAlias) { ast_log(LOG_ERROR, "Failed to allocate memory for email alias\n"); return 1; @@ -1861,6 +2481,16 @@ int reload_config(int reload) pNewAlias->next = gAliasList; gAliasList = pNewAlias; pNewAlias = NULL; + } else if (!strcasecmp(v->name, "t35country")) { + t35countrycode = atoi(v->value); + } else if (!strcasecmp(v->name, "t35extensions")) { + t35extensions = atoi(v->value); + } else if (!strcasecmp(v->name, "manufacturer")) { + manufacturer = atoi(v->value); + } else if (!strcasecmp(v->name, "vendorid")) { + ast_copy_string(vendor, v->value, sizeof(vendor)); + } else if (!strcasecmp(v->name, "versionid")) { + ast_copy_string(version, v->value, sizeof(version)); } else if (!strcasecmp(v->name, "callerid")) { ast_copy_string(gCallerID, v->value, sizeof(gCallerID)); } else if (!strcasecmp(v->name, "incominglimit")) { @@ -1874,13 +2504,14 @@ int reload_config(int reload) gRasGkMode = RasDiscoverGatekeeper; } else { gRasGkMode = RasUseSpecificGatekeeper; - ast_copy_string(gGatekeeper, v->value, sizeof(gGatekeeper)); + strncpy(gGatekeeper, v->value, sizeof(gGatekeeper)-1); } } else if (!strcasecmp(v->name, "logfile")) { - ast_copy_string(gLogFile, v->value, sizeof(gLogFile)); + strncpy(gLogFile, v->value, sizeof(gLogFile)-1); } else if (!strcasecmp(v->name, "context")) { - ast_copy_string(gContext, v->value, sizeof(gContext)); - ast_verb(3, " == Setting default context to %s\n", gContext); + strncpy(gContext, v->value, sizeof(gContext)-1); + ast_verbose(VERBOSE_PREFIX_3 " == Setting default context to %s\n", + gContext); } else if (!strcasecmp(v->name, "rtptimeout")) { gRTPTimeout = atoi(v->value); if (gRTPTimeout <= 0) @@ -1905,7 +2536,7 @@ int reload_config(int reload) } 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); + ast_copy_string(gAccountcode, v->value, sizeof(gAccountcode)); } else if (!strcasecmp(v->name, "disallow")) { ast_parse_allow_disallow(&gPrefs, &gCapability, v->value, 0); } else if (!strcasecmp(v->name, "allow")) { @@ -1919,6 +2550,8 @@ int reload_config(int reload) gDTMFMode = H323_DTMF_INBAND; else if (!strcasecmp(v->value, "rfc2833")) gDTMFMode = H323_DTMF_RFC2833; + else if (!strcasecmp(v->value, "cisco")) + gDTMFMode = H323_DTMF_CISCO; else if (!strcasecmp(v->value, "q931keypad")) gDTMFMode = H323_DTMF_Q931; else if (!strcasecmp(v->value, "h245alphanumeric")) @@ -1926,10 +2559,27 @@ int reload_config(int reload) else if (!strcasecmp(v->value, "h245signal")) gDTMFMode = H323_DTMF_H245SIGNAL; else { - ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value); + ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", + v->value); gDTMFMode = H323_DTMF_RFC2833; } - } + } else if (!strcasecmp(v->name, "relaxdtmf")) { + gDTMFMode |= ast_true(v->value) ? H323_DTMF_INBANDRELAX : 0; + } else if (!strcasecmp(v->name, "dtmfcodec") && atoi(v->value)) { + gDTMFCodec = atoi(v->value); + } else if (!strcasecmp(v->name, "t38support")) { + if (!strcasecmp(v->value, "disabled")) + gT38Support = T38_DISABLED; + if (!strcasecmp(v->value, "no")) + gT38Support = T38_DISABLED; + else if (!strcasecmp(v->value, "faxgw")) + gT38Support = T38_FAXGW; + else if (!strcasecmp(v->value, "yes")) + gT38Support = T38_ENABLED; + } else if (!strcasecmp(v->name, "tracelevel")) { + gTRCLVL = atoi(v->value); + ooH323EpSetTraceLevel(gTRCLVL); + } v = v->next; } @@ -1967,7 +2617,7 @@ int reload_config(int reload) ast_config_destroy(cfg); - /* Determine ip address if necessary */ + /* Determine ip address if neccessary */ if (ast_strlen_zero(gIP)) { ooGetLocalIPAddress(gIP); if (!strcmp(gIP, "127.0.0.1")) { @@ -1981,8 +2631,10 @@ int reload_config(int reload) 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]; @@ -2002,11 +2654,12 @@ static char *handle_cli_ooh323_show_peer(struct ast_cli_entry *e, int cmd, struc 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])) + if(!strcmp(peer->name, a->argv[3])) break; else { prev = peer; @@ -2016,32 +2669,49 @@ static char *handle_cli_ooh323_show_peer(struct ast_cli_entry *e, int cmd, struc } 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"); + sprintf(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_CISCO) { + ast_cli(a->fd, "%s\n", "cisco"); + ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", peer->dtmfcodec); + } else if (peer->dtmfmode & H323_DTMF_RFC2833) { + ast_cli(a->fd, "%s\n", "rfc2833"); + ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", peer->dtmfcodec); + } 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"); + ast_cli(a->fd, "%s\n", "h245alphanumeric"); else if (peer->dtmfmode & H323_DTMF_H245SIGNAL) - ast_cli(a->fd, "%s\n", "h245signal"); + ast_cli(a->fd, "%s\n", "h245signal"); + else if (peer->dtmfmode & H323_DTMF_INBAND && peer->dtmfmode & H323_DTMF_INBANDRELAX) + ast_cli(a->fd, "%s\n", "inband-relaxed"); + else if (peer->dtmfmode & H323_DTMF_INBAND) + ast_cli(a->fd, "%s\n", "inband"); 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_cli(a->fd, "%s\n", "unknown"); + + ast_cli(a->fd,"%-15s", "T.38 Mode: "); + if (peer->t38support == T38_DISABLED) + ast_cli(a->fd, "%s\n", "disabled"); + else if (peer->t38support == T38_FAXGW) + ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible"); + + 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); + 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); + if (peer->rtpmaskstr[0]) + ast_cli(a->fd, "%-15.15s%s\n", "rtpmask: ", peer->rtpmaskstr); + ast_mutex_unlock(&peer->lock); } else { - ast_cli(a->fd, "Peer %s not found\n", a->argv[3]); - ast_cli(a->fd, "\n"); + ast_cli(a->fd, "Peer %s not found\n", a->argv[3]); + ast_cli(a->fd, "\n"); } ast_mutex_unlock(&peerl.lock); @@ -2050,10 +2720,9 @@ static char *handle_cli_ooh323_show_peer(struct ast_cli_entry *e, int cmd, struc 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; - + char formats[FORMAT_STRING_SIZE]; + char ip_port[30]; #define FORMAT "%-15.15s %-15.15s %-23.23s %-s\n" switch (cmd) { @@ -2070,25 +2739,24 @@ static char *handle_cli_ooh323_show_peers(struct ast_cli_entry *e, int cmd, stru if (a->argc != 3) return CLI_SHOWUSAGE; - ast_cli(a->fd, FORMAT, "Name", "Accountcode", "ip:port", "Formats"); + 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, + ast_cli(a->fd, FORMAT, peer->name, peer->accountcode, ip_port, - ast_getformatname_multiple(formats, sizeof(formats), peer->capability)); + ast_getformatname_multiple(formats,FORMAT_STRING_SIZE,peer->capability)); prev = peer; peer = peer->next; ast_mutex_unlock(&prev->lock); + } ast_mutex_unlock(&peerl.lock); - #undef FORMAT - return CLI_SUCCESS; } @@ -2128,13 +2796,14 @@ static char *handle_cli_ooh323_show_user(struct ast_cli_entry *e, int cmd, struc 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])) + if(!strcmp(user->name, a->argv[3])) { break; - else { + } else { prev = user; user = user->next; ast_mutex_unlock(&prev->lock); @@ -2142,30 +2811,49 @@ static char *handle_cli_ooh323_show_user(struct ast_cli_entry *e, int cmd, struc } 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"); + 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_CISCO) { + ast_cli(a->fd, "%s\n", "cisco"); + ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", user->dtmfcodec); + } else if (user->dtmfmode & H323_DTMF_RFC2833) { + ast_cli(a->fd, "%s\n", "rfc2833"); + ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", user->dtmfcodec); + } 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"); + ast_cli(a->fd, "%s\n", "h245alphanumeric"); else if (user->dtmfmode & H323_DTMF_H245SIGNAL) - ast_cli(a->fd, "%s\n", "h245signal"); + ast_cli(a->fd, "%s\n", "h245signal"); + else if (user->dtmfmode & H323_DTMF_INBAND && user->dtmfmode & H323_DTMF_INBANDRELAX) + ast_cli(a->fd, "%s\n", "inband-relaxed"); + else if (user->dtmfmode & H323_DTMF_INBAND) + ast_cli(a->fd, "%s\n", "inband"); 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_cli(a->fd, "%s\n", "unknown"); + + ast_cli(a->fd,"%-15s", "T.38 Mode: "); + if (user->t38support == T38_DISABLED) + ast_cli(a->fd, "%s\n", "disabled"); + else if (user->t38support == T38_FAXGW) + ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible"); + + 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", "InUse: ", user->inUse); + ast_cli(a->fd, "%-15.15s%d\n", "rtptimeout: ", user->rtptimeout); + if (user->rtpmaskstr[0]) + ast_cli(a->fd, "%-15.15s%s\n", "rtpmask: ", user->rtpmaskstr); ast_mutex_unlock(&user->lock); } else { - ast_cli(a->fd, "User %s not found\n", a->argv[3]); - ast_cli(a->fd, "\n"); + ast_cli(a->fd, "User %s not found\n", a->argv[3]); + ast_cli(a->fd, "\n"); } ast_mutex_unlock(&userl.lock); @@ -2174,9 +2862,8 @@ static char *handle_cli_ooh323_show_user(struct ast_cli_entry *e, int cmd, struc 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; - + char formats[FORMAT_STRING_SIZE]; #define FORMAT1 "%-15.15s %-15.15s %-15.15s %-s\n" switch (cmd) { @@ -2193,24 +2880,26 @@ static char *handle_cli_ooh323_show_users(struct ast_cli_entry *e, int cmd, stru if (a->argc != 3) return CLI_SHOWUSAGE; - ast_cli(a->fd, FORMAT1, "Username", "Accountcode", "Context", "Formats"); + + ast_cli(a->fd, FORMAT1, "Username", "Accountcode", "Context", "Formats"); ast_mutex_lock(&userl.lock); user = userl.users; - while (user) { + while(user) + { ast_mutex_lock(&user->lock); - ast_cli(a->fd, FORMAT1, user->name, + ast_cli(a->fd, FORMAT1, user->name, user->accountcode, user->context, - ast_getformatname_multiple(formats, 512, user->capability)); + ast_getformatname_multiple(formats, FORMAT_STRING_SIZE, user->capability)); prev = user; user = user->next; ast_mutex_unlock(&prev->lock); + } ast_mutex_unlock(&userl.lock); - #undef FORMAT1 + return RESULT_SUCCESS; - return CLI_SUCCESS; } static char *handle_cli_ooh323_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) @@ -2246,7 +2935,7 @@ static int ooh323_show_channels(int fd, int argc, char *argv[]) static char *handle_cli_ooh323_show_config(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - char value[512]; + char value[FORMAT_STRING_SIZE]; ooAliases *pAlias = NULL, *pAliasNext = NULL;; switch (cmd) { @@ -2263,25 +2952,27 @@ static char *handle_cli_ooh323_show_config(struct ast_cli_entry *e, int cmd, str 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", + ast_cli(a->fd, "\nObjective Open H.323 Channel Driver's Config:\n"); + snprintf(value, sizeof(value), "%s:%d", gIP, gPort); + ast_cli(a->fd, "%-20s%s\n", "IP:Port: ", value); + ast_cli(a->fd, "%-20s%d-%d\n", "H.225 port range: ", + ooconfig.mTCPPortStart, ooconfig.mTCPPortEnd); + 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", + 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", + ast_cli(a->fd, "%-20s%s\n", "MEDIAWAITFORCONN", (OO_TESTFLAG(gH323ep.flags, OO_M_MEDIAWAITFORCONN) != 0) ? "yes" : "no"); - } #endif if (gRasGkMode == RasNoGatekeeper) @@ -2291,38 +2982,61 @@ static char *handle_cli_ooh323_show_config(struct ast_cli_entry *e, int cmd, str 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"); + 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,FORMAT_STRING_SIZE,gCapability)); + + ast_cli(a->fd, "%-20s", "DTMF Mode: "); + if (gDTMFMode & H323_DTMF_CISCO) { + ast_cli(a->fd, "%s\n", "cisco"); + ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", gDTMFCodec); + } else if (gDTMFMode & H323_DTMF_RFC2833) { + ast_cli(a->fd, "%s\n", "rfc2833"); + ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", gDTMFCodec); + } 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"); + ast_cli(a->fd, "%s\n", "h245alphanumeric"); else if (gDTMFMode & H323_DTMF_H245SIGNAL) - ast_cli(a->fd, "%s\n", "h245signal"); + ast_cli(a->fd, "%s\n", "h245signal"); + else if (gDTMFMode & H323_DTMF_INBAND && gDTMFMode & H323_DTMF_INBANDRELAX) + ast_cli(a->fd, "%s\n", "inband-relaxed"); + else if (gDTMFMode & H323_DTMF_INBAND) + ast_cli(a->fd, "%s\n", "inband"); 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)); + + ast_cli(a->fd,"%-20s", "T.38 Mode: "); + if (gT38Support == T38_DISABLED) + ast_cli(a->fd, "%s\n", "disabled"); + else if (gT38Support == T38_FAXGW) + ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible"); + + ast_cli(a->fd, "%-20s%ld\n", "Call counter: ", callnumber); + 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: "); + 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); + 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); + } + else{ + ast_cli(a->fd,"\t%-30s\n",pAlias->value); pAlias = pAlias->next; } } - return CLI_SUCCESS; } @@ -2333,8 +3047,10 @@ static struct ast_cli_entry cli_ooh323[] = { 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"), + AST_CLI_DEFINE(handle_cli_ooh323_reload, "reload ooh323 config") }; + static int load_module(void) { int res; @@ -2345,12 +3061,14 @@ static int load_module(void) OOH323CALLBACKS h323Callbacks = { .onNewCallCreated = onNewCallCreated, .onAlerting = onAlerting, + .onProgress = onProgress, .onIncomingCall = NULL, - .onOutgoingCall = NULL, + .onOutgoingCall = onOutgoingCall, .onCallEstablished = onCallEstablished, .onCallCleared = onCallCleared, .openLogicalChannels = NULL, - .onReceivedDTMF = &ooh323_onReceivedDigit + .onReceivedDTMF = ooh323_onReceivedDigit, + .onModeChanged = onModeChanged }; ast_log(LOG_NOTICE, @@ -2361,6 +3079,8 @@ static int load_module(void) "---\n" "---------------------------------------------------------------------------------\n"); + myself = ast_module_info->self; + h225Callbacks.onReceivedSetup = &ooh323_onReceivedSetup; userl.users = NULL; @@ -2386,24 +3106,33 @@ static int load_module(void) ast_log(LOG_ERROR, "Unable to register channel class %s\n", type); return 0; } - ast_rtp_proto_register(&ooh323_rtp); + ast_rtp_glue_register(&ooh323_rtp); + ast_udptl_proto_register(&ooh323_udptl); 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"); + ast_log(LOG_ERROR, "Failed to initialize OOH323 endpoint-" + "OOH323 Disabled\n"); return 1; } if (gIsGateway) ooH323EpSetAsGateway(); + ooH323EpSetVersionInfo(t35countrycode, t35extensions, manufacturer, + vendor, version); ooH323EpDisableAutoAnswer(); ooH323EpSetH225MsgCallbacks(h225Callbacks); - ooH323EpSetTraceLevel(OOTRCLVLDBGC); + ooH323EpSetTraceLevel(gTRCLVL); ooH323EpSetLocalAddress(gIP, gPort); ooH323EpSetCallerID(gCallerID); + if(ooH323EpSetTCPPortRange(ooconfig.mTCPPortStart, + ooconfig.mTCPPortEnd) == OO_FAILED) { + ast_log(LOG_ERROR, "h225portrange: Failed to set range\n"); + } + /* Set aliases if any */ for (pNewAlias = gAliasList; pNewAlias; pNewAlias = pNewAlias->next) { switch (pNewAlias->type) { @@ -2416,20 +3145,18 @@ static int load_module(void) case T_H225AliasAddress_email_ID: ooH323EpAddAliasEmailID(pNewAlias->value); break; + default: + ; } } 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); + 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); @@ -2449,6 +3176,11 @@ static int load_module(void) if (!gTunneling) ooH323EpDisableH245Tunneling(); + if (gBeMaster) + ooH323EpTryBeMaster(1); + + ooH323EpEnableManualRingback(); + /* Gatekeeper */ if (gRasGkMode == RasUseSpecificGatekeeper) ooGkClientInit(gRasGkMode, gGatekeeper, 0); @@ -2459,22 +3191,23 @@ static int load_module(void) ooH323EpSetH323Callbacks(h323Callbacks); /* Add endpoint capabilities */ - if (ooh323c_set_capability(&gPrefs, gCapability, gDTMFMode) < 0) { + if (ooh323c_set_capability(&gPrefs, gCapability, gDTMFMode, gDTMFCodec) < 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"); + 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"); + ast_log(LOG_ERROR, "Failed to start OOH323 stack thread. " + "OOH323 DISABLED\n"); ooH323EpDestroy(); return 1; } @@ -2504,6 +3237,7 @@ static void *do_monitor(void *data) ast_verb(1, "Reloading H.323\n"); ooh323_do_reload(); } + /* Check for interfaces needing to be killed */ ast_mutex_lock(&iflock); time(&t); @@ -2514,11 +3248,21 @@ static void *do_monitor(void *data) /* TODO: Need to add rtptimeout keepalive support */ if (ast_test_flag(h323, H323_NEEDDESTROY)) { ooh323_destroy (h323); - } + } /* else if (ast_test_flag(h323, H323_NEEDSTART) && h323->owner) { + ast_channel_lock(h323->owner); + if (ast_pbx_start(h323->owner)) { + ast_log(LOG_WARNING, "Unable to start PBX on %s\n", h323->owner->name); + ast_channel_unlock(h323->owner); + ast_hangup(h323->owner); + } + ast_channel_unlock(h323->owner); + ast_clear_flag(h323, H323_NEEDSTART); + } */ h323 = h323_next; } ast_mutex_unlock(&iflock); pthread_testcancel(); + /* Wait for sched or io */ res = ast_sched_wait(sched); if ((res < 0) || (res > 1000)) { @@ -2575,7 +3319,7 @@ int ooh323_destroy(struct ooh323_pvt *p) { /* NOTE: Assumes iflock already acquired */ struct ooh323_pvt *prev = NULL, *cur = NULL; - + struct ooh323_user *user = NULL; if (gH323Debug) { ast_verbose("--- ooh323_destroy \n"); @@ -2599,7 +3343,9 @@ int ooh323_destroy(struct ooh323_pvt *p) iflist = cur->next; if (cur->callToken) { - free(cur->callToken); + if (gH323Debug) + ast_verbose(" Destroying %s\n", cur->callToken); + ast_free(cur->callToken); cur->callToken = 0; } @@ -2623,29 +3369,54 @@ int ooh323_destroy(struct ooh323_pvt *p) cur->callerid_num = 0; } - if (cur->rtp) { - ast_rtp_destroy(cur->rtp); - cur->rtp = 0; + ast_rtp_instance_destroy(cur->rtp); + cur->rtp = NULL; + } + + if (cur->udptl) { + ast_udptl_destroy(cur->udptl); + cur->udptl = NULL; } /* Unlink us from the owner if we have one */ if (cur->owner) { - ast_channel_lock(cur->owner); + while(ast_channel_trylock(cur->owner)) { + ast_debug(1,"Failed to grab lock, trying again\n"); + DEADLOCK_AVOIDANCE(&cur->lock); + } ast_debug(1, "Detaching from %s\n", cur->owner->name); cur->owner->tech_pvt = NULL; ast_channel_unlock(cur->owner); cur->owner = NULL; + ast_module_unref(myself); } if (cur->vad) { ast_dsp_free(cur->vad); cur->vad = NULL; } + +/* decrement user/peer count */ + + if(!ast_test_flag(cur, H323_OUTGOING)) { + if (cur->neighbor.user) { + user = find_user(p->callerid_name, cur->neighbor.user); + if(user && user->inUse > 0) { + ast_mutex_lock(&user->lock); + user->inUse--; + ast_mutex_unlock(&user->lock); + } + free(cur->neighbor.user); + } + } else { +/* outgoing limit decrement here !!! */ + } + ast_mutex_unlock(&cur->lock); ast_mutex_destroy(&cur->lock); - free(cur); + ast_free(cur); } if (gH323Debug) @@ -2664,14 +3435,20 @@ int delete_peers() 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); + if(prev->h323id) free(prev->h323id); + if(prev->email) free(prev->email); + if(prev->url) free(prev->url); + if(prev->e164) free(prev->e164); + if(prev->rtpmask) { + ast_mutex_lock(&prev->rtpmask->lock); + prev->rtpmask->inuse--; + ast_mutex_unlock(&prev->rtpmask->lock); + if (prev->rtpmask->inuse == 0) { + regfree(&prev->rtpmask->regex); + ast_mutex_destroy(&prev->rtpmask->lock); + free(prev->rtpmask); + } + } free(prev); if (cur == peerl.peers) { @@ -2692,6 +3469,17 @@ int delete_users() prev = cur; cur = cur->next; ast_mutex_destroy(&prev->lock); + + if(prev->rtpmask) { + ast_mutex_lock(&prev->rtpmask->lock); + prev->rtpmask->inuse--; + ast_mutex_unlock(&prev->rtpmask->lock); + if (prev->rtpmask->inuse == 0) { + regfree(&prev->rtpmask->regex); + ast_mutex_destroy(&prev->rtpmask->lock); + free(prev->rtpmask); + } + } free(prev); if (cur == userl.users) { break; @@ -2712,9 +3500,9 @@ static int unload_module(void) } /* 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_rtp_glue_unregister(&ooh323_rtp); + ast_udptl_proto_unregister(&ooh323_udptl); ast_channel_unregister(&ooh323_tech); - #if 0 ast_unregister_atexit(&ast_ooh323c_exit); #endif @@ -2825,38 +3613,39 @@ static int unload_module(void) -static enum ast_rtp_get_result ooh323_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp) +static enum ast_rtp_glue_result ooh323_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **rtp) { struct ooh323_pvt *p = NULL; - enum ast_rtp_get_result res = AST_RTP_TRY_PARTIAL; + enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_LOCAL; if (!(p = (struct ooh323_pvt *) chan->tech_pvt)) - return AST_RTP_GET_FAILED; - - *rtp = p->rtp; + return AST_RTP_GLUE_RESULT_FORBID; if (!(p->rtp)) { - return AST_RTP_GET_FAILED; + return AST_RTP_GLUE_RESULT_FORBID; } - res = AST_RTP_TRY_NATIVE; + + *rtp = p->rtp ? ao2_ref(p->rtp, +1), p->rtp : NULL; + + res = AST_RTP_GLUE_RESULT_LOCAL; return res; } -static enum ast_rtp_get_result ooh323_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp **rtp) +static enum ast_rtp_glue_result ooh323_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp_instance **rtp) { struct ooh323_pvt *p = NULL; - enum ast_rtp_get_result res = AST_RTP_TRY_PARTIAL; + enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_LOCAL; if (!(p = (struct ooh323_pvt *) chan->tech_pvt)) - return AST_RTP_GET_FAILED; - - *rtp = p->vrtp; + return AST_RTP_GLUE_RESULT_FORBID; if (!(p->rtp)) { - return AST_RTP_GET_FAILED; + return AST_RTP_GLUE_RESULT_FORBID; } - res = AST_RTP_TRY_NATIVE; + + *rtp = p->vrtp ? ao2_ref(p->vrtp, +1), p->vrtp : NULL; + res = AST_RTP_GLUE_RESULT_LOCAL; return res; } @@ -2880,7 +3669,7 @@ int ooh323_update_capPrefsOrderForCall int ooh323_convertAsteriskCapToH323Cap(int cap) { - char formats[512]; + char formats[FORMAT_STRING_SIZE]; switch (cap) { case AST_FORMAT_ULAW: return OO_G711ULAW64K; @@ -2888,21 +3677,35 @@ int ooh323_convertAsteriskCapToH323Cap(int cap) return OO_G711ALAW64K; case AST_FORMAT_GSM: return OO_GSMFULLRATE; + +#ifdef AST_FORMAT_AMRNB + case AST_FORMAT_AMRNB: + return OO_AMRNB; +#endif +#ifdef AST_FORMAT_SPEEX + case AST_FORMAT_SPEEX: + return OO_SPEEX; +#endif + case AST_FORMAT_G729A: return OO_G729A; + case AST_FORMAT_G726: + return OO_G726; + case AST_FORMAT_G726_AAL2: + return OO_G726AAL2; 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)); + ast_getformatname_multiple(formats,FORMAT_STRING_SIZE,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) +static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, + struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, int codecs, int nat_active) { /* XXX Deal with Video */ struct ooh323_pvt *p; @@ -2923,8 +3726,8 @@ static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, 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); + ast_rtp_instance_get_remote_address(rtp, &them); + ast_rtp_instance_get_local_address(rtp, &us); return 0; } @@ -2941,11 +3744,27 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call) ast_verbose("--- configure_local_rtp\n"); if (p->rtp) { - ast_rtp_codec_setpref(p->rtp, &p->prefs); + ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &p->prefs); + if (p->dtmfmode & H323_DTMF_RFC2833 && p->dtmfcodec) { + ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_DTMF, 1); + ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), + p->rtp, p->dtmfcodec, "audio", "telephone-event", 0); + } + if (p->dtmfmode & H323_DTMF_CISCO && p->dtmfcodec) { + ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_DTMF, 1); + ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), + p->rtp, p->dtmfcodec, "audio", "cisco-telephone-event", 0); + } + /* figure out our local RTP port and tell the H.323 stack about it*/ + ast_rtp_instance_get_local_address(p->rtp, &us); + + if (p->rtptimeout) { + ast_rtp_instance_set_timeout(p->rtp, p->rtptimeout); + } + ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_RTCP, 1); + } - /* 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); @@ -2962,9 +3781,27 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call) ooAddMediaInfo(call, mediaInfo); strcpy(mediaInfo.dir, "receive"); ooAddMediaInfo(call, mediaInfo); + + strcpy(mediaInfo.dir, "transmit"); + mediaInfo.cap = OO_G729B; + ooAddMediaInfo(call, mediaInfo); + strcpy(mediaInfo.dir, "receive"); + ooAddMediaInfo(call, mediaInfo); } } + if (p->udptl) { + ast_udptl_get_us(p->udptl, &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; + mediaInfo.cap = OO_T38; + strcpy(mediaInfo.dir, "transmit"); + ooAddMediaInfo(call, mediaInfo); + strcpy(mediaInfo.dir, "receive"); + ooAddMediaInfo(call, mediaInfo); + if (gH323Debug) ast_verbose("+++ configure_local_rtp\n"); @@ -2978,7 +3815,7 @@ void setup_rtp_connection(ooCallData *call, const char *remoteIp, struct sockaddr_in them; if (gH323Debug) - ast_verbose("--- setup_rtp_connection\n"); + ast_verbose("--- setup_rtp_connection %s:%d\n", remoteIp, remotePort); /* Find the call or allocate a private structure if call not found */ p = find_call(call); @@ -2991,11 +3828,14 @@ void setup_rtp_connection(ooCallData *call, const char *remoteIp, 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); + ast_rtp_instance_set_remote_address(p->rtp, &them); - if (gH323Debug) { + if (p->writeformat & AST_FORMAT_G726_AAL2) + ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, 2, + "audio", "G726-32", AST_RTP_OPT_G726_NONSTANDARD); + + if(gH323Debug) ast_verbose("+++ setup_rtp_connection\n"); - } return; } @@ -3004,28 +3844,169 @@ void close_rtp_connection(ooCallData *call) { struct ooh323_pvt *p = NULL; - if (gH323Debug) { + 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"); + 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_rtp_instance_stop(p->rtp); } ast_mutex_unlock(&p->lock); - if (gH323Debug) { + if(gH323Debug) ast_verbose("+++ close_rtp_connection\n"); + + return; +} + +/* + udptl handling functions + */ + +static struct ast_udptl *ooh323_get_udptl_peer(struct ast_channel *chan) +{ + struct ooh323_pvt *p; + struct ast_udptl *udptl = NULL; + + p = chan->tech_pvt; + if (!p) + return NULL; + + ast_mutex_lock(&p->lock); + if (p->udptl) + udptl = p->udptl; + ast_mutex_unlock(&p->lock); + return udptl; +} + +static int ooh323_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl) +{ + struct ooh323_pvt *p; + + p = chan->tech_pvt; + if (!p) + return -1; + ast_mutex_lock(&p->lock); + if (udptl) + ast_udptl_get_peer(udptl, &p->udptlredirip); + else + memset(&p->udptlredirip, 0, sizeof(p->udptlredirip)); + + ast_mutex_unlock(&p->lock); + return 0; +} + +void setup_udptl_connection(ooCallData *call, const char *remoteIp, + int remotePort) +{ + struct ooh323_pvt *p = NULL; + struct sockaddr_in them; + + if (gH323Debug) + ast_verbose("--- setup_udptl_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; + } + + ast_mutex_lock(&p->lock); + if (p->owner) { + while (p->owner && ast_channel_trylock(p->owner)) { + ast_debug(1,"Failed to grab lock, trying again\n"); + DEADLOCK_AVOIDANCE(&p->lock); + } + if (!p->owner) { + ast_mutex_unlock(&p->lock); + ast_log(LOG_ERROR, "Channel has no owner\n"); + return; + } + } else { + ast_mutex_unlock(&p->lock); + ast_log(LOG_ERROR, "Channel has no owner\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_udptl_set_peer(p->udptl, &them); + p->t38_tx_enable = 1; + p->lastTxT38 = time(NULL); + if (p->t38support == T38_ENABLED) { + struct ast_control_t38_parameters parameters = { .request_response = 0 }; + parameters.request_response = AST_T38_NEGOTIATED; + ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, ¶meters, sizeof(parameters)); + } + if (gH323Debug) + ast_debug(1, "Receiving UDPTL %s:%d\n", ast_inet_ntoa(them.sin_addr), + ntohs(them.sin_port)); + + ast_channel_unlock(p->owner); + ast_mutex_unlock(&p->lock); + + if(gH323Debug) + ast_verbose("+++ setup_udptl_connection\n"); + + return; +} + +void close_udptl_connection(ooCallData *call) +{ + struct ooh323_pvt *p = NULL; + + if(gH323Debug) + ast_verbose("--- close_udptl_connection\n"); + + p = find_call(call); + if (!p) { + ast_log(LOG_ERROR, "Couldn't find matching call to close udptl " + "connection\n"); + return; } + ast_mutex_lock(&p->lock); + if (p->owner) { + while (p->owner && ast_channel_trylock(p->owner)) { + ast_debug(1,"Failed to grab lock, trying again\n"); + DEADLOCK_AVOIDANCE(&p->lock); + } + if (!p->owner) { + ast_mutex_unlock(&p->lock); + ast_log(LOG_ERROR, "Channel has no owner\n"); + return; + } + } else { + ast_mutex_unlock(&p->lock); + ast_log(LOG_ERROR, "Channel has no owner\n"); + return; + } + + p->t38_tx_enable = 0; + if (p->t38support == T38_ENABLED) { + struct ast_control_t38_parameters parameters = { .request_response = 0 }; + parameters.request_response = AST_T38_TERMINATED; + ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, ¶meters, sizeof(parameters)); + } + + ast_channel_unlock(p->owner); + ast_mutex_unlock(&p->lock); + + if(gH323Debug) + ast_verbose("+++ close_udptl_connection\n"); return; } +/* end of udptl handling */ int update_our_aliases(ooCallData *call, struct ooh323_pvt *p) { @@ -3040,7 +4021,8 @@ int update_our_aliases(ooCallData *call, struct ooh323_pvt *p) updated = 1; } if (psAlias->type == T_H225AliasAddress_dialedDigits) { - ast_copy_string(p->callee_dialedDigits, psAlias->value, sizeof(p->callee_dialedDigits)); + ast_copy_string(p->callee_dialedDigits, psAlias->value, + sizeof(p->callee_dialedDigits)); updated = 1; } if (psAlias->type == T_H225AliasAddress_url_ID) { @@ -3062,44 +4044,118 @@ struct ast_frame *ooh323_rtp_read(struct ast_channel *ast, struct ooh323_pvt *p) static struct ast_frame null_frame = { AST_FRAME_NULL, }; switch (ast->fdno) { case 0: - f = ast_rtp_read(p->rtp); /* RTP Audio */ + f = ast_rtp_instance_read(p->rtp, 0); /* RTP Audio */ break; case 1: - f = ast_rtcp_read(p->rtp); /* RTCP Control Channel */ + f = ast_rtp_instance_read(p->rtp, 1); /* RTCP Control Channel */ break; case 2: - f = ast_rtp_read(p->vrtp); /* RTP Video */ + f = ast_rtp_instance_read(p->vrtp, 0); /* RTP Video */ break; case 3: - f = ast_rtcp_read(p->vrtp); /* RTCP Control Channel for video */ + f = ast_rtp_instance_read(p->vrtp, 1); /* RTCP Control Channel for video */ + break; + case 5: + f = ast_udptl_read(p->udptl); /* UDPTL t.38 data */ + if (gH323Debug) ast_debug(1, "Got UDPTL %d/%d len %d for %s\n", + f->frametype, f->subclass, f->datalen, ast->name); 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->frametype == AST_FRAME_VOICE && !p->faxmode) { if (f->subclass != p->owner->nativeformats) { - ast_debug(1, "Oooh, format changed to %d\n", f->subclass); + 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) { + + if ((p->dtmfmode & H323_DTMF_INBAND) && p->vad && + (f->subclass == AST_FORMAT_SLINEAR || f->subclass == AST_FORMAT_ALAW || + f->subclass == AST_FORMAT_ULAW)) { 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); - } + if (f && (f->frametype == AST_FRAME_DTMF)) + ast_debug(1, "* Detected inband DTMF '%c'\n",f->subclass); } } } return f; } +void onModeChanged(ooCallData *call, int t38mode) { + struct ooh323_pvt *p; + + 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); + + if (gH323Debug) + ast_debug(1, "change mode to %d for %s\n", t38mode, call->callToken); + + if (t38mode == p->faxmode) { + if (gH323Debug) + ast_debug(1, "mode for %s is already %d\n", call->callToken, + t38mode); + ast_mutex_unlock(&p->lock); + return; + } + + if (p->owner) { + while (p->owner && ast_channel_trylock(p->owner)) { + ast_debug(1,"Failed to grab lock, trying again\n"); + DEADLOCK_AVOIDANCE(&p->lock); + } + if (!p->owner) { + ast_mutex_unlock(&p->lock); + ast_log(LOG_ERROR, "Channel has no owner\n"); + return; + } + } else { + ast_mutex_unlock(&p->lock); + ast_log(LOG_ERROR, "Channel has no owner\n"); + return; + } + + if (t38mode) { + + + if (p->t38support == T38_ENABLED) { + +/* AST_T38_CONTROL mode */ + + struct ast_control_t38_parameters parameters = { .request_response = 0 }; + parameters.request_response = AST_T38_REQUEST_NEGOTIATE; + ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, + ¶meters, sizeof(parameters)); + p->faxmode = 1; + + } + } else { + if (p->t38support == T38_ENABLED) { + struct ast_control_t38_parameters parameters = { .request_response = 0 }; + parameters.request_response = AST_T38_REQUEST_TERMINATE; + ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, + ¶meters, sizeof(parameters)); + } + p->faxmode = 0; + p->t38_init = 0; + } + + p->chmodepend = 0; + ast_channel_unlock(p->owner); + ast_mutex_unlock(&p->lock); +} + + int ooh323_convert_hangupcause_asteriskToH323(int cause) { @@ -3124,6 +4180,8 @@ int ooh323_convert_hangupcause_asteriskToH323(int cause) } return 0; + + } int ooh323_convert_hangupcause_h323ToAsterisk(int cause) |