raw: enable server and client raw sockets
authorAndy Green <andy@warmcat.com>
Tue, 7 Mar 2017 08:06:05 +0000 (16:06 +0800)
committerAndy Green <andy@warmcat.com>
Tue, 7 Mar 2017 08:06:05 +0000 (16:06 +0800)
13 files changed:
README.coding.md
lib/client.c
lib/context.c
lib/handshake.c
lib/libwebsockets.c
lib/libwebsockets.h
lib/parsers.c
lib/private-libwebsockets.h
lib/server.c
lib/service.c
plugins/protocol_lws_raw_test.c
test-server/test-client.c
test-server/test-server-v2.0.c

index 15d4c4a..33a13f6 100644 (file)
@@ -440,6 +440,122 @@ on the flags during open.
 7) There is an optional `mod_time` uint32_t member in the generic fop_fd.  If you are able to set it during open, you
 should indicate it by setting `LWS_FOP_FLAG_MOD_TIME_VALID` on the flags.
 
+@section rawfd RAW file descriptor polling
+
+LWS allows you to include generic platform file descriptors in the lws service / poll / event loop.
+
+Open your fd normally and then
+
+```
+       lws_sock_file_fd_type u;
+
+       u.filefd = your_open_file_fd;
+
+       if (!lws_adopt_descriptor_vhost(vhost, 0, u,
+                                       "protocol-name-to-bind-to",
+                                       optional_wsi_parent_or_NULL)) {
+               // failed
+       }
+
+       // OK
+```
+
+A wsi is created for the file fd that acts like other wsi, you will get these
+callbacks on the named protocol
+
+```
+       LWS_CALLBACK_RAW_ADOPT_FILE
+       LWS_CALLBACK_RAW_RX_FILE
+       LWS_CALLBACK_RAW_WRITEABLE_FILE
+       LWS_CALLBACK_RAW_CLOSE_FILE
+```
+
+starting with LWS_CALLBACK_RAW_ADOPT_FILE.
+
+`protocol-lws-raw-test` plugin provides a method for testing this with
+`libwebsockets-test-server-v2.0`:
+
+The plugin creates a FIFO on your system called "/tmp/lws-test-raw"
+
+You can feed it data through the FIFO like this
+
+```
+  $ sudo sh -c "echo hello > /tmp/lws-test-raw"
+```
+
+This plugin simply prints the data.  But it does it through the lws event
+loop / service poll.
+
+@section rawsrvsocket RAW server socket descriptor polling
+
+You can also enable your vhost to accept RAW socket connections, in addition to
+HTTP[s] and WS[s].  If the first bytes written on the connection are not a
+valid HTTP method, then the connection switches to RAW mode.
+
+This is disabled by default, you enable it by setting the `.options` flag
+LWS_SERVER_OPTION_FALLBACK_TO_RAW when creating the vhost.
+
+RAW mode socket connections receive the following callbacks
+
+```
+       LWS_CALLBACK_RAW_ADOPT
+       LWS_CALLBACK_RAW_RX
+       LWS_CALLBACK_RAW_WRITEABLE
+       LWS_CALLBACK_RAW_CLOSE
+```
+
+You can control which protocol on your vhost handles these RAW mode
+incoming connections by marking the selected protocol with a pvo `raw`, eg
+
+```
+        "protocol-lws-raw-test": {
+                 "status": "ok",
+                 "raw": "1"
+        },
+```
+
+The "raw" pvo marks this protocol as being used for RAW connections.
+
+`protocol-lws-raw-test` plugin provides a method for testing this with
+`libwebsockets-test-server-v2.0`:
+
+Run libwebsockets-test-server-v2.0 and connect to it by telnet, eg
+
+```
+    $ telnet 127.0.0.1 7681
+```
+
+type something that isn't a valid HTTP method and enter, before the
+connection times out.  The connection will switch to RAW mode using this
+protocol, and pass the unused rx as a raw RX callback.
+    
+The test protocol echos back what was typed on telnet to telnet.
+
+@section rawclientsocket RAW client socket descriptor polling
+
+You can now also open RAW socket connections in client mode.
+
+Follow the usual method for creating a client connection, but set the
+`info.method` to "RAW".  When the connection is made, the wsi will be
+converted to RAW mode and operate using the same callbacks as the
+server RAW sockets described above.
+
+The libwebsockets-test-client supports this using raw:// URLS.  To
+test, open a netcat listener in one window
+
+```
+ $ nc -l 9999
+```
+
+and in another window, connect to it using the test client
+
+```
+ $ libwebsockets-test-client raw://127.0.0.1:9999
+```
+
+The connection should succeed, and text typed in the netcat window (including a CRLF)
+will be received in the client.
+
 @section ecdh ECDH Support
 
 ECDH Certs are now supported.  Enable the CMake option
index 57b79f4..5a29aa6 100755 (executable)
@@ -196,6 +196,9 @@ lws_client_socket_service(struct lws_context *context, struct lws *wsi,
        case LWSCM_WSCL_ISSUE_HANDSHAKE2:
                p = lws_generate_client_handshake(wsi, p);
                if (p == NULL) {
+                       if (wsi->mode == LWSCM_RAW)
+                               return 0;
+
                        lwsl_err("Failed to generate handshake for client\n");
                        lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
                        return 0;
@@ -1027,6 +1030,36 @@ lws_generate_client_handshake(struct lws *wsi, char *pkt)
        } else
                wsi->do_ws = 0;
 
+       if (!strcmp(meth, "RAW")) {
+               const char *pp = lws_hdr_simple_ptr(wsi,
+                                       _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
+               lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
+               lwsl_notice("client transition to raw\n");
+               if (pp) {
+                       const struct lws_protocols *pr;
+
+                       pr = lws_vhost_name_to_protocol(wsi->vhost, pp);
+
+                       if (!pr) {
+                               lwsl_err("protocol %s not enabled on vhost\n",
+                                        pp);
+                               return NULL;
+                       }
+
+                       lws_bind_protocol(wsi, pr);
+               }
+               if ((wsi->protocol->callback)(wsi,
+                               LWS_CALLBACK_RAW_ADOPT,
+                               wsi->user_space, NULL, 0))
+                       return NULL;
+
+               wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
+               lws_union_transition(wsi, LWSCM_RAW);
+               lws_header_table_detach(wsi, 1);
+
+               return NULL;
+       }
+
        if (wsi->do_ws) {
                /*
                 * create the random key
index 024cc81..7f4237a 100644 (file)
@@ -175,6 +175,13 @@ lws_protocol_init(struct lws_context *context)
                                                   vh->protocols[n].name);
                                                vh->default_protocol_index = n;
                                        }
+                                       if (!strcmp(pvo->name, "raw")) {
+                                               lwsl_notice("Setting raw "
+                                                  "protocol for vh %s to %s\n",
+                                                  vh->name,
+                                                  vh->protocols[n].name);
+                                               vh->raw_protocol_index = n;
+                                       }
                                        pvo = pvo->next;
                                }
 
index 68215cb..5f34b0e 100644 (file)
@@ -121,6 +121,11 @@ lws_read(struct lws *wsi, unsigned char *buf, size_t len)
                        /* Handshake indicates this session is done. */
                        goto bail;
 
+               /* we might have transitioned to RAW */
+               if (wsi->mode == LWSCM_RAW)
+                        /* we gave the read buffer to RAW handler already */
+                       goto read_ok;
+
                /*
                 * It's possible that we've exhausted our data already, or
                 * rx flow control has stopped us dealing with this early,
index 9443589..d03e740 100755 (executable)
@@ -165,6 +165,32 @@ lws_remove_child_from_any_parent(struct lws *wsi)
        }
 }
 
+int
+lws_bind_protocol(struct lws *wsi, const struct lws_protocols *p)
+{
+//     if (wsi->protocol == p)
+//             return 0;
+
+       if (wsi->protocol)
+               wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP_DROP_PROTOCOL,
+                                       wsi->user_space, NULL, 0);
+       if (!wsi->user_space_externally_allocated)
+               lws_free_set_NULL(wsi->user_space);
+
+       wsi->protocol = p;
+       if (!p)
+               return 0;
+
+       if (lws_ensure_user_space(wsi))
+               return 1;
+
+       if (wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP_BIND_PROTOCOL,
+                                   wsi->user_space, NULL, 0))
+               return 1;
+
+       return 0;
+}
+
 void
 lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
 {
index 14682a9..d76a558 100644 (file)
@@ -1612,6 +1612,8 @@ enum lws_context_options {
         * the context, only the string you give in the client connect
         * info for .origin (if any) will be used directly.
         */
+       LWS_SERVER_OPTION_FALLBACK_TO_RAW                       = (1 << 20),
+       /**< (VH) if invalid http is coming in the first line,  */
 
        /****** add new things just above ---^ ******/
 };
index 26f53f4..4eb0459 100644 (file)
@@ -813,9 +813,16 @@ swallow:
                                }
                        /*
                         * hm it's an unknown http method from a client in fact,
-                        * treat as dangerous
+                        * it cannot be valid http
                         */
                        if (m == ARRAY_SIZE(methods)) {
+                               /*
+                                * are we set up to accept raw in these cases?
+                                */
+                               if (lws_check_opt(wsi->vhost->options,
+                                          LWS_SERVER_OPTION_FALLBACK_TO_RAW))
+                                       return 2; /* transition to raw */
+
                                lwsl_info("Unknown method - dropping\n");
                                goto forbid;
                        }
index 80d0636..b0b5947 100644 (file)
@@ -795,6 +795,7 @@ struct lws_vhost {
        unsigned int created_vhost_protocols:1;
 
        unsigned char default_protocol_index;
+       unsigned char raw_protocol_index;
 };
 
 /*
index 32d972e..94eb0d0 100644 (file)
@@ -210,7 +210,7 @@ lws_select_vhost(struct lws_context *context, int port, const char *servername)
        if (p)
                colon = p - servername;
 
-       /* first try exact matches */
+       /* Priotity 1: first try exact matches */
 
        while (vhost) {
                if (port == vhost->listen_port &&
@@ -222,7 +222,7 @@ lws_select_vhost(struct lws_context *context, int port, const char *servername)
        }
 
        /*
-        * if no exact matches, try matching *.vhost-name
+        * Priority 2: if no exact matches, try matching *.vhost-name
         * unintentional matches are possible but resolve to x.com for *.x.com
         * which is reasonable.  If exact match exists we already chose it and
         * never reach here.  SSL will still fail it if the cert doesn't allow
@@ -243,6 +243,20 @@ lws_select_vhost(struct lws_context *context, int port, const char *servername)
                vhost = vhost->vhost_next;
        }
 
+       /* Priority 3: match the first vhost on our port */
+
+       vhost = context->vhost_list;
+       while (vhost) {
+               if (port == vhost->listen_port) {
+                       lwsl_info("vhost match to %s based on port %d\n",
+                                       vhost->name, port);
+                       return vhost;
+               }
+               vhost = vhost->vhost_next;
+       }
+
+       /* no match */
+
        return NULL;
 }
 
@@ -1137,43 +1151,19 @@ transaction_result_n:
 #endif
 }
 
-int
-lws_bind_protocol(struct lws *wsi, const struct lws_protocols *p)
-{
-//     if (wsi->protocol == p)
-//             return 0;
-
-       if (wsi->protocol)
-               wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP_DROP_PROTOCOL,
-                                       wsi->user_space, NULL, 0);
-       if (!wsi->user_space_externally_allocated)
-               lws_free_set_NULL(wsi->user_space);
-
-       wsi->protocol = p;
-       if (!p)
-               return 0;
-
-       if (lws_ensure_user_space(wsi))
-               return 1;
-
-       if (wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP_BIND_PROTOCOL,
-                                   wsi->user_space, NULL, 0))
-               return 1;
-
-       return 0;
-}
-
 
 int
 lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
 {
+       int protocol_len, n = 0, hit, non_space_char_found = 0, m;
        struct lws_context *context = lws_get_context(wsi);
        struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
        struct _lws_header_related hdr;
        struct allocated_headers *ah;
-       int protocol_len, n = 0, hit, non_space_char_found = 0;
+       unsigned char *obuf = *buf;
        char protocol_list[128];
        char protocol_name[64];
+       size_t olen = len;
        char *p;
 
        if (len >= 10000000) {
@@ -1195,7 +1185,38 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
                        goto bail_nuke_ah;
                }
 
-               if (lws_parse(wsi, *(*buf)++)) {
+               m = lws_parse(wsi, *(*buf)++);
+               if (m) {
+                       if (m == 2) {
+                               /*
+                                * we are transitioning from http with
+                                * an AH, to raw.  Drop the ah and set
+                                * the mode.
+                                */
+raw_transition:
+                               lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
+                               lws_bind_protocol(wsi, &wsi->vhost->protocols[
+                                                       wsi->vhost->
+                                                       raw_protocol_index]);
+                               lwsl_info("transition to raw vh %s prot %d\n",
+                                         wsi->vhost->name,
+                                         wsi->vhost->raw_protocol_index);
+                               if ((wsi->protocol->callback)(wsi,
+                                               LWS_CALLBACK_RAW_ADOPT,
+                                               wsi->user_space, NULL, 0))
+                                       goto bail_nuke_ah;
+
+                               wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
+                               lws_union_transition(wsi, LWSCM_RAW);
+                               lws_header_table_detach(wsi, 1);
+
+                               if (m == 2 && (wsi->protocol->callback)(wsi,
+                                               LWS_CALLBACK_RAW_RX,
+                                               wsi->user_space, obuf, olen))
+                                       return 1;
+
+                               return 0;
+                       }
                        lwsl_info("lws_parse failed\n");
                        goto bail_nuke_ah;
                }
@@ -1253,13 +1274,8 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
 
                if (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECT)) {
                        lwsl_info("Changing to RAW mode\n");
-                       lws_union_transition(wsi, LWSCM_RAW);
-                       if (!wsi->more_rx_waiting) {
-                               wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
-
-                               //lwsl_notice("%p: dropping ah EST\n", wsi);
-                               lws_header_table_detach(wsi, 1);
-                       }
+                       m = 0;
+                       goto raw_transition;
                }
 
                wsi->mode = LWSCM_PRE_WS_SERVING_ACCEPT;
@@ -1991,6 +2007,7 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
        case LWSCM_HTTP_SERVING:
        case LWSCM_HTTP_SERVING_ACCEPTED:
        case LWSCM_HTTP2_SERVING:
+       case LWSCM_RAW:
 
                /* handle http headers coming in */
 
@@ -2033,9 +2050,9 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
 
                /* these states imply we MUST have an ah attached */
 
-               if (wsi->state == LWSS_HTTP ||
+               if (wsi->mode != LWSCM_RAW && (wsi->state == LWSS_HTTP ||
                    wsi->state == LWSS_HTTP_ISSUING_FILE ||
-                   wsi->state == LWSS_HTTP_HEADERS) {
+                   wsi->state == LWSS_HTTP_HEADERS)) {
                        if (!wsi->u.hdr.ah) {
                                
                                //lwsl_err("wsi %p: missing ah\n", wsi);
@@ -2105,7 +2122,7 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
 
                len = lws_ssl_capable_read(wsi, pt->serv_buf,
                                           context->pt_serv_buf_size);
-//             lwsl_notice("%s: wsi %p read %d\r\n", __func__, wsi, len);
+               lwsl_debug("%s: wsi %p read %d\r\n", __func__, wsi, len);
                switch (len) {
                case 0:
                        lwsl_info("%s: read 0 len\n", __func__);
@@ -2124,10 +2141,10 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
                                        wsi, LWS_CALLBACK_RAW_RX,
                                        wsi->user_space, pt->serv_buf, len);
                        if (n < 0) {
-                               lwsl_info("raw writeable_fail\n");
+                               lwsl_info("LWS_CALLBACK_RAW_RX_fail\n");
                                goto fail;
                        }
-                       break;
+                       goto try_pollout;
                }
 
                /* just ignore incoming if waiting for close */
@@ -2162,6 +2179,17 @@ try_pollout:
                        goto fail;
                }
 
+               if (wsi->mode == LWSCM_RAW) {
+                       n = user_callback_handle_rxflow(wsi->protocol->callback,
+                                       wsi, LWS_CALLBACK_RAW_WRITEABLE,
+                                       wsi->user_space, NULL, 0);
+                       if (n < 0) {
+                               lwsl_info("writeable_fail\n");
+                               goto fail;
+                       }
+                       break;
+               }
+
                if (!wsi->hdr_parsing_completed)
                        break;
 
index 84e489d..4b15319 100644 (file)
@@ -863,13 +863,15 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
                        goto handled;
                }
 #endif
+               /* fallthru */
+       case LWSCM_RAW:
                n = lws_server_socket_service(context, wsi, pollfd);
                if (n) /* closed by above */
                        return 1;
                goto handled;
 
        case LWSCM_RAW_FILEDESC:
-       case LWSCM_RAW:
+
                if (pollfd->revents & LWS_POLLOUT) {
                        n = lws_calllback_as_writeable(wsi);
                        if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
@@ -892,6 +894,9 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
                                goto close_and_handled;
                        }
                }
+
+               if (pollfd->revents & LWS_POLLHUP)
+                       goto close_and_handled;
                n = 0;
                goto handled;
 
index 047f136..35867e6 100644 (file)
  * may be proprietary.  So unlike the library itself, they are licensed
  * Public Domain.
  *
+ * This plugin test both raw file descriptors and raw socket descriptors.  It
+ * can test both or just one depending on how you configure it.  libwebsockets-
+ * test-server-v2.0 is set up to test both.
+ *
+ * RAW File Descriptor Testing
+ * ===========================
+ *
  * Enable on a vhost like this
  *
  *        "protocol-lws-raw-test": {
  *
  *  $ sudo sh -c "echo hello > /tmp/lws-test-raw"
  *
- * This plugin simply prints the data.  But it does it through the lws event loop /
- * service poll.
+ * This plugin simply prints the data.  But it does it through the lws event
+ * loop / service poll.
+ *
+ *
+ * RAW Socket Descriptor Testing
+ * =============================
+ *
+ * 1) You must give the vhost the option flag LWS_SERVER_OPTION_FALLBACK_TO_RAW
+ *
+ * 2) Enable on a vhost like this
+ *
+ *        "protocol-lws-raw-test": {
+ *                 "status": "ok",
+ *                 "raw": "1"
+ *        },
+ *
+ *    The "raw" pvo marks this protocol as being used for RAW connections.
+ *
+ * 3) Run libwebsockets-test-server-v2.0 and connect to it by telnet, eg
+ *
+ *    telnet 127.0.0.1 7681
+ *
+ *    type something that isn't a valid HTTP method and enter, before the
+ *    connection times out.  The connection will switch to RAW mode using this
+ *    protocol, and pass the unused rx as a raw RX callback.
+ *
+ *    The test protocol echos back what was typed on telnet to telnet.
  */
 
 #if !defined (LWS_PLUGIN_STATIC)
@@ -51,6 +83,8 @@ struct per_vhost_data__raw_test {
 
 struct per_session_data__raw_test {
        int number;
+       unsigned char buf[128];
+       int len;
 };
 
 static int
@@ -84,8 +118,8 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
                                pvo = pvo->next;
                        }
                        if (vhd->fifo_path[0] == '\0') {
-                               lwsl_err("Missing pvo \"fifo-path\"\n");
-                               return 1;
+                               lwsl_err("%s: Missing pvo \"fifo-path\", raw file fd testing disabled\n", __func__);
+                               break;
                        }
                }
                unlink(vhd->fifo_path);
@@ -101,7 +135,9 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
                }
                lwsl_notice("FIFO %s created\n", vhd->fifo_path);
                u.filefd = vhd->fifo;
-               if (!lws_adopt_descriptor_vhost(vhd->vhost, 0, u, "protocol-lws-raw-test", NULL)) {
+               if (!lws_adopt_descriptor_vhost(vhd->vhost, 0, u,
+                                               "protocol-lws-raw-test",
+                                               NULL)) {
                        lwsl_err("Failed to adopt fifo descriptor\n");
                        close(vhd->fifo);
                        unlink(vhd->fifo_path);
@@ -118,6 +154,11 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
                }
                break;
 
+
+       /*
+        * Callbacks related to Raw file descriptor testing
+        */
+
        case LWS_CALLBACK_RAW_ADOPT_FILE:
                lwsl_notice("LWS_CALLBACK_RAW_ADOPT_FILE\n");
                break;
@@ -179,6 +220,32 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
                lwsl_notice("LWS_CALLBACK_RAW_WRITEABLE_FILE\n");
                break;
 
+       /*
+        * Callbacks related to Raw socket descriptor testing
+        */
+
+       case LWS_CALLBACK_RAW_ADOPT:
+               lwsl_notice("LWS_CALLBACK_RAW_ADOPT\n");
+               break;
+
+       case LWS_CALLBACK_RAW_RX:
+               lwsl_notice("LWS_CALLBACK_RAW_RX %ld\n", (long)len);
+               if (len > sizeof(pss->buf))
+                       len = sizeof(pss->buf);
+               memcpy(pss->buf, in, len);
+               pss->len = len;
+               lws_callback_on_writable(wsi);
+               break;
+
+       case LWS_CALLBACK_RAW_CLOSE:
+               lwsl_notice("LWS_CALLBACK_RAW_CLOSE\n");
+               break;
+
+       case LWS_CALLBACK_RAW_WRITEABLE:
+               lwsl_notice("LWS_CALLBACK_RAW_WRITEABLE\n");
+               lws_write(wsi, pss->buf, pss->len, LWS_WRITE_HTTP);
+               break;
+
        default:
                break;
        }
index 63d0d6d..4575ee0 100644 (file)
@@ -334,10 +334,38 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
        return 0;
 }
 
+static int
+callback_test_raw_client(struct lws *wsi, enum lws_callback_reasons reason,
+                        void *user, void *in, size_t len)
+{
+       switch (reason) {
+       case LWS_CALLBACK_RAW_ADOPT:
+               lwsl_notice("LWS_CALLBACK_RAW_ADOPT\n");
+               break;
+
+       case LWS_CALLBACK_RAW_RX:
+               lwsl_notice("LWS_CALLBACK_RAW_RX %ld\n", (long)len);
+               puts(in);
+               break;
+
+       case LWS_CALLBACK_RAW_CLOSE:
+               lwsl_notice("LWS_CALLBACK_RAW_CLOSE\n");
+               break;
+
+       case LWS_CALLBACK_RAW_WRITEABLE:
+               lwsl_notice("LWS_CALLBACK_RAW_WRITEABLE\n");
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
 
 /* list of supported protocols and callbacks */
 
-static struct lws_protocols protocols[] = {
+static const struct lws_protocols protocols[] = {
        {
                "dumb-increment-protocol",
                callback_dumb_increment,
@@ -349,6 +377,11 @@ static struct lws_protocols protocols[] = {
                callback_lws_mirror,
                0,
                128,
+       }, {
+               "lws-test-raw-client",
+               callback_test_raw_client,
+               0,
+               128
        },
        { NULL, NULL, 0, 0 } /* end */
 };
@@ -597,7 +630,13 @@ int main(int argc, char **argv)
                        i.method = "GET";
                do_ws = 0;
        } else
-               lwsl_notice("using %s mode (ws)\n", prot);
+               if (!strcmp(prot, "raw")) {
+                       i.method = "RAW";
+                       i.protocol = "lws-test-raw-client";
+                       lwsl_notice("using RAW mode connection\n");
+                       do_ws = 0;
+               } else
+                       lwsl_notice("using %s mode (ws)\n", prot);
 
        /*
         * sit there servicing the websocket context to handle incoming
index 96e00a5..61149f8 100644 (file)
@@ -155,13 +155,34 @@ static const struct lws_protocol_vhost_options pvo_opt = {
        "1"
 };
 
+static const struct lws_protocol_vhost_options pvo_opt4a = {
+       NULL,
+       NULL,
+       "raw", /* indicate we are the protocol that gets raw connections */
+       "1"
+};
+
+static const struct lws_protocol_vhost_options pvo_opt4 = {
+       &pvo_opt4a,
+       NULL,
+       "fifo-path", /* tell the raw test plugin to open a raw file here */
+       "/tmp/lws-test-raw"
+};
+
 /*
  * We must enable the plugin protocols we want into our vhost with a
  * linked-list.  We can also give the plugin per-vhost options here.
  */
 
-static const struct lws_protocol_vhost_options pvo_3 = {
+static const struct lws_protocol_vhost_options pvo_4 = {
        NULL,
+       &pvo_opt4, /* set us as the protocol who gets raw connections */
+       "protocol-lws-raw-test",
+       "" /* ignored, just matches the protocol name above */
+};
+
+static const struct lws_protocol_vhost_options pvo_3 = {
+       &pvo_4,
        NULL,
        "protocol-post-demo",
        "" /* ignored, just matches the protocol name above */
@@ -367,7 +388,7 @@ int main(int argc, char **argv)
        info.gid = gid;
        info.uid = uid;
        info.max_http_header_pool = 16;
-       info.options = opts |
+       info.options = opts | LWS_SERVER_OPTION_FALLBACK_TO_RAW |
                        LWS_SERVER_OPTION_VALIDATE_UTF8 |
                        LWS_SERVER_OPTION_LIBUV; /* plugins require this */