[asterisk-commits] branch oej/test-this-branch r10714 - in /team/oej/test-this-branch: ./ doc/

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Wed Feb 22 09:56:25 MST 2006


Author: oej
Date: Wed Feb 22 10:56:14 2006
New Revision: 10714

URL: http://svn.digium.com/view/asterisk?rev=10714&view=rev
Log:
Adding carrier ENUM support (patch #5526)

Modified:
    team/oej/test-this-branch/README.test-this-branch
    team/oej/test-this-branch/doc/enum.txt
    team/oej/test-this-branch/enum.c

Modified: team/oej/test-this-branch/README.test-this-branch
URL: http://svn.digium.com/view/asterisk/team/oej/test-this-branch/README.test-this-branch?rev=10714&r1=10713&r2=10714&view=diff
==============================================================================
--- team/oej/test-this-branch/README.test-this-branch (original)
+++ team/oej/test-this-branch/README.test-this-branch Wed Feb 22 10:56:14 2006
@@ -19,14 +19,15 @@
 - peermatch: New peer matching algorithm (no bug report yet)
 - rtcp: Improved support for RTCP (#2863)
 - dialplan-ami-events: Report dialplan reload in manager (#5741)
-- sipregister: A new registration architecture (#5834)
-- subscribemwi: Support for SIP subscription of MWI notification (#6390)
+- sipregister: A new registration architecture (rizzo, oej #5834)
+- subscribemwi: Support for SIP subscription of MWI notification (oej #6390)
 - iptos: New IPtos support, separate audio and signalling (#6355)
 
 And the following stand-alone patches
-- New CLI commands for global variables (#6506)
-- Additional options for the CHANNEL dialplan function
+- New CLI commands for global variables (oej, #6506)
+- Additional options for the CHANNEL dialplan function (oej)
 - Manager sendtext event (ZX81, #6131)
+- Carrier ENUM support (otmar, #5526)
 
 Coming here soon:
 - metermaids: Subscription support for parking lots (#5779)

Modified: team/oej/test-this-branch/doc/enum.txt
URL: http://svn.digium.com/view/asterisk/team/oej/test-this-branch/doc/enum.txt?rev=10714&r1=10713&r2=10714&view=diff
==============================================================================
--- team/oej/test-this-branch/doc/enum.txt (original)
+++ team/oej/test-this-branch/doc/enum.txt Wed Feb 22 10:56:14 2006
@@ -25,6 +25,14 @@
 actually create channels ("dial") results given by the ENUMLOOKUP
 function is then up to the administrator to implement in a way that
 best suits their environment.
+
+This function uses the enum.conf configuration file. You can turn
+on verbose output by setting verbose to an integer > 0, e.g.
+
+; enum.conf
+[general]
+verbose => 10
+
 
 Function: ENUMLOOKUP(<number>[,pointer_type[,options[,zone_suffix]]])
 
@@ -125,7 +133,7 @@
 
 
 Example 8: Look up the ISN mapping in freenum.org alpha test zone
-exten => 100,1,Set(foo=${ENUMLOOKUP(1234*256,,,freenum.org)})
+exten => 100,1,Set(foo=${ENUMLOOKUP(1234*256,,i,freenum.org)})
   returns: ${foo}="1234 at 204.91.156.10"  [note: this result is subject
   to change as it is "live" DNS]
 
@@ -217,9 +225,45 @@
   the form ABC*DEF (where ABC and DEF are at least one numeric digit)
   then perform an ISN-style lookup where the lookup is manipulated to
   C.B.A.DEF.domain.tld (all other settings and options apply.)  See
-  http://www.freenum.org/ for more details on ISN lookups.  In the
-  unlikely event you wish to avoid ISN re-writes, put an "n" as the
-  first digit of the search string - the "n" will be ignored for the search.
+  http://www.freenum.org/ for more details on ISN lookups.  
+  In previous versions this feature was enable by default, now
+  you need to add an 'i' to the options to perform ISN-style lookups.
+
+
+  k) Carrier ENUM usage: If "r" is contained in the options field, then
+  the lookup will follow the Carrier ENUM rules as proposed in
+  ftp://ftp.rfc-editor.org/in-notes/internet-drafts/draft-haberler-carrier-enum-01.txt
+  Summary: an additional label will be inserted into the ENUM domain
+  name to branch off the carrier tree from the default user-ENUM tree.
+
+  The label to insert is configured in enum.conf as:
+
+  [carrier]
+  branchlabel     => carrier
+
+  Examples:
+  	4.9.7.1.carrier.e164.arpa
+  	4.9.7.carrier.1.e164.arpa
+  	carrier.4.9.7.1.e164.arpa
+ 
+  The position of this label within the DNS tree is controlled by the blr_alg
+  parameter (also in enum.conf). Currently, there are two algorithms to
+  choose from:
+
+  blr_alg         => cc
+  This algorithm always inserts the carrier label at the country-code level.
+  Examples: carrier.1.e164.arpa, carrier.3.4.e164.arpa, carrier.2.5.3.e164.arpa
+  This is the default.
+
+  blr_alg         => txt
+  With this setting, ENUMLOOKUP will look for a TXT record at 
+  <branchlabel>.<reverse-country-code>.<apex> to indicate after how many digits the
+  carrier label should in inserted. e.g. a
+
+  carrier.1.e164.arpa.	IN	TXT	"4"
+
+  record will tell the module to look for carrier ENUM for +1 234 5678 999 at
+  9.9.9.8.7.6.5.carrier.4.3.2.1.e164.arpa.
 
 
 ==EXAMPLES==

Modified: team/oej/test-this-branch/enum.c
URL: http://svn.digium.com/view/asterisk/team/oej/test-this-branch/enum.c?rev=10714&r1=10713&r2=10714&view=diff
==============================================================================
--- team/oej/test-this-branch/enum.c (original)
+++ team/oej/test-this-branch/enum.c Wed Feb 22 10:56:14 2006
@@ -27,6 +27,7 @@
  * \arg Funding provided by nic.at
  */
 
+#include <sys/times.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -74,6 +75,12 @@
 } *toplevs;
 
 static int enumver = 0;
+static int enum_verbose = 0;
+static char carrier_branchlabel[32] = "carrier";
+/* how to do carrier enum branch location resolution? */
+#define ENUMLOOKUP_BLR_CC     0
+#define ENUMLOOKUP_BLR_TXT      1
+static int blr_alg = ENUMLOOKUP_BLR_CC;
 
 AST_MUTEX_DEFINE_STATIC(enumlock);
 
@@ -81,6 +88,184 @@
 	unsigned short order;
 	unsigned short pref;
 } __attribute__ ((__packed__));
+
+
+/*--- find_cclen: Determine the length of a country code when give a E.164 string ---*/
+/*
+ * Input: E.164 number w/o leading +
+ *
+ * Output: number of digits in the country code
+ * 	   0 on invalid number
+ *
+ * convention:
+ *   3 digits is the default length of a country code.
+ *   country codes 1 and 7 are a single digit.
+ *   the following country codes are two digits: 20, 27, 30-34, 36, 39,
+ *     40, 41, 43-49, 51-58, 60-66, 81, 82, 84, 86, 90-95, 98.
+ */
+static int cclen(const char *number)
+{
+	char d1,d2;
+
+	if (!number || (strlen(number) < 3))
+		return(0);
+
+	d1 = number[0];
+	d2 = number[1];
+	
+	if (!isdigit(d2)) 
+		return(0);
+
+	switch(d1) {
+		case '1':
+		case '7':
+			return(1);
+		case '2':
+			if ((d2 == '0') || (d1 == '7'))
+				return(2);
+			break;
+		case '3':
+			if ((d2 >= '0') && (d1 <= '4'))
+				return(2);
+			if ((d2 == '6') || (d1 == '9'))
+				return(2);
+			break;
+		case '4':
+			if (d2 != '2')
+				return(2);
+			break;
+		case '5':
+			if ((d2 >= '1') && (d1 <= '8'))
+				return(2);
+			break;
+		case '6':
+			if (d1 <= '6')
+				return(2);
+			break;
+		case '8':
+			if ((d2 == '1') || (d1 == '2') || (d1 == '4') || (d1 == '6')) 
+				return(2);
+			break;
+		case '9':
+			if (d1 <= '5')
+				return(2);
+			if (d2 == '8')
+				return(2);
+			break;
+		default:
+			return(0);
+	}
+
+	return(3);
+}
+
+
+struct txt_context {
+	char txt[1024];		/* TXT record in TXT lookup */
+	int txtlen;		/* Length */
+};
+
+/*--- txt_callback2: Callback for TXT record lookup, /ol version */
+static int txt_callback2(void *context, char *answer, int len, char *fullanswer)
+{
+	struct txt_context *c = (struct txt_context *)context;
+	unsigned int i;
+
+	c->txt[0] = 0;	/* default to empty */
+	c->txtlen = 0;
+
+	if (answer == NULL) {
+		return 0;
+	}
+
+	/* RFC1035: 
+	 *
+	 * <character-string> is a single length octet followed by that number of characters.
+	 * TXT-DATA        One or more <character-string>s.
+	 *
+	 * We only take the first string here.
+	 */
+
+	i = *answer++;
+	len -= 1;
+
+	if (i > len) {	/* illegal packet */
+		ast_log(LOG_WARNING, "txt_callback2: malformed TXT record.\n");
+		return 0;
+	}
+
+	if (i >= sizeof(c->txt)) {	/* too long? */
+		ast_log(LOG_WARNING, "txt_callback2: TXT record too long.\n");
+		i = sizeof(c->txt) - 1;
+	}
+
+	ast_copy_string(c->txt, answer, i + 1);
+	c->txtlen = i;
+
+	return 1;
+}
+
+
+/*--- blr_txt: Determine the branch location record as stored in a TXT record ---*/
+/*
+ * Input: CC code
+ *
+ * Output: number of digits in the number before the carrier branch 
+ *
+ * Algorithm:  Build <carrier_branchlabel>.c.c.<suffix> and look for a TXT lookup.
+ * 		Return atoi(TXT-record).
+ * 		Return -1 on not found.
+ *
+ */
+static int blr_txt(const char *cc, const char *suffix)
+{
+	struct txt_context context;
+	char domain[128];
+	char *p1,*p2;
+	int ret;
+
+	ast_mutex_lock(&enumlock);
+	if (sizeof(domain) < (strlen(cc) * 2 + strlen(carrier_branchlabel) + strlen(suffix) + 2)) {
+		ast_mutex_unlock(&enumlock);
+		ast_log(LOG_WARNING, "ERROR: string sizing in blr_txt.\n");
+		return(-1);
+	}
+
+	strcpy(domain, carrier_branchlabel);
+	p1 = domain + strlen(domain);
+	ast_mutex_unlock(&enumlock);
+
+	*p1++ = '.';
+	*p1   = 0;
+		
+	p2 = (char *) cc + strlen(cc) - 1;
+	while(p2 >= cc) {
+		if (isdigit(*p2)) {
+			*p1++ = *p2;
+			*p1++ = '.';
+		}
+		p2--;
+	}
+	strcat(p1, suffix);
+
+	if (enum_verbose > 4)
+		ast_verbose(VERBOSE_PREFIX_4 "blr_txt() FQDN for TXT record: %s, cc was %s\n", domain, cc);
+
+	ret = ast_search_dns(&context, domain, C_IN, T_TXT, txt_callback2);
+	if (ret > 0) {
+		ret = atoi(context.txt);
+
+		if ((ret>=0) && (ret<20)) {
+			if (enum_verbose > 3)
+				ast_verbose(VERBOSE_PREFIX_3 "blr_txt() BLR TXT record for %s is %d (apex: %s)\n", cc, ret, suffix);
+			return(ret);
+		}
+	}
+	if (enum_verbose > 3)
+		ast_verbose(VERBOSE_PREFIX_3 "blr_txt() BLR TXT record for %s not found (apex: %s)\n", cc, suffix);
+	return(-1);
+}
+
 
 /*! \brief Parse NAPTR record information elements */
 static int parse_ie(char *data, int maxdatalen, char *src, int srclen)
@@ -161,6 +346,10 @@
 	if (option_debug > 2)	/* Advanced NAPTR debugging */
 		ast_log(LOG_DEBUG, "NAPTR input='%s', flags='%s', services='%s', regexp='%s', repl='%s'\n",
 			naptrinput, flags, services, regexp, repl);
+	if (enum_verbose > 1)
+		ast_verbose(VERBOSE_PREFIX_2 "NAPTR input='%s', flags='%s', services='%s', regexp='%s', repl='%s'\n",
+			naptrinput, flags, services, regexp, repl);
+			
 
 	if (tolower(flags[0]) != 'u') {
 		ast_log(LOG_WARNING, "NAPTR Flag must be 'U' or 'u'.\n");
@@ -287,6 +476,10 @@
 
 /* do not return requested value, just count RRs and return thei number in dst */
 #define ENUMLOOKUP_OPTIONS_COUNT       1
+/* do an ISN style lookup */
+#define ENUMLOOKUP_OPTIONS_ISN         2
+/* do a carrier ENUM lookup */
+#define ENUMLOOKUP_OPTIONS_CARRIER     4
 
 struct enum_naptr_rr {
 	struct naptr naptr; /* order and preference of RR */
@@ -386,10 +579,12 @@
 int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen, char* suffix, char* options)
 {
 	struct enum_context context;
-	char tmp[259 + 512];
-	char naptrinput[512];
-	int pos = strlen(number) - 1;
-	int newpos = 0;
+	char tmp[512];
+	char domain[256];
+	char left[128];
+	char middle[128];
+
+	char naptrinput[128];
 	int ret = -1;
 	struct enum_search *s = NULL;
 	int version = -1;
@@ -399,12 +594,25 @@
 	int k = 0;
 	int i = 0;
 	int z = 0;
-
+	int spaceleft = 0;
+	struct timeval time_start, time_end;
+
+#if 0
 	if (number[0] == 'n') {
 		strncpy(naptrinput, number+1, sizeof(naptrinput));
 	} else {
-		strncpy(naptrinput, number, sizeof(naptrinput));
-	}
+		strncpy(naptrinput, number, sizeof(naptrinput)); }
+#endif
+
+	/*
+	 * The "number" paramter includes a leading '+' if it's a full E.164 number (and not ISN)
+	 * We need to preserve that as the regex inside NAPTRs expect the +.
+	 *
+	 * But for the domain generation, the '+' is a nuissance, so we get rid of it.
+	 */
+	ast_copy_string(naptrinput, number, sizeof(naptrinput));
+	if (number[0] == '+')
+		number++;
 
 	context.naptrinput = naptrinput;	/* The number */
 	context.dst = dst;			/* Return string */
@@ -416,52 +624,128 @@
 	context.naptr_rrs = NULL;
 	context.naptr_rrs_count = 0;
 
+	/*
+	 * Process options:
+	 *
+	 * 	c	Return count, not URI
+	 * 	i	Do ISN transformation
+	 * 	r	Use carrier ENUM 
+	 * 	\d+	Return n-th URI
+	 *
+	 */
 	if (options != NULL){
-		if (*options == 'c'){
-			context.options = ENUMLOOKUP_OPTIONS_COUNT;
+		if (strchr(options,'i'))
+			context.options |= ENUMLOOKUP_OPTIONS_ISN;
+		else if (strchr(options,'r'))
+			context.options |= ENUMLOOKUP_OPTIONS_CARRIER;
+
+		if (strchr(options,'c')){
+			context.options |= ENUMLOOKUP_OPTIONS_COUNT;
 			context.position = 0;
 		} else {
-			context.position = atoi(options);
+			char *digits = options;
+			while (*digits && (!isdigit(*digits)))
+				digits++;
+			context.position = atoi(digits);
 			if (context.position < 1)
 				context.position = 1;
 		}
 	}
 
-	if (pos > 128)
-		pos = 128;
+	if (enum_verbose > 1)
+		ast_verbose(VERBOSE_PREFIX_2 "ENUM options(%s): pos=%d, options='%d'\n",
+			options, context.position, context.position);
+
+	/* default: the whole number will be flipped, no middle domain component */
+	ast_copy_string(left, number, sizeof(left));
+	middle[0] = '\0';
 
 	/* ISN rewrite */
-	p1 = strchr(number, '*');
-
-	if (number[0] == 'n') { /* do not perform ISN rewrite ('n' is testing flag) */
-		p1 = NULL;
-		k = 1; /* strip 'n' from number */
-	}
-
-	if (p1 != NULL) {
-		p2 = p1+1;
-		while (p1 > number){
-			p1--;
-			tmp[newpos++] = *p1;
-			tmp[newpos++] = '.';
-		}
-		if (*p2) {
-			while(*p2 && newpos < 128){
-				tmp[newpos++] = *p2;
-				p2++;
+	if ((context.options & ENUMLOOKUP_OPTIONS_ISN) && (p1 = strchr(number, '*'))) {
+		*p1++ = '\0';
+
+		ast_copy_string(left, number, sizeof(left));
+		ast_copy_string(middle, p1, sizeof(middle)-2);
+		strcat(middle, ".");
+		
+		if (enum_verbose > 1)
+			ast_verbose(VERBOSE_PREFIX_2 "ISM ENUM: left=%s, middle='%s'\n",
+				left, middle);
+
+
+	/* Carrier ENUM rewrite */
+	} else if (context.options & ENUMLOOKUP_OPTIONS_CARRIER) {
+		int sdl=0;
+		char cc[8];
+		int cc_len = cclen(number);
+
+
+		switch(blr_alg) {
+			case ENUMLOOKUP_BLR_TXT:
+				strncpy(cc, number, cc_len); /* cclen() never returns more than 3 */
+				cc[cc_len] = 0;
+
+				/* carrier ENUM is only called via ENUMLOOKUP, thus we have a suffix */
+				sdl = blr_txt(cc, suffix);
+
+				if (sdl < 0) {
+					sdl = cc_len;
+				}
+				break;
+
+			case ENUMLOOKUP_BLR_CC:	/* BLR is at the country-code level */
+			default:
+				sdl = cc_len;
+				break;
+		}
+
+		if (sdl > strlen(number)) {	/* Number too short for this sdl? */
+			ast_log(LOG_WARNING, "CARRIER ENUM: subdomain location %d behind number %s\n", sdl, number);
+			return(0);
+		}
+
+		ast_copy_string(left, number+sdl, sizeof(left));
+
+		ast_mutex_lock(&enumlock);
+		ast_copy_string(middle, carrier_branchlabel, sizeof(middle) - 2);
+		strcat(middle, ".");
+		ast_mutex_unlock(&enumlock);
+
+		p1 = middle + strlen(middle);
+		p2 = (char *) number + sdl - 1;
+		while(p2 >= number) {
+			if (isdigit(*p2)) {
+				*p1++ = *p2;
+				*p1++ = '.';
 			}
-			tmp[newpos++] = '.';
-		}
-
-	} else {
-		while (pos >= k) {
-			if (isdigit(number[pos])) {
-				tmp[newpos++] = number[pos];
-				tmp[newpos++] = '.';
-			}
-			pos--;
-		}
-	}
+			p2--;
+		}
+		*p1 = '\0';
+
+		if (enum_verbose > 1)
+			ast_verbose(VERBOSE_PREFIX_2 "CARRIER ENUM: cclen=%d, left=%s, middle='%s'\n",
+				cc_len, left, middle);
+
+	}
+
+
+	if (strlen(left)*2 + 2 > sizeof(domain)) {
+		ast_log(LOG_WARNING, "string to long in ast_get_enum\n");
+		return -1;
+	}
+
+	/* flip left into domain */
+	p1 = domain;
+	p2 = left + strlen(left);
+	while(p2 >= left) {
+		if (isdigit(*p2)) {
+			*p1++ = *p2;
+			*p1++ = '.';
+		}
+		p2--;
+	}
+	*p1 = '\0';
+
 
 	if (chan && ast_autoservice_start(chan) < 0)
 		return -1;
@@ -475,18 +759,37 @@
 		} else {
 			s = s->next;
 		}
+		spaceleft = sizeof(tmp) - 2;
+		ast_copy_string(tmp, domain, spaceleft);
+		spaceleft -= strlen(domain);
+		if (*middle) {
+			strncat(tmp, middle, spaceleft);
+			spaceleft -= strlen(middle);
+		}
+				 
+			
 		if (suffix != NULL) {
-			strncpy(tmp + newpos, suffix, sizeof(tmp) - newpos - 1);
+			strncat(tmp, suffix, spaceleft);
 		} else if (s) {
-			strncpy(tmp + newpos, s->toplev, sizeof(tmp) - newpos - 1);
+			strncat(tmp, s->toplev, spaceleft);
 		}
 		ast_mutex_unlock(&enumlock);
 		if (!s)
 			break;
+
+		(void) gettimeofday(&time_start, NULL);
 		ret = ast_search_dns(&context, tmp, C_IN, T_NAPTR, enum_callback);
+		(void) gettimeofday(&time_end, NULL);
+
+		if (enum_verbose > 1)
+			ast_verbose(VERBOSE_PREFIX_2 "ast_get_enum() profiling: %s, %s, %ld usec\n", 
+				(ret>0) ? "OK" : "FAIL", tmp, 
+				(time_end.tv_sec - time_start.tv_sec) * 1000000 + 
+				(time_end.tv_usec - time_start.tv_usec));
+
 		if (ret > 0)
 			break;
-		if (suffix != NULL)
+		if (suffix != NULL)	/* don't need to loop if apex was given */
                        break;
 	}
 	if (ret < 0) {
@@ -552,16 +855,13 @@
 {
 	struct enum_context context;
 	char tmp[259 + 512];
-	char naptrinput[512] = "+";
 	int pos = strlen(number) - 1;
 	int newpos = 0;
 	int ret = -1;
 	struct enum_search *s = NULL;
 	int version = -1;
 
-	strncat(naptrinput, number, sizeof(naptrinput) - 2);
-
-	context.naptrinput = naptrinput;
+	context.naptrinput = NULL;
 	context.dst = dst;
 	context.dstlen = dstlen;
 	context.tech = tech;
@@ -589,7 +889,7 @@
 			s = s->next;
 		}
 		if (s) {
-			strncpy(tmp + newpos, s->toplev, sizeof(tmp) - newpos - 1);
+			ast_copy_string(tmp + newpos, s->toplev, sizeof(tmp) - newpos);
 		}
 		ast_mutex_unlock(&enumlock);
 		if (!s)
@@ -625,6 +925,7 @@
 	struct ast_config *cfg;
 	struct enum_search *s, *sl;
 	struct ast_variable *v;
+	char *string;
 
 	/* Destroy existing list */
 	ast_mutex_lock(&enumlock);
@@ -637,10 +938,18 @@
 	toplevs = NULL;
 	cfg = ast_config_load("enum.conf");
 	if (cfg) {
+		if ((string=ast_variable_retrieve(cfg, "general", "verbose"))) {
+			enum_verbose = atoi(string);
+		} else {
+			enum_verbose = 0;
+		}
+
 		sl = NULL;
 		v = ast_variable_browse(cfg, "general");
 		while(v) {
 			if (!strcasecmp(v->name, "search")) {
+				if (enum_verbose > 1)
+					ast_verbose(VERBOSE_PREFIX_2 "ast_enum_init() adding apex: %s\n", v->value);
 				s = enum_newtoplev(v->value);
 				if (s) {
 					if (sl)
@@ -652,6 +961,18 @@
 			}
 			v = v->next;
 		}
+		if (!sl)	/* no search param in config file */
+			toplevs = enum_newtoplev(TOPLEV);
+
+		if ((string=ast_variable_retrieve(cfg, "carrier", "branchlabel"))) {
+			ast_copy_string(carrier_branchlabel, string, sizeof(carrier_branchlabel));
+		}
+
+		if ((string=ast_variable_retrieve(cfg, "carrier", "blr_alg"))) {
+			blr_alg = ENUMLOOKUP_BLR_CC; /* default */
+			if (!strcasecmp(string, "txt"))
+				blr_alg = ENUMLOOKUP_BLR_TXT; 
+		}
 		ast_config_destroy(cfg);
 	} else {
 		toplevs = enum_newtoplev(TOPLEV);



More information about the asterisk-commits mailing list