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);