Commit Graph

5661 Commits

Author SHA1 Message Date
Sean Bright 5cd88cb64d res_pjsip: Don't allow a leading period when wildcard matching
The reference identifier (what the client provides - in this case a
hostname) must start with a domain label, not a `.`.

The current implementation will match `.seanbright.com` against
`*.seanbright.com` which is incorrect.
2026-06-04 13:04:20 +00:00
George Joseph 1982afca0d Ensure channel locks aren't held while calling ast_set_variables.
If the channel is locked when calling ast_set_variables and any of the
variables contained dialplan functions, there's a possiblilty of a deadlock.
To prevent this, either the explicit locks were removed or the call to
ast_set_variables moved out of the lock scope.  A warning to not hold
channel locks is also added to the documentation for ast_set_variables.

Resolves: #1936
2026-06-04 13:04:20 +00:00
George Joseph a4b0ee20db res_rtp_asterisk: Fix incorrect reference in ast_rtp_get_stat().
```
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_STDEVMES, \
AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->local_stdevmes, \
rtp->rtcp->stdev_rxjitter);
```

Should have been

```
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_STDEVMES, \
AST_RTP_INSTANCE_STAT_COMBINED_MES, stats->local_stdevmes, \
rtp->rtcp->stdev_rxmes);
```

Note the last macro parameter name.

Resolves: #1938
2026-06-04 13:04:20 +00:00
George Joseph ac1cee069f channel.c: Move setting RTP stats from ast_softhangup to ast_ari_channels_hangup.
The original trigger for setting the RTP stats in ast_softhangup() came from
an ARI issue where stats weren't being set in time to be reported on STASIS_END
events. The thought was that setting them in a common place like ast_softhangup()
would ensure the stats were set in possibly other scenarios.  Unfortunately,
setting the RTP stats variables in ast_softhangup() broke ABI as it required
that no channel locks be held which was not the case earlier.

Given that the original issue was ARI, we can move setting the stats to
ast_ari_channels_hangup() in resource_channels just before it calls
ast_softhangup().  This might not catch all cases of the stats not being set,
but it won't break ABI or deadlock either.

Resolves: #1928
2026-06-04 13:04:20 +00:00
George Joseph 20de9cbbe5 res_rtp_asterisk: Add option to control stun host resolution when TTL = 0
If a hostname is specified for stunaddr in rtp.conf, periodic DNS resolution
is enabled based on the TTL returned in the DNS results.  If the TTL returned
is 0, it means that the next time the IP address is needed, it must be
looked up again.  I.E.  Don't cache.  Historically (and incorrectly) however,
res_rtp_asterisk stopped the periodic resolution and never re-resolved the
hostname again.

Besides what's mentioned in the user notes...
* Additional debugging was added in various STUN/DNS functions.
* The `rtp show settings` CLI command shows more detailed STUN info.
* Some debugging was added to dns_core.c and dns_recurring.c.

UserNote: A new `stunaddr_reresolve_ttl_0` parameter has been added to rtp.conf
that allows control over what happens when a STUN server hostname lookup
returns a TTL of 0.  The values can be set as follows:
- 'no': This is the historical (and current default) behavior of not doing
any further lookups and continuing to use the last successful result until
Asterisk is restarted or rtp.conf is reloaded.
- 'yes': Use the last cached result for the current call but trigger
re-resolution in the background for the benefit of future calls.
If the result of the background lookup is a ttl > 0, periodic resolution
will be restarted otherwise the next call will use the new cached value
and will trigger a background lookup again.

UserNote: A new CLI command `rtp resolve stun hostname` has been added
that will force a resolution of the STUN hostname and (re)start periodic
resolution if the result has a TTL > 0.

Resolves: #1858
2026-06-04 13:04:20 +00:00
Jaco Kroon a77095817a pjsip_configuration: Show actual dtls_verify config.
Rather than merely showing

dtls_verify : Yes/No

in pjsip show endpoint xxx it will now be shown what exactly is being
checked, ie, one of:

dtls_verify : No
dtls_verify : Fingerprint
dtls_verify : Certificate
dtls_verify : Yes

Where Yes implies both Fingerprint and Certificate.

Signed-off-by: Jaco Kroon <jaco@uls.co.za>
2026-06-04 13:04:20 +00:00
Maximilian Fridrich ea8ecd6dea res_pjsip_messaging: Update To URI only if it is a SIP(S) URI
When a message is sent via ARI, the ARI endpoint only provides a To
field which is also used as destination field. This means that the To
field might not necessarily contain a SIP URI but might instead specify
an Asterisk endpoint (in MessageDestinationInfo format). This led to
many warnings even though the message was sent correctly.

The fix is to only call `ast_sip_update_to_uri` if the To field starts
with the sip: or sips: scheme.

Resolves: #1357
2026-06-04 13:04:19 +00:00
Mike Bradeen e90e3ea403 res_stir_shaken: fix memory free crash when Asterisk is built with malloc_debug
crypto_utils uses ast_asprintf to allocate the search string when checking the
certificate subject, but was not using ast_free to free it. This caused a crash
when Asterisk was built with malloc_debug

Resolves: #1921
2026-06-04 13:04:19 +00:00
Peter Krall f11c71ca36 res_stasis/resource_bridges: Split bridge playback control and wrapper cleanup
Modified the bridge playback teardown so the worker thread removes only the
playback control, while the after-bridge callback removes the playback
wrapper once the announcer has actually left the bridge.

This avoids a stale window where a new playback request could create a
replacement announcer before the old announcer had fully exited the holding
bridge.

Also replaced the flexible trailing bridge_id storage in the shared worker
thread data with an optional bridge_id pointer, since recording paths use the
same structure without a bridge id.

Fixes: #1861
2026-06-04 13:04:19 +00:00
Sebastian Denz c6421d8143 res_pjsip_outbound_publish.c: Add more verbose documentation for outbound_proxy usage 2026-06-04 13:04:19 +00:00
mattia 9da9d57d5e res_pjsip: Add per-endpoint RTP port range configuration
Add rtp_port_start and rtp_port_end options to PJSIP endpoint
configuration, allowing each endpoint to use a dedicated RTP port
range instead of the global rtp.conf setting.

This is useful for scenarios where different endpoints need isolated
port ranges, such as firewall rules per trunk, multi-tenant systems,
or network QoS policies tied to port ranges.

The implementation adds ast_rtp_instance_new_with_port_range() to the
RTP engine API, which sets the port range on the instance before the
engine allocates the transport. The default RTP engine
(res_rtp_asterisk) checks for per-instance overrides in
rtp_allocate_transport() and falls back to the global range when
none is set.

Both options must be set together, with values >= 1024 and
rtp_port_end > rtp_port_start. Setting both to 0 (the default)
preserves existing behavior.

Resolves: https://github.com/asterisk/asterisk-feature-requests/issues/71

UserNote: PJSIP endpoints now support rtp_port_start and
rtp_port_end options to configure a dedicated RTP port range per
endpoint, overriding the global rtp.conf setting.

UpgradeNote: An alembic database migration has been added to add
the rtp_port_start and rtp_port_end columns to the ps_endpoints
table. Run "alembic upgrade head" to apply the schema change.

DeveloperNote: New public API: ast_rtp_instance_new_with_port_range()
creates an RTP instance with a per-instance port range.
ast_rtp_instance_get_port_start() and ast_rtp_instance_get_port_end()
allow RTP engines to query the override. Third-party RTP engines can
use these getters to support per-instance port ranges.
2026-06-04 13:04:19 +00:00
George Joseph e247f1f24f ari_websockets: Fix two issues in the cleanup of outbound websockets.
1.  session_cleanup() now saves the websocket type before unlinking the
session from the session registry.  This prevents a FRACK when cleaning
up per-call websockets when MALLOC_DEBUG is used.

2.  session_shutdown_cb() and outbound_sessions_load() now call
pthread_cancel() to cancel the session handler thread to prevent the
thread from continually trying to connect to a server after the
connection config has been removed by a reload.  This required the
thread to use pthread_cleanup_push() to clean up its reference to the
session instead of RAII because RAII destructors don't get run when
pthread_cancel() is used.

Resolves: #1894
2026-06-04 13:04:19 +00:00
phoneben 7116b76c06 cdrel_custom: fix SQLite compatibility for versions < 3.20.0
cdrel_custom: fix SQLite compatibility for versions < 3.20.0

Replace sqlite3_prepare_v3 + SQLITE_PREPARE_PERSISTENT with a version-guarded fallback to sqlite3_prepare_v2 for older SQLite builds.

Resolves: #1885
2026-06-04 13:04:19 +00:00
Daniel Donoghue 63cf60c43c stasis_broadcast: Add optional ARI broadcast with first-claim-wins
Adds two optional modules:
res_stasis_broadcast.so: Infrastructure for broadcasting a single incoming
channel to multiple ARI applications with atomic first-claim-wins semantics.

app_stasis_broadcast.so: Provides the StasisBroadcast() dialplan application
which invokes the broadcast infrastructure.

Both modules are self-contained; if neither is loaded there is zero runtime
impact. Loading them does not alter existing Stasis or ARI behavior unless
explicitly used.

Key Features (only active when modules are loaded):
Fisher-Yates shuffled broadcast dispatch for fair claim races
Atomic claim operations using mutex + condition variable signaling
Configurable broadcast timeouts
Safe regex application filtering with validation to mitigate ReDoS risk
Thread-safe channel variable snapshotting (channel locked during reads)
Late-claim safety: broadcast context kept alive until after the Stasis
session ends so concurrent claimants always receive 409 Conflict rather
than 404 Not Found
Memory safety via RAII_VAR, ast_json_ref/unref, and ao2 reference counting

Components Added:
res/res_stasis_broadcast.c: Core broadcast + claim logic
apps/app_stasis_broadcast.c: StasisBroadcast() dialplan application
include/asterisk/stasis_app_broadcast.h: Public API header
res/ari/resource_events.c: Integrates POST /ari/events/claim endpoint
rest-api/api-docs/events.json: New CallBroadcast and CallClaimed events

Implementation Notes:
Broadcast contexts reside in an ao2 hash container keyed by channel id. Each
context holds atomic claim state, winner application name, timeout metadata,
and a condition variable for waiters. Broadcast contexts are kept alive until
after stasis_app_exec() returns so that concurrent claimants racing against
the timeout always receive 409 Conflict. Broadcast dispatch calls
stasis_app_send() directly for each matching application in shuffled order.
Regex filters are validated with bounded length, group depth, quantified
group count, and alternation limits to reduce pathological backtracking.
Timeout calculation uses timespec arithmetic with overflow-safe millisecond
remainder handling. Event JSON follows existing Stasis/ARI conventions;
references are managed correctly to avoid leaks or double frees.

Optional Nature / Impact:
No changes to existing APIs, events, or applications when absent.
Clean fallback: systems ignoring the modules behave identically to prior
versions.

Development was assisted by Claude (Anthropic). All generated code has been
reviewed, tested, and is understood by the author.

UserNote: New optional modules res_stasis_broadcast.so and
app_stasis_broadcast.so enable broadcasting an incoming channel to multiple
ARI applications. The first application to successfully claim (via
POST /ari/events/claim) wins channel control. StasisBroadcast() dialplan
application initiates broadcasts. CallBroadcast and CallClaimed events notify
applications. When modules are not loaded, behavior is unchanged.

DeveloperNote: New public APIs in stasis_app_broadcast.h:
stasis_app_broadcast_channel(), stasis_app_claim_channel(),
stasis_app_broadcast_winner(), and stasis_app_broadcast_wait(). New ARI event
types (CallBroadcast, CallClaimed) added to events.json. All code is isolated;
no existing ABI modified.
2026-06-04 13:04:19 +00:00
Sven Kube 776a71e6d4 res_audiosocket: Tolerate non-audio frame types
This commit implements the handling of non-voice or DTMF frames like the
chan_websocket handling added in #1588. Rather than treating unsupported
frames as fatal errors, silently ignore CNG frames and log a warning for
other unsupported types.
2026-06-04 13:04:19 +00:00
George Joseph eddef5b4d8 res_rtp_asterisk: Destroy ioqueue in rtp_ioqueue_thread_destroy.
The rtp_ioqueue_thread_destroy() function was destroying the the ioqueue
thread and releasing its pool but not destroying the ioqueue itself.  This
was causing the ioqueue's epoll file descriptor to leak.

Resolves: #1867
2026-06-04 13:04:19 +00:00
Daniel Donoghue bad1a01549 res_pjsip_maintenance: Add PJSIP endpoint maintenance mode
Introduces res_pjsip_maintenance, a loadable module that allows
operators to place individual PJSIP endpoints into maintenance mode
at runtime without unregistering or disabling them.

While an endpoint is in maintenance mode:
 * New inbound INVITE and SUBSCRIBE dialogs are rejected with
   503 Service Unavailable and a Retry-After: 300 header.
 * In-progress dialogs (re-INVITE, UPDATE, BYE, etc.) are
   unaffected and complete normally.
 * Outbound originations via Dial() or ARI originate are refused
   before any SIP session is created.

State is held in-memory only and is cleared on module unload
or Asterisk restart.

This module was developed with AI assistance (Claude).  All code
has been reviewed and tested by the author, who takes full
responsibility for the submission.

CLI interface:
  pjsip set maintenance <on|off> <endpoint|all>
  pjsip show maintenance [endpoint]

AMI interface:
  Action: PJSIPSetMaintenance
  Endpoint: <name>|all
  State: on|off

  Action: PJSIPShowMaintenance
  Endpoint: <name>  (optional; omit to list all)

  Emits PJSIPMaintenanceStatus events per result, followed by
  PJSIPMaintenanceStatusComplete. State changes also emit an
  unsolicited PJSIPMaintenanceStatus event.

To support outbound blocking, a new session_create callback is
added to ast_sip_session_supplement. Supplements that set this
callback are invoked at the start of ast_sip_session_create_outgoing()
in res_pjsip_session, before any dialog or invite session resources
are allocated. res_pjsip_maintenance registers itself as a session
supplement and uses this callback to gate outbound session creation
on a per-endpoint basis.

MODULEINFO:
  <depend>pjproject</depend>
  <depend>res_pjsip</depend>
  <depend>res_pjsip_session</depend>

UserNote: New module res_pjsip_maintenance adds runtime maintenance
mode for PJSIP endpoints. Use "pjsip set maintenance <on|off>
<endpoint|all>" to enable or disable, and "pjsip show maintenance"
to list affected endpoints. AMI actions PJSIPSetMaintenance and
PJSIPShowMaintenance provide programmatic access. No configuration
file changes required.

DeveloperNote: ast_sip_session_supplement gains a new optional
callback - int (*session_create)(struct ast_sip_endpoint *endpoint,
const char *destination). It is called from the global supplement
list (not per-session) at the start of ast_sip_session_create_outgoing()
via ast_sip_session_check_supplement_create(). Returning non-zero
blocks the outgoing session. Modules that need to gate outbound
SIP session creation should register a supplement with this callback
set rather than hooking into chan_pjsip directly.
2026-06-04 13:04:19 +00:00
Mike Bradeen ebb95c0cbe res_pjsip_outbound_registration: only update the Expires header if the value has changed
The PJSIP outbound registration API has undocumented behavior when reconfiguring
the outbound registration if the expires value being set is the same as what was
previously set.

In this case PJSIP will remove the Expires header entirely from subsequent
outbound REGISTER requests. To eliminate this as an issue we now check the current
expires value against the configured expires value and only apply it if it differs.

This ensures that outbound REGISTER requests always contain an Expires header.

Resolves: #1859
2026-06-04 13:04:18 +00:00
George Joseph cb703e409c res_pjsip_config_wizard: Trigger reloads from a pjsip servant thread
When res_pjsip is reloaded directly, it does the sorcery reload in a pjsip
servant thread as it's supposed to.  res_pjsip_config_wizard however
was not which was leading to occasional deadlocks.  It now does the reload
in a servant thread just like res_pjsip.

Resolves: #1855
2026-06-04 13:04:18 +00:00
nappsoft bfd14294c6 res_cdrel_custom: do not free config when no new config was loaded
When the res_cdrel_custom modules is reloaded and the config has not been changed asterisk should not free the old config. Otherwise the connection to the database will be closed and no new connection will be opened.

Resolves: #1852
2026-04-02 10:01:51 -06:00
George Joseph b3f6728a28 res_cdrel_custom: Resolve several formatting issues.
Several issues are resolved:

* Internally, floats were used for timestamp values but this could result
in wrapping so they've been changed to doubles.

* Historically, the default CEL eventtime format is `<seconds>.<microseconds>`
with `<microseconds>` always being 6 digits.  This should have continued to be
the case but res_cdrel_custom wasn't checking the `dateformat` setting in
cel.conf and was defaulting to `%F %T`.  res_cdrel_custom now gets the default
date format from cel.conf, which will be whatever the `dateformat` parameter
is set to or `<seconds>.<microseconds>` if not set.

* The timeval field formatter for both CDR and CEL wasn't handling custom
strftime format strings correctly.  This is now fixed so you should be able
to specifiy custom strftime format strings for the CEL `eventtime` and CDR
`start`, `answer` and `end` fields.  For example: `eventtime(%FT%T%z)`.

Resolves: #1844
Resolves: #1845
2026-04-01 13:26:01 -06:00
Sven Kube a7524793bb res_audiosocket: Fix header read loop to use correct buffer offset
The PR #1522 introduced the header read loop for audiosocket packets
which does not handle partial header reads correctly. This commit
adds the missing buffer offsets.
2026-03-26 19:23:13 +00:00
George Joseph 8826840990 chan_pjsip: Set correct cause codes for non-2XX responses.
Redirects initiated by 302 response codes weren't handled correctly
when setting the hangup cause code and tech cause code on the responding
channel.  They're now set to 23 (REDIRECTED_TO_NEW_DESTINATION) and
302 (Moved permanently).  Other non-2XX response codes also had issues.

A new API ast_channel_dialed_causes_iterator() was added to retrieve
the hangup cause codes for a channel.

chan_pjsip_session_end() in chan_pjsip has been refactored to set the
correct cause codes on a channel based on the cause codes added by
chan_pjsip_incoming_response_update_cause().  Copious amounts of
debugging and comments were also added.

Resolves: #1819
2026-03-26 19:23:13 +00:00
Michal Hajek 96e8a8a002 res_pjsip_config_wizard: Force reload on Named ACL change events
Currently, endpoints created via the PJSIP Config Wizard do not update
their ACL rules if the underlying Named ACL (in acl.conf) changes.
This occurs because the wizard relies on file timestamp and content
caching of pjsip_wizard.conf, which remains unchanged during an external
ACL update. As a result, endpoints retain stale ACL rules even after
a reload.

This patch updates res_pjsip_config_wizard to subscribe to the
ast_named_acl_change_type Stasis event. A local generation counter is
incremented whenever an ACL change event is received.

During a reload, the wizard compares the current local generation against
the generation stored in the wizard object. If a change is detected:
1. The file cache optimization (CONFIG_FLAG_FILEUNCHANGED) is bypassed.
2. Wizard objects utilizing 'acl' or 'contact_acl' are forced to update,
   ensuring they pick up the new IP rules.

Signed-off-by: Michal Hajek michal.hajek@daktela.com

Fixes: #1641
2026-03-26 19:23:13 +00:00
George Joseph 7226577c64 res_pjsip: Remove temp transport state when a transport fails to load.
If a pjsip transport (A) fails to load, its temporary state gets left behind
causing the next transport to load (B) to pick up some of its parameters,
including its name. This can cause B to have the correct name (B) in its
transport object but the wrong name (A) in its internal state object. When a
transport state is searched for later on, transport state B is returned but a
retrieval of the actual transport object will fail because B's transport
state id is actually "A" and transport "A" doesn't exist because it failed
to load.

remove_temporary_state() is now being called in all error paths in
config_transport.c functions that call find_or_create_temporary_state().

A bit of extra debugging was also added to res_pjsip_nat.c.

Resolves: #1814
2026-03-26 19:23:13 +00:00
Alexis Hadjisotiriou 0f90e107da res_pjsip_messaging: Remove Contact header from out-of-dialog MESSAGE as per RFC3428
According to RFC 3428 (Section 5), a Contact header is not required in a
MESSAGE request unless the sender wants to establish a session. This
patch ensures that the Contact header is removed from out-of-dialog
MESSAGE requests within res_pjsip_messaging.c.

Fixes: #1356
2026-03-26 19:23:13 +00:00
Mike Bradeen a76678e085 acl: Add ACL support to http and ari
Add uri prefix based acl support to the built in http server.
This allows an acl to be added per uri prefix (ie '/metrics'
or '/ws') to restrict access.

Add user based acl support for ARI. This adds new acl options
to the user section of ari.conf to restrict access on a per
user basis.

resolves: #1799

UserNote: A new section, type=restriction has been added to http.conf
to allow an uri prefix based acl to be configured. See
http.conf.sample for examples and more information.
The user section of ari.conf can now contain an acl configuration
to restrict users access. See ari.conf.sample for examples and more
information
2026-03-26 19:23:13 +00:00
Robert Wilson 4066fa3b30 res_rtp_asterisk.c: Fix DTLS packet drop when TURN loopback re-injection occurs before ICE candidate check
When TURN is configured in rtp.conf, pjproject re-injects TURN packets
via 127.0.0.1 (the loopback address). The DTLS packet handler checks the
source address against the ICE active candidate list before the loopback
address substitution runs, causing the packet to be silently dropped as
the source 127.0.0.1 is not in the candidate list.

Fix by performing the loopback address substitution before the ICE
candidate source check in the DTLS path, mirroring the logic already
present in the non-DTLS RTP path.

Fixes: #1795

UserNote: WebRTC calls using TURN configured in rtp.conf (turnaddr,
turnusername, turnpassword) will now correctly complete DTLS/SRTP
negotiation. Previously all DTLS packets were silently dropped due to
the loopback re-injection address not being in the ICE active candidate
list.
2026-03-26 19:23:13 +00:00
Sean Bright b9df90b518 resource_channels.c: Fix validation response for externalMedia with AudioSockets
The AudioSocket encapsulation for externalMedia requires a UUID to be
provided in the `data` parameter of the ARI call. If not provided, we
should return a 400 Bad Request instead of a 500 Internal Server
Error.

Pointed out by AVT in the community forum[1].

1: https://community.asterisk.org/t/externalmedia-audiosocket-on-asterisk-22/112149
2026-03-26 19:23:13 +00:00
George Joseph 7630f02494 CDR/CEL Custom Performance Improvements
There is a LOT of work in this commit but the TL;DR is that it takes
CEL processing from using 38% of the CPU instructions used by a call,
which is more than that used by the call processing itself, down to less
than 10% of the instructions.

So here's the deal...  cdr_custom, cdr_sqlite3_custom, cel_custom
and cel_sqlite3_custom all shared one ugly trait...they all used
ast_str_substitute_variables() or pbx_substitute_variables_helper()
to resolve the dialplan functions used in their config files.  Not only
are they both extraordinarily expensive, they both require a dummy
channel to be allocated and destroyed for each record written.  For CDRs,
that's not too bad because we only write one CDR per call.  For CELs however,
it's a disaster.

As far as source code goes, the modules basically all did the same thing.
Unfortunately, they did it badly.  The config files simply contained long
opaque strings which were intepreted by ast_str_substitute_variables() or
pbx_substitute_variables_helper(), the very functions that ate all the
instructions.  This meant introducing a new "advanced" config format much
like the advanced manager event filtering added to manager.conf in 2024.
Fortunately however, if the legacy config was recognizable, we were able to
parse it as an advanced config and gain the benefit.  If not, then it
goes the legacy, and very expensive, route.

Given the commonality among the modules, instead of making the same
improvements to 4 modules then trying to maintain them over time, a single
module "res_cdrel_custom" was created that contains all of the common code.
A few bonuses became possible in the process...
* The cdr_custom and cel_custom modules now support JSON formatted output.
* The cdr_sqlite_custom and cel_sqlite3_custom modules no longer have
  to share an Sqlite3 database.

Summary of changes:

A new module "res/res_cdrel_custom.c" has been created and the existing
cdr_custom, cdr_sqlite3_custom, cel_custom and cel_sqlite3_custom modules
are now just stubs that call the code in res_cdrel_custom.

res_cdrel_custom contains:
* A common configuration facility.
* Getters for both CDR and CEL fields that share the same abstraction.
* Formatters for all data types found in the ast_cdr and ast_event
  structures that share the same abstraction.
* Common writers for the text file and database backends that, you guessed it,
  share the same abstraction.

The result is that while there is certainly a net increase in the number of
lines in the code base, most of it is in the configuration handling at
load-time.  The run-time instruction path length is now significanty shorter.

```
Scenario                   Instructions     Latency
=====================================================
CEL pre changes                  38.49%     37.51%
CEL Advanced                      9.68%      6.06%
CEL Legacy (auto-conv to adv)     9.95%      6.13%

CEL Sqlite3 pre changes          39.41%     39.90%
CEL Sqlite3 Advanced             25.68%     24.24%
CEL Sqlite3 Legacy (auto conv)   25.88%     24.53%

CDR pre changes                   4.79%      2.95%
CDR Advanced                      0.79%      0.47%
CDR Legacy (auto conv to adv)     0.86%      0.51%

CDR Sqlite3 pre changes           4.47%      2.89%
CEL Sqlite3 Advanced              2.16%      1.29%
CEL Sqlite3 Legacy (auto conv)    2.19%      1.30%
```

Notes:
* We only write one CDR per call but every little bit helps.
* Sqlite3 still takes a fair amount of resources but the new config
  makes a decent improvement.
* Legacy configs that we can't auto convert will still take the
  "pre changes" path.

If you're interested in more implementation details, see the comments
at the top of the res_cdrel_custom.c file.

One minor fix to CEL is also included...Although TenantID was added to the
ast_event structure, it was always rendered as an empty string.  It's now
properly rendered.

UserNote: Significant performance improvements have been made to the
cdr_custom, cdr_sqlite3_custom, cel_custom and cel_sqlite3_custom modules.
See the new sample config files for those modules to see how to benefit
from them.
2026-03-26 19:23:13 +00:00
Ben Ford 00d4d47be0 chan_websocket: Add media direction.
Currently, WebSockets both accept and send media without the option to
disable one or the other. This commit adds the ability to set the media
direction for a WebSocket, making it unidirectional or bidirectional
(the default). Direction is done from the point of view of the
application, NOT Asterisk. The allowed values are 'both', 'in', and
'out'. If media direction is 'both' (the default), Asterisk accepts and
sends media to the application. If it is 'in', Asterisk will drop any
media received from the application. If it is 'out', Asterisk will not
write any media frames to the application.

UserNote: WebSocket now supports media direction, allowing for
unidirectional media. This is done from the perspective of the
application and can be set via channel origination, external media, or
commands sent from the application. Check out
https://docs.asterisk.org/Configuration/Channel-Drivers/WebSocket/ for
more.
2026-03-26 19:23:13 +00:00
Prashant Srivastav 19e3bb10a5 fix: Add macOS (Darwin) compatibility for building Asterisk
- Makefile: Skip /usr/lib/bundle1.o on modern macOS (doesn't exist)
- Makefile.rules: Skip -fno-partial-inlining for clang (gcc-only flag)
- include/asterisk/utils.h: Use asterisk/endian.h instead of <endian.h>
- main/Makefile: Add Darwin-specific pjproject linking with -force_load
- main/strcompat.c: Include poll-compat.h, use ast_poll()
- main/xml.c: Add ASTMM_LIBC ASTMM_IGNORE for libxml2 compatibility
- res/res_pjsip/config_transport.c: Define TCP keepalive constants for macOS

Tested on macOS Darwin 25.2.0 (Apple Silicon ARM64)
2026-03-26 19:23:13 +00:00
Mike Bradeen 69008cc2b0 res_rtp_asterisk: use correct sample rate lookup to account for g722
Swap out ast_rtp_get_rate for ast_format_get_sample_rate when looking
at the paired audio codec rate to account for g722 oddness.

Resolves: #1657
2026-03-26 19:23:13 +00:00
Sean Bright da2afacfea res_pjsip_outbound_registration.c: Prevent crash if load_module() fails
`ast_cli_unregister_multiple()` expects internal data members to be heap
allocated which happens during a successful call to
`ast_cli_register_multiple()`. CLI handlers defined traditionally - those whose
handler responds to the CLI_INIT message - take care of this automatically. But
when we statically provide a `command` or `usage` member, we _must_ initialize
them with `ast_cli_register_multiple()` before attempting to destroy them.

Resolves: #1651
2026-03-26 19:23:12 +00:00
Alexis Hadjisotiriou 9b2d080038 pjsip_configuration: Ensure s= and o= lines in SDP are never empty
According to RFC 8866 (Section 5.2), the Session Name (s=) field and
the username part of origin (o=) are both mandatory and cannot be
empty. If a session has no name, or no username part of origin, the
RFC recommends using a single dash (-) as a placeholder.

This fix ensures that if the session name or the username part of
origin length is zero , it defaults to -.

Fixes: #1524
2026-03-26 19:23:12 +00:00
Arcadiy Ivanov 4c1e0e2c75 res_pjsip_session: Make sure NAT hook runs when packet is retransmitted for whatever reason.
This hook may not be necessary when we do a retransmit, but when there are two
INVITEs, one *initial* and one with auth digest, the second INVITE contains wrong (unmodified) media address
due to the commented line below.
The NAT hook needs to run due to filters potentially reverting previously modified packets.

Fixes: #449
2026-03-26 19:23:12 +00:00
Naveen Albert 18e3001097 build: Fix unused-but-set-variable warnings with gcc 16.
Fix or remove a few variables that were being set but not actually
used anywhere, causing warnings with gcc 16.

Resolves: #1783
2026-03-26 19:23:12 +00:00
Joshua C. Colp 5e64c9438b build: Fix GCC discarded-qualifiers const errors.
GCC 15.2.1 pays attention to the discarding of the const
qualifier when strchr, strrchr, memchr, or memrchr are now
used. This change fixes numerous errors with this throughout
the tree. The fixes can be broken down into the following:

1. The return value should be considered const.
2. The value passed to strchr or strrchr can be cast as it is
   expected and allowed to be modified.
3. The pointer passed to strchr or strrchr is not meant to be
   modified and so the contents must be duplicated.
4. It was declared const and never should have been.
2026-03-26 19:23:12 +00:00
Mike Bradeen 7e0c3eb630 res_pjsip_header_funcs: Add new PJSIP_INHERITABLE_HEADER dialplan function
Adds a new PJSIP_INHERITABLE_HEADER dialplan function to add
inheritable headers from the inbound channel to an outbound
bridged channel.  This works similarly to the existing
PJSIP_HEADER function, but will set the header on the bridged
outbound channel's INVITE upon Dial.

Inheritable headers can be updated or removed from the inbound
channel as well as from a pre-dial handler

Resolves: #1670

UserNote: A new PJSIP_HEADER option has been added that allows
inheriting pjsip headers from the inbound to the outbound bridged
channel.
Example- same => n,Set(PJSIP_INHERITABLE_HEADER(add,X-custom-1)=alpha)
will add X-custom-1: alpha to the outbound pjsip channel INVITE
upon Dial.
2026-03-26 19:23:12 +00:00
hishamway 9aa763f260 res_pjsip_session.c: Prevent INVITE failover when session is cancelled
When an outbound INVITE transaction times out (408) or receives a 503 error,
check_request_status() attempts to failover to the next available address by
restarting the INVITE session. However, the function did not check if the
inv_session was already cancelled before attempting the failover.

This caused unexpected behavior when a caller hung up during a ring group
scenario: after CANCEL was sent but the remote endpoint failed to respond
with 487 (e.g., due to network disconnection), the transaction timeout
would trigger a NEW outbound INVITE to the next address, even though the
session was already terminated.

This violates RFC 3261 Section 9.1 which states that if no final response
is received after CANCEL within 64*T1 seconds, the client should consider
the transaction cancelled and destroy it, not retry to another address.

The fix adds a check for both PJSIP_INV_STATE_DISCONNECTED and inv->cancelling
at the beginning of check_request_status(). This ensures that:
- Failover is blocked when the user explicitly cancelled the call (CANCEL sent)
- Failover is still allowed for legitimate timeout/503 scenarios where no
  CANCEL was initiated (e.g., SRV failover when first server is unreachable)

Resolves: #1716
2026-03-26 19:23:12 +00:00
Alexei Gradinari 28543516c7 res_pjsip_pubsub: Fix ao2 reference leak of subscription tree in ast_sip_subscription
allocate_subscription() increments the ao2 reference count of the subscription tree,
but the reference was not consistently released during subscription destruction,
resulting in leaked sip_subscription_tree objects.

This patch makes destroy_subscription() responsible for releasing sub->tree,
removes ad-hoc cleanup in error paths,
and guards tree cleanup to ensure refcount symmetry and correct ownership.

Fixes: #1703
2026-03-26 19:23:12 +00:00
Mike Bradeen 0ab029d9cf res_sorcery_memory_cache: Reduce cache lock time for sorcery memory cache populate command
Reduce cache lock time for AMI and CLI sorcery memory cache populate
commands by adding a new populate_lock to the sorcery_memory_cache
struct which is locked separately from the existing cache lock so that
the cache lock can be maintained for a reduced time, locking only when
the cache objects are removed and re-populated.

Resolves: #1700

UserNote: The AMI command sorcery memory cache populate will now
return an error if there is an internal error performing the populate.
The CLI command will display an error in this case as well.
2026-01-15 16:47:32 +00:00
George Joseph e6f5a091bf chan_websocket: Use the channel's ability to poll fds for the websocket read.
We now add the websocket's file descriptor to the channel's fd array and let
it poll for data availability instead if having a dedicated thread that
does the polling. This eliminates the thread and allows removal of most
explicit locking since the core channel code will lock the channel to prevent
simultaneous calls to webchan_read, webchan_hangup, etc.

While we were here, the hangup code was refactored to use ast_hangup_with_cause
instead of directly queueing an AST_CONTROL_HANGUP frame.  This allows us
to set hangup causes and generate snapshots.

For a bit of extra debugging, a table of websocket close codes was added
to http_websocket.h with an accompanying "to string" function added to
res_http_websocket.c

Resolves: #1683
2026-01-15 16:47:31 +00:00
Peter Krall 3a68e78696 res/ari/resource_bridges.c: Normalize channel_format ref handling for bridge media
Always take an explicit reference on the format used for bridge playback
and recording channels, regardless of where it was sourced, and release
it after prepare_bridge_media_channel. This aligns the code paths and
avoids mixing borrowed and owned references while preserving behavior.

Fixes: #1648
2026-01-15 16:47:31 +00:00
George Joseph e6d4e62a78 res_geolocation: Fix multiple issues with XML generation.
* 3d positions were being rendered without an enclosing `<gml:pos>`
  element resulting in invalid XML.
* There was no way to set the `id` attribute on the enclosing `tuple`, `device`
  and `person` elements.
* There was no way to set the value of the `deviceID` element.
* Parsing of degree and radian UOMs was broken resulting in them appearing
  outside an XML element.
* The UOM schemas for degrees and radians were reversed.
* The Ellipsoid shape was missing and the Ellipse shape was defined multiple
  times.
* The `crs` location_info parameter, although documented, didn't work.
* The `pos3d` location_info parameter appears in some documentation but
  wasn't being parsed correctly.
* The retransmission-allowed and retention-expiry sub-elements of usage-rules
  were using the `gp` namespace instead of the `gbp` namespace.

In addition to fixing the above, several other code refactorings were
performed and the unit test enhanced to include a round trip
XML -> eprofile -> XML validation.

Resolves: #1667

UserNote: Geolocation: Two new optional profile parameters have been added.
* `pidf_element_id` which sets the value of the `id` attribute on the top-level
  PIDF-LO `device`, `person` or `tuple` elements.
* `device_id` which sets the content of the `<deviceID>` element.
Both parameters can include channel variables.

UpgradeNote: Geolocation: In order to correct bugs in both code and
documentation, the following changes to the parameters for GML geolocation
locations are now in effect:
* The documented but unimplemented `crs` (coordinate reference system) element
  has been added to the location_info parameter that indicates whether the `2d`
  or `3d` reference system is to be used. If the crs isn't valid for the shape
  specified, an error will be generated. The default depends on the shape
  specified.
* The Circle, Ellipse and ArcBand shapes MUST use a `2d` crs.  If crs isn't
  specified, it will default to `2d` for these shapes.
  The Sphere, Ellipsoid and Prism shapes MUST use a `3d` crs. If crs isn't
  specified, it will default to `3d` for these shapes.
  The Point and Polygon shapes may use either crs.  The default crs is `2d`
  however so if `3d` positions are used, the crs must be explicitly set to `3d`.
* The `geoloc show gml_shape_defs` CLI command has been updated to show which
  coordinate reference systems are valid for each shape.
* The `pos3d` element has been removed in favor of allowing the `pos` element
  to include altitude if the crs is `3d`.  The number of values in the `pos`
  element MUST be 2 if the crs is `2d` and 3 if the crs is `3d`.  An error
  will be generated for any other combination.
* The angle unit-of-measure for shapes that use angles should now be included
  in the respective parameter.  The default is `degrees`. There were some
  inconsistent references to `orientation_uom` in some documentation but that
  parameter never worked and is now removed.  See examples below.
Examples...
```
  location_info = shape="Sphere", pos="39.0 -105.0 1620", radius="20"
  location_info = shape="Point", crs="3d", pos="39.0 -105.0 1620"
  location_info = shape="Point", pos="39.0 -105.0"
  location_info = shape=Ellipsoid, pos="39.0 -105.0 1620", semiMajorAxis="20"
                semiMinorAxis="10", verticalAxis="0", orientation="25 degrees"
  pidf_element_id = ${CHANNEL(name)}-${EXTEN}
  device_id = mac:001122334455
  Set(GEOLOC_PROFILE(pidf_element_id)=${CHANNEL(name)}/${EXTEN})
```
2026-01-15 16:47:31 +00:00
George Joseph 7285079c6a stasis/control.c: Add destructor to timeout_datastore.
The timeout_datastore was missing a destructor resulting in a leak
of 16 bytes for every outgoing ARI call.

Resolves: #1681
2026-01-15 16:47:31 +00:00
Alexei Gradinari 257fd8c180 res_pjsip_mwi: Fix off-nominal endpoint ao2 ref leak in mwi_get_notify_data
Delay acquisition of the ast_sip_endpoint reference in mwi_get_notify_data()
to avoid an ao2 ref leak on early-return error paths.

Move ast_sip_subscription_get_endpoint() to just before first use so all
acquired references are properly cleaned up.

Fixes: #1675
2026-01-15 16:47:31 +00:00
Maximilian Fridrich c3b1313acf res_pjsip_messaging: Add support for following 3xx redirects
This commit integrates the redirect module into res_pjsip_messaging
to enable following 3xx redirect responses for outgoing SIP MESSAGEs.

When follow_redirect_methods contains 'message' on an endpoint, Asterisk
will now follow 3xx redirect responses for MESSAGEs, similar to how
it behaves for INVITE responses.

Resolves: #1576

UserNote: A new pjsip endpoint option follow_redirect_methods was added.
This option is a comma-delimited, case-insensitive list of SIP methods
for which SIP 3XX redirect responses are followed. An alembic upgrade
script has been added for adding this new option to the Asterisk
database.
2026-01-15 16:47:31 +00:00
Maximilian Fridrich a105421d59 res_pjsip: Introduce redirect module for handling 3xx responses
This commit introduces a new redirect handling module that provides
infrastructure for following SIP 3xx redirect responses. The redirect
functionality respects the endpoint's redirect_method setting and only
follows redirects when set to 'uri_pjsip'. This infrastructure can be
used by any PJSIP module that needs to handle 3xx redirect responses.
2026-01-15 16:47:31 +00:00
Sven Kube 593f09dc6e res_pjsip_refer: don't defer session termination for ari transfer
Allow session termination during an in progress ari handled transfer.
2026-01-15 16:47:31 +00:00