Update upstream source from tag 'upstream/16.16.1_dfsg'
Update to upstream version '16.16.1~dfsg'
with Debian dir f16697f3b34970a7f1d1834d46dea766749fc1c7
Bernhard Schmidt
3 years ago
10 | 10 | === and the other UPGRADE files for older releases. |
11 | 11 | === |
12 | 12 | ============================================================================== |
13 | ||
14 | ------------------------------------------------------------------------------ | |
15 | --- Functionality changes from Asterisk 16.15.0 to Asterisk 16.16.0 ---------- | |
16 | ------------------------------------------------------------------------------ | |
17 | ||
18 | Core | |
19 | ------------------ | |
20 | * The location where the media cache stores its temporary files | |
21 | is no longer hardcoded to /tmp but can now be configured separately | |
22 | via the astcachedir config variable in asterisk.conf. To retain | |
23 | backwards compatibility, the default location remains /tmp. | |
24 | ||
25 | app_voicemail | |
26 | ------------------ | |
27 | * The VoiceMail application can now be configured to send greetings and | |
28 | instructions via early media and only answering the channel when it is | |
29 | time for the caller to record their message. This behavior can be | |
30 | activated by passing the new 'e' option to VoiceMail. | |
13 | 31 | |
14 | 32 | ------------------------------------------------------------------------------ |
15 | 33 | --- Functionality changes from Asterisk 16.13.0 to Asterisk 16.14.0 ---------- |
0 | 2020-12-22 21:02 +0000 Asterisk Development Team <asteriskteam@digium.com> | |
1 | ||
2 | * asterisk 16.15.1 Released. | |
3 | ||
4 | 2020-12-22 15:02 +0000 [49fbd57889] Asterisk Development Team <asteriskteam@digium.com> | |
5 | ||
6 | * Update for 16.15.1 | |
7 | ||
8 | 2020-12-22 02:58 +0000 [354049e055] Torrey Searle <tsearle@voxbone.com> | |
0 | 2021-02-18 16:48 +0000 Asterisk Development Team <asteriskteam@digium.com> | |
1 | ||
2 | * asterisk 16.16.1 Released. | |
3 | ||
4 | 2021-02-01 15:24 +0000 [a5619097cd] Kevin Harwell <kharwell@sangoma.com> | |
5 | ||
6 | * AST-2021-002: Remote crash possible when negotiating T.38 | |
7 | ||
8 | When an endpoint requests to re-negotiate for fax and the incoming | |
9 | re-invite is received prior to Asterisk sending out the 200 OK for | |
10 | the initial invite the re-invite gets delayed. When Asterisk does | |
11 | finally send the re-inivite the SDP includes streams for both audio | |
12 | and T.38. | |
13 | ||
14 | This happens because when the pending topology and active topologies | |
15 | differ (pending stream is not in the active) in the delayed scenario | |
16 | the pending stream is appended to the active topology. However, in | |
17 | the fax case the pending stream should replace the active. | |
18 | ||
19 | This patch makes it so when a delay occurs during fax negotiation, | |
20 | to or from, the audio stream is replaced by the T.38 stream, or vice | |
21 | versa instead of being appended. | |
22 | ||
23 | Further when Asterisk sent the re-invite with both audio and T.38, | |
24 | and the endpoint responded with a declined T.38 stream then Asterisk | |
25 | would crash when attempting to change the T.38 state. | |
26 | ||
27 | This patch also puts in a check that ensures the media state has a | |
28 | valid fax session (associated udptl object) before changing the | |
29 | T.38 state internally. | |
30 | ||
31 | ASTERISK-29203 #close | |
32 | ||
33 | Change-Id: I407f4fa58651255b6a9030d34fd6578cf65ccf09 | |
34 | ||
35 | 2021-01-26 11:09 +0000 [3f4dfd5c02] Alexander Traud <pabstraud@compuserve.com> | |
36 | ||
37 | * rtp: Enable srtp replay protection | |
38 | ||
39 | Add option "srtpreplayprotection" rtp.conf to enable srtp | |
40 | replay protection. | |
41 | ||
42 | ASTERISK-29260 | |
43 | Reported by: Alexander Traud | |
44 | ||
45 | Change-Id: I5cd346e3c6b6812039d1901aa4b7be688173b458 | |
46 | ||
47 | 2020-12-28 06:43 +0000 [17561b5e64] Ivan Poddubnyi <ivan.poddubny@gmail.com> | |
48 | ||
49 | * res_pjsip_diversion: Fix adding more than one histinfo to Supported | |
50 | ||
51 | New responses sent within a PJSIP sessions are based on those that were | |
52 | sent before. Therefore, adding/modifying a header once causes it to be | |
53 | sent on all responses that follow. | |
54 | ||
55 | Sending 181 Call Is Being Forwarded many times first adds "histinfo" | |
56 | duplicated more and more, and eventually overflows past the array | |
57 | boundary. | |
58 | ||
59 | This commit adds a check preventing adding "histinfo" more than once, | |
60 | and skipping it if there is no more space in the header. | |
61 | ||
62 | Similar overflow situations can also occur in res_pjsip_path and | |
63 | res_pjsip_outbound_registration so those were also modified to | |
64 | check the bounds and suppress duplicate Supported values. | |
65 | ||
66 | ASTERISK-29227 | |
67 | Reported by: Ivan Poddubny | |
68 | ||
69 | Change-Id: Id43704a1f1a0293e35cc7f844026f0b04f2ac322 | |
70 | ||
71 | 2020-12-11 14:49 +0000 [4cea145aa9] Sean Bright <sean.bright@gmail.com> | |
72 | ||
73 | * res_rtp_asterisk.c: Fix signed mismatch that leads to overflow | |
74 | ||
75 | ASTERISK-29205 #close | |
76 | ||
77 | Change-Id: Ib7aa65644e8df76e2378d7613ee7cf751b9d0bea | |
78 | ||
79 | 2021-02-05 05:26 +0000 [321632b02e] Joshua C. Colp <jcolp@sangoma.com> | |
80 | ||
81 | * pjsip: Make modify_local_offer2 tolerate previous failed SDP. | |
82 | ||
83 | If a remote side is broken and sends an SDP that can not be | |
84 | negotiated the call will be torn down but there is a window | |
85 | where a second 183 Session Progress or 200 OK that is forked | |
86 | can be received that also attempts to negotiate SDP. Since | |
87 | the code marked the SDP negotiation as being done and complete | |
88 | prior to this it assumes that there is an active local and remote | |
89 | SDP which it can modify, while in fact there is not as the SDP | |
90 | did not successfully negotiate. Since there is no local or remote | |
91 | SDP a crash occurs. | |
92 | ||
93 | This patch changes the pjmedia_sdp_neg_modify_local_offer2 | |
94 | function to no longer assume that a previous SDP negotiation | |
95 | was successful. | |
96 | ||
97 | ASTERISK-29196 | |
98 | ||
99 | Change-Id: I22de45916d3b05fdc2a67da92b3a38271ee5949e | |
100 | ||
101 | 2021-01-21 16:28 +0000 Asterisk Development Team <asteriskteam@digium.com> | |
102 | ||
103 | * asterisk 16.16.0 Released. | |
104 | ||
105 | 2021-01-14 16:20 +0000 Asterisk Development Team <asteriskteam@digium.com> | |
106 | ||
107 | * asterisk 16.16.0-rc1 Released. | |
108 | ||
109 | 2021-01-14 09:51 +0000 [6056818467] Asterisk Development Team <asteriskteam@digium.com> | |
110 | ||
111 | * Update CHANGES and UPGRADE.txt for 16.16.0 | |
112 | 2020-12-30 07:56 +0000 [45e1d89135] Jean Aunis <jean.aunis@prescom.fr> | |
113 | ||
114 | * Stasis/messaging: tech subscriptions conflict with endpoint subscriptions. | |
115 | ||
116 | When both a tech subscription and an endpoint subscription exist for a given | |
117 | endpoint, TextMessageReceived events are dispatched to the tech subscription | |
118 | only. | |
119 | ||
120 | ASTERISK-29229 | |
121 | ||
122 | Change-Id: I9eac4cba5f9e27285a282509395347abc58fc2b8 | |
123 | ||
124 | 2020-12-23 08:44 +0000 [34b0960310] Alexander Traud <pabstraud@compuserve.com> | |
125 | ||
126 | * chan_sip: SDP: Sidestep stream parsing when its media is disabled. | |
127 | ||
128 | Previously, chan_sip parsed all known media streams in an SDP offer | |
129 | like video (and text) even when videosupport=no (and textsupport=no). | |
130 | This wasted processor power. Furthermore, chan_sip accepted SDP offers, | |
131 | including no audio but just video (or text) streams although | |
132 | videosupport=no (or textsupport=no). Finally, chan_sip denied the whole | |
133 | offer instead of individual streams when they had encryption (SDES-sRTP) | |
134 | unexpectedly enabled. | |
135 | ||
136 | ASTERISK-29238 | |
137 | ASTERISK-29237 | |
138 | ASTERISK-29222 | |
139 | ||
140 | Change-Id: Ie49e4e2a11f0265f914b684738348ba8c0f89755 | |
141 | ||
142 | 2020-12-29 12:16 +0000 [97afc9055f] Ivan Poddubnyi <ivan.poddubny@gmail.com> | |
143 | ||
144 | * chan_pjsip: Assign SIPDOMAIN after creating a channel | |
145 | ||
146 | session->channel doesn't exist until chan_pjsip creates it, so intead of | |
147 | setting a channel variable every new incoming call sets one and the same | |
148 | global variable. | |
149 | ||
150 | This patch moves the code to chan_pjsip so that SIPDOMAIN is set on | |
151 | a newly created channel, it also removes a misleading reference to | |
152 | channel->session used to fetch call pickup configuraion. | |
153 | ||
154 | ASTERISK-29240 | |
155 | ||
156 | Change-Id: I90c9bbbed01f5d8863585631a29322ae4e046755 | |
157 | ||
158 | 2020-12-31 05:53 +0000 [17fa9c93d0] Ivan Poddubnyi <ivan.poddubny@gmail.com> | |
159 | ||
160 | * chan_pjsip: Stop queueing control frames twice on outgoing channels | |
161 | ||
162 | The fix for ASTERISK-27902 made chan_pjsip process SIP responses twice. | |
163 | This resulted in extra noise in logs (for example, "is making progress" | |
164 | and "is ringing" get logged twice by app_dial), as well as in noise in | |
165 | signalling: one incoming 183 Session Progress results in 2 outgoing 183-s. | |
166 | ||
167 | This change splits the response handler into 2 functions: | |
168 | - one for updating HANGUPCAUSE, which is still called twice, | |
169 | - another that does the rest, which is called only once as before. | |
170 | ||
171 | ASTERISK-28016 | |
172 | Reported-by: Alex Hermann | |
173 | ||
174 | ASTERISK-28549 | |
175 | Reported-by: Gant Liu | |
176 | ||
177 | ASTERISK-28185 | |
178 | Reported-by: Julien | |
179 | ||
180 | Change-Id: I0a1874be5bb5ed12d572d17c7f80de6e5e542940 | |
181 | ||
182 | 2020-12-23 11:41 +0000 [7df88c98d0] Jaco Kroon <jaco@uls.co.za> | |
183 | ||
184 | * contrib/systemd: Added note on common issues with systemd and asterisk | |
185 | ||
186 | With newer version of linux /var/run/ is a symlink to /run/ that has | |
187 | been turned into tmpfs. | |
188 | ||
189 | Added note that if asterisk has to bind to a specific IP that | |
190 | systemd has to wait until the network is up. | |
191 | ||
192 | Added note on how to make sure that the environment variable | |
193 | HOSTNAME is included. | |
194 | ||
195 | ASTERISK-29216 | |
196 | Reported by: Mark Petersen | |
197 | Tested by: Mark Petersen | |
198 | ||
199 | Change-Id: Ib3e560655befd3e99eec743687144f5569533379 | |
200 | ||
201 | 2021-01-07 08:39 +0000 [7ed20b9d3b] George Joseph <gjoseph@digium.com> | |
202 | ||
203 | * Revert "res_pjsip_outbound_registration.c: Use our own scheduler and other stuff" | |
204 | ||
205 | This reverts commit e1fd51cd2c183a3eb61803f52277d1a7d7a18c9c. | |
206 | ||
207 | Reason for revert: Too many issues reported. Need to research and correct. | |
208 | ||
209 | ASTERISK-29230 | |
210 | ASTERISK-29231 | |
211 | Reported by: Michael Maier | |
212 | ||
213 | Change-Id: Ie2356c1cd74436603600599885286b98055b8a17 | |
214 | ||
215 | 2020-12-23 11:41 +0000 [aca435dfe7] Jaco Kroon <jaco@uls.co.za> | |
216 | ||
217 | * pbx_lua: Add LUA_VERSIONS environment variable to ./configure. | |
218 | ||
219 | On Gentoo it's possible to have multiple lua versions installed, all | |
220 | with a path of /usr, so it's not possible to use the current --with-lua | |
221 | option to determisticly pin to a specific version as is required by the | |
222 | Gentoo PMS standards. | |
223 | ||
224 | This environment variable allows to lock to specific versions, | |
225 | unversioned check will be skipped if this variable is supplied. | |
226 | ||
227 | Change-Id: I8c403eda05df25ee0193960262ce849c7d2fd088 | |
228 | Signed-off-by: Jaco Kroon <jaco@uls.co.za> | |
229 | ||
230 | 2020-12-18 13:06 +0000 [32e36144c7] Jaco Kroon <jaco@uls.co.za> | |
231 | ||
232 | * func_lock: fix multiple-channel-grant problems. | |
233 | ||
234 | Under contention it becomes possible that multiple channels will be told | |
235 | they successfully obtained the lock, which is a bug. Please refer | |
236 | ||
237 | ASTERISK-29217 | |
238 | ||
239 | This introduces a couple of changes. | |
240 | ||
241 | 1. Replaces requesters ao2 container with simple counter (we don't | |
242 | really care who is waiting for the lock, only how many). This is | |
243 | updated undex ->mutex to prevent memory access races. | |
244 | 2. Correct semantics for ast_cond_timedwait() as described in | |
245 | pthread_cond_broadcast(3P) is used (multiple threads can be released | |
246 | on a single _signal()). | |
247 | 3. Module unload races are taken care of and memory properly cleaned | |
248 | up. | |
249 | ||
250 | Change-Id: I6f68b5ec82ff25b2909daf6e4d19ca864a463e29 | |
251 | Signed-off-by: Jaco Kroon <jaco@uls.co.za> | |
252 | ||
253 | 2020-12-07 16:59 +0000 [e127a57761] Dan Cropp <dan@amtelco.com> | |
254 | ||
255 | * chan_pjsip: Incorporate channel reference count into transfer_refer(). | |
256 | ||
257 | Add channel reference count for PJSIP REFER. The call could be terminated | |
258 | prior to the result of the transfer. In that scenario, when the SUBSCRIBE/NOTIFY | |
259 | occurred several minutes later, it would attempt to access a session which was | |
260 | no longer valid. Terminate event subscription if pjsip_xfer_initiate() or | |
261 | pjsip_xfer_send_request() fails in transfer_refer(). | |
262 | ||
263 | ASTERISK-29201 #close | |
264 | Reported-by: Dan Cropp | |
265 | ||
266 | Change-Id: I3fd92fd14b4e3844d3d7b0f60fe417a4df5f2435 | |
267 | ||
268 | 2020-12-23 13:06 +0000 [e96f744816] Kevin Harwell <kharwell@sangoma.com> | |
269 | ||
270 | * app_mixmonitor: cleanup datastore when monitor thread fails to launch | |
271 | ||
272 | launch_monitor_thread is responsible for creating and initializing | |
273 | the mixmonitor, and dependent data structures. There was one off | |
274 | nominal path after the datastore gets created that triggers when | |
275 | the channel being monitored is hung up prior to monitor starting | |
276 | itself. | |
277 | ||
278 | If this happened the monitor thread would not "launch", and the | |
279 | mixmonitor object and associated objects are freed, including the | |
280 | underlying datastore data object. However, the datastore itself was | |
281 | not removed from the channel, so when the channel eventually gets | |
282 | destroyed it tries to access the previously freed datastore data | |
283 | and crashes. | |
284 | ||
285 | This patch removes and frees datastore object itself from the channel | |
286 | before freeing the mixmonitor object thus ensuring the channel does | |
287 | not call it when destroyed. | |
288 | ||
289 | ASTERISK-28947 #close | |
290 | ||
291 | Change-Id: Id4f9e958956d62473ed5ff06c98ae3436e839ff8 | |
292 | ||
293 | 2020-12-24 09:03 +0000 [2b7af3eb27] Sean Bright <sean.bright@gmail.com> | |
294 | ||
295 | * app_voicemail: Prevent deadlocks when out of ODBC database connections | |
296 | ||
297 | ASTERISK-28992 #close | |
298 | ||
299 | Change-Id: Ia7d608924036139ee2520b840d077762d02668d0 | |
300 | ||
301 | 2020-12-18 09:16 +0000 [4c5bffb217] Sean Bright <sean.bright@gmail.com> | |
302 | ||
303 | * asterisk: Export additional manager functions | |
304 | ||
305 | Rename check_manager_enabled() and check_webmanager_enabled() to begin | |
306 | with ast_ so that the symbols are automatically exported by the | |
307 | linker. | |
308 | ||
309 | ASTERISK~29184 | |
310 | ||
311 | Change-Id: I85762b9a5d14500c15f6bad6507138c8858644c9 | |
312 | ||
313 | 2020-12-26 11:42 +0000 [89cf7899be] Richard Mudgett <rmudgett@digium.com> | |
314 | ||
315 | * res_pjsip_session.c: Fix compiler warnings. | |
316 | ||
317 | AST_VECTOR_SIZE() returns a size_t. This is not always equivalent to an | |
318 | unsigned long on all machines. | |
319 | ||
320 | Change-Id: I0a4189a104e6e3a2e2273de06620eaef19df9338 | |
321 | ||
322 | 2020-12-13 06:03 +0000 [ab3f57d88f] Sungtae Kim <pchero21@gmail.com> | |
323 | ||
324 | * res_pjsip_session: Fixed NULL active media topology handle | |
325 | ||
326 | Added NULL pointer check to prevent Asterisk crash. | |
327 | ||
328 | ASTERISK-29215 | |
329 | ||
330 | Change-Id: If07e50ea8d78cb610af9195fc13b5dca4bfcef95 | |
331 | ||
332 | 2020-12-22 02:58 +0000 [9196e0d1d5] Torrey Searle <tsearle@voxbone.com> | |
9 | 333 | |
10 | 334 | * res/res_pjsip_diversion: prevent crash on tel: uri in History-Info |
11 | 335 | |
17 | 341 | |
18 | 342 | Change-Id: I0320aa205f22cda511d60a2edf2b037e8fd6cc37 |
19 | 343 | |
20 | 2020-11-19 12:34 +0000 Asterisk Development Team <asteriskteam@digium.com> | |
21 | ||
22 | * asterisk 16.15.0 Released. | |
344 | 2020-12-11 13:27 +0000 [0a23296834] Sean Bright <sean.bright@gmail.com> | |
345 | ||
346 | * app_chanspy: Spyee information missing in ChanSpyStop AMI Event | |
347 | ||
348 | The documentation in the wiki says there should be spyee-channel | |
349 | information elements in the ChanSpyStop AMI event. | |
350 | ||
351 | https://wiki.asterisk.org/wiki/x/Xc5uAg | |
352 | ||
353 | However, this is not the case in Asterisk <= 16.10.0 Version. We're | |
354 | using these Spyee* arguments since Asterisk 11.x, so these arguments | |
355 | vanished in Asterisk 12 or higher. | |
356 | ||
357 | For maximum compatibility, we still send the ChanSpyStop event even if | |
358 | we are not able to find any 'Spyee' information. | |
359 | ||
360 | ASTERISK-28883 #close | |
361 | ||
362 | Change-Id: I81ce397a3fd614c094d043ffe5b1b1d76188835f | |
363 | ||
364 | 2020-11-30 19:27 +0000 [a47e6965b3] Sungtae Kim <pchero21@gmail.com> | |
365 | ||
366 | * res_ari: Fix wrong media uri handle for channel play | |
367 | ||
368 | Fixed wrong null object handle in | |
369 | /channels/<channel_id>/play request handler. | |
370 | ||
371 | ASTERISK-29188 | |
372 | ||
373 | Change-Id: I6691c640247a51ad15f23e4a203ca8430809bafe | |
374 | ||
375 | 2020-12-10 09:09 +0000 [5a2867efa9] George Joseph <gjoseph@digium.com> | |
376 | ||
377 | * logger.c: Automatically add a newline to formats that don't have one | |
378 | ||
379 | Scope tracing allows you to not specify a format string or | |
380 | variable, in which case it just prints the indent, file, | |
381 | function, and line number. The trace output automatically | |
382 | adds a newline to the end in this case. If you also have | |
383 | debugging turned on for the module, a debug message is | |
384 | also printed but the standard log functionality which | |
385 | prints it doesn't add the newline so you have messages | |
386 | that don't break correctly. | |
387 | ||
388 | * format_log_message_ap(), which is the common log | |
389 | message formatter for all channels, now adds a | |
390 | newline to the end of format strings that don't | |
391 | already have a newline. | |
392 | ||
393 | ASTERISK-29209 | |
394 | Reported by: Alexander Traud | |
395 | ||
396 | Change-Id: I994a7df27f88df343b7d19f3e81a4b562d9d41da | |
397 | ||
398 | 2020-12-08 11:37 +0000 [11def974a8] Pirmin Walthert <infos@nappsoft.ch> | |
399 | ||
400 | * res_pjsip_nat.c: Create deep copies of strings when appropriate | |
401 | ||
402 | In rewrite_uri asterisk was not making deep copies of strings when | |
403 | changing the uri. This was in some cases causing garbage in the route | |
404 | header and in other cases even crashing asterisk when receiving a | |
405 | message with a record-route header set. Thanks to Ralf Kubis for | |
406 | pointing out why this happens. A similar problem was found in | |
407 | res_pjsip_transport_websocket.c. Pjproject needs as well to be patched | |
408 | to avoid garbage in CANCEL messages. | |
409 | ||
410 | ASTERISK-29024 #close | |
411 | ||
412 | Change-Id: Ic5acd7fa2fbda3080f5f36ef12e46804939b198b | |
413 | ||
414 | 2020-12-16 06:17 +0000 [7e4bb4ed11] Joshua C. Colp <jcolp@sangoma.com> | |
415 | ||
416 | * res_pjsip_pidf_digium_body_supplement: Support Sangoma user agent. | |
417 | ||
418 | This adds support for both Digium and Sangoma user agent strings | |
419 | for the Sangoma specific body supplement. | |
420 | ||
421 | Change-Id: Ib99362b24b91d3cbe888d8b2fce3fad5515d9482 | |
422 | ||
423 | 2020-12-10 17:06 +0000 [bb46595799] Nathan Bruning <nathan@iperity.com> | |
424 | ||
425 | * res_musiconhold: Don't crash when real-time doesn't return any entries | |
426 | ||
427 | ASTERISK-29211 #close | |
428 | ||
429 | Change-Id: Ifbf0a4f786ab2a52342f9d1a1db4c9907f069877 | |
430 | ||
431 | 2020-10-29 06:25 +0000 [8d2558209b] laszlovl <digium@lvlconsultancy.nl> | |
432 | ||
433 | * Introduce astcachedir, to be used for temporary bucket files | |
434 | ||
435 | As described in the issue, /tmp is not a suitable location for a | |
436 | large amount of cached media files, since most distributions make | |
437 | /tmp a RAM-based tmpfs mount with limited capacity. | |
438 | ||
439 | I opted for a location that can be configured separately, as opposed | |
440 | to using a subdirectory of spooldir, given the different storage | |
441 | profile (transient files vs files that might stay there indefinitely). | |
442 | ||
443 | This commit just makes the cache directory configurable, but leaves | |
444 | it at /tmp by default, to ensure backwards compatibility. | |
445 | ||
446 | A future commit that only targets master could change the default | |
447 | location to something more sensible such as /var/tmp/asterisk. At | |
448 | that point, the cachedir could be created and cleaned up during | |
449 | uninstall by the Makefile script. | |
450 | ||
451 | ASTERISK-29143 | |
452 | ||
453 | Change-Id: Ic54e95199405abacd9e509cef5f08fa14c510b5d | |
454 | ||
455 | 2020-10-29 12:21 +0000 [ea744ca7c2] Joshua C. Colp <jcolp@sangoma.com> | |
456 | ||
457 | * pjsip: Match lifetime of INVITE session to our session. | |
458 | ||
459 | In some circumstances it was possible for an INVITE | |
460 | session to be destroyed while we were still using it. | |
461 | This occurred due to the reference on the INVITE session | |
462 | being released internally as a result of its state | |
463 | changing to DISCONNECTED. | |
464 | ||
465 | This change adds a reference to the INVITE session | |
466 | which is released when our own session is destroyed, | |
467 | ensuring that the INVITE session remains valid for | |
468 | the lifetime of our session. | |
469 | ||
470 | ASTERISK-29022 | |
471 | ||
472 | Change-Id: I300c6d9005ff0e6efbe1132daefc7e47ca6228c9 | |
473 | ||
474 | 2020-11-21 11:51 +0000 [0c185c9e21] Sean Bright <sean.bright@gmail.com> | |
475 | ||
476 | * res_http_media_cache.c: Set reasonable number of redirects | |
477 | ||
478 | By default libcurl does not follow redirects, so we explicitly enable | |
479 | it by setting CURLOPT_FOLLOWLOCATION. Once that is enabled, libcurl | |
480 | will follow up to CURLOPT_MAXREDIRS redirects, which by default is | |
481 | configured to be unlimited. | |
482 | ||
483 | This patch sets CURLOPT_MAXREDIRS to a more reasonable default (8). If | |
484 | we determine at some point that this needs to be increased on | |
485 | configurable it is a trivial change. | |
486 | ||
487 | ASTERISK-29173 #close | |
488 | ||
489 | Change-Id: I4925ebbcf0c7d728bb9252b3795b3479ae225b30 | |
490 | ||
491 | 2020-11-23 14:56 +0000 [ddbf3a7f73] Sean Bright <sean.bright@gmail.com> | |
492 | ||
493 | * media_cache: Fix reference leak with bucket file metadata | |
494 | ||
495 | Change-Id: Ia0e4124110df613ce5fdfa9ef8780016ebaa52c6 | |
496 | ||
497 | 2020-11-24 00:55 +0000 [159522003a] Stanislav <stas.abramenkov@gmail.com> | |
498 | ||
499 | * res_pjsip_stir_shaken: Fix module description | |
500 | ||
501 | the 'J' is missing in module description. | |
502 | "PSIP STIR/SHAKEN Module for Asterisk" -> "PJSIP STIR/SHAKEN Module for Asterisk" | |
503 | ||
504 | ASTERISK-29175 #close | |
505 | ||
506 | Change-Id: I17da008540ee2e8496b644d05f995b320b54ad7a | |
507 | ||
508 | 2020-10-12 05:30 +0000 [15566494f9] Joshua C. Colp <jcolp@sangoma.com> | |
509 | ||
510 | * voicemail: add option 'e' to play greetings as early media | |
511 | ||
512 | When using this option, answering the channel is deferred until | |
513 | all prompts/greetings have been played and the caller is about | |
514 | to leave their message. | |
515 | ||
516 | ASTERISK-29118 #close | |
517 | ||
518 | Change-Id: I41b9f0428783c0bd697c8c994f906d1e75ce9ddb | |
519 | ||
520 | 2020-11-02 02:02 +0000 [4c79bc19d1] Alexander Traud <pabstraud@compuserve.com> | |
521 | ||
522 | * loader: Sync load- and build-time deps. | |
523 | ||
524 | In MODULEINFO, each depend has to be listed in .requires of AST_MODULE_INFO. | |
525 | ||
526 | ASTERISK-29148 | |
527 | ||
528 | Change-Id: I254dd33194ae38d2877b8021c57c2a5deb6bbcd2 | |
529 | ||
530 | 2020-11-18 13:11 +0000 [a360150ee0] Sean Bright <sean.bright@gmail.com> | |
531 | ||
532 | * CHANGES: Remove already applied CHANGES update | |
533 | ||
534 | Change-Id: Iee7163bc732d58c5cbaa2cfab1f5aab4a412060a | |
535 | ||
536 | 2020-11-04 07:39 +0000 [f667c5a781] Alexander Traud <pabstraud@compuserve.com> | |
537 | ||
538 | * chan_sip: Remove unused sip_socket->port. | |
539 | ||
540 | 12 years ago, with ASTERISK_12115 the last four get/uses of socket.port | |
541 | vanished. However, the struct member itself and all seven set/uses | |
542 | remained as dead code. | |
543 | ||
544 | ASTERISK-28798 | |
545 | ||
546 | Change-Id: Ib90516a49eca3d724a70191278aaf2144fb58c59 | |
547 | ||
548 | 2020-11-17 14:19 +0000 [a8f6238cc8] Alexander Greiner-Baer <alex+asterisk@greiner-baer.de> | |
549 | ||
550 | * res_pjsip: set Accept-Encoding to identity in OPTIONS response | |
551 | ||
552 | RFC 3261 says that the Accept-Encoding header should be present | |
553 | in an options response. Permitted values according to RFC 2616 | |
554 | are only compression algorithms like gzip or the default identity | |
555 | encoding. Therefore "text/plain" is not a correct value here. | |
556 | As long as the header is hard coded, it should be set to "identity". | |
557 | ||
558 | Without this fix an Alcatel OmniPCX periodically logs warnings like | |
559 | "[sip_acceptIncorrectHeader] Header Accept-Encoding is malformed" | |
560 | on a SIP Trunk. | |
561 | ||
562 | ASTERISK-29165 #close | |
563 | ||
564 | Change-Id: I0aa2211ebf0b4c2ed554ac7cda794523803a3840 | |
565 | ||
566 | 2020-11-13 06:19 +0000 [89d3de37ca] Boris P. Korzun <drtr0jan@yandex.ru> | |
567 | ||
568 | * bridge_basic: Fixed setup of recall channels | |
569 | ||
570 | Fixed a bug (like a typo) in retransfer_enter() | |
571 | at main/bridge_basic.c:2641. common_recall_channel_setup() setups | |
572 | common things on the recalled transfer target, but used same target | |
573 | as source instead trasfered. | |
574 | ||
575 | ASTERISK-29161 #close | |
576 | ||
577 | Change-Id: Ieb549654a621c38b1ad5e9d15b9f18823d9cc31f | |
578 | ||
579 | 2020-11-16 04:38 +0000 [d1a78e047d] Alexander Traud <pabstraud@compuserve.com> | |
580 | ||
581 | * modules.conf: Align the comments for more conclusiveness. | |
582 | ||
583 | Change-Id: I79cc693cd5a6e5dd7d403b7e91d970ff1ddf8306 | |
584 | ||
585 | 2020-11-11 08:55 +0000 [8d8c9db618] George Joseph <gjoseph@digium.com> | |
586 | ||
587 | * app_queue: Fix deadlock between update and show queues | |
588 | ||
589 | Operations that update queues when shared_lastcall is set lock the | |
590 | queue in question, then have to lock the queues container to find the | |
591 | other queues with the same member. On the other hand, __queues_show | |
592 | (which is called by both the CLI and AMI) does the reverse. It locks | |
593 | the queues container, then iterates over the queues locking each in | |
594 | turn to display them. This creates a deadlock. | |
595 | ||
596 | * Moved queue print logic from __queues_show to a separate function | |
597 | that can be called for a single queue. | |
598 | ||
599 | * Updated __queues_show so it doesn't need to lock or traverse | |
600 | the queues container to show a single queue. | |
601 | ||
602 | * Updated __queues_show to snap a copy of the queues container and iterate | |
603 | over that instead of locking the queues container and iterating over | |
604 | it while locked. This prevents us from having to hold both the | |
605 | container lock and the queue locks at the same time. This also | |
606 | allows us to sort the queue entries. | |
607 | ||
608 | ASTERISK-29155 | |
609 | ||
610 | Change-Id: I78d4dc36728c2d7bc187b97d82673fc77f2bcf41 | |
23 | 611 | |
24 | 612 | 2020-11-12 12:03 +0000 Asterisk Development Team <asteriskteam@digium.com> |
25 | 613 |
48 | 48 | export DESTDIR |
49 | 49 | |
50 | 50 | export INSTALL_PATH # Additional prefix for the following paths |
51 | export ASTCACHEDIR | |
51 | 52 | export ASTETCDIR # Path for config files |
52 | 53 | export ASTVARRUNDIR |
53 | 54 | export ASTSPOOLDIR |
554 | 555 | |
555 | 556 | NEWHEADERS=$(notdir $(wildcard include/asterisk/*.h)) |
556 | 557 | OLDHEADERS=$(filter-out $(NEWHEADERS) $(notdir $(DESTDIR)$(ASTHEADERDIR)),$(notdir $(wildcard $(DESTDIR)$(ASTHEADERDIR)/*.h))) |
557 | INSTALLDIRS="$(ASTLIBDIR)" "$(ASTMODDIR)" "$(ASTSBINDIR)" "$(ASTETCDIR)" "$(ASTVARRUNDIR)" \ | |
558 | INSTALLDIRS="$(ASTLIBDIR)" "$(ASTMODDIR)" "$(ASTSBINDIR)" "$(ASTCACHEDIR)" "$(ASTETCDIR)" "$(ASTVARRUNDIR)" \ | |
558 | 559 | "$(ASTSPOOLDIR)" "$(ASTSPOOLDIR)/dictate" "$(ASTSPOOLDIR)/meetme" \ |
559 | 560 | "$(ASTSPOOLDIR)/monitor" "$(ASTSPOOLDIR)/system" "$(ASTSPOOLDIR)/tmp" \ |
560 | 561 | "$(ASTSPOOLDIR)/voicemail" "$(ASTSPOOLDIR)/recording" \ |
778 | 779 | done ; \ |
779 | 780 | if [ "$(OVERWRITE)" = "y" ]; then \ |
780 | 781 | echo "Updating asterisk.conf" ; \ |
781 | sed -e 's|^astetcdir.*$$|astetcdir => $(ASTETCDIR)|' \ | |
782 | sed -e 's|^astcachedir.*$$|astcachedir => $(ASTCACHEDIR)|' \ | |
783 | -e 's|^astetcdir.*$$|astetcdir => $(ASTETCDIR)|' \ | |
782 | 784 | -e 's|^astmoddir.*$$|astmoddir => $(ASTMODDIR)|' \ |
783 | 785 | -e 's|^astvarlibdir.*$$|astvarlibdir => $(ASTVARLIBDIR)|' \ |
784 | 786 | -e 's|^astdbdir.*$$|astdbdir => $(ASTDBDIR)|' \ |
844 | 844 | ast_audiohook_unlock(&csth.spy_audiohook); |
845 | 845 | ast_audiohook_destroy(&csth.spy_audiohook); |
846 | 846 | |
847 | ast_verb(2, "Done Spying on channel %s\n", name); | |
848 | publish_chanspy_message(chan, spyee_autochan->chan, 0); | |
849 | ||
847 | 850 | if (spyee_bridge_autochan) { |
848 | 851 | ast_autochan_destroy(spyee_bridge_autochan); |
849 | 852 | } |
850 | ||
851 | ast_verb(2, "Done Spying on channel %s\n", name); | |
852 | publish_chanspy_message(chan, NULL, 0); | |
853 | 853 | |
854 | 854 | return running; |
855 | 855 | } |
861 | 861 | return 0; |
862 | 862 | } |
863 | 863 | |
864 | static void mixmonitor_ds_remove_and_free(struct ast_channel *chan, const char *datastore_id) | |
865 | { | |
866 | struct ast_datastore *datastore; | |
867 | ||
868 | ast_channel_lock(chan); | |
869 | ||
870 | datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, datastore_id); | |
871 | ||
872 | /* | |
873 | * Currently the one place this function is called from guarantees a | |
874 | * datastore is present, thus return checks can be avoided here. | |
875 | */ | |
876 | ast_channel_datastore_remove(chan, datastore); | |
877 | ast_datastore_free(datastore); | |
878 | ||
879 | ast_channel_unlock(chan); | |
880 | } | |
881 | ||
864 | 882 | static int launch_monitor_thread(struct ast_channel *chan, const char *filename, |
865 | 883 | unsigned int flags, int readvol, int writevol, |
866 | 884 | const char *post_process, const char *filename_write, |
936 | 954 | pbx_builtin_setvar_helper(chan, uid_channel_var, datastore_id); |
937 | 955 | } |
938 | 956 | } |
939 | ast_free(datastore_id); | |
940 | 957 | |
941 | 958 | mixmonitor->name = ast_strdup(ast_channel_name(chan)); |
942 | 959 | |
986 | 1003 | if (startmon(chan, &mixmonitor->audiohook)) { |
987 | 1004 | ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n", |
988 | 1005 | mixmonitor_spy_type, ast_channel_name(chan)); |
1006 | mixmonitor_ds_remove_and_free(chan, datastore_id); | |
1007 | ast_free(datastore_id); | |
989 | 1008 | ast_autochan_destroy(mixmonitor->autochan); |
990 | 1009 | ast_audiohook_destroy(&mixmonitor->audiohook); |
991 | 1010 | mixmonitor_free(mixmonitor); |
992 | 1011 | return -1; |
993 | 1012 | } |
1013 | ||
1014 | ast_free(datastore_id); | |
994 | 1015 | |
995 | 1016 | /* reference be released at mixmonitor destruction */ |
996 | 1017 | mixmonitor->callid = ast_read_threadstorage_callid(); |
9641 | 9641 | } |
9642 | 9642 | } |
9643 | 9643 | |
9644 | /*! \brief Print a single queue to AMI or the CLI */ | |
9645 | static void print_queue(struct mansession *s, int fd, struct call_queue *q) | |
9646 | { | |
9647 | float sl; | |
9648 | float sl2; | |
9649 | struct ao2_iterator mem_iter; | |
9650 | struct ast_str *out = ast_str_alloca(512); | |
9651 | time_t now = time(NULL); | |
9652 | ||
9653 | ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count); | |
9654 | if (q->maxlen) { | |
9655 | ast_str_append(&out, 0, "%d", q->maxlen); | |
9656 | } else { | |
9657 | ast_str_append(&out, 0, "unlimited"); | |
9658 | } | |
9659 | sl = 0; | |
9660 | sl2 = 0; | |
9661 | if (q->callscompleted > 0) { | |
9662 | sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); | |
9663 | } | |
9664 | if (q->callscompleted + q->callsabandoned > 0) { | |
9665 | sl2 =100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted)); | |
9666 | } | |
9667 | ||
9668 | ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%%, SL2:%2.1f%% within %ds", | |
9669 | int2strat(q->strategy), q->holdtime, q->talktime, q->weight, q->callscompleted, q->callsabandoned, sl, sl2, q->servicelevel); | |
9670 | do_print(s, fd, ast_str_buffer(out)); | |
9671 | if (!ao2_container_count(q->members)) { | |
9672 | do_print(s, fd, " No Members"); | |
9673 | } else { | |
9674 | struct member *mem; | |
9675 | ||
9676 | do_print(s, fd, " Members: "); | |
9677 | mem_iter = ao2_iterator_init(q->members, 0); | |
9678 | while ((mem = ao2_iterator_next(&mem_iter))) { | |
9679 | ast_str_set(&out, 0, " %s", mem->membername); | |
9680 | if (strcasecmp(mem->membername, mem->interface)) { | |
9681 | ast_str_append(&out, 0, " (%s", mem->interface); | |
9682 | if (!ast_strlen_zero(mem->state_interface) | |
9683 | && strcmp(mem->state_interface, mem->interface)) { | |
9684 | ast_str_append(&out, 0, " from %s", mem->state_interface); | |
9685 | } | |
9686 | ast_str_append(&out, 0, ")"); | |
9687 | } | |
9688 | if (mem->penalty) { | |
9689 | ast_str_append(&out, 0, " with penalty %d", mem->penalty); | |
9690 | } | |
9691 | ||
9692 | ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled"); | |
9693 | ||
9694 | ast_str_append(&out, 0, "%s%s%s%s%s%s%s%s%s", | |
9695 | mem->dynamic ? ast_term_color(COLOR_CYAN, COLOR_BLACK) : "", mem->dynamic ? " (dynamic)" : "", ast_term_reset(), | |
9696 | mem->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset(), | |
9697 | mem->starttime ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->starttime ? " (in call)" : "", ast_term_reset()); | |
9698 | ||
9699 | if (mem->paused) { | |
9700 | ast_str_append(&out, 0, " %s(paused%s%s was %ld secs ago)%s", | |
9701 | ast_term_color(COLOR_BROWN, COLOR_BLACK), | |
9702 | ast_strlen_zero(mem->reason_paused) ? "" : ":", | |
9703 | ast_strlen_zero(mem->reason_paused) ? "" : mem->reason_paused, | |
9704 | (long) (now - mem->lastpause), | |
9705 | ast_term_reset()); | |
9706 | } | |
9707 | ||
9708 | ast_str_append(&out, 0, " (%s%s%s)", | |
9709 | ast_term_color( | |
9710 | mem->status == AST_DEVICE_UNAVAILABLE || mem->status == AST_DEVICE_UNKNOWN ? | |
9711 | COLOR_RED : COLOR_GREEN, COLOR_BLACK), | |
9712 | ast_devstate2str(mem->status), ast_term_reset()); | |
9713 | if (mem->calls) { | |
9714 | ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)", | |
9715 | mem->calls, (long) (now - mem->lastcall)); | |
9716 | } else { | |
9717 | ast_str_append(&out, 0, " has taken no calls yet"); | |
9718 | } | |
9719 | do_print(s, fd, ast_str_buffer(out)); | |
9720 | ao2_ref(mem, -1); | |
9721 | } | |
9722 | ao2_iterator_destroy(&mem_iter); | |
9723 | } | |
9724 | if (!q->head) { | |
9725 | do_print(s, fd, " No Callers"); | |
9726 | } else { | |
9727 | struct queue_ent *qe; | |
9728 | int pos = 1; | |
9729 | ||
9730 | do_print(s, fd, " Callers: "); | |
9731 | for (qe = q->head; qe; qe = qe->next) { | |
9732 | ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)", | |
9733 | pos++, ast_channel_name(qe->chan), (long) (now - qe->start) / 60, | |
9734 | (long) (now - qe->start) % 60, qe->prio); | |
9735 | do_print(s, fd, ast_str_buffer(out)); | |
9736 | } | |
9737 | } | |
9738 | do_print(s, fd, ""); /* blank line between entries */ | |
9739 | } | |
9740 | ||
9741 | AO2_STRING_FIELD_SORT_FN(call_queue, name); | |
9742 | ||
9644 | 9743 | /*! |
9645 | 9744 | * \brief Show queue(s) status and statistics |
9646 | 9745 | * |
9651 | 9750 | { |
9652 | 9751 | struct call_queue *q; |
9653 | 9752 | struct ast_str *out = ast_str_alloca(512); |
9753 | struct ao2_container *sorted_queues; | |
9754 | ||
9755 | struct ao2_iterator queue_iter; | |
9654 | 9756 | int found = 0; |
9655 | time_t now = time(NULL); | |
9656 | struct ao2_iterator queue_iter; | |
9657 | struct ao2_iterator mem_iter; | |
9658 | 9757 | |
9659 | 9758 | if (argc != 2 && argc != 3) { |
9660 | 9759 | return CLI_SHOWUSAGE; |
9662 | 9761 | |
9663 | 9762 | if (argc == 3) { /* specific queue */ |
9664 | 9763 | if ((q = find_load_queue_rt_friendly(argv[2]))) { |
9665 | queue_t_unref(q, "Done with temporary pointer"); | |
9666 | } | |
9667 | } else if (ast_check_realtime("queues")) { | |
9764 | ao2_lock(q); | |
9765 | print_queue(s, fd, q); | |
9766 | ao2_unlock(q); | |
9767 | queue_unref(q); | |
9768 | } else { | |
9769 | ast_str_set(&out, 0, "No such queue: %s.", argv[2]); | |
9770 | do_print(s, fd, ast_str_buffer(out)); | |
9771 | } | |
9772 | return CLI_SUCCESS; | |
9773 | } | |
9774 | ||
9775 | if (ast_check_realtime("queues")) { | |
9668 | 9776 | /* This block is to find any queues which are defined in realtime but |
9669 | 9777 | * which have not yet been added to the in-core container |
9670 | 9778 | */ |
9681 | 9789 | } |
9682 | 9790 | } |
9683 | 9791 | |
9684 | ao2_lock(queues); | |
9685 | queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK); | |
9792 | /* | |
9793 | * Snapping a copy of the container prevents having to lock both the queues container | |
9794 | * and the queue itself at the same time. It also allows us to sort the entries. | |
9795 | */ | |
9796 | sorted_queues = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, call_queue_sort_fn, NULL); | |
9797 | if (!sorted_queues) { | |
9798 | return CLI_SUCCESS; | |
9799 | } | |
9800 | if (ao2_container_dup(sorted_queues, queues, 0)) { | |
9801 | ao2_ref(sorted_queues, -1); | |
9802 | return CLI_SUCCESS; | |
9803 | } | |
9804 | ||
9805 | /* | |
9806 | * No need to lock the container since it's temporary and static. | |
9807 | * We also unlink the entries as we use them so the container is | |
9808 | * empty when the iterator finishes. We can then just unref the container. | |
9809 | */ | |
9810 | queue_iter = ao2_iterator_init(sorted_queues, AO2_ITERATOR_DONTLOCK | AO2_ITERATOR_UNLINK); | |
9686 | 9811 | while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) { |
9687 | float sl; | |
9688 | float sl2; | |
9689 | ||
9690 | 9812 | struct call_queue *realtime_queue = NULL; |
9691 | ||
9692 | 9813 | ao2_lock(q); |
9693 | 9814 | /* This check is to make sure we don't print information for realtime |
9694 | 9815 | * queues which have been deleted from realtime but which have not yet |
9695 | 9816 | * been deleted from the in-core container. Only do this if we're not |
9696 | 9817 | * looking for a specific queue. |
9697 | 9818 | */ |
9698 | if (argc < 3 && q->realtime) { | |
9819 | if (q->realtime) { | |
9699 | 9820 | realtime_queue = find_load_queue_rt_friendly(q->name); |
9700 | 9821 | if (!realtime_queue) { |
9701 | 9822 | ao2_unlock(q); |
9705 | 9826 | queue_t_unref(realtime_queue, "Queue is already in memory"); |
9706 | 9827 | } |
9707 | 9828 | |
9708 | if (argc == 3 && strcasecmp(q->name, argv[2])) { | |
9709 | ao2_unlock(q); | |
9710 | queue_t_unref(q, "Done with iterator"); | |
9711 | continue; | |
9712 | } | |
9713 | 9829 | found = 1; |
9714 | ||
9715 | ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count); | |
9716 | if (q->maxlen) { | |
9717 | ast_str_append(&out, 0, "%d", q->maxlen); | |
9718 | } else { | |
9719 | ast_str_append(&out, 0, "unlimited"); | |
9720 | } | |
9721 | sl = 0; | |
9722 | sl2 = 0; | |
9723 | if (q->callscompleted > 0) { | |
9724 | sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted); | |
9725 | } | |
9726 | if (q->callscompleted + q->callsabandoned > 0) { | |
9727 | sl2 =100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted)); | |
9728 | } | |
9729 | ||
9730 | ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%%, SL2:%2.1f%% within %ds", | |
9731 | int2strat(q->strategy), q->holdtime, q->talktime, q->weight, q->callscompleted, q->callsabandoned, sl, sl2, q->servicelevel); | |
9732 | do_print(s, fd, ast_str_buffer(out)); | |
9733 | if (!ao2_container_count(q->members)) { | |
9734 | do_print(s, fd, " No Members"); | |
9735 | } else { | |
9736 | struct member *mem; | |
9737 | ||
9738 | do_print(s, fd, " Members: "); | |
9739 | mem_iter = ao2_iterator_init(q->members, 0); | |
9740 | while ((mem = ao2_iterator_next(&mem_iter))) { | |
9741 | ast_str_set(&out, 0, " %s", mem->membername); | |
9742 | if (strcasecmp(mem->membername, mem->interface)) { | |
9743 | ast_str_append(&out, 0, " (%s", mem->interface); | |
9744 | if (!ast_strlen_zero(mem->state_interface) | |
9745 | && strcmp(mem->state_interface, mem->interface)) { | |
9746 | ast_str_append(&out, 0, " from %s", mem->state_interface); | |
9747 | } | |
9748 | ast_str_append(&out, 0, ")"); | |
9749 | } | |
9750 | if (mem->penalty) { | |
9751 | ast_str_append(&out, 0, " with penalty %d", mem->penalty); | |
9752 | } | |
9753 | ||
9754 | ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled"); | |
9755 | ||
9756 | ast_str_append(&out, 0, "%s%s%s%s%s%s%s%s%s", | |
9757 | mem->dynamic ? ast_term_color(COLOR_CYAN, COLOR_BLACK) : "", mem->dynamic ? " (dynamic)" : "", ast_term_reset(), | |
9758 | mem->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset(), | |
9759 | mem->starttime ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->starttime ? " (in call)" : "", ast_term_reset()); | |
9760 | ||
9761 | if (mem->paused) { | |
9762 | ast_str_append(&out, 0, " %s(paused%s%s was %ld secs ago)%s", | |
9763 | ast_term_color(COLOR_BROWN, COLOR_BLACK), | |
9764 | ast_strlen_zero(mem->reason_paused) ? "" : ":", | |
9765 | ast_strlen_zero(mem->reason_paused) ? "" : mem->reason_paused, | |
9766 | (long) (now - mem->lastpause), | |
9767 | ast_term_reset()); | |
9768 | } | |
9769 | ||
9770 | ast_str_append(&out, 0, " (%s%s%s)", | |
9771 | ast_term_color( | |
9772 | mem->status == AST_DEVICE_UNAVAILABLE || mem->status == AST_DEVICE_UNKNOWN ? | |
9773 | COLOR_RED : COLOR_GREEN, COLOR_BLACK), | |
9774 | ast_devstate2str(mem->status), ast_term_reset()); | |
9775 | if (mem->calls) { | |
9776 | ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)", | |
9777 | mem->calls, (long) (now - mem->lastcall)); | |
9778 | } else { | |
9779 | ast_str_append(&out, 0, " has taken no calls yet"); | |
9780 | } | |
9781 | do_print(s, fd, ast_str_buffer(out)); | |
9782 | ao2_ref(mem, -1); | |
9783 | } | |
9784 | ao2_iterator_destroy(&mem_iter); | |
9785 | } | |
9786 | if (!q->head) { | |
9787 | do_print(s, fd, " No Callers"); | |
9788 | } else { | |
9789 | struct queue_ent *qe; | |
9790 | int pos = 1; | |
9791 | ||
9792 | do_print(s, fd, " Callers: "); | |
9793 | for (qe = q->head; qe; qe = qe->next) { | |
9794 | ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)", | |
9795 | pos++, ast_channel_name(qe->chan), (long) (now - qe->start) / 60, | |
9796 | (long) (now - qe->start) % 60, qe->prio); | |
9797 | do_print(s, fd, ast_str_buffer(out)); | |
9798 | } | |
9799 | } | |
9800 | do_print(s, fd, ""); /* blank line between entries */ | |
9830 | print_queue(s, fd, q); | |
9831 | ||
9801 | 9832 | ao2_unlock(q); |
9802 | 9833 | queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */ |
9803 | 9834 | } |
9804 | 9835 | ao2_iterator_destroy(&queue_iter); |
9805 | ao2_unlock(queues); | |
9836 | ao2_ref(sorted_queues, -1); | |
9806 | 9837 | if (!found) { |
9807 | if (argc == 3) { | |
9808 | ast_str_set(&out, 0, "No such queue: %s.", argv[2]); | |
9809 | } else { | |
9810 | ast_str_set(&out, 0, "No queues."); | |
9811 | } | |
9838 | ast_str_set(&out, 0, "No queues."); | |
9812 | 9839 | do_print(s, fd, ast_str_buffer(out)); |
9813 | 9840 | } |
9814 | 9841 | return CLI_SUCCESS; |
166 | 166 | <argument name="c" /> |
167 | 167 | <para>Accept digits for a new extension in context <replaceable>c</replaceable>, |
168 | 168 | if played during the greeting. Context defaults to the current context.</para> |
169 | </option> | |
170 | <option name="e"> | |
171 | <para>Play greetings as early media -- only answer the channel just | |
172 | before accepting the voice message.</para> | |
169 | 173 | </option> |
170 | 174 | <option name="g"> |
171 | 175 | <argument name="#" required="true" /> |
659 | 663 | OPT_AUTOPLAY = (1 << 6), |
660 | 664 | OPT_DTMFEXIT = (1 << 7), |
661 | 665 | OPT_MESSAGE_Urgent = (1 << 8), |
662 | OPT_MESSAGE_PRIORITY = (1 << 9) | |
666 | OPT_MESSAGE_PRIORITY = (1 << 9), | |
667 | OPT_EARLYM_GREETING = (1 << 10) | |
663 | 668 | }; |
664 | 669 | |
665 | 670 | enum vm_option_args { |
685 | 690 | AST_APP_OPTION('p', OPT_PREPEND_MAILBOX), |
686 | 691 | AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER), |
687 | 692 | AST_APP_OPTION('U', OPT_MESSAGE_Urgent), |
688 | AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY) | |
693 | AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY), | |
694 | AST_APP_OPTION('e', OPT_EARLYM_GREETING) | |
689 | 695 | }); |
690 | 696 | |
691 | 697 | static const char * const mailbox_folders[] = { |
3932 | 3938 | char fn[PATH_MAX]; |
3933 | 3939 | char full_fn[PATH_MAX]; |
3934 | 3940 | char msgnums[80]; |
3941 | char msg_id[MSG_ID_LEN] = ""; | |
3935 | 3942 | char *argv[] = { dir, msgnums }; |
3936 | 3943 | struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv }; |
3937 | 3944 | struct odbc_obj *obj; |
4036 | 4043 | } else { |
4037 | 4044 | res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL); |
4038 | 4045 | if (res == SQL_NULL_DATA && !strcasecmp(coltitle, "msg_id")) { |
4039 | char msg_id[MSG_ID_LEN]; | |
4046 | /* Generate msg_id now, but don't store it until we're done with this | |
4047 | connection */ | |
4040 | 4048 | generate_msg_id(msg_id); |
4041 | 4049 | snprintf(rowdata, sizeof(rowdata), "%s", msg_id); |
4042 | odbc_update_msg_id(dir, msgnum, msg_id); | |
4043 | 4050 | } else if (res == SQL_NULL_DATA && !strcasecmp(coltitle, "category")) { |
4044 | 4051 | /* Ignore null column value for category */ |
4045 | 4052 | ast_debug(3, "Ignoring null category column in ODBC voicemail retrieve_file.\n"); |
4064 | 4071 | close(fd); |
4065 | 4072 | |
4066 | 4073 | ast_odbc_release_obj(obj); |
4074 | ||
4075 | /* If res_odbc is configured to only allow a single database connection, we | |
4076 | will deadlock if we try to do this before releasing the connection we | |
4077 | were just using. */ | |
4078 | if (!ast_strlen_zero(msg_id)) { | |
4079 | odbc_update_msg_id(dir, msgnum, msg_id); | |
4080 | } | |
4067 | 4081 | |
4068 | 4082 | return x - 1; |
4069 | 4083 | } |
6958 | 6972 | return -1; |
6959 | 6973 | } |
6960 | 6974 | /* The meat of recording the message... All the announcements and beeps have been played*/ |
6975 | if (ast_channel_state(chan) != AST_STATE_UP) { | |
6976 | ast_answer(chan); | |
6977 | } | |
6961 | 6978 | ast_copy_string(fmt, vmfmts, sizeof(fmt)); |
6962 | 6979 | if (!ast_strlen_zero(fmt)) { |
6963 | 6980 | char msg_id[MSG_ID_LEN] = ""; |
12363 | 12380 | |
12364 | 12381 | memset(&leave_options, 0, sizeof(leave_options)); |
12365 | 12382 | |
12366 | if (ast_channel_state(chan) != AST_STATE_UP) | |
12367 | ast_answer(chan); | |
12368 | ||
12369 | 12383 | if (!ast_strlen_zero(data)) { |
12370 | 12384 | tmp = ast_strdupa(data); |
12371 | 12385 | AST_STANDARD_APP_ARGS(args, tmp); |
12396 | 12410 | if (ast_strlen_zero(temp)) |
12397 | 12411 | return 0; |
12398 | 12412 | args.argv0 = ast_strdupa(temp); |
12413 | } | |
12414 | ||
12415 | if (ast_channel_state(chan) != AST_STATE_UP) { | |
12416 | if (ast_test_flag(&flags, OPT_EARLYM_GREETING)) { | |
12417 | ast_indicate(chan, AST_CONTROL_PROGRESS); | |
12418 | } else { | |
12419 | ast_answer(chan); | |
12420 | } | |
12399 | 12421 | } |
12400 | 12422 | |
12401 | 12423 | res = leave_voicemail(chan, args.argv0, &leave_options); |
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.1</title><h1 align="center"><a name="top">Release Summary</a></h1><h3 align="center">asterisk-16.15.1</h3><h3 align="center">Date: 2020-12-22</h3><h3 align="center"><asteriskteam@digium.com></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="#open_issues">Open 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 has been made to address one or more security vulnerabilities that have been identified. A security advisory document has been published for each vulnerability that includes additional information. Users of versions of Asterisk that are affected are strongly encouraged to review the advisories and determine what action they should take to protect their systems from these issues.</p><p>Security Advisories:</p><ul> | |
7 | <li><a href="http://downloads.asterisk.org/pub/security/AST-2020-003,AST-2020-004.html">AST-2020-003,AST-2020-004</a></li> | |
8 | </ul><p>The data in this summary reflects changes that have been made since the previous release, asterisk-16.15.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"> | |
9 | <tr><th width="33%">Coders</th><th width="33%">Testers</th><th width="33%">Reporters</th></tr> | |
10 | <tr valign="top"><td width="33%">1 Torrey Searle <tsearle@voxbone.com><br/>1 Asterisk Development Team <asteriskteam@digium.com><br/></td><td width="33%"><td width="33%">1 Mikhail Ivanov <mivanov@lanta-net.ru><br/>1 Torrey Searle <tsearle@gmail.com><br/></td></tr> | |
11 | </table><hr><a name="open_issues"><h2 align="center">Open Issues</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a list of all open issues from the issue tracker that were referenced by changes that went into this release.</p><h3>Security</h3><h4>Category: Resources/res_pjsip_diversion</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29219">ASTERISK-29219</a>: res_pjsip_diversion: Crash if Tel URI contains History-Info<br/>Reported by: Torrey Searle<ul> | |
12 | <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=354049e055a2c0162d510f2c75d1580f80d0d6e6">[354049e055]</a> Torrey Searle -- res/res_pjsip_diversion: prevent crash on tel: uri in History-Info</li> | |
13 | </ul><br><h3>Bug</h3><h4>Category: Resources/res_pjsip_diversion</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29191">ASTERISK-29191</a>: tel: URI in Diversion header causes crash<br/>Reported by: Mikhail Ivanov<ul> | |
14 | <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=354049e055a2c0162d510f2c75d1580f80d0d6e6">[354049e055]</a> Torrey Searle -- res/res_pjsip_diversion: prevent crash on tel: uri in History-Info</li> | |
15 | </ul><br><h4>Category: pjproject/pjsip</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29191">ASTERISK-29191</a>: tel: URI in Diversion header causes crash<br/>Reported by: Mikhail Ivanov<ul> | |
16 | <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=354049e055a2c0162d510f2c75d1580f80d0d6e6">[354049e055]</a> Torrey Searle -- res/res_pjsip_diversion: prevent crash on tel: uri in History-Info</li> | |
17 | </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"> | |
18 | <tr><th>Revision</th><th>Author</th><th>Summary</th></tr> | |
19 | <tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=49fbd5788924f4d3d05165194b380ade69cacafb">49fbd57889</a></td><td>Asterisk Development Team</td><td>Update for 16.15.1</td></tr> | |
20 | </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.15.0-summary.html | 213 --------------- | |
21 | asterisk-16.15.0-summary.txt | 543 ---------------------------------------- | |
22 | b/.version | 2 | |
23 | b/ChangeLog | 16 + | |
24 | b/asterisk-16.15.1-summary.html | 17 + | |
25 | b/asterisk-16.15.1-summary.txt | 47 +++ | |
26 | 6 files changed, 81 insertions(+), 757 deletions(-)</pre><br></html>⏎ |
0 | Release Summary | |
1 | ||
2 | asterisk-16.15.1 | |
3 | ||
4 | Date: 2020-12-22 | |
5 | ||
6 | <asteriskteam@digium.com> | |
7 | ||
8 | ---------------------------------------------------------------------- | |
9 | ||
10 | Table of Contents | |
11 | ||
12 | 1. Summary | |
13 | 2. Contributors | |
14 | 3. Open Issues | |
15 | 4. Other Changes | |
16 | 5. Diffstat | |
17 | ||
18 | ---------------------------------------------------------------------- | |
19 | ||
20 | Summary | |
21 | ||
22 | [Back to Top] | |
23 | ||
24 | This release has been made to address one or more security vulnerabilities | |
25 | that have been identified. A security advisory document has been published | |
26 | for each vulnerability that includes additional information. Users of | |
27 | versions of Asterisk that are affected are strongly encouraged to review | |
28 | the advisories and determine what action they should take to protect their | |
29 | systems from these issues. | |
30 | ||
31 | Security Advisories: | |
32 | ||
33 | * AST-2020-003,AST-2020-004 | |
34 | ||
35 | The data in this summary reflects changes that have been made since the | |
36 | previous release, asterisk-16.15.0. | |
37 | ||
38 | ---------------------------------------------------------------------- | |
39 | ||
40 | Contributors | |
41 | ||
42 | [Back to Top] | |
43 | ||
44 | This table lists the people who have submitted code, those that have | |
45 | tested patches, as well as those that reported issues on the issue tracker | |
46 | that were resolved in this release. For coders, the number is how many of | |
47 | their patches (of any size) were committed into this release. For testers, | |
48 | the number is the number of times their name was listed as assisting with | |
49 | testing a patch. Finally, for reporters, the number is the number of | |
50 | issues that they reported that were affected by commits that went into | |
51 | this release. | |
52 | ||
53 | Coders Testers Reporters | |
54 | 1 Torrey Searle 1 Mikhail Ivanov | |
55 | 1 Asterisk Development Team 1 Torrey Searle | |
56 | ||
57 | ---------------------------------------------------------------------- | |
58 | ||
59 | Open Issues | |
60 | ||
61 | [Back to Top] | |
62 | ||
63 | This is a list of all open issues from the issue tracker that were | |
64 | referenced by changes that went into this release. | |
65 | ||
66 | Security | |
67 | ||
68 | Category: Resources/res_pjsip_diversion | |
69 | ||
70 | ASTERISK-29219: res_pjsip_diversion: Crash if Tel URI contains | |
71 | History-Info | |
72 | Reported by: Torrey Searle | |
73 | * [354049e055] Torrey Searle -- res/res_pjsip_diversion: prevent crash | |
74 | on tel: uri in History-Info | |
75 | ||
76 | Bug | |
77 | ||
78 | Category: Resources/res_pjsip_diversion | |
79 | ||
80 | ASTERISK-29191: tel: URI in Diversion header causes crash | |
81 | Reported by: Mikhail Ivanov | |
82 | * [354049e055] Torrey Searle -- res/res_pjsip_diversion: prevent crash | |
83 | on tel: uri in History-Info | |
84 | ||
85 | Category: pjproject/pjsip | |
86 | ||
87 | ASTERISK-29191: tel: URI in Diversion header causes crash | |
88 | Reported by: Mikhail Ivanov | |
89 | * [354049e055] Torrey Searle -- res/res_pjsip_diversion: prevent crash | |
90 | on tel: uri in History-Info | |
91 | ||
92 | ---------------------------------------------------------------------- | |
93 | ||
94 | Commits Not Associated with an Issue | |
95 | ||
96 | [Back to Top] | |
97 | ||
98 | This is a list of all changes that went into this release that did not | |
99 | reference a JIRA issue. | |
100 | ||
101 | +------------------------------------------------------------------------+ | |
102 | | Revision | Author | Summary | | |
103 | |----------------+-------------------------------+-----------------------| | |
104 | | 49fbd57889 | Asterisk Development Team | Update for 16.15.1 | | |
105 | +------------------------------------------------------------------------+ | |
106 | ||
107 | ---------------------------------------------------------------------- | |
108 | ||
109 | Diffstat Results | |
110 | ||
111 | [Back to Top] | |
112 | ||
113 | This is a summary of the changes to the source code that went into this | |
114 | release that was generated using the diffstat utility. | |
115 | ||
116 | asterisk-16.15.0-summary.html | 213 --------------- | |
117 | asterisk-16.15.0-summary.txt | 543 ---------------------------------------- | |
118 | b/.version | 2 | |
119 | b/ChangeLog | 16 + | |
120 | b/asterisk-16.15.1-summary.html | 17 + | |
121 | b/asterisk-16.15.1-summary.txt | 47 +++ | |
122 | 6 files changed, 81 insertions(+), 757 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.16.1</title><h1 align="center"><a name="top">Release Summary</a></h1><h3 align="center">asterisk-16.16.1</h3><h3 align="center">Date: 2021-02-18</h3><h3 align="center"><asteriskteam@digium.com></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="#diffstat">Diffstat</a></li> | |
5 | </ol><hr><a name="summary"><h2 align="center">Summary</h2></a><center><a href="#top">[Back to Top]</a></center><p>This release has been made to address one or more security vulnerabilities that have been identified. A security advisory document has been published for each vulnerability that includes additional information. Users of versions of Asterisk that are affected are strongly encouraged to review the advisories and determine what action they should take to protect their systems from these issues.</p><p>Security Advisories:</p><ul> | |
6 | <li><a href="http://downloads.asterisk.org/pub/security/AST-2021-001,AST-2021-002,AST-2021-003,AST-2021-004,AST-2021-005.html">AST-2021-001,AST-2021-002,AST-2021-003,AST-2021-004,AST-2021-005</a></li> | |
7 | </ul><p>The data in this summary reflects changes that have been made since the previous release, asterisk-16.16.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"> | |
8 | <tr><th width="33%">Coders</th><th width="33%">Testers</th><th width="33%">Reporters</th></tr> | |
9 | <tr valign="top"><td width="33%">1 Ivan Poddubnyi <ivan.poddubny@gmail.com><br/>1 Sean Bright <sean.bright@gmail.com><br/>1 Kevin Harwell <kharwell@sangoma.com><br/>1 Alexander Traud <pabstraud@compuserve.com><br/>1 Joshua C. Colp <jcolp@sangoma.com><br/></td><td width="33%"><td width="33%">1 Mauri de Souza Meneguzzo (3CPlus) <mauri.nunes@fluxoti.com><br/>1 Ivan Poddubny<br/>1 Ivan Poddubny <ivan.poddubny@gmail.com><br/>1 Edvin Vidmar <edvinvidmar@hotmail.com><br/>1 Alexander Traud <pabstraud@compuserve.com><br/>1 Gregory Massel <greg@csurf.co.za><br/>1 Alexander Traud<br/></td></tr> | |
10 | </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: Resources/res_srtp</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29260">ASTERISK-29260</a>: sRTP Replay Protection ignored; even tears down long calls<br/>Reported by: Alexander Traud<ul> | |
11 | <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=3f4dfd5c022c82265cbaba7fa726d1e27dd21cce">[3f4dfd5c02]</a> Alexander Traud -- rtp: Enable srtp replay protection</li> | |
12 | </ul><br><h4>Category: pjproject/pjsip</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29227">ASTERISK-29227</a>: res_pjsip_diversion: sending multiple 181 responses causes memory corruption and crash<br/>Reported by: Ivan Poddubny<ul> | |
13 | <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=17561b5e643092b64a1e8351b25017b28ed690b4">[17561b5e64]</a> Ivan Poddubnyi -- res_pjsip_diversion: Fix adding more than one histinfo to Supported</li> | |
14 | </ul><br><h3>Bug</h3><h4>Category: Resources/res_pjsip</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29196">ASTERISK-29196</a>: res_pjsip: Segmentation fault<br/>Reported by: Mauri de Souza Meneguzzo (3CPlus)<ul> | |
15 | <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=321632b02e828406d45bc4be2793399f1746c32a">[321632b02e]</a> Joshua C. Colp -- pjsip: Make modify_local_offer2 tolerate previous failed SDP.</li> | |
16 | </ul><br><h4>Category: Resources/res_pjsip_session</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29203">ASTERISK-29203</a>: res_pjsip_t38: Crash when changing state<br/>Reported by: Gregory Massel<ul> | |
17 | <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a5619097cd7e4da4d64a513d9659871ea217a706">[a5619097cd]</a> Kevin Harwell -- AST-2021-002: Remote crash possible when negotiating T.38</li> | |
18 | </ul><br><h4>Category: Resources/res_pjsip_t38</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29203">ASTERISK-29203</a>: res_pjsip_t38: Crash when changing state<br/>Reported by: Gregory Massel<ul> | |
19 | <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a5619097cd7e4da4d64a513d9659871ea217a706">[a5619097cd]</a> Kevin Harwell -- AST-2021-002: Remote crash possible when negotiating T.38</li> | |
20 | </ul><br><h4>Category: Resources/res_rtp_asterisk</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-29205">ASTERISK-29205</a>: res_rtp_asterisk: Asterisk crashes when making hold/unhold from webrtc client<br/>Reported by: Edvin Vidmar<ul> | |
21 | <li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=4cea145aa9a7dc90eabdd1f63cb3162f3e1d91e8">[4cea145aa9]</a> Sean Bright -- res_rtp_asterisk.c: Fix signed mismatch that leads to overflow</li> | |
22 | </ul><br><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>configs/samples/rtp.conf.sample | 12 +++++++ | |
23 | doc/CHANGES-staging/srtp_replay_protection.txt | 9 +++++ | |
24 | doc/UPGRADE-staging/srtp_replay_protection.txt | 9 +++++ | |
25 | res/res_pjsip_diversion.c | 14 ++++++++ | |
26 | res/res_pjsip_outbound_registration.c | 12 +++++++ | |
27 | res/res_pjsip_path.c | 12 +++++++ | |
28 | res/res_pjsip_session.c | 9 +++++ | |
29 | res/res_pjsip_t38.c | 9 +++++ | |
30 | res/res_rtp_asterisk.c | 16 +++++++--- | |
31 | res/res_srtp.c | 5 +-- | |
32 | third-party/pjproject/patches/0080-fix-sdp-neg-modify-local-offer.patch | 15 +++++++++ | |
33 | 11 files changed, 115 insertions(+), 7 deletions(-)</pre><br></html>⏎ |
0 | Release Summary | |
1 | ||
2 | asterisk-16.16.1 | |
3 | ||
4 | Date: 2021-02-18 | |
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. Diffstat | |
16 | ||
17 | ---------------------------------------------------------------------- | |
18 | ||
19 | Summary | |
20 | ||
21 | [Back to Top] | |
22 | ||
23 | This release has been made to address one or more security vulnerabilities | |
24 | that have been identified. A security advisory document has been published | |
25 | for each vulnerability that includes additional information. Users of | |
26 | versions of Asterisk that are affected are strongly encouraged to review | |
27 | the advisories and determine what action they should take to protect their | |
28 | systems from these issues. | |
29 | ||
30 | Security Advisories: | |
31 | ||
32 | * AST-2021-001,AST-2021-002,AST-2021-003,AST-2021-004,AST-2021-005 | |
33 | ||
34 | The data in this summary reflects changes that have been made since the | |
35 | previous release, asterisk-16.16.0. | |
36 | ||
37 | ---------------------------------------------------------------------- | |
38 | ||
39 | Contributors | |
40 | ||
41 | [Back to Top] | |
42 | ||
43 | This table lists the people who have submitted code, those that have | |
44 | tested patches, as well as those that reported issues on the issue tracker | |
45 | that were resolved in this release. For coders, the number is how many of | |
46 | their patches (of any size) were committed into this release. For testers, | |
47 | the number is the number of times their name was listed as assisting with | |
48 | testing a patch. Finally, for reporters, the number is the number of | |
49 | issues that they reported that were affected by commits that went into | |
50 | this release. | |
51 | ||
52 | Coders Testers Reporters | |
53 | 1 Ivan Poddubnyi 1 Mauri de Souza Meneguzzo (3CPlus) | |
54 | 1 Sean Bright 1 Ivan Poddubny | |
55 | 1 Kevin Harwell 1 Ivan Poddubny | |
56 | 1 Alexander Traud 1 Edvin Vidmar | |
57 | 1 Joshua C. Colp 1 Alexander Traud | |
58 | 1 Gregory Massel | |
59 | 1 Alexander Traud | |
60 | ||
61 | ---------------------------------------------------------------------- | |
62 | ||
63 | Closed Issues | |
64 | ||
65 | [Back to Top] | |
66 | ||
67 | This is a list of all issues from the issue tracker that were closed by | |
68 | changes that went into this release. | |
69 | ||
70 | Security | |
71 | ||
72 | Category: Resources/res_srtp | |
73 | ||
74 | ASTERISK-29260: sRTP Replay Protection ignored; even tears down long calls | |
75 | Reported by: Alexander Traud | |
76 | * [3f4dfd5c02] Alexander Traud -- rtp: Enable srtp replay protection | |
77 | ||
78 | Category: pjproject/pjsip | |
79 | ||
80 | ASTERISK-29227: res_pjsip_diversion: sending multiple 181 responses causes | |
81 | memory corruption and crash | |
82 | Reported by: Ivan Poddubny | |
83 | * [17561b5e64] Ivan Poddubnyi -- res_pjsip_diversion: Fix adding more | |
84 | than one histinfo to Supported | |
85 | ||
86 | Bug | |
87 | ||
88 | Category: Resources/res_pjsip | |
89 | ||
90 | ASTERISK-29196: res_pjsip: Segmentation fault | |
91 | Reported by: Mauri de Souza Meneguzzo (3CPlus) | |
92 | * [321632b02e] Joshua C. Colp -- pjsip: Make modify_local_offer2 | |
93 | tolerate previous failed SDP. | |
94 | ||
95 | Category: Resources/res_pjsip_session | |
96 | ||
97 | ASTERISK-29203: res_pjsip_t38: Crash when changing state | |
98 | Reported by: Gregory Massel | |
99 | * [a5619097cd] Kevin Harwell -- AST-2021-002: Remote crash possible when | |
100 | negotiating T.38 | |
101 | ||
102 | Category: Resources/res_pjsip_t38 | |
103 | ||
104 | ASTERISK-29203: res_pjsip_t38: Crash when changing state | |
105 | Reported by: Gregory Massel | |
106 | * [a5619097cd] Kevin Harwell -- AST-2021-002: Remote crash possible when | |
107 | negotiating T.38 | |
108 | ||
109 | Category: Resources/res_rtp_asterisk | |
110 | ||
111 | ASTERISK-29205: res_rtp_asterisk: Asterisk crashes when making hold/unhold | |
112 | from webrtc client | |
113 | Reported by: Edvin Vidmar | |
114 | * [4cea145aa9] Sean Bright -- res_rtp_asterisk.c: Fix signed mismatch | |
115 | that leads to overflow | |
116 | ||
117 | ---------------------------------------------------------------------- | |
118 | ||
119 | Diffstat Results | |
120 | ||
121 | [Back to Top] | |
122 | ||
123 | This is a summary of the changes to the source code that went into this | |
124 | release that was generated using the diffstat utility. | |
125 | ||
126 | configs/samples/rtp.conf.sample | 12 +++++++ | |
127 | doc/CHANGES-staging/srtp_replay_protection.txt | 9 +++++ | |
128 | doc/UPGRADE-staging/srtp_replay_protection.txt | 9 +++++ | |
129 | res/res_pjsip_diversion.c | 14 ++++++++ | |
130 | res/res_pjsip_outbound_registration.c | 12 +++++++ | |
131 | res/res_pjsip_path.c | 12 +++++++ | |
132 | res/res_pjsip_session.c | 9 +++++ | |
133 | res/res_pjsip_t38.c | 9 +++++ | |
134 | res/res_rtp_asterisk.c | 16 +++++++--- | |
135 | res/res_srtp.c | 5 +-- | |
136 | third-party/pjproject/patches/0080-fix-sdp-neg-modify-local-offer.patch | 15 +++++++++ | |
137 | 11 files changed, 115 insertions(+), 7 deletions(-) |
25 | 25 | src="$1" |
26 | 26 | dst="$2" |
27 | 27 | sed <"$src" \ |
28 | -e "s|__ASTERISK_CACHE_DIR__|$ASTCACHEDIR|g" \ | |
28 | 29 | -e "s|__ASTERISK_DATA_DIR__|$ASTDATADIR|g" \ |
29 | 30 | -e "s|__ASTERISK_DB_DIR__|$ASTDBDIR|g" \ |
30 | 31 | -e "s|__ASTERISK_ETC_DIR__|$ASTETCDIR|g" \ |
6 | 6 | */ |
7 | 7 | #define DEFAULT_CONFIG_FILE "${INSTALL_PATH}${ASTCONFPATH}" |
8 | 8 | |
9 | #define DEFAULT_CACHE_DIR "${INSTALL_PATH}${ASTCACHEDIR}" | |
9 | 10 | #define DEFAULT_CONFIG_DIR "${INSTALL_PATH}${ASTETCDIR}" |
10 | 11 | #define DEFAULT_MODULE_DIR "${INSTALL_PATH}${ASTMODDIR}" |
11 | 12 | #define DEFAULT_AGI_DIR "${INSTALL_PATH}${AGI_DIR}" |
31 | 31 | cat <<EOF > "$PPATH/asterisk.pc" |
32 | 32 | install_prefix=$INSTALL_PREFIX |
33 | 33 | version_number=$ASTERISKVERSIONNUM |
34 | cachedir=$ASTCACHEDIR | |
34 | 35 | etcdir=$ASTETCDIR |
35 | 36 | libdir=$ASTLIBDIR |
36 | 37 | varlibdir=$ASTVARLIBDIR |
136 | 136 | static void chan_pjsip_session_end(struct ast_sip_session *session); |
137 | 137 | static int chan_pjsip_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata); |
138 | 138 | static void chan_pjsip_incoming_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata); |
139 | static void chan_pjsip_incoming_response_update_cause(struct ast_sip_session *session, struct pjsip_rx_data *rdata); | |
139 | 140 | |
140 | 141 | /*! \brief SIP session supplement structure */ |
141 | 142 | static struct ast_sip_session_supplement chan_pjsip_supplement = { |
144 | 145 | .session_begin = chan_pjsip_session_begin, |
145 | 146 | .session_end = chan_pjsip_session_end, |
146 | 147 | .incoming_request = chan_pjsip_incoming_request, |
148 | .incoming_response = chan_pjsip_incoming_response, | |
147 | 149 | /* It is important that this supplement runs after media has been negotiated */ |
148 | 150 | .response_priority = AST_SIP_SESSION_AFTER_MEDIA, |
149 | 151 | }; |
152 | 154 | static struct ast_sip_session_supplement chan_pjsip_supplement_response = { |
153 | 155 | .method = "INVITE", |
154 | 156 | .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL, |
155 | .incoming_response = chan_pjsip_incoming_response, | |
157 | .incoming_response = chan_pjsip_incoming_response_update_cause, | |
156 | 158 | .response_priority = AST_SIP_SESSION_BEFORE_MEDIA | AST_SIP_SESSION_AFTER_MEDIA, |
157 | 159 | }; |
158 | 160 | |
672 | 674 | ast_log(LOG_ERROR, "Session already DISCONNECTED [reason=%d (%s)]\n", |
673 | 675 | session->inv_session->cause, |
674 | 676 | pjsip_get_status_text(session->inv_session->cause)->ptr); |
675 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
676 | pjsip_inv_dec_ref(session->inv_session); | |
677 | #endif | |
678 | 677 | return 0; |
679 | 678 | } |
680 | 679 | |
690 | 689 | if (status == PJ_SUCCESS && packet) { |
691 | 690 | ast_sip_session_send_response(session, packet); |
692 | 691 | } |
693 | ||
694 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
695 | pjsip_inv_dec_ref(session->inv_session); | |
696 | #endif | |
697 | 692 | |
698 | 693 | if (status != PJ_SUCCESS) { |
699 | 694 | char err[PJ_ERR_MSG_SIZE]; |
723 | 718 | |
724 | 719 | ast_setstate(ast, AST_STATE_UP); |
725 | 720 | session = ao2_bump(channel->session); |
726 | ||
727 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
728 | if (pjsip_inv_add_ref(session->inv_session) != PJ_SUCCESS) { | |
729 | ast_log(LOG_ERROR, "Can't increase the session reference counter\n"); | |
730 | ao2_ref(session, -1); | |
731 | return -1; | |
732 | } | |
733 | #endif | |
734 | 721 | |
735 | 722 | /* the answer task needs to be pushed synchronously otherwise a race condition |
736 | 723 | can occur between this thread and bridging (specifically when native bridging |
741 | 728 | if (res == -1) { |
742 | 729 | ast_log(LOG_ERROR,"Cannot answer '%s': Unable to push answer task to the threadpool.\n", |
743 | 730 | ast_channel_name(session->channel)); |
744 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
745 | pjsip_inv_dec_ref(session->inv_session); | |
746 | #endif | |
747 | 731 | } |
748 | 732 | ao2_ref(session, -1); |
749 | 733 | ast_channel_lock(ast); |
1342 | 1326 | ast_sip_session_send_response(session, packet); |
1343 | 1327 | } |
1344 | 1328 | |
1345 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
1346 | pjsip_inv_dec_ref(session->inv_session); | |
1347 | #endif | |
1348 | 1329 | ao2_ref(ind_data, -1); |
1349 | 1330 | |
1350 | 1331 | return 0; |
1376 | 1357 | ast_log(LOG_ERROR, "Session already DISCONNECTED [reason=%d (%s)]\n", |
1377 | 1358 | session->inv_session->cause, |
1378 | 1359 | pjsip_get_status_text(session->inv_session->cause)->ptr); |
1379 | goto failure; | |
1360 | return -1; | |
1380 | 1361 | } |
1381 | 1362 | |
1382 | 1363 | if (ast_sip_create_request("INFO", session->inv_session->dlg, session->endpoint, NULL, NULL, &tdata)) { |
1383 | 1364 | ast_log(LOG_ERROR, "Could not create text video update INFO request\n"); |
1384 | goto failure; | |
1365 | return -1; | |
1385 | 1366 | } |
1386 | 1367 | if (ast_sip_add_body(tdata, &body)) { |
1387 | 1368 | ast_log(LOG_ERROR, "Could not add body to text video update INFO request\n"); |
1388 | goto failure; | |
1369 | return -1; | |
1389 | 1370 | } |
1390 | 1371 | ast_sip_session_send_request(session, tdata); |
1391 | 1372 | |
1392 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
1393 | pjsip_inv_dec_ref(session->inv_session); | |
1394 | #endif | |
1395 | ||
1396 | 1373 | return 0; |
1397 | ||
1398 | failure: | |
1399 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
1400 | pjsip_inv_dec_ref(session->inv_session); | |
1401 | #endif | |
1402 | return -1; | |
1403 | ||
1404 | 1374 | } |
1405 | 1375 | |
1406 | 1376 | /*! |
1448 | 1418 | ast_log(LOG_ERROR, "Session already DISCONNECTED [reason=%d (%s)]\n", |
1449 | 1419 | session->inv_session->cause, |
1450 | 1420 | pjsip_get_status_text(session->inv_session->cause)->ptr); |
1451 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
1452 | pjsip_inv_dec_ref(session->inv_session); | |
1453 | #endif | |
1454 | 1421 | ao2_ref(session, -1); |
1455 | 1422 | return -1; |
1456 | 1423 | } |
1490 | 1457 | } |
1491 | 1458 | } |
1492 | 1459 | } |
1493 | ||
1494 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
1495 | pjsip_inv_dec_ref(session->inv_session); | |
1496 | #endif | |
1497 | 1460 | |
1498 | 1461 | ao2_ref(session, -1); |
1499 | 1462 | return 0; |
1725 | 1688 | res = ast_rtp_instance_write(media->rtp, &fr); |
1726 | 1689 | } else { |
1727 | 1690 | ao2_ref(channel->session, +1); |
1728 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
1729 | if (pjsip_inv_add_ref(channel->session->inv_session) != PJ_SUCCESS) { | |
1730 | ast_log(LOG_ERROR, "Can't increase the session reference counter\n"); | |
1691 | if (ast_sip_push_task(channel->session->serializer, transmit_info_with_vidupdate, channel->session)) { | |
1731 | 1692 | ao2_cleanup(channel->session); |
1732 | } else { | |
1733 | #endif | |
1734 | if (ast_sip_push_task(channel->session->serializer, transmit_info_with_vidupdate, channel->session)) { | |
1735 | ao2_cleanup(channel->session); | |
1736 | } | |
1737 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
1738 | 1693 | } |
1739 | #endif | |
1740 | 1694 | } |
1741 | 1695 | ast_test_suite_event_notify("AST_CONTROL_VIDUPDATE", "Result: Success"); |
1742 | 1696 | } else { |
1750 | 1704 | break; |
1751 | 1705 | case AST_CONTROL_CONNECTED_LINE: |
1752 | 1706 | ao2_ref(channel->session, +1); |
1753 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
1754 | if (pjsip_inv_add_ref(channel->session->inv_session) != PJ_SUCCESS) { | |
1755 | ao2_cleanup(channel->session); | |
1756 | SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Couldn't increase the session reference counter\n", | |
1757 | ast_channel_name(ast)); | |
1758 | } | |
1759 | #endif | |
1760 | 1707 | if (ast_sip_push_task(channel->session->serializer, update_connected_line_information, channel->session)) { |
1761 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
1762 | pjsip_inv_dec_ref(channel->session->inv_session); | |
1763 | #endif | |
1764 | 1708 | ao2_cleanup(channel->session); |
1765 | 1709 | } |
1766 | 1710 | break; |
1867 | 1811 | if (!ind_data) { |
1868 | 1812 | SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Couldn't alloc indicate data\n", ast_channel_name(ast)); |
1869 | 1813 | } |
1870 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
1871 | if (pjsip_inv_add_ref(ind_data->session->inv_session) != PJ_SUCCESS) { | |
1872 | ao2_cleanup(ind_data); | |
1873 | SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Couldn't increase the session reference counter\n", ast_channel_name(ast)); | |
1874 | } | |
1875 | #endif | |
1814 | ||
1876 | 1815 | if (ast_sip_push_task(channel->session->serializer, indicate, ind_data)) { |
1877 | 1816 | ast_log(LOG_ERROR, "%s: Cannot send response code %d to endpoint %s. Could not queue task properly\n", |
1878 | 1817 | ast_channel_name(ast), response_code, ast_sorcery_object_get_id(channel->session->endpoint)); |
1879 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
1880 | pjsip_inv_dec_ref(ind_data->session->inv_session); | |
1881 | #endif | |
1882 | 1818 | ao2_cleanup(ind_data); |
1883 | 1819 | res = -1; |
1884 | 1820 | } |
1971 | 1907 | */ |
1972 | 1908 | static void xfer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event) |
1973 | 1909 | { |
1974 | struct ast_sip_session *session; | |
1975 | struct ast_channel *chan = NULL; | |
1910 | struct ast_channel *chan; | |
1976 | 1911 | enum ast_control_transfer message = AST_TRANSFER_SUCCESS; |
1977 | 1912 | int res = 0; |
1978 | 1913 | |
1980 | 1915 | return; |
1981 | 1916 | } |
1982 | 1917 | |
1983 | session = pjsip_evsub_get_mod_data(sub, refer_callback_module.id); | |
1984 | if (!session) { | |
1985 | return; | |
1986 | } | |
1987 | ||
1988 | chan = session->channel; | |
1918 | chan = pjsip_evsub_get_mod_data(sub, refer_callback_module.id); | |
1989 | 1919 | if (!chan) { |
1990 | 1920 | return; |
1991 | 1921 | } |
2011 | 1941 | */ |
2012 | 1942 | if (refer_sub && !pj_stricmp2(&refer_sub->hvalue, "false")) { |
2013 | 1943 | /* Since no subscription is desired, assume that call has been transferred successfully. */ |
1944 | /* Channel reference will be released at end of function */ | |
2014 | 1945 | /* Terminate subscription. */ |
1946 | pjsip_evsub_set_mod_data(sub, refer_callback_module.id, NULL); | |
2015 | 1947 | pjsip_evsub_terminate(sub, PJ_TRUE); |
2016 | 1948 | res = -1; |
2017 | 1949 | } |
2076 | 2008 | } |
2077 | 2009 | |
2078 | 2010 | if (res) { |
2079 | ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message)); | |
2011 | ast_queue_control_data(chan, AST_CONTROL_TRANSFER, &message, sizeof(message)); | |
2012 | ao2_ref(chan, -1); | |
2080 | 2013 | } |
2081 | 2014 | } |
2082 | 2015 | |
2089 | 2022 | const char *ref_by_val; |
2090 | 2023 | char local_info[pj_strlen(&session->inv_session->dlg->local.info_str) + 1]; |
2091 | 2024 | struct pjsip_evsub_user xfer_cb; |
2025 | struct ast_channel *chan = session->channel; | |
2092 | 2026 | |
2093 | 2027 | pj_bzero(&xfer_cb, sizeof(xfer_cb)); |
2094 | 2028 | xfer_cb.on_evsub_state = &xfer_client_on_evsub_state; |
2095 | 2029 | |
2096 | 2030 | if (pjsip_xfer_create_uac(session->inv_session->dlg, &xfer_cb, &sub) != PJ_SUCCESS) { |
2097 | 2031 | message = AST_TRANSFER_FAILED; |
2098 | ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message)); | |
2032 | ast_queue_control_data(chan, AST_CONTROL_TRANSFER, &message, sizeof(message)); | |
2099 | 2033 | |
2100 | 2034 | return; |
2101 | 2035 | } |
2102 | 2036 | |
2103 | pjsip_evsub_set_mod_data(sub, refer_callback_module.id, session); | |
2037 | /* refer_callback_module requires a reference to chan | |
2038 | * which will be released in xfer_client_on_evsub_state() | |
2039 | * when the implicit REFER subscription terminates */ | |
2040 | pjsip_evsub_set_mod_data(sub, refer_callback_module.id, chan); | |
2041 | ao2_ref(chan, +1); | |
2104 | 2042 | |
2105 | 2043 | if (pjsip_xfer_initiate(sub, pj_cstr(&tmp, target), &packet) != PJ_SUCCESS) { |
2106 | message = AST_TRANSFER_FAILED; | |
2107 | ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message)); | |
2108 | pjsip_evsub_terminate(sub, PJ_FALSE); | |
2109 | ||
2110 | return; | |
2111 | } | |
2112 | ||
2113 | ref_by_val = pbx_builtin_getvar_helper(session->channel, "SIPREFERREDBYHDR"); | |
2044 | goto failure; | |
2045 | } | |
2046 | ||
2047 | ref_by_val = pbx_builtin_getvar_helper(chan, "SIPREFERREDBYHDR"); | |
2114 | 2048 | if (!ast_strlen_zero(ref_by_val)) { |
2115 | 2049 | ast_sip_add_header(packet, "Referred-By", ref_by_val); |
2116 | 2050 | } else { |
2118 | 2052 | ast_sip_add_header(packet, "Referred-By", local_info); |
2119 | 2053 | } |
2120 | 2054 | |
2121 | pjsip_xfer_send_request(sub, packet); | |
2055 | if (pjsip_xfer_send_request(sub, packet) == PJ_SUCCESS) { | |
2056 | return; | |
2057 | } | |
2058 | ||
2059 | failure: | |
2060 | message = AST_TRANSFER_FAILED; | |
2061 | ast_queue_control_data(chan, AST_CONTROL_TRANSFER, &message, sizeof(message)); | |
2062 | pjsip_evsub_set_mod_data(sub, refer_callback_module.id, NULL); | |
2063 | pjsip_evsub_terminate(sub, PJ_FALSE); | |
2064 | ||
2065 | ao2_ref(chan, -1); | |
2122 | 2066 | } |
2123 | 2067 | |
2124 | 2068 | static int transfer(void *data) |
2149 | 2093 | } |
2150 | 2094 | } |
2151 | 2095 | |
2152 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
2153 | pjsip_inv_dec_ref(trnf_data->session->inv_session); | |
2154 | #endif | |
2155 | ||
2156 | 2096 | ao2_ref(trnf_data, -1); |
2157 | 2097 | ao2_cleanup(endpoint); |
2158 | 2098 | ao2_cleanup(contact); |
2169 | 2109 | return -1; |
2170 | 2110 | } |
2171 | 2111 | |
2172 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
2173 | if (pjsip_inv_add_ref(trnf_data->session->inv_session) != PJ_SUCCESS) { | |
2174 | ast_log(LOG_ERROR, "Can't increase the session reference counter\n"); | |
2175 | ao2_cleanup(trnf_data); | |
2176 | return -1; | |
2177 | } | |
2178 | #endif | |
2179 | ||
2180 | 2112 | if (ast_sip_push_task(channel->session->serializer, transfer, trnf_data)) { |
2181 | 2113 | ast_log(LOG_WARNING, "Error requesting transfer\n"); |
2182 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
2183 | pjsip_inv_dec_ref(trnf_data->session->inv_session); | |
2184 | #endif | |
2185 | 2114 | ao2_cleanup(trnf_data); |
2186 | 2115 | return -1; |
2187 | 2116 | } |
2276 | 2205 | ast_log(LOG_ERROR, "Session already DISCONNECTED [reason=%d (%s)]\n", |
2277 | 2206 | session->inv_session->cause, |
2278 | 2207 | pjsip_get_status_text(session->inv_session->cause)->ptr); |
2279 | goto failure; | |
2208 | return -1; | |
2280 | 2209 | } |
2281 | 2210 | |
2282 | 2211 | if (!(body_text = ast_str_create(32))) { |
2283 | 2212 | ast_log(LOG_ERROR, "Could not allocate buffer for INFO DTMF.\n"); |
2284 | goto failure; | |
2213 | return -1; | |
2285 | 2214 | } |
2286 | 2215 | ast_str_set(&body_text, 0, "Signal=%c\r\nDuration=%u\r\n", dtmf_data->digit, dtmf_data->duration); |
2287 | 2216 | |
2289 | 2218 | |
2290 | 2219 | if (ast_sip_create_request("INFO", session->inv_session->dlg, session->endpoint, NULL, NULL, &tdata)) { |
2291 | 2220 | ast_log(LOG_ERROR, "Could not create DTMF INFO request\n"); |
2292 | goto failure; | |
2221 | return -1; | |
2293 | 2222 | } |
2294 | 2223 | if (ast_sip_add_body(tdata, &body)) { |
2295 | 2224 | ast_log(LOG_ERROR, "Could not add body to DTMF INFO request\n"); |
2296 | 2225 | pjsip_tx_data_dec_ref(tdata); |
2297 | goto failure; | |
2226 | return -1; | |
2298 | 2227 | } |
2299 | 2228 | ast_sip_session_send_request(session, tdata); |
2300 | 2229 | |
2301 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
2302 | pjsip_inv_dec_ref(session->inv_session); | |
2303 | #endif | |
2304 | ||
2305 | 2230 | return 0; |
2306 | ||
2307 | failure: | |
2308 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
2309 | pjsip_inv_dec_ref(session->inv_session); | |
2310 | #endif | |
2311 | return -1; | |
2312 | ||
2313 | 2231 | } |
2314 | 2232 | |
2315 | 2233 | /*! \brief Function called by core to stop a DTMF digit */ |
2350 | 2268 | return -1; |
2351 | 2269 | } |
2352 | 2270 | |
2353 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
2354 | if (pjsip_inv_add_ref(dtmf_data->session->inv_session) != PJ_SUCCESS) { | |
2355 | ast_log(LOG_ERROR, "Can't increase the session reference counter\n"); | |
2356 | ao2_cleanup(dtmf_data); | |
2357 | return -1; | |
2358 | } | |
2359 | #endif | |
2360 | ||
2361 | 2271 | if (ast_sip_push_task(channel->session->serializer, transmit_info_dtmf, dtmf_data)) { |
2362 | 2272 | ast_log(LOG_WARNING, "Error sending DTMF via INFO.\n"); |
2363 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
2364 | pjsip_inv_dec_ref(dtmf_data->session->inv_session); | |
2365 | #endif | |
2366 | 2273 | ao2_cleanup(dtmf_data); |
2367 | 2274 | return -1; |
2368 | 2275 | } |
2857 | 2764 | ast_sip_send_request(tdata, data->session->inv_session->dlg, data->session->endpoint, NULL, NULL); |
2858 | 2765 | } |
2859 | 2766 | |
2860 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
2861 | pjsip_inv_dec_ref(data->session->inv_session); | |
2862 | #endif | |
2863 | ||
2864 | 2767 | ao2_cleanup(data); |
2865 | 2768 | |
2866 | 2769 | return 0; |
2882 | 2785 | return -1; |
2883 | 2786 | } |
2884 | 2787 | |
2885 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
2886 | if (pjsip_inv_add_ref(data->session->inv_session) != PJ_SUCCESS) { | |
2887 | ast_log(LOG_ERROR, "Can't increase the session reference counter\n"); | |
2888 | ao2_ref(data, -1); | |
2889 | return -1; | |
2890 | } | |
2891 | #endif | |
2892 | ||
2893 | 2788 | if (ast_sip_push_task(channel->session->serializer, sendtext, data)) { |
2894 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
2895 | pjsip_inv_dec_ref(data->session->inv_session); | |
2896 | #endif | |
2897 | 2789 | ao2_ref(data, -1); |
2898 | 2790 | return -1; |
2899 | 2791 | } |
3051 | 2943 | } |
3052 | 2944 | } |
3053 | 2945 | |
2946 | static void set_sipdomain_variable(struct ast_sip_session *session) | |
2947 | { | |
2948 | pjsip_sip_uri *sip_ruri = pjsip_uri_get_uri(session->request_uri); | |
2949 | size_t size = pj_strlen(&sip_ruri->host) + 1; | |
2950 | char *domain = ast_alloca(size); | |
2951 | ||
2952 | ast_copy_pj_str(domain, &sip_ruri->host, size); | |
2953 | ||
2954 | pbx_builtin_setvar_helper(session->channel, "SIPDOMAIN", domain); | |
2955 | return; | |
2956 | } | |
2957 | ||
3054 | 2958 | /*! \brief Function called when a request is received on the session */ |
3055 | 2959 | static int chan_pjsip_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata) |
3056 | 2960 | { |
3102 | 3006 | SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Failed to allocate new PJSIP channel on incoming SIP INVITE\n", |
3103 | 3007 | ast_sip_session_get_name(session)); |
3104 | 3008 | } |
3009 | ||
3010 | set_sipdomain_variable(session); | |
3011 | ||
3105 | 3012 | /* channel gets created on incoming request, but we wait to call start |
3106 | 3013 | so other supplements have a chance to run */ |
3107 | 3014 | SCOPE_EXIT_RTN_VALUE(0, "%s\n", ast_sip_session_get_name(session)); |
3197 | 3104 | }; |
3198 | 3105 | |
3199 | 3106 | /*! \brief Function called when a response is received on the session */ |
3200 | static void chan_pjsip_incoming_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata) | |
3107 | static void chan_pjsip_incoming_response_update_cause(struct ast_sip_session *session, struct pjsip_rx_data *rdata) | |
3201 | 3108 | { |
3202 | 3109 | struct pjsip_status_line status = rdata->msg_info.msg->line.status; |
3203 | 3110 | struct ast_control_pvt_cause_code *cause_code; |
3222 | 3129 | cause_code->ast_cause = hangup_sip2cause(status.code); |
3223 | 3130 | ast_queue_control_data(session->channel, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size); |
3224 | 3131 | ast_channel_hangupcause_hash_set(session->channel, cause_code, data_size); |
3132 | ||
3133 | SCOPE_EXIT_RTN("%s\n", ast_sip_session_get_name(session)); | |
3134 | } | |
3135 | ||
3136 | /*! \brief Function called when a response is received on the session */ | |
3137 | static void chan_pjsip_incoming_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata) | |
3138 | { | |
3139 | struct pjsip_status_line status = rdata->msg_info.msg->line.status; | |
3140 | SCOPE_ENTER(3, "%s: Status: %d\n", ast_sip_session_get_name(session), status.code); | |
3141 | ||
3142 | if (!session->channel) { | |
3143 | SCOPE_EXIT_RTN("%s: No channel\n", ast_sip_session_get_name(session)); | |
3144 | } | |
3225 | 3145 | |
3226 | 3146 | switch (status.code) { |
3227 | 3147 | case 180: |
3119 | 3119 | |
3120 | 3120 | if (ast_iostream_get_ssl(tcptls_session->stream)) { |
3121 | 3121 | set_socket_transport(&req.socket, AST_TRANSPORT_TLS); |
3122 | req.socket.port = htons(ourport_tls); | |
3123 | 3122 | } else { |
3124 | 3123 | set_socket_transport(&req.socket, AST_TRANSPORT_TCP); |
3125 | req.socket.port = htons(ourport_tcp); | |
3126 | 3124 | } |
3127 | 3125 | req.socket.fd = ast_iostream_get_fd(tcptls_session->stream); |
3128 | 3126 | |
6401 | 6399 | } |
6402 | 6400 | } |
6403 | 6401 | |
6404 | if (!dialog->socket.type) | |
6402 | if (!dialog->socket.type) { | |
6405 | 6403 | set_socket_transport(&dialog->socket, AST_TRANSPORT_UDP); |
6406 | if (!dialog->socket.port) { | |
6407 | dialog->socket.port = htons(ast_sockaddr_port(&bindaddr)); | |
6408 | 6404 | } |
6409 | 6405 | |
6410 | 6406 | if (!ast_sockaddr_port(&dialog->sa)) { |
10444 | 10440 | rtcp_mux_offered = has_media_level_attribute(iterator, req, "rtcp-mux"); |
10445 | 10441 | |
10446 | 10442 | /* Check for 'audio' media offer */ |
10447 | if (strncmp(m, "audio ", 6) == 0) { | |
10443 | if (p->rtp && strncmp(m, "audio ", 6) == 0) { | |
10448 | 10444 | if ((sscanf(m, "audio %30u/%30u %17s %n", &x, &numberofports, protocol, &len) == 3 && len > 0) || |
10449 | 10445 | (sscanf(m, "audio %30u %17s %n", &x, protocol, &len) == 2 && len > 0)) { |
10450 | 10446 | codecs = m + len; |
10554 | 10550 | } |
10555 | 10551 | } |
10556 | 10552 | /* Check for 'video' media offer */ |
10557 | else if (strncmp(m, "video ", 6) == 0) { | |
10553 | else if (p->vrtp && strncmp(m, "video ", 6) == 0) { | |
10558 | 10554 | if ((sscanf(m, "video %30u/%30u %17s %n", &x, &numberofports, protocol, &len) == 3 && len > 0) || |
10559 | 10555 | (sscanf(m, "video %30u %17s %n", &x, protocol, &len) == 2 && len > 0)) { |
10560 | 10556 | codecs = m + len; |
10633 | 10629 | } |
10634 | 10630 | } |
10635 | 10631 | /* Check for 'text' media offer */ |
10636 | else if (strncmp(m, "text ", 5) == 0) { | |
10632 | else if (p->trtp && strncmp(m, "text ", 5) == 0) { | |
10637 | 10633 | if ((sscanf(m, "text %30u/%30u %17s %n", &x, &numberofports, protocol, &len) == 3 && len > 0) || |
10638 | 10634 | (sscanf(m, "text %30u %17s %n", &x, protocol, &len) == 2 && len > 0)) { |
10639 | 10635 | codecs = m + len; |
15147 | 15143 | ast_string_field_set(mwi->call, peersecret, mwi->secret); |
15148 | 15144 | } |
15149 | 15145 | set_socket_transport(&mwi->call->socket, mwi->transport); |
15150 | mwi->call->socket.port = htons(mwi->portno); | |
15151 | 15146 | ast_sip_ouraddrfor(&mwi->call->sa, &mwi->call->ourip, mwi->call); |
15152 | 15147 | build_via(mwi->call); |
15153 | 15148 | |
16261 | 16256 | ast_string_field_set(p, exten, r->callback); |
16262 | 16257 | } |
16263 | 16258 | |
16264 | /* Set transport and port so the correct contact is built */ | |
16259 | /* Set transport so the correct contact is built */ | |
16265 | 16260 | set_socket_transport(&p->socket, r->transport); |
16266 | if (r->transport == AST_TRANSPORT_TLS || r->transport == AST_TRANSPORT_TCP) { | |
16267 | if (ast_sockaddr_isnull(&sip_tcp_desc.local_address)) { | |
16268 | ast_log(LOG_ERROR, | |
16269 | "TCP/TLS clients without server were not tested.\n"); | |
16270 | ast_log(LOG_ERROR, | |
16271 | "Please, follow-up and report at issue 28798.\n"); | |
16272 | } else { | |
16273 | p->socket.port = | |
16274 | htons(ast_sockaddr_port(&sip_tcp_desc.local_address)); | |
16275 | } | |
16276 | } | |
16277 | 16261 | |
16278 | 16262 | /* |
16279 | 16263 | check which address we should use in our contact header |
29425 | 29409 | |
29426 | 29410 | req.socket.fd = sipsock; |
29427 | 29411 | set_socket_transport(&req.socket, AST_TRANSPORT_UDP); |
29428 | req.socket.tcptls_session = NULL; | |
29429 | req.socket.port = htons(ast_sockaddr_port(&bindaddr)); | |
29412 | req.socket.tcptls_session = NULL; | |
29430 | 29413 | |
29431 | 29414 | handle_request_do(&req, &addr); |
29432 | 29415 | deinit_req(&req); |
32367 | 32350 | (peer->socket.type & AST_TRANSPORT_TLS) ? |
32368 | 32351 | STANDARD_TLS_PORT : STANDARD_SIP_PORT); |
32369 | 32352 | } |
32370 | if (!peer->socket.port) { | |
32371 | peer->socket.port = htons(((peer->socket.type & AST_TRANSPORT_TLS) ? STANDARD_TLS_PORT : STANDARD_SIP_PORT)); | |
32372 | } | |
32373 | 32353 | |
32374 | 32354 | if (realtime) { |
32375 | 32355 | int enablepoke = 1; |
789 | 789 | struct sip_socket { |
790 | 790 | enum ast_transport type; /*!< UDP, TCP or TLS */ |
791 | 791 | int fd; /*!< Filed descriptor, the actual socket */ |
792 | uint16_t port; | |
792 | uint16_t unused; /* since 1.6.2, retained not to change order/size of struct */ | |
793 | 793 | struct ast_tcptls_session_instance *tcptls_session; /* If tcp or tls, a socket manager */ |
794 | 794 | struct ast_websocket *ws_session; /*! If ws or wss, a WebSocket session */ |
795 | 795 | }; |
0 | 0 | [modules] |
1 | 1 | autoload = no |
2 | 2 | |
3 | ; This is a minimal module load. We are loading only the modules required for | |
4 | ; the Asterisk features used in the Super Awesome Company configuration. | |
3 | ; This is a minimal module load. We are loading only the modules | |
4 | ; required for the Asterisk features used in the "Super Awesome | |
5 | ; Company" configuration. | |
5 | 6 | |
6 | 7 | ; Applications |
7 | 8 | |
109 | 110 | load = res_sorcery_realtime.so |
110 | 111 | load = res_timing_timerfd.so |
111 | 112 | |
112 | ; Don't load res_hep.so and kin unless you are using hep monitoring in your network | |
113 | ; Do not load res_hep and kin unless you are using HEP monitoring | |
114 | ; <http://sipcapture.org> in your network. | |
113 | 115 | |
114 | 116 | noload = res_hep.so |
115 | 117 | noload = res_hep_pjsip.so |
0 | 0 | [directories](!) |
1 | astcachedir => /tmp | |
1 | 2 | astetcdir => /etc/asterisk |
2 | 3 | astmoddir => /usr/lib/asterisk/modules |
3 | 4 | astvarlibdir => /var/lib/asterisk |
23 | 23 | ; the "require" keyword. Asterisk will exit with a status code of 2 |
24 | 24 | ; if a required module does not load. |
25 | 25 | ; |
26 | ; require = chan_pjsip.so | |
26 | ;require = chan_pjsip.so | |
27 | 27 | ; |
28 | 28 | ; If you want you can combine with preload |
29 | 29 | ; preload-require = your_special_module.so |
34 | 34 | ; By default, load chan_oss only (automatically). |
35 | 35 | ; |
36 | 36 | noload => chan_alsa.so |
37 | noload => chan_console.so | |
37 | 38 | ;noload => chan_oss.so |
38 | noload => chan_console.so | |
39 | ||
39 | ; | |
40 | ; Do not load res_hep and kin unless you are using HEP monitoring | |
41 | ; <http://sipcapture.org> in your network. | |
42 | ; | |
40 | 43 | noload => res_hep.so |
41 | 44 | noload => res_hep_pjsip.so |
42 | 45 | noload => res_hep_rtcp.so |
43 | 43 | ; if rtp packets are dropped from one or both ends after a call is |
44 | 44 | ; connected. This option is set to 4 by default. |
45 | 45 | ; probation=8 |
46 | ; | |
47 | ; Enable sRTP replay protection. Buggy SIP user agents (UAs) reset the | |
48 | ; sequence number (RTP-SEQ) on a re-INVITE, for example, with Session Timers | |
49 | ; or on Call Hold/Resume, but keep the synchronization source (RTP-SSRC). If | |
50 | ; the new RTP-SEQ is higher than the previous one, the call continues if the | |
51 | ; roll-over counter (sRTP-ROC) is zero (the call lasted less than 22 minutes). | |
52 | ; In all other cases, the call faces one-way audio or even no audio at all. | |
53 | ; "replay check failed (index too old)" gets printed continuously. This is a | |
54 | ; software bug. You have to report this to the creator of that UA. Until it is | |
55 | ; fixed, you could disable sRTP replay protection (see RFC 3711 section 3.3.2). | |
56 | ; This option is enabled by default. | |
57 | ; srtpreplayprotection=yes | |
46 | 58 | ; |
47 | 59 | ; Whether to enable or disable ICE support. This option is enabled by default. |
48 | 60 | ; icesupport=false |
1042 | 1042 | MISDN_DIR |
1043 | 1043 | MISDN_INCLUDE |
1044 | 1044 | MISDN_LIB |
1045 | LUA_VERSIONS | |
1045 | 1046 | PBX_LUA |
1046 | 1047 | LUA_DIR |
1047 | 1048 | LUA_INCLUDE |
1286 | 1287 | BUILD_VENDOR |
1287 | 1288 | BUILD_CPU |
1288 | 1289 | BUILD_PLATFORM |
1290 | astcachedir | |
1289 | 1291 | astvarrundir |
1290 | 1292 | astlogdir |
1291 | 1293 | astspooldir |
1467 | 1469 | CXXCPP |
1468 | 1470 | JANSSON_CONFIGURE_OPTS |
1469 | 1471 | PJPROJECT_CONFIGURE_OPTS |
1472 | LUA_VERSIONS | |
1470 | 1473 | PKG_CONFIG |
1471 | 1474 | PKG_CONFIG_PATH |
1472 | 1475 | PKG_CONFIG_LIBDIR |
2225 | 2228 | Additional configure options to pass to bundled jansson |
2226 | 2229 | PJPROJECT_CONFIGURE_OPTS |
2227 | 2230 | Additional configure options to pass to bundled pjproject |
2231 | LUA_VERSIONS | |
2232 | A space separated list of target lua versions to test. | |
2228 | 2233 | PKG_CONFIG path to pkg-config utility |
2229 | 2234 | PKG_CONFIG_PATH |
2230 | 2235 | directories to add to pkg-config's search path |
4651 | 4656 | |
4652 | 4657 | # System default paths |
4653 | 4658 | astsbindir='${sbindir}' |
4659 | astcachedir='/tmp' | |
4654 | 4660 | astetcdir='${sysconfdir}/asterisk' |
4655 | 4661 | astheaderdir='${includedir}/asterisk' |
4656 | 4662 | astlibdir='${libdir}' |
4719 | 4725 | ;; |
4720 | 4726 | solaris*) |
4721 | 4727 | if test ${prefix} = 'NONE'; then |
4728 | astcachedir=/tmp | |
4722 | 4729 | astetcdir=/var/etc/asterisk |
4723 | 4730 | astsbindir=/opt/asterisk/sbin |
4724 | 4731 | astlibdir=/opt/asterisk/lib |
29511 | 29518 | |
29512 | 29519 | |
29513 | 29520 | |
29514 | for ver in 5.4 5.3 5.2 5.1; do | |
29521 | for ver in ${LUA_VERSIONS:-5.4 5.3 5.2 5.1}; do | |
29515 | 29522 | |
29516 | 29523 | if test "x${PBX_LUA}" != "x1" -a "${USE_LUA}" != "no"; then |
29517 | 29524 | pbxlibdir="" |
29622 | 29629 | done |
29623 | 29630 | |
29624 | 29631 | # Some distributions (like openSUSE and NetBSD) remove the 5.x suffix. |
29632 | if test "x${LUA_VERSIONS}" = "x"; then | |
29625 | 29633 | |
29626 | 29634 | if test "x${PBX_LUA}" != "x1" -a "${USE_LUA}" != "no"; then |
29627 | 29635 | pbxlibdir="" |
29718 | 29726 | fi |
29719 | 29727 | |
29720 | 29728 | |
29729 | fi | |
29721 | 29730 | |
29722 | 29731 | # Accept either RADIUS client library, their APIs are fully compatible, |
29723 | 29732 | # just different header filenames and different SONAMEs |
33 | 33 | |
34 | 34 | # System default paths |
35 | 35 | AC_SUBST([astsbindir], ['${sbindir}'])dnl |
36 | AC_SUBST([astcachedir], ['/tmp'])dnl | |
36 | 37 | AC_SUBST([astetcdir], ['${sysconfdir}/asterisk'])dnl |
37 | 38 | AC_SUBST([astheaderdir], ['${includedir}/asterisk'])dnl |
38 | 39 | AC_SUBST([astlibdir], ['${libdir}'])dnl |
97 | 98 | ;; |
98 | 99 | solaris*) |
99 | 100 | if test ${prefix} = 'NONE'; then |
101 | astcachedir=/tmp | |
100 | 102 | astetcdir=/var/etc/asterisk |
101 | 103 | astsbindir=/opt/asterisk/sbin |
102 | 104 | astlibdir=/opt/asterisk/lib |
508 | 510 | AST_EXT_LIB_SETUP([LIBXSLT], [LibXSLT], [libxslt]) |
509 | 511 | AST_EXT_LIB_SETUP_OPTIONAL([LIBXSLT_CLEANUP], [LibXSLT Library Cleanup Function], [LIBXSLT], [libxslt]) |
510 | 512 | AST_EXT_LIB_SETUP([LUA], [Lua], [lua]) |
513 | AC_ARG_VAR([LUA_VERSIONS],[A space separated list of target lua versions to test.]) | |
511 | 514 | AST_EXT_LIB_SETUP([MISDN], [mISDN user], [misdn]) |
512 | 515 | AST_EXT_LIB_SETUP([MYSQLCLIENT], [MySQL client], [mysqlclient]) |
513 | 516 | AST_EXT_LIB_SETUP([NBS], [Network Broadcast Sound], [nbs]) |
2552 | 2555 | fi |
2553 | 2556 | AST_EXT_LIB_CHECK([OPUSFILE], [opusfile], [op_open_callbacks], [opus/opusfile.h], [], [$__opus_include]) |
2554 | 2557 | |
2555 | for ver in 5.4 5.3 5.2 5.1; do | |
2558 | for ver in ${LUA_VERSIONS:-5.4 5.3 5.2 5.1}; do | |
2556 | 2559 | AST_EXT_LIB_CHECK([LUA], lua${ver}, [luaL_newstate], lua${ver}/lua.h, [-lm]) |
2557 | 2560 | if test "x${PBX_LUA}" = "x1" ; then |
2558 | 2561 | if test x"${LUA_DIR}" = x; then |
2565 | 2568 | done |
2566 | 2569 | |
2567 | 2570 | # Some distributions (like openSUSE and NetBSD) remove the 5.x suffix. |
2568 | AST_EXT_LIB_CHECK([LUA], [lua], [luaL_newstate], [lua.h], [-lm]) | |
2571 | if test "x${LUA_VERSIONS}" = "x"; then | |
2572 | AST_EXT_LIB_CHECK([LUA], [lua], [luaL_newstate], [lua.h], [-lm]) | |
2573 | fi | |
2569 | 2574 | |
2570 | 2575 | # Accept either RADIUS client library, their APIs are fully compatible, |
2571 | 2576 | # just different header filenames and different SONAMEs |
0 | 0 | [Unit] |
1 | 1 | Description=Asterisk PBX and telephony daemon. |
2 | 2 | After=network.target |
3 | #include these if asterisk need to bind to a specific IP (other than 0.0.0.0) | |
4 | #Wants=network-online.target | |
5 | #After=network-online.target network.target | |
3 | 6 | |
4 | 7 | [Service] |
5 | 8 | Type=notify |
6 | 9 | Environment=HOME=/var/lib/asterisk |
10 | #if systemd do not provide hostname and you need to use ${ENV(HOSTNAME)} | |
11 | #Environment=HOSTNAME=%H | |
7 | 12 | WorkingDirectory=/var/lib/asterisk |
8 | 13 | User=asterisk |
9 | 14 | Group=asterisk |
10 | 15 | ExecStart=/usr/sbin/asterisk -mqf -C /etc/asterisk/asterisk.conf |
11 | 16 | ExecReload=/usr/sbin/asterisk -rx 'core reload' |
17 | #if /var/run is a tmpfs, this will create /var/run/asterisk on start | |
18 | #RuntimeDirectory=asterisk | |
12 | 19 | |
13 | 20 | #Nice=0 |
14 | 21 | #UMask=0002 |
0 | Subject: Messaging | |
1 | ||
2 | In order to reduce the amount of AMI and ARI events generated, | |
3 | the global "Message/ast_msg_queue" channel can be set to suppress | |
4 | it's normal channel housekeeping events such as "Newexten", | |
5 | "VarSet", etc. This can greatly reduce load on the manager | |
6 | and ARI applications when the Digium Phone Module for Asterisk | |
7 | is in use. To enable, set "hide_messaging_ami_events" in | |
8 | asterisk.conf to "yes" In Asterisk versions <18, the default | |
9 | is "no" preserving existing behavior. Beginning with | |
10 | Asterisk 18, the option will default to "yes". |
0 | Subject: res_srtp | |
1 | ||
2 | SRTP replay protection has been added to res_srtp and | |
3 | a new configuration option "srtpreplayprotection" has | |
4 | been added to the rtp.conf config file. For security | |
5 | reasons, the default setting is "yes". Buggy clients | |
6 | may not handle this correctly which could result in | |
7 | no, or one way, audio and Asterisk error messages like | |
8 | "replay check failed". |
0 | Subject: res_srtp | |
1 | ||
2 | SRTP replay protection has been added to res_srtp and | |
3 | a new configuration option "srtpreplayprotection" has | |
4 | been added to the rtp.conf config file. For security | |
5 | reasons, the default setting is "yes". Buggy clients | |
6 | may not handle this correctly which could result in | |
7 | no, or one way, audio and Asterisk error messages like | |
8 | "replay check failed". |
109 | 109 | static void lock_free(void *data); |
110 | 110 | static void lock_fixup(void *data, struct ast_channel *oldchan, struct ast_channel *newchan); |
111 | 111 | static int unloading = 0; |
112 | static pthread_t broker_tid = AST_PTHREADT_NULL; | |
113 | 112 | |
114 | 113 | static const struct ast_datastore_info lock_info = { |
115 | 114 | .type = "MUTEX", |
123 | 122 | ast_cond_t cond; |
124 | 123 | /*! count is needed so if a recursive mutex exits early, we know how many times to unlock it. */ |
125 | 124 | unsigned int count; |
126 | /*! Container of requesters for the named lock */ | |
127 | struct ao2_container *requesters; | |
125 | /*! Count of waiting of requesters for the named lock */ | |
126 | unsigned int requesters; | |
128 | 127 | /*! who owns us */ |
129 | 128 | struct ast_channel *owner; |
130 | 129 | /*! name of the lock */ |
146 | 145 | while ((clframe = AST_LIST_REMOVE_HEAD(oldlist, list))) { |
147 | 146 | /* Only unlock if we own the lock */ |
148 | 147 | if (clframe->channel == clframe->lock_frame->owner) { |
148 | ast_mutex_lock(&clframe->lock_frame->mutex); | |
149 | 149 | clframe->lock_frame->count = 0; |
150 | 150 | clframe->lock_frame->owner = NULL; |
151 | ast_cond_signal(&clframe->lock_frame->cond); | |
152 | ast_mutex_unlock(&clframe->lock_frame->mutex); | |
151 | 153 | } |
152 | 154 | ast_free(clframe); |
153 | 155 | } |
172 | 174 | if (clframe->lock_frame->owner == oldchan) { |
173 | 175 | clframe->lock_frame->owner = newchan; |
174 | 176 | } |
175 | /* We don't move requesters, because the thread stack is different */ | |
176 | 177 | clframe->channel = newchan; |
177 | 178 | } |
178 | 179 | AST_LIST_UNLOCK(list); |
179 | } | |
180 | ||
181 | static void *lock_broker(void *unused) | |
182 | { | |
183 | struct lock_frame *frame; | |
184 | struct timespec forever = { 1000000, 0 }; | |
185 | for (;;) { | |
186 | int found_requester = 0; | |
187 | ||
188 | /* Test for cancel outside of the lock */ | |
189 | pthread_testcancel(); | |
190 | AST_LIST_LOCK(&locklist); | |
191 | ||
192 | AST_LIST_TRAVERSE(&locklist, frame, entries) { | |
193 | if (ao2_container_count(frame->requesters)) { | |
194 | found_requester++; | |
195 | ast_mutex_lock(&frame->mutex); | |
196 | if (!frame->owner) { | |
197 | ast_cond_signal(&frame->cond); | |
198 | } | |
199 | ast_mutex_unlock(&frame->mutex); | |
200 | } | |
201 | } | |
202 | ||
203 | AST_LIST_UNLOCK(&locklist); | |
204 | pthread_testcancel(); | |
205 | ||
206 | /* If there are no requesters, then wait for a signal */ | |
207 | if (!found_requester) { | |
208 | nanosleep(&forever, NULL); | |
209 | } else { | |
210 | sched_yield(); | |
211 | } | |
212 | } | |
213 | /* Not reached */ | |
214 | return NULL; | |
215 | } | |
216 | ||
217 | static int ast_channel_cmp_cb(void *obj, void *arg, int flags) | |
218 | { | |
219 | struct ast_channel *chan = obj, *cmp_args = arg; | |
220 | return strcasecmp(ast_channel_name(chan), ast_channel_name(cmp_args)) ? 0 : CMP_MATCH; | |
221 | 180 | } |
222 | 181 | |
223 | 182 | static int get_lock(struct ast_channel *chan, char *lockname, int trylock) |
289 | 248 | AST_LIST_UNLOCK(&locklist); |
290 | 249 | return -1; |
291 | 250 | } |
292 | current->requesters = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, | |
293 | NULL, ast_channel_cmp_cb); | |
294 | if (!current->requesters) { | |
295 | ast_mutex_destroy(¤t->mutex); | |
296 | ast_cond_destroy(¤t->cond); | |
297 | ast_free(current); | |
298 | AST_LIST_UNLOCK(&locklist); | |
299 | return -1; | |
300 | } | |
251 | current->requesters = 0; | |
301 | 252 | AST_LIST_INSERT_TAIL(&locklist, current, entries); |
302 | 253 | } |
254 | /* Add to requester list */ | |
255 | ast_mutex_lock(¤t->mutex); | |
256 | current->requesters++; | |
257 | ast_mutex_unlock(¤t->mutex); | |
303 | 258 | AST_LIST_UNLOCK(&locklist); |
304 | 259 | |
305 | 260 | /* Found lock or created one - now find or create the corresponding link in the channel */ |
336 | 291 | * the same amount, before we'll release this one. |
337 | 292 | */ |
338 | 293 | if (current->owner == chan) { |
294 | /* We're not a requester, we already have it */ | |
295 | ast_mutex_lock(¤t->mutex); | |
296 | current->requesters--; | |
297 | ast_mutex_unlock(¤t->mutex); | |
339 | 298 | current->count++; |
340 | 299 | return 0; |
341 | 300 | } |
342 | ||
343 | /* Okay, we have both frames, so now we need to try to lock. | |
344 | * | |
345 | * Locking order: always lock locklist first. We need the | |
346 | * locklist lock because the broker thread counts whether | |
347 | * there are requesters with the locklist lock held, and we | |
348 | * need to hold it, so that when we send our signal, below, | |
349 | * to wake up the broker thread, it definitely will see that | |
350 | * a requester exists at that point in time. Otherwise, we | |
351 | * could add to the requesters after it has already seen that | |
352 | * that lock is unoccupied and wait forever for another signal. | |
353 | */ | |
354 | AST_LIST_LOCK(&locklist); | |
355 | ast_mutex_lock(¤t->mutex); | |
356 | /* Add to requester list */ | |
357 | ao2_link(current->requesters, chan); | |
358 | pthread_kill(broker_tid, SIGURG); | |
359 | AST_LIST_UNLOCK(&locklist); | |
360 | 301 | |
361 | 302 | /* Wait up to three seconds from now for LOCK. */ |
362 | 303 | now = ast_tvnow(); |
363 | 304 | timeout.tv_sec = now.tv_sec + 3; |
364 | 305 | timeout.tv_nsec = now.tv_usec * 1000; |
365 | 306 | |
366 | if (!current->owner | |
367 | || (!trylock | |
368 | && !(res = ast_cond_timedwait(¤t->cond, ¤t->mutex, &timeout)))) { | |
369 | res = 0; | |
307 | ast_mutex_lock(¤t->mutex); | |
308 | ||
309 | res = 0; | |
310 | while (!trylock && !res && current->owner) { | |
311 | res = ast_cond_timedwait(¤t->cond, ¤t->mutex, &timeout); | |
312 | } | |
313 | if (current->owner) { | |
314 | /* timeout; | |
315 | * trylock; or | |
316 | * cond_timedwait failed. | |
317 | * | |
318 | * either way, we fail to obtain the lock. | |
319 | */ | |
320 | res = -1; | |
321 | } else { | |
370 | 322 | current->owner = chan; |
371 | 323 | current->count++; |
372 | } else { | |
373 | res = -1; | |
324 | res = 0; | |
374 | 325 | } |
375 | 326 | /* Remove from requester list */ |
376 | ao2_unlink(current->requesters, chan); | |
327 | current->requesters--; | |
328 | if (res && unloading) | |
329 | ast_cond_signal(¤t->cond); | |
377 | 330 | ast_mutex_unlock(¤t->mutex); |
378 | 331 | |
379 | 332 | return res; |
421 | 374 | } |
422 | 375 | |
423 | 376 | if (--clframe->lock_frame->count == 0) { |
377 | ast_mutex_lock(&clframe->lock_frame->mutex); | |
424 | 378 | clframe->lock_frame->owner = NULL; |
379 | ast_cond_signal(&clframe->lock_frame->cond); | |
380 | ast_mutex_unlock(&clframe->lock_frame->mutex); | |
425 | 381 | } |
426 | 382 | |
427 | 383 | ast_copy_string(buf, "1", len); |
477 | 433 | /* Module flag */ |
478 | 434 | unloading = 1; |
479 | 435 | |
480 | AST_LIST_LOCK(&locklist); | |
481 | while ((current = AST_LIST_REMOVE_HEAD(&locklist, entries))) { | |
482 | /* If any locks are currently in use, then we cannot unload this module */ | |
483 | if (current->owner || ao2_container_count(current->requesters)) { | |
484 | /* Put it back */ | |
485 | AST_LIST_INSERT_HEAD(&locklist, current, entries); | |
486 | AST_LIST_UNLOCK(&locklist); | |
487 | unloading = 0; | |
488 | return -1; | |
489 | } | |
490 | ast_mutex_destroy(¤t->mutex); | |
491 | ao2_ref(current->requesters, -1); | |
492 | ast_free(current); | |
493 | } | |
494 | ||
495 | /* No locks left, unregister functions */ | |
436 | /* Make it impossible for new requesters to be added | |
437 | * NOTE: channels could already be in get_lock() */ | |
496 | 438 | ast_custom_function_unregister(&lock_function); |
497 | 439 | ast_custom_function_unregister(&trylock_function); |
440 | ||
441 | AST_LIST_LOCK(&locklist); | |
442 | AST_LIST_TRAVERSE(&locklist, current, entries) { | |
443 | ast_mutex_lock(¤t->mutex); | |
444 | while (current->owner || current->requesters) { | |
445 | /* either the mutex is locked, or other parties are currently in get_lock, | |
446 | * we need to wait for all of those to clear first */ | |
447 | ast_cond_wait(¤t->cond, ¤t->mutex); | |
448 | } | |
449 | ast_mutex_unlock(¤t->mutex); | |
450 | /* At this point we know: | |
451 | * 1. the lock has been released, | |
452 | * 2. there are no requesters (nor should any be able to sneak in). | |
453 | */ | |
454 | ast_mutex_destroy(¤t->mutex); | |
455 | ast_cond_destroy(¤t->cond); | |
456 | ast_free(current); | |
457 | } | |
458 | AST_LIST_UNLOCK(&locklist); | |
459 | AST_LIST_HEAD_DESTROY(&locklist); | |
460 | ||
461 | /* At this point we can safely stop access to UNLOCK */ | |
498 | 462 | ast_custom_function_unregister(&unlock_function); |
499 | ||
500 | if (broker_tid != AST_PTHREADT_NULL) { | |
501 | pthread_cancel(broker_tid); | |
502 | pthread_kill(broker_tid, SIGURG); | |
503 | pthread_join(broker_tid, NULL); | |
504 | } | |
505 | ||
506 | AST_LIST_UNLOCK(&locklist); | |
507 | 463 | |
508 | 464 | return 0; |
509 | 465 | } |
514 | 470 | res |= ast_custom_function_register_escalating(&trylock_function, AST_CFE_READ); |
515 | 471 | res |= ast_custom_function_register_escalating(&unlock_function, AST_CFE_READ); |
516 | 472 | |
517 | if (ast_pthread_create_background(&broker_tid, NULL, lock_broker, NULL)) { | |
518 | ast_log(LOG_ERROR, "Failed to start lock broker thread. Unloading func_lock module.\n"); | |
519 | broker_tid = AST_PTHREADT_NULL; | |
520 | unload_module(); | |
521 | return AST_MODULE_LOAD_DECLINE; | |
522 | } | |
523 | ||
524 | 473 | return res; |
525 | 474 | } |
526 | 475 |
1946 | 1946 | .load = load_module, |
1947 | 1947 | .unload = unload_module, |
1948 | 1948 | .reload = reload, |
1949 | .requires = "res_odbc", | |
1949 | 1950 | ); |
518 | 518 | .support_level = AST_MODULE_SUPPORT_CORE, |
519 | 519 | .load = load_module, |
520 | 520 | .unload = unload_module, |
521 | .requires = "app_chanspy,func_cut,func_groupcount,func_uri", | |
521 | 522 | ); |
114 | 114 | }; |
115 | 115 | |
116 | 116 | /*! \brief Check if AMI is enabled */ |
117 | int check_manager_enabled(void); | |
117 | int ast_manager_check_enabled(void); | |
118 | 118 | |
119 | 119 | /*! \brief Check if AMI/HTTP is enabled */ |
120 | int check_webmanager_enabled(void); | |
120 | int ast_webmanager_check_enabled(void); | |
121 | 121 | |
122 | 122 | /*! Add a custom hook to be called when an event is fired |
123 | 123 | \param hook struct manager_custom_hook object to add |
17 | 17 | #ifndef _ASTERISK_PATHS_H |
18 | 18 | #define _ASTERISK_PATHS_H |
19 | 19 | |
20 | extern const char *ast_config_AST_CACHE_DIR; | |
20 | 21 | extern const char *ast_config_AST_CONFIG_DIR; |
21 | 22 | extern const char *ast_config_AST_CONFIG_FILE; |
22 | 23 | extern const char *ast_config_AST_MODULE_DIR; |
533 | 533 | |
534 | 534 | ast_cli(a->fd, "\n* Subsystems\n"); |
535 | 535 | ast_cli(a->fd, " -------------\n"); |
536 | ast_cli(a->fd, " Manager (AMI): %s\n", check_manager_enabled() ? "Enabled" : "Disabled"); | |
537 | ast_cli(a->fd, " Web Manager (AMI/HTTP): %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled"); | |
536 | ast_cli(a->fd, " Manager (AMI): %s\n", ast_manager_check_enabled() ? "Enabled" : "Disabled"); | |
537 | ast_cli(a->fd, " Web Manager (AMI/HTTP): %s\n", ast_webmanager_check_enabled() ? "Enabled" : "Disabled"); | |
538 | 538 | ast_cli(a->fd, " Call data records: %s\n", ast_cdr_is_enabled() ? "Enabled" : "Disabled"); |
539 | 539 | ast_cli(a->fd, " Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled"); |
540 | 540 |
2637 | 2637 | &props->original_transferer_colp); |
2638 | 2638 | ast_party_id_reset(&ast_channel_connected(props->recall_target)->priv); |
2639 | 2639 | |
2640 | common_recall_channel_setup(props->recall_target, props->recall_target); | |
2640 | common_recall_channel_setup(props->recall_target, props->transferer); | |
2641 | 2641 | ast_channel_unlock(props->recall_target); |
2642 | 2642 | ast_channel_unlock(props->transferer); |
2643 | 2643 |
72 | 72 | #include "asterisk/json.h" |
73 | 73 | #include "asterisk/file.h" |
74 | 74 | #include "asterisk/module.h" |
75 | #include "asterisk/paths.h" | |
75 | 76 | |
76 | 77 | /*! \brief Number of buckets for the container of schemes */ |
77 | 78 | #define SCHEME_BUCKETS 53 |
898 | 899 | { |
899 | 900 | int fd; |
900 | 901 | |
901 | ast_copy_string(file->path, "/tmp/bucket-XXXXXX", sizeof(file->path)); | |
902 | snprintf(file->path, sizeof(file->path), "%s/bucket-XXXXXX", ast_config_AST_CACHE_DIR); | |
902 | 903 | |
903 | 904 | fd = mkstemp(file->path); |
904 | 905 | if (fd < 0) { |
1671 | 1671 | return NULL; |
1672 | 1672 | } |
1673 | 1673 | |
1674 | /* Automatically add a newline to format strings that don't have one */ | |
1675 | if (!ast_ends_with(ast_str_buffer(buf), "\n")) { | |
1676 | ast_str_append(&buf, 0, "\n"); | |
1677 | } | |
1678 | ||
1674 | 1679 | /* Create a new logging message */ |
1675 | 1680 | if (!(logmsg = ast_calloc_with_stringfields(1, struct logmsg, res + 128))) { |
1676 | 1681 | return NULL; |
1945 | 1945 | AST_RWLIST_UNLOCK(&manager_hooks); |
1946 | 1946 | } |
1947 | 1947 | |
1948 | int check_manager_enabled(void) | |
1948 | int ast_manager_check_enabled(void) | |
1949 | 1949 | { |
1950 | 1950 | return manager_enabled; |
1951 | 1951 | } |
1952 | 1952 | |
1953 | int check_webmanager_enabled(void) | |
1953 | int ast_webmanager_check_enabled(void) | |
1954 | 1954 | { |
1955 | 1955 | return (webmanager_enabled && manager_enabled); |
1956 | 1956 | } |
6308 | 6308 | ast_option_maxfiles, |
6309 | 6309 | AST_CLI_YESNO(ast_realtime_enabled()), |
6310 | 6310 | AST_CLI_YESNO(ast_cdr_is_enabled()), |
6311 | AST_CLI_YESNO(check_webmanager_enabled()) | |
6311 | AST_CLI_YESNO(ast_webmanager_check_enabled()) | |
6312 | 6312 | ); |
6313 | 6313 | return 0; |
6314 | 6314 | } |
824 | 824 | struct stasis_message *message) |
825 | 825 | { |
826 | 826 | RAII_VAR(struct ast_str *, spyer_channel_string, NULL, ast_free); |
827 | RAII_VAR(struct ast_str *, spyee_channel_string, NULL, ast_free); | |
827 | 828 | struct ast_channel_snapshot *spyer; |
829 | struct ast_channel_snapshot *spyee; | |
830 | const char *spyee_info = ""; | |
828 | 831 | struct ast_multi_channel_blob *payload = stasis_message_data(message); |
829 | 832 | |
830 | 833 | spyer = ast_multi_channel_blob_get_channel(payload, "spyer_channel"); |
831 | 834 | if (!spyer) { |
832 | ast_log(AST_LOG_WARNING, "Received ChanSpy Start event with no spyer channel!\n"); | |
835 | ast_log(AST_LOG_WARNING, "Received ChanSpy Stop event with no spyer channel!\n"); | |
833 | 836 | return; |
834 | 837 | } |
835 | 838 | |
838 | 841 | return; |
839 | 842 | } |
840 | 843 | |
844 | spyee = ast_multi_channel_blob_get_channel(payload, "spyee_channel"); | |
845 | if (spyee) { | |
846 | spyee_channel_string = ast_manager_build_channel_state_string_prefix(spyee, "Spyee"); | |
847 | if (spyee_channel_string) { | |
848 | spyee_info = ast_str_buffer(spyee_channel_string); | |
849 | } | |
850 | } | |
851 | ||
841 | 852 | manager_event(EVENT_FLAG_CALL, "ChanSpyStop", |
842 | "%s", | |
843 | ast_str_buffer(spyer_channel_string)); | |
853 | "%s%s", | |
854 | ast_str_buffer(spyer_channel_string), | |
855 | spyee_info); | |
844 | 856 | } |
845 | 857 | |
846 | 858 | static void channel_chanspy_start_cb(void *data, struct stasis_subscription *sub, |
97 | 97 | char ast_defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE; |
98 | 98 | |
99 | 99 | struct _cfg_paths { |
100 | char cache_dir[PATH_MAX]; | |
100 | 101 | char config_dir[PATH_MAX]; |
101 | 102 | char module_dir[PATH_MAX]; |
102 | 103 | char spool_dir[PATH_MAX]; |
124 | 125 | }; |
125 | 126 | |
126 | 127 | static struct _cfg_paths cfg_paths = { |
128 | .cache_dir = DEFAULT_CACHE_DIR, | |
127 | 129 | .config_dir = DEFAULT_CONFIG_DIR, |
128 | 130 | .module_dir = DEFAULT_MODULE_DIR, |
129 | 131 | .spool_dir = DEFAULT_SPOOL_DIR, |
144 | 146 | .ctl_file = "asterisk.ctl", |
145 | 147 | }; |
146 | 148 | |
149 | const char *ast_config_AST_CACHE_DIR = cfg_paths.cache_dir; | |
147 | 150 | const char *ast_config_AST_CONFIG_DIR = cfg_paths.config_dir; |
148 | 151 | const char *ast_config_AST_CONFIG_FILE = cfg_paths.config_file; |
149 | 152 | const char *ast_config_AST_MODULE_DIR = cfg_paths.module_dir; |
253 | 256 | } |
254 | 257 | |
255 | 258 | for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) { |
256 | if (!strcasecmp(v->name, "astetcdir")) { | |
259 | if (!strcasecmp(v->name, "astcachedir")) { | |
260 | ast_copy_string(cfg_paths.cache_dir, v->value, sizeof(cfg_paths.cache_dir)); | |
261 | } else if (!strcasecmp(v->name, "astetcdir")) { | |
257 | 262 | ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir)); |
258 | 263 | } else if (!strcasecmp(v->name, "astspooldir")) { |
259 | 264 | ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir)); |
326 | 326 | s = ast_str_buffer(*str); |
327 | 327 | } else if (!strcmp(var, "SYSTEMNAME")) { |
328 | 328 | s = ast_config_AST_SYSTEM_NAME; |
329 | } else if (!strcmp(var, "ASTCACHEDIR")) { | |
330 | s = ast_config_AST_CACHE_DIR; | |
329 | 331 | } else if (!strcmp(var, "ASTETCDIR")) { |
330 | 332 | s = ast_config_AST_CONFIG_DIR; |
331 | 333 | } else if (!strcmp(var, "ASTMODDIR")) { |
96 | 96 | ASTMANDIR = @astmandir@ |
97 | 97 | astvarlibdir = @astvarlibdir@ |
98 | 98 | ASTVARLIBDIR = @astvarlibdir@ |
99 | ASTCACHEDIR = @astcachedir@ | |
99 | 100 | ASTDATADIR = @astdatadir@ |
100 | 101 | ASTDBDIR = @astdbdir@ |
101 | 102 | ASTKEYDIR = @astkeydir@ |
250 | 250 | .support_level = AST_MODULE_SUPPORT_EXTENDED, |
251 | 251 | .load = load_module, |
252 | 252 | .unload = unload_module, |
253 | .requires = "res_hep,res_pjsip", | |
253 | .requires = "res_pjsip,res_pjsip_session,res_hep", | |
254 | 254 | ); |
214 | 214 | curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_header_callback); |
215 | 215 | curl_easy_setopt(curl, CURLOPT_USERAGENT, GLOBAL_USERAGENT); |
216 | 216 | curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); |
217 | curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 8); | |
217 | 218 | curl_easy_setopt(curl, CURLOPT_URL, ast_sorcery_object_get_id(cb_data->bucket_file)); |
218 | 219 | curl_easy_setopt(curl, CURLOPT_HEADERDATA, cb_data); |
219 | 220 |
1612 | 1612 | char *category = NULL; |
1613 | 1613 | size_t entry_count = 0; |
1614 | 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, ""); | |
1620 | if (dup) { | |
1621 | entry_count++; | |
1622 | ast_variable_list_append(&var, dup); | |
1615 | /* entries is NULL if there are no results */ | |
1616 | if (entries) { | |
1617 | while ((category = ast_category_browse(entries, category))) { | |
1618 | const char *entry = ast_variable_retrieve(entries, category, "entry"); | |
1619 | ||
1620 | if (entry) { | |
1621 | struct ast_variable *dup = ast_variable_new("entry", entry, ""); | |
1622 | if (dup) { | |
1623 | entry_count++; | |
1624 | ast_variable_list_append(&var, dup); | |
1625 | } | |
1623 | 1626 | } |
1624 | 1627 | } |
1625 | } | |
1626 | ast_config_destroy(entries); | |
1628 | ast_config_destroy(entries); | |
1629 | } | |
1627 | 1630 | |
1628 | 1631 | if (entry_count == 0) { |
1629 | 1632 | /* Behave as though this class doesn't exist */ |
1142 | 1142 | .unload = unload_module, |
1143 | 1143 | .reload = reload, |
1144 | 1144 | .load_pri = AST_MODPRI_REALTIME_DEPEND, |
1145 | .requires = "res_odbc_transaction", | |
1145 | 1146 | ); |
33 | 33 | |
34 | 34 | /*** MODULEINFO |
35 | 35 | <depend>pjproject</depend> |
36 | <depend>res_sorcery_config</depend> | |
36 | 37 | <support_level>core</support_level> |
37 | 38 | ***/ |
38 | 39 | |
766 | 767 | .unload = unload_module, |
767 | 768 | .reload = reload_module, |
768 | 769 | .load_pri = AST_MODPRI_CHANNEL_DEPEND - 6, |
770 | .requires = "res_sorcery_config", | |
769 | 771 | ); |
93 | 93 | */ |
94 | 94 | |
95 | 95 | #define DEFAULT_LANGUAGE "en" |
96 | #define DEFAULT_ENCODING "text/plain" | |
96 | #define DEFAULT_ENCODING "identity" | |
97 | 97 | |
98 | 98 | /*! \brief These are the number of buckets to store AORs in */ |
99 | 99 | #ifdef LOW_MEMORY |
5428 | 5428 | .unload = unload_module, |
5429 | 5429 | .reload = reload_module, |
5430 | 5430 | .load_pri = AST_MODPRI_CHANNEL_DEPEND - 5, |
5431 | .requires = "dnsmgr,res_pjproject", | |
5431 | .requires = "dnsmgr,res_pjproject,res_sorcery_config,res_sorcery_memory,res_sorcery_astdb", | |
5432 | 5432 | .optional_modules = "res_statsd", |
5433 | 5433 | ); |
119 | 119 | static int add_supported(pjsip_tx_data *tdata) |
120 | 120 | { |
121 | 121 | pjsip_supported_hdr *hdr; |
122 | unsigned int i; | |
122 | 123 | |
123 | 124 | hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL); |
124 | 125 | if (!hdr) { |
129 | 130 | } |
130 | 131 | |
131 | 132 | pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr); |
133 | } | |
134 | ||
135 | /* Asterisk can send multiple "181 Call forwarded" in a single session, | |
136 | * we might have already modified Supported before | |
137 | */ | |
138 | for (i = 0; i < hdr->count; ++i) { | |
139 | if (pj_stricmp(&hdr->values[i], &HISTINFO_SUPPORTED_NAME) == 0) { | |
140 | return 0; | |
141 | } | |
142 | } | |
143 | ||
144 | if (hdr->count >= PJSIP_GENERIC_ARRAY_MAX_COUNT) { | |
145 | return -1; | |
132 | 146 | } |
133 | 147 | |
134 | 148 | /* add on to the existing Supported header */ |
33 | 33 | #include "asterisk/res_pjsip_session.h" |
34 | 34 | |
35 | 35 | #define DEFAULT_LANGUAGE "en" |
36 | #define DEFAULT_ENCODING "text/plain" | |
36 | #define DEFAULT_ENCODING "identity" | |
37 | 37 | |
38 | 38 | static int options_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata) |
39 | 39 | { |
65 | 65 | return; |
66 | 66 | } |
67 | 67 | |
68 | static void rewrite_uri(pjsip_rx_data *rdata, pjsip_sip_uri *uri) | |
68 | static void rewrite_uri(pjsip_rx_data *rdata, pjsip_sip_uri *uri, pj_pool_t *pool) | |
69 | 69 | { |
70 | 70 | |
71 | 71 | if (pj_strcmp2(&uri->host, rdata->pkt_info.src_name) != 0) { |
72 | 72 | save_orig_contact_host(rdata, uri); |
73 | 73 | } |
74 | 74 | |
75 | pj_cstr(&uri->host, rdata->pkt_info.src_name); | |
75 | pj_strdup2(pool, &uri->host, rdata->pkt_info.src_name); | |
76 | 76 | uri->port = rdata->pkt_info.src_port; |
77 | 77 | if (!strcasecmp("WSS", rdata->tp_info.transport->type_name)) { |
78 | 78 | /* WSS is special, we don't want to overwrite the URI at all as it needs to be ws */ |
150 | 150 | |
151 | 151 | if (rr) { |
152 | 152 | uri = pjsip_uri_get_uri(&rr->name_addr); |
153 | rewrite_uri(rdata, uri); | |
153 | rewrite_uri(rdata, uri, rdata->tp_info.pool); | |
154 | 154 | res = 0; |
155 | 155 | } |
156 | 156 | |
157 | 157 | if (dlg && !pj_list_empty(&dlg->route_set) && !dlg->route_set_frozen) { |
158 | 158 | pjsip_routing_hdr *route = dlg->route_set.next; |
159 | 159 | uri = pjsip_uri_get_uri(&route->name_addr); |
160 | rewrite_uri(rdata, uri); | |
160 | rewrite_uri(rdata, uri, dlg->pool); | |
161 | 161 | res = 0; |
162 | 162 | } |
163 | 163 | |
183 | 183 | if (contact && !contact->star && (PJSIP_URI_SCHEME_IS_SIP(contact->uri) || PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) { |
184 | 184 | pjsip_sip_uri *uri = pjsip_uri_get_uri(contact->uri); |
185 | 185 | |
186 | rewrite_uri(rdata, uri); | |
186 | rewrite_uri(rdata, uri, rdata->tp_info.pool); | |
187 | 187 | |
188 | 188 | if (dlg && pj_list_empty(&dlg->route_set) && (!dlg->remote.contact |
189 | 189 | || pjsip_uri_cmp(PJSIP_URI_IN_REQ_URI, dlg->remote.contact->uri, contact->uri))) { |
342 | 342 | */ |
343 | 343 | pjsip_tx_data *last_tdata; |
344 | 344 | /*! \brief Timer entry for retrying on temporal responses */ |
345 | struct ast_sip_sched_task *sched_task; | |
345 | pj_timer_entry timer; | |
346 | 346 | /*! \brief Optional line parameter placed into Contact */ |
347 | 347 | char line[LINE_PARAMETER_SIZE]; |
348 | 348 | /*! \brief Current number of retries */ |
373 | 373 | char *transport_name; |
374 | 374 | /*! \brief The name of the registration sorcery object */ |
375 | 375 | 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; | |
382 | 376 | }; |
383 | 377 | |
384 | 378 | /*! \brief Outbound registration state information (persists for lifetime that registration should exist) */ |
517 | 511 | return NULL; |
518 | 512 | } |
519 | 513 | |
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); | |
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); | |
522 | 516 | |
523 | 517 | return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", state->registration->endpoint); |
524 | 518 | } |
530 | 524 | /*! \brief Helper function which cancels the timer on a client */ |
531 | 525 | static void cancel_registration(struct sip_outbound_registration_client_state *client_state) |
532 | 526 | { |
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; | |
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); | |
537 | 531 | } |
538 | 532 | } |
539 | 533 | |
550 | 544 | callback_invoked = ast_threadstorage_get(®ister_callback_invoked, sizeof(int)); |
551 | 545 | if (!callback_invoked) { |
552 | 546 | 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); | |
555 | 547 | return PJ_ENOMEM; |
556 | 548 | } |
557 | 549 | *callback_invoked = 0; |
579 | 571 | * drop the references we just added |
580 | 572 | */ |
581 | 573 | 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); | |
584 | 574 | pjsip_tx_data_dec_ref(tdata); |
585 | 575 | ao2_ref(client_state, -1); |
586 | 576 | return status; |
602 | 592 | /*! \brief Callback function for registering */ |
603 | 593 | static int handle_client_registration(void *data) |
604 | 594 | { |
605 | struct sip_outbound_registration_client_state *client_state = data; | |
595 | RAII_VAR(struct sip_outbound_registration_client_state *, client_state, data, ao2_cleanup); | |
606 | 596 | pjsip_tx_data *tdata; |
607 | 597 | |
608 | if (client_state->status == SIP_REGISTRATION_STOPPED) { | |
598 | if (client_state->status == SIP_REGISTRATION_STOPPED | |
599 | || pjsip_regc_register(client_state->client, PJ_FALSE, &tdata) != PJ_SUCCESS) { | |
609 | 600 | return 0; |
610 | 601 | } |
611 | 602 | |
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); | |
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 | } | |
622 | 612 | |
623 | 613 | if (client_state->support_path) { |
624 | 614 | pjsip_supported_hdr *hdr; |
615 | int i; | |
625 | 616 | |
626 | 617 | hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL); |
627 | 618 | if (!hdr) { |
629 | 620 | hdr = pjsip_supported_hdr_create(tdata->pool); |
630 | 621 | if (!hdr) { |
631 | 622 | pjsip_tx_data_dec_ref(tdata); |
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; | |
623 | return -1; | |
635 | 624 | } |
636 | 625 | |
637 | 626 | pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr); |
638 | 627 | } |
639 | 628 | |
629 | /* Don't add the value if it's already there */ | |
630 | for (i = 0; i < hdr->count; ++i) { | |
631 | if (pj_stricmp(&hdr->values[i], &PATH_NAME) == 0) { | |
632 | return 1; | |
633 | } | |
634 | } | |
635 | ||
636 | if (hdr->count >= PJSIP_GENERIC_ARRAY_MAX_COUNT) { | |
637 | return 0; | |
638 | } | |
639 | ||
640 | 640 | /* add on to the existing Supported header */ |
641 | 641 | pj_strassign(&hdr->values[hdr->count++], &PATH_NAME); |
642 | 642 | } |
646 | 646 | return 0; |
647 | 647 | } |
648 | 648 | |
649 | /*! \brief Timer callback function, used just for registrations */ | |
650 | static void sip_outbound_registration_timer_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry) | |
651 | { | |
652 | struct sip_outbound_registration_client_state *client_state = entry->user_data; | |
653 | ||
654 | entry->id = 0; | |
655 | ||
656 | /* | |
657 | * Transfer client_state reference to serializer task so the | |
658 | * nominal path will not dec the client_state ref in this | |
659 | * pjproject callback thread. | |
660 | */ | |
661 | if (ast_sip_push_task(client_state->serializer, handle_client_registration, client_state)) { | |
662 | ast_log(LOG_WARNING, "Scheduled outbound registration could not be executed.\n"); | |
663 | ao2_ref(client_state, -1); | |
664 | } | |
665 | } | |
666 | ||
649 | 667 | /*! \brief Helper function which sets up the timer to re-register in a specific amount of time */ |
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); | |
668 | static void schedule_registration(struct sip_outbound_registration_client_state *client_state, unsigned int seconds) | |
669 | { | |
670 | pj_time_val delay = { .sec = seconds, }; | |
671 | pjsip_regc_info info; | |
655 | 672 | |
656 | 673 | cancel_registration(client_state); |
657 | 674 | |
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); | |
675 | pjsip_regc_get_info(client_state->client, &info); | |
676 | ast_debug(1, "Scheduling outbound registration to server '%.*s' from client '%.*s' in %d seconds\n", | |
677 | (int) info.server_uri.slen, info.server_uri.ptr, | |
678 | (int) info.client_uri.slen, info.client_uri.ptr, | |
679 | seconds); | |
680 | ||
681 | ao2_ref(client_state, +1); | |
682 | if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &client_state->timer, &delay) != PJ_SUCCESS) { | |
683 | ast_log(LOG_WARNING, "Failed to schedule registration to server '%.*s' from client '%.*s'\n", | |
684 | (int) info.server_uri.slen, info.server_uri.ptr, | |
685 | (int) info.client_uri.slen, info.client_uri.ptr); | |
686 | ao2_ref(client_state, -1); | |
666 | 687 | } |
667 | 688 | } |
668 | 689 | |
699 | 720 | { |
700 | 721 | struct sip_outbound_registration_client_state *client_state = data; |
701 | 722 | |
723 | cancel_registration(client_state); | |
724 | ||
702 | 725 | if (client_state->client) { |
703 | 726 | pjsip_regc_info info; |
704 | 727 | pjsip_tx_data *tdata; |
705 | 728 | |
706 | /* We need to get the live state to test "is_busy" */ | |
707 | 729 | pjsip_regc_get_info(client_state->client, &info); |
708 | 730 | |
709 | 731 | if (info.is_busy == PJ_TRUE) { |
710 | 732 | /* If a client transaction is in progress we defer until it is complete */ |
711 | 733 | ast_debug(1, |
712 | "%s: Registration transaction is busy with server '%.*s' from client '%.*s'.\n", | |
713 | client_state->registration_name, | |
734 | "Registration transaction is busy with server '%.*s' from client '%.*s'.\n", | |
714 | 735 | (int) info.server_uri.slen, info.server_uri.ptr, |
715 | 736 | (int) info.client_uri.slen, info.client_uri.ptr); |
716 | 737 | client_state->destroy = 1; |
723 | 744 | break; |
724 | 745 | case SIP_REGISTRATION_REGISTERED: |
725 | 746 | ast_debug(1, |
726 | "%s: Trying to unregister with server '%.*s' from client '%.*s' before destruction.\n", | |
727 | client_state->registration_name, | |
747 | "Trying to unregister with server '%.*s' from client '%.*s' before destruction.\n", | |
728 | 748 | (int) info.server_uri.slen, info.server_uri.ptr, |
729 | 749 | (int) info.client_uri.slen, info.client_uri.ptr); |
730 | cancel_registration(client_state); | |
750 | ||
731 | 751 | update_client_state_status(client_state, SIP_REGISTRATION_STOPPING); |
732 | 752 | client_state->destroy = 1; |
733 | 753 | if (pjsip_regc_unregister(client_state->client, &tdata) == PJ_SUCCESS |
737 | 757 | } |
738 | 758 | break; |
739 | 759 | case SIP_REGISTRATION_REJECTED_TEMPORARY: |
760 | case SIP_REGISTRATION_REJECTED_PERMANENT: | |
740 | 761 | case SIP_REGISTRATION_STOPPING: |
741 | cancel_registration(client_state); | |
742 | break; | |
743 | case SIP_REGISTRATION_REJECTED_PERMANENT: | |
744 | 762 | case SIP_REGISTRATION_STOPPED: |
745 | 763 | break; |
746 | 764 | } |
751 | 769 | |
752 | 770 | update_client_state_status(client_state, SIP_REGISTRATION_STOPPED); |
753 | 771 | ast_sip_auth_vector_destroy(&client_state->outbound_auths); |
754 | ||
755 | 772 | ao2_ref(client_state, -1); |
756 | 773 | |
757 | 774 | return 0; |
809 | 826 | } |
810 | 827 | } |
811 | 828 | |
812 | static void schedule_retry(struct registration_response *response, unsigned int interval) | |
829 | static void schedule_retry(struct registration_response *response, unsigned int interval, | |
830 | const char *server_uri, const char *client_uri) | |
813 | 831 | { |
814 | 832 | update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_TEMPORARY); |
815 | schedule_registration(response->client_state, interval * 1000); | |
833 | schedule_registration(response->client_state, interval); | |
816 | 834 | |
817 | 835 | if (response->rdata) { |
818 | ast_log(LOG_WARNING, "%s: Temporal response '%d' received from '%s' on " | |
836 | ast_log(LOG_WARNING, "Temporal response '%d' received from '%s' on " | |
819 | 837 | "registration attempt to '%s', retrying in '%u'\n", |
820 | response->client_state->registration_name, | |
821 | response->code, response->client_state->server_uri, response->client_state->client_uri, interval); | |
838 | response->code, server_uri, client_uri, interval); | |
822 | 839 | } else { |
823 | ast_log(LOG_WARNING, "%s: No response received from '%s' on " | |
840 | ast_log(LOG_WARNING, "No response received from '%s' on " | |
824 | 841 | "registration attempt to '%s', retrying in '%u'\n", |
825 | response->client_state->registration_name, | |
826 | response->client_state->server_uri, response->client_state->client_uri, interval); | |
842 | server_uri, client_uri, interval); | |
827 | 843 | } |
828 | 844 | } |
829 | 845 | |
836 | 852 | return 0; |
837 | 853 | } |
838 | 854 | |
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); | |
855 | if (DEBUG_ATLEAST(1)) { | |
856 | pjsip_regc_info info; | |
857 | ||
858 | pjsip_regc_get_info(state->client_state->client, &info); | |
859 | ast_log(LOG_DEBUG, | |
860 | "Outbound registration transport to server '%.*s' from client '%.*s' shutdown\n", | |
861 | (int) info.server_uri.slen, info.server_uri.ptr, | |
862 | (int) info.client_uri.slen, info.client_uri.ptr); | |
863 | } | |
842 | 864 | |
843 | 865 | cancel_registration(state->client_state); |
844 | 866 | |
911 | 933 | static int handle_registration_response(void *data) |
912 | 934 | { |
913 | 935 | struct registration_response *response = data; |
936 | pjsip_regc_info info; | |
937 | char server_uri[PJSIP_MAX_URL_SIZE]; | |
938 | char client_uri[PJSIP_MAX_URL_SIZE]; | |
914 | 939 | |
915 | 940 | if (response->client_state->status == SIP_REGISTRATION_STOPPED) { |
916 | 941 | ao2_ref(response, -1); |
917 | 942 | return 0; |
918 | 943 | } |
919 | 944 | |
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); | |
945 | pjsip_regc_get_info(response->client_state->client, &info); | |
946 | ast_copy_pj_str(server_uri, &info.server_uri, sizeof(server_uri)); | |
947 | ast_copy_pj_str(client_uri, &info.client_uri, sizeof(client_uri)); | |
948 | ||
949 | ast_debug(1, "Processing REGISTER response %d from server '%s' for client '%s'\n", | |
950 | response->code, server_uri, client_uri); | |
923 | 951 | |
924 | 952 | if (response->code == 408 || response->code == 503) { |
925 | 953 | if ((ast_sip_failover_request(response->old_request))) { |
941 | 969 | if (!ast_sip_create_request_with_auth(&response->client_state->outbound_auths, |
942 | 970 | response->rdata, response->old_request, &tdata)) { |
943 | 971 | response->client_state->auth_attempted = 1; |
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); | |
972 | ast_debug(1, "Sending authenticated REGISTER to server '%s' from client '%s'\n", | |
973 | server_uri, client_uri); | |
947 | 974 | pjsip_tx_data_add_ref(tdata); |
948 | 975 | res = registration_client_send(response->client_state, tdata); |
949 | 976 | |
957 | 984 | return 0; |
958 | 985 | } |
959 | 986 | } else { |
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); | |
987 | ast_log(LOG_WARNING, "Failed to create authenticated REGISTER request to server '%s' from client '%s'\n", | |
988 | server_uri, client_uri); | |
963 | 989 | } |
964 | 990 | /* Otherwise, fall through so the failure is processed appropriately */ |
965 | 991 | } |
972 | 998 | int next_registration_round; |
973 | 999 | |
974 | 1000 | /* If the registration went fine simply reschedule registration for the future */ |
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); | |
1001 | ast_debug(1, "Outbound registration to '%s' with client '%s' successful\n", server_uri, client_uri); | |
978 | 1002 | update_client_state_status(response->client_state, SIP_REGISTRATION_REGISTERED); |
979 | 1003 | response->client_state->retries = 0; |
980 | next_registration_round = (response->expiration - REREGISTER_BUFFER_TIME) * 1000; | |
1004 | next_registration_round = response->expiration - REREGISTER_BUFFER_TIME; | |
981 | 1005 | if (next_registration_round < 0) { |
982 | /* Re-register no sooner than the buffer time. */ | |
983 | next_registration_round = REREGISTER_BUFFER_TIME * 1000; | |
1006 | /* Re-register immediately. */ | |
1007 | next_registration_round = 0; | |
984 | 1008 | } |
985 | 1009 | schedule_registration(response->client_state, next_registration_round); |
986 | 1010 | |
988 | 1012 | registration_transport_monitor_setup(response->rdata->tp_info.transport, |
989 | 1013 | response->client_state->registration_name); |
990 | 1014 | } else { |
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); | |
1015 | ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri); | |
994 | 1016 | update_client_state_status(response->client_state, SIP_REGISTRATION_UNREGISTERED); |
995 | 1017 | ast_sip_transport_monitor_unregister(response->rdata->tp_info.transport, |
996 | 1018 | registration_transport_shutdown_cb, response->client_state->registration_name, |
1000 | 1022 | /* We need to deal with the pending destruction instead. */ |
1001 | 1023 | } else if (response->retry_after) { |
1002 | 1024 | /* If we have been instructed to retry after a period of time, schedule it as such */ |
1003 | schedule_retry(response, response->retry_after); | |
1025 | schedule_retry(response, response->retry_after, server_uri, client_uri); | |
1004 | 1026 | } else if (response->client_state->retry_interval |
1005 | 1027 | && sip_outbound_registration_is_temporal(response->code, response->client_state)) { |
1006 | 1028 | if (response->client_state->retries == response->client_state->max_retries) { |
1007 | 1029 | /* If we received enough temporal responses to exceed our maximum give up permanently */ |
1008 | 1030 | update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_PERMANENT); |
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); | |
1031 | ast_log(LOG_WARNING, "Maximum retries reached when attempting outbound registration to '%s' with client '%s', stopping registration attempt\n", | |
1032 | server_uri, client_uri); | |
1012 | 1033 | } else { |
1013 | 1034 | /* On the other hand if we can still try some more do so */ |
1014 | 1035 | response->client_state->retries++; |
1015 | schedule_retry(response, response->client_state->retry_interval); | |
1036 | schedule_retry(response, response->client_state->retry_interval, server_uri, client_uri); | |
1016 | 1037 | } |
1017 | 1038 | } else { |
1018 | 1039 | if (response->code == 403 |
1021 | 1042 | /* A forbidden response retry interval is configured and there are retries remaining */ |
1022 | 1043 | update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_TEMPORARY); |
1023 | 1044 | response->client_state->retries++; |
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); | |
1045 | schedule_registration(response->client_state, response->client_state->forbidden_retry_interval); | |
1046 | ast_log(LOG_WARNING, "403 Forbidden fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n", | |
1047 | server_uri, client_uri, response->client_state->forbidden_retry_interval); | |
1028 | 1048 | } else if (response->client_state->fatal_retry_interval |
1029 | 1049 | && response->client_state->retries < response->client_state->max_retries) { |
1030 | 1050 | /* Some kind of fatal failure response received, so retry according to configured interval */ |
1031 | 1051 | update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_TEMPORARY); |
1032 | 1052 | response->client_state->retries++; |
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); | |
1053 | schedule_registration(response->client_state, response->client_state->fatal_retry_interval); | |
1054 | ast_log(LOG_WARNING, "'%d' fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n", | |
1055 | response->code, server_uri, client_uri, response->client_state->fatal_retry_interval); | |
1037 | 1056 | } else { |
1038 | 1057 | /* Finally if there's no hope of registering give up */ |
1039 | 1058 | update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_PERMANENT); |
1040 | 1059 | if (response->rdata) { |
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); | |
1060 | ast_log(LOG_WARNING, "Fatal response '%d' received from '%s' on registration attempt to '%s', stopping outbound registration\n", | |
1061 | response->code, server_uri, client_uri); | |
1044 | 1062 | } else { |
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); | |
1063 | ast_log(LOG_WARNING, "Fatal registration attempt to '%s', stopping outbound registration\n", client_uri); | |
1047 | 1064 | } |
1048 | 1065 | } |
1049 | 1066 | } |
1050 | 1067 | |
1051 | ast_system_publish_registry("PJSIP", response->client_state->client_uri, response->client_state->server_uri, | |
1068 | ast_system_publish_registry("PJSIP", client_uri, server_uri, | |
1052 | 1069 | sip_outbound_registration_status_str(response->client_state->status), NULL); |
1053 | 1070 | |
1054 | 1071 | if (response->client_state->destroy) { |
1089 | 1106 | */ |
1090 | 1107 | response->client_state = client_state; |
1091 | 1108 | |
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); | |
1109 | ast_debug(1, "Received REGISTER response %d(%.*s)\n", | |
1110 | param->code, (int) param->reason.slen, param->reason.ptr); | |
1096 | 1111 | |
1097 | 1112 | if (param->rdata) { |
1098 | 1113 | struct pjsip_retry_after_hdr *retry_after; |
1127 | 1142 | * pjproject callback thread. |
1128 | 1143 | */ |
1129 | 1144 | if (ast_sip_push_task(client_state->serializer, handle_registration_response, response)) { |
1130 | ast_log(LOG_WARNING, "%s: Failed to pass incoming registration response to threadpool\n", | |
1131 | client_state->registration_name); | |
1145 | ast_log(LOG_WARNING, "Failed to pass incoming registration response to threadpool\n"); | |
1132 | 1146 | ao2_cleanup(response); |
1133 | 1147 | } |
1134 | 1148 | } |
1138 | 1152 | { |
1139 | 1153 | struct sip_outbound_registration_state *state = obj; |
1140 | 1154 | |
1141 | ast_debug(3, "%s: Destroying registration state for registration to server '%s' from client '%s'\n", | |
1142 | state->client_state->registration_name, | |
1155 | ast_debug(3, "Destroying registration state for registration to server '%s' from client '%s'\n", | |
1143 | 1156 | state->registration ? state->registration->server_uri : "", |
1144 | 1157 | state->registration ? state->registration->client_uri : ""); |
1145 | 1158 | ao2_cleanup(state->registration); |
1150 | 1163 | ao2_ref(state->client_state, -1); |
1151 | 1164 | } else if (ast_sip_push_task(state->client_state->serializer, |
1152 | 1165 | handle_client_state_destruction, state->client_state)) { |
1153 | ast_log(LOG_WARNING, "%s: Failed to pass outbound registration client destruction to threadpool\n", | |
1154 | state->client_state->registration_name); | |
1166 | ast_log(LOG_WARNING, "Failed to pass outbound registration client destruction to threadpool\n"); | |
1155 | 1167 | ao2_ref(state->client_state, -1); |
1156 | 1168 | } |
1157 | 1169 | } |
1160 | 1172 | static void sip_outbound_registration_client_state_destroy(void *obj) |
1161 | 1173 | { |
1162 | 1174 | 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); | |
1166 | 1175 | |
1167 | 1176 | ast_statsd_log_string("PJSIP.registrations.count", AST_STATSD_GAUGE, "-1", 1.0); |
1168 | 1177 | ast_statsd_log_string_va("PJSIP.registrations.state.%s", AST_STATSD_GAUGE, "-1", 1.0, |
1171 | 1180 | ast_taskprocessor_unreference(client_state->serializer); |
1172 | 1181 | ast_free(client_state->transport_name); |
1173 | 1182 | 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); | |
1177 | 1183 | if (client_state->last_tdata) { |
1178 | 1184 | pjsip_tx_data_dec_ref(client_state->last_tdata); |
1179 | 1185 | } |
1197 | 1203 | } |
1198 | 1204 | |
1199 | 1205 | state->client_state->status = SIP_REGISTRATION_UNREGISTERED; |
1206 | pj_timer_entry_init(&state->client_state->timer, 0, state->client_state, | |
1207 | sip_outbound_registration_timer_cb); | |
1200 | 1208 | state->client_state->transport_name = ast_strdup(registration->transport); |
1201 | 1209 | state->client_state->registration_name = |
1202 | 1210 | ast_strdup(ast_sorcery_object_get_id(registration)); |
1431 | 1439 | } |
1432 | 1440 | |
1433 | 1441 | pj_cstr(&server_uri, registration->server_uri); |
1434 | state->client_state->server_uri = ast_strdup(registration->server_uri); | |
1442 | ||
1435 | 1443 | |
1436 | 1444 | if (sip_dialog_create_contact(pjsip_regc_get_pool(state->client_state->client), |
1437 | 1445 | &contact_uri, S_OR(registration->contact_user, "s"), &server_uri, &selector, |
1438 | 1446 | state->client_state->line)) { |
1439 | 1447 | return -1; |
1440 | 1448 | } |
1441 | ast_copy_pj_str2(&state->client_state->contact_uri, &contact_uri); | |
1442 | 1449 | |
1443 | 1450 | pj_cstr(&client_uri, registration->client_uri); |
1444 | state->client_state->client_uri = ast_strdup(registration->client_uri); | |
1445 | ||
1446 | 1451 | if (pjsip_regc_init(state->client_state->client, &server_uri, &client_uri, |
1447 | 1452 | &client_uri, 1, &contact_uri, registration->expiration) != PJ_SUCCESS) { |
1448 | 1453 | return -1; |
1449 | 1454 | } |
1450 | 1455 | |
1451 | ||
1452 | 1456 | return 0; |
1453 | 1457 | } |
1454 | 1458 | |
1458 | 1462 | struct sip_outbound_registration_state *state = data; |
1459 | 1463 | struct sip_outbound_registration *registration = ao2_bump(state->registration); |
1460 | 1464 | 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); | |
1465 | 1465 | |
1466 | 1466 | /* Just in case the client state is being reused for this registration, free the auth information */ |
1467 | 1467 | ast_sip_auth_vector_destroy(&state->client_state->outbound_auths); |
1484 | 1484 | |
1485 | 1485 | pjsip_regc_update_expires(state->client_state->client, registration->expiration); |
1486 | 1486 | |
1487 | schedule_registration(state->client_state, ((ast_random() % 10) + 1) * 1000); | |
1487 | schedule_registration(state->client_state, (ast_random() % 10) + 1); | |
1488 | 1488 | |
1489 | 1489 | ao2_ref(registration, -1); |
1490 | 1490 | ao2_ref(state, -1); |
1613 | 1613 | struct sip_outbound_registration_state *state = obj; |
1614 | 1614 | struct pjsip_regc *client = state->client_state->client; |
1615 | 1615 | pjsip_tx_data *tdata; |
1616 | ||
1617 | ast_debug(1, "%s: Unregistering contacts with server '%s' from client '%s'\n", | |
1618 | state->client_state->registration_name, | |
1616 | pjsip_regc_info info; | |
1617 | ||
1618 | pjsip_regc_get_info(client, &info); | |
1619 | ast_debug(1, "Unregistering contacts with server '%s' from client '%s'\n", | |
1619 | 1620 | state->registration->server_uri, state->registration->client_uri); |
1620 | 1621 | |
1621 | 1622 | cancel_registration(state->client_state); |
1642 | 1643 | static int queue_register(struct sip_outbound_registration_state *state) |
1643 | 1644 | { |
1644 | 1645 | 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 | ||
1650 | 1646 | if (ast_sip_push_task(state->client_state->serializer, sip_outbound_registration_perform, state)) { |
1651 | 1647 | ao2_ref(state, -1); |
1652 | 1648 | return -1; |
1900 | 1896 | ast_sip_sorcery_object_to_ami(ami->registration, &buf); |
1901 | 1897 | |
1902 | 1898 | if ((state = get_state(ast_sorcery_object_get_id(ami->registration)))) { |
1903 | int next_reg = 0; | |
1899 | pjsip_regc_info info; | |
1904 | 1900 | |
1905 | 1901 | if (state->client_state->status == SIP_REGISTRATION_REGISTERED) { |
1906 | 1902 | ++ami->registered; |
1911 | 1907 | ast_str_append(&buf, 0, "Status: %s\r\n", |
1912 | 1908 | sip_outbound_registration_status_str(state->client_state->status)); |
1913 | 1909 | |
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); | |
1910 | pjsip_regc_get_info(state->client_state->client, &info); | |
1911 | ast_str_append(&buf, 0, "NextReg: %d\r\n", info.next_reg); | |
1920 | 1912 | ao2_ref(state, -1); |
1921 | 1913 | } |
1922 | 1914 | |
2021 | 2013 | ast_assert(context->output_buffer != NULL); |
2022 | 2014 | |
2023 | 2015 | ast_str_append(&context->output_buffer, 0, |
2024 | " <Registration/ServerURI..............................> <Auth..........> <Status.......>"); | |
2025 | ast_str_append(&context->output_buffer, 0, | |
2026 | " <Last Reg..> <Intvl> <Next Start.....secs>\n" | |
2027 | "=============================================="); | |
2016 | " <Registration/ServerURI..............................> <Auth..........> <Status.......>\n"); | |
2028 | 2017 | |
2029 | 2018 | return 0; |
2030 | 2019 | } |
2031 | ||
2032 | #define TIME_FORMAT "%a %T" | |
2033 | 2020 | |
2034 | 2021 | static int cli_print_body(void *obj, void *arg, int flags) |
2035 | 2022 | { |
2037 | 2024 | struct ast_sip_cli_context *context = arg; |
2038 | 2025 | const char *id = ast_sorcery_object_get_id(registration); |
2039 | 2026 | 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 | ||
2048 | 2027 | #define REGISTRATION_URI_FIELD_LEN 53 |
2049 | 2028 | |
2050 | 2029 | ast_assert(context->output_buffer != NULL); |
2051 | 2030 | |
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", | |
2031 | ast_str_append(&context->output_buffer, 0, " %-s/%-*.*s %-16s %-16s\n", | |
2064 | 2032 | id, |
2065 | 2033 | (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)), |
2066 | 2034 | (int) (REGISTRATION_URI_FIELD_LEN - strlen(id)), |
2068 | 2036 | AST_VECTOR_SIZE(®istration->outbound_auths) |
2069 | 2037 | ? AST_VECTOR_GET(®istration->outbound_auths, 0) |
2070 | 2038 | : "n/a", |
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 | ||
2039 | (state ? sip_outbound_registration_status_str(state->client_state->status) : "Unregistered")); | |
2077 | 2040 | ao2_cleanup(state); |
2078 | ||
2079 | 2041 | |
2080 | 2042 | if (context->show_details |
2081 | 2043 | || (context->show_details_only_level_0 && context->indent_level == 0)) { |
122 | 122 | static int add_supported(pjsip_tx_data *tdata) |
123 | 123 | { |
124 | 124 | pjsip_supported_hdr *hdr; |
125 | int i; | |
125 | 126 | |
126 | 127 | hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL); |
127 | 128 | if (!hdr) { |
132 | 133 | } |
133 | 134 | |
134 | 135 | pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr); |
136 | } | |
137 | ||
138 | /* Don't add the value if it's already there */ | |
139 | for (i = 0; i < hdr->count; ++i) { | |
140 | if (pj_stricmp(&hdr->values[i], &PATH_SUPPORTED_NAME) == 0) { | |
141 | return 0; | |
142 | } | |
143 | } | |
144 | ||
145 | if (hdr->count >= PJSIP_GENERIC_ARRAY_MAX_COUNT) { | |
146 | return -1; | |
135 | 147 | } |
136 | 148 | |
137 | 149 | /* add on to the existing Supported header */ |
41 | 41 | pj_xml_node *node; |
42 | 42 | char sanitized[1024]; |
43 | 43 | |
44 | /* The res_pjsip_exten_state module converts the user agent to lower case */ | |
44 | 45 | if (ast_strlen_zero(state_data->user_agent) || |
45 | !strstr(state_data->user_agent, "digium")) { | |
46 | /* not a digium phone */ | |
46 | (!strstr(state_data->user_agent, "digium") && | |
47 | !strstr(state_data->user_agent, "sangoma"))) { | |
48 | /* not a Sangoma phone */ | |
47 | 49 | return 0; |
48 | 50 | } |
49 | 51 | |
106 | 108 | return 0; |
107 | 109 | } |
108 | 110 | |
109 | AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP PIDF Digium presence supplement", | |
111 | AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP PIDF Sangoma presence supplement", | |
110 | 112 | .support_level = AST_MODULE_SUPPORT_CORE, |
111 | 113 | .load = load_module, |
112 | 114 | .unload = unload_module, |
2267 | 2267 | ast_sip_session_get_name(session)); |
2268 | 2268 | } |
2269 | 2269 | |
2270 | if (active_media_state) { | |
2270 | /* | |
2271 | * Attempt to resolve only if objects are available, and it's not | |
2272 | * switching to or from an image type. | |
2273 | */ | |
2274 | if (active_media_state && active_media_state->topology && | |
2275 | (!active_media_state->default_session[AST_MEDIA_TYPE_IMAGE] == | |
2276 | !pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE])) { | |
2277 | ||
2271 | 2278 | struct ast_sip_session_media_state *new_pending_state; |
2272 | 2279 | /* |
2273 | 2280 | * We need to check if the passed in active and pending states are equal |
2978 | 2985 | ast_dsp_free(session->dsp); |
2979 | 2986 | |
2980 | 2987 | if (session->inv_session) { |
2981 | pjsip_dlg_dec_session(session->inv_session->dlg, &session_module); | |
2988 | struct pjsip_dialog *dlg = session->inv_session->dlg; | |
2989 | ||
2990 | /* The INVITE session uses the dialog pool for memory, so we need to | |
2991 | * decrement its reference first before that of the dialog. | |
2992 | */ | |
2993 | ||
2994 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
2995 | pjsip_inv_dec_ref(session->inv_session); | |
2996 | #endif | |
2997 | pjsip_dlg_dec_session(dlg, &session_module); | |
2982 | 2998 | } |
2983 | 2999 | |
2984 | 3000 | ast_test_suite_event_notify("SESSION_DESTROYED", "Endpoint: %s", endpoint_name); |
3086 | 3102 | } |
3087 | 3103 | ast_sip_dialog_set_serializer(inv_session->dlg, session->serializer); |
3088 | 3104 | ast_sip_dialog_set_endpoint(inv_session->dlg, endpoint); |
3105 | ||
3106 | /* When a PJSIP INVITE session is created it is created with a reference | |
3107 | * count of 1, with that reference being managed by the underlying state | |
3108 | * of the INVITE session itself. When the INVITE session transitions to | |
3109 | * a DISCONNECTED state that reference is released. This means we can not | |
3110 | * rely on that reference to ensure the INVITE session remains for the | |
3111 | * lifetime of our session. To ensure it does we add our own reference | |
3112 | * and release it when our own session goes away, ensuring that the INVITE | |
3113 | * session remains for the lifetime of session. | |
3114 | */ | |
3115 | ||
3116 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
3117 | if (pjsip_inv_add_ref(inv_session) != PJ_SUCCESS) { | |
3118 | ast_log(LOG_ERROR, "Can't increase the session reference counter\n"); | |
3119 | return NULL; | |
3120 | } | |
3121 | #endif | |
3122 | ||
3089 | 3123 | pjsip_dlg_inc_session(inv_session->dlg, &session_module); |
3090 | 3124 | inv_session->mod_data[session_module.id] = ao2_bump(session); |
3091 | 3125 | session->contact = ao2_bump(contact); |
3711 | 3745 | */ |
3712 | 3746 | AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(session->exten); |
3713 | 3747 | |
3714 | pickup_cfg = ast_get_chan_features_pickup_config(session->channel); | |
3748 | pickup_cfg = ast_get_chan_features_pickup_config(NULL); /* session->channel doesn't exist yet, using NULL */ | |
3715 | 3749 | if (!pickup_cfg) { |
3716 | 3750 | ast_log(LOG_ERROR, "%s: Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n", |
3717 | 3751 | ast_sip_session_get_name(session)); |
3723 | 3757 | |
3724 | 3758 | if (!strcmp(session->exten, pickupexten) || |
3725 | 3759 | ast_exists_extension(NULL, session->endpoint->context, session->exten, 1, NULL)) { |
3726 | size_t size = pj_strlen(&sip_ruri->host) + 1; | |
3727 | char *domain = ast_alloca(size); | |
3728 | ||
3729 | ast_copy_pj_str(domain, &sip_ruri->host, size); | |
3730 | pbx_builtin_setvar_helper(session->channel, "SIPDOMAIN", domain); | |
3731 | ||
3732 | 3760 | /* |
3733 | 3761 | * Save off the INVITE Request-URI in case it is |
3734 | 3762 | * needed: CHANNEL(pjsip,request_uri) |
3961 | 3989 | ast_sip_session_get_name(invite->session), |
3962 | 3990 | invite->session->inv_session->cause, |
3963 | 3991 | pjsip_get_status_text(invite->session->inv_session->cause)->ptr); |
3964 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
3965 | pjsip_inv_dec_ref(invite->session->inv_session); | |
3966 | #endif | |
3967 | 3992 | SCOPE_EXIT_RTN_VALUE(-1); |
3968 | 3993 | } |
3969 | 3994 | |
4081 | 4106 | handle_incoming_request(invite->session, invite->rdata); |
4082 | 4107 | |
4083 | 4108 | end: |
4084 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
4085 | pjsip_inv_dec_ref(invite->session->inv_session); | |
4086 | #endif | |
4087 | 4109 | SCOPE_EXIT_RTN_VALUE(0, "%s\n", ast_sip_session_get_name(invite->session)); |
4088 | 4110 | } |
4089 | 4111 | |
4126 | 4148 | * process handling has successfully completed. |
4127 | 4149 | */ |
4128 | 4150 | |
4129 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
4130 | if (pjsip_inv_add_ref(inv_session) != PJ_SUCCESS) { | |
4131 | ast_log(LOG_ERROR, "Can't increase the session reference counter\n"); | |
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); | |
4136 | } | |
4137 | return; | |
4138 | } | |
4139 | #endif | |
4140 | 4151 | session = ast_sip_session_alloc(endpoint, NULL, inv_session, rdata); |
4141 | 4152 | if (!session) { |
4142 | 4153 | /* Dialog's lock and reference are removed in new_invite_initial_answer */ |
4144 | 4155 | /* Terminate the session if it wasn't done in the answer */ |
4145 | 4156 | pjsip_inv_terminate(inv_session, 500, PJ_FALSE); |
4146 | 4157 | } |
4147 | ||
4148 | #ifdef HAVE_PJSIP_INV_SESSION_REF | |
4149 | pjsip_inv_dec_ref(inv_session); | |
4150 | #endif | |
4151 | 4158 | return; |
4152 | 4159 | } |
4153 | 4160 | |
5514 | 5521 | } |
5515 | 5522 | if (AST_VECTOR_SIZE(&left->sessions) != AST_VECTOR_SIZE(&right->sessions)) { |
5516 | 5523 | 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), | |
5524 | SCOPE_EXIT_RTN_VALUE(0, "session vector sizes different: left %zu != right %zu\n", | |
5525 | AST_VECTOR_SIZE(&left->sessions), | |
5518 | 5526 | AST_VECTOR_SIZE(&right->sessions)); |
5519 | 5527 | } |
5520 | 5528 | if (AST_VECTOR_SIZE(&left->read_callbacks) != AST_VECTOR_SIZE(&right->read_callbacks)) { |
5521 | 5529 | 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), | |
5530 | SCOPE_EXIT_RTN_VALUE(0, "read_callback vector sizes different: left %zu != right %zu\n", | |
5531 | AST_VECTOR_SIZE(&left->read_callbacks), | |
5523 | 5532 | AST_VECTOR_SIZE(&right->read_callbacks)); |
5524 | 5533 | } |
5525 | 5534 |
322 | 322 | #define AST_BUILDOPT_SUM "" |
323 | 323 | |
324 | 324 | AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, |
325 | "PSIP STIR/SHAKEN Module for Asterisk", | |
325 | "PJSIP STIR/SHAKEN Module for Asterisk", | |
326 | 326 | .support_level = AST_MODULE_SUPPORT_CORE, |
327 | 327 | .load = load_module, |
328 | 328 | .unload = unload_module, |
329 | 329 | .load_pri = AST_MODPRI_DEFAULT, |
330 | .requires = "res_pjsip,res_stir_shaken", | |
330 | .requires = "res_pjsip,res_pjsip_session,res_stir_shaken", | |
331 | 331 | ); |
319 | 319 | int index; |
320 | 320 | |
321 | 321 | session_media = session->active_media_state->default_session[AST_MEDIA_TYPE_IMAGE]; |
322 | ||
323 | /* | |
324 | * If there is a session_media object, but no udptl object available | |
325 | * then it's assumed the stream was declined. | |
326 | */ | |
327 | if (!session_media->udptl) { | |
328 | session_media = NULL; | |
329 | } | |
330 | ||
322 | 331 | if (!session_media) { |
323 | 332 | ast_log(LOG_WARNING, "Received %d response to T.38 re-invite on '%s' but no active session media\n", |
324 | 333 | status.code, session->channel ? ast_channel_name(session->channel) : "unknown channel"); |
453 | 453 | pj_strbuf(txp_str)); |
454 | 454 | } |
455 | 455 | |
456 | pj_cstr(&uri->host, rdata->pkt_info.src_name); | |
456 | pj_strdup2(rdata->tp_info.pool, &uri->host, rdata->pkt_info.src_name); | |
457 | 457 | uri->port = rdata->pkt_info.src_port; |
458 | 458 | pj_strdup(rdata->tp_info.pool, &uri->transport_param, txp_str); |
459 | 459 | } |
180 | 180 | #define STRICT_RTP_LEARN_TIMEOUT 5000 |
181 | 181 | |
182 | 182 | #define DEFAULT_STRICT_RTP STRICT_RTP_YES /*!< Enabled by default */ |
183 | #define DEFAULT_SRTP_REPLAY_PROTECTION 1 | |
183 | 184 | #define DEFAULT_ICESUPPORT 1 |
184 | 185 | #define DEFAULT_DTLS_MTU 1200 |
185 | 186 | |
202 | 203 | static int strictrtp = DEFAULT_STRICT_RTP; /*!< Only accept RTP frames from a defined source. If we receive an indication of a changing source, enter learning mode. */ |
203 | 204 | static int learning_min_sequential = DEFAULT_LEARNING_MIN_SEQUENTIAL; /*!< Number of sequential RTP frames needed from a single source during learning mode to accept new source. */ |
204 | 205 | static int learning_min_duration = DEFAULT_LEARNING_MIN_DURATION; /*!< Lowest acceptable timeout between the first and the last sequential RTP frame. */ |
206 | static int srtp_replay_protection = DEFAULT_SRTP_REPLAY_PROTECTION; | |
205 | 207 | #if defined(HAVE_OPENSSL) && (OPENSSL_VERSION_NUMBER >= 0x10001000L) && !defined(OPENSSL_NO_SRTP) |
206 | 208 | static int dtls_mtu = DEFAULT_DTLS_MTU; |
207 | 209 | #endif |
6081 | 6083 | |
6082 | 6084 | /* If this is encrypted then decrypt the payload */ |
6083 | 6085 | if ((*rtcpheader & 0xC0) && res_srtp && srtp && res_srtp->unprotect( |
6084 | srtp, rtcpheader, &len, 1) < 0) { | |
6086 | srtp, rtcpheader, &len, 1 | (srtp_replay_protection << 1)) < 0) { | |
6085 | 6087 | return &ast_null_frame; |
6086 | 6088 | } |
6087 | 6089 | |
6931 | 6933 | /* If there is no more room left for storing packets stop now, we leave 20 |
6932 | 6934 | * extra bits at the end just in case. |
6933 | 6935 | */ |
6934 | if ((sizeof(bdata) - (packet_len + delta_len + 20)) < 0) { | |
6936 | if (packet_len + delta_len + 20 > sizeof(bdata)) { | |
6935 | 6937 | res = -1; |
6936 | 6938 | break; |
6937 | 6939 | } |
6965 | 6967 | previous_packet = statistics; |
6966 | 6968 | |
6967 | 6969 | /* If there is no more room left in the packet stop handling of any subsequent packets */ |
6968 | if ((sizeof(bdata) - (packet_len + delta_len + 20)) < 0) { | |
6970 | if (packet_len + delta_len + 20 > sizeof(bdata)) { | |
6969 | 6971 | break; |
6970 | 6972 | } |
6971 | 6973 | } |
7169 | 7171 | |
7170 | 7172 | /* If this payload is encrypted then decrypt it using the given SRTP instance */ |
7171 | 7173 | if ((*read_area & 0xC0) && res_srtp && srtp && res_srtp->unprotect( |
7172 | srtp, read_area, &res, 0) < 0) { | |
7174 | srtp, read_area, &res, 0 | (srtp_replay_protection << 1)) < 0) { | |
7173 | 7175 | return &ast_null_frame; |
7174 | 7176 | } |
7175 | 7177 | |
8957 | 8959 | if (strictrtp) { |
8958 | 8960 | ast_cli(a->fd, " Probation: %d frames\n", learning_min_sequential); |
8959 | 8961 | } |
8962 | ||
8963 | ast_cli(a->fd, " Replay Protect: %s\n", AST_CLI_YESNO(srtp_replay_protection)); | |
8960 | 8964 | #ifdef HAVE_PJPROJECT |
8961 | 8965 | ast_cli(a->fd, " ICE support: %s\n", AST_CLI_YESNO(icesupport)); |
8962 | 8966 | #endif |
9059 | 9063 | strictrtp = DEFAULT_STRICT_RTP; |
9060 | 9064 | learning_min_sequential = DEFAULT_LEARNING_MIN_SEQUENTIAL; |
9061 | 9065 | learning_min_duration = DEFAULT_LEARNING_MIN_DURATION; |
9066 | srtp_replay_protection = DEFAULT_SRTP_REPLAY_PROTECTION; | |
9062 | 9067 | |
9063 | 9068 | /** This resource is not "reloaded" so much as unloaded and loaded again. |
9064 | 9069 | * In the case of the TURN related variables, the memory referenced by a |
9137 | 9142 | learning_min_sequential = DEFAULT_LEARNING_MIN_SEQUENTIAL; |
9138 | 9143 | } |
9139 | 9144 | learning_min_duration = CALC_LEARNING_MIN_DURATION(learning_min_sequential); |
9145 | } | |
9146 | if ((s = ast_variable_retrieve(cfg, "general", "srtpreplayprotection"))) { | |
9147 | srtp_replay_protection = ast_true(s); | |
9140 | 9148 | } |
9141 | 9149 | #ifdef HAVE_PJPROJECT |
9142 | 9150 | if ((s = ast_variable_retrieve(cfg, "general", "icesupport"))) { |
363 | 363 | } |
364 | 364 | |
365 | 365 | /* Vtable functions */ |
366 | static int ast_srtp_unprotect(struct ast_srtp *srtp, void *buf, int *len, int rtcp) | |
366 | static int ast_srtp_unprotect(struct ast_srtp *srtp, void *buf, int *len, int flags) | |
367 | 367 | { |
368 | 368 | int res = 0; |
369 | 369 | int i; |
370 | int retry = 0; | |
370 | int rtcp = (flags & 0x01) >> 0; | |
371 | int retry = (flags & 0x02) >> 1; | |
371 | 372 | struct ast_rtp_instance_stats stats = {0,}; |
372 | 373 | |
373 | 374 | tryagain: |
488 | 488 | for (i = 0; i < media_count; i++) { |
489 | 489 | char *media_uri; |
490 | 490 | |
491 | if (ast_strlen_zero(media[i])) { | |
492 | ast_log(LOG_ERROR, "Attempted to play media on channel '%s' but no media URI was provided.\n", | |
493 | stasis_app_control_get_channel_id(control)); | |
494 | ao2_ref(playback, -1); | |
495 | return NULL; | |
496 | } | |
497 | ||
491 | 498 | media_uri = ast_malloc(strlen(media[i]) + 1); |
492 | 499 | if (!media_uri) { |
493 | 500 | ao2_ref(playback, -1); |
65 | 65 | struct ast_str *app; |
66 | 66 | /*! \brief Snoop channel */ |
67 | 67 | struct ast_channel *chan; |
68 | /*! \brief The channel that the Snoop channel is snooping on */ | |
69 | struct ast_channel *spyee_chan; | |
68 | 70 | /*! \brief Whether the spy capability is active or not */ |
69 | 71 | unsigned int spy_active:1; |
70 | 72 | /*! \brief Whether the whisper capability is active or not */ |
71 | 73 | unsigned int whisper_active:1; |
72 | /*! \brief Uniqueid of the channel this snoop is snooping on */ | |
73 | char uniqueid[AST_MAX_UNIQUEID]; | |
74 | 74 | /*! \brief A frame of silence to use when the audiohook returns null */ |
75 | 75 | struct ast_frame silence; |
76 | 76 | }; |
99 | 99 | |
100 | 100 | ast_free(snoop->app); |
101 | 101 | |
102 | ast_channel_cleanup(snoop->spyee_chan); | |
102 | 103 | ast_channel_cleanup(snoop->chan); |
103 | 104 | } |
104 | 105 | |
133 | 134 | } |
134 | 135 | ast_multi_channel_blob_add_channel(payload, "spyer_channel", snoop_snapshot); |
135 | 136 | |
136 | spyee_snapshot = ast_channel_snapshot_get_latest(snoop->uniqueid); | |
137 | spyee_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(snoop->spyee_chan)); | |
137 | 138 | if (spyee_snapshot) { |
138 | 139 | ast_multi_channel_blob_add_channel(payload, "spyee_channel", spyee_snapshot); |
139 | 140 | } |
353 | 354 | return NULL; |
354 | 355 | } |
355 | 356 | |
356 | ast_copy_string(snoop->uniqueid, ast_channel_uniqueid(chan), sizeof(snoop->uniqueid)); | |
357 | ||
358 | 357 | /* To keep the channel valid on the Snoop structure until it is destroyed we bump the ref up here */ |
359 | 358 | ast_channel_ref(snoop->chan); |
360 | 359 | |
424 | 423 | return NULL; |
425 | 424 | } |
426 | 425 | |
426 | /* Keep a reference to the channel we are spying on */ | |
427 | snoop->spyee_chan = ast_channel_ref(chan); | |
428 | ||
427 | 429 | publish_chanspy_message(snoop, 1); |
428 | 430 | |
429 | 431 | /* The caller of this has a reference as well */ |
288 | 288 | return json_obj; |
289 | 289 | } |
290 | 290 | |
291 | static void dispatch_message(struct message_subscription *sub, const char *endpoint_name, struct ast_json *json_msg) | |
292 | { | |
293 | int i; | |
294 | ||
295 | ast_debug(3, "Dispatching message to subscription %s for endpoint %s\n", | |
296 | sub->token, | |
297 | endpoint_name); | |
298 | for (i = 0; i < AST_VECTOR_SIZE(&sub->applications); i++) { | |
299 | struct application_tuple *tuple = AST_VECTOR_GET(&sub->applications, i); | |
300 | ||
301 | tuple->callback(endpoint_name, json_msg, tuple->pvt); | |
302 | } | |
303 | } | |
304 | ||
291 | 305 | static int handle_msg_cb(struct ast_msg *msg) |
292 | 306 | { |
307 | /* We have at most 3 subscriptions: TECH_WILDCARD, tech itself, and endpoint. */ | |
308 | struct message_subscription *matching_subscriptions[3]; | |
293 | 309 | struct message_subscription *sub; |
294 | int i; | |
310 | int i, j; | |
311 | int result; | |
295 | 312 | char buf[256]; |
296 | 313 | const char *endpoint_name; |
297 | 314 | struct ast_json *json_msg; |
298 | 315 | |
299 | 316 | msg_to_endpoint(msg, buf, sizeof(buf)); |
300 | ||
317 | endpoint_name = buf; | |
318 | json_msg = msg_to_json(msg); | |
319 | if (!json_msg) { | |
320 | return -1; | |
321 | } | |
322 | result = -1; | |
323 | ||
324 | /* Find subscriptions to TECH_WILDCARD and to the endpoint's technology. */ | |
301 | 325 | ast_rwlock_rdlock(&tech_subscriptions_lock); |
302 | for (i = 0; i < AST_VECTOR_SIZE(&tech_subscriptions); i++) { | |
326 | for (i = 0, j = 0; i < AST_VECTOR_SIZE(&tech_subscriptions) && j < 2; i++) { | |
303 | 327 | sub = AST_VECTOR_GET(&tech_subscriptions, i); |
304 | 328 | |
305 | 329 | if (!sub) { |
308 | 332 | |
309 | 333 | if (!strcmp(sub->token, TECH_WILDCARD) |
310 | 334 | || !strncasecmp(sub->token, buf, strlen(sub->token))) { |
311 | ast_rwlock_unlock(&tech_subscriptions_lock); | |
312 | ao2_bump(sub); | |
313 | endpoint_name = buf; | |
314 | goto match; | |
335 | ao2_ref(sub, +1); | |
336 | matching_subscriptions[j++] = sub; | |
315 | 337 | } |
316 | 338 | } |
317 | 339 | ast_rwlock_unlock(&tech_subscriptions_lock); |
318 | 340 | |
341 | /* Find the subscription to this particular endpoint. */ | |
319 | 342 | sub = ao2_find(endpoint_subscriptions, buf, OBJ_SEARCH_KEY); |
320 | 343 | if (sub) { |
321 | endpoint_name = buf; | |
322 | goto match; | |
323 | } | |
324 | ||
325 | return -1; | |
326 | ||
327 | match: | |
328 | ast_debug(3, "Dispatching message for %s\n", endpoint_name); | |
329 | ||
330 | json_msg = msg_to_json(msg); | |
331 | if (!json_msg) { | |
344 | matching_subscriptions[j++] = sub; | |
345 | } | |
346 | ||
347 | /* Dispatch the message to all matching subscriptions. */ | |
348 | for (i = 0; i < j; i++) { | |
349 | sub = matching_subscriptions[i]; | |
350 | ||
351 | dispatch_message(sub, endpoint_name, json_msg); | |
352 | ||
332 | 353 | ao2_ref(sub, -1); |
333 | return -1; | |
334 | } | |
335 | ||
336 | for (i = 0; i < AST_VECTOR_SIZE(&sub->applications); i++) { | |
337 | struct application_tuple *tuple = AST_VECTOR_GET(&sub->applications, i); | |
338 | ||
339 | tuple->callback(endpoint_name, json_msg, tuple->pvt); | |
354 | result = 0; | |
340 | 355 | } |
341 | 356 | |
342 | 357 | ast_json_unref(json_msg); |
343 | ao2_ref(sub, -1); | |
344 | return 0; | |
358 | return result; | |
345 | 359 | } |
346 | 360 | |
347 | 361 | struct ast_msg_handler ari_msg_handler = { |
696 | 696 | .load = load_module, |
697 | 697 | .reload = reload_module, |
698 | 698 | .unload = unload_module, |
699 | .requires = "res_http_media_cache", | |
699 | 700 | ); |
+37
-0
0 | From ce18018cc17bef8f80c08686e3a7b28384ef3ba5 Mon Sep 17 00:00:00 2001 | |
1 | From: sauwming <ming@teluu.com> | |
2 | Date: Mon, 12 Oct 2020 13:31:25 +0800 | |
3 | Subject: [PATCH] Fix incorrect copying of destination info when creating | |
4 | CANCEL (#2546) | |
5 | ||
6 | --- | |
7 | pjsip/src/pjsip/sip_util.c | 10 +++++----- | |
8 | 1 file changed, 5 insertions(+), 5 deletions(-) | |
9 | ||
10 | diff --git a/pjsip/src/pjsip/sip_util.c b/pjsip/src/pjsip/sip_util.c | |
11 | index d10a6fa30..a1bf878ea 100644 | |
12 | --- a/pjsip/src/pjsip/sip_util.c | |
13 | +++ b/pjsip/src/pjsip/sip_util.c | |
14 | @@ -779,14 +779,14 @@ PJ_DEF(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt, | |
15 | pjsip_hdr_clone(cancel_tdata->pool, req_tdata->saved_strict_route); | |
16 | } | |
17 | ||
18 | - /* Copy the destination host name from the original request */ | |
19 | - pj_strdup(cancel_tdata->pool, &cancel_tdata->dest_info.name, | |
20 | - &req_tdata->dest_info.name); | |
21 | - | |
22 | - /* Finally copy the destination info from the original request */ | |
23 | + /* Copy the destination info from the original request */ | |
24 | pj_memcpy(&cancel_tdata->dest_info, &req_tdata->dest_info, | |
25 | sizeof(req_tdata->dest_info)); | |
26 | ||
27 | + /* Finally, copy the destination host name from the original request */ | |
28 | + pj_strdup(cancel_tdata->pool, &cancel_tdata->dest_info.name, | |
29 | + &req_tdata->dest_info.name); | |
30 | + | |
31 | /* Done. | |
32 | * Return the transmit buffer containing the CANCEL request. | |
33 | */ | |
34 | -- | |
35 | 2.25.1 | |
36 |
0 | diff --git a/pjmedia/src/pjmedia/sdp_neg.c b/pjmedia/src/pjmedia/sdp_neg.c | |
1 | index 3b85b4273..a14009662 100644 | |
2 | --- a/pjmedia/src/pjmedia/sdp_neg.c | |
3 | +++ b/pjmedia/src/pjmedia/sdp_neg.c | |
4 | @@ -304,7 +304,6 @@ PJ_DEF(pj_status_t) pjmedia_sdp_neg_modify_local_offer2( | |
5 | { | |
6 | pjmedia_sdp_session *new_offer; | |
7 | pjmedia_sdp_session *old_offer; | |
8 | - char media_used[PJMEDIA_MAX_SDP_MEDIA]; | |
9 | unsigned oi; /* old offer media index */ | |
10 | pj_status_t status; | |
11 | ||
12 | @@ -323,8 +322,19 @@ PJ_DEF(pj_status_t) pjmedia_sdp_neg_modify_local_offer2( | |
13 | /* Change state to STATE_LOCAL_OFFER */ | |
14 | neg->state = PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER; | |
15 | ||
16 | + /* When there is no active local SDP in state PJMEDIA_SDP_NEG_STATE_DONE, | |
17 | + * it means that the previous initial SDP nego must have been failed, | |
18 | + * so we'll just set the local SDP offer here. | |
19 | + */ | |
20 | + if (!neg->active_local_sdp) { | |
21 | + neg->initial_sdp_tmp = NULL; | |
22 | + neg->initial_sdp = pjmedia_sdp_session_clone(pool, local); | |
23 | + neg->neg_local_sdp = pjmedia_sdp_session_clone(pool, local); | |
24 | + | |
25 | + return PJ_SUCCESS; | |
26 | + } | |
27 | + | |
28 | /* Init vars */ | |
29 | - pj_bzero(media_used, sizeof(media_used)); | |
30 | old_offer = neg->active_local_sdp; | |
31 | new_offer = pjmedia_sdp_session_clone(pool, local); | |
32 |