From ec443a41d0742008686a02e9ba90456d36aa336b Mon Sep 17 00:00:00 2001
From: Richard Mudgett <rmudgett@digium.com>
Date: Fri, 13 Jun 2014 05:29:30 +0000
Subject: [PATCH] AST-2014-007: Fix of fix to allow AMI and SIP TCP to send
 messages.

ASTERISK-23673 #close
Reported by: Richard Mudgett

Review: https://reviewboard.asterisk.org/r/3617/
........

Merged revisions 416066 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 416067 from http://svn.asterisk.org/svn/asterisk/branches/11


git-svn-id: https://origsvn.digium.com/svn/asterisk/certified/branches/11.6@416106 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 channels/chan_sip.c       |  6 ++++++
 include/asterisk/tcptls.h | 16 +++++++++++++++-
 main/http.c               |  3 +++
 main/manager.c            |  6 ++++++
 main/tcptls.c             | 17 ++++++++++++++++-
 5 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index df20b83901..5a71388d5b 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -3109,6 +3109,12 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s
 		goto cleanup;
 	}
 
+	/*
+	 * We cannot let the stream exclusively wait for data to arrive.
+	 * We have to wake up the task to send outgoing messages.
+	 */
+	ast_tcptls_stream_set_exclusive_input(tcptls_session->stream_cookie, 0);
+
 	ast_tcptls_stream_set_timeout_sequence(tcptls_session->stream_cookie, ast_tvnow(),
 		tcptls_session->client ? -1 : (authtimeout * 1000));
 
diff --git a/include/asterisk/tcptls.h b/include/asterisk/tcptls.h
index 17b532cdab..3356a92ccd 100644
--- a/include/asterisk/tcptls.h
+++ b/include/asterisk/tcptls.h
@@ -189,7 +189,21 @@ void ast_tcptls_stream_set_timeout_inactivity(struct ast_tcptls_stream *stream,
  */
 void ast_tcptls_stream_set_timeout_sequence(struct ast_tcptls_stream *stream, struct timeval start, int timeout);
 
-/*! \brief 
+/*!
+ * \brief Set the TCP/TLS stream I/O if it can exclusively depend upon the set timeouts.
+ *
+ * \param stream TCP/TLS stream control data.
+ * \param exclusive_input TRUE if stream can exclusively wait for fd input.
+ * Otherwise, the stream will not wait for fd input.  It will wait while
+ * trying to send data.
+ *
+ * \note The stream timeouts still need to be set.
+ *
+ * \return Nothing
+ */
+void ast_tcptls_stream_set_exclusive_input(struct ast_tcptls_stream *stream, int exclusive_input);
+
+/*! \brief
  * describes a server instance
  */
 struct ast_tcptls_session_instance {
diff --git a/main/http.c b/main/http.c
index ffc03fceab..a123dd28c5 100644
--- a/main/http.c
+++ b/main/http.c
@@ -877,6 +877,9 @@ static void *httpd_helper_thread(void *data)
 	flags |= O_NONBLOCK;
 	fcntl(ser->fd, F_SETFL, flags);
 
+	/* We can let the stream wait for data to arrive. */
+	ast_tcptls_stream_set_exclusive_input(ser->stream_cookie, 1);
+
 	ast_tcptls_stream_set_timeout_inactivity(ser->stream_cookie, session_inactivity);
 
 	if (!fgets(buf, sizeof(buf), ser->f) || feof(ser->f)) {
diff --git a/main/manager.c b/main/manager.c
index fe67d5c5cf..51a3b4292a 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -5562,6 +5562,12 @@ static void *session_do(void *data)
 	}
 	ao2_unlock(session);
 
+	/*
+	 * We cannot let the stream exclusively wait for data to arrive.
+	 * We have to wake up the task to send async events.
+	 */
+	ast_tcptls_stream_set_exclusive_input(ser->stream_cookie, 0);
+
 	ast_tcptls_stream_set_timeout_sequence(ser->stream_cookie,
 		ast_tvnow(), authtimeout * 1000);
 
diff --git a/main/tcptls.c b/main/tcptls.c
index 83c21cf8da..65101f4c9c 100644
--- a/main/tcptls.c
+++ b/main/tcptls.c
@@ -77,6 +77,8 @@ struct ast_tcptls_stream {
 	 * feature to work correctly.
 	 */
 	int timeout;
+	/*! TRUE if stream can exclusively wait for fd input. */
+	int exclusive_input;
 };
 
 void ast_tcptls_stream_set_timeout_disable(struct ast_tcptls_stream *stream)
@@ -102,6 +104,13 @@ void ast_tcptls_stream_set_timeout_sequence(struct ast_tcptls_stream *stream, st
 	stream->timeout = timeout;
 }
 
+void ast_tcptls_stream_set_exclusive_input(struct ast_tcptls_stream *stream, int exclusive_input)
+{
+	ast_assert(stream != NULL);
+
+	stream->exclusive_input = exclusive_input;
+}
+
 /*!
  * \internal
  * \brief fopencookie()/funopen() stream read function.
@@ -151,6 +160,11 @@ static HOOK_T tcptls_stream_read(void *cookie, char *buf, LEN_T size)
 				ast_debug(1, "TLS clean shutdown alert reading data\n");
 				return 0;
 			case SSL_ERROR_WANT_READ:
+				if (!stream->exclusive_input) {
+					/* We cannot wait for data now. */
+					errno = EAGAIN;
+					return -1;
+				}
 				while ((ms = ast_remaining_ms(start, stream->timeout))) {
 					res = ast_wait_for_input(stream->fd, ms);
 					if (0 < res) {
@@ -202,7 +216,8 @@ static HOOK_T tcptls_stream_read(void *cookie, char *buf, LEN_T size)
 
 	for (;;) {
 		res = read(stream->fd, buf, size);
-		if (0 <= res) {
+		if (0 <= res || !stream->exclusive_input) {
+			/* Got data or we cannot wait for it. */
 			return res;
 		}
 		if (errno != EINTR && errno != EAGAIN) {
-- 
GitLab