[libpri-commits] trunk r356 - in /trunk: pri.c pri_q931.h q921.c q931.c

libpri-commits at lists.digium.com libpri-commits at lists.digium.com
Thu Jul 6 14:11:37 MST 2006


Author: mattf
Date: Thu Jul  6 16:11:37 2006
New Revision: 356

URL: http://svn.digium.com/view/libpri?rev=356&view=rev
Log:
Updates to add T309 to libpri.  Thanks flefoll!

Modified:
    trunk/pri.c
    trunk/pri_q931.h
    trunk/q921.c
    trunk/q931.c

Modified: trunk/pri.c
URL: http://svn.digium.com/view/libpri/trunk/pri.c?rev=356&r1=355&r2=356&view=diff
==============================================================================
--- trunk/pri.c (original)
+++ trunk/pri.c Thu Jul  6 16:11:37 2006
@@ -781,6 +781,7 @@
 	len += sprintf(buf + len, "T203 Timer: %d\n", pri->timers[PRI_TIMER_T203]);
 	len += sprintf(buf + len, "T305 Timer: %d\n", pri->timers[PRI_TIMER_T305]);
 	len += sprintf(buf + len, "T308 Timer: %d\n", pri->timers[PRI_TIMER_T308]);
+	len += sprintf(buf + len, "T309 Timer: %d\n", pri->timers[PRI_TIMER_T309]);
 	len += sprintf(buf + len, "T313 Timer: %d\n", pri->timers[PRI_TIMER_T313]);
 	len += sprintf(buf + len, "N200 Counter: %d\n", pri->timers[PRI_TIMER_N200]);
 

Modified: trunk/pri_q931.h
URL: http://svn.digium.com/view/libpri/trunk/pri_q931.h?rev=356&r1=355&r2=356&view=diff
==============================================================================
--- trunk/pri_q931.h (original)
+++ trunk/pri_q931.h Thu Jul  6 16:11:37 2006
@@ -285,5 +285,7 @@
 extern void q931_dump(struct pri *pri, q931_h *h, int len, int txrx);
 
 extern void __q931_destroycall(struct pri *pri, q931_call *c);
-	
+
+extern void q931_dl_indication(struct pri *pri, int event);
+
 #endif

Modified: trunk/q921.c
URL: http://svn.digium.com/view/libpri/trunk/q921.c?rev=356&r1=355&r2=356&view=diff
==============================================================================
--- trunk/q921.c (original)
+++ trunk/q921.c Thu Jul  6 16:11:37 2006
@@ -667,6 +667,9 @@
 	/* Start the T203 timer */
 	pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri);
 	
+	/* Notify Layer 3 */
+	q931_dl_indication(pri, PRI_EVENT_DCHAN_UP);
+
 	/* Report event that D-Channel is now up */
 	pri->ev.gen.e = PRI_EVENT_DCHAN_UP;
 	return &pri->ev;
@@ -677,6 +680,9 @@
 	/* Reset counters, reset sabme timer etc */
 	q921_reset(pri);
 	
+	/* Notify Layer 3 */
+	q931_dl_indication(pri, PRI_EVENT_DCHAN_DOWN);
+
 	/* Report event that D-Channel is now up */
 	pri->ev.gen.e = PRI_EVENT_DCHAN_DOWN;
 	return &pri->ev;

Modified: trunk/q931.c
URL: http://svn.digium.com/view/libpri/trunk/q931.c?rev=356&r1=355&r2=356&view=diff
==============================================================================
--- trunk/q931.c (original)
+++ trunk/q931.c Thu Jul  6 16:11:37 2006
@@ -216,6 +216,18 @@
 #define FUNC_RECV(name) int ((name))(int full_ie, struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
 #define FUNC_SEND(name) int ((name))(int full_ie, struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
 
+#if 1
+/* Update call state with transition trace. */
+#define UPDATE_OURCALLSTATE(pri,c,newstate) do {\
+	if (pri->debug & (PRI_DEBUG_Q931_STATE) && c->ourcallstate != newstate) \
+		pri_message(pri, DBGHEAD "call %d on channel %d enters state %d (%s)\n", DBGINFO, \
+		            c->cr, c->channelno, newstate, callstate2str(newstate)); \
+	c->ourcallstate = newstate; \
+	} while (0)
+#else
+/* Update call state with no trace. */
+#define UPDATE_OURCALLSTATE(pri,c,newstate) c->ourcallstate = newstate
+#endif
 
 struct ie {
 	/* Maximal count of same IEs at the message (0 - any, 1..n - limited) */
@@ -2484,7 +2496,7 @@
 
 static int restart_ack(struct pri *pri, q931_call *c)
 {
-	c->ourcallstate = Q931_CALL_STATE_NULL;
+	UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL);
 	c->peercallstate = Q931_CALL_STATE_NULL;
 	return send_message(pri, c, Q931_RESTART_ACKNOWLEDGE, restart_ack_ies);
 }
@@ -2555,7 +2567,7 @@
 	}
 	c->chanflags &= ~FLAG_PREFERRED;
 	c->chanflags |= FLAG_EXCLUSIVE;
-	c->ourcallstate = Q931_CALL_STATE_INCOMING_CALL_PROCEEDING;
+	UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_INCOMING_CALL_PROCEEDING);
 	c->peercallstate = Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING;
 	if (info) {
 		c->progloc = LOC_PRIV_NET_LOCAL_USER;
@@ -2583,7 +2595,7 @@
 		c->progressmask = PRI_PROG_INBAND_AVAILABLE;
 	} else
 		c->progressmask = 0;
-	c->ourcallstate = Q931_CALL_STATE_CALL_RECEIVED;
+	UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CALL_RECEIVED);
 	c->peercallstate = Q931_CALL_STATE_CALL_DELIVERED;
 	c->alive = 1;
 	return send_message(pri, c, Q931_ALERTING, alerting_ies);
@@ -2607,7 +2619,7 @@
 		c->progressmask = PRI_PROG_CALLED_NOT_ISDN;
 	} else
 		c->progressmask = 0;
-	c->ourcallstate = Q931_CALL_STATE_OVERLAP_RECEIVING;
+	UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_OVERLAP_RECEIVING);
 	c->peercallstate = Q931_CALL_STATE_OVERLAP_SENDING;
 	c->alive = 1;
 	return send_message(pri, c, Q931_SETUP_ACKNOWLEDGE, connect_ies);
@@ -2681,10 +2693,11 @@
 		c->progressmask = PRI_PROG_CALLED_NOT_ISDN;
 	} else
 		c->progressmask = 0;
-	if (pri->localtype == PRI_CPE)
-		c->ourcallstate = Q931_CALL_STATE_CONNECT_REQUEST;
-	else
-		c->ourcallstate = Q931_CALL_STATE_ACTIVE;
+	if (pri->localtype == PRI_CPE) {
+		UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CONNECT_REQUEST);
+	} else {
+		UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_ACTIVE);
+	}
 	c->peercallstate = Q931_CALL_STATE_ACTIVE;
 	c->alive = 1;
 	/* Setup timer */
@@ -2700,7 +2713,7 @@
 
 int q931_release(struct pri *pri, q931_call *c, int cause)
 {
-	c->ourcallstate = Q931_CALL_STATE_RELEASE_REQUEST;
+	UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_RELEASE_REQUEST);
 	/* c->peercallstate stays the same */
 	if (c->alive) {
 		c->alive = 0;
@@ -2739,7 +2752,7 @@
 	c->channelno = channel;		
 	c->chanflags &= ~FLAG_PREFERRED;
 	c->chanflags |= FLAG_EXCLUSIVE;
-	c->ourcallstate = Q931_CALL_STATE_RESTART;
+	UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_RESTART);
 	c->peercallstate = Q931_CALL_STATE_RESTART_REQUEST;
 	return send_message(pri, c, Q931_RESTART, restart_ies);
 }
@@ -2748,7 +2761,7 @@
 
 int q931_disconnect(struct pri *pri, q931_call *c, int cause)
 {
-	c->ourcallstate = Q931_CALL_STATE_DISCONNECT_REQUEST;
+	UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_DISCONNECT_REQUEST);
 	c->peercallstate = Q931_CALL_STATE_DISCONNECT_INDICATION;
 	if (c->alive) {
 		c->alive = 0;
@@ -2864,7 +2877,7 @@
 		c->alive = 1;
 		/* make sure we call PRI_EVENT_HANGUP_ACK once we send/receive RELEASE_COMPLETE */
 		c->sendhangupack = 1;
-		c->ourcallstate = Q931_CALL_STATE_CALL_INITIATED;
+		UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CALL_INITIATED);
 		c->peercallstate = Q931_CALL_STATE_OVERLAP_SENDING;	
 	}
 	return res;
@@ -2876,7 +2889,7 @@
 static int q931_release_complete(struct pri *pri, q931_call *c, int cause)
 {
 	int res = 0;
-	c->ourcallstate = Q931_CALL_STATE_NULL;
+	UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL);
 	c->peercallstate = Q931_CALL_STATE_NULL;
 	if (cause > -1) {
 		c->cause = cause;
@@ -3256,7 +3269,7 @@
 			q931_destroycall(pri, c->cr);
 			break;
 		}
-		c->ourcallstate = Q931_CALL_STATE_RESTART;
+		UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_RESTART);
 		c->peercallstate = Q931_CALL_STATE_RESTART_REQUEST;
 		/* Send back the Restart Acknowledge */
 		restart_ack(pri, c);
@@ -3276,7 +3289,7 @@
 		if (c->progressmask & PRI_PROG_CALLER_NOT_ISDN)
 			c->nonisdn = 1;
 		c->newcall = 0;
-		c->ourcallstate = Q931_CALL_STATE_CALL_PRESENT;
+		UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CALL_PRESENT);
 		c->peercallstate = Q931_CALL_STATE_CALL_INITIATED;
 		/* it's not yet a call since higher level can respond with RELEASE or RELEASE_COMPLETE */
 		c->alive = 0;
@@ -3321,7 +3334,7 @@
 			q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
 			break;
 		}
-		c->ourcallstate = Q931_CALL_STATE_CALL_DELIVERED;
+		UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CALL_DELIVERED);
 		c->peercallstate = Q931_CALL_STATE_CALL_RECEIVED;
 		pri->ev.e = PRI_EVENT_RINGING;
 		pri->ev.ringing.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
@@ -3341,7 +3354,7 @@
 			q931_status(pri, c, PRI_CAUSE_WRONG_MESSAGE);
 			break;
 		}
-		c->ourcallstate = Q931_CALL_STATE_ACTIVE;
+		UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_ACTIVE);
 		c->peercallstate = Q931_CALL_STATE_CONNECT_REQUEST;
 		pri->ev.e = PRI_EVENT_ANSWER;
 		pri->ev.answer.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
@@ -3396,7 +3409,7 @@
 		pri->ev.proceeding.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
 		if (mh->msg == Q931_CALL_PROCEEDING) {
 			pri->ev.e = PRI_EVENT_PROCEEDING;
-			c->ourcallstate = Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING;
+			UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING);
 			c->peercallstate = Q931_CALL_STATE_INCOMING_CALL_PROCEEDING;
 		}
 		pri->ev.proceeding.progress = c->progress;
@@ -3413,7 +3426,7 @@
 			q931_status(pri,c,PRI_CAUSE_WRONG_MESSAGE);
 			break;
 		}
-		c->ourcallstate = Q931_CALL_STATE_ACTIVE;
+		UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_ACTIVE);
 		c->peercallstate = Q931_CALL_STATE_ACTIVE;
 		break;
 	case Q931_STATUS:
@@ -3441,7 +3454,7 @@
 			pri->ev.hangup.aoc_units = c->aoc_units;
 			libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo));
 			/* Free resources */
-			c->ourcallstate = Q931_CALL_STATE_NULL;
+			UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL);
 			c->peercallstate = Q931_CALL_STATE_NULL;
 			if (c->alive) {
 				pri->ev.e = PRI_EVENT_HANGUP;
@@ -3460,7 +3473,7 @@
 		}
 		break;
 	case Q931_RELEASE_COMPLETE:
-		c->ourcallstate = Q931_CALL_STATE_NULL;
+		UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL);
 		c->peercallstate = Q931_CALL_STATE_NULL;
 		pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
 		pri->ev.hangup.cause = c->cause;
@@ -3495,7 +3508,7 @@
 		else {
 			c->peercallstate = Q931_CALL_STATE_RELEASE_REQUEST;
 		}
-		c->ourcallstate = Q931_CALL_STATE_NULL;
+		UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL);
 		pri->ev.e = PRI_EVENT_HANGUP;
 		pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
 		pri->ev.hangup.cause = c->cause;
@@ -3520,7 +3533,7 @@
 			q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
 			break;
 		}
-		c->ourcallstate = Q931_CALL_STATE_DISCONNECT_INDICATION;
+		UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_DISCONNECT_INDICATION);
 		c->peercallstate = Q931_CALL_STATE_DISCONNECT_REQUEST;
 		c->sendhangupack = 1;
 		/* Return such an event */
@@ -3538,7 +3551,7 @@
 			q931_hangup(pri,c,c->cause);
 		break;
 	case Q931_RESTART_ACKNOWLEDGE:
-		c->ourcallstate = Q931_CALL_STATE_NULL;
+		UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL);
 		c->peercallstate = Q931_CALL_STATE_NULL;
 		pri->ev.e = PRI_EVENT_RESTART_ACK;
 		pri->ev.restartack.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
@@ -3579,7 +3592,7 @@
 			q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
 			break;
 		}
-		c->ourcallstate = Q931_CALL_STATE_OVERLAP_SENDING;
+		UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_OVERLAP_SENDING);
 		c->peercallstate = Q931_CALL_STATE_OVERLAP_RECEIVING;
 		pri->ev.e = PRI_EVENT_SETUP_ACK;
 		pri->ev.setup_ack.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
@@ -3628,6 +3641,131 @@
 	return 0;
 }
 
+/* Clear a call, although we did not receive any hangup notification. */
+static int pri_internal_clear(void *data)
+{
+	struct q931_call *c = data;
+	struct pri *pri = c->pri;
+	int res;
+
+	if (c->retranstimer)
+		pri_schedule_del(pri, c->retranstimer);
+	c->retranstimer = 0;
+	c->useruserinfo[0] = '\0';
+	c->cause = -1;
+	c->causecode = -1;
+	c->causeloc = -1;
+	c->sugcallstate = -1;
+	c->aoc_units = -1;
+
+	UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL);
+	c->peercallstate = Q931_CALL_STATE_NULL;
+	pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+	pri->ev.hangup.cause = c->cause;      		
+	pri->ev.hangup.cref = c->cr;          		
+	pri->ev.hangup.call = c;              		
+	pri->ev.hangup.aoc_units = c->aoc_units;
+	libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo));
+
+	/* Free resources */
+	if (c->alive) {
+		pri->ev.e = PRI_EVENT_HANGUP;
+		res = Q931_RES_HAVEEVENT;
+		c->alive = 0;
+	} else if (c->sendhangupack) {
+		res = Q931_RES_HAVEEVENT;
+		pri->ev.e = PRI_EVENT_HANGUP_ACK;
+		q931_hangup(pri, c, c->cause);
+	} else {
+		res = 0;
+		q931_hangup(pri, c, c->cause);
+	}
+
+	return res;
+}
+
+/* Handle T309 timeout for an active call. */
+static void pri_dl_down_timeout(void *data)
+{
+	struct q931_call *c = data;
+	struct pri *pri = c->pri;
+	if (pri->debug & PRI_DEBUG_Q931_STATE)
+		pri_message(pri, DBGHEAD "Timed out waiting for data link re-establishment\n", DBGINFO);
+
+	c->cause = PRI_CAUSE_DESTINATION_OUT_OF_ORDER;
+	if (pri_internal_clear(c) == Q931_RES_HAVEEVENT)
+		pri->schedev = 1;
+}
+
+/* Handle Layer 2 down event for a non active call. */
+static void pri_dl_down_cancelcall(void *data)
+{
+	struct q931_call *c = data;
+	struct pri *pri = c->pri;
+	if (pri->debug & PRI_DEBUG_Q931_STATE)
+		pri_message(pri, DBGHEAD "Cancel non active call after data link failure\n", DBGINFO);
+
+	c->cause = PRI_CAUSE_DESTINATION_OUT_OF_ORDER;
+	if (pri_internal_clear(c) == Q931_RES_HAVEEVENT)
+		pri->schedev = 1;
+}
+
+/* Receive an indication from Layer 2 */
+void q931_dl_indication(struct pri *pri, int event)
+{
+	q931_call *cur = NULL;
+
+	/* Just return if T309 is not enabled. */
+	if (!pri || pri->timers[PRI_TIMER_T309] < 0)
+		return;
+
+	switch (event) {
+	case PRI_EVENT_DCHAN_DOWN:
+		pri_message(pri, DBGHEAD "link is DOWN\n", DBGINFO);
+		cur = *pri->callpool;
+		while(cur) {
+			if (cur->ourcallstate == Q931_CALL_STATE_ACTIVE) {
+				/* For a call in Active state, activate T309 only if there is no timer already running. */
+				if (!cur->retranstimer) {
+					pri_message(pri, DBGHEAD "activate T309 for call %d on channel %d\n", DBGINFO, cur->cr, cur->channelno);
+					cur->retranstimer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T309], pri_dl_down_timeout, cur);
+				}
+			} else if (cur->ourcallstate != Q931_CALL_STATE_NULL) {
+				/* For a call that is not in Active state, schedule internal clearing of the call 'ASAP' (delay 0). */
+				pri_message(pri, DBGHEAD "cancel call %d on channel %d in state %d (%s)\n", DBGINFO,
+				            cur->cr, cur->channelno, cur->ourcallstate, callstate2str(cur->ourcallstate));
+				if (cur->retranstimer)
+					pri_schedule_del(pri, cur->retranstimer);
+				cur->retranstimer = pri_schedule_event(pri, 0, pri_dl_down_cancelcall, cur);
+			}
+			cur = cur->next;
+		}
+		break;
+	case PRI_EVENT_DCHAN_UP:
+		pri_message(pri, DBGHEAD "link is UP\n", DBGINFO);
+		cur = *pri->callpool;
+		while(cur) {
+			if (cur->ourcallstate == Q931_CALL_STATE_ACTIVE && cur->retranstimer) {
+				pri_message(pri, DBGHEAD "cancel T309 for call %d on channel %d\n", DBGINFO, cur->cr, cur->channelno);
+				pri_schedule_del(pri, cur->retranstimer);
+				cur->retranstimer = 0;
+				q931_status(pri, cur, PRI_CAUSE_NORMAL_UNSPECIFIED);
+			} else if (cur->ourcallstate != Q931_CALL_STATE_NULL &&
+				cur->ourcallstate != Q931_CALL_STATE_DISCONNECT_REQUEST &&
+				cur->ourcallstate != Q931_CALL_STATE_DISCONNECT_INDICATION &&
+				cur->ourcallstate != Q931_CALL_STATE_RELEASE_REQUEST) {
+
+				/* The STATUS message sent here is not required by Q.931, but it may help anyway. */
+				q931_status(pri, cur, PRI_CAUSE_NORMAL_UNSPECIFIED);
+			}
+			cur = cur->next;
+		}
+		break;
+	default:
+		pri_message(pri, DBGHEAD "unexpected event %d.\n", DBGINFO, event);
+	}
+}
+
 int q931_call_getcrv(struct pri *pri, q931_call *call, int *callmode)
 {
 	if (callmode)



More information about the libpri-commits mailing list