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