1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * ws protocol handler plugin for testing raw file and raw socket 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Written in 2010-2019 by Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * This file is made available under the Creative Commons CC0 1.0 7d4afb5ceSopenharmony_ci * Universal Public Domain Dedication. 8d4afb5ceSopenharmony_ci * 9d4afb5ceSopenharmony_ci * The person who associated a work with this deed has dedicated 10d4afb5ceSopenharmony_ci * the work to the public domain by waiving all of his or her rights 11d4afb5ceSopenharmony_ci * to the work worldwide under copyright law, including all related 12d4afb5ceSopenharmony_ci * and neighboring rights, to the extent allowed by law. You can copy, 13d4afb5ceSopenharmony_ci * modify, distribute and perform the work, even for commercial purposes, 14d4afb5ceSopenharmony_ci * all without asking permission. 15d4afb5ceSopenharmony_ci * 16d4afb5ceSopenharmony_ci * These test plugins are intended to be adapted for use in your code, which 17d4afb5ceSopenharmony_ci * may be proprietary. So unlike the library itself, they are licensed 18d4afb5ceSopenharmony_ci * Public Domain. 19d4afb5ceSopenharmony_ci * 20d4afb5ceSopenharmony_ci * This plugin test both raw file descriptors and raw socket descriptors. It 21d4afb5ceSopenharmony_ci * can test both or just one depending on how you configure it. libwebsockets- 22d4afb5ceSopenharmony_ci * test-server-v2.0 is set up to test both. 23d4afb5ceSopenharmony_ci * 24d4afb5ceSopenharmony_ci * RAW File Descriptor Testing 25d4afb5ceSopenharmony_ci * =========================== 26d4afb5ceSopenharmony_ci * 27d4afb5ceSopenharmony_ci * Enable on a vhost like this 28d4afb5ceSopenharmony_ci * 29d4afb5ceSopenharmony_ci * "protocol-lws-raw-test": { 30d4afb5ceSopenharmony_ci * "status": "ok", 31d4afb5ceSopenharmony_ci * "fifo-path": "/tmp/lws-test-raw" 32d4afb5ceSopenharmony_ci * }, 33d4afb5ceSopenharmony_ci * 34d4afb5ceSopenharmony_ci * Then you can feed it data through the FIFO like this 35d4afb5ceSopenharmony_ci * 36d4afb5ceSopenharmony_ci * $ sudo sh -c "echo hello > /tmp/lws-test-raw" 37d4afb5ceSopenharmony_ci * 38d4afb5ceSopenharmony_ci * This plugin simply prints the data. But it does it through the lws event 39d4afb5ceSopenharmony_ci * loop / service poll. 40d4afb5ceSopenharmony_ci * 41d4afb5ceSopenharmony_ci * 42d4afb5ceSopenharmony_ci * RAW Socket Descriptor Testing 43d4afb5ceSopenharmony_ci * ============================= 44d4afb5ceSopenharmony_ci * 45d4afb5ceSopenharmony_ci * 1) You must give the vhost the option flag 46d4afb5ceSopenharmony_ci * LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG 47d4afb5ceSopenharmony_ci * 48d4afb5ceSopenharmony_ci * 2) Enable on a vhost like this 49d4afb5ceSopenharmony_ci * 50d4afb5ceSopenharmony_ci * "protocol-lws-raw-test": { 51d4afb5ceSopenharmony_ci * "status": "ok", 52d4afb5ceSopenharmony_ci * "raw": "1" 53d4afb5ceSopenharmony_ci * }, 54d4afb5ceSopenharmony_ci * 55d4afb5ceSopenharmony_ci * The "raw" pvo marks this protocol as being used for RAW connections. 56d4afb5ceSopenharmony_ci * 57d4afb5ceSopenharmony_ci * 3) Run libwebsockets-test-server-v2.0 and connect to it by telnet, eg 58d4afb5ceSopenharmony_ci * 59d4afb5ceSopenharmony_ci * telnet 127.0.0.1 7681 60d4afb5ceSopenharmony_ci * 61d4afb5ceSopenharmony_ci * type something that isn't a valid HTTP method and enter, before the 62d4afb5ceSopenharmony_ci * connection times out. The connection will switch to RAW mode using this 63d4afb5ceSopenharmony_ci * protocol, and pass the unused rx as a raw RX callback. 64d4afb5ceSopenharmony_ci * 65d4afb5ceSopenharmony_ci * The test protocol echos back what was typed on telnet to telnet. 66d4afb5ceSopenharmony_ci */ 67d4afb5ceSopenharmony_ci 68d4afb5ceSopenharmony_ci#if !defined (LWS_PLUGIN_STATIC) 69d4afb5ceSopenharmony_ci#if !defined(LWS_DLL) 70d4afb5ceSopenharmony_ci#define LWS_DLL 71d4afb5ceSopenharmony_ci#endif 72d4afb5ceSopenharmony_ci#if !defined(LWS_INTERNAL) 73d4afb5ceSopenharmony_ci#define LWS_INTERNAL 74d4afb5ceSopenharmony_ci#endif 75d4afb5ceSopenharmony_ci#include <libwebsockets.h> 76d4afb5ceSopenharmony_ci#endif 77d4afb5ceSopenharmony_ci 78d4afb5ceSopenharmony_ci#include <string.h> 79d4afb5ceSopenharmony_ci#include <fcntl.h> 80d4afb5ceSopenharmony_ci 81d4afb5ceSopenharmony_ci#include <sys/stat.h> 82d4afb5ceSopenharmony_ci 83d4afb5ceSopenharmony_cistruct per_vhost_data__raw_test { 84d4afb5ceSopenharmony_ci struct lws_context *context; 85d4afb5ceSopenharmony_ci struct lws_vhost *vhost; 86d4afb5ceSopenharmony_ci const struct lws_protocols *protocol; 87d4afb5ceSopenharmony_ci char fifo_path[100]; 88d4afb5ceSopenharmony_ci int fifo; 89d4afb5ceSopenharmony_ci char zero_length_read; 90d4afb5ceSopenharmony_ci}; 91d4afb5ceSopenharmony_ci 92d4afb5ceSopenharmony_cistruct per_session_data__raw_test { 93d4afb5ceSopenharmony_ci int number; 94d4afb5ceSopenharmony_ci unsigned char buf[128]; 95d4afb5ceSopenharmony_ci int len; 96d4afb5ceSopenharmony_ci}; 97d4afb5ceSopenharmony_ci 98d4afb5ceSopenharmony_cistatic int 99d4afb5ceSopenharmony_cicallback_raw_test(struct lws *wsi, enum lws_callback_reasons reason, void *user, 100d4afb5ceSopenharmony_ci void *in, size_t len) 101d4afb5ceSopenharmony_ci{ 102d4afb5ceSopenharmony_ci struct per_session_data__raw_test *pss = 103d4afb5ceSopenharmony_ci (struct per_session_data__raw_test *)user; 104d4afb5ceSopenharmony_ci struct per_vhost_data__raw_test *vhd = 105d4afb5ceSopenharmony_ci (struct per_vhost_data__raw_test *) 106d4afb5ceSopenharmony_ci lws_protocol_vh_priv_get(lws_get_vhost(wsi), 107d4afb5ceSopenharmony_ci lws_get_protocol(wsi)); 108d4afb5ceSopenharmony_ci lws_sock_file_fd_type u; 109d4afb5ceSopenharmony_ci 110d4afb5ceSopenharmony_ci (void)pss; 111d4afb5ceSopenharmony_ci 112d4afb5ceSopenharmony_ci switch (reason) { 113d4afb5ceSopenharmony_ci case LWS_CALLBACK_PROTOCOL_INIT: 114d4afb5ceSopenharmony_ci vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), 115d4afb5ceSopenharmony_ci lws_get_protocol(wsi), 116d4afb5ceSopenharmony_ci sizeof(struct per_vhost_data__raw_test)); 117d4afb5ceSopenharmony_ci if (!vhd) 118d4afb5ceSopenharmony_ci return 0; 119d4afb5ceSopenharmony_ci vhd->context = lws_get_context(wsi); 120d4afb5ceSopenharmony_ci vhd->protocol = lws_get_protocol(wsi); 121d4afb5ceSopenharmony_ci vhd->vhost = lws_get_vhost(wsi); 122d4afb5ceSopenharmony_ci { 123d4afb5ceSopenharmony_ci const struct lws_protocol_vhost_options *pvo = 124d4afb5ceSopenharmony_ci (const struct lws_protocol_vhost_options *)in; 125d4afb5ceSopenharmony_ci while (pvo) { 126d4afb5ceSopenharmony_ci if (!strcmp(pvo->name, "fifo-path")) 127d4afb5ceSopenharmony_ci lws_strncpy(vhd->fifo_path, pvo->value, 128d4afb5ceSopenharmony_ci sizeof(vhd->fifo_path)); 129d4afb5ceSopenharmony_ci pvo = pvo->next; 130d4afb5ceSopenharmony_ci } 131d4afb5ceSopenharmony_ci if (vhd->fifo_path[0] == '\0') { 132d4afb5ceSopenharmony_ci lwsl_warn("%s: Missing pvo \"fifo-path\", " 133d4afb5ceSopenharmony_ci "raw file fd testing disabled\n", 134d4afb5ceSopenharmony_ci __func__); 135d4afb5ceSopenharmony_ci break; 136d4afb5ceSopenharmony_ci } 137d4afb5ceSopenharmony_ci } 138d4afb5ceSopenharmony_ci unlink(vhd->fifo_path); 139d4afb5ceSopenharmony_ci if (mkfifo(vhd->fifo_path, 0666)) { 140d4afb5ceSopenharmony_ci lwsl_err("mkfifo failed\n"); 141d4afb5ceSopenharmony_ci return 1; 142d4afb5ceSopenharmony_ci } 143d4afb5ceSopenharmony_ci vhd->fifo = lws_open(vhd->fifo_path, O_NONBLOCK | O_RDONLY); 144d4afb5ceSopenharmony_ci if (vhd->fifo == -1) { 145d4afb5ceSopenharmony_ci lwsl_err("opening fifo failed\n"); 146d4afb5ceSopenharmony_ci unlink(vhd->fifo_path); 147d4afb5ceSopenharmony_ci return 1; 148d4afb5ceSopenharmony_ci } 149d4afb5ceSopenharmony_ci lwsl_notice("FIFO %s created\n", vhd->fifo_path); 150d4afb5ceSopenharmony_ci u.filefd = vhd->fifo; 151d4afb5ceSopenharmony_ci if (!lws_adopt_descriptor_vhost(vhd->vhost, 152d4afb5ceSopenharmony_ci LWS_ADOPT_RAW_FILE_DESC, u, 153d4afb5ceSopenharmony_ci "protocol-lws-raw-test", 154d4afb5ceSopenharmony_ci NULL)) { 155d4afb5ceSopenharmony_ci lwsl_err("Failed to adopt fifo descriptor\n"); 156d4afb5ceSopenharmony_ci close(vhd->fifo); 157d4afb5ceSopenharmony_ci unlink(vhd->fifo_path); 158d4afb5ceSopenharmony_ci return 1; 159d4afb5ceSopenharmony_ci } 160d4afb5ceSopenharmony_ci break; 161d4afb5ceSopenharmony_ci 162d4afb5ceSopenharmony_ci case LWS_CALLBACK_PROTOCOL_DESTROY: 163d4afb5ceSopenharmony_ci if (!vhd) 164d4afb5ceSopenharmony_ci break; 165d4afb5ceSopenharmony_ci if (vhd->fifo >= 0) { 166d4afb5ceSopenharmony_ci close(vhd->fifo); 167d4afb5ceSopenharmony_ci unlink(vhd->fifo_path); 168d4afb5ceSopenharmony_ci } 169d4afb5ceSopenharmony_ci break; 170d4afb5ceSopenharmony_ci 171d4afb5ceSopenharmony_ci 172d4afb5ceSopenharmony_ci /* 173d4afb5ceSopenharmony_ci * Callbacks related to Raw file descriptor testing 174d4afb5ceSopenharmony_ci */ 175d4afb5ceSopenharmony_ci 176d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_ADOPT_FILE: 177d4afb5ceSopenharmony_ci lwsl_notice("LWS_CALLBACK_RAW_ADOPT_FILE\n"); 178d4afb5ceSopenharmony_ci break; 179d4afb5ceSopenharmony_ci 180d4afb5ceSopenharmony_ci 181d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_RX_FILE: 182d4afb5ceSopenharmony_ci lwsl_notice("LWS_CALLBACK_RAW_RX_FILE\n"); 183d4afb5ceSopenharmony_ci { 184d4afb5ceSopenharmony_ci char buf[256]; 185d4afb5ceSopenharmony_ci int n; 186d4afb5ceSopenharmony_ci 187d4afb5ceSopenharmony_ci n = (int)read(vhd->fifo, buf, sizeof(buf) - 1); 188d4afb5ceSopenharmony_ci if (n < 0) { 189d4afb5ceSopenharmony_ci lwsl_err("FIFO read failed\n"); 190d4afb5ceSopenharmony_ci return 1; 191d4afb5ceSopenharmony_ci } 192d4afb5ceSopenharmony_ci /* 193d4afb5ceSopenharmony_ci * When nobody opened the other side of the FIFO, the 194d4afb5ceSopenharmony_ci * FIFO fd acts well and only signals POLLIN when 195d4afb5ceSopenharmony_ci * somebody opened and wrote to it. 196d4afb5ceSopenharmony_ci * 197d4afb5ceSopenharmony_ci * But if the other side of the FIFO closed it, we will 198d4afb5ceSopenharmony_ci * see an endless POLLIN and 0 available to read. 199d4afb5ceSopenharmony_ci * 200d4afb5ceSopenharmony_ci * The only way to handle it is to reopen the FIFO our 201d4afb5ceSopenharmony_ci * side and wait for a new peer. This is a quirk of 202d4afb5ceSopenharmony_ci * FIFOs not of LWS. 203d4afb5ceSopenharmony_ci */ 204d4afb5ceSopenharmony_ci if (n == 0) { /* peer closed - reopen in close processing */ 205d4afb5ceSopenharmony_ci vhd->zero_length_read = 1; 206d4afb5ceSopenharmony_ci return 1; 207d4afb5ceSopenharmony_ci } 208d4afb5ceSopenharmony_ci buf[n] = '\0'; 209d4afb5ceSopenharmony_ci lwsl_info("read %d\n", n); 210d4afb5ceSopenharmony_ci puts(buf); 211d4afb5ceSopenharmony_ci } 212d4afb5ceSopenharmony_ci break; 213d4afb5ceSopenharmony_ci 214d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_CLOSE_FILE: 215d4afb5ceSopenharmony_ci lwsl_notice("LWS_CALLBACK_RAW_CLOSE_FILE\n"); 216d4afb5ceSopenharmony_ci if (vhd->zero_length_read) { 217d4afb5ceSopenharmony_ci vhd->zero_length_read = 0; 218d4afb5ceSopenharmony_ci close(vhd->fifo); 219d4afb5ceSopenharmony_ci /* the wsi that adopted the fifo file is closing... 220d4afb5ceSopenharmony_ci * reopen the fifo and readopt 221d4afb5ceSopenharmony_ci */ 222d4afb5ceSopenharmony_ci vhd->fifo = lws_open(vhd->fifo_path, 223d4afb5ceSopenharmony_ci O_NONBLOCK | O_RDONLY); 224d4afb5ceSopenharmony_ci if (vhd->fifo == -1) { 225d4afb5ceSopenharmony_ci lwsl_err("opening fifo failed\n"); 226d4afb5ceSopenharmony_ci return 1; 227d4afb5ceSopenharmony_ci } 228d4afb5ceSopenharmony_ci lwsl_notice("FIFO %s reopened\n", vhd->fifo_path); 229d4afb5ceSopenharmony_ci u.filefd = vhd->fifo; 230d4afb5ceSopenharmony_ci if (!lws_adopt_descriptor_vhost(vhd->vhost, 0, u, 231d4afb5ceSopenharmony_ci "protocol-lws-raw-test", NULL)) { 232d4afb5ceSopenharmony_ci lwsl_err("Failed to adopt fifo descriptor\n"); 233d4afb5ceSopenharmony_ci close(vhd->fifo); 234d4afb5ceSopenharmony_ci return 1; 235d4afb5ceSopenharmony_ci } 236d4afb5ceSopenharmony_ci } 237d4afb5ceSopenharmony_ci break; 238d4afb5ceSopenharmony_ci 239d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_WRITEABLE_FILE: 240d4afb5ceSopenharmony_ci lwsl_notice("LWS_CALLBACK_RAW_WRITEABLE_FILE\n"); 241d4afb5ceSopenharmony_ci break; 242d4afb5ceSopenharmony_ci 243d4afb5ceSopenharmony_ci /* 244d4afb5ceSopenharmony_ci * Callbacks related to Raw socket descriptor testing 245d4afb5ceSopenharmony_ci */ 246d4afb5ceSopenharmony_ci 247d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_ADOPT: 248d4afb5ceSopenharmony_ci lwsl_notice("LWS_CALLBACK_RAW_ADOPT\n"); 249d4afb5ceSopenharmony_ci break; 250d4afb5ceSopenharmony_ci 251d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_RX: 252d4afb5ceSopenharmony_ci lwsl_notice("LWS_CALLBACK_RAW_RX %ld\n", (long)len); 253d4afb5ceSopenharmony_ci if (len > sizeof(pss->buf)) 254d4afb5ceSopenharmony_ci len = sizeof(pss->buf); 255d4afb5ceSopenharmony_ci memcpy(pss->buf, in, len); 256d4afb5ceSopenharmony_ci pss->len = (int)len; 257d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 258d4afb5ceSopenharmony_ci break; 259d4afb5ceSopenharmony_ci 260d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_CLOSE: 261d4afb5ceSopenharmony_ci lwsl_notice("LWS_CALLBACK_RAW_CLOSE\n"); 262d4afb5ceSopenharmony_ci break; 263d4afb5ceSopenharmony_ci 264d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_WRITEABLE: 265d4afb5ceSopenharmony_ci lwsl_notice("LWS_CALLBACK_RAW_WRITEABLE\n"); 266d4afb5ceSopenharmony_ci lws_write(wsi, pss->buf, (size_t)pss->len, LWS_WRITE_HTTP); 267d4afb5ceSopenharmony_ci break; 268d4afb5ceSopenharmony_ci 269d4afb5ceSopenharmony_ci default: 270d4afb5ceSopenharmony_ci break; 271d4afb5ceSopenharmony_ci } 272d4afb5ceSopenharmony_ci 273d4afb5ceSopenharmony_ci return 0; 274d4afb5ceSopenharmony_ci} 275d4afb5ceSopenharmony_ci 276d4afb5ceSopenharmony_ci#define LWS_PLUGIN_PROTOCOL_RAW_TEST \ 277d4afb5ceSopenharmony_ci { \ 278d4afb5ceSopenharmony_ci "protocol-lws-raw-test", \ 279d4afb5ceSopenharmony_ci callback_raw_test, \ 280d4afb5ceSopenharmony_ci sizeof(struct per_session_data__raw_test), \ 281d4afb5ceSopenharmony_ci 1024, /* rx buf size must be >= permessage-deflate rx size */ 0, NULL, 0\ 282d4afb5ceSopenharmony_ci } 283d4afb5ceSopenharmony_ci 284d4afb5ceSopenharmony_ci#if !defined (LWS_PLUGIN_STATIC) 285d4afb5ceSopenharmony_ci 286d4afb5ceSopenharmony_ciLWS_VISIBLE const struct lws_protocols lws_raw_test_protocols[] = { 287d4afb5ceSopenharmony_ci LWS_PLUGIN_PROTOCOL_RAW_TEST 288d4afb5ceSopenharmony_ci}; 289d4afb5ceSopenharmony_ci 290d4afb5ceSopenharmony_ciLWS_VISIBLE const lws_plugin_protocol_t lws_raw_test = { 291d4afb5ceSopenharmony_ci .hdr = { 292d4afb5ceSopenharmony_ci "lws raw test", 293d4afb5ceSopenharmony_ci "lws_protocol_plugin", 294d4afb5ceSopenharmony_ci LWS_BUILD_HASH, 295d4afb5ceSopenharmony_ci LWS_PLUGIN_API_MAGIC 296d4afb5ceSopenharmony_ci }, 297d4afb5ceSopenharmony_ci 298d4afb5ceSopenharmony_ci .protocols = lws_raw_test_protocols, 299d4afb5ceSopenharmony_ci .count_protocols = LWS_ARRAY_SIZE(lws_raw_test_protocols), 300d4afb5ceSopenharmony_ci .extensions = NULL, 301d4afb5ceSopenharmony_ci .count_extensions = 0, 302d4afb5ceSopenharmony_ci}; 303d4afb5ceSopenharmony_ci 304d4afb5ceSopenharmony_ci#endif 305