Gets serialized into the bool on the profile's global level.
Isn't leg specific, but global for the whole session.
Only used to remove SST related headers and option tags
from requests and replies being sent through either
`SBCCallLeg::onSendRequest()` or `SBCCallLeg::onSendReply()`.
Transparent means - do not touch existing SST headers.
SessionTimer implementation factory isn't triggered in this case.
Change-Id: Id98a8abc957be11d140eba2394fed7ebe1302ca7
This is a prolongation of the commit 5085fb134878
In case this very leg (A or B) doesn't support
SST timers, then before sending out the request/reply
to the end-point, make sure to remove SST related stuff:
- `Supported: timer` (option tag)
- `Require: timer` (option tag)
- `Session-Expires` header
- `Min-SE` header
Remove previously introduced manipulations from the
`SBCCallLeg::relayEvent()`, which is rather meant
to process the incoming request/reply event
in the other leg (and not this leg), because then
we mistakingly remove headers checking the wrong leg.
Hence `SBCCallLeg::relayEvent()` -> `AmB2BSession::relayEvent()`
is only responsible to post the relay event for this leg,
and the `SBCCallLeg::onSendRequest()` / `SBCCallLeg::onSendReply()`
are actually handlers for the end view of the SIP message being
sent out.
Additionally: introduce the `SBCCallLeg::onSendReply()` hook,
for the virtual `AmSession::onSendReply()`, that should accordingly
handle SST removal in the scope of SBCCallLeg.
Additionally: introduce the `sessionTimerSupportedByLeg()` static
helper for SBCCallLeg, to check support of SST based on A/B leg awareness.
Change-Id: Icb5d0bc5a62b06e26a46a1bceeb5c73aa8d7bf2a
In case the session originator never declared SST support
(with `aleg_sst_enable=yes`), then remove all possible SST
related headers and `timer` option tags where present.
This gets removed in all sip responses/requests going
towards the caller in this case.
Change-Id: I960fa09d00a8f324665b89d2e3ab0b44cbfcd677
Mirrors the sems-pbx fix for the shared apps/sbc and core code.
When a mid-transfer call is picked up (BLF), SEMS sends a re-INVITE
with the picker's media towards the caller while another re-INVITE is
still pending on that leg. It used to answer 491 and drop the update,
so the call connects with no audio on either side.
The P-Force-491: 0 marker exists to prevent exactly this: it tells the
receiving leg to queue the update instead of 491ing it. But
onB2BEvent() read the marker from the relayed request hdrs - which
SBCCallLeg::relayEvent() has already run the profile's header filter
over. Whitelist profiles don't list the header, so it was stripped and
the 491 fired anyway.
Read the marker earlier, in AmB2BSession::onSipRequest() while the hdrs
are still unfiltered, and carry it as a skip_491 flag on the event. The
queued update is replayed once the pending transaction ends, as before.
This CE codebase has no call_transfer module, so t/test-xdsm-race.py
reproduces the race with generic sbc.putOnHold/sbc.resumeHeld DSM
actions over the same CallLeg.cpp path: the basic race, two stacked
self-updates ahead of a collision, a plain unmarked glare that must
still get 491, and the marker surviving the whitelist filter. Each
collision carries the marker like the real pickup does, so the tests
491 on unpatched code.
Also make the tests robust on a loaded CI: recvB2BINVITE() skips
in-dialog INVITEs (those with a To-tag), and the queued updates are read
by CSeq freshness, so timer-A retransmissions of earlier re-INVITEs
piling up in the socket buffer aren't mistaken for the awaited update.
Change-Id: Ie55f0a2f33a0dde5e2c3dd8dd2fb2c82c67a06c4
Introduce explicit policy for within-dialog SST support:
- whenever remote side (call leg) doesn't explicitly declare
it supports timers (with `Supported: timer`), disable all
previously set timers for this particular leg
- this touches request originator, as well as answerer
- requests: only UPDATE and INVITE methods are affected
- answers: only positive answers are affected
- by default this behavior is always disabled if not enabled
explicitly in the profile's config with `sst_strict_mode`
- sst_strict_mode takes either `yes` or `no`
P.S.: the `sst_strict_mode` must not be initialized to true
by default, because RFC 4028 explicitly tells to support
the operation even when only one UA understands session timers.
So we have to be quite accurate and not enforce the strict mode.
Change-Id: Ie6647eb061a73dc052367dbd291589198487093c
Update the usage of the `getParameter()` through
the modules, whereas the default value isn't given.
Change-Id: I4c725639f56b70e5548fa3da321c8452675cdf99
Rework plug-ins parser so that it supports
the multi-line parsing.
E.g.:
load_plugins=wav;\
gsm;\
g729;\
opus;\
g722;\
di_dial;\
...
Change-Id: Ic672ff72db73279d9fd3d52ba9a60fa5f6d7eb25
- Add pyproject.toml and tox.ini with consistent black and pycodestyle
settings.
+ Fix all errors >= E300.
- Place unconditional imports at the beginning of the file.
- Do not import more than one module at the same time.
- Do not use blackslash at EOL within brackets.
- Do not use bare except.
- Do not end statement with semicolon.
- Do not place multiple statements in the same line.
- Use «is» and «is not» instead of «==» and «!=» for None.
- Disambiguate short variable name by giving it a better longer name.
- Remove trailing whitespace.
- Fix expected number of blank lines.
Change-Id: I02a29887a1267f5b843822e0ff05b7dca4416554
The code had not been converted to Python 3.x, and was not even
compiling there, with something like:
$ find -name '*.py' | xargs -n1 python3 -m py_compute
Change-Id: I795f931123d1bccb85670fe0dc6b06c46a9f22c2
Properly place the clear RTP receivers handler.
Instead of doing directly from the destructor,
do it on state change (onBeforeDestroy) via
the down to up virtual function realization search.
Is triggered by `AmSession::finalize()`.
Closes Coverity CID 642748.
Change-Id: I4c224425e9fbecedef3d29a6658f1723313b19c4
All the subsequent code already relies on the fact
it's not NULL, so makes no sense to actually check
this later again.
Closes Coverity CID 642754.
Change-Id: I0de348d0deff6d36f4d0ecfdb2635c94d1101fb2
This commit introduces a new RTP transport model,
based on the AmRtpTransport abstraction, providing a more modular and
efficient approach to RTP handling compared to the legacy model.
General things:
- Introduction of new RTP receiver and transport abstractions
- The new model coexists with the legacy RTP handling
to preserve backward compatibility
Architecture overview:
- A new AmRtpTransport layer is introduced to encapsulate RTP transport logic
and decouple it from AmRtpStream and session-level code
- Transport-specific functionality is implemented via dedicated classes:
- AmRtpTransport: base abstraction responsible for RTP/RTCP packet flow,
lifecycle management, and interaction with streams
- AmRtpUdpSocket: UDP-based RTP socket implementation
- AmRtpSocketPair: manages RTP/RTCP socket pairs and their coordination
- AmRtpStream is refactored to rely on the transport interface
instead of directly managing sockets and low-level I/O
Integration details:
- SIP session and dialog logic (AmSession, AmSipDialog) is updated to work with
the new transport model
- SBC call legs and call profiles are extended to support transport selection
and lifecycle handling
- SDP processing (AmSdp) is updated to reflect transport capabilities and
address handling changes
This refactoring improves separation of concerns, reduces coupling between RTP
streaming and transport mechanics, and provides a cleaner foundation for future
RTP extensions and optimizations.
Code provenance and license:
- part of the code was written by Fokus GmbH
- part of the code was written by Sipwise GmbH
- part of the code base copyrighted by Fokus GmbH was provided by them in
the form of backports under the GPL license.
- these changes are covered by the GPL, matching the existing project license
Change-Id: I313c4abd9b54f805c1e668c019cf6fb8c4a9e46d
If the Content-Length is empty, then it makes no sense
to parse and filter application/sdp body.
Otherwise a parser is going to fail and answer with 488.
Change-Id: I92cdd19319c6f4a4edcfbaeec7bad1be12c8a0b0
Add parsing of Content-Length, for cases
were this length matters (e.g. ct length > 0,
but suddenly there is no SDP body).
Also add a getter for the AmContentType's length.
Change-Id: I92cdd19319c6f4a4edcfbaeec7bad1be12c8a0b1
Reverse inheritence between singleton class and its base.
Change singleton template so that the singleton class doesn't inherit
from its base, but rather that the singelton class inherits from the
singleton template. This removes the need to keep the singleton base
classes separate (with the underscore prefix) plus a `typedef` for the
singleton class, and instead makes the class itself become the
singleton. (The exception being intermediate classes that have multiple
other derived classes, which is only the wheeltimer).
This makes for cleaner typing, but requires use of listing the singleton
template as friend class.
No functional changes.
Change-Id: Ic45cb01f7870ce0ba97188e58340b10fdc0380cb
Preamble: no functional changes.
AmSdp::parse() mixes int values with bool,
what makes the behavior not really clear, not defined
and can lead to the unpredicted result (even though the
compiler *should* actually fix that, but one ought to
not rely on this).
Hence make the parse method only be working with bool values.
Then, reverse the return value so that it's clear
that wrongly parsed is `false`, and good parsed is `true`.
Refactor all users accordingly.
Also rework those users, who indeed need `int` value
be returned, e.g. when having -1.
Do the same thing with the `parse_sdp_line_ex()` helper,
whereas parse() is the only user of it. And also reverse
the interpretation of true/false.
Then, make `parse()` working with a plain `char*`, so not a const.
Because doing a tricks like:
cast `char*` to const (user level) -> cast `const char*` to non-const
in a function (in a old C-like manner), has really no sense.
Refactor everything accordingly.
Other than that, refactor AmMimeBody:
Refactor it to work with a plain `char *` pointer instead of working
with `unsigned char *`, which nowadays has really no sense and
rather is a rudiment of C-like code base coming from the past.
Convert `payload` from `unsigned char*` to `char *` accordingly.
Refactor everything in AmMimeBody implementation accordingly.
Remove rudiment C-like casting everywhere, where possible.
Update `parseMultipart()` to work with a plain `const char *`
instead of `const unsigned char*`
P.S.: leave a list of TODO's for further rework, which
is not directly related to this scope of rework.
Change-Id: Ie1e132429245e0d2cc740d5b1c1fc17cf037a820
When using that, the return value must always
be checked, because the parsing itself can indeed fail.
Fixes such things as:
** CID 583412: Error handling issues (CHECKED_RETURN)
/core/AmB2BSession.cpp: 340 in AmB2BSession::acceptPendingInvite(AmSipRequest *, const AmMimeBody *)()
_____________________________________________________________________________________________
*** CID 583412: Error handling issues (CHECKED_RETURN)
/core/AmB2BSession.cpp: 340 in AmB2BSession::acceptPendingInvite(AmSipRequest *, const AmMimeBody *)()
334 return;
335 }
336
337 /* port must reflect actual port in SDP offer coming in */
338 if (sdp) {
339 AmSdp fake_sdp;
>>> CID 583412: Error handling issues (CHECKED_RETURN)
>>> Calling "parse" without checking return value (as is done elsewhere 12 out of 15 times).
340 fake_sdp.parse((const char *)sdp->getPayload());
341 desired_port = getMediaPort(fake_sdp);
342 }
343
344 if (desired_port) {
345 ILOG_DLG(L_DBG, "Desired port for fake 200OK is '%d'\n", desired_port);
Change-Id: I7bd177a624ebe2df2629863eb31f97f99bd921bb
Set the port in fake SDP answer (to the other side)
coming from the leg, which now replaces the previously
existing one, to the port gotten from the replace INVITE.
Otherwise, if to use the port from the pending transaction
(towards pick-up'er) it confuses rtpengine with a case
when same port talks to himself, and then can later be
used to update the pick-uper's leg once again.
Change-Id: I4c001f7956a005b64285c05586839f01216cfd91
Force the leg being connected instead of the replaced one
to the rtp_relay_mode = RTP_Direct, because otherwise
legs can get SEMS involved into rtp relay after a transfer
is finished.
Change-Id: Ifb55feaa7813fc303a663ac132b0bfe175772ce0
Make the AmOfferAnswer model actual and introduce
according class API updates.
Accordingly update CallLeg, SBCCallLeg and AmSipDialog.
Change-Id: Iab26f4a7577af56df68ffe693859eaac08913b7f
If the CallLeg isn't SIP relayable, then makes no sense
to relay INVITE to the other leg, otherwise it gets stuck
on the other side.
Change-Id: I43dff24981084885a20f697537419a6dac75b806
When this leg being reconnected, is still in progress
of posting remaining events to update the other side
(the reconnect originator), don't consider it as
sip relay ready. Otherwise any INVITE updates coming
to it, will lead to stumbled INVITEs coming to the other leg,
but without a possibility to use it here (because e.g. this
other side never seen 200OK answer even).
Change-Id: I183d0f70433c156030de38238db395e2c1372352
We can now use the sets to iterate the bindings in order of their
expiry and exit the loop when we encounter the first one with an expiry
in the future.
Change-Id: I093bea9807b4a432ac965b402394edc43eef5a1f
Add an ordered set of all AorEntry objects, ordered by expire time.
Amend modifier methods to update the set whenever some expire time is
updated or an entry or binding removed.
Change-Id: I2afe5becfa2124dbc8c33b38fe1a3e6d4b8a20d5
Move deletion of bindings into AorHash, similar to how expire times are
set. This makes it possible to manage expiry in a central place.
Change-Id: I76a72881ed202e85fb70e9d8526bac55863d07db
Make AorEntry keep an ordered set of all bindings, ordered by expire
time. This makes it easy to quickly tell when the next binding is set to
expire, and which one. Store iterators to bindings in the set so that
they can be used to directly remove the binding when expired.
Change-Id: Ib63c15d5f6e8990e2f4d237726be54da76194a20
Provide accessor methods. Put the setter into AorHash and require
iterators. All bindings must be in an AorEntry container and all
AorEntry objects must be in the AorHash container. By putting the setter
in AorHash and using iterators we can make sure that the binding is in
the container already and that expiry values are kept consistent.
Change-Id: I1c5140d1a7547059f61e47cd317680fcb6eae9fe
Provide a proper class for key matching/ordering instead of
hand-crafting a key to be used as index in several places. Use a simple
ordered map instead of the bucket-based approach.
Change-Id: I9e1918a48e103b655caac160c125a0393d261fca
Put all AorEntry objects into a single hash map. Eliminates the need for
AorBucket. Use an unorered hash map for performance. Use lock guards
instead of manual lock/unlock. Remove an unused argument to gbc().
Switch to the full tick cycle length instead of the tick-based one as
there are no more buckets to iterate.
Change-Id: I7da3bacaa5a28b7e628695ab879394fc6d56f5d2
Simplify the little-used RegisterCache alias hash by using the new
hash_map template. Eliminates the need for AliasBucket. Use an unordered
hash map for performance. Use lock guards instead of manual lock/unlock.
Manually `delete` contained objects as our table's .erase() doesn't do
that.
Change-Id: Ia9721460ce8264fc0a90184a91beca46012b64dd
Instead of relying on a short tick duration to make sure the thread
exits when requested, add a dedicated condition flag and variable. Use
AmThread on_stop to set it and wake up the thread. Use the condition
variable's timed wait instead of nanosleep for the ticks.
This somewhat duplicates what other threads are doing, and what
stop_requested() is doing, and should be unified into a single mechanism
provided by AmThread in the future.
Change-Id: I364e747b4acc1986fa262588c47d83c063ff2d69
For newly created call profiles use the move operation
instead of copy one.
Fixes:
CID 542292:Variable copied when it could be moved (COPY_INSTEAD_OF_MOVE)
Change-Id: Ia130fc3e32d23e63f3d41fc6261e90ecf742ecf7