]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Multiple revisions 375993-375994
authorMark Michelson <mmichelson@digium.com>
Wed, 7 Nov 2012 17:16:24 +0000 (17:16 +0000)
committerMark Michelson <mmichelson@digium.com>
Wed, 7 Nov 2012 17:16:24 +0000 (17:16 +0000)
........
  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

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/10@375995 65c4cc65-6c06-0410-ace0-fbb531ad65f3

18 files changed:
apps/app_dial.c
apps/app_jack.c
apps/app_meetme.c
apps/app_queue.c
apps/app_record.c
apps/app_waitforring.c
channels/chan_agent.c
channels/chan_dahdi.c
channels/chan_iax2.c
channels/sig_analog.c
channels/sig_pri.c
include/asterisk/channel.h
include/asterisk/time.h
main/channel.c
main/pbx.c
main/rtp_engine.c
main/utils.c
res/res_fax.c

index 247b4466a8518493babd14dbdc3fe874835afcaf..ac0574cb31eef297378e49bf91fe066c8c3cafb0 100644 (file)
@@ -1055,6 +1055,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) {
@@ -1095,7 +1096,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
                ast_poll_channel_add(in, epollo->chan);
 #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;
@@ -1626,10 +1627,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(in->cdr);
+       }
+
+       if (!*to) {
+               ast_verb(3, "Nobody picked up in %d ms\n", orig);
+       }
+       if (!*to || ast_check_hangup(in)) {
+               ast_cdr_noanswer(in->cdr);
        }
 
 #ifdef HAVE_EPOLL
index 7a20e63a9b89e0ea133d5272ce9655865cea4ff6..4841d407df8555e7cbfa39cc628ab20c2c8fbd38 100644 (file)
@@ -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) {
index c190192cc1648e31ab6f514ee087c79d41d926b0..9a0869475e41102e507412a2c50bd2fd0e7d940d 100644 (file)
@@ -1900,7 +1900,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);
index 96189f0e853dca560ebedbb38ca2063e4adf866e..f4aee6fdcf93995cf4430df4c7e594d727218fc8 100644 (file)
@@ -3642,6 +3642,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);
 
@@ -3656,8 +3657,8 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                        ast_poll_channel_add(in, epollo->chan);
        }
 #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;
@@ -3913,10 +3914,11 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                                        endtime -= starttime;
                                                        rna(endtime * 1000, qe, on, membername, 0);
                                                        if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
-                                                               if (qe->parent->timeoutrestart)
-                                                                       *to = orig;
+                                                               if (qe->parent->timeoutrestart) {
+                                                                       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);
                                                                }
@@ -3932,9 +3934,10 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                                        rna(endtime * 1000, qe, on, membername, 0);
                                                        do_hang(o);
                                                        if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
-                                                               if (qe->parent->timeoutrestart)
-                                                                       *to = orig;
-                                                               if (*to > 500) {
+                                                               if (qe->parent->timeoutrestart) {
+                                                                       start_time_tv = ast_tvnow();
+                                                               }
+                                                               if (ast_remaining_ms(start_time_tv, orig) > 500) {
                                                                        ring_one(qe, outgoing, &numbusies);
                                                                        starttime = (long) time(NULL);
                                                                }
@@ -4021,9 +4024,10 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                        rna(endtime * 1000, qe, on, membername, 1);
                                        do_hang(o);
                                        if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
-                                               if (qe->parent->timeoutrestart)
-                                                       *to = orig;
-                                               if (*to > 500) {
+                                               if (qe->parent->timeoutrestart) {
+                                                       start_time_tv = ast_tvnow();
+                                               }
+                                               if (ast_remaining_ms(start_time_tv, orig) > 500) {
                                                        ring_one(qe, outgoing, &numbusies);
                                                        starttime = (long) time(NULL);
                                                }
@@ -4094,9 +4098,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);
                }
        }
 
index 91fbd984b4333e63c8ecadcca839a8e579fffdbb..4c1bc14f35d0f34f0ca609d789dc0202f30b99da 100644 (file)
@@ -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;
index bd0353b074d15da07e0ea47ccd1f9e57b49f7b39..fc02de303ede0b752c252497a748d4d524862ba1 100644 (file)
@@ -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;
index 7bcff86f259d9f8a6813b76feae62dc5de5a7875..c3454ec2b023cb3cf0d7f5e0a7a54a1f477ec836 100644 (file)
@@ -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)
index ebf4eb7ddaa468a68cd6eb4bc4c8aa5a14937115..726c1f9bd22a4999733634ee72756d0640d4e6b4 100644 (file)
@@ -6129,6 +6129,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", chan->name);
@@ -7300,6 +7301,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;
@@ -7521,6 +7523,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 */
@@ -7540,8 +7543,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 != c0->fds[0]) ||
@@ -7589,7 +7592,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;
@@ -10594,6 +10597,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", chan->name);
                                dahdi_setlinear(p->subs[idx].dfd, 0);
@@ -10604,10 +10610,12 @@ static void *analog_ss_thread(void *data)
                                 * can drop some of them.
                                 */
                                ast_set_flag(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()
@@ -10627,7 +10635,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 (chan->_state == AST_STATE_RING ||
@@ -10650,6 +10658,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);
@@ -10726,10 +10737,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");
@@ -10857,12 +10871,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");
@@ -10878,7 +10898,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);
 
index e0e2ca99987ce7266a8ca2ec7d2a37b02741b17a..bdbb685c912a536278a0c30d0e353016a54b639c 100644 (file)
@@ -5654,6 +5654,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)
@@ -13830,6 +13835,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++) {
@@ -13854,8 +13861,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)
@@ -13866,7 +13874,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);
index eb13eb7f89d221d8b88a2bcde0d054f09f20cc17..a916990143a90b80c0c371ba9678b1e2d089c101 100644 (file)
@@ -2393,6 +2393,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", chan->name);
 
@@ -2405,10 +2408,12 @@ static void *__analog_ss_thread(void *data)
                                 * can drop some of them.
                                 */
                                ast_set_flag(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()
@@ -2429,7 +2434,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 (chan->_state == AST_STATE_RING ||
@@ -2463,6 +2468,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));
 
@@ -2500,10 +2508,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");
index ad8c31452075b6ddd09a744e3ed6880d1224756e..07ac5f8fa5fa78b197e602cc05b32f2592cdb9fb 100644 (file)
@@ -1833,7 +1833,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;
 
        ast_verb(3, "Initiating idle call on channel %s\n", chan->name);
        snprintf(ex, sizeof(ex), "%d/%s", pvt->channel, pvt->pri->idledial);
@@ -1842,7 +1844,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 */
@@ -1868,7 +1875,6 @@ static void *do_idle_thread(void *v_pvt)
                        };
                }
                ast_frfree(f);
-               ms = newms;
        }
        /* Hangup the channel since nothing happend */
        ast_hangup(chan);
index bbd439389c1978946be9756d09a4ccd13f616682..2820fc09b6b0d744bb31820cea0f6bc7d789354e 100644 (file)
@@ -1692,7 +1692,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.
@@ -1702,7 +1702,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.
index 4fa08723b935bf9be5da7e4a35081828636db9e2..dd68db7044e50498c845ba9ef18876183cac100d 100644 (file)
@@ -151,6 +151,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
  */
index 4b8eadc26e7aaa134278d72b806a9024a5b594b8..02eaed31b9ef56201653b9a3b4e5a9bb2cdbba2a 100644 (file)
@@ -1862,11 +1862,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);
@@ -1876,8 +1878,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;
                }
@@ -3031,12 +3035,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", chan->name, strerror(errno));
@@ -3560,11 +3567,14 @@ 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;
 }
 
@@ -3619,6 +3629,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(c, AST_FLAG_ZOMBIE) || ast_check_hangup(c))
@@ -3630,19 +3641,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,
@@ -4652,25 +4653,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;
-       
-       while (!done) {
+       struct timeval start = ast_tvnow();
+       int ms;
+
+       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);
        }
@@ -5659,18 +5667,19 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c
        if (ast_call(chan, data, 0)) {  /* ast_call failed... */
                ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
        } else {
+               struct timeval start = ast_tvnow();
                res = 1;        /* mark success in case chan->_state is already AST_STATE_UP */
                while (timeout && chan->_state != 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(chan->call_forward)) {
                                if (!(chan = ast_call_forward(NULL, chan, NULL, cap, oh, outstate))) {
                                        return NULL;
index a12ef4f078db1607d3d8e824f7a3097b16656802..1cfb8be9698b16067ecb8f7c46169ac6165a0b9f 100644 (file)
@@ -8880,13 +8880,15 @@ static void *async_wait(void *data)
        int res;
        struct ast_frame *f;
        struct ast_app *app;
+       struct timeval start = ast_tvnow();
+       int ms;
 
-       while (timeout && (chan->_state != AST_STATE_UP)) {
-               res = ast_waitfor(chan, timeout);
+       while ((ms = ast_remaining_ms(start, timeout)) &&
+                       chan->_state != AST_STATE_UP) {
+               res = ast_waitfor(chan, ms);
                if (res < 1)
                        break;
-               if (timeout > -1)
-                       timeout = res;
+
                f = ast_read(chan);
                if (!f)
                        break;
index ea5e9035331e93a907e20282080c74ca05251992..1a4129a418e14a78af4b74cd59a5c926f4f70ff5 100644 (file)
@@ -808,6 +808,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)) {
@@ -838,7 +839,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(&c0->rawreadformat, &c1->rawwriteformat) == AST_FORMAT_CMP_NOT_EQUAL) ||
                        (ast_format_cmp(&c1->rawreadformat, &c0->rawwriteformat) == AST_FORMAT_CMP_NOT_EQUAL)) {
@@ -864,8 +867,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;
                        }
@@ -999,6 +1003,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);
@@ -1043,7 +1048,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 ((c0->tech_pvt != pvt0) ||
                    (c1->tech_pvt != pvt1) ||
@@ -1138,9 +1145,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;
                        }
index a679ee15ec8ca7260fa5b98df0e43a8dc8c49f3f..d7f0f3ad8e7c56e345b08482b4474452ce0155cf 100644 (file)
@@ -1438,6 +1438,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.
index 836973829f3bef5f39ddd07797647eb345b2c30d..bb5da90a16b5411555a1b1685dee42dd240abc5f 100644 (file)
@@ -1228,9 +1228,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", chan->name);
        if (ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) != 0) {
@@ -1239,20 +1241,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", chan->name);
                        return -1;
                }
 
-               if (ms == 0) { /* all done, nothing happened */
-                       ast_debug(1, "channel '%s' timed-out during T.38 shutdown\n", chan->name);
-                       break;
-               }
-
                if (!(frame = ast_read(chan))) {
                        return -1;
                }
@@ -1280,6 +1281,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", chan->name);
+       }
+
        return 0;
 }
 
@@ -1288,7 +1293,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);
@@ -1299,6 +1304,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);
@@ -1379,8 +1386,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", chan->name, 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;
 
@@ -1397,7 +1405,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);
@@ -1466,7 +1474,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) {
@@ -1483,36 +1491,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", chan->name);
                                        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", chan->name);
+                               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", chan->name, timeout, ms, res);
+       ast_debug(3, "channel '%s' - event loop stopped { timeout: %d, remaining_time: %d }\n", chan->name, timeout, remaining_time);
 
        set_channel_variables(chan, details);
 
@@ -1546,9 +1548,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) {
@@ -1558,9 +1562,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", chan->name);
                                ast_playtones_stop(chan);
@@ -1617,7 +1623,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", chan->name);
 
        /* 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);
@@ -1626,13 +1632,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", chan->name);
                        return -1;
                }
-
                if (ms == 0) { /* all done, nothing happened */
                        ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", chan->name);
                        details->caps &= ~AST_FAX_TECH_T38;
@@ -1660,21 +1668,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", chan->name);
                                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", chan->name);
                                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 */
@@ -1942,9 +1953,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
@@ -1952,7 +1965,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) {
@@ -1962,8 +1975,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", chan->name);
                        ast_playtones_stop(chan);
@@ -2000,13 +2016,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);
@@ -2020,7 +2039,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", chan->name);
 
                /* 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);
@@ -2029,13 +2048,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", chan->name);
                                return -1;
                        }
-
                        if (ms == 0) { /* all done, nothing happened */
                                ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", chan->name);
                                details->caps &= ~AST_FAX_TECH_T38;
@@ -2063,21 +2084,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", chan->name);
                                        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", chan->name);
                                        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 */
@@ -2093,15 +2117,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", chan->name);
                                        ast_playtones_stop(chan);
                                        return -1;
                                }
-
                                if (ms == 0) { /* all done, nothing happened */
                                        break;
                                }
@@ -2132,13 +2158,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);