From ede9ad2b1302f15d6885e178e4290ef9dcd5d62d Mon Sep 17 00:00:00 2001
From: Andy Green <andy@warmcat.com>
Date: Fri, 23 Jun 2017 10:27:52 +0800
Subject: [PATCH] client: add libuv support to lws_client_reset

More direct solution to problem described in

https://github.com/warmcat/libwebsockets/pull/940
---
 lib/client-handshake.c      | 25 +++++++++++++++++++++++++
 lib/libuv.c                 | 28 +++++++++++++++++++++++++++-
 lib/private-libwebsockets.h |  4 ++++
 3 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/lib/client-handshake.c b/lib/client-handshake.c
index 6286f2d0..4fb9d4c2 100644
--- a/lib/client-handshake.c
+++ b/lib/client-handshake.c
@@ -203,6 +203,15 @@ lws_client_connect_2(struct lws *wsi)
 
 	if (!lws_socket_is_valid(wsi->desc.sockfd)) {
 
+#if defined(LWS_USE_LIBUV)
+		if (LWS_LIBUV_ENABLED(context))
+			if (lws_libuv_check_watcher_active(wsi)) {
+				lwsl_warn("Waiting for libuv watcher to close\n");
+				cce = "waiting for libuv watcher to close";
+				goto oom4;
+			}
+#endif
+
 #ifdef LWS_USE_IPV6
 		if (wsi->ipv6) {
 			sa46.sa6.sin6_port = htons(port);
@@ -232,6 +241,7 @@ lws_client_connect_2(struct lws *wsi)
 		lws_libev_accept(wsi, wsi->desc);
 		lws_libuv_accept(wsi, wsi->desc);
 		lws_libevent_accept(wsi, wsi->desc);
+
 		if (insert_wsi_socket_into_fds(context, wsi)) {
 			compatible_close(wsi->desc.sockfd);
 			cce = "insert wsi failed";
@@ -474,7 +484,22 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
 
 	/* close the connection by hand */
 
+#ifdef LWS_USE_LIBUV
+	if (LWS_LIBUV_ENABLED(wsi->context)) {
+		lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi);
+		/*
+		 * libuv has to do his own close handle processing asynchronously
+		 * but once it starts we can do everything else synchronously,
+		 * including trash wsi->desc.sockfd since it took a copy.
+		 *
+		 * When it completes it will call compatible_close()
+		 */
+		lws_libuv_closehandle_manually(wsi);
+	} else
+#else
 	compatible_close(wsi->desc.sockfd);
+#endif
+
 	remove_wsi_socket_from_fds(wsi);
 
 	wsi->desc.sockfd = LWS_SOCK_INVALID;
diff --git a/lib/libuv.c b/lib/libuv.c
index e295ee32..c0d5aa33 100644
--- a/lib/libuv.c
+++ b/lib/libuv.c
@@ -520,13 +520,39 @@ lws_libuv_closehandle(struct lws *wsi)
 	struct lws_context *context = lws_get_context(wsi);
 
 	/* required to defer actual deletion until libuv has processed it */
-
 	uv_close((uv_handle_t*)&wsi->w_read.uv_watcher, lws_libuv_closewsi);
 
 	if (context->requested_kill && context->count_wsi_allocated == 0)
 		lws_libuv_kill(context);
 }
 
+static void
+lws_libuv_closewsi_m(uv_handle_t* handle)
+{
+	lws_sockfd_type sockfd = (lws_sockfd_type)(long long)handle->data;
+
+	compatible_close(sockfd);
+}
+
+void
+lws_libuv_closehandle_manually(struct lws *wsi)
+{
+	uv_handle_t *h = (void *)&wsi->w_read.uv_watcher;
+
+	h->data = (void *)(long long)wsi->desc.sockfd;
+	/* required to defer actual deletion until libuv has processed it */
+	uv_close((uv_handle_t*)&wsi->w_read.uv_watcher, lws_libuv_closewsi_m);
+}
+
+int
+lws_libuv_check_watcher_active(struct lws *wsi)
+{
+	uv_handle_t *h = (void *)&wsi->w_read.uv_watcher;
+
+	return uv_is_active(h);
+}
+
+
 #if defined(LWS_WITH_PLUGINS) && (UV_VERSION_MAJOR > 0)
 
 LWS_VISIBLE int
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index dc6146ce..1cee7c2e 100644
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -1035,6 +1035,10 @@ LWS_EXTERN void
 lws_close_free_wsi_final(struct lws *wsi);
 LWS_EXTERN void
 lws_libuv_closehandle(struct lws *wsi);
+LWS_EXTERN void
+lws_libuv_closehandle_manually(struct lws *wsi);
+LWS_EXTERN int
+lws_libuv_check_watcher_active(struct lws *wsi);
 
 LWS_VISIBLE LWS_EXTERN int
 lws_plat_plugins_init(struct lws_context * context, const char * const *d);
-- 
GitLab