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