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

Signed-off-by: Andy Green <andy@warmcat.com>
diff --git a/Makefile.am b/Makefile.am
index bb67621..dec9704 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,2 +1,2 @@
-SUBDIRS=lib test-server 
 
+SUBDIRS=lib test-server
diff --git a/Makefile.in b/Makefile.in
index 02a4a84..20e9dba 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -181,6 +181,7 @@
 build_os = @build_os@
 build_vendor = @build_vendor@
 builddir = @builddir@
+clientcertdir = @clientcertdir@
 datadir = @datadir@
 datarootdir = @datarootdir@
 docdir = @docdir@
@@ -214,7 +215,7 @@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-SUBDIRS = lib test-server 
+SUBDIRS = lib test-server
 all: config.h
 	$(MAKE) $(AM_MAKEFLAGS) all-recursive
 
diff --git a/README-test-server b/README-test-server
index 9a48db2..f10520e 100644
--- a/README-test-server
+++ b/README-test-server
@@ -33,6 +33,10 @@
 			to disable the built-in ones and force use
 			of the libcrypto (part of openssl) ones.
 
+--with-client-cert-dir=dir   tells the client ssl support where to
+			     look for trust certificates to validate
+			     the remote certificate against.
+
 Testing server with a browser
 -----------------------------
 
@@ -44,11 +48,8 @@
 script in there on the browser to open a websocket connection.
 Incrementing numbers should appear in the browser display.
 
-Using SSL
----------
-
-The client side operation does not support SSL yet, but the
-server side does.
+Using SSL on the server side
+----------------------------
 
 To test it using SSL/WSS, just run the test server with
 
@@ -68,6 +69,7 @@
 test-server.c is all that is needed to use libwebsockets for
 serving both the script html over http and websockets.
 
+
 Forkless operation
 ------------------
 
@@ -76,6 +78,7 @@
 configure option --nofork and simply call libwebsocket_service()
 from your own main loop as shown in the test app sources.
 
+
 Testing websocket client support
 --------------------------------
 
@@ -91,6 +94,19 @@
 same time you will be able to see the circles being drawn.
 
 
+Testing SSL on the client side
+------------------------------
+
+To test SSL/WSS client action, just run the client test with
+
+$ libwebsockets-test-client localhost --ssl
+
+By default the client test applet is set to accept selfsigned
+certificates used by the test server, this is indicated by the
+use_ssl var being set to 2.  Set it to 1 to reject any server
+certificate that it doesn't have a trusted CA cert for.
+
+
 Websocket version supported
 ---------------------------
 
diff --git a/configure b/configure
index 3e0ce28..4ff42ac 100755
--- a/configure
+++ b/configure
@@ -616,6 +616,7 @@
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+clientcertdir
 LIBCRYPTO_FALSE
 LIBCRYPTO_TRUE
 CPP
@@ -739,6 +740,7 @@
 enable_openssl
 enable_nofork
 enable_libcrypto
+with_client_cert_dir
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1383,7 +1385,7 @@
   --disable-libtool-lock  avoid locking (might break parallel builds)
   --enable-openssl  Enables https support and needs openssl libs
   --enable-nofork  Disables fork-related options
-  --enable-libcrypto  Use libcrypto MD5 and SHA1 implemntations
+  --enable-libcrypto  Use libcrypto MD5 and SHA1 implementations
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -1393,6 +1395,8 @@
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
   --with-sysroot=DIR Search for dependent libraries within DIR
                         (or the compiler's sysroot if not specified).
+  --with-client-cert-dir  directory containing client certs, defaults to
+                          /etc/pki/tls/certs/
 
 Some influential environment variables:
   CC          C compiler command
@@ -11963,6 +11967,7 @@
 
 
 
+
 #
 #
 #
@@ -12285,6 +12290,23 @@
 
 
 
+#
+#
+#
+
+# Check whether --with-client-cert-dir was given.
+if test "${with_client_cert_dir+set}" = set; then :
+  withval=$with_client_cert_dir; clientcertdir=$withval
+else
+  clientcertdir=/etc/pki/tls/certs/
+
+fi
+
+
+
+
+
+
 
 # Checks for header files.
 for ac_header in fcntl.h netinet/in.h stdlib.h string.h sys/socket.h unistd.h
diff --git a/configure.ac b/configure.ac
index 019b3f9..00b69f4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,6 +17,7 @@
 AC_PROG_MAKE_SET
 AC_CONFIG_MACRO_DIR([m4])
 
+
 #
 #
 #
@@ -48,7 +49,7 @@
 #
 #
 AC_ARG_ENABLE(libcrypto,
- [  --enable-libcrypto  Use libcrypto MD5 and SHA1 implemntations],
+ [  --enable-libcrypto  Use libcrypto MD5 and SHA1 implementations],
  [ libcrypto=yes
  ])
 
@@ -59,6 +60,19 @@
 AM_CONDITIONAL(LIBCRYPTO, test x$libcrypto = xyes)
 
 
+#
+#
+#
+AC_ARG_WITH([client-cert-dir],
+[AS_HELP_STRING([--with-client-cert-dir],[directory containing client certs, defaults to /etc/pki/tls/certs/])],
+[clientcertdir=$withval],
+[clientcertdir=/etc/pki/tls/certs/]
+)
+AC_SUBST([clientcertdir])
+
+AC_SUBST([CFLAGS])
+
+
 
 # Checks for header files.
 AC_CHECK_HEADERS([fcntl.h netinet/in.h stdlib.h string.h sys/socket.h unistd.h])
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 2280bdc..8328c29 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -12,7 +12,7 @@
 dist_libwebsockets_la_SOURCES += md5.c sha-1.c
 endif
 
-libwebsockets_la_CFLAGS=-Wall -Werror -std=gnu99 -pedantic -rdynamic -fPIC -c
+libwebsockets_la_CFLAGS:=-rdynamic -fPIC -Wall -Werror -std=gnu99 -pedantic -c -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\"
 libwebsockets_la_LDFLAGS=-version-info 0:2
 
 all-local:
diff --git a/lib/Makefile.in b/lib/Makefile.in
index 9f58996..775baba 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -183,6 +183,7 @@
 build_os = @build_os@
 build_vendor = @build_vendor@
 builddir = @builddir@
+clientcertdir = @clientcertdir@
 datadir = @datadir@
 datarootdir = @datarootdir@
 docdir = @docdir@
@@ -221,7 +222,7 @@
 dist_libwebsockets_la_SOURCES = libwebsockets.c handshake.c parsers.c \
 	libwebsockets.h base64-decode.c client-handshake.c \
 	private-libwebsockets.h $(am__append_1)
-libwebsockets_la_CFLAGS = -Wall -Werror -std=gnu99 -pedantic -rdynamic -fPIC -c
+libwebsockets_la_CFLAGS := -rdynamic -fPIC -Wall -Werror -std=gnu99 -pedantic -c -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\"
 libwebsockets_la_LDFLAGS = -version-info 0:2
 all: all-am
 
diff --git a/lib/client-handshake.c b/lib/client-handshake.c
index 64f72cb..e93ce99 100644
--- a/lib/client-handshake.c
+++ b/lib/client-handshake.c
@@ -9,8 +9,10 @@
 void
 strtolower(char *s)
 {
-	while (*s)
-		*s++ = tolower(*s);
+	while (*s) {
+		*s = tolower(*s);
+		s++;
+	}
 }
 
 void
@@ -53,7 +55,7 @@
 	/* shut down reasonably cleanly */
 
 #ifdef LWS_OPENSSL_SUPPORT
-	if (use_ssl) {
+	if (wsi->ssl) {
 		n = SSL_get_fd(wsi->ssl);
 		SSL_shutdown(wsi->ssl);
 		close(n);
@@ -67,10 +69,29 @@
 #endif
 }
 
+
+/**
+ * libwebsocket_client_connect() - Connect to another websocket server
+ * @this:	Websocket context
+ * @address:	Remote server address, eg, "myserver.com"
+ * @port:	Port to connect to on the remote server, eg, 80
+ * @ssl_connection:	0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
+ *			signed certs
+ * @path:	Websocket path on server
+ * @host:	Hostname on server
+ * @origin:	Socket origin name
+ * @protocol:	Comma-separated list of protocols being asked for from
+ *		the server, or just one.  The server will pick the one it
+ *		likes best.
+ *
+ *	This function creates a connection to a remote server
+ */
+
 struct libwebsocket *
-libwebsocket_client_connect(struct libwebsocket_context *clients,
+libwebsocket_client_connect(struct libwebsocket_context *this,
 			      const char *address,
 			      int port,
+			      int ssl_connection,
 			      const char *path,
 			      const char *host,
 			      const char *origin,
@@ -94,12 +115,22 @@
 	int okay = 0;
 	struct libwebsocket *wsi;
 	int n;
+#ifdef LWS_OPENSSL_SUPPORT
+	char ssl_err_buf[512];
+#else
+	if (ssl_connection) {
+		fprintf(stderr, "libwebsockets not configured for ssl\n");
+		return NULL;
+	}
+#endif
 
 	wsi = malloc(sizeof(struct libwebsocket));
-	if (wsi == NULL)
+	if (wsi == NULL) {
+		fprintf(stderr, "Out of memort allocing new connection\n");
 		return NULL;
+	}
 
-	clients->wsi[clients->fds_count] = wsi;
+	this->wsi[this->fds_count] = wsi;
 
 	wsi->ietf_spec_revision = 4;
 	wsi->name_buffer_pos = 0;
@@ -137,10 +168,36 @@
 
 	if (connect(wsi->sock, (struct sockaddr *)&server_addr,
 					      sizeof(struct sockaddr)) == -1)  {
-		fprintf(stderr, "Connect failed");
+		fprintf(stderr, "Connect failed\n");
 		goto bail1;
 	}
 
+#ifdef LWS_OPENSSL_SUPPORT
+	if (ssl_connection) {
+
+		wsi->ssl = SSL_new(this->ssl_client_ctx);
+		wsi->client_bio = BIO_new_socket(wsi->sock, BIO_NOCLOSE);
+		SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio);
+
+		if (SSL_connect(wsi->ssl) <= 0) {
+			fprintf(stderr, "SSL connect error %s\n",
+				ERR_error_string(ERR_get_error(), ssl_err_buf));
+			goto bail2;
+		}
+
+		n = SSL_get_verify_result(wsi->ssl);
+		if (n != X509_V_OK) {
+			if (n == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT &&
+							    ssl_connection == 2)
+				goto cert_okay;
+
+		    fprintf(stderr, "server's cert didn't look good %d\n", n);
+		    goto bail2;
+		}
+	} else
+		wsi->ssl = NULL;
+cert_okay:
+#endif
 	/*
 	 * create the random key
 	 */
@@ -199,7 +256,17 @@
 
 	/* send our request to the server */
 
-	n = send(wsi->sock, pkt, p - pkt, 0);
+#ifdef LWS_OPENSSL_SUPPORT
+	if (ssl_connection)
+		n = SSL_write(wsi->ssl, pkt, p - pkt);
+	else
+#endif
+		n = send(wsi->sock, pkt, p - pkt, 0);
+
+	if (n < 0) {
+		fprintf(stderr, "ERROR writing to client socket\n");
+		goto bail2;
+	}
 
 	wsi->parser_state = WSI_TOKEN_NAME_PART;
 
@@ -230,7 +297,13 @@
 	 *  Sec-WebSocket-Protocol: chat
 	 */
 
-	len = recv(wsi->sock, pkt, sizeof pkt, 0);
+#ifdef LWS_OPENSSL_SUPPORT
+	if (ssl_connection)
+		len = SSL_read(wsi->ssl, pkt, sizeof pkt);
+	else
+#endif
+		len = recv(wsi->sock, pkt, sizeof pkt, 0);
+
 	if (len < 0) {
 		fprintf(stderr, "libwebsocket_client_handshake read error\n");
 		goto bail2;
@@ -300,7 +373,7 @@
 	if (!wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len) {
 
 		/* no protocol name to work from, default to first protocol */
-		wsi->protocol = &clients->protocols[0];
+		wsi->protocol = &this->protocols[0];
 
 		goto check_accept;
 	}
@@ -331,10 +404,10 @@
 	 */
 	n = 0;
 	wsi->protocol = NULL;
-	while (clients->protocols[n].callback) {
+	while (this->protocols[n].callback) {
 		if (strcmp(wsi->utf8_token[WSI_TOKEN_PROTOCOL].token,
-				       clients->protocols[n].name) == 0)
-			wsi->protocol = &clients->protocols[n];
+				       this->protocols[n].name) == 0)
+			wsi->protocol = &this->protocols[n];
 		n++;
 	}
 
@@ -373,15 +446,21 @@
 
 	/* okay he is good to go */
 
-	clients->fds[clients->fds_count].fd = wsi->sock;
-	clients->fds[clients->fds_count].revents = 0;
-	clients->fds[clients->fds_count++].events = POLLIN;
+	this->fds[this->fds_count].fd = wsi->sock;
+	this->fds[this->fds_count].revents = 0;
+	this->fds[this->fds_count++].events = POLLIN;
 
 	wsi->state = WSI_STATE_ESTABLISHED;
 	wsi->client_mode = 1;
 
 	fprintf(stderr, "handshake OK for protocol %s\n", wsi->protocol->name);
 
+	/* call him back to inform him he is up */
+
+	wsi->protocol->callback(wsi,
+			 LWS_CALLBACK_CLIENT_ESTABLISHED,
+			 wsi->user_space,
+			 NULL, 0);
 	return wsi;
 
 
diff --git a/lib/handshake.c b/lib/handshake.c
index d6928d7..d126809 100644
--- a/lib/handshake.c
+++ b/lib/handshake.c
@@ -131,7 +131,7 @@
 	strcpy(p, wsi->utf8_token[WSI_TOKEN_ORIGIN].token);
 	p += wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len;
 #ifdef LWS_OPENSSL_SUPPORT
-	if (use_ssl) {
+	if (wsi->ssl) {
 		strcpy(p,   "\x0d\x0aSec-WebSocket-Location: wss://");
 		p += strlen("\x0d\x0aSec-WebSocket-Location: wss://");
 	} else {
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);
diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index 57ab481..a486221 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -26,9 +26,11 @@
 
 enum libwebsocket_callback_reasons {
 	LWS_CALLBACK_ESTABLISHED,
+	LWS_CALLBACK_CLIENT_ESTABLISHED,
 	LWS_CALLBACK_CLOSED,
 	LWS_CALLBACK_RECEIVE,
 	LWS_CALLBACK_CLIENT_RECEIVE,
+	LWS_CALLBACK_CLIENT_WRITEABLE,
 	LWS_CALLBACK_HTTP,
 	LWS_CALLBACK_BROADCAST
 };
@@ -42,7 +44,9 @@
 
 	LWS_WRITE_CLOSE,
 	LWS_WRITE_PING,
-	LWS_WRITE_PONG
+	LWS_WRITE_PONG,
+
+	LWS_WRITE_NO_FIN = 0x40
 };
 
 struct libwebsocket;
@@ -67,15 +71,25 @@
  *	You get an opportunity to initialize user data when called back with
  *	LWS_CALLBACK_ESTABLISHED reason.
  *
- *	LWS_CALLBACK_ESTABLISHED:  after successful websocket handshake
+ *	LWS_CALLBACK_ESTABLISHED:  after the server completes a handshake with
+ *				an incoming client
+ *
+ *      LWS_CALLBACK_CLIENT_ESTABLISHED: after your client connection completed
+ *				a handshake with the remote server
  *
  *	LWS_CALLBACK_CLOSED: when the websocket session ends
  *
  *	LWS_CALLBACK_BROADCAST: signal to send to client (you would use
  *				libwebsocket_write() taking care about the
  *				special buffer requirements
- *	LWS_CALLBACK_RECEIVE: data has appeared for the server, it can be
- *				found at *in and is len bytes long
+ *
+ *	LWS_CALLBACK_RECEIVE: data has appeared for this server endpoint from a
+ *				remote client, it can be found at *in and is
+ *				len bytes long
+ *
+ *	LWS_CALLBACK_CLIENT_RECEIVE: data has appeared from the server for the
+ *				client connection, it can be found at *in and
+ *				is len bytes long
  *
  *	LWS_CALLBACK_HTTP: an http request has come from a client that is not
  *				asking to upgrade the connection to a websocket
@@ -85,6 +99,13 @@
  *				@in points to the URI path requested and
  *				libwebsockets_serve_http_file() makes it very
  *				simple to send back a file to the client.
+ *
+ *	LWS_CALLBACK_CLIENT_WRITEABLE:  if you call
+ *		libwebsocket_callback_on_writable() on a connection, you will
+ *		get this callback coming when the connection socket is able to
+ *		accept another write packet without blocking.  If it already
+ *		was able to take another packet without blocking, you'll get
+ *		this callback at the next call to the service loop function.
  */
 extern int callback(struct libwebsocket *wsi,
 			 enum libwebsocket_callback_reasons reason, void *user,
@@ -197,6 +218,17 @@
 extern const struct libwebsocket_protocols *
 libwebsockets_get_protocol(struct libwebsocket *wsi);
 
+extern int
+libwebsocket_callback_on_writable(struct libwebsocket *wsi);
+
+extern int
+libwebsocket_callback_on_writable_all_protocol(
+				 const struct libwebsocket_protocols *protocol);
+
+
+extern int
+libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable);
+
 extern size_t
 libwebsockets_remaining_packet_payload(struct libwebsocket *wsi);
 
@@ -204,6 +236,7 @@
 libwebsocket_client_connect(struct libwebsocket_context *clients,
 			      const char *address,
 			      int port,
+			      int ssl_connection,
 			      const char *path,
 			      const char *host,
 			      const char *origin,
diff --git a/lib/parsers.c b/lib/parsers.c
index 9d9efb3..8d56221 100644
--- a/lib/parsers.c
+++ b/lib/parsers.c
@@ -977,8 +977,6 @@
  *	packet while not burdening the user code with any protocol knowledge.
  */
 
- /* FIXME FIN bit */
-
 int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf,
 			  size_t len, enum libwebsocket_write_protocol protocol)
 {
@@ -987,6 +985,11 @@
 	int post = 0;
 	unsigned int shift = 7;
 
+	if (len == 0) {
+		fprintf(stderr, "zero length libwebsocket_write attempt\n");
+		return 0;
+	}
+
 	if (protocol == LWS_WRITE_HTTP)
 		goto send_raw;
 
@@ -999,7 +1002,7 @@
 	/* chrome likes this as of 30 Oct */
 	/* Firefox 4.0b6 likes this as of 30 Oct */
 	case 0:
-		if (protocol == LWS_WRITE_BINARY) {
+		if ((protocol & 0xf) == LWS_WRITE_BINARY) {
 			/* in binary mode we send 7-bit used length blocks */
 			pre = 1;
 			while (len & (127 << shift)) {
@@ -1031,7 +1034,7 @@
 
 	case 4:
 
-		switch (protocol) {
+		switch (protocol & 0xf) {
 		case LWS_WRITE_TEXT:
 			n = LWS_WS_OPCODE_04__TEXT_FRAME;
 			break;
@@ -1054,12 +1057,8 @@
 			return -1;
 		}
 
-		/*
-		 * We don't really support the metaframe concept with FIN.
-		 * Just set FIN on every packet for now
-		 */
-
-		n |= 1 << 7;
+		if (!(protocol & LWS_WRITE_NO_FIN))
+			n |= 1 << 7;
 
 		if (len < 126) {
 			buf[-2] = n;
@@ -1130,10 +1129,9 @@
 		memcpy(&buf[0 - pre], wsi->frame_masking_nonce_04, 4);
 	}
 
-
 send_raw:
 #ifdef LWS_OPENSSL_SUPPORT
-	if (use_ssl) {
+	if (wsi->ssl) {
 		n = SSL_write(wsi->ssl, buf - pre, len + pre + post);
 		if (n < 0) {
 			fprintf(stderr, "ERROR writing to socket\n");
@@ -1149,6 +1147,7 @@
 #ifdef LWS_OPENSSL_SUPPORT
 	}
 #endif
+
 	debug("written %d bytes to client\n", (int)len);
 
 	return 0;
@@ -1199,6 +1198,8 @@
 	n = 1;
 	while (n > 0) {
 		n = read(fd, buf, 512);
+		if (n <= 0)
+			continue;
 		libwebsocket_write(wsi, (unsigned char *)buf, n,
 								LWS_WRITE_HTTP);
 	}
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index a263d83..dfeb373 100644
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -67,11 +67,6 @@
 }
 #endif
 
-#ifdef LWS_OPENSSL_SUPPORT
-extern SSL_CTX *ssl_ctx;
-extern int use_ssl;
-#endif
-
 
 #define MAX_CLIENTS 100
 #define LWS_MAX_HEADER_NAME_LENGTH 64
@@ -79,7 +74,7 @@
 #define LWS_INITIAL_HDR_ALLOC 256
 #define LWS_ADDITIONAL_HDR_ALLOC 64
 #define MAX_USER_RX_BUFFER 512
-#define MAX_BROADCAST_PAYLOAD 1024
+#define MAX_BROADCAST_PAYLOAD 2048
 #define LWS_MAX_PROTOCOLS 10
 
 #define MAX_WEBSOCKET_04_KEY_LEN 128
@@ -175,6 +170,8 @@
 	int listen_port;
 #ifdef LWS_OPENSSL_SUPPORT
 	int use_ssl;
+	SSL_CTX *ssl_ctx;
+	SSL_CTX *ssl_client_ctx;
 #endif
 	struct libwebsocket_protocols *protocols;
 	int count_protocols;
@@ -224,6 +221,7 @@
 
 #ifdef LWS_OPENSSL_SUPPORT
 	SSL *ssl;
+	BIO *client_bio;
 #endif
 
 	void *user_space;
diff --git a/lib/sha-1.c b/lib/sha-1.c
index 1bec395..aea5d6a 100644
--- a/lib/sha-1.c
+++ b/lib/sha-1.c
@@ -146,27 +146,31 @@
 
 	for (t = 0; t < 20; t++) {
 		s = t & 0x0f;
-		if (t >= 16) {
-			W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s));
-		}
+		if (t >= 16)
+			W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
+							W((s+2) & 0x0f) ^ W(s));
+
 		tmp = S(5, a) + F0(b, c, d) + e + W(s) + K(t);
 		e = d; d = c; c = S(30, b); b = a; a = tmp;
 	}
 	for (t = 20; t < 40; t++) {
 		s = t & 0x0f;
-		W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s));
+		W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
+							W((s+2) & 0x0f) ^ W(s));
 		tmp = S(5, a) + F1(b, c, d) + e + W(s) + K(t);
 		e = d; d = c; c = S(30, b); b = a; a = tmp;
 	}
 	for (t = 40; t < 60; t++) {
 		s = t & 0x0f;
-		W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s));
+		W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
+							W((s+2) & 0x0f) ^ W(s));
 		tmp = S(5, a) + F2(b, c, d) + e + W(s) + K(t);
 		e = d; d = c; c = S(30, b); b = a; a = tmp;
 	}
 	for (t = 60; t < 80; t++) {
 		s = t & 0x0f;
-		W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^ W((s+2) & 0x0f) ^ W(s));
+		W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
+							W((s+2) & 0x0f) ^ W(s));
 		tmp = S(5, a) + F3(b, c, d) + e + W(s) + K(t);
 		e = d; d = c; c = S(30, b); b = a; a = tmp;
 	}
diff --git a/libwebsockets-api-doc.html b/libwebsockets-api-doc.html
index 0016684..f649d79 100644
--- a/libwebsockets-api-doc.html
+++ b/libwebsockets-api-doc.html
@@ -58,6 +58,45 @@
 nothing is pending, or as soon as it services whatever was pending.
 </blockquote>
 <hr>
+<h2>libwebsocket_callback_on_writable - Request a callback when this socket becomes able to be written to without blocking</h2>
+<i>int</i>
+<b>libwebsocket_callback_on_writable</b>
+(<i>struct libwebsocket *</i> <b>wsi</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>wsi</b>
+<dd>Websocket connection instance to get callback for
+</dl>
+<hr>
+<h2>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.</h2>
+<i>int</i>
+<b>libwebsocket_callback_on_writable_all_protocol</b>
+(<i>const struct libwebsocket_protocols *</i> <b>protocol</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>protocol</b>
+<dd>Protocol whose connections will get callbacks
+</dl>
+<hr>
+<h2>libwebsocket_rx_flow_control - Enable and disable socket servicing for receieved packets.</h2>
+<i>int</i>
+<b>libwebsocket_rx_flow_control</b>
+(<i>struct libwebsocket *</i> <b>wsi</b>,
+<i>int</i> <b>enable</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>wsi</b>
+<dd>Websocket connection instance to get callback for
+<dt><b>enable</b>
+<dd>0 = disable read servicing for this connection, 1 = enable
+</dl>
+<h3>Description</h3>
+<blockquote>
+<p>
+If the output side of a server process becomes choked, this allows flow
+control for the input side.
+</blockquote>
+<hr>
 <h2>libwebsocket_create_context - Create the websocket handler</h2>
 <i>struct libwebsocket_context *</i>
 <b>libwebsocket_create_context</b>
@@ -258,6 +297,44 @@
 Many protocols won't care becuse their packets are always small.
 </blockquote>
 <hr>
+<h2>libwebsocket_client_connect - Connect to another websocket server</h2>
+<i>struct libwebsocket *</i>
+<b>libwebsocket_client_connect</b>
+(<i>struct libwebsocket_context *</i> <b>this</b>,
+<i>const char *</i> <b>address</b>,
+<i>int</i> <b>port</b>,
+<i>int</i> <b>ssl_connection</b>,
+<i>const char *</i> <b>path</b>,
+<i>const char *</i> <b>host</b>,
+<i>const char *</i> <b>origin</b>,
+<i>const char *</i> <b>protocol</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>this</b>
+<dd>Websocket context
+<dt><b>address</b>
+<dd>Remote server address, eg, "myserver.com"
+<dt><b>port</b>
+<dd>Port to connect to on the remote server, eg, 80
+<dt><b>ssl_connection</b>
+<dd>0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
+signed certs
+<dt><b>path</b>
+<dd>Websocket path on server
+<dt><b>host</b>
+<dd>Hostname on server
+<dt><b>origin</b>
+<dd>Socket origin name
+<dt><b>protocol</b>
+<dd>Comma-separated list of protocols being asked for from
+the server, or just one.  The server will pick the one it
+likes best.
+</dl>
+<h3>Description</h3>
+<blockquote>
+This function creates a connection to a remote server
+</blockquote>
+<hr>
 <h2>callback - User server actions</h2>
 <i>int</i>
 <b>callback</b>
@@ -293,7 +370,13 @@
 </blockquote>
 <h3>LWS_CALLBACK_ESTABLISHED</h3>
 <blockquote>
-after successful websocket handshake
+after the server completes a handshake with
+an incoming client
+</blockquote>
+<h3>LWS_CALLBACK_CLIENT_ESTABLISHED</h3>
+<blockquote>
+after your client connection completed
+a handshake with the remote server
 </blockquote>
 <h3>LWS_CALLBACK_CLOSED</h3>
 <blockquote>
@@ -307,8 +390,15 @@
 </blockquote>
 <h3>LWS_CALLBACK_RECEIVE</h3>
 <blockquote>
-data has appeared for the server, it can be
-found at *in and is len bytes long
+data has appeared for this server endpoint from a
+remote client, it can be found at *in and is
+len bytes long
+</blockquote>
+<h3>LWS_CALLBACK_CLIENT_RECEIVE</h3>
+<blockquote>
+data has appeared from the server for the
+client connection, it can be found at *in and
+is len bytes long
 </blockquote>
 <h3>LWS_CALLBACK_HTTP</h3>
 <blockquote>
@@ -321,6 +411,15 @@
 <b>libwebsockets_serve_http_file</b> makes it very
 simple to send back a file to the client.
 </blockquote>
+<h3>LWS_CALLBACK_CLIENT_WRITEABLE</h3>
+<blockquote>
+if you call
+<b>libwebsocket_callback_on_writable</b> on a connection, you will
+get this callback coming when the connection socket is able to
+accept another write packet without blocking.  If it already
+was able to take another packet without blocking, you'll get
+this callback at the next call to the service loop function.
+</blockquote>
 <hr>
 <h2>struct libwebsocket_protocols - List of protocols and handlers server supports.</h2>
 <b>struct libwebsocket_protocols</b> {<br>
diff --git a/test-server/Makefile.am b/test-server/Makefile.am
index 43d3c7c..c1083a5 100644
--- a/test-server/Makefile.am
+++ b/test-server/Makefile.am
@@ -3,6 +3,12 @@
 libwebsockets_test_server_LDADD=-L../lib -lwebsockets
 libwebsockets_test_client_SOURCES=test-client.c
 libwebsockets_test_client_LDADD=-L../lib -lwebsockets
+
+
+
+libwebsockets_test_server_CFLAGS:= -Wall -Werror -std=gnu99 -pedantic -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\"
+libwebsockets_test_client_CFLAGS:= -Wall -Werror -std=gnu99 -pedantic -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\"
+
 #
 # cook a random test cert and key
 # notice your real cert and key will want to be 0600 permissions
diff --git a/test-server/Makefile.in b/test-server/Makefile.in
index 03ad8a8..c7555af 100644
--- a/test-server/Makefile.in
+++ b/test-server/Makefile.in
@@ -48,14 +48,24 @@
 CONFIG_CLEAN_VPATH_FILES =
 am__installdirs = "$(DESTDIR)$(bindir)"
 PROGRAMS = $(bin_PROGRAMS)
-am_libwebsockets_test_client_OBJECTS = test-client.$(OBJEXT)
+am_libwebsockets_test_client_OBJECTS =  \
+	libwebsockets_test_client-test-client.$(OBJEXT)
 libwebsockets_test_client_OBJECTS =  \
 	$(am_libwebsockets_test_client_OBJECTS)
 libwebsockets_test_client_DEPENDENCIES =
-am_libwebsockets_test_server_OBJECTS = test-server.$(OBJEXT)
+libwebsockets_test_client_LINK = $(LIBTOOL) --tag=CC \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+	$(libwebsockets_test_client_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+am_libwebsockets_test_server_OBJECTS =  \
+	libwebsockets_test_server-test-server.$(OBJEXT)
 libwebsockets_test_server_OBJECTS =  \
 	$(am_libwebsockets_test_server_OBJECTS)
 libwebsockets_test_server_DEPENDENCIES =
+libwebsockets_test_server_LINK = $(LIBTOOL) --tag=CC \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+	$(libwebsockets_test_server_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
 DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
 depcomp = $(SHELL) $(top_srcdir)/depcomp
 am__depfiles_maybe = depfiles
@@ -156,6 +166,7 @@
 build_os = @build_os@
 build_vendor = @build_vendor@
 builddir = @builddir@
+clientcertdir = @clientcertdir@
 datadir = @datadir@
 datarootdir = @datarootdir@
 docdir = @docdir@
@@ -193,6 +204,8 @@
 libwebsockets_test_server_LDADD = -L../lib -lwebsockets
 libwebsockets_test_client_SOURCES = test-client.c
 libwebsockets_test_client_LDADD = -L../lib -lwebsockets
+libwebsockets_test_server_CFLAGS := -Wall -Werror -std=gnu99 -pedantic -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\"
+libwebsockets_test_client_CFLAGS := -Wall -Werror -std=gnu99 -pedantic -DDATADIR=\"@datadir@\" -DLWS_OPENSSL_CLIENT_CERTS=\"@clientcertdir@\"
 all: all-am
 
 .SUFFIXES:
@@ -272,10 +285,10 @@
 	rm -f $$list
 libwebsockets-test-client$(EXEEXT): $(libwebsockets_test_client_OBJECTS) $(libwebsockets_test_client_DEPENDENCIES) 
 	@rm -f libwebsockets-test-client$(EXEEXT)
-	$(LINK) $(libwebsockets_test_client_OBJECTS) $(libwebsockets_test_client_LDADD) $(LIBS)
+	$(libwebsockets_test_client_LINK) $(libwebsockets_test_client_OBJECTS) $(libwebsockets_test_client_LDADD) $(LIBS)
 libwebsockets-test-server$(EXEEXT): $(libwebsockets_test_server_OBJECTS) $(libwebsockets_test_server_DEPENDENCIES) 
 	@rm -f libwebsockets-test-server$(EXEEXT)
-	$(LINK) $(libwebsockets_test_server_OBJECTS) $(libwebsockets_test_server_LDADD) $(LIBS)
+	$(libwebsockets_test_server_LINK) $(libwebsockets_test_server_OBJECTS) $(libwebsockets_test_server_LDADD) $(LIBS)
 
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
@@ -283,8 +296,8 @@
 distclean-compile:
 	-rm -f *.tab.c
 
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-client.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-server.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_test_client-test-client.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libwebsockets_test_server-test-server.Po@am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -307,6 +320,34 @@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
 
+libwebsockets_test_client-test-client.o: test-client.c
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_client_CFLAGS) $(CFLAGS) -MT libwebsockets_test_client-test-client.o -MD -MP -MF $(DEPDIR)/libwebsockets_test_client-test-client.Tpo -c -o libwebsockets_test_client-test-client.o `test -f 'test-client.c' || echo '$(srcdir)/'`test-client.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/libwebsockets_test_client-test-client.Tpo $(DEPDIR)/libwebsockets_test_client-test-client.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='test-client.c' object='libwebsockets_test_client-test-client.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_client_CFLAGS) $(CFLAGS) -c -o libwebsockets_test_client-test-client.o `test -f 'test-client.c' || echo '$(srcdir)/'`test-client.c
+
+libwebsockets_test_client-test-client.obj: test-client.c
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_client_CFLAGS) $(CFLAGS) -MT libwebsockets_test_client-test-client.obj -MD -MP -MF $(DEPDIR)/libwebsockets_test_client-test-client.Tpo -c -o libwebsockets_test_client-test-client.obj `if test -f 'test-client.c'; then $(CYGPATH_W) 'test-client.c'; else $(CYGPATH_W) '$(srcdir)/test-client.c'; fi`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/libwebsockets_test_client-test-client.Tpo $(DEPDIR)/libwebsockets_test_client-test-client.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='test-client.c' object='libwebsockets_test_client-test-client.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_client_CFLAGS) $(CFLAGS) -c -o libwebsockets_test_client-test-client.obj `if test -f 'test-client.c'; then $(CYGPATH_W) 'test-client.c'; else $(CYGPATH_W) '$(srcdir)/test-client.c'; fi`
+
+libwebsockets_test_server-test-server.o: test-server.c
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_server_CFLAGS) $(CFLAGS) -MT libwebsockets_test_server-test-server.o -MD -MP -MF $(DEPDIR)/libwebsockets_test_server-test-server.Tpo -c -o libwebsockets_test_server-test-server.o `test -f 'test-server.c' || echo '$(srcdir)/'`test-server.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/libwebsockets_test_server-test-server.Tpo $(DEPDIR)/libwebsockets_test_server-test-server.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='test-server.c' object='libwebsockets_test_server-test-server.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_server_CFLAGS) $(CFLAGS) -c -o libwebsockets_test_server-test-server.o `test -f 'test-server.c' || echo '$(srcdir)/'`test-server.c
+
+libwebsockets_test_server-test-server.obj: test-server.c
+@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_server_CFLAGS) $(CFLAGS) -MT libwebsockets_test_server-test-server.obj -MD -MP -MF $(DEPDIR)/libwebsockets_test_server-test-server.Tpo -c -o libwebsockets_test_server-test-server.obj `if test -f 'test-server.c'; then $(CYGPATH_W) 'test-server.c'; else $(CYGPATH_W) '$(srcdir)/test-server.c'; fi`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/libwebsockets_test_server-test-server.Tpo $(DEPDIR)/libwebsockets_test_server-test-server.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='test-server.c' object='libwebsockets_test_server-test-server.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libwebsockets_test_server_CFLAGS) $(CFLAGS) -c -o libwebsockets_test_server-test-server.obj `if test -f 'test-server.c'; then $(CYGPATH_W) 'test-server.c'; else $(CYGPATH_W) '$(srcdir)/test-server.c'; fi`
+
 mostlyclean-libtool:
 	-rm -f *.lo
 
@@ -514,6 +555,7 @@
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags uninstall uninstall-am uninstall-binPROGRAMS
 
+
 #
 # cook a random test cert and key
 # notice your real cert and key will want to be 0600 permissions
diff --git a/test-server/test-client.c b/test-server/test-client.c
index 3243ccd..3636951 100644
--- a/test-server/test-client.c
+++ b/test-server/test-client.c
@@ -35,11 +35,11 @@
  * server just it simplifies the demo).
  *
  *  dumb-increment-protocol:  we connect to the server and print the number
- * 				we are given
+ *				we are given
  *
  *  lws-mirror-protocol: draws random circles, which are mirrored on to every
- * 				client (see them being drawn in every browser
- * 				session also using the test server)
+ *				client (see them being drawn in every browser
+ *				session also using the test server)
  */
 
 enum demo_protocols {
@@ -62,7 +62,8 @@
 	switch (reason) {
 
 	case LWS_CALLBACK_CLIENT_RECEIVE:
-		fprintf(stderr, "rx %d '%s'\n", len, in);
+		((char *)in)[len] = '\0';
+		fprintf(stderr, "rx %d '%s'\n", (int)len, (char *)in);
 		break;
 
 	default:
@@ -75,148 +76,49 @@
 
 /* lws-mirror_protocol */
 
-/* "how to draw a circle" */
-
-struct coord {
-	int x;
-	int y;
-};
-
-static struct coord circle[] = {
-
-{ 0, 240 },
-{ 12, 239 },
-{ 25, 238 },
-{ 37, 237 },
-{ 49, 234 },
-{ 62, 231 },
-{ 74, 228 },
-{ 86, 224 },
-{ 97, 219 },
-{ 108, 213 },
-{ 120, 207 },
-{ 130, 201 },
-{ 141, 194 },
-{ 151, 186 },
-{ 160, 178 },
-{ 169, 169 },
-{ 178, 160 },
-{ 186, 151 },
-{ 194, 141 },
-{ 201, 130 },
-{ 207, 120 },
-{ 213, 108 },
-{ 219, 97 },
-{ 224, 86 },
-{ 228, 74 },
-{ 231, 62 },
-{ 234, 49 },
-{ 237, 37 },
-{ 238, 25 },
-{ 239, 12 },
-{ 240, 0 },
-{ 239, -12 },
-{ 238, -25 },
-{ 237, -37 },
-{ 234, -49 },
-{ 231, -62 },
-{ 228, -74 },
-{ 224, -86 },
-{ 219, -97 },
-{ 213, -108 },
-{ 207, -120 },
-{ 201, -130 },
-{ 194, -141 },
-{ 186, -151 },
-{ 178, -160 },
-{ 169, -169 },
-{ 160, -178 },
-{ 151, -186 },
-{ 141, -194 },
-{ 130, -201 },
-{ 120, -207 },
-{ 108, -213 },
-{ 97, -219 },
-{ 86, -224 },
-{ 74, -228 },
-{ 62, -231 },
-{ 49, -234 },
-{ 37, -237 },
-{ 25, -238 },
-{ 12, -239 },
-{ 0, -240 },
-{ -12, -239 },
-{ -25, -238 },
-{ -37, -237 },
-{ -49, -234 },
-{ -62, -231 },
-{ -74, -228 },
-{ -86, -224 },
-{ -97, -219 },
-{ -108, -213 },
-{ -119, -207 },
-{ -130, -201 },
-{ -141, -194 },
-{ -151, -186 },
-{ -160, -178 },
-{ -169, -169 },
-{ -178, -160 },
-{ -186, -151 },
-{ -194, -141 },
-{ -201, -130 },
-{ -207, -120 },
-{ -213, -108 },
-{ -219, -97 },
-{ -224, -86 },
-{ -228, -74 },
-{ -231, -62 },
-{ -234, -49 },
-{ -237, -37 },
-{ -238, -25 },
-{ -239, -12 },
-{ -240, 0 },
-{ -239, 12 },
-{ -238, 25 },
-{ -237, 37 },
-{ -234, 49 },
-{ -231, 62 },
-{ -228, 74 },
-{ -224, 86 },
-{ -219, 97 },
-{ -213, 108 },
-{ -207, 120 },
-{ -201, 130 },
-{ -194, 141 },
-{ -186, 151 },
-{ -178, 160 },
-{ -169, 169 },
-{ -160, 178 },
-{ -151, 186 },
-{ -141, 194 },
-{ -130, 201 },
-{ -119, 207 },
-{ -108, 213 },
-{ -97, 219 },
-{ -86, 224 },
-{ -74, 228 },
-{ -62, 231 },
-{ -49, 234 },
-{ -37, 237 },
-{ -25, 238 },
-{ -12, 239 },
-{ 0, 240 },
-	
-};
 
 static int
 callback_lws_mirror(struct libwebsocket *wsi,
 			enum libwebsocket_callback_reasons reason,
 					       void *user, void *in, size_t len)
 {
+	unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 4096 +
+						  LWS_SEND_BUFFER_POST_PADDING];
+	int l;
+
 	switch (reason) {
 
+	case LWS_CALLBACK_CLIENT_ESTABLISHED:
+
+		/*
+		 * start the ball rolling,
+		 * LWS_CALLBACK_CLIENT_WRITEABLE will come immediately
+		 */
+
+		libwebsocket_callback_on_writable(wsi);
+		break;
+
 	case LWS_CALLBACK_CLIENT_RECEIVE:
-//		fprintf(stderr, "rx %d '%s'\n", len, in);
+/*		fprintf(stderr, "rx %d '%s'\n", (int)len, (char *)in); */
+		break;
+
+	case LWS_CALLBACK_CLIENT_WRITEABLE:
+
+		l = sprintf((char *)&buf[LWS_SEND_BUFFER_PRE_PADDING],
+					"c #%06X %d %d %d;",
+					(int)random() & 0xffffff,
+					(int)random() % 500,
+					(int)random() % 250,
+					(int)random() % 24);
+
+		libwebsocket_write(wsi,
+			&buf[LWS_SEND_BUFFER_PRE_PADDING], l, LWS_WRITE_TEXT);
+
+		/* get notified as soon as we can write again */
+
+		libwebsocket_callback_on_writable(wsi);
+
+		usleep(200);
 		break;
 
 	default:
@@ -245,9 +147,9 @@
 };
 
 static struct option options[] = {
-	{ "help", 	no_argument, NULL, 'h' },
-	{ "port", 	required_argument, NULL, 'p' },
-	{ "ssl", 	no_argument, NULL, 's' },
+	{ "help",	no_argument,		NULL, 'h' },
+	{ "port",	required_argument,	NULL, 'p' },
+	{ "ssl",	no_argument,		NULL, 's' },
 	{ NULL, 0, 0, 0 }
 };
 
@@ -258,19 +160,10 @@
 	int port = 7681;
 	int use_ssl = 0;
 	struct libwebsocket_context *context;
-	const char * address = argv[1];
+	const char *address = argv[1];
 	struct libwebsocket *wsi_dumb;
 	struct libwebsocket *wsi_mirror;
-	unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1024 +
-						  LWS_SEND_BUFFER_POST_PADDING];
-	int len;
-	int i = 0;
-	int xofs;
-	int yofs;
-	int oldx;
-	int oldy;
-	int scale;
-	int colour;
+
 
 	fprintf(stderr, "libwebsockets test client\n"
 			"(C) Copyright 2010 Andy Green <andy@warmcat.com> "
@@ -287,7 +180,7 @@
 			continue;
 		switch (n) {
 		case 's':
-			use_ssl = 1;
+			use_ssl = 2; /* 2 = allow selfsigned */
 			break;
 		case 'p':
 			port = atoi(optarg);
@@ -315,8 +208,8 @@
 
 	/* create a client websocket using dumb increment protocol */
 
-	wsi_dumb = libwebsocket_client_connect(context, address, port, "/",
-				       "http://host", "origin",
+	wsi_dumb = libwebsocket_client_connect(context, address, port, use_ssl,
+					"/", "http://host", "origin",
 				       protocols[PROTOCOL_DUMB_INCREMENT].name);
 
 	if (wsi_dumb == NULL) {
@@ -326,8 +219,8 @@
 
 	/* create a client websocket using mirror protocol */
 
-	wsi_mirror = libwebsocket_client_connect(context, address, port, "/",
-				       "http://host", "origin",
+	wsi_mirror = libwebsocket_client_connect(context, address, port,
+					use_ssl,  "/", "http://host", "origin",
 				       protocols[PROTOCOL_LWS_MIRROR].name);
 
 	if (wsi_mirror == NULL) {
@@ -343,39 +236,8 @@
 	 */
 
 	n = 0;
-	while (n >= 0) {
-
-		usleep(10000);
-
-		if (i == sizeof circle / sizeof circle[0])
-			i = 0;
-
-		if (i == 0) {
-			xofs = random() % 500;
-			yofs = random() % 250;
-			scale = random() % 24;
-			if (!scale)
-				scale = 1;
-
-			oldx = xofs + (circle[i].x / scale);
-			oldy = yofs + (circle[i].y / scale);
-			colour = random() & 0xffffff;
-		}
-
-		len = sprintf(&buf[LWS_SEND_BUFFER_PRE_PADDING],
-			"d #%06X %d %d %d %d", colour, oldx, oldy,
-				xofs + (circle[i].x / scale),
-				yofs + (circle[i].y / scale));
-		oldx = xofs + (circle[i].x / scale);
-		oldy = yofs + (circle[i].y / scale);
-		i++;
-
-		libwebsocket_write(wsi_mirror,
-			&buf[LWS_SEND_BUFFER_PRE_PADDING], len, LWS_WRITE_TEXT);
-
-
-		n = libwebsocket_service(context, 0);
-	}
+	while (n >= 0)
+		n = libwebsocket_service(context, 1000);
 
 	libwebsocket_client_close(wsi_dumb);
 	libwebsocket_client_close(wsi_mirror);
diff --git a/test-server/test-server.c b/test-server/test-server.c
index 832a45a..4f4512f 100644
--- a/test-server/test-server.c
+++ b/test-server/test-server.c
@@ -24,6 +24,7 @@
 #include <unistd.h>
 #include <getopt.h>
 #include <string.h>
+#include <sys/time.h>
 
 #include "../lib/libwebsockets.h"
 
@@ -36,11 +37,11 @@
  *
  *  dumb-increment-protocol:  once the socket is opened, an incrementing
  *				ascii string is sent down it every 50ms.
- * 				If you send "reset\n" on the websocket, then
- * 				the incrementing number is reset to 0.
+ *				If you send "reset\n" on the websocket, then
+ *				the incrementing number is reset to 0.
  *
  *  lws-mirror-protocol: copies any received packet to every connection also
- * 				using this protocol, including the sender
+ *				using this protocol, including the sender
  */
 
 enum demo_protocols {
@@ -55,7 +56,7 @@
 };
 
 
-#define LOCAL_RESOURCE_PATH "/usr/share/libwebsockets-test-server"
+#define LOCAL_RESOURCE_PATH DATADIR"/libwebsockets-test-server"
 
 /* this protocol server (always the first one) just knows how to do HTTP */
 
@@ -65,7 +66,7 @@
 {
 	switch (reason) {
 	case LWS_CALLBACK_HTTP:
-		fprintf(stderr, "serving HTTP URI %s\n", in);
+		fprintf(stderr, "serving HTTP URI %s\n", (char *)in);
 
 		if (in && strcmp(in, "/favicon.ico") == 0) {
 			if (libwebsockets_serve_http_file(wsi,
@@ -108,9 +109,9 @@
 					       void *user, void *in, size_t len)
 {
 	int n;
-	char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
+	unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
 						  LWS_SEND_BUFFER_POST_PADDING];
-	char *p = (char *)&buf[LWS_SEND_BUFFER_PRE_PADDING];
+	unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
 	struct per_session_data__dumb_increment *pss = user;
 
 	switch (reason) {
@@ -126,7 +127,7 @@
 	 */
 
 	case LWS_CALLBACK_BROADCAST:
-		n = sprintf(p, "%d", pss->number++);
+		n = sprintf((char *)p, "%d", pss->number++);
 		n = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
 		if (n < 0) {
 			fprintf(stderr, "ERROR writing to socket");
@@ -135,7 +136,7 @@
 		break;
 
 	case LWS_CALLBACK_RECEIVE:
-		fprintf(stderr, "rx %d\n", len);
+		fprintf(stderr, "rx %d\n", (int)len);
 		if (len < 6)
 			break;
 		if (strcmp(in, "reset\n") == 0)
@@ -152,33 +153,92 @@
 
 /* lws-mirror_protocol */
 
+#define MAX_MESSAGE_QUEUE 64
+
+struct per_session_data__lws_mirror {
+	struct libwebsocket *wsi;
+	int ringbuffer_tail;
+};
+
+struct a_message {
+	void *payload;
+	size_t len;
+};
+
+static struct a_message ringbuffer[MAX_MESSAGE_QUEUE];
+static int ringbuffer_head;
+
+
 static int
 callback_lws_mirror(struct libwebsocket *wsi,
 			enum libwebsocket_callback_reasons reason,
 					       void *user, void *in, size_t len)
 {
 	int n;
+	struct per_session_data__lws_mirror *pss = user;
 
 	switch (reason) {
 
+	case LWS_CALLBACK_ESTABLISHED:
+		pss->ringbuffer_tail = ringbuffer_head;
+		pss->wsi = wsi;
+		break;
+
+	case LWS_CALLBACK_CLIENT_WRITEABLE:
+		if (pss->ringbuffer_tail != ringbuffer_head) {
+
+			n = libwebsocket_write(wsi, (unsigned char *)
+				   ringbuffer[pss->ringbuffer_tail].payload +
+				   LWS_SEND_BUFFER_PRE_PADDING,
+				   ringbuffer[pss->ringbuffer_tail].len,
+								LWS_WRITE_TEXT);
+			if (n < 0) {
+				fprintf(stderr, "ERROR writing to socket");
+				exit(1);
+			}
+
+			if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1))
+				pss->ringbuffer_tail = 0;
+			else
+				pss->ringbuffer_tail++;
+
+			if (((ringbuffer_head - pss->ringbuffer_tail) %
+				  MAX_MESSAGE_QUEUE) < (MAX_MESSAGE_QUEUE - 15))
+				libwebsocket_rx_flow_control(wsi, 1);
+
+			libwebsocket_callback_on_writable(wsi);
+
+		}
+		break;
+
 	case LWS_CALLBACK_BROADCAST:
 		n = libwebsocket_write(wsi, in, len, LWS_WRITE_TEXT);
+		if (n < 0)
+			fprintf(stderr, "mirror write failed\n");
 		break;
 
 	case LWS_CALLBACK_RECEIVE:
-		/*
-		 * copy the incoming packet to all other protocol users
-		 *
-		 * This demonstrates how easy it is to broadcast from inside
-		 * a callback.
-		 * 
-		 * How this works is it calls back to the callback for all
-		 * connected sockets using this protocol with
-		 * LWS_CALLBACK_BROADCAST reason.  Our handler for that above
-		 * writes the data down the socket.
-		 */
-		libwebsockets_broadcast(libwebsockets_get_protocol(wsi),
-								       in, len);
+
+		if (ringbuffer[ringbuffer_head].payload)
+			free(ringbuffer[ringbuffer_head].payload);
+
+		ringbuffer[ringbuffer_head].payload =
+				malloc(LWS_SEND_BUFFER_PRE_PADDING + len +
+						  LWS_SEND_BUFFER_POST_PADDING);
+		ringbuffer[ringbuffer_head].len = len;
+		memcpy((char *)ringbuffer[ringbuffer_head].payload +
+					  LWS_SEND_BUFFER_PRE_PADDING, in, len);
+		if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
+			ringbuffer_head = 0;
+		else
+			ringbuffer_head++;
+
+		if (((ringbuffer_head - pss->ringbuffer_tail) %
+				  MAX_MESSAGE_QUEUE) > (MAX_MESSAGE_QUEUE - 10))
+			libwebsocket_rx_flow_control(wsi, 0);
+
+		libwebsocket_callback_on_writable_all_protocol(
+					       libwebsockets_get_protocol(wsi));
 		break;
 
 	default:
@@ -206,6 +266,8 @@
 	[PROTOCOL_LWS_MIRROR] = {
 		.name = "lws-mirror-protocol",
 		.callback = callback_lws_mirror,
+		.per_session_data_size =
+				sizeof(struct per_session_data__lws_mirror),
 	},
 	[DEMO_PROTOCOL_COUNT] = {  /* end of list */
 		.callback = NULL
@@ -213,9 +275,9 @@
 };
 
 static struct option options[] = {
-	{ "help", 	no_argument, NULL, 'h' },
-	{ "port", 	required_argument, NULL, 'p' },
-	{ "ssl", 	no_argument, NULL, 's' },
+	{ "help",	no_argument,		NULL, 'h' },
+	{ "port",	required_argument,	NULL, 'p' },
+	{ "ssl",	no_argument,		NULL, 's' },
 	{ NULL, 0, 0, 0 }
 };
 
@@ -231,6 +293,9 @@
 	int port = 7681;
 	int use_ssl = 0;
 	struct libwebsocket_context *context;
+#ifdef LWS_NO_FORK
+	unsigned int oldus = 0;
+#endif
 
 	fprintf(stderr, "libwebsockets test server\n"
 			"(C) Copyright 2010-2011 Andy Green <andy@warmcat.com> "
@@ -275,13 +340,14 @@
 	fprintf(stderr, " Using no-fork service loop\n");
 
 	while (1) {
-		
-		usleep(50000);
+		struct timeval tv;
+
+		gettimeofday(&tv, NULL);
 
 		/*
 		 * This broadcasts to all dumb-increment-protocol connections
 		 * at 20Hz.
-		 * 
+		 *
 		 * We're just sending a character 'x', in these examples the
 		 * callbacks send their own per-connection content.
 		 *
@@ -291,8 +357,12 @@
 		 * We take care of pre-and-post padding allocation.
 		 */
 
-		libwebsockets_broadcast(&protocols[PROTOCOL_DUMB_INCREMENT],
+		if (((unsigned int)tv.tv_usec - oldus) > 50000) {
+			libwebsockets_broadcast(
+					&protocols[PROTOCOL_DUMB_INCREMENT],
 					&buf[LWS_SEND_BUFFER_PRE_PADDING], 1);
+			oldus = tv.tv_usec;
+		}
 
 		/*
 		 * This example server does not fork or create a thread for
@@ -304,7 +374,7 @@
 		 * immediately and quickly.
 		 */
 
-		libwebsocket_service(context, 0);
+		libwebsocket_service(context, 50);
 	}
 
 #else
@@ -327,13 +397,13 @@
 	}
 
 	while (1) {
-		
+
 		usleep(50000);
 
 		/*
 		 * This broadcasts to all dumb-increment-protocol connections
 		 * at 20Hz.
-		 * 
+		 *
 		 * We're just sending a character 'x', in these examples the
 		 * callbacks send their own per-connection content.
 		 *
diff --git a/test-server/test.html b/test-server/test.html
index 466310a..5f030f3 100644
--- a/test-server/test.html
+++ b/test-server/test.html
@@ -7,7 +7,8 @@
 
 <body>
 <h2>libwebsockets "dumb-increment-protocol" test applet</h2>
-The incrementing number is coming from the server.
+The incrementing number is coming from the server and is individual for
+each connection to the server... try opening a second browser window.
 Click the button to send the server a websocket message to
 reset the number.<br><br>
 
@@ -27,6 +28,8 @@
 The lws-mirror protocol doesn't interpret what is being sent to it, it just
 re-sends it to every other websocket it has a connection with using that
 protocol, including the guy who sent the packet.
+<p>libwebsockets-test-client spams circles on to this shared canvas when
+run.</p>
 <br><br>
 
 <table>
@@ -121,13 +124,25 @@
 		} 
 
 		socket_lm.onmessage =function got_packet(msg) {
-			i = msg.data.split(' ');
-			if (i[0] == 'd') {
-				ctx.strokeStyle = i[1];
-				ctx.beginPath();
-				ctx.moveTo(+(i[2]), +(i[3]));
-				ctx.lineTo(+(i[4]), +(i[5]));
-				ctx.stroke();
+			j = msg.data.split(';');
+			f = 0;
+			while (f < j.length - 1) {
+				i = j[f].split(' ');
+				if (i[0] == 'd') {
+					ctx.strokeStyle = i[1];
+					ctx.beginPath();
+					ctx.moveTo(+(i[2]), +(i[3]));
+					ctx.lineTo(+(i[4]), +(i[5]));
+					ctx.stroke();
+				}
+				if (i[0] == 'c') {
+					ctx.strokeStyle = i[1];
+					ctx.beginPath();
+					ctx.arc(+(i[2]), +(i[3]), +(i[4]), 0, Math.PI*2, true); 
+					ctx.stroke();
+				}
+
+				f++;
 			}
 		}
 
@@ -192,7 +207,7 @@
 		last_y = y;
 		return;
 	}
-	socket_lm.send("d " + color + " " + last_x + " " + last_y + " " + x + ' ' + y);
+	socket_lm.send("d " + color + " " + last_x + " " + last_y + " " + x + ' ' + y + ';');
 
 	last_x = x;
 	last_y = y;