[svn-commits] trunk - r286 /trunk/

svn-commits at lists.digium.com svn-commits at lists.digium.com
Thu Jan 5 14:50:52 CST 2006


Author: mattf
Date: Thu Jan  5 14:50:51 2006
New Revision: 286

URL: http://svn.digium.com/view/libpri?rev=286&view=rev
Log:
Lots of changes for APDU handling and debugging.  Thanks PCadach (bug #5265)!

Modified:
    trunk/pri_facility.c
    trunk/pri_facility.h
    trunk/pri_q931.h
    trunk/q931.c
    trunk/testprilib.c

Modified: trunk/pri_facility.c
URL: http://svn.digium.com/view/libpri/trunk/pri_facility.c?rev=286&r1=285&r2=286&view=diff
==============================================================================
--- trunk/pri_facility.c (original)
+++ trunk/pri_facility.c Thu Jan  5 14:50:51 2006
@@ -32,6 +32,132 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <limits.h>
+
+static char *asn1id2text(int id)
+{
+	static char data[32];
+	static char *strings[] = {
+		"none",
+		"Boolean",
+		"Integer",
+		"Bit String",
+		"Octet String",
+		"NULL",
+		"Object Identifier",
+		"Object Descriptor",
+		"External Reference",
+		"Real Number",
+		"Enumerated",
+		"Embedded PDV",
+		"UTF-8 String",
+		"Relative Object ID",
+		"Reserved (0e)",
+		"Reserved (0f)",
+		"Sequence",
+		"Set",
+		"Numeric String",
+		"Printable String",
+		"Tele-Text String",
+		"IA-5 String",
+		"UTC Time",
+		"Generalized Time",
+	};
+	if (id > 0 && id <= 0x18) {
+		return strings[id];
+	} else {
+		sprintf(data, "Unknown (%02x)", id);
+		return data;
+	}
+}
+
+static int asn1_dumprecursive(struct pri *pri, void *comp_ptr, int len, int level)
+{
+	unsigned char *vdata = (unsigned char *)comp_ptr;
+	struct rose_component *comp;
+	int i = 0;
+	int j, k, l;
+	int clen = 0;
+
+	while (len > 0) {
+		GET_COMPONENT(comp, i, vdata, len);
+		pri_message(pri, "%*s%02X %04X", 2 * level, "", comp->type, comp->len);
+		if ((comp->type == 0) && (comp->len == 0))
+			return clen + 2;
+		if ((comp->type & ASN1_PC_MASK) == ASN1_PRIMITIVE) {
+			for (j = 0; j < comp->len; ++j)
+				pri_message(pri, " %02X", comp->data[j]);
+		}
+		if ((comp->type & ASN1_CLAN_MASK) == ASN1_UNIVERSAL) {
+			switch (comp->type & ASN1_TYPE_MASK) {
+			case 0:
+				pri_message(pri, " (none)");
+				break;
+			case ASN1_BOOLEAN:
+				pri_message(pri, " (BOOLEAN: %d)", comp->data[0]);
+				break;
+			case ASN1_INTEGER:
+				for (k = l = 0; k < comp->len; ++k)
+					l = (l << 8) | comp->data[k];
+				pri_message(pri, " (INTEGER: %d)", l);
+				break;
+			case ASN1_BITSTRING:
+				pri_message(pri, " (BITSTRING:");
+				for (k = 0; k < comp->len; ++k)
+				pri_message(pri, " %02x", comp->data[k]);
+				pri_message(pri, ")");
+				break;
+			case ASN1_OCTETSTRING:
+				pri_message(pri, " (OCTETSTRING:");
+				for (k = 0; k < comp->len; ++k)
+					pri_message(pri, " %02x", comp->data[k]);
+				pri_message(pri, ")");
+				break;
+			case ASN1_NULL:
+				pri_message(pri, " (NULL)");
+				break;
+			case ASN1_OBJECTIDENTIFIER:
+				pri_message(pri, " (OBJECTIDENTIFIER:");
+				for (k = 0; k < comp->len; ++k)
+					pri_message(pri, " %02x", comp->data[k]);
+				pri_message(pri, ")");
+				break;
+			case ASN1_ENUMERATED:
+				for (k = l = 0; k < comp->len; ++k)
+					l = (l << 8) | comp->data[k];
+				pri_message(pri, " (ENUMERATED: %d)", l);
+				break;
+			case ASN1_SEQUENCE:
+				pri_message(pri, " (SEQUENCE)");
+				break;
+			default:
+				pri_message(pri, " (component %02x - %s)", comp->type, asn1id2text(comp->type & ASN1_TYPE_MASK));
+				break;
+			}
+		}
+		else if ((comp->type & ASN1_CLAN_MASK) == ASN1_CONTEXT_SPECIFIC) {
+			pri_message(pri, " (CONTEXT SPECIFIC [%d])", comp->type & ASN1_TYPE_MASK);
+		}
+		else {
+			pri_message(pri, " (component %02x)", comp->type);
+		}
+		pri_message(pri, "\n");
+		if ((comp->type & ASN1_PC_MASK) == ASN1_CONSTRUCTOR)
+			j = asn1_dumprecursive(pri, comp->data, (comp->len ? comp->len : INT_MAX), level+1);
+		else
+			j = comp->len;
+		j += 2;
+		len -= j;
+		vdata += j;
+		clen += j;
+	}
+	return clen;
+}
+
+int asn1_dump(struct pri *pri, void *comp, int len)
+{
+	return asn1_dumprecursive(pri, comp, len, 0);
+}
 
 static unsigned char get_invokeid(struct pri *pri)
 {
@@ -46,28 +172,44 @@
 	int  pres;
 };
 
+#define PRI_CHECKOVERFLOW(size) \
+		if (msgptr - message + (size) >= sizeof(message)) { \
+			*msgptr = '\0'; \
+			pri_message(pri, "%s", message); \
+			msgptr = message; \
+		}
+
 static void dump_apdu(struct pri *pri, unsigned char *c, int len) 
 {
 	#define MAX_APDU_LENGTH	255
+	static char hexs[16] = "0123456789ABCDEF";
 	int i;
 	char message[(2 + MAX_APDU_LENGTH * 3 + 6 + MAX_APDU_LENGTH + 3)] = "";	/* please adjust here, if you make changes below! */
-	
-	if (len > MAX_APDU_LENGTH)
-		return;
-	
-	snprintf(message, sizeof(message)-1, " [");	
-	for (i=0; i<len; i++)
-		snprintf((char *)(message+strlen(message)), sizeof(message)-strlen(message)-1, " %02x", c[i]);
-	snprintf((char *)(message+strlen(message)), sizeof(message)-strlen(message)-1, " ] - [");
+	char *msgptr;
+	
+	msgptr = message;
+	*msgptr++ = ' ';
+	*msgptr++ = '[';
 	for (i=0; i<len; i++) {
-		if (c[i] < 20 || c[i] >= 128)
-			snprintf((char *)(message+strlen(message)), sizeof(message)-strlen(message)-1, "°");
-		else
-			snprintf((char *)(message+strlen(message)), sizeof(message)-strlen(message)-1, "%c", c[i]);
-	}
-	snprintf((char *)(message+strlen(message)), sizeof(message)-strlen(message)-1, "]\n");
-	pri_message(pri, message);
-}
+		PRI_CHECKOVERFLOW(3);
+		*msgptr++ = ' ';
+		*msgptr++ = hexs[(c[i] >> 4) & 0x0f];
+		*msgptr++ = hexs[(c[i]) & 0x0f];
+	}
+	PRI_CHECKOVERFLOW(6);
+	strcpy(msgptr, " ] - [");
+	msgptr += strlen(msgptr);
+	for (i=0; i<len; i++) {
+		PRI_CHECKOVERFLOW(1);
+		*msgptr++ = ((c[i] < ' ') || (c[i] > '~')) ? '.' : c[i];
+	}
+	PRI_CHECKOVERFLOW(2);
+	*msgptr++ = ']';
+	*msgptr++ = '\n';
+	*msgptr = '\0';
+	pri_message(pri, "%s", message);
+}
+#undef PRI_CHECKOVERFLOW
 
 int redirectingreason_from_q931(struct pri *pri, int redirectingreason)
 {
@@ -564,9 +706,11 @@
 	unsigned char buffer[256];
 	int len = 253;
 	
+#if 0	/* This is not required by specifications */
 	if (!strlen(call->callername)) {
 		return -1;
 	}
+#endif
 
 	buffer[i] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
 	i++;
@@ -749,7 +893,7 @@
 	}
 
 
-	/* Now the ADPu that contains the information that needs sent.
+	/* Now the APDU that contains the information that needs sent.
 	 * We can reuse the buffer since the queue function doesn't
 	 * need it. */
 
@@ -903,7 +1047,7 @@
 
 	res = pri_call_apdu_queue(c1, Q931_FACILITY, buffer, i, NULL, NULL);
 	if (res) {
-		pri_message(pri, "Could not queue ADPU in facility message\n");
+		pri_message(pri, "Could not queue APDU in facility message\n");
 		return -1;
 	}
 
@@ -1110,7 +1254,7 @@
 	/* code below is untested */
 	res = pri_call_apdu_queue(c, Q931_FACILITY, buffer, i, NULL, NULL);
 	if (res) {
-		pri_message(pri, "Could not queue ADPU in facility message\n");
+		pri_message(pri, "Could not queue APDU in facility message\n");
 		return -1;
 	}
 
@@ -1305,6 +1449,7 @@
 		return 0;
 	}
 
+#if 0
 	if (pri->localtype == PRI_NETWORK) {
 		switch (pri->switchtype) {
 			case PRI_SWITCH_NI2:
@@ -1324,6 +1469,10 @@
 		}
 		return 0;
 	}
+#else
+	if (pri->switchtype == PRI_SWITCH_NI2)
+		add_callername_facility_ies(pri, call, (pri->localtype == PRI_CPE));
+#endif
 
 	return 0;
 }

Modified: trunk/pri_facility.h
URL: http://svn.digium.com/view/libpri/trunk/pri_facility.h?rev=286&r1=285&r2=286&view=diff
==============================================================================
--- trunk/pri_facility.h (original)
+++ trunk/pri_facility.h Thu Jan  5 14:50:51 2006
@@ -146,7 +146,7 @@
 		break; \
 	(component) = (struct rose_component*)&((ptr)[idx]); \
 	if ((idx)+(component)->len+2 > (length)) { \
-		if ((component)->len != 128) \
+		if ((component)->len != ASN1_LEN_INDEF) \
 			pri_message(pri, "Length (%d) of 0x%X component is too long\n", (component)->len, (component)->type); \
 	}
 /*
@@ -169,6 +169,7 @@
 #define CHECK_COMPONENT(component, comptype, message) \
 	if ((component)->type && ((component)->type & ASN1_TYPE_MASK) != (comptype)) { \
 		pri_message(pri, (message), (component)->type); \
+		asn1_dump(pri, (component), (component)->len+2); \
 		break; \
 	}
 	
@@ -249,7 +250,7 @@
 /* starts a 2BCT */
 extern int eect_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
 
-/* Use this function to queue a facility-IE born ADPU onto a call
+/* Use this function to queue a facility-IE born APDU onto a call
  * call is the call to use, messagetype is any one of the Q931 messages,
  * apdu is the apdu data, apdu_len is the length of the apdu data  */
 extern int pri_call_apdu_queue(q931_call *call, int messagetype, void *apdu, int apdu_len, void (*function)(void *data), void *data);
@@ -257,7 +258,9 @@
 /* Used by q931.c to cleanup the apdu queue upon destruction of a call */
 extern int pri_call_apdu_queue_cleanup(q931_call *call);
 
-/* Adds the "standard" ADPUs to a call */
+/* Adds the "standard" APDUs to a call */
 extern int pri_call_add_standard_apdus(struct pri *pri, q931_call *call);
 
+int asn1_dump(struct pri *pri, void *comp, int len);
+
 #endif /* _PRI_FACILITY_H */

Modified: trunk/pri_q931.h
URL: http://svn.digium.com/view/libpri/trunk/pri_q931.h?rev=286&r1=285&r2=286&view=diff
==============================================================================
--- trunk/pri_q931.h (original)
+++ trunk/pri_q931.h Thu Jan  5 14:50:51 2006
@@ -243,6 +243,10 @@
 /* EuroISDN  */
 #define Q931_SENDING_COMPLETE		0xa1
 
+
+/* Q.SIG specific */
+#define QSIG_IE_TRANSIT_COUNT		0x31
+
 extern int q931_receive(struct pri *pri, q931_h *h, int len);
 
 extern int q931_alerting(struct pri *pri, q931_call *call, int channel, int info);

Modified: trunk/q931.c
URL: http://svn.digium.com/view/libpri/trunk/q931.c?rev=286&r1=285&r2=286&view=diff
==============================================================================
--- trunk/q931.c (original)
+++ trunk/q931.c Thu Jan  5 14:50:51 2006
@@ -1119,22 +1119,21 @@
 	int i = 0;
 
 	for (tmp = call->apdus; tmp; tmp = tmp->next) {
-		if (tmp->message == msgtype)
-			break;
-	}
-
+		if ((tmp->message == msgtype) && !tmp->sent)
+			break;
+	}
+	
 	if (!tmp)	/* No APDU found */
 		return 0;
 
-	if (tmp->apdu_len > 235) { /* TODO: find out how much sapce we can use */
-		pri_message(pri, "Requested ADPU (%d bytes) is too long\n", tmp->apdu_len);
-
-
+	if (tmp->apdu_len > 235) { /* TODO: find out how much space we can use */
+		pri_message(pri, "Requested APDU (%d bytes) is too long\n", tmp->apdu_len);
 		return 0;
 	}
 	
-	memcpy(ie->data, tmp->apdu, tmp->apdu_len);
+	memcpy(&ie->data[i], tmp->apdu, tmp->apdu_len);
 	i += tmp->apdu_len;
+	tmp->sent = 1;
 
 	return i + 2;
 }
@@ -1434,57 +1433,71 @@
 	}
 }
 
-static void dump_ie_data(unsigned char *c, int len)
-{
-	char tmp[1024] = "";
-	int x=0;
+#define CHECK_OVERFLOW(limit) \
+	if (tmpptr - tmp + limit >= sizeof(tmp)) { \
+		*tmpptr = '\0'; \
+		pri_message(pri, "%s", tmpptr = tmp); \
+	}
+
+static void dump_ie_data(struct pri *pri, unsigned char *c, int len)
+{
+	static char hexs[16] = "0123456789ABCDEF";
+	char tmp[1024], *tmpptr;
 	int lastascii = 0;
-	while(len) {
+	tmpptr = tmp;
+	for (; len; --len, ++c) {
+		CHECK_OVERFLOW(7);
 		if (isprint(*c)) {
 			if (!lastascii) {
-				if (*tmp) { 
-					tmp[x++] = ',';
-					tmp[x++] = ' ';
+				if (tmpptr != tmp) { 
+					*tmpptr++ = ',';
+					*tmpptr++ = ' ';
 				}
-				tmp[x++] = '\'';
+				*tmpptr++ = '\'';
+				lastascii = 1;
 			}
-			tmp[x++] = *c;
-			lastascii = 1;
+			*tmpptr++ = *c;
 		} else {
 			if (lastascii) {
-				tmp[x++] = '\'';
+				*tmpptr++ = '\'';
+				lastascii = 0;
 			}
-			if (*tmp) { 
-				tmp[x++] = ',';
-				tmp[x++] = ' ';
+			if (tmpptr != tmp) { 
+				*tmpptr++ = ',';
+				*tmpptr++ = ' ';
 			}
-			sprintf (tmp + x, "0x%02x", *c);
-			x += 4;
-			lastascii = 0;
-		}
-		c++;
-		len--;
+			*tmpptr++ = '0';
+			*tmpptr++ = 'x';
+			*tmpptr++ = hexs[(*c >> 4) & 0x0f];
+			*tmpptr++ = hexs[(*c) & 0x0f];
+		}
 	}
 	if (lastascii)
-		tmp[x++] = '\'';
-	pri_message(NULL, tmp);
+		*tmpptr++ = '\'';
+	*tmpptr = '\0';
+	pri_message(pri, "%s", tmp);
 }
 
 static FUNC_DUMP(dump_facility)
 {
 	pri_message(pri, "%c Facility (len=%2d, codeset=%d) [ ", prefix, len, Q931_IE_CODESET(full_ie));
-	dump_ie_data(ie->data, ie->len);
+	dump_ie_data(pri, ie->data, ie->len);
 	pri_message(NULL, " ]\n");
+	if (ie->len > 1) {
+		pri_message(pri, "PROTOCOL %02X\n", ie->data[0] & ASN1_TYPE_MASK);
+		asn1_dump(pri, &ie->data[1], ie->len - 1);
+	}
+
 }
 
 static FUNC_DUMP(dump_network_spec_fac)
 {
 	pri_message(pri, "%c Network-Specific Facilities (len=%2d) [ ", prefix, ie->len);
 	if (ie->data[0] == 0x00) {
-		pri_message(pri, code2str(ie->data[1], facilities, sizeof(facilities) / sizeof(facilities[0])));
+ 		pri_message(pri, "%s", code2str(ie->data[1], facilities, sizeof(facilities) / sizeof(facilities[0])));
 	}
 	else
-		dump_ie_data(ie->data, ie->len);
+ 		dump_ie_data(pri, ie->data, ie->len);
 	pri_message(pri, " ]\n");
 }
 
@@ -1925,6 +1938,17 @@
 	pri_message(pri, "Signal %s (%d)\n", signal2str(ie->data[0]), ie->data[0]);
 }
 
+static FUNC_DUMP(dump_transit_count)
+{
+	/* Defined in ECMA-225 */
+	pri_message(pri, "%c Transit Count (len=%02d): ", prefix, len);
+	if (len < 3) {
+		pri_message(pri, "Invalid length\n");
+		return;
+	}
+	pri_message(pri, "Count=%d (0x%02x)\n", ie->data[0] & 0x1f, ie->data[0] & 0x1f);
+}
+
 
 struct ie ies[] = {
 	/* Codeset 0 - Common */
@@ -1954,7 +1978,7 @@
 	{ 0, Q931_LOW_LAYER_COMPAT, "Low-layer Compatibility" },
 	{ 0, Q931_HIGH_LAYER_COMPAT, "High-layer Compatibility" },
 	{ 1, Q931_PACKET_SIZE, "Packet Size" },
-	{ 1, Q931_IE_FACILITY, "Facility" , dump_facility, receive_facility, transmit_facility },
+	{ 0, Q931_IE_FACILITY, "Facility" , dump_facility, receive_facility, transmit_facility },
 	{ 1, Q931_IE_REDIRECTION_NUMBER, "Redirection Number" },
 	{ 1, Q931_IE_REDIRECTION_SUBADDR, "Redirection Subaddress" },
 	{ 1, Q931_IE_FEATURE_ACTIVATE, "Feature Activation" },
@@ -1979,6 +2003,8 @@
 	{ 1, Q931_IE_USER_USER_FACILITY, "User-User Facility" },
 	{ 1, Q931_IE_UPDATE, "Update" },
 	{ 1, Q931_SENDING_COMPLETE, "Sending Complete", dump_sending_complete, receive_sending_complete, transmit_sending_complete },
+	/* Codeset 4 - Q.SIG specific */
+	{ 1, QSIG_IE_TRANSIT_COUNT | Q931_CODESET(4), "Transit Count", dump_transit_count },
 	/* Codeset 6 - Network specific */
 	{ 1, Q931_IE_ORIGINATING_LINE_INFO, "Originating Line Information", dump_line_information, receive_line_information, transmit_line_information },
 	{ 1, Q931_IE_FACILITY | Q931_CODESET(6), "Facility", dump_facility, receive_facility, transmit_facility },
@@ -2090,14 +2116,14 @@
 	int full_ie = Q931_FULL_IE(codeset, ie->ie);
 	int base_ie;
 
-	pri_message(NULL, "%c [", prefix);
-	pri_message(NULL, "%02x", ie->ie);
+	pri_message(pri, "%c [", prefix);
+	pri_message(pri, "%02x", ie->ie);
 	if (!(ie->ie & 0x80)) {
-		pri_message(NULL, " %02x", ielen(ie)-2);
+		pri_message(pri, " %02x", ielen(ie)-2);
 		for (x = 0; x + 2 < ielen(ie); ++x)
-			pri_message(NULL, " %02x", ie->data[x]);
-	}
-	pri_message(NULL, "]\n");
+			pri_message(pri, " %02x", ie->data[x]);
+	}
+	pri_message(pri, "]\n");
 
 	/* Special treatment for shifts */
 	if((full_ie & 0xf0) == Q931_LOCKING_SHIFT)
@@ -2114,7 +2140,7 @@
 			return;
 		}
 	
-	pri_error(pri, "!! %c Unknown IE %d (len = %d)\n", prefix, base_ie, ielen(ie));
+	pri_error(pri, "!! %c Unknown IE %d (cs%d, len = %d)\n", prefix, Q931_IE_IE(base_ie), Q931_IE_CODESET(base_ie), ielen(ie));
 }
 
 static q931_call *q931_getcall(struct pri *pri, int cr)
@@ -2377,7 +2403,6 @@
 	int offset=0;
 	int x;
 	int codeset;
-	struct apdu_event *facevent = c->apdus;
 	
 	memset(buf, 0, sizeof(buf));
 	len = sizeof(buf);
@@ -2386,24 +2411,7 @@
 	x=0;
 	codeset = 0;
 	while(ies[x] > -1) {
-		if (ies[x] == Q931_IE_FACILITY) {
-			res = 0;
-			while (facevent) {
-				if (!facevent->sent && (facevent->message == msgtype)) { 
-					int tmpres;
-					tmpres = add_ie(pri, c, mh->msg, ies[x], (q931_ie *)(mh->data + offset), len, &codeset);
-					if (tmpres < 0) {
-						pri_error(pri, "!! Unable to add IE '%s'\n", ie2str(ies[x]));
-						return -1;
-					}
-					res += tmpres;
-					facevent->sent = 1;
-				}
-				facevent = facevent->next;
-			}
-		} else {
-			res = add_ie(pri, c, mh->msg, ies[x], (q931_ie *)(mh->data + offset), len, &codeset);
-		}
+		res = add_ie(pri, c, mh->msg, ies[x], (q931_ie *)(mh->data + offset), len, &codeset);
 
 		if (res < 0) {
 			pri_error(pri, "!! Unable to add IE '%s'\n", ie2str(ies[x]));

Modified: trunk/testprilib.c
URL: http://svn.digium.com/view/libpri/trunk/testprilib.c?rev=286&r1=285&r2=286&view=diff
==============================================================================
--- trunk/testprilib.c (original)
+++ trunk/testprilib.c Thu Jan  5 14:50:51 2006
@@ -147,7 +147,7 @@
 	}
 }
 
-static void testmsg(char *s)
+static void testmsg(struct pri *pri, char *s)
 {
 	char *c;
 	static int keeplast = 0;
@@ -173,7 +173,7 @@
 		keeplast = 0;
 }
 
-static void testerr(char *s)
+static void testerr(struct pri *pri, char *s)
 {
 	char *c;
 	static int keeplast = 0;
@@ -264,6 +264,7 @@
 	}
 	first = pri;
 	pri_set_debug(pri, DEBUG_LEVEL);
+	pri_facility_enable(pri);
 	if (pthread_create(&tmp, NULL, dchan, pri)) {
 		perror("thread(0)");
 		exit(1);
@@ -273,6 +274,7 @@
 		exit(1);
 	}
 	pri_set_debug(pri, DEBUG_LEVEL);
+	pri_facility_enable(pri);
 	if (pthread_create(&tmp, NULL, dchan, pri)) {
 		perror("thread(1)");
 		exit(1);



More information about the svn-commits mailing list