A feature of chan_sip that service providers relied upon was the ability to
identify by the Authorization username. This is most often used when customers
have a PBX that needs to register rather than identify by IP address. From my
own experiance, this is pretty common with small businesses who otherwise
don't need a static IP.
In this scenario, a register from the customer's PBX may succeed because From
will usually contain the PBXs account id but an INVITE will contain the caller
id. With nothing recognizable in From, the service provider's Asterisk can
never match to an endpoint and the INVITE just stays unauthorized.
The fixes:
A new value "auth_username" has been added to endpoint/identify_by that
will use the username and digest fields in the Authorization header
instead of username and domain in the the From header to match an endpoint,
or the To header to match an aor. This code as added to
res_pjsip_endpoint_identifier_user rather than creating a new module.
Although identify_by was always a comma-separated list, there was only
1 choice so order wasn't preserved. So to keep the order, a vector was added
to the end of ast_sip_endpoint. This is only used by res_pjsip_registrar
to find the aor. The res_pjsip_endpoint_identifier_* modules are called in
globals/endpoint_identifier_order.
Along the way, the logic in res_pjsip_registrar was corrected to match
most-specific to least-specific as res_pjsip_endpoint_identifier_user does.
The order is:
username@domain
username@domain_alias
username
Auth by username does present 1 problem however, the first INVITE won't have
an Authorization header so the distributor, not finding a match on anything,
sends a securty_alert. It still sends a 401 with a challenge so the next
INVITE will have the Authorization header and presumably succeed. As a result
though, that first security alert is actually a false alarm.
To address this, a new feature has been added to pjsip_distributor that keeps
track of unidentified requests and only sends the security alert if a
configurable number of unidentified requests come from the same IP in a
configurable amout of time. Those configuration options have been added to
the global config object. This feature is only used when auth_username
is enabled.
Finally, default_realm was added to the globals object to replace the hard
coded "asterisk" used when an endpoint is not yet identified.
The testsuite tests all pass but new tests are forthcoming for this new
feature.
ASTERISK-25835 #close
Reported-by: Ross Beer
Change-Id: I30ba62d208e6f63439600916fcd1c08a365ed69d
This patch added new global pjsip option 'disable_multi_domain'.
Disabling Multi Domain can improve Realtime performance by reducing
number of database requests.
ASTERISK-25930 #close
Change-Id: I2e7160f3aae68475d52742107949a799aa2c7dc7
The run_agi function is eating control frames when it shouldn't be. This is
causing issues when an AGI is run from CONNECTED_LINE_SEND_SUB in a blond
transfer.
Alice calls Bob. Bob attended transfers to Charlie but hangs up before Charlie
answers.
Alice gets the COLP UPDATE indicating Charlie but Charlie never gets an UPDATE
and is left thinking he's connected to Bob.
In this case, when CONNECTED_LINE_SEND_SUB runs on Alice's channel and it calls
an AGI, the extra eaten frames prevent CONNECTED_LINE_SEND_SUB from running on
Charlie's channel.
The fix was to accumulate deferrable frames in the "forever" loop instead of
dropping them, and re-queue them just before running the actual agi command
or exiting.
ASTERISK-25951 #close
Change-Id: I0f4bbfd72fc1126c2aaba41da3233a33d0433645
We lose the fact that there is a swap channel if there is one. We
currently wind up rejoining the stasis bridge as a normal join after the
swap channel has already been kicked from the bridge.
This patch preserves the swap channel so the AMI/ARI events can note that
the channel joining the bridge is swapping with another channel. Another
benefit to swaqpping in one operation is if there are any channels that
get lonely (MOH, bridge playback, and bridge record channels). The lonely
channels won't leave before the joining channel has a chance to come back
in under stasis if the swap channel is the only reason the lonely channels
are staying in the bridge.
ASTERISK-25947 #close
Reported by: Richard Mudgett
ASTERISK-24649
Reported by: John Bigelow
ASTERISK-24782
Reported by: John Bigelow
Change-Id: If37ea508831d1fed6dbfac2f191c638fc0a850ee
When create_new_id_hdr creates a new RPID or PAI header, it starts by cloning
the From header, then it overwrites the display name and uri from the channel's
connected.id. If the connected.id.name wasn't valid, create_new_id_hdr was
leaving the display name from the From header in the new RPID or PAI header.
On an attended transfer where the originator had a caller id number set but not
a display name, the re-INVITE to the final transferee had the number of the
originator but the display name of the transferer.
Added a check to clear out the display name in the new header if
connected.id.name was invalid.
ASTERISK-25942 #close
Change-Id: I60b4bf7a7ece9b7425eba74151c0b4969cd2738b
The PJSIP parsing functions provide a nice concise way to check the
length of a hostname in a SIP URI. The problem is that in order to use
those parsing functions, it's required to use them from a thread that
has registered with PJLib.
On startup, when parsing AOR configuration, the permanent URI handler
may not be run from a PJLib-registered thread. Specifically, this could
happen when Asterisk was started in daemon mode rather than
console-mode. If PJProject were compiled with assertions enabled, then
this would cause Asterisk to crash on startup.
The solution presented here is to do our own parsing of the contact URI
in order to ensure that the hostname in the URI is not too long. The
parsing does not attempt to perform a full SIP URI parse/validation,
since the hostname in the URI is what is important.
ASTERISK-25928 #close
Reported by Joshua Colp
Change-Id: Ic3d6c20ff3502507c17244a8b7e2ca761dc7fb60
Recent changes to the PJSIP registrar resulted in tests failing due to
missing AOR_CONTACT_ADDED test events. The reason for this was that the
user_agent string had junk values in it, resulting in being unable to
generate the event.
I'm going to be honest here, I have no idea why this was happening. Here
are the steps needed for the user_agent variable to get messed up:
* REGISTER is received
* First contact in the REGISTER results in a contact being removed
* Second contact in the REGISTER results in a contact being added
* The contact, AOR, expiration, and user agent all have to be passed as
format parameters to the creation of a string. Any subset of those
parameters would not be enough to cause the problem.
Looking into what was happening, the thing that struck me as odd was
that the user_agent variable was meant to be set to the value of the
User-Agent SIP header in the incoming REGISTER. However, when removing a
contact, the user_agent variable would be set (via ast_strdupa inside a
loop) to the stored contact's user_agent. This means that the
user_agent's value would be incorrect when attempting to process further
contacts in the incoming REGISTER.
The fix here is to use a different variable for the stored user agent
when removing a contact. Correcting the behavior to be correct also
means the memory usage is less weird, and the issue no longer occurs.
ASTERISK-25929 #close
Reported by Joshua Colp
Change-Id: I7cd24c86a38dec69ebcc94150614bc25f46b8c08
At shutdown it is possible for modules to be unloaded that wouldn't
normally be unloaded. This allows the environment to be cleaned up.
The res_pjsip_transport_management module did not have the unload
logic in it to clean itself up causing the res_pjsip module to not
get unloaded. As a result the res_pjsip monitor thread kept going
processing traffic and timers when it shouldn't.
Change-Id: Ic8cadee131e3b2c436a81d3ae8bb5775999ae00a
The scheduler thread that kills idle TCP connections was not registering
with PJProject properly and causing assertions if PJProject was built in
debug mode.
This change registers the thread with PJProject the first time that the
scheduler callback executes.
AST-2016-005
Change-Id: I5f7a37e2c80726a99afe9dc2a4a69bdedf661283
There are several places that do scheduled tasks or periodic housecleaning,
each with its own implementation:
* res_pjsip_keepalive has a thread that sends keepalives.
* pjsip_distributor has a thread that cleans up expired unidentified requests.
* res_pjsip_registrar_expire has a thread that cleans up expired contacts.
* res_pjsip_pubsub uses ast_sched directly and then calls ast_sip_push_task.
* res_pjsip_sdp_rtp also uses ast_sched to send keepalives.
There are also places where we should be doing scheduled work but aren't.
A good example are the places we have sorcery observers to start registration
or qualify. These don't work when changes are made to a backend database
without a pjsip reload. We need to check periodically.
As a first step to solving these issues, a new ast_sip_sched facility has
been created.
ast_sip_sched wraps ast_sched but only uses ast_sched as a scheduled queue.
When a task is ready to run, ast_sip_task_pusk is called for it. This ensures
that the task is executed in a PJLIB registered thread and doesn't hold up the
ast_sched thread so it can immediately continue processing the queue. The
serializer used by ast_sip_sched is one of your choosing or a random one from
the res_pjsip pool if you don't choose one.
Another feature is the ability to automatically clean up the task_data when the
task expires (if ever). If it's an ao2 object, it will be dereferenced, if
it's a malloc'd object it will be freed. This is selectable when the task is
scheduled. Even if you choose to not auto dereference an ao2 task data object,
the scheduler itself maintains a reference to it while the task is under it's
control. This prevents the data from disappearing out from under the task.
There are two scheduling models.
AST_SIP_SCHED_TASK_PERIODIC specifies that the invocations of the task occur at
the specific interval. That is, every "interval" milliseconds, regardless of
how long the task takes. If the task takes longer than the interval, it will
be scheduled at the next available multiple of interval. For exmaple: If the
task has an interval of 60 secs and the task takes 70 secs (it better not),
the next invocation will happen at 120 seconds.
AST_SIP_SCHED_TASK_DELAY specifies that the next invocation of the task should
start "interval" milliseconds after the current invocation has finished.
Also, the same ast_sched facility for fixed or variable intervals exists. The
task's return code in conjunction with the AST_SIP_SCHED_TASK_FIXED or
AST_SIP_SCHED_TASK_VARIABLE flags controls the next invocation start time.
One res_pjsip.h housekeeping change was made. The pjsip header files were
added to the top. There have been a few cases lately where I've needed
res_pjsip.h just for ast_sip calls and had compiles fail spectacularly because
I didn't add the pjsip header files to my source even though I never referenced
any pjsip calls.
Finally, a few new convenience APIs were added to astobj2 to make things a
little easier in the scheduler. ao2_ref_and_lock() calls ao2_ref() and
ao2_lock() in one go. ao2_unlock_and_unref() does the reverse. A few macros
were also copied from res_phoneprov because I got tired of having to duplicate
the same hash, sort and compare functions over and over again. The
AO2_STRING_FIELD_(HASH|SORT|CMP)_FN macros will insert functions suitable for
aor_container_alloc into your source.
This facility can be used immediately for the situations where we already have
a thread that wakes up periodically or do some scheduled work. For the
registration and qualify issues, additional sorcery and schema changes would
need to be made so that we can easily detect changed objects on a periodic
basis without having to pull the entire database back to check. I'm thinking
of a last-updated timestamp on the rows but more on this later.
Change-Id: I7af6ad2b2d896ea68e478aa1ae201d6dd016ba1c
"Idle" here means that someone connects to us and does not send a SIP
request. PJProject will not automatically time out such connections, so
it's up to Asterisk to do it instead.
When we receive an incoming TCP connection, we will start a timer
(equivalent to transaction timer D) waiting to receive an incoming
request. If we do not receive a request in that timeframe, then we will
shut down the TCP connection.
ASTERISK-25796 #close
Reported by George Joseph
AST-2016-005
Change-Id: I7b0d303e5d140d0ccaf2f7af562071e3d1130ac6
Due to some ignored return values, Asterisk could crash if processing an
incoming REGISTER whose contact URI was above a certain length.
ASTERISK-25707 #close
Reported by George Joseph
Patches:
0001-res_pjsip-Validate-that-URIs-don-t-exceed-pjproject-.patch
AST-2016-004
Change-Id: I0ed3898fe7ab10121b76c8c79046692de3a1be55
* Added Useragent and RegExpire headers to AMI Event
ContactStatusDetail with associated documentation.
ASTERISK-25903 #close
Change-Id: If3d121e943e588d016ba51d4eb9c6a421a562239
Contact expiration can occur in several places: res_pjsip_registrar,
res_pjsip_registrar_expire, and automatically when anyone calls
ast_sip_location_retrieve_aor_contact. At the same time, res_pjsip_registrar
may also be attempting to renew or add a contact. Since none of this was locked
it was possible for one thread to be renewing a contact and another thread to
expire it immediately because it was working off of stale data. This was the
casue of intermittent registration/inbound/nominal/multiple_contacts test
failures.
Now, the new named lock functionality is used to lock the aor during contact
expire and add operations and res_pjsip_registrar_expire now checks the
expiration with the lock held before deleting the contact.
ASTERISK-25885 #close
Reported-by: Josh Colp
Change-Id: I83d413c46a47796f3ab052ca3b349f21cca47059
The first available transport of the appropriate type is used now.
This patch adds new config option 'transport' for outbound-publish.
If transport is set then outbound PUBLISH requests will use this transport.
ASTERISK-25901 #close
Change-Id: Ib389130489b70e36795b0003fa5fd386e2680151
BLF pickup isn't working on Cisco SPA and Snom phones
if the direction="recipient" attribute is missing in 'dialog' tag.
This patch adds direction="recipient" if extension state is
Ringing.
ASTERISK-24601 #close
Change-Id: I5b2c097ca29fd59e92ba237ca5d397cb1b0bcd8c
When shutting down, the PJSIP sorcery is destroyed. The registrar
expiration module queries the PJSIP sorcery to determine what
to expire. As there was no synchronization between termination
of the expiration thread and the unloading of the module it was
possible for the thread to try to access the PJSIP sorcery after
it had been destroyed.
This change ensures that the thread is shut down before allowing
the module to be considered unloaded.
Change-Id: I69fd239edbaaf160c2d37ae00d3ac06e5596fe8b
Some SIP devices indicate hold/unhold using deferred SDP reinvites. In
other words, they provide no SDP in the reinvite.
A typical transaction that starts hold might look something like this:
* Device sends reinvite with no SDP
* Asterisk sends 200 OK with SDP indicating sendrecv on streams.
* Device sends ACK with SDP indicating sendonly on streams.
At this point, PJMedia's SDP negotiator saves Asterisk's local state as
being recvonly.
Now, when the device attempts to unhold, it again uses a deferred SDP
reinvite, so we end up doing the following:
* Device sends reinvite with no SDP
* Asterisk sends 200 OK with SDP indicating recvonly on streams
* Device sends ACK with SDP indicating sendonly on streams
The problem here is that Asterisk offered recvonly, and by RFC 3264's
rules, if an offer is recvonly, the answer has to be sendonly. The
result is that the device is not taken off hold.
What is supposed to happen is that Asterisk should indicate sendrecv in
the 200 OK that it sends. This way, the device has the freedom to
indicate sendrecv if it wants the stream taken off hold, or it can
continue to respond with sendonly if the purpose of the reinvite was
something else (like a session timer refresher).
The fix here is to alter the SDP negotiator's state when we receive a
reinvite with no SDP. If the negotiator's state is currently in the
recvonly or inactive state, then we alter our local state to be
sendrecv. This way, we allow the device to indicate the stream state as
desired.
ASTERISK-25854 #close
Reported by Robert McGilvray
Change-Id: I7615737276165eef3a593038413d936247dcc6ed
I forgot the new voicemail_extension wasn't a stringfield and didn't check
for NULL where I should have.
Change-Id: I029482d5c2ab72474838750461bd46b0809c90fb
The only caller of ari_bridges_play_found() has this note:
If ari_bridges_play_found fails because the channel is unavailable for
playback, The channel will be removed from the playback list soon. We can
keep trying to get channels from the list until we either get one that
will work or else there isn't a channel for this bridge anymore, in which
case we'll revert to ari_bridges_play_new.
Change-Id: Ib068141b367ccaa17be0dab4181c98e26c5127d6
The stasis_app_playback and stasis_app_recording structs need to have a
struct stasis_app_control ref. Other threads can get a reference to the
playback and recording structs from their respective global container.
These other threads can then use the control pointer they contain after
the control struct has gone.
* Add control ref to stasis_app_playback and stasis_app_recording structs.
With the refs added, the control command queue can now have a circular
control reference which will cause the control struct to never get
released if the control's command queue is not flushed when the channel
leaves the Stasis application. Also the command queue needs better
protection from adding commands if the control->is_done flag is set.
* Flush the control command queue on exit.
ASTERISK-25882 #close
Change-Id: I3cf1fb59cbe6f50f20d9e35a2c07ac07d7f4320d
* Give the struct stasis_app_control ao2 object a ref to the channel held
in the object. Now the channel will still be around if a thread needs to
post a stasis message instead of crash because the topic was destroyed.
* Moved stopping any lingering silence generator out of the struct
stasis_app_control destructor and made it a part of exiting the Stasis
application. Who knows which thread the destructor will be called under
so it cannot affect the channel's silence generator. Not only was the
channel unprotected when the silence generator was stopped, stasis may no
longer even control the channel.
ASTERISK-25882
Change-Id: I21728161b5fe638cef7976fa36a605043a7497e4
Background:
If your extension is 1000 and the voicemail access extension is 1571 and you
dial 1571, usually a dialplan rule calls voicemailmain with your extension and
you are placed directly in your mailbox. Therefore most admins program the
voicemail (or other speed dial) button on their phones to the access extension.
Some phones (Snom at least) use whatever is programmed there to also subscribe
for MWI and so can't dial one number and subscribe to another. This works fine
in chan_sip because chan_sip completely ignores the user portion of the
SUBSCRIBE message request URI. If it can match the peer, is subscribes to the
peer's mailbox. The user could be set to anything or nothing and you'd still
get subscribed to your mailbox.
Issue:
chan_pjsip actually uses the user portion of the URI to find an aor and its
mailboxes. Therefore a subscribe to 1571 results in a 404. Sure, you can
create an aor for 1571 but you certainly can't add your entire voicemail
system's mailboxes to it and everyone would get notified of every MWI.
Solution:
When an MWI subscribe comes in and an aor can't be found that matches the
resource directly, check the resource against the endpoint's aors. If an aor
is found that has a voicemail_extension that matches the resource, use it.
ASTERISK-25865
Reported-by: Ross Beer
Change-Id: I770ea185f751f1ada888fafb4b452115f1c06e9e
res_pjsip_mwi was missing the chan_sip "vmexten" functionality which adds
the Message-Account header to the MWI NOTIFY. Also, specifying mailboxes
on endpoints for unsolicited mwi and on aors for subscriptions required
that the admin know in advance which the client wanted. If you specified
mailboxes on the endpoint, subscriptions were rejected even if you also
specified mailboxes on the aor.
Voicemail extension:
* Added a global default_voicemail_extension which defaults to "".
* Added voicemail_extension to both endpoint and aor.
* Added ast_sip_subscription_get_dialog for support.
* Added ast_sip_subscription_get_sip_uri for support.
When an unsolicited NOTIFY is constructed, the From header is parsed, the
voicemail extension from the endpoint is substituted for the user, and the
result placed in the Message-Account field in the body.
When a subscribed NOTIFY is constructed, the subscription dialog local uri
is parsed, the voicemail_extension from the aor (looked up from the
subscription resource name) is substituted for the user, and the result
placed in the Message-Account field in the body.
If no voicemail extension was defined, the Message-Account field is not added
to the NOTIFY body.
mwi_subscribe_replaces_unsolicited:
* Added mwi_subscribe_replaces_unsolicited to endpoint.
The previous behavior was to reject a subscribe if a previous internal
subscription for unsolicited MWI was found for the mailbox. That remains the
default. However, if there are mailboxes also set on the aor and the client
subscribes and mwi_subscribe_replaces_unsolicited is set, the existing internal
subscription is removed and replaced with the external subscription. This
allows an admin to configure mailboxes on both the endpoint and aor and allows
the client to select which to use.
ASTERISK-25865 #close
Reported-by: Ross Beer
Change-Id: Ic15a9415091760539c7134a5ba3dc4a6a1217cea
Commit 1bce690ccb was incrementing txcount
for rtcp packets as well as rtp packets and that was causing sender reports
to be generated instead of receiver reports in cases where no rtp was actually
being sent.
Moved the txcount increment from __rtp_sento, which handles both rtp and rtcp,
to rtp_sento which only handles rtp packets.
Discovered by the hep/rtcp-receiver test.
Change-Id: Ie442e4bb947a68847a676497021ba10ffaf376d5
Added the ability to show channel statistics to chan_pjsip (cli_functions.c)
Moved the existing 'pjsip show channel(s)' functionality from
pjsip_configuration to cli_functions.c. The stats needed chan_pjsip's
private header so it made sense to move the existing channel commands as well.
Now using stasis_cache_dump to get the channel snapshots rather than retrieving
all endpoints, then getting each one's channel snapshots. Much more efficient.
Change-Id: I03b114522126d27434030b285bf6d531ddd79869
No one seemed to notice but every time an OPTIONS goes out, it goes
out with a From of "asterisk" (or whatever the default from_user is set to),
even if you specify an endpoint.
The issue had several causes...
qualify_contact is only called with an endpoint if called from the CLI.
If the endpoint is NULL, qualify_contact only looks up the endpoint if
authenticate_qualify=yes. Even then, it never passes it on to
ast_sip_create_request where the From header is set. Therefore From
is always "asterisk" (or whatever the default from_user is set to).
Even if ast_sip_create_request were to get an endpoint, it only sets
the From if endpoint->from_user is set.
The fix is 4 parts...
First, create_out_of_dialog_request was modified to use the endpoint id
if endpoint was specified and from_user is not set.
Second, qualify_contact was modified to always look up an endpoint if
one wasn't specified regardless of authenticate_qualify. It then passes
the endpoint on to create_out_of_dialog_request.
Third (and most importantly), find_an_endpoint was modified to find
an endpoint by using an "aors LIKE %contact->aor%" predicate with
ast_sorcery_retrieve_by_fields. As such, this patch will only work
if the sorcery realtime optimizations patch goes in. Otherwise we'd
be pulling the entire endpoints database every time we send an OPTIONS.
Since we already know the contact's aor, the on_endpoint callback was also
modified to just check if the contact->aor is an exact match to one of
the endpoint's.
Finally, since we now have an endpoint for every OPTIONS request,
res_pjsip/endpt_send_request (which handles out-of-dialog reqests) was
updated to get the transport from the endpoint and set it on tdata.
Now the correct transport is used.
Change-Id: I2207e12bb435e373bd1e03ad091d82e5aba011af
Asterisk uses separate UDP ports for RTP and RTCP traffic and RFC 5764
explicitly states:
There MUST be a separate DTLS-SRTP session for each distinct pair of
source and destination ports used by a media session
This means RTP keying material cannot be used for DTLS RTCP, which was
the reason why RTCP encryption would fail.
ASTERISK-25642
Change-Id: I7e8779d8b63e371088081bb113131361b2847e3a
rxcount, txcount, rxoctetcount and txoctetcount weren't being calculated
for bridged streams because the calulations were being done after the
bridged short-circuit. Actually, rxoctetcount wasn't ever being calculated.
Moved the calculations so they occur for all valid received packets and
all transmitted packets. Also added rxoctetcount and txoctetcount to
ast_rtp_instance_stat.
Change-Id: I08fb06011a82d38c3b4068867a615068fbe59cbb
Blind transfers to a recognized parking extension need to use the parker's
channel variable values to create the dynamic parking lot. This is
because there is always only one parker while the parkee may actually be a
multi-party bridge. A multi-party bridge can never supply the needed
channel variables to create the dynamic parking lot. In the multi-party
bridge blind transfer scenario, the parker's CHANNEL(parkinglot) value and
channel variables are inherited by the local channel used to park the
bridge.
* In park_common_setup(), make use the parker instead of the parkee to
supply the dynamic parking lot channel variable values. In all but one
case, the parkee is the same as the parker. However, in the recognized
parking extension blind transfer scenario for a two party bridge they are
different channels. For consistency, we need to use the parker channel.
* In park_local_transfer(), pass the CHANNEL(parkinglot) value to the
local channel when blind transferring a multi-party bridge to a recognized
parking extension.
* When a local channel starts a call, the Local;2 side needs to inherit
the CHANNEL(parkinglot) value from Local;1.
The DTMF one-touch parking case wasn't even trying to create dynamic
parking lots before it aborted the attempt.
* In parking_park_call(), add missing code to create a dynamic parking
lot.
A DTMF bridge hook is documented as returning -1 to remove the hook.
Though the hook caller is really coded to accept non-zero. See the
ast_bridge_hook_callback typedef.
* In feature_park_call(), don't remove the DTMF one-touch parking hook
because of an error.
ASTERISK-24605 #close
Reported by: Philip Correia
Patches:
call_park.patch (license #6672) patch uploaded by Philip Correia
Change-Id: I221d3a8fcc181877a1158d17004474d35d8016c9
There were a number of places in the res_pjsip stack that were getting
all endpoints or all aors, and then filtering them locally.
A good example is pjsip_options which, on startup, retrieves all
endpoints, then the aors for those endpoints, then tests the aors to see
if the qualify_frequency is > 0. One issue was that it never did
anything with the endpoints other than retrieve the aors so we probably
could have skipped a step and just retrieved all aors. But nevermind.
This worked reasonably well with local config files but with a realtime
backend and thousands of objects, this was a nightmare. The issue
really boiled down to the fact that while realtime supports predicates
that are passed to the database engine, the non-realtime sorcery
backends didn't.
They do now.
The realtime engines have a scheme for doing simple comparisons. They
take in an ast_variable (or list) for matching, and the name of each
variable can contain an operator. For instance, a name of
"qualify_frequency >" and a value of "0" would create a SQL predicate
that looks like "where qualify_frequency > '0'". If there's no operator
after the name, the engines add an '=' so a simple name of
"qualify_frequency" and a value of "10" would return exact matches.
The non-realtime backends decide whether to include an object in a
result set by calling ast_sorcery_changeset_create on every object in
the internal container. However, ast_sorcery_changeset_create only does
exact string matches though so a name of "qualify_frequency >" and a
value of "0" returns nothing because the literal "qualify_frequency >"
doesn't match any name in the objset set.
So, the real task was to create a generic string matcher that can take a
left value, operator and a right value and perform the match. To that
end, strings.c has a new ast_strings_match(left, operator, right)
function. Left and right are the strings to operate on and the operator
can be a string containing any of the following: = (or NULL or ""), !=,
>, >=, <, <=, like or regex. If the operator is like or regex, the
right string should be a %-pattern or a regex expression. If both left
and right can be converted to float, then a numeric comparison is
performed, otherwise a string comparison is performed.
To use this new function on ast_variables, 2 new functions were added to
config.c. One that compares 2 ast_variables, and one that compares 2
ast_variable lists. The former is useful when you want to compare 2
ast_variables that happen to be in a list but don't want to traverse the
list. The latter will traverse the right list and return true if all
the variables in it match the left list.
Now, the backends' fields_cmp functions call ast_variable_lists_match
instead of ast_sorcery_changeset_create and they can now process the
same syntax as the realtime engines. The realtime backend just passes
the variable list unaltered to the engine. The only gotcha is that
there's no common realtime engine support for regex so that's been noted
in the api docs for ast_sorcery_retrieve_by_fields.
Only one more change to sorcery was done... A new config flag
"allow_unqualified_fetch" was added to reg_sorcery_realtime.
"no": ignore fetches if no predicate fields were supplied.
"error": same as no but emit an error. (good for testing)
"yes": allow (the default);
"warn": allow but emit a warning. (good for testing)
Now on to res_pjsip...
pjsip_options was modified to retrieve aors with qualify_frequency > 0
rather than all endpoints then all aors. Not only was this a big
improvement in realtime retrieval but even for config files there's an
improvement because we're not going through endpoints anymore.
res_pjsip_mwi was modified to retieve only endpoints with something in
the mailboxes field instead of all endpoints then testing mailboxes.
res_pjsip_registrar_expire was completely refactored. It was retrieving
all contacts then setting up scheduler entries to check for expiration.
Now, it's a single thread (like keepalive) that periodically retrieves
only contacts whose expiration time is < now and deletes them. A new
contact_expiration_check_interval was added to global with a default of
30 seconds.
Ross Beer reports that with this patch, his Asterisk startup time dropped
from around an hour to under 30 seconds.
There are still objects that can't be filtered at the database like
identifies, transports, and registrations. These are not going to be
anywhere near as numerous as endpoints, aors, auths, contacts however.
Back to allow_unqualified_fetch. If this is set to yes and you have a
very large number of objects in the database, the pjsip CLI commands
will attempt to retrive ALL of them if not qualified with a LIKE.
Worse, if you type "pjsip show endpoint <tab>" guess what's going to
happen? :) Having a cache helps but all the objects will have to be
retrieved at least once to fill the cache. Setting
allow_unqualified_fetch=no prevents the mass retrieve and should be used
on endpoints, auths, aors, and contacts. It should NOT be used for
identifies, registrations and transports since these MUST be
retrieved in bulk.
Example sorcery.conf:
[res_pjsip]
endpoint=config,pjsip.conf,criteria=type=endpoint
endpoint=realtime,ps_endpoints,allow_unqualified_fetch=error
ASTERISK-25826 #close
Reported-by: Ross Beer
Tested-by: Ross Beer
Change-Id: Id2691e447db90892890036e663aaf907b2dc1c67
res/parking/parking_applications.c:
* Add malloc fail checks in setup_park_common_datastore().
* Fix playing parking failed announcement to only happen on non-blind
transfers in park_app_exec(). It could never go out before because a test
was provedly always false.
res/parking/parking_bridge.c:
* Fix NULL tolerance in generate_parked_user() because
bridge_parking_push() can theoretically pass a NULL parker channel if the
parker channel went away for some reason.
* Clarify some weird code dealing with blind_transfer in
bridge_parking_push().
res/parking/parking_bridge_features.c:
* Made park_local_transfer() set BLINDTRANSFER on the Local;1 channel
which will be bulk copied to the Local;2 channel on the subsequent
ast_call(). The additional advantage is if the parker channel has the
BLINDTRANSFER and ATTENDEDTRANSFER variables set they are now guaranteed
to be overridden.
res/parking/parking_manager.c:
* Fix AMI Park action input range checking of the Timeout header in
manager_park().
* Reduced locking scope to where needed in manager_park().
res/res_parking.c:
* Fix some off nominal missing unlocks by eliminating the returns.
Change-Id: Ib64945bc285acb05a306dc12e6f16854898915ca
The configuration unsigned integer option handler sets flags for the
parser as if the option should be a signed integer (PARSE_INT32),
leading to errors on "out of range" values. Fix flags (PARSE_UINT32).
A fix to res_pjsip is also present which stops invalid flags from
being passed when registering sorcery object fields for qualify
status.
ASTERISK-25612 #close
Change-Id: I96b539336275e0e72a8e8033487d2c3344debd3e
The log message when a MusicOnHold music class was not found was changed
from debug level to WARNING level in Asterisk 11.19 and 13.5. For those
using realtime musiconhold, this message is wrong because it warns
before checking the database.
This changeset delays the warning until after the database has been
checked.
Reported-by: Conrad de Wet
ASTERISK-25444 #close
Change-Id: I6cfb2db2f9cfbd2bb3d30566ecae361c4abf6dbf
The "Refer-to" header of an incoming REFER request is parsed by
pjsip_parse_uri(). That function requires the URI parameter to be NULL
terminated. Unfortunately, the previous code added the NULL terminator by
overwriting memory that may not be safe. The overwritten memory results
could be benign, memory corruption, or a segmentation fault. Now the URI
is NULL terminated safely by copying the URI to a new chunk of memory with
the correct size to be NULL terminated.
ASTERISK-25814 #close
Change-Id: I32565496684a5a49c3278fce06474b8c94b37342
Older versions of PJSIP do not have the proto field on the TLS transport
setting structure. This change adds a configure check so even if it is
not present we will still be able to build.
Change-Id: Ibf3f47befb91ed1b8194bf63888baa6fee05aba9
Per RFC3325, the 'From' header is now anonymized on outgoing calls when
caller id presentation is prohibited.
TID = trust_id_outbound
PRO = Set(CALLERID(pres)=prohib)
USR = endpoint/from_user
DOM = endpoint/from_domain
PAI = YES(privacy=off), NO(not sent), PRI(privacy=full) (assumes send_pai=yes)
Conditions |Result
--------------------|----------------------------------------------------
TID PRO USR DOM |PAI FROM
--------------------|----------------------------------------------------
Y Y abc def.ghi |PRI "Anonymous" <sip:abc@def.ghi>
Y Y abc |PRI "Anonymous" <sip:abc@anonymous.invalid>
Y Y def.ghi |PRI "Anonymous" <sip:anonymous@def.ghi>
Y Y |PRI "Anonymous" <sip:anonymous@anonymous.invalid>
Y N abc def.ghi |YES <sip:abc@def.ghi>
Y N abc |YES <sip:abc@<ip_address>>
Y N def.ghi |YES "Caller Name" <sip:<caller_exten>@def.ghi>
Y N |YES "Caller Name" <sip:<caller_exten>@<ip_address>>
N Y abc def.ghi |NO "Anonymous" <sip:abc@def.ghi>
N Y abc |NO "Anonymous" <sip:abc@anonymous.invalid>
N Y def.ghi |NO "Anonymous" <sip:anonymous@def.ghi>
N Y |NO "Anonymous" <sip:anonymous@anonymous.invalid>
N N abc def.ghi |YES <sip:abc@def.ghi>
N N abc |YES <sip:abc@<ip_address>>
N N def.ghi |YES "Caller Name" <sip:<caller_exten>@def.ghi>
N N |YES "Caller Name" <sip:<caller_exten>@<ip_address>>
ASTERISK-25791 #close
Reported-by: Anthony Messina
Change-Id: I2c82a5ca1413c2c00fb62ea95b0ae8e97af54dc9
During the transfer process, some phones (okay it was the Jitsi softphone,
but maybe others are out there) send a "bye" immediately after receiving a
SIP Notify. When a "bye" is received early for some types of transfers the
transferer channel may no longer be available during late stage transfer
processing.
For instance, during an attended transfer involving stasis bridging at one
point the created local channel looks for an associated swap channel in
order to retrieve the stasis application name. If the transferer has hung
up then the local channel will fail to find it. The local channel then has
no way to know which stasis app to enter, so it fails and hangs up as well.
Thus the transfer does not complete as expected.
This patch delays the sending of the initial notify in order to give the
transfer process enough time to gather the necessary data for a successful
transfer.
ASTERISK-25771
Change-Id: I09cfc9a5d6ed4c007bc70625e0972b470393bf16
PJSIP does not ensure that when printing the message body the
buffer will be NULL terminated. This is problematic when searching
for the signal and duration values of the DTMF.
This change ensures the buffer is always NULL terminated.
Change-Id: I52653a1a60c93092d06af31a27408d569cc98968
ast_sip_get_transport_states was returning a container of internal_state
objects instead of ast_sip_transport_state objects. This was causing
transport lookups to fail, most noticably in res_pjsip_nat, which
couldn't find the correct external addresses. This was causing contacts
to go out with internal ip addresses.
ASTERISK-25830 #close
Reported-by: Sean Bright
Change-Id: I1aee6a2fd46c42e8dd0af72498d17de459ac750e
In message.c, if msg_alloc fails to init the string field,
vars may be null, so use a null tolerant cleanup.
In res_pjsip_messaging.c, if msg_data_create fails, mdata
will be null, so use a null tolerant cleanup.
ASTERISK-25323
Change-Id: Ic2d55c2c3750d5616e2a05ea92a19c717507ff56
Previous chan_sip behavior:
Before this patch chan_sip would always strip any quotes from an incoming
reason and pass that value up as the REDIRECTING(reason). For an outgoing
reason value, chan_sip would check the value against known values and
quote any it didn't recognize. Incoming 480 response message reason text
was just assigned to the REDIRECTING(reason).
Previous chan_pjsip behavior:
Before this patch chan_pjsip would always pass the incoming reason value
up as the REDIRECTING(reason). For an outgoing reason value, chan_pjsip
would send the reason value as passed down.
With this patch:
Both channel drivers match incoming reason values with values documented
by REDIRECTING(reason) and values documented by RFC5806 regardless of
whether they are quoted or not. RFC5806 values are mapped to the
equivalent REDIRECTING(reason) documented value and is set in
REDIRECTING(reason). e.g., an incoming RFC5806 'unconditional' value or a
quoted string version ('"unconditional"') is converted to
REDIRECTING(reason)'s 'cfu' value. The user's dialplan only needs to deal
with 'cfu' instead of any of the aliases.
The incoming 480 response reason text supported by chan_sip checks for
known reason values and if not matched then puts quotes around the reason
string and assigns that to REDIRECTING(reason).
Both channel drivers send outgoing known REDIRECTING(reason) values as the
unquoted RFC5806 equivalent. User custom values are either sent as is or
with added quotes if SIP doesn't allow a character within the value as
part of a RFC3261 Section 25.1 token. Note that there are still
limitations on what characters can be put in a custom user value. e.g.,
embedding quotes in the middle of the reason string is silly and just
going to cause you grief.
* Setting a REDIRECTING(reason) value now recognizes RFC5806 aliases.
e.g., Setting REDIRECTING(reason) to 'unconditional' is converted to the
'cfu' value.
* Added missing malloc() NULL return check in res_pjsip_diversion.c
set_redirecting_reason().
* Fixed potential read from a stale pointer in res_pjsip_diversion.c
add_diversion_header(). The reason string needed to be copied into the
tdata memory pool to ensure that the string would always be available.
Otherwise, if the reason string returned by reason_code_to_str() was a
user's reason string then the string could be freed later by another
thread.
Change-Id: Ifba83d23a195a9f64d55b9c681d2e62476b68a87
* Fix double unref of other_party channel in off nominal path.
* This is unlikely to be a real problem. However, for safety,
in handle_incoming_request() keep the datastore ref with the
other_party channel ref until we are finished with the other_party
channel.
Change-Id: I78f22547bf0bb99fb20814ceab75952bd857f821
This backs out item 4 of the 4875e5ac32
commit. Item 4 added the t38_bye_supplement. Unfortunately, the frame
that it puts into the bridge may or may not be processed by the time the
bridged peer is kicked out of the bridge. If it is processed then all is
well. However, if it is not processed then that channel is stuck in fax
mode until it hangs up or maybe if it joins another bridge for T.38
faxing.
ASTERISK-25582
Change-Id: Ib20a03ecadf1bf8a0dcadfadf6c2f2e60919a9f7
There are a few cases where we're emitting notices or warnings
for things that really need neither, like a client retrying to subscribe
to mwi when they're not conifgured for it. They get a 404 so there's no
need for non-debug messages.
Change-Id: I05e38a7ff6c2f2521146f4be6a79731b9864e61f