[libpri-commits] rmudgett: branch 1.4 r2288 - /branches/1.4/

SVN commits to the libpri project libpri-commits at lists.digium.com
Wed Jun 27 19:16:38 CDT 2012


Author: rmudgett
Date: Wed Jun 27 19:16:33 2012
New Revision: 2288

URL: http://svnview.digium.com/svn/libpri?view=rev&rev=2288
Log:
Implement T316 to allow RESTART messages to be automatically retransmitted.

Q.931 defines the T316 timer to retransmit RESTART messages if a RESTART
ACKNOWLEDGE message is not received before the timer expires.  Q.931
defaults the time of T316 to 2 minutes with the default number of
consecutive RESTART failures as two.

* To support legacy behavior, the T316 timer is disabled by default.  It
is also disabled because the user cannot configure it to disabled if it is
enabled.

* The N316 count is created to allow the number of RESTART attempts to be
configurable.  Note you will need to recompile Asterisk to be able to
configure N316.

(issue ASTERISK-19608)
(issue AST-815)
(closes issue PRI-133)
Reported by: Mike Boylan
Tested by: rmudgett

Modified:
    branches/1.4/libpri.h
    branches/1.4/pri.c
    branches/1.4/pri_internal.h
    branches/1.4/q931.c

Modified: branches/1.4/libpri.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/libpri.h?view=diff&rev=2288&r1=2287&r2=2288
==============================================================================
--- branches/1.4/libpri.h (original)
+++ branches/1.4/libpri.h Wed Jun 27 19:16:33 2012
@@ -2179,7 +2179,7 @@
 	PRI_TIMER_T310,	/*!< Maximum time between receiving a CALL_PROCEEDING and receiving a ALERT/CONNECT/DISCONNECT/PROGRESS */
 	PRI_TIMER_T313,	/*!< Wait for CONNECT acknowledge, CPE side only */
 	PRI_TIMER_T314,
-	PRI_TIMER_T316,	/*!< Maximum time between transmitting a RESTART and receiving a RESTART ACK */
+	PRI_TIMER_T316,	/*!< Time to wait for a RESTART ACK before retransmitting RESTART. (Timer enabled if greater than zero.) */
 	PRI_TIMER_T317,
 	PRI_TIMER_T318,
 	PRI_TIMER_T319,
@@ -2221,6 +2221,7 @@
 	PRI_TIMER_QSIG_CC_T4,	/*!< Path reservation supervision timeout. */
 
 	PRI_TIMER_T312,			/*!< Supervise broadcast SETUP message call reference retention. */
+	PRI_TIMER_N316,			/*!< Number of times to transmit RESTART before giving up if T316 enabled. */
 
 	/* Must be last in the enum list */
 	PRI_MAX_TIMERS

Modified: branches/1.4/pri.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri.c?view=diff&rev=2288&r1=2287&r2=2288
==============================================================================
--- branches/1.4/pri.c (original)
+++ branches/1.4/pri.c Wed Jun 27 19:16:33 2012
@@ -81,6 +81,7 @@
 	{ "T313",           PRI_TIMER_T313,             PRI_ALL_SWITCHES },
 	{ "T314",           PRI_TIMER_T314,             PRI_ALL_SWITCHES },
 	{ "T316",           PRI_TIMER_T316,             PRI_ALL_SWITCHES },
+	{ "N316",           PRI_TIMER_N316,             PRI_ALL_SWITCHES },
 	{ "T317",           PRI_TIMER_T317,             PRI_ALL_SWITCHES },
 	{ "T318",           PRI_TIMER_T318,             PRI_ALL_SWITCHES },
 	{ "T319",           PRI_TIMER_T319,             PRI_ALL_SWITCHES },
@@ -184,6 +185,10 @@
 	ctrl->timers[PRI_TIMER_T309] = 6 * 1000;	/* Time to wait before clearing calls in case of D-channel transient event.  Q.931 specifies 6-90 seconds */
 	ctrl->timers[PRI_TIMER_T312] = (4 + 2) * 1000;/* Supervise broadcast SETUP message call reference retention. T303 + 2 seconds */
 	ctrl->timers[PRI_TIMER_T313] = 4 * 1000;	/* Wait for CONNECT acknowledge, CPE side only */
+#if 0	/* Default disable the T316 timer otherwise the user cannot disable it. */
+	ctrl->timers[PRI_TIMER_T316] = 2 * 60 * 1000;	/* RESTART retransmit timer */
+#endif
+	ctrl->timers[PRI_TIMER_N316] = 2;			/* Send RESTART this many times before giving up. */
 
 	ctrl->timers[PRI_TIMER_TM20] = 2500;		/* Max time awaiting XID response - Q.921 Appendix IV */
 	ctrl->timers[PRI_TIMER_NM20] = 3;			/* Number of XID retransmits - Q.921 Appendix IV */
@@ -1795,7 +1800,8 @@
 			enum PRI_TIMERS_AND_COUNTERS tmr;
 
 			tmr = pri_timer[idx].number;
-			if (0 <= ctrl->timers[tmr]) {
+			if (0 <= ctrl->timers[tmr]
+				|| tmr == PRI_TIMER_T316) {
 				used = pri_snprintf(buf, used, buf_size, "  %s: %d\n",
 					pri_timer[idx].name, ctrl->timers[tmr]);
 			}

Modified: branches/1.4/pri_internal.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri_internal.h?view=diff&rev=2288&r1=2287&r2=2288
==============================================================================
--- branches/1.4/pri_internal.h (original)
+++ branches/1.4/pri_internal.h Wed Jun 27 19:16:33 2012
@@ -652,6 +652,7 @@
 
 	unsigned int slotmap_size:1;/* TRUE if the slotmap is E1 (32 bits). */
 
+	/*! Control the RESTART reception to the upper layer. */
 	struct {
 		/*! Timer ID of RESTART notification events to upper layer. */
 		int timer;
@@ -662,6 +663,15 @@
 		/*! Channel ID list */
 		char chan_no[32];
 	} restart;
+	/*! Control the RESTART retransmissions. */
+	struct {
+		/*! T316 RESTART retransmit timer. */
+		int t316_timer;
+		/*! Number of times remaining that RESTART can be transmitted. */
+		int remain;
+		/*! Encoded RESTART channel id. */
+		int channel;
+	} restart_tx;
 };
 
 enum CC_STATES {

Modified: branches/1.4/q931.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/q931.c?view=diff&rev=2288&r1=2287&r2=2288
==============================================================================
--- branches/1.4/q931.c (original)
+++ branches/1.4/q931.c Wed Jun 27 19:16:33 2012
@@ -4422,6 +4422,7 @@
 
 	ctrl = cur->pri;
 	pri_schedule_del(ctrl, cur->restart.timer);
+	pri_schedule_del(ctrl, cur->restart_tx.t316_timer);
 	pri_schedule_del(ctrl, cur->retranstimer);
 	pri_schedule_del(ctrl, cur->hold_timer);
 	pri_schedule_del(ctrl, cur->fake_clearing_timer);
@@ -5913,6 +5914,81 @@
 
 static int restart_ies[] = { Q931_CHANNEL_IDENT, Q931_RESTART_INDICATOR, -1 };
 
+static void t316_expire(void *vcall);
+
+/*!
+ * \internal
+ * \brief Send the RESTART message to the peer.
+ *
+ * \param call Q.931 call leg
+ * \param channel Encoded channel id to use.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int q931_send_restart(struct q931_call *call)
+{
+	struct pri *ctrl = call->pri;
+	int channel = call->restart_tx.channel;
+
+	/* Start timer T316 if enabled. */
+	if (0 < ctrl->timers[PRI_TIMER_T316]) {
+		call->restart_tx.t316_timer =
+			pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T316], t316_expire, call);
+		--call->restart_tx.remain;
+	}
+
+	call->ri = 0;
+	call->ds1no = (channel >> 8) & 0xFF;
+	call->ds1explicit = (channel >> 16) & 0x1;
+	call->channelno = channel & 0xFF;
+	call->chanflags &= ~FLAG_PREFERRED;
+	call->chanflags |= FLAG_EXCLUSIVE;
+	UPDATE_OURCALLSTATE(ctrl, call, Q931_CALL_STATE_RESTART);
+	call->peercallstate = Q931_CALL_STATE_RESTART_REQUEST;
+	return send_message(ctrl, call, Q931_RESTART, restart_ies);
+}
+
+/*!
+ * \internal
+ * \brief T316 expired.
+ *
+ * \param vcall Q.931 call leg
+ *
+ * \return Nothing
+ */
+static void t316_expire(void *vcall)
+{
+	struct q931_call *call = vcall;
+
+	call->restart_tx.t316_timer = 0;
+
+	if (call->restart_tx.remain) {
+		/* Retransmit the RESTART */
+		q931_send_restart(call);
+	} else {
+		int channel = call->restart_tx.channel;
+
+		pri_message(call->pri,
+			"!! Peer failed to ack our RESTART request for ds1/channel:%d/%d.\n",
+			(channel >> 8) & 0xFF, channel & 0xFF);
+	}
+}
+
+/*!
+ * \internal
+ * \brief Stop timer T316.
+ *
+ * \param call Q.931 call leg
+ *
+ * \return Nothing
+ */
+static void stop_t316(struct q931_call *call)
+{
+	pri_schedule_del(call->pri, call->restart_tx.t316_timer);
+	call->restart_tx.t316_timer = 0;
+}
+
 /*!
  * \brief Send the RESTART message to the peer.
  *
@@ -5930,9 +6006,6 @@
  * there might not be anything connected.  The broadcast could
  * be handled in a similar manner to the broadcast SETUP.
  *
- * \todo Need to implement T316 to protect against missing
- * RESTART_ACKNOWLEDGE and STATUS messages.
- *
  * \todo NT PTMP mode should implement some protection from
  * receiving a RESTART on channels in use by another TEI.
  *
@@ -5941,22 +6014,21 @@
  */
 int q931_restart(struct pri *ctrl, int channel)
 {
-	struct q931_call *c;
-
-	c = q931_getcall(&ctrl->link, 0 | Q931_CALL_REFERENCE_FLAG);
-	if (!c)
+	struct q931_call *call;
+
+	if (!channel) {
 		return -1;
-	if (!channel)
+	}
+	call = q931_getcall(&ctrl->link, 0 | Q931_CALL_REFERENCE_FLAG);
+	if (!call) {
 		return -1;
-	c->ri = 0;
-	c->ds1no = (channel & 0xff00) >> 8;
-	c->ds1explicit = (channel & 0x10000) >> 16;
-	c->channelno = channel & 0xff;
-	c->chanflags &= ~FLAG_PREFERRED;
-	c->chanflags |= FLAG_EXCLUSIVE;
-	UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_RESTART);
-	c->peercallstate = Q931_CALL_STATE_RESTART_REQUEST;
-	return send_message(ctrl, c, Q931_RESTART, restart_ies);
+	}
+
+	stop_t316(call);
+	call->restart_tx.remain = (0 < ctrl->timers[PRI_TIMER_N316])
+		? ctrl->timers[PRI_TIMER_N316] : 1;
+	call->restart_tx.channel = channel;
+	return q931_send_restart(call);
 }
 
 static int disconnect_ies[] = { Q931_CAUSE, Q931_IE_FACILITY, Q931_IE_USER_USER, -1 };
@@ -9007,6 +9079,16 @@
 		c->peercallstate = Q931_CALL_STATE_NULL;
 		ctrl->ev.e = PRI_EVENT_RESTART_ACK;
 		ctrl->ev.restartack.channel = q931_encode_channel(c);
+		if (c->restart_tx.t316_timer
+			/*
+			 * Since the DS1 value can vary, only check the channel number.
+			 * We're only supposed to have one RESTART request outstanding
+			 * at a time anyway.
+			 */
+			&& (c->restart_tx.channel & 0xFF) == (ctrl->ev.restartack.channel & 0xFF)) {
+			/* This is the RESTART ACKNOWLEDGE we are expecting. */
+			stop_t316(c);
+		}
 		return Q931_RES_HAVEEVENT;
 	case Q931_INFORMATION:
 		/* XXX We're handling only INFORMATION messages that contain




More information about the libpri-commits mailing list