[asterisk-commits] mjordan: trunk r382440 - in /trunk: ./ channels/ channels/sip/include/ config...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Mar 5 07:14:51 CST 2013


Author: mjordan
Date: Tue Mar  5 07:14:43 2013
New Revision: 382440

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=382440
Log:
Add RFC 3327 Path header support to chan_sip

This patch adds support for RFC 3327 "Path" headers. This can be enabled in
sip.conf using the 'supportpath' setting, either on a global basis or on a
peer basis. This setting enables Asterisk to route outgoing out-of-dialog
requests via a set of proxies by using a pre-loaded route-set defined by the
Path headers in the REGISTER request. This patch also adds Realtime support
for dynamically updating the Path information for a peer.

A huge thank-you to Klaus Darillion and Olle E Johansson for their efforts
in writing this patch.

Review: https://reviewboard.asterisk.org/r/2235/
Review: https://reviewboard.asterisk.org/r/991/

(closes issue ASTERISK-16884)
Reported by: klaus3000
Tested by: klaus3000, oej, mjordan
patches:
  path-1.8.0-patch.txt uploaded by klaus3000 (License 5054)
  oolong-path-support-trunk in team branch by oej (License 5267)


Modified:
    trunk/CHANGES
    trunk/CREDITS
    trunk/channels/chan_sip.c
    trunk/channels/sip/include/sip.h
    trunk/configs/res_ldap.conf.sample
    trunk/configs/sip.conf.sample
    trunk/contrib/realtime/mysql/sippeers.sql
    trunk/contrib/realtime/postgresql/realtime.sql
    trunk/contrib/scripts/asterisk.ldap-schema
    trunk/contrib/scripts/asterisk.ldif

Modified: trunk/CHANGES
URL: http://svnview.digium.com/svn/asterisk/trunk/CHANGES?view=diff&rev=382440&r1=382439&r2=382440
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Tue Mar  5 07:14:43 2013
@@ -50,6 +50,13 @@
 
  * Added ECAM command support for Sony Ericsson phones.
 
+chan_sip
+------------------
+ * Added support for RFC 3327 "Path" headers. This can be enabled in sip.conf
+   using the 'supportpath' setting, either on a global basis or on a peer basis.
+   This setting enables Asterisk to route outgoing out-of-dialog requests via a
+   set of proxies by using a pre-loaded route-set defined by the Path headers in
+   the REGISTER request. See Realtime updates for more configuration information.
 
 Features
 -------------------
@@ -94,6 +101,15 @@
    that the REDIRECTING dialplan function can be used to set the redirecting
    reason to any string. It also allows for custom strings to be read as the
    redirecting reason from SIP Diversion headers.
+
+Realtime
+------------------
+ * Dynamic realtime tables for SIP Users can now include a 'path' field. This
+   will store the path information for that peer when it registers. Realtime
+   tables can also use the 'supportpath' field to enable Path header support.
+
+ * LDAP realtime configurations for SIP Users now have the AstAccountPathSupport
+   objectIdentifier. This maps to the supportpath option in sip.conf. 
 
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 10 to Asterisk 11 --------------------

Modified: trunk/CREDITS
URL: http://svnview.digium.com/svn/asterisk/trunk/CREDITS?view=diff&rev=382440&r1=382439&r2=382440
==============================================================================
--- trunk/CREDITS (original)
+++ trunk/CREDITS Tue Mar  5 07:14:43 2013
@@ -22,7 +22,7 @@
 	* John Todd, TalkPlus, Inc.  and JR Richardson, Ntegrated Solutions. 
 		for funding the development of SIP Session Timers support.
 
-	* Omnitor AB, Gunnar Hellström, for funding work with videocaps, 
+	* Omnitor AB, Gunnar Hellstr�m, for funding work with videocaps, 
 		T.140 RED, originate with video/text and many more 
 		contributions.
 
@@ -54,7 +54,7 @@
 
 === HARDWARE DONORS === 
 
- We'd like to thank the followwing for granting access to hardware for testing.
+ We'd like to thank the following for granting access to hardware for testing.
 
 	* Thanks to QuickNet Technologies for their donation of an Internet
 		PhoneJack and Linejack card to the project.  
@@ -63,13 +63,12 @@
 	* Thanks to VoipSupply for their donation of Sipura ATAs to the project
 		for T.38 testing. (http://www.voipsupply.com)
 
-
 	* Thanks to Grandstream for their donation of ATAs to the project for
 		T.38 testing. (http://www.grandstream.com)
 
 === MISCELLANEOUS PATCHES ===
 
- We'd like to thank the flollowing for their patches
+ We'd like to thank the following for their patches
 
 	* Jim Dixon - Zapata Telephony and app_rpt
 		http://www.zapatatelephony.org/app_rpt.html
@@ -240,7 +239,8 @@
 		ControlPlayback, and multiple bug fixes See 
 		http://voip-info.org/users/view/sergee serg(AT)voipsolutions.ru
 
-	* Klaus Darillon - the SIPremoveHeader function in chan_sip
+	* Klaus Darillon - the SIPremoveHeader function in chan_sip and SIP Path
+		Support.
 
 	* Moises Silva (moy) - for writing LibOpenR2, and providing support for
 		it in chan_dahdi moises.silva(AT)gmail.com
@@ -252,7 +252,7 @@
 		cdr_tds rewrite, countless other improvements, fixes, and good
 		ideas. sean(AT)malleable.com
 
-	* Jan Kaláb - Calendaring support for Exchange Server 2007+ via 
+	* Jan Kal�b - Calendaring support for Exchange Server 2007+ via 
 		Exchange Web Services.
 
 	* University of Oslo (uio.no), Norway - SIP Max-Forwards setting 

Modified: trunk/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_sip.c?view=diff&rev=382440&r1=382439&r2=382440
==============================================================================
--- trunk/channels/chan_sip.c (original)
+++ trunk/channels/chan_sip.c Tue Mar  5 07:14:43 2013
@@ -1187,6 +1187,8 @@
 static void free_old_route(struct sip_route *route);
 static void list_route(struct sip_route *route);
 static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards, int resp);
+static int build_path(struct sip_pvt *p, struct sip_peer *peer, struct sip_request *req, char *pathbuf);
+static int copy_route(struct sip_route **dst, const struct sip_route *src);
 static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sockaddr *addr,
 					      struct sip_request *req, const char *uri);
 static struct sip_pvt *get_sip_pvt_byid_locked(const char *callid, const char *totag, const char *fromtag);
@@ -1360,7 +1362,7 @@
 static int peer_ipcmp_cb_full(void *obj, void *arg, void *data, int flags);
 
 /* Realtime device support */
-static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *username, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms);
+static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *username, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms, const char *path);
 static void update_peer(struct sip_peer *p, int expire);
 static struct ast_variable *get_insecure_variable_from_config(struct ast_config *config);
 static const char *get_name_from_variable(const struct ast_variable *var);
@@ -1442,6 +1444,7 @@
 static int add_rpid(struct sip_request *req, struct sip_pvt *p);
 static int add_vidupdate(struct sip_request *req);
 static void add_route(struct sip_request *req, struct sip_route *route);
+static void make_route_list(struct sip_route *route, char *r, int rem);
 static int copy_header(struct sip_request *req, const struct sip_request *orig, const char *field);
 static int copy_all_header(struct sip_request *req, const struct sip_request *orig, const char *field);
 static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const struct sip_request *orig, const char *field);
@@ -5112,7 +5115,7 @@
 	that name and store that in the "regserver" field in the sippeers
 	table to facilitate multi-server setups.
 */
-static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *defaultuser, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms)
+static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *defaultuser, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms, const char *path)
 {
 	char port[10];
 	char ipaddr[INET6_ADDRSTRLEN];
@@ -5135,10 +5138,11 @@
 	ast_copy_string(ipaddr, ast_sockaddr_isnull(addr) ? "" : ast_sockaddr_stringify_addr(addr), sizeof(ipaddr));
 	ast_copy_string(port, ast_sockaddr_port(addr) ? ast_sockaddr_stringify_port(addr) : "", sizeof(port));
 
-	if (ast_strlen_zero(sysname))	/* No system name, disable this */
+	if (ast_strlen_zero(sysname)) {	/* No system name, disable this */
 		sysname = NULL;
-	else if (sip_cfg.rtsave_sysname)
+	} else if (sip_cfg.rtsave_sysname) {
 		syslabel = "regserver";
+	}
 
 	/* XXX IMPORTANT: Anytime you add a new parameter to be updated, you
          *  must also add it to contrib/scripts/asterisk.ldap-schema,
@@ -5146,18 +5150,38 @@
          *  and to configs/res_ldap.conf.sample as described in
          *  bugs 15156 and 15895
          */
-	if (fc) {
-		ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr,
-			"port", port, "regseconds", regseconds,
-			deprecated_username ? "username" : "defaultuser", defaultuser,
-			"useragent", useragent, "lastms", str_lastms,
-			fc, fullcontact, syslabel, sysname, SENTINEL); /* note fc and syslabel _can_ be NULL */
+
+	/* This is ugly, we need something better ;-) */
+	if (sip_cfg.rtsave_path) {
+		if (fc) {
+			ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr,
+				"port", port, "regseconds", regseconds,
+				deprecated_username ? "username" : "defaultuser", defaultuser,
+				"useragent", useragent, "lastms", str_lastms,
+				"path", path,			/* Path data can be NULL */
+				fc, fullcontact, syslabel, sysname, SENTINEL); /* note fc and syslabel _can_ be NULL */
+		} else {
+			ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr,
+				"port", port, "regseconds", regseconds,
+				"useragent", useragent, "lastms", str_lastms,
+				deprecated_username ? "username" : "defaultuser", defaultuser,
+				"path", path,			/* Path data can be NULL */
+				syslabel, sysname, SENTINEL); /* note syslabel _can_ be NULL */
+		}
 	} else {
-		ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr,
-			"port", port, "regseconds", regseconds,
-			"useragent", useragent, "lastms", str_lastms,
-			deprecated_username ? "username" : "defaultuser", defaultuser,
-			syslabel, sysname, SENTINEL); /* note syslabel _can_ be NULL */
+		if (fc) {
+			ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr,
+				"port", port, "regseconds", regseconds,
+				deprecated_username ? "username" : "defaultuser", defaultuser,
+				"useragent", useragent, "lastms", str_lastms,
+				fc, fullcontact, syslabel, sysname, SENTINEL); /* note fc and syslabel _can_ be NULL */
+		} else {
+			ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr,
+				"port", port, "regseconds", regseconds,
+				"useragent", useragent, "lastms", str_lastms,
+				deprecated_username ? "username" : "defaultuser", defaultuser,
+				syslabel, sysname, SENTINEL); /* note syslabel _can_ be NULL */
+		}
 	}
 }
 
@@ -5251,6 +5275,10 @@
 	if (peer->chanvars) {
 		ast_variables_destroy(peer->chanvars);
 		peer->chanvars = NULL;
+	}
+	if (peer->path) {
+		free_old_route(peer->path);
+		peer->path = NULL;
 	}
 
 	register_peer_exten(peer, FALSE);
@@ -5294,7 +5322,9 @@
 	int rtcachefriends = ast_test_flag(&p->flags[1], SIP_PAGE2_RTCACHEFRIENDS);
 	if (sip_cfg.peer_rtupdate &&
 	    (p->is_realtime || rtcachefriends)) {
-		realtime_update_peer(p->name, &p->addr, p->username, p->fullcontact, p->useragent, expire, p->deprecated_username, p->lastms);
+		char path[SIPBUFSIZE * 2];
+		make_route_list(p->path, path, sizeof(path));
+		realtime_update_peer(p->name, &p->addr, p->username, p->fullcontact, p->useragent, expire, p->deprecated_username, p->lastms, path);
 	}
 }
 
@@ -5989,6 +6019,8 @@
 	return 0;
 }
 
+static int __set_address_from_contact(const char *fullcontact, struct ast_sockaddr *addr, int tcp);
+
 /*! \brief Create address structure from peer reference.
  *	This function copies data from peer to the dialog, so we don't have to look up the peer
  *	again from memory or database during the life time of the dialog.
@@ -6029,6 +6061,12 @@
 	dialog->rtptimeout = peer->rtptimeout;
 	dialog->rtpholdtimeout = peer->rtpholdtimeout;
 	dialog->rtpkeepalive = peer->rtpkeepalive;
+	copy_route(&dialog->route, peer->path);
+	if (dialog->route) {
+		/* Parse SIP URI of first route-set hop and use it as target address */
+		__set_address_from_contact(dialog->route->hop, &dialog->sa, dialog->socket.type == SIP_TRANSPORT_TLS ? 1 : 0);
+	}
+
 	if (dialog_initialize_rtp(dialog)) {
 		return -1;
 	}
@@ -6391,7 +6429,7 @@
 	ast_clear_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT_T38);
 
 	if (p->options->transfer) {
-		char buf[SIPBUFSIZE/2];
+		char buf[SIPBUFSIZE / 2];
 
 		if (referer) {
 			if (sipdebug)
@@ -11342,12 +11380,14 @@
  *  is supported for this dialog. */
 static int add_supported(struct sip_pvt *pvt, struct sip_request *req)
 {
+	char supported_value[SIPBUFSIZE];
 	int res;
-	if (st_get_mode(pvt, 0) != SESSION_TIMER_MODE_REFUSE) {
-		res = add_header(req, "Supported", "replaces, timer");
-	} else {
-		res = add_header(req, "Supported", "replaces");
-	}
+
+	sprintf(supported_value, "replaces%s%s",
+		(st_get_mode(pvt, 0) != SESSION_TIMER_MODE_REFUSE) ? ", timer" : "",
+		ast_test_flag(&pvt->flags[0], SIP_USEPATH) ? ", path" : "");
+	res = add_header(req, "Supported", supported_value);
+
 	return res;
 }
 
@@ -11523,11 +11563,20 @@
 /*! \brief Add route header into request per learned route */
 static void add_route(struct sip_request *req, struct sip_route *route)
 {
-	char r[SIPBUFSIZE*2], *p;
-	int n, rem = sizeof(r);
+	char r[SIPBUFSIZE * 2];
 
 	if (!route)
 		return;
+
+	make_route_list(route, r, sizeof(r));
+	add_header(req, "Route", r);
+}
+
+/*! \brief Make the comma separated list of route headers from the route list */
+static void make_route_list(struct sip_route *route, char *r, int rem)
+{
+	char *p;
+	int n;
 
 	p = r;
 	for (;route ; route = route->next) {
@@ -11545,7 +11594,6 @@
 		rem -= (n+2);
 	}
 	*p = '\0';
-	add_header(req, "Route", r);
 }
 
 /*! \brief Set destination from SIP URI
@@ -11821,6 +11869,9 @@
 			char *brackets = strchr(contact_uri, '<');
 			snprintf(contact, sizeof(contact), "%s%s%s;expires=%d", brackets ? "" : "<", contact_uri, brackets ? "" : ">", p->expiry);
 			add_header(resp, "Contact", contact);	/* Not when we unregister */
+		}
+		if (p->method == SIP_REGISTER && ast_test_flag(&p->flags[0], SIP_USEPATH)) {
+			copy_header(resp, req, "Path");
 		}
 	} else if (!ast_strlen_zero(p->our_contact) && resp_needs_contact(msg, p->method)) {
 		add_header(resp, "Contact", p->our_contact);
@@ -15337,6 +15388,7 @@
 	add_header(&req, "To", to);
 	add_header(&req, "Call-ID", p->callid);
 	add_header(&req, "CSeq", tmp);
+	add_supported(p, &req);
 	if (!ast_strlen_zero(global_useragent))
 		add_header(&req, "User-Agent", global_useragent);
 
@@ -15648,6 +15700,7 @@
 			ast_update_realtime(tablename, "name", peer->name, "fullcontact", "", "ipaddr", "", "port", "", "regseconds", "0", "regserver", "", "useragent", "", "lastms", "0", SENTINEL);
 		} else {
 			ast_db_del("SIP/Registry", peer->name);
+			ast_db_del("SIP/RegistryPath", peer->name);
 			ast_db_del("SIP/PeerMethods", peer->name);
 		}
 	}
@@ -15751,6 +15804,7 @@
 static void reg_source_db(struct sip_peer *peer)
 {
 	char data[256];
+	char path[SIPBUFSIZE * 2];
 	struct ast_sockaddr sa;
 	int expire;
 	char full_addr[128];
@@ -15809,6 +15863,9 @@
 			sip_unref_peer(peer, "remove registration ref"),
 			sip_ref_peer(peer, "add registration ref"));
 	register_peer_exten(peer, TRUE);
+	if (!ast_db_get("SIP/RegistryPath", peer->name, path, sizeof(path))) {
+		build_path(NULL, peer, NULL, path);
+	}
 }
 
 /*! \brief Save contact header for 200 OK on INVITE */
@@ -16104,11 +16161,21 @@
 		}
 	}
 	pvt->expiry = expire;
+	if (!build_path(pvt, peer, req, NULL)) {
+		/* Tell the dialog to use the Path header in the response */
+		ast_set2_flag(&pvt->flags[0], 1, SIP_USEPATH);
+	}
 	snprintf(data, sizeof(data), "%s:%d:%s:%s", ast_sockaddr_stringify(&peer->addr),
 		 expire, peer->username, peer->fullcontact);
 	/* We might not immediately be able to reconnect via TCP, but try caching it anyhow */
-	if (!peer->rt_fromcontact || !sip_cfg.peer_rtupdate)
+	if (!peer->rt_fromcontact || !sip_cfg.peer_rtupdate) {
+		char path[SIPBUFSIZE * 2];
+		if (peer->path) {
+			make_route_list(peer->path, path, sizeof(path));
+			ast_db_put("SIP/RegistryPath", peer->name, path);
+		}
 		ast_db_put("SIP/Registry", peer->name, data);
+	}
 	manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Registered\r\nAddress: %s\r\n", peer->name,  ast_sockaddr_stringify(&peer->addr));
 
 	/* Is this a new IP address for us? */
@@ -16144,10 +16211,10 @@
 static void list_route(struct sip_route *route)
 {
 	if (!route) {
-		ast_verbose("list_route: no route\n");
+		ast_verbose("list_route: no route/path\n");
 	} else {
 		for (;route; route = route->next)
-			ast_verbose("list_route: hop: <%s>\n", route->hop);
+			ast_verbose("list_route: route/path hop: <%s>\n", route->hop);
 	}
 }
 
@@ -16275,6 +16342,134 @@
 	if (sip_debug_test_pvt(p)) {
 		list_route(p->route);
 	}
+}
+
+/*! \internal \brief Create a new route
+ * \retval NULL on error
+ * \retval sip_route on success
+ */
+static struct sip_route *create_route(const char *hop, struct sip_route *prev)
+{
+	struct sip_route *route;
+	int len;
+
+	if (ast_strlen_zero(hop)) {
+		return NULL;
+	}
+	len = strlen(hop) + 1;
+
+	/* ast_calloc is not needed because all fields are initialized in
+	 * this block */
+	route = ast_malloc(sizeof(*route) + len);
+	if (!route) {
+		return NULL;
+	}
+	ast_copy_string(route->hop, hop, len);
+
+	route->next = NULL;
+	if (prev) {
+		prev->next = route;
+	}
+	return route;
+}
+
+/*! \internal \brief copy route-set
+ * \retval non-zero on failure
+ * \retval 0 on success
+ */
+static int copy_route(struct sip_route **dst, const struct sip_route *src)
+{
+	struct sip_route *thishop, *head, *tail;
+
+	/* Build a tailq, then assign it to **d when done. */
+	head = NULL;
+	tail = head;
+	for (; src; src = src->next) {
+		thishop = create_route(src->hop, tail);
+		if (!thishop) {
+			return -1;
+		}
+		if (!head) {
+			head = thishop;
+		}
+		tail = thishop;
+
+		ast_debug(2, "copy_route: copied hop: <%s>\n", thishop->hop);
+	}
+	*dst = head;
+
+	return 0;
+}
+
+/*! \brief Build route list from Path header
+ *  RFC 3327 requires that the Path header contains SIP URIs with lr paramter.
+ *  Thus, we do not care about strict routing SIP routers
+ */
+static int build_path(struct sip_pvt *p, struct sip_peer *peer, struct sip_request *req, char *pathbuf)
+{
+	struct sip_route *thishop, *head, *tail;
+	int start = 0;
+	int len;
+	char *pr;
+
+	if (peer->path) {
+		free_old_route(peer->path);
+		peer->path = NULL;
+	}
+
+	if (!ast_test_flag(&peer->flags[0], SIP_USEPATH)) {
+		ast_debug(2, "build_path: do not use Path headers\n");
+		return -1;
+	}
+	ast_debug(2, "build_path: try to build pre-loaded route-set by parsing Path headers\n");
+
+	/* Build a tailq, then assign it to peer->path when done. */
+	head = NULL;
+	tail = head;
+	/* 1st we pass through all the hops in any Path headers */
+	for (;;) {
+		/* Either loop over the request's Path headers or parse the buffer */
+		if (req) {
+			pr = ast_strdupa(__get_header(req, "Path", &start));
+			if (*pr == '\0') {
+				break;
+			}
+		} else if (pathbuf) {
+			if (start == 0) {
+				pr = ast_strdupa(pathbuf);
+				start++;
+			} else {
+				break;
+			}
+		} else {
+			break;
+		}
+		for (; (pr = strchr(pr, '<')) ; pr += (len + 1)) {
+			/* Parse out each route entry */
+			++pr;
+			len = strcspn(pr, ">");
+			*(pr + len) = '\0';
+			thishop = create_route(pr, tail);
+			if (!thishop) {
+				return -1;
+			}
+
+			if (!head) {
+				head = thishop;
+			}
+			tail = thishop;
+			ast_debug(2, "build_path: Path hop: <%s>\n", thishop->hop);
+		}
+	}
+
+	/* Store as new route */
+	peer->path = head;
+
+	/* For debugging dump what we ended up with */
+	if (p && sip_debug_test_pvt(p)) {
+		list_route(peer->path);
+	}
+	return 0;
 }
 
 /*! \brief builds the sip_pvt's nonce field which is used for the authentication 
@@ -19984,6 +20179,20 @@
 		ast_cli(fd, "  Ign SDP ver  : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_IGNORESDPVERSION)));
 		ast_cli(fd, "  Trust RPID   : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_TRUSTRPID)));
 		ast_cli(fd, "  Send RPID    : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_SENDRPID)));
+		ast_cli(fd, "  Path support : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_USEPATH)));
+		ast_cli(fd, "  Path         : ");
+		if (!peer->path) {
+			ast_cli(fd, "N/A\n");
+		} else {
+			struct sip_route *r = peer->path;
+			int first = 1;
+			while (r) {
+				ast_cli(fd, "%s<%s>", first ? "" : ", ", r->hop);
+				first = 0;
+				r = r->next;
+			}
+			ast_cli(fd, "\n");
+		}
 		ast_cli(fd, "  Subscriptions: %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWSUBSCRIBE)));
 		ast_cli(fd, "  Overlap dial : %s\n", allowoverlap2str(ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWOVERLAP)));
 		if (peer->outboundproxy)
@@ -20577,6 +20786,7 @@
 	ast_cli(a->fd, "  Allow promisc. redir:   %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_PROMISCREDIR)));
 	ast_cli(a->fd, "  Enable call counters:   %s\n", AST_CLI_YESNO(global_callcounter));
 	ast_cli(a->fd, "  SIP domain support:     %s\n", AST_CLI_YESNO(!AST_LIST_EMPTY(&domain_list)));
+	ast_cli(a->fd, "  Path support :          %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_USEPATH)));
 	ast_cli(a->fd, "  Realm. auth:            %s\n", AST_CLI_YESNO(credentials != NULL));
 	if (credentials) {
 		struct sip_auth *auth;
@@ -20750,6 +20960,7 @@
 		ast_cli(a->fd, "  Update:                 %s\n", AST_CLI_YESNO(sip_cfg.peer_rtupdate));
 		ast_cli(a->fd, "  Ignore Reg. Expire:     %s\n", AST_CLI_YESNO(sip_cfg.ignore_regexpire));
 		ast_cli(a->fd, "  Save sys. name:         %s\n", AST_CLI_YESNO(sip_cfg.rtsave_sysname));
+		ast_cli(a->fd, "  Save path header:       %s\n", AST_CLI_YESNO(sip_cfg.rtsave_path));
 		ast_cli(a->fd, "  Auto Clear:             %d (%s)\n", sip_cfg.rtautoclear, ast_test_flag(&global_flags[1], SIP_PAGE2_RTAUTOCLEAR) ? "Enabled" : "Disabled");
 	}
 	ast_cli(a->fd, "\n----\n");
@@ -23342,7 +23553,7 @@
 {
 	int expires, expires_ms;
 	struct sip_registry *r;
-	r=p->registry;
+	r = p->registry;
 	
 	switch (resp) {
 	case 401:	/* Unauthorized */
@@ -29492,6 +29703,11 @@
 	ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
 	ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
 	ast_copy_flags(&p->flags[2], &peer->flags[2], SIP_PAGE3_FLAGS_TO_COPY);
+	copy_route(&p->route, peer->path);
+	if (p->route) {
+		/* Parse SIP URI of first route-set hop and use it as target address */
+		__set_address_from_contact(p->route->hop, &p->sa, p->socket.type == SIP_TRANSPORT_TLS ? 1 : 0);	
+	}
 
 	/* Send OPTIONs to peer's fullcontact */
 	if (!ast_strlen_zero(peer->fullcontact)) {
@@ -29946,6 +30162,9 @@
 	if (!strcasecmp(v->name, "trustrpid")) {
 		ast_set_flag(&mask[0], SIP_TRUSTRPID);
 		ast_set2_flag(&flags[0], ast_true(v->value), SIP_TRUSTRPID);
+	} else if (!strcasecmp(v->name, "supportpath")) {
+		ast_set_flag(&mask[0], SIP_USEPATH);
+		ast_set2_flag(&flags[0], ast_true(v->value), SIP_USEPATH);
 	} else if (!strcasecmp(v->name, "sendrpid")) {
 		ast_set_flag(&mask[0], SIP_SENDRPID);
 		if (!strcasecmp(v->value, "pai")) {
@@ -31528,6 +31747,8 @@
 			ast_set2_flag(&global_flags[1], ast_true(v->value), SIP_PAGE2_RTCACHEFRIENDS);
 		} else if (!strcasecmp(v->name, "rtsavesysname")) {
 			sip_cfg.rtsave_sysname = ast_true(v->value);
+		} else if (!strcasecmp(v->name, "rtsavepath")) {
+			sip_cfg.rtsave_path = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "rtupdate")) {
 			sip_cfg.peer_rtupdate = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "ignoreregexpire")) {

Modified: trunk/channels/sip/include/sip.h
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sip/include/sip.h?view=diff&rev=382440&r1=382439&r2=382440
==============================================================================
--- trunk/channels/sip/include/sip.h (original)
+++ trunk/channels/sip/include/sip.h Tue Mar  5 07:14:43 2013
@@ -294,6 +294,7 @@
 #define SIP_PROG_INBAND_NO     (1 << 25)
 #define SIP_PROG_INBAND_YES    (2 << 25)
 
+#define SIP_USEPATH          (1 << 27) /*!< GDP: Trust and use incoming Path headers? */
 #define SIP_SENDRPID         (3 << 29) /*!< DP: Remote Party-ID Support */
 #define SIP_SENDRPID_NO      (0 << 29)
 #define SIP_SENDRPID_PAI     (1 << 29) /*!< Use "P-Asserted-Identity" for rpid */
@@ -304,7 +305,7 @@
 #define SIP_FLAGS_TO_COPY \
 	(SIP_PROMISCREDIR | SIP_TRUSTRPID | SIP_SENDRPID | SIP_DTMF | SIP_REINVITE | \
 	 SIP_PROG_INBAND | SIP_USECLIENTCODE | SIP_NAT_FORCE_RPORT | SIP_G726_NONSTANDARD | \
-	 SIP_USEREQPHONE | SIP_INSECURE)
+	 SIP_USEREQPHONE | SIP_INSECURE | SIP_USEPATH)
 /*@}*/
 
 /*! \name SIPflags2
@@ -737,6 +738,7 @@
 struct sip_settings {
 	int peer_rtupdate;          /*!< G: Update database with registration data for peer? */
 	int rtsave_sysname;         /*!< G: Save system name at registration? */
+	int rtsave_path;            /*!< G: Save path header on registration */
 	int ignore_regexpire;       /*!< G: Ignore expiration of peer  */
 	int rtautoclear;            /*!< Realtime ?? */
 	int directrtpsetup;         /*!< Enable support for Direct RTP setup (no re-invites) */
@@ -1368,6 +1370,7 @@
 	int timer_t1;                   /*!<  The maximum T1 value for the peer */
 	int timer_b;                    /*!<  The maximum timer B (transaction timeouts) */
 	int fromdomainport;             /*!<  The From: domain port */
+	struct sip_route *path;         /*!<  Head of linked list of out-of-dialog outgoing routing steps (fm Path headers) */
 
 	/*XXX Seems like we suddenly have two flags with the same content. Why? To be continued... */
 	enum sip_peer_type type; /*!< Distinguish between "user" and "peer" types. This is used solely for CLI and manager commands */

Modified: trunk/configs/res_ldap.conf.sample
URL: http://svnview.digium.com/svn/asterisk/trunk/configs/res_ldap.conf.sample?view=diff&rev=382440&r1=382439&r2=382440
==============================================================================
--- trunk/configs/res_ldap.conf.sample (original)
+++ trunk/configs/res_ldap.conf.sample Tue Mar  5 07:14:43 2013
@@ -121,6 +121,7 @@
 defaultuser = AstAccountDefaultUser
 regserver = AstAccountRegistrationServer
 lastms = AstAccountLastQualifyMilliseconds
+supportpath = AstAccountPathSupport
 additionalFilter=(objectClass=AsteriskSIPUser)
 
 ;

Modified: trunk/configs/sip.conf.sample
URL: http://svnview.digium.com/svn/asterisk/trunk/configs/sip.conf.sample?view=diff&rev=382440&r1=382439&r2=382440
==============================================================================
--- trunk/configs/sip.conf.sample (original)
+++ trunk/configs/sip.conf.sample Tue Mar  5 07:14:43 2013
@@ -442,6 +442,21 @@
 ;outboundproxy=[2001:db8::1]:5062               ; IPv6 address literal with explicit port
 ;                                               ; (could also be tcp,udp) - defining transports on the proxy line only
 ;                                               ; applies for the global proxy, otherwise use the transport= option
+
+;supportpath=yes		; This activates parsing and handling of Path header as defined in RFC 3327. This enables
+				; Asterisk to route outgoing out-of-dialog requests via a set of proxies by using a pre-loaded
+				; route-set defined by the Path headers in the REGISTER request.
+				; NOTE: There are multiple things to consider with this setting:
+				;  * As this influences routing of SIP requests make sure to not trust Path headers provided
+				;    by the user's SIP client (the proxy in front of Asterisk should remove existing user
+				;    provided Path headers).
+				;  * When a peer has both a path and outboundproxy set, the path will be added to Route: header
+				;    but routing to next hop is done using the outboundproxy.
+				;  * If set globally, not only will all peers use the Path header, but outbound REGISTER
+				;    requests from Asterisk will add path to the Supported header.
+
+;rtsavepath=yes                 ; If using dynamic realtime, store the path headers
+
 ;matchexternaddrlocally = yes     ; Only substitute the externaddr or externhost setting if it matches
                                 ; your localnet setting. Unless you have some sort of strange network
                                 ; setup you will not need to enable this.

Modified: trunk/contrib/realtime/mysql/sippeers.sql
URL: http://svnview.digium.com/svn/asterisk/trunk/contrib/realtime/mysql/sippeers.sql?view=diff&rev=382440&r1=382439&r2=382440
==============================================================================
--- trunk/contrib/realtime/mysql/sippeers.sql (original)
+++ trunk/contrib/realtime/mysql/sippeers.sql Tue Mar  5 07:14:43 2013
@@ -79,6 +79,7 @@
       `callingpres` enum('allowed_not_screened','allowed_passed_screen','allowed_failed_screen','allowed','prohib_not_screened','prohib_passed_screen','prohib_failed_screen','prohib') DEFAULT NULL,
       `mohinterpret` varchar(40) DEFAULT NULL,
       `mohsuggest` varchar(40) DEFAULT NULL,
+      `path` varchar(256) DEFAULT NULL,
       `parkinglot` varchar(40) DEFAULT NULL,
       `hasvoicemail` enum('yes','no') DEFAULT NULL,
       `subscribemwi` enum('yes','no') DEFAULT NULL,
@@ -90,6 +91,7 @@
       `ignoresdpversion` enum('yes','no') DEFAULT NULL,
       `allowtransfer` enum('yes','no') DEFAULT NULL,
       `dynamic` enum('yes','no') DEFAULT NULL,
+      `supportpath` enum('yes','no') DEFAULT NULL,
       PRIMARY KEY (`id`),
       UNIQUE KEY `name` (`name`),
       KEY `ipaddr` (`ipaddr`,`port`),

Modified: trunk/contrib/realtime/postgresql/realtime.sql
URL: http://svnview.digium.com/svn/asterisk/trunk/contrib/realtime/postgresql/realtime.sql?view=diff&rev=382440&r1=382439&r2=382440
==============================================================================
--- trunk/contrib/realtime/postgresql/realtime.sql (original)
+++ trunk/contrib/realtime/postgresql/realtime.sql Tue Mar  5 07:14:43 2013
@@ -38,6 +38,7 @@
 callgroup character varying(10),
 callerid character varying(80),
 canreinvite character varying(3) DEFAULT 'yes',
+supportpath character varying(3) DEFAULT 'no',
 context character varying(80),
 defaultip character varying(15),
 dtmfmode character varying(7),
@@ -70,6 +71,7 @@
 lastms integer DEFAULT 0 NOT NULL,
 defaultuser character varying(80),
 fullcontact character varying(80),
+path character varying(256),
 regserver character varying(30),
 useragent character varying(40),
 callbackextension character varying(40)

Modified: trunk/contrib/scripts/asterisk.ldap-schema
URL: http://svnview.digium.com/svn/asterisk/trunk/contrib/scripts/asterisk.ldap-schema?view=diff&rev=382440&r1=382439&r2=382440
==============================================================================
--- trunk/contrib/scripts/asterisk.ldap-schema (original)
+++ trunk/contrib/scripts/asterisk.ldap-schema Tue Mar  5 07:14:43 2013
@@ -112,7 +112,7 @@
 objectIdentifier AstAccountAllowOverlap AstAttrType:67
 objectIdentifier AstAccountVideoSupport AstAttrType:68
 objectIdentifier AstAccountIgnoreSDPVersion AstAttrType:69
-
+objectIdentifier AstAccountPathSupport AstAttrType:70
 
 #############################################################################
 # Object Class OIDs
@@ -636,6 +636,13 @@
 attributetype ( AstAccountIgnoreSDPVersion
         NAME 'AstAccountIgnoreSDPVersion'
         DESC 'Asterisk account ignore SDP version'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+
+attributetype ( AstAccountPathSupport
+        NAME 'AstAccountPathSupport'
+        DESC 'Asterisk account support Path RFC 3327'
         EQUALITY caseIgnoreMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
@@ -762,7 +769,8 @@
         AstAccountTransport $
         AstAccountType $ 
         AstAccountUserAgent $	
-        AstAccountVideoSupport
+        AstAccountVideoSupport $
+        AstAccountPathSupport
     )
     )
 

Modified: trunk/contrib/scripts/asterisk.ldif
URL: http://svnview.digium.com/svn/asterisk/trunk/contrib/scripts/asterisk.ldif?view=diff&rev=382440&r1=382439&r2=382440
==============================================================================
--- trunk/contrib/scripts/asterisk.ldif (original)
+++ trunk/contrib/scripts/asterisk.ldif Tue Mar  5 07:14:43 2013
@@ -108,6 +108,7 @@
 olcObjectIdentifier: AstAccountAllowOverlap AstAttrType:67
 olcObjectIdentifier: AstAccountVideoSupport AstAttrType:68
 olcObjectIdentifier: AstAccountIgnoreSDPVersion AstAttrType:69
+olcObjectIdentifier: AstAccountPathSupport AstAttrType:70
 #
 #
 #############################################################################
@@ -632,6 +633,13 @@
 olcAttributeTypes: ( AstAccountIgnoreSDPVersion
         NAME 'AstAccountIgnoreSDPVersion'
         DESC 'Asterisk account ignore SDP version'
+        EQUALITY caseIgnoreMatch
+        SUBSTR caseIgnoreSubstringsMatch
+        SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+#
+olcAttributeTypes: ( AstAccountPathSupport
+        NAME 'AstAccountPathSupport'
+        DESC 'Asterisk account support Path RFC 3327'
         EQUALITY caseIgnoreMatch
         SUBSTR caseIgnoreSubstringsMatch
         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
@@ -758,7 +766,8 @@
         AstAccountTransport $
         AstAccountType $
         AstAccountUserAgent $
-        AstAccountVideoSupport
+        AstAccountVideoSupport $
+        AstAccountPathSupport
     )
     )
 #




More information about the asterisk-commits mailing list