123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- /*
- * ws protocol handler plugin for testing raw file and raw socket
- *
- * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
- *
- * This file is made available under the Creative Commons CC0 1.0
- * Universal Public Domain Dedication.
- *
- * The person who associated a work with this deed has dedicated
- * the work to the public domain by waiving all of his or her rights
- * to the work worldwide under copyright law, including all related
- * and neighboring rights, to the extent allowed by law. You can copy,
- * modify, distribute and perform the work, even for commercial purposes,
- * all without asking permission.
- *
- * These test plugins are intended to be adapted for use in your code, which
- * 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": {
- * "status": "ok",
- * "fifo-path": "/tmp/lws-test-raw"
- * },
- *
- * Then 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.
- *
- *
- * 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)
- #define LWS_DLL
- #define LWS_INTERNAL
- #include "../lib/libwebsockets.h"
- #endif
- #include <string.h>
- struct per_vhost_data__raw_test {
- struct lws_context *context;
- struct lws_vhost *vhost;
- const struct lws_protocols *protocol;
- char fifo_path[100];
- int fifo;
- char zero_length_read;
- };
- struct per_session_data__raw_test {
- int number;
- unsigned char buf[128];
- int len;
- };
- static int
- callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
- void *user, void *in, size_t len)
- {
- struct per_session_data__raw_test *pss =
- (struct per_session_data__raw_test *)user;
- struct per_vhost_data__raw_test *vhd =
- (struct per_vhost_data__raw_test *)
- lws_protocol_vh_priv_get(lws_get_vhost(wsi),
- lws_get_protocol(wsi));
- lws_sock_file_fd_type u;
- (void)pss;
- switch (reason) {
- case LWS_CALLBACK_PROTOCOL_INIT:
- vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
- lws_get_protocol(wsi),
- sizeof(struct per_vhost_data__raw_test));
- vhd->context = lws_get_context(wsi);
- vhd->protocol = lws_get_protocol(wsi);
- vhd->vhost = lws_get_vhost(wsi);
- {
- const struct lws_protocol_vhost_options *pvo =
- (const struct lws_protocol_vhost_options *)in;
- while (pvo) {
- if (!strcmp(pvo->name, "fifo-path"))
- strncpy(vhd->fifo_path, pvo->value, sizeof(vhd->fifo_path) - 1);
- pvo = pvo->next;
- }
- if (vhd->fifo_path[0] == '\0') {
- lwsl_err("%s: Missing pvo \"fifo-path\", raw file fd testing disabled\n", __func__);
- break;
- }
- }
- unlink(vhd->fifo_path);
- if (mkfifo(vhd->fifo_path, 0666)) {
- lwsl_err("mkfifo failed\n");
- return 1;
- }
- vhd->fifo = open(vhd->fifo_path, O_NONBLOCK | O_RDONLY);
- if (vhd->fifo == -1) {
- lwsl_err("opening fifo failed\n");
- unlink(vhd->fifo_path);
- return 1;
- }
- 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)) {
- lwsl_err("Failed to adopt fifo descriptor\n");
- close(vhd->fifo);
- unlink(vhd->fifo_path);
- return 1;
- }
- break;
- case LWS_CALLBACK_PROTOCOL_DESTROY:
- if (!vhd)
- break;
- if (vhd->fifo >- 0) {
- close(vhd->fifo);
- unlink(vhd->fifo_path);
- }
- break;
- /*
- * Callbacks related to Raw file descriptor testing
- */
- case LWS_CALLBACK_RAW_ADOPT_FILE:
- lwsl_notice("LWS_CALLBACK_RAW_ADOPT_FILE\n");
- break;
- case LWS_CALLBACK_RAW_RX_FILE:
- lwsl_notice("LWS_CALLBACK_RAW_RX_FILE\n");
- {
- char buf[256];
- int n;
-
- n = read(vhd->fifo, buf, sizeof(buf) - 1);
- if (n < 0) {
- lwsl_err("FIFO read failed\n");
- return 1;
- }
- /*
- * When nobody opened the other side of the FIFO, the FIFO fd acts well and
- * only signals POLLIN when somebody opened and wrote to it.
- *
- * But if the other side of the FIFO closed it, we will see an endless
- * POLLIN and 0 available to read.
- *
- * The only way to handle it is to reopen the FIFO our side and wait for a
- * new peer. This is a quirk of FIFOs not of LWS.
- */
- if (n == 0) { /* peer closed - do reopen in close processing */
- vhd->zero_length_read = 1;
- return 1;
- }
- buf[n] = '\0';
- lwsl_info("read %d\n", n);
- puts(buf);
- }
- break;
- case LWS_CALLBACK_RAW_CLOSE_FILE:
- lwsl_notice("LWS_CALLBACK_RAW_CLOSE_FILE\n");
- if (vhd->zero_length_read) {
- vhd->zero_length_read = 0;
- close(vhd->fifo);
- /* the wsi that adopted the fifo file is closing... reopen the fifo and readopt */
- vhd->fifo = open(vhd->fifo_path, O_NONBLOCK | O_RDONLY);
- if (vhd->fifo == -1) {
- lwsl_err("opening fifo failed\n");
- return 1;
- }
- lwsl_notice("FIFO %s reopened\n", vhd->fifo_path);
- u.filefd = vhd->fifo;
- 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);
- return 1;
- }
- }
- break;
- case LWS_CALLBACK_RAW_WRITEABLE_FILE:
- 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;
- }
- return 0;
- }
- #define LWS_PLUGIN_PROTOCOL_RAW_TEST \
- { \
- "protocol-lws-raw-test", \
- callback_raw_test, \
- sizeof(struct per_session_data__raw_test), \
- 1024, /* rx buf size must be >= permessage-deflate rx size */ \
- }
- #if !defined (LWS_PLUGIN_STATIC)
-
- static const struct lws_protocols protocols[] = {
- LWS_PLUGIN_PROTOCOL_RAW_TEST
- };
- LWS_EXTERN LWS_VISIBLE int
- init_protocol_lws_raw_test(struct lws_context *context,
- struct lws_plugin_capability *c)
- {
- if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
- lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
- c->api_magic);
- return 1;
- }
- c->protocols = protocols;
- c->count_protocols = ARRAY_SIZE(protocols);
- c->extensions = NULL;
- c->count_extensions = 0;
- return 0;
- }
- LWS_EXTERN LWS_VISIBLE int
- destroy_protocol_lws_raw_test(struct lws_context *context)
- {
- return 0;
- }
- #endif
|