[asterisk-commits] dlee: branch dlee/stasis-app r382538 - in /team/dlee/stasis-app: ./ apps/ cha...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Mar 6 14:39:14 CST 2013


Author: dlee
Date: Wed Mar  6 14:39:10 2013
New Revision: 382538

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=382538
Log:
Merged revisions 382458-382515 from http://svn.asterisk.org/svn/asterisk/team/dlee/stasis-core

Modified:
    team/dlee/stasis-app/   (props changed)
    team/dlee/stasis-app/CHANGES
    team/dlee/stasis-app/CREDITS
    team/dlee/stasis-app/apps/app_confbridge.c
    team/dlee/stasis-app/apps/app_stasis.c
    team/dlee/stasis-app/channels/chan_sip.c
    team/dlee/stasis-app/channels/chan_unistim.c
    team/dlee/stasis-app/channels/sip/include/sip.h
    team/dlee/stasis-app/configs/res_ldap.conf.sample
    team/dlee/stasis-app/configs/sip.conf.sample
    team/dlee/stasis-app/contrib/realtime/mysql/sippeers.sql
    team/dlee/stasis-app/contrib/realtime/postgresql/realtime.sql
    team/dlee/stasis-app/contrib/scripts/asterisk.ldap-schema
    team/dlee/stasis-app/contrib/scripts/asterisk.ldif
    team/dlee/stasis-app/include/asterisk/format_cap.h
    team/dlee/stasis-app/include/asterisk/sorcery.h
    team/dlee/stasis-app/include/asterisk/stasis.h
    team/dlee/stasis-app/main/bridging.c
    team/dlee/stasis-app/main/channel.c
    team/dlee/stasis-app/main/event.c
    team/dlee/stasis-app/main/manager.c
    team/dlee/stasis-app/main/sorcery.c
    team/dlee/stasis-app/main/stasis.c
    team/dlee/stasis-app/main/stasis_cache.c
    team/dlee/stasis-app/main/threadpool.c
    team/dlee/stasis-app/tests/test_sorcery.c
    team/dlee/stasis-app/tests/test_stasis.c

Propchange: team/dlee/stasis-app/
------------------------------------------------------------------------------
Binary property 'branch-11-merged' - no diff available.

Propchange: team/dlee/stasis-app/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Wed Mar  6 14:39:10 2013
@@ -1,1 +1,1 @@
-/team/dlee/stasis-core:1-382313
+/team/dlee/stasis-core:1-382537

Modified: team/dlee/stasis-app/CHANGES
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-app/CHANGES?view=diff&rev=382538&r1=382537&r2=382538
==============================================================================
--- team/dlee/stasis-app/CHANGES (original)
+++ team/dlee/stasis-app/CHANGES Wed Mar  6 14:39:10 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 --------------------
@@ -397,6 +413,9 @@
    which set the force_rport and comedia options automatically if Asterisk
    detects that an incoming SIP request crossed a NAT after being sent by
    the remote endpoint.
+
+ * The default global nat setting in sip.conf has been changed from force_rport
+   to auto_force_rport.
 
  * NAT settings are now a combinable list of options. The equivalent of the
    deprecated nat=yes is nat=force_rport,comedia. nat=no behaves as before.

Modified: team/dlee/stasis-app/CREDITS
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-app/CREDITS?view=diff&rev=382538&r1=382537&r2=382538
==============================================================================
--- team/dlee/stasis-app/CREDITS (original)
+++ team/dlee/stasis-app/CREDITS Wed Mar  6 14:39:10 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: team/dlee/stasis-app/apps/app_confbridge.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-app/apps/app_confbridge.c?view=diff&rev=382538&r1=382537&r2=382538
==============================================================================
--- team/dlee/stasis-app/apps/app_confbridge.c (original)
+++ team/dlee/stasis-app/apps/app_confbridge.c Wed Mar  6 14:39:10 2013
@@ -596,13 +596,13 @@
 	return tmp;
 }
 
-static void set_rec_filename(struct conference_bridge *bridge, struct ast_str **filename)
+static void set_rec_filename(struct conference_bridge *bridge, struct ast_str **filename, int is_new)
 {
 	char *rec_file = bridge->b_profile.rec_file;
 	time_t now;
 	char *ext;
 
-	if (ast_str_strlen(*filename) && ast_test_flag(&bridge->b_profile, BRIDGE_OPT_RECORD_FILE_APPEND)) {
+	if (ast_str_strlen(*filename) && ast_test_flag(&bridge->b_profile, BRIDGE_OPT_RECORD_FILE_APPEND) && !is_new) {
 		    return;
 	}
 
@@ -627,12 +627,28 @@
 	}
 }
 
+static int is_new_rec_file(const char *rec_file, struct ast_str **orig_rec_file)
+{
+	if (!ast_strlen_zero(rec_file)) {
+		if (!*orig_rec_file) {
+			*orig_rec_file = ast_str_create(PATH_MAX);
+		}
+
+		if (strcmp(ast_str_buffer(*orig_rec_file), rec_file)) {
+			ast_str_set(orig_rec_file, 0, "%s", rec_file);
+			return 1;
+		}
+	}
+	return 0;
+}
+
 static void *record_thread(void *obj)
 {
 	struct conference_bridge *conference_bridge = obj;
 	struct ast_app *mixmonapp = pbx_findapp("MixMonitor");
 	struct ast_channel *chan;
 	struct ast_str *filename = ast_str_alloca(PATH_MAX);
+	struct ast_str *orig_rec_file = NULL;
 
 	ast_mutex_lock(&conference_bridge->record_lock);
 	if (!mixmonapp) {
@@ -645,7 +661,8 @@
 
 	/* XXX If we get an EXIT right here, START will essentially be a no-op */
 	while (conference_bridge->record_state != CONF_RECORD_EXIT) {
-		set_rec_filename(conference_bridge, &filename);
+		set_rec_filename(conference_bridge, &filename,
+				 is_new_rec_file(conference_bridge->b_profile.rec_file, &orig_rec_file));
 		chan = ast_channel_ref(conference_bridge->record_chan);
 		ast_answer(chan);
 		pbx_exec(chan, mixmonapp, ast_str_buffer(filename));
@@ -655,6 +672,7 @@
 		/* STOP has been called. Wait for either a START or an EXIT */
 		ast_cond_wait(&conference_bridge->record_cond, &conference_bridge->record_lock);
 	}
+	ast_free(orig_rec_file);
 	ast_mutex_unlock(&conference_bridge->record_lock);
 	ao2_ref(conference_bridge, -1);
 	return NULL;

Modified: team/dlee/stasis-app/apps/app_stasis.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-app/apps/app_stasis.c?view=diff&rev=382538&r1=382537&r2=382538
==============================================================================
--- team/dlee/stasis-app/apps/app_stasis.c (original)
+++ team/dlee/stasis-app/apps/app_stasis.c Wed Mar  6 14:39:10 2013
@@ -333,7 +333,7 @@
 	return 0;
 }
 
-static void sub_handler(void *data, struct stasis_topic *topic, struct stasis_message *message)
+static void sub_handler(void *data, struct stasis_subscription *sub, struct stasis_topic *topic, struct stasis_message *message)
 {
 	struct stasis_app *app = data;
 	if (ast_channel_snapshot() == stasis_message_type(message)) {
@@ -342,6 +342,9 @@
 
 		msg = stasis_app_event_create("channel-state-change", snapshot, NULL);
 		app_send(app, msg);
+	}
+	if (stasis_subscription_final_message(sub, message)) {
+		ao2_cleanup(data);
 	}
 }
 
@@ -411,6 +414,7 @@
 		ast_log(LOG_ERROR, "Error subscribing app %s to channel %s\n", args.app_name, ast_channel_name(chan));
 		return -1;
 	}
+	ao2_ref(app, +1); /* subscription now has a reference */
 
 	res = send_start_msg(app, chan, args.argc - 1, args.app_argv);
 	if (res != 0) {

Modified: team/dlee/stasis-app/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-app/channels/chan_sip.c?view=diff&rev=382538&r1=382537&r2=382538
==============================================================================
--- team/dlee/stasis-app/channels/chan_sip.c (original)
+++ team/dlee/stasis-app/channels/chan_sip.c Wed Mar  6 14:39:10 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);
@@ -1399,7 +1401,7 @@
 static int get_also_info(struct sip_pvt *p, struct sip_request *oreq);
 static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req);
 static int set_address_from_contact(struct sip_pvt *pvt);
-static void check_via(struct sip_pvt *p, struct sip_request *req);
+static void check_via(struct sip_pvt *p, const struct sip_request *req);
 static int get_rpid(struct sip_pvt *p, struct sip_request *oreq);
 static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason, char **reason_str);
 static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_recall_core_id);
@@ -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)
@@ -8747,9 +8785,8 @@
 
 	if (useglobal_nat && addr) {
 		/* Setup NAT structure according to global settings if we have an address */
-		ast_copy_flags(&p->flags[0], &global_flags[0], SIP_NAT_FORCE_RPORT);
 		ast_sockaddr_copy(&p->recv, addr);
-
+		check_via(p, req);
 		do_setnat(p);
 	}
 
@@ -11343,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;
 }
 
@@ -11524,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) {
@@ -11546,7 +11594,6 @@
 		rem -= (n+2);
 	}
 	*p = '\0';
-	add_header(req, "Route", r);
 }
 
 /*! \brief Set destination from SIP URI
@@ -11822,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);
@@ -12116,8 +12166,9 @@
 
 	if (useglobal_nat && addr) {
 		ast_copy_flags(&p->flags[0], &global_flags[0], SIP_NAT_FORCE_RPORT);
+		ast_copy_flags(&p->flags[2], &global_flags[2], SIP_PAGE3_NAT_AUTO_RPORT);
 		ast_sockaddr_copy(&p->recv, addr);
-		do_setnat(p);
+		check_via(p, req);
 	}
 
 	ast_string_field_set(p, fromdomain, default_fromdomain);
@@ -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 
@@ -17958,7 +18153,7 @@
 }
 
 /*! \brief check Via: header for hostname, port and rport request/answer */
-static void check_via(struct sip_pvt *p, struct sip_request *req)
+static void check_via(struct sip_pvt *p, const struct sip_request *req)
 {
 	char via[512];
 	char *c, *maddr;
@@ -18090,6 +18285,21 @@
 				of, ast_sockaddr_stringify(&p->recv));
 		}
 		return AUTH_DONT_KNOW;
+	}
+
+	/*  build_peer, called through sip_find_peer, is not able to check the
+	 *  sip_pvt->natdetected flag in order to determine if the peer is behind
+	 *  NAT or not when SIP_PAGE3_NAT_AUTO_RPORT or SIP_PAGE3_NAT_AUTO_COMEDIA
+	 *  are set on the peer.  So we check for that here and set the peer's
+	 *  address accordingly.
+	 */
+	if (p->natdetected && ast_test_flag(&peer->flags[2], SIP_PAGE3_NAT_AUTO_RPORT)) {
+		ast_set_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT);
+		ast_sockaddr_copy(&peer->addr, &p->recv);
+	}
+
+	if (p->natdetected && ast_test_flag(&peer->flags[2], SIP_PAGE3_NAT_AUTO_COMEDIA)) {
+		ast_set_flag(&peer->flags[1], SIP_PAGE2_SYMMETRICRTP);
 	}
 
 	if (!ast_apply_acl(peer->acl, addr, "SIP Peer ACL: ")) {
@@ -19969,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)
@@ -20562,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;
@@ -20735,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");
@@ -23327,7 +23553,7 @@
 {
 	int expires, expires_ms;
 	struct sip_registry *r;
-	r=p->registry;
+	r = p->registry;
 	
 	switch (resp) {
 	case 401:	/* Unauthorized */
@@ -28426,7 +28652,10 @@
 	owner_chan_ref = sip_pvt_lock_full(p);
 
 	copy_socket_data(&p->socket, &req->socket);
-	ast_sockaddr_copy(&p->recv, addr);
+
+	if (ast_sockaddr_isnull(&p->recv)) { /* This may already be set before getting here */
+		ast_sockaddr_copy(&p->recv, addr);
+	}
 
 	/* if we have an owner, then this request has been authenticated */
 	if (p->owner) {
@@ -29474,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)) {
@@ -29928,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")) {
@@ -30637,7 +30874,7 @@
 			} else if (!strcasecmp(v->name, "host")) {
 				if (!strcasecmp(v->value, "dynamic")) {
 					/* They'll register with us */
-					if ((!found && !realtime) || !peer->host_dynamic) {
+					if ((!found && !ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS)) || !peer->host_dynamic) {
 						/* Initialize stuff if this is a new peer, or if it used to
 						 * not be dynamic before the reload. */
 						ast_sockaddr_setnull(&peer->addr);
@@ -30990,6 +31227,10 @@
 		set_socket_transport(&peer->socket, peer->default_outbound_transport);
 	}
 
+	ast_copy_flags(&peer->flags[0], &peerflags[0], mask[0].flags);
+	ast_copy_flags(&peer->flags[1], &peerflags[1], mask[1].flags);
+	ast_copy_flags(&peer->flags[2], &peerflags[2], mask[2].flags);
+
 	if (ast_str_strlen(fullcontact)) {
 		ast_string_field_set(peer, fullcontact, ast_str_buffer(fullcontact));
 		peer->rt_fromcontact = TRUE;
@@ -31083,9 +31324,6 @@
 		sip_poke_peer(peer, 0);
 	}
 
-	ast_copy_flags(&peer->flags[0], &peerflags[0], mask[0].flags);
-	ast_copy_flags(&peer->flags[1], &peerflags[1], mask[1].flags);
-	ast_copy_flags(&peer->flags[2], &peerflags[2], mask[2].flags);
 	if (ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWSUBSCRIBE)) {
 		sip_cfg.allowsubscribe = TRUE;	/* No global ban any more */
 	}
@@ -31509,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: team/dlee/stasis-app/channels/chan_unistim.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-app/channels/chan_unistim.c?view=diff&rev=382538&r1=382537&r2=382538
==============================================================================
--- team/dlee/stasis-app/channels/chan_unistim.c (original)
+++ team/dlee/stasis-app/channels/chan_unistim.c Wed Mar  6 14:39:10 2013
@@ -4647,6 +4647,7 @@
 	ast_mutex_lock(&sub->parent->parent->lock);
 	if (!sub->parent->parent->session) {
 		ast_log(LOG_WARNING, "Unistim callback function called without a session\n");
+		ast_mutex_unlock(&sub->parent->parent->lock);
 		return NULL;
 	}
 	ast_mutex_unlock(&sub->parent->parent->lock);
@@ -5080,6 +5081,7 @@
 	if (p->owner != oldchan) {
 		ast_log(LOG_WARNING, "old channel wasn't %s (%p) but was %s (%p)\n",
 				ast_channel_name(oldchan), oldchan, ast_channel_name(p->owner), p->owner);
+		ast_mutex_unlock(&p->lock);
 		return -1;
 	}
 

Modified: team/dlee/stasis-app/channels/sip/include/sip.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-app/channels/sip/include/sip.h?view=diff&rev=382538&r1=382537&r2=382538
==============================================================================
--- team/dlee/stasis-app/channels/sip/include/sip.h (original)
+++ team/dlee/stasis-app/channels/sip/include/sip.h Wed Mar  6 14:39:10 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: team/dlee/stasis-app/configs/res_ldap.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-app/configs/res_ldap.conf.sample?view=diff&rev=382538&r1=382537&r2=382538
==============================================================================
--- team/dlee/stasis-app/configs/res_ldap.conf.sample (original)
+++ team/dlee/stasis-app/configs/res_ldap.conf.sample Wed Mar  6 14:39:10 2013
@@ -121,6 +121,7 @@
 defaultuser = AstAccountDefaultUser
 regserver = AstAccountRegistrationServer
 lastms = AstAccountLastQualifyMilliseconds
+supportpath = AstAccountPathSupport
 additionalFilter=(objectClass=AsteriskSIPUser)
 
 ;

Modified: team/dlee/stasis-app/configs/sip.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-app/configs/sip.conf.sample?view=diff&rev=382538&r1=382537&r2=382538
==============================================================================
--- team/dlee/stasis-app/configs/sip.conf.sample (original)
+++ team/dlee/stasis-app/configs/sip.conf.sample Wed Mar  6 14:39:10 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: team/dlee/stasis-app/contrib/realtime/mysql/sippeers.sql
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-app/contrib/realtime/mysql/sippeers.sql?view=diff&rev=382538&r1=382537&r2=382538
==============================================================================
--- team/dlee/stasis-app/contrib/realtime/mysql/sippeers.sql (original)
+++ team/dlee/stasis-app/contrib/realtime/mysql/sippeers.sql Wed Mar  6 14:39:10 2013
@@ -24,7 +24,7 @@
       `transport` enum('udp','tcp','udp,tcp','tcp,udp') DEFAULT NULL,
       `dtmfmode` enum('rfc2833','info','shortinfo','inband','auto') DEFAULT NULL,
       `directmedia` enum('yes','no','nonat','update') DEFAULT NULL,
-      `nat` enum('yes','no','never','route') DEFAULT NULL,

[... 1738 lines stripped ...]



More information about the asterisk-commits mailing list