Codebase list asterisk / e52ddbd
Update upstream source from tag 'upstream/16.15.0_dfsg' Update to upstream version '16.15.0~dfsg' with Debian dir b9b59cc37ea5ea5abc7fb2816076ca4f0af6f82f Bernhard Schmidt 3 years ago
102 changed file(s) with 9838 addition(s) and 1264 deletion(s). Raw diff Collapse all Expand all
0 16.14.0
0 16.15.0
1010 === and the other UPGRADE files for older releases.
1111 ===
1212 ==============================================================================
13
14 ------------------------------------------------------------------------------
15 --- Functionality changes from Asterisk 16.13.0 to Asterisk 16.14.0 ----------
16 ------------------------------------------------------------------------------
17
18 Core
19 ------------------
20 * Added debug logging categories that allow a user to output debug information
21 based on a specified category. This lets the user limit, and filter debug
22 output to data relevant to a particular context, or topic. For instance the
23 following categories are now available for debug logging purposes:
24
25 dtls, dtls_packet, ice, rtcp, rtcp_packet, rtp, rtp_packet, stun, stun_packet
26
27 These debug categories can be enable/disable via an Asterisk CLI command:
28
29 core set debug category <category>[:<sublevel>] [category[:<sublevel] ...]
30 core set debug category off [<category> [<category>] ...]
31
32 If no sub-level is associated all debug statements for a given category are
33 output. If a sub-level is given then only those statements assigned a value
34 at or below the associated sub-level are output.
35
36 STIR/SHAKEN
37 ------------------
38 * STIR/SHAKEN support has been added to Asterisk. Configuration is done in
39 stir_shaken.conf. There is a sample configuration file to help you get
40 started (asterisk/configs/samples/stir_shaken.conf.sample). Once that's
41 set up, you can enable STIR/SHAKEN on any endpoint by setting stir_shaken
42 to yes on the endpoint configuration object. This will add an Identity
43 header on outgoing INVITEs, and check for an Identity header on incoming
44 INVITEs. This option has been added to Alembic as well.
45
46 The information received on an incoming INVITE can be checked using the
47 STIR_SHAKEN dialplan function. There are two variations:
48
49 STIR_SHAKEN(count)
50 STIR_SHAKEN(0, verify_result)
51
52 The first variation will tell you how many STIR/SHAKEN results are on the
53 channel. The second fetches information for a specific result. The first
54 parameter is the index, followed by what information you want to retrieve.
55 The available options are 'verify_result', 'identity', and 'attestation'.
56
57 app_confbridge
58 ------------------
59 * app_confbridge now has the ability to force the estimated bitrate on an SFU
60 bridge. To use it, set a bridge profile's remb_behavior to "force" and
61 set remb_estimated_bitrate to a rate in bits per second. The
62 remb_estimated_bitrate parameter is ignored if remb_behavior is something
63 other than "force".
1364
1465 ------------------------------------------------------------------------------
1566 --- Functionality changes from Asterisk 16.13.0 to Asterisk 16.14.0 ----------
0 2020-10-19 18:12 +0000 Asterisk Development Team <asteriskteam@digium.com>
1
2 * asterisk 16.14.0 Released.
0 2020-11-19 12:34 +0000 Asterisk Development Team <asteriskteam@digium.com>
1
2 * asterisk 16.15.0 Released.
3
4 2020-11-12 12:03 +0000 Asterisk Development Team <asteriskteam@digium.com>
5
6 * asterisk 16.15.0-rc1 Released.
7
8 2020-11-12 05:48 +0000 [3366956139] Asterisk Development Team <asteriskteam@digium.com>
9
10 * Update CHANGES and UPGRADE.txt for 16.15.0
11 2020-11-02 13:53 +0000 [e1fd51cd2c] George Joseph <gjoseph@digium.com>
12
13 * res_pjsip_outbound_registration.c: Use our own scheduler and other stuff
14
15 * Instead of using the pjproject timer heap, we now use our own
16 pjsip_scheduler. This allows us to more easily debug and allows us to
17 see times in "pjsip show/list registrations" as well as being able to
18 see the registrations in "pjsip show scheduled_tasks".
19
20 * Added the last registration time, registration interval, and the next
21 registration time to the CLI output.
22
23 * Removed calls to pjsip_regc_info() except where absolutely necessary.
24 Most of the calls were just to get the server and client URIs for log
25 messages so we now just save them on the client_state object when we
26 create it.
27
28 * Added log messages where needed and updated most of the existong ones
29 to include the registration object name at the start of the message.
30
31 Change-Id: I4534a0fc78c7cb69f23b7b449dda9748c90daca2
32
33 2020-11-02 13:53 +0000 [80f116c156] George Joseph <gjoseph@digium.com>
34
35 * pjsip_scheduler.c: Add type ONESHOT and enhance cli show command
36
37 * Added a ONESHOT type that never reschedules.
38
39 * Added "like" capability to "pjsip show scheduled_tasks" so you can do
40 the following:
41
42 CLI> pjsip show scheduled_tasks like outreg
43 PJSIP Scheduled Tasks:
44
45 Task Name Interval Times Run ...
46 ============================================= ========= ========= ...
47 pjsip/outreg/testtrunk-reg-0-00000074 50.000 oneshot ...
48 pjsip/outreg/voipms-reg-0-00000073 110.000 oneshot ...
49
50 * Fixed incorrect display of "Next Start".
51
52 * Compacted the displays of times in the CLI.
53
54 * Added two new functions (ast_sip_sched_task_get_times2,
55 ast_sip_sched_task_get_times_by_name2) that retrieve the interval,
56 next start time, and next run time in addition to the times already
57 returned by ast_sip_sched_task_get_times().
58
59 Change-Id: Ie718ca9fd30490b8a167bedf6b0b06d619dc52f3
60
61 2020-10-02 14:32 +0000 [728cd55cde] Alexei Gradinari <alex2grad@gmail.com>
62
63 * sched: AST_SCHED_REPLACE_UNREF can lead to use after free of data
64
65 The data can be freed if the old object '_data' is the same object as
66 new 'data'. Because at first the object is unreferenced which can lead
67 to destroying it.
68
69 This could happened in res_pjsip_pubsub when the publication is updated
70 which could lead to segfault in function publish_expire.
71
72 Change-Id: I0164f57c387243510bdbd2f8dcf33377b6c202da
73
74 2020-10-30 11:43 +0000 [ddfb76a864] Alexander Traud <pabstraud@compuserve.com>
75
76 * res_pjsip/config_transport: Load and run without OpenSSL.
77
78 ASTERISK-28933
79 Reported-by: Walter Doekes
80
81 Change-Id: I65eac49e5b0a79261ea80e2b9b38a836886ed59f
82
83 2020-10-30 05:53 +0000 [277aa0ced6] Alexander Traud <pabstraud@compuserve.com>
84
85 * res_stir_shaken: Include OpenSSL headers where used actually.
86
87 This avoids the inclusion of the OpenSSL headers in the public header,
88 which avoids one external library dependency in res_pjsip_stir_shaken.
89
90 Change-Id: I6a07e2d81d2b5442e24e99b8cc733a99f881dcf4
91
92 2020-10-18 13:40 +0000 [5046e1fb06] Dovid Bender <dovid@telecurve.com>
93
94 * func_curl.c: Allow user to set what return codes constitute a failure.
95
96 Currently any response from res_curl where we get an answer from the
97 web server, regardless of what the response is (404, 403 etc.) Asterisk
98 currently treats it as a success. This patch allows you to set which
99 codes should be considered as a failure by Asterisk. If say we set
100 failurecodes=404,403 then when using curl in realtime if a server gives
101 a 404 error Asterisk will try to failover to the next option set in
102 extconfig.conf
103
104 ASTERISK-28825
105
106 Reported by: Dovid Bender
107 Code by: Gobinda Paul
108
109 Change-Id: I94443e508343e0a3e535e51ea6e0562767639987
110
111 2020-10-19 17:21 +0000 [8973fe5cf3] Kevin Harwell <kharwell@digium.com>
112
113 * AST-2020-001 - res_pjsip: Return dialog locked and referenced
114
115 pjproject returns the dialog locked and with a reference. However,
116 in Asterisk the method that handles this decrements the reference
117 and removes the lock prior to returning. This makes it possible,
118 under some circumstances, for another thread to free said dialog
119 before the thread that created it attempts to use it again. Of
120 course when the thread that created it tries to use a freed dialog
121 a crash can occur.
122
123 This patch makes it so Asterisk now returns the newly created
124 dialog both locked, and with an added reference. This allows the
125 caller to de-reference, and unlock the dialog when it is safe to
126 do so.
127
128 In the case of a new SIP Invite the lock, and reference are now
129 held for the entirety of the new invite handling process.
130 Otherwise it's possible for the dialog, or its dependent objects,
131 like the transaction, to disappear. For example if there is a TCP
132 transport error.
133
134 ASTERISK-29057 #close
135
136 Change-Id: I5ef645a47829596f402cf383dc02c629c618969e
137
138 2020-11-02 10:29 +0000 [58aa6a7057] Ben Ford <bford@digium.com>
139
140 * AST-2020-002 - res_pjsip: Stop sending INVITEs after challenge limit.
141
142 If Asterisk sends out an INVITE and receives a challenge with a
143 different nonce value each time, it will continuously send out INVITEs,
144 even if the call is hung up. The endpoint must be configured for
145 outbound authentication for this to occur. A limit has been set on
146 outbound INVITEs so that, once reached, Asterisk will stop sending
147 INVITEs and the transaction will terminate.
148
149 ASTERISK-29013
150
151 Change-Id: I2d001ca745b00ca8aa12030f2240cd72363b46f7
152
153 2020-10-29 10:21 +0000 [e067d5c8fd] Sean Bright <sean.bright@gmail.com>
154
155 * sip_to_pjsip.py: Handle #include globs and other fixes
156
157 * Wildcards in #includes are now properly expanded
158
159 * Implement operators for Section class to allow sorting
160
161 ASTERISK-29142 #close
162
163 Change-Id: I9b9cd95f4cbe5c24506b75d17173c5aa1a83e5df
164
165 2020-10-29 08:35 +0000 [13b56c4be6] Alexander Traud <pabstraud@compuserve.com>
166
167 * Compiler fixes for GCC with -Og
168
169 ASTERISK-29144
170
171 Change-Id: I2a72c072083b4492a223c6f9d73d21f4f424db62
172
173 2020-10-30 03:46 +0000 [334661601a] Alexander Traud <pabstraud@compuserve.com>
174
175 * Compiler fixes for GCC when printf %s is NULL
176
177 ASTERISK-29146
178
179 Change-Id: Ib04bdad87d729f805f5fc620ef9952f58ea96d41
180
181 2020-10-29 08:59 +0000 [92ca48d54c] Alexander Traud <pabstraud@compuserve.com>
182
183 * Compiler fixes for GCC with -Os
184
185 ASTERISK-29145
186
187 Change-Id: I9af705f2b9725c53141aef5d0ff512a1800f073c
188
189 2020-10-23 10:26 +0000 [951ce0524d] Alexander Traud <pabstraud@compuserve.com>
190
191 * chan_sip: On authentication, pick MD5 for sure.
192
193 RFC 8760 added new digest-access-authentication schemes. Testing
194 revealed that chan_sip does not pick MD5 if several schemes are offered
195 by the User Agent Server (UAS). This change does not implement any of
196 the new schemes like SHA-256. This change makes sure, MD5 is picked so
197 UAS with SHA-2 enabled, like the service www.linphone.org/freesip, can
198 still be used. This should have worked since day one because SIP/2.0
199 already envisioned several schemes (see RFC 3261 and its augmented BNF
200 for 'algorithm' which includes 'token' as third alternative; note: if
201 'algorithm' was not present, MD5 is still assumed even in RFC 7616).
202
203 Change-Id: I61ca0b1f74b5ec2b5f3062c2d661cafeaf597fcd
204
205 2020-06-04 09:23 +0000 [f98eed17c1] Walter Doekes <walter+asterisk@wjd.nu>
206
207 * main/say: Work around gcc 9 format-truncation false positive
208
209 Version: gcc (Ubuntu 9.3.0-10ubuntu2) 9.3.0
210 Warning:
211 say.c:2371:24: error: ‘%d’ directive output may be truncated writing
212 between 1 and 11 bytes into a region of size 10
213 [-Werror=format-truncation=]
214 2371 | snprintf(buf, 10, "%d", num);
215 say.c:2371:23: note: directive argument in the range [-2147483648, 9]
216
217 That's not possible though, as the if() starts out checking for (num < 0),
218 making this Warning a false positive.
219
220 (Also replaced some else<TAB>if with else<SP>if while in the vicinity.)
221
222 Change-Id: Ic7a70120188c9aa525a6d70289385bfce878438a
223
224 2020-10-19 15:31 +0000 [92e1de458a] Kevin Harwell <kharwell@digium.com>
225
226 * res_pjsip, res_pjsip_session: initialize local variables
227
228 This patch initializes a couple of local variables to some default values.
229 Interestingly, in the 'pj_status_t dlg_status' case the value not being
230 initialized caused memory to grow, and not be recovered, in the off nominal
231 path (at least on my machine).
232
233 Change-Id: I22ee65e1e1bff8efacea8a167c6c8428898523f7
234
235 2020-10-23 09:55 +0000 [65426f4312] Alexander Traud <pabstraud@compuserve.com>
236
237 * install_prereq: Add GMime 3.0.
238
239 Ubuntu 20.10 does not come with GMime 2.6. Ubuntu 16.04 LTS does not
240 come with GMime 3.0. aptitude ignores any missing package. Therefore,
241 it installs the correct package(s). However, in Ubuntu 18.04 LTS and
242 Ubuntu 20.04 LTS, both versions are installed alongside although only
243 one is really needed.
244
245 Change-Id: Ic58aa9f2e131d94671f286f17dbd61e1ccbabcb7
246
247 2020-10-23 09:49 +0000 [fb721ce82c] Alexander Traud <pabstraud@compuserve.com>
248
249 * BuildSystem: Enable Lua 5.4.
250
251 Note to maintainers: Lua 5.4, Lua 5.3, and Lua 5.2 have not been tested
252 at runtime with pbx_lua. Until then, use the lowest available version
253 of Lua, if you enabled the module pbx_lua at all.
254
255 Change-Id: Ie5270448b11fcb4e2a53d899e4fe7fea793ce7e0
256
257 2020-10-22 11:21 +0000 [e326b133dc] Sean Bright <sean.bright@gmail.com>
258
259 * features.conf.sample: Sample sound files incorrectly quoted
260
261 ASTERISK-29136 #close
262
263 Change-Id: I3186536d65a50014c8da4780c9224919caa81440
264
265 2020-10-19 13:06 +0000 [69356a7895] Asterisk Development Team <asteriskteam@digium.com>
266
267 * Update CHANGES and UPGRADE.txt for 16.14.0
268 2020-10-12 00:45 +0000 [606bd35060] Andrew Siplas <andrew@asiplas.net>
269
270 * logger.conf.sample: add missing comment mark
271
272 Add missing comment mark from stock configuration.
273
274 ASTERISK-29123 #close
275
276 Change-Id: I4f94eb4544166bca8af4c17fd11edee3c6980620
277
278 2020-08-28 16:32 +0000 [e051806e80] Kevin Harwell <kharwell@digium.com>
279
280 * Logging: Add debug logging categories
281
282 Added debug logging categories that allow a user to output debug
283 information based on a specified category. This lets the user limit,
284 and filter debug output to data relevant to a particular context,
285 or topic. For instance the following categories are now available for
286 debug logging purposes:
287
288 dtls, dtls_packet, ice, rtcp, rtcp_packet, rtp, rtp_packet,
289 stun, stun_packet
290
291 These debug categories can be enable/disable via an Asterisk CLI command.
292
293 While this overrides, and outputs debug data, core system debugging is
294 not affected by this patch. Statements still output at their appropriate
295 debug level. As well backwards compatibility has been maintained with
296 past debug groups that could be enabled using the CLI (e.g. rtpdebug,
297 stundebug, etc.).
298
299 ASTERISK-29054 #close
300
301 Change-Id: I6e6cb247bb1f01dbf34750b2cd98e5b5b41a1849
302 (cherry picked from commit 56028426de0692e8e36167251053c91b96e97c41)
303
304 2020-10-05 10:44 +0000 [0b835f2156] Jean Aunis <jean.aunis@prescom.fr>
305
306 * resource_endpoints.c: memory leak when providing a 404 response
307
308 When handling a send_message request to a non-existing endpoint, the response's
309 body is overriden and not properly freed.
310
311 ASTERISK-29108
312
313 Change-Id: Ie1d3d70065f80793445b60f5e4a7eb31b4b9c5c8
314
315 2020-09-30 15:00 +0000 [d0313d8b12] Sean Bright <sean.bright@gmail.com>
316
317 * tcptls.c: Don't close TCP client file descriptors more than once
318
319 ASTERISK-28430 #close
320
321 Change-Id: Ib556b0a0c95cca939e956886214ec8d828d89606
322
323 2020-08-04 14:36 +0000 [681a1624b5] Ben Ford <bford@digium.com>
324
325 * utils.c: NULL terminate ast_base64decode_string.
326
327 With the addition of STIR/SHAKEN, the function ast_base64decode_string
328 was added for convenience since there is a lot of converting done during
329 the STIR/SHAKEN process. This function returned the decoded string for
330 you, but did not NULL terminate it, causing some issues (specifically
331 with MALLOC_DEBUG). Now, the returned string is NULL terminated, and the
332 documentation has been updated to reflect this.
333
334 Change-Id: Icdd7d05b323b0c47ff6ed43492937a03641bdcf5
335
336 2020-07-20 13:05 +0000 [df7c4ed0ed] Ben Ford <bford@digium.com>
337
338 * res_stir_shaken: Fix memory allocation error in curl.c
339
340 Fixed a memory allocation that was not passing in the correct size for
341 the struct in curl.c.
342
343 Change-Id: I5fb92fbbe84b075fa6aefa2423786df80e114c3a
344
345 2020-06-24 11:49 +0000 [21ab0a450b] Ben Ford <bford@digium.com>
346
347 * res_stir_shaken: Add stir_shaken option and general improvements.
348
349 Added a new configuration option for PJSIP endpoints - stir_shaken. If
350 set to yes, then STIR/SHAKEN support will be added to inbound and
351 outbound INVITEs. The default is no. Alembic has been updated to include
352 this option.
353
354 Previously the dialplan function was not trimming the whitespace from
355 the parameters it recieved. Now it does.
356
357 Also added a conditional that, when TEST_FRAMEWORK is enabled, the
358 timestamp in the identity header will be overlooked. This is just for
359 testing, since the testsuite will rely on a SIPp scenario with a preset
360 identity header to trigger the MISMATCH result.
361
362 Change-Id: I43d67f1489b8c1c5729ed3ca8d71e35ddf438df1
363
364 2020-06-02 09:04 +0000 [d979bdf87a] Ben Ford <bford@digium.com>
365
366 * res_stir_shaken: Add outbound INVITE support.
367
368 Integrated STIR/SHAKEN support with outgoing INVITEs. When an INVITE is
369 sent, the caller ID will be checked to see if there is a certificate
370 that corresponds to it. If so, that information will be retrieved and an
371 Identity header will be added to the SIP message. The format is:
372
373 header.payload.signature;info=<public_key_url>alg=ES256;ppt=shaken
374
375 Header, payload, and signature are all BASE64 encoded. The public key
376 URL is retrieved from the certificate. Currently the algorithm and ppt
377 are ES256 and shaken, respectively. This message is signed and can be
378 used for verification on the receiving end.
379
380 Two new configuration options have been added to the certificate object:
381 attestation and origid. The attestation is required and must be A, B, or
382 C. origid is the origination identifier.
383
384 A new utility function has been added as well that takes a string,
385 allocates space, BASE64 encodes it, then returns it, eliminating the
386 need to calculate the size yourself.
387
388 Change-Id: I1f84d6a5839cb2ed152ef4255b380cfc2de662b4
389
390 2020-05-19 14:46 +0000 [746ce16b16] Ben Ford <bford@digium.com>
391
392 * res_stir_shaken: Add inbound INVITE support.
393
394 Integrated STIR/SHAKEN support with incoming INVITES. Upon receiving an
395 INVITE, the Identity header is retrieved, parsing the message to verify
396 the signature. If any of the parsing fails,
397 AST_STIR_SHAKEN_VERIFY_NOT_PRESENT will be added to the channel for this
398 caller ID. If verification itself fails,
399 AST_STIR_SHAKEN_VERIFY_SIGNATURE_FAILED will be added. If anything in
400 the payload does not line up with the SIP signaling,
401 AST_STIR_SHAKEN_VERIFY_MISMATCH will be added. If all of the above steps
402 pass, then AST_STIR_SHAKEN_VERIFY_PASSED will be added, completing the
403 verification process.
404
405 A new config option has been added to the general section for
406 stir_shaken.conf. "signature_timeout" is the amount of time a signature
407 will be considered valid. If an INVITE is received and the amount of
408 time between when it was received and when it was signed is greater than
409 signature_timeout, verification will fail.
410
411 Some changes were also made to signing and verification. There was an
412 error where the whole JSON string was being signed rather than the
413 header combined with the payload. This has been changed to sign the
414 correct thing. Verification has been changed to do this as well, and the
415 unit tests have been updated to reflect these changes.
416
417 A couple of utility functions have also been added. One decodes a BASE64
418 string and returns the decoded string, doing all the length calculations
419 for you. The other retrieves a string value from a header in a rdata
420 object.
421
422 Change-Id: I855f857be3d1c63b64812ac35d9ce0534085b913
423
424 2020-05-13 16:37 +0000 [9d7628829c] Ben Ford <bford@digium.com>
425
426 * res_stir_shaken: Add unit tests for signing and verification.
427
428 Added two unit tests, one for signing and another for verifying.
429 stir_shaken_sign checks to make sure that all the required parameters
430 are passed in and then signs the actual payload. If a signature is
431 produced and a payload returned as a result, the test passes.
432 stir_shaken_verify takes the signature from a signed payload to verify.
433 This unit test also verifies that all the required information is passed
434 in, and then attempts to verify the signature. If verification is
435 successful and a payload is returned, the test passes.
436
437 Change-Id: I9fa43380f861ccf710cd0f6b6c102a517c86ea13
438
439 2020-05-04 16:11 +0000 [035b463c93] Ben Ford <bford@digium.com>
440
441 * res_stir_shaken: Added dialplan function and API call.
442
443 Adds the "STIR_SHAKEN" dialplan function and an API call to add a
444 STIR_SHAKEN verification result to a channel. This information will be
445 held in a datastore on the channel that can later be queried through the
446 "STIR_SHAKEN" dialplan funtion to get information on STIR_SHAKEN results
447 including identity, attestation, and verify_result. Here are some
448 examples:
449
450 STIR_SHAKEN(count)
451 STIR_SHAKEN(0, identity)
452 STIR_SHAKEN(1, attestation)
453 STIR_SHAKEN(2, verify_result)
454
455 Getting the count can be used to iterate through the results and pull
456 information by specifying the index and the field you want to retrieve.
457
458 Change-Id: Ice6d52a3a7d6e4607c9c35b28a1f7c25f5284a82
459
460 2020-05-01 07:29 +0000 [0392a8e620] Joshua C. Colp <jcolp@sangoma.com>
461
462 * res_stir_shaken: Use ast_asprintf for creating file path.
463
464 Change-Id: Ice5d92ecea2f1101c80487484f48ef98be2f1824
465
466 2020-04-15 13:15 +0000 [70af7e1311] Ben Ford <bford@digium.com>
467
468 * res_stir_shaken: Implemented signature verification.
469
470 There are a lot of moving parts in this patch, but the focus of it is on
471 the verification of the signature using a public key located at the
472 public key URL provided in the JSON payload. First, we check the
473 database to see if we have already downloaded the key. If so, check to
474 see if it has expired. If it has, redownload from the URL. If we don't
475 have an entry in the database, just go ahead and download the public
476 key. The expiration is tested each time we download the file. After
477 that, read the public key from the file and use it to verify the
478 signature. All sanity checking is done when the payload is first
479 received, so the verification is complete once this point is reached.
480
481 The XML has also been added since a new config option was added to
482 general (curl_timeout). The maximum amount of time to wait for a
483 download can be configured through this option, with a low value by
484 default.
485
486 Change-Id: I3ba4c63880493bf8c7d17a9cfca1af0e934d1a1c
487
488 2020-04-13 11:47 +0000 [971b125fc0] Alexander Traud <pabstraud@compuserve.com>
489
490 * res_stir_shaken: Do not build without OpenSSL.
491
492 Change-Id: Idba5151a3079f9dcc0076d635422c5df5845114f
493
494 2020-03-26 13:34 +0000 [e9ee9a381b] Ben Ford <bford@digium.com>
495
496 * res_stir_shaken: Implemented signing of JSON payload.
497
498 This change provides functions that take in a JSON payload, verify that
499 the contents contain all the mandatory fields and required values (if
500 any), and signs the payload with the private key. Four fields are added
501 to the payload: x5u, attest, iat, and origid. As of now, these are just
502 placeholder values that will be set to actual values once the logic is
503 implemented for what to do when an actual payload is received, but the
504 functions to add these values have all been implemented and are ready to
505 use. Upon successful signing and the addition of those four values, a
506 ast_stir_shaken_payload is returned, containing other useful information
507 such as the algorithm and signature.
508
509 Change-Id: I74fa41c0640ab2a64a1a80110155bd7062f13393
510
511 2020-03-23 15:00 +0000 [716e51a3f3] Ben Ford <bford@digium.com>
512
513 * res_stir_shaken: Initial commit and reading private key.
514
515 This commit sets up some of the initial framework for the module and
516 adds a way to read the private key from the specified file, which will
517 then be appended to the certificate object. This works fine for now, but
518 eventually some other structure will likely need to be used to store all
519 this information. Similarly, the caller_id_number is specified on the
520 certificate config object, but in the end we will want that information
521 to be tied to the certificate itself and read it from there.
522
523 A method has been added that will retrieve the private key associated
524 with the caller_id_number passed in. Tab completion for certificates and
525 stores has also been added.
526
527 Change-Id: Ic4bc1416fab5d6afe15a8e2d32f7ddd4e023295f
528
529 2020-09-29 13:04 +0000 [7a64868118] Sean Bright <sean.bright@gmail.com>
530
531 * pbx.c: On error, ast_add_extension2_lockopt should always free 'data'
532
533 In the event that the desired extension already exists,
534 ast_add_extension2_lockopt() will free the 'data' it is passed before
535 returning an error, so we should not be freeing it ourselves.
536
537 Additionally, there were two places where ast_add_extension2_lockopt()
538 could return an error without also freeing the 'data' pointer, so we
539 add that.
540
541 ASTERISK-29097 #close
542
543 Change-Id: I904707aae55169feda050a5ed7c6793b53fe6eae
544
545 2020-09-29 19:57 +0000 [9ac933fbba] Sean Bright <sean.bright@gmail.com>
546
547 * app_voicemail.c: Document VMSayName interruption behavior
548
549 ASTERISK-26424 #close
550
551 Change-Id: I797ad0ed302d0b3d2c90543eff5b7207ed08ecf0
552
553 2020-09-24 13:46 +0000 [3b0a53f257] George Joseph <gjoseph@digium.com>
554
555 * app_confbridge/bridge_softmix: Add ability to force estimated bitrate
556
557 app_confbridge now has the ability to set the estimated bitrate on an
558 SFU bridge. To use it, set a bridge profile's remb_behavior to "force"
559 and set remb_estimated_bitrate to a rate in bits per second. The
560 remb_estimated_bitrate parameter is ignored if remb_behavior is something
561 other than "force".
562
563 Change-Id: Idce6464ff014a37ea3b82944452e56cc4d75ab0a
564
565 2020-09-28 07:42 +0000 [374d18cb97] lvl <digium@lvlconsultancy.nl>
566
567 * res_musiconhold: Load all realtime entries, not just the first
568
569 ASTERISK-29099
570
571 Change-Id: I45636679c0fb5a5f59114c8741626631a604e8a6
572
573 2020-09-22 22:39 +0000 [cd793c7c81] Holger Hans Peter Freyther <holger@moiji-mobile.com>
574
575 * res_pjsip_sdp_rtp: Fix accidentally native bridging calls
576
577 Stop advertising RFC2833 support on the rtp_engine when DTMF mode is
578 auto but no tel_event was found inside SDP file.
579
580 On an incoming call create_rtp will be called and when session->dtmf is
581 set to AST_SIP_DTMF_AUTO, the AST_RTP_PROPERTY_DTMF will be set without
582 looking at the SDP file.
583
584 Once get_codecs gets called we move the DTMF mode from RFC2833 to INBAND
585 but continued to advertise RFC2833 support.
586
587 This meant the native_rtp bridge would falsely consider the two channels
588 as compatible. In addition to changing the DTMF mode we now set or
589 remove the AST_RTP_PROPERTY_DTMF.
590
591 The property is checked in ast_rtp_dtmf_compatible and called by
592 native_rtp_bridge_compatible.
593
594 ASTERISK-29051 #close
595
596 Change-Id: I1e0c1e324598a437932c0b7836bcb626aba8e287
597
598 2020-09-23 04:05 +0000 [efcc6d6f6b] Jasper van der Neut <jasper@isotopic.nl>
599
600 * channels: Don't dereference NULL pointer
601
602 Check result of ast_translator_build_path against NULL before dereferencing.
603
604 ASTERISK-29091
605
606 Change-Id: Ia3538ea190bd371f70c9dd49984b021765691b29
607
608 2020-09-24 09:54 +0000 [14b483dd5e] Torrey Searle <tsearle@voxbone.com>
609
610 * res_pjsip_diversion: fix double 181
611
612 Arming response to both AST_SIP_SESSION_BEFORE_REDIRECTING and
613 AST_SIP_SESSION_BEFORE_MEDIA causes 302 to to be handled twice,
614 resulting in to 181 being generated.
615
616 Change-Id: I866e5461564644ffb8a5e12b6f1330b50a7b63ab
617
618 2020-09-24 11:47 +0000 [fccf360fcb] Sean Bright <sean.bright@gmail.com>
619
620 * res_musiconhold: Clarify that playlist mode only supports HTTP(S) URLs
621
622 Change-Id: I41e77a04e4a523f4ed61a7a20b738ffd42be441e
623
624 2020-09-23 15:20 +0000 [cba132a797] Sean Bright <sean.bright@gmail.com>
625
626 * dsp.c: Update calls to ast_format_cmp to check result properly
627
628 ASTERISK-28311 #close
629
630 Change-Id: Ib1ce8fc1a8752751f5bf3615c59245532dfd9aa2
631
632 2020-09-22 05:05 +0000 [baa6e8f112] Joshua C. Colp <jcolp@sangoma.com>
633
634 * res_pjsip_session: Fix stream name memory leak.
635
636 When constructing a stream name based on the media type
637 and position the allocated name was not being freed
638 causing a leak.
639
640 Change-Id: I52510863b24a2f531f0a55b440bb2c81844029de
641
642 2020-09-18 08:09 +0000 [799426cd58] Sean Bright <sean.bright@gmail.com>
643
644 * func_curl.c: Prevent crash when using CURLOPT(httpheader)
645
646 Because we use shared thread-local cURL instances, we need to ensure
647 that the state of the cURL instance is correct before each invocation.
648
649 In the case of custom headers, we were not resetting cURL's internal
650 HTTP header pointer which could result in a crash if subsequent
651 requests do not configure custom headers.
652
653 ASTERISK-29085 #close
654
655 Change-Id: I8b4ab34038156dfba613030a45f10e932d2e992d
656
657 2020-09-18 15:02 +0000 [4a7bbac0ed] Sean Bright <sean.bright@gmail.com>
658
659 * res_musiconhold: Start playlist after initial announcement
660
661 Only track our sample offset if we are playing a non-announcement file,
662 otherwise we will skip that number of samples when we start playing the
663 first MoH file.
664
665 ASTERISK-24329 #close
666
667 Change-Id: Ib6b3c84fcaa1063889ab38ba7e7fc50050a3ccfc
668
669 2020-09-22 05:13 +0000 [e6ed74347c] Joshua C. Colp <jcolp@sangoma.com>
670
671 * res_pjsip_session: Fix session reference leak.
672
673 The ast_sip_dialog_get_session function returns the session
674 with reference count increased. This was not taken into
675 account and was causing sessions to remain around when they
676 should not be.
677
678 ASTERISK-29089
679
680 Change-Id: I430fa721b0a824311a59effec6056e9ec528e3e8
681
682 2020-09-16 08:01 +0000 [f7285140b4] Michal Hajek <michal.hajek@daktela.com>
683
684 * res_stasis.c: Add compare function for bridges moh container
685
686 Sometimes not play MOH on bridge.
687
688 ASTERISK-29081
689 Reported-by: Michal Hajek <michal.hajek@daktela.com>
690
691 Change-Id: I760c73e0c9be1d340303b5d1c18a00c4759e8232
692
693 2020-09-17 11:40 +0000 [fb6f2157e7] George Joseph <gjoseph@digium.com>
694
695 * logger.h: Fix ast_trace to respect scope_level
696
697 ast_trace() was always emitting messages when it's level was set to -1
698 because it was ignoring scope_level.
699
700 Change-Id: I849c8f4f4613899c37f82be0202024e7d117e506
701
702 2020-09-17 13:01 +0000 [8d9633074e] George Joseph <gjoseph@digium.com>
703
704 * bridge_softmix/sfu_topologies_on_join: Ignore topology change failures
705
706 When a channel joins a bridge, we do topology change requests on all
707 existing channels to add the new participant to them. However the
708 announcer channel will return an error because it doesn't support
709 topology in the first place. Unfortunately, there doesn't seem to be a
710 reliable way to tell if the error is expected or not so the error is
711 ignored for all channels. If the request fails on a "real" channel,
712 that channel just won't get the new participant's video.
713
714 Change-Id: Ic95db4683f27d224c1869fe887795d6b9fdea4f0
715
716 2020-09-15 16:16 +0000 [9458577f68] Sean Bright <sean.bright@gmail.com>
717
718 * res_pjsip_session.c: Fix build when TEST_FRAMEWORK is not defined
719
720 Change-Id: Id4852c26e9c412af8e37b5dd3c15da9453ad3276
721
722 2020-08-13 03:34 +0000 [5a12463c07] Torrey Searle <tsearle@voxbone.com>
723
724 * res_pjsip_diversion: implement support for History-Info
725
726 Implemention of History-Info capable of interworking with Diversion
727 Header following RFC7544
728
729 ASTERISK-29027 #close
730
731 Change-Id: I2296369582d4b295c5ea1e60bec391dd1d318fa6
732
733 2020-09-14 13:23 +0000 [c9cc281484] Sean Bright <sean.bright@gmail.com>
734
735 * format_cap: Perform codec lookups by pointer instead of name
736
737 ASTERISK-28416 #close
738
739 Change-Id: I069420875ebdbcaada52d92599a5f7de3cb2cdf4
740
741 2020-09-11 11:09 +0000 [df429c97a1] George Joseph <gjoseph@digium.com>
742
743 * res_pjsip_session: Fix issue with COLP and 491
744
745 The recent 491 changes introduced a check to determine if the active
746 and pending topologies were equal and to suppress the re-invite if they
747 were. When a re-invite is sent for a COLP-only change, the pending
748 topology is NULL so that check doesn't happen and the re-invite is
749 correctly sent. Of course, sending the re-invite sets the pending
750 topology. If a 491 is received, when we resend the re-invite, the
751 pending topology is set and since we didn't request a change to the
752 topology in the first place, pending and active topologies are equal so
753 the topologies-equal check causes the re-invite to be erroneously
754 suppressed.
755
756 This change checks if the topologies are equal before we run the media
757 state resolver (which recreates the pending topology) so that when we
758 do the final topologies-equal check we know if this was a topology
759 change request. If it wasn't a change request, we don't suppress
760 the re-invite even though the topologies are equal.
761
762 ASTERISK-29014
763
764 Change-Id: Iffd7dd0500301156a566119ebde528d1a9573314
765
766 2020-08-20 15:09 +0000 [6abf6f345d] George Joseph <gjoseph@digium.com>
767
768 * debugging: Add enough to choke a mule
769
770 Added to:
771 * bridges/bridge_softmix.c
772 * channels/chan_pjsip.c
773 * include/asterisk/res_pjsip_session.h
774 * main/channel.c
775 * res/res_pjsip_session.c
776
777 There NO functional changes in this commit.
778
779 Change-Id: I06af034d1ff3ea1feb56596fd7bd6d7939dfdcc3
780
781 2020-08-20 11:21 +0000 [65088494cb] George Joseph <gjoseph@digium.com>
782
783 * res_pjsip_session: Handle multi-stream re-invites better
784
785 When both Asterisk and a UA send re-invites at the same time, both
786 send 491 "Transaction in progress" responses to each other and back
787 off a specified amount of time before retrying. When Asterisk
788 prepares to send its re-invite, it sets up the session's pending
789 media state with the new topology it wants, then sends the
790 re-invite. Unfortunately, when it received the re-invite from the
791 UA, it partially processed the media in the re-invite and reset
792 the pending media state before sending the 491 losing the state it
793 set in its own re-invite.
794
795 Asterisk also was not tracking re-invites received while an existing
796 re-invite was queued resulting in sending stale SDP with missing
797 or duplicated streams, or no re-invite at all because we erroneously
798 determined that a re-invite wasn't needed.
799
800 There was also an issue in bridge_softmix where we were using a stream
801 from the wrong topology to determine if a stream was added. This also
802 caused us to erroneously determine that a re-invite wasn't needed.
803
804 Regardless of how the delayed re-invite was triggered, we need to
805 reconcile the topology that was active at the time the delayed
806 request was queued, the pending topology of the queued request,
807 and the topology currently active on the session. To do this we
808 need a topology resolver AND we need to make stream named unique
809 so we can accurately tell what a stream has been added or removed
810 and if we can re-use a slot in the topology.
811
812 Summary of changes:
813
814 * bridge_softmix:
815 * We no longer reset the stream name to "removed" in
816 remove_all_original_streams(). That was causing multiple streams
817 to have the same name and wrecked the checks for duplicate streams.
818
819 * softmix_bridge_stream_sources_update() was checking the old_stream
820 to see if it had the softmix prefix and not considering the stream
821 as "new" if it did. If the stream in that slot has something in it
822 because another re-invite happened, then that slot in old might
823 have a softmix stream but the same stream in new might actually
824 be a new one. Now we check the new_stream's name instead of
825 the old_stream's.
826
827 * stream:
828 * Instead of using plain media type name ("audio", "video", etc) as
829 the default stream name, we now append the stream position to it
830 to make it unique. We need to do this so we can distinguish multiple
831 streams of the same type from each other.
832
833 * When we set a stream's state to REMOVED, we no longer reset its
834 name to "removed" or destroy its metadata. Again, we need to
835 do this so we can distinguish multiple streams of the same
836 type from each other.
837
838 * res_pjsip_session:
839 * Added resolve_refresh_media_states() that takes in 3 media states
840 and creates an up-to-date pending media state that includes the changes
841 that might have happened while a delayed session refresh was in the
842 delayed queue.
843
844 * Added is_media_state_valid() that checks the consistency of
845 a media state and returns a true/false value. A valid state has:
846 * The same number of stream entries as media session entries.
847 Some media session entries can be NULL however.
848 * No duplicate streams.
849 * A valid stream for each non-NULL media session.
850 * A stream that matches each media session's stream_num
851 and media type.
852
853 * Updated handle_incoming_sdp() to set the stream name to include the
854 stream position number in the name to make it unique.
855
856 * Updated the ast_sip_session_delayed_request structure to include both
857 the pending and active media states and updated the associated delay
858 functions to process them.
859
860 * Updated sip_session_refresh() to accept both the pending and active
861 media states that were in effect when the request was originally queued
862 and to pass them on should the request need to be delayed again.
863
864 * Updated sip_session_refresh() to call resolve_refresh_media_states()
865 and substitute its results for the pending state passed in.
866
867 * Updated sip_session_refresh() with additional debugging.
868
869 * Updated session_reinvite_on_rx_request() to simply return PJ_FALSE
870 to pjproject if a transaction is in progress. This stops us from
871 creating a partial pending media state that would be invalid later on.
872
873 * Updated reschedule_reinvite() to clone both the current pending and
874 active media states and pass them to delay_request() so the resolver
875 can tell what the original intention of the re-invite was.
876
877 * Added a large unit test for the resolver.
878
879 ASTERISK-29014
880
881 Change-Id: Id3440972943c611a15f652c6c569fa0e4536bfcb
882
883 2020-08-30 15:42 +0000 [af339d0adb] Sungtae Kim <pchero21@gmail.com>
884
885 * res_stasis.c: Added video_single option for bridge creation
886
887 Currently, it was not possible to create bridge with video_mode single.
888 This made hard to put the bridge in a vidoe_single mode.
889 So, added video_single option for Bridge creation using the ARI.
890 This allows create a bridge with video_mode single.
891
892 ASTERISK-29055
893
894 Change-Id: I43e720e5c83fc75fafe10fe22808ae7f055da2ae
895
896 2020-08-31 07:21 +0000 [a353b76c75] Sungtae Kim <pchero21@gmail.com>
897
898 * realtime: Increased reg_server character size
899
900 Currently, the ps_contacts table's reg_server column in realtime database type is varchar(20).
901 This is fine for normal cases, but if the hostname is longer than 20, it returns error and then
902 failed to register the contact address of the peer.
903
904 Normally, 20 characters limitation for the hostname is fine, but with the cloud env.
905 So, increased the size to 255.
906
907 ASTERISK-29056
908
909 Change-Id: Iac52c8c35030303cfa551bb39f410b33bffc507d
910
911 2020-08-31 11:14 +0000 [e7620d034a] Ben Ford <bford@digium.com>
912
913 * Bridging: Use a ref to bridge_channel's channel to prevent crash.
914
915 There's a race condition with bridging where a bridge can be torn down
916 causing the bridge_channel's ast_channel to become NULL when it's still
917 needed. This particular case happened with attended transfers, but the
918 crash occurred when trying to publish a stasis message. Now, the
919 bridge_channel is locked, a ref to the ast_channel is obtained, and that
920 ref is passed down the chain.
921
922 Change-Id: Ic48715c0c041615d17d286790ae3e8c61bb28814
3923
4924 2020-09-09 15:01 +0000 Asterisk Development Team <asteriskteam@digium.com>
5925
564564 "$(ASTDATADIR)/firmware/iax" "$(ASTDATADIR)/images" "$(ASTDATADIR)/keys" \
565565 "$(ASTDATADIR)/phoneprov" "$(ASTDATADIR)/rest-api" "$(ASTDATADIR)/static-http" \
566566 "$(ASTDATADIR)/sounds" "$(ASTDATADIR)/moh" "$(ASTMANDIR)/man8" "$(AGI_DIR)" "$(ASTDBDIR)" \
567 "$(ASTDATADIR)/third-party"
567 "$(ASTDATADIR)/third-party" "${ASTDATADIR}/keys/stir_shaken"
568568
569569 installdirs:
570570 @for i in $(INSTALLDIRS); do \
1616 === suggested replacement functionality.
1717 ===
1818 ===========================================================
19
20 ------------------------------------------------------------------------------
21 --- Functionality changes from Asterisk 16.13.0 to Asterisk 16.14.0 ----------
22 ------------------------------------------------------------------------------
23
24 res_stir_shaken
25 ------------------
26 * A new directory has been added under the default (e.g., /var/lib/asterisk) -
27 inside the 'keys' directory - named 'stir_shaken'. This directory will
28 hold public keys that have been downloaded for STIR/SHAKEN verification.
1929
2030 ------------------------------------------------------------------------------
2131 --- Functionality changes from Asterisk 16.9.0 to Asterisk 16.10.0 -----------
584584 unsigned int i;
585585 ASN1BOOL aligned=TRUE;
586586 int stat;
587 Q931InformationElement *ie;
587 Q931InformationElement *ie=NULL;
588588 /* OOCTXT *pctxt = &gH323ep.msgctxt; */
589589 if(q931Msg ==NULL)
590590 {
17291729 ast_brige_set_remb_behavior(conference->bridge, AST_BRIDGE_VIDEO_SFU_REMB_LOWEST_ALL);
17301730 } else if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST_ALL)) {
17311731 ast_brige_set_remb_behavior(conference->bridge, AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST_ALL);
1732 } else if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_REMB_BEHAVIOR_FORCE)) {
1733 ast_brige_set_remb_behavior(conference->bridge, AST_BRIDGE_VIDEO_SFU_REMB_FORCE);
1734 ast_bridge_set_remb_estimated_bitrate(conference->bridge, conference->b_profile.remb_estimated_bitrate);
17321735 }
17331736 }
17341737
395395 {
396396 struct directory_item **block, *item;
397397 int i, limit, res = 0;
398 char buf[9];
398 char buf[7+12]; /* INT_MIN has a length of 12 chars */
399399
400400 /* option p(n): cellphone pause option */
401401 select_item_pause(chan, flags, opts);
379379 <description>
380380 <para>This application will say the recorded name of the voicemail user specified as the
381381 argument to this application. If no context is provided, <literal>default</literal> is assumed.</para>
382 <para>Similar to the Background() application, playback of the recorded
383 name can be interrupted by entering an extension, which will be searched
384 for in the current context.</para>
382385 </description>
383386 </application>
384387 <function name="MAILBOX_EXISTS" language="en_US">
1129911302 int skipuser, int max_logins, int silent)
1130011303 {
1130111304 int useadsi = 0, valid = 0, logretries = 0;
11302 char password[AST_MAX_EXTENSION], *passptr;
11305 char password[AST_MAX_EXTENSION], *passptr = NULL;
1130311306 struct ast_vm_user vmus, *vmu = NULL;
1130411307
1130511308 /* If ADSI is supported, setup login screen */
532532 <para>The highest estimated maximum bitrate of all receivers in the bridge
533533 is taken and sent to each sender.</para>
534534 </enum>
535 <enum name="force">
536 <para>The bitrate configured in <literal>remb_estimated_bitrate</literal>
537 is sent to each sender.</para>
538 </enum>
535539 </enumlist>
536540 </description>
541 <see-also><ref type="configOption">remb_estimated_bitrate</ref></see-also>
542 </configOption>
543 <configOption name="remb_estimated_bitrate">
544 <synopsis>Sets the estimated bitrate sent to each participant in REMB reports</synopsis>
545 <description><para>
546 When <literal>remb_behavior</literal> is set to <literal>force</literal>,
547 this options sets the estimated bitrate (in bits per second) sent to each participant
548 in REMB reports.
549 </para></description>
550 <see-also><ref type="configOption">remb_behavior</ref></see-also>
537551 </configOption>
538552 <configOption name="enable_events" default="no">
539553 <synopsis>Enables events for this bridge</synopsis>
21582172 BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST |
21592173 BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE_ALL |
21602174 BRIDGE_OPT_REMB_BEHAVIOR_LOWEST_ALL |
2161 BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST_ALL);
2175 BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST_ALL |
2176 BRIDGE_OPT_REMB_BEHAVIOR_FORCE
2177 );
21622178
21632179 if (!strcasecmp(var->value, "average")) {
21642180 ast_set_flag(b_profile, BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE);
21722188 ast_set_flag(b_profile, BRIDGE_OPT_REMB_BEHAVIOR_LOWEST_ALL);
21732189 } else if (!strcasecmp(var->value, "highest_all")) {
21742190 ast_set_flag(b_profile, BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST_ALL);
2191 } else if (!strcasecmp(var->value, "force")) {
2192 ast_set_flag(b_profile, BRIDGE_OPT_REMB_BEHAVIOR_FORCE);
21752193 } else {
21762194 return -1;
21772195 }
24182436 aco_option_register(&cfg_info, "video_update_discard", ACO_EXACT, bridge_types, "2000", OPT_UINT_T, 0, FLDSET(struct bridge_profile, video_update_discard));
24192437 aco_option_register(&cfg_info, "remb_send_interval", ACO_EXACT, bridge_types, "0", OPT_UINT_T, 0, FLDSET(struct bridge_profile, remb_send_interval));
24202438 aco_option_register_custom(&cfg_info, "remb_behavior", ACO_EXACT, bridge_types, "average", remb_behavior_handler, 0);
2439 aco_option_register(&cfg_info, "remb_estimated_bitrate", ACO_EXACT, bridge_types, "0", OPT_UINT_T, 0, FLDSET(struct bridge_profile, remb_estimated_bitrate));
24212440 aco_option_register(&cfg_info, "enable_events", ACO_EXACT, bridge_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), BRIDGE_OPT_ENABLE_EVENTS);
24222441 /* This option should only be used with the CONFBRIDGE dialplan function */
24232442 aco_option_register_custom(&cfg_info, "template", ACO_EXACT, bridge_types, NULL, bridge_template_handler, 0);
8686 BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE_ALL = (1 << 12), /*!< The average of all REMB reports in the entire bridge is sent to each sender */
8787 BRIDGE_OPT_REMB_BEHAVIOR_LOWEST_ALL = (1 << 13), /*!< The lowest estimated maximum bitrate from all receivers is sent to each sender */
8888 BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST_ALL = (1 << 14), /*!< The highest estimated maximum bitrate from all receivers is sent to each sender */
89 BRIDGE_OPT_REMB_BEHAVIOR_FORCE = (1 << 15), /*!< Force the REMB estimated bitrate to that specifiec in remb_estimated_bitrate */
8990 };
9091
9192 enum conf_menu_action_id {
234235 char regcontext[AST_MAX_CONTEXT];
235236 unsigned int video_update_discard; /*!< Amount of time after sending a video update request that subsequent requests should be discarded */
236237 unsigned int remb_send_interval; /*!< Interval at which a combined REMB frame is sent to video sources */
238 unsigned int remb_estimated_bitrate; /*!< Bitrate sent when BRIDGE_OPT_REMB_BEHAVIOR_FORCE is set */
237239 };
238240
239241 /*! \brief The structure that represents a conference bridge */
+0
-76
asterisk-16.14.0-summary.html less more
0 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><title>Release Summary - asterisk-16.14.0</title><h1 align="center"><a name="top">Release Summary</a></h1><h3 align="center">asterisk-16.14.0</h3><h3 align="center">Date: 2020-10-19</h3><h3 align="center">&lt;asteriskteam@digium.com&gt;</h3><hr><h2 align="center">Table of Contents</h2><ol>
1 <li><a href="#summary">Summary</a></li>
2 <li><a href="#contributors">Contributors</a></li>
3 <li><a href="#closed_issues">Closed Issues</a></li>
4 <li><a href="#commits">Other Changes</a></li>
5 <li><a href="#diffstat">Diffstat</a></li>
6 </ol><hr><a name="summary"><h2 align="center">Summary</h2></a><center><a href="#top">[Back to Top]</a></center><p>This release is a point release of an existing major version. The changes included were made to address problems that have been identified in this release series, or are minor, backwards compatible new features or improvements. Users should be able to safely upgrade to this version if this release series is already in use. Users considering upgrading from a previous version are strongly encouraged to review the UPGRADE.txt document as well as the CHANGES document for information about upgrading to this release series.</p><p>The data in this summary reflects changes that have been made since the previous release, asterisk-16.13.0.</p><hr><a name="contributors"><h2 align="center">Contributors</h2></a><center><a href="#top">[Back to Top]</a></center><p>This table lists the people who have submitted code, those that have tested patches, as well as those that reported issues on the issue tracker that were resolved in this release. For coders, the number is how many of their patches (of any size) were committed into this release. For testers, the number is the number of times their name was listed as assisting with testing a patch. Finally, for reporters, the number is the number of issues that they reported that were affected by commits that went into this release.</p><table width="100%" border="0">
7 <tr><th width="33%">Coders</th><th width="33%">Testers</th><th width="33%">Reporters</th></tr>
8 <tr valign="top"><td width="33%">4 Sean Bright <sean.bright@gmail.com><br/>4 George Joseph <gjoseph@digium.com><br/>3 Joshua C. Colp <jcolp@sangoma.com><br/>2 Kevin Harwell <kharwell@digium.com><br/>2 Asterisk Development Team <asteriskteam@digium.com><br/>2 Alexander Traud <pabstraud@compuserve.com><br/>1 Kfir Itzhak <mastertheknife@gmail.com><br/>1 Evandro César Arruda <ecarruda@gmail.com><br/>1 Torrey Searle <tsearle@voxbone.com><br/>1 Patrick Verzele <patrick@verzele.be><br/>1 Nickolay Shmyrev <nshmyrev@alphacephei.com><br/>1 Andrew Siplas <andrew@asiplas.net><br/></td><td width="33%"><td width="33%">1 Nickolay V. Shmyrev <nshmyrev@alphacephei.com><br/>1 Ramarajan <pramarajan@sangoma.com><br/>1 Ove Aursand <oveaurs@gmail.com><br/>1 Evandro César Arruda <ecarruda@gmail.com><br/>1 Thomas Johnson <tjohnson@microautomation.com><br/>1 Misha Vodsedalek <vmisha@seznam.cz><br/>1 Andrew Siplas <andrew@asiplas.net><br/>1 Torrey Searle <tsearle@gmail.com><br/>1 Kfir Itzhak <mastertheknife@gmail.com><br/>1 Joshua C. Colp <jcolp@digium.com><br/>1 Karsten Wemheuer <kwe-digium@iptam.com><br/>1 Joseph Ades <josephades1@gmail.com><br/>1 Leandro Dardini <ldardini@gmail.com><br/></td></tr>
9 </table><hr><a name="closed_issues"><h2 align="center">Closed Issues</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a list of all issues from the issue tracker that were closed by changes that went into this release.</p><h3>Bug</h3><h4>Category: Applications/app_queue</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-25665">ASTERISK-25665</a>: Duplicate logging in queue log for EXITEMPTY events<br/>Reported by: Ove Aursand<ul>
10 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=ae718c975af775511295093776f0c0a3d83b521d">[ae718c975a]</a> Kfir Itzhak -- app_queue: Fix leave-empty not recording a call as abandoned</li>
11 </ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29043">ASTERISK-29043</a>: app_queue: Leave empty sometimes not recorded as abandoned<br/>Reported by: Kfir Itzhak<ul>
12 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=ae718c975af775511295093776f0c0a3d83b521d">[ae718c975a]</a> Kfir Itzhak -- app_queue: Fix leave-empty not recording a call as abandoned</li>
13 </ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29034">ASTERISK-29034</a>: Lastpause of realtime members is reseting<br/>Reported by: Evandro César Arruda<ul>
14 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=aa93107444fc41c09c7a34620fdd7b86b90eb57a">[aa93107444]</a> Evandro César Arruda -- app_queue: Member lastpause time reseting</li>
15 </ul><br><h4>Category: Applications/app_voicemail</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29029">ASTERISK-29029</a>: Voicemail "pollmailboxes"-option not working, bug in function handle_subscribe<br/>Reported by: Karsten Wemheuer<ul>
16 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=53a88df076023510d49d8f0818e24a8ec5d5dece">[53a88df076]</a> Sean Bright -- app_voicemail: Fix pollmailboxes</li>
17 </ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-27273">ASTERISK-27273</a>: app_voicemail: When a voicemail is marked as "Urgent", it is not sent by email/processed by the mailcmd command<br/>Reported by: Leandro Dardini<ul>
18 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=788b60d935cb910f7417611416c54be3c8d49517">[788b60d935]</a> Sean Bright -- app_voicemail: Process urgent messages with mailcmd</li>
19 </ul><br><h4>Category: Channels/chan_pjsip</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-28878">ASTERISK-28878</a>: chan_pjsip: PJSIP_MEDIA_OFFER Broken asterisk 16<br/>Reported by: Joseph Ades<ul>
20 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=17258e0cdf2a0b8c3747a63b2fe469a3e1b3544b">[17258e0cdf]</a> Kevin Harwell -- chan_pjsip: disallow PJSIP_SEND_SESSION_REFRESH pre-answer execution</li>
21 </ul><br><h4>Category: Configs/Samples</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29123">ASTERISK-29123</a>: logger.conf.sample missing comment mark on line 115<br/>Reported by: Andrew Siplas<ul>
22 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=8ac6ae48ceb1c1c9f6cf8b36c58a2b8c1ab7a2de">[8ac6ae48ce]</a> Andrew Siplas -- logger.conf.sample: add missing comment mark</li>
23 </ul><br><h4>Category: PBX/General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29046">ASTERISK-29046</a>: pbx: Deadlock when doing a reload, while simultaneously doing an ExtensionState on a pattern match hint that ends up adding an extension<br/>Reported by: Ramarajan<ul>
24 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=04527176458b0183d440891ec31770abedece71c">[0452717645]</a> Joshua C. Colp -- pbx: Fix hints deadlock between reload and ExtensionState.</li>
25 </ul><br><h4>Category: Resources/res_parking</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29042">ASTERISK-29042</a>: res_parking: Parker UUID is no longer copied<br/>Reported by: Misha Vodsedalek<ul>
26 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=075a7ee4a6b29afbfc9190b4abbfdd1983a75706">[075a7ee4a6]</a> Joshua C. Colp -- parking: Copy parker UUID as well.</li>
27 </ul><br><h4>Category: Resources/res_pjsip_diversion</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29001">ASTERISK-29001</a>: chan_pjsip does not process or forward 181 responses<br/>Reported by: Torrey Searle<ul>
28 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=75756ab850891318aa76607fb612f49879ce2b55">[75756ab850]</a> Torrey Searle -- res_pjsip_diversion: handle 181</li>
29 </ul><br><h4>Category: Resources/res_pjsip_session</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29033">ASTERISK-29033</a>: res_pjsip_session: Aggressively terminates session on failed re-INVITE<br/>Reported by: Joshua C. Colp<ul>
30 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=eaed23b340ab4dd15b25319878200ba2832c2660">[eaed23b340]</a> Joshua C. Colp -- res_pjsip_session: Don't aggressively terminate on failed re-INVITE.</li>
31 </ul><br><h4>Category: Resources/res_rtp_asterisk</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-28974">ASTERISK-28974</a>: res_rtp_asterisk: T.140 messages have appended RTP string to each message block.<br/>Reported by: Thomas Johnson<ul>
32 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=32b593c3251b5c2ae5a62814ae082915138f2606">[32b593c325]</a> Sean Bright -- bridge_channel: Ensure text messages are zero terminated</li>
33 </ul><br><h4>Category: Resources/res_speech</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29040">ASTERISK-29040</a>: res_speech: Assertion on format<br/>Reported by: Nickolay V. Shmyrev<ul>
34 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=444c6061617d32a4b744bebe3e9d67ccaedfeb9c">[444c606161]</a> Nickolay Shmyrev -- res_speech: Bump reference on format object</li>
35 </ul><br><hr><a name="commits"><h2 align="center">Commits Not Associated with an Issue</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a list of all changes that went into this release that did not reference a JIRA issue.</p><table width="100%" border="1">
36 <tr><th>Revision</th><th>Author</th><th>Summary</th></tr>
37 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=c1a5bbe7bf084721b2e2e52cdfc68513fda609ab">c1a5bbe7bf</a></td><td>Asterisk Development Team</td><td>Update for 16.14.0-rc1</td></tr>
38 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=bd0724c7ed8a7c3bec9ec4320780c50a48e13590">bd0724c7ed</a></td><td>Asterisk Development Team</td><td>Update CHANGES and UPGRADE.txt for 16.14.0</td></tr>
39 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=ab34417f7ea9cd818a7b801b41da0c534b71c988">ab34417f7e</a></td><td>Patrick Verzele</td><td>res_pjsip_session: Deferred re-INVITE without SDP send a=sendrecv instead of a=sendonly</td></tr>
40 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=7b441505dcdb0b4d7a030adea3eae628e11ab80e">7b441505dc</a></td><td>Kevin Harwell</td><td>conversions: Add string to signed integer conversion functions</td></tr>
41 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a14c5301e738c442013511c2e904c15891e1a023">a14c5301e7</a></td><td>George Joseph</td><td>ast_coredumper: Fix issues with naming</td></tr>
42 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=afc5cf8d677686fb567464e2ddb21f639a95953c">afc5cf8d67</a></td><td>Alexander Traud</td><td>samples: Fix keep_alive_interval default in pjsip.conf.</td></tr>
43 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=0fa20c8df6cccabfbb4724777ae2b4fd725836f8">0fa20c8df6</a></td><td>Alexander Traud</td><td>sip_nat_settings: Update script for latest Linux.</td></tr>
44 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=d28a44c33d1e72b91b78ba56282bf56a0730a277">d28a44c33d</a></td><td>George Joseph</td><td>logger.c: Added a new log formatter called "plain"</td></tr>
45 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=55358b127692aadbecfb400bc2665aeb871f043b">55358b1276</a></td><td>Sean Bright</td><td>res_musiconhold.c: Use ast_file_read_dir to scan MoH directory</td></tr>
46 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=b9ba0f8da8a37d065a07ad060ebbb94e324f281e">b9ba0f8da8</a></td><td>George Joseph</td><td>scope_trace: Added debug messages and added additional macros</td></tr>
47 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=377caaed3cf2fd2d2aea9f2c18eb6f87a612f5ff">377caaed3c</a></td><td>George Joseph</td><td>stream.c: Added 2 more debugging utils and added pos to stream string</td></tr>
48 </table><hr><a name="diffstat"><h2 align="center">Diffstat Results</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a summary of the changes to the source code that went into this release that was generated using the diffstat utility.</p><pre>asterisk-16.13.0-summary.html | 77 ----------
49 asterisk-16.13.0-summary.txt | 248 ----------------------------------
50 b/.version | 2
51 b/CHANGES | 22 +++
52 b/ChangeLog | 229 ++++++++++++++++++++++++++++++-
53 b/apps/app_queue.c | 3
54 b/apps/app_voicemail.c | 30 +---
55 b/asterisk-16.14.0-rc1-summary.html | 78 ++++++++++
56 b/asterisk-16.14.0-rc1-summary.txt | 242 +++++++++++++++++++++++++++++++++
57 b/channels/pjsip/dialplan_functions.c | 5
58 b/configs/samples/logger.conf.sample | 4
59 b/configs/samples/pjsip.conf.sample | 10 -
60 b/contrib/scripts/ast_coredumper | 4
61 b/contrib/scripts/sip_nat_settings | 19 --
62 b/include/asterisk/conversions.h | 54 +++++++
63 b/include/asterisk/frame.h | 5
64 b/include/asterisk/logger.h | 86 ++++++++++-
65 b/include/asterisk/stream.h | 26 +++
66 b/main/bridge_channel.c | 37 ++++-
67 b/main/conversions.c | 51 ++++++
68 b/main/logger.c | 52 +++++++
69 b/main/stream.c | 27 +--
70 b/res/res_musiconhold.c | 131 +++++++++--------
71 b/res/res_pjsip_diversion.c | 6
72 b/res/res_pjsip_session.c | 13 +
73 b/res/res_speech.c | 7
74 b/tests/test_conversions.c | 146 +++++++++++++++++++-
75 27 files changed, 1147 insertions(+), 467 deletions(-)</pre><br></html>
+0
-248
asterisk-16.14.0-summary.txt less more
0 Release Summary
1
2 asterisk-16.14.0
3
4 Date: 2020-10-19
5
6 <asteriskteam@digium.com>
7
8 ----------------------------------------------------------------------
9
10 Table of Contents
11
12 1. Summary
13 2. Contributors
14 3. Closed Issues
15 4. Other Changes
16 5. Diffstat
17
18 ----------------------------------------------------------------------
19
20 Summary
21
22 [Back to Top]
23
24 This release is a point release of an existing major version. The changes
25 included were made to address problems that have been identified in this
26 release series, or are minor, backwards compatible new features or
27 improvements. Users should be able to safely upgrade to this version if
28 this release series is already in use. Users considering upgrading from a
29 previous version are strongly encouraged to review the UPGRADE.txt
30 document as well as the CHANGES document for information about upgrading
31 to this release series.
32
33 The data in this summary reflects changes that have been made since the
34 previous release, asterisk-16.13.0.
35
36 ----------------------------------------------------------------------
37
38 Contributors
39
40 [Back to Top]
41
42 This table lists the people who have submitted code, those that have
43 tested patches, as well as those that reported issues on the issue tracker
44 that were resolved in this release. For coders, the number is how many of
45 their patches (of any size) were committed into this release. For testers,
46 the number is the number of times their name was listed as assisting with
47 testing a patch. Finally, for reporters, the number is the number of
48 issues that they reported that were affected by commits that went into
49 this release.
50
51 Coders Testers Reporters
52 4 Sean Bright 1 Nickolay V. Shmyrev
53 4 George Joseph 1 Ramarajan
54 3 Joshua C. Colp 1 Ove Aursand
55 2 Kevin Harwell 1 Evandro César Arruda
56 2 Asterisk Development Team 1 Thomas Johnson
57 2 Alexander Traud 1 Misha Vodsedalek
58 1 Kfir Itzhak 1 Andrew Siplas
59 1 Evandro César Arruda 1 Torrey Searle
60 1 Torrey Searle 1 Kfir Itzhak
61 1 Patrick Verzele 1 Joshua C. Colp
62 1 Nickolay Shmyrev 1 Karsten Wemheuer
63 1 Andrew Siplas 1 Joseph Ades
64 1 Leandro Dardini
65
66 ----------------------------------------------------------------------
67
68 Closed Issues
69
70 [Back to Top]
71
72 This is a list of all issues from the issue tracker that were closed by
73 changes that went into this release.
74
75 Bug
76
77 Category: Applications/app_queue
78
79 ASTERISK-25665: Duplicate logging in queue log for EXITEMPTY events
80 Reported by: Ove Aursand
81 * [ae718c975a] Kfir Itzhak -- app_queue: Fix leave-empty not recording a
82 call as abandoned
83 ASTERISK-29043: app_queue: Leave empty sometimes not recorded as abandoned
84 Reported by: Kfir Itzhak
85 * [ae718c975a] Kfir Itzhak -- app_queue: Fix leave-empty not recording a
86 call as abandoned
87 ASTERISK-29034: Lastpause of realtime members is reseting
88 Reported by: Evandro César Arruda
89 * [aa93107444] Evandro César Arruda -- app_queue: Member lastpause time
90 reseting
91
92 Category: Applications/app_voicemail
93
94 ASTERISK-29029: Voicemail "pollmailboxes"-option not working, bug in
95 function handle_subscribe
96 Reported by: Karsten Wemheuer
97 * [53a88df076] Sean Bright -- app_voicemail: Fix pollmailboxes
98 ASTERISK-27273: app_voicemail: When a voicemail is marked as "Urgent", it
99 is not sent by email/processed by the mailcmd command
100 Reported by: Leandro Dardini
101 * [788b60d935] Sean Bright -- app_voicemail: Process urgent messages
102 with mailcmd
103
104 Category: Channels/chan_pjsip
105
106 ASTERISK-28878: chan_pjsip: PJSIP_MEDIA_OFFER Broken asterisk 16
107 Reported by: Joseph Ades
108 * [17258e0cdf] Kevin Harwell -- chan_pjsip: disallow
109 PJSIP_SEND_SESSION_REFRESH pre-answer execution
110
111 Category: Configs/Samples
112
113 ASTERISK-29123: logger.conf.sample missing comment mark on line 115
114 Reported by: Andrew Siplas
115 * [8ac6ae48ce] Andrew Siplas -- logger.conf.sample: add missing comment
116 mark
117
118 Category: PBX/General
119
120 ASTERISK-29046: pbx: Deadlock when doing a reload, while simultaneously
121 doing an ExtensionState on a pattern match hint that ends up adding an
122 extension
123 Reported by: Ramarajan
124 * [0452717645] Joshua C. Colp -- pbx: Fix hints deadlock between reload
125 and ExtensionState.
126
127 Category: Resources/res_parking
128
129 ASTERISK-29042: res_parking: Parker UUID is no longer copied
130 Reported by: Misha Vodsedalek
131 * [075a7ee4a6] Joshua C. Colp -- parking: Copy parker UUID as well.
132
133 Category: Resources/res_pjsip_diversion
134
135 ASTERISK-29001: chan_pjsip does not process or forward 181 responses
136 Reported by: Torrey Searle
137 * [75756ab850] Torrey Searle -- res_pjsip_diversion: handle 181
138
139 Category: Resources/res_pjsip_session
140
141 ASTERISK-29033: res_pjsip_session: Aggressively terminates session on
142 failed re-INVITE
143 Reported by: Joshua C. Colp
144 * [eaed23b340] Joshua C. Colp -- res_pjsip_session: Don't aggressively
145 terminate on failed re-INVITE.
146
147 Category: Resources/res_rtp_asterisk
148
149 ASTERISK-28974: res_rtp_asterisk: T.140 messages have appended RTP string
150 to each message block.
151 Reported by: Thomas Johnson
152 * [32b593c325] Sean Bright -- bridge_channel: Ensure text messages are
153 zero terminated
154
155 Category: Resources/res_speech
156
157 ASTERISK-29040: res_speech: Assertion on format
158 Reported by: Nickolay V. Shmyrev
159 * [444c606161] Nickolay Shmyrev -- res_speech: Bump reference on format
160 object
161
162 ----------------------------------------------------------------------
163
164 Commits Not Associated with an Issue
165
166 [Back to Top]
167
168 This is a list of all changes that went into this release that did not
169 reference a JIRA issue.
170
171 +------------------------------------------------------------------------+
172 | Revision | Author | Summary |
173 |------------+----------------------+------------------------------------|
174 | c1a5bbe7bf | Asterisk Development | Update for 16.14.0-rc1 |
175 | | Team | |
176 |------------+----------------------+------------------------------------|
177 | bd0724c7ed | Asterisk Development | Update CHANGES and UPGRADE.txt for |
178 | | Team | 16.14.0 |
179 |------------+----------------------+------------------------------------|
180 | | | res_pjsip_session: Deferred |
181 | ab34417f7e | Patrick Verzele | re-INVITE without SDP send |
182 | | | a=sendrecv instead of a=sendonly |
183 |------------+----------------------+------------------------------------|
184 | 7b441505dc | Kevin Harwell | conversions: Add string to signed |
185 | | | integer conversion functions |
186 |------------+----------------------+------------------------------------|
187 | a14c5301e7 | George Joseph | ast_coredumper: Fix issues with |
188 | | | naming |
189 |------------+----------------------+------------------------------------|
190 | afc5cf8d67 | Alexander Traud | samples: Fix keep_alive_interval |
191 | | | default in pjsip.conf. |
192 |------------+----------------------+------------------------------------|
193 | 0fa20c8df6 | Alexander Traud | sip_nat_settings: Update script |
194 | | | for latest Linux. |
195 |------------+----------------------+------------------------------------|
196 | d28a44c33d | George Joseph | logger.c: Added a new log |
197 | | | formatter called "plain" |
198 |------------+----------------------+------------------------------------|
199 | | | res_musiconhold.c: Use |
200 | 55358b1276 | Sean Bright | ast_file_read_dir to scan MoH |
201 | | | directory |
202 |------------+----------------------+------------------------------------|
203 | b9ba0f8da8 | George Joseph | scope_trace: Added debug messages |
204 | | | and added additional macros |
205 |------------+----------------------+------------------------------------|
206 | | | stream.c: Added 2 more debugging |
207 | 377caaed3c | George Joseph | utils and added pos to stream |
208 | | | string |
209 +------------------------------------------------------------------------+
210
211 ----------------------------------------------------------------------
212
213 Diffstat Results
214
215 [Back to Top]
216
217 This is a summary of the changes to the source code that went into this
218 release that was generated using the diffstat utility.
219
220 asterisk-16.13.0-summary.html | 77 ----------
221 asterisk-16.13.0-summary.txt | 248 ----------------------------------
222 b/.version | 2
223 b/CHANGES | 22 +++
224 b/ChangeLog | 229 ++++++++++++++++++++++++++++++-
225 b/apps/app_queue.c | 3
226 b/apps/app_voicemail.c | 30 +---
227 b/asterisk-16.14.0-rc1-summary.html | 78 ++++++++++
228 b/asterisk-16.14.0-rc1-summary.txt | 242 +++++++++++++++++++++++++++++++++
229 b/channels/pjsip/dialplan_functions.c | 5
230 b/configs/samples/logger.conf.sample | 4
231 b/configs/samples/pjsip.conf.sample | 10 -
232 b/contrib/scripts/ast_coredumper | 4
233 b/contrib/scripts/sip_nat_settings | 19 --
234 b/include/asterisk/conversions.h | 54 +++++++
235 b/include/asterisk/frame.h | 5
236 b/include/asterisk/logger.h | 86 ++++++++++-
237 b/include/asterisk/stream.h | 26 +++
238 b/main/bridge_channel.c | 37 ++++-
239 b/main/conversions.c | 51 ++++++
240 b/main/logger.c | 52 +++++++
241 b/main/stream.c | 27 +--
242 b/res/res_musiconhold.c | 131 +++++++++--------
243 b/res/res_pjsip_diversion.c | 6
244 b/res/res_pjsip_session.c | 13 +
245 b/res/res_speech.c | 7
246 b/tests/test_conversions.c | 146 +++++++++++++++++++-
247 27 files changed, 1147 insertions(+), 467 deletions(-)
0 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><title>Release Summary - asterisk-16.15.0</title><h1 align="center"><a name="top">Release Summary</a></h1><h3 align="center">asterisk-16.15.0</h3><h3 align="center">Date: 2020-11-19</h3><h3 align="center">&lt;asteriskteam@digium.com&gt;</h3><hr><h2 align="center">Table of Contents</h2><ol>
1 <li><a href="#summary">Summary</a></li>
2 <li><a href="#contributors">Contributors</a></li>
3 <li><a href="#closed_issues">Closed Issues</a></li>
4 <li><a href="#commits">Other Changes</a></li>
5 <li><a href="#diffstat">Diffstat</a></li>
6 </ol><hr><a name="summary"><h2 align="center">Summary</h2></a><center><a href="#top">[Back to Top]</a></center><p>This release is a point release of an existing major version. The changes included were made to address problems that have been identified in this release series, or are minor, backwards compatible new features or improvements. Users should be able to safely upgrade to this version if this release series is already in use. Users considering upgrading from a previous version are strongly encouraged to review the UPGRADE.txt document as well as the CHANGES document for information about upgrading to this release series.</p><p>The data in this summary reflects changes that have been made since the previous release, asterisk-16.14.0.</p><hr><a name="contributors"><h2 align="center">Contributors</h2></a><center><a href="#top">[Back to Top]</a></center><p>This table lists the people who have submitted code, those that have tested patches, as well as those that reported issues on the issue tracker that were resolved in this release. For coders, the number is how many of their patches (of any size) were committed into this release. For testers, the number is the number of times their name was listed as assisting with testing a patch. Finally, for reporters, the number is the number of issues that they reported that were affected by commits that went into this release.</p><table width="100%" border="0">
7 <tr><th width="33%">Coders</th><th width="33%">Testers</th><th width="33%">Reporters</th></tr>
8 <tr valign="top"><td width="33%">12 Ben Ford <bford@digium.com><br/>11 Sean Bright <sean.bright@gmail.com><br/>9 Alexander Traud <pabstraud@compuserve.com><br/>8 George Joseph <gjoseph@digium.com><br/>3 Kevin Harwell <kharwell@digium.com><br/>3 Asterisk Development Team <asteriskteam@digium.com><br/>3 Joshua C. Colp <jcolp@sangoma.com><br/>2 Torrey Searle <tsearle@voxbone.com><br/>2 Sungtae Kim <pchero21@gmail.com><br/>1 Holger Hans Peter Freyther <holger@moiji-mobile.com><br/>1 Dovid Bender <dovid@telecurve.com><br/>1 Walter Doekes <walter+asterisk@wjd.nu><br/>1 Alexei Gradinari <alex2grad@gmail.com><br/>1 Jean Aunis <jean.aunis@prescom.fr><br/>1 Jasper van der Neut <jasper@isotopic.nl><br/>1 Michal Hajek <michal.hajek@daktela.com><br/>1 laszlovl <digium@lvlconsultancy.nl><br/>1 Andrew Siplas <andrew@asiplas.net><br/></td><td width="33%"><td width="33%">3 Alexander Traud <pabstraud@compuserve.com><br/>2 George Joseph <gjoseph@digium.com><br/>2 sungtae kim <pchero21@gmail.com><br/>2 Sebastian Damm <damm@sipgate.de><br/>1 Walter Doekes <walter+asterisk@wjd.nu><br/>1 周家建 <zhou_0611@163.com><br/>1 Andrew Siplas <andrew@asiplas.net><br/>1 Jean Aunis - Prescom <jean.aunis@prescom.fr><br/>1 Kevin Harwell <kharwell@digium.com><br/>1 dovid <dovi5988@dovid.net><br/>1 Brian J. Murrell <brian@interlinx.bc.ca><br/>1 Vieri <vieridipaola@gmail.com><br/>1 Walter Doekes<br/>1 Ross Beer <ross.beer@voicehost.co.uk><br/>1 Benjamin M. <mailinglist@perspectives.qc.ca><br/>1 Péter Juhász <peter.juhasz@comnica.com><br/>1 under <under@list.ru><br/>1 Thomas Frederiksen <tommer@nicesurprise.com><br/>1 laszlovl <digium@lvlconsultancy.nl><br/>1 Michael Newton <miken32@gmail.com><br/>1 Sandro Gauci <sandro@enablesecurity.com><br/>1 Dovid Bender<br/>1 Jasper van der Neut <jasper@isotopic.nl><br/>1 Torrey Searle <tsearle@gmail.com><br/>1 Michal Hajek <michal.hajek@daktela.com><br/>1 Hajek Michal <michal.hajek@daktela.com><br/>1 Eric Smith <abkowald@gmail.com><br/></td></tr>
9 </table><hr><a name="closed_issues"><h2 align="center">Closed Issues</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a list of all issues from the issue tracker that were closed by changes that went into this release.</p><h3>Security</h3><h4>Category: pjproject/pjsip</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29057">ASTERISK-29057</a>: pjsip: Crash on call rejection during high load<br/>Reported by: Sandro Gauci<ul>
10 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=8973fe5cf3d683fe8113c11c9cc7f2eb413c0b89">[8973fe5cf3]</a> Kevin Harwell -- AST-2020-001 - res_pjsip: Return dialog locked and referenced</li>
11 </ul><br><h3>New Feature</h3><h4>Category: Resources/res_pjsip_diversion</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29027">ASTERISK-29027</a>: Implement support for History-Info<br/>Reported by: Torrey Searle<ul>
12 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=5a12463c0709513514abd42a48039d62ca9a6155">[5a12463c07]</a> Torrey Searle -- res_pjsip_diversion: implement support for History-Info</li>
13 </ul><br><h3>Bug</h3><h4>Category: . I did not set the category correctly.</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29146">ASTERISK-29146</a>: GCC Warnings: ‘%s’ directive argument is null.<br/>Reported by: Alexander Traud<ul>
14 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=334661601a8a5b7d937c54f0a5e7df6326f05f3b">[334661601a]</a> Alexander Traud -- Compiler fixes for GCC when printf %s is NULL</li>
15 </ul><br><h4>Category: Applications/app_directory</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29144">ASTERISK-29144</a>: GCC Warnings with OPTIMIZE=-Og make<br/>Reported by: Alexander Traud<ul>
16 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=13b56c4be6034ecf33f480ead096a22e72ac66c8">[13b56c4be6]</a> Alexander Traud -- Compiler fixes for GCC with -Og</li>
17 </ul><br><h4>Category: Applications/app_voicemail</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29144">ASTERISK-29144</a>: GCC Warnings with OPTIMIZE=-Og make<br/>Reported by: Alexander Traud<ul>
18 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=13b56c4be6034ecf33f480ead096a22e72ac66c8">[13b56c4be6]</a> Alexander Traud -- Compiler fixes for GCC with -Og</li>
19 </ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26424">ASTERISK-26424</a>: app_voicemail: Undocumented behavior from VMSayName<br/>Reported by: Eric Smith<ul>
20 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=9ac933fbbad7f28d281b8c3ed3f3b6d2f8b9b580">[9ac933fbba]</a> Sean Bright -- app_voicemail.c: Document VMSayName interruption behavior</li>
21 </ul><br><h4>Category: Channels/General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29144">ASTERISK-29144</a>: GCC Warnings with OPTIMIZE=-Og make<br/>Reported by: Alexander Traud<ul>
22 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=13b56c4be6034ecf33f480ead096a22e72ac66c8">[13b56c4be6]</a> Alexander Traud -- Compiler fixes for GCC with -Og</li>
23 </ul><br><h4>Category: Configs/Samples</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29123">ASTERISK-29123</a>: logger.conf.sample missing comment mark on line 115<br/>Reported by: Andrew Siplas<ul>
24 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=606bd35060c7802de68498a644a7fd799ffeca0a">[606bd35060]</a> Andrew Siplas -- logger.conf.sample: add missing comment mark</li>
25 </ul><br><h4>Category: Contrib/General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29142">ASTERISK-29142</a>: sip_to_pjsip.py: doesn't read globbed includes<br/>Reported by: Michael Newton<ul>
26 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=e067d5c8fd1538fa32d67084ae6c7dad728d0828">[e067d5c8fd]</a> Sean Bright -- sip_to_pjsip.py: Handle #include globs and other fixes</li>
27 </ul><br><h4>Category: Core/Channels</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29091">ASTERISK-29091</a>: Crash when ast_translator_build_path fails<br/>Reported by: Jasper van der Neut<ul>
28 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=efcc6d6f6b277e9f4be5470680e0a947bb42275a">[efcc6d6f6b]</a> Jasper van der Neut -- channels: Don't dereference NULL pointer</li>
29 </ul><br><h4>Category: Core/General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-28430">ASTERISK-28430</a>: res_rtp_asterisk.c: FRACK!, Failed assertion errno != EBADF<br/>Reported by: under<ul>
30 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=d0313d8b12bc1eb5efa8c73962272aa2e707d0e3">[d0313d8b12]</a> Sean Bright -- tcptls.c: Don't close TCP client file descriptors more than once</li>
31 </ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-28311">ASTERISK-28311</a>: dsp: ast_dsp_silence_noise_with_energy wrong judgment of frame format<br/>Reported by: 周家建<ul>
32 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=cba132a7979986fa82a189776473b77084ba951f">[cba132a797]</a> Sean Bright -- dsp.c: Update calls to ast_format_cmp to check result properly</li>
33 </ul><br><h4>Category: Core/RTP</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-28416">ASTERISK-28416</a>: Unable to get rtp codec payload code for slin<br/>Reported by: Brian J. Murrell<ul>
34 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=c9cc281484aec8c6a73e94d7f586b1c1bd2a0dff">[c9cc281484]</a> Sean Bright -- format_cap: Perform codec lookups by pointer instead of name</li>
35 </ul><br><h4>Category: Documentation</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29136">ASTERISK-29136</a>: config: Sample features.conf incorrectly includes " around sound files<br/>Reported by: Benjamin M.<ul>
36 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=e326b133dc3613778f2e0b6a15b69c5719a06d63">[e326b133dc]</a> Sean Bright -- features.conf.sample: Sample sound files incorrectly quoted</li>
37 </ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-26424">ASTERISK-26424</a>: app_voicemail: Undocumented behavior from VMSayName<br/>Reported by: Eric Smith<ul>
38 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=9ac933fbbad7f28d281b8c3ed3f3b6d2f8b9b580">[9ac933fbba]</a> Sean Bright -- app_voicemail.c: Document VMSayName interruption behavior</li>
39 </ul><br><h4>Category: Functions/func_curl</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-28825">ASTERISK-28825</a>: Any curl response checks out as valid even if 404 is returned.<br/>Reported by: dovid<ul>
40 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=5046e1fb062dd07c0593f10aee078b74a19e307b">[5046e1fb06]</a> Dovid Bender -- func_curl.c: Allow user to set what return codes constitute a failure.</li>
41 </ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29085">ASTERISK-29085</a>: func_curl: Segmentation fault when using CURL after setting httpheader CURLOPT<br/>Reported by: Péter Juhász<ul>
42 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=799426cd58fed60a4eee33a3b08ce52709a74670">[799426cd58]</a> Sean Bright -- func_curl.c: Prevent crash when using CURLOPT(httpheader)</li>
43 </ul><br><h4>Category: Functions/func_odbc</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29144">ASTERISK-29144</a>: GCC Warnings with OPTIMIZE=-Og make<br/>Reported by: Alexander Traud<ul>
44 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=13b56c4be6034ecf33f480ead096a22e72ac66c8">[13b56c4be6]</a> Alexander Traud -- Compiler fixes for GCC with -Og</li>
45 </ul><br><h4>Category: Resources/res_ari_endpoints</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29108">ASTERISK-29108</a>: resource_endpoints.c : Memory leak if endpoint not found<br/>Reported by: Jean Aunis - Prescom<ul>
46 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=0b835f21563c33f1aa0b3793e8617b2d8fc81de8">[0b835f2156]</a> Jean Aunis -- resource_endpoints.c: memory leak when providing a 404 response</li>
47 </ul><br><h4>Category: Resources/res_musiconhold</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29099">ASTERISK-29099</a>: res_musiconhold: Realtime MOH only loads a single entry<br/>Reported by: laszlovl<ul>
48 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=374d18cb974cb106026f5d8d722e13c106da1458">[374d18cb97]</a> laszlovl -- res_musiconhold: Load all realtime entries, not just the first</li>
49 </ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-24329">ASTERISK-24329</a>: Music On Hold announcement cuts intro of music the first time it is played<br/>Reported by: Thomas Frederiksen<ul>
50 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=4a7bbac0ed8b27ead4901e7bccebb8c14c7c6797">[4a7bbac0ed]</a> Sean Bright -- res_musiconhold: Start playlist after initial announcement</li>
51 </ul><br><h4>Category: Resources/res_pjsip</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-28933">ASTERISK-28933</a>: res_pjsip.so fails to load when bundled pjproject is compiled without libssl<br/>Reported by: Walter Doekes<ul>
52 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=ddfb76a864fd8e0d29fe7c14db5b8f760e3662f5">[ddfb76a864]</a> Alexander Traud -- res_pjsip/config_transport: Load and run without OpenSSL.</li>
53 </ul><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29013">ASTERISK-29013</a>: res_pjsip: Asterisk doesn't stop sending invites (with auth) on 407 replies<br/>Reported by: Sebastian Damm<ul>
54 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=58aa6a7057ca0bf8d62e0fe8c7a9b1a6bcf7cd9f">[58aa6a7057]</a> Ben Ford -- AST-2020-002 - res_pjsip: Stop sending INVITEs after challenge limit.</li>
55 </ul><br><h4>Category: Resources/res_pjsip_authenticator_digest</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29013">ASTERISK-29013</a>: res_pjsip: Asterisk doesn't stop sending invites (with auth) on 407 replies<br/>Reported by: Sebastian Damm<ul>
56 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=58aa6a7057ca0bf8d62e0fe8c7a9b1a6bcf7cd9f">[58aa6a7057]</a> Ben Ford -- AST-2020-002 - res_pjsip: Stop sending INVITEs after challenge limit.</li>
57 </ul><br><h4>Category: Resources/res_pjsip_config_wizard</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29097">ASTERISK-29097</a>: res_pjsip_config_wizard: Crash when freeing string when failing to add extension<br/>Reported by: Vieri<ul>
58 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=7a648681184e7b17cd2a28d98b79f903c04a418b">[7a64868118]</a> Sean Bright -- pbx.c: On error, ast_add_extension2_lockopt should always free 'data'</li>
59 </ul><br><h4>Category: Resources/res_pjsip_sdp_rtp</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29051">ASTERISK-29051</a>: res_pjsip_sdp_rtp: Does not set correct values on RTP instance when "auto" DTMF is used<br/>Reported by: Sebastian Damm<ul>
60 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=cd793c7c81fa261014623b57e9d8e96b0dad23c1">[cd793c7c81]</a> Holger Hans Peter Freyther -- res_pjsip_sdp_rtp: Fix accidentally native bridging calls</li>
61 </ul><br><h4>Category: Resources/res_pjsip_session</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29014">ASTERISK-29014</a>: res_pjsip_session: Re-INVITE collisions aren't handled correctly<br/>Reported by: George Joseph<ul>
62 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=df429c97a14e393798868760f63c3bbb1705b220">[df429c97a1]</a> George Joseph -- res_pjsip_session: Fix issue with COLP and 491</li>
63 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=65088494cb8bbc07ffb402cf2e8ac9078d17bb22">[65088494cb]</a> George Joseph -- res_pjsip_session: Handle multi-stream re-invites better</li>
64 </ul><br><h4>Category: Resources/res_rtp_asterisk</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29089">ASTERISK-29089</a>: RTP Ports not cleared after hangup<br/>Reported by: Ross Beer<ul>
65 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=e6ed74347ce748361e92bb0341c47c0ec2d0065f">[e6ed74347c]</a> Joshua C. Colp -- res_pjsip_session: Fix session reference leak.</li>
66 </ul><br><h4>Category: Resources/res_stasis</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29081">ASTERISK-29081</a>: res_stasis: Add compare function for bridges moh container<br/>Reported by: Hajek Michal<ul>
67 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=f7285140b418899b55551e203489f80e5a75566e">[f7285140b4]</a> Michal Hajek -- res_stasis.c: Add compare function for bridges moh container</li>
68 </ul><br><h4>Category: Utilities/muted</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29145">ASTERISK-29145</a>: GCC Warnings with OPTIMIZE=-Os make<br/>Reported by: Alexander Traud<ul>
69 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=92ca48d54c33c52a40cbeaa637caaecdd98a5587">[92ca48d54c]</a> Alexander Traud -- Compiler fixes for GCC with -Os</li>
70 </ul><br><h3>Improvement</h3><h4>Category: Core/Logging</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29054">ASTERISK-29054</a>: Logger: Add debug logging categories<br/>Reported by: Kevin Harwell<ul>
71 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=e051806e80be7ac1da55def1fb1ddc5b85d6fbec">[e051806e80]</a> Kevin Harwell -- Logging: Add debug logging categories</li>
72 </ul><br><h4>Category: Resources/General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29056">ASTERISK-29056</a>: Increase reg_server column size for ps_contacts table realtime<br/>Reported by: sungtae kim<ul>
73 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a353b76c75fbac19d44cc5c4884f1a0144ad225b">[a353b76c75]</a> Sungtae Kim -- realtime: Increased reg_server character size</li>
74 </ul><br><h4>Category: Resources/res_stasis</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29055">ASTERISK-29055</a>: Create a Bridge with video_single mode<br/>Reported by: sungtae kim<ul>
75 <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=af339d0adb39e883fcabffd799c08e9c04de0c57">[af339d0adb]</a> Sungtae Kim -- res_stasis.c: Added video_single option for bridge creation</li>
76 </ul><br><hr><a name="commits"><h2 align="center">Commits Not Associated with an Issue</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a list of all changes that went into this release that did not reference a JIRA issue.</p><table width="100%" border="1">
77 <tr><th>Revision</th><th>Author</th><th>Summary</th></tr>
78 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=fbe2e9b6871fd9047af8091175c34638b388dc6c">fbe2e9b687</a></td><td>Asterisk Development Team</td><td>Update for 16.15.0-rc1</td></tr>
79 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=3366956139de7a96d776385ea61211d7be985ff2">3366956139</a></td><td>Asterisk Development Team</td><td>Update CHANGES and UPGRADE.txt for 16.15.0</td></tr>
80 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=e1fd51cd2c183a3eb61803f52277d1a7d7a18c9c">e1fd51cd2c</a></td><td>George Joseph</td><td>res_pjsip_outbound_registration.c: Use our own scheduler and other stuff</td></tr>
81 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=80f116c1562d41b107506ebf332062a20282ca04">80f116c156</a></td><td>George Joseph</td><td>pjsip_scheduler.c: Add type ONESHOT and enhance cli show command</td></tr>
82 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=728cd55cde57d90f331e8395be517beeef812346">728cd55cde</a></td><td>Alexei Gradinari</td><td>sched: AST_SCHED_REPLACE_UNREF can lead to use after free of data</td></tr>
83 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=277aa0ced61f9fa2a3693ed5d59165d4a7425e05">277aa0ced6</a></td><td>Alexander Traud</td><td>res_stir_shaken: Include OpenSSL headers where used actually.</td></tr>
84 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=951ce0524d9ccadccc96c8bf68aa78f91fd8000a">951ce0524d</a></td><td>Alexander Traud</td><td>chan_sip: On authentication, pick MD5 for sure.</td></tr>
85 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=f98eed17c1ece6c4f18a91e730905ec1af5f8e87">f98eed17c1</a></td><td>Walter Doekes</td><td>main/say: Work around gcc 9 format-truncation false positive</td></tr>
86 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=92e1de458af79457db064d507bca28fe980f88ff">92e1de458a</a></td><td>Kevin Harwell</td><td>res_pjsip, res_pjsip_session: initialize local variables</td></tr>
87 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=65426f4312d93b3ca8410ea2dbdfd3674a95049f">65426f4312</a></td><td>Alexander Traud</td><td>install_prereq: Add GMime 3.0.</td></tr>
88 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=fb721ce82c6d40d9aea621561719899f68cf5d13">fb721ce82c</a></td><td>Alexander Traud</td><td>BuildSystem: Enable Lua 5.4.</td></tr>
89 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=69356a7895e96694f0993b637cff65261b9f8dea">69356a7895</a></td><td>Asterisk Development Team</td><td>Update CHANGES and UPGRADE.txt for 16.14.0</td></tr>
90 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=681a1624b578c7f0f798f0eb0c5e54d308343ae8">681a1624b5</a></td><td>Ben Ford</td><td>utils.c: NULL terminate ast_base64decode_string.</td></tr>
91 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=df7c4ed0eda1fcb44fe106661a62d88bd977fdd7">df7c4ed0ed</a></td><td>Ben Ford</td><td>res_stir_shaken: Fix memory allocation error in curl.c</td></tr>
92 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=21ab0a450be4d16f7c82f6e23ad75d6a343f7de3">21ab0a450b</a></td><td>Ben Ford</td><td>res_stir_shaken: Add stir_shaken option and general improvements.</td></tr>
93 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=d979bdf87a70a822942130b791456e81cfbdb9bc">d979bdf87a</a></td><td>Ben Ford</td><td>res_stir_shaken: Add outbound INVITE support.</td></tr>
94 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=746ce16b169fd133593b2c3dc3568fd29b4f041b">746ce16b16</a></td><td>Ben Ford</td><td>res_stir_shaken: Add inbound INVITE support.</td></tr>
95 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=9d7628829cef6be12dc8029c720ce5e18e4701f0">9d7628829c</a></td><td>Ben Ford</td><td>res_stir_shaken: Add unit tests for signing and verification.</td></tr>
96 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=035b463c931a36c15a87118bc3fab832e8ad79c5">035b463c93</a></td><td>Ben Ford</td><td>res_stir_shaken: Added dialplan function and API call.</td></tr>
97 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=0392a8e620aaa0cc2df9c3b15174ec0b2eaab6c4">0392a8e620</a></td><td>Joshua C. Colp</td><td>res_stir_shaken: Use ast_asprintf for creating file path.</td></tr>
98 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=70af7e13114da93109332c125210a3b274dc89b3">70af7e1311</a></td><td>Ben Ford</td><td>res_stir_shaken: Implemented signature verification.</td></tr>
99 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=971b125fc08b4066ea3f3704c732421eeda7cac4">971b125fc0</a></td><td>Alexander Traud</td><td>res_stir_shaken: Do not build without OpenSSL.</td></tr>
100 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=e9ee9a381b96e3ce16fcee88a1fa6ca2dc54bd78">e9ee9a381b</a></td><td>Ben Ford</td><td>res_stir_shaken: Implemented signing of JSON payload.</td></tr>
101 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=716e51a3f36cc6ce19c04937a5d83e3b98c2c05c">716e51a3f3</a></td><td>Ben Ford</td><td>res_stir_shaken: Initial commit and reading private key.</td></tr>
102 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=3b0a53f257c20f899e6a594d810424583b812755">3b0a53f257</a></td><td>George Joseph</td><td>app_confbridge/bridge_softmix: Add ability to force estimated bitrate</td></tr>
103 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=14b483dd5e40cd574a6ae896a62c183034cfeea2">14b483dd5e</a></td><td>Torrey Searle</td><td>res_pjsip_diversion: fix double 181</td></tr>
104 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=fccf360fcb90622ee07c86755b4d3e0fc9fa757f">fccf360fcb</a></td><td>Sean Bright</td><td>res_musiconhold: Clarify that playlist mode only supports HTTP(S) URLs</td></tr>
105 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=baa6e8f1127c95bc871d00d595d4a468ca3fd3a4">baa6e8f112</a></td><td>Joshua C. Colp</td><td>res_pjsip_session: Fix stream name memory leak.</td></tr>
106 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=fb6f2157e7e02759a0e1bb701f133621a5f77389">fb6f2157e7</a></td><td>George Joseph</td><td>logger.h: Fix ast_trace to respect scope_level</td></tr>
107 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=8d9633074eb5068124714c3d3f415a40aadad557">8d9633074e</a></td><td>George Joseph</td><td>bridge_softmix/sfu_topologies_on_join: Ignore topology change failures</td></tr>
108 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=9458577f680a513734cf56730a4957d47cc32544">9458577f68</a></td><td>Sean Bright</td><td>res_pjsip_session.c: Fix build when TEST_FRAMEWORK is not defined</td></tr>
109 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=6abf6f345dbd0510d8a217d16cc1819e4d2bf815">6abf6f345d</a></td><td>George Joseph</td><td>debugging: Add enough to choke a mule</td></tr>
110 <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=e7620d034a0df7b438a91b77ebaa7d38c6a426ba">e7620d034a</a></td><td>Ben Ford</td><td>Bridging: Use a ref to bridge_channel's channel to prevent crash.</td></tr>
111 </table><hr><a name="diffstat"><h2 align="center">Diffstat Results</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a summary of the changes to the source code that went into this release that was generated using the diffstat utility.</p><pre>asterisk-16.14.0-summary.html | 76
112 asterisk-16.14.0-summary.txt | 248 -
113 b/.version | 2
114 b/CHANGES | 51
115 b/ChangeLog | 920 ++++
116 b/Makefile | 2
117 b/UPGRADE.txt | 10
118 b/addons/ooh323c/src/ooq931.c | 2
119 b/apps/app_confbridge.c | 3
120 b/apps/app_directory.c | 2
121 b/apps/app_voicemail.c | 5
122 b/apps/confbridge/conf_config_parser.c | 21
123 b/apps/confbridge/include/confbridge.h | 2
124 b/asterisk-16.15.0-rc1-summary.html | 215 +
125 b/asterisk-16.15.0-rc1-summary.txt | 542 ++
126 b/bridges/bridge_softmix.c | 153
127 b/channels/chan_iax2.c | 2
128 b/channels/chan_pjsip.c | 74
129 b/channels/chan_sip.c | 13
130 b/configs/samples/confbridge.conf.sample | 7
131 b/configs/samples/features.conf.sample | 4
132 b/configs/samples/musiconhold.conf.sample | 4
133 b/configs/samples/pjsip.conf.sample | 18
134 b/configs/samples/res_curl.conf.sample | 1
135 b/configs/samples/stir_shaken.conf.sample | 61
136 b/configure | 2
137 b/configure.ac | 2
138 b/contrib/ast-db-manage/config/versions/1ae0609b6646_increse_reg_server_size.py | 22
139 b/contrib/ast-db-manage/config/versions/61797b9fced6_add_stir_shaken.py | 31
140 b/contrib/ast-db-manage/config/versions/e658c26033ca_create_history_info_flag.py | 38
141 b/contrib/realtime/mysql/mysql_config.sql | 18
142 b/contrib/realtime/postgresql/postgresql_config.sql | 18
143 b/contrib/scripts/install_prereq | 2
144 b/contrib/scripts/sip_to_pjsip/astconfigparser.py | 43
145 b/funcs/func_curl.c | 48
146 b/funcs/func_odbc.c | 2
147 b/include/asterisk/bridge.h | 14
148 b/include/asterisk/bridge_channel.h | 14
149 b/include/asterisk/format_cache.h | 13
150 b/include/asterisk/logger.h | 4
151 b/include/asterisk/logger_category.h | 178
152 b/include/asterisk/pbx.h | 8
153 b/include/asterisk/res_pjsip.h | 109
154 b/include/asterisk/res_pjsip_session.h | 8
155 b/include/asterisk/res_stir_shaken.h | 114
156 b/include/asterisk/rtp_engine.h | 79
157 b/include/asterisk/sched.h | 5
158 b/include/asterisk/stream.h | 4
159 b/include/asterisk/stun.h | 25
160 b/include/asterisk/utils.h | 26
161 b/main/bridge.c | 44
162 b/main/bridge_channel.c | 20
163 b/main/channel.c | 14
164 b/main/cli.c | 51
165 b/main/dsp.c | 4
166 b/main/format_cache.c | 21
167 b/main/format_cap.c | 2
168 b/main/indications.c | 6
169 b/main/logger.c | 5
170 b/main/logger_category.c | 324 +
171 b/main/pbx.c | 12
172 b/main/rtp_engine.c | 68
173 b/main/say.c | 20
174 b/main/stream.c | 30
175 b/main/stun.c | 61
176 b/main/tcptls.c | 12
177 b/main/utils.c | 50
178 b/res/Makefile | 1
179 b/res/ari/resource_bridges.h | 4
180 b/res/ari/resource_endpoints.c | 1
181 b/res/parking/parking_bridge_features.c | 1
182 b/res/res_musiconhold.c | 24
183 b/res/res_parking.c | 1
184 b/res/res_pjsip.c | 78
185 b/res/res_pjsip/config_transport.c | 18
186 b/res/res_pjsip/pjsip_configuration.c | 2
187 b/res/res_pjsip/pjsip_scheduler.c | 180
188 b/res/res_pjsip/pjsip_transport_management.c | 2
189 b/res/res_pjsip_config_wizard.c | 1
190 b/res/res_pjsip_diversion.c | 326 +
191 b/res/res_pjsip_outbound_registration.c | 296 -
192 b/res/res_pjsip_pubsub.c | 10
193 b/res/res_pjsip_sdp_rtp.c | 26
194 b/res/res_pjsip_session.c | 1938 ++++++++--
195 b/res/res_pjsip_stir_shaken.c | 332 +
196 b/res/res_rtp_asterisk.c | 403 +-
197 b/res/res_stasis.c | 31
198 b/res/res_stir_shaken.c | 1665 ++++++++
199 b/res/res_stir_shaken.exports.in | 6
200 b/res/res_stir_shaken/certificate.c | 388 ++
201 b/res/res_stir_shaken/certificate.h | 119
202 b/res/res_stir_shaken/curl.c | 199 +
203 b/res/res_stir_shaken/curl.h | 73
204 b/res/res_stir_shaken/general.c | 286 +
205 b/res/res_stir_shaken/general.h | 111
206 b/res/res_stir_shaken/stir_shaken.c | 122
207 b/res/res_stir_shaken/stir_shaken.h | 55
208 b/res/res_stir_shaken/store.c | 202 +
209 b/res/res_stir_shaken/store.h | 37
210 b/res/stasis/stasis_bridge.c | 2
211 b/rest-api/api-docs/bridges.json | 4
212 101 files changed, 9762 insertions(+), 1191 deletions(-)</pre><br></html>
0 Release Summary
1
2 asterisk-16.15.0
3
4 Date: 2020-11-19
5
6 <asteriskteam@digium.com>
7
8 ----------------------------------------------------------------------
9
10 Table of Contents
11
12 1. Summary
13 2. Contributors
14 3. Closed Issues
15 4. Other Changes
16 5. Diffstat
17
18 ----------------------------------------------------------------------
19
20 Summary
21
22 [Back to Top]
23
24 This release is a point release of an existing major version. The changes
25 included were made to address problems that have been identified in this
26 release series, or are minor, backwards compatible new features or
27 improvements. Users should be able to safely upgrade to this version if
28 this release series is already in use. Users considering upgrading from a
29 previous version are strongly encouraged to review the UPGRADE.txt
30 document as well as the CHANGES document for information about upgrading
31 to this release series.
32
33 The data in this summary reflects changes that have been made since the
34 previous release, asterisk-16.14.0.
35
36 ----------------------------------------------------------------------
37
38 Contributors
39
40 [Back to Top]
41
42 This table lists the people who have submitted code, those that have
43 tested patches, as well as those that reported issues on the issue tracker
44 that were resolved in this release. For coders, the number is how many of
45 their patches (of any size) were committed into this release. For testers,
46 the number is the number of times their name was listed as assisting with
47 testing a patch. Finally, for reporters, the number is the number of
48 issues that they reported that were affected by commits that went into
49 this release.
50
51 Coders Testers Reporters
52 12 Ben Ford 3 Alexander Traud
53 11 Sean Bright 2 George Joseph
54 9 Alexander Traud 2 sungtae kim
55 8 George Joseph 2 Sebastian Damm
56 3 Kevin Harwell 1 Walter Doekes
57 3 Asterisk Development Team 1 å*¨å®¶å»º
58 3 Joshua C. Colp 1 Andrew Siplas
59 2 Torrey Searle 1 Jean Aunis - Prescom
60 2 Sungtae Kim 1 Kevin Harwell
61 1 Holger Hans Peter Freyther 1 dovid
62 1 Dovid Bender 1 Brian J. Murrell
63 1 Walter Doekes 1 Vieri
64 1 Alexei Gradinari 1 Walter Doekes
65 1 Jean Aunis 1 Ross Beer
66 1 Jasper van der Neut 1 Benjamin M.
67 1 Michal Hajek 1 Péter Juhász
68 1 laszlovl 1 under
69 1 Andrew Siplas 1 Thomas Frederiksen
70 1 laszlovl
71 1 Michael Newton
72 1 Sandro Gauci
73 1 Dovid Bender
74 1 Jasper van der Neut
75 1 Torrey Searle
76 1 Michal Hajek
77 1 Hajek Michal
78 1 Eric Smith
79
80 ----------------------------------------------------------------------
81
82 Closed Issues
83
84 [Back to Top]
85
86 This is a list of all issues from the issue tracker that were closed by
87 changes that went into this release.
88
89 Security
90
91 Category: pjproject/pjsip
92
93 ASTERISK-29057: pjsip: Crash on call rejection during high load
94 Reported by: Sandro Gauci
95 * [8973fe5cf3] Kevin Harwell -- AST-2020-001 - res_pjsip: Return dialog
96 locked and referenced
97
98 New Feature
99
100 Category: Resources/res_pjsip_diversion
101
102 ASTERISK-29027: Implement support for History-Info
103 Reported by: Torrey Searle
104 * [5a12463c07] Torrey Searle -- res_pjsip_diversion: implement support
105 for History-Info
106
107 Bug
108
109 Category: . I did not set the category correctly.
110
111 ASTERISK-29146: GCC Warnings: â**%sâ** directive argument is null.
112 Reported by: Alexander Traud
113 * [334661601a] Alexander Traud -- Compiler fixes for GCC when printf %s
114 is NULL
115
116 Category: Applications/app_directory
117
118 ASTERISK-29144: GCC Warnings with OPTIMIZE=-Og make
119 Reported by: Alexander Traud
120 * [13b56c4be6] Alexander Traud -- Compiler fixes for GCC with -Og
121
122 Category: Applications/app_voicemail
123
124 ASTERISK-29144: GCC Warnings with OPTIMIZE=-Og make
125 Reported by: Alexander Traud
126 * [13b56c4be6] Alexander Traud -- Compiler fixes for GCC with -Og
127 ASTERISK-26424: app_voicemail: Undocumented behavior from VMSayName
128 Reported by: Eric Smith
129 * [9ac933fbba] Sean Bright -- app_voicemail.c: Document VMSayName
130 interruption behavior
131
132 Category: Channels/General
133
134 ASTERISK-29144: GCC Warnings with OPTIMIZE=-Og make
135 Reported by: Alexander Traud
136 * [13b56c4be6] Alexander Traud -- Compiler fixes for GCC with -Og
137
138 Category: Configs/Samples
139
140 ASTERISK-29123: logger.conf.sample missing comment mark on line 115
141 Reported by: Andrew Siplas
142 * [606bd35060] Andrew Siplas -- logger.conf.sample: add missing comment
143 mark
144
145 Category: Contrib/General
146
147 ASTERISK-29142: sip_to_pjsip.py: doesn't read globbed includes
148 Reported by: Michael Newton
149 * [e067d5c8fd] Sean Bright -- sip_to_pjsip.py: Handle #include globs and
150 other fixes
151
152 Category: Core/Channels
153
154 ASTERISK-29091: Crash when ast_translator_build_path fails
155 Reported by: Jasper van der Neut
156 * [efcc6d6f6b] Jasper van der Neut -- channels: Don't dereference NULL
157 pointer
158
159 Category: Core/General
160
161 ASTERISK-28430: res_rtp_asterisk.c: FRACK!, Failed assertion errno !=
162 EBADF
163 Reported by: under
164 * [d0313d8b12] Sean Bright -- tcptls.c: Don't close TCP client file
165 descriptors more than once
166 ASTERISK-28311: dsp: ast_dsp_silence_noise_with_energy wrong judgment of
167 frame format
168 Reported by: å*¨å®¶å»º
169 * [cba132a797] Sean Bright -- dsp.c: Update calls to ast_format_cmp to
170 check result properly
171
172 Category: Core/RTP
173
174 ASTERISK-28416: Unable to get rtp codec payload code for slin
175 Reported by: Brian J. Murrell
176 * [c9cc281484] Sean Bright -- format_cap: Perform codec lookups by
177 pointer instead of name
178
179 Category: Documentation
180
181 ASTERISK-29136: config: Sample features.conf incorrectly includes " around
182 sound files
183 Reported by: Benjamin M.
184 * [e326b133dc] Sean Bright -- features.conf.sample: Sample sound files
185 incorrectly quoted
186 ASTERISK-26424: app_voicemail: Undocumented behavior from VMSayName
187 Reported by: Eric Smith
188 * [9ac933fbba] Sean Bright -- app_voicemail.c: Document VMSayName
189 interruption behavior
190
191 Category: Functions/func_curl
192
193 ASTERISK-28825: Any curl response checks out as valid even if 404 is
194 returned.
195 Reported by: dovid
196 * [5046e1fb06] Dovid Bender -- func_curl.c: Allow user to set what
197 return codes constitute a failure.
198 ASTERISK-29085: func_curl: Segmentation fault when using CURL after
199 setting httpheader CURLOPT
200 Reported by: Péter Juhász
201 * [799426cd58] Sean Bright -- func_curl.c: Prevent crash when using
202 CURLOPT(httpheader)
203
204 Category: Functions/func_odbc
205
206 ASTERISK-29144: GCC Warnings with OPTIMIZE=-Og make
207 Reported by: Alexander Traud
208 * [13b56c4be6] Alexander Traud -- Compiler fixes for GCC with -Og
209
210 Category: Resources/res_ari_endpoints
211
212 ASTERISK-29108: resource_endpoints.c : Memory leak if endpoint not found
213 Reported by: Jean Aunis - Prescom
214 * [0b835f2156] Jean Aunis -- resource_endpoints.c: memory leak when
215 providing a 404 response
216
217 Category: Resources/res_musiconhold
218
219 ASTERISK-29099: res_musiconhold: Realtime MOH only loads a single entry
220 Reported by: laszlovl
221 * [374d18cb97] laszlovl -- res_musiconhold: Load all realtime entries,
222 not just the first
223 ASTERISK-24329: Music On Hold announcement cuts intro of music the first
224 time it is played
225 Reported by: Thomas Frederiksen
226 * [4a7bbac0ed] Sean Bright -- res_musiconhold: Start playlist after
227 initial announcement
228
229 Category: Resources/res_pjsip
230
231 ASTERISK-28933: res_pjsip.so fails to load when bundled pjproject is
232 compiled without libssl
233 Reported by: Walter Doekes
234 * [ddfb76a864] Alexander Traud -- res_pjsip/config_transport: Load and
235 run without OpenSSL.
236 ASTERISK-29013: res_pjsip: Asterisk doesn't stop sending invites (with
237 auth) on 407 replies
238 Reported by: Sebastian Damm
239 * [58aa6a7057] Ben Ford -- AST-2020-002 - res_pjsip: Stop sending
240 INVITEs after challenge limit.
241
242 Category: Resources/res_pjsip_authenticator_digest
243
244 ASTERISK-29013: res_pjsip: Asterisk doesn't stop sending invites (with
245 auth) on 407 replies
246 Reported by: Sebastian Damm
247 * [58aa6a7057] Ben Ford -- AST-2020-002 - res_pjsip: Stop sending
248 INVITEs after challenge limit.
249
250 Category: Resources/res_pjsip_config_wizard
251
252 ASTERISK-29097: res_pjsip_config_wizard: Crash when freeing string when
253 failing to add extension
254 Reported by: Vieri
255 * [7a64868118] Sean Bright -- pbx.c: On error,
256 ast_add_extension2_lockopt should always free 'data'
257
258 Category: Resources/res_pjsip_sdp_rtp
259
260 ASTERISK-29051: res_pjsip_sdp_rtp: Does not set correct values on RTP
261 instance when "auto" DTMF is used
262 Reported by: Sebastian Damm
263 * [cd793c7c81] Holger Hans Peter Freyther -- res_pjsip_sdp_rtp: Fix
264 accidentally native bridging calls
265
266 Category: Resources/res_pjsip_session
267
268 ASTERISK-29014: res_pjsip_session: Re-INVITE collisions aren't handled
269 correctly
270 Reported by: George Joseph
271 * [df429c97a1] George Joseph -- res_pjsip_session: Fix issue with COLP
272 and 491
273 * [65088494cb] George Joseph -- res_pjsip_session: Handle multi-stream
274 re-invites better
275
276 Category: Resources/res_rtp_asterisk
277
278 ASTERISK-29089: RTP Ports not cleared after hangup
279 Reported by: Ross Beer
280 * [e6ed74347c] Joshua C. Colp -- res_pjsip_session: Fix session
281 reference leak.
282
283 Category: Resources/res_stasis
284
285 ASTERISK-29081: res_stasis: Add compare function for bridges moh container
286 Reported by: Hajek Michal
287 * [f7285140b4] Michal Hajek -- res_stasis.c: Add compare function for
288 bridges moh container
289
290 Category: Utilities/muted
291
292 ASTERISK-29145: GCC Warnings with OPTIMIZE=-Os make
293 Reported by: Alexander Traud
294 * [92ca48d54c] Alexander Traud -- Compiler fixes for GCC with -Os
295
296 Improvement
297
298 Category: Core/Logging
299
300 ASTERISK-29054: Logger: Add debug logging categories
301 Reported by: Kevin Harwell
302 * [e051806e80] Kevin Harwell -- Logging: Add debug logging categories
303
304 Category: Resources/General
305
306 ASTERISK-29056: Increase reg_server column size for ps_contacts table
307 realtime
308 Reported by: sungtae kim
309 * [a353b76c75] Sungtae Kim -- realtime: Increased reg_server character
310 size
311
312 Category: Resources/res_stasis
313
314 ASTERISK-29055: Create a Bridge with video_single mode
315 Reported by: sungtae kim
316 * [af339d0adb] Sungtae Kim -- res_stasis.c: Added video_single option
317 for bridge creation
318
319 ----------------------------------------------------------------------
320
321 Commits Not Associated with an Issue
322
323 [Back to Top]
324
325 This is a list of all changes that went into this release that did not
326 reference a JIRA issue.
327
328 +------------------------------------------------------------------------+
329 | Revision | Author | Summary |
330 |------------+---------------+-------------------------------------------|
331 | | Asterisk | |
332 | fbe2e9b687 | Development | Update for 16.15.0-rc1 |
333 | | Team | |
334 |------------+---------------+-------------------------------------------|
335 | | Asterisk | Update CHANGES and UPGRADE.txt for |
336 | 3366956139 | Development | 16.15.0 |
337 | | Team | |
338 |------------+---------------+-------------------------------------------|
339 | e1fd51cd2c | George Joseph | res_pjsip_outbound_registration.c: Use |
340 | | | our own scheduler and other stuff |
341 |------------+---------------+-------------------------------------------|
342 | 80f116c156 | George Joseph | pjsip_scheduler.c: Add type ONESHOT and |
343 | | | enhance cli show command |
344 |------------+---------------+-------------------------------------------|
345 | 728cd55cde | Alexei | sched: AST_SCHED_REPLACE_UNREF can lead |
346 | | Gradinari | to use after free of data |
347 |------------+---------------+-------------------------------------------|
348 | 277aa0ced6 | Alexander | res_stir_shaken: Include OpenSSL headers |
349 | | Traud | where used actually. |
350 |------------+---------------+-------------------------------------------|
351 | 951ce0524d | Alexander | chan_sip: On authentication, pick MD5 for |
352 | | Traud | sure. |
353 |------------+---------------+-------------------------------------------|
354 | f98eed17c1 | Walter Doekes | main/say: Work around gcc 9 |
355 | | | format-truncation false positive |
356 |------------+---------------+-------------------------------------------|
357 | 92e1de458a | Kevin Harwell | res_pjsip, res_pjsip_session: initialize |
358 | | | local variables |
359 |------------+---------------+-------------------------------------------|
360 | 65426f4312 | Alexander | install_prereq: Add GMime 3.0. |
361 | | Traud | |
362 |------------+---------------+-------------------------------------------|
363 | fb721ce82c | Alexander | BuildSystem: Enable Lua 5.4. |
364 | | Traud | |
365 |------------+---------------+-------------------------------------------|
366 | | Asterisk | Update CHANGES and UPGRADE.txt for |
367 | 69356a7895 | Development | 16.14.0 |
368 | | Team | |
369 |------------+---------------+-------------------------------------------|
370 | 681a1624b5 | Ben Ford | utils.c: NULL terminate |
371 | | | ast_base64decode_string. |
372 |------------+---------------+-------------------------------------------|
373 | df7c4ed0ed | Ben Ford | res_stir_shaken: Fix memory allocation |
374 | | | error in curl.c |
375 |------------+---------------+-------------------------------------------|
376 | 21ab0a450b | Ben Ford | res_stir_shaken: Add stir_shaken option |
377 | | | and general improvements. |
378 |------------+---------------+-------------------------------------------|
379 | d979bdf87a | Ben Ford | res_stir_shaken: Add outbound INVITE |
380 | | | support. |
381 |------------+---------------+-------------------------------------------|
382 | 746ce16b16 | Ben Ford | res_stir_shaken: Add inbound INVITE |
383 | | | support. |
384 |------------+---------------+-------------------------------------------|
385 | 9d7628829c | Ben Ford | res_stir_shaken: Add unit tests for |
386 | | | signing and verification. |
387 |------------+---------------+-------------------------------------------|
388 | 035b463c93 | Ben Ford | res_stir_shaken: Added dialplan function |
389 | | | and API call. |
390 |------------+---------------+-------------------------------------------|
391 | 0392a8e620 | Joshua C. | res_stir_shaken: Use ast_asprintf for |
392 | | Colp | creating file path. |
393 |------------+---------------+-------------------------------------------|
394 | 70af7e1311 | Ben Ford | res_stir_shaken: Implemented signature |
395 | | | verification. |
396 |------------+---------------+-------------------------------------------|
397 | 971b125fc0 | Alexander | res_stir_shaken: Do not build without |
398 | | Traud | OpenSSL. |
399 |------------+---------------+-------------------------------------------|
400 | e9ee9a381b | Ben Ford | res_stir_shaken: Implemented signing of |
401 | | | JSON payload. |
402 |------------+---------------+-------------------------------------------|
403 | 716e51a3f3 | Ben Ford | res_stir_shaken: Initial commit and |
404 | | | reading private key. |
405 |------------+---------------+-------------------------------------------|
406 | 3b0a53f257 | George Joseph | app_confbridge/bridge_softmix: Add |
407 | | | ability to force estimated bitrate |
408 |------------+---------------+-------------------------------------------|
409 | 14b483dd5e | Torrey Searle | res_pjsip_diversion: fix double 181 |
410 |------------+---------------+-------------------------------------------|
411 | fccf360fcb | Sean Bright | res_musiconhold: Clarify that playlist |
412 | | | mode only supports HTTP(S) URLs |
413 |------------+---------------+-------------------------------------------|
414 | baa6e8f112 | Joshua C. | res_pjsip_session: Fix stream name memory |
415 | | Colp | leak. |
416 |------------+---------------+-------------------------------------------|
417 | fb6f2157e7 | George Joseph | logger.h: Fix ast_trace to respect |
418 | | | scope_level |
419 |------------+---------------+-------------------------------------------|
420 | 8d9633074e | George Joseph | bridge_softmix/sfu_topologies_on_join: |
421 | | | Ignore topology change failures |
422 |------------+---------------+-------------------------------------------|
423 | 9458577f68 | Sean Bright | res_pjsip_session.c: Fix build when |
424 | | | TEST_FRAMEWORK is not defined |
425 |------------+---------------+-------------------------------------------|
426 | 6abf6f345d | George Joseph | debugging: Add enough to choke a mule |
427 |------------+---------------+-------------------------------------------|
428 | e7620d034a | Ben Ford | Bridging: Use a ref to bridge_channel's |
429 | | | channel to prevent crash. |
430 +------------------------------------------------------------------------+
431
432 ----------------------------------------------------------------------
433
434 Diffstat Results
435
436 [Back to Top]
437
438 This is a summary of the changes to the source code that went into this
439 release that was generated using the diffstat utility.
440
441 asterisk-16.14.0-summary.html | 76
442 asterisk-16.14.0-summary.txt | 248 -
443 b/.version | 2
444 b/CHANGES | 51
445 b/ChangeLog | 920 ++++
446 b/Makefile | 2
447 b/UPGRADE.txt | 10
448 b/addons/ooh323c/src/ooq931.c | 2
449 b/apps/app_confbridge.c | 3
450 b/apps/app_directory.c | 2
451 b/apps/app_voicemail.c | 5
452 b/apps/confbridge/conf_config_parser.c | 21
453 b/apps/confbridge/include/confbridge.h | 2
454 b/asterisk-16.15.0-rc1-summary.html | 215 +
455 b/asterisk-16.15.0-rc1-summary.txt | 542 ++
456 b/bridges/bridge_softmix.c | 153
457 b/channels/chan_iax2.c | 2
458 b/channels/chan_pjsip.c | 74
459 b/channels/chan_sip.c | 13
460 b/configs/samples/confbridge.conf.sample | 7
461 b/configs/samples/features.conf.sample | 4
462 b/configs/samples/musiconhold.conf.sample | 4
463 b/configs/samples/pjsip.conf.sample | 18
464 b/configs/samples/res_curl.conf.sample | 1
465 b/configs/samples/stir_shaken.conf.sample | 61
466 b/configure | 2
467 b/configure.ac | 2
468 b/contrib/ast-db-manage/config/versions/1ae0609b6646_increse_reg_server_size.py | 22
469 b/contrib/ast-db-manage/config/versions/61797b9fced6_add_stir_shaken.py | 31
470 b/contrib/ast-db-manage/config/versions/e658c26033ca_create_history_info_flag.py | 38
471 b/contrib/realtime/mysql/mysql_config.sql | 18
472 b/contrib/realtime/postgresql/postgresql_config.sql | 18
473 b/contrib/scripts/install_prereq | 2
474 b/contrib/scripts/sip_to_pjsip/astconfigparser.py | 43
475 b/funcs/func_curl.c | 48
476 b/funcs/func_odbc.c | 2
477 b/include/asterisk/bridge.h | 14
478 b/include/asterisk/bridge_channel.h | 14
479 b/include/asterisk/format_cache.h | 13
480 b/include/asterisk/logger.h | 4
481 b/include/asterisk/logger_category.h | 178
482 b/include/asterisk/pbx.h | 8
483 b/include/asterisk/res_pjsip.h | 109
484 b/include/asterisk/res_pjsip_session.h | 8
485 b/include/asterisk/res_stir_shaken.h | 114
486 b/include/asterisk/rtp_engine.h | 79
487 b/include/asterisk/sched.h | 5
488 b/include/asterisk/stream.h | 4
489 b/include/asterisk/stun.h | 25
490 b/include/asterisk/utils.h | 26
491 b/main/bridge.c | 44
492 b/main/bridge_channel.c | 20
493 b/main/channel.c | 14
494 b/main/cli.c | 51
495 b/main/dsp.c | 4
496 b/main/format_cache.c | 21
497 b/main/format_cap.c | 2
498 b/main/indications.c | 6
499 b/main/logger.c | 5
500 b/main/logger_category.c | 324 +
501 b/main/pbx.c | 12
502 b/main/rtp_engine.c | 68
503 b/main/say.c | 20
504 b/main/stream.c | 30
505 b/main/stun.c | 61
506 b/main/tcptls.c | 12
507 b/main/utils.c | 50
508 b/res/Makefile | 1
509 b/res/ari/resource_bridges.h | 4
510 b/res/ari/resource_endpoints.c | 1
511 b/res/parking/parking_bridge_features.c | 1
512 b/res/res_musiconhold.c | 24
513 b/res/res_parking.c | 1
514 b/res/res_pjsip.c | 78
515 b/res/res_pjsip/config_transport.c | 18
516 b/res/res_pjsip/pjsip_configuration.c | 2
517 b/res/res_pjsip/pjsip_scheduler.c | 180
518 b/res/res_pjsip/pjsip_transport_management.c | 2
519 b/res/res_pjsip_config_wizard.c | 1
520 b/res/res_pjsip_diversion.c | 326 +
521 b/res/res_pjsip_outbound_registration.c | 296 -
522 b/res/res_pjsip_pubsub.c | 10
523 b/res/res_pjsip_sdp_rtp.c | 26
524 b/res/res_pjsip_session.c | 1938 ++++++++--
525 b/res/res_pjsip_stir_shaken.c | 332 +
526 b/res/res_rtp_asterisk.c | 403 +-
527 b/res/res_stasis.c | 31
528 b/res/res_stir_shaken.c | 1665 ++++++++
529 b/res/res_stir_shaken.exports.in | 6
530 b/res/res_stir_shaken/certificate.c | 388 ++
531 b/res/res_stir_shaken/certificate.h | 119
532 b/res/res_stir_shaken/curl.c | 199 +
533 b/res/res_stir_shaken/curl.h | 73
534 b/res/res_stir_shaken/general.c | 286 +
535 b/res/res_stir_shaken/general.h | 111
536 b/res/res_stir_shaken/stir_shaken.c | 122
537 b/res/res_stir_shaken/stir_shaken.h | 55
538 b/res/res_stir_shaken/store.c | 202 +
539 b/res/res_stir_shaken/store.h | 37
540 b/res/stasis/stasis_bridge.c | 2
541 b/rest-api/api-docs/bridges.json | 4
542 101 files changed, 9762 insertions(+), 1191 deletions(-)
620620 static void sfu_topologies_on_join(struct ast_bridge *bridge,
621621 struct ast_bridge_channel *joiner)
622622 {
623 struct ast_stream_topology *joiner_video = NULL;
623 RAII_VAR(struct ast_stream_topology *, joiner_video, NULL, ast_stream_topology_free);
624624 struct ast_bridge_channels_list *participants = &bridge->channels;
625625 struct ast_bridge_channel *participant;
626626 int res;
627627 struct softmix_channel *sc;
628 SCOPE_ENTER(3, "%s: \n", ast_channel_name(joiner->chan));
628629
629630 joiner_video = ast_stream_topology_alloc();
630631 if (!joiner_video) {
631 return;
632 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Couldn't alloc topology\n", ast_channel_name(joiner->chan));
632633 }
633634
634635 sc = joiner->tech_pvt;
641642 ast_channel_unlock(joiner->chan);
642643
643644 if (res || !sc->topology) {
644 goto cleanup;
645 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Couldn't append source streams\n", ast_channel_name(joiner->chan));
645646 }
646647
647648 AST_LIST_TRAVERSE(participants, participant, entry) {
648649 if (participant == joiner) {
649650 continue;
650651 }
652 ast_trace(-1, "%s: Appending existing participant %s\n", ast_channel_name(joiner->chan),
653 ast_channel_name(participant->chan));
651654 ast_channel_lock(participant->chan);
652655 res = append_source_streams(sc->topology, ast_channel_name(participant->chan),
653656 bridge->softmix.send_sdp_label ? ast_channel_uniqueid(participant->chan) : NULL,
654657 ast_channel_get_stream_topology(participant->chan));
655658 ast_channel_unlock(participant->chan);
656659 if (res) {
657 goto cleanup;
658 }
659 }
660
661 ast_channel_request_stream_topology_change(joiner->chan, sc->topology, NULL);
660 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s/%s: Couldn't append source streams\n",
661 ast_channel_name(participant->chan), ast_channel_name(joiner->chan));
662 }
663 }
664
665 ast_trace(-1, "%s: Requesting topology change.\n", ast_channel_name(joiner->chan));
666 res = ast_channel_request_stream_topology_change(joiner->chan, sc->topology, NULL);
667 if (res) {
668 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Couldn't request topology change\n", ast_channel_name(joiner->chan));
669 }
662670
663671 AST_LIST_TRAVERSE(participants, participant, entry) {
664672 if (participant == joiner) {
666674 }
667675
668676 sc = participant->tech_pvt;
677 ast_trace(-1, "%s: Appending joiner %s\n", ast_channel_name(participant->chan),
678 ast_channel_name(joiner->chan));
679
669680 if (append_all_streams(sc->topology, joiner_video)) {
670 goto cleanup;
671 }
672 ast_channel_request_stream_topology_change(participant->chan, sc->topology, NULL);
673 }
674
675 cleanup:
676 ast_stream_topology_free(joiner_video);
681 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s/%s: Couldn't append streams\n",
682 ast_channel_name(participant->chan), ast_channel_name(joiner->chan));
683 }
684 ast_trace(-1, "%s: Requesting topology change\n", ast_channel_name(participant->chan));
685 res = ast_channel_request_stream_topology_change(participant->chan, sc->topology, NULL);
686 if (res) {
687 ast_trace(-1, "%s/%s: Couldn't request topology change\n",
688 ast_channel_name(participant->chan), ast_channel_name(joiner->chan));
689 }
690 }
691
692 SCOPE_EXIT();
677693 }
678694
679695 /*! \brief Function called when a channel is joined into the bridge */
690706 int pos_id;
691707 int is_announcement = 0;
692708 int samplerate_change;
709 SCOPE_ENTER(3, "%s:\n", ast_channel_name(bridge_channel->chan));
693710
694711 softmix_data = bridge->tech_pvt;
695712 if (!softmix_data) {
696 return -1;
713 SCOPE_EXIT_RTN_VALUE(-1, "No tech_pvt\n");
697714 }
698715
699716 /* Create a new softmix_channel structure and allocate various things on it */
700717 if (!(sc = ast_calloc(1, sizeof(*sc)))) {
701 return -1;
718 SCOPE_EXIT_RTN_VALUE(-1, "Couldn't alloc tech_pvt\n");
702719 }
703720
704721 samplerate_change = softmix_data->internal_rate;
723740 "Could not allocate enough memory.\n", bridge->uniqueid,
724741 ast_channel_name(bridge_channel->chan));
725742 ast_free(sc);
726 return -1;
743 SCOPE_EXIT_RTN_VALUE(-1, "Couldn't do binaural join\n");
727744 }
728745 }
729746 }
752769 }
753770
754771 softmix_poke_thread(softmix_data);
755 return 0;
772 SCOPE_EXIT_RTN_VALUE(0);
756773 }
757774
758775 static int remove_destination_streams(struct ast_stream_topology *topology,
10801097 if (!strcmp(ast_stream_get_name(stream), ast_stream_get_name(original_stream))) {
10811098 struct ast_stream *removed;
10821099
1083 /* Since the participant is still going to be in the bridge we
1084 * change the name so that routing does not attempt to route video
1085 * to this stream.
1086 */
1087 removed = ast_stream_clone(stream, "removed");
1100 removed = ast_stream_clone(stream, NULL);
10881101 if (!removed) {
10891102 return -1;
10901103 }
13821395 case AST_BRIDGE_VIDEO_SFU_REMB_AVERAGE:
13831396 case AST_BRIDGE_VIDEO_SFU_REMB_LOWEST:
13841397 case AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST:
1398 case AST_BRIDGE_VIDEO_SFU_REMB_FORCE:
13851399 /* These will never actually get hit due to being handled by remb_collect_report below */
13861400 break;
13871401 }
14031417 /* We evenly divide the available maximum bitrate across the video sources
14041418 * to this receiver so each source gets an equal slice.
14051419 */
1420
1421 if (bridge->softmix.video_mode.mode_data.sfu_data.remb_behavior == AST_BRIDGE_VIDEO_SFU_REMB_FORCE) {
1422 softmix_data->bitrate = bridge->softmix.video_mode.mode_data.sfu_data.estimated_bitrate;
1423 return;
1424 }
1425
14061426 bitrate = (sc->remb.br_mantissa << sc->remb.br_exp) / AST_VECTOR_SIZE(&sc->video_sources);
14071427
14081428 /* If this receiver has no bitrate yet ignore it */
14471467 case AST_BRIDGE_VIDEO_SFU_REMB_LOWEST_ALL:
14481468 case AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST_ALL:
14491469 /* These will never actually get hit due to being handled by remb_collect_report_all above */
1470 break;
1471 case AST_BRIDGE_VIDEO_SFU_REMB_FORCE:
1472 /* Don't do anything, we've already forced it */
14501473 break;
14511474 }
14521475 }
22532276 struct ast_stream_topology *added_streams;
22542277 struct ast_bridge_channels_list *participants = &bridge->channels;
22552278 struct ast_bridge_channel *participant;
2279 SCOPE_ENTER(3, "%s: OT: %s NT: %s\n", ast_channel_name(bridge_channel->chan),
2280 ast_str_tmp(256, ast_stream_topology_to_str(old_topology, &STR_TMP)),
2281 ast_str_tmp(256, ast_stream_topology_to_str(new_topology, &STR_TMP)));
22562282
22572283 added_streams = ast_stream_topology_alloc();
22582284 if (!added_streams) {
2259 return;
2285 SCOPE_EXIT_LOG(LOG_ERROR, "%s: Couldn't alloc topology\n", ast_channel_name(bridge_channel->chan));
22602286 }
22612287
22622288 /* We go through the old topology comparing it to the new topology to determine what streams
22652291 * Added streams are copied into a topology and added to each other participant while for
22662292 * removed streams we merely store their position and mark them as removed later.
22672293 */
2294 ast_trace(-1, "%s: Checking for state changes\n", ast_channel_name(bridge_channel->chan));
22682295 for (index = 0; index < ast_stream_topology_get_count(sc->topology) && index < ast_stream_topology_get_count(new_topology); ++index) {
22692296 struct ast_stream *old_stream = ast_stream_topology_get_stream(sc->topology, index);
22702297 struct ast_stream *new_stream = ast_stream_topology_get_stream(new_topology, index);
2298 SCOPE_ENTER(4, "%s: Slot: %d Old stream: %s New stream: %s\n", ast_channel_name(bridge_channel->chan),
2299 index, ast_str_tmp(256, ast_stream_to_str(old_stream, &STR_TMP)),
2300 ast_str_tmp(256, ast_stream_to_str(new_stream, &STR_TMP)));
22712301
22722302 /* Ignore all streams that don't carry video and streams that are strictly outgoing destination streams */
22732303 if ((ast_stream_get_type(old_stream) != AST_MEDIA_TYPE_VIDEO && ast_stream_get_type(new_stream) != AST_MEDIA_TYPE_VIDEO) ||
2274 !strncmp(ast_stream_get_name(old_stream), SOFTBRIDGE_VIDEO_DEST_PREFIX,
2304 !strncmp(ast_stream_get_name(new_stream), SOFTBRIDGE_VIDEO_DEST_PREFIX,
22752305 SOFTBRIDGE_VIDEO_DEST_LEN)) {
2276 continue;
2306 SCOPE_EXIT_EXPR(continue, "%s: Stream %d ignored\n", ast_channel_name(bridge_channel->chan), index);
22772307 }
22782308
22792309 if (ast_stream_get_type(old_stream) == AST_MEDIA_TYPE_VIDEO && ast_stream_get_type(new_stream) != AST_MEDIA_TYPE_VIDEO) {
22802310 /* If a stream renegotiates from video to non-video then we need to remove it as a source */
2311 ast_trace(-1, "%s: Stream %d added to remove list\n", ast_channel_name(bridge_channel->chan), index);
22812312 removed_streams[removed_streams_count++] = index;
22822313 } else if (ast_stream_get_type(old_stream) != AST_MEDIA_TYPE_VIDEO && ast_stream_get_type(new_stream) == AST_MEDIA_TYPE_VIDEO) {
22832314 if (ast_stream_get_state(new_stream) != AST_STREAM_STATE_REMOVED) {
22852316 if (append_source_stream(added_streams, ast_channel_name(bridge_channel->chan),
22862317 bridge->softmix.send_sdp_label ? ast_channel_uniqueid(bridge_channel->chan) : NULL,
22872318 new_stream, index)) {
2288 goto cleanup;
2319 SCOPE_EXIT_EXPR(goto cleanup, "%s: Couldn't append source stream %d:%s\n", ast_channel_name(bridge_channel->chan),
2320 index, ast_stream_get_name(new_stream));
22892321 }
2322 ast_trace(-1, "%s: Stream %d changed from non-video to video\n", ast_channel_name(bridge_channel->chan), index);
22902323 }
22912324 } else if (ast_stream_get_state(old_stream) != AST_STREAM_STATE_REMOVED &&
22922325 ast_stream_get_state(new_stream) != AST_STREAM_STATE_SENDRECV && ast_stream_get_state(new_stream) != AST_STREAM_STATE_RECVONLY) {
2326 ast_trace(-1, "%s: Stream %d added to remove list\n", ast_channel_name(bridge_channel->chan), index);
22932327 /* If a stream renegotiates and is removed then we remove it */
22942328 removed_streams[removed_streams_count++] = index;
22952329 } else if ((ast_stream_get_state(old_stream) == AST_STREAM_STATE_REMOVED || ast_stream_get_state(old_stream) == AST_STREAM_STATE_INACTIVE ||
23002334 if (append_source_stream(added_streams, ast_channel_name(bridge_channel->chan),
23012335 bridge->softmix.send_sdp_label ? ast_channel_uniqueid(bridge_channel->chan) : NULL,
23022336 new_stream, index)) {
2303 goto cleanup;
2337 SCOPE_EXIT_EXPR(goto cleanup, "%s: Couldn't append source stream %d:%s\n", ast_channel_name(bridge_channel->chan),
2338 index, ast_stream_get_name(new_stream));
23042339 }
2305 }
2340 ast_trace(-1, "%s: Stream %d:%s changed state from %s to %s\n", ast_channel_name(bridge_channel->chan),
2341 index, ast_stream_get_name(old_stream), ast_stream_state2str(ast_stream_get_state(old_stream)),
2342 ast_stream_state2str(ast_stream_get_state(new_stream)));
2343 } else {
2344 ast_trace(-1, "%s: Stream %d:%s didn't do anything\n", ast_channel_name(bridge_channel->chan),
2345 index, ast_stream_get_name(old_stream));
2346 }
2347 SCOPE_EXIT();
23062348 }
23072349
23082350 /* Any newly added streams that did not take the position of a removed stream
23102352 * removed from the topology but merely marked as removed we can pick up where we
23112353 * left off when comparing the old and new topologies.
23122354 */
2355 ast_trace(-1, "%s: Checking for newly added streams\n", ast_channel_name(bridge_channel->chan));
2356
23132357 for (; index < ast_stream_topology_get_count(new_topology); ++index) {
23142358 struct ast_stream *stream = ast_stream_topology_get_stream(new_topology, index);
2359 SCOPE_ENTER(4, "%s: Checking stream %d:%s\n", ast_channel_name(bridge_channel->chan), index,
2360 ast_stream_get_name(stream));
23152361
23162362 if (!is_video_source(stream)) {
2317 continue;
2363 SCOPE_EXIT_EXPR(continue, "%s: Stream %d:%s is not video source\n", ast_channel_name(bridge_channel->chan),
2364 index, ast_stream_get_name(stream));
23182365 }
23192366
23202367 if (append_source_stream(added_streams, ast_channel_name(bridge_channel->chan),
23212368 bridge->softmix.send_sdp_label ? ast_channel_uniqueid(bridge_channel->chan) : NULL,
23222369 stream, index)) {
2323 goto cleanup;
2324 }
2370 SCOPE_EXIT_EXPR(goto cleanup, "%s: Couldn't append stream %d:%s\n", ast_channel_name(bridge_channel->chan),
2371 index, ast_stream_get_name(stream));
2372 }
2373 SCOPE_EXIT("%s: Added new stream %s\n", ast_channel_name(bridge_channel->chan),
2374 ast_str_tmp(256, ast_stream_to_str(stream, &STR_TMP)));
23252375 }
23262376
23272377 /* We always update the stored topology if we can to reflect what is currently negotiated */
23362386 * other participants.
23372387 */
23382388 if (!removed_streams_count && !ast_stream_topology_get_count(added_streams)) {
2389 ast_trace(-1, "%s: Nothing added or removed\n", ast_channel_name(bridge_channel->chan));
23392390 goto cleanup;
23402391 }
23412392
2393 ast_trace(-1, "%s: Processing adds and removes\n", ast_channel_name(bridge_channel->chan));
23422394 /* Go through each participant adding in the new streams and removing the old ones */
2343 AST_LIST_TRAVERSE(participants, participant, entry) {
2395 AST_LIST_TRAVERSE(participants, participant, entry)
2396 {
2397 struct softmix_channel *participant_sc = participant->tech_pvt;
2398 SCOPE_ENTER(4, "%s/%s: Old participant topology %s\n",
2399 ast_channel_name(bridge_channel->chan),
2400 ast_channel_name(participant->chan),
2401 ast_str_tmp(256, ast_stream_topology_to_str(participant_sc->topology, &STR_TMP)));
2402
23442403 if (participant == bridge_channel) {
2345 continue;
2346 }
2347
2348 sc = participant->tech_pvt;
2404 SCOPE_EXIT_EXPR(continue, "%s/%s: Same channel. Skipping\n",
2405 ast_channel_name(bridge_channel->chan),
2406 ast_channel_name(participant->chan));
2407 }
23492408
23502409 /* We add in all the new streams first so that they do not take the place
23512410 * of any of our removed streams, allowing the remote side to reset the state
23522411 * for each removed stream. */
2353 if (append_all_streams(sc->topology, added_streams)) {
2354 goto cleanup;
2355 }
2412 if (append_all_streams(participant_sc->topology, added_streams)) {
2413 SCOPE_EXIT_EXPR(goto cleanup, "%s/%s: Couldn't append streams\n", ast_channel_name(bridge_channel->chan),
2414 ast_channel_name(participant->chan));
2415 }
2416 ast_trace(-1, "%s/%s: Adding streams %s\n", ast_channel_name(bridge_channel->chan),
2417 ast_channel_name(participant->chan),
2418 ast_str_tmp(256, ast_stream_topology_to_str(added_streams, &STR_TMP)));
23562419
23572420 /* Then we go through and remove any ones that were removed */
2358 for (index = 0; removed_streams_count && index < ast_stream_topology_get_count(sc->topology); ++index) {
2421 for (index = 0;
2422 removed_streams_count && index < ast_stream_topology_get_count(sc->topology); ++index) {
23592423 struct ast_stream *stream = ast_stream_topology_get_stream(sc->topology, index);
23602424 int removed_stream;
23612425
23622426 for (removed_stream = 0; removed_stream < removed_streams_count; ++removed_stream) {
2363 if (is_video_dest(stream, ast_channel_name(bridge_channel->chan), removed_streams[removed_stream])) {
2427 if (is_video_dest(stream, ast_channel_name(bridge_channel->chan),
2428 removed_streams[removed_stream])) {
2429 ast_trace(-1, "%s/%s: Removing stream %s\n",
2430 ast_channel_name(bridge_channel->chan),
2431 ast_channel_name(participant->chan),
2432 ast_str_tmp(256, ast_stream_to_str(stream, &STR_TMP)));
23642433 ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED);
23652434 }
23662435 }
23672436 }
2368
2369 ast_channel_request_stream_topology_change(participant->chan, sc->topology, NULL);
2370 }
2371
2437 ast_channel_request_stream_topology_change(participant->chan, participant_sc->topology, NULL);
2438 SCOPE_EXIT("%s/%s: New participant topology %s\n",
2439 ast_channel_name(bridge_channel->chan),
2440 ast_channel_name(participant->chan),
2441 ast_str_tmp(256, ast_stream_topology_to_str(participant_sc->topology, &STR_TMP)));
2442 }
2443
2444 ast_trace(-1, "%s: New topology %s\n", ast_channel_name(bridge_channel->chan),
2445 ast_str_tmp(256, ast_stream_topology_to_str(sc->topology, &STR_TMP)));
23722446
23732447 cleanup:
23742448 ast_stream_topology_free(added_streams);
2449 SCOPE_EXIT();
23752450 }
23762451
23772452 /*!
23922467 struct ast_vector_int media_types;
23932468 int nths[AST_MEDIA_TYPE_END] = {0};
23942469 int idx;
2470 SCOPE_ENTER(3, "%s: \n", ast_channel_name(bridge_channel->chan));
23952471
23962472 switch (bridge->softmix.video_mode.mode) {
23972473 case AST_BRIDGE_VIDEO_MODE_NONE:
23992475 case AST_BRIDGE_VIDEO_MODE_TALKER_SRC:
24002476 default:
24012477 ast_bridge_channel_stream_map(bridge_channel);
2402 return;
2478 SCOPE_EXIT_RTN("%s: Not in SFU mode\n", ast_channel_name(bridge_channel->chan));
24032479 case AST_BRIDGE_VIDEO_MODE_SFU:
24042480 break;
24052481 }
25092585 }
25102586
25112587 AST_VECTOR_FREE(&media_types);
2588 SCOPE_EXIT_RTN("%s\n", ast_channel_name(bridge_channel->chan));
25122589 }
25132590
25142591 static struct ast_bridge_technology softmix_bridge = {
27992799 int error = 0;
28002800
28012801 if (ast_strlen_zero(addr)) {
2802 ast_log(LOG_WARNING, "invalid calltokenoptional %s\n", addr);
2802 ast_log(LOG_WARNING, "invalid calltokenoptional (null)\n");
28032803 return -1;
28042804 }
28052805
15691569
15701570 static int on_topology_change_response(struct ast_sip_session *session, pjsip_rx_data *rdata)
15711571 {
1572 SCOPE_ENTER(3, "%s: Received response code %d. PT: %s AT: %s\n", ast_sip_session_get_name(session),
1573 rdata->msg_info.msg->line.status.code,
1574 ast_str_tmp(256, ast_stream_topology_to_str(session->pending_media_state->topology, &STR_TMP)),
1575 ast_str_tmp(256, ast_stream_topology_to_str(session->active_media_state->topology, &STR_TMP)));
1576
1577
15721578 if (PJSIP_IS_STATUS_IN_CLASS(rdata->msg_info.msg->line.status.code, 200)) {
15731579 /* The topology was changed to something new so give notice to what requested
15741580 * it so it queries the channel and updates accordingly.
15751581 */
15761582 if (session->channel) {
15771583 ast_queue_control(session->channel, AST_CONTROL_STREAM_TOPOLOGY_CHANGED);
1578 }
1584 SCOPE_EXIT_RTN_VALUE(0, "%s: Queued topology change frame\n", ast_sip_session_get_name(session));
1585 }
1586 SCOPE_EXIT_RTN_VALUE(0, "%s: No channel? Can't queue topology change frame\n", ast_sip_session_get_name(session));
15791587 } else if (300 <= rdata->msg_info.msg->line.status.code) {
15801588 /* The topology change failed, so drop the current pending media state */
15811589 ast_sip_session_media_state_reset(session->pending_media_state);
1582 }
1583
1584 return 0;
1590 SCOPE_EXIT_RTN_VALUE(0, "%s: response code > 300. Resetting pending media state\n", ast_sip_session_get_name(session));
1591 }
1592
1593 SCOPE_EXIT_RTN_VALUE(0, "%s: Nothing to do\n", ast_sip_session_get_name(session));
15851594 }
15861595
15871596 static int send_topology_change_refresh(void *data)
15881597 {
15891598 struct topology_change_refresh_data *refresh_data = data;
1599 struct ast_sip_session *session = refresh_data->session;
15901600 int ret;
1591
1592 ret = ast_sip_session_refresh(refresh_data->session, NULL, NULL, on_topology_change_response,
1601 SCOPE_ENTER(3, "%s: %s\n", ast_sip_session_get_name(session),
1602 ast_str_tmp(256, ast_stream_topology_to_str(refresh_data->media_state->topology, &STR_TMP)));
1603
1604
1605 ret = ast_sip_session_refresh(session, NULL, NULL, on_topology_change_response,
15931606 AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1, refresh_data->media_state);
15941607 refresh_data->media_state = NULL;
15951608 topology_change_refresh_data_free(refresh_data);
15961609
1597 return ret;
1610 SCOPE_EXIT_RTN_VALUE(ret, "%s\n", ast_sip_session_get_name(session));
15981611 }
15991612
16001613 static int handle_topology_request_change(struct ast_sip_session *session,
16261639 size_t device_buf_size;
16271640 int i;
16281641 const struct ast_stream_topology *topology;
1642 struct ast_frame f = {
1643 .frametype = AST_FRAME_CONTROL,
1644 .subclass = {
1645 .integer = condition
1646 }
1647 };
1648 char condition_name[256];
1649 SCOPE_ENTER(3, "%s: Indicated %s\n", ast_channel_name(ast),
1650 ast_frame_subclass2str(&f, condition_name, sizeof(condition_name), NULL, 0));
16291651
16301652 switch (condition) {
16311653 case AST_CONTROL_RINGING:
17301752 ao2_ref(channel->session, +1);
17311753 #ifdef HAVE_PJSIP_INV_SESSION_REF
17321754 if (pjsip_inv_add_ref(channel->session->inv_session) != PJ_SUCCESS) {
1733 ast_log(LOG_ERROR, "Can't increase the session reference counter\n");
17341755 ao2_cleanup(channel->session);
1735 return -1;
1756 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Couldn't increase the session reference counter\n",
1757 ast_channel_name(ast));
17361758 }
17371759 #endif
17381760 if (ast_sip_push_task(channel->session->serializer, update_connected_line_information, channel->session)) {
18221844 break;
18231845 case AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE:
18241846 topology = data;
1847 ast_trace(-1, "%s: New topology: %s\n", ast_channel_name(ast),
1848 ast_str_tmp(256, ast_stream_topology_to_str(topology, &STR_TMP)));
18251849 res = handle_topology_request_change(channel->session, topology);
18261850 break;
18271851 case AST_CONTROL_STREAM_TOPOLOGY_CHANGED:
18411865 struct indicate_data *ind_data = indicate_data_alloc(channel->session, condition, response_code, data, datalen);
18421866
18431867 if (!ind_data) {
1844 return -1;
1868 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Couldn't alloc indicate data\n", ast_channel_name(ast));
18451869 }
18461870 #ifdef HAVE_PJSIP_INV_SESSION_REF
18471871 if (pjsip_inv_add_ref(ind_data->session->inv_session) != PJ_SUCCESS) {
1848 ast_log(LOG_ERROR, "Can't increase the session reference counter\n");
18491872 ao2_cleanup(ind_data);
1850 return -1;
1873 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Couldn't increase the session reference counter\n", ast_channel_name(ast));
18511874 }
18521875 #endif
18531876 if (ast_sip_push_task(channel->session->serializer, indicate, ind_data)) {
1854 ast_log(LOG_NOTICE, "Cannot send response code %d to endpoint %s. Could not queue task properly\n",
1855 response_code, ast_sorcery_object_get_id(channel->session->endpoint));
1877 ast_log(LOG_ERROR, "%s: Cannot send response code %d to endpoint %s. Could not queue task properly\n",
1878 ast_channel_name(ast), response_code, ast_sorcery_object_get_id(channel->session->endpoint));
18561879 #ifdef HAVE_PJSIP_INV_SESSION_REF
18571880 pjsip_inv_dec_ref(ind_data->session->inv_session);
18581881 #endif
18611884 }
18621885 }
18631886
1864 return res;
1887 SCOPE_EXIT_RTN_VALUE(res, "%s\n", ast_channel_name(ast));
18651888 }
18661889
18671890 struct transfer_data {
30343057 RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
30353058 struct transport_info_data *transport_data;
30363059 pjsip_tx_data *packet = NULL;
3060 SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
30373061
30383062 if (session->channel) {
3039 return 0;
3063 SCOPE_EXIT_RTN_VALUE(0, "%s: No channel\n", ast_sip_session_get_name(session));
30403064 }
30413065
30423066 /* Check for a to-tag to determine if this is a reinvite */
30523076 */
30533077 session->defer_terminate = 0;
30543078 ast_sip_session_terminate(session, 400);
3055 return -1;
3079 SCOPE_EXIT_RTN_VALUE(-1, "%s: We have a To tag but no channel. Terminating session\n", ast_sip_session_get_name(session));
30563080 }
30573081
30583082 datastore = ast_sip_session_alloc_datastore(&transport_info, "transport_info");
30593083 if (!datastore) {
3060 return -1;
3084 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Couldn't alloc transport_info datastore\n", ast_sip_session_get_name(session));
30613085 }
30623086
30633087 transport_data = ast_calloc(1, sizeof(*transport_data));
30643088 if (!transport_data) {
3065 return -1;
3089 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Couldn't alloc transport_info\n", ast_sip_session_get_name(session));
30663090 }
30673091 pj_sockaddr_cp(&transport_data->local_addr, &rdata->tp_info.transport->local_addr);
30683092 pj_sockaddr_cp(&transport_data->remote_addr, &rdata->pkt_info.src_addr);
30753099 ast_sip_session_send_response(session, packet);
30763100 }
30773101
3078 ast_log(LOG_ERROR, "Failed to allocate new PJSIP channel on incoming SIP INVITE\n");
3079 return -1;
3102 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Failed to allocate new PJSIP channel on incoming SIP INVITE\n",
3103 ast_sip_session_get_name(session));
30803104 }
30813105 /* channel gets created on incoming request, but we wait to call start
30823106 so other supplements have a chance to run */
3083 return 0;
3107 SCOPE_EXIT_RTN_VALUE(0, "%s\n", ast_sip_session_get_name(session));
30843108 }
30853109
30863110 static int call_pickup_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
31783202 struct pjsip_status_line status = rdata->msg_info.msg->line.status;
31793203 struct ast_control_pvt_cause_code *cause_code;
31803204 int data_size = sizeof(*cause_code);
3205 SCOPE_ENTER(3, "%s: Status: %d\n", ast_sip_session_get_name(session), status.code);
31813206
31823207 if (!session->channel) {
3183 return;
3208 SCOPE_EXIT_RTN("%s: No channel\n", ast_sip_session_get_name(session));
31843209 }
31853210
31863211 /* Build and send the tech-specific cause information */
32003225
32013226 switch (status.code) {
32023227 case 180:
3228 ast_trace(-1, "%s: Queueing RINGING\n", ast_sip_session_get_name(session));
32033229 ast_queue_control(session->channel, AST_CONTROL_RINGING);
32043230 ast_channel_lock(session->channel);
32053231 if (ast_channel_state(session->channel) != AST_STATE_UP) {
32083234 ast_channel_unlock(session->channel);
32093235 break;
32103236 case 183:
3237 ast_trace(-1, "%s: Queueing PROGRESS\n", ast_sip_session_get_name(session));
32113238 if (session->endpoint->ignore_183_without_sdp) {
32123239 pjsip_rdata_sdp_info *sdp = pjsip_rdata_get_sdp_info(rdata);
32133240 if (sdp && sdp->body.ptr) {
32183245 }
32193246 break;
32203247 case 200:
3248 ast_trace(-1, "%s: Queueing ANSWER\n", ast_sip_session_get_name(session));
32213249 ast_queue_control(session->channel, AST_CONTROL_ANSWER);
32223250 break;
32233251 default:
3224 break;
3225 }
3252 ast_trace(-1, "%s: Not queueing anything\n", ast_sip_session_get_name(session));
3253 break;
3254 }
3255
3256 SCOPE_EXIT_RTN("%s\n", ast_sip_session_get_name(session));
32263257 }
32273258
32283259 static int chan_pjsip_incoming_ack(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
32293260 {
3261 SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
3262
32303263 if (rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD) {
32313264 if (session->endpoint->media.direct_media.enabled && session->channel) {
3265 ast_trace(-1, "%s: Queueing SRCCHANGE\n", ast_sip_session_get_name(session));
32323266 ast_queue_control(session->channel, AST_CONTROL_SRCCHANGE);
32333267 }
32343268 }
3235 return 0;
3269 SCOPE_EXIT_RTN_VALUE(0, "%s\n", ast_sip_session_get_name(session));
32363270 }
32373271
32383272 static int update_devstate(void *obj, void *arg, int flags)
2307623076 char tmp[512];
2307723077 char *c;
2307823078 char oldnonce[256];
23079 int start = 0;
2307923080
2308023081 /* table of recognised keywords, and places where they should be copied */
2308123082 const struct x {
2309023091 { NULL, 0 },
2309123092 };
2309223093
23093 ast_copy_string(tmp, sip_get_header(req, header), sizeof(tmp));
23094 if (ast_strlen_zero(tmp))
23095 return -1;
23094 do {
23095 ast_copy_string(tmp, __get_header(req, header, &start), sizeof(tmp));
23096 if (ast_strlen_zero(tmp))
23097 return -1;
23098 } while (strcasestr(tmp, "algorithm=") && !strcasestr(tmp, "algorithm=MD5"));
2309623099 if (strncasecmp(tmp, "Digest ", strlen("Digest "))) {
2309723100 ast_log(LOG_WARNING, "missing Digest.\n");
2309823101 return -1;
2880428807 if (start && !found_supported) {
2880528808 /* Format requested that we do not support */
2880628809 transmit_response(p, "406 Not Acceptable", req);
28807 ast_debug(2, "Received SIP mailbox subscription for unknown format: %s\n", accept);
28810 ast_debug(2, "Received SIP mailbox subscription for unknown format\n");
2880828811 pvt_set_needdestroy(p, "unknown format");
2880928812 if (authpeer) {
2881028813 sip_unref_peer(authpeer, "sip_unref_peer, from handle_request_subscribe (authpeer 3)");
3038430387
3038530388 p_hdrval = sip_get_header(rsp, "Min-SE");
3038630389 if (ast_strlen_zero(p_hdrval)) {
30387 ast_log(LOG_WARNING, "422 response without a Min-SE header %s\n", p_hdrval);
30390 ast_log(LOG_WARNING, "422 response without a Min-SE header\n");
3038830391 return;
3038930392 }
3039030393 rtn = parse_minse(p_hdrval, &minse);
263263 ; the highest maximum bitrate is forwarded to the sender. If set to "average_all" a single average
264264 ; is generated from every receiver and the same value is sent to every sender. If set to
265265 ; "lowest_all" the lowest maximum bitrate of all receivers is sent to every sender. If set to
266 ; "highest_all" the highest maximum bitrate of all receivers is sent to every sender. This
267 ; defaults to "average".
266 ; "highest_all" the highest maximum bitrate of all receivers is sent to every sender.
267 ; When set to "force", the value set in remb_estimated_bitrate is sent to every sender.
268 ; This defaults to "average".
269 ;remb_estimated_bitrate=0 ; When remb_behavior is set to 'force', this options sets the estimated bitrate
270 ; (in bits per second) sent to each participant in REMB reports.
268271
269272 ;enable_events=no ; If enabled, recipients who joined the bridge via a channel driver
270273 ; that supports Enhanced Messaging (currently only chan_pjsip) will
2525 ; By default, this is 2.
2626 ;transferdialattempts = 3 ; Number of times that a transferer may attempt to dial an extension before
2727 ; being kicked back to the original call.
28 ;transferretrysound = "beep" ; Sound to play when a transferer fails to dial a valid extension.
29 ;transferinvalidsound = "beeperr" ; Sound to play when a transferer fails to dial a valid extension and is out of retries.
28 ;transferretrysound = beep ; Sound to play when a transferer fails to dial a valid extension.
29 ;transferinvalidsound = beeperr ; Sound to play when a transferer fails to dial a valid extension and is out of retries.
3030 ;atxferabort = *1 ; cancel the attended transfer
3131 ;atxfercomplete = *2 ; complete the attended transfer, dropping out of the call
3232 ;atxferthreeway = *3 ; complete the attended transfer, but stay in the call. This will turn the call into a multi-party bridge
1212 ; valid mode options:
1313 ; files -- read files from a directory in any Asterisk supported
1414 ; media format
15 ; playlist -- provide a fixed list of filenames or URLs to play
15 ; playlist -- provide a fixed list of filenames or HTTP(S) URLs to play
1616 ; quietmp3 -- default
1717 ; mp3 -- loud
1818 ; mp3nb -- unbuffered
5555 ; Each entry must be one of:
5656 ;
5757 ; * An absolute path to the file to be played, without an extension.
58 ; * A URL
58 ; * An HTTP(S) URL
5959 ;
6060 ; The entries are played in the order in which they appear in the
6161 ; configuration. The 'sort' option is not used for this mode.
332332 ;device_state_busy_at=1
333333 ;allow_subscribe=yes
334334 ;sub_min_expiry=30
335 ;
336 ; STIR/SHAKEN support.
337 ;
338 ;stir_shaken=no
335339
336340 ;[6001]
337341 ;type=auth
855859 ; chan_sip and prevents these 183 responses from
856860 ; being forwarded.
857861 ; (default: no)
862 ;stir_shaken =
863 ; If this is enabled, STIR/SHAKEN operations will be
864 ; performed on this endpoint. This includes inbound
865 ; and outbound INVITEs. On an inbound INVITE, Asterisk
866 ; will check for an Identity header and attempt to
867 ; verify the call. On an outbound INVITE, Asterisk will
868 ; add an Identity header that others can use to verify
869 ; calls from this endpoint. Additional configuration is
870 ; done in stir_shaken.conf.
871 ; The STIR_SHAKEN dialplan function must be used to get
872 ; the verification results on inbound INVITEs. Nothing
873 ; happens to the call if verification fails; it's up to
874 ; you to determine what to do with the results.
875 ; (default: no)
858876
859877 ;==========================AUTH SECTION OPTIONS=========================
860878 ;[auth]
55 proxytype=http
66 proxyport=8001
77 ;proxyuserpwd=asterisk:asteriskrocks
8 ;failurecodes=404,408,503
0 ;
1 ; This file is used by the res_stir_shaken module to configure parameters
2 ; used for STIR/SHAKEN.
3 ;
4 ;
5 ; [general]
6 ;
7 ; File path to the certificate authority certificate
8 ;ca_file=/etc/asterisk/stir/ca.crt
9 ;
10 ; File path to a chain of trust
11 ;ca_path=/etc/asterisk/stir/ca
12 ;
13 ; Maximum size to use for caching public keys
14 ;cache_max_size=1000
15 ;
16 ; Maximum time (in seconds) to wait to CURL certificates
17 ;curl_timeout=2
18 ;
19 ; Amount of time (in seconds) a signature is valid for
20 ;signature_timeout=15
21 ;
22 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23 ;
24 ; A certificate store is used to examine, and load all certificates found in a
25 ; given directory. When using this type the public key URL is generated based
26 ; upon the filename, and variable substitution.
27 ;[certificates]
28 ;
29 ; type must be "store"
30 ;type=store
31 ;
32 ; Path to a directory containing certificates
33 ;path=/etc/asterisk/stir
34 ;
35 ; URL to the public key(s). Must contain variable '${CERTIFICATE}' used for
36 ; substitution
37 ;public_key_url=http://mycompany.com/${CERTIFICATE}.pub
38 ;
39 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
40 ;
41 ; Individual certificates are declared by using the certificate type.
42 ;[alice]
43 ;
44 ; type must be "certificate"
45 ;type=certificate
46 ;
47 ; File path to a certificate
48 ;path=/etc/asterisk/stir/alice.crt
49 ;
50 ; URL to the public key
51 ;public_key_url=http://mycompany.com/alice.pub
52 ;
53 ; The caller ID number to match on
54 ;caller_id_number=1234567
55 ;
56 ; Must have an attestation of A, B, or C
57 ;attestation=C
58 ;
59 ; The origination identifier for the certificate
60 ;origid=MyAsterisk
2951129511
2951229512
2951329513
29514 for ver in 5.3 5.2 5.1; do
29514 for ver in 5.4 5.3 5.2 5.1; do
2951529515
2951629516 if test "x${PBX_LUA}" != "x1" -a "${USE_LUA}" != "no"; then
2951729517 pbxlibdir=""
25522552 fi
25532553 AST_EXT_LIB_CHECK([OPUSFILE], [opusfile], [op_open_callbacks], [opus/opusfile.h], [], [$__opus_include])
25542554
2555 for ver in 5.3 5.2 5.1; do
2555 for ver in 5.4 5.3 5.2 5.1; do
25562556 AST_EXT_LIB_CHECK([LUA], lua${ver}, [luaL_newstate], lua${ver}/lua.h, [-lm])
25572557 if test "x${PBX_LUA}" = "x1" ; then
25582558 if test x"${LUA_DIR}" = x; then
0 """increse reg server size
1
2 Revision ID: 1ae0609b6646
3 Revises: 79290b511e4b
4 Create Date: 2020-08-31 13:50:19.772439
5
6 """
7
8 # revision identifiers, used by Alembic.
9 revision = '1ae0609b6646'
10 down_revision = '79290b511e4b'
11
12 from alembic import op
13 import sqlalchemy as sa
14
15
16 def upgrade():
17 op.alter_column('ps_contacts', 'reg_server', type_=sa.String(255))
18
19
20 def downgrade():
21 op.alter_column('ps_contacts', 'reg_server', type_=sa.String(20))
0 """add stir shaken
1
2 Revision ID: 61797b9fced6
3 Revises: fbb7766f17bc
4 Create Date: 2020-06-29 11:52:59.946929
5
6 """
7
8 # revision identifiers, used by Alembic.
9 revision = '61797b9fced6'
10 down_revision = 'e658c26033ca'
11
12 from alembic import op
13 import sqlalchemy as sa
14 from sqlalchemy.dialects.postgresql import ENUM
15
16 YESNO_NAME = 'yesno_values'
17 YESNO_VALUES = ['yes', 'no']
18
19 AST_BOOL_NAME = 'ast_bool_values'
20 AST_BOOL_VALUES = [ '0', '1',
21 'off', 'on',
22 'false', 'true',
23 'no', 'yes' ]
24
25 def upgrade():
26 ast_bool_values = ENUM(*AST_BOOL_VALUES, name=AST_BOOL_NAME, create_type=False)
27 op.add_column('ps_endpoints', sa.Column('stir_shaken', ast_bool_values))
28
29 def downgrade():
30 op.drop_column('ps_endpoints', 'stir_shaken')
0 """create history info flag
1
2 Revision ID: e658c26033ca
3 Revises: 1ae0609b6646
4 Create Date: 2020-08-13 10:53:21.032591
5
6 """
7
8 # revision identifiers, used by Alembic.
9 revision = 'e658c26033ca'
10 down_revision = '1ae0609b6646'
11
12 from alembic import op
13 import sqlalchemy as sa
14 from sqlalchemy.dialects.postgresql import ENUM
15
16 AST_BOOL_NAME = 'ast_bool_values'
17 # We'll just ignore the n/y and f/t abbreviations as Asterisk does not write
18 # those aliases.
19 AST_BOOL_VALUES = [ '0', '1',
20 'off', 'on',
21 'false', 'true',
22 'no', 'yes' ]
23
24 def upgrade():
25 ############################# Enums ##############################
26
27 # ast_bool_values has already been created, so use postgres enum object
28 # type to get around "already created" issue - works okay with mysql
29 ast_bool_values = ENUM(*AST_BOOL_VALUES, name=AST_BOOL_NAME, create_type=False)
30
31 op.add_column('ps_endpoints', sa.Column('send_history_info', ast_bool_values))
32
33
34 def downgrade():
35 if op.get_context().bind.dialect.name == 'mssql':
36 op.drop_constraint('ck_ps_endpoints_send_history_info_ast_bool_values','ps_endpoints')
37 op.drop_column('ps_endpoints', 'send_history_info')
12551255
12561256 UPDATE alembic_version SET version_num='79290b511e4b' WHERE alembic_version.version_num = 'fbb7766f17bc';
12571257
1258 -- Running upgrade 79290b511e4b -> 1ae0609b6646
1259
1260 ALTER TABLE ps_contacts MODIFY reg_server VARCHAR(255) NULL;
1261
1262 UPDATE alembic_version SET version_num='1ae0609b6646' WHERE alembic_version.version_num = '79290b511e4b';
1263
1264 -- Running upgrade 1ae0609b6646 -> e658c26033ca
1265
1266 ALTER TABLE ps_endpoints ADD COLUMN send_history_info ENUM('0','1','off','on','false','true','no','yes');
1267
1268 UPDATE alembic_version SET version_num='e658c26033ca' WHERE alembic_version.version_num = '1ae0609b6646';
1269
1270 -- Running upgrade e658c26033ca -> 61797b9fced6
1271
1272 ALTER TABLE ps_endpoints ADD COLUMN stir_shaken ENUM('0','1','off','on','false','true','no','yes');
1273
1274 UPDATE alembic_version SET version_num='61797b9fced6' WHERE alembic_version.version_num = 'e658c26033ca';
1275
13571357
13581358 UPDATE alembic_version SET version_num='79290b511e4b' WHERE alembic_version.version_num = 'fbb7766f17bc';
13591359
1360 -- Running upgrade 79290b511e4b -> 1ae0609b6646
1361
1362 ALTER TABLE ps_contacts ALTER COLUMN reg_server TYPE VARCHAR(255);
1363
1364 UPDATE alembic_version SET version_num='1ae0609b6646' WHERE alembic_version.version_num = '79290b511e4b';
1365
1366 -- Running upgrade 1ae0609b6646 -> e658c26033ca
1367
1368 ALTER TABLE ps_endpoints ADD COLUMN send_history_info ast_bool_values;
1369
1370 UPDATE alembic_version SET version_num='e658c26033ca' WHERE alembic_version.version_num = '1ae0609b6646';
1371
1372 -- Running upgrade e658c26033ca -> 61797b9fced6
1373
1374 ALTER TABLE ps_endpoints ADD COLUMN stir_shaken ast_bool_values;
1375
1376 UPDATE alembic_version SET version_num='61797b9fced6' WHERE alembic_version.version_num = 'e658c26033ca';
1377
13601378 COMMIT;
13611379
2323 PACKAGES_DEBIAN="$PACKAGES_DEBIAN libedit-dev libjansson-dev libsqlite3-dev uuid-dev libxml2-dev"
2424 # Asterisk: for addons:
2525 PACKAGES_DEBIAN="$PACKAGES_DEBIAN libspeex-dev libspeexdsp-dev libogg-dev libvorbis-dev libasound2-dev portaudio19-dev libcurl4-openssl-dev xmlstarlet bison flex"
26 PACKAGES_DEBIAN="$PACKAGES_DEBIAN libpq-dev unixodbc-dev libneon27-dev libgmime-2.6-dev liblua5.2-dev liburiparser-dev libxslt1-dev libssl-dev"
26 PACKAGES_DEBIAN="$PACKAGES_DEBIAN libpq-dev unixodbc-dev libneon27-dev libgmime-2.6-dev libgmime-3.0-dev liblua5.2-dev liburiparser-dev libxslt1-dev libssl-dev"
2727 PACKAGES_DEBIAN="$PACKAGES_DEBIAN libvpb-dev libmysqlclient-dev libbluetooth-dev libradcli-dev freetds-dev libosptk-dev libjack-jackd2-dev bash libcap-dev"
2828 PACKAGES_DEBIAN="$PACKAGES_DEBIAN libsnmp-dev libiksemel-dev libcorosync-common-dev libcpg-dev libcfg-dev libnewt-dev libpopt-dev libical-dev libspandsp-dev"
2929 PACKAGES_DEBIAN="$PACKAGES_DEBIAN libresample1-dev libc-client2007e-dev binutils-dev libsrtp0-dev libsrtp2-dev libgsm1-dev doxygen graphviz zlib1g-dev libldap2-dev"
55 """
66
77 import re
8 import glob
89 import itertools
910
1011 from astdicts import OrderedDict
5556 Use self.id as means of determining equality
5657 """
5758 return self.id == other.id
59
60 def __lt__(self, other):
61 """
62 Use self.id as means of determining equality
63 """
64 return self.id < other.id
65
66 def __gt__(self, other):
67 """
68 Use self.id as means of determining equality
69 """
70 return self.id > other.id
71
72 def __le__(self, other):
73 """
74 Use self.id as means of determining equality
75 """
76 return self.id <= other.id
77
78 def __ge__(self, other):
79 """
80 Use self.id as means of determining equality
81 """
82 return self.id >= other.id
5883
5984 def get(self, key, from_self=True, from_templates=True,
6085 from_defaults=True):
214239 included filename, otherwise None.
215240 """
216241
217 match = re.match('^#include\s*[<"]?(.*)[>"]?$', line)
218 return match.group(1) if match else None
242 match = re.match('^#include\s*([^;]+).*$', line)
243 if match:
244 trimmed = match.group(1).rstrip()
245 quoted = re.match('^"([^"]+)"$', trimmed)
246 if quoted:
247 return quoted.group(1)
248 bracketed = re.match('^<([^>]+)>$', trimmed)
249 if bracketed:
250 return bracketed.group(1)
251 return trimmed
252 return None
219253
220254
221255 def try_section(line):
457491
458492 include_name = try_include(line)
459493 if include_name:
460 parser = self.add_include(include_name)
461 parser.read(include_name, sect)
494 for incl in sorted(glob.iglob(include_name)):
495 parser = self.add_include(incl)
496 parser.read(incl, sect)
462497 continue
463498
464499 section, is_template, templates = try_section(line)
186186 </enum>
187187 </enumlist>
188188 </enum>
189 <enum name="failurecodes">
190 <para>A comma separated list of HTTP response codes to be treated as errors</para>
191 </enum>
189192 </enumlist>
190193 </parameter>
191194 </syntax>
204207 ((LIBCURL_VERSION_MAJOR > (a)) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR > (b))) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR == (b)) && (LIBCURL_VERSION_PATCH >= (c))))
205208
206209 #define CURLOPT_SPECIAL_HASHCOMPAT ((CURLoption) -500)
210
211 #define CURLOPT_SPECIAL_FAILURE_CODE 999
207212
208213 static void curlds_free(void *data);
209214
317322 } else if (!strcasecmp(name, "hashcompat")) {
318323 *key = CURLOPT_SPECIAL_HASHCOMPAT;
319324 *ot = OT_ENUM;
325 } else if (!strcasecmp(name, "failurecodes")) {
326 *key = CURLOPT_SPECIAL_FAILURE_CODE;
327 *ot = OT_STRING;
320328 } else {
321329 return -1;
322330 }
654662 static int acf_curl_helper(struct ast_channel *chan, struct curl_args *args)
655663 {
656664 struct ast_str *escapebuf = ast_str_thread_get(&thread_escapebuf, 16);
657 int ret = -1;
665 int ret = 0;
666 long http_code = 0; /* read curl response */
667 size_t i;
668 struct ast_vector_int hasfailurecode = { NULL };
669 char *failurecodestrings,*found;
658670 CURL **curl;
659671 struct curl_settings *cur;
660672 struct curl_slist *headers = NULL;
681693 ast_autoservice_start(chan);
682694 }
683695
696 AST_VECTOR_INIT(&hasfailurecode, 0); /*Initialize vector*/
684697 AST_LIST_LOCK(&global_curl_info);
685698 AST_LIST_TRAVERSE(&global_curl_info, cur, list) {
686699 if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) {
687700 hashcompat = (long) cur->value;
688701 } else if (cur->key == CURLOPT_HTTPHEADER) {
689702 headers = curl_slist_append(headers, (char*) cur->value);
703 } else if (cur->key == CURLOPT_SPECIAL_FAILURE_CODE) {
704 failurecodestrings = (char*) cur->value;
705 while( (found = strsep(&failurecodestrings, ",")) != NULL) {
706 AST_VECTOR_APPEND(&hasfailurecode, atoi(found));
707 }
690708 } else {
691709 curl_easy_setopt(*curl, cur->key, cur->value);
692710 }
705723 hashcompat = (long) cur->value;
706724 } else if (cur->key == CURLOPT_HTTPHEADER) {
707725 headers = curl_slist_append(headers, (char*) cur->value);
726 } else if (cur->key == CURLOPT_SPECIAL_FAILURE_CODE) {
727 failurecodestrings = (char*) cur->value;
728 while( (found = strsep(&failurecodestrings, ",")) != NULL) {
729 AST_VECTOR_APPEND(&hasfailurecode, atoi(found));
730 }
708731 } else {
709732 curl_easy_setopt(*curl, cur->key, cur->value);
710733 }
720743 curl_easy_setopt(*curl, CURLOPT_POSTFIELDS, args->postdata);
721744 }
722745
723 if (headers) {
724 curl_easy_setopt(*curl, CURLOPT_HTTPHEADER, headers);
725 }
746 /* Always assign the headers - even when NULL - in case we had
747 * custom headers the last time we used this shared cURL
748 * instance */
749 curl_easy_setopt(*curl, CURLOPT_HTTPHEADER, headers);
726750
727751 /* Temporarily assign a buffer for curl to write errors to. */
728752 curl_errbuf[0] = curl_errbuf[CURL_ERROR_SIZE] = '\0';
737761 * here, but the source allows it. See: "typecheck: allow NULL to unset
738762 * CURLOPT_ERRORBUFFER" (62bcf005f4678a93158358265ba905bace33b834). */
739763 curl_easy_setopt(*curl, CURLOPT_ERRORBUFFER, (char*)NULL);
764 curl_easy_getinfo (*curl, CURLINFO_RESPONSE_CODE, &http_code);
765
766 for (i = 0; i < AST_VECTOR_SIZE(&hasfailurecode); ++i) {
767 if (http_code == AST_VECTOR_GET(&hasfailurecode,i)){
768 ast_log(LOG_NOTICE, "%s%sCURL '%s' returned response code (%ld).\n",
769 chan ? ast_channel_name(chan) : "",
770 chan ? ast_channel_name(chan) : ": ",
771 args->url,
772 http_code);
773 ret=-1;
774 break;
775 }
776 }
777 AST_VECTOR_FREE(&hasfailurecode); /* Release the vector*/
740778
741779 if (store) {
742780 AST_LIST_UNLOCK(list);
773811 ast_free(fields);
774812 ast_free(values);
775813 }
776 ret = 0;
777814 }
778815
779816 if (chan) {
883920 " ssl_verifypeer - Whether to verify the peer certificate (boolean)\n"
884921 " hashcompat - Result data will be compatible for use with HASH()\n"
885922 " - if value is \"legacy\", will translate '+' to ' '\n"
923 " failurecodes - A comma separated list of HTTP response codes to be treated as errors\n"
886924 "",
887925 .read = acf_curlopt_read,
888926 .read2 = acf_curlopt_read2,
11801180 static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_query **query)
11811181 {
11821182 const char *tmp;
1183 const char *tmp2;
1183 const char *tmp2 = NULL;
11841184 int i;
11851185
11861186 if (!cfg || !catg) {
139139 AST_BRIDGE_VIDEO_SFU_REMB_LOWEST_ALL,
140140 /*! The highest reported bitrate from all channels in the bridge is forwarded to each sender */
141141 AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST_ALL,
142 /*! Force the REMB estimated bitrate to a specified value */
143 AST_BRIDGE_VIDEO_SFU_REMB_FORCE,
142144 };
143145
144146 /*! \brief This is used for selective forwarding unit configuration */
147149 unsigned int remb_send_interval;
148150 /*! How the combined REMB report is generated */
149151 enum ast_bridge_video_sfu_remb_behavior remb_behavior;
152 /*! The estimated bitrate when behavior is "force" */
153 float estimated_bitrate;
150154 };
151155
152156 /*! \brief Data structure that defines a video source mode */
988992 void ast_brige_set_remb_behavior(struct ast_bridge *bridge, enum ast_bridge_video_sfu_remb_behavior behavior);
989993
990994 /*!
995 * \brief Force the REMB report estimated bitrate to a specific max value
996 *
997 * \param bridge Bridge to set the REMB behavior on
998 * \param estimated_bitrate The estimated bitrate in bits per second
999 *
1000 * \note This can only be called when the bridge has been set to the SFU video mode.
1001 */
1002 void ast_bridge_set_remb_estimated_bitrate(struct ast_bridge *bridge, float estimated_bitrate);
1003
1004 /*!
9911005 * \brief Update information about talker energy for talker src video mode.
9921006 */
9931007 void ast_bridge_update_talker_src_video_mode(struct ast_bridge *bridge, struct ast_channel *chan, int talker_energy, int is_keyfame);
193193 };
194194
195195 /*!
196 * \brief Get a ref to the bridge_channel's ast_channel
197 *
198 * \param bridge_channel The bridge channel
199 *
200 * \note The returned channel NEEDS to be unref'd once you are done with it. In general, this
201 * function is best used when accessing the bridge_channel chan from outside of a bridging
202 * thread.
203 *
204 * \retval ref'd ast_channel on success
205 * \retval NULL otherwise
206 */
207 struct ast_channel *ast_bridge_channel_get_chan(struct ast_bridge_channel *bridge_channel);
208
209 /*!
196210 * \brief Try locking the bridge_channel.
197211 *
198212 * \param bridge_channel What to try locking
313313 */
314314 int ast_format_cache_is_slinear(struct ast_format *format);
315315
316 /*!
317 * \brief Retrieve a format from the cache by its codec
318 *
319 * \param codec The codec to search by
320 *
321 * \retval non-NULL if found
322 * \retval NULL if not found
323 *
324 * \note The returned format has its reference count incremented. It must be
325 * dropped using ao2_ref or ao2_cleanup.
326 */
327 struct ast_format *ast_format_cache_get_by_codec(const struct ast_codec *codec);
328
316329 #endif /* _AST_FORMAT_CACHE_H */
662662 */
663663 #define ast_trace_raw(level, indent_type, ...) \
664664 ast_debug(level < 0 ? __scope_level : level, " " __VA_ARGS__); \
665 if (TRACE_ATLEAST(level)) { \
665 if (TRACE_ATLEAST(level < 0 ? __scope_level : level)) { \
666666 __ast_trace(__FILE__, __LINE__, __PRETTY_FUNCTION__, indent_type, 0, " " __VA_ARGS__); \
667667 }
668668
677677 */
678678 #define ast_trace(level, ...) \
679679 ast_debug(level < 0 ? __scope_level : level, " " __VA_ARGS__); \
680 if (TRACE_ATLEAST(level)) { \
680 if (TRACE_ATLEAST(level < 0 ? __scope_level : level)) { \
681681 __ast_trace(__FILE__, __LINE__, __PRETTY_FUNCTION__, AST_TRACE_INDENT_SAME, 0, " " __VA_ARGS__); \
682682 }
683683
0 /*
1 * Asterisk -- An open source telephony toolkit.
2 *
3 * Copyright (C) 2020, Sangoma Technologies Corporation
4 *
5 * Kevin Harwell <kharwell@sangoma.com>
6 *
7 * See http://www.asterisk.org for more information about
8 * the Asterisk project. Please do not directly contact
9 * any of the maintainers of this project for assistance;
10 * the project provides a web site, mailing lists and IRC
11 * channels for your use.
12 *
13 * This program is free software, distributed under the terms of
14 * the GNU General Public License Version 2. See the LICENSE file
15 * at the top of the source tree.
16 */
17 #ifndef ASTERISK_LOGGER_CATEGORY_H
18 #define ASTERISK_LOGGER_CATEGORY_H
19
20 #include "asterisk/logger.h"
21
22 /*!
23 * Logger category is enabled
24 */
25 #define AST_LOG_CATEGORY_ENABLED -1
26
27 /*!
28 * Logger category is disabled
29 */
30 #define AST_LOG_CATEGORY_DISABLED 0
31
32 /*!
33 * \brief Load/Initialize system wide logger category functionality
34 *
35 * \retval 0 Success, -1 Failure
36 *
37 * \since 16.14
38 * \since 17.8
39 * \since 18.0
40 */
41 int ast_logger_category_load(void);
42
43 /*!
44 * \brief Unload system wide logger category functionality
45 *
46 * \retval 0 Success, -1 Failure
47 *
48 * \since 16.14
49 * \since 17.8
50 * \since 18.0
51 */
52 int ast_logger_category_unload(void);
53
54 /*!
55 * \brief Register a debug level logger category
56 *
57 * \param name The name of the category
58 * \param id The unique id of the category
59 *
60 * \retval 0 if failed to register/retrieve an id. Otherwise it returns the id
61 * for the registered category.
62 *
63 * \since 16.14
64 * \since 17.8
65 * \since 18.0
66 */
67 uintmax_t ast_debug_category_register(const char *name);
68
69 /*!
70 * \brief Un-register a debug level logger category
71 *
72 * \retval 0 Success, -1 Failure
73 *
74 * \since 16.14
75 * \since 17.8
76 * \since 18.0
77 */
78 int ast_debug_category_unregister(const char *name);
79
80 /*!
81 * \brief Set the debug category's sublevel
82 *
83 * Statements are output at a specified sublevel. Typically any number greater
84 * than or equal to 0. Other acceptable values include AST_LOG_CATEGORY_ENABLED
85 * and AST_LOG_CATEGORY_DISABLED.
86 *
87 * \param name The name of the category
88 * \param sublevel The debug sublevel output number
89 *
90 * \retval 0 Success, -1 Failure
91 *
92 * \since 16.14
93 * \since 17.8
94 * \since 18.0
95 */
96 int ast_debug_category_set_sublevel(const char *name, int sublevel);
97
98 /*!
99 * \brief Set one or more debug category's sublevel.
100 *
101 * Accepts an array of category names, and optional associated sublevels. Sublevels can
102 * be associated with a name by using a ':' as a separator. For example:
103 *
104 * <category name>:<category sublevel>
105 *
106 * The given default sublevel is used if no sublevel is associated with a name.
107 *
108 * \param names An array of category names
109 * \param size The size of the array (number of elements)
110 * \param default_sublevel The sublevel value to use if one is not associated with a name
111 *
112 * \retval 0 Success, -1 Failure
113 *
114 * \since 16.14
115 * \since 17.8
116 * \since 18.0
117 */
118 int ast_debug_category_set_sublevels(const char * const *names, size_t size, int default_sublevel);
119
120 /*!
121 * \brief Add a unique (no duplicates) result to a request for completion for debug categories.
122 *
123 * \param argv A list of already completed options
124 * \param argc The number of already completed options
125 * \param word The word to complete
126 * \param state The state
127 *
128 * \retval 0 Success, -1 Failure
129 *
130 * \since 16.14
131 * \since 17.8
132 * \since 18.0
133 */
134 char *ast_debug_category_complete(const char * const *argv, int argc, const char *word, int state);
135
136 /*!
137 * \brief Check if a debug category is enabled, and allowed to output
138 *
139 * \note If more than one id is specified then if even one is allowed "true"
140 * is returned.
141 *
142 * \param sublevel Current set sublevel must be this sublevel or less
143 * \param ids One or more unique category ids to check
144 *
145 * \retval 1 if allowed, 0 if not allowed
146 *
147 * \since 16.14
148 * \since 17.8
149 * \since 18.0
150 */
151 int ast_debug_category_is_allowed(int sublevel, uintmax_t ids);
152
153 /*!
154 * \brief Log for a debug category.
155 *
156 * This will output log data for debug under the following conditions:
157 *
158 * 1. The specified sublevel is at, or below the current system debug level
159 * 2. At least one of the given category ids is enabled AND
160 * a. The category sublevel is enabled OR the given sublevel is at, or
161 * below a category's specified sublevel.
162 *
163 * \param sublevel The minimum level to output at
164 * \param ids One or more unique category ids to output for
165 *
166 * \since 16.14
167 * \since 17.8
168 * \since 18.0
169 */
170 #define ast_debug_category(sublevel, ids, ...) \
171 do { \
172 if (DEBUG_ATLEAST(sublevel) || ast_debug_category_is_allowed(sublevel, ids)) { \
173 ast_log(AST_LOG_DEBUG, __VA_ARGS__); \
174 } \
175 } while (0)
176
177 #endif /* ASTERISK_LOGGER_CATEGORY_H */
491491 * \param callerid pattern to match CallerID, or NULL to match any CallerID
492492 * \param application application to run on the extension with that priority level
493493 * \param data data to pass to the application
494 * \param datad
494 * \param datad a pointer to a function that will deallocate \c data when needed
495 * or NULL if \c data does not need to be freed.
495496 * \param registrar who registered the extension
497 *
498 * \note On any failure, the function pointed to by \c datap will be called and passed the
499 * \c data pointer.
496500 *
497501 * \retval 0 success
498502 * \retval -1 failure
519523 * \since 12.0.0
520524 *
521525 * \note con must be write locked prior to calling. For details about the arguments,
522 * check ast_add_extension2()
526 * check ast_add_extension()
523527 */
524528 int ast_add_extension2_nolock(struct ast_context *con, int replace, const char *extension,
525529 int priority, const char *label, const char *callerid,
7373
7474 /*! \brief Maximum number of ciphers supported for a TLS transport */
7575 #define SIP_TLS_MAX_CIPHERS 64
76
77 /*! Maximum number of challenges before assuming that we are in a loop */
78 #define MAX_RX_CHALLENGES 10
7679
7780 /*!
7881 * \brief Structure for SIP transport information
579582 unsigned int send_diversion;
580583 /*! When performing connected line update, which method should be used */
581584 enum ast_sip_session_refresh_method refresh_method;
585 /*! Do we add History-Info headers to applicable outgoing requests/responses? */
586 unsigned int send_history_info;
582587 };
583588
584589 /*!
831836 unsigned int send_connected_line;
832837 /*! Ignore 183 if no SDP is present */
833838 unsigned int ignore_183_without_sdp;
839 /*! Enable STIR/SHAKEN support on this endpoint */
840 unsigned int stir_shaken;
834841 };
835842
836843 /*! URI parameter for symmetric transport */
17011708 AST_SIP_SCHED_TASK_VARIABLE = (1 << 0),
17021709
17031710 /*!
1711 * Run just once.
1712 * Return values are ignored.
1713 */
1714 AST_SIP_SCHED_TASK_ONESHOT = (1 << 6),
1715
1716 /*!
17041717 * The task data is not an AO2 object.
17051718 */
17061719 AST_SIP_SCHED_TASK_DATA_NOT_AO2 = (0 << 1),
18221835 struct timeval *when_queued, struct timeval *last_start, struct timeval *last_end);
18231836
18241837 /*!
1838 * \brief Gets the queued, last start, last_end, time left, interval, next run
1839 * \since 16.15.0
1840 * \since 18.1.0
1841 *
1842 * \param schtd The task structure pointer
1843 * \param[out] when_queued Pointer to a timeval structure to contain the time when queued
1844 * \param[out] last_start Pointer to a timeval structure to contain the time when last started
1845 * \param[out] last_end Pointer to a timeval structure to contain the time when last ended
1846 * \param[out] interval Pointer to an int to contain the interval in ms
1847 * \param[out] time_left Pointer to an int to contain the ms left to the next run
1848 * \param[out] last_end Pointer to a timeval structure to contain the next run time
1849 * \retval 0 Success
1850 * \retval -1 Failure
1851 * \note Any of the pointers can be NULL if you don't need them.
1852 */
1853 int ast_sip_sched_task_get_times2(struct ast_sip_sched_task *schtd,
1854 struct timeval *when_queued, struct timeval *last_start, struct timeval *last_end,
1855 int *interval, int *time_left, struct timeval *next_start);
1856
1857 /*!
18251858 * \brief Gets the last start and end times of the task by name
18261859 * \since 13.9.0
18271860 *
18371870 struct timeval *when_queued, struct timeval *last_start, struct timeval *last_end);
18381871
18391872 /*!
1873 * \brief Gets the queued, last start, last_end, time left, interval, next run by task name
1874 * \since 16.15.0
1875 * \since 18.1.0
1876 *
1877 * \param name The task name
1878 * \param[out] when_queued Pointer to a timeval structure to contain the time when queued
1879 * \param[out] last_start Pointer to a timeval structure to contain the time when last started
1880 * \param[out] last_end Pointer to a timeval structure to contain the time when last ended
1881 * \param[out] interval Pointer to an int to contain the interval in ms
1882 * \param[out] time_left Pointer to an int to contain the ms left to the next run
1883 * \param[out] last_end Pointer to a timeval structure to contain the next run time
1884 * \retval 0 Success
1885 * \retval -1 Failure
1886 * \note Any of the pointers can be NULL if you don't need them.
1887 */
1888 int ast_sip_sched_task_get_times_by_name2(const char *name,
1889 struct timeval *when_queued, struct timeval *last_start, struct timeval *last_end,
1890 int *interval, int *time_left, struct timeval *next_start);
1891
1892 /*!
18401893 * \brief Gets the number of milliseconds until the next invocation
18411894 * \since 13.9.0
18421895 *
19191972 /*!
19201973 * \brief General purpose method for creating a UAS dialog with an endpoint
19211974 *
1975 * \deprecated This function is unsafe (due to the returned object not being locked nor
1976 * having its reference incremented) and should no longer be used. Instead
1977 * use ast_sip_create_dialog_uas_locked so a properly locked and referenced
1978 * object is returned.
1979 *
19221980 * \param endpoint A pointer to the endpoint
19231981 * \param rdata The request that is starting the dialog
19241982 * \param[out] status On failure, the reason for failure in creating the dialog
19251983 */
19261984 pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pj_status_t *status);
1985
1986 /*!
1987 * \brief General purpose method for creating a UAS dialog with an endpoint
1988 *
1989 * This function creates and returns a locked, and referenced counted pjsip
1990 * dialog object. The caller is thus responsible for freeing the allocated
1991 * memory, decrementing the reference, and releasing the lock when done with
1992 * the returned object.
1993 *
1994 * \note The safest way to unlock the object, and decrement its reference is by
1995 * calling pjsip_dlg_dec_lock. Alternatively, pjsip_dlg_dec_session can be
1996 * used to decrement the reference only.
1997 *
1998 * The dialog is returned locked and with a reference in order to ensure that the
1999 * dialog object, and any of its associated objects (e.g. transaction) are not
2000 * untimely destroyed. For instance, that could happen when a transport error
2001 * occurs.
2002 *
2003 * As long as the caller maintains a reference to the dialog there should be no
2004 * worry that it might unknowningly be destroyed. However, once the caller unlocks
2005 * the dialog there is a danger that some of the dialog's internal objects could
2006 * be lost and/or compromised. For example, when the aforementioned transport error
2007 * occurs the dialog's associated transaction gets destroyed (see pjsip_dlg_on_tsx_state
2008 * in sip_dialog.c, and mod_inv_on_tsx_state in sip_inv.c).
2009 *
2010 * In this case and before using the dialog again the caller should re-lock the
2011 * dialog, check to make sure the dialog is still established, and the transaction
2012 * still exists and has not been destroyed.
2013 *
2014 * \param endpoint A pointer to the endpoint
2015 * \param rdata The request that is starting the dialog
2016 * \param[out] status On failure, the reason for failure in creating the dialog
2017 *
2018 * \retval A locked, and reference counted pjsip_dialog object.
2019 * \retval NULL on failure
2020 */
2021 pjsip_dialog *ast_sip_create_dialog_uas_locked(const struct ast_sip_endpoint *endpoint,
2022 pjsip_rx_data *rdata, pj_status_t *status);
19272023
19282024 /*!
19292025 * \brief General purpose method for creating an rdata structure using specific information
21612257 * \retval non-NULL The matching endpoint
21622258 */
21632259 struct ast_sip_endpoint *ast_sip_identify_endpoint(pjsip_rx_data *rdata);
2260
2261 /*!
2262 * \brief Get a specific header value from rdata
2263 *
2264 * \note The returned value does not need to be freed since it's from the rdata pool
2265 *
2266 * \param rdata The rdata
2267 * \param str The header to find
2268 *
2269 * \retval NULL on failure
2270 * \retval The header value on success
2271 */
2272 char *ast_sip_rdata_get_header_value(pjsip_rx_data *rdata, const pj_str_t str);
21642273
21652274 /*!
21662275 * \brief Set the outbound proxy for an outbound SIP message
116116 unsigned int changed;
117117 /*! \brief Remote media stream label */
118118 char *remote_mslabel;
119 /*! \brief Remote stream label */
120 char *remote_label;
121 /*! \brief Stream name */
122 char *stream_name;
119123 };
120124
121125 /*!
218222 enum ast_sip_dtmf_mode dtmf;
219223 /*! Initial incoming INVITE Request-URI. NULL otherwise. */
220224 pjsip_uri *request_uri;
221 /* Media statistics for negotiated RTP streams */
225 /*! Media statistics for negotiated RTP streams */
222226 AST_VECTOR(, struct ast_rtp_instance_stats *) media_stats;
227 /*! Number of challenges received during outgoing requests to determine if we are in a loop */
228 unsigned int authentication_challenge_count:4;
223229 };
224230
225231 typedef int (*ast_sip_session_request_creation_cb)(struct ast_sip_session *session, pjsip_tx_data *tdata);
0 /*
1 * Asterisk -- An open source telephony toolkit.
2 *
3 * Copyright (C) 2020, Sangoma Technologies Corporation
4 *
5 * Kevin Harwell <kharwell@sangoma.com>
6 *
7 * See http://www.asterisk.org for more information about
8 * the Asterisk project. Please do not directly contact
9 * any of the maintainers of this project for assistance;
10 * the project provides a web site, mailing lists and IRC
11 * channels for your use.
12 *
13 * This program is free software, distributed under the terms of
14 * the GNU General Public License Version 2. See the LICENSE file
15 * at the top of the source tree.
16 */
17 #ifndef _RES_STIR_SHAKEN_H
18 #define _RES_STIR_SHAKEN_H
19
20 #define STIR_SHAKEN_ENCRYPTION_ALGORITHM "ES256"
21 #define STIR_SHAKEN_PPT "shaken"
22 #define STIR_SHAKEN_TYPE "passport"
23
24 enum ast_stir_shaken_verification_result {
25 AST_STIR_SHAKEN_VERIFY_NOT_PRESENT, /*! No STIR/SHAKEN information was available */
26 AST_STIR_SHAKEN_VERIFY_SIGNATURE_FAILED, /*! Signature verification failed */
27 AST_STIR_SHAKEN_VERIFY_MISMATCH, /*! Contents of the signaling and the STIR/SHAKEN payload did not match */
28 AST_STIR_SHAKEN_VERIFY_PASSED, /*! Signature verified and contents match signaling */
29 };
30
31 struct ast_stir_shaken_payload;
32
33 struct ast_json;
34
35 /*!
36 * \brief Retrieve the value for 'signature' from an ast_stir_shaken_payload
37 *
38 * \param payload The payload
39 *
40 * \retval The signature
41 */
42 unsigned char *ast_stir_shaken_payload_get_signature(const struct ast_stir_shaken_payload *payload);
43
44 /*!
45 * \brief Retrieve the value for 'public_key_url' from an ast_stir_shaken_payload
46 *
47 * \param payload The payload
48 *
49 * \retval The public key URL
50 */
51 char *ast_stir_shaken_payload_get_public_key_url(const struct ast_stir_shaken_payload *payload);
52
53 /*!
54 * \brief Retrieve the value for 'signature_timeout' from 'general' config object
55 *
56 * \retval The signature timeout
57 */
58 unsigned int ast_stir_shaken_get_signature_timeout(void);
59
60 /*!
61 * \brief Add a STIR/SHAKEN verification result to a channel
62 *
63 * \param chan The channel
64 * \param identity The identity
65 * \param attestation The attestation
66 * \param result The verification result
67 *
68 * \retval -1 on failure
69 * \retval 0 on success
70 */
71 int ast_stir_shaken_add_verification(struct ast_channel *chan, const char *identity, const char *attestation,
72 enum ast_stir_shaken_verification_result result);
73
74 /*!
75 * \brief Verify a JSON STIR/SHAKEN payload
76 *
77 * \param header The payload header
78 * \param payload The payload section
79 * \param signature The payload signature
80 * \param algorithm The signature algorithm
81 * \param public_key_url The public key URL
82 *
83 * \retval ast_stir_shaken_payload on success
84 * \retval NULL on failure
85 */
86 struct ast_stir_shaken_payload *ast_stir_shaken_verify(const char *header, const char *payload, const char *signature,
87 const char *algorithm, const char *public_key_url);
88
89 /*!
90 * \brief Retrieve the stir/shaken sorcery context
91 *
92 * \retval The stir/shaken sorcery context
93 */
94 struct ast_sorcery *ast_stir_shaken_sorcery(void);
95
96 /*!
97 * \brief Free a STIR/SHAKEN payload
98 */
99 void ast_stir_shaken_payload_free(struct ast_stir_shaken_payload *payload);
100
101 /*!
102 * \brief Sign a JSON STIR/SHAKEN payload
103 *
104 * \note This function will automatically add the "attest", "iat", and "origid" fields.
105 *
106 * \param json The JWT to sign
107 *
108 * \retval ast_stir_shaken_payload on success
109 * \retval NULL on failure
110 */
111 struct ast_stir_shaken_payload *ast_stir_shaken_sign(struct ast_json *json);
112
113 #endif /* _RES_STIR_SHAKEN_H */
7676 #include "asterisk/res_srtp.h"
7777 #include "asterisk/stasis.h"
7878 #include "asterisk/vector.h"
79 #include "asterisk/logger_category.h"
7980
8081 /*! Maximum number of payload types RTP can support. */
8182 #define AST_RTP_MAX_PT 128
28182819 */
28192820 struct stasis_topic *ast_rtp_topic(void);
28202821
2822 /* RTP debug logging category name */
2823 #define AST_LOG_CATEGORY_RTP "rtp"
2824 /* RTP packet debug logging category name */
2825 #define AST_LOG_CATEGORY_RTP_PACKET "rtp_packet"
2826 /* RTCP debug logging category name */
2827 #define AST_LOG_CATEGORY_RTCP "rtcp"
2828 /* RTCP packet debug logging category name */
2829 #define AST_LOG_CATEGORY_RTCP_PACKET "rtcp_packet"
2830 /* DTLS debug logging category name */
2831 #define AST_LOG_CATEGORY_DTLS "dtls"
2832 /* DTLS packet debug logging category name */
2833 #define AST_LOG_CATEGORY_DTLS_PACKET "dtls_packet"
2834 /* ICE debug logging category name */
2835 #define AST_LOG_CATEGORY_ICE "ice"
2836
2837 uintmax_t ast_debug_category_rtp_id(void);
2838 uintmax_t ast_debug_category_rtp_packet_id(void);
2839 uintmax_t ast_debug_category_rtcp_id(void);
2840 uintmax_t ast_debug_category_rtcp_packet_id(void);
2841 uintmax_t ast_debug_category_dtls_id(void);
2842 uintmax_t ast_debug_category_dtls_packet_id(void);
2843 uintmax_t ast_debug_category_ice_id(void);
2844
2845 #define AST_DEBUG_CATEGORY_RTP ast_debug_category_rtp_id() /* RTP debug logging category id */
2846 #define AST_DEBUG_CATEGORY_RTP_PACKET ast_debug_category_rtp_packet_id() /* RTP packet debug logging category id */
2847 #define AST_DEBUG_CATEGORY_RTCP ast_debug_category_rtcp_id() /* RTCP debug logging category id */
2848 #define AST_DEBUG_CATEGORY_RTCP_PACKET ast_debug_category_rtcp_packet_id() /* RTCP packet debug logging category id */
2849 #define AST_DEBUG_CATEGORY_DTLS ast_debug_category_dtls_id() /* DTLS debug logging category id */
2850 #define AST_DEBUG_CATEGORY_DTLS_PACKET ast_debug_category_dtls_packet_id() /* DTLS packet debug logging category id */
2851 #define AST_DEBUG_CATEGORY_ICE ast_debug_category_ice_id() /* ICE debug logging category id */
2852
2853 /*!
2854 * \brief Log debug level RTP information
2855 *
2856 * \param sublevel Debug output sublevel (>= 0)
2857 * \param ... String format and any associated arguments
2858 */
2859 #define ast_debug_rtp(sublevel, ...) \
2860 ast_debug_category(sublevel, AST_DEBUG_CATEGORY_RTP, __VA_ARGS__)
2861
2862 /* Allow logging of RTP packets? */
2863 #define ast_debug_rtp_packet_is_allowed \
2864 ast_debug_category_is_allowed(AST_LOG_CATEGORY_ENABLED, AST_DEBUG_CATEGORY_RTP_PACKET)
2865
2866 /*!
2867 * \brief Log debug level RTCP information
2868 *
2869 * \param sublevel Debug output sublevel (>= 0)
2870 * \param ... String format and any associated arguments
2871 */
2872 #define ast_debug_rtcp(sublevel, ...) \
2873 ast_debug_category(sublevel, AST_DEBUG_CATEGORY_RTCP, __VA_ARGS__)
2874
2875 /* Allow logging of RTCP packets? */
2876 #define ast_debug_rtcp_packet_is_allowed \
2877 ast_debug_category_is_allowed(AST_LOG_CATEGORY_ENABLED, AST_DEBUG_CATEGORY_RTCP_PACKET)
2878
2879 /*!
2880 * \brief Log debug level DTLS information
2881 *
2882 * \param sublevel Debug output sublevel (>= 0)
2883 * \param ... String format and any associated arguments
2884 */
2885 #define ast_debug_dtls(sublevel, ...) \
2886 ast_debug_category(sublevel, AST_DEBUG_CATEGORY_DTLS, __VA_ARGS__)
2887
2888 /* Allow logging of DTLS packets? */
2889 #define ast_debug_dtls_packet_is_allowed \
2890 ast_debug_category_is_allowed(AST_LOG_CATEGORY_ENABLED, AST_DEBUG_CATEGORY_DTLS_PACKET)
2891 /*!
2892 * \brief Log debug level ICE information
2893 *
2894 * \param sublevel Debug output sublevel (>= 0)
2895 * \param ... String format and any associated arguments
2896 */
2897 #define ast_debug_ice(sublevel, ...) \
2898 ast_debug_category(sublevel, AST_DEBUG_CATEGORY_ICE, __VA_ARGS__)
2899
28212900 /* @} */
28222901
28232902 #if defined(__cplusplus) || defined(c_plusplus)
135135 while (id > -1 && (_res = ast_sched_del(sched, id) && _count++ < 10)) { \
136136 usleep(1); \
137137 } \
138 if (!_res && _data) \
138 if (!_res && _data && _data != data) \
139139 unrefcall; /* should ref _data! */ \
140140 if (_count == 10) \
141141 ast_log(LOG_WARNING, "Unable to cancel schedule ID %d. This is probably a bug (%s: %s, line %d).\n", id, __FILE__, __PRETTY_FUNCTION__, __LINE__); \
142 refcall; \
142 if (_data != data) \
143 refcall; \
143144 id = ast_sched_add_variable(sched, when, callback, data, variable); \
144145 if (id == -1) \
145146 addfailcall; \
428428 * \returns the position of the stream in the topology (-1 on error)
429429 *
430430 * \since 15
431 *
432 * \note If the stream's name is empty, it'll be set to <stream_type>-<position>
431433 */
432434 int ast_stream_topology_append_stream(struct ast_stream_topology *topology,
433435 struct ast_stream *stream);
473475 * the first unused position. You can't set positions beyond that.
474476 *
475477 * \since 15
478 *
479 * \note If the stream's name is empty, it'll be set to <stream_type>-<position>
476480 */
477481 int ast_stream_topology_set_stream(struct ast_stream_topology *topology,
478482 unsigned int position, struct ast_stream *stream);
2626 #define _ASTERISK_STUN_H
2727
2828 #include "asterisk/network.h"
29 #include "asterisk/logger_category.h"
2930
3031 #if defined(__cplusplus) || defined(c_plusplus)
3132 extern "C" {
3233 #endif
34
35 /* STUN debug logging category name */
36 #define AST_LOG_CATEGORY_STUN "stun"
37 /* STUN packet debug logging category name */
38 #define AST_LOG_CATEGORY_STUN_PACKET "stun_packet"
39
40 uintmax_t ast_debug_category_stun_id(void);
41 uintmax_t ast_debug_category_stun_packet_id(void);
42
43 #define AST_DEBUG_CATEGORY_STUN ast_debug_category_stun_id() /* STUN debug logging category id */
44 #define AST_DEBUG_CATEGORY_STUN_PACKET ast_debug_category_stun_packet_id() /* STUN packet debug logging category id */
45
46 /*!
47 * \brief Log debug level STUN information
48 *
49 * \param sublevel Debug output sublevel (>= 0)
50 * \param ... String format and any associated arguments
51 */
52 #define ast_debug_stun(sublevel, ...) \
53 ast_debug_category(sublevel, AST_DEBUG_CATEGORY_STUN, __VA_ARGS__)
54
55 /* Is logging of stun packets allowed? */
56 #define ast_debug_stun_packet_is_allowed \
57 ast_debug_category_is_allowed(AST_LOG_CATEGORY_ENABLED, AST_DEBUG_CATEGORY_STUN_PACKET)
3358
3459 static const int STANDARD_STUN_PORT = 3478;
3560
239239 int ast_base64encode(char *dst, const unsigned char *src, int srclen, int max);
240240
241241 /*!
242 * \brief Same as ast_base64encode, but does hte math for you and returns
243 * an encoded string
244 *
245 * \note The returned string will need to be freed later
246 *
247 * \param src The source buffer
248 *
249 * \retval NULL on failure
250 * \retval Encoded string on success
251 */
252 char *ast_base64encode_string(const char *src);
253
254 /*!
242255 * \brief Decode data from base64
243256 * \param dst the destination buffer
244257 * \param src the source buffer
248261 * this parameter should be sizeof(dst) - 1.
249262 */
250263 int ast_base64decode(unsigned char *dst, const char *src, int max);
264
265 /*!
266 * \brief Same as ast_base64decode, but does the math for you and returns
267 * a decoded string
268 *
269 * \note The returned string will need to be freed later and IS NULL terminated
270 *
271 * \param src The source buffer
272 *
273 * \retval NULL on failure
274 * \retval Decoded string on success
275 */
276 char *ast_base64decode_string(const char *src);
251277
252278 #define AST_URI_ALPHANUM (1 << 0)
253279 #define AST_URI_MARK (1 << 1)
17521752 ast_channel_lock(chan);
17531753 ast_channel_internal_bridge_channel_set(chan, NULL);
17541754 ast_channel_unlock(chan);
1755 /* Due to a race condition, we lock the bridge channel here for ast_bridge_channel_get_chan */
1756 ao2_lock(bridge_channel);
17551757 bridge_channel->chan = NULL;
1758 ao2_unlock(bridge_channel);
17561759 /* If bridge_channel->swap is not NULL then the join failed. */
17571760 ao2_t_cleanup(bridge_channel->swap, "Bridge complete: join failed");
17581761 bridge_channel->swap = NULL;
18211824 ast_channel_lock(chan);
18221825 ast_channel_internal_bridge_channel_set(chan, NULL);
18231826 ast_channel_unlock(chan);
1827 /* Lock here for ast_bridge_channel_get_chan */
1828 ao2_lock(bridge_channel);
18241829 bridge_channel->chan = NULL;
1830 ao2_unlock(bridge_channel);
18251831 /* If bridge_channel->swap is not NULL then the join failed. */
18261832 ao2_t_cleanup(bridge_channel->swap, "Bridge complete: Independent impart join failed");
18271833 bridge_channel->swap = NULL;
19221928 ast_channel_lock(chan);
19231929 ast_channel_internal_bridge_channel_set(chan, NULL);
19241930 ast_channel_unlock(chan);
1931 /* Lock here for ast_bridge_channel_get_chan */
1932 ao2_lock(bridge_channel);
19251933 bridge_channel->chan = NULL;
1934 ao2_unlock(bridge_channel);
19261935 ao2_t_cleanup(bridge_channel->swap, "Bridge complete: Impart failed");
19271936 bridge_channel->swap = NULL;
19281937 ast_bridge_features_destroy(bridge_channel->features);
38273836 ast_bridge_lock(bridge);
38283837 cleanup_video_mode(bridge);
38293838 bridge->softmix.video_mode.mode = AST_BRIDGE_VIDEO_MODE_SINGLE_SRC;
3830 bridge->softmix.video_mode.mode_data.single_src_data.chan_vsrc = ast_channel_ref(video_src_chan);
3831 ast_verb(5, "Video source in bridge '%s' (%s) is now '%s' (%s)\n",
3832 bridge->name, bridge->uniqueid,
3833 ast_channel_name(video_src_chan),
3834 ast_channel_uniqueid(video_src_chan));
3839 if (video_src_chan) {
3840 bridge->softmix.video_mode.mode_data.single_src_data.chan_vsrc = ast_channel_ref(video_src_chan);
3841 ast_verb(5, "Video source in bridge '%s' (%s) is now '%s' (%s)\n",
3842 bridge->name, bridge->uniqueid,
3843 ast_channel_name(video_src_chan),
3844 ast_channel_uniqueid(video_src_chan));
3845 ast_indicate(video_src_chan, AST_CONTROL_VIDUPDATE);
3846 }
38353847 ast_bridge_publish_state(bridge);
3836 ast_indicate(video_src_chan, AST_CONTROL_VIDUPDATE);
38373848 ast_bridge_unlock(bridge);
38383849 }
38393850
38753886
38763887 ast_bridge_lock(bridge);
38773888 bridge->softmix.video_mode.mode_data.sfu_data.remb_behavior = behavior;
3889 ast_bridge_unlock(bridge);
3890 }
3891
3892 void ast_bridge_set_remb_estimated_bitrate(struct ast_bridge *bridge, float estimated_bitrate)
3893 {
3894 ast_assert(bridge->softmix.video_mode.mode == AST_BRIDGE_VIDEO_MODE_SFU);
3895
3896 ast_bridge_lock(bridge);
3897 bridge->softmix.video_mode.mode_data.sfu_data.estimated_bitrate = estimated_bitrate;
38783898 ast_bridge_unlock(bridge);
38793899 }
38803900
47704790
47714791 if (to_transferee_bridge_channel) {
47724792 /* Take off hold if they are on hold. */
4773 ast_bridge_channel_write_unhold(to_transferee_bridge_channel);
4793 if (ast_bridge_channel_write_unhold(to_transferee_bridge_channel)) {
4794 ast_log(LOG_ERROR, "Transferee channel disappeared during transfer!\n");
4795 res = AST_BRIDGE_TRANSFER_FAIL;
4796 goto end;
4797 }
47744798 }
47754799
47764800 if (to_target_bridge_channel) {
47774801 const char *target_complete_sound;
47784802
47794803 /* Take off hold if they are on hold. */
4780 ast_bridge_channel_write_unhold(to_target_bridge_channel);
4804 if (ast_bridge_channel_write_unhold(to_target_bridge_channel)) {
4805 ast_log(LOG_ERROR, "Target channel disappeared during transfer!\n");
4806 res = AST_BRIDGE_TRANSFER_FAIL;
4807 goto end;
4808 }
47814809
47824810 /* Is there a courtesy sound to play to the target? */
47834811 ast_channel_lock(to_transfer_target);
205205 static void bridge_sync_signal(struct bridge_sync *sync_struct)
206206 {
207207 ast_sem_post(&sync_struct->sem);
208 }
209
210 struct ast_channel *ast_bridge_channel_get_chan(struct ast_bridge_channel *bridge_channel)
211 {
212 struct ast_channel *chan;
213
214 ao2_lock(bridge_channel);
215 chan = ao2_bump(bridge_channel->chan);
216 ao2_unlock(bridge_channel);
217
218 return chan;
208219 }
209220
210221 void ast_bridge_channel_lock_bridge(struct ast_bridge_channel *bridge_channel)
11761187
11771188 int ast_bridge_channel_write_unhold(struct ast_bridge_channel *bridge_channel)
11781189 {
1179 ast_channel_publish_cached_blob(bridge_channel->chan, ast_channel_unhold_type(), NULL);
1190 struct ast_channel *chan = ast_bridge_channel_get_chan(bridge_channel);
1191
1192 if (!chan) {
1193 return -1;
1194 }
1195
1196 ast_channel_publish_cached_blob(chan, ast_channel_unhold_type(), NULL);
1197 ao2_ref(chan, -1);
11801198
11811199 return ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_UNHOLD, NULL, 0);
11821200 }
57205720 if (!direction) {
57215721 /* reading */
57225722 trans_pvt = ast_translator_build_path(best_set_fmt, best_native_fmt);
5723 trans_pvt->interleaved_stereo = 0;
5723 if (trans_pvt) {
5724 trans_pvt->interleaved_stereo = 0;
5725 }
57245726 } else {
57255727 /* writing */
57265728 trans_pvt = ast_translator_build_path(best_native_fmt, best_set_fmt);
5727 trans_pvt->interleaved_stereo = interleaved_stereo;
5729 if (trans_pvt) {
5730 trans_pvt->interleaved_stereo = interleaved_stereo;
5731 }
57285732 }
57295733 access->set_trans(chan, trans_pvt);
57305734 res = trans_pvt ? 0 : -1;
1102811032 }
1102911033
1103011034 if (ast_stream_topology_equal(ast_channel_get_stream_topology(chan), topology)) {
11031 ast_debug(3, "Topology of %s already matches what is requested so ignoring topology change request\n",
11032 ast_channel_name(chan));
11035 ast_debug(2, "%s: Topologies already match. Current: %s Requested: %s\n",
11036 ast_channel_name(chan),
11037 ast_str_tmp(256, ast_stream_topology_to_str(ast_channel_get_stream_topology(chan), &STR_TMP)),
11038 ast_str_tmp(256, ast_stream_topology_to_str(topology, &STR_TMP)));
1103311039 ast_channel_unlock(chan);
1103411040 return 0;
1103511041 }
5454 #include "asterisk/app.h"
5555 #include "asterisk/lock.h"
5656 #include "asterisk/threadstorage.h"
57 #include "asterisk/logger_category.h"
5758 #include "asterisk/translate.h"
5859 #include "asterisk/bridge.h"
5960 #include "asterisk/stasis_channels.h"
477478 if (!strcasecmp(a->argv[e->args], "atleast")) {
478479 atleast = 1;
479480 }
481
480482 if (a->argc != e->args + atleast + 1 && a->argc != e->args + atleast + 2) {
481483 return CLI_SHOWUSAGE;
482484 }
485
483486 if (sscanf(a->argv[e->args + atleast], "%30d", &newlevel) != 1) {
484487 return CLI_SHOWUSAGE;
485488 }
584587 return NULL;
585588
586589 case CLI_GENERATE:
590 if (!strcasecmp(argv3, "category")) {
591 return NULL;
592 }
593
587594 if (!strcasecmp(argv3, "atleast")) {
588595 atleast = 1;
589596 }
617624 */
618625
619626 return handle_debug_or_trace(DEBUG_HANDLER, e, cmd, a);
620
621627 }
622628
623629 static char *handle_trace(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
15331539 }
15341540
15351541 ast_cli(a->fd, "Debugging on new channels is %s\n", args.is_off ? "disabled" : "enabled");
1542
1543 return CLI_SUCCESS;
1544 }
1545
1546 static char *handle_debug_category(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1547 {
1548 const char *argv4 = a->argv ? S_OR(a->argv[4], "") : "";
1549 int offset = strncasecmp(argv4, "off", strlen(argv4)) ? 0 : 1;
1550
1551 switch (cmd) {
1552 case CLI_INIT:
1553 e->command = "core set debug category";
1554 e->usage =
1555 "Usage: core set debug category <category>[:<sublevel>] [category[:<sublevel] ...]\n"
1556 " core set debug category off [<category> [<category>] ...]\n\n"
1557 " Allows enabling and disabling debug logging categories.\n"
1558 " When a category is enabled all relevant debug messages are logged\n"
1559 " for a given category. However, if a sublevel is specified only\n"
1560 " those categorized messages at or below the coded debug sublevel\n"
1561 " are logged.\n";
1562 return NULL;
1563
1564 case CLI_GENERATE:
1565 if (a->pos < e->args) {
1566 return NULL;
1567 }
1568
1569 if (a->pos == 4 && offset) {
1570 ast_cli_completion_add(ast_strdup("off"));
1571 }
1572
1573 return ast_debug_category_complete(a->argv + 4,
1574 a->pos - e->args, a->word, a->n - 1);
1575 }
1576
1577 if (a->argc <= e->args) {
1578 return CLI_SHOWUSAGE;
1579 }
1580
1581 ast_debug_category_set_sublevels(a->argv + e->args + offset, a->argc - e->args - offset,
1582 offset ? AST_LOG_CATEGORY_DISABLED : AST_LOG_CATEGORY_ENABLED);
15361583
15371584 return CLI_SUCCESS;
15381585 }
19552002
19562003 AST_CLI_DEFINE(handle_core_set_debug_channel, "Enable/disable debugging on a channel"),
19572004
2005 AST_CLI_DEFINE(handle_debug_category, "Enable/disable debugging categories"),
2006
19582007 AST_CLI_DEFINE(handle_debug, "Set level of debug chattiness"),
19592008 AST_CLI_DEFINE(handle_trace, "Set level of trace chattiness"),
19602009 AST_CLI_DEFINE(handle_verbose, "Set level of verbose chattiness"),
14411441 } else {
14421442 odata = f->data.ptr;
14431443 len = f->datalen;
1444 if (ast_format_cmp(f->subclass.format, ast_format_ulaw)) {
1444 if (ast_format_cmp(f->subclass.format, ast_format_ulaw) == AST_FORMAT_CMP_EQUAL) {
14451445 s = ast_alloca(len * 2);
14461446 for (x = 0; x < len; x++) {
14471447 s[x] = AST_MULAW(odata[x]);
14481448 }
1449 } else if (ast_format_cmp(f->subclass.format, ast_format_alaw)) {
1449 } else if (ast_format_cmp(f->subclass.format, ast_format_alaw) == AST_FORMAT_CMP_EQUAL) {
14501450 s = ast_alloca(len * 2);
14511451 for (x = 0; x < len; x++) {
14521452 s[x] = AST_ALAW(odata[x]);
554554
555555 return 0;
556556 }
557
558 struct ast_format *ast_format_cache_get_by_codec(const struct ast_codec *codec)
559 {
560 struct ast_format *format;
561 struct ao2_iterator it;
562
563 for (it = ao2_iterator_init(formats, 0);
564 (format = ao2_iterator_next(&it));
565 ao2_ref(format, -1)) {
566 struct ast_codec *candidate = ast_format_get_codec(format);
567 if (codec == candidate) {
568 ao2_cleanup(candidate);
569 ao2_iterator_destroy(&it);
570 return format;
571 }
572 ao2_cleanup(candidate);
573 }
574
575 ao2_iterator_destroy(&it);
576 return NULL;
577 }
231231 continue;
232232 }
233233
234 format = ast_format_cache_get(codec->name);
234 format = ast_format_cache_get_by_codec(codec);
235235
236236 if (format == ast_format_none) {
237237 ao2_ref(format, -1);
701701 ast_tone_zone_lock(tz);
702702
703703 if (ast_register_indication(tz, a->argv[3], a->argv[4])) {
704 ast_log(LOG_WARNING, "Unable to register indication %s/%s\n", a->argv[2], a->argv[3]);
704 if (ast_strlen_zero(a->argv[3])) {
705 ast_log(LOG_WARNING, "Unable to register indication %s\n", a->argv[2]);
706 } else {
707 ast_log(LOG_WARNING, "Unable to register indication %s/%s\n", a->argv[2], a->argv[3]);
708 }
705709 if (created_country) {
706710 ast_unregister_indication_country(a->argv[2]);
707711 }
5151 #include "asterisk/module.h"
5252 #include "asterisk/paths.h" /* use ast_config_AST_LOG_DIR */
5353 #include "asterisk/logger.h"
54 #include "asterisk/logger_category.h"
5455 #include "asterisk/lock.h"
5556 #include "asterisk/channel.h"
5657 #include "asterisk/config.h"
18671868 ast_log(LOG_ERROR, "Errors detected in logger.conf. Default console logging is being used.\n");
18681869 }
18691870
1871 ast_logger_category_load();
1872
18701873 return 0;
18711874 }
18721875
18731876 void close_logger(void)
18741877 {
18751878 struct logchannel *f = NULL;
1879
1880 ast_logger_category_unload();
18761881
18771882 ast_cli_unregister_multiple(cli_logger, ARRAY_LEN(cli_logger));
18781883
0 /*
1 * Asterisk -- An open source telephony toolkit.
2 *
3 * Copyright (C) 2020, Sangoma Technologies Corporation
4 *
5 * Kevin Harwell <kharwell@sangoma.com>
6 *
7 * See http://www.asterisk.org for more information about
8 * the Asterisk project. Please do not directly contact
9 * any of the maintainers of this project for assistance;
10 * the project provides a web site, mailing lists and IRC
11 * channels for your use.
12 *
13 * This program is free software, distributed under the terms of
14 * the GNU General Public License Version 2. See the LICENSE file
15 * at the top of the source tree.
16 */
17
18 #include "asterisk.h"
19
20 #include "asterisk/cli.h"
21 #include "asterisk/conversions.h"
22 #include "asterisk/logger_category.h"
23 #include "asterisk/vector.h"
24
25 struct category_t {
26 int sublevel;
27 uintmax_t id;
28 char name[0];
29 };
30
31 AST_VECTOR_RW(categories_t, struct category_t *);
32
33 struct categories_level_t {
34 int type;
35 int sublevel;
36 uintmax_t id_pool;
37 uintmax_t state;
38 struct categories_t categories;
39 };
40
41 /*! \brief Retrieve the next available id.
42 *
43 * Ids must be a power of 2. This allows for fast lookup, and "or'ing" of ids
44 * in order to permit multiple categories in a log statement.
45 */
46 static uintmax_t get_next_id(struct categories_level_t *level)
47 {
48 if (level->id_pool == 0) {
49 level->id_pool = 1;
50 } else if (level->id_pool >= (UINTMAX_MAX / 2)) {
51 /* No more ids left*/
52 return 0;
53 } else {
54 level->id_pool <<= 1;
55 }
56
57 return level->id_pool;
58 }
59
60 static int cmp_by_name(const struct category_t *category, const char *name)
61 {
62 return !strcmp(category->name, name);
63 }
64
65 static uintmax_t category_register(struct categories_level_t *level, const char *name)
66 {
67 int i;
68 struct category_t *category;
69
70 AST_VECTOR_RW_WRLOCK(&level->categories);
71
72 i = AST_VECTOR_GET_INDEX(&level->categories, name, cmp_by_name);
73 if (i >= 0) {
74 AST_VECTOR_RW_UNLOCK(&level->categories);
75 ast_log(LOG_ERROR, "Cannot register logger category '%s'. "
76 "Name already used for type.\n", name);
77 return 0;
78 }
79
80 category = ast_calloc(1, sizeof(*category) + strlen(name) + 1);
81 if (!category) {
82 AST_VECTOR_RW_UNLOCK(&level->categories);
83 return 0;
84 }
85
86 category->id = get_next_id(level);
87 category->sublevel = AST_LOG_CATEGORY_DISABLED;
88 strcpy(category->name, name); /* Safe */
89
90 if (AST_VECTOR_APPEND(&level->categories, category)) {
91 AST_VECTOR_RW_UNLOCK(&level->categories);
92 ast_log(LOG_ERROR, "Cannot register logger category '%s'. "
93 "Unable to append.\n", name);
94 return 0;
95 }
96
97 AST_VECTOR_RW_UNLOCK(&level->categories);
98 return category->id;
99 }
100
101 static int category_unregister(struct categories_level_t *level, const char *name)
102 {
103 int res;
104
105 AST_VECTOR_RW_WRLOCK(&level->categories);
106 res = AST_VECTOR_REMOVE_CMP_UNORDERED(&level->categories, name, cmp_by_name, ast_free);
107 AST_VECTOR_RW_UNLOCK(&level->categories);
108
109 return res;
110 }
111
112 static int casecmp_by_name(const struct category_t *category, const char *name)
113 {
114 return !strcasecmp(category->name, name);
115 }
116
117 static int category_set_sublevel(struct category_t *category, struct categories_level_t *level,
118 const char *name, int sublevel)
119 {
120 int locked = 0;
121
122 if (!category) {
123 struct category_t **obj;
124
125 if (!name) {
126 return -1;
127 }
128
129 locked = !AST_VECTOR_RW_WRLOCK(&level->categories);
130 if (!locked) {
131 return -1;
132 }
133
134 obj = AST_VECTOR_GET_CMP(&level->categories, name, casecmp_by_name);
135 if (!obj) {
136 AST_VECTOR_RW_UNLOCK(&level->categories);
137 return -1;
138 }
139
140 category = *obj;
141 }
142
143 category->sublevel = sublevel;
144
145 if (category->sublevel == AST_LOG_CATEGORY_DISABLED) {
146 level->state &= ~category->id;
147 } else {
148 level->state |= category->id;
149 }
150
151 if (locked) {
152 AST_VECTOR_RW_UNLOCK(&level->categories);
153 }
154
155 return 0;
156 }
157
158 static int category_set_sublevels(struct categories_level_t *level,
159 const char * const *names, size_t size, int default_sublevel)
160 {
161 int i;
162
163 if (!names || !size) {
164 level->state = default_sublevel;
165 AST_VECTOR_RW_WRLOCK(&level->categories);
166 AST_VECTOR_CALLBACK_VOID(&level->categories, category_set_sublevel,
167 level, NULL, default_sublevel);
168 AST_VECTOR_RW_UNLOCK(&level->categories);
169 return 0;
170 }
171
172 for (i = 0; i < size; ++i) {
173 const char *sublevel;
174 int num = default_sublevel;
175
176 sublevel = strchr(names[i], ':');
177 if (sublevel) {
178 size_t len = ++sublevel - names[i];
179 char name[len];
180
181 if (*sublevel && ast_str_to_int(sublevel, &num)) {
182 continue;
183 }
184
185 ast_copy_string(name, names[i], len);
186 category_set_sublevel(NULL, level, name, num);
187 } else {
188 category_set_sublevel(NULL, level, names[i], num);
189 }
190 }
191
192 return 0;
193 }
194
195 static char *category_complete(struct categories_level_t *level, const char * const *argv,
196 int argc, const char *word, int state)
197 {
198 int wordlen = strlen(word);
199 int which = 0;
200 int i, j;
201
202 AST_VECTOR_RW_RDLOCK(&level->categories);
203
204 if (argc == AST_VECTOR_SIZE(&level->categories)) {
205 AST_VECTOR_RW_UNLOCK(&level->categories);
206 return NULL;
207 }
208
209 for (i = 0; i < AST_VECTOR_SIZE(&level->categories); ++i) {
210 struct category_t *category = AST_VECTOR_GET(&level->categories, i);
211
212 if (!strncasecmp(word, category->name, wordlen) && (++which > state)) {
213 /* Check to see if one is already been included */
214 for (j = 0; j < argc; ++j) {
215 if (!strncasecmp(category->name, argv[j], strlen(category->name))) {
216 break;
217 }
218 }
219
220 if (j != argc) {
221 continue;
222 }
223
224 if (state != -1) {
225 AST_VECTOR_RW_UNLOCK(&level->categories);
226 return ast_strdup(category->name);
227 }
228
229 if (ast_cli_completion_add(ast_strdup(category->name))) {
230 AST_VECTOR_RW_UNLOCK(&level->categories);
231 return NULL;
232 }
233 }
234 }
235
236 AST_VECTOR_RW_UNLOCK(&level->categories);
237 return NULL;
238 }
239
240 static int category_is_allowed(int sublevel, struct categories_level_t *level, uintmax_t ids)
241 {
242 /* Check level, and potentially allow but only if there is a matching state enabled */
243 if (ids & level->state) {
244 int i;
245
246 if (sublevel == AST_LOG_CATEGORY_ENABLED || sublevel == 0) {
247 /* If at least one id is enabled then always allow these sublevels */
248 return 1;
249 }
250
251 AST_VECTOR_RW_RDLOCK(&level->categories);
252 for (i = 0; i < AST_VECTOR_SIZE(&level->categories); ++i) {
253 struct category_t *category = AST_VECTOR_GET(&level->categories, i);
254
255 /*
256 * If there is at least one matching category, and that category is enabled
257 * or its sub-level is at or above the given sub-level then allow.
258 */
259 if ((category->id & ids) && category->sublevel != AST_LOG_CATEGORY_DISABLED &&
260 (category->sublevel == AST_LOG_CATEGORY_ENABLED || category->sublevel >= sublevel)) {
261 AST_VECTOR_RW_UNLOCK(&level->categories);
262 return 1;
263 }
264 }
265 AST_VECTOR_RW_UNLOCK(&level->categories);
266 }
267
268 return 0;
269 }
270
271 static struct categories_level_t debug_categories = {
272 .type = __LOG_DEBUG,
273 .sublevel = 0,
274 .id_pool = 0,
275 .state = 0,
276 };
277
278 uintmax_t ast_debug_category_register(const char *name)
279 {
280 return category_register(&debug_categories, name);
281 }
282
283 int ast_debug_category_unregister(const char *name)
284 {
285 return category_unregister(&debug_categories, name);
286 }
287
288 int ast_debug_category_set_sublevel(const char *name, int sublevel)
289 {
290 return category_set_sublevel(NULL, &debug_categories, name, sublevel);
291 }
292
293 int ast_debug_category_set_sublevels(const char * const *names,
294 size_t size, int default_sublevel)
295 {
296 return category_set_sublevels(&debug_categories, names, size, default_sublevel);
297 }
298
299 char *ast_debug_category_complete(const char * const *argv, int argc,
300 const char *word, int state)
301 {
302 return category_complete(&debug_categories, argv, argc, word, state);
303 }
304
305 int ast_debug_category_is_allowed(int sublevel, uintmax_t ids)
306 {
307 return category_is_allowed(sublevel, &debug_categories, ids);
308 }
309
310 int ast_logger_category_unload(void)
311 {
312 AST_VECTOR_RW_FREE(&debug_categories.categories);
313 return 0;
314 }
315
316 int ast_logger_category_load(void)
317 {
318 if (AST_VECTOR_RW_INIT(&debug_categories.categories, 10)) {
319 return -1;
320 }
321
322 return 0;
323 }
73457345 if (ast_strlen_zero(extension)) {
73467346 ast_log(LOG_ERROR,"You have to be kidding-- add exten '' to context %s? Figure out a name and call me back. Action ignored.\n",
73477347 con->name);
7348 /* We always need to deallocate 'data' on failure */
7349 if (datad) {
7350 datad(data);
7351 }
73487352 return -1;
73497353 }
73507354
74007404 }
74017405
74027406 /* Be optimistic: Build the extension structure first */
7403 if (!(tmp = ast_calloc(1, length)))
7407 tmp = ast_calloc(1, length);
7408 if (!tmp) {
7409 /* We always need to deallocate 'data' on failure */
7410 if (datad) {
7411 datad(data);
7412 }
74047413 return -1;
7414 }
74057415
74067416 if (ast_strlen_zero(label)) /* let's turn empty labels to a null ptr */
74077417 label = 0;
35323532 return rtp_topic;
35333533 }
35343534
3535 static uintmax_t debug_category_rtp_id;
3536
3537 uintmax_t ast_debug_category_rtp_id(void)
3538 {
3539 return debug_category_rtp_id;
3540 }
3541
3542 static uintmax_t debug_category_rtp_packet_id;
3543
3544 uintmax_t ast_debug_category_rtp_packet_id(void)
3545 {
3546 return debug_category_rtp_packet_id;
3547 }
3548
3549 static uintmax_t debug_category_rtcp_id;
3550
3551 uintmax_t ast_debug_category_rtcp_id(void)
3552 {
3553 return debug_category_rtcp_id;
3554 }
3555
3556 static uintmax_t debug_category_rtcp_packet_id;
3557
3558 uintmax_t ast_debug_category_rtcp_packet_id(void)
3559 {
3560 return debug_category_rtcp_packet_id;
3561 }
3562
3563 static uintmax_t debug_category_dtls_id;
3564
3565 uintmax_t ast_debug_category_dtls_id(void)
3566 {
3567 return debug_category_dtls_id;
3568 }
3569
3570 static uintmax_t debug_category_dtls_packet_id;
3571
3572 uintmax_t ast_debug_category_dtls_packet_id(void)
3573 {
3574 return debug_category_dtls_packet_id;
3575 }
3576
3577 static uintmax_t debug_category_ice_id;
3578
3579 uintmax_t ast_debug_category_ice_id(void)
3580 {
3581 return debug_category_ice_id;
3582 }
3583
35353584 static void rtp_engine_shutdown(void)
35363585 {
35373586 int x;
35563605 }
35573606 mime_types_len = 0;
35583607 ast_rwlock_unlock(&mime_types_lock);
3608
3609 ast_debug_category_unregister(AST_LOG_CATEGORY_ICE);
3610
3611 ast_debug_category_unregister(AST_LOG_CATEGORY_DTLS_PACKET);
3612 ast_debug_category_unregister(AST_LOG_CATEGORY_DTLS);
3613
3614 ast_debug_category_unregister(AST_LOG_CATEGORY_RTCP_PACKET);
3615 ast_debug_category_unregister(AST_LOG_CATEGORY_RTCP);
3616
3617 ast_debug_category_unregister(AST_LOG_CATEGORY_RTP_PACKET);
3618 ast_debug_category_unregister(AST_LOG_CATEGORY_RTP);
35593619 }
35603620
35613621 int ast_rtp_engine_init(void)
36833743 add_static_payload(127, ast_format_slin96, 0);
36843744 /* payload types above 127 are not valid */
36853745
3746 debug_category_rtp_id = ast_debug_category_register(AST_LOG_CATEGORY_RTP);
3747 debug_category_rtp_packet_id = ast_debug_category_register(AST_LOG_CATEGORY_RTP_PACKET);
3748 debug_category_rtcp_id = ast_debug_category_register(AST_LOG_CATEGORY_RTCP);
3749 debug_category_rtcp_packet_id = ast_debug_category_register(AST_LOG_CATEGORY_RTCP_PACKET);
3750 debug_category_dtls_id = ast_debug_category_register(AST_LOG_CATEGORY_DTLS);
3751 debug_category_dtls_packet_id = ast_debug_category_register(AST_LOG_CATEGORY_DTLS_PACKET);
3752 debug_category_ice_id = ast_debug_category_register(AST_LOG_CATEGORY_ICE);
3753
36863754 return 0;
36873755 }
36883756
580580 } else if (playh) {
581581 ast_copy_string(fn, "digits/hundred", sizeof(fn));
582582 playh = 0;
583 } else if (num < 20) {
583 } else if (num < 20) {
584584 snprintf(fn, sizeof(fn), "digits/%d", num);
585585 num = 0;
586 } else if (num < 100) {
586 } else if (num < 100) {
587587 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
588588 num %= 10;
589589 } else {
12471247 return res;
12481248 ast_copy_string(fn, "digits/thousand", sizeof(fn));
12491249 num = num % 1000;
1250 } else if (num < 1000000000) {
1250 } else if (num < 1000000000) {
12511251 res = ast_say_number_full_fr(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
12521252 if (res)
12531253 return res;
14821482 } else if (num < 30) {
14831483 ast_copy_string(fn, "digits/20on", sizeof(fn));
14841484 num -= 20;
1485 } else if (num < 100) {
1485 } else if (num < 100) {
14861486 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
14871487 num %= 10;
14881488 } else {
24942494 } else if (playt) {
24952495 snprintf(fn, sizeof(fn), "digits/thousand");
24962496 playt = 0;
2497 } else if (num < 10) {
2498 snprintf(buf, 10, "%d", num);
2497 } else if (num < 10) {
2498 snprintf(buf, 12, "%d", num);
24992499 if (last_length - strlen(buf) > 1 && last_length != 0) {
25002500 last_length = strlen(buf);
25012501 playz++;
25032503 }
25042504 snprintf(fn, sizeof(fn), "digits/%d", num);
25052505 num = 0;
2506 } else if (num < 100) {
2506 } else if (num < 100) {
25072507 snprintf(buf, 10, "%d", num);
25082508 if (last_length - strlen(buf) > 1 && last_length != 0) {
25092509 last_length = strlen(buf);
26792679 } else {
26802680 num = 0;
26812681 }
2682 } else if (num < 20) {
2682 } else if (num < 20) {
26832683 if (options && strlen(options) == 1 && num < 3) {
26842684 snprintf(fn, sizeof(fn), "digits/%d%s", num, options);
26852685 } else {
28472847 } else if (playohz) {
28482848 ast_copy_string(fn, "digits/0-hundred-odd", sizeof(fn));
28492849 playohz = 0;
2850 } else if (num < 20) {
2850 } else if (num < 20) {
28512851 snprintf(fn, sizeof(fn), "digits/%d", num);
28522852 num = 0;
2853 } else if (num < 100) {
2853 } else if (num < 100) {
28542854 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
28552855 num %= 10;
28562856 if ((num == 5) || (num == 4) || (num == 1)) playl++;
100100 [AST_STREAM_STATE_INACTIVE] = "inactive",
101101 };
102102
103 #define MIN_STREAM_NAME_LEN 16
104
103105 struct ast_stream *ast_stream_alloc(const char *name, enum ast_media_type type)
104106 {
105107 struct ast_stream *stream;
106 size_t name_len = MAX(strlen(S_OR(name, "")), 7); /* Ensure there is enough room for 'removed' */
108 size_t name_len = MAX(strlen(S_OR(name, "")), MIN_STREAM_NAME_LEN); /* Ensure there is enough room for 'removed' or a type-position */
107109
108110 stream = ast_calloc(1, sizeof(*stream) + name_len + 1);
109111 if (!stream) {
135137 }
136138
137139 stream_name = name ?: stream->name;
138 name_len = MAX(strlen(stream_name), 7); /* Ensure there is enough room for 'removed' */
140 name_len = MAX(strlen(S_OR(stream_name, "")), MIN_STREAM_NAME_LEN); /* Ensure there is enough room for 'removed' or a type-position */
139141 new_stream = ast_calloc(1, sizeof(*stream) + name_len + 1);
140142 if (!new_stream) {
141143 return NULL;
252254
253255 stream->state = state;
254256
255 /* When a stream is set to removed that means that any previous data for it
256 * is no longer valid. We therefore change its name to removed and remove
257 * any old metadata associated with it.
258 */
259 if (state == AST_STREAM_STATE_REMOVED) {
260 strcpy(stream->name, "removed");
261 ast_variables_destroy(stream->metadata);
262 stream->metadata = NULL;
263 if (stream->formats) {
264 ast_format_cap_remove_by_type(stream->formats, AST_MEDIA_TYPE_UNKNOWN);
265 }
266 }
267257 }
268258
269259 const char *ast_stream_state2str(enum ast_stream_state state)
520510
521511 stream->position = AST_VECTOR_SIZE(&topology->streams) - 1;
522512
513 if (ast_strlen_zero(stream->name)) {
514 snprintf(stream->name, MIN_STREAM_NAME_LEN, "%s-%d", ast_codec_media_type2str(stream->type), stream->position);
515 }
516
523517 return AST_VECTOR_SIZE(&topology->streams) - 1;
524518 }
525519
576570 return AST_VECTOR_APPEND(&topology->streams, stream);
577571 }
578572
573 if (ast_strlen_zero(stream->name)) {
574 snprintf(stream->name, MIN_STREAM_NAME_LEN, "%s-%d", ast_codec_media_type2str(stream->type), stream->position);
575 }
576
579577 return AST_VECTOR_REPLACE(&topology->streams, position, stream);
580578 }
581579
634632 return NULL;
635633 }
636634
637 stream = ast_stream_alloc(ast_codec_media_type2str(type), type);
635 stream = ast_stream_alloc(NULL, type);
638636 if (!stream) {
639637 ao2_cleanup(new_cap);
640638 ast_stream_topology_free(topology);
649647 ast_stream_topology_free(topology);
650648 return NULL;
651649 }
650
651 snprintf(stream->name, MIN_STREAM_NAME_LEN, "%s-%d", ast_codec_media_type2str(stream->type), stream->position);
652652 }
653653
654654 return topology;
3131
3232 #include "asterisk.h"
3333
34 #include "asterisk/logger.h"
35 #include "asterisk/logger_category.h"
3436 #include "asterisk/_private.h"
3537 #include "asterisk/stun.h"
3638 #include "asterisk/cli.h"
3739 #include "asterisk/utils.h"
3840 #include "asterisk/channel.h"
39
40 static int stundebug; /*!< Are we debugging stun? */
4141
4242 /*!
4343 * \brief STUN support code
177177
178178 static int stun_process_attr(struct stun_state *state, struct stun_attr *attr)
179179 {
180 if (stundebug)
180 if (ast_debug_stun_packet_is_allowed) {
181181 ast_verbose("Found STUN Attribute %s (%04x), length %d\n",
182 stun_attr2str(ntohs(attr->attr)), (unsigned)ntohs(attr->attr), ntohs(attr->len));
182 stun_attr2str(ntohs(attr->attr)), (unsigned)ntohs(attr->attr), ntohs(attr->len));
183 }
183184 switch (ntohs(attr->attr)) {
184185 case STUN_USERNAME:
185186 state->username = (const char *) (attr->value);
188189 state->password = (const char *) (attr->value);
189190 break;
190191 default:
191 if (stundebug)
192 if (ast_debug_stun_packet_is_allowed) {
192193 ast_verbose("Ignoring STUN attribute %s (%04x), length %d\n",
193 stun_attr2str(ntohs(attr->attr)), (unsigned)ntohs(attr->attr), ntohs(attr->len));
194 }
194 stun_attr2str(ntohs(attr->attr)), (unsigned)ntohs(attr->attr), ntohs(attr->len));
195 }
196 }
197
195198 return 0;
196199 }
197200
274277 * while 'data' is advanced accordingly.
275278 */
276279 if (len < sizeof(struct stun_header)) {
277 ast_debug(1, "Runt STUN packet (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header));
280 ast_debug_stun(1, "Runt STUN packet (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header));
278281 return -1;
279282 }
280283 len -= sizeof(struct stun_header);
281284 data += sizeof(struct stun_header);
282285 x = ntohs(hdr->msglen); /* len as advertised in the message */
283 if (stundebug)
286 if (ast_debug_stun_packet_is_allowed)
284287 ast_verbose("STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), (unsigned)ntohs(hdr->msgtype), x);
285288 if (x > len) {
286 ast_debug(1, "Scrambled STUN packet length (got %d, expecting %d)\n", x, (int)len);
289 ast_debug_stun(1, "Scrambled STUN packet length (got %d, expecting %d)\n", x, (int)len);
287290 } else
288291 len = x;
289292 memset(&st, 0, sizeof(st));
290293 while (len) {
291294 if (len < sizeof(struct stun_attr)) {
292 ast_debug(1, "Runt Attribute (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr));
295 ast_debug_stun(1, "Runt Attribute (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr));
293296 break;
294297 }
295298 attr = (struct stun_attr *)data;
296299 /* compute total attribute length */
297300 x = ntohs(attr->len) + sizeof(struct stun_attr);
298301 if (x > len) {
299 ast_debug(1, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", x, (int)len);
302 ast_debug_stun(1, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", x, (int)len);
300303 break;
301304 }
302305 if (stun_cb)
303306 stun_cb(attr, arg);
304307 if (stun_process_attr(&st, attr)) {
305 ast_debug(1, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), (unsigned)ntohs(attr->attr));
308 ast_debug_stun(1, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), (unsigned)ntohs(attr->attr));
306309 break;
307310 }
308311 /* Clear attribute id: in case previous entry was a string,
336339 attr = (struct stun_attr *)resp->ies;
337340 switch (ntohs(hdr->msgtype)) {
338341 case STUN_BINDREQ:
339 if (stundebug)
342 if (ast_debug_stun_packet_is_allowed)
340343 ast_verbose("STUN Bind Request, username: %s\n",
341344 st.username ? st.username : "<none>");
342345 if (st.username) {
354357 ret = AST_STUN_ACCEPT;
355358 break;
356359 default:
357 if (stundebug)
360 if (ast_debug_stun_packet_is_allowed)
358361 ast_verbose("Dunno what to do with STUN message %04x (%s)\n", (unsigned)ntohs(hdr->msgtype), stun_msg2str(ntohs(hdr->msgtype)));
359362 }
360363 }
415418 /* Send STUN message. */
416419 res = stun_send(s, dst, req);
417420 if (res < 0) {
418 ast_debug(1, "stun_send try %d failed: %s\n", retry, strerror(errno));
421 ast_debug_stun(1, "stun_send try %d failed: %s\n", retry, strerror(errno));
419422 break;
420423 }
421424 if (!answer) {
458461 res = recvfrom(s, rsp_buf, sizeof(rsp_buf) - 1,
459462 0, (struct sockaddr *) &src, &srclen);
460463 if (res < 0) {
461 ast_debug(1, "recvfrom try %d failed: %s\n", retry, strerror(errno));
464 ast_debug_stun(1, "recvfrom try %d failed: %s\n", retry, strerror(errno));
462465 break;
463466 }
464467
499502 return CLI_SHOWUSAGE;
500503
501504 if (!strncasecmp(a->argv[e->args-1], "on", 2))
502 stundebug = 1;
505 ast_debug_category_set_sublevel(AST_LOG_CATEGORY_STUN_PACKET, AST_LOG_CATEGORY_ENABLED);
503506 else if (!strncasecmp(a->argv[e->args-1], "off", 3))
504 stundebug = 0;
507 ast_debug_category_set_sublevel(AST_LOG_CATEGORY_STUN_PACKET, AST_LOG_CATEGORY_DISABLED);
505508 else
506509 return CLI_SHOWUSAGE;
507510
508 ast_cli(a->fd, "STUN Debugging %s\n", stundebug ? "Enabled" : "Disabled");
511 ast_cli(a->fd, "STUN Debugging %s\n", ast_debug_stun_packet_is_allowed ? "Enabled" : "Disabled");
509512 return CLI_SUCCESS;
510513 }
511514
513516 AST_CLI_DEFINE(handle_cli_stun_set_debug, "Enable/Disable STUN debugging"),
514517 };
515518
519 static uintmax_t debug_category_stun_id;
520
521 uintmax_t ast_debug_category_stun_id(void)
522 {
523 return debug_category_stun_id;
524 }
525
526 static uintmax_t debug_category_stun_packet_id;
527
528 uintmax_t ast_debug_category_stun_packet_id(void)
529 {
530 return debug_category_stun_packet_id;
531 }
532
516533 static void stun_shutdown(void)
517534 {
518535 ast_cli_unregister_multiple(cli_stun, sizeof(cli_stun) / sizeof(struct ast_cli_entry));
536
537 ast_debug_category_unregister(AST_LOG_CATEGORY_STUN_PACKET);
538 ast_debug_category_unregister(AST_LOG_CATEGORY_STUN);
519539 }
520540
521541 /*! \brief Initialize the STUN system in Asterisk */
523543 {
524544 ast_cli_register_multiple(cli_stun, sizeof(cli_stun) / sizeof(struct ast_cli_entry));
525545 ast_register_cleanup(stun_shutdown);
526 }
546
547 debug_category_stun_id = ast_debug_category_register(AST_LOG_CATEGORY_STUN);
548 debug_category_stun_packet_id = ast_debug_category_register(AST_LOG_CATEGORY_STUN_PACKET);
549 }
607607 return handle_tcptls_connection(tcptls_session);
608608
609609 client_start_error:
610 if (desc) {
611 close(desc->accept_fd);
612 desc->accept_fd = -1;
613 }
614610 ao2_ref(tcptls_session, -1);
615611 return NULL;
616
617612 }
618613
619614 struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_session_args *desc)
629624
630625 /* If we return early, there is no connection */
631626 ast_sockaddr_setnull(&desc->old_address);
632
633 if (desc->accept_fd != -1) {
634 close(desc->accept_fd);
635 }
636627
637628 fd = desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->remote_address) ?
638629 AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP);
670661 if (!tcptls_session->stream) {
671662 goto error;
672663 }
664
665 /* From here on out, the iostream owns the accept_fd and it will take
666 * care of closing it when the iostream is closed */
673667
674668 tcptls_session->parent = desc;
675669 tcptls_session->parent->worker_fn = NULL;
307307 }
308308 /* Don't worry about left over bits, they're extra anyway */
309309 return cnt;
310 }
311
312 /*! \brief Decode BASE64 encoded text and return the string */
313 char *ast_base64decode_string(const char *src)
314 {
315 size_t encoded_len;
316 size_t decoded_len;
317 int padding = 0;
318 unsigned char *decoded_string;
319
320 if (ast_strlen_zero(src)) {
321 return NULL;
322 }
323
324 encoded_len = strlen(src);
325 if (encoded_len > 2 && src[encoded_len - 1] == '=') {
326 padding++;
327 if (src[encoded_len - 2] == '=') {
328 padding++;
329 }
330 }
331
332 decoded_len = (encoded_len / 4 * 3) - padding;
333 decoded_string = ast_malloc(decoded_len + 1);
334 if (!decoded_string) {
335 return NULL;
336 }
337
338 ast_base64decode(decoded_string, src, decoded_len);
339 decoded_string[decoded_len] = '\0';
340
341 return (char *)decoded_string;
310342 }
311343
312344 /*! \brief encode text to BASE64 coding */
364396 int ast_base64encode(char *dst, const unsigned char *src, int srclen, int max)
365397 {
366398 return ast_base64encode_full(dst, src, srclen, max, 0);
399 }
400
401 /*! \brief Encode to BASE64 and return encoded string */
402 char *ast_base64encode_string(const char *src)
403 {
404 size_t encoded_len;
405 char *encoded_string;
406
407 if (ast_strlen_zero(src)) {
408 return NULL;
409 }
410
411 encoded_len = ((strlen(src) * 4 / 3 + 3) & ~3) + 1;
412 encoded_string = ast_calloc(1, encoded_len);
413
414 ast_base64encode(encoded_string, (const unsigned char *)src, strlen(src), encoded_len);
415
416 return encoded_string;
367417 }
368418
369419 static void base64_init(void)
6868 $(call MOD_ADD_C,res_ari,ari/cli.c ari/config.c ari/ari_websockets.c)
6969 $(call MOD_ADD_C,res_ari_model,ari/ari_model_validators.c)
7070 $(call MOD_ADD_C,res_stasis_recording,stasis_recording/stored.c)
71 $(call MOD_ADD_C,res_stir_shaken,$(wildcard res_stir_shaken/*.c))
7172
7273 res_parking.o: _ASTCFLAGS+=$(AST_NO_FORMAT_TRUNCATION)
7374
5151 void ast_ari_bridges_list(struct ast_variable *headers, struct ast_ari_bridges_list_args *args, struct ast_ari_response *response);
5252 /*! Argument struct for ast_ari_bridges_create() */
5353 struct ast_ari_bridges_create_args {
54 /*! Comma separated list of bridge type attributes (mixing, holding, dtmf_events, proxy_media, video_sfu). */
54 /*! Comma separated list of bridge type attributes (mixing, holding, dtmf_events, proxy_media, video_sfu, video_single). */
5555 const char *type;
5656 /*! Unique ID to give to the bridge being created. */
5757 const char *bridge_id;
8181 void ast_ari_bridges_create(struct ast_variable *headers, struct ast_ari_bridges_create_args *args, struct ast_ari_response *response);
8282 /*! Argument struct for ast_ari_bridges_create_with_id() */
8383 struct ast_ari_bridges_create_with_id_args {
84 /*! Comma separated list of bridge type attributes (mixing, holding, dtmf_events, proxy_media, video_sfu) to set. */
84 /*! Comma separated list of bridge type attributes (mixing, holding, dtmf_events, proxy_media, video_sfu, video_single) to set. */
8585 const char *type;
8686 /*! Unique ID to give to the bridge being created. */
8787 const char *bridge_id;
210210 if (ast_msg_send(msg, to, from)) {
211211 ast_ari_response_error(response, 404, "Not Found",
212212 "Endpoint not found");
213 return;
213214 }
214215
215216 response->message = ast_json_null();
660660 dial_string_flat, PARK_DIAL_CONTEXT, ast_get_extension_registrar(existing_exten));
661661 } else if (ast_add_extension2_nolock(park_dial_context, 1, dial_string_flat, 1, NULL, NULL,
662662 "Dial", duplicate_returnexten, ast_free_ptr, BASE_REGISTRAR, NULL, 0)) {
663 ast_free(duplicate_returnexten);
664663 ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n",
665664 dial_string_flat, PARK_DIAL_CONTEXT, returnexten);
666665 }
476476 return -1;
477477 }
478478
479 state->samples += f->samples;
479 /* Only track our offset within the current file if we are not in the
480 * the middle of an announcement */
481 if (!state->announcement) {
482 state->samples += f->samples;
483 }
484
480485 state->sample_queue -= f->samples;
481486 if (ast_format_cmp(f->subclass.format, state->mohwfmt) == AST_FORMAT_CMP_NOT_EQUAL) {
482487 ao2_replace(state->mohwfmt, f->subclass.format);
11381143
11391144 AST_VECTOR_APPEND(playlist_entries, dup);
11401145 } else {
1141 ast_log(LOG_ERROR, "Playlist entries must be a URL or absolute path, '%s' provided.\n", var->value);
1146 ast_log(LOG_ERROR, "Playlist entries must be an HTTP(S) URL or absolute path, '%s' provided.\n", var->value);
11421147 }
11431148 } else if (!strcasecmp(var->name, "directory")) {
11441149 ast_copy_string(mohclass->dir, var->value, sizeof(mohclass->dir));
16031608 if (var) {
16041609 const char *mode = ast_variable_find_in_list(var, "mode");
16051610 if (ast_strings_equal(mode, "playlist")) {
1606 struct ast_variable *entries = ast_load_realtime("musiconhold_entry", "name", name, SENTINEL);
1607 struct ast_variable *cur = entries;
1611 struct ast_config *entries = ast_load_realtime_multientry("musiconhold_entry", "position >=", "0", "name", name, SENTINEL);
1612 char *category = NULL;
16081613 size_t entry_count = 0;
1609 for (; cur; cur = cur->next) {
1610 if (!strcmp(cur->name, "entry")) {
1611 struct ast_variable *dup = ast_variable_new(cur->name, cur->value, "");
1614
1615 while ((category = ast_category_browse(entries, category))) {
1616 const char *entry = ast_variable_retrieve(entries, category, "entry");
1617
1618 if (entry) {
1619 struct ast_variable *dup = ast_variable_new("entry", entry, "");
16121620 if (dup) {
16131621 entry_count++;
16141622 ast_variable_list_append(&var, dup);
16151623 }
16161624 }
16171625 }
1618 ast_variables_destroy(entries);
1626 ast_config_destroy(entries);
16191627
16201628 if (entry_count == 0) {
16211629 /* Behave as though this class doesn't exist */
723723
724724 if (ast_add_extension2_nolock(context, replace, extension, priority, NULL, NULL,
725725 application, data_duplicate, ast_free_ptr, registrar, NULL, 0)) {
726 ast_free(data_duplicate);
727726 return -1;
728727 }
729728
617617 res = pjsip_tcp_transport_start3(ast_sip_get_pjsip_endpoint(), &cfg,
618618 &temp_state->state->factory);
619619 }
620 #if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0
620621 } else if (transport->type == AST_TRANSPORT_TLS) {
621622 static int option = 1;
622623
647648 &temp_state->state->host, NULL, transport->async_operations,
648649 &temp_state->state->factory);
649650 }
651 #endif
650652 } else if ((transport->type == AST_TRANSPORT_WS) || (transport->type == AST_TRANSPORT_WSS)) {
651653 if (transport->cos || transport->tos) {
652654 ast_log(LOG_WARNING, "TOS and COS values ignored for websocket transport\n");
977979 }
978980
979981 /*! \brief Helper function which turns a cipher name into an identifier */
982 #if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0
980983 static pj_ssl_cipher cipher_name_to_id(const char *name)
981984 {
982985 pj_ssl_cipher ciphers[PJ_SSL_SOCK_MAX_CIPHERS];
996999
9971000 return 0;
9981001 }
1002 #endif
9991003
10001004 /*!
10011005 * \internal
10071011 * \retval 0 on success.
10081012 * \retval -1 on error.
10091013 */
1014 #if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0
10101015 static int transport_cipher_add(struct ast_sip_transport_state *state, const char *name)
10111016 {
10121017 pj_ssl_cipher cipher;
10371042 return -1;
10381043 }
10391044 }
1045 #endif
10401046
10411047 /*! \brief Custom handler for TLS cipher setting */
1048 #if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0
10421049 static int transport_tls_cipher_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
10431050 {
10441051 struct ast_sip_transport *transport = obj;
10651072 }
10661073 return res ? -1 : 0;
10671074 }
1068
1075 #endif
1076
1077 #if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0
10691078 static void cipher_to_str(char **buf, const pj_ssl_cipher *ciphers, unsigned int cipher_num)
10701079 {
10711080 struct ast_str *str;
10871096 *buf = ast_strdup(ast_str_buffer(str));
10881097 ast_free(str);
10891098 }
1090
1099 #endif
1100
1101 #if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0
10911102 static int transport_tls_cipher_to_str(const void *obj, const intptr_t *args, char **buf)
10921103 {
10931104 const struct ast_sip_transport *transport = obj;
11001111 cipher_to_str(buf, state->ciphers, state->tls.ciphers_num);
11011112 return *buf ? 0 : -1;
11021113 }
1103
1114 #endif
1115
1116 #if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0
11041117 static char *handle_pjsip_list_ciphers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11051118 {
11061119 pj_ssl_cipher ciphers[PJ_SSL_SOCK_MAX_CIPHERS];
11311144 ast_free(buf);
11321145 return CLI_SUCCESS;
11331146 }
1147 #endif
11341148
11351149 /*! \brief Custom handler for localnet setting */
11361150 static int transport_localnet_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
13301344 }
13311345
13321346 static struct ast_cli_entry cli_commands[] = {
1347 #if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0
13331348 AST_CLI_DEFINE(handle_pjsip_list_ciphers, "List available OpenSSL cipher names"),
1349 #endif
13341350 AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Transports",
13351351 .command = "pjsip list transports",
13361352 .usage = "Usage: pjsip list transports [ like <pattern> ]\n"
14321448 ast_sorcery_object_field_register_custom(sorcery, "transport", "verify_client", "", transport_tls_bool_handler, verify_client_to_str, NULL, 0, 0);
14331449 ast_sorcery_object_field_register_custom(sorcery, "transport", "require_client_cert", "", transport_tls_bool_handler, require_client_cert_to_str, NULL, 0, 0);
14341450 ast_sorcery_object_field_register_custom(sorcery, "transport", "method", "", transport_tls_method_handler, tls_method_to_str, NULL, 0, 0);
1451 #if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0
14351452 ast_sorcery_object_field_register_custom(sorcery, "transport", "cipher", "", transport_tls_cipher_handler, transport_tls_cipher_to_str, NULL, 0, 0);
1453 #endif
14361454 ast_sorcery_object_field_register_custom(sorcery, "transport", "local_net", "", transport_localnet_handler, localnet_to_str, localnet_to_vl, 0, 0);
14371455 ast_sorcery_object_field_register_custom(sorcery, "transport", "tos", "0", transport_tos_handler, tos_to_str, NULL, 0, 0);
14381456 ast_sorcery_object_field_register(sorcery, "transport", "cos", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, cos));
18811881 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_rpid", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_rpid));
18821882 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rpid_immediate", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.rpid_immediate));
18831883 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_diversion", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_diversion));
1884 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_history_info", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_history_info));
18841885 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, subscription.mwi.mailboxes));
18851886 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "voicemail_extension", "", voicemail_extension_handler, voicemail_extension_to_str, NULL, 0, 0);
18861887 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "aggregate_mwi", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.mwi.aggregate));
19651966 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "accept_multiple_sdp_answers", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.accept_multiple_sdp_answers));
19661967 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "suppress_q850_reason_headers", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, suppress_q850_reason_headers));
19671968 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "ignore_183_without_sdp", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, ignore_183_without_sdp));
1969 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "stir_shaken", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, stir_shaken));
19681970
19691971 if (ast_sip_initialize_sorcery_transport()) {
19701972 ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
2828 #include "include/res_pjsip_private.h"
2929 #include "asterisk/res_pjsip_cli.h"
3030 #include "asterisk/taskprocessor.h"
31
32 #include <regex.h>
3133
3234 #define TASK_BUCKETS 53
3335
104106 * Don't restart if the task returned <= 0 or if the interval
105107 * was set to 0 while the task was running
106108 */
107 if (res <= 0 || !schtd->interval) {
109 if ((schtd->flags & AST_SIP_SCHED_TASK_ONESHOT) || res <= 0 || !schtd->interval) {
108110 schtd->interval = 0;
109111 ao2_unlock(schtd);
110112 ao2_unlink(tasks, schtd);
231233 return res;
232234 }
233235
234
235 int ast_sip_sched_task_get_times(struct ast_sip_sched_task *schtd,
236 struct timeval *queued, struct timeval *last_start, struct timeval *last_end)
236 int ast_sip_sched_task_get_times2(struct ast_sip_sched_task *schtd,
237 struct timeval *queued, struct timeval *last_start, struct timeval *last_end,
238 int *interval, int *time_left, struct timeval *next_start)
237239 {
238240 ao2_lock(schtd);
239241 if (queued) {
245247 if (last_end) {
246248 memcpy(last_end, &schtd->last_end, sizeof(struct timeval));
247249 }
250
251 if (interval) {
252 *interval = schtd->interval;
253 }
254
255 if (time_left || next_start) {
256 int delay;
257 struct timeval since_when;
258 struct timeval now;
259 struct timeval next;
260
261 if (schtd->interval) {
262 delay = schtd->interval;
263 now = ast_tvnow();
264
265 if (schtd->flags & AST_SIP_SCHED_TASK_DELAY) {
266 since_when = schtd->is_running ? now : schtd->last_end;
267 } else {
268 since_when = schtd->last_start.tv_sec ? schtd->last_start : schtd->when_queued;
269 }
270
271 delay -= ast_tvdiff_ms(now, since_when);
272
273 delay = delay < 0 ? 0 : delay;
274
275
276 if (time_left) {
277 *time_left = delay;
278 }
279
280 if (next_start) {
281 next = ast_tvadd(now, ast_tv(delay / 1000, (delay % 1000) * 1000));
282 memcpy(next_start, &next, sizeof(struct timeval));
283 }
284 } else {
285 if (time_left) {
286 *time_left = -1;
287 }
288 }
289
290 }
291
248292 ao2_unlock(schtd);
249293
250294 return 0;
295 }
296
297
298 int ast_sip_sched_task_get_times(struct ast_sip_sched_task *schtd,
299 struct timeval *queued, struct timeval *last_start, struct timeval *last_end)
300 {
301 return ast_sip_sched_task_get_times2(schtd, queued, last_start, last_end, NULL, NULL, NULL);
302 }
303
304 int ast_sip_sched_task_get_times_by_name2(const char *name,
305 struct timeval *queued, struct timeval *last_start, struct timeval *last_end,
306 int *interval, int *time_left, struct timeval *next_start)
307 {
308 int res;
309 struct ast_sip_sched_task *schtd;
310
311 if (ast_strlen_zero(name)) {
312 return -1;
313 }
314
315 schtd = ao2_find(tasks, name, OBJ_SEARCH_KEY);
316 if (!schtd) {
317 return -1;
318 }
319
320 res = ast_sip_sched_task_get_times2(schtd, queued, last_start, last_end, interval, time_left,
321 next_start);
322 ao2_ref(schtd, -1);
323 return res;
251324 }
252325
253326 int ast_sip_sched_task_get_times_by_name(const char *name,
254327 struct timeval *queued, struct timeval *last_start, struct timeval *last_end)
255328 {
256 int res;
257 struct ast_sip_sched_task *schtd;
258
259 if (ast_strlen_zero(name)) {
260 return -1;
261 }
262
263 schtd = ao2_find(tasks, name, OBJ_SEARCH_KEY);
264 if (!schtd) {
265 return -1;
266 }
267
268 res = ast_sip_sched_task_get_times(schtd, queued, last_start, last_end);
269 ao2_ref(schtd, -1);
270 return res;
329 return ast_sip_sched_task_get_times_by_name2(name, queued, last_start, last_end,
330 NULL, NULL, NULL);
271331 }
272332
273333 int ast_sip_sched_task_get_name(struct ast_sip_sched_task *schtd, char *name, size_t maxlen)
286346 int ast_sip_sched_task_get_next_run(struct ast_sip_sched_task *schtd)
287347 {
288348 int delay;
289 struct timeval since_when;
290 struct timeval now;
291
292 ao2_lock(schtd);
293
294 if (schtd->interval) {
295 delay = schtd->interval;
296 now = ast_tvnow();
297
298 if (schtd->flags & AST_SIP_SCHED_TASK_DELAY) {
299 since_when = schtd->is_running ? now : schtd->last_end;
300 } else {
301 since_when = schtd->last_start.tv_sec ? schtd->last_start : schtd->when_queued;
302 }
303
304 delay -= ast_tvdiff_ms(now, since_when);
305
306 delay = delay < 0 ? 0 : delay;
307 } else {
308 delay = -1;
309 }
310
311 ao2_unlock(schtd);
349
350 ast_sip_sched_task_get_times2(schtd, NULL, NULL, NULL, NULL, &delay, NULL);
312351
313352 return delay;
314353 }
395434 schtd->task = sip_task;
396435 schtd->interval = interval;
397436 schtd->flags = flags;
437 schtd->last_start = ast_tv(0, 0);
398438 if (!ast_strlen_zero(name)) {
399439 strcpy(schtd->name, name); /* Safe */
400440 } else {
444484 #undef ID_LEN
445485 }
446486
487 #define TIME_FORMAT "%a %T"
488
447489 static char *cli_show_tasks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
448490 {
449491 struct ao2_iterator iter;
450492 struct ao2_container *sorted_tasks;
451493 struct ast_sip_sched_task *schtd;
452 const char *log_format;
453494 struct ast_tm tm;
495 char times_run[16];
454496 char queued[32];
455497 char last_start[32];
456498 char next_start[32];
457 int datelen;
458499 struct timeval now;
459 static const char separator[] = "=============================================";
500 int using_regex = 0;
501 regex_t regex;
460502
461503 switch (cmd) {
462504 case CLI_INIT:
463505 e->command = "pjsip show scheduled_tasks";
464 e->usage = "Usage: pjsip show scheduled_tasks\n"
465 " Show all scheduled tasks\n";
506 e->usage = "Usage: pjsip show scheduled_tasks [ like <pattern> ]\n"
507 " Show scheduled pjsip tasks\n";
466508 return NULL;
467509 case CLI_GENERATE:
468510 return NULL;
469511 }
470512
471 if (a->argc != 3) {
513 if (a->argc != 3 && a->argc != 5) {
472514 return CLI_SHOWUSAGE;
515 }
516
517 if (a->argc == 5) {
518 int regrc;
519 if (!strcasecmp(a->argv[3], "like") == 0) {
520 return CLI_SHOWUSAGE;
521 }
522 regrc = regcomp(&regex, a->argv[4], REG_EXTENDED | REG_ICASE | REG_NOSUB);
523 if (regrc) {
524 char err[256];
525 regerror(regrc, &regex, err, 256);
526 ast_cli(a->fd, "PJSIP Scheduled Tasks: Error: %s\n", err);
527 return CLI_FAILURE;
528 }
529 using_regex = 1;
473530 }
474531
475532 /* Get a sorted snapshot of the scheduled tasks */
476533 sorted_tasks = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
477534 ast_sip_sched_task_sort_fn, NULL);
478535 if (!sorted_tasks) {
479 return CLI_SUCCESS;
536 ast_cli(a->fd, "PJSIP Scheduled Tasks: Unable to allocate temporary container\n");
537 return CLI_FAILURE;
480538 }
481539 if (ao2_container_dup(sorted_tasks, tasks, 0)) {
482540 ao2_ref(sorted_tasks, -1);
483 return CLI_SUCCESS;
541 ast_cli(a->fd, "PJSIP Scheduled Tasks: Unable to sort temporary container\n");
542 return CLI_FAILURE;
484543 }
485544
486545 now = ast_tvnow();
487 log_format = ast_logger_get_dateformat();
488546
489547 ast_localtime(&now, &tm, NULL);
490 datelen = ast_strftime(queued, sizeof(queued), log_format, &tm);
491548
492549 ast_cli(a->fd, "PJSIP Scheduled Tasks:\n\n");
493550
494 ast_cli(a->fd, "%1$-45s %2$-9s %3$-9s %4$-5s %6$-*5$s %7$-*5$s %8$-*5$s %9$7s\n",
495 "Task Name", "Interval", "Times Run", "State",
496 datelen, "Queued", "Last Started", "Next Start", "( secs)");
497
498 ast_cli(a->fd, "%1$-45.45s %2$-9.9s %3$-9.9s %4$-5.5s %6$-*5$.*5$s %7$-*5$.*5$s %9$-*8$.*8$s\n",
499 separator, separator, separator, separator,
500 datelen, separator, separator, datelen + 8, separator);
551 ast_cli(a->fd,
552 "<Task Name....................................> <Interval> <Times Run> <State>"
553 " <Queued....> <Last Start> <Next Start.....secs>\n"
554 "=============================================================================="
555 "===================================================\n");
501556
502557 iter = ao2_iterator_init(sorted_tasks, AO2_ITERATOR_UNLINK);
503558 for (; (schtd = ao2_iterator_next(&iter)); ao2_ref(schtd, -1)) {
505560 struct timeval next;
506561
507562 ao2_lock(schtd);
563
564 if (using_regex && regexec(&regex, schtd->name, 0, NULL, 0) == REG_NOMATCH) {
565 ao2_unlock(schtd);
566 continue;
567 }
508568
509569 next_run_sec = ast_sip_sched_task_get_next_run(schtd) / 1000;
510570 if (next_run_sec < 0) {
515575 next = ast_tvadd(now, ast_tv(next_run_sec, 0));
516576
517577 ast_localtime(&schtd->when_queued, &tm, NULL);
518 ast_strftime(queued, sizeof(queued), log_format, &tm);
519
520 if (ast_tvzero(schtd->last_start)) {
521 strcpy(last_start, "not yet started");
522 } else {
523 ast_localtime(&schtd->last_start, &tm, NULL);
524 ast_strftime(last_start, sizeof(last_start), log_format, &tm);
525 }
578 ast_strftime(queued, sizeof(queued), TIME_FORMAT, &tm);
579
580 ast_localtime(&schtd->last_start, &tm, NULL);
581 ast_strftime(last_start, sizeof(last_start), TIME_FORMAT, &tm);
526582
527583 ast_localtime(&next, &tm, NULL);
528 ast_strftime(next_start, sizeof(next_start), log_format, &tm);
529
530 ast_cli(a->fd, "%1$-46.46s%2$9.3f %3$9d %4$-5s %6$-*5$s %7$-*5$s %8$-*5$s (%9$5d)\n",
584 ast_strftime(next_start, sizeof(next_start), TIME_FORMAT, &tm);
585
586 sprintf(times_run, "%d", schtd->run_count);
587
588 ast_cli(a->fd, "%-46.46s %9d %9s %-5s %-12s %-12s %-12s %8d\n",
531589 schtd->name,
532 schtd->interval / 1000.0,
533 schtd->run_count,
590 schtd->interval / 1000,
591 schtd->flags & AST_SIP_SCHED_TASK_ONESHOT ? "oneshot" : times_run,
534592 schtd->is_running ? "run" : "wait",
535 datelen, queued, last_start,
593 queued,
594 (ast_tvzero(schtd->last_start) || (schtd->flags & AST_SIP_SCHED_TASK_ONESHOT) ? "" : last_start),
536595 next_start,
537596 next_run_sec);
538597 ao2_unlock(schtd);
539598 }
599 if (using_regex) {
600 regfree(&regex);
601 }
540602 ao2_iterator_destroy(&iter);
603 ast_cli(a->fd, "\nTotal Scheduled Tasks: %d\n\n", ao2_container_count(sorted_tasks));
541604 ao2_ref(sorted_tasks, -1);
542 ast_cli(a->fd, "\n");
543605
544606 return CLI_SUCCESS;
545607 }
546608
547609 static struct ast_cli_entry cli_commands[] = {
548 AST_CLI_DEFINE(cli_show_tasks, "Show all scheduled tasks"),
610 AST_CLI_DEFINE(cli_show_tasks, "Show pjsip scheduled tasks"),
549611 };
550612
551613 int ast_sip_initialize_scheduler(void)
7777 static void *keepalive_transport_thread(void *data)
7878 {
7979 struct ao2_container *transports;
80 pj_thread_desc desc;
80 pj_thread_desc desc = { 0 };
8181 pj_thread_t *thread;
8282
8383 if (pj_thread_register("Asterisk Keepalive Thread", desc, &thread) != PJ_SUCCESS) {
425425 <synopsis>Send the Diversion header, conveying the diversion
426426 information to the called user agent</synopsis>
427427 </configOption>
428 <configOption name="send_history_info" default="no">
429 <synopsis>Send the History-Info header, conveying the diversion
430 information to the called and calling user agents</synopsis>
431 </configOption>
428432 <configOption name="send_pai" default="no">
429433 <synopsis>Send the P-Asserted-Identity header</synopsis>
430434 </configOption>
11511155 this 183 can cause loss of ringback tone. This flag emulates
11521156 the behavior of chan_sip and prevents these 183 responses from
11531157 being forwarded.</para>
1158 </description>
1159 </configOption>
1160 <configOption name="stir_shaken" default="no">
1161 <synopsis>Enable STIR/SHAKEN support on this endpoint</synopsis>
1162 <description><para>
1163 Enable STIR/SHAKEN support on this endpoint. On incoming INVITEs,
1164 the Identity header will be checked for validity. On outgoing
1165 INVITEs, an Identity header will be added.</para>
11541166 </description>
11551167 </configOption>
11561168 </configObject>
31063118 return endpoint;
31073119 }
31083120
3121 char *ast_sip_rdata_get_header_value(pjsip_rx_data *rdata, const pj_str_t str)
3122 {
3123 pjsip_generic_string_hdr *hdr;
3124 pj_str_t hdr_val;
3125
3126 hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str, NULL);
3127 if (!hdr) {
3128 return NULL;
3129 }
3130
3131 pj_strdup_with_null(rdata->tp_info.pool, &hdr_val, &hdr->hvalue);
3132
3133 return hdr_val.ptr;
3134 }
3135
31093136 static int do_cli_dump_endpt(void *v_a)
31103137 {
31113138 struct ast_cli_args *a = v_a;
36763703 return 0;
36773704 }
36783705
3679 pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pj_status_t *status)
3706 typedef pj_status_t (*create_dlg_uac)(pjsip_user_agent *ua, pjsip_rx_data *rdata,
3707 const pj_str_t *contact, pjsip_dialog **p_dlg);
3708
3709 static pjsip_dialog *create_dialog_uas(const struct ast_sip_endpoint *endpoint,
3710 pjsip_rx_data *rdata, pj_status_t *status, create_dlg_uac create_fun)
36803711 {
36813712 pjsip_dialog *dlg;
36823713 pj_str_t contact;
37113742 (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "",
37123743 (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : "");
37133744
3714 #ifdef HAVE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK
3715 *status = pjsip_dlg_create_uas_and_inc_lock(pjsip_ua_instance(), rdata, &contact, &dlg);
3716 #else
3717 *status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, &contact, &dlg);
3718 #endif
3745 *status = create_fun(pjsip_ua_instance(), rdata, &contact, &dlg);
37193746 if (*status != PJ_SUCCESS) {
37203747 char err[PJ_ERR_MSG_SIZE];
37213748
37283755 dlg->sess_count++;
37293756 pjsip_dlg_set_transport(dlg, &selector);
37303757 dlg->sess_count--;
3758
3759 return dlg;
3760 }
3761
3762 pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pj_status_t *status)
3763 {
37313764 #ifdef HAVE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK
3732 pjsip_dlg_dec_lock(dlg);
3765 pjsip_dialog *dlg;
3766
3767 dlg = create_dialog_uas(endpoint, rdata, status, pjsip_dlg_create_uas_and_inc_lock);
3768 if (dlg) {
3769 pjsip_dlg_dec_lock(dlg);
3770 }
3771
3772 return dlg;
3773 #else
3774 return create_dialog_uas(endpoint, rdata, status, pjsip_dlg_create_uas);
37333775 #endif
3776 }
3777
3778 pjsip_dialog *ast_sip_create_dialog_uas_locked(const struct ast_sip_endpoint *endpoint,
3779 pjsip_rx_data *rdata, pj_status_t *status)
3780 {
3781 #ifdef HAVE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK
3782 return create_dialog_uas(endpoint, rdata, status, pjsip_dlg_create_uas_and_inc_lock);
3783 #else
3784 /*
3785 * This is put here in order to be compatible with older versions of pjproject.
3786 * Best we can do in this case is immediately lock after getting the dialog.
3787 * However, that does leave a "gap" between creating and locking.
3788 */
3789 pjsip_dialog *dlg;
3790
3791 dlg = create_dialog_uas(endpoint, rdata, status, pjsip_dlg_create_uas);
3792 if (dlg) {
3793 pjsip_dlg_inc_lock(dlg);
3794 }
37343795
37353796 return dlg;
3797 #endif
37363798 }
37373799
37383800 int ast_sip_create_rdata_with_contact(pjsip_rx_data *rdata, char *packet, const char *src_name, int src_port,
40274089 return pj_stristr(&method, message_method) ? PJ_TRUE : PJ_FALSE;
40284090 }
40294091
4030 /*! Maximum number of challenges before assuming that we are in a loop */
4031 #define MAX_RX_CHALLENGES 10
40324092 #define TIMER_INACTIVE 0
40334093 #define TIMEOUT_TIMER2 5
40344094
474474
475475 if (ast_add_extension2_nolock(context, 0, exten, priority, NULL, NULL,
476476 app, data, free_ptr, BASE_REGISTRAR, NULL, 0)) {
477 ast_free(data);
478477 return -1;
479478 }
480479
3535 #include "asterisk/strings.h"
3636
3737 static const pj_str_t diversion_name = { "Diversion", 9 };
38 static const pj_str_t history_info_name = { "History-Info", 12 };
39 static pj_str_t HISTINFO_SUPPORTED_NAME = { "histinfo", 8 };
3840
3941 /*!
4042 * \internal
7981 static const struct reasons {
8082 enum AST_REDIRECTING_REASON code;
8183 const char *text;
84 const unsigned int cause;
8285 } reason_table[] = {
83 { AST_REDIRECTING_REASON_UNKNOWN, "unknown" },
84 { AST_REDIRECTING_REASON_USER_BUSY, "user-busy" },
85 { AST_REDIRECTING_REASON_NO_ANSWER, "no-answer" },
86 { AST_REDIRECTING_REASON_UNAVAILABLE, "unavailable" },
87 { AST_REDIRECTING_REASON_UNCONDITIONAL, "unconditional" },
88 { AST_REDIRECTING_REASON_TIME_OF_DAY, "time-of-day" },
89 { AST_REDIRECTING_REASON_DO_NOT_DISTURB, "do-not-disturb" },
90 { AST_REDIRECTING_REASON_DEFLECTION, "deflection" },
91 { AST_REDIRECTING_REASON_FOLLOW_ME, "follow-me" },
92 { AST_REDIRECTING_REASON_OUT_OF_ORDER, "out-of-service" },
93 { AST_REDIRECTING_REASON_AWAY, "away" },
94 { AST_REDIRECTING_REASON_CALL_FWD_DTE, "cf_dte" }, /* Non-standard */
95 { AST_REDIRECTING_REASON_SEND_TO_VM, "send_to_vm" }, /* Non-standard */
86 { AST_REDIRECTING_REASON_UNKNOWN, "unknown", 404 },
87 { AST_REDIRECTING_REASON_USER_BUSY, "user-busy", 486 },
88 { AST_REDIRECTING_REASON_NO_ANSWER, "no-answer", 408 },
89 { AST_REDIRECTING_REASON_UNAVAILABLE, "unavailable", 503 },
90 { AST_REDIRECTING_REASON_UNCONDITIONAL, "unconditional", 302 },
91 { AST_REDIRECTING_REASON_TIME_OF_DAY, "time-of-day", 404 },
92 { AST_REDIRECTING_REASON_DO_NOT_DISTURB, "do-not-disturb", 404 },
93 { AST_REDIRECTING_REASON_DEFLECTION, "deflection", 480 },
94 { AST_REDIRECTING_REASON_FOLLOW_ME, "follow-me", 404 },
95 { AST_REDIRECTING_REASON_OUT_OF_ORDER, "out-of-service", 404 },
96 { AST_REDIRECTING_REASON_AWAY, "away", 404 },
97 { AST_REDIRECTING_REASON_CALL_FWD_DTE, "cf_dte", 404 }, /* Non-standard */
98 { AST_REDIRECTING_REASON_SEND_TO_VM, "send_to_vm", 404 }, /* Non-standard */
9699 };
100
101 static enum AST_REDIRECTING_REASON cause_to_reason(const unsigned long cause) {
102 switch(cause) {
103 case 302:
104 return AST_REDIRECTING_REASON_UNCONDITIONAL;
105 case 486:
106 return AST_REDIRECTING_REASON_USER_BUSY;
107 case 408:
108 return AST_REDIRECTING_REASON_NO_ANSWER;
109 case 480:
110 case 487:
111 return AST_REDIRECTING_REASON_DEFLECTION;
112 case 503:
113 return AST_REDIRECTING_REASON_UNAVAILABLE;
114 default:
115 return AST_REDIRECTING_REASON_UNKNOWN;
116 }
117 }
118
119 static int add_supported(pjsip_tx_data *tdata)
120 {
121 pjsip_supported_hdr *hdr;
122
123 hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
124 if (!hdr) {
125 /* insert a new Supported header */
126 hdr = pjsip_supported_hdr_create(tdata->pool);
127 if (!hdr) {
128 return -1;
129 }
130
131 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
132 }
133
134 /* add on to the existing Supported header */
135 pj_strassign(&hdr->values[hdr->count++], &HISTINFO_SUPPORTED_NAME);
136
137 return 0;
138 }
97139
98140 static const char *reason_code_to_str(const struct ast_party_redirecting_reason *reason)
99141 {
115157 return "unknown";
116158 }
117159
160 static const unsigned int reason_code_to_cause(const struct ast_party_redirecting_reason *reason)
161 {
162 int idx;
163 int code;
164
165 code = reason->code;
166 for (idx = 0; idx < ARRAY_LEN(reason_table); ++idx) {
167 if (code == reason_table[idx].code) {
168 return reason_table[idx].cause;
169 }
170 }
171
172 return 404;
173 }
174
118175 static pjsip_fromto_hdr *get_diversion_header(pjsip_rx_data *rdata)
119176 {
120177 static const pj_str_t from_name = { "From", 4 };
132189 /* parse as a fromto header */
133190 return pjsip_parse_hdr(rdata->tp_info.pool, &from_name, value.ptr,
134191 pj_strlen(&value), &size);
192 }
193
194 /* Asterisk keeps track of 2 things. The redirected from address and
195 * the redirected to address. If first=0 method will get the most recent
196 * redirection target for use as the redirected to address. If first=1
197 * then this method will get the original redirection target (index=1)
198 * for use as the redirected from address.
199 */
200 static pjsip_fromto_hdr *get_history_info_header(pjsip_rx_data *rdata, const unsigned int first)
201 {
202 static const pj_str_t from_name = { "From", 4 };
203 pjsip_fromto_hdr * result_hdr = NULL;
204
205 pjsip_generic_string_hdr *hdr = NULL;
206
207 hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &history_info_name, NULL);
208
209 if (!hdr) {
210 return NULL;
211 }
212
213 do {
214 static const pj_str_t index_name = { "index", 5 };
215 pj_str_t value;
216 int size;
217 pjsip_fromto_hdr * fromto_hdr = NULL;
218 pjsip_param * index = NULL;
219
220 pj_strdup_with_null(rdata->tp_info.pool, &value, &hdr->hvalue);
221
222 /* parse as a fromto header */
223 fromto_hdr = pjsip_parse_hdr(rdata->tp_info.pool, &from_name, value.ptr,
224 pj_strlen(&value), &size);
225
226 if (fromto_hdr == NULL) {
227 continue;
228 }
229
230 index = pjsip_param_find(&fromto_hdr->other_param, &index_name);
231
232 if (index) {
233 if (!pj_strcmp2(&index->value, "1")) {
234 if (!first) {
235 continue;
236 } else {
237 return fromto_hdr;
238 }
239 }
240 }
241
242 result_hdr = fromto_hdr;
243
244 } while ((hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &history_info_name, hdr->next)));
245
246 return result_hdr;
135247 }
136248
137249 static void set_redirecting_value(char **dst, const pj_str_t *src)
196308 }
197309 }
198310
199 static void set_redirecting_reason(pjsip_fromto_hdr *hdr,
311 static void set_redirecting_reason_by_cause(pjsip_name_addr *name_addr,
200312 struct ast_party_redirecting_reason *data)
201313 {
314 static const pj_str_t cause_name = { "cause", 5 };
315 pjsip_sip_uri *uri = pjsip_uri_get_uri(name_addr);
316 pjsip_param *cause = pjsip_param_find(&uri->other_param, &cause_name);
317 unsigned long cause_value;
318
319 if (!cause) {
320 return;
321 }
322
323 cause_value = pj_strtoul(&cause->value);
324
325 data->code = cause_to_reason(cause_value);
326 ast_free(data->str);
327 data->str = ast_strdup("");
328 }
329
330 static void set_redirecting_reason(pjsip_fromto_hdr *from_info, pjsip_name_addr *to_info,
331 struct ast_party_redirecting_reason *data)
332 {
202333 static const pj_str_t reason_name = { "reason", 6 };
203 pjsip_param *reason = pjsip_param_find(&hdr->other_param, &reason_name);
334 pjsip_param *reason = pjsip_param_find(&from_info->other_param, &reason_name);
204335 char *reason_str;
205336
206337 if (!reason) {
338 if (to_info) {
339 set_redirecting_reason_by_cause(to_info, data);
340 }
207341 return;
208342 }
209343
245379 if (from_info) {
246380 set_redirecting_id((pjsip_name_addr*)from_info->uri,
247381 &data.from, &update.from);
248 set_redirecting_reason(from_info, &data.reason);
382 set_redirecting_reason(from_info, to_info, &data.reason);
383 ast_set_party_id_all(&update.priv_to);
249384 } else {
250385 copy_redirecting_id(&data.from, &session->id, &update.from);
251386 }
252387
253 set_redirecting_id(to_info, &data.to, &update.to);
388 if (to_info) {
389 set_redirecting_id(to_info, &data.to, &update.to);
390 }
254391
255392 ast_set_party_id_all(&update.priv_orig);
256393 ast_set_party_id_all(&update.priv_from);
272409 if (hdr) {
273410 set_redirecting(session, hdr, (pjsip_name_addr*)
274411 PJSIP_MSG_TO_HDR(rdata->msg_info.msg)->uri);
412 } else {
413 pjsip_fromto_hdr *history_info_to;
414 pjsip_fromto_hdr *history_info_from;
415 history_info_to = get_history_info_header(rdata, 0);
416
417 if (history_info_to) {
418 /* If History-Info is present, then it will also include the original
419 redirected-from in addition to the redirected-to */
420 history_info_from = get_history_info_header(rdata, 1);
421 set_redirecting(session, history_info_from, (pjsip_name_addr*)history_info_to->uri);
422 }
275423 }
276424
277425 return 0;
284432
285433 pjsip_status_line status = rdata->msg_info.msg->line.status;
286434 pjsip_fromto_hdr *div_hdr;
435 pjsip_fromto_hdr *history_info_to;
436 pjsip_fromto_hdr *history_info_from;
287437 pjsip_contact_hdr *contact_hdr;
288438
289439 if ((status.code != 302) && (status.code != 181)) {
291441 }
292442
293443 /* use the diversion header info if there is one. if not one then use the
294 session caller id info. if that doesn't exist use info from the To hdr*/
295 if (!(div_hdr = get_diversion_header(rdata)) && !session->id.number.valid) {
296 div_hdr = PJSIP_MSG_TO_HDR(rdata->msg_info.msg);
297 }
298
299 contact_hdr = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg, &contact_name, &contact_name_s, NULL);
300
301 set_redirecting(session, div_hdr, contact_hdr ? (pjsip_name_addr*)contact_hdr->uri :
302 (pjsip_name_addr*)PJSIP_MSG_FROM_HDR(rdata->msg_info.msg)->uri);
444 the history-info, if that doesn't exist, use session caller id info. if
445 that doesn't exist use info from the To hdr*/
446 if (!(div_hdr = get_diversion_header(rdata))) {
447 history_info_to = get_history_info_header(rdata, 0);
448
449 if (history_info_to) {
450 /* If History-Info is present, then it will also include the original
451 redirected-from in addition to the redirected-to */
452 history_info_from = get_history_info_header(rdata, 1);
453 set_redirecting(session, history_info_from, (pjsip_name_addr*)history_info_to->uri);
454 return;
455 }
456 if (!div_hdr && !session->id.number.valid) {
457 div_hdr = PJSIP_MSG_TO_HDR(rdata->msg_info.msg);
458 }
459 }
460
461
462 if (status.code == 302) {
463 /* With 302, Contact indicates the final destination and possibly Diversion indicates the hop before */
464 contact_hdr = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg, &contact_name, &contact_name_s, NULL);
465
466 set_redirecting(session, div_hdr, contact_hdr ? (pjsip_name_addr*)contact_hdr->uri :
467 (pjsip_name_addr*)PJSIP_MSG_FROM_HDR(rdata->msg_info.msg)->uri);
468 } else {
469 /* With 181, Diversion is non-standard, but if present indicates the new final destination, and To indicating the original */
470 set_redirecting(session, PJSIP_MSG_TO_HDR(rdata->msg_info.msg),
471 div_hdr ? (pjsip_name_addr*)div_hdr->uri : NULL);
472 }
303473 }
304474
305475 /*!
311481 */
312482 static void add_diversion_header(pjsip_tx_data *tdata, struct ast_party_redirecting *data)
313483 {
484 static const pj_str_t reason_name = { "reason", 6 };
485
314486 pjsip_fromto_hdr *hdr;
315487 pjsip_name_addr *name_addr;
316488 pjsip_sip_uri *uri;
319491 const char *reason_str;
320492 const char *quote_str;
321493 char *reason_buf;
322
323 struct ast_party_id *id = &data->from;
324 pjsip_uri *base = PJSIP_MSG_FROM_HDR(tdata->msg)->uri;
494 pjsip_uri *base;
495
496 struct ast_party_id *id = NULL;
497 if (tdata->msg->type == PJSIP_REQUEST_MSG) {
498 id = &data->from;
499 } else {
500 /* In responses indicate the new destination */
501 id = &data->to;
502 }
503
504 base = PJSIP_MSG_FROM_HDR(tdata->msg)->uri;
325505
326506 if (!id->number.valid || ast_strlen_zero(id->number.str)) {
327507 return;
338518 pj_strdup2(tdata->pool, &uri->user, id->number.str);
339519
340520 param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
341 param->name = pj_str("reason");
521 param->name = reason_name;
342522
343523 reason_str = reason_code_to_str(&data->reason);
344524
360540 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
361541 }
362542
543 /*!
544 * \internal
545 * \brief Adds history-info header information to an outbound SIP message
546 *
547 * \param tdata The outbound message
548 * \param data The redirecting data used to fill parts of the history-info header
549 */
550 static void add_history_info_header(pjsip_tx_data *tdata, struct ast_party_redirecting *data)
551 {
552 static const pj_str_t index_name = { "index", 5 };
553 static const pj_str_t cause_name = { "cause", 5 };
554 static const pj_str_t first_index = { "1", 1 };
555 static const pj_str_t last_index = { "1.1", 3 };
556
557 pjsip_fromto_hdr *hdr;
558 pjsip_name_addr *name_addr;
559 pjsip_sip_uri *uri;
560 pjsip_param *param;
561 pjsip_fromto_hdr *old_hdr;
562 unsigned int cause;
563 char *cause_buf;
564
565 struct ast_party_id *to = &data->to;
566 struct ast_party_id *from = &data->from;
567
568 pjsip_uri *base = PJSIP_MSG_TO_HDR(tdata->msg)->uri;
569
570
571 hdr = pjsip_from_hdr_create(tdata->pool);
572 hdr->type = PJSIP_H_OTHER;
573 hdr->sname = hdr->name = history_info_name;
574
575 name_addr = pjsip_uri_clone(tdata->pool, base);
576 uri = pjsip_uri_get_uri(name_addr->uri);
577
578 /* if no redirecting information, then TO is the original destination */
579 if (from->number.valid && !ast_strlen_zero(from->number.str)) {
580 pj_strdup2(tdata->pool, &name_addr->display, from->name.str);
581 pj_strdup2(tdata->pool, &uri->user, from->number.str);
582 }
583
584 param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
585 param->name = index_name;
586 param->value = first_index;
587
588
589 pj_list_insert_before(&hdr->other_param, param);
590 hdr->uri = (pjsip_uri *) name_addr;
591
592 while ((old_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &history_info_name, NULL)) != NULL) {
593 pj_list_erase(old_hdr);
594 }
595
596 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
597
598 if (!to->number.valid || ast_strlen_zero(to->number.str)) {
599 return;
600 }
601
602 hdr = pjsip_from_hdr_create(tdata->pool);
603 hdr->type = PJSIP_H_OTHER;
604 hdr->sname = hdr->name = history_info_name;
605
606 name_addr = pjsip_uri_clone(tdata->pool, base);
607 uri = pjsip_uri_get_uri(name_addr->uri);
608
609 pj_strdup2(tdata->pool, &name_addr->display, to->name.str);
610 pj_strdup2(tdata->pool, &uri->user, to->number.str);
611
612 param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
613 param->name = index_name;
614 param->value = last_index;
615 pj_list_insert_before(&hdr->other_param, param);
616
617 param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
618 param->name = cause_name;
619 cause = reason_code_to_cause(&data->reason);
620 cause_buf = pj_pool_alloc(tdata->pool, 4);
621 snprintf(cause_buf, 4, "%ud", cause);
622 param->value = pj_str(cause_buf);
623 pj_list_insert_before(&uri->other_param, param);
624 hdr->uri = (pjsip_uri *) name_addr;
625
626 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
627 }
628
363629 static void get_redirecting_add_diversion(struct ast_sip_session *session, pjsip_tx_data *tdata)
364630 {
365631 struct ast_party_redirecting *data;
632
633 add_supported(tdata);
366634
367635 if (session->channel && session->endpoint->id.send_diversion &&
368636 (data = ast_channel_redirecting(session->channel))->count) {
369637 add_diversion_header(tdata, data);
638 }
639 if (session->channel && session->endpoint->id.send_history_info) {
640 data = ast_channel_redirecting(session->channel);
641 add_history_info_header(tdata, data);
370642 }
371643 }
372644
409681 .incoming_response = diversion_incoming_response,
410682 .outgoing_request = diversion_outgoing_request,
411683 .outgoing_response = diversion_outgoing_response,
412 .response_priority = AST_SIP_SESSION_BEFORE_REDIRECTING|AST_SIP_SESSION_BEFORE_MEDIA,
684 .response_priority = AST_SIP_SESSION_BEFORE_MEDIA,
413685 };
414686
415687 static int load_module(void)
342342 */
343343 pjsip_tx_data *last_tdata;
344344 /*! \brief Timer entry for retrying on temporal responses */
345 pj_timer_entry timer;
345 struct ast_sip_sched_task *sched_task;
346346 /*! \brief Optional line parameter placed into Contact */
347347 char line[LINE_PARAMETER_SIZE];
348348 /*! \brief Current number of retries */
373373 char *transport_name;
374374 /*! \brief The name of the registration sorcery object */
375375 char *registration_name;
376 /*! \brief Server URI */
377 char *server_uri;
378 /*! \brief Client URI */
379 char *client_uri;
380 /*! \brief Contact URI */
381 char *contact_uri;
376382 };
377383
378384 /*! \brief Outbound registration state information (persists for lifetime that registration should exist) */
511517 return NULL;
512518 }
513519
514 ast_debug(3, "Determined relationship to outbound registration '%s' based on line '%s', using configured endpoint '%s'\n",
515 ast_sorcery_object_get_id(state->registration), state->client_state->line, state->registration->endpoint);
520 ast_debug(3, "%s: Line '%s', using configured endpoint '%s'\n",
521 state->client_state->registration_name, state->client_state->line, state->registration->endpoint);
516522
517523 return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", state->registration->endpoint);
518524 }
524530 /*! \brief Helper function which cancels the timer on a client */
525531 static void cancel_registration(struct sip_outbound_registration_client_state *client_state)
526532 {
527 if (pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()),
528 &client_state->timer, client_state->timer.id)) {
529 /* The timer was successfully cancelled, drop the refcount of client_state */
530 ao2_ref(client_state, -1);
533 if (client_state->sched_task) {
534 ast_sip_sched_task_cancel(client_state->sched_task);
535 ao2_cleanup(client_state->sched_task);
536 client_state->sched_task = NULL;
531537 }
532538 }
533539
544550 callback_invoked = ast_threadstorage_get(&register_callback_invoked, sizeof(int));
545551 if (!callback_invoked) {
546552 pjsip_tx_data_dec_ref(tdata);
553 ast_log(LOG_ERROR, "%s: Failed to get threadstorage for registration to server '%s' from client '%s'\n",
554 client_state->registration_name, client_state->server_uri, client_state->client_uri);
547555 return PJ_ENOMEM;
548556 }
549557 *callback_invoked = 0;
571579 * drop the references we just added
572580 */
573581 if ((status != PJ_SUCCESS) && !(*callback_invoked)) {
582 ast_log(LOG_ERROR, "%s: Failed send registration to server '%s' from client '%s'\n",
583 client_state->registration_name, client_state->server_uri, client_state->client_uri);
574584 pjsip_tx_data_dec_ref(tdata);
575585 ao2_ref(client_state, -1);
576586 return status;
592602 /*! \brief Callback function for registering */
593603 static int handle_client_registration(void *data)
594604 {
595 RAII_VAR(struct sip_outbound_registration_client_state *, client_state, data, ao2_cleanup);
605 struct sip_outbound_registration_client_state *client_state = data;
596606 pjsip_tx_data *tdata;
597607
598 if (client_state->status == SIP_REGISTRATION_STOPPED
599 || pjsip_regc_register(client_state->client, PJ_FALSE, &tdata) != PJ_SUCCESS) {
608 if (client_state->status == SIP_REGISTRATION_STOPPED) {
600609 return 0;
601610 }
602611
603 if (DEBUG_ATLEAST(1)) {
604 pjsip_regc_info info;
605
606 pjsip_regc_get_info(client_state->client, &info);
607 ast_log(LOG_DEBUG, "Outbound REGISTER attempt %u to '%.*s' with client '%.*s'\n",
608 client_state->retries + 1,
609 (int) info.server_uri.slen, info.server_uri.ptr,
610 (int) info.client_uri.slen, info.client_uri.ptr);
611 }
612 if (pjsip_regc_register(client_state->client, PJ_FALSE, &tdata) != PJ_SUCCESS) {
613 ast_log(LOG_ERROR, "%s: Failed to create registration to server '%s' from client '%s'\n",
614 client_state->registration_name, client_state->server_uri, client_state->client_uri);
615 return 0;
616 }
617
618 ast_debug(1, "%s: Outbound REGISTER attempt %u to '%s' with client '%s'\n",
619 client_state->registration_name,
620 client_state->retries + 1,
621 client_state->server_uri, client_state->client_uri);
612622
613623 if (client_state->support_path) {
614624 pjsip_supported_hdr *hdr;
619629 hdr = pjsip_supported_hdr_create(tdata->pool);
620630 if (!hdr) {
621631 pjsip_tx_data_dec_ref(tdata);
622 return -1;
632 ast_log(LOG_ERROR, "%s: Failed to add SUPPORTED header to registration to server '%s' from client '%s'\n",
633 client_state->registration_name, client_state->server_uri, client_state->client_uri);
634 return 0;
623635 }
624636
625637 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
634646 return 0;
635647 }
636648
637 /*! \brief Timer callback function, used just for registrations */
638 static void sip_outbound_registration_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
639 {
640 struct sip_outbound_registration_client_state *client_state = entry->user_data;
641
642 entry->id = 0;
643
644 /*
645 * Transfer client_state reference to serializer task so the
646 * nominal path will not dec the client_state ref in this
647 * pjproject callback thread.
648 */
649 if (ast_sip_push_task(client_state->serializer, handle_client_registration, client_state)) {
650 ast_log(LOG_WARNING, "Scheduled outbound registration could not be executed.\n");
651 ao2_ref(client_state, -1);
652 }
653 }
654
655649 /*! \brief Helper function which sets up the timer to re-register in a specific amount of time */
656 static void schedule_registration(struct sip_outbound_registration_client_state *client_state, unsigned int seconds)
657 {
658 pj_time_val delay = { .sec = seconds, };
659 pjsip_regc_info info;
650 static void schedule_registration(struct sip_outbound_registration_client_state *client_state, unsigned int ms)
651 {
652
653 ast_debug(1, "%s: Scheduling outbound registration to server '%s' from client '%s' in %d ms\n",
654 client_state->registration_name, client_state->server_uri, client_state->client_uri, ms);
660655
661656 cancel_registration(client_state);
662657
663 pjsip_regc_get_info(client_state->client, &info);
664 ast_debug(1, "Scheduling outbound registration to server '%.*s' from client '%.*s' in %d seconds\n",
665 (int) info.server_uri.slen, info.server_uri.ptr,
666 (int) info.client_uri.slen, info.client_uri.ptr,
667 seconds);
668
669 ao2_ref(client_state, +1);
670 if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &client_state->timer, &delay) != PJ_SUCCESS) {
671 ast_log(LOG_WARNING, "Failed to schedule registration to server '%.*s' from client '%.*s'\n",
672 (int) info.server_uri.slen, info.server_uri.ptr,
673 (int) info.client_uri.slen, info.client_uri.ptr);
674 ao2_ref(client_state, -1);
658 client_state->sched_task = ast_sip_schedule_task(client_state->serializer,
659 ms, handle_client_registration, ast_taskprocessor_name(client_state->serializer),
660 client_state,
661 AST_SIP_SCHED_TASK_ONESHOT | AST_SIP_SCHED_TASK_DATA_AO2);
662
663 if (!client_state->sched_task) {
664 ast_log(LOG_WARNING, "%s: Failed to schedule registration to server '%s' from client '%s'\n",
665 client_state->registration_name, client_state->server_uri, client_state->client_uri);
675666 }
676667 }
677668
708699 {
709700 struct sip_outbound_registration_client_state *client_state = data;
710701
711 cancel_registration(client_state);
712
713702 if (client_state->client) {
714703 pjsip_regc_info info;
715704 pjsip_tx_data *tdata;
716705
706 /* We need to get the live state to test "is_busy" */
717707 pjsip_regc_get_info(client_state->client, &info);
718708
719709 if (info.is_busy == PJ_TRUE) {
720710 /* If a client transaction is in progress we defer until it is complete */
721711 ast_debug(1,
722 "Registration transaction is busy with server '%.*s' from client '%.*s'.\n",
712 "%s: Registration transaction is busy with server '%.*s' from client '%.*s'.\n",
713 client_state->registration_name,
723714 (int) info.server_uri.slen, info.server_uri.ptr,
724715 (int) info.client_uri.slen, info.client_uri.ptr);
725716 client_state->destroy = 1;
732723 break;
733724 case SIP_REGISTRATION_REGISTERED:
734725 ast_debug(1,
735 "Trying to unregister with server '%.*s' from client '%.*s' before destruction.\n",
726 "%s: Trying to unregister with server '%.*s' from client '%.*s' before destruction.\n",
727 client_state->registration_name,
736728 (int) info.server_uri.slen, info.server_uri.ptr,
737729 (int) info.client_uri.slen, info.client_uri.ptr);
738
730 cancel_registration(client_state);
739731 update_client_state_status(client_state, SIP_REGISTRATION_STOPPING);
740732 client_state->destroy = 1;
741733 if (pjsip_regc_unregister(client_state->client, &tdata) == PJ_SUCCESS
745737 }
746738 break;
747739 case SIP_REGISTRATION_REJECTED_TEMPORARY:
740 case SIP_REGISTRATION_STOPPING:
741 cancel_registration(client_state);
742 break;
748743 case SIP_REGISTRATION_REJECTED_PERMANENT:
749 case SIP_REGISTRATION_STOPPING:
750744 case SIP_REGISTRATION_STOPPED:
751745 break;
752746 }
757751
758752 update_client_state_status(client_state, SIP_REGISTRATION_STOPPED);
759753 ast_sip_auth_vector_destroy(&client_state->outbound_auths);
754
760755 ao2_ref(client_state, -1);
761756
762757 return 0;
814809 }
815810 }
816811
817 static void schedule_retry(struct registration_response *response, unsigned int interval,
818 const char *server_uri, const char *client_uri)
812 static void schedule_retry(struct registration_response *response, unsigned int interval)
819813 {
820814 update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_TEMPORARY);
821 schedule_registration(response->client_state, interval);
815 schedule_registration(response->client_state, interval * 1000);
822816
823817 if (response->rdata) {
824 ast_log(LOG_WARNING, "Temporal response '%d' received from '%s' on "
818 ast_log(LOG_WARNING, "%s: Temporal response '%d' received from '%s' on "
825819 "registration attempt to '%s', retrying in '%u'\n",
826 response->code, server_uri, client_uri, interval);
820 response->client_state->registration_name,
821 response->code, response->client_state->server_uri, response->client_state->client_uri, interval);
827822 } else {
828 ast_log(LOG_WARNING, "No response received from '%s' on "
823 ast_log(LOG_WARNING, "%s: No response received from '%s' on "
829824 "registration attempt to '%s', retrying in '%u'\n",
830 server_uri, client_uri, interval);
825 response->client_state->registration_name,
826 response->client_state->server_uri, response->client_state->client_uri, interval);
831827 }
832828 }
833829
840836 return 0;
841837 }
842838
843 if (DEBUG_ATLEAST(1)) {
844 pjsip_regc_info info;
845
846 pjsip_regc_get_info(state->client_state->client, &info);
847 ast_log(LOG_DEBUG,
848 "Outbound registration transport to server '%.*s' from client '%.*s' shutdown\n",
849 (int) info.server_uri.slen, info.server_uri.ptr,
850 (int) info.client_uri.slen, info.client_uri.ptr);
851 }
839 ast_debug(1,
840 "%s: Outbound registration transport to server '%s' from client '%s' shutdown\n",
841 state->client_state->registration_name, state->client_state->server_uri, state->client_state->client_uri);
852842
853843 cancel_registration(state->client_state);
854844
921911 static int handle_registration_response(void *data)
922912 {
923913 struct registration_response *response = data;
924 pjsip_regc_info info;
925 char server_uri[PJSIP_MAX_URL_SIZE];
926 char client_uri[PJSIP_MAX_URL_SIZE];
927914
928915 if (response->client_state->status == SIP_REGISTRATION_STOPPED) {
929916 ao2_ref(response, -1);
930917 return 0;
931918 }
932919
933 pjsip_regc_get_info(response->client_state->client, &info);
934 ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri));
935 ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri));
936
937 ast_debug(1, "Processing REGISTER response %d from server '%s' for client '%s'\n",
938 response->code, server_uri, client_uri);
920 ast_debug(1, "%s: Processing REGISTER response %d from server '%s' for client '%s' with expiration '%d'\n",
921 response->client_state->registration_name, response->code, response->client_state->server_uri,
922 response->client_state->client_uri, response->expiration);
939923
940924 if (response->code == 408 || response->code == 503) {
941925 if ((ast_sip_failover_request(response->old_request))) {
957941 if (!ast_sip_create_request_with_auth(&response->client_state->outbound_auths,
958942 response->rdata, response->old_request, &tdata)) {
959943 response->client_state->auth_attempted = 1;
960 ast_debug(1, "Sending authenticated REGISTER to server '%s' from client '%s'\n",
961 server_uri, client_uri);
944 ast_debug(1, "%s: Sending authenticated REGISTER to server '%s' from client '%s'\n",
945 response->client_state->registration_name, response->client_state->server_uri,
946 response->client_state->client_uri);
962947 pjsip_tx_data_add_ref(tdata);
963948 res = registration_client_send(response->client_state, tdata);
964949
972957 return 0;
973958 }
974959 } else {
975 ast_log(LOG_WARNING, "Failed to create authenticated REGISTER request to server '%s' from client '%s'\n",
976 server_uri, client_uri);
960 ast_log(LOG_WARNING, "%s: Failed to create authenticated REGISTER request to server '%s' from client '%s'\n",
961 response->client_state->registration_name, response->client_state->server_uri,
962 response->client_state->client_uri);
977963 }
978964 /* Otherwise, fall through so the failure is processed appropriately */
979965 }
986972 int next_registration_round;
987973
988974 /* If the registration went fine simply reschedule registration for the future */
989 ast_debug(1, "Outbound registration to '%s' with client '%s' successful\n", server_uri, client_uri);
975 ast_debug(1, "%s: Outbound registration to '%s' with client '%s' successful\n",
976 response->client_state->registration_name, response->client_state->server_uri,
977 response->client_state->client_uri);
990978 update_client_state_status(response->client_state, SIP_REGISTRATION_REGISTERED);
991979 response->client_state->retries = 0;
992 next_registration_round = response->expiration - REREGISTER_BUFFER_TIME;
980 next_registration_round = (response->expiration - REREGISTER_BUFFER_TIME) * 1000;
993981 if (next_registration_round < 0) {
994 /* Re-register immediately. */
995 next_registration_round = 0;
982 /* Re-register no sooner than the buffer time. */
983 next_registration_round = REREGISTER_BUFFER_TIME * 1000;
996984 }
997985 schedule_registration(response->client_state, next_registration_round);
998986
1000988 registration_transport_monitor_setup(response->rdata->tp_info.transport,
1001989 response->client_state->registration_name);
1002990 } else {
1003 ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri);
991 ast_debug(1, "%s: Outbound unregistration to '%s' with client '%s' successful\n",
992 response->client_state->registration_name, response->client_state->server_uri,
993 response->client_state->client_uri);
1004994 update_client_state_status(response->client_state, SIP_REGISTRATION_UNREGISTERED);
1005995 ast_sip_transport_monitor_unregister(response->rdata->tp_info.transport,
1006996 registration_transport_shutdown_cb, response->client_state->registration_name,
10101000 /* We need to deal with the pending destruction instead. */
10111001 } else if (response->retry_after) {
10121002 /* If we have been instructed to retry after a period of time, schedule it as such */
1013 schedule_retry(response, response->retry_after, server_uri, client_uri);
1003 schedule_retry(response, response->retry_after);
10141004 } else if (response->client_state->retry_interval
10151005 && sip_outbound_registration_is_temporal(response->code, response->client_state)) {
10161006 if (response->client_state->retries == response->client_state->max_retries) {
10171007 /* If we received enough temporal responses to exceed our maximum give up permanently */
10181008 update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_PERMANENT);
1019 ast_log(LOG_WARNING, "Maximum retries reached when attempting outbound registration to '%s' with client '%s', stopping registration attempt\n",
1020 server_uri, client_uri);
1009 ast_log(LOG_WARNING, "%s: Maximum retries reached when attempting outbound registration to '%s' with client '%s', stopping registration attempt\n",
1010 response->client_state->registration_name, response->client_state->server_uri,
1011 response->client_state->client_uri);
10211012 } else {
10221013 /* On the other hand if we can still try some more do so */
10231014 response->client_state->retries++;
1024 schedule_retry(response, response->client_state->retry_interval, server_uri, client_uri);
1015 schedule_retry(response, response->client_state->retry_interval);
10251016 }
10261017 } else {
10271018 if (response->code == 403
10301021 /* A forbidden response retry interval is configured and there are retries remaining */
10311022 update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_TEMPORARY);
10321023 response->client_state->retries++;
1033 schedule_registration(response->client_state, response->client_state->forbidden_retry_interval);
1034 ast_log(LOG_WARNING, "403 Forbidden fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n",
1035 server_uri, client_uri, response->client_state->forbidden_retry_interval);
1024 schedule_registration(response->client_state, response->client_state->forbidden_retry_interval * 1000);
1025 ast_log(LOG_WARNING, "%s: 403 Forbidden fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n",
1026 response->client_state->registration_name, response->client_state->server_uri,
1027 response->client_state->client_uri, response->client_state->forbidden_retry_interval);
10361028 } else if (response->client_state->fatal_retry_interval
10371029 && response->client_state->retries < response->client_state->max_retries) {
10381030 /* Some kind of fatal failure response received, so retry according to configured interval */
10391031 update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_TEMPORARY);
10401032 response->client_state->retries++;
1041 schedule_registration(response->client_state, response->client_state->fatal_retry_interval);
1042 ast_log(LOG_WARNING, "'%d' fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n",
1043 response->code, server_uri, client_uri, response->client_state->fatal_retry_interval);
1033 schedule_registration(response->client_state, response->client_state->fatal_retry_interval * 1000);
1034 ast_log(LOG_WARNING, "%s: '%d' fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n",
1035 response->client_state->registration_name, response->code, response->client_state->server_uri,
1036 response->client_state->client_uri, response->client_state->fatal_retry_interval);
10441037 } else {
10451038 /* Finally if there's no hope of registering give up */
10461039 update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_PERMANENT);
10471040 if (response->rdata) {
1048 ast_log(LOG_WARNING, "Fatal response '%d' received from '%s' on registration attempt to '%s', stopping outbound registration\n",
1049 response->code, server_uri, client_uri);
1041 ast_log(LOG_WARNING, "%s: Fatal response '%d' received from '%s' on registration attempt to '%s', stopping outbound registration\n",
1042 response->client_state->registration_name, response->code, response->client_state->server_uri,
1043 response->client_state->client_uri);
10501044 } else {
1051 ast_log(LOG_WARNING, "Fatal registration attempt to '%s', stopping outbound registration\n", client_uri);
1045 ast_log(LOG_WARNING, "%s: Fatal registration attempt to '%s', stopping outbound registration\n",
1046 response->client_state->registration_name, response->client_state->client_uri);
10521047 }
10531048 }
10541049 }
10551050
1056 ast_system_publish_registry("PJSIP", client_uri, server_uri,
1051 ast_system_publish_registry("PJSIP", response->client_state->client_uri, response->client_state->server_uri,
10571052 sip_outbound_registration_status_str(response->client_state->status), NULL);
10581053
10591054 if (response->client_state->destroy) {
10941089 */
10951090 response->client_state = client_state;
10961091
1097 ast_debug(1, "Received REGISTER response %d(%.*s)\n",
1098 param->code, (int) param->reason.slen, param->reason.ptr);
1092 ast_debug(1, "%s: Received REGISTER response %d(%.*s) from '%s': Expires: %d\n",
1093 client_state->registration_name,
1094 param->code, (int) param->reason.slen, param->reason.ptr,
1095 client_state->server_uri, param->expiration);
10991096
11001097 if (param->rdata) {
11011098 struct pjsip_retry_after_hdr *retry_after;
11301127 * pjproject callback thread.
11311128 */
11321129 if (ast_sip_push_task(client_state->serializer, handle_registration_response, response)) {
1133 ast_log(LOG_WARNING, "Failed to pass incoming registration response to threadpool\n");
1130 ast_log(LOG_WARNING, "%s: Failed to pass incoming registration response to threadpool\n",
1131 client_state->registration_name);
11341132 ao2_cleanup(response);
11351133 }
11361134 }
11401138 {
11411139 struct sip_outbound_registration_state *state = obj;
11421140
1143 ast_debug(3, "Destroying registration state for registration to server '%s' from client '%s'\n",
1141 ast_debug(3, "%s: Destroying registration state for registration to server '%s' from client '%s'\n",
1142 state->client_state->registration_name,
11441143 state->registration ? state->registration->server_uri : "",
11451144 state->registration ? state->registration->client_uri : "");
11461145 ao2_cleanup(state->registration);
11511150 ao2_ref(state->client_state, -1);
11521151 } else if (ast_sip_push_task(state->client_state->serializer,
11531152 handle_client_state_destruction, state->client_state)) {
1154 ast_log(LOG_WARNING, "Failed to pass outbound registration client destruction to threadpool\n");
1153 ast_log(LOG_WARNING, "%s: Failed to pass outbound registration client destruction to threadpool\n",
1154 state->client_state->registration_name);
11551155 ao2_ref(state->client_state, -1);
11561156 }
11571157 }
11601160 static void sip_outbound_registration_client_state_destroy(void *obj)
11611161 {
11621162 struct sip_outbound_registration_client_state *client_state = obj;
1163
1164 ast_debug(3, "%s: Destroying registration client state\n",
1165 client_state->registration_name);
11631166
11641167 ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "-1", 1.0);
11651168 ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "-1", 1.0,
11681171 ast_taskprocessor_unreference(client_state->serializer);
11691172 ast_free(client_state->transport_name);
11701173 ast_free(client_state->registration_name);
1174 ast_free(client_state->server_uri);
1175 ast_free(client_state->client_uri);
1176 ast_free(client_state->contact_uri);
11711177 if (client_state->last_tdata) {
11721178 pjsip_tx_data_dec_ref(client_state->last_tdata);
11731179 }
11911197 }
11921198
11931199 state->client_state->status = SIP_REGISTRATION_UNREGISTERED;
1194 pj_timer_entry_init(&state->client_state->timer, 0, state->client_state,
1195 sip_outbound_registration_timer_cb);
11961200 state->client_state->transport_name = ast_strdup(registration->transport);
11971201 state->client_state->registration_name =
11981202 ast_strdup(ast_sorcery_object_get_id(registration));
14271431 }
14281432
14291433 pj_cstr(&server_uri, registration->server_uri);
1430
1434 state->client_state->server_uri = ast_strdup(registration->server_uri);
14311435
14321436 if (sip_dialog_create_contact(pjsip_regc_get_pool(state->client_state->client),
14331437 &contact_uri, S_OR(registration->contact_user, "s"), &server_uri, &selector,
14341438 state->client_state->line)) {
14351439 return -1;
14361440 }
1441 ast_copy_pj_str2(&state->client_state->contact_uri, &contact_uri);
14371442
14381443 pj_cstr(&client_uri, registration->client_uri);
1444 state->client_state->client_uri = ast_strdup(registration->client_uri);
1445
14391446 if (pjsip_regc_init(state->client_state->client, &server_uri, &client_uri,
14401447 &client_uri, 1, &contact_uri, registration->expiration) != PJ_SUCCESS) {
14411448 return -1;
14421449 }
14431450
1451
14441452 return 0;
14451453 }
14461454
14501458 struct sip_outbound_registration_state *state = data;
14511459 struct sip_outbound_registration *registration = ao2_bump(state->registration);
14521460 size_t i;
1461
1462 ast_debug(1, "%s: Performing register to server '%s' from client '%s' Expiration: %d\n",
1463 state->client_state->registration_name,
1464 state->registration->server_uri, state->registration->client_uri, registration->expiration);
14531465
14541466 /* Just in case the client state is being reused for this registration, free the auth information */
14551467 ast_sip_auth_vector_destroy(&state->client_state->outbound_auths);
14721484
14731485 pjsip_regc_update_expires(state->client_state->client, registration->expiration);
14741486
1475 schedule_registration(state->client_state, (ast_random() % 10) + 1);
1487 schedule_registration(state->client_state, ((ast_random() % 10) + 1) * 1000);
14761488
14771489 ao2_ref(registration, -1);
14781490 ao2_ref(state, -1);
16011613 struct sip_outbound_registration_state *state = obj;
16021614 struct pjsip_regc *client = state->client_state->client;
16031615 pjsip_tx_data *tdata;
1604 pjsip_regc_info info;
1605
1606 pjsip_regc_get_info(client, &info);
1607 ast_debug(1, "Unregistering contacts with server '%s' from client '%s'\n",
1616
1617 ast_debug(1, "%s: Unregistering contacts with server '%s' from client '%s'\n",
1618 state->client_state->registration_name,
16081619 state->registration->server_uri, state->registration->client_uri);
16091620
16101621 cancel_registration(state->client_state);
16311642 static int queue_register(struct sip_outbound_registration_state *state)
16321643 {
16331644 ao2_ref(state, +1);
1645
1646 ast_debug(1, "%s: Queueing register to server '%s' from client '%s'\n",
1647 state->client_state->registration_name,
1648 state->registration->server_uri, state->registration->client_uri);
1649
16341650 if (ast_sip_push_task(state->client_state->serializer, sip_outbound_registration_perform, state)) {
16351651 ao2_ref(state, -1);
16361652 return -1;
18841900 ast_sip_sorcery_object_to_ami(ami->registration, &buf);
18851901
18861902 if ((state = get_state(ast_sorcery_object_get_id(ami->registration)))) {
1887 pjsip_regc_info info;
1903 int next_reg = 0;
18881904
18891905 if (state->client_state->status == SIP_REGISTRATION_REGISTERED) {
18901906 ++ami->registered;
18951911 ast_str_append(&buf, 0, "Status: %s\r\n",
18961912 sip_outbound_registration_status_str(state->client_state->status));
18971913
1898 pjsip_regc_get_info(state->client_state->client, &info);
1899 ast_str_append(&buf, 0, "NextReg: %d\r\n", info.next_reg);
1914 if (state->client_state->status == SIP_REGISTRATION_REGISTERED && state->client_state->sched_task) {
1915 ast_sip_sched_task_get_times2(state->client_state->sched_task, NULL, NULL, NULL, NULL,
1916 &next_reg, NULL);
1917 }
1918
1919 ast_str_append(&buf, 0, "NextReg: %d\r\n", next_reg / 1000);
19001920 ao2_ref(state, -1);
19011921 }
19021922
20012021 ast_assert(context->output_buffer != NULL);
20022022
20032023 ast_str_append(&context->output_buffer, 0,
2004 " <Registration/ServerURI..............................> <Auth..........> <Status.......>\n");
2024 " <Registration/ServerURI..............................> <Auth..........> <Status.......>");
2025 ast_str_append(&context->output_buffer, 0,
2026 " <Last Reg..> <Intvl> <Next Start.....secs>\n"
2027 "==============================================");
20052028
20062029 return 0;
20072030 }
2031
2032 #define TIME_FORMAT "%a %T"
20082033
20092034 static int cli_print_body(void *obj, void *arg, int flags)
20102035 {
20122037 struct ast_sip_cli_context *context = arg;
20132038 const char *id = ast_sorcery_object_get_id(registration);
20142039 struct sip_outbound_registration_state *state = get_state(id);
2040 int next_run_ms = 0;
2041 struct timeval next = { 0, 0 };
2042 struct timeval last = { 0, 0 };
2043 struct ast_tm tm;
2044 char next_start[32] = "";
2045 char last_start[32] = "";
2046 int interval;
2047
20152048 #define REGISTRATION_URI_FIELD_LEN 53
20162049
20172050 ast_assert(context->output_buffer != NULL);
20182051
2019 ast_str_append(&context->output_buffer, 0, " %-s/%-*.*s %-16s %-16s\n",
2052 if (state->client_state->sched_task) {
2053 ast_sip_sched_task_get_times2(state->client_state->sched_task, &last, NULL, NULL, &interval,
2054 &next_run_ms, &next);
2055
2056 ast_localtime(&last, &tm, NULL);
2057 ast_strftime(last_start, sizeof(last_start), TIME_FORMAT, &tm);
2058
2059 ast_localtime(&next, &tm, NULL);
2060 ast_strftime(next_start, sizeof(next_start), TIME_FORMAT, &tm);
2061 }
2062
2063 ast_str_append(&context->output_buffer, 0, " %-s/%-*.*s %-16s %-16s",
20202064 id,
20212065 (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
20222066 (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)),
20242068 AST_VECTOR_SIZE(&registration->outbound_auths)
20252069 ? AST_VECTOR_GET(&registration->outbound_auths, 0)
20262070 : "n/a",
2027 (state ? sip_outbound_registration_status_str(state->client_state->status) : "Unregistered"));
2071 (state ? sip_outbound_registration_status_str(state->client_state->status) : "Unregistered")
2072 );
2073
2074 ast_str_append(&context->output_buffer, 0, " %-12s %7d %-12s %8d\n",
2075 last_start, interval / 1000, next_start, next_run_ms / 1000);
2076
20282077 ao2_cleanup(state);
2078
20292079
20302080 if (context->show_details
20312081 || (context->show_details_only_level_0 && context->indent_level == 0)) {
14761476 }
14771477 sub_tree->role = AST_SIP_NOTIFIER;
14781478
1479 dlg = ast_sip_create_dialog_uas(endpoint, rdata, dlg_status);
1479 dlg = ast_sip_create_dialog_uas_locked(endpoint, rdata, dlg_status);
14801480 if (!dlg) {
14811481 if (*dlg_status != PJ_EEXISTS) {
14821482 ast_log(LOG_WARNING, "Unable to create dialog for SIP subscription\n");
14971497 }
14981498
14991499 pjsip_evsub_create_uas(dlg, &pubsub_cb, rdata, 0, &sub_tree->evsub);
1500
15001501 subscription_setup_dialog(sub_tree, dlg);
1502
1503 /*
1504 * The evsub and subscription setup both add dialog refs, so the dialog ref that
1505 * was added when the dialog was created (see ast_sip_create_dialog_uas_lock) can
1506 * now be removed. The lock should no longer be needed so can be removed too.
1507 */
1508 pjsip_dlg_dec_lock(dlg);
15011509
15021510 #ifdef HAVE_PJSIP_EVSUB_GRP_LOCK
15031511 pjsip_evsub_add_ref(sub_tree->evsub);
5151 #include "asterisk/dsp.h"
5252 #include "asterisk/linkedlists.h" /* for AST_LIST_NEXT */
5353 #include "asterisk/stream.h"
54 #include "asterisk/logger_category.h"
5455 #include "asterisk/format_cache.h"
5556
5657 #include "asterisk/res_pjsip.h"
8081 keepalive = ast_rtp_instance_get_keepalive(rtp);
8182
8283 if (!ast_sockaddr_isnull(&session_media->direct_media_addr)) {
83 ast_debug(3, "Not sending RTP keepalive on RTP instance %p since direct media is in use\n", rtp);
84 ast_debug_rtp(3, "(%p) RTP not sending keepalive since direct media is in use\n", rtp);
8485 return keepalive * 1000;
8586 }
8687
8788 interval = time(NULL) - ast_rtp_instance_get_last_tx(rtp);
8889 send_keepalive = interval >= keepalive;
8990
90 ast_debug(3, "It has been %d seconds since RTP was last sent on instance %p. %sending keepalive\n",
91 (int) interval, rtp, send_keepalive ? "S" : "Not s");
91 ast_debug_rtp(3, "(%p) RTP it has been %d seconds since RTP was last sent. %sending keepalive\n",
92 rtp, (int) interval, send_keepalive ? "S" : "Not s");
9293
9394 if (send_keepalive) {
9495 ast_rtp_instance_sendcng(rtp, 0);
136137 * - disconnect channel unless direct media is in use.
137138 */
138139 if (!ast_sockaddr_isnull(&session_media->direct_media_addr)) {
139 ast_debug(3, "Not disconnecting channel '%s' for lack of %s RTP activity in %d seconds "
140 "since direct media is in use\n", ast_channel_name(chan),
140 ast_debug_rtp(3, "(%p) RTP not disconnecting channel '%s' for lack of %s RTP activity in %d seconds "
141 "since direct media is in use\n", rtp, ast_channel_name(chan),
141142 ast_codec_media_type2str(session_media->type), elapsed);
142143 ast_channel_unlock(chan);
143144 ast_channel_unref(chan);
231232
232233 if (session->endpoint->media.bind_rtp_to_media_address && !ast_strlen_zero(session->endpoint->media.address)) {
233234 if (ast_sockaddr_parse(&temp_media_address, session->endpoint->media.address, 0)) {
234 ast_debug(1, "Endpoint %s: Binding RTP media to %s\n",
235 ast_debug_rtp(1, "Endpoint %s: Binding RTP media to %s\n",
235236 ast_sorcery_object_get_id(session->endpoint),
236237 session->endpoint->media.address);
237238 media_address = &temp_media_address;
238239 } else {
239 ast_debug(1, "Endpoint %s: RTP media address invalid: %s\n",
240 ast_debug_rtp(1, "Endpoint %s: RTP media address invalid: %s\n",
240241 ast_sorcery_object_get_id(session->endpoint),
241242 session->endpoint->media.address);
242243 }
254255
255256 pj_sockaddr_print(&trans_state->host, hoststr, sizeof(hoststr), 0);
256257 if (ast_sockaddr_parse(&temp_media_address, hoststr, 0)) {
257 ast_debug(1, "Transport %s bound to %s: Using it for RTP media.\n",
258 ast_debug_rtp(1, "Transport %s bound to %s: Using it for RTP media.\n",
258259 session->endpoint->transport, hoststr);
259260 media_address = &temp_media_address;
260261 } else {
261 ast_debug(1, "Transport %s bound to %s: Invalid for RTP media.\n",
262 ast_debug_rtp(1, "Transport %s bound to %s: Invalid for RTP media.\n",
262263 session->endpoint->transport, hoststr);
263264 }
264265 ao2_ref(trans_state, -1);
375376 }
376377 if (!tel_event && (session->dtmf == AST_SIP_DTMF_AUTO)) {
377378 ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_INBAND);
379 ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_DTMF, 0);
378380 }
379381
380382 if (session->dtmf == AST_SIP_DTMF_AUTO_INFO) {
381383 if (tel_event) {
382384 ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_RFC2833);
385 ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_DTMF, 1);
383386 } else {
384387 ast_rtp_instance_dtmf_mode_set(session_media->rtp, AST_RTP_DTMF_MODE_NONE);
388 ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_DTMF, 0);
385389 }
386390 }
387391
713717 return;
714718 }
715719
720 ast_debug_ice(2, "(%p) ICE process attributes\n", session_media->rtp);
721
716722 attr = pjmedia_sdp_media_find_attr2(remote_stream, "ice-ufrag", NULL);
717723 if (!attr) {
718724 attr = pjmedia_sdp_attr_find2(remote->attr_count, remote->attr, "ice-ufrag", NULL);
721727 ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
722728 ice->set_authentication(session_media->rtp, attr_value, NULL);
723729 } else {
730 ast_debug_ice(2, "(%p) ICE no, or invalid ice-ufrag\n", session_media->rtp);
724731 return;
725732 }
726733
732739 ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value));
733740 ice->set_authentication(session_media->rtp, NULL, attr_value);
734741 } else {
742 ast_debug_ice(2, "(%p) ICE no, or invalid ice-pwd\n", session_media->rtp);
735743 return;
736744 }
737745
7474 ast_sip_session_sdp_creation_cb on_sdp_creation,
7575 ast_sip_session_response_cb on_response,
7676 enum ast_sip_session_refresh_method method, int generate_new_sdp,
77 struct ast_sip_session_media_state *media_state,
77 struct ast_sip_session_media_state *pending_media_state,
78 struct ast_sip_session_media_state *active_media_state,
7879 int queued);
7980
8081 /*! \brief NAT hook for modifying outgoing messages with SDP */
480481
481482 ast_free(session_media->mid);
482483 ast_free(session_media->remote_mslabel);
484 ast_free(session_media->remote_label);
485 ast_free(session_media->stream_name);
483486 }
484487
485488 struct ast_sip_session_media *ast_sip_session_media_state_add(struct ast_sip_session *session,
486489 struct ast_sip_session_media_state *media_state, enum ast_media_type type, int position)
487490 {
488491 struct ast_sip_session_media *session_media = NULL;
492 SCOPE_ENTER(1, "%s Adding position %d\n", ast_sip_session_get_name(session), position);
489493
490494 /* It is possible for this media state to already contain a session for the stream. If this
491495 * is the case we simply return it.
492496 */
493497 if (position < AST_VECTOR_SIZE(&media_state->sessions)) {
494 return AST_VECTOR_GET(&media_state->sessions, position);
498 session_media = AST_VECTOR_GET(&media_state->sessions, position);
499 if (session_media) {
500 SCOPE_EXIT_RTN_VALUE(session_media, "Using existing media_session\n");
501 }
495502 }
496503
497504 /* Determine if we can reuse the session media from the active media state if present */
500507 /* A stream can never exist without an accompanying media session */
501508 if (session_media->type == type) {
502509 ao2_ref(session_media, +1);
510 ast_trace(1, "Reusing existing media session\n");
503511 /*
504512 * If this session_media was previously removed, its bundle group was probably reset
505513 * to -1 so if bundling is enabled on the endpoint, we need to reset it to 0, set
511519 ast_free(session_media->mid);
512520 if (ast_asprintf(&session_media->mid, "%s-%d", ast_codec_media_type2str(type), position) < 0) {
513521 ao2_ref(session_media, -1);
514 return NULL;
522 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't alloc mid\n");
515523 }
516524 }
517525 } else {
526 ast_trace(1, "Can't reuse existing media session because the types are different. %s <> %s\n",
527 ast_codec_media_type2str(type), ast_codec_media_type2str(session_media->type));
518528 session_media = NULL;
519529 }
520530 }
525535 if (!session_media) {
526536 return NULL;
527537 }
538 ast_trace(1, "Creating new media session\n");
528539
529540 session_media->encryption = session->endpoint->media.rtp.encryption;
530541 session_media->remote_ice = session->endpoint->media.rtp.ice_support;
540551 */
541552 if (ast_asprintf(&session_media->mid, "%s-%d", ast_codec_media_type2str(type), position) < 0) {
542553 ao2_ref(session_media, -1);
543 return NULL;
554 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't alloc mid\n");
544555 }
545556 session_media->bundle_group = 0;
546557
554565 }
555566 }
556567
568 ast_free(session_media->stream_name);
569 session_media->stream_name = ast_strdup(ast_stream_get_name(ast_stream_topology_get_stream(media_state->topology, position)));
570
557571 if (AST_VECTOR_REPLACE(&media_state->sessions, position, session_media)) {
558572 ao2_ref(session_media, -1);
559573
560 return NULL;
574 SCOPE_EXIT_RTN_VALUE(NULL, "Couldn't replace media_session\n");
561575 }
562576
563577 /* If this stream will be active in some way and it is the first of this type then consider this the default media session to match */
564578 if (!media_state->default_session[type] && ast_stream_get_state(ast_stream_topology_get_stream(media_state->topology, position)) != AST_STREAM_STATE_REMOVED) {
579 ast_trace(1, "Setting media session as default for %s\n", ast_codec_media_type2str(session_media->type));
580
565581 media_state->default_session[type] = session_media;
566582 }
567583
568 return session_media;
584 SCOPE_EXIT_RTN_VALUE(session_media, "Done\n");
569585 }
570586
571587 static int is_stream_limitation_reached(enum ast_media_type type, const struct ast_sip_endpoint *endpoint, int *type_streams)
670686
671687 ast_free(session_media->remote_mslabel);
672688 session_media->remote_mslabel = NULL;
689 ast_free(session_media->remote_label);
690 session_media->remote_label = NULL;
673691
674692 for (index = 0; index < stream->attr_count; ++index) {
675693 pjmedia_sdp_attr *attr = stream->attr[index];
678696 char *msid, *tmp = attr_value;
679697 static const pj_str_t STR_msid = { "msid", 4 };
680698 static const pj_str_t STR_ssrc = { "ssrc", 4 };
681
682 if (!pj_strcmp(&attr->name, &STR_msid)) {
699 static const pj_str_t STR_label = { "label", 5 };
700
701 if (!pj_strcmp(&attr->name, &STR_label)) {
702 ast_copy_pj_str(attr_value, &attr->value, sizeof(attr_value));
703 session_media->remote_label = ast_strdup(attr_value);
704 } else if (!pj_strcmp(&attr->name, &STR_msid)) {
683705 ast_copy_pj_str(attr_value, &attr->value, sizeof(attr_value));
684706 msid = strsep(&tmp, " ");
685707 session_media->remote_mslabel = ast_strdup(msid);
739761 int i;
740762 int handled = 0;
741763 int type_streams[AST_MEDIA_TYPE_END] = {0};
764 SCOPE_ENTER(3, "%s: Media count: %d\n", ast_sip_session_get_name(session), sdp->media_count);
742765
743766 if (session->inv_session && session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
744 ast_log(LOG_ERROR, "Failed to handle incoming SDP. Session has been already disconnected\n");
745 return -1;
767 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Failed to handle incoming SDP. Session has been already disconnected\n",
768 ast_sip_session_get_name(session));
746769 }
747770
748771 /* It is possible for SDP deferral to have already created a pending topology */
749772 if (!session->pending_media_state->topology) {
750773 session->pending_media_state->topology = ast_stream_topology_alloc();
751774 if (!session->pending_media_state->topology) {
752 return -1;
775 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Couldn't alloc pending topology\n",
776 ast_sip_session_get_name(session));
753777 }
754778 }
755779
763787 enum ast_media_type type;
764788 struct ast_stream *stream = NULL;
765789 pjmedia_sdp_media *remote_stream = sdp->media[i];
790 SCOPE_ENTER(4, "%s: Processing stream %d\n", ast_sip_session_get_name(session), i);
766791
767792 /* We need a null-terminated version of the media string */
768793 ast_copy_pj_str(media, &sdp->media[i]->desc.media, sizeof(media));
771796 /* See if we have an already existing stream, which can occur from SDP deferral checking */
772797 if (i < ast_stream_topology_get_count(session->pending_media_state->topology)) {
773798 stream = ast_stream_topology_get_stream(session->pending_media_state->topology, i);
799 ast_trace(-1, "%s: Using existing pending stream %s\n", ast_sip_session_get_name(session),
800 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
774801 }
775802 if (!stream) {
776803 struct ast_stream *existing_stream = NULL;
804 char *stream_name = NULL, *stream_name_allocated = NULL;
805 const char *stream_label = NULL;
777806
778807 if (session->active_media_state->topology &&
779808 (i < ast_stream_topology_get_count(session->active_media_state->topology))) {
780809 existing_stream = ast_stream_topology_get_stream(session->active_media_state->topology, i);
781 }
782
783 stream = ast_stream_alloc(existing_stream ? ast_stream_get_name(existing_stream) : ast_codec_media_type2str(type), type);
810 ast_trace(-1, "%s: Found existing active stream %s\n", ast_sip_session_get_name(session),
811 ast_str_tmp(128, ast_stream_to_str(existing_stream, &STR_TMP)));
812
813 if (ast_stream_get_state(existing_stream) != AST_STREAM_STATE_REMOVED) {
814 stream_name = (char *)ast_stream_get_name(existing_stream);
815 stream_label = ast_stream_get_metadata(existing_stream, "SDP:LABEL");
816 }
817 }
818
819 if (ast_strlen_zero(stream_name)) {
820 if (ast_asprintf(&stream_name_allocated, "%s-%d", ast_codec_media_type2str(type), i) < 0) {
821 handled = 0;
822 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't alloc stream name\n",
823 ast_sip_session_get_name(session));
824
825 }
826 stream_name = stream_name_allocated;
827 ast_trace(-1, "%s: Using %s for new stream name\n", ast_sip_session_get_name(session),
828 stream_name);
829 }
830
831 stream = ast_stream_alloc(stream_name, type);
832 ast_free(stream_name_allocated);
784833 if (!stream) {
785 return -1;
786 }
834 handled = 0;
835 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't alloc stream\n",
836 ast_sip_session_get_name(session));
837 }
838
839 if (!ast_strlen_zero(stream_label)) {
840 ast_stream_set_metadata(stream, "SDP:LABEL", stream_label);
841 ast_trace(-1, "%s: Using %s for new stream label\n", ast_sip_session_get_name(session),
842 stream_label);
843
844 }
845
787846 if (ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream)) {
788847 ast_stream_free(stream);
789 return -1;
790 }
791 if (existing_stream) {
792 const char *stream_label = ast_stream_get_metadata(existing_stream, "SDP:LABEL");
793
794 if (!ast_strlen_zero(stream_label)) {
795 ast_stream_set_metadata(stream, "SDP:LABEL", stream_label);
796 }
848 handled = 0;
849 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't set stream in topology\n",
850 ast_sip_session_get_name(session));
797851 }
798852
799853 /* For backwards compatibility with the core the default audio stream is always sendrecv */
814868 } else {
815869 ast_stream_set_state(stream, AST_STREAM_STATE_SENDRECV);
816870 }
871 ast_trace(-1, "%s: Using new stream %s\n", ast_sip_session_get_name(session),
872 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
817873 }
818874
819875 session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_media_type_from_str(media), i);
820876 if (!session_media) {
821 return -1;
877 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't alloc session media\n",
878 ast_sip_session_get_name(session));
822879 }
823880
824881 /* If this stream is already declined mark it as such, or mark it as such if we've reached the limit */
825882 if (!remote_stream->desc.port || is_stream_limitation_reached(type, session->endpoint, type_streams)) {
826 ast_debug(1, "Declining incoming SDP media stream '%s' at position '%d'\n",
827 ast_codec_media_type2str(type), i);
828883 remove_stream_from_bundle(session_media, stream);
829 continue;
884 SCOPE_EXIT_EXPR(continue, "%s: Declining incoming SDP media stream %s'\n",
885 ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
830886 }
831887
832888 set_mid_and_bundle_group(session, session_media, sdp, remote_stream);
834890
835891 if (session_media->handler) {
836892 handler = session_media->handler;
837 ast_debug(1, "Negotiating incoming SDP media stream '%s' using %s SDP handler\n",
838 ast_codec_media_type2str(session_media->type),
893 ast_trace(-1, "%s: Negotiating incoming SDP media stream %s using %s SDP handler\n",
894 ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)),
839895 session_media->handler->id);
840896 res = handler->negotiate_incoming_sdp_stream(session, session_media, sdp, i, stream);
841897 if (res < 0) {
842898 /* Catastrophic failure. Abort! */
843 return -1;
899 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't negotiate stream %s\n",
900 ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
844901 } else if (res == 0) {
845 ast_debug(1, "Declining incoming SDP media stream '%s' at position '%d'\n",
846 ast_codec_media_type2str(type), i);
847902 remove_stream_from_bundle(session_media, stream);
848 continue;
903 SCOPE_EXIT_EXPR(continue, "%s: Declining incoming SDP media stream %s\n",
904 ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
849905 } else if (res > 0) {
850 ast_debug(1, "Media stream '%s' handled by %s\n",
851 ast_codec_media_type2str(session_media->type),
852 session_media->handler->id);
853 /* Handled by this handler. Move to the next stream */
854906 handled = 1;
855907 ++type_streams[type];
856 continue;
908 /* Handled by this handler. Move to the next stream */
909 SCOPE_EXIT_EXPR(continue, "%s: Media stream %s handled by %s\n",
910 ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)),
911 session_media->handler->id);
857912 }
858913 }
859914
860915 handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
861916 if (!handler_list) {
862 ast_debug(1, "No registered SDP handlers for media type '%s'\n", media);
863 continue;
917 SCOPE_EXIT_EXPR(continue, "%s: Media stream %s has no registered handlers\n",
918 ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
864919 }
865920 AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
866921 if (handler == session_media->handler) {
867922 continue;
868923 }
869 ast_debug(1, "Negotiating incoming SDP media stream '%s' using %s SDP handler\n",
870 ast_codec_media_type2str(session_media->type),
924 ast_trace(-1, "%s: Negotiating incoming SDP media stream %s using %s SDP handler\n",
925 ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)),
871926 handler->id);
927
872928 res = handler->negotiate_incoming_sdp_stream(session, session_media, sdp, i, stream);
873929 if (res < 0) {
874930 /* Catastrophic failure. Abort! */
875 return -1;
931 handled = 0;
932 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't negotiate stream %s\n",
933 ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
876934 } else if (res == 0) {
877 ast_debug(1, "Declining incoming SDP media stream '%s' at position '%d'\n",
878 ast_codec_media_type2str(type), i);
879935 remove_stream_from_bundle(session_media, stream);
936 ast_trace(-1, "%s: Declining incoming SDP media stream %s\n",
937 ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
880938 continue;
881939 } else if (res > 0) {
882 ast_debug(1, "Media stream '%s' handled by %s\n",
883 ast_codec_media_type2str(session_media->type),
884 handler->id);
885 /* Handled by this handler. Move to the next stream */
886940 session_media_set_handler(session_media, handler);
887941 handled = 1;
888942 ++type_streams[type];
943 ast_trace(-1, "%s: Media stream %s handled by %s\n",
944 ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)),
945 session_media->handler->id);
889946 break;
890947 }
891948 }
892 }
893 if (!handled) {
894 return -1;
895 }
896 return 0;
949
950 SCOPE_EXIT("%s: Done with stream %s\n", ast_sip_session_get_name(session),
951 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
952 }
953
954 end:
955 SCOPE_EXIT_RTN_VALUE(handled ? 0 : -1, "%s: Handled? %s\n", ast_sip_session_get_name(session),
956 handled ? "yes" : "no");
897957 }
898958
899959 static int handle_negotiated_sdp_session_media(struct ast_sip_session_media *session_media,
936996
937997 handler = session_media->handler;
938998 if (handler) {
939 ast_debug(1, "Applying negotiated SDP media stream '%s' using %s SDP handler\n",
940 ast_codec_media_type2str(session_media->type),
999 ast_debug(4, "%s: Applying negotiated SDP media stream '%s' using %s SDP handler\n",
1000 ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type),
9411001 handler->id);
9421002 res = handler->apply_negotiated_sdp_stream(session, session_media, local, remote, index, asterisk_stream);
9431003 if (res >= 0) {
944 ast_debug(1, "Applied negotiated SDP media stream '%s' using %s SDP handler\n",
945 ast_codec_media_type2str(session_media->type),
1004 ast_debug(4, "%s: Applied negotiated SDP media stream '%s' using %s SDP handler\n",
1005 ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type),
9461006 handler->id);
9471007 return 0;
9481008 }
9511011
9521012 handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
9531013 if (!handler_list) {
954 ast_debug(1, "No registered SDP handlers for media type '%s'\n", media);
1014 ast_debug(4, "%s: No registered SDP handlers for media type '%s'\n", ast_sip_session_get_name(session), media);
9551015 return -1;
9561016 }
9571017 AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
9581018 if (handler == session_media->handler) {
9591019 continue;
9601020 }
961 ast_debug(1, "Applying negotiated SDP media stream '%s' using %s SDP handler\n",
962 ast_codec_media_type2str(session_media->type),
1021 ast_debug(4, "%s: Applying negotiated SDP media stream '%s' using %s SDP handler\n",
1022 ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type),
9631023 handler->id);
9641024 res = handler->apply_negotiated_sdp_stream(session, session_media, local, remote, index, asterisk_stream);
9651025 if (res < 0) {
9671027 return -1;
9681028 }
9691029 if (res > 0) {
970 ast_debug(1, "Applied negotiated SDP media stream '%s' using %s SDP handler\n",
971 ast_codec_media_type2str(session_media->type),
1030 ast_debug(4, "%s: Applied negotiated SDP media stream '%s' using %s SDP handler\n",
1031 ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type),
9721032 handler->id);
9731033 /* Handled by this handler. Move to the next stream */
9741034 session_media_set_handler(session_media, handler);
9771037 }
9781038
9791039 if (session_media->handler && session_media->handler->stream_stop) {
980 ast_debug(1, "Stopping SDP media stream '%s' as it is not currently negotiated\n",
981 ast_codec_media_type2str(session_media->type));
1040 ast_debug(4, "%s: Stopping SDP media stream '%s' as it is not currently negotiated\n",
1041 ast_sip_session_get_name(session), ast_codec_media_type2str(session_media->type));
9821042 session_media->handler->stream_stop(session_media);
9831043 }
9841044
10031063 active_media_state_clone =
10041064 ast_sip_session_media_state_clone(session->active_media_state);
10051065 if (!active_media_state_clone) {
1006 ast_log(LOG_WARNING, "Unable to clone active media state for channel '%s'\n",
1007 session->channel ? ast_channel_name(session->channel) : "unknown");
1066 ast_log(LOG_WARNING, "%s: Unable to clone active media state\n",
1067 ast_sip_session_get_name(session));
10081068 return -1;
10091069 }
10101070
10111071 ast_sip_session_media_state_free(session->pending_media_state);
10121072 session->pending_media_state = active_media_state_clone;
10131073 } else {
1014 ast_log(LOG_WARNING, "No pending or active media state for channel '%s'\n",
1015 session->channel ? ast_channel_name(session->channel) : "unknown");
1074 ast_log(LOG_WARNING, "%s: No pending or active media state\n",
1075 ast_sip_session_get_name(session));
10161076 return -1;
10171077 }
10181078 }
10241084 */
10251085 if (ast_stream_topology_get_count(session->pending_media_state->topology) != local->media_count
10261086 || AST_VECTOR_SIZE(&session->pending_media_state->sessions) != local->media_count) {
1027 ast_log(LOG_WARNING, "Local SDP for channel '%s' contains %d media streams while we expected it to contain %u\n",
1028 session->channel ? ast_channel_name(session->channel) : "unknown",
1087 ast_log(LOG_WARNING, "%s: Local SDP contains %d media streams while we expected it to contain %u\n",
1088 ast_sip_session_get_name(session),
10291089 ast_stream_topology_get_count(session->pending_media_state->topology), local->media_count);
10301090 return -1;
10311091 }
12691329 /*! Whether to generate new SDP */
12701330 int generate_new_sdp;
12711331 /*! Requested media state for the SDP */
1272 struct ast_sip_session_media_state *media_state;
1332 struct ast_sip_session_media_state *pending_media_state;
1333 /*! Active media state at the time of the original request */
1334 struct ast_sip_session_media_state *active_media_state;
1335
12731336 AST_LIST_ENTRY(ast_sip_session_delayed_request) next;
12741337 };
12751338
12791342 ast_sip_session_sdp_creation_cb on_sdp_creation,
12801343 ast_sip_session_response_cb on_response,
12811344 int generate_new_sdp,
1282 struct ast_sip_session_media_state *media_state)
1345 struct ast_sip_session_media_state *pending_media_state,
1346 struct ast_sip_session_media_state *active_media_state)
12831347 {
12841348 struct ast_sip_session_delayed_request *delay = ast_calloc(1, sizeof(*delay));
12851349
12911355 delay->on_sdp_creation = on_sdp_creation;
12921356 delay->on_response = on_response;
12931357 delay->generate_new_sdp = generate_new_sdp;
1294 delay->media_state = media_state;
1358 delay->pending_media_state = pending_media_state;
1359 delay->active_media_state = active_media_state;
12951360 return delay;
12961361 }
12971362
12981363 static void delayed_request_free(struct ast_sip_session_delayed_request *delay)
12991364 {
1300 ast_sip_session_media_state_free(delay->media_state);
1365 ast_sip_session_media_state_free(delay->pending_media_state);
1366 ast_sip_session_media_state_free(delay->active_media_state);
13011367 ast_free(delay);
13021368 }
13031369
13121378 static int send_delayed_request(struct ast_sip_session *session, struct ast_sip_session_delayed_request *delay)
13131379 {
13141380 int res;
1315
1316 ast_debug(3, "Endpoint '%s(%s)' sending delayed %s request.\n",
1317 ast_sorcery_object_get_id(session->endpoint),
1318 session->channel ? ast_channel_name(session->channel) : "",
1381 SCOPE_ENTER(3, "%s: sending delayed %s request\n",
1382 ast_sip_session_get_name(session),
13191383 delayed_method2str(delay->method));
13201384
13211385 switch (delay->method) {
13221386 case DELAYED_METHOD_INVITE:
13231387 res = sip_session_refresh(session, delay->on_request_creation,
13241388 delay->on_sdp_creation, delay->on_response,
1325 AST_SIP_SESSION_REFRESH_METHOD_INVITE, delay->generate_new_sdp, delay->media_state, 1);
1389 AST_SIP_SESSION_REFRESH_METHOD_INVITE, delay->generate_new_sdp, delay->pending_media_state,
1390 delay->active_media_state, 1);
13261391 /* Ownership of media state transitions to ast_sip_session_refresh */
1327 delay->media_state = NULL;
1328 return res;
1392 delay->pending_media_state = NULL;
1393 delay->active_media_state = NULL;
1394 SCOPE_EXIT_RTN_VALUE(res, "%s\n", ast_sip_session_get_name(session));
13291395 case DELAYED_METHOD_UPDATE:
13301396 res = sip_session_refresh(session, delay->on_request_creation,
13311397 delay->on_sdp_creation, delay->on_response,
1332 AST_SIP_SESSION_REFRESH_METHOD_UPDATE, delay->generate_new_sdp, delay->media_state, 1);
1398 AST_SIP_SESSION_REFRESH_METHOD_UPDATE, delay->generate_new_sdp, delay->pending_media_state,
1399 delay->active_media_state, 1);
13331400 /* Ownership of media state transitions to ast_sip_session_refresh */
1334 delay->media_state = NULL;
1335 return res;
1401 delay->pending_media_state = NULL;
1402 delay->active_media_state = NULL;
1403 SCOPE_EXIT_RTN_VALUE(res, "%s\n", ast_sip_session_get_name(session));
13361404 case DELAYED_METHOD_BYE:
13371405 ast_sip_session_terminate(session, 0);
1338 return 0;
1339 }
1340 ast_log(LOG_WARNING, "Don't know how to send delayed %s(%d) request.\n",
1406 SCOPE_EXIT_RTN_VALUE(0, "%s: Terminating session on delayed BYE\n", ast_sip_session_get_name(session));
1407 }
1408
1409 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Don't know how to send delayed %s(%d) request.\n",
1410 ast_sip_session_get_name(session),
13411411 delayed_method2str(delay->method), delay->method);
1342 return -1;
13431412 }
13441413
13451414 /*!
13581427 struct ast_sip_session_delayed_request *delay;
13591428 int found = 0;
13601429 int res = 0;
1430 SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
13611431
13621432 AST_LIST_TRAVERSE_SAFE_BEGIN(&session->delayed_requests, delay, next) {
13631433 switch (delay->method) {
13651435 break;
13661436 case DELAYED_METHOD_UPDATE:
13671437 AST_LIST_REMOVE_CURRENT(next);
1438 ast_trace(-1, "%s: Sending delayed %s request\n", ast_sip_session_get_name(session),
1439 delayed_method2str(delay->method));
13681440 res = send_delayed_request(session, delay);
13691441 delayed_request_free(delay);
13701442 if (!res) {
13831455 AST_LIST_TRAVERSE_SAFE_END;
13841456
13851457 ao2_ref(session, -1);
1386 return res;
1458 SCOPE_EXIT_RTN_VALUE(res, "%s\n", ast_sip_session_get_name(session));
13871459 }
13881460
13891461 /*!
14031475 int found = 0;
14041476 int res = 0;
14051477 int timer_running;
1478 SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
14061479
14071480 /* re-INVITE collision timer running? */
14081481 timer_running = pj_timer_entry_running(&session->rescheduled_reinvite);
14211494 }
14221495 if (found) {
14231496 AST_LIST_REMOVE_CURRENT(next);
1497 ast_trace(-1, "%s: Sending delayed %s request\n", ast_sip_session_get_name(session),
1498 delayed_method2str(delay->method));
14241499 res = send_delayed_request(session, delay);
14251500 delayed_request_free(delay);
14261501 if (!res) {
14311506 AST_LIST_TRAVERSE_SAFE_END;
14321507
14331508 ao2_ref(session, -1);
1434 return res;
1509 SCOPE_EXIT_RTN_VALUE(res, "%s\n", ast_sip_session_get_name(session));
14351510 }
14361511
14371512 /*!
14481523 {
14491524 struct ast_sip_session *session = vsession;
14501525 int res;
1526 SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
14511527
14521528 if (session->inv_session->invite_tsx) {
14531529 /*
14601536 res = invite_terminated(session);
14611537 }
14621538
1463 return res;
1539 SCOPE_EXIT_RTN_VALUE(res, "%s\n", ast_sip_session_get_name(session));
14641540 }
14651541
14661542 /*!
15021578 ast_sip_session_response_cb on_response,
15031579 int generate_new_sdp,
15041580 enum delayed_method method,
1505 struct ast_sip_session_media_state *media_state)
1581 struct ast_sip_session_media_state *pending_media_state,
1582 struct ast_sip_session_media_state *active_media_state,
1583 int queue_head)
15061584 {
15071585 struct ast_sip_session_delayed_request *delay = delayed_request_alloc(method,
1508 on_request, on_sdp_creation, on_response, generate_new_sdp, media_state);
1586 on_request, on_sdp_creation, on_response, generate_new_sdp, pending_media_state,
1587 active_media_state);
1588 SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
15091589
15101590 if (!delay) {
1511 ast_sip_session_media_state_free(media_state);
1512 return -1;
1513 }
1514
1515 if (method == DELAYED_METHOD_BYE) {
1591 ast_sip_session_media_state_free(pending_media_state);
1592 ast_sip_session_media_state_free(active_media_state);
1593 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "Unable to allocate delay request\n");
1594 }
1595
1596 if (method == DELAYED_METHOD_BYE || queue_head) {
15161597 /* Send BYE as early as possible */
15171598 AST_LIST_INSERT_HEAD(&session->delayed_requests, delay, next);
15181599 } else {
15191600 AST_LIST_INSERT_TAIL(&session->delayed_requests, delay, next);
15201601 }
1521 return 0;
1602 SCOPE_EXIT_RTN_VALUE(0);
15221603 }
15231604
15241605 static pjmedia_sdp_session *generate_session_refresh_sdp(struct ast_sip_session *session)
15251606 {
15261607 pjsip_inv_session *inv_session = session->inv_session;
15271608 const pjmedia_sdp_session *previous_sdp = NULL;
1609 SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
15281610
15291611 if (inv_session->neg) {
15301612 if (pjmedia_sdp_neg_was_answer_remote(inv_session->neg)) {
15331615 pjmedia_sdp_neg_get_active_local(inv_session->neg, &previous_sdp);
15341616 }
15351617 }
1536 return create_local_sdp(inv_session, session, previous_sdp);
1618 SCOPE_EXIT_RTN_VALUE(create_local_sdp(inv_session, session, previous_sdp));
15371619 }
15381620
15391621 static void set_from_header(struct ast_sip_session *session)
15971679 ast_channel_lock(session->channel);
15981680 pjsip_from_domain = pbx_builtin_getvar_helper(session->channel, "SIPFROMDOMAIN");
15991681 if (!ast_strlen_zero(pjsip_from_domain)) {
1600 ast_debug(3, "From header domain reset by channel variable SIPFROMDOMAIN (%s)\n", pjsip_from_domain);
1682 ast_debug(3, "%s: From header domain reset by channel variable SIPFROMDOMAIN (%s)\n",
1683 ast_sip_session_get_name(session), pjsip_from_domain);
16011684 pj_strdup2(dlg_pool, &dlg_info_uri->host, pjsip_from_domain);
16021685 }
16031686 ast_channel_unlock(session->channel);
16291712 }
16301713 }
16311714
1715 /*
1716 * Helper macros for merging and validating media states
1717 */
1718 #define STREAM_REMOVED(_stream) (ast_stream_get_state(_stream) == AST_STREAM_STATE_REMOVED)
1719 #define STATE_REMOVED(_stream_state) (_stream_state == AST_STREAM_STATE_REMOVED)
1720 #define STATE_NONE(_stream_state) (_stream_state == AST_STREAM_STATE_END)
1721 #define GET_STREAM_SAFE(_topology, _i) (_i < ast_stream_topology_get_count(_topology) ? ast_stream_topology_get_stream(_topology, _i) : NULL)
1722 #define GET_STREAM_STATE_SAFE(_stream) (_stream ? ast_stream_get_state(_stream) : AST_STREAM_STATE_END)
1723 #define GET_STREAM_NAME_SAFE(_stream) (_stream ? ast_stream_get_name(_stream) : "")
1724
1725 /*!
1726 * \internal
1727 * \brief Validate a media state
1728 *
1729 * \param state Media state
1730 *
1731 * \retval 1 The media state is valid
1732 * \retval 0 The media state is NOT valid
1733 *
1734 */
1735 static int is_media_state_valid(const char *session_name, struct ast_sip_session_media_state *state)
1736 {
1737 int stream_count = ast_stream_topology_get_count(state->topology);
1738 int session_count = AST_VECTOR_SIZE(&state->sessions);
1739 int i;
1740 int res = 0;
1741 SCOPE_ENTER(3, "%s: Topology: %s\n", session_name,
1742 ast_str_tmp(256, ast_stream_topology_to_str(state->topology, &STR_TMP)));
1743
1744 if (session_count != stream_count) {
1745 SCOPE_EXIT_RTN_VALUE(0, "%s: %d media sessions but %d streams\n", session_name,
1746 session_count, stream_count);
1747 }
1748
1749 for (i = 0; i < stream_count; i++) {
1750 struct ast_sip_session_media *media = NULL;
1751 struct ast_stream *stream = ast_stream_topology_get_stream(state->topology, i);
1752 const char *stream_name = NULL;
1753 int j;
1754 SCOPE_ENTER(4, "%s: Checking stream %s\n", session_name, ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
1755
1756 if (!stream) {
1757 SCOPE_EXIT_EXPR(goto end, "%s: stream %d is null\n", session_name, i);
1758 }
1759 stream_name = ast_stream_get_name(stream);
1760
1761 for (j = 0; j < stream_count; j++) {
1762 struct ast_stream *possible_dup = ast_stream_topology_get_stream(state->topology, j);
1763 if (j == i || !possible_dup) {
1764 continue;
1765 }
1766 if (!STREAM_REMOVED(stream) && ast_strings_equal(stream_name, GET_STREAM_NAME_SAFE(possible_dup))) {
1767 SCOPE_EXIT_EXPR(goto end, "%s: stream %i %s is duplicated to %d\n", session_name,
1768 i, stream_name, j);
1769 }
1770 }
1771
1772 media = AST_VECTOR_GET(&state->sessions, i);
1773 if (!media) {
1774 SCOPE_EXIT_EXPR(continue, "%s: media %d is null\n", session_name, i);
1775 }
1776
1777 for (j = 0; j < session_count; j++) {
1778 struct ast_sip_session_media *possible_dup = AST_VECTOR_GET(&state->sessions, j);
1779 if (j == i || !possible_dup) {
1780 continue;
1781 }
1782 if (!ast_strlen_zero(media->label) && !ast_strlen_zero(possible_dup->label)
1783 && ast_strings_equal(media->label, possible_dup->label)) {
1784 SCOPE_EXIT_EXPR(goto end, "%s: media %d %s is duplicated to %d\n", session_name,
1785 i, media->label, j);
1786 }
1787 }
1788
1789 if (media->stream_num != i) {
1790 SCOPE_EXIT_EXPR(goto end, "%s: media %d has stream_num %d\n", session_name,
1791 i, media->stream_num);
1792 }
1793
1794 if (media->type != ast_stream_get_type(stream)) {
1795 SCOPE_EXIT_EXPR(goto end, "%s: media %d has type %s but stream has type %s\n", stream_name,
1796 i, ast_codec_media_type2str(media->type), ast_codec_media_type2str(ast_stream_get_type(stream)));
1797 }
1798 SCOPE_EXIT("%s: Done with stream %s\n", session_name, ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
1799 }
1800
1801 res = 1;
1802 end:
1803 SCOPE_EXIT_RTN_VALUE(res, "%s: %s\n", session_name, res ? "Valid" : "NOT Valid");
1804 }
1805
1806 /*!
1807 * \internal
1808 * \brief Merge media states for a delayed session refresh
1809 *
1810 * \param session_name For log messages
1811 * \param delayed_pending_state The pending media state at the time the resuest was queued
1812 * \param delayed_active_state The active media state at the time the resuest was queued
1813 * \param current_active_state The current active media state
1814 * \param run_validation Whether to run validation on the resulting media state or not
1815 *
1816 * \returns New merged topology or NULL if there's an error
1817 *
1818 */
1819 static struct ast_sip_session_media_state *resolve_refresh_media_states(
1820 const char *session_name,
1821 struct ast_sip_session_media_state *delayed_pending_state,
1822 struct ast_sip_session_media_state *delayed_active_state,
1823 struct ast_sip_session_media_state *current_active_state,
1824 int run_post_validation)
1825 {
1826 RAII_VAR(struct ast_sip_session_media_state *, new_pending_state, NULL, ast_sip_session_media_state_free);
1827 struct ast_sip_session_media_state *returned_media_state = NULL;
1828 struct ast_stream_topology *delayed_pending = delayed_pending_state->topology;
1829 struct ast_stream_topology *delayed_active = delayed_active_state->topology;
1830 struct ast_stream_topology *current_active = current_active_state->topology;
1831 struct ast_stream_topology *new_pending = NULL;
1832 int i;
1833 int max_stream_count;
1834 int res;
1835 SCOPE_ENTER(2, "%s: DP: %s DA: %s CA: %s\n", session_name,
1836 ast_str_tmp(256, ast_stream_topology_to_str(delayed_pending, &STR_TMP)),
1837 ast_str_tmp(256, ast_stream_topology_to_str(delayed_active, &STR_TMP)),
1838 ast_str_tmp(256, ast_stream_topology_to_str(current_active, &STR_TMP))
1839 );
1840
1841 max_stream_count = MAX(ast_stream_topology_get_count(delayed_pending),
1842 ast_stream_topology_get_count(delayed_active));
1843 max_stream_count = MAX(max_stream_count, ast_stream_topology_get_count(current_active));
1844
1845 /*
1846 * The new_pending_state is always based on the currently negotiated state because
1847 * the stream ordering in its topology must be preserved.
1848 */
1849 new_pending_state = ast_sip_session_media_state_clone(current_active_state);
1850 if (!new_pending_state) {
1851 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Couldn't clone current_active_state to new_pending_state\n", session_name);
1852 }
1853 new_pending = new_pending_state->topology;
1854
1855 for (i = 0; i < max_stream_count; i++) {
1856 struct ast_stream *dp_stream = GET_STREAM_SAFE(delayed_pending, i);
1857 struct ast_stream *da_stream = GET_STREAM_SAFE(delayed_active, i);
1858 struct ast_stream *ca_stream = GET_STREAM_SAFE(current_active, i);
1859 struct ast_stream *np_stream = GET_STREAM_SAFE(new_pending, i);
1860 struct ast_stream *found_da_stream = NULL;
1861 struct ast_stream *found_np_stream = NULL;
1862 enum ast_stream_state dp_state = GET_STREAM_STATE_SAFE(dp_stream);
1863 enum ast_stream_state da_state = GET_STREAM_STATE_SAFE(da_stream);
1864 enum ast_stream_state ca_state = GET_STREAM_STATE_SAFE(ca_stream);
1865 enum ast_stream_state np_state = GET_STREAM_STATE_SAFE(np_stream);
1866 enum ast_stream_state found_da_state = AST_STREAM_STATE_END;
1867 enum ast_stream_state found_np_state = AST_STREAM_STATE_END;
1868 const char *da_name = GET_STREAM_NAME_SAFE(da_stream);
1869 const char *dp_name = GET_STREAM_NAME_SAFE(dp_stream);
1870 const char *ca_name = GET_STREAM_NAME_SAFE(ca_stream);
1871 const char *np_name = GET_STREAM_NAME_SAFE(np_stream);
1872 const char *found_da_name __attribute__((unused)) = "";
1873 const char *found_np_name __attribute__((unused)) = "";
1874 int found_da_slot __attribute__((unused)) = -1;
1875 int found_np_slot = -1;
1876 int removed_np_slot = -1;
1877 int j;
1878 SCOPE_ENTER(3, "%s: slot: %d DP: %s DA: %s CA: %s\n", session_name, i,
1879 ast_str_tmp(128, ast_stream_to_str(dp_stream, &STR_TMP)),
1880 ast_str_tmp(128, ast_stream_to_str(da_stream, &STR_TMP)),
1881 ast_str_tmp(128, ast_stream_to_str(ca_stream, &STR_TMP)));
1882
1883 if (STATE_NONE(da_state) && STATE_NONE(dp_state) && STATE_NONE(ca_state)) {
1884 SCOPE_EXIT_EXPR(break, "%s: All gone\n", session_name);
1885 }
1886
1887 /*
1888 * Simple cases are handled first to avoid having to search the NP and DA
1889 * topologies for streams with the same name but not in the same position.
1890 */
1891
1892 if (STATE_NONE(dp_state) && !STATE_NONE(da_state)) {
1893 /*
1894 * The slot in the delayed pending topology can't be empty if the delayed
1895 * active topology has a stream there. Streams can't just go away. They
1896 * can be reused or marked "removed" but they can't go away.
1897 */
1898 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_WARNING, "%s: DP slot is empty but DA is not\n", session_name);
1899 }
1900
1901 if (STATE_NONE(dp_state)) {
1902 /*
1903 * The current active topology can certainly have streams that weren't
1904 * in existence when the delayed request was queued. In this case,
1905 * no action is needed since we already copied the current active topology
1906 * to the new pending one.
1907 */
1908 SCOPE_EXIT_EXPR(continue, "%s: No DP stream so use CA stream as is\n", session_name);
1909 }
1910
1911 if (ast_strings_equal(dp_name, da_name) && ast_strings_equal(da_name, ca_name)) {
1912 /*
1913 * The delayed pending stream in this slot matches by name, the streams
1914 * in the same slot in the other two topologies. Easy case.
1915 */
1916 ast_trace(-1, "%s: Same stream in all 3 states\n", session_name);
1917 if (dp_state == da_state && da_state == ca_state) {
1918 /* All the same state, no need to update. */
1919 SCOPE_EXIT_EXPR(continue, "%s: All in the same state so nothing to do\n", session_name);
1920 }
1921 if (da_state != ca_state) {
1922 /*
1923 * Something set the CA state between the time this request was queued
1924 * and now. The CA state wins so we don't do anything.
1925 */
1926 SCOPE_EXIT_EXPR(continue, "%s: Ignoring request to change state from %s to %s\n",
1927 session_name, ast_stream_state2str(ca_state), ast_stream_state2str(dp_state));
1928 }
1929 if (dp_state != da_state) {
1930 /* DP needs to update the state */
1931 ast_stream_set_state(np_stream, dp_state);
1932 SCOPE_EXIT_EXPR(continue, "%s: Changed NP stream state from %s to %s\n",
1933 session_name, ast_stream_state2str(ca_state), ast_stream_state2str(dp_state));
1934 }
1935 }
1936
1937 /*
1938 * We're done with the simple cases. For the rest, we need to identify if the
1939 * DP stream we're trying to take action on is already in the other topologies
1940 * possibly in a different slot. To do that, if the stream in the DA or CA slots
1941 * doesn't match the current DP stream, we need to iterate over the topology
1942 * looking for a stream with the same name.
1943 */
1944
1945 /*
1946 * Since we already copied all of the CA streams to the NP topology, we'll use it
1947 * instead of CA because we'll be updating the NP as we go.
1948 */
1949 if (!ast_strings_equal(dp_name, np_name)) {
1950 /*
1951 * The NP stream in this slot doesn't have the same name as the DP stream
1952 * so we need to see if it's in another NP slot. We're not going to stop
1953 * when we find a matching stream because we also want to find the first
1954 * removed removed slot, if any, so we can re-use this slot. We'll break
1955 * early if we find both before we reach the end.
1956 */
1957 ast_trace(-1, "%s: Checking if DP is already in NP somewhere\n", session_name);
1958 for (j = 0; j < ast_stream_topology_get_count(new_pending); j++) {
1959 struct ast_stream *possible_existing = ast_stream_topology_get_stream(new_pending, j);
1960 const char *possible_existing_name = GET_STREAM_NAME_SAFE(possible_existing);
1961
1962 ast_trace(-1, "%s: Checking %s against %s\n", session_name, dp_name, possible_existing_name);
1963 if (found_np_slot == -1 && ast_strings_equal(dp_name, possible_existing_name)) {
1964 ast_trace(-1, "%s: Pending stream %s slot %d is in NP slot %d\n", session_name,
1965 dp_name, i, j);
1966 found_np_slot = j;
1967 found_np_stream = possible_existing;
1968 found_np_state = ast_stream_get_state(possible_existing);
1969 found_np_name = ast_stream_get_name(possible_existing);
1970 }
1971 if (STREAM_REMOVED(possible_existing) && removed_np_slot == -1) {
1972 removed_np_slot = j;
1973 }
1974 if (removed_np_slot >= 0 && found_np_slot >= 0) {
1975 break;
1976 }
1977 }
1978 } else {
1979 /* Makes the subsequent code easier */
1980 found_np_slot = i;
1981 found_np_stream = np_stream;
1982 found_np_state = np_state;
1983 found_np_name = np_name;
1984 }
1985
1986 if (!ast_strings_equal(dp_name, da_name)) {
1987 /*
1988 * The DA stream in this slot doesn't have the same name as the DP stream
1989 * so we need to see if it's in another DA slot. In real life, the DA stream
1990 * in this slot could have a different name but there shouldn't be a case
1991 * where the DP stream is another slot in the DA topology. Just in case though.
1992 * We don't care about removed slots in the DA topology.
1993 */
1994 ast_trace(-1, "%s: Checking if DP is already in DA somewhere\n", session_name);
1995 for (j = 0; j < ast_stream_topology_get_count(delayed_active); j++) {
1996 struct ast_stream *possible_existing = ast_stream_topology_get_stream(delayed_active, j);
1997 const char *possible_existing_name = GET_STREAM_NAME_SAFE(possible_existing);
1998
1999 ast_trace(-1, "%s: Checking %s against %s\n", session_name, dp_name, possible_existing_name);
2000 if (ast_strings_equal(dp_name, possible_existing_name)) {
2001 ast_trace(-1, "%s: Pending stream %s slot %d is already in delayed active slot %d\n",
2002 session_name, dp_name, i, j);
2003 found_da_slot = j;
2004 found_da_stream = possible_existing;
2005 found_da_state = ast_stream_get_state(possible_existing);
2006 found_da_name = ast_stream_get_name(possible_existing);
2007 break;
2008 }
2009 }
2010 } else {
2011 /* Makes the subsequent code easier */
2012 found_da_slot = i;
2013 found_da_stream = da_stream;
2014 found_da_state = da_state;
2015 found_da_name = da_name;
2016 }
2017
2018 ast_trace(-1, "%s: Found NP slot: %d Found removed NP slot: %d Found DA slot: %d\n",
2019 session_name, found_np_slot, removed_np_slot, found_da_slot);
2020
2021 /*
2022 * Now we know whether the DP stream is new or changing state and we know if the DP
2023 * stream exists in the other topologies and if so, where in those topologies it exists.
2024 */
2025
2026 if (!found_da_stream) {
2027 /*
2028 * The DP stream isn't in the DA topology which would imply that the intention of the
2029 * request was to add the stream, not change its state. It's possible though that
2030 * the stream was added by another request between the time this request was queued
2031 * and now so we need to check the CA topology as well.
2032 */
2033 ast_trace(-1, "%s: There was no corresponding DA stream so the request was to add a stream\n", session_name);
2034
2035 if (found_np_stream) {
2036 /*
2037 * We found it in the CA topology. Since the intention was to add it
2038 * and it's already there, there's nothing to do.
2039 */
2040 SCOPE_EXIT_EXPR(continue, "%s: New stream requested but it's already in CA\n", session_name);
2041 } else {
2042 /* OK, it's not in either which would again imply that the intention of the
2043 * request was to add the stream.
2044 */
2045 ast_trace(-1, "%s: There was no corresponding NP stream\n", session_name);
2046 if (STATE_REMOVED(dp_state)) {
2047 /*
2048 * How can DP request to remove a stream that doesn't seem to exist anythere?
2049 * It's not. It's possible that the stream was already removed and the slot
2050 * reused in the CA topology, but it would still have to exist in the DA
2051 * topology. Bail.
2052 */
2053 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR,
2054 "%s: Attempting to remove stream %d:%s but it doesn't exist anywhere.\n", session_name, i, dp_name);
2055 } else {
2056 /*
2057 * We're now sure we want to add the the stream. Since we can re-use
2058 * slots in the CA topology that have streams marked as "removed", we
2059 * use the slot we saved in removed_np_slot if it exists.
2060 */
2061 ast_trace(-1, "%s: Checking for open slot\n", session_name);
2062 if (removed_np_slot >= 0) {
2063 struct ast_sip_session_media *old_media = AST_VECTOR_GET(&new_pending_state->sessions, removed_np_slot);
2064 res = ast_stream_topology_set_stream(new_pending, removed_np_slot, ast_stream_clone(dp_stream, NULL));
2065 if (res != 0) {
2066 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_WARNING, "%s: Couldn't set stream in new topology\n", session_name);
2067 }
2068 /*
2069 * Since we're reusing the removed_np_slot slot for something else, we need
2070 * to free and remove any session media already in it.
2071 * ast_stream_topology_set_stream() took care of freeing the old stream.
2072 */
2073 res = AST_VECTOR_REPLACE(&new_pending_state->sessions, removed_np_slot, NULL);
2074 if (res != 0) {
2075 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_WARNING, "%s: Couldn't replace media session\n", session_name);
2076 }
2077
2078 ao2_cleanup(old_media);
2079 SCOPE_EXIT_EXPR(continue, "%s: Replaced removed stream in slot %d\n",
2080 session_name, removed_np_slot);
2081 } else {
2082 int new_slot = ast_stream_topology_append_stream(new_pending, ast_stream_clone(dp_stream, NULL));
2083 if (new_slot < 0) {
2084 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_WARNING, "%s: Couldn't append stream in new topology\n", session_name);
2085 }
2086
2087 res = AST_VECTOR_REPLACE(&new_pending_state->sessions, new_slot, NULL);
2088 if (res != 0) {
2089 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_WARNING, "%s: Couldn't replace media session\n", session_name);
2090 }
2091 SCOPE_EXIT_EXPR(continue, "%s: Appended new stream to slot %d\n",
2092 session_name, new_slot);
2093 }
2094 }
2095 }
2096 } else {
2097 /*
2098 * The DP stream exists in the DA topology so it's a change of some sort.
2099 */
2100 ast_trace(-1, "%s: There was a corresponding DA stream so the request was to change/remove a stream\n", session_name);
2101 if (dp_state == found_da_state) {
2102 /* No change? Let's see if it's in CA */
2103 if (!found_np_stream) {
2104 /*
2105 * The DP and DA state are the same which would imply that the stream
2106 * already exists but it's not in the CA topology. It's possible that
2107 * between the time this request was queued and now the stream was removed
2108 * from the CA topology and the slot used for something else. Nothing
2109 * we can do here.
2110 */
2111 SCOPE_EXIT_EXPR(continue, "%s: Stream doesn't exist in CA so nothing to do\n", session_name);
2112 } else if (dp_state == found_np_state) {
2113 SCOPE_EXIT_EXPR(continue, "%s: States are the same all around so nothing to do\n", session_name);
2114 } else {
2115 SCOPE_EXIT_EXPR(continue, "%s: Something changed the CA state so we're going to leave it as is\n", session_name);
2116 }
2117 } else {
2118 /* We have a state change. */
2119 ast_trace(-1, "%s: Requesting state change to %s\n", session_name, ast_stream_state2str(dp_state));
2120 if (!found_np_stream) {
2121 SCOPE_EXIT_EXPR(continue, "%s: Stream doesn't exist in CA so nothing to do\n", session_name);
2122 } else if (da_state == found_np_state) {
2123 ast_stream_set_state(found_np_stream, dp_state);
2124 SCOPE_EXIT_EXPR(continue, "%s: Changed NP stream state from %s to %s\n",
2125 session_name, ast_stream_state2str(found_np_state), ast_stream_state2str(dp_state));
2126 } else {
2127 SCOPE_EXIT_EXPR(continue, "%s: Something changed the CA state so we're going to leave it as is\n",
2128 session_name);
2129 }
2130 }
2131 }
2132
2133 SCOPE_EXIT("%s: Done with slot %d\n", session_name, i);
2134 }
2135
2136 ast_trace(-1, "%s: Resetting default media states\n", session_name);
2137 for (i = 0; i < AST_MEDIA_TYPE_END; i++) {
2138 int j;
2139 new_pending_state->default_session[i] = NULL;
2140 for (j = 0; j < AST_VECTOR_SIZE(&new_pending_state->sessions); j++) {
2141 struct ast_sip_session_media *media = AST_VECTOR_GET(&new_pending_state->sessions, j);
2142 struct ast_stream *stream = ast_stream_topology_get_stream(new_pending_state->topology, j);
2143
2144 if (media && media->type == i && !STREAM_REMOVED(stream)) {
2145 new_pending_state->default_session[i] = media;
2146 break;
2147 }
2148 }
2149 }
2150
2151 if (run_post_validation) {
2152 ast_trace(-1, "%s: Running post-validation\n", session_name);
2153 if (!is_media_state_valid(session_name, new_pending_state)) {
2154 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "State not consistent\n");
2155 }
2156 }
2157
2158 /*
2159 * We need to move the new pending state to another variable and set new_pending_state to NULL
2160 * so RAII_VAR doesn't free it.
2161 */
2162 returned_media_state = new_pending_state;
2163 new_pending_state = NULL;
2164 SCOPE_EXIT_RTN_VALUE(returned_media_state, "%s: NP: %s\n", session_name,
2165 ast_str_tmp(256, ast_stream_topology_to_str(new_pending, &STR_TMP)));
2166 }
2167
16322168 static int sip_session_refresh(struct ast_sip_session *session,
16332169 ast_sip_session_request_creation_cb on_request_creation,
16342170 ast_sip_session_sdp_creation_cb on_sdp_creation,
16352171 ast_sip_session_response_cb on_response,
16362172 enum ast_sip_session_refresh_method method, int generate_new_sdp,
1637 struct ast_sip_session_media_state *media_state,
2173 struct ast_sip_session_media_state *pending_media_state,
2174 struct ast_sip_session_media_state *active_media_state,
16382175 int queued)
16392176 {
16402177 pjsip_inv_session *inv_session = session->inv_session;
16412178 pjmedia_sdp_session *new_sdp = NULL;
16422179 pjsip_tx_data *tdata;
1643
1644 if (media_state && (!media_state->topology || !generate_new_sdp)) {
1645 ast_sip_session_media_state_free(media_state);
1646 return -1;
2180 int res;
2181 SCOPE_ENTER(3, "%s: New SDP? %s Queued? %s DP: %s DA: %s\n", ast_sip_session_get_name(session),
2182 generate_new_sdp ? "yes" : "no", queued ? "yes" : "no",
2183 pending_media_state ? ast_str_tmp(256, ast_stream_topology_to_str(pending_media_state->topology, &STR_TMP)) : "none",
2184 active_media_state ? ast_str_tmp(256, ast_stream_topology_to_str(active_media_state->topology, &STR_TMP)) : "none");
2185
2186 if (pending_media_state && (!pending_media_state->topology || !generate_new_sdp)) {
2187
2188 ast_sip_session_media_state_free(pending_media_state);
2189 ast_sip_session_media_state_free(active_media_state);
2190 SCOPE_EXIT_RTN_VALUE(-1, "%s: Not sending reinvite because %s%s\n", ast_sip_session_get_name(session),
2191 pending_media_state->topology == NULL ? "pending topology is null " : "",
2192 !generate_new_sdp ? "generate_new_sdp is false" : "");
16472193 }
16482194
16492195 if (inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
16502196 /* Don't try to do anything with a hung-up call */
1651 ast_debug(3, "Not sending reinvite to %s because of disconnected state...\n",
1652 ast_sorcery_object_get_id(session->endpoint));
1653 ast_sip_session_media_state_free(media_state);
1654 return 0;
2197 ast_sip_session_media_state_free(pending_media_state);
2198 ast_sip_session_media_state_free(active_media_state);
2199 SCOPE_EXIT_RTN_VALUE(0, "%s: Not sending reinvite because of disconnected state\n",
2200 ast_sip_session_get_name(session));
16552201 }
16562202
16572203 /* If the dialog has not yet been established we have to defer until it has */
16582204 if (inv_session->dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {
1659 ast_debug(3, "Delay sending request to %s because dialog has not been established...\n",
1660 ast_sorcery_object_get_id(session->endpoint));
1661 return delay_request(session, on_request_creation, on_sdp_creation, on_response,
2205 res = delay_request(session, on_request_creation, on_sdp_creation, on_response,
16622206 generate_new_sdp,
16632207 method == AST_SIP_SESSION_REFRESH_METHOD_INVITE
16642208 ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE,
1665 media_state);
2209 pending_media_state, active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);
2210 SCOPE_EXIT_RTN_VALUE(res, "%s: Delay sending reinvite because dialog has not been established\n",
2211 ast_sip_session_get_name(session));
16662212 }
16672213
16682214 if (method == AST_SIP_SESSION_REFRESH_METHOD_INVITE) {
16692215 if (inv_session->invite_tsx) {
16702216 /* We can't send a reinvite yet, so delay it */
1671 ast_debug(3, "Delay sending reinvite to %s because of outstanding transaction...\n",
1672 ast_sorcery_object_get_id(session->endpoint));
1673 return delay_request(session, on_request_creation, on_sdp_creation,
1674 on_response, generate_new_sdp, DELAYED_METHOD_INVITE, media_state);
2217 res = delay_request(session, on_request_creation, on_sdp_creation,
2218 on_response, generate_new_sdp, DELAYED_METHOD_INVITE, pending_media_state,
2219 active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);
2220 SCOPE_EXIT_RTN_VALUE(res, "%s: Delay sending reinvite because of outstanding transaction\n",
2221 ast_sip_session_get_name(session));
16752222 } else if (inv_session->state != PJSIP_INV_STATE_CONFIRMED) {
16762223 /* Initial INVITE transaction failed to progress us to a confirmed state
16772224 * which means re-invites are not possible
16782225 */
1679 ast_debug(3, "Not sending reinvite to %s because not in confirmed state...\n",
1680 ast_sorcery_object_get_id(session->endpoint));
1681 ast_sip_session_media_state_free(media_state);
1682 return 0;
2226 ast_sip_session_media_state_free(pending_media_state);
2227 ast_sip_session_media_state_free(active_media_state);
2228 SCOPE_EXIT_RTN_VALUE(0, "%s: Not sending reinvite because not in confirmed state\n",
2229 ast_sip_session_get_name(session));
16832230 }
16842231 }
16852232
16882235 if (inv_session->neg
16892236 && pjmedia_sdp_neg_get_state(inv_session->neg)
16902237 != PJMEDIA_SDP_NEG_STATE_DONE) {
1691 ast_debug(3, "Delay session refresh with new SDP to %s because SDP negotiation is not yet done...\n",
1692 ast_sorcery_object_get_id(session->endpoint));
1693 return delay_request(session, on_request_creation, on_sdp_creation,
2238 res = delay_request(session, on_request_creation, on_sdp_creation,
16942239 on_response, generate_new_sdp,
16952240 method == AST_SIP_SESSION_REFRESH_METHOD_INVITE
1696 ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE, media_state);
2241 ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE, pending_media_state,
2242 active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);
2243 SCOPE_EXIT_RTN_VALUE(res, "%s: Delay session refresh with new SDP because SDP negotiation is not yet done\n",
2244 ast_sip_session_get_name(session));
16972245 }
16982246
16992247 /* If an explicitly requested media state has been provided use it instead of any pending one */
1700 if (media_state) {
2248 if (pending_media_state) {
17012249 int index;
17022250 int type_streams[AST_MEDIA_TYPE_END] = {0};
1703 struct ast_stream *stream;
2251 int topology_change_request = 0;
2252
2253 ast_trace(-1, "%s: Pending media state exists\n", ast_sip_session_get_name(session));
17042254
17052255 /* Media state conveys a desired media state, so if there are outstanding
17062256 * delayed requests we need to ensure we go into the queue and not jump
17082258 * order.
17092259 */
17102260 if (!queued && !AST_LIST_EMPTY(&session->delayed_requests)) {
1711 ast_debug(3, "Delay sending reinvite to %s because of outstanding requests...\n",
1712 ast_sorcery_object_get_id(session->endpoint));
1713 return delay_request(session, on_request_creation, on_sdp_creation,
2261 res = delay_request(session, on_request_creation, on_sdp_creation,
17142262 on_response, generate_new_sdp,
17152263 method == AST_SIP_SESSION_REFRESH_METHOD_INVITE
1716 ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE, media_state);
2264 ? DELAYED_METHOD_INVITE : DELAYED_METHOD_UPDATE, pending_media_state,
2265 active_media_state ? active_media_state : ast_sip_session_media_state_clone(session->active_media_state), queued);
2266 SCOPE_EXIT_RTN_VALUE(res, "%s: Delay sending reinvite because of outstanding requests\n",
2267 ast_sip_session_get_name(session));
2268 }
2269
2270 if (active_media_state) {
2271 struct ast_sip_session_media_state *new_pending_state;
2272 /*
2273 * We need to check if the passed in active and pending states are equal
2274 * before we run the media states resolver. We'll use the flag later
2275 * to signal whether this was topology change or some other change such
2276 * as a connected line change.
2277 */
2278 topology_change_request = !ast_stream_topology_equal(active_media_state->topology, pending_media_state->topology);
2279
2280 ast_trace(-1, "%s: Active media state exists and is%s equal to pending\n", ast_sip_session_get_name(session),
2281 topology_change_request ? " not" : "");
2282 ast_trace(-1, "%s: DP: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(pending_media_state->topology, &STR_TMP)));
2283 ast_trace(-1, "%s: DA: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(active_media_state->topology, &STR_TMP)));
2284 ast_trace(-1, "%s: CP: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(session->pending_media_state->topology, &STR_TMP)));
2285 ast_trace(-1, "%s: CA: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(session->active_media_state->topology, &STR_TMP)));
2286
2287 new_pending_state = resolve_refresh_media_states(ast_sip_session_get_name(session),
2288 pending_media_state, active_media_state, session->active_media_state, 1);
2289 if (new_pending_state) {
2290 ast_trace(-1, "%s: NP: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(new_pending_state->topology, &STR_TMP)));
2291 ast_sip_session_media_state_free(pending_media_state);
2292 pending_media_state = new_pending_state;
2293 } else {
2294 ast_sip_session_media_state_reset(pending_media_state);
2295 ast_sip_session_media_state_free(active_media_state);
2296 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Unable to merge media states\n", ast_sip_session_get_name(session));
2297 }
17172298 }
17182299
17192300 /* Prune the media state so the number of streams fit within the configured limits - we do it here
17212302 * of the SDP when producing it we'd be in trouble. We also enforce formats here for media types that
17222303 * are configurable on the endpoint.
17232304 */
1724 for (index = 0; index < ast_stream_topology_get_count(media_state->topology); ++index) {
2305 ast_trace(-1, "%s: Pruning and checking formats of streams\n", ast_sip_session_get_name(session));
2306
2307 for (index = 0; index < ast_stream_topology_get_count(pending_media_state->topology); ++index) {
17252308 struct ast_stream *existing_stream = NULL;
1726
1727 stream = ast_stream_topology_get_stream(media_state->topology, index);
2309 struct ast_stream *stream = ast_stream_topology_get_stream(pending_media_state->topology, index);
2310 SCOPE_ENTER(4, "%s: Checking stream %s\n", ast_sip_session_get_name(session),
2311 ast_stream_get_name(stream));
17282312
17292313 if (session->active_media_state->topology &&
17302314 index < ast_stream_topology_get_count(session->active_media_state->topology)) {
17312315 existing_stream = ast_stream_topology_get_stream(session->active_media_state->topology, index);
2316 ast_trace(-1, "%s: Found existing stream %s\n", ast_sip_session_get_name(session),
2317 ast_stream_get_name(existing_stream));
17322318 }
17332319
17342320 if (is_stream_limitation_reached(ast_stream_get_type(stream), session->endpoint, type_streams)) {
1735 if (index < AST_VECTOR_SIZE(&media_state->sessions)) {
1736 struct ast_sip_session_media *session_media = AST_VECTOR_GET(&media_state->sessions, index);
2321 if (index < AST_VECTOR_SIZE(&pending_media_state->sessions)) {
2322 struct ast_sip_session_media *session_media = AST_VECTOR_GET(&pending_media_state->sessions, index);
17372323
17382324 ao2_cleanup(session_media);
1739 AST_VECTOR_REMOVE(&media_state->sessions, index, 1);
2325 AST_VECTOR_REMOVE(&pending_media_state->sessions, index, 1);
17402326 }
17412327
1742 ast_stream_topology_del_stream(media_state->topology, index);
2328 ast_stream_topology_del_stream(pending_media_state->topology, index);
2329 ast_trace(-1, "%s: Dropped overlimit stream %s\n", ast_sip_session_get_name(session),
2330 ast_stream_get_name(stream));
17432331
17442332 /* A stream has potentially moved into our spot so we need to jump back so we process it */
17452333 index -= 1;
1746 continue;
2334 SCOPE_EXIT_EXPR(continue);
17472335 }
17482336
17492337 /* No need to do anything with stream if it's media state is removed */
17502338 if (ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED) {
17512339 /* If there is no existing stream we can just not have this stream in the topology at all. */
17522340 if (!existing_stream) {
1753 ast_stream_topology_del_stream(media_state->topology, index);
2341 ast_trace(-1, "%s: Dropped removed stream %s\n", ast_sip_session_get_name(session),
2342 ast_stream_get_name(stream));
2343 ast_stream_topology_del_stream(pending_media_state->topology, index);
2344 /* TODO: Do we need to remove the corresponding media state? */
17542345 index -= 1;
17552346 }
1756 continue;
2347 SCOPE_EXIT_EXPR(continue);
17572348 }
17582349
17592350 /* Enforce the configured allowed codecs on audio and video streams */
17632354
17642355 joint_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
17652356 if (!joint_cap) {
1766 ast_sip_session_media_state_free(media_state);
1767 return 0;
2357 ast_sip_session_media_state_free(pending_media_state);
2358 ast_sip_session_media_state_free(active_media_state);
2359 res = -1;
2360 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Unable to alloc format caps\n", ast_sip_session_get_name(session));
17682361 }
17692362 ast_format_cap_get_compatible(ast_stream_get_formats(stream), session->endpoint->media.codecs, joint_cap);
17702363 if (!ast_format_cap_count(joint_cap)) {
17742367 /* If there is no existing stream we can just not have this stream in the topology
17752368 * at all.
17762369 */
1777 ast_stream_topology_del_stream(media_state->topology, index);
2370 ast_stream_topology_del_stream(pending_media_state->topology, index);
17782371 index -= 1;
1779 continue;
2372 SCOPE_EXIT_EXPR(continue, "%s: Dropped incompatible stream %s\n",
2373 ast_sip_session_get_name(session), ast_stream_get_name(stream));
17802374 } else if (ast_stream_get_state(stream) != ast_stream_get_state(existing_stream) ||
17812375 strcmp(ast_stream_get_name(stream), ast_stream_get_name(existing_stream))) {
17822376 /* If the underlying stream is a different type or different name then we have to
17842378 * is preserved.
17852379 */
17862380 ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED);
1787 continue;
2381 SCOPE_EXIT_EXPR(continue, "%s: Dropped incompatible stream %s\n",
2382 ast_sip_session_get_name(session), ast_stream_get_name(stream));
17882383 } else {
17892384 /* However if the stream is otherwise remaining the same we can keep the formats
17902385 * that exist on it already which allows media to continue to flow. We don't modify
17992394 }
18002395
18012396 ++type_streams[ast_stream_get_type(stream)];
2397
2398 SCOPE_EXIT();
18022399 }
18032400
18042401 if (session->active_media_state->topology) {
18072404 * streams than are currently present we fill in the topology to match the current number of streams
18082405 * that are active.
18092406 */
1810 for (index = ast_stream_topology_get_count(media_state->topology);
2407
2408 for (index = ast_stream_topology_get_count(pending_media_state->topology);
18112409 index < ast_stream_topology_get_count(session->active_media_state->topology); ++index) {
2410 struct ast_stream *stream = ast_stream_topology_get_stream(session->active_media_state->topology, index);
18122411 struct ast_stream *cloned;
1813
1814 stream = ast_stream_topology_get_stream(session->active_media_state->topology, index);
1815 ast_assert(stream != NULL);
2412 int position;
2413 SCOPE_ENTER(4, "%s: Stream %s not in pending\n", ast_sip_session_get_name(session),
2414 ast_stream_get_name(stream));
18162415
18172416 cloned = ast_stream_clone(stream, NULL);
18182417 if (!cloned) {
1819 ast_sip_session_media_state_free(media_state);
1820 return -1;
2418 ast_sip_session_media_state_free(pending_media_state);
2419 ast_sip_session_media_state_free(active_media_state);
2420 res = -1;
2421 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Unable to clone stream %s\n",
2422 ast_sip_session_get_name(session), ast_stream_get_name(stream));
18212423 }
18222424
18232425 ast_stream_set_state(cloned, AST_STREAM_STATE_REMOVED);
1824 if (ast_stream_topology_append_stream(media_state->topology, cloned) < 0) {
2426 position = ast_stream_topology_append_stream(pending_media_state->topology, cloned);
2427 if (position < 0) {
18252428 ast_stream_free(cloned);
1826 ast_sip_session_media_state_free(media_state);
1827 return -1;
2429 ast_sip_session_media_state_free(pending_media_state);
2430 ast_sip_session_media_state_free(active_media_state);
2431 res = -1;
2432 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Unable to append cloned stream\n",
2433 ast_sip_session_get_name(session));
18282434 }
2435 SCOPE_EXIT("%s: Appended empty stream in position %d to make counts match\n",
2436 ast_sip_session_get_name(session), position);
18292437 }
18302438
1831 /* If the resulting media state matches the existing active state don't bother doing a session refresh */
1832 if (ast_stream_topology_equal(session->active_media_state->topology, media_state->topology)) {
1833 ast_sip_session_media_state_free(media_state);
2439 /*
2440 * We can suppress this re-invite if the pending topology is equal to the currently
2441 * active topology but only if this re-invite was the result of a requested topology
2442 * change. If it was the result of some other change, like connected line, then
2443 * we don't want to suppress it even though the topologies are equal.
2444 */
2445 if (topology_change_request && ast_stream_topology_equal(session->active_media_state->topology, pending_media_state->topology)) {
2446 ast_trace(-1, "%s: CA: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(session->active_media_state->topology, &STR_TMP)));
2447 ast_trace(-1, "%s: NP: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(pending_media_state->topology, &STR_TMP)));
2448 ast_sip_session_media_state_free(pending_media_state);
2449 ast_sip_session_media_state_free(active_media_state);
18342450 /* For external consumers we return 0 to say success, but internally for
18352451 * send_delayed_request we return a separate value to indicate that this
18362452 * session refresh would be redundant so we didn't send it
18372453 */
1838 return queued ? 1 : 0;
2454 SCOPE_EXIT_RTN_VALUE(queued ? 1 : 0, "%s: Topologies are equal. Not sending re-invite\n",
2455 ast_sip_session_get_name(session));
18392456 }
18402457 }
18412458
18422459 ast_sip_session_media_state_free(session->pending_media_state);
1843 session->pending_media_state = media_state;
2460 session->pending_media_state = pending_media_state;
18442461 }
18452462
18462463 new_sdp = generate_session_refresh_sdp(session);
18472464 if (!new_sdp) {
1848 ast_log(LOG_ERROR, "Failed to generate session refresh SDP. Not sending session refresh\n");
18492465 ast_sip_session_media_state_reset(session->pending_media_state);
1850 return -1;
2466 ast_sip_session_media_state_free(active_media_state);
2467 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Failed to generate session refresh SDP. Not sending session refresh\n",
2468 ast_sip_session_get_name(session));
18512469 }
18522470 if (on_sdp_creation) {
18532471 if (on_sdp_creation(session, new_sdp)) {
18542472 ast_sip_session_media_state_reset(session->pending_media_state);
1855 return -1;
2473 ast_sip_session_media_state_free(active_media_state);
2474 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: on_sdp_creation failed\n", ast_sip_session_get_name(session));
18562475 }
18572476 }
18582477 }
18592478
18602479 if (method == AST_SIP_SESSION_REFRESH_METHOD_INVITE) {
18612480 if (pjsip_inv_reinvite(inv_session, NULL, new_sdp, &tdata)) {
1862 ast_log(LOG_WARNING, "Failed to create reinvite properly.\n");
18632481 if (generate_new_sdp) {
18642482 ast_sip_session_media_state_reset(session->pending_media_state);
18652483 }
1866 return -1;
2484 ast_sip_session_media_state_free(active_media_state);
2485 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Failed to create reinvite properly\n", ast_sip_session_get_name(session));
18672486 }
18682487 } else if (pjsip_inv_update(inv_session, NULL, new_sdp, &tdata)) {
1869 ast_log(LOG_WARNING, "Failed to create UPDATE properly.\n");
18702488 if (generate_new_sdp) {
18712489 ast_sip_session_media_state_reset(session->pending_media_state);
18722490 }
1873 return -1;
2491 ast_sip_session_media_state_free(active_media_state);
2492 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: Failed to create UPDATE properly\n", ast_sip_session_get_name(session));
18742493 }
18752494 if (on_request_creation) {
18762495 if (on_request_creation(session, tdata)) {
18772496 if (generate_new_sdp) {
18782497 ast_sip_session_media_state_reset(session->pending_media_state);
18792498 }
1880 return -1;
1881 }
1882 }
1883 ast_debug(3, "Sending session refresh SDP via %s to %s\n",
1884 method == AST_SIP_SESSION_REFRESH_METHOD_INVITE ? "re-INVITE" : "UPDATE",
1885 ast_sorcery_object_get_id(session->endpoint));
2499 ast_sip_session_media_state_free(active_media_state);
2500 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: on_request_creation failed.\n", ast_sip_session_get_name(session));
2501 }
2502 }
18862503 ast_sip_session_send_request_with_cb(session, tdata, on_response);
1887 return 0;
2504 ast_sip_session_media_state_free(active_media_state);
2505
2506 end:
2507 SCOPE_EXIT_RTN_VALUE(res, "%s: Sending session refresh SDP via %s\n", ast_sip_session_get_name(session),
2508 method == AST_SIP_SESSION_REFRESH_METHOD_INVITE ? "re-INVITE" : "UPDATE");
18882509 }
18892510
18902511 int ast_sip_session_refresh(struct ast_sip_session *session,
18952516 struct ast_sip_session_media_state *media_state)
18962517 {
18972518 return sip_session_refresh(session, on_request_creation, on_sdp_creation,
1898 on_response, method, generate_new_sdp, media_state, 0);
2519 on_response, method, generate_new_sdp, media_state, NULL, 0);
18992520 }
19002521
19012522 int ast_sip_session_regenerate_answer(struct ast_sip_session *session,
20572678
20582679 handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
20592680 if (!handler_list) {
2060 ast_debug(1, "No registered SDP handlers for media type '%s'\n", media);
2681 ast_debug(3, "%s: No registered SDP handlers for media type '%s'\n", ast_sip_session_get_name(session), media);
20612682 continue;
20622683 }
20632684 AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
21022723 !(dlg = pjsip_ua_find_dialog(&rdata->msg_info.cid->id, &rdata->msg_info.to->tag, &rdata->msg_info.from->tag, PJ_FALSE)) ||
21032724 !(session = ast_sip_dialog_get_session(dlg)) ||
21042725 !session->channel) {
2726 return PJ_FALSE;
2727 }
2728
2729 if (session->inv_session->invite_tsx) {
2730 /* There's a transaction in progress so bail now and let pjproject send 491 */
21052731 return PJ_FALSE;
21062732 }
21072733
22212847 .on_rx_request = session_reinvite_on_rx_request,
22222848 };
22232849
2224
22252850 void ast_sip_session_send_request_with_cb(struct ast_sip_session *session, pjsip_tx_data *tdata,
22262851 ast_sip_session_response_cb on_response)
22272852 {
23082933 struct ast_sip_session *session = obj;
23092934 struct ast_sip_session_delayed_request *delay;
23102935
2936 #ifdef TEST_FRAMEWORK
23112937 /* We dup the endpoint ID in case the endpoint gets freed out from under us */
23122938 const char *endpoint_name = session->endpoint ?
23132939 ast_strdupa(ast_sorcery_object_get_id(session->endpoint)) : "<none>";
2314
2315 ast_debug(3, "Destroying SIP session with endpoint %s\n", endpoint_name);
2940 #endif
2941
2942 ast_debug(3, "%s: Destroying SIP session\n", ast_sip_session_get_name(session));
23162943
23172944 ast_test_suite_event_notify("SESSION_DESTROYING",
23182945 "Endpoint: %s\r\n"
24733100 return NULL;
24743101 }
24753102
3103 /* Track the number of challenges received on outbound requests */
3104 session->authentication_challenge_count = 0;
3105
24763106 /* Fire seesion begin handlers */
24773107 handle_session_begin(session);
24783108
26293259 }
26303260
26313261 inv = pjsip_dlg_get_inv_session(dlg);
3262 session = inv->mod_data[session_module.id];
3263
26323264 if (PJSIP_INV_STATE_CONFIRMED <= inv->state) {
26333265 /*
26343266 * We cannot handle reINVITE authentication at this
26353267 * time because the reINVITE transaction is still in
26363268 * progress.
26373269 */
2638 ast_debug(1, "A reINVITE is being challenged.\n");
3270 ast_debug(3, "%s: A reINVITE is being challenged\n", ast_sip_session_get_name(session));
26393271 return PJ_FALSE;
26403272 }
2641 ast_debug(1, "Initial INVITE is being challenged.\n");
2642
2643 session = inv->mod_data[session_module.id];
3273 ast_debug(3, "%s: Initial INVITE is being challenged.\n", ast_sip_session_get_name(session));
3274
3275 if (++session->authentication_challenge_count > MAX_RX_CHALLENGES) {
3276 ast_debug(3, "%s: Initial INVITE reached maximum number of auth attempts.\n", ast_sip_session_get_name(session));
3277 return PJ_FALSE;
3278 }
26443279
26453280 if (ast_sip_create_request_with_auth(&session->endpoint->outbound_auths, rdata,
26463281 tsx->last_tx, &tdata)) {
28913526 break;
28923527 case PJSIP_INV_STATE_CONFIRMED:
28933528 if (session->inv_session->invite_tsx) {
2894 ast_debug(3, "Delay sending BYE to %s because of outstanding transaction...\n",
2895 ast_sorcery_object_get_id(session->endpoint));
3529 ast_debug(3, "%s: Delay sending BYE because of outstanding transaction...\n",
3530 ast_sip_session_get_name(session));
28963531 /* If this is delayed the only thing that will happen is a BYE request so we don't
28973532 * actually need to store the response code for when it happens.
28983533 */
2899 delay_request(session, NULL, NULL, NULL, 0, DELAYED_METHOD_BYE, NULL);
3534 delay_request(session, NULL, NULL, NULL, 0, DELAYED_METHOD_BYE, NULL, NULL, 1);
29003535 break;
29013536 }
29023537 /* Fall through */
30143649
30153650 if (session->ended_while_deferred) {
30163651 /* Complete the session end started by the remote hangup. */
3017 ast_debug(3, "Ending session (%p) after being deferred\n", session);
3652 ast_debug(3, "%s: Ending session after being deferred\n", ast_sip_session_get_name(session));
30183653 session->ended_while_deferred = 0;
30193654 session_end(session);
30203655 }
30783713
30793714 pickup_cfg = ast_get_chan_features_pickup_config(session->channel);
30803715 if (!pickup_cfg) {
3081 ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
3716 ast_log(LOG_ERROR, "%s: Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n",
3717 ast_sip_session_get_name(session));
30823718 pickupexten = "";
30833719 } else {
30843720 pickupexten = ast_strdupa(pickup_cfg->pickupexten);
31153751 return SIP_GET_DEST_EXTEN_NOT_FOUND;
31163752 }
31173753
3754 /*
3755 * /internal
3756 * /brief Process initial answer for an incoming invite
3757 *
3758 * This function should only be called during the setup, and handling of a
3759 * new incoming invite. Most, if not all of the time, this will be called
3760 * when an error occurs and we need to respond as such.
3761 *
3762 * When a SIP session termination code is given for the answer it's assumed
3763 * this call then will be the final bit of processing before ending session
3764 * setup. As such, we've been holding a lock, and a reference on the invite
3765 * session's dialog. So before returning this function removes that reference,
3766 * and unlocks the dialog.
3767 *
3768 * \param inv_session The session on which to answer
3769 * \param rdata The original request
3770 * \param answer_code The answer's numeric code
3771 * \param terminate_code The termination code if the answer fails
3772 * \param notify Whether or not to call on_state_changed
3773 *
3774 * \retval 0 if invite successfully answered, -1 if an error occurred
3775 */
3776 static int new_invite_initial_answer(pjsip_inv_session *inv_session, pjsip_rx_data *rdata,
3777 int answer_code, int terminate_code, pj_bool_t notify)
3778 {
3779 pjsip_tx_data *tdata = NULL;
3780 int res = 0;
3781
3782 if (inv_session->state != PJSIP_INV_STATE_DISCONNECTED) {
3783 if (pjsip_inv_initial_answer(
3784 inv_session, rdata, answer_code, NULL, NULL, &tdata) != PJ_SUCCESS) {
3785
3786 pjsip_inv_terminate(inv_session, terminate_code ? terminate_code : answer_code, notify);
3787 res = -1;
3788 } else {
3789 pjsip_inv_send_msg(inv_session, tdata);
3790 }
3791 }
3792
3793 if (answer_code >= 300) {
3794 /*
3795 * A session is ending. The dialog has a reference that needs to be
3796 * removed and holds a lock that needs to be unlocked before returning.
3797 */
3798 pjsip_dlg_dec_lock(inv_session->dlg);
3799 }
3800
3801 return res;
3802 }
3803
3804 /*
3805 * /internal
3806 * /brief Create and initialize a pjsip invite session
3807
3808 * pjsip_inv_session adds, and maintains a reference to the dialog upon a successful
3809 * invite session creation until the session is destroyed. However, we'll wait to
3810 * remove the reference that was added for the dialog when it gets created since we're
3811 * not ready to unlock the dialog in this function.
3812 *
3813 * So, if this function successfully returns that means it returns with its newly
3814 * created, and associated dialog locked and with two references (i.e. dialog's
3815 * reference count should be 2).
3816 *
3817 * \param endpoint A pointer to the endpoint
3818 * \param rdata The request that is starting the dialog
3819 *
3820 * \retval A pjsip invite session object
3821 * \retval NULL on error
3822 */
31183823 static pjsip_inv_session *pre_session_setup(pjsip_rx_data *rdata, const struct ast_sip_endpoint *endpoint)
31193824 {
31203825 pjsip_tx_data *tdata;
31213826 pjsip_dialog *dlg;
31223827 pjsip_inv_session *inv_session;
31233828 unsigned int options = endpoint->extensions.flags;
3124 pj_status_t dlg_status;
3829 pj_status_t dlg_status = PJ_EUNKNOWN;
31253830
31263831 if (pjsip_inv_verify_request(rdata, &options, NULL, NULL, ast_sip_get_pjsip_endpoint(), &tdata) != PJ_SUCCESS) {
31273832 if (tdata) {
31333838 }
31343839 return NULL;
31353840 }
3136 dlg = ast_sip_create_dialog_uas(endpoint, rdata, &dlg_status);
3841
3842 dlg = ast_sip_create_dialog_uas_locked(endpoint, rdata, &dlg_status);
31373843 if (!dlg) {
31383844 if (dlg_status != PJ_EEXISTS) {
31393845 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
31403846 }
31413847 return NULL;
31423848 }
3849
3850 /*
3851 * The returned dialog holds a lock and has a reference added. Any paths where the
3852 * dialog invite session is not returned must unlock the dialog and remove its reference.
3853 */
3854
31433855 if (pjsip_inv_create_uas(dlg, rdata, NULL, options, &inv_session) != PJ_SUCCESS) {
31443856 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
3857 /*
3858 * The acquired dialog holds a lock, and a reference. Since the dialog is not
3859 * going to be returned here it must first be unlocked and de-referenced. This
3860 * must be done prior to calling dialog termination.
3861 */
3862 pjsip_dlg_dec_lock(dlg);
31453863 pjsip_dlg_terminate(dlg);
31463864 return NULL;
31473865 }
31503868 inv_session->sdp_neg_flags = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE;
31513869 #endif
31523870 if (pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS) {
3153 if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) != PJ_SUCCESS) {
3154 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3155 }
3156 pjsip_inv_send_msg(inv_session, tdata);
3871 /* Dialog's lock and a reference are removed in new_invite_initial_answer */
3872 new_invite_initial_answer(inv_session, rdata, 500, 500, PJ_FALSE);
3873 /* Remove 2nd reference added at inv_session creation */
3874 pjsip_dlg_dec_session(inv_session->dlg, &session_module);
31573875 return NULL;
31583876 }
3877
31593878 return inv_session;
31603879 }
31613880
32303949 pjsip_rdata_sdp_info *sdp_info;
32313950 pjmedia_sdp_session *local = NULL;
32323951 char buffer[AST_SOCKADDR_BUFLEN];
3952 SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(invite->session));
3953
32333954
32343955 /* From this point on, any calls to pjsip_inv_terminate have the last argument as PJ_TRUE
32353956 * so that we will be notified so we can destroy the session properly
32363957 */
32373958
32383959 if (invite->session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
3239 ast_log(LOG_ERROR, "Session already DISCONNECTED [reason=%d (%s)]\n",
3960 ast_trace_log(-1, LOG_ERROR, "%s: Session already DISCONNECTED [reason=%d (%s)]\n",
3961 ast_sip_session_get_name(invite->session),
32403962 invite->session->inv_session->cause,
32413963 pjsip_get_status_text(invite->session->inv_session->cause)->ptr);
32423964 #ifdef HAVE_PJSIP_INV_SESSION_REF
32433965 pjsip_inv_dec_ref(invite->session->inv_session);
32443966 #endif
3245 return -1;
3967 SCOPE_EXIT_RTN_VALUE(-1);
32463968 }
32473969
32483970 switch (get_destination(invite->session, invite->rdata)) {
32503972 /* Things worked. Keep going */
32513973 break;
32523974 case SIP_GET_DEST_UNSUPPORTED_URI:
3975 ast_trace(-1, "%s: Call (%s:%s) to extension '%s' - unsupported uri\n",
3976 ast_sip_session_get_name(invite->session),
3977 invite->rdata->tp_info.transport->type_name,
3978 pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),
3979 invite->session->exten);
32533980 if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 416, NULL, NULL, &tdata) == PJ_SUCCESS) {
32543981 ast_sip_session_send_response(invite->session, tdata);
32553982 } else {
32573984 }
32583985 goto end;
32593986 case SIP_GET_DEST_EXTEN_PARTIAL:
3260 ast_debug(1, "Call from '%s' (%s:%s) to extension '%s' - partial match\n",
3261 ast_sorcery_object_get_id(invite->session->endpoint),
3987 ast_trace(-1, "%s: Call (%s:%s) to extension '%s' - partial match\n",
3988 ast_sip_session_get_name(invite->session),
32623989 invite->rdata->tp_info.transport->type_name,
32633990 pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),
32643991 invite->session->exten);
32713998 goto end;
32723999 case SIP_GET_DEST_EXTEN_NOT_FOUND:
32734000 default:
3274 ast_log(LOG_NOTICE, "Call from '%s' (%s:%s) to extension '%s' rejected because extension not found in context '%s'.\n",
3275 ast_sorcery_object_get_id(invite->session->endpoint),
4001 ast_trace_log(-1, LOG_NOTICE, "%s: Call (%s:%s) to extension '%s' rejected because extension not found in context '%s'.\n",
4002 ast_sip_session_get_name(invite->session),
32764003 invite->rdata->tp_info.transport->type_name,
32774004 pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),
32784005 invite->session->exten,
33054032 * so let's go ahead and send a 100 Trying out to stop any
33064033 * retransmissions.
33074034 */
4035 ast_trace(-1, "%s: Call (%s:%s) to extension '%s' sending 100 Trying\n",
4036 ast_sip_session_get_name(invite->session),
4037 invite->rdata->tp_info.transport->type_name,
4038 pj_sockaddr_print(&invite->rdata->pkt_info.src_addr, buffer, sizeof(buffer), 3),
4039 invite->session->exten);
33084040 if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 100, NULL, NULL, &tdata) != PJ_SUCCESS) {
33094041 pjsip_inv_terminate(invite->session->inv_session, 500, PJ_TRUE);
33104042 goto end;
33524084 #ifdef HAVE_PJSIP_INV_SESSION_REF
33534085 pjsip_inv_dec_ref(invite->session->inv_session);
33544086 #endif
3355 return 0;
4087 SCOPE_EXIT_RTN_VALUE(0, "%s\n", ast_sip_session_get_name(invite->session));
33564088 }
33574089
33584090 static void handle_new_invite_request(pjsip_rx_data *rdata)
33594091 {
33604092 RAII_VAR(struct ast_sip_endpoint *, endpoint,
33614093 ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup);
3362 pjsip_tx_data *tdata = NULL;
33634094 pjsip_inv_session *inv_session = NULL;
33644095 struct ast_sip_session *session;
33654096 struct new_invite invite;
33724103 return;
33734104 }
33744105
4106 /*
4107 * Upon a successful pre_session_setup the associated dialog is returned locked
4108 * and with an added reference. Well actually two references. One added when the
4109 * dialog itself was created, and another added when the pjsip invite session was
4110 * created and the dialog was added to it.
4111 *
4112 * In order to ensure the dialog's, and any of its internal attributes, lifetimes
4113 * we'll hold the lock and maintain the reference throughout the entire new invite
4114 * handling process. See ast_sip_create_dialog_uas_locked for more details but,
4115 * basically we do this to make sure a transport failure does not destroy the dialog
4116 * and/or transaction out from underneath us between pjsip calls. Alternatively, we
4117 * could probably release the lock if we needed to, but then we'd have to re-lock and
4118 * check the dialog and transaction prior to every pjsip call.
4119 *
4120 * That means any off nominal/failure paths in this function must remove the associated
4121 * dialog reference added at dialog creation, and remove the lock. As well the
4122 * referenced pjsip invite session must be "cleaned up", which should also then
4123 * remove its reference to the dialog at that time.
4124 *
4125 * Nominally we'll unlock the dialog, and release the reference when all new invite
4126 * process handling has successfully completed.
4127 */
4128
33754129 #ifdef HAVE_PJSIP_INV_SESSION_REF
33764130 if (pjsip_inv_add_ref(inv_session) != PJ_SUCCESS) {
33774131 ast_log(LOG_ERROR, "Can't increase the session reference counter\n");
3378 if (inv_session->state != PJSIP_INV_STATE_DISCONNECTED) {
3379 if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) {
3380 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3381 } else {
3382 pjsip_inv_send_msg(inv_session, tdata);
3383 }
4132 /* Dialog's lock and a reference are removed in new_invite_initial_answer */
4133 if (!new_invite_initial_answer(inv_session, rdata, 500, 500, PJ_FALSE)) {
4134 /* Terminate the session if it wasn't done in the answer */
4135 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
33844136 }
33854137 return;
33864138 }
33874139 #endif
3388
33894140 session = ast_sip_session_alloc(endpoint, NULL, inv_session, rdata);
33904141 if (!session) {
3391 if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) {
4142 /* Dialog's lock and reference are removed in new_invite_initial_answer */
4143 if (!new_invite_initial_answer(inv_session, rdata, 500, 500, PJ_FALSE)) {
4144 /* Terminate the session if it wasn't done in the answer */
33924145 pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
3393 } else {
3394 pjsip_inv_send_msg(inv_session, tdata);
3395 }
4146 }
4147
33964148 #ifdef HAVE_PJSIP_INV_SESSION_REF
33974149 pjsip_inv_dec_ref(inv_session);
33984150 #endif
34094161 invite.session = session;
34104162 invite.rdata = rdata;
34114163 new_invite(&invite);
4164
4165 /*
4166 * The dialog lock and reference added at dialog creation time must be
4167 * maintained throughout the new invite process. Since we're pretty much
4168 * done at this point with things it's safe to go ahead and remove the lock
4169 * and the reference here. See ast_sip_create_dialog_uas_locked for more info.
4170 *
4171 * Note, any future functionality added that does work using the dialog must
4172 * be done before this.
4173 */
4174 pjsip_dlg_dec_lock(inv_session->dlg);
34124175
34134176 ao2_ref(session, -1);
34144177 }
34884251 {
34894252 struct ast_sip_session *session = entry->user_data;
34904253
3491 ast_debug(3, "Endpoint '%s(%s)' re-INVITE collision timer expired.\n",
3492 ast_sorcery_object_get_id(session->endpoint),
3493 session->channel ? ast_channel_name(session->channel) : "");
4254 ast_debug(3, "%s: re-INVITE collision timer expired.\n",
4255 ast_sip_session_get_name(session));
34944256
34954257 if (AST_LIST_EMPTY(&session->delayed_requests)) {
34964258 /* No delayed request pending, so just return */
35104272 {
35114273 pjsip_inv_session *inv = session->inv_session;
35124274 pj_time_val tv;
3513
3514 ast_debug(3, "Endpoint '%s(%s)' re-INVITE collision.\n",
3515 ast_sorcery_object_get_id(session->endpoint),
3516 session->channel ? ast_channel_name(session->channel) : "");
3517 if (delay_request(session, NULL, NULL, on_response, 1, DELAYED_METHOD_INVITE, NULL)) {
3518 return;
3519 }
4275 struct ast_sip_session_media_state *pending_media_state;
4276 struct ast_sip_session_media_state *active_media_state;
4277 const char *session_name = ast_sip_session_get_name(session);
4278 SCOPE_ENTER(3, "%s\n", session_name);
4279
4280 pending_media_state = ast_sip_session_media_state_clone(session->pending_media_state);
4281 if (!pending_media_state) {
4282 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Failed to clone pending media state\n", session_name);
4283 }
4284
4285 active_media_state = ast_sip_session_media_state_clone(session->active_media_state);
4286 if (!active_media_state) {
4287 ast_sip_session_media_state_free(pending_media_state);
4288 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Failed to clone active media state\n", session_name);
4289 }
4290
4291 if (delay_request(session, NULL, NULL, on_response, 1, DELAYED_METHOD_INVITE, pending_media_state,
4292 active_media_state, 1)) {
4293 ast_sip_session_media_state_free(pending_media_state);
4294 ast_sip_session_media_state_free(active_media_state);
4295 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Failed to add delayed request\n", session_name);
4296 }
4297
35204298 if (pj_timer_entry_running(&session->rescheduled_reinvite)) {
35214299 /* Timer already running. Something weird is going on. */
3522 ast_debug(1, "Endpoint '%s(%s)' re-INVITE collision while timer running!!!\n",
3523 ast_sorcery_object_get_id(session->endpoint),
3524 session->channel ? ast_channel_name(session->channel) : "");
3525 return;
4300 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: re-INVITE collision while timer running!!!\n", session_name);
35264301 }
35274302
35284303 tv.sec = 0;
35374312 if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(),
35384313 &session->rescheduled_reinvite, &tv) != PJ_SUCCESS) {
35394314 ao2_ref(session, -1);
3540 }
4315 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Couldn't schedule timer\n", session_name);
4316 }
4317
4318 SCOPE_EXIT_RTN();
35414319 }
35424320
35434321 static void __print_debug_details(const char *function, pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e)
35954373 {
35964374 struct ast_sip_session_supplement *supplement;
35974375 struct pjsip_request_line req = rdata->msg_info.msg->line.req;
3598
3599 ast_debug(3, "Method is %.*s\n", (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name));
4376 SCOPE_ENTER(3, "%s: Method is %.*s\n", ast_sip_session_get_name(session), (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name));
4377
36004378 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
36014379 if (supplement->incoming_request && does_method_match(&req.method.name, supplement->method)) {
36024380 if (supplement->incoming_request(session, rdata)) {
36044382 }
36054383 }
36064384 }
4385
4386 SCOPE_EXIT("%s\n", ast_sip_session_get_name(session));
36074387 }
36084388
36094389 static void handle_session_begin(struct ast_sip_session *session)
36454425 {
36464426 struct ast_sip_session_supplement *supplement;
36474427 struct pjsip_status_line status = rdata->msg_info.msg->line.status;
3648
3649 ast_debug(3, "Response is %d %.*s\n", status.code, (int) pj_strlen(&status.reason),
3650 pj_strbuf(&status.reason));
4428 SCOPE_ENTER(3, "%s: Response is %d %.*s\n", ast_sip_session_get_name(session),
4429 status.code, (int) pj_strlen(&status.reason), pj_strbuf(&status.reason));
36514430
36524431 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
36534432 if (!(supplement->response_priority & response_priority)) {
36574436 supplement->incoming_response(session, rdata);
36584437 }
36594438 }
4439
4440 SCOPE_EXIT("%s\n", ast_sip_session_get_name(session));
36604441 }
36614442
36624443 static int handle_incoming(struct ast_sip_session *session, pjsip_rx_data *rdata,
36634444 enum ast_sip_session_response_priority response_priority)
36644445 {
3665 ast_debug(3, "Received %s\n", rdata->msg_info.msg->type == PJSIP_REQUEST_MSG ?
3666 "request" : "response");
3667
36684446 if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) {
36694447 handle_incoming_request(session, rdata);
36704448 } else {
36784456 {
36794457 struct ast_sip_session_supplement *supplement;
36804458 struct pjsip_request_line req = tdata->msg->line.req;
3681
3682 ast_debug(3, "Method is %.*s\n", (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name));
4459 SCOPE_ENTER(3, "%s: Method is %.*s\n", ast_sip_session_get_name(session),
4460 (int) pj_strlen(&req.method.name), pj_strbuf(&req.method.name));
4461
36834462 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
36844463 if (supplement->outgoing_request && does_method_match(&req.method.name, supplement->method)) {
36854464 supplement->outgoing_request(session, tdata);
36864465 }
36874466 }
4467 SCOPE_EXIT("%s\n", ast_sip_session_get_name(session));
36884468 }
36894469
36904470 static void handle_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
36924472 struct ast_sip_session_supplement *supplement;
36934473 struct pjsip_status_line status = tdata->msg->line.status;
36944474 pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
3695
3696 if (!cseq) {
3697 ast_log(LOG_ERROR, "Cannot send response due to missing sequence header");
3698 return;
3699 }
3700
3701 ast_debug(3, "Method is %.*s, Response is %d %.*s\n", (int) pj_strlen(&cseq->method.name),
4475 SCOPE_ENTER(3, "%s: Method is %.*s, Response is %d %.*s\n", ast_sip_session_get_name(session),
4476 (int) pj_strlen(&cseq->method.name),
37024477 pj_strbuf(&cseq->method.name), status.code, (int) pj_strlen(&status.reason),
37034478 pj_strbuf(&status.reason));
4479
4480
4481 if (!cseq) {
4482 SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Cannot send response due to missing sequence header",
4483 ast_sip_session_get_name(session));
4484 }
37044485
37054486 AST_LIST_TRAVERSE(&session->supplements, supplement, next) {
37064487 if (supplement->outgoing_response && does_method_match(&cseq->method.name, supplement->method)) {
37074488 supplement->outgoing_response(session, tdata);
37084489 }
37094490 }
4491
4492 SCOPE_EXIT("%s\n", ast_sip_session_get_name(session));
37104493 }
37114494
37124495 static int session_end(void *vsession)
37714554 struct ast_sip_session *session, pjsip_rx_data *rdata)
37724555 {
37734556 pjsip_msg *msg;
4557 ast_debug(3, "%s: Received %s\n", ast_sip_session_get_name(session), rdata->msg_info.msg->type == PJSIP_REQUEST_MSG ?
4558 "request" : "response");
4559
37744560
37754561 handle_incoming(session, rdata, AST_SIP_SESSION_BEFORE_MEDIA);
37764562 msg = rdata->msg_info.msg;
37864572 * SDP answer.
37874573 */
37884574 ast_debug(1,
3789 "Endpoint '%s(%s)': Ending session due to incomplete SDP negotiation. %s\n",
3790 ast_sorcery_object_get_id(session->endpoint),
3791 session->channel ? ast_channel_name(session->channel) : "",
4575 "%s: Ending session due to incomplete SDP negotiation. %s\n",
4576 ast_sip_session_get_name(session),
37924577 pjsip_rx_data_get_info(rdata));
37934578 if (pjsip_inv_end_session(inv, 400, NULL, &tdata) == PJ_SUCCESS
37944579 && tdata) {
38254610 handle_incoming_before_media(inv, session, e->body.rx_msg.rdata);
38264611 break;
38274612 case PJSIP_EVENT_TSX_STATE:
3828 ast_debug(3, "Source of transaction state change is %s\n", pjsip_event_str(e->body.tsx_state.type));
4613 ast_debug(3, "%s: Source of transaction state change is %s\n", ast_sip_session_get_name(session),
4614 pjsip_event_str(e->body.tsx_state.type));
38294615 /* Transaction state changes are prompted by some other underlying event. */
38304616 switch(e->body.tsx_state.type) {
38314617 case PJSIP_EVENT_TX_MSG:
38614647
38624648 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
38634649 if (session->defer_end) {
3864 ast_debug(3, "Deferring session (%p) end\n", session);
4650 ast_debug(3, "%s: Deferring session end\n", ast_sip_session_get_name(session));
38654651 session->ended_while_deferred = 1;
38664652 return;
38674653 }
39674753 return;
39684754 }
39694755 if (inv->state == PJSIP_INV_STATE_CONFIRMED) {
3970 ast_debug(1, "reINVITE received final response code %d\n",
4756 ast_debug(1, "%s: reINVITE received final response code %d\n",
4757 ast_sip_session_get_name(session),
39714758 tsx->status_code);
39724759 if ((tsx->status_code == 401 || tsx->status_code == 407)
4760 && ++session->authentication_challenge_count < MAX_RX_CHALLENGES
39734761 && !ast_sip_create_request_with_auth(
39744762 &session->endpoint->outbound_auths,
39754763 e->body.tsx_state.src.rdata, tsx->last_tx, &tdata)) {
40404828 pjsip_rx_data_get_info(e->body.tsx_state.src.rdata),
40414829 sdp_negotiation_done ? "complete" : "incomplete");
40424830 if (!sdp_negotiation_done) {
4043 ast_debug(1, "Endpoint '%s(%s)': Incomplete SDP negotiation cancelled session. %s\n",
4044 ast_sorcery_object_get_id(session->endpoint),
4045 session->channel ? ast_channel_name(session->channel) : "",
4831 ast_debug(1, "%s: Incomplete SDP negotiation cancelled session. %s\n",
4832 ast_sip_session_get_name(session),
40464833 pjsip_rx_data_get_info(e->body.tsx_state.src.rdata));
40474834 } else if (pjsip_inv_end_session(inv, 500, NULL, &tdata) == PJ_SUCCESS
40484835 && tdata) {
4049 ast_debug(1, "Endpoint '%s(%s)': Ending session due to RFC5407 race condition. %s\n",
4050 ast_sorcery_object_get_id(session->endpoint),
4051 session->channel ? ast_channel_name(session->channel) : "",
4836 ast_debug(1, "%s: Ending session due to RFC5407 race condition. %s\n",
4837 ast_sip_session_get_name(session),
40524838 pjsip_rx_data_get_info(e->body.tsx_state.src.rdata));
40534839 ast_sip_session_send_request(session, tdata);
40544840 }
40604846 if (tsx->role == PJSIP_ROLE_UAC) {
40614847 if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
40624848 /* This means we got a final response to our outgoing method */
4063 ast_debug(1, "%.*s received final response code %d\n",
4849 ast_debug(1, "%s: %.*s received final response code %d\n",
4850 ast_sip_session_get_name(session),
40644851 (int) pj_strlen(&tsx->method.name), pj_strbuf(&tsx->method.name),
40654852 tsx->status_code);
40664853 if ((tsx->status_code == 401 || tsx->status_code == 407)
4854 && ++session->authentication_challenge_count < MAX_RX_CHALLENGES
40674855 && !ast_sip_create_request_with_auth(
40684856 &session->endpoint->outbound_auths,
40694857 e->body.tsx_state.src.rdata, tsx->last_tx, &tdata)) {
41024890
41034891 if (tsx->method.id == PJSIP_INVITE_METHOD) {
41044892 if (tsx->state == PJSIP_TSX_STATE_PROCEEDING) {
4105 ast_debug(3, "Endpoint '%s(%s)' INVITE delay check. tsx-state:%s\n",
4106 ast_sorcery_object_get_id(session->endpoint),
4107 session->channel ? ast_channel_name(session->channel) : "",
4893 ast_debug(3, "%s: INVITE delay check. tsx-state:%s\n",
4894 ast_sip_session_get_name(session),
41084895 pjsip_tsx_state_str(tsx->state));
41094896 check_delayed_requests(session, invite_proceeding);
41104897 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
41134900 * queuing delayed requests, no matter what event caused
41144901 * the transaction to terminate.
41154902 */
4116 ast_debug(3, "Endpoint '%s(%s)' INVITE delay check. tsx-state:%s\n",
4117 ast_sorcery_object_get_id(session->endpoint),
4118 session->channel ? ast_channel_name(session->channel) : "",
4903 ast_debug(3, "%s: INVITE delay check. tsx-state:%s\n",
4904 ast_sip_session_get_name(session),
41194905 pjsip_tsx_state_str(tsx->state));
41204906 check_delayed_requests(session, invite_terminated);
41214907 }
41224908 } else if (tsx->role == PJSIP_ROLE_UAC
41234909 && tsx->state == PJSIP_TSX_STATE_COMPLETED
41244910 && !pj_strcmp2(&tsx->method.name, "UPDATE")) {
4125 ast_debug(3, "Endpoint '%s(%s)' UPDATE delay check. tsx-state:%s\n",
4126 ast_sorcery_object_get_id(session->endpoint),
4127 session->channel ? ast_channel_name(session->channel) : "",
4911 ast_debug(3, "%s: UPDATE delay check. tsx-state:%s\n",
4912 ast_sip_session_get_name(session),
41284913 pjsip_tsx_state_str(tsx->state));
41294914 check_delayed_requests(session, update_completed);
41304915 }
42605045 pjmedia_sdp_session *local;
42615046 int i;
42625047 int stream;
5048 SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
42635049
42645050 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
4265 ast_log(LOG_ERROR, "Failed to create session SDP. Session has been already disconnected\n");
4266 return NULL;
5051 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Failed to create session SDP. Session has been already disconnected\n",
5052 ast_sip_session_get_name(session));
42675053 }
42685054
42695055 if (!inv->pool_prov || !(local = PJ_POOL_ZALLOC_T(inv->pool_prov, pjmedia_sdp_session))) {
4270 return NULL;
5056 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Pool allocation failure\n", ast_sip_session_get_name(session));
42715057 }
42725058
42735059 if (!offer) {
42925078 session->pending_media_state->topology = ast_stream_topology_clone(session->endpoint->media.topology);
42935079 }
42945080 if (!session->pending_media_state->topology) {
4295 return NULL;
4296 }
4297 }
5081 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: No pending media state topology\n", ast_sip_session_get_name(session));
5082 }
5083 }
5084
5085 ast_trace(-1, "%s: Processing streams\n", ast_sip_session_get_name(session));
42985086
42995087 for (i = 0; i < ast_stream_topology_get_count(session->pending_media_state->topology); ++i) {
43005088 struct ast_sip_session_media *session_media;
4301 struct ast_stream *stream;
5089 struct ast_stream *stream = ast_stream_topology_get_stream(session->pending_media_state->topology, i);
43025090 unsigned int streams = local->media_count;
5091 SCOPE_ENTER(4, "%s: Processing stream %s\n", ast_sip_session_get_name(session),
5092 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
43035093
43045094 /* This code does not enforce any maximum stream count limitations as that is done on either
43055095 * the handling of an incoming SDP offer or on the handling of a session refresh.
43065096 */
43075097
4308 stream = ast_stream_topology_get_stream(session->pending_media_state->topology, i);
4309
43105098 session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_stream_get_type(stream), i);
43115099 if (!session_media) {
4312 return NULL;
5100 local = NULL;
5101 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't alloc/add session media for stream %s\n",
5102 ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
43135103 }
43145104
43155105 if (add_sdp_streams(session_media, session, local, offer, stream)) {
4316 return NULL;
5106 local = NULL;
5107 SCOPE_EXIT_LOG_EXPR(goto end, LOG_ERROR, "%s: Couldn't add sdp streams for stream %s\n",
5108 ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
43175109 }
43185110
43195111 /* If a stream was actually added then add any additional details */
43275119 attr = pjmedia_sdp_attr_create(inv->pool_prov, "mid", pj_cstr(&stmp, session_media->mid));
43285120 pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr);
43295121 }
5122
5123 ast_trace(-1, "%s: Stream %s added%s%s\n", ast_sip_session_get_name(session),
5124 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)),
5125 S_COR(!ast_strlen_zero(session_media->mid), " with mid ", ""), S_OR(session_media->mid, ""));
5126
43305127 }
43315128
43325129 /* Ensure that we never exceed the maximum number of streams PJMEDIA will allow. */
43335130 if (local->media_count == PJMEDIA_MAX_SDP_MEDIA) {
4334 break;
4335 }
5131 SCOPE_EXIT_EXPR(break, "%s: Stream %s exceeded max pjmedia count of %d\n",
5132 ast_sip_session_get_name(session), ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)),
5133 PJMEDIA_MAX_SDP_MEDIA);
5134 }
5135
5136 SCOPE_EXIT("%s: Done with %s\n", ast_sip_session_get_name(session),
5137 ast_str_tmp(128, ast_stream_to_str(stream, &STR_TMP)));
5138
43365139 }
43375140
43385141 /* Add any bundle groups that are present on the media state */
5142 ast_trace(-1, "%s: Adding bundle groups (if available)\n", ast_sip_session_get_name(session));
43395143 if (add_bundle_groups(session, inv->pool_prov, local)) {
4340 return NULL;
5144 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Couldn't add bundle groups\n", ast_sip_session_get_name(session));
43415145 }
43425146
43435147 /* Use the connection details of an available media if possible for SDP level */
5148 ast_trace(-1, "%s: Copying connection details\n", ast_sip_session_get_name(session));
5149
43445150 for (stream = 0; stream < local->media_count; stream++) {
5151 SCOPE_ENTER(4, "%s: Processing media %d\n", ast_sip_session_get_name(session), stream);
43455152 if (!local->media[stream]->conn) {
4346 continue;
5153 SCOPE_EXIT_EXPR(continue, "%s: Media %d has no connection info\n", ast_sip_session_get_name(session), stream);
43475154 }
43485155
43495156 if (local->conn) {
43525159 !pj_strcmp(&local->conn->addr, &local->media[stream]->conn->addr)) {
43535160 local->media[stream]->conn = NULL;
43545161 }
4355 continue;
5162 SCOPE_EXIT_EXPR(continue, "%s: Media %d has good existing connection info\n", ast_sip_session_get_name(session), stream);
43565163 }
43575164
43585165 /* This stream's connection info will serve as the connection details for SDP level */
43595166 local->conn = local->media[stream]->conn;
43605167 local->media[stream]->conn = NULL;
43615168
4362 continue;
5169 SCOPE_EXIT_EXPR(continue, "%s: Media %d reset\n", ast_sip_session_get_name(session), stream);
43635170 }
43645171
43655172 /* If no SDP level connection details are present then create some */
43665173 if (!local->conn) {
5174 ast_trace(-1, "%s: Creating connection details\n", ast_sip_session_get_name(session));
5175
43675176 local->conn = pj_pool_zalloc(inv->pool_prov, sizeof(struct pjmedia_sdp_conn));
43685177 local->conn->net_type = STR_IN;
43695178 local->conn->addr_type = session->endpoint->media.rtp.ipv6 ? STR_IP6 : STR_IP4;
43795188 pj_strassign(&local->origin.addr_type, &local->conn->addr_type);
43805189 pj_strassign(&local->origin.addr, &local->conn->addr);
43815190
4382 return local;
5191 end:
5192 SCOPE_EXIT_RTN_VALUE(local, "%s\n", ast_sip_session_get_name(session));
43835193 }
43845194
43855195 static void session_inv_on_rx_offer(pjsip_inv_session *inv, const pjmedia_sdp_session *offer)
43865196 {
4387 struct ast_sip_session *session;
5197 struct ast_sip_session *session = inv->mod_data[session_module.id];
43885198 pjmedia_sdp_session *answer;
5199 SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
43895200
43905201 if (ast_shutdown_final()) {
4391 return;
5202 SCOPE_EXIT_RTN("%s: Shutdown in progress\n", ast_sip_session_get_name(session));
43925203 }
43935204
43945205 session = inv->mod_data[session_module.id];
43955206 if (handle_incoming_sdp(session, offer)) {
43965207 ast_sip_session_media_state_reset(session->pending_media_state);
4397 return;
5208 SCOPE_EXIT_RTN("%s: handle_incoming_sdp failed\n", ast_sip_session_get_name(session));
43985209 }
43995210
44005211 if ((answer = create_local_sdp(inv, session, offer))) {
44015212 pjsip_inv_set_sdp_answer(inv, answer);
4402 }
5213 SCOPE_EXIT_RTN("%s: Set SDP answer\n", ast_sip_session_get_name(session));
5214 }
5215 SCOPE_EXIT_RTN("%s: create_local_sdp failed\n", ast_sip_session_get_name(session));
44035216 }
44045217
44055218 #if 0
44115224
44125225 static void session_inv_on_media_update(pjsip_inv_session *inv, pj_status_t status)
44135226 {
4414 struct ast_sip_session *session;
5227 struct ast_sip_session *session = inv->mod_data[session_module.id];
44155228 const pjmedia_sdp_session *local, *remote;
5229 SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
44165230
44175231 if (ast_shutdown_final()) {
4418 return;
5232 SCOPE_EXIT_RTN("%s: Shutdown in progress\n", ast_sip_session_get_name(session));
44195233 }
44205234
44215235 session = inv->mod_data[session_module.id];
44255239 * don't care about media updates.
44265240 * Just ignore
44275241 */
4428 return;
5242 SCOPE_EXIT_RTN("%s: No channel or session\n", ast_sip_session_get_name(session));
44295243 }
44305244
44315245 if (session->endpoint) {
44435257
44445258 if (inv->following_fork) {
44455259 if (session->endpoint->media.rtp.follow_early_media_fork) {
4446 ast_debug(3, "Following early media fork with different To tags\n");
5260 ast_trace(-1, "%s: Following early media fork with different To tags\n", ast_sip_session_get_name(session));
44475261 } else {
4448 ast_debug(3, "Not following early media fork with different To tags\n");
5262 ast_trace(-1, "%s: Not following early media fork with different To tags\n", ast_sip_session_get_name(session));
44495263 bail = 1;
44505264 }
44515265 }
44525266 #ifdef HAVE_PJSIP_INV_ACCEPT_MULTIPLE_SDP_ANSWERS
44535267 else if (inv->updated_sdp_answer) {
44545268 if (session->endpoint->media.rtp.accept_multiple_sdp_answers) {
4455 ast_debug(3, "Accepting updated SDP with same To tag\n");
5269 ast_trace(-1, "%s: Accepting updated SDP with same To tag\n", ast_sip_session_get_name(session));
44565270 } else {
4457 ast_debug(3, "Ignoring updated SDP answer with same To tag\n");
5271 ast_trace(-1, "%s: Ignoring updated SDP answer with same To tag\n", ast_sip_session_get_name(session));
44585272 bail = 1;
44595273 }
44605274 }
44615275 #endif
44625276 if (bail) {
4463 return;
5277 SCOPE_EXIT_RTN("%s: Bailing\n", ast_sip_session_get_name(session));
44645278 }
44655279 }
44665280
44695283 ast_channel_hangupcause_set(session->channel, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
44705284 ast_set_hangupsource(session->channel, ast_channel_name(session->channel), 0);
44715285 ast_queue_hangup(session->channel);
4472 return;
5286 SCOPE_EXIT_RTN("%s: Couldn't get active or local or remote negotiator. Hanging up\n", ast_sip_session_get_name(session));
44735287 }
44745288
44755289 if (handle_negotiated_sdp(session, local, remote)) {
44765290 ast_sip_session_media_state_reset(session->pending_media_state);
4477 }
5291 SCOPE_EXIT_RTN("%s: handle_negotiated_sdp failed. Resetting pending media state\n", ast_sip_session_get_name(session));
5292 }
5293 SCOPE_EXIT_RTN("%s\n", ast_sip_session_get_name(session));
44785294 }
44795295
44805296 static pjsip_redirect_op session_inv_on_redirected(pjsip_inv_session *inv, const pjsip_uri *target, const pjsip_event *e)
45445360 struct ast_sip_nat_hook *hook = ast_sip_mod_data_get(
45455361 tdata->mod_data, session_module.id, MOD_DATA_NAT_HOOK);
45465362 struct pjmedia_sdp_session *sdp;
5363 pjsip_dialog *dlg = pjsip_tdata_get_dlg(tdata);
5364 RAII_VAR(struct ast_sip_session *, session, dlg ? ast_sip_dialog_get_session(dlg) : NULL, ao2_cleanup);
45475365 int stream;
45485366
45495367 /* SDP produced by us directly will never be multipart */
45675385 * outgoing session IP is local. If it is, we'll do
45685386 * rewriting. No localnet configured? Always rewrite. */
45695387 if (ast_sip_transport_is_local(transport_state, &our_sdp_addr) || !transport_state->localnet) {
4570 ast_debug(5, "Setting external media address to %s\n", ast_sockaddr_stringify_addr_remote(&transport_state->external_media_address));
4571 pj_strdup2(tdata->pool, &sdp->conn->addr, ast_sockaddr_stringify_addr_remote(&transport_state->external_media_address));
5388 ast_debug(5, "%s: Setting external media address to %s\n", ast_sip_session_get_name(session),
5389 ast_sockaddr_stringify_host(&transport_state->external_media_address));
5390 pj_strdup2(tdata->pool, &sdp->conn->addr, ast_sockaddr_stringify_host(&transport_state->external_media_address));
45725391 pj_strassign(&sdp->origin.addr, &sdp->conn->addr);
45735392 }
45745393 }
45845403
45855404 handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
45865405 if (!handler_list) {
4587 ast_debug(1, "No registered SDP handlers for media type '%s'\n", media);
5406 ast_debug(4, "%s: No registered SDP handlers for media type '%s'\n", ast_sip_session_get_name(session),
5407 media);
45885408 continue;
45895409 }
45905410 AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
45975417 /* We purposely do this so that the hook will not be invoked multiple times, ie: if a retransmit occurs */
45985418 ast_sip_mod_data_set(tdata->pool, tdata->mod_data, session_module.id, MOD_DATA_NAT_HOOK, nat_hook);
45995419 }
5420
5421 #ifdef TEST_FRAMEWORK
5422
5423 static struct ast_stream *test_stream_alloc(const char *name, enum ast_media_type type, enum ast_stream_state state)
5424 {
5425 struct ast_stream *stream;
5426
5427 stream = ast_stream_alloc(name, type);
5428 if (!stream) {
5429 return NULL;
5430 }
5431 ast_stream_set_state(stream, state);
5432
5433 return stream;
5434 }
5435
5436 static struct ast_sip_session_media *test_media_add(
5437 struct ast_sip_session_media_state *media_state, const char *name, enum ast_media_type type,
5438 enum ast_stream_state state, int position)
5439 {
5440 struct ast_sip_session_media *session_media = NULL;
5441 struct ast_stream *stream = NULL;
5442
5443 stream = test_stream_alloc(name, type, state);
5444 if (!stream) {
5445 return NULL;
5446 }
5447
5448 if (position >= 0 && position < ast_stream_topology_get_count(media_state->topology)) {
5449 ast_stream_topology_set_stream(media_state->topology, position, stream);
5450 } else {
5451 position = ast_stream_topology_append_stream(media_state->topology, stream);
5452 }
5453
5454 session_media = ao2_alloc_options(sizeof(*session_media), session_media_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
5455 if (!session_media) {
5456 return NULL;
5457 }
5458
5459 session_media->keepalive_sched_id = -1;
5460 session_media->timeout_sched_id = -1;
5461 session_media->type = type;
5462 session_media->stream_num = position;
5463 session_media->bundle_group = -1;
5464 strcpy(session_media->label, name);
5465
5466 if (AST_VECTOR_REPLACE(&media_state->sessions, position, session_media)) {
5467 ao2_ref(session_media, -1);
5468
5469 return NULL;
5470 }
5471
5472 /* If this stream will be active in some way and it is the first of this type then consider this the default media session to match */
5473 if (!media_state->default_session[type] && ast_stream_get_state(ast_stream_topology_get_stream(media_state->topology, position)) != AST_STREAM_STATE_REMOVED) {
5474 media_state->default_session[type] = session_media;
5475 }
5476
5477 return session_media;
5478 }
5479
5480 static int test_is_media_session_equal(struct ast_sip_session_media *left, struct ast_sip_session_media *right)
5481 {
5482 if (left == right) {
5483 return 1;
5484 }
5485
5486 if (!left) {
5487 return 1;
5488 }
5489
5490 if (!right) {
5491 return 0;
5492 }
5493 return memcmp(left, right, sizeof(*left)) == 0;
5494 }
5495
5496 static int test_is_media_state_equal(struct ast_sip_session_media_state *left, struct ast_sip_session_media_state *right,
5497 int assert_on_failure)
5498 {
5499 int i;
5500 SCOPE_ENTER(2);
5501
5502 if (left == right) {
5503 SCOPE_EXIT_RTN_VALUE(1, "equal\n");
5504 }
5505
5506 if (!(left && right)) {
5507 ast_assert(!assert_on_failure);
5508 SCOPE_EXIT_RTN_VALUE(0, "one is null: left: %p right: %p\n", left, right);
5509 }
5510
5511 if (!ast_stream_topology_equal(left->topology, right->topology)) {
5512 ast_assert(!assert_on_failure);
5513 SCOPE_EXIT_RTN_VALUE(0, "topologies differ\n");
5514 }
5515 if (AST_VECTOR_SIZE(&left->sessions) != AST_VECTOR_SIZE(&right->sessions)) {
5516 ast_assert(!assert_on_failure);
5517 SCOPE_EXIT_RTN_VALUE(0, "session vector sizes different: left %lu != right %lu\n", AST_VECTOR_SIZE(&left->sessions),
5518 AST_VECTOR_SIZE(&right->sessions));
5519 }
5520 if (AST_VECTOR_SIZE(&left->read_callbacks) != AST_VECTOR_SIZE(&right->read_callbacks)) {
5521 ast_assert(!assert_on_failure);
5522 SCOPE_EXIT_RTN_VALUE(0, "read_callback vector sizes different: left %lu != right %lu\n", AST_VECTOR_SIZE(&left->read_callbacks),
5523 AST_VECTOR_SIZE(&right->read_callbacks));
5524 }
5525
5526 for (i = 0; i < AST_VECTOR_SIZE(&left->sessions) ; i++) {
5527 if (!test_is_media_session_equal(AST_VECTOR_GET(&left->sessions, i), AST_VECTOR_GET(&right->sessions, i))) {
5528 ast_assert(!assert_on_failure);
5529 SCOPE_EXIT_RTN_VALUE(0, "Media session %d different\n", i);
5530 }
5531 }
5532
5533 for (i = 0; i < AST_VECTOR_SIZE(&left->read_callbacks) ; i++) {
5534 if (memcmp(AST_VECTOR_GET_ADDR(&left->read_callbacks, i),
5535 AST_VECTOR_GET_ADDR(&right->read_callbacks, i),
5536 sizeof(struct ast_sip_session_media_read_callback_state)) != 0) {
5537 ast_assert(!assert_on_failure);
5538 SCOPE_EXIT_RTN_VALUE(0, "read_callback %d different\n", i);
5539 }
5540 }
5541
5542 for (i = 0; i < AST_MEDIA_TYPE_END; i++) {
5543 if (!(left->default_session[i] && right->default_session[i])) {
5544 continue;
5545 }
5546 if (!left->default_session[i] || !right->default_session[i]
5547 || left->default_session[i]->stream_num != right->default_session[i]->stream_num) {
5548 ast_assert(!assert_on_failure);
5549 SCOPE_EXIT_RTN_VALUE(0, "Default media session %d different. Left: %s Right: %s\n", i,
5550 left->default_session[i] ? left->default_session[i]->label : "null",
5551 right->default_session[i] ? right->default_session[i]->label : "null");
5552 }
5553 }
5554
5555 SCOPE_EXIT_RTN_VALUE(1, "equal\n");
5556 }
5557
5558 AST_TEST_DEFINE(test_resolve_refresh_media_states)
5559 {
5560 #define FREE_STATE() \
5561 ({ \
5562 ast_sip_session_media_state_free(new_pending_state); \
5563 new_pending_state = NULL; \
5564 ast_sip_session_media_state_free(delayed_pending_state); \
5565 delayed_pending_state = NULL; \
5566 ast_sip_session_media_state_free(delayed_active_state); \
5567 delayed_active_state = NULL; \
5568 ast_sip_session_media_state_free(current_active_state); \
5569 current_active_state = NULL; \
5570 ast_sip_session_media_state_free(expected_pending_state); \
5571 expected_pending_state = NULL; \
5572 })
5573
5574 #define RESET_STATE(__num) \
5575 ({ \
5576 testnum=__num; \
5577 ast_trace(-1, "Test %d\n", testnum); \
5578 test_failed = 0; \
5579 delayed_pending_state = ast_sip_session_media_state_alloc(); \
5580 delayed_pending_state->topology = ast_stream_topology_alloc(); \
5581 delayed_active_state = ast_sip_session_media_state_alloc(); \
5582 delayed_active_state->topology = ast_stream_topology_alloc(); \
5583 current_active_state = ast_sip_session_media_state_alloc(); \
5584 current_active_state->topology = ast_stream_topology_alloc(); \
5585 expected_pending_state = ast_sip_session_media_state_alloc(); \
5586 expected_pending_state->topology = ast_stream_topology_alloc(); \
5587 })
5588
5589 #define CHECKER() \
5590 ({ \
5591 new_pending_state = resolve_refresh_media_states("unittest", delayed_pending_state, delayed_active_state, current_active_state, 1); \
5592 if (!test_is_media_state_equal(new_pending_state, expected_pending_state, 0)) { \
5593 res = AST_TEST_FAIL; \
5594 test_failed = 1; \
5595 ast_test_status_update(test, "da: %s\n", ast_str_tmp(256, ast_stream_topology_to_str(delayed_active_state->topology, &STR_TMP))); \
5596 ast_test_status_update(test, "dp: %s\n", ast_str_tmp(256, ast_stream_topology_to_str(delayed_pending_state->topology, &STR_TMP))); \
5597 ast_test_status_update(test, "ca: %s\n", ast_str_tmp(256, ast_stream_topology_to_str(current_active_state->topology, &STR_TMP))); \
5598 ast_test_status_update(test, "ep: %s\n", ast_str_tmp(256, ast_stream_topology_to_str(expected_pending_state->topology, &STR_TMP))); \
5599 ast_test_status_update(test, "np: %s\n", ast_str_tmp(256, ast_stream_topology_to_str(new_pending_state->topology, &STR_TMP))); \
5600 } \
5601 ast_test_status_update(test, "Test %d %s\n", testnum, test_failed ? "FAILED" : "passed"); \
5602 ast_trace(-1, "Test %d %s\n", testnum, test_failed ? "FAILED" : "passed"); \
5603 test_failed = 0; \
5604 FREE_STATE(); \
5605 })
5606
5607
5608 struct ast_sip_session_media_state * delayed_pending_state = NULL;
5609 struct ast_sip_session_media_state * delayed_active_state = NULL;
5610 struct ast_sip_session_media_state * current_active_state = NULL;
5611 struct ast_sip_session_media_state * new_pending_state = NULL;
5612 struct ast_sip_session_media_state * expected_pending_state = NULL;
5613 enum ast_test_result_state res = AST_TEST_PASS;
5614 int test_failed = 0;
5615 int testnum = 0;
5616 SCOPE_ENTER(1);
5617
5618 switch (cmd) {
5619 case TEST_INIT:
5620 info->name = "merge_refresh_topologies";
5621 info->category = "/res/res_pjsip_session/";
5622 info->summary = "Test merging of delayed request topologies";
5623 info->description = "Test merging of delayed request topologies";
5624 SCOPE_EXIT_RTN_VALUE(AST_TEST_NOT_RUN);
5625 case TEST_EXECUTE:
5626 break;
5627 }
5628
5629 RESET_STATE(1);
5630 test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5631 test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5632 test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5633
5634 test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5635 test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5636 test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5637 test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5638
5639 test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5640 test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5641 test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5642
5643 test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5644 test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5645 test_media_add(expected_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5646 test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5647 CHECKER();
5648
5649 RESET_STATE(2);
5650 test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5651 test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5652 test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5653
5654 test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5655 test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5656 test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5657 test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5658
5659 test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5660 test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5661 test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5662
5663 test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5664 test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5665 test_media_add(expected_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5666 test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5667 CHECKER();
5668
5669 RESET_STATE(3);
5670 test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5671 test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5672 test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5673
5674 test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5675 test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5676 test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5677 test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5678
5679 test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5680 test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5681 test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5682 test_media_add(current_active_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5683 test_media_add(current_active_state, "myvideo5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5684
5685 test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5686 test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5687 test_media_add(expected_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5688 test_media_add(expected_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5689 test_media_add(expected_pending_state, "myvideo5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5690 test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5691 CHECKER();
5692
5693 RESET_STATE(4);
5694 test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5695 test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5696 test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5697
5698 test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5699 test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5700 test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5701 test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5702
5703 test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5704 test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5705 test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5706
5707 test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5708 test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5709 test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5710 CHECKER();
5711
5712 RESET_STATE(5);
5713 test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5714 test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5715 test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5716
5717 test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5718 test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5719 test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5720
5721 test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5722 test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5723 test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5724
5725 test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5726 test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5727 test_media_add(expected_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5728 CHECKER();
5729
5730 RESET_STATE(6);
5731 test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5732 test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5733 test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5734
5735 test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5736 test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5737 test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5738 test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5739
5740 test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5741 test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5742 test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5743 test_media_add(current_active_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5744
5745 test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5746 test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5747 test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5748 test_media_add(expected_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5749 CHECKER();
5750
5751 RESET_STATE(7);
5752 test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5753 test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5754 test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5755
5756 test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5757 test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5758 test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5759 test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5760 test_media_add(delayed_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5761
5762 test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5763 test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5764 test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5765 test_media_add(current_active_state, "myvideo5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5766 test_media_add(current_active_state, "myvideo6", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5767
5768 test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5769 test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5770 test_media_add(expected_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5771 test_media_add(expected_pending_state, "myvideo5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5772 test_media_add(expected_pending_state, "myvideo6", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5773 test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5774 test_media_add(expected_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5775 CHECKER();
5776
5777 RESET_STATE(8);
5778 test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5779 test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5780 test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5781
5782 test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5783 test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5784 test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5785 test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5786 test_media_add(delayed_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5787
5788 test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5789 test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5790 test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5791
5792 test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5793 test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5794 test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5795 test_media_add(expected_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5796 CHECKER();
5797
5798 RESET_STATE(9);
5799 test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5800 test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5801 test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5802
5803 test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5804 test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5805 test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5806 test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5807 test_media_add(delayed_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5808
5809 test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5810 test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5811 test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5812
5813 test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5814 test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5815 test_media_add(expected_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5816 CHECKER();
5817
5818 RESET_STATE(10);
5819 test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5820 test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5821 test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5822
5823 test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5824 test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5825 test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5826
5827 test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5828 test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5829 test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5830 test_media_add(current_active_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5831
5832 test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5833 test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5834 test_media_add(expected_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_REMOVED, -1);
5835 test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5836 CHECKER();
5837
5838 RESET_STATE(11);
5839 test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5840 test_media_add(delayed_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5841 test_media_add(delayed_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5842 test_media_add(delayed_active_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5843
5844 test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5845 test_media_add(delayed_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5846 test_media_add(delayed_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5847 test_media_add(delayed_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5848
5849 test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5850 test_media_add(current_active_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5851 test_media_add(current_active_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5852 test_media_add(current_active_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5853
5854 test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5855 test_media_add(expected_pending_state, "myvideo1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5856 test_media_add(expected_pending_state, "myvideo2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5857 test_media_add(expected_pending_state, "myvideo4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5858 test_media_add(expected_pending_state, "myvideo3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5859 CHECKER();
5860
5861 RESET_STATE(12);
5862 test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5863 test_media_add(delayed_active_state, "292-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5864 test_media_add(delayed_active_state, "296-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5865
5866 test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5867 test_media_add(delayed_pending_state, "292-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5868 test_media_add(delayed_pending_state, "296-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5869 test_media_add(delayed_pending_state, "297-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5870 test_media_add(delayed_pending_state, "294-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5871
5872 test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5873 test_media_add(current_active_state, "292-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5874 test_media_add(current_active_state, "296-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5875 test_media_add(current_active_state, "290-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5876 test_media_add(current_active_state, "297-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5877
5878 test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5879 test_media_add(expected_pending_state, "292-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5880 test_media_add(expected_pending_state, "296-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5881 test_media_add(expected_pending_state, "290-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5882 test_media_add(expected_pending_state, "297-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5883 test_media_add(expected_pending_state, "294-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5884 CHECKER();
5885
5886 RESET_STATE(13);
5887 test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5888 test_media_add(delayed_active_state, "293-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5889 test_media_add(delayed_active_state, "292-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5890 test_media_add(delayed_active_state, "294-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5891 test_media_add(delayed_active_state, "295-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5892 test_media_add(delayed_active_state, "296-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5893
5894 test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5895 test_media_add(delayed_pending_state, "293-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5896 test_media_add(delayed_pending_state, "292-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5897 test_media_add(delayed_pending_state, "294-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5898 test_media_add(delayed_pending_state, "295-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5899 test_media_add(delayed_pending_state, "296-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5900 test_media_add(delayed_pending_state, "298-7", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5901
5902 test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5903 test_media_add(current_active_state, "293-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5904 test_media_add(current_active_state, "292-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5905 test_media_add(current_active_state, "294-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5906 test_media_add(current_active_state, "295-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5907 test_media_add(current_active_state, "296-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5908 test_media_add(current_active_state, "290-6", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5909
5910 test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5911 test_media_add(expected_pending_state, "293-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5912 test_media_add(expected_pending_state, "292-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5913 test_media_add(expected_pending_state, "294-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5914 test_media_add(expected_pending_state, "295-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5915 test_media_add(expected_pending_state, "296-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5916 test_media_add(expected_pending_state, "290-6", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5917 test_media_add(expected_pending_state, "298-7", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5918 CHECKER();
5919
5920 RESET_STATE(14);
5921 test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5922 test_media_add(delayed_active_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5923 test_media_add(delayed_active_state, "297-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5924
5925 test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5926 test_media_add(delayed_pending_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5927 test_media_add(delayed_pending_state, "294-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5928 test_media_add(delayed_pending_state, "295-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5929
5930 test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5931 test_media_add(current_active_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5932 test_media_add(current_active_state, "297-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5933 test_media_add(current_active_state, "291-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5934 test_media_add(current_active_state, "294-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5935
5936 test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5937 test_media_add(expected_pending_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5938 test_media_add(expected_pending_state, "297-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5939 test_media_add(expected_pending_state, "291-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5940 test_media_add(expected_pending_state, "294-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5941 test_media_add(expected_pending_state, "295-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5942 CHECKER();
5943
5944 RESET_STATE(15);
5945 test_media_add(delayed_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5946 test_media_add(delayed_active_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5947 test_media_add(delayed_active_state, "297-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5948
5949 test_media_add(delayed_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5950 test_media_add(delayed_pending_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDONLY, -1);
5951 test_media_add(delayed_pending_state, "294-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5952 test_media_add(delayed_pending_state, "295-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5953
5954 test_media_add(current_active_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5955 test_media_add(current_active_state, "297-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5956 test_media_add(current_active_state, "291-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5957 test_media_add(current_active_state, "294-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5958 test_media_add(current_active_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5959
5960 test_media_add(expected_pending_state, "audio", AST_MEDIA_TYPE_AUDIO, AST_STREAM_STATE_SENDRECV, -1);
5961 test_media_add(expected_pending_state, "297-2", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5962 test_media_add(expected_pending_state, "291-3", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5963 test_media_add(expected_pending_state, "294-4", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5964 test_media_add(expected_pending_state, "298-1", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDONLY, -1);
5965 test_media_add(expected_pending_state, "295-5", AST_MEDIA_TYPE_VIDEO, AST_STREAM_STATE_SENDRECV, -1);
5966 CHECKER();
5967
5968 SCOPE_EXIT_RTN_VALUE(res);
5969 }
5970 #endif /* TEST_FRAMEWORK */
46005971
46015972 static int load_module(void)
46025973 {
46265997 ast_sip_register_service(&outbound_invite_auth_module);
46275998
46285999 ast_module_shutdown_ref(ast_module_info->self);
4629
6000 #ifdef TEST_FRAMEWORK
6001 AST_TEST_REGISTER(test_resolve_refresh_media_states);
6002 #endif
46306003 return AST_MODULE_LOAD_SUCCESS;
46316004 }
46326005
46336006 static int unload_module(void)
46346007 {
6008 #ifdef TEST_FRAMEWORK
6009 AST_TEST_UNREGISTER(test_resolve_refresh_media_states);
6010 #endif
46356011 ast_sip_unregister_service(&outbound_invite_auth_module);
46366012 ast_sip_unregister_service(&session_reinvite_module);
46376013 ast_sip_unregister_service(&session_module);
0 /*
1 * Asterisk -- An open source telephony toolkit.
2 *
3 * Copyright (C) 2020, Sangoma Technologies Corporation
4 *
5 * Ben Ford <bford@sangoma.com>
6 *
7 * See http://www.asterisk.org for more information about
8 * the Asterisk project. Please do not directly contact
9 * any of the maintainers of this project for assistance;
10 * the project provides a web site, mailing lists and IRC
11 * channels for your use.
12 *
13 * This program is free software, distributed under the terms of
14 * the GNU General Public License Version 2. See the LICENSE file
15 * at the top of the source tree.
16 */
17
18 /*** MODULEINFO
19 <depend>pjproject</depend>
20 <depend>res_pjsip</depend>
21 <depend>res_pjsip_session</depend>
22 <depend>res_stir_shaken</depend>
23 <support_level>core</support_level>
24 ***/
25
26 #include "asterisk.h"
27
28 #include <pjsip.h>
29 #include <pjsip_ua.h>
30
31 #include "asterisk/res_pjsip.h"
32 #include "asterisk/res_pjsip_session.h"
33 #include "asterisk/module.h"
34
35 #include "asterisk/res_stir_shaken.h"
36
37 /*!
38 * \brief Get the attestation from the payload
39 *
40 * \param json_str The JSON string representation of the payload
41 *
42 * \retval Empty string on failure
43 * \retval The attestation on success
44 */
45 static char *get_attestation_from_payload(const char *json_str)
46 {
47 RAII_VAR(struct ast_json *, json, NULL, ast_json_free);
48 char *attestation;
49
50 json = ast_json_load_string(json_str, NULL);
51 attestation = (char *)ast_json_string_get(ast_json_object_get(json, "attest"));
52
53 if (!ast_strlen_zero(attestation)) {
54 return attestation;
55 }
56
57 return "";
58 }
59
60 /*!
61 * \brief Compare the caller ID from the INVITE with the one in the payload
62 *
63 * \param json_str The JSON string represntation of the payload
64 *
65 * \retval -1 on failure
66 * \retval 0 on success
67 */
68 static int compare_caller_id(char *caller_id, const char *json_str)
69 {
70 RAII_VAR(struct ast_json *, json, NULL, ast_json_free);
71 char *caller_id_other;
72
73 json = ast_json_load_string(json_str, NULL);
74 caller_id_other = (char *)ast_json_string_get(ast_json_object_get(
75 ast_json_object_get(json, "orig"), "tn"));
76
77 if (strcmp(caller_id, caller_id_other)) {
78 return -1;
79 }
80
81 return 0;
82 }
83
84 /*!
85 * \brief Compare the current timestamp with the one in the payload. If the difference
86 * is greater than the signature timeout, it's not valid anymore
87 *
88 * \param json_str The JSON string representation of the payload
89 *
90 * \retval -1 on failure
91 * \retval 0 on success
92 */
93 static int compare_timestamp(const char *json_str)
94 {
95 RAII_VAR(struct ast_json *, json, NULL, ast_json_free);
96 long int timestamp;
97 struct timeval now = ast_tvnow();
98
99 #ifdef TEST_FRAMEWORK
100 ast_debug(3, "Ignoring STIR/SHAKEN timestamp\n");
101 return 0;
102 #endif
103
104 json = ast_json_load_string(json_str, NULL);
105 timestamp = ast_json_integer_get(ast_json_object_get(json, "iat"));
106
107 if (now.tv_sec - timestamp > ast_stir_shaken_get_signature_timeout()) {
108 return -1;
109 }
110
111 return 0;
112 }
113
114 /*!
115 * \internal
116 * \brief Session supplement callback on an incoming INVITE request
117 *
118 * When we receive an INVITE, check it for STIR/SHAKEN information and
119 * decide what to do from there
120 *
121 * \param session The session that has received an INVITE
122 * \param rdata The incoming INVITE
123 */
124 static int stir_shaken_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
125 {
126 static const pj_str_t identity_str = { "Identity", 8 };
127 char *identity_hdr_val;
128 char *encoded_val;
129 struct ast_channel *chan = session->channel;
130 char *caller_id = session->id.number.str;
131 RAII_VAR(char *, header, NULL, ast_free);
132 RAII_VAR(char *, payload, NULL, ast_free);
133 char *signature;
134 char *algorithm;
135 char *public_key_url;
136 char *attestation;
137 int mismatch = 0;
138 struct ast_stir_shaken_payload *ss_payload;
139
140 if (!session->endpoint->stir_shaken) {
141 return 0;
142 }
143
144 identity_hdr_val = ast_sip_rdata_get_header_value(rdata, identity_str);
145 if (ast_strlen_zero(identity_hdr_val)) {
146 ast_stir_shaken_add_verification(chan, caller_id, "", AST_STIR_SHAKEN_VERIFY_NOT_PRESENT);
147 return 0;
148 }
149
150 encoded_val = strtok_r(identity_hdr_val, ".", &identity_hdr_val);
151 header = ast_base64decode_string(encoded_val);
152 if (ast_strlen_zero(header)) {
153 ast_stir_shaken_add_verification(chan, caller_id, "", AST_STIR_SHAKEN_VERIFY_SIGNATURE_FAILED);
154 return 0;
155 }
156
157 encoded_val = strtok_r(identity_hdr_val, ".", &identity_hdr_val);
158 payload = ast_base64decode_string(encoded_val);
159 if (ast_strlen_zero(payload)) {
160 ast_stir_shaken_add_verification(chan, caller_id, "", AST_STIR_SHAKEN_VERIFY_SIGNATURE_FAILED);
161 return 0;
162 }
163
164 /* It's fine to leave the signature encoded */
165 signature = strtok_r(identity_hdr_val, ";", &identity_hdr_val);
166 if (ast_strlen_zero(signature)) {
167 ast_stir_shaken_add_verification(chan, caller_id, "", AST_STIR_SHAKEN_VERIFY_SIGNATURE_FAILED);
168 return 0;
169 }
170
171 /* Trim "info=<" to get public key URL */
172 strtok_r(identity_hdr_val, "<", &identity_hdr_val);
173 public_key_url = strtok_r(identity_hdr_val, ">", &identity_hdr_val);
174 if (ast_strlen_zero(public_key_url)) {
175 ast_stir_shaken_add_verification(chan, caller_id, "", AST_STIR_SHAKEN_VERIFY_SIGNATURE_FAILED);
176 return 0;
177 }
178
179 algorithm = strtok_r(identity_hdr_val, ";", &identity_hdr_val);
180 if (ast_strlen_zero(algorithm)) {
181 ast_stir_shaken_add_verification(chan, caller_id, "", AST_STIR_SHAKEN_VERIFY_SIGNATURE_FAILED);
182 return 0;
183 }
184
185 attestation = get_attestation_from_payload(payload);
186
187 ss_payload = ast_stir_shaken_verify(header, payload, signature, algorithm, public_key_url);
188 if (!ss_payload) {
189 ast_stir_shaken_add_verification(chan, caller_id, attestation, AST_STIR_SHAKEN_VERIFY_SIGNATURE_FAILED);
190 return 0;
191 }
192 ast_stir_shaken_payload_free(ss_payload);
193
194 mismatch |= compare_caller_id(caller_id, payload);
195 mismatch |= compare_timestamp(payload);
196
197 if (mismatch) {
198 ast_stir_shaken_add_verification(chan, caller_id, attestation, AST_STIR_SHAKEN_VERIFY_MISMATCH);
199 return 0;
200 }
201
202 ast_stir_shaken_add_verification(chan, caller_id, attestation, AST_STIR_SHAKEN_VERIFY_PASSED);
203
204 return 0;
205 }
206
207 static void add_identity_header(const struct ast_sip_session *session, pjsip_tx_data *tdata)
208 {
209 static const pj_str_t identity_str = { "Identity", 8 };
210 pjsip_generic_string_hdr *identity_hdr;
211 pj_str_t identity_val;
212 pjsip_fromto_hdr *old_identity;
213 char *signature;
214 char *public_key_url;
215 struct ast_json *header;
216 struct ast_json *payload;
217 char *dumped_string;
218 RAII_VAR(struct ast_json *, json, NULL, ast_json_free);
219 RAII_VAR(struct ast_stir_shaken_payload *, ss_payload, NULL, ast_stir_shaken_payload_free);
220 RAII_VAR(char *, encoded_header, NULL, ast_free);
221 RAII_VAR(char *, encoded_payload, NULL, ast_free);
222 RAII_VAR(char *, combined_str, NULL, ast_free);
223 size_t combined_size;
224
225 old_identity = pjsip_msg_find_hdr_by_name(tdata->msg, &identity_str, NULL);
226 if (old_identity) {
227 return;
228 }
229
230 /* x5u (public key URL), attestation, and origid will be added by ast_stir_shaken_sign */
231 json = ast_json_pack("{s: {s: s, s: s, s: s}, s: {s: {s: s}}}", "header", "alg", "ES256", "ppt", "shaken", "typ", "passport",
232 "payload", "orig", "tn", session->id.number.str);
233 if (!json) {
234 ast_log(LOG_ERROR, "Failed to allocate memory for STIR/SHAKEN JSON\n");
235 return;
236 }
237
238 ss_payload = ast_stir_shaken_sign(json);
239 if (!ss_payload) {
240 ast_log(LOG_ERROR, "Failed to allocate memory for STIR/SHAKEN payload\n");
241 return;
242 }
243
244 header = ast_json_object_get(json, "header");
245 dumped_string = ast_json_dump_string(header);
246 encoded_header = ast_base64encode_string(dumped_string);
247 ast_json_free(dumped_string);
248 if (!encoded_header) {
249 ast_log(LOG_ERROR, "Failed to encode STIR/SHAKEN header\n");
250 return;
251 }
252
253 payload = ast_json_object_get(json, "payload");
254 dumped_string = ast_json_dump_string(payload);
255 encoded_payload = ast_base64encode_string(dumped_string);
256 ast_json_free(dumped_string);
257 if (!encoded_payload) {
258 ast_log(LOG_ERROR, "Failed to encode STIR/SHAKEN payload\n");
259 return;
260 }
261
262 signature = (char *)ast_stir_shaken_payload_get_signature(ss_payload);
263 public_key_url = ast_stir_shaken_payload_get_public_key_url(ss_payload);
264
265 /* The format for the identity header:
266 * header.payload.signature;info=<public_key_url>alg=STIR_SHAKEN_ENCRYPTION_ALGORITHM;ppt=STIR_SHAKEN_PPT
267 */
268 combined_size = strlen(encoded_header) + 1 + strlen(encoded_payload) + 1
269 + strlen(signature) + strlen(";info=<>alg=;ppt=") + strlen(public_key_url)
270 + strlen(STIR_SHAKEN_ENCRYPTION_ALGORITHM) + strlen(STIR_SHAKEN_PPT) + 1;
271 combined_str = ast_calloc(1, combined_size);
272 if (!combined_str) {
273 ast_log(LOG_ERROR, "Failed to allocate memory for STIR/SHAKEN identity string\n");
274 return;
275 }
276 snprintf(combined_str, combined_size, "%s.%s.%s;info=<%s>alg=%s;ppt=%s", encoded_header,
277 encoded_payload, signature, public_key_url, STIR_SHAKEN_ENCRYPTION_ALGORITHM, STIR_SHAKEN_PPT);
278
279 identity_val = pj_str(combined_str);
280 identity_hdr = pjsip_generic_string_hdr_create(tdata->pool, &identity_str, &identity_val);
281 if (!identity_hdr) {
282 ast_log(LOG_ERROR, "Failed to create STIR/SHAKEN Identity header\n");
283 return;
284 }
285
286 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)identity_hdr);
287 }
288
289 static void stir_shaken_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
290 {
291 if (!session->endpoint->stir_shaken) {
292 return;
293 }
294
295 if (ast_strlen_zero(session->id.number.str) && session->id.number.valid) {
296 return;
297 }
298
299 add_identity_header(session, tdata);
300 }
301
302 static struct ast_sip_session_supplement stir_shaken_supplement = {
303 .method = "INVITE",
304 .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 1, /* Run AFTER channel creation */
305 .incoming_request = stir_shaken_incoming_request,
306 .outgoing_request = stir_shaken_outgoing_request,
307 };
308
309 static int unload_module(void)
310 {
311 ast_sip_session_unregister_supplement(&stir_shaken_supplement);
312 return 0;
313 }
314
315 static int load_module(void)
316 {
317 ast_sip_session_register_supplement(&stir_shaken_supplement);
318 return AST_MODULE_LOAD_SUCCESS;
319 }
320
321 #undef AST_BUILDOPT_SUM
322 #define AST_BUILDOPT_SUM ""
323
324 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER,
325 "PSIP STIR/SHAKEN Module for Asterisk",
326 .support_level = AST_MODULE_SUPPORT_CORE,
327 .load = load_module,
328 .unload = unload_module,
329 .load_pri = AST_MODPRI_DEFAULT,
330 .requires = "res_pjsip,res_stir_shaken",
331 );
6363 #endif
6464
6565 #include "asterisk/options.h"
66 #include "asterisk/logger_category.h"
6667 #include "asterisk/stun.h"
6768 #include "asterisk/pbx.h"
6869 #include "asterisk/frame.h"
109110 #define MAXIMUM_RTP_RECV_BUFFER_SIZE (DEFAULT_RTP_RECV_BUFFER_SIZE + 20) /*!< Maximum RTP receive buffer size */
110111 #define OLD_PACKET_COUNT 1000 /*!< The number of previous packets that are considered old */
111112 #define MISSING_SEQNOS_ADDED_TRIGGER 2 /*!< The number of immediate missing packets that will trigger an immediate NACK */
113
112114 #define SEQNO_CYCLE_OVER 65536 /*!< The number after the maximum allowed sequence number */
113115
114116 /*! Full INTRA-frame Request / Fast Update Request (From RFC2032) */
188190
189191 static int rtpstart = DEFAULT_RTP_START; /*!< First port for RTP sessions (set in rtp.conf) */
190192 static int rtpend = DEFAULT_RTP_END; /*!< Last port for RTP sessions (set in rtp.conf) */
191 static int rtpdebug; /*!< Are we debugging? */
192 static int rtcpdebug; /*!< Are we debugging RTCP? */
193193 static int rtcpstats; /*!< Are we debugging RTCP? */
194194 static int rtcpinterval = RTCP_DEFAULT_INTERVALMS; /*!< Time between rtcp reports in millisecs */
195195 static struct ast_sockaddr rtpdebugaddr; /*!< Debug packets to/from this host */
668668 int rtcp = 0;
669669 struct ast_sockaddr remote_address = { {0, } };
670670 int ice;
671 int bytes_sent;
671672
672673 /* OpenSSL can't tolerate a packet not being sent, so we always state that
673674 * we sent the packet. If it isn't then retransmission will occur.
684685 return len;
685686 }
686687
687 __rtp_sendto(instance, (char *)buf, len, 0, &remote_address, rtcp, &ice, 0);
688 bytes_sent = __rtp_sendto(instance, (char *)buf, len, 0, &remote_address, rtcp, &ice, 0);
689
690 if (bytes_sent > 0 && ast_debug_dtls_packet_is_allowed) {
691 ast_debug(0, "(%p) DTLS - sent %s packet to %s%s (len %-6.6d)\n",
692 instance, rtcp ? "RTCP" : "RTP", ast_sockaddr_stringify(&remote_address),
693 ice ? " (via ICE)" : "", bytes_sent);
694 }
688695
689696 return len;
690697 }
816823 ast_sockaddr_copy(&remote_candidate->relay_address, &candidate->relay_address);
817824 remote_candidate->type = candidate->type;
818825
826 ast_debug_ice(2, "(%p) ICE add remote candidate\n", instance);
827
819828 ao2_link(rtp->ice_proposed_remote_candidates, remote_candidate);
820829 ao2_ref(remote_candidate, -1);
821830 }
861870 ao2_unlock(instance);
862871 ao2_ref(ice, -1);
863872 ao2_lock(instance);
873 ast_debug_ice(2, "(%p) ICE stopped\n", instance);
864874 }
865875 }
866876
921931 struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
922932 int res;
923933
924 ast_debug(3, "Resetting ICE for RTP instance '%p'\n", instance);
934 ast_debug_ice(3, "(%p) ICE resetting\n", instance);
925935 if (!rtp->ice->real_ice->is_nominating && !rtp->ice->real_ice->is_complete) {
926 ast_debug(3, "Nevermind. ICE isn't ready for a reset\n");
936 ast_debug_ice(3, " (%p) ICE nevermind, not ready for a reset\n", instance);
927937 return 0;
928938 }
929939
930 ast_debug(3, "Recreating ICE session %s (%d) for RTP instance '%p'\n", ast_sockaddr_stringify(&rtp->ice_original_rtp_addr), rtp->ice_port, instance);
940 ast_debug_ice(3, "(%p) ICE recreating ICE session %s (%d)\n",
941 instance, ast_sockaddr_stringify(&rtp->ice_original_rtp_addr), rtp->ice_port);
931942 res = ice_create(instance, &rtp->ice_original_rtp_addr, rtp->ice_port, 1);
932943 if (!res) {
933944 /* Use the current expected role for the ICE session */
10031014 /* Check for equivalence in the lists */
10041015 if (rtp->ice_active_remote_candidates &&
10051016 !ice_candidates_compare(rtp->ice_proposed_remote_candidates, rtp->ice_active_remote_candidates)) {
1006 ast_debug(3, "Proposed == active candidates for RTP instance '%p'\n", instance);
1017 ast_debug_ice(2, "(%p) ICE proposed equals active candidates\n", instance);
10071018 ao2_cleanup(rtp->ice_proposed_remote_candidates);
10081019 rtp->ice_proposed_remote_candidates = NULL;
10091020 /* If this ICE session is being preserved then go back to the role it currently is */
10161027 rtp->ice_active_remote_candidates = rtp->ice_proposed_remote_candidates;
10171028 rtp->ice_proposed_remote_candidates = NULL;
10181029
1030 ast_debug_ice(2, "(%p) ICE start\n", instance);
1031
10191032 /* Reset the ICE session. Is this going to work? */
10201033 if (ice_reset_session(instance)) {
1021 ast_log(LOG_NOTICE, "Failed to create replacement ICE session\n");
1034 ast_log(LOG_NOTICE, "(%p) ICE failed to create replacement session\n", instance);
10221035 return;
10231036 }
10241037
10531066 }
10541067
10551068 if (candidate->id == AST_RTP_ICE_COMPONENT_RTP && rtp->turn_rtp) {
1056 ast_debug(3, "RTP candidate %s (%p)\n", ast_sockaddr_stringify(&candidate->address), instance);
1069 ast_debug_ice(2, "(%p) ICE RTP candidate %s\n", instance, ast_sockaddr_stringify(&candidate->address));
10571070 /* Release the instance lock to avoid deadlock with PJPROJECT group lock */
10581071 ao2_unlock(instance);
10591072 pj_turn_sock_set_perm(rtp->turn_rtp, 1, &candidates[cand_cnt].addr, 1);
10601073 ao2_lock(instance);
10611074 } else if (candidate->id == AST_RTP_ICE_COMPONENT_RTCP && rtp->turn_rtcp) {
1062 ast_debug(3, "RTCP candidate %s (%p)\n", ast_sockaddr_stringify(&candidate->address), instance);
1075 ast_debug_ice(2, "(%p) ICE RTCP candidate %s\n", instance, ast_sockaddr_stringify(&candidate->address));
10631076 /* Release the instance lock to avoid deadlock with PJPROJECT group lock */
10641077 ao2_unlock(instance);
10651078 pj_turn_sock_set_perm(rtp->turn_rtcp, 1, &candidates[cand_cnt].addr, 1);
10731086 ao2_iterator_destroy(&i);
10741087
10751088 if (cand_cnt < ao2_container_count(rtp->ice_active_remote_candidates)) {
1076 ast_log(LOG_WARNING, "Lost %d ICE candidates. Consider increasing PJ_ICE_MAX_CAND in PJSIP (%p)\n",
1077 ao2_container_count(rtp->ice_active_remote_candidates) - cand_cnt, instance);
1089 ast_log(LOG_WARNING, "(%p) ICE lost %d candidates. Consider increasing PJ_ICE_MAX_CAND in PJSIP\n",
1090 instance, ao2_container_count(rtp->ice_active_remote_candidates) - cand_cnt);
10781091 }
10791092
10801093 if (!has_rtp) {
1081 ast_log(LOG_WARNING, "No RTP candidates; skipping ICE checklist (%p)\n", instance);
1094 ast_log(LOG_WARNING, "(%p) ICE no RTP candidates; skipping checklist\n", instance);
10821095 }
10831096
10841097 /* If we're only dealing with one ICE component, then we don't care about the lack of RTCP candidates */
10851098 if (!has_rtcp && rtp->ice_num_components > 1) {
1086 ast_log(LOG_WARNING, "No RTCP candidates; skipping ICE checklist (%p)\n", instance);
1099 ast_log(LOG_WARNING, "(%p) ICE no RTCP candidates; skipping checklist\n", instance);
10871100 }
10881101
10891102 if (rtp->ice && has_rtp && (has_rtcp || rtp->ice_num_components == 1)) {
10971110 ao2_unlock(instance);
10981111 res = pj_ice_sess_create_check_list(ice->real_ice, &ufrag, &passwd, cand_cnt, &candidates[0]);
10991112 if (res == PJ_SUCCESS) {
1100 ast_debug(3, "Successfully created ICE checklist (%p)\n", instance);
1113 ast_debug_ice(2, "(%p) ICE successfully created checklist\n", instance);
11011114 ast_test_suite_event_notify("ICECHECKLISTCREATE", "Result: SUCCESS");
11021115 pj_ice_sess_start_check(ice->real_ice);
11031116 pj_timer_heap_poll(timer_heap, NULL);
11101123 ao2_lock(instance);
11111124
11121125 pj_strerror(res, reason, sizeof(reason));
1113 ast_log(LOG_WARNING, "Failed to create ICE session check list: %s (%p)\n", reason, instance);
1126 ast_log(LOG_WARNING, "(%p) ICE failed to create session check list: %s\n", instance, reason);
11141127 }
11151128
11161129 ast_test_suite_event_notify("ICECHECKLISTCREATE", "Result: FAILURE");
11731186 {
11741187 struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
11751188
1176 ast_debug(3, "Set role to %s (%p)\n",
1177 role == AST_RTP_ICE_ROLE_CONTROLLED ? "CONTROLLED" : "CONTROLLING", instance);
1178
11791189 if (!rtp->ice) {
1180 ast_debug(3, "Set role failed; no ice instance (%p)\n", instance);
1190 ast_debug_ice(3, "(%p) ICE set role failed; no ice instance\n", instance);
11811191 return;
11821192 }
11831193
11851195
11861196 if (!rtp->ice->real_ice->is_nominating && !rtp->ice->real_ice->is_complete) {
11871197 pj_thread_register_check();
1188
1198 ast_debug_ice(2, "(%p) ICE set role to %s\n",
1199 instance, role == AST_RTP_ICE_ROLE_CONTROLLED ? "CONTROLLED" : "CONTROLLING");
11891200 pj_ice_sess_change_role(rtp->ice->real_ice, role == AST_RTP_ICE_ROLE_CONTROLLED ?
11901201 PJ_ICE_SESS_ROLE_CONTROLLED : PJ_ICE_SESS_ROLE_CONTROLLING);
11911202 } else {
1192 ast_debug(3, "Not setting ICE role because state is %s\n", rtp->ice->real_ice->is_nominating ? "nominating" : "complete" );
1203 ast_debug_ice(2, "(%p) ICE not setting role because state is %s\n",
1204 instance, rtp->ice->real_ice->is_nominating ? "nominating" : "complete");
11931205 }
11941206 }
11951207
12601272 ao2_ref(ice, -1);
12611273 ao2_lock(instance);
12621274 if (!rtp->ice || status != PJ_SUCCESS) {
1275 ast_debug_ice(2, "(%p) ICE unable to add candidate: %s, %d\n", instance, ast_sockaddr_stringify(
1276 &candidate->address), candidate->priority);
12631277 ao2_ref(candidate, -1);
12641278 return;
12651279 }
12661280
12671281 /* By placing the candidate into the ICE session it will have produced the priority, so update the local candidate with it */
12681282 candidate->priority = rtp->ice->real_ice->lcand[rtp->ice->real_ice->lcand_cnt - 1].prio;
1283
1284 ast_debug_ice(2, "(%p) ICE add candidate: %s, %d\n", instance, ast_sockaddr_stringify(
1285 &candidate->address), candidate->priority);
12691286
12701287 ao2_link(rtp->ice_local_candidates, candidate);
12711288 ao2_ref(candidate, -1);
12911308 char buf[100];
12921309
12931310 pj_strerror(status, buf, sizeof(buf));
1294 ast_log(LOG_WARNING, "PJ ICE Rx error status code: %d '%s'.\n",
1295 (int)status, buf);
1311 ast_log(LOG_WARNING, "(%p) ICE PJ Rx error status code: %d '%s'.\n",
1312 instance, (int)status, buf);
12961313 return;
12971314 }
12981315 if (!rtp->rtp_passthrough) {
16231640 turn_cb, &turn_sock_cfg, instance, turn_sock);
16241641 ao2_cleanup(ice);
16251642 if (status != PJ_SUCCESS) {
1626 ast_log(LOG_WARNING, "Could not create a TURN client socket\n");
1643 ast_log(LOG_WARNING, "(%p) Could not create a TURN client socket\n", instance);
16271644 ao2_lock(instance);
16281645 return;
16291646 }
16341651 pj_strset2(&cred.data.static_cred.data, (char*)password);
16351652
16361653 pj_turn_sock_alloc(*turn_sock, pj_cstr(&turn_addr, server), port, NULL, &cred, NULL);
1654
1655 ast_debug_ice(2, "(%p) ICE request TURN %s %s candidate\n", instance,
1656 transport == AST_TRANSPORT_UDP ? "UDP" : "TCP",
1657 component == AST_RTP_ICE_COMPONENT_RTP ? "RTP" : "RTCP");
1658
16371659 ao2_lock(instance);
16381660
16391661 /*
16861708 if (!icesupport || !rtp->ice || rtp->ice_num_components == num_components) {
16871709 return;
16881710 }
1711
1712 ast_debug_ice(2, "(%p) ICE change number of components %u -> %u\n", instance,
1713 rtp->ice_num_components, num_components);
16891714
16901715 rtp->ice_num_components = num_components;
16911716 ice_reset_session(instance);
17811806 return 0;
17821807 }
17831808
1809 ast_debug_dtls(3, "(%p) DTLS RTCP setup\n", instance);
17841810 return dtls_details_initialize(&rtp->rtcp->dtls, rtp->ssl_ctx, rtp->dtls.dtls_setup, instance);
17851811 }
17861812
20742100 return 0;
20752101 }
20762102
2103 ast_debug_dtls(3, "(%p) DTLS RTP setup\n", instance);
2104
20772105 if (!ast_rtp_engine_srtp_is_registered()) {
20782106 ast_log(LOG_ERROR, "SRTP support module is not loaded or available. Try loading res_srtp.so.\n");
20792107 return -1;
21962224 struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
21972225 SSL *ssl = rtp->dtls.ssl;
21982226
2227 ast_debug_dtls(3, "(%p) DTLS stop\n", instance);
21992228 ao2_unlock(instance);
22002229 dtls_srtp_stop_timeout_timer(instance, rtp, 0);
22012230 ao2_lock(instance);
24682497 {
24692498 struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
24702499
2471 ast_debug(3, "dtls_perform_handshake (%p) - ssl = %p, setup = %d\n",
2500 ast_debug_dtls(3, "(%p) DTLS perform handshake - ssl = %p, setup = %d\n",
24722501 rtp, dtls->ssl, dtls->dtls_setup);
24732502
24742503 /* If we are not acting as a client connecting to the remote side then
25082537 }
25092538 dtls->connection = AST_RTP_DTLS_CONNECTION_NEW;
25102539
2511 ast_debug(3, "dtls_perform_setup - connection reset'\n");
2540 ast_debug_dtls(3, "DTLS perform setup - connection reset\n");
25122541 }
25132542 #endif
25142543
25472576 return;
25482577 }
25492578
2550 ast_debug(3, "ast_rtp_on_ice_complete (%p) - perform DTLS\n", rtp);
2579 ast_debug_category(2, AST_DEBUG_CATEGORY_ICE | AST_DEBUG_CATEGORY_DTLS,
2580 "(%p) ICE starting media - perform DTLS - (%p)\n", instance, rtp);
25512581
25522582 /*
25532583 * Seemingly no reason to call dtls_perform_setup here. Currently we'll do a full
25842614 /* PJPROJECT ICE optional callback */
25852615 static void ast_rtp_on_valid_pair(pj_ice_sess *ice)
25862616 {
2617 ast_debug_ice(2, "(%p) ICE valid pair, start media\n", ice->user_data);
25872618 ast_rtp_ice_start_media(ice, PJ_SUCCESS);
25882619 }
25892620 #endif
25912622 /* PJPROJECT ICE callback */
25922623 static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status)
25932624 {
2625 ast_debug_ice(2, "(%p) ICE complete, start media\n", ice->user_data);
25942626 ast_rtp_ice_start_media(ice, status);
25952627 }
25962628
26802712
26812713 static inline int rtp_debug_test_addr(struct ast_sockaddr *addr)
26822714 {
2683 if (!rtpdebug) {
2715 if (!ast_debug_rtp_packet_is_allowed) {
26842716 return 0;
26852717 }
26862718 if (!ast_sockaddr_isnull(&rtpdebugaddr)) {
26962728
26972729 static inline int rtcp_debug_test_addr(struct ast_sockaddr *addr)
26982730 {
2699 if (!rtcpdebug) {
2731 if (!ast_debug_rtcp_packet_is_allowed) {
27002732 return 0;
27012733 }
27022734 if (!ast_sockaddr_isnull(&rtcpdebugaddr)) {
27182750 struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls;
27192751 struct timeval dtls_timeout;
27202752
2753 ast_debug_dtls(3, "(%p) DTLS srtp - handle timeout - rtcp=%d\n", instance, rtcp);
27212754 DTLSv1_handle_timeout(dtls->ssl);
27222755
27232756 /* If a timeout can't be retrieved then this recurring scheduled item must stop */
27772810 ao2_ref(instance, -1);
27782811 ast_log(LOG_WARNING, "Scheduling '%s' DTLS retransmission for RTP instance [%p] failed.\n",
27792812 !rtcp ? "RTP" : "RTCP", instance);
2813 } else {
2814 ast_debug_dtls(3, "(%p) DTLS srtp - scheduled timeout timer for '%d'\n", instance, timeout);
27802815 }
27812816 }
27822817 }
27872822 struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls;
27882823
27892824 AST_SCHED_DEL_UNREF(rtp->sched, dtls->timeout_timer, ao2_ref(instance, -1));
2825 ast_debug_dtls(3, "(%p) DTLS srtp - stopped timeout timer'\n", instance);
27902826 }
27912827
27922828 /* Scheduler callback */
27972833
27982834 ao2_lock(instance);
27992835
2836 ast_debug_dtls(3, "(%p) DTLS srtp - renegotiate'\n", instance);
28002837 SSL_renegotiate(rtp->dtls.ssl);
28012838 SSL_do_handshake(rtp->dtls.ssl);
28022839
28202857 struct ast_srtp_policy *local_policy, *remote_policy = NULL;
28212858 int res = -1;
28222859 struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls;
2860
2861 ast_debug_dtls(3, "(%p) DTLS srtp - add local ssrc - rtcp=%d, set_remote_policy=%d'\n",
2862 instance, rtcp, set_remote_policy);
28232863
28242864 /* Produce key information and set up SRTP */
28252865 if (!SSL_export_keying_material(dtls->ssl, material, SRTP_MASTER_LEN * 2, "EXTRACTOR-dtls_srtp", 19, NULL, 0, 0)) {
28982938 struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls;
28992939 int index;
29002940
2901 ast_debug(3, "Setup DTLS SRTP (%p)'\n", rtp);
2941 ast_debug_dtls(3, "(%p) DTLS setup SRTP rtp=%p'\n", instance, rtp);
29022942
29032943 /* If a fingerprint is present in the SDP make sure that the peer certificate matches it */
29042944 if (rtp->dtls_verify & AST_RTP_DTLS_VERIFY_FINGERPRINT) {
30473087 return -1;
30483088 }
30493089
3050 ast_debug(3, "__rtp_recvfrom (%p) - Got SSL packet '%d'\n", rtp, *in);
3090 ast_debug_dtls(3, "(%p) DTLS - __rtp_recvfrom rtp=%p - Got SSL packet '%d'\n", instance, rtp, *in);
30513091
30523092 /*
30533093 * A race condition is prevented between dtls_perform_handshake()
30893129 /* Notify that dtls has been established */
30903130 res = RTP_DTLS_ESTABLISHED;
30913131
3092 ast_debug(3, "__rtp_recvfrom (%p) - DTLS established'\n", rtp);
3132 ast_debug_dtls(3, "(%p) DTLS - __rtp_recvfrom rtp=%p - established'\n", instance, rtp);
30933133 } else {
30943134 /* Since we've sent additional traffic start the timeout timer for retransmission */
30953135 dtls_srtp_start_timeout_timer(instance, rtp, rtcp);
34833523
34843524 if (getifaddrs(&ifa) < 0) {
34853525 /* If we can't get addresses, we can't load ICE candidates */
3486 ast_log(LOG_ERROR, "Error obtaining list of local addresses: %s\n",
3487 strerror(errno));
3526 ast_log(LOG_ERROR, "(%p) ICE Error obtaining list of local addresses: %s\n",
3527 instance, strerror(errno));
34883528 } else {
3529 ast_debug_ice(2, "(%p) ICE add system candidates\n", instance);
34893530 /* Iterate through the list of addresses obtained from the system,
34903531 * until we've iterated through all of them, or accepted
34913532 * PJ_ICE_MAX_CAND candidates */
35873628 struct sockaddr_in answer;
35883629 int rsp;
35893630
3631 ast_debug_category(3, AST_DEBUG_CATEGORY_ICE | AST_DEBUG_CATEGORY_STUN,
3632 "(%p) ICE request STUN %s %s candidate\n", instance,
3633 transport == AST_TRANSPORT_UDP ? "UDP" : "TCP",
3634 component == AST_RTP_ICE_COMPONENT_RTP ? "RTP" : "RTCP");
3635
35903636 /*
35913637 * The instance should not be locked because we can block
35923638 * waiting for a STUN respone.
36983744 ao2_cleanup(rtp->ice_local_candidates);
36993745 rtp->ice_local_candidates = NULL;
37003746
3747 ast_debug_ice(2, "(%p) ICE create%s\n", instance, replace ? " and replace" : "");
3748
37013749 ice = ao2_alloc_options(sizeof(*ice), ice_wrap_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
37023750 if (!ice) {
37033751 ast_rtp_ice_stop(instance);
37813829 ast_sockaddr_set_port(&rtp->bind_address, x);
37823830 /* Try to bind, this will tell us whether the port is available or not */
37833831 if (!ast_bind(rtp->s, &rtp->bind_address)) {
3784 ast_debug(1, "Allocated port %d for RTP instance '%p'\n", x, instance);
3832 ast_debug_rtp(1, "(%p) RTP allocated port %d\n", instance, x);
37853833 ast_rtp_instance_set_local_address(instance, &rtp->bind_address);
37863834 ast_test_suite_event_notify("RTP_PORT_ALLOCATED", "Port: %d", x);
37873835 break;
38113859 /* Create an ICE session for ICE negotiation */
38123860 if (icesupport) {
38133861 rtp->ice_num_components = 2;
3814 ast_debug(3, "Creating ICE session %s (%d) for RTP instance '%p'\n", ast_sockaddr_stringify(&rtp->bind_address), x, instance);
3862 ast_debug_ice(2, "(%p) ICE creating session %s (%d)\n", instance,
3863 ast_sockaddr_stringify(&rtp->bind_address), x);
38153864 if (ice_create(instance, &rtp->bind_address, x, 0)) {
3816 ast_log(LOG_NOTICE, "Failed to create ICE session\n");
3865 ast_log(LOG_NOTICE, "(%p) ICE failed to create session\n", instance);
38173866 } else {
38183867 rtp->ice_port = x;
38193868 ast_sockaddr_copy(&rtp->ice_original_rtp_addr, &rtp->bind_address);
38903939 rtp->turn_rtcp = NULL;
38913940 }
38923941
3942 ast_debug_ice(2, "(%p) ICE RTP transport deallocating\n", instance);
38933943 /* Destroy any ICE session */
38943944 ast_rtp_ice_stop(instance);
38953945
42174267 rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
42184268
42194269 if (duration > 0 && (measured_samples = duration * ast_rtp_get_rate(rtp->f.subclass.format) / 1000) > rtp->send_duration) {
4220 ast_debug(2, "Adjusting final end duration from %d to %u\n", rtp->send_duration, measured_samples);
4270 ast_debug_rtp(2, "(%p) RTP adjusting final end duration from %d to %u\n",
4271 instance, rtp->send_duration, measured_samples);
42214272 rtp->send_duration = measured_samples;
42224273 }
42234274
42804331
42814332 /* We simply set this bit so that the next packet sent will have the marker bit turned on */
42824333 ast_set_flag(rtp, FLAG_NEED_MARKER_BIT);
4283 ast_debug(3, "Setting the marker bit due to a source update\n");
4334 ast_debug_rtp(3, "(%p) RTP setting the marker bit due to a source update\n", instance);
42844335
42854336 return;
42864337 }
42984349 ast_set_flag(rtp, FLAG_NEED_MARKER_BIT);
42994350 }
43004351
4301 ast_debug(3, "Changing ssrc from %u to %u due to a source change\n", rtp->ssrc, ssrc);
4352 ast_debug_rtp(3, "(%p) RTP changing ssrc from %u to %u due to a source change\n",
4353 instance, rtp->ssrc, ssrc);
43024354
43034355 if (srtp) {
4304 ast_debug(3, "Changing ssrc for SRTP from %u to %u\n", rtp->ssrc, ssrc);
4356 ast_debug_rtp(3, "(%p) RTP changing ssrc for SRTP from %u to %u\n",
4357 instance, rtp->ssrc, ssrc);
43054358 res_srtp->change_source(srtp, rtp->ssrc, ssrc);
43064359 if (rtcp_srtp != srtp) {
43074360 res_srtp->change_source(rtcp_srtp, rtp->ssrc, ssrc);
46384691 res = ast_rtcp_generate_report(instance, rtcpheader, report, sr);
46394692
46404693 if (res == 0 || res == 1) {
4641 ast_debug(1, "Failed to generate %s report!\n", sr ? "SR" : "RR");
4694 ast_debug_rtcp(1, "(%p) RTCP failed to generate %s report!\n", instance, sr ? "SR" : "RR");
46424695 return 0;
46434696 }
46444697
46474700 res = ast_rtcp_generate_sdes(instance, rtcpheader + packet_len, report);
46484701
46494702 if (res == 0 || res == 1) {
4650 ast_debug(1, "Failed to generate SDES!\n");
4703 ast_debug_rtcp(1, "(%p) RTCP failed to generate SDES!\n", instance);
46514704 return 0;
46524705 }
46534706
48554908 if (abs((int)rtp->lastts - pred) < MAX_TIMESTAMP_SKEW) {
48564909 rtp->lastts = pred;
48574910 } else {
4858 ast_debug(3, "Difference is %d, ms is %u\n", abs((int)rtp->lastts - pred), ms);
4911 ast_debug_rtp(3, "(%p) RTP audio difference is %d, ms is %u\n",
4912 instance, abs((int)rtp->lastts - pred), ms);
48594913 mark = 1;
48604914 }
48614915 }
48704924 rtp->lastts = pred;
48714925 rtp->lastovidtimestamp += frame->samples;
48724926 } else {
4873 ast_debug(3, "Difference is %d, ms is %u (%u), pred/ts/samples %u/%d/%d\n", abs((int)rtp->lastts - pred), ms, ms * 90, rtp->lastts, pred, frame->samples);
4927 ast_debug_rtp(3, "(%p) RTP video difference is %d, ms is %u (%u), pred/ts/samples %u/%d/%d\n",
4928 instance, abs((int)rtp->lastts - pred), ms, ms * 90, rtp->lastts, pred, frame->samples);
48744929 rtp->lastovidtimestamp = rtp->lastts;
48754930 }
48764931 }
48844939 rtp->lastts = pred;
48854940 rtp->lastotexttimestamp += frame->samples;
48864941 } else {
4887 ast_debug(3, "Difference is %d, ms is %u, pred/ts/samples %u/%d/%d\n", abs((int)rtp->lastts - pred), ms, rtp->lastts, pred, frame->samples);
4942 ast_debug_rtp(3, "(%p) RTP other difference is %d, ms is %u, pred/ts/samples %u/%d/%d\n",
4943 instance, abs((int)rtp->lastts - pred), ms, rtp->lastts, pred, frame->samples);
48884944 rtp->lastotexttimestamp = rtp->lastts;
48894945 }
48904946 }
50005056 res = rtp_sendto(instance, (void *)rtpheader, packet_len, 0, &remote_address, &ice);
50015057 if (res < 0) {
50025058 if (!ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT) || (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT) && (ast_test_flag(rtp, FLAG_NAT_ACTIVE) == FLAG_NAT_ACTIVE))) {
5003 ast_debug(1, "RTP Transmission error of packet %d to %s: %s\n",
5004 rtp->seqno,
5059 ast_debug_rtp(1, "(%p) RTP transmission error of packet %d to %s: %s\n",
5060 instance, rtp->seqno,
50055061 ast_sockaddr_stringify(&remote_address),
50065062 strerror(errno));
5007 } else if (((ast_test_flag(rtp, FLAG_NAT_ACTIVE) == FLAG_NAT_INACTIVE) || rtpdebug) && !ast_test_flag(rtp, FLAG_NAT_INACTIVE_NOWARN)) {
5063 } else if (((ast_test_flag(rtp, FLAG_NAT_ACTIVE) == FLAG_NAT_INACTIVE) || ast_debug_rtp_packet_is_allowed) && !ast_test_flag(rtp, FLAG_NAT_INACTIVE_NOWARN)) {
50085064 /* Only give this error message once if we are not RTP debugging */
5009 if (rtpdebug)
5010 ast_debug(0, "RTP NAT: Can't write RTP to private address %s, waiting for other end to send audio...\n",
5011 ast_sockaddr_stringify(&remote_address));
5065 if (ast_debug_rtp_packet_is_allowed)
5066 ast_debug(0, "(%p) RTP NAT: Can't write RTP to private address %s, waiting for other end to send audio...\n",
5067 instance, ast_sockaddr_stringify(&remote_address));
50125068 ast_set_flag(rtp, FLAG_NAT_INACTIVE_NOWARN);
50135069 }
50145070 } else {
50155071 if (rtp->rtcp && rtp->rtcp->schedid < 0) {
5016 ast_debug(1, "Starting RTCP transmission on RTP instance '%p'\n", instance);
5072 ast_debug_rtcp(1, "(%p) RTCP starting transmission\n", instance);
50175073 ao2_ref(instance, +1);
50185074 rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_rtcp_calc_interval(rtp), ast_rtcp_write, instance);
50195075 if (rtp->rtcp->schedid < 0) {
51595215 ao2_cleanup);
51605216
51615217 if (feedback->fmt != AST_RTP_RTCP_FMT_REMB) {
5162 ast_debug(1, "Provided an RTCP feedback frame of format %d to write on RTP instance '%p' but only REMB is supported\n",
5163 feedback->fmt, instance);
5218 ast_debug_rtcp(1, "(%p) RTCP provided feedback frame of format %d to write, but only REMB is supported\n",
5219 instance, feedback->fmt);
51645220 return;
51655221 }
51665222
51705226
51715227 /* If REMB support is not enabled don't send this RTCP packet */
51725228 if (!ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_REMB)) {
5173 ast_debug(1, "Provided an RTCP feedback REMB report to write on RTP instance '%p' but REMB support not enabled\n",
5229 ast_debug_rtcp(1, "(%p) RTCP provided feedback REMB report to write, but REMB support not enabled\n",
51745230 instance);
51755231 return;
51765232 }
52225278
52235279 /* If we don't actually know the remote address don't even bother doing anything */
52245280 if (ast_sockaddr_isnull(&remote_address)) {
5225 ast_debug(1, "No remote address on RTP instance '%p' so dropping frame\n", instance);
5281 ast_debug_rtp(1, "(%p) RTP no remote address on instance, so dropping frame\n", instance);
52265282 return 0;
52275283 }
52285284
52395295
52405296 /* If there is no data length we can't very well send the packet */
52415297 if (!frame->datalen) {
5242 ast_debug(1, "Received frame with no data for RTP instance '%p' so dropping frame\n", instance);
5298 ast_debug_rtp(1, "(%p) RTP received frame with no data for instance, so dropping frame\n", instance);
52435299 return 0;
52445300 }
52455301
52715327 format = frame->subclass.format;
52725328 if (ast_format_cmp(rtp->lasttxformat, format) == AST_FORMAT_CMP_NOT_EQUAL) {
52735329 /* Oh dear, if the format changed we will have to set up a new smoother */
5274 ast_debug(1, "Ooh, format changed from %s to %s\n",
5275 ast_format_get_name(rtp->lasttxformat),
5330 ast_debug_rtp(1, "(%p) RTP ooh, format changed from %s to %s\n",
5331 instance, ast_format_get_name(rtp->lasttxformat),
52765332 ast_format_get_name(frame->subclass.format));
52775333 ao2_replace(rtp->lasttxformat, format);
52785334 if (rtp->smoother) {
53975453 ast_rtp_instance_get_remote_address(instance, &remote_address);
53985454
53995455 if (((compensate && type == AST_FRAME_DTMF_END) || (type == AST_FRAME_DTMF_BEGIN)) && ast_tvcmp(ast_tvnow(), rtp->dtmfmute) < 0) {
5400 ast_debug(1, "Ignore potential DTMF echo from '%s'\n",
5401 ast_sockaddr_stringify(&remote_address));
5456 ast_debug_rtp(1, "(%p) RTP ignore potential DTMF echo from '%s'\n",
5457 instance, ast_sockaddr_stringify(&remote_address));
54025458 rtp->resp = 0;
54035459 rtp->dtmfsamples = 0;
54045460 return &ast_null_frame;
54055461 }
5406 ast_debug(1, "Creating %s DTMF Frame: %d (%c), at %s\n",
5407 type == AST_FRAME_DTMF_END ? "END" : "BEGIN",
5462 ast_debug_rtp(1, "(%p) RTP creating %s DTMF Frame: %d (%c), at %s\n",
5463 instance, type == AST_FRAME_DTMF_END ? "END" : "BEGIN",
54085464 rtp->resp, rtp->resp,
54095465 ast_sockaddr_stringify(&remote_address));
54105466 if (rtp->resp == 'X') {
54495505 }
54505506
54515507 /* Print out debug if turned on */
5452 if (rtpdebug)
5508 if (ast_debug_rtp_packet_is_allowed)
54535509 ast_debug(0, "- RTP 2833 Event: %08x (len = %d)\n", event, len);
54545510
54555511 /* Figure out what digit was pressed */
54655521 resp = 'X';
54665522 } else {
54675523 /* Not a supported event */
5468 ast_debug(1, "Ignoring RTP 2833 Event: %08x. Not a DTMF Digit.\n", event);
5524 ast_debug_rtp(1, "(%p) RTP ignoring RTP 2833 Event: %08x. Not a DTMF Digit.\n", instance, event);
54695525 return;
54705526 }
54715527
55035559 rtp->resp = 0;
55045560 rtp->dtmf_duration = rtp->dtmf_timeout = 0;
55055561 AST_LIST_INSERT_TAIL(frames, f, frame_list);
5506 } else if (rtpdebug) {
5507 ast_debug(1, "Dropping duplicate or out of order DTMF END frame (seqno: %u, ts %u, digit %c)\n",
5508 seqno, timestamp, resp);
5562 } else if (ast_debug_rtp_packet_is_allowed) {
5563 ast_debug_rtp(1, "(%p) RTP dropping duplicate or out of order DTMF END frame (seqno: %u, ts %u, digit %c)\n",
5564 instance, seqno, timestamp, resp);
55095565 }
55105566 } else {
55115567 /* Begin/continuation */
55205576 * improperly duplicate incoming DTMF, so just drop
55215577 * this.
55225578 */
5523 if (rtpdebug) {
5524 ast_debug(1, "Dropping out of order DTMF frame (seqno %u, ts %u, digit %c)\n",
5579 if (ast_debug_rtp_packet_is_allowed) {
5580 ast_debug(0, "Dropping out of order DTMF frame (seqno %u, ts %u, digit %c)\n",
55255581 seqno, timestamp, resp);
55265582 }
55275583 return;
56055661 power = data[2];
56065662 event = data[3] & 0x1f;
56075663
5608 if (rtpdebug)
5664 if (ast_debug_rtp_packet_is_allowed)
56095665 ast_debug(0, "Cisco DTMF Digit: %02x (len=%d, seq=%d, flags=%02x, power=%u, history count=%d)\n", event, len, seq, flags, power, (len - 4) / 2);
56105666 if (event < 10) {
56115667 resp = '0' + event;
56455701 /* Convert comfort noise into audio with various codecs. Unfortunately this doesn't
56465702 totally help us out becuase we don't have an engine to keep it going and we are not
56475703 guaranteed to have it every 20ms or anything */
5648 if (rtpdebug) {
5704 if (ast_debug_rtp_packet_is_allowed) {
56495705 ast_debug(0, "- RTP 3389 Comfort noise event: Format %s (len = %d)\n",
56505706 ast_format_get_name(rtp->lastrxformat), len);
56515707 }
58875943 unsigned int packets_not_found = 0;
58885944
58895945 if (!rtp->send_buffer) {
5890 ast_debug(1, "Tried to handle NACK request, but we don't have a RTP packet storage!\n");
5946 ast_debug_rtcp(1, "(%p) RTCP tried to handle NACK request, "
5947 "but we don't have a RTP packet storage!\n", instance);
58915948 return res;
58925949 }
58935950
59165973 }
59175974 res += rtp_sendto(instance, payload->buf, payload->size, 0, &remote_address, &ice);
59185975 } else {
5919 ast_debug(1, "Received NACK request for RTP packet with seqno %d, but we don't have it\n", pid);
5976 ast_debug_rtcp(1, "(%p) RTCP received NACK request for RTP packet with seqno %d, "
5977 "but we don't have it\n", instance, pid);
59205978 packets_not_found++;
59215979 }
59225980 /*
59385996 }
59395997 res += rtp_sendto(instance, payload->buf, payload->size, 0, &remote_address, &ice);
59405998 } else {
5941 ast_debug(1, "Remote end also requested RTP packet with seqno %d, but we don't have it\n", seqno);
5999 ast_debug_rtcp(1, "(%p) RTCP remote end also requested RTP packet with seqno %d, "
6000 "but we don't have it\n", instance, seqno);
59426001 packets_not_found++;
59436002 }
59446003 }
59536012 */
59546013 ast_data_buffer_resize(rtp->send_buffer, MIN(MAXIMUM_RTP_SEND_BUFFER_SIZE,
59556014 ast_data_buffer_max(rtp->send_buffer) + packets_not_found));
5956 ast_debug(2, "Send buffer on RTP instance '%p' is now at maximum of %zu\n", instance, ast_data_buffer_max(rtp->send_buffer));
6015 ast_debug_rtcp(2, "(%p) RTCP send buffer on RTP instance is now at maximum of %zu\n",
6016 instance, ast_data_buffer_max(rtp->send_buffer));
59576017 }
59586018
59596019 return res;
60276087
60286088 packetwords = len / 4;
60296089
6030 ast_debug(1, "Got RTCP report of %d bytes from %s\n",
6031 len, ast_sockaddr_stringify(addr));
6090 ast_debug_rtcp(1, "(%p) RTCP got report of %d bytes from %s\n",
6091 instance, len, ast_sockaddr_stringify(addr));
60326092
60336093 /*
60346094 * Validate the RTCP packet according to an adapted and slightly
60356095 * modified RFC3550 validation algorithm.
60366096 */
60376097 if (packetwords < RTCP_HEADER_SSRC_LENGTH) {
6038 ast_debug(1, "%p -- RTCP from %s: Frame size (%u words) is too short\n",
6039 transport_rtp, ast_sockaddr_stringify(addr), packetwords);
6098 ast_debug_rtcp(1, "(%p) RTCP %p -- from %s: Frame size (%u words) is too short\n",
6099 instance, transport_rtp, ast_sockaddr_stringify(addr), packetwords);
60406100 return &ast_null_frame;
60416101 }
60426102 position = 0;
60436103 first_word = ntohl(rtcpheader[position]);
60446104 if ((first_word & RTCP_VALID_MASK) != RTCP_VALID_VALUE) {
6045 ast_debug(1, "%p -- RTCP from %s: Failed first packet validity check\n",
6046 transport_rtp, ast_sockaddr_stringify(addr));
6105 ast_debug_rtcp(1, "(%p) RTCP %p -- from %s: Failed first packet validity check\n",
6106 instance, transport_rtp, ast_sockaddr_stringify(addr));
60476107 return &ast_null_frame;
60486108 }
60496109 do {
60546114 first_word = ntohl(rtcpheader[position]);
60556115 } while ((first_word & RTCP_VERSION_MASK_SHIFTED) == RTCP_VERSION_SHIFTED);
60566116 if (position != packetwords) {
6057 ast_debug(1, "%p -- RTCP from %s: Failed packet version or length check\n",
6058 transport_rtp, ast_sockaddr_stringify(addr));
6117 ast_debug_rtcp(1, "(%p) RTCP %p -- from %s: Failed packet version or length check\n",
6118 instance, transport_rtp, ast_sockaddr_stringify(addr));
60596119 return &ast_null_frame;
60606120 }
60616121
61456205 min_length = length;
61466206 break;
61476207 default:
6148 ast_debug(1, "%p -- RTCP from %s: %u(%s) skipping record\n",
6149 transport_rtp, ast_sockaddr_stringify(addr), pt, rtcp_payload_type2str(pt));
6208 ast_debug_rtcp(1, "(%p) RTCP %p -- from %s: %u(%s) skipping record\n",
6209 instance, transport_rtp, ast_sockaddr_stringify(addr), pt, rtcp_payload_type2str(pt));
61506210 if (rtcp_debug_test_addr(addr)) {
61516211 ast_verbose("\n");
61526212 ast_verbose("RTCP from %s: %u(%s) skipping record\n",
61566216 continue;
61576217 }
61586218 if (length < min_length) {
6159 ast_debug(1, "%p -- RTCP from %s: %u(%s) length field less than expected minimum. Min:%u Got:%u\n",
6160 transport_rtp, ast_sockaddr_stringify(addr), pt, rtcp_payload_type2str(pt),
6219 ast_debug_rtcp(1, "(%p) RTCP %p -- from %s: %u(%s) length field less than expected minimum. Min:%u Got:%u\n",
6220 instance, transport_rtp, ast_sockaddr_stringify(addr), pt, rtcp_payload_type2str(pt),
61616221 min_length - 1, length - 1);
61626222 return &ast_null_frame;
61636223 }
62476307 * for a different stream.
62486308 */
62496309 position += length;
6250 ast_debug(1, "%p -- RTCP from %s: Skipping record, received SSRC '%u' != expected '%u'\n",
6251 rtp, ast_sockaddr_stringify(addr), ssrc, rtp->themssrc);
6310 ast_debug_rtcp(1, "(%p) RTCP %p -- from %s: Skipping record, received SSRC '%u' != expected '%u'\n",
6311 instance, rtp, ast_sockaddr_stringify(addr), ssrc, rtp->themssrc);
62526312 if (child) {
62536313 ao2_unlock(child);
62546314 }
62616321 /* Send to whoever sent to us */
62626322 if (ast_sockaddr_cmp(&rtp->rtcp->them, addr)) {
62636323 ast_sockaddr_copy(&rtp->rtcp->them, addr);
6264 if (rtpdebug) {
6265 ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s\n",
6266 ast_sockaddr_stringify(addr));
6324 if (ast_debug_rtp_packet_is_allowed) {
6325 ast_debug(0, "(%p) RTCP NAT: Got RTCP from other end. Now sending to address %s\n",
6326 instance, ast_sockaddr_stringify(addr));
62676327 }
62686328 }
62696329 }
65266586 if (ast_sockaddr_is_ipv4(&addr)) {
65276587 ast_sockaddr_to_sin(&addr, &addr_tmp);
65286588 } else if (ast_sockaddr_ipv4_mapped(&addr, &addr_v4)) {
6529 ast_debug(1, "Using IPv6 mapped address %s for STUN\n",
6530 ast_sockaddr_stringify(&addr));
6589 ast_debug_stun(2, "(%p) STUN using IPv6 mapped address %s\n",
6590 instance, ast_sockaddr_stringify(&addr));
65316591 ast_sockaddr_to_sin(&addr_v4, &addr_tmp);
65326592 } else {
6533 ast_debug(1, "Cannot do STUN for non IPv4 address %s\n",
6534 ast_sockaddr_stringify(&addr));
6593 ast_debug_stun(2, "(%p) STUN cannot do for non IPv4 address %s\n",
6594 instance, ast_sockaddr_stringify(&addr));
65356595 return &ast_null_frame;
65366596 }
65376597 if ((ast_stun_handle_packet(rtp->rtcp->s, &addr_tmp, read_area, res, NULL, NULL) == AST_STUN_ACCEPT)) {
65786638
65796639 /* If the payload coming in is not one of the negotiated ones then send it to the core, this will cause formats to change and the bridge to break */
65806640 if (ast_rtp_codecs_find_payload_code(ast_rtp_instance_get_codecs(instance1), bridged_payload) == -1) {
6581 ast_debug(1, "Unsupported payload type received \n");
6641 ast_debug_rtp(1, "(%p, %p) RTP unsupported payload type received\n", instance, instance1);
65826642 return -1;
65836643 }
65846644
65886648 * core so they can be filtered accordingly.
65896649 */
65906650 if (rtp->last_end_timestamp == timestamp) {
6591 ast_debug(1, "Feeding packet with duplicate timestamp to core\n");
6651 ast_debug_rtp(1, "(%p, %p) RTP feeding packet with duplicate timestamp to core\n", instance, instance1);
65926652 return -1;
65936653 }
65946654
66206680
66216681 /* If bridged peer is in dtmf, feed all packets to core until it finishes to avoid infinite dtmf */
66226682 if (bridged->sending_digit) {
6623 ast_debug(1, "Feeding packet to core until DTMF finishes\n");
6683 ast_debug_rtp(1, "(%p, %p) RTP Feeding packet to core until DTMF finishes\n", instance, instance1);
66246684 ao2_unlock(instance1);
66256685 ao2_lock(instance);
66266686 return -1;
66346694 if (!bridged->asymmetric_codec
66356695 && bridged->lastrxformat != ast_format_none
66366696 && ast_format_cmp(payload_type->format, bridged->lastrxformat) == AST_FORMAT_CMP_NOT_EQUAL) {
6637 ast_debug(1, "Asymmetric RTP codecs detected (TX: %s, RX: %s) sending frame to core\n",
6638 ast_format_get_name(payload_type->format),
6697 ast_debug_rtp(1, "(%p, %p) RTP asymmetric RTP codecs detected (TX: %s, RX: %s) sending frame to core\n",
6698 instance, instance1, ast_format_get_name(payload_type->format),
66396699 ast_format_get_name(bridged->lastrxformat));
66406700 ao2_unlock(instance1);
66416701 ao2_lock(instance);
66486708 ast_rtp_instance_get_remote_address(instance1, &remote_address);
66496709
66506710 if (ast_sockaddr_isnull(&remote_address)) {
6651 ast_debug(5, "Remote address is null, most likely RTP has been stopped\n");
6711 ast_debug_rtp(5, "(%p, %p) RTP remote address is null, most likely RTP has been stopped\n",
6712 instance, instance1);
66526713 ao2_unlock(instance1);
66536714 ao2_lock(instance);
66546715 return 0;
66856746 "RTP Transmission error of packet to %s: %s\n",
66866747 ast_sockaddr_stringify(&remote_address),
66876748 strerror(errno));
6688 } else if (((ast_test_flag(bridged, FLAG_NAT_ACTIVE) == FLAG_NAT_INACTIVE) || rtpdebug) && !ast_test_flag(bridged, FLAG_NAT_INACTIVE_NOWARN)) {
6689 if (rtpdebug || DEBUG_ATLEAST(1)) {
6749 } else if (((ast_test_flag(bridged, FLAG_NAT_ACTIVE) == FLAG_NAT_INACTIVE) || ast_debug_rtp_packet_is_allowed) && !ast_test_flag(bridged, FLAG_NAT_INACTIVE_NOWARN)) {
6750 if (ast_debug_rtp_packet_is_allowed || DEBUG_ATLEAST(1)) {
66906751 ast_log(LOG_WARNING,
66916752 "RTP NAT: Can't write RTP to private "
66926753 "address %s, waiting for other end to "
69647025 /* The packet is now fully constructed so send it out */
69657026 ast_sockaddr_copy(&remote_address, &rtp->rtcp->them);
69667027
6967 ast_debug(2, "Sending transport-cc feedback packet of size '%d' on '%s' with packet count of %d (small = %d, large = %d, lost = %d)\n",
6968 packet_len, ast_rtp_instance_get_channel_id(instance), packet_count, small_delta_count, large_delta_count, lost_count);
7028 ast_debug_rtcp(2, "(%p) RTCP sending transport-cc feedback packet of size '%d' on '%s' with packet count of %d (small = %d, large = %d, lost = %d)\n",
7029 instance, packet_len, ast_rtp_instance_get_channel_id(instance), packet_count, small_delta_count, large_delta_count, lost_count);
69697030
69707031 res = rtcp_sendto(instance, (unsigned int *)rtcpheader, packet_len, 0, &remote_address, &ice);
69717032 if (res < 0) {
70257086
70267087 /* If we have not yet scheduled the periodic sending of feedback for this transport then do so */
70277088 if (transport_rtp->transport_wide_cc.schedid < 0 && transport_rtp->rtcp) {
7028 ast_debug(1, "Starting RTCP transport-cc feedback transmission on RTP instance '%p'\n", transport);
7089 ast_debug_rtcp(1, "(%p) RTCP starting transport-cc feedback transmission on RTP instance '%p'\n", instance, transport);
70297090 ao2_ref(transport, +1);
70307091 transport_rtp->transport_wide_cc.schedid = ast_sched_add(rtp->sched, 1000,
70317092 rtp_transport_wide_cc_feedback_produce, transport);
74597520 if (ast_sockaddr_is_ipv4(&addr)) {
74607521 ast_sockaddr_to_sin(&addr, &addr_tmp);
74617522 } else if (ast_sockaddr_ipv4_mapped(&addr, &addr_v4)) {
7462 ast_debug(1, "Using IPv6 mapped address %s for STUN\n",
7463 ast_sockaddr_stringify(&addr));
7523 ast_debug_stun(1, "(%p) STUN using IPv6 mapped address %s\n",
7524 instance, ast_sockaddr_stringify(&addr));
74647525 ast_sockaddr_to_sin(&addr_v4, &addr_tmp);
74657526 } else {
7466 ast_debug(1, "Cannot do STUN for non IPv4 address %s\n",
7467 ast_sockaddr_stringify(&addr));
7527 ast_debug_stun(1, "(%p) STUN cannot do for non IPv4 address %s\n",
7528 instance, ast_sockaddr_stringify(&addr));
74687529 return &ast_null_frame;
74697530 }
74707531 if ((ast_stun_handle_packet(rtp->s, &addr_tmp, read_area, res, NULL, NULL) == AST_STUN_ACCEPT) &&
76107671 break;
76117672 }
76127673 /* Not ready to accept the RTP stream candidate */
7613 ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection. Will switch to it in %d packets.\n",
7614 rtp, ast_sockaddr_stringify(&addr), rtp->rtp_source_learn.packets);
7674 ast_debug_rtp(1, "(%p) RTP %p -- Received packet from %s, dropping due to strict RTP protection. Will switch to it in %d packets.\n",
7675 instance, rtp, ast_sockaddr_stringify(&addr), rtp->rtp_source_learn.packets);
76157676 } else {
76167677 /*
76177678 * This is either an attacking stream or
76197680 */
76207681 ast_sockaddr_copy(&rtp->rtp_source_learn.proposed_address, &addr);
76217682 rtp_learning_seq_init(&rtp->rtp_source_learn, seqno);
7622 ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection. Qualifying new stream.\n",
7623 rtp, ast_sockaddr_stringify(&addr));
7683 ast_debug_rtp(1, "(%p) RTP %p -- Received packet from %s, dropping due to strict RTP protection. Qualifying new stream.\n",
7684 instance, rtp, ast_sockaddr_stringify(&addr));
76247685 }
76257686 return &ast_null_frame;
76267687 }
76387699 if (!ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) {
76397700 break;
76407701 }
7641 ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection.\n",
7642 rtp, ast_sockaddr_stringify(&addr));
7702 ast_debug_rtp(1, "(%p) RTP %p -- Received packet from %s, dropping due to strict RTP protection.\n",
7703 instance, rtp, ast_sockaddr_stringify(&addr));
76437704 #ifdef TEST_FRAMEWORK
76447705 {
76457706 static int strict_rtp_test_event = 1;
76667727 ast_sockaddr_set_port(&rtp->rtcp->them, ast_sockaddr_port(&addr) + 1);
76677728 }
76687729 ast_set_flag(rtp, FLAG_NAT_ACTIVE);
7669 if (rtpdebug)
7670 ast_debug(0, "RTP NAT: Got audio from other end. Now sending to address %s\n",
7671 ast_sockaddr_stringify(&remote_address));
7730 if (ast_debug_rtp_packet_is_allowed)
7731 ast_debug(0, "(%p) RTP NAT: Got audio from other end. Now sending to address %s\n",
7732 instance, ast_sockaddr_stringify(&remote_address));
76727733 }
76737734 }
76747735
76967757 };
76977758
76987759 if (!mark) {
7699 if (rtpdebug) {
7700 ast_debug(1, "Forcing Marker bit, because SSRC has changed\n");
7760 if (ast_debug_rtp_packet_is_allowed) {
7761 ast_debug(0, "(%p) RTP forcing Marker bit, because SSRC has changed\n", instance);
77017762 }
77027763 mark = 1;
77037764 }
77497810
77507811 if (!AST_VECTOR_REMOVE_CMP_ORDERED(&rtp->missing_seqno, seqno, find_by_value,
77517812 AST_VECTOR_ELEM_CLEANUP_NOOP)) {
7752 ast_debug(2, "Packet with sequence number '%d' on RTP instance '%p' is no longer missing\n",
7753 seqno, instance);
7813 ast_debug_rtp(2, "(%p) RTP Packet with sequence number '%d' on instance is no longer missing\n",
7814 instance, seqno);
77547815 }
77557816
77567817 /* If we don't have the next packet after this we can directly return the frame, as there is no
77927853 return AST_LIST_FIRST(&frames);
77937854 }
77947855
7795 ast_debug(2, "Pulled buffered packet with sequence number '%d' to additionally return on RTP instance '%p'\n",
7796 frame->seqno, instance);
7856 ast_debug_rtp(2, "(%p) RTP pulled buffered packet with sequence number '%d' to additionally return\n",
7857 instance, frame->seqno);
77977858 AST_LIST_INSERT_TAIL(&frames, frame, frame_list);
77987859 prev_seqno = rtp->expectedrxseqno;
77997860 rtp->expectedrxseqno++;
78147875 */
78157876
78167877 if (rtp->rtp_source_learn.stream_type == AST_MEDIA_TYPE_VIDEO) {
7817 ast_debug(2, "Source on RTP instance '%p' has wild gap or packet loss, sending FIR\n",
7878 ast_debug_rtp(2, "(%p) RTP source has wild gap or packet loss, sending FIR\n",
78187879 instance);
78197880 rtp_write_rtcp_fir(instance, rtp, &remote_address);
78207881 }
78327893 if (frame) {
78337894 AST_LIST_INSERT_TAIL(&frames, frame, frame_list);
78347895 prev_seqno = seqno;
7835 ast_debug(2, "Inserted just received packet with sequence number '%d' in correct order on RTP instance '%p'\n",
7836 seqno, instance);
7896 ast_debug_rtp(2, "(%p) RTP inserted just received packet with sequence number '%d' in correct order\n",
7897 instance, seqno);
78377898 }
78387899 /* It is possible due to packet retransmission for this packet to also exist in the receive
78397900 * buffer so we explicitly remove it in case this occurs, otherwise the receive buffer will
78577918 if (frame) {
78587919 AST_LIST_INSERT_TAIL(&frames, frame, frame_list);
78597920 prev_seqno = rtp->expectedrxseqno;
7860 ast_debug(2, "Emptying queue and returning packet with sequence number '%d' from RTP instance '%p'\n",
7861 frame->seqno, instance);
7921 ast_debug_rtp(2, "(%p) RTP emptying queue and returning packet with sequence number '%d'\n",
7922 instance, frame->seqno);
78627923 }
78637924 ast_free(payload);
78647925 }
78827943 rtp->expectedrxseqno = 0;
78837944 }
78847945
7885 ast_debug(2, "Adding just received packet with sequence number '%d' to end of dumped queue on RTP instance '%p'\n",
7886 seqno, instance);
7946 ast_debug_rtp(2, "(%p) RTP adding just received packet with sequence number '%d' to end of dumped queue\n",
7947 instance, seqno);
78877948 }
78887949
78897950 /* When we flush increase our chance for next time by growing the receive buffer when possible
78917952 */
78927953 ast_data_buffer_resize(rtp->recv_buffer, MIN(MAXIMUM_RTP_RECV_BUFFER_SIZE,
78937954 ast_data_buffer_max(rtp->recv_buffer) + AST_VECTOR_SIZE(&rtp->missing_seqno)));
7894 ast_debug(2, "Receive buffer on RTP instance '%p' is now at maximum of %zu\n", instance, ast_data_buffer_max(rtp->recv_buffer));
7955 ast_debug_rtp(2, "(%p) RTP receive buffer is now at maximum of %zu\n", instance, ast_data_buffer_max(rtp->recv_buffer));
78957956
78967957 /* As there is such a large gap we don't want to flood the order side with missing packets, so we
78977958 * give up and start anew.
79177978 if ((seqno < rtp->expectedrxseqno && ((rtp->expectedrxseqno - seqno) <= OLD_PACKET_COUNT)) ||
79187979 (seqno > rtp->expectedrxseqno && (seqno >= (65535 - OLD_PACKET_COUNT + rtp->expectedrxseqno)))) {
79197980 /* If this is a packet from the past then we have received a duplicate packet, so just drop it */
7920 ast_debug(2, "Received an old packet with sequence number '%d' on RTP instance '%p', dropping it\n",
7921 seqno, instance);
7981 ast_debug_rtp(2, "(%p) RTP received an old packet with sequence number '%d', dropping it\n",
7982 instance, seqno);
79227983 return &ast_null_frame;
79237984 } else if (ast_data_buffer_get(rtp->recv_buffer, seqno)) {
79247985 /* If this is a packet we already have buffered then it is a duplicate, so just drop it */
7925 ast_debug(2, "Received a duplicate transmission of packet with sequence number '%d' on RTP instance '%p', dropping it\n",
7926 seqno, instance);
7986 ast_debug_rtp(2, "(%p) RTP received a duplicate transmission of packet with sequence number '%d', dropping it\n",
7987 instance, seqno);
79277988 return &ast_null_frame;
79287989 } else {
79297990 /* This is an out of order packet from the future */
79327993 int remove_failed;
79337994 unsigned int missing_seqnos_added = 0;
79347995
7935 ast_debug(2, "Received an out of order packet with sequence number '%d' while expecting '%d' from the future on RTP instance '%p'\n",
7936 seqno, rtp->expectedrxseqno, instance);
7996 ast_debug_rtp(2, "(%p) RTP received an out of order packet with sequence number '%d' while expecting '%d' from the future\n",
7997 instance, seqno, rtp->expectedrxseqno);
79377998
79387999 payload = ast_malloc(sizeof(*payload) + res);
79398000 if (!payload) {
79608021 remove_failed = AST_VECTOR_REMOVE_CMP_ORDERED(&rtp->missing_seqno, seqno, find_by_value,
79618022 AST_VECTOR_ELEM_CLEANUP_NOOP);
79628023 if (!remove_failed) {
7963 ast_debug(2, "Packet with sequence number '%d' on RTP instance '%p' is no longer missing\n",
7964 seqno, instance);
8024 ast_debug_rtp(2, "(%p) RTP packet with sequence number '%d' is no longer missing\n",
8025 instance, seqno);
79658026 }
79668027
79678028 /* The missing sequence number code works by taking the sequence number of the
80078068 continue;
80088069 }
80098070
8010 ast_debug(2, "Added missing sequence number '%d' to RTP instance '%p'\n",
8011 missing_seqno, instance);
8071 ast_debug_rtp(2, "(%p) RTP added missing sequence number '%d'\n",
8072 instance, missing_seqno);
80128073 AST_VECTOR_ADD_SORTED(&rtp->missing_seqno, missing_seqno,
80138074 compare_by_value);
80148075 missing_seqnos_added++;
80388099 */
80398100 rtcpheader = ast_malloc(sizeof(*rtcpheader) + data_size);
80408101 if (!rtcpheader) {
8041 ast_debug(1, "Failed to allocate memory for NACK\n");
8102 ast_debug_rtcp(1, "(%p) RTCP failed to allocate memory for NACK\n", instance);
80428103 return &ast_null_frame;
80438104 }
80448105
80558116 res = ast_rtcp_generate_nack(instance, rtcpheader + packet_len);
80568117
80578118 if (res == 0) {
8058 ast_debug(1, "Failed to construct NACK, stopping here\n");
8119 ast_debug_rtcp(1, "(%p) RTCP failed to construct NACK, stopping here\n", instance);
80598120 return &ast_null_frame;
80608121 }
80618122
80638124
80648125 res = rtcp_sendto(instance, rtcpheader, packet_len, 0, &remote_address, &ice);
80658126 if (res < 0) {
8066 ast_debug(1, "Failed to send NACK request out\n");
8127 ast_debug_rtcp(1, "(%p) RTCP failed to send NACK request out\n", instance);
80678128 } else {
8068 ast_debug(2, "Sending a NACK request on RTP instance '%p' to get missing packets\n", instance);
8129 ast_debug_rtcp(2, "(%p) RTCP sending a NACK request to get missing packets\n", instance);
80698130 /* Update RTCP SR/RR statistics */
80708131 ast_rtcp_calculate_sr_rr_statistics(instance, rtcp_report, remote_address, ice, sr);
80718132 }
80858146 struct ast_sockaddr local_addr;
80868147
80878148 if (rtp->rtcp && rtp->rtcp->type == value) {
8088 ast_debug(1, "Ignoring duplicate RTCP property on RTP instance '%p'\n", instance);
8149 ast_debug_rtcp(1, "(%p) RTCP ignoring duplicate property\n", instance);
80898150 return;
80908151 }
80918152
81378198 AF_INET :
81388199 ast_sockaddr_is_ipv6(&rtp->rtcp->us) ?
81398200 AF_INET6 : -1)) < 0) {
8140 ast_debug(1, "Failed to create a new socket for RTCP on instance '%p'\n", instance);
8201 ast_debug_rtcp(1, "(%p) RTCP failed to create a new socket\n", instance);
81418202 ast_free(rtp->rtcp->local_addr_str);
81428203 ast_free(rtp->rtcp);
81438204 rtp->rtcp = NULL;
81468207
81478208 /* Try to actually bind to the IP address and port we are going to use for RTCP, if this fails we have to bail out */
81488209 if (ast_bind(rtp->rtcp->s, &rtp->rtcp->us)) {
8149 ast_debug(1, "Failed to setup RTCP on RTP instance '%p'\n", instance);
8210 ast_debug_rtcp(1, "(%p) RTCP failed to setup RTP instance\n", instance);
81508211 close(rtp->rtcp->s);
81518212 ast_free(rtp->rtcp->local_addr_str);
81528213 ast_free(rtp->rtcp);
81868247 #endif
81878248 }
81888249
8189 ast_debug(1, "Setup RTCP on RTP instance '%p'\n", instance);
8250 ast_debug_rtcp(1, "(%p) RTCP setup on RTP instance\n", instance);
81908251 } else {
81918252 if (rtp->rtcp) {
81928253 if (rtp->rtcp->schedid > -1) {
81968257 ao2_ref(instance, -1);
81978258 } else {
81988259 /* Unable to cancel scheduler entry */
8199 ast_debug(1, "Failed to tear down RTCP on RTP instance '%p'\n", instance);
8260 ast_debug_rtcp(1, "(%p) RTCP failed to tear down RTCP\n", instance);
82008261 ao2_lock(instance);
82018262 return;
82028263 }
82088269 if (!ast_sched_del(rtp->sched, rtp->transport_wide_cc.schedid)) {
82098270 ao2_ref(instance, -1);
82108271 } else {
8211 ast_debug(1, "Failed to tear down RTCP transport-cc feedback on RTP instance '%p'\n", instance);
8272 ast_debug_rtcp(1, "(%p) RTCP failed to tear down transport-cc feedback\n", instance);
82128273 ao2_lock(instance);
82138274 return;
82148275 }
82888349 }
82898350
82908351 if (rtp->rtcp && !ast_sockaddr_isnull(addr)) {
8291 ast_debug(1, "Setting RTCP address on RTP instance '%p'\n", instance);
8352 ast_debug_rtcp(1, "(%p) RTCP setting address on RTP instance\n", instance);
82928353 ast_sockaddr_copy(&rtp->rtcp->them, addr);
82938354
82948355 if (rtp->rtcp->type == AST_RTP_INSTANCE_RTCP_STANDARD) {
87848845 }
87858846 #endif
87868847
8787 ast_debug(3, "ast_rtp_activate (%p) - setup and perform DTLS'\n", rtp);
8848 ast_debug_dtls(3, "(%p) DTLS - ast_rtp_activate rtp=%p - setup and perform DTLS'\n", instance, rtp);
87888849
87898850 dtls_perform_setup(&rtp->dtls);
87908851 dtls_perform_handshake(instance, &rtp->dtls, 0);
88098870 return CLI_FAILURE;
88108871 }
88118872 rtpdebugport = (!ast_strlen_zero(debugport) && debugport[0] != '0');
8812 ast_cli(a->fd, "RTP Debugging Enabled for address: %s\n",
8873 ast_cli(a->fd, "RTP Packet Debugging Enabled for address: %s\n",
88138874 ast_sockaddr_stringify(&rtpdebugaddr));
8814 rtpdebug = 1;
8875 ast_debug_category_set_sublevel(AST_LOG_CATEGORY_RTP_PACKET, AST_LOG_CATEGORY_ENABLED);
88158876 return CLI_SUCCESS;
88168877 }
88178878
88268887 return CLI_FAILURE;
88278888 }
88288889 rtcpdebugport = (!ast_strlen_zero(debugport) && debugport[0] != '0');
8829 ast_cli(a->fd, "RTCP Debugging Enabled for address: %s\n",
8890 ast_cli(a->fd, "RTCP Packet Debugging Enabled for address: %s\n",
88308891 ast_sockaddr_stringify(&rtcpdebugaddr));
8831 rtcpdebug = 1;
8892 ast_debug_category_set_sublevel(AST_LOG_CATEGORY_RTCP_PACKET, AST_LOG_CATEGORY_ENABLED);
88328893 return CLI_SUCCESS;
88338894 }
88348895
88498910
88508911 if (a->argc == e->args) { /* set on or off */
88518912 if (!strncasecmp(a->argv[e->args-1], "on", 2)) {
8852 rtpdebug = 1;
8913 ast_debug_category_set_sublevel(AST_LOG_CATEGORY_RTP_PACKET, AST_LOG_CATEGORY_ENABLED);
88538914 memset(&rtpdebugaddr, 0, sizeof(rtpdebugaddr));
8854 ast_cli(a->fd, "RTP Debugging Enabled\n");
8915 ast_cli(a->fd, "RTP Packet Debugging Enabled\n");
88558916 return CLI_SUCCESS;
88568917 } else if (!strncasecmp(a->argv[e->args-1], "off", 3)) {
8857 rtpdebug = 0;
8858 ast_cli(a->fd, "RTP Debugging Disabled\n");
8918 ast_debug_category_set_sublevel(AST_LOG_CATEGORY_RTP_PACKET, AST_LOG_CATEGORY_DISABLED);
8919 ast_cli(a->fd, "RTP Packet Debugging Disabled\n");
88598920 return CLI_SUCCESS;
88608921 }
88618922 } else if (a->argc == e->args +1) { /* ip */
89208981
89218982 if (a->argc == e->args) { /* set on or off */
89228983 if (!strncasecmp(a->argv[e->args-1], "on", 2)) {
8923 rtcpdebug = 1;
8984 ast_debug_category_set_sublevel(AST_LOG_CATEGORY_RTCP_PACKET, AST_LOG_CATEGORY_ENABLED);
89248985 memset(&rtcpdebugaddr, 0, sizeof(rtcpdebugaddr));
8925 ast_cli(a->fd, "RTCP Debugging Enabled\n");
8986 ast_cli(a->fd, "RTCP Packet Debugging Enabled\n");
89268987 return CLI_SUCCESS;
89278988 } else if (!strncasecmp(a->argv[e->args-1], "off", 3)) {
8928 rtcpdebug = 0;
8929 ast_cli(a->fd, "RTCP Debugging Disabled\n");
8989 ast_debug_category_set_sublevel(AST_LOG_CATEGORY_RTCP_PACKET, AST_LOG_CATEGORY_DISABLED);
8990 ast_cli(a->fd, "RTCP Packet Debugging Disabled\n");
89308991 return CLI_SUCCESS;
89318992 }
89328993 } else if (a->argc == e->args +1) { /* ip */
424424 );
425425 };
426426
427 /*! AO2 comparison function for bridges moh container */
428 static int bridges_channel_compare(void *obj, void *arg, int flags)
429 {
430 const struct stasis_app_bridge_channel_wrapper *object_left = obj;
431 const struct stasis_app_bridge_channel_wrapper *object_right = arg;
432 const char *right_key = arg;
433 int cmp;
434
435 switch (flags & OBJ_SEARCH_MASK) {
436 case OBJ_SEARCH_OBJECT:
437 right_key = object_right->bridge_id;
438 case OBJ_SEARCH_KEY:
439 cmp = strcmp(object_left->bridge_id, right_key);
440 break;
441 case OBJ_SEARCH_PARTIAL_KEY:
442 cmp = strncmp(object_left->bridge_id, right_key, strlen(right_key));
443 break;
444 default:
445 cmp = 0;
446 break;
447 }
448 if (cmp) {
449 return 0;
450 }
451 return CMP_MATCH;
452 }
453
427454 static void stasis_app_bridge_channel_wrapper_destructor(void *obj)
428455 {
429456 struct stasis_app_bridge_channel_wrapper *wrapper = obj;
791818 capabilities &= ~AST_BRIDGE_CAPABILITY_NATIVE;
792819 } else if (!strcmp(requested_type, "video_sfu")) {
793820 video_mode = AST_BRIDGE_VIDEO_MODE_SFU;
821 } else if (!strcmp(requested_type, "video_single")) {
822 video_mode = AST_BRIDGE_VIDEO_MODE_SINGLE_SRC;
794823 }
795824 }
796825
23202349 BRIDGES_NUM_BUCKETS, bridges_hash, NULL, bridges_compare);
23212350 app_bridges_moh = ao2_container_alloc_hash(
23222351 AO2_ALLOC_OPT_LOCK_MUTEX, 0,
2323 37, bridges_channel_hash_fn, NULL, NULL);
2352 37, bridges_channel_hash_fn, NULL, bridges_channel_compare);
23242353 app_bridges_playback = ao2_container_alloc_hash(
23252354 AO2_ALLOC_OPT_LOCK_MUTEX, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT,
23262355 37, bridges_channel_hash_fn, bridges_channel_sort_fn, NULL);
0 /*
1 * Asterisk -- An open source telephony toolkit.
2 *
3 * Copyright (C) 2020, Sangoma Technologies Corporation
4 *
5 * Kevin Harwell <kharwell@digium.com>
6 *
7 * See http://www.asterisk.org for more information about
8 * the Asterisk project. Please do not directly contact
9 * any of the maintainers of this project for assistance;
10 * the project provides a web site, mailing lists and IRC
11 * channels for your use.
12 *
13 * This program is free software, distributed under the terms of
14 * the GNU General Public License Version 2. See the LICENSE file
15 * at the top of the source tree.
16 */
17
18 #include "asterisk.h"
19
20 #include <sys/stat.h>
21
22 #include "asterisk/cli.h"
23 #include "asterisk/sorcery.h"
24
25 #include "stir_shaken.h"
26 #include "certificate.h"
27 #include "asterisk/res_stir_shaken.h"
28
29 #define CONFIG_TYPE "certificate"
30
31 struct stir_shaken_certificate {
32 SORCERY_OBJECT(details);
33 AST_DECLARE_STRING_FIELDS(
34 /*! Path to a directory containing certificates */
35 AST_STRING_FIELD(path);
36 /*! URL to the public key */
37 AST_STRING_FIELD(public_key_url);
38 /*! The caller ID number associated with the certificate */
39 AST_STRING_FIELD(caller_id_number);
40 /*! The attestation level for this certificate */
41 AST_STRING_FIELD(attestation);
42 /*! The origination ID for this certificate */
43 AST_STRING_FIELD(origid);
44 );
45 /*! The private key for the certificate */
46 EVP_PKEY *private_key;
47 };
48
49 static struct stir_shaken_certificate *stir_shaken_certificate_get(const char *id)
50 {
51 return ast_sorcery_retrieve_by_id(ast_stir_shaken_sorcery(), CONFIG_TYPE, id);
52 }
53
54 static struct ao2_container *stir_shaken_certificate_get_all(void)
55 {
56 return ast_sorcery_retrieve_by_fields(ast_stir_shaken_sorcery(), CONFIG_TYPE,
57 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
58 }
59
60 static void stir_shaken_certificate_destructor(void *obj)
61 {
62 struct stir_shaken_certificate *cfg = obj;
63
64 EVP_PKEY_free(cfg->private_key);
65 ast_string_field_free_memory(cfg);
66 }
67
68 static void *stir_shaken_certificate_alloc(const char *name)
69 {
70 struct stir_shaken_certificate *cfg;
71
72 cfg = ast_sorcery_generic_alloc(sizeof(*cfg), stir_shaken_certificate_destructor);
73 if (!cfg) {
74 return NULL;
75 }
76
77 if (ast_string_field_init(cfg, 512)) {
78 ao2_ref(cfg, -1);
79 return NULL;
80 }
81
82 return cfg;
83 }
84
85 struct stir_shaken_certificate *stir_shaken_certificate_get_by_caller_id_number(const char *caller_id_number)
86 {
87 struct ast_variable fields = {
88 .name = "caller_id_number",
89 .value = caller_id_number,
90 .next = NULL,
91 };
92
93 return ast_sorcery_retrieve_by_fields(ast_stir_shaken_sorcery(),
94 "certificate", AST_RETRIEVE_FLAG_DEFAULT, &fields);
95 }
96
97 const char *stir_shaken_certificate_get_public_key_url(struct stir_shaken_certificate *cert)
98 {
99 return cert ? cert->public_key_url : NULL;
100 }
101
102 const char *stir_shaken_certificate_get_attestation(struct stir_shaken_certificate *cert)
103 {
104 return cert ? cert->attestation : NULL;
105 }
106
107 const char *stir_shaken_certificate_get_origid(struct stir_shaken_certificate *cert)
108 {
109 return cert ? cert->origid : NULL;
110 }
111
112 EVP_PKEY *stir_shaken_certificate_get_private_key(struct stir_shaken_certificate *cert)
113 {
114 return cert ? cert->private_key : NULL;
115 }
116
117 static int stir_shaken_certificate_apply(const struct ast_sorcery *sorcery, void *obj)
118 {
119 EVP_PKEY *private_key;
120 struct stir_shaken_certificate *cert = obj;
121
122 if (ast_strlen_zero(cert->caller_id_number)) {
123 ast_log(LOG_ERROR, "Caller ID must be present\n");
124 return -1;
125 }
126
127 if (ast_strlen_zero(cert->attestation)) {
128 ast_log(LOG_ERROR, "Attestation must be present\n");
129 return -1;
130 }
131
132 private_key = stir_shaken_read_key(cert->path, 1);
133 if (!private_key) {
134 return -1;
135 }
136
137 cert->private_key = private_key;
138
139 return 0;
140 }
141
142 static char *stir_shaken_certificate_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
143 {
144 struct stir_shaken_certificate *cfg;
145
146 switch(cmd) {
147 case CLI_INIT:
148 e->command = "stir_shaken show certificate";
149 e->usage =
150 "Usage: stir_shaken show certificate <id>\n"
151 " Show the certificate stir/shaken settings for a given id\n";
152 return NULL;
153 case CLI_GENERATE:
154 if (a->pos == 3) {
155 return stir_shaken_tab_complete_name(a->word, stir_shaken_certificate_get_all());
156 } else {
157 return NULL;
158 }
159 }
160
161 if (a->argc != 4) {
162 return CLI_SHOWUSAGE;
163 }
164
165 cfg = stir_shaken_certificate_get(a->argv[3]);
166 stir_shaken_cli_show(cfg, a, 0);
167 ao2_cleanup(cfg);
168
169 return CLI_SUCCESS;
170 }
171
172 static char *stir_shaken_certificate_show_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
173 {
174 struct ao2_container *container;
175
176 switch(cmd) {
177 case CLI_INIT:
178 e->command = "stir_shaken show certificates";
179 e->usage =
180 "Usage: stir_shaken show certificates\n"
181 " Show all configured certificates for stir/shaken\n";
182 return NULL;
183 case CLI_GENERATE:
184 return NULL;
185 }
186
187 if (a->argc != 3) {
188 return CLI_SHOWUSAGE;
189 }
190
191 container = stir_shaken_certificate_get_all();
192 if (!container || ao2_container_count(container) == 0) {
193 ast_cli(a->fd, "No stir/shaken certificates found\n");
194 ao2_cleanup(container);
195 return CLI_SUCCESS;
196 }
197
198 ao2_callback(container, OBJ_NODATA, stir_shaken_cli_show, a);
199 ao2_ref(container, -1);
200
201 return CLI_SUCCESS;
202 }
203
204 static struct ast_cli_entry stir_shaken_certificate_cli[] = {
205 AST_CLI_DEFINE(stir_shaken_certificate_show, "Show stir/shaken certificate configuration by id"),
206 AST_CLI_DEFINE(stir_shaken_certificate_show_all, "Show all stir/shaken certificate configurations"),
207 };
208
209 static int on_load_path(const struct aco_option *opt, struct ast_variable *var, void *obj)
210 {
211 struct stir_shaken_certificate *cfg = obj;
212 struct stat statbuf;
213
214 if (stat(var->value, &statbuf)) {
215 ast_log(LOG_ERROR, "stir/shaken - path '%s' not found\n", var->value);
216 return -1;
217 }
218
219 if (!S_ISREG(statbuf.st_mode)) {
220 ast_log(LOG_ERROR, "stir/shaken - path '%s' is not a file\n", var->value);
221 return -1;
222 }
223
224 return ast_string_field_set(cfg, path, var->value);
225 }
226
227 static int path_to_str(const void *obj, const intptr_t *args, char **buf)
228 {
229 const struct stir_shaken_certificate *cfg = obj;
230
231 *buf = ast_strdup(cfg->path);
232
233 return 0;
234 }
235
236 static int on_load_public_key_url(const struct aco_option *opt, struct ast_variable *var, void *obj)
237 {
238 struct stir_shaken_certificate *cfg = obj;
239
240 if (!ast_begins_with(var->value, "http")) {
241 ast_log(LOG_ERROR, "stir/shaken - public_key_url scheme must be 'http[s]'\n");
242 return -1;
243 }
244
245 return ast_string_field_set(cfg, public_key_url, var->value);
246 }
247
248 static int public_key_url_to_str(const void *obj, const intptr_t *args, char **buf)
249 {
250 const struct stir_shaken_certificate *cfg = obj;
251
252 *buf = ast_strdup(cfg->public_key_url);
253
254 return 0;
255 }
256
257 static int on_load_attestation(const struct aco_option *opt, struct ast_variable *var, void *obj)
258 {
259 struct stir_shaken_certificate *cfg = obj;
260
261 if (strcmp(var->value, "A") && strcmp(var->value, "B") && strcmp(var->value, "C")) {
262 ast_log(LOG_ERROR, "stir/shaken - attestation level must be A, B, or C (object=%s)\n",
263 ast_sorcery_object_get_id(cfg));
264 return -1;
265 }
266
267 return ast_string_field_set(cfg, attestation, var->value);
268 }
269
270 static int attestation_to_str(const void *obj, const intptr_t *args, char **buf)
271 {
272 const struct stir_shaken_certificate *cfg = obj;
273
274 *buf = ast_strdup(cfg->attestation);
275
276 return 0;
277 }
278
279 #ifdef TEST_FRAMEWORK
280
281 /* Name for test certificaate */
282 #define TEST_CONFIG_NAME "test_stir_shaken_certificate"
283 /* The public key URL to use for the test certificate */
284 #define TEST_CONFIG_URL "http://testing123"
285
286 int test_stir_shaken_cleanup_cert(const char *caller_id_number)
287 {
288 struct stir_shaken_certificate *cert;
289 struct ast_sorcery *sorcery;
290 int res = 0;
291
292 sorcery = ast_stir_shaken_sorcery();
293
294 cert = stir_shaken_certificate_get_by_caller_id_number(caller_id_number);
295 if (!cert) {
296 return 0;
297 }
298
299 res = ast_sorcery_delete(sorcery, cert);
300 ao2_cleanup(cert);
301 if (res) {
302 ast_log(LOG_ERROR, "Failed to delete sorcery object with caller ID "
303 "'%s'\n", caller_id_number);
304 return -1;
305 }
306
307 res = ast_sorcery_remove_wizard_mapping(sorcery, CONFIG_TYPE, "memory");
308
309 return res;
310 }
311
312 int test_stir_shaken_create_cert(const char *caller_id_number, const char *file_path)
313 {
314 struct stir_shaken_certificate *cert;
315 struct ast_sorcery *sorcery;
316 EVP_PKEY *private_key;
317 int res = 0;
318
319 sorcery = ast_stir_shaken_sorcery();
320
321 res = ast_sorcery_insert_wizard_mapping(sorcery, CONFIG_TYPE, "memory", "testing", 0, 0);
322 if (res) {
323 ast_log(LOG_ERROR, "Failed to insert STIR/SHAKEN test certificate mapping\n");
324 return -1;
325 }
326
327 cert = ast_sorcery_alloc(sorcery, CONFIG_TYPE, TEST_CONFIG_NAME);
328 if (!cert) {
329 ast_log(LOG_ERROR, "Failed to allocate test certificate\n");
330 return -1;
331 }
332
333 ast_string_field_set(cert, path, file_path);
334 ast_string_field_set(cert, public_key_url, TEST_CONFIG_URL);
335 ast_string_field_set(cert, caller_id_number, caller_id_number);
336
337 private_key = stir_shaken_read_key(cert->path, 1);
338 if (!private_key) {
339 ast_log(LOG_ERROR, "Failed to read test key from %s\n", cert->path);
340 test_stir_shaken_cleanup_cert(caller_id_number);
341 return -1;
342 }
343
344 cert->private_key = private_key;
345
346 ast_sorcery_create(sorcery, cert);
347
348 return res;
349 }
350
351 #endif /* TEST_FRAMEWORK */
352
353 int stir_shaken_certificate_unload(void)
354 {
355 ast_cli_unregister_multiple(stir_shaken_certificate_cli,
356 ARRAY_LEN(stir_shaken_certificate_cli));
357
358 return 0;
359 }
360
361 int stir_shaken_certificate_load(void)
362 {
363 struct ast_sorcery *sorcery = ast_stir_shaken_sorcery();
364
365 ast_sorcery_apply_default(sorcery, CONFIG_TYPE, "config", "stir_shaken.conf,criteria=type=certificate");
366
367 if (ast_sorcery_object_register(sorcery, CONFIG_TYPE, stir_shaken_certificate_alloc,
368 NULL, stir_shaken_certificate_apply)) {
369 ast_log(LOG_ERROR, "stir/shaken - failed to register '%s' sorcery object\n", CONFIG_TYPE);
370 return -1;
371 }
372
373 ast_sorcery_object_field_register(sorcery, CONFIG_TYPE, "type", "", OPT_NOOP_T, 0, 0);
374 ast_sorcery_object_field_register_custom(sorcery, CONFIG_TYPE, "path", "",
375 on_load_path, path_to_str, NULL, 0, 0);
376 ast_sorcery_object_field_register_custom(sorcery, CONFIG_TYPE, "public_key_url", "",
377 on_load_public_key_url, public_key_url_to_str, NULL, 0, 0);
378 ast_sorcery_object_field_register_custom(sorcery, CONFIG_TYPE, "attestation", "",
379 on_load_attestation, attestation_to_str, NULL, 0, 0);
380 ast_sorcery_object_field_register(sorcery, CONFIG_TYPE, "origid", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct stir_shaken_certificate, origid));
381 ast_sorcery_object_field_register(sorcery, CONFIG_TYPE, "caller_id_number", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct stir_shaken_certificate, caller_id_number));
382
383 ast_cli_register_multiple(stir_shaken_certificate_cli,
384 ARRAY_LEN(stir_shaken_certificate_cli));
385
386 return 0;
387 }
0 /*
1 * Asterisk -- An open source telephony toolkit.
2 *
3 * Copyright (C) 2020, Sangoma Technologies Corporation
4 *
5 * Kevin Harwell <kharwell@sangoma.com>
6 *
7 * See http://www.asterisk.org for more information about
8 * the Asterisk project. Please do not directly contact
9 * any of the maintainers of this project for assistance;
10 * the project provides a web site, mailing lists and IRC
11 * channels for your use.
12 *
13 * This program is free software, distributed under the terms of
14 * the GNU General Public License Version 2. See the LICENSE file
15 * at the top of the source tree.
16 */
17 #ifndef _STIR_SHAKEN_CERTIFICATE_H
18 #define _STIR_SHAKEN_CERTIFICATE_H
19
20 #include <openssl/evp.h>
21
22 struct ast_sorcery;
23
24 struct stir_shaken_certificate;
25
26 /*!
27 * \brief Get a STIR/SHAKEN certificate by caller ID number
28 *
29 * \param callier_id_number The caller ID number
30 *
31 * \retval NULL if not found
32 * \retval The certificate on success
33 */
34 struct stir_shaken_certificate *stir_shaken_certificate_get_by_caller_id_number(const char *caller_id_number);
35
36 /*!
37 * \brief Get the public key URL associated with a certificate
38 *
39 * \param cert The certificate to get the public key URL from
40 *
41 * \retval NULL on failure
42 * \retval The public key URL on success
43 */
44 const char *stir_shaken_certificate_get_public_key_url(struct stir_shaken_certificate *cert);
45
46 /*!
47 * \brief Get the attestation level associated with a certificate
48 *
49 * \param cert The certificate
50 *
51 * \retval NULL on failure
52 * \retval The attestation on success
53 */
54 const char *stir_shaken_certificate_get_attestation(struct stir_shaken_certificate *cert);
55
56 /*!
57 * \brief Get the origination ID associated with a certificate
58 *
59 * \param cert The certificate
60 *
61 * \retval NULL on failure
62 * \retval The origid on success
63 */
64 const char *stir_shaken_certificate_get_origid(struct stir_shaken_certificate *cert);
65
66 /*!
67 * \brief Get the private key associated with a certificate
68 *
69 * \param cert The certificate to get the private key from
70 *
71 * \retval NULL on failure
72 * \retval The private key on success
73 */
74 EVP_PKEY *stir_shaken_certificate_get_private_key(struct stir_shaken_certificate *cert);
75
76 #ifdef TEST_FRAMEWORK
77
78 /*!
79 * \brief Clean up the certificate and mappings set up in test_stir_shaken_init
80 *
81 * \param caller_id_number The caller ID of the certificate to clean up
82 *
83 * \retval non-zero on failure
84 * \retval 0 on success
85 */
86 int test_stir_shaken_cleanup_cert(const char *caller_id_number);
87
88 /*!
89 * \brief Initialize a test certificate through wizard mappings
90 *
91 * \note test_stir_shaken_cleanup should be called when done with this certificate
92 *
93 * \param caller_id_number The caller ID of the certificate to create
94 * \param file_path The path to the private key for this certificate
95 *
96 * \retval non-zero on failure
97 * \retval 0 on success
98 */
99 int test_stir_shaken_create_cert(const char *caller_id_number, const char *file_path);
100
101 #endif /* TEST_FRAMEWORK */
102
103 /*!
104 * \brief Load time initialization for the stir/shaken 'certificate' configuration
105 *
106 * \retval 0 on success, -1 on error
107 */
108 int stir_shaken_certificate_load(void);
109
110 /*!
111 * \brief Unload time cleanup for the stir/shaken 'certificate' configuration
112 *
113 * \retval 0 on success, -1 on error
114 */
115 int stir_shaken_certificate_unload(void);
116
117 #endif /* _STIR_SHAKEN_CERTIFICATE_H */
118
0 /*
1 * Asterisk -- An open source telephony toolkit.
2 *
3 * Copyright (C) 2020, Sangoma Technologies Corporation
4 *
5 * Ben Ford <bford@sangoma.com>
6 *
7 * See http://www.asterisk.org for more information about
8 * the Asterisk project. Please do not directly contact
9 * any of the maintainers of this project for assistance;
10 * the project provides a web site, mailing lists and IRC
11 * channels for your use.
12 *
13 * This program is free software, distributed under the terms of
14 * the GNU General Public License Version 2. See the LICENSE file
15 * at the top of the source tree.
16 */
17
18 #include "asterisk.h"
19
20 #include "asterisk/utils.h"
21 #include "asterisk/logger.h"
22 #include "curl.h"
23 #include "general.h"
24
25 #include <curl/curl.h>
26
27 /* Used to check CURL headers */
28 #define MAX_HEADER_LENGTH 1023
29
30 /* Used for CURL requests */
31 #define GLOBAL_USERAGENT "asterisk-libcurl-agent/1.0"
32
33 /* CURL callback data to avoid storing useless info in AstDB */
34 struct curl_cb_data {
35 char *cache_control;
36 char *expires;
37 };
38
39 struct curl_cb_data *curl_cb_data_create(void)
40 {
41 struct curl_cb_data *data;
42
43 data = ast_calloc(1, sizeof(*data));
44
45 return data;
46 }
47
48 void curl_cb_data_free(struct curl_cb_data *data)
49 {
50 if (!data) {
51 return;
52 }
53
54 ast_free(data->cache_control);
55 ast_free(data->expires);
56
57 ast_free(data);
58 }
59
60 char *curl_cb_data_get_cache_control(const struct curl_cb_data *data)
61 {
62 if (!data) {
63 return NULL;
64 }
65
66 return data->cache_control;
67 }
68
69 char *curl_cb_data_get_expires(const struct curl_cb_data *data)
70 {
71 if (!data) {
72 return NULL;
73 }
74
75 return data->expires;
76 }
77
78 /*!
79 * \brief Called when a CURL request completes
80 *
81 * \param data The curl_cb_data structure to store expiration info
82 */
83 static size_t curl_header_callback(char *buffer, size_t size, size_t nitems, void *data)
84 {
85 struct curl_cb_data *cb_data = data;
86 size_t realsize;
87 char *header;
88 char *value;
89
90 realsize = size * nitems;
91
92 if (realsize > MAX_HEADER_LENGTH) {
93 ast_log(LOG_WARNING, "CURL header length is too large (size: '%zu' | max: '%d')\n",
94 realsize, MAX_HEADER_LENGTH);
95 return 0;
96 }
97
98 header = ast_alloca(realsize + 1);
99 memcpy(header, buffer, realsize);
100 header[realsize] = '\0';
101 value = strchr(header, ':');
102 if (!value) {
103 return realsize;
104 }
105 *value++ = '\0';
106 value = ast_trim_blanks(ast_skip_blanks(value));
107
108 if (!strcasecmp(header, "Cache-Control")) {
109 cb_data->cache_control = ast_strdup(value);
110 } else if (!strcasecmp(header, "Expires")) {
111 cb_data->expires = ast_strdup(value);
112 }
113
114 return realsize;
115 }
116
117 /*!
118 * \brief Prepare a CURL instance to use
119 *
120 * \param data The CURL callback data
121 *
122 * \retval NULL on failure
123 * \retval CURL instance on success
124 */
125 static CURL *get_curl_instance(struct curl_cb_data *data)
126 {
127 CURL *curl;
128 struct stir_shaken_general *cfg;
129 unsigned int curl_timeout;
130
131 cfg = stir_shaken_general_get();
132 curl_timeout = ast_stir_shaken_curl_timeout(cfg);
133 ao2_cleanup(cfg);
134
135 curl = curl_easy_init();
136 if (!curl) {
137 return NULL;
138 }
139
140 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
141 curl_easy_setopt(curl, CURLOPT_TIMEOUT, curl_timeout);
142 curl_easy_setopt(curl, CURLOPT_USERAGENT, GLOBAL_USERAGENT);
143 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
144 curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_header_callback);
145 curl_easy_setopt(curl, CURLOPT_HEADERDATA, data);
146
147 return curl;
148 }
149
150 int curl_public_key(const char *public_key_url, const char *path, struct curl_cb_data *data)
151 {
152 FILE *public_key_file;
153 long http_code;
154 CURL *curl;
155 char curl_errbuf[CURL_ERROR_SIZE + 1];
156 char hash[41];
157
158 ast_sha1_hash(hash, public_key_url);
159
160 curl_errbuf[CURL_ERROR_SIZE] = '\0';
161
162 public_key_file = fopen(path, "wb");
163 if (!public_key_file) {
164 ast_log(LOG_ERROR, "Failed to open file '%s' to write public key from '%s': %s (%d)\n",
165 path, public_key_url, strerror(errno), errno);
166 return -1;
167 }
168
169 curl = get_curl_instance(data);
170 if (!curl) {
171 ast_log(LOG_ERROR, "Failed to set up CURL isntance for '%s'\n", public_key_url);
172 fclose(public_key_file);
173 return -1;
174 }
175
176 curl_easy_setopt(curl, CURLOPT_URL, public_key_url);
177 curl_easy_setopt(curl, CURLOPT_WRITEDATA, public_key_file);
178 curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errbuf);
179
180 if (curl_easy_perform(curl)) {
181 ast_log(LOG_ERROR, "%s\n", curl_errbuf);
182 curl_easy_cleanup(curl);
183 fclose(public_key_file);
184 return -1;
185 }
186
187 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
188
189 curl_easy_cleanup(curl);
190 fclose(public_key_file);
191
192 if (http_code / 100 != 2) {
193 ast_log(LOG_ERROR, "Failed to retrieve URL '%s': code %ld\n", public_key_url, http_code);
194 return -1;
195 }
196
197 return 0;
198 }
0 /*
1 * Asterisk -- An open source telephony toolkit.
2 *
3 * Copyright (C) 2020, Sangoma Technologies Corporation
4 *
5 * Ben Ford <bford@sangoma.com>
6 *
7 * See http://www.asterisk.org for more information about
8 * the Asterisk project. Please do not directly contact
9 * any of the maintainers of this project for assistance;
10 * the project provides a web site, mailing lists and IRC
11 * channels for your use.
12 *
13 * This program is free software, distributed under the terms of
14 * the GNU General Public License Version 2. See the LICENSE file
15 * at the top of the source tree.
16 */
17 #ifndef _STIR_SHAKEN_CURL_H
18 #define _STIR_SHAKEN_CURL_H
19
20 /* Forward declarion for CURL callback data */
21 struct curl_cb_data;
22
23 /*!
24 * \brief Allocate memory for a curl_cb_data struct
25 *
26 * \note This will need to be freed by the consumer using curl_cb_data_free
27 *
28 * \retval NULL on failure
29 * \retval curl_cb_struct on success
30 */
31 struct curl_cb_data *curl_cb_data_create(void);
32
33 /*!
34 * \brief Free a curl_cb_data struct
35 *
36 * \param data The curl_cb_data struct to free
37 */
38 void curl_cb_data_free(struct curl_cb_data *data);
39
40 /*!
41 * \brief Get the cache_control field from a curl_cb_data struct
42 *
43 * \param data The curl_cb_data
44 *
45 * \retval cache_control on success
46 * \retval NULL otherwise
47 */
48 char *curl_cb_data_get_cache_control(const struct curl_cb_data *data);
49
50 /*!
51 * \brief Get the expires field from a curl_cb_data struct
52 *
53 * \param data The curl_cb_data
54 *
55 * \retval expires on success
56 * \retval NULL otherwise
57 */
58 char *curl_cb_data_get_expires(const struct curl_cb_data *data);
59
60 /*!
61 * \brief CURL the public key from the provided URL to the specified path
62 *
63 * \param public_key_url The public key URL
64 * \param path The path to download the file to
65 * \param data The curl_cb_data
66 *
67 * \retval 1 on failure
68 * \retval 0 on success
69 */
70 int curl_public_key(const char *public_key_url, const char *path, struct curl_cb_data *data);
71
72 #endif /* _STIR_SHAKEN_CURL_H */
0 /*
1 * Asterisk -- An open source telephony toolkit.
2 *
3 * Copyright (C) 2020, Sangoma Technologies Corporation
4 *
5 * Kevin Harwell <kharwell@digium.com>
6 *
7 * See http://www.asterisk.org for more information about
8 * the Asterisk project. Please do not directly contact
9 * any of the maintainers of this project for assistance;
10 * the project provides a web site, mailing lists and IRC
11 * channels for your use.
12 *
13 * This program is free software, distributed under the terms of
14 * the GNU General Public License Version 2. See the LICENSE file
15 * at the top of the source tree.
16 */
17
18 #include "asterisk.h"
19
20 #include "asterisk/cli.h"
21 #include "asterisk/sorcery.h"
22
23 #include "stir_shaken.h"
24 #include "general.h"
25 #include "asterisk/res_stir_shaken.h"
26
27 #define CONFIG_TYPE "general"
28
29 #define DEFAULT_CA_FILE ""
30 #define DEFAULT_CA_PATH ""
31 #define DEFAULT_CACHE_MAX_SIZE 1000
32 #define DEFAULT_CURL_TIMEOUT 2
33 #define DEFAULT_SIGNATURE_TIMEOUT 15
34
35 struct stir_shaken_general {
36 SORCERY_OBJECT(details);
37 AST_DECLARE_STRING_FIELDS(
38 /*! File path to a certificate authority */
39 AST_STRING_FIELD(ca_file);
40 /*! File path to a chain of trust */
41 AST_STRING_FIELD(ca_path);
42 );
43 /*! Maximum size of public keys cache */
44 unsigned int cache_max_size;
45 /*! Maximum time to wait to CURL certificates */
46 unsigned int curl_timeout;
47 /*! Amount of time a signature is valid for */
48 unsigned int signature_timeout;
49 };
50
51 static struct stir_shaken_general *default_config = NULL;
52
53 struct stir_shaken_general *stir_shaken_general_get()
54 {
55 struct stir_shaken_general *cfg;
56 struct ao2_container *container;
57
58 container = ast_sorcery_retrieve_by_fields(ast_stir_shaken_sorcery(), CONFIG_TYPE,
59 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
60 if (!container || ao2_container_count(container) == 0) {
61 ao2_cleanup(container);
62 return ao2_bump(default_config);
63 }
64
65 cfg = ao2_find(container, NULL, 0);
66 ao2_ref(container, -1);
67
68 return cfg;
69 }
70
71 const char *ast_stir_shaken_ca_file(const struct stir_shaken_general *cfg)
72 {
73 return cfg ? cfg->ca_file : DEFAULT_CA_FILE;
74 }
75
76 const char *ast_stir_shaken_ca_path(const struct stir_shaken_general *cfg)
77 {
78 return cfg ? cfg->ca_path : DEFAULT_CA_PATH;
79 }
80
81 unsigned int ast_stir_shaken_cache_max_size(const struct stir_shaken_general *cfg)
82 {
83 return cfg ? cfg->cache_max_size : DEFAULT_CACHE_MAX_SIZE;
84 }
85
86 unsigned int ast_stir_shaken_curl_timeout(const struct stir_shaken_general *cfg)
87 {
88 return cfg ? cfg->curl_timeout : DEFAULT_CURL_TIMEOUT;
89 }
90
91 unsigned int ast_stir_shaken_signature_timeout(const struct stir_shaken_general *cfg)
92 {
93 return cfg ? cfg->signature_timeout : DEFAULT_SIGNATURE_TIMEOUT;
94 }
95
96 static void stir_shaken_general_destructor(void *obj)
97 {
98 struct stir_shaken_general *cfg = obj;
99
100 ast_string_field_free_memory(cfg);
101 }
102
103 static void *stir_shaken_general_alloc(const char *name)
104 {
105 struct stir_shaken_general *cfg;
106
107 cfg = ast_sorcery_generic_alloc(sizeof(*cfg), stir_shaken_general_destructor);
108 if (!cfg) {
109 return NULL;
110 }
111
112 if (ast_string_field_init(cfg, 512)) {
113 ao2_ref(cfg, -1);
114 return NULL;
115 }
116
117 return cfg;
118 }
119
120 static int stir_shaken_general_apply(const struct ast_sorcery *sorcery, void *obj)
121 {
122 return 0;
123 }
124
125 static void stir_shaken_general_loaded(const char *name, const struct ast_sorcery *sorcery,
126 const char *object_type, int reloaded)
127 {
128 struct stir_shaken_general *cfg;
129
130 if (strcmp(object_type, CONFIG_TYPE)) {
131 /* Not interested */
132 return;
133 }
134
135 if (default_config) {
136 ao2_ref(default_config, -1);
137 default_config = NULL;
138 }
139
140 cfg = stir_shaken_general_get();
141 if (cfg) {
142 ao2_ref(cfg, -1);
143 return;
144 }
145
146 /* Use the default configuration if on is not specified */
147 default_config = ast_sorcery_alloc(sorcery, CONFIG_TYPE, NULL);
148 if (default_config) {
149 stir_shaken_general_apply(sorcery, default_config);
150 }
151 }
152
153 static const struct ast_sorcery_instance_observer stir_shaken_general_observer = {
154 .object_type_loaded = stir_shaken_general_loaded,
155 };
156
157 static char *stir_shaken_general_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
158 {
159 struct stir_shaken_general *cfg;
160
161 switch(cmd) {
162 case CLI_INIT:
163 e->command = "stir_shaken show general";
164 e->usage =
165 "Usage: stir_shaken show general\n"
166 " Show the general stir/shaken settings\n";
167 return NULL;
168 case CLI_GENERATE:
169 return NULL;
170 }
171
172 if (a->argc != 3) {
173 return CLI_SHOWUSAGE;
174 }
175
176 cfg = stir_shaken_general_get();
177 stir_shaken_cli_show(cfg, a, 0);
178 ao2_cleanup(cfg);
179
180 return CLI_SUCCESS;
181 }
182
183 static struct ast_cli_entry stir_shaken_general_cli[] = {
184 AST_CLI_DEFINE(stir_shaken_general_show, "Show stir/shaken general configuration"),
185 };
186
187 static int on_load_ca_file(const struct aco_option *opt, struct ast_variable *var, void *obj)
188 {
189 struct stir_shaken_general *cfg = obj;
190
191 if (!ast_file_is_readable(var->value)) {
192 ast_log(LOG_ERROR, "stir/shaken - %s '%s' not found, or is unreadable\n",
193 var->name, var->value);
194 return -1;
195 }
196
197 return ast_string_field_set(cfg, ca_file, var->value);
198 }
199
200 static int ca_file_to_str(const void *obj, const intptr_t *args, char **buf)
201 {
202 const struct stir_shaken_general *cfg = obj;
203
204 *buf = ast_strdup(cfg->ca_file);
205
206 return 0;
207 }
208
209 static int on_load_ca_path(const struct aco_option *opt, struct ast_variable *var, void *obj)
210 {
211 struct stir_shaken_general *cfg = obj;
212
213 if (!ast_file_is_readable(var->value)) {
214 ast_log(LOG_ERROR, "stir/shaken - %s '%s' not found, or is unreadable\n",
215 var->name, var->value);
216 return -1;
217 }
218
219 return ast_string_field_set(cfg, ca_path, var->value);
220 }
221
222 static int ca_path_to_str(const void *obj, const intptr_t *args, char **buf)
223 {
224 const struct stir_shaken_general *cfg = obj;
225
226 *buf = ast_strdup(cfg->ca_path);
227
228 return 0;
229 }
230
231 int stir_shaken_general_unload(void)
232 {
233 ast_cli_unregister_multiple(stir_shaken_general_cli,
234 ARRAY_LEN(stir_shaken_general_cli));
235
236 ast_sorcery_instance_observer_remove(ast_stir_shaken_sorcery(),
237 &stir_shaken_general_observer);
238
239 if (default_config) {
240 ao2_ref(default_config, -1);
241 default_config = NULL;
242 }
243
244 return 0;
245 }
246
247 int stir_shaken_general_load(void)
248 {
249 struct ast_sorcery *sorcery = ast_stir_shaken_sorcery();
250
251 ast_sorcery_apply_default(sorcery, CONFIG_TYPE, "config",
252 "stir_shaken.conf,criteria=type=general,single_object=yes,explicit_name=general");
253
254 if (ast_sorcery_object_register(sorcery, CONFIG_TYPE, stir_shaken_general_alloc,
255 NULL, stir_shaken_general_apply)) {
256 ast_log(LOG_ERROR, "stir/shaken - failed to register '%s' sorcery object\n", CONFIG_TYPE);
257 return -1;
258 }
259
260 ast_sorcery_object_field_register(sorcery, CONFIG_TYPE, "type", "", OPT_NOOP_T, 0, 0);
261 ast_sorcery_object_field_register_custom(sorcery, CONFIG_TYPE, "ca_file",
262 DEFAULT_CA_FILE, on_load_ca_file, ca_file_to_str, NULL, 0, 0);
263 ast_sorcery_object_field_register_custom(sorcery, CONFIG_TYPE, "ca_path",
264 DEFAULT_CA_PATH, on_load_ca_path, ca_path_to_str, NULL, 0, 0);
265 ast_sorcery_object_field_register(sorcery, CONFIG_TYPE, "cache_max_size",
266 __stringify(DEFAULT_CACHE_MAX_SIZE), OPT_UINT_T, 0,
267 FLDSET(struct stir_shaken_general, cache_max_size));
268 ast_sorcery_object_field_register(sorcery, CONFIG_TYPE, "curl_timeout",
269 __stringify(DEFAULT_CURL_TIMEOUT), OPT_UINT_T, 0,
270 FLDSET(struct stir_shaken_general, curl_timeout));
271 ast_sorcery_object_field_register(sorcery, CONFIG_TYPE, "signature_timeout",
272 __stringify(DEFAULT_SIGNATURE_TIMEOUT), OPT_UINT_T, 0,
273 FLDSET(struct stir_shaken_general, signature_timeout));
274
275 if (ast_sorcery_instance_observer_add(sorcery, &stir_shaken_general_observer)) {
276 ast_log(LOG_ERROR, "stir/shaken - failed to register loaded observer for '%s' "
277 "sorcery object type\n", CONFIG_TYPE);
278 return -1;
279 }
280
281 ast_cli_register_multiple(stir_shaken_general_cli,
282 ARRAY_LEN(stir_shaken_general_cli));
283
284 return 0;
285 }
0 /*
1 * Asterisk -- An open source telephony toolkit.
2 *
3 * Copyright (C) 2020, Sangoma Technologies Corporation
4 *
5 * Kevin Harwell <kharwell@sangoma.com>
6 *
7 * See http://www.asterisk.org for more information about
8 * the Asterisk project. Please do not directly contact
9 * any of the maintainers of this project for assistance;
10 * the project provides a web site, mailing lists and IRC
11 * channels for your use.
12 *
13 * This program is free software, distributed under the terms of
14 * the GNU General Public License Version 2. See the LICENSE file
15 * at the top of the source tree.
16 */
17 #ifndef _STIR_SHAKEN_GENERAL_H
18 #define _STIR_SHAKEN_GENERAL_H
19
20 struct ast_sorcery;
21
22 /*!
23 * \brief General configuration for stir/shaken
24 */
25 struct stir_shaken_general;
26
27 /*!
28 * \brief Retrieve the stir/shaken 'general' configuration object
29 *
30 * A default configuration object is returned if no configuration was specified.
31 * As well, NULL can be returned if there is no configuration, and a problem
32 * occurred while loading the defaults.
33 *
34 * \note Object is returned with a reference that the caller is responsible
35 * for de-referencing.
36 *
37 * \retval A 'general' configuration object, or NULL
38 */
39 struct stir_shaken_general *stir_shaken_general_get(void);
40
41 /*!
42 * \brief Retrieve the 'ca_file' general configuration option value
43 *
44 * \note If a NULL configuration is given, then the default value is returned
45 *
46 * \param cfg A 'general' configuration object
47 *
48 * \retval The 'ca_file' value
49 */
50 const char *ast_stir_shaken_ca_file(const struct stir_shaken_general *cfg);
51
52 /*!
53 * \brief Retrieve the 'ca_path' general configuration option value
54 *
55 * \note If a NULL configuration is given, then the default value is returned
56 *
57 * \param cfg A 'general' configuration object
58 *
59 * \retval The 'ca_path' value
60 */
61 const char *ast_stir_shaken_ca_path(const struct stir_shaken_general *cfg);
62
63 /*!
64 * \brief Retrieve the 'cache_max_size' general configuration option value
65 *
66 * \note If a NULL configuration is given, then the default value is returned
67 *
68 * \param cfg A 'general' configuration object
69 *
70 * \retval The 'cache_max_size' value
71 */
72 unsigned int ast_stir_shaken_cache_max_size(const struct stir_shaken_general *cfg);
73
74 /*!
75 * \brief Retrieve the 'curl_timeout' general configuration option value
76 *
77 * \note If a NULL configuration is given, then the default value is returned
78 *
79 * \param cfg A 'general' configuration object
80 *
81 * \retval The 'curl_timeout' value
82 */
83 unsigned int ast_stir_shaken_curl_timeout(const struct stir_shaken_general *cfg);
84
85 /*!
86 * \brief Retrieve the 'signature_timeout' general configuration option value
87 *
88 * \note if a NULL configuration is given, then the default value is returned
89 *
90 * \param cfg A 'general' configuration object
91 *
92 * \retval The 'signature_timeout' value
93 */
94 unsigned int ast_stir_shaken_signature_timeout(const struct stir_shaken_general *cfg);
95
96 /*!
97 * \brief Load time initialization for the stir/shaken 'general' configuration
98 *
99 * \retval 0 on success, -1 on error
100 */
101 int stir_shaken_general_load(void);
102
103 /*!
104 * \brief Unload time cleanup for the stir/shaken 'general' configuration
105 *
106 * \retval 0 on success, -1 on error
107 */
108 int stir_shaken_general_unload(void);
109
110 #endif /* _STIR_SHAKEN_GENERAL_H */
0 /*
1 * Asterisk -- An open source telephony toolkit.
2 *
3 * Copyright (C) 2020, Sangoma Technologies Corporation
4 *
5 * Kevin Harwell <kharwell@digium.com>
6 *
7 * See http://www.asterisk.org for more information about
8 * the Asterisk project. Please do not directly contact
9 * any of the maintainers of this project for assistance;
10 * the project provides a web site, mailing lists and IRC
11 * channels for your use.
12 *
13 * This program is free software, distributed under the terms of
14 * the GNU General Public License Version 2. See the LICENSE file
15 * at the top of the source tree.
16 */
17
18 /*! \file
19 *
20 * \brief Internal stir/shaken utilities
21 */
22
23 #include "asterisk.h"
24
25 #include <openssl/evp.h>
26 #include <openssl/pem.h>
27
28 #include "asterisk/cli.h"
29 #include "asterisk/sorcery.h"
30
31 #include "stir_shaken.h"
32 #include "asterisk/res_stir_shaken.h"
33
34 int stir_shaken_cli_show(void *obj, void *arg, int flags)
35 {
36 struct ast_cli_args *a = arg;
37 struct ast_variable *options;
38 struct ast_variable *i;
39
40 if (!obj) {
41 ast_cli(a->fd, "No stir/shaken configuration found\n");
42 return 0;
43 }
44
45 options = ast_variable_list_sort(ast_sorcery_objectset_create2(
46 ast_stir_shaken_sorcery(), obj, AST_HANDLER_ONLY_STRING));
47 if (!options) {
48 return 0;
49 }
50
51 ast_cli(a->fd, "%s: %s\n", ast_sorcery_object_get_type(obj),
52 ast_sorcery_object_get_id(obj));
53
54 for (i = options; i; i = i->next) {
55 ast_cli(a->fd, "\t%s: %s\n", i->name, i->value);
56 }
57
58 ast_cli(a->fd, "\n");
59
60 ast_variables_destroy(options);
61
62 return 0;
63 }
64
65 char *stir_shaken_tab_complete_name(const char *word, struct ao2_container *container)
66 {
67 void *obj;
68 struct ao2_iterator it;
69 int wordlen = strlen(word);
70 int ret;
71
72 it = ao2_iterator_init(container, 0);
73 while ((obj = ao2_iterator_next(&it))) {
74 if (!strncasecmp(word, ast_sorcery_object_get_id(obj), wordlen)) {
75 ret = ast_cli_completion_add(ast_strdup(ast_sorcery_object_get_id(obj)));
76 if (ret) {
77 ao2_ref(obj, -1);
78 break;
79 }
80 }
81 ao2_ref(obj, -1);
82 }
83 ao2_iterator_destroy(&it);
84
85 return NULL;
86 }
87
88 EVP_PKEY *stir_shaken_read_key(const char *path, int priv)
89 {
90 EVP_PKEY *key = NULL;
91 FILE *fp;
92
93 fp = fopen(path, "r");
94 if (!fp) {
95 ast_log(LOG_ERROR, "Failed to read %s key file '%s'\n", priv ? "private" : "public", path);
96 return NULL;
97 }
98
99 if (priv) {
100 key = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
101 } else {
102 key = PEM_read_PUBKEY(fp, NULL, NULL, NULL);
103 }
104
105 if (!key) {
106 ast_log(LOG_ERROR, "Failed to read %s key from file '%s'\n", priv ? "private" : "public", path);
107 fclose(fp);
108 return NULL;
109 }
110
111 if (EVP_PKEY_id(key) != EVP_PKEY_EC) {
112 ast_log(LOG_ERROR, "%s key from '%s' must be of type EVP_PKEY_EC\n", priv ? "private" : "public", path);
113 fclose(fp);
114 EVP_PKEY_free(key);
115 return NULL;
116 }
117
118 fclose(fp);
119
120 return key;
121 }
0 /*
1 * Asterisk -- An open source telephony toolkit.
2 *
3 * Copyright (C) 2020, Sangoma Technologies Corporation
4 *
5 * Kevin Harwell <kharwell@sangoma.com>
6 *
7 * See http://www.asterisk.org for more information about
8 * the Asterisk project. Please do not directly contact
9 * any of the maintainers of this project for assistance;
10 * the project provides a web site, mailing lists and IRC
11 * channels for your use.
12 *
13 * This program is free software, distributed under the terms of
14 * the GNU General Public License Version 2. See the LICENSE file
15 * at the top of the source tree.
16 */
17 #ifndef _STIR_SHAKEN_H
18 #define _STIR_SHAKEN_H
19
20 #include <openssl/evp.h>
21
22 /*!
23 * \brief Output configuration settings to the Asterisk CLI
24 *
25 * \param obj A sorcery object containing configuration data
26 * \param arg Asterisk CLI argument object
27 * \param flags ao2 container flags
28 *
29 * \retval 0
30 */
31 int stir_shaken_cli_show(void *obj, void *arg, int flags);
32
33 /*!
34 * \brief Tab completion for name matching with STIR/SHAKEN CLI commands
35 *
36 * \param word The word to tab complete on
37 * \param container The sorcery container to iterate through
38 *
39 * \retval The tab completion options
40 */
41 char *stir_shaken_tab_complete_name(const char *word, struct ao2_container *container);
42
43 /*!
44 * \brief Reads the public (or private) key from the specified path
45 *
46 * \param path The path to the file containing the private key
47 * \param priv Specify 0 for public, 1 for private
48 *
49 * \retval NULL on failure
50 * \retval The public/private key on success
51 */
52 EVP_PKEY *stir_shaken_read_key(const char *path, int priv);
53
54 #endif /* _STIR_SHAKEN_H */
0 /*
1 * Asterisk -- An open source telephony toolkit.
2 *
3 * Copyright (C) 2020, Sangoma Technologies Corporation
4 *
5 * Kevin Harwell <kharwell@digium.com>
6 *
7 * See http://www.asterisk.org for more information about
8 * the Asterisk project. Please do not directly contact
9 * any of the maintainers of this project for assistance;
10 * the project provides a web site, mailing lists and IRC
11 * channels for your use.
12 *
13 * This program is free software, distributed under the terms of
14 * the GNU General Public License Version 2. See the LICENSE file
15 * at the top of the source tree.
16 */
17
18 #include "asterisk.h"
19
20 #include <sys/stat.h>
21
22 #include "asterisk/cli.h"
23 #include "asterisk/sorcery.h"
24
25 #include "stir_shaken.h"
26 #include "store.h"
27 #include "asterisk/res_stir_shaken.h"
28
29 #define CONFIG_TYPE "store"
30
31 #define VARIABLE_SUBSTITUTE "${CERTIFICATE}"
32
33 struct stir_shaken_store {
34 SORCERY_OBJECT(details);
35 AST_DECLARE_STRING_FIELDS(
36 /*! Path to a directory containing certificates */
37 AST_STRING_FIELD(path);
38 /*! URL to the public key */
39 AST_STRING_FIELD(public_key_url);
40 );
41 };
42
43 static struct stir_shaken_store *stir_shaken_store_get(const char *id)
44 {
45 return ast_sorcery_retrieve_by_id(ast_stir_shaken_sorcery(), CONFIG_TYPE, id);
46 }
47
48 static struct ao2_container *stir_shaken_store_get_all(void)
49 {
50 return ast_sorcery_retrieve_by_fields(ast_stir_shaken_sorcery(), CONFIG_TYPE,
51 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
52 }
53
54 static void stir_shaken_store_destructor(void *obj)
55 {
56 struct stir_shaken_store *cfg = obj;
57
58 ast_string_field_free_memory(cfg);
59 }
60
61 static void *stir_shaken_store_alloc(const char *name)
62 {
63 struct stir_shaken_store *cfg;
64
65 cfg = ast_sorcery_generic_alloc(sizeof(*cfg), stir_shaken_store_destructor);
66 if (!cfg) {
67 return NULL;
68 }
69
70 if (ast_string_field_init(cfg, 512)) {
71 ao2_ref(cfg, -1);
72 return NULL;
73 }
74
75 return cfg;
76 }
77
78 static int stir_shaken_store_apply(const struct ast_sorcery *sorcery, void *obj)
79 {
80 return 0;
81 }
82
83 static char *stir_shaken_store_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
84 {
85 struct stir_shaken_store *cfg;
86
87 switch(cmd) {
88 case CLI_INIT:
89 e->command = "stir_shaken show store";
90 e->usage =
91 "Usage: stir_shaken show store <id>\n"
92 " Show the store stir/shaken settings for a given id\n";
93 return NULL;
94 case CLI_GENERATE:
95 if (a->pos == 3) {
96 return stir_shaken_tab_complete_name(a->word, stir_shaken_store_get_all());
97 } else {
98 return NULL;
99 };
100 }
101
102 if (a->argc != 4) {
103 return CLI_SHOWUSAGE;
104 }
105
106 cfg = stir_shaken_store_get(a->argv[3]);
107 stir_shaken_cli_show(cfg, a, 0);
108 ao2_cleanup(cfg);
109
110 return CLI_SUCCESS;
111 }
112
113 static struct ast_cli_entry stir_shaken_store_cli[] = {
114 AST_CLI_DEFINE(stir_shaken_store_show, "Show stir/shaken store configuration by id"),
115 };
116
117 static int on_load_path(const struct aco_option *opt, struct ast_variable *var, void *obj)
118 {
119 struct stir_shaken_store *cfg = obj;
120 struct stat statbuf;
121
122 if (stat(var->value, &statbuf)) {
123 ast_log(LOG_ERROR, "stir/shaken - path '%s' not found\n", var->value);
124 return -1;
125 }
126
127 if (!S_ISDIR(statbuf.st_mode)) {
128 ast_log(LOG_ERROR, "stir/shaken - path '%s' is not a directory\n", var->value);
129 return -1;
130 }
131
132 return ast_string_field_set(cfg, path, var->value);
133 }
134
135 static int path_to_str(const void *obj, const intptr_t *args, char **buf)
136 {
137 const struct stir_shaken_store *cfg = obj;
138
139 *buf = ast_strdup(cfg->path);
140
141 return 0;
142 }
143
144 static int on_load_public_key_url(const struct aco_option *opt, struct ast_variable *var, void *obj)
145 {
146 struct stir_shaken_store *cfg = obj;
147
148 if (!ast_begins_with(var->value, "http")) {
149 ast_log(LOG_ERROR, "stir/shaken - public_key_url scheme must be 'http[s]'\n");
150 return -1;
151 }
152
153 if (!strstr(var->value, VARIABLE_SUBSTITUTE)) {
154 ast_log(LOG_ERROR, "stir/shaken - public_key_url must contain variable '%s' "
155 "used for substitution\n", VARIABLE_SUBSTITUTE);
156 return -1;
157 }
158
159 return ast_string_field_set(cfg, public_key_url, var->value);
160 }
161
162 static int public_key_url_to_str(const void *obj, const intptr_t *args, char **buf)
163 {
164 const struct stir_shaken_store *cfg = obj;
165
166 *buf = ast_strdup(cfg->public_key_url);
167
168 return 0;
169 }
170
171 int stir_shaken_store_unload(void)
172 {
173 ast_cli_unregister_multiple(stir_shaken_store_cli,
174 ARRAY_LEN(stir_shaken_store_cli));
175
176 return 0;
177 }
178
179 int stir_shaken_store_load(void)
180 {
181 struct ast_sorcery *sorcery = ast_stir_shaken_sorcery();
182
183 ast_sorcery_apply_default(sorcery, CONFIG_TYPE, "config", "stir_shaken.conf,criteria=type=store");
184
185 if (ast_sorcery_object_register(sorcery, CONFIG_TYPE, stir_shaken_store_alloc,
186 NULL, stir_shaken_store_apply)) {
187 ast_log(LOG_ERROR, "stir/shaken - failed to register '%s' sorcery object\n", CONFIG_TYPE);
188 return -1;
189 }
190
191 ast_sorcery_object_field_register(sorcery, CONFIG_TYPE, "type", "", OPT_NOOP_T, 0, 0);
192 ast_sorcery_object_field_register_custom(sorcery, CONFIG_TYPE, "path", "",
193 on_load_path, path_to_str, NULL, 0, 0);
194 ast_sorcery_object_field_register_custom(sorcery, CONFIG_TYPE, "public_key_url", "",
195 on_load_public_key_url, public_key_url_to_str, NULL, 0, 0);
196
197 ast_cli_register_multiple(stir_shaken_store_cli,
198 ARRAY_LEN(stir_shaken_store_cli));
199
200 return 0;
201 }
0 /*
1 * Asterisk -- An open source telephony toolkit.
2 *
3 * Copyright (C) 2020, Sangoma Technologies Corporation
4 *
5 * Kevin Harwell <kharwell@sangoma.com>
6 *
7 * See http://www.asterisk.org for more information about
8 * the Asterisk project. Please do not directly contact
9 * any of the maintainers of this project for assistance;
10 * the project provides a web site, mailing lists and IRC
11 * channels for your use.
12 *
13 * This program is free software, distributed under the terms of
14 * the GNU General Public License Version 2. See the LICENSE file
15 * at the top of the source tree.
16 */
17 #ifndef _STIR_SHAKEN_STORE_H
18 #define _STIR_SHAKEN_STORE_H
19
20 struct ast_sorcery;
21
22 /*!
23 * \brief Load time initialization for the stir/shaken 'store' configuration
24 *
25 * \retval 0 on success, -1 on error
26 */
27 int stir_shaken_store_load(void);
28
29 /*!
30 * \brief Unload time cleanup for the stir/shaken 'store' configuration
31 *
32 * \retval 0 on success, -1 on error
33 */
34 int stir_shaken_store_unload(void);
35
36 #endif /* _STIR_SHAKEN_STORE_H */
0 /*
1 * Asterisk -- An open source telephony toolkit.
2 *
3 * Copyright (C) 2020, Sangoma Technologies Corporation
4 *
5 * Kevin Harwell <kharwell@digium.com>
6 *
7 * See http://www.asterisk.org for more information about
8 * the Asterisk project. Please do not directly contact
9 * any of the maintainers of this project for assistance;
10 * the project provides a web site, mailing lists and IRC
11 * channels for your use.
12 *
13 * This program is free software, distributed under the terms of
14 * the GNU General Public License Version 2. See the LICENSE file
15 * at the top of the source tree.
16 */
17
18 /*** MODULEINFO
19 <depend>crypto</depend>
20 <depend>curl</depend>
21 <depend>res_curl</depend>
22 <support_level>core</support_level>
23 ***/
24
25 #include "asterisk.h"
26
27 #include <openssl/evp.h>
28
29 #include "asterisk/module.h"
30 #include "asterisk/sorcery.h"
31 #include "asterisk/time.h"
32 #include "asterisk/json.h"
33 #include "asterisk/astdb.h"
34 #include "asterisk/paths.h"
35 #include "asterisk/conversions.h"
36 #include "asterisk/pbx.h"
37 #include "asterisk/global_datastores.h"
38 #include "asterisk/app.h"
39 #include "asterisk/test.h"
40
41 #include "asterisk/res_stir_shaken.h"
42 #include "res_stir_shaken/stir_shaken.h"
43 #include "res_stir_shaken/general.h"
44 #include "res_stir_shaken/store.h"
45 #include "res_stir_shaken/certificate.h"
46 #include "res_stir_shaken/curl.h"
47
48 /*** DOCUMENTATION
49 <configInfo name="res_stir_shaken" language="en_US">
50 <synopsis>STIR/SHAKEN module for Asterisk</synopsis>
51 <configFile name="stir_shaken.conf">
52 <configObject name="general">
53 <synopsis>STIR/SHAKEN general options</synopsis>
54 <configOption name="type">
55 <synopsis>Must be of type 'general'.</synopsis>
56 </configOption>
57 <configOption name="ca_file" default="">
58 <synopsis>File path to the certificate authority certificate</synopsis>
59 </configOption>
60 <configOption name="ca_path" default="">
61 <synopsis>File path to a chain of trust</synopsis>
62 </configOption>
63 <configOption name="cache_max_size" default="1000">
64 <synopsis>Maximum size to use for caching public keys</synopsis>
65 </configOption>
66 <configOption name="curl_timeout" default="2">
67 <synopsis>Maximum time to wait to CURL certificates</synopsis>
68 </configOption>
69 <configOption name="signature_timeout" default="15">
70 <synopsis>Amount of time a signature is valid for</synopsis>
71 </configOption>
72 </configObject>
73 <configObject name="store">
74 <synopsis>STIR/SHAKEN certificate store options</synopsis>
75 <configOption name="type">
76 <synopsis>Must be of type 'store'.</synopsis>
77 </configOption>
78 <configOption name="path" default="">
79 <synopsis>Path to a directory containing certificates</synopsis>
80 </configOption>
81 <configOption name="public_key_url" default="">
82 <synopsis>URL to the public key(s)</synopsis>
83 <description><para>
84 Must be a valid http, or https, URL. The URL must also contain the ${CERTIFICATE} variable, which is used for public key name substitution.
85 For example: http://mycompany.com/${CERTIFICATE}.pub
86 </para></description>
87 </configOption>
88 </configObject>
89 <configObject name="certificate">
90 <synopsis>STIR/SHAKEN certificate options</synopsis>
91 <configOption name="type">
92 <synopsis>Must be of type 'certificate'.</synopsis>
93 </configOption>
94 <configOption name="path" default="">
95 <synopsis>File path to a certificate</synopsis>
96 </configOption>
97 <configOption name="public_key_url" default="">
98 <synopsis>URL to the public key</synopsis>
99 <description><para>
100 Must be a valid http, or https, URL.
101 </para></description>
102 </configOption>
103 <configOption name="attestation">
104 <synopsis>Attestation level</synopsis>
105 </configOption>
106 <configOption name="origid" default="">
107 <synopsis>The origination ID</synopsis>
108 </configOption>
109 <configOption name="caller_id_number" default="">
110 <synopsis>The caller ID number to match on.</synopsis>
111 </configOption>
112 </configObject>
113 </configFile>
114 </configInfo>
115 <function name="STIR_SHAKEN" language="en_US">
116 <synopsis>
117 Gets the number of STIR/SHAKEN results or a specific STIR/SHAKEN value from a result on the channel.
118 </synopsis>
119 <syntax>
120 <parameter name="index" required="true">
121 <para>The index of the STIR/SHAKEN result to get. If only 'count' is passed in, gets the number of STIR/SHAKEN results instead.</para>
122 </parameter>
123 <parameter name="value" required="false">
124 <para>The value to get from the STIR/SHAKEN result. Only used when an index is passed in (instead of 'count'). Allowable values:</para>
125 <enumlist>
126 <enum name = "identity" />
127 <enum name = "attestation" />
128 <enum name = "verify_result" />
129 </enumlist>
130 </parameter>
131 </syntax>
132 <description>
133 <para>This function will either return the number of STIR/SHAKEN identities, or return information on the specified identity.
134 To get the number of identities, just pass 'count' as the only parameter to the function. If you want to get information on a
135 specific STIR/SHAKEN identity, you can get the number of identities and then pass an index as the first parameter and one of
136 the values you would like to retrieve as the second parameter.
137 </para>
138 <example title="Get count and retrieve value">
139 same => n,NoOp(Number of STIR/SHAKEN identities: ${STIR_SHAKEN(count)})
140 same => n,NoOp(Identity ${STIR_SHAKEN(0, identity)} has attestation level ${STIR_SHAKEN(0, attestation)})
141 </example>
142 </description>
143 </function>
144 ***/
145
146 static struct ast_sorcery *stir_shaken_sorcery;
147
148 /* Used for AstDB entries */
149 #define AST_DB_FAMILY "STIR_SHAKEN"
150
151 /* The directory name to store keys in. Appended to ast_config_DATA_DIR */
152 #define STIR_SHAKEN_DIR_NAME "stir_shaken"
153
154 /* The maximum length for path storage */
155 #define MAX_PATH_LEN 256
156
157 /* The default amount of time (in seconds) to use for certificate expiration
158 * if no cache data is available
159 */
160 #define EXPIRATION_BUFFER 15
161
162 struct ast_stir_shaken_payload {
163 /*! The JWT header */
164 struct ast_json *header;
165 /*! The JWT payload */
166 struct ast_json *payload;
167 /*! Signature for the payload */
168 unsigned char *signature;
169 /*! The algorithm used */
170 char *algorithm;
171 /*! THe URL to the public key for the certificate */
172 char *public_key_url;
173 };
174
175 struct ast_sorcery *ast_stir_shaken_sorcery(void)
176 {
177 return stir_shaken_sorcery;
178 }
179
180 void ast_stir_shaken_payload_free(struct ast_stir_shaken_payload *payload)
181 {
182 if (!payload) {
183 return;
184 }
185
186 ast_json_unref(payload->header);
187 ast_json_unref(payload->payload);
188 ast_free(payload->algorithm);
189 ast_free(payload->public_key_url);
190 ast_free(payload->signature);
191
192 ast_free(payload);
193 }
194
195 unsigned char *ast_stir_shaken_payload_get_signature(const struct ast_stir_shaken_payload *payload)
196 {
197 return payload ? payload->signature : NULL;
198 }
199
200 char *ast_stir_shaken_payload_get_public_key_url(const struct ast_stir_shaken_payload *payload)
201 {
202 return payload ? payload->public_key_url : NULL;
203 }
204
205 unsigned int ast_stir_shaken_get_signature_timeout(void)
206 {
207 return ast_stir_shaken_signature_timeout(stir_shaken_general_get());
208 }
209
210 /*!
211 * \brief Convert an ast_stir_shaken_verification_result to string representation
212 *
213 * \param result The result to convert
214 *
215 * \retval empty string if not a valid enum value
216 * \retval string representation of result otherwise
217 */
218 static const char *stir_shaken_verification_result_to_string(enum ast_stir_shaken_verification_result result)
219 {
220 switch (result) {
221 case AST_STIR_SHAKEN_VERIFY_NOT_PRESENT:
222 return "Verification not present";
223 case AST_STIR_SHAKEN_VERIFY_SIGNATURE_FAILED:
224 return "Signature failed";
225 case AST_STIR_SHAKEN_VERIFY_MISMATCH:
226 return "Verification mismatch";
227 case AST_STIR_SHAKEN_VERIFY_PASSED:
228 return "Verification passed";
229 default:
230 break;
231 }
232
233 return "";
234 }
235
236 /* The datastore struct holding verification information for the channel */
237 struct stir_shaken_datastore {
238 /* The identitifier for the STIR/SHAKEN verification */
239 char *identity;
240 /* The attestation value */
241 char *attestation;
242 /* The actual verification result */
243 enum ast_stir_shaken_verification_result verify_result;
244 };
245
246 /*!
247 * \brief Frees a stir_shaken_datastore structure
248 *
249 * \param datastore The datastore to free
250 */
251 static void stir_shaken_datastore_free(struct stir_shaken_datastore *datastore)
252 {
253 if (!datastore) {
254 return;
255 }
256
257 ast_free(datastore->identity);
258 ast_free(datastore->attestation);
259 ast_free(datastore);
260 }
261
262 /*!
263 * \brief The callback to destroy a stir_shaken_datastore
264 *
265 * \param data The stir_shaken_datastore
266 */
267 static void stir_shaken_datastore_destroy_cb(void *data)
268 {
269 struct stir_shaken_datastore *datastore = data;
270 stir_shaken_datastore_free(datastore);
271 }
272
273 /* The stir_shaken_datastore info used to add and compare stir_shaken_datastores on the channel */
274 static const struct ast_datastore_info stir_shaken_datastore_info = {
275 .type = "STIR/SHAKEN VERIFICATION",
276 .destroy = stir_shaken_datastore_destroy_cb,
277 };
278
279 int ast_stir_shaken_add_verification(struct ast_channel *chan, const char *identity, const char *attestation,
280 enum ast_stir_shaken_verification_result result)
281 {
282 struct stir_shaken_datastore *ss_datastore;
283 struct ast_datastore *datastore;
284 const char *chan_name;
285
286 if (!chan) {
287 ast_log(LOG_ERROR, "Channel is required to add STIR/SHAKEN verification\n");
288 return -1;
289 }
290
291 chan_name = ast_channel_name(chan);
292
293 if (!identity) {
294 ast_log(LOG_ERROR, "No identity to add STIR/SHAKEN verification to channel "
295 "%s\n", chan_name);
296 return -1;
297 }
298
299 if (!attestation) {
300 ast_log(LOG_ERROR, "Attestation cannot be NULL to add STIR/SHAKEN verification to "
301 "channel %s\n", chan_name);
302 return -1;
303 }
304
305 ss_datastore = ast_calloc(1, sizeof(*ss_datastore));
306 if (!ss_datastore) {
307 ast_log(LOG_ERROR, "Failed to allocate space for STIR/SHAKEN datastore for "
308 "channel %s\n", chan_name);
309 return -1;
310 }
311
312 ss_datastore->identity = ast_strdup(identity);
313 if (!ss_datastore->identity) {
314 ast_log(LOG_ERROR, "Failed to allocate space for STIR/SHAKEN datastore "
315 "identity for channel %s\n", chan_name);
316 stir_shaken_datastore_free(ss_datastore);
317 return -1;
318 }
319
320 ss_datastore->attestation = ast_strdup(attestation);
321 if (!ss_datastore->attestation) {
322 ast_log(LOG_ERROR, "Failed to allocate space for STIR/SHAKEN datastore "
323 "attestation for channel %s\n", chan_name);
324 stir_shaken_datastore_free(ss_datastore);
325 return -1;
326 }
327
328 ss_datastore->verify_result = result;
329
330 datastore = ast_datastore_alloc(&stir_shaken_datastore_info, NULL);
331 if (!datastore) {
332 ast_log(LOG_ERROR, "Failed to allocate space for datastore for channel "
333 "%s\n", chan_name);
334 stir_shaken_datastore_free(ss_datastore);
335 return -1;
336 }
337
338 datastore->data = ss_datastore;
339
340 ast_channel_lock(chan);
341 ast_channel_datastore_add(chan, datastore);
342 ast_channel_unlock(chan);
343
344 return 0;
345 }
346
347 /*!
348 * \brief Sets the expiration for the public key based on the provided fields.
349 * If Cache-Control is present, use it. Otherwise, use Expires.
350 *
351 * \param hash The hash for the public key URL
352 * \param data The CURL callback data containing expiration data
353 */
354 static void set_public_key_expiration(const char *public_key_url, const struct curl_cb_data *data)
355 {
356 char time_buf[32];
357 char *value;
358 struct timeval actual_expires = ast_tvnow();
359 char hash[41];
360
361 ast_sha1_hash(hash, public_key_url);
362
363 value = curl_cb_data_get_cache_control(data);
364 if (!ast_strlen_zero(value)) {
365 char *str_max_age;
366
367 str_max_age = strstr(value, "s-maxage");
368 if (!str_max_age) {
369 str_max_age = strstr(value, "max-age");
370 }
371
372 if (str_max_age) {
373 unsigned int max_age;
374 char *equal = strchr(str_max_age, '=');
375 if (equal && !ast_str_to_uint(equal + 1, &max_age)) {
376 actual_expires.tv_sec += max_age;
377 }
378 }
379 } else {
380 value = curl_cb_data_get_expires(data);
381 if (!ast_strlen_zero(value)) {
382 struct tm expires_time;
383
384 strptime(value, "%a, %d %b %Y %T %z", &expires_time);
385 expires_time.tm_isdst = -1;
386 actual_expires.tv_sec = mktime(&expires_time);
387 }
388 }
389
390 if (ast_strlen_zero(value)) {
391 actual_expires.tv_sec += EXPIRATION_BUFFER;
392 }
393
394 snprintf(time_buf, sizeof(time_buf), "%30lu", actual_expires.tv_sec);
395
396 ast_db_put(hash, "expiration", time_buf);
397 }
398
399 /*!
400 * \brief Check to see if the public key is expired
401 *
402 * \param public_key_url The public key URL
403 *
404 * \retval 1 if expired
405 * \retval 0 if not expired
406 */
407 static int public_key_is_expired(const char *public_key_url)
408 {
409 struct timeval current_time = ast_tvnow();
410 struct timeval expires = { .tv_sec = 0, .tv_usec = 0 };
411 char expiration[32];
412 char hash[41];
413
414 ast_sha1_hash(hash, public_key_url);
415 ast_db_get(hash, "expiration", expiration, sizeof(expiration));
416
417 if (ast_strlen_zero(expiration)) {
418 return 1;
419 }
420
421 if (ast_str_to_ulong(expiration, (unsigned long *)&expires.tv_sec)) {
422 return 1;
423 }
424
425 return ast_tvcmp(current_time, expires) == -1 ? 0 : 1;
426 }
427
428 /*!
429 * \brief Returns the path to the downloaded file for the provided URL
430 *
431 * \param public_key_url The public key URL
432 *
433 * \retval Empty string if not present in AstDB
434 * \retval The file path if present in AstDB
435 */
436 static char *get_path_to_public_key(const char *public_key_url)
437 {
438 char hash[41];
439 char file_path[MAX_PATH_LEN];
440
441 ast_sha1_hash(hash, public_key_url);
442
443 ast_db_get(hash, "path", file_path, sizeof(file_path));
444
445 if (ast_strlen_zero(file_path)) {
446 file_path[0] = '\0';
447 }
448
449 return ast_strdup(file_path);
450 }
451
452 /*!
453 * \brief Add the public key details and file path to AstDB
454 *
455 * \param public_key_url The public key URL
456 * \param filepath The path to the file
457 */
458 static void add_public_key_to_astdb(const char *public_key_url, const char *filepath)
459 {
460 char hash[41];
461
462 ast_sha1_hash(hash, public_key_url);
463
464 ast_db_put(AST_DB_FAMILY, public_key_url, hash);
465 ast_db_put(hash, "path", filepath);
466 }
467
468 /*!
469 * \brief Remove the public key details and associated information from AstDB
470 *
471 * \param public_key_url The public key URL
472 */
473 static void remove_public_key_from_astdb(const char *public_key_url)
474 {
475 char hash[41];
476 char filepath[MAX_PATH_LEN];
477
478 ast_sha1_hash(hash, public_key_url);
479
480 /* Remove this public key from storage */
481 ast_db_get(hash, "path", filepath, sizeof(filepath));
482
483 /* Remove the actual file from the system */
484 remove(filepath);
485
486 ast_db_del(AST_DB_FAMILY, public_key_url);
487 ast_db_deltree(hash, NULL);
488 }
489
490 /*!
491 * \brief Verifies the signature using a public key
492 *
493 * \param msg The payload
494 * \param signature The signature to verify
495 * \param public_key The public key used for verification
496 *
497 * \retval -1 on failure
498 * \retval 0 on success
499 */
500 static int stir_shaken_verify_signature(const char *msg, const char *signature, EVP_PKEY *public_key)
501 {
502 EVP_MD_CTX *mdctx = NULL;
503 int ret = 0;
504 unsigned char *decoded_signature;
505 size_t signature_length, decoded_signature_length, padding = 0;
506
507 mdctx = EVP_MD_CTX_create();
508 if (!mdctx) {
509 ast_log(LOG_ERROR, "Failed to create Message Digest Context\n");
510 return -1;
511 }
512
513 ret = EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, public_key);
514 if (ret != 1) {
515 ast_log(LOG_ERROR, "Failed to initialize Message Digest Context\n");
516 EVP_MD_CTX_destroy(mdctx);
517 return -1;
518 }
519
520 ret = EVP_DigestVerifyUpdate(mdctx, (unsigned char *)msg, strlen(msg));
521 if (ret != 1) {
522 ast_log(LOG_ERROR, "Failed to update Message Digest Context\n");
523 EVP_MD_CTX_destroy(mdctx);
524 return -1;
525 }
526
527 /* We need to decode the signature from base64 to bytes. Make sure we have
528 * at least enough characters for this check */
529 signature_length = strlen(signature);
530 if (signature_length > 2 && signature[signature_length - 1] == '=') {
531 padding++;
532 if (signature[signature_length - 2] == '=') {
533 padding++;
534 }
535 }
536
537 decoded_signature_length = (signature_length / 4 * 3) - padding;
538 decoded_signature = ast_calloc(1, decoded_signature_length);
539 ast_base64decode(decoded_signature, signature, decoded_signature_length);
540
541 ret = EVP_DigestVerifyFinal(mdctx, decoded_signature, decoded_signature_length);
542 if (ret != 1) {
543 ast_log(LOG_ERROR, "Failed final phase of signature verification\n");
544 EVP_MD_CTX_destroy(mdctx);
545 ast_free(decoded_signature);
546 return -1;
547 }
548
549 EVP_MD_CTX_destroy(mdctx);
550 ast_free(decoded_signature);
551
552 return 0;
553 }
554
555 /*!
556 * \brief CURL the file located at public_key_url to the specified path
557 *
558 * \param public_key_url The public key URL
559 * \param path The path to download the file to
560 *
561 * \retval -1 on failure
562 * \retval 0 on success
563 */
564 static int run_curl(const char *public_key_url, const char *path)
565 {
566 struct curl_cb_data *data;
567
568 data = curl_cb_data_create();
569 if (!data) {
570 ast_log(LOG_ERROR, "Failed to create CURL callback data\n");
571 return -1;
572 }
573
574 if (curl_public_key(public_key_url, path, data)) {
575 ast_log(LOG_ERROR, "Could not retrieve public key for '%s'\n", public_key_url);
576 curl_cb_data_free(data);
577 return -1;
578 }
579
580 set_public_key_expiration(public_key_url, data);
581 curl_cb_data_free(data);
582
583 return 0;
584 }
585
586 /*!
587 * \brief Downloads the public key from public_key_url. If curl is non-zero, that signals
588 * CURL has already been run, and we should bail here. The entry is added to AstDB as well.
589 *
590 * \param public_key_url The public key URL
591 * \param path The path to download the file to
592 * \param curl Flag signaling if we have run CURL or not
593 *
594 * \retval -1 on failure
595 * \retval 0 on success
596 */
597 static int curl_and_check_expiration(const char *public_key_url, const char *path, int *curl)
598 {
599 if (curl) {
600 ast_log(LOG_ERROR, "Already downloaded public key '%s'\n", path);
601 return -1;
602 }
603
604 if (run_curl(public_key_url, path)) {
605 return -1;
606 }
607
608 if (public_key_is_expired(public_key_url)) {
609 ast_log(LOG_ERROR, "Newly downloaded public key '%s' is expired\n", path);
610 return -1;
611 }
612
613 *curl = 1;
614 add_public_key_to_astdb(public_key_url, path);
615
616 return 0;
617 }
618
619 struct ast_stir_shaken_payload *ast_stir_shaken_verify(const char *header, const char *payload, const char *signature,
620 const char *algorithm, const char *public_key_url)
621 {
622 struct ast_stir_shaken_payload *ret_payload;
623 EVP_PKEY *public_key;
624 char *filename;
625 int curl = 0;
626 RAII_VAR(char *, file_path, NULL, ast_free);
627 RAII_VAR(char *, combined_str, NULL, ast_free);
628 size_t combined_size;
629
630 if (ast_strlen_zero(header)) {
631 ast_log(LOG_ERROR, "'header' is required for STIR/SHAKEN verification\n");
632 return NULL;
633 }
634
635 if (ast_strlen_zero(payload)) {
636 ast_log(LOG_ERROR, "'payload' is required for STIR/SHAKEN verification\n");
637 return NULL;
638 }
639
640 if (ast_strlen_zero(signature)) {
641 ast_log(LOG_ERROR, "'signature' is required for STIR/SHAKEN verification\n");
642 return NULL;
643 }
644
645 if (ast_strlen_zero(algorithm)) {
646 ast_log(LOG_ERROR, "'algorithm' is required for STIR/SHAKEN verification\n");
647 return NULL;
648 }
649
650 if (ast_strlen_zero(public_key_url)) {
651 ast_log(LOG_ERROR, "'public_key_url' is required for STIR/SHAKEN verification\n");
652 return NULL;
653 }
654
655 /* Check to see if we have already downloaded this public key. The reason we
656 * store the file path is because:
657 *
658 * 1. If, for some reason, the default directory changes, we still know where
659 * to look for the files we already have.
660 *
661 * 2. In the future, if we want to add a way to store the keys in multiple
662 * {configurable) directories, we already have the storage mechanism in place.
663 * The only thing that would be left to do is pull from the configuration.
664 */
665 file_path = get_path_to_public_key(public_key_url);
666
667 /* If we don't have an entry in AstDB, CURL from the provided URL */
668 if (ast_strlen_zero(file_path)) {
669 /* Remove this entry from the database, since we will be
670 * downloading a new file anyways.
671 */
672 remove_public_key_from_astdb(public_key_url);
673
674 /* Go ahead and free file_path, in case anything was allocated above */
675 ast_free(file_path);
676
677 /* Set up the default path */
678 filename = basename(public_key_url);
679 if (ast_asprintf(&file_path, "%s/keys/%s/%s", ast_config_AST_DATA_DIR, STIR_SHAKEN_DIR_NAME, filename) < 0) {
680 return NULL;
681 }
682
683 /* Download to the default path */
684 if (run_curl(public_key_url, file_path)) {
685 return NULL;
686 }
687
688 /* Signal that we have already downloaded a new file, no reason to do it again */
689 curl = 1;
690
691 /* We should have a successful download at this point, so
692 * add an entry to the database.
693 */
694 add_public_key_to_astdb(public_key_url, file_path);
695 }
696
697 /* Check to see if the key we downloaded (or already had) is expired */
698 if (public_key_is_expired(public_key_url)) {
699
700 ast_debug(3, "Public key '%s' is expired\n", public_key_url);
701
702 remove_public_key_from_astdb(public_key_url);
703
704 /* If this fails, then there's nothing we can do */
705 if (curl_and_check_expiration(public_key_url, file_path, &curl)) {
706 return NULL;
707 }
708 }
709
710 /* First attempt to read the key. If it fails, try downloading the file,
711 * unless we already did. Check for expiration again */
712 public_key = stir_shaken_read_key(file_path, 0);
713 if (!public_key) {
714
715 ast_debug(3, "Failed first read of public key file '%s'\n", file_path);
716
717 remove_public_key_from_astdb(public_key_url);
718
719 if (curl_and_check_expiration(public_key_url, file_path, &curl)) {
720 return NULL;
721 }
722
723 public_key = stir_shaken_read_key(file_path, 0);
724 if (!public_key) {
725 ast_log(LOG_ERROR, "Failed to read public key from '%s'\n", file_path);
726 remove_public_key_from_astdb(public_key_url);
727 return NULL;
728 }
729 }
730
731 /* Combine the header and payload to get the original signed message: header.payload */
732 combined_size = strlen(header) + strlen(payload) + 2;
733 combined_str = ast_calloc(1, combined_size);
734 if (!combined_str) {
735 ast_log(LOG_ERROR, "Failed to allocate space for message to verify\n");
736 EVP_PKEY_free(public_key);
737 return NULL;
738 }
739 snprintf(combined_str, combined_size, "%s.%s", header, payload);
740 if (stir_shaken_verify_signature(combined_str, signature, public_key)) {
741 ast_log(LOG_ERROR, "Failed to verify signature\n");
742 EVP_PKEY_free(public_key);
743 return NULL;
744 }
745
746 /* We don't need the public key anymore */
747 EVP_PKEY_free(public_key);
748
749 ret_payload = ast_calloc(1, sizeof(*ret_payload));
750 if (!ret_payload) {
751 ast_log(LOG_ERROR, "Failed to allocate STIR/SHAKEN payload\n");
752 return NULL;
753 }
754
755 ret_payload->header = ast_json_load_string(header, NULL);
756 if (!ret_payload->header) {
757 ast_log(LOG_ERROR, "Failed to create JSON from header\n");
758 ast_stir_shaken_payload_free(ret_payload);
759 return NULL;
760 }
761
762 ret_payload->payload = ast_json_load_string(payload, NULL);
763 if (!ret_payload->payload) {
764 ast_log(LOG_ERROR, "Failed to create JSON from payload\n");
765 ast_stir_shaken_payload_free(ret_payload);
766 return NULL;
767 }
768
769 ret_payload->signature = (unsigned char *)ast_strdup(signature);
770 ret_payload->algorithm = ast_strdup(algorithm);
771 ret_payload->public_key_url = ast_strdup(public_key_url);
772
773 return ret_payload;
774 }
775
776 /*!
777 * \brief Verifies the necessary contents are in the JSON and returns a
778 * ast_stir_shaken_payload with the extracted values.
779 *
780 * \param json The JSON to verify
781 *
782 * \return ast_stir_shaken_payload on success
783 * \return NULL on failure
784 */
785 static struct ast_stir_shaken_payload *stir_shaken_verify_json(struct ast_json *json)
786 {
787 struct ast_stir_shaken_payload *payload;
788 struct ast_json *obj;
789 const char *val;
790
791 payload = ast_calloc(1, sizeof(*payload));
792 if (!payload) {
793 ast_log(LOG_ERROR, "Failed to allocate STIR/SHAKEN payload\n");
794 goto cleanup;
795 }
796
797 /* Look through the header first */
798 obj = ast_json_object_get(json, "header");
799 if (!obj) {
800 ast_log(LOG_ERROR, "STIR/SHAKEN JWT did not have the required field 'header'\n");
801 goto cleanup;
802 }
803
804 payload->header = ast_json_deep_copy(obj);
805 if (!payload->header) {
806 ast_log(LOG_ERROR, "STIR_SHAKEN payload failed to copy 'header'\n");
807 goto cleanup;
808 }
809
810 /* Check the ppt value for "shaken" */
811 val = ast_json_string_get(ast_json_object_get(obj, "ppt"));
812 if (ast_strlen_zero(val)) {
813 ast_log(LOG_ERROR, "STIR/SHAKEN JWT did not have the required field 'ppt'\n");
814 goto cleanup;
815 }
816 if (strcmp(val, STIR_SHAKEN_PPT)) {
817 ast_log(LOG_ERROR, "STIR/SHAKEN JWT field 'ppt' did not have "
818 "required value '%s' (was '%s')\n", STIR_SHAKEN_PPT, val);
819 goto cleanup;
820 }
821
822 /* Check the typ value for "passport" */
823 val = ast_json_string_get(ast_json_object_get(obj, "typ"));
824 if (ast_strlen_zero(val)) {
825 ast_log(LOG_ERROR, "STIR/SHAKEN JWT did not have the required field 'typ'\n");
826 goto cleanup;
827 }
828 if (strcmp(val, STIR_SHAKEN_TYPE)) {
829 ast_log(LOG_ERROR, "STIR/SHAKEN JWT field 'typ' did not have "
830 "required value '%s' (was '%s')\n", STIR_SHAKEN_TYPE, val);
831 goto cleanup;
832 }
833
834 /* Check the alg value for "ES256" */
835 val = ast_json_string_get(ast_json_object_get(obj, "alg"));
836 if (ast_strlen_zero(val)) {
837 ast_log(LOG_ERROR, "STIR/SHAKEN JWT did not have required field 'alg'\n");
838 goto cleanup;
839 }
840 if (strcmp(val, STIR_SHAKEN_ENCRYPTION_ALGORITHM)) {
841 ast_log(LOG_ERROR, "STIR/SHAKEN JWT field 'alg' did not have "
842 "required value '%s' (was '%s')\n", STIR_SHAKEN_ENCRYPTION_ALGORITHM, val);
843 goto cleanup;
844 }
845
846 payload->algorithm = ast_strdup(val);
847 if (!payload->algorithm) {
848 ast_log(LOG_ERROR, "STIR/SHAKEN payload failed to copy 'algorithm'\n");
849 goto cleanup;
850 }
851
852 /* Now let's check the payload section */
853 obj = ast_json_object_get(json, "payload");
854 if (!obj) {
855 ast_log(LOG_ERROR, "STIR/SHAKEN payload JWT did not have required field 'payload'\n");
856 goto cleanup;
857 }
858
859 /* Check the orig tn value for not NULL */
860 val = ast_json_string_get(ast_json_object_get(ast_json_object_get(obj, "orig"), "tn"));
861 if (ast_strlen_zero(val)) {
862 ast_log(LOG_ERROR, "STIR/SHAKEN JWT did not have required field 'orig->tn'\n");
863 goto cleanup;
864 }
865
866 /* Payload seems sane. Copy it and return on success */
867 payload->payload = ast_json_deep_copy(obj);
868 if (!payload->payload) {
869 ast_log(LOG_ERROR, "STIR/SHAKEN payload failed to copy 'payload'\n");
870 goto cleanup;
871 }
872
873 return payload;
874
875 cleanup:
876 ast_stir_shaken_payload_free(payload);
877 return NULL;
878 }
879
880 /*!
881 * \brief Signs the payload and returns the signature.
882 *
883 * \param json_str The string representation of the JSON
884 * \param private_key The private key used to sign the payload
885 *
886 * \retval signature on success
887 * \retval NULL on failure
888 */
889 static unsigned char *stir_shaken_sign(char *json_str, EVP_PKEY *private_key)
890 {
891 EVP_MD_CTX *mdctx = NULL;
892 int ret = 0;
893 unsigned char *encoded_signature = NULL;
894 unsigned char *signature = NULL;
895 size_t encoded_length = 0;
896 size_t signature_length = 0;
897
898 mdctx = EVP_MD_CTX_create();
899 if (!mdctx) {
900 ast_log(LOG_ERROR, "Failed to create Message Digest Context\n");
901 goto cleanup;
902 }
903
904 ret = EVP_DigestSignInit(mdctx, NULL, EVP_sha256(), NULL, private_key);
905 if (ret != 1) {
906 ast_log(LOG_ERROR, "Failed to initialize Message Digest Context\n");
907 goto cleanup;
908 }
909
910 ret = EVP_DigestSignUpdate(mdctx, json_str, strlen(json_str));
911 if (ret != 1) {
912 ast_log(LOG_ERROR, "Failed to update Message Digest Context\n");
913 goto cleanup;
914 }
915
916 ret = EVP_DigestSignFinal(mdctx, NULL, &signature_length);
917 if (ret != 1) {
918 ast_log(LOG_ERROR, "Failed initial phase of Message Digest Context signing\n");
919 goto cleanup;
920 }
921
922 signature = ast_calloc(1, sizeof(unsigned char) * signature_length);
923 if (!signature) {
924 ast_log(LOG_ERROR, "Failed to allocate space for signature\n");
925 goto cleanup;
926 }
927
928 ret = EVP_DigestSignFinal(mdctx, signature, &signature_length);
929 if (ret != 1) {
930 ast_log(LOG_ERROR, "Failed final phase of Message Digest Context signing\n");
931 goto cleanup;
932 }
933
934 /* There are 6 bits to 1 base64 digit, so in order to get the size of the base64 encoded
935 * signature, we need to multiply by the number of bits in a byte and divide by 6. Since
936 * there's rounding when doing base64 conversions, add 3 bytes, just in case, and account
937 * for padding. Add another byte for the NULL-terminator.
938 */
939 encoded_length = ((signature_length * 4 / 3 + 3) & ~3) + 1;
940 encoded_signature = ast_calloc(1, encoded_length);
941 if (!encoded_signature) {
942 ast_log(LOG_ERROR, "Failed to allocate space for encoded signature\n");
943 goto cleanup;
944 }
945
946 ast_base64encode((char *)encoded_signature, signature, signature_length, encoded_length);
947
948 cleanup:
949 if (mdctx) {
950 EVP_MD_CTX_destroy(mdctx);
951 }
952 ast_free(signature);
953
954 return encoded_signature;
955 }
956
957 /*!
958 * \brief Adds the 'x5u' (public key URL) field to the JWT.
959 *
960 * \param json The JWT
961 * \param x5u The public key URL
962 *
963 * \retval 0 on success
964 * \retval -1 on failure
965 */
966 static int stir_shaken_add_x5u(struct ast_json *json, const char *x5u)
967 {
968 struct ast_json *value;
969
970 value = ast_json_string_create(x5u);
971 if (!value) {
972 return -1;
973 }
974
975 return ast_json_object_set(ast_json_object_get(json, "header"), "x5u", value);
976 }
977
978 /*!
979 * \brief Adds the 'attest' field to the JWT.
980 *
981 * \param json The JWT
982 * \param attest The value to set attest to
983 *
984 * \retval 0 on success
985 * \retval -1 on failure
986 */
987 static int stir_shaken_add_attest(struct ast_json *json, const char *attest)
988 {
989 struct ast_json *value;
990
991 value = ast_json_string_create(attest);
992 if (!value) {
993 return -1;
994 }
995
996 return ast_json_object_set(ast_json_object_get(json, "payload"), "attest", value);
997 }
998
999 /*!
1000 * \brief Adds the 'origid' field to the JWT.
1001 *
1002 * \param json The JWT
1003 * \param origid The value to set origid to
1004 *
1005 * \retval 0 on success
1006 * \retval -1 on failure
1007 */
1008 static int stir_shaken_add_origid(struct ast_json *json, const char *origid)
1009 {
1010 struct ast_json *value;
1011
1012 value = ast_json_string_create(origid);
1013 if (!origid) {
1014 return -1;
1015 }
1016
1017 return ast_json_object_set(ast_json_object_get(json, "payload"), "origid", value);
1018 }
1019
1020 /*!
1021 * \brief Adds the 'iat' field to the JWT.
1022 *
1023 * \param json The JWT
1024 *
1025 * \retval 0 on success
1026 * \retval -1 on failure
1027 */
1028 static int stir_shaken_add_iat(struct ast_json *json)
1029 {
1030 struct ast_json *value;
1031 struct timeval tv;
1032 int timestamp;
1033
1034 tv = ast_tvnow();
1035 timestamp = tv.tv_sec + tv.tv_usec / 1000;
1036 value = ast_json_integer_create(timestamp);
1037
1038 return ast_json_object_set(ast_json_object_get(json, "payload"), "iat", value);
1039 }
1040
1041 struct ast_stir_shaken_payload *ast_stir_shaken_sign(struct ast_json *json)
1042 {
1043 struct ast_stir_shaken_payload *ss_payload;
1044 unsigned char *signature;
1045 const char *public_key_url;
1046 const char *caller_id_num;
1047 const char *header;
1048 const char *payload;
1049 struct ast_json *tmp_json;
1050 char *msg = NULL;
1051 size_t msg_len;
1052 struct stir_shaken_certificate *cert = NULL;
1053
1054 ss_payload = stir_shaken_verify_json(json);
1055 if (!ss_payload) {
1056 return NULL;
1057 }
1058
1059 /* From the payload section of the JSON, get the orig section, and then get
1060 * the value of tn. This will be the caller ID number */
1061 caller_id_num = ast_json_string_get(ast_json_object_get(ast_json_object_get(
1062 ast_json_object_get(json, "payload"), "orig"), "tn"));
1063 if (!caller_id_num) {
1064 ast_log(LOG_ERROR, "Failed to get caller ID number from JWT\n");
1065 goto cleanup;
1066 }
1067
1068 cert = stir_shaken_certificate_get_by_caller_id_number(caller_id_num);
1069 if (!cert) {
1070 ast_log(LOG_ERROR, "Failed to retrieve certificate for caller ID "
1071 "'%s'\n", caller_id_num);
1072 goto cleanup;
1073 }
1074
1075 public_key_url = stir_shaken_certificate_get_public_key_url(cert);
1076 if (stir_shaken_add_x5u(json, public_key_url)) {
1077 ast_log(LOG_ERROR, "Failed to add 'x5u' (public key URL) to payload\n");
1078 goto cleanup;
1079 }
1080 ss_payload->public_key_url = ast_strdup(public_key_url);
1081
1082 if (stir_shaken_add_attest(json, stir_shaken_certificate_get_attestation(cert))) {
1083 ast_log(LOG_ERROR, "Failed to add 'attest' to payload\n");
1084 goto cleanup;
1085 }
1086
1087 if (stir_shaken_add_origid(json, stir_shaken_certificate_get_origid(cert))) {
1088 ast_log(LOG_ERROR, "Failed to add 'origid' to payload\n");
1089 goto cleanup;
1090 }
1091
1092 if (stir_shaken_add_iat(json)) {
1093 ast_log(LOG_ERROR, "Failed to add 'iat' to payload\n");
1094 goto cleanup;
1095 }
1096
1097 /* Get the header and the payload. Combine them to get the message to sign */
1098 tmp_json = ast_json_object_get(json, "header");
1099 header = ast_json_dump_string(tmp_json);
1100 tmp_json = ast_json_object_get(json, "payload");
1101 payload = ast_json_dump_string(tmp_json);
1102 msg_len = strlen(header) + strlen(payload) + 2;
1103 msg = ast_calloc(1, msg_len);
1104 if (!msg) {
1105 ast_log(LOG_ERROR, "Failed to allocate space for message to sign\n");
1106 goto cleanup;
1107 }
1108 snprintf(msg, msg_len, "%s.%s", header, payload);
1109
1110 signature = stir_shaken_sign(msg, stir_shaken_certificate_get_private_key(cert));
1111 if (!signature) {
1112 goto cleanup;
1113 }
1114
1115 ss_payload->signature = signature;
1116 ao2_cleanup(cert);
1117 ast_free(msg);
1118
1119 return ss_payload;
1120
1121 cleanup:
1122 ao2_cleanup(cert);
1123 ast_stir_shaken_payload_free(ss_payload);
1124 ast_free(msg);
1125 return NULL;
1126 }
1127
1128 /*!
1129 * \brief Retrieves STIR/SHAKEN verification information for the channel via dialplan.
1130 * Examples:
1131 *
1132 * STIR_SHAKEN(count)
1133 * STIR_SHAKEN(0, identity)
1134 * STIR_SHAKEN(1, attestation)
1135 * STIR_SHAKEN(27, verify_result)
1136 *
1137 * \retval -1 on failure
1138 * \retval 0 on success
1139 */
1140 static int stir_shaken_read(struct ast_channel *chan, const char *function,
1141 char *data, char *buf, size_t len)
1142 {
1143 struct stir_shaken_datastore *ss_datastore;
1144 struct ast_datastore *datastore;
1145 char *parse;
1146 char *first;
1147 char *second;
1148 unsigned int target_index, current_index = 0;
1149 AST_DECLARE_APP_ARGS(args,
1150 AST_APP_ARG(first_param);
1151 AST_APP_ARG(second_param);
1152 );
1153
1154 if (ast_strlen_zero(data)) {
1155 ast_log(LOG_WARNING, "%s requires at least one argument\n", function);
1156 return -1;
1157 }
1158
1159 if (!chan) {
1160 ast_log(LOG_ERROR, "No channel for %s function\n", function);
1161 return -1;
1162 }
1163
1164 parse = ast_strdupa(data);
1165
1166 AST_STANDARD_APP_ARGS(args, parse);
1167
1168 first = ast_strip(args.first_param);
1169 if (ast_strlen_zero(first)) {
1170 ast_log(LOG_ERROR, "An argument must be passed to %s\n", function);
1171 return -1;
1172 }
1173
1174 second = ast_strip(args.second_param);
1175
1176 /* Check if we are only looking for the number of STIR/SHAKEN verification results */
1177 if (!strcasecmp(first, "count")) {
1178
1179 size_t count = 0;
1180
1181 if (!ast_strlen_zero(second)) {
1182 ast_log(LOG_ERROR, "%s only takes 1 paramater for 'count'\n", function);
1183 return -1;
1184 }
1185
1186 ast_channel_lock(chan);
1187 AST_LIST_TRAVERSE(ast_channel_datastores(chan), datastore, entry) {
1188 if (datastore->info != &stir_shaken_datastore_info) {
1189 continue;
1190 }
1191 count++;
1192 }
1193 ast_channel_unlock(chan);
1194
1195 snprintf(buf, len, "%zu", count);
1196 return 0;
1197 }
1198
1199 /* If we aren't doing a count, then there should be two parameters. The field
1200 * we are searching for will be the second parameter. The index is the first.
1201 */
1202 if (ast_strlen_zero(second)) {
1203 ast_log(LOG_ERROR, "Retrieving a value using %s requires two paramaters (index, value) "
1204 "- only index was given\n", function);
1205 return -1;
1206 }
1207
1208 if (ast_str_to_uint(first, &target_index)) {
1209 ast_log(LOG_ERROR, "Failed to convert index %s to integer for function %s\n",
1210 first, function);
1211 return -1;
1212 }
1213
1214 /* We don't store by uid for the datastore, so just search for the specified index */
1215 ast_channel_lock(chan);
1216 AST_LIST_TRAVERSE(ast_channel_datastores(chan), datastore, entry) {
1217 if (datastore->info != &stir_shaken_datastore_info) {
1218 continue;
1219 }
1220
1221 if (current_index == target_index) {
1222 break;
1223 }
1224
1225 current_index++;
1226 }
1227 ast_channel_unlock(chan);
1228 if (current_index != target_index || !datastore) {
1229 ast_log(LOG_WARNING, "No STIR/SHAKEN results for index '%s'\n", first);
1230 return -1;
1231 }
1232 ss_datastore = datastore->data;
1233
1234 if (!strcasecmp(second, "identity")) {
1235 ast_copy_string(buf, ss_datastore->identity, len);
1236 } else if (!strcasecmp(second, "attestation")) {
1237 ast_copy_string(buf, ss_datastore->attestation, len);
1238 } else if (!strcasecmp(second, "verify_result")) {
1239 ast_copy_string(buf, stir_shaken_verification_result_to_string(ss_datastore->verify_result), len);
1240 } else {
1241 ast_log(LOG_ERROR, "No such value '%s' for %s\n", second, function);
1242 return -1;
1243 }
1244
1245 return 0;
1246 }
1247
1248 static struct ast_custom_function stir_shaken_function = {
1249 .name = "STIR_SHAKEN",
1250 .read = stir_shaken_read,
1251 };
1252
1253 #ifdef TEST_FRAMEWORK
1254
1255 static void test_stir_shaken_add_fake_astdb_entry(const char *public_key_url, const char *file_path)
1256 {
1257 struct timeval expires = ast_tvnow();
1258 char time_buf[32];
1259 char hash[41];
1260
1261 ast_sha1_hash(hash, public_key_url);
1262 add_public_key_to_astdb(public_key_url, file_path);
1263 snprintf(time_buf, sizeof(time_buf), "%30lu", expires.tv_sec + 300);
1264
1265 ast_db_put(hash, "expiration", time_buf);
1266 }
1267
1268 /*!
1269 * \brief Create a private or public key certificate
1270 *
1271 * \param file_path The path of the file to create
1272 * \param private Set to 0 if public, 1 if private
1273 *
1274 * \retval -1 on failure
1275 * \retval 0 on success
1276 */
1277 static int test_stir_shaken_write_temp_key(char *file_path, int private)
1278 {
1279 FILE *file;
1280 int fd;
1281 char *data;
1282 char *type = private ? "private" : "public";
1283 char *private_data =
1284 "-----BEGIN EC PRIVATE KEY-----\n"
1285 "MHcCAQEEIFkNGlrmRky2j7wmjGBGoPFBsyEQELmEYN02BiiG508noAoGCCqGSM49\n"
1286 "AwEHoUQDQgAECwCaeAYwVG/FAnEnkwaucz6o047iSWq3cJBBUc0n2ZlUDr5VywAz\n"
1287 "MZ86EthIqF3CGZjhLHn0xRITXYwfqTtWBw==\n"
1288 "-----END EC PRIVATE KEY-----";
1289 char *public_data =
1290 "-----BEGIN PUBLIC KEY-----\n"
1291 "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECwCaeAYwVG/FAnEnkwaucz6o047i\n"
1292 "SWq3cJBBUc0n2ZlUDr5VywAzMZ86EthIqF3CGZjhLHn0xRITXYwfqTtWBw==\n"
1293 "-----END PUBLIC KEY-----";
1294
1295 fd = mkstemp(file_path);
1296 if (fd < 0) {
1297 ast_log(LOG_ERROR, "Failed to create temp %s file: %s\n", type, strerror(errno));
1298 return -1;
1299 }
1300
1301 file = fdopen(fd, "w");
1302 if (!file) {
1303 ast_log(LOG_ERROR, "Failed to create temp %s key file: %s\n", type, strerror(errno));
1304 return -1;
1305 }
1306
1307 data = private ? private_data : public_data;
1308 if (fputs(data, file) == EOF) {
1309 ast_log(LOG_ERROR, "Failed to write temp %s key file\n", type);
1310 fclose(file);
1311 return -1;
1312 }
1313
1314 fclose(file);
1315
1316 return 0;
1317 }
1318
1319 AST_TEST_DEFINE(test_stir_shaken_sign)
1320 {
1321 char *caller_id_number = "1234567";
1322 char file_path[] = "/tmp/stir_shaken_private.XXXXXX";
1323 RAII_VAR(char *, rm_on_exit, file_path, unlink);
1324 RAII_VAR(struct ast_json *, json, NULL, ast_json_free);
1325 RAII_VAR(struct ast_stir_shaken_payload *, payload, NULL, ast_stir_shaken_payload_free);
1326
1327 switch (cmd) {
1328 case TEST_INIT:
1329 info->name = "stir_shaken_sign";
1330 info->category = "/res/res_stir_shaken/";
1331 info->summary = "STIR/SHAKEN sign unit test";
1332 info->description =
1333 "Tests signing a JWT with a private key.";
1334 return AST_TEST_NOT_RUN;
1335 case TEST_EXECUTE:
1336 break;
1337 }
1338
1339 /* We only need a private key to sign */
1340 test_stir_shaken_write_temp_key(file_path, 1);
1341 test_stir_shaken_create_cert(caller_id_number, file_path);
1342
1343 /* Test missing header section */
1344 json = ast_json_pack("{s: {s: {s: s}}}", "payload", "orig", "tn", caller_id_number);
1345 payload = ast_stir_shaken_sign(json);
1346 if (payload) {
1347 ast_test_status_update(test, "Signed an invalid JWT (missing 'header')\n");
1348 test_stir_shaken_cleanup_cert(caller_id_number);
1349 return AST_TEST_FAIL;
1350 }
1351
1352 /* Test missing payload section */
1353 ast_json_free(json);
1354 json = ast_json_pack("{s: {s: s, s: s, s: s, s: s}}", "header", "alg",
1355 STIR_SHAKEN_ENCRYPTION_ALGORITHM, "ppt", STIR_SHAKEN_PPT, "typ", STIR_SHAKEN_TYPE,
1356 "x5u", "http://testing123");
1357 payload = ast_stir_shaken_sign(json);
1358 if (payload) {
1359 ast_test_status_update(test, "Signed an invalid JWT (missing 'payload')\n");
1360 test_stir_shaken_cleanup_cert(caller_id_number);
1361 return AST_TEST_FAIL;
1362 }
1363
1364 /* Test missing alg section */
1365 ast_json_free(json);
1366 json = ast_json_pack("{s: {s: s, s: s, s: s}, s: {s: {s: s}}}", "header", "ppt",
1367 STIR_SHAKEN_PPT, "typ", STIR_SHAKEN_TYPE, "x5u", "http://testing123", "payload",
1368 "orig", "tn", caller_id_number);
1369 payload = ast_stir_shaken_sign(json);
1370 if (payload) {
1371 ast_test_status_update(test, "Signed an invalid JWT (missing 'alg')\n");
1372 test_stir_shaken_cleanup_cert(caller_id_number);
1373 return AST_TEST_FAIL;
1374 }
1375
1376 /* Test invalid alg value */
1377 ast_json_free(json);
1378 json = ast_json_pack("{s: {s: s, s: s, s: s, s: s}, s: {s: {s: s}}}", "header", "alg",
1379 "invalid algorithm", "ppt", STIR_SHAKEN_PPT, "typ", STIR_SHAKEN_TYPE,
1380 "x5u", "http://testing123", "payload", "orig", "tn", caller_id_number);
1381 payload = ast_stir_shaken_sign(json);
1382 if (payload) {
1383 ast_test_status_update(test, "Signed an invalid JWT (wrong 'alg')\n");
1384 test_stir_shaken_cleanup_cert(caller_id_number);
1385 return AST_TEST_FAIL;
1386 }
1387
1388 /* Test missing ppt section */
1389 ast_json_free(json);
1390 json = ast_json_pack("{s: {s: s, s: s, s: s}, s: {s: {s: s}}}", "header", "alg",
1391 STIR_SHAKEN_ENCRYPTION_ALGORITHM, "typ", STIR_SHAKEN_TYPE, "x5u", "http://testing123",
1392 "payload", "orig", "tn", caller_id_number);
1393 payload = ast_stir_shaken_sign(json);
1394 if (payload) {
1395 ast_test_status_update(test, "Signed an invalid JWT (missing 'ppt')\n");
1396 test_stir_shaken_cleanup_cert(caller_id_number);
1397 return AST_TEST_FAIL;
1398 }
1399
1400 /* Test invalid ppt value */
1401 ast_json_free(json);
1402 json = ast_json_pack("{s: {s: s, s: s, s: s, s: s}, s: {s: {s: s}}}", "header", "alg",
1403 STIR_SHAKEN_ENCRYPTION_ALGORITHM, "ppt", "invalid ppt", "typ", STIR_SHAKEN_TYPE,
1404 "x5u", "http://testing123", "payload", "orig", "tn", caller_id_number);
1405 payload = ast_stir_shaken_sign(json);
1406 if (payload) {
1407 ast_test_status_update(test, "Signed an invalid JWT (wrong 'ppt')\n");
1408 test_stir_shaken_cleanup_cert(caller_id_number);
1409 return AST_TEST_FAIL;
1410 }
1411
1412 /* Test missing typ section */
1413 ast_json_free(json);
1414 json = ast_json_pack("{s: {s: s, s: s, s: s}, s: {s: {s: s}}}", "header", "alg",
1415 STIR_SHAKEN_ENCRYPTION_ALGORITHM, "ppt", STIR_SHAKEN_PPT, "x5u", "http://testing123",
1416 "payload", "orig", "tn", caller_id_number);
1417 payload = ast_stir_shaken_sign(json);
1418 if (payload) {
1419 ast_test_status_update(test, "Signed an invalid JWT (missing 'typ')\n");
1420 test_stir_shaken_cleanup_cert(caller_id_number);
1421 return AST_TEST_FAIL;
1422 }
1423
1424 /* Test invalid typ value */
1425 ast_json_free(json);
1426 json = ast_json_pack("{s: {s: s, s: s, s: s, s: s}, s: {s: {s: s}}}", "header", "alg",
1427 STIR_SHAKEN_ENCRYPTION_ALGORITHM, "ppt", STIR_SHAKEN_PPT, "typ", "invalid typ",
1428 "x5u", "http://testing123", "payload", "orig", "tn", caller_id_number);
1429 payload = ast_stir_shaken_sign(json);
1430 if (payload) {
1431 ast_test_status_update(test, "Signed an invalid JWT (wrong 'typ')\n");
1432 test_stir_shaken_cleanup_cert(caller_id_number);
1433 return AST_TEST_FAIL;
1434 }
1435
1436 /* Test missing orig section */
1437 ast_json_free(json);
1438 json = ast_json_pack("{s: {s: s, s: s, s: s, s: s}, s: {s: s}}", "header", "alg",
1439 STIR_SHAKEN_ENCRYPTION_ALGORITHM, "ppt", STIR_SHAKEN_PPT, "typ", STIR_SHAKEN_TYPE,
1440 "x5u", "http://testing123", "payload", "filler", "filler");
1441 payload = ast_stir_shaken_sign(json);
1442 if (payload) {
1443 ast_test_status_update(test, "Signed an invalid JWT (missing 'orig')\n");
1444 test_stir_shaken_cleanup_cert(caller_id_number);
1445 return AST_TEST_FAIL;
1446 }
1447
1448 /* Test missing tn section */
1449 ast_json_free(json);
1450 json = ast_json_pack("{s: {s: s, s: s, s: s, s: s}, s: {s: s}}", "header", "alg",
1451 STIR_SHAKEN_ENCRYPTION_ALGORITHM, "ppt", STIR_SHAKEN_PPT, "typ", STIR_SHAKEN_TYPE,
1452 "x5u", "http://testing123", "payload", "orig", "filler");
1453 payload = ast_stir_shaken_sign(json);
1454 if (payload) {
1455 ast_test_status_update(test, "Signed an invalid JWT (missing 'tn')\n");
1456 test_stir_shaken_cleanup_cert(caller_id_number);
1457 return AST_TEST_FAIL;
1458 }
1459
1460 /* Test valid JWT */
1461 ast_json_free(json);
1462 json = ast_json_pack("{s: {s: s, s: s, s: s, s: s}, s: {s: {s: s}}}", "header", "alg",
1463 STIR_SHAKEN_ENCRYPTION_ALGORITHM, "ppt", STIR_SHAKEN_PPT, "typ", STIR_SHAKEN_TYPE,
1464 "x5u", "http://testing123", "payload", "orig", "tn", caller_id_number);
1465 payload = ast_stir_shaken_sign(json);
1466 if (!payload) {
1467 ast_test_status_update(test, "Failed to sign a valid JWT\n");
1468 test_stir_shaken_cleanup_cert(caller_id_number);
1469 return AST_TEST_FAIL;
1470 }
1471
1472 test_stir_shaken_cleanup_cert(caller_id_number);
1473
1474 return AST_TEST_PASS;
1475 }
1476
1477 AST_TEST_DEFINE(test_stir_shaken_verify)
1478 {
1479 char *caller_id_number = "1234567";
1480 char *public_key_url = "http://testing123";
1481 char *header;
1482 char *payload;
1483 struct ast_json *tmp_json;
1484 char public_path[] = "/tmp/stir_shaken_public.XXXXXX";
1485 char private_path[] = "/tmp/stir_shaken_public.XXXXXX";
1486 RAII_VAR(char *, rm_on_exit_public, public_path, unlink);
1487 RAII_VAR(char *, rm_on_exit_private, private_path, unlink);
1488 RAII_VAR(struct ast_json *, json, NULL, ast_json_free);
1489 RAII_VAR(struct ast_stir_shaken_payload *, signed_payload, NULL, ast_stir_shaken_payload_free);
1490 RAII_VAR(struct ast_stir_shaken_payload *, returned_payload, NULL, ast_stir_shaken_payload_free);
1491
1492 switch (cmd) {
1493 case TEST_INIT:
1494 info->name = "stir_shaken_verify";
1495 info->category = "/res/res_stir_shaken/";
1496 info->summary = "STIR/SHAKEN verify unit test";
1497 info->description =
1498 "Tests verifying a signature with a public key";
1499 return AST_TEST_NOT_RUN;
1500 case TEST_EXECUTE:
1501 break;
1502 }
1503
1504 /* We need the private key to sign, but we also need the corresponding
1505 * public key to verify */
1506 test_stir_shaken_write_temp_key(public_path, 0);
1507 test_stir_shaken_write_temp_key(private_path, 1);
1508 test_stir_shaken_create_cert(caller_id_number, private_path);
1509
1510 /* Get the signature */
1511 json = ast_json_pack("{s: {s: s, s: s, s: s, s: s}, s: {s: {s: s}}}", "header", "alg",
1512 STIR_SHAKEN_ENCRYPTION_ALGORITHM, "ppt", STIR_SHAKEN_PPT, "typ", STIR_SHAKEN_TYPE,
1513 "x5u", public_key_url, "payload", "orig", "tn", caller_id_number);
1514 signed_payload = ast_stir_shaken_sign(json);
1515 if (!signed_payload) {
1516 ast_test_status_update(test, "Failed to sign a valid JWT\n");
1517 test_stir_shaken_cleanup_cert(caller_id_number);
1518 return AST_TEST_FAIL;
1519 }
1520
1521 /* Get the header and payload for ast_stir_shaken_verify */
1522 tmp_json = ast_json_object_get(json, "header");
1523 header = ast_json_dump_string(tmp_json);
1524 tmp_json = ast_json_object_get(json, "payload");
1525 payload = ast_json_dump_string(tmp_json);
1526
1527 /* Test empty header parameter */
1528 returned_payload = ast_stir_shaken_verify("", payload, (const char *)signed_payload->signature,
1529 STIR_SHAKEN_ENCRYPTION_ALGORITHM, public_key_url);
1530 if (returned_payload) {
1531 ast_test_status_update(test, "Verified a signature with missing 'header'\n");
1532 test_stir_shaken_cleanup_cert(caller_id_number);
1533 return AST_TEST_FAIL;
1534 }
1535
1536 /* Test empty payload parameter */
1537 returned_payload = ast_stir_shaken_verify(header, "", (const char *)signed_payload->signature,
1538 STIR_SHAKEN_ENCRYPTION_ALGORITHM, public_key_url);
1539 if (returned_payload) {
1540 ast_test_status_update(test, "Verified a signature with missing 'payload'\n");
1541 test_stir_shaken_cleanup_cert(caller_id_number);
1542 return AST_TEST_FAIL;
1543 }
1544
1545 /* Test empty signature parameter */
1546 returned_payload = ast_stir_shaken_verify(header, payload, "",
1547 STIR_SHAKEN_ENCRYPTION_ALGORITHM, public_key_url);
1548 if (returned_payload) {
1549 ast_test_status_update(test, "Verified a signature with missing 'signature'\n");
1550 test_stir_shaken_cleanup_cert(caller_id_number);
1551 return AST_TEST_FAIL;
1552 }
1553
1554 /* Test empty algorithm parameter */
1555 returned_payload = ast_stir_shaken_verify(header, payload, (const char *)signed_payload->signature,
1556 "", public_key_url);
1557 if (returned_payload) {
1558 ast_test_status_update(test, "Verified a signature with missing 'algorithm'\n");
1559 test_stir_shaken_cleanup_cert(caller_id_number);
1560 return AST_TEST_FAIL;
1561 }
1562
1563 /* Test empty public key URL */
1564 returned_payload = ast_stir_shaken_verify(header, payload, (const char *)signed_payload->signature,
1565 STIR_SHAKEN_ENCRYPTION_ALGORITHM, "");
1566 if (returned_payload) {
1567 ast_test_status_update(test, "Verified a signature with missing 'public key URL'\n");
1568 test_stir_shaken_cleanup_cert(caller_id_number);
1569 return AST_TEST_FAIL;
1570 }
1571
1572 /* Trick the function into thinking we've already downloaded the key */
1573 test_stir_shaken_add_fake_astdb_entry(public_key_url, public_path);
1574
1575 /* Verify a valid signature */
1576 returned_payload = ast_stir_shaken_verify(header, payload, (const char *)signed_payload->signature,
1577 STIR_SHAKEN_ENCRYPTION_ALGORITHM, public_key_url);
1578 if (!returned_payload) {
1579 ast_test_status_update(test, "Failed to verify a valid signature\n");
1580 remove_public_key_from_astdb(public_key_url);
1581 test_stir_shaken_cleanup_cert(caller_id_number);
1582 return AST_TEST_FAIL;
1583 }
1584
1585 remove_public_key_from_astdb(public_key_url);
1586
1587 test_stir_shaken_cleanup_cert(caller_id_number);
1588
1589 return AST_TEST_PASS;
1590 }
1591
1592 #endif /* TEST_FRAMEWORK */
1593
1594 static int reload_module(void)
1595 {
1596 if (stir_shaken_sorcery) {
1597 ast_sorcery_reload(stir_shaken_sorcery);
1598 }
1599
1600 return 0;
1601 }
1602
1603 static int unload_module(void)
1604 {
1605 int res = 0;
1606
1607 stir_shaken_certificate_unload();
1608 stir_shaken_store_unload();
1609 stir_shaken_general_unload();
1610
1611 ast_sorcery_unref(stir_shaken_sorcery);
1612 stir_shaken_sorcery = NULL;
1613
1614 res |= ast_custom_function_unregister(&stir_shaken_function);
1615
1616 AST_TEST_UNREGISTER(test_stir_shaken_sign);
1617 AST_TEST_UNREGISTER(test_stir_shaken_verify);
1618
1619 return res;
1620 }
1621
1622 static int load_module(void)
1623 {
1624 int res = 0;
1625
1626 if (!(stir_shaken_sorcery = ast_sorcery_open())) {
1627 ast_log(LOG_ERROR, "stir/shaken - failed to open sorcery\n");
1628 return AST_MODULE_LOAD_DECLINE;
1629 }
1630
1631 if (stir_shaken_general_load()) {
1632 unload_module();
1633 return AST_MODULE_LOAD_DECLINE;
1634 }
1635
1636 if (stir_shaken_store_load()) {
1637 unload_module();
1638 return AST_MODULE_LOAD_DECLINE;
1639 }
1640
1641 if (stir_shaken_certificate_load()) {
1642 unload_module();
1643 return AST_MODULE_LOAD_DECLINE;
1644 }
1645
1646 ast_sorcery_load(ast_stir_shaken_sorcery());
1647
1648 res |= ast_custom_function_register(&stir_shaken_function);
1649
1650 AST_TEST_REGISTER(test_stir_shaken_sign);
1651 AST_TEST_REGISTER(test_stir_shaken_verify);
1652
1653 return res;
1654 }
1655
1656 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER,
1657 "STIR/SHAKEN Module for Asterisk",
1658 .support_level = AST_MODULE_SUPPORT_CORE,
1659 .load = load_module,
1660 .unload = unload_module,
1661 .reload = reload_module,
1662 .load_pri = AST_MODPRI_CHANNEL_DEPEND - 1,
1663 .requires = "res_curl",
1664 );
0 {
1 global:
2 LINKER_SYMBOL_PREFIXast_stir_*;
3 local:
4 *;
5 };
312312 * this should rarely be changed but should become configurable in the future.
313313 */
314314 ast_bridge_set_video_update_discard(bridge, 5);
315 } else if (video_mode == AST_BRIDGE_VIDEO_MODE_SINGLE_SRC) {
316 ast_bridge_set_single_src_video_mode(bridge, NULL);
315317 } else {
316318 ast_bridge_set_talker_src_video_mode(bridge);
317319 }
2929 "parameters": [
3030 {
3131 "name": "type",
32 "description": "Comma separated list of bridge type attributes (mixing, holding, dtmf_events, proxy_media, video_sfu).",
32 "description": "Comma separated list of bridge type attributes (mixing, holding, dtmf_events, proxy_media, video_sfu, video_single).",
3333 "paramType": "query",
3434 "required": false,
3535 "allowMultiple": false,
6868 "parameters": [
6969 {
7070 "name": "type",
71 "description": "Comma separated list of bridge type attributes (mixing, holding, dtmf_events, proxy_media, video_sfu) to set.",
71 "description": "Comma separated list of bridge type attributes (mixing, holding, dtmf_events, proxy_media, video_sfu, video_single) to set.",
7272 "paramType": "query",
7373 "required": false,
7474 "allowMultiple": false,
745745 },
746746 "video_mode": {
747747 "type": "string",
748 "description": "The video mode the bridge is using. One of 'none', 'talker', or 'single'.",
748 "description": "The video mode the bridge is using. One of 'none', 'talker', 'sfu', or 'single'.",
749749 "required": false
750750 },
751751 "video_source_id": {
122122 static int load_config(void)
123123 {
124124 FILE *f;
125 char buf[1024];
125 char buf[256];
126126 char *val;
127127 char *val2;
128128 int lineno=0;