--- asterisk-11.16.0/res/res_rtp_asterisk.c	2015-01-29 15:08:39.000000000 +0300
+++ asterisk-11.16.0-newpatch/res/res_rtp_asterisk.c	2015-03-06 18:52:32.084146048 +0300
@@ -206,6 +206,10 @@
 #ifdef HAVE_OPENSSL_SRTP
 struct dtls_details {
 	SSL *ssl;         /*!< SSL session */
+	ast_mutex_t lock ;        /*!< SSL mutex */
+	ast_mutex_t master_pending_lock ;        /*!< SSL pending mutex */
+	ast_mutex_t dtls_timer_lock;           /*!< Lock for synchronization purposes */
+	int dtlstimerid; /*!< Scheduled item id for DTLS retransmission for RTP */
 	BIO *read_bio;    /*!< Memory buffer for reading */
 	BIO *write_bio;   /*!< Memory buffer for writing */
 	enum ast_rtp_dtls_setup dtls_setup; /*!< Current setup state */
@@ -318,7 +322,6 @@
 
 #ifdef HAVE_OPENSSL_SRTP
 	SSL_CTX *ssl_ctx; /*!< SSL context */
-	ast_mutex_t dtls_timer_lock;           /*!< Lock for synchronization purposes */
 	enum ast_rtp_dtls_verify dtls_verify; /*!< What to verify */
 	enum ast_srtp_suite suite;   /*!< SRTP crypto suite */
 	enum ast_rtp_dtls_hash local_hash; /*!< Local hash used for the fingerprint */
@@ -327,7 +330,6 @@
 	unsigned char remote_fingerprint[EVP_MAX_MD_SIZE]; /*!< Fingerprint of the peer certificate */
 	unsigned int rekey; /*!< Interval at which to renegotiate and rekey */
 	int rekeyid; /*!< Scheduled item id for rekeying */
-	int dtlstimerid; /*!< Scheduled item id for DTLS retransmission for RTP */
 	struct dtls_details dtls; /*!< DTLS state information */
 #endif
 };
@@ -1189,6 +1191,13 @@
 {
 	dtls->dtls_setup = setup;
 
+	ast_mutex_init(&dtls->lock);
+	ast_mutex_init(&dtls->master_pending_lock);
+	ast_mutex_init(&dtls->dtls_timer_lock);
+	
+	dtls->dtlstimerid = -1;
+
+	ast_mutex_lock(&dtls->lock);
 	if (!(dtls->ssl = SSL_new(ssl_ctx))) {
 		ast_log(LOG_ERROR, "Failed to allocate memory for SSL\n");
 		goto error;
@@ -1215,23 +1224,20 @@
 	}
 	dtls->connection = AST_RTP_DTLS_CONNECTION_NEW;
 
+	ast_mutex_unlock(&dtls->lock);
 	return 0;
 
 error:
-	if (dtls->read_bio) {
-		BIO_free(dtls->read_bio);
-		dtls->read_bio = NULL;
-	}
-
-	if (dtls->write_bio) {
-		BIO_free(dtls->write_bio);
-		dtls->write_bio = NULL;
-	}
-
 	if (dtls->ssl) {
+		SSL_clear(dtls->ssl);
 		SSL_free(dtls->ssl);
+		ast_log(LOG_ERROR, "SSL Free\n");
 		dtls->ssl = NULL;
+		dtls->read_bio = NULL;
+		dtls->write_bio = NULL;
 	}
+	ast_mutex_unlock(&dtls->lock);
+
 	return -1;
 }
 
@@ -1378,19 +1384,30 @@
 {
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 
+	ast_mutex_lock(&rtp->dtls.lock);
 	if (rtp->ssl_ctx) {
 		SSL_CTX_free(rtp->ssl_ctx);
 		rtp->ssl_ctx = NULL;
 	}
 
 	if (rtp->dtls.ssl) {
+		SSL_clear(rtp->dtls.ssl);
 		SSL_free(rtp->dtls.ssl);
 		rtp->dtls.ssl = NULL;
+		rtp->dtls.read_bio = NULL;
+		rtp->dtls.write_bio = NULL;
 	}
-
+	ast_mutex_unlock(&rtp->dtls.lock);
+	
 	if (rtp->rtcp && rtp->rtcp->dtls.ssl) {
+		ast_mutex_lock(&rtp->rtcp->dtls.lock);
+		SSL_clear(rtp->rtcp->dtls.ssl);
 		SSL_free(rtp->rtcp->dtls.ssl);
 		rtp->rtcp->dtls.ssl = NULL;
+		rtp->rtcp->dtls.read_bio = NULL;
+		rtp->rtcp->dtls.write_bio = NULL;
+		ast_mutex_unlock(&rtp->rtcp->dtls.lock);
+	
 	}
 }
 
@@ -1398,14 +1415,18 @@
 {
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 
+	ast_mutex_lock(&rtp->dtls.lock);
 	if (SSL_is_init_finished(rtp->dtls.ssl)) {
 		SSL_shutdown(rtp->dtls.ssl);
 		rtp->dtls.connection = AST_RTP_DTLS_CONNECTION_NEW;
 	}
+	ast_mutex_unlock(&rtp->dtls.lock);
 
 	if (rtp->rtcp && SSL_is_init_finished(rtp->rtcp->dtls.ssl)) {
+		ast_mutex_lock(&rtp->rtcp->dtls.lock);
 		SSL_shutdown(rtp->rtcp->dtls.ssl);
 		rtp->rtcp->dtls.connection = AST_RTP_DTLS_CONNECTION_NEW;
+		ast_mutex_unlock(&rtp->rtcp->dtls.lock);
 	}
 }
 
@@ -1472,11 +1493,15 @@
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 
 	if (rtp->dtls.ssl) {
+		ast_mutex_lock(&rtp->dtls.lock);
 		dtls_set_setup(&rtp->dtls.dtls_setup, setup, rtp->dtls.ssl);
+		ast_mutex_unlock(&rtp->dtls.lock);
 	}
 
 	if (rtp->rtcp && rtp->rtcp->dtls.ssl) {
+		ast_mutex_lock(&rtp->rtcp->dtls.lock);
 		dtls_set_setup(&rtp->rtcp->dtls.dtls_setup, setup, rtp->rtcp->dtls.ssl);
+		ast_mutex_unlock(&rtp->rtcp->dtls.lock);
 	}
 }
 
@@ -1570,10 +1595,28 @@
 {
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 
+	ast_mutex_lock(&dtls->lock);
 	if (!dtls->ssl) {
+		ast_mutex_unlock(&dtls->lock);
 		return;
 	}
 
+#if 0
+	if (!SSL_is_init_finished(dtls->ssl)) {
+		SSL_do_handshake(dtls->ssl);
+	} else {
+		SSL_clear(dtls->ssl);
+		SSL_free(dtls->ssl);
+		ast_log(LOG_ERROR, "SSL Free\n");
+		dtls->ssl = NULL;		
+		dtls->write_bio = NULL;
+		dtls->read_bio = NULL;
+
+		ast_mutex_unlock(&dtls->lock);
+		return;
+	}
+
+#endif
 	if (SSL_is_init_finished(dtls->ssl)) {
 		SSL_clear(dtls->ssl);
 		if (dtls->dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) {
@@ -1584,7 +1627,12 @@
 		dtls->connection = AST_RTP_DTLS_CONNECTION_NEW;
 	}
 	SSL_do_handshake(dtls->ssl);
+	ast_mutex_unlock(&dtls->lock);
+
+
+	ast_mutex_lock(&dtls->master_pending_lock);
 	dtls_srtp_check_pending(instance, rtp, rtcp);
+	ast_mutex_unlock(&dtls->master_pending_lock);
 }
 #endif
 
@@ -1737,42 +1785,56 @@
 
 #ifdef HAVE_OPENSSL_SRTP
 
-static int dtls_srtp_handle_timeout(const void *data)
+static int dtls_srtp_handle_timeout(const void *data, int rtcp)
 {
 	struct ast_rtp_instance *instance = (struct ast_rtp_instance *)data;
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+	struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls;
 
-	if (!rtp)
+	if (!rtp || !dtls)
 	{
+		ao2_ref(instance, -1);
 		return 0;
 	}
 
-	ast_mutex_lock(&rtp->dtls_timer_lock);
-	if (rtp->dtlstimerid == -1)
+	ast_mutex_lock(&dtls->dtls_timer_lock);
+	if (dtls->dtlstimerid == -1)
 	{
-		ast_mutex_unlock(&rtp->dtls_timer_lock);
+		ast_mutex_unlock(&dtls->dtls_timer_lock);
 		ao2_ref(instance, -1);
 		return 0;
 	}
 
-	rtp->dtlstimerid = -1;
-	ast_mutex_unlock(&rtp->dtls_timer_lock);
+	dtls->dtlstimerid = -1;
+	ast_mutex_unlock(&dtls->dtls_timer_lock);
 
-	if (rtp->dtls.ssl && !SSL_is_init_finished(rtp->dtls.ssl)) {
-		DTLSv1_handle_timeout(rtp->dtls.ssl);
+	ast_mutex_lock(&dtls->lock);
+	if (dtls->ssl && !SSL_is_init_finished(dtls->ssl)) {
+		DTLSv1_handle_timeout(dtls->ssl);
 	}
-	dtls_srtp_check_pending(instance, rtp, 0);
+	ast_mutex_unlock(&dtls->lock);
 
-	if (rtp->rtcp && rtp->rtcp->dtls.ssl && !SSL_is_init_finished(rtp->rtcp->dtls.ssl)) {
-		DTLSv1_handle_timeout(rtp->rtcp->dtls.ssl);
-	}
-	dtls_srtp_check_pending(instance, rtp, 1);
+	ast_mutex_lock(&dtls->master_pending_lock);
+	dtls_srtp_check_pending(instance, rtp, rtcp);
+	ast_mutex_unlock(&dtls->master_pending_lock);
 
 	ao2_ref(instance, -1);
 
 	return 0;
 }
 
+static int dtls_srtp_handle_timeout_rtp(const void *data)
+{
+	dtls_srtp_handle_timeout(data, 0);
+	return 0;
+}
+static int dtls_srtp_handle_timeout_rtcp(const void *data)
+{
+	dtls_srtp_handle_timeout(data, 1);
+	return 0;
+}
+
+
 static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp, int rtcp)
 {
 	struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls;
@@ -1783,7 +1845,14 @@
 		return;
 	}
 
-	pending = BIO_ctrl_pending(dtls->write_bio);
+	ast_mutex_lock(&dtls->lock);
+	if (dtls->ssl && dtls->write_bio) {
+		pending = BIO_ctrl_pending(dtls->write_bio);
+	} else {
+		ast_mutex_unlock(&dtls->lock);
+		return;
+	}
+	ast_mutex_unlock(&dtls->lock);
 
 	if (pending > 0) {
 		char outgoing[pending];
@@ -1802,24 +1871,31 @@
 			return;
 		}
 
-		out = BIO_read(dtls->write_bio, outgoing, sizeof(outgoing));
+		ast_mutex_lock(&dtls->lock);
+		if (!dtls->write_bio){
+			ast_mutex_unlock(&dtls->lock);
+			return;
+		}
+
+		out = BIO_read(dtls->write_bio, outgoing, pending);
+		ast_mutex_unlock(&dtls->lock);
 
 		/* Stop existing DTLS timer if running */
-		ast_mutex_lock(&rtp->dtls_timer_lock);
-		if (rtp->dtlstimerid > -1) {
-			AST_SCHED_DEL_UNREF(rtp->sched, rtp->dtlstimerid, ao2_ref(instance, -1));
-			rtp->dtlstimerid = -1;
+		ast_mutex_lock(&dtls->dtls_timer_lock);
+		if (dtls->dtlstimerid > -1) {
+			AST_SCHED_DEL_UNREF(rtp->sched, dtls->dtlstimerid, ao2_ref(instance, -1));
+			dtls->dtlstimerid = -1;
 		}
 
 		if (DTLSv1_get_timeout(dtls->ssl, &dtls_timeout)) {
 			int timeout = dtls_timeout.tv_sec * 1000 + dtls_timeout.tv_usec / 1000;
 			ao2_ref(instance, +1);
-			if ((rtp->dtlstimerid = ast_sched_add(rtp->sched, timeout, dtls_srtp_handle_timeout, instance)) < 0) {
+			if ((dtls->dtlstimerid = ast_sched_add(rtp->sched, timeout, !rtcp ? dtls_srtp_handle_timeout_rtp : dtls_srtp_handle_timeout_rtcp, instance)) < 0) {
 				ao2_ref(instance, -1);
 				ast_log(LOG_WARNING, "scheduling DTLS retransmission for RTP instance [%p] failed.\n", instance);
 			}
 		}
-		ast_mutex_unlock(&rtp->dtls_timer_lock);
+		ast_mutex_unlock(&dtls->dtls_timer_lock);
 
 		__rtp_sendto(instance, outgoing, out, 0, &remote_address, rtcp, &ice, 0);
 	}
@@ -1830,14 +1906,34 @@
 	struct ast_rtp_instance *instance = (struct ast_rtp_instance *)data;
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 
+
+	ast_mutex_lock(&rtp->dtls.lock);
+	if (!rtp || !rtp->dtls.ssl){
+		ast_mutex_unlock(&rtp->dtls.lock);
+		rtp->rekeyid = -1;
+		ao2_ref(instance, -1);
+		return 0;
+	}
+
 	SSL_renegotiate(rtp->dtls.ssl);
 	SSL_do_handshake(rtp->dtls.ssl);
+	ast_mutex_unlock(&rtp->dtls.lock);
+
+	ast_mutex_lock(&rtp->dtls.master_pending_lock);
 	dtls_srtp_check_pending(instance, rtp, 0);
+	ast_mutex_unlock(&rtp->dtls.master_pending_lock);
 
+	ast_mutex_lock(&rtp->rtcp->dtls.lock);
 	if (rtp->rtcp && rtp->rtcp->dtls.ssl) {
 		SSL_renegotiate(rtp->rtcp->dtls.ssl);
 		SSL_do_handshake(rtp->rtcp->dtls.ssl);
+		ast_mutex_unlock(&rtp->rtcp->dtls.lock);
+
+		ast_mutex_lock(&rtp->rtcp->dtls.master_pending_lock);
 		dtls_srtp_check_pending(instance, rtp, 1);
+		ast_mutex_unlock(&rtp->rtcp->dtls.master_pending_lock);
+	} else {
+		ast_mutex_unlock(&rtp->rtcp->dtls.lock);
 	}
 
 	rtp->rekeyid = -1;
@@ -1994,15 +2090,20 @@
 	}
 
 #ifdef HAVE_OPENSSL_SRTP
+	struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls;
+
+	ast_mutex_lock(&dtls->master_pending_lock);
 	dtls_srtp_check_pending(instance, rtp, rtcp);
+	ast_mutex_unlock(&dtls->master_pending_lock);
 
 	/* If this is an SSL packet pass it to OpenSSL for processing */
 	if ((*in >= 20) && (*in <= 64)) {
-		struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls;
 		int res = 0;
 
 		/* If no SSL session actually exists terminate things */
+		ast_mutex_lock(&dtls->lock);
 		if (!dtls->ssl) {
+			ast_mutex_unlock(&dtls->lock);
 			ast_log(LOG_ERROR, "Received SSL traffic on RTP instance '%p' without an SSL session\n",
 				instance);
 			return -1;
@@ -2013,12 +2114,24 @@
 			dtls->dtls_setup = AST_RTP_DTLS_SETUP_PASSIVE;
 			SSL_set_accept_state(dtls->ssl);
 		}
+		ast_mutex_unlock(&dtls->lock);
 
+		
+		ast_mutex_lock(&dtls->master_pending_lock);
 		dtls_srtp_check_pending(instance, rtp, rtcp);
+		ast_mutex_unlock(&dtls->master_pending_lock);
+
+		ast_mutex_lock(&dtls->lock);
+		if (!dtls->read_bio){
+			ast_log(LOG_WARNING, "dtls->read_bio is broken by race condition\n");
+			ast_mutex_unlock(&dtls->lock);
+			return -1;
+		}
 
 		BIO_write(dtls->read_bio, buf, len);
 
 		len = SSL_read(dtls->ssl, buf, len);
+		ast_mutex_unlock(&dtls->lock);
 
 		if ((len < 0) && (SSL_get_error(dtls->ssl, len) == SSL_ERROR_SSL)) {
 			unsigned long error = ERR_get_error();
@@ -2027,7 +2140,16 @@
 			return -1;
 		}
 
+		ast_mutex_lock(&dtls->master_pending_lock);
 		dtls_srtp_check_pending(instance, rtp, rtcp);
+		ast_mutex_unlock(&dtls->master_pending_lock);
+
+		ast_mutex_lock(&dtls->lock);
+		if (!dtls->ssl){
+			ast_log(LOG_WARNING, "dtls->ssl is broken by race condition\n");
+			ast_mutex_unlock(&dtls->lock);
+			return -1;
+		}
 
 		if (SSL_is_init_finished(dtls->ssl)) {
 			/* Any further connections will be existing since this is now established */
@@ -2037,6 +2159,7 @@
 				res = dtls_srtp_setup(rtp, srtp, instance);
 			}
 		}
+		ast_mutex_unlock(&dtls->lock);
 
 		return res;
 	}
@@ -2456,7 +2579,7 @@
 
 #ifdef HAVE_OPENSSL_SRTP
 	rtp->rekeyid = -1;
-	rtp->dtlstimerid = -1;
+//	rtp->dtlstimerid = -1;
 #endif
 
 	return 0;
@@ -2480,18 +2603,31 @@
 		close(rtp->s);
 	}
 
+
 	/* Destroy RTCP if it was being used */
 	if (rtp->rtcp) {
 		/*
-		 * It is not possible for there to be an active RTCP scheduler
+		 It is not possible for there to be an active RTCP scheduler
 		 * entry at this point since it holds a reference to the
 		 * RTP instance while it's active.
 		 */
 		close(rtp->rtcp->s);
 #ifdef HAVE_OPENSSL_SRTP
+		ast_mutex_lock(&rtp->rtcp->dtls.lock);
+
 		if (rtp->rtcp->dtls.ssl) {
+			SSL_clear(rtp->rtcp->dtls.ssl);
 			SSL_free(rtp->rtcp->dtls.ssl);
+			rtp->rtcp->dtls.ssl = NULL;
+			rtp->rtcp->dtls.read_bio = NULL;
+			rtp->rtcp->dtls.write_bio = NULL;
 		}
+
+
+		ast_mutex_unlock(&rtp->rtcp->dtls.lock);
+		ast_mutex_destroy(&rtp->rtcp->dtls.lock);
+		ast_mutex_destroy(&rtp->rtcp->dtls.master_pending_lock);
+		ast_mutex_destroy(&rtp->rtcp->dtls.dtls_timer_lock);
 #endif
 		ast_free(rtp->rtcp);
 	}
@@ -2549,17 +2685,28 @@
 #endif
 
 #ifdef HAVE_OPENSSL_SRTP
+	ast_mutex_lock(&rtp->dtls.lock);
 	/* Destroy the SSL context if present */
 	if (rtp->ssl_ctx) {
 		SSL_CTX_free(rtp->ssl_ctx);
 	}
 
 	/* Destroy the SSL session if present */
+
 	if (rtp->dtls.ssl) {
+		SSL_clear(rtp->dtls.ssl);
 		SSL_free(rtp->dtls.ssl);
+		rtp->dtls.ssl = NULL;
+		rtp->dtls.read_bio = NULL;
+		rtp->dtls.write_bio = NULL;
 	}
+
+
+	ast_mutex_unlock(&rtp->dtls.lock);
+	ast_mutex_destroy(&rtp->dtls.lock);
 #endif
 
+
 	/* Finally destroy ourselves */
 	ast_free(rtp);
 
@@ -4571,12 +4718,22 @@
 					}
 					rtp->rtcp->schedid = -1;
 				}
-				close(rtp->rtcp->s);
 #ifdef HAVE_OPENSSL_SRTP
+				ast_mutex_lock(&rtp->rtcp->dtls.lock);
+
 				if (rtp->rtcp->dtls.ssl) {
+					SSL_clear(rtp->rtcp->dtls.ssl);
 					SSL_free(rtp->rtcp->dtls.ssl);
+					rtp->rtcp->dtls.ssl = NULL;
+					rtp->rtcp->dtls.read_bio = NULL;
+					rtp->rtcp->dtls.write_bio = NULL;	
 				}
+
+
+				ast_mutex_unlock(&rtp->rtcp->dtls.lock);
+				ast_mutex_destroy(&rtp->rtcp->dtls.lock);
 #endif
+				close(rtp->rtcp->s);
 				ast_free(rtp->rtcp);
 				rtp->rtcp = NULL;
 			}
@@ -4781,9 +4938,21 @@
 
 #ifdef HAVE_OPENSSL_SRTP
 	AST_SCHED_DEL_UNREF(rtp->sched, rtp->rekeyid, ao2_ref(instance, -1));
-	ast_mutex_lock(&rtp->dtls_timer_lock);
-	AST_SCHED_DEL_UNREF(rtp->sched, rtp->dtlstimerid, ao2_ref(instance, -1));
-	ast_mutex_unlock(&rtp->dtls_timer_lock);
+
+	ast_mutex_lock(&rtp->dtls.dtls_timer_lock);
+	if (rtp->dtls.dtlstimerid > 0){
+		AST_SCHED_DEL_UNREF(rtp->sched, rtp->dtls.dtlstimerid, ao2_ref(instance, -1));
+	}
+	ast_mutex_unlock(&rtp->dtls.dtls_timer_lock);
+
+
+	if (rtp->rtcp){
+		ast_mutex_lock(&rtp->rtcp->dtls.dtls_timer_lock);
+		if (rtp->rtcp->dtls.dtlstimerid > 0){
+			AST_SCHED_DEL_UNREF(rtp->sched, rtp->rtcp->dtls.dtlstimerid, ao2_ref(instance, -1));
+		}
+		ast_mutex_unlock(&rtp->rtcp->dtls.dtls_timer_lock);
+	}
 #endif
 
 	if (rtp->rtcp && rtp->rtcp->schedid > 0) {
