move-to-automatic-protocol-list-scheme.patch
authorAndy Green <andy@warmcat.com>
Fri, 12 Nov 2010 10:44:16 +0000 (10:44 +0000)
committerAndy Green <andy@warmcat.com>
Fri, 12 Nov 2010 10:44:16 +0000 (10:44 +0000)
Signed-off-by: Andy Green <andy@warmcat.com>
lib/Makefile.am
lib/Makefile.in
lib/handshake.c
lib/libwebsockets.c
lib/libwebsockets.h
lib/parsers.c
lib/private-libwebsockets.h
libwebsockets-api-doc.html
test-server/test-server.c

index 78ced38..7cc2120 100644 (file)
@@ -12,7 +12,7 @@ libwebsockets_la_LDFLAGS=-version-info 0:1
 all-local:
         ../scripts/kernel-doc -html \
                 libwebsockets.c \
-                parsers.c \
-                ../test-server/test-server.c \
+               parsers.c \
+                libwebsockets.h \
                        > ../libwebsockets-api-doc.html
 
index 493db5b..dcf4a67 100644 (file)
@@ -578,8 +578,8 @@ uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES
 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.
index 2ca7938..7deb581 100644 (file)
@@ -94,9 +94,9 @@ libwebsocket_read(struct libwebsocket *wsi, unsigned char * buf, size_t len)
                
                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 @@ libwebsocket_read(struct libwebsocket *wsi, unsigned char * buf, size_t len)
 
                /* 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 @@ libwebsocket_read(struct libwebsocket *wsi, unsigned char * buf, size_t len)
                
                /* 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:
index 11ab790..60ecde2 100644 (file)
@@ -31,6 +31,48 @@ extern int
 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 @@ libwebsocket_close_and_free_session(struct libwebsocket *wsi)
 
        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 @@ libwebsocket_close_and_free_session(struct libwebsocket *wsi)
 #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 @@ libwebsocket_close_and_free_session(struct libwebsocket *wsi)
  */
 
 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 @@ int libwebsocket_create_server(int port,
                /* 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 @@ int libwebsocket_create_server(int port,
        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 @@ int libwebsocket_create_server(int port,
                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 @@ int libwebsocket_create_server(int port,
                                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 @@ int libwebsocket_create_server(int port,
                                        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 @@ int libwebsocket_create_server(int port,
                                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 @@ int libwebsocket_create_server(int port,
 
                        if (!(fds[client].revents & POLLIN))
                                continue;
-                               
-//                     fprintf(stderr, "POLLIN\n");
 
 #ifdef LWS_OPENSSL_SUPPORT
                        if (use_ssl)
@@ -371,8 +412,6 @@ int libwebsocket_create_server(int port,
 #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 @@ int libwebsocket_create_server(int port,
                        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 @@ poll_out:
 
                        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;               
index b1588b1..24042fc 100644 (file)
@@ -29,7 +29,6 @@ enum libwebsocket_callback_reasons {
        LWS_CALLBACK_SEND,
        LWS_CALLBACK_RECEIVE,
        LWS_CALLBACK_HTTP,
-       LWS_CALLBACK_PROTOCOL_FILTER,
 };
 
 enum libwebsocket_write_protocol {
@@ -40,14 +39,36 @@ enum libwebsocket_write_protocol {
 
 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!
index 9a767f8..52cd126 100644 (file)
@@ -210,9 +210,9 @@ static int libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c)
                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;
index 27f495a..d3789f1 100644 (file)
@@ -121,8 +121,7 @@ struct lws_tokens {
  */
 
 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 @@ struct libwebsocket {
        SSL *ssl;
 #endif
 
-       /* last */
-       char user_space[0];
+       void *user_space;
 };
 
 extern void 
index 5471d3a..e7dcb82 100644 (file)
@@ -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>,
 <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 @@ to http requests from the client.  It allows the callback to issue
 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>
index 1bba6e0..26f4a86 100644 (file)
 static int port = 7681;
 static int use_ssl = 0;
 
-struct per_session_data {
-       int number;
-};
-
- /**
- * 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.
- */
+/* this protocol server (always the first one) just knows how to do HTTP */
 
-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 @@ static int websocket_callback(struct libwebsocket * wsi,
                        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
-        */
+       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_PROTOCOL_FILTER:
-               if (in == NULL) {
-                       fprintf(stderr, "Client did not request protocol\n");
-                       /* reject it */
+       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;
                }
-               fprintf(stderr, "Client requested protocol '%s'\n", in);
-               if (strcmp(in, "dumb-increment-protocol") == 0)
-                       /* accept it */
-                       return 0;
+               break;
 
-               /* reject the connection */
-               return 1;
+       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 @@ int main(int argc, char **argv)
                                                    "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 @@ int main(int argc, char **argv)
                        break;
                case 'h':
                        fprintf(stderr, "Usage: test-server "
-                                            "[--port=<p>] [--protocol=<v>]\n");
+                                            "[--port=<p>] [--ssl]\n");
                        exit(1);
                }
        }
@@ -222,9 +168,8 @@ int main(int argc, char **argv)
        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;
        }