[svn-commits] mnicholson: branch 1.4 r299194 - /branches/1.4/channels/chan_sip.c

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Dec 20 20:45:43 UTC 2010


Author: mnicholson
Date: Mon Dec 20 14:45:38 2010
New Revision: 299194

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=299194
Log:
Respond as soon as possible with a 202 Accepted to refer requests.

This change also plugs a few memory leaks that can occur when parking sip calls.

ABE-2656

Modified:
    branches/1.4/channels/chan_sip.c

Modified: branches/1.4/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.4/channels/chan_sip.c?view=diff&rev=299194&r1=299193&r2=299194
==============================================================================
--- branches/1.4/channels/chan_sip.c (original)
+++ branches/1.4/channels/chan_sip.c Mon Dec 20 14:45:38 2010
@@ -4947,6 +4947,69 @@
 	return p;
 }
 
+/*!
+ * \brief Parse a Via header
+ *
+ * \note This function does not parse all of the elmentes of the via header at
+ * this time.
+ *
+ * VIA syntax. RFC 3261 section 25.1
+ * Via               =  ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm)
+ * via-parm          =  sent-protocol LWS sent-by *( SEMI via-params )
+ * via-params        =  via-ttl / via-maddr
+ *                   / via-received / via-branch
+ *                   / via-extension
+ * via-ttl           =  "ttl" EQUAL ttl
+ * via-maddr         =  "maddr" EQUAL host
+ * via-received      =  "received" EQUAL (IPv4address / IPv6address)
+ * via-branch        =  "branch" EQUAL token
+ * via-extension     =  generic-param
+ * sent-protocol     =  protocol-name SLASH protocol-version
+ *                   SLASH transport
+ * protocol-name     =  "SIP" / token
+ * protocol-version  =  token
+ * transport         =  "UDP" / "TCP" / "TLS" / "SCTP"
+ *                   / other-transport
+ * sent-by           =  host [ COLON port ]
+ * ttl               =  1*3DIGIT ; 0 to 255
+ */
+static void get_viabranch(char *via, char **sent_by, char **branch)
+{
+	char *tmp;
+
+	if (sent_by) {
+		*sent_by = NULL;
+	}
+	if (branch) {
+		*branch = NULL;
+	}
+	if (ast_strlen_zero(via)) {
+		return;
+	}
+
+	/* chop off sent-protocol */
+	strsep(&via, " \t\r\n");
+	if (ast_strlen_zero(via)) {
+		return;
+	}
+
+	/* chop off sent-by */
+	via = ast_skip_blanks(via);
+	*sent_by = strsep(&via, "; \t\r\n");
+	if (ast_strlen_zero(via)) {
+		return;
+	}
+
+	/* now see if there is a branch parameter in there */
+	if (branch && (tmp = strstr(via, "branch="))) {
+		/* find the branch ID */
+		via = ast_skip_blanks(tmp + 7);
+
+		/* chop off the branch parameter */
+		*branch = strsep(&via, "; \t\r\n");
+	}
+}
+
 /*! \brief Connect incoming SIP message to current dialog or create new dialog structure
 	Called by handle_request, sipsock_read */
 static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *sin, const int intended_method)
@@ -6549,6 +6612,7 @@
 {
 	char newto[256];
 	const char *ot;
+	char *via, *sent_by;
 
 	init_resp(resp, msg);
 	copy_via_headers(p, resp, req, "Via");
@@ -6591,6 +6655,13 @@
 	} else if (!ast_strlen_zero(p->our_contact) && resp_needs_contact(msg, p->method)) {
 		add_header(resp, "Contact", p->our_contact);
 	}
+
+	via = ast_strdupa(get_header(req, "Via"));
+	get_viabranch(via, &sent_by, NULL);
+	if (!ast_strlen_zero(sent_by)) {
+		set_destination(p, sent_by);
+	}
+
 	return 0;
 }
 
@@ -14301,6 +14372,7 @@
 
 	if (!transferee || !transferer) {
 		ast_log(LOG_ERROR, "Missing channels for parking! Transferer %s Transferee %s\n", transferer ? "<available>" : "<missing>", transferee ? "<available>" : "<missing>" );
+		free(d);
 		return NULL;
 	}
 	if (option_debug > 3) 
@@ -14311,6 +14383,7 @@
 		ast_log(LOG_WARNING, "Masquerade failed.\n");
 		transmit_response(transferer->tech_pvt, "503 Internal error", &req);
 		ast_channel_unlock(transferee);
+		free(d);
 		return NULL;
 	} 
 	ast_channel_unlock(transferee);
@@ -14330,7 +14403,6 @@
 
 	/* Any way back to the current call??? */
 	/* Transmit response to the REFER request */
-	transmit_response(transferer->tech_pvt, "202 Accepted", &req);
 	if (!res)	{
 		/* Transfer succeeded */
 		append_history(transferer->tech_pvt, "SIPpark","Parked call on %d", ext);
@@ -14359,6 +14431,7 @@
 	struct ast_channel *transferee, *transferer;
 		/* Chan2m: The transferer, chan1m: The transferee */
 	pthread_t th;
+	pthread_attr_t attr;
 
 	transferee = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan1->accountcode, chan1->exten, chan1->context, chan1->amaflags, "Parking/%s", chan1->name);
 	transferer = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan2->accountcode, chan2->exten, chan2->context, chan2->amaflags, "SIPPeer/%s", chan2->name);
@@ -14428,27 +14501,28 @@
 		}
 		return -1;
 	}
-	if ((d = ast_calloc(1, sizeof(*d)))) {
-		pthread_attr_t attr;
-
-		pthread_attr_init(&attr);
-		pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);	
-
-		/* Save original request for followup */
-		copy_request(&d->req, req);
-		d->chan1 = transferee;	/* Transferee */
-		d->chan2 = transferer;	/* Transferer */
-		d->seqno = seqno;
-		if (ast_pthread_create_background(&th, &attr, sip_park_thread, d) < 0) {
-			/* Could not start thread */
-			free(d);	/* We don't need it anymore. If thread is created, d will be free'd
-					   by sip_park_thread() */
-			pthread_attr_destroy(&attr);
-			return 0;
-		}
+	if (!(d = ast_calloc(1, sizeof(*d)))) {
+		return -1;
+	}
+
+	pthread_attr_init(&attr);
+	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+	/* Save original request for followup */
+	copy_request(&d->req, req);
+	d->chan1 = transferee;	/* Transferee */
+	d->chan2 = transferer;	/* Transferer */
+	d->seqno = seqno;
+	if (ast_pthread_create_background(&th, &attr, sip_park_thread, d) < 0) {
+		/* Could not start thread */
+		free(d);	/* We don't need it anymore. If thread is created, d will be free'd
+				   by sip_park_thread() */
 		pthread_attr_destroy(&attr);
-	} 
-	return -1;
+		return -1;
+	}
+	pthread_attr_destroy(&attr);
+
+	return 0;
 }
 
 /*! \brief Turn off generator data 
@@ -15790,7 +15864,6 @@
 		transferer->refer->replaces_callid_fromtag))) {
 		if (transferer->refer->localtransfer) {
 			/* We did not find the refered call. Sorry, can't accept then */
-			transmit_response(transferer, "202 Accepted", req);
 			/* Let's fake a response from someone else in order
 		   	to follow the standard */
 			transmit_notify_with_sipfrag(transferer, seqno, "481 Call leg/transaction does not exist", TRUE);
@@ -15806,7 +15879,6 @@
 	}
 
 	/* Ok, we can accept this transfer */
-	transmit_response(transferer, "202 Accepted", req);
 	append_history(transferer, "Xfer", "Refer accepted");
 	if (!targetcall_pvt->owner) {	/* No active channel */
 		if (option_debug > 3)
@@ -16093,6 +16165,9 @@
 
 	ast_set_flag(&p->flags[0], SIP_GOTREFER);	
 
+	/* From here on failures will be indicated with NOTIFY requests */
+	transmit_response(p, "202 Accepted", req);
+
 	/* Attended transfer: Find all call legs and bridge transferee with target*/
 	if (p->refer->attendedtransfer) {
 		if ((res = local_attended_transfer(p, &current, req, seqno)))
@@ -16115,13 +16190,13 @@
 		append_history(p, "Xfer", "REFER to call parking.");
 		if (sipdebug && option_debug > 3)
 			ast_log(LOG_DEBUG, "SIP transfer to parking: trying to park %s. Parked by %s\n", current.chan2->name, current.chan1->name);
-		sip_park(current.chan2, current.chan1, req, seqno);
+		if ((res = sip_park(current.chan2, current.chan1, req, seqno))) {
+			transmit_notify_with_sipfrag(p, seqno, "500 Internal Server Error", TRUE);
+		}
 		return res;
 	} 
 
 	/* Blind transfers and remote attended xfers */
-	transmit_response(p, "202 Accepted", req);
-
 	if (current.chan1 && current.chan2) {
 		if (option_debug > 2)
 			ast_log(LOG_DEBUG, "chan1->name: %s\n", current.chan1->name);




More information about the svn-commits mailing list