From 40d5abc2aae82daf31876eb45aa30c9e6329dfdf Mon Sep 17 00:00:00 2001
From: Andy Green <andy.green@linaro.org>
Date: Fri, 17 Apr 2015 20:29:58 +0800
Subject: [PATCH] close reply must use writable control reply path

Signed-off-by: Andy Green <andy.green@linaro.org>
---
 lib/parsers.c               | 20 ++++++++------------
 lib/private-libwebsockets.h |  1 +
 lib/service.c               |  7 ++++++-
 3 files changed, 15 insertions(+), 13 deletions(-)

diff --git a/lib/parsers.c b/lib/parsers.c
index bcf1d305..cc2e2d52 100644
--- a/lib/parsers.c
+++ b/lib/parsers.c
@@ -572,7 +572,6 @@ LWS_VISIBLE int lws_frame_is_binary(struct libwebsocket *wsi)
 int
 libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c)
 {
-	int n;
 	struct lws_tokens eff_buf;
 	int ret = 0;
 
@@ -870,18 +869,15 @@ spill:
 				lwsl_parser("seen client close ack\n");
 				return -1;
 			}
+			if (wsi->state == WSI_STATE_RETURNED_CLOSE_ALREADY)
+				/* if he sends us 2 CLOSE, kill him */
+				return -1;
+
 			lwsl_parser("server sees client close packet\n");
-			/* parrot the close packet payload back */
-			n = libwebsocket_write(wsi, (unsigned char *)
-				&wsi->u.ws.rx_user_buffer[
-					LWS_SEND_BUFFER_PRE_PADDING],
-					wsi->u.ws.rx_user_buffer_head,
-							       LWS_WRITE_CLOSE);
-			if (n < 0)
-				lwsl_info("write of close ack failed %d\n", n);
 			wsi->state = WSI_STATE_RETURNED_CLOSE_ALREADY;
-			/* close the connection */
-			return -1;
+			/* deal with the close packet contents as a PONG */
+			wsi->u.ws.payload_is_close = 1;
+			goto process_as_ping;
 
 		case LWS_WS_OPCODE_07__PING:
 			lwsl_info("received %d byte ping, sending pong\n",
@@ -895,7 +891,7 @@ spill:
 				lwsl_parser("DROP PING since one pending\n");
 				goto ping_drop;
 			}
-			
+process_as_ping:
 			/* control packets can only be < 128 bytes long */
 			if (wsi->u.ws.rx_user_buffer_head > 128 - 4) {
 				lwsl_parser("DROP PING payload too large\n");
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index 5e73dff3..3e8657c3 100644
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -791,6 +791,7 @@ struct _lws_websocket_related {
 	unsigned int this_frame_masked:1;
 	unsigned int inside_frame:1; /* next write will be more of frame */
 	unsigned int clean_buffer:1; /* buffer not rewritten by extension */
+	unsigned int payload_is_close:1; /* process as PONG, but it is close */
 
 	unsigned char *ping_payload_buf; /* non-NULL if malloc'd */
 	unsigned int ping_payload_alloc; /* length malloc'd */
diff --git a/lib/service.c b/lib/service.c
index f1cb9341..40cef568 100644
--- a/lib/service.c
+++ b/lib/service.c
@@ -101,9 +101,14 @@ lws_handle_POLLOUT_event(struct libwebsocket_context *context,
 							       LWS_WRITE_PONG);
 		if (n < 0)
 			return -1;
+
 		/* well he is sent, mark him done */
 		wsi->u.ws.ping_pending_flag = 0;
-		/* leave POLLOUT active either way */
+		if (wsi->u.ws.payload_is_close)
+			/* oh... a close frame was it... then we are done */
+			return -1;
+
+		/* otherwise for PING, leave POLLOUT active either way */
 		return 0;
 	}
 
-- 
GitLab