[asterisk-commits] russell: trunk r99085 - in /trunk: ./ channels/ configs/ doc/ include/asteris...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Jan 18 16:04:34 CST 2008


Author: russell
Date: Fri Jan 18 16:04:33 2008
New Revision: 99085

URL: http://svn.digium.com/view/asterisk?view=rev&rev=99085
Log:
Merge changes from team/group/sip-tcptls

This set of changes introduces TCP and TLS support for chan_sip.  There are various
new options in configs/sip.conf.sample that are used to enable these features.  Also,
there is a document, doc/siptls.txt that describes some things in more detail.

This code was implemented by Brett Bryant and James Golovich.  It was reviewed
by Joshua Colp and myself.  A number of other people participated in the testing
of this code, but since it was done outside of the bug tracker, I do not have their
names.  If you were one of them, thanks a lot for the help!

(closes issue #4903, but with completely different code that what exists there.)

Added:
    trunk/doc/siptls.txt
      - copied unchanged from r99084, team/group/sip-tcptls/doc/siptls.txt
    trunk/include/asterisk/tcptls.h
      - copied unchanged from r99084, team/group/sip-tcptls/include/asterisk/tcptls.h
    trunk/main/tcptls.c
      - copied unchanged from r99084, team/group/sip-tcptls/main/tcptls.c
Modified:
    trunk/CHANGES
    trunk/CREDITS
    trunk/channels/chan_sip.c
    trunk/configs/sip.conf.sample
    trunk/include/asterisk/http.h
    trunk/main/Makefile
    trunk/main/http.c
    trunk/main/manager.c

Change Statistics:
 trunk/CHANGES                 |    5 
 trunk/CREDITS                 |    7 
 trunk/channels/chan_sip.c     |  791 +++++++++++++++++++++++++-----
 trunk/configs/sip.conf.sample |   16 
 trunk/include/asterisk/http.h |   86 ---
 trunk/main/Makefile           |    2 
 trunk/main/http.c             |  200 -------
 trunk/main/manager.c          |    3 
 8 files changed, 716 insertions(+), 394 deletions(-)

Modified: trunk/CHANGES
URL: http://svn.digium.com/view/asterisk/trunk/CHANGES?view=diff&rev=99085&r1=99084&r2=99085
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Fri Jan 18 16:04:33 2008
@@ -128,6 +128,11 @@
      SIP uri.
   * Added a new global and per-peer option, qualifyfreq, which allows you to configure
      the qualify frequency.
+  * Added SIP Session Timers support (RFC 4028).  This prevents stuck SIP sessions that
+     were not properly torn down due to network or endpoint failures during an established
+     SIP session.
+  * Added TCP and TLS support for SIP.  See doc/siptls.txt and configs/sip.conf.sample for
+     more information on how it is used.
 
 IAX2 changes
 ------------

Modified: trunk/CREDITS
URL: http://svn.digium.com/view/asterisk/trunk/CREDITS?view=diff&rev=99085&r1=99084&r2=99085
==============================================================================
--- trunk/CREDITS (original)
+++ trunk/CREDITS Fri Jan 18 16:04:33 2008
@@ -56,7 +56,7 @@
 	and sip configs.
 	anthmct(AT)yahoo.com              http://www.asterlink.com
 
-James Golovich - Innumerable contributions
+James Golovich - Innumerable contributions, including SIP TCP and TLS support.
 	You can find him and asterisk-perl at http://asterisk.gnuinter.net
 
 Andre Bierwirth - Extension hints and status
@@ -175,6 +175,11 @@
 
 Luigi Rizzo - astobj2, console_video, windows build, chan_oss cleanup,
 	and a bunch of infrastructure work (loader, new_cli, ...)
+
+Brett Bryant - digit option for musiconhold selection, ENUMQUERY and ENUMRESULT functions,
+	feature group configuration for features.conf, per-file CLI debug and verbose settings,
+	TCP and TLS support for SIP, and various bug fixes.
+	brettbryant(AT)gmail.com
 
 === OTHER CONTRIBUTIONS ===
 John Todd - Monkey sounds and associated teletorture prompt

Modified: trunk/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_sip.c?view=diff&rev=99085&r1=99084&r2=99085
==============================================================================
--- trunk/channels/chan_sip.c (original)
+++ trunk/channels/chan_sip.c Fri Jan 18 16:04:33 2008
@@ -175,6 +175,7 @@
 #include "asterisk/translate.h"
 #include "asterisk/version.h"
 #include "asterisk/event.h"
+#include "asterisk/tcptls.h"
 
 #ifndef FALSE
 #define FALSE    0
@@ -574,8 +575,9 @@
 /*! \brief SIP Extensions we support */
 #define SUPPORTED_EXTENSIONS "replaces, timer" 
 
-/*! \brief Standard SIP port from RFC 3261. DO NOT CHANGE THIS */
+/*! \brief Standard SIP and TLS port from RFC 3261. DO NOT CHANGE THIS */
 #define STANDARD_SIP_PORT	5060
+#define STANDARD_TLS_PORT	5061
 /* Note: in many SIP headers, absence of a port number implies port 5060,
  * and this is why we cannot change the above constant.
  * There is a limited number of places in asterisk where we could,
@@ -757,7 +759,23 @@
 #define DEC_CALL_RINGING 2
 #define INC_CALL_RINGING 3
 
-/*! \brief The data grabbed from the UDP socket
+/*!< Define some SIP transports */
+enum sip_transport {
+	SIP_TRANSPORT_UDP = 1,
+	SIP_TRANSPORT_TCP = 1 << 1,
+	SIP_TRANSPORT_TLS = 1 << 2,
+};
+
+struct sip_socket {
+	ast_mutex_t *lock;
+	enum sip_transport type;
+	int fd;
+	uint16_t port;
+	struct server_instance *ser;
+};
+
+/*! \brief sip_request: The data grabbed from the UDP socket
+ *
  * \verbatim
  * Incoming messages: we first store the data from the socket in data[],
  * adding a trailing \0 to make string parsing routines happy.
@@ -795,6 +813,7 @@
 	char *header[SIP_MAX_HEADERS];
 	char *line[SIP_MAX_LINES];
 	char data[SIP_MAX_PACKET];
+	struct sip_socket socket;
 };
 
 /*! \brief structure used in transfers */
@@ -1175,6 +1194,7 @@
 		AST_STRING_FIELD(rpid_from);	/*!< Our RPID From header */
 		AST_STRING_FIELD(url);		/*!< URL to be sent with next message to peer */
 	);
+	struct sip_socket socket;
 	unsigned int ocseq;			/*!< Current outgoing seqno */
 	unsigned int icseq;			/*!< Current incoming seqno */
 	ast_group_t callgroup;			/*!< Call group */
@@ -1397,6 +1417,7 @@
 struct sip_peer {
 	ASTOBJ_COMPONENTS(struct sip_peer);	/*!< name, refcount, objflags,  object pointers */
 					/*!< peer->name is the unique name of this object */
+	struct sip_socket socket;
 	char secret[80];		/*!< Password */
 	char md5secret[80];		/*!< Password in MD5 */
 	struct sip_auth *auth;		/*!< Realm authentication list */
@@ -1500,6 +1521,7 @@
 		AST_STRING_FIELD(callback);	/*!< Contact extension */
 		AST_STRING_FIELD(random);
 	);
+	enum sip_transport transport;
 	int portno;			/*!<  Optional port override */
 	int expire;			/*!< Sched ID of expiration */
 	int expiry;			/*!< Value to use for the Expires header */
@@ -1516,7 +1538,18 @@
 	char lastmsg[256];		/*!< Last Message sent/received */
 };
 
+struct sip_threadinfo {
+	int stop;
+	pthread_t threadid;
+	struct server_instance *ser;
+	enum sip_transport type;	/* We keep a copy of the type here so we can display it in the connection list */
+	AST_LIST_ENTRY(sip_threadinfo) list;
+};
+
 /* --- Linked lists of various objects --------*/
+
+/*! \brief  The thread list of TCP threads */
+static AST_LIST_HEAD_STATIC(threadl, sip_threadinfo);
 
 /*! \brief  The user list: Users and friends */
 static struct ast_user_list {
@@ -1605,6 +1638,8 @@
  */
 static struct ast_ha *localaddr;		/*!< List of local networks, on the same side of NAT as this Asterisk */
 
+static int ourport_tcp;
+static int ourport_tls;
 static struct sockaddr_in debugaddr;
 
 static struct ast_config *notify_types;		/*!< The list of manual NOTIFY types we know how to send */
@@ -1637,6 +1672,10 @@
 static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
 static int sip_senddigit_begin(struct ast_channel *ast, char digit);
 static int sip_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
+
+static int handle_request_do(struct sip_request *req, struct sockaddr_in *sin);
+static int sip_standard_port(struct sip_socket s);
+static int sip_prepare_socket(struct sip_pvt *p);
 
 /*--- Transmitting responses and requests */
 static int sipsock_read(int *id, int fd, short events, void *ignore);
@@ -1811,6 +1850,11 @@
 static void sip_dump_history(struct sip_pvt *dialog);	/* Dump history to debuglog at end of dialog, before destroying data */
 static inline int sip_debug_test_addr(const struct sockaddr_in *addr);
 static inline int sip_debug_test_pvt(struct sip_pvt *p);
+
+
+/*! \brief Append to SIP dialog history 
+	\return Always returns 0 */
+#define append_history(p, event, fmt , args... )	append_history_full(p, "%-15s " fmt, event, ## args)
 static void append_history_full(struct sip_pvt *p, const char *fmt, ...);
 static void sip_dump_history(struct sip_pvt *dialog);
 
@@ -1998,6 +2042,31 @@
  */
 static struct ast_channel_tech sip_tech_info;
 
+static void *sip_tcp_worker_fn(void *);
+
+static struct ast_tls_config sip_tls_cfg;
+static struct ast_tls_config default_tls_cfg;
+
+static struct server_args sip_tcp_desc = {
+	.accept_fd = -1,
+	.master = AST_PTHREADT_NULL,
+	.tls_cfg = NULL,
+	.poll_timeout = -1,
+	.name = "sip tcp server",
+	.accept_fn = server_root,
+	.worker_fn = sip_tcp_worker_fn,
+};
+
+static struct server_args sip_tls_desc = {
+	.accept_fd = -1,
+	.master = AST_PTHREADT_NULL,
+	.tls_cfg = &sip_tls_cfg,
+	.poll_timeout = -1,
+	.name = "sip tls server",
+	.accept_fn = server_root,
+	.worker_fn = sip_tcp_worker_fn,
+};
+
 /* wrapper macro to tell whether t points to one of the sip_tech descriptors */
 #define IS_SIP_TECH(t)  ((t) == &sip_tech || (t) == &sip_tech_info)
 
@@ -2038,6 +2107,119 @@
 	.get_codec = sip_get_codec,
 };
 
+static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct server_instance *ser);
+
+static void *sip_tcp_helper_thread(void *data)
+{
+	struct sip_pvt *pvt = data;
+	struct server_instance *ser = pvt->socket.ser;
+
+	return _sip_tcp_helper_thread(pvt, ser);
+}
+
+static void *sip_tcp_worker_fn(void *data)
+{
+	struct server_instance *ser = data;
+
+	return _sip_tcp_helper_thread(NULL, ser);
+}
+
+/*! \brief SIP TCP helper function */
+static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct server_instance *ser) 
+{
+	int res, cl;
+	struct sip_request req = { 0, } , reqcpy = { 0, };
+	struct sip_threadinfo *me;
+	char buf[1024];
+
+	me = ast_calloc(1, sizeof(*me));
+
+	if (!me)
+		goto cleanup2;
+
+	me->threadid = pthread_self();
+	me->ser = ser;
+	if (ser->ssl)
+		me->type = SIP_TRANSPORT_TLS;
+	else
+		me->type = SIP_TRANSPORT_TCP;
+
+	AST_LIST_LOCK(&threadl);
+	AST_LIST_INSERT_TAIL(&threadl, me, list);
+	AST_LIST_UNLOCK(&threadl);
+
+	req.socket.lock = ast_calloc(1, sizeof(*req.socket.lock));
+
+	if (!req.socket.lock)
+		goto cleanup;
+
+	ast_mutex_init(req.socket.lock);
+
+	for (;;) {
+		memset(req.data, 0, sizeof(req.data));
+		req.len = 0;
+		req.ignore = 0;
+
+		req.socket.fd = ser->fd;
+		if (ser->ssl) {
+			req.socket.type = SIP_TRANSPORT_TLS;
+			req.socket.port = htons(ourport_tls);
+		} else {
+			req.socket.type = SIP_TRANSPORT_TCP;
+			req.socket.port = htons(ourport_tcp);
+		}
+		res = ast_wait_for_input(ser->fd, -1);
+		if (res < 0) {
+			ast_log(LOG_DEBUG, "ast_wait_for_input returned %d\n", res);
+			goto cleanup;
+		}
+
+		/* Read in headers one line at a time */
+		while (req.len < 4 || strncmp((char *)&req.data + req.len - 4, "\r\n\r\n", 4)) {
+			if (req.socket.lock) 
+				ast_mutex_lock(req.socket.lock);
+			if (!fgets(buf, sizeof(buf), ser->f))
+				goto cleanup;
+			if (req.socket.lock) 
+				ast_mutex_unlock(req.socket.lock);
+			if (me->stop) 
+				 goto cleanup;
+			strncat(req.data, buf, sizeof(req.data) - req.len);
+			req.len = strlen(req.data);
+		}
+		parse_copy(&reqcpy, &req);
+		if (sscanf(get_header(&reqcpy, "Content-Length"), "%d", &cl)) {
+			while (cl > 0) {
+				if (req.socket.lock) 
+					ast_mutex_lock(req.socket.lock);
+				if (!fread(buf, (cl < sizeof(buf)) ? cl : sizeof(buf), 1, ser->f))
+					goto cleanup;
+				if (req.socket.lock) 
+					ast_mutex_unlock(req.socket.lock);
+				if (me->stop)
+					goto cleanup;
+				cl -= strlen(buf);
+				strncat(req.data, buf, sizeof(req.data) - req.len);
+				req.len = strlen(req.data);
+			}
+		}
+		req.socket.ser = ser;
+		handle_request_do(&req, &ser->requestor);
+	}
+
+cleanup:
+	AST_LIST_LOCK(&threadl);
+	AST_LIST_REMOVE(&threadl, me, list);
+	AST_LIST_UNLOCK(&threadl);
+	ast_free(me);
+cleanup2:
+	fclose(ser->f);
+	ast_free(ser);
+	ast_free(req.socket.lock);
+
+	return NULL;
+}
+
 #define sip_pvt_lock(x) ast_mutex_lock(&x->pvt_lock)
 #define sip_pvt_unlock(x) ast_mutex_unlock(&x->pvt_lock)
 
@@ -2076,10 +2258,6 @@
 	get_udptl_info: sip_get_udptl_peer,
 	set_udptl_peer: sip_set_udptl_peer,
 };
-
-/*! \brief Append to SIP dialog history 
-	\return Always returns 0 */
-#define append_history(p, event, fmt , args... )	append_history_full(p, "%-15s " fmt, event, ## args)
 
 static void append_history_full(struct sip_pvt *p, const char *fmt, ...)
 	__attribute__ ((format (printf, 2, 3)));
@@ -2283,12 +2461,45 @@
 	return sip_debug_test_addr(sip_real_dst(p));
 }
 
+static inline const char *get_transport(enum sip_transport t)
+{
+	switch (t) {
+	case SIP_TRANSPORT_UDP:
+		return "UDP";
+	case SIP_TRANSPORT_TCP:
+		return "TCP";
+	case SIP_TRANSPORT_TLS:
+		return "TLS";
+	}
+
+	return "UNKNOWN";
+}
+
 /*! \brief Transmit SIP message */
 static int __sip_xmit(struct sip_pvt *p, char *data, int len)
 {
-	int res;
+	int res = 0;
 	const struct sockaddr_in *dst = sip_real_dst(p);
-	res = sendto(sipsock, data, len, 0, (const struct sockaddr *)dst, sizeof(struct sockaddr_in));
+
+	ast_log(LOG_DEBUG, "Trying to put '%.10s' onto %s socket...\n", data, get_transport(p->socket.type));
+
+	if (sip_prepare_socket(p) < 0)
+		return XMIT_ERROR;
+
+	if (p->socket.lock)
+		ast_mutex_lock(p->socket.lock);
+
+	if (p->socket.type & SIP_TRANSPORT_UDP) 
+		res = sendto(p->socket.fd, data, len, 0, (const struct sockaddr *)dst, sizeof(struct sockaddr_in));
+	else {
+		if (p->socket.ser->f) 
+			res = server_write(p->socket.ser, data, len);
+		else
+			ast_log(LOG_DEBUG, "No p->socket.ser->f len=%d\n", len);
+	} 
+
+	if (p->socket.lock)
+		ast_mutex_unlock(p->socket.lock);
 
 	if (res == -1) {
 		switch (errno) {
@@ -2301,9 +2512,9 @@
 	}
 	if (res != len)
 		ast_log(LOG_WARNING, "sip_xmit of %p (len %d) to %s:%d returned %d: %s\n", data, len, ast_inet_ntoa(dst->sin_addr), ntohs(dst->sin_port), res, strerror(errno));
+
 	return res;
 }
-
 
 /*! \brief Build a Via header for a request */
 static void build_via(struct sip_pvt *p)
@@ -2312,7 +2523,8 @@
 	const char *rport = ast_test_flag(&p->flags[0], SIP_NAT) & SIP_NAT_RFC3581 ? ";rport" : "";
 
 	/* z9hG4bK is a magic cookie.  See RFC 3261 section 8.1.1.7 */
-	ast_string_field_build(p, via, "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x%s",
+	ast_string_field_build(p, via, "SIP/2.0/%s %s:%d;branch=z9hG4bK%08x%s",
+			get_transport(p->socket.type),
 			ast_inet_ntoa(p->ourip.sin_addr),
 			ntohs(p->ourip.sin_port), p->branch, rport);
 }
@@ -2543,9 +2755,21 @@
 */
 static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, char *data, int len, int fatal, int sipmethod)
 {
-	struct sip_pkt *pkt;
+	struct sip_pkt *pkt = NULL;
 	int siptimer_a = DEFAULT_RETRANS;
 	int xmitres = 0;
+
+	/* If the transport is something reliable (TCP or TLS) then don't really send this reliably */
+	/* I removed the code from retrans_pkt that does the same thing so it doesn't get loaded into the scheduler */
+	/* According to the RFC some packets need to be retransmitted even if its TCP, so this needs to get revisited */
+	if (!(p->socket.type & SIP_TRANSPORT_UDP)) {
+		xmitres = __sip_xmit(dialog_ref(p), data, len);	/* Send packet */
+		if (xmitres == XMIT_ERROR) {	/* Serious network trouble, no need to try again */
+			append_history(p, "XmitErr", "%s", fatal ? "(Critical)" : "(Non-critical)");
+			return AST_FAILURE;
+		} else
+			return AST_SUCCESS;
+	}
 
 	if (!(pkt = ast_calloc(1, sizeof(*pkt) + len + 1)))
 		return AST_FAILURE;
@@ -2893,6 +3117,7 @@
 			ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", tmp);
 		}
 	}
+	
 	return tmp;
 }
 
@@ -2929,7 +3154,7 @@
 		if (!strncasecmp(uri, scheme, l))
 			uri += l;
 		else {
-			ast_log(LOG_NOTICE, "Missing scheme '%s' in '%s'\n", scheme, uri);
+			ast_debug(1, "Missing scheme '%s' in '%s'\n", scheme, uri);
 			error = -1;
 		}
 	}
@@ -3542,6 +3767,8 @@
  */
 static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
 {
+	dialog->socket = peer->socket;
+
 	if ((peer->addr.sin_addr.s_addr || peer->defaddr.sin_addr.s_addr) &&
 	    (!peer->maxms || ((peer->lastms >= 0)  && (peer->lastms <= peer->maxms)))) {
 		dialog->sa = (peer->addr.sin_addr.s_addr) ? peer->addr : peer->defaddr;
@@ -3701,13 +3928,13 @@
    	   then hostname lookup */
 
 	hostn = peername;
-	portno = port ? atoi(port) : STANDARD_SIP_PORT;
+	portno = port ? atoi(port) : (dialog->socket.type & SIP_TRANSPORT_TLS) ? STANDARD_TLS_PORT : STANDARD_SIP_PORT;
 	if (global_srvlookup) {
 		char service[MAXHOSTNAMELEN];
 		int tportno;
 		int ret;
 
-		snprintf(service, sizeof(service), "_sip._udp.%s", peername);
+		snprintf(service, sizeof(service), "_sip._%s.%s", get_transport(dialog->socket.type), peername);
 		ret = ast_get_srv(NULL, host, sizeof(host), &tportno, service);
 		if (ret > 0) {
 			hostn = host;
@@ -3825,6 +4052,7 @@
 
 		p->t38.jointcapability = p->t38.capability;
 		ast_debug(2,"Our T38 capability (%d), joint T38 capability (%d)\n", p->t38.capability, p->t38.jointcapability);
+
 		xmitres = transmit_invite(p, SIP_INVITE, 1, 2);
 		if (xmitres == XMIT_ERROR)
 			return -1;
@@ -5284,6 +5512,8 @@
 
 	ast_mutex_init(&p->pvt_lock);
 
+	p->socket.fd = -1;
+	p->socket.type = SIP_TRANSPORT_UDP;
 	p->method = intended_method;
 	p->initid = -1;
 	p->waitid = -1;
@@ -5539,14 +5769,40 @@
 {
 	struct sip_registry *reg;
 	int portnum = 0;
-	char username[256] = "";
+	enum sip_transport transport = SIP_TRANSPORT_UDP;
+	char buf[256] = "";
+	char *username = NULL;
 	char *hostname=NULL, *secret=NULL, *authuser=NULL;
 	char *porta=NULL;
 	char *callback=NULL;
+	char *trans=NULL;
 
 	if (!value)
 		return -1;
-	ast_copy_string(username, value, sizeof(username));
+
+	ast_copy_string(buf, value, sizeof(buf));
+
+	username = strstr(buf, "://");
+
+	if (username) {
+		*username = '\0';
+		username += 3;
+
+		trans = buf;
+
+		if (!strcasecmp(trans, "udp"))
+			transport = SIP_TRANSPORT_UDP;
+		else if (!strcasecmp(trans, "tcp"))
+			transport = SIP_TRANSPORT_TCP;
+		else if (!strcasecmp(trans, "tls"))
+			transport = SIP_TRANSPORT_TLS;
+		else
+			ast_log(LOG_WARNING, "'%s' is not a valid transport value for registration '%s' at line '%d'\n", trans, value, lineno);
+	} else {
+		username = buf;
+		ast_log(LOG_DEBUG, "no trans\n");
+	}
+
 	/* First split around the last '@' then parse the two components. */
 	hostname = strrchr(username, '@'); /* allow @ in the first part */
 	if (hostname)
@@ -5600,6 +5856,7 @@
 		ast_string_field_set(reg, authuser, authuser);
 	if (secret)
 		ast_string_field_set(reg, secret, secret);
+	reg->transport = transport;
 	reg->expire = -1;
 	reg->expiry = default_expiry;
 	reg->timeout =  -1;
@@ -7045,6 +7302,12 @@
 	build_via(p);
 	ast_string_field_set(p, callid, callid);
 
+	p->socket.lock = req->socket.lock;
+	p->socket.type = req->socket.type;
+	p->socket.fd = req->socket.fd;
+	p->socket.port = req->socket.port;
+	p->socket.ser = req->socket.ser;
+
 	/* Use this temporary pvt structure to send the message */
 	__transmit_response(p, msg, req, XMIT_UNRELIABLE);
 
@@ -7933,10 +8196,13 @@
 static void build_contact(struct sip_pvt *p)
 {
 	/* Construct Contact: header */
-	if (ntohs(p->ourip.sin_port) != STANDARD_SIP_PORT)
-		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), ntohs(p->ourip.sin_port));
-	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));
+	if (p->socket.type & SIP_TRANSPORT_UDP) {
+		if (!sip_standard_port(p->socket))
+			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), ntohs(p->socket.port));
+		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 
+		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), ntohs(p->socket.port), get_transport(p->socket.type));
 }
 
 /*! \brief Build the Remote Party-ID & From using callingpres options */
@@ -8085,8 +8351,8 @@
 		l = tmp_l;
 	}
 
-	if (ntohs(p->ourip.sin_port) != STANDARD_SIP_PORT && ast_strlen_zero(p->fromdomain))
-		snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s:%d>;tag=%s", n, l, S_OR(p->fromdomain, ast_inet_ntoa(p->ourip.sin_addr)), ntohs(p->ourip.sin_port), p->tag);
+	if (!sip_standard_port(p->socket) && ast_strlen_zero(p->fromdomain))
+		snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s:%d>;tag=%s", n, l, S_OR(p->fromdomain, ast_inet_ntoa(p->ourip.sin_addr)), ntohs(p->socket.port), p->tag);
 	else
 		snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s>;tag=%s", n, l, S_OR(p->fromdomain, ast_inet_ntoa(p->ourip.sin_addr)), p->tag);
 
@@ -8367,7 +8633,7 @@
 
 	ast_copy_string(from, get_header(&p->initreq, "From"), sizeof(from));
 	c = get_in_brackets(from);
-	if (strncasecmp(c, "sip:", 4)) {
+	if (strncasecmp(c, "sip:", 4) && strncasecmp(c, "sips:", 5)) {
 		ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", c);
 		return -1;
 	}
@@ -8376,7 +8642,7 @@
 
 	ast_copy_string(to, get_header(&p->initreq, "To"), sizeof(to));
 	c = get_in_brackets(to);
-	if (strncasecmp(c, "sip:", 4)) {
+	if (strncasecmp(c, "sip:", 4) && strncasecmp(c, "sips:", 5)) {
 		ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", c);
 		return -1;
 	}
@@ -8682,6 +8948,7 @@
 			ast_log(LOG_WARNING, "Unable to allocate registration transaction (memory or socket error)\n");
 			return 0;
 		}
+		
 		if (p->do_history)
 			append_history(p, "RegistryInit", "Account: %s@%s", r->username, r->hostname);
 
@@ -8733,6 +9000,9 @@
 		if (!ast_strlen_zero(r->callback))
 			ast_string_field_set(p, exten, r->callback);
 
+		/* Set transport and port so the correct contact is built */
+		p->socket.type = r->transport;
+		p->socket.port = htons(r->portno);
 		/*
 		  check which address we should use in our contact header 
 		  based on whether the remote host is on the external or
@@ -8838,6 +9108,7 @@
 	r->regstate = auth ? REG_STATE_AUTHSENT : REG_STATE_REGSENT;
 	r->regattempts++;	/* Another attempt */
 	ast_debug(4, "REGISTER attempt %d to %s@%s\n", r->regattempts, r->username, r->hostname);
+
 	return send_request(p, &req, XMIT_CRITICAL, p->ocseq);
 }
 
@@ -8892,10 +9163,12 @@
 	ast_copy_string(from, of, sizeof(from));
 	of = get_in_brackets(from);
 	ast_string_field_set(p, from, of);
-	if (strncasecmp(of, "sip:", 4))
-		ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n");
+	if (!strncasecmp(of, "sip:", 4))
+		of += 4;
+	else if (!strncasecmp(of, "sips:", 5))
+		of += 5;
 	else
-		of += 4;
+		ast_log(LOG_NOTICE, "From address missing 'sip(s):', using it anyway\n");
 	/* Get just the username part */
 	if ((c = strchr(dest, '@')))
 		c = NULL;
@@ -9148,7 +9421,7 @@
 	ast_string_field_set(pvt, okcontacturi, c);
 
 	/* We should return false for URI:s we can't handle,
-		like sips:, tel:, mailto:,ldap: etc */
+		like tel:, mailto:,ldap: etc */
 	return TRUE;		
 }
 
@@ -9159,7 +9432,7 @@
 	struct ast_hostent ahp;
 	int port;
 	char *host, *pt;
-	char *contact;
+	char *contact, *contact2;
 
 
 	if (ast_test_flag(&pvt->flags[0], SIP_NAT_ROUTE)) {
@@ -9172,11 +9445,21 @@
 
 	/* Work on a copy */
 	contact = ast_strdupa(pvt->fullcontact);
+	contact2 = ast_strdupa(pvt->fullcontact);
 	/* We have only the part in <brackets> here so we just need to parse a SIP URI.*/
 
-	if (parse_uri(contact, "sip:", &contact, NULL, &host, &pt, 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;
+	if (pvt->socket.type == SIP_TRANSPORT_TLS) {
+		if (parse_uri(contact, "sips:", &contact, NULL, &host, &pt, NULL)) {
+			if (parse_uri(contact2, "sip:", &contact, NULL, &host, &pt, 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;
+	} else {
+		if (parse_uri(contact, "sip:", &contact, NULL, &host, &pt, 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;
+	}
+
 	ast_verbose("--- set_address_from_contact host '%s'\n", host);
 
 	/* XXX This could block for a long time XXX */
@@ -9201,7 +9484,7 @@
 	char data[BUFSIZ];
 	const char *expires = get_header(req, "Expires");
 	int expiry = atoi(expires);
-	char *curi, *host, *pt;
+	char *curi, *host, *pt, *curi2;
 	int port;
 	const char *useragent;
 	struct hostent *hp;
@@ -9222,11 +9505,14 @@
 		}
 	}
 
+	pvt->socket = peer->socket = req->socket;
+
 	/* Look for brackets */
 	curi = contact;
 	if (strchr(contact, '<') == NULL)	/* No <, check for ; and strip it */
 		strsep(&curi, ";");	/* This is Header options, not URI options */
 	curi = get_in_brackets(contact);
+	curi2 = ast_strdupa(curi);
 
 	/* if they did not specify Contact: or Expires:, they are querying
 	   what we currently have stored as their contact address, so return
@@ -9264,9 +9550,18 @@
 	ast_string_field_build(pvt, our_contact, "<%s>", curi);
 
 	/* Make sure it's a SIP URL */
-	if (parse_uri(curi, "sip:", &curi, NULL, &host, &pt, NULL))
-		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;
+	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))
+				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))
+			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;
+	}
+
 	oldsin = peer->addr;
 	if (!ast_test_flag(&peer->flags[0], SIP_NAT_ROUTE)) {
 		/* XXX This could block for a long time XXX */
@@ -9302,7 +9597,8 @@
 		ast_sched_add(sched, (expiry + 10) * 1000, expire_register, peer);
 	pvt->expiry = expiry;
 	snprintf(data, sizeof(data), "%s:%d:%d:%s:%s", ast_inet_ntoa(peer->addr.sin_addr), ntohs(peer->addr.sin_port), expiry, peer->username, peer->fullcontact);
-	if (!peer->rt_fromcontact) 
+	/* Saving TCP connections is useless, we won't be able to reconnect */
+	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\n", peer->name);
 
@@ -9738,6 +10034,8 @@
 
 	if (!strncasecmp(c, "sip:", 4)) {
 		name = c + 4;
+	} else if (!strncasecmp(c, "sips:", 5)) {
+		name = c + 5;
 	} else {
 		name = c;
 		ast_log(LOG_NOTICE, "Invalid to address: '%s' from %s (missing sip:) trying to use anyway...\n", c, ast_inet_ntoa(sin->sin_addr));
@@ -9775,6 +10073,7 @@
 		} else
 			res = AUTH_NOT_FOUND;
 	}
+
 	if (peer) {
 		/* Set Frame packetization */
 		if (p->rtp) {
@@ -9928,11 +10227,14 @@
 		return 0;
 
 	exten = get_in_brackets(tmp);
-	if (strncasecmp(exten, "sip:", 4)) {
+	if (!strncasecmp(exten, "sip:", 4)) {
+		exten += 4;
+	} else if (!strncasecmp(exten, "sips:", 5)) {
+		exten += 5;
+	} else {
 		ast_log(LOG_WARNING, "Huh?  Not an RDNIS SIP header (%s)?\n", exten);
 		return -1;
 	}
-	exten += 4;
 
 	/* Get diversion-reason param if present */
 	if ((params = strchr(tmp, ';'))) {
@@ -9996,12 +10298,15 @@
 		ast_uri_decode(tmp);
 
 	uri = get_in_brackets(tmp);
-
-	if (strncasecmp(uri, "sip:", 4)) {
+	
+	if (!strncasecmp(uri, "sip:", 4)) {
+		uri += 4;
+	} else if (!strncasecmp(uri, "sips:", 5)) {
+		uri += 5;
+	} else {
 		ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", uri);
 		return -1;
 	}
-	uri += 4;
 
 	/* Now find the From: caller ID and name */
 	/* XXX Why is this done in get_destination? Isn't it already done?
@@ -10015,11 +10320,14 @@
 	} 
 	
 	if (!ast_strlen_zero(from)) {
-		if (strncasecmp(from, "sip:", 4)) {
+		if (!strncasecmp(from, "sip:", 4)) {
+			from += 4;
+		} else if (!strncasecmp(from, "sips:", 5)) {
+			from += 5;
+		} else {
 			ast_log(LOG_WARNING, "Huh?  Not a SIP header (%s)?\n", from);
 			return -1;
 		}
-		from += 4;
 		if ((a = strchr(from, '@')))
 			*a++ = '\0';
 		else
@@ -10188,11 +10496,14 @@
 	if (pedanticsipchecking)
 		ast_uri_decode(refer_to);
 
-	if (strncasecmp(refer_to, "sip:", 4)) {
+	if (!strncasecmp(refer_to, "sip:", 4)) {
+		refer_to += 4;			/* Skip sip: */
+	} else if (!strncasecmp(refer_to, "sips:", 5)) {
+		refer_to += 5;
+	} else {
 		ast_log(LOG_WARNING, "Can't transfer to non-sip: URI.  (Refer-to: %s)?\n", refer_to);
 		return -3;
 	}
-	refer_to += 4;			/* Skip sip: */
 
 	/* Get referred by header if it exists */
 	p_referred_by = get_header(req, "Referred-By");
@@ -10219,11 +10530,13 @@
 		}
 
 		referred_by_uri = get_in_brackets(h_referred_by);
-		if(strncasecmp(referred_by_uri, "sip:", 4)) {
+		if (!strncasecmp(referred_by_uri, "sip:", 4)) {
+			referred_by_uri += 4;		/* Skip sip: */
+		} else if (!strncasecmp(referred_by_uri, "sips:", 5)) {
+			referred_by_uri += 5;		/* Skip sips: */
+		} else {
 			ast_log(LOG_WARNING, "Huh?  Not a sip: header (Referred-by: %s). Skipping.\n", referred_by_uri);
 			referred_by_uri = NULL;
-		} else {
-			referred_by_uri += 4;		/* Skip sip: */
 		}
 	}
 
@@ -10348,12 +10661,16 @@
 
 	if (pedanticsipchecking)
 		ast_uri_decode(c);
-	
-	if (strncasecmp(c, "sip:", 4)) {
+
+	if (!strncasecmp(c, "sip:", 4)) {
+		c += 4;
+	} else if (!strncasecmp(c, "sips:", 5)) {
+		c += 5;
+	} else {
 		ast_log(LOG_WARNING, "Huh?  Not a SIP header in Also: transfer (%s)?\n", c);
 		return -1;
 	}
-	c += 4;
+
 	if ((a = strchr(c, ';'))) 	/* Remove arguments */
 		*a = '\0';
 	
@@ -10457,7 +10774,7 @@
 	if (c) {
 		*c = '\0';
 		c = ast_skip_blanks(c+1);
-		if (strcasecmp(via, "SIP/2.0/UDP")) {
+		if (strcasecmp(via, "SIP/2.0/UDP") && strcasecmp(via, "SIP/2.0/TCP") && strcasecmp(via, "SIP/2.0/TLS")) {
 			ast_log(LOG_WARNING, "Don't know how to respond via '%s'\n", via);
 			return;
 		}
@@ -10840,7 +11157,7 @@
 	char from[256];
 	char *dummy;	/* dummy return value for parse_uri */
 	char *domain;	/* dummy return value for parse_uri */
-	char *of;
+	char *of, *of2;
 	char rpid_num[50];
 	const char *rpid;
 	enum check_auth_result res;
@@ -10868,6 +11185,8 @@
 		char *t = uri2;
 		if (!strncasecmp(t, "sip:", 4))
 			t+= 4;
+		else if (!strncasecmp(t, "sips:", 5))
+			t += 5;
 		ast_string_field_set(p, exten, t);
 		t = strchr(p->exten, '@');
 		if (t)
@@ -10878,10 +11197,19 @@
 	/* save the URI part of the From header */
 	ast_string_field_set(p, from, of);
 
+	of2 = ast_strdupa(of);
+
 	/* ignore all fields but name */
-	if (parse_uri(of, "sip:", &of, &dummy, &domain, &dummy, &dummy)) {
-		ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n");
-	}
+	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))
+				ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n");
+		}
+	} else {
+		if (parse_uri(of, "sip:", &of, &dummy, &domain, &dummy, &dummy))
+			ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n");
+	}
+
 	if (ast_strlen_zero(of)) {
 		/* XXX note: the original code considered a missing @host
 		 * as a username-only URI. The SIP RFC (19.1.1) says that
@@ -11026,7 +11354,7 @@
 /*! \brief  CLI Command to show calls within limits set by call_limit */
 static char *sip_show_inuse(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-#define FORMAT  "%-25.25s %-15.15s %-15.15s \n"
+#define FORMAT "%-25.25s %-15.15s %-15.15s \n"
 #define FORMAT2 "%-25.25s %-15.15s %-15.15s \n"
 	char ilimits[40];
 	char iused[40];
@@ -11082,6 +11410,7 @@
 #undef FORMAT2
 }
 
+
 /*! \brief Convert transfer mode to text string */
 static char *transfermode2str(enum transfermodes mode)
 {
@@ -11179,6 +11508,43 @@
 static const char *cli_yesno(int x)
 {
 	return x ? "Yes" : "No";
+}
+
+/*! \brief  Show active TCP connections */
+static char *sip_show_tcp(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct sip_threadinfo *th;
+
+#define FORMAT2 "%-30.30s %3.6s %9.9s %6.6s\n"
+#define FORMAT  "%-30.30s %-6d %-9.9s %-6.6s\n"
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "sip show tcp";
+		e->usage =
+			"Usage: sip show tcp\n"
+			"       Lists all active TCP/TLS sessions.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != 3)
+		return CLI_SHOWUSAGE;
+
+	ast_cli(a->fd, FORMAT2, "Host", "Port", "Transport", "Type");
+	AST_LIST_LOCK(&threadl);
+	AST_LIST_TRAVERSE(&threadl, th, list) {
+		ast_cli(a->fd, FORMAT, ast_inet_ntoa(th->ser->requestor.sin_addr), 
+			ntohs(th->ser->requestor.sin_port), 
+			get_transport(th->type), 
+			(th->ser->client ? "Client" : "Server"));
+
+	}
+	AST_LIST_UNLOCK(&threadl);
+	return CLI_SUCCESS;
+#undef FORMAT
+#undef FORMAT2
 }
 
 /*! \brief  CLI Command 'SIP Show Users' */
@@ -11960,6 +12326,7 @@
 		ast_cli(fd, "  ToHost       : %s\n", peer->tohost);
 		ast_cli(fd, "  Addr->IP     : %s Port %d\n",  peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)", ntohs(peer->addr.sin_port));
 		ast_cli(fd, "  Defaddr->IP  : %s Port %d\n", ast_inet_ntoa(peer->defaddr.sin_addr), ntohs(peer->defaddr.sin_port));
+		ast_cli(fd, "  Transport    : %s\n", get_transport(peer->socket.type));
 		if (!ast_strlen_zero(global_regcontext))
 			ast_cli(fd, "  Reg. exten   : %s\n", peer->regexten);
 		ast_cli(fd, "  Def. Username: %s\n", peer->username);
@@ -13755,6 +14122,8 @@
 	if (ast_test_flag(&p->flags[0], SIP_PROMISCREDIR)) {
 		if (!strncasecmp(s, "sip:", 4))
 			s += 4;
+		else if (!strncasecmp(s, "sips:", 5))
+			s += 5;
 		e = strchr(s, '/');
 		if (e)
 			*e = '\0';
@@ -13776,6 +14145,8 @@
 
 		if (!strncasecmp(s, "sip:", 4))
 			s += 4;
+		else if (!strncasecmp(s, "sips:", 5))
+			s += 5;
 		e = strchr(s, ';');	/* And username ; parameters? */
 		if (e)
 			*e = '\0';	
@@ -15106,7 +15477,7 @@
 			ast_softhangup_nolock(transferer->chan1, AST_SOFTHANGUP_DEV);
 		if (target->chan1)
 			ast_softhangup_nolock(target->chan1, AST_SOFTHANGUP_DEV);
-		return -2;
+		return -1;
 	}
 	return 0;
 }
@@ -16203,7 +16574,6 @@
 		/* Failed transfer */
 		transmit_notify_with_sipfrag(transferer, seqno, "486 Busy Here", TRUE);
 		append_history(transferer, "Xfer", "Refer failed");
-		transferer->refer->status = REFER_FAILED;
 		if (targetcall_pvt->owner)
 			ast_channel_unlock(targetcall_pvt->owner);
 		/* Right now, we have to hangup, sorry. Bridge is destroyed */
@@ -17362,15 +17732,11 @@
 {
 	struct sip_request req;
 	struct sockaddr_in sin = { 0, };
-	struct sip_pvt *p;
 	int res;
 	socklen_t len = sizeof(sin);
-	int nounlock;
-	int recount = 0;
-	int lockretry;
 
 	memset(&req, 0, sizeof(req));
-	res = recvfrom(sipsock, req.data, sizeof(req.data) - 1, 0, (struct sockaddr *)&sin, &len);
+	res = recvfrom(fd, req.data, sizeof(req.data) - 1, 0, (struct sockaddr *)&sin, &len);
 	if (res < 0) {
 #if !defined(__FreeBSD__)
 		if (errno == EAGAIN)
@@ -17387,20 +17753,42 @@
 	} else
 		req.data[res] = '\0';
 	req.len = res;
-	if(sip_debug_test_addr(&sin))	/* Set the debug flag early on packet level */
-		req.debug = 1;
+
+	req.socket.fd 	= sipsock;
+	req.socket.type = SIP_TRANSPORT_UDP;
+	req.socket.ser	= NULL;
+	req.socket.port = htons(bindaddr.sin_port);
+	req.socket.lock = NULL;
+
+	handle_request_do(&req, &sin);
+
+	return 1;
+}
+
+static int handle_request_do(struct sip_request *req, struct sockaddr_in *sin) 
+{
+	struct sip_pvt *p;
+	int recount = 0;
+	int nounlock = 0;
+	int lockretry;
+
+	if (sip_debug_test_addr(sin))	/* Set the debug flag early on packet level */
+		req->debug = 1;
 	if (pedanticsipchecking)
-		req.len = lws2sws(req.data, req.len);	/* Fix multiline headers */
-	if (req.debug)
-		ast_verbose("\n<--- SIP read from %s:%d --->\n%s\n<------------->\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), req.data);
-
-	parse_request(&req);
-	req.method = find_sip_method(req.rlPart1);
-
-	if (req.debug)
-		ast_verbose("--- (%d headers %d lines)%s ---\n", req.headers, req.lines, (req.headers + req.lines == 0) ? " Nat keepalive" : "");
-
-	if (req.headers < 2)	/* Must have at least two headers */
+		req->len = lws2sws(req->data, req->len);	/* Fix multiline headers */
+	if (req->debug) {
+		ast_verbose("\n<--- SIP read from %s://%s:%d --->\n%s\n<------------->\n", 
+			get_transport(req->socket.type), ast_inet_ntoa(sin->sin_addr), 
+			ntohs(sin->sin_port), req->data);
+	}
+
+	parse_request(req);
+	req->method = find_sip_method(req->rlPart1);
+
+	if (req->debug)
+		ast_verbose("--- (%d headers %d lines)%s ---\n", req->headers, req->lines, (req->headers + req->lines == 0) ? " Nat keepalive" : "");
+
+	if (req->headers < 2)	/* Must have at least two headers */
 		return 1;
 
 	/* Process request, with netlock held, and with usual deadlock avoidance */
@@ -17408,12 +17796,15 @@
 		ast_mutex_lock(&netlock);
 
 		/* Find the active SIP dialog or create a new one */
-		p = find_call(&req, &sin, req.method);	/* returns p locked */
+		p = find_call(req, sin, req->method);	/* returns p locked */
 		if (p == NULL) {
-			ast_debug(1, "Invalid SIP message - rejected , no callid, len %d\n", req.len);
+			ast_debug(1, "Invalid SIP message - rejected , no callid, len %d\n", req->len);
 			ast_mutex_unlock(&netlock);
 			return 1;
 		}
+
+		p->socket = req->socket;
+
 		/* Go ahead and lock the owner if it has one -- we may need it */
 		/* becaues this is deadlock-prone, we need to try and unlock if failed */
 		if (!p->owner || !ast_channel_trylock(p->owner))
@@ -17424,35 +17815,117 @@
 		/* Sleep for a very short amount of time */
 		usleep(1);
 	}
-	p->recv = sin;
+	p->recv = *sin;
 
 	if (p->do_history) /* This is a request or response, note what it was for */
-		append_history(p, "Rx", "%s / %s / %s", req.data, get_header(&req, "CSeq"), req.rlPart2);
+		append_history(p, "Rx", "%s / %s / %s", req->data, get_header(req, "CSeq"), req->rlPart2);
 
 	if (!lockretry) {
 		if (p->owner)
 			ast_log(LOG_ERROR, "We could NOT get the channel lock for %s! \n", S_OR(p->owner->name, "- no channel name ??? - "));
 		ast_log(LOG_ERROR, "SIP transaction failed: %s \n", p->callid);
-		if (req.method != SIP_ACK)
-			transmit_response(p, "503 Server error", &req);	/* We must respond according to RFC 3261 sec 12.2 */
+		if (req->method != SIP_ACK)
+			transmit_response(p, "503 Server error", req);	/* We must respond according to RFC 3261 sec 12.2 */
 		/* XXX We could add retry-after to make sure they come back */
 		append_history(p, "LockFail", "Owner lock failed, transaction failed.");
 		return 1;
 	}
+
 	nounlock = 0;
-	if (handle_incoming(p, &req, &sin, &recount, &nounlock) == -1) {
+	if (handle_incoming(p, req, sin, &recount, &nounlock) == -1) {
 		/* Request failed */
 		ast_debug(1, "SIP message could not be handled, bad request: %-70.70s\n", p->callid[0] ? p->callid : "<no callid>");
 	}
 		
+	if (recount)
+		ast_update_use_count();
+
 	if (p->owner && !nounlock)
 		ast_channel_unlock(p->owner);
 	sip_pvt_unlock(p);
 	ast_mutex_unlock(&netlock);
-	if (recount)
-		ast_update_use_count();
 
 	return 1;
+}
+

[... 785 lines stripped ...]



More information about the asterisk-commits mailing list