diff options
-rw-r--r-- | apps/app_dial.c | 14 | ||||
-rw-r--r-- | apps/app_jack.c | 4 | ||||
-rw-r--r-- | apps/app_meetme.c | 2 | ||||
-rw-r--r-- | apps/app_queue.c | 24 | ||||
-rw-r--r-- | apps/app_record.c | 27 | ||||
-rw-r--r-- | apps/app_waitforring.c | 25 | ||||
-rw-r--r-- | channels/chan_agent.c | 14 | ||||
-rw-r--r-- | channels/chan_dahdi.c | 42 | ||||
-rw-r--r-- | channels/chan_iax2.c | 14 | ||||
-rw-r--r-- | channels/sig_analog.c | 22 | ||||
-rw-r--r-- | channels/sig_pri.c | 12 | ||||
-rw-r--r-- | include/asterisk/channel.h | 4 | ||||
-rw-r--r-- | include/asterisk/time.h | 14 | ||||
-rw-r--r-- | main/channel.c | 76 | ||||
-rw-r--r-- | main/pbx.c | 10 | ||||
-rw-r--r-- | main/rtp_engine.c | 16 | ||||
-rw-r--r-- | main/utils.c | 17 | ||||
-rw-r--r-- | res/res_fax.c | 127 |
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); |