move-to-automatic-protocol-list-scheme.patch

Signed-off-by: Andy Green <andy@warmcat.com>
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 78ced38..7cc2120 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -12,7 +12,7 @@
 all-local:
 	 ../scripts/kernel-doc -html \
                 libwebsockets.c \
-                parsers.c \
-                ../test-server/test-server.c \
+		parsers.c \
+                libwebsockets.h \
 			> ../libwebsockets-api-doc.html
 
diff --git a/lib/Makefile.in b/lib/Makefile.in
index 493db5b..dcf4a67 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -578,8 +578,8 @@
 all-local:
 	 ../scripts/kernel-doc -html \
                 libwebsockets.c \
-                parsers.c \
-                ../test-server/test-server.c \
+		parsers.c \
+                libwebsockets.h \
 			> ../libwebsockets-api-doc.html
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/lib/handshake.c b/lib/handshake.c
index 2ca7938..7deb581 100644
--- a/lib/handshake.c
+++ b/lib/handshake.c
@@ -94,9 +94,9 @@
 		
 		if (!wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len ||
 			     !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len) {
-			if (wsi->callback)
-				(wsi->callback)(wsi, LWS_CALLBACK_HTTP,
-							&wsi->user_space[0],
+			if (wsi->protocol->callback)
+				(wsi->protocol->callback)(wsi, LWS_CALLBACK_HTTP,
+							&wsi->user_space,
 				   wsi->utf8_token[WSI_TOKEN_GET_URI].token, 0);
 			wsi->state = WSI_STATE_HTTP;
 			return 0;
@@ -132,11 +132,41 @@
 
 		/* Make sure user side is happy about protocol */
 
-		if (wsi->callback)
-			wsi->callback(wsi, LWS_CALLBACK_PROTOCOL_FILTER,
-				      &wsi->user_space[0],
-				      wsi->utf8_token[WSI_TOKEN_PROTOCOL].token,
-				      0);
+		while (wsi->protocol->callback) {
+
+			if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token == NULL) {
+				if (wsi->protocol->name == NULL)
+					break;
+			} else
+				if (strcmp(
+				     wsi->utf8_token[WSI_TOKEN_PROTOCOL].token,
+						      wsi->protocol->name) == 0)
+					break;
+							
+			wsi->protocol++;
+		}
+		if (wsi->protocol->callback == NULL) {
+			if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token == NULL)
+				fprintf(stderr, "[no protocol] "
+					"not supported (use NULL .name)\n");
+			else
+				fprintf(stderr, "Requested protocol %s "
+						"not supported\n",
+				     wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
+			goto bail;
+		}
+
+		/* allocate the per-connection user memory (if any) */
+
+		if (wsi->protocol->per_session_data_size) {
+			wsi->user_space = malloc(
+					  wsi->protocol->per_session_data_size);
+			if (wsi->user_space  == NULL) {
+				fprintf(stderr, "Out of memory for "
+							   "conn user space\n");
+				goto bail;
+			}
+		}
 		
 		/* create the response packet */
 		
@@ -243,9 +273,9 @@
 		
 		/* notify user code that we're ready to roll */
 				
-		if (wsi->callback)
-			wsi->callback(wsi, LWS_CALLBACK_ESTABLISHED,
-						  &wsi->user_space[0], NULL, 0);
+		if (wsi->protocol->callback)
+			wsi->protocol->callback(wsi, LWS_CALLBACK_ESTABLISHED,
+						  &wsi->user_space, NULL, 0);
 		break;
 
 	case WSI_STATE_ESTABLISHED:
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index 11ab790..60ecde2 100644
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -31,6 +31,48 @@
 libwebsocket_read(struct libwebsocket *wsi, unsigned char * buf, size_t len);
 
 
+/* document the generic callback (it's a fake prototype under this) */
+/**
+ * callback() - User server actions
+ * @wsi:	Opaque websocket instance pointer
+ * @reason:	The reason for the call
+ * @user:	Pointer to per-session user data allocated by library
+ * @in:		Pointer used for some callback reasons
+ * @len:	Length set for some callback reasons
+ * 
+ * 	This callback is the way the user controls what is served.  All the
+ * 	protocol detail is hidden and handled by the library.
+ * 
+ * 	For each connection / session there is user data allocated that is
+ * 	pointed to by "user".  You set the size of this user data area when
+ * 	the library is initialized with libwebsocket_create_server.
+ * 
+ * 	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_CLOSED: when the websocket session ends
+ *
+ * 	LWS_CALLBACK_SEND: opportunity 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_HTTP: an http request has come from a client that is not
+ * 				asking to upgrade the connection to a websocket
+ * 				one.  This is a chance to serve http content,
+ * 				for example, to send a script to the client
+ * 				which will then open the websockets connection.
+ * 				@in points to the URI path requested and 
+ * 				libwebsockets_serve_http_file() makes it very
+ * 				simple to send back a file to the client.
+ */
+extern int callback(struct libwebsocket * wsi,
+			 enum libwebsocket_callback_reasons reason, void * user,
+							  void *in, size_t len);
+
 
 void 
 libwebsocket_close_and_free_session(struct libwebsocket *wsi)
@@ -39,8 +81,8 @@
 
 	wsi->state = WSI_STATE_DEAD_SOCKET;
 
-	if (wsi->callback && n == WSI_STATE_ESTABLISHED)
-		wsi->callback(wsi, LWS_CALLBACK_CLOSED, &wsi->user_space[0], 
+	if (wsi->protocol->callback && n == WSI_STATE_ESTABLISHED)
+		wsi->protocol->callback(wsi, LWS_CALLBACK_CLOSED, &wsi->user_space, 
 								       NULL, 0);
 
 	for (n = 0; n < WSI_TOKEN_COUNT; n++)
@@ -62,17 +104,18 @@
 #ifdef LWS_OPENSSL_SUPPORT
 	}
 #endif
+	if (wsi->user_space)
+		free(wsi->user_space);
+
 	free(wsi);
 }
 
 /**
  * libwebsocket_create_server() - Create the listening websockets server
  * @port:	Port to listen on
- * @callback:	The callback in user code to perform actual serving
- * @user_area_size:	How much memory to allocate per connection session
- * 			which will be used by the user application to store
- * 			per-session data.  A pointer to this space is given
- * 			when the user callback is called.
+ * @protocols:	Array of structures listing supported protocols and a protocol-
+ * 		specific callback for each one.  The list is ended with an
+ * 		entry that has a NULL callback pointer.
  * @ssl_cert_filepath:	If libwebsockets was compiled to use ssl, and you want
  * 			to listen using SSL, set to the filepath to fetch the
  * 			server cert from, otherwise NULL for unencrypted
@@ -98,10 +141,7 @@
  */
 
 int libwebsocket_create_server(int port,
-			       int (*callback)(struct libwebsocket *,
-					enum libwebsocket_callback_reasons, 
-					void *, void *, size_t),
-			       size_t user_area_size,
+			       const struct libwebsocket_protocols *protocols,
 			       const char * ssl_cert_filepath,
 			       const char * ssl_private_key_filepath,
 			       int gid, int uid)
@@ -185,14 +225,7 @@
 		/* SSL is happy and has a cert it's content with */
 	}
 #endif
-	
-	if (!callback) {
-		fprintf(stderr, "callback is not optional!\n");
-		return -1;
-	}
- 
-	/* sit there listening for connects, accept and spawn session servers */
- 
+  
 	sockfd = socket(AF_INET, SOCK_STREAM, 0);
 	if (sockfd < 0) {
 		fprintf(stderr, "ERROR opening socket");
@@ -226,7 +259,7 @@
 	if (n)
 		return sockfd;
  
-	// drop any root privs for this thread
+	/* drop any root privs for this thread */
 
 	if (gid != -1)
 		if (setgid(gid))
@@ -235,8 +268,11 @@
 		if (setuid(uid))
 			fprintf(stderr, "setuid: %s\n", strerror(errno));
 
-	/* we are running in a forked subprocess now */
- 
+ 	/*
+	 * sit there listening for connects, accept and service connections
+	 * in a poll loop, without any further forking
+	 */
+
 	listen(sockfd, 5);
 	fprintf(stderr, " Listening on port %d\n", port);
  	
@@ -273,8 +309,7 @@
 				continue;
 			}
 
-			wsi[fds_count] = malloc(sizeof(struct libwebsocket) +
-								user_area_size);
+			wsi[fds_count] = malloc(sizeof(struct libwebsocket));
 			if (!wsi[fds_count])
 				return -1;
 
@@ -313,11 +348,10 @@
 					ntohs(cli_addr.sin_port), fd,
 					  SSL_get_version(wsi[fds_count]->ssl));
 				
-			} else {
-//			fprintf(stderr, "accepted new conn  port %u on fd=%d\n",
-//						  ntohs(cli_addr.sin_port), fd);
-			}
+			} else
 #endif
+				debug("accepted new conn  port %u on fd=%d\n",
+						  ntohs(cli_addr.sin_port), fd);
 			
 			/* intialize the instance struct */
 
@@ -330,11 +364,20 @@
 				wsi[fds_count]->utf8_token[n].token_len = 0;
 			}
 
-			wsi[fds_count]->callback = callback;
+			/*
+			 * these can only be set once the protocol is known
+			 * we set an unestablished connection's protocol pointer
+			 * to the start of the supported list, so it can look
+			 * for matching ones during the handshake
+			 */
+			wsi[fds_count]->protocol = protocols;
+			wsi[fds_count]->user_space = NULL;
+
 			/*
 			 * Default protocol is 76
 			 * After 76, there's a header specified to inform which
-			 * draft the client wants
+			 * draft the client wants, when that's seen we modify
+			 * the individual connection's spec revision accordingly
 			 */
 			wsi[fds_count]->ietf_spec_revision = 76;
 
@@ -361,8 +404,6 @@
 
 			if (!(fds[client].revents & POLLIN))
 				continue;
-				
-//			fprintf(stderr, "POLLIN\n");
 
 #ifdef LWS_OPENSSL_SUPPORT
 			if (use_ssl)
@@ -371,8 +412,6 @@
 #endif
 				n = recv(fds[client].fd, buf, sizeof(buf), 0);
 
-//			fprintf(stderr, "read returned %d\n", n);
-
 			if (n < 0) {
 				fprintf(stderr, "Socket read returned %d\n", n);
 				continue;
@@ -389,7 +428,10 @@
 			if (libwebsocket_read(wsi[client], buf, n) >= 0)
 				continue;
 			
-			/* it closed and nuked wsi[client] */
+			/*
+			 * it closed and nuked wsi[client], so remove the
+			 * socket handle and wsi from our service list
+			 */
 nuke_this:
 			for (n = client; n < fds_count - 1; n++) {
 				fds[n] = fds[n + 1];
@@ -404,12 +446,9 @@
 
 			if (wsi[client]->state != WSI_STATE_ESTABLISHED)
 				continue;
-						
-			if (!wsi[client]->callback)
-				continue;
 
-			wsi[client]->callback(wsi[client], LWS_CALLBACK_SEND, 
-					  &wsi[client]->user_space[0], NULL, 0);
+			wsi[client]->protocol->callback(wsi[client], LWS_CALLBACK_SEND, 
+					  &wsi[client]->user_space, NULL, 0);
 		}
 		
 		continue;		
diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index b1588b1..24042fc 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -29,7 +29,6 @@
 	LWS_CALLBACK_SEND,
 	LWS_CALLBACK_RECEIVE,
 	LWS_CALLBACK_HTTP,
-	LWS_CALLBACK_PROTOCOL_FILTER,
 };
 
 enum libwebsocket_write_protocol {
@@ -40,14 +39,36 @@
 
 struct libwebsocket;
 
+/**
+ * struct libwebsocket_protocols - 	List of protocols and handlers server
+ * 					supports.
+ * @name:	Protocol name that must match the one given in the client
+ * 		Javascript new WebSocket(url, 'protocol') name
+ * @callback:	The service callback used for this protocol.  It allows the
+ * 		service action for an entire protocol to be encapsulated in
+ * 		the protocol-specific callback
+ * @per_session_data_size:	Each new connection using this protocol gets
+ * 		this much memory allocated on connection establishment and
+ * 		freed on connection takedown.  A pointer to this per-connection
+ * 		allocation is passed into the callback in the 'user' parameter
+ * 
+ * 	This structure represents one protocol supported by the server.  An
+ * 	array of these structures is passed to libwebsocket_create_server()
+ * 	allows as many protocols as you like to be handled by one server.
+ */
+
+struct libwebsocket_protocols {
+	const char *name;
+	int (*callback)(struct libwebsocket * wsi,
+			 enum libwebsocket_callback_reasons reason, void * user,
+							  void *in, size_t len);
+	size_t per_session_data_size;
+};
+
 extern int libwebsocket_create_server(int port,
-		  int (*callback)(struct libwebsocket *wsi,
-				  enum libwebsocket_callback_reasons reason,
-				  void *user, void *in, size_t len),
-					       size_t user_space,
-					       const char * ssl_cert_filepath,
-					const char * ssl_private_key_filepath,
-							      int gid, int uid);
+		  const struct libwebsocket_protocols *protocols,
+		  const char * ssl_cert_filepath,
+		  const char * ssl_private_key_filepath, int gid, int uid);
 
 /*
  * IMPORTANT NOTICE!
diff --git a/lib/parsers.c b/lib/parsers.c
index 9a767f8..52cd126 100644
--- a/lib/parsers.c
+++ b/lib/parsers.c
@@ -210,9 +210,9 @@
 		if (wsi->rx_user_buffer_head != MAX_USER_RX_BUFFER)
 			break;
 issue:
-		if (wsi->callback)
-			wsi->callback(wsi, LWS_CALLBACK_RECEIVE,
-			  &wsi->user_space[0],
+		if (wsi->protocol->callback)
+			wsi->protocol->callback(wsi, LWS_CALLBACK_RECEIVE,
+			  &wsi->user_space,
 			  &wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
 			  wsi->rx_user_buffer_head);
 		wsi->rx_user_buffer_head = 0;
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index 27f495a..d3789f1 100644
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -121,8 +121,7 @@
  */
 
 struct libwebsocket {
-	int (*callback)(struct libwebsocket *,
-	     enum libwebsocket_callback_reasons reason, void *, void *, size_t);
+	const struct libwebsocket_protocols *protocol;
 
 	enum lws_connection_states state;
 
@@ -145,8 +144,7 @@
 	SSL *ssl;
 #endif
 
-	/* last */
-	char user_space[0];
+	void *user_space;
 };
 
 extern void 
diff --git a/libwebsockets-api-doc.html b/libwebsockets-api-doc.html
index 5471d3a..e7dcb82 100644
--- a/libwebsockets-api-doc.html
+++ b/libwebsockets-api-doc.html
@@ -1,9 +1,72 @@
+<h2>callback - User server actions</h2>
+<i>int</i>
+<b>callback</b>
+(<i>struct libwebsocket *</i> <b>wsi</b>,
+<i>enum libwebsocket_callback_reasons</i> <b>reason</b>,
+<i>void *</i> <b>user</b>,
+<i>void *</i> <b>in</b>,
+<i>size_t</i> <b>len</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>wsi</b>
+<dd>Opaque websocket instance pointer
+<dt><b>reason</b>
+<dd>The reason for the call
+<dt><b>user</b>
+<dd>Pointer to per-session user data allocated by library
+<dt><b>in</b>
+<dd>Pointer used for some callback reasons
+<dt><b>len</b>
+<dd>Length set for some callback reasons
+</dl>
+<h3>Description</h3>
+<blockquote>
+This callback is the way the user controls what is served.  All the
+protocol detail is hidden and handled by the library.
+<p>
+For each connection / session there is user data allocated that is
+pointed to by "user".  You set the size of this user data area when
+the library is initialized with libwebsocket_create_server.
+<p>
+You get an opportunity to initialize user data when called back with
+LWS_CALLBACK_ESTABLISHED reason.
+</blockquote>
+<h3>LWS_CALLBACK_ESTABLISHED</h3>
+<blockquote>
+after successful websocket handshake
+</blockquote>
+<h3>LWS_CALLBACK_CLOSED</h3>
+<blockquote>
+when the websocket session ends
+</blockquote>
+<h3>LWS_CALLBACK_SEND</h3>
+<blockquote>
+opportunity to send to client (you would use
+<b>libwebsocket_write</b> taking care about the
+special buffer requirements
+</blockquote>
+<h3>LWS_CALLBACK_RECEIVE</h3>
+<blockquote>
+data has appeared for the server, it can be
+found at *in and is len bytes long
+</blockquote>
+<h3>LWS_CALLBACK_HTTP</h3>
+<blockquote>
+an http request has come from a client that is not
+asking to upgrade the connection to a websocket
+one.  This is a chance to serve http content,
+for example, to send a script to the client
+which will then open the websockets connection.
+<tt><b>in</b></tt> points to the URI path requested and 
+<b>libwebsockets_serve_http_file</b> makes it very
+simple to send back a file to the client.
+</blockquote>
+<hr>
 <h2>libwebsocket_create_server - Create the listening websockets server</h2>
 <i>int</i>
 <b>libwebsocket_create_server</b>
 (<i>int</i> <b>port</b>,
-<i>int (*</i><b>callback</b>) <i>(struct libwebsocket *, 					enum libwebsocket_callback_reasons,  					void *, void *, size_t)</i>,
-<i>size_t</i> <b>user_area_size</b>,
+<i>const struct libwebsocket_protocols *</i> <b>protocols</b>,
 <i>const char *</i> <b>ssl_cert_filepath</b>,
 <i>const char *</i> <b>ssl_private_key_filepath</b>,
 <i>int</i> <b>gid</b>,
@@ -12,13 +75,10 @@
 <dl>
 <dt><b>port</b>
 <dd>Port to listen on
-<dt><b>callback</b>
-<dd>The callback in user code to perform actual serving
-<dt><b>user_area_size</b>
-<dd>How much memory to allocate per connection session
-which will be used by the user application to store
-per-session data.  A pointer to this space is given
-when the user callback is called.
+<dt><b>protocols</b>
+<dd>Array of structures listing supported protocols and a protocol-
+specific callback for each one.  The list is ended with an
+entry that has a NULL callback pointer.
 <dt><b>ssl_cert_filepath</b>
 <dd>If libwebsockets was compiled to use ssl, and you want
 to listen using SSL, set to the filepath to fetch the
@@ -109,3 +169,31 @@
 local files down the http link in a single step.
 </blockquote>
 <hr>
+<h2>struct libwebsocket_protocols - List of protocols and handlers server supports.</h2>
+<b>struct libwebsocket_protocols</b> {<br>
+&nbsp; &nbsp; <i>const char *</i> <b>name</b>;<br>
+&nbsp; &nbsp; <i>int (*</i><b>callback</b>) <i>(struct libwebsocket * wsi,enum libwebsocket_callback_reasons reason, void * user,void *in, size_t len)</i>;<br>
+&nbsp; &nbsp; <i>size_t</i> <b>per_session_data_size</b>;<br>
+};<br>
+<h3>Members</h3>
+<dl>
+<dt><b>name</b>
+<dd>Protocol name that must match the one given in the client
+Javascript new WebSocket(url, 'protocol') name
+<dt><b>callback</b>
+<dd>The service callback used for this protocol.  It allows the
+service action for an entire protocol to be encapsulated in
+the protocol-specific callback
+<dt><b>per_session_data_size</b>
+<dd>Each new connection using this protocol gets
+this much memory allocated on connection establishment and
+freed on connection takedown.  A pointer to this per-connection
+allocation is passed into the callback in the 'user' parameter
+</dl>
+<h3>Description</h3>
+<blockquote>
+This structure represents one protocol supported by the server.  An
+array of these structures is passed to <b>libwebsocket_create_server</b>
+allows as many protocols as you like to be handled by one server.
+</blockquote>
+<hr>
diff --git a/test-server/test-server.c b/test-server/test-server.c
index 1bba6e0..26f4a86 100644
--- a/test-server/test-server.c
+++ b/test-server/test-server.c
@@ -31,116 +31,14 @@
 static int port = 7681;
 static int use_ssl = 0;
 
-struct per_session_data {
-	int number;
-};
+/* this protocol server (always the first one) just knows how to do HTTP */
 
- /**
- * libwebsocket_callback() - User server actions
- * @wsi:	Opaque websocket instance pointer
- * @reason:	The reason for the call
- * @user:	Pointer to per-session user data allocated by library
- * @in:		Pointer used for some callback reasons
- * @len:	Length set for some callback reasons
- * 
- * 	This callback is the way the user controls what is served.  All the
- * 	protocol detail is hidden and handled by the library.
- * 
- * 	For each connection / session there is user data allocated that is
- * 	pointed to by "user".  You set the size of this user data area when
- * 	the library is initialized with libwebsocket_create_server.
- * 
- * 	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_CLOSED: when the websocket session ends
- *
- * 	LWS_CALLBACK_SEND: opportunity 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_HTTP: an http request has come from a client that is not
- * 				asking to upgrade the connection to a websocket
- * 				one.  This is a chance to serve http content,
- * 				for example, to send a script to the client
- * 				which will then open the websockets connection.
- * 				@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_PROTOCOL_FILTER: before the confirmation handshake is sent
- * 				the user callback is given a chance to confirm
- * 				it's OK with the protocol that was requested
- * 				from the client.  The protocol string (which
- * 				may be NULL if no protocol header was sent)
- * 				can be found at parameter @in.  Return 0 from
- * 				the callback to allow the connection or nonzero
- * 				to abort the connection.
- */
-
-static int websocket_callback(struct libwebsocket * wsi,
+static int callback_http(struct libwebsocket * wsi,
 		enum libwebsocket_callback_reasons reason, void * user,
 							   void *in, size_t len)
 {
-	int n;
-	char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
-						  LWS_SEND_BUFFER_POST_PADDING];
-	char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
-	struct per_session_data * pss = user;
-	
 	switch (reason) {
-	/*
-	 * Websockets session handshake completed and is established
-	 */
-	case LWS_CALLBACK_ESTABLISHED:
-		fprintf(stderr, "Websocket connection established\n");
-		pss->number = 0;
-		break;
-
-	/*
-	 * Websockets session is closed
-	 */
-	case LWS_CALLBACK_CLOSED:
-		fprintf(stderr, "Websocket connection closed\n");
-		break;
-
-	/*
-	 * Opportunity for us to send something on the connection
-	 */
-	case LWS_CALLBACK_SEND:	
-		n = sprintf(p, "%d", pss->number++);
-		n = libwebsocket_write(wsi, (unsigned char *)p, n,
-								LWS_WRITE_TEXT);
-		if (n < 0) {
-			fprintf(stderr, "ERROR writing to socket");
-			exit(1);
-		}
-		break;
-	/*
-	 * Something has arrived for us on the connection, it's len bytes long
-	 * and is available at *in
-	 */
-	case LWS_CALLBACK_RECEIVE:
-		fprintf(stderr, "Received %d bytes payload\n", (int)len);
-		if (strcmp(in, "reset\n") == 0)
-			pss->number = 0;
-		break;
-
-	/*
-	 * The client has asked us for something in normal HTTP mode,
-	 * not websockets mode.  Normally it means we want to send
-	 * our script / html to the client, and when that script runs
-	 * it will start up separate websocket connections.
-	 * 
-	 * Interpret the URI string to figure out what is needed to send
-	 */
-		 
 	case LWS_CALLBACK_HTTP:
-
 		fprintf(stderr, "serving HTTP URI %s\n", in);
 		
 		if (in && strcmp(in, "/favicon.ico") == 0) {
@@ -157,34 +55,82 @@
 			fprintf(stderr, "Failed to send HTTP file\n");
 		break;
 
-	/*
-	 * This is our chance to choose if we support one of the requested
-	 * protocols or not.  in points to the protocol string.  Nonzero return
-	 * aborts the connection handshake
-	 */
-
-	case LWS_CALLBACK_PROTOCOL_FILTER:
-		if (in == NULL) {
-			fprintf(stderr, "Client did not request protocol\n");
-			/* reject it */
-			return 1;
-		}
-		fprintf(stderr, "Client requested protocol '%s'\n", in);
-		if (strcmp(in, "dumb-increment-protocol") == 0)
-			/* accept it */
-			return 0;
-
-		/* reject the connection */
-		return 1;
+	default:
+		break;
 	}
 
 	return 0;
 }
 
+/* dumb_increment protocol */
+
+struct per_session_data__dumb_increment {
+	int number;
+};
+
+static int
+callback_dumb_increment(struct libwebsocket * wsi,
+			enum libwebsocket_callback_reasons reason,
+			void * user, void *in, size_t len)
+{
+	int n;
+	char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
+						  LWS_SEND_BUFFER_POST_PADDING];
+	unsigned char *p = (unsigned char *)&buf[LWS_SEND_BUFFER_PRE_PADDING];
+	struct per_session_data__dumb_increment * pss = user;
+	
+	switch (reason) {
+
+	case LWS_CALLBACK_ESTABLISHED:
+		pss->number = 0;
+		break;
+
+	case LWS_CALLBACK_SEND:	
+		n = sprintf(p, "%d", pss->number++);
+		n = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
+		if (n < 0) {
+			fprintf(stderr, "ERROR writing to socket");
+			return 1;
+		}
+		break;
+
+	case LWS_CALLBACK_RECEIVE:
+		if (len < 6)
+			break;
+		if (strcmp(in, "reset\n") == 0)
+			pss->number = 0;
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+
+/* list of supported protocols and callbacks */
+
+static const struct libwebsocket_protocols protocols[] = {
+	{
+		.name = "http-only",
+		.callback = callback_http,
+		.per_session_data_size = 0,
+	},
+	{
+		.name = "dumb-increment-protocol",
+		.callback = callback_dumb_increment,
+		.per_session_data_size =
+				sizeof(struct per_session_data__dumb_increment),
+	},
+	{  /* end of list */
+		.callback = NULL
+	}
+};
+
 static struct option options[] = {
 	{ "help", 	no_argument, NULL, 'h' },
 	{ "port", 	required_argument, NULL, 'p' },
-	{ "protocol", 	required_argument, NULL, 'r' },
 	{ "ssl", 	no_argument, NULL, 's' },
 	{ NULL, 0, 0, 0 }
 };
@@ -202,7 +148,7 @@
 						    "licensed under LGPL2.1\n");
 	
 	while (n >= 0) {
-		n = getopt_long(argc, argv, "hp:r:", options, NULL);
+		n = getopt_long(argc, argv, "hp:", options, NULL);
 		if (n < 0)
 			continue;
 		switch (n) {
@@ -214,7 +160,7 @@
 			break;
 		case 'h':
 			fprintf(stderr, "Usage: test-server "
-					     "[--port=<p>] [--protocol=<v>]\n");
+					     "[--port=<p>] [--ssl]\n");
 			exit(1);
 		}
 	}
@@ -222,9 +168,8 @@
 	if (!use_ssl)
 		cert_path = key_path = NULL;
 	
-	if (libwebsocket_create_server(port, websocket_callback,
-					 sizeof(struct per_session_data),
-					     cert_path, key_path, -1, -1) < 0) {
+	if (libwebsocket_create_server(port, protocols,
+				       cert_path, key_path, -1, -1) < 0) {
 		fprintf(stderr, "libwebsocket init failed\n");
 		return -1;
 	}