• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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