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