[asterisk-commits] file: branch file/chan_jingle2 r365690 - /team/file/chan_jingle2/channels/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue May 8 14:38:05 CDT 2012


Author: file
Date: Tue May  8 14:38:01 2012
New Revision: 365690

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=365690
Log:
Add locking to protect the owner channel since it can be changed during masquerades.

Modified:
    team/file/chan_jingle2/channels/chan_jingle2.c

Modified: team/file/chan_jingle2/channels/chan_jingle2.c
URL: http://svnview.digium.com/svn/asterisk/team/file/chan_jingle2/channels/chan_jingle2.c?view=diff&rev=365690&r1=365689&r2=365690
==============================================================================
--- team/file/chan_jingle2/channels/chan_jingle2.c (original)
+++ team/file/chan_jingle2/channels/chan_jingle2.c Tue May  8 14:38:01 2012
@@ -816,6 +816,31 @@
 	iks_delete(iq);
 }
 
+/*! \brief Helper function which gets the session lock and ultimately channel lock if present */
+static void jingle_get_owner_lock(struct jingle_session *session)
+{
+	while (session->owner && ast_channel_trylock(session->owner)) {
+		ao2_unlock(session);
+		usleep(1);
+		ao2_lock(session);
+	}
+}
+
+/*! \brief Helper function which queues a hangup frame with cause code */
+static void jingle_queue_hangup_with_cause(struct jingle_session *session, int cause)
+{
+	ao2_lock(session);
+
+	jingle_get_owner_lock(session);
+
+	if (session->owner) {
+		ast_queue_hangup_with_cause(session->owner, cause);
+		ast_channel_unlock(session->owner);
+	}
+
+	ao2_unlock(session);
+}
+
 /*! \brief Internal function which sends a transport-info message */
 static void jingle_send_transport_info(struct jingle_session *session, const char *from)
 {
@@ -826,7 +851,7 @@
 	if (!(iq = iks_new("iq")) ||
 	    !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle"))) {
 		iks_delete(iq);
-		ast_queue_hangup_with_cause(session->owner, AST_CAUSE_SWITCH_CONGESTION);
+		jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
 		return;
 	}
 
@@ -888,7 +913,7 @@
 	if (!res) {
 		ast_aji_send(session->connection, iq);
 	} else {
-		ast_queue_hangup_with_cause(session->owner, AST_CAUSE_SWITCH_CONGESTION);
+		jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
 	}
 
 	/* Clean up after ourselves */
@@ -975,7 +1000,7 @@
 
 	if (!(iq = iks_new("iq")) ||
 	    !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle"))) {
-		ast_queue_hangup_with_cause(session->owner, AST_CAUSE_SWITCH_CONGESTION);
+		jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
 		iks_delete(iq);
 		return;
 	}
@@ -1057,7 +1082,7 @@
 	if (!res) {
 		ast_aji_send(session->connection, iq);
 	} else {
-		ast_queue_hangup_with_cause(session->owner, AST_CAUSE_SWITCH_CONGESTION);
+		jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
 	}
 
 	iks_delete(video_transport);
@@ -1100,7 +1125,17 @@
 
 	/* If no error occurred they accepted our session-initiate message happily */
 	if (!error) {
-		ast_queue_control(session->owner, AST_CONTROL_PROCEEDING);
+		ao2_lock(session);
+
+		jingle_get_owner_lock(session);
+
+		if (session->owner) {
+			ast_queue_control(session->owner, AST_CONTROL_PROCEEDING);
+			ast_channel_unlock(session->owner);
+		}
+
+		ao2_unlock(session);
+
                 jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
 		return IKS_FILTER_EAT;
 	}
@@ -1130,16 +1165,16 @@
 			
 			session->gone = 0;
 		} else {
-			ast_queue_hangup_with_cause(session->owner, AST_CAUSE_PROTOCOL_ERROR);
+			jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
 		}
 	} else if (iks_find_with_attrib(error, "service-unavailable", "xmlns", XMPP_STANZAS_NS)) {
-		ast_queue_hangup_with_cause(session->owner, AST_CAUSE_CONGESTION);
+		jingle_queue_hangup_with_cause(session, AST_CAUSE_CONGESTION);
 	} else if (iks_find_with_attrib(error, "resource-constraint", "xmlns", XMPP_STANZAS_NS)) {
-		ast_queue_hangup_with_cause(session->owner, AST_CAUSE_REQUESTED_CHAN_UNAVAIL);
+		jingle_queue_hangup_with_cause(session, AST_CAUSE_REQUESTED_CHAN_UNAVAIL);
 	} else if (iks_find_with_attrib(error, "bad-request", "xmlns", XMPP_STANZAS_NS)) {
-		ast_queue_hangup_with_cause(session->owner, AST_CAUSE_PROTOCOL_ERROR);
+		jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
 	} else if (iks_find_with_attrib(error, "remote-server-not-found", "xmlns", XMPP_STANZAS_NS)) {
-		ast_queue_hangup_with_cause(session->owner, AST_CAUSE_NO_ROUTE_DESTINATION);
+		jingle_queue_hangup_with_cause(session, AST_CAUSE_NO_ROUTE_DESTINATION);
 	} else if (iks_find_with_attrib(error, "feature-not-implemented", "xmlns", XMPP_STANZAS_NS)) {
 		/* Assume that this occurred because the remote side does not support our transport, so drop it down one and try again */
 		session->transport--;
@@ -1166,10 +1201,10 @@
                         session->gone = 0;
 		} else {
 			/* Otherwise we have exhausted all transports */
-			ast_queue_hangup_with_cause(session->owner, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
+			jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
 		}
 	} else {
-		ast_queue_hangup_with_cause(session->owner, AST_CAUSE_PROTOCOL_ERROR);
+		jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
 	}
 
 	return IKS_FILTER_EAT;
@@ -1222,21 +1257,30 @@
 		break;
 	}
 
-	if (session->owner && frame && frame->frametype == AST_FRAME_VOICE &&
-	    !ast_format_cap_iscompatible(ast_channel_nativeformats(session->owner), &frame->subclass.format)) {
-		if (!ast_format_cap_iscompatible(session->jointcap, &frame->subclass.format)) {
-			ast_debug(1, "Bogus frame of format '%s' received from '%s'!\n",
-				  ast_getformatname(&frame->subclass.format), ast_channel_name(session->owner));
-			frame = &ast_null_frame;
-		} else {
-			ast_debug(1, "Oooh, format changed to %s\n",
-				  ast_getformatname(&frame->subclass.format));
-			ast_format_cap_remove_bytype(ast_channel_nativeformats(session->owner), AST_FORMAT_TYPE_AUDIO);
-			ast_format_cap_add(ast_channel_nativeformats(session->owner), &frame->subclass.format);
-			ast_set_read_format(session->owner, ast_channel_readformat(session->owner));
-			ast_set_write_format(session->owner, ast_channel_writeformat(session->owner));
-		}
-	}
+	ao2_lock(session);
+
+	jingle_get_owner_lock(session);
+
+	if (session->owner) {
+		if (frame && frame->frametype == AST_FRAME_VOICE &&
+		    !ast_format_cap_iscompatible(ast_channel_nativeformats(session->owner), &frame->subclass.format)) {
+			if (!ast_format_cap_iscompatible(session->jointcap, &frame->subclass.format)) {
+				ast_debug(1, "Bogus frame of format '%s' received from '%s'!\n",
+					  ast_getformatname(&frame->subclass.format), ast_channel_name(session->owner));
+				frame = &ast_null_frame;
+			} else {
+				ast_debug(1, "Oooh, format changed to %s\n",
+					  ast_getformatname(&frame->subclass.format));
+				ast_format_cap_remove_bytype(ast_channel_nativeformats(session->owner), AST_FORMAT_TYPE_AUDIO);
+				ast_format_cap_add(ast_channel_nativeformats(session->owner), &frame->subclass.format);
+				ast_set_read_format(session->owner, ast_channel_readformat(session->owner));
+				ast_set_write_format(session->owner, ast_channel_writeformat(session->owner));
+			}
+		}
+		ast_channel_unlock(session->owner);
+	}
+
+	ao2_unlock(session);
 
 	return frame;
 }
@@ -1282,7 +1326,11 @@
 {
 	struct jingle_session *session = ast_channel_tech_pvt(newchan);
 
+	ao2_lock(session);
+
 	session->owner = newchan;
+
+	ao2_unlock(session);
 
 	return 0;
 }
@@ -1303,7 +1351,7 @@
 		break;
 	case AST_CONTROL_BUSY:
 		if (ast_channel_state(ast) != AST_STATE_UP) {
-			ast_channel_hangupcause_set(session->owner, AST_CAUSE_BUSY);
+			ast_channel_hangupcause_set(ast, AST_CAUSE_BUSY);
 			ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
 		} else {
 			res = -1;
@@ -1311,7 +1359,7 @@
 		break;
 	case AST_CONTROL_CONGESTION:
 		if (ast_channel_state(ast) != AST_STATE_UP) {
-			ast_channel_hangupcause_set(session->owner, AST_CAUSE_CONGESTION);
+			ast_channel_hangupcause_set(ast, AST_CAUSE_CONGESTION);
 			ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
 		} else {
 			res = -1;
@@ -1319,7 +1367,7 @@
 		break;
 	case AST_CONTROL_INCOMPLETE:
 		if (ast_channel_state(ast) != AST_STATE_UP) {
-			ast_channel_hangupcause_set(session->owner, AST_CAUSE_CONGESTION);
+			ast_channel_hangupcause_set(ast, AST_CAUSE_CONGESTION);
 			ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
 		}
 		break;
@@ -1549,7 +1597,6 @@
 	}
 
 	/* We purposely don't decrement the session here as there is a reference on the channel */
-
 	ao2_link(endpoint->sessions, session);
 	ao2_ref(endpoint, -1);
 
@@ -1571,7 +1618,7 @@
 		if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
 			/* If this content stanza has no name consider it invalid and move on */
 			if (ast_strlen_zero(name) && !(name = iks_find_attrib(content, "jin:name"))) {
-				ast_queue_hangup_with_cause(session->owner, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
+				jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
 				return;
 			}
 
@@ -1600,7 +1647,7 @@
 			if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
 				media = "audio";
 			} else if (ast_strlen_zero(media)) {
-				ast_queue_hangup_with_cause(session->owner, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
+				jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
 				return;
 			}
 
@@ -1622,7 +1669,7 @@
 
 				/* If video is not present cancel this session */
 				if (!session->vrtp) {
-					ast_queue_hangup_with_cause(session->owner, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
+					jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
 					return;
 				}
 
@@ -1630,7 +1677,7 @@
 				ast_format_cap_remove_bytype(session->jointcap, AST_FORMAT_TYPE_VIDEO);
 			} else {
 				/* Unknown media type */
-				ast_queue_hangup_with_cause(session->owner, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
+				jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
 				return;
 			}
 
@@ -1658,7 +1705,7 @@
 
 			if (ast_format_cap_is_empty(session->jointcap)) {
 				/* We have no compatible codecs, so terminate the session appropriately */
-				ast_queue_hangup_with_cause(session->owner, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
+				jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
 				return;
 			}
 
@@ -1669,7 +1716,7 @@
 
 		/* If we get past the description handling and we still don't know what RTP instance this is for... it is unknown content */
 		if (!rtp) {
-			ast_queue_hangup_with_cause(session->owner, AST_CAUSE_SWITCH_CONGESTION);
+			jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
 			return;
 		}
 
@@ -1680,12 +1727,12 @@
 			iks *candidate;
 
 			if (!ice) {
-				ast_queue_hangup_with_cause(session->owner, AST_CAUSE_SWITCH_CONGESTION);
+				jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
 				return;
 			}
 
 			if (ast_strlen_zero(ufrag) || ast_strlen_zero(pwd)) {
-				ast_queue_hangup_with_cause(session->owner, AST_CAUSE_PROTOCOL_ERROR);
+				jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
 				return;
 			}
 
@@ -1705,14 +1752,14 @@
 				if (ast_strlen_zero(component) || ast_strlen_zero(foundation) || ast_strlen_zero(generation) || ast_strlen_zero(id) ||
 				    ast_strlen_zero(ip) || ast_strlen_zero(network) || ast_strlen_zero(port) || ast_strlen_zero(priority) ||
 				    ast_strlen_zero(protocol) || ast_strlen_zero(type)) {
-					ast_queue_hangup_with_cause(session->owner, AST_CAUSE_PROTOCOL_ERROR);
+					jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
 					return;
 				}
 
 				if ((sscanf(component, "%30u", &local_candidate.id) != 1) ||
 				    (sscanf(priority, "%30u", &local_candidate.priority) != 1) ||
 				    (sscanf(port, "%30d", &real_port) != 1)) {
-					ast_queue_hangup_with_cause(session->owner, AST_CAUSE_PROTOCOL_ERROR);
+					jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
 					return;
 				}
 
@@ -1758,7 +1805,7 @@
 			iks *candidate;
 
 			if (!ice) {
-				ast_queue_hangup_with_cause(session->owner, AST_CAUSE_SWITCH_CONGESTION);
+				jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
 				return;
 			}
 
@@ -1790,7 +1837,7 @@
 				/* If this candidate is incomplete skip it */
 				if (ast_strlen_zero(address) || ast_strlen_zero(port) || ast_strlen_zero(username) ||
 				    ast_strlen_zero(name)) {
-					ast_queue_hangup_with_cause(session->owner, AST_CAUSE_PROTOCOL_ERROR);
+					jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
 					return;
 				}
 
@@ -1801,7 +1848,7 @@
 
 				/* Parse the target information so we can send a STUN request to the candidate */
 				if (sscanf(port, "%30d", &real_port) != 1) {
-					ast_queue_hangup_with_cause(session->owner, AST_CAUSE_PROTOCOL_ERROR);
+					jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
 					return;
 				}
 				ast_sockaddr_parse(&target, address, PARSE_PORT_FORBID);
@@ -1815,7 +1862,7 @@
 			}
 		} else if (iks_find(content, "transport")) {
 			/* If this is a transport we do not support terminate the session as it probably won't work out in the end */
-			ast_queue_hangup_with_cause(session->owner, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
+			jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
 			changed = 0;
 			break;
 		}
@@ -1823,12 +1870,22 @@
 
 	/* Update the channel if the formats have changed */
 	if (changed) {
-		struct ast_format fmt;
-
-		ast_format_cap_copy(ast_channel_nativeformats(session->owner), session->jointcap);
-		ast_codec_choose(&session->prefs, session->jointcap, 1, &fmt);
-		ast_set_read_format(session->owner, &fmt);
-		ast_set_write_format(session->owner, &fmt);
+		ao2_lock(session);
+
+		jingle_get_owner_lock(session);
+
+		if (session->owner) {
+			struct ast_format fmt;
+
+			ast_format_cap_copy(ast_channel_nativeformats(session->owner), session->jointcap);
+			ast_codec_choose(&session->prefs, session->jointcap, 1, &fmt);
+			ast_set_read_format(session->owner, &fmt);
+			ast_set_write_format(session->owner, &fmt);
+
+			ast_channel_unlock(session->owner);
+		}
+
+		ao2_unlock(session);
 	}
 }
 
@@ -1894,8 +1951,6 @@
 
 	jingle_interpret_content(session, pak);
 	jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
-
-	/* Session reference count is purposely not decremented here due to having a reference on the channel */
 }
 
 /*! \brief Handler function for the 'transport-info' action */
@@ -1923,9 +1978,16 @@
 
 	jingle_interpret_content(session, pak);
 
+	ao2_lock(session);
+
+	jingle_get_owner_lock(session);
+
 	if (session->owner) {
 		ast_queue_control(session->owner, AST_CONTROL_ANSWER);
-	}
+		ast_channel_unlock(session->owner);
+	}
+
+	ao2_unlock(session);
 
 	jingle_send_response(endpoint->connection, pak);
 }
@@ -1938,6 +2000,10 @@
 					   "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
 		return;
 	}
+
+	ao2_lock(session);
+
+	jingle_get_owner_lock(session);
 
         if (session->owner) {
 		if (iks_find_with_attrib(pak->query, "ringing", "xmlns", JINGLE_RTP_INFO_NS)) {
@@ -1950,7 +2016,10 @@
 		} else if (iks_find_with_attrib(pak->query, "unhold", "xmlns", JINGLE_RTP_INFO_NS)) {
 			ast_queue_control(session->owner, AST_CONTROL_UNHOLD);
 		}
+		ast_channel_unlock(session->owner);
         }
+
+	ao2_unlock(session);
 
 	jingle_send_response(endpoint->connection, pak);
 }
@@ -1963,6 +2032,10 @@
 					   "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
 		return;
 	}
+
+	ao2_lock(session);
+
+	jingle_get_owner_lock(session);
 
 	if (session->owner) {
 		iks *reason, *text;
@@ -1983,7 +2056,11 @@
 
 		ast_queue_hangup_with_cause(session->owner, cause);
 		session->gone = 1;
-	}
+
+		ast_channel_unlock(session->owner);
+	}
+
+	ao2_unlock(session);
 
 	jingle_send_response(endpoint->connection, pak);
 }




More information about the asterisk-commits mailing list