[Pkg-voip-commits] [asterisk] 01/05: New upstream version 13.14.0~dfsg
Bernhard Schmidt
berni at moszumanska.debian.org
Sun Feb 26 23:58:03 UTC 2017
This is an automated email from the git hooks/post-receive script.
berni pushed a commit to branch master
in repository asterisk.
commit 211513abfa2ec24371b21d1ef486f836bfd3e9bd
Author: Bernhard Schmidt <berni at debian.org>
Date: Mon Feb 13 22:53:35 2017 +0100
New upstream version 13.14.0~dfsg
---
.version | 2 +-
CHANGES | 50 +
ChangeLog | 1574 +++++++++++++++++++-
addons/chan_mobile.c | 13 +-
apps/app_queue.c | 40 +-
apps/app_voicemail.c | 6 +-
asterisk-13.13.1-summary.html | 25 -
asterisk-13.13.1-summary.txt | 115 --
asterisk-13.14.0-summary.html | 336 +++++
asterisk-13.14.0-summary.txt | 878 +++++++++++
bootstrap.sh | 2 +-
bridges/bridge_native_rtp.c | 81 +-
build_tools/download_externals | 4 +-
build_tools/make_build_h | 10 +-
channels/chan_dahdi.c | 4 +-
channels/chan_oss.c | 2 +-
channels/chan_pjsip.c | 9 +-
channels/chan_rtp.c | 7 +-
channels/chan_sip.c | 103 +-
channels/pjsip/dialplan_functions.c | 62 +-
codecs/codec_dahdi.c | 2 +-
configs/samples/ast_debug_tools.conf.sample | 57 +
configs/samples/pjproject.conf.sample | 25 +-
configs/samples/res_odbc.conf.sample | 6 +-
configure | 12 +-
configure.ac | 10 +-
contrib/Makefile | 14 +-
.../28ab27a7826d_add_srv_lookups_to_identify.py | 31 +
contrib/realtime/mssql/mssql_config.sql | 14 +
contrib/realtime/mysql/mysql_config.sql | 6 +
contrib/realtime/oracle/oracle_config.sql | 14 +
contrib/realtime/postgresql/postgresql_config.sql | 6 +
contrib/scripts/ast_coredumper | 533 +++++++
contrib/scripts/ast_logescalator | 399 +++++
contrib/scripts/ast_loggrabber | 255 ++++
contrib/scripts/autosupport | 4 +-
funcs/func_strings.c | 1 -
include/asterisk/abstract_jb.h | 3 +
include/asterisk/ari.h | 24 +-
include/asterisk/channel.h | 72 +-
include/asterisk/frame.h | 2 +
include/asterisk/mod_format.h | 6 +-
include/asterisk/options.h | 41 +
include/asterisk/res_pjsip.h | 10 +
include/asterisk/rtp_engine.h | 4 +-
include/asterisk/stasis_app.h | 49 +
include/asterisk/tcptls.h | 4 +
include/asterisk/translate.h | 2 +-
include/asterisk/utils.h | 9 +
include/jitterbuf.h | 3 +
main/Makefile | 12 +-
main/abstract_jb.c | 31 +-
main/acl.c | 36 +-
main/app.c | 36 +-
main/asterisk.c | 35 +-
main/astobj2.c | 13 +
main/audiohook.c | 40 +-
main/autoservice.c | 66 +-
main/channel.c | 217 +--
main/channel_internal_api.c | 68 +-
main/fixedjitterbuf.c | 6 +-
main/fixedjitterbuf.h | 3 +
main/format_compatibility.c | 4 +-
main/frame.c | 69 +-
main/jitterbuf.c | 5 +-
main/libasteriskpj.c | 2 +
main/libasteriskssl.c | 4 +-
main/manager.c | 6 +-
main/message.c | 9 +
main/rtp_engine.c | 2 +-
main/srv.c | 3 +-
main/strings.c | 21 +-
main/taskprocessor.c | 8 +-
main/tcptls.c | 94 +-
main/utils.c | 24 +-
makeopts.in | 2 +
res/ari/ari_websockets.c | 14 +-
res/ari/cli.c | 175 +++
res/ari/resource_events.c | 9 +
res/res_agi.c | 10 +-
res/res_ari.c | 77 +-
res/res_ari_applications.c | 42 +-
res/res_ari_asterisk.c | 120 +-
res/res_ari_bridges.c | 162 +-
res/res_ari_channels.c | 318 +---
res/res_ari_device_states.c | 27 +-
res/res_ari_endpoints.c | 45 +-
res/res_ari_events.c | 18 +-
res/res_ari_mailboxes.c | 27 +-
res/res_ari_playbacks.c | 24 +-
res/res_ari_recordings.c | 48 +-
res/res_ari_sounds.c | 21 +-
res/res_calendar_caldav.c | 4 +-
res/res_musiconhold.c | 2 +
res/res_pjproject.c | 156 +-
res/res_pjsip.c | 72 +-
res/res_pjsip/pjsip_configuration.c | 6 +-
res/res_pjsip/pjsip_options.c | 17 +-
res/res_pjsip_diversion.c | 3 +-
res/res_pjsip_endpoint_identifier_ip.c | 160 +-
res/res_pjsip_history.c | 91 +-
res/res_pjsip_outbound_authenticator_digest.c | 12 +-
res/res_pjsip_outbound_registration.c | 21 +-
res/res_pjsip_pubsub.c | 635 +++++++-
res/res_pjsip_refer.c | 8 +-
res/res_pjsip_registrar.c | 70 +-
res/res_pjsip_sdp_rtp.c | 7 +-
res/res_pjsip_session.c | 8 +
res/res_pjsip_t38.c | 7 +-
res/res_pjsip_transport_websocket.c | 5 +-
res/res_rtp_asterisk.c | 117 +-
res/res_sorcery_memory_cache.c | 41 +-
res/res_stasis.c | 23 +-
res/stasis/app.c | 73 +-
res/stasis/app.h | 27 -
res/stasis/cli.c | 216 ---
res/stasis/cli.h | 43 -
res/stasis/stasis_bridge.c | 6 +-
rest-api-templates/param_parsing.mustache | 15 -
rest-api-templates/res_ari_resource.c.mustache | 3 +-
tests/test_ari.c | 22 +-
tests/test_substitution.c | 9 +
tests/test_voicemail_api.c | 52 +-
third-party/Makefile | 2 +-
third-party/Makefile.rules | 4 +
third-party/pjproject/Makefile | 61 +-
third-party/pjproject/configure.m4 | 8 +-
.../patches/0000-set_apps_initial_log_level.patch | 39 +
third-party/pjproject/patches/config_site.h | 17 +-
129 files changed, 7003 insertions(+), 1953 deletions(-)
diff --git a/.version b/.version
index b88ad97..510cd5b 100644
--- a/.version
+++ b/.version
@@ -1 +1 @@
-13.13.1
\ No newline at end of file
+13.14.0
\ No newline at end of file
diff --git a/CHANGES b/CHANGES
index adba984..dc5f058 100644
--- a/CHANGES
+++ b/CHANGES
@@ -9,6 +9,56 @@
==============================================================================
------------------------------------------------------------------------------
+--- Functionality changes from Asterisk 13.13.0 to Asterisk 13.14.0 ----------
+------------------------------------------------------------------------------
+
+res_pjproject
+------------------
+ * Added new CLI command "pjproject set log level". The new command allows
+ the maximum PJPROJECT log levels to be adjusted dynamically and
+ independently from the set debug logging level like many other similar
+ module debug logging commands.
+
+ * Added new companion CLI command "pjproject show log level" to allow the
+ user to see the current maximum pjproject logging level.
+
+ * Added new pjproject.conf startup section "log_level' option to set the
+ initial maximum PJPROJECT logging level.
+
+res_pjsip_outbound_registration
+------------------
+ * Statsd no longer logs redundant status PJSIP.registrations.state changes
+ for internal state transitions that don't change the reported public status
+ state.
+
+res_pjsip_registrar
+------------------
+ * The PJSIPShowRegistrationInboundContactStatuses AMI command has been added
+ to return ContactStatusDetail events as opposed to
+ PJSIPShowRegistrationsInbound which just a dumps every defined AOR.
+
+res_pjsip
+------------------
+ * Six existing contact fields have been added to the end of the
+ ContactStatusDetail AMI event:
+ ID, AuthenticateQualify, OutboundProxy, Path, QualifyFrequency and
+ QualifyTimeout. Existing fields have not been disturbed.
+
+res_pjsip_endpoint_identifier_ip
+------------------
+ * SRV lookups can now be done on provided hostnames to determine additional
+ source IP addresses for requests. This is configurable using the
+ "srv_lookups" option on the identify and defaults to "yes".
+
+ARI
+------------------
+ * The 'ari set debug' command has been enhanced to accept 'all' as an
+ application name. This allows dumping of all apps even if an app
+ hasn't registered yet.
+
+ * 'ari set debug' now displays requests and responses as well as events.
+
+------------------------------------------------------------------------------
--- Functionality changes from Asterisk 13.12.0 to Asterisk 13.13.0 ----------
------------------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 2b71a62..041f74c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,12 +1,1106 @@
-2016-12-08 17:30 +0000 Asterisk Development Team <asteriskteam at digium.com>
+2017-02-13 19:51 +0000 Asterisk Development Team <asteriskteam at digium.com>
- * asterisk 13.13.1 Released.
+ * asterisk 13.14.0 Released.
-2016-12-08 11:26 +0000 [5e06e6d8a2] Kevin Harwell <kharwell at digium.com>
+2017-02-08 19:13 +0000 Asterisk Development Team <asteriskteam at digium.com>
- * Update for 13.13.1
+ * asterisk 13.14.0-rc2 Released.
-2016-11-30 09:31 +0000 [e80603b6d6] Walter Doekes <walter+asterisk at wjd.nu>
+2017-02-08 11:50 +0000 [3f3290ce4f] Mark Michelson <mmichelson at digium.com>
+
+ * Revert "Update qualifies when AOR configuration changes."
+
+ This reverts commit 6492e91392b8fd394193e411c6eb64b45486093f.
+
+ The change in question was intended to prevent the need to reload in
+ order to update qualifies on contacts when an AOR changes. However, this
+ ended up causing a deadlock instead.
+
+ Change-Id: I1a835c90a5bb65b6dc3a1e94cddc12a4afc3d71e
+
+2017-02-07 12:01 +0000 [1f2ae7908d] nappsoft <infos at nappsoft.com> (license 6822)
+
+ * srv: Fix crash when ast_srv_lookup is used and 0 records are returned.
+
+ When performing an SRV lookup using the ast_srv_lookup function it
+ did not properly handle the situation where 0 records are returned.
+ If this happened it would wrongly assume that at least one record
+ was present.
+
+ This change fixes the code so it will exit early if an error occurs
+ or if 0 records are returned.
+
+ ASTERISK-26772
+ patches:
+ srv_lookup.patch submitted by nappsoft (license 6822)
+
+ Change-Id: I09b19081c74e0ad11c12bf54a257243b1bcb2351
+
+2017-02-06 16:27 +0000 Asterisk Development Team <asteriskteam at digium.com>
+
+ * asterisk 13.14.0-rc1 Released.
+
+2017-02-02 11:26 +0000 [70aff89e5d] Sean Bright <sean.bright at gmail.com>
+
+ * res_odbc: Remove deprecated settings from sample configuration file
+
+ ASTERISK-26704 #close
+ Reported by: Anthony Messina
+
+ Change-Id: I976a1f94cf79c5f31e76174c61f5c6a65fd6354f
+
+2017-02-01 15:56 +0000 [3aee199913] Sean Bright <sean.bright at gmail.com>
+
+ * audiohooks: Muting a hook can mute underlying frames
+
+ If an audiohook is placed on a channel that does not require transcoding,
+ muting that hook will cause the underlying frames to be muted as well.
+
+ The original patch is from David Woolley but I have modified slightly.
+
+ ASTERISK-21094 #close
+ Reported by: David Woolley
+ Patches:
+ ASTERISK-21094-Patch-1.8-1.txt (license #5737) patch uploaded
+ by David Woolley
+
+ Change-Id: Ib2b68c6283e227cbeb5fa478b2d0f625dae338ed
+
+2017-02-01 13:54 +0000 [6492e91392] Mark Michelson <mmichelson at digium.com>
+
+ * Update qualifies when AOR configuration changes.
+
+ Prior to this change, qualifies would only update in the following
+ cases:
+ * A reload of res_pjsip.so was issued.
+ * A dynamic contact was re-registered after its AOR's qualify_frequency
+ had been changed
+ This does not work well if you are using realtime for your AORs. You can
+ update your database to have a new qualify_frequency, but the permanent
+ contacts on that AOR will not have their qualifies updated. And the
+ dynamic contacts on that AOR will not have their qualifies updated until
+ the next registration, which could be a long time.
+
+ This change seeks to fix this problem by making it so that whenever AOR
+ configuration is applied, the contacts pertaining to that AOR have their
+ qualifies updated.
+
+ Additions from this patch:
+ * AOR sorcery objects now have an apply handler that calls into a newly
+ added function in the OPTIONS code. This causes all contacts
+ associated with that AOR to re-schedule qualifies.
+ * When it is time to qualify a contact, the OPTIONS code checks to see
+ if the AOR can still be retrieved. If not, then qualification is
+ canceled on the contact.
+
+ Alterations from this patch:
+ * The registrar code no longer updates contact's qualify_frequence and
+ qualify_timeout. There is no point to this since those values already
+ get updated when the AOR changes.
+ * Reloading res_pjsip.so no longer calls the OPTIONS initialization
+ function. Reloading res_pjsip.so results in re-loading AORs, which
+ results in re-scheduling qualifies.
+
+ Change-Id: I2e7c3316da28f389c45954f24c4e9389abac1121
+
+2017-01-31 18:28 +0000 [43f0ff4b69] Richard Mudgett <rmudgett at digium.com>
+
+ * channel.c: Fix unbalanced read queue deadlocking local channels.
+
+ Using the timerfd timing module can cause channel freezing, lingering, or
+ deadlock issues. The problem is because this is the only timing module
+ that uses an associated alert-pipe. When the alert-pipe becomes
+ unbalanced with respect to the number of frames in the read queue bad
+ things can happen. If the alert-pipe has fewer alerts queued than the
+ read queue then nothing might wake up the thread to handle received frames
+ from the channel driver. For local channels this is the only way to wake
+ up the thread to handle received frames. Being unbalanced in the other
+ direction is less of an issue as it will cause unnecessary reads into the
+ channel driver.
+
+ ASTERISK-26716 is an example of this deadlock which was indirectly fixed
+ by the change that found the need for this patch.
+
+ * In channel.c:__ast_queue_frame(): Adding frame lists to the read queue
+ did not add the same number of alerts to the alert-pipe. Correspondingly,
+ when there is an exceptionally long queue event, any removed frames did
+ not also remove the corresponding number of alerts from the alert-pipe.
+
+ ASTERISK-26632 #close
+
+ Change-Id: Ia98137c5bf6e9d6d202ce0eb36441851875863f6
+
+2017-01-31 16:38 +0000 [a199f94908] Richard Mudgett <rmudgett at digium.com>
+
+ * res_agi: Prevent an AGI from eating frames it should not. (Re-do)
+
+ A dialplan intercept routine is equivalent to an interrupt routine. As
+ such, the routine must be done quickly and you do not have access to the
+ media stream. These restrictions are necessary because the media stream
+ is the responsibility of some other code and interfering with or delaying
+ that processing is bad. A possible future dialplan processing
+ architecture change may allow the interception routine to run in a
+ different thread from the main thread handling the media and remove the
+ execution time restriction.
+
+ * Made res_agi.c:run_agi() running an AGI in an interception routine run
+ in DeadAGI mode. No touchy channel frames.
+
+ ASTERISK-25951
+
+ ASTERISK-26343
+
+ ASTERISK-26716
+
+ Change-Id: I638f147ca7a7f2590d7194a8ef4090eb191e4e43
+
+2017-01-31 16:32 +0000 [6bed318a66] Richard Mudgett <rmudgett at digium.com>
+
+ * Frame deferral: Revert API refactoring.
+
+ There are several issues with deferring frames that are caused by the
+ refactoring.
+
+ 1) The code deferring frames mishandles adding a deferred frame to the
+ deferred queue. As a result the deferred queue can only be one frame
+ long.
+
+ 2) Deferrable frames can come directly from the channel driver as well as
+ the read queue. These frames need to be added to the deferred queue.
+
+ 3) Whoever is deferring frames is really only doing the __ast_read() to
+ collect deferred frames and doesn't care about the returned frames except
+ to detect a hangup event. When frame deferral is completed we must make
+ the normal frame processing see the hangup as a frame anyway. As such,
+ there is no need to have varying hangup frame deferral methods. We also
+ need to be aware of the AST_SOFTHANGUP_ASYNCGOTO hangup that isn't real.
+ That fake hangup is to cause the PBX thread to break out of loops to go
+ execute a new dialplan location.
+
+ 4) To properly deal with deferrable frames from the channel driver as
+ pointed out by (2) above, means that it is possible to process a dialplan
+ interception routine while frames are deferred because of the
+ AST_CONTROL_READ_ACTION control frame. Deferring frames is not
+ implemented as a re-entrant operation so you could have the unsupported
+ case of two sections of code thinking they have control of the media
+ stream.
+
+ A worse problem is because of the bad implementation of the AMI PlayDTMF
+ action. It can cause two threads to be deferring frames on the same
+ channel at the same time. (ASTERISK_25940)
+
+ * Rather than fix all these problems simply revert the API refactoring as
+ there is going to be only autoservice and safe_sleep deferring frames
+ anyway.
+
+ ASTERISK-26343
+
+ ASTERISK-26716 #close
+
+ Change-Id: I45069c779aa3a35b6c863f65245a6df2c7865496
+
+2017-01-31 11:17 +0000 [e371e13b9e] Joshua Colp <jcolp at digium.com>
+
+ * res_pjsip: Handle invocation of callback on outgoing request when error occurs.
+
+ There are some error cases in PJSIP when sending a request that will
+ result in the callback for the request being invoked. The code did not
+ handle this case and assumed on every error case that the callback was not
+ invoked.
+
+ The code has been changed to check whether the callback has been invoked
+ and if so to absorb the error and treat it as a success.
+
+ ASTERISK-26679
+ ASTERISK-26699
+
+ Change-Id: I563982ba204da5aa1428989a11c06dd9087fea91
+
+2017-01-30 09:02 +0000 [339c30f2b6] Sean Bright <sean.bright at gmail.com>
+
+ * res_rtp_asterisk: Swap byte-order when sending signed linear
+
+ Before Asterisk 13, signed linear was converted into network byte order by a
+ smoother before being sent over the network. We restore this behavior by
+ forcing the creation of a smoother when slinear is in use and setting the
+ appropriate flags so that the byte order conversion is always done.
+
+ ASTERISK-24858 #close
+ Reported-by: Frankie Chin
+
+ Change-Id: I868449617d1a7819578f218c8c6b2111ad84f5a9
+
+2017-01-31 12:46 +0000 [7fd28cefdb] gtjoseph <gjoseph at digium.com>
+
+ * debug_utilities: Install ast_logescalator to /var/lib/asterisk/scripts
+
+ Forgot to install it with the original patch
+
+ Change-Id: I8bdb540a6694971ae5fe21f48d532332c6482e4c
+
+2017-01-25 06:50 +0000 [456bc3c704] gtjoseph <gjoseph at digium.com>
+
+ * debug_utilities: Add ast_logescalator
+
+ The escalator works by creating a set of startup commands in cli.conf
+ that set up logger channels and issue the debug commands for the
+ subsystems specified. If asterisk is running when it is executed,
+ the same commands will be issued to the running instance. The original
+ cli.conf is saved before any changes are made and can be restored by
+ executing '$prog --reset'.
+
+ The log output will be stored in...
+ $astlogdir/message.$uniqueid
+ $astlogdir/debug.$uniqueid
+ $astlogdir/dtmf.$uniqueid
+ $astlogdir/fax.$uniqueid
+ $astlogdir/security.$uniqueid
+ $astlogdir/pjsip_history.$uniqueid
+ $astlogdir/sip_history.$uniqueid
+
+ Some minor tweaks were made to chan_sip, and res_pjsip_history
+ so their history output could be send to a log channel as packets
+ are captured.
+
+ A minor tweak was also made to manager so events are output to verbose
+ when "manager set debug on" is issued.
+
+ Change-Id: I799f8e5013b86dc5282961b27383d134bf09e543
+
+2017-01-23 09:35 +0000 [54b027916a] Torrey Searle <torrey at voxbone.com>
+
+ * libastssl/pj: libastssl/pj should have an so_version
+
+ Issue introduced in b59956a87. In the non-darwin case libastssl/pj
+ should be versioned. This causes the symbol file for this lib
+ to not be generated.
+
+ Change-Id: Ib07ae8c40252813c488e2c1ac6204fd42816dd4c
+
+2017-01-24 19:51 +0000 [3c8f84786e] Kirill Katsnelson <kkm at smartaction.com>
+
+ * make_build_h: handle backslashes in external strings
+
+ LikewiseOpen creates user names with a backslash in them. A gentle
+ massage with sed(1) allows such strings to be inserted into build.h
+ properly quoted. I am also adding the same for host name and other
+ strings used in the script that are more or less user-controlled.
+
+ ASTERISK-26754
+
+ Change-Id: Iac5ef2b67a68ee58f35ddbf86bb818ba6eabecae
+
+2017-01-17 20:46 +0000 [555e8cd2ba] Kirill Katsnelson <kkm at smartaction.com>
+
+ * ast_careful_fwrite to support EPIPE gracefully
+
+ When a reading end of the network socket is closed by an AMI manager,
+ the EPIPE is signaled when writing to our end, resulting in the
+ spurious log error message
+
+ ast_careful_fwrite: fwrite() returned error: Broken pipe
+
+ Previously EPIPE was handled in ast_carefulwrite() a few lines above,
+ but not in this function.
+
+ ASTERISK-26753
+
+ Change-Id: I6a67335cd6526608bb9b78f796c626b1677664b8
+
+2017-01-24 22:31 +0000 [be92f10a16] Kirill Katsnelson <kkm at smartaction.com>
+
+ * app_queue: Fix queues randomly disappearing on reload
+
+ With 500+ queues and a reload every minute, a random queue disappears
+ upon reload. The cause is mususe of the 'dead' flag. Namely, all queues
+ were marked dead up front, and then "resurrected" by dropping this flag
+ for those found in the configuration. But a queue marked dead can be
+ removed also when control leaves the app entry point on a PBX thread.
+
+ With this change, the queue is marked only not found, and at the end of
+ reload only the queues that are still not found are actually marked as
+ dead, so the dead flag is never reset, and set only on positively dead
+ queues.
+
+ ASTERISK-26755
+
+ Change-Id: I3a4537aec9eb8d8aeeaa0193407e3523feb004bf
+
+2017-01-26 07:57 +0000 [aae9df0643] Joshua Colp <jcolp at digium.com>
+
+ * res_pjsip_endpoint_identifier_ip: Fix memory leak of hosts when resolving.
+
+ This change adds a missing unreference of the hostname when resolving and
+ also cleans up the iterator.
+
+ ASTERISK-26735
+
+ Change-Id: Ic012ebaf3d89e714eec340b7b0c5e63c66af857a
+
+2017-01-25 15:26 +0000 [9e3150b98d] Mark Michelson <mmichelson at digium.com>
+
+ * Add reload options to CLI/AMI stale object commands.
+
+ Marking an object as stale in a memory cache is supposed to prime the
+ cache so that the next time the item is retrieved, the stale item is
+ deleted from the cache and a background task is run to re-populate the
+ cache with a fresh version of the object.
+
+ The problem is, there are some object types out there for which there is
+ no natural reason that they would be retrieved from the backend with any
+ regularity. Outbound PJSIP registrations are a good example of this. At
+ startup, they are read, and an object-specific state is created that
+ refers to the initially-retrieved object for all time.
+
+ Adding the "reload" option to the CLI/AMI commands gives the cache the
+ opportunity to manually re-retrieve the object from the backend, both
+ storing the new object in the cache and applying the new object's
+ configuration to the module that uses that object.
+
+ Change-Id: Ieb1fe7270ceed491f057ec5cbf0e097bde96c5c8
+
+2017-01-10 17:39 +0000 [c54f9d2bf0] Richard Mudgett <rmudgett at digium.com>
+
+ * T.140: Fix format ref and memory leaks.
+
+ * channel.c:ast_sendtext(): Fix T.140 SendText memory leak.
+
+ * format_compatibility.c: T.140 RED and T.140 were swapped.
+
+ * res_rtp_asterisk.c:rtp_red_init(): Fix ast_format_t140_red ref leak.
+
+ * res_rtp_asterisk.c:rtp_red_init(): Fix data race after starting periodic
+ scheduled red_write().
+
+ * res_rtp_asterisk.c: Some other minor misc tweaks.
+
+ Change-Id: Ifa27a2e0f8a966b1cf628607c86fc4374b0b88cb
+
+2017-01-24 15:39 +0000 [a2f0adccbd] Joshua Colp <jcolp at digium.com>
+
+ * res_pjsip_endpoint_identifier_ip: Ensure error defaults to 0.
+
+ When configuring a match using a netmask the error variable was
+ not defaulting to 0. For some people this would cause the code
+ to think an error occurred when adding the match when in reality
+ it added perfectly fine.
+
+ ASTERISK-26693
+
+ Change-Id: I850c250813742bddde65c84e739093c9e01dfe56
+
+2017-01-10 17:37 +0000 [607b3ac736] Richard Mudgett <rmudgett at digium.com>
+
+ * astobj2.c: Add excessive ref count trap.
+
+ Change-Id: I32e6a589cf9009450e4ff7cb85c07c9d9ef7fe4a
+
+2017-01-10 13:11 +0000 [ab8cb5a7ce] Richard Mudgett <rmudgett at digium.com>
+
+ * main/app.c: Memory corruption from early format destruction.
+
+ * make_silence() created a malloced silence slin frame without adding a
+ slin format ref. When the frame is destroyed it will unref the slin
+ format that never had a ref added. Memory corruption is expected to
+ follow.
+
+ * Simplified and fixed counting the number of samples in a frame list for
+ make_silence().
+
+ * Eliminated an unnecessary RAII_VAR associated with the make_silence()
+ frame.
+
+ Change-Id: I47de3f9b92635b7f8b4d72309444d6c0aee6f747
+
+2017-01-11 14:59 +0000 [dcd8e4b1a0] Richard Mudgett <rmudgett at digium.com>
+
+ * frame.c: Fix off-nominal format ref leaks.
+
+ * ast_frisolate() could leak frame format refs on allocation
+ failures.
+
+ * Similified code in ast_frisolate() and code used by
+ ast_frisolate().
+
+ Change-Id: I79566d4d36b3d7801bf0c8294fcd3e9a86a2ed6d
+
+2017-01-13 19:08 +0000 [00a227e93d] Richard Mudgett <rmudgett at digium.com>
+
+ * stasis_bridge.c: Fix off-nominal stasis control ref leak.
+
+ Change-Id: Ib17218343a6596832060180e19386da9df150ac8
+
+2017-01-10 12:30 +0000 [38a2021c68] Richard Mudgett <rmudgett at digium.com>
+
+ * res_musiconhold.c: Fix format ref leak when parsing MOH config class.
+
+ Change-Id: Ica8e8e2ce7604c2c61ec55bef07dc675361d2ea5
+
+2017-01-10 14:03 +0000 [ab7a9fc5b2] Richard Mudgett <rmudgett at digium.com>
+
+ * chan_oss.c: Fix format ref leak in oss_read().
+
+ Change-Id: I0a5d56c7dcf327d60f86a4c25a23571733709fd0
+
+2017-01-10 17:48 +0000 [1484a991e1] Richard Mudgett <rmudgett at digium.com>
+
+ * Add notes about embedded ast_frame structs holding a format ref.
+
+ mod_format.h: Note ast_filestream.fr holds a format ref.
+
+ translate.h: Note ast_trans_pvt.f holds a format ref.
+
+ Change-Id: I86bda354d725207b41e08920355d7c31b2d7f749
+
+2017-01-19 09:05 +0000 [17f4989d49] gtjoseph <gjoseph at digium.com>
+
+ * ari: Implement 'debug all' and request/response logging
+
+ The 'ari set debug' command has been enhanced to accept 'all' as an
+ application name. This allows dumping of all apps even if an app
+ hasn't registered yet. To accomplish this, a new global_debug global
+ variable was added to res/stasis/app.c and new APIs were added to
+ set and query the value.
+
+ 'ari set debug' now displays requests and responses as well as events.
+ This required refactoring the existing debug code.
+
+ * The implementation for 'ari set debug' was moved from stasis/cli.{c,h}
+ to ari/cli.{c,h}, and stasis/cli.{c,h} were deleted.
+ * In order to print the body of incoming requests even if a request
+ failed, the consumption of the body was moved from the ari stubs
+ to ast_ari_callback in res_ari.c and the moustache templates were
+ then regenerated. The body is now passed to ast_ari_invoke and then
+ on to the handlers. This results in code savings since that template
+ was inserted multiple times into all the stubs.
+
+ An additional change was made to the ao2_str_container implementation
+ to add partial key searching and a sort function. The existing cli
+ code assumed it was already there when it wasn't so the tab completion
+ was never working.
+
+ Change-Id: Ief936f747ce47f1fb14035fbe61152cf766406bf
+
+2017-01-20 21:13 +0000 [30cb4eb57f] Richard Mudgett <rmudgett at digium.com>
+
+ * PJPROJECT logging: Fix detection of max supported log level.
+
+ The mechanism used for detecting the maximum log level compiled into the
+ linked pjproject did not work. The API call simply stores the requested
+ level into an integer and does no range checking. Asterisk was assuming
+ that there was range checking and limited the new value to the allowable
+ range. To get the actual maximum log level compiled into the linked
+ pjproject we need to get and save off the initial set log level from
+ pjproject. This is the maximum log level supported.
+
+ * Get and save off the initial log level setting before altering it to the
+ desired level on startup. This has to be done by a macro rather than
+ calling a core function to avoid incorrectly linking pjproject.
+
+ * Split the initial log level warning messages to warn if the linked
+ pjproject cannot support the requested startup level and if it is too low
+ to get the pjproject buildopts for "pjproject show buildopts".
+
+ * Adjust the CLI "pjproject set log level" to check the saved max log
+ level and to generate normal output messages instead of a warning message.
+
+ ASTERISK-26743 #close
+
+ Change-Id: I40aa76653e2a1dece66c3f8734594b4f0471cfb4
+
+2017-01-21 14:43 +0000 [cd2677f966] Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+ * tests: use datadir for sound files
+
+ Some (voicemail-related) tests API symlinks beep.gsm and other files
+ from ast_config_AST_VAR_DIR. It should use ast_config_AST_DATA_DIR.
+
+ ASTERISK-26740 #close
+
+ Change-Id: Id49c56fb9e16df64b1a2b829693ca7601252df89
+
+2017-01-20 23:41 +0000 [b62f84bfb1] Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+ * test_voicemail_api: order of params to VERIFY macros
+
+ Fix order of parameters in calls to VM_API_INT_VERIFY and
+ VM_API_STRING_VERIFY
+
+ ASTERISK-26739 #close
+
+ Change-Id: I30dc6b36893aadad6012be3f16f93aa5720870d6
+ Note: status: builds. Not tested any further.
+
+2017-01-05 13:21 +0000 [e3dcb9ddd9] Richard Mudgett <rmudgett at digium.com>
+
+ * res_pjsip_pubsub.c: Implement "pjsip show subscriptions" commands.
+
+ ASTERISK-23828 #close
+
+ Change-Id: Ifb8a3b61f447aedc58a8e6b36a810f7566018567
+
+2017-01-23 16:18 +0000 [75497c33ea] Mark Michelson <mmichelson at digium.com>
+
+ * Free endpoint ACLs when destroying PJSIP endpoints.
+
+ If endpoint ACLs were specified, they were not being freed
+ when endpoints were destroyed. On systems with realtime endpoints, this
+ could add up quickly since each DB lookup would allocate the ACL without
+ freeing it.
+
+ ASTERISK-26731 #close
+ Reported by Ustinov Artem
+
+ Change-Id: Ie1f8bf5b7a0de628c975beba01e69c56893331ad
+
+2017-01-23 09:10 +0000 [177e81ee47] gtjoseph <gjoseph at digium.com>
+
+ * pjproject_bundled: Fix setting max log level
+
+ An earlier attempt to prevent pjsua from spitting out an extra 6795
+ lines of debug output every time the testsuite called it was also
+ turning off the ability for asterisk to output debug info when it
+ needed to. This patch reverts the earlier fix and instead adds
+ a pjproject patch that sets the startup log level to 1 for pjsua
+ pjsystest and the pjsua python binding. This is an asterisk-only
+ patch that does not affect pjproject functionality and will not be
+ submitted upstream.
+
+ Change-Id: I347a8b58b2626f2906ccfc1d339e907627a0c9e8
+
+2017-01-23 10:08 +0000 [6d23b2e360] Joshua Colp <jcolp at digium.com>
+
+ * res_pjsip_endpoint_identifier_ip: Read settings before resolving.
+
+ An option has been added, srv_lookups, which controls whether
+ SRV lookups are performed on the provided match hosts or not.
+ It was possible for this option to be applied after resolution
+ had already happened.
+
+ This change makes it so hosts are stored away, settings are read
+ and applied, and then resolution is done. This ensures that no
+ matter the ordering the srv_lookups option is in effect.
+
+ ASTERISK-26735
+
+ Change-Id: I750378cb277be0140f8c5539450270afbfc43388
+
+2017-01-22 17:25 +0000 [a969bf3577] Richard Mudgett <rmudgett at digium.com>
+
+ * LISTFILTER: Remove outdated ERROR message.
+
+ Feeding LISTFILTER an empty variable results in an invalid ERROR message.
+ Earlier changes made the message useless because we can no longer tell if
+ the variable is empty or does not exist. It is valid to try to remove a
+ value from an empty list just as it is valid to try to remove a value that
+ is not in a non-empty list.
+
+ * Removed the outdated ERROR message.
+
+ * Added more test cases to the LISTFILTER unit test.
+
+ Change-Id: Ided9040e6359c44a335ef54e02ef5950a1863134
+
+2017-01-05 15:11 +0000 [3890337e7a] Richard Mudgett <rmudgett at digium.com>
+
+ * res_pjsip_pubsub.c: Fix AMI event list counts.
+
+ Fix the AMI PJSIPShowSubscriptionsInbound, PJSIPShowSubscriptionsOutbound,
+ and PJSIPShowResourceLists actions event counts. The reported counts may
+ not necessarily be accurate depending on what happens.
+
+ The subscriptions count would be wrong if Asterisk ever has outbound
+ subscriptions.
+
+ The resource list count could be wrong if a list were added or removed
+ during the AMI action being processed.
+
+ Change-Id: I4344301827523fa174960a42c413fd19abe4aed5
+
+2017-01-05 13:02 +0000 [fe4801c4f9] Richard Mudgett <rmudgett at digium.com>
+
+ * res_pjsip_pubsub.c: Fix incorrect message string wrapping.
+
+ Change-Id: Id771e6fe56d89ce365ddcbb423f820af97211120
+
+2017-01-05 13:01 +0000 [46484b8730] Richard Mudgett <rmudgett at digium.com>
+
+ * res_pjsip_pubsub.c: Eliminate trivial SCOPED_LOCK usage.
+
+ Change-Id: Ie0b69a830385452042fa19e7d267c6790ec6b6be
+
+2017-01-05 12:58 +0000 [8160474d7d] Richard Mudgett <rmudgett at digium.com>
+
+ * res_pjsip: alloca can never fail.
+
+ Change-Id: Ia2a6158e5fdf311bc2a1c0c43417978de504b1f1
+
+2017-01-13 11:03 +0000 [c628a7acac] gtjoseph <gjoseph at digium.com>
+
+ * debug_utilities: Create ast_loggrabber
+
+ ast_loggrabber gathers log files from customizable search patterns,
+ optionally converts POSIX timestamps to a readable format and
+ tarballs the results.
+
+ Also a few tweaks were made to ast_coredumper.
+
+ Change-Id: I8bfe1468ada24c1344ce4abab7b002a59a659495
+ (cherry picked from commit 5fa1c56d7e76999aa14f133a33f6b168e7c3b99c)
+
+2017-01-01 03:47 +0000 [e335b706ee] Richard Mudgett <rmudgett at digium.com>
+
+ * res_pjsip_outbound_authenticator_digest.c: Fix spacing in warning messages.
+
+ Change-Id: I573f0343c0c63a785cd4da60d57cc9f8b9ce7f49
+
+2017-01-12 15:58 +0000 [883e7fde31] Kevin Harwell <kharwell at digium.com>
+
+ * abstract/fixed/adpative jitter buffer: disallow frame re-inserts
+
+ It was possible for a frame to be re-inserted into a jitter buffer after it
+ had been removed from it. A case when this happened was if a frame was read
+ out of the jitterbuffer, passed to the translation core, and then multiple
+ frames were returned from said translation core. Upon multiple frames being
+ returned the first is passed on, but sebsequently "chained" frames are put
+ back into the read queue. Thus it was possible for a frame to go back into
+ the jitter buffer where this would cause problems.
+
+ This patch adds a flag to frames that are inserted into the channel's read
+ queue after translation. The abstract jitter buffer code then checks for this
+ flag and ignores any frames marked as such.
+
+ Change-Id: I276c44edc9dcff61e606242f71274265c7779587
+
+2017-01-13 21:23 +0000 [473330983b] Richard Mudgett <rmudgett at digium.com>
+
+ * taskprocessor.c: Change when high water warning logged.
+
+ The task processor queue reached X scheduled tasks message was originally
+ intended to get logged only once per task processor to prevent spamming
+ the log. This is no longer necessary since high and low water thresholds
+ can better control when the message is logged.
+
+ It is beneficial to generate the warning each time a task processor
+ reaches the high water level because PJSIP stops processing new requests
+ while any high water alert is active. Without this change you would have
+ to enable at least debug level 3 logging to know about a repeated alert
+ trigger.
+
+ * Made generate the warning message whenever a task is pushed into the
+ task processor that triggers the high water alert.
+
+ * Appended 'again' to the warning for a repeated high water alert trigger.
+
+ Change-Id: Iabf75a004f7edaf1e5e8c323099418e667cac999
+
+2017-01-10 05:54 +0000 [0047b1bc49] Aaron An <anjb at ti-net.com.cn>
+
+ * res_rtp_asterisk: Fix bug in function CHANNEL(rtcp, all_rtt)
+
+ Function CHANNEL(rtcp,all_rtt) CHANNEL(rtcp,all_loss) CHANNEL(rtcp,all_jitter)
+ always return 0.0 due to wrong define of macro "AST_RTP_SATA_SET" and
+ "AST_RTP_STAT_STRCPY".
+ It should compare "combined" with "stat" not "current_stat".
+
+ ASTERISK-26710 #close
+ Reported-by: Aaron An
+ Tested-by: AaronAn
+
+ Change-Id: Id4140fafbf92e2db689dac5b17d9caa009028a15
+
+2017-01-10 18:10 +0000 [47474cfd54] gtjoseph <gjoseph at digium.com>
+
+ * debug_utilities: Create the ast_coredumper utility
+
+ This utility allows easy manipulation of asterisk coredumps.
+
+ * Configurable search paths and patterns for existing coredumps
+ * Can generate a consistent coredump from the running instance
+ * Can dump the lock_infos table from a coredump
+ * Dumps backtraces to separate files...
+ - thread apply 1 bt full -> <coredump>.thread1.txt
+ - thread apply all bt -> <coredump>.brief.txt
+ - thread apply all bt full -> <coredump>.full.txt
+ - lock_infos table -> <coredump>.locks.txt
+ * Can tarball corefiles and optionally delete them after processing
+ * Can tarball results files and optionally delete them after processing
+ * Converts ':' in coredump and results file names '-' to facilitate
+ uploading. Jira for instance, won't accept file names with colons
+ in them.
+
+ Tested on Fedora24+, Ubuntu14+, Debian6+, CentOS6+ and FreeBSD9+[1].
+
+ [1] For *BSDs, the "devel/gdb" package might have to be installed to
+ get a recent gdb. The utility will check all instances of gdb
+ it finds in $PATH and if one isn't found that can run python, it
+ prints a friendly error.
+
+ Change-Id: I935d37ab9db85ef923f32b05579897f0893d33cd
+
+2017-01-08 10:29 +0000 [f8cd73ec3c] gtjoseph <gjoseph at digium.com>
+
+ * pjproject_bundled: Fix compilation with MALLOC_DEBUG
+
+ When MALLOC_DEBUG was specified, make was failing. Immediately
+ remaking would work. The issues was in the ordering of the make
+ dependencies.
+
+ Change-Id: If6030b54fc693f3179f32bfd20c6b5d5f1b3f7cd
+
+2017-01-05 06:11 +0000 [37aaaa2da2] Joshua Colp <jcolp at digium.com>
+
+ * res_pjsip_endpoint_identifier_ip: Add support for SRV lookups.
+
+ This change implements SRV support for the IP based endpoint
+ identifier module. All possible addresses through SRV are looked
+ up and added as matches. If no SRV records are available a
+ fallback to normal host resolution is done. If an IP address
+ is provided then no SRV lookup occurs.
+
+ This is configured using the "srv_lookups" option on the
+ identify section and defaults to "yes".
+
+ ASTERISK-26693
+
+ Change-Id: I6b641e275bf96629320efa8b479737062aed82ac
+
+2016-12-22 09:13 +0000 [569dac8e50] Alexander Traud <pabstraud at compuserve.com>
+
+ * res_pjsip_session: Access SIPDOMAIN via Dialplan.
+
+ This feature was available in the SIP channel driver chan_sip. For example,
+ Asterisk is the outbound proxy and has to handle all SIP-URIs, even domains not
+ local to Asterisk. In that case, SIPDOMAIN is used in the Dialplan, to detect
+ and dial remote SIP-URIs. This change here sets the SIP destination domain of
+ an inbound call (SIPDOMAIN) in the SIP channel driver res_pjsip as well.
+
+ ASTERISK-26670 #close
+
+ Change-Id: I27c880dc404a3c1c6792e1ba3545475339577243
+
+2017-01-04 05:50 +0000 [367128e70b] Alexander Traud <pabstraud at compuserve.com>
+
+ * chan_sip: Remember SDP negotiation on SIP_CODEC_INBOUND.
+
+ After a SIP_CODEC_INBOUND in the dialplan, do not continue with cached formats
+ but remember the joint format. Cached formats contain default parameters,
+ often create an empty fmtp line. However, a joint format might have passed
+ format_get_joint(.) in a res_format_attr_* module (like Opus Codec) and
+ contain the resulting format parameters from a SDP negotiation.
+
+ ASTERISK-26691 #close
+
+ Change-Id: I35712d98a793d4c3efdd156cec57deab9014b1dc
+
+2017-01-03 15:14 +0000 [d7e5a747c3] gtjoseph <gjoseph at digium.com>
+
+ * pjproject_bundled: Compile pjsua with max log level = 2
+
+ A while back, we changed config_site.h to set PJ_LOG_MAX_LEVEL = 6.
+ This allowed us to control the log level better from inside Asterisk.
+ An unfortunate side effect of this was that the pjsua binary and
+ python bindings were also compiled with log level set to 6 so whenever
+ a testsuite test that uses pjsua runs, it spits out 6795 lines of
+ debug in an instant even before the test starts. I believe this
+ overruns the Jenkins capture buffer and prevents the test from
+ properly terminating. In turn, this results in the testsuite just
+ hanging until the job is killed. It's more frequent on the higher
+ end agents because they can spit out the messages faster.
+
+ Unfortunately, the messages are all spit out before we have control
+ of the python pj.Lib instance where we can set logging levels so the
+ only alternative was to actually compile pjsua and _pjsua.so with an
+ overridden PJ_LOG_MAX_LEVEL. Although defining a lower max level was
+ done in the Makefile, the define in config_site.h had to be wrapped
+ with "#ifndef" so the change would take effect.
+
+ Change-Id: I2af9e7d48dde1927279c586c9c725d868fe6f3ff
+
+2016-12-22 16:00 +0000 [34e728cfb9] Joshua Colp <jcolp at digium.com>
+
+ * chan_pjsip: Use session for retrieving CHANNEL() information.
+
+ The CHANNEL() dialplan function implementation for PJSIP allows
+ querying of PJSIP specific information. This used the channel
+ passed in to get the PJSIP session and associated information.
+ It is possible for this channel to be masqueraded and end
+ up as a different channel type by the time the information
+ request is actually acted upon.
+
+ This change retrieves the PJSIP session safely and accesses
+ data from it (including channel). This provides a guarantee
+ that the session and channel will not be altered when the
+ request is being acted upon.
+
+ ASTERISK-26673
+
+ Change-Id: I335e12b89e1820cafdd92b3e7526b8ba649eb7e6
+
+2016-12-31 19:56 +0000 [a398f98b08] Joshua Elson <joshelson at gmail.com>
+
+ * res_pjsip: Fix known compact header issues
+
+ ASTERISK-26684 #close
+
+ Change-Id: Ifd7e401c45015119dd5e8421dbfe3afa6381744a
+
+2016-12-30 09:10 +0000 [0ab9d103f6] JoshE (license 6075)
+
+ * res_pjsip_refer: Handle compact Refer-To header.
+
+ refer_incoming_refer_request needed to look for the "r" header as well
+ as the "Refer-To" header.
+
+ ASTERISK-26655 #close
+ patches:
+ refer_compact_fix.diff submitted by JoshE (license 6075)
+
+ Change-Id: I610410a99b02427ea5db887aeb454d5f12c2259f
+
+2016-12-23 12:11 +0000 [21151408f7] Richard Mudgett <rmudgett at digium.com>
+
+ * bridge_native_rtp.c: Minor code cleanups.
+
+ In native_rtp_bridge_compatible_check()
+
+ * Made one variable declaration per line.
+
+ * Extracted if test assignment to make the test easier to see.
+
+ * Made long if tests easier to see the combinatorial logic.
+
+ * Added bridge id to a couple debug messages.
+
+ Change-Id: I65bc5732aa7c9a2537f062f106fbea711cf2daad
+
+2016-12-23 12:10 +0000 [9dcf9e9cea] Richard Mudgett <rmudgett at digium.com>
+
+ * bridge_native_rtp.c: Fix native rtp bridge data race.
+
+ native_rtp_bridge_compatible() didn't lock the bridge channels before
+ checking the channels for native bridging ability. As a result, one of
+ the channel's native format capabilities structure got replaced out from
+ under the native bridge check. Use of a stale pointer to freed memory
+ causes bad things to happen.
+
+ MALLOC_DEBUG, DO_CRASH, and the
+ tests/channels/pjsip/transfers/blind_transfer/caller_direct_media
+ testsuite test caught this.
+
+ * Add missing channel locking in native_rtp_bridge_compatible().
+
+ Change-Id: If25fdb3ac8e85563c4857fb8216b3d9dc3d0fa53
+
+2016-12-21 16:28 +0000 [a9e459f8ac] Richard Mudgett <rmudgett at digium.com>
+
+ * res_rtp_asterisk.c: Fix uninitialized memory crash.
+
+ ast_rtp_remote_address_set() could pass an uninitialized 'us' parameter to
+ ast_ouraddrfor(). If ast_ouraddrfor() returns an error then the 'us'
+ parameter may not get initialized. Thus when the code tries to save the
+ 'us' parameter to the local address we could try to copy a ridiculous
+ sized memory buffer and segfault.
+
+ * Made pass an initialized 'us' parameter to ast_ouraddrfor().
+
+ * Optimized out the 'us' struct variable.
+
+ ASTERISK-26672 #close
+
+ Change-Id: I4acea5dcdf0813da2c7d3e11c2d6067d160d17dc
+
+2016-12-21 17:55 +0000 [bcdd282ada] Richard Mudgett <rmudgett at digium.com>
+
+ * res_rtp_asterisk.c: Initialize ourip passed to ast_find_ourip().
+
+ We access uninitialized memory when the 'ourip' parameter does not
+ have an initial guess to our IP address.
+
+ ASTERISK-26672
+
+ Change-Id: I35507ea1ad7455d2be188f6ccdd4add7bd150e15
+
+2016-12-21 16:25 +0000 [ac31233dbe] Richard Mudgett <rmudgett at digium.com>
+
+ * acl.c: Improve ast_ouraddrfor() diagnostic messages.
+
+ * Made not generate strings unless they will actually be used.
+
+ ASTERISK-26672
+
+ Change-Id: I155fbe7fdff5ce47dfe5326f3baf5446849702c3
+
+2016-12-21 17:54 +0000 [0aa5db4b38] Richard Mudgett <rmudgett at digium.com>
+
+ * chan_rtp.c: Fix uninitialized memory crash.
+
+ unicast_rtp_request() could pass an uninitialized 'us' parameter to
+ ast_ouraddrfor(). If ast_ouraddrfor() returns an error then the 'us'
+ parameter may not get initialized. Thus when the code tries to save the
+ 'us' parameter to the local address we could try to copy a ridiculous
+ sized memory buffer and segfault.
+
+ * Made pass an initialized 'us' parameter to ast_ouraddrfor() and abort
+ the UnicastRTP channel request if it fails.
+
+ ASTERISK-26672
+
+ Change-Id: I1ef7a7c09f4da4f15dcb6de660d2bcac5f2a95c0
+
+2016-12-07 15:23 +0000 [e2fa3c7eda] Richard Mudgett <rmudgett at digium.com>
+
+ * res_rtp_asterisk.c: Fix off nominal memory leak.
+
+ Change-Id: I95b1088d11244a2edae6607c12fbf33b38658a75
+
+2016-12-09 12:23 +0000 [d13be4eff6] Martin Tomec <tomec at ipex.cz>
+
+ * app_queue: Ensure member is removed from pending when hanging up.
+
+ In some cases member is added to pending_members, and the channel
+ is hung up before any extension state change. So the member would
+ stay in pending_members forever. So when we call do_hang, we
+ should also remove member from pending.
+
+ ASTERISK-26621 #close
+
+ Change-Id: Iae476b5c06481db18ebe0fa594b3e80fdc9a7d54
+
+2016-12-18 15:23 +0000 [815f755155] gtjoseph <gjoseph at digium.com>
+
+ * pjproject_bundled: Make build single threaded
+
+ There were just too many issues in various environments with
+ multi threaded building of pjproject. It doesn't really speed
+ things up anyway since asterisk is already being compiled in
+ parallel.
+
+ Change-Id: Ie5648fb91bb89b4224b6bf43a0daa1af793c4ce1
+
+2016-12-08 20:00 +0000 [493849dcd7] Corey Farrell <git at cfware.com>
+
+ * chan_sip: Reorder unload_module to deal with stuck TCP threads.
+
+ In some situations TCP threads may become frozen. This creates the
+ possibility that Asterisk could segfault if they become unfrozen after
+ chan_sip has been dlclose'd. This reorders the unload_module process to
+ allow abort if threads do not exit within 5 seconds.
+
+ High level order as follows:
+ 1) Unregister from the core to stop new requests.
+ 2) Signal threads to stop
+ 3) Clear config based tables (but do not free the table itself).
+ 4) Verify that threads have shutdown, cancel unload if not.
+ 5) Clean all remaining resources.
+
+ ASTERISK-26586
+
+ Change-Id: Ie23692041d838fbd35ece61868f4c640960ff882
+
+2016-12-16 01:32 +0000 [ab447f8a6a] David M. Lee <dlee at respoke.io>
+
+ * configure: fix with-pjproject-bundled
+
+ The AC_ARG_WITH macro's shell variable is withval; not enableval. Purely
+ coincidentally, the option would work when --enable-dev-mode is given.
+
+ Also fixed a portability problem with bootstrap.sh, since -printf is not
+ a portable option for find.
+
+ Change-Id: I0f0e5b1a934b5af5737713834361e9c95b96b376
+
+2016-12-15 13:25 +0000 [35736d419a] Richard Mudgett <rmudgett at digium.com>
+
+ * autosupport: Add 'pjproject show buildopts'
+
+ Change-Id: I8aa55a7c3fb175235ddc7f85e9457d5102d06fa7
+
+2016-12-14 14:21 +0000 [4b285d226d] Richard Mudgett <rmudgett at digium.com>
+
+ * chan_dahdi.c: Fix bounds check regression.
+
+ Caused by ASTERISK-25494
+
+ Change-Id: I1fc408c1a083745ff59da5c4113041bbfce54bcb
+
+2016-12-13 14:34 +0000 [9114574188] Richard Mudgett <rmudgett at digium.com>
+
+ * res_pjsip: Add/update ERROR msg if invalid URI.
+
+ ASTERISK-24499
+
+ Change-Id: Ie305153e47e922233b2ff24715e0e326e5fa3a6c
+
+2016-12-12 18:38 +0000 [75a6afbec5] Richard Mudgett <rmudgett at digium.com>
+
+ * MESSAGE: Flush Message/ast_msg_queue channel alert pipe.
+
+ ASTERISK-25083
+
+ Change-Id: Id54baa57a8dbca84e29f28bcd2ffc0a5ac12d8b2
+
+2016-12-13 14:06 +0000 [91485734a4] gtjoseph <gjoseph at digium.com>
+
+ * res_sorcery_memory_cache: Change an error to a debug message
+
+ When a sorcery user calls ast_sorcery_delete on an object that
+ may have already expired from the cache, res_sorcery_memory_cache
+ spits out an ERROR. Since this can happen frequently and validly when
+ an inbound registration expires after the cache entry expired, the
+ errors are unnecessary and misleading. Changed to a debug/1.
+
+ Change-Id: Idf3a67038c16e3da814cf612ff4d6d18ad29ecd7
+
+2016-12-09 08:14 +0000 [cd46e86491] gtjoseph <gjoseph at digium.com>
+
+ * pjproject_bundled: Retry download if previously saved tarball is bad
+
+ If a tarball is corrupted during download, the makefile will attempt to
+ download it again. If the tarball somehow gets corrupted after it's
+ downloaded however, the makefile was just failing. We now
+ retry the download.
+
+ ASTERISK-26653 #close
+
+ Change-Id: I1b24d454852d80186f60c5a65dc4624ea8a1c359
+
+2016-12-08 12:54 +0000 [22820e10fe] Badalyan Vyacheslav <v.badalyan at open-bs.ru>
+
+ * chan_sip: Delete unneeded check
+
+ P is always true. We check it before
+
+ Change-Id: Iee61cda002a9f61aee26b9f66c5f9b59e3389efb
+
+2016-12-08 12:58 +0000 [6aa2c5e5f9] Badalyan Vyacheslav <v.badalyan at open-bs.ru>
+
+ * Small code cleanup in chan_sip
+
+ The conditional expressions of the 'if' operators situated
+ alongside each other are identical.
+
+ Change-Id: I2cf7c317b106ec14440c7f1b5dcfbf03639f748a
+
+2016-12-08 12:43 +0000 [b596fac838] Badalyan Vyacheslav <v.badalyan at open-bs.ru>
+
+ * Fix typo in chan_sip
+
+ The conditional expressions of the 'if' operators
+ situated alongside each other are identical.
+
+ Change-Id: I652b6dcddb3be007e669a6aa8107edb31a1ddafb
+
+2016-12-08 12:30 +0000 [483ed9f1aa] Badalyan Vyacheslav <v.badalyan at open-bs.ru>
+
+ * res_pjsip: Fix 'A = B != C' kind.
+
+ Consider reviewing the expression of the 'A = B != C' kind.
+ The expression is calculated as following: 'A = (B != C)'
+
+ Change-Id: Ibaa637dfda47d51a20e26069d3103e05ce80003d
+
+2016-11-30 09:31 +0000 [41c6319c4e] Walter Doekes <walter+asterisk at wjd.nu>
* chan_sip: Do not allow non-SP/HTAB between header key and colon.
@@ -39,9 +1133,8 @@
AST-2016-009
Change-Id: I78086fbc524ac733b8f7f78cb423c91075fd489b
- (cherry picked from commit 41c6319c4e1261f40813e60017e3b65f4115c94d)
-2016-11-14 18:18 +0000 [fa52ecb9fb] Joshua Colp <jcolp at digium.com>
+2016-11-14 18:18 +0000 [888142e891] Joshua Colp <jcolp at digium.com>
* res_format_attr_opus: Fix crash when fmtp contains spaces.
@@ -56,15 +1149,379 @@
Change-Id: I01f53e5d9fa9f1925a7365f8d25071b5b3ac2dc3
-2016-11-23 15:26 +0000 Asterisk Development Team <asteriskteam at digium.com>
+2016-12-06 14:54 +0000 [ebc67d3053] gtjoseph <gjoseph at digium.com>
+
+ * res_pjsip_registrar: AMI Add RegistrationInboundContactStatuses command
+
+ The PJSIPShowRegistrationsInbound AMI command was just dumping out
+ all AORs which was pretty useless and resource heavy since it had
+ to get all endpoints, then all aors for each endpoint, then all
+ contacts for each aor.
+
+ PJSIPShowRegistrationInboundContactStatuses sends ContactStatusDetail
+ events which meets the intended purpose of the other command and has
+ significantly less overhead. Also, some additional fields that were
+ added to Contact since the original creation of the ContactStatusDetail
+ event have been added to the end of the event.
+
+ For compatibility purposes, PJSIPShowRegistrationsInbound is left
+ intact.
+
+ ASTERISK-26644 #close
+
+ Change-Id: I326f12c9ecb52bf37ba03f0748749de4da01490a
+
+2016-12-06 16:45 +0000 [d506874477] Richard Mudgett <rmudgett at digium.com>
+
+ * Bundled pjproject: Fix finding SIP transactions.
+
+ Occasionally SIP message transactions are not found when they should be.
+ In the particular case an incoming INVITE transaction is CANCELed but the
+ INVITE transaction cannot be found so a 481 response is returned for the
+ CANCEL. The problematic calls have a '_' character in the Via branch
+ parameter.
+
+ The problem is in the pjproject PJ_HASH_USE_OWN_TOLOWER feature's code.
+ The problem with the "own tolower" code is that it does not calculate the
+ same hash value as when the pj_tolower() function is used. The "own
+ tolower" code will erroneously modify the ASCII characters '@', '[', '\\',
+ ']', '^', and '_'. Calls to pj_hash_calc_tolower() can use the
+ PJ_HASH_USE_OWN_TOLOWER substitute algorithm when enabled. Calls to
+ pj_hash_get_lower(), pj_hash_set_lower(), and pj_hash_set_np_lower() call
+ find_entry() which never uses the PJ_HASH_USE_OWN_TOLOWER algorithm. As a
+ result you may not be able to find a hash tabled entry because the
+ calculated hash values would differ.
+
+ * Simply disable PJ_HASH_USE_OWN_TOLOWER.
+
+ ASTERISK-26490 #close
+
+ Change-Id: If89bfdb5f301b8b685881a9a2a6e0c3c5af32253
+
+2016-12-06 12:06 +0000 [4b233675d8] gtjoseph <gjoseph at digium.com>
+
+ * pjproject_bundled: Fix missing inclusion of symbols
+
+ Added back in a -g3, and an -O3 when DONT_OPTIMIZE is not set, to
+ the CFLAGS. Not sure how they went missing.
+
+ Also fixed an uninstall problem where we weren't removing the
+ symlink from libasteriskpj.so.2 to libasteriskpj.so. While I was
+ there, I fixed it for libasteriskssl as well.
+
+ Change-Id: I9e00873b1e9082d05b5549d974534b48a2142556
+
+2016-12-02 12:04 +0000 [580f83dac7] Richard Mudgett <rmudgett at digium.com>
+
+ * Remove files that got merged in error somehow to the 13 branch.
+
+ Change-Id: Id79e2226c31084f9252d5aede9050d3cf13322c8
+
+2016-11-30 18:25 +0000 [61ba2a014a] Richard Mudgett <rmudgett at digium.com>
+
+ * res_pjsip_outbound_registration.c: Filter redundant statsd reporting.
+
+ Increasing the testsuite shutdown timeout before forcibly killing
+ Asterisk allowed more events to be sent out. Some tests failed as
+ a result. The tests/channels/pjsip/statsd/registrations failed
+ because we now get the statsd events that a comment in the test
+ configuration stated couldn't be intercepted. Unfortunately, we
+ get a variable number of events because of internal status state
+ transition races generating redundant statsd events.
+
+ We were reporting redundant statsd PJSIP.registrations.state changes
+ for internal state changes that equated to the same thing publicly.
+
+ * Made update_client_state_status() filter out redundant statsd
+ updates.
+
+ ASTERISK-26527
+
+ Change-Id: If851c7d514bb530d9226e4941ba97dcf52000646
+
+2016-11-22 11:20 +0000 [2ceb609edb] Guido Falsi <mad at madpilot.net>
+
+ * res_rtp: Fix regression when IPv6 is not available.
+
+ The latest Release candidate fails to create RTP streams when IPv6
+ is not available. Due to the changes made in September the ast_sockaddr
+ structure passed around to create these streams is always of AF_INET6
+ type, causing failure when used for IPv4. This patch adds a utility
+ function to check for availability of IPv6 and applies such check
+ at startup to determine how to create the ast_sockaddr structures.
+
+ ASTERISK-26617 #close
+
+ Change-Id: I627a4e91795e821111e1cda523f083a40d0e0c3e
- * asterisk 13.13.0 Released.
+2016-11-28 19:43 +0000 [53459cdaa9] Eduardo S. Libardi <eslibardi at gmail.com>
-2016-11-22 18:02 +0000 Asterisk Development Team <asteriskteam at digium.com>
+ * res_calendar_caldav: Add support reading gmail calendar
- * asterisk 13.13.0-rc2 Released.
+ The response from gmail calendar includes the string name
+ "caldav:calendar-data". res_calendar_caldav implements
+ the example included in RFC 4791: string "C:calendar-data".
+ When reading the calendar, res_calendar_caldav compare the
+ string and if does not match just discards the event.
+ This commit compares the response to both strings,
+ successfully loading gmail calendar events.
+ Writing to gmail calendar is working prior to this fix.
-2016-11-21 09:40 +0000 [e246b36a3c] gtjoseph <gjoseph at digium.com>
+ ASTERISK-26624
+ Reported by: Eduardo S. Libardi
+
+ Change-Id: Ia1eef10552ae616efb645d390f5ffe81260d7d4a
+
+2016-11-23 18:27 +0000 [44fe4a5769] Richard Mudgett <rmudgett at digium.com>
+
+ * PJPROJECT logging: Made easier to get available logging levels.
+
+ Use of the new logging is as simple as issuing the new CLI command or
+ setting the new pjproject.conf option.
+
+ Other options that can affect the logging are how you have the pjproject
+ log levels mapped to Asterisk log types in pjproject.conf and if you have
+ configured Asterisk to log the DEBUG type messages. Altering the
+ pjproject.conf level mapping shouldn't be necessary for most installations
+ as the default mapping is sensible. Configuring Asterisk to log the DEBUG
+ message type is standard practice for collecting debug information.
+
+ * Added CLI "pjproject set log level" command to dynamically adjust the
+ maximum pjproject log message level.
+
+ * Added CLI "pjproject show log level" command to see the currently set
+ maximum pjproject log message level.
+
+ * Added pjproject.conf startup section "log_level" option to set the
+ initial maximum pjproject log message level so all messages could be
+ captured from initialization.
+
+ * Set PJ_LOG_MAX_LEVEL to 6 to compile in all defined logging levels into
+ bundled pjproject. Pjproject will use the currently set run time log
+ level to determine if a log message is generated just like Asterisk
+ verbose and debug logging levels.
+
+ * In log_forwarder(), made always log enabled and mapped pjproject log
+ messages. DEBUG mapped log messages are no longer gated by the current
+ Asterisk debug logging level.
+
+ * Removed RAII_VAR() from res_pjproject.c:get_log_level().
+
+ ASTERISK-26630 #close
+
+ Change-Id: I6dca12979f482ffb0450aaf58db0fe0f6d2e5389
+
+2016-11-30 10:48 +0000 [17b0b91afa] Mark Michelson <mmichelson at digium.com>
+
+ * Frame deferral: Re-queue deferred frames one-at-a-time.
+
+ The recent change that made frame deferral into an API had a behavior
+ change to it. When frame deferral was completed, we would take all of
+ the deferred frames and queue them all onto the channel in one call to
+ ast_queue_frame_head(). Before frame deferral was API-ized, places that
+ performed manual frame deferral would actually take each deferred frame
+ and queue them onto the channel.
+
+ This change in behavior caused the confbridge_recording test to start
+ failing consistently. Without going too crazily deep into the details,
+ a channel was getting "stuck" in an ast_safe_sleep(). An AMI redirect
+ was attempting to break it out of the sleep, but because there were more
+ frames in the channel read queue than expected, the channel ended up
+ being unable to break from its sleep loop.
+
+ By restoring the behavior of individual frame queuing after deferral,
+ the test starts passing again.
+
+ Note, this points to a potential underlying issue pointing to an
+ "unbalance" that can occur when queuing multiple frames at once,
+ and so a follow-up issue is being created to investigate that
+ possibility.
+
+ Change-Id: Ied5dacacda06d343dea751ed5814a03364fe5a7d
+
+2016-06-28 16:26 +0000 [b0c9f07f04] Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+ * OpenSSL 1.1.0 support
+
+ OpenSSL 1.1.0 includes some major changes in the interface. See
+ https://wiki.openssl.org/index.php/1.1_API_Changes .
+
+ Status: Right now there are still a few deprecation notes with OpenSSL
+ 1.1.0. But it's a start.
+
+ Changes:
+ * CRYPTO_LOCK is no longer available. Replace it with its value for now.
+ I don't completely understand what it is used for there.
+ * Remove several functions from libasteriskssl that seem to no longer be
+ needed.
+ * Structures have become opaque and are accesses with accessors.
+ * ERR_remove_thread_state() no longer needed.
+ * SSLv2 code now could no longer be used in 1.1.
+
+ ASTERISK-26109 #close
+
+ Change-Id: I5e29d477d486ca29b6aae0dc2f5dff960c1cb82b
+
+2016-11-28 15:12 +0000 [a33ed3327a] Matt Jordan <mjordan at digium.com>
+
+ * res/res_pjsip: Fix documentation whitespace issues
+
+ Tabs > Spaces.
+
+ Change-Id: If1e43a71822615a898e958e0f8b2e882606f0bd0
+
+2016-11-22 10:27 +0000 [09c36a6535] Matt Jordan <mjordan at digium.com>
+
+ * res_pjsip/chan_sip: Advertise 'ws' in the SIP URI transport parameter
+
+ Per RFC 7118 5.2, the SIP URI 'transport' parameter should advertise
+ 'ws' when WebSockets are to be used as the transport. This applies to
+ both secure and insecure WebSockets.
+
+ There were two bugs in Asterisk with respect to this:
+
+ (1) The most egregious occurs in res_pjsip. There, we advertise 'ws' for
+ insecure websockets and 'wss' for secure websockets. While this
+ would seem to make sense - since 'WS' and 'WSS' are used for the Via
+ Transport parameter - this is not the case for the SIP URI. This
+ patch corrects that by registering the secure websockets with
+ pjproject using the shorthand 'WS', and by returning 'ws' when asked
+ for the transport parameter. Note that in pjproject, it is perfectly
+ valid to have multiple transports use the same shorthand.
+
+ (2) In chan_sip, we return an upper-case version of the transport 'WS'
+ instead of 'ws'. Since we should be strict in what we send and
+ liberal in what we accept (within reason), this patch lower-cases
+ the transport before appending it to the parameter.
+
+ ASTERISK-24330 #close
+ Reported by: cervajs, Inaki Baz Castillo
+
+ Change-Id: Iff77b645f8cc3b7cd35168a6676c26b147f22f42
+
+2016-11-28 11:03 +0000 [29e887e9e1] gtjoseph <gjoseph at digium.com>
+
+ * build_tools: Fix download_externals to handle certified branches
+
+ download_externals wasn't handling the "certified/13.x" version
+ correctly.
+
+ Change-Id: I124d195bb117ca36fd7bf1150c630f3b474a9d9a
+
+2016-11-02 05:05 +0000 [bfb8c962c4] Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+
+ * autoconf: more variants for OSARCH linux-gnu
+
+ There are quite a few odd GNU/Linux platforms. Just call all of them
+ linux-gnu.
+
+ Specifically this fixes building the Debian platforms mips64el and x32.
+ And maybe also others.
+
+ ASTERISK-26546 #close
+
+ Change-Id: I06ec4bd7f0ee1c84b6b24d81538223b07c4174b1
+
+2016-11-17 08:25 +0000 [a1fa909033] Timo Teräs <timo.teras at iki.fi>
+
+ * codec_dahdi: Fix poll.h include.
+
+ POSIX defines poll.h. sys/poll.h should not be used as it is c-library
+ internal header which may or may not exist. Notably in musl including
+ sys/poll.h generates warning of being incorrect.
+
+ Change-Id: Ib318c1c7142a737bcf3caa4d8d72560bebe39252
+
+2016-11-26 10:57 +0000 [0cc8351484] Michael Kuron <m.kuron at gmx.de>
+
+ * chan_sip: Fix segfault during module unload
+
+ If a TCP/TLS connection was pending (not accepted and not timed out) during
+ unload of chan_sip, Asterisk would segfault when trying to send a signal to
+ a thread whose thread ID hadn't been recorded yet. This commit fixes that by
+ recording the thread ID before calling the blocking connect() syscall.
+ This was a regression introduced by 776a14386a55b5425c7e9617eff8af8b45427144.
+
+ The above wasn't enough to fix the segfault, which was now delayed to the
+ point where connect() timed out. Therefore, it was necessary to also remove
+ the SA_RESTART flag from the SIGURG sigaction so that pthread_kill() could be
+ used to interruput the connect() syscall.
+ This was a regression introduced by 5d313f51b982a18f7321adcf7c7a4e822d8b2714.
+
+ ASTERISK-26586 #close
+
+ Change-Id: I76fd9d47d56e4264e2629bce8ec15fecba673e7b
+
+2016-11-11 08:16 +0000 [8756ce64b7] gestoip2 <gestoip2 at ull.edu.es>
+
+ * res_rtp_asterisk: RTT miscalculation in RTCP
+
+ When retrieving RTCP stats for PJSIP channels, RTT values are unreliable.
+ RTT calculation is correct, but the data representation isn't. RTT is
+ represented by a 32-bit fixed-point number with the integer part in the
+ first 16 bits and the fractional part in the last 16 bits. In order to
+ get the RTT value, the fractional part is miscalculated, there is an
+ unnecessary 16 bit shift that causes overflow. Besides this there is
+ another mistake, when transforming the integer value to the fixed point
+ fractional part via bitwise operation, that loses precision.
+
+ * RTT fractional part is no longer shifted, avoiding overflow.
+
+ * RTT fractional part is transformed to its fixed-point value more
+ precisely.
+
+ * Fixed timeval2ntp() and ntp2timeval() second fraction conversions.
+
+ * Fixed NTP timestamp report logging. The usec was inexplicably
+ multiplied by 4096.
+
+ ASTERISK-26566 #close
+ Reported by Hector Royo Concepcion
+
+ Change-Id: Ie09bdabfee75afb3f1b8ddfd963e5219ada3b96f
+
+2016-11-15 13:44 +0000 [8e77d6f520] Michael Kuron <m.kuron at gmx.de>
+
+ * tcptls: Use new certificate upon sip reload
+
+ Previously, a TLS server socket would only be restarted upon sip reload if the
+ bind address had changed. This commit adds checking for changes to TLS
+ parameters like certificate, ciphers, etc. so they get picked up without
+ requiring a reload of the entire chan_sip module. This does not affect open
+ connections in any way, but new connections will use the new TLS parameters.
+ The changes also apply to HTTP and Manager.
+
+ ASTERISK-26604 #close
+
+ Change-Id: I169e86cefc6dcd627c915134015a6a1ab1aadbe6
+2016-11-11 00:29 +0000 [86d824b7ff] Timo Teräs <timo.teras at iki.fi>
+
+ * addons/chan_mobile: do not use strerror_r
+
+ The two reasons why it might be used are that some systems do not
+ implement strerror in thread safe manner, and that strerror_r returns
+ the error code in the string in case there's no error message.
+
+ However, all of asterisk elsewhere uses strerror() and assumes it
+ to be thread safe. And in chan_mobile the errno is also explicitly
+ printed so neither of the above reasons are valid.
+
+ The reasoning to remove usage is that there are actually two versions
+ of strerror_r: XSI and GNU. They are incompatible in their return
+ value, and there's no easy way to figure out which one is being
+ used. glibc gives you the GNU version if _GNU_SOURCE is defined,
+ but the same feature test macro is needed for other symbols. On
+ all other systems you assumedly get XSI symbol, and compilation warnings
+ as well as non-working error printing.
+
+ Thus the easiest solution is to just remove strerror_r and use
+ strerror as rest of the code. Alternative is to introduce ast_strerror
+ in separate translation unit so it can request the XSI symbol in
+ glibc case, and replace all usage of strerror.
+
+ Change-Id: I84d35225b5642d85d48bc35fdf399afbae28a91d
+
+2016-11-21 09:40 +0000 [425da14927] gtjoseph <gjoseph at digium.com>
* build: Backport addition of librt check to configure.ac
@@ -77,9 +1534,98 @@
Change-Id: I1424008fd8c90f389dda53162ec4a340b253a3c1
-2016-11-22 11:20 +0000 [855f05e525] Kevin Harwell <kharwell at digium.com>
+2016-11-16 12:05 +0000 [2a40c3a867] gtjoseph <gjoseph at digium.com>
+
+ * pjproject_bundled: Improve reliability of pjproject download
+
+ The download process now has a timeout which will cause wget to retry
+ if it stops retrieving data for 5 seconds and fetch and curl to timeout
+ if the whole retrieval take smore than 30 seconds.
+
+ If the tarball retrieval works, the MD5SUM file is retrieved from
+ the downloads site and the md5 checksum is verified.
+
+ If either the tarball retrieval or MD5SUM retrieval fails, or the
+ checksums don't match, the entire process is retried once. If it
+ fails again, any incomplete tarball is deleted.
+
+ .DELETE_ON_ERROR: was also added to the Makefile. Not only does
+ this delete the tarball on failure, it till also delete corrupted
+ library files from the pjproject source directory should they
+ fail to build correctly.
+
+ Tested all the way back to FreeBSD 9, CentOS 6, Debian 6 and
+ Ubuntu 14.
+
+ Change-Id: Iea7d33b96a31622ab1b6e54baebaf271959514e1
+
+2016-11-11 07:13 +0000 [12c4e664bc] Mikheili Dautashvili <mishadaut at gmail.com>
+
+ * main/app.c: Transmit Silence on ControlPlayback pause
+
+ ASTERISK-26562 #close
+
+ Change-Id: Ie6cb0ffc2b8c775639ce7784fe96f4ea00cfa2f8
+
+2016-11-15 15:01 +0000 [cf6d13180e] Alexei Gradinari <alex2grad at gmail.com>
+
+ * chan_pjsip: fix switching sending codec when asymmetric_rtp_codec=no
+
+ The sending codec is switched to the receiving codec and then
+ is switched back to the best native codec on EVERY receiving RTP packets.
+ This is because after call of ast_channel_set_rawwriteformat there is call
+ of ast_set_write_format which calls set_format which sets rawwriteformat
+ to the best native format.
+
+ This patch adds a new function ast_set_write_format_path which set
+ specific write path on channel and uses this function to switch
+ the sending codec.
+
+ ASTERISK-26603 #close
+
+ Change-Id: I5b7d098f8b254ce8f45546e6c36e5d324737f71d
+
+2016-11-10 13:34 +0000 [ee73af1d88] gtjoseph <gjoseph at digium.com>
+
+ * Update for 13.12.2
+
+2016-11-04 10:57 +0000 [a3614d75f6] Kevin Harwell <kharwell at digium.com>
+
+ * Revert "chan_sip: Fix lastrtprx always updated"
+
+ This reverts commit 93332cb1d0eea18021ea6538237297e627d6e2fc.
+
+ Unfortunately, the aforementioned commit caused a regression (incoming calls
+ would eventually disconnect). Thus it is being removed.
+
+ ASTERISK-26523 #close
+ ASTERISK-25270
+
+ Change-Id: Ibf5586adc303073a8eac667a4cbfdb6be184a64d
+
+2016-10-27 13:48 +0000 [7d7b52c434] Mark Michelson <mmichelson at digium.com>
+
+ * Update for 13.12.1
+
+2016-10-26 07:51 +0000 [9c761b8f45] Joshua Colp <jcolp at digium.com>
+
+ * app_voicemail: Clear voice mailbox in MailboxExists and MAILBOX_EXISTS.
+
+ When executing the MailboxExists dialplan application and
+ MAILBOX_EXISTS dialplan function the passed in temporary voice
+ mailbox was not cleared, causing it to try to free garbage.
+
+ ASTERISK-26503 #close
+
+ Change-Id: Ie21ccfa1b80b9c59318e596f6b8e17da2b5a7cb3
+
+2016-10-25 14:13 +0000 [226a7e36c5] Mark Michelson <mmichelson at digium.com>
+
+ * Update for 13.12.0
+
+2016-10-17 14:08 +0000 [df75b647da] Mark Michelson <mmichelson at digium.com>
- * Update for 13.13.0
+ * Update for 13.12.0-rc1
2016-11-18 18:59 +0000 Asterisk Development Team <asteriskteam at digium.com>
diff --git a/addons/chan_mobile.c b/addons/chan_mobile.c
index f748f79..7077704 100644
--- a/addons/chan_mobile.c
+++ b/addons/chan_mobile.c
@@ -3855,10 +3855,7 @@ static void *do_monitor_phone(void *data)
}
if ((at_msg = at_read_full(hfp->rsock, buf, sizeof(buf))) < 0) {
- /* XXX gnu specific strerror_r is assummed here, this
- * is not really safe. See the strerror(3) man page
- * for more info. */
- ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror_r(errno, buf, sizeof(buf)), errno);
+ ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror(errno), errno);
break;
}
@@ -3995,7 +3992,7 @@ static void *do_monitor_phone(void *data)
ast_debug(1, "[%s] error parsing message\n", pvt->id);
goto e_cleanup;
case AT_READ_ERROR:
- ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror_r(errno, buf, sizeof(buf)), errno);
+ ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror(errno), errno);
goto e_cleanup;
default:
break;
@@ -4073,11 +4070,7 @@ static void *do_monitor_headset(void *data)
continue;
if ((at_msg = at_read_full(pvt->rfcomm_socket, buf, sizeof(buf))) < 0) {
- if (strerror_r(errno, buf, sizeof(buf)))
- ast_debug(1, "[%s] error reading from device\n", pvt->id);
- else
- ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, buf, errno);
-
+ ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror(errno), errno);
goto e_cleanup;
}
ast_debug(1, "[%s] %s\n", pvt->id, buf);
diff --git a/apps/app_queue.c b/apps/app_queue.c
index c9f3aee..2867e6b 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -2331,6 +2331,7 @@ static int pending_members_cmp(void *obj, void *arg, int flags)
static void pending_members_remove(struct member *mem)
{
+ ast_debug(3, "Removed %s from pending_members\n", mem->membername);
ao2_find(pending_members, mem, OBJ_POINTER | OBJ_NODATA | OBJ_UNLINK);
}
@@ -4184,6 +4185,7 @@ static void do_hang(struct callattempt *o)
{
o->stillgoing = 0;
ast_hangup(o->chan);
+ pending_members_remove(o->member);
o->chan = NULL;
}
@@ -4264,6 +4266,7 @@ static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
* If not found add it to the container so another queue
* won't attempt to call this member at the same time.
*/
+ ast_debug(3, "Add %s to pending_members\n", call->member->membername);
ao2_link(pending_members, call->member);
ao2_unlock(pending_members);
@@ -4399,7 +4402,6 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
/* Again, keep going even if there's an error */
ast_verb(3, "Couldn't call %s\n", tmp->interface);
do_hang(tmp);
- pending_members_remove(tmp->member);
++*busies;
return 0;
}
@@ -9031,33 +9033,22 @@ static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask,
queue_t_unref(q, "Expiring creation reference");
}
-static int remove_members_and_mark_unfound(void *obj, void *arg, int flags)
+static int mark_unfound(void *obj, void *arg, int flags)
{
struct call_queue *q = obj;
char *queuename = arg;
if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
q->found = 0;
-
}
return 0;
}
-static int mark_dead_and_unfound(void *obj, void *arg, int flags)
+static int kill_if_unfound(void *obj, void *arg, int flags)
{
struct call_queue *q = obj;
char *queuename = arg;
- if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
+ if (!q->realtime && !q->found && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
q->dead = 1;
- q->found = 0;
- }
- return 0;
-}
-
-static int kill_dead_queues(void *obj, void *arg, int flags)
-{
- struct call_queue *q = obj;
- char *queuename = arg;
- if ((ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name)) && q->dead) {
return CMP_MATCH;
} else {
return 0;
@@ -9082,7 +9073,6 @@ static int reload_queues(int reload, struct ast_flags *mask, const char *queuena
char *cat;
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
- const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
if (!(cfg = ast_config_load("queues.conf", config_flags))) {
ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
@@ -9097,18 +9087,10 @@ static int reload_queues(int reload, struct ast_flags *mask, const char *queuena
/* We've made it here, so it looks like we're doing operations on all queues. */
ao2_lock(queues);
- /* Mark all queues as dead for the moment if we're reloading queues.
- * For clarity, we could just be reloading members, in which case we don't want to mess
- * with the other queue parameters at all*/
- if (queue_reload) {
- ao2_callback(queues, OBJ_NODATA | OBJ_NOLOCK, mark_dead_and_unfound, (char *) queuename);
- }
-
- if (member_reload) {
- ao2_callback(queues, OBJ_NODATA, remove_members_and_mark_unfound, (char *) queuename);
- }
+ /* Mark non-realtime queues not found at the beginning. */
+ ao2_callback(queues, OBJ_NODATA, mark_unfound, (char *) queuename);
- /* Chug through config file */
+ /* Chug through config file. */
cat = NULL;
while ((cat = ast_category_browse(cfg, cat)) ) {
if (!strcasecmp(cat, "general") && queue_reload) {
@@ -9120,9 +9102,9 @@ static int reload_queues(int reload, struct ast_flags *mask, const char *queuena
}
ast_config_destroy(cfg);
- /* Unref all the dead queues if we were reloading queues */
if (queue_reload) {
- ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NOLOCK, kill_dead_queues, (char *) queuename);
+ /* Unlink and mark dead all non-realtime queues that were not found in the configuration file. */
+ ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NOLOCK, kill_if_unfound, (char *) queuename);
}
ao2_unlock(queues);
return 0;
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c
index bee684e..1c75105 100644
--- a/apps/app_voicemail.c
+++ b/apps/app_voicemail.c
@@ -14316,7 +14316,7 @@ AST_TEST_DEFINE(test_voicemail_vmsayname)
ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
goto exit_vmsayname_test;
}
- snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
+ snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_DATA_DIR);
snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
/* we're not going to hear the sound anyway, just use a valid gsm audio file */
if ((res = symlink(dir, dir2))) {
@@ -14562,8 +14562,8 @@ AST_TEST_DEFINE(test_voicemail_notify_endl)
break;
}
- snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
- snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
+ snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_DATA_DIR);
+ snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_DATA_DIR);
if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
!(vmu = find_or_create(testcontext, testmailbox))) {
diff --git a/asterisk-13.13.1-summary.html b/asterisk-13.13.1-summary.html
deleted file mode 100644
index f31a497..0000000
--- a/asterisk-13.13.1-summary.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<!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-13.13.1</title><h1 align="center"><a name="top">Release Summary</a></h1><h3 align="center">asterisk-13.13.1</h3><h3 align="center">Date: 2016-12-08</h3><h3 align="center"><asteriskteam at 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 fr [...]
-<li><a href="http://downloads.asterisk.org/pub/security/AST-2016-008,AST-2016-009.html">AST-2016-008,AST-2016-009</a></li>
-</ul><p>The data in this summary reflects changes that have been made since the previous release, asterisk-13.13.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 com [...]
-<tr><th width="33%">Coders</th><th width="33%">Testers</th><th width="33%">Reporters</th></tr>
-<tr valign="top"><td width="33%">1 Kevin Harwell <kharwell at digium.com><br/>1 Walter Doekes <walter+asterisk at wjd.nu><br/>1 Joshua Colp <jcolp at digium.com><br/></td><td width="33%"><td width="33%">1 Walter Doekes <walter+asterisk at wjd.nu><br/>1 Jørgen H <asterisk.org at hovland.cx><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>Bug</h3><h4>Category: Channels/chan_sip/Interoperability</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26433">ASTERISK-26433</a>: chan_sip: Allows To-tag checks to be bypassed, setting up new calls<br/>Reported by: Walter Doekes<ul>
-<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=e80603b6d6ce512b6f1549b944d9dacbac8b21f2">[e80603b6d6]</a> Walter Doekes -- chan_sip: Do not allow non-SP/HTAB between header key and colon.</li>
-</ul><br><h4>Category: Resources/res_format_attr_opus</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26579">ASTERISK-26579</a>: codec_opus: Recursiveness when parsing fmtp line<br/>Reported by: Jørgen H<ul>
-<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=fa52ecb9fb36c6ad99591728e5330b5c715c8899">[fa52ecb9fb]</a> Joshua Colp -- res_format_attr_opus: Fix crash when fmtp contains spaces.</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=5e06e6d8a2375dbfa92c6bbfee5e2de438ede11d">5e06e6d8a2</a></td><td>Kevin Harwell</td><td>Update for 13.13.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>asterisk-13.13.0-summary.html | 304 ---------------
-asterisk-13.13.0-summary.txt | 767 ----------------------------------------
-b/.version | 2
-b/ChangeLog | 54 ++
-b/asterisk-13.13.1-summary.html | 15
-b/asterisk-13.13.1-summary.txt | 92 ++++
-6 files changed, 162 insertions(+), 1072 deletions(-)</pre><br></html>
\ No newline at end of file
diff --git a/asterisk-13.13.1-summary.txt b/asterisk-13.13.1-summary.txt
deleted file mode 100644
index 0f84bd0..0000000
--- a/asterisk-13.13.1-summary.txt
+++ /dev/null
@@ -1,115 +0,0 @@
- Release Summary
-
- asterisk-13.13.1
-
- Date: 2016-12-08
-
- <asteriskteam at 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-2016-008,AST-2016-009
-
- The data in this summary reflects changes that have been made since the
- previous release, asterisk-13.13.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 Kevin Harwell 1 Walter Doekes
- 1 Walter Doekes 1 JA,rgen H
- 1 Joshua Colp
-
- ----------------------------------------------------------------------
-
- 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.
-
- Bug
-
- Category: Channels/chan_sip/Interoperability
-
- ASTERISK-26433: chan_sip: Allows To-tag checks to be bypassed, setting up
- new calls
- Reported by: Walter Doekes
- * [e80603b6d6] Walter Doekes -- chan_sip: Do not allow non-SP/HTAB
- between header key and colon.
-
- Category: Resources/res_format_attr_opus
-
- ASTERISK-26579: codec_opus: Recursiveness when parsing fmtp line
- Reported by: JA,rgen H
- * [fa52ecb9fb] Joshua Colp -- res_format_attr_opus: Fix crash when fmtp
- contains spaces.
-
- ----------------------------------------------------------------------
-
- 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 |
- |--------------------+-----------------------+---------------------------|
- | 5e06e6d8a2 | Kevin Harwell | Update for 13.13.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.
-
- asterisk-13.13.0-summary.html | 304 ---------------
- asterisk-13.13.0-summary.txt | 767 ----------------------------------------
- b/.version | 2
- b/ChangeLog | 54 ++
- b/asterisk-13.13.1-summary.html | 15
- b/asterisk-13.13.1-summary.txt | 92 ++++
- 6 files changed, 162 insertions(+), 1072 deletions(-)
diff --git a/asterisk-13.14.0-summary.html b/asterisk-13.14.0-summary.html
new file mode 100644
index 0000000..fb8a8af
--- /dev/null
+++ b/asterisk-13.14.0-summary.html
@@ -0,0 +1,336 @@
+<!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-13.14.0</title><h1 align="center"><a name="top">Release Summary</a></h1><h3 align="center">asterisk-13.14.0</h3><h3 align="center">Date: 2017-02-13</h3><h3 align="center"><asteriskteam at 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="#open_issues">Open 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 is a point release of an existing major version. The changes included were made to address problems that have been identified in this release series, or are minor, backwards compatible new features or improvements. Users should be able to safely upgrade to this version if this release series is already in use. Users considering upgrading from a previous version a [...]
+<tr><th width="33%">Coders</th><th width="33%">Testers</th><th width="33%">Reporters</th></tr>
+<tr valign="top"><td width="33%">35 Richard Mudgett <rmudgett at digium.com><br/>19 George Joseph <gjoseph at digium.com><br/>8 Joshua Colp <jcolp at digium.com><br/>8 Mark Michelson <mmichelson at digium.com><br/>4 Badalyan Vyacheslav <v.badalyan at open-bs.ru><br/>4 Tzafrir Cohen <tzafrir.cohen at xorcom.com><br/>3 Sean Bright <sean.bright at gmail.com><br/>3 Kirill Katsnelson <kkm at smartaction.com><br/>2 Michael Kuron <m.kuron at gmx.de><br/>2 Kevin Harwell <kharwell at digium.com><br/>2 Alexander Traud <pabstra [...]
+</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>New Feature</h3><h4>Category: Core/General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26630">ASTERISK-26630</a>: Make logging PJPROJECT messages a bit easier<br/>Reported by: Richard Mudgett<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=44fe4a576968a61fc3c0f6633e5ea9fc2c104105">[44fe4a5769]</a> Richard Mudgett -- PJPROJECT logging: Made easier to get available logging levels.</li>
+</ul><br><h4>Category: Resources/res_pjsip/Bundling</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26630">ASTERISK-26630</a>: Make logging PJPROJECT messages a bit easier<br/>Reported by: Richard Mudgett<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=44fe4a576968a61fc3c0f6633e5ea9fc2c104105">[44fe4a5769]</a> Richard Mudgett -- PJPROJECT logging: Made easier to get available logging levels.</li>
+</ul><br><h3>Bug</h3><h4>Category: Applications/app_dial</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-24499">ASTERISK-24499</a>: Need more explicit debug when PJSIP dialstring is invalid<br/>Reported by: Rusty Newton<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=91145741885859471c6f07124ffda91d1b2bdd58">[9114574188]</a> Richard Mudgett -- res_pjsip: Add/update ERROR msg if invalid URI.</li>
+</ul><br><h4>Category: Applications/app_mixmonitor</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-21094">ASTERISK-21094</a>: MixMonitorMute mutes through stream if already slinear (e.g. Originate)<br/>Reported by: David Woolley<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=3aee19991355fc8c4bad6066dd7a0b1cf003c077">[3aee199913]</a> Sean Bright -- audiohooks: Muting a hook can mute underlying frames</li>
+</ul><br><h4>Category: Applications/app_queue</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26755">ASTERISK-26755</a>: app_queue: Random queues disappear on "core reload queue all"<br/>Reported by: Kirill Katsnelson<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=be92f10a16aaa575a91c00b065abd9562b0cc133">[be92f10a16]</a> Kirill Katsnelson -- app_queue: Fix queues randomly disappearing on reload</li>
+</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26621">ASTERISK-26621</a>: app_queue: Queue application does not ring members with Local interface<br/>Reported by: Jonas Kellens<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=d13be4eff699449172efbd9fed0ee97f6a790b6a">[d13be4eff6]</a> Martin Tomec -- app_queue: Ensure member is removed from pending when hanging up.</li>
+</ul><br><h4>Category: Applications/app_stasis</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26716">ASTERISK-26716</a>: ari: Channels with pre-dial handlers cannot be hung up via ARI<br/>Reported by: Tom Pawelek<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=43f0ff4b69358687a5f958a57dd8ba4bffc4a5f4">[43f0ff4b69]</a> Richard Mudgett -- channel.c: Fix unbalanced read queue deadlocking local channels.</li>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a199f94908601be10c0b43e3b3b7d67c41c5025f">[a199f94908]</a> Richard Mudgett -- res_agi: Prevent an AGI from eating frames it should not. (Re-do)</li>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=6bed318a660c5258925c84f5d3f7012f3183c2de">[6bed318a66]</a> Richard Mudgett -- Frame deferral: Revert API refactoring.</li>
+</ul><br><h4>Category: Applications/app_voicemail</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26503">ASTERISK-26503</a>: app_voicemail: Asterisk crashes when MailboxExists is used<br/>Reported by: Doug Lytle<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=9c761b8f45892211b52d2c6655d2641aa4a64cd6">[9c761b8f45]</a> Joshua Colp -- app_voicemail: Clear voice mailbox in MailboxExists and MAILBOX_EXISTS.</li>
+</ul><br><h4>Category: Channels/chan_dahdi</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25494">ASTERISK-25494</a>: build: GCC 5.1.x catches some new const, array bounds and missing paren issues<br/>Reported by: George Joseph<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=4b285d226d2e9d92f1be53e84435c7d4cbf290be">[4b285d226d]</a> Richard Mudgett -- chan_dahdi.c: Fix bounds check regression.</li>
+</ul><br><h4>Category: Channels/chan_pjsip</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26673">ASTERISK-26673</a>: chan_pjsip: Crash when using CHANNEL dialplan function around masquerade<br/>Reported by: Joshua Colp<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=34e728cfb9f175d85b463547ebf9977305b76c1b">[34e728cfb9]</a> Joshua Colp -- chan_pjsip: Use session for retrieving CHANNEL() information.</li>
+</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26603">ASTERISK-26603</a>: [patch] chan_pjsip: not switching sending codec to receiving codec when asymmetric_rtp_codec=no<br/>Reported by: Alexei Gradinari<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=cf6d13180effc92a2483dccc68f2f188689a40fa">[cf6d13180e]</a> Alexei Gradinari -- chan_pjsip: fix switching sending codec when asymmetric_rtp_codec=no</li>
+</ul><br><h4>Category: Channels/chan_rtp</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26672">ASTERISK-26672</a>: Crash when setting remote address on RTP instance<br/>Reported by: Richard Mudgett<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a9e459f8ace24f4d0c4febc2eb7fa17162c577c6">[a9e459f8ac]</a> Richard Mudgett -- res_rtp_asterisk.c: Fix uninitialized memory crash.</li>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=bcdd282adaae7d47c91172d4e38306fc3b3566c7">[bcdd282ada]</a> Richard Mudgett -- res_rtp_asterisk.c: Initialize ourip passed to ast_find_ourip().</li>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=ac31233dbe996b4e2a1ccf9b7b2b35f6ed19e43c">[ac31233dbe]</a> Richard Mudgett -- acl.c: Improve ast_ouraddrfor() diagnostic messages.</li>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=0aa5db4b38e80a059c3cd2c1d70ee9c509c0f488">[0aa5db4b38]</a> Richard Mudgett -- chan_rtp.c: Fix uninitialized memory crash.</li>
+</ul><br><h4>Category: Channels/chan_sip/CodecHandling</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26691">ASTERISK-26691</a>: Remember SDP negotiation on SIP_CODEC_INBOUND.<br/>Reported by: Alexander Traud<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=367128e70be203f1c2a7b5371cd8f72a5dc69905">[367128e70b]</a> Alexander Traud -- chan_sip: Remember SDP negotiation on SIP_CODEC_INBOUND.</li>
+</ul><br><h4>Category: Channels/chan_sip/General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25494">ASTERISK-25494</a>: build: GCC 5.1.x catches some new const, array bounds and missing paren issues<br/>Reported by: George Joseph<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=4b285d226d2e9d92f1be53e84435c7d4cbf290be">[4b285d226d]</a> Richard Mudgett -- chan_dahdi.c: Fix bounds check regression.</li>
+</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26523">ASTERISK-26523</a>: chan_sip: Asterisk 13.12.1 disconnects incoming calls after 2 minutes - rtptimeout behaving badly - regression<br/>Reported by: Michael Keuter<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a3614d75f650abd3a9028fccabfcd88649381284">[a3614d75f6]</a> Kevin Harwell -- Revert "chan_sip: Fix lastrtprx always updated"</li>
+</ul><br><h4>Category: Channels/chan_sip/Interoperability</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26433">ASTERISK-26433</a>: chan_sip: Allows To-tag checks to be bypassed, setting up new calls<br/>Reported by: Walter Doekes<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=41c6319c4e1261f40813e60017e3b65f4115c94d">[41c6319c4e]</a> Walter Doekes -- chan_sip: Do not allow non-SP/HTAB between header key and colon.</li>
+</ul><br><h4>Category: Channels/chan_sip/TCP-TLS</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26586">ASTERISK-26586</a>: chan_sip: Segfaults upon reload if client with MWI wasn't registered<br/>Reported by: Michael Kuron<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=493849dcd7224145388fac81bc791d219f17aae1">[493849dcd7]</a> Corey Farrell -- chan_sip: Reorder unload_module to deal with stuck TCP threads.</li>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=0cc8351484ffbad5c5d7294f68016a83de00b7c6">[0cc8351484]</a> Michael Kuron -- chan_sip: Fix segfault during module unload</li>
+</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26604">ASTERISK-26604</a>: chan_sip: sip reload doesn't apply changes to tlscertfile, tlsciphers, etc.<br/>Reported by: Michael Kuron<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=8e77d6f52039e3ba20374c8a0083ad73bcce9e98">[8e77d6f520]</a> Michael Kuron -- tcptls: Use new certificate upon sip reload</li>
+</ul><br><h4>Category: Channels/chan_sip/WebSocket</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-24330">ASTERISK-24330</a>: Requirement for 'wss' value in Contact header transport parameter on inbound traffic violates RFC7118<br/>Reported by: Marek Cervenka<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=09c36a65356093e2a40cd2b23ff9f945e1028589">[09c36a6535]</a> Matt Jordan -- res_pjsip/chan_sip: Advertise 'ws' in the SIP URI transport parameter</li>
+</ul><br><h4>Category: Channels/chan_skinny</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25494">ASTERISK-25494</a>: build: GCC 5.1.x catches some new const, array bounds and missing paren issues<br/>Reported by: George Joseph<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=4b285d226d2e9d92f1be53e84435c7d4cbf290be">[4b285d226d]</a> Richard Mudgett -- chan_dahdi.c: Fix bounds check regression.</li>
+</ul><br><h4>Category: Codecs/General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-24858">ASTERISK-24858</a>: [patch]Asterisk 13 PJSIP sends RTP packets in wrong byte order on Intel platform when using slin codec<br/>Reported by: Frankie Chin<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=339c30f2b65b005817b073bc9b7c8ad2e7e3fde9">[339c30f2b6]</a> Sean Bright -- res_rtp_asterisk: Swap byte-order when sending signed linear</li>
+</ul><br><h4>Category: Core/BuildSystem</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26546">ASTERISK-26546</a>: mips64el and x32 - undefined reference to symbol 'dlopen@@GLIBC_2.2'<br/>Reported by: Tzafrir Cohen<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=bfb8c962c4485815a1e0552113408738fff30eb2">[bfb8c962c4]</a> Tzafrir Cohen -- autoconf: more variants for OSARCH linux-gnu</li>
+</ul><br><h4>Category: Core/DNS</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26772">ASTERISK-26772</a>: Crash in srv.c on startup with pjsip<br/>Reported by: nappsoft<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=1f2ae7908d265e2c565f1aae5717b4047e2e4504">[1f2ae7908d]</a> nappsoft -- srv: Fix crash when ast_srv_lookup is used and 0 records are returned.</li>
+</ul><br><h4>Category: Core/General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26632">ASTERISK-26632</a>: core: Possibility of a frame "imbalance" leading to stuck channels.<br/>Reported by: Mark Michelson<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=43f0ff4b69358687a5f958a57dd8ba4bffc4a5f4">[43f0ff4b69]</a> Richard Mudgett -- channel.c: Fix unbalanced read queue deadlocking local channels.</li>
+</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26753">ASTERISK-26753</a>: AMI disconnect causes "ast_careful_fwrite: fwrite() returned error: Broken pipe"<br/>Reported by: Kirill Katsnelson<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=555e8cd2ba3d6e24ce678e7ebc0fb9a8895ead65">[555e8cd2ba]</a> Kirill Katsnelson -- ast_careful_fwrite to support EPIPE gracefully</li>
+</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25083">ASTERISK-25083</a>: Message.c: Message channel becomes saturated with frames leading to spammy log messages<br/>Reported by: Jonathan Rose<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=75a6afbec53141f26ad41c94c1b3499116b23508">[75a6afbec5]</a> Richard Mudgett -- MESSAGE: Flush Message/ast_msg_queue channel alert pipe.</li>
+</ul><br><h4>Category: Core/RTP</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-24858">ASTERISK-24858</a>: [patch]Asterisk 13 PJSIP sends RTP packets in wrong byte order on Intel platform when using slin codec<br/>Reported by: Frankie Chin<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=339c30f2b65b005817b073bc9b7c8ad2e7e3fde9">[339c30f2b6]</a> Sean Bright -- res_rtp_asterisk: Swap byte-order when sending signed linear</li>
+</ul><br><h4>Category: Documentation</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26704">ASTERISK-26704</a>: res_odbc.conf contains deprecated configuration: 'pooling', 'shared_connections', 'limit', and 'idlecheck' options were replaced by 'max_connections'.<br/>Reported by: Anthony Messina<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=70aff89e5dc7f04235e24382b034cb93b4262321">[70aff89e5d]</a> Sean Bright -- res_odbc: Remove deprecated settings from sample configuration file</li>
+</ul><br><h4>Category: General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26754">ASTERISK-26754</a>: build_tools: make_build_h does not handle \ in user name <br/>Reported by: Kirill Katsnelson<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=3c8f84786e7700d678a09d2060838ec2a4815b7d">[3c8f84786e]</a> Kirill Katsnelson -- make_build_h: handle backslashes in external strings</li>
+</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26546">ASTERISK-26546</a>: mips64el and x32 - undefined reference to symbol 'dlopen@@GLIBC_2.2'<br/>Reported by: Tzafrir Cohen<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=bfb8c962c4485815a1e0552113408738fff30eb2">[bfb8c962c4]</a> Tzafrir Cohen -- autoconf: more variants for OSARCH linux-gnu</li>
+</ul><br><h4>Category: Resources/res_agi</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25951">ASTERISK-25951</a>: res_agi: run_agi eats frames it shouldn't<br/>Reported by: George Joseph<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a199f94908601be10c0b43e3b3b7d67c41c5025f">[a199f94908]</a> Richard Mudgett -- res_agi: Prevent an AGI from eating frames it should not. (Re-do)</li>
+</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26343">ASTERISK-26343</a>: ASTERISK-25951 causes issues for callerid manipulation through agi<br/>Reported by: Morten Tryfoss<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a199f94908601be10c0b43e3b3b7d67c41c5025f">[a199f94908]</a> Richard Mudgett -- res_agi: Prevent an AGI from eating frames it should not. (Re-do)</li>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=6bed318a660c5258925c84f5d3f7012f3183c2de">[6bed318a66]</a> Richard Mudgett -- Frame deferral: Revert API refactoring.</li>
+</ul><br><h4>Category: Resources/res_format_attr_opus</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26579">ASTERISK-26579</a>: codec_opus: Recursiveness when parsing fmtp line<br/>Reported by: Jørgen H<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=888142e89160169220bff1bae742f6ef558a7b11">[888142e891]</a> Joshua Colp -- res_format_attr_opus: Fix crash when fmtp contains spaces.</li>
+</ul><br><h4>Category: Resources/res_http_websocket</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-24330">ASTERISK-24330</a>: Requirement for 'wss' value in Contact header transport parameter on inbound traffic violates RFC7118<br/>Reported by: Marek Cervenka<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=09c36a65356093e2a40cd2b23ff9f945e1028589">[09c36a6535]</a> Matt Jordan -- res_pjsip/chan_sip: Advertise 'ws' in the SIP URI transport parameter</li>
+</ul><br><h4>Category: Resources/res_odbc</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26704">ASTERISK-26704</a>: res_odbc.conf contains deprecated configuration: 'pooling', 'shared_connections', 'limit', and 'idlecheck' options were replaced by 'max_connections'.<br/>Reported by: Anthony Messina<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=70aff89e5dc7f04235e24382b034cb93b4262321">[70aff89e5d]</a> Sean Bright -- res_odbc: Remove deprecated settings from sample configuration file</li>
+</ul><br><h4>Category: Resources/res_pjsip</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26679">ASTERISK-26679</a>: Crash on invalid contact domain (pjsip aor)<br/>Reported by: Dmitriy<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=e371e13b9eb6ce1f60bf31a8d25c7d4bdcd01d8d">[e371e13b9e]</a> Joshua Colp -- res_pjsip: Handle invocation of callback on outgoing request when error occurs.</li>
+</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26699">ASTERISK-26699</a>: res_pjsip: Assertion when sending OPTIONS request to endpoint<br/>Reported by: Ross Beer<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=e371e13b9eb6ce1f60bf31a8d25c7d4bdcd01d8d">[e371e13b9e]</a> Joshua Colp -- res_pjsip: Handle invocation of callback on outgoing request when error occurs.</li>
+</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26743">ASTERISK-26743</a>: PJPROJECT: Detecting compiled max log level does not work.<br/>Reported by: Richard Mudgett<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=30cb4eb57fe25e14a14e99008f5706b0f994d10b">[30cb4eb57f]</a> Richard Mudgett -- PJPROJECT logging: Fix detection of max supported log level.</li>
+</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26684">ASTERISK-26684</a>: res_pjsip: Various issues with compact SIP headers<br/>Reported by: Joshua Elson<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a398f98b08f98538ec6c70b67f46a5a24fe4d001">[a398f98b08]</a> Joshua Elson -- res_pjsip: Fix known compact header issues</li>
+</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-24499">ASTERISK-24499</a>: Need more explicit debug when PJSIP dialstring is invalid<br/>Reported by: Rusty Newton<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=91145741885859471c6f07124ffda91d1b2bdd58">[9114574188]</a> Richard Mudgett -- res_pjsip: Add/update ERROR msg if invalid URI.</li>
+</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26490">ASTERISK-26490</a>: res_pjsip: sends 481 Call/Transaction Does Not Exist when transaction branch parameter contains "_"<br/>Reported by: Juris Breicis<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=d506874477d2b2d64f50fa5d2fa77565934656d6">[d506874477]</a> Richard Mudgett -- Bundled pjproject: Fix finding SIP transactions.</li>
+</ul><br><h4>Category: Resources/res_pjsip/Bundling</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26743">ASTERISK-26743</a>: PJPROJECT: Detecting compiled max log level does not work.<br/>Reported by: Richard Mudgett<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=30cb4eb57fe25e14a14e99008f5706b0f994d10b">[30cb4eb57f]</a> Richard Mudgett -- PJPROJECT logging: Fix detection of max supported log level.</li>
+</ul><br><h4>Category: Resources/res_pjsip_endpoint_identifier_ip</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26735">ASTERISK-26735</a>: res_pjsip_endpoint_identifier_ip: "srv_lookups" after match in .conf has no effect<br/>Reported by: Michael Maier<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=aae9df06433512f58701daf66ae99c292d6c9908">[aae9df0643]</a> Joshua Colp -- res_pjsip_endpoint_identifier_ip: Fix memory leak of hosts when resolving.</li>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=6d23b2e360789f44923b527fa97564a2ff648268">[6d23b2e360]</a> Joshua Colp -- res_pjsip_endpoint_identifier_ip: Read settings before resolving.</li>
+</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26693">ASTERISK-26693</a>: res_pjsip_endpoint_identifier_ip: Add support for SRV<br/>Reported by: Joshua Colp<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a2f0adccbd0fc3ea18a222783aeecd09cf427815">[a2f0adccbd]</a> Joshua Colp -- res_pjsip_endpoint_identifier_ip: Ensure error defaults to 0.</li>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=37aaaa2da24ee7f3631a63b26c96fd3586cedbcb">[37aaaa2da2]</a> Joshua Colp -- res_pjsip_endpoint_identifier_ip: Add support for SRV lookups.</li>
+</ul><br><h4>Category: Resources/res_pjsip_registrar</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26644">ASTERISK-26644</a>: PJSIPShowRegistrationsInbound just dumps all aors<br/>Reported by: George Joseph<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=ebc67d305398caf8738dcc4b7c88b9e40fa3d58e">[ebc67d3053]</a> gtjoseph -- res_pjsip_registrar: AMI Add RegistrationInboundContactStatuses command</li>
+</ul><br><h4>Category: Resources/res_pjsip_session</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26670">ASTERISK-26670</a>: [patch] Outgoing SIP-URI Dialing via PJSIP<br/>Reported by: Alexander Traud<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=569dac8e50dd9213dd6c0f9f060fe697377e6f70">[569dac8e50]</a> Alexander Traud -- res_pjsip_session: Access SIPDOMAIN via Dialplan.</li>
+</ul><br><h4>Category: Resources/res_rtp_asterisk</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-24858">ASTERISK-24858</a>: [patch]Asterisk 13 PJSIP sends RTP packets in wrong byte order on Intel platform when using slin codec<br/>Reported by: Frankie Chin<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=339c30f2b65b005817b073bc9b7c8ad2e7e3fde9">[339c30f2b6]</a> Sean Bright -- res_rtp_asterisk: Swap byte-order when sending signed linear</li>
+</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26710">ASTERISK-26710</a>: [patch] res_rtp_asterisk: CHANNEL arguments, (rtcp,all_rtt),(rtcp,all_loss),(rtcp,all_jitter) always return 0<br/>Reported by: Aaron An<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=0047b1bc4962b5051608c8f7a02a8b03ee4d7ec5">[0047b1bc49]</a> Aaron An -- res_rtp_asterisk: Fix bug in function CHANNEL(rtcp, all_rtt)</li>
+</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26672">ASTERISK-26672</a>: Crash when setting remote address on RTP instance<br/>Reported by: Richard Mudgett<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a9e459f8ace24f4d0c4febc2eb7fa17162c577c6">[a9e459f8ac]</a> Richard Mudgett -- res_rtp_asterisk.c: Fix uninitialized memory crash.</li>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=bcdd282adaae7d47c91172d4e38306fc3b3566c7">[bcdd282ada]</a> Richard Mudgett -- res_rtp_asterisk.c: Initialize ourip passed to ast_find_ourip().</li>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=ac31233dbe996b4e2a1ccf9b7b2b35f6ed19e43c">[ac31233dbe]</a> Richard Mudgett -- acl.c: Improve ast_ouraddrfor() diagnostic messages.</li>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=0aa5db4b38e80a059c3cd2c1d70ee9c509c0f488">[0aa5db4b38]</a> Richard Mudgett -- chan_rtp.c: Fix uninitialized memory crash.</li>
+</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26617">ASTERISK-26617</a>: res_rtp_asterisk: Can't bind on systems without IPv6<br/>Reported by: Guido Falsi<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=2ceb609edb64e930300806e75dc1a45386f800ef">[2ceb609edb]</a> Guido Falsi -- res_rtp: Fix regression when IPv6 is not available.</li>
+</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26566">ASTERISK-26566</a>: res_rtp_asterisk: RTT miscalculation in RTCP<br/>Reported by: Hector Royo Concepcion<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=8756ce64b7874dbcc0cd9a47aa09fc21cb4f9f81">[8756ce64b7]</a> gestoip2 -- res_rtp_asterisk: RTT miscalculation in RTCP</li>
+</ul><br><h4>Category: Resources/res_sorcery_memory_cache</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26731">ASTERISK-26731</a>: res_sorcery_memory_cache: memory leak on every sorcery memory cache populate<br/>Reported by: Ustinov Artem<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=75497c33ea4f52d969c0d845ab30d0c152c34c4d">[75497c33ea]</a> Mark Michelson -- Free endpoint ACLs when destroying PJSIP endpoints.</li>
+</ul><br><h4>Category: Tests/General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26740">ASTERISK-26740</a>: voicemail API test: uses varlibdir instead of datadir for a sound file<br/>Reported by: Tzafrir Cohen<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=cd2677f966574980caeb6da2cdcaa2dc5ec1e83f">[cd2677f966]</a> Tzafrir Cohen -- tests: use datadir for sound files</li>
+</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26739">ASTERISK-26739</a>: voicemail API test: confuses expected and actual values<br/>Reported by: Tzafrir Cohen<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=b62f84bfb1cec9ad7099aaa6f63ac4cfc08cb829">[b62f84bfb1]</a> Tzafrir Cohen -- test_voicemail_api: order of params to VERIFY macros</li>
+</ul><br><h4>Category: Third-Party/pjproject</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26653">ASTERISK-26653</a>: pjproject_bundled doesn't verify already downloaded tarballs<br/>Reported by: George Joseph<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=cd46e86491e3f8946bbe9c97b8a1d7eaf708dda9">[cd46e86491]</a> gtjoseph -- pjproject_bundled: Retry download if previously saved tarball is bad</li>
+</ul><br><h4>Category: pjproject/pjsip</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26655">ASTERISK-26655</a>: [patch]pjsip: Transfers Broken with Compact Headers Enabled<br/>Reported by: JoshE<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=0ab9d103f614c6339334c60bc032c1f8f941326c">[0ab9d103f6]</a> JoshE -- res_pjsip_refer: Handle compact Refer-To header.</li>
+</ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26490">ASTERISK-26490</a>: res_pjsip: sends 481 Call/Transaction Does Not Exist when transaction branch parameter contains "_"<br/>Reported by: Juris Breicis<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=d506874477d2b2d64f50fa5d2fa77565934656d6">[d506874477]</a> Richard Mudgett -- Bundled pjproject: Fix finding SIP transactions.</li>
+</ul><br><h3>Improvement</h3><h4>Category: Applications/app_controlplayback</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26562">ASTERISK-26562</a>: app_controlplayback: Transmit Silence on ControlPlayback pause<br/>Reported by: Mikheili Dautashvili<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=12c4e664bc864e4272688fe9ce10a99d0630bc34">[12c4e664bc]</a> Mikheili Dautashvili -- main/app.c: Transmit Silence on ControlPlayback pause</li>
+</ul><br><h4>Category: Resources/res_calendar_caldav</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26624">ASTERISK-26624</a>: res_calendar_caldav: Add support for gmail<br/>Reported by: Eduardo Scudeller Libardi<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=53459cdaa958bbbebc3edb18f460e522bbf56b2f">[53459cdaa9]</a> Eduardo S. Libardi -- res_calendar_caldav: Add support reading gmail calendar</li>
+</ul><br><h4>Category: Resources/res_pjsip</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-23828">ASTERISK-23828</a>: pjsip - Need a command to list active SIP subscriptions<br/>Reported by: Rusty Newton<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=e3dcb9ddd957fb64ddd43a7656463c0fe0c444cf">[e3dcb9ddd9]</a> Richard Mudgett -- res_pjsip_pubsub.c: Implement "pjsip show subscriptions" commands.</li>
+</ul><br><h4>Category: Tests/testsuite</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26527">ASTERISK-26527</a>: Testsuite: increase timeout to check "core fullybooted wait" up to 30 sec<br/>Reported by: Badalian Vyacheslav<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=61ba2a014a25a8423f775b61b7ac56f951be3df8">[61ba2a014a]</a> Richard Mudgett -- res_pjsip_outbound_registration.c: Filter redundant statsd reporting.</li>
+</ul><br><hr><a name="open_issues"><h2 align="center">Open Issues</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a list of all open issues from the issue tracker that were referenced by changes that went into this release.</p><h3>Bug</h3><h4>Category: Core/BuildSystem</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26109">ASTERISK-26109</a>: Asterisk fails building with OpenSSL 1.1.0<br/>Reported by: Tzafrir Cohen<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=b0c9f07f040dfa1713899f6b5ad1e3321bd56481">[b0c9f07f04]</a> Tzafrir Cohen -- OpenSSL 1.1.0 support</li>
+</ul><br><h4>Category: Core/Jitterbuffer</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25270">ASTERISK-25270</a>: chan_sip: rtptimeout doesn't work at all when using JitterBuffers of any kind<br/>Reported by: Florian Loyau<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a3614d75f650abd3a9028fccabfcd88649381284">[a3614d75f6]</a> Kevin Harwell -- Revert "chan_sip: Fix lastrtprx always updated"</li>
+</ul><br><h4>Category: Core/RTP</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25270">ASTERISK-25270</a>: chan_sip: rtptimeout doesn't work at all when using JitterBuffers of any kind<br/>Reported by: Florian Loyau<ul>
+<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a3614d75f650abd3a9028fccabfcd88649381284">[a3614d75f6]</a> Kevin Harwell -- Revert "chan_sip: Fix lastrtprx always updated"</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=ec97c41ac817bce13d8bd9436c35ad3ef95a9f72">ec97c41ac8</a></td><td>gtjoseph</td><td>Update for 13.14.0-rc2</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=3f3290ce4f83c00a8ab4c25378ebf0c0e797453b">3f3290ce4f</a></td><td>Mark Michelson</td><td>Revert "Update qualifies when AOR configuration changes."</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=7dbe77d63946ce204611a75d5f79d37f9d624ee1">7dbe77d639</a></td><td>gtjoseph</td><td>Update for 13.14.0-rc1</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=6492e91392b8fd394193e411c6eb64b45486093f">6492e91392</a></td><td>Mark Michelson</td><td>Update qualifies when AOR configuration changes.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=7fd28cefdb2a41308b22b6e29d9a10ff38acb2e5">7fd28cefdb</a></td><td>gtjoseph</td><td>debug_utilities: Install ast_logescalator to /var/lib/asterisk/scripts</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=456bc3c704ffce7807caa6f5f4bc92ed1720c871">456bc3c704</a></td><td>gtjoseph</td><td>debug_utilities: Add ast_logescalator</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=54b027916a71f2b83b2050cef5ef704ea5de39b2">54b027916a</a></td><td>Torrey Searle</td><td>libastssl/pj: libastssl/pj should have an so_version</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=9e3150b98ddf4ecfe09e281c73c634b89ba2514e">9e3150b98d</a></td><td>Mark Michelson</td><td>Add reload options to CLI/AMI stale object commands.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=c54f9d2bf01ab943c122c5326da52decf6e492cd">c54f9d2bf0</a></td><td>Richard Mudgett</td><td>T.140: Fix format ref and memory leaks.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=607b3ac736e9bdd69acb69f85c2d5a66271a4bb2">607b3ac736</a></td><td>Richard Mudgett</td><td>astobj2.c: Add excessive ref count trap.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=ab8cb5a7ce227ed2c889d58a04d7167aa49e3f63">ab8cb5a7ce</a></td><td>Richard Mudgett</td><td>main/app.c: Memory corruption from early format destruction.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=dcd8e4b1a0fd5159e6799a71d15ba56e16c374a7">dcd8e4b1a0</a></td><td>Richard Mudgett</td><td>frame.c: Fix off-nominal format ref leaks.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=00a227e93dec78170a0637a1216f619f70f73df9">00a227e93d</a></td><td>Richard Mudgett</td><td>stasis_bridge.c: Fix off-nominal stasis control ref leak.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=38a2021c68df5352f601439c7317cac5082d10a8">38a2021c68</a></td><td>Richard Mudgett</td><td>res_musiconhold.c: Fix format ref leak when parsing MOH config class.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=ab7a9fc5b29c274651159b18f7057c9b150fede3">ab7a9fc5b2</a></td><td>Richard Mudgett</td><td>chan_oss.c: Fix format ref leak in oss_read().</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=1484a991e17bb3320fbf8d1cfbe92d7ba5d6ea01">1484a991e1</a></td><td>Richard Mudgett</td><td>Add notes about embedded ast_frame structs holding a format ref.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=17f4989d49c7117684c04bff8a3e6fed1c6e6aad">17f4989d49</a></td><td>gtjoseph</td><td>ari: Implement 'debug all' and request/response logging</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=177e81ee47708a30b0a042acf4be19b4b812676e">177e81ee47</a></td><td>gtjoseph</td><td>pjproject_bundled: Fix setting max log level</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a969bf357708514104b67274a6c07d4697ea0eff">a969bf3577</a></td><td>Richard Mudgett</td><td>LISTFILTER: Remove outdated ERROR message.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=3890337e7a14bb04bcd2d60b2112de588ec93828">3890337e7a</a></td><td>Richard Mudgett</td><td>res_pjsip_pubsub.c: Fix AMI event list counts.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=fe4801c4f95a89ecc83cec14bec9f90a40994528">fe4801c4f9</a></td><td>Richard Mudgett</td><td>res_pjsip_pubsub.c: Fix incorrect message string wrapping.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=46484b87300e249b1a8584fe0f45a57e8362f723">46484b8730</a></td><td>Richard Mudgett</td><td>res_pjsip_pubsub.c: Eliminate trivial SCOPED_LOCK usage.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=8160474d7db9b5975172c88d27cc6c1880700831">8160474d7d</a></td><td>Richard Mudgett</td><td>res_pjsip: alloca can never fail.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=c628a7acacea0d519e0e5919a2a1db1ba5851ee0">c628a7acac</a></td><td>gtjoseph</td><td>debug_utilities: Create ast_loggrabber</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=e335b706ee4e592c168e23dca5a813f84988778f">e335b706ee</a></td><td>Richard Mudgett</td><td>res_pjsip_outbound_authenticator_digest.c: Fix spacing in warning messages.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=883e7fde31ab9db886c482f12383f6baa57e9e92">883e7fde31</a></td><td>Kevin Harwell</td><td>abstract/fixed/adpative jitter buffer: disallow frame re-inserts</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=473330983b47618772b1dd414df8e063e5da6a53">473330983b</a></td><td>Richard Mudgett</td><td>taskprocessor.c: Change when high water warning logged.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=47474cfd54a9185c1433464ccfd6301427a03957">47474cfd54</a></td><td>gtjoseph</td><td>debug_utilities: Create the ast_coredumper utility</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=f8cd73ec3c159f2e6c464952c92d8fdb69394371">f8cd73ec3c</a></td><td>gtjoseph</td><td>pjproject_bundled: Fix compilation with MALLOC_DEBUG</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=d7e5a747c312de18647213359103ce6022776864">d7e5a747c3</a></td><td>gtjoseph</td><td>pjproject_bundled: Compile pjsua with max log level = 2</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=21151408f7d984c7652f479f03ddd452e1d275f7">21151408f7</a></td><td>Richard Mudgett</td><td>bridge_native_rtp.c: Minor code cleanups.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=9dcf9e9cea87b7bf7f2bbdbaddd51377a6138bfa">9dcf9e9cea</a></td><td>Richard Mudgett</td><td>bridge_native_rtp.c: Fix native rtp bridge data race.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=e2fa3c7edabd52b62830a32930b0b4aaf4bcb9ac">e2fa3c7eda</a></td><td>Richard Mudgett</td><td>res_rtp_asterisk.c: Fix off nominal memory leak.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=815f7551550908c83220196ba08742af0c745772">815f755155</a></td><td>gtjoseph</td><td>pjproject_bundled: Make build single threaded</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=ab447f8a6a3d05908395ed52ec3b981c1e8943c1">ab447f8a6a</a></td><td>David M. Lee</td><td>configure: fix with-pjproject-bundled</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=35736d419a85b877072fe3688f410376b8ce4613">35736d419a</a></td><td>Richard Mudgett</td><td>autosupport: Add 'pjproject show buildopts'</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=91485734a48e9e44292b80b8993fb464bc3817b0">91485734a4</a></td><td>gtjoseph</td><td>res_sorcery_memory_cache: Change an error to a debug message</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=22820e10fe866df47373bb2ef18d159cea40079b">22820e10fe</a></td><td>Badalyan Vyacheslav</td><td>chan_sip: Delete unneeded check</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=6aa2c5e5f967128a89a95e40c8846bbd091eb6fb">6aa2c5e5f9</a></td><td>Badalyan Vyacheslav</td><td>Small code cleanup in chan_sip</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=b596fac8384c470af6fc656953609882c629fe7d">b596fac838</a></td><td>Badalyan Vyacheslav</td><td>Fix typo in chan_sip</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=483ed9f1aa2575a94f9ccfd6c490e72d4611f249">483ed9f1aa</a></td><td>Badalyan Vyacheslav</td><td>res_pjsip: Fix 'A = B != C' kind.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=4b233675d86fef64e6ccce82a0f7b038d3c7e032">4b233675d8</a></td><td>gtjoseph</td><td>pjproject_bundled: Fix missing inclusion of symbols</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=580f83dac713614bd8904f8722a900299ff4f8bc">580f83dac7</a></td><td>Richard Mudgett</td><td>Remove files that got merged in error somehow to the 13 branch.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=17b0b91afa1aa6b8b503a75e96b054f13612356a">17b0b91afa</a></td><td>Mark Michelson</td><td>Frame deferral: Re-queue deferred frames one-at-a-time.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a33ed3327aa7530b9c9dbd98bd575f85c15ec8a4">a33ed3327a</a></td><td>Matt Jordan</td><td>res/res_pjsip: Fix documentation whitespace issues</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=29e887e9e11d3a60ebc0f177ba3dcddb2e07e8fe">29e887e9e1</a></td><td>gtjoseph</td><td>build_tools: Fix download_externals to handle certified branches</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a1fa9090337aeb14cc5e86cd7d212d35cc95b37a">a1fa909033</a></td><td>Timo Teräs</td><td>codec_dahdi: Fix poll.h include.</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=86d824b7fff5c9135694dbff6dc2a64b51964752">86d824b7ff</a></td><td>Timo Teräs</td><td>addons/chan_mobile: do not use strerror_r</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=425da14927f10205911f5db6d6b193b22203c224">425da14927</a></td><td>gtjoseph</td><td>build: Backport addition of librt check to configure.ac</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=2a40c3a8679f1a02d88c48f0424fa41df09203a8">2a40c3a867</a></td><td>gtjoseph</td><td>pjproject_bundled: Improve reliability of pjproject download</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=ee73af1d88c9ff6db90f70f934f5ea57b8ab0625">ee73af1d88</a></td><td>gtjoseph</td><td>Update for 13.12.2</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=7d7b52c434eb23ef470ad51d08ee4029a7078b78">7d7b52c434</a></td><td>Mark Michelson</td><td>Update for 13.12.1</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=226a7e36c538de73cee76de4183b1569bd5501e5">226a7e36c5</a></td><td>Mark Michelson</td><td>Update for 13.12.0</td></tr>
+<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=df75b647da03eba6920020bac0cc950032a1e930">df75b647da</a></td><td>Mark Michelson</td><td>Update for 13.12.0-rc1</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>asterisk-13.13.0-summary.html | 304 -
+asterisk-13.13.0-summary.txt | 767 ----
+b/.version | 2
+b/CHANGES | 50
+b/ChangeLog | 1614 +++++++++-
+b/addons/chan_mobile.c | 13
+b/apps/app_queue.c | 40
+b/apps/app_voicemail.c | 6
+b/asterisk-13.14.0-rc2-summary.html | 20
+b/asterisk-13.14.0-rc2-summary.txt | 104
+b/bootstrap.sh | 2
+b/bridges/bridge_native_rtp.c | 81
+b/build_tools/download_externals | 4
+b/build_tools/make_build_h | 10
+b/channels/chan_dahdi.c | 4
+b/channels/chan_oss.c | 2
+b/channels/chan_pjsip.c | 9
+b/channels/chan_rtp.c | 7
+b/channels/chan_sip.c | 111
+b/channels/pjsip/dialplan_functions.c | 62
+b/codecs/codec_dahdi.c | 2
+b/configs/samples/ast_debug_tools.conf.sample | 57
+b/configs/samples/pjproject.conf.sample | 25
+b/configs/samples/res_odbc.conf.sample | 6
+b/configure | 12
+b/configure.ac | 10
+b/contrib/Makefile | 14
+b/contrib/ast-db-manage/config/versions/28ab27a7826d_add_srv_lookups_to_identify.py | 31
+b/contrib/realtime/mssql/mssql_config.sql | 14
+b/contrib/realtime/mysql/mysql_config.sql | 6
+b/contrib/realtime/oracle/oracle_config.sql | 14
+b/contrib/realtime/postgresql/postgresql_config.sql | 6
+b/contrib/scripts/ast_coredumper | 533 +++
+b/contrib/scripts/ast_logescalator | 399 ++
+b/contrib/scripts/ast_loggrabber | 255 +
+b/contrib/scripts/autosupport | 4
+b/funcs/func_strings.c | 1
+b/include/asterisk/abstract_jb.h | 3
+b/include/asterisk/ari.h | 24
+b/include/asterisk/channel.h | 72
+b/include/asterisk/frame.h | 2
+b/include/asterisk/mod_format.h | 6
+b/include/asterisk/options.h | 41
+b/include/asterisk/res_pjsip.h | 10
+b/include/asterisk/rtp_engine.h | 4
+b/include/asterisk/stasis_app.h | 49
+b/include/asterisk/tcptls.h | 4
+b/include/asterisk/translate.h | 2
+b/include/asterisk/utils.h | 9
+b/include/jitterbuf.h | 3
+b/main/Makefile | 12
+b/main/abstract_jb.c | 31
+b/main/acl.c | 36
+b/main/app.c | 36
+b/main/asterisk.c | 35
+b/main/astobj2.c | 13
+b/main/audiohook.c | 40
+b/main/autoservice.c | 66
+b/main/channel.c | 217 -
+b/main/channel_internal_api.c | 68
+b/main/fixedjitterbuf.c | 6
+b/main/fixedjitterbuf.h | 3
+b/main/format_compatibility.c | 4
+b/main/frame.c | 69
+b/main/jitterbuf.c | 5
+b/main/libasteriskpj.c | 2
+b/main/libasteriskssl.c | 4
+b/main/manager.c | 6
+b/main/message.c | 9
+b/main/rtp_engine.c | 2
+b/main/srv.c | 3
+b/main/strings.c | 21
+b/main/taskprocessor.c | 8
+b/main/tcptls.c | 94
+b/main/utils.c | 24
+b/makeopts.in | 2
+b/res/ari/ari_websockets.c | 14
+b/res/ari/cli.c | 175 +
+b/res/ari/resource_events.c | 9
+b/res/res_agi.c | 10
+b/res/res_ari.c | 77
+b/res/res_ari_applications.c | 42
+b/res/res_ari_asterisk.c | 120
+b/res/res_ari_bridges.c | 162 -
+b/res/res_ari_channels.c | 318 -
+b/res/res_ari_device_states.c | 27
+b/res/res_ari_endpoints.c | 45
+b/res/res_ari_events.c | 18
+b/res/res_ari_mailboxes.c | 27
+b/res/res_ari_playbacks.c | 24
+b/res/res_ari_recordings.c | 48
+b/res/res_ari_sounds.c | 21
+b/res/res_calendar_caldav.c | 4
+b/res/res_format_attr_opus.c | 38
+b/res/res_musiconhold.c | 2
+b/res/res_pjproject.c | 156
+b/res/res_pjsip.c | 72
+b/res/res_pjsip/pjsip_configuration.c | 6
+b/res/res_pjsip/pjsip_options.c | 17
+b/res/res_pjsip_diversion.c | 3
+b/res/res_pjsip_endpoint_identifier_ip.c | 160
+b/res/res_pjsip_history.c | 91
+b/res/res_pjsip_outbound_authenticator_digest.c | 12
+b/res/res_pjsip_outbound_registration.c | 21
+b/res/res_pjsip_pubsub.c | 635 +++
+b/res/res_pjsip_refer.c | 8
+b/res/res_pjsip_registrar.c | 70
+b/res/res_pjsip_sdp_rtp.c | 7
+b/res/res_pjsip_session.c | 8
+b/res/res_pjsip_t38.c | 7
+b/res/res_pjsip_transport_websocket.c | 5
+b/res/res_rtp_asterisk.c | 117
+b/res/res_sorcery_memory_cache.c | 41
+b/res/res_stasis.c | 23
+b/res/stasis/app.c | 73
+b/res/stasis/app.h | 27
+b/res/stasis/stasis_bridge.c | 6
+b/rest-api-templates/param_parsing.mustache | 15
+b/rest-api-templates/res_ari_resource.c.mustache | 3
+b/tests/test_ari.c | 22
+b/tests/test_substitution.c | 9
+b/tests/test_voicemail_api.c | 52
+b/third-party/Makefile | 2
+b/third-party/Makefile.rules | 4
+b/third-party/pjproject/Makefile | 61
+b/third-party/pjproject/configure.m4 | 8
+b/third-party/pjproject/patches/0000-set_apps_initial_log_level.patch | 13
+res/stasis/cli.c | 216 -
+res/stasis/cli.h | 43
+129 files changed, 5945 insertions(+), 2895 deletions(-)</pre><br></html>
\ No newline at end of file
diff --git a/asterisk-13.14.0-summary.txt b/asterisk-13.14.0-summary.txt
new file mode 100644
index 0000000..e2c3043
--- /dev/null
+++ b/asterisk-13.14.0-summary.txt
@@ -0,0 +1,878 @@
+ Release Summary
+
+ asterisk-13.14.0
+
+ Date: 2017-02-13
+
+ <asteriskteam at digium.com>
+
+ ----------------------------------------------------------------------
+
+ Table of Contents
+
+ 1. Summary
+ 2. Contributors
+ 3. Closed Issues
+ 4. Open Issues
+ 5. Other Changes
+ 6. Diffstat
+
+ ----------------------------------------------------------------------
+
+ Summary
+
+ [Back to Top]
+
+ This release is a point release of an existing major version. The changes
+ included were made to address problems that have been identified in this
+ release series, or are minor, backwards compatible new features or
+ improvements. Users should be able to safely upgrade to this version if
+ this release series is already in use. Users considering upgrading from a
+ previous version are strongly encouraged to review the UPGRADE.txt
+ document as well as the CHANGES document for information about upgrading
+ to this release series.
+
+ The data in this summary reflects changes that have been made since the
+ previous release, asterisk-13.13.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
+ 35 Richard Mudgett 1 AaronAn 6 Richard Mudgett
+ 19 George Joseph 4 Tzafrir Cohen
+ 8 Joshua Colp 4 George Joseph
+ 8 Mark Michelson 3 Michael Kuron
+ 4 Badalyan Vyacheslav 3 Joshua Colp
+ 4 Tzafrir Cohen 3 Kirill Katsnelson
+ 3 Sean Bright 3 Tom Pawelek
+ 3 Kirill Katsnelson 2 Rusty Newton
+ 2 Michael Kuron 2 Morten Tryfoss
+ 2 Kevin Harwell 2 Alexander Traud
+ 2 Alexander Traud 2 Michael Maier
+ 2 Matt Jordan 1 Walter Doekes
+ 2 Timo TerACURs 1 Alexei Gradinari
+ 1 Walter Doekes 1 Ustinov Artem
+ 1 Alexei Gradinari 1 Dmitriy
+ 1 Martin Tomec 1 Michael Keuter
+ 1 Guido Falsi 1 Jonas Kellens
+ 1 Joshua Elson 1 Guido Falsi
+ 1 jassim mishal 1 Ross Beer
+ 1 Aaron An 1 Mikheili Dautashvili
+ 1 nappsoft 1 Juris Breicis
+ 1 JoshE 1 Aaron An
+ 1 Corey Farrell 1 nappsoft
+ 1 gestoip2 1 JoshE
+ 1 Eduardo Scudeller Libardi 1 Hector Royo Concepcion
+ 1 David M. Lee 1 Frankie Chin
+ 1 Torrey Searle 1 Eduardo S. Libardi
+ 1 Eduardo Scudeller Libardi
+ 1 Badalian Vyacheslav
+ 1 Doug Lytle
+ 1 David Woolley
+ 1 David Woolley
+ 1 Jonathan Rose
+ 1 Joshua Elson
+ 1 Anthony Messina
+ 1 Marek Cervenka
+ 1 Florian Loyau
+ 1 cervajs, Inaki Baz Castillo
+ 1 JA,rgen H
+ 1 Mark Michelson
+
+ ----------------------------------------------------------------------
+
+ 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.
+
+ New Feature
+
+ Category: Core/General
+
+ ASTERISK-26630: Make logging PJPROJECT messages a bit easier
+ Reported by: Richard Mudgett
+ * [44fe4a5769] Richard Mudgett -- PJPROJECT logging: Made easier to get
+ available logging levels.
+
+ Category: Resources/res_pjsip/Bundling
+
+ ASTERISK-26630: Make logging PJPROJECT messages a bit easier
+ Reported by: Richard Mudgett
+ * [44fe4a5769] Richard Mudgett -- PJPROJECT logging: Made easier to get
+ available logging levels.
+
+ Bug
+
+ Category: Applications/app_dial
+
+ ASTERISK-24499: Need more explicit debug when PJSIP dialstring is invalid
+ Reported by: Rusty Newton
+ * [9114574188] Richard Mudgett -- res_pjsip: Add/update ERROR msg if
+ invalid URI.
+
+ Category: Applications/app_mixmonitor
+
+ ASTERISK-21094: MixMonitorMute mutes through stream if already slinear
+ (e.g. Originate)
+ Reported by: David Woolley
+ * [3aee199913] Sean Bright -- audiohooks: Muting a hook can mute
+ underlying frames
+
+ Category: Applications/app_queue
+
+ ASTERISK-26755: app_queue: Random queues disappear on "core reload queue
+ all"
+ Reported by: Kirill Katsnelson
+ * [be92f10a16] Kirill Katsnelson -- app_queue: Fix queues randomly
+ disappearing on reload
+ ASTERISK-26621: app_queue: Queue application does not ring members with
+ Local interface
+ Reported by: Jonas Kellens
+ * [d13be4eff6] Martin Tomec -- app_queue: Ensure member is removed from
+ pending when hanging up.
+
+ Category: Applications/app_stasis
+
+ ASTERISK-26716: ari: Channels with pre-dial handlers cannot be hung up via
+ ARI
+ Reported by: Tom Pawelek
+ * [43f0ff4b69] Richard Mudgett -- channel.c: Fix unbalanced read queue
+ deadlocking local channels.
+ * [a199f94908] Richard Mudgett -- res_agi: Prevent an AGI from eating
+ frames it should not. (Re-do)
+ * [6bed318a66] Richard Mudgett -- Frame deferral: Revert API
+ refactoring.
+
+ Category: Applications/app_voicemail
+
+ ASTERISK-26503: app_voicemail: Asterisk crashes when MailboxExists is used
+ Reported by: Doug Lytle
+ * [9c761b8f45] Joshua Colp -- app_voicemail: Clear voice mailbox in
+ MailboxExists and MAILBOX_EXISTS.
+
+ Category: Channels/chan_dahdi
+
+ ASTERISK-25494: build: GCC 5.1.x catches some new const, array bounds and
+ missing paren issues
+ Reported by: George Joseph
+ * [4b285d226d] Richard Mudgett -- chan_dahdi.c: Fix bounds check
+ regression.
+
+ Category: Channels/chan_pjsip
+
+ ASTERISK-26673: chan_pjsip: Crash when using CHANNEL dialplan function
+ around masquerade
+ Reported by: Joshua Colp
+ * [34e728cfb9] Joshua Colp -- chan_pjsip: Use session for retrieving
+ CHANNEL() information.
+ ASTERISK-26603: [patch] chan_pjsip: not switching sending codec to
+ receiving codec when asymmetric_rtp_codec=no
+ Reported by: Alexei Gradinari
+ * [cf6d13180e] Alexei Gradinari -- chan_pjsip: fix switching sending
+ codec when asymmetric_rtp_codec=no
+
+ Category: Channels/chan_rtp
+
+ ASTERISK-26672: Crash when setting remote address on RTP instance
+ Reported by: Richard Mudgett
+ * [a9e459f8ac] Richard Mudgett -- res_rtp_asterisk.c: Fix uninitialized
+ memory crash.
+ * [bcdd282ada] Richard Mudgett -- res_rtp_asterisk.c: Initialize ourip
+ passed to ast_find_ourip().
+ * [ac31233dbe] Richard Mudgett -- acl.c: Improve ast_ouraddrfor()
+ diagnostic messages.
+ * [0aa5db4b38] Richard Mudgett -- chan_rtp.c: Fix uninitialized memory
+ crash.
+
+ Category: Channels/chan_sip/CodecHandling
+
+ ASTERISK-26691: Remember SDP negotiation on SIP_CODEC_INBOUND.
+ Reported by: Alexander Traud
+ * [367128e70b] Alexander Traud -- chan_sip: Remember SDP negotiation on
+ SIP_CODEC_INBOUND.
+
+ Category: Channels/chan_sip/General
+
+ ASTERISK-25494: build: GCC 5.1.x catches some new const, array bounds and
+ missing paren issues
+ Reported by: George Joseph
+ * [4b285d226d] Richard Mudgett -- chan_dahdi.c: Fix bounds check
+ regression.
+ ASTERISK-26523: chan_sip: Asterisk 13.12.1 disconnects incoming calls
+ after 2 minutes - rtptimeout behaving badly - regression
+ Reported by: Michael Keuter
+ * [a3614d75f6] Kevin Harwell -- Revert "chan_sip: Fix lastrtprx always
+ updated"
+
+ Category: Channels/chan_sip/Interoperability
+
+ ASTERISK-26433: chan_sip: Allows To-tag checks to be bypassed, setting up
+ new calls
+ Reported by: Walter Doekes
+ * [41c6319c4e] Walter Doekes -- chan_sip: Do not allow non-SP/HTAB
+ between header key and colon.
+
+ Category: Channels/chan_sip/TCP-TLS
+
+ ASTERISK-26586: chan_sip: Segfaults upon reload if client with MWI wasn't
+ registered
+ Reported by: Michael Kuron
+ * [493849dcd7] Corey Farrell -- chan_sip: Reorder unload_module to deal
+ with stuck TCP threads.
+ * [0cc8351484] Michael Kuron -- chan_sip: Fix segfault during module
+ unload
+ ASTERISK-26604: chan_sip: sip reload doesn't apply changes to tlscertfile,
+ tlsciphers, etc.
+ Reported by: Michael Kuron
+ * [8e77d6f520] Michael Kuron -- tcptls: Use new certificate upon sip
+ reload
+
+ Category: Channels/chan_sip/WebSocket
+
+ ASTERISK-24330: Requirement for 'wss' value in Contact header transport
+ parameter on inbound traffic violates RFC7118
+ Reported by: Marek Cervenka
+ * [09c36a6535] Matt Jordan -- res_pjsip/chan_sip: Advertise 'ws' in the
+ SIP URI transport parameter
+
+ Category: Channels/chan_skinny
+
+ ASTERISK-25494: build: GCC 5.1.x catches some new const, array bounds and
+ missing paren issues
+ Reported by: George Joseph
+ * [4b285d226d] Richard Mudgett -- chan_dahdi.c: Fix bounds check
+ regression.
+
+ Category: Codecs/General
+
+ ASTERISK-24858: [patch]Asterisk 13 PJSIP sends RTP packets in wrong byte
+ order on Intel platform when using slin codec
+ Reported by: Frankie Chin
+ * [339c30f2b6] Sean Bright -- res_rtp_asterisk: Swap byte-order when
+ sending signed linear
+
+ Category: Core/BuildSystem
+
+ ASTERISK-26546: mips64el and x32 - undefined reference to symbol
+ 'dlopen@@GLIBC_2.2'
+ Reported by: Tzafrir Cohen
+ * [bfb8c962c4] Tzafrir Cohen -- autoconf: more variants for OSARCH
+ linux-gnu
+
+ Category: Core/DNS
+
+ ASTERISK-26772: Crash in srv.c on startup with pjsip
+ Reported by: nappsoft
+ * [1f2ae7908d] nappsoft -- srv: Fix crash when ast_srv_lookup is used
+ and 0 records are returned.
+
+ Category: Core/General
+
+ ASTERISK-26632: core: Possibility of a frame "imbalance" leading to stuck
+ channels.
+ Reported by: Mark Michelson
+ * [43f0ff4b69] Richard Mudgett -- channel.c: Fix unbalanced read queue
+ deadlocking local channels.
+ ASTERISK-26753: AMI disconnect causes "ast_careful_fwrite: fwrite()
+ returned error: Broken pipe"
+ Reported by: Kirill Katsnelson
+ * [555e8cd2ba] Kirill Katsnelson -- ast_careful_fwrite to support EPIPE
+ gracefully
+ ASTERISK-25083: Message.c: Message channel becomes saturated with frames
+ leading to spammy log messages
+ Reported by: Jonathan Rose
+ * [75a6afbec5] Richard Mudgett -- MESSAGE: Flush Message/ast_msg_queue
+ channel alert pipe.
+
+ Category: Core/RTP
+
+ ASTERISK-24858: [patch]Asterisk 13 PJSIP sends RTP packets in wrong byte
+ order on Intel platform when using slin codec
+ Reported by: Frankie Chin
+ * [339c30f2b6] Sean Bright -- res_rtp_asterisk: Swap byte-order when
+ sending signed linear
+
+ Category: Documentation
+
+ ASTERISK-26704: res_odbc.conf contains deprecated configuration:
+ 'pooling', 'shared_connections', 'limit', and 'idlecheck' options were
+ replaced by 'max_connections'.
+ Reported by: Anthony Messina
+ * [70aff89e5d] Sean Bright -- res_odbc: Remove deprecated settings from
+ sample configuration file
+
+ Category: General
+
+ ASTERISK-26754: build_tools: make_build_h does not handle \ in user name
+ Reported by: Kirill Katsnelson
+ * [3c8f84786e] Kirill Katsnelson -- make_build_h: handle backslashes in
+ external strings
+ ASTERISK-26546: mips64el and x32 - undefined reference to symbol
+ 'dlopen@@GLIBC_2.2'
+ Reported by: Tzafrir Cohen
+ * [bfb8c962c4] Tzafrir Cohen -- autoconf: more variants for OSARCH
+ linux-gnu
+
+ Category: Resources/res_agi
+
+ ASTERISK-25951: res_agi: run_agi eats frames it shouldn't
+ Reported by: George Joseph
+ * [a199f94908] Richard Mudgett -- res_agi: Prevent an AGI from eating
+ frames it should not. (Re-do)
+ ASTERISK-26343: ASTERISK-25951 causes issues for callerid manipulation
+ through agi
+ Reported by: Morten Tryfoss
+ * [a199f94908] Richard Mudgett -- res_agi: Prevent an AGI from eating
+ frames it should not. (Re-do)
+ * [6bed318a66] Richard Mudgett -- Frame deferral: Revert API
+ refactoring.
+
+ Category: Resources/res_format_attr_opus
+
+ ASTERISK-26579: codec_opus: Recursiveness when parsing fmtp line
+ Reported by: JA,rgen H
+ * [888142e891] Joshua Colp -- res_format_attr_opus: Fix crash when fmtp
+ contains spaces.
+
+ Category: Resources/res_http_websocket
+
+ ASTERISK-24330: Requirement for 'wss' value in Contact header transport
+ parameter on inbound traffic violates RFC7118
+ Reported by: Marek Cervenka
+ * [09c36a6535] Matt Jordan -- res_pjsip/chan_sip: Advertise 'ws' in the
+ SIP URI transport parameter
+
+ Category: Resources/res_odbc
+
+ ASTERISK-26704: res_odbc.conf contains deprecated configuration:
+ 'pooling', 'shared_connections', 'limit', and 'idlecheck' options were
+ replaced by 'max_connections'.
+ Reported by: Anthony Messina
+ * [70aff89e5d] Sean Bright -- res_odbc: Remove deprecated settings from
+ sample configuration file
+
+ Category: Resources/res_pjsip
+
+ ASTERISK-26679: Crash on invalid contact domain (pjsip aor)
+ Reported by: Dmitriy
+ * [e371e13b9e] Joshua Colp -- res_pjsip: Handle invocation of callback
+ on outgoing request when error occurs.
+ ASTERISK-26699: res_pjsip: Assertion when sending OPTIONS request to
+ endpoint
+ Reported by: Ross Beer
+ * [e371e13b9e] Joshua Colp -- res_pjsip: Handle invocation of callback
+ on outgoing request when error occurs.
+ ASTERISK-26743: PJPROJECT: Detecting compiled max log level does not work.
+ Reported by: Richard Mudgett
+ * [30cb4eb57f] Richard Mudgett -- PJPROJECT logging: Fix detection of
+ max supported log level.
+ ASTERISK-26684: res_pjsip: Various issues with compact SIP headers
+ Reported by: Joshua Elson
+ * [a398f98b08] Joshua Elson -- res_pjsip: Fix known compact header
+ issues
+ ASTERISK-24499: Need more explicit debug when PJSIP dialstring is invalid
+ Reported by: Rusty Newton
+ * [9114574188] Richard Mudgett -- res_pjsip: Add/update ERROR msg if
+ invalid URI.
+ ASTERISK-26490: res_pjsip: sends 481 Call/Transaction Does Not Exist when
+ transaction branch parameter contains "_"
+ Reported by: Juris Breicis
+ * [d506874477] Richard Mudgett -- Bundled pjproject: Fix finding SIP
+ transactions.
+
+ Category: Resources/res_pjsip/Bundling
+
+ ASTERISK-26743: PJPROJECT: Detecting compiled max log level does not work.
+ Reported by: Richard Mudgett
+ * [30cb4eb57f] Richard Mudgett -- PJPROJECT logging: Fix detection of
+ max supported log level.
+
+ Category: Resources/res_pjsip_endpoint_identifier_ip
+
+ ASTERISK-26735: res_pjsip_endpoint_identifier_ip: "srv_lookups" after
+ match in .conf has no effect
+ Reported by: Michael Maier
+ * [aae9df0643] Joshua Colp -- res_pjsip_endpoint_identifier_ip: Fix
+ memory leak of hosts when resolving.
+ * [6d23b2e360] Joshua Colp -- res_pjsip_endpoint_identifier_ip: Read
+ settings before resolving.
+ ASTERISK-26693: res_pjsip_endpoint_identifier_ip: Add support for SRV
+ Reported by: Joshua Colp
+ * [a2f0adccbd] Joshua Colp -- res_pjsip_endpoint_identifier_ip: Ensure
+ error defaults to 0.
+ * [37aaaa2da2] Joshua Colp -- res_pjsip_endpoint_identifier_ip: Add
+ support for SRV lookups.
+
+ Category: Resources/res_pjsip_registrar
+
+ ASTERISK-26644: PJSIPShowRegistrationsInbound just dumps all aors
+ Reported by: George Joseph
+ * [ebc67d3053] gtjoseph -- res_pjsip_registrar: AMI Add
+ RegistrationInboundContactStatuses command
+
+ Category: Resources/res_pjsip_session
+
+ ASTERISK-26670: [patch] Outgoing SIP-URI Dialing via PJSIP
+ Reported by: Alexander Traud
+ * [569dac8e50] Alexander Traud -- res_pjsip_session: Access SIPDOMAIN
+ via Dialplan.
+
+ Category: Resources/res_rtp_asterisk
+
+ ASTERISK-24858: [patch]Asterisk 13 PJSIP sends RTP packets in wrong byte
+ order on Intel platform when using slin codec
+ Reported by: Frankie Chin
+ * [339c30f2b6] Sean Bright -- res_rtp_asterisk: Swap byte-order when
+ sending signed linear
+ ASTERISK-26710: [patch] res_rtp_asterisk: CHANNEL arguments,
+ (rtcp,all_rtt),(rtcp,all_loss),(rtcp,all_jitter) always return 0
+ Reported by: Aaron An
+ * [0047b1bc49] Aaron An -- res_rtp_asterisk: Fix bug in function
+ CHANNEL(rtcp, all_rtt)
+ ASTERISK-26672: Crash when setting remote address on RTP instance
+ Reported by: Richard Mudgett
+ * [a9e459f8ac] Richard Mudgett -- res_rtp_asterisk.c: Fix uninitialized
+ memory crash.
+ * [bcdd282ada] Richard Mudgett -- res_rtp_asterisk.c: Initialize ourip
+ passed to ast_find_ourip().
+ * [ac31233dbe] Richard Mudgett -- acl.c: Improve ast_ouraddrfor()
+ diagnostic messages.
+ * [0aa5db4b38] Richard Mudgett -- chan_rtp.c: Fix uninitialized memory
+ crash.
+ ASTERISK-26617: res_rtp_asterisk: Can't bind on systems without IPv6
+ Reported by: Guido Falsi
+ * [2ceb609edb] Guido Falsi -- res_rtp: Fix regression when IPv6 is not
+ available.
+ ASTERISK-26566: res_rtp_asterisk: RTT miscalculation in RTCP
+ Reported by: Hector Royo Concepcion
+ * [8756ce64b7] gestoip2 -- res_rtp_asterisk: RTT miscalculation in RTCP
+
+ Category: Resources/res_sorcery_memory_cache
+
+ ASTERISK-26731: res_sorcery_memory_cache: memory leak on every sorcery
+ memory cache populate
+ Reported by: Ustinov Artem
+ * [75497c33ea] Mark Michelson -- Free endpoint ACLs when destroying
+ PJSIP endpoints.
+
+ Category: Tests/General
+
+ ASTERISK-26740: voicemail API test: uses varlibdir instead of datadir for
+ a sound file
+ Reported by: Tzafrir Cohen
+ * [cd2677f966] Tzafrir Cohen -- tests: use datadir for sound files
+ ASTERISK-26739: voicemail API test: confuses expected and actual values
+ Reported by: Tzafrir Cohen
+ * [b62f84bfb1] Tzafrir Cohen -- test_voicemail_api: order of params to
+ VERIFY macros
+
+ Category: Third-Party/pjproject
+
+ ASTERISK-26653: pjproject_bundled doesn't verify already downloaded
+ tarballs
+ Reported by: George Joseph
+ * [cd46e86491] gtjoseph -- pjproject_bundled: Retry download if
+ previously saved tarball is bad
+
+ Category: pjproject/pjsip
+
+ ASTERISK-26655: [patch]pjsip: Transfers Broken with Compact Headers
+ Enabled
+ Reported by: JoshE
+ * [0ab9d103f6] JoshE -- res_pjsip_refer: Handle compact Refer-To header.
+ ASTERISK-26490: res_pjsip: sends 481 Call/Transaction Does Not Exist when
+ transaction branch parameter contains "_"
+ Reported by: Juris Breicis
+ * [d506874477] Richard Mudgett -- Bundled pjproject: Fix finding SIP
+ transactions.
+
+ Improvement
+
+ Category: Applications/app_controlplayback
+
+ ASTERISK-26562: app_controlplayback: Transmit Silence on ControlPlayback
+ pause
+ Reported by: Mikheili Dautashvili
+ * [12c4e664bc] Mikheili Dautashvili -- main/app.c: Transmit Silence on
+ ControlPlayback pause
+
+ Category: Resources/res_calendar_caldav
+
+ ASTERISK-26624: res_calendar_caldav: Add support for gmail
+ Reported by: Eduardo Scudeller Libardi
+ * [53459cdaa9] Eduardo S. Libardi -- res_calendar_caldav: Add support
+ reading gmail calendar
+
+ Category: Resources/res_pjsip
+
+ ASTERISK-23828: pjsip - Need a command to list active SIP subscriptions
+ Reported by: Rusty Newton
+ * [e3dcb9ddd9] Richard Mudgett -- res_pjsip_pubsub.c: Implement "pjsip
+ show subscriptions" commands.
+
+ Category: Tests/testsuite
+
+ ASTERISK-26527: Testsuite: increase timeout to check "core fullybooted
+ wait" up to 30 sec
+ Reported by: Badalian Vyacheslav
+ * [61ba2a014a] Richard Mudgett -- res_pjsip_outbound_registration.c:
+ Filter redundant statsd reporting.
+
+ ----------------------------------------------------------------------
+
+ Open Issues
+
+ [Back to Top]
+
+ This is a list of all open issues from the issue tracker that were
+ referenced by changes that went into this release.
+
+ Bug
+
+ Category: Core/BuildSystem
+
+ ASTERISK-26109: Asterisk fails building with OpenSSL 1.1.0
+ Reported by: Tzafrir Cohen
+ * [b0c9f07f04] Tzafrir Cohen -- OpenSSL 1.1.0 support
+
+ Category: Core/Jitterbuffer
+
+ ASTERISK-25270: chan_sip: rtptimeout doesn't work at all when using
+ JitterBuffers of any kind
+ Reported by: Florian Loyau
+ * [a3614d75f6] Kevin Harwell -- Revert "chan_sip: Fix lastrtprx always
+ updated"
+
+ Category: Core/RTP
+
+ ASTERISK-25270: chan_sip: rtptimeout doesn't work at all when using
+ JitterBuffers of any kind
+ Reported by: Florian Loyau
+ * [a3614d75f6] Kevin Harwell -- Revert "chan_sip: Fix lastrtprx always
+ updated"
+
+ ----------------------------------------------------------------------
+
+ 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 |
+ |------------+-------------+---------------------------------------------|
+ | ec97c41ac8 | gtjoseph | Update for 13.14.0-rc2 |
+ |------------+-------------+---------------------------------------------|
+ | 3f3290ce4f | Mark | Revert "Update qualifies when AOR |
+ | | Michelson | configuration changes." |
+ |------------+-------------+---------------------------------------------|
+ | 7dbe77d639 | gtjoseph | Update for 13.14.0-rc1 |
+ |------------+-------------+---------------------------------------------|
+ | 6492e91392 | Mark | Update qualifies when AOR configuration |
+ | | Michelson | changes. |
+ |------------+-------------+---------------------------------------------|
+ | 7fd28cefdb | gtjoseph | debug_utilities: Install ast_logescalator |
+ | | | to /var/lib/asterisk/scripts |
+ |------------+-------------+---------------------------------------------|
+ | 456bc3c704 | gtjoseph | debug_utilities: Add ast_logescalator |
+ |------------+-------------+---------------------------------------------|
+ | 54b027916a | Torrey | libastssl/pj: libastssl/pj should have an |
+ | | Searle | so_version |
+ |------------+-------------+---------------------------------------------|
+ | 9e3150b98d | Mark | Add reload options to CLI/AMI stale object |
+ | | Michelson | commands. |
+ |------------+-------------+---------------------------------------------|
+ | c54f9d2bf0 | Richard | T.140: Fix format ref and memory leaks. |
+ | | Mudgett | |
+ |------------+-------------+---------------------------------------------|
+ | 607b3ac736 | Richard | astobj2.c: Add excessive ref count trap. |
+ | | Mudgett | |
+ |------------+-------------+---------------------------------------------|
+ | ab8cb5a7ce | Richard | main/app.c: Memory corruption from early |
+ | | Mudgett | format destruction. |
+ |------------+-------------+---------------------------------------------|
+ | dcd8e4b1a0 | Richard | frame.c: Fix off-nominal format ref leaks. |
+ | | Mudgett | |
+ |------------+-------------+---------------------------------------------|
+ | 00a227e93d | Richard | stasis_bridge.c: Fix off-nominal stasis |
+ | | Mudgett | control ref leak. |
+ |------------+-------------+---------------------------------------------|
+ | 38a2021c68 | Richard | res_musiconhold.c: Fix format ref leak when |
+ | | Mudgett | parsing MOH config class. |
+ |------------+-------------+---------------------------------------------|
+ | ab7a9fc5b2 | Richard | chan_oss.c: Fix format ref leak in |
+ | | Mudgett | oss_read(). |
+ |------------+-------------+---------------------------------------------|
+ | 1484a991e1 | Richard | Add notes about embedded ast_frame structs |
+ | | Mudgett | holding a format ref. |
+ |------------+-------------+---------------------------------------------|
+ | 17f4989d49 | gtjoseph | ari: Implement 'debug all' and |
+ | | | request/response logging |
+ |------------+-------------+---------------------------------------------|
+ | 177e81ee47 | gtjoseph | pjproject_bundled: Fix setting max log |
+ | | | level |
+ |------------+-------------+---------------------------------------------|
+ | a969bf3577 | Richard | LISTFILTER: Remove outdated ERROR message. |
+ | | Mudgett | |
+ |------------+-------------+---------------------------------------------|
+ | 3890337e7a | Richard | res_pjsip_pubsub.c: Fix AMI event list |
+ | | Mudgett | counts. |
+ |------------+-------------+---------------------------------------------|
+ | fe4801c4f9 | Richard | res_pjsip_pubsub.c: Fix incorrect message |
+ | | Mudgett | string wrapping. |
+ |------------+-------------+---------------------------------------------|
+ | 46484b8730 | Richard | res_pjsip_pubsub.c: Eliminate trivial |
+ | | Mudgett | SCOPED_LOCK usage. |
+ |------------+-------------+---------------------------------------------|
+ | 8160474d7d | Richard | res_pjsip: alloca can never fail. |
+ | | Mudgett | |
+ |------------+-------------+---------------------------------------------|
+ | c628a7acac | gtjoseph | debug_utilities: Create ast_loggrabber |
+ |------------+-------------+---------------------------------------------|
+ | e335b706ee | Richard | res_pjsip_outbound_authenticator_digest.c: |
+ | | Mudgett | Fix spacing in warning messages. |
+ |------------+-------------+---------------------------------------------|
+ | 883e7fde31 | Kevin | abstract/fixed/adpative jitter buffer: |
+ | | Harwell | disallow frame re-inserts |
+ |------------+-------------+---------------------------------------------|
+ | 473330983b | Richard | taskprocessor.c: Change when high water |
+ | | Mudgett | warning logged. |
+ |------------+-------------+---------------------------------------------|
+ | 47474cfd54 | gtjoseph | debug_utilities: Create the ast_coredumper |
+ | | | utility |
+ |------------+-------------+---------------------------------------------|
+ | f8cd73ec3c | gtjoseph | pjproject_bundled: Fix compilation with |
+ | | | MALLOC_DEBUG |
+ |------------+-------------+---------------------------------------------|
+ | d7e5a747c3 | gtjoseph | pjproject_bundled: Compile pjsua with max |
+ | | | log level = 2 |
+ |------------+-------------+---------------------------------------------|
+ | 21151408f7 | Richard | bridge_native_rtp.c: Minor code cleanups. |
+ | | Mudgett | |
+ |------------+-------------+---------------------------------------------|
+ | 9dcf9e9cea | Richard | bridge_native_rtp.c: Fix native rtp bridge |
+ | | Mudgett | data race. |
+ |------------+-------------+---------------------------------------------|
+ | e2fa3c7eda | Richard | res_rtp_asterisk.c: Fix off nominal memory |
+ | | Mudgett | leak. |
+ |------------+-------------+---------------------------------------------|
+ | 815f755155 | gtjoseph | pjproject_bundled: Make build single |
+ | | | threaded |
+ |------------+-------------+---------------------------------------------|
+ | ab447f8a6a | David M. | configure: fix with-pjproject-bundled |
+ | | Lee | |
+ |------------+-------------+---------------------------------------------|
+ | 35736d419a | Richard | autosupport: Add 'pjproject show buildopts' |
+ | | Mudgett | |
+ |------------+-------------+---------------------------------------------|
+ | 91485734a4 | gtjoseph | res_sorcery_memory_cache: Change an error |
+ | | | to a debug message |
+ |------------+-------------+---------------------------------------------|
+ | 22820e10fe | Badalyan | chan_sip: Delete unneeded check |
+ | | Vyacheslav | |
+ |------------+-------------+---------------------------------------------|
+ | 6aa2c5e5f9 | Badalyan | Small code cleanup in chan_sip |
+ | | Vyacheslav | |
+ |------------+-------------+---------------------------------------------|
+ | b596fac838 | Badalyan | Fix typo in chan_sip |
+ | | Vyacheslav | |
+ |------------+-------------+---------------------------------------------|
+ | 483ed9f1aa | Badalyan | res_pjsip: Fix 'A = B != C' kind. |
+ | | Vyacheslav | |
+ |------------+-------------+---------------------------------------------|
+ | 4b233675d8 | gtjoseph | pjproject_bundled: Fix missing inclusion of |
+ | | | symbols |
+ |------------+-------------+---------------------------------------------|
+ | 580f83dac7 | Richard | Remove files that got merged in error |
+ | | Mudgett | somehow to the 13 branch. |
+ |------------+-------------+---------------------------------------------|
+ | 17b0b91afa | Mark | Frame deferral: Re-queue deferred frames |
+ | | Michelson | one-at-a-time. |
+ |------------+-------------+---------------------------------------------|
+ | a33ed3327a | Matt Jordan | res/res_pjsip: Fix documentation whitespace |
+ | | | issues |
+ |------------+-------------+---------------------------------------------|
+ | 29e887e9e1 | gtjoseph | build_tools: Fix download_externals to |
+ | | | handle certified branches |
+ |------------+-------------+---------------------------------------------|
+ | a1fa909033 | Timo | codec_dahdi: Fix poll.h include. |
+ | | TerACURs | |
+ |------------+-------------+---------------------------------------------|
+ | 86d824b7ff | Timo | addons/chan_mobile: do not use strerror_r |
+ | | TerACURs | |
+ |------------+-------------+---------------------------------------------|
+ | 425da14927 | gtjoseph | build: Backport addition of librt check to |
+ | | | configure.ac |
+ |------------+-------------+---------------------------------------------|
+ | 2a40c3a867 | gtjoseph | pjproject_bundled: Improve reliability of |
+ | | | pjproject download |
+ |------------+-------------+---------------------------------------------|
+ | ee73af1d88 | gtjoseph | Update for 13.12.2 |
+ |------------+-------------+---------------------------------------------|
+ | 7d7b52c434 | Mark | Update for 13.12.1 |
+ | | Michelson | |
+ |------------+-------------+---------------------------------------------|
+ | 226a7e36c5 | Mark | Update for 13.12.0 |
+ | | Michelson | |
+ |------------+-------------+---------------------------------------------|
+ | df75b647da | Mark | Update for 13.12.0-rc1 |
+ | | Michelson | |
+ +------------------------------------------------------------------------+
+
+ ----------------------------------------------------------------------
+
+ 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.
+
+ asterisk-13.13.0-summary.html | 304 -
+ asterisk-13.13.0-summary.txt | 767 ----
+ b/.version | 2
+ b/CHANGES | 50
+ b/ChangeLog | 1614 +++++++++-
+ b/addons/chan_mobile.c | 13
+ b/apps/app_queue.c | 40
+ b/apps/app_voicemail.c | 6
+ b/asterisk-13.14.0-rc2-summary.html | 20
+ b/asterisk-13.14.0-rc2-summary.txt | 104
+ b/bootstrap.sh | 2
+ b/bridges/bridge_native_rtp.c | 81
+ b/build_tools/download_externals | 4
+ b/build_tools/make_build_h | 10
+ b/channels/chan_dahdi.c | 4
+ b/channels/chan_oss.c | 2
+ b/channels/chan_pjsip.c | 9
+ b/channels/chan_rtp.c | 7
+ b/channels/chan_sip.c | 111
+ b/channels/pjsip/dialplan_functions.c | 62
+ b/codecs/codec_dahdi.c | 2
+ b/configs/samples/ast_debug_tools.conf.sample | 57
+ b/configs/samples/pjproject.conf.sample | 25
+ b/configs/samples/res_odbc.conf.sample | 6
+ b/configure | 12
+ b/configure.ac | 10
+ b/contrib/Makefile | 14
+ b/contrib/ast-db-manage/config/versions/28ab27a7826d_add_srv_lookups_to_identify.py | 31
+ b/contrib/realtime/mssql/mssql_config.sql | 14
+ b/contrib/realtime/mysql/mysql_config.sql | 6
+ b/contrib/realtime/oracle/oracle_config.sql | 14
+ b/contrib/realtime/postgresql/postgresql_config.sql | 6
+ b/contrib/scripts/ast_coredumper | 533 +++
+ b/contrib/scripts/ast_logescalator | 399 ++
+ b/contrib/scripts/ast_loggrabber | 255 +
+ b/contrib/scripts/autosupport | 4
+ b/funcs/func_strings.c | 1
+ b/include/asterisk/abstract_jb.h | 3
+ b/include/asterisk/ari.h | 24
+ b/include/asterisk/channel.h | 72
+ b/include/asterisk/frame.h | 2
+ b/include/asterisk/mod_format.h | 6
+ b/include/asterisk/options.h | 41
+ b/include/asterisk/res_pjsip.h | 10
+ b/include/asterisk/rtp_engine.h | 4
+ b/include/asterisk/stasis_app.h | 49
+ b/include/asterisk/tcptls.h | 4
+ b/include/asterisk/translate.h | 2
+ b/include/asterisk/utils.h | 9
+ b/include/jitterbuf.h | 3
+ b/main/Makefile | 12
+ b/main/abstract_jb.c | 31
+ b/main/acl.c | 36
+ b/main/app.c | 36
+ b/main/asterisk.c | 35
+ b/main/astobj2.c | 13
+ b/main/audiohook.c | 40
+ b/main/autoservice.c | 66
+ b/main/channel.c | 217 -
+ b/main/channel_internal_api.c | 68
+ b/main/fixedjitterbuf.c | 6
+ b/main/fixedjitterbuf.h | 3
+ b/main/format_compatibility.c | 4
+ b/main/frame.c | 69
+ b/main/jitterbuf.c | 5
+ b/main/libasteriskpj.c | 2
+ b/main/libasteriskssl.c | 4
+ b/main/manager.c | 6
+ b/main/message.c | 9
+ b/main/rtp_engine.c | 2
+ b/main/srv.c | 3
+ b/main/strings.c | 21
+ b/main/taskprocessor.c | 8
+ b/main/tcptls.c | 94
+ b/main/utils.c | 24
+ b/makeopts.in | 2
+ b/res/ari/ari_websockets.c | 14
+ b/res/ari/cli.c | 175 +
+ b/res/ari/resource_events.c | 9
+ b/res/res_agi.c | 10
+ b/res/res_ari.c | 77
+ b/res/res_ari_applications.c | 42
+ b/res/res_ari_asterisk.c | 120
+ b/res/res_ari_bridges.c | 162 -
+ b/res/res_ari_channels.c | 318 -
+ b/res/res_ari_device_states.c | 27
+ b/res/res_ari_endpoints.c | 45
+ b/res/res_ari_events.c | 18
+ b/res/res_ari_mailboxes.c | 27
+ b/res/res_ari_playbacks.c | 24
+ b/res/res_ari_recordings.c | 48
+ b/res/res_ari_sounds.c | 21
+ b/res/res_calendar_caldav.c | 4
+ b/res/res_format_attr_opus.c | 38
+ b/res/res_musiconhold.c | 2
+ b/res/res_pjproject.c | 156
+ b/res/res_pjsip.c | 72
+ b/res/res_pjsip/pjsip_configuration.c | 6
+ b/res/res_pjsip/pjsip_options.c | 17
+ b/res/res_pjsip_diversion.c | 3
+ b/res/res_pjsip_endpoint_identifier_ip.c | 160
+ b/res/res_pjsip_history.c | 91
+ b/res/res_pjsip_outbound_authenticator_digest.c | 12
+ b/res/res_pjsip_outbound_registration.c | 21
+ b/res/res_pjsip_pubsub.c | 635 +++
+ b/res/res_pjsip_refer.c | 8
+ b/res/res_pjsip_registrar.c | 70
+ b/res/res_pjsip_sdp_rtp.c | 7
+ b/res/res_pjsip_session.c | 8
+ b/res/res_pjsip_t38.c | 7
+ b/res/res_pjsip_transport_websocket.c | 5
+ b/res/res_rtp_asterisk.c | 117
+ b/res/res_sorcery_memory_cache.c | 41
+ b/res/res_stasis.c | 23
+ b/res/stasis/app.c | 73
+ b/res/stasis/app.h | 27
+ b/res/stasis/stasis_bridge.c | 6
+ b/rest-api-templates/param_parsing.mustache | 15
+ b/rest-api-templates/res_ari_resource.c.mustache | 3
+ b/tests/test_ari.c | 22
+ b/tests/test_substitution.c | 9
+ b/tests/test_voicemail_api.c | 52
+ b/third-party/Makefile | 2
+ b/third-party/Makefile.rules | 4
+ b/third-party/pjproject/Makefile | 61
+ b/third-party/pjproject/configure.m4 | 8
+ b/third-party/pjproject/patches/0000-set_apps_initial_log_level.patch | 13
+ res/stasis/cli.c | 216 -
+ res/stasis/cli.h | 43
+ 129 files changed, 5945 insertions(+), 2895 deletions(-)
diff --git a/bootstrap.sh b/bootstrap.sh
index 051ee3e..272c57b 100755
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -46,7 +46,7 @@ check_for_app aclocal${MY_AM_VER}
echo "Generating the configure script ..."
-aclocal${MY_AM_VER} -I autoconf `find third-party/ -maxdepth 1 -type d -printf "-I %p "`
+aclocal${MY_AM_VER} -I autoconf `find third-party -maxdepth 1 -type d | xargs -I {} echo -I {}`
autoconf${MY_AC_VER}
autoheader${MY_AC_VER}
automake${MY_AM_VER} --add-missing --copy 2>/dev/null
diff --git a/bridges/bridge_native_rtp.c b/bridges/bridge_native_rtp.c
index 7eacc9d..a106d2d 100644
--- a/bridges/bridge_native_rtp.c
+++ b/bridges/bridge_native_rtp.c
@@ -270,7 +270,6 @@ static struct ast_frame *native_rtp_framehook(struct ast_channel *chan, struct a
}
bridge = ast_channel_get_bridge(chan);
-
if (bridge) {
/* native_rtp_bridge_start/stop are not being called from bridging
core so we need to lock the bridge prior to calling these functions
@@ -312,26 +311,21 @@ static int native_rtp_bridge_capable(struct ast_channel *chan)
return !ast_channel_has_hook_requiring_audio(chan);
}
-static int native_rtp_bridge_compatible(struct ast_bridge *bridge)
+static int native_rtp_bridge_compatible_check(struct ast_bridge *bridge, struct ast_bridge_channel *bc0, struct ast_bridge_channel *bc1)
{
- struct ast_bridge_channel *bc0 = AST_LIST_FIRST(&bridge->channels);
- struct ast_bridge_channel *bc1 = AST_LIST_LAST(&bridge->channels);
enum ast_rtp_glue_result native_type;
- struct ast_rtp_glue *glue0, *glue1;
+ struct ast_rtp_glue *glue0;
+ struct ast_rtp_glue *glue1;
RAII_VAR(struct ast_rtp_instance *, instance0, NULL, ao2_cleanup);
RAII_VAR(struct ast_rtp_instance *, instance1, NULL, ao2_cleanup);
RAII_VAR(struct ast_rtp_instance *, vinstance0, NULL, ao2_cleanup);
RAII_VAR(struct ast_rtp_instance *, vinstance1, NULL, ao2_cleanup);
RAII_VAR(struct ast_format_cap *, cap0, NULL, ao2_cleanup);
RAII_VAR(struct ast_format_cap *, cap1, NULL, ao2_cleanup);
- int read_ptime0, read_ptime1, write_ptime0, write_ptime1;
-
- /* We require two channels before even considering native bridging */
- if (bridge->num_channels != 2) {
- ast_debug(1, "Bridge '%s' can not use native RTP bridge as two channels are required\n",
- bridge->uniqueid);
- return 0;
- }
+ int read_ptime0;
+ int read_ptime1;
+ int write_ptime0;
+ int write_ptime1;
if (!native_rtp_bridge_capable(bc0->chan)) {
ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has features which prevent it\n",
@@ -345,29 +339,34 @@ static int native_rtp_bridge_compatible(struct ast_bridge *bridge)
return 0;
}
- if ((native_type = native_rtp_bridge_get(bc0->chan, bc1->chan, &glue0, &glue1, &instance0, &instance1, &vinstance0, &vinstance1))
- == AST_RTP_GLUE_RESULT_FORBID) {
+ native_type = native_rtp_bridge_get(bc0->chan, bc1->chan, &glue0, &glue1,
+ &instance0, &instance1, &vinstance0, &vinstance1);
+ if (native_type == AST_RTP_GLUE_RESULT_FORBID) {
ast_debug(1, "Bridge '%s' can not use native RTP bridge as it was forbidden while getting details\n",
bridge->uniqueid);
return 0;
}
- if (ao2_container_count(bc0->features->dtmf_hooks) && ast_rtp_instance_dtmf_mode_get(instance0)) {
+ if (ao2_container_count(bc0->features->dtmf_hooks)
+ && ast_rtp_instance_dtmf_mode_get(instance0)) {
ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has DTMF hooks\n",
bridge->uniqueid, ast_channel_name(bc0->chan));
return 0;
}
- if (ao2_container_count(bc1->features->dtmf_hooks) && ast_rtp_instance_dtmf_mode_get(instance1)) {
+ if (ao2_container_count(bc1->features->dtmf_hooks)
+ && ast_rtp_instance_dtmf_mode_get(instance1)) {
ast_debug(1, "Bridge '%s' can not use native RTP bridge as channel '%s' has DTMF hooks\n",
bridge->uniqueid, ast_channel_name(bc1->chan));
return 0;
}
- if ((native_type == AST_RTP_GLUE_RESULT_LOCAL) && ((ast_rtp_instance_get_engine(instance0)->local_bridge !=
- ast_rtp_instance_get_engine(instance1)->local_bridge) ||
- (ast_rtp_instance_get_engine(instance0)->dtmf_compatible &&
- !ast_rtp_instance_get_engine(instance0)->dtmf_compatible(bc0->chan, instance0, bc1->chan, instance1)))) {
+ if (native_type == AST_RTP_GLUE_RESULT_LOCAL
+ && (ast_rtp_instance_get_engine(instance0)->local_bridge
+ != ast_rtp_instance_get_engine(instance1)->local_bridge
+ || (ast_rtp_instance_get_engine(instance0)->dtmf_compatible
+ && !ast_rtp_instance_get_engine(instance0)->dtmf_compatible(bc0->chan,
+ instance0, bc1->chan, instance1)))) {
ast_debug(1, "Bridge '%s' can not use local native RTP bridge as local bridge or DTMF is not compatible\n",
bridge->uniqueid);
return 0;
@@ -386,11 +385,16 @@ static int native_rtp_bridge_compatible(struct ast_bridge *bridge)
if (glue1->get_codec) {
glue1->get_codec(bc1->chan, cap1);
}
- if (ast_format_cap_count(cap0) != 0 && ast_format_cap_count(cap1) != 0 && !ast_format_cap_iscompatible(cap0, cap1)) {
+ if (ast_format_cap_count(cap0) != 0
+ && ast_format_cap_count(cap1) != 0
+ && !ast_format_cap_iscompatible(cap0, cap1)) {
struct ast_str *codec_buf0 = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
struct ast_str *codec_buf1 = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
- ast_debug(1, "Channel codec0 = %s is not codec1 = %s, cannot native bridge in RTP.\n",
- ast_format_cap_get_names(cap0, &codec_buf0), ast_format_cap_get_names(cap1, &codec_buf1));
+
+ ast_debug(1, "Bridge '%s': Channel codec0 = %s is not codec1 = %s, cannot native bridge in RTP.\n",
+ bridge->uniqueid,
+ ast_format_cap_get_names(cap0, &codec_buf0),
+ ast_format_cap_get_names(cap1, &codec_buf1));
return 0;
}
@@ -400,14 +404,39 @@ static int native_rtp_bridge_compatible(struct ast_bridge *bridge)
write_ptime1 = ast_format_cap_get_format_framing(cap1, ast_channel_rawwriteformat(bc1->chan));
if (read_ptime0 != write_ptime1 || read_ptime1 != write_ptime0) {
- ast_debug(1, "Packetization differs between RTP streams (%d != %d or %d != %d). Cannot native bridge in RTP\n",
- read_ptime0, write_ptime1, read_ptime1, write_ptime0);
+ ast_debug(1, "Bridge '%s': Packetization differs between RTP streams (%d != %d or %d != %d). Cannot native bridge in RTP\n",
+ bridge->uniqueid,
+ read_ptime0, write_ptime1, read_ptime1, write_ptime0);
return 0;
}
return 1;
}
+static int native_rtp_bridge_compatible(struct ast_bridge *bridge)
+{
+ struct ast_bridge_channel *bc0;
+ struct ast_bridge_channel *bc1;
+ int is_compatible;
+
+ /* We require two channels before even considering native bridging */
+ if (bridge->num_channels != 2) {
+ ast_debug(1, "Bridge '%s' can not use native RTP bridge as two channels are required\n",
+ bridge->uniqueid);
+ return 0;
+ }
+
+ bc0 = AST_LIST_FIRST(&bridge->channels);
+ bc1 = AST_LIST_LAST(&bridge->channels);
+
+ ast_channel_lock_both(bc0->chan, bc1->chan);
+ is_compatible = native_rtp_bridge_compatible_check(bridge, bc0, bc1);
+ ast_channel_unlock(bc0->chan);
+ ast_channel_unlock(bc1->chan);
+
+ return is_compatible;
+}
+
/*! \brief Helper function which adds frame hook to bridge channel */
static int native_rtp_bridge_framehook_attach(struct ast_bridge_channel *bridge_channel)
{
diff --git a/build_tools/download_externals b/build_tools/download_externals
index 2bc357c..d2e2e4f 100755
--- a/build_tools/download_externals
+++ b/build_tools/download_externals
@@ -45,11 +45,11 @@ if [[ -z ${cache_dir} ]] ; then
fi
version=$(${ASTTOPDIR}/build_tools/make_version ${ASTTOPDIR})
-if [[ ! ${version} =~ ^(GIT-)?([^.-]+)[.-].* ]] ; then
+if [[ ! ${version} =~ ^(GIT-)?(certified/)?([^.-]+)[.-].* ]] ; then
echo "${module_name}: Couldn't parse version ${version}"
exit 1
fi
-major_version=${BASH_REMATCH[2]}
+major_version=${BASH_REMATCH[3]}
if [[ "${major_version}" == "master" ]] ; then
echo "${module_name}: External module downloading is not available in the 'master' git branch. Please disable in menuselect and download manually."
diff --git a/build_tools/make_build_h b/build_tools/make_build_h
index a7cb6fe..2c8895e 100755
--- a/build_tools/make_build_h
+++ b/build_tools/make_build_h
@@ -1,13 +1,13 @@
#!/bin/sh
-HOSTNAME=`uname -n`
-KERNEL=`uname -r`
-MACHINE=`uname -m`
+HOSTNAME=`uname -n | sed 's/\\\\/\\\\\\\\/g'`
+KERNEL=`uname -r | sed 's/\\\\/\\\\\\\\/g'`
+MACHINE=`uname -m | sed 's/\\\\/\\\\\\\\/g'`
OS=`uname -s`
-USER=`id | awk -F")" '{print $1}'| awk -F"(" '{print $2}'`
+USER=`id | awk -F")" '{print $1}'| awk -F"(" '{print $2}' | sed 's/\\\\/\\\\\\\\/g'`
DATE=`date -u "+%Y-%m-%d %H:%M:%S"`
cat << END
/*
- * build.h
+ * build.h
* Automatically generated
*/
#define BUILD_HOSTNAME "${HOSTNAME}"
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index 2e139a2..6d740d0 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -18905,8 +18905,8 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
}
/* This check is only needed to satisfy the compiler that element_count can't cause an out of bounds */
- if (element_count >= ARRAY_LEN(c)) {
- element_count = ARRAY_LEN(c) - 1;
+ if (element_count > ARRAY_LEN(c)) {
+ element_count = ARRAY_LEN(c);
}
/* Ring cadences cannot be negative */
diff --git a/channels/chan_oss.c b/channels/chan_oss.c
index 912a5eb..aa870df 100644
--- a/channels/chan_oss.c
+++ b/channels/chan_oss.c
@@ -727,7 +727,7 @@ static struct ast_frame *oss_read(struct ast_channel *c)
return f;
/* ok we can build and deliver the frame to the caller */
f->frametype = AST_FRAME_VOICE;
- f->subclass.format = ao2_bump(ast_format_slin);
+ f->subclass.format = ast_format_slin;
f->samples = FRAME_SIZE;
f->datalen = FRAME_SIZE * 2;
f->data.ptr = o->oss_read_buf + AST_FRIENDLY_OFFSET;
diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c
index cc4b2ef..6e3d087 100644
--- a/channels/chan_pjsip.c
+++ b/channels/chan_pjsip.c
@@ -679,7 +679,11 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se
return f;
}
-/*! \brief Function called by core to read any waiting frames */
+/*!
+ * \brief Function called by core to read any waiting frames
+ *
+ * \note The channel is already locked.
+ */
static struct ast_frame *chan_pjsip_read(struct ast_channel *ast)
{
struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast);
@@ -737,8 +741,7 @@ static struct ast_frame *chan_pjsip_read(struct ast_channel *ast)
ast_debug(1, "Oooh, got a frame with format of %s on channel '%s' when we're sending '%s', switching to match\n",
ast_format_get_name(f->subclass.format), ast_channel_name(ast),
ast_format_get_name(ast_channel_rawwriteformat(ast)));
- ast_channel_set_rawwriteformat(ast, f->subclass.format);
- ast_set_write_format(ast, ast_channel_writeformat(ast));
+ ast_set_write_format_path(ast, ast_channel_writeformat(ast), f->subclass.format);
if (ast_channel_is_bridged(ast)) {
ast_channel_set_unbridged_nolock(ast, 1);
diff --git a/channels/chan_rtp.c b/channels/chan_rtp.c
index f1f4f05..d671706 100644
--- a/channels/chan_rtp.c
+++ b/channels/chan_rtp.c
@@ -316,7 +316,12 @@ static struct ast_channel *unicast_rtp_request(const char *type, struct ast_form
engine_name = S_COR(ast_test_flag(&opts, OPT_RTP_ENGINE),
opt_args[OPT_ARG_RTP_ENGINE], "asterisk");
- ast_ouraddrfor(&address, &local_address);
+ ast_sockaddr_copy(&local_address, &address);
+ if (ast_ouraddrfor(&address, &local_address)) {
+ ast_log(LOG_ERROR, "Could not get our address for sending media to '%s'\n",
+ args.destination);
+ goto failure;
+ }
instance = ast_rtp_instance_new(engine_name, NULL, &local_address, NULL);
if (!instance) {
ast_log(LOG_ERROR,
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 38492b9..83f72b9 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -609,6 +609,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
</managerEvent>
***/
+static int log_level = -1;
+
static int min_expiry = DEFAULT_MIN_EXPIRY; /*!< Minimum accepted registration time */
static int max_expiry = DEFAULT_MAX_EXPIRY; /*!< Maximum accepted registration time */
static int default_expiry = DEFAULT_DEFAULT_EXPIRY;
@@ -1774,7 +1776,7 @@ static void destroy_escs(void)
{
int i;
for (i = 0; i < ARRAY_LEN(event_state_compositors); i++) {
- ao2_cleanup(event_state_compositors[i].compositor);
+ ao2_replace(event_state_compositors[i].compositor, NULL);
}
}
@@ -2503,7 +2505,7 @@ static void sip_threadinfo_destructor(void *obj)
struct sip_threadinfo *th = obj;
struct tcptls_packet *packet;
- if (th->alert_pipe[1] > -1) {
+ if (th->alert_pipe[0] > -1) {
close(th->alert_pipe[0]);
}
if (th->alert_pipe[1] > -1) {
@@ -2959,6 +2961,7 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s
if (!(me = sip_threadinfo_create(tcptls_session, tcptls_session->ssl ? AST_TRANSPORT_TLS : AST_TRANSPORT_TCP))) {
goto cleanup;
}
+ me->threadid = pthread_self();
ao2_t_ref(me, +1, "Adding threadinfo ref for tcp_helper_thread");
} else {
struct sip_threadinfo tmp = {
@@ -2966,8 +2969,13 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s
};
if ((!(ca = tcptls_session->parent)) ||
- (!(me = ao2_t_find(threadt, &tmp, OBJ_POINTER, "ao2_find, getting sip_threadinfo in tcp helper thread"))) ||
- (!(tcptls_session = ast_tcptls_client_start(tcptls_session)))) {
+ (!(me = ao2_t_find(threadt, &tmp, OBJ_POINTER, "ao2_find, getting sip_threadinfo in tcp helper thread")))) {
+ goto cleanup;
+ }
+
+ me->threadid = pthread_self();
+
+ if (!(tcptls_session = ast_tcptls_client_start(tcptls_session))) {
goto cleanup;
}
}
@@ -2978,7 +2986,6 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s
goto cleanup;
}
- me->threadid = pthread_self();
ast_debug(2, "Starting thread for %s server\n", tcptls_session->ssl ? "TLS" : "TCP");
/* set up pollfd to watch for reads on both the socket and the alert_pipe */
@@ -3929,6 +3936,9 @@ static __attribute__((format(printf, 2, 0))) void append_history_va(struct sip_p
}
AST_LIST_INSERT_TAIL(p->history, hist, list);
p->history_entries++;
+ if (log_level != -1) {
+ ast_log_dynamic_level(log_level, "%s\n", buf);
+ }
}
/*! \brief Append to SIP dialog history with arg list */
@@ -6882,10 +6892,9 @@ static int update_call_counter(struct sip_pvt *fup, int event)
ast_log(LOG_ERROR, "update_call_counter(%s, %d) called with no event!\n", name, event);
}
- if (p) {
- ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", p->name);
- sip_unref_peer(p, "update_call_counter: sip_unref_peer from call counter");
- }
+ ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", p->name);
+ sip_unref_peer(p, "update_call_counter: sip_unref_peer from call counter");
+
return 0;
}
@@ -7367,6 +7376,12 @@ static void try_suggested_sip_codec(struct sip_pvt *p)
ao2_ref(fmt, -1);
}
+
+ /* The original joint formats may have contained negotiated parameters (fmtp)
+ * like the Opus Codec or iLBC 20. The cached formats contain the default
+ * parameters, which could be different than the negotiated (joint) result. */
+ ast_format_cap_replace_from_cap(p->jointcaps, original_jointcaps, AST_MEDIA_TYPE_UNKNOWN);
+
ao2_ref(original_jointcaps, -1);
return;
}
@@ -10795,6 +10810,9 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
struct ast_str *vpeer_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
struct ast_str *tpeer_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
struct ast_str *joint_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
+ struct ast_str *s1 = ast_str_alloca(SIPBUFSIZE);
+ struct ast_str *s2 = ast_str_alloca(SIPBUFSIZE);
+ struct ast_str *s3 = ast_str_alloca(SIPBUFSIZE);
ast_verbose("Capabilities: us - %s, peer - audio=%s/video=%s/text=%s, combined - %s\n",
ast_format_cap_get_names(p->caps, &cap_buf),
@@ -10802,11 +10820,6 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
ast_format_cap_get_names(vpeercapability, &vpeer_buf),
ast_format_cap_get_names(tpeercapability, &tpeer_buf),
ast_format_cap_get_names(newjointcapability, &joint_buf));
- }
- if (debug) {
- struct ast_str *s1 = ast_str_alloca(SIPBUFSIZE);
- struct ast_str *s2 = ast_str_alloca(SIPBUFSIZE);
- struct ast_str *s3 = ast_str_alloca(SIPBUFSIZE);
ast_verbose("Non-codec capabilities (dtmf): us - %s, peer - %s, combined - %s\n",
ast_rtp_lookup_mime_multiple2(s1, NULL, p->noncodeccapability, 0, 0),
@@ -14136,6 +14149,7 @@ static void build_contact(struct sip_pvt *p, struct sip_request *req, int incomi
char tmp[SIPBUFSIZE];
char *user = ast_uri_encode(p->exten, tmp, sizeof(tmp), ast_uri_sip_user);
int use_sips;
+ char *transport = ast_strdupa(sip_get_transport(p->socket.type));
if (incoming) {
use_sips = uas_sips_contact(req);
@@ -14150,7 +14164,7 @@ static void build_contact(struct sip_pvt *p, struct sip_request *req, int incomi
} else {
ast_string_field_build(p, our_contact, "<%s:%s%s%s;transport=%s>",
use_sips ? "sips" : "sip", user, ast_strlen_zero(user) ? "" : "@",
- ast_sockaddr_stringify_remote(&p->ourip), sip_get_transport(p->socket.type));
+ ast_sockaddr_stringify_remote(&p->ourip), ast_str_to_lower(transport));
}
}
@@ -35071,6 +35085,10 @@ static int load_module(void)
struct sip_peer *bogus_peer;
ast_verbose("SIP channel loading...\n");
+ log_level = ast_logger_register_level("SIP_HISTORY");
+ if (log_level < 0) {
+ ast_log(LOG_WARNING, "Unable to register history log level\n");
+ }
if (STASIS_MESSAGE_TYPE_INIT(session_timeout_type)) {
unload_module();
@@ -35270,6 +35288,8 @@ static int unload_module(void)
struct ao2_iterator i;
struct timeval start;
+ ast_sched_dump(sched);
+
ast_sip_api_provider_unregister();
if (sip_cfg.websocket_enabled) {
@@ -35279,12 +35299,11 @@ static int unload_module(void)
network_change_stasis_unsubscribe();
acl_change_event_stasis_unsubscribe();
- ast_sched_dump(sched);
-
/* First, take us out of the channel type list */
ast_channel_unregister(&sip_tech);
-
ast_msg_tech_unregister(&sip_msg_tech);
+ ast_cc_monitor_unregister(&sip_cc_monitor_callbacks);
+ ast_cc_agent_unregister(&sip_cc_agent_callbacks);
/* Unregister dial plan functions */
ast_custom_function_unregister(&sippeer_function);
@@ -35348,8 +35367,6 @@ static int unload_module(void)
}
ao2_iterator_destroy(&i);
- unlink_all_peers_from_tables();
-
ast_mutex_lock(&monlock);
if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
pthread_t th = monitor_thread;
@@ -35363,7 +35380,12 @@ static int unload_module(void)
ast_mutex_unlock(&monlock);
}
+ /* Clear containers */
+ unlink_all_peers_from_tables();
cleanup_all_regs();
+ sip_epa_unregister_all();
+ destroy_escs();
+ clear_sip_domains();
{
struct ao2_iterator iter;
@@ -35392,6 +35414,23 @@ static int unload_module(void)
*/
ast_sched_runq(sched);
+ /*
+ * Wait awhile for the TCP/TLS thread container to become empty.
+ *
+ * XXX This is a hack, but the worker threads cannot be created
+ * joinable. They can die on their own and remove themselves
+ * from the container thus resulting in a huge memory leak.
+ */
+ start = ast_tvnow();
+ while (ao2_container_count(threadt) && (ast_tvdiff_sec(ast_tvnow(), start) < 5)) {
+ sched_yield();
+ }
+ if (ao2_container_count(threadt)) {
+ ast_debug(2, "TCP/TLS thread container did not become empty :(\n");
+
+ return -1;
+ }
+
/* Free memory for local network address mask */
ast_free_ha(localaddr);
@@ -35402,30 +35441,12 @@ static int unload_module(void)
}
ast_mutex_unlock(&authl_lock);
- sip_epa_unregister_all();
- destroy_escs();
-
ast_free(default_tls_cfg.certfile);
ast_free(default_tls_cfg.pvtfile);
ast_free(default_tls_cfg.cipher);
ast_free(default_tls_cfg.cafile);
ast_free(default_tls_cfg.capath);
- /*
- * Wait awhile for the TCP/TLS thread container to become empty.
- *
- * XXX This is a hack, but the worker threads cannot be created
- * joinable. They can die on their own and remove themselves
- * from the container thus resulting in a huge memory leak.
- */
- start = ast_tvnow();
- while (ao2_container_count(threadt) && (ast_tvdiff_sec(ast_tvnow(), start) < 5)) {
- sched_yield();
- }
- if (ao2_container_count(threadt)) {
- ast_debug(2, "TCP/TLS thread container did not become empty :(\n");
- }
-
ao2_cleanup(registry_list);
ao2_cleanup(subscription_mwi_list);
@@ -35439,7 +35460,6 @@ static int unload_module(void)
ao2_t_cleanup(threadt, "unref the thread table");
ao2_t_cleanup(sip_monitor_instances, "unref the sip_monitor_instances table");
- clear_sip_domains();
sip_cfg.contact_acl = ast_free_acl_list(sip_cfg.contact_acl);
if (sipsock_read_id) {
ast_io_remove(io, sipsock_read_id);
@@ -35452,8 +35472,6 @@ static int unload_module(void)
ast_context_destroy_by_name(used_context, "SIP");
ast_unload_realtime("sipregs");
ast_unload_realtime("sippeers");
- ast_cc_monitor_unregister(&sip_cc_monitor_callbacks);
- ast_cc_agent_unregister(&sip_cc_agent_callbacks);
sip_reqresp_parser_exit();
sip_unregister_tests();
@@ -35469,6 +35487,9 @@ static int unload_module(void)
sip_cfg.caps = NULL;
STASIS_MESSAGE_TYPE_CLEANUP(session_timeout_type);
+ if (log_level != -1) {
+ ast_logger_unregister_level("SIP_HISTORY");
+ }
return 0;
}
diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c
index ecf5105..719a074 100644
--- a/channels/pjsip/dialplan_functions.c
+++ b/channels/pjsip/dialplan_functions.c
@@ -722,7 +722,7 @@ static int channel_read_pjsip(struct ast_channel *chan, const char *type, const
/*! \brief Struct used to push function arguments to task processor */
struct pjsip_func_args {
- struct ast_channel *chan;
+ struct ast_sip_session *session;
const char *param;
const char *type;
const char *field;
@@ -737,49 +737,31 @@ static int read_pjsip(void *data)
struct pjsip_func_args *func_args = data;
if (!strcmp(func_args->param, "rtp")) {
- func_args->ret = channel_read_rtp(func_args->chan, func_args->type,
+ func_args->ret = channel_read_rtp(func_args->session->channel, func_args->type,
func_args->field, func_args->buf,
func_args->len);
} else if (!strcmp(func_args->param, "rtcp")) {
- func_args->ret = channel_read_rtcp(func_args->chan, func_args->type,
+ func_args->ret = channel_read_rtcp(func_args->session->channel, func_args->type,
func_args->field, func_args->buf,
func_args->len);
} else if (!strcmp(func_args->param, "endpoint")) {
- struct ast_sip_channel_pvt *pvt = ast_channel_tech_pvt(func_args->chan);
-
- if (!pvt) {
- ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(func_args->chan));
+ if (!func_args->session->endpoint) {
+ ast_log(AST_LOG_WARNING, "Channel %s has no endpoint!\n", ast_channel_name(func_args->session->channel));
return -1;
}
- if (!pvt->session || !pvt->session->endpoint) {
- ast_log(AST_LOG_WARNING, "Channel %s has no endpoint!\n", ast_channel_name(func_args->chan));
- return -1;
- }
- snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(pvt->session->endpoint));
+ snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(func_args->session->endpoint));
} else if (!strcmp(func_args->param, "contact")) {
- struct ast_sip_channel_pvt *pvt = ast_channel_tech_pvt(func_args->chan);
-
- if (!pvt) {
- ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(func_args->chan));
- return -1;
- }
- if (!pvt->session || !pvt->session->contact) {
+ if (!func_args->session->contact) {
return 0;
}
- snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(pvt->session->contact));
+ snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(func_args->session->contact));
} else if (!strcmp(func_args->param, "aor")) {
- struct ast_sip_channel_pvt *pvt = ast_channel_tech_pvt(func_args->chan);
-
- if (!pvt) {
- ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(func_args->chan));
- return -1;
- }
- if (!pvt->session || !pvt->session->aor) {
+ if (!func_args->session->aor) {
return 0;
}
- snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(pvt->session->aor));
+ snprintf(func_args->buf, func_args->len, "%s", ast_sorcery_object_get_id(func_args->session->aor));
} else if (!strcmp(func_args->param, "pjsip")) {
- func_args->ret = channel_read_pjsip(func_args->chan, func_args->type,
+ func_args->ret = channel_read_pjsip(func_args->session->channel, func_args->type,
func_args->field, func_args->buf,
func_args->len);
} else {
@@ -806,7 +788,6 @@ int pjsip_acf_channel_read(struct ast_channel *chan, const char *cmd, char *data
ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
return -1;
}
- channel = ast_channel_tech_pvt(chan);
/* Check for zero arguments */
if (ast_strlen_zero(parse)) {
@@ -816,29 +797,44 @@ int pjsip_acf_channel_read(struct ast_channel *chan, const char *cmd, char *data
AST_STANDARD_APP_ARGS(args, parse);
+ ast_channel_lock(chan);
+
/* Sanity check */
if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
ast_log(LOG_WARNING, "Cannot call %s on a non-PJSIP channel\n", cmd);
+ ast_channel_unlock(chan);
return 0;
}
+ channel = ast_channel_tech_pvt(chan);
if (!channel) {
- ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
+ ast_log(LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan));
+ ast_channel_unlock(chan);
return -1;
}
+ if (!channel->session) {
+ ast_log(LOG_WARNING, "Channel %s has no session\n", ast_channel_name(chan));
+ ast_channel_unlock(chan);
+ return -1;
+ }
+
+ func_args.session = ao2_bump(channel->session);
+ ast_channel_unlock(chan);
+
memset(buf, 0, len);
- func_args.chan = chan;
func_args.param = args.param;
func_args.type = args.type;
func_args.field = args.field;
func_args.buf = buf;
func_args.len = len;
- if (ast_sip_push_task_synchronous(channel->session->serializer, read_pjsip, &func_args)) {
+ if (ast_sip_push_task_synchronous(func_args.session->serializer, read_pjsip, &func_args)) {
ast_log(LOG_WARNING, "Unable to read properties of channel %s: failed to push task\n", ast_channel_name(chan));
+ ao2_ref(func_args.session, -1);
return -1;
}
+ ao2_ref(func_args.session, -1);
return func_args.ret;
}
diff --git a/codecs/codec_dahdi.c b/codecs/codec_dahdi.c
index 8832bc3..f207b64 100644
--- a/codecs/codec_dahdi.c
+++ b/codecs/codec_dahdi.c
@@ -36,11 +36,11 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+#include <poll.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
-#include <sys/poll.h>
#include <dahdi/user.h>
#include "asterisk/lock.h"
diff --git a/configs/samples/ast_debug_tools.conf.sample b/configs/samples/ast_debug_tools.conf.sample
new file mode 100644
index 0000000..f26626b
--- /dev/null
+++ b/configs/samples/ast_debug_tools.conf.sample
@@ -0,0 +1,57 @@
+#
+# This file is used by the Asterisk debug tools.
+# Unlike other Asterisk config files, this one is
+# "sourced" by bash and must adhere to bash semantics.
+#
+
+# A list of coredumps and/or coredump search patterns.
+# Bash extended globs are enabled and any resulting files
+# that aren't actually coredumps are silently ignored
+# so you can be liberal with the globs.
+#
+# If your patterns contains spaces be sure to only quote
+# the portion of the pattern that DOESN'T contain wildcard
+# expressions. If you quote the whole pattern, it won't
+# be expanded and the glob characters will be treated as
+# literals.
+#
+# The exclusion of files ending ".txt" is just for
+# demonstration purposes as non-coredumps will be ignored
+# anyway.
+COREDUMPS=(/tmp/core[-._]asterisk!(*.txt) /tmp/core[-._]$(hostname)!(*.txt))
+
+# Date command for the "running" coredump and tarballs.
+# DATEFORMAT will be executed to get the timestamp.
+# Don't put quotes around the format string or they'll be
+# treated as literal characters. Also be aware of colons
+# in the output as you can't upload files with colons in
+# the name to Jira.
+#
+# Unix timestamp
+#DATEFORMAT='date +%s.%N'
+#
+# Unix timestamp on *BSD/MacOS after installing coreutils
+#DATEFORMAT='gdate +%s.%N'
+#
+# Readable GMT
+#DATEFORMAT='date -u +%FT%H-%M-%S%z'
+#
+# Readable Local time
+DATEFORMAT='date +%FT%H-%M-%S%z'
+
+# A list of log files and/or log file search patterns using the
+# same syntax as COREDUMPS.
+#
+LOGFILES=(/var/log/asterisk/messages* /var/log/asterisk/queue* \
+ /var/log/asterisk/debug* /var/log/asterisk/security*)
+
+# ast_loggrabber converts POSIX timestamps to readable format
+# using this Python strftime format string. If not specified
+# or an empty string, no format covnersion is done.
+LOG_DATEFORMAT="%m/%d-%H:%M:%S.%f"
+
+# The timezone to use when converting POSIX timestamps to
+# readable format. It can be specified in "<continent>/<city>"
+# format or in abbreviation format such as "CST6CDT". If not
+# specified, the "local" timezone is used.
+# LOG_TIMEZONE=
diff --git a/configs/samples/pjproject.conf.sample b/configs/samples/pjproject.conf.sample
index 97af734..82c81a1 100644
--- a/configs/samples/pjproject.conf.sample
+++ b/configs/samples/pjproject.conf.sample
@@ -1,15 +1,36 @@
; Common pjproject options
;
+;[startup]
+; NOTES: The name of this section in the pjproject.conf configuration file must
+; remain startup or the configuration will not be applied.
+;
+;log_level=default ; Initial maximum pjproject logging level to log
+ ; Valid values are: 0-6, and default
+ ;
+ ; Note: This option is needed very early in the startup
+ ; process so it can only be read from config files because
+ ; the modules for other methods have not been loaded yet.
+;type= ; Must be of type startup (default: "")
+
;========================LOG_MAPPINGS SECTION OPTIONS===============================
;[log_mappings]
; SYNOPSIS: Provides pjproject to Asterisk log level mappings.
; NOTES: The name of this section in the pjproject.conf configuration file must
; remain log_mappings or the configuration will not be applied.
; The defaults mentioned below only apply if this file or the 'log_mappings'
-; object can'tbe found. If the object is found, there are no defaults. If
+; object can't be found. If the object is found, there are no defaults. If
; you don't specify an entry, nothing will be logged for that level.
;
+; These logging level meanings are typically used by pjproject:
+; - 0: fatal error
+; - 1: error
+; - 2: warning
+; - 3: info
+; - 4: debug
+; - 5: trace
+; - 6: more detailed trace
+;
;asterisk_error = ; A comma separated list of pjproject log levels to map to
; Asterisk errors.
; (default: "0,1")
@@ -24,5 +45,5 @@
; (default: "")
;asterisk_debug = ; A comma separated list of pjproject log levels to map to
; Asterisk debug
- ; (default: "3,4,5")
+ ; (default: "3,4,5,6")
;type= ; Must be of type log_mappings (default: "")
diff --git a/configs/samples/res_odbc.conf.sample b/configs/samples/res_odbc.conf.sample
index 42d89ec..c69f556 100644
--- a/configs/samples/res_odbc.conf.sample
+++ b/configs/samples/res_odbc.conf.sample
@@ -74,13 +74,11 @@ password => mypass
pre-connect => yes
; Certain servers, such as MS SQL Server and Sybase use the TDS protocol, which
-; limits the number of active queries per connection to 1. By telling res_odbc
-; not to share connections, Asterisk can be made to work with these servers.
+; limits the number of active queries per connection to 1.
[sqlserver]
enabled => no
dsn => mickeysoft
-share_connections => no
-limit => 5
+max_connections => 5
username => oscar
password => thegrouch
pre-connect => yes
diff --git a/configure b/configure
index 8d1ad91..cbf3022 100755
--- a/configure
+++ b/configure
@@ -1207,6 +1207,7 @@ PBX_BISON
OPENSSL
SHA1SUM
LDCONFIG
+DOWNLOAD_TIMEOUT
DOWNLOAD_TO_STDOUT
DOWNLOAD
FETCH
@@ -4894,7 +4895,7 @@ case "${host_os}" in
OSARCH=cygwin
PBX_WINARCH=1
;;
- linux-gnueabi* | linux-gnuspe)
+ linux-gnu*)
OSARCH=linux-gnu
;;
kfreebsd*-gnu)
@@ -7871,9 +7872,11 @@ fi
if test "${WGET}" != ":" ; then
DOWNLOAD=${WGET}
DOWNLOAD_TO_STDOUT="${WGET} -O-"
+ DOWNLOAD_TIMEOUT='--timeout=$1'
else if test "${CURL}" != ":" ; then
DOWNLOAD="${CURL} -O --progress-bar -w \"%{url_effective}\n\""
DOWNLOAD_TO_STDOUT="${CURL} -L --progress-bar -w \"%{url_effective}\n\""
+ DOWNLOAD_TIMEOUT='--max-time $(or $2,$1)'
else
# Extract the first word of "fetch", so it can be a program name with args.
set dummy fetch; ac_word=$2
@@ -7918,11 +7921,14 @@ fi
DOWNLOAD=${FETCH}
DOWNLOAD_TO_STDOUT="${FETCH} -o-"
+ DOWNLOAD_TIMEOUT='--timeout=$(or $2,$1)'
fi
fi
+
+
# Extract the first word of "ldconfig", so it can be a program name with args.
set dummy ldconfig; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
@@ -9203,7 +9209,7 @@ PJPROJECT_BUNDLED=no
# Check whether --with-pjproject-bundled was given.
if test "${with_pjproject_bundled+set}" = set; then :
- withval=$with_pjproject_bundled; case "${enableval}" in
+ withval=$with_pjproject_bundled; case "${withval}" in
n|no) PJPROJECT_BUNDLED=no ;;
*) PJPROJECT_BUNDLED=yes ;;
esac
@@ -9251,7 +9257,7 @@ $as_echo "configuring" >&6; }
as_fn_error $? "cat is required to build bundled pjproject" "$LINENO" 5
fi
- export TAR PATCH SED NM EXTERNALS_CACHE_DIR DOWNLOAD_TO_STDOUT
+ export TAR PATCH SED NM EXTERNALS_CACHE_DIR DOWNLOAD_TO_STDOUT DOWNLOAD_TIMEOUT DOWNLOAD MD5 CAT
${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} EXTERNALS_CACHE_DIR=${EXTERNALS_CACHE_DIR} configure
if test $? -ne 0 ; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
diff --git a/configure.ac b/configure.ac
index 797770e..931abe1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -178,7 +178,7 @@ case "${host_os}" in
OSARCH=cygwin
PBX_WINARCH=1
;;
- linux-gnueabi* | linux-gnuspe)
+ linux-gnu*)
OSARCH=linux-gnu
;;
kfreebsd*-gnu)
@@ -264,6 +264,7 @@ AC_SUBST(GNU_LD)
AC_PATH_PROG([BISON], [bison], :)
AC_PATH_PROG([CMP], [cmp], :)
+AC_PATH_PROG([CAT], [cat], :)
AC_PATH_PROG([FLEX], [flex], :)
AC_PATH_PROG([GREP], [grep], :)
AC_PATH_PROG([PYTHON], [python], :)
@@ -294,18 +295,23 @@ AC_PATH_PROG([NM], [nm], :)
if test "${WGET}" != ":" ; then
DOWNLOAD=${WGET}
DOWNLOAD_TO_STDOUT="${WGET} -O-"
+ DOWNLOAD_TIMEOUT='--timeout=$1'
else if test "${CURL}" != ":" ; then
DOWNLOAD="${CURL} -O --progress-bar -w \"%{url_effective}\n\""
DOWNLOAD_TO_STDOUT="${CURL} -L --progress-bar -w \"%{url_effective}\n\""
+ DOWNLOAD_TIMEOUT='--max-time $(or $2,$1)'
else
AC_PATH_PROG([FETCH], [fetch], [:])
DOWNLOAD=${FETCH}
DOWNLOAD_TO_STDOUT="${FETCH} -o-"
+ DOWNLOAD_TIMEOUT='--timeout=$(or $2,$1)'
fi
fi
AC_SUBST(DOWNLOAD)
AC_SUBST(DOWNLOAD_TO_STDOUT)
+AC_SUBST(DOWNLOAD_TIMEOUT)
+
AC_PATH_PROG([LDCONFIG], [ldconfig], :)
AC_PATH_PROG([SHA1SUM], [sha1sum], $ac_aux_dir/build_tools/sha1sum-sh)
AC_PATH_PROG([OPENSSL], [openssl], :)
@@ -425,7 +431,7 @@ AH_TEMPLATE(m4_bpatsubst([[HAVE_PJPROJECT_BUNDLED]], [(.*)]), [Define to 1 when
AC_ARG_WITH([pjproject-bundled],
[AS_HELP_STRING([--with-pjproject-bundled],
[Use bundled pjproject libraries])],
- [case "${enableval}" in
+ [case "${withval}" in
n|no) PJPROJECT_BUNDLED=no ;;
*) PJPROJECT_BUNDLED=yes ;;
esac])
diff --git a/contrib/Makefile b/contrib/Makefile
index 2c91b47..9512de5 100644
--- a/contrib/Makefile
+++ b/contrib/Makefile
@@ -20,10 +20,14 @@ clean:
include $(ASTTOPDIR)/Makefile.rules
install:
- if [ -n "$(findstring REF_DEBUG,$(MENUSELECT_CFLAGS))" ]; then \
- $(INSTALL) -d "$(DESTDIR)$(ASTDATADIR)/scripts"; \
- $(INSTALL) -m 755 scripts/refcounter.py "$(DESTDIR)$(ASTDATADIR)/scripts/refcounter.py"; \
- fi
+ $(INSTALL) -d "$(DESTDIR)$(ASTDATADIR)/scripts"
+ $(INSTALL) -m 755 scripts/ast_logescalator "$(DESTDIR)$(ASTDATADIR)/scripts/ast_logescalator"
+ $(INSTALL) -m 755 scripts/ast_loggrabber "$(DESTDIR)$(ASTDATADIR)/scripts/ast_loggrabber"
+ $(INSTALL) -m 755 scripts/ast_coredumper "$(DESTDIR)$(ASTDATADIR)/scripts/ast_coredumper"
+ $(INSTALL) -m 755 scripts/refcounter.py "$(DESTDIR)$(ASTDATADIR)/scripts/refcounter.py"
uninstall:
- rm -f "$(DESTDIR)$(ASTDATADIR)/scripts/refcounter.py"
+ -rm -f "$(DESTDIR)$(ASTDATADIR)/scripts/ast_logescalator"
+ -rm -f "$(DESTDIR)$(ASTDATADIR)/scripts/ast_loggrabber"
+ -rm -f "$(DESTDIR)$(ASTDATADIR)/scripts/ast_coredumper"
+ -rm -f "$(DESTDIR)$(ASTDATADIR)/scripts/refcounter.py"
diff --git a/contrib/ast-db-manage/config/versions/28ab27a7826d_add_srv_lookups_to_identify.py b/contrib/ast-db-manage/config/versions/28ab27a7826d_add_srv_lookups_to_identify.py
new file mode 100644
index 0000000..8831e20
--- /dev/null
+++ b/contrib/ast-db-manage/config/versions/28ab27a7826d_add_srv_lookups_to_identify.py
@@ -0,0 +1,31 @@
+"""add srv_lookups to identify
+
+Revision ID: 28ab27a7826d
+Revises: 4468b4a91372
+Create Date: 2017-01-06 14:53:38.829655
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '28ab27a7826d'
+down_revision = '4468b4a91372'
+
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy.dialects.postgresql import ENUM
+
+YESNO_NAME = 'yesno_values'
+YESNO_VALUES = ['yes', 'no']
+
+def upgrade():
+ ############################# Enums ##############################
+
+ # yesno_values have already been created, so use postgres enum object
+ # type to get around "already created" issue - works okay with mysql
+ yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False)
+
+ op.add_column('ps_endpoint_id_ips', sa.Column('srv_lookups', yesno_values))
+
+
+def downgrade():
+ op.drop_column('ps_endpoint_id_ips', 'srv_lookups')
diff --git a/contrib/realtime/mssql/mssql_config.sql b/contrib/realtime/mssql/mssql_config.sql
index 1582406..ba27afb 100644
--- a/contrib/realtime/mssql/mssql_config.sql
+++ b/contrib/realtime/mssql/mssql_config.sql
@@ -1551,6 +1551,20 @@ UPDATE alembic_version SET version_num='4468b4a91372' WHERE alembic_version.vers
GO
+-- Running upgrade 4468b4a91372 -> 28ab27a7826d
+
+ALTER TABLE ps_endpoint_id_ips ADD srv_lookups VARCHAR(3) NULL;
+
+GO
+
+ALTER TABLE ps_endpoint_id_ips ADD CONSTRAINT yesno_values CHECK (srv_lookups IN ('yes', 'no'));
+
+GO
+
+UPDATE alembic_version SET version_num='28ab27a7826d' WHERE alembic_version.version_num = '4468b4a91372';
+
+GO
+
COMMIT;
GO
diff --git a/contrib/realtime/mysql/mysql_config.sql b/contrib/realtime/mysql/mysql_config.sql
index 69329d9..ca3f130 100644
--- a/contrib/realtime/mysql/mysql_config.sql
+++ b/contrib/realtime/mysql/mysql_config.sql
@@ -956,3 +956,9 @@ ALTER TABLE ps_endpoints ADD COLUMN asymmetric_rtp_codec ENUM('yes','no');
UPDATE alembic_version SET version_num='4468b4a91372' WHERE alembic_version.version_num = 'a6ef36f1309';
+-- Running upgrade 4468b4a91372 -> 28ab27a7826d
+
+ALTER TABLE ps_endpoint_id_ips ADD COLUMN srv_lookups ENUM('yes','no');
+
+UPDATE alembic_version SET version_num='28ab27a7826d' WHERE alembic_version.version_num = '4468b4a91372';
+
diff --git a/contrib/realtime/oracle/oracle_config.sql b/contrib/realtime/oracle/oracle_config.sql
index 90f1245..d2a4f0f 100644
--- a/contrib/realtime/oracle/oracle_config.sql
+++ b/contrib/realtime/oracle/oracle_config.sql
@@ -1549,3 +1549,17 @@ UPDATE alembic_version SET version_num='4468b4a91372' WHERE alembic_version.vers
/
+-- Running upgrade 4468b4a91372 -> 28ab27a7826d
+
+ALTER TABLE ps_endpoint_id_ips ADD srv_lookups VARCHAR(3 CHAR)
+
+/
+
+ALTER TABLE ps_endpoint_id_ips ADD CONSTRAINT yesno_values CHECK (srv_lookups IN ('yes', 'no'))
+
+/
+
+UPDATE alembic_version SET version_num='28ab27a7826d' WHERE alembic_version.version_num = '4468b4a91372'
+
+/
+
diff --git a/contrib/realtime/postgresql/postgresql_config.sql b/contrib/realtime/postgresql/postgresql_config.sql
index 436d32f..9f169e5 100644
--- a/contrib/realtime/postgresql/postgresql_config.sql
+++ b/contrib/realtime/postgresql/postgresql_config.sql
@@ -1032,5 +1032,11 @@ ALTER TABLE ps_endpoints ADD COLUMN asymmetric_rtp_codec yesno_values;
UPDATE alembic_version SET version_num='4468b4a91372' WHERE alembic_version.version_num = 'a6ef36f1309';
+-- Running upgrade 4468b4a91372 -> 28ab27a7826d
+
+ALTER TABLE ps_endpoint_id_ips ADD COLUMN srv_lookups yesno_values;
+
+UPDATE alembic_version SET version_num='28ab27a7826d' WHERE alembic_version.version_num = '4468b4a91372';
+
COMMIT;
diff --git a/contrib/scripts/ast_coredumper b/contrib/scripts/ast_coredumper
new file mode 100755
index 0000000..81e94e9
--- /dev/null
+++ b/contrib/scripts/ast_coredumper
@@ -0,0 +1,533 @@
+#!/usr/bin/env bash
+# Turn on extended globbing
+shopt -s extglob
+# Bail on any error
+set -e
+
+prog=$(basename $0)
+
+print_help() {
+cat <<EOF
+NAME
+ $prog - Dump and/or format asterisk coredump files
+
+SYNOPSIS
+ $prog [ --help ] [ --running | --RUNNING ] [ --latest ]
+ [ --tarball-coredumps ] [ --delete-coredumps-after ]
+ [ --tarball-results ] [ --delete-results-after ]
+ [ --tarball-uniqueid="<uniqueid>" ]
+ [ --no-default-search ] [ --append-coredumps ]
+ [ <coredump> | <pattern> ... ]
+
+DESCRIPTION
+
+ Extracts backtraces and lock tables from Asterisk coredump files.
+ For each coredump found, 4 new result files are created:
+ - <coredump>.brief.txt: The output of "thread apply all bt".
+
+ - <coredump>.thread1.txt: The output of "thread apply 1 bt full".
+
+ - <coredump>.full.txt: The output of "thread apply all bt full".
+
+ - <coredump>.locks.txt: If asterisk was compiled with
+ "DEBUG_THREADS", this file will contain a dump of the locks
+ table similar to doing a "core show locks" from the asterisk
+ CLI.
+
+ Optional features:
+ - The running asterisk process can be suspended and dumped.
+ - The coredumps can be merged into a tarball.
+ - The coredumps can be deleted after processing.
+ - The results files can be merged into a tarball.
+ - The results files can be deleted after processing.
+
+ Options:
+
+ --help
+ Print this help.
+
+ --running
+ Create a coredump from the running asterisk instance and
+ process it along with any other coredumps found (if any).
+ WARNING: This WILL interrupt call processing. You will be
+ asked to confirm.
+
+ --RUNNING
+ Same as --running but without the confirmation prompt.
+ DANGEROUS!!
+
+ --latest
+ Process only the latest coredump from those specified (based
+ on last-modified time). If a dump of the running process was
+ requested, it is always included in addition to the latest
+ from the existing coredumps.
+
+ --tarball-coredumps
+ Creates a gzipped tarball of all coredumps processed.
+ The tarball name will be:
+ /tmp/asterisk.<timestamp>.coredumps.tar.gz
+
+ --delete-coredumps-after
+ Deletes all processed coredumps regardless of whether
+ a tarball was created.
+
+ --tarball-results
+ Creates a gzipped tarball of all result files produced.
+ The tarball name will be:
+ /tmp/asterisk.<timestamp>.results.tar.gz
+
+ --delete-results-after
+ Deletes all processed results regardless of whether
+ a tarball was created. It probably doesn't make sense
+ to use this option unless you have also specified
+ --tarball-results.
+
+ --tarball-uniqueid="<uniqueid>"
+ Normally DATEFORMAT is used to make the tarballs unique
+ but you can use your own unique id in the tarball names
+ such as the Jira issue id.
+
+ --no-default-search
+ Ignore COREDUMPS from the config files and process only
+ coredumps listed on the command line (if any) and/or
+ the running asterisk instance (if requested).
+
+ --append-coredumps
+ Append any coredumps specified on the command line to the
+ config file specified ones instead of overriding them.
+
+ <coredump> | <pattern>
+ A list of coredumps or coredump search patterns. Unless
+ --append-coredumps was specified, these entries will override
+ those specified in the config files.
+
+ Any resulting file that isn't actually a coredump is silently
+ ignored. If your patterns contains spaces be sure to only
+ quote the portion of the pattern that DOESN'T contain wildcard
+ expressions. If you quote the whole pattern, it won't be
+ expanded.
+
+ If --no-default-search is specified and no files are specified
+ on the command line, then the only the running asterisk process
+ will be dumped (if requested). Otherwise if no files are
+ specified on the command line the value of COREDUMPS from
+ ast_debug_tools.conf will be used. Failing that, the following
+ patterns will be used:
+ /tmp/core[-._]asterisk!(*.txt)
+ /tmp/core[-._]\$(hostname)!(*.txt)
+
+NOTES
+ You must be root to use $prog.
+
+ The script relies on not only bash, but also recent GNU date and
+ gdb with python support. *BSD operating systems may require
+ installation of the 'coreutils' and 'devel/gdb' packagess and minor
+ tweaking of the ast_debug_tools.conf file.
+
+ Any files output will have ':' characters changed to '-'. This is
+ to facilitate uploading those files to Jira which doesn't like the
+ colons.
+
+FILES
+ /etc/asterisk/ast_debug_tools.conf
+ ~/ast_debug_tools.conf
+ ./ast_debug_tools.conf
+
+ #
+ # This file is used by the Asterisk debug tools.
+ # Unlike other Asterisk config files, this one is
+ # "sourced" by bash and must adhere to bash semantics.
+ #
+
+ # A list of coredumps and/or coredump search patterns.
+ # Bash extended globs are enabled and any resulting files
+ # that aren't actually coredumps are silently ignored
+ # so you can be liberal with the globs.
+ #
+ # If your patterns contains spaces be sure to only quote
+ # the portion of the pattern that DOESN'T contain wildcard
+ # expressions. If you quote the whole pattern, it won't
+ # be expanded and the glob characters will be treated as
+ # literals.
+ #
+ # The exclusion of files ending ".txt" is just for
+ # demonstration purposes as non-coredumps will be ignored
+ # anyway.
+ COREDUMPS=(/tmp/core[-._]asterisk!(*.txt) /tmp/core[-._]\$(hostname)!(*.txt))
+
+ # Date command for the "running" coredump and tarballs.
+ # DATEFORMAT will be executed to get the timestamp.
+ # Don't put quotes around the format string or they'll be
+ # treated as literal characters. Also be aware of colons
+ # in the output as you can't upload files with colons in
+ # the name to Jira.
+ #
+ # Unix timestamp
+ #DATEFORMAT='date +%s.%N'
+ #
+ # *BSD/MacOS doesn't support %N but after installing GNU
+ # coreutils...
+ #DATEFORMAT='gdate +%s.%N'
+ #
+ # Readable GMT
+ #DATEFORMAT='date -u +%FT%H-%M-%S%z'
+ #
+ # Readable Local time
+ DATEFORMAT='date +%FT%H-%M-%S%z'
+
+EOF
+ exit 1
+}
+
+if [ $EUID -ne 0 ] ; then
+ echo "You must be root to use $prog."
+ exit 1
+fi
+
+running=false
+RUNNING=false
+latest=false
+tarball_coredumps=false
+delete_coredumps_after=false
+tarball_results=false
+delete_results_after=false
+append_coredumps=false
+
+declare -a COREDUMPS
+declare -a ARGS_COREDUMPS
+
+# Read config files from least important to most important
+[ -f /etc/asterisk/ast_debug_tools.conf ] && source /etc/asterisk/ast_debug_tools.conf
+[ -f ~/ast_debug_tools.conf ] && source ~/ast_debug_tools.conf
+[ -f ./ast_debug_tools.conf ] && source ./ast_debug_tools.conf
+
+# For *BSD, the preferred gdb may be in /usr/local/bin so we
+# need to search for one that supports python.
+for g in $(which -a gdb) ; do
+ result=$($g --batch --ex "python print('hello')" 2>/dev/null || : )
+ if [[ "$result" =~ ^hello$ ]] ; then
+ GDB=$g
+ break
+ fi
+done
+
+if [ -z "$GDB" ] ; then
+ echo "No suitable gdb was found in $PATH"
+ exit 1
+fi
+
+if [ ${#COREDUMPS[@]} -eq 0 ] ; then
+ COREDUMPS+=(/tmp/core[-._]asterisk!(*.txt) /tmp/core[-._]$(hostname)!(*.txt))
+fi
+
+DATEFORMAT=${DATEFORMAT:-'date +%FT%H-%M-%S%z'}
+
+# Use "$@" (with the quotes) so spaces in patterns or
+# file names are preserved.
+# Later on when we have to iterate over COREDUMPS, we always
+# use the indexes rather than trying to expand the values of COREDUMPS
+# just in case.
+
+for a in "$@" ; do
+ case "$a" in
+ --running)
+ running=true
+ ;;
+ --RUNNING)
+ RUNNING=true
+ ;;
+ --no-default-search)
+ # Clean out COREDUMPS from config files
+ COREDUMPS=()
+ ;;
+ --latest)
+ latest=true
+ ;;
+ --tarball-coredumps)
+ tarball_coredumps=true
+ ;;
+ --delete-coredumps-after)
+ delete_coredumps_after=true
+ ;;
+ --tarball-results)
+ tarball_results=true
+ ;;
+ --delete-results-after)
+ delete_results_after=true
+ ;;
+ --append-coredumps)
+ append_coredumps=true
+ ;;
+ --tarball-uniqueid=*)
+ tarball_uniqueid=${a#*=}
+ ;;
+ --help|-*)
+ print_help
+ ;;
+ *)
+ ARGS_COREDUMPS+=("$a")
+ # If any files are specified on the command line, ignore those
+ # specified in the config files unless append-coredumps was specified.
+ if ! $append_coredumps ; then
+ COREDUMPS=()
+ fi
+ esac
+done
+
+# append coredumps/patterns specified as command line arguments to COREDUMPS.
+for i in ${!ARGS_COREDUMPS[@]} ; do
+ COREDUMPS+=("${ARGS_COREDUMPS[$i]}")
+done
+
+# At this point, all glob entries that match files should be expanded.
+# Any entries that don't exist are probably globs that didn't match anything
+# and need to be pruned. Any non coredumps are also pruned.
+
+for i in ${!COREDUMPS[@]} ; do
+ if [ ! -f "${COREDUMPS[$i]}" ] ; then
+ unset COREDUMPS[$i]
+ continue
+ fi
+ # Some versions of 'file' don't allow only the first n bytes of the
+ # file to be processed so we use dd to grab just the first 32 bytes.
+ mimetype=$(dd if="${COREDUMPS[$i]}" bs=32 count=1 2>/dev/null | file -bi -)
+ if [[ ! "$mimetype" =~ coredump ]] ; then
+ unset COREDUMPS[$i]
+ continue
+ fi
+done
+
+# Sort and weed out any dups
+IFS=$'\x0a'
+readarray -t COREDUMPS < <(echo -n "${COREDUMPS[*]}" | sort -u )
+unset IFS
+
+# If --latest, get the last modified timestamp of each file,
+# sort them, then return the latest.
+if [ ${#COREDUMPS[@]} -gt 0 ] && $latest ; then
+ lf=$(find "${COREDUMPS[@]}" -printf '%T@ %p\n' | sort -n | tail -1)
+ COREDUMPS=("${lf#* }")
+fi
+
+# Timestamp to use for output files
+df=${tarball_uniqueid:-$(${DATEFORMAT})}
+
+if $running || $RUNNING ; then
+ # We need to go through some gyrations to find the pid of the running
+ # MAIN asterisk process and not someone or something running asterisk -r.
+ # The pid file may NOT be in /var/run/asterisk so we need to find any
+ # running asterisk process and see if -C was specified on the command
+ # line. The chances of more than 1 asterisk instance running with
+ # different -C options is so unlikely that we're going to ignore it.
+ #
+ # 'ps axo command' should work on Linux (back to CentOS6) and FreeBSD.
+ # If asterisk was started with -C, get the asterisk.conf file.
+ # If it wasn't, assume /etc/asterisk/asterisk.conf
+ astetcconf=`ps axo command | sed -n -r -e "s/.*asterisk\s+.*-C\s+([^ ]+).*/\1/gp" | tail -1`
+ [ x$astetcconf = x ] && astetcconf=/etc/asterisk/asterisk.conf
+ # Now parse out astrundir and cat asterisk.pid
+ astrundir=$(sed -n -r -e "s/astrundir\s+[=>]+\s+(.*)/\1/gp" $astetcconf)
+ pid=$(cat $astrundir/asterisk.pid 2>/dev/null || : )
+ if [ x$pid = x ] ; then
+ echo "Asterisk is not running"
+ else
+ if $RUNNING ; then
+ answer=Y
+ else
+ read -p "WARNING: Taking a core dump of the running asterisk instance will suspend call processing while the dump is saved. Do you wish to continue? (y/N) " answer
+ fi
+ if [[ "$answer" =~ ^[Yy] ]] ; then
+ cf="/tmp/core-asterisk-running-$df"
+ echo "Dumping running asterisk process to $cf"
+ ${GDB} -p $pid -q --batch --ex "gcore $cf" >/dev/null 2>&1
+ COREDUMPS+=("$cf")
+ else
+ echo "Skipping dump of running process"
+ fi
+ fi
+fi
+
+if [ "${#COREDUMPS[@]}" -eq 0 ] ; then
+ echo "No coredumps found"
+ print_help
+fi
+
+# Extract the gdb scripts from the end of this script
+# and save them to /tmp/.gdbinit
+
+ss=`egrep -n "^#@@@SCRIPTSTART@@@" $0 |cut -f1 -d:`
+tail -n +${ss} $0 >/tmp/.ast_coredumper.gdbinit
+
+# Now iterate over the coredumps and dump the debugging info
+for i in ${!COREDUMPS[@]} ; do
+ cf=${COREDUMPS[$i]}
+ echo "Processing $cf"
+ ${GDB} -n --batch -q --ex "source /tmp/.ast_coredumper.gdbinit" $(which asterisk) "$cf" 2>/dev/null | (
+ of=/dev/null
+ while IFS= read line ; do
+ if [[ "$line" =~ !@!@!@!\ ([^\ ]+)\ !@!@!@! ]] ; then
+ of=${cf}-${BASH_REMATCH[1]}
+ of=${of//:/-}
+ rm -f "$of"
+ echo "Creating $of"
+ fi
+ echo -e $"$line" >> "$of"
+ done
+ )
+done
+
+if $tarball_coredumps ; then
+ tf=/tmp/asterisk-$df.coredumps.tar
+ echo "Creating $tf.gz"
+ for i in ${!COREDUMPS[@]} ; do
+ tar -uvf $tf "${COREDUMPS[@]}" 2>/dev/null
+ done
+ gzip $tf
+fi
+
+if $delete_coredumps_after ; then
+ for i in ${!COREDUMPS[@]} ; do
+ rm -rf "${COREDUMPS[$i]}"
+ done
+fi
+
+if $tarball_results ; then
+ tf=/tmp/asterisk-$df-results.tar
+ echo "Creating $tf.gz"
+ for i in ${!COREDUMPS[@]} ; do
+ tar -uvf $tf "${COREDUMPS[$i]//:/-}"-{brief,full,thread1,locks}.txt 2>/dev/null
+ done
+ gzip $tf
+fi
+
+if $delete_results_after ; then
+ for i in ${!COREDUMPS[@]} ; do
+ rm -rf "${COREDUMPS[$i]//:/-}"-{brief,full,thread1,locks}.txt
+ done
+fi
+
+exit
+
+# Be careful editng the inline scripts.
+# They're space-indented.
+
+# We need the python bit because lock_infos isn't
+# a valid symbol in asterisk unless DEBUG_THREADS was
+# used during the compile. Also, interrupt and continue
+# are only valid for a running program.
+
+#@@@SCRIPTSTART@@@
+python
+class DumpAsteriskCommand(gdb.Command):
+
+ def __init__(self):
+ super(DumpAsteriskCommand, self).__init__ ("dump-asterisk",
+ gdb.COMMAND_OBSCURE, gdb.COMPLETE_COMMAND)
+
+ def invoke(self, arg, from_tty):
+ try:
+ gdb.execute("interrupt", from_tty)
+ except:
+ pass
+ print("!@!@!@! thread1.txt !@!@!@!\n")
+ try:
+ gdb.execute("thread apply 1 bt full", from_tty)
+ except:
+ pass
+ print("!@!@!@! brief.txt !@!@!@!\n")
+ try:
+ gdb.execute("thread apply all bt", from_tty)
+ except:
+ pass
+ print("!@!@!@! full.txt !@!@!@!\n")
+ try:
+ gdb.execute("thread apply all bt full", from_tty)
+ except:
+ pass
+ print("!@!@!@! locks.txt !@!@!@!\n")
+ try:
+ gdb.execute("show_locks", from_tty)
+ except:
+ pass
+ try:
+ gdb.execute("continue", from_tty)
+ except:
+ pass
+
+DumpAsteriskCommand ()
+end
+
+define show_locks
+ set $n = lock_infos.first
+
+ if $argc == 0
+ printf " where_held count-|\n"
+ printf " suspended-| |\n"
+ printf " type- | times locked-| | |\n"
+ printf "thread status file line function lock name | lock addr | | |\n"
+ else
+ printf "thread,status,file,line,function,lock_name,lock_type,lock_addr,times_locked,suspended,where_held_count,where_held_file,where_held_line,where_held_function,there_held_thread\n"
+ end
+
+ while $n
+ if $n->num_locks > 0
+ set $i = 0
+ while $i < $n->num_locks
+ if $n->locks[$i]->suspended == 0
+ if ((ast_mutex_t *)$n->locks[$i]->lock_addr)->tracking
+ if $n->locks[$i]->type > 0
+ set $track = ((ast_rwlock_t *)$n->locks[$i]->lock_addr)->track
+ else
+ set $track = ((ast_mutex_t *)$n->locks[$i]->lock_addr)->track
+ end
+ end
+ set $reentrancy = $track->reentrancy
+ set $pending = $n->locks[$i]->pending
+ if $argc > 0
+ printf "%p,%d,%s,%d,%s,%s,%d,%p,%d,%d,%d",\
+ $n->thread_id, $n->locks[$i]->pending, $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
+ $n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
+ $n->locks[$i]->suspended, $track->reentrancy
+ if $reentrancy
+ if $pending
+ printf ",%s,%d,%s,%p", $track->file[0], $track->lineno[0], $track->func[0], $track->thread[0]
+ end
+ end
+ else
+ if $n->locks[$i]->pending < 0
+ printf "%p failed %-20s %6d %-36s %-20s %d %14p %3d %d %d",\
+ $n->thread_id,\
+ $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
+ $n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
+ $n->locks[$i]->suspended, $track->reentrancy
+ end
+ if $n->locks[$i]->pending == 0
+ printf "%p holding %-20s %6d %-36s %-20s %d %14p %3d %d %d",\
+ $n->thread_id,\
+ $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
+ $n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
+ $n->locks[$i]->suspended, $track->reentrancy
+ end
+ if $n->locks[$i]->pending > 0
+ printf "%p waiting %-20s %6d %-36s %-20s %d %14p %3d %d %d",\
+ $n->thread_id,\
+ $n->locks[$i]->file, $n->locks[$i]->line_num, $n->locks[$i]->func,\
+ $n->locks[$i]->lock_name, $n->locks[$i]->type, $n->locks[$i]->lock_addr, $n->locks[$i]->times_locked,\
+ $n->locks[$i]->suspended, $track->reentrancy
+ end
+ if $reentrancy
+ if $pending
+ printf "\n held at: %-20s %6d %-36s by 0x%08lx", $track->file[0], $track->lineno[0], $track->func[0], $track->thread_id[0]
+ end
+ end
+ end
+ printf "\n"
+ end
+ set $i = $i + 1
+ end
+ end
+ set $n = $n->entry->next
+ end
+end
+
+dump-asterisk
diff --git a/contrib/scripts/ast_logescalator b/contrib/scripts/ast_logescalator
new file mode 100755
index 0000000..054ef9b
--- /dev/null
+++ b/contrib/scripts/ast_logescalator
@@ -0,0 +1,399 @@
+#!/usr/bin/env bash
+# Turn on extended globbing
+shopt -s extglob
+# Bail on any error
+set -e
+
+prog=$(basename $0)
+
+print_help() {
+cat <<EOF
+NAME
+ $prog - Escalate Asterisk logging levels
+
+SYNOPSIS
+ $prog [ --help ] | [ [ --reset ] | [
+ [ --uniqueid="<uniqueid>" ]
+
+ [ --pjsip-debug=<on|off> ] [ --sip-debug=<on|off> ]
+ [ --iax2-debug=<on|off> ]
+
+ [ --agi-debug=<on|off> ] [ --ami-debug=<on|off> ]
+ [ --ari-debug=<on|off> ] [ --cdr-debug=<on|off> ]
+ [ --channel-debug=<on|off> ] [ --rtp-debug=<on|off> ]
+ [ --rtcp-debug=<on|off> ]
+
+ [ --dtmf-debug=<on|off> ] [ --fax-debug=<on|off> ]
+ [ --security-debug=<on|off> ]
+
+ [ --pjsip-history=<on|off> ] [ --sip-history=<on|off> ]
+
+ [ --verbose=<level> ] [ --debug=<level> ]
+ ] ]
+
+DESCRIPTION
+
+ Escalates log and/or debug levels on Asterisk subsystems.
+
+ Options:
+
+ --help
+ Print this help.
+
+ --reset
+ Resets logging to the pre-escalation state.
+
+ --uniqueid="<uniqueid>"
+ Normally DATEFORMAT from ast_debug_tools.conf is used to make
+ the log files unique but you can set the unique id to
+ something else such as the Jira issue. Once any logging
+ is enabled, the uniqueid is stored in cli.conf so any future
+ on/off commands will use the same uniqueid. Use the --reset
+ option to reset it (and everything else).
+
+ --pjsip-debug --sip-debug --iax2-debug --agi-debug --ami-debug
+ --ari-debug --cdr-debug --channel-debug --rtp-debug --rtcp-debug
+ Issues the subsystem appropriate command to turn on
+ or off debugging. These are usually functional debug messages
+ such as packet dumps as opposed to code level messages and usually
+ go to the VERBOSE log channel.
+
+ --dtmf-debug --fax-debug --security-debug
+ These subsystems set up their own log channels so if turned
+ on, log files will be created in \$astlogdir for them.
+
+ --pjsip-history --sip-history
+ The pjsip and sip channels have the ability to output an
+ abbreviated, one-line, packet summary. If enabled, the summaries
+ will be written to \$astlogdir/pjsip_history.\$UNIQUEID and
+ \$astlogdir/sip_history.\$UNIQUEID.
+
+ --verbose-level --debug-level
+ Sets the levels for their respective messages.
+
+NOTES
+
+ The escalator works by creating a set of startup commands in cli.conf
+ that set up logger channels and issue the debug commands. If asterisk
+ is running when $prog is executed, the same commands will be issued
+ to the running instance. The original cli.conf is saved before any
+ changes are made and can be restored by executing '$prog --reset'.
+
+ The log output will be stored in...
+ \$astlogdir/message.\$uniqueid
+ \$astlogdir/debug.\$uniqueid
+ \$astlogdir/dtmf.\$uniqueid
+ \$astlogdir/fax.\$uniqueid
+ \$astlogdir/security.\$uniqueid
+ \$astlogdir/pjsip_history.\$uniqueid
+ \$astlogdir/sip_history.\$uniqueid
+
+EOF
+ exit 1
+}
+
+PJSIP_DEBUG_SPECIFIED=false
+PJSIP_HISTORY_SPECIFIED=false
+SIP_DEBUG_SPECIFIED=false
+SIP_HISTORY_SPECIFIED=false
+IAX2_DEBUG_SPECIFIED=false
+ARI_DEBUG_SPECIFIED=false
+AMI_DEBUG_SPECIFIED=false
+AGI_DEBUG_SPECIFIED=false
+CDR_DEBUG_SPECIFIED=false
+CHANNEL_DEBUG_SPECIFIED=false
+RTP_DEBUG_SPECIFIED=false
+RTCP_DEBUG_SPECIFIED=false
+DTMF_DEBUG_SPECIFIED=false
+FAX_DEBUG_SPECIFIED=false
+SECURITY_DEBUG_SPECIFIED=false
+DEBUG_LEVEL_SPECIFIED=false
+VERBOSE_LEVEL_SPECIFIED=false
+DEBUGS=false
+RESET=false
+
+declare -A DEBUG_COMMANDS=(
+[PJSIP,on]="pjsip set logger on" [PJSIP,off]="pjsip set logger off"
+[SIP,on]="sip set debug on" [SIP,off]="sip set debug off"
+[IAX2,on]="iax2 set debug on" [IAX2,off]="iax2 set debug off"
+[ARI,on]="ari set debug all on" [ARI,off]="ari set debug all off"
+[AMI,on]="manager set debug on" [AMI,off]="manager set debug off"
+[AGI,on]="agi set debug on" [AGI,off]="agi set debug off"
+[CDR,on]="cdr set debug on" [CDR,off]="cdr set debug off"
+[CHANNEL,on]="core set debug channel all" [CHANNEL,off]="core set debug channel all off"
+[RTP,on]="rtp set debug on" [RTP,on]="rtp set debug off"
+[RTCP,on]="rtcp set debug on" [RTCP,off]="rtcp set debug off"
+)
+
+VERBOSE_LEVELS="NOTICE,WARNING,ERROR,VERBOSE"
+DEBUG_LEVELS="DEBUG"
+
+# Read config files from least important to most important
+[ -f /etc/asterisk/ast_debug_tools.conf ] && source /etc/asterisk/ast_debug_tools.conf
+[ -f ~/ast_debug_tools.conf ] && source ~/ast_debug_tools.conf
+[ -f ./ast_debug_tools.conf ] && source ./ast_debug_tools.conf
+
+DATEFORMAT=${DATEFORMAT:-'date +%FT%H-%M-%S%z'}
+UNIQUEID=$($DATEFORMAT)
+UNIQUEID_SPECIFIED=false
+
+for a in "$@" ; do
+ case "$a" in
+ --*-debug=*)
+ subsystem=${a%-debug=*}
+ subsystem=${subsystem#--}
+ flag=${a#*=}
+ if [[ ${flag,,} =~ ^y(es)?|on ]] ; then
+ eval ${subsystem^^}_DEBUG=true
+ else
+ eval ${subsystem^^}_DEBUG=false
+ fi
+ eval ${subsystem^^}_DEBUG_SPECIFIED=true
+ DEBUGS=true
+ ;;
+ --pjsip-history=*)
+ ;&
+ --sip-history=*)
+ subsystem=${a%-history=*}
+ subsystem=${subsystem#--}
+ if [[ ${a#*=} =~ ^[Yy].* ]] ; then
+ eval ${subsystem^^}_HISTORY=true
+ else
+ eval ${subsystem^^}_HISTORY=false
+ fi
+ eval ${subsystem^^}_HISTORY_SPECIFIED=true
+ DEBUGS=true
+ ;;
+ --verbose=*)
+ VERBOSE_LEVEL=${a#*=}
+ VERBOSE_LEVEL_SPECIFIED=true
+ DEBUGS=true
+ ;;
+ --debug=*)
+ DEBUG_LEVEL=${a#*=}
+ DEBUG_LEVEL_SPECIFIED=true
+ DEBUGS=true
+ ;;
+ --reset)
+ RESET=true
+ ;;
+ --uniqueid=*)
+ UNIQUEID=${a#*=}
+ UNIQUEID_SPECIFIED=true
+ DEBUGS=true
+ ;;
+ --help|*)
+ print_help
+ ;;
+ esac
+done
+
+if $DEBUGS && $RESET ; then
+ echo "--reset must be specified by itself"
+ print_help
+fi
+
+if ! $DEBUGS && ! $RESET ; then
+ echo "No options specified."
+ print_help
+fi
+
+ASTERISK_IS_RUNNING=false
+CONFIG_DIR=/etc/asterisk
+LOG_DIR=/var/log/asterisk
+
+if [ "$(pidof asterisk)" != "" ] ; then
+ CONFIG_DIR=`asterisk -rx "core show settings" | sed -n -r -e "s/^\s*Configuration\s+directory:\s+(.*)$/\1/gp"`
+ LOG_DIR=`asterisk -rx "core show settings" | sed -n -r -e "s/^\s*Log\s+directory:\s+(.*)$/\1/gp"`
+ ASTERISK_IS_RUNNING=true
+fi
+CLI_CONF="$CONFIG_DIR/cli.conf"
+
+if [ ! -f "$CLI_CONF" ] ; then
+ echo "The location of cli.conf could not be determined."
+ exit 1
+fi
+
+if $RESET ; then
+ if [ -f "$CLI_CONF.unescalated" ] ; then
+ mv "$CLI_CONF.unescalated" "$CLI_CONF"
+ fi
+ if $ASTERISK_IS_RUNNING ; then
+ (
+ asterisk -rx "core set verbose 0"
+ asterisk -rx "core set debug 0"
+ asterisk -rx "pjsip set logger off"
+ asterisk -rx "pjsip set history off"
+ asterisk -rx "sip set debug off"
+ asterisk -rx "sip set history off"
+ asterisk -rx "iax2 set debug off"
+ asterisk -rx "manager set debug off"
+ asterisk -rx "ari set debug all off"
+ asterisk -rx "agi set debug off"
+ asterisk -rx "rtp set debug off"
+ asterisk -rx "rtcp set debug off"
+ asterisk -rx "cdr set debug off"
+ asterisk -rx "core set debug channel all off"
+ asterisk -rx "logger reload"
+ ) >/dev/null 2>&1 || :
+ fi
+ exit 1
+fi
+
+if ! grep -q "; --START DEBUG_LOGGING-- ;" $CLI_CONF ; then
+ VERBOSE_LOG="$LOG_DIR/message.${UNIQUEID}"
+ DEBUG_LOG="$LOG_DIR/debug.${UNIQUEID}"
+ PJSIP_HISTORY_LOG="$LOG_DIR/pjsip_history.${UNIQUEID}"
+ SIP_HISTORY_LOG="$LOG_DIR/sip_history.${UNIQUEID}"
+ DTMF_LOG="$LOG_DIR/dtmf.${UNIQUEID}"
+ FAX_LOG="$LOG_DIR/fax.${UNIQUEID}"
+ SECURITY_LOG="$LOG_DIR/security.${UNIQUEID}"
+
+ cp "$CLI_CONF" "$CLI_CONF.unescalated"
+
+ sed -i -r -e "s/\[startup_commands\]/[startup_commands_original](!)/g" "$CLI_CONF"
+
+ cat >> "$CLI_CONF" <<-EOF
+ ; --START DEBUG_LOGGING-- ;
+
+ [pjsip_debug](!)
+ pjsip set logger on = yes
+
+ [sip_debug](!)
+ sip set debug on = yes
+
+ [iax2_debug](!)
+ iax2 set debug on = yes
+
+ [ari_debug](!)
+ ari set debug all on = yes
+
+ [ami_debug](!)
+ manager set debug on = yes
+
+ [agi_debug](!)
+ agi set debug on = yes
+
+ [cdr_debug](!)
+ cdr set debug on = yes
+
+ [channel_debug](!)
+ core set debug channel all = yes
+
+ [rtp_debug](!)
+ rtp set debug on = yes
+
+ [rtcp_debug](!)
+ rtcp set debug on = yes
+
+ [dtmf_debug](!)
+ logger add channel $DTMF_LOG DTMF = yes
+
+ [fax_debug](!)
+ logger add channel $FAX_LOG FAX = yes
+
+ [security_debug](!)
+ logger add channel $SECURITY_LOG SECURITY = yes
+
+ [pjsip_history](!)
+ logger add channel $PJSIP_HISTORY_LOG PJSIP_HISTORY = yes
+ pjsip set history on = yes
+
+ [sip_history](!)
+ logger add channel $SIP_HISTORY_LOG SIP_HISTORY = yes
+ sip set history on = yes
+
+ [verbose_level](!)
+ core set verbose 3 = yes
+
+ [debug_level](!)
+ core set debug 3 = yes
+
+ [log_channels](!)
+ logger add channel $VERBOSE_LOG NOTICE,WARNING,ERROR,VERBOSE = yes
+ logger add channel $DEBUG_LOG DEBUG = yes
+
+ [startup_commands](startup_commands_original,log_channels)
+
+ ; --END DEBUG_LOGGING-- ;
+ EOF
+
+else
+ if $UNIQUEID_SPECIFIED ; then
+ echo "Debug logging is already active. Either rerun $prog without --uniqueid or with --reset to start over."
+ exit 1
+ fi
+
+ VERBOSE_LOG=$(sed -n -r -e "s at logger add channel ($LOG_DIR/message\..+)\s+NOTICE.*@\1 at p" "$CLI_CONF")
+ DEBUG_LOG=$(sed -n -r -e "s at logger add channel ($LOG_DIR/debug\..+)\s+DEBUG.*@\1 at p" "$CLI_CONF")
+ PJSIP_HISTORY_LOG=$(sed -n -r -e "s at logger add channel ($LOG_DIR/pjsip_history\..+)\s+PJSIP.*@\1 at p" "$CLI_CONF")
+ SIP_HISTORY_LOG=$(sed -n -r -e "s at logger add channel ($LOG_DIR/sip_history\..+)\s+SIP.*@\1 at p" "$CLI_CONF")
+ DTMF_LOG=$(sed -n -r -e "s at logger add channel ($LOG_DIR/dtmf\..+)\s+DTMF.*@\1 at p" "$CLI_CONF")
+ FAX_LOG=$(sed -n -r -e "s at logger add channel ($LOG_DIR/fax\..+)\s+FAX.*@\1 at p" "$CLI_CONF")
+ SECURITY_LOG=$(sed -n -r -e "s at logger add channel ($LOG_DIR/security\..+)\s+SECURITY.*@\1 at p" "$CLI_CONF")
+fi
+
+for x in PJSIP SIP ARI AMI AGI ARI IAX2 CDR RTP RTCP ; do
+ if eval \$${x}_DEBUG_SPECIFIED ; then
+ if eval \$${x}_DEBUG ; then
+ if $ASTERISK_IS_RUNNING ; then
+ asterisk -rx "${DEBUG_COMMANDS[$x,on]}"
+ fi
+ egrep -q "^\[startup_commands\].*${x,,}_debug.*" "$CLI_CONF" ||
+ sed -i -r -e "/\[startup_commands\]/ s/\((.*)\)/(\1,${x,,}_debug)/g" "$CLI_CONF"
+ else
+ if $ASTERISK_IS_RUNNING ; then
+ asterisk -rx "${DEBUG_COMMANDS[$x,off]}"
+ fi
+ sed -i -r -e "/\[startup_commands\].*${x,,}_debug.*/ s/,${x,,}_debug//g" "$CLI_CONF"
+ fi
+ fi
+done
+
+for x in DTMF FAX SECURITY ; do
+ if eval \$${x}_DEBUG_SPECIFIED ; then
+ if eval \$${x}_DEBUG ; then
+ if $ASTERISK_IS_RUNNING ; then
+ asterisk -rx "$(eval "echo logger add channel \$${x}_LOG ${x}")" >/dev/null 2>&1
+ fi
+ egrep -q "^\[startup_commands\].*${x,,}_debug.*" "$CLI_CONF" ||
+ sed -i -r -e "/\[startup_commands\]/ s/\((.*)\)/(\1,${x,,}_debug)/g" "$CLI_CONF"
+ else
+ if $ASTERISK_IS_RUNNING ; then
+ asterisk -rx "$(eval "echo logger remove channel \$${x}_LOG")"
+ fi
+ sed -i -r -e "/\[startup_commands\].*${x,,}_debug.*/ s/,${x,,}_debug//g" "$CLI_CONF"
+ fi
+ fi
+done
+
+for x in PJSIP SIP ; do
+ if eval \$${x}_HISTORY_SPECIFIED ; then
+ if eval \$${x}_HISTORY ; then
+ if $ASTERISK_IS_RUNNING ; then
+ asterisk -rx "$(eval "echo logger add channel \$${x}_HISTORY_LOG ${x}_HISTORY")"
+ asterisk -rx "${x,,} set history on"
+ fi
+ egrep -q "^\[startup_commands\].*${x,,}_history.*" "$CLI_CONF" ||
+ sed -i -r -e "/\[startup_commands\]/ s/\((.*)\)/(\1,${x,,}_history)/g" "$CLI_CONF"
+ else
+ if $ASTERISK_IS_RUNNING ; then
+ asterisk -rx "$(eval "echo logger remove channel \$${x}_HISTORY_LOG")"
+ asterisk -rx "${x,,} set history off"
+ fi
+ sed -i -r -e "/\[startup_commands\].*${x,,}_history.*/ s/,${x,,}_history//g" "$CLI_CONF"
+ fi
+ fi
+done
+
+for x in VERBOSE DEBUG ; do
+ if eval \$${x}_LEVEL_SPECIFIED ; then
+ if $ASTERISK_IS_RUNNING ; then
+ asterisk -rx "$(eval "echo logger add channel \$${x}_LOG \$${x}_LEVELS")"
+ asterisk -rx "$(eval "echo core set ${x,,} \$${x}_LEVEL")"
+ fi
+ sed -i -r -e "$(eval "echo s/core set ${x,,} .*/core set ${x,,} \$${x}_LEVEL/g")" "$CLI_CONF"
+ egrep -q "^\[startup_commands\].*${x,,}_level.*" "$CLI_CONF" ||
+ sed -i -r -e "/\[startup_commands\]/ s/\((.*)\)/(\1,${x,,}_level)/g" "$CLI_CONF"
+ fi
+done
diff --git a/contrib/scripts/ast_loggrabber b/contrib/scripts/ast_loggrabber
new file mode 100755
index 0000000..2036d54
--- /dev/null
+++ b/contrib/scripts/ast_loggrabber
@@ -0,0 +1,255 @@
+#!/usr/bin/env bash
+# Turn on extended globbing
+shopt -s extglob
+# Bail on any error
+set -e
+
+prog=$(basename $0)
+
+print_help() {
+cat <<EOF
+NAME
+$prog - Gather asterisk log files
+
+SYNOPSIS
+ $prog [ --help ] [ --dateformat="<dateformat>" ]
+ [ --timezone="<timezone>" ] [ --append-logfiles ]
+ [ --tarball-uniqueid="<uniqueid>" ]
+ [ <logfiles> | <pattern> ... ]
+
+DESCRIPTION
+
+ Gathers log files, optionally converts POSIX timestamps
+ to readable format. and creates a tarball.
+
+ Options:
+
+ --help
+ Print this help.
+
+ --dateformat="<dateformat>"
+ A Python strftime format string to be used when converting
+ POSIX timestamps in log files to readable format. If not
+ specified as an argument or in the config file, no conversion
+ is done.
+
+ --timezone="<timezone>"
+ The timezone to use when converting POSIX timestamps to
+ readable format. It can be specified in "<continent>/<city>"
+ format or in abbreviation format such as "CST6CDT". If not
+ specified as an argument or in the config file, the "local"
+ timezone is used.
+
+ --append-logfiles
+ Append any log files specified on the command line to the
+ config file specified ones instead of overriding them.
+
+ --tarball-uniqueid="<uniqueid>"
+ Normally DATEFORMAT is used to make the tarballs unique
+ but you can use your own unique id in the tarball names
+ such as a Jira issue id.
+
+ <logfiles> | <pattern>
+ A list of log files or log file search patterns. Unless
+ --append-logfiles was specified, these entries will override
+ those specified in the config files.
+
+ If no files are specified on the command line the, value of
+ LOGFILES from ast_debug_tools.conf will be used. Failing
+ that, the following patterns will be used:
+ /var/log/asterisk/messages*
+ /var/log/asterisk/queue*
+ /var/log/asterisk/debug*
+ /var/log/asterisk/security*
+
+NOTES
+ Any files output will have ':' characters changed to '-'. This is
+ to facilitate uploading those files to Jira which doesn't like the
+ colons.
+
+FILES
+ /etc/asterisk/ast_debug_tools.conf
+ ~/ast_debug_tools.conf
+ ./ast_debug_tools.conf
+
+ # Readable Local time for the tarball names
+ DATEFORMAT='date +%FT%H-%M-%S%z'
+
+ # A list of log files and/or log file search patterns using the
+ # same syntax as COREDUMPS.
+ #
+ LOGFILES=(/var/log/asterisk/messages* /var/log/asterisk/queue* \\
+ /var/log/asterisk/debug* /var/log/asterisk/security*)
+
+ # $prog converts POSIX timestamps to readable format
+ # using this Python strftime format string. If not specified
+ # or an empty string, no format covnersion is done.
+ LOG_DATEFORMAT="%m/%d %H:%M:%S.%f"
+
+ # The timezone to use when converting POSIX timestamps to
+ # readable format. It can be specified in "<continent>/<city>"
+ # format or in abbreviation format such as "CST6CDT". If not
+ # specified, the "local" timezone is used.
+ # LOG_TIMEZONE=
+
+EOF
+ exit 1
+}
+
+append_logfiles=false
+
+declare -a LOGFILES
+declare -a ARGS_LOGFILES
+
+# Read config files from least important to most important
+[ -f /etc/asterisk/ast_debug_tools.conf ] && source /etc/asterisk/ast_debug_tools.conf
+[ -f ~/ast_debug_tools.conf ] && source ~/ast_debug_tools.conf
+[ -f ./ast_debug_tools.conf ] && source ./ast_debug_tools.conf
+
+if [ ${#LOGFILES[@]} -eq 0 ] ; then
+ LOGFILES+=(/var/log/asterisk/messages* /var/log/asterisk/queue* \
+ /var/log/asterisk/debug* /var/log/asterisk/security*)
+fi
+
+DATEFORMAT=${DATEFORMAT:-'date +%FT%H-%M-%S%z'}
+
+# Use "$@" (with the quotes) so spaces in patterns or
+# file names are preserved.
+# Later on when we have to iterate over LOGFILES, we always
+# use the indexes rather than trying to expand the values of LOGFILES
+# just in case.
+
+for a in "$@" ; do
+ case "$a" in
+ --dateformat=*)
+ LOG_DATEFORMAT=${a#*=}
+ ;;
+ --timezone=*)
+ LOG_TIMEZONE=${a#*=}
+ ;;
+ --append-logfiles)
+ append_logfiles=true
+ ;;
+ --tarball-uniqueid=*)
+ tarball_uniqueid=${a#*=}
+ ;;
+ --help|-*)
+ print_help
+ ;;
+ *)
+ ARGS_LOGFILES+=("$a")
+ # If any files are specified on the command line, ignore those
+ # specified in the config files unless append-logfiles was specified.
+ if ! $append_logfiles ; then
+ LOGFILES=()
+ fi
+ esac
+done
+
+# append logfiles/patterns specified as command line arguments to LOGFILES.
+for i in ${!ARGS_LOGFILES[@]} ; do
+ LOGFILES+=("${ARGS_LOGFILES[$i]}")
+done
+
+# At this point, all glob entries that match files should be expanded.
+# Any entries that don't exist are probably globs that didn't match anything
+# and need to be pruned.
+
+for i in ${!LOGFILES[@]} ; do
+ if [ ! -f "${LOGFILES[$i]}" ] ; then
+ unset LOGFILES[$i]
+ continue
+ fi
+done
+
+# Sort and weed out any dups
+IFS=$'\x0a'
+readarray -t LOGFILES < <(echo -n "${LOGFILES[*]}" | sort -u )
+unset IFS
+
+if [ "${#LOGFILES[@]}" -eq 0 ] ; then
+ echo "No log files found"
+ print_help
+fi
+
+# Timestamp to use for output files
+df=${tarball_uniqueid:-$(${DATEFORMAT})}
+
+# Extract the Python timestamp conver script from the end of this
+# script and save it to /tmp/.ast_tsconvert.py
+
+ss=`egrep -n "^#@@@SCRIPTSTART@@@" $0 |cut -f1 -d:`
+tail -n +${ss} $0 >/tmp/.ast_tsconvert.py
+
+tmpdir=$(mktemp -d)
+if [ -z "$tmpdir" ] ; then
+ echo "${prog}: Unable to create temporary directory."
+ exit 1
+fi
+trap "rm -rf $tmpdir" EXIT
+tardir=asterisk-${df}.logfiles
+
+# Now iterate over the logfiles
+for i in ${!LOGFILES[@]} ; do
+ lf=${LOGFILES[$i]}
+ destdir="$tmpdir/$tardir/$(dirname $lf)"
+ destfile="$tmpdir/$tardir/$lf"
+ mkdir -p "$destdir" 2>/dev/null || :
+ if [ -n "$LOG_DATEFORMAT" ] ; then
+ echo "Converting $lf"
+ cat "$lf" | python /tmp/.ast_tsconvert.py --format="$LOG_DATEFORMAT" --timezone="$LOG_TIMEZONE" > "${destfile}"
+ else
+ echo "Copying $lf"
+ cp "$lf" "${destfile}"
+ fi
+done
+
+echo "Creating /tmp/$tardir.tar.gz"
+tar -czvf /tmp/$tardir.tar.gz -C $tmpdir $tardir 2>/dev/null
+
+exit
+
+# Be careful editng the inline scripts.
+# They're space-indented.
+
+# We need the python bit because lock_infos isn't
+# a valid symbol in asterisk unless DEBUG_THREADS was
+# used during the compile. Also, interrupt and continue
+# are only valid for a running program.
+
+#@@@SCRIPTSTART@@@
+import argparse
+import datetime as dt
+import dateutil.tz as tz
+import re
+import sys
+import time
+
+parser = argparse.ArgumentParser(description="Make POSIX timestamps readable")
+parser.add_argument('--format', action='store', required=True)
+parser.add_argument('--timezone', action='store', required=False)
+args=parser.parse_args()
+
+# We only convert timestamps that are at the beginning of a line
+# or are preceeded by a whilespace character or a '['
+rets = re.compile(r'(^|(?<=\s|\[))\d+(\.\d+)?', flags=re.M)
+if args.timezone and len(args.timezone) > 0:
+ tzf = tz.tzfile('/usr/share/zoneinfo/' + args.timezone)
+else:
+ tzf = tz.tzfile('/etc/localtime')
+
+now = time.time()
+a_year_ago = now - (86400.0 * 365)
+
+def convert(match):
+ ts = float(match.group(0))
+ if ts <= now and ts > a_year_ago and len(args.format) > 0:
+ return dt.datetime.fromtimestamp(ts, tzf).strftime(args.format)
+ else:
+ return match.group(0)
+
+while 1:
+ line = sys.stdin.readline()
+ if not line:
+ break
+ print(rets.sub(convert, line))
diff --git a/contrib/scripts/autosupport b/contrib/scripts/autosupport
index 3e0213a..948f628 100755
--- a/contrib/scripts/autosupport
+++ b/contrib/scripts/autosupport
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Autosupport Version 2.1.0
+# Autosupport Version 2.1.3
# Collect support information
#
# Copyright (C) 2005-2016, Digium, Inc.
@@ -187,7 +187,7 @@ echo >> $OUTPUT;
# Add check to see if asterisk is running.
if [ -e /var/run/asterisk.ctl ] || [ -e /var/run/asterisk/asterisk.ctl ]; then
for command in "core show version" "pri show version" "dahdi show version" \
- "pjsip show version" "pjsip show buildopts" \
+ "pjsip show version" "pjsip show buildopts" "pjproject show buildopts" \
"core show translation" \
"core show uptime" "core show settings" "core show sysinfo" "core show channels" \
"pri show spans" "dahdi show status" "dahdi show channels" "dahdi show channel 1" \
diff --git a/funcs/func_strings.c b/funcs/func_strings.c
index efa4bfd..c76bddc 100644
--- a/funcs/func_strings.c
+++ b/funcs/func_strings.c
@@ -619,7 +619,6 @@ static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, ch
}
ast_str_substitute_variables(&orig_list, 0, chan, varsubst);
if (!ast_str_strlen(orig_list)) {
- ast_log(LOG_ERROR, "List variable '%s' not found\n", args.listname);
if (chan) {
ast_channel_unlock(chan);
}
diff --git a/include/asterisk/abstract_jb.h b/include/asterisk/abstract_jb.h
index 8a5e3d2..173b22a 100644
--- a/include/asterisk/abstract_jb.h
+++ b/include/asterisk/abstract_jb.h
@@ -109,6 +109,8 @@ typedef int (*jb_remove_impl)(void *jb, struct ast_frame **fout);
typedef void (*jb_force_resynch_impl)(void *jb);
/*! \brief Empty and reset jb */
typedef void (*jb_empty_and_reset_impl)(void *jb);
+/*! \brief Check if late */
+typedef int (*jb_is_late_impl)(void *jb, long ts);
/*!
@@ -127,6 +129,7 @@ struct ast_jb_impl
jb_remove_impl remove;
jb_force_resynch_impl force_resync;
jb_empty_and_reset_impl empty_and_reset;
+ jb_is_late_impl is_late;
};
/*!
diff --git a/include/asterisk/ari.h b/include/asterisk/ari.h
index 1c54a69..cad9b32 100644
--- a/include/asterisk/ari.h
+++ b/include/asterisk/ari.h
@@ -59,7 +59,8 @@ struct ast_ari_response;
typedef void (*stasis_rest_callback)(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response);
+ struct ast_variable *headers, struct ast_json *body,
+ struct ast_ari_response *response);
/*!
* \brief Handler for a single RESTful path segment.
@@ -134,7 +135,7 @@ int ast_ari_remove_handler(struct stasis_rest_handlers *handler);
void ast_ari_invoke(struct ast_tcptls_session_instance *ser,
const char *uri, enum ast_http_method method,
struct ast_variable *get_params, struct ast_variable *headers,
- struct ast_ari_response *response);
+ struct ast_json *body, struct ast_ari_response *response);
/*!
* \internal
@@ -189,6 +190,25 @@ int ast_ari_websocket_session_write(struct ast_ari_websocket_session *session,
struct ast_json *message);
/*!
+ * \brief Get the Session ID for an ARI WebSocket.
+ *
+ * \param session Session to query.
+ * \return Session ID.
+ * \return \c NULL on error.
+ */
+const char *ast_ari_websocket_session_id(
+ const struct ast_ari_websocket_session *session);
+
+/*!
+ * \brief Get the remote address from an ARI WebSocket.
+ *
+ * \param session Session to write to.
+ * \return ast_sockaddr (does not have to be freed)
+ */
+struct ast_sockaddr *ast_ari_websocket_session_get_remote_addr(
+ struct ast_ari_websocket_session *session);
+
+/*!
* \brief The stock message to return when out of memory.
*
* The refcount is NOT bumped on this object, so ast_json_ref() if you want to
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index c9e537f..c237a00 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -966,16 +966,6 @@ enum {
* The channel is executing a subroutine or macro
*/
AST_FLAG_SUBROUTINE_EXEC = (1 << 27),
- /*!
- * The channel is currently in an operation where
- * frames should be deferred.
- */
- AST_FLAG_DEFER_FRAMES = (1 << 28),
- /*!
- * The channel is currently deferring hangup frames
- * in addition to other frame types.
- */
- AST_FLAG_DEFER_HANGUP_FRAMES = (1 << 29),
};
/*! \brief ast_bridge_config flags */
@@ -2013,6 +2003,21 @@ int ast_prod(struct ast_channel *chan);
int ast_set_read_format_path(struct ast_channel *chan, struct ast_format *raw_format, struct ast_format *core_format);
/*!
+ * \brief Set specific write path on channel.
+ * \since 13.13.0
+ *
+ * \param chan Channel to setup write path.
+ * \param core_format What the core wants to write.
+ * \param raw_format Raw write format.
+ *
+ * \pre chan is locked
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int ast_set_write_format_path(struct ast_channel *chan, struct ast_format *core_format, struct ast_format *raw_format);
+
+/*!
* \brief Sets read format on channel chan from capabilities
* Set read format for channel to whichever component of "format" is best.
* \param chan channel to change
@@ -4224,6 +4229,7 @@ typedef enum {
} ast_alert_status_t;
int ast_channel_alert_write(struct ast_channel *chan);
int ast_channel_alert_writable(struct ast_channel *chan);
+ast_alert_status_t ast_channel_internal_alert_flush(struct ast_channel *chan);
ast_alert_status_t ast_channel_internal_alert_read(struct ast_channel *chan);
int ast_channel_internal_alert_readable(struct ast_channel *chan);
void ast_channel_internal_alertpipe_clear(struct ast_channel *chan);
@@ -4692,42 +4698,20 @@ enum ast_channel_error {
enum ast_channel_error ast_channel_errno(void);
/*!
- * \brief Retrieve the deferred read queue.
- */
-struct ast_readq_list *ast_channel_deferred_readq(struct ast_channel *chan);
-
-/*!
- * \brief Start deferring deferrable frames on this channel
- *
- * Sometimes, a channel gets entered into a mode where a "main" application
- * is tasked with servicing frames on the channel, but that application does
- * not need to act on those frames. However, it would be imprudent to simply
- * drop important frames. This function can be called so that important frames
- * will be deferred, rather than placed in the channel frame queue as normal.
- *
- * Hangups are an interesting frame type. Hangups will always be detectable by
- * a reader when a channel is deferring frames. If the defer_hangups parameter
- * is non-zero, then the hangup frame will also be duplicated and deferred, so
- * that the next reader of the channel will get the hangup frame, too.
- *
- * \pre chan MUST be locked before calling
+ * \brief Am I currently running an intercept dialplan routine.
+ * \since 13.14.0
*
- * \param chan The channel on which frames should be deferred
- * \param defer_hangups Defer hangups in addition to other deferrable frames
- */
-void ast_channel_start_defer_frames(struct ast_channel *chan, int defer_hangups);
-
-/*!
- * \brief Stop deferring deferrable frames on this channel
- *
- * When it is time to stop deferring frames on the channel, all deferred frames
- * will be queued onto the channel's read queue so that the next servicer of
- * the channel can handle those frames as necessary.
- *
- * \pre chan MUST be locked before calling
+ * \details
+ * A dialplan intercept routine is equivalent to an interrupt
+ * routine. As such, the routine must be done quickly and you
+ * do not have access to the media stream. These restrictions
+ * are necessary because the media stream is the responsibility
+ * of some other code and interfering with or delaying that
+ * processing is bad.
*
- * \param chan The channel on which to stop deferring frames.
+ * \retval 0 Not in an intercept routine.
+ * \retval 1 In an intercept routine.
*/
-void ast_channel_stop_defer_frames(struct ast_channel *chan);
+int ast_channel_get_intercept_mode(void);
#endif /* _ASTERISK_CHANNEL_H */
diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h
index 20f40f8..108dcaf 100644
--- a/include/asterisk/frame.h
+++ b/include/asterisk/frame.h
@@ -133,6 +133,8 @@ enum ast_frame_type {
enum {
/*! This frame contains valid timing information */
AST_FRFLAG_HAS_TIMING_INFO = (1 << 0),
+ /*! This frame has been requeued */
+ AST_FRFLAG_REQUEUED = (1 << 1),
};
struct ast_frame_subclass {
diff --git a/include/asterisk/mod_format.h b/include/asterisk/mod_format.h
index 7f17741..d76be5e 100644
--- a/include/asterisk/mod_format.h
+++ b/include/asterisk/mod_format.h
@@ -114,7 +114,11 @@ struct ast_filestream {
int lasttimeout;
struct ast_channel *owner;
FILE *f;
- struct ast_frame fr; /*!< frame produced by read, typically */
+ /*!
+ * \brief frame produced by read, typically
+ * \note This frame holds a fr.subclass.format ref.
+ */
+ struct ast_frame fr;
char *buf; /*!< buffer pointed to by ast_frame; */
void *_private; /*!< pointer to private buffer */
const char *orig_chan_name;
diff --git a/include/asterisk/options.h b/include/asterisk/options.h
index 21bd7a7..950764e 100644
--- a/include/asterisk/options.h
+++ b/include/asterisk/options.h
@@ -132,6 +132,47 @@ enum ast_option_flags {
#define ast_opt_lock_confdir ast_test_flag(&ast_options, AST_OPT_FLAG_LOCK_CONFIG_DIR)
#define ast_opt_generic_plc ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC)
+/*! Maximum log level defined by PJPROJECT. */
+#define MAX_PJ_LOG_MAX_LEVEL 6
+/*!
+ * Normal PJPROJECT active log level used by Asterisk.
+ *
+ * These levels are usually mapped to Error and
+ * Warning Asterisk log levels which shouldn't
+ * normally be suppressed.
+ */
+#define DEFAULT_PJ_LOG_MAX_LEVEL 2
+
+/*!
+ * \brief Get maximum log level pjproject was compiled with.
+ *
+ * \details
+ * Determine the maximum log level the pjproject we are running
+ * with supports.
+ *
+ * When pjproject is initially loaded the default log level in
+ * effect is the maximum log level the library was compiled to
+ * generate. We must save this value off somewhere before we
+ * change it to what we want to use as the default level.
+ *
+ * \note This must be done before calling pj_init() so the level
+ * we want to use as the default level is in effect while the
+ * library initializes.
+ */
+#define AST_PJPROJECT_INIT_LOG_LEVEL() \
+ do { \
+ if (ast_pjproject_max_log_level < 0) { \
+ ast_pjproject_max_log_level = pj_log_get_level(); \
+ } \
+ pj_log_set_level(ast_option_pjproject_log_level); \
+ } while (0)
+
+/*! Current linked pjproject maximum logging level */
+extern int ast_pjproject_max_log_level;
+
+/*! Current pjproject logging level */
+extern int ast_option_pjproject_log_level;
+
extern struct ast_flags ast_options;
extern int option_verbose;
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index 4ad6607..c97e4b5 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -2321,6 +2321,16 @@ int ast_sip_format_endpoint_ami(struct ast_sip_endpoint *endpoint,
struct ast_sip_ami *ami, int *count);
/*!
+ * \brief Formats the contact and sends over AMI.
+ *
+ * \param obj a pointer an ast_sip_contact_wrapper structure
+ * \param arg a pointer to an ast_sip_ami structure
+ * \param flags ignored
+ * \retval 0 Success, otherwise non-zero on error
+ */
+int ast_sip_format_contact_ami(void *obj, void *arg, int flags);
+
+/*!
* \brief Format auth details for AMI.
*
* \param auths an auth array
diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h
index 24af056..c4a5b6b 100644
--- a/include/asterisk/rtp_engine.h
+++ b/include/asterisk/rtp_engine.h
@@ -369,7 +369,7 @@ struct ast_rtp_instance_stats {
};
#define AST_RTP_STAT_SET(current_stat, combined, placement, value) \
-if (stat == current_stat || stat == AST_RTP_INSTANCE_STAT_ALL || (combined >= 0 && combined == current_stat)) { \
+if (stat == current_stat || stat == AST_RTP_INSTANCE_STAT_ALL || (combined >= 0 && combined == stat)) { \
placement = value; \
if (stat == current_stat) { \
return 0; \
@@ -377,7 +377,7 @@ return 0; \
}
#define AST_RTP_STAT_STRCPY(current_stat, combined, placement, value) \
-if (stat == current_stat || stat == AST_RTP_INSTANCE_STAT_ALL || (combined >= 0 && combined == current_stat)) { \
+if (stat == current_stat || stat == AST_RTP_INSTANCE_STAT_ALL || (combined >= 0 && combined == stat)) { \
ast_copy_string(placement, value, sizeof(placement)); \
if (stat == current_stat) { \
return 0; \
diff --git a/include/asterisk/stasis_app.h b/include/asterisk/stasis_app.h
index 53ce116..6f9897c 100644
--- a/include/asterisk/stasis_app.h
+++ b/include/asterisk/stasis_app.h
@@ -891,6 +891,55 @@ int stasis_app_channel_unreal_set_internal(struct ast_channel *chan);
*/
int stasis_app_channel_set_internal(struct ast_channel *chan);
+/*!
+ * \brief Enable/disable request/response and event logging on an application
+ *
+ * \param app The app to debug
+ * \param debug If non-zero, enable debugging. If zero, disable.
+ */
+void stasis_app_set_debug(struct stasis_app *app, int debug);
+
+/*!
+ * \brief Enable/disable request/response and event logging on an application
+ *
+ * \param app_name The app name to debug
+ * \param debug If non-zero, enable debugging. If zero, disable.
+ */
+void stasis_app_set_debug_by_name(const char *app_name, int debug);
+
+/*!
+ * \brief Get debug status of an application
+ *
+ * \param app The app to check
+ * \return The debug flag for the app || the global debug flag
+ */
+int stasis_app_get_debug(struct stasis_app *app);
+
+/*!
+ * \brief Get debug status of an application
+ *
+ * \param app_name The app_name to check
+ * \return The debug flag for the app || the global debug flag
+ */
+int stasis_app_get_debug_by_name(const char *app_name);
+
+/*!
+ * \brief Enable/disable request/response and event logging on all applications
+ *
+ * \param debug If non-zero, enable debugging. If zero, disable.
+ */
+void stasis_app_set_global_debug(int debug);
+
+struct ast_cli_args;
+
+/*!
+ * \brief Dump properties of a \c stasis_app to the CLI
+ *
+ * \param app The application
+ * \param a The CLI arguments
+ */
+void stasis_app_to_cli(const struct stasis_app *app, struct ast_cli_args *a);
+
/*! @} */
#endif /* _ASTERISK_STASIS_APP_H */
diff --git a/include/asterisk/tcptls.h b/include/asterisk/tcptls.h
index 3c5f450..d19ec52 100644
--- a/include/asterisk/tcptls.h
+++ b/include/asterisk/tcptls.h
@@ -107,6 +107,9 @@ struct ast_tls_config {
char *capath;
struct ast_flags flags;
SSL_CTX *ssl_ctx;
+ char certhash[41];
+ char pvthash[41];
+ char cahash[41];
};
/*! \page AstTlsOverview TLS Implementation Overview
@@ -151,6 +154,7 @@ struct ast_tcptls_session_args {
void (*periodic_fn)(void *);/*!< something we may want to run before after select on the accept socket */
void *(*worker_fn)(void *); /*!< the function in charge of doing the actual work */
const char *name;
+ struct ast_tls_config *old_tls_cfg; /*!< copy of the SSL configuration to determine whether changes have been made */
};
struct ast_tcptls_stream;
diff --git a/include/asterisk/translate.h b/include/asterisk/translate.h
index e2a4f30..ce46cd0 100644
--- a/include/asterisk/translate.h
+++ b/include/asterisk/translate.h
@@ -208,7 +208,7 @@ struct ast_translator {
*/
struct ast_trans_pvt {
struct ast_translator *t;
- struct ast_frame f; /*!< used in frameout */
+ struct ast_frame f; /*!< used in frameout. This frame holds a f.subclass.format ref. */
int samples; /*!< samples available in outbuf */
/*! \brief actual space used in outbuf */
int datalen;
diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h
index a504a5d..4a5dbf2 100644
--- a/include/asterisk/utils.h
+++ b/include/asterisk/utils.h
@@ -1127,4 +1127,13 @@ int ast_file_is_readable(const char *filename);
*/
int ast_compare_versions(const char *version1, const char *version2);
+/*
+ * \brief Test that an OS supports IPv6 Networking.
+ * \since 13.14.0
+ *
+ * \return True (non-zero) if the IPv6 supported.
+ * \return False (zero) if the OS doesn't support IPv6.
+ */
+int ast_check_ipv6(void);
+
#endif /* _ASTERISK_UTILS_H */
diff --git a/include/jitterbuf.h b/include/jitterbuf.h
index 6da11a6..32579fc 100644
--- a/include/jitterbuf.h
+++ b/include/jitterbuf.h
@@ -166,6 +166,9 @@ enum jb_return_code jb_setconf(jitterbuf *jb, jb_conf *conf);
typedef void __attribute__((format(printf, 1, 2))) (*jb_output_function_t)(const char *fmt, ...);
void jb_setoutput(jb_output_function_t err, jb_output_function_t warn, jb_output_function_t dbg);
+/*! \brief Checks if the given time stamp is late */
+int jb_is_late(jitterbuf *jb, long ts);
+
#ifdef __cplusplus
}
#endif
diff --git a/main/Makefile b/main/Makefile
index 37b9446..a51b48b 100644
--- a/main/Makefile
+++ b/main/Makefile
@@ -205,7 +205,7 @@ ASTSSL_LDLIBS=-L. -lasteriskssl
ifeq ($(findstring darwin,$(OSARCH)),) # not Darwin
ASTSSL_LIB:=libasteriskssl.so
-$(ASTSSL_LIB).$(ASTSSL_SO_VERSION): _ASTLDFLAGS+=-Wl,-soname=$(ASTSSL_LIB)
+$(ASTSSL_LIB).$(ASTSSL_SO_VERSION): _ASTLDFLAGS+=-Wl,-soname=$(ASTSSL_LIB).$(ASTSSL_SO_VERSION)
$(ASTSSL_LIB).$(ASTSSL_SO_VERSION): _ASTCFLAGS+=-fPIC -DAST_MODULE=\"asteriskssl\"
$(ASTSSL_LIB).$(ASTSSL_SO_VERSION): LIBS+=$(ASTSSL_LIBS)
ifeq ($(GNU_LD),1)
@@ -285,7 +285,7 @@ ifeq ($(GNU_LD),1)
$(CMD_PREFIX) echo -e "local:\n*;\n};" >> libasteriskpj.exports
endif
-$(ASTPJ_LIB).$(ASTPJ_SO_VERSION): _ASTLDFLAGS+=-Wl,-soname=$(ASTPJ_LIB) $(PJ_LDFLAGS)
+$(ASTPJ_LIB).$(ASTPJ_SO_VERSION): _ASTLDFLAGS+=-Wl,-soname=$(ASTPJ_LIB).$(ASTPJ_SO_VERSION) $(PJ_LDFLAGS)
$(ASTPJ_LIB).$(ASTPJ_SO_VERSION): _ASTCFLAGS+=-fPIC -DAST_MODULE=\"asteriskpj\" $(PJ_CFLAGS)
$(ASTPJ_LIB).$(ASTPJ_SO_VERSION): LIBS+=$(PJPROJECT_LDLIBS) -lssl -lcrypto -luuid -lm -lpthread $(RT_LIB)
ifeq ($(GNU_LD),1)
@@ -363,10 +363,14 @@ binuninstall:
rm -f "$(DESTDIR)$(ASTSBINDIR)/$(MAIN_TGT)"
rm -f "$(DESTDIR)$(ASTSBINDIR)/rasterisk"
ifneq ($(ASTSSL_LIB).$(ASTSSL_SO_VERSION),.)
- rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTSSL_LIB).$(ASTSSL_SO_VERSION)"
+# ASTSSL_SO_VERSION may not exist on Darwin
+ rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTSSL_LIB).$(ASTSSL_SO_VERSION)" || :
+ rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTSSL_LIB)"
endif
ifneq ($(ASTPJ_LIB).$(ASTPJ_SO_VERSION),.)
- rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTPJ_LIB).$(ASTPJ_SO_VERSION)"
+# ASTSSL_SO_VERSION may not exist on Darwin
+ rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTPJ_LIB).$(ASTPJ_SO_VERSION)" || :
+ rm -f "$(DESTDIR)$(ASTLIBDIR)/$(ASTPJ_LIB)"
endif
ifneq ($(LDCONFIG),)
$(LDCONFIG) $(LDCONFIG_FLAGS) "$(DESTDIR)$(ASTLIBDIR)/"
diff --git a/main/abstract_jb.c b/main/abstract_jb.c
index b629fe8..1c9eb51 100644
--- a/main/abstract_jb.c
+++ b/main/abstract_jb.c
@@ -67,6 +67,7 @@ static long jb_next_fixed(void *jb);
static int jb_remove_fixed(void *jb, struct ast_frame **fout);
static void jb_force_resynch_fixed(void *jb);
static void jb_empty_and_reset_fixed(void *jb);
+static int jb_is_late_fixed(void *jb, long ts);
/* adaptive */
static void * jb_create_adaptive(struct ast_jb_conf *general_config);
static void jb_destroy_adaptive(void *jb);
@@ -77,6 +78,7 @@ static long jb_next_adaptive(void *jb);
static int jb_remove_adaptive(void *jb, struct ast_frame **fout);
static void jb_force_resynch_adaptive(void *jb);
static void jb_empty_and_reset_adaptive(void *jb);
+static int jb_is_late_adaptive(void *jb, long ts);
/* Available jb implementations */
static const struct ast_jb_impl avail_impl[] = {
@@ -92,6 +94,7 @@ static const struct ast_jb_impl avail_impl[] = {
.remove = jb_remove_fixed,
.force_resync = jb_force_resynch_fixed,
.empty_and_reset = jb_empty_and_reset_fixed,
+ .is_late = jb_is_late_fixed,
},
{
.name = "adaptive",
@@ -105,6 +108,7 @@ static const struct ast_jb_impl avail_impl[] = {
.remove = jb_remove_adaptive,
.force_resync = jb_force_resynch_adaptive,
.empty_and_reset = jb_empty_and_reset_adaptive,
+ .is_late = jb_is_late_adaptive,
}
};
@@ -706,6 +710,11 @@ static void jb_empty_and_reset_fixed(void *jb)
}
}
+static int jb_is_late_fixed(void *jb, long ts)
+{
+ return fixed_jb_is_late(jb, ts);
+}
+
/* adaptive */
static void *jb_create_adaptive(struct ast_jb_conf *general_config)
@@ -812,6 +821,11 @@ const struct ast_jb_impl *ast_jb_get_impl(enum ast_jb_type type)
return NULL;
}
+static int jb_is_late_adaptive(void *jb, long ts)
+{
+ return jb_is_late(jb, ts);
+}
+
#define DEFAULT_TIMER_INTERVAL 20
#define DEFAULT_SIZE 200
#define DEFAULT_TARGET_EXTRA 40
@@ -895,7 +909,22 @@ static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_fram
}
}
- if (!frame) {
+ /*
+ * If the frame has been requeued (for instance when the translate core returns
+ * more than one frame) then if the frame is late we want to immediately return
+ * it. Otherwise attempt to insert it into the jitterbuffer.
+ *
+ * If the frame is requeued and late then in all likely hood it's a frame that
+ * that was previously retrieved from the jitterbuffer, passed to the translate
+ * core, and then put back into the channel read queue. Even if it had not been
+ * in the jitterbuffer prior to now it needs to be the next frame "out".
+ *
+ * However late arriving frames that have not been requeued (i.e. regular frames)
+ * need to be passed to the jitterbuffer so they can be appropriately dropped. As
+ * well any requeued frames that are not late should be put into the jitterbuffer.
+ */
+ if (!frame || (ast_test_flag(frame, AST_FRFLAG_REQUEUED) &&
+ framedata->jb_impl->is_late(framedata->jb_obj, frame->ts))) {
return frame;
}
diff --git a/main/acl.c b/main/acl.c
index 87776b3..9820e8b 100644
--- a/main/acl.c
+++ b/main/acl.c
@@ -914,40 +914,48 @@ int ast_get_ip(struct ast_sockaddr *addr, const char *hostname)
int ast_ouraddrfor(const struct ast_sockaddr *them, struct ast_sockaddr *us)
{
+ /*
+ * We must create the errno string before creating the address
+ * string because it could wipe out errno on the error return
+ * paths.
+ */
+ const char *sock_err;
int port;
int s;
+ /* Preserve our original address port */
port = ast_sockaddr_port(us);
- if ((s = socket(ast_sockaddr_is_ipv6(them) ? AF_INET6 : AF_INET,
- SOCK_DGRAM, 0)) < 0) {
- ast_log(LOG_ERROR, "Cannot create socket\n");
+ s = socket(ast_sockaddr_is_ipv6(them) ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ sock_err = ast_strdupa(strerror(errno));
+ ast_log(LOG_ERROR, "Cannot create socket to %s: %s\n",
+ ast_sockaddr_stringify_addr(them), sock_err);
return -1;
}
if (ast_connect(s, them)) {
- ast_log(LOG_WARNING, "Cannot connect\n");
+ sock_err = ast_strdupa(strerror(errno));
+ ast_log(LOG_WARNING, "Cannot connect to %s: %s\n",
+ ast_sockaddr_stringify_addr(them), sock_err);
close(s);
return -1;
}
if (ast_getsockname(s, us)) {
-
- ast_log(LOG_WARNING, "Cannot get socket name\n");
+ sock_err = ast_strdupa(strerror(errno));
+ ast_log(LOG_WARNING, "Cannot get socket name for connection to %s: %s\n",
+ ast_sockaddr_stringify_addr(them), sock_err);
close(s);
return -1;
}
close(s);
- {
- const char *them_addr = ast_strdupa(ast_sockaddr_stringify_addr(them));
- const char *us_addr = ast_strdupa(ast_sockaddr_stringify_addr(us));
-
- ast_debug(3, "For destination '%s', our source address is '%s'.\n",
- them_addr, us_addr);
- }
-
ast_sockaddr_set_port(us, port);
+ ast_debug(3, "For destination '%s', our source address is '%s'.\n",
+ ast_strdupa(ast_sockaddr_stringify_addr(them)),
+ ast_strdupa(ast_sockaddr_stringify_addr(us)));
+
return 0;
}
diff --git a/main/app.c b/main/app.c
index a89e5b0..ee7cef2 100644
--- a/main/app.c
+++ b/main/app.c
@@ -1073,6 +1073,7 @@ static int control_streamfile(struct ast_channel *chan,
int res;
long pause_restart_point = 0;
long offset = 0;
+ struct ast_silence_generator *silgen = NULL;
if (!file) {
return -1;
@@ -1161,6 +1162,10 @@ static int control_streamfile(struct ast_channel *chan,
if ((suspend && strchr(suspend, res)) || res == AST_CONTROL_STREAM_SUSPEND) {
pause_restart_point = ast_tellstream(ast_channel_stream(chan));
+
+ if (ast_opt_transmit_silence) {
+ silgen = ast_channel_start_silence_generator(chan);
+ }
ast_test_suite_event_notify("PLAYBACK","Channel: %s\r\n"
"Control: %s\r\n",
ast_channel_name(chan),
@@ -1174,6 +1179,11 @@ static int control_streamfile(struct ast_channel *chan,
break;
}
}
+ if (silgen) {
+ ast_channel_stop_silence_generator(chan, silgen);
+ silgen = NULL;
+ }
+
if ((suspend && (res == *suspend)) || res == AST_CONTROL_STREAM_SUSPEND) {
res = 0;
ast_test_suite_event_notify("PLAYBACK","Channel: %s\r\n"
@@ -1412,22 +1422,20 @@ static struct ast_frame *make_silence(const struct ast_frame *orig)
size_t size;
size_t datalen;
size_t samples = 0;
- struct ast_frame *next;
if (!orig) {
return NULL;
}
+ do {
+ if (ast_format_cmp(orig->subclass.format, ast_format_slin) == AST_FORMAT_CMP_NOT_EQUAL) {
+ ast_log(LOG_WARNING, "Attempting to silence non-slin frame\n");
+ return NULL;
+ }
- if (ast_format_cmp(orig->subclass.format, ast_format_slin) == AST_FORMAT_CMP_NOT_EQUAL) {
- ast_log(LOG_WARNING, "Attempting to silence non-slin frame\n");
- return NULL;
- }
-
- for (next = AST_LIST_NEXT(orig, frame_list);
- orig;
- orig = next, next = orig ? AST_LIST_NEXT(orig, frame_list) : NULL) {
samples += orig->samples;
- }
+
+ orig = AST_LIST_NEXT(orig, frame_list);
+ } while (orig);
ast_verb(4, "Silencing %zu samples\n", samples);
@@ -1445,7 +1453,7 @@ static struct ast_frame *make_silence(const struct ast_frame *orig)
silence->samples = samples;
silence->datalen = datalen;
- silence->subclass.format = ast_format_slin;
+ silence->subclass.format = ao2_bump(ast_format_slin);
return silence;
}
@@ -1651,14 +1659,13 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
/* It's all good */
res = 0;
} else {
- RAII_VAR(struct ast_frame *, silence, NULL, ast_frame_dtor);
+ struct ast_frame *silence = NULL;
struct ast_frame *orig = f;
if (muted) {
silence = make_silence(orig);
if (!silence) {
- ast_log(LOG_WARNING,
- "Error creating silence\n");
+ ast_log(LOG_WARNING, "Error creating silence\n");
break;
}
f = silence;
@@ -1669,6 +1676,7 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
}
res = ast_writestream(others[x], f);
}
+ ast_frame_dtor(silence);
f = orig;
}
diff --git a/main/asterisk.c b/main/asterisk.c
index fa91993..994dfbe 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -325,6 +325,8 @@ int ast_verb_sys_level;
int option_verbose; /*!< Verbosity level */
int option_debug; /*!< Debug level */
+int ast_pjproject_max_log_level = -1;/* Default to -1 to know if we have read the level from pjproject yet. */
+int ast_option_pjproject_log_level;
double ast_option_maxload; /*!< Max load avg on system */
int ast_option_maxcalls; /*!< Max number of active calls */
int ast_option_maxfiles; /*!< Max number of open file handles (files, sockets) */
@@ -1799,7 +1801,6 @@ static void _urg_handler(int num)
static struct sigaction urg_handler = {
.sa_handler = _urg_handler,
- .sa_flags = SA_RESTART,
};
static void _hup_handler(int num)
@@ -3892,6 +3893,37 @@ static void ast_readconfig(void)
ast_config_destroy(cfg);
}
+static void read_pjproject_startup_options(void)
+{
+ struct ast_config *cfg;
+ struct ast_variable *v;
+ struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE | CONFIG_FLAG_NOREALTIME };
+
+ ast_option_pjproject_log_level = DEFAULT_PJ_LOG_MAX_LEVEL;
+
+ cfg = ast_config_load2("pjproject.conf", "" /* core, can't reload */, config_flags);
+ if (!cfg
+ || cfg == CONFIG_STATUS_FILEUNCHANGED
+ || cfg == CONFIG_STATUS_FILEINVALID) {
+ /* We'll have to use defaults */
+ return;
+ }
+
+ for (v = ast_variable_browse(cfg, "startup"); v; v = v->next) {
+ if (!strcasecmp(v->name, "log_level")) {
+ if (sscanf(v->value, "%30d", &ast_option_pjproject_log_level) != 1) {
+ ast_option_pjproject_log_level = DEFAULT_PJ_LOG_MAX_LEVEL;
+ } else if (ast_option_pjproject_log_level < 0) {
+ ast_option_pjproject_log_level = 0;
+ } else if (MAX_PJ_LOG_MAX_LEVEL < ast_option_pjproject_log_level) {
+ ast_option_pjproject_log_level = MAX_PJ_LOG_MAX_LEVEL;
+ }
+ }
+ }
+
+ ast_config_destroy(cfg);
+}
+
static void *monitor_sig_flags(void *unused)
{
for (;;) {
@@ -4613,6 +4645,7 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou
check_init(ast_timing_init(), "Timing");
check_init(ast_ssl_init(), "SSL");
+ read_pjproject_startup_options();
check_init(ast_pj_init(), "Embedded PJProject");
check_init(app_init(), "App Core");
check_init(devstate_init(), "Device State Core");
diff --git a/main/astobj2.c b/main/astobj2.c
index 7320c5e..569db0b 100644
--- a/main/astobj2.c
+++ b/main/astobj2.c
@@ -421,6 +421,19 @@ static int internal_ao2_ref(void *user_data, int delta, const char *file, int li
if (0 < current_value) {
/* The object still lives. */
+#define EXCESSIVE_REF_COUNT 100000
+
+ if (EXCESSIVE_REF_COUNT <= current_value && ret < EXCESSIVE_REF_COUNT) {
+ char excessive_ref_buf[100];
+
+ /* We just reached or went over the excessive ref count trigger */
+ snprintf(excessive_ref_buf, sizeof(excessive_ref_buf),
+ "Excessive refcount %d reached on ao2 object %p",
+ current_value, user_data);
+ ast_log(__LOG_ERROR, file, line, func, "%s\n", excessive_ref_buf);
+
+ __ast_assert_failed(0, excessive_ref_buf, file, line, func);
+ }
return ret;
}
diff --git a/main/audiohook.c b/main/audiohook.c
index 5dfbb5d..f5812e7 100644
--- a/main/audiohook.c
+++ b/main/audiohook.c
@@ -157,6 +157,11 @@ int ast_audiohook_destroy(struct ast_audiohook *audiohook)
return 0;
}
+#define SHOULD_MUTE(hook, dir) \
+ ((ast_test_flag(hook, AST_AUDIOHOOK_MUTE_READ) && (dir == AST_AUDIOHOOK_DIRECTION_READ)) || \
+ (ast_test_flag(hook, AST_AUDIOHOOK_MUTE_WRITE) && (dir == AST_AUDIOHOOK_DIRECTION_WRITE)) || \
+ (ast_test_flag(hook, AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE) == (AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE)))
+
/*! \brief Writes a frame into the audiohook structure
* \param audiohook Audiohook structure
* \param direction Direction the audio frame came from
@@ -172,7 +177,6 @@ int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohoo
int our_factory_ms;
int other_factory_samples;
int other_factory_ms;
- int muteme = 0;
/* Update last feeding time to be current */
*rwtime = ast_tvnow();
@@ -194,17 +198,6 @@ int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohoo
ast_slinfactory_flush(other_factory);
}
- /* swap frame data for zeros if mute is required */
- if ((ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_READ) && (direction == AST_AUDIOHOOK_DIRECTION_READ)) ||
- (ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_WRITE) && (direction == AST_AUDIOHOOK_DIRECTION_WRITE)) ||
- (ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE) == (AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE))) {
- muteme = 1;
- }
-
- if (muteme && frame->datalen > 0) {
- ast_frame_clear(frame);
- }
-
/* Write frame out to respective factory */
ast_slinfactory_feed(factory, frame);
@@ -243,8 +236,11 @@ static struct ast_frame *audiohook_read_frame_single(struct ast_audiohook *audio
return NULL;
}
- /* If a volume adjustment needs to be applied apply it */
- if (vol) {
+ if (SHOULD_MUTE(audiohook, direction)) {
+ /* Swap frame data for zeros if mute is required */
+ ast_frame_clear(&frame);
+ } else if (vol) {
+ /* If a volume adjustment needs to be applied apply it */
ast_frame_adjust_volume(&frame, vol);
}
@@ -293,8 +289,12 @@ static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audioho
if (usable_read) {
if (ast_slinfactory_read(&audiohook->read_factory, buf1, samples)) {
read_buf = buf1;
- /* Adjust read volume if need be */
- if (audiohook->options.read_volume) {
+
+ if ((ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_READ))) {
+ /* Clear the frame data if we are muting */
+ memset(buf1, 0, sizeof(buf1));
+ } else if (audiohook->options.read_volume) {
+ /* Adjust read volume if need be */
adjust_value = abs(audiohook->options.read_volume);
for (count = 0; count < samples; count++) {
if (audiohook->options.read_volume > 0) {
@@ -313,8 +313,12 @@ static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audioho
if (usable_write) {
if (ast_slinfactory_read(&audiohook->write_factory, buf2, samples)) {
write_buf = buf2;
- /* Adjust write volume if need be */
- if (audiohook->options.write_volume) {
+
+ if ((ast_test_flag(audiohook, AST_AUDIOHOOK_MUTE_WRITE))) {
+ /* Clear the frame data if we are muting */
+ memset(buf2, 0, sizeof(buf2));
+ } else if (audiohook->options.write_volume) {
+ /* Adjust write volume if need be */
adjust_value = abs(audiohook->options.write_volume);
for (count = 0; count < samples; count++) {
if (audiohook->options.write_volume > 0) {
diff --git a/main/autoservice.c b/main/autoservice.c
index 81d267c..305ab23 100644
--- a/main/autoservice.c
+++ b/main/autoservice.c
@@ -61,6 +61,10 @@ struct asent {
unsigned int use_count;
unsigned int orig_end_dtmf_flag:1;
unsigned int ignore_frame_types;
+ /*! Frames go on at the head of deferred_frames, so we have the frames
+ * from newest to oldest. As we put them at the head of the readq, we'll
+ * end up with them in the right order for the channel's readq. */
+ AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
AST_LIST_ENTRY(asent) list;
};
@@ -75,13 +79,19 @@ static int as_chan_list_state;
static void *autoservice_run(void *ign)
{
struct ast_callid *callid = NULL;
+ struct ast_frame hangup_frame = {
+ .frametype = AST_FRAME_CONTROL,
+ .subclass.integer = AST_CONTROL_HANGUP,
+ };
while (!asexit) {
struct ast_channel *mons[MAX_AUTOMONS];
+ struct asent *ents[MAX_AUTOMONS];
struct ast_channel *chan;
struct asent *as;
- int x = 0, ms = 50;
+ int i, x = 0, ms = 50;
struct ast_frame *f = NULL;
+ struct ast_frame *defer_frame = NULL;
AST_LIST_LOCK(&aslist);
@@ -96,6 +106,7 @@ static void *autoservice_run(void *ign)
AST_LIST_TRAVERSE(&aslist, as, list) {
if (!ast_check_hangup(as->chan)) {
if (x < MAX_AUTOMONS) {
+ ents[x] = as;
mons[x++] = as->chan;
} else {
ast_log(LOG_WARNING, "Exceeded maximum number of automatic monitoring events. Fix autoservice.c\n");
@@ -126,9 +137,51 @@ static void *autoservice_run(void *ign)
}
f = ast_read(chan);
- if (f) {
+
+ if (!f) {
+ /* No frame means the channel has been hung up.
+ * A hangup frame needs to be queued here as ast_waitfor() may
+ * never return again for the condition to be detected outside
+ * of autoservice. So, we'll leave a HANGUP queued up so the
+ * thread in charge of this channel will know. */
+
+ defer_frame = &hangup_frame;
+ } else if (ast_is_deferrable_frame(f)) {
+ defer_frame = f;
+ } else {
+ /* Can't defer. Discard and continue with next. */
ast_frfree(f);
+ continue;
}
+
+ for (i = 0; i < x; i++) {
+ struct ast_frame *dup_f;
+
+ if (mons[i] != chan) {
+ continue;
+ }
+
+ if (!f) { /* defer_frame == &hangup_frame */
+ if ((dup_f = ast_frdup(defer_frame))) {
+ AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
+ }
+ } else {
+ if ((dup_f = ast_frisolate(defer_frame))) {
+ AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
+ }
+ if (dup_f != defer_frame) {
+ ast_frfree(defer_frame);
+ }
+ }
+
+ break;
+ }
+ /* The ast_waitfor_n() call will only read frames from
+ * the channels' file descriptors. If ast_waitfor_n()
+ * returns non-NULL, then one of the channels in the
+ * mons array must have triggered the return. It's
+ * therefore impossible that we got here while (i >= x).
+ * If we did, we'd need to ast_frfree(f) if (f). */
}
ast_callid_threadassoc_change(NULL);
@@ -167,7 +220,6 @@ int ast_autoservice_start(struct ast_channel *chan)
as->orig_end_dtmf_flag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY) ? 1 : 0;
if (!as->orig_end_dtmf_flag)
ast_set_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY);
- ast_channel_start_defer_frames(chan, 1);
ast_channel_unlock(chan);
AST_LIST_LOCK(&aslist);
@@ -201,6 +253,7 @@ int ast_autoservice_stop(struct ast_channel *chan)
{
int res = -1;
struct asent *as, *removed = NULL;
+ struct ast_frame *f;
int chan_list_state;
AST_LIST_LOCK(&aslist);
@@ -252,7 +305,12 @@ int ast_autoservice_stop(struct ast_channel *chan)
}
ast_channel_lock(chan);
- ast_channel_stop_defer_frames(chan);
+ while ((f = AST_LIST_REMOVE_HEAD(&as->deferred_frames, frame_list))) {
+ if (!((1 << f->frametype) & as->ignore_frame_types)) {
+ ast_queue_frame_head(chan, f);
+ }
+ ast_frfree(f);
+ }
ast_channel_unlock(chan);
free(as);
diff --git a/main/channel.c b/main/channel.c
index 54b9130..28cfa79 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -1061,26 +1061,6 @@ struct ast_channel *ast_dummy_channel_alloc(void)
return tmp;
}
-void ast_channel_start_defer_frames(struct ast_channel *chan, int defer_hangups)
-{
- ast_set_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES);
- ast_set2_flag(ast_channel_flags(chan), defer_hangups, AST_FLAG_DEFER_HANGUP_FRAMES);
-}
-
-void ast_channel_stop_defer_frames(struct ast_channel *chan)
-{
- ast_clear_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES);
-
- /* Move the deferred frames onto the channel read queue, ahead of other queued frames */
- ast_queue_frame_head(chan, AST_LIST_FIRST(ast_channel_deferred_readq(chan)));
- /* ast_frfree will mosey down the list and free them all */
- if (!AST_LIST_EMPTY(ast_channel_deferred_readq(chan))) {
- ast_frfree(AST_LIST_FIRST(ast_channel_deferred_readq(chan)));
- }
- /* Reset the list to be empty */
- AST_LIST_HEAD_INIT_NOLOCK(ast_channel_deferred_readq(chan));
-}
-
static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int head, struct ast_frame *after)
{
struct ast_frame *f;
@@ -1167,6 +1147,9 @@ static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, in
}
AST_LIST_REMOVE_CURRENT(frame_list);
ast_frfree(cur);
+
+ /* Read from the alert pipe for each flushed frame. */
+ ast_channel_internal_alert_read(chan);
}
}
AST_LIST_TRAVERSE_SAFE_END;
@@ -1183,9 +1166,13 @@ static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, in
}
if (ast_channel_alert_writable(chan)) {
- if (ast_channel_alert_write(chan)) {
- ast_log(LOG_WARNING, "Unable to write to alert pipe on %s (qlen = %u): %s!\n",
- ast_channel_name(chan), queued_frames, strerror(errno));
+ /* Write to the alert pipe for each added frame */
+ while (new_frames--) {
+ if (ast_channel_alert_write(chan)) {
+ ast_log(LOG_WARNING, "Unable to write to alert pipe on %s (qlen = %u): %s!\n",
+ ast_channel_name(chan), queued_frames, strerror(errno));
+ break;
+ }
}
} else if (ast_channel_timingfd(chan) > -1) {
ast_timer_enable_continuous(ast_channel_timer(chan));
@@ -1544,18 +1531,19 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c
int res = 0;
struct timeval start;
int ms;
+ AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
+
+ AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames);
/* If no other generator is present, start silencegen while waiting */
if (ast_opt_transmit_silence && !ast_channel_generatordata(chan)) {
silgen = ast_channel_start_silence_generator(chan);
}
- ast_channel_lock(chan);
- ast_channel_start_defer_frames(chan, 0);
- ast_channel_unlock(chan);
-
start = ast_tvnow();
while ((ms = ast_remaining_ms(start, timeout_ms))) {
+ struct ast_frame *dup_f = NULL;
+
if (cond && ((*cond)(data) == 0)) {
break;
}
@@ -1570,7 +1558,18 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c
res = -1;
break;
}
- ast_frfree(f);
+
+ if (!ast_is_deferrable_frame(f)) {
+ ast_frfree(f);
+ continue;
+ }
+
+ if ((dup_f = ast_frisolate(f))) {
+ if (dup_f != f) {
+ ast_frfree(f);
+ }
+ AST_LIST_INSERT_HEAD(&deferred_frames, dup_f, frame_list);
+ }
}
}
@@ -1579,8 +1578,17 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*c
ast_channel_stop_silence_generator(chan, silgen);
}
+ /* We need to free all the deferred frames, but we only need to
+ * queue the deferred frames if there was no error and no
+ * hangup was received
+ */
ast_channel_lock(chan);
- ast_channel_stop_defer_frames(chan);
+ while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) {
+ if (!res) {
+ ast_queue_frame_head(chan, f);
+ }
+ ast_frfree(f);
+ }
ast_channel_unlock(chan);
return res;
@@ -3884,36 +3892,6 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
if (!AST_LIST_EMPTY(ast_channel_readq(chan))) {
int skip_dtmf = should_skip_dtmf(chan);
- if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES)) {
- AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_readq(chan), f, frame_list) {
- if (ast_is_deferrable_frame(f)) {
- if(f->frametype == AST_FRAME_CONTROL &&
- (f->subclass.integer == AST_CONTROL_HANGUP ||
- f->subclass.integer == AST_CONTROL_END_OF_Q)) {
- /* Hangup is a special case. We want to defer the frame, but we also do not
- * want to remove it from the frame queue. So rather than just moving the frame
- * over, we duplicate it and move the copy to the deferred readq.
- *
- * The reason for this? This way, whoever calls ast_read() will get a NULL return
- * immediately and can tell the channel has hung up and do what it needs to. Also,
- * when frame deferral finishes, then whoever calls ast_read() next will also get
- * the hangup.
- */
- if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_DEFER_HANGUP_FRAMES)) {
- struct ast_frame *dup;
-
- dup = ast_frdup(f);
- AST_LIST_INSERT_TAIL(ast_channel_deferred_readq(chan), dup, frame_list);
- }
- } else {
- AST_LIST_INSERT_TAIL(ast_channel_deferred_readq(chan), f, frame_list);
- AST_LIST_REMOVE_CURRENT(frame_list);
- }
- }
- }
- AST_LIST_TRAVERSE_SAFE_END;
- }
-
AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_readq(chan), f, frame_list) {
/* We have to be picky about which frame we pull off of the readq because
* there are cases where we want to leave DTMF frames on the queue until
@@ -4336,12 +4314,19 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
* at the end of the queue.
*/
if (AST_LIST_NEXT(f, frame_list)) {
+ struct ast_frame *cur, *multi_frame = AST_LIST_NEXT(f, frame_list);
+
+ /* Mark these frames as being re-queued */
+ for (cur = multi_frame; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
+ ast_set_flag(cur, AST_FRFLAG_REQUEUED);
+ }
+
if (!readq_tail) {
- ast_queue_frame_head(chan, AST_LIST_NEXT(f, frame_list));
+ ast_queue_frame_head(chan, multi_frame);
} else {
- __ast_queue_frame(chan, AST_LIST_NEXT(f, frame_list), 0, readq_tail);
+ __ast_queue_frame(chan, multi_frame, 0, readq_tail);
}
- ast_frfree(AST_LIST_NEXT(f, frame_list));
+ ast_frfree(multi_frame);
AST_LIST_NEXT(f, frame_list) = NULL;
}
@@ -4883,16 +4868,18 @@ int ast_sendtext(struct ast_channel *chan, const char *text)
if (ast_channel_tech(chan)->write_text && (ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_MEDIA_TYPE_TEXT))) {
struct ast_frame f;
+ memset(&f, 0, sizeof(f));
f.frametype = AST_FRAME_TEXT;
f.src = "DIALPLAN";
f.mallocd = AST_MALLOCD_DATA;
f.datalen = strlen(text);
f.data.ptr = ast_strdup(text);
- f.offset = 0;
- f.seqno = 0;
-
f.subclass.format = ast_format_t140;
- res = ast_channel_tech(chan)->write_text(chan, &f);
+
+ if (f.data.ptr) {
+ res = ast_channel_tech(chan)->write_text(chan, &f);
+ ast_frfree(&f);
+ }
} else if (ast_channel_tech(chan)->send_text) {
res = ast_channel_tech(chan)->send_text(chan, text);
}
@@ -5476,6 +5463,42 @@ int ast_set_read_format_path(struct ast_channel *chan, struct ast_format *raw_fo
return 0;
}
+int ast_set_write_format_path(struct ast_channel *chan, struct ast_format *core_format, struct ast_format *raw_format)
+{
+ struct ast_trans_pvt *trans_old;
+ struct ast_trans_pvt *trans_new;
+
+ if (ast_format_cmp(ast_channel_rawwriteformat(chan), raw_format) == AST_FORMAT_CMP_EQUAL
+ && ast_format_cmp(ast_channel_writeformat(chan), core_format) == AST_FORMAT_CMP_EQUAL) {
+ /* Nothing to setup */
+ return 0;
+ }
+
+ ast_debug(1, "Channel %s setting write format path: %s -> %s\n",
+ ast_channel_name(chan),
+ ast_format_get_name(core_format),
+ ast_format_get_name(raw_format));
+
+ /* Setup new translation path. */
+ if (ast_format_cmp(raw_format, core_format) != AST_FORMAT_CMP_EQUAL) {
+ trans_new = ast_translator_build_path(raw_format, core_format);
+ if (!trans_new) {
+ return -1;
+ }
+ } else {
+ /* No translation needed. */
+ trans_new = NULL;
+ }
+ trans_old = ast_channel_writetrans(chan);
+ if (trans_old) {
+ ast_translator_free_path(trans_old);
+ }
+ ast_channel_writetrans_set(chan, trans_new);
+ ast_channel_set_rawwriteformat(chan, raw_format);
+ ast_channel_set_writeformat(chan, core_format);
+ return 0;
+}
+
struct set_format_access {
const char *direction;
struct ast_trans_pvt *(*get_trans)(const struct ast_channel *chan);
@@ -10212,6 +10235,36 @@ void ast_channel_queue_redirecting_update(struct ast_channel *chan, const struct
ast_queue_control_data(chan, AST_CONTROL_REDIRECTING, data, datalen);
}
+/*!
+ * Storage to determine if the current thread is running an intercept dialplan routine.
+ */
+AST_THREADSTORAGE_RAW(in_intercept_routine);
+
+/*!
+ * \internal
+ * \brief Set the current intercept dialplan routine status mode.
+ * \since 13.14.0
+ *
+ * \param in_intercept_mode New intercept mode. (Non-zero if in intercept mode)
+ *
+ * \return Nothing
+ */
+static void channel_set_intercept_mode(int in_intercept_mode)
+{
+ int status;
+
+ status = ast_threadstorage_set_ptr(&in_intercept_routine,
+ in_intercept_mode ? (void *) 1 : (void *) 0);
+ if (status) {
+ ast_log(LOG_ERROR, "Failed to set dialplan intercept mode\n");
+ }
+}
+
+int ast_channel_get_intercept_mode(void)
+{
+ return ast_threadstorage_get_ptr(&in_intercept_routine) ? 1 : 0;
+}
+
int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int is_caller, int is_frame)
{
static int deprecation_warning = 0;
@@ -10245,15 +10298,11 @@ int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struc
ast_party_connected_line_copy(ast_channel_connected(macro_chan), connected);
}
- ast_channel_start_defer_frames(macro_chan, 0);
ast_channel_unlock(macro_chan);
+ channel_set_intercept_mode(1);
retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args);
-
- ast_channel_lock(macro_chan);
- ast_channel_stop_defer_frames(macro_chan);
- ast_channel_unlock(macro_chan);
-
+ channel_set_intercept_mode(0);
if (!retval) {
struct ast_party_connected_line saved_connected;
@@ -10301,15 +10350,11 @@ int ast_channel_redirecting_macro(struct ast_channel *autoservice_chan, struct a
ast_party_redirecting_copy(ast_channel_redirecting(macro_chan), redirecting);
}
- ast_channel_start_defer_frames(macro_chan, 0);
ast_channel_unlock(macro_chan);
+ channel_set_intercept_mode(1);
retval = ast_app_run_macro(autoservice_chan, macro_chan, macro, macro_args);
-
- ast_channel_lock(macro_chan);
- ast_channel_stop_defer_frames(macro_chan);
- ast_channel_unlock(macro_chan);
-
+ channel_set_intercept_mode(0);
if (!retval) {
struct ast_party_redirecting saved_redirecting;
@@ -10350,15 +10395,11 @@ int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct
ast_party_connected_line_copy(ast_channel_connected(sub_chan), connected);
}
- ast_channel_start_defer_frames(sub_chan, 0);
ast_channel_unlock(sub_chan);
+ channel_set_intercept_mode(1);
retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0);
-
- ast_channel_lock(sub_chan);
- ast_channel_stop_defer_frames(sub_chan);
- ast_channel_unlock(sub_chan);
-
+ channel_set_intercept_mode(0);
if (!retval) {
struct ast_party_connected_line saved_connected;
@@ -10399,15 +10440,11 @@ int ast_channel_redirecting_sub(struct ast_channel *autoservice_chan, struct ast
ast_party_redirecting_copy(ast_channel_redirecting(sub_chan), redirecting);
}
- ast_channel_start_defer_frames(sub_chan, 0);
ast_channel_unlock(sub_chan);
+ channel_set_intercept_mode(1);
retval = ast_app_run_sub(autoservice_chan, sub_chan, sub, sub_args, 0);
-
- ast_channel_lock(sub_chan);
- ast_channel_stop_defer_frames(sub_chan);
- ast_channel_unlock(sub_chan);
-
+ channel_set_intercept_mode(0);
if (!retval) {
struct ast_party_redirecting saved_redirecting;
diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c
index 4bc770d..bb33e9f 100644
--- a/main/channel_internal_api.c
+++ b/main/channel_internal_api.c
@@ -223,7 +223,6 @@ struct ast_channel {
struct stasis_cp_single *topics; /*!< Topic for all channel's events */
struct stasis_forward *endpoint_forward; /*!< Subscription for event forwarding to endpoint's topic */
struct stasis_forward *endpoint_cache_forward; /*!< Subscription for cache updates to endpoint's topic */
- struct ast_readq_list deferred_readq;
};
/*! \brief The monotonically increasing integer counter for channel uniqueids */
@@ -1249,14 +1248,9 @@ int ast_channel_alert_write(struct ast_channel *chan)
return write(chan->alertpipe[1], &blah, sizeof(blah)) != sizeof(blah);
}
-ast_alert_status_t ast_channel_internal_alert_read(struct ast_channel *chan)
+static int channel_internal_alert_check_nonblock(struct ast_channel *chan)
{
int flags;
- char blah;
-
- if (!ast_channel_internal_alert_readable(chan)) {
- return AST_ALERT_NOT_READABLE;
- }
flags = fcntl(chan->alertpipe[0], F_GETFL);
/* For some odd reason, the alertpipe occasionally loses nonblocking status,
@@ -1265,9 +1259,62 @@ ast_alert_status_t ast_channel_internal_alert_read(struct ast_channel *chan)
ast_log(LOG_ERROR, "Alertpipe on channel %s lost O_NONBLOCK?!!\n", ast_channel_name(chan));
if (fcntl(chan->alertpipe[0], F_SETFL, flags | O_NONBLOCK) < 0) {
ast_log(LOG_WARNING, "Unable to set alertpipe nonblocking! (%d: %s)\n", errno, strerror(errno));
- return AST_ALERT_READ_FATAL;
+ return -1;
}
}
+ return 0;
+}
+
+ast_alert_status_t ast_channel_internal_alert_flush(struct ast_channel *chan)
+{
+ int bytes_read;
+ char blah[100];
+
+ if (!ast_channel_internal_alert_readable(chan)) {
+ return AST_ALERT_NOT_READABLE;
+ }
+ if (channel_internal_alert_check_nonblock(chan)) {
+ return AST_ALERT_READ_FATAL;
+ }
+
+ /* Read the alertpipe until it is exhausted. */
+ for (;;) {
+ bytes_read = read(chan->alertpipe[0], blah, sizeof(blah));
+ if (bytes_read < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ /*
+ * Would block so nothing left to read.
+ * This is the normal loop exit.
+ */
+ break;
+ }
+ ast_log(LOG_WARNING, "read() failed flushing alertpipe: %s\n",
+ strerror(errno));
+ return AST_ALERT_READ_FAIL;
+ }
+ if (!bytes_read) {
+ /* Read nothing so we are done */
+ break;
+ }
+ }
+
+ return AST_ALERT_READ_SUCCESS;
+}
+
+ast_alert_status_t ast_channel_internal_alert_read(struct ast_channel *chan)
+{
+ char blah;
+
+ if (!ast_channel_internal_alert_readable(chan)) {
+ return AST_ALERT_NOT_READABLE;
+ }
+ if (channel_internal_alert_check_nonblock(chan)) {
+ return AST_ALERT_READ_FATAL;
+ }
+
if (read(chan->alertpipe[0], &blah, sizeof(blah)) < 0) {
if (errno != EINTR && errno != EAGAIN) {
ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
@@ -1699,8 +1746,3 @@ enum ast_channel_error ast_channel_internal_errno(void)
return *error_code;
}
-
-struct ast_readq_list *ast_channel_deferred_readq(struct ast_channel *chan)
-{
- return &chan->deferred_readq;
-}
diff --git a/main/fixedjitterbuf.c b/main/fixedjitterbuf.c
index 17cad49..ebc5259 100644
--- a/main/fixedjitterbuf.c
+++ b/main/fixedjitterbuf.c
@@ -196,7 +196,6 @@ int fixed_jb_put_first(struct fixed_jb *jb, void *data, long ms, long ts, long n
return fixed_jb_put(jb, data, ms, ts, now);
}
-
int fixed_jb_put(struct fixed_jb *jb, void *data, long ms, long ts, long now)
{
struct fixed_jb_frame *frame, *next, *newframe;
@@ -349,3 +348,8 @@ int fixed_jb_remove(struct fixed_jb *jb, struct fixed_jb_frame *frameout)
return FIXED_JB_OK;
}
+
+int fixed_jb_is_late(struct fixed_jb *jb, long ts)
+{
+ return jb->rxcore + jb->delay + ts < jb->next_delivery;
+}
diff --git a/main/fixedjitterbuf.h b/main/fixedjitterbuf.h
index df9bbac..ab8e5e2 100644
--- a/main/fixedjitterbuf.h
+++ b/main/fixedjitterbuf.h
@@ -85,6 +85,9 @@ int fixed_jb_remove(struct fixed_jb *jb, struct fixed_jb_frame *frameout);
void fixed_jb_set_force_resynch(struct fixed_jb *jb);
+/*! \brief Checks if the given time stamp is late */
+int fixed_jb_is_late(struct fixed_jb *jb, long ts);
+
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
diff --git a/main/format_compatibility.c b/main/format_compatibility.c
index cf66af2..0f1dff7 100644
--- a/main/format_compatibility.c
+++ b/main/format_compatibility.c
@@ -264,10 +264,10 @@ struct ast_format *ast_format_compatibility_bitfield2format(uint64_t bitfield)
/*! T.140 RED Text format RFC 4103 */
case AST_FORMAT_T140_RED:
- return ast_format_t140;
+ return ast_format_t140_red;
/*! T.140 Text format - ITU T.140, RFC 4103 */
case AST_FORMAT_T140:
- return ast_format_t140_red;
+ return ast_format_t140;
}
return NULL;
}
diff --git a/main/frame.c b/main/frame.c
index b5ab985..4261b04 100644
--- a/main/frame.c
+++ b/main/frame.c
@@ -84,9 +84,9 @@ static struct ast_frame *ast_frame_header_new(void)
if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames)))) {
if ((f = AST_LIST_REMOVE_HEAD(&frames->list, frame_list))) {
size_t mallocd_len = f->mallocd_hdr_len;
+
memset(f, 0, sizeof(*f));
f->mallocd_hdr_len = mallocd_len;
- f->mallocd = AST_MALLOCD_HDR;
frames->size--;
return f;
}
@@ -141,12 +141,12 @@ static void __frame_free(struct ast_frame *fr, int cache)
#endif
if (fr->mallocd & AST_MALLOCD_DATA) {
- if (fr->data.ptr)
+ if (fr->data.ptr) {
ast_free(fr->data.ptr - fr->offset);
+ }
}
if (fr->mallocd & AST_MALLOCD_SRC) {
- if (fr->src)
- ast_free((void *) fr->src);
+ ast_free((void *) fr->src);
}
if (fr->mallocd & AST_MALLOCD_HDR) {
if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) ||
@@ -208,14 +208,14 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr)
return NULL;
}
out->frametype = fr->frametype;
+ out->subclass = fr->subclass;
if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) ||
(fr->frametype == AST_FRAME_IMAGE)) {
- out->subclass.format = ao2_bump(fr->subclass.format);
- } else {
- memcpy(&out->subclass, &fr->subclass, sizeof(out->subclass));
+ ao2_bump(out->subclass.format);
}
out->datalen = fr->datalen;
out->samples = fr->samples;
+ out->mallocd = AST_MALLOCD_HDR;
out->offset = fr->offset;
/* Copy the timing data */
ast_copy_flags(out, fr, AST_FLAGS_ALL);
@@ -228,47 +228,64 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr)
out = fr;
}
- if (!(fr->mallocd & AST_MALLOCD_SRC) && fr->src) {
- if (!(out->src = ast_strdup(fr->src))) {
- if (out != fr) {
- ast_free(out);
+ if (fr->src) {
+ /* The original frame has a source string */
+ if (!(fr->mallocd & AST_MALLOCD_SRC)) {
+ /*
+ * The original frame has a non-malloced source string.
+ *
+ * Duplicate the string and put it into the isolated frame
+ * which may also be the original frame.
+ */
+ newdata = ast_strdup(fr->src);
+ if (!newdata) {
+ if (out != fr) {
+ ast_frame_free(out, 0);
+ }
+ return NULL;
}
- return NULL;
+ out->src = newdata;
+ out->mallocd |= AST_MALLOCD_SRC;
+ } else if (out != fr) {
+ /* Steal the source string from the original frame. */
+ out->src = fr->src;
+ fr->src = NULL;
+ fr->mallocd &= ~AST_MALLOCD_SRC;
+ out->mallocd |= AST_MALLOCD_SRC;
}
- } else {
- out->src = fr->src;
- fr->src = NULL;
- fr->mallocd &= ~AST_MALLOCD_SRC;
}
if (!(fr->mallocd & AST_MALLOCD_DATA)) {
+ /* The original frame has a non-malloced data buffer. */
if (!fr->datalen) {
+ /* Actually it's just an int so we can simply copy it. */
out->data.uint32 = fr->data.uint32;
- out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC;
return out;
}
- if (!(newdata = ast_malloc(fr->datalen + AST_FRIENDLY_OFFSET))) {
- if (out->src != fr->src) {
- ast_free((void *) out->src);
- }
+ /*
+ * Duplicate the data buffer and put it into the isolated frame
+ * which may also be the original frame.
+ */
+ newdata = ast_malloc(fr->datalen + AST_FRIENDLY_OFFSET);
+ if (!newdata) {
if (out != fr) {
- ast_free(out);
+ ast_frame_free(out, 0);
}
return NULL;
}
newdata += AST_FRIENDLY_OFFSET;
out->offset = AST_FRIENDLY_OFFSET;
- out->datalen = fr->datalen;
memcpy(newdata, fr->data.ptr, fr->datalen);
out->data.ptr = newdata;
- } else {
+ out->mallocd |= AST_MALLOCD_DATA;
+ } else if (out != fr) {
+ /* Steal the data buffer from the original frame. */
out->data = fr->data;
memset(&fr->data, 0, sizeof(fr->data));
fr->mallocd &= ~AST_MALLOCD_DATA;
+ out->mallocd |= AST_MALLOCD_DATA;
}
- out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
-
return out;
}
diff --git a/main/jitterbuf.c b/main/jitterbuf.c
index 1bfe508..df3164f 100644
--- a/main/jitterbuf.c
+++ b/main/jitterbuf.c
@@ -845,4 +845,7 @@ enum jb_return_code jb_setconf(jitterbuf *jb, jb_conf *conf)
return JB_OK;
}
-
+int jb_is_late(jitterbuf *jb, long ts)
+{
+ return ts + jb->info.current < jb->info.next_voice_ts;
+}
diff --git a/main/libasteriskpj.c b/main/libasteriskpj.c
index aed0ec8..80c4d18 100644
--- a/main/libasteriskpj.c
+++ b/main/libasteriskpj.c
@@ -37,6 +37,7 @@ ASTERISK_REGISTER_FILE()
#include <pjlib.h>
#endif
+#include "asterisk/options.h"
#include "asterisk/_private.h" /* ast_pj_init() */
/*!
@@ -46,6 +47,7 @@ ASTERISK_REGISTER_FILE()
int ast_pj_init(void)
{
#ifdef HAVE_PJPROJECT_BUNDLED
+ AST_PJPROJECT_INIT_LOG_LEVEL();
pj_init();
#endif
return 0;
diff --git a/main/libasteriskssl.c b/main/libasteriskssl.c
index b326701..c4d4c56 100644
--- a/main/libasteriskssl.c
+++ b/main/libasteriskssl.c
@@ -67,13 +67,14 @@ static void ssl_lock(int mode, int n, const char *file, int line)
return;
}
- if (mode & CRYPTO_LOCK) {
+ if (mode & 0x1) {
ast_mutex_lock(&ssl_locks[n]);
} else {
ast_mutex_unlock(&ssl_locks[n]);
}
}
+#if !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < 0x10100000L
int SSL_library_init(void)
{
#if defined(AST_DEVMODE)
@@ -115,6 +116,7 @@ void ERR_free_strings(void)
{
/* we can't allow this to be called, ever */
}
+#endif /* !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < 0x10100000L */
#endif /* HAVE_OPENSSL */
diff --git a/main/manager.c b/main/manager.c
index 0ca84b2..251085a 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -5855,7 +5855,11 @@ static int match_filter(struct mansession *s, char *eventdata)
{
int result = 0;
- ast_debug(3, "Examining AMI event:\n%s\n", eventdata);
+ if (manager_debug) {
+ ast_verbose("<-- Examining AMI event: -->\n%s\n", eventdata);
+ } else {
+ ast_debug(3, "Examining AMI event:\n%s\n", eventdata);
+ }
if (!ao2_container_count(s->session->whitefilters) && !ao2_container_count(s->session->blackfilters)) {
return 1; /* no filtering means match all */
} else if (ao2_container_count(s->session->whitefilters) && !ao2_container_count(s->session->blackfilters)) {
diff --git a/main/message.c b/main/message.c
index d4e48fb..594853f 100644
--- a/main/message.c
+++ b/main/message.c
@@ -777,11 +777,20 @@ static void chan_cleanup(struct ast_channel *chan)
if (msg_ds) {
ast_channel_datastore_add(chan, msg_ds);
}
+
/*
* Clear softhangup flags.
*/
ast_channel_clear_softhangup(chan, AST_SOFTHANGUP_ALL);
+ /*
+ * Flush the alert pipe in case we miscounted somewhere when
+ * messing with frames on the read queue, we had to flush the
+ * read queue above, or we had an "Exceptionally long queue
+ * length" event.
+ */
+ ast_channel_internal_alert_flush(chan);
+
ast_channel_unlock(chan);
}
diff --git a/main/rtp_engine.c b/main/rtp_engine.c
index 0512531..5c7b7a0 100644
--- a/main/rtp_engine.c
+++ b/main/rtp_engine.c
@@ -1987,7 +1987,7 @@ static struct ast_manager_event_blob *rtcp_report_to_ami(struct stasis_message *
if (type == AST_RTP_RTCP_SR) {
ast_str_append(&packet_string, 0, "SentNTP: %lu.%06lu\r\n",
(unsigned long)payload->report->sender_information.ntp_timestamp.tv_sec,
- (unsigned long)payload->report->sender_information.ntp_timestamp.tv_usec * 4096);
+ (unsigned long)payload->report->sender_information.ntp_timestamp.tv_usec);
ast_str_append(&packet_string, 0, "SentRTP: %u\r\n",
payload->report->sender_information.rtp_timestamp);
ast_str_append(&packet_string, 0, "SentPackets: %u\r\n",
diff --git a/main/srv.c b/main/srv.c
index 0938a0c..dcfcc2b 100644
--- a/main/srv.c
+++ b/main/srv.c
@@ -211,7 +211,8 @@ int ast_srv_lookup(struct srv_context **context, const char *service, const char
}
AST_LIST_HEAD_INIT_NOLOCK(&(*context)->entries);
- if ((ast_search_dns(*context, service, C_IN, T_SRV, srv_callback)) < 0) {
+ if (((ast_search_dns(*context, service, C_IN, T_SRV, srv_callback)) < 1) ||
+ AST_LIST_EMPTY(&(*context)->entries)) {
ast_free(*context);
*context = NULL;
return -1;
diff --git a/main/strings.c b/main/strings.c
index 7cb55de..7f2025a 100644
--- a/main/strings.c
+++ b/main/strings.c
@@ -186,15 +186,32 @@ static int str_hash(const void *obj, const int flags)
return ast_str_hash(obj);
}
+static int str_sort(const void *lhs, const void *rhs, int flags)
+{
+ if ((flags & OBJ_SEARCH_MASK) == OBJ_SEARCH_PARTIAL_KEY) {
+ return strncmp(lhs, rhs, strlen(rhs));
+ } else {
+ return strcmp(lhs, rhs);
+ }
+}
+
static int str_cmp(void *lhs, void *rhs, int flags)
{
- return strcmp(lhs, rhs) ? 0 : CMP_MATCH;
+ int cmp = 0;
+
+ if ((flags & OBJ_SEARCH_MASK) == OBJ_SEARCH_PARTIAL_KEY) {
+ cmp = strncmp(lhs, rhs, strlen(rhs));
+ } else {
+ cmp = strcmp(lhs, rhs);
+ }
+
+ return cmp ? 0 : CMP_MATCH;
}
//struct ao2_container *ast_str_container_alloc_options(enum ao2_container_opts opts, int buckets)
struct ao2_container *ast_str_container_alloc_options(enum ao2_alloc_opts opts, int buckets)
{
- return ao2_container_alloc_options(opts, buckets, str_hash, str_cmp);
+ return ao2_container_alloc_hash(opts, 0, buckets, str_hash, str_sort, str_cmp);
}
int ast_str_container_add(struct ao2_container *str_container, const char *add)
diff --git a/main/taskprocessor.c b/main/taskprocessor.c
index bbf282c..f4ebab3 100644
--- a/main/taskprocessor.c
+++ b/main/taskprocessor.c
@@ -884,12 +884,10 @@ static int taskprocessor_push(struct ast_taskprocessor *tps, struct tps_task *t)
previous_size = tps->tps_queue_size++;
if (tps->tps_queue_high <= tps->tps_queue_size) {
- if (!tps->high_water_warned) {
- tps->high_water_warned = 1;
- ast_log(LOG_WARNING, "The '%s' task processor queue reached %ld scheduled tasks.\n",
- tps->name, tps->tps_queue_size);
- }
if (!tps->high_water_alert) {
+ ast_log(LOG_WARNING, "The '%s' task processor queue reached %ld scheduled tasks%s.\n",
+ tps->name, tps->tps_queue_size, tps->high_water_warned ? " again" : "");
+ tps->high_water_warned = 1;
tps->high_water_alert = 1;
tps_alert_add(tps, +1);
}
diff --git a/main/tcptls.c b/main/tcptls.c
index bccb03d..21abd26 100644
--- a/main/tcptls.c
+++ b/main/tcptls.c
@@ -39,6 +39,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <signal.h>
#include <sys/signal.h>
+#include <sys/stat.h>
#include "asterisk/compat.h"
#include "asterisk/tcptls.h"
@@ -49,6 +50,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/manager.h"
#include "asterisk/astobj2.h"
#include "asterisk/pbx.h"
+#include "asterisk/app.h"
/*! ao2 object used for the FILE stream fopencookie()/funopen() cookie. */
struct ast_tcptls_stream {
@@ -398,13 +400,19 @@ static int tcptls_stream_close(void *cookie)
SSL_get_error(stream->ssl, res));
}
+#if defined(OPENSSL_API_COMPAT) && OPENSSL_API_COMPAT >= 0x10100000L
+ if (!SSL_is_server(stream->ssl)) {
+#else
if (!stream->ssl->server) {
+#endif
/* For client threads, ensure that the error stack is cleared */
+#if !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < 0x10100000L
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
ERR_remove_thread_state(NULL);
#else
ERR_remove_state(0);
#endif /* OPENSSL_VERSION_NUMBER >= 0x10000000L */
+#endif /* !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < 0x10100000L */
}
SSL_free(stream->ssl);
@@ -813,7 +821,7 @@ static int __ssl_setup(struct ast_tls_config *cfg, int client)
}
if (client) {
-#ifndef OPENSSL_NO_SSL2
+#if !defined(OPENSSL_NO_SSL2) && (OPENSSL_VERSION_NUMBER < 0x10100000L)
if (ast_test_flag(&cfg->flags, AST_SSL_SSLV2_CLIENT)) {
ast_log(LOG_WARNING, "Usage of SSLv2 is discouraged due to known vulnerabilities. Please use 'tlsv1' or leave the TLS method unspecified!\n");
cfg->ssl_ctx = SSL_CTX_new(SSLv2_client_method());
@@ -1076,9 +1084,64 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc)
{
int flags;
int x = 1;
+ int tls_changed = 0;
+
+ if (desc->tls_cfg) {
+ char hash[41];
+ char *str = NULL;
+ struct stat st;
+
+ /* Store the hashes of the TLS certificate etc. */
+ if (stat(desc->tls_cfg->certfile, &st) || NULL == (str = ast_read_textfile(desc->tls_cfg->certfile))) {
+ memset(hash, 0, 41);
+ } else {
+ ast_sha1_hash(hash, str);
+ }
+ ast_free(str);
+ str = NULL;
+ memcpy(desc->tls_cfg->certhash, hash, 41);
+ if (stat(desc->tls_cfg->pvtfile, &st) || NULL == (str = ast_read_textfile(desc->tls_cfg->pvtfile))) {
+ memset(hash, 0, 41);
+ } else {
+ ast_sha1_hash(hash, str);
+ }
+ ast_free(str);
+ str = NULL;
+ memcpy(desc->tls_cfg->pvthash, hash, 41);
+ if (stat(desc->tls_cfg->cafile, &st) || NULL == (str = ast_read_textfile(desc->tls_cfg->cafile))) {
+ memset(hash, 0, 41);
+ } else {
+ ast_sha1_hash(hash, str);
+ }
+ ast_free(str);
+ str = NULL;
+ memcpy(desc->tls_cfg->cahash, hash, 41);
+
+ /* Check whether TLS configuration has changed */
+ if (!desc->old_tls_cfg) { /* No previous configuration */
+ tls_changed = 1;
+ desc->old_tls_cfg = ast_calloc(1, sizeof(*desc->old_tls_cfg));
+ } else if (memcmp(desc->tls_cfg->certhash, desc->old_tls_cfg->certhash, 41)) {
+ tls_changed = 1;
+ } else if (memcmp(desc->tls_cfg->pvthash, desc->old_tls_cfg->pvthash, 41)) {
+ tls_changed = 1;
+ } else if (strcmp(desc->tls_cfg->cipher, desc->old_tls_cfg->cipher)) {
+ tls_changed = 1;
+ } else if (memcmp(desc->tls_cfg->cahash, desc->old_tls_cfg->cahash, 41)) {
+ tls_changed = 1;
+ } else if (strcmp(desc->tls_cfg->capath, desc->old_tls_cfg->capath)) {
+ tls_changed = 1;
+ } else if (memcmp(&desc->tls_cfg->flags, &desc->old_tls_cfg->flags, sizeof(desc->tls_cfg->flags))) {
+ tls_changed = 1;
+ }
+
+ if (tls_changed) {
+ ast_debug(1, "Changed parameters for %s found\n", desc->name);
+ }
+ }
/* Do nothing if nothing has changed */
- if (!ast_sockaddr_cmp(&desc->old_address, &desc->local_address)) {
+ if (!tls_changed && !ast_sockaddr_cmp(&desc->old_address, &desc->local_address)) {
ast_debug(1, "Nothing changed in %s\n", desc->name);
return;
}
@@ -1134,6 +1197,22 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc)
/* Set current info */
ast_sockaddr_copy(&desc->old_address, &desc->local_address);
+ if (desc->old_tls_cfg) {
+ ast_free(desc->old_tls_cfg->certfile);
+ ast_free(desc->old_tls_cfg->pvtfile);
+ ast_free(desc->old_tls_cfg->cipher);
+ ast_free(desc->old_tls_cfg->cafile);
+ ast_free(desc->old_tls_cfg->capath);
+ desc->old_tls_cfg->certfile = ast_strdup(desc->tls_cfg->certfile);
+ desc->old_tls_cfg->pvtfile = ast_strdup(desc->tls_cfg->pvtfile);
+ desc->old_tls_cfg->cipher = ast_strdup(desc->tls_cfg->cipher);
+ desc->old_tls_cfg->cafile = ast_strdup(desc->tls_cfg->cafile);
+ desc->old_tls_cfg->capath = ast_strdup(desc->tls_cfg->capath);
+ memcpy(desc->old_tls_cfg->certhash, desc->tls_cfg->certhash, 41);
+ memcpy(desc->old_tls_cfg->pvthash, desc->tls_cfg->pvthash, 41);
+ memcpy(desc->old_tls_cfg->cahash, desc->tls_cfg->cahash, 41);
+ memcpy(&desc->old_tls_cfg->flags, &desc->tls_cfg->flags, sizeof(desc->old_tls_cfg->flags));
+ }
return;
@@ -1179,6 +1258,17 @@ void ast_tcptls_server_stop(struct ast_tcptls_session_args *desc)
close(desc->accept_fd);
}
desc->accept_fd = -1;
+
+ if (desc->old_tls_cfg) {
+ ast_free(desc->old_tls_cfg->certfile);
+ ast_free(desc->old_tls_cfg->pvtfile);
+ ast_free(desc->old_tls_cfg->cipher);
+ ast_free(desc->old_tls_cfg->cafile);
+ ast_free(desc->old_tls_cfg->capath);
+ ast_free(desc->old_tls_cfg);
+ desc->old_tls_cfg = NULL;
+ }
+
ast_debug(2, "Stopped server :: %s\n", desc->name);
}
diff --git a/main/utils.c b/main/utils.c
index 03bead2..de7ff8f 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -1453,7 +1453,9 @@ int ast_careful_fwrite(FILE *f, int fd, const char *src, size_t len, int timeout
if (ferror(f) && errno != EINTR && errno != EAGAIN) {
/* fatal error from fwrite() */
- if (!feof(f)) {
+ if (errno == EPIPE) {
+ ast_debug(1, "fwrite() failed due to reading end being closed: EPIPE\n");
+ } else if (!feof(f)) {
/* Don't spam the logs if it was just that the connection is closed. */
ast_log(LOG_ERROR, "fwrite() returned error: %s\n", strerror(errno));
}
@@ -1486,8 +1488,12 @@ int ast_careful_fwrite(FILE *f, int fd, const char *src, size_t len, int timeout
continue;
}
if (errno && !feof(f)) {
- /* Don't spam the logs if it was just that the connection is closed. */
- ast_log(LOG_ERROR, "fflush() returned error: %s\n", strerror(errno));
+ if (errno == EPIPE) {
+ ast_debug(1, "fflush() failed due to reading end being closed: EPIPE\n");
+ } else {
+ /* Don't spam the logs if it was just that the connection is closed. */
+ ast_log(LOG_ERROR, "fflush() returned error: %s\n", strerror(errno));
+ }
}
n = -1;
break;
@@ -2425,6 +2431,18 @@ char *ast_utils_which(const char *binary, char *fullpath, size_t fullpath_size)
return NULL;
}
+int ast_check_ipv6(void)
+{
+ int udp6_socket = socket(AF_INET6, SOCK_DGRAM, 0);
+
+ if (udp6_socket < 0) {
+ return 0;
+ }
+
+ close(udp6_socket);
+ return 1;
+}
+
void DO_CRASH_NORETURN ast_do_crash(void)
{
#if defined(DO_CRASH)
diff --git a/makeopts.in b/makeopts.in
index 5ad2ced..3f92562 100644
--- a/makeopts.in
+++ b/makeopts.in
@@ -28,6 +28,7 @@ WGET=@WGET@
FETCH=@FETCH@
DOWNLOAD=@DOWNLOAD@
DOWNLOAD_TO_STDOUT=@DOWNLOAD_TO_STDOUT@
+DOWNLOAD_MAX_TIMEOUT=@DOWNLOAD_MAX_TIMEOUT@
SOUNDS_CACHE_DIR=@SOUNDS_CACHE_DIR@
EXTERNALS_CACHE_DIR=@EXTERNALS_CACHE_DIR@
RUBBER=@RUBBER@
@@ -46,6 +47,7 @@ TAR=@TAR@
PATCH=@PATCH@
SED=@SED@
NM=@NM@
+CAT=@CAT@
BUILD_PLATFORM=@BUILD_PLATFORM@
BUILD_CPU=@BUILD_CPU@
diff --git a/res/ari/ari_websockets.c b/res/ari/ari_websockets.c
index f06a667..6a296dc 100644
--- a/res/ari/ari_websockets.c
+++ b/res/ari/ari_websockets.c
@@ -23,6 +23,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/ari.h"
#include "asterisk/astobj2.h"
#include "asterisk/http_websocket.h"
+#include "asterisk/stasis_app.h"
#include "internal.h"
/*! \file
@@ -139,6 +140,7 @@ struct ast_json *ast_ari_websocket_session_read(
ast_log(LOG_WARNING,
"WebSocket input failed to parse\n");
}
+
break;
default:
/* Ignore all other message types */
@@ -174,16 +176,20 @@ int ast_ari_websocket_session_write(struct ast_ari_websocket_session *session,
return -1;
}
-#ifdef AST_DEVMODE
- ast_debug(3, "Examining ARI event (length %u): \n%s\n", (unsigned int) strlen(str), str);
-#endif
if (ast_websocket_write_string(session->ws_session, str)) {
- ast_log(LOG_NOTICE, "Problem occurred during websocket write, websocket closed\n");
+ ast_log(LOG_NOTICE, "Problem occurred during websocket write to %s, websocket closed\n",
+ ast_sockaddr_stringify(ast_ari_websocket_session_get_remote_addr(session)));
return -1;
}
return 0;
}
+struct ast_sockaddr *ast_ari_websocket_session_get_remote_addr(
+ struct ast_ari_websocket_session *session)
+{
+ return ast_websocket_remote_address(session->ws_session);
+}
+
void ari_handle_websocket(struct ast_websocket_server *ws_server,
struct ast_tcptls_session_instance *ser, const char *uri,
enum ast_http_method method, struct ast_variable *get_params,
diff --git a/res/ari/cli.c b/res/ari/cli.c
index 8194079..90c1773 100644
--- a/res/ari/cli.c
+++ b/res/ari/cli.c
@@ -28,6 +28,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/astobj2.h"
#include "asterisk/cli.h"
+#include "asterisk/stasis_app.h"
#include "internal.h"
static char *ari_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
@@ -251,11 +252,185 @@ static char *ari_mkpasswd(struct ast_cli_entry *e, int cmd, struct ast_cli_args
return CLI_SUCCESS;
}
+static char *ari_show_apps(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ struct ao2_container *apps;
+ struct ao2_iterator it_apps;
+ char *app;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ari show apps";
+ e->usage =
+ "Usage: ari show apps\n"
+ " Lists all registered applications.\n"
+ ;
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ default:
+ break;
+ }
+
+ if (a->argc != 3) {
+ return CLI_SHOWUSAGE;
+ }
+
+ apps = stasis_app_get_all();
+ if (!apps) {
+ ast_cli(a->fd, "Unable to retrieve registered applications!\n");
+ return CLI_FAILURE;
+ }
+
+ ast_cli(a->fd, "Application Name \n");
+ ast_cli(a->fd, "=========================\n");
+ it_apps = ao2_iterator_init(apps, 0);
+ while ((app = ao2_iterator_next(&it_apps))) {
+ ast_cli(a->fd, "%-25.25s\n", app);
+ ao2_ref(app, -1);
+ }
+
+ ao2_iterator_destroy(&it_apps);
+ ao2_ref(apps, -1);
+
+ return CLI_SUCCESS;
+}
+
+struct app_complete {
+ /*! Nth app to search for */
+ int state;
+ /*! Which app currently on */
+ int which;
+};
+
+static int complete_ari_app_search(void *obj, void *arg, void *data, int flags)
+{
+ struct app_complete *search = data;
+
+ if (++search->which > search->state) {
+ return CMP_MATCH;
+ }
+ return 0;
+}
+
+static char *complete_ari_app(struct ast_cli_args *a, int include_all)
+{
+ RAII_VAR(struct ao2_container *, apps, stasis_app_get_all(), ao2_cleanup);
+ RAII_VAR(char *, app, NULL, ao2_cleanup);
+
+ struct app_complete search = {
+ .state = a->n,
+ };
+
+ if (a->pos != 3) {
+ return NULL;
+ }
+
+ if (!apps) {
+ ast_cli(a->fd, "Error getting ARI applications\n");
+ return CLI_FAILURE;
+ }
+
+ if (include_all && ast_strlen_zero(a->word)) {
+ ast_str_container_add(apps, " all");
+ }
+
+ app = ao2_callback_data(apps,
+ ast_strlen_zero(a->word) ? 0 : OBJ_SEARCH_PARTIAL_KEY,
+ complete_ari_app_search, (char*)a->word, &search);
+
+ return app ? ast_strdup(app) : NULL;
+}
+
+static char *ari_show_app(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ void *app;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ari show app";
+ e->usage =
+ "Usage: ari show app <application>\n"
+ " Provide detailed information about a registered application.\n"
+ ;
+ return NULL;
+ case CLI_GENERATE:
+ return complete_ari_app(a, 0);
+ default:
+ break;
+ }
+
+ if (a->argc != 4) {
+ return CLI_SHOWUSAGE;
+ }
+
+ app = stasis_app_get_by_name(a->argv[3]);
+ if (!app) {
+ return CLI_FAILURE;
+ }
+
+ stasis_app_to_cli(app, a);
+
+ ao2_ref(app, -1);
+
+ return CLI_SUCCESS;
+}
+
+static char *ari_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ void *app;
+ int debug;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ari set debug";
+ e->usage =
+ "Usage: ari set debug <application|all> <on|off>\n"
+ " Enable or disable debugging on a specific application.\n"
+ ;
+ return NULL;
+ case CLI_GENERATE:
+ return complete_ari_app(a, 1);
+ default:
+ break;
+ }
+
+ if (a->argc != 5) {
+ return CLI_SHOWUSAGE;
+ }
+
+ debug = !strcmp(a->argv[4], "on");
+
+ if (!strcmp(a->argv[3], "all")) {
+ stasis_app_set_global_debug(debug);
+ ast_cli(a->fd, "Debugging on all applications %s\n",
+ debug ? "enabled" : "disabled");
+ return CLI_SUCCESS;
+ }
+
+ app = stasis_app_get_by_name(a->argv[3]);
+ if (!app) {
+ return CLI_FAILURE;
+ }
+
+ stasis_app_set_debug(app, debug);
+ ast_cli(a->fd, "Debugging on '%s' %s\n",
+ stasis_app_name(app),
+ debug ? "enabled" : "disabled");
+
+ ao2_ref(app, -1);
+
+ return CLI_SUCCESS;
+}
+
static struct ast_cli_entry cli_ari[] = {
AST_CLI_DEFINE(ari_show, "Show ARI settings"),
AST_CLI_DEFINE(ari_show_users, "List ARI users"),
AST_CLI_DEFINE(ari_show_user, "List single ARI user"),
AST_CLI_DEFINE(ari_mkpasswd, "Encrypts a password"),
+ AST_CLI_DEFINE(ari_show_apps, "List registered ARI applications"),
+ AST_CLI_DEFINE(ari_show_app, "Display details of a registered ARI application"),
+ AST_CLI_DEFINE(ari_set_debug, "Enable/disable debugging of an ARI application"),
};
int ast_ari_cli_register(void) {
diff --git a/res/ari/resource_events.c b/res/ari/resource_events.c
index 71d54b4..535ce70 100644
--- a/res/ari/resource_events.c
+++ b/res/ari/resource_events.c
@@ -139,6 +139,15 @@ static void app_handler(void *data, const char *app_name,
ao2_lock(session);
if (session->ws_session) {
+ if (stasis_app_get_debug_by_name(app_name)) {
+ char *str = ast_json_dump_string_format(message, ast_ari_json_format());
+
+ ast_verbose("<--- Sending ARI event to %s --->\n%s\n",
+ ast_sockaddr_stringify(ast_ari_websocket_session_get_remote_addr(session->ws_session)),
+ str);
+ ast_json_free(str);
+ }
+
ast_ari_websocket_session_write(session->ws_session, message);
}
ao2_unlock(session);
diff --git a/res/res_agi.c b/res/res_agi.c
index 969c62d..cd0d621 100644
--- a/res/res_agi.c
+++ b/res/res_agi.c
@@ -4075,7 +4075,7 @@ static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, ch
break;
}
} else if (c) {
- ami_res = "Command Not Permitted on a dead channel";
+ ami_res = "Command Not Permitted on a dead channel or intercept routine";
resultcode = 511;
ast_agi_send(agi->fd, chan, "%d %s\n", resultcode, ami_res);
@@ -4111,6 +4111,8 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
const char *sighup_str;
const char *exit_on_hangup_str;
int exit_on_hangup;
+ /*! Running in an interception routine is like DeadAGI mode. No touchy the channel frames. */
+ int in_intercept = ast_channel_get_intercept_mode();
ast_channel_lock(chan);
sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
@@ -4145,7 +4147,7 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
}
}
ms = -1;
- if (dead) {
+ if (dead || in_intercept) {
c = ast_waitfor_nandfds(&chan, 0, &agi->ctrl, 1, NULL, &outfd, &ms);
} else if (!ast_check_hangup(chan)) {
c = ast_waitfor_nandfds(&chan, 1, &agi->ctrl, 1, NULL, &outfd, &ms);
@@ -4223,10 +4225,10 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
if (agidebug)
ast_verbose("<%s>AGI Rx << %s\n", ast_channel_name(chan), buf);
- cmd_status = agi_handle_command(chan, agi, buf, dead);
+ cmd_status = agi_handle_command(chan, agi, buf, dead || in_intercept);
switch (cmd_status) {
case AGI_RESULT_FAILURE:
- if (dead || !ast_check_hangup(chan)) {
+ if (dead || in_intercept || !ast_check_hangup(chan)) {
/* The failure was not because of a hangup. */
returnstatus = AGI_RESULT_FAILURE;
}
diff --git a/res/res_ari.c b/res/res_ari.c
index 4ff98ce..c6f81dc 100644
--- a/res/res_ari.c
+++ b/res/res_ari.c
@@ -147,6 +147,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/astobj2.h"
#include "asterisk/module.h"
#include "asterisk/paths.h"
+#include "asterisk/stasis_app.h"
#include <string.h>
#include <sys/stat.h>
@@ -490,7 +491,7 @@ static void handle_options(struct stasis_rest_handlers *handler,
void ast_ari_invoke(struct ast_tcptls_session_instance *ser,
const char *uri, enum ast_http_method method,
struct ast_variable *get_params, struct ast_variable *headers,
- struct ast_ari_response *response)
+ struct ast_json *body, struct ast_ari_response *response)
{
RAII_VAR(struct stasis_rest_handlers *, root, NULL, ao2_cleanup);
struct stasis_rest_handlers *handler;
@@ -505,8 +506,10 @@ void ast_ari_invoke(struct ast_tcptls_session_instance *ser,
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);
+
for (i = 0; found_handler == NULL && i < handler->num_children; ++i) {
struct stasis_rest_handlers *child = handler->children[i];
@@ -568,7 +571,7 @@ void ast_ari_invoke(struct ast_tcptls_session_instance *ser,
return;
}
- callback(ser, get_params, path_vars, headers, response);
+ callback(ser, get_params, path_vars, headers, body, response);
if (response->message == NULL && response->response_code == 0) {
/* Really should not happen */
ast_log(LOG_ERROR, "ARI %s %s not implemented\n",
@@ -878,6 +881,10 @@ static int ast_ari_callback(struct ast_tcptls_session_instance *ser,
RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
struct ast_ari_response response = {};
RAII_VAR(struct ast_variable *, post_vars, NULL, ast_variables_destroy);
+ struct ast_variable *var;
+ const char *app_name = NULL;
+ RAII_VAR(struct ast_json *, body, ast_json_null(), ast_json_free);
+ int debug_app = 0;
if (!response_body) {
ast_http_request_close_on_completion(ser);
@@ -925,6 +932,25 @@ static int ast_ari_callback(struct ast_tcptls_session_instance *ser,
"Bad Request", "Error parsing request body");
goto request_failed;
}
+
+ /* Look for a JSON request entity only if there were no post_vars.
+ * If there were post_vars, then the request body would already have
+ * been consumed and can not be read again.
+ */
+ body = ast_http_get_json(ser, headers);
+ if (!body) {
+ switch (errno) {
+ case EFBIG:
+ ast_ari_response_error(&response, 413, "Request Entity Too Large", "Request body too large");
+ goto request_failed;
+ case ENOMEM:
+ ast_ari_response_error(&response, 500, "Internal Server Error", "Error processing request");
+ goto request_failed;
+ case EIO:
+ ast_ari_response_error(&response, 400, "Bad Request", "Error parsing request body");
+ goto request_failed;
+ }
+ }
}
if (get_params == NULL) {
get_params = post_vars;
@@ -941,6 +967,41 @@ static int ast_ari_callback(struct ast_tcptls_session_instance *ser,
get_params = post_vars;
}
+ /* At this point, get_params will contain post_vars (if any) */
+ app_name = ast_variable_find_in_list(get_params, "app");
+ if (!app_name) {
+ struct ast_json *app = ast_json_object_get(body, "app");
+
+ app_name = (app ? ast_json_string_get(app) : NULL);
+ }
+
+ /* stasis_app_get_debug_by_name returns an "||" of the app's debug flag
+ * and the global debug flag.
+ */
+ debug_app = stasis_app_get_debug_by_name(app_name);
+ if (debug_app) {
+ struct ast_str *buf = ast_str_create(512);
+ char *str = ast_json_dump_string_format(body, ast_ari_json_format());
+
+ if (!buf) {
+ ast_http_request_close_on_completion(ser);
+ ast_http_error(ser, 500, "Server Error", "Out of memory");
+ goto request_failed;
+ }
+
+ ast_str_append(&buf, 0, "<--- ARI request received from: %s --->\n",
+ ast_sockaddr_stringify(&ser->remote_address));
+ for (var = headers; var; var = var->next) {
+ ast_str_append(&buf, 0, "%s: %s\n", var->name, var->value);
+ }
+ for (var = get_params; var; var = var->next) {
+ ast_str_append(&buf, 0, "%s: %s\n", var->name, var->value);
+ }
+ ast_verbose("%sbody:\n%s\n\n", ast_str_buffer(buf), str);
+ ast_json_free(str);
+ ast_free(buf);
+ }
+
user = authenticate_user(get_params, headers);
if (response.response_code > 0) {
/* POST parameter processing error. Do nothing. */
@@ -979,7 +1040,7 @@ static int ast_ari_callback(struct ast_tcptls_session_instance *ser,
}
} else {
/* Other RESTful resources */
- ast_ari_invoke(ser, uri, method, get_params, headers,
+ ast_ari_invoke(ser, uri, method, get_params, headers, body,
&response);
}
@@ -991,6 +1052,7 @@ static int ast_ari_callback(struct ast_tcptls_session_instance *ser,
}
request_failed:
+
/* If you explicitly want to have no content, set message to
* ast_json_null().
*/
@@ -1013,8 +1075,13 @@ request_failed:
}
}
- ast_debug(3, "Examining ARI response:\n%d %s\n%s\n%s\n", response.response_code,
- response.response_text, ast_str_buffer(response.headers), ast_str_buffer(response_body));
+ if (debug_app) {
+ ast_verbose("<--- Sending ARI response to %s --->\n%d %s\n%s%s\n\n",
+ ast_sockaddr_stringify(&ser->remote_address), response.response_code,
+ response.response_text, ast_str_buffer(response.headers),
+ ast_str_buffer(response_body));
+ }
+
ast_http_send(ser, method, response.response_code,
response.response_text, response.headers, response_body,
0, 0);
diff --git a/res/res_ari_applications.c b/res/res_ari_applications.c
index dd868a6..ac2c3ba 100644
--- a/res/res_ari_applications.c
+++ b/res/res_ari_applications.c
@@ -62,10 +62,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
static void ast_ari_applications_list_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_applications_list_args args = {};
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -113,11 +112,10 @@ fin: __attribute__((unused))
static void ast_ari_applications_get_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_applications_get_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -210,11 +208,10 @@ int ast_ari_applications_subscribe_parse_body(
static void ast_ari_applications_subscribe_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_applications_subscribe_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -272,21 +269,6 @@ static void ast_ari_applications_subscribe_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_applications_subscribe_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -376,11 +358,10 @@ int ast_ari_applications_unsubscribe_parse_body(
static void ast_ari_applications_unsubscribe_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_applications_unsubscribe_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -438,21 +419,6 @@ static void ast_ari_applications_unsubscribe_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_applications_unsubscribe_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
diff --git a/res/res_ari_asterisk.c b/res/res_ari_asterisk.c
index b52a2a7..b1680e3 100644
--- a/res/res_ari_asterisk.c
+++ b/res/res_ari_asterisk.c
@@ -62,11 +62,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
static void ast_ari_asterisk_get_object_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_asterisk_get_object_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -135,11 +134,10 @@ int ast_ari_asterisk_update_object_parse_body(
static void ast_ari_asterisk_update_object_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_asterisk_update_object_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -157,21 +155,6 @@ static void ast_ari_asterisk_update_object_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
args.fields = body;
ast_ari_asterisk_update_object(headers, &args, response);
#if defined(AST_DEVMODE)
@@ -218,11 +201,10 @@ fin: __attribute__((unused))
static void ast_ari_asterisk_delete_object_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_asterisk_delete_object_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -322,11 +304,10 @@ int ast_ari_asterisk_get_info_parse_body(
static void ast_ari_asterisk_get_info_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_asterisk_get_info_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -378,21 +359,6 @@ static void ast_ari_asterisk_get_info_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_asterisk_get_info_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -441,10 +407,9 @@ fin: __attribute__((unused))
static void ast_ari_asterisk_list_modules_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_asterisk_list_modules_args args = {};
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -492,11 +457,10 @@ fin: __attribute__((unused))
static void ast_ari_asterisk_get_module_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_asterisk_get_module_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -552,11 +516,10 @@ fin: __attribute__((unused))
static void ast_ari_asterisk_load_module_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_asterisk_load_module_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -611,11 +574,10 @@ fin: __attribute__((unused))
static void ast_ari_asterisk_unload_module_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_asterisk_unload_module_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -671,11 +633,10 @@ fin: __attribute__((unused))
static void ast_ari_asterisk_reload_module_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_asterisk_reload_module_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -731,10 +692,9 @@ fin: __attribute__((unused))
static void ast_ari_asterisk_list_log_channels_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_asterisk_list_log_channels_args args = {};
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -795,11 +755,10 @@ int ast_ari_asterisk_add_log_parse_body(
static void ast_ari_asterisk_add_log_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_asterisk_add_log_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -817,21 +776,6 @@ static void ast_ari_asterisk_add_log_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_asterisk_add_log_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -880,11 +824,10 @@ fin: __attribute__((unused))
static void ast_ari_asterisk_delete_log_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_asterisk_delete_log_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -939,11 +882,10 @@ fin: __attribute__((unused))
static void ast_ari_asterisk_rotate_log_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_asterisk_rotate_log_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -1011,11 +953,10 @@ int ast_ari_asterisk_get_global_var_parse_body(
static void ast_ari_asterisk_get_global_var_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_asterisk_get_global_var_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -1027,21 +968,6 @@ static void ast_ari_asterisk_get_global_var_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_asterisk_get_global_var_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -1106,11 +1032,10 @@ int ast_ari_asterisk_set_global_var_parse_body(
static void ast_ari_asterisk_set_global_var_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_asterisk_set_global_var_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -1125,21 +1050,6 @@ static void ast_ari_asterisk_set_global_var_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_asterisk_set_global_var_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
diff --git a/res/res_ari_bridges.c b/res/res_ari_bridges.c
index 458192d..2889c15 100644
--- a/res/res_ari_bridges.c
+++ b/res/res_ari_bridges.c
@@ -62,10 +62,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
static void ast_ari_bridges_list_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_bridges_list_args args = {};
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -134,11 +133,10 @@ int ast_ari_bridges_create_parse_body(
static void ast_ari_bridges_create_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_bridges_create_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -156,21 +154,6 @@ static void ast_ari_bridges_create_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_bridges_create_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -234,11 +217,10 @@ int ast_ari_bridges_create_with_id_parse_body(
static void ast_ari_bridges_create_with_id_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_bridges_create_with_id_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -259,21 +241,6 @@ static void ast_ari_bridges_create_with_id_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_bridges_create_with_id_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -320,11 +287,10 @@ fin: __attribute__((unused))
static void ast_ari_bridges_get_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_bridges_get_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -379,11 +345,10 @@ fin: __attribute__((unused))
static void ast_ari_bridges_destroy_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_bridges_destroy_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -480,11 +445,10 @@ int ast_ari_bridges_add_channel_parse_body(
static void ast_ari_bridges_add_channel_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_bridges_add_channel_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -545,21 +509,6 @@ static void ast_ari_bridges_add_channel_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_bridges_add_channel_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -650,11 +599,10 @@ int ast_ari_bridges_remove_channel_parse_body(
static void ast_ari_bridges_remove_channel_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_bridges_remove_channel_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -712,21 +660,6 @@ static void ast_ari_bridges_remove_channel_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_bridges_remove_channel_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -779,11 +712,10 @@ fin: __attribute__((unused))
static void ast_ari_bridges_set_video_source_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_bridges_set_video_source_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -843,11 +775,10 @@ fin: __attribute__((unused))
static void ast_ari_bridges_clear_video_source_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_bridges_clear_video_source_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -915,11 +846,10 @@ int ast_ari_bridges_start_moh_parse_body(
static void ast_ari_bridges_start_moh_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_bridges_start_moh_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -937,21 +867,6 @@ static void ast_ari_bridges_start_moh_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_bridges_start_moh_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -1000,11 +915,10 @@ fin: __attribute__((unused))
static void ast_ari_bridges_stop_moh_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_bridges_stop_moh_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -1089,11 +1003,10 @@ int ast_ari_bridges_play_parse_body(
static void ast_ari_bridges_play_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_bridges_play_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -1123,21 +1036,6 @@ static void ast_ari_bridges_play_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_bridges_play_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -1211,11 +1109,10 @@ int ast_ari_bridges_play_with_id_parse_body(
static void ast_ari_bridges_play_with_id_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_bridges_play_with_id_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -1245,21 +1142,6 @@ static void ast_ari_bridges_play_with_id_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_bridges_play_with_id_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -1345,11 +1227,10 @@ int ast_ari_bridges_record_parse_body(
static void ast_ari_bridges_record_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_bridges_record_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -1385,21 +1266,6 @@ static void ast_ari_bridges_record_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_bridges_record_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c
index 8cb3388..fca0cef 100644
--- a/res/res_ari_channels.c
+++ b/res/res_ari_channels.c
@@ -62,10 +62,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
static void ast_ari_channels_list_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_list_args args = {};
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -174,11 +173,10 @@ int ast_ari_channels_originate_parse_body(
static void ast_ari_channels_originate_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_originate_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -226,21 +224,6 @@ static void ast_ari_channels_originate_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
args.variables = body;
ast_ari_channels_originate(headers, &args, response);
#if defined(AST_DEVMODE)
@@ -286,11 +269,10 @@ fin: __attribute__((unused))
static void ast_ari_channels_get_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_get_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -402,11 +384,10 @@ int ast_ari_channels_originate_with_id_parse_body(
static void ast_ari_channels_originate_with_id_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_originate_with_id_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -457,21 +438,6 @@ static void ast_ari_channels_originate_with_id_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
args.variables = body;
ast_ari_channels_originate_with_id(headers, &args, response);
#if defined(AST_DEVMODE)
@@ -530,11 +496,10 @@ int ast_ari_channels_hangup_parse_body(
static void ast_ari_channels_hangup_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_hangup_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -552,21 +517,6 @@ static void ast_ari_channels_hangup_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_channels_hangup_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -640,11 +590,10 @@ int ast_ari_channels_continue_in_dialplan_parse_body(
static void ast_ari_channels_continue_in_dialplan_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_continue_in_dialplan_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -671,21 +620,6 @@ static void ast_ari_channels_continue_in_dialplan_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_channels_continue_in_dialplan_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -747,11 +681,10 @@ int ast_ari_channels_redirect_parse_body(
static void ast_ari_channels_redirect_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_redirect_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -769,21 +702,6 @@ static void ast_ari_channels_redirect_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_channels_redirect_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -834,11 +752,10 @@ fin: __attribute__((unused))
static void ast_ari_channels_answer_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_answer_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -894,11 +811,10 @@ fin: __attribute__((unused))
static void ast_ari_channels_ring_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_ring_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -954,11 +870,10 @@ fin: __attribute__((unused))
static void ast_ari_channels_ring_stop_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_ring_stop_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -1043,11 +958,10 @@ int ast_ari_channels_send_dtmf_parse_body(
static void ast_ari_channels_send_dtmf_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_send_dtmf_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -1077,21 +991,6 @@ static void ast_ari_channels_send_dtmf_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_channels_send_dtmf_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -1154,11 +1053,10 @@ int ast_ari_channels_mute_parse_body(
static void ast_ari_channels_mute_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_mute_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -1176,21 +1074,6 @@ static void ast_ari_channels_mute_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_channels_mute_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -1252,11 +1135,10 @@ int ast_ari_channels_unmute_parse_body(
static void ast_ari_channels_unmute_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_unmute_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -1274,21 +1156,6 @@ static void ast_ari_channels_unmute_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_channels_unmute_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -1337,11 +1204,10 @@ fin: __attribute__((unused))
static void ast_ari_channels_hold_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_hold_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -1397,11 +1263,10 @@ fin: __attribute__((unused))
static void ast_ari_channels_unhold_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_unhold_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -1470,11 +1335,10 @@ int ast_ari_channels_start_moh_parse_body(
static void ast_ari_channels_start_moh_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_start_moh_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -1492,21 +1356,6 @@ static void ast_ari_channels_start_moh_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_channels_start_moh_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -1555,11 +1404,10 @@ fin: __attribute__((unused))
static void ast_ari_channels_stop_moh_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_stop_moh_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -1615,11 +1463,10 @@ fin: __attribute__((unused))
static void ast_ari_channels_start_silence_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_start_silence_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -1675,11 +1522,10 @@ fin: __attribute__((unused))
static void ast_ari_channels_stop_silence_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_stop_silence_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -1764,11 +1610,10 @@ int ast_ari_channels_play_parse_body(
static void ast_ari_channels_play_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_play_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -1798,21 +1643,6 @@ static void ast_ari_channels_play_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_channels_play_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -1886,11 +1716,10 @@ int ast_ari_channels_play_with_id_parse_body(
static void ast_ari_channels_play_with_id_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_play_with_id_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -1920,21 +1749,6 @@ static void ast_ari_channels_play_with_id_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_channels_play_with_id_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -2020,11 +1834,10 @@ int ast_ari_channels_record_parse_body(
static void ast_ari_channels_record_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_record_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -2060,21 +1873,6 @@ static void ast_ari_channels_record_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_channels_record_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -2138,11 +1936,10 @@ int ast_ari_channels_get_channel_var_parse_body(
static void ast_ari_channels_get_channel_var_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_get_channel_var_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -2160,21 +1957,6 @@ static void ast_ari_channels_get_channel_var_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_channels_get_channel_var_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -2241,11 +2023,10 @@ int ast_ari_channels_set_channel_var_parse_body(
static void ast_ari_channels_set_channel_var_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_set_channel_var_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -2266,21 +2047,6 @@ static void ast_ari_channels_set_channel_var_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_channels_set_channel_var_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -2359,11 +2125,10 @@ int ast_ari_channels_snoop_channel_parse_body(
static void ast_ari_channels_snoop_channel_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_snoop_channel_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -2393,21 +2158,6 @@ static void ast_ari_channels_snoop_channel_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_channels_snoop_channel_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -2481,11 +2231,10 @@ int ast_ari_channels_snoop_channel_with_id_parse_body(
static void ast_ari_channels_snoop_channel_with_id_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_channels_snoop_channel_with_id_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -2515,21 +2264,6 @@ static void ast_ari_channels_snoop_channel_with_id_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_channels_snoop_channel_with_id_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
diff --git a/res/res_ari_device_states.c b/res/res_ari_device_states.c
index 6d5d19f..cf0b7a9 100644
--- a/res/res_ari_device_states.c
+++ b/res/res_ari_device_states.c
@@ -62,10 +62,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
static void ast_ari_device_states_list_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_device_states_list_args args = {};
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -113,11 +112,10 @@ fin: __attribute__((unused))
static void ast_ari_device_states_get_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_device_states_get_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -184,11 +182,10 @@ int ast_ari_device_states_update_parse_body(
static void ast_ari_device_states_update_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_device_states_update_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -206,21 +203,6 @@ static void ast_ari_device_states_update_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_device_states_update_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -269,11 +251,10 @@ fin: __attribute__((unused))
static void ast_ari_device_states_delete_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_device_states_delete_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
diff --git a/res/res_ari_endpoints.c b/res/res_ari_endpoints.c
index e3ade43..4a5ddd9 100644
--- a/res/res_ari_endpoints.c
+++ b/res/res_ari_endpoints.c
@@ -62,10 +62,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
static void ast_ari_endpoints_list_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_endpoints_list_args args = {};
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -134,11 +133,10 @@ int ast_ari_endpoints_send_message_parse_body(
static void ast_ari_endpoints_send_message_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_endpoints_send_message_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -156,21 +154,6 @@ static void ast_ari_endpoints_send_message_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
args.variables = body;
ast_ari_endpoints_send_message(headers, &args, response);
#if defined(AST_DEVMODE)
@@ -216,11 +199,10 @@ fin: __attribute__((unused))
static void ast_ari_endpoints_list_by_tech_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_endpoints_list_by_tech_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -275,11 +257,10 @@ fin: __attribute__((unused))
static void ast_ari_endpoints_get_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_endpoints_get_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -355,11 +336,10 @@ int ast_ari_endpoints_send_message_to_endpoint_parse_body(
static void ast_ari_endpoints_send_message_to_endpoint_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_endpoints_send_message_to_endpoint_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -383,21 +363,6 @@ static void ast_ari_endpoints_send_message_to_endpoint_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
args.variables = body;
ast_ari_endpoints_send_message_to_endpoint(headers, &args, response);
#if defined(AST_DEVMODE)
diff --git a/res/res_ari_events.c b/res/res_ari_events.c
index e85db4c..d102428 100644
--- a/res/res_ari_events.c
+++ b/res/res_ari_events.c
@@ -288,11 +288,10 @@ int ast_ari_events_user_event_parse_body(
static void ast_ari_events_user_event_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_events_user_event_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -353,21 +352,6 @@ static void ast_ari_events_user_event_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
args.variables = body;
ast_ari_events_user_event(headers, &args, response);
#if defined(AST_DEVMODE)
diff --git a/res/res_ari_mailboxes.c b/res/res_ari_mailboxes.c
index 6ed16a8..8e0648b 100644
--- a/res/res_ari_mailboxes.c
+++ b/res/res_ari_mailboxes.c
@@ -62,10 +62,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
static void ast_ari_mailboxes_list_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_mailboxes_list_args args = {};
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -113,11 +112,10 @@ fin: __attribute__((unused))
static void ast_ari_mailboxes_get_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_mailboxes_get_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -189,11 +187,10 @@ int ast_ari_mailboxes_update_parse_body(
static void ast_ari_mailboxes_update_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_mailboxes_update_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -214,21 +211,6 @@ static void ast_ari_mailboxes_update_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_mailboxes_update_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -276,11 +258,10 @@ fin: __attribute__((unused))
static void ast_ari_mailboxes_delete_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_mailboxes_delete_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
diff --git a/res/res_ari_playbacks.c b/res/res_ari_playbacks.c
index 2336033..a0ebd66 100644
--- a/res/res_ari_playbacks.c
+++ b/res/res_ari_playbacks.c
@@ -62,11 +62,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
static void ast_ari_playbacks_get_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_playbacks_get_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -121,11 +120,10 @@ fin: __attribute__((unused))
static void ast_ari_playbacks_stop_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_playbacks_stop_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -193,11 +191,10 @@ int ast_ari_playbacks_control_parse_body(
static void ast_ari_playbacks_control_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_playbacks_control_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -215,21 +212,6 @@ static void ast_ari_playbacks_control_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_playbacks_control_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
diff --git a/res/res_ari_recordings.c b/res/res_ari_recordings.c
index 04ce0ac..bdcf676 100644
--- a/res/res_ari_recordings.c
+++ b/res/res_ari_recordings.c
@@ -62,10 +62,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
static void ast_ari_recordings_list_stored_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_recordings_list_stored_args args = {};
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -113,11 +112,10 @@ fin: __attribute__((unused))
static void ast_ari_recordings_get_stored_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_recordings_get_stored_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -172,11 +170,10 @@ fin: __attribute__((unused))
static void ast_ari_recordings_delete_stored_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_recordings_delete_stored_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -244,11 +241,10 @@ int ast_ari_recordings_copy_stored_parse_body(
static void ast_ari_recordings_copy_stored_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_recordings_copy_stored_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -266,21 +262,6 @@ static void ast_ari_recordings_copy_stored_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_recordings_copy_stored_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -329,11 +310,10 @@ fin: __attribute__((unused))
static void ast_ari_recordings_get_live_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_recordings_get_live_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -388,11 +368,10 @@ fin: __attribute__((unused))
static void ast_ari_recordings_cancel_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_recordings_cancel_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -447,11 +426,10 @@ fin: __attribute__((unused))
static void ast_ari_recordings_stop_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_recordings_stop_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -506,11 +484,10 @@ fin: __attribute__((unused))
static void ast_ari_recordings_pause_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_recordings_pause_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -566,11 +543,10 @@ fin: __attribute__((unused))
static void ast_ari_recordings_unpause_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_recordings_unpause_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -626,11 +602,10 @@ fin: __attribute__((unused))
static void ast_ari_recordings_mute_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_recordings_mute_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -686,11 +661,10 @@ fin: __attribute__((unused))
static void ast_ari_recordings_unmute_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_recordings_unmute_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
diff --git a/res/res_ari_sounds.c b/res/res_ari_sounds.c
index 935025d..48fa204 100644
--- a/res/res_ari_sounds.c
+++ b/res/res_ari_sounds.c
@@ -79,11 +79,10 @@ int ast_ari_sounds_list_parse_body(
static void ast_ari_sounds_list_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_sounds_list_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
@@ -98,21 +97,6 @@ static void ast_ari_sounds_list_cb(
} else
{}
}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
if (ast_ari_sounds_list_parse_body(body, &args)) {
ast_ari_response_alloc_failed(response);
goto fin;
@@ -159,11 +143,10 @@ fin: __attribute__((unused))
static void ast_ari_sounds_get_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_sounds_get_args args = {};
struct ast_variable *i;
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
diff --git a/res/res_calendar_caldav.c b/res/res_calendar_caldav.c
index a8eac7c..6b4f908 100644
--- a/res/res_calendar_caldav.c
+++ b/res/res_calendar_caldav.c
@@ -482,7 +482,7 @@ static void handle_start_element(void *data, const xmlChar *fullname, const xmlC
{
struct xmlstate *state = data;
- if (!xmlStrcasecmp(fullname, BAD_CAST "C:calendar-data")) {
+ if (!xmlStrcasecmp(fullname, BAD_CAST "C:calendar-data") || !xmlStrcasecmp(fullname, BAD_CAST "caldav:calendar-data")) {
state->in_caldata = 1;
ast_str_reset(state->cdata);
}
@@ -496,7 +496,7 @@ static void handle_end_element(void *data, const xmlChar *name)
icalcomponent *iter;
icalcomponent *comp;
- if (xmlStrcasecmp(name, BAD_CAST "C:calendar-data")) {
+ if (xmlStrcasecmp(name, BAD_CAST "C:calendar-data") && xmlStrcasecmp(name, BAD_CAST "caldav:calendar-data")) {
return;
}
diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c
index 6f51820..6b0f00a 100644
--- a/res/res_musiconhold.c
+++ b/res/res_musiconhold.c
@@ -1433,6 +1433,7 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con
else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "alpha"))
ast_set_flag(mohclass, MOH_SORTALPHA);
else if (!strcasecmp(tmp->name, "format")) {
+ ao2_cleanup(mohclass->format);
mohclass->format = ast_format_cache_get(tmp->value);
if (!mohclass->format) {
ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", tmp->value);
@@ -1765,6 +1766,7 @@ static int load_moh_classes(int reload)
} else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "alpha")) {
ast_set_flag(class, MOH_SORTALPHA);
} else if (!strcasecmp(var->name, "format")) {
+ ao2_cleanup(class->format);
class->format = ast_format_cache_get(var->value);
if (!class->format) {
ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
diff --git a/res/res_pjproject.c b/res/res_pjproject.c
index 08699f3..e02515b 100644
--- a/res/res_pjproject.c
+++ b/res/res_pjproject.c
@@ -41,6 +41,27 @@
<configInfo name="res_pjproject" language="en_US">
<synopsis>pjproject common configuration</synopsis>
<configFile name="pjproject.conf">
+ <configObject name="startup">
+ <synopsis>Asterisk startup time options for PJPROJECT</synopsis>
+ <description>
+ <note><para>The id of this object, as well as its type, must be
+ 'startup' or it won't be found.</para></note>
+ </description>
+ <configOption name="type">
+ <synopsis>Must be of type 'startup'.</synopsis>
+ </configOption>
+ <configOption name="log_level" default="2">
+ <synopsis>Initial maximum pjproject logging level to log.</synopsis>
+ <description>
+ <para>Valid values are: 0-6, and default</para>
+ <note><para>
+ This option is needed very early in the startup process
+ so it can only be read from config files because the
+ modules for other methods have not been loaded yet.
+ </para></note>
+ </description>
+ </configOption>
+ </configObject>
<configObject name="log_mappings">
<synopsis>PJPROJECT to Asterisk Log Level Mapping</synopsis>
<description><para>Warnings and errors in the pjproject libraries are generally handled
@@ -64,7 +85,7 @@
<configOption name="asterisk_notice" default="">
<synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_NOTICE.</synopsis>
</configOption>
- <configOption name="asterisk_debug" default="3,4,5">
+ <configOption name="asterisk_debug" default="3,4,5,6">
<synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_DEBUG.</synopsis>
</configOption>
<configOption name="asterisk_verbose" default="">
@@ -84,6 +105,7 @@ ASTERISK_REGISTER_FILE()
#include <pjsip.h>
#include <pj/log.h>
+#include "asterisk/options.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/cli.h"
@@ -146,9 +168,11 @@ static struct log_mappings *get_log_mappings(void)
static int get_log_level(int pj_level)
{
- RAII_VAR(struct log_mappings *, mappings, get_log_mappings(), ao2_cleanup);
+ int mapped_level;
unsigned char l;
+ struct log_mappings *mappings;
+ mappings = get_log_mappings();
if (!mappings) {
return __LOG_ERROR;
}
@@ -156,18 +180,21 @@ static int get_log_level(int pj_level)
l = '0' + fmin(pj_level, 9);
if (strchr(mappings->asterisk_error, l)) {
- return __LOG_ERROR;
+ mapped_level = __LOG_ERROR;
} else if (strchr(mappings->asterisk_warning, l)) {
- return __LOG_WARNING;
+ mapped_level = __LOG_WARNING;
} else if (strchr(mappings->asterisk_notice, l)) {
- return __LOG_NOTICE;
+ mapped_level = __LOG_NOTICE;
} else if (strchr(mappings->asterisk_verbose, l)) {
- return __LOG_VERBOSE;
+ mapped_level = __LOG_VERBOSE;
} else if (strchr(mappings->asterisk_debug, l)) {
- return __LOG_DEBUG;
+ mapped_level = __LOG_DEBUG;
+ } else {
+ mapped_level = __LOG_SUPPRESS;
}
- return __LOG_SUPPRESS;
+ ao2_ref(mappings, -1);
+ return mapped_level;
}
static void log_forwarder(int level, const char *data, int len)
@@ -194,13 +221,6 @@ static void log_forwarder(int level, const char *data, int len)
return;
}
- if (ast_level == __LOG_DEBUG) {
- /* Obey the debug level for res_pjproject */
- if (!DEBUG_ATLEAST(level)) {
- return;
- }
- }
-
/* PJPROJECT uses indention to indicate function call depth. We'll prepend
* log statements with a tab so they'll have a better shot at lining
* up */
@@ -351,9 +371,99 @@ static char *handle_pjproject_show_log_mappings(struct ast_cli_entry *e, int cmd
return CLI_SUCCESS;
}
+struct max_pjproject_log_level_check {
+ /*!
+ * Compile time sanity check to determine if
+ * MAX_PJ_LOG_MAX_LEVEL matches CLI syntax.
+ */
+ char check[1 / (6 == MAX_PJ_LOG_MAX_LEVEL)];
+};
+
+static char *handle_pjproject_set_log_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ int level_new;
+ int level_old;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "pjproject set log level {default|0|1|2|3|4|5|6}";
+ e->usage =
+ "Usage: pjproject set log level {default|<level>}\n"
+ "\n"
+ " Set the maximum active pjproject logging level.\n"
+ " See pjproject.conf.sample for additional information\n"
+ " about the various levels pjproject uses.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc != 5) {
+ return CLI_SHOWUSAGE;
+ }
+
+ if (!strcasecmp(a->argv[4], "default")) {
+ level_new = DEFAULT_PJ_LOG_MAX_LEVEL;
+ } else {
+ if (sscanf(a->argv[4], "%30d", &level_new) != 1
+ || level_new < 0 || MAX_PJ_LOG_MAX_LEVEL < level_new) {
+ return CLI_SHOWUSAGE;
+ }
+ }
+
+ /* Update pjproject logging level */
+ if (ast_pjproject_max_log_level < level_new) {
+ level_new = ast_pjproject_max_log_level;
+ ast_cli(a->fd,
+ "Asterisk built or linked with pjproject PJ_LOG_MAX_LEVEL=%d.\n"
+ "Lowering request to the max supported level.\n",
+ ast_pjproject_max_log_level);
+ }
+ level_old = ast_option_pjproject_log_level;
+ if (level_old == level_new) {
+ ast_cli(a->fd, "pjproject log level is still %d.\n", level_old);
+ } else {
+ ast_cli(a->fd, "pjproject log level was %d and is now %d.\n",
+ level_old, level_new);
+ ast_option_pjproject_log_level = level_new;
+ pj_log_set_level(level_new);
+ }
+
+ return CLI_SUCCESS;
+}
+
+static char *handle_pjproject_show_log_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "pjproject show log level";
+ e->usage =
+ "Usage: pjproject show log level\n"
+ "\n"
+ " Show the current maximum active pjproject logging level.\n"
+ " See pjproject.conf.sample for additional information\n"
+ " about the various levels pjproject uses.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc != 4) {
+ return CLI_SHOWUSAGE;
+ }
+
+ ast_cli(a->fd, "pjproject log level is %d.%s\n",
+ ast_option_pjproject_log_level,
+ ast_option_pjproject_log_level == DEFAULT_PJ_LOG_MAX_LEVEL ? " (default)" : "");
+
+ return CLI_SUCCESS;
+}
+
static struct ast_cli_entry pjproject_cli[] = {
+ AST_CLI_DEFINE(handle_pjproject_set_log_level, "Set the maximum active pjproject logging level"),
AST_CLI_DEFINE(handle_pjproject_show_buildopts, "Show the compiled config of the pjproject in use"),
AST_CLI_DEFINE(handle_pjproject_show_log_mappings, "Show pjproject to Asterisk log mappings"),
+ AST_CLI_DEFINE(handle_pjproject_show_log_level, "Show the maximum active pjproject logging level"),
};
static int load_module(void)
@@ -387,10 +497,11 @@ static int load_module(void)
}
ast_string_field_set(default_log_mappings, asterisk_error, "0,1");
ast_string_field_set(default_log_mappings, asterisk_warning, "2");
- ast_string_field_set(default_log_mappings, asterisk_debug, "3,4,5");
+ ast_string_field_set(default_log_mappings, asterisk_debug, "3,4,5,6");
ast_sorcery_load(pjproject_sorcery);
+ AST_PJPROJECT_INIT_LOG_LEVEL();
pj_init();
decor_orig = pj_log_get_decor();
@@ -405,9 +516,22 @@ static int load_module(void)
*/
pj_log_set_log_func(capture_buildopts_cb);
pj_log_set_decor(0);
+ pj_log_set_level(MAX_PJ_LOG_MAX_LEVEL);/* Set level to guarantee the dump output. */
pj_dump_config();
pj_log_set_decor(PJ_LOG_HAS_SENDER | PJ_LOG_HAS_INDENT);
pj_log_set_log_func(log_forwarder);
+ if (ast_pjproject_max_log_level < ast_option_pjproject_log_level) {
+ ast_log(LOG_WARNING,
+ "Asterisk built or linked with pjproject PJ_LOG_MAX_LEVEL=%d which is too low for startup level: %d.\n",
+ ast_pjproject_max_log_level, ast_option_pjproject_log_level);
+ ast_option_pjproject_log_level = ast_pjproject_max_log_level;
+ }
+ pj_log_set_level(ast_option_pjproject_log_level);
+ if (!AST_VECTOR_SIZE(&buildopts)) {
+ ast_log(LOG_NOTICE,
+ "Asterisk built or linked with pjproject PJ_LOG_MAX_LEVEL=%d which is too low to get buildopts.\n",
+ ast_pjproject_max_log_level);
+ }
ast_cli_register_multiple(pjproject_cli, ARRAY_LEN(pjproject_cli));
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index dd4a619..c35b782 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -919,14 +919,14 @@
On outbound requests, force the user portion of the Contact header to this value.
</para></description>
</configOption>
- <configOption name="asymmetric_rtp_codec" default="no">
- <synopsis>Allow the sending and receiving RTP codec to differ</synopsis>
- <description><para>
- When set to "yes" the codec in use for sending will be allowed to differ from
- that of the received one. PJSIP will not automatically switch the sending one
- to the receiving one.
- </para></description>
- </configOption>
+ <configOption name="asymmetric_rtp_codec" default="no">
+ <synopsis>Allow the sending and receiving RTP codec to differ</synopsis>
+ <description><para>
+ When set to "yes" the codec in use for sending will be allowed to differ from
+ that of the received one. PJSIP will not automatically switch the sending one
+ to the receiving one.
+ </para></description>
+ </configOption>
</configObject>
<configObject name="auth">
<synopsis>Authentication type</synopsis>
@@ -2090,10 +2090,31 @@
<para>Absolute time that this contact is no longer valid after</para>
</parameter>
<parameter name="ViaAddress">
- <para>IP address:port of the last Via header in REGISTER request</para>
+ <para>IP address:port of the last Via header in REGISTER request.
+ Will only appear in the event if available.</para>
</parameter>
<parameter name="CallID">
- <para>Content of the Call-ID header in REGISTER request</para>
+ <para>Content of the Call-ID header in REGISTER request.
+ Will only appear in the event if available.</para>
+ </parameter>
+ <parameter name="ID">
+ <para>The sorcery ID of the contact.</para>
+ </parameter>
+ <parameter name="AuthenticateQualify">
+ <para>A boolean indicating whether a qualify should be authenticated.</para>
+ </parameter>
+ <parameter name="OutboundProxy">
+ <para>The contact's outbound proxy.</para>
+ </parameter>
+ <parameter name="Path">
+ <para>The Path header received on the REGISTER.</para>
+ </parameter>
+ <parameter name="QualifyFrequency">
+ <para>The interval in seconds at which the contact will be qualified.</para>
+ </parameter>
+ <parameter name="QualifyTimeout">
+ <para>The elapsed time in decimal seconds after which an OPTIONS
+ message is sent before the contact is considered unavailable.</para>
</parameter>
</syntax>
</managerEventInstance>
@@ -2888,7 +2909,8 @@ pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint,
res = pjsip_dlg_create_uac(pjsip_ua_instance(), &local_uri, NULL, &remote_uri, &target_uri, &dlg);
if (res != PJ_SUCCESS) {
if (res == PJSIP_EINVALIDURI) {
- ast_log(LOG_ERROR, "Could not create dialog to endpoint '%s' as URI '%s' is not valid\n",
+ ast_log(LOG_ERROR,
+ "Endpoint '%s': Could not create dialog to invalid URI '%s'. Is endpoint registered?\n",
ast_sorcery_object_get_id(endpoint), uri);
}
return NULL;
@@ -3222,8 +3244,9 @@ static int create_out_of_dialog_request(const pjsip_method *method, struct ast_s
pjsip_contact_hdr *contact_hdr;
pjsip_sip_uri *contact_uri;
static const pj_str_t HCONTACT = { "Contact", 7 };
+ static const pj_str_t HCONTACTSHORT = { "m", 1 };
- contact_hdr = pjsip_msg_find_hdr_by_name((*tdata)->msg, &HCONTACT, NULL);
+ contact_hdr = pjsip_msg_find_hdr_by_names((*tdata)->msg, &HCONTACT, &HCONTACTSHORT, NULL);
if (contact_hdr) {
contact_uri = pjsip_uri_get_uri(contact_hdr->uri);
pj_strdup2(pool, &contact_uri->user, endpoint->contact_user);
@@ -3379,6 +3402,8 @@ struct send_request_wrapper {
void (*callback)(void *token, pjsip_event *e);
/*! Non-zero when the callback is called. */
unsigned int cb_called;
+ /*! Non-zero if endpt_send_request_cb() was called. */
+ unsigned int send_cb_called;
/*! Timeout timer. */
pj_timer_entry *timeout_timer;
/*! Original timeout. */
@@ -3396,6 +3421,12 @@ static void endpt_send_request_cb(void *token, pjsip_event *e)
struct send_request_wrapper *req_wrapper = token;
unsigned int cb_called;
+ /*
+ * Needed because we cannot otherwise tell if this callback was
+ * called when pjsip_endpt_send_request() returns error.
+ */
+ req_wrapper->send_cb_called = 1;
+
if (e->body.tsx_state.type == PJSIP_EVENT_TIMER) {
ast_debug(2, "%p: PJSIP tsx timer expired\n", req_wrapper);
@@ -3579,12 +3610,10 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint,
if (ret_val != PJ_SUCCESS) {
char errmsg[PJ_ERR_MSG_SIZE];
- /*
- * endpt_send_request_cb is not expected to ever be called
- * because the request didn't get far enough to attempt
- * sending.
- */
- ao2_ref(req_wrapper, -1);
+ if (!req_wrapper->send_cb_called) {
+ /* endpt_send_request_cb is not expected to ever be called now. */
+ ao2_ref(req_wrapper, -1);
+ }
/* Complain of failure to send the request. */
pj_strerror(ret_val, errmsg, sizeof(errmsg));
@@ -3621,6 +3650,13 @@ static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint,
req_wrapper->cb_called = 1;
}
ao2_unlock(req_wrapper);
+ } else if (req_wrapper->cb_called) {
+ /*
+ * We cannot report any error. The callback has
+ * already freed any resources associated with
+ * token.
+ */
+ ret_val = PJ_SUCCESS;
}
}
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index 84dfa22..bfaf750 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -1711,9 +1711,7 @@ static int cli_endpoint_print_body(void *obj, void *arg, int flags)
if (number) {
print_name_len = strlen(id) + strlen(number) + 2;
- if (!(print_name = alloca(print_name_len))) {
- return -1;
- }
+ print_name = ast_alloca(print_name_len);
snprintf(print_name, print_name_len, "%s/%s", id, number);
}
@@ -2072,6 +2070,8 @@ static void endpoint_destructor(void* obj)
ast_variables_destroy(endpoint->channel_vars);
AST_VECTOR_FREE(&endpoint->ident_method_order);
ast_free(endpoint->contact_user);
+ ast_free_acl_list(endpoint->contact_acl);
+ ast_free_acl_list(endpoint->acl);
}
static int init_subscription_configuration(struct ast_sip_endpoint_subscription_configuration *subscription)
diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c
index 8c8836f..d4159f5 100644
--- a/res/res_pjsip/pjsip_options.c
+++ b/res/res_pjsip/pjsip_options.c
@@ -711,7 +711,8 @@ static pj_status_t send_options_response(pjsip_rx_data *rdata, int code)
pj_status_t status;
/* Make the response object */
- if ((status = ast_sip_create_response(rdata, code, NULL, &tdata) != PJ_SUCCESS)) {
+ status = ast_sip_create_response(rdata, code, NULL, &tdata);
+ if (status != PJ_SUCCESS) {
ast_log(LOG_ERROR, "Unable to create response (%d)\n", status);
return status;
}
@@ -1227,7 +1228,7 @@ static void qualify_and_schedule_all(void)
}
-static int format_contact_status(void *obj, void *arg, int flags)
+int ast_sip_format_contact_ami(void *obj, void *arg, int flags)
{
struct ast_sip_contact_wrapper *wrapper = obj;
struct ast_sip_contact *contact = wrapper->contact;
@@ -1266,7 +1267,15 @@ static int format_contact_status(void *obj, void *arg, int flags)
ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt);
}
ast_str_append(&buf, 0, "EndpointName: %s\r\n",
- ast_sorcery_object_get_id(endpoint));
+ endpoint ? ast_sorcery_object_get_id(endpoint) : S_OR(contact->endpoint_name, ""));
+
+ ast_str_append(&buf, 0, "ID: %s\r\n", ast_sorcery_object_get_id(contact));
+ ast_str_append(&buf, 0, "AuthenticateQualify: %d\r\n", contact->authenticate_qualify);
+ ast_str_append(&buf, 0, "OutboundProxy: %s\r\n", contact->outbound_proxy);
+ ast_str_append(&buf, 0, "Path: %s\r\n", contact->path);
+ ast_str_append(&buf, 0, "QualifyFrequency: %u\r\n", contact->qualify_frequency);
+ ast_str_append(&buf, 0, "QualifyTimeout: %.3f\r\n", contact->qualify_timeout);
+
astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
ami->count++;
@@ -1279,7 +1288,7 @@ static int format_contact_status_for_aor(void *obj, void *arg, int flags)
{
struct ast_sip_aor *aor = obj;
- return ast_sip_for_each_contact(aor, format_contact_status, arg);
+ return ast_sip_for_each_contact(aor, ast_sip_format_contact_ami, arg);
}
static int format_ami_contact_status(const struct ast_sip_endpoint *endpoint,
diff --git a/res/res_pjsip_diversion.c b/res/res_pjsip_diversion.c
index b9225de..a9ffdf4 100644
--- a/res/res_pjsip_diversion.c
+++ b/res/res_pjsip_diversion.c
@@ -277,6 +277,7 @@ static int diversion_incoming_request(struct ast_sip_session *session, pjsip_rx_
static void diversion_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata)
{
static const pj_str_t contact_name = { "Contact", 7 };
+ static const pj_str_t contact_name_s = { "m", 1 };
pjsip_status_line status = rdata->msg_info.msg->line.status;
pjsip_fromto_hdr *div_hdr;
@@ -292,7 +293,7 @@ static void diversion_incoming_response(struct ast_sip_session *session, pjsip_r
div_hdr = PJSIP_MSG_TO_HDR(rdata->msg_info.msg);
}
- contact_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &contact_name, NULL);
+ contact_hdr = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg, &contact_name, &contact_name_s, NULL);
set_redirecting(session, div_hdr, contact_hdr ? (pjsip_name_addr*)contact_hdr->uri :
(pjsip_name_addr*)PJSIP_MSG_FROM_HDR(rdata->msg_info.msg)->uri);
diff --git a/res/res_pjsip_endpoint_identifier_ip.c b/res/res_pjsip_endpoint_identifier_ip.c
index b1ffd2c..6fc724a 100644
--- a/res/res_pjsip_endpoint_identifier_ip.c
+++ b/res/res_pjsip_endpoint_identifier_ip.c
@@ -51,6 +51,13 @@
mask with a slash ('/')
</para></description>
</configOption>
+ <configOption name="srv_lookups" default="yes">
+ <synopsis>Perform SRV lookups for provided hostnames.</synopsis>
+ <description><para>When enabled, <replaceable>srv_lookups</replaceable> will
+ perform SRV lookups for _sip._udp, _sip._tcp, and _sips._tcp of the given
+ hostnames to determine additional addresses that traffic may originate from.
+ </para></description>
+ </configOption>
<configOption name="type">
<synopsis>Must be of type 'identify'.</synopsis>
</configOption>
@@ -59,6 +66,9 @@
</configInfo>
***/
+/*! \brief The number of buckets for storing hosts for resolution */
+#define HOSTS_BUCKETS 53
+
/*! \brief Structure for an IP identification matching object */
struct ip_identify_match {
/*! \brief Sorcery object details */
@@ -70,6 +80,10 @@ struct ip_identify_match {
);
/*! \brief Networks or addresses that should match this */
struct ast_ha *matches;
+ /*! \brief Perform SRV resolution of hostnames */
+ unsigned int srv_lookups;
+ /*! \brief Hosts to be resolved after applying configuration */
+ struct ao2_container *hosts;
};
/*! \brief Destructor function for a matching object */
@@ -79,6 +93,7 @@ static void ip_identify_destroy(void *obj)
ast_string_field_free_memory(identify);
ast_free_ha(identify->matches);
+ ao2_cleanup(identify->hosts);
}
/*! \brief Allocator function for a matching object */
@@ -153,6 +168,72 @@ static struct ast_sip_endpoint_identifier ip_identifier = {
.identify_endpoint = ip_identify,
};
+/*! \brief Helper function which performs a host lookup and adds result to identify match */
+static int ip_identify_match_host_lookup(struct ip_identify_match *identify, const char *host)
+{
+ struct ast_sockaddr *addrs;
+ int num_addrs = 0, error = 0, i;
+ int results = 0;
+
+ num_addrs = ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC);
+ if (!num_addrs) {
+ return -1;
+ }
+
+ for (i = 0; i < num_addrs; ++i) {
+ /* Check if the address is already in the list, if so don't bother adding it again */
+ if (identify->matches && (ast_apply_ha(identify->matches, &addrs[i]) != AST_SENSE_ALLOW)) {
+ continue;
+ }
+
+ /* We deny what we actually want to match because there is an implicit permit all rule for ACLs */
+ identify->matches = ast_append_ha("d", ast_sockaddr_stringify_addr(&addrs[i]), identify->matches, &error);
+
+ if (!identify->matches || error) {
+ results = -1;
+ break;
+ }
+
+ results += 1;
+ }
+
+ ast_free(addrs);
+
+ return results;
+}
+
+/*! \brief Helper function which performs an SRV lookup and then resolves the hostname */
+static int ip_identify_match_srv_lookup(struct ip_identify_match *identify, const char *prefix, const char *host)
+{
+ char service[NI_MAXHOST];
+ struct srv_context *context = NULL;
+ int srv_ret;
+ const char *srvhost;
+ unsigned short srvport;
+ int results = 0;
+
+ snprintf(service, sizeof(service), "%s.%s", prefix, host);
+
+ while (!(srv_ret = ast_srv_lookup(&context, service, &srvhost, &srvport))) {
+ int hosts;
+
+ /* In the case of the SRV lookup we don't care if it fails, we will output a log message
+ * when we fallback to a normal lookup.
+ */
+ hosts = ip_identify_match_host_lookup(identify, srvhost);
+ if (hosts == -1) {
+ results = -1;
+ break;
+ } else {
+ results += hosts;
+ }
+ }
+
+ ast_srv_cleanup(&context);
+
+ return results;
+}
+
/*! \brief Custom handler for match field */
static int ip_identify_match_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
{
@@ -165,9 +246,8 @@ static int ip_identify_match_handler(const struct aco_option *opt, struct ast_va
}
while ((current_string = ast_strip(strsep(&input_string, ",")))) {
- struct ast_sockaddr *addrs;
- int num_addrs = 0, error = 0, i;
char *mask = strrchr(current_string, '/');
+ int error = 0;
if (ast_strlen_zero(current_string)) {
continue;
@@ -185,36 +265,79 @@ static int ip_identify_match_handler(const struct aco_option *opt, struct ast_va
continue;
}
- num_addrs = ast_sockaddr_resolve(&addrs, current_string, PARSE_PORT_FORBID, AST_AF_UNSPEC);
- if (!num_addrs) {
- ast_log(LOG_ERROR, "Address '%s' provided on ip endpoint identifier '%s' did not resolve to any address\n",
- var->value, ast_sorcery_object_get_id(obj));
+ if (!identify->hosts) {
+ identify->hosts = ast_str_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, HOSTS_BUCKETS);
+ if (!identify->hosts) {
+ ast_log(LOG_ERROR, "Failed to create container to store hosts on ip endpoint identifier '%s'\n",
+ ast_sorcery_object_get_id(obj));
+ return -1;
+ }
+ }
+
+ error = ast_str_container_add(identify->hosts, current_string);
+ if (error) {
+ ast_log(LOG_ERROR, "Failed to store host '%s' for resolution on ip endpoint identifier '%s'\n",
+ current_string, ast_sorcery_object_get_id(obj));
return -1;
}
+ }
- for (i = 0; i < num_addrs; ++i) {
- /* We deny what we actually want to match because there is an implicit permit all rule for ACLs */
- identify->matches = ast_append_ha("d", ast_sockaddr_stringify_addr(&addrs[i]), identify->matches, &error);
+ return 0;
+}
- if (!identify->matches || error) {
- ast_log(LOG_ERROR, "Failed to add address '%s' to ip endpoint identifier '%s'\n",
- ast_sockaddr_stringify_addr(&addrs[i]), ast_sorcery_object_get_id(obj));
- error = -1;
- break;
+/*! \brief Apply handler for identify type */
+static int ip_identify_apply(const struct ast_sorcery *sorcery, void *obj)
+{
+ struct ip_identify_match *identify = obj;
+ char *current_string;
+ struct ao2_iterator i;
+
+ if (!identify->hosts) {
+ return 0;
+ }
+
+ i = ao2_iterator_init(identify->hosts, 0);
+ while ((current_string = ao2_iterator_next(&i))) {
+ struct ast_sockaddr address;
+ int results = 0;
+
+ /* If the provided string is not an IP address perform SRV resolution on it */
+ if (identify->srv_lookups && !ast_sockaddr_parse(&address, current_string, 0)) {
+ results = ip_identify_match_srv_lookup(identify, "_sip._udp", current_string);
+ if (results != -1) {
+ results += ip_identify_match_srv_lookup(identify, "_sip._tcp", current_string);
+ }
+ if (results != -1) {
+ results += ip_identify_match_srv_lookup(identify, "_sips._tcp", current_string);
}
}
- ast_free(addrs);
+ /* If SRV falls fall back to a normal lookup on the host itself */
+ if (!results) {
+ results = ip_identify_match_host_lookup(identify, current_string);
+ }
- if (error) {
+ if (results == 0) {
+ ast_log(LOG_ERROR, "Address '%s' provided on ip endpoint identifier '%s' did not resolve to any address\n",
+ current_string, ast_sorcery_object_get_id(obj));
+ } else if (results == -1) {
+ ast_log(LOG_ERROR, "An error occurred when adding resolution results of '%s' on '%s'\n",
+ current_string, ast_sorcery_object_get_id(obj));
+ ao2_ref(current_string, -1);
+ ao2_iterator_destroy(&i);
return -1;
}
+
+ ao2_ref(current_string, -1);
}
+ ao2_iterator_destroy(&i);
+
+ ao2_ref(identify->hosts, -1);
+ identify->hosts = NULL;
return 0;
}
-
static int match_to_str(const void *obj, const intptr_t *args, char **buf)
{
RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free);
@@ -462,13 +585,14 @@ static int load_module(void)
ast_sorcery_apply_config(ast_sip_get_sorcery(), "res_pjsip_endpoint_identifier_ip");
ast_sorcery_apply_default(ast_sip_get_sorcery(), "identify", "config", "pjsip.conf,criteria=type=identify");
- if (ast_sorcery_object_register(ast_sip_get_sorcery(), "identify", ip_identify_alloc, NULL, NULL)) {
+ if (ast_sorcery_object_register(ast_sip_get_sorcery(), "identify", ip_identify_alloc, NULL, ip_identify_apply)) {
return AST_MODULE_LOAD_DECLINE;
}
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "type", "", OPT_NOOP_T, 0, 0);
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ip_identify_match, endpoint_name));
ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "identify", "match", "", ip_identify_match_handler, match_to_str, match_to_var_list, 0, 0);
+ ast_sorcery_object_field_register(ast_sip_get_sorcery(), "identify", "srv_lookups", "yes", OPT_BOOL_T, 1, FLDSET(struct ip_identify_match, srv_lookups));
ast_sorcery_load_object(ast_sip_get_sorcery(), "identify");
ast_sip_register_endpoint_identifier_with_name(&ip_identifier, "ip");
diff --git a/res/res_pjsip_history.c b/res/res_pjsip_history.c
index ea5f5e8..651f19d 100644
--- a/res/res_pjsip_history.c
+++ b/res/res_pjsip_history.c
@@ -159,6 +159,9 @@ struct expression_token {
char field[];
};
+/*! \brief Log level for history output */
+static int log_level = -1;
+
/*!
* \brief Operator callback for determining equality
*/
@@ -646,6 +649,41 @@ static struct pjsip_history_entry *pjsip_history_entry_alloc(pjsip_msg *msg)
return entry;
}
+/*! \brief Format single line history entry */
+static void sprint_list_entry(struct pjsip_history_entry *entry, char *line, int len)
+{
+ char addr[64];
+
+ if (entry->transmitted) {
+ pj_sockaddr_print(&entry->dst, addr, sizeof(addr), 3);
+ } else {
+ pj_sockaddr_print(&entry->src, addr, sizeof(addr), 3);
+ }
+
+ if (entry->msg->type == PJSIP_REQUEST_MSG) {
+ char uri[128];
+
+ pjsip_uri_print(PJSIP_URI_IN_REQ_URI, entry->msg->line.req.uri, uri, sizeof(uri));
+ snprintf(line, len, "%-5.5d %-10.10ld %-5.5s %-24.24s %.*s %s SIP/2.0",
+ entry->number,
+ entry->timestamp.tv_sec,
+ entry->transmitted ? "* ==>" : "* <==",
+ addr,
+ (int)pj_strlen(&entry->msg->line.req.method.name),
+ pj_strbuf(&entry->msg->line.req.method.name),
+ uri);
+ } else {
+ snprintf(line, len, "%-5.5d %-10.10ld %-5.5s %-24.24s SIP/2.0 %u %.*s",
+ entry->number,
+ entry->timestamp.tv_sec,
+ entry->transmitted ? "* ==>" : "* <==",
+ addr,
+ entry->msg->line.status.code,
+ (int)pj_strlen(&entry->msg->line.status.reason),
+ pj_strbuf(&entry->msg->line.status.reason));
+ }
+}
+
/*! \brief PJSIP callback when a SIP message is transmitted */
static pj_status_t history_on_tx_msg(pjsip_tx_data *tdata)
{
@@ -667,6 +705,13 @@ static pj_status_t history_on_tx_msg(pjsip_tx_data *tdata)
AST_VECTOR_APPEND(&vector_history, entry);
ast_mutex_unlock(&history_lock);
+ if (log_level != -1) {
+ char line[256];
+
+ sprint_list_entry(entry, line, sizeof(line));
+ ast_log_dynamic_level(log_level, "%s\n", line);
+ }
+
return PJ_SUCCESS;
}
@@ -700,6 +745,13 @@ static pj_bool_t history_on_rx_msg(pjsip_rx_data *rdata)
AST_VECTOR_APPEND(&vector_history, entry);
ast_mutex_unlock(&history_lock);
+ if (log_level != -1) {
+ char line[256];
+
+ sprint_list_entry(entry, line, sizeof(line));
+ ast_log_dynamic_level(log_level, "%s\n", line);
+ }
+
return PJ_FALSE;
}
@@ -1120,38 +1172,12 @@ static void display_entry_list(struct ast_cli_args *a, struct vector_history_t *
for (i = 0; i < AST_VECTOR_SIZE(vec); i++) {
struct pjsip_history_entry *entry;
- char addr[64];
char line[256];
entry = AST_VECTOR_GET(vec, i);
+ sprint_list_entry(entry, line, sizeof(line));
- if (entry->transmitted) {
- pj_sockaddr_print(&entry->dst, addr, sizeof(addr), 3);
- } else {
- pj_sockaddr_print(&entry->src, addr, sizeof(addr), 3);
- }
-
- if (entry->msg->type == PJSIP_REQUEST_MSG) {
- char uri[128];
-
- pjsip_uri_print(PJSIP_URI_IN_REQ_URI, entry->msg->line.req.uri, uri, sizeof(uri));
- snprintf(line, sizeof(line), "%.*s %s SIP/2.0",
- (int)pj_strlen(&entry->msg->line.req.method.name),
- pj_strbuf(&entry->msg->line.req.method.name),
- uri);
- } else {
- snprintf(line, sizeof(line), "SIP/2.0 %u %.*s",
- entry->msg->line.status.code,
- (int)pj_strlen(&entry->msg->line.status.reason),
- pj_strbuf(&entry->msg->line.status.reason));
- }
-
- ast_cli(a->fd, "%-5.5d %-10.10ld %-5.5s %-24.24s %s\n",
- entry->number,
- entry->timestamp.tv_sec,
- entry->transmitted ? "* ==>" : "* <==",
- addr,
- line);
+ ast_cli(a->fd, "%s\n", line);
}
}
@@ -1321,6 +1347,11 @@ static int load_module(void)
{
CHECK_PJSIP_MODULE_LOADED();
+ log_level = ast_logger_register_level("PJSIP_HISTORY");
+ if (log_level < 0) {
+ ast_log(LOG_WARNING, "Unable to register history log level\n");
+ }
+
pj_caching_pool_init(&cachingpool, &pj_pool_factory_default_policy, 0);
AST_VECTOR_INIT(&vector_history, HISTORY_INITIAL_SIZE);
@@ -1341,6 +1372,10 @@ static int unload_module(void)
pj_caching_pool_destroy(&cachingpool);
+ if (log_level != -1) {
+ ast_logger_unregister_level("PJSIP_HISTORY");
+ }
+
return 0;
}
diff --git a/res/res_pjsip_outbound_authenticator_digest.c b/res/res_pjsip_outbound_authenticator_digest.c
index d4dfce4..11b5108 100644
--- a/res/res_pjsip_outbound_authenticator_digest.c
+++ b/res/res_pjsip_outbound_authenticator_digest.c
@@ -141,18 +141,18 @@ static int digest_create_request_with_auth_from_old(const struct ast_sip_auth_ve
++cseq->cseq;
return 0;
case PJSIP_ENOCREDENTIAL:
- ast_log(LOG_WARNING, "Unable to create request with auth."
- "No auth credentials for any realms in challenge.\n");
+ ast_log(LOG_WARNING,
+ "Unable to create request with auth. No auth credentials for any realms in challenge.\n");
break;
case PJSIP_EAUTHSTALECOUNT:
- ast_log(LOG_WARNING, "Unable to create request with auth."
- "Number of stale retries exceeded\n");
+ ast_log(LOG_WARNING,
+ "Unable to create request with auth. Number of stale retries exceeded.\n");
break;
case PJSIP_EFAILEDCREDENTIAL:
- ast_log(LOG_WARNING, "Authentication credentials not accepted by server\n");
+ ast_log(LOG_WARNING, "Authentication credentials not accepted by server.\n");
break;
default:
- ast_log(LOG_WARNING, "Unable to create request with auth. Unknown failure\n");
+ ast_log(LOG_WARNING, "Unable to create request with auth. Unknown failure.\n");
break;
}
diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c
index ff66194..da15f19 100644
--- a/res/res_pjsip_outbound_registration.c
+++ b/res/res_pjsip_outbound_registration.c
@@ -627,15 +627,30 @@ static void schedule_registration(struct sip_outbound_registration_client_state
static void update_client_state_status(struct sip_outbound_registration_client_state *client_state, enum sip_outbound_registration_status status)
{
+ const char *status_old;
+ const char *status_new;
+
if (client_state->status == status) {
+ /* Status state did not change at all. */
+ return;
+ }
+
+ status_old = sip_outbound_registration_status_str(client_state->status);
+ status_new = sip_outbound_registration_status_str(status);
+ client_state->status = status;
+
+ if (!strcmp(status_old, status_new)) {
+ /*
+ * The internal status state may have changed but the status
+ * state we tell the world did not change at all.
+ */
return;
}
ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "-1", 1.0,
- sip_outbound_registration_status_str(client_state->status));
+ status_old);
ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "+1", 1.0,
- sip_outbound_registration_status_str(status));
- client_state->status = status;
+ status_new);
}
/*! \brief Callback function for unregistering (potentially) and destroying state */
diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c
index f6b6efc..f515582 100644
--- a/res/res_pjsip_pubsub.c
+++ b/res/res_pjsip_pubsub.c
@@ -42,6 +42,7 @@
#include "asterisk/res_pjsip.h"
#include "asterisk/callerid.h"
#include "asterisk/manager.h"
+#include "asterisk/cli.h"
#include "asterisk/test.h"
#include "res_pjsip/include/res_pjsip_private.h"
#include "asterisk/res_pjsip_presence_xml.h"
@@ -889,8 +890,9 @@ static void build_node_children(struct ast_sip_endpoint *endpoint, const struct
if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
current = tree_node_alloc(resource, visited, 0);
if (!current) {
- ast_debug(1, "Subscription to leaf resource %s was successful, but encountered"
- "allocation error afterwards\n", resource);
+ ast_debug(1,
+ "Subscription to leaf resource %s was successful, but encountered allocation error afterwards\n",
+ resource);
continue;
}
ast_debug(2, "Subscription to leaf resource %s resulted in success. Adding to parent %s\n",
@@ -1039,14 +1041,16 @@ static int datastore_cmp(void *obj, void *arg, int flags)
static void add_subscription(struct sip_subscription_tree *obj)
{
- SCOPED_LOCK(lock, &subscriptions, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
+ AST_RWLIST_WRLOCK(&subscriptions);
AST_RWLIST_INSERT_TAIL(&subscriptions, obj, next);
+ AST_RWLIST_UNLOCK(&subscriptions);
}
static void remove_subscription(struct sip_subscription_tree *obj)
{
struct sip_subscription_tree *i;
- SCOPED_LOCK(lock, &subscriptions, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
+
+ AST_RWLIST_WRLOCK(&subscriptions);
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&subscriptions, i, next) {
if (i == obj) {
AST_RWLIST_REMOVE_CURRENT(next);
@@ -1058,6 +1062,7 @@ static void remove_subscription(struct sip_subscription_tree *obj)
}
}
AST_RWLIST_TRAVERSE_SAFE_END;
+ AST_RWLIST_UNLOCK(&subscriptions);
}
static void destroy_subscription(struct ast_sip_subscription *sub)
@@ -1600,18 +1605,19 @@ static int for_each_subscription(on_subscription_t on_subscription, void *arg)
{
int num = 0;
struct sip_subscription_tree *i;
- SCOPED_LOCK(lock, &subscriptions, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
if (!on_subscription) {
return num;
}
+ AST_RWLIST_RDLOCK(&subscriptions);
AST_RWLIST_TRAVERSE(&subscriptions, i, next) {
if (on_subscription(i, arg)) {
break;
}
++num;
}
+ AST_RWLIST_UNLOCK(&subscriptions);
return num;
}
@@ -2554,8 +2560,9 @@ static int publication_cmp_fn(void *obj, void *arg, int flags)
static void publish_add_handler(struct ast_sip_publish_handler *handler)
{
- SCOPED_LOCK(lock, &publish_handlers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
+ AST_RWLIST_WRLOCK(&publish_handlers);
AST_RWLIST_INSERT_TAIL(&publish_handlers, handler, next);
+ AST_RWLIST_UNLOCK(&publish_handlers);
}
int ast_sip_register_publish_handler(struct ast_sip_publish_handler *handler)
@@ -2582,7 +2589,8 @@ int ast_sip_register_publish_handler(struct ast_sip_publish_handler *handler)
void ast_sip_unregister_publish_handler(struct ast_sip_publish_handler *handler)
{
struct ast_sip_publish_handler *iter;
- SCOPED_LOCK(lock, &publish_handlers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
+
+ AST_RWLIST_WRLOCK(&publish_handlers);
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&publish_handlers, iter, next) {
if (handler == iter) {
AST_RWLIST_REMOVE_CURRENT(next);
@@ -2592,27 +2600,30 @@ void ast_sip_unregister_publish_handler(struct ast_sip_publish_handler *handler)
}
}
AST_RWLIST_TRAVERSE_SAFE_END;
+ AST_RWLIST_UNLOCK(&publish_handlers);
}
AST_RWLIST_HEAD_STATIC(subscription_handlers, ast_sip_subscription_handler);
static void sub_add_handler(struct ast_sip_subscription_handler *handler)
{
- SCOPED_LOCK(lock, &subscription_handlers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
+ AST_RWLIST_WRLOCK(&subscription_handlers);
AST_RWLIST_INSERT_TAIL(&subscription_handlers, handler, next);
ast_module_ref(ast_module_info->self);
+ AST_RWLIST_UNLOCK(&subscription_handlers);
}
static struct ast_sip_subscription_handler *find_sub_handler_for_event_name(const char *event_name)
{
struct ast_sip_subscription_handler *iter;
- SCOPED_LOCK(lock, &subscription_handlers, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
+ AST_RWLIST_RDLOCK(&subscription_handlers);
AST_RWLIST_TRAVERSE(&subscription_handlers, iter, next) {
if (!strcmp(iter->event_name, event_name)) {
break;
}
}
+ AST_RWLIST_UNLOCK(&subscription_handlers);
return iter;
}
@@ -2630,8 +2641,9 @@ int ast_sip_register_subscription_handler(struct ast_sip_subscription_handler *h
existing = find_sub_handler_for_event_name(handler->event_name);
if (existing) {
- ast_log(LOG_ERROR, "Unable to register subscription handler for event %s."
- "A handler is already registered\n", handler->event_name);
+ ast_log(LOG_ERROR,
+ "Unable to register subscription handler for event %s. A handler is already registered\n",
+ handler->event_name);
return -1;
}
@@ -2651,7 +2663,8 @@ int ast_sip_register_subscription_handler(struct ast_sip_subscription_handler *h
void ast_sip_unregister_subscription_handler(struct ast_sip_subscription_handler *handler)
{
struct ast_sip_subscription_handler *iter;
- SCOPED_LOCK(lock, &subscription_handlers, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
+
+ AST_RWLIST_WRLOCK(&subscription_handlers);
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&subscription_handlers, iter, next) {
if (handler == iter) {
AST_RWLIST_REMOVE_CURRENT(next);
@@ -2660,6 +2673,7 @@ void ast_sip_unregister_subscription_handler(struct ast_sip_subscription_handler
}
}
AST_RWLIST_TRAVERSE_SAFE_END;
+ AST_RWLIST_UNLOCK(&subscription_handlers);
}
static struct ast_sip_pubsub_body_generator *find_body_generator_type_subtype_nolock(const char *type, const char *subtype)
@@ -2829,7 +2843,6 @@ static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata)
AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(resource);
expires_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, rdata->msg_info.msg->hdr.next);
-
if (expires_header) {
if (expires_header->ivalue == 0) {
ast_log(LOG_WARNING, "Subscription request from endpoint %s rejected. Expiration of 0 is invalid\n",
@@ -2888,8 +2901,8 @@ static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata)
static struct ast_sip_publish_handler *find_pub_handler(const char *event)
{
struct ast_sip_publish_handler *iter = NULL;
- SCOPED_LOCK(lock, &publish_handlers, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
+ AST_RWLIST_RDLOCK(&publish_handlers);
AST_RWLIST_TRAVERSE(&publish_handlers, iter, next) {
if (strcmp(event, iter->event_name)) {
ast_debug(3, "Event %s does not match %s\n", event, iter->event_name);
@@ -2898,6 +2911,7 @@ static struct ast_sip_publish_handler *find_pub_handler(const char *event)
ast_debug(3, "Event name match: %s = %s\n", event, iter->event_name);
break;
}
+ AST_RWLIST_UNLOCK(&publish_handlers);
return iter;
}
@@ -3261,8 +3275,8 @@ int ast_sip_pubsub_register_body_generator(struct ast_sip_pubsub_body_generator
void ast_sip_pubsub_unregister_body_generator(struct ast_sip_pubsub_body_generator *generator)
{
struct ast_sip_pubsub_body_generator *iter;
- SCOPED_LOCK(lock, &body_generators, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
+ AST_RWLIST_WRLOCK(&body_generators);
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&body_generators, iter, list) {
if (iter == generator) {
AST_LIST_REMOVE_CURRENT(list);
@@ -3270,6 +3284,7 @@ void ast_sip_pubsub_unregister_body_generator(struct ast_sip_pubsub_body_generat
}
}
AST_RWLIST_TRAVERSE_SAFE_END;
+ AST_RWLIST_UNLOCK(&body_generators);
}
int ast_sip_pubsub_register_body_supplement(struct ast_sip_pubsub_body_supplement *supplement)
@@ -3284,8 +3299,8 @@ int ast_sip_pubsub_register_body_supplement(struct ast_sip_pubsub_body_supplemen
void ast_sip_pubsub_unregister_body_supplement(struct ast_sip_pubsub_body_supplement *supplement)
{
struct ast_sip_pubsub_body_supplement *iter;
- SCOPED_LOCK(lock, &body_supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
+ AST_RWLIST_WRLOCK(&body_supplements);
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&body_supplements, iter, list) {
if (iter == supplement) {
AST_LIST_REMOVE_CURRENT(list);
@@ -3293,6 +3308,7 @@ void ast_sip_pubsub_unregister_body_supplement(struct ast_sip_pubsub_body_supple
}
}
AST_RWLIST_TRAVERSE_SAFE_END;
+ AST_RWLIST_UNLOCK(&body_supplements);
}
const char *ast_sip_subscription_get_body_type(struct ast_sip_subscription *sub)
@@ -3646,6 +3662,8 @@ static int ami_subscription_detail(struct sip_subscription_tree *sub_tree,
sip_subscription_to_ami(sub_tree, &buf);
astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
ast_free(buf);
+
+ ++ami->count;
return 0;
}
@@ -3664,14 +3682,13 @@ static int ami_subscription_detail_outbound(struct sip_subscription_tree *sub_tr
static int ami_show_subscriptions_inbound(struct mansession *s, const struct message *m)
{
struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
- int num;
- astman_send_listack(s, m, "Following are Events for "
- "each inbound Subscription", "start");
+ astman_send_listack(s, m, "Following are Events for each inbound Subscription",
+ "start");
- num = for_each_subscription(ami_subscription_detail_inbound, &ami);
+ for_each_subscription(ami_subscription_detail_inbound, &ami);
- astman_send_list_complete_start(s, m, "InboundSubscriptionDetailComplete", num);
+ astman_send_list_complete_start(s, m, "InboundSubscriptionDetailComplete", ami.count);
astman_send_list_complete_end(s);
return 0;
}
@@ -3679,14 +3696,13 @@ static int ami_show_subscriptions_inbound(struct mansession *s, const struct mes
static int ami_show_subscriptions_outbound(struct mansession *s, const struct message *m)
{
struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
- int num;
- astman_send_listack(s, m, "Following are Events for "
- "each outbound Subscription", "start");
+ astman_send_listack(s, m, "Following are Events for each outbound Subscription",
+ "start");
- num = for_each_subscription(ami_subscription_detail_outbound, &ami);
+ for_each_subscription(ami_subscription_detail_outbound, &ami);
- astman_send_list_complete_start(s, m, "OutboundSubscriptionDetailComplete", num);
+ astman_send_list_complete_start(s, m, "OutboundSubscriptionDetailComplete", ami.count);
astman_send_list_complete_end(s);
return 0;
}
@@ -3707,31 +3723,31 @@ static int format_ami_resource_lists(void *obj, void *arg, int flags)
return CMP_STOP;
}
astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
-
ast_free(buf);
+
+ ++ami->count;
return 0;
}
static int ami_show_resource_lists(struct mansession *s, const struct message *m)
{
struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
- int num;
struct ao2_container *lists;
lists = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "resource_list",
AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
- if (!lists || !(num = ao2_container_count(lists))) {
+ if (!lists || !ao2_container_count(lists)) {
astman_send_error(s, m, "No resource lists found\n");
return 0;
}
- astman_send_listack(s, m, "A listing of resource lists follows, "
- "presented as ResourceListDetail events", "start");
+ astman_send_listack(s, m, "A listing of resource lists follows, presented as ResourceListDetail events",
+ "start");
ao2_callback(lists, OBJ_NODATA, format_ami_resource_lists, &ami);
- astman_send_list_complete_start(s, m, "ResourceListDetailComplete", num);
+ astman_send_list_complete_start(s, m, "ResourceListDetailComplete", ami.count);
astman_send_list_complete_end(s);
return 0;
}
@@ -3739,6 +3755,541 @@ static int ami_show_resource_lists(struct mansession *s, const struct message *m
#define AMI_SHOW_SUBSCRIPTIONS_INBOUND "PJSIPShowSubscriptionsInbound"
#define AMI_SHOW_SUBSCRIPTIONS_OUTBOUND "PJSIPShowSubscriptionsOutbound"
+#define MAX_REGEX_ERROR_LEN 128
+
+struct cli_sub_parms {
+ /*! CLI handler entry e parameter */
+ struct ast_cli_entry *e;
+ /*! CLI handler entry a parameter */
+ struct ast_cli_args *a;
+ /*! CLI subscription entry output line(s) */
+ struct ast_str *buf;
+ /*! Compiled regular expression to select if buf is written to CLI when not NULL. */
+ regex_t *like;
+ int count;
+};
+
+struct cli_sub_complete_parms {
+ struct ast_cli_args *a;
+ /*! Found callid for search position */
+ char *callid;
+ int wordlen;
+ int which;
+};
+
+static int cli_complete_subscription_common(struct sip_subscription_tree *sub_tree, struct cli_sub_complete_parms *cli)
+{
+ pj_str_t *callid;
+
+ if (!sub_tree->dlg) {
+ return 0;
+ }
+
+ callid = &sub_tree->dlg->call_id->id;
+ if (cli->wordlen <= pj_strlen(callid)
+ && !strncasecmp(cli->a->word, pj_strbuf(callid), cli->wordlen)
+ && (++cli->which > cli->a->n)) {
+ cli->callid = ast_malloc(pj_strlen(callid) + 1);
+ if (cli->callid) {
+ ast_copy_pj_str(cli->callid, callid, pj_strlen(callid) + 1);
+ }
+ return -1;
+ }
+ return 0;
+}
+
+static int cli_complete_subscription_inbound(struct sip_subscription_tree *sub_tree, void *arg)
+{
+ return sub_tree->role == AST_SIP_NOTIFIER
+ ? cli_complete_subscription_common(sub_tree, arg) : 0;
+}
+
+static int cli_complete_subscription_outbound(struct sip_subscription_tree *sub_tree, void *arg)
+{
+ return sub_tree->role == AST_SIP_SUBSCRIBER
+ ? cli_complete_subscription_common(sub_tree, arg) : 0;
+}
+
+static char *cli_complete_subscription_callid(struct ast_cli_args *a)
+{
+ struct cli_sub_complete_parms cli;
+ on_subscription_t on_subscription;
+
+ if (a->pos != 4) {
+ return NULL;
+ }
+
+ if (!strcasecmp(a->argv[3], "inbound")) {
+ on_subscription = cli_complete_subscription_inbound;
+ } else if (!strcasecmp(a->argv[3], "outbound")) {
+ on_subscription = cli_complete_subscription_outbound;
+ } else {
+ /* Should never get here */
+ ast_assert(0);
+ return NULL;
+ }
+
+ cli.a = a;
+ cli.callid = NULL;
+ cli.wordlen = strlen(a->word);
+ cli.which = 0;
+ for_each_subscription(on_subscription, &cli);
+
+ return cli.callid;
+}
+
+static int cli_subscription_expiry(struct sip_subscription_tree *sub_tree)
+{
+ int expiry;
+
+ expiry = sub_tree->persistence
+ ? ast_tvdiff_ms(sub_tree->persistence->expires, ast_tvnow()) / 1000
+ : 0;
+ if (expiry < 0) {
+ /* Subscription expired */
+ expiry = 0;
+ }
+ return expiry;
+}
+
+static int cli_show_subscription_common(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)
+{
+ const char *callid = (const char *) cli->buf;/* Member repurposed to pass in callid */
+ pj_str_t *sub_callid;
+ struct ast_str *buf;
+ char *src;
+ char *dest;
+ char *key;
+ char *value;
+ char *value_end;
+ int key_len;
+ int key_filler_width;
+ int value_len;
+
+ if (!sub_tree->dlg) {
+ return 0;
+ }
+ sub_callid = &sub_tree->dlg->call_id->id;
+ if (pj_strcmp2(sub_callid, callid)) {
+ return 0;
+ }
+
+ buf = ast_str_create(512);
+ if (!buf) {
+ return -1;
+ }
+
+ ast_cli(cli->a->fd,
+ "%-20s: %s\n"
+ "===========================================================================\n",
+ "ParameterName", "ParameterValue");
+
+ ast_str_append(&buf, 0, "Resource: %s\n", sub_tree->root->resource);
+ ast_str_append(&buf, 0, "Event: %s\n", sub_tree->root->handler->event_name);
+ ast_str_append(&buf, 0, "Expiry: %d\n", cli_subscription_expiry(sub_tree));
+
+ sip_subscription_to_ami(sub_tree, &buf);
+
+ /* Convert AMI \r\n to \n line terminators. */
+ src = strchr(ast_str_buffer(buf), '\r');
+ if (src) {
+ dest = src;
+ ++src;
+ while (*src) {
+ if (*src == '\r') {
+ ++src;
+ continue;
+ }
+ *dest++ = *src++;
+ }
+ *dest = '\0';
+ ast_str_update(buf);
+ }
+
+ /* Reformat AMI key value pairs to pretty columns */
+ key = ast_str_buffer(buf);
+ do {
+ value = strchr(key, ':');
+ if (!value) {
+ break;
+ }
+ value_end = strchr(value, '\n');
+ if (!value_end) {
+ break;
+ }
+
+ /* Calculate field lengths */
+ key_len = value - key;
+ key_filler_width = 20 - key_len;
+ if (key_filler_width < 0) {
+ key_filler_width = 0;
+ }
+ value_len = value_end - value;
+
+ ast_cli(cli->a->fd, "%.*s%*s%.*s\n",
+ key_len, key, key_filler_width, "",
+ value_len, value);
+
+ key = value_end + 1;
+ } while (*key);
+ ast_cli(cli->a->fd, "\n");
+
+ ast_free(buf);
+
+ return -1;
+}
+
+static int cli_show_subscription_inbound(struct sip_subscription_tree *sub_tree, void *arg)
+{
+ return sub_tree->role == AST_SIP_NOTIFIER
+ ? cli_show_subscription_common(sub_tree, arg) : 0;
+}
+
+static int cli_show_subscription_outbound(struct sip_subscription_tree *sub_tree, void *arg)
+{
+ return sub_tree->role == AST_SIP_SUBSCRIBER
+ ? cli_show_subscription_common(sub_tree, arg) : 0;
+}
+
+static char *cli_show_subscription_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ on_subscription_t on_subscription;
+ struct cli_sub_parms cli;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "pjsip show subscription {inbound|outbound}";
+ e->usage = "Usage:\n"
+ " pjsip show subscription inbound <call-id>\n"
+ " pjsip show subscription outbound <call-id>\n"
+ " Show active subscription with the dialog call-id\n";
+ return NULL;
+ case CLI_GENERATE:
+ return cli_complete_subscription_callid(a);
+ }
+
+ if (a->argc != 5) {
+ return CLI_SHOWUSAGE;
+ }
+
+ if (!strcasecmp(a->argv[3], "inbound")) {
+ on_subscription = cli_show_subscription_inbound;
+ } else if (!strcasecmp(a->argv[3], "outbound")) {
+ on_subscription = cli_show_subscription_outbound;
+ } else {
+ /* Should never get here */
+ ast_assert(0);
+ return NULL;
+ }
+
+ /* Find the subscription with the specified call-id */
+ cli.a = a;
+ cli.e = e;
+ cli.buf = (void *) a->argv[4];/* Repurpose the buf member to pass in callid */
+ for_each_subscription(on_subscription, &cli);
+
+ return CLI_SUCCESS;
+}
+
+#define CLI_SHOW_SUB_FORMAT_HEADER \
+ "Endpoint: <Endpoint/Caller-ID.............................................>\n" \
+ "Resource: <Resource/Event.................................................>\n" \
+ " Expiry: <Expiry> <Call-id..............................................>\n" \
+ "===========================================================================\n\n"
+#define CLI_SHOW_SUB_FORMAT_ENTRY \
+ "Endpoint: %s/%s\n" \
+ "Resource: %s/%s\n" \
+ " Expiry: %8d %s\n\n"
+
+static int cli_show_subscriptions_detail(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)
+{
+ char caller_id[256];
+ char callid[256];
+
+ ast_callerid_merge(caller_id, sizeof(caller_id),
+ S_COR(sub_tree->endpoint->id.self.name.valid,
+ sub_tree->endpoint->id.self.name.str, NULL),
+ S_COR(sub_tree->endpoint->id.self.number.valid,
+ sub_tree->endpoint->id.self.number.str, NULL),
+ "<none>");
+
+ /* Call-id */
+ if (sub_tree->dlg) {
+ ast_copy_pj_str(callid, &sub_tree->dlg->call_id->id, sizeof(callid));
+ } else {
+ ast_copy_string(callid, "<unknown>", sizeof(callid));
+ }
+
+ ast_str_set(&cli->buf, 0, CLI_SHOW_SUB_FORMAT_ENTRY,
+ ast_sorcery_object_get_id(sub_tree->endpoint), caller_id,
+ sub_tree->root->resource, sub_tree->root->handler->event_name,
+ cli_subscription_expiry(sub_tree), callid);
+
+ if (cli->like) {
+ if (regexec(cli->like, ast_str_buffer(cli->buf), 0, NULL, 0)) {
+ /* Output line did not match the regex */
+ return 0;
+ }
+ }
+
+ ast_cli(cli->a->fd, "%s", ast_str_buffer(cli->buf));
+ ++cli->count;
+
+ return 0;
+}
+
+static int cli_show_subscriptions_inbound(struct sip_subscription_tree *sub_tree, void *arg)
+{
+ return sub_tree->role == AST_SIP_NOTIFIER
+ ? cli_show_subscriptions_detail(sub_tree, arg) : 0;
+}
+
+static int cli_show_subscriptions_outbound(struct sip_subscription_tree *sub_tree, void *arg)
+{
+ return sub_tree->role == AST_SIP_SUBSCRIBER
+ ? cli_show_subscriptions_detail(sub_tree, arg) : 0;
+}
+
+static char *cli_show_subscriptions_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ on_subscription_t on_subscription;
+ struct cli_sub_parms cli;
+ regex_t like;
+ const char *regex;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "pjsip show subscriptions {inbound|outbound} [like]";
+ e->usage = "Usage:\n"
+ " pjsip show subscriptions inbound [like <regex>]\n"
+ " Show active inbound subscriptions\n"
+ " pjsip show subscriptions outbound [like <regex>]\n"
+ " Show active outbound subscriptions\n"
+ "\n"
+ " The regex selects a subscriptions output that matches.\n"
+ " i.e., All output lines for a subscription are checked\n"
+ " as a block by the regex.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc != 4 && a->argc != 6) {
+ return CLI_SHOWUSAGE;
+ }
+ if (!strcasecmp(a->argv[3], "inbound")) {
+ on_subscription = cli_show_subscriptions_inbound;
+ } else if (!strcasecmp(a->argv[3], "outbound")) {
+ on_subscription = cli_show_subscriptions_outbound;
+ } else {
+ /* Should never get here */
+ ast_assert(0);
+ return CLI_SHOWUSAGE;
+ }
+ if (a->argc == 6) {
+ int rc;
+
+ if (strcasecmp(a->argv[4], "like")) {
+ return CLI_SHOWUSAGE;
+ }
+
+ /* Setup regular expression */
+ memset(&like, 0, sizeof(like));
+ cli.like = &like;
+ regex = a->argv[5];
+ rc = regcomp(cli.like, regex, REG_EXTENDED | REG_NOSUB);
+ if (rc) {
+ char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
+
+ regerror(rc, cli.like, regerr, MAX_REGEX_ERROR_LEN);
+ ast_cli(a->fd, "Regular expression '%s' failed to compile: %s\n",
+ regex, regerr);
+ return CLI_FAILURE;
+ }
+ } else {
+ cli.like = NULL;
+ regex = NULL;
+ }
+
+ cli.a = a;
+ cli.e = e;
+ cli.count = 0;
+ cli.buf = ast_str_create(256);
+ if (!cli.buf) {
+ if (cli.like) {
+ regfree(cli.like);
+ }
+ return CLI_FAILURE;
+ }
+
+ ast_cli(a->fd, CLI_SHOW_SUB_FORMAT_HEADER);
+ for_each_subscription(on_subscription, &cli);
+ ast_cli(a->fd, "%d active subscriptions%s%s%s\n",
+ cli.count,
+ regex ? " matched \"" : "",
+ regex ?: "",
+ regex ? "\"" : "");
+
+ ast_free(cli.buf);
+ if (cli.like) {
+ regfree(cli.like);
+ }
+
+ return CLI_SUCCESS;
+}
+
+#define CLI_LIST_SUB_FORMAT_HEADER "%-30.30s %-30.30s %6.6s %s\n"
+#define CLI_LIST_SUB_FORMAT_ENTRY "%-30.30s %-30.30s %6d %s\n"
+
+static int cli_list_subscriptions_detail(struct sip_subscription_tree *sub_tree, struct cli_sub_parms *cli)
+{
+ char ep_cid_buf[50];
+ char res_evt_buf[50];
+ char callid[256];
+
+ /* Endpoint/CID column */
+ snprintf(ep_cid_buf, sizeof(ep_cid_buf), "%s/%s",
+ ast_sorcery_object_get_id(sub_tree->endpoint),
+ S_COR(sub_tree->endpoint->id.self.name.valid, sub_tree->endpoint->id.self.name.str,
+ S_COR(sub_tree->endpoint->id.self.number.valid,
+ sub_tree->endpoint->id.self.number.str, "<none>")));
+
+ /* Resource/Event column */
+ snprintf(res_evt_buf, sizeof(res_evt_buf), "%s/%s",
+ sub_tree->root->resource,
+ sub_tree->root->handler->event_name);
+
+ /* Call-id column */
+ if (sub_tree->dlg) {
+ ast_copy_pj_str(callid, &sub_tree->dlg->call_id->id, sizeof(callid));
+ } else {
+ ast_copy_string(callid, "<unknown>", sizeof(callid));
+ }
+
+ ast_str_set(&cli->buf, 0, CLI_LIST_SUB_FORMAT_ENTRY,
+ ep_cid_buf,
+ res_evt_buf,
+ cli_subscription_expiry(sub_tree),
+ callid);
+
+ if (cli->like) {
+ if (regexec(cli->like, ast_str_buffer(cli->buf), 0, NULL, 0)) {
+ /* Output line did not match the regex */
+ return 0;
+ }
+ }
+
+ ast_cli(cli->a->fd, "%s", ast_str_buffer(cli->buf));
+ ++cli->count;
+
+ return 0;
+}
+
+static int cli_list_subscriptions_inbound(struct sip_subscription_tree *sub_tree, void *arg)
+{
+ return sub_tree->role == AST_SIP_NOTIFIER
+ ? cli_list_subscriptions_detail(sub_tree, arg) : 0;
+}
+
+static int cli_list_subscriptions_outbound(struct sip_subscription_tree *sub_tree, void *arg)
+{
+ return sub_tree->role == AST_SIP_SUBSCRIBER
+ ? cli_list_subscriptions_detail(sub_tree, arg) : 0;
+}
+
+static char *cli_list_subscriptions_inout(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ on_subscription_t on_subscription;
+ struct cli_sub_parms cli;
+ regex_t like;
+ const char *regex;
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "pjsip list subscriptions {inbound|outbound} [like]";
+ e->usage = "Usage:\n"
+ " pjsip list subscriptions inbound [like <regex>]\n"
+ " List active inbound subscriptions\n"
+ " pjsip list subscriptions outbound [like <regex>]\n"
+ " List active outbound subscriptions\n"
+ "\n"
+ " The regex selects output lines that match.\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (a->argc != 4 && a->argc != 6) {
+ return CLI_SHOWUSAGE;
+ }
+ if (!strcasecmp(a->argv[3], "inbound")) {
+ on_subscription = cli_list_subscriptions_inbound;
+ } else if (!strcasecmp(a->argv[3], "outbound")) {
+ on_subscription = cli_list_subscriptions_outbound;
+ } else {
+ /* Should never get here */
+ ast_assert(0);
+ return CLI_SHOWUSAGE;
+ }
+ if (a->argc == 6) {
+ int rc;
+
+ if (strcasecmp(a->argv[4], "like")) {
+ return CLI_SHOWUSAGE;
+ }
+
+ /* Setup regular expression */
+ memset(&like, 0, sizeof(like));
+ cli.like = &like;
+ regex = a->argv[5];
+ rc = regcomp(cli.like, regex, REG_EXTENDED | REG_NOSUB);
+ if (rc) {
+ char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
+
+ regerror(rc, cli.like, regerr, MAX_REGEX_ERROR_LEN);
+ ast_cli(a->fd, "Regular expression '%s' failed to compile: %s\n",
+ regex, regerr);
+ return CLI_FAILURE;
+ }
+ } else {
+ cli.like = NULL;
+ regex = NULL;
+ }
+
+ cli.a = a;
+ cli.e = e;
+ cli.count = 0;
+ cli.buf = ast_str_create(256);
+ if (!cli.buf) {
+ if (cli.like) {
+ regfree(cli.like);
+ }
+ return CLI_FAILURE;
+ }
+
+ ast_cli(a->fd, CLI_LIST_SUB_FORMAT_HEADER,
+ "Endpoint/CLI", "Resource/Event", "Expiry", "Call-id");
+ for_each_subscription(on_subscription, &cli);
+ ast_cli(a->fd, "\n%d active subscriptions%s%s%s\n",
+ cli.count,
+ regex ? " matched \"" : "",
+ regex ?: "",
+ regex ? "\"" : "");
+
+ ast_free(cli.buf);
+ if (cli.like) {
+ regfree(cli.like);
+ }
+
+ return CLI_SUCCESS;
+}
+
+static struct ast_cli_entry cli_commands[] = {
+ AST_CLI_DEFINE(cli_list_subscriptions_inout, "List active inbound/outbound subscriptions"),
+ AST_CLI_DEFINE(cli_show_subscription_inout, "Show active subscription details"),
+ AST_CLI_DEFINE(cli_show_subscriptions_inout, "Show active inbound/outbound subscriptions"),
+};
+
static int persistence_endpoint_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
{
struct subscription_persistence *persistence = obj;
@@ -4680,6 +5231,8 @@ static int load_module(void)
ast_manager_register_xml("PJSIPShowResourceLists", EVENT_FLAG_SYSTEM,
ami_show_resource_lists);
+ ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
+
AST_TEST_REGISTER(resource_tree);
AST_TEST_REGISTER(complex_resource_tree);
AST_TEST_REGISTER(bad_resource);
@@ -4693,6 +5246,16 @@ static int load_module(void)
static int unload_module(void)
{
+ AST_TEST_UNREGISTER(resource_tree);
+ AST_TEST_UNREGISTER(complex_resource_tree);
+ AST_TEST_UNREGISTER(bad_resource);
+ AST_TEST_UNREGISTER(bad_branch);
+ AST_TEST_UNREGISTER(duplicate_resource);
+ AST_TEST_UNREGISTER(loop);
+ AST_TEST_UNREGISTER(bad_event);
+
+ ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
+
ast_manager_unregister(AMI_SHOW_SUBSCRIPTIONS_OUTBOUND);
ast_manager_unregister(AMI_SHOW_SUBSCRIPTIONS_INBOUND);
ast_manager_unregister("PJSIPShowResourceLists");
@@ -4702,14 +5265,6 @@ static int unload_module(void)
ast_sched_context_destroy(sched);
}
- AST_TEST_UNREGISTER(resource_tree);
- AST_TEST_UNREGISTER(complex_resource_tree);
- AST_TEST_UNREGISTER(bad_resource);
- AST_TEST_UNREGISTER(bad_branch);
- AST_TEST_UNREGISTER(duplicate_resource);
- AST_TEST_UNREGISTER(loop);
- AST_TEST_UNREGISTER(bad_event);
-
return 0;
}
diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c
index 99295d5..d52a922 100644
--- a/res/res_pjsip_refer.c
+++ b/res/res_pjsip_refer.c
@@ -573,6 +573,7 @@ static void refer_blind_callback(struct ast_channel *chan, struct transfer_chann
pjsip_generic_string_hdr *referred_by;
static const pj_str_t str_referred_by = { "Referred-By", 11 };
+ static const pj_str_t str_referred_by_s = { "b", 1 };
pbx_builtin_setvar_helper(chan, "SIPTRANSFER", "yes");
@@ -651,8 +652,8 @@ static void refer_blind_callback(struct ast_channel *chan, struct transfer_chann
pbx_builtin_setvar_helper(chan, "SIPREFERRINGCONTEXT", S_OR(refer->context, NULL));
- referred_by = pjsip_msg_find_hdr_by_name(refer->rdata->msg_info.msg,
- &str_referred_by, NULL);
+ referred_by = pjsip_msg_find_hdr_by_names(refer->rdata->msg_info.msg,
+ &str_referred_by, &str_referred_by_s, NULL);
if (referred_by) {
size_t uri_size = pj_strlen(&referred_by->hvalue) + 1;
char *uri = ast_alloca(uri_size);
@@ -1006,6 +1007,7 @@ static int refer_incoming_refer_request(struct ast_sip_session *session, struct
int response;
static const pj_str_t str_refer_to = { "Refer-To", 8 };
+ static const pj_str_t str_refer_to_s = { "r", 1 };
static const pj_str_t str_replaces = { "Replaces", 8 };
if (!session->channel) {
@@ -1024,7 +1026,7 @@ static int refer_incoming_refer_request(struct ast_sip_session *session, struct
}
/* A Refer-To header is required */
- refer_to = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL);
+ refer_to = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg, &str_refer_to, &str_refer_to_s, NULL);
if (!refer_to) {
pjsip_dlg_respond(session->inv_session->dlg, rdata, 400, NULL, NULL, NULL);
ast_debug(3, "Received a REFER without Refer-To on channel '%s' from endpoint '%s'\n",
diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c
index a13f8f8..d54bffa 100644
--- a/res/res_pjsip_registrar.c
+++ b/res/res_pjsip_registrar.c
@@ -46,11 +46,32 @@
<syntax />
<description>
<para>
- In response <literal>InboundRegistrationDetail</literal> events showing configuration and status
- information are raised for each inbound registration object. As well as <literal>AuthDetail</literal>
- events for each associated auth object. Once all events are completed an
- <literal>InboundRegistrationDetailComplete</literal> is issued.
- </para>
+ In response, <literal>InboundRegistrationDetail</literal> events showing configuration
+ and status information are raised for all contacts, static or dynamic. Once all events
+ are completed an <literal>InboundRegistrationDetailComplete</literal> is issued.
+ </para>
+ <warning><para>
+ This command just dumps all coonfigured AORs with contacts, even if the contact
+ is a permanent one. To really get just inbound registrations, use
+ <literal>PJSIPShowRegistrationInboundContactStatuses</literal>.
+ </para>
+ </warning>
+ </description>
+ <see-also>
+ <ref type="manager" module="res_pjsip_registrar">PJSIPShowRegistrationInboundContactStatuses</ref>
+ </see-also>
+ </manager>
+ <manager name="PJSIPShowRegistrationInboundContactStatuses" language="en_US">
+ <synopsis>
+ Lists ContactStatuses for PJSIP inbound registrations.
+ </synopsis>
+ <syntax />
+ <description>
+ <para>
+ In response, <literal>ContactStatusDetail</literal> events showing status information
+ are raised for each inbound registration (dynamic contact) object. Once all events
+ are completed a <literal>ContactStatusDetailComplete</literal> event is issued.
+ </para>
</description>
</manager>
***/
@@ -793,6 +814,42 @@ static int ami_show_registrations(struct mansession *s, const struct message *m)
return 0;
}
+static int ami_show_registration_contact_statuses(struct mansession *s, const struct message *m)
+{
+ int count = 0;
+ struct ast_sip_ami ami = { .s = s, .m = m, .arg = NULL, .action_id = astman_get_header(m, "ActionID"), };
+ struct ao2_container *contacts = ast_sorcery_retrieve_by_fields(
+ ast_sip_get_sorcery(), "contact", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
+ struct ao2_iterator i;
+ struct ast_sip_contact *contact;
+
+ astman_send_listack(s, m, "Following are ContactStatusEvents for each Inbound "
+ "registration", "start");
+
+ if (contacts) {
+ i = ao2_iterator_init(contacts, 0);
+ while ((contact = ao2_iterator_next(&i))) {
+ struct ast_sip_contact_wrapper wrapper;
+
+ wrapper.aor_id = (char *)contact->aor;
+ wrapper.contact = contact;
+ wrapper.contact_id = (char *)ast_sorcery_object_get_id(contact);
+
+ ast_sip_format_contact_ami(&wrapper, &ami, 0);
+ count++;
+
+ ao2_ref(contact, -1);
+ }
+ ao2_iterator_destroy(&i);
+ ao2_ref(contacts, -1);
+ }
+
+ astman_send_list_complete_start(s, m, "ContactStatusDetailComplete", count);
+ astman_send_list_complete_end(s);
+ return 0;
+}
+
+#define AMI_SHOW_REGISTRATION_CONTACT_STATUSES "PJSIPShowRegistrationInboundContactStatuses"
#define AMI_SHOW_REGISTRATIONS "PJSIPShowRegistrationsInbound"
static pjsip_module registrar_module = {
@@ -825,6 +882,8 @@ static int load_module(void)
ast_manager_register_xml(AMI_SHOW_REGISTRATIONS, EVENT_FLAG_SYSTEM,
ami_show_registrations);
+ ast_manager_register_xml(AMI_SHOW_REGISTRATION_CONTACT_STATUSES, EVENT_FLAG_SYSTEM,
+ ami_show_registration_contact_statuses);
return AST_MODULE_LOAD_SUCCESS;
}
@@ -832,6 +891,7 @@ static int load_module(void)
static int unload_module(void)
{
ast_manager_unregister(AMI_SHOW_REGISTRATIONS);
+ ast_manager_unregister(AMI_SHOW_REGISTRATION_CONTACT_STATUSES);
ast_sip_unregister_service(®istrar_module);
return 0;
}
diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c
index 66550a2..b27050e 100644
--- a/res/res_pjsip_sdp_rtp.c
+++ b/res/res_pjsip_sdp_rtp.c
@@ -51,6 +51,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/acl.h"
#include "asterisk/sdp_srtp.h"
#include "asterisk/dsp.h"
+#include "asterisk/utils.h"
#include "asterisk/res_pjsip.h"
#include "asterisk/res_pjsip_session.h"
@@ -1493,7 +1494,11 @@ static int load_module(void)
{
CHECK_PJSIP_SESSION_MODULE_LOADED();
- ast_sockaddr_parse(&address_rtp, "::", 0);
+ if (ast_check_ipv6()) {
+ ast_sockaddr_parse(&address_rtp, "::", 0);
+ } else {
+ ast_sockaddr_parse(&address_rtp, "0.0.0.0", 0);
+ }
if (!(sched = ast_sched_context_create())) {
ast_log(LOG_ERROR, "Unable to create scheduler context.\n");
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index 9e363a1..3c4f102 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -1736,6 +1736,8 @@ struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint
/* If we still have no URI to dial fail to create the session */
if (ast_strlen_zero(uri)) {
+ ast_log(LOG_ERROR, "Endpoint '%s': No URI available. Is endpoint registered?\n",
+ ast_sorcery_object_get_id(endpoint));
return NULL;
}
@@ -1996,6 +1998,12 @@ static enum sip_get_destination_result get_destination(struct ast_sip_session *s
if (!strcmp(session->exten, pickupexten) ||
ast_exists_extension(NULL, session->endpoint->context, session->exten, 1, NULL)) {
+ size_t size = pj_strlen(&sip_ruri->host) + 1;
+ char *domain = ast_alloca(size);
+
+ ast_copy_pj_str(domain, &sip_ruri->host, size);
+ pbx_builtin_setvar_helper(session->channel, "SIPDOMAIN", domain);
+
return SIP_GET_DEST_EXTEN_FOUND;
}
/* XXX In reality, we'll likely have further options so that partial matches
diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c
index cf12111..0787f07 100644
--- a/res/res_pjsip_t38.c
+++ b/res/res_pjsip_t38.c
@@ -44,6 +44,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/netsock2.h"
#include "asterisk/channel.h"
#include "asterisk/acl.h"
+#include "asterisk/utils.h"
#include "asterisk/res_pjsip.h"
#include "asterisk/res_pjsip_session.h"
@@ -918,7 +919,11 @@ static int load_module(void)
{
CHECK_PJSIP_SESSION_MODULE_LOADED();
- ast_sockaddr_parse(&address, "::", 0);
+ if (ast_check_ipv6()) {
+ ast_sockaddr_parse(&address, "::", 0);
+ } else {
+ ast_sockaddr_parse(&address, "0.0.0.0", 0);
+ }
if (ast_sip_session_register_supplement(&t38_supplement)) {
ast_log(LOG_ERROR, "Unable to register T.38 session supplement\n");
diff --git a/res/res_pjsip_transport_websocket.c b/res/res_pjsip_transport_websocket.c
index 4181828..82ade56 100644
--- a/res/res_pjsip_transport_websocket.c
+++ b/res/res_pjsip_transport_websocket.c
@@ -378,7 +378,6 @@ static void websocket_cb(struct ast_websocket *session, struct ast_variable *par
static pj_bool_t websocket_on_rx_msg(pjsip_rx_data *rdata)
{
static const pj_str_t STR_WS = { "ws", 2 };
- static const pj_str_t STR_WSS = { "wss", 3 };
pjsip_contact_hdr *contact;
long type = rdata->tp_info.transport->key.type;
@@ -395,7 +394,7 @@ static pj_bool_t websocket_on_rx_msg(pjsip_rx_data *rdata)
uri->port = rdata->pkt_info.src_port;
ast_debug(4, "Re-wrote Contact URI host/port to %.*s:%d\n",
(int)pj_strlen(&uri->host), pj_strbuf(&uri->host), uri->port);
- pj_strdup(rdata->tp_info.pool, &uri->transport_param, (type == (long)transport_type_ws) ? &STR_WS : &STR_WSS);
+ pj_strdup(rdata->tp_info.pool, &uri->transport_param, &STR_WS);
}
rdata->msg_info.via->rport_param = 0;
@@ -431,7 +430,7 @@ static int load_module(void)
CHECK_PJSIP_MODULE_LOADED();
pjsip_transport_register_type(PJSIP_TRANSPORT_RELIABLE, "WS", 5060, &transport_type_ws);
- pjsip_transport_register_type(PJSIP_TRANSPORT_RELIABLE | PJSIP_TRANSPORT_SECURE, "WSS", 5060, &transport_type_wss);
+ pjsip_transport_register_type(PJSIP_TRANSPORT_RELIABLE | PJSIP_TRANSPORT_SECURE, "WS", 5060, &transport_type_wss);
if (ast_sip_register_service(&websocket_module) != PJ_SUCCESS) {
return AST_MODULE_LOAD_DECLINE;
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index 75bace2..ba2d815 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -54,6 +54,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <ifaddrs.h>
#endif
+#include "asterisk/options.h"
#include "asterisk/stun.h"
#include "asterisk/pbx.h"
#include "asterisk/frame.h"
@@ -231,6 +232,7 @@ struct dtls_details {
/*! \brief RTP session description */
struct ast_rtp {
int s;
+ /*! \note The f.subclass.format holds a ref. */
struct ast_frame f;
unsigned char rawdata[8192 + AST_FRIENDLY_OFFSET];
unsigned int ssrc; /*!< Synchronization source, RFC 3550, page 10. */
@@ -1454,12 +1456,6 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con
return -1;
}
- if (!(certbio = BIO_new(BIO_s_file()))) {
- ast_log(LOG_ERROR, "Failed to allocate memory for certificate fingerprinting on RTP instance '%p'\n",
- instance);
- return -1;
- }
-
if (rtp->local_hash == AST_RTP_DTLS_HASH_SHA1) {
type = EVP_sha1();
} else if (rtp->local_hash == AST_RTP_DTLS_HASH_SHA256) {
@@ -1470,6 +1466,12 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con
return -1;
}
+ if (!(certbio = BIO_new(BIO_s_file()))) {
+ ast_log(LOG_ERROR, "Failed to allocate memory for certificate fingerprinting on RTP instance '%p'\n",
+ instance);
+ return -1;
+ }
+
if (!BIO_read_filename(certbio, dtls_cfg->certfile) ||
!(cert = PEM_read_bio_X509(certbio, NULL, 0, NULL)) ||
!X509_digest(cert, type, fingerprint, &size) ||
@@ -2766,6 +2768,7 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance)
if (rtp->red) {
AST_SCHED_DEL(rtp->sched, rtp->red->schedid);
ast_free(rtp->red);
+ rtp->red = NULL;
}
#ifdef HAVE_PJPROJECT
@@ -3086,7 +3089,26 @@ static void timeval2ntp(struct timeval tv, unsigned int *msw, unsigned int *lsw)
unsigned int sec, usec, frac;
sec = tv.tv_sec + 2208988800u; /* Sec between 1900 and 1970 */
usec = tv.tv_usec;
- frac = (usec << 12) + (usec << 8) - ((usec * 3650) >> 6);
+ /*
+ * Convert usec to 0.32 bit fixed point without overflow.
+ *
+ * = usec * 2^32 / 10^6
+ * = usec * 2^32 / (2^6 * 5^6)
+ * = usec * 2^26 / 5^6
+ *
+ * The usec value needs 20 bits to represent 999999 usec. So
+ * splitting the 2^26 to get the most precision using 32 bit
+ * values gives:
+ *
+ * = ((usec * 2^12) / 5^6) * 2^14
+ *
+ * Splitting the division into two stages preserves all the
+ * available significant bits of usec over doing the division
+ * all at once.
+ *
+ * = ((((usec * 2^12) / 5^3) * 2^7) / 5^3) * 2^7
+ */
+ frac = ((((usec << 12) / 125) << 7) / 125) << 7;
*msw = sec;
*lsw = frac;
}
@@ -3094,7 +3116,8 @@ static void timeval2ntp(struct timeval tv, unsigned int *msw, unsigned int *lsw)
static void ntp2timeval(unsigned int msw, unsigned int lsw, struct timeval *tv)
{
tv->tv_sec = msw - 2208988800u;
- tv->tv_usec = ((lsw << 6) / 3650) - (lsw >> 12) - (lsw >> 8);
+ /* Reverse the sequence in timeval2ntp() */
+ tv->tv_usec = ((((lsw >> 7) * 125) >> 7) * 125) >> 12;
}
static void calculate_lost_packet_statistics(struct ast_rtp *rtp,
@@ -3279,9 +3302,9 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr)
ast_sockaddr_stringify(&remote_address), ice ? " (via ICE)" : "");
ast_verbose(" Our SSRC: %u\n", rtcp_report->ssrc);
if (sr) {
- ast_verbose(" Sent(NTP): %u.%010u\n",
+ ast_verbose(" Sent(NTP): %u.%06u\n",
(unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_sec,
- (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_usec * 4096);
+ (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_usec);
ast_verbose(" Sent(RTP): %u\n", rtcp_report->sender_information.rtp_timestamp);
ast_verbose(" Sent packets: %u\n", rtcp_report->sender_information.packet_count);
ast_verbose(" Sent octets: %u\n", rtcp_report->sender_information.octet_count);
@@ -3466,7 +3489,8 @@ static int ast_rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame
return 0;
}
-static struct ast_frame *red_t140_to_red(struct rtp_red *red) {
+static struct ast_frame *red_t140_to_red(struct rtp_red *red)
+{
unsigned char *data = red->t140red.data.ptr;
int len = 0;
int i;
@@ -3610,6 +3634,11 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr
/* If no smoother is present see if we have to set one up */
if (!rtp->smoother && ast_format_can_be_smoothed(format)) {
unsigned int framing_ms = ast_rtp_codecs_get_framing(ast_rtp_instance_get_codecs(instance));
+ int is_slinear = ast_format_cache_is_slinear(format);
+
+ if (!framing_ms && is_slinear) {
+ framing_ms = ast_format_get_default_ms(format);
+ }
if (framing_ms) {
rtp->smoother = ast_smoother_new((framing_ms * ast_format_get_minimum_bytes(format)) / ast_format_get_minimum_ms(format));
@@ -3618,6 +3647,9 @@ static int ast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *fr
ast_format_get_name(format), framing_ms, ast_format_get_minimum_bytes(format));
return -1;
}
+ if (is_slinear) {
+ ast_smoother_set_flags(rtp->smoother, AST_SMOOTHER_FLAG_BE);
+ }
}
}
@@ -4020,9 +4052,22 @@ static int update_rtt_stats(struct ast_rtp *rtp, unsigned int lsr, unsigned int
lsr_a = ((msw & 0x0000ffff) << 16) | ((lsw & 0xffff0000) >> 16);
rtt = lsr_a - lsr - dlsr;
rtt_msw = (rtt & 0xffff0000) >> 16;
- rtt_lsw = (rtt & 0x0000ffff) << 16;
+ rtt_lsw = (rtt & 0x0000ffff);
rtt_tv.tv_sec = rtt_msw;
- rtt_tv.tv_usec = ((rtt_lsw << 6) / 3650) - (rtt_lsw >> 12) - (rtt_lsw >> 8);
+ /*
+ * Convert 16.16 fixed point rtt_lsw to usec without
+ * overflow.
+ *
+ * = rtt_lsw * 10^6 / 2^16
+ * = rtt_lsw * (2^6 * 5^6) / 2^16
+ * = rtt_lsw * 5^6 / 2^10
+ *
+ * The rtt_lsw value is in 16.16 fixed point format and 5^6
+ * requires 14 bits to represent. We have enough space to
+ * directly do the conversion because there is no integer
+ * component in rtt_lsw.
+ */
+ rtt_tv.tv_usec = (rtt_lsw * 15625) >> 10;
rtp->rtcp->rtt = (double)rtt_tv.tv_sec + ((double)rtt_tv.tv_usec / 1000000);
if (lsr_a - dlsr < lsr) {
return 1;
@@ -4218,9 +4263,9 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
&rtcp_report->sender_information.ntp_timestamp);
rtcp_report->sender_information.rtp_timestamp = ntohl(rtcpheader[i + 2]);
if (rtcp_debug_test_addr(&addr)) {
- ast_verbose("NTP timestamp: %u.%010u\n",
+ ast_verbose("NTP timestamp: %u.%06u\n",
(unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_sec,
- (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_usec * 4096);
+ (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_usec);
ast_verbose("RTP timestamp: %u\n", rtcp_report->sender_information.rtp_timestamp);
ast_verbose("SPC: %u\tSOC: %u\n",
rtcp_report->sender_information.packet_count,
@@ -4881,9 +4926,11 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro
ast_sockaddr_set_port(&rtp->rtcp->us,
ast_sockaddr_port(&rtp->rtcp->us) + 1);
+ ast_sockaddr_copy(&local_addr, &rtp->rtcp->us);
if (!ast_find_ourip(&local_addr, &rtp->rtcp->us, 0)) {
ast_sockaddr_set_port(&local_addr, ast_sockaddr_port(&rtp->rtcp->us));
} else {
+ /* Failed to get local address reset to use default. */
ast_sockaddr_copy(&local_addr, &rtp->rtcp->us);
}
@@ -4972,31 +5019,31 @@ static int ast_rtp_fd(struct ast_rtp_instance *instance, int rtcp)
static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct ast_sockaddr *addr)
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
- struct ast_sockaddr local, us;
+ struct ast_sockaddr local;
+ ast_rtp_instance_get_local_address(instance, &local);
if (!ast_sockaddr_isnull(addr)) {
/* Update the local RTP address with what is being used */
- ast_ouraddrfor(addr, &us);
- ast_rtp_instance_get_local_address(instance, &local);
- ast_sockaddr_set_port(&us, ast_sockaddr_port(&local));
- ast_rtp_instance_set_local_address(instance, &us);
+ if (ast_ouraddrfor(addr, &local)) {
+ /* Failed to update our address so reuse old local address */
+ ast_rtp_instance_get_local_address(instance, &local);
+ } else {
+ ast_rtp_instance_set_local_address(instance, &local);
+ }
}
if (rtp->rtcp) {
ast_debug(1, "Setting RTCP address on RTP instance '%p'\n", instance);
ast_sockaddr_copy(&rtp->rtcp->them, addr);
if (!ast_sockaddr_isnull(addr)) {
- ast_sockaddr_set_port(&rtp->rtcp->them,
- ast_sockaddr_port(addr) + 1);
- }
+ ast_sockaddr_set_port(&rtp->rtcp->them, ast_sockaddr_port(addr) + 1);
- if (!ast_sockaddr_isnull(addr)) {
/* Update the local RTCP address with what is being used */
- ast_sockaddr_set_port(&us, ast_sockaddr_port(&local) + 1);
- ast_sockaddr_copy(&rtp->rtcp->us, &us);
+ ast_sockaddr_set_port(&local, ast_sockaddr_port(&local) + 1);
+ ast_sockaddr_copy(&rtp->rtcp->us, &local);
ast_free(rtp->rtcp->local_addr_str);
- rtp->rtcp->local_addr_str = ast_strdup(ast_sockaddr_stringify(&us));
+ rtp->rtcp->local_addr_str = ast_strdup(ast_sockaddr_stringify(&local));
}
}
@@ -5006,8 +5053,6 @@ static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct
rtp->strict_rtp_state = STRICT_RTP_LEARN;
rtp_learning_seq_init(&rtp->rtp_source_learn, rtp->seqno);
}
-
- return;
}
/*! \brief Write t140 redundacy frame
@@ -5028,22 +5073,21 @@ static int rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
int x;
- if (!(rtp->red = ast_calloc(1, sizeof(*rtp->red)))) {
+ rtp->red = ast_calloc(1, sizeof(*rtp->red));
+ if (!rtp->red) {
return -1;
}
rtp->red->t140.frametype = AST_FRAME_TEXT;
- ao2_replace(rtp->red->t140.subclass.format, ast_format_t140_red);
+ rtp->red->t140.subclass.format = ast_format_t140_red;
rtp->red->t140.data.ptr = &rtp->red->buf_data;
- rtp->red->t140.ts = 0;
rtp->red->t140red = rtp->red->t140;
rtp->red->t140red.data.ptr = &rtp->red->t140red_data;
- rtp->red->t140red.datalen = 0;
+
rtp->red->ti = buffer_time;
rtp->red->num_gen = generations;
rtp->red->hdrlen = generations * 4 + 1;
- rtp->red->prev_ts = 0;
for (x = 0; x < generations; x++) {
rtp->red->pt[x] = payloads[x];
@@ -5053,8 +5097,6 @@ static int rtp_red_init(struct ast_rtp_instance *instance, int buffer_time, int
rtp->red->t140red_data[x*4] = rtp->red->pt[x] = payloads[x]; /* primary pt */
rtp->red->schedid = ast_sched_add(rtp->sched, generations, red_write, instance);
- rtp->red->t140.datalen = 0;
-
return 0;
}
@@ -5182,7 +5224,7 @@ static void ast_rtp_stop(struct ast_rtp_instance *instance)
if (rtp->red) {
AST_SCHED_DEL(rtp->sched, rtp->red->schedid);
- free(rtp->red);
+ ast_free(rtp->red);
rtp->red = NULL;
}
@@ -5635,6 +5677,7 @@ static int load_module(void)
#ifdef HAVE_PJPROJECT
pj_lock_t *lock;
+ AST_PJPROJECT_INIT_LOG_LEVEL();
if (pj_init() != PJ_SUCCESS) {
return AST_MODULE_LOAD_DECLINE;
}
diff --git a/res/res_sorcery_memory_cache.c b/res/res_sorcery_memory_cache.c
index 4ce4e18..5f7ffb6 100644
--- a/res/res_sorcery_memory_cache.c
+++ b/res/res_sorcery_memory_cache.c
@@ -83,6 +83,9 @@
<parameter name="Object" required="true">
<para>The name of the object to mark as stale.</para>
</parameter>
+ <parameter name="Reload" required="false">
+ <para>If true, then immediately reload the object from the backend cache instead of waiting for the next retrieval</para>
+ </parameter>
</syntax>
<description>
<para>Marks an object as stale within a sorcery memory cache.</para>
@@ -1394,10 +1397,8 @@ static void sorcery_memory_cache_load(void *data, const struct ast_sorcery *sorc
ast_debug(1, "Memory cache '%s' associated with sorcery instance '%p' of module '%s' with object type '%s'\n",
cache->name, sorcery, ast_sorcery_get_module(sorcery), type);
- if (cache->full_backend_cache) {
- cache->sorcery = sorcery;
- cache->object_type = ast_strdup(type);
- }
+ cache->sorcery = sorcery;
+ cache->object_type = ast_strdup(type);
}
/*!
@@ -1555,7 +1556,7 @@ static int sorcery_memory_cache_delete(const struct ast_sorcery *sorcery, void *
ao2_unlock(cache->objects);
if (res) {
- ast_log(LOG_ERROR, "Unable to delete object '%s' from sorcery cache\n", ast_sorcery_object_get_id(object));
+ ast_debug(1, "Unable to delete object '%s' from sorcery cache\n", ast_sorcery_object_get_id(object));
}
return res;
@@ -1870,8 +1871,10 @@ static char *sorcery_memory_cache_stale(struct ast_cli_entry *e, int cmd, struct
case CLI_INIT:
e->command = "sorcery memory cache stale";
e->usage =
- "Usage: sorcery memory cache stale <cache name> [object name]\n"
- " Mark a specific object or ALL objects as stale in a sorcery memory cache.\n";
+ "Usage: sorcery memory cache stale <cache name> [object name [reload]]\n"
+ " Mark a specific object or ALL objects as stale in a sorcery memory cache.\n"
+ " If \"reload\" is specified, then the object is marked stale and immediately\n"
+ " retrieved from backend storage to repopulate the cache\n";
return NULL;
case CLI_GENERATE:
if (a->pos == 4) {
@@ -1883,7 +1886,7 @@ static char *sorcery_memory_cache_stale(struct ast_cli_entry *e, int cmd, struct
}
}
- if (a->argc < 5 || a->argc > 6) {
+ if (a->argc < 5 || a->argc > 7) {
return CLI_SHOWUSAGE;
}
@@ -1907,6 +1910,15 @@ static char *sorcery_memory_cache_stale(struct ast_cli_entry *e, int cmd, struct
if (!mark_object_as_stale_in_cache(cache, a->argv[5])) {
ast_cli(a->fd, "Successfully marked object '%s' in memory cache '%s' as stale\n",
a->argv[5], a->argv[4]);
+ if (a->argc == 7 && ast_true(a->argv[6])) {
+ struct sorcery_memory_cached_object *cached;
+
+ cached = ao2_find(cache->objects, a->argv[5], OBJ_SEARCH_KEY | OBJ_NOLOCK);
+ if (cached) {
+ memory_cache_stale_update_object(cache->sorcery, cache, cached);
+ ao2_ref(cached, -1);
+ }
+ }
} else {
ast_cli(a->fd, "Object '%s' in sorcery memory cache '%s' could not be marked as stale as it was not found\n",
a->argv[5], a->argv[4]);
@@ -2066,6 +2078,7 @@ static int sorcery_memory_cache_ami_stale_object(struct mansession *s, const str
{
const char *cache_name = astman_get_header(m, "Cache");
const char *object_name = astman_get_header(m, "Object");
+ const char *reload = astman_get_header(m, "Reload");
struct sorcery_memory_cache *cache;
int res;
@@ -2084,7 +2097,19 @@ static int sorcery_memory_cache_ami_stale_object(struct mansession *s, const str
}
ao2_rdlock(cache->objects);
+
res = mark_object_as_stale_in_cache(cache, object_name);
+
+ if (ast_true(reload)) {
+ struct sorcery_memory_cached_object *cached;
+
+ cached = ao2_find(cache->objects, object_name, OBJ_SEARCH_KEY | OBJ_NOLOCK);
+ if (cached) {
+ memory_cache_stale_update_object(cache->sorcery, cache, cached);
+ ao2_ref(cached, -1);
+ }
+ }
+
ao2_unlock(cache->objects);
ao2_ref(cache, -1);
diff --git a/res/res_stasis.c b/res/res_stasis.c
index 72b536b..55240ba 100644
--- a/res/res_stasis.c
+++ b/res/res_stasis.c
@@ -67,7 +67,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "stasis/app.h"
#include "stasis/control.h"
#include "stasis/messaging.h"
-#include "stasis/cli.h"
#include "stasis/stasis_bridge.h"
#include "asterisk/core_unreal.h"
#include "asterisk/musiconhold.h"
@@ -178,11 +177,6 @@ static struct ast_json *stasis_start_to_json(struct stasis_message *message,
STASIS_MESSAGE_TYPE_DEFN_LOCAL(start_message_type,
.to_json = stasis_start_to_json);
-const char *stasis_app_name(const struct stasis_app *app)
-{
- return app_name(app);
-}
-
/*! AO2 hash function for \ref app */
static int app_hash(const void *obj, const int flags)
{
@@ -944,7 +938,7 @@ static int send_start_msg_snapshots(struct ast_channel *chan, struct stasis_app
if (app_subscribe_channel(app, chan)) {
ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n",
- app_name(app), ast_channel_name(chan));
+ stasis_app_name(app), ast_channel_name(chan));
return -1;
}
@@ -958,7 +952,7 @@ static int send_start_msg_snapshots(struct ast_channel *chan, struct stasis_app
payload->replace_channel = ao2_bump(replace_channel_snapshot);
json_blob = ast_json_pack("{s: s, s: o, s: []}",
- "app", app_name(app),
+ "app", stasis_app_name(app),
"timestamp", ast_json_timeval(ast_tvnow(), NULL),
"args");
if (!json_blob) {
@@ -1028,7 +1022,7 @@ int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan)
return 0;
}
- blob = ast_json_pack("{s: s}", "app", app_name(app));
+ blob = ast_json_pack("{s: s}", "app", stasis_app_name(app));
if (!blob) {
ast_log(LOG_ERROR, "Error packing JSON for StasisEnd message\n");
return -1;
@@ -1474,10 +1468,6 @@ static struct stasis_app *find_app_by_name(const char *app_name)
res = ao2_find(apps_registry, app_name, OBJ_SEARCH_KEY);
}
- if (!res) {
- ast_log(LOG_WARNING, "Could not find app '%s'\n",
- app_name ? : "(null)");
- }
return res;
}
@@ -1958,8 +1948,6 @@ static int unload_module(void)
{
stasis_app_unregister_event_sources();
- cli_cleanup();
-
messaging_cleanup();
cleanup();
@@ -2117,11 +2105,6 @@ static int load_module(void)
return AST_MODULE_LOAD_FAILURE;
}
- if (cli_init()) {
- unload_module();
- return AST_MODULE_LOAD_FAILURE;
- }
-
bridge_stasis_init();
stasis_app_register_event_sources();
diff --git a/res/stasis/app.c b/res/stasis/app.c
index 0bef0ee..e122f34 100644
--- a/res/stasis/app.c
+++ b/res/stasis/app.c
@@ -43,6 +43,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define CHANNEL_ALL "__AST_CHANNEL_ALL_TOPIC"
#define ENDPOINT_ALL "__AST_ENDPOINT_ALL_TOPIC"
+/*! Global debug flag. No need for locking */
+int global_debug;
+
static int unsubscribe(struct stasis_app *app, const char *kind, const char *id, int terminate);
struct stasis_app {
@@ -843,15 +846,64 @@ static void bridge_default_handler(void *data, struct stasis_subscription *sub,
}
}
-void app_set_debug(struct stasis_app *app, int debug)
+void stasis_app_set_debug(struct stasis_app *app, int debug)
{
if (!app) {
return;
}
- {
- SCOPED_AO2LOCK(lock, app);
- app->debug = debug;
+ app->debug = debug;
+}
+
+void stasis_app_set_debug_by_name(const char *app_name, int debug)
+{
+ struct stasis_app *app = stasis_app_get_by_name(app_name);
+
+ if (!app) {
+ return;
+ }
+
+ app->debug = debug;
+ ao2_cleanup(app);
+}
+
+int stasis_app_get_debug(struct stasis_app *app)
+{
+ return (app ? app->debug : 0) || global_debug;
+}
+
+int stasis_app_get_debug_by_name(const char *app_name)
+{
+ RAII_VAR(struct stasis_app *, app, stasis_app_get_by_name(app_name), ao2_cleanup);
+
+ return (app ? app->debug : 0) || global_debug;
+}
+
+void stasis_app_set_global_debug(int debug)
+{
+ global_debug = debug;
+ if (!global_debug) {
+ struct ao2_container *app_names = stasis_app_get_all();
+ struct ao2_iterator it_app_names;
+ char *app_name;
+ struct stasis_app *app;
+
+ if (!app_names || !ao2_container_count(app_names)) {
+ ao2_cleanup(app_names);
+ return;
+ }
+
+ it_app_names = ao2_iterator_init(app_names, 0);
+ while ((app_name = ao2_iterator_next(&it_app_names))) {
+ if ((app = stasis_app_get_by_name(app_name))) {
+ stasis_app_set_debug(app, 0);
+ }
+
+ ao2_cleanup(app_name);
+ ao2_cleanup(app);
+ }
+ ao2_iterator_cleanup(&it_app_names);
+ ao2_cleanup(app_names);
}
}
@@ -952,7 +1004,6 @@ struct stasis_topic *ast_app_get_topic(struct stasis_app *app)
void app_send(struct stasis_app *app, struct ast_json *message)
{
stasis_app_cb handler;
- int debug;
char eid[20];
RAII_VAR(void *, data, NULL, ao2_cleanup);
@@ -965,7 +1016,6 @@ void app_send(struct stasis_app *app, struct ast_json *message)
/* Copy off mutable state with lock held */
{
SCOPED_AO2LOCK(lock, app);
- debug = app->debug;
handler = app->handler;
if (app->data) {
ao2_ref(app->data, +1);
@@ -974,13 +1024,6 @@ void app_send(struct stasis_app *app, struct ast_json *message)
/* Name is immutable; no need to copy */
}
- if (debug) {
- char *dump = ast_json_dump_string_format(message, AST_JSON_PRETTY);
- ast_verb(0, "Dispatching message to Stasis app '%s':\n%s\n",
- app->name, dump);
- ast_json_free(dump);
- }
-
if (!handler) {
ast_verb(3,
"Inactive Stasis app '%s' missed message\n", app->name);
@@ -1053,7 +1096,7 @@ void app_update(struct stasis_app *app, stasis_app_cb handler, void *data)
app->data = data;
}
-const char *app_name(const struct stasis_app *app)
+const char *stasis_app_name(const struct stasis_app *app)
{
return app->name;
}
@@ -1070,7 +1113,7 @@ static int forwards_filter_by_type(void *obj, void *arg, int flags)
return 0;
}
-void app_to_cli(const struct stasis_app *app, struct ast_cli_args *a)
+void stasis_app_to_cli(const struct stasis_app *app, struct ast_cli_args *a)
{
struct ao2_iterator *channels;
struct ao2_iterator *endpoints;
diff --git a/res/stasis/app.h b/res/stasis/app.h
index 6ed6a29..ac4ac59 100644
--- a/res/stasis/app.h
+++ b/res/stasis/app.h
@@ -109,15 +109,6 @@ int app_is_finished(struct stasis_app *app);
void app_update(struct stasis_app *app, stasis_app_cb handler, void *data);
/*!
- * \brief Return an application's name.
- *
- * \param app Application.
- * \return Name of the application.
- * \return \c NULL is \a app is \c NULL.
- */
-const char *app_name(const struct stasis_app *app);
-
-/*!
* \brief Send a message to an application.
*
* \param app Application.
@@ -137,16 +128,6 @@ struct app_forwards;
*/
struct ast_json *app_to_json(const struct stasis_app *app);
-struct ast_cli_args;
-
-/*!
- * \brief Dump properties of a \c stasis_app to the CLI
- *
- * \param app The application
- * \param a The CLI arguments
- */
-void app_to_cli(const struct stasis_app *app, struct ast_cli_args *a);
-
/*!
* \brief Subscribes an application to a channel.
*
@@ -300,12 +281,4 @@ char *app_get_replace_channel_app(struct ast_channel *chan);
*/
int app_send_end_msg(struct stasis_app *app, struct ast_channel *chan);
-/*!
- * \brief Enable/disable debugging on an application
- *
- * \param app The app to debug
- * \param debug If non-zero, enable debugging. If zero, disable.
- */
-void app_set_debug(struct stasis_app *app, int debug);
-
#endif /* _ASTERISK_RES_STASIS_APP_H */
diff --git a/res/stasis/cli.c b/res/stasis/cli.c
deleted file mode 100644
index f1dee55..0000000
--- a/res/stasis/cli.c
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2016, Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief Stasis CLI commands.
- *
- * \author Matt Jordan <mjordan at digium.com>
- */
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include "asterisk/cli.h"
-#include "asterisk/astobj2.h"
-
-#include "cli.h"
-#include "app.h"
-
-
-static char *ari_show_apps(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
- struct ao2_container *apps;
- struct ao2_iterator it_apps;
- char *app;
-
- switch (cmd) {
- case CLI_INIT:
- e->command = "ari show apps";
- e->usage =
- "Usage: ari show apps\n"
- " Lists all registered applications.\n"
- ;
- return NULL;
- case CLI_GENERATE:
- return NULL;
- default:
- break;
- }
-
- if (a->argc != 3) {
- return CLI_SHOWUSAGE;
- }
-
- apps = stasis_app_get_all();
- if (!apps) {
- ast_cli(a->fd, "Unable to retrieve registered applications!\n");
- return CLI_FAILURE;
- }
-
- ast_cli(a->fd, "Application Name \n");
- ast_cli(a->fd, "=========================\n");
- it_apps = ao2_iterator_init(apps, 0);
- while ((app = ao2_iterator_next(&it_apps))) {
- ast_cli(a->fd, "%-25.25s\n", app);
- ao2_ref(app, -1);
- }
-
- ao2_iterator_destroy(&it_apps);
- ao2_ref(apps, -1);
-
- return CLI_SUCCESS;
-}
-
-struct app_complete {
- /*! Nth app to search for */
- int state;
- /*! Which app currently on */
- int which;
-};
-
-static int complete_ari_app_search(void *obj, void *arg, void *data, int flags)
-{
- struct app_complete *search = data;
-
- if (++search->which > search->state) {
- return CMP_MATCH;
- }
- return 0;
-}
-
-static char *complete_ari_app(struct ast_cli_args *a)
-{
- RAII_VAR(struct ao2_container *, apps, stasis_app_get_all(), ao2_cleanup);
- RAII_VAR(char *, app, NULL, ao2_cleanup);
-
- struct app_complete search = {
- .state = a->n,
- };
-
- if (!apps) {
- ast_cli(a->fd, "Error getting ARI applications\n");
- return CLI_FAILURE;
- }
-
- app = ao2_callback_data(apps,
- ast_strlen_zero(a->word) ? 0 : OBJ_PARTIAL_KEY,
- complete_ari_app_search, (char*)a->word, &search);
-
- return app ? ast_strdup(app) : NULL;
-}
-
-static char *complete_ari_show_app(struct ast_cli_args *a)
-{
- if (a->pos == 3) {
- return complete_ari_app(a);
- }
-
- return NULL;
-}
-
-static char *ari_show_app(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
- void *app;
-
- switch (cmd) {
- case CLI_INIT:
- e->command = "ari show app";
- e->usage =
- "Usage: ari show app <application>\n"
- " Provide detailed information about a registered application.\n"
- ;
- return NULL;
- case CLI_GENERATE:
- return complete_ari_show_app(a);
- default:
- break;
- }
-
- if (a->argc != 4) {
- return CLI_SHOWUSAGE;
- }
-
- app = stasis_app_get_by_name(a->argv[3]);
- if (!app) {
- return CLI_FAILURE;
- }
-
- app_to_cli(app, a);
-
- ao2_ref(app, -1);
-
- return CLI_SUCCESS;
-}
-
-static char *ari_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
- void *app;
- int debug;
-
- switch (cmd) {
- case CLI_INIT:
- e->command = "ari set debug";
- e->usage =
- "Usage: ari set debug <application> <on|off>\n"
- " Enable or disable debugging on a specific application.\n"
- ;
- return NULL;
- case CLI_GENERATE:
- return complete_ari_show_app(a);
- default:
- break;
- }
-
- if (a->argc != 5) {
- return CLI_SHOWUSAGE;
- }
-
- app = stasis_app_get_by_name(a->argv[3]);
- if (!app) {
- return CLI_FAILURE;
- }
-
- debug = !strcmp(a->argv[4], "on");
- app_set_debug(app, debug);
- ast_cli(a->fd, "Debugging on '%s' %s\n",
- app_name(app),
- debug ? "enabled" : "disabled");
-
- ao2_ref(app, -1);
-
- return CLI_SUCCESS;
-}
-
-static struct ast_cli_entry cli_ari[] = {
- AST_CLI_DEFINE(ari_show_apps, "List registered ARI applications"),
- AST_CLI_DEFINE(ari_show_app, "Display details of a registered ARI application"),
- AST_CLI_DEFINE(ari_set_debug, "Enable/disable debugging of an ARI application"),
-};
-
-
-int cli_init(void)
-{
- return ast_cli_register_multiple(cli_ari, ARRAY_LEN(cli_ari));
-}
-
-void cli_cleanup(void)
-{
- ast_cli_unregister_multiple(cli_ari, ARRAY_LEN(cli_ari));
-}
diff --git a/res/stasis/cli.h b/res/stasis/cli.h
deleted file mode 100644
index 49235c7..0000000
--- a/res/stasis/cli.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2016, Digium, Inc.
- *
- * Matt Jordan <mjordan at digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-#ifndef _ASTERISK_RES_STASIS_CLI_H
-#define _ASTERISK_RES_STASIS_CLI_H
-
-/*! \file
- *
- * \brief Internal API for Stasis application CLI commands
- *
- * \author Matt Jordan <mjordan at digium.com>
- * \since 13.13.0
- */
-
-/*!
- * \brief Initialize the CLI commands
- *
- * \retval 0 on success
- * \retval non-zero on error
- */
-int cli_init(void);
-
-/*!
- * \brief Cleanup the CLI commands
- */
-void cli_cleanup(void);
-
-#endif /* _ASTERISK_RES_STASIS_CLI_H */
diff --git a/res/stasis/stasis_bridge.c b/res/stasis/stasis_bridge.c
index 9ffc2d7..81b35e3 100644
--- a/res/stasis/stasis_bridge.c
+++ b/res/stasis/stasis_bridge.c
@@ -157,13 +157,13 @@ static int bridge_stasis_push_peek(struct ast_bridge *self, struct ast_bridge_ch
}
to_be_replaced = ast_channel_snapshot_get_latest(ast_channel_uniqueid(swap->chan));
- ast_debug(3, "Copying stasis app name %s from %s to %s\n", app_name(control_app(swap_control)),
+ ast_debug(3, "Copying stasis app name %s from %s to %s\n", stasis_app_name(control_app(swap_control)),
ast_channel_name(swap->chan), ast_channel_name(bridge_channel->chan));
ast_channel_lock(bridge_channel->chan);
/* copy the app name from the swap channel */
- app_set_replace_channel_app(bridge_channel->chan, app_name(control_app(swap_control)));
+ app_set_replace_channel_app(bridge_channel->chan, stasis_app_name(control_app(swap_control)));
/* set the replace channel snapshot */
app_set_replace_channel_snapshot(bridge_channel->chan, to_be_replaced);
@@ -217,6 +217,7 @@ static int bridge_stasis_push(struct ast_bridge *self, struct ast_bridge_channel
*/
return -1;
}
+ ao2_cleanup(control);
/*
* If going into a holding bridge, default the role to participant, if
@@ -236,7 +237,6 @@ static int bridge_stasis_push(struct ast_bridge *self, struct ast_bridge_channel
}
}
- ao2_cleanup(control);
if (self->allowed_capabilities & STASIS_BRIDGE_MIXING_CAPABILITIES) {
ast_bridge_channel_update_linkedids(bridge_channel, swap);
if (ast_test_flag(&self->feature_flags, AST_BRIDGE_FLAG_SMART)) {
diff --git a/rest-api-templates/param_parsing.mustache b/rest-api-templates/param_parsing.mustache
index 247c121..d156ab7 100644
--- a/rest-api-templates/param_parsing.mustache
+++ b/rest-api-templates/param_parsing.mustache
@@ -85,21 +85,6 @@
{{/has_path_parameters}}
{{^is_websocket}}
{{#parse_body}}
- /* Look for a JSON request entity */
- body = ast_http_get_json(ser, headers);
- if (!body) {
- switch (errno) {
- case EFBIG:
- ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
- goto fin;
- case ENOMEM:
- ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
- goto fin;
- case EIO:
- ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
- goto fin;
- }
- }
{{#body_parameter}}
args.{{c_name}} = body;
{{/body_parameter}}
diff --git a/rest-api-templates/res_ari_resource.c.mustache b/rest-api-templates/res_ari_resource.c.mustache
index 08f6204..a59f63d 100644
--- a/rest-api-templates/res_ari_resource.c.mustache
+++ b/rest-api-templates/res_ari_resource.c.mustache
@@ -78,13 +78,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
static void ast_ari_{{c_name}}_{{c_nickname}}_cb(
struct ast_tcptls_session_instance *ser,
struct ast_variable *get_params, struct ast_variable *path_vars,
- struct ast_variable *headers, struct ast_ari_response *response)
+ struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
{
struct ast_ari_{{c_name}}_{{c_nickname}}_args args = {};
{{#has_parameters}}
struct ast_variable *i;
{{/has_parameters}}
- RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
#if defined(AST_DEVMODE)
int is_valid;
int code;
diff --git a/tests/test_ari.c b/tests/test_ari.c
index a61a118..e2c36fb 100644
--- a/tests/test_ari.c
+++ b/tests/test_ari.c
@@ -62,6 +62,7 @@ static void handler(const char *name,
struct ast_variable *get_params,
struct ast_variable *path_vars,
struct ast_variable *headers,
+ struct ast_json *body,
struct ast_ari_response *response)
{
struct ast_json *message = ast_json_pack("{s: s, s: {}, s: {}, s: {}}",
@@ -99,9 +100,10 @@ static void handler(const char *name,
struct ast_variable *get_params, \
struct ast_variable *path_vars, \
struct ast_variable *headers, \
+ struct ast_json *body, \
struct ast_ari_response *response) \
{ \
- handler(#name, response_code, get_params, path_vars, headers, response); \
+ handler(#name, response_code, get_params, path_vars, headers, body, response); \
}
HANDLER(bang_get, 200)
@@ -344,7 +346,8 @@ AST_TEST_DEFINE(invoke_get)
"head2", "head-two",
"path_vars");
- ast_ari_invoke(NULL, "foo", AST_HTTP_GET, get_params, headers, response);
+ ast_ari_invoke(NULL, "foo", AST_HTTP_GET, get_params, headers,
+ ast_json_null(), response);
ast_test_validate(test, 1 == invocation_count);
ast_test_validate(test, 200 == response->response_code);
@@ -381,7 +384,8 @@ AST_TEST_DEFINE(invoke_wildcard)
"path_vars",
"bam", "foshizzle");
- ast_ari_invoke(NULL, "foo/foshizzle", AST_HTTP_GET, get_params, headers, response);
+ ast_ari_invoke(NULL, "foo/foshizzle", AST_HTTP_GET, get_params, headers,
+ ast_json_null(), response);
ast_test_validate(test, 1 == invocation_count);
ast_test_validate(test, 200 == response->response_code);
@@ -418,7 +422,8 @@ AST_TEST_DEFINE(invoke_delete)
"path_vars",
"bam", "foshizzle");
- ast_ari_invoke(NULL, "foo/foshizzle/bang", AST_HTTP_DELETE, get_params, headers, response);
+ ast_ari_invoke(NULL, "foo/foshizzle/bang", AST_HTTP_DELETE, get_params, headers,
+ ast_json_null(), response);
ast_test_validate(test, 1 == invocation_count);
ast_test_validate(test, 204 == response->response_code);
@@ -468,7 +473,8 @@ AST_TEST_DEFINE(invoke_post)
"head2", "head-two",
"path_vars");
- ast_ari_invoke(NULL, "foo/bar", AST_HTTP_POST, get_params, headers, response);
+ ast_ari_invoke(NULL, "foo/bar", AST_HTTP_POST, get_params, headers,
+ ast_json_null(), response);
ast_test_validate(test, 1 == invocation_count);
ast_test_validate(test, 200 == response->response_code);
@@ -497,7 +503,8 @@ AST_TEST_DEFINE(invoke_bad_post)
fixture = setup_invocation_test();
response = response_alloc();
- ast_ari_invoke(NULL, "foo", AST_HTTP_POST, get_params, headers, response);
+ ast_ari_invoke(NULL, "foo", AST_HTTP_POST, get_params, headers,
+ ast_json_null(), response);
ast_test_validate(test, 0 == invocation_count);
ast_test_validate(test, 405 == response->response_code);
@@ -525,7 +532,8 @@ AST_TEST_DEFINE(invoke_not_found)
fixture = setup_invocation_test();
response = response_alloc();
- ast_ari_invoke(NULL, "foo/fizzle/i-am-not-a-resource", AST_HTTP_GET, get_params, headers, response);
+ ast_ari_invoke(NULL, "foo/fizzle/i-am-not-a-resource", AST_HTTP_GET, get_params, headers,
+ ast_json_null(), response);
ast_test_validate(test, 0 == invocation_count);
ast_test_validate(test, 404 == response->response_code);
diff --git a/tests/test_substitution.c b/tests/test_substitution.c
index 46e8ce9..2635430 100644
--- a/tests/test_substitution.c
+++ b/tests/test_substitution.c
@@ -287,7 +287,16 @@ AST_TEST_DEFINE(test_substitution)
TEST(test_expected_result(test, c, "A${${baz}o:-2:1}A", "A2A"));
TEST(test_expected_result(test, c, "A${${baz}o:-2:-1}A", "A2A"));
pbx_builtin_setvar_helper(c, "list1", "ab&cd&ef");
+ TEST(test_expected_result(test, c, "${LISTFILTER(list1,&,ab)}", "cd&ef"));
TEST(test_expected_result(test, c, "${LISTFILTER(list1,&,cd)}", "ab&ef"));
+ TEST(test_expected_result(test, c, "${LISTFILTER(list1,&,ef)}", "ab&cd"));
+ TEST(test_expected_result(test, c, "${LISTFILTER(list1,&,gh)}", "ab&cd&ef"));
+ TEST(test_expected_result(test, c, "${LISTFILTER(list1,&,c)}", "ab&cd&ef"));
+ TEST(test_expected_result(test, c, "${LISTFILTER(list1,&,d)}", "ab&cd&ef"));
+ pbx_builtin_setvar_helper(c, "list2", "ab");
+ TEST(test_expected_result(test, c, "${LISTFILTER(list2,&,ab)}", ""));
+ pbx_builtin_setvar_helper(c, "list_empty", "");
+ TEST(test_expected_result(test, c, "${LISTFILTER(list_empty,&,ab)}", ""));
TEST(test_expected_result(test, c, "${SHELL(printf '%d' 123)},${SHELL(printf '%d' 456)}", "123,456"));
TEST(test_expected_result(test, c, "${foo},${CDR(answer)},${SHELL(printf '%d' 456)}", "123,,456"));
TEST(test_expected_result(test, c, "${foo},${CDR(answer,u)},${SHELL(printf '%d' 456)}", "123,0.000000,456"));
diff --git a/tests/test_voicemail_api.c b/tests/test_voicemail_api.c
index aba1b64..188db4a 100644
--- a/tests/test_voicemail_api.c
+++ b/tests/test_voicemail_api.c
@@ -242,7 +242,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
return AST_TEST_FAIL; \
} \
VM_API_SNAPSHOT_CREATE((mailbox), (context), (folder), 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0); \
- VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 0); \
+ VM_API_INT_VERIFY(0, test_mbox_snapshot->total_msg_num); \
test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot); \
} while (0)
@@ -462,7 +462,7 @@ static int test_vm_api_create_voicemail_files(const char *context, const char *m
folder_path, snapshot->msg_number);
snprintf(snd_path, sizeof(snd_path), "%s/msg%04u.gsm",
folder_path, snapshot->msg_number);
- snprintf(beep_path, sizeof(beep_path), "%s/sounds/en/beep.gsm", ast_config_AST_VAR_DIR);
+ snprintf(beep_path, sizeof(beep_path), "%s/sounds/en/beep.gsm", ast_config_AST_DATA_DIR);
if (test_vm_api_create_voicemail_folder(folder_path)) {
return 1;
@@ -1004,10 +1004,10 @@ AST_TEST_DEFINE(voicemail_api_nominal_move)
test_vm_api_update_test_snapshots(test_mbox_snapshot);
test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
- VM_API_STRING_FIELD_VERIFY(test_snapshots[0]->folder_name, "Family");
- VM_API_STRING_FIELD_VERIFY(test_snapshots[1]->folder_name, "Family");
- VM_API_INT_VERIFY(test_snapshots[1]->msg_number, 0);
- VM_API_INT_VERIFY(test_snapshots[0]->msg_number, 1);
+ VM_API_STRING_FIELD_VERIFY("Family", test_snapshots[0]->folder_name);
+ VM_API_STRING_FIELD_VERIFY("Family", test_snapshots[1]->folder_name);
+ VM_API_INT_VERIFY(0, test_snapshots[1]->msg_number);
+ VM_API_INT_VERIFY(1, test_snapshots[0]->msg_number);
/* Move both of the 2345 messages to Family */
ast_test_status_update(test, "Test move of test_vm_api_2345 messages from Inbox to Family\n");
@@ -1018,8 +1018,8 @@ AST_TEST_DEFINE(voicemail_api_nominal_move)
test_vm_api_update_test_snapshots(test_mbox_snapshot);
test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
- VM_API_STRING_FIELD_VERIFY(test_snapshots[2]->folder_name, "Family");
- VM_API_STRING_FIELD_VERIFY(test_snapshots[3]->folder_name, "Family");
+ VM_API_STRING_FIELD_VERIFY("Family", test_snapshots[2]->folder_name);
+ VM_API_STRING_FIELD_VERIFY("Family", test_snapshots[3]->folder_name);
ast_test_status_update(test, "Test move of test_vm_api_2345 message from Family to INBOX\n");
VM_API_MOVE_MESSAGE("test_vm_api_2345", "default", 2, "Family", multi_msg_ids, "INBOX");
@@ -1028,8 +1028,8 @@ AST_TEST_DEFINE(voicemail_api_nominal_move)
test_vm_api_update_test_snapshots(test_mbox_snapshot);
test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
- VM_API_STRING_FIELD_VERIFY(test_snapshots[2]->folder_name, "INBOX");
- VM_API_STRING_FIELD_VERIFY(test_snapshots[3]->folder_name, "INBOX");
+ VM_API_STRING_FIELD_VERIFY("INBOX", test_snapshots[2]->folder_name);
+ VM_API_STRING_FIELD_VERIFY("INBOX", test_snapshots[3]->folder_name);
VM_API_TEST_CLEANUP;
@@ -1250,12 +1250,12 @@ AST_TEST_DEFINE(voicemail_api_nominal_forward)
/* Make sure we didn't delete the message */
VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
- VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 1);
+ VM_API_INT_VERIFY(1, test_mbox_snapshot->total_msg_num);
test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
/* We should now have a total of 3 messages in test_vm_api_2345 INBOX */
VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
- VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 3);
+ VM_API_INT_VERIFY(3, test_mbox_snapshot->total_msg_num);
test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
ast_test_status_update(test, "Test forwarding message 0 from test_vm_api_1234 INBOX with default context to test_vm_api_2345 INBOX\n");
@@ -1263,12 +1263,12 @@ AST_TEST_DEFINE(voicemail_api_nominal_forward)
/* Make sure we didn't delete the message */
VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
- VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 1);
+ VM_API_INT_VERIFY(1, test_mbox_snapshot->total_msg_num);
test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
/* We should now have a total of 4 messages in test_vm_api_2345 INBOX */
VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
- VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 4);
+ VM_API_INT_VERIFY(4, test_mbox_snapshot->total_msg_num);
test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
ast_test_status_update(test, "Test forwarding message 0 from test_vm_api_1234 INBOX to test_vm_api_2345 INBOX with default context\n");
@@ -1276,12 +1276,12 @@ AST_TEST_DEFINE(voicemail_api_nominal_forward)
/* Make sure we didn't delete the message */
VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
- VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 1);
+ VM_API_INT_VERIFY(1, test_mbox_snapshot->total_msg_num);
test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
/* We should now have a total of 5 messages in test_vm_api_2345 INBOX */
VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
- VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 5);
+ VM_API_INT_VERIFY(5, test_mbox_snapshot->total_msg_num);
test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
ast_test_status_update(test, "Test forwarding message 0 from test_vm_api_1234 INBOX to test_vm_api_2345 INBOX, deleting original\n");
@@ -1289,12 +1289,12 @@ AST_TEST_DEFINE(voicemail_api_nominal_forward)
/* Make sure we deleted the message */
VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
- VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 0);
+ VM_API_INT_VERIFY(0, test_mbox_snapshot->total_msg_num);
test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
/* We should now have a total of 6 messages in test_vm_api_2345 INBOX */
VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
- VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 6);
+ VM_API_INT_VERIFY(6, test_mbox_snapshot->total_msg_num);
test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
ast_test_status_update(test, "Test forwarding 2 messages from test_vm_api_2345 INBOX to test_vm_api_1234 INBOX");
@@ -1302,24 +1302,24 @@ AST_TEST_DEFINE(voicemail_api_nominal_forward)
/* Make sure we didn't delete the messages */
VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
- VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 6);
+ VM_API_INT_VERIFY(6, test_mbox_snapshot->total_msg_num);
test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
/* We should now have a total of 2 messages in test_vm_api_1234 INBOX */
VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
- VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 2);
+ VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num);
test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
ast_test_status_update(test, "Test forwarding 2 messages from test_vm_api_2345 INBOX to test_vm_api_1234 Family, deleting original\n");
VM_API_FORWARD_MESSAGE("test_vm_api_2345", "default", "INBOX", "test_vm_api_1234", "default", "Family", 2, multi_msg_ids, 1);
/* Make sure we deleted the messages */
VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "INBOX", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
- VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 4);
+ VM_API_INT_VERIFY(4, test_mbox_snapshot->total_msg_num);
test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
/* We should now have a total of 2 messages in test_vm_api_1234 Family */
VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "Family", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
- VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 2);
+ VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num);
test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
VM_API_TEST_CLEANUP;
@@ -1449,20 +1449,20 @@ AST_TEST_DEFINE(voicemail_api_nominal_msg_playback)
ast_test_status_update(test, "Playing back message from test_vm_api_2345 to callback function\n");
VM_API_PLAYBACK_MESSAGE(test_channel, "test_vm_api_2345", "default", "INBOX", message_id_2345[0], &message_playback_callback_fn);
- VM_API_INT_VERIFY(global_entered_playback_callback, 1);
+ VM_API_INT_VERIFY(1, global_entered_playback_callback);
global_entered_playback_callback = 0;
ast_test_status_update(test, "Playing back message from test_vm_api_2345 to callback function with default context\n");
VM_API_PLAYBACK_MESSAGE(test_channel, "test_vm_api_2345", NULL, "INBOX", message_id_2345[1], &message_playback_callback_fn);
- VM_API_INT_VERIFY(global_entered_playback_callback, 1);
+ VM_API_INT_VERIFY(1, global_entered_playback_callback);
global_entered_playback_callback = 0;
VM_API_SNAPSHOT_CREATE("test_vm_api_1234", "default", "Old", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
- VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 2);
+ VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num);
test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
VM_API_SNAPSHOT_CREATE("test_vm_api_2345", "default", "Old", 0, AST_VM_SNAPSHOT_SORT_BY_TIME, 0);
- VM_API_INT_VERIFY(test_mbox_snapshot->total_msg_num, 2);
+ VM_API_INT_VERIFY(2, test_mbox_snapshot->total_msg_num);
test_mbox_snapshot = ast_vm_mailbox_snapshot_destroy(test_mbox_snapshot);
ast_hangup(test_channel);
diff --git a/third-party/Makefile b/third-party/Makefile
index 0aca21e..f3016f1 100644
--- a/third-party/Makefile
+++ b/third-party/Makefile
@@ -13,7 +13,7 @@ override MAKECMDGOALS?=all
MAKECMDGOALS:=$(subst dist-clean,distclean,$(MAKECMDGOALS))
MAKECMDGOALS:=$(subst tpclean,clean,$(MAKECMDGOALS))
-all distclean dist-clean install tpclean : $(TP_SUBDIRS)
+all distclean dist-clean install uninstall tpclean : $(TP_SUBDIRS)
install uninstall: $(TP_INSTALL_SUBDIRS)
$(TP_SUBDIRS):
diff --git a/third-party/Makefile.rules b/third-party/Makefile.rules
index 4f804dd..f8b72ba 100644
--- a/third-party/Makefile.rules
+++ b/third-party/Makefile.rules
@@ -26,4 +26,8 @@ export TAR
export PATCH
export SED
export NM
+export MD5
+export CAT
export DOWNLOAD
+export DOWNLOAD_TO_STDOUT
+export DOWNLOAD_TIMEOUT
diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile
index 5a4c2d1..bfd1c27 100644
--- a/third-party/pjproject/Makefile
+++ b/third-party/pjproject/Makefile
@@ -1,5 +1,7 @@
.PHONY: _all all _install install clean distclean echo_cflags configure
+.NOTPARALLEL:
+
include ../versions.mak
export PJDIR := $(shell pwd -P)/source
@@ -20,6 +22,11 @@ ifeq ($(findstring clean,$(MAKECMDGOALS)),clean)
SPECIAL_TARGETS += clean
endif
+ifeq ($(findstring uninstall,$(MAKECMDGOALS)),uninstall)
+ SPECIAL_TARGETS += uninstall
+endif
+
+
ifneq ($(wildcard ../../makeopts),)
include ../../makeopts
endif
@@ -56,15 +63,15 @@ ifeq ($(SPECIAL_TARGETS),)
endif
ifeq ($(findstring MALLOC_DEBUG,$(MENUSELECT_CFLAGS)),MALLOC_DEBUG)
CF += -DMALLOC_DEBUG
- MALLOC_DEBUG = yes
- $(apps): export LDFLAGS += -L$(PJDIR)/pjsip-apps/lib -Wl,-whole-archive -lasterisk_malloc_debug -Wl,-no-whole-archive
- $(apps): source/pjsip-apps/lib/libasterisk_malloc_debug.a
- source/pjsip-apps/src/python/_pjsua.so: LDFLAGS += -L$(PJDIR)/pjsip-apps/lib -Wl,-whole-archive -lasterisk_malloc_debug -Wl,-no-whole-archive
- source/pjsip-apps/src/python/_pjsua.so: source/pjsip-apps/lib/libasterisk_malloc_debug.a
+ MALLOC_DEBUG_LIBS = source/pjsip-apps/lib/libasterisk_malloc_debug.a
+ MALLOC_DEBUG_LDFLAGS = -L$(PJDIR)/pjsip-apps/lib -Wl,-whole-archive -lasterisk_malloc_debug -Wl,-no-whole-archive
endif
- TARGETS += pjproject.symbols
- export CFLAGS += $(CF)
+ ifeq ($(findstring DONT_OPTIMIZE,$(MENUSELECT_CFLAGS)),)
+ CF += -O3
+ endif
+ export CFLAGS += $(CF) -g3
export LDFLAGS += $(CC_LDFLAGS)
+ TARGETS += pjproject.symbols
else
all install:
endif
@@ -75,16 +82,41 @@ include ../Makefile.rules
include Makefile.rules
ECHO_PREFIX := $(ECHO_PREFIX) echo '[pjproject] '
+SHELL_ECHO_PREFIX := echo '[pjproject] '
_all: $(TARGETS)
+define verify_tarball
+ ($(SHELL_ECHO_PREFIX) Verifying $(TARBALL) &&\
+ tarball_sum=$$($(CAT) $(TARBALL) | $(MD5) | $(SED) -n -r -e "s/^([^ ]+)\s+.*/\1/gp") ;\
+ required_sum=$$($(SED) -n -r -e "s/^([^ ]+)\s+$(TARBALL_FILE)/\1/gp" $(PJMD5SUM)) ;\
+ if [ "$$tarball_sum" != "$$required_sum" ] ; then $(SHELL_ECHO_PREFIX) Verify failed ; exit 1 ;\
+ else $(SHELL_ECHO_PREFIX) Verify successful ; exit 0 ; fi; )
+endef
+
+define download_from_pjproject
+ ($(SHELL_ECHO_PREFIX) Downloading $(TARBALL_URL) to $(TARBALL) ;\
+ $(DOWNLOAD_TO_STDOUT) $(call DOWNLOAD_TIMEOUT,5,10) $(TARBALL_URL) > $(TARBALL) &&\
+ $(SHELL_ECHO_PREFIX) Downloading $(PJPROJECT_URL)/MD5SUM to $(PJMD5SUM) &&\
+ $(DOWNLOAD_TO_STDOUT) $(call DOWNLOAD_TIMEOUT,5,10) $(PJPROJECT_URL)/MD5SUM.TXT > $(PJMD5SUM) &&\
+ $(verify_tarball))
+endef
+
+.DELETE_ON_ERROR:
+
DOWNLOAD_DIR := $(or $(EXTERNALS_CACHE_DIR),$(TMPDIR),$(wildcard /tmp),.)
+TARBALL_FILE = pjproject-$(PJPROJECT_VERSION).tar.bz2
+TARBALL = $(DOWNLOAD_DIR)/$(TARBALL_FILE)
+TARBALL_URL = $(PJPROJECT_URL)/$(TARBALL_FILE)
+PJMD5SUM = $(patsubst %.tar.bz2,%.md5,$(TARBALL))
-$(DOWNLOAD_DIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2: ../versions.mak
- $(ECHO_PREFIX) Downloading $(PJPROJECT_URL)/$(@F) to $@
- $(CMD_PREFIX) $(DOWNLOAD_TO_STDOUT) $(PJPROJECT_URL)/$(@F) > $@
+$(TARBALL): ../versions.mak
+ $(CMD_PREFIX) $(download_from_pjproject) || (rm -rf $@ ;\
+ $(SHELL_ECHO_PREFIX) Retrying download ; $(download_from_pjproject))
source/.unpacked: $(DOWNLOAD_DIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2
+ ($(verify_tarball)) || (rm -rf $@ ;\
+ $(SHELL_ECHO_PREFIX) Retrying download ; $(download_from_pjproject))
$(ECHO_PREFIX) Unpacking $<
- at rm -rf source pjproject-* >/dev/null 2>&1
$(CMD_PREFIX) $(TAR) -xjf $<
@@ -106,7 +138,6 @@ source/pjlib/include/pj/%.h: patches/%.h
.rebuild_needed: $(wildcard ../../makeopts) $(wildcard ../../menuselect.makeopts)
$(ECHO_PREFIX) Rebuilding
$(CMD_PREFIX) $(MAKE) clean $(REALLY_QUIET)
- @touch .rebuild_needed
source/build.mak: Makefile.rules source/version.mak source/user.mak $(addprefix source/pjlib/include/pj/,$(notdir $(wildcard patches/*.h))) .rebuild_needed
$(ECHO_PREFIX) Configuring with $(PJPROJECT_CONFIG_OPTS)
@@ -123,13 +154,11 @@ echo_cflags: source/build.mak
libpj%.a: source/build.mak
$(ECHO_PREFIX) Compiling lib $(@F)
$(CMD_PREFIX) $(MAKE) -C $(dir $(shell dirname $@))/build $(@F) $(REALLY_QUIET)
- - at rm -rf .rebuild_needed
# pjsua needs resample and g711 to successfully run the testsuite
-libresample%.a: .rebuild_needed source/build.mak
+libresample%.a: source/build.mak
$(ECHO_PREFIX) Compiling lib $(@F)
$(CMD_PREFIX) $(MAKE) -C $(dir $(shell dirname $@))/build/resample all $(REALLY_QUIET)
- - at rm -rf .rebuild_needed
# We need to compile pjlib, then pjlib-util, then the rest
# so we separate them out and create the dependencies
@@ -158,7 +187,8 @@ source/pjsip-apps/lib/libasterisk_malloc_debug.a: source/pjsip-apps/lib/asterisk
$(CMD_PREFIX) ar qs $@ $< >/dev/null 2>&1
$(apps): APP = $(filter pj%,$(subst -, ,$(notdir $@)))
-$(apps): pjproject.symbols $(APP_THIRD_PARTY_LIB_FILES)
+$(apps): LDFLAGS += $(MALLOC_DEBUG_LDFLAGS)
+$(apps): $(MALLOC_DEBUG_LIBS) pjproject.symbols $(APP_THIRD_PARTY_LIB_FILES)
$(ECHO_PREFIX) Compiling $(APP)
$(CMD_PREFIX) +$(MAKE) -C source/pjsip-apps/build $(filter pj%,$(subst -, ,$(notdir $@))) $(REALLY_QUIET)
@@ -166,6 +196,7 @@ source/pjsip-apps/src/python/_pjsua.o: source/pjsip-apps/src/python/_pjsua.c $(a
$(ECHO_PREFIX) Compiling python bindings
$(CMD_PREFIX) $(CC) -o $@ -c $< $(PYTHONDEV_INCLUDE) $(CFLAGS) $(PJ_CFLAGS)
+source/pjsip-apps/src/python/_pjsua.so: LDFLAGS += $(MALLOC_DEBUG_LDFLAGS)
source/pjsip-apps/src/python/_pjsua.so: source/pjsip-apps/src/python/_pjsua.o
$(ECHO_PREFIX) Linking python bindings $(@F)
$(CMD_PREFIX) gcc -shared -pthread -o $@ $< $(LDFLAGS) $(PJ_LDFLAGS) $(APP_LDLIBS) $(PYTHONDEV_LIB) $(REALLY_QUIET)
diff --git a/third-party/pjproject/configure.m4 b/third-party/pjproject/configure.m4
index 7c60c2a..8294d8e 100644
--- a/third-party/pjproject/configure.m4
+++ b/third-party/pjproject/configure.m4
@@ -28,8 +28,14 @@ AC_DEFUN([_PJPROJECT_CONFIGURE],
if test "${NM}" = ":" ; then
AC_MSG_ERROR(nm is required to build bundled pjproject)
fi
+ if test "${MD5}" = ":" ; then
+ AC_MSG_ERROR(md5sum is required to build bundled pjproject)
+ fi
+ if test "${CAT}" = ":" ; then
+ AC_MSG_ERROR(cat is required to build bundled pjproject)
+ fi
- export TAR PATCH SED NM EXTERNALS_CACHE_DIR DOWNLOAD_TO_STDOUT
+ export TAR PATCH SED NM EXTERNALS_CACHE_DIR DOWNLOAD_TO_STDOUT DOWNLOAD_TIMEOUT DOWNLOAD MD5 CAT
${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} EXTERNALS_CACHE_DIR=${EXTERNALS_CACHE_DIR} configure
if test $? -ne 0 ; then
AC_MSG_RESULT(failed)
diff --git a/third-party/pjproject/patches/0000-set_apps_initial_log_level.patch b/third-party/pjproject/patches/0000-set_apps_initial_log_level.patch
new file mode 100644
index 0000000..fc0f570
--- /dev/null
+++ b/third-party/pjproject/patches/0000-set_apps_initial_log_level.patch
@@ -0,0 +1,39 @@
+diff --git a/pjsip-apps/src/pjsua/main.c b/pjsip-apps/src/pjsua/main.c
+index 2baaf82..11831f2 100644
+--- a/pjsip-apps/src/pjsua/main.c
++++ b/pjsip-apps/src/pjsua/main.c
+@@ -126,5 +126,7 @@ int main_func(int argc, char *argv[])
+
+ int main(int argc, char *argv[])
+ {
++ pj_log_set_level(1);
++
+ return pj_run_app(&main_func, argc, argv, 0);
+ }
+diff --git a/pjsip-apps/src/pjsystest/main_console.c b/pjsip-apps/src/pjsystest/main_console.c
+index 122cdc7..dc79eab 100644
+--- a/pjsip-apps/src/pjsystest/main_console.c
++++ b/pjsip-apps/src/pjsystest/main_console.c
+@@ -133,6 +133,8 @@ void gui_sleep(unsigned sec)
+
+ int main()
+ {
++ pj_log_set_level(1);
++
+ if (systest_init() != PJ_SUCCESS)
+ return 1;
+
+diff --git a/pjsip-apps/src/python/_pjsua.c b/pjsip-apps/src/python/_pjsua.c
+index fb80e23..c9b21d8 100644
+--- a/pjsip-apps/src/python/_pjsua.c
++++ b/pjsip-apps/src/python/_pjsua.c
+@@ -4437,7 +4437,8 @@ init_pjsua(void)
+ PyObject* m = NULL;
+ #define ADD_CONSTANT(mod,name) PyModule_AddIntConstant(mod,#name,name)
+
+-
++ pj_log_set_level(1);
++
+ PyEval_InitThreads();
+
+ if (PyType_Ready(&PyTyp_pjsua_callback) < 0)
diff --git a/third-party/pjproject/patches/config_site.h b/third-party/pjproject/patches/config_site.h
index 1a48695..5e29cdb 100644
--- a/third-party/pjproject/patches/config_site.h
+++ b/third-party/pjproject/patches/config_site.h
@@ -34,7 +34,11 @@
#define PJ_SCANNER_USE_BITWISE 0
#define PJ_OS_HAS_CHECK_STACK 0
-#define PJ_LOG_MAX_LEVEL 3
+
+#ifndef PJ_LOG_MAX_LEVEL
+#define PJ_LOG_MAX_LEVEL 6
+#endif
+
#define PJ_ENABLE_EXTRA_CHECK 1
#define PJSIP_MAX_TSX_COUNT ((64*1024)-1)
#define PJSIP_MAX_DIALOG_COUNT ((64*1024)-1)
@@ -43,7 +47,16 @@
#define PJ_DEBUG 0
#define PJSIP_SAFE_MODULE 0
#define PJ_HAS_STRICMP_ALNUM 0
-#define PJ_HASH_USE_OWN_TOLOWER 1
+
+/*
+ * Do not ever enable PJ_HASH_USE_OWN_TOLOWER because the algorithm is
+ * inconsistently used when calculating the hash value and doesn't
+ * convert the same characters as pj_tolower()/tolower(). Thus you
+ * can get different hash values if the string hashed has certain
+ * characters in it. (ASCII '@', '[', '\\', ']', '^', and '_')
+ */
+#undef PJ_HASH_USE_OWN_TOLOWER
+
/*
It is imperative that PJSIP_UNESCAPE_IN_PLACE remain 0 or undefined.
Enabling it will result in SEGFAULTS when URIs containing escape sequences are encountered.
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-voip/asterisk.git
More information about the Pkg-voip-commits
mailing list