close reply must use writable control reply path
authorAndy Green <andy.green@linaro.org>
Fri, 17 Apr 2015 12:29:58 +0000 (20:29 +0800)
committerAndy Green <andy.green@linaro.org>
Fri, 17 Apr 2015 12:29:58 +0000 (20:29 +0800)
Signed-off-by: Andy Green <andy.green@linaro.org>
lib/parsers.c
lib/private-libwebsockets.h
lib/service.c

index bcf1d30..cc2e2d5 100644 (file)
@@ -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");
index 5e73dff..3e8657c 100644 (file)
@@ -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 */
index f1cb934..40cef56 100644 (file)
@@ -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;
        }