Compare commits
49 Commits
Author | SHA1 | Date |
---|---|---|
Asterisk Development Team | fc13cc2f59 | |
Asterisk Development Team | 95c35e1765 | |
Benjamin Keith Ford | 07001c3033 | |
George Joseph | a6bdc1268a | |
Ben Ford | 92499125e8 | |
Asterisk Development Team | 5ffe12b6ef | |
Joshua Colp | b3951ee5b5 | |
Asterisk Development Team | 6f7ff1297c | |
George Joseph | 3fb68578a2 | |
Kevin Harwell | 84e8364ce7 | |
Kevin Harwell | 5214acbd7f | |
George Joseph | 9cc9c0267b | |
Asterisk Development Team | 708cd4d4d7 | |
George Joseph | abcb8efdcd | |
George Joseph | 410ee33355 | |
Kevin Harwell | fb29778ae4 | |
Joshua Colp | ce7641c8e8 | |
Guido Falsi | e23ed0eff0 | |
George Joseph | e86fbd0ba7 | |
George Joseph | 5a856f640a | |
Joshua Colp | a60ffe0255 | |
Kevin Harwell | 2976625d42 | |
Kevin Harwell | c02cbeade8 | |
Asterisk Development Team | eec4ab633e | |
Joshua Colp | 03ca4a98dc | |
Alexei Gradinari | c961d3d9ad | |
Dan Cropp | 64a2eeef89 | |
George Joseph | fe6551f69b | |
Alexei Gradinari | 7591e0f3a4 | |
Sean Bright | fa7883c492 | |
George Joseph | 6113d21710 | |
Friendly Automation | 9936616290 | |
Kevin Harwell | a92f9f595b | |
George Joseph | b083537d84 | |
George Joseph | c4b6e3c1af | |
George Joseph | d567518086 | |
Joshua Colp | 37a49cc6d3 | |
George Joseph | 6d610a6b56 | |
Friendly Automation | 3fdb788f33 | |
George Joseph | 95b490fc2e | |
Kevin Harwell | 66b607db88 | |
Sean Bright | 40e3bdc50c | |
Joshua Colp | 02826c20f5 | |
George Joseph | a59fae9a4b | |
Torrey Searle | 6af55244a7 | |
Asterisk Development Team | 8b3fd0f564 | |
George Joseph | 7b3a612d69 | |
George Joseph | 2938679ff2 | |
George Joseph | 80d8dce6af |
|
@ -1,5 +1,5 @@
|
|||
[gerrit]
|
||||
defaultbranch=master
|
||||
defaultbranch=17
|
||||
#
|
||||
# Intentional padding to ensure it is possible to point a commit
|
||||
# to an alternative gerrit server/repository without breaking
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
40
|
131
CHANGES
131
CHANGES
|
@ -12,6 +12,137 @@
|
|||
===
|
||||
==============================================================================
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- New functionality introduced in Asterisk 17.0.0 --------------------------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Bridging
|
||||
------------------
|
||||
* The bridging core no longer uses the stasis cache for bridge
|
||||
snapshots. The latest bridge snapshot is now stored on the
|
||||
ast_bridge structure itself.
|
||||
|
||||
The following APIs are no longer available since the stasis cache
|
||||
is no longer used:
|
||||
ast_bridge_topic_cached()
|
||||
ast_bridge_topic_all_cached()
|
||||
|
||||
A topic pool is now used for individual bridge topics.
|
||||
|
||||
The ast_bridge_cache() function was removed since there's no
|
||||
longer a separate container of snapshots.
|
||||
|
||||
A new function "ast_bridges()" was created to retrieve the
|
||||
container of all bridges. Users formerly calling
|
||||
ast_bridge_cache() can use the new function to iterate over
|
||||
bridges and retrieve the latest snapshot directly from the
|
||||
bridge.
|
||||
|
||||
The ast_bridge_snapshot_get_latest() function was renamed to
|
||||
ast_bridge_get_snapshot_by_uniqueid().
|
||||
|
||||
A new function "ast_bridge_get_snapshot()" was created to retrieve
|
||||
the bridge snapshot directly from the bridge structure.
|
||||
|
||||
The ast_bridge_topic_all() function now returns a normal topic
|
||||
not a cached one so you can't use stasis cache functions on it
|
||||
either.
|
||||
|
||||
The ast_bridge_snapshot_type() stasis message now has the
|
||||
ast_bridge_snapshot_update structure as it's data. It contains
|
||||
the last snapshot and the new one.
|
||||
|
||||
Channels
|
||||
------------------
|
||||
* The core no longer uses the stasis cache for channels snapshots.
|
||||
The following APIs are no longer available:
|
||||
ast_channel_topic_cached()
|
||||
ast_channel_topic_all_cached()
|
||||
The ast_channel_cache_all() and ast_channel_cache_by_name() functions
|
||||
now returns an ao2_container of ast_channel_snapshots rather than a
|
||||
container of stasis_messages therefore you can't call stasis_cache
|
||||
functions on it.
|
||||
The ast_channel_topic_all() function now returns a normal topic,
|
||||
not a cached one so you can't use stasis cache functions on it either.
|
||||
The ast_channel_snapshot_type() stasis message now has the
|
||||
ast_channel_snapshot_update structure as it's data.
|
||||
ast_channel_snapshot_get_latest() still returns the latest snapshot.
|
||||
|
||||
chan_sip
|
||||
------------------
|
||||
* The chan_sip module is now deprecated, users should migrate to the
|
||||
replacement module chan_pjsip. See guides at the Asterisk Wiki:
|
||||
https://wiki.asterisk.org/wiki/x/tAHOAQ
|
||||
https://wiki.asterisk.org/wiki/x/hYCLAQ
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 16.0.0 to Asterisk 17.0.0 ------------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
AttendedTransfer
|
||||
------------------
|
||||
* A new application, this will queue up attended transfer to the given extension.
|
||||
|
||||
BlindTransfer
|
||||
------------------
|
||||
* A new application, this will redirect all channels currently
|
||||
bridged to the caller channel to the specified destination.
|
||||
|
||||
ConfBridge
|
||||
------------------
|
||||
* Add "average_all", "highest_all", and "lowest_all" values for
|
||||
the remb_behavior option. These values operate on a bridge
|
||||
level instead of a per-source level. This means that a single
|
||||
REMB value is calculated and sent to every sender, instead of
|
||||
a REMB value that is unique for the specific sender..
|
||||
|
||||
Dial
|
||||
------------------
|
||||
* Add RINGTIME and RINGTIME_MS variables containing respectively seconds and
|
||||
milliseconds between creation of the dialing channel and receiving the first
|
||||
RINGING signal
|
||||
|
||||
Add PROGRESSTIME and PROGRESSTIME_MS variables analogous to the above with respect to
|
||||
the PROGRESS signal. Shorter of these two times should be equivalent to
|
||||
the PDD (Post Dial Delay) value
|
||||
|
||||
Add DIALEDTIME_MS and ANSWEREDTIME_MS variables to get millisecond resolution
|
||||
versions of DIALEDTIME and ANSWEREDTIME
|
||||
|
||||
RTP/ICE
|
||||
------------------
|
||||
* You can now indicate that you'd like an ice_host_candidate's local address
|
||||
to be published as well as the mapped address. See the sample rtp.conf
|
||||
for more information.
|
||||
|
||||
ReadExten
|
||||
------------------
|
||||
* Add 'p' option to stop reading extension if user presses '#' key.
|
||||
|
||||
pbx_dundi
|
||||
------------------
|
||||
* The DUNDi PBX module now supports IPv4/IPv6 dual binding.
|
||||
|
||||
res_pjsip
|
||||
------------------
|
||||
* Added a new PJSIP global setting called norefersub.
|
||||
Default is true to keep support working as before.
|
||||
|
||||
res_pjsip_refer configures PJSIP norefersub capability accordingly.
|
||||
|
||||
Checks the PJSIP global setting value.
|
||||
If it is true (default) it adds the norefersub capability to PJSIP.
|
||||
If it is false (disabled) it does not add the norefersub capability
|
||||
to PJSIP.
|
||||
|
||||
This is useful for Cisco switches that do not follow RFC4488.
|
||||
|
||||
res_rtp_asterisk
|
||||
------------------
|
||||
* DTLS packets will now be fragmented according to the MTU as set in rtp.conf. This
|
||||
allows larger certificates to be used for the DTLS negotiation. By default this value
|
||||
is 1200.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 16.2.0 to Asterisk 16.3.0 ----------
|
||||
------------------------------------------------------------------------------
|
||||
|
|
122
UPGRADE.txt
122
UPGRADE.txt
|
@ -18,6 +18,128 @@
|
|||
===
|
||||
===========================================================
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 17.0.0 to Asterisk 17.0.1 ------------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
AMI
|
||||
------------------
|
||||
* The AMI Originate action, which optionally takes a dialplan application as
|
||||
an argument, no longer accepts "Originate" as the application due to
|
||||
security concerns.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- New functionality introduced in Asterisk 17.0.0 --------------------------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Applications
|
||||
------------------
|
||||
* The JabberStatus application, deprecated in Asterisk 12, has been removed.
|
||||
|
||||
Bridging
|
||||
------------------
|
||||
* The bridging core no longer uses the stasis cache for bridge
|
||||
snapshots. The latest bridge snapshot is now stored on the
|
||||
ast_bridge structure itself.
|
||||
|
||||
The following APIs are no longer available since the stasis cache
|
||||
is no longer used:
|
||||
ast_bridge_topic_cached()
|
||||
ast_bridge_topic_all_cached()
|
||||
|
||||
A topic pool is now used for individual bridge topics.
|
||||
|
||||
The ast_bridge_cache() function was removed since there's no
|
||||
longer a separate container of snapshots.
|
||||
|
||||
A new function "ast_bridges()" was created to retrieve the
|
||||
container of all bridges. Users formerly calling
|
||||
ast_bridge_cache() can use the new function to iterate over
|
||||
bridges and retrieve the latest snapshot directly from the
|
||||
bridge.
|
||||
|
||||
The ast_bridge_snapshot_get_latest() function was renamed to
|
||||
ast_bridge_get_snapshot_by_uniqueid().
|
||||
|
||||
A new function "ast_bridge_get_snapshot()" was created to retrieve
|
||||
the bridge snapshot directly from the bridge structure.
|
||||
|
||||
The ast_bridge_topic_all() function now returns a normal topic
|
||||
not a cached one so you can't use stasis cache functions on it
|
||||
either.
|
||||
|
||||
The ast_bridge_snapshot_type() stasis message now has the
|
||||
ast_bridge_snapshot_update structure as it's data. It contains
|
||||
the last snapshot and the new one.
|
||||
|
||||
Build
|
||||
------------------
|
||||
* Asterisk headers are no longer installed and uninstalled automatically when
|
||||
performing a "make install" or a "make uninstall". To install/uninstall the
|
||||
headers, use "make install-headers" and "make uninstall-headers". The headers
|
||||
also continue to be uninstalled when performing a "make uninstall-all".
|
||||
|
||||
Channels
|
||||
------------------
|
||||
* The core no longer uses the stasis cache for channels snapshots.
|
||||
The following APIs are no longer available:
|
||||
ast_channel_topic_cached()
|
||||
ast_channel_topic_all_cached()
|
||||
The ast_channel_cache_all() and ast_channel_cache_by_name() functions
|
||||
now returns an ao2_container of ast_channel_snapshots rather than a
|
||||
container of stasis_messages therefore you can't call stasis_cache
|
||||
functions on it.
|
||||
The ast_channel_topic_all() function now returns a normal topic,
|
||||
not a cached one so you can't use stasis cache functions on it either.
|
||||
The ast_channel_snapshot_type() stasis message now has the
|
||||
ast_channel_snapshot_update structure as it's data.
|
||||
ast_channel_snapshot_get_latest() still returns the latest snapshot.
|
||||
|
||||
chan_sip
|
||||
------------------
|
||||
* The chan_sip module is now deprecated, users should migrate to the
|
||||
replacement module chan_pjsip. See guides at the Asterisk Wiki:
|
||||
https://wiki.asterisk.org/wiki/x/tAHOAQ
|
||||
https://wiki.asterisk.org/wiki/x/hYCLAQ
|
||||
|
||||
func_callerid
|
||||
------------------
|
||||
* The CALLERPRES() dialplan function, deprecated in Asterisk 1.8, has been
|
||||
removed.
|
||||
|
||||
res_parking
|
||||
------------------
|
||||
* The PARKINGSLOT channel variable, deprecated in Asterisk 12 in favor of the
|
||||
PARKING_SPACE channel variable, will no longer be set.
|
||||
|
||||
res_xmpp
|
||||
------------------
|
||||
* The JabberStatus application, deprecated in Asterisk 12, has been removed.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 16.0.0 to Asterisk 17.0.0 ------------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Core
|
||||
------------------
|
||||
* res_pjsip_pubsub is now required so call transfer progress can be monitored
|
||||
and reported in the channel variable TRANSFERSTATUS.
|
||||
|
||||
app_voicemail.c
|
||||
------------------
|
||||
* The "Voicemail Build Options" section of menuselect has been removed along with
|
||||
the FILE_STORAGE, ODBC_STORAGE and IMAP_STORAGE menuselect options. All 3 variants
|
||||
of the voicemail app can now be built at the same by enabling app_voicemail,
|
||||
app_voicemail_imap, and app_voicemail_odbc under the "Applications" section.
|
||||
By default, only app_voicemail is enabled. Also, the modules.conf sample has
|
||||
been updated to "noload" app_voicemail_imap and app_voicemail_odbc should they
|
||||
all be built. Packagers must update their build scripts appropriately.
|
||||
|
||||
chan_pjsip
|
||||
------------------
|
||||
* res_pjsip_pubsub is now required so call transfer progress can be monitored
|
||||
and reported in the channel variable TRANSFERSTATUS.
|
||||
|
||||
New in 16.0.0:
|
||||
|
||||
app_fax:
|
||||
|
|
|
@ -1457,9 +1457,9 @@ static void send_agent_logoff(struct ast_channel *chan, const char *agent, long
|
|||
|
||||
ast_assert(agent != NULL);
|
||||
|
||||
blob = ast_json_pack("{s: s, s: i}",
|
||||
blob = ast_json_pack("{s: s, s: I}",
|
||||
"agent", agent,
|
||||
"logintime", logintime);
|
||||
"logintime", (ast_json_int_t)logintime);
|
||||
if (!blob) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -5898,12 +5898,12 @@ static void send_agent_complete(const char *queuename, struct ast_channel_snapsh
|
|||
break;
|
||||
}
|
||||
|
||||
blob = ast_json_pack("{s: s, s: s, s: s, s: i, s: i, s: s}",
|
||||
blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I, s: s}",
|
||||
"Queue", queuename,
|
||||
"Interface", member->interface,
|
||||
"MemberName", member->membername,
|
||||
"HoldTime", (long)(callstart - holdstart),
|
||||
"TalkTime", (long)(time(NULL) - callstart),
|
||||
"HoldTime", (ast_json_int_t)(callstart - holdstart),
|
||||
"TalkTime", (ast_json_int_t)(time(NULL) - callstart),
|
||||
"Reason", reason ?: "");
|
||||
|
||||
queue_publish_multi_channel_snapshot_blob(ast_queue_topic(queuename), caller, peer,
|
||||
|
@ -7174,12 +7174,12 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
|
|||
ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "CONNECT", "%ld|%s|%ld", (long) (time(NULL) - qe->start), ast_channel_uniqueid(peer),
|
||||
(long)(orig - to > 0 ? (orig - to) / 1000 : 0));
|
||||
|
||||
blob = ast_json_pack("{s: s, s: s, s: s, s: i, s: i}",
|
||||
blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I}",
|
||||
"Queue", queuename,
|
||||
"Interface", member->interface,
|
||||
"MemberName", member->membername,
|
||||
"HoldTime", (long) (time(NULL) - qe->start),
|
||||
"RingTime", (long)(orig - to > 0 ? (orig - to) / 1000 : 0));
|
||||
"HoldTime", (ast_json_int_t)(time(NULL) - qe->start),
|
||||
"RingTime", (ast_json_int_t)(orig - to > 0 ? (orig - to) / 1000 : 0));
|
||||
queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_connect_type(), blob);
|
||||
|
||||
ast_copy_string(oldcontext, ast_channel_context(qe->chan), sizeof(oldcontext));
|
||||
|
|
|
@ -46,39 +46,6 @@
|
|||
* \verbinclude voicemail.conf.sample
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<defaultenabled>yes</defaultenabled>
|
||||
<use type="module">res_adsi</use>
|
||||
<use type="module">res_smdi</use>
|
||||
<support_level>core</support_level>
|
||||
***/
|
||||
|
||||
/*** MAKEOPTS
|
||||
<category name="MENUSELECT_OPTS_app_voicemail" displayname="Voicemail Build Options" positive_output="yes" touch_on_change="apps/app_voicemail.c apps/app_directory.c">
|
||||
<member name="FILE_STORAGE" displayname="Storage of Voicemail using filesystem">
|
||||
<conflict>ODBC_STORAGE</conflict>
|
||||
<conflict>IMAP_STORAGE</conflict>
|
||||
<defaultenabled>yes</defaultenabled>
|
||||
<support_level>core</support_level>
|
||||
</member>
|
||||
<member name="ODBC_STORAGE" displayname="Storage of Voicemail using ODBC">
|
||||
<depend>generic_odbc</depend>
|
||||
<conflict>IMAP_STORAGE</conflict>
|
||||
<conflict>FILE_STORAGE</conflict>
|
||||
<defaultenabled>no</defaultenabled>
|
||||
<support_level>core</support_level>
|
||||
</member>
|
||||
<member name="IMAP_STORAGE" displayname="Storage of Voicemail using IMAP4">
|
||||
<depend>imap_tk</depend>
|
||||
<conflict>ODBC_STORAGE</conflict>
|
||||
<conflict>FILE_STORAGE</conflict>
|
||||
<use type="external">openssl</use>
|
||||
<defaultenabled>no</defaultenabled>
|
||||
<support_level>core</support_level>
|
||||
</member>
|
||||
</category>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#ifdef IMAP_STORAGE
|
||||
|
@ -7212,7 +7179,7 @@ leave_vm_out:
|
|||
#ifdef IMAP_STORAGE
|
||||
/* expunge message - use UID Expunge if supported on IMAP server*/
|
||||
ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
|
||||
if (expungeonhangup == 1) {
|
||||
if (expungeonhangup == 1 && vms->mailstream != NULL) {
|
||||
ast_mutex_lock(&vms->lock);
|
||||
#ifdef HAVE_IMAP_TK2006
|
||||
if (LEVELUIDPLUS (vms->mailstream)) {
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<!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"><title>Release Summary - asterisk-17.0.1</title><h1 align="center"><a name="top">Release Summary</a></h1><h3 align="center">asterisk-17.0.1</h3><h3 align="center">Date: 2019-11-21</h3><h3 align="center"><asteriskteam@digium.com></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="#closed_issues">Closed Issues</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><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:</p><ul>
|
||||
<li><a href="http://downloads.asterisk.org/pub/security/AST-2019-006,AST-2019-007.html">AST-2019-006,AST-2019-007</a></li>
|
||||
</ul><p>The data in this summary reflects changes that have been made since the previous release, asterisk-17.0.0.</p><hr><a name="contributors"><h2 align="center">Contributors</h2></a><center><a href="#top">[Back to Top]</a></center><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 affected by commits that went into this release.</p><table width="100%" border="0">
|
||||
<tr><th width="33%">Coders</th><th width="33%">Testers</th><th width="33%">Reporters</th></tr>
|
||||
<tr valign="top"><td width="33%">1 Asterisk Development Team <asteriskteam@digium.com><br/>1 George Joseph <gjoseph@digium.com><br/>1 Ben Ford <bford@digium.com><br/></td><td width="33%"><td width="33%">1 Eliel Sardañons <eliels@gmail.com><br/>1 Andrey V. T. <avt1203@gmail.com><br/>1 Eliel Sardañons<br/></td></tr>
|
||||
</table><hr><a name="closed_issues"><h2 align="center">Closed Issues</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a list of all issues from the issue tracker that were closed by changes that went into this release.</p><h3>Security</h3><h4>Category: Channels/chan_sip/General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-28589">ASTERISK-28589</a>: chan_sip: Depending on configuration an INVITE can alter Addr of a peer<br/>Reported by: Andrey V. T.<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=92499125e8f4b88707b2606186d8cfa2be587918">[92499125e8]</a> Ben Ford -- chan_sip.c: Prevent address change on unauthenticated SIP request.</li>
|
||||
</ul><br><h4>Category: Core/ManagerInterface</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-28580">ASTERISK-28580</a>: Bypass SYSTEM write permission in manager action allows system commands execution<br/>Reported by: Eliel Sardañons<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a6bdc1268ac5a28d5e39da28ceb508cdfa641068">[a6bdc1268a]</a> George Joseph -- manager.c: Prevent the Originate action from running the Originate app</li>
|
||||
</ul><br><hr><a name="commits"><h2 align="center">Commits Not Associated with an Issue</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a list of all changes that went into this release that did not reference a JIRA issue.</p><table width="100%" border="1">
|
||||
<tr><th>Revision</th><th>Author</th><th>Summary</th></tr>
|
||||
<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=95c35e17650b911b311e7038caf9e24162167197">95c35e1765</a></td><td>Asterisk Development Team</td><td>Update CHANGES and UPGRADE.txt for 17.0.1</td></tr>
|
||||
</table><hr><a name="diffstat"><h2 align="center">Diffstat Results</h2></a><center><a href="#top">[Back to Top]</a></center><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>0 files changed</pre><br></html>
|
|
@ -0,0 +1,111 @@
|
|||
Release Summary
|
||||
|
||||
asterisk-17.0.1
|
||||
|
||||
Date: 2019-11-21
|
||||
|
||||
<asteriskteam@digium.com>
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Summary
|
||||
2. Contributors
|
||||
3. Closed Issues
|
||||
4. Other Changes
|
||||
5. 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-2019-006,AST-2019-007
|
||||
|
||||
The data in this summary reflects changes that have been made since the
|
||||
previous release, asterisk-17.0.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 affected by commits that went into
|
||||
this release.
|
||||
|
||||
Coders Testers Reporters
|
||||
1 Asterisk Development Team 1 Eliel Sardañons
|
||||
1 George Joseph 1 Andrey V. T.
|
||||
1 Ben Ford 1 Eliel Sardañons
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Closed Issues
|
||||
|
||||
[Back to Top]
|
||||
|
||||
This is a list of all issues from the issue tracker that were closed by
|
||||
changes that went into this release.
|
||||
|
||||
Security
|
||||
|
||||
Category: Channels/chan_sip/General
|
||||
|
||||
ASTERISK-28589: chan_sip: Depending on configuration an INVITE can alter
|
||||
Addr of a peer
|
||||
Reported by: Andrey V. T.
|
||||
* [92499125e8] Ben Ford -- chan_sip.c: Prevent address change on
|
||||
unauthenticated SIP request.
|
||||
|
||||
Category: Core/ManagerInterface
|
||||
|
||||
ASTERISK-28580: Bypass SYSTEM write permission in manager action allows
|
||||
system commands execution
|
||||
Reported by: Eliel Sardañons
|
||||
* [a6bdc1268a] George Joseph -- manager.c: Prevent the Originate action
|
||||
from running the Originate app
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Commits Not Associated with an Issue
|
||||
|
||||
[Back to Top]
|
||||
|
||||
This is a list of all changes that went into this release that did not
|
||||
reference a JIRA issue.
|
||||
|
||||
+------------------------------------------------------------------------+
|
||||
| Revision | Author | Summary |
|
||||
|------------+---------------------------+-------------------------------|
|
||||
| 95c35e1765 | Asterisk Development Team | Update CHANGES and |
|
||||
| | | UPGRADE.txt for 17.0.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.
|
||||
|
||||
0 files changed
|
|
@ -15158,10 +15158,12 @@ static void mfcr2_show_links_of(struct ast_cli_args *a, struct r2links *list_hea
|
|||
int channo;
|
||||
int prev_channo;
|
||||
x++;
|
||||
switch (mfcr2->r2master) {
|
||||
case 0L: thread_status = "zero"; break;
|
||||
case AST_PTHREADT_NULL: thread_status = "none"; break;
|
||||
default: thread_status = "created"; break;
|
||||
if (mfcr2->r2master == 0L) {
|
||||
thread_status = "zero";
|
||||
} else if (mfcr2->r2master == AST_PTHREADT_NULL) {
|
||||
thread_status = "none";
|
||||
} else {
|
||||
thread_status = "created";
|
||||
}
|
||||
snprintf(index, sizeof(index), "%d", mfcr2->index);
|
||||
snprintf(live_chans_str, sizeof(live_chans_str), "%d", mfcr2->live_chans);
|
||||
|
|
|
@ -11111,18 +11111,18 @@ static int socket_process_helper(struct iax2_thread *thread)
|
|||
if (iaxs[fr->callno]->pingtime <= peer->maxms) {
|
||||
ast_log(LOG_NOTICE, "Peer '%s' is now REACHABLE! Time: %u\n", peer->name, iaxs[fr->callno]->pingtime);
|
||||
ast_endpoint_set_state(peer->endpoint, AST_ENDPOINT_ONLINE);
|
||||
blob = ast_json_pack("{s: s, s: i}",
|
||||
blob = ast_json_pack("{s: s, s: I}",
|
||||
"peer_status", "Reachable",
|
||||
"time", iaxs[fr->callno]->pingtime);
|
||||
"time", (ast_json_int_t)iaxs[fr->callno]->pingtime);
|
||||
ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */
|
||||
}
|
||||
} else if ((peer->historicms > 0) && (peer->historicms <= peer->maxms)) {
|
||||
if (iaxs[fr->callno]->pingtime > peer->maxms) {
|
||||
ast_log(LOG_NOTICE, "Peer '%s' is now TOO LAGGED (%u ms)!\n", peer->name, iaxs[fr->callno]->pingtime);
|
||||
ast_endpoint_set_state(peer->endpoint, AST_ENDPOINT_ONLINE);
|
||||
blob = ast_json_pack("{s: s, s: i}",
|
||||
blob = ast_json_pack("{s: s, s: I}",
|
||||
"peer_status", "Lagged",
|
||||
"time", iaxs[fr->callno]->pingtime);
|
||||
"time", (ast_json_int_t)iaxs[fr->callno]->pingtime);
|
||||
ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -749,7 +749,8 @@ static int chan_pjsip_answer(struct ast_channel *ast)
|
|||
}
|
||||
|
||||
/*! \brief Internal helper function called when CNG tone is detected */
|
||||
static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *session, struct ast_frame *f)
|
||||
static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_channel *ast, struct ast_sip_session *session,
|
||||
struct ast_frame *f)
|
||||
{
|
||||
const char *target_context;
|
||||
int exists;
|
||||
|
@ -765,11 +766,11 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se
|
|||
}
|
||||
|
||||
/* If already executing in the fax extension don't do anything */
|
||||
if (!strcmp(ast_channel_exten(session->channel), "fax")) {
|
||||
if (!strcmp(ast_channel_exten(ast), "fax")) {
|
||||
return f;
|
||||
}
|
||||
|
||||
target_context = S_OR(ast_channel_macrocontext(session->channel), ast_channel_context(session->channel));
|
||||
target_context = S_OR(ast_channel_macrocontext(ast), ast_channel_context(ast));
|
||||
|
||||
/*
|
||||
* We need to unlock the channel here because ast_exists_extension has the
|
||||
|
@ -778,25 +779,30 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se
|
|||
*
|
||||
* ast_async_goto() has its own restriction on not holding the channel lock.
|
||||
*/
|
||||
ast_channel_unlock(session->channel);
|
||||
ast_channel_unlock(ast);
|
||||
ast_frfree(f);
|
||||
f = &ast_null_frame;
|
||||
exists = ast_exists_extension(session->channel, target_context, "fax", 1,
|
||||
S_COR(ast_channel_caller(session->channel)->id.number.valid,
|
||||
ast_channel_caller(session->channel)->id.number.str, NULL));
|
||||
exists = ast_exists_extension(ast, target_context, "fax", 1,
|
||||
S_COR(ast_channel_caller(ast)->id.number.valid,
|
||||
ast_channel_caller(ast)->id.number.str, NULL));
|
||||
if (exists) {
|
||||
ast_verb(2, "Redirecting '%s' to fax extension due to CNG detection\n",
|
||||
ast_channel_name(session->channel));
|
||||
pbx_builtin_setvar_helper(session->channel, "FAXEXTEN", ast_channel_exten(session->channel));
|
||||
if (ast_async_goto(session->channel, target_context, "fax", 1)) {
|
||||
ast_channel_name(ast));
|
||||
pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast));
|
||||
if (ast_async_goto(ast, target_context, "fax", 1)) {
|
||||
ast_log(LOG_ERROR, "Failed to async goto '%s' into fax extension in '%s'\n",
|
||||
ast_channel_name(session->channel), target_context);
|
||||
ast_channel_name(ast), target_context);
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_NOTICE, "FAX CNG detected on '%s' but no fax extension in '%s'\n",
|
||||
ast_channel_name(session->channel), target_context);
|
||||
ast_channel_name(ast), target_context);
|
||||
}
|
||||
ast_channel_lock(session->channel);
|
||||
|
||||
/* It's possible for a masquerade to have occurred when doing the ast_async_goto resulting in
|
||||
* the channel on the session having changed. Since we need to return with the original channel
|
||||
* locked we lock the channel that was passed in and not session->channel.
|
||||
*/
|
||||
ast_channel_lock(ast);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
@ -895,7 +901,11 @@ static struct ast_frame *chan_pjsip_read_stream(struct ast_channel *ast)
|
|||
if (f->subclass.integer == 'f') {
|
||||
ast_debug(3, "Channel driver fax CNG detected on %s\n",
|
||||
ast_channel_name(ast));
|
||||
f = chan_pjsip_cng_tone_detected(session, f);
|
||||
f = chan_pjsip_cng_tone_detected(ast, session, f);
|
||||
/* When chan_pjsip_cng_tone_detected returns it is possible for the
|
||||
* channel pointed to by ast and by session->channel to differ due to a
|
||||
* masquerade. It's best not to touch things after this.
|
||||
*/
|
||||
} else {
|
||||
ast_debug(3, "* Detected inband DTMF '%c' on '%s'\n", f->subclass.integer,
|
||||
ast_channel_name(ast));
|
||||
|
|
|
@ -19245,18 +19245,6 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
|
|||
bogus_peer = NULL;
|
||||
}
|
||||
|
||||
/* build_peer, called through sip_find_peer, is not able to check the
|
||||
* sip_pvt->natdetected flag in order to determine if the peer is behind
|
||||
* NAT or not when SIP_PAGE3_NAT_AUTO_RPORT or SIP_PAGE3_NAT_AUTO_COMEDIA
|
||||
* are set on the peer. So we check for that here and set the peer's
|
||||
* address accordingly.
|
||||
*/
|
||||
set_peer_nat(p, peer);
|
||||
|
||||
if (p->natdetected && ast_test_flag(&peer->flags[2], SIP_PAGE3_NAT_AUTO_RPORT)) {
|
||||
ast_sockaddr_copy(&peer->addr, &p->recv);
|
||||
}
|
||||
|
||||
if (!ast_apply_acl(peer->acl, addr, "SIP Peer ACL: ")) {
|
||||
ast_debug(2, "Found peer '%s' for '%s', but fails host access\n", peer->name, of);
|
||||
sip_unref_peer(peer, "sip_unref_peer: check_peer_ok: from sip_find_peer call, early return of AUTH_ACL_FAILED");
|
||||
|
@ -19325,6 +19313,21 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
|
|||
ast_string_field_set(p, peermd5secret, NULL);
|
||||
}
|
||||
if (!(res = check_auth(p, req, peer->name, p->peersecret, p->peermd5secret, sipmethod, uri2, reliable))) {
|
||||
|
||||
/* build_peer, called through sip_find_peer, is not able to check the
|
||||
* sip_pvt->natdetected flag in order to determine if the peer is behind
|
||||
* NAT or not when SIP_PAGE3_NAT_AUTO_RPORT or SIP_PAGE3_NAT_AUTO_COMEDIA
|
||||
* are set on the peer. So we check for that here and set the peer's
|
||||
* address accordingly. The address should ONLY be set once we are sure
|
||||
* authentication was a success. If, for example, an INVITE was sent that
|
||||
* matched the peer name but failed the authentication check, the address
|
||||
* would be updated, which is bad.
|
||||
*/
|
||||
set_peer_nat(p, peer);
|
||||
if (p->natdetected && ast_test_flag(&peer->flags[2], SIP_PAGE3_NAT_AUTO_RPORT)) {
|
||||
ast_sockaddr_copy(&peer->addr, &p->recv);
|
||||
}
|
||||
|
||||
/* If we have a call limit, set flag */
|
||||
if (peer->call_limit)
|
||||
ast_set_flag(&p->flags[0], SIP_CALL_LIMIT);
|
||||
|
@ -19424,6 +19427,7 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
|
|||
}
|
||||
}
|
||||
sip_unref_peer(peer, "check_peer_ok: sip_unref_peer: tossing temp ptr to peer from sip_find_peer");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -35349,8 +35353,8 @@ static void deprecation_notice(void)
|
|||
{
|
||||
ast_log(LOG_WARNING, "chan_sip has no official maintainer and is deprecated. Migration to\n");
|
||||
ast_log(LOG_WARNING, "chan_pjsip is recommended. See guides at the Asterisk Wiki:\n");
|
||||
ast_log(LOG_WARNING, "https://wiki.asterisk.org/wiki/x/tAHOAQ\n");
|
||||
ast_log(LOG_WARNING, "https://wiki.asterisk.org/wiki/x/hYCLAQ\n");
|
||||
ast_log(LOG_WARNING, "https://wiki.asterisk.org/wiki/display/AST/Migrating+from+chan_sip+to+res_pjsip\n");
|
||||
ast_log(LOG_WARNING, "https://wiki.asterisk.org/wiki/display/AST/Configuring+res_pjsip\n");
|
||||
}
|
||||
|
||||
/*! \brief Event callback which indicates we're fully booted */
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
CREATE TABLE alembic_version (
|
||||
version_num VARCHAR(32) NOT NULL,
|
||||
CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num)
|
||||
);
|
||||
|
||||
-- Running upgrade -> 210693f3123d
|
||||
|
||||
CREATE TABLE cdr (
|
||||
accountcode VARCHAR(20),
|
||||
src VARCHAR(80),
|
||||
dst VARCHAR(80),
|
||||
dcontext VARCHAR(80),
|
||||
clid VARCHAR(80),
|
||||
channel VARCHAR(80),
|
||||
dstchannel VARCHAR(80),
|
||||
lastapp VARCHAR(80),
|
||||
lastdata VARCHAR(80),
|
||||
start DATETIME,
|
||||
answer DATETIME,
|
||||
end DATETIME,
|
||||
duration INTEGER,
|
||||
billsec INTEGER,
|
||||
disposition VARCHAR(45),
|
||||
amaflags VARCHAR(45),
|
||||
userfield VARCHAR(256),
|
||||
uniqueid VARCHAR(150),
|
||||
linkedid VARCHAR(150),
|
||||
peeraccount VARCHAR(20),
|
||||
sequence INTEGER
|
||||
);
|
||||
|
||||
INSERT INTO alembic_version (version_num) VALUES ('210693f3123d');
|
||||
|
||||
-- Running upgrade 210693f3123d -> 54cde9847798
|
||||
|
||||
ALTER TABLE cdr MODIFY accountcode VARCHAR(80) NULL;
|
||||
|
||||
ALTER TABLE cdr MODIFY peeraccount VARCHAR(80) NULL;
|
||||
|
||||
UPDATE alembic_version SET version_num='54cde9847798' WHERE alembic_version.version_num = '210693f3123d';
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,35 @@
|
|||
CREATE TABLE alembic_version (
|
||||
version_num VARCHAR(32) NOT NULL,
|
||||
CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num)
|
||||
);
|
||||
|
||||
-- Running upgrade -> a2e9769475e
|
||||
|
||||
CREATE TABLE voicemail_messages (
|
||||
dir VARCHAR(255) NOT NULL,
|
||||
msgnum INTEGER NOT NULL,
|
||||
context VARCHAR(80),
|
||||
macrocontext VARCHAR(80),
|
||||
callerid VARCHAR(80),
|
||||
origtime INTEGER,
|
||||
duration INTEGER,
|
||||
recording BLOB,
|
||||
flag VARCHAR(30),
|
||||
category VARCHAR(30),
|
||||
mailboxuser VARCHAR(30),
|
||||
mailboxcontext VARCHAR(30),
|
||||
msg_id VARCHAR(40)
|
||||
);
|
||||
|
||||
ALTER TABLE voicemail_messages ADD CONSTRAINT voicemail_messages_dir_msgnum PRIMARY KEY (dir, msgnum);
|
||||
|
||||
CREATE INDEX voicemail_messages_dir ON voicemail_messages (dir);
|
||||
|
||||
INSERT INTO alembic_version (version_num) VALUES ('a2e9769475e');
|
||||
|
||||
-- Running upgrade a2e9769475e -> 39428242f7f5
|
||||
|
||||
ALTER TABLE voicemail_messages MODIFY recording BLOB(4294967295) NULL;
|
||||
|
||||
UPDATE alembic_version SET version_num='39428242f7f5' WHERE alembic_version.version_num = 'a2e9769475e';
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
BEGIN;
|
||||
|
||||
CREATE TABLE alembic_version (
|
||||
version_num VARCHAR(32) NOT NULL,
|
||||
CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num)
|
||||
);
|
||||
|
||||
-- Running upgrade -> 210693f3123d
|
||||
|
||||
CREATE TABLE cdr (
|
||||
accountcode VARCHAR(20),
|
||||
src VARCHAR(80),
|
||||
dst VARCHAR(80),
|
||||
dcontext VARCHAR(80),
|
||||
clid VARCHAR(80),
|
||||
channel VARCHAR(80),
|
||||
dstchannel VARCHAR(80),
|
||||
lastapp VARCHAR(80),
|
||||
lastdata VARCHAR(80),
|
||||
start TIMESTAMP WITHOUT TIME ZONE,
|
||||
answer TIMESTAMP WITHOUT TIME ZONE,
|
||||
"end" TIMESTAMP WITHOUT TIME ZONE,
|
||||
duration INTEGER,
|
||||
billsec INTEGER,
|
||||
disposition VARCHAR(45),
|
||||
amaflags VARCHAR(45),
|
||||
userfield VARCHAR(256),
|
||||
uniqueid VARCHAR(150),
|
||||
linkedid VARCHAR(150),
|
||||
peeraccount VARCHAR(20),
|
||||
sequence INTEGER
|
||||
);
|
||||
|
||||
INSERT INTO alembic_version (version_num) VALUES ('210693f3123d');
|
||||
|
||||
-- Running upgrade 210693f3123d -> 54cde9847798
|
||||
|
||||
ALTER TABLE cdr ALTER COLUMN accountcode TYPE VARCHAR(80);
|
||||
|
||||
ALTER TABLE cdr ALTER COLUMN peeraccount TYPE VARCHAR(80);
|
||||
|
||||
UPDATE alembic_version SET version_num='54cde9847798' WHERE alembic_version.version_num = '210693f3123d';
|
||||
|
||||
COMMIT;
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,39 @@
|
|||
BEGIN;
|
||||
|
||||
CREATE TABLE alembic_version (
|
||||
version_num VARCHAR(32) NOT NULL,
|
||||
CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num)
|
||||
);
|
||||
|
||||
-- Running upgrade -> a2e9769475e
|
||||
|
||||
CREATE TABLE voicemail_messages (
|
||||
dir VARCHAR(255) NOT NULL,
|
||||
msgnum INTEGER NOT NULL,
|
||||
context VARCHAR(80),
|
||||
macrocontext VARCHAR(80),
|
||||
callerid VARCHAR(80),
|
||||
origtime INTEGER,
|
||||
duration INTEGER,
|
||||
recording BYTEA,
|
||||
flag VARCHAR(30),
|
||||
category VARCHAR(30),
|
||||
mailboxuser VARCHAR(30),
|
||||
mailboxcontext VARCHAR(30),
|
||||
msg_id VARCHAR(40)
|
||||
);
|
||||
|
||||
ALTER TABLE voicemail_messages ADD CONSTRAINT voicemail_messages_dir_msgnum PRIMARY KEY (dir, msgnum);
|
||||
|
||||
CREATE INDEX voicemail_messages_dir ON voicemail_messages (dir);
|
||||
|
||||
INSERT INTO alembic_version (version_num) VALUES ('a2e9769475e');
|
||||
|
||||
-- Running upgrade a2e9769475e -> 39428242f7f5
|
||||
|
||||
ALTER TABLE voicemail_messages ALTER COLUMN recording TYPE BYTEA;
|
||||
|
||||
UPDATE alembic_version SET version_num='39428242f7f5' WHERE alembic_version.version_num = 'a2e9769475e';
|
||||
|
||||
COMMIT;
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
Subject: AttendedTransfer
|
||||
|
||||
A new application, this will queue up attended transfer to the given extension.
|
|
@ -1,4 +0,0 @@
|
|||
Subject: BlindTransfer
|
||||
|
||||
A new application, this will redirect all channels currently
|
||||
bridged to the caller channel to the specified destination.
|
|
@ -1,7 +0,0 @@
|
|||
Subject: ConfBridge
|
||||
|
||||
Add "average_all", "highest_all", and "lowest_all" values for
|
||||
the remb_behavior option. These values operate on a bridge
|
||||
level instead of a per-source level. This means that a single
|
||||
REMB value is calculated and sent to every sender, instead of
|
||||
a REMB value that is unique for the specific sender..
|
|
@ -1,12 +0,0 @@
|
|||
Subject: Dial
|
||||
|
||||
Add RINGTIME and RINGTIME_MS variables containing respectively seconds and
|
||||
milliseconds between creation of the dialing channel and receiving the first
|
||||
RINGING signal
|
||||
|
||||
Add PROGRESSTIME and PROGRESSTIME_MS variables analogous to the above with respect to
|
||||
the PROGRESS signal. Shorter of these two times should be equivalent to
|
||||
the PDD (Post Dial Delay) value
|
||||
|
||||
Add DIALEDTIME_MS and ANSWEREDTIME_MS variables to get millisecond resolution
|
||||
versions of DIALEDTIME and ANSWEREDTIME
|
|
@ -1,3 +0,0 @@
|
|||
Subject: ReadExten
|
||||
|
||||
Add 'p' option to stop reading extension if user presses '#' key.
|
|
@ -1,36 +0,0 @@
|
|||
Subject: Bridging
|
||||
Master-Only: true
|
||||
|
||||
The bridging core no longer uses the stasis cache for bridge
|
||||
snapshots. The latest bridge snapshot is now stored on the
|
||||
ast_bridge structure itself.
|
||||
|
||||
The following APIs are no longer available since the stasis cache
|
||||
is no longer used:
|
||||
ast_bridge_topic_cached()
|
||||
ast_bridge_topic_all_cached()
|
||||
|
||||
A topic pool is now used for individual bridge topics.
|
||||
|
||||
The ast_bridge_cache() function was removed since there's no
|
||||
longer a separate container of snapshots.
|
||||
|
||||
A new function "ast_bridges()" was created to retrieve the
|
||||
container of all bridges. Users formerly calling
|
||||
ast_bridge_cache() can use the new function to iterate over
|
||||
bridges and retrieve the latest snapshot directly from the
|
||||
bridge.
|
||||
|
||||
The ast_bridge_snapshot_get_latest() function was renamed to
|
||||
ast_bridge_get_snapshot_by_uniqueid().
|
||||
|
||||
A new function "ast_bridge_get_snapshot()" was created to retrieve
|
||||
the bridge snapshot directly from the bridge structure.
|
||||
|
||||
The ast_bridge_topic_all() function now returns a normal topic
|
||||
not a cached one so you can't use stasis cache functions on it
|
||||
either.
|
||||
|
||||
The ast_bridge_snapshot_type() stasis message now has the
|
||||
ast_bridge_snapshot_update structure as it's data. It contains
|
||||
the last snapshot and the new one.
|
|
@ -1,7 +0,0 @@
|
|||
Subject: chan_sip
|
||||
Master-Only: true
|
||||
|
||||
The chan_sip module is now deprecated, users should migrate to the
|
||||
replacement module chan_pjsip. See guides at the Asterisk Wiki:
|
||||
https://wiki.asterisk.org/wiki/x/tAHOAQ
|
||||
https://wiki.asterisk.org/wiki/x/hYCLAQ
|
|
@ -1,16 +0,0 @@
|
|||
Subject: Channels
|
||||
Master-Only: true
|
||||
|
||||
The core no longer uses the stasis cache for channels snapshots.
|
||||
The following APIs are no longer available:
|
||||
ast_channel_topic_cached()
|
||||
ast_channel_topic_all_cached()
|
||||
The ast_channel_cache_all() and ast_channel_cache_by_name() functions
|
||||
now returns an ao2_container of ast_channel_snapshots rather than a
|
||||
container of stasis_messages therefore you can't call stasis_cache
|
||||
functions on it.
|
||||
The ast_channel_topic_all() function now returns a normal topic,
|
||||
not a cached one so you can't use stasis cache functions on it either.
|
||||
The ast_channel_snapshot_type() stasis message now has the
|
||||
ast_channel_snapshot_update structure as it's data.
|
||||
ast_channel_snapshot_get_latest() still returns the latest snapshot.
|
|
@ -1,3 +0,0 @@
|
|||
Subject: pbx_dundi
|
||||
|
||||
The DUNDi PBX module now supports IPv4/IPv6 dual binding.
|
|
@ -1,13 +0,0 @@
|
|||
Subject: res_pjsip
|
||||
|
||||
Added a new PJSIP global setting called norefersub.
|
||||
Default is true to keep support working as before.
|
||||
|
||||
res_pjsip_refer configures PJSIP norefersub capability accordingly.
|
||||
|
||||
Checks the PJSIP global setting value.
|
||||
If it is true (default) it adds the norefersub capability to PJSIP.
|
||||
If it is false (disabled) it does not add the norefersub capability
|
||||
to PJSIP.
|
||||
|
||||
This is useful for Cisco switches that do not follow RFC4488.
|
|
@ -1,5 +0,0 @@
|
|||
Subject: res_rtp_asterisk
|
||||
|
||||
DTLS packets will now be fragmented according to the MTU as set in rtp.conf. This
|
||||
allows larger certificates to be used for the DTLS negotiation. By default this value
|
||||
is 1200.
|
|
@ -1,5 +0,0 @@
|
|||
Subject: RTP/ICE
|
||||
|
||||
You can now indicate that you'd like an ice_host_candidate's local address
|
||||
to be published as well as the mapped address. See the sample rtp.conf
|
||||
for more information.
|
|
@ -1,9 +0,0 @@
|
|||
Subject: app_voicemail.c
|
||||
|
||||
The "Voicemail Build Options" section of menuselect has been removed along with
|
||||
the FILE_STORAGE, ODBC_STORAGE and IMAP_STORAGE menuselect options. All 3 variants
|
||||
of the voicemail app can now be built at the same by enabling app_voicemail,
|
||||
app_voicemail_imap, and app_voicemail_odbc under the "Applications" section.
|
||||
By default, only app_voicemail is enabled. Also, the modules.conf sample has
|
||||
been updated to "noload" app_voicemail_imap and app_voicemail_odbc should they
|
||||
all be built. Packagers must update their build scripts appropriately.
|
|
@ -1,4 +0,0 @@
|
|||
Subject: Applications
|
||||
Master-Only: true
|
||||
|
||||
The JabberStatus application, deprecated in Asterisk 12, has been removed.
|
|
@ -1,36 +0,0 @@
|
|||
Subject: Bridging
|
||||
Master-Only: true
|
||||
|
||||
The bridging core no longer uses the stasis cache for bridge
|
||||
snapshots. The latest bridge snapshot is now stored on the
|
||||
ast_bridge structure itself.
|
||||
|
||||
The following APIs are no longer available since the stasis cache
|
||||
is no longer used:
|
||||
ast_bridge_topic_cached()
|
||||
ast_bridge_topic_all_cached()
|
||||
|
||||
A topic pool is now used for individual bridge topics.
|
||||
|
||||
The ast_bridge_cache() function was removed since there's no
|
||||
longer a separate container of snapshots.
|
||||
|
||||
A new function "ast_bridges()" was created to retrieve the
|
||||
container of all bridges. Users formerly calling
|
||||
ast_bridge_cache() can use the new function to iterate over
|
||||
bridges and retrieve the latest snapshot directly from the
|
||||
bridge.
|
||||
|
||||
The ast_bridge_snapshot_get_latest() function was renamed to
|
||||
ast_bridge_get_snapshot_by_uniqueid().
|
||||
|
||||
A new function "ast_bridge_get_snapshot()" was created to retrieve
|
||||
the bridge snapshot directly from the bridge structure.
|
||||
|
||||
The ast_bridge_topic_all() function now returns a normal topic
|
||||
not a cached one so you can't use stasis cache functions on it
|
||||
either.
|
||||
|
||||
The ast_bridge_snapshot_type() stasis message now has the
|
||||
ast_bridge_snapshot_update structure as it's data. It contains
|
||||
the last snapshot and the new one.
|
|
@ -1,5 +0,0 @@
|
|||
Subject: chan_pjsip
|
||||
Subject: Core
|
||||
|
||||
res_pjsip_pubsub is now required so call transfer progress can be monitored
|
||||
and reported in the channel variable TRANSFERSTATUS.
|
|
@ -1,7 +0,0 @@
|
|||
Subject: chan_sip
|
||||
Master-Only: true
|
||||
|
||||
The chan_sip module is now deprecated, users should migrate to the
|
||||
replacement module chan_pjsip. See guides at the Asterisk Wiki:
|
||||
https://wiki.asterisk.org/wiki/x/tAHOAQ
|
||||
https://wiki.asterisk.org/wiki/x/hYCLAQ
|
|
@ -1,16 +0,0 @@
|
|||
Subject: Channels
|
||||
Master-Only: true
|
||||
|
||||
The core no longer uses the stasis cache for channels snapshots.
|
||||
The following APIs are no longer available:
|
||||
ast_channel_topic_cached()
|
||||
ast_channel_topic_all_cached()
|
||||
The ast_channel_cache_all() and ast_channel_cache_by_name() functions
|
||||
now returns an ao2_container of ast_channel_snapshots rather than a
|
||||
container of stasis_messages therefore you can't call stasis_cache
|
||||
functions on it.
|
||||
The ast_channel_topic_all() function now returns a normal topic,
|
||||
not a cached one so you can't use stasis cache functions on it either.
|
||||
The ast_channel_snapshot_type() stasis message now has the
|
||||
ast_channel_snapshot_update structure as it's data.
|
||||
ast_channel_snapshot_get_latest() still returns the latest snapshot.
|
|
@ -1,5 +0,0 @@
|
|||
Subject: func_callerid
|
||||
Master-Only: true
|
||||
|
||||
The CALLERPRES() dialplan function, deprecated in Asterisk 1.8, has been
|
||||
removed.
|
|
@ -1,7 +0,0 @@
|
|||
Subject: Build
|
||||
Master-Only: true
|
||||
|
||||
Asterisk headers are no longer installed and uninstalled automatically when
|
||||
performing a "make install" or a "make uninstall". To install/uninstall the
|
||||
headers, use "make install-headers" and "make uninstall-headers". The headers
|
||||
also continue to be uninstalled when performing a "make uninstall-all".
|
|
@ -1,5 +0,0 @@
|
|||
Subject: res_parking
|
||||
Master-Only: true
|
||||
|
||||
The PARKINGSLOT channel variable, deprecated in Asterisk 12 in favor of the
|
||||
PARKING_SPACE channel variable, will no longer be set.
|
|
@ -1,4 +0,0 @@
|
|||
Subject: res_xmpp
|
||||
Master-Only: true
|
||||
|
||||
The JabberStatus application, deprecated in Asterisk 12, has been removed.
|
|
@ -203,7 +203,7 @@ static int talk_detect_audiohook_cb(struct ast_audiohook *audiohook, struct ast_
|
|||
int64_t diff_ms = ast_tvdiff_ms(ast_tvnow(), td_params->talking_start);
|
||||
diff_ms -= td_params->dsp_silence_threshold;
|
||||
|
||||
blob = ast_json_pack("{s: i}", "duration", diff_ms);
|
||||
blob = ast_json_pack("{s: I}", "duration", (ast_json_int_t)diff_ms);
|
||||
if (!blob) {
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -263,6 +263,28 @@ struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot,
|
|||
enum ast_cel_event_type event_type, const char *userdefevname,
|
||||
struct ast_json *extra, const char *peer_str);
|
||||
|
||||
/*!
|
||||
* \brief Allocate and populate a CEL event structure
|
||||
*
|
||||
* \param snapshot An ast_channel_snapshot of the primary channel associated
|
||||
* with this channel event.
|
||||
* \param event_type The type of call event being reported.
|
||||
* \param event_time The time at which the event occurred.
|
||||
* \param userdefevname Custom name for the call event. (optional)
|
||||
* \param extra An event-specific opaque JSON blob to be rendered and placed
|
||||
* in the "CEL_EXTRA" information element of the call event. (optional)
|
||||
* \param peer_str A list of comma-separated peer channel names. (optional)
|
||||
*
|
||||
* \since 13.29.0
|
||||
* \since 16.6.0
|
||||
*
|
||||
* \retval The created ast_event structure
|
||||
* \retval NULL on failure
|
||||
*/
|
||||
struct ast_event *ast_cel_create_event_with_time(struct ast_channel_snapshot *snapshot,
|
||||
enum ast_cel_event_type event_type, const struct timeval *event_time,
|
||||
const char *userdefevname, struct ast_json *extra, const char *peer_str);
|
||||
|
||||
/*!
|
||||
* \brief CEL backend callback
|
||||
*/
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
- \ref manager.c Main manager code file
|
||||
*/
|
||||
|
||||
#define AMI_VERSION "5.0.0"
|
||||
#define AMI_VERSION "6.0.0"
|
||||
#define DEFAULT_MANAGER_PORT 5038 /* Default port for Asterisk management via TCP */
|
||||
#define DEFAULT_MANAGER_TLS_PORT 5039 /* Default port for Asterisk management via TCP */
|
||||
|
||||
|
|
|
@ -1738,13 +1738,13 @@ static struct ast_json *s_to_json(const struct ast_aoc_decoded *decoded)
|
|||
decoded->aoc_s_entries[i].rate.duration.amount,
|
||||
decoded->aoc_s_entries[i].rate.duration.multiplier);
|
||||
|
||||
time = ast_json_pack("{s:i, s:i}",
|
||||
"Length", decoded->aoc_s_entries[i].rate.duration.time,
|
||||
time = ast_json_pack("{s:I, s:i}",
|
||||
"Length", (ast_json_int_t)decoded->aoc_s_entries[i].rate.duration.time,
|
||||
"Scale", decoded->aoc_s_entries[i].rate.duration.time_scale);
|
||||
|
||||
if (decoded->aoc_s_entries[i].rate.duration.granularity_time) {
|
||||
granularity = ast_json_pack("{s:i, s:i}",
|
||||
"Length", decoded->aoc_s_entries[i].rate.duration.granularity_time,
|
||||
granularity = ast_json_pack("{s:I, s:i}",
|
||||
"Length", (ast_json_int_t)decoded->aoc_s_entries[i].rate.duration.granularity_time,
|
||||
"Scale", decoded->aoc_s_entries[i].rate.duration.granularity_time_scale);
|
||||
}
|
||||
|
||||
|
|
|
@ -1076,9 +1076,9 @@ static void cc_publish_offertimerstart(int core_id, const char *caller, unsigned
|
|||
{
|
||||
struct ast_json *extras;
|
||||
|
||||
extras = ast_json_pack("{s: s, s: i}",
|
||||
extras = ast_json_pack("{s: s, s: I}",
|
||||
"caller", caller,
|
||||
"expires", expires);
|
||||
"expires", (ast_json_int_t)expires);
|
||||
|
||||
cc_publish(ast_cc_offertimerstart_type(), core_id, extras);
|
||||
ast_json_unref(extras);
|
||||
|
|
52
main/cdr.c
52
main/cdr.c
|
@ -718,6 +718,7 @@ struct cdr_object {
|
|||
struct timeval start; /*!< When this CDR was created */
|
||||
struct timeval answer; /*!< Either when the channel was answered, or when the path between channels was established */
|
||||
struct timeval end; /*!< When this CDR was finalized */
|
||||
struct timeval lastevent; /*!< The time at which the last event was created regarding this CDR */
|
||||
unsigned int sequence; /*!< A monotonically increasing number for each CDR */
|
||||
struct ast_flags flags; /*!< Flags on the CDR */
|
||||
AST_DECLARE_STRING_FIELDS(
|
||||
|
@ -1035,7 +1036,7 @@ static void cdr_object_dtor(void *obj)
|
|||
* This implicitly sets the state of the newly created CDR to the Single state
|
||||
* (\ref single_state_fn_table)
|
||||
*/
|
||||
static struct cdr_object *cdr_object_alloc(struct ast_channel_snapshot *chan)
|
||||
static struct cdr_object *cdr_object_alloc(struct ast_channel_snapshot *chan, const struct timeval *event_time)
|
||||
{
|
||||
struct cdr_object *cdr;
|
||||
|
||||
|
@ -1055,6 +1056,7 @@ static struct cdr_object *cdr_object_alloc(struct ast_channel_snapshot *chan)
|
|||
ast_string_field_set(cdr, linkedid, chan->peer->linkedid);
|
||||
cdr->disposition = AST_CDR_NULL;
|
||||
cdr->sequence = ast_atomic_fetchadd_int(&global_cdr_sequence, +1);
|
||||
cdr->lastevent = *event_time;
|
||||
|
||||
cdr->party_a.snapshot = chan;
|
||||
ao2_t_ref(cdr->party_a.snapshot, +1, "bump snapshot during CDR creation");
|
||||
|
@ -1070,14 +1072,14 @@ static struct cdr_object *cdr_object_alloc(struct ast_channel_snapshot *chan)
|
|||
* \brief Create a new \ref cdr_object and append it to an existing chain
|
||||
* \param cdr The \ref cdr_object to append to
|
||||
*/
|
||||
static struct cdr_object *cdr_object_create_and_append(struct cdr_object *cdr)
|
||||
static struct cdr_object *cdr_object_create_and_append(struct cdr_object *cdr, const struct timeval *event_time)
|
||||
{
|
||||
struct cdr_object *new_cdr;
|
||||
struct cdr_object *it_cdr;
|
||||
struct cdr_object *cdr_last;
|
||||
|
||||
cdr_last = cdr->last;
|
||||
new_cdr = cdr_object_alloc(cdr_last->party_a.snapshot);
|
||||
new_cdr = cdr_object_alloc(cdr_last->party_a.snapshot, event_time);
|
||||
if (!new_cdr) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1440,7 +1442,7 @@ static void cdr_object_finalize(struct cdr_object *cdr)
|
|||
if (!ast_tvzero(cdr->end)) {
|
||||
return;
|
||||
}
|
||||
cdr->end = ast_tvnow();
|
||||
cdr->end = cdr->lastevent;
|
||||
|
||||
if (cdr->disposition == AST_CDR_NULL) {
|
||||
if (!ast_tvzero(cdr->answer)) {
|
||||
|
@ -1490,7 +1492,7 @@ static void cdr_object_check_party_a_hangup(struct cdr_object *cdr)
|
|||
static void cdr_object_check_party_a_answer(struct cdr_object *cdr)
|
||||
{
|
||||
if (cdr->party_a.snapshot->state == AST_STATE_UP && ast_tvzero(cdr->answer)) {
|
||||
cdr->answer = ast_tvnow();
|
||||
cdr->answer = cdr->lastevent;
|
||||
/* tv_usec is suseconds_t, which could be int or long */
|
||||
CDR_DEBUG("%p - Set answered time to %ld.%06ld\n", cdr,
|
||||
(long)cdr->answer.tv_sec,
|
||||
|
@ -1634,7 +1636,7 @@ static int base_process_parked_channel(struct cdr_object *cdr, struct ast_parked
|
|||
|
||||
static void single_state_init_function(struct cdr_object *cdr)
|
||||
{
|
||||
cdr->start = ast_tvnow();
|
||||
cdr->start = cdr->lastevent;
|
||||
cdr_object_check_party_a_answer(cdr);
|
||||
}
|
||||
|
||||
|
@ -2149,6 +2151,7 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str
|
|||
|
||||
ao2_lock(cdr);
|
||||
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
|
||||
it_cdr->lastevent = *stasis_message_timestamp(message);
|
||||
if (ast_strlen_zero(dial_status)) {
|
||||
if (!it_cdr->fn_table->process_dial_begin) {
|
||||
continue;
|
||||
|
@ -2179,7 +2182,7 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str
|
|||
if (res && ast_strlen_zero(dial_status)) {
|
||||
struct cdr_object *new_cdr;
|
||||
|
||||
new_cdr = cdr_object_create_and_append(cdr);
|
||||
new_cdr = cdr_object_create_and_append(cdr, stasis_message_timestamp(message));
|
||||
if (new_cdr) {
|
||||
new_cdr->fn_table->process_dial_begin(new_cdr, caller, peer);
|
||||
}
|
||||
|
@ -2281,7 +2284,7 @@ static void handle_channel_snapshot_update_message(void *data, struct stasis_sub
|
|||
}
|
||||
|
||||
if (update->new_snapshot && !update->old_snapshot) {
|
||||
cdr = cdr_object_alloc(update->new_snapshot);
|
||||
cdr = cdr_object_alloc(update->new_snapshot, stasis_message_timestamp(message));
|
||||
if (!cdr) {
|
||||
return;
|
||||
}
|
||||
|
@ -2300,6 +2303,7 @@ static void handle_channel_snapshot_update_message(void *data, struct stasis_sub
|
|||
|
||||
ao2_lock(cdr);
|
||||
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
|
||||
it_cdr->lastevent = *stasis_message_timestamp(message);
|
||||
if (!it_cdr->fn_table->process_party_a) {
|
||||
continue;
|
||||
}
|
||||
|
@ -2309,7 +2313,7 @@ static void handle_channel_snapshot_update_message(void *data, struct stasis_sub
|
|||
/* We're not hung up and we have a new snapshot - we need a new CDR */
|
||||
struct cdr_object *new_cdr;
|
||||
|
||||
new_cdr = cdr_object_create_and_append(cdr);
|
||||
new_cdr = cdr_object_create_and_append(cdr, stasis_message_timestamp(message));
|
||||
if (new_cdr) {
|
||||
new_cdr->fn_table->process_party_a(new_cdr, update->new_snapshot);
|
||||
}
|
||||
|
@ -2321,6 +2325,7 @@ static void handle_channel_snapshot_update_message(void *data, struct stasis_sub
|
|||
ao2_lock(cdr);
|
||||
CDR_DEBUG("%p - Beginning finalize/dispatch for %s\n", cdr, update->old_snapshot->base->name);
|
||||
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
|
||||
it_cdr->lastevent = *stasis_message_timestamp(message);
|
||||
cdr_object_finalize(it_cdr);
|
||||
}
|
||||
cdr_object_dispatch(cdr);
|
||||
|
@ -2429,6 +2434,7 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription *
|
|||
/* Party A */
|
||||
ao2_lock(cdr);
|
||||
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
|
||||
it_cdr->lastevent = *stasis_message_timestamp(message);
|
||||
if (!it_cdr->fn_table->process_bridge_leave) {
|
||||
continue;
|
||||
}
|
||||
|
@ -2463,7 +2469,7 @@ static void bridge_candidate_add_to_cdr(struct cdr_object *cdr,
|
|||
{
|
||||
struct cdr_object *new_cdr;
|
||||
|
||||
new_cdr = cdr_object_create_and_append(cdr);
|
||||
new_cdr = cdr_object_create_and_append(cdr, &cdr->lastevent);
|
||||
if (!new_cdr) {
|
||||
return;
|
||||
}
|
||||
|
@ -2574,7 +2580,8 @@ static void handle_bridge_pairings(struct cdr_object *cdr, struct ast_bridge_sna
|
|||
*/
|
||||
static void handle_parking_bridge_enter_message(struct cdr_object *cdr,
|
||||
struct ast_bridge_snapshot *bridge,
|
||||
struct ast_channel_snapshot *channel)
|
||||
struct ast_channel_snapshot *channel,
|
||||
const struct timeval *event_time)
|
||||
{
|
||||
int res = 1;
|
||||
struct cdr_object *it_cdr;
|
||||
|
@ -2583,6 +2590,8 @@ static void handle_parking_bridge_enter_message(struct cdr_object *cdr,
|
|||
ao2_lock(cdr);
|
||||
|
||||
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
|
||||
it_cdr->lastevent = *event_time;
|
||||
|
||||
if (it_cdr->fn_table->process_parking_bridge_enter) {
|
||||
res &= it_cdr->fn_table->process_parking_bridge_enter(it_cdr, bridge, channel);
|
||||
}
|
||||
|
@ -2595,7 +2604,7 @@ static void handle_parking_bridge_enter_message(struct cdr_object *cdr,
|
|||
|
||||
if (res) {
|
||||
/* No one handled it - we need a new one! */
|
||||
new_cdr = cdr_object_create_and_append(cdr);
|
||||
new_cdr = cdr_object_create_and_append(cdr, event_time);
|
||||
if (new_cdr) {
|
||||
/* Let the single state transition us to Parked */
|
||||
cdr_object_transition_state(new_cdr, &single_state_fn_table);
|
||||
|
@ -2612,7 +2621,8 @@ static void handle_parking_bridge_enter_message(struct cdr_object *cdr,
|
|||
*/
|
||||
static void handle_standard_bridge_enter_message(struct cdr_object *cdr,
|
||||
struct ast_bridge_snapshot *bridge,
|
||||
struct ast_channel_snapshot *channel)
|
||||
struct ast_channel_snapshot *channel,
|
||||
const struct timeval *event_time)
|
||||
{
|
||||
enum process_bridge_enter_results result;
|
||||
struct cdr_object *it_cdr;
|
||||
|
@ -2623,6 +2633,8 @@ static void handle_standard_bridge_enter_message(struct cdr_object *cdr,
|
|||
|
||||
try_again:
|
||||
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
|
||||
it_cdr->lastevent = *event_time;
|
||||
|
||||
if (it_cdr->fn_table->process_party_a) {
|
||||
CDR_DEBUG("%p - Updating Party A %s snapshot\n", it_cdr,
|
||||
channel->base->name);
|
||||
|
@ -2669,7 +2681,7 @@ try_again:
|
|||
handle_bridge_pairings(handled_cdr, bridge);
|
||||
} else {
|
||||
/* Nothing handled it - we need a new one! */
|
||||
new_cdr = cdr_object_create_and_append(cdr);
|
||||
new_cdr = cdr_object_create_and_append(cdr, event_time);
|
||||
if (new_cdr) {
|
||||
/* This is guaranteed to succeed: the new CDR is created in the single state
|
||||
* and will be able to handle the bridge enter message
|
||||
|
@ -2717,9 +2729,9 @@ static void handle_bridge_enter_message(void *data, struct stasis_subscription *
|
|||
}
|
||||
|
||||
if (!strcmp(bridge->subclass, "parking")) {
|
||||
handle_parking_bridge_enter_message(cdr, bridge, channel);
|
||||
handle_parking_bridge_enter_message(cdr, bridge, channel, stasis_message_timestamp(message));
|
||||
} else {
|
||||
handle_standard_bridge_enter_message(cdr, bridge, channel);
|
||||
handle_standard_bridge_enter_message(cdr, bridge, channel, stasis_message_timestamp(message));
|
||||
}
|
||||
ao2_cleanup(cdr);
|
||||
}
|
||||
|
@ -2769,6 +2781,7 @@ static void handle_parked_call_message(void *data, struct stasis_subscription *s
|
|||
ao2_lock(cdr);
|
||||
|
||||
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
|
||||
it_cdr->lastevent = *stasis_message_timestamp(message);
|
||||
if (it_cdr->fn_table->process_parked_channel) {
|
||||
unhandled &= it_cdr->fn_table->process_parked_channel(it_cdr, payload);
|
||||
}
|
||||
|
@ -2778,7 +2791,7 @@ static void handle_parked_call_message(void *data, struct stasis_subscription *s
|
|||
/* Nothing handled the messgae - we need a new one! */
|
||||
struct cdr_object *new_cdr;
|
||||
|
||||
new_cdr = cdr_object_create_and_append(cdr);
|
||||
new_cdr = cdr_object_create_and_append(cdr, stasis_message_timestamp(message));
|
||||
if (new_cdr) {
|
||||
/* As the new CDR is created in the single state, it is guaranteed
|
||||
* to have a function for the parked call message and will handle
|
||||
|
@ -3607,6 +3620,7 @@ int ast_cdr_reset(const char *channel_name, int keep_variables)
|
|||
memset(&it_cdr->end, 0, sizeof(it_cdr->end));
|
||||
memset(&it_cdr->answer, 0, sizeof(it_cdr->answer));
|
||||
it_cdr->start = ast_tvnow();
|
||||
it_cdr->lastevent = it_cdr->start;
|
||||
cdr_object_check_party_a_answer(it_cdr);
|
||||
}
|
||||
ao2_unlock(cdr);
|
||||
|
@ -3628,6 +3642,7 @@ int ast_cdr_fork(const char *channel_name, struct ast_flags *options)
|
|||
|
||||
{
|
||||
SCOPED_AO2LOCK(lock, cdr);
|
||||
struct timeval now = ast_tvnow();
|
||||
|
||||
cdr_obj = cdr->last;
|
||||
if (cdr_obj->fn_table == &finalized_state_fn_table) {
|
||||
|
@ -3641,7 +3656,7 @@ int ast_cdr_fork(const char *channel_name, struct ast_flags *options)
|
|||
* copied over automatically as part of the append
|
||||
*/
|
||||
ast_debug(1, "Forking CDR for channel %s\n", cdr->party_a.snapshot->base->name);
|
||||
new_cdr = cdr_object_create_and_append(cdr);
|
||||
new_cdr = cdr_object_create_and_append(cdr, &now);
|
||||
if (!new_cdr) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -3671,6 +3686,7 @@ int ast_cdr_fork(const char *channel_name, struct ast_flags *options)
|
|||
}
|
||||
new_cdr->start = cdr_obj->start;
|
||||
new_cdr->answer = cdr_obj->answer;
|
||||
new_cdr->lastevent = ast_tvnow();
|
||||
|
||||
/* Modify the times based on the flags passed in */
|
||||
if (ast_test_flag(options, AST_CDR_FLAG_SET_ANSWER)
|
||||
|
|
82
main/cel.c
82
main/cel.c
|
@ -519,14 +519,23 @@ struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot,
|
|||
struct ast_json *extra, const char *peer)
|
||||
{
|
||||
struct timeval eventtime = ast_tvnow();
|
||||
|
||||
return ast_cel_create_event_with_time(snapshot, event_type, &eventtime,
|
||||
userdefevname, extra, peer);
|
||||
}
|
||||
|
||||
struct ast_event *ast_cel_create_event_with_time(struct ast_channel_snapshot *snapshot,
|
||||
enum ast_cel_event_type event_type, const struct timeval *event_time,
|
||||
const char *userdefevname, struct ast_json *extra, const char *peer)
|
||||
{
|
||||
RAII_VAR(char *, extra_txt, NULL, ast_json_free);
|
||||
if (extra) {
|
||||
extra_txt = ast_json_dump_string(extra);
|
||||
}
|
||||
return ast_event_new(AST_EVENT_CEL,
|
||||
AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, event_type,
|
||||
AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
|
||||
AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_usec,
|
||||
AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, event_time->tv_sec,
|
||||
AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, event_time->tv_usec,
|
||||
AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_STR, S_OR(userdefevname, ""),
|
||||
AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->caller->name,
|
||||
AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR, snapshot->caller->number,
|
||||
|
@ -558,8 +567,9 @@ static int cel_backend_send_cb(void *obj, void *arg, int flags)
|
|||
}
|
||||
|
||||
static int cel_report_event(struct ast_channel_snapshot *snapshot,
|
||||
enum ast_cel_event_type event_type, const char *userdefevname,
|
||||
struct ast_json *extra, const char *peer_str)
|
||||
enum ast_cel_event_type event_type, const struct timeval *event_time,
|
||||
const char *userdefevname, struct ast_json *extra,
|
||||
const char *peer_str)
|
||||
{
|
||||
struct ast_event *ev;
|
||||
RAII_VAR(struct cel_config *, cfg, ao2_global_obj_ref(cel_configs), ao2_cleanup);
|
||||
|
@ -587,7 +597,7 @@ static int cel_report_event(struct ast_channel_snapshot *snapshot,
|
|||
return 0;
|
||||
}
|
||||
|
||||
ev = ast_cel_create_event(snapshot, event_type, userdefevname, extra, peer_str);
|
||||
ev = ast_cel_create_event_with_time(snapshot, event_type, event_time, userdefevname, extra, peer_str);
|
||||
if (!ev) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -601,7 +611,7 @@ static int cel_report_event(struct ast_channel_snapshot *snapshot,
|
|||
|
||||
/* called whenever a channel is destroyed or a linkedid is changed to
|
||||
* potentially emit a CEL_LINKEDID_END event */
|
||||
static void check_retire_linkedid(struct ast_channel_snapshot *snapshot)
|
||||
static void check_retire_linkedid(struct ast_channel_snapshot *snapshot, const struct timeval *event_time)
|
||||
{
|
||||
RAII_VAR(struct ao2_container *, linkedids, ao2_global_obj_ref(cel_linkedids), ao2_cleanup);
|
||||
struct cel_linkedid *lid;
|
||||
|
@ -632,7 +642,7 @@ static void check_retire_linkedid(struct ast_channel_snapshot *snapshot)
|
|||
ao2_unlink(linkedids, lid);
|
||||
ao2_unlock(linkedids);
|
||||
|
||||
cel_report_event(snapshot, AST_CEL_LINKEDID_END, NULL, NULL, NULL);
|
||||
cel_report_event(snapshot, AST_CEL_LINKEDID_END, event_time, NULL, NULL, NULL);
|
||||
} else {
|
||||
ao2_unlock(linkedids);
|
||||
}
|
||||
|
@ -852,7 +862,8 @@ int ast_cel_fill_record(const struct ast_event *e, struct ast_cel_event_record *
|
|||
/*! \brief Typedef for callbacks that get called on channel snapshot updates */
|
||||
typedef void (*cel_channel_snapshot_monitor)(
|
||||
struct ast_channel_snapshot *old_snapshot,
|
||||
struct ast_channel_snapshot *new_snapshot);
|
||||
struct ast_channel_snapshot *new_snapshot,
|
||||
const struct timeval *event_time);
|
||||
|
||||
static struct cel_dialstatus *get_dialstatus(const char *uniqueid)
|
||||
{
|
||||
|
@ -884,12 +895,13 @@ static const char *get_blob_variable(struct ast_multi_channel_blob *blob, const
|
|||
/*! \brief Handle channel state changes */
|
||||
static void cel_channel_state_change(
|
||||
struct ast_channel_snapshot *old_snapshot,
|
||||
struct ast_channel_snapshot *new_snapshot)
|
||||
struct ast_channel_snapshot *new_snapshot,
|
||||
const struct timeval *event_time)
|
||||
{
|
||||
int is_hungup, was_hungup;
|
||||
|
||||
if (!old_snapshot) {
|
||||
cel_report_event(new_snapshot, AST_CEL_CHANNEL_START, NULL, NULL, NULL);
|
||||
cel_report_event(new_snapshot, AST_CEL_CHANNEL_START, event_time, NULL, NULL, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -904,26 +916,27 @@ static void cel_channel_state_change(
|
|||
"hangupcause", new_snapshot->hangup->cause,
|
||||
"hangupsource", new_snapshot->hangup->source,
|
||||
"dialstatus", dialstatus ? dialstatus->dialstatus : "");
|
||||
cel_report_event(new_snapshot, AST_CEL_HANGUP, NULL, extra, NULL);
|
||||
cel_report_event(new_snapshot, AST_CEL_HANGUP, event_time, NULL, extra, NULL);
|
||||
ast_json_unref(extra);
|
||||
ao2_cleanup(dialstatus);
|
||||
|
||||
cel_report_event(new_snapshot, AST_CEL_CHANNEL_END, NULL, NULL, NULL);
|
||||
cel_report_event(new_snapshot, AST_CEL_CHANNEL_END, event_time, NULL, NULL, NULL);
|
||||
if (ast_cel_track_event(AST_CEL_LINKEDID_END)) {
|
||||
check_retire_linkedid(new_snapshot);
|
||||
check_retire_linkedid(new_snapshot, event_time);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (old_snapshot->state != new_snapshot->state && new_snapshot->state == AST_STATE_UP) {
|
||||
cel_report_event(new_snapshot, AST_CEL_ANSWER, NULL, NULL, NULL);
|
||||
cel_report_event(new_snapshot, AST_CEL_ANSWER, event_time, NULL, NULL, NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void cel_channel_linkedid_change(
|
||||
struct ast_channel_snapshot *old_snapshot,
|
||||
struct ast_channel_snapshot *new_snapshot)
|
||||
struct ast_channel_snapshot *new_snapshot,
|
||||
const struct timeval *event_time)
|
||||
{
|
||||
if (!old_snapshot) {
|
||||
return;
|
||||
|
@ -935,13 +948,14 @@ static void cel_channel_linkedid_change(
|
|||
if (ast_cel_track_event(AST_CEL_LINKEDID_END)
|
||||
&& strcmp(old_snapshot->peer->linkedid, new_snapshot->peer->linkedid)) {
|
||||
cel_linkedid_ref(new_snapshot->peer->linkedid);
|
||||
check_retire_linkedid(old_snapshot);
|
||||
check_retire_linkedid(old_snapshot, event_time);
|
||||
}
|
||||
}
|
||||
|
||||
static void cel_channel_app_change(
|
||||
struct ast_channel_snapshot *old_snapshot,
|
||||
struct ast_channel_snapshot *new_snapshot)
|
||||
struct ast_channel_snapshot *new_snapshot,
|
||||
const struct timeval *event_time)
|
||||
{
|
||||
if (old_snapshot && !strcmp(old_snapshot->dialplan->appl, new_snapshot->dialplan->appl)) {
|
||||
return;
|
||||
|
@ -949,12 +963,12 @@ static void cel_channel_app_change(
|
|||
|
||||
/* old snapshot has an application, end it */
|
||||
if (old_snapshot && !ast_strlen_zero(old_snapshot->dialplan->appl)) {
|
||||
cel_report_event(old_snapshot, AST_CEL_APP_END, NULL, NULL, NULL);
|
||||
cel_report_event(old_snapshot, AST_CEL_APP_END, event_time, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
/* new snapshot has an application, start it */
|
||||
if (!ast_strlen_zero(new_snapshot->dialplan->appl)) {
|
||||
cel_report_event(new_snapshot, AST_CEL_APP_START, NULL, NULL, NULL);
|
||||
cel_report_event(new_snapshot, AST_CEL_APP_START, event_time, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -988,7 +1002,7 @@ static void cel_snapshot_update_cb(void *data, struct stasis_subscription *sub,
|
|||
}
|
||||
|
||||
for (i = 0; i < ARRAY_LEN(cel_channel_monitors); ++i) {
|
||||
cel_channel_monitors[i](update->old_snapshot, update->new_snapshot);
|
||||
cel_channel_monitors[i](update->old_snapshot, update->new_snapshot, stasis_message_timestamp(message));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1056,7 +1070,8 @@ static void cel_bridge_enter_cb(
|
|||
return;
|
||||
}
|
||||
|
||||
cel_report_event(chan_snapshot, AST_CEL_BRIDGE_ENTER, NULL, extra, ast_str_buffer(peer_str));
|
||||
cel_report_event(chan_snapshot, AST_CEL_BRIDGE_ENTER, stasis_message_timestamp(message),
|
||||
NULL, extra, ast_str_buffer(peer_str));
|
||||
}
|
||||
|
||||
static void cel_bridge_leave_cb(
|
||||
|
@ -1085,7 +1100,8 @@ static void cel_bridge_leave_cb(
|
|||
return;
|
||||
}
|
||||
|
||||
cel_report_event(chan_snapshot, AST_CEL_BRIDGE_EXIT, NULL, extra, ast_str_buffer(peer_str));
|
||||
cel_report_event(chan_snapshot, AST_CEL_BRIDGE_EXIT, stasis_message_timestamp(message),
|
||||
NULL, extra, ast_str_buffer(peer_str));
|
||||
}
|
||||
|
||||
static void cel_parking_cb(
|
||||
|
@ -1102,7 +1118,8 @@ static void cel_parking_cb(
|
|||
"parker_dial_string", parked_payload->parker_dial_string,
|
||||
"parking_lot", parked_payload->parkinglot);
|
||||
if (extra) {
|
||||
cel_report_event(parked_payload->parkee, AST_CEL_PARK_START, NULL, extra, NULL);
|
||||
cel_report_event(parked_payload->parkee, AST_CEL_PARK_START, stasis_message_timestamp(message),
|
||||
NULL, extra, NULL);
|
||||
}
|
||||
return;
|
||||
case PARKED_CALL_TIMEOUT:
|
||||
|
@ -1131,7 +1148,8 @@ static void cel_parking_cb(
|
|||
}
|
||||
|
||||
if (extra) {
|
||||
cel_report_event(parked_payload->parkee, AST_CEL_PARK_END, NULL, extra, NULL);
|
||||
cel_report_event(parked_payload->parkee, AST_CEL_PARK_END, stasis_message_timestamp(message),
|
||||
NULL, extra, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1224,7 +1242,8 @@ static void cel_dial_cb(void *data, struct stasis_subscription *sub,
|
|||
|
||||
extra = ast_json_pack("{s: s}", "forward", get_blob_variable(blob, "forward"));
|
||||
if (extra) {
|
||||
cel_report_event(snapshot, AST_CEL_FORWARD, NULL, extra, NULL);
|
||||
cel_report_event(snapshot, AST_CEL_FORWARD, stasis_message_timestamp(message),
|
||||
NULL, extra, NULL);
|
||||
ast_json_unref(extra);
|
||||
}
|
||||
}
|
||||
|
@ -1247,7 +1266,8 @@ static void cel_generic_cb(
|
|||
{
|
||||
const char *event = ast_json_string_get(ast_json_object_get(event_details, "event"));
|
||||
struct ast_json *extra = ast_json_object_get(event_details, "extra");
|
||||
cel_report_event(obj->snapshot, event_type, event, extra, NULL);
|
||||
cel_report_event(obj->snapshot, event_type, stasis_message_timestamp(message),
|
||||
event, extra, NULL);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -1276,7 +1296,8 @@ static void cel_blind_transfer_cb(
|
|||
"transferee_channel_name", transfer_msg->transferee ? transfer_msg->transferee->base->name : "N/A",
|
||||
"transferee_channel_uniqueid", transfer_msg->transferee ? transfer_msg->transferee->base->uniqueid : "N/A");
|
||||
if (extra) {
|
||||
cel_report_event(chan_snapshot, AST_CEL_BLINDTRANSFER, NULL, extra, NULL);
|
||||
cel_report_event(chan_snapshot, AST_CEL_BLINDTRANSFER, stasis_message_timestamp(message),
|
||||
NULL, extra, NULL);
|
||||
ast_json_unref(extra);
|
||||
}
|
||||
}
|
||||
|
@ -1339,7 +1360,8 @@ static void cel_attended_transfer_cb(
|
|||
}
|
||||
break;
|
||||
}
|
||||
cel_report_event(channel1, AST_CEL_ATTENDEDTRANSFER, NULL, extra, NULL);
|
||||
cel_report_event(channel1, AST_CEL_ATTENDEDTRANSFER, stasis_message_timestamp(message),
|
||||
NULL, extra, NULL);
|
||||
ast_json_unref(extra);
|
||||
}
|
||||
|
||||
|
@ -1363,7 +1385,7 @@ static void cel_pickup_cb(
|
|||
return;
|
||||
}
|
||||
|
||||
cel_report_event(target, AST_CEL_PICKUP, NULL, extra, NULL);
|
||||
cel_report_event(target, AST_CEL_PICKUP, stasis_message_timestamp(message), NULL, extra, NULL);
|
||||
ast_json_unref(extra);
|
||||
}
|
||||
|
||||
|
@ -1387,7 +1409,7 @@ static void cel_local_cb(
|
|||
return;
|
||||
}
|
||||
|
||||
cel_report_event(localone, AST_CEL_LOCAL_OPTIMIZE, NULL, extra, NULL);
|
||||
cel_report_event(localone, AST_CEL_LOCAL_OPTIMIZE, stasis_message_timestamp(message), NULL, extra, NULL);
|
||||
ast_json_unref(extra);
|
||||
}
|
||||
|
||||
|
|
|
@ -3328,10 +3328,10 @@ static void send_dtmf_end_event(struct ast_channel *chan,
|
|||
RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
|
||||
char digit_str[] = { digit, '\0' };
|
||||
|
||||
blob = ast_json_pack("{ s: s, s: s, s: i }",
|
||||
blob = ast_json_pack("{ s: s, s: s, s: I }",
|
||||
"digit", digit_str,
|
||||
"direction", dtmf_direction_to_string(direction),
|
||||
"duration_ms", duration_ms);
|
||||
"duration_ms", (ast_json_int_t)duration_ms);
|
||||
if (!blob) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -394,8 +394,8 @@ static void local_optimization_started_cb(struct ast_unreal_pvt *base, struct as
|
|||
return;
|
||||
}
|
||||
|
||||
json_object = ast_json_pack("{s: i, s: i}",
|
||||
"dest", dest, "id", id);
|
||||
json_object = ast_json_pack("{s: i, s: I}",
|
||||
"dest", dest, "id", (ast_json_int_t)id);
|
||||
|
||||
if (!json_object) {
|
||||
return;
|
||||
|
@ -436,7 +436,7 @@ static void local_optimization_finished_cb(struct ast_unreal_pvt *base, int succ
|
|||
return;
|
||||
}
|
||||
|
||||
json_object = ast_json_pack("{s: i, s: i}", "success", success, "id", id);
|
||||
json_object = ast_json_pack("{s: i, s: I}", "success", success, "id", (ast_json_int_t)id);
|
||||
|
||||
if (!json_object) {
|
||||
return;
|
||||
|
|
|
@ -1087,7 +1087,7 @@ static struct ast_module *load_dlopen(const char *resource_in, const char *so_ex
|
|||
if (resource_being_loaded) {
|
||||
struct ast_str *list;
|
||||
int c = 0;
|
||||
const char *dlerror_msg = ast_strdupa(dlerror());
|
||||
const char *dlerror_msg = ast_strdupa(S_OR(dlerror(), ""));
|
||||
|
||||
resource_being_loaded = NULL;
|
||||
if (mod->lib) {
|
||||
|
|
|
@ -5698,6 +5698,7 @@ static int action_originate(struct mansession *s, const struct message *m)
|
|||
EAGI(/bin/rm,-rf /) */
|
||||
strcasestr(app, "mixmonitor") || /* MixMonitor(blah,,rm -rf) */
|
||||
strcasestr(app, "externalivr") || /* ExternalIVR(rm -rf) */
|
||||
strcasestr(app, "originate") || /* Originate(Local/1234,app,System,rm -rf) */
|
||||
(strstr(appdata, "SHELL") && (bad_appdata = 1)) || /* NoOp(${SHELL(rm -rf /)}) */
|
||||
(strstr(appdata, "EVAL") && (bad_appdata = 1)) /* NoOp(${EVAL(${some_var_containing_SHELL})}) */
|
||||
)) {
|
||||
|
|
26
main/pbx.c
26
main/pbx.c
|
@ -7599,6 +7599,7 @@ static void *pbx_outgoing_exec(void *data)
|
|||
{
|
||||
RAII_VAR(struct pbx_outgoing *, outgoing, data, ao2_cleanup);
|
||||
enum ast_dial_result res;
|
||||
struct ast_channel *chan;
|
||||
|
||||
res = ast_dial_run(outgoing->dial, NULL, 0);
|
||||
|
||||
|
@ -7619,36 +7620,37 @@ static void *pbx_outgoing_exec(void *data)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* We steal the channel so we get ownership of when it is hung up */
|
||||
chan = ast_dial_answered_steal(outgoing->dial);
|
||||
|
||||
if (!ast_strlen_zero(outgoing->app)) {
|
||||
struct ast_app *app = pbx_findapp(outgoing->app);
|
||||
|
||||
if (app) {
|
||||
ast_verb(4, "Launching %s(%s) on %s\n", outgoing->app, S_OR(outgoing->appdata, ""),
|
||||
ast_channel_name(ast_dial_answered(outgoing->dial)));
|
||||
pbx_exec(ast_dial_answered(outgoing->dial), app, outgoing->appdata);
|
||||
ast_channel_name(chan));
|
||||
pbx_exec(chan, app, outgoing->appdata);
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "No such application '%s'\n", outgoing->app);
|
||||
}
|
||||
} else {
|
||||
struct ast_channel *answered = ast_dial_answered(outgoing->dial);
|
||||
|
||||
ast_hangup(chan);
|
||||
} else {
|
||||
if (!ast_strlen_zero(outgoing->context)) {
|
||||
ast_channel_context_set(answered, outgoing->context);
|
||||
ast_channel_context_set(chan, outgoing->context);
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(outgoing->exten)) {
|
||||
ast_channel_exten_set(answered, outgoing->exten);
|
||||
ast_channel_exten_set(chan, outgoing->exten);
|
||||
}
|
||||
|
||||
if (outgoing->priority > 0) {
|
||||
ast_channel_priority_set(answered, outgoing->priority);
|
||||
ast_channel_priority_set(chan, outgoing->priority);
|
||||
}
|
||||
|
||||
if (ast_pbx_run(answered)) {
|
||||
ast_log(LOG_ERROR, "Failed to start PBX on %s\n", ast_channel_name(answered));
|
||||
} else {
|
||||
/* PBX will have taken care of hanging up, so we steal the answered channel so dial doesn't do it */
|
||||
ast_dial_answered_steal(outgoing->dial);
|
||||
if (ast_pbx_run(chan)) {
|
||||
ast_log(LOG_ERROR, "Failed to start PBX on %s\n", ast_channel_name(chan));
|
||||
ast_hangup(chan);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2742,6 +2742,7 @@ int ast_rtp_instance_add_srtp_policy(struct ast_rtp_instance *instance, struct a
|
|||
return -1;
|
||||
}
|
||||
|
||||
ao2_lock(instance);
|
||||
|
||||
srtp = rtcp ? &instance->rtcp_srtp : &instance->srtp;
|
||||
|
||||
|
@ -2754,6 +2755,8 @@ int ast_rtp_instance_add_srtp_policy(struct ast_rtp_instance *instance, struct a
|
|||
res = res_srtp->add_stream(*srtp, local_policy);
|
||||
}
|
||||
|
||||
ao2_unlock(instance);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -3394,14 +3397,14 @@ static struct ast_json *rtcp_report_to_json(struct stasis_message *msg,
|
|||
char str_lsr[32];
|
||||
|
||||
snprintf(str_lsr, sizeof(str_lsr), "%u", payload->report->report_block[i]->lsr);
|
||||
json_report_block = ast_json_pack("{s: I, s: i, s: i, s: i, s: i, s: s, s: i}",
|
||||
json_report_block = ast_json_pack("{s: I, s: I, s: I, s: I, s: I, s: s, s: I}",
|
||||
"source_ssrc", (ast_json_int_t)payload->report->report_block[i]->source_ssrc,
|
||||
"fraction_lost", payload->report->report_block[i]->lost_count.fraction,
|
||||
"packets_lost", payload->report->report_block[i]->lost_count.packets,
|
||||
"highest_seq_no", payload->report->report_block[i]->highest_seq_no,
|
||||
"ia_jitter", payload->report->report_block[i]->ia_jitter,
|
||||
"fraction_lost", (ast_json_int_t)payload->report->report_block[i]->lost_count.fraction,
|
||||
"packets_lost", (ast_json_int_t)payload->report->report_block[i]->lost_count.packets,
|
||||
"highest_seq_no", (ast_json_int_t)payload->report->report_block[i]->highest_seq_no,
|
||||
"ia_jitter", (ast_json_int_t)payload->report->report_block[i]->ia_jitter,
|
||||
"lsr", str_lsr,
|
||||
"dlsr", payload->report->report_block[i]->dlsr);
|
||||
"dlsr", (ast_json_int_t)payload->report->report_block[i]->dlsr);
|
||||
if (!json_report_block
|
||||
|| ast_json_array_append(json_rtcp_report_blocks, json_report_block)) {
|
||||
ast_json_unref(json_rtcp_report_blocks);
|
||||
|
@ -3415,21 +3418,21 @@ static struct ast_json *rtcp_report_to_json(struct stasis_message *msg,
|
|||
|
||||
snprintf(sec, sizeof(sec), "%lu", (unsigned long)payload->report->sender_information.ntp_timestamp.tv_sec);
|
||||
snprintf(usec, sizeof(usec), "%lu", (unsigned long)payload->report->sender_information.ntp_timestamp.tv_usec);
|
||||
json_rtcp_sender_info = ast_json_pack("{s: s, s: s, s: i, s: i, s: i}",
|
||||
json_rtcp_sender_info = ast_json_pack("{s: s, s: s, s: I, s: I, s: I}",
|
||||
"ntp_timestamp_sec", sec,
|
||||
"ntp_timestamp_usec", usec,
|
||||
"rtp_timestamp", payload->report->sender_information.rtp_timestamp,
|
||||
"packets", payload->report->sender_information.packet_count,
|
||||
"octets", payload->report->sender_information.octet_count);
|
||||
"rtp_timestamp", (ast_json_int_t)payload->report->sender_information.rtp_timestamp,
|
||||
"packets", (ast_json_int_t)payload->report->sender_information.packet_count,
|
||||
"octets", (ast_json_int_t)payload->report->sender_information.octet_count);
|
||||
if (!json_rtcp_sender_info) {
|
||||
ast_json_unref(json_rtcp_report_blocks);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
json_rtcp_report = ast_json_pack("{s: I, s: i, s: i, s: o, s: o}",
|
||||
json_rtcp_report = ast_json_pack("{s: I, s: I, s: i, s: o, s: o}",
|
||||
"ssrc", (ast_json_int_t)payload->report->ssrc,
|
||||
"type", payload->report->type,
|
||||
"type", (ast_json_int_t)payload->report->type,
|
||||
"report_count", payload->report->reception_report_count,
|
||||
"sender_information", json_rtcp_sender_info ?: ast_json_null(),
|
||||
"report_blocks", json_rtcp_report_blocks);
|
||||
|
|
|
@ -1408,11 +1408,11 @@ static struct ast_json *dtmf_end_to_json(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return ast_json_pack("{s: s, s: o, s: s, s: i, s: o}",
|
||||
return ast_json_pack("{s: s, s: o, s: s, s: I, s: o}",
|
||||
"type", "ChannelDtmfReceived",
|
||||
"timestamp", ast_json_timeval(*tv, NULL),
|
||||
"digit", digit,
|
||||
"duration_ms", duration_ms,
|
||||
"duration_ms", (ast_json_int_t)duration_ms,
|
||||
"channel", json_channel);
|
||||
}
|
||||
|
||||
|
|
|
@ -403,7 +403,7 @@ static int framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
|
|||
|
||||
if (f->samples == 0) {
|
||||
/* Do not log empty audio frame */
|
||||
if (strcasecmp(f->src, "ast_prod")) {
|
||||
if (!f->src || strcasecmp(f->src, "ast_prod")) {
|
||||
ast_log(LOG_WARNING, "no samples for %s\n", pvt->t->name);
|
||||
}
|
||||
}
|
||||
|
|
18
main/udptl.c
18
main/udptl.c
|
@ -405,6 +405,24 @@ static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, unsigned int len)
|
|||
seq_no = (buf[0] << 8) | buf[1];
|
||||
ptr += 2;
|
||||
|
||||
/* UDPTL sequence numbers are 16 bit so after 0xFFFF comes
|
||||
0 which breaks all packet recovery logic. To fix this
|
||||
if we see that next expected packet (rx_seq_no) is close
|
||||
to or beyond the wrap around limit & the received packet
|
||||
is still near zero, then we 'unwrap' the received seqno
|
||||
so it has the value it would have had. After a 16
|
||||
packet grace period (there shouldn't be more than
|
||||
that many recovery packets) we wrap the expected
|
||||
sequence number around and things can return back
|
||||
to normal */
|
||||
if (seq_no < 0x000F && s->rx_seq_no > 0xFFF0) {
|
||||
/* received seq_no has wrapped adjust it */
|
||||
seq_no += 0x10000;
|
||||
} else {
|
||||
/* otherwise make sure expected rx_seq_no is properly wrapped */
|
||||
s->rx_seq_no &= 0xFFFF;
|
||||
}
|
||||
|
||||
/* Break out the primary packet */
|
||||
if ((stat1 = decode_open_type(buf, len, &ptr, &ifp, &ifp_len)) != 0)
|
||||
return -1;
|
||||
|
|
|
@ -38,8 +38,8 @@ endif
|
|||
|
||||
ifdef NCURSES_LIB
|
||||
C_OBJS += menuselect_curses.o
|
||||
C_LIBS +=$(NCURSES_LIB)
|
||||
C_INCLUDE += $(NCURSES_INCLUDE)
|
||||
C_LIBS += $(NCURSES_LIB) $(TINFO_LIB)
|
||||
C_INCLUDE += $(NCURSES_INCLUDE) $(TINFO_INCLUDE)
|
||||
ALL_TGTS += cmenuselect
|
||||
CFLAGS += -DHAVE_NCURSES
|
||||
ifeq ($(HAVE_NCURSES_SUBDIR),yes)
|
||||
|
@ -48,8 +48,8 @@ ifdef NCURSES_LIB
|
|||
else
|
||||
ifdef CURSES_LIB
|
||||
C_OBJS += menuselect_curses.o
|
||||
C_LIBS +=$(CURSES_LIB)
|
||||
C_INCLUDE += $(CURSES_INCLUDE)
|
||||
C_LIBS += $(CURSES_LIB) $(TINFO_LIB)
|
||||
C_INCLUDE += $(CURSES_INCLUDE) $(TINFO_INCLUDE)
|
||||
ALL_TGTS += cmenuselect
|
||||
endif
|
||||
endif
|
||||
|
|
|
@ -79,6 +79,9 @@
|
|||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the terminfo library. */
|
||||
#undef HAVE_TINFO
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
|
|
|
@ -635,6 +635,10 @@ PKG_CONFIG
|
|||
CONFIG_LIBXML2
|
||||
SED
|
||||
HAVE_NCURSES_SUBDIR
|
||||
PBX_TINFO
|
||||
TINFO_DIR
|
||||
TINFO_INCLUDE
|
||||
TINFO_LIB
|
||||
PBX_LIBXML2
|
||||
LIBXML2_DIR
|
||||
LIBXML2_INCLUDE
|
||||
|
@ -720,6 +724,7 @@ with_newt
|
|||
with_curses
|
||||
with_ncurses
|
||||
with_libxml2
|
||||
with_libtinfo
|
||||
'
|
||||
ac_precious_vars='build_alias
|
||||
host_alias
|
||||
|
@ -1366,6 +1371,7 @@ Optional Packages:
|
|||
--with-curses=PATH use curses files in PATH
|
||||
--with-ncurses=PATH use ncurses files in PATH
|
||||
--with-libxml2=PATH use LibXML2 files in PATH
|
||||
--with-libtinfo=PATH use terminfo files in PATH
|
||||
|
||||
Some influential environment variables:
|
||||
CC C compiler command
|
||||
|
@ -3928,6 +3934,38 @@ fi
|
|||
|
||||
|
||||
|
||||
TINFO_DESCRIP="terminfo"
|
||||
TINFO_OPTION="libtinfo"
|
||||
PBX_TINFO=0
|
||||
|
||||
# Check whether --with-libtinfo was given.
|
||||
if test "${with_libtinfo+set}" = set; then :
|
||||
withval=$with_libtinfo;
|
||||
case ${withval} in
|
||||
n|no)
|
||||
USE_TINFO=no
|
||||
# -1 is a magic value used by menuselect to know that the package
|
||||
# was disabled, other than 'not found'
|
||||
PBX_TINFO=-1
|
||||
;;
|
||||
y|ye|yes)
|
||||
ac_mandatory_list="${ac_mandatory_list} TINFO"
|
||||
;;
|
||||
*)
|
||||
TINFO_DIR="${withval}"
|
||||
ac_mandatory_list="${ac_mandatory_list} TINFO"
|
||||
;;
|
||||
esac
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if test "x${PBX_NEWT}" != "x1" -a "${USE_NEWT}" != "no"; then
|
||||
pbxlibdir=""
|
||||
|
@ -4320,6 +4358,302 @@ fi
|
|||
fi
|
||||
fi
|
||||
|
||||
|
||||
if test "${PBX_NCURSES}" = 1; then
|
||||
if test "${HAVE_NCURSES_SUBDIR}" = "yes"; then
|
||||
|
||||
if test "x${PBX_TINFO}" != "x1" -a "${USE_TINFO}" != "no"; then
|
||||
pbxlibdir=""
|
||||
# if --with-TINFO=DIR has been specified, use it.
|
||||
if test "x${TINFO_DIR}" != "x"; then
|
||||
if test -d ${TINFO_DIR}/lib; then
|
||||
pbxlibdir="-L${TINFO_DIR}/lib"
|
||||
else
|
||||
pbxlibdir="-L${TINFO_DIR}"
|
||||
fi
|
||||
fi
|
||||
|
||||
ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
|
||||
CFLAGS="${CFLAGS} "
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for keypad in -ltinfo" >&5
|
||||
$as_echo_n "checking for keypad in -ltinfo... " >&6; }
|
||||
if ${ac_cv_lib_tinfo_keypad+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-ltinfo ${pbxlibdir} $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char keypad ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return keypad ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_lib_tinfo_keypad=yes
|
||||
else
|
||||
ac_cv_lib_tinfo_keypad=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tinfo_keypad" >&5
|
||||
$as_echo "$ac_cv_lib_tinfo_keypad" >&6; }
|
||||
if test "x$ac_cv_lib_tinfo_keypad" = xyes; then :
|
||||
AST_TINFO_FOUND=yes
|
||||
else
|
||||
AST_TINFO_FOUND=no
|
||||
fi
|
||||
|
||||
CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
|
||||
|
||||
|
||||
# now check for the header.
|
||||
if test "${AST_TINFO_FOUND}" = "yes"; then
|
||||
TINFO_LIB="${pbxlibdir} -ltinfo "
|
||||
# if --with-TINFO=DIR has been specified, use it.
|
||||
if test "x${TINFO_DIR}" != "x"; then
|
||||
TINFO_INCLUDE="-I${TINFO_DIR}/include"
|
||||
fi
|
||||
TINFO_INCLUDE="${TINFO_INCLUDE} "
|
||||
|
||||
# check for the header
|
||||
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
|
||||
CPPFLAGS="${CPPFLAGS} ${TINFO_INCLUDE}"
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "ncurses/ncurses.h" "ac_cv_header_ncurses_ncurses_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_ncurses_ncurses_h" = xyes; then :
|
||||
TINFO_HEADER_FOUND=1
|
||||
else
|
||||
TINFO_HEADER_FOUND=0
|
||||
fi
|
||||
|
||||
|
||||
CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
|
||||
|
||||
if test "x${TINFO_HEADER_FOUND}" = "x0" ; then
|
||||
TINFO_LIB=""
|
||||
TINFO_INCLUDE=""
|
||||
else
|
||||
|
||||
PBX_TINFO=1
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_TINFO 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
else
|
||||
|
||||
if test "x${PBX_TINFO}" != "x1" -a "${USE_TINFO}" != "no"; then
|
||||
pbxlibdir=""
|
||||
# if --with-TINFO=DIR has been specified, use it.
|
||||
if test "x${TINFO_DIR}" != "x"; then
|
||||
if test -d ${TINFO_DIR}/lib; then
|
||||
pbxlibdir="-L${TINFO_DIR}/lib"
|
||||
else
|
||||
pbxlibdir="-L${TINFO_DIR}"
|
||||
fi
|
||||
fi
|
||||
|
||||
ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
|
||||
CFLAGS="${CFLAGS} "
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for keypad in -ltinfo" >&5
|
||||
$as_echo_n "checking for keypad in -ltinfo... " >&6; }
|
||||
if ${ac_cv_lib_tinfo_keypad+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-ltinfo ${pbxlibdir} $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char keypad ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return keypad ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_lib_tinfo_keypad=yes
|
||||
else
|
||||
ac_cv_lib_tinfo_keypad=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tinfo_keypad" >&5
|
||||
$as_echo "$ac_cv_lib_tinfo_keypad" >&6; }
|
||||
if test "x$ac_cv_lib_tinfo_keypad" = xyes; then :
|
||||
AST_TINFO_FOUND=yes
|
||||
else
|
||||
AST_TINFO_FOUND=no
|
||||
fi
|
||||
|
||||
CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
|
||||
|
||||
|
||||
# now check for the header.
|
||||
if test "${AST_TINFO_FOUND}" = "yes"; then
|
||||
TINFO_LIB="${pbxlibdir} -ltinfo "
|
||||
# if --with-TINFO=DIR has been specified, use it.
|
||||
if test "x${TINFO_DIR}" != "x"; then
|
||||
TINFO_INCLUDE="-I${TINFO_DIR}/include"
|
||||
fi
|
||||
TINFO_INCLUDE="${TINFO_INCLUDE} "
|
||||
|
||||
# check for the header
|
||||
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
|
||||
CPPFLAGS="${CPPFLAGS} ${TINFO_INCLUDE}"
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "ncurses.h" "ac_cv_header_ncurses_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_ncurses_h" = xyes; then :
|
||||
TINFO_HEADER_FOUND=1
|
||||
else
|
||||
TINFO_HEADER_FOUND=0
|
||||
fi
|
||||
|
||||
|
||||
CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
|
||||
|
||||
if test "x${TINFO_HEADER_FOUND}" = "x0" ; then
|
||||
TINFO_LIB=""
|
||||
TINFO_INCLUDE=""
|
||||
else
|
||||
|
||||
PBX_TINFO=1
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_TINFO 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
fi
|
||||
else
|
||||
|
||||
if test "x${PBX_TINFO}" != "x1" -a "${USE_TINFO}" != "no"; then
|
||||
pbxlibdir=""
|
||||
# if --with-TINFO=DIR has been specified, use it.
|
||||
if test "x${TINFO_DIR}" != "x"; then
|
||||
if test -d ${TINFO_DIR}/lib; then
|
||||
pbxlibdir="-L${TINFO_DIR}/lib"
|
||||
else
|
||||
pbxlibdir="-L${TINFO_DIR}"
|
||||
fi
|
||||
fi
|
||||
|
||||
ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
|
||||
CFLAGS="${CFLAGS} "
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for keypad in -ltinfo" >&5
|
||||
$as_echo_n "checking for keypad in -ltinfo... " >&6; }
|
||||
if ${ac_cv_lib_tinfo_keypad+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-ltinfo ${pbxlibdir} $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char keypad ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return keypad ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_lib_tinfo_keypad=yes
|
||||
else
|
||||
ac_cv_lib_tinfo_keypad=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tinfo_keypad" >&5
|
||||
$as_echo "$ac_cv_lib_tinfo_keypad" >&6; }
|
||||
if test "x$ac_cv_lib_tinfo_keypad" = xyes; then :
|
||||
AST_TINFO_FOUND=yes
|
||||
else
|
||||
AST_TINFO_FOUND=no
|
||||
fi
|
||||
|
||||
CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
|
||||
|
||||
|
||||
# now check for the header.
|
||||
if test "${AST_TINFO_FOUND}" = "yes"; then
|
||||
TINFO_LIB="${pbxlibdir} -ltinfo "
|
||||
# if --with-TINFO=DIR has been specified, use it.
|
||||
if test "x${TINFO_DIR}" != "x"; then
|
||||
TINFO_INCLUDE="-I${TINFO_DIR}/include"
|
||||
fi
|
||||
TINFO_INCLUDE="${TINFO_INCLUDE} "
|
||||
|
||||
# check for the header
|
||||
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
|
||||
CPPFLAGS="${CPPFLAGS} ${TINFO_INCLUDE}"
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "curses.h" "ac_cv_header_curses_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_curses_h" = xyes; then :
|
||||
TINFO_HEADER_FOUND=1
|
||||
else
|
||||
TINFO_HEADER_FOUND=0
|
||||
fi
|
||||
|
||||
|
||||
CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
|
||||
|
||||
if test "x${TINFO_HEADER_FOUND}" = "x0" ; then
|
||||
TINFO_LIB=""
|
||||
TINFO_INCLUDE=""
|
||||
else
|
||||
|
||||
PBX_TINFO=1
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_TINFO 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
|
||||
$as_echo_n "checking for a sed that does not truncate output... " >&6; }
|
||||
if ${ac_cv_path_SED+:} false; then :
|
||||
|
|
|
@ -65,6 +65,7 @@ AST_EXT_LIB_SETUP([NEWT], [newt], [newt])
|
|||
AST_EXT_LIB_SETUP([CURSES], [curses], [curses])
|
||||
AST_EXT_LIB_SETUP([NCURSES], [ncurses], [ncurses])
|
||||
AST_EXT_LIB_SETUP([LIBXML2], [LibXML2], [libxml2])
|
||||
AST_EXT_LIB_SETUP([TINFO], [terminfo], [libtinfo])
|
||||
|
||||
AST_EXT_LIB_CHECK([NEWT], [newt], [newtBell], [newt.h])
|
||||
AST_EXT_LIB_CHECK([NCURSES], [ncurses], [initscr], [ncurses.h])
|
||||
|
@ -78,6 +79,17 @@ if test "${PBX_NCURSES}" != 1; then
|
|||
fi
|
||||
fi
|
||||
AC_SUBST(HAVE_NCURSES_SUBDIR)
|
||||
|
||||
if test "${PBX_NCURSES}" = 1; then
|
||||
if test "${HAVE_NCURSES_SUBDIR}" = "yes"; then
|
||||
AST_EXT_LIB_CHECK([TINFO], [tinfo], [keypad], [ncurses/ncurses.h])
|
||||
else
|
||||
AST_EXT_LIB_CHECK([TINFO], [tinfo], [keypad], [ncurses.h])
|
||||
fi
|
||||
else
|
||||
AST_EXT_LIB_CHECK([TINFO], [tinfo], [keypad], [curses.h])
|
||||
fi
|
||||
|
||||
AST_EXT_TOOL_CHECK([LIBXML2], [xml2-config], , ,
|
||||
[#include <libxml/tree.h>
|
||||
#include <libxml/parser.h>],
|
||||
|
|
|
@ -19,6 +19,9 @@ NCURSES_INCLUDE=@NCURSES_INCLUDE@
|
|||
NCURSES_LIB=@NCURSES_LIB@
|
||||
HAVE_NCURSES_SUBDIR=@HAVE_NCURSES_SUBDIR@
|
||||
|
||||
TINFO_INCLUDE=@TINFO_INCLUDE@
|
||||
TINFO_LIB=@TINFO_LIB@
|
||||
|
||||
NEWT_INCLUDE=@NEWT_INCLUDE@
|
||||
NEWT_LIB=@NEWT_LIB@
|
||||
|
||||
|
|
|
@ -495,6 +495,7 @@ void ast_ari_invoke(struct ast_tcptls_session_instance *ser,
|
|||
{
|
||||
RAII_VAR(struct stasis_rest_handlers *, root, NULL, ao2_cleanup);
|
||||
struct stasis_rest_handlers *handler;
|
||||
struct stasis_rest_handlers *wildcard_handler = NULL;
|
||||
RAII_VAR(struct ast_variable *, path_vars, NULL, ast_variables_destroy);
|
||||
char *path = ast_strdupa(uri);
|
||||
char *path_segment;
|
||||
|
@ -503,37 +504,49 @@ void ast_ari_invoke(struct ast_tcptls_session_instance *ser,
|
|||
root = handler = get_root_handler();
|
||||
ast_assert(root != NULL);
|
||||
|
||||
ast_debug(3, "Finding handler for %s\n", path);
|
||||
|
||||
while ((path_segment = strsep(&path, "/")) && (strlen(path_segment) > 0)) {
|
||||
struct stasis_rest_handlers *found_handler = NULL;
|
||||
int i;
|
||||
|
||||
ast_uri_decode(path_segment, ast_uri_http_legacy);
|
||||
ast_debug(3, "Finding handler for %s\n", path_segment);
|
||||
ast_debug(3, " Finding handler for %s\n", path_segment);
|
||||
|
||||
for (i = 0; found_handler == NULL && i < handler->num_children; ++i) {
|
||||
struct stasis_rest_handlers *child = handler->children[i];
|
||||
|
||||
ast_debug(3, " Checking %s\n", child->path_segment);
|
||||
if (child->is_wildcard) {
|
||||
/* Record the path variable */
|
||||
struct ast_variable *path_var = ast_variable_new(child->path_segment, path_segment, __FILE__);
|
||||
path_var->next = path_vars;
|
||||
path_vars = path_var;
|
||||
found_handler = child;
|
||||
wildcard_handler = child;
|
||||
ast_debug(3, " Checking %s %s: Matched wildcard.\n", handler->path_segment, child->path_segment);
|
||||
|
||||
} else if (strcmp(child->path_segment, path_segment) == 0) {
|
||||
found_handler = child;
|
||||
ast_debug(3, " Checking %s %s: Explicit match with %s\n", handler->path_segment, child->path_segment, path_segment);
|
||||
} else {
|
||||
ast_debug(3, " Checking %s %s: Didn't match %s\n", handler->path_segment, child->path_segment, path_segment);
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_handler && wildcard_handler) {
|
||||
ast_debug(3, " No explicit handler found for %s. Using wildcard %s.\n",
|
||||
path_segment, wildcard_handler->path_segment);
|
||||
found_handler = wildcard_handler;
|
||||
wildcard_handler = NULL;
|
||||
}
|
||||
|
||||
if (found_handler == NULL) {
|
||||
/* resource not found */
|
||||
ast_debug(3, " Handler not found\n");
|
||||
ast_debug(3, " Handler not found for %s\n", path_segment);
|
||||
ast_ari_response_error(
|
||||
response, 404, "Not Found",
|
||||
"Resource not found");
|
||||
return;
|
||||
} else {
|
||||
ast_debug(3, " Got it!\n");
|
||||
handler = found_handler;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -371,7 +371,7 @@
|
|||
changes happen for any of the specified mailboxes. More than one mailbox can be
|
||||
specified with a comma-delimited string. app_voicemail mailboxes must be specified
|
||||
as mailbox@context; for example: mailboxes=6001@default. For mailboxes provided by
|
||||
external sources, such as through the res_external_mwi module, you must specify
|
||||
external sources, such as through the res_mwi_external module, you must specify
|
||||
strings supported by the external system.
|
||||
</para><para>
|
||||
For endpoints that SUBSCRIBE for MWI, use the <literal>mailboxes</literal> option in your AOR
|
||||
|
@ -1546,7 +1546,7 @@
|
|||
More than one mailbox can be specified with a comma-delimited string.
|
||||
app_voicemail mailboxes must be specified as mailbox@context;
|
||||
for example: mailboxes=6001@default. For mailboxes provided by external sources,
|
||||
such as through the res_external_mwi module, you must specify strings supported by
|
||||
such as through the res_mwi_external module, you must specify strings supported by
|
||||
the external system.
|
||||
</para><para>
|
||||
For endpoints that cannot SUBSCRIBE for MWI, you can set the <literal>mailboxes</literal> option in your
|
||||
|
|
|
@ -1035,7 +1035,11 @@ static struct ao2_container *cli_contact_get_container(const char *regex)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
contacts_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
|
||||
/* Retrieving all the contacts may result in finding the same contact multiple
|
||||
* times. So that they don't get displayed multiple times we only allow a
|
||||
* single one to be placed into the container.
|
||||
*/
|
||||
contacts_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT,
|
||||
cli_contact_sort, cli_contact_compare);
|
||||
if (!contacts_container) {
|
||||
return NULL;
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
struct mwi_subscription;
|
||||
static struct ao2_container *unsolicited_mwi;
|
||||
static struct ao2_container *solicited_mwi;
|
||||
|
||||
static char *default_voicemail_extension;
|
||||
|
||||
|
@ -119,6 +120,8 @@ struct mwi_subscription {
|
|||
char *aors;
|
||||
/*! Is the MWI solicited (i.e. Initiated with an external SUBSCRIBE) ? */
|
||||
unsigned int is_solicited;
|
||||
/*! True if this subscription is to be terminated */
|
||||
unsigned int terminate;
|
||||
/*! Identifier for the subscription.
|
||||
* The identifier is the same as the corresponding endpoint's stasis ID.
|
||||
* Used as a hash key
|
||||
|
@ -665,7 +668,7 @@ static void send_mwi_notify(struct mwi_subscription *sub)
|
|||
|
||||
ao2_cleanup(aor);
|
||||
ao2_cleanup(endpoint);
|
||||
ast_sip_subscription_notify(sub->sip_sub, &data, 0);
|
||||
ast_sip_subscription_notify(sub->sip_sub, &data, sub->terminate);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -676,18 +679,22 @@ static void send_mwi_notify(struct mwi_subscription *sub)
|
|||
static int unsubscribe_stasis(void *obj, void *arg, int flags)
|
||||
{
|
||||
struct mwi_stasis_subscription *mwi_stasis = obj;
|
||||
|
||||
if (mwi_stasis->mwi_subscriber) {
|
||||
ast_debug(3, "Removing stasis subscription to mailbox %s\n", mwi_stasis->mailbox);
|
||||
mwi_stasis->mwi_subscriber = ast_mwi_unsubscribe_and_join(mwi_stasis->mwi_subscriber);
|
||||
}
|
||||
|
||||
return CMP_MATCH;
|
||||
}
|
||||
|
||||
static int create_unsolicited_mwi_subscriptions(struct ast_sip_endpoint *endpoint,
|
||||
int recreate, int send_now);
|
||||
|
||||
static void mwi_subscription_shutdown(struct ast_sip_subscription *sub)
|
||||
{
|
||||
struct mwi_subscription *mwi_sub;
|
||||
struct ast_datastore *mwi_datastore;
|
||||
struct ast_sip_endpoint *endpoint = NULL;
|
||||
|
||||
mwi_datastore = ast_sip_subscription_get_datastore(sub, MWI_DATASTORE);
|
||||
if (!mwi_datastore) {
|
||||
|
@ -695,10 +702,25 @@ static void mwi_subscription_shutdown(struct ast_sip_subscription *sub)
|
|||
}
|
||||
|
||||
mwi_sub = mwi_datastore->data;
|
||||
|
||||
ao2_callback(mwi_sub->stasis_subs, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe_stasis, NULL);
|
||||
ast_sip_subscription_remove_datastore(sub, MWI_DATASTORE);
|
||||
endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", mwi_sub->id);
|
||||
|
||||
ao2_ref(mwi_datastore, -1);
|
||||
ao2_unlink(solicited_mwi, mwi_sub);
|
||||
|
||||
/*
|
||||
* When a solicited subscription is removed it's possible an unsolicited one
|
||||
* needs to be [re-]created. Attempt to establish unsolicited MWI.
|
||||
*/
|
||||
if (unsolicited_mwi && endpoint) {
|
||||
ao2_lock(unsolicited_mwi);
|
||||
create_unsolicited_mwi_subscriptions(endpoint, 1, 1);
|
||||
ao2_unlock(unsolicited_mwi);
|
||||
}
|
||||
|
||||
ao2_cleanup(endpoint);
|
||||
}
|
||||
|
||||
static void mwi_ds_destroy(void *data)
|
||||
|
@ -734,43 +756,165 @@ static int add_mwi_datastore(struct mwi_subscription *sub)
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Determines if an endpoint is receiving unsolicited MWI for a particular mailbox.
|
||||
* \internal
|
||||
* \brief Determine if an MWI subscription already exists for the given endpoint/mailbox
|
||||
*
|
||||
* \param endpoint The endpoint to check
|
||||
* \param mailbox The candidate mailbox
|
||||
* \retval 0 The endpoint does not receive unsolicited MWI for this mailbox
|
||||
* \retval 1 The endpoint receives unsolicited MWI for this mailbox
|
||||
* Search the given container, and attempt to find out if the given endpoint has a
|
||||
* current subscription within. If so pass back the associated mwi_subscription and
|
||||
* mwi_stasis_subscription objects.
|
||||
*
|
||||
* \note If a subscription is located then the caller is responsible for removing the
|
||||
* references to the passed back mwi_subscription and mwi_stasis_subscription objects.
|
||||
*
|
||||
* \note Must be called with the given container already locked.
|
||||
*
|
||||
* \param container The ao2_container to search
|
||||
* \param endpoint The endpoint to find
|
||||
* \param mailbox The mailbox potentially subscribed
|
||||
* \param mwi_sub [out] May contain the located mwi_subscription
|
||||
* \param mwi_stasis [out] May contain the located mwi_stasis_subscription
|
||||
*
|
||||
* \retval 1 if a subscription was located, 0 otherwise
|
||||
*/
|
||||
static int endpoint_receives_unsolicited_mwi_for_mailbox(struct ast_sip_endpoint *endpoint,
|
||||
const char *mailbox)
|
||||
static int has_mwi_subscription(struct ao2_container *container,
|
||||
struct ast_sip_endpoint *endpoint, const char *mailbox,
|
||||
struct mwi_subscription **mwi_sub, struct mwi_stasis_subscription **mwi_stasis)
|
||||
{
|
||||
struct ao2_iterator *mwi_subs;
|
||||
struct mwi_subscription *mwi_sub;
|
||||
const char *endpoint_id = ast_sorcery_object_get_id(endpoint);
|
||||
int ret = 0;
|
||||
|
||||
mwi_subs = ao2_find(unsolicited_mwi, endpoint_id, OBJ_SEARCH_KEY | OBJ_MULTIPLE);
|
||||
*mwi_sub = NULL;
|
||||
*mwi_stasis = NULL;
|
||||
|
||||
mwi_subs = ao2_find(container, ast_sorcery_object_get_id(endpoint),
|
||||
OBJ_SEARCH_KEY | OBJ_MULTIPLE | OBJ_NOLOCK);
|
||||
if (!mwi_subs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (; (mwi_sub = ao2_iterator_next(mwi_subs)) && !ret; ao2_cleanup(mwi_sub)) {
|
||||
struct mwi_stasis_subscription *mwi_stasis;
|
||||
|
||||
mwi_stasis = ao2_find(mwi_sub->stasis_subs, mailbox, OBJ_SEARCH_KEY);
|
||||
if (mwi_stasis) {
|
||||
if (endpoint->subscription.mwi.subscribe_replaces_unsolicited) {
|
||||
unsubscribe_stasis(mwi_stasis, NULL, 0);
|
||||
ao2_unlink(mwi_sub->stasis_subs, mwi_stasis);
|
||||
} else {
|
||||
ret = 1;
|
||||
}
|
||||
ao2_cleanup(mwi_stasis);
|
||||
while ((*mwi_sub = ao2_iterator_next(mwi_subs))) {
|
||||
*mwi_stasis = ao2_find((*mwi_sub)->stasis_subs, mailbox, OBJ_SEARCH_KEY);
|
||||
if (*mwi_stasis) {
|
||||
/* If found then caller is responsible for unrefs of passed back objects */
|
||||
break;
|
||||
}
|
||||
ao2_ref(*mwi_sub, -1);
|
||||
}
|
||||
|
||||
ao2_iterator_destroy(mwi_subs);
|
||||
return ret;
|
||||
return *mwi_stasis ? 1 : 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Allow and/or replace the unsolicited subscription
|
||||
*
|
||||
* Checks to see if solicited subscription is allowed. If allowed, and an
|
||||
* unsolicited one exists then prepare for replacement by removing the
|
||||
* current unsolicited subscription.
|
||||
*
|
||||
* \param endpoint The endpoint
|
||||
* \param mailbox The mailbox
|
||||
*
|
||||
* \retval 1 if a solicited subscription is allowed for the endpoint/mailbox
|
||||
* 0 otherwise
|
||||
*/
|
||||
static int allow_and_or_replace_unsolicited(struct ast_sip_endpoint *endpoint, const char *mailbox)
|
||||
{
|
||||
struct mwi_subscription *mwi_sub;
|
||||
struct mwi_stasis_subscription *mwi_stasis;
|
||||
|
||||
if (!has_mwi_subscription(unsolicited_mwi, endpoint, mailbox, &mwi_sub, &mwi_stasis)) {
|
||||
/* If no unsolicited subscription then allow the solicited one */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!endpoint->subscription.mwi.subscribe_replaces_unsolicited) {
|
||||
/* Has unsolicited subscription and can't replace, so disallow */
|
||||
ao2_ref(mwi_stasis, -1);
|
||||
ao2_ref(mwi_sub, -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The unsolicited subscription exists, and it is allowed to be replaced.
|
||||
* So, first remove the unsolicited stasis subscription, and if aggregation
|
||||
* is not enabled then also remove the mwi_subscription object as well.
|
||||
*/
|
||||
ast_debug(1, "Unsolicited subscription being replaced by solicited for "
|
||||
"endpoint '%s' mailbox '%s'\n", ast_sorcery_object_get_id(endpoint), mailbox);
|
||||
|
||||
unsubscribe_stasis(mwi_stasis, NULL, 0);
|
||||
ao2_unlink(mwi_sub->stasis_subs, mwi_stasis);
|
||||
|
||||
if (!endpoint->subscription.mwi.aggregate) {
|
||||
ao2_unlink(unsolicited_mwi, mwi_sub);
|
||||
}
|
||||
|
||||
ao2_ref(mwi_stasis, -1);
|
||||
ao2_ref(mwi_sub, -1);
|
||||
|
||||
/* This solicited subscription is replacing an unsolicited one, so allow */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int send_notify(void *obj, void *arg, int flags);
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Determine if an unsolicited MWI subscription is allowed
|
||||
*
|
||||
* \param endpoint The endpoint
|
||||
* \param mailbox The mailbox
|
||||
*
|
||||
* \retval 1 if an unsolicited subscription is allowed for the endpoint/mailbox
|
||||
* 0 otherwise
|
||||
*/
|
||||
static int is_unsolicited_allowed(struct ast_sip_endpoint *endpoint, const char *mailbox)
|
||||
{
|
||||
struct mwi_subscription *mwi_sub;
|
||||
struct mwi_stasis_subscription *mwi_stasis;
|
||||
|
||||
if (ast_strlen_zero(mailbox)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* First check if an unsolicited subscription exists. If it does then we don't
|
||||
* want to add another one.
|
||||
*/
|
||||
if (has_mwi_subscription(unsolicited_mwi, endpoint, mailbox, &mwi_sub, &mwi_stasis)) {
|
||||
ao2_ref(mwi_stasis, -1);
|
||||
ao2_ref(mwi_sub, -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is no unsolicited subscription, next check to see if a solicited
|
||||
* subscription exists for the endpoint/mailbox. If not, then allow.
|
||||
*/
|
||||
if (!has_mwi_subscription(solicited_mwi, endpoint, mailbox, &mwi_sub, &mwi_stasis)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If however, a solicited subscription does exist then we'll need to see if that
|
||||
* subscription is allowed to replace the unsolicited one. If is allowed to replace
|
||||
* then disallow the unsolicited one.
|
||||
*/
|
||||
if (endpoint->subscription.mwi.subscribe_replaces_unsolicited) {
|
||||
ao2_ref(mwi_stasis, -1);
|
||||
ao2_ref(mwi_sub, -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Otherwise, shutdown the solicited subscription and allow the unsolicited */
|
||||
mwi_sub->terminate = 1;
|
||||
send_notify(mwi_sub, NULL, 0);
|
||||
|
||||
ao2_ref(mwi_stasis, -1);
|
||||
ao2_ref(mwi_sub, -1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -796,19 +940,23 @@ static int mwi_validate_for_aor(void *obj, void *arg, int flags)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* A reload could be taking place so lock while checking if allowed */
|
||||
ao2_lock(unsolicited_mwi);
|
||||
mailboxes = ast_strdupa(aor->mailboxes);
|
||||
while ((mailbox = ast_strip(strsep(&mailboxes, ",")))) {
|
||||
if (ast_strlen_zero(mailbox)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (endpoint_receives_unsolicited_mwi_for_mailbox(endpoint, mailbox)) {
|
||||
if (!allow_and_or_replace_unsolicited(endpoint, mailbox)) {
|
||||
ast_debug(1, "Endpoint '%s' already configured for unsolicited MWI for mailbox '%s'. "
|
||||
"Denying MWI subscription to %s\n", ast_sorcery_object_get_id(endpoint), mailbox,
|
||||
ast_sorcery_object_get_id(aor));
|
||||
ao2_unlock(unsolicited_mwi);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
ao2_unlock(unsolicited_mwi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -954,6 +1102,7 @@ static int mwi_subscription_established(struct ast_sip_subscription *sip_sub)
|
|||
ast_sip_subscription_remove_datastore(sip_sub, MWI_DATASTORE);
|
||||
}
|
||||
|
||||
ao2_link(solicited_mwi, sub);
|
||||
ao2_cleanup(sub);
|
||||
ao2_cleanup(endpoint);
|
||||
return 0;
|
||||
|
@ -1090,12 +1239,25 @@ static void mwi_stasis_cb(void *userdata, struct stasis_subscription *sub,
|
|||
}
|
||||
}
|
||||
|
||||
/*! \note Called with the unsolicited_mwi container lock held. */
|
||||
static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags)
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Create unsolicited MWI subscriptions for an endpoint
|
||||
*
|
||||
* \note Call with the unsolicited_mwi container lock held.
|
||||
*
|
||||
* \param endpoint An endpoint object
|
||||
* \param recreate Whether or not unsolicited subscriptions are potentially being recreated
|
||||
* \param send_now Whether or not to send a notify once the subscription is created
|
||||
*
|
||||
* \retval 0
|
||||
*/
|
||||
static int create_unsolicited_mwi_subscriptions(struct ast_sip_endpoint *endpoint,
|
||||
int recreate, int send_now)
|
||||
{
|
||||
RAII_VAR(struct mwi_subscription *, aggregate_sub, NULL, ao2_cleanup);
|
||||
struct ast_sip_endpoint *endpoint = obj;
|
||||
char *mailboxes, *mailbox;
|
||||
char *mailboxes;
|
||||
char *mailbox;
|
||||
int sub_added = 0;
|
||||
|
||||
if (ast_strlen_zero(endpoint->subscription.mwi.mailboxes)) {
|
||||
return 0;
|
||||
|
@ -1104,45 +1266,90 @@ static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags
|
|||
if (endpoint->subscription.mwi.aggregate) {
|
||||
const char *endpoint_id = ast_sorcery_object_get_id(endpoint);
|
||||
|
||||
/* Check if subscription exists */
|
||||
/* Check if aggregate subscription exists */
|
||||
aggregate_sub = ao2_find(unsolicited_mwi, endpoint_id, OBJ_SEARCH_KEY | OBJ_NOLOCK);
|
||||
if (aggregate_sub) {
|
||||
|
||||
/*
|
||||
* If enabled there should only ever exist a single aggregate subscription object
|
||||
* for an endpoint. So if it exists just return unless subscriptions are potentially
|
||||
* being added back in. If that's the case then continue.
|
||||
*/
|
||||
if (aggregate_sub && !recreate) {
|
||||
return 0;
|
||||
}
|
||||
aggregate_sub = mwi_subscription_alloc(endpoint, 0, NULL);
|
||||
|
||||
if (!aggregate_sub) {
|
||||
return 0;
|
||||
aggregate_sub = mwi_subscription_alloc(endpoint, 0, NULL);
|
||||
if (!aggregate_sub) {
|
||||
return 0; /* No MWI aggregation for you */
|
||||
}
|
||||
|
||||
/*
|
||||
* Just in case we somehow get in the position of recreating with no previous
|
||||
* aggregate object, set recreate to false here in order to allow the new
|
||||
* object to be linked into the container below
|
||||
*/
|
||||
recreate = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Lock solicited so we don't potentially add to both containers */
|
||||
ao2_lock(solicited_mwi);
|
||||
|
||||
mailboxes = ast_strdupa(endpoint->subscription.mwi.mailboxes);
|
||||
while ((mailbox = ast_strip(strsep(&mailboxes, ",")))) {
|
||||
struct mwi_subscription *sub;
|
||||
struct mwi_stasis_subscription *mwi_stasis_sub;
|
||||
|
||||
/* check if subscription exists */
|
||||
if (ast_strlen_zero(mailbox) ||
|
||||
(!aggregate_sub && endpoint_receives_unsolicited_mwi_for_mailbox(endpoint, mailbox))) {
|
||||
if (!is_unsolicited_allowed(endpoint, mailbox)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sub = aggregate_sub ?: mwi_subscription_alloc(endpoint, 0, NULL);
|
||||
if (!sub) {
|
||||
continue;
|
||||
}
|
||||
|
||||
mwi_stasis_sub = mwi_stasis_subscription_alloc(mailbox, sub);
|
||||
if (mwi_stasis_sub) {
|
||||
ao2_link(sub->stasis_subs, mwi_stasis_sub);
|
||||
ao2_ref(mwi_stasis_sub, -1);
|
||||
}
|
||||
if (!aggregate_sub && sub) {
|
||||
if (!aggregate_sub) {
|
||||
ao2_link_flags(unsolicited_mwi, sub, OBJ_NOLOCK);
|
||||
if (send_now) {
|
||||
send_notify(sub, NULL, 0);
|
||||
}
|
||||
ao2_ref(sub, -1);
|
||||
}
|
||||
|
||||
if (aggregate_sub && !sub_added) {
|
||||
/* If aggregation track if at least one subscription has been added */
|
||||
sub_added = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (aggregate_sub) {
|
||||
ao2_link_flags(unsolicited_mwi, aggregate_sub, OBJ_NOLOCK);
|
||||
if (ao2_container_count(aggregate_sub->stasis_subs)) {
|
||||
/* Only link if we're dealing with a new aggregate object */
|
||||
if (!recreate) {
|
||||
ao2_link_flags(unsolicited_mwi, aggregate_sub, OBJ_NOLOCK);
|
||||
}
|
||||
if (send_now && sub_added) {
|
||||
send_notify(aggregate_sub, NULL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ao2_unlock(solicited_mwi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags)
|
||||
{
|
||||
return create_unsolicited_mwi_subscriptions(obj, 0, 0);
|
||||
}
|
||||
|
||||
static int unsubscribe(void *obj, void *arg, int flags)
|
||||
{
|
||||
struct mwi_subscription *mwi_sub = obj;
|
||||
|
@ -1347,11 +1554,20 @@ static int load_module(void)
|
|||
ast_log(AST_LOG_WARNING, "Failed to create MWI serializer pool. The default SIP pool will be used for MWI\n");
|
||||
}
|
||||
|
||||
solicited_mwi = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MWI_BUCKETS,
|
||||
mwi_sub_hash, NULL, mwi_sub_cmp);
|
||||
if (!solicited_mwi) {
|
||||
mwi_serializer_pool_shutdown();
|
||||
ast_sip_unregister_subscription_handler(&mwi_handler);
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
||||
unsolicited_mwi = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MWI_BUCKETS,
|
||||
mwi_sub_hash, NULL, mwi_sub_cmp);
|
||||
if (!unsolicited_mwi) {
|
||||
mwi_serializer_pool_shutdown();
|
||||
ast_sip_unregister_subscription_handler(&mwi_handler);
|
||||
ao2_ref(solicited_mwi, -1);
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
||||
|
@ -1384,6 +1600,8 @@ static int unload_module(void)
|
|||
ao2_ref(unsolicited_mwi, -1);
|
||||
unsolicited_mwi = NULL;
|
||||
|
||||
ao2_cleanup(solicited_mwi);
|
||||
|
||||
mwi_serializer_pool_shutdown();
|
||||
|
||||
ast_sip_unregister_subscription_handler(&mwi_handler);
|
||||
|
|
|
@ -1006,7 +1006,7 @@ static int setup_sdes_srtp(struct ast_sip_session_media *session_media,
|
|||
return 0;
|
||||
}
|
||||
|
||||
ast_debug(1, "Ignoring crypto offer with unsupported parameters: %s\n", crypto_str);
|
||||
ast_log(LOG_WARNING, "Ignoring crypto offer with unsupported parameters: %s\n", crypto_str);
|
||||
}
|
||||
|
||||
/* no usable crypto attributes found */
|
||||
|
|
|
@ -203,7 +203,6 @@ static int t38_automatic_reject(void *obj)
|
|||
{
|
||||
RAII_VAR(struct ast_sip_session *, session, obj, ao2_cleanup);
|
||||
RAII_VAR(struct ast_datastore *, datastore, ast_sip_session_get_datastore(session, "t38"), ao2_cleanup);
|
||||
struct ast_sip_session_media *session_media;
|
||||
|
||||
if (!datastore) {
|
||||
return 0;
|
||||
|
@ -212,8 +211,7 @@ static int t38_automatic_reject(void *obj)
|
|||
ast_debug(2, "Automatically rejecting T.38 request on channel '%s'\n",
|
||||
session->channel ? ast_channel_name(session->channel) : "<gone>");
|
||||
|
||||
session_media = session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
|
||||
t38_change_state(session, session_media, datastore->data, T38_REJECTED);
|
||||
t38_change_state(session, NULL, datastore->data, T38_REJECTED);
|
||||
ast_sip_session_resume_reinvite(session);
|
||||
|
||||
return 0;
|
||||
|
@ -322,28 +320,37 @@ static int t38_reinvite_response_cb(struct ast_sip_session *session, pjsip_rx_da
|
|||
int index;
|
||||
|
||||
session_media = session->active_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
|
||||
t38_change_state(session, session_media, state, T38_ENABLED);
|
||||
if (!session_media) {
|
||||
ast_log(LOG_WARNING, "Received %d response to T.38 re-invite on '%s' but no active session media\n",
|
||||
status.code, session->channel ? ast_channel_name(session->channel) : "unknown channel");
|
||||
} else {
|
||||
t38_change_state(session, session_media, state, T38_ENABLED);
|
||||
|
||||
/* Stop all the streams in the stored away active state, they'll go back to being active once
|
||||
* we reinvite back.
|
||||
*/
|
||||
for (index = 0; index < AST_VECTOR_SIZE(&state->media_state->sessions); ++index) {
|
||||
struct ast_sip_session_media *session_media = AST_VECTOR_GET(&state->media_state->sessions, index);
|
||||
/* Stop all the streams in the stored away active state, they'll go back to being active once
|
||||
* we reinvite back.
|
||||
*/
|
||||
for (index = 0; index < AST_VECTOR_SIZE(&state->media_state->sessions); ++index) {
|
||||
struct ast_sip_session_media *session_media = AST_VECTOR_GET(&state->media_state->sessions, index);
|
||||
|
||||
if (session_media && session_media->handler && session_media->handler->stream_stop) {
|
||||
session_media->handler->stream_stop(session_media);
|
||||
if (session_media && session_media->handler && session_media->handler->stream_stop) {
|
||||
session_media->handler->stream_stop(session_media);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
session_media = session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
|
||||
t38_change_state(session, session_media, state, T38_REJECTED);
|
||||
|
||||
/* Abort this attempt at switching to T.38 by resetting the pending state and freeing our stored away active state */
|
||||
ast_sip_session_media_state_free(state->media_state);
|
||||
state->media_state = NULL;
|
||||
ast_sip_session_media_state_reset(session->pending_media_state);
|
||||
}
|
||||
|
||||
/* If no session_media then response contained a declined stream, so disable */
|
||||
t38_change_state(session, NULL, state, session_media ? T38_REJECTED : T38_DISABLED);
|
||||
|
||||
/* Abort this attempt at switching to T.38 by resetting the pending state and freeing our stored away active state */
|
||||
ast_sip_session_media_state_free(state->media_state);
|
||||
state->media_state = NULL;
|
||||
ast_sip_session_media_state_reset(session->pending_media_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -426,12 +433,10 @@ static int t38_interpret_parameters(void *obj)
|
|||
/* Negotiation can not take place without a valid max_ifp value. */
|
||||
if (!parameters->max_ifp) {
|
||||
if (data->session->t38state == T38_PEER_REINVITE) {
|
||||
session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
|
||||
t38_change_state(data->session, session_media, state, T38_REJECTED);
|
||||
t38_change_state(data->session, NULL, state, T38_REJECTED);
|
||||
ast_sip_session_resume_reinvite(data->session);
|
||||
} else if (data->session->t38state == T38_ENABLED) {
|
||||
session_media = data->session->active_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
|
||||
t38_change_state(data->session, session_media, state, T38_DISABLED);
|
||||
t38_change_state(data->session, NULL, state, T38_DISABLED);
|
||||
ast_sip_session_refresh(data->session, NULL, NULL, NULL,
|
||||
AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1, state->media_state);
|
||||
state->media_state = NULL;
|
||||
|
@ -454,6 +459,11 @@ static int t38_interpret_parameters(void *obj)
|
|||
state->our_parms.version = MIN(state->our_parms.version, state->their_parms.version);
|
||||
state->our_parms.rate_management = state->their_parms.rate_management;
|
||||
session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
|
||||
if (!session_media) {
|
||||
ast_log(LOG_ERROR, "Failed to negotiate parameters for reinvite on channel '%s' (No pending session media).\n",
|
||||
data->session->channel ? ast_channel_name(data->session->channel) : "unknown channel");
|
||||
break;
|
||||
}
|
||||
ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp);
|
||||
t38_change_state(data->session, session_media, state, T38_ENABLED);
|
||||
ast_sip_session_resume_reinvite(data->session);
|
||||
|
@ -468,8 +478,13 @@ static int t38_interpret_parameters(void *obj)
|
|||
}
|
||||
state->our_parms = *parameters;
|
||||
session_media = media_state->default_session[AST_MEDIA_TYPE_IMAGE];
|
||||
if (!session_media) {
|
||||
ast_log(LOG_ERROR, "Failed to negotiate parameters on channel '%s' (No default session media).\n",
|
||||
data->session->channel ? ast_channel_name(data->session->channel) : "unknown channel");
|
||||
break;
|
||||
}
|
||||
ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp);
|
||||
t38_change_state(data->session, session_media, state, T38_LOCAL_REINVITE);
|
||||
t38_change_state(data->session, NULL, state, T38_LOCAL_REINVITE);
|
||||
ast_sip_session_refresh(data->session, NULL, t38_reinvite_sdp_cb, t38_reinvite_response_cb,
|
||||
AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1, media_state);
|
||||
}
|
||||
|
@ -478,12 +493,10 @@ static int t38_interpret_parameters(void *obj)
|
|||
case AST_T38_REFUSED:
|
||||
case AST_T38_REQUEST_TERMINATE: /* Shutdown T38 */
|
||||
if (data->session->t38state == T38_PEER_REINVITE) {
|
||||
session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
|
||||
t38_change_state(data->session, session_media, state, T38_REJECTED);
|
||||
t38_change_state(data->session, NULL, state, T38_REJECTED);
|
||||
ast_sip_session_resume_reinvite(data->session);
|
||||
} else if (data->session->t38state == T38_ENABLED) {
|
||||
session_media = data->session->active_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
|
||||
t38_change_state(data->session, session_media, state, T38_DISABLED);
|
||||
t38_change_state(data->session, NULL, state, T38_DISABLED);
|
||||
ast_sip_session_refresh(data->session, NULL, NULL, NULL, AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1, state->media_state);
|
||||
state->media_state = NULL;
|
||||
}
|
||||
|
@ -493,6 +506,11 @@ static int t38_interpret_parameters(void *obj)
|
|||
|
||||
if (data->session->t38state == T38_PEER_REINVITE) {
|
||||
session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE];
|
||||
if (!session_media) {
|
||||
ast_log(LOG_ERROR, "Failed to request parameters for reinvite on channel '%s' (No pending session media).\n",
|
||||
data->session->channel ? ast_channel_name(data->session->channel) : "unknown channel");
|
||||
break;
|
||||
}
|
||||
parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl);
|
||||
parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
|
||||
ast_queue_control_data(data->session->channel, AST_CONTROL_T38_PARAMETERS, ¶meters, sizeof(parameters));
|
||||
|
@ -788,7 +806,7 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session,
|
|||
|
||||
if ((session->t38state == T38_REJECTED) || (session->t38state == T38_DISABLED)) {
|
||||
ast_debug(3, "Declining; T.38 state is rejected or declined\n");
|
||||
t38_change_state(session, session_media, state, T38_DISABLED);
|
||||
t38_change_state(session, NULL, state, T38_DISABLED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -6713,7 +6713,6 @@ static void rtp_instance_parse_transport_wide_cc(struct ast_rtp_instance *instan
|
|||
if (transport_rtp->transport_wide_cc.schedid < 0 && transport_rtp->rtcp) {
|
||||
ast_debug(1, "Starting RTCP transport-cc feedback transmission on RTP instance '%p'\n", transport);
|
||||
ao2_ref(transport, +1);
|
||||
ast_log(LOG_NOTICE, "Starting feedback\n");
|
||||
transport_rtp->transport_wide_cc.schedid = ast_sched_add(rtp->sched, 1000,
|
||||
rtp_transport_wide_cc_feedback_produce, transport);
|
||||
if (transport_rtp->transport_wide_cc.schedid < 0) {
|
||||
|
|
|
@ -1006,6 +1006,7 @@ static int stale_item_update(const void *data)
|
|||
ast_sorcery_object_get_id(task_data->object));
|
||||
sorcery_memory_cache_create(task_data->sorcery, task_data->cache,
|
||||
object);
|
||||
ao2_ref(object, -1);
|
||||
}
|
||||
|
||||
ast_test_suite_event_notify("SORCERY_MEMORY_CACHE_REFRESHED", "Cache: %s\r\nType: %s\r\nName: %s\r\n",
|
||||
|
|
|
@ -373,6 +373,12 @@ static int ast_srtp_unprotect(struct ast_srtp *srtp, void *buf, int *len, int rt
|
|||
|
||||
tryagain:
|
||||
|
||||
if (!srtp->session) {
|
||||
ast_log(LOG_ERROR, "SRTP unprotect %s - missing session\n", rtcp ? "rtcp" : "rtp");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
res = rtcp ? srtp_unprotect_rtcp(srtp->session, buf, len) : srtp_unprotect(srtp->session, buf, len);
|
||||
if (res != err_status_no_ctx) {
|
||||
|
@ -481,6 +487,12 @@ static int ast_srtp_protect(struct ast_srtp *srtp, void **buf, int *len, int rtc
|
|||
int res;
|
||||
unsigned char *localbuf;
|
||||
|
||||
if (!srtp->session) {
|
||||
ast_log(LOG_ERROR, "SRTP protect %s - missing session\n", rtcp ? "rtcp" : "rtp");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((*len + SRTP_MAX_TRAILER_LEN) > sizeof(srtp->buf)) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -501,6 +513,7 @@ static int ast_srtp_protect(struct ast_srtp *srtp, void **buf, int *len, int rtc
|
|||
static int ast_srtp_create(struct ast_srtp **srtp, struct ast_rtp_instance *rtp, struct ast_srtp_policy *policy)
|
||||
{
|
||||
struct ast_srtp *temp;
|
||||
int status;
|
||||
|
||||
if (!(temp = res_srtp_new())) {
|
||||
return -1;
|
||||
|
@ -508,10 +521,13 @@ static int ast_srtp_create(struct ast_srtp **srtp, struct ast_rtp_instance *rtp,
|
|||
ast_module_ref(ast_module_info->self);
|
||||
|
||||
/* Any failures after this point can use ast_srtp_destroy to destroy the instance */
|
||||
if (srtp_create(&temp->session, &policy->sp) != err_status_ok) {
|
||||
status = srtp_create(&temp->session, &policy->sp);
|
||||
if (status != err_status_ok) {
|
||||
/* Session either wasn't created or was created and dealloced. */
|
||||
temp->session = NULL;
|
||||
ast_srtp_destroy(temp);
|
||||
ast_log(LOG_ERROR, "Failed to create srtp session on rtp instance (%p) - %s\n",
|
||||
rtp, srtp_errstr(status));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -525,10 +541,19 @@ static int ast_srtp_create(struct ast_srtp **srtp, struct ast_rtp_instance *rtp,
|
|||
|
||||
static int ast_srtp_replace(struct ast_srtp **srtp, struct ast_rtp_instance *rtp, struct ast_srtp_policy *policy)
|
||||
{
|
||||
if ((*srtp) != NULL) {
|
||||
ast_srtp_destroy(*srtp);
|
||||
struct ast_srtp *old = *srtp;
|
||||
int res = ast_srtp_create(srtp, rtp, policy);
|
||||
|
||||
if (!res && old) {
|
||||
ast_srtp_destroy(old);
|
||||
}
|
||||
return ast_srtp_create(srtp, rtp, policy);
|
||||
|
||||
if (res) {
|
||||
ast_log(LOG_ERROR, "Failed to replace srtp (%p) on rtp instance (%p) "
|
||||
"- keeping old\n", *srtp, rtp);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void ast_srtp_destroy(struct ast_srtp *srtp)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"_copyright": "Copyright (C) 2012 - 2013, Digium, Inc.",
|
||||
"_author": "David M. Lee, II <dlee@digium.com>",
|
||||
"_svn_revision": "$Revision$",
|
||||
"apiVersion": "4.0.0",
|
||||
"apiVersion": "5.0.0",
|
||||
"swaggerVersion": "1.1",
|
||||
"basePath": "http://localhost:8088/ari",
|
||||
"apis": [
|
||||
|
|
|
@ -20,6 +20,8 @@ if (env.TIMEOUT_GATES) {
|
|||
|
||||
pipeline {
|
||||
options {
|
||||
ansiColor('gnome-terminal')
|
||||
throttle(['asterisk-gate'])
|
||||
timestamps()
|
||||
timeout(time: timeoutTime, unit: timeoutUnits)
|
||||
}
|
||||
|
@ -57,19 +59,20 @@ pipeline {
|
|||
|
||||
agent {
|
||||
/* All of the stages need to be performed on a docker host */
|
||||
label "swdev-docker"
|
||||
label "asterisk-gate"
|
||||
}
|
||||
|
||||
stages {
|
||||
stage ("->") {
|
||||
/*
|
||||
* Jenkins will try to automatically rebuild this job when
|
||||
* the jenkinsfile changes but since this job is dependent on
|
||||
* Gerrit, we really don't want to do anything in that case.
|
||||
*/
|
||||
when {
|
||||
/*
|
||||
* Jenkins will try to automatically rebuild this job when
|
||||
* the jenkinsfile changes but since this job is dependent on
|
||||
* Gerrit, we really don't want to do anything in that case.
|
||||
*/
|
||||
not { environment name: 'GERRIT_CHANGE_NUMBER', value: '' }
|
||||
not { environment name: 'GERRIT_EVENT_ACCOUNT_NAME', value: 'Jenkins2' }
|
||||
/* If "skip_gate" is in the comments, don't run the job */
|
||||
not { expression { env.GERRIT_EVENT_COMMENT_TEXT ==~ /.*skip_gate.*/ } }
|
||||
}
|
||||
steps {
|
||||
/* Here's where we switch to scripted pipeline */
|
||||
|
@ -97,7 +100,7 @@ pipeline {
|
|||
withCredentials([usernamePassword(credentialsId: "${JENKINS_GERRIT_CREDS}",
|
||||
passwordVariable: 'GERRIT_USER_PW', usernameVariable: 'GERRIT_USER_NAME')]) {
|
||||
|
||||
sh "printenv | sort"
|
||||
sh "printenv -0 | sort -z | tr '\\0' '\\n'"
|
||||
|
||||
checkout scm: [$class: 'GitSCM',
|
||||
branches: [[name: env.GERRIT_BRANCH ]],
|
||||
|
|
|
@ -20,6 +20,8 @@ if (env.TIMEOUT_DAILIES) {
|
|||
|
||||
pipeline {
|
||||
options {
|
||||
ansiColor('gnome-terminal')
|
||||
throttle(['asterisk-daily'])
|
||||
timestamps()
|
||||
timeout(time: timeoutTime, unit: timeoutUnits)
|
||||
}
|
||||
|
@ -29,7 +31,7 @@ pipeline {
|
|||
|
||||
agent {
|
||||
/* All of the stages need to be performed on a docker host */
|
||||
label "swdev-docker"
|
||||
label "asterisk-daily"
|
||||
}
|
||||
|
||||
stages {
|
||||
|
@ -41,7 +43,7 @@ pipeline {
|
|||
|
||||
stage ("Checkout") {
|
||||
sh "sudo chown -R jenkins:users ."
|
||||
sh "printenv | sort"
|
||||
sh "printenv -0 | sort -z | tr '\\0' '\\n'"
|
||||
sh "sudo tests/CI/setupJenkinsEnvironment.sh"
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@ if (env.TIMEOUT_REF_DEBUG) {
|
|||
|
||||
pipeline {
|
||||
options {
|
||||
ansiColor('gnome-terminal')
|
||||
throttle(['asterisk-ref-debug'])
|
||||
timestamps()
|
||||
timeout(time: timeoutTime, unit: timeoutUnits)
|
||||
}
|
||||
|
@ -29,7 +31,7 @@ pipeline {
|
|||
|
||||
agent {
|
||||
/* All of the stages need to be performed on a docker host */
|
||||
label "swdev-docker"
|
||||
label "asterisk-ref-debug"
|
||||
}
|
||||
|
||||
stages {
|
||||
|
@ -41,7 +43,7 @@ pipeline {
|
|||
|
||||
stage ("Checkout") {
|
||||
sh "sudo chown -R jenkins:users ."
|
||||
sh "printenv | sort"
|
||||
sh "printenv -0 | sort -z | tr '\\0' '\\n'"
|
||||
sh "sudo tests/CI/setupJenkinsEnvironment.sh"
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@ if (env.TIMEOUT_UNITTESTS) {
|
|||
|
||||
pipeline {
|
||||
options {
|
||||
ansiColor('gnome-terminal')
|
||||
throttle(['asterisk-check'])
|
||||
timestamps()
|
||||
timeout(time: timeoutTime, unit: timeoutUnits)
|
||||
}
|
||||
|
@ -59,7 +61,7 @@ pipeline {
|
|||
}
|
||||
agent {
|
||||
/* All of the stages need to be performed on a docker host */
|
||||
label "swdev-docker"
|
||||
label "asterisk-check"
|
||||
}
|
||||
|
||||
stages {
|
||||
|
@ -98,7 +100,7 @@ pipeline {
|
|||
withCredentials([usernamePassword(credentialsId: "${JENKINS_GERRIT_CREDS}",
|
||||
passwordVariable: 'GERRIT_USER_PW', usernameVariable: 'GERRIT_USER_NAME')]) {
|
||||
|
||||
sh "printenv | sort"
|
||||
sh "printenv -0 | sort -z | tr '\\0' '\\n'"
|
||||
|
||||
checkout scm: [$class: 'GitSCM',
|
||||
branches: [[name: env.GERRIT_BRANCH ]],
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
Index: pjsip/include/pjsip/sip_config.h
|
||||
===================================================================
|
||||
--- a/pjsip/include/pjsip/sip_config.h (revision 6050)
|
||||
+++ b/pjsip/include/pjsip/sip_config.h (working copy)
|
||||
@@ -1190,6 +1190,20 @@
|
||||
# define PJSIP_AUTH_CACHED_POOL_MAX_SIZE (20 * 1024)
|
||||
#endif
|
||||
|
||||
+
|
||||
+/**
|
||||
+ * Specify whether the cnonce used for SIP authentication contain digits only.
|
||||
+ * The "cnonce" value is setup using GUID generator, i.e:
|
||||
+ * pj_create_unique_string(), and the GUID string may contain hyphen character
|
||||
+ * ("-"). Some SIP servers do not like this GUID format, so this option will
|
||||
+ * strip any hyphens from the GUID string.
|
||||
+ *
|
||||
+ * Default is 1 (cnonce will only contain digit characters).
|
||||
+ */
|
||||
+#ifndef PJSIP_AUTH_CNONCE_USE_DIGITS_ONLY
|
||||
+# define PJSIP_AUTH_CNONCE_USE_DIGITS_ONLY 1
|
||||
+#endif
|
||||
+
|
||||
/*****************************************************************************
|
||||
* SIP Event framework and presence settings.
|
||||
*/
|
||||
Index: pjsip/src/pjsip/sip_auth_client.c
|
||||
===================================================================
|
||||
--- a/pjsip/src/pjsip/sip_auth_client.c (revision 6050)
|
||||
+++ b/pjsip/src/pjsip/sip_auth_client.c (working copy)
|
||||
@@ -396,7 +396,23 @@
|
||||
|
||||
/* Create cnonce */
|
||||
pj_create_unique_string( cached_auth->pool, &cached_auth->cnonce );
|
||||
+#if defined(PJSIP_AUTH_CNONCE_USE_DIGITS_ONLY) && \
|
||||
+ PJSIP_AUTH_CNONCE_USE_DIGITS_ONLY!=0
|
||||
+ if (pj_strchr(&cached_auth->cnonce, '-')) {
|
||||
+ /* remove hyphen character. */
|
||||
+ int w, r, len = pj_strlen(&cached_auth->cnonce);
|
||||
+ char *s = cached_auth->cnonce.ptr;
|
||||
|
||||
+ w = r = 0;
|
||||
+ for (; r < len; r++) {
|
||||
+ if (s[r] != '-')
|
||||
+ s[w++] = s[r];
|
||||
+ }
|
||||
+ s[w] = '\0';
|
||||
+ cached_auth->cnonce.slen = w;
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
/* Initialize nonce-count */
|
||||
cached_auth->nc = 1;
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
From 489281f29fc7b97143cf79154f22e5007adaba39 Mon Sep 17 00:00:00 2001
|
||||
From: George Joseph <gjoseph@digium.com>
|
||||
Date: Wed, 9 Oct 2019 07:49:44 -0600
|
||||
Subject: [PATCH 30/31] ssl regression fix
|
||||
|
||||
---
|
||||
pjlib/src/pj/ssl_sock_gtls.c | 6 ++++--
|
||||
pjlib/src/pj/ssl_sock_imp_common.c | 4 ++++
|
||||
pjlib/src/pj/ssl_sock_imp_common.h | 3 +++
|
||||
pjlib/src/pj/ssl_sock_ossl.c | 9 +++++----
|
||||
4 files changed, 16 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/pjlib/src/pj/ssl_sock_gtls.c b/pjlib/src/pj/ssl_sock_gtls.c
|
||||
index 311b7b757..484770ae4 100644
|
||||
--- a/pjlib/src/pj/ssl_sock_gtls.c
|
||||
+++ b/pjlib/src/pj/ssl_sock_gtls.c
|
||||
@@ -1050,7 +1050,8 @@ static void ssl_update_certs_info(pj_ssl_sock_t *ssock)
|
||||
goto us_out;
|
||||
|
||||
tls_cert_get_info(ssock->pool, &ssock->local_cert_info, cert);
|
||||
- tls_cert_get_chain_raw(ssock->pool, &ssock->local_cert_info, us, 1);
|
||||
+ pj_pool_reset(ssock->info_pool);
|
||||
+ tls_cert_get_chain_raw(ssock->info_pool, &ssock->local_cert_info, us, 1);
|
||||
|
||||
us_out:
|
||||
tls_last_error = ret;
|
||||
@@ -1077,7 +1078,8 @@ us_out:
|
||||
goto peer_out;
|
||||
|
||||
tls_cert_get_info(ssock->pool, &ssock->remote_cert_info, cert);
|
||||
- tls_cert_get_chain_raw(ssock->pool, &ssock->remote_cert_info, certs,
|
||||
+ pj_pool_reset(ssock->info_pool);
|
||||
+ tls_cert_get_chain_raw(ssock->info_pool, &ssock->remote_cert_info, certs,
|
||||
certslen);
|
||||
|
||||
peer_out:
|
||||
diff --git a/pjlib/src/pj/ssl_sock_imp_common.c b/pjlib/src/pj/ssl_sock_imp_common.c
|
||||
index e6273d832..51a62a2fb 100644
|
||||
--- a/pjlib/src/pj/ssl_sock_imp_common.c
|
||||
+++ b/pjlib/src/pj/ssl_sock_imp_common.c
|
||||
@@ -616,6 +616,7 @@ static void ssl_on_destroy(void *arg)
|
||||
}
|
||||
|
||||
/* Secure release pool, i.e: all memory blocks will be zeroed first */
|
||||
+ pj_pool_secure_release(&ssock->info_pool);
|
||||
pj_pool_secure_release(&ssock->pool);
|
||||
}
|
||||
|
||||
@@ -1262,15 +1263,18 @@ PJ_DEF(pj_status_t) pj_ssl_sock_create (pj_pool_t *pool,
|
||||
{
|
||||
pj_ssl_sock_t *ssock;
|
||||
pj_status_t status;
|
||||
+ pj_pool_t *info_pool;
|
||||
|
||||
PJ_ASSERT_RETURN(pool && param && p_ssock, PJ_EINVAL);
|
||||
PJ_ASSERT_RETURN(param->sock_type == pj_SOCK_STREAM(), PJ_ENOTSUP);
|
||||
|
||||
+ info_pool = pj_pool_create(pool->factory, "ssl_chain%p", 512, 512, NULL);
|
||||
pool = pj_pool_create(pool->factory, "ssl%p", 512, 512, NULL);
|
||||
|
||||
/* Create secure socket */
|
||||
ssock = ssl_alloc(pool);
|
||||
ssock->pool = pool;
|
||||
+ ssock->info_pool = info_pool;
|
||||
ssock->sock = PJ_INVALID_SOCKET;
|
||||
ssock->ssl_state = SSL_STATE_NULL;
|
||||
ssock->circ_buf_input.owner = ssock;
|
||||
diff --git a/pjlib/src/pj/ssl_sock_imp_common.h b/pjlib/src/pj/ssl_sock_imp_common.h
|
||||
index 09f259ef7..eb45f14e0 100644
|
||||
--- a/pjlib/src/pj/ssl_sock_imp_common.h
|
||||
+++ b/pjlib/src/pj/ssl_sock_imp_common.h
|
||||
@@ -96,6 +96,9 @@ typedef struct circ_buf_t {
|
||||
struct pj_ssl_sock_t
|
||||
{
|
||||
pj_pool_t *pool;
|
||||
+ pj_pool_t *info_pool; /* this is for certificate chain
|
||||
+ * information allocation. Don't use for
|
||||
+ * other purposes. */
|
||||
pj_ssl_sock_t *parent;
|
||||
pj_ssl_sock_param param;
|
||||
pj_ssl_sock_param newsock_param;
|
||||
diff --git a/pjlib/src/pj/ssl_sock_ossl.c b/pjlib/src/pj/ssl_sock_ossl.c
|
||||
index b4ac5c15f..2545b7c37 100644
|
||||
--- a/pjlib/src/pj/ssl_sock_ossl.c
|
||||
+++ b/pjlib/src/pj/ssl_sock_ossl.c
|
||||
@@ -1637,11 +1637,12 @@ static void ssl_update_certs_info(pj_ssl_sock_t *ssock)
|
||||
|
||||
chain = SSL_get_peer_cert_chain(ossock->ossl_ssl);
|
||||
if (chain) {
|
||||
- ssl_update_remote_cert_chain_info(ssock->pool,
|
||||
- &ssock->remote_cert_info,
|
||||
- chain, PJ_TRUE);
|
||||
+ pj_pool_reset(ssock->info_pool);
|
||||
+ ssl_update_remote_cert_chain_info(ssock->info_pool,
|
||||
+ &ssock->remote_cert_info,
|
||||
+ chain, PJ_TRUE);
|
||||
} else {
|
||||
- ssock->remote_cert_info.raw_chain.cnt = 0;
|
||||
+ ssock->remote_cert_info.raw_chain.cnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.21.0
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
From 9c6108ca392d5e0392e7fb5d2ffde85e3c44ce55 Mon Sep 17 00:00:00 2001
|
||||
From: George Joseph <gjoseph@digium.com>
|
||||
Date: Wed, 9 Oct 2019 07:50:32 -0600
|
||||
Subject: [PATCH 31/31] transport regression fix
|
||||
|
||||
---
|
||||
pjsip/src/pjsip/sip_transport.c | 73 +++++++++++++++++++++++++++------
|
||||
1 file changed, 61 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c
|
||||
index 65ac823d4..da6b70e50 100644
|
||||
--- a/pjsip/src/pjsip/sip_transport.c
|
||||
+++ b/pjsip/src/pjsip/sip_transport.c
|
||||
@@ -50,6 +50,24 @@ static const char *addr_string(const pj_sockaddr_t *addr)
|
||||
str, sizeof(str));
|
||||
return str;
|
||||
}
|
||||
+static const char* print_tpsel_info(const pjsip_tpselector *sel)
|
||||
+{
|
||||
+ static char tpsel_info_buf[80];
|
||||
+ if (!sel) return "(null)";
|
||||
+ if (sel->type==PJSIP_TPSELECTOR_LISTENER)
|
||||
+ pj_ansi_snprintf(tpsel_info_buf, sizeof(tpsel_info_buf),
|
||||
+ "listener[%s], reuse=%d", sel->u.listener->obj_name,
|
||||
+ !sel->disable_connection_reuse);
|
||||
+ else if (sel->type==PJSIP_TPSELECTOR_TRANSPORT)
|
||||
+ pj_ansi_snprintf(tpsel_info_buf, sizeof(tpsel_info_buf),
|
||||
+ "transport[%s], reuse=%d", sel->u.transport->info,
|
||||
+ !sel->disable_connection_reuse);
|
||||
+ else
|
||||
+ pj_ansi_snprintf(tpsel_info_buf, sizeof(tpsel_info_buf),
|
||||
+ "unknown[%p], reuse=%d", sel->u.ptr,
|
||||
+ !sel->disable_connection_reuse);
|
||||
+ return tpsel_info_buf;
|
||||
+}
|
||||
#else
|
||||
# define TRACE_(x)
|
||||
#endif
|
||||
@@ -1210,10 +1228,14 @@ PJ_DEF(pj_status_t) pjsip_transport_register( pjsip_tpmgr *mgr,
|
||||
* new transport to the list.
|
||||
*/
|
||||
pj_list_push_back(tp_ref, tp_add);
|
||||
+ TRACE_((THIS_FILE, "Remote address already registered, "
|
||||
+ "appended the transport to the list"));
|
||||
} else {
|
||||
/* Transport list not found, add it to the hash table. */
|
||||
pj_hash_set_np(mgr->table, &tp->key, key_len, hval, tp_add->tp_buf,
|
||||
tp_add);
|
||||
+ TRACE_((THIS_FILE, "Remote address not registered, "
|
||||
+ "added the transport to the hash"));
|
||||
}
|
||||
|
||||
/* Add ref transport group lock, if any */
|
||||
@@ -1283,6 +1305,13 @@ static pj_status_t destroy_transport( pjsip_tpmgr *mgr,
|
||||
/* The transport list has multiple entry. */
|
||||
pj_hash_set_np(mgr->table, &tp_next->tp->key, key_len,
|
||||
hval, tp_next->tp_buf, tp_next);
|
||||
+ TRACE_((THIS_FILE, "Hash entry updated after "
|
||||
+ "transport %d being destroyed",
|
||||
+ tp->obj_name));
|
||||
+ } else {
|
||||
+ TRACE_((THIS_FILE, "Hash entry deleted after "
|
||||
+ "transport %d being destroyed",
|
||||
+ tp->obj_name));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1294,6 +1323,14 @@ static pj_status_t destroy_transport( pjsip_tpmgr *mgr,
|
||||
}
|
||||
tp_iter = tp_iter->next;
|
||||
} while (tp_iter != tp_ref);
|
||||
+
|
||||
+ if (tp_iter->tp != tp) {
|
||||
+ PJ_LOG(3, (THIS_FILE, "Warning: transport %s being destroyed is "
|
||||
+ "not registered", tp->obj_name));
|
||||
+ }
|
||||
+ } else {
|
||||
+ PJ_LOG(3, (THIS_FILE, "Warning: transport %s being destroyed is "
|
||||
+ "not found in the hash table", tp->obj_name));
|
||||
}
|
||||
|
||||
pj_lock_release(mgr->lock);
|
||||
@@ -2159,6 +2196,7 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport(pjsip_tpmgr *mgr,
|
||||
NULL, tp);
|
||||
}
|
||||
|
||||
+
|
||||
/*
|
||||
* pjsip_tpmgr_acquire_transport2()
|
||||
*
|
||||
@@ -2176,8 +2214,9 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
|
||||
pjsip_tpfactory *factory;
|
||||
pj_status_t status;
|
||||
|
||||
- TRACE_((THIS_FILE,"Acquiring transport type=%s, remote=%s:%d",
|
||||
+ TRACE_((THIS_FILE,"Acquiring transport type=%s, sel=%s remote=%s:%d",
|
||||
pjsip_transport_get_type_name(type),
|
||||
+ print_tpsel_info(sel),
|
||||
addr_string(remote),
|
||||
pj_sockaddr_get_port(remote)));
|
||||
|
||||
@@ -2194,6 +2233,7 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
|
||||
/* See if the transport is (not) suitable */
|
||||
if (seltp->key.type != type) {
|
||||
pj_lock_release(mgr->lock);
|
||||
+ TRACE_((THIS_FILE, "Transport type in tpsel not matched"));
|
||||
return PJSIP_ETPNOTSUITABLE;
|
||||
}
|
||||
|
||||
@@ -2234,6 +2274,7 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
|
||||
{
|
||||
if (sel->u.listener->type != type) {
|
||||
pj_lock_release(mgr->lock);
|
||||
+ TRACE_((THIS_FILE, "Listener type in tpsel not matched"));
|
||||
return PJSIP_ETPNOTSUITABLE;
|
||||
}
|
||||
}
|
||||
@@ -2249,21 +2290,25 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
|
||||
tp_entry = (transport *)pj_hash_get(mgr->table, &key, key_len,
|
||||
NULL);
|
||||
if (tp_entry) {
|
||||
- if (sel && sel->type == PJSIP_TPSELECTOR_LISTENER) {
|
||||
- transport *tp_iter = tp_entry;
|
||||
- do {
|
||||
+ transport *tp_iter = tp_entry;
|
||||
+ do {
|
||||
+ /* Don't use transport being shutdown */
|
||||
+ if (!tp_iter->tp->is_shutdown) {
|
||||
if (sel && sel->type == PJSIP_TPSELECTOR_LISTENER &&
|
||||
- sel->u.listener &&
|
||||
- tp_iter->tp->factory == sel->u.listener)
|
||||
+ sel->u.listener)
|
||||
{
|
||||
+ /* Match listener if selector is set */
|
||||
+ if (tp_iter->tp->factory == sel->u.listener) {
|
||||
+ tp_ref = tp_iter->tp;
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
tp_ref = tp_iter->tp;
|
||||
break;
|
||||
}
|
||||
- tp_iter = tp_iter->next;
|
||||
- } while (tp_iter != tp_entry);
|
||||
- } else {
|
||||
- tp_ref = tp_entry->tp;
|
||||
- }
|
||||
+ }
|
||||
+ tp_iter = tp_iter->next;
|
||||
+ } while (tp_iter != tp_entry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2276,7 +2321,7 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
|
||||
|
||||
/* Ignore address for loop transports. */
|
||||
if (type == PJSIP_TRANSPORT_LOOP ||
|
||||
- type == PJSIP_TRANSPORT_LOOP_DGRAM)
|
||||
+ type == PJSIP_TRANSPORT_LOOP_DGRAM)
|
||||
{
|
||||
pj_sockaddr *addr = &key.rem_addr;
|
||||
|
||||
@@ -2315,6 +2360,7 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
|
||||
* 'duplicate' of the existing transport (same type & remote addr,
|
||||
* but different factory).
|
||||
*/
|
||||
+ TRACE_((THIS_FILE, "Transport found but from different listener"));
|
||||
}
|
||||
|
||||
if (tp_ref!=NULL && !tp_ref->is_shutdown) {
|
||||
@@ -2347,10 +2393,13 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
|
||||
*/
|
||||
|
||||
/* Verify that the listener type matches the destination type */
|
||||
+ /* Already checked above. */
|
||||
+ /*
|
||||
if (sel->u.listener->type != type) {
|
||||
pj_lock_release(mgr->lock);
|
||||
return PJSIP_ETPNOTSUITABLE;
|
||||
}
|
||||
+ */
|
||||
|
||||
/* We'll use this listener to create transport */
|
||||
factory = sel->u.listener;
|
||||
--
|
||||
2.21.0
|
||||
|
Loading…
Reference in New Issue