lws-meta
[platform/upstream/libwebsockets.git] / lib / libwebsockets.c
index d51f29e..5cd0c03 100755 (executable)
@@ -116,6 +116,13 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs)
        struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
        time_t now;
 
+       if (secs == LWS_TO_KILL_SYNC) {
+               lws_remove_from_timeout_list(wsi);
+               lwsl_debug("synchronously killing %p\n", wsi);
+               lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
+               return;
+       }
+
        lws_pt_lock(pt);
 
        time(&now);
@@ -157,6 +164,12 @@ lws_remove_child_from_any_parent(struct lws *wsi)
                if (*pwsi == wsi) {
                        lwsl_info("%s: detach %p from parent %p\n",
                                        __func__, wsi, wsi->parent);
+
+                       if (wsi->parent->protocol)
+                               wsi->parent->protocol->callback(wsi,
+                                               LWS_CALLBACK_CHILD_CLOSING,
+                                              wsi->parent->user_space, wsi, 0);
+
                        *pwsi = wsi->sibling_list;
                        seen = 1;
                        break;
@@ -228,6 +241,8 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
        struct lws_tokens eff_buf;
        int n, m, ret;
 
+       lwsl_debug("%s: %p\n", __func__, wsi);
+
        if (!wsi)
                return;
 
@@ -243,9 +258,8 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
        }
 #endif
 
-       if (wsi->u.hdr.ah)
-               /* we're closing, losing some rx is OK */
-               wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
+       /* we're closing, losing some rx is OK */
+       lws_header_table_force_to_detachable_state(wsi);
 
        context = wsi->context;
        pt = &context->pt[(int)wsi->tsi];
@@ -338,6 +352,7 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
                return;
 
        /* we tried the polite way... */
+       case LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION:
        case LWSS_AWAITING_CLOSE_ACK:
                goto just_kill_connection;
 
@@ -454,29 +469,14 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
 #if defined (LWS_WITH_ESP8266)
                wsi->close_is_pending_send_completion = 1;
 #endif
-               n = lws_write(wsi, &wsi->u.ws.ping_payload_buf[LWS_PRE],
-                             wsi->u.ws.close_in_ping_buffer_len,
-                             LWS_WRITE_CLOSE);
-               if (n >= 0) {
-                       /*
-                        * we have sent a nice protocol level indication we
-                        * now wish to close, we should not send anything more
-                        */
-                       wsi->state = LWSS_AWAITING_CLOSE_ACK;
-
-                       /*
-                        * ...and we should wait for a reply for a bit
-                        * out of politeness
-                        */
-                       lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_ACK, 1);
-                       lwsl_debug("sent close indication, awaiting ack\n");
-
-                       return;
-               }
 
-               lwsl_info("close: sending close packet failed, hanging up\n");
+               lwsl_debug("waiting for chance to send close\n");
+               wsi->waiting_to_send_close_frame = 1;
+               wsi->state = LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION;
+               lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_SEND, 2);
+               lws_callback_on_writable(wsi);
 
-               /* else, the send failed and we should just hang up */
+               return;
        }
 
 just_kill_connection:
@@ -583,6 +583,8 @@ just_kill_connection:
        /* checking return redundant since we anyway close */
        if (wsi->desc.sockfd != LWS_SOCK_INVALID)
                remove_wsi_socket_from_fds(wsi);
+       else
+               lws_same_vh_protocol_remove(wsi);
 
 #if defined(LWS_WITH_ESP8266)
        espconn_disconnect(wsi->desc.sockfd);
@@ -640,6 +642,7 @@ just_kill_connection:
            ((wsi->state_pre_close == LWSS_ESTABLISHED) ||
            (wsi->state_pre_close == LWSS_RETURNED_CLOSE_ALREADY) ||
            (wsi->state_pre_close == LWSS_AWAITING_CLOSE_ACK) ||
+           (wsi->state_pre_close == LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION) ||
            (wsi->state_pre_close == LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) ||
            (wsi->mode == LWSCM_WS_CLIENT && wsi->state_pre_close == LWSS_HTTP) ||
            (wsi->mode == LWSCM_WS_SERVING && wsi->state_pre_close == LWSS_HTTP))) {
@@ -684,13 +687,18 @@ async_close:
        wsi->socket_is_permanently_unusable = 1;
 
 #ifdef LWS_USE_LIBUV
-       if (LWS_LIBUV_ENABLED(context)) {
-               lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi);
-               /* libuv has to do his own close handle processing asynchronously */
-               lws_libuv_closehandle(wsi);
+       if (!wsi->parent_carries_io)
+               if (LWS_LIBUV_ENABLED(context)) {
+                       if (wsi->listener) {
+                               lwsl_debug("%s: stopping listner libuv poll\n", __func__);
+                               uv_poll_stop(&wsi->w_read.uv_watcher);
+                       }
+                       lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi);
+                       /* libuv has to do his own close handle processing asynchronously */
+                       lws_libuv_closehandle(wsi);
 
-               return;
-       }
+                       return;
+               }
 #endif
 
        lws_close_free_wsi_final(wsi);
@@ -866,6 +874,9 @@ lws_get_peer_simple(struct lws *wsi, char *name, int namelen)
        int af = AF_INET;
        void *p, *q;
 
+       if (wsi->parent_carries_io)
+               wsi = wsi->parent;
+
 #ifdef LWS_USE_IPV6
        if (LWS_IPV6_ENABLED(wsi->vhost)) {
                len = sizeof(sin6);
@@ -1417,6 +1428,12 @@ lws_is_final_fragment(struct lws *wsi)
        return wsi->u.ws.final && !wsi->u.ws.rx_packet_length && !wsi->u.ws.rx_draining_ext;
 }
 
+LWS_VISIBLE int
+lws_is_first_fragment(struct lws *wsi)
+{
+       return wsi->u.ws.first_fragment;
+}
+
 LWS_VISIBLE unsigned char
 lws_get_reserved_bits(struct lws *wsi)
 {
@@ -1661,6 +1678,48 @@ lws_get_child(const struct lws *wsi)
 }
 
 LWS_VISIBLE LWS_EXTERN void
+lws_set_parent_carries_io(struct lws *wsi)
+{
+       wsi->parent_carries_io = 1;
+}
+
+LWS_VISIBLE LWS_EXTERN void *
+lws_get_opaque_parent_data(const struct lws *wsi)
+{
+       return wsi->opaque_parent_data;
+}
+
+LWS_VISIBLE LWS_EXTERN void
+lws_set_opaque_parent_data(struct lws *wsi, void *data)
+{
+       wsi->opaque_parent_data = data;
+}
+
+LWS_VISIBLE LWS_EXTERN int
+lws_get_child_pending_on_writable(const struct lws *wsi)
+{
+       return wsi->parent_pending_cb_on_writable;
+}
+
+LWS_VISIBLE LWS_EXTERN void
+lws_clear_child_pending_on_writable(struct lws *wsi)
+{
+       wsi->parent_pending_cb_on_writable = 0;
+}
+
+LWS_VISIBLE LWS_EXTERN int
+lws_get_close_length(struct lws *wsi)
+{
+       return wsi->u.ws.close_in_ping_buffer_len;
+}
+
+LWS_VISIBLE LWS_EXTERN unsigned char *
+lws_get_close_payload(struct lws *wsi)
+{
+       return &wsi->u.ws.ping_payload_buf[LWS_PRE];
+}
+
+LWS_VISIBLE LWS_EXTERN void
 lws_close_reason(struct lws *wsi, enum lws_close_status status,
                 unsigned char *buf, size_t len)
 {
@@ -2552,7 +2611,7 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len
         * Actually having made the env, as a cgi we don't need the ah
         * any more
         */
-       if (wsi->u.hdr.ah->rxpos == wsi->u.hdr.ah->rxlen)
+       if (lws_header_table_is_in_detachable_state(wsi))
                lws_header_table_detach(wsi, 0);
 
        /* we are ready with the redirection pipes... run the thing */