Commit Graph

5652 Commits

Author SHA1 Message Date
Sebastian Denz
9bad7ee2fc res_pjsip_outbound_publish.c: Add more verbose documentation for outbound_proxy usage 2026-05-07 15:40:23 +00:00
mattia
aee2b7da29 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-04-28 17:45:52 +00:00
George Joseph
99c0abaf1a 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-04-28 13:44:11 +00:00
phoneben
3f943350a3 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-04-22 19:03:19 +00:00
Daniel Donoghue
61ba588d58 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-04-22 18:05:00 +00:00
Sven Kube
3da083d71a 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-04-22 17:58:15 +00:00
George Joseph
54904b1ff5 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-04-16 18:25:45 +00:00
Daniel Donoghue
f845b71c75 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-04-16 18:25:34 +00:00
Mike Bradeen
ced54bb04a 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-04-13 14:15:03 +00:00
George Joseph
63e3810c0b 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-04-08 17:03:03 +00:00
nappsoft
6a877ec87a 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 15:56:21 +00:00
George Joseph
242276bbaa 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 19:16:15 +00:00
Sven Kube
3a9c59b492 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-18 14:38:11 +00:00
George Joseph
34b015599c 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-17 16:15:36 +00:00
Michal Hajek
f410523c43 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-17 14:47:34 +00:00
George Joseph
d9920a272a 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-09 12:25:18 +00:00
Alexis Hadjisotiriou
691bb4cf30 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-09 12:22:15 +00:00
Mike Bradeen
8472e75ac1 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-05 12:52:37 +00:00
Robert Wilson
5ed193aa14 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-04 14:23:23 +00:00
Sean Bright
9aca269f7b 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-02 18:26:48 +00:00
George Joseph
9c23df049d 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-02 16:43:24 +00:00
Ben Ford
2a85ae7314 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-02-26 15:55:51 +00:00
Prashant Srivastav
d4e366145f 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-02-26 15:51:02 +00:00
Mike Bradeen
f7d1a278b7 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-02-26 14:59:14 +00:00
Sean Bright
9a63e2c84c 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-02-26 14:40:16 +00:00
Alexis Hadjisotiriou
3ac94f21f4 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-02-26 14:07:53 +00:00
Arcadiy Ivanov
e0b95e9644 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-02-26 14:06:07 +00:00
Naveen Albert
f87f4d4e47 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-02-25 13:25:14 +00:00
Joshua C. Colp
681a77f638 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-02-18 13:43:30 +00:00
Mike Bradeen
24456a3c49 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-01-27 16:49:51 +00:00
hishamway
1fd4e3af28 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-01-22 18:11:38 +00:00
Alexei Gradinari
6cc8b96452 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-01-22 17:51:17 +00:00
Mike Bradeen
3225cd54d4 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-08 13:26:17 +00:00
George Joseph
a1c3677d4a 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-05 14:49:20 +00:00
Peter Krall
13d01a86e3 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-05 12:45:34 +00:00
George Joseph
445130eeab 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-05 12:45:04 +00:00
George Joseph
44f61c92e2 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
2025-12-31 18:51:38 +00:00
Alexei Gradinari
6c12996020 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
2025-12-30 15:28:47 +00:00
Maximilian Fridrich
ebde5ae5cb 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.
2025-12-30 15:09:29 +00:00
Maximilian Fridrich
569b3ed995 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.
2025-12-30 15:09:28 +00:00
Sven Kube
c955692e9c res_pjsip_refer: don't defer session termination for ari transfer
Allow session termination during an in progress ari handled transfer.
2025-12-29 20:13:39 +00:00
Sean Bright
aff11dca5f res_odbc: Use SQL_SUCCEEDED() macro where applicable.
This is just a cleanup of some repetitive code.
2025-12-29 18:33:03 +00:00
Justin T. Gibbs
0e8a22caf0 rtp/rtcp: Configure dual-stack behavior via IPV6_V6ONLY
Dual-stack behavior (simultaneous listening for IPV4 and IPV6
connections on a single socket) is required by Asterisk's ICE
implementation.  On systems with the IPV6_V6ONLY sockopt, set
the option to 0 (dual-stack enabled) when binding to the IPV6
any address. This ensures correct behavior regardless of the
system's default dual-stack configuration.
2025-12-29 18:04:52 +00:00
Joshua C. Colp
6c047d3da5 pjsip: Move from threadpool to taskpool
This change moves the PJSIP module from the threadpool API
to the taskpool API. PJSIP-specific implementations for
task usage have been removed and replaced with calls to
the optimized taskpool implementations instead. The need
for a pool of serializers has also been removed as
taskpool inherently provides this. The default settings
have also been changed to be more realistic for common
usage.

UpgradeNote: The threadpool_* options in pjsip.conf have now
been deprecated though they continue to be read and used.
They have been replaced with taskpool options that give greater
control over the underlying taskpool used for PJSIP. An alembic
upgrade script has been added to add these options to realtime
as well.
2025-12-16 17:03:43 +00:00
phoneben
01deece587 Disable device state caching for ephemeral channels
chan_audiosocket/chan_rtp/res_stasis_snoop: Disable device state caching for ephemeral channels

Resolves: #1638
2025-12-16 14:56:03 +00:00
phoneben
017e3409ab Fix false null-deref warning in channel_state
Resolve analyzer warning in channel_state by checking AST_FLAG_DEAD on snapshot, which is guaranteed non-NULL.

Resolves: #1430
2025-12-10 12:58:05 +00:00
Sean Bright
0a83b87b4c Revert "func_hangupcause.c: Add access to Reason headers via HANGUPCAUSE()"
This reverts commit 5177662990.

For rationale, see #1621 and #1606
2025-12-09 17:04:07 +00:00
Mike Bradeen
e016ba689a taskprocessors: Improve logging and add new cli options
This change makes some small changes to improve log readability in
addition to the following changes:

Modified 'core show taskprocessors' to now show Low time and High time
for task execution.

New command 'core show taskprocessor name <taskprocessor-name>' to dump
taskprocessor info and current queue.

Addionally, a new test was added to demonstrate the 'show taskprocessor
name' functionality:
test execute category /main/taskprocessor/ name taskprocessor_cli_show

Setting 'core set debug 3 taskprocessor.c' will now log pushed tasks.
(Warning this is will cause extremely high levels of logging at even
low traffic levels.)

Resolves: #1566

UserNote: New CLI command has been added -
core show taskprocessor name <taskprocessor-name>
2025-12-04 16:13:02 +00:00
George Joseph
01f26c412e chan_websocket: Add capability for JSON control messages and events.
With recent enhancements to chan_websocket, the original plain-text
implementation of control messages and events is now too limiting.  We
probably should have used JSON initially but better late than never.  Going
forward, enhancements that require control message or event changes will
only be done to the JSON variants and the plain-text variants are now
deprecated but not yet removed.

* Added the chan_websocket.conf config file that allows setting which control
message format to use globally: "json" or "plain-text".  "plain-text" is the
default for now to preserve existing behavior.

* Added a dialstring option `f(json|plain-text)` to allow the format to be
overridden on a call-by-call basis.  Again, 'plain-text' is the default for
now to preserve existing behavior.

The JSON for commands sent by the app to Asterisk must be...
`{ "command": "<command>" ... }` where `<command>` is one of `ANSWER`, `HANGUP`,
`START_MEDIA_BUFFERING`, etc.  The `STOP_MEDIA_BUFFERING` command takes an
additional, optional parameter to be returned in the corresponding
`MEDIA_BUFFERING_COMPLETED` event:
`{ "command": "STOP_MEDIA_BUFFERING", "correlation_id": "<correlation id>" }`.

The JSON for events sent from Asterisk to the app will be...
`{ "event": "<event>", "channel_id": "<channel_id>" ... }`.
The `MEDIA_START` event will now look like...

```
{
  "event": "MEDIA_START",
  "connection_id": "media_connection1",
  "channel": "WebSocket/media_connection1/0x5140001a0040",
  "channel_id": "1761245643.1",
  "format": "ulaw",
  "optimal_frame_size": 160,
  "ptime": 20,
  "channel_variables": {
    "DIALEDPEERNUMBER": "media_connection1/c(ulaw)",
    "MEDIA_WEBSOCKET_CONNECTION_ID": "media_connection1",
    "MEDIA_WEBSOCKET_OPTIMAL_FRAME_SIZE": "160"
  }
}
```

Note the addition of the channel variables which can't be supported
with the plain-text formatting.

The documentation will be updated with the exact formats for all commands
and events.

Resolves: #1546
Resolves: #1563

DeveloperNote: The chan_websocket plain-text control and event messages are now
deprecated (but remain the default) in favor of JSON formatted messages.
See https://docs.asterisk.org/Configuration/Channel-Drivers/WebSocket for
more information.

DeveloperNote: A "transport_data" parameter has been added to the
channels/externalMedia ARI endpoint which, for websocket, allows the caller
to specify parameters to be added to the dialstring for the channel.  For
instance, `"transport_data": "f(json)"`.
2025-11-04 19:27:50 +00:00
Roman Pertsev
9cd2805a5f res_audiosocket: fix temporarily unavailable
Operations on non-blocking sockets may return a resource temporarily unavailable error (EAGAIN or EWOULDBLOCK). This is not a fatal error but a normal condition indicating that the operation would block.

This patch corrects the handling of this case. Instead of incorrectly treating it as a reason to terminate the connection, the code now waits for data to arrive on the socket.
2025-10-29 15:21:43 +00:00