diff --git a/lib/parsers.c b/lib/parsers.c
index bcf1d305b6c246ad2114cc7546354e6106d930c3..cc2e2d521677cd7099a0d9bff673ff18506ad0e3 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 5e73dff3b624b882c2a237fc4b32de7dc419d4ab..3e8657c36006e1b0d80de327587992b73376c7a9 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 f1cb9341159ed357717580f39e9e21e1facfa5eb..40cef568283c34352ef8ebaee3cf13df39ef9125 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;
 	}