1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * lws-minimal-secure-streams-tx 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Written in 2010-2021 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 * 10d4afb5ceSopenharmony_ci * This demonstrates proxied mass tx from secure streams, this example is a 11d4afb5ceSopenharmony_ci * client that has no policy of its own, but gets stuff done via the ss proxy. 12d4afb5ceSopenharmony_ci * 13d4afb5ceSopenharmony_ci * It opens a websocket stream and fires 100 x small 80-byte payloads on it 14d4afb5ceSopenharmony_ci * at 20Hz (50ms) 15d4afb5ceSopenharmony_ci */ 16d4afb5ceSopenharmony_ci 17d4afb5ceSopenharmony_ci#define LWS_SS_USE_SSPC 18d4afb5ceSopenharmony_ci 19d4afb5ceSopenharmony_ci#include <libwebsockets.h> 20d4afb5ceSopenharmony_ci#include <string.h> 21d4afb5ceSopenharmony_ci#include <signal.h> 22d4afb5ceSopenharmony_ci 23d4afb5ceSopenharmony_ci#define PKT_SIZE 80 24d4afb5ceSopenharmony_ci#define RATE_US 50000 25d4afb5ceSopenharmony_ci 26d4afb5ceSopenharmony_cistatic int interrupted, bad = 1, reads = 100; 27d4afb5ceSopenharmony_ci 28d4afb5ceSopenharmony_citypedef struct myss { 29d4afb5ceSopenharmony_ci struct lws_ss_handle *ss; 30d4afb5ceSopenharmony_ci void *opaque_data; 31d4afb5ceSopenharmony_ci /* ... application specific state ... */ 32d4afb5ceSopenharmony_ci lws_sorted_usec_list_t sul; 33d4afb5ceSopenharmony_ci 34d4afb5ceSopenharmony_ci int count; 35d4afb5ceSopenharmony_ci char due; 36d4afb5ceSopenharmony_ci} myss_t; 37d4afb5ceSopenharmony_ci 38d4afb5ceSopenharmony_ci/* secure streams payload interface */ 39d4afb5ceSopenharmony_ci 40d4afb5ceSopenharmony_cistatic lws_ss_state_return_t 41d4afb5ceSopenharmony_cimyss_rx(void *userobj, const uint8_t *buf, size_t len, int flags) 42d4afb5ceSopenharmony_ci{ 43d4afb5ceSopenharmony_ci /* this example isn't interested in rx */ 44d4afb5ceSopenharmony_ci return LWSSSSRET_OK; 45d4afb5ceSopenharmony_ci} 46d4afb5ceSopenharmony_ci 47d4afb5ceSopenharmony_cistatic void 48d4afb5ceSopenharmony_citxcb(struct lws_sorted_usec_list *sul) 49d4afb5ceSopenharmony_ci{ 50d4afb5ceSopenharmony_ci myss_t *m = lws_container_of(sul, myss_t, sul); 51d4afb5ceSopenharmony_ci 52d4afb5ceSopenharmony_ci /* 53d4afb5ceSopenharmony_ci * We want to do 100 of these ws messages, and then exit, so we can run 54d4afb5ceSopenharmony_ci * this as a pass / fail test. 55d4afb5ceSopenharmony_ci */ 56d4afb5ceSopenharmony_ci 57d4afb5ceSopenharmony_ci if (m->count == reads) { 58d4afb5ceSopenharmony_ci interrupted = 1; 59d4afb5ceSopenharmony_ci bad = 0; 60d4afb5ceSopenharmony_ci } else { 61d4afb5ceSopenharmony_ci m->due = 1; 62d4afb5ceSopenharmony_ci lws_ss_request_tx(m->ss); 63d4afb5ceSopenharmony_ci } 64d4afb5ceSopenharmony_ci 65d4afb5ceSopenharmony_ci lws_sul_schedule(lws_ss_get_context(m->ss), 0, &m->sul, txcb, RATE_US); 66d4afb5ceSopenharmony_ci} 67d4afb5ceSopenharmony_ci 68d4afb5ceSopenharmony_cistatic lws_ss_state_return_t 69d4afb5ceSopenharmony_cimyss_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len, 70d4afb5ceSopenharmony_ci int *flags) 71d4afb5ceSopenharmony_ci{ 72d4afb5ceSopenharmony_ci myss_t *m = (myss_t *)userobj; 73d4afb5ceSopenharmony_ci 74d4afb5ceSopenharmony_ci if (!m->due) 75d4afb5ceSopenharmony_ci return LWSSSSRET_TX_DONT_SEND; 76d4afb5ceSopenharmony_ci 77d4afb5ceSopenharmony_ci m->due = 0; 78d4afb5ceSopenharmony_ci 79d4afb5ceSopenharmony_ci if (lws_get_random(lws_ss_get_context(m->ss), buf, PKT_SIZE) != PKT_SIZE) 80d4afb5ceSopenharmony_ci return LWSSSSRET_TX_DONT_SEND; 81d4afb5ceSopenharmony_ci 82d4afb5ceSopenharmony_ci *len = PKT_SIZE; 83d4afb5ceSopenharmony_ci *flags = LWSSS_FLAG_SOM | LWSSS_FLAG_EOM; 84d4afb5ceSopenharmony_ci 85d4afb5ceSopenharmony_ci m->count++; 86d4afb5ceSopenharmony_ci 87d4afb5ceSopenharmony_ci lws_sul_schedule(lws_ss_get_context(m->ss), 0, &m->sul, txcb, RATE_US); 88d4afb5ceSopenharmony_ci 89d4afb5ceSopenharmony_ci lwsl_user("%s: sending pkt %d\n", __func__, m->count); 90d4afb5ceSopenharmony_ci 91d4afb5ceSopenharmony_ci return LWSSSSRET_OK; 92d4afb5ceSopenharmony_ci} 93d4afb5ceSopenharmony_ci 94d4afb5ceSopenharmony_cistatic lws_ss_state_return_t 95d4afb5ceSopenharmony_cimyss_state(void *userobj, void *sh, lws_ss_constate_t state, 96d4afb5ceSopenharmony_ci lws_ss_tx_ordinal_t ack) 97d4afb5ceSopenharmony_ci{ 98d4afb5ceSopenharmony_ci myss_t *m = (myss_t *)userobj; 99d4afb5ceSopenharmony_ci struct lws_context *context = lws_ss_get_context(m->ss); 100d4afb5ceSopenharmony_ci 101d4afb5ceSopenharmony_ci lwsl_user("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name((int)state), 102d4afb5ceSopenharmony_ci (unsigned int)ack); 103d4afb5ceSopenharmony_ci 104d4afb5ceSopenharmony_ci switch (state) { 105d4afb5ceSopenharmony_ci case LWSSSCS_CREATING: 106d4afb5ceSopenharmony_ci return lws_ss_client_connect(m->ss); 107d4afb5ceSopenharmony_ci 108d4afb5ceSopenharmony_ci case LWSSSCS_CONNECTED: 109d4afb5ceSopenharmony_ci lws_sul_schedule(context, 0, &m->sul, txcb, RATE_US); 110d4afb5ceSopenharmony_ci break; 111d4afb5ceSopenharmony_ci case LWSSSCS_DISCONNECTED: 112d4afb5ceSopenharmony_ci lws_sul_cancel(&m->sul); 113d4afb5ceSopenharmony_ci break; 114d4afb5ceSopenharmony_ci case LWSSSCS_ALL_RETRIES_FAILED: 115d4afb5ceSopenharmony_ci /* if we're out of retries, we want to close the app and FAIL */ 116d4afb5ceSopenharmony_ci interrupted = 1; 117d4afb5ceSopenharmony_ci break; 118d4afb5ceSopenharmony_ci default: 119d4afb5ceSopenharmony_ci break; 120d4afb5ceSopenharmony_ci } 121d4afb5ceSopenharmony_ci 122d4afb5ceSopenharmony_ci return 0; 123d4afb5ceSopenharmony_ci} 124d4afb5ceSopenharmony_ci 125d4afb5ceSopenharmony_cistatic void 126d4afb5ceSopenharmony_cisigint_handler(int sig) 127d4afb5ceSopenharmony_ci{ 128d4afb5ceSopenharmony_ci interrupted = 1; 129d4afb5ceSopenharmony_ci} 130d4afb5ceSopenharmony_ci 131d4afb5ceSopenharmony_cistatic const lws_ss_info_t ssi = { 132d4afb5ceSopenharmony_ci .handle_offset = offsetof(myss_t, ss), 133d4afb5ceSopenharmony_ci .opaque_user_data_offset = offsetof(myss_t, opaque_data), 134d4afb5ceSopenharmony_ci .rx = myss_rx, 135d4afb5ceSopenharmony_ci .tx = myss_tx, 136d4afb5ceSopenharmony_ci .state = myss_state, 137d4afb5ceSopenharmony_ci .user_alloc = sizeof(myss_t), 138d4afb5ceSopenharmony_ci .streamtype = "spam" 139d4afb5ceSopenharmony_ci}; 140d4afb5ceSopenharmony_ci 141d4afb5ceSopenharmony_ciint main(int argc, const char **argv) 142d4afb5ceSopenharmony_ci{ 143d4afb5ceSopenharmony_ci int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE; 144d4afb5ceSopenharmony_ci struct lws_context_creation_info info; 145d4afb5ceSopenharmony_ci struct lws_context *context; 146d4afb5ceSopenharmony_ci const char *p; 147d4afb5ceSopenharmony_ci 148d4afb5ceSopenharmony_ci signal(SIGINT, sigint_handler); 149d4afb5ceSopenharmony_ci 150d4afb5ceSopenharmony_ci if ((p = lws_cmdline_option(argc, argv, "-d"))) 151d4afb5ceSopenharmony_ci logs = atoi(p); 152d4afb5ceSopenharmony_ci 153d4afb5ceSopenharmony_ci if ((p = lws_cmdline_option(argc, argv, "-c"))) 154d4afb5ceSopenharmony_ci reads = atoi(p); 155d4afb5ceSopenharmony_ci 156d4afb5ceSopenharmony_ci lws_set_log_level(logs, NULL); 157d4afb5ceSopenharmony_ci lwsl_user("LWS secure streams client TX [-d<verb>]\n"); 158d4afb5ceSopenharmony_ci 159d4afb5ceSopenharmony_ci memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ 160d4afb5ceSopenharmony_ci 161d4afb5ceSopenharmony_ci info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; 162d4afb5ceSopenharmony_ci info.fd_limit_per_thread = 1 + 6 + 1; 163d4afb5ceSopenharmony_ci info.port = CONTEXT_PORT_NO_LISTEN; 164d4afb5ceSopenharmony_ci info.protocols = lws_sspc_protocols; 165d4afb5ceSopenharmony_ci { 166d4afb5ceSopenharmony_ci const char *p; 167d4afb5ceSopenharmony_ci 168d4afb5ceSopenharmony_ci /* connect to ssproxy via UDS by default, else via 169d4afb5ceSopenharmony_ci * tcp connection to this port */ 170d4afb5ceSopenharmony_ci if ((p = lws_cmdline_option(argc, argv, "-p"))) 171d4afb5ceSopenharmony_ci info.ss_proxy_port = (uint16_t)atoi(p); 172d4afb5ceSopenharmony_ci 173d4afb5ceSopenharmony_ci /* UDS "proxy.ss.lws" in abstract namespace, else this socket 174d4afb5ceSopenharmony_ci * path; when -p given this can specify the network interface 175d4afb5ceSopenharmony_ci * to bind to */ 176d4afb5ceSopenharmony_ci if ((p = lws_cmdline_option(argc, argv, "-i"))) 177d4afb5ceSopenharmony_ci info.ss_proxy_bind = p; 178d4afb5ceSopenharmony_ci 179d4afb5ceSopenharmony_ci /* if -p given, -a specifies the proxy address to connect to */ 180d4afb5ceSopenharmony_ci if ((p = lws_cmdline_option(argc, argv, "-a"))) 181d4afb5ceSopenharmony_ci info.ss_proxy_address = p; 182d4afb5ceSopenharmony_ci } 183d4afb5ceSopenharmony_ci 184d4afb5ceSopenharmony_ci context = lws_create_context(&info); 185d4afb5ceSopenharmony_ci if (!context) { 186d4afb5ceSopenharmony_ci lwsl_err("lws init failed\n"); 187d4afb5ceSopenharmony_ci goto bail1; 188d4afb5ceSopenharmony_ci } 189d4afb5ceSopenharmony_ci 190d4afb5ceSopenharmony_ci if (lws_ss_create(context, 0, &ssi, NULL, NULL, NULL, NULL)) { 191d4afb5ceSopenharmony_ci lwsl_err("%s: create secure stream failed\n", __func__); 192d4afb5ceSopenharmony_ci goto bail; 193d4afb5ceSopenharmony_ci } 194d4afb5ceSopenharmony_ci 195d4afb5ceSopenharmony_ci /* the event loop */ 196d4afb5ceSopenharmony_ci 197d4afb5ceSopenharmony_ci while (n >= 0 && !interrupted) 198d4afb5ceSopenharmony_ci n = lws_service(context, 0); 199d4afb5ceSopenharmony_ci 200d4afb5ceSopenharmony_cibail: 201d4afb5ceSopenharmony_ci lws_context_destroy(context); 202d4afb5ceSopenharmony_ci 203d4afb5ceSopenharmony_cibail1: 204d4afb5ceSopenharmony_ci lwsl_user("Completed: %s\n", bad ? "failed" : "OK"); 205d4afb5ceSopenharmony_ci 206d4afb5ceSopenharmony_ci return bad; 207d4afb5ceSopenharmony_ci} 208