introduce-ssl-client-connections--flow-control.patch

Signed-off-by: Andy Green <andy@warmcat.com>
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index 1c4bd17..8d46209 100644
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -21,11 +21,6 @@
 
 #include "private-libwebsockets.h"
 
-#ifdef LWS_OPENSSL_SUPPORT
-SSL_CTX *ssl_ctx;
-int use_ssl;
-#endif
-
 void
 libwebsocket_close_and_free_session(struct libwebsocket *wsi)
 {
@@ -49,7 +44,7 @@
 /*	fprintf(stderr, "closing fd=%d\n", wsi->sock); */
 
 #ifdef LWS_OPENSSL_SUPPORT
-	if (use_ssl) {
+	if (wsi->ssl) {
 		n = SSL_get_fd(wsi->ssl);
 		SSL_shutdown(wsi->ssl);
 		close(n);
@@ -93,6 +88,19 @@
 			goto nuke_this;
 		}
 
+		/* the guy requested a callback when it was OK to write */
+
+		if ((unsigned long)this->wsi[client] > LWS_MAX_PROTOCOLS &&
+					  this->fds[client].revents & POLLOUT) {
+
+			this->fds[client].events &= ~POLLOUT;
+
+			this->wsi[client]->protocol->callback(this->wsi[client],
+				LWS_CALLBACK_CLIENT_WRITEABLE,
+				this->wsi[client]->user_space,
+				NULL, 0);
+		}
+
 		/* any incoming data ready? */
 
 		if (!(this->fds[client].revents & POLLIN))
@@ -158,7 +166,7 @@
 		}
 
 #ifdef LWS_OPENSSL_SUPPORT
-		if (this->use_ssl)
+		if (this->wsi[client]->ssl)
 			n = SSL_read(this->wsi[client]->ssl, buf, sizeof buf);
 		else
 #endif
@@ -218,8 +226,8 @@
 		libwebsocket_close_and_free_session(this->wsi[client]);
 
 #ifdef LWS_OPENSSL_SUPPORT
-	if (ssl_ctx)
-		SSL_CTX_free(ssl_ctx);
+	if (this->ssl_ctx)
+		SSL_CTX_free(this->ssl_ctx);
 #endif
 
 	if (this)
@@ -336,9 +344,12 @@
 		}
 
 #ifdef LWS_OPENSSL_SUPPORT
+		this->wsi[this->fds_count]->ssl = NULL;
+
 		if (this->use_ssl) {
 
-			this->wsi[this->fds_count]->ssl = SSL_new(ssl_ctx);
+			this->wsi[this->fds_count]->ssl =
+							 SSL_new(this->ssl_ctx);
 			if (this->wsi[this->fds_count]->ssl == NULL) {
 				fprintf(stderr, "SSL_new failed: %s\n",
 				    ERR_error_string(SSL_get_error(
@@ -440,7 +451,8 @@
 		close(this->fds[0].fd);
 
 #ifdef LWS_OPENSSL_SUPPORT
-	SSL_CTX_free(ssl_ctx);
+	if (this->ssl_ctx)
+		SSL_CTX_free(this->ssl_ctx);
 #endif
 
 	if (this)
@@ -453,6 +465,91 @@
 	return 1;
 }
 
+/**
+ * libwebsocket_callback_on_writable() - Request a callback when this socket
+ *					 becomes able to be written to without
+ *					 blocking
+ *
+ * @wsi:	Websocket connection instance to get callback for
+ */
+
+int
+libwebsocket_callback_on_writable(struct libwebsocket *wsi)
+{
+	struct libwebsocket_context *this = wsi->protocol->owning_server;
+	int n;
+
+	for (n = this->count_protocols + 1; n < this->fds_count; n++)
+		if (this->wsi[n] == wsi) {
+			this->fds[n].events |= POLLOUT;
+			return 0;
+		}
+
+	fprintf(stderr, "libwebsocket_callback_on_writable "
+							"didn't find socket\n");
+	return 1;
+}
+
+/**
+ * libwebsocket_callback_on_writable_all_protocol() - Request a callback for
+ *			all connections using the given protocol when it
+ *			becomes possible to write to each socket without
+ *			blocking in turn.
+ *
+ * @protocol:	Protocol whose connections will get callbacks
+ */
+
+int
+libwebsocket_callback_on_writable_all_protocol(
+				  const struct libwebsocket_protocols *protocol)
+{
+	struct libwebsocket_context *this = protocol->owning_server;
+	int n;
+
+	for (n = this->count_protocols + 1; n < this->fds_count; n++)
+		if ((unsigned long)this->wsi[n] > LWS_MAX_PROTOCOLS)
+			if (this->wsi[n]->protocol == protocol)
+				this->fds[n].events |= POLLOUT;
+
+	return 0;
+}
+
+/**
+ * libwebsocket_rx_flow_control() - Enable and disable socket servicing for
+ *				receieved packets.
+ *
+ * If the output side of a server process becomes choked, this allows flow
+ * control for the input side.
+ *
+ * @wsi:	Websocket connection instance to get callback for
+ * @enable:	0 = disable read servicing for this connection, 1 = enable
+ */
+
+int
+libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable)
+{
+	struct libwebsocket_context *this = wsi->protocol->owning_server;
+	int n;
+
+	for (n = this->count_protocols + 1; n < this->fds_count; n++)
+		if (this->wsi[n] == wsi) {
+			if (enable)
+				this->fds[n].events |= POLLIN;
+			else
+				this->fds[n].events &= ~POLLIN;
+
+			return 0;
+		}
+
+	fprintf(stderr, "libwebsocket_callback_on_writable "
+						     "unable to find socket\n");
+	return 1;
+}
+
+static void sigpipe_handler(int x)
+{
+}
+
 
 /**
  * libwebsocket_create_context() - Create the websocket handler
@@ -515,47 +612,103 @@
 #ifdef LWS_OPENSSL_SUPPORT
 	SSL_METHOD *method;
 	char ssl_err_buf[512];
-
-	use_ssl = ssl_cert_filepath != NULL && ssl_private_key_filepath != NULL;
-	if (use_ssl)
-		fprintf(stderr, " Compiled with SSL support, using it\n");
-	else
-		fprintf(stderr, " Compiled with SSL support, not using it\n");
-
-#else
-	if (ssl_cert_filepath != NULL && ssl_private_key_filepath != NULL) {
-		fprintf(stderr, " Not compiled for OpenSSl support!\n");
-		return NULL;
-	}
-	fprintf(stderr, " Compiled without SSL support, serving unencrypted\n");
 #endif
 
+	this = malloc(sizeof(struct libwebsocket_context));
+	if (!this) {
+		fprintf(stderr, "No memory for websocket context\n");
+		return NULL;
+	}
+	this->protocols = protocols;
+	this->listen_port = port;
+
+	if (port) {
+
 #ifdef LWS_OPENSSL_SUPPORT
-	if (use_ssl) {
-		SSL_library_init();
+		this->use_ssl = ssl_cert_filepath != NULL &&
+					       ssl_private_key_filepath != NULL;
+		if (this->use_ssl)
+			fprintf(stderr, " Compiled with SSL support, "
+								  "using it\n");
+		else
+			fprintf(stderr, " Compiled with SSL support, "
+							      "not using it\n");
 
-		OpenSSL_add_all_algorithms();
-		SSL_load_error_strings();
-
-		/*
-		 * Firefox insists on SSLv23 not SSLv3
-		 * Konq disables SSLv2 by default now, SSLv23 works
-		 */
-
-		method = (SSL_METHOD *)SSLv23_server_method();
-		if (!method) {
-			fprintf(stderr, "problem creating ssl method: %s\n",
-				ERR_error_string(ERR_get_error(), ssl_err_buf));
+#else
+		if (ssl_cert_filepath != NULL &&
+					     ssl_private_key_filepath != NULL) {
+			fprintf(stderr, " Not compiled for OpenSSl support!\n");
 			return NULL;
 		}
-		ssl_ctx = SSL_CTX_new(method);	/* create context */
-		if (!ssl_ctx) {
-			printf("problem creating ssl context: %s\n",
-				ERR_error_string(ERR_get_error(), ssl_err_buf));
-			return NULL;
-		}
+		fprintf(stderr, " Compiled without SSL support, "
+						       "serving unencrypted\n");
+#endif
+	}
+
+	/* ignore SIGPIPE */
+
+	signal(SIGPIPE, sigpipe_handler);
+
+
+#ifdef LWS_OPENSSL_SUPPORT
+
+	/* basic openssl init */
+
+	SSL_library_init();
+
+	OpenSSL_add_all_algorithms();
+	SSL_load_error_strings();
+
+	/*
+	 * Firefox insists on SSLv23 not SSLv3
+	 * Konq disables SSLv2 by default now, SSLv23 works
+	 */
+
+	method = (SSL_METHOD *)SSLv23_server_method();
+	if (!method) {
+		fprintf(stderr, "problem creating ssl method: %s\n",
+			ERR_error_string(ERR_get_error(), ssl_err_buf));
+		return NULL;
+	}
+	this->ssl_ctx = SSL_CTX_new(method);	/* create context */
+	if (!this->ssl_ctx) {
+		fprintf(stderr, "problem creating ssl context: %s\n",
+			ERR_error_string(ERR_get_error(), ssl_err_buf));
+		return NULL;
+	}
+
+	/* client context */
+
+	method = (SSL_METHOD *)SSLv23_client_method();
+	if (!method) {
+		fprintf(stderr, "problem creating ssl method: %s\n",
+			ERR_error_string(ERR_get_error(), ssl_err_buf));
+		return NULL;
+	}
+	this->ssl_client_ctx = SSL_CTX_new(method);	/* create context */
+	if (!this->ssl_client_ctx) {
+		fprintf(stderr, "problem creating ssl context: %s\n",
+			ERR_error_string(ERR_get_error(), ssl_err_buf));
+		return NULL;
+	}
+
+
+	/* openssl init for cert verification (used with client sockets) */
+
+	if (!SSL_CTX_load_verify_locations(this->ssl_client_ctx, NULL,
+						    LWS_OPENSSL_CLIENT_CERTS)) {
+		fprintf(stderr, "Unable to load SSL Client certs from %s "
+			"(set by --with-client-cert-dir= in configure) -- "
+			" client ssl isn't going to work",
+						      LWS_OPENSSL_CLIENT_CERTS);
+	}
+
+	if (this->use_ssl) {
+
+		/* openssl init for server sockets */
+
 		/* set the local certificate from CertFile */
-		n = SSL_CTX_use_certificate_file(ssl_ctx,
+		n = SSL_CTX_use_certificate_file(this->ssl_ctx,
 					ssl_cert_filepath, SSL_FILETYPE_PEM);
 		if (n != 1) {
 			fprintf(stderr, "problem getting cert '%s': %s\n",
@@ -564,7 +717,7 @@
 			return NULL;
 		}
 		/* set the private key from KeyFile */
-		if (SSL_CTX_use_PrivateKey_file(ssl_ctx,
+		if (SSL_CTX_use_PrivateKey_file(this->ssl_ctx,
 						ssl_private_key_filepath,
 						       SSL_FILETYPE_PEM) != 1) {
 			fprintf(stderr, "ssl problem getting key '%s': %s\n",
@@ -573,7 +726,7 @@
 			return NULL;
 		}
 		/* verify private key */
-		if (!SSL_CTX_check_private_key(ssl_ctx)) {
+		if (!SSL_CTX_check_private_key(this->ssl_ctx)) {
 			fprintf(stderr, "Private SSL key doesn't match cert\n");
 			return NULL;
 		}
@@ -587,12 +740,6 @@
 	if (lws_b64_selftest())
 		return NULL;
 
-
-	this = malloc(sizeof(struct libwebsocket_context));
-
-	this->protocols = protocols;
-	this->listen_port = port;
-
 	/* set up our external listening socket we serve on */
 
 	if (port) {
@@ -641,9 +788,6 @@
 	this->fds[0].fd = sockfd;
 	this->fds[0].events = POLLIN;
 	this->count_protocols = 0;
-#ifdef LWS_OPENSSL_SUPPORT
-	this->use_ssl = use_ssl;
-#endif
 
 	if (port) {
 		listen(sockfd, 5);