From e3d141dae9a816880bf826b710b1e9a36aaf1aa2 Mon Sep 17 00:00:00 2001
From: Andy Green <andy.green@linaro.org>
Date: Sat, 27 Feb 2016 11:42:22 +0800
Subject: [PATCH] adopt readbuf do service

Signed-off-by: Andy Green <andy.green@linaro.org>
---
 lib/client-handshake.c      |  6 ++---
 lib/client.c                |  2 +-
 lib/libuv.c                 |  8 ++++---
 lib/libwebsockets.c         |  2 +-
 lib/parsers.c               | 29 +++++++++++++++++++-----
 lib/private-libwebsockets.h |  6 ++---
 lib/server.c                | 44 ++++++++++++++++++++++++++++---------
 lib/service.c               |  5 ++++-
 8 files changed, 74 insertions(+), 28 deletions(-)

diff --git a/lib/client-handshake.c b/lib/client-handshake.c
index 96854afe..264cca98 100644
--- a/lib/client-handshake.c
+++ b/lib/client-handshake.c
@@ -303,7 +303,7 @@ lws_client_connect_2(struct lws *wsi)
 oom4:
 	/* we're closing, losing some rx is OK */
 	wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
-	lws_header_table_detach(wsi);
+	lws_header_table_detach(wsi, 0);
 	lws_free(wsi);
 
 	return NULL;
@@ -405,7 +405,7 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
 	}
 #endif
 
-	if (lws_header_table_attach(wsi))
+	if (lws_header_table_attach(wsi, 0))
 		goto bail;
 
 	/*
@@ -470,7 +470,7 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
 bail1:
 	/* we're closing, losing some rx is OK */
 	wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
-	lws_header_table_detach(wsi);
+	lws_header_table_detach(wsi, 0);
 bail:
 	lws_free(wsi);
 
diff --git a/lib/client.c b/lib/client.c
index 33d990e4..94497e94 100644
--- a/lib/client.c
+++ b/lib/client.c
@@ -798,7 +798,7 @@ check_accept:
 	lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
 
 	/* free up his parsing allocations */
-	lws_header_table_detach(wsi);
+	lws_header_table_detach(wsi, 0);
 
 	lws_union_transition(wsi, LWSCM_WS_CLIENT);
 	wsi->state = LWSS_ESTABLISHED;
diff --git a/lib/libuv.c b/lib/libuv.c
index ac1ab6de..5400f315 100644
--- a/lib/libuv.c
+++ b/lib/libuv.c
@@ -80,7 +80,7 @@ lws_uv_timeout_cb(uv_timer_t *timer)
 	struct lws_context_per_thread *pt = container_of(timer,
 			struct lws_context_per_thread, uv_timeout_watcher);
 
-	lwsl_info("%s\n", __func__);
+	lwsl_debug("%s\n", __func__);
 	/* do timeout check only */
 	lws_service_fd_tsi(pt->context, NULL, pt->tid);
 }
@@ -119,8 +119,10 @@ lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, uv_signal_cb cb,
 	 */
 	if (wsi) {
 		wsi->w_read.context = context;
-		uv_poll_init(pt->io_loop_uv, &wsi->w_read.uv_watcher, pt->lserv_fd);
-		uv_poll_start(&wsi->w_read.uv_watcher, UV_READABLE, lws_accept_cb);
+		uv_poll_init(pt->io_loop_uv, &wsi->w_read.uv_watcher,
+			     pt->lserv_fd);
+		uv_poll_start(&wsi->w_read.uv_watcher, UV_READABLE,
+			      lws_accept_cb);
 	}
 
 	uv_timer_init(pt->io_loop_uv, &pt->uv_timeout_watcher);
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index 00217f76..257d6b41 100644
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -63,7 +63,7 @@ lws_free_wsi(struct lws *wsi)
 		wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
 
 	/* we may not have an ah, but may be on the waiting list... */
-	lws_header_table_detach(wsi);
+	lws_header_table_detach(wsi, 0);
 
 	wsi->context->count_wsi_allocated--;
 	lwsl_debug("%s: %p, remaining wsi %d\n", __func__, wsi,
diff --git a/lib/parsers.c b/lib/parsers.c
index e802e8ce..cb025414 100644
--- a/lib/parsers.c
+++ b/lib/parsers.c
@@ -61,9 +61,11 @@ lextable_decode(int pos, char c)
 }
 
 void
-lws_header_table_reset(struct lws *wsi)
+lws_header_table_reset(struct lws *wsi, int autoservice)
 {
 	struct allocated_headers *ah = wsi->u.hdr.ah;
+	struct lws_context_per_thread *pt;
+	struct lws_pollfd *pfd;
 
 	/* if we have the idea we're resetting 'our' ah, must be bound to one */
 	assert(ah);
@@ -87,14 +89,29 @@ lws_header_table_reset(struct lws *wsi)
 	 * processing), apply and free it.
 	 */
 	if (wsi->u.hdr.preamble_rx) {
-		memcpy(ah->rx, wsi->u.hdr.preamble_rx, wsi->u.hdr.preamble_rx_len);
+		memcpy(ah->rx, wsi->u.hdr.preamble_rx,
+		       wsi->u.hdr.preamble_rx_len);
 		ah->rxlen = wsi->u.hdr.preamble_rx_len;
 		lws_free_set_NULL(wsi->u.hdr.preamble_rx);
+
+		if (autoservice) {
+			lwsl_notice("%s: calling service on readbuf ah\n", __func__);
+
+			pt = &wsi->context->pt[(int)wsi->tsi];
+
+			/* unlike a normal connect, we have the headers already
+			 * (or the first part of them anyway)
+			 */
+			pfd = &pt->fds[wsi->position_in_fds_table];
+			pfd->revents |= LWS_POLLIN;
+			lwsl_err("%s: calling service\n", __func__);
+			lws_service_fd_tsi(wsi->context, pfd, wsi->tsi);
+		}
 	}
 }
 
 int LWS_WARN_UNUSED_RESULT
-lws_header_table_attach(struct lws *wsi)
+lws_header_table_attach(struct lws *wsi, int autoservice)
 {
 	struct lws_context *context = wsi->context;
 	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
@@ -165,7 +182,7 @@ lws_header_table_attach(struct lws *wsi)
 	lws_pt_unlock(pt);
 
 reset:
-	lws_header_table_reset(wsi);
+	lws_header_table_reset(wsi, autoservice);
 	time(&wsi->u.hdr.ah->assigned);
 
 	return 0;
@@ -176,7 +193,7 @@ bail:
 	return 1;
 }
 
-int lws_header_table_detach(struct lws *wsi)
+int lws_header_table_detach(struct lws *wsi, int autoservice)
 {
 	struct lws_context *context = wsi->context;
 	struct allocated_headers *ah = wsi->u.hdr.ah;
@@ -258,7 +275,7 @@ int lws_header_table_detach(struct lws *wsi)
 
 	wsi->u.hdr.ah = ah;
 	ah->wsi = wsi; /* new owner */
-	lws_header_table_reset(wsi);
+	lws_header_table_reset(wsi, autoservice);
 	time(&wsi->u.hdr.ah->assigned);
 
 	assert(wsi->position_in_fds_table != -1);
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index 5dd48178..d7a9389c 100644
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -1296,13 +1296,13 @@ LWS_EXTERN int
 lws_plat_set_socket_options(struct lws_context *context, lws_sockfd_type fd);
 
 LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_header_table_attach(struct lws *wsi);
+lws_header_table_attach(struct lws *wsi, int autoservice);
 
 LWS_EXTERN int
-lws_header_table_detach(struct lws *wsi);
+lws_header_table_detach(struct lws *wsi, int autoservice);
 
 LWS_EXTERN void
-lws_header_table_reset(struct lws *wsi);
+lws_header_table_reset(struct lws *wsi, int autoservice);
 
 LWS_EXTERN char * LWS_WARN_UNUSED_RESULT
 lws_hdr_simple_ptr(struct lws *wsi, enum lws_token_indexes h);
diff --git a/lib/server.c b/lib/server.c
index bd57ad2e..eeb0b0d3 100644
--- a/lib/server.c
+++ b/lib/server.c
@@ -330,7 +330,7 @@ lws_http_action(struct lws *wsi)
 bail_nuke_ah:
 	/* we're closing, losing some rx is OK */
 	wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
-	lws_header_table_detach(wsi);
+	lws_header_table_detach(wsi, 1);
 
 	return 1;
 }
@@ -628,7 +628,7 @@ bail_nuke_ah:
 	/* drop the header info */
 	/* we're closing, losing some rx is OK */
 	wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
-	lws_header_table_detach(wsi);
+	lws_header_table_detach(wsi, 1);
 
 	return 1;
 }
@@ -753,9 +753,9 @@ lws_http_transaction_completed(struct lws *wsi)
 
 		if (!wsi->more_rx_waiting) {
 			wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
-			lws_header_table_detach(wsi);
+			lws_header_table_detach(wsi, 1);
 		} else
-			lws_header_table_reset(wsi);
+			lws_header_table_reset(wsi, 1);
 	}
 
 	/* If we're (re)starting on headers, need other implied init */
@@ -861,7 +861,9 @@ lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd,
 			 const char *readbuf, size_t len)
 {
 	struct lws *wsi = lws_adopt_socket(context, accept_fd);
+	struct lws_context_per_thread *pt;
 	struct allocated_headers *ah;
+	struct lws_pollfd *pfd;
 
 	if (!wsi)
 		return NULL;
@@ -878,24 +880,42 @@ lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd,
 	 *
 	 * if one is available, get it and place the data in his ah rxbuf...
 	 * wsi with ah that have pending rxbuf get auto-POLLIN service.
+	 *
+	 * no autoservice because we didn't get a chance to attach the
+	 * readbuf data to wsi or ah yet, and we will do it next if we get
+	 * the ah.
 	 */
-	if (!lws_header_table_attach(wsi)) {
+	if (!lws_header_table_attach(wsi, 0)) {
 		ah = wsi->u.hdr.ah;
 		memcpy(ah->rx, readbuf, len);
 		ah->rxpos = 0;
 		ah->rxlen = len;
 
+		lwsl_notice("%s: calling service on readbuf ah\n", __func__);
+		pt = &context->pt[(int)wsi->tsi];
+
+		/* unlike a normal connect, we have the headers already
+		 * (or the first part of them anyway).
+		 * libuv won't come back and service us without a network
+		 * event, so we need to do the header service right here.
+		 */
+		pfd = &pt->fds[wsi->position_in_fds_table];
+		pfd->revents |= LWS_POLLIN;
+		lwsl_err("%s: calling service\n", __func__);
+		if (lws_service_fd_tsi(context, pfd, wsi->tsi))
+			/* service closed us */
+			return NULL;
+
 		return wsi;
 	}
-
+	lwsl_err("%s: deferring handling ah\n", __func__);
 	/*
 	 * hum if no ah came, we are on the wait list and must defer
 	 * dealing with this until the ah arrives.
 	 *
 	 * later successful lws_header_table_attach() will apply the
-	 * below to the rx buffer.
+	 * below to the rx buffer (via lws_header_table_reset()).
 	 */
-
 	wsi->u.hdr.preamble_rx = lws_malloc(len);
 	memcpy(wsi->u.hdr.preamble_rx, readbuf, len);
 	wsi->u.hdr.preamble_rx_len = len;
@@ -958,7 +978,8 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
 		    wsi->state == LWSS_HTTP_ISSUING_FILE ||
 		    wsi->state == LWSS_HTTP_HEADERS) {
 			if (!wsi->u.hdr.ah)
-				if (lws_header_table_attach(wsi))
+				/* no autoservice beacuse we will do it next */
+				if (lws_header_table_attach(wsi, 0))
 					goto try_pollout;
 
 			ah = wsi->u.hdr.ah;
@@ -1002,7 +1023,7 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
 					    (wsi->mode != LWSCM_HTTP_SERVING &&
 					     wsi->mode != LWSCM_HTTP_SERVING_ACCEPTED &&
 					     wsi->mode != LWSCM_HTTP2_SERVING))
-						lws_header_table_detach(wsi);
+						lws_header_table_detach(wsi, 1);
 				}
 				break;
 			}
@@ -1052,6 +1073,9 @@ try_pollout:
 			goto fail;
 		}
 
+		if (!wsi->hdr_parsing_completed)
+			break;
+
 		if (wsi->state != LWSS_HTTP_ISSUING_FILE) {
 			n = user_callback_handle_rxflow(wsi->protocol->callback,
 					wsi, LWS_CALLBACK_HTTP_WRITEABLE,
diff --git a/lib/service.c b/lib/service.c
index 6ebd562d..c665f117 100644
--- a/lib/service.c
+++ b/lib/service.c
@@ -237,6 +237,9 @@ user_service:
 			return 1;
 		}
 
+	if (!wsi->hdr_parsing_completed)
+		return 0;
+
 #ifdef LWS_USE_HTTP2
 	/*
 	 * we are the 'network wsi' for potentially many muxed child wsi with
@@ -789,7 +792,7 @@ drain:
 			/* we can run the normal ah detach flow despite
 			 * being in ws union mode, since all union members
 			 * start with hdr */
-			lws_header_table_detach(wsi);
+			lws_header_table_detach(wsi, 0);
 		}
 
 		pending = lws_ssl_pending(wsi);
-- 
GitLab