1 #include "uwsgi.h"
2
3 /*
4
5 uWSGI websockets functions
6
7 sponsored by 20Tab S.r.l. <info@20tab.com>
8
9 */
10
11 extern struct uwsgi_server uwsgi;
12
13 #define REQ_DATA wsgi_req->method_len, wsgi_req->method, wsgi_req->uri_len, wsgi_req->uri, wsgi_req->remote_addr_len, wsgi_req->remote_addr
14
uwsgi_websocket_message(struct wsgi_request * wsgi_req,char * msg,size_t len,uint8_t opcode)15 static struct uwsgi_buffer *uwsgi_websocket_message(struct wsgi_request *wsgi_req, char *msg, size_t len, uint8_t opcode) {
16 struct uwsgi_buffer *ub = wsgi_req->websocket_send_buf;
17 if (!ub) {
18 wsgi_req->websocket_send_buf = uwsgi_buffer_new(10 + len);
19 ub = wsgi_req->websocket_send_buf;
20 }
21 else {
22 // reset the buffer
23 ub->pos = 0;
24 }
25 if (uwsgi_buffer_u8(ub, opcode)) goto error;
26 if (len < 126) {
27 if (uwsgi_buffer_u8(ub, len)) goto error;
28 }
29 else if (len <= (uint16_t) 0xffff) {
30 if (uwsgi_buffer_u8(ub, 126)) goto error;
31 if (uwsgi_buffer_u16be(ub, len)) goto error;
32 }
33 else {
34 if (uwsgi_buffer_u8(ub, 127)) goto error;
35 if (uwsgi_buffer_u64be(ub, len)) goto error;
36 }
37
38 if (uwsgi_buffer_append(ub, msg, len)) goto error;
39 return ub;
40
41 error:
42 return NULL;
43 }
44
uwsgi_websockets_ping(struct wsgi_request * wsgi_req)45 static int uwsgi_websockets_ping(struct wsgi_request *wsgi_req) {
46 if (uwsgi_response_write_body_do(wsgi_req, uwsgi.websockets_ping->buf, uwsgi.websockets_ping->pos)) {
47 return -1;
48 }
49 wsgi_req->websocket_last_ping = uwsgi_now();
50 return 0;
51 }
52
uwsgi_websockets_pong(struct wsgi_request * wsgi_req)53 static int uwsgi_websockets_pong(struct wsgi_request *wsgi_req) {
54 return uwsgi_response_write_body_do(wsgi_req, uwsgi.websockets_pong->buf, uwsgi.websockets_pong->pos);
55 }
56
uwsgi_websockets_close(struct wsgi_request * wsgi_req)57 static int uwsgi_websockets_close(struct wsgi_request *wsgi_req) {
58 return uwsgi_response_write_body_do(wsgi_req, uwsgi.websockets_close->buf, uwsgi.websockets_close->pos);
59 }
60
uwsgi_websockets_check_pingpong(struct wsgi_request * wsgi_req)61 static int uwsgi_websockets_check_pingpong(struct wsgi_request *wsgi_req) {
62 time_t now = uwsgi_now();
63 // first round
64 if (wsgi_req->websocket_last_ping == 0) {
65 return uwsgi_websockets_ping(wsgi_req);
66 }
67 // pong not received ?
68 if (wsgi_req->websocket_last_pong < wsgi_req->websocket_last_ping) {
69 if (now - wsgi_req->websocket_last_ping > uwsgi.websockets_pong_tolerance) {
70 uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) no PONG received in %d seconds !!!\n", REQ_DATA, uwsgi.websockets_pong_tolerance);
71 return -1;
72 }
73 return 0;
74 }
75 // pong received, send another ping
76 if (now - wsgi_req->websocket_last_ping >= uwsgi.websockets_ping_freq) {
77 return uwsgi_websockets_ping(wsgi_req);
78 }
79 return 0;
80 }
81
uwsgi_websocket_send_do(struct wsgi_request * wsgi_req,char * msg,size_t len,uint8_t opcode)82 static int uwsgi_websocket_send_do(struct wsgi_request *wsgi_req, char *msg, size_t len, uint8_t opcode) {
83 struct uwsgi_buffer *ub = uwsgi_websocket_message(wsgi_req, msg, len, opcode);
84 if (!ub) return -1;
85
86 return uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
87 }
88
uwsgi_websocket_send_from_sharedarea_do(struct wsgi_request * wsgi_req,int id,uint64_t pos,uint64_t len,uint8_t opcode)89 static int uwsgi_websocket_send_from_sharedarea_do(struct wsgi_request *wsgi_req, int id, uint64_t pos, uint64_t len, uint8_t opcode) {
90 struct uwsgi_sharedarea *sa = uwsgi_sharedarea_get_by_id(id, pos);
91 if (!sa) return -1;
92 if (!len) {
93 len = sa->honour_used ? sa->used-pos : ((sa->max_pos+1)-pos);
94 }
95 uwsgi_rlock(sa->lock);
96 sa->hits++;
97 struct uwsgi_buffer *ub = uwsgi_websocket_message(wsgi_req, sa->area, len, opcode);
98 uwsgi_rwunlock(sa->lock);
99 if (!ub) return -1;
100
101 return uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
102 }
103
uwsgi_websocket_send(struct wsgi_request * wsgi_req,char * msg,size_t len)104 int uwsgi_websocket_send(struct wsgi_request *wsgi_req, char *msg, size_t len) {
105 if (wsgi_req->websocket_closed) {
106 return -1;
107 }
108 ssize_t ret = uwsgi_websocket_send_do(wsgi_req, msg, len, 0x81);
109 if (ret < 0) {
110 wsgi_req->websocket_closed = 1;
111 }
112 return ret;
113 }
114
uwsgi_websocket_send_from_sharedarea(struct wsgi_request * wsgi_req,int id,uint64_t pos,uint64_t len)115 int uwsgi_websocket_send_from_sharedarea(struct wsgi_request *wsgi_req, int id, uint64_t pos, uint64_t len) {
116 if (wsgi_req->websocket_closed) {
117 return -1;
118 }
119 ssize_t ret = uwsgi_websocket_send_from_sharedarea_do(wsgi_req, id, pos, len, 0x81);
120 if (ret < 0) {
121 wsgi_req->websocket_closed = 1;
122 }
123 return ret;
124 }
125
uwsgi_websocket_send_binary(struct wsgi_request * wsgi_req,char * msg,size_t len)126 int uwsgi_websocket_send_binary(struct wsgi_request *wsgi_req, char *msg, size_t len) {
127 if (wsgi_req->websocket_closed) {
128 return -1;
129 }
130 ssize_t ret = uwsgi_websocket_send_do(wsgi_req, msg, len, 0x82);
131 if (ret < 0) {
132 wsgi_req->websocket_closed = 1;
133 }
134 return ret;
135 }
136
uwsgi_websocket_send_binary_from_sharedarea(struct wsgi_request * wsgi_req,int id,uint64_t pos,uint64_t len)137 int uwsgi_websocket_send_binary_from_sharedarea(struct wsgi_request *wsgi_req, int id, uint64_t pos, uint64_t len) {
138 if (wsgi_req->websocket_closed) {
139 return -1;
140 }
141 ssize_t ret = uwsgi_websocket_send_from_sharedarea_do(wsgi_req, id, pos, len, 0x82);
142 if (ret < 0) {
143 wsgi_req->websocket_closed = 1;
144 }
145 return ret;
146 }
147
uwsgi_websocket_parse_header(struct wsgi_request * wsgi_req)148 static void uwsgi_websocket_parse_header(struct wsgi_request *wsgi_req) {
149 uint8_t byte1 = wsgi_req->websocket_buf->buf[0];
150 uint8_t byte2 = wsgi_req->websocket_buf->buf[1];
151 wsgi_req->websocket_is_fin = byte1 >> 7;
152 wsgi_req->websocket_opcode = byte1 & 0xf;
153 wsgi_req->websocket_has_mask = byte2 >> 7;
154 wsgi_req->websocket_size = byte2 & 0x7f;
155 }
156
uwsgi_websockets_parse(struct wsgi_request * wsgi_req)157 static struct uwsgi_buffer *uwsgi_websockets_parse(struct wsgi_request *wsgi_req) {
158 // de-mask buffer
159 uint8_t *ptr = (uint8_t *) (wsgi_req->websocket_buf->buf + (wsgi_req->websocket_pktsize - wsgi_req->websocket_size));
160 size_t i;
161
162 if (wsgi_req->websocket_has_mask) {
163 uint8_t *mask = ptr-4;
164 for(i=0;i<wsgi_req->websocket_size;i++) {
165 ptr[i] = ptr[i] ^ mask[i%4];
166 }
167 }
168
169 struct uwsgi_buffer *ub = NULL;
170 if (wsgi_req->websocket_opcode == 0) {
171 if (uwsgi.websockets_continuation_buffer == NULL) {
172 uwsgi_log("Error continuation with empty previous buffer");
173 goto error;
174 }
175 ub = uwsgi.websockets_continuation_buffer;
176 }
177 else {
178 ub = uwsgi_buffer_new(wsgi_req->websocket_size);
179 }
180 if (uwsgi_buffer_append(ub, (char *) ptr, wsgi_req->websocket_size)) goto error;
181 if (uwsgi_buffer_decapitate(wsgi_req->websocket_buf, wsgi_req->websocket_pktsize)) goto error;
182 wsgi_req->websocket_phase = 0;
183 wsgi_req->websocket_need = 2;
184
185 if (wsgi_req->websocket_is_fin) {
186 uwsgi.websockets_continuation_buffer = NULL;
187 /// Freeing websockets_continuation_buffer is done by the caller
188 return ub;
189 }
190 uwsgi.websockets_continuation_buffer = ub;
191 /// Message is not complete, send empty dummy buffer to signal waiting for full message
192 ub = uwsgi_buffer_new(1);
193 uwsgi_buffer_append(ub, "\0", 1);
194 return ub;
195 error:
196 uwsgi_buffer_destroy(ub);
197 if (uwsgi.websockets_continuation_buffer != NULL && ub != uwsgi.websockets_continuation_buffer) {
198 uwsgi_buffer_destroy(uwsgi.websockets_continuation_buffer);
199 }
200 uwsgi.websockets_continuation_buffer = NULL;
201 return NULL;
202 }
203
204
uwsgi_websockets_recv_pkt(struct wsgi_request * wsgi_req,int nb)205 static ssize_t uwsgi_websockets_recv_pkt(struct wsgi_request *wsgi_req, int nb) {
206
207 int ret = -1;
208
209 for(;;) {
210 ssize_t rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->websocket_buf->buf + wsgi_req->websocket_buf->pos, wsgi_req->websocket_buf->len - wsgi_req->websocket_buf->pos);
211 if (rlen > 0) return rlen;
212 if (rlen == 0) return -1;
213 if (rlen < 0) {
214 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
215 if (nb) {
216 if (uwsgi_websockets_check_pingpong(wsgi_req)) {
217 return -1;
218 }
219 return 0;
220 }
221 goto wait;
222 }
223 uwsgi_req_error("uwsgi_websockets_recv_pkt()");
224 return -1;
225 }
226
227 wait:
228 ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.websockets_ping_freq);
229 if (ret > 0) {
230 rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->websocket_buf->buf + wsgi_req->websocket_buf->pos, wsgi_req->websocket_buf->len - wsgi_req->websocket_buf->pos);
231 if (rlen > 0) return rlen;
232 if (rlen <= 0) return -1;
233 }
234 if (ret < 0) {
235 uwsgi_req_error("uwsgi_websockets_recv_pkt()");
236 return -1;
237 }
238 // send unsolicited pong
239 if (uwsgi_websockets_check_pingpong(wsgi_req)) {
240 return -1;
241 }
242 }
243
244 return -1;
245 }
246
247
uwsgi_websocket_recv_do(struct wsgi_request * wsgi_req,int nb)248 static struct uwsgi_buffer *uwsgi_websocket_recv_do(struct wsgi_request *wsgi_req, int nb) {
249 if (!wsgi_req->websocket_buf) {
250 // this buffer will be destroyed on connection close
251 wsgi_req->websocket_buf = uwsgi_buffer_new(uwsgi.page_size);
252 // need 2 byte header
253 wsgi_req->websocket_need = 2;
254 }
255
256 for(;;) {
257 size_t remains = wsgi_req->websocket_buf->pos;
258 // i have data;
259 if (remains >= wsgi_req->websocket_need) {
260 switch(wsgi_req->websocket_phase) {
261 // header
262 case 0:
263 uwsgi_websocket_parse_header(wsgi_req);
264 wsgi_req->websocket_pktsize = 2 + (wsgi_req->websocket_has_mask*4);
265 if (wsgi_req->websocket_size == 126) {
266 wsgi_req->websocket_need += 2;
267 wsgi_req->websocket_phase = 1;
268 wsgi_req->websocket_pktsize += 2;
269 }
270 else if (wsgi_req->websocket_size == 127) {
271 wsgi_req->websocket_need += 8;
272 wsgi_req->websocket_phase = 1;
273 wsgi_req->websocket_pktsize += 8;
274 }
275 else {
276 wsgi_req->websocket_phase = 2;
277 }
278 break;
279 // size
280 case 1:
281 if (wsgi_req->websocket_size == 126) {
282 wsgi_req->websocket_size = uwsgi_be16(wsgi_req->websocket_buf->buf+2);
283 }
284 else if (wsgi_req->websocket_size == 127) {
285 wsgi_req->websocket_size = uwsgi_be64(wsgi_req->websocket_buf->buf+2);
286 }
287 else {
288 uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) BUG error in websocket parser\n", REQ_DATA);
289 return NULL;
290 }
291 if (wsgi_req->websocket_size > (uwsgi.websockets_max_size*1024)) {
292 uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) invalid packet size received: %llu, max allowed: %llu\n", REQ_DATA, wsgi_req->websocket_size, uwsgi.websockets_max_size * 1024);
293 return NULL;
294 }
295 wsgi_req->websocket_phase = 2;
296 break;
297 // mask check
298 case 2:
299 if (wsgi_req->websocket_has_mask) {
300 wsgi_req->websocket_need += 4;
301 wsgi_req->websocket_phase = 3;
302 }
303 else {
304 wsgi_req->websocket_need += wsgi_req->websocket_size;
305 wsgi_req->websocket_pktsize += wsgi_req->websocket_size;
306 wsgi_req->websocket_phase = 4;
307 }
308 break;
309 // mask
310 case 3:
311 wsgi_req->websocket_pktsize += wsgi_req->websocket_size;
312 wsgi_req->websocket_need += wsgi_req->websocket_size;
313 wsgi_req->websocket_phase = 4;
314 break;
315 // message
316 case 4:
317 switch (wsgi_req->websocket_opcode) {
318 // message
319 case 0:
320 case 1:
321 case 2:
322 return uwsgi_websockets_parse(wsgi_req);
323 // close
324 case 0x8:
325 uwsgi_websockets_close(wsgi_req);
326 return NULL;
327 // ping
328 case 0x9:
329 if (uwsgi_websockets_pong(wsgi_req)) {
330 return NULL;
331 }
332 break;
333 // pong
334 case 0xA:
335 wsgi_req->websocket_last_pong = uwsgi_now();
336 break;
337 default:
338 break;
339 }
340 // reset the status
341 wsgi_req->websocket_phase = 0;
342 wsgi_req->websocket_need = 2;
343 // decapitate the buffer
344 if (uwsgi_buffer_decapitate(wsgi_req->websocket_buf, wsgi_req->websocket_pktsize)) return NULL;
345 break;
346 // oops
347 default:
348 uwsgi_log("[uwsgi-websocket] \"%.*s %.*s\" (%.*s) BUG error in websocket parser\n", REQ_DATA);
349 return NULL;
350 }
351 }
352 // need more data
353 else {
354 if (uwsgi_buffer_ensure(wsgi_req->websocket_buf, uwsgi.page_size)) return NULL;
355 ssize_t len = uwsgi_websockets_recv_pkt(wsgi_req, nb);
356 if (len <= 0) {
357 if (nb == 1 && len == 0) {
358 // return an empty buffer to signal blocking event
359 return uwsgi_buffer_new(0);
360 }
361 return NULL;
362 }
363 // update buffer size
364 wsgi_req->websocket_buf->pos+=len;
365 }
366 }
367
368 return NULL;
369 }
370
clear_continuation_buffer()371 static void clear_continuation_buffer() {
372 if (uwsgi.websockets_continuation_buffer != NULL) {
373 uwsgi_buffer_destroy(uwsgi.websockets_continuation_buffer);
374 uwsgi.websockets_continuation_buffer = NULL;
375 }
376 }
377
uwsgi_websocket_recv(struct wsgi_request * wsgi_req)378 struct uwsgi_buffer *uwsgi_websocket_recv(struct wsgi_request *wsgi_req) {
379 if (wsgi_req->websocket_closed) {
380 return NULL;
381 }
382 struct uwsgi_buffer *ub = uwsgi_websocket_recv_do(wsgi_req, 0);
383 if (!ub) {
384 clear_continuation_buffer();
385 wsgi_req->websocket_closed = 1;
386 }
387 return ub;
388 }
389
uwsgi_websocket_recv_nb(struct wsgi_request * wsgi_req)390 struct uwsgi_buffer *uwsgi_websocket_recv_nb(struct wsgi_request *wsgi_req) {
391 if (wsgi_req->websocket_closed) {
392 return NULL;
393 }
394 struct uwsgi_buffer *ub = uwsgi_websocket_recv_do(wsgi_req, 1);
395 if (!ub) {
396 clear_continuation_buffer();
397 wsgi_req->websocket_closed = 1;
398 }
399 return ub;
400 }
401
402
403
uwsgi_websockets_simple_send(struct wsgi_request * wsgi_req,struct uwsgi_buffer * ub)404 ssize_t uwsgi_websockets_simple_send(struct wsgi_request *wsgi_req, struct uwsgi_buffer *ub) {
405 ssize_t len = wsgi_req->socket->proto_write(wsgi_req, ub->buf, ub->pos);
406 if (wsgi_req->write_errors > 0) {
407 return -1;
408 }
409 return len;
410 }
411
uwsgi_websocket_handshake(struct wsgi_request * wsgi_req,char * key,uint16_t key_len,char * origin,uint16_t origin_len,char * proto,uint16_t proto_len)412 int uwsgi_websocket_handshake(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *origin, uint16_t origin_len, char *proto, uint16_t proto_len) {
413 #ifdef UWSGI_SSL
414 if (!key_len) {
415 key = wsgi_req->http_sec_websocket_key;
416 key_len = wsgi_req->http_sec_websocket_key_len;
417 }
418 if (key_len == 0) return -1;
419
420 char sha1[20];
421 if (uwsgi_response_prepare_headers(wsgi_req, "101 Web Socket Protocol Handshake", 33)) return -1;
422 if (uwsgi_response_add_header(wsgi_req, "Upgrade", 7, "WebSocket", 9)) return -1;
423 if (uwsgi_response_add_header(wsgi_req, "Connection", 10, "Upgrade", 7)) return -1;
424
425 // if origin was requested or proto_len is specified, send it back
426 if (wsgi_req->http_origin_len > 0 || origin_len > 0) {
427 if (!origin_len) {
428 origin = wsgi_req->http_origin;
429 origin_len = wsgi_req->http_origin_len;
430 }
431 if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Origin", 20, origin, origin_len)) return -1;
432 }
433 else {
434 if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Origin", 20, "*", 1)) return -1;
435 }
436
437 // if protocol was requested or proto_len is specified, send it back
438 if (wsgi_req->http_sec_websocket_protocol_len > 0 || proto_len > 0) {
439 if (!proto_len) {
440 proto = wsgi_req->http_sec_websocket_protocol;
441 proto_len = wsgi_req->http_sec_websocket_protocol_len;
442 }
443 if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Protocol", 22, proto, proto_len)) return -1;
444 }
445 // generate websockets sha1 and encode it to base64
446 if (!uwsgi_sha1_2n(key, key_len, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", 36, sha1)) return -1;
447 size_t b64_len = 0;
448 char *b64 = uwsgi_base64_encode(sha1, 20, &b64_len);
449 if (!b64) return -1;
450
451 if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Accept", 20, b64, b64_len)) {
452 free(b64);
453 return -1;
454 }
455 free(b64);
456
457 wsgi_req->websocket_last_pong = uwsgi_now();
458
459 return uwsgi_response_write_headers_do(wsgi_req);
460 #else
461 uwsgi_log("you need to build uWSGI with SSL support to use the websocket handshake api function !!!\n");
462 return -1;
463 #endif
464 }
465
uwsgi_websockets_init()466 void uwsgi_websockets_init() {
467 uwsgi.websockets_pong = uwsgi_buffer_new(2);
468 uwsgi_buffer_append(uwsgi.websockets_pong, "\x8A\0", 2);
469 uwsgi.websockets_ping = uwsgi_buffer_new(2);
470 uwsgi_buffer_append(uwsgi.websockets_ping, "\x89\0", 2);
471 uwsgi.websockets_close = uwsgi_buffer_new(2);
472 uwsgi_buffer_append(uwsgi.websockets_close, "\x88\0", 2);
473 uwsgi.websockets_ping_freq = 30;
474 uwsgi.websockets_pong_tolerance = 3;
475 uwsgi.websockets_max_size = 1024;
476 uwsgi.websockets_continuation_buffer = NULL;
477 }
478