[svn-commits] dvossel: branch 1.6.2 r200984 - in /branches/1.6.2: ./ channels/chan_sip.c

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Jun 16 11:29:06 CDT 2009


Author: dvossel
Date: Tue Jun 16 11:28:49 2009
New Revision: 200984

URL: http://svn.asterisk.org/svn-view/asterisk?view=rev&rev=200984
Log:
Merged revisions 200946 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/trunk

........
  r200946 | dvossel | 2009-06-16 11:03:30 -0500 (Tue, 16 Jun 2009) | 32 lines
  
  SIP transport type issues
  
  What this patch addresses:
  1. ast_sip_ouraddrfor() by default binds to the UDP address/port
  reguardless if the sip->pvt is of type UDP or not.  Now when no
  remapping is required, ast_sip_ouraddrfor() checks the sip_pvt's
  transport type, attempting to set the address and port to the
  correct TCP/TLS bindings if necessary.
  2.  It is not necessary to send the port number in the Contact
  header unless the port is non-standard for the transport type.
  This patch fixes this and removes the todo note.
  3.  In sip_alloc(), the default dialog built always uses transport
  type UDP.  Now sip_alloc() looks at the sip_request (if present)
  and determines what transport type to use by default.
  4.  When changing the transport type of a sip_socket, the file
  descriptor must be set to -1 and in some cases the tcptls_session's
  ref count must be decremented and set to NULL.  I've encountered
  several issues associated with this process and have created a function,
  set_socket_transport(), to handle the setting of the socket type.
  
  
  (closes issue #13865)
  Reported by: st
  Patches:
        dont_add_port_if_tls.patch uploaded by Kristijan (license 753)
        13865.patch uploaded by mmichelson (license 60)
        tls_port_v5.patch uploaded by vrban (license 756)
        transport_issues.diff uploaded by dvossel (license 671)
  Tested by: mmichelson, Kristijan, vrban, jmacz, dvossel
  
  Review: https://reviewboard.asterisk.org/r/278/
........

Modified:
    branches/1.6.2/   (props changed)
    branches/1.6.2/channels/chan_sip.c

Propchange: branches/1.6.2/
------------------------------------------------------------------------------
Binary property 'trunk-merged' - no diff available.

Modified: branches/1.6.2/channels/chan_sip.c
URL: http://svn.asterisk.org/svn-view/asterisk/branches/1.6.2/channels/chan_sip.c?view=diff&rev=200984&r1=200983&r2=200984
==============================================================================
--- branches/1.6.2/channels/chan_sip.c (original)
+++ branches/1.6.2/channels/chan_sip.c Tue Jun 16 11:28:49 2009
@@ -2259,7 +2259,7 @@
 
 /*--- Dialog management */
 static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *sin,
-				 int useglobal_nat, const int intended_method);
+				 int useglobal_nat, const int intended_method, struct sip_request *req);
 static int __sip_autodestruct(const void *data);
 static void sip_scheddestroy(struct sip_pvt *p, int ms);
 static int sip_cancel_destroy(struct sip_pvt *p);
@@ -2458,6 +2458,7 @@
 static void destroy_association(struct sip_peer *peer);
 static void set_insecure_flags(struct ast_flags *flags, const char *value, int lineno);
 static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask, struct ast_variable *v);
+static void set_socket_transport(struct sip_socket *socket, int transport);
 
 /* Realtime device support */
 static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *username, const char *fullcontact, const char *useragent, int expirey, int deprecated_username, int lastms);
@@ -2468,7 +2469,7 @@
 static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
 
 /*--- Internal UA client handling (outbound registrations) */
-static void ast_sip_ouraddrfor(struct in_addr *them, struct sockaddr_in *us);
+static void ast_sip_ouraddrfor(struct in_addr *them, struct sockaddr_in *us, struct sip_pvt *p);
 static void sip_registry_destroy(struct sip_registry *reg);
 static int sip_register(const char *value, int lineno);
 static const char *regstate2str(enum sipregistrystate regstate) attribute_const;
@@ -2777,14 +2778,14 @@
 		reqcpy.data = str_save;
 		ast_str_reset(reqcpy.data);
 
-		req.socket.fd = tcptls_session->fd;
 		if (tcptls_session->ssl) {
-			req.socket.type = SIP_TRANSPORT_TLS;
+			set_socket_transport(&req.socket, SIP_TRANSPORT_TLS);
 			req.socket.port = htons(ourport_tls);
 		} else {
-			req.socket.type = SIP_TRANSPORT_TCP;
+			set_socket_transport(&req.socket, SIP_TRANSPORT_TCP);
 			req.socket.port = htons(ourport_tcp);
 		}
+		req.socket.fd = tcptls_session->fd;
 		res = ast_wait_for_input(tcptls_session->fd, -1);
 		if (res < 0) {
 			ast_debug(2, "SIP %s server :: ast_wait_for_input returned %d\n", tcptls_session->ssl ? "SSL": "TCP", res);
@@ -3270,8 +3271,9 @@
 */
 static inline const char *get_transport_pvt(struct sip_pvt *p)
 {
-	if (p->outboundproxy && p->outboundproxy->transport)
-		p->socket.type = p->outboundproxy->transport;
+	if (p->outboundproxy && p->outboundproxy->transport) {
+		set_socket_transport(&p->socket, p->outboundproxy->transport);
+	}
 
 	return get_transport(p->socket.type);
 }
@@ -3346,7 +3348,7 @@
  * externip or can get away with our internal bindaddr
  * 'us' is always overwritten.
  */
-static void ast_sip_ouraddrfor(struct in_addr *them, struct sockaddr_in *us)
+static void ast_sip_ouraddrfor(struct in_addr *them, struct sockaddr_in *us, struct sip_pvt *p)
 {
 	struct sockaddr_in theirs;
 	/* Set want_remap to non-zero if we want to remap 'us' to an externally
@@ -3390,10 +3392,34 @@
 			ast_log(LOG_WARNING, "stun failed\n");
 		ast_debug(1, "Target address %s is not local, substituting externip\n", 
 			ast_inet_ntoa(*(struct in_addr *)&them->s_addr));
+	} else if (p) {
+		/* no remapping, but we bind to a specific address, so use it. */
+		switch (p->socket.type) {
+		case SIP_TRANSPORT_TCP:
+			if (sip_tcp_desc.local_address.sin_addr.s_addr) {
+				*us = sip_tcp_desc.local_address;
+			} else {
+				us->sin_port = sip_tcp_desc.local_address.sin_port;
+			}
+			break;
+		case SIP_TRANSPORT_TLS:
+			if (sip_tls_desc.local_address.sin_addr.s_addr) {
+				*us = sip_tls_desc.local_address;
+			} else {
+				us->sin_port = sip_tls_desc.local_address.sin_port;
+			}
+				break;
+		case SIP_TRANSPORT_UDP:
+			/* fall through on purpose */
+		default:
+			if (bindaddr.sin_addr.s_addr) {
+				*us = bindaddr;
+			}
+		}
 	} else if (bindaddr.sin_addr.s_addr) {
-		/* no remapping, but we bind to a specific address, so use it. */
 		*us = bindaddr;
 	}
+	ast_debug(3, "Setting SIP_TRANSPORT_%s with address %s:%d\n", get_transport(p->socket.type), ast_inet_ntoa(us->sin_addr), ntohs(us->sin_port));
 }
 
 /*! \brief Append to SIP dialog history with arg list  */
@@ -4918,8 +4944,9 @@
 
 	if (peer) {
 		int res;
-		if (newdialog)
-			dialog->socket.type = 0;
+		if (newdialog) {
+			set_socket_transport(&dialog->socket, 0);
+		}
 		res = create_addr_from_peer(dialog, peer);
 		if (!ast_strlen_zero(port)) {
 			if ((portno = atoi(port))) {
@@ -4981,7 +5008,7 @@
 	}
 
 	if (!dialog->socket.type)
-		dialog->socket.type = SIP_TRANSPORT_UDP;
+		set_socket_transport(&dialog->socket, SIP_TRANSPORT_UDP);
 	if (!dialog->socket.port)
 		dialog->socket.port = bindaddr.sin_port;
 	dialog->sa.sin_port = htons(portno);
@@ -6706,7 +6733,7 @@
  * remember to release the reference.
  */
 static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *sin,
-				 int useglobal_nat, const int intended_method)
+				 int useglobal_nat, const int intended_method, struct sip_request *req)
 {
 	struct sip_pvt *p;
 
@@ -6718,8 +6745,13 @@
 		return NULL;
 	}
 
+	if (req) {
+		set_socket_transport(&p->socket, req->socket.type); /* Later in ast_sip_ouraddrfor we need this to choose the right ip and port for the specific transport */
+	} else {
+		set_socket_transport(&p->socket, SIP_TRANSPORT_UDP);
+	}
+
 	p->socket.fd = -1;
-	p->socket.type = SIP_TRANSPORT_UDP;
 	p->method = intended_method;
 	p->initid = -1;
 	p->waitid = -1;
@@ -6742,7 +6774,7 @@
 		p->ourip = internip;
 	else {
 		p->sa = *sin;
-		ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip);
+		ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p);
 	}
 
 	/* Copy global flags to this PVT at setup. */
@@ -6985,7 +7017,7 @@
 			transmit_response_using_temp(callid, sin, 1, intended_method, req, "489 Bad event");
 		} else {
 			/* Ok, time to create a new SIP dialog object, a pvt */
-			if ((p = sip_alloc(callid, sin, 1, intended_method)))  {
+			if ((p = sip_alloc(callid, sin, 1, intended_method, req)))  {
 				/* Ok, we've created a dialog, let's go and process it */
 				sip_pvt_lock(p);
 			} else {
@@ -8947,7 +8979,7 @@
 		p->ourip = internip;
 	else {
 		p->sa = *sin;
-		ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip);
+		ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p);
 	}
 
 	p->branch = ast_random();
@@ -9870,15 +9902,17 @@
 {
 
 	int ourport = ntohs(p->ourip.sin_port);
-
-	if (p->socket.type & SIP_TRANSPORT_UDP) {
-		if (!sip_standard_port(p->socket.type, ourport))
-			ast_string_field_build(p, our_contact, "<sip:%s%s%s:%d>", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr), ourport);
+	/* only add port if it's non-standard for the transport type */
+	if (!sip_standard_port(p->socket.type, ourport)) {
+		if (p->socket.type == SIP_TRANSPORT_UDP)
+			ast_string_field_build(p, our_contact, "<sip:%s%s%s:%d>", p->exten, S_OR(p->exten, "@"), ast_inet_ntoa(p->ourip.sin_addr), ourport);
 		else
-			ast_string_field_build(p, our_contact, "<sip:%s%s%s>", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr));
-	} else  {
-		/*! \todo We should not always add port here. Port is only added if it's non-standard (see code above) */
-		ast_string_field_build(p, our_contact, "<sip:%s%s%s:%d;transport=%s>", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr), ourport, get_transport(p->socket.type));
+			ast_string_field_build(p, our_contact, "<sip:%s%s%s:%d;transport=%s>", p->exten, S_OR(p->exten, "@"), ast_inet_ntoa(p->ourip.sin_addr), ourport, get_transport(p->socket.type));
+	} else {
+		if (p->socket.type == SIP_TRANSPORT_UDP)
+			ast_string_field_build(p, our_contact, "<sip:%s%s%s>", p->exten, S_OR(p->exten, "@"), ast_inet_ntoa(p->ourip.sin_addr));
+		else
+			ast_string_field_build(p, our_contact, "<sip:%s%s%s;transport=%s>", p->exten, S_OR(p->exten, "@"), ast_inet_ntoa(p->ourip.sin_addr), get_transport(p->socket.type));
 	}
 }
 
@@ -10281,7 +10315,7 @@
 	}
 	
 	/* Create a dialog that we will use for the subscription */
-	if (!(mwi->call = sip_alloc(NULL, NULL, 0, SIP_SUBSCRIBE))) {
+	if (!(mwi->call = sip_alloc(NULL, NULL, 0, SIP_SUBSCRIBE, NULL))) {
 		return -1;
 	}
 
@@ -10319,9 +10353,9 @@
 	if (!ast_strlen_zero(mwi->secret)) {
 		ast_string_field_set(mwi->call, peersecret, mwi->secret);
 	}
-	mwi->call->socket.type = mwi->transport;
+	set_socket_transport(&mwi->call->socket, mwi->transport);
 	mwi->call->socket.port = htons(mwi->portno);
-	ast_sip_ouraddrfor(&mwi->call->sa.sin_addr, &mwi->call->ourip);
+	ast_sip_ouraddrfor(&mwi->call->sa.sin_addr, &mwi->call->ourip, mwi->call);
 	build_contact(mwi->call);
 	build_via(mwi->call);
 	build_callid_pvt(mwi->call);
@@ -10667,7 +10701,7 @@
 		channame += 4;
 	}
 
-	if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY))) {
+	if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY, NULL))) {
 		astman_send_error(s, m, "Unable to build sip pvt data for notify (memory/socket error)");
 		return 0;
 	}
@@ -10685,7 +10719,7 @@
 	ast_set_flag(&p->flags[0], SIP_OUTGOING);
 
 	/* Recalculate our side, and recalculate Call ID */
-	ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip);
+	ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p);
 	build_via(p);
 	ao2_t_unlink(dialogs, p, "About to change the callid -- remove the old name");
 	build_callid_pvt(p);
@@ -10872,7 +10906,7 @@
 			r->callid_valid = TRUE;
 		}
 		/* Allocate SIP dialog for registration */
-		if (!(p = sip_alloc( r->callid, NULL, 0, SIP_REGISTER))) {
+		if (!(p = sip_alloc( r->callid, NULL, 0, SIP_REGISTER, NULL))) {
 			ast_log(LOG_WARNING, "Unable to allocate registration transaction (memory or socket error)\n");
 			return 0;
 		}
@@ -10939,7 +10973,7 @@
 			ast_string_field_set(p, exten, r->callback);
 
 		/* Set transport and port so the correct contact is built */
-		p->socket.type = r->transport;
+		set_socket_transport(&p->socket, r->transport);
 		if (r->transport == SIP_TRANSPORT_TLS || r->transport == SIP_TRANSPORT_TCP) {
 			p->socket.port = sip_tcp_desc.local_address.sin_port;
 		}
@@ -10949,7 +10983,7 @@
 		  based on whether the remote host is on the external or
 		  internal network so we can register through nat
 		 */
-		ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip);
+		ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p);
 		build_contact(p);
 	}
 
@@ -11275,15 +11309,15 @@
 	}
 }
 
-static void set_peer_transport(struct sip_peer *peer, int transport)
+static void set_socket_transport(struct sip_socket *socket, int transport)
 {
 	/* if the transport type changes, clear all socket data */
-	if (peer->socket.type != transport) {
-		peer->socket.type = transport;
-		peer->socket.fd = -1;
-		if (peer->socket.tcptls_session) {
-			ao2_ref(peer->socket.tcptls_session, -1);
-			peer->socket.tcptls_session = NULL;
+	if (socket->type != transport) {
+		socket->fd = -1;
+		socket->type = transport;
+		if (socket->tcptls_session) {
+			ao2_ref(socket->tcptls_session, -1);
+			socket->tcptls_session = NULL;
 		}
 	}
 }
@@ -11300,7 +11334,7 @@
 	memset(&peer->addr, 0, sizeof(peer->addr));
 
 	destroy_association(peer);	/* remove registration data from storage */
-	set_peer_transport(peer, peer->default_outbound_transport);
+	set_socket_transport(&peer->socket, peer->default_outbound_transport);
 
 	manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Unregistered\r\nCause: Expired\r\n", peer->name);
 	register_peer_exten(peer, FALSE);	/* Remove regexten */
@@ -11547,7 +11581,7 @@
 	} else if (!strcasecmp(curi, "*") || !expire) {	/* Unregister this peer */
 		/* This means remove all registrations and return OK */
 		memset(&peer->addr, 0, sizeof(peer->addr));
-		set_peer_transport(peer, peer->default_outbound_transport);
+		set_socket_transport(&peer->socket, peer->default_outbound_transport);
 
 		AST_SCHED_DEL_UNREF(sched, peer->expire,
 				unref_peer(peer, "remove register expire ref"));
@@ -11602,7 +11636,7 @@
 	 * transport type, change it.  If it got this far, it is a
 	 * supported type, but check just in case */
 	if ((peer->socket.type != transport_type) && (peer->transports & transport_type)) {
-		set_peer_transport(peer, transport_type);
+		set_socket_transport(&peer->socket, transport_type);
 	}
 
 	oldsin = peer->addr;
@@ -16160,7 +16194,7 @@
 	for (i = 3; i < a->argc; i++) {
 		struct sip_pvt *p;
 
-		if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY))) {
+		if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY, NULL))) {
 			ast_log(LOG_WARNING, "Unable to build sip pvt data for notify (memory/socket error)\n");
 			return CLI_FAILURE;
 		}
@@ -16178,7 +16212,7 @@
 		ast_set_flag(&p->flags[0], SIP_OUTGOING);
 
 		/* Recalculate our side, and recalculate Call ID */
-		ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip);
+		ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p);
 		build_via(p);
 		ao2_t_unlink(dialogs, p, "About to change the callid -- remove the old name");
 		build_callid_pvt(p);
@@ -16704,8 +16738,7 @@
 		p->socket.tcptls_session = NULL;
 	}
 
-	p->socket.fd = -1;
-	p->socket.type = transport;
+	set_socket_transport(&p->socket, transport);
 
 	if (ast_test_flag(&p->flags[0], SIP_PROMISCREDIR)) {
 		char *host = NULL;
@@ -21052,8 +21085,8 @@
 	}
 
 	req.len = res;
-	req.socket.fd 	= sipsock;
-	req.socket.type = SIP_TRANSPORT_UDP;
+	req.socket.fd = sipsock;
+	set_socket_transport(&req.socket, SIP_TRANSPORT_UDP);
 	req.socket.tcptls_session	= NULL;
 	req.socket.port = bindaddr.sin_port;
 
@@ -21401,13 +21434,13 @@
 		p = dialog_ref(peer->mwipvt, "sip_send_mwi_to_peer: Setting dialog ptr p from peer->mwipvt-- should this be done?");
 	} else {
 		/* Build temporary dialog for this message */
-		if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY))) 
+		if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY, NULL))) 
 			return -1;
 		/* If we don't set the socket type to 0, then create_addr_from_peer will fail immediately if the peer
 		 * uses any transport other than UDP. We set the type to 0 here and then let create_addr_from_peer copy 
 		 * the peer's socket information to the sip_pvt we just allocated
 		 */
-		p->socket.type = 0;
+		set_socket_transport(&p->socket, 0);
 		if (create_addr_from_peer(p, peer)) {
 			/* Maybe they're not registered, etc. */
 			dialog_unlink_all(p, TRUE, TRUE);
@@ -21416,7 +21449,7 @@
 			return 0;
 		}
 		/* Recalculate our side, and recalculate Call ID */
-		ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip);
+		ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p);
 		build_via(p);
 		ao2_t_unlink(dialogs, p, "About to change the callid -- remove the old name");
 		build_callid_pvt(p);
@@ -21982,7 +22015,7 @@
 		peer->call = dialog_unref(peer->call, "unref dialog peer->call");
 		/* peer->call = sip_destroy(peer->call); */
 	}
-	if (!(p = sip_alloc(NULL, NULL, 0, SIP_OPTIONS))) {
+	if (!(p = sip_alloc(NULL, NULL, 0, SIP_OPTIONS, NULL))) {
 		return -1;
 	}
 	peer->call = dialog_ref(p, "copy sip alloc from p to peer->call");
@@ -22003,7 +22036,7 @@
 		ast_string_field_set(p, tohost, ast_inet_ntoa(peer->addr.sin_addr));
 
 	/* Recalculate our side, and recalculate Call ID */
-	ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip);
+	ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p);
 	build_via(p);
 	ao2_t_unlink(dialogs, p, "About to change the callid -- remove the old name");
 	build_callid_pvt(p);
@@ -22177,7 +22210,7 @@
 	}
 	ast_debug(1, "Asked to create a SIP channel with formats: %s\n", ast_getformatname_multiple(tmp, sizeof(tmp), oldformat));
 
-	if (!(p = sip_alloc(NULL, NULL, 0, SIP_INVITE))) {
+	if (!(p = sip_alloc(NULL, NULL, 0, SIP_INVITE, NULL))) {
 		ast_log(LOG_ERROR, "Unable to build sip pvt data for '%s' (Out of memory or socket error)\n", dest);
 		*cause = AST_CAUSE_SWITCH_CONGESTION;
 		return NULL;
@@ -22246,8 +22279,7 @@
 		host = tmp;
 	}
 
-	p->socket.fd = -1;
-	p->socket.type = transport;
+	set_socket_transport(&p->socket, transport);
 
 	/* We now have 
 		host = peer name, DNS host name or DNS domain (for SRV) 
@@ -22265,7 +22297,7 @@
 	if (ast_strlen_zero(p->peername) && ext)
 		ast_string_field_set(p, peername, ext);
 	/* Recalculate our side, and recalculate Call ID */
-	ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip);
+	ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip, p);
 	build_via(p);
 	ao2_t_unlink(dialogs, p, "About to change the callid -- remove the old name");
 	build_callid_pvt(p);
@@ -22646,8 +22678,7 @@
 		peer->expire = -1;
 		peer->pokeexpire = -1;
 		peer->addr.sin_port = htons(STANDARD_SIP_PORT);
-		peer->socket.type = SIP_TRANSPORT_UDP;
-		peer->socket.fd = -1;
+		set_socket_transport(&peer->socket, SIP_TRANSPORT_UDP);
 	}
 	peer->type = SIP_TYPE_PEER;
 	ast_copy_flags(&peer->flags[0], &global_flags[0], SIP_FLAGS_TO_COPY);
@@ -23151,7 +23182,7 @@
 	if (((peer->socket.type != peer->default_outbound_transport) && (peer->expire == -1)) ||
 		!(peer->socket.type & peer->transports) || !(peer->socket.type)) {
 
-		set_peer_transport(peer, peer->default_outbound_transport);
+		set_socket_transport(&peer->socket, peer->default_outbound_transport);
 	}
 
 	if (fullcontact->used > 0) {




More information about the svn-commits mailing list