diff --git a/CMakeLists.txt b/CMakeLists.txt
index f7fc82bf..875da83b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -493,8 +493,14 @@ if (LWS_WITH_SSL)
 
 		list(APPEND LIB_LIST "${LWS_CYASSL_LIB}")
 	else()
+		if (OPENSSL_ROOT_DIR)
+			set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/include")
+			set(OPENSSL_LIBRARIES "${OPENSSL_ROOT_DIR}/lib/libssl.so" "${OPENSSL_ROOT_DIR}/lib/libcrypto.so")
+		else(OPENSSL_ROOT_DIR)
+		
 		# TODO: Add support for STATIC also.
 		find_package(OpenSSL REQUIRED)
+		endif(OPENSSL_ROOT_DIR)
 
 		message("OpenSSL include dir: ${OPENSSL_INCLUDE_DIR}")
 		message("OpenSSL libraries: ${OPENSSL_LIBRARIES}")
diff --git a/README.build b/README.build
index dab5ac2e..5521e060 100644
--- a/README.build
+++ b/README.build
@@ -66,7 +66,14 @@ Building on Unix:
 	access to ALPN support only in newer OpenSSL versions) the nice way to
 	express that in one cmake command is eg,
 	
-		-DOPENSSL_ROOT_DIR=/usr/local/ssl
+	cmake .. -DOPENSSL_ROOT_DIR=/usr/local/ssl \
+		 -DCMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE=/usr/local/ssl \
+		 -DLWS_WITH_HTTP2=1
+	
+	When you run the test apps using non-distro SSL, you have to force them
+	to use your libs, not the distro ones
+	
+	LD_LIBRARY_PATH=/usr/local/ssl/lib libwebsockets-test-server --ssl
 
 4. Finally you can build using the generated Makefile:
 
@@ -150,6 +157,29 @@ cmake .. -DLWS_USE_CYASSL=1 \
 
 NOTE: On windows use the .lib file extension for LWS_CYASSL_LIB instead.
 
+
+Reproducing HTTP2.0 tests
+-------------------------
+
+You must have built and be running lws against a version of openssl that has
+ALPN / NPN.  Most distros still have older versions.  You'll know it's right by
+seeing
+
+lwsts[4752]:  Compiled with OpenSSL support
+lwsts[4752]:  Using SSL mode
+lwsts[4752]:  HTTP2 / ALPN enabled
+
+at lws startup.
+
+For non-SSL HTTP2.0 upgrade
+
+nghttp -nvasu http://localhost:7681/test.htm
+
+For SSL / ALPN HTTP2.0 upgrade
+
+nghttp -nvas https://localhost:7681/test.html
+
+
 Cross compiling
 ---------------
 To enable cross compiling libwebsockets using CMake you need to create
diff --git a/lib/http2.c b/lib/http2.c
index 15e07931..7279f6b8 100644
--- a/lib/http2.c
+++ b/lib/http2.c
@@ -77,8 +77,11 @@ lws_create_server_child_wsi(struct libwebsocket_context *context, struct libwebs
 	
 	wsi->state = WSI_STATE_HTTP2_ESTABLISHED;
 	wsi->mode = parent_wsi->mode;
+	
+	wsi->protocol = &context->protocols[0];
+	libwebsocket_ensure_user_space(wsi);
 
-	lwsl_info("%s: %p new child %p, sid %d\n", __func__, parent_wsi, wsi, sid);
+	lwsl_info("%s: %p new child %p, sid %d, user_space=%p\n", __func__, parent_wsi, wsi, sid, wsi->user_space);
 	
 	return wsi;
 }
@@ -189,7 +192,7 @@ lws_http2_parser(struct libwebsocket_context *context,
 			return 1;
 
 		if (!https_client_preface[wsi->u.http2.count]) {
-			lwsl_err("http2: %p: established\n", wsi);
+			lwsl_info("http2: %p: established\n", wsi);
 			wsi->state = WSI_STATE_HTTP2_ESTABLISHED_PRE_SETTINGS;
 			wsi->u.http2.count = 0;
 			
@@ -224,6 +227,16 @@ lws_http2_parser(struct libwebsocket_context *context,
 				if (lws_hpack_interpret(context, wsi->u.http2.stream_wsi, c))
 					return 1;
 				break;
+			case LWS_HTTP2_FRAME_TYPE_GOAWAY:
+				if (wsi->u.http2.count >= 5 && wsi->u.http2.count <= 8) {
+					wsi->u.http2.hpack_e_dep <<= 8;
+					wsi->u.http2.hpack_e_dep |= c;
+					if (wsi->u.http2.count == 8) {
+						lwsl_info("goaway err 0x%x\n", wsi->u.http2.hpack_e_dep);
+					}
+				}
+				wsi->u.http2.GOING_AWAY = 1;
+				break;
 			}
 			if (wsi->u.http2.count != wsi->u.http2.length)
 				break;
@@ -241,7 +254,7 @@ lws_http2_parser(struct libwebsocket_context *context,
 			switch (wsi->u.http2.type) {
 			case LWS_HTTP2_FRAME_TYPE_HEADERS:
 				/* service the http request itself */
-				lwsl_info("servicing initial http request\n");
+				lwsl_info("servicing initial http request, wsi=%p, stream wsi=%p\n", wsi, wsi->u.http2.stream_wsi);
 				n = lws_http_action(context, wsi->u.http2.stream_wsi);
 				lwsl_info("  action result %d\n", n);
 				break;
@@ -378,6 +391,11 @@ int lws_http2_do_pps_send(struct libwebsocket_context *context, struct libwebsoc
 			
 			wsi->u.http.fd = LWS_INVALID_FILE;
 			
+			if (lws_is_ssl(lws_http2_get_network_wsi(wsi))) {
+				lwsl_info("skipping nonexistant ssl upgrade headers\n");
+				break;
+			}
+			
 			/* 
 			 * we need to treat the headers from this upgrade
 			 * as the first job.  These need to get
@@ -405,4 +423,28 @@ int lws_http2_do_pps_send(struct libwebsocket_context *context, struct libwebsoc
 	}
 	
 	return 0;
-}
\ No newline at end of file
+}
+
+struct libwebsocket * lws_http2_get_nth_child(struct libwebsocket *wsi, int n)
+{
+	do {
+		wsi = wsi->u.http2.next_child_wsi;
+		if (!wsi)
+			return NULL;
+	} while (n--);
+
+	return wsi;
+}
+#if 0
+struct libwebsocket * lws_http2_get_next_waiting_child(struct libwebsocket *wsi)
+{
+	struct libwebsocket *wsi_child = wsi, *wsi2;
+
+	do {
+		wsi2 = lws_http2_get_nth_child(wsi_child, wsi_child->round_robin_POLLOUT);
+		if (wsi2 == NULL) {
+			wsi_child->round_robin = 0;
+		}
+	}
+}
+#endif
\ No newline at end of file
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index 2387e7cc..bb1a08d6 100644
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -702,6 +702,7 @@ libwebsocket_get_reserved_bits(struct libwebsocket *wsi)
 int
 libwebsocket_ensure_user_space(struct libwebsocket *wsi)
 {
+	lwsl_info("%s: %p protocol %p\n", __func__, wsi, wsi->protocol);
 	if (!wsi->protocol)
 		return 1;
 
@@ -716,7 +717,8 @@ libwebsocket_ensure_user_space(struct libwebsocket *wsi)
 		}
 		memset(wsi->user_space, 0,
 					 wsi->protocol->per_session_data_size);
-	}
+	} else
+		lwsl_info("%s: %p protocol pss %u, user_space=%d\n", __func__, wsi, wsi->protocol->per_session_data_size, wsi->user_space);
 	return 0;
 }
 
diff --git a/lib/pollfd.c b/lib/pollfd.c
index 3995a378..63cdfc36 100644
--- a/lib/pollfd.c
+++ b/lib/pollfd.c
@@ -193,6 +193,40 @@ LWS_VISIBLE int
 libwebsocket_callback_on_writable(struct libwebsocket_context *context,
 						      struct libwebsocket *wsi)
 {
+#ifdef LWS_USE_HTTP2
+	struct libwebsocket *network_wsi, *wsi2;
+	int already;
+
+	lwsl_info("%s: %p\n", __func__, wsi);
+	
+	if (wsi->mode != LWS_CONNMODE_HTTP2_SERVING)
+		goto network_sock;
+	
+	if (wsi->u.http2.requested_POLLOUT) {
+		lwsl_info("already pending writable\n");
+		return 1;
+	}
+	
+	network_wsi = lws_http2_get_network_wsi(wsi);
+	already = network_wsi->u.http2.requested_POLLOUT;
+	
+	/* mark everybody above him as requesting pollout */
+	
+	wsi2 = wsi;
+	while (wsi2) {
+		wsi2->u.http2.requested_POLLOUT = 1;
+		lwsl_info("mark %p pending writable\n", wsi2);
+		wsi2 = wsi2->u.http2.parent_wsi;
+	}
+	
+	/* for network action, act only on the network wsi */
+	
+	wsi = network_wsi;
+	if (already)
+		return 1;
+network_sock:
+#endif
+
 	if (lws_ext_callback_for_each_active(wsi,
 				LWS_EXT_CALLBACK_REQUEST_ON_WRITEABLE, NULL, 0))
 		return 1;
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index 4f171de2..9ff23c1e 100755
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -697,9 +697,14 @@ struct _lws_http2_related {
 	unsigned char frame_state;
 	unsigned char padding;
 	
+	unsigned short round_robin_POLLOUT;
+	unsigned short count_POLLOUT_children;
+
 	unsigned int END_STREAM:1;
 	unsigned int END_HEADERS:1;
 	unsigned int send_END_STREAM:1;
+	unsigned int GOING_AWAY;
+	unsigned int requested_POLLOUT:1;
 
 	/* hpack */
 	enum http2_hpack_state hpack;
@@ -720,7 +725,7 @@ struct _lws_http2_related {
 	unsigned char one_setting[LWS_HTTP2_SETTINGS_LENGTH];
 };
 
-#define HTTP2_IS_TOPLEVEL_WSI(wsi) (!wsi->parent_wsi)
+#define HTTP2_IS_TOPLEVEL_WSI(wsi) (!wsi->u.http2.parent_wsi)
 
 #endif
 
@@ -824,6 +829,7 @@ struct libwebsocket {
 	BIO *client_bio;
 	unsigned int use_ssl:2;
 	unsigned int buffered_reads_pending:1;
+	unsigned int upgraded:1;
 #endif
 
 #ifdef _WIN32
@@ -954,6 +960,7 @@ user_callback_handle_rxflow(callback_function,
 							  void *in, size_t len);
 #ifdef LWS_USE_HTTP2
 LWS_EXTERN struct libwebsocket *lws_http2_get_network_wsi(struct libwebsocket *wsi);
+struct libwebsocket * lws_http2_get_nth_child(struct libwebsocket *wsi, int n);
 LWS_EXTERN int
 lws_http2_interpret_settings_payload(struct http2_settings *settings, unsigned char *buf, int len);
 LWS_EXTERN void lws_http2_init(struct http2_settings *settings);
@@ -989,6 +996,10 @@ lws_add_http2_header_status(struct libwebsocket_context *context,
 			    unsigned int code,
 			    unsigned char **p,
 			    unsigned char *end);
+LWS_EXTERN
+void lws_http2_configure_if_upgraded(struct libwebsocket *wsi);
+#else
+#define lws_http2_configure_if_upgraded(x)
 #endif
 
 LWS_EXTERN int
diff --git a/lib/service.c b/lib/service.c
index f3c01388..1ac4173b 100644
--- a/lib/service.c
+++ b/lib/service.c
@@ -21,12 +21,38 @@
 
 #include "private-libwebsockets.h"
 
+static int
+lws_calllback_as_writeable(struct libwebsocket_context *context,
+		   struct libwebsocket *wsi)
+{
+	int n;
+
+	switch (wsi->mode) {
+	case LWS_CONNMODE_WS_CLIENT:
+		n = LWS_CALLBACK_CLIENT_WRITEABLE;
+		break;
+	case LWS_CONNMODE_WS_SERVING:
+		n = LWS_CALLBACK_SERVER_WRITEABLE;
+		break;
+	default:
+		n = LWS_CALLBACK_HTTP_WRITEABLE;
+		break;
+	}
+	lwsl_info("%s: %p (user=%p)\n", __func__, wsi, wsi->user_space);
+	return user_callback_handle_rxflow(wsi->protocol->callback, context,
+			wsi, (enum libwebsocket_callback_reasons) n,
+						      wsi->user_space, NULL, 0);
+}
+
 int
 lws_handle_POLLOUT_event(struct libwebsocket_context *context,
 		   struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd)
 {
 	int n;
 	struct lws_tokens eff_buf;
+#ifdef LWS_USE_HTTP2
+	struct libwebsocket *wsi2;
+#endif
 	int ret;
 	int m;
 	int handled = 0;
@@ -186,14 +212,56 @@ user_service:
 	}
 
 notify_action:
-	if (wsi->mode == LWS_CONNMODE_WS_CLIENT)
-		n = LWS_CALLBACK_CLIENT_WRITEABLE;
-	else
-		n = LWS_CALLBACK_SERVER_WRITEABLE;
+#ifdef LWS_USE_HTTP2
+	/* 
+	 * we are the 'network wsi' for potentially many muxed child wsi with
+	 * no network connection of their own, who have to use us for all their
+	 * network actions.  So we use a round-robin scheme to share out the
+	 * POLLOUT notifications to our children.
+	 * 
+	 * But because any child could exhaust the socket's ability to take
+	 * writes, we can only let one child get notified each time.
+	 * 
+	 * In addition children may be closed / deleted / added between POLLOUT
+	 * notifications, so we can't hold pointers
+	 */
+	
+	if (wsi->mode != LWS_CONNMODE_HTTP2_SERVING) {
+		lwsl_info("%s: non http2\n", __func__);
+		goto notify;
+	}
 
-	return user_callback_handle_rxflow(wsi->protocol->callback, context,
-			wsi, (enum libwebsocket_callback_reasons) n,
-						      wsi->user_space, NULL, 0);
+	wsi->u.http2.requested_POLLOUT = 0;
+	if (!wsi->u.http2.initialized) {
+		lwsl_info("pollout on uninitialized http2 conn\n");
+		return 0;
+	}
+	
+	lwsl_info("%s: doing children\n", __func__);
+
+	wsi2 = wsi;
+	do {
+		wsi2 = wsi2->u.http2.next_child_wsi;
+		lwsl_info("%s: child %p\n", __func__, wsi2);
+		if (!wsi2)
+			continue;
+		if (!wsi2->u.http2.requested_POLLOUT)
+			continue;
+		wsi2->u.http2.requested_POLLOUT = 0;
+		if (lws_calllback_as_writeable(context, wsi2)) {
+			lwsl_debug("Closing POLLOUT child\n");
+			libwebsocket_close_and_free_session(context, wsi2,
+						LWS_CLOSE_STATUS_NOSTATUS);
+		}
+		wsi2 = wsi;
+	} while (wsi2 != NULL && !lws_send_pipe_choked(wsi));
+	
+	lwsl_info("%s: completed\n", __func__);
+	
+	return 0;
+notify:
+#endif
+	return lws_calllback_as_writeable(context, wsi);
 }
 
 
diff --git a/lib/ssl-http2.c b/lib/ssl-http2.c
index a0ab2771..445e87d9 100644
--- a/lib/ssl-http2.c
+++ b/lib/ssl-http2.c
@@ -53,14 +53,35 @@
 #ifdef LWS_OPENSSL_SUPPORT
 
 #if OPENSSL_VERSION_NUMBER >= 0x10002000L
-static int alpn_select_proto_cb(SSL* ssl,
-                         const unsigned char **out,
-                         unsigned char *outlen,
-                         const unsigned char *in, unsigned int inlen,
-                         void *arg)
+
+struct alpn_ctx {
+	unsigned char *data;
+	unsigned short len;
+};
+
+static int npn_cb(SSL *s, const unsigned char **data, unsigned int *len, void *arg)
 {
-	lwsl_err((char *)in);
-	return SSL_TLSEXT_ERR_OK; /* SSL_TLSEXT_ERR_NOACK */
+	struct alpn_ctx *alpn_ctx = arg;
+
+	lwsl_info("%s\n", __func__);
+	*data = alpn_ctx->data;
+	*len = alpn_ctx->len;
+
+	return SSL_TLSEXT_ERR_OK;
+}
+
+static int alpn_cb(SSL *s, const unsigned char **out,
+		unsigned char *outlen, const unsigned char *in,
+		unsigned int inlen, void *arg)
+{
+	struct alpn_ctx *alpn_ctx = arg;
+
+	if (SSL_select_next_proto((unsigned char **)out, outlen,
+				  alpn_ctx->data, alpn_ctx->len, in, inlen) !=
+							OPENSSL_NPN_NEGOTIATED)
+		return SSL_TLSEXT_ERR_NOACK;
+
+	return SSL_TLSEXT_ERR_OK;
 }
 #endif
 
@@ -68,13 +89,68 @@ LWS_VISIBLE void
 lws_context_init_http2_ssl(struct libwebsocket_context *context)
 {
 #if OPENSSL_VERSION_NUMBER >= 0x10002000L
+	static struct alpn_ctx protos = { (unsigned char *)
+						"\x05h2-14"
+						"\x08http/1.1",
+						6 + 9 };
+
+	SSL_CTX_set_next_protos_advertised_cb(context->ssl_ctx, npn_cb, &protos);
+	
 	// ALPN selection callback
-	SSL_CTX_set_alpn_select_cb(context->ssl_ctx, alpn_select_proto_cb, NULL);
+	SSL_CTX_set_alpn_select_cb(context->ssl_ctx, alpn_cb, &protos);
 	lwsl_notice(" HTTP2 / ALPN enabled\n");
 #else
 	lwsl_notice(" HTTP2 / ALPN configured but not supported by OpenSSL version 0x%x\n", OPENSSL_VERSION_NUMBER);
 #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
 }
 
+void lws_http2_configure_if_upgraded(struct libwebsocket *wsi)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+	struct allocated_headers *ah;
+	const unsigned char *name;
+	unsigned len;
+	const char *method = "alpn";
+
+	SSL_get0_alpn_selected(wsi->ssl, &name, &len);
+	
+	if (!len) {
+		SSL_get0_next_proto_negotiated(wsi->ssl, &name, &len);
+		method = "npn";
+	}
+	
+	if (len) {
+		lwsl_info("negotiated %s using %s\n", name, method);
+		wsi->use_ssl = 1;
+		if (strncmp((char *)name, "http/1.1", 8) == 0)
+			return;
+		
+		/* http2 */
+		
+		wsi->mode = LWS_CONNMODE_HTTP2_SERVING;
+		wsi->state = WSI_STATE_HTTP2_AWAIT_CLIENT_PREFACE;
+		
+		/* adopt the header info */
+
+		ah = wsi->u.hdr.ah;
+
+		wsi->mode = LWS_CONNMODE_HTTP2_SERVING;
+
+		/* union transition */
+		memset(&wsi->u, 0, sizeof(wsi->u));
+		
+		/* http2 union member has http union struct at start */
+		wsi->u.http.ah = ah;
+		
+		lws_http2_init(&wsi->u.http2.peer_settings);
+		lws_http2_init(&wsi->u.http2.my_settings);
+		
+		/* HTTP2 union */
+		
+	} else
+		lwsl_info("no npn/alpn upgrade\n");
+#endif
+}
+
 #endif
 #endif
\ No newline at end of file
diff --git a/lib/ssl.c b/lib/ssl.c
index 7bec931c..b37f1bb8 100644
--- a/lib/ssl.c
+++ b/lib/ssl.c
@@ -593,6 +593,8 @@ accepted:
 
 		wsi->mode = LWS_CONNMODE_HTTP_SERVING;
 
+		lws_http2_configure_if_upgraded(wsi);
+
 		lwsl_debug("accepted new SSL conn\n");
 		break;
 	}
diff --git a/test-server/test-server.c b/test-server/test-server.c
index 04f0b34e..2ab28f78 100644
--- a/test-server/test-server.c
+++ b/test-server/test-server.c
@@ -345,8 +345,9 @@ static int callback_http(struct libwebsocket_context *context,
 		/*
 		 * we can send more of whatever it is we were sending
 		 */
-
+lwsl_info("LWS_CALLBACK_HTTP_WRITEABLE\n");
 		do {
+			lwsl_info("a\n");
 			n = read(pss->fd, buffer + LWS_SEND_BUFFER_PRE_PADDING,
 				 sizeof (buffer) - LWS_SEND_BUFFER_PRE_PADDING);
 			/* problem reading, close conn */
@@ -355,7 +356,7 @@ static int callback_http(struct libwebsocket_context *context,
 			/* sent it all, close conn */
 			if (n == 0)
 				goto flush_bail;
-
+			lwsl_info("b\n");
 			/*
 			 * To support HTTP2, must take care about preamble space
 			 * and identify when we send the last frame
@@ -366,13 +367,14 @@ static int callback_http(struct libwebsocket_context *context,
 			if (m < 0)
 				/* write failed, close conn */
 				goto bail;
+						lwsl_info("c\n");
 			/*
 			 * http2 won't do this
 			 */
 			if (m != n)
 				/* partial write, adjust */
 				lseek(pss->fd, m - n, SEEK_CUR);
-
+			lwsl_info("d\n");
 			if (m) /* while still active, extend timeout */
 				libwebsocket_set_timeout(wsi,
 					PENDING_TIMEOUT_HTTP_CONTENT, 5);
@@ -382,8 +384,9 @@ static int callback_http(struct libwebsocket_context *context,
 				break;
 
 		} while (!lws_send_pipe_choked(wsi));
-		
+					lwsl_info("e\n");
 		libwebsocket_callback_on_writable(context, wsi);
+					lwsl_info("f\n");
 		break;
 flush_bail:
 		/* true if still partial pending */