1 /*
2 * lws-minimal-secure-streams-tx
3 *
4 * Written in 2010-2020 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 tx from secure streams.
11 *
12 * It opens a stream and fires small 80-byte payloads on it at 50Hz (20ms)
13 */
14
15 #include <libwebsockets.h>
16 #include <string.h>
17 #include <signal.h>
18
19 #define PKT_SIZE 80
20 #define RATE_US 50000
21
22 static int interrupted, bad = 1;
23
24 typedef struct myss {
25 struct lws_sspc_handle *ss;
26 void *opaque_data;
27 /* ... application specific state ... */
28 lws_sorted_usec_list_t sul;
29
30 int count;
31 char due;
32 } myss_t;
33
34 /* secure streams payload interface */
35
36 static int
myss_rx(void * userobj,const uint8_t * buf,size_t len,int flags)37 myss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
38 {
39 // myss_t *m = (myss_t *)userobj;
40
41 //lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags);
42 //lwsl_hexdump_info(buf, len);
43
44 return 0;
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 if (m->count == 1000) {
53 interrupted = 1;
54 return;
55 }
56
57 m->due = 1;
58 lws_sspc_request_tx(m->ss);
59
60 lws_sul_schedule(lws_sspc_get_context(m->ss), 0, &m->sul, txcb, RATE_US);
61
62
63 }
64
65 static int
myss_tx(void * userobj,lws_ss_tx_ordinal_t ord,uint8_t * buf,size_t * len,int * flags)66 myss_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
67 int *flags)
68 {
69 myss_t *m = (myss_t *)userobj;
70
71 if (!m->due)
72 return 0;
73
74 m->due = 0;
75
76 if (lws_get_random(lws_sspc_get_context(m->ss), buf, PKT_SIZE) != PKT_SIZE)
77 return 1;
78
79 *len = PKT_SIZE;
80 *flags = 0;
81 if (!m->count)
82 *flags |= LWSSS_FLAG_SOM;
83 if (m->count == 999) {
84 *flags |= LWSSS_FLAG_EOM;
85 lwsl_user("%s: sent final packet\n", __func__);
86 bad = 0;
87 }
88
89 m->count++;
90
91 lws_sul_schedule(lws_sspc_get_context(m->ss), 0, &m->sul, txcb, RATE_US);
92
93 // lwsl_user("%s: sending pkt %d\n", __func__, m->count);
94
95 return 0;
96 }
97
98 static int
myss_state(void * userobj,void * sh,lws_ss_constate_t state,lws_ss_tx_ordinal_t ack)99 myss_state(void *userobj, void *sh, lws_ss_constate_t state,
100 lws_ss_tx_ordinal_t ack)
101 {
102 myss_t *m = (myss_t *)userobj;
103 struct lws_context *context = lws_sspc_get_context(m->ss);
104
105 lwsl_user("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name(state),
106 (unsigned int)ack);
107
108 switch (state) {
109 case LWSSSCS_CREATING:
110 break;
111 case LWSSSCS_CONNECTED:
112 lws_sul_schedule(context, 0, &m->sul, txcb, RATE_US);
113 break;
114 case LWSSSCS_DISCONNECTED:
115 lws_sul_schedule(context, 0, &m->sul, txcb,
116 LWS_SET_TIMER_USEC_CANCEL);
117 break;
118 case LWSSSCS_ALL_RETRIES_FAILED:
119 /* if we're out of retries, we want to close the app and FAIL */
120 interrupted = 1;
121 break;
122 default:
123 break;
124 }
125
126 return 0;
127 }
128
129 static void
sigint_handler(int sig)130 sigint_handler(int sig)
131 {
132 interrupted = 1;
133 }
134
main(int argc,const char ** argv)135 int main(int argc, const char **argv)
136 {
137 int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
138 struct lws_context_creation_info info;
139 struct lws_context *context;
140 lws_ss_info_t ssi;
141 const char *p;
142
143 signal(SIGINT, sigint_handler);
144
145 if ((p = lws_cmdline_option(argc, argv, "-d")))
146 logs = atoi(p);
147
148 lws_set_log_level(logs, NULL);
149 lwsl_user("LWS secure streams client TX [-d<verb>]\n");
150
151 memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
152
153 info.options = //LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
154 LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
155 info.fd_limit_per_thread = 1 + 6 + 1;
156 info.port = CONTEXT_PORT_NO_LISTEN;
157 info.protocols = lws_sspc_protocols;
158 #if defined(LWS_WITH_DETAILED_LATENCY)
159 info.detailed_latency_cb = lws_det_lat_plot_cb;
160 info.detailed_latency_filepath = "/tmp/lws-latency-ssclient";
161 #endif
162
163 context = lws_create_context(&info);
164 if (!context) {
165 lwsl_err("lws init failed\n");
166 return 1;
167 }
168
169 /*
170 * We're requesting a secure stream via proxy... where and how this
171 * connects are details managed by the proxy policy
172 */
173
174 memset(&ssi, 0, sizeof ssi);
175 ssi.handle_offset = offsetof(myss_t, ss);
176 ssi.opaque_user_data_offset = offsetof(myss_t, opaque_data);
177 ssi.rx = myss_rx;
178 ssi.tx = myss_tx;
179 ssi.state = myss_state;
180 ssi.user_alloc = sizeof(myss_t);
181 ssi.streamtype = "spam";
182
183 if (lws_sspc_create(context, 0, &ssi, NULL, NULL, NULL, NULL)) {
184 lwsl_err("%s: create secure stream failed\n", __func__);
185 goto bail;
186 }
187
188 /* the event loop */
189
190 while (n >= 0 && !interrupted)
191 n = lws_service(context, 0);
192
193 bail:
194 lws_context_destroy(context);
195 lwsl_user("Completed: %s\n", bad ? "failed" : "OK");
196
197 return bad;
198 }
199