[svn-commits] mattf: branch mattf/libpri-1.4-q921-rewrite r1362 - /team/mattf/libpri-1.4-q9...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Wed Dec 2 15:34:32 CST 2009


Author: mattf
Date: Wed Dec  2 15:34:28 2009
New Revision: 1362

URL: http://svnview.digium.com/svn/libpri?view=rev&rev=1362
Log:
Merged revisions 1310,1316,1322,1331,1345,1351 via svnmerge from 
https://origsvn.digium.com/svn/libpri/branches/1.4

................
r1310 | rmudgett | 2009-11-13 16:59:35 -0600 (Fri, 13 Nov 2009) | 6 lines

There must be only one source for the invoke id values per D channel group.

If there are potentially multiple sources for the invoke id sequence then
we could get confused if there are multiple outstanding messages with the
same invoke id that get responses.

................
r1316 | rmudgett | 2009-11-13 17:46:57 -0600 (Fri, 13 Nov 2009) | 1 line

We now have 32 timers.  No need to reserve minimum space anymore.
................
r1322 | rmudgett | 2009-11-13 18:20:53 -0600 (Fri, 13 Nov 2009) | 14 lines

Reimplement callback mechanism to handle APDU response messages that we care about.

1) No sent messages will remain in the APDU queue unless they have an
active timer to remove them.  The dummy call reference call and global
call reference call structures will not act like a memory leak to sent
messages.

2) The new T-RESPONSE timer will be the generic response guard if the
standards do not otherwise specify a timer for a message response.

3) The callback will be called.  If it is called because of a response
message, then the callback has an opportunity to indicate if more
responses are expected.

................
r1331 | rmudgett | 2009-11-17 18:36:20 -0600 (Tue, 17 Nov 2009) | 11 lines

Merged revision 1328 from
https://origsvn.digium.com/svn/libpri/team/mattf/libpri-1.4-q921-rewrite

..........
  r1328 | mattf | 2009-11-17 15:16:11 -0600 (Tue, 17 Nov 2009) | 1 line

  outboundbroadcast isn't set at this time, since it is set after the
  message is transmited, so we must use other criteria to determine the need
  for broadcast on a setup
..........

................
r1345 | rmudgett | 2009-11-20 17:42:40 -0600 (Fri, 20 Nov 2009) | 14 lines

Delay processing of facility ie's after all other ie's are processed.

*  Some ROSE message processing depends on the presence of other ies.  The
DivertingLegInformation1, and 3 messages will be used as the default
connected line number if the connected number ie is not present.  The
redirecting number ie is used as a default to the redirecting number in
the DivertingLegInformation2 message if the ROSE message does not contain
it and the redirecting number ie is present.

*  Some ROSE message processing depends upon other ie values.  The
StatusRequest, CCBS-T-Call, and CcRingout messages collectively need the
BC, HLC, LLC, called number, called subaddress, calling number, and
calling subaddress ie information to be available.

................
r1351 | rmudgett | 2009-11-20 20:40:23 -0600 (Fri, 20 Nov 2009) | 10 lines

Fix debug output so built up output lines are readable again.

A recent change to Asterisk put the span number at the begining of each
line.  This is a good thing if you need to debug multiple spans or forget
which span you are debugging.  Unfortunately, any pri_message() output
that is not a complete line is messed up.

The pri_message() function now will accumulate line output until a '\n' is
seen on the end.

................

Modified:
    team/mattf/libpri-1.4-q921-rewrite/   (props changed)
    team/mattf/libpri-1.4-q921-rewrite/libpri.h
    team/mattf/libpri-1.4-q921-rewrite/pri.c
    team/mattf/libpri-1.4-q921-rewrite/pri_facility.c
    team/mattf/libpri-1.4-q921-rewrite/pri_facility.h
    team/mattf/libpri-1.4-q921-rewrite/pri_internal.h
    team/mattf/libpri-1.4-q921-rewrite/q931.c

Propchange: team/mattf/libpri-1.4-q921-rewrite/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Wed Dec  2 15:34:28 2009
@@ -1,1 +1,1 @@
-/branches/1.4:1-1292
+/branches/1.4:1-1361

Modified: team/mattf/libpri-1.4-q921-rewrite/libpri.h
URL: http://svnview.digium.com/svn/libpri/team/mattf/libpri-1.4-q921-rewrite/libpri.h?view=diff&rev=1362&r1=1361&r2=1362
==============================================================================
--- team/mattf/libpri-1.4-q921-rewrite/libpri.h (original)
+++ team/mattf/libpri-1.4-q921-rewrite/libpri.h Wed Dec  2 15:34:28 2009
@@ -1296,9 +1296,10 @@
 	PRI_TIMER_T_HOLD,	/*!< Maximum time to wait for HOLD request response. */
 	PRI_TIMER_T_RETRIEVE,	/*!< Maximum time to wait for RETRIEVE request response. */
 
+	PRI_TIMER_T_RESPONSE,	/*!< Maximum time to wait for a typical APDU response. */
+
 	/* Must be last in the enum list */
-	_PRI_MAX_TIMERS,
-	PRI_MAX_TIMERS = (_PRI_MAX_TIMERS < 32) ? 32 : _PRI_MAX_TIMERS
+	PRI_MAX_TIMERS
 };
 
 /* Get PRI version */

Modified: team/mattf/libpri-1.4-q921-rewrite/pri.c
URL: http://svnview.digium.com/svn/libpri/team/mattf/libpri-1.4-q921-rewrite/pri.c?view=diff&rev=1362&r1=1361&r2=1362
==============================================================================
--- team/mattf/libpri-1.4-q921-rewrite/pri.c (original)
+++ team/mattf/libpri-1.4-q921-rewrite/pri.c Wed Dec  2 15:34:28 2009
@@ -88,6 +88,7 @@
 	{ "T322",           PRI_TIMER_T322,             PRI_ALL_SWITCHES },
 	{ "T-HOLD",         PRI_TIMER_T_HOLD,           PRI_ALL_SWITCHES },
 	{ "T-RETRIEVE",     PRI_TIMER_T_RETRIEVE,       PRI_ALL_SWITCHES },
+	{ "T-RESPONSE",     PRI_TIMER_T_RESPONSE,       PRI_ALL_SWITCHES },
 /* *INDENT-ON* */
 };
 
@@ -157,6 +158,8 @@
 	ctrl->timers[PRI_TIMER_T_HOLD] = 4 * 1000;	/* Wait for HOLD request response. */
 	ctrl->timers[PRI_TIMER_T_RETRIEVE] = 4 * 1000;/* Wait for RETRIEVE request response. */
 
+	ctrl->timers[PRI_TIMER_T_RESPONSE] = 4 * 1000;	/* Maximum time to wait for a typical APDU response. */
+
 	/* Set any switch specific override default values */
 	switch (switchtype) {
 	default:
@@ -236,6 +239,7 @@
 			pri_schedule_del(call->pri, call->retranstimer);
 			pri_call_apdu_queue_cleanup(call);
 		}
+		free(p->msg_line);
 		free(p);
 	}
 }
@@ -263,6 +267,14 @@
 		}
 		p = &dummy_ctrl->ctrl;
 		break;
+	}
+	if (!master) {
+		/* This is the master record. */
+		p->msg_line = calloc(1, sizeof(*p->msg_line));
+		if (!p->msg_line) {
+			free(p);
+			return NULL;
+		}
 	}
 
 	p->bri = bri;
@@ -1129,20 +1141,77 @@
 	__pri_error = func;
 }
 
-void pri_message(struct pri *pri, char *fmt, ...)
+static void pri_old_message(struct pri *ctrl, const char *fmt, va_list *ap)
 {
 	char tmp[1024];
-	va_list ap;
-	va_start(ap, fmt);
-	vsnprintf(tmp, sizeof(tmp), fmt, ap);
-	va_end(ap);
+
+	vsnprintf(tmp, sizeof(tmp), fmt, *ap);
 	if (__pri_message)
-		__pri_message(PRI_MASTER(pri), tmp);
+		__pri_message(ctrl, tmp);
 	else
 		fputs(tmp, stdout);
 }
 
-void pri_error(struct pri *pri, char *fmt, ...)
+void pri_message(struct pri *ctrl, const char *fmt, ...)
+{
+	int added_length;
+	va_list ap;
+
+	ctrl = PRI_MASTER(ctrl);
+	if (!ctrl || !ctrl->msg_line) {
+		/* Just have to do it the old way. */
+		va_start(ap, fmt);
+		pri_old_message(ctrl, fmt, &ap);
+		va_end(ap);
+		return;
+	}
+
+	va_start(ap, fmt);
+	added_length = vsnprintf(ctrl->msg_line->str + ctrl->msg_line->length,
+		sizeof(ctrl->msg_line->str) - ctrl->msg_line->length, fmt, ap);
+	va_end(ap);
+	if (added_length < 0
+		|| sizeof(ctrl->msg_line->str) <= ctrl->msg_line->length + added_length) {
+		static char truncated_output[] =
+			"v-- Error building output or output was truncated. (Next line) --v\n";
+
+		/*
+		 * This clause should never need to run because the
+		 * output line accumulation buffer is quite large.
+		 */
+
+		/* vsnprintf() error or output string was truncated. */
+		if (__pri_message) {
+			__pri_message(ctrl, truncated_output);
+		} else {
+			fputs(truncated_output, stdout);
+		}
+
+		/* Add a terminating '\n' to force a flush of the line. */
+		ctrl->msg_line->length = strlen(ctrl->msg_line->str);
+		if (ctrl->msg_line->length) {
+			ctrl->msg_line->str[ctrl->msg_line->length - 1] = '\n';
+		} else {
+			ctrl->msg_line->str[0] = '\n';
+			ctrl->msg_line->str[1] = '\0';
+		}
+	} else {
+		ctrl->msg_line->length += added_length;
+	}
+
+	if (ctrl->msg_line->length
+		&& ctrl->msg_line->str[ctrl->msg_line->length - 1] == '\n') {
+		/* The accumulated output line was terminated so send it out. */
+		ctrl->msg_line->length = 0;
+		if (__pri_message) {
+			__pri_message(ctrl, ctrl->msg_line->str);
+		} else {
+			fputs(ctrl->msg_line->str, stdout);
+		}
+	}
+}
+
+void pri_error(struct pri *pri, const char *fmt, ...)
 {
 	char tmp[1024];
 	va_list ap;

Modified: team/mattf/libpri-1.4-q921-rewrite/pri_facility.c
URL: http://svnview.digium.com/svn/libpri/team/mattf/libpri-1.4-q921-rewrite/pri_facility.c?view=diff&rev=1362&r1=1361&r2=1362
==============================================================================
--- team/mattf/libpri-1.4-q921-rewrite/pri_facility.c (original)
+++ team/mattf/libpri-1.4-q921-rewrite/pri_facility.c Wed Dec  2 15:34:28 2009
@@ -42,6 +42,7 @@
 
 static short get_invokeid(struct pri *ctrl)
 {
+	ctrl = PRI_MASTER(ctrl);
 	return ++ctrl->last_invoke;
 }
 
@@ -1022,7 +1023,7 @@
 		return -1;
 	}
 
-	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer);
+	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
 }
 
 /*!
@@ -1191,7 +1192,7 @@
 		return -1;
 	}
 
-	return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer);
+	return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL);
 }
 
 /*!
@@ -1313,7 +1314,7 @@
 		return -1;
 	}
 
-	return pri_call_apdu_queue(call, messagetype, buffer, end - buffer);
+	return pri_call_apdu_queue(call, messagetype, buffer, end - buffer, NULL);
 }
 
 /*!
@@ -1384,7 +1385,7 @@
 		return -1;
 	}
 
-	if (pri_call_apdu_queue(apdubearer, Q931_FACILITY, buffer, end - buffer)) {
+	if (pri_call_apdu_queue(apdubearer, Q931_FACILITY, buffer, end - buffer, NULL)) {
 		return -1;
 	}
 
@@ -1447,7 +1448,7 @@
 		return -1;
 	}
 
-	return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer);
+	return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL);
 }
 
 /*!
@@ -1556,7 +1557,7 @@
 			return -1;
 		}
 
-		if (pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer)) {
+		if (pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL)) {
 			return -1;
 		}
 
@@ -1579,7 +1580,7 @@
 		mymessage = Q931_FACILITY;
 	}
 
-	return pri_call_apdu_queue(call, mymessage, buffer, end - buffer);
+	return pri_call_apdu_queue(call, mymessage, buffer, end - buffer, NULL);
 }
 /* End Callername */
 
@@ -1713,7 +1714,7 @@
 		return -1;
 	}
 
-	return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer);
+	return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL);
 }
 /* End MWI */
 
@@ -1772,7 +1773,7 @@
 		return -1;
 	}
 
-	if (pri_call_apdu_queue(c1, Q931_FACILITY, buffer, end - buffer)) {
+	if (pri_call_apdu_queue(c1, Q931_FACILITY, buffer, end - buffer, NULL)) {
 		pri_message(ctrl, "Could not queue APDU in facility message\n");
 		return -1;
 	}
@@ -2093,7 +2094,7 @@
 		return -1;
 	}
 
-	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer);
+	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
 }
 
 /*!
@@ -2220,14 +2221,10 @@
 {
 	int res;
 
-	res = pri_call_apdu_queue_cleanup(call->bridged_call);
-	if (res) {
-		pri_message(ctrl, "Could not Clear queue ADPU\n");
-		return -1;
-	}
+	pri_call_apdu_queue_cleanup(call->bridged_call);
 
 	/* Send message */
-	res = pri_call_apdu_queue(call->bridged_call, Q931_FACILITY, ie->data, ie->len);
+	res = pri_call_apdu_queue(call->bridged_call, Q931_FACILITY, ie->data, ie->len, NULL);
 	if (res) {
 		pri_message(ctrl, "Could not queue ADPU in facility message\n");
 		return -1;
@@ -2295,7 +2292,7 @@
 		return -1;
 	}
 
-	res = pri_call_apdu_queue(c1, Q931_FACILITY, buffer, pos - buffer);
+	res = pri_call_apdu_queue(c1, Q931_FACILITY, buffer, pos - buffer, NULL);
 	if (res) {
 		pri_message(ctrl, "Could not queue ADPU in facility message\n");
 		return -1;
@@ -2324,7 +2321,7 @@
 		return -1;
 	}
 
-	res = pri_call_apdu_queue(c2, Q931_FACILITY, buffer, pos - buffer);
+	res = pri_call_apdu_queue(c2, Q931_FACILITY, buffer, pos - buffer, NULL);
 	if (res) {
 		pri_message(ctrl, "Could not queue ADPU in facility message\n");
 		return -1;
@@ -2409,7 +2406,7 @@
 
 	/* Remember that if we queue a facility IE for a facility message we
 	 * have to explicitly send the facility message ourselves */
-	if (pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer)
+	if (pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL)
 		|| q931_facility(call->pri, call)) {
 		pri_message(ctrl, "Could not schedule facility message for call %d\n", call->cr);
 		return -1;
@@ -2555,7 +2552,7 @@
 		return -1;
 	}
 
-	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer);
+	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
 }
 
 /* ===== End Call Transfer Supplementary Service (ECMA-178) ===== */
@@ -2623,7 +2620,7 @@
 		return -1;
 	}
 
-	return pri_call_apdu_queue(call, messagetype, buffer, end - buffer);
+	return pri_call_apdu_queue(call, messagetype, buffer, end - buffer, NULL);
 }
 
 /*!
@@ -2689,7 +2686,7 @@
 		return -1;
 	}
 
-	return pri_call_apdu_queue(call, messagetype, buffer, end - buffer);
+	return pri_call_apdu_queue(call, messagetype, buffer, end - buffer, NULL);
 }
 
 /*!
@@ -2699,11 +2696,18 @@
  * \param messagetype Q.931 message type.
  * \param apdu Facility ie contents buffer.
  * \param apdu_len Length of the contents buffer.
+ * \param response Sender supplied information to handle APDU response messages.
+ *        NULL if don't care about responses.
+ *
+ * \note
+ * Only APDU messages with an invoke component can supply a response pointer.
+ * If any other APDU messages supply a response pointer then aliasing of the
+ * invoke_id can occur.
  *
  * \retval 0 on success.
  * \retval -1 on error.
  */
-int pri_call_apdu_queue(q931_call *call, int messagetype, const unsigned char *apdu, int apdu_len)
+int pri_call_apdu_queue(q931_call *call, int messagetype, const unsigned char *apdu, int apdu_len, struct apdu_callback_data *response)
 {
 	struct apdu_event *cur = NULL;
 	struct apdu_event *new_event = NULL;
@@ -2730,11 +2734,16 @@
 		return -1;
 	}
 
+	/* Fill in the APDU event */
 	new_event->message = messagetype;
+	if (response) {
+		new_event->response = *response;
+	}
+	new_event->call = call;
 	new_event->apdu_len = apdu_len;
 	memcpy(new_event->apdu, apdu, apdu_len);
 
-	/* Append APDU to the end of the list. */
+	/* Append APDU event to the end of the list. */
 	if (call->apdus) {
 		for (cur = call->apdus; cur->next; cur = cur->next) {
 		}
@@ -2746,22 +2755,85 @@
 	return 0;
 }
 
-int pri_call_apdu_queue_cleanup(q931_call *call)
-{
-	struct apdu_event *cur_event = NULL, *free_event = NULL;
-
-	if (call && call->apdus) {
+/* Used by q931.c to cleanup the apdu queue upon destruction of a call */
+void pri_call_apdu_queue_cleanup(q931_call *call)
+{
+	struct apdu_event *cur_event;
+	struct apdu_event *free_event;
+
+	if (call) {
 		cur_event = call->apdus;
 		call->apdus = NULL;
 		while (cur_event) {
-			/* TODO: callbacks, some way of giving return res on status of apdu */
+			if (cur_event->response.callback) {
+				/* Indicate to callback that the APDU is being cleaned up. */
+				cur_event->response.callback(APDU_CALLBACK_REASON_CLEANUP, call->pri,
+					call, cur_event, NULL);
+
+				/* Stop any response timeout. */
+				pri_schedule_del(call->pri, cur_event->timer);
+			}
 			free_event = cur_event;
 			cur_event = cur_event->next;
 			free(free_event);
 		}
 	}
-
-	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Find an outstanding APDU with the given invoke id.
+ *
+ * \param call Call to find APDU.
+ * \param invoke_id Invoke id to match outstanding APDUs in queue.
+ *
+ * \retval apdu_event if found.
+ * \retval NULL if not found.
+ */
+static struct apdu_event *pri_call_apdu_find(struct q931_call *call, int invoke_id)
+{
+	struct apdu_event *apdu;
+
+	for (apdu = call->apdus; apdu; apdu = apdu->next) {
+		/*
+		 * Note: The APDU cannot be sent and still in the queue without a
+		 * callback and timeout timer active.  Therefore, an invoke_id of
+		 * zero is valid and not just the result of a memset().
+		 */
+		if (apdu->response.invoke_id == invoke_id && apdu->sent) {
+			break;
+		}
+	}
+	return apdu;
+}
+
+/*!
+ * \brief Delete the given APDU event from the given call.
+ *
+ * \param call Call to remove the APDU.
+ * \param doomed APDU event to delete.
+ *
+ * \return Nothing
+ */
+void pri_call_apdu_delete(struct q931_call *call, struct apdu_event *doomed)
+{
+	struct apdu_event **prev;
+	struct apdu_event *cur;
+
+	/* Find APDU in list. */
+	for (prev = &call->apdus, cur = call->apdus;
+		cur;
+		prev = &cur->next, cur = cur->next) {
+		if (cur == doomed) {
+			/* Stop any response timeout. */
+			pri_schedule_del(call->pri, cur->timer);
+
+			/* Remove APDU from list. */
+			*prev = cur->next;
+			free(cur);
+			break;
+		}
+	}
 }
 
 /*! \note Only called when sending the SETUP message. */
@@ -2947,7 +3019,7 @@
 		return -1;
 	}
 
-	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer);
+	return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
 }
 
 /*!
@@ -3079,7 +3151,7 @@
 		return -1;
 	}
 
-	return pri_call_apdu_queue(call, msgtype, buffer, end - buffer);
+	return pri_call_apdu_queue(call, msgtype, buffer, end - buffer, NULL);
 }
 
 /*!
@@ -3162,11 +3234,39 @@
 void rose_handle_reject(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie,
 	const struct fac_extension_header *header, const struct rose_msg_reject *reject)
 {
+	struct apdu_event *apdu;
+	union apdu_msg_data msg;
+
+	/* Gripe to the user about getting rejected. */
 	pri_error(ctrl, "ROSE REJECT:\n");
 	if (reject->invoke_id_present) {
 		pri_error(ctrl, "\tINVOKE ID: %d\n", reject->invoke_id);
 	}
 	pri_error(ctrl, "\tPROBLEM: %s\n", rose_reject2str(reject->code));
+
+	switch (ctrl->switchtype) {
+	case PRI_SWITCH_DMS100:
+		/* The DMS-100 switch apparently handles invoke_id as an invoke operation. */
+		return;
+	default:
+		break;
+	}
+
+	if (!reject->invoke_id_present) {
+		/*
+		 * No invoke id to look up so we cannot match it to any outstanding APDUs.
+		 * This REJECT is apparently meant for someone monitoring the link.
+		 */
+		return;
+	}
+	apdu = pri_call_apdu_find(call, reject->invoke_id);
+	if (!apdu) {
+		return;
+	}
+	msg.reject = reject;
+	if (apdu->response.callback(APDU_CALLBACK_REASON_MSG_REJECT, ctrl, call, apdu, &msg)) {
+		pri_call_apdu_delete(call, apdu);
+	}
 }
 
 /*!
@@ -3185,7 +3285,10 @@
 	const struct fac_extension_header *header, const struct rose_msg_error *error)
 {
 	const char *dms100_operation;
-
+	struct apdu_event *apdu;
+	union apdu_msg_data msg;
+
+	/* Gripe to the user about getting an error. */
 	pri_error(ctrl, "ROSE RETURN ERROR:\n");
 	switch (ctrl->switchtype) {
 	case PRI_SWITCH_DMS100:
@@ -3210,6 +3313,23 @@
 		break;
 	}
 	pri_error(ctrl, "\tERROR: %s\n", rose_error2str(error->code));
+
+	switch (ctrl->switchtype) {
+	case PRI_SWITCH_DMS100:
+		/* The DMS-100 switch apparently handles invoke_id as an invoke operation. */
+		return;
+	default:
+		break;
+	}
+
+	apdu = pri_call_apdu_find(call, error->invoke_id);
+	if (!apdu) {
+		return;
+	}
+	msg.error = error;
+	if (apdu->response.callback(APDU_CALLBACK_REASON_MSG_ERROR, ctrl, call, apdu, &msg)) {
+		pri_call_apdu_delete(call, apdu);
+	}
 }
 
 /*!
@@ -3227,8 +3347,12 @@
 void rose_handle_result(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie,
 	const struct fac_extension_header *header, const struct rose_msg_result *result)
 {
+	struct apdu_event *apdu;
+	union apdu_msg_data msg;
+
 	switch (ctrl->switchtype) {
 	case PRI_SWITCH_DMS100:
+		/* The DMS-100 switch apparently handles invoke_id as an invoke operation. */
 		switch (result->invoke_id) {
 		case ROSE_DMS100_RLT_OPERATION_IND:
 			if (result->operation != ROSE_DMS100_RLT_OperationInd) {
@@ -3255,87 +3379,13 @@
 		break;
 	}
 
-	switch (result->operation) {
-	case ROSE_None:
-		/*
-		 * This is simply a positive ACK to the invoke request.
-		 * The invoke ID must be used to distinguish between outstanding
-		 * invoke requests.
-		 */
-		break;
-#if 0	/* Not handled yet */
-	case ROSE_ETSI_ActivationDiversion:
-		break;
-	case ROSE_ETSI_DeactivationDiversion:
-		break;
-	case ROSE_ETSI_InterrogationDiversion:
-		break;
-#endif	/* Not handled yet */
-	case ROSE_ETSI_CallDeflection:
-		/* Successfully completed call deflection.  Nothing to do. */
-		break;
-	case ROSE_ETSI_CallRerouting:
-		/* Successfully completed call rerouting.  Nothing to do. */
-		break;
-#if 0	/* Not handled yet */
-	case ROSE_ETSI_InterrogateServedUserNumbers:
-		break;
-#endif	/* Not handled yet */
-#if 0	/* Not handled yet */
-	case ROSE_ETSI_ChargingRequest:
-		break;
-#endif	/* Not handled yet */
-#if 0	/* Not handled yet */
-	case ROSE_ETSI_EctExecute:
-		break;
-	case ROSE_ETSI_ExplicitEctExecute:
-		break;
-	case ROSE_ETSI_EctLinkIdRequest:
-		break;
-	case ROSE_ETSI_EctLoopTest:
-		break;
-#endif	/* Not handled yet */
-#if 0	/* Not handled yet */
-	case ROSE_QSIG_ChargeRequest:
-		break;
-	case ROSE_QSIG_AocComplete:
-		break;
-#endif	/* Not handled yet */
-#if 0	/* Not handled yet */
-	case ROSE_QSIG_CallTransferIdentify:
-		break;
-	case ROSE_QSIG_CallTransferInitiate:
-		break;
-	case ROSE_QSIG_CallTransferSetup:
-		break;
-#endif	/* Not handled yet */
-#if 0	/* Not handled yet */
-	case ROSE_QSIG_ActivateDiversionQ:
-		break;
-	case ROSE_QSIG_DeactivateDiversionQ:
-		break;
-	case ROSE_QSIG_InterrogateDiversionQ:
-		break;
-	case ROSE_QSIG_CheckRestriction:
-		break;
-#endif	/* Not handled yet */
-	case ROSE_QSIG_CallRerouting:
-		/* Successfully completed call rerouting.  Nothing to do. */
-		break;
-#if 0	/* Not handled yet */
-	case ROSE_QSIG_MWIActivate:
-		break;
-	case ROSE_QSIG_MWIDeactivate:
-		break;
-	case ROSE_QSIG_MWIInterrogate:
-		break;
-#endif	/* Not handled yet */
-	default:
-		if (ctrl->debug & PRI_DEBUG_APDU) {
-			pri_message(ctrl, "!! ROSE result operation not handled! %s\n",
-				rose_operation2str(result->operation));
-		}
-		break;
+	apdu = pri_call_apdu_find(call, result->invoke_id);
+	if (!apdu) {
+		return;
+	}
+	msg.result = result;
+	if (apdu->response.callback(APDU_CALLBACK_REASON_MSG_RESULT, ctrl, call, apdu, &msg)) {
+		pri_call_apdu_delete(call, apdu);
 	}
 }
 
@@ -3505,27 +3555,31 @@
 		break;
 #endif	/* Not handled yet */
 	case ROSE_ETSI_DivertingLegInformation1:
-		/*
-		 * Unless otherwise indicated by CONNECT, the divertedToNumber will be
-		 * the remote_id.number.
-		 *
-		 * Fortunately, the connected number ie is supposed to come after the
-		 * facility ie in the same message so it will be processed later.
-		 */
 		if (invoke->args.etsi.DivertingLegInformation1.diverted_to_present) {
-			rose_copy_presented_number_unscreened_to_q931(ctrl, &call->remote_id.number,
+			rose_copy_presented_number_unscreened_to_q931(ctrl, &party_id.number,
 				&invoke->args.etsi.DivertingLegInformation1.diverted_to);
 			/*
 			 * We set the presentation value since the sender cannot know the
 			 * presentation value preference of the destination party.
 			 */
-			if (call->remote_id.number.str[0]) {
-				call->remote_id.number.presentation =
+			if (party_id.number.str[0]) {
+				party_id.number.presentation =
 					PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
+			} else {
+				party_id.number.presentation =
+					PRI_PRES_UNAVAILABLE | PRI_PRES_USER_NUMBER_UNSCREENED;
 			}
 		} else {
-			q931_party_number_init(&call->remote_id.number);
-			call->remote_id.number.valid = 1;
+			q931_party_number_init(&party_id.number);
+			party_id.number.valid = 1;
+		}
+
+		/*
+		 * Unless otherwise indicated by CONNECT, the divertedToNumber will be
+		 * the remote_id.number.
+		 */
+		if (!call->connected_number_in_message) {
+			call->remote_id.number = party_id.number;
 		}
 
 		/* divertedToNumber is put in redirecting.to.number */
@@ -3539,7 +3593,7 @@
 				PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
 			break;
 		case 2:	/* notificationWithDivertedToNr */
-			call->redirecting.to.number = call->remote_id.number;
+			call->redirecting.to.number = party_id.number;
 			break;
 		}
 
@@ -3566,7 +3620,7 @@
 			rose_copy_presented_number_unscreened_to_q931(ctrl,
 				&call->redirecting.from.number,
 				&invoke->args.etsi.DivertingLegInformation2.diverting);
-		} else {
+		} else if (!call->redirecting_number_in_message) {
 			q931_party_number_init(&call->redirecting.from.number);
 			call->redirecting.from.number.valid = 1;
 		}
@@ -3586,15 +3640,14 @@
 		/*
 		 * Unless otherwise indicated by CONNECT, this will be the
 		 * remote_id.number.presentation.
-		 *
-		 * Fortunately, the connected number ie is supposed to come after the
-		 * facility ie in the same message so it will be processed later.
 		 */
 		if (!invoke->args.etsi.DivertingLegInformation3.presentation_allowed_indicator) {
-			call->remote_id.number.presentation =
-				PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
 			call->redirecting.to.number.presentation =
 				PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
+			if (!call->connected_number_in_message) {
+				call->remote_id.number.presentation =
+					PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
+			}
 		}
 
 		switch (call->redirecting.state) {
@@ -3899,19 +3952,20 @@
 			&deflection);
 		break;
 	case ROSE_QSIG_DivertingLegInformation1:
+		q931_party_number_init(&party_id.number);
+		rose_copy_number_to_q931(ctrl, &party_id.number,
+			&invoke->args.qsig.DivertingLegInformation1.nominated_number);
+		if (party_id.number.str[0]) {
+			party_id.number.presentation =
+				PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
+		}
+
 		/*
 		 * Unless otherwise indicated by CONNECT, the nominatedNr will be
 		 * the remote_id.number.
-		 *
-		 * Fortunately, the connected number ie is supposed to come after the
-		 * facility ie in the same message so it will be processed later.
 		 */
-		q931_party_number_init(&call->remote_id.number);
-		rose_copy_number_to_q931(ctrl, &call->remote_id.number,
-			&invoke->args.qsig.DivertingLegInformation1.nominated_number);
-		if (call->remote_id.number.str[0]) {
-			call->remote_id.number.presentation =
-				PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
+		if (!call->connected_number_in_message) {
+			call->remote_id.number = party_id.number;
 		}
 
 		/* nominatedNr is put in redirecting.to.number */
@@ -3925,7 +3979,7 @@
 				PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
 			break;
 		case QSIG_NOTIFICATION_WITH_DIVERTED_TO_NR:
-			call->redirecting.to.number = call->remote_id.number;
+			call->redirecting.to.number = party_id.number;
 			break;
 		}
 
@@ -3952,7 +4006,7 @@
 			rose_copy_presented_number_unscreened_to_q931(ctrl,
 				&call->redirecting.from.number,
 				&invoke->args.qsig.DivertingLegInformation2.diverting);
-		} else {
+		} else if (!call->redirecting_number_in_message) {
 			q931_party_number_init(&call->redirecting.from.number);
 			call->redirecting.from.number.valid = 1;
 		}
@@ -3992,15 +4046,14 @@
 		/*
 		 * Unless otherwise indicated by CONNECT, this will be the
 		 * remote_id.number.presentation.
-		 *
-		 * Fortunately, the connected number ie is supposed to come after the
-		 * facility ie in the same message so it will be processed later.
 		 */
 		if (!invoke->args.qsig.DivertingLegInformation3.presentation_allowed_indicator) {
-			call->remote_id.number.presentation =
-				PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
 			call->redirecting.to.number.presentation =
 				PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
+			if (!call->connected_number_in_message) {
+				call->remote_id.number.presentation =
+					PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
+			}
 		}
 
 		/* redirectionName is put in redirecting.to.name */

Modified: team/mattf/libpri-1.4-q921-rewrite/pri_facility.h
URL: http://svnview.digium.com/svn/libpri/team/mattf/libpri-1.4-q921-rewrite/pri_facility.h?view=diff&rev=1362&r1=1361&r2=1362
==============================================================================
--- team/mattf/libpri-1.4-q921-rewrite/pri_facility.h (original)
+++ team/mattf/libpri-1.4-q921-rewrite/pri_facility.h Wed Dec  2 15:34:28 2009
@@ -31,6 +31,13 @@
 #define _PRI_FACILITY_H
 #include "pri_q931.h"
 
+/* Forward declare some structs */
+struct fac_extension_header;
+struct rose_msg_invoke;
+struct rose_msg_result;
+struct rose_msg_error;
+struct rose_msg_reject;
+
 /* Protocol Profile field */
 #define Q932_PROTOCOL_MASK			0x1F
 #define Q932_PROTOCOL_ROSE			0x11	/* X.219 & X.229 */
@@ -65,6 +72,107 @@
 #define QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR	0x01
 #define QSIG_NOTIFICATION_WITH_DIVERTED_TO_NR		0x02
 
+/*! Reasons an APDU callback is called. */
+enum APDU_CALLBACK_REASON {
+	/*!
+	 * \brief Send setup error.  Abort and cleanup.
+	 * \note The message may or may not actually get sent.
+	 * \note The callback cannot generate an event subcmd.
+	 * \note The callback should not send messages.  Out of order messages will result.
+	 */
+	APDU_CALLBACK_REASON_ERROR,
+	/*!
+	 * \brief Abort and cleanup.
+	 * \note The APDU queue is being destroyed.
+	 * \note The callback cannot generate an event subcmd.
+	 * \note The callback cannot send messages as the call is likely being destroyed.
+	 */
+	APDU_CALLBACK_REASON_CLEANUP,
+	/*!
+	 * \brief Timeout waiting for responses to the message.
+	 * \note The callback can generate an event subcmd.
+	 * \note The callback can send messages.
+	 */
+	APDU_CALLBACK_REASON_TIMEOUT,
+	/*!
+	 * \brief Received a facility response message.
+	 * \note The callback can generate an event subcmd.
+	 * \note The callback can send messages.
+	 */
+	APDU_CALLBACK_REASON_MSG_RESULT,
+	/*!
+	 * \brief Received a facility error message.
+	 * \note The callback can generate an event subcmd.
+	 * \note The callback can send messages.
+	 */
+	APDU_CALLBACK_REASON_MSG_ERROR,
+	/*!
+	 * \brief Received a facility reject message.
+	 * \note The callback can generate an event subcmd.
+	 * \note The callback can send messages.
+	 */
+	APDU_CALLBACK_REASON_MSG_REJECT,
+};
+
+union apdu_msg_data {
+	const struct rose_msg_result *result;
+	const struct rose_msg_error *error;
+	const struct rose_msg_reject *reject;
+};
+
+union apdu_callback_param {
+	void *ptr;
+	long value;
+	char pad[8];
+};
+
+struct apdu_callback_data {
+	/*! APDU invoke id to match with any response messages. (Result/Error/Reject) */
+	int invoke_id;
+	/*!
+	 * \brief Time to wait for responses to APDU in ms.
+	 * \note Set to 0 if send the message only.
+	 * \note Set to less than 0 for PRI_TIMER_T_RESPONSE time.
+	 */
+	int timeout_time;
+	/*!
+	 * \brief APDU callback function.
+	 *
+	 * \param reason Reason callback is called.
+	 * \param ctrl D channel controller.
+	 * \param call Q.931 call leg.
+	 * \param apdu APDU queued entry.  Do not change!
+	 * \param msg APDU response message data.  (NULL if was not the reason called.)
+	 *
+	 * \note
+	 * A callback must be supplied if the sender cares about any APDU_CALLBACK_REASON.
+	 *
+	 * \return TRUE if no more responses are expected.
+	 */
+	int (*callback)(enum APDU_CALLBACK_REASON reason, struct pri *ctrl, struct q931_call *call, struct apdu_event *apdu, const union apdu_msg_data *msg);
+	/*! \brief Sender data for the callback function to identify the particular APDU. */
+	union apdu_callback_param user;
+};
+
+struct apdu_event {
+	/*! Linked list pointer */
+	struct apdu_event *next;
+	/*! TRUE if this APDU has been sent. */
+	int sent;
+	/*! What message to send the ADPU in */
+	int message;
+	/*! Sender supplied information to handle APDU response messages. */
+	struct apdu_callback_data response;
+	/*! Q.931 call leg.  (Needed for the APDU timeout.) */
+	struct q931_call *call;
+	/*! Response timeout timer. */
+	int timer;
+	/*! Length of ADPU */
+	int apdu_len;
+	/*! ADPU to send */
+	unsigned char apdu[255];
+};
+
 /* Queues an MWI apdu on a the given call */
 int mwi_message_send(struct pri *pri, q931_call *call, struct pri_sr *req, int activate);
 
@@ -87,22 +195,14 @@
 int rose_connected_name_encode(struct pri *pri, q931_call *call, int messagetype);
 int rose_called_name_encode(struct pri *pri, q931_call *call, int messagetype);
 
-int pri_call_apdu_queue(q931_call *call, int messagetype, const unsigned char *apdu, int apdu_len);
-
-/* Used by q931.c to cleanup the apdu queue upon destruction of a call */
-int pri_call_apdu_queue_cleanup(q931_call *call);
+int pri_call_apdu_queue(q931_call *call, int messagetype, const unsigned char *apdu, int apdu_len, struct apdu_callback_data *response);
+void pri_call_apdu_queue_cleanup(q931_call *call);
+void pri_call_apdu_delete(struct q931_call *call, struct apdu_event *doomed);
 
 /* Adds the "standard" APDUs to a call */
 int pri_call_add_standard_apdus(struct pri *pri, q931_call *call);
 
 void asn1_dump(struct pri *ctrl, const unsigned char *start_asn1, const unsigned char *end);
-
-/* Forward declare some ROSE structures for the following prototypes */
-struct fac_extension_header;
-struct rose_msg_invoke;
-struct rose_msg_result;
-struct rose_msg_error;
-struct rose_msg_reject;
 
 void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_invoke *invoke);
 void rose_handle_result(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_result *result);

Modified: team/mattf/libpri-1.4-q921-rewrite/pri_internal.h
URL: http://svnview.digium.com/svn/libpri/team/mattf/libpri-1.4-q921-rewrite/pri_internal.h?view=diff&rev=1362&r1=1361&r2=1362
==============================================================================
--- team/mattf/libpri-1.4-q921-rewrite/pri_internal.h (original)
+++ team/mattf/libpri-1.4-q921-rewrite/pri_internal.h Wed Dec  2 15:34:28 2009
@@ -40,6 +40,9 @@
 #define DBGHEAD __FILE__ ":%d %s: "
 #define DBGINFO __LINE__,__PRETTY_FUNCTION__
 
+/* Forward declare some structs */
+struct apdu_event;
+
 struct pri_sched {
 	struct timeval when;
 	void (*callback)(void *data);
@@ -48,6 +51,17 @@
 
 /*! Maximum number of scheduled events active at the same time. */
 #define MAX_SCHED 128
+
+/*! Maximum number of facility ie's to handle per incoming message. */
+#define MAX_FACILITY_IES	8
+
+/*! Accumulated pri_message() line until a '\n' is seen on the end. */
+struct pri_msg_line {
+	/*! Accumulated buffer used. */
+	unsigned length;
+	/*! Accumulated pri_message() contents. */
+	char str[2048];
+};
 
 /*! \brief D channel controller structure */
 struct pri {
@@ -55,6 +69,8 @@
 	pri_io_cb read_func;		/* Read data callback */
 	pri_io_cb write_func;		/* Write data callback */
 	void *userdata;
+	/*! Accumulated pri_message() line. (Valid in master record only) */
+	struct pri_msg_line *msg_line;
 	struct pri *subchannel;	/* Sub-channel if appropriate */
 	struct pri *master;		/* Master channel if appropriate */
 	struct pri_sched pri_sched[MAX_SCHED];	/* Scheduled events */
@@ -143,8 +159,18 @@
 	unsigned int q931_rxcount;
 #endif
 
-	short last_invoke;	/* Last ROSE invoke ID */
+	short last_invoke;	/* Last ROSE invoke ID (Valid in master record only) */
 	unsigned char sendfacility;
+
+	/*! For delayed processing of facility ie's. */
+	struct {
+		/*! Array of facility ie locations in the current received message. */
+		q931_ie *ie[MAX_FACILITY_IES];
+		/*! Codeset facility ie found within. */
+		unsigned char codeset[MAX_FACILITY_IES];
+		/*! Number of facility ie's in the array from the current received message. */
+		unsigned char count;
+	} facility;
 };
 
 /*! \brief Maximum name length plus null terminator (From ECMA-164) */
@@ -312,13 +338,6 @@
 
 #define Q931_MAX_TEI	8
 
-struct apdu_event {
-	struct apdu_event *next;	/* Linked list pointer */
-	int message;			/* What message to send the ADPU in */
-	int apdu_len; 			/* Length of ADPU */
-	unsigned char apdu[255];			/* ADPU to send */
-};
-
 /*! \brief Incoming call transfer states. */
 enum INCOMING_CT_STATE {
 	/*!
@@ -478,6 +497,10 @@
 	int hold_timer;
 
 	int deflection_in_progress;	/*!< CallDeflection for NT PTMP in progress. */
+	/*! TRUE if the connected number ie was in the current received message. */
+	int connected_number_in_message;
+	/*! TRUE if the redirecting number ie was in the current received message. */
+	int redirecting_number_in_message;
 
 	int useruserprotocoldisc;
 	char useruserinfo[256];
@@ -519,7 +542,7 @@
 
 /*! D channel control structure with associated dummy call reference record. */
 struct d_ctrl_dummy {
-	/*! D channel control structure. */
+	/*! D channel control structure. Must be first in the structure. */
 	struct pri ctrl;
 	/*! Dummy call reference call record. */
 	struct q931_call dummy_call;
@@ -533,8 +556,8 @@
 
 extern pri_event *pri_mkerror(struct pri *pri, char *errstr);
 
-void pri_message(struct pri *ctrl, char *fmt, ...) __attribute__((format(printf, 2, 3)));
-void pri_error(struct pri *ctrl, char *fmt, ...) __attribute__((format(printf, 2, 3)));
+void pri_message(struct pri *ctrl, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
+void pri_error(struct pri *ctrl, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
 
 void libpri_copy_string(char *dst, const char *src, size_t size);
 

Modified: team/mattf/libpri-1.4-q921-rewrite/q931.c
URL: http://svnview.digium.com/svn/libpri/team/mattf/libpri-1.4-q921-rewrite/q931.c?view=diff&rev=1362&r1=1361&r2=1362
==============================================================================
--- team/mattf/libpri-1.4-q921-rewrite/q931.c (original)
+++ team/mattf/libpri-1.4-q921-rewrite/q931.c Wed Dec  2 15:34:28 2009
@@ -1740,6 +1740,7 @@
 {
 	int i = 0;
 
+	call->connected_number_in_message = 1;
 	call->remote_id.number.valid = 1;
 	call->remote_id.number.presentation =
 		PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
@@ -1824,6 +1825,7 @@
 {
 	int i = 0;
 
+	call->redirecting_number_in_message = 1;
 	call->redirecting.from.number.valid = 1;
 	call->redirecting.from.number.presentation =
 		PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
@@ -2266,6 +2268,8 @@
 	return 0;
 }
 
+static void q931_apdu_timeout(void *data);
+
 static int transmit_facility(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
 {
 	struct apdu_event **prev;
@@ -2275,9 +2279,7 @@
 	for (prev = &call->apdus, cur = call->apdus;
 		cur;
 		prev = &cur->next, cur = cur->next) {
-		if (cur->message == msgtype) {
-			/* Remove APDU from list. */
-			*prev = cur->next;
+		if (!cur->sent && cur->message == msgtype) {
 			break;
 		}
 	}
@@ -2292,20 +2294,76 @@
 		facility_decode_dump(ctrl, cur->apdu, cur->apdu_len);
 	}
 
-	if (cur->apdu_len > 235) { /* TODO: find out how much space we can use */
-		pri_message(ctrl, "Requested APDU (%d bytes) is too long\n", cur->apdu_len);
+	if (len < cur->apdu_len) { 
+		pri_error(ctrl,
+			"Could not fit facility ie in message.  Size needed:%d  Available space:%d\n",
+			cur->apdu_len + 2, len);
+
+		/* Remove APDU from list. */
+		*prev = cur->next;
+
+		if (cur->response.callback) {
+			/* Indicate to callback that the APDU had a problem getting sent. */
+			cur->response.callback(APDU_CALLBACK_REASON_ERROR, ctrl, call, cur, NULL);
+		}
+
 		free(cur);
 		return 0;
 	}
 
 	memcpy(ie->data, cur->apdu, cur->apdu_len);
 	apdu_len = cur->apdu_len;
-	free(cur);
+	cur->sent = 1;
+
+	if (cur->response.callback && cur->response.timeout_time) {
+		int duration;
+
+		if (0 < cur->response.timeout_time) {
+			/* Sender specified timeout duration. */
+			duration = cur->response.timeout_time;
+		} else {
+			/* Sender wants to use the typical timeout duration. */

[... 152 lines stripped ...]



More information about the svn-commits mailing list