VSF Documented
__vsf_linux_urihandler_websocket.inc
Go to the documentation of this file.
1/*****************************************************************************
2 * Copyright(C)2009-2022 by VSF Team *
3 * *
4 * Licensed under the Apache License, Version 2.0 (the "License"); *
5 * you may not use this file except in compliance with the License. *
6 * You may obtain a copy of the License at *
7 * *
8 * http://www.apache.org/licenses/LICENSE-2.0 *
9 * *
10 * Unless required by applicable law or agreed to in writing, software *
11 * distributed under the License is distributed on an "AS IS" BASIS, *
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13 * See the License for the specific language governing permissions and *
14 * limitations under the License. *
15 * *
16 ****************************************************************************/
17
18/*============================ INCLUDES ======================================*/
19
20#include <mbedtls/sha1.h>
21#include <mbedtls/base64.h>
22
23/*============================ MACROS ========================================*/
24
25#if VSF_USE_MBEDTLS != ENABLED
26# error sha1 in mbedtls is used as handshake algo, please enable VSF_USE_MBEDTLS
27#endif
28
29/*============================ MACROFIED FUNCTIONS ===========================*/
30/*============================ TYPES =========================================*/
31
32enum {
33 WEBSOCKET_STATE_CONNECTING,
34 WEBSOCKET_STATE_CONNECTTED,
35 WEBSOCKET_STATE_PARSE_HEADER = WEBSOCKET_STATE_CONNECTTED,
36 WEBSOCKET_STATE_PARSE_REALLEN,
37 WEBSOCKET_STATE_PARSE_MASKING,
38 WEBSOCKET_STATE_PARSE_DATA,
39 WEBSOCKET_STATE_CLOSING,
40 WEBSOCKET_STATE_CLOSED,
41};
42
43/*============================ PROTOTYPES ====================================*/
44
45static vsf_err_t __vsf_linux_httpd_urihandler_websocket_init(vsf_linux_httpd_request_t *req, uint8_t *data, uint_fast32_t size);
46static vsf_err_t __vsf_linux_httpd_urihandler_websocket_fini(vsf_linux_httpd_request_t *req);
47static vsf_err_t __vsf_linux_httpd_urihandler_websocket_serve(vsf_linux_httpd_request_t *req);
48static void __vsf_linux_httpd_urihandler_socket_stream_evthandler(vsf_stream_t *stream, void *param, vsf_stream_evt_t evt);
49
50/*============================ LOCAL VARIABLES ===============================*/
51
52static char __websocket_magic[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
53
54/*============================ GLOBAL VARIABLES ==============================*/
55
57 .init_fn = __vsf_linux_httpd_urihandler_websocket_init,
58 .fini_fn = __vsf_linux_httpd_urihandler_websocket_fini,
59 .serve_fn = __vsf_linux_httpd_urihandler_websocket_serve,
60 .stream_evthandler_fn = __vsf_linux_httpd_urihandler_socket_stream_evthandler,
61};
62
63/*============================ IMPLEMENTATION ================================*/
64
65static void __vsf_linux_httpd_urihandler_socket_stream_evthandler(vsf_stream_t *stream, void *param, vsf_stream_evt_t evt)
66{
67 vsf_linux_httpd_request_t *req = param;
68 const vsf_linux_httpd_urihandler_t *urihandler = req->urihandler;
69 vsf_linux_httpd_urihandler_websocket_t *urihandler_websocket = &req->urihandler_ctx.websocket;
71 uint8_t header[8];
72
73 switch (evt) {
76 switch (urihandler_websocket->state) {
77 case WEBSOCKET_STATE_PARSE_HEADER:
78 parse_header:
79 if (size >= 2) {
80 size -= vsf_stream_read(stream, header, 2);
81 urihandler_websocket->is_fin = !!(header[0] * 0x80);
82 urihandler_websocket->opcode = header[0] & 0x0F;
83 switch (urihandler_websocket->opcode) {
84 case 0:
85 urihandler_websocket->is_start = false;
86 parse_len:
87 urihandler_websocket->is_masking = !!(header[1] & 0x80);
88 header[1] &= ~0x80;
89 switch (header[1]) {
90 case 126:
91 urihandler_websocket->len_size = 2;
92 urihandler_websocket->state = WEBSOCKET_STATE_PARSE_REALLEN;
93 goto parse_reallen;
94 case 127:
95 urihandler_websocket->len_size = 8;
96 urihandler_websocket->state = WEBSOCKET_STATE_PARSE_REALLEN;
97 goto parse_reallen;
98 default:
99 urihandler_websocket->len_size = 0;
100 urihandler_websocket->payload_len = header[1];
101 goto parsed_reallen;
102 }
103 break;
104 case 1:
105 urihandler_websocket->is_string = true;
106 urihandler_websocket->is_start = true;
107 goto parse_len;
108 case 2:
109 urihandler_websocket->is_string = false;
110 urihandler_websocket->is_start = true;
111 goto parse_len;
112 case 8:
113 case 9:
114 case 10:
115 goto parse_len;
116 }
117 }
118 break;
119 case WEBSOCKET_STATE_PARSE_REALLEN:
120 parse_reallen:
121 if (size >= urihandler_websocket->len_size) {
122 size -= vsf_stream_read(stream, header, urihandler_websocket->len_size);
123 switch (urihandler_websocket->len_size) {
124 case 2: urihandler_websocket->payload_len = get_unaligned_be16(header); break;
125 case 8: urihandler_websocket->payload_len = get_unaligned_be64(header); break;
126 }
127 parsed_reallen:
128 if (urihandler_websocket->is_masking) {
129 urihandler_websocket->state = WEBSOCKET_STATE_PARSE_MASKING;
130 goto parse_masking;
131 } else if (urihandler_websocket->payload_len > 0) {
132 urihandler_websocket->state = WEBSOCKET_STATE_PARSE_DATA;
133 goto parse_data;
134 } else {
135 urihandler_websocket->state = WEBSOCKET_STATE_PARSE_HEADER;
136 goto parse_header;
137 }
138 }
139 break;
140 case WEBSOCKET_STATE_PARSE_MASKING:
141 parse_masking:
142 if (size < 4) {
143 break;
144 }
145 size -= vsf_stream_read(stream, urihandler_websocket->masking_key, 4);
146 urihandler_websocket->masking_pos = 0;
147 urihandler_websocket->state = WEBSOCKET_STATE_PARSE_DATA;
148 if (0 == urihandler_websocket->payload_len) {
149 urihandler_websocket->state = WEBSOCKET_STATE_PARSE_HEADER;
150 goto parse_header;
151 }
152 // fallthrough
153 case WEBSOCKET_STATE_PARSE_DATA:
154 parse_data:
155 while (size > 0) {
156 uint8_t *buf;
157 uint_fast32_t cur_size = vsf_stream_get_rbuf(stream, &buf);
158 cur_size = vsf_min(cur_size, size);
159
160 uint_fast32_t realsize = vsf_min(cur_size, urihandler_websocket->payload_len);
161 urihandler_websocket->payload_len -= realsize;
162 size -= realsize;
163
164 if (urihandler_websocket->is_masking) {
165 uint8_t masking_pos = urihandler_websocket->masking_pos;
166 for (uint_fast32_t i = 0; i < realsize; i++) {
167 buf[i] ^= urihandler_websocket->masking_key[masking_pos];
168 masking_pos++;
169 masking_pos &= 3;
170 }
171 urihandler_websocket->masking_pos = masking_pos;
172 }
173
174 switch (urihandler_websocket->opcode) {
175 case 0:
176 case 1:
177 case 2:
178 if (urihandler->websocket.on_message != NULL) {
179 urihandler->websocket.on_message(req,
180 (const vsf_linux_httpd_urihandler_websocket_t *)urihandler_websocket,
181 buf, realsize);
182 }
183 break;
184 case 8:
185 header[0] = 0x88;
186 header[1] = 0x02;
187 vsf_stream_write(req->stream_out, header, 2);
188 vsf_stream_write(req->stream_out, buf, realsize);
189 urihandler_websocket->state = WEBSOCKET_STATE_CLOSING;
190 break;
191 }
192 vsf_stream_read(stream, NULL, realsize);
193
194 if (0 == urihandler_websocket->payload_len) {
195 urihandler_websocket->state = WEBSOCKET_STATE_PARSE_HEADER;
196 if (size > 0) {
197 goto parse_header;
198 }
199 }
200 }
201 break;
202 }
203 break;
205 switch (urihandler_websocket->state) {
206 case WEBSOCKET_STATE_CONNECTING:
207 if (!vsf_stream_get_data_size(stream)) {
208 urihandler_websocket->state = WEBSOCKET_STATE_CONNECTTED;
209 if (urihandler->websocket.on_open != NULL) {
210 urihandler->websocket.on_open(req);
211 }
212 }
213 break;
214 case WEBSOCKET_STATE_CLOSING:
215 if (!vsf_stream_get_data_size(stream)) {
216 vsf_stream_disconnect_rx(req->stream_in);
218 urihandler_websocket->state = WEBSOCKET_STATE_CLOSED;
219 if (urihandler->websocket.on_close != NULL) {
220 urihandler->websocket.on_close(req);
221 }
222 }
223 break;
224 }
225 break;
226 }
227}
228
229static vsf_err_t __vsf_linux_httpd_urihandler_websocket_init(vsf_linux_httpd_request_t *req, uint8_t *data, uint_fast32_t size)
230{
231 VSF_LINUX_ASSERT((req != NULL) && (req->uri != NULL));
232 if (!req->websocket || (NULL == req->websocket_key)) {
233 req->response = VSF_LINUX_HTTPD_BAD_REQUEST;
234 return VSF_ERR_FAIL;
235 }
236
237 vsf_linux_httpd_urihandler_websocket_t *urihandler_websocket = &req->urihandler_ctx.websocket;
238 vsf_fifo_stream_t *stream;
239 int bufsize = sizeof(req->buffer) / 2;
240
241 urihandler_websocket->state = WEBSOCKET_STATE_CONNECTING;
242
243 stream = &urihandler_websocket->stream_out;
244 memset(stream, 0, sizeof(*stream));
245 stream->op = &vsf_fifo_stream_op;
246 stream->buffer = req->buffer;
247 stream->size = bufsize;
248 VSF_STREAM_INIT(stream);
249 stream->tx.param = req;
250 VSF_STREAM_CONNECT_TX(stream);
251 req->is_stream_out_started = true;
252 req->stream_out = &stream->use_as__vsf_stream_t;
253
254 stream = &urihandler_websocket->stream_in;
255 memset(stream, 0, sizeof(*stream));
256 stream->op = &vsf_fifo_stream_op;
257 stream->buffer = req->buffer + bufsize;
258 stream->size = bufsize;
259 VSF_STREAM_INIT(stream);
260 stream->rx.param = req;
261 VSF_STREAM_CONNECT_RX(stream);
262 req->stream_in = &stream->use_as__vsf_stream_t;
263
264 vsf_stream_write_str(req->stream_out, "HTTP/1.1 101 Switching Protocols\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Accept: ");
265
266 char secbuf[32 + sizeof(__websocket_magic)];
267 strcpy(secbuf, req->websocket_key);
268 strcat(secbuf, __websocket_magic);
269 free(req->websocket_key);
270 req->websocket_key = NULL;
271
272 mbedtls_sha1_context ctx;
273 uint8_t sha1_output[20];
274 mbedtls_sha1_init(&ctx);
275 mbedtls_sha1_starts(&ctx);
276 mbedtls_sha1_update(&ctx, (const unsigned char *)secbuf, strlen(secbuf));
277 mbedtls_sha1_finish(&ctx, sha1_output);
278 mbedtls_sha1_free(&ctx);
279
280 size_t olen;
281 mbedtls_base64_encode((unsigned char *)secbuf, sizeof(secbuf), &olen,
282 (const unsigned char *)sha1_output, sizeof(sha1_output));
283 vsf_stream_write_str(req->stream_out, secbuf);
284 vsf_stream_write_str(req->stream_out, "\r\n\r\n");
285
286 req->response = VSF_LINUX_HTTPD_OK;
287 return VSF_ERR_NONE;
288}
289
290static vsf_err_t __vsf_linux_httpd_urihandler_websocket_fini(vsf_linux_httpd_request_t *req)
291{
292 return VSF_ERR_NONE;
293}
294
295static vsf_err_t __vsf_linux_httpd_urihandler_websocket_serve(vsf_linux_httpd_request_t *req)
296{
297 return VSF_ERR_NONE;
298}
299
300int vsf_linux_httpd_websocket_write(vsf_linux_httpd_request_t *req, uint8_t *buf, int len, bool is_string)
301{
302 vsf_stream_t *stream = req->stream_out;
303 if (NULL == stream) {
304 return -1;
305 }
306
307 uint8_t len_size = len < 126 ? 1 : len < 65535 ? 2 : 8;
308 int size_dst = vsf_stream_get_free_size(stream);
309 if (size_dst < 2) {
310 return 0;
311 }
312
313 uint8_t header[8];
314 header[0] = is_string ? 0x81 : 0x82;
315__again:
316 switch (len_size) {
317 case 1:
318 len = vsf_min(len, size_dst - 2);
319 header[1] = len;
320 break;
321 case 2:
322 if (size_dst < 4) {
323 len = 125;
324 goto __again;
325 }
326 len = vsf_min(len, size_dst - 4);
327 header[1] = 126;
328 put_unaligned_be16(len, &header[2]);
329 len_size++;
330 break;
331 case 8:
332 if (size_dst < 10) {
333 len = 65535;
334 goto __again;
335 }
336 len = vsf_min(len, size_dst - 10);
337 header[1] = 127;
338 put_unaligned_be64(len, &header[2]);
339 len_size++;
340 break;
341 }
342 vsf_stream_write(stream, header, 1 + len_size);
343 vsf_stream_write(stream, buf, len);
344 return len;
345}
#define vsf_min(__a, __b)
Definition __type.h:152
vsf_err_t
Definition __type.h:42
@ VSF_ERR_NONE
none error
Definition __type.h:44
@ VSF_ERR_FAIL
failed
Definition __type.h:51
const vsf_linux_httpd_urihandler_op_t vsf_linux_httpd_urihandler_websocket_op
int vsf_linux_httpd_websocket_write(vsf_linux_httpd_request_t *req, uint8_t *buf, int len, bool is_string)
Definition vsf_fifo_stream.h:99
Definition vsf_linux_httpd.h:251
bool is_stream_out_started
Definition vsf_linux_httpd.h:291
char * uri
Definition vsf_linux_httpd.h:291
Definition vsf_simple_stream.h:254
uint_fast32_t vsf_stream_get_free_size(vsf_stream_t *stream)
Definition vsf_simple_stream.c:120
#define VSF_STREAM_CONNECT_TX(__stream)
Definition vsf_simple_stream.h:136
uint_fast32_t vsf_stream_get_rbuf(vsf_stream_t *stream, uint8_t **ptr)
Definition vsf_simple_stream.c:139
uint_fast32_t vsf_stream_read(vsf_stream_t *stream, uint8_t *buf, uint_fast32_t size)
Definition vsf_simple_stream.c:76
uint_fast32_t vsf_stream_write(vsf_stream_t *stream, uint8_t *buf, uint_fast32_t size)
Definition vsf_simple_stream.c:84
#define VSF_STREAM_INIT(__stream)
Definition vsf_simple_stream.h:126
uint_fast32_t vsf_stream_get_data_size(vsf_stream_t *stream)
Definition vsf_simple_stream.c:114
vsf_stream_evt_t
Definition vsf_simple_stream.h:160
void vsf_stream_disconnect_tx(vsf_stream_t *stream)
Definition vsf_simple_stream.c:211
#define VSF_STREAM_CONNECT_RX(__stream)
Definition vsf_simple_stream.h:135
void vsf_stream_disconnect_rx(vsf_stream_t *stream)
Definition vsf_simple_stream.c:205
@ VSF_STREAM_ON_OUT
Definition vsf_simple_stream.h:165
@ VSF_STREAM_ON_IN
Definition vsf_simple_stream.h:163
struct ieee80211_ext_chansw_ie data
Definition ieee80211.h:80
#define NULL
Definition stddef.h:52
unsigned int uint_fast32_t
Definition stdint.h:27
unsigned char uint8_t
Definition stdint.h:5
#define free
Definition stdlib.h:30
size_t strlen(const char *str)
char * strcat(char *dest, const char *src)
void * memset(void *s, int ch, size_t n)
char * strcpy(char *dest, const char *src)
Definition vsf_linux_httpd.h:170
vsf_err_t(* init_fn)(vsf_linux_httpd_request_t *req, uint8_t *data, uint_fast32_t size)
Definition vsf_linux_httpd.h:171
Definition vsf_linux_httpd.h:208
vsf_linux_httpd_websocket_onmessage_t on_message
Definition vsf_linux_httpd.h:237
vsf_linux_httpd_websocket_onclose_t on_close
Definition vsf_linux_httpd.h:235
vsf_linux_httpd_websocket_onopen_t on_open
Definition vsf_linux_httpd.h:234
struct vsf_linux_httpd_urihandler_t::@804::@807 websocket
Definition __vsf_linux_urihandler_websocket.h:33
uint8_t opcode
Definition __vsf_linux_urihandler_websocket.h:40
vsf_fifo_stream_t stream_in
Definition __vsf_linux_urihandler_websocket.h:34
uint8_t is_start
Definition __vsf_linux_urihandler_websocket.h:41
uint8_t masking_key[4]
Definition __vsf_linux_urihandler_websocket.h:37
uint8_t is_string
Definition __vsf_linux_urihandler_websocket.h:43
uint8_t len_size
Definition __vsf_linux_urihandler_websocket.h:38
uint8_t is_fin
Definition __vsf_linux_urihandler_websocket.h:42
uint8_t masking_pos
Definition __vsf_linux_urihandler_websocket.h:45
uint8_t is_masking
Definition __vsf_linux_urihandler_websocket.h:44
vsf_fifo_stream_t stream_out
Definition __vsf_linux_urihandler_websocket.h:35
uint8_t state
Definition __vsf_linux_urihandler_websocket.h:39
uint64_t payload_len
Definition __vsf_linux_urihandler_websocket.h:36
const vsf_stream_op_t vsf_fifo_stream_op
Definition vsf_fifo_stream.c:45
#define VSF_LINUX_ASSERT
Definition vsf_linux_cfg.h:31
#define vsf_stream_write_str(__stream, __str)
Definition vsf_linux_httpd.c:76
@ VSF_LINUX_HTTPD_BAD_REQUEST
Definition vsf_linux_httpd.h:143
@ VSF_LINUX_HTTPD_OK
Definition vsf_linux_httpd.h:139
uint32_t size
Definition vsf_memfs.h:50