From 51d9afadd68ee356ced4276b0a72da75c66f9f50 Mon Sep 17 00:00:00 2001
From: Andy Green <andy.green@linaro.org>
Date: Wed, 24 Feb 2016 11:05:56 +0800
Subject: [PATCH] adopt variant with preamble rx

Signed-off-by: Andy Green <andy.green@linaro.org>
---
 changelog                   |  8 ++++
 lib/libwebsockets.h         |  3 ++
 lib/parsers.c               | 13 +++++++
 lib/private-libwebsockets.h |  2 +
 lib/server.c                | 74 +++++++++++++++++++++++++++++++++++++
 libwebsockets-api-doc.html  | 39 +++++++++++++++++++
 6 files changed, 139 insertions(+)

diff --git a/changelog b/changelog
index 347b778e..be8c8172 100644
--- a/changelog
+++ b/changelog
@@ -53,6 +53,14 @@ User API additions
 which lets you set the name of the ECDH curve OpenSSL should use.  By
 default (if you leave ecdh_curve NULL) it will use "prime256v1"
 
+2) MINOR NEWAPI It was already possible to adopt a foreign socket that had not
+been read from using lws_adopt_socket() since v1.7.  Now you can adopt a
+partially-used socket if you don't need SSL, by passing it what you read
+so it can drain that before reading from the socket.
+
+LWS_VISIBLE LWS_EXTERN struct lws *
+lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd,
+		const char *readbuf, size_t len);
 
 
 v1.7.0
diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index 6175a3d2..3e949392 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -1712,6 +1712,9 @@ lws_client_connect_via_info(struct lws_client_connect_info * ccinfo);
 
 LWS_VISIBLE LWS_EXTERN struct lws *
 lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd);
+LWS_VISIBLE LWS_EXTERN struct lws *
+lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd,
+		const char *readbuf, size_t len);
 
 LWS_VISIBLE LWS_EXTERN const char * LWS_WARN_UNUSED_RESULT
 lws_canonical_hostname(struct lws_context *context);
diff --git a/lib/parsers.c b/lib/parsers.c
index 2547ec90..c78fb92e 100644
--- a/lib/parsers.c
+++ b/lib/parsers.c
@@ -81,6 +81,16 @@ lws_header_table_reset(struct lws *wsi)
 
 	/* since we will restart the ah, our new headers are not completed */
 	wsi->hdr_parsing_completed = 0;
+
+	/*
+	 * if we inherited pending rx (from socket adoption deferred
+	 * 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);
+		ah->rxlen = wsi->u.hdr.preamble_rx_len;
+		lws_free_set_NULL(wsi->u.hdr.preamble_rx);
+	}
 }
 
 int LWS_WARN_UNUSED_RESULT
@@ -179,6 +189,9 @@ int lws_header_table_detach(struct lws *wsi)
 		  (void *)wsi, (void *)wsi->u.hdr.ah, wsi->tsi,
 		  pt->ah_count_in_use);
 
+	if (wsi->u.hdr.preamble_rx)
+		lws_free_set_NULL(wsi->u.hdr.preamble_rx);
+
 	/* may not be detached while he still has unprocessed rx */
 	if (ah && ah->rxpos != ah->rxlen) {
 		lwsl_err("%s: %p: rxpos:%d, rxlen:%d\n", __func__, wsi,
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index af62e8ff..315c32e1 100644
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -940,6 +940,8 @@ struct _lws_header_related {
 	/* MUST be first in struct */
 	struct allocated_headers *ah;
 	struct lws *ah_wait_list;
+	unsigned char *preamble_rx;
+	unsigned int preamble_rx_len;
 	enum uri_path_states ups;
 	enum uri_esc_states ues;
 	short lextable_pos;
diff --git a/lib/server.c b/lib/server.c
index cc846d4d..92a8eedc 100644
--- a/lib/server.c
+++ b/lib/server.c
@@ -821,6 +821,80 @@ fail:
 	return NULL;
 }
 
+/**
+ * lws_adopt_socket_readbuf() - adopt foreign socket and first rx as if listen socket accepted it
+ * @context:	lws context
+ * @accept_fd:	fd of already-accepted socket to adopt
+ * @readbuf:	NULL or pointer to data that must be drained before reading from
+ *		accept_fd
+ * @len:	The length of the data held at @readbuf
+ *
+ * Either returns new wsi bound to accept_fd, or closes accept_fd and
+ * returns NULL, having cleaned up any new wsi pieces.
+ *
+ * LWS adopts the socket in http serving mode, it's ready to accept an upgrade
+ * to ws or just serve http.
+ *
+ * If your external code did not already read from the socket, you can use
+ * lws_adopt_socket() instead.
+ *
+ * This api is guaranteed to use the data at @readbuf first, before reading from
+ * the socket.
+ *
+ * @readbuf is limited to the size of the ah rx buf, currently 2048 bytes.
+ */
+
+LWS_VISIBLE LWS_EXTERN struct lws *
+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 allocated_headers *ah;
+
+	if (!wsi)
+		return NULL;
+
+	if (!readbuf)
+		return wsi;
+
+	if (len > sizeof(ah->rx)) {
+		lwsl_err("%s: rx in too big\n", __func__);
+		goto bail;
+	}
+	/*
+	 * we can't process the initial read data until we can attach an ah.
+	 *
+	 * 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.
+	 */
+	if (!lws_header_table_attach(wsi)) {
+		ah = wsi->u.hdr.ah;
+		memcpy(ah->rx, readbuf, len);
+		ah->rxpos = 0;
+		ah->rxlen = len;
+
+		return wsi;
+	}
+
+	/*
+	 * 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.
+	 */
+
+	wsi->u.hdr.preamble_rx = lws_malloc(len);
+	wsi->u.hdr.preamble_rx_len = len;
+
+	return wsi;
+
+bail:
+	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
+
+	return NULL;
+}
+
 LWS_VISIBLE int
 lws_server_socket_service(struct lws_context *context, struct lws *wsi,
 			  struct lws_pollfd *pollfd)
diff --git a/libwebsockets-api-doc.html b/libwebsockets-api-doc.html
index 13d3f006..640ce8e5 100644
--- a/libwebsockets-api-doc.html
+++ b/libwebsockets-api-doc.html
@@ -790,6 +790,42 @@ LWS adopts the socket in http serving mode, it's ready to accept an upgrade
 to ws or just serve http.
 </blockquote>
 <hr>
+<h2>lws_adopt_socket_readbuf - adopt foreign socket and first rx as if listen socket accepted it</h2>
+<i>LWS_EXTERN struct lws *</i>
+<b>lws_adopt_socket_readbuf</b>
+(<i>struct lws_context *</i> <b>context</b>,
+<i>lws_sockfd_type</i> <b>accept_fd</b>,
+<i>const char *</i> <b>readbuf</b>,
+<i>size_t</i> <b>len</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>context</b>
+<dd>lws context
+<dt><b>accept_fd</b>
+<dd>fd of already-accepted socket to adopt
+<dt><b>readbuf</b>
+<dd>NULL or pointer to data that must be drained before reading from
+accept_fd
+<dt><b>len</b>
+<dd>The length of the data held at <tt><b>readbuf</b></tt>
+</dl>
+<h3>Description</h3>
+<blockquote>
+Either returns new wsi bound to accept_fd, or closes accept_fd and
+returns NULL, having cleaned up any new wsi pieces.
+<p>
+LWS adopts the socket in http serving mode, it's ready to accept an upgrade
+to ws or just serve http.
+<p>
+If your external code did not already read from the socket, you can use
+<b>lws_adopt_socket</b> instead.
+<p>
+This api is guaranteed to use the data at <tt><b>readbuf</b></tt> first, before reading from
+the socket.
+<p>
+<tt><b>readbuf</b></tt> is limited to the size of the ah rx buf, currently 2048 bytes.
+</blockquote>
+<hr>
 <h2>lws_serve_http_file - Send a file back to the client using http</h2>
 <i>int</i>
 <b>lws_serve_http_file</b>
@@ -1518,6 +1554,7 @@ header.
 &nbsp; &nbsp; <i>unsigned int</i> <b>count_threads</b>;<br>
 &nbsp; &nbsp; <i>unsigned int</i> <b>fd_limit_per_thread</b>;<br>
 &nbsp; &nbsp; <i>unsigned int</i> <b>timeout_secs</b>;<br>
+&nbsp; &nbsp; <i>const char *</i> <b>ecdh_curve</b>;<br>
 };<br>
 <h3>Members</h3>
 <dl>
@@ -1613,6 +1650,8 @@ limit by the number of threads.
 library are protected from hanging forever by timeouts.  If
 nonzero, this member lets you set the timeout used in seconds.
 Otherwise a default timeout is used.
+<dt><b>ecdh_curve</b>
+<dd>if NULL, defaults to initializing server with "prime256v1"
 </dl>
 <hr>
 <h2>struct lws_client_connect_info - parameters to connect with when using lws_client_connect_via_info()</h2>
-- 
GitLab