[asterisk-commits] mjordan: tag 10.2.0-rc2 r354885 - in /tags/10.2.0-rc2: ./ apps/ channels/ inc...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Feb 10 13:46:18 CST 2012
Author: mjordan
Date: Fri Feb 10 13:46:14 2012
New Revision: 354885
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=354885
Log:
Commit r353397,354000,353916,354496,354543,354548 for 10.2.0-rc2
Removed:
tags/10.2.0-rc2/asterisk-10.2.0-rc1-summary.html
tags/10.2.0-rc2/asterisk-10.2.0-rc1-summary.txt
Modified:
tags/10.2.0-rc2/ (props changed)
tags/10.2.0-rc2/.version
tags/10.2.0-rc2/ChangeLog
tags/10.2.0-rc2/apps/app_parkandannounce.c
tags/10.2.0-rc2/channels/chan_agent.c
tags/10.2.0-rc2/channels/chan_sip.c
tags/10.2.0-rc2/include/asterisk/dnsmgr.h
tags/10.2.0-rc2/main/dnsmgr.c
Propchange: tags/10.2.0-rc2/
------------------------------------------------------------------------------
svn:mergeinfo = /branches/10:353372,353397,353916,354000,354496,354543,354548
Modified: tags/10.2.0-rc2/.version
URL: http://svnview.digium.com/svn/asterisk/tags/10.2.0-rc2/.version?view=diff&rev=354885&r1=354884&r2=354885
==============================================================================
--- tags/10.2.0-rc2/.version (original)
+++ tags/10.2.0-rc2/.version Fri Feb 10 13:46:14 2012
@@ -1,1 +1,1 @@
-10.2.0-rc1
+10.2.0-rc2
Modified: tags/10.2.0-rc2/ChangeLog
URL: http://svnview.digium.com/svn/asterisk/tags/10.2.0-rc2/ChangeLog?view=diff&rev=354885&r1=354884&r2=354885
==============================================================================
--- tags/10.2.0-rc2/ChangeLog (original)
+++ tags/10.2.0-rc2/ChangeLog Fri Feb 10 13:46:14 2012
@@ -1,3 +1,60 @@
+2012-02-10 Asterisk Development Team <asteriskteam at digium.com>
+
+ * Asterisk 10.2.0-rc2 Released.
+
+ * channels/chan_sip.c: Fix SIP INFO DTMF handling for non-numeric
+ codes. In ASTERISK-18924, SIP INFO DTMF handling was changed to
+ account for both lowercase alphatbetic DTMF events, as well as
+ uppercase alphabetic DTMF events. When this occurred, the comparison
+ of the character buffer containing the event code was changed such
+ that the buffer was first compared against '0' and '9' to determine if
+ it was numeric. Unfortunately, since the first character in the
+ buffer will typically be '1' in the case of non-numeric event codes
+ (10-16), this caused those codes to be converted to a DTMF event of
+ '1'. This patch fixes that, and cleans up handling of both
+ application/dtmf-relay and application/dtmf content types.
+ Review: https://reviewboard.asterisk.org/r/1722/
+ (closes issue ASTERISK-19290) Reported by: Ira Emus
+ Tested by: mjordan
+
+ * apps/app_parkandannounce.c: Fix crash in ParkAndAnnounce from
+ uninitialized caller_id storage (closes issue ASTERISK-19311)
+ Reported by: tootai
+ Tested by: rmudgett
+
+ * channels/chan_agent.c: Fixes deadlocks occuring in chan_agent due to
+ r335976. Bad locking order was added to chan_agent to prevent
+ segfaults from having no locking in a patch by irroot. This patch
+ addresses the bad locking order by releasing locks before getting the
+ right locking order to stop deadlocks from occuring when doing
+ multiple interactions with agents. (closes issue ASTERISK-19285)
+ Reported by: Alex Villacis Lasso
+ Review: https://reviewboard.asterisk.org/r/1708/
+
+ * channels/chan_sip.c: Ensure entering T.38 passthrough does not cause
+ an infinite loop. After R340970 Asterisk was still polling the RTCP
+ file descriptor after RTCP is shut down and removed. If the
+ descriptor happened to have data ready when the removal occured then
+ Asterisk would go into an infinite loop trying to read data that it
+ can never actually access. This change disables the audio RTCP file
+ descriptor for the duration of the T.38 transaction. (closes issue
+ ASTERISK-18951) Reported-by: Kristijan Vrban
+
+ * channels/chan_sip.c,include/asterisk/dnsmgr.h,main/dnsmgr.c: Re-link
+ peers by IP when dnsmgr changes the IP Asterisk's dnsmgr currently
+ takes a pointer to an ast_sockaddr and updates it anytime an address
+ resolves to something different. There are a couple of issues with
+ this. First, the ast_sockaddr is usually the address of an ast_sockaddr
+ inside a refcounted struct and we never bump the refcount of those
+ structs when using dnsmgr. This makes it possible that a refresh could
+ happen after the destructor for that object is called (despite
+ ast_dnsmgr_release being called in that destructor). Second, the
+ module using dnsmgr cannot be aware of an address changing without
+ polling for it in the code. If an action needs to be taken on address
+ update (like re-linking a SIP peer in the peers_by_ip table), then
+ polling for this change negates many of the benefits of having dnsmgr
+ in the first place.
+
2012-02-01 Asterisk Development Team <asteriskteam at digium.com>
* Asterisk 10.2.0-rc1 Released.
Modified: tags/10.2.0-rc2/apps/app_parkandannounce.c
URL: http://svnview.digium.com/svn/asterisk/tags/10.2.0-rc2/apps/app_parkandannounce.c?view=diff&rev=354885&r1=354884&r2=354885
==============================================================================
--- tags/10.2.0-rc2/apps/app_parkandannounce.c (original)
+++ tags/10.2.0-rc2/apps/app_parkandannounce.c Fri Feb 10 13:46:14 2012
@@ -150,6 +150,7 @@
}
/* Save the CallerID because the masquerade turns chan into a ZOMBIE. */
+ ast_party_id_init(&caller_id);
ast_channel_lock(chan);
ast_party_id_copy(&caller_id, &chan->caller.id);
ast_channel_unlock(chan);
Modified: tags/10.2.0-rc2/channels/chan_agent.c
URL: http://svnview.digium.com/svn/asterisk/tags/10.2.0-rc2/channels/chan_agent.c?view=diff&rev=354885&r1=354884&r2=354885
==============================================================================
--- tags/10.2.0-rc2/channels/chan_agent.c (original)
+++ tags/10.2.0-rc2/channels/chan_agent.c Fri Feb 10 13:46:14 2012
@@ -1,7 +1,7 @@
/*
* Asterisk -- An open source telephony toolkit.
*
- * Copyright (C) 1999 - 2006, Digium, Inc.
+ * Copyright (C) 1999 - 2012, Digium, Inc.
*
* Mark Spencer <markster at digium.com>
*
@@ -374,6 +374,43 @@
};
/*!
+ * \brief Locks the owning channel for a LOCKED pvt while obeying locking order. The pvt
+ * must enter this function locked and will be returned locked, but this function will
+ * unlock the pvt for a short time, so it can't be used while expecting the pvt to remain
+ * static. If function returns a non NULL channel, it will need to be unlocked and
+ * unrefed once it is no longer needed.
+ *
+ * \param pvt Pointer to the LOCKED agent_pvt for which the owner is needed
+ * \ret locked channel which owns the pvt at the time of completion. NULL if not available.
+ */
+static struct ast_channel *agent_lock_owner(struct agent_pvt *pvt)
+{
+ struct ast_channel *owner;
+
+ for (;;) {
+ if (!pvt->owner) { /* No owner. Nothing to do. */
+ return NULL;
+ }
+
+ /* If we don't ref the owner, it could be killed when we unlock the pvt. */
+ owner = ast_channel_ref(pvt->owner);
+
+ /* Locking order requires us to lock channel, then pvt. */
+ ast_mutex_unlock(&pvt->lock);
+ ast_channel_lock(owner);
+ ast_mutex_lock(&pvt->lock);
+
+ /* Check if owner changed during pvt unlock period */
+ if (owner != pvt->owner) { /* Channel changed. Unref and do another pass. */
+ ast_channel_unlock(owner);
+ owner = ast_channel_unref(owner);
+ } else { /* Channel stayed the same. Return it. */
+ return owner;
+ }
+ }
+}
+
+/*!
* Adds an agent to the global list of agents.
*
* \param agent A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith"
@@ -553,7 +590,11 @@
struct ast_frame *f = NULL;
static struct ast_frame answer_frame = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
int cur_time = time(NULL);
+ struct ast_channel *owner;
+
ast_mutex_lock(&p->lock);
+ owner = agent_lock_owner(p);
+
CHECK_FORMATS(ast, p);
if (!p->start) {
p->start = cur_time;
@@ -583,13 +624,11 @@
int howlong = cur_time - p->start;
if (p->autologoff && (howlong >= p->autologoff)) {
ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
- if (p->owner || p->chan) {
- while (p->owner && ast_channel_trylock(p->owner)) {
- DEADLOCK_AVOIDANCE(&p->lock);
- }
- if (p->owner) {
- ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
- ast_channel_unlock(p->owner);
+ if (owner || p->chan) {
+ if (owner) {
+ ast_softhangup(owner, AST_SOFTHANGUP_EXPLICIT);
+ ast_channel_unlock(owner);
+ owner = ast_channel_unref(owner);
}
while (p->chan && ast_channel_trylock(p->chan)) {
@@ -651,6 +690,11 @@
}
}
+ if (owner) {
+ ast_channel_unlock(owner);
+ owner = ast_channel_unref(owner);
+ }
+
CLEANUP(ast,p);
if (p->chan && !p->chan->_bridge) {
if (strcasecmp(p->chan->tech->type, "Local")) {
@@ -888,6 +932,14 @@
static int agent_hangup(struct ast_channel *ast)
{
struct agent_pvt *p = ast->tech_pvt;
+ struct ast_channel *indicate_chan = NULL;
+ char *tmp_moh; /* moh buffer for indicating after unlocking p */
+
+ if (p->pending) {
+ AST_LIST_LOCK(&agents);
+ AST_LIST_REMOVE(&agents, p, list);
+ AST_LIST_UNLOCK(&agents);
+ }
ast_mutex_lock(&p->lock);
p->owner = NULL;
@@ -910,7 +962,7 @@
if (p->start && (ast->_state != AST_STATE_UP)) {
p->start = 0;
} else
- p->start = 0;
+ p->start = 0;
if (p->chan) {
p->chan->_bridge = NULL;
/* If they're dead, go ahead and hang up on the agent now */
@@ -919,14 +971,20 @@
ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
ast_channel_unlock(p->chan);
} else if (p->loginstart) {
- ast_channel_lock(p->chan);
- ast_indicate_data(p->chan, AST_CONTROL_HOLD,
- S_OR(p->moh, NULL),
- !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
- ast_channel_unlock(p->chan);
+ indicate_chan = ast_channel_ref(p->chan);
+ tmp_moh = ast_strdupa(p->moh);
}
}
ast_mutex_unlock(&p->lock);
+
+ if (indicate_chan) {
+ ast_channel_lock(indicate_chan);
+ ast_indicate_data(indicate_chan, AST_CONTROL_HOLD,
+ S_OR(tmp_moh, NULL),
+ !ast_strlen_zero(tmp_moh) ? strlen(tmp_moh) + 1 : 0);
+ ast_channel_unlock(indicate_chan);
+ indicate_chan = ast_channel_unref(indicate_chan);
+ }
/* Only register a device state change if the agent is still logged in */
if (!p->loginstart) {
@@ -935,11 +993,6 @@
ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
}
- if (p->pending) {
- AST_LIST_LOCK(&agents);
- AST_LIST_REMOVE(&agents, p, list);
- AST_LIST_UNLOCK(&agents);
- }
if (p->abouttograb) {
/* Let the "about to grab" thread know this isn't valid anymore, and let it
kill it later */
@@ -1492,6 +1545,8 @@
/*!
* Lists agents and their status to the Manager API.
* It is registered on load_module() and it gets called by the manager backend.
+ * This function locks both the pvt and the channel that owns it for a while, but
+ * does not keep these locks.
* \param s
* \param m
* \returns
@@ -1514,7 +1569,9 @@
astman_send_ack(s, m, "Agents will follow");
AST_LIST_LOCK(&agents);
AST_LIST_TRAVERSE(&agents, p, list) {
- ast_mutex_lock(&p->lock);
+ struct ast_channel *owner;
+ ast_mutex_lock(&p->lock);
+ owner = agent_lock_owner(p);
/* Status Values:
AGENT_LOGGEDOFF - Agent isn't logged in
@@ -1529,16 +1586,14 @@
if (p->chan) {
loginChan = ast_strdupa(p->chan->name);
- if (p->owner && p->owner->_bridge) {
+ if (owner && owner->_bridge) {
talkingto = S_COR(p->chan->caller.id.number.valid,
p->chan->caller.id.number.str, "n/a");
- ast_channel_lock(p->owner);
- if ((bridge = ast_bridged_channel(p->owner))) {
+ if ((bridge = ast_bridged_channel(owner))) {
talkingtoChan = ast_strdupa(bridge->name);
} else {
talkingtoChan = "n/a";
}
- ast_channel_unlock(p->owner);
status = "AGENT_ONCALL";
} else {
talkingto = "n/a";
@@ -1550,6 +1605,11 @@
talkingto = "n/a";
talkingtoChan = "n/a";
status = "AGENT_LOGGEDOFF";
+ }
+
+ if (owner) {
+ ast_channel_unlock(owner);
+ owner = ast_channel_unref(owner);
}
astman_append(s, "Event: Agents\r\n"
@@ -1583,14 +1643,14 @@
ret = 0;
if (p->owner || p->chan) {
if (!soft) {
+ struct ast_channel *owner;
ast_mutex_lock(&p->lock);
-
- while (p->owner && ast_channel_trylock(p->owner)) {
- DEADLOCK_AVOIDANCE(&p->lock);
- }
- if (p->owner) {
- ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
- ast_channel_unlock(p->owner);
+ owner = agent_lock_owner(p);
+
+ if (owner) {
+ ast_softhangup(owner, AST_SOFTHANGUP_EXPLICIT);
+ ast_channel_unlock(owner);
+ owner = ast_channel_unref(owner);
}
while (p->chan && ast_channel_trylock(p->chan)) {
@@ -1727,7 +1787,9 @@
AST_LIST_LOCK(&agents);
AST_LIST_TRAVERSE(&agents, p, list) {
+ struct ast_channel *owner;
ast_mutex_lock(&p->lock);
+ owner = agent_lock_owner(p);
if (p->pending) {
if (p->group)
ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group));
@@ -1740,10 +1802,11 @@
username[0] = '\0';
if (p->chan) {
snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
- if (p->owner && ast_bridged_channel(p->owner))
+ if (owner && ast_bridged_channel(owner)) {
snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
- else
+ } else {
strcpy(talkingto, " is idle");
+ }
online_agents++;
} else {
strcpy(location, "not logged in");
@@ -1756,6 +1819,11 @@
username, location, talkingto, music);
count_agents++;
}
+
+ if (owner) {
+ ast_channel_unlock(owner);
+ owner = ast_channel_unref(owner);
+ }
ast_mutex_unlock(&p->lock);
}
AST_LIST_UNLOCK(&agents);
@@ -1796,21 +1864,32 @@
AST_LIST_LOCK(&agents);
AST_LIST_TRAVERSE(&agents, p, list) {
+ struct ast_channel *owner;
+
agent_status = 0; /* reset it to offline */
ast_mutex_lock(&p->lock);
+ owner = agent_lock_owner(p);
+
if (!ast_strlen_zero(p->name))
snprintf(username, sizeof(username), "(%s) ", p->name);
else
username[0] = '\0';
if (p->chan) {
snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
- if (p->owner && ast_bridged_channel(p->owner))
- snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
- else
+ if (owner && ast_bridged_channel(owner)) {
+ snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(owner)->name);
+ } else {
strcpy(talkingto, " is idle");
+ }
agent_status = 1;
online_agents++;
}
+
+ if (owner) {
+ ast_channel_unlock(owner);
+ owner = ast_channel_unref(owner);
+ }
+
if (!ast_strlen_zero(p->moh))
snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
if (agent_status)
@@ -2386,12 +2465,16 @@
AST_LIST_LOCK(&agents);
AST_LIST_TRAVERSE(&agents, p, list) {
+ struct ast_channel *owner;
+
data_agent = ast_data_add_node(data_root, "agent");
if (!data_agent) {
continue;
}
ast_mutex_lock(&p->lock);
+ owner = agent_lock_owner(p);
+
if (!(p->pending)) {
ast_data_add_str(data_agent, "id", p->agent);
ast_data_add_structure(agent_pvt, data_agent, p);
@@ -2402,17 +2485,25 @@
if (!data_channel) {
ast_mutex_unlock(&p->lock);
ast_data_remove_node(data_root, data_agent);
+ if (owner) {
+ ast_channel_unlock(owner);
+ owner = ast_channel_unref(owner);
+ }
continue;
}
ast_channel_data_add_structure(data_channel, p->chan, 0);
- if (p->owner && ast_bridged_channel(p->owner)) {
+ if (owner && ast_bridged_channel(owner)) {
data_talkingto = ast_data_add_node(data_agent, "talkingto");
if (!data_talkingto) {
ast_mutex_unlock(&p->lock);
ast_data_remove_node(data_root, data_agent);
+ if (owner) {
+ ast_channel_unlock(owner);
+ owner = ast_channel_unref(owner);
+ }
continue;
}
- ast_channel_data_add_structure(data_talkingto, ast_bridged_channel(p->owner), 0);
+ ast_channel_data_add_structure(data_talkingto, ast_bridged_channel(owner), 0);
}
} else {
ast_data_add_node(data_agent, "talkingto");
@@ -2420,6 +2511,12 @@
}
ast_data_add_str(data_agent, "musiconhold", p->moh);
}
+
+ if (owner) {
+ ast_channel_unlock(owner);
+ owner = ast_channel_unref(owner);
+ }
+
ast_mutex_unlock(&p->lock);
/* if this agent doesn't match remove the added agent. */
Modified: tags/10.2.0-rc2/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/tags/10.2.0-rc2/channels/chan_sip.c?view=diff&rev=354885&r1=354884&r2=354885
==============================================================================
--- tags/10.2.0-rc2/channels/chan_sip.c (original)
+++ tags/10.2.0-rc2/channels/chan_sip.c Fri Feb 10 13:46:14 2012
@@ -2894,6 +2894,11 @@
if (which == SIP_PEERS_ALL || peer->the_mark) {
peer_sched_cleanup(peer);
+ if (peer->dnsmgr) {
+ ast_dnsmgr_release(peer->dnsmgr);
+ peer->dnsmgr = NULL;
+ sip_unref_peer(peer, "Release peer from dnsmgr");
+ }
return CMP_MATCH;
}
return 0;
@@ -4677,8 +4682,6 @@
ao2_t_ref(peer->auth, -1, "Removing peer authentication");
peer->auth = NULL;
}
- if (peer->dnsmgr)
- ast_dnsmgr_release(peer->dnsmgr);
if (peer->socket.tcptls_session) {
ao2_ref(peer->socket.tcptls_session, -1);
@@ -5418,6 +5421,12 @@
return 0;
}
+/*! \brief The default sip port for the given transport */
+static inline int default_sip_port(enum sip_transport type)
+{
+ return type == SIP_TRANSPORT_TLS ? STANDARD_TLS_PORT : STANDARD_SIP_PORT;
+}
+
/*! \brief create address structure from device name
* Or, if peer not found, find it in the global DNS
* returns TRUE (-1) on failure, FALSE on success */
@@ -5520,9 +5529,7 @@
}
if (!ast_sockaddr_port(&dialog->sa)) {
- ast_sockaddr_set_port(&dialog->sa,
- (dialog->socket.type == SIP_TRANSPORT_TLS) ?
- STANDARD_TLS_PORT : STANDARD_SIP_PORT);
+ ast_sockaddr_set_port(&dialog->sa, default_sip_port(dialog->socket.type));
}
ast_sockaddr_copy(&dialog->recv, &dialog->sa);
return 0;
@@ -5742,7 +5749,6 @@
ast_string_field_free_memory(reg);
ast_atomic_fetchadd_int(®objs, -1);
- ast_dnsmgr_release(reg->dnsmgr);
ast_free(reg);
}
@@ -5756,7 +5762,6 @@
AST_SCHED_DEL(sched, mwi->resub);
ast_string_field_free_memory(mwi);
- ast_dnsmgr_release(mwi->dnsmgr);
ast_free(mwi);
}
@@ -9423,6 +9428,10 @@
/* Ensure RTCP is enabled since it may be inactive
if we're coming back from a T.38 session */
ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_RTCP, 1);
+ /* Ensure audio RTCP reads are enabled */
+ if (p->owner) {
+ ast_channel_set_fd(p->owner, 1, ast_rtp_instance_fd(p->rtp, 1));
+ }
if (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO) {
ast_clear_flag(&p->flags[0], SIP_DTMF);
@@ -9439,6 +9448,10 @@
} else if (udptlportno > 0) {
if (debug)
ast_verbose("Got T.38 Re-invite without audio. Keeping RTP active during T.38 session.\n");
+ /* Prevent audio RTCP reads */
+ if (p->owner) {
+ ast_channel_set_fd(p->owner, 1, -1);
+ }
/* Silence RTCP while audio RTP is inactive */
ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_RTCP, 0);
} else {
@@ -12686,6 +12699,72 @@
return 0;
}
+static void on_dns_update_registry(struct ast_sockaddr *old, struct ast_sockaddr *new, void *data)
+{
+ struct sip_registry *reg = data;
+ const char *old_str;
+
+ /* This shouldn't happen, but just in case */
+ if (ast_sockaddr_isnull(new)) {
+ ast_debug(1, "Empty sockaddr change...ignoring!\n");
+ return;
+ }
+
+ if (!ast_sockaddr_port(new)) {
+ ast_sockaddr_set_port(new, reg->portno);
+ }
+
+ old_str = ast_strdupa(ast_sockaddr_stringify(old));
+
+ ast_debug(1, "Changing registry %s from %s to %s\n", S_OR(reg->peername, reg->hostname), old_str, ast_sockaddr_stringify(new));
+ ast_sockaddr_copy(®->us, new);
+}
+
+static void on_dns_update_peer(struct ast_sockaddr *old, struct ast_sockaddr *new, void *data)
+{
+ struct sip_peer *peer = data;
+ const char *old_str;
+
+ /* This shouldn't happen, but just in case */
+ if (ast_sockaddr_isnull(new)) {
+ ast_debug(1, "Empty sockaddr change...ignoring!\n");
+ return;
+ }
+
+ if (!ast_sockaddr_isnull(&peer->addr)) {
+ ao2_unlink(peers_by_ip, peer);
+ }
+
+ if (!ast_sockaddr_port(new)) {
+ ast_sockaddr_set_port(new, default_sip_port(peer->socket.type));
+ }
+
+ old_str = ast_strdupa(ast_sockaddr_stringify(old));
+ ast_debug(1, "Changing peer %s address from %s to %s\n", peer->name, old_str, ast_sockaddr_stringify(new));
+
+ ao2_lock(peer);
+ ast_sockaddr_copy(&peer->addr, new);
+ ao2_unlock(peer);
+
+ ao2_link(peers_by_ip, peer);
+}
+
+static void on_dns_update_mwi(struct ast_sockaddr *old, struct ast_sockaddr *new, void *data)
+{
+ struct sip_subscription_mwi *mwi = data;
+ const char *old_str;
+
+ /* This shouldn't happen, but just in case */
+ if (ast_sockaddr_isnull(new)) {
+ ast_debug(1, "Empty sockaddr change...ignoring!\n");
+ return;
+ }
+
+ old_str = ast_strdupa(ast_sockaddr_stringify(old));
+ ast_debug(1, "Changing mwi %s from %s to %s\n", mwi->hostname, old_str, ast_sockaddr_stringify(new));
+ ast_sockaddr_copy(&mwi->us, new);
+}
+
/*! \brief Actually setup an MWI subscription or resubscribe */
static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi)
{
@@ -12695,7 +12774,11 @@
snprintf(transport, sizeof(transport), "_%s._%s", get_srv_service(mwi->transport), get_srv_protocol(mwi->transport));
mwi->us.ss.ss_family = get_address_family_filter(&bindaddr); /* Filter address family */
- ast_dnsmgr_lookup(mwi->hostname, &mwi->us, &mwi->dnsmgr, sip_cfg.srvlookup ? transport : NULL);
+ ASTOBJ_REF(mwi); /* Add a ref for storing the mwi on the dnsmgr for updates */
+ ast_dnsmgr_lookup_cb(mwi->hostname, &mwi->us, &mwi->dnsmgr, sip_cfg.srvlookup ? transport : NULL, on_dns_update_mwi, mwi);
+ if (!mwi->dnsmgr) {
+ ASTOBJ_UNREF(mwi, sip_subscribe_mwi_destroy); /* dnsmgr disabled, remove reference */
+ }
}
/* If we already have a subscription up simply send a resubscription */
@@ -13376,17 +13459,8 @@
}
if (r->dnsmgr) {
- struct sip_peer *peer;
/* If the registration has timed out, maybe the IP changed. Force a refresh. */
ast_dnsmgr_refresh(r->dnsmgr);
- /* If we are resolving a peer, we have to make sure the refreshed address gets copied */
- if ((peer = sip_find_peer(r->hostname, NULL, TRUE, FINDPEERS, FALSE, 0))) {
- ast_sockaddr_copy(&peer->addr, &r->us);
- if (r->portno) {
- ast_sockaddr_set_port(&peer->addr, r->portno);
- }
- peer = sip_unref_peer(peer, "unref after sip_find_peer");
- }
}
/* If the initial tranmission failed, we may not have an existing dialog,
@@ -13475,7 +13549,12 @@
* or peer NULL. Since we're only concerned with its existence, we're not going to
* bother getting a ref to the proxy*/
if (!obproxy_get(r->call, peer)) {
- ast_dnsmgr_lookup(peer ? peer->tohost : r->hostname, &r->us, &r->dnsmgr, sip_cfg.srvlookup ? transport : NULL);
+ registry_addref(r, "add reg ref for dnsmgr");
+ ast_dnsmgr_lookup_cb(peer ? peer->tohost : r->hostname, &r->us, &r->dnsmgr, sip_cfg.srvlookup ? transport : NULL, on_dns_update_registry, r);
+ if (!r->dnsmgr) {
+ /*dnsmgr refresh disabled, no reference added! */
+ registry_unref(r, "remove reg ref, dnsmgr disabled");
+ }
}
if (peer) {
peer = sip_unref_peer(peer, "removing peer ref for dnsmgr_lookup");
@@ -13508,18 +13587,21 @@
}
/* Use port number specified if no SRV record was found */
- if (!ast_sockaddr_port(&r->us) && r->portno) {
- ast_sockaddr_set_port(&r->us, r->portno);
- }
-
- /* It is possible that DNS is unavailable at the time the peer is created. Here, if
- * we've updated the address in the registry, we copy it to the peer so that
- * create_addr() can copy it to the dialog via create_addr_from_peer */
- if ((peer = sip_find_peer(r->hostname, NULL, TRUE, FINDPEERS, FALSE, 0))) {
- if (ast_sockaddr_isnull(&peer->addr) && !(ast_sockaddr_isnull(&r->us))) {
- ast_sockaddr_copy(&peer->addr, &r->us);
- }
- peer = sip_unref_peer(peer, "unref after sip_find_peer");
+ if (!ast_sockaddr_isnull(&r->us)) {
+ if (!ast_sockaddr_port(&r->us) && r->portno) {
+ ast_sockaddr_set_port(&r->us, r->portno);
+ }
+
+ /* It is possible that DNS was unavailable at the time the peer was created.
+ * Here, if we've updated the address in the registry via manually calling
+ * ast_dnsmgr_lookup_cb() above, then we call the same function that dnsmgr would
+ * call if it was updating a peer's address */
+ if ((peer = sip_find_peer(S_OR(r->peername, r->hostname), NULL, TRUE, FINDPEERS, FALSE, 0))) {
+ if (ast_sockaddr_cmp(&peer->addr, &r->us)) {
+ on_dns_update_peer(&peer->addr, &r->us, peer);
+ }
+ peer = sip_unref_peer(peer, "unref after sip_find_peer");
+ }
}
/* Find address to hostname */
@@ -14357,9 +14439,7 @@
peer->portinuri = ast_sockaddr_port(&testsa) ? TRUE : FALSE;
if (!ast_sockaddr_port(&testsa)) {
- ast_sockaddr_set_port(&testsa,
- transport_type == SIP_TRANSPORT_TLS ?
- STANDARD_TLS_PORT : STANDARD_SIP_PORT);
+ ast_sockaddr_set_port(&testsa, default_sip_port(transport_type));
}
ast_sockaddr_copy(&peer->addr, &testsa);
@@ -19223,7 +19303,8 @@
/* Need to check the media/type */
if (!strcasecmp(c, "application/dtmf-relay") ||
- !strcasecmp(c, "application/vnd.nortelnetworks.digits")) {
+ !strcasecmp(c, "application/vnd.nortelnetworks.digits") ||
+ !strcasecmp(c, "application/dtmf")) {
unsigned int duration = 0;
if (!p->owner) { /* not a PBX call */
@@ -19232,44 +19313,55 @@
return;
}
- /* Try getting the "signal=" part */
- if (ast_strlen_zero(c = get_body(req, "Signal", '=')) && ast_strlen_zero(c = get_body(req, "d", '='))) {
- ast_log(LOG_WARNING, "Unable to retrieve DTMF signal from INFO message from %s\n", p->callid);
- transmit_response(p, "200 OK", req); /* Should return error */
- return;
+ /* If dtmf-relay or vnd.nortelnetworks.digits, parse the signal and duration;
+ * otherwise use the body as the signal */
+ if (strcasecmp(c, "application/dtmf")) {
+ const char *msg_body;
+
+ if ( ast_strlen_zero(msg_body = get_body(req, "Signal", '='))
+ && ast_strlen_zero(msg_body = get_body(req, "d", '='))) {
+ ast_log(LOG_WARNING, "Unable to retrieve DTMF signal for INFO message on "
+ "call %s\n", p->callid);
+ transmit_response(p, "200 OK", req);
+ return;
+ }
+ ast_copy_string(buf, msg_body, sizeof(buf));
+
+ if (!ast_strlen_zero((msg_body = get_body(req, "Duration", '=')))) {
+ sscanf(msg_body, "%30u", &duration);
+ }
} else {
- ast_copy_string(buf, c, sizeof(buf));
- }
-
- if (!ast_strlen_zero((c = get_body(req, "Duration", '=')))) {
- duration = atoi(c);
- }
- if (!duration) {
- duration = 100; /* 100 ms */
- }
-
-
+ /* Type is application/dtmf, simply use what's in the message body */
+ get_msg_text(buf, sizeof(buf), req);
+ }
+
+ /* An empty message body requires us to send a 200 OK */
if (ast_strlen_zero(buf)) {
transmit_response(p, "200 OK", req);
return;
}
- if ('0' <= buf[0] && buf[0] <= '9') {
- event = buf[0] - '0';
- } else if (buf[0] == '*') {
+ if (!duration) {
+ duration = 100; /* 100 ms */
+ }
+
+ if (buf[0] == '*') {
event = 10;
} else if (buf[0] == '#') {
event = 11;
+ } else if (buf[0] == '!') {
+ event = 16;
} else if ('A' <= buf[0] && buf[0] <= 'D') {
event = 12 + buf[0] - 'A';
} else if ('a' <= buf[0] && buf[0] <= 'd') {
event = 12 + buf[0] - 'a';
- } else if (buf[0] == '!') {
- event = 16;
- } else {
- /* Unknown digit */
- event = 0;
- }
+ } else if ((sscanf(buf, "%30u", &event) != 1) || event > 16) {
+ ast_log(AST_LOG_WARNING, "Unable to convert DTMF event signal code to a valid "
+ "value for INFO message on call %s\n", p->callid);
+ transmit_response(p, "200 OK", req);
+ return;
+ }
+
if (event == 16) {
/* send a FLASH event */
struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_FLASH, } };
@@ -19286,7 +19378,7 @@
f.subclass.integer = '*';
} else if (event == 11) {
f.subclass.integer = '#';
- } else if (event < 16) {
+ } else {
f.subclass.integer = 'A' + (event - 12);
}
f.len = duration;
@@ -19297,55 +19389,6 @@
}
transmit_response(p, "200 OK", req);
return;
- } else if (!strcasecmp(c, "application/dtmf")) {
- /*! \todo Note: Doesn't read the duration of the DTMF. Should be fixed. */
- unsigned int duration = 0;
-
- if (!p->owner) { /* not a PBX call */
- transmit_response(p, "481 Call leg/transaction does not exist", req);
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- return;
- }
-
- get_msg_text(buf, sizeof(buf), req);
- duration = 100; /* 100 ms */
-
- if (ast_strlen_zero(buf)) {
- transmit_response(p, "200 OK", req);
- return;
- }
- event = atoi(buf);
- if (event == 16) {
- /* send a FLASH event */
- struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_FLASH }, };
- ast_queue_frame(p->owner, &f);
- if (sipdebug) {
- ast_verbose("* DTMF-relay event received: FLASH\n");
- }
- } else {
- /* send a DTMF event */
- struct ast_frame f = { AST_FRAME_DTMF, };
- if (event < 10) {
- f.subclass.integer = '0' + event;
- } else if (event == 10) {
- f.subclass.integer = '*';
- } else if (event == 11) {
- f.subclass.integer = '#';
- } else if (event < 16) {
- f.subclass.integer = 'A' + (event - 12);
- } else {
- /* Unknown digit. */
- f.subclass.integer = '0';
- }
- f.len = duration;
- ast_queue_frame(p->owner, &f);
- if (sipdebug) {
- ast_verbose("* DTMF-relay event received: %c\n", (int) f.subclass.integer);
- }
- }
- transmit_response(p, "200 OK", req);
- return;
-
} else if (!strcasecmp(c, "application/media_control+xml")) {
/* Eh, we'll just assume it's a fast picture update for now */
if (p->owner) {
@@ -28550,10 +28593,16 @@
snprintf(transport, sizeof(transport), "_%s._%s", get_srv_service(peer->socket.type), get_srv_protocol(peer->socket.type));
peer->addr.ss.ss_family = get_address_family_filter(&bindaddr); /* Filter address family */
- if (ast_dnsmgr_lookup(_srvlookup, &peer->addr, &peer->dnsmgr, sip_cfg.srvlookup && !peer->portinuri ? transport : NULL)) {
+ if (ast_dnsmgr_lookup_cb(_srvlookup, &peer->addr, &peer->dnsmgr, sip_cfg.srvlookup && !peer->portinuri ? transport : NULL,
+ on_dns_update_peer, sip_ref_peer(peer, "Store peer on dnsmgr"))) {
ast_log(LOG_ERROR, "srvlookup failed for host: %s, on peer %s, removing peer\n", _srvlookup, peer->name);
+ sip_unref_peer(peer, "dnsmgr lookup failed, getting rid of peer dnsmgr ref");
sip_unref_peer(peer, "getting rid of a peer pointer");
return NULL;
+ }
+ if (!peer->dnsmgr) {
+ /* dnsmgr refresh disabeld, release reference */
+ sip_unref_peer(peer, "dnsmgr disabled, unref peer");
}
ast_string_field_set(peer, tohost, srvlookup);
@@ -28686,7 +28735,7 @@
/* First, destroy all outstanding registry calls */
/* This is needed, since otherwise active registry entries will not be destroyed */
ASTOBJ_CONTAINER_TRAVERSE(®l, 1, do { /* regl is locked */
- ASTOBJ_RDLOCK(iterator); /* now regl is locked, and the object is also locked */
+ ASTOBJ_WRLOCK(iterator); /* now regl is locked, and the object is also locked */
if (iterator->call) {
ast_debug(3, "Destroying active SIP dialog for registry %s@%s\n", iterator->username, iterator->hostname);
/* This will also remove references to the registry */
@@ -28698,6 +28747,11 @@
}
if (iterator->timeout > -1) {
AST_SCHED_DEL_UNREF(sched, iterator->timeout, registry_unref(iterator, "reg ptr unref from reload config"));
+ }
+ if (iterator->dnsmgr) {
+ ast_dnsmgr_release(iterator->dnsmgr);
+ iterator->dnsmgr = NULL;
+ registry_unref(iterator, "reg ptr unref from dnsmgr");
}
ASTOBJ_UNLOCK(iterator);
} while(0));
@@ -31344,6 +31398,16 @@
cleanup_all_regs();
ASTOBJ_CONTAINER_DESTROYALL(®l, sip_registry_destroy);
ASTOBJ_CONTAINER_DESTROY(®l);
+
+ ASTOBJ_CONTAINER_TRAVERSE(&submwil, 1, do {
+ ASTOBJ_WRLOCK(iterator);
+ if (iterator->dnsmgr) {
+ ast_dnsmgr_release(iterator->dnsmgr);
+ iterator->dnsmgr = NULL;
+ ASTOBJ_UNREF(iterator, sip_subscribe_mwi_destroy);
+ }
+ ASTOBJ_UNLOCK(iterator);
+ } while(0));
ASTOBJ_CONTAINER_DESTROYALL(&submwil, sip_subscribe_mwi_destroy);
ASTOBJ_CONTAINER_DESTROY(&submwil);
Modified: tags/10.2.0-rc2/include/asterisk/dnsmgr.h
URL: http://svnview.digium.com/svn/asterisk/tags/10.2.0-rc2/include/asterisk/dnsmgr.h?view=diff&rev=354885&r1=354884&r2=354885
==============================================================================
--- tags/10.2.0-rc2/include/asterisk/dnsmgr.h (original)
+++ tags/10.2.0-rc2/include/asterisk/dnsmgr.h Fri Feb 10 13:46:14 2012
@@ -36,6 +36,8 @@
* This is an opaque type.
*/
struct ast_dnsmgr_entry;
+
+typedef void (*dns_update_func)(struct ast_sockaddr *old_addr, struct ast_sockaddr *new_addr, void *data);
/*!
* \brief Allocate a new DNS manager entry
@@ -105,6 +107,31 @@
int ast_dnsmgr_lookup(const char *name, struct ast_sockaddr *result, struct ast_dnsmgr_entry **dnsmgr, const char *service);
/*!
+ * \brief Allocate and initialize a DNS manager entry, with update callback
+ *
+ * \param name the hostname
+ * \param result The addr which is intended to be updated in the update callback when DNS manager calls it on refresh.
+ * The address family is used as an input parameter to filter the returned addresses.
+ * If it is 0, both IPv4 and IPv6 addresses can be returned.
+ * \param dnsmgr Where to store the allocate DNS manager entry
+ * \param service
+ * \param func The update callback function
+ * The update callback will be called when DNS manager detects that an IP address has been changed.
+ * Instead of updating the addr itself, DNS manager will call this callback function with the old
+ * and new addresses. It is the responsibility of the callback to perform any updates
+ * \param data A pointer to data that will be passed through to the callback function
+ *
+ * \note
+ * This function allocates a new DNS manager entry object, and fills it with
+ * the provided hostname and IP address. This function _does_ force an initial
+ * lookup, so it may block for some period of time.
+ *
+ * \retval 0 success
+ * \retval non-zero failure
+ */
+int ast_dnsmgr_lookup_cb(const char *name, struct ast_sockaddr *result, struct ast_dnsmgr_entry **dnsmgr, const char *service, dns_update_func func, void *data);
+
+/*!
* \brief Force a refresh of a dnsmgr entry
*
* \retval non-zero if the result is different than the previous result
Modified: tags/10.2.0-rc2/main/dnsmgr.c
URL: http://svnview.digium.com/svn/asterisk/tags/10.2.0-rc2/main/dnsmgr.c?view=diff&rev=354885&r1=354884&r2=354885
==============================================================================
--- tags/10.2.0-rc2/main/dnsmgr.c (original)
+++ tags/10.2.0-rc2/main/dnsmgr.c Fri Feb 10 13:46:14 2012
@@ -58,6 +58,10 @@
unsigned int family;
/*! Set to 1 if the entry changes */
unsigned int changed:1;
+ /*! Data to pass back to update_func */
+ void *data;
+ /*! The callback function to execute on address update */
+ dns_update_func update_func;
ast_mutex_t lock;
AST_RWLIST_ENTRY(ast_dnsmgr_entry) list;
/*! just 1 here, but we use calloc to allocate the correct size */
@@ -129,7 +133,7 @@
ast_free(entry);
}
-int ast_dnsmgr_lookup(const char *name, struct ast_sockaddr *result, struct ast_dnsmgr_entry **dnsmgr, const char *service)
+static int internal_dnsmgr_lookup(const char *name, struct ast_sockaddr *result, struct ast_dnsmgr_entry **dnsmgr, const char *service, dns_update_func func, void *data)
{
unsigned int family;
@@ -164,7 +168,19 @@
ast_verb(3, "adding dns manager for '%s'\n", name);
*dnsmgr = ast_dnsmgr_get_family(name, result, service, family);
+ (*dnsmgr)->update_func = func;
+ (*dnsmgr)->data = data;
return !*dnsmgr;
+}
+
+int ast_dnsmgr_lookup(const char *name, struct ast_sockaddr *result, struct ast_dnsmgr_entry **dnsmgr, const char *service)
+{
+ return internal_dnsmgr_lookup(name, result, dnsmgr, service, NULL, NULL);
+}
+
+int ast_dnsmgr_lookup_cb(const char *name, struct ast_sockaddr *result, struct ast_dnsmgr_entry **dnsmgr, const char *service, dns_update_func func, void *data)
+{
+ return internal_dnsmgr_lookup(name, result, dnsmgr, service, func, data);
}
/*
@@ -186,16 +202,19 @@
if (!ast_sockaddr_port(&tmp)) {
ast_sockaddr_set_port(&tmp, ast_sockaddr_port(entry->result));
}
-
if (ast_sockaddr_cmp(&tmp, entry->result)) {
const char *old_addr = ast_strdupa(ast_sockaddr_stringify(entry->result));
const char *new_addr = ast_strdupa(ast_sockaddr_stringify(&tmp));
- ast_log(LOG_NOTICE, "dnssrv: host '%s' changed from %s to %s\n",
- entry->name, old_addr, new_addr);
-
- ast_sockaddr_copy(entry->result, &tmp);
- changed = entry->changed = 1;
+ if (entry->update_func) {
+ entry->update_func(entry->result, &tmp, entry->data);
+ } else {
+ ast_log(LOG_NOTICE, "dnssrv: host '%s' changed from %s to %s\n",
+ entry->name, old_addr, new_addr);
+
+ ast_sockaddr_copy(entry->result, &tmp);
+ changed = entry->changed = 1;
+ }
}
}
More information about the asterisk-commits
mailing list