• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lws-minimal-secure-streams-server
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 #include <libwebsockets.h>
11 #include <assert.h>
12 
13 extern int interrupted, bad, multipart;
14 
15 static const char *html =
16 		/* normally we serve this... */
17 	"<head><meta content=\"text/html;charset=utf-8\" "
18 			"http-equiv=\"Content-Type\"><script>"
19 	" var ws = new WebSocket(\"wss://localhost:7681\", \"mywsprotocol\");"
20 	"try { ws.onopen = function() { console.log(\"open\"); }; "
21 		"ws.onmessage = function got_packet(msg) { "
22 		   "var s=\"\"; s += msg.data; "
23 		   "document.getElementById(\"wsd\").innerHTML = s; };"
24 		"} catch(exception) {"
25 		"alert(\"<p>Error\" + exception); }"
26 	"</script></head><html><body>"
27 	  "Hello from the web server<br>"
28 	  "<div id=\"wsd\"></div>"
29 	"</body></html>",
30 
31 *multipart_html =
32 	/*
33 	 * If you use -m commandline switch we send this instead, as
34 	 * multipart/form-data
35 	 */
36 	"--aBoundaryString\r\n"
37 	"Content-Disposition: form-data; name=\"myFile\"; filename=\"xxx.txt\"\r\n"
38 	"Content-Type: text/plain\r\n"
39 	"\r\n"
40 	"The file contents\r\n"
41 	"--aBoundaryString\r\n"
42 	"Content-Disposition: form-data; name=\"myField\"\r\n"
43 	"\r\n"
44 	"(data)\r\n"
45 	"--aBoundaryString--\r\n";
46 
47 
48 typedef struct myss {
49 	struct lws_ss_handle 		*ss;
50 	void				*opaque_data;
51 	/* ... application specific state ... */
52 
53 	lws_sorted_usec_list_t		sul;
54 	int				count;
55 	char				upgraded;
56 
57 } myss_srv_t;
58 
59 /*
60  * This is the Secure Streams Server RX and TX for HTTP(S)
61  */
62 
63 static lws_ss_state_return_t
myss_srv_rx(void * userobj,const uint8_t * buf,size_t len,int flags)64 myss_srv_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
65 {
66 //	myss_srv_t *m = (myss_srv_t *)userobj;
67 
68 	lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags);
69 	lwsl_hexdump_info(buf, len);
70 
71 	/*
72 	 * If we received the whole message, for our example it means
73 	 * we are done.
74 	 */
75 	if (flags & LWSSS_FLAG_EOM) {
76 		bad = 0;
77 		interrupted = 1;
78 	}
79 
80 	return 0;
81 }
82 
83 static lws_ss_state_return_t
myss_srv_tx(void * userobj,lws_ss_tx_ordinal_t ord,uint8_t * buf,size_t * len,int * flags)84 myss_srv_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
85 	int *flags)
86 {
87 	myss_srv_t *m = (myss_srv_t *)userobj;
88 	const char *send = html;
89 
90 	if (m->upgraded)
91 		return LWSSSSRET_TX_DONT_SEND;
92 
93 	if (multipart)
94 		send = multipart_html;
95 
96 	*flags = LWSSS_FLAG_SOM | LWSSS_FLAG_EOM;
97 
98 	lws_strncpy((char *)buf, send, *len);
99 	*len = strlen(send);
100 
101 	return 0;
102 }
103 
104 /*
105  * This is the Secure Streams Server RX and TX for WS(S)... when we get a
106  * state that the underlying connection upgraded protocol, we switch the stream
107  * rx and tx handlers to here.
108  */
109 
110 static lws_ss_state_return_t
myss_ws_rx(void * userobj,const uint8_t * buf,size_t len,int flags)111 myss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
112 {
113 //	myss_srv_t *m = (myss_srv_t *)userobj;
114 
115 	lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags);
116 	lwsl_hexdump_info(buf, len);
117 
118 	/*
119 	 * If we received the whole message, for our example it means
120 	 * we are done.
121 	 */
122 	if (flags & LWSSS_FLAG_EOM) {
123 		bad = 0;
124 		interrupted = 1;
125 	}
126 
127 	return 0;
128 }
129 
130 /* this is the callback that mediates sending the incrementing number */
131 
132 static void
spam_sul_cb(struct lws_sorted_usec_list * sul)133 spam_sul_cb(struct lws_sorted_usec_list *sul)
134 {
135 	myss_srv_t *m = lws_container_of(sul, myss_srv_t, sul);
136 
137 	if (!lws_ss_request_tx(m->ss))
138 		lws_sul_schedule(lws_ss_get_context(m->ss), 0, &m->sul, spam_sul_cb,
139 			 100 * LWS_US_PER_MS);
140 }
141 
142 static lws_ss_state_return_t
myss_ws_tx(void * userobj,lws_ss_tx_ordinal_t ord,uint8_t * buf,size_t * len,int * flags)143 myss_ws_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
144 	int *flags)
145 {
146 	myss_srv_t *m = (myss_srv_t *)userobj;
147 
148 	*flags = LWSSS_FLAG_SOM | LWSSS_FLAG_EOM;
149 
150 	*len = (unsigned int)lws_snprintf((char *)buf, *len, "hello from ws %d", m->count++);
151 
152 	lws_sul_schedule(lws_ss_get_context(m->ss), 0, &m->sul, spam_sul_cb,
153 			 100 * LWS_US_PER_MS);
154 
155 	return 0;
156 }
157 
158 static lws_ss_state_return_t
myss_srv_state(void * userobj,void * sh,lws_ss_constate_t state,lws_ss_tx_ordinal_t ack)159 myss_srv_state(void *userobj, void *sh, lws_ss_constate_t state,
160 	   lws_ss_tx_ordinal_t ack)
161 {
162 	myss_srv_t *m = (myss_srv_t *)userobj;
163 
164 	lwsl_user("%s: %p %s, ord 0x%x\n", __func__, m->ss,
165 		  lws_ss_state_name((int)state), (unsigned int)ack);
166 
167 	switch (state) {
168 	case LWSSSCS_DISCONNECTED:
169 		lws_sul_cancel(&m->sul);
170 		break;
171 	case LWSSSCS_CREATING:
172 		return lws_ss_request_tx(m->ss);
173 
174 	case LWSSSCS_ALL_RETRIES_FAILED:
175 		/* if we're out of retries, we want to close the app and FAIL */
176 		interrupted = 1;
177 		break;
178 
179 	case LWSSSCS_SERVER_TXN:
180 		/*
181 		 * The underlying protocol started a transaction, let's
182 		 * describe how we want to complete it.  We can defer this until
183 		 * later, eg, after we have consumed any rx that's coming with
184 		 * the client's transaction initiation phase, but in this
185 		 * example we know what we want to do already.
186 		 *
187 		 * We do want to ack the transaction...
188 		 */
189 		lws_ss_server_ack(m->ss, 0);
190 		/*
191 		 * ... it's going to be either text/html or multipart ...
192 		 */
193 		if (multipart) {
194 			if (lws_ss_set_metadata(m->ss, "mime",
195 			   "multipart/form-data; boundary=aBoundaryString", 45))
196 				return LWSSSSRET_DISCONNECT_ME;
197 		} else
198 			if (lws_ss_set_metadata(m->ss, "mime", "text/html", 9))
199 				return LWSSSSRET_DISCONNECT_ME;
200 		/*
201 		 * ...it's going to be whatever size it is (and request tx)
202 		 */
203 		return lws_ss_request_tx_len(m->ss, (unsigned long)
204 				(multipart ? strlen(multipart_html) :
205 							 strlen(html)));
206 
207 	case LWSSSCS_SERVER_UPGRADE:
208 
209 		/*
210 		 * This is sent when the underlying protocol has experienced
211 		 * an upgrade, eg, http->ws... it's a one-way upgrade on this
212 		 * stream, change the handlers to deal with the kind of
213 		 * messages we send on ws
214 		 */
215 
216 		m->upgraded = 1;
217 		lws_ss_change_handlers(m->ss, myss_ws_rx, myss_ws_tx, NULL);
218 		return lws_ss_request_tx(m->ss); /* we want to start sending numbers */
219 
220 	default:
221 		break;
222 	}
223 
224 	return 0;
225 }
226 
227 const lws_ss_info_t ssi_server = {
228 	.handle_offset			= offsetof(myss_srv_t, ss),
229 	.opaque_user_data_offset	= offsetof(myss_srv_t, opaque_data),
230 	.streamtype			= "myserver",
231 	.rx				= myss_srv_rx,
232 	.tx				= myss_srv_tx,
233 	.state				= myss_srv_state,
234 	.user_alloc			= sizeof(myss_srv_t),
235 };
236