Compare commits

...

21 Commits

Author SHA1 Message Date
Asterisk Autobuilder
e7a8f691b1 Importing release summary for 10.2.1 release.
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/10.2.1@359786 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-03-15 20:21:44 +00:00
Asterisk Autobuilder
41be81853a Merge 359694,359707 for 10.2.1
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/10.2.1@359771 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-03-15 20:11:44 +00:00
Asterisk Autobuilder
a60c429e3b Create 10.2.1 tag
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/10.2.1@359769 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-03-15 20:04:12 +00:00
Asterisk Autobuilder
6354f024fc Importing release summary for 10.2.0 release.
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/10.2.0@358213 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-03-05 18:04:12 +00:00
Asterisk Autobuilder
8ead31fa5f Update ChangeLog, .version
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/10.2.0@358212 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-03-05 18:00:51 +00:00
Asterisk Autobuilder
af77390661 Create tag for 10.2.0
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/10.2.0@358211 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-03-05 17:56:43 +00:00
Asterisk Autobuilder
9b0cbc077d Importing release summary for 10.2.0-rc4 release.
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/10.2.0-rc4@357739 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-03-01 22:25:45 +00:00
Matthew Jordan
b5271f6544 Merge 357667, update ChangeLog and .version
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/10.2.0-rc4@357730 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-03-01 22:21:37 +00:00
Matthew Jordan
27f375d116 Create tag for 10.2.0-rc4
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/10.2.0-rc4@357718 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-03-01 21:46:47 +00:00
Asterisk Autobuilder
1a5f0f6020 Importing release summary for 10.2.0-rc3 release.
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/10.2.0-rc3@357270 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-02-28 18:07:21 +00:00
Matthew Jordan
33935737b2 Updated ChangeLog slightly
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/10.2.0-rc3@357269 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-02-28 18:06:35 +00:00
Matthew Jordan
fd251c280d Updates for 10.2.0-rc3
Updated:
1) .version
2) ChangeLog
3) Removed old summaries
4) Merged r355733, r356476, r357095


git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/10.2.0-rc3@357265 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-02-28 17:57:25 +00:00
Matthew Jordan
027ae68683 Create 10.2.0-rc3
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/10.2.0-rc3@357262 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-02-28 17:24:00 +00:00
Asterisk Autobuilder
2a7e2eda0d Importing release summary for 10.2.0-rc2 release.
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/10.2.0-rc2@354887 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-02-10 19:51:04 +00:00
Matthew Jordan
9c42adbb61 Commit r353397,354000,353916,354496,354543,354548 for 10.2.0-rc2
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/10.2.0-rc2@354885 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-02-10 19:46:14 +00:00
Matthew Jordan
429160dea3 Create 10.2.0-rc2 tag
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/10.2.0-rc2@354883 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-02-10 19:21:35 +00:00
Asterisk Autobuilder
1c5231a6d7 Updated ChangeLog with date
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/10.2.0-rc1@353649 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-02-01 18:17:05 +00:00
Asterisk Autobuilder
04af418f6b Use autotagged externals
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/10.2.0-rc1@353316 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-01-30 14:17:17 +00:00
Asterisk Autobuilder
da01d9cd63 Importing release summary for 10.2.0-rc1 release.
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/10.2.0-rc1@353315 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-01-30 14:17:04 +00:00
Asterisk Autobuilder
3a7bdbe0fb Importing files for 10.2.0-rc1 release.
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/10.2.0-rc1@353314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-01-30 14:16:57 +00:00
Asterisk Autobuilder
3d38554f88 Creating tag for the release of asterisk-10.2.0-rc1
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/10.2.0-rc1@353313 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2012-01-30 14:15:54 +00:00
14 changed files with 22107 additions and 232 deletions

3
.lastclean Normal file
View File

@@ -0,0 +1,3 @@
39

1
.version Normal file
View File

@@ -0,0 +1 @@
10.2.1

21479
ChangeLog Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -78,7 +78,7 @@ static void milliwatt_release(struct ast_channel *chan, void *data)
static int milliwatt_generate(struct ast_channel *chan, void *data, int len, int samples)
{
unsigned char buf[AST_FRIENDLY_OFFSET + 640];
const int maxsamples = ARRAY_LEN(buf);
const int maxsamples = ARRAY_LEN(buf) - (AST_FRIENDLY_OFFSET / sizeof(buf[0]));
int i, *indexp = (int *) data;
struct ast_frame wf = {
.frametype = AST_FRAME_VOICE,

View File

@@ -150,6 +150,7 @@ static int parkandannounce_exec(struct ast_channel *chan, const char *data)
}
/* 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);

View File

@@ -0,0 +1,62 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /><title>Release Summary - asterisk-10.2.1</title></head>
<body>
<h1 align="center"><a name="top">Release Summary</a></h1>
<h3 align="center">asterisk-10.2.1</h3>
<h3 align="center">Date: 2012-03-15</h3>
<h3 align="center">&lt;asteriskteam@digium.com&gt;</h3>
<hr/>
<h2 align="center">Table of Contents</h2>
<ol>
<li><a href="#summary">Summary</a></li>
<li><a href="#contributors">Contributors</a></li>
<li><a href="#commits">Other Changes</a></li>
<li><a href="#diffstat">Diffstat</a></li>
</ol>
<hr/>
<a name="summary"><h2 align="center">Summary</h2></a>
<center><a href="#top">[Back to Top]</a></center><br/><p>This release has been made to address one or more security vulnerabilities that have been identified. A security advisory document has been published for each vulnerability that includes additional information. Users of versions of Asterisk that are affected are strongly encouraged to review the advisories and determine what action they should take to protect their systems from these issues.</p>
<p>Security Advisories: <a href="http://downloads.asterisk.org/pub/security/AST-2012-002.html">AST-2012-002</a>, <a href="http://downloads.asterisk.org/pub/security/AST-2012-003.html">AST-2012-003</a></p>
<p>The data in this summary reflects changes that have been made since the previous release, asterisk-10.2.0.</p>
<hr/>
<a name="contributors"><h2 align="center">Contributors</h2></a>
<center><a href="#top">[Back to Top]</a></center><br/><p>This table lists the people who have submitted code, those that have tested patches, as well as those that reported issues on the issue tracker that were resolved in this release. For coders, the number is how many of their patches (of any size) were committed into this release. For testers, the number is the number of times their name was listed as assisting with testing a patch. Finally, for reporters, the number is the number of issues that they reported that were closed by commits that went into this release.</p>
<table width="100%" border="0">
<tr>
<td width="33%"><h3>Coders</h3></td>
<td width="33%"><h3>Testers</h3></td>
<td width="33%"><h3>Reporters</h3></td>
</tr>
<tr valign="top">
<td>
2 bebuild<br/>
</td>
<td>
</td>
<td>
</td>
</tr>
</table>
<hr/>
<a name="commits"><h2 align="center">Commits Not Associated with an Issue</h2></a>
<center><a href="#top">[Back to Top]</a></center><br/><p>This is a list of all changes that went into this release that did not directly close an issue from the issue tracker. The commits may have been marked as being related to an issue. If that is the case, the issue numbers are listed here, as well.</p>
<table width="100%" border="1">
<tr><td><b>Revision</b></td><td><b>Author</b></td><td><b>Summary</b></td><td><b>Issues Referenced</b></td></tr><tr><td><a href="http://svn.digium.com/view/asterisk/tags/10.2.1?view=revision&revision=359769">359769</a></td><td>bebuild</td><td>Create 10.2.1 tag</td>
<td></td></tr><tr><td><a href="http://svn.digium.com/view/asterisk/tags/10.2.1?view=revision&revision=359771">359771</a></td><td>bebuild</td><td>Merge 359694,359707 for 10.2.1</td>
<td></td></tr></table>
<hr/>
<a name="diffstat"><h2 align="center">Diffstat Results</h2></a>
<center><a href="#top">[Back to Top]</a></center><br/><p>This is a summary of the changes to the source code that went into this release that was generated using the diffstat utility.</p>
<pre>
.version | 2
ChangeLog | 8
apps/app_milliwatt.c | 2
asterisk-10.2.0-summary.html | 325 -------------------------
asterisk-10.2.0-summary.txt | 540 -------------------------------------------
main/utils.c | 128 +++++-----
6 files changed, 75 insertions(+), 930 deletions(-)
</pre><br/>
<hr/>
</body>
</html>

View File

@@ -0,0 +1,91 @@
Release Summary
asterisk-10.2.1
Date: 2012-03-15
<asteriskteam@digium.com>
----------------------------------------------------------------------
Table of Contents
1. Summary
2. Contributors
3. Other Changes
4. Diffstat
----------------------------------------------------------------------
Summary
[Back to Top]
This release has been made to address one or more security vulnerabilities
that have been identified. A security advisory document has been published
for each vulnerability that includes additional information. Users of
versions of Asterisk that are affected are strongly encouraged to review
the advisories and determine what action they should take to protect their
systems from these issues.
Security Advisories: AST-2012-002, AST-2012-003
The data in this summary reflects changes that have been made since the
previous release, asterisk-10.2.0.
----------------------------------------------------------------------
Contributors
[Back to Top]
This table lists the people who have submitted code, those that have
tested patches, as well as those that reported issues on the issue tracker
that were resolved in this release. For coders, the number is how many of
their patches (of any size) were committed into this release. For testers,
the number is the number of times their name was listed as assisting with
testing a patch. Finally, for reporters, the number is the number of
issues that they reported that were closed by commits that went into this
release.
Coders Testers Reporters
2 bebuild
----------------------------------------------------------------------
Commits Not Associated with an Issue
[Back to Top]
This is a list of all changes that went into this release that did not
directly close an issue from the issue tracker. The commits may have been
marked as being related to an issue. If that is the case, the issue
numbers are listed here, as well.
+------------------------------------------------------------------------+
| Revision | Author | Summary | Issues Referenced |
|----------+---------+-------------------------------+-------------------|
| 359769 | bebuild | Create 10.2.1 tag | |
|----------+---------+-------------------------------+-------------------|
| 359771 | bebuild | Merge 359694,359707 for | |
| | | 10.2.1 | |
+------------------------------------------------------------------------+
----------------------------------------------------------------------
Diffstat Results
[Back to Top]
This is a summary of the changes to the source code that went into this
release that was generated using the diffstat utility.
.version | 2
ChangeLog | 8
apps/app_milliwatt.c | 2
asterisk-10.2.0-summary.html | 325 -------------------------
asterisk-10.2.0-summary.txt | 540 -------------------------------------------
main/utils.c | 128 +++++-----
6 files changed, 75 insertions(+), 930 deletions(-)
----------------------------------------------------------------------

View File

@@ -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@digium.com>
*
@@ -373,6 +373,43 @@ static struct ast_channel_tech agent_tech = {
.set_base_channel = agent_set_base_channel,
};
/*!
* \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.
*
@@ -553,7 +590,11 @@ static struct ast_frame *agent_read(struct ast_channel *ast)
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 @@ static struct ast_frame *agent_read(struct ast_channel *ast)
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 @@ static struct ast_frame *agent_read(struct ast_channel *ast)
}
}
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 @@ int agent_set_base_channel(struct ast_channel *chan, struct ast_channel *base)
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 @@ static int agent_hangup(struct ast_channel *ast)
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,15 +971,21 @@ static int agent_hangup(struct ast_channel *ast)
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) {
p->logincallerid[0] = '\0';
@@ -935,11 +993,6 @@ static int agent_hangup(struct ast_channel *ast)
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 @@ static force_inline int powerof(unsigned int d)
/*!
* 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 @@ static int action_agents(struct mansession *s, const struct message *m)
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 @@ static int action_agents(struct mansession *s, const struct message *m)
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";
@@ -1552,6 +1607,11 @@ static int action_agents(struct mansession *s, const struct message *m)
status = "AGENT_LOGGEDOFF";
}
if (owner) {
ast_channel_unlock(owner);
owner = ast_channel_unref(owner);
}
astman_append(s, "Event: Agents\r\n"
"Agent: %s\r\n"
"Name: %s\r\n"
@@ -1583,14 +1643,14 @@ static int agent_logoff(const char *agent, int soft)
ret = 0;
if (p->owner || p->chan) {
if (!soft) {
struct ast_channel *owner;
ast_mutex_lock(&p->lock);
owner = agent_lock_owner(p);
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) {
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 @@ static char *agents_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *
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 @@ static char *agents_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *
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 @@ static char *agents_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *
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 @@ static char *agents_show_online(struct ast_cli_entry *e, int cmd, struct ast_cli
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 @@ static int agents_data_provider_get(const struct ast_data_search *search,
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 @@ static int agents_data_provider_get(const struct ast_data_search *search,
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 @@ static int agents_data_provider_get(const struct ast_data_search *search,
}
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. */

View File

@@ -1293,7 +1293,7 @@ static int auto_congest(const void *arg);
static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *addr, const int intended_method);
static void free_old_route(struct sip_route *route);
static void list_route(struct sip_route *route);
static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards);
static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards, int resp);
static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sockaddr *addr,
struct sip_request *req, const char *uri);
static struct sip_pvt *get_sip_pvt_byid_locked(const char *callid, const char *totag, const char *fromtag);
@@ -2894,6 +2894,11 @@ static int match_and_cleanup_peer_sched(void *peerobj, void *arg, int flags)
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 @@ static void sip_destroy_peer(struct sip_peer *peer)
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 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
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 @@ static int create_addr(struct sip_pvt *dialog, const char *opeer, struct ast_soc
}
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 @@ static void sip_registry_destroy(struct sip_registry *reg)
ast_string_field_free_memory(reg);
ast_atomic_fetchadd_int(&regobjs, -1);
ast_dnsmgr_release(reg->dnsmgr);
ast_free(reg);
}
@@ -5756,7 +5762,6 @@ static void sip_subscribe_mwi_destroy(struct sip_subscription_mwi *mwi)
AST_SCHED_DEL(sched, mwi->resub);
ast_string_field_free_memory(mwi);
ast_dnsmgr_release(mwi->dnsmgr);
ast_free(mwi);
}
@@ -8115,7 +8120,7 @@ static void forked_invite_init(struct sip_request *req, const char *new_theirtag
ast_string_field_set(p, our_contact, original->our_contact);
ast_string_field_set(p, fullcontact, original->fullcontact);
parse_ok_contact(p, req);
build_route(p, req, 1);
build_route(p, req, 1, 0);
transmit_request(p, SIP_ACK, p->ocseq, XMIT_UNRELIABLE, TRUE);
transmit_request(p, SIP_BYE, 0, XMIT_RELIABLE, TRUE);
@@ -9423,6 +9428,10 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
/* 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 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
} 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 {
@@ -10581,7 +10594,15 @@ static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, in
snprintf(tmp, sizeof(tmp), "%d %s", seqno, sip_methods[sipmethod].text);
add_header(req, "Via", p->via);
if (p->route) {
/*
* Use the learned route set unless this is a CANCEL on an ACK for a non-2xx
* final response. For a CANCEL or ACK, we have to send to the same destination
* as the original INVITE.
*/
if (sipmethod == SIP_CANCEL ||
(sipmethod == SIP_ACK && (p->invitestate == INV_COMPLETED || p->invitestate == INV_CANCELLED))) {
set_destination(p, ast_strdupa(p->uri));
} else if (p->route) {
set_destination(p, p->route->hop);
add_route(req, is_strict ? p->route->next : p->route);
}
@@ -12686,6 +12707,72 @@ static int sip_subscribe_mwi_do(const void *data)
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(&reg->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 +12782,11 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi)
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 +13467,8 @@ static int sip_reg_timeout(const void *data)
}
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 +13557,12 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
* 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 +13595,21 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
}
/* 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);
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");
}
peer = sip_unref_peer(peer, "unref after sip_find_peer");
}
/* Find address to hostname */
@@ -13881,15 +13971,15 @@ static int transmit_request(struct sip_pvt *p, int sipmethod, int seqno, enum xm
{
struct sip_request resp;
if (sipmethod == SIP_ACK) {
p->invitestate = INV_CONFIRMED;
}
reqprep(&resp, p, sipmethod, seqno, newbranch);
if (sipmethod == SIP_CANCEL && p->answered_elsewhere) {
add_header(&resp, "Reason", "SIP;cause=200;text=\"Call completed elsewhere\"");
}
if (sipmethod == SIP_ACK) {
p->invitestate = INV_CONFIRMED;
}
return send_request(p, &resp, reliable, seqno ? seqno : p->ocseq);
}
@@ -14357,9 +14447,7 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
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);
@@ -14466,8 +14554,9 @@ static void list_route(struct sip_route *route)
}
}
/*! \brief Build route list from Record-Route header */
static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards)
/*! \brief Build route list from Record-Route header
\param resp the SIP response code or 0 for a request */
static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards, int resp)
{
struct sip_route *thishop, *head, *tail;
int start = 0;
@@ -14485,8 +14574,11 @@ static void build_route(struct sip_pvt *p, struct sip_request *req, int backward
p->route = NULL;
}
/* We only want to create the route set the first time this is called */
p->route_persistent = 1;
/* We only want to create the route set the first time this is called except
it is called from a provisional response.*/
if ((resp < 100) || (resp > 199)) {
p->route_persistent = 1;
}
/* Build a tailq, then assign it to p->route when done.
* If backwards, we add entries from the head so they end up
@@ -19223,7 +19315,8 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req)
/* 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 +19325,55 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req)
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));
/* Type is application/dtmf, simply use what's in the message body */
get_msg_text(buf, sizeof(buf), req);
}
if (!ast_strlen_zero((c = get_body(req, "Duration", '=')))) {
duration = atoi(c);
}
if (!duration) {
duration = 100; /* 100 ms */
}
/* 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,56 +19390,8 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req)
f.subclass.integer = '*';
} else if (event == 11) {
f.subclass.integer = '#';
} else if (event < 16) {
f.subclass.integer = 'A' + (event - 12);
}
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/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.subclass.integer = 'A' + (event - 12);
}
f.len = duration;
ast_queue_frame(p->owner, &f);
@@ -19345,7 +19401,6 @@ static void handle_request_info(struct sip_pvt *p, struct sip_request *req)
}
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) {
@@ -20524,7 +20579,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
* */
parse_ok_contact(p, req);
if (!reinvite) {
build_route(p, req, 1);
build_route(p, req, 1, resp);
}
if (!req->ignore && p->owner) {
if (get_rpid(p, req)) {
@@ -20574,7 +20629,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
* */
parse_ok_contact(p, req);
if (!reinvite) {
build_route(p, req, 1);
build_route(p, req, 1, resp);
}
if (!req->ignore && p->owner) {
struct ast_party_redirecting redirecting;
@@ -20600,7 +20655,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
* */
parse_ok_contact(p, req);
if (!reinvite) {
build_route(p, req, 1);
build_route(p, req, 1, resp);
}
if (!req->ignore && p->owner) {
if (get_rpid(p, req)) {
@@ -20700,7 +20755,7 @@ static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest
parse_ok_contact(p, req);
/* Save Record-Route for any later requests we make on this dialogue */
if (!reinvite)
build_route(p, req, 1);
build_route(p, req, 1, resp);
if(set_address_from_contact(p)) {
/* Bad contact - we don't know how to reach this device */
@@ -23266,7 +23321,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
*recount = 1;
/* Save Record-Route for any later requests we make on this dialogue */
build_route(p, req, 0);
build_route(p, req, 0, 0);
if (c) {
ast_party_redirecting_init(&redirecting);
@@ -25303,7 +25358,7 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req,
if (sipdebug)
ast_debug(4, "Initializing initreq for method %s - callid %s\n", sip_methods[req->method].text, p->callid);
check_via(p, req);
build_route(p, req, 0);
build_route(p, req, 0, 0);
} else if (req->debug && req->ignore)
ast_verbose("Ignoring this SUBSCRIBE request\n");
@@ -28550,11 +28605,17 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
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 +28747,7 @@ static void cleanup_all_regs(void)
/* First, destroy all outstanding registry calls */
/* This is needed, since otherwise active registry entries will not be destroyed */
ASTOBJ_CONTAINER_TRAVERSE(&regl, 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 */
@@ -28699,6 +28760,11 @@ static void cleanup_all_regs(void)
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 +31410,16 @@ static int unload_module(void)
cleanup_all_regs();
ASTOBJ_CONTAINER_DESTROYALL(&regl, sip_registry_destroy);
ASTOBJ_CONTAINER_DESTROY(&regl);
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);

View File

@@ -37,6 +37,8 @@ extern "C" {
*/
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
*
@@ -104,6 +106,31 @@ void ast_dnsmgr_release(struct ast_dnsmgr_entry *entry);
*/
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
*

View File

@@ -737,6 +737,7 @@ int ast_find_ourip(struct ast_sockaddr *ourip, const struct ast_sockaddr *bindad
{
char ourhost[MAXHOSTNAMELEN] = "";
struct ast_sockaddr root;
int res, port = ast_sockaddr_port(ourip);
/* just use the bind address if it is nonzero */
if (!ast_sockaddr_is_any(bindaddr)) {
@@ -749,6 +750,8 @@ int ast_find_ourip(struct ast_sockaddr *ourip, const struct ast_sockaddr *bindad
ast_log(LOG_WARNING, "Unable to get hostname\n");
} else {
if (resolve_first(ourip, ourhost, PARSE_PORT_FORBID, family) == 0) {
/* reset port since resolve_first wipes this out */
ast_sockaddr_set_port(ourip, port);
return 0;
}
}
@@ -756,8 +759,12 @@ int ast_find_ourip(struct ast_sockaddr *ourip, const struct ast_sockaddr *bindad
/* A.ROOT-SERVERS.NET. */
if (!resolve_first(&root, "A.ROOT-SERVERS.NET", PARSE_PORT_FORBID, 0) &&
!ast_ouraddrfor(&root, ourip)) {
/* reset port since resolve_first wipes this out */
ast_sockaddr_set_port(ourip, port);
return 0;
}
return get_local_address(ourip);
res = get_local_address(ourip);
ast_sockaddr_set_port(ourip, port);
return res;
}

View File

@@ -5544,6 +5544,16 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c
}
}
/*
* I seems strange to set the CallerID on an outgoing call leg
* to whom we are calling, but this function's callers are doing
* various Originate methods. This call leg goes to the local
* user. Once the local user answers, the dialplan needs to be
* able to access the CallerID from the CALLERID function as if
* the local user had placed this call.
*/
ast_set_callerid(chan, cid_num, cid_name, cid_num);
ast_set_flag(chan->cdr, AST_CDR_FLAG_ORIGINATED);
ast_party_connected_line_set_init(&connected, &chan->connected);
if (cid_num) {

View File

@@ -58,6 +58,10 @@ struct ast_dnsmgr_entry {
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 @@ void ast_dnsmgr_release(struct ast_dnsmgr_entry *entry)
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,9 +168,21 @@ int ast_dnsmgr_lookup(const char *name, struct ast_sockaddr *result, struct ast_
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);
}
/*
* Refresh a dnsmgr entry
*/
@@ -186,16 +202,19 @@ static int dnsmgr_refresh(struct ast_dnsmgr_entry *entry, int verbose)
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);
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;
ast_sockaddr_copy(entry->result, &tmp);
changed = entry->changed = 1;
}
}
}

View File

@@ -1989,10 +1989,29 @@ int ast_utils_init(void)
* pedantic arg can be set to nonzero if we need to do addition Digest check.
*/
int ast_parse_digest(const char *digest, struct ast_http_digest *d, int request, int pedantic) {
int i;
char *c, key[512], val[512];
char *c;
struct ast_str *str = ast_str_create(16);
/* table of recognised keywords, and places where they should be copied */
const struct x {
const char *key;
const ast_string_field *field;
} *i, keys[] = {
{ "username=", &d->username },
{ "realm=", &d->realm },
{ "nonce=", &d->nonce },
{ "uri=", &d->uri },
{ "domain=", &d->domain },
{ "response=", &d->response },
{ "cnonce=", &d->cnonce },
{ "opaque=", &d->opaque },
/* Special cases that cannot be directly copied */
{ "algorithm=", NULL },
{ "qop=", NULL },
{ "nc=", NULL },
{ NULL, 0 },
};
if (ast_strlen_zero(digest) || !d || !str) {
ast_free(str);
return -1;
@@ -2010,72 +2029,55 @@ int ast_parse_digest(const char *digest, struct ast_http_digest *d, int request,
c += strlen("Digest ");
/* lookup for keys/value pair */
while (*c && *(c = ast_skip_blanks(c))) {
while (c && *c && *(c = ast_skip_blanks(c))) {
/* find key */
i = 0;
while (*c && *c != '=' && *c != ',' && !isspace(*c)) {
key[i++] = *c++;
}
key[i] = '\0';
c = ast_skip_blanks(c);
if (*c == '=') {
c = ast_skip_blanks(++c);
i = 0;
if (*c == '\"') {
/* in quotes. Skip first and look for last */
c++;
while (*c && *c != '\"') {
if (*c == '\\' && c[1] != '\0') { /* unescape chars */
c++;
}
val[i++] = *c++;
}
for (i = keys; i->key != NULL; i++) {
char *src, *separator;
int unescape = 0;
if (strncasecmp(c, i->key, strlen(i->key)) != 0) {
continue;
}
/* Found. Skip keyword, take text in quotes or up to the separator. */
c += strlen(i->key);
if (*c == '"') {
src = ++c;
separator = "\"";
unescape = 1;
} else {
/* token */
while (*c && *c != ',' && !isspace(*c)) {
val[i++] = *c++;
src = c;
separator = ",";
}
strsep(&c, separator); /* clear separator and move ptr */
if (unescape) {
ast_unescape_c(src);
}
if (i->field) {
ast_string_field_ptr_set(d, i->field, src);
} else {
/* Special cases that require additional procesing */
if (!strcasecmp(i->key, "algorithm=")) {
if (strcasecmp(src, "MD5")) {
ast_log(LOG_WARNING, "Digest algorithm: \"%s\" not supported.\n", src);
ast_free(str);
return -1;
}
} else if (!strcasecmp(i->key, "qop=") && !strcasecmp(src, "auth")) {
d->qop = 1;
} else if (!strcasecmp(i->key, "nc=")) {
unsigned long u;
if (sscanf(src, "%30lx", &u) != 1) {
ast_log(LOG_WARNING, "Incorrect Digest nc value: \"%s\".\n", src);
ast_free(str);
return -1;
}
ast_string_field_set(d, nc, src);
}
}
val[i] = '\0';
break;
}
while (*c && *c != ',') {
c++;
}
if (*c) {
c++;
}
if (!strcasecmp(key, "username")) {
ast_string_field_set(d, username, val);
} else if (!strcasecmp(key, "realm")) {
ast_string_field_set(d, realm, val);
} else if (!strcasecmp(key, "nonce")) {
ast_string_field_set(d, nonce, val);
} else if (!strcasecmp(key, "uri")) {
ast_string_field_set(d, uri, val);
} else if (!strcasecmp(key, "domain")) {
ast_string_field_set(d, domain, val);
} else if (!strcasecmp(key, "response")) {
ast_string_field_set(d, response, val);
} else if (!strcasecmp(key, "algorithm")) {
if (strcasecmp(val, "MD5")) {
ast_log(LOG_WARNING, "Digest algorithm: \"%s\" not supported.\n", val);
return -1;
}
} else if (!strcasecmp(key, "cnonce")) {
ast_string_field_set(d, cnonce, val);
} else if (!strcasecmp(key, "opaque")) {
ast_string_field_set(d, opaque, val);
} else if (!strcasecmp(key, "qop") && !strcasecmp(val, "auth")) {
d->qop = 1;
} else if (!strcasecmp(key, "nc")) {
unsigned long u;
if (sscanf(val, "%30lx", &u) != 1) {
ast_log(LOG_WARNING, "Incorrect Digest nc value: \"%s\".\n", val);
return -1;
}
ast_string_field_set(d, nc, val);
if (i->key == NULL) { /* not found, try ',' */
strsep(&c, ",");
}
}
ast_free(str);