[asterisk-commits] dvossel: branch dvossel/sip_via_tcp_rework r194284 - in /team/dvossel/sip_via...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed May 13 10:03:57 CDT 2009


Author: dvossel
Date: Wed May 13 10:03:53 2009
New Revision: 194284

URL: http://svn.asterisk.org/svn-view/asterisk?view=rev&rev=194284
Log:
SIP set outbound transport type from Registration

Now the default transport type is only used until the peer registers.  When registration takes place the transport type is parsed out of the Contact header.  If the Contact header's transport type is equal to one that the peer supports, the peer's default transport type for outbound connections is set to match the Contact header's type.  If the Contact header's transport type is not present, then the peer's default transport type is set to match the one the peer registered with.


Modified:
    team/dvossel/sip_via_tcp_rework/channels/chan_sip.c
    team/dvossel/sip_via_tcp_rework/configs/sip.conf.sample

Modified: team/dvossel/sip_via_tcp_rework/channels/chan_sip.c
URL: http://svn.asterisk.org/svn-view/asterisk/team/dvossel/sip_via_tcp_rework/channels/chan_sip.c?view=diff&rev=194284&r1=194283&r2=194284
==============================================================================
--- team/dvossel/sip_via_tcp_rework/channels/chan_sip.c (original)
+++ team/dvossel/sip_via_tcp_rework/channels/chan_sip.c Wed May 13 10:03:53 2009
@@ -3245,6 +3245,28 @@
 	return sip_debug_test_addr(sip_real_dst(p));
 }
 
+/*! \brief Return sip_transport enum representing transport types in const char *transport */
+static enum sip_transport get_transport_str2enum(const char *transport)
+{
+	int res = 0;
+
+	if (ast_strlen_zero(transport)) {
+		return res;
+	}
+
+	if (!strcasecmp(transport, "udp")) {
+		res |= SIP_TRANSPORT_UDP;
+	}
+	if (!strcasecmp(transport, "tcp")) {
+		res |= SIP_TRANSPORT_TCP;
+	}
+	if (!strcasecmp(transport, "tls")) {
+		res |= SIP_TRANSPORT_TLS;
+	}
+
+	return res;
+}
+
 /*! \brief Return configuration of transports for a device */
 static inline const char *get_transport_list(unsigned int transports) {
 	switch (transports) {
@@ -4081,10 +4103,9 @@
  * general form we are expecting is sip[s]:username[:password][;parameter]@host[:port][;...] 
  * \endverbatim
  * 
- * \todo This function needs to look for ;transport= too
  */
 static int parse_uri(char *uri, char *scheme,
-	char **ret_name, char **pass, char **domain, char **port, char **options)
+	char **ret_name, char **pass, char **domain, char **port, char **options, char **transport)
 {
 	char *name = NULL;
 	int error = 0;
@@ -4103,6 +4124,17 @@
 			error = -1;
 		}
 	}
+	if (transport) {
+		char *t, *type = "";
+		*transport = "";
+		if ((t = strstr(uri, "transport="))) {
+			strsep(&t, "=");
+			if ((type = strsep(&t, ";"))) {
+				*transport = type;
+			}
+		}
+	}
+
 	if (!domain) {
 		/* if we don't want to split around domain, keep everything as a name,
 		 * so we need to do nothing here, except remember why.
@@ -11564,16 +11596,16 @@
 		We still need to be able to send to the remote agent through the proxy.
        */
 	if (tcp) {
-		if (!parse_uri(contact, "sips:", &contact, NULL, &host, &pt, NULL)) {
+		if (!parse_uri(contact, "sips:", &contact, NULL, &host, &pt, NULL, NULL)) {
 			use_tls = TRUE;
 		} else {
-			if (parse_uri(contact2, "sip:", &contact, NULL, &host, &pt, NULL))
+			if (parse_uri(contact2, "sip:", &contact, NULL, &host, &pt, NULL, NULL))
 				ast_log(LOG_NOTICE, "'%s' is not a valid SIP contact (missing sip:) trying to use anyway\n", contact);
 		}
 		port = !ast_strlen_zero(pt) ? atoi(pt) : STANDARD_TLS_PORT;
 		/*! \todo XXX why are we setting TLS port if there's no port given? parse_uri needs to return the transport. */
 	} else {
-		if (parse_uri(contact, "sip:", &contact, NULL, &host, &pt, NULL))
+		if (parse_uri(contact, "sip:", &contact, NULL, &host, &pt, NULL, NULL))
 			ast_log(LOG_NOTICE, "'%s' is not a valid SIP contact (missing sip:) trying to use anyway\n", contact);
 		port = !ast_strlen_zero(pt) ? atoi(pt) : STANDARD_SIP_PORT;
 	}
@@ -11610,20 +11642,21 @@
 	return __set_address_from_contact(pvt->fullcontact, &pvt->sa, pvt->socket.type == SIP_TRANSPORT_TLS ? 1 : 0);
 }
 
-
 /*! \brief Parse contact header and save registration (peer registration) */
 static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, struct sip_peer *peer, struct sip_request *req)
 {
-	char contact[SIPBUFSIZE]; 
+	char contact[SIPBUFSIZE];
 	char data[SIPBUFSIZE];
 	const char *expires = get_header(req, "Expires");
 	int expire = atoi(expires);
-	char *curi, *host, *pt, *curi2;
+	char *curi, *host, *pt, *curi2, *transport;
 	int port;
+	int transport_type;
 	const char *useragent;
 	struct hostent *hp;
 	struct ast_hostent ahp;
 	struct sockaddr_in oldsin, testsin;
+
 
 	ast_copy_string(contact, get_header(req, "Contact"), sizeof(contact));
 
@@ -11639,8 +11672,6 @@
 		}
 	}
 
-	if (peer->socket.type == req->socket.type)
-		copy_socket_data(&peer->socket, &req->socket);
 	copy_socket_data(&pvt->socket, &req->socket);
 
 	/* Look for brackets */
@@ -11667,7 +11698,7 @@
 				unref_peer(peer, "remove register expire ref"));
 
 		destroy_association(peer);
-		
+
 		register_peer_exten(peer, FALSE);	/* Remove extension from regexten= setting in sip.conf */
 		ast_string_field_set(peer, fullcontact, "");
 		ast_string_field_set(peer, useragent, "");
@@ -11688,22 +11719,40 @@
 	ast_string_field_build(pvt, our_contact, "<%s>", curi);
 
 	/* Make sure it's a SIP URL */
-	/*! \todo This code assumes that the Contact is using the same transport as the
-		REGISTER request. That might not be true at all. You can receive
-		sips: requests over any transport. Needs to be fixed.
-		Does not parse the ;transport uri parameter at this point, which might be handy
-		in some situations.
-	*/
 	if (pvt->socket.type == SIP_TRANSPORT_TLS) {
-		if (parse_uri(curi, "sips:", &curi, NULL, &host, &pt, NULL)) {
-			if (parse_uri(curi2, "sip:", &curi, NULL, &host, &pt, NULL))
+		if (parse_uri(curi, "sips:", &curi, NULL, &host, &pt, NULL, &transport)) {
+			if (parse_uri(curi2, "sip:", &curi, NULL, &host, &pt, NULL, &transport))
 				ast_log(LOG_NOTICE, "Not a valid SIP contact (missing sip:) trying to use anyway\n");
 		}
 		port = !ast_strlen_zero(pt) ? atoi(pt) : STANDARD_TLS_PORT;
 	} else {
-		if (parse_uri(curi, "sip:", &curi, NULL, &host, &pt, NULL))
+		if (parse_uri(curi, "sip:", &curi, NULL, &host, &pt, NULL, &transport))
 			ast_log(LOG_NOTICE, "Not a valid SIP contact (missing sip:) trying to use anyway\n");
 		port = !ast_strlen_zero(pt) ? atoi(pt) : STANDARD_SIP_PORT;
+	}
+
+	/* handle the transport type specified in Contact header. */
+	if ((transport_type = get_transport_str2enum(transport))) {
+		/* if the port is not specified but the transport is, make sure to set the
+		 * default port to match the specified transport.  This may or may not be the
+		 * same transport used by the pvt struct for the Register dialog. */
+		if (ast_strlen_zero(pt)) {
+			port = (transport_type == SIP_TRANSPORT_TLS) ? STANDARD_TLS_PORT : STANDARD_SIP_PORT;
+		}
+	} else {
+		transport_type = pvt->socket.type;
+	}
+
+	/* if the peer's socket type is different than the Registration
+	 * 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)) {
+		peer->socket.type = transport_type;
+		peer->socket.fd = -1;
+		if (peer->socket.tcptls_session) {
+			ao2_ref(peer->socket.tcptls_session, -1);
+			peer->socket.tcptls_session = NULL;
+		}
 	}
 
 	oldsin = peer->addr;
@@ -11744,6 +11793,16 @@
 		peer->addr = pvt->recv;
 	}
 
+	/* if the Contact header information copied into peer->addr matches the
+	 * received address, and the transport types are the same, then copy socket
+	 * data into the peer struct */
+	if ((peer->socket.type == pvt->socket.type) &&
+		(peer->addr.sin_addr.s_addr == pvt->recv.sin_addr.s_addr) &&
+		(peer->addr.sin_port == pvt->recv.sin_port)){
+
+		copy_socket_data(&peer->socket, &pvt->socket);
+	}
+
 	/* Now that our address has been updated put ourselves back into the container for lookups */
 	ao2_t_link(peers_by_ip, peer, "ao2_link into peers_by_ip table");
 
@@ -11763,7 +11822,7 @@
 	if (peer->is_realtime && !ast_test_flag(&peer->flags[1], SIP_PAGE2_RTCACHEFRIENDS)) {
 		peer->expire = -1;
 	} else {
-		peer->expire = ast_sched_add(sched, (expire + 10) * 1000, expire_register, 
+		peer->expire = ast_sched_add(sched, (expire + 10) * 1000, expire_register,
 				ref_peer(peer, "add registration ref"));
 		if (peer->expire == -1) {
 			unref_peer(peer, "remote registration ref");
@@ -11775,7 +11834,7 @@
 		XXX WHY???? XXX
 		\todo Fix this immediately.
 	*/
-	if (!peer->rt_fromcontact && (peer->socket.type & SIP_TRANSPORT_UDP)) 
+	if (!peer->rt_fromcontact && (peer->socket.type & SIP_TRANSPORT_UDP))
 		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\nPort: %d\r\n", peer->name,  ast_inet_ntoa(peer->addr.sin_addr), ntohs(peer->addr.sin_port));
 
@@ -13618,12 +13677,12 @@
 	/*! \todo Samme logical error as in many places above. Need a generic function for this.
  	*/
 	if (p->socket.type == SIP_TRANSPORT_TLS) {
-		if (parse_uri(of, "sips:", &of, &dummy, &domain, &dummy, &dummy)) {
-			if (parse_uri(of2, "sip:", &of, &dummy, &domain, &dummy, &dummy))
+		if (parse_uri(of, "sips:", &of, &dummy, &domain, &dummy, &dummy, NULL)) {
+			if (parse_uri(of2, "sip:", &of, &dummy, &domain, &dummy, &dummy, NULL))
 				ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n");
 		}
 	} else {
-		if (parse_uri(of, "sip:", &of, &dummy, &domain, &dummy, &dummy))
+		if (parse_uri(of, "sip:", &of, &dummy, &domain, &dummy, &dummy, NULL))
 			ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n");
 	}
 
@@ -23221,9 +23280,10 @@
 {
 	struct sip_peer *peer = NULL;
 	struct ast_ha *oldha = NULL;
-	int found=0;
-	int firstpass=1;
-	int format=0;		/* Ama flags */
+	int found = 0;
+	int firstpass = 1;
+	int format = 0;		/* Ama flags */
+	int original_transport = 0;
 	time_t regseconds = 0;
 	struct ast_flags peerflags[2] = {{(0)}};
 	struct ast_flags mask[2] = {{(0)}};
@@ -23286,8 +23346,9 @@
 	/* If we have realm authentication information, remove them (reload) */
 	clear_realm_authentication(peer->auth);
 	peer->auth = NULL;
+	original_transport = peer->socket.type;
+	peer->socket.type = 0;
 	peer->transports = 0;
-	peer->socket.type = 0;
 
 	for (; v || ((v = alt) && !(alt=NULL)); v = v->next) {
 		if (handle_common_options(&peerflags[0], &mask[0], v))
@@ -23310,7 +23371,6 @@
 
 				if (!peer->socket.type) { /*!< The first transport listed should be used for outgoing */
 					peer->socket.type = peer->transports;
-					peer->socket.fd = -1;
 				}
 			}
 		} else if (realtime && !strcasecmp(v->name, "regseconds")) {
@@ -23623,7 +23683,24 @@
 		peer->transports = default_transports;
 		/* Set default primary transport */
 		peer->socket.type = default_primary_transport;
+	}
+
+	/* If the original peer socket type before rebuilding the peer is NOT equal to the new one,
+	 * override the new one with the original if a registration is present and the original type
+	 * is still supported by the peer.
+	 *
+	 * The original socket information is used to keep the socket type consistent with what was
+	 * specified during peer Registration.  The default set during build_peer should only be used when a
+	 * registration is not present. */
+	if ((original_transport != peer->socket.type) && ((peer->transports & original_transport)) && (peer->expire > -1)) {
+			peer->socket.type = original_transport;
+	} else if (original_transport != peer->socket.type) {
+		/* if the transport type changes, clear all socket data */
 		peer->socket.fd = -1;
+		if (peer->socket.tcptls_session) {
+			ao2_ref(peer->socket.tcptls_session, -1);
+			peer->socket.tcptls_session = NULL;
+		}
 	}
 
 	if (fullcontact->used > 0) {
@@ -23648,7 +23725,7 @@
 		if ((params = strchr(_srvlookup, ';'))) {
 			*params++ = '\0';
 		}
-		
+
 		snprintf(transport, sizeof(transport), "_sip._%s", get_transport(peer->socket.type));
 
 		if (ast_dnsmgr_lookup(_srvlookup, &peer->addr, &peer->dnsmgr, sip_cfg.srvlookup ? transport : NULL)) {

Modified: team/dvossel/sip_via_tcp_rework/configs/sip.conf.sample
URL: http://svn.asterisk.org/svn-view/asterisk/team/dvossel/sip_via_tcp_rework/configs/sip.conf.sample?view=diff&rev=194284&r1=194283&r2=194284
==============================================================================
--- team/dvossel/sip_via_tcp_rework/configs/sip.conf.sample (original)
+++ team/dvossel/sip_via_tcp_rework/configs/sip.conf.sample Wed May 13 10:03:53 2009
@@ -899,11 +899,14 @@
 ;remotesecret=guessit             ; Our password to their service
 ;defaultuser=yourusername         ; Authentication user for outbound proxies
 ;fromuser=yourusername            ; Many SIP providers require this!
-;fromdomain=provider.sip.domain        
+;fromdomain=provider.sip.domain 
 ;host=box.provider.com
-;transport=udp,tcp                ; This sets the transport type to udp for outgoing, and will
-;                                 ;   accept both tcp and udp. Default is udp. The first transport
-;                                 ;   listed will always be used for outgoing connections.
+;transport=udp,tcp                ; This sets the default transport type to udp for outgoing, and will
+;                                 ; accept both tcp and udp. The default transport type is only used for
+;                                 ; outbound messages until a Registration takes place.  During the
+;                                 ; peer Registration the transport type may change to another supported
+;                                 ; type if the peer requests so.
+
 ;usereqphone=yes                  ; This provider requires ";user=phone" on URI
 ;callcounter=yes                  ; Enable call counter
 ;busylevel=2                      ; Signal busy at 2 or more calls




More information about the asterisk-commits mailing list