aboutsummaryrefslogtreecommitdiffstats
path: root/channels/chan_h323.c
diff options
context:
space:
mode:
authorjeremy <jeremy@f38db490-d61c-443f-a65b-d21fe96a405b>2004-12-15 23:24:13 +0000
committerjeremy <jeremy@f38db490-d61c-443f-a65b-d21fe96a405b>2004-12-15 23:24:13 +0000
commitd405f48268f1722f7b52ae79007b817b5b4e6835 (patch)
treec6ab11cf50a0edeab333525773145b9f6fd9ab7e /channels/chan_h323.c
parent00105edf932d8417e9ac7ab76833869a0b8a0b4d (diff)
Major fixes: Fixed deadlock issue, added support for inband call progress and correct Progress Indicator messages, added configurable RTP payload to send RFC2833 DTMF and correct sending of RFC2833 User Input capability, fixed hostname parsing on peers, preliminary support for correct Q.931 cause codes and fixed bindaddr compile warning
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@4466 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels/chan_h323.c')
-rwxr-xr-xchannels/chan_h323.c181
1 files changed, 140 insertions, 41 deletions
diff --git a/channels/chan_h323.c b/channels/chan_h323.c
index 5b92834c5..a3a22e8c7 100755
--- a/channels/chan_h323.c
+++ b/channels/chan_h323.c
@@ -81,6 +81,8 @@ chan_ringing_cb on_chan_ringing;
con_established_cb on_connection_established;
clear_con_cb on_connection_cleared;
answer_call_cb on_answer_call;
+progress_cb on_progress;
+rfc2833_cb on_set_rfc2833_payload;
/* global debug flag */
int h323debug;
@@ -91,6 +93,7 @@ static char *desc = "The NuFone Network's Open H.323 Channel Driver";
static char *tdesc = "The NuFone Network's Open H.323 Channel Driver";
static char *config = "h323.conf";
static char default_context[AST_MAX_EXTENSION] = "default";
+static struct sockaddr_in bindaddr;
/** H.323 configuration values */
static int h323_signalling_port = 1720;
@@ -99,9 +102,6 @@ static int gatekeeper_disable = 1;
static int gatekeeper_discover = 0;
static int usingGk = 0;
static int gkroute = 0;
-static int noFastStart = 0;
-static int noH245Tunneling = 0;
-static int noSilenceSuppression = 0;
/* Assume we can native bridge by default */
static int bridging = 1;
/* Find user by alias (h.323 id) is default, alternative is the incomming call's source IP address*/
@@ -111,6 +111,8 @@ static int tos = 0;
static int dtmfmode = H323_DTMF_RFC2833;
static char secret[50];
+static call_options_t global_options;
+
/** Private structure of a OpenH323 channel */
struct oh323_pvt {
ast_mutex_t lock; /* Channel private lock */
@@ -261,7 +263,7 @@ static struct oh323_user *build_user(char *name, struct ast_variable *v)
if (user) {
memset(user, 0, sizeof(struct oh323_user));
strncpy(user->name, name, sizeof(user->name) - 1);
-
+ user->options.dtmfcodec = 101;
/* set a native brigding default value */
user->bridge = bridging;
/* and default context */
@@ -274,17 +276,39 @@ static struct oh323_user *build_user(char *name, struct ast_variable *v)
} else if (!strcasecmp(v->name, "nat")) {
user->nat = ast_true(v->value);
} else if (!strcasecmp(v->name, "noFastStart")) {
- user->noFastStart = ast_true(v->value);
+ user->options.noFastStart = ast_true(v->value);
} else if (!strcasecmp(v->name, "noH245Tunneling")) {
- user->noH245Tunneling = ast_true(v->value);
+ user->options.noH245Tunneling = ast_true(v->value);
} else if (!strcasecmp(v->name, "noSilenceSuppression")) {
- user->noSilenceSuppression = ast_true(v->value);
+ user->options.noSilenceSuppression = ast_true(v->value);
} else if (!strcasecmp(v->name, "secret")) {
strncpy(user->secret, v->value, sizeof(user->secret) - 1);
} else if (!strcasecmp(v->name, "callerid")) {
strncpy(user->callerid, v->value, sizeof(user->callerid) - 1);
} else if (!strcasecmp(v->name, "accountcode")) {
strncpy(user->accountcode, v->value, sizeof(user->accountcode) - 1);
+ } else if (!strcasecmp(v->name, "progress_setup")) {
+ int progress_setup = atoi(v->value);
+ if ((progress_setup != 0) &&
+ (progress_setup != 1) &&
+ (progress_setup != 3) &&
+ (progress_setup != 8)) {
+ ast_log(LOG_WARNING, "Invalid value %d for progress_setup at line %d, assuming 0\n", progress_setup, v->lineno);
+ progress_setup = 0;
+ }
+ user->options.progress_setup = progress_setup;
+ } else if (!strcasecmp(v->name, "progress_alert")) {
+ int progress_alert = atoi(v->value);
+ if ((progress_alert != 0) &&
+ (progress_alert != 8)) {
+ ast_log(LOG_WARNING, "Invalud value %d for progress_alert at line %d, assuming 0\n", progress_alert, v->lineno);
+ progress_alert = 0;
+ }
+ user->options.progress_alert = progress_alert;
+ } else if (!strcasecmp(v->name, "progress_audio")) {
+ user->options.progress_audio = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "dtmfcodec")) {
+ user->options.dtmfcodec = atoi(v->value);
} else if (!strcasecmp(v->name, "host")) {
if (!strcasecmp(v->value, "dynamic")) {
ast_log(LOG_ERROR, "A dynamic host on a type=user does not make any sense\n");
@@ -354,6 +378,8 @@ static struct oh323_peer *build_peer(char *name, struct ast_variable *v)
peer->ha = NULL;
peer->addr.sin_family = AF_INET;
peer->capability = capability;
+ peer->options.dtmfcodec = 101;
+ peer->dtmfmode = H323_DTMF_RFC2833;
while(v) {
if (!strcasecmp(v->name, "bridge")) {
@@ -361,11 +387,33 @@ static struct oh323_peer *build_peer(char *name, struct ast_variable *v)
} else if (!strcasecmp(v->name, "nat")) {
peer->nat = ast_true(v->value);
} else if (!strcasecmp(v->name, "noFastStart")) {
- peer->noFastStart = ast_true(v->value);
+ peer->options.noFastStart = ast_true(v->value);
} else if (!strcasecmp(v->name, "noH245Tunneling")) {
- peer->noH245Tunneling = ast_true(v->value);
+ peer->options.noH245Tunneling = ast_true(v->value);
} else if (!strcasecmp(v->name, "noSilenceSuppression")) {
- peer->noSilenceSuppression = ast_true(v->value);
+ peer->options.noSilenceSuppression = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "progress_setup")) {
+ int progress_setup = atoi(v->value);
+ if ((progress_setup != 0) &&
+ (progress_setup != 1) &&
+ (progress_setup != 3) &&
+ (progress_setup != 8)) {
+ ast_log(LOG_WARNING, "Invalid value %d for progress_setup at line %d, assuming 0\n", progress_setup, v->lineno);
+ progress_setup = 0;
+ }
+ peer->options.progress_setup = progress_setup;
+ } else if (!strcasecmp(v->name, "progress_alert")) {
+ int progress_alert = atoi(v->value);
+ if ((progress_alert != 0) &&
+ (progress_alert != 8)) {
+ ast_log(LOG_WARNING, "Invalid value %d for progress_alert at line %d, assuming 0\n", progress_alert, v->lineno);
+ progress_alert = 0;
+ }
+ peer->options.progress_alert = progress_alert;
+ } else if (!strcasecmp(v->name, "progress_audio")) {
+ peer->options.progress_audio = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "dtmfcodec")) {
+ peer->options.dtmfcodec = atoi(v->value);
} else if (!strcasecmp(v->name, "dtmfmode")) {
if (!strcasecmp(v->value, "inband")) {
peer->dtmfmode = H323_DTMF_INBAND;
@@ -415,6 +463,7 @@ static struct oh323_peer *build_peer(char *name, struct ast_variable *v)
*/
static int oh323_digit(struct ast_channel *c, char digit)
{
+ ast_log(LOG_DEBUG, "Sending %c...\n", digit);
struct oh323_pvt *p = (struct oh323_pvt *) c->pvt->pvt;
if (p && p->rtp && (p->dtmfmode & H323_DTMF_RFC2833)) {
ast_rtp_senddigit(p->rtp, digit);
@@ -438,8 +487,6 @@ static int oh323_call(struct ast_channel *c, char *dest, int timeout)
char addr[INET_ADDRSTRLEN];
char called_addr[INET_ADDRSTRLEN];
- ast_log(LOG_DEBUG, "Dest is %s\n", dest);
-
if ((c->_state != AST_STATE_DOWN) && (c->_state != AST_STATE_RESERVED)) {
ast_log(LOG_WARNING, "Line is already in use (%s)\n", c->name);
return -1;
@@ -448,9 +495,6 @@ static int oh323_call(struct ast_channel *c, char *dest, int timeout)
memset(addr, 0, sizeof(addr));
if (usingGk) {
memcpy(addr, dest, strlen(addr));
- pvt->options.noFastStart = noFastStart;
- pvt->options.noH245Tunneling = noH245Tunneling;
- pvt->options.noSilenceSuppression = noSilenceSuppression;
pvt->options.port = h323_signalling_port;
} else {
ast_inet_ntoa(addr, sizeof(addr), pvt->sa.sin_addr);
@@ -464,8 +508,8 @@ static int oh323_call(struct ast_channel *c, char *dest, int timeout)
} else {
sprintf(called_addr, "%s:%d",addr, pvt->options.port);
}
- ast_log(LOG_DEBUG, "Placing outgoing call to %s\n", dest);
- res = h323_make_call(dest, &(pvt->cd), pvt->options);
+ ast_log(LOG_DEBUG, "Placing outgoing call to %s, %d\n", called_addr, pvt->options.dtmfcodec);
+ res = h323_make_call(called_addr, &(pvt->cd), &pvt->options);
if (res) {
ast_log(LOG_NOTICE, "h323_make_call failed(%s)\n", c->name);
return -1;
@@ -518,7 +562,7 @@ static int oh323_hangup(struct ast_channel *c)
/* Start the process if it's not already started */
if (!pvt->alreadygone) {
- if (h323_clear_call((pvt->cd).call_token)) {
+ if (h323_clear_call((pvt->cd).call_token, c->hangupcause)) {
ast_log(LOG_DEBUG, "ClearCall failed.\n");
}
pvt->needdestroy = 1;
@@ -617,13 +661,15 @@ static int oh323_indicate(struct ast_channel *c, int condition)
{
struct oh323_pvt *pvt = (struct oh323_pvt *) c->pvt->pvt;
-
+
+ ast_log(LOG_DEBUG, "OH323: Indicating %d on %s\n", condition, pvt->cd.call_token);
+
switch(condition) {
case AST_CONTROL_RINGING:
if (c->_state == AST_STATE_RING || c->_state == AST_STATE_RINGING) {
h323_send_alerting(pvt->cd.call_token);
break;
- }
+ }
return -1;
case AST_CONTROL_PROGRESS:
if (c->_state != AST_STATE_UP) {
@@ -656,7 +702,7 @@ static int oh323_indicate(struct ast_channel *c, int condition)
return -1;
ast_mutex_unlock(&pvt->lock);
}
- return 0;
+ return -1;
}
static int oh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
@@ -681,6 +727,11 @@ static struct ast_channel *oh323_new(struct oh323_pvt *pvt, int state, const cha
/* Don't hold a oh323_pvt lock while we allocate a chanel */
ast_mutex_unlock(&pvt->lock);
ch = ast_channel_alloc(1);
+ /* Update usage counter */
+ ast_mutex_lock(&usecnt_lock);
+ usecnt++;
+ ast_mutex_unlock(&usecnt_lock);
+ ast_update_use_count();
ast_mutex_lock(&pvt->lock);
if (ch) {
snprintf(ch->name, sizeof(ch->name), "H323/%s", host);
@@ -720,12 +771,6 @@ static struct ast_channel *oh323_new(struct oh323_pvt *pvt, int state, const cha
/* Set the owner of this channel */
pvt->owner = ch;
- /* Update usage counter */
- ast_mutex_lock(&usecnt_lock);
- usecnt++;
- ast_mutex_unlock(&usecnt_lock);
- ast_update_use_count();
-
strncpy(ch->context, pvt->context, sizeof(ch->context) - 1);
strncpy(ch->exten, pvt->exten, sizeof(ch->exten) - 1);
ch->priority = 1;
@@ -758,6 +803,7 @@ static struct ast_channel *oh323_new(struct oh323_pvt *pvt, int state, const cha
} else {
ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
}
+ ast_mutex_unlock(&pvt->lock);
return ch;
}
@@ -911,10 +957,8 @@ static int create_addr(struct oh323_pvt *pvt, char *opeer)
ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", pvt->nat);
ast_rtp_setnat(pvt->rtp, pvt->nat);
}
- pvt->options.noFastStart = p->noFastStart;
- pvt->options.noH245Tunneling = p->noH245Tunneling;
- pvt->options.noSilenceSuppression = p->noSilenceSuppression;
- if (pvt->dtmfmode) {
+ memcpy(&pvt->options, &p->options, sizeof(pvt->options));
+ if (p->dtmfmode) {
pvt->dtmfmode = p->dtmfmode;
if (pvt->dtmfmode & H323_DTMF_RFC2833) {
pvt->nonCodecCapability |= AST_RTP_DTMF;
@@ -937,6 +981,7 @@ static int create_addr(struct oh323_pvt *pvt, char *opeer)
}
hp = ast_gethostbyname(hostn, &ahp);
if (hp) {
+ memcpy(&pvt->options, &global_options, sizeof(pvt->options));
memcpy(&pvt->sa.sin_addr, hp->h_addr, sizeof(pvt->sa.sin_addr));
pvt->sa.sin_port = htons(portno);
return 0;
@@ -950,7 +995,7 @@ static int create_addr(struct oh323_pvt *pvt, char *opeer)
return 0;
}
}
-static struct ast_channel *oh323_request(const char *type, int format, void *data)
+static struct ast_channel *oh323_request(const char *type, int format, void *data, int *cause)
{
int oldformat;
struct oh323_pvt *pvt;
@@ -1000,6 +1045,7 @@ static struct ast_channel *oh323_request(const char *type, int format, void *dat
return NULL;
}
}
+
/* pass on our capabilites to the H.323 stack */
ast_mutex_lock(&caplock);
h323_set_capability(pvt->capability, pvt->dtmfmode);
@@ -1089,6 +1135,8 @@ struct rtp_info *external_rtp_create(unsigned call_reference, const char * token
return info;
}
+int progress(unsigned call_reference, const char *token, int inband);
+
/**
* Call-back function passing remote ip/port information from H.323 to asterisk
*
@@ -1110,6 +1158,10 @@ void setup_rtp_connection(unsigned call_reference, const char *remoteIp, int rem
them.sin_addr.s_addr = inet_addr(remoteIp);
them.sin_port = htons(remotePort);
ast_rtp_set_peer(pvt->rtp, &them);
+
+ if (pvt->options.progress_audio) {
+ progress(call_reference, token, 1);
+ }
return;
}
@@ -1139,16 +1191,38 @@ void connection_made(unsigned call_reference, const char *token)
return;
}
+int progress(unsigned call_reference, const char *token, int inband)
+{
+ struct oh323_pvt *p;
+
+ ast_log(LOG_DEBUG, "Received ALERT/PROGRESS message for %s tones\n", (inband ? "inband" : "self-generated"));
+ p = find_call(call_reference, token);
+
+ if (!p) {
+ ast_log(LOG_ERROR, "Private structure not found in progress.\n");
+ return -1;
+ }
+ if (!p->owner) {
+ ast_log(LOG_ERROR, "No Asterisk channel associated with private structure.\n");
+ return -1;
+ }
+
+ ast_queue_control(p->owner, (inband ? AST_CONTROL_PROGRESS : AST_CONTROL_RINGING));
+
+ return 0;
+}
+
/**
* Call-back function for incoming calls
*
* Returns 1 on success
*/
-int setup_incoming_call(call_details_t cd)
+call_options_t *setup_incoming_call(call_details_t cd)
{
struct oh323_pvt *pvt = NULL;
struct oh323_user *user = NULL;
struct oh323_alias *alias = NULL;
+ call_options_t *call_options = NULL;
char iabuf[INET_ADDRSTRLEN];
/* allocate the call*/
@@ -1156,7 +1230,7 @@ int setup_incoming_call(call_details_t cd)
if (!pvt) {
ast_log(LOG_ERROR, "Unable to allocate private structure, this is bad.\n");
- return 0;
+ return NULL;
}
/* Populate the call details in the private structure */
@@ -1185,7 +1259,7 @@ int setup_incoming_call(call_details_t cd)
alias = find_alias(cd.call_dest_alias);
if (!alias) {
ast_log(LOG_ERROR, "Call for %s rejected, alias not found\n", cd.call_dest_alias);
- return 0;
+ return NULL;
}
strncpy(pvt->exten, alias->name, sizeof(pvt->exten) - 1);
strncpy(pvt->context, alias->context, sizeof(pvt->context) - 1);
@@ -1202,17 +1276,18 @@ int setup_incoming_call(call_details_t cd)
}
if (ast_strlen_zero(default_context)) {
ast_log(LOG_ERROR, "Call from '%s' rejected due to no default context\n", pvt->cd.call_source_aliases);
- return 0;
+ return NULL;
}
strncpy(pvt->context, default_context, sizeof(pvt->context) - 1);
ast_log(LOG_DEBUG, "Sending %s to context [%s]\n", cd.call_source_aliases, pvt->context);
+ memset(&pvt->options, 0, sizeof(pvt->options));
} else {
if (user->host) {
if (strcasecmp(cd.sourceIp, ast_inet_ntoa(iabuf, sizeof(iabuf), user->addr.sin_addr))){
if (ast_strlen_zero(user->context)) {
if (ast_strlen_zero(default_context)) {
ast_log(LOG_ERROR, "Call from '%s' rejected due to non-matching IP address (%s) and no default context\n", user->name, cd.sourceIp);
- return 0;
+ return NULL;
}
strncpy(pvt->context, default_context, sizeof(pvt->context) - 1);
} else {
@@ -1238,10 +1313,11 @@ int setup_incoming_call(call_details_t cd)
if (user->amaflags) {
pvt->amaflags = user->amaflags;
}
+ call_options = &user->options;
}
}
exit:
- return 1;
+ return call_options;
}
/**
@@ -1357,6 +1433,21 @@ void cleanup_connection(call_details_t cd)
return;
}
+void set_dtmf_payload(unsigned call_reference, const char *token, int payload)
+{
+ struct oh323_pvt *pvt = NULL;
+
+ pvt = find_call(call_reference, token);
+ if (!pvt) {
+ return;
+ }
+ ast_mutex_lock(&pvt->lock);
+ if (pvt->rtp) {
+ ast_rtp_set_rtpmap_type(pvt->rtp, payload, "audio", "telephone-event");
+ }
+ ast_mutex_unlock(&pvt->lock);
+}
+
static void *do_monitor(void *data)
{
int res;
@@ -1599,6 +1690,8 @@ int reload_config(void)
h323debug = 0;
dtmfmode = H323_DTMF_RFC2833;
memset(&bindaddr, 0, sizeof(bindaddr));
+ memset(&global_options, 0, sizeof(global_options));
+ global_options.dtmfcodec = 101;
v = ast_variable_browse(cfg, "general");
while(v) {
/* Create the interface list */
@@ -1667,14 +1760,18 @@ int reload_config(void)
ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value);
dtmfmode = H323_DTMF_RFC2833;
}
+ } else if (!strcasecmp(v->name, "dtmfcodec")) {
+ global_options.dtmfcodec = atoi(v->value);
} else if (!strcasecmp(v->name, "UserByAlias")) {
userbyalias = ast_true(v->value);
} else if (!strcasecmp(v->name, "bridge")) {
bridging = ast_true(v->value);
} else if (!strcasecmp(v->name, "noFastStart")) {
- noFastStart = ast_true(v->value);
+ global_options.noFastStart = ast_true(v->value);
} else if (!strcasecmp(v->name, "noH245Tunneling")) {
- noH245Tunneling = ast_true(v->value);
+ global_options.noH245Tunneling = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "noSilenceSuppression")) {
+ global_options.noSilenceSuppression = ast_true(v->value);
}
v = v->next;
}
@@ -1948,7 +2045,9 @@ int load_module()
chan_ringing,
connection_made,
send_digit,
- answer_call);
+ answer_call,
+ progress,
+ set_dtmf_payload);
/* start the h.323 listener */
if (h323_start_listener(h323_signalling_port, bindaddr)) {
ast_log(LOG_ERROR, "Unable to create H323 listener.\n");