summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Michelson <mmichelson@digium.com>2012-11-07 19:15:26 +0000
committerMark Michelson <mmichelson@digium.com>2012-11-07 19:15:26 +0000
commitf2bb9afe17ee3e321a2d853dbfed4a93a67c25ca (patch)
treee86066d0a7b10defce1f17b3e2038527555f92e9
parent6ad0126425993bd9c9c73b0c05a52984cbcadc5d (diff)
Multiple revisions 375993-375994
........ r375993 | mmichelson | 2012-11-07 11:01:13 -0600 (Wed, 07 Nov 2012) | 30 lines Fix misuses of timeouts throughout the code. Prior to this change, a common method for determining if a timeout was reached was to call a function such as ast_waitfor_n() and inspect the out parameter that told how many milliseconds were left, then use that as the input to ast_waitfor_n() on the next go-around. The problem with this is that in some cases, submillisecond timeouts can occur, resulting in the out parameter not decreasing any. When this happens thousands of times, the result is that the timeout takes much longer than intended to be reached. As an example, I had a situation where a 3 second timeout took multiple days to finally end since most wakeups from ast_waitfor_n() were under a millisecond. This patch seeks to fix this pattern throughout the code. Now we log the time when an operation began and find the difference in wall clock time between now and when the event started. This means that sub-millisecond timeouts now cannot play havoc when trying to determine if something has timed out. Part of this fix also includes changing the function ast_waitfor() so that it is possible for it to return less than zero when a negative timeout is given to it. This makes it actually possible to detect errors in ast_waitfor() when there is no timeout. (closes issue ASTERISK-20414) reported by David M. Lee Review: https://reviewboard.asterisk.org/r/2135/ ........ r375994 | mmichelson | 2012-11-07 11:08:44 -0600 (Wed, 07 Nov 2012) | 3 lines Remove some debugging that accidentally made it in the last commit. ........ Merged revisions 375993-375994 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 375995 from http://svn.asterisk.org/svn/asterisk/branches/10 ........ Merged revisions 376014 from http://svn.asterisk.org/svn/asterisk/branches/11 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@376015 65c4cc65-6c06-0410-ace0-fbb531ad65f3
-rw-r--r--apps/app_dial.c14
-rw-r--r--apps/app_jack.c4
-rw-r--r--apps/app_meetme.c2
-rw-r--r--apps/app_queue.c24
-rw-r--r--apps/app_record.c27
-rw-r--r--apps/app_waitforring.c25
-rw-r--r--channels/chan_agent.c14
-rw-r--r--channels/chan_dahdi.c42
-rw-r--r--channels/chan_iax2.c14
-rw-r--r--channels/sig_analog.c22
-rw-r--r--channels/sig_pri.c12
-rw-r--r--include/asterisk/channel.h4
-rw-r--r--include/asterisk/time.h14
-rw-r--r--main/channel.c76
-rw-r--r--main/pbx.c10
-rw-r--r--main/rtp_engine.c16
-rw-r--r--main/utils.c17
-rw-r--r--res/res_fax.c127
18 files changed, 306 insertions, 158 deletions
diff --git a/apps/app_dial.c b/apps/app_dial.c
index 310326dc1..b162a4127 100644
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -1116,6 +1116,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
int is_cc_recall;
int cc_frame_received = 0;
int num_ringing = 0;
+ struct timeval start = ast_tvnow();
ast_party_connected_line_init(&connected_caller);
if (single) {
@@ -1158,7 +1159,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
}
#endif
- while (*to && !peer) {
+ while ((*to = ast_remaining_ms(start, orig)) && !peer) {
struct chanlist *o;
int pos = 0; /* how many channels do we handle */
int numlines = prestart;
@@ -1702,10 +1703,13 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
skip_frame:;
ast_frfree(f);
}
- if (!*to)
- ast_verb(3, "Nobody picked up in %d ms\n", orig);
- if (!*to || ast_check_hangup(in))
- ast_cdr_noanswer(ast_channel_cdr(in));
+ }
+
+ if (!*to) {
+ ast_verb(3, "Nobody picked up in %d ms\n", orig);
+ }
+ if (!*to || ast_check_hangup(in)) {
+ ast_cdr_noanswer(ast_channel_cdr(in));
}
#ifdef HAVE_EPOLL
diff --git a/apps/app_jack.c b/apps/app_jack.c
index 10964f462..d1bdfa38f 100644
--- a/apps/app_jack.c
+++ b/apps/app_jack.c
@@ -768,7 +768,9 @@ static int jack_exec(struct ast_channel *chan, const char *data)
while (!jack_data->stop) {
struct ast_frame *f;
- ast_waitfor(chan, -1);
+ if (ast_waitfor(chan, -1) < 0) {
+ break;
+ }
f = ast_read(chan);
if (!f) {
diff --git a/apps/app_meetme.c b/apps/app_meetme.c
index c2bfccd03..da66c5941 100644
--- a/apps/app_meetme.c
+++ b/apps/app_meetme.c
@@ -1917,7 +1917,7 @@ static void conf_flush(int fd, struct ast_channel *chan)
/* when no frames are available, this will wait
for 1 millisecond maximum
*/
- while (ast_waitfor(chan, 1)) {
+ while (ast_waitfor(chan, 1) > 0) {
f = ast_read(chan);
if (f)
ast_frfree(f);
diff --git a/apps/app_queue.c b/apps/app_queue.c
index a6ec76616..775f34348 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -4052,6 +4052,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
#endif
struct ast_party_connected_line connected_caller;
char *inchan_name;
+ struct timeval start_time_tv = ast_tvnow();
ast_party_connected_line_init(&connected_caller);
@@ -4068,7 +4069,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
}
#endif
- while (*to && !peer) {
+ while ((*to = ast_remaining_ms(start_time_tv, orig)) && !peer) {
int numlines, retry, pos = 1;
struct ast_channel *watchers[AST_MAX_WATCHERS];
watchers[0] = in;
@@ -4341,10 +4342,10 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
rna(endtime * 1000, qe, on, membername, qe->parent->autopausebusy);
if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
if (qe->parent->timeoutrestart) {
- *to = orig;
+ start_time_tv = ast_tvnow();
}
/* Have enough time for a queue member to answer? */
- if (*to > 500) {
+ if (ast_remaining_ms(start_time_tv, orig) > 500) {
ring_one(qe, outgoing, &numbusies);
starttime = (long) time(NULL);
}
@@ -4362,9 +4363,9 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
do_hang(o);
if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
if (qe->parent->timeoutrestart) {
- *to = orig;
+ start_time_tv = ast_tvnow();
}
- if (*to > 500) {
+ if (ast_remaining_ms(start_time_tv, orig) > 500) {
ring_one(qe, outgoing, &numbusies);
starttime = (long) time(NULL);
}
@@ -4457,9 +4458,9 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
do_hang(o);
if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
if (qe->parent->timeoutrestart) {
- *to = orig;
+ start_time_tv = ast_tvnow();
}
- if (*to > 500) {
+ if (ast_remaining_ms(start_time_tv, orig) > 500) {
ring_one(qe, outgoing, &numbusies);
starttime = (long) time(NULL);
}
@@ -4538,10 +4539,11 @@ skip_frame:;
ast_frfree(f);
}
- if (!*to) {
- for (o = start; o; o = o->call_next) {
- rna(orig, qe, o->interface, o->member->membername, 1);
- }
+ }
+
+ if (!*to) {
+ for (o = start; o; o = o->call_next) {
+ rna(orig, qe, o->interface, o->member->membername, 1);
}
if (ast_channel_cdr(in)
diff --git a/apps/app_record.c b/apps/app_record.c
index ff233d6a9..051f97bb8 100644
--- a/apps/app_record.c
+++ b/apps/app_record.c
@@ -160,7 +160,6 @@ static int record_exec(struct ast_channel *chan, const char *data)
int terminator = '#';
struct ast_format rfmt;
int ioflags;
- int waitres;
struct ast_silence_generator *silgen = NULL;
struct ast_flags flags = { 0, };
AST_DECLARE_APP_ARGS(args,
@@ -169,8 +168,11 @@ static int record_exec(struct ast_channel *chan, const char *data)
AST_APP_ARG(maxduration);
AST_APP_ARG(options);
);
+ int ms;
+ struct timeval start;
ast_format_clear(&rfmt);
+
/* The next few lines of code parse out the filename and header from the input string */
if (ast_strlen_zero(data)) { /* no data implies no filename or anything is present */
ast_log(LOG_WARNING, "Record requires an argument (filename)\n");
@@ -331,14 +333,15 @@ static int record_exec(struct ast_channel *chan, const char *data)
if (maxduration <= 0)
maxduration = -1;
- while ((waitres = ast_waitfor(chan, maxduration)) > -1) {
- if (maxduration > 0) {
- if (waitres == 0) {
- gottimeout = 1;
- pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "TIMEOUT");
- break;
- }
- maxduration = waitres;
+ start = ast_tvnow();
+ while ((ms = ast_remaining_ms(start, maxduration))) {
+ ms = ast_waitfor(chan, ms);
+ if (ms < 0) {
+ break;
+ }
+
+ if (maxduration > 0 && ms == 0) {
+ break;
}
f = ast_read(chan);
@@ -390,6 +393,12 @@ static int record_exec(struct ast_channel *chan, const char *data)
}
ast_frfree(f);
}
+
+ if (maxduration > 0 && !ms) {
+ gottimeout = 1;
+ pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "TIMEOUT");
+ }
+
if (!f) {
ast_debug(1, "Got hangup\n");
res = -1;
diff --git a/apps/app_waitforring.c b/apps/app_waitforring.c
index bd0353b07..fc02de303 100644
--- a/apps/app_waitforring.c
+++ b/apps/app_waitforring.c
@@ -63,22 +63,29 @@ static int waitforring_exec(struct ast_channel *chan, const char *data)
struct ast_silence_generator *silgen = NULL;
int res = 0;
double s;
+ int timeout_ms;
int ms;
+ struct timeval start = ast_tvnow();
if (!data || (sscanf(data, "%30lg", &s) != 1)) {
ast_log(LOG_WARNING, "WaitForRing requires an argument (minimum seconds)\n");
return 0;
}
+ if (s < 0.0) {
+ ast_log(LOG_WARNING, "Invalid timeout provided for WaitForRing (%lg)\n", s);
+ return 0;
+ }
+
if (ast_opt_transmit_silence) {
silgen = ast_channel_start_silence_generator(chan);
}
- ms = s * 1000.0;
- while (ms > 0) {
+ timeout_ms = s * 1000.0;
+ while ((ms = ast_remaining_ms(start, timeout_ms))) {
ms = ast_waitfor(chan, ms);
if (ms < 0) {
- res = ms;
+ res = -1;
break;
}
if (ms > 0) {
@@ -95,14 +102,12 @@ static int waitforring_exec(struct ast_channel *chan, const char *data)
}
/* Now we're really ready for the ring */
if (!res) {
- ms = 99999999;
- while(ms > 0) {
- ms = ast_waitfor(chan, ms);
- if (ms < 0) {
- res = ms;
+ for (;;) {
+ int wait_res = ast_waitfor(chan, -1);
+ if (wait_res < 0) {
+ res = -1;
break;
- }
- if (ms > 0) {
+ } else {
f = ast_read(chan);
if (!f) {
res = -1;
diff --git a/channels/chan_agent.c b/channels/chan_agent.c
index 1c68d1187..0f0c4d288 100644
--- a/channels/chan_agent.c
+++ b/channels/chan_agent.c
@@ -1046,6 +1046,8 @@ static int agent_ack_sleep(void *data)
int res=0;
int to = 1000;
struct ast_frame *f;
+ struct timeval start = ast_tvnow();
+ int ms;
/* Wait a second and look for something */
@@ -1053,12 +1055,14 @@ static int agent_ack_sleep(void *data)
if (!p->chan)
return -1;
- for(;;) {
- to = ast_waitfor(p->chan, to);
- if (to < 0)
+ while ((ms = ast_remaining_ms(start, to))) {
+ ms = ast_waitfor(p->chan, ms);
+ if (ms < 0) {
return -1;
- if (!to)
+ }
+ if (ms == 0) {
return 0;
+ }
f = ast_read(p->chan);
if (!f)
return -1;
@@ -1078,7 +1082,7 @@ static int agent_ack_sleep(void *data)
ast_mutex_unlock(&p->lock);
res = 0;
}
- return res;
+ return 0;
}
static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index b69bf3f07..ce2d23325 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -6240,6 +6240,7 @@ static int dahdi_accept_r2_call_exec(struct ast_channel *chan, const char *data)
if (res == 0) {
continue;
}
+ res = 0;
f = ast_read(chan);
if (!f) {
ast_debug(1, "No frame read on channel %s, going out ...\n", ast_channel_name(chan));
@@ -7411,6 +7412,7 @@ static enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_ch
int priority = 0;
struct ast_channel *oc0, *oc1;
enum ast_bridge_result res;
+ struct timeval start = ast_tvnow();
#ifdef PRI_2BCT
int triedtopribridge = 0;
q931_call *q931c0;
@@ -7629,6 +7631,7 @@ static enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_ch
for (;;) {
struct ast_channel *c0_priority[2] = {c0, c1};
struct ast_channel *c1_priority[2] = {c1, c0};
+ int ms;
/* Here's our main loop... Start by locking things, looking for private parts,
and then balking if anything is wrong */
@@ -7645,8 +7648,8 @@ static enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_ch
ast_channel_unlock(c0);
ast_channel_unlock(c1);
-
- if (!timeoutms ||
+ ms = ast_remaining_ms(start, timeoutms);
+ if (!ms ||
(op0 != p0) ||
(op1 != p1) ||
(ofd0 != ast_channel_fd(c0, 0)) ||
@@ -7694,7 +7697,7 @@ static enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_ch
}
#endif
- who = ast_waitfor_n(priority ? c0_priority : c1_priority, 2, &timeoutms);
+ who = ast_waitfor_n(priority ? c0_priority : c1_priority, 2, &ms);
if (!who) {
ast_debug(1, "Ooh, empty read...\n");
continue;
@@ -10756,6 +10759,9 @@ static void *analog_ss_thread(void *data)
/* If set to use DTMF CID signalling, listen for DTMF */
if (p->cid_signalling == CID_SIG_DTMF) {
int k = 0;
+ int off_ms;
+ struct timeval start = ast_tvnow();
+ int ms;
cs = NULL;
ast_debug(1, "Receiving DTMF cid on channel %s\n", ast_channel_name(chan));
dahdi_setlinear(p->subs[idx].dfd, 0);
@@ -10766,10 +10772,12 @@ static void *analog_ss_thread(void *data)
* can drop some of them.
*/
ast_set_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY);
- res = 4000;/* This is a typical OFF time between rings. */
+ off_ms = 4000;/* This is a typical OFF time between rings. */
for (;;) {
struct ast_frame *f;
- res = ast_waitfor(chan, res);
+
+ ms = ast_remaining_ms(start, off_ms);
+ res = ast_waitfor(chan, ms);
if (res <= 0) {
/*
* We do not need to restore the dahdi_setlinear()
@@ -10789,7 +10797,7 @@ static void *analog_ss_thread(void *data)
dtmfbuf[k++] = f->subclass.integer;
}
ast_debug(1, "CID got digit '%c'\n", f->subclass.integer);
- res = 4000;/* This is a typical OFF time between rings. */
+ start = ast_tvnow();
}
ast_frfree(f);
if (ast_channel_state(chan) == AST_STATE_RING ||
@@ -10812,6 +10820,9 @@ static void *analog_ss_thread(void *data)
} else if ((p->cid_signalling == CID_SIG_V23) || (p->cid_signalling == CID_SIG_V23_JP)) {
cs = callerid_new(p->cid_signalling);
if (cs) {
+ int off_ms;
+ struct timeval start;
+ int ms;
samples = 0;
#if 1
bump_gains(p);
@@ -10888,10 +10899,13 @@ static void *analog_ss_thread(void *data)
}
/* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */
- res = 4000;/* This is a typical OFF time between rings. */
+ start = ast_tvnow();
+ off_ms = 4000;/* This is a typical OFF time between rings. */
for (;;) {
struct ast_frame *f;
- res = ast_waitfor(chan, res);
+
+ ms = ast_remaining_ms(start, off_ms);
+ res = ast_waitfor(chan, ms);
if (res <= 0) {
ast_log(LOG_WARNING, "CID timed out waiting for ring. "
"Exiting simple switch\n");
@@ -11019,12 +11033,18 @@ static void *analog_ss_thread(void *data)
} else if (p->use_callerid && p->cid_start == CID_START_RING) {
if (p->cid_signalling == CID_SIG_DTMF) {
int k = 0;
+ int off_ms;
+ struct timeval start;
+ int ms;
cs = NULL;
dahdi_setlinear(p->subs[idx].dfd, 0);
- res = 2000;
+ off_ms = 2000;
+ start = ast_tvnow();
for (;;) {
struct ast_frame *f;
- res = ast_waitfor(chan, res);
+
+ ms = ast_remaining_ms(start, off_ms);
+ res = ast_waitfor(chan, ms);
if (res <= 0) {
ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
"Exiting simple switch\n");
@@ -11040,7 +11060,7 @@ static void *analog_ss_thread(void *data)
if (f->frametype == AST_FRAME_DTMF) {
dtmfbuf[k++] = f->subclass.integer;
ast_debug(1, "CID got digit '%c'\n", f->subclass.integer);
- res = 2000;
+ start = ast_tvnow();
}
ast_frfree(f);
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 272ad832b..758b2bca2 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -5627,6 +5627,11 @@ static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_cha
}
to = 1000;
who = ast_waitfor_n(cs, 2, &to);
+ /* XXX This will need to be updated to calculate
+ * timeout correctly once timeoutms is allowed to be
+ * > 0. Right now, this can go badly if the waitfor
+ * times out in less than a millisecond
+ */
if (timeoutms > -1) {
timeoutms -= (1000 - to);
if (timeoutms < 0)
@@ -13893,6 +13898,8 @@ static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *dat
/* By here we must have a dp */
if (dp->flags & CACHE_FLAG_PENDING) {
+ struct timeval start;
+ int ms;
/* Okay, here it starts to get nasty. We need a pipe now to wait
for a reply to come back so long as it's pending */
for (x = 0; x < ARRAY_LEN(dp->waiters); x++) {
@@ -13917,8 +13924,9 @@ static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *dat
if (chan)
old = ast_channel_defer_dtmf(chan);
doabort = 0;
- while(timeout) {
- c = ast_waitfor_nandfds(&chan, chan ? 1 : 0, &com[0], 1, NULL, &outfd, &timeout);
+ start = ast_tvnow();
+ while ((ms = ast_remaining_ms(start, timeout))) {
+ c = ast_waitfor_nandfds(&chan, chan ? 1 : 0, &com[0], 1, NULL, &outfd, &ms);
if (outfd > -1)
break;
if (!c)
@@ -13929,7 +13937,7 @@ static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *dat
}
ast_frfree(f);
}
- if (!timeout) {
+ if (!ms) {
ast_log(LOG_WARNING, "Timeout waiting for %s exten %s\n", data, exten);
}
AST_LIST_LOCK(&dpcache);
diff --git a/channels/sig_analog.c b/channels/sig_analog.c
index 395f1a520..593d033b4 100644
--- a/channels/sig_analog.c
+++ b/channels/sig_analog.c
@@ -2391,6 +2391,9 @@ static void *__analog_ss_thread(void *data)
if (p->cid_signalling == CID_SIG_DTMF) {
int k = 0;
int oldlinearity;
+ int timeout_ms;
+ int ms;
+ struct timeval start = ast_tvnow();
cs = NULL;
ast_debug(1, "Receiving DTMF cid on channel %s\n", ast_channel_name(chan));
@@ -2403,10 +2406,12 @@ static void *__analog_ss_thread(void *data)
* can drop some of them.
*/
ast_set_flag(ast_channel_flags(chan), AST_FLAG_END_DTMF_ONLY);
- res = 4000;/* This is a typical OFF time between rings. */
+ timeout_ms = 4000;/* This is a typical OFF time between rings. */
for (;;) {
struct ast_frame *f;
- res = ast_waitfor(chan, res);
+
+ ms = ast_remaining_ms(start, timeout_ms);
+ res = ast_waitfor(chan, ms);
if (res <= 0) {
/*
* We do not need to restore the analog_set_linear_mode()
@@ -2427,7 +2432,7 @@ static void *__analog_ss_thread(void *data)
dtmfbuf[k++] = f->subclass.integer;
}
ast_debug(1, "CID got digit '%c'\n", f->subclass.integer);
- res = 4000;/* This is a typical OFF time between rings. */
+ start = ast_tvnow();
}
ast_frfree(f);
if (ast_channel_state(chan) == AST_STATE_RING ||
@@ -2461,6 +2466,9 @@ static void *__analog_ss_thread(void *data)
numbuf[0] = 0;
if (!analog_start_cid_detect(p, p->cid_signalling)) {
+ int off_ms;
+ int ms;
+ struct timeval off_start;
while (1) {
res = analog_get_callerid(p, namebuf, numbuf, &ev, timeout - ast_tvdiff_ms(ast_tvnow(), start));
@@ -2498,10 +2506,12 @@ static void *__analog_ss_thread(void *data)
}
/* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */
- res = 4000;/* This is a typical OFF time between rings. */
- for (;;) {
+ off_start = ast_tvnow();
+ off_ms = 4000;/* This is a typical OFF time between rings. */
+ while ((ms = ast_remaining_ms(off_start, off_ms))) {
struct ast_frame *f;
- res = ast_waitfor(chan, res);
+
+ res = ast_waitfor(chan, ms);
if (res <= 0) {
ast_log(LOG_WARNING, "CID timed out waiting for ring. "
"Exiting simple switch\n");
diff --git a/channels/sig_pri.c b/channels/sig_pri.c
index 93a77efd7..e01ceadd3 100644
--- a/channels/sig_pri.c
+++ b/channels/sig_pri.c
@@ -1881,7 +1881,9 @@ static void *do_idle_thread(void *v_pvt)
struct ast_frame *f;
char ex[80];
/* Wait up to 30 seconds for an answer */
- int newms, ms = 30000;
+ int timeout_ms = 30000;
+ int ms;
+ struct timeval start;
struct ast_callid *callid;
if ((callid = ast_channel_callid(chan))) {
@@ -1896,7 +1898,12 @@ static void *do_idle_thread(void *v_pvt)
ast_hangup(chan);
return NULL;
}
- while ((newms = ast_waitfor(chan, ms)) > 0) {
+ start = ast_tvnow();
+ while ((ms = ast_remaining_ms(start, timeout_ms))) {
+ if (ast_waitfor(chan, ms) <= 0) {
+ break;
+ }
+
f = ast_read(chan);
if (!f) {
/* Got hangup */
@@ -1922,7 +1929,6 @@ static void *do_idle_thread(void *v_pvt)
};
}
ast_frfree(f);
- ms = newms;
}
/* Hangup the channel since nothing happend */
ast_hangup(chan);
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index ce9ef7aa2..0157d761e 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -1680,7 +1680,7 @@ int ast_is_deferrable_frame(const struct ast_frame *frame);
/*!
* \brief Wait for a specified amount of time, looking for hangups
* \param chan channel to wait for
- * \param ms length of time in milliseconds to sleep
+ * \param ms length of time in milliseconds to sleep. This should never be less than zero.
* \details
* Waits for a specified amount of time, servicing the channel as required.
* \return returns -1 on hangup, otherwise 0.
@@ -1690,7 +1690,7 @@ int ast_safe_sleep(struct ast_channel *chan, int ms);
/*!
* \brief Wait for a specified amount of time, looking for hangups and a condition argument
* \param chan channel to wait for
- * \param ms length of time in milliseconds to sleep
+ * \param ms length of time in milliseconds to sleep.
* \param cond a function pointer for testing continue condition
* \param data argument to be passed to the condition test function
* \return returns -1 on hangup, otherwise 0.
diff --git a/include/asterisk/time.h b/include/asterisk/time.h
index 4fa08723b..dd68db704 100644
--- a/include/asterisk/time.h
+++ b/include/asterisk/time.h
@@ -152,6 +152,20 @@ struct timeval ast_tvadd(struct timeval a, struct timeval b);
struct timeval ast_tvsub(struct timeval a, struct timeval b);
/*!
+ * \brief Calculate remaining milliseconds given a starting timestamp
+ * and upper bound
+ *
+ * If the upper bound is negative, then this indicates that there is no
+ * upper bound on the amount of time to wait. This will result in a
+ * negative return.
+ *
+ * \param start When timing started being calculated
+ * \param max_ms The maximum number of milliseconds to wait from start. May be negative.
+ * \return The number of milliseconds left to wait for. May be negative.
+ */
+int ast_remaining_ms(struct timeval start, int max_ms);
+
+/*!
* \brief Returns a timeval from sec, usec
*/
AST_INLINE_API(
diff --git a/main/channel.c b/main/channel.c
index 126e44cf6..9998225f0 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -1669,11 +1669,13 @@ int ast_is_deferrable_frame(const struct ast_frame *frame)
}
/*! \brief Wait, look for hangups and condition arg */
-int ast_safe_sleep_conditional(struct ast_channel *chan, int ms, int (*cond)(void*), void *data)
+int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*cond)(void*), void *data)
{
struct ast_frame *f;
struct ast_silence_generator *silgen = NULL;
int res = 0;
+ struct timeval start;
+ int ms;
AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames);
@@ -1683,8 +1685,10 @@ int ast_safe_sleep_conditional(struct ast_channel *chan, int ms, int (*cond)(voi
silgen = ast_channel_start_silence_generator(chan);
}
- while (ms > 0) {
+ start = ast_tvnow();
+ while ((ms = ast_remaining_ms(start, timeout_ms))) {
struct ast_frame *dup_f = NULL;
+
if (cond && ((*cond)(data) == 0)) {
break;
}
@@ -3005,12 +3009,15 @@ int __ast_answer(struct ast_channel *chan, unsigned int delay, int cdr_answer)
do {
AST_LIST_HEAD_NOLOCK(, ast_frame) frames;
struct ast_frame *cur, *new;
- int ms = MAX(delay, 500);
+ int timeout_ms = MAX(delay, 500);
unsigned int done = 0;
+ struct timeval start;
AST_LIST_HEAD_INIT_NOLOCK(&frames);
+ start = ast_tvnow();
for (;;) {
+ int ms = ast_remaining_ms(start, timeout_ms);
ms = ast_waitfor(chan, ms);
if (ms < 0) {
ast_log(LOG_WARNING, "Error condition occurred when polling channel %s for a voice frame: %s\n", ast_channel_name(chan), strerror(errno));
@@ -3568,11 +3575,13 @@ struct ast_channel *ast_waitfor_n(struct ast_channel **c, int n, int *ms)
int ast_waitfor(struct ast_channel *c, int ms)
{
- int oldms = ms; /* -1 if no timeout */
-
- ast_waitfor_nandfds(&c, 1, NULL, 0, NULL, NULL, &ms);
- if ((ms < 0) && (oldms < 0)) {
- ms = 0;
+ if (ms < 0) {
+ do {
+ ms = 100000;
+ ast_waitfor_nandfds(&c, 1, NULL, 0, NULL, NULL, &ms);
+ } while (!ms);
+ } else {
+ ast_waitfor_nandfds(&c, 1, NULL, 0, NULL, NULL, &ms);
}
return ms;
}
@@ -3628,6 +3637,7 @@ int ast_settimeout(struct ast_channel *c, unsigned int rate, int (*func)(const v
int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, int cmdfd)
{
struct timeval start = ast_tvnow();
+ int ms;
/* Stop if we're a zombie or need a soft hangup */
if (ast_test_flag(ast_channel_flags(c), AST_FLAG_ZOMBIE) || ast_check_hangup(c))
@@ -3639,19 +3649,9 @@ int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, in
/* Wait for a digit, no more than timeout_ms milliseconds total.
* Or, wait indefinitely if timeout_ms is <0.
*/
- while (ast_tvdiff_ms(ast_tvnow(), start) < timeout_ms || timeout_ms < 0) {
+ while ((ms = ast_remaining_ms(start, timeout_ms))) {
struct ast_channel *rchan;
- int outfd=-1;
- int ms;
-
- if (timeout_ms < 0) {
- ms = timeout_ms;
- } else {
- ms = timeout_ms - ast_tvdiff_ms(ast_tvnow(), start);
- if (ms < 0) {
- ms = 0;
- }
- }
+ int outfd = -1;
errno = 0;
/* While ast_waitfor_nandfds tries to help by reducing the timeout by how much was waited,
@@ -4690,25 +4690,32 @@ int ast_recvchar(struct ast_channel *chan, int timeout)
char *ast_recvtext(struct ast_channel *chan, int timeout)
{
- int res, done = 0;
+ int res;
char *buf = NULL;
+ struct timeval start = ast_tvnow();
+ int ms;
- while (!done) {
+ while ((ms = ast_remaining_ms(start, timeout))) {
struct ast_frame *f;
- if (ast_check_hangup(chan))
+
+ if (ast_check_hangup(chan)) {
break;
- res = ast_waitfor(chan, timeout);
- if (res <= 0) /* timeout or error */
+ }
+ res = ast_waitfor(chan, ms);
+ if (res <= 0) {/* timeout or error */
break;
- timeout = res; /* update timeout */
+ }
f = ast_read(chan);
- if (f == NULL)
+ if (f == NULL) {
break; /* no frame */
- if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_HANGUP)
- done = 1; /* force a break */
- else if (f->frametype == AST_FRAME_TEXT) { /* what we want */
+ }
+ if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_HANGUP) {
+ ast_frfree(f);
+ break;
+ } else if (f->frametype == AST_FRAME_TEXT) { /* what we want */
buf = ast_strndup((char *) f->data.ptr, f->datalen); /* dup and break */
- done = 1;
+ ast_frfree(f);
+ break;
}
ast_frfree(f);
}
@@ -5724,18 +5731,19 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c
if (ast_call(chan, addr, 0)) { /* ast_call failed... */
ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, addr);
} else {
+ struct timeval start = ast_tvnow();
res = 1; /* mark success in case chan->_state is already AST_STATE_UP */
while (timeout && ast_channel_state(chan) != AST_STATE_UP) {
struct ast_frame *f;
- res = ast_waitfor(chan, timeout);
+ int ms = ast_remaining_ms(start, timeout);
+
+ res = ast_waitfor(chan, ms);
if (res == 0) { /* timeout, treat it like ringing */
*outstate = AST_CONTROL_RINGING;
break;
}
if (res < 0) /* error or done */
break;
- if (timeout > -1)
- timeout = res;
if (!ast_strlen_zero(ast_channel_call_forward(chan))) {
if (!(chan = ast_call_forward(NULL, chan, NULL, cap, oh, outstate))) {
return NULL;
diff --git a/main/pbx.c b/main/pbx.c
index 375c232ea..ba66fcac5 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -9767,6 +9767,8 @@ static void *async_wait(void *data)
struct ast_frame *f;
struct ast_app *app;
int have_early_media = 0;
+ struct timeval start = ast_tvnow();
+ int ms;
if (chan) {
struct ast_callid *callid = ast_channel_callid(chan);
@@ -9776,12 +9778,12 @@ static void *async_wait(void *data)
}
}
- while (timeout && (ast_channel_state(chan) != AST_STATE_UP)) {
- res = ast_waitfor(chan, timeout);
+ while ((ms = ast_remaining_ms(start, timeout)) &&
+ ast_channel_state(chan) != AST_STATE_UP) {
+ res = ast_waitfor(chan, ms);
if (res < 1)
break;
- if (timeout > -1)
- timeout = res;
+
f = ast_read(chan);
if (!f)
break;
diff --git a/main/rtp_engine.c b/main/rtp_engine.c
index 55ca0f2b7..29c9286a1 100644
--- a/main/rtp_engine.c
+++ b/main/rtp_engine.c
@@ -949,6 +949,7 @@ static enum ast_bridge_result local_bridge_loop(struct ast_channel *c0, struct a
enum ast_bridge_result res = AST_BRIDGE_FAILED;
struct ast_channel *who = NULL, *other = NULL, *cs[3] = { NULL, };
struct ast_frame *fr = NULL;
+ struct timeval start;
/* Start locally bridging both instances */
if (instance0->engine->local_bridge && instance0->engine->local_bridge(instance0, instance1)) {
@@ -979,7 +980,9 @@ static enum ast_bridge_result local_bridge_loop(struct ast_channel *c0, struct a
cs[0] = c0;
cs[1] = c1;
cs[2] = NULL;
+ start = ast_tvnow();
for (;;) {
+ int ms;
/* If the underlying formats have changed force this bridge to break */
if ((ast_format_cmp(ast_channel_rawreadformat(c0), ast_channel_rawwriteformat(c1)) == AST_FORMAT_CMP_NOT_EQUAL) ||
(ast_format_cmp(ast_channel_rawreadformat(c1), ast_channel_rawwriteformat(c0)) == AST_FORMAT_CMP_NOT_EQUAL)) {
@@ -1005,8 +1008,9 @@ static enum ast_bridge_result local_bridge_loop(struct ast_channel *c0, struct a
break;
}
/* Wait on a channel to feed us a frame */
- if (!(who = ast_waitfor_n(cs, 2, &timeoutms))) {
- if (!timeoutms) {
+ ms = ast_remaining_ms(start, timeoutms);
+ if (!(who = ast_waitfor_n(cs, 2, &ms))) {
+ if (!ms) {
res = AST_BRIDGE_RETRY;
break;
}
@@ -1145,6 +1149,7 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0,
struct ast_sockaddr ac1 = {{0,}}, vac1 = {{0,}}, tac1 = {{0,}}, ac0 = {{0,}}, vac0 = {{0,}}, tac0 = {{0,}};
struct ast_sockaddr t1 = {{0,}}, vt1 = {{0,}}, tt1 = {{0,}}, t0 = {{0,}}, vt0 = {{0,}}, tt0 = {{0,}};
struct ast_frame *fr = NULL;
+ struct timeval start;
if (!oldcap0 || !oldcap1) {
ast_channel_unlock(c0);
@@ -1189,7 +1194,9 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0,
cs[0] = c0;
cs[1] = c1;
cs[2] = NULL;
+ start = ast_tvnow();
for (;;) {
+ int ms;
/* Check if anything changed */
if ((ast_channel_tech_pvt(c0) != pvt0) ||
(ast_channel_tech_pvt(c1) != pvt1) ||
@@ -1284,9 +1291,10 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0,
ast_format_cap_copy(oldcap0, cap0);
}
+ ms = ast_remaining_ms(start, timeoutms);
/* Wait for frame to come in on the channels */
- if (!(who = ast_waitfor_n(cs, 2, &timeoutms))) {
- if (!timeoutms) {
+ if (!(who = ast_waitfor_n(cs, 2, &ms))) {
+ if (!ms) {
res = AST_BRIDGE_RETRY;
break;
}
diff --git a/main/utils.c b/main/utils.c
index 0ff33cba2..3476729ce 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -1470,6 +1470,23 @@ struct timeval ast_tvsub(struct timeval a, struct timeval b)
}
return a;
}
+
+int ast_remaining_ms(struct timeval start, int max_ms)
+{
+ int ms;
+
+ if (max_ms < 0) {
+ ms = max_ms;
+ } else {
+ ms = max_ms - ast_tvdiff_ms(ast_tvnow(), start);
+ if (ms < 0) {
+ ms = 0;
+ }
+ }
+
+ return ms;
+}
+
#undef ONE_MILLION
/*! \brief glibc puts a lock inside random(3), so that the results are thread-safe.
diff --git a/res/res_fax.c b/res/res_fax.c
index cc3e23fe6..32225d32d 100644
--- a/res/res_fax.c
+++ b/res/res_fax.c
@@ -1262,9 +1262,11 @@ static int set_fax_t38_caps(struct ast_channel *chan, struct ast_fax_session_det
static int disable_t38(struct ast_channel *chan)
{
- int ms;
+ int timeout_ms;
struct ast_frame *frame = NULL;
struct ast_control_t38_parameters t38_parameters = { .request_response = AST_T38_REQUEST_TERMINATE, };
+ struct timeval start;
+ int ms;
ast_debug(1, "Shutting down T.38 on %s\n", ast_channel_name(chan));
if (ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) != 0) {
@@ -1273,20 +1275,19 @@ static int disable_t38(struct ast_channel *chan)
}
/* wait up to five seconds for negotiation to complete */
- ms = 5000;
-
- while (ms > 0) {
+ timeout_ms = 5000;
+ start = ast_tvnow();
+ while ((ms = ast_remaining_ms(start, timeout_ms))) {
ms = ast_waitfor(chan, ms);
+
+ if (ms == 0) {
+ break;
+ }
if (ms < 0) {
ast_debug(1, "error while disabling T.38 on channel '%s'\n", ast_channel_name(chan));
return -1;
}
- if (ms == 0) { /* all done, nothing happened */
- ast_debug(1, "channel '%s' timed-out during T.38 shutdown\n", ast_channel_name(chan));
- break;
- }
-
if (!(frame = ast_read(chan))) {
return -1;
}
@@ -1314,6 +1315,10 @@ static int disable_t38(struct ast_channel *chan)
ast_frfree(frame);
}
+ if (ms == 0) { /* all done, nothing happened */
+ ast_debug(1, "channel '%s' timed-out during T.38 shutdown\n", ast_channel_name(chan));
+ }
+
return 0;
}
@@ -1322,7 +1327,7 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det
{
int ms;
int timeout = RES_FAX_TIMEOUT;
- int res = 0, chancount;
+ int res, chancount;
unsigned int expected_frametype = -1;
union ast_frame_subclass expected_framesubclass = { .integer = -1 };
unsigned int t38negotiated = (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED);
@@ -1333,6 +1338,8 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det
struct ast_channel *c = chan;
struct ast_format orig_write_format;
struct ast_format orig_read_format;
+ int remaining_time;
+ struct timeval start;
ast_format_clear(&orig_write_format);
ast_format_clear(&orig_read_format);
@@ -1413,8 +1420,9 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det
ast_debug(5, "channel %s will wait on FAX fd %d\n", ast_channel_name(chan), fax->fd);
/* handle frames for the session */
- ms = 1000;
- while ((res > -1) && (ms > -1) && (timeout > 0)) {
+ remaining_time = timeout;
+ start = ast_tvnow();
+ while (remaining_time > 0) {
struct ast_channel *ready_chan;
int ofd, exception;
@@ -1431,7 +1439,7 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det
GENERIC_FAX_EXEC_SET_VARS(fax, chan, "HANGUP", "remote channel hungup");
c = NULL;
chancount = 0;
- timeout -= (1000 - ms);
+ remaining_time = ast_remaining_ms(start, timeout);
fax->tech->cancel_session(fax);
if (fax->tech->generate_silence) {
fax->tech->generate_silence(fax);
@@ -1500,7 +1508,7 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det
fax->tech->write(fax, frame);
fax->frames_received++;
}
- timeout = RES_FAX_TIMEOUT;
+ start = ast_tvnow();
}
ast_frfree(frame);
} else if (ofd == fax->fd) {
@@ -1517,36 +1525,30 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det
ast_write(chan, frame);
fax->frames_sent++;
ast_frfree(frame);
- timeout = RES_FAX_TIMEOUT;
+ start = ast_tvnow();
} else {
if (ms && (ofd < 0)) {
if ((errno == 0) || (errno == EINTR)) {
- timeout -= (1000 - ms);
- if (timeout <= 0)
+ remaining_time = ast_remaining_ms(start, timeout);
+ if (remaining_time <= 0)
GENERIC_FAX_EXEC_ERROR(fax, chan, "TIMEOUT", "fax session timed-out");
continue;
} else {
ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", ast_channel_name(chan));
GENERIC_FAX_EXEC_ERROR(fax, chan, "UNKNOWN", "error polling data");
- res = ms;
break;
}
} else {
/* nothing happened */
- if (timeout > 0) {
- timeout -= 1000;
- if (timeout <= 0)
- GENERIC_FAX_EXEC_ERROR(fax, chan, "TIMEOUT", "fax session timed-out");
- continue;
- } else {
- ast_log(LOG_WARNING, "channel '%s' timed-out during the FAX transmission.\n", ast_channel_name(chan));
+ remaining_time = ast_remaining_ms(start, timeout);
+ if (remaining_time <= 0) {
GENERIC_FAX_EXEC_ERROR(fax, chan, "TIMEOUT", "fax session timed-out");
break;
}
}
}
}
- ast_debug(3, "channel '%s' - event loop stopped { timeout: %d, ms: %d, res: %d }\n", ast_channel_name(chan), timeout, ms, res);
+ ast_debug(3, "channel '%s' - event loop stopped { timeout: %d, remaining_time: %d }\n", ast_channel_name(chan), timeout, remaining_time);
set_channel_variables(chan, details);
@@ -1580,9 +1582,11 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det
static int receivefax_t38_init(struct ast_channel *chan, struct ast_fax_session_details *details)
{
- int ms;
+ int timeout_ms;
struct ast_frame *frame = NULL;
struct ast_control_t38_parameters t38_parameters;
+ struct timeval start;
+ int ms;
/* don't send any audio if we've already received a T.38 reinvite */
if (ast_channel_get_t38_state(chan) != T38_STATE_NEGOTIATING) {
@@ -1592,9 +1596,11 @@ static int receivefax_t38_init(struct ast_channel *chan, struct ast_fax_session_
return -1;
}
- ms = 3000;
- while (ms > 0) {
+ timeout_ms = 3000;
+ start = ast_tvnow();
+ while ((ms = ast_remaining_ms(start, timeout_ms))) {
ms = ast_waitfor(chan, ms);
+
if (ms < 0) {
ast_log(LOG_ERROR, "error while generating CED tone on %s\n", ast_channel_name(chan));
ast_playtones_stop(chan);
@@ -1651,7 +1657,7 @@ static int receivefax_t38_init(struct ast_channel *chan, struct ast_fax_session_
ast_debug(1, "Negotiating T.38 for receive on %s\n", ast_channel_name(chan));
/* wait up to five seconds for negotiation to complete */
- ms = 5000;
+ timeout_ms = 5000;
/* set parameters based on the session's parameters */
t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
@@ -1660,13 +1666,15 @@ static int receivefax_t38_init(struct ast_channel *chan, struct ast_fax_session_
return -1;
}
- while (ms > 0) {
+ start = ast_tvnow();
+ while ((ms = ast_remaining_ms(start, timeout_ms))) {
+ int break_loop = 0;
+
ms = ast_waitfor(chan, ms);
if (ms < 0) {
ast_log(LOG_WARNING, "error on '%s' while waiting for T.38 negotiation.\n", ast_channel_name(chan));
return -1;
}
-
if (ms == 0) { /* all done, nothing happened */
ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", ast_channel_name(chan));
details->caps &= ~AST_FAX_TECH_T38;
@@ -1694,21 +1702,24 @@ static int receivefax_t38_init(struct ast_channel *chan, struct ast_fax_session_
t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
details->caps &= ~AST_FAX_TECH_AUDIO;
report_fax_status(chan, details, "T.38 Negotiated");
- ms = 0;
+ break_loop = 1;
break;
case AST_T38_REFUSED:
ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", ast_channel_name(chan));
details->caps &= ~AST_FAX_TECH_T38;
- ms = 0;
+ break_loop = 1;
break;
default:
ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", ast_channel_name(chan));
details->caps &= ~AST_FAX_TECH_T38;
- ms = 0;
+ break_loop = 1;
break;
}
}
ast_frfree(frame);
+ if (break_loop) {
+ break;
+ }
}
/* if T.38 was negotiated, we are done initializing */
@@ -1976,9 +1987,11 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
static int sendfax_t38_init(struct ast_channel *chan, struct ast_fax_session_details *details)
{
- int ms;
+ int timeout_ms;
struct ast_frame *frame = NULL;
struct ast_control_t38_parameters t38_parameters;
+ struct timeval start;
+ int ms;
/* send CNG tone while listening for the receiver to initiate a switch
* to T.38 mode; if they do, stop sending the CNG tone and proceed with
@@ -1986,7 +1999,7 @@ static int sendfax_t38_init(struct ast_channel *chan, struct ast_fax_session_det
*
* 10500 is enough time for 3 CNG tones
*/
- ms = 10500;
+ timeout_ms = 10500;
/* don't send any audio if we've already received a T.38 reinvite */
if (ast_channel_get_t38_state(chan) != T38_STATE_NEGOTIATING) {
@@ -1996,8 +2009,11 @@ static int sendfax_t38_init(struct ast_channel *chan, struct ast_fax_session_det
}
}
- while (ms > 0) {
+ start = ast_tvnow();
+ while ((ms = ast_remaining_ms(start, timeout_ms))) {
+ int break_loop = 0;
ms = ast_waitfor(chan, ms);
+
if (ms < 0) {
ast_log(LOG_ERROR, "error while generating CNG tone on %s\n", ast_channel_name(chan));
ast_playtones_stop(chan);
@@ -2034,13 +2050,16 @@ static int sendfax_t38_init(struct ast_channel *chan, struct ast_fax_session_det
t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
details->caps &= ~AST_FAX_TECH_AUDIO;
report_fax_status(chan, details, "T.38 Negotiated");
- ms = 0;
+ break_loop = 1;
break;
default:
break;
}
}
ast_frfree(frame);
+ if (break_loop) {
+ break;
+ }
}
ast_playtones_stop(chan);
@@ -2054,7 +2073,7 @@ static int sendfax_t38_init(struct ast_channel *chan, struct ast_fax_session_det
ast_debug(1, "Negotiating T.38 for send on %s\n", ast_channel_name(chan));
/* wait up to five seconds for negotiation to complete */
- ms = 5000;
+ timeout_ms = 5000;
/* set parameters based on the session's parameters */
t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
@@ -2063,13 +2082,15 @@ static int sendfax_t38_init(struct ast_channel *chan, struct ast_fax_session_det
return -1;
}
- while (ms > 0) {
+ start = ast_tvnow();
+ while ((ms = ast_remaining_ms(start, timeout_ms))) {
+ int break_loop = 0;
+
ms = ast_waitfor(chan, ms);
if (ms < 0) {
ast_log(LOG_WARNING, "error on '%s' while waiting for T.38 negotiation.\n", ast_channel_name(chan));
return -1;
}
-
if (ms == 0) { /* all done, nothing happened */
ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", ast_channel_name(chan));
details->caps &= ~AST_FAX_TECH_T38;
@@ -2097,21 +2118,24 @@ static int sendfax_t38_init(struct ast_channel *chan, struct ast_fax_session_det
t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
details->caps &= ~AST_FAX_TECH_AUDIO;
report_fax_status(chan, details, "T.38 Negotiated");
- ms = 0;
+ break_loop = 1;
break;
case AST_T38_REFUSED:
ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", ast_channel_name(chan));
details->caps &= ~AST_FAX_TECH_T38;
- ms = 0;
+ break_loop = 1;
break;
default:
ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", ast_channel_name(chan));
details->caps &= ~AST_FAX_TECH_T38;
- ms = 0;
+ break_loop = 1;
break;
}
}
ast_frfree(frame);
+ if (break_loop) {
+ break;
+ }
}
/* if T.38 was negotiated, we are done initializing */
@@ -2127,15 +2151,17 @@ static int sendfax_t38_init(struct ast_channel *chan, struct ast_fax_session_det
return -1;
}
- ms = 3500;
- while (ms > 0) {
+ timeout_ms = 3500;
+ start = ast_tvnow();
+ while ((ms = ast_remaining_ms(start, timeout_ms))) {
+ int break_loop = 0;
+
ms = ast_waitfor(chan, ms);
if (ms < 0) {
ast_log(LOG_ERROR, "error while generating second CNG tone on %s\n", ast_channel_name(chan));
ast_playtones_stop(chan);
return -1;
}
-
if (ms == 0) { /* all done, nothing happened */
break;
}
@@ -2166,13 +2192,16 @@ static int sendfax_t38_init(struct ast_channel *chan, struct ast_fax_session_det
t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
details->caps &= ~AST_FAX_TECH_AUDIO;
report_fax_status(chan, details, "T.38 Negotiated");
- ms = 0;
+ break_loop = 1;
break;
default:
break;
}
}
ast_frfree(frame);
+ if (break_loop) {
+ break;
+ }
}
ast_playtones_stop(chan);