diff --git a/apps/app_dial.c b/apps/app_dial.c index b8e2e0a7b474d6ccc54411ce91f272387abcf8d3..b464c9d90218f8521c06573652bf87ddc8b509d2 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -1115,6 +1115,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) { @@ -1157,7 +1158,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; @@ -1701,10 +1702,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 10964f4621cc00f7f322c2752028f66e63b39af2..d1bdfa38f052f4143016332054e114aacdfe201b 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 892ebaac0bf50dc74d06c2cb923500b061ea0d52..7fd2e500d9aeee725c420c94f26062abc0ea9701 100644 --- a/apps/app_meetme.c +++ b/apps/app_meetme.c @@ -1907,7 +1907,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 40dd87d4167b7da27a74a6e5633479c6095196cc..62b54b6eed539ee67dc4ded91f0b3b85630c9b7f 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -4058,6 +4058,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); @@ -4073,8 +4074,8 @@ 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); } @@ -4532,10 +4533,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); } } diff --git a/apps/app_record.c b/apps/app_record.c index ff233d6a95b9892fb1803c75aa5990e7f128a5ae..051f97bb85093c1cd668c8cba14491ca24f630c7 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 bd0353b074d15da07e0ea47ccd1f9e57b49f7b39..fc02de303ede0b752c252497a748d4d524862ba1 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 8f1162a50d8ac2dc03f81901633f1e4777420b6a..81cf8d56783aeef55dd8b9925b5dc3cdab537a40 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 39b1e172822a2bfa2c466b42a9513179de3e3903..390f8b2a22f80a8cf92f8a754740d24be0b51b1e 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -6206,6 +6206,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)); @@ -7377,6 +7378,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; @@ -7595,6 +7597,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 */ @@ -7611,8 +7614,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)) || @@ -7660,7 +7663,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; @@ -10729,6 +10732,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); @@ -10739,10 +10745,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() @@ -10762,7 +10770,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 || @@ -10785,6 +10793,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); @@ -10861,10 +10872,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"); @@ -10992,12 +11006,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"); @@ -11013,7 +11033,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 8ce8f9dbba3415561e43f1b2b0881a61632a120c..80041336f46d97f68e3f07294f1f5760cfaf4be3 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -5619,6 +5619,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) @@ -13885,6 +13890,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++) { @@ -13909,8 +13916,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) @@ -13921,7 +13929,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 79e8e7cb24f4daad461bc9cfe7727f78e1fd1471..e710c2b24a117b9e4f962e1bfb6cfe8ad51dba5e 100644 --- a/channels/sig_analog.c +++ b/channels/sig_analog.c @@ -2394,6 +2394,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)); @@ -2406,10 +2409,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() @@ -2430,7 +2435,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 || @@ -2464,6 +2469,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)); @@ -2501,10 +2509,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 bf73ced37746533c339d9cd3de75ae5ac5e51aea..4691e166a028134cd15535163ee6c47d760be454 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 51d62a43790b6373e6b8552b073440b801a4c91b..40dbf4381ce23c39217ad1f514bcd2c5912870b6 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -1665,7 +1665,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. @@ -1675,7 +1675,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 4fa08723b935bf9be5da7e4a35081828636db9e2..dd68db7044e50498c845ba9ef18876183cac100d 100644 --- a/include/asterisk/time.h +++ b/include/asterisk/time.h @@ -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 */ diff --git a/main/channel.c b/main/channel.c index a56ce3fbe3c95e3e7785439fb603412b0537293b..e2ac10a10e21fe0238c2d9c87baa9eee511f747e 100644 --- a/main/channel.c +++ b/main/channel.c @@ -1666,11 +1666,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); @@ -1680,8 +1682,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; } @@ -2957,12 +2961,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)); @@ -3520,11 +3527,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; } @@ -3580,6 +3589,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)) @@ -3591,19 +3601,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, @@ -4642,25 +4642,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); } @@ -5676,18 +5683,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 fec6180ea29a4e383a82c2e999090d21f9d0c72e..7554f29e94dba1ec13dfa5ad5bea66e2b3582770 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -9766,6 +9766,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); @@ -9775,12 +9777,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 4bcdb138ae162daf76ef15780412fc33c3171371..4e2669088919704b1deae77fead3bec09bcfd17b 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 0ff33cba2793c171f0127d2c2da0bbf90957f367..3476729cedaacbbaa600f04bce69108d600de5eb 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 6141dd7a872cec66d6e16d1754e47a01107de2f7..fd0294bbeb254802a9767a5320bdbdb234d8317c 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -1253,9 +1253,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) { @@ -1264,20 +1266,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; } @@ -1305,6 +1306,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; } @@ -1313,7 +1318,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); @@ -1324,6 +1329,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); @@ -1404,8 +1411,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; @@ -1422,7 +1430,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); @@ -1491,7 +1499,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) { @@ -1508,36 +1516,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); @@ -1571,9 +1573,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) { @@ -1583,9 +1587,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); @@ -1642,7 +1648,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); @@ -1651,13 +1657,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; @@ -1685,21 +1693,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 */ @@ -1967,9 +1978,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 @@ -1977,7 +1990,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) { @@ -1987,8 +2000,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); @@ -2025,13 +2041,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); @@ -2045,7 +2064,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); @@ -2054,13 +2073,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; @@ -2088,21 +2109,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 */ @@ -2118,15 +2142,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; } @@ -2157,13 +2183,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);