[asterisk-commits] mmichelson: branch 10 r375995 - in /branches/10: ./ apps/ channels/ include/a...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Nov 7 11:16:30 CST 2012


Author: mmichelson
Date: Wed Nov  7 11:16:24 2012
New Revision: 375995

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=375995
Log:
Multiple revisions 375993-375994

........
  r375993 | mmichelson | 2012-11-07 11:01:13 -0600 (Wed, 07 Nov 2012) | 30 lines
  
  Fix misuses of timeouts throughout the code.
  
  Prior to this change, a common method for determining if a timeout
  was reached was to call a function such as ast_waitfor_n() and inspect
  the out parameter that told how many milliseconds were left, then use
  that as the input to ast_waitfor_n() on the next go-around.
  
  The problem with this is that in some cases, submillisecond timeouts
  can occur, resulting in the out parameter not decreasing any. When this
  happens thousands of times, the result is that the timeout takes much
  longer than intended to be reached. As an example, I had a situation where
  a 3 second timeout took multiple days to finally end since most wakeups
  from ast_waitfor_n() were under a millisecond.
  
  This patch seeks to fix this pattern throughout the code. Now we log the
  time when an operation began and find the difference in wall clock time
  between now and when the event started. This means that sub-millisecond timeouts
  now cannot play havoc when trying to determine if something has timed out.
  
  Part of this fix also includes changing the function ast_waitfor() so that it
  is possible for it to return less than zero when a negative timeout is given
  to it. This makes it actually possible to detect errors in ast_waitfor() when
  there is no timeout.
  
  (closes issue ASTERISK-20414)
  reported by David M. Lee
  
  Review: https://reviewboard.asterisk.org/r/2135/
........
  r375994 | mmichelson | 2012-11-07 11:08:44 -0600 (Wed, 07 Nov 2012) | 3 lines
  
  Remove some debugging that accidentally made it in the last commit.
........

Merged revisions 375993-375994 from http://svn.asterisk.org/svn/asterisk/branches/1.8

Modified:
    branches/10/   (props changed)
    branches/10/apps/app_dial.c
    branches/10/apps/app_jack.c
    branches/10/apps/app_meetme.c
    branches/10/apps/app_queue.c
    branches/10/apps/app_record.c
    branches/10/apps/app_waitforring.c
    branches/10/channels/chan_agent.c
    branches/10/channels/chan_dahdi.c
    branches/10/channels/chan_iax2.c
    branches/10/channels/sig_analog.c
    branches/10/channels/sig_pri.c
    branches/10/include/asterisk/channel.h
    branches/10/include/asterisk/time.h
    branches/10/main/channel.c
    branches/10/main/pbx.c
    branches/10/main/rtp_engine.c
    branches/10/main/utils.c
    branches/10/res/res_fax.c

Propchange: branches/10/
------------------------------------------------------------------------------
Binary property 'branch-1.8-merged' - no diff available.

Modified: branches/10/apps/app_dial.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/apps/app_dial.c?view=diff&rev=375995&r1=375994&r2=375995
==============================================================================
--- branches/10/apps/app_dial.c (original)
+++ branches/10/apps/app_dial.c Wed Nov  7 11:16:24 2012
@@ -1055,6 +1055,7 @@
 	int is_cc_recall;
 	int cc_frame_received = 0;
 	int num_ringing = 0;
+	struct timeval start = ast_tvnow();
 
 	ast_party_connected_line_init(&connected_caller);
 	if (single) {
@@ -1095,7 +1096,7 @@
 		ast_poll_channel_add(in, epollo->chan);
 #endif
 
-	while (*to && !peer) {
+	while ((*to = ast_remaining_ms(start, orig)) && !peer) {
 		struct chanlist *o;
 		int pos = 0; /* how many channels do we handle */
 		int numlines = prestart;
@@ -1626,10 +1627,13 @@
 skip_frame:;
 			ast_frfree(f);
 		}
-		if (!*to)
-			ast_verb(3, "Nobody picked up in %d ms\n", orig);
-		if (!*to || ast_check_hangup(in))
-			ast_cdr_noanswer(in->cdr);
+	}
+
+	if (!*to) {
+		ast_verb(3, "Nobody picked up in %d ms\n", orig);
+	}
+	if (!*to || ast_check_hangup(in)) {
+		ast_cdr_noanswer(in->cdr);
 	}
 
 #ifdef HAVE_EPOLL

Modified: branches/10/apps/app_jack.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/apps/app_jack.c?view=diff&rev=375995&r1=375994&r2=375995
==============================================================================
--- branches/10/apps/app_jack.c (original)
+++ branches/10/apps/app_jack.c Wed Nov  7 11:16:24 2012
@@ -768,7 +768,9 @@
 	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) {

Modified: branches/10/apps/app_meetme.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/apps/app_meetme.c?view=diff&rev=375995&r1=375994&r2=375995
==============================================================================
--- branches/10/apps/app_meetme.c (original)
+++ branches/10/apps/app_meetme.c Wed Nov  7 11:16:24 2012
@@ -1900,7 +1900,7 @@
 		/* 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);

Modified: branches/10/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/apps/app_queue.c?view=diff&rev=375995&r1=375994&r2=375995
==============================================================================
--- branches/10/apps/app_queue.c (original)
+++ branches/10/apps/app_queue.c Wed Nov  7 11:16:24 2012
@@ -3642,6 +3642,7 @@
 #endif
 	struct ast_party_connected_line connected_caller;
 	char *inchan_name;
+	struct timeval start_time_tv = ast_tvnow();
 
 	ast_party_connected_line_init(&connected_caller);
 
@@ -3656,8 +3657,8 @@
 			ast_poll_channel_add(in, epollo->chan);
 	}
 #endif
-	
-	while (*to && !peer) {
+
+	while ((*to = ast_remaining_ms(start_time_tv, orig)) && !peer) {
 		int numlines, retry, pos = 1;
 		struct ast_channel *watchers[AST_MAX_WATCHERS];
 		watchers[0] = in;
@@ -3913,10 +3914,11 @@
 							endtime -= starttime;
 							rna(endtime * 1000, qe, on, membername, 0);
 							if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
-								if (qe->parent->timeoutrestart)
-									*to = orig;
+								if (qe->parent->timeoutrestart) {
+									start_time_tv = ast_tvnow();
+								}
 								/* Have enough time for a queue member to answer? */
-								if (*to > 500) {
+								if (ast_remaining_ms(start_time_tv, orig) > 500) {
 									ring_one(qe, outgoing, &numbusies);
 									starttime = (long) time(NULL);
 								}
@@ -3932,9 +3934,10 @@
 							rna(endtime * 1000, qe, on, membername, 0);
 							do_hang(o);
 							if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
-								if (qe->parent->timeoutrestart)
-									*to = orig;
-								if (*to > 500) {
+								if (qe->parent->timeoutrestart) {
+									start_time_tv = ast_tvnow();
+								}
+								if (ast_remaining_ms(start_time_tv, orig) > 500) {
 									ring_one(qe, outgoing, &numbusies);
 									starttime = (long) time(NULL);
 								}
@@ -4021,9 +4024,10 @@
 					rna(endtime * 1000, qe, on, membername, 1);
 					do_hang(o);
 					if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
-						if (qe->parent->timeoutrestart)
-							*to = orig;
-						if (*to > 500) {
+						if (qe->parent->timeoutrestart) {
+							start_time_tv = ast_tvnow();
+						}
+						if (ast_remaining_ms(start_time_tv, orig) > 500) {
 							ring_one(qe, outgoing, &numbusies);
 							starttime = (long) time(NULL);
 						}
@@ -4094,9 +4098,11 @@
 
 			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);
 		}
 	}
 

Modified: branches/10/apps/app_record.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/apps/app_record.c?view=diff&rev=375995&r1=375994&r2=375995
==============================================================================
--- branches/10/apps/app_record.c (original)
+++ branches/10/apps/app_record.c Wed Nov  7 11:16:24 2012
@@ -160,7 +160,6 @@
 	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 @@
 		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 @@
 	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 @@
 		}
 		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;

Modified: branches/10/apps/app_waitforring.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/apps/app_waitforring.c?view=diff&rev=375995&r1=375994&r2=375995
==============================================================================
--- branches/10/apps/app_waitforring.c (original)
+++ branches/10/apps/app_waitforring.c Wed Nov  7 11:16:24 2012
@@ -63,10 +63,17 @@
 	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;
 	}
 
@@ -74,11 +81,11 @@
 		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 @@
 	}
 	/* 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;

Modified: branches/10/channels/chan_agent.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/channels/chan_agent.c?view=diff&rev=375995&r1=375994&r2=375995
==============================================================================
--- branches/10/channels/chan_agent.c (original)
+++ branches/10/channels/chan_agent.c Wed Nov  7 11:16:24 2012
@@ -1046,6 +1046,8 @@
 	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 @@
 	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 @@
 		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)

Modified: branches/10/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/channels/chan_dahdi.c?view=diff&rev=375995&r1=375994&r2=375995
==============================================================================
--- branches/10/channels/chan_dahdi.c (original)
+++ branches/10/channels/chan_dahdi.c Wed Nov  7 11:16:24 2012
@@ -6129,6 +6129,7 @@
 		if (res == 0) {
 			continue;
 		}
+		res = 0;
 		f = ast_read(chan);
 		if (!f) {
 			ast_debug(1, "No frame read on channel %s, going out ...\n", chan->name);
@@ -7300,6 +7301,7 @@
 	int priority = 0;
 	struct ast_channel *oc0, *oc1;
 	enum ast_bridge_result res;
+	struct timeval start = ast_tvnow();
 #ifdef PRI_2BCT
 	int triedtopribridge = 0;
 	q931_call *q931c0;
@@ -7521,6 +7523,7 @@
 	for (;;) {
 		struct ast_channel *c0_priority[2] = {c0, c1};
 		struct ast_channel *c1_priority[2] = {c1, c0};
+		int ms;
 
 		/* Here's our main loop...  Start by locking things, looking for private parts,
 		   and then balking if anything is wrong */
@@ -7540,8 +7543,8 @@
 
 		ast_channel_unlock(c0);
 		ast_channel_unlock(c1);
-
-		if (!timeoutms ||
+		ms = ast_remaining_ms(start, timeoutms);
+		if (!ms ||
 			(op0 != p0) ||
 			(op1 != p1) ||
 			(ofd0 != c0->fds[0]) ||
@@ -7589,7 +7592,7 @@
 		}
 #endif
 
-		who = ast_waitfor_n(priority ? c0_priority : c1_priority, 2, &timeoutms);
+		who = ast_waitfor_n(priority ? c0_priority : c1_priority, 2, &ms);
 		if (!who) {
 			ast_debug(1, "Ooh, empty read...\n");
 			continue;
@@ -10594,6 +10597,9 @@
 			/* If set to use DTMF CID signalling, listen for DTMF */
 			if (p->cid_signalling == CID_SIG_DTMF) {
 				int k = 0;
+				int off_ms;
+				struct timeval start = ast_tvnow();
+				int ms;
 				cs = NULL;
 				ast_debug(1, "Receiving DTMF cid on channel %s\n", chan->name);
 				dahdi_setlinear(p->subs[idx].dfd, 0);
@@ -10604,10 +10610,12 @@
 				 * can drop some of them.
 				 */
 				ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
-				res = 4000;/* This is a typical OFF time between rings. */
+				off_ms = 4000;/* This is a typical OFF time between rings. */
 				for (;;) {
 					struct ast_frame *f;
-					res = ast_waitfor(chan, res);
+
+					ms = ast_remaining_ms(start, off_ms);
+					res = ast_waitfor(chan, ms);
 					if (res <= 0) {
 						/*
 						 * We do not need to restore the dahdi_setlinear()
@@ -10627,7 +10635,7 @@
 							dtmfbuf[k++] = f->subclass.integer;
 						}
 						ast_debug(1, "CID got digit '%c'\n", f->subclass.integer);
-						res = 4000;/* This is a typical OFF time between rings. */
+						start = ast_tvnow();
 					}
 					ast_frfree(f);
 					if (chan->_state == AST_STATE_RING ||
@@ -10650,6 +10658,9 @@
 			} else if ((p->cid_signalling == CID_SIG_V23) || (p->cid_signalling == CID_SIG_V23_JP)) {
 				cs = callerid_new(p->cid_signalling);
 				if (cs) {
+					int off_ms;
+					struct timeval start;
+					int ms;
 					samples = 0;
 #if 1
 					bump_gains(p);
@@ -10726,10 +10737,13 @@
 					}
 
 					/* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */
-					res = 4000;/* This is a typical OFF time between rings. */
+					start = ast_tvnow();
+					off_ms = 4000;/* This is a typical OFF time between rings. */
 					for (;;) {
 						struct ast_frame *f;
-						res = ast_waitfor(chan, res);
+
+						ms = ast_remaining_ms(start, off_ms);
+						res = ast_waitfor(chan, ms);
 						if (res <= 0) {
 							ast_log(LOG_WARNING, "CID timed out waiting for ring. "
 								"Exiting simple switch\n");
@@ -10857,12 +10871,18 @@
 		} else if (p->use_callerid && p->cid_start == CID_START_RING) {
 			if (p->cid_signalling == CID_SIG_DTMF) {
 				int k = 0;
+				int off_ms;
+				struct timeval start;
+				int ms;
 				cs = NULL;
 				dahdi_setlinear(p->subs[idx].dfd, 0);
-				res = 2000;
+				off_ms = 2000;
+				start = ast_tvnow();
 				for (;;) {
 					struct ast_frame *f;
-					res = ast_waitfor(chan, res);
+
+					ms = ast_remaining_ms(start, off_ms);
+					res = ast_waitfor(chan, ms);
 					if (res <= 0) {
 						ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
 							"Exiting simple switch\n");
@@ -10878,7 +10898,7 @@
 					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);
 

Modified: branches/10/channels/chan_iax2.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/channels/chan_iax2.c?view=diff&rev=375995&r1=375994&r2=375995
==============================================================================
--- branches/10/channels/chan_iax2.c (original)
+++ branches/10/channels/chan_iax2.c Wed Nov  7 11:16:24 2012
@@ -5654,6 +5654,11 @@
 		}
 		to = 1000;
 		who = ast_waitfor_n(cs, 2, &to);
+		/* XXX This will need to be updated to calculate
+		 * timeout correctly once timeoutms is allowed to be
+		 * > 0. Right now, this can go badly if the waitfor
+		 * times out in less than a millisecond
+		 */
 		if (timeoutms > -1) {
 			timeoutms -= (1000 - to);
 			if (timeoutms < 0)
@@ -13830,6 +13835,8 @@
 
 	/* By here we must have a dp */
 	if (dp->flags & CACHE_FLAG_PENDING) {
+		struct timeval start;
+		int ms;
 		/* Okay, here it starts to get nasty.  We need a pipe now to wait
 		   for a reply to come back so long as it's pending */
 		for (x = 0; x < ARRAY_LEN(dp->waiters); x++) {
@@ -13854,8 +13861,9 @@
 		if (chan)
 			old = ast_channel_defer_dtmf(chan);
 		doabort = 0;
-		while(timeout) {
-			c = ast_waitfor_nandfds(&chan, chan ? 1 : 0, &com[0], 1, NULL, &outfd, &timeout);
+		start = ast_tvnow();
+		while ((ms = ast_remaining_ms(start, timeout))) {
+			c = ast_waitfor_nandfds(&chan, chan ? 1 : 0, &com[0], 1, NULL, &outfd, &ms);
 			if (outfd > -1)
 				break;
 			if (!c)
@@ -13866,7 +13874,7 @@
 			}
 			ast_frfree(f);
 		}
-		if (!timeout) {
+		if (!ms) {
 			ast_log(LOG_WARNING, "Timeout waiting for %s exten %s\n", data, exten);
 		}
 		AST_LIST_LOCK(&dpcache);

Modified: branches/10/channels/sig_analog.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/channels/sig_analog.c?view=diff&rev=375995&r1=375994&r2=375995
==============================================================================
--- branches/10/channels/sig_analog.c (original)
+++ branches/10/channels/sig_analog.c Wed Nov  7 11:16:24 2012
@@ -2393,6 +2393,9 @@
 			if (p->cid_signalling == CID_SIG_DTMF) {
 				int k = 0;
 				int oldlinearity; 
+				int timeout_ms;
+				int ms;
+				struct timeval start = ast_tvnow();
 				cs = NULL;
 				ast_debug(1, "Receiving DTMF cid on channel %s\n", chan->name);
 
@@ -2405,10 +2408,12 @@
 				 * can drop some of them.
 				 */
 				ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
-				res = 4000;/* This is a typical OFF time between rings. */
+				timeout_ms = 4000;/* This is a typical OFF time between rings. */
 				for (;;) {
 					struct ast_frame *f;
-					res = ast_waitfor(chan, res);
+
+					ms = ast_remaining_ms(start, timeout_ms);
+					res = ast_waitfor(chan, ms);
 					if (res <= 0) {
 						/*
 						 * We do not need to restore the analog_set_linear_mode()
@@ -2429,7 +2434,7 @@
 							dtmfbuf[k++] = f->subclass.integer;
 						}
 						ast_debug(1, "CID got digit '%c'\n", f->subclass.integer);
-						res = 4000;/* This is a typical OFF time between rings. */
+						start = ast_tvnow();
 					}
 					ast_frfree(f);
 					if (chan->_state == AST_STATE_RING ||
@@ -2463,6 +2468,9 @@
 				numbuf[0] = 0;
 
 				if (!analog_start_cid_detect(p, p->cid_signalling)) {
+					int off_ms;
+					int ms;
+					struct timeval off_start;
 					while (1) {
 						res = analog_get_callerid(p, namebuf, numbuf, &ev, timeout - ast_tvdiff_ms(ast_tvnow(), start));
 
@@ -2500,10 +2508,12 @@
 					}
 
 					/* 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");

Modified: branches/10/channels/sig_pri.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/channels/sig_pri.c?view=diff&rev=375995&r1=375994&r2=375995
==============================================================================
--- branches/10/channels/sig_pri.c (original)
+++ branches/10/channels/sig_pri.c Wed Nov  7 11:16:24 2012
@@ -1833,7 +1833,9 @@
 	struct ast_frame *f;
 	char ex[80];
 	/* Wait up to 30 seconds for an answer */
-	int newms, ms = 30000;
+	int timeout_ms = 30000;
+	int ms;
+	struct timeval start;
 
 	ast_verb(3, "Initiating idle call on channel %s\n", chan->name);
 	snprintf(ex, sizeof(ex), "%d/%s", pvt->channel, pvt->pri->idledial);
@@ -1842,7 +1844,12 @@
 		ast_hangup(chan);
 		return NULL;
 	}
-	while ((newms = ast_waitfor(chan, ms)) > 0) {
+	start = ast_tvnow();
+	while ((ms = ast_remaining_ms(start, timeout_ms))) {
+		if (ast_waitfor(chan, ms) <= 0) {
+			break;
+		}
+
 		f = ast_read(chan);
 		if (!f) {
 			/* Got hangup */
@@ -1868,7 +1875,6 @@
 			};
 		}
 		ast_frfree(f);
-		ms = newms;
 	}
 	/* Hangup the channel since nothing happend */
 	ast_hangup(chan);

Modified: branches/10/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/branches/10/include/asterisk/channel.h?view=diff&rev=375995&r1=375994&r2=375995
==============================================================================
--- branches/10/include/asterisk/channel.h (original)
+++ branches/10/include/asterisk/channel.h Wed Nov  7 11:16:24 2012
@@ -1692,7 +1692,7 @@
 /*!
  * \brief Wait for a specified amount of time, looking for hangups
  * \param chan channel to wait for
- * \param ms length of time in milliseconds to sleep
+ * \param ms length of time in milliseconds to sleep. This should never be less than zero.
  * \details
  * Waits for a specified amount of time, servicing the channel as required.
  * \return returns -1 on hangup, otherwise 0.
@@ -1702,7 +1702,7 @@
 /*!
  * \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.

Modified: branches/10/include/asterisk/time.h
URL: http://svnview.digium.com/svn/asterisk/branches/10/include/asterisk/time.h?view=diff&rev=375995&r1=375994&r2=375995
==============================================================================
--- branches/10/include/asterisk/time.h (original)
+++ branches/10/include/asterisk/time.h Wed Nov  7 11:16:24 2012
@@ -152,6 +152,20 @@
 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(

Modified: branches/10/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/main/channel.c?view=diff&rev=375995&r1=375994&r2=375995
==============================================================================
--- branches/10/main/channel.c (original)
+++ branches/10/main/channel.c Wed Nov  7 11:16:24 2012
@@ -1862,11 +1862,13 @@
 }
 
 /*! \brief Wait, look for hangups and condition arg */
-int ast_safe_sleep_conditional(struct ast_channel *chan, int ms, int (*cond)(void*), void *data)
+int ast_safe_sleep_conditional(struct ast_channel *chan, int timeout_ms, int (*cond)(void*), void *data)
 {
 	struct ast_frame *f;
 	struct ast_silence_generator *silgen = NULL;
 	int res = 0;
+	struct timeval start;
+	int ms;
 	AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
 
 	AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames);
@@ -1876,8 +1878,10 @@
 		silgen = ast_channel_start_silence_generator(chan);
 	}
 
-	while (ms > 0) {
+	start = ast_tvnow();
+	while ((ms = ast_remaining_ms(start, timeout_ms))) {
 		struct ast_frame *dup_f = NULL;
+
 		if (cond && ((*cond)(data) == 0)) {
 			break;
 		}
@@ -3031,12 +3035,15 @@
 		do {
 			AST_LIST_HEAD_NOLOCK(, ast_frame) frames;
 			struct ast_frame *cur, *new;
-			int ms = MAX(delay, 500);
+			int timeout_ms = MAX(delay, 500);
 			unsigned int done = 0;
+			struct timeval start;
 
 			AST_LIST_HEAD_INIT_NOLOCK(&frames);
 
+			start = ast_tvnow();
 			for (;;) {
+				int ms = ast_remaining_ms(start, timeout_ms);
 				ms = ast_waitfor(chan, ms);
 				if (ms < 0) {
 					ast_log(LOG_WARNING, "Error condition occurred when polling channel %s for a voice frame: %s\n", chan->name, strerror(errno));
@@ -3560,11 +3567,14 @@
 
 int ast_waitfor(struct ast_channel *c, int ms)
 {
-	int oldms = ms;	/* -1 if no timeout */
-
-	ast_waitfor_nandfds(&c, 1, NULL, 0, NULL, NULL, &ms);
-	if ((ms < 0) && (oldms < 0))
-		ms = 0;
+	if (ms < 0) {
+		do {
+			ms = 100000;
+			ast_waitfor_nandfds(&c, 1, NULL, 0, NULL, NULL, &ms);
+		} while (!ms);
+	} else {
+		ast_waitfor_nandfds(&c, 1, NULL, 0, NULL, NULL, &ms);
+	}
 	return ms;
 }
 
@@ -3619,6 +3629,7 @@
 int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, int cmdfd)
 {
 	struct timeval start = ast_tvnow();
+	int ms;
 
 	/* Stop if we're a zombie or need a soft hangup */
 	if (ast_test_flag(c, AST_FLAG_ZOMBIE) || ast_check_hangup(c))
@@ -3630,19 +3641,9 @@
 	/* Wait for a digit, no more than timeout_ms milliseconds total.
 	 * Or, wait indefinitely if timeout_ms is <0.
 	 */
-	while (ast_tvdiff_ms(ast_tvnow(), start) < timeout_ms || timeout_ms < 0) {
+	while ((ms = ast_remaining_ms(start, timeout_ms))) {
 		struct ast_channel *rchan;
-		int outfd=-1;
-		int ms;
-
-		if (timeout_ms < 0) {
-			ms = timeout_ms;
-		} else {
-			ms = timeout_ms - ast_tvdiff_ms(ast_tvnow(), start);
-			if (ms < 0) {
-				ms = 0;
-			}
-		}
+		int outfd = -1;
 
 		errno = 0;
 		/* While ast_waitfor_nandfds tries to help by reducing the timeout by how much was waited,
@@ -4652,25 +4653,32 @@
 
 char *ast_recvtext(struct ast_channel *chan, int timeout)
 {
-	int res, done = 0;
+	int res;
 	char *buf = NULL;
-	
-	while (!done) {
+	struct timeval start = ast_tvnow();
+	int ms;
+
+	while ((ms = ast_remaining_ms(start, timeout))) {
 		struct ast_frame *f;
-		if (ast_check_hangup(chan))
+
+		if (ast_check_hangup(chan)) {
 			break;
-		res = ast_waitfor(chan, timeout);
-		if (res <= 0) /* timeout or error */
+		}
+		res = ast_waitfor(chan, ms);
+		if (res <= 0)  {/* timeout or error */
 			break;
-		timeout = res;	/* update timeout */
+		}
 		f = ast_read(chan);
-		if (f == NULL)
+		if (f == NULL) {
 			break; /* no frame */
-		if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_HANGUP)
-			done = 1;	/* force a break */
-		else if (f->frametype == AST_FRAME_TEXT) {		/* what we want */
+		}
+		if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_HANGUP) {
+			ast_frfree(f);
+			break;
+		} else if (f->frametype == AST_FRAME_TEXT) {		/* what we want */
 			buf = ast_strndup((char *) f->data.ptr, f->datalen);	/* dup and break */
-			done = 1;
+			ast_frfree(f);
+			break;
 		}
 		ast_frfree(f);
 	}
@@ -5659,18 +5667,19 @@
 	if (ast_call(chan, data, 0)) {	/* ast_call failed... */
 		ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
 	} else {
+		struct timeval start = ast_tvnow();
 		res = 1;	/* mark success in case chan->_state is already AST_STATE_UP */
 		while (timeout && chan->_state != AST_STATE_UP) {
 			struct ast_frame *f;
-			res = ast_waitfor(chan, timeout);
+			int ms = ast_remaining_ms(start, timeout);
+
+			res = ast_waitfor(chan, ms);
 			if (res == 0) { /* timeout, treat it like ringing */
 				*outstate = AST_CONTROL_RINGING;
 				break;
 			}
 			if (res < 0) /* error or done */
 				break;
-			if (timeout > -1)
-				timeout = res;
 			if (!ast_strlen_zero(chan->call_forward)) {
 				if (!(chan = ast_call_forward(NULL, chan, NULL, cap, oh, outstate))) {
 					return NULL;

Modified: branches/10/main/pbx.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/main/pbx.c?view=diff&rev=375995&r1=375994&r2=375995
==============================================================================
--- branches/10/main/pbx.c (original)
+++ branches/10/main/pbx.c Wed Nov  7 11:16:24 2012
@@ -8880,13 +8880,15 @@
 	int res;
 	struct ast_frame *f;
 	struct ast_app *app;
-
-	while (timeout && (chan->_state != AST_STATE_UP)) {
-		res = ast_waitfor(chan, timeout);
+	struct timeval start = ast_tvnow();
+	int ms;
+
+	while ((ms = ast_remaining_ms(start, timeout)) &&
+			chan->_state != AST_STATE_UP) {
+		res = ast_waitfor(chan, ms);
 		if (res < 1)
 			break;
-		if (timeout > -1)
-			timeout = res;
+
 		f = ast_read(chan);
 		if (!f)
 			break;

Modified: branches/10/main/rtp_engine.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/main/rtp_engine.c?view=diff&rev=375995&r1=375994&r2=375995
==============================================================================
--- branches/10/main/rtp_engine.c (original)
+++ branches/10/main/rtp_engine.c Wed Nov  7 11:16:24 2012
@@ -808,6 +808,7 @@
 	enum ast_bridge_result res = AST_BRIDGE_FAILED;
 	struct ast_channel *who = NULL, *other = NULL, *cs[3] = { NULL, };
 	struct ast_frame *fr = NULL;
+	struct timeval start;
 
 	/* Start locally bridging both instances */
 	if (instance0->engine->local_bridge && instance0->engine->local_bridge(instance0, instance1)) {
@@ -838,7 +839,9 @@
 	cs[0] = c0;
 	cs[1] = c1;
 	cs[2] = NULL;
+	start = ast_tvnow();
 	for (;;) {
+		int ms;
 		/* If the underlying formats have changed force this bridge to break */
 		if ((ast_format_cmp(&c0->rawreadformat, &c1->rawwriteformat) == AST_FORMAT_CMP_NOT_EQUAL) ||
 			(ast_format_cmp(&c1->rawreadformat, &c0->rawwriteformat) == AST_FORMAT_CMP_NOT_EQUAL)) {
@@ -864,8 +867,9 @@
 			break;
 		}
 		/* Wait on a channel to feed us a frame */
-		if (!(who = ast_waitfor_n(cs, 2, &timeoutms))) {
-			if (!timeoutms) {
+		ms = ast_remaining_ms(start, timeoutms);
+		if (!(who = ast_waitfor_n(cs, 2, &ms))) {
+			if (!ms) {
 				res = AST_BRIDGE_RETRY;
 				break;
 			}
@@ -999,6 +1003,7 @@
 	struct ast_sockaddr ac1 = {{0,}}, vac1 = {{0,}}, tac1 = {{0,}}, ac0 = {{0,}}, vac0 = {{0,}}, tac0 = {{0,}};
 	struct ast_sockaddr t1 = {{0,}}, vt1 = {{0,}}, tt1 = {{0,}}, t0 = {{0,}}, vt0 = {{0,}}, tt0 = {{0,}};
 	struct ast_frame *fr = NULL;
+	struct timeval start;
 
 	if (!oldcap0 || !oldcap1) {
 		ast_channel_unlock(c0);
@@ -1043,7 +1048,9 @@
 	cs[0] = c0;
 	cs[1] = c1;
 	cs[2] = NULL;
+	start = ast_tvnow();
 	for (;;) {
+		int ms;
 		/* Check if anything changed */
 		if ((c0->tech_pvt != pvt0) ||
 		    (c1->tech_pvt != pvt1) ||
@@ -1138,9 +1145,10 @@
 			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;
 			}

Modified: branches/10/main/utils.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/main/utils.c?view=diff&rev=375995&r1=375994&r2=375995
==============================================================================
--- branches/10/main/utils.c (original)
+++ branches/10/main/utils.c Wed Nov  7 11:16:24 2012
@@ -1438,6 +1438,23 @@
 	}
 	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.

Modified: branches/10/res/res_fax.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/res/res_fax.c?view=diff&rev=375995&r1=375994&r2=375995
==============================================================================
--- branches/10/res/res_fax.c (original)
+++ branches/10/res/res_fax.c Wed Nov  7 11:16:24 2012
@@ -1228,9 +1228,11 @@
 
 static int disable_t38(struct ast_channel *chan)
 {
-	int ms;
+	int timeout_ms;
 	struct ast_frame *frame = NULL;
 	struct ast_control_t38_parameters t38_parameters = { .request_response = AST_T38_REQUEST_TERMINATE, };
+	struct timeval start;
+	int ms;
 
 	ast_debug(1, "Shutting down T.38 on %s\n", chan->name);
 	if (ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) != 0) {
@@ -1239,18 +1241,17 @@
 	}
 
 	/* wait up to five seconds for negotiation to complete */
-	ms = 5000;
-
-	while (ms > 0) {
+	timeout_ms = 5000;
+	start = ast_tvnow();
+	while ((ms = ast_remaining_ms(start, timeout_ms))) {
 		ms = ast_waitfor(chan, ms);
+
+		if (ms == 0) {
+			break;
+		}
 		if (ms < 0) {
 			ast_debug(1, "error while disabling T.38 on channel '%s'\n", chan->name);
 			return -1;
-		}
-
-		if (ms == 0) { /* all done, nothing happened */
-			ast_debug(1, "channel '%s' timed-out during T.38 shutdown\n", chan->name);
-			break;
 		}
 
 		if (!(frame = ast_read(chan))) {
@@ -1280,6 +1281,10 @@
 		ast_frfree(frame);
 	}
 
+	if (ms == 0) { /* all done, nothing happened */
+		ast_debug(1, "channel '%s' timed-out during T.38 shutdown\n", chan->name);
+	}
+
 	return 0;
 }
 
@@ -1288,7 +1293,7 @@
 {
 	int ms;
 	int timeout = RES_FAX_TIMEOUT;
-	int res = 0, chancount;
+	int res, chancount;
 	unsigned int expected_frametype = -1;
 	union ast_frame_subclass expected_framesubclass = { .integer = -1 };
 	unsigned int t38negotiated = (ast_channel_get_t38_state(chan) == T38_STATE_NEGOTIATED);
@@ -1299,6 +1304,8 @@
 	struct ast_channel *c = chan;
 	struct ast_format orig_write_format;
 	struct ast_format orig_read_format;
+	int remaining_time;
+	struct timeval start;
 
 	ast_format_clear(&orig_write_format);
 	ast_format_clear(&orig_read_format);
@@ -1379,8 +1386,9 @@
 	ast_debug(5, "channel %s will wait on FAX fd %d\n", chan->name, fax->fd);
 
 	/* handle frames for the session */
-	ms = 1000;
-	while ((res > -1) && (ms > -1) && (timeout > 0)) {
+	remaining_time = timeout;
+	start = ast_tvnow();
+	while (remaining_time > 0) {
 		struct ast_channel *ready_chan;
 		int ofd, exception;
 
@@ -1397,7 +1405,7 @@
 				GENERIC_FAX_EXEC_SET_VARS(fax, chan, "HANGUP", "remote channel hungup");
 				c = NULL;
 				chancount = 0;
-				timeout -= (1000 - ms);
+				remaining_time = ast_remaining_ms(start, timeout);
 				fax->tech->cancel_session(fax);
 				if (fax->tech->generate_silence) {
 					fax->tech->generate_silence(fax);
@@ -1466,7 +1474,7 @@
 					fax->tech->write(fax, frame);
 					fax->frames_received++;
 				}
-				timeout = RES_FAX_TIMEOUT;
+				start = ast_tvnow();
 			}
 			ast_frfree(frame);
 		} else if (ofd == fax->fd) {
@@ -1483,36 +1491,30 @@
 			ast_write(chan, frame);
 			fax->frames_sent++;
 			ast_frfree(frame);
-			timeout = RES_FAX_TIMEOUT;
+			start = ast_tvnow();
 		} else {
 			if (ms && (ofd < 0)) {
 				if ((errno == 0) || (errno == EINTR)) {
-					timeout -= (1000 - ms);
-					if (timeout <= 0)
+					remaining_time = ast_remaining_ms(start, timeout);
+					if (remaining_time <= 0)
 						GENERIC_FAX_EXEC_ERROR(fax, chan, "TIMEOUT", "fax session timed-out");
 					continue;
 				} else {
 					ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", chan->name);
 					GENERIC_FAX_EXEC_ERROR(fax, chan, "UNKNOWN", "error polling data");
-					res = ms;
 					break;
 				}
 			} else {
 				/* nothing happened */
-				if (timeout > 0) {
-					timeout -= 1000;
-					if (timeout <= 0)
-						GENERIC_FAX_EXEC_ERROR(fax, chan, "TIMEOUT", "fax session timed-out");
-					continue;
-				} else {
-					ast_log(LOG_WARNING, "channel '%s' timed-out during the FAX transmission.\n", chan->name);
+				remaining_time = ast_remaining_ms(start, timeout);
+				if (remaining_time <= 0) {
 					GENERIC_FAX_EXEC_ERROR(fax, chan, "TIMEOUT", "fax session timed-out");
 					break;
 				}
 			}
 		}
 	}
-	ast_debug(3, "channel '%s' - event loop stopped { timeout: %d, ms: %d, res: %d }\n", chan->name, timeout, ms, res);
+	ast_debug(3, "channel '%s' - event loop stopped { timeout: %d, remaining_time: %d }\n", chan->name, timeout, remaining_time);
 
 	set_channel_variables(chan, details);
 
@@ -1546,9 +1548,11 @@
 
 static int receivefax_t38_init(struct ast_channel *chan, struct ast_fax_session_details *details)
 {
-	int ms;
+	int timeout_ms;
 	struct ast_frame *frame = NULL;
 	struct ast_control_t38_parameters t38_parameters;
+	struct timeval start;
+	int ms;
 
 	/* don't send any audio if we've already received a T.38 reinvite */
 	if (ast_channel_get_t38_state(chan) != T38_STATE_NEGOTIATING) {
@@ -1558,9 +1562,11 @@
 			return -1;
 		}
 
-		ms = 3000;
-		while (ms > 0) {
+		timeout_ms = 3000;
+		start = ast_tvnow();
+		while ((ms = ast_remaining_ms(start, timeout_ms))) {
 			ms = ast_waitfor(chan, ms);
+
 			if (ms < 0) {
 				ast_log(LOG_ERROR, "error while generating CED tone on %s\n", chan->name);
 				ast_playtones_stop(chan);
@@ -1617,7 +1623,7 @@
 	ast_debug(1, "Negotiating T.38 for receive on %s\n", chan->name);
 
 	/* wait up to five seconds for negotiation to complete */
-	ms = 5000;
+	timeout_ms = 5000;
 
 	/* set parameters based on the session's parameters */
 	t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
@@ -1626,13 +1632,15 @@
 		return -1;
 	}
 
-	while (ms > 0) {
+	start = ast_tvnow();
+	while ((ms = ast_remaining_ms(start, timeout_ms))) {
+		int break_loop = 0;
+
 		ms = ast_waitfor(chan, ms);
 		if (ms < 0) {
 			ast_log(LOG_WARNING, "error on '%s' while waiting for T.38 negotiation.\n", chan->name);
 			return -1;
 		}
-
 		if (ms == 0) { /* all done, nothing happened */
 			ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", chan->name);
 			details->caps &= ~AST_FAX_TECH_T38;
@@ -1660,21 +1668,24 @@
 				t38_parameters_ast_to_fax(&details->their_t38_parameters, parameters);
 				details->caps &= ~AST_FAX_TECH_AUDIO;
 				report_fax_status(chan, details, "T.38 Negotiated");
-				ms = 0;
+				break_loop = 1;
 				break;
 			case AST_T38_REFUSED:
 				ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", chan->name);
 				details->caps &= ~AST_FAX_TECH_T38;
-				ms = 0;
+				break_loop = 1;
 				break;
 			default:
 				ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", chan->name);
 				details->caps &= ~AST_FAX_TECH_T38;
-				ms = 0;
+				break_loop = 1;
 				break;
 			}
 		}
 		ast_frfree(frame);
+		if (break_loop) {
+			break;
+		}
 	}
 
 	/* if T.38 was negotiated, we are done initializing */
@@ -1942,9 +1953,11 @@
 
 static int sendfax_t38_init(struct ast_channel *chan, struct ast_fax_session_details *details)
 {
-	int ms;
+	int timeout_ms;
 	struct ast_frame *frame = NULL;
 	struct ast_control_t38_parameters t38_parameters;
+	struct timeval start;
+	int ms;
 
 	/* send CNG tone while listening for the receiver to initiate a switch
 	 * to T.38 mode; if they do, stop sending the CNG tone and proceed with
@@ -1952,7 +1965,7 @@
 	 *
 	 * 10500 is enough time for 3 CNG tones
 	 */
-	ms = 10500;
+	timeout_ms = 10500;
 

[... 128 lines stripped ...]



More information about the asterisk-commits mailing list