Commit ea04aadb33 for asterisk.org
commit ea04aadb331c046d2e6334f89d2b829cfbeb650d
Author: Tinet-mucw <mucw@ti-net.com.cn>
Date: Wed Aug 26 18:13:41 2026 -0700
apps/app_chanspy: don't delay spyee Hangup when spy channel has no reverse media
channel_spy() waited indefinitely on the spy channel, so after the spyee
hung up the spy audiohook leaving RUNNING was not noticed until waitfor
timed out. That kept an autochan reference on the spyee and delayed its
destructor / Hangup.
Poll with a short timeout instead. On timeout, only re-check hook status;
call ast_read() only when the spy channel is readable.
Resolves: #2123
diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c
index adcd72df20..b9a9f39b3c 100644
--- a/apps/app_chanspy.c
+++ b/apps/app_chanspy.c
@@ -811,14 +811,23 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto
channel has gone away.
*/
- /* Note: it is very important that the ast_waitfor() be the first
- condition in this expression, so that if we wait for some period
- of time before receiving a frame from our spying channel, we check
- for hangup on the spied-on channel _after_ knowing that a frame
- has arrived, since the spied-on channel could have gone away while
- we were waiting
+ /* Use a short waitfor timeout so we notice the spy audiohook leaving
+ RUNNING promptly. An indefinite wait holds an autochan ref on the
+ spyee until waitfor times out, delaying destructor / Hangup when
+ the spy channel is not readable.
*/
- while (ast_waitfor(chan, -1) > -1 && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
+ while (csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
+ int waitres = ast_waitfor(chan, 100);
+
+ if (waitres < 0) {
+ running = -1;
+ break;
+ }
+ if (waitres == 0) {
+ /* Timeout: re-check hook status without reading. */
+ continue;
+ }
+
if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
running = -1;
if (f) {