From 551b35e8228bf01324de39c629929387f6da5e05 Mon Sep 17 00:00:00 2001
From: "David M. Lee" <dlee@digium.com>
Date: Wed, 25 Feb 2015 20:43:16 +0000
Subject: [PATCH] Increase WebSocket frame size and improve large read handling

Some WebSocket applications, like [chan_respoke][], require a larger
frame size than the default 8k; this patch bumps the default to 16k.
This patch also fixes some problems exacerbated by large frames.

The sanity counter was decremented on every fread attempt in
ws_safe_read(), regardless of whether data was read from the socket or
not. For large frames, this could result in loss of sanity prior to
reading the entire frame. (16k frame / 1448 bytes per segment = 12
segments).

This patch changes the sanity counter so that it only decrements when
fread() doesn't read any bytes. This more closely matches the original
intention of ws_safe_read(), given that the error message is
"Websocket seems unresponsive".

This patch also properly logs EOF conditions, so disconnects are no
longer confused with unresponsive connections.

 [chan_respoke]: https://github.com/respoke/chan_respoke

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


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@432236 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 res/res_http_websocket.c | 39 +++++++++++++++++++++++++--------------
 1 file changed, 25 insertions(+), 14 deletions(-)

diff --git a/res/res_http_websocket.c b/res/res_http_websocket.c
index 4bcdd5382e..21b7b7db45 100644
--- a/res/res_http_websocket.c
+++ b/res/res_http_websocket.c
@@ -48,7 +48,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #define MAX_PROTOCOL_BUCKETS 7
 
 /*! \brief Size of the pre-determined buffer for WebSocket frames */
-#define MAXIMUM_FRAME_SIZE 8192
+#define MAXIMUM_FRAME_SIZE 16384
 
 /*! \brief Default reconstruction size for multi-frame payload reconstruction. If exceeded the next frame will start a
  *         payload.
@@ -361,18 +361,35 @@ int AST_OPTIONAL_API_NAME(ast_websocket_set_timeout)(struct ast_websocket *sessi
  */
 static inline int ws_safe_read(struct ast_websocket *session, char *buf, int len, enum ast_websocket_opcode *opcode)
 {
-	int sanity;
 	size_t rlen;
 	int xlen = len;
 	char *rbuf = buf;
-	for (sanity = 10; sanity; sanity--) {
+	int sanity = 10;
+
+	for (;;) {
 		clearerr(session->f);
 		rlen = fread(rbuf, 1, xlen, session->f);
-		if (!rlen && ferror(session->f) && errno != EAGAIN) {
-			ast_log(LOG_ERROR, "Error reading from web socket: %s\n", strerror(errno));
-			*opcode = AST_WEBSOCKET_OPCODE_CLOSE;
-			session->closing = 1;
-			return -1;
+		if (!rlen) {
+			if (feof(session->f)) {
+				ast_log(LOG_WARNING, "Web socket closed abruptly\n");
+				*opcode = AST_WEBSOCKET_OPCODE_CLOSE;
+				session->closing = 1;
+				return -1;
+			}
+
+			if (ferror(session->f) && errno != EAGAIN) {
+				ast_log(LOG_ERROR, "Error reading from web socket: %s\n", strerror(errno));
+				*opcode = AST_WEBSOCKET_OPCODE_CLOSE;
+				session->closing = 1;
+				return -1;
+			}
+
+			if (!--sanity) {
+				ast_log(LOG_WARNING, "Websocket seems unresponsive, disconnecting ...\n");
+				*opcode = AST_WEBSOCKET_OPCODE_CLOSE;
+				session->closing = 1;
+				return -1;
+			}
 		}
 		xlen = xlen - rlen;
 		rbuf = rbuf + rlen;
@@ -386,12 +403,6 @@ static inline int ws_safe_read(struct ast_websocket *session, char *buf, int len
 			return -1;
 		}
 	}
-	if (!sanity) {
-		ast_log(LOG_WARNING, "Websocket seems unresponsive, disconnecting ...\n");
-		*opcode = AST_WEBSOCKET_OPCODE_CLOSE;
-		session->closing = 1;
-		return -1;
-	}
 	return 0;
 }
 
-- 
GitLab