1 #include <switch.h>
2 #include "ws.h"
3 #include <pthread.h>
4 
5 #ifndef _MSC_VER
6 #include <fcntl.h>
7 #endif
8 
9 #if defined(__linux__) || defined(__GLIBC__)
10 #include <byteswap.h>
11 #endif
12 
13 #ifndef _MSC_VER
14 #define ms_sleep(x)	usleep( x * 1000);
15 #else
16 #define ms_sleep(x) Sleep( x );
17 #endif
18 
19 #ifdef _MSC_VER
20 /* warning C4706: assignment within conditional expression*/
21 #pragma warning(disable: 4706)
22 #endif
23 
24 #define WS_BLOCK 1
25 #define WS_NOBLOCK 0
26 
27 #define WS_INIT_SANITY 5000
28 #define WS_WRITE_SANITY 200
29 
30 #define SHA1_HASH_SIZE 20
31 static struct ws_globals_s ws_globals;
32 
33 #ifndef WSS_STANDALONE
34 
init_ssl(void)35 void init_ssl(void)
36 {
37 	//	SSL_library_init();
38 }
deinit_ssl(void)39 void deinit_ssl(void)
40 {
41 	return;
42 }
43 
44 #else
45 static void pthreads_thread_id(CRYPTO_THREADID *id);
46 static void pthreads_locking_callback(int mode, int type, const char *file, int line);
47 
48 static pthread_mutex_t *lock_cs;
49 static long *lock_count;
50 
51 
52 
thread_setup(void)53 static void thread_setup(void)
54 {
55 	int i;
56 
57 	lock_cs = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
58 	lock_count = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));
59 
60 	for (i = 0; i < CRYPTO_num_locks(); i++) {
61 		lock_count[i] = 0;
62 		pthread_mutex_init(&(lock_cs[i]), NULL);
63 	}
64 
65 	CRYPTO_THREADID_set_callback(pthreads_thread_id);
66 	CRYPTO_set_locking_callback(pthreads_locking_callback);
67 }
68 
thread_cleanup(void)69 static void thread_cleanup(void)
70 {
71 	int i;
72 
73 	CRYPTO_set_locking_callback(NULL);
74 
75 	for (i=0; i<CRYPTO_num_locks(); i++) {
76 		pthread_mutex_destroy(&(lock_cs[i]));
77 	}
78 	OPENSSL_free(lock_cs);
79 	OPENSSL_free(lock_count);
80 
81 }
82 
pthreads_locking_callback(int mode,int type,const char * file,int line)83 static void pthreads_locking_callback(int mode, int type, const char *file, int line)
84 {
85 
86 	if (mode & CRYPTO_LOCK) {
87 		pthread_mutex_lock(&(lock_cs[type]));
88 		lock_count[type]++;
89 	} else {
90 		pthread_mutex_unlock(&(lock_cs[type]));
91 	}
92 }
93 
94 
95 
pthreads_thread_id(CRYPTO_THREADID * id)96 static void pthreads_thread_id(CRYPTO_THREADID *id)
97 {
98 	CRYPTO_THREADID_set_numeric(id, (unsigned long)pthread_self());
99 }
100 
101 
init_ssl(void)102 void init_ssl(void) {
103 	SSL_library_init();
104 
105 
106 	OpenSSL_add_all_algorithms();   /* load & register cryptos */
107 	SSL_load_error_strings();     /* load all error messages */
108 	ws_globals.ssl_method = SSLv23_server_method();   /* create server instance */
109 	ws_globals.ssl_ctx = SSL_CTX_new(ws_globals.ssl_method);         /* create context */
110 	assert(ws_globals.ssl_ctx);
111 
112 	/* Disable SSLv2 */
113 	SSL_CTX_set_options(ws_globals.ssl_ctx, SSL_OP_NO_SSLv2);
114 	/* Disable SSLv3 */
115 	SSL_CTX_set_options(ws_globals.ssl_ctx, SSL_OP_NO_SSLv3);
116 	/* Disable TLSv1 */
117 	SSL_CTX_set_options(ws_globals.ssl_ctx, SSL_OP_NO_TLSv1);
118 	/* Disable Compression CRIME (Compression Ratio Info-leak Made Easy) */
119 	SSL_CTX_set_options(ws_globals.ssl_ctx, SSL_OP_NO_COMPRESSION);
120 	/* set the local certificate from CertFile */
121 	SSL_CTX_use_certificate_file(ws_globals.ssl_ctx, ws_globals.cert, SSL_FILETYPE_PEM);
122 	/* set the private key from KeyFile */
123 	SSL_CTX_use_PrivateKey_file(ws_globals.ssl_ctx, ws_globals.key, SSL_FILETYPE_PEM);
124 	/* verify private key */
125 	if ( !SSL_CTX_check_private_key(ws_globals.ssl_ctx) ) {
126 		abort();
127     }
128 
129 	SSL_CTX_set_cipher_list(ws_globals.ssl_ctx, "HIGH:!DSS:!aNULL@STRENGTH");
130 
131 	thread_setup();
132 }
133 
134 
deinit_ssl(void)135 void deinit_ssl(void) {
136 	thread_cleanup();
137 }
138 
139 #endif
140 
141 static const char c64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
142 
143 
cheezy_get_var(char * data,char * name,char * buf,size_t buflen)144 static int cheezy_get_var(char *data, char *name, char *buf, size_t buflen)
145 {
146   char *p=data;
147 
148   /* the old way didnt make sure that variable values were used for the name hunt
149    * and didnt ensure that only a full match of the variable name was used
150    */
151 
152   do {
153     if(!strncasecmp(p,name,strlen(name)) && *(p+strlen(name))==':') break;
154   } while((p = (strstr(p,"\n")+1))!=(char *)1);
155 
156 
157   if (p && p != (char *)1 && *p!='\0') {
158     char *v, *e = 0;
159 
160     v = strchr(p, ':');
161     if (v) {
162       v++;
163       while(v && *v == ' ') {
164 	v++;
165       }
166       if (v)  {
167 	e = strchr(v, '\r');
168 	if (!e) {
169 	  e = strchr(v, '\n');
170 	}
171       }
172 
173       if (v && e) {
174 	int cplen;
175 	size_t len = e - v;
176 
177 	if (len > buflen - 1) {
178 	  cplen = buflen -1;
179 	} else {
180 	  cplen = len;
181 	}
182 
183 	strncpy(buf, v, cplen);
184 	*(buf+cplen) = '\0';
185 	return 1;
186       }
187 
188     }
189   }
190   return 0;
191 }
192 
b64encode(unsigned char * in,size_t ilen,unsigned char * out,size_t olen)193 static int b64encode(unsigned char *in, size_t ilen, unsigned char *out, size_t olen)
194 {
195 	int y=0,bytes=0;
196 	size_t x=0;
197 	unsigned int b=0,l=0;
198 
199 	if(olen) {
200 	}
201 
202 	for(x=0;x<ilen;x++) {
203 		b = (b<<8) + in[x];
204 		l += 8;
205 		while (l >= 6) {
206 			out[bytes++] = c64[(b>>(l-=6))%64];
207 			if(++y!=72) {
208 				continue;
209 			}
210 			//out[bytes++] = '\n';
211 			y=0;
212 		}
213 	}
214 
215 	if (l > 0) {
216 		out[bytes++] = c64[((b%16)<<(6-l))%64];
217 	}
218 	if (l != 0) while (l < 6) {
219 		out[bytes++] = '=', l += 2;
220 	}
221 
222 	return 0;
223 }
224 
225 #ifdef NO_OPENSSL
sha1_digest(char * digest,unsigned char * in)226 static void sha1_digest(char *digest, unsigned char *in)
227 {
228 	SHA1Context sha;
229 	char *p;
230 	int x;
231 
232 
233 	SHA1Init(&sha);
234 	SHA1Update(&sha, in, strlen(in));
235 	SHA1Final(&sha, digest);
236 }
237 #else
238 
sha1_digest(unsigned char * digest,char * in)239 static void sha1_digest(unsigned char *digest, char *in)
240 {
241 	SHA_CTX sha;
242 
243 	SHA1_Init(&sha);
244 	SHA1_Update(&sha, in, strlen(in));
245 	SHA1_Final(digest, &sha);
246 
247 }
248 
249 #endif
250 
ws_handshake(wsh_t * wsh)251 int ws_handshake(wsh_t *wsh)
252 {
253 	char key[256] = "";
254 	char version[5] = "";
255 	char proto[256] = "";
256 	char proto_buf[384] = "";
257 	char input[512] = "";
258 	unsigned char output[SHA1_HASH_SIZE] = "";
259 	char b64[256] = "";
260 	char respond[1024] = "";
261 	ssize_t bytes;
262 	char *p, *e = 0;
263 
264 	if (wsh->sock == ws_sock_invalid) {
265 		return -3;
266 	}
267 
268 	while((bytes = ws_raw_read(wsh, wsh->buffer + wsh->datalen, wsh->buflen - wsh->datalen, WS_BLOCK)) > 0) {
269 		wsh->datalen += bytes;
270 		if (strstr(wsh->buffer, "\r\n\r\n") || strstr(wsh->buffer, "\n\n")) {
271 			break;
272 		}
273 	}
274 
275 	if (bytes < 0 || bytes > wsh->buflen -1) {
276 		goto err;
277 	}
278 
279 	*(wsh->buffer + wsh->datalen) = '\0';
280 
281 	if (strncasecmp(wsh->buffer, "GET ", 4)) {
282 		goto err;
283 	}
284 
285 	p = wsh->buffer + 4;
286 
287 	e = strchr(p, ' ');
288 	if (!e) {
289 		goto err;
290 	}
291 
292 	wsh->uri = malloc((e-p) + 1);
293 
294 	if (!wsh->uri) goto err;
295 
296 	strncpy(wsh->uri, p, e-p);
297 	*(wsh->uri + (e-p)) = '\0';
298 
299 	cheezy_get_var(wsh->buffer, "Sec-WebSocket-Key", key, sizeof(key));
300 	cheezy_get_var(wsh->buffer, "Sec-WebSocket-Version", version, sizeof(version));
301 	cheezy_get_var(wsh->buffer, "Sec-WebSocket-Protocol", proto, sizeof(proto));
302 
303 	if (!*key) {
304 		goto err;
305 	}
306 
307 	snprintf(input, sizeof(input), "%s%s", key, WEBSOCKET_GUID);
308 	sha1_digest(output, input);
309 	b64encode((unsigned char *)output, SHA1_HASH_SIZE, (unsigned char *)b64, sizeof(b64));
310 
311 	if (*proto) {
312 		snprintf(proto_buf, sizeof(proto_buf), "Sec-WebSocket-Protocol: %s\r\n", proto);
313 	}
314 
315 	snprintf(respond, sizeof(respond),
316 			 "HTTP/1.1 101 Switching Protocols\r\n"
317 			 "Upgrade: websocket\r\n"
318 			 "Connection: Upgrade\r\n"
319 			 "Sec-WebSocket-Accept: %s\r\n"
320 			 "%s\r\n",
321 			 b64,
322 			 proto_buf);
323 	respond[511] = 0;
324 
325 	if (ws_raw_write(wsh, respond, strlen(respond)) != (ssize_t)strlen(respond)) {
326 		goto err;
327 	}
328 
329 	wsh->handshake = 1;
330 
331 	return 0;
332 
333  err:
334 
335 	if (!wsh->stay_open) {
336 
337 		if (bytes > 0) {
338 			snprintf(respond, sizeof(respond), "HTTP/1.1 400 Bad Request\r\n"
339 					 "Sec-WebSocket-Version: 13\r\n\r\n");
340 			respond[511] = 0;
341 
342 			ws_raw_write(wsh, respond, strlen(respond));
343 		}
344 
345 		ws_close(wsh, WS_NONE);
346 	}
347 
348 	return -1;
349 
350 }
351 
352 #define SSL_WANT_READ_WRITE(err) (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
353 
ws_raw_read(wsh_t * wsh,void * data,size_t bytes,int block)354 ssize_t ws_raw_read(wsh_t *wsh, void *data, size_t bytes, int block)
355 {
356 	ssize_t r;
357 	int ssl_err = 0;
358 
359 	wsh->x++;
360 	if (wsh->x > 250) ms_sleep(1);
361 
362 	if (wsh->ssl) {
363 		do {
364 			r = SSL_read(wsh->ssl, data, bytes);
365 
366 			if (r < 0) {
367 				ssl_err = SSL_get_error(wsh->ssl, r);
368 
369 				if (SSL_WANT_READ_WRITE(ssl_err)) {
370 					if (!block) {
371 						r = -2;
372 						goto end;
373 					}
374 					wsh->x++;
375 					ms_sleep(10);
376 				} else {
377 					r = -1;
378 					goto end;
379 				}
380 			}
381 
382 		} while (r < 0 && SSL_WANT_READ_WRITE(ssl_err) && wsh->x < 1000);
383 
384 		goto end;
385 	}
386 
387 	do {
388 
389 		r = recv(wsh->sock, data, bytes, 0);
390 
391 		if (r == -1) {
392 			if (!block && xp_is_blocking(xp_errno())) {
393 				r = -2;
394 				goto end;
395 			}
396 
397 			if (block) {
398 				wsh->x++;
399 				ms_sleep(10);
400 			}
401 		}
402 	} while (r == -1 && xp_is_blocking(xp_errno()) && wsh->x < 1000);
403 
404  end:
405 
406 	if (wsh->x >= 10000 || (block && wsh->x >= 1000)) {
407 		r = -1;
408 	}
409 
410 	if (r > 0) {
411 		*((char *)data + r) = '\0';
412 	}
413 
414 	if (r >= 0) {
415 		wsh->x = 0;
416 	}
417 
418 	return r;
419 }
420 
ws_raw_write(wsh_t * wsh,void * data,size_t bytes)421 ssize_t ws_raw_write(wsh_t *wsh, void *data, size_t bytes)
422 {
423 	ssize_t r;
424 	int sanity = WS_WRITE_SANITY;
425 	int ssl_err = 0;
426 	size_t wrote = 0;
427 
428 	if (wsh->ssl) {
429 		do {
430 			r = SSL_write(wsh->ssl, (void *)((unsigned char *)data + wrote), bytes - wrote);
431 
432 			if (r == 0) {
433 				ssl_err = 42;
434 				break;
435 			}
436 
437 			if (r > 0) {
438 				wrote += r;
439 			}
440 
441 			if (sanity < WS_WRITE_SANITY) {
442 				int ms = 1;
443 
444 				if (wsh->block) {
445 					if (sanity < WS_WRITE_SANITY / 2) {
446 						ms = 25;
447 					} else if (sanity < WS_WRITE_SANITY * 3 / 4) {
448 						ms = 50;
449 					}
450 				}
451 				ms_sleep(ms);
452 			}
453 
454 			if (r < 0) {
455 				ssl_err = SSL_get_error(wsh->ssl, r);
456 
457 				if (!SSL_WANT_READ_WRITE(ssl_err)) {
458 					break;
459 				}
460 				ssl_err = 0;
461 			}
462 
463 		} while (--sanity > 0 && wrote < bytes);
464 
465 		if (!sanity) ssl_err = 56;
466 
467 		if (ssl_err) {
468 			r = ssl_err * -1;
469 		}
470 
471 		return r;
472 	}
473 
474 	do {
475 		r = send(wsh->sock, (void *)((unsigned char *)data + wrote), bytes - wrote, 0);
476 
477 		if (r > 0) {
478 			wrote += r;
479 		}
480 
481 		if (sanity < WS_WRITE_SANITY) {
482 			int ms = 1;
483 
484 			if (wsh->block) {
485 				if (sanity < WS_WRITE_SANITY / 2) {
486 					ms = 25;
487 				} else if (sanity < WS_WRITE_SANITY * 3 / 4) {
488 					ms = 50;
489 				}
490 			}
491 			ms_sleep(ms);
492 		}
493 
494 		if (r == -1) {
495 			if (!xp_is_blocking(xp_errno())) {
496 				break;
497 			}
498 		}
499 
500 	} while (--sanity > 0 && wrote < bytes);
501 
502 	//if (r<0) {
503 		//printf("wRITE FAIL: %s\n", strerror(errno));
504 	//}
505 
506 	return r < 0 ? r : wrote;
507 }
508 
509 #ifdef _MSC_VER
setup_socket(ws_socket_t sock)510 static int setup_socket(ws_socket_t sock)
511 {
512 	unsigned long v = 1;
513 
514 	if (ioctlsocket(sock, FIONBIO, &v) == SOCKET_ERROR) {
515 		return -1;
516 	}
517 
518 	return 0;
519 
520 }
521 
restore_socket(ws_socket_t sock)522 static int restore_socket(ws_socket_t sock)
523 {
524 	unsigned long v = 0;
525 
526 	if (ioctlsocket(sock, FIONBIO, &v) == SOCKET_ERROR) {
527 		return -1;
528 	}
529 
530 	return 0;
531 
532 }
533 
534 #else
535 
setup_socket(ws_socket_t sock)536 static int setup_socket(ws_socket_t sock)
537 {
538 	int flags = fcntl(sock, F_GETFL, 0);
539 	return fcntl(sock, F_SETFL, flags | O_NONBLOCK);
540 }
541 
restore_socket(ws_socket_t sock)542 static int restore_socket(ws_socket_t sock)
543 {
544 	int flags = fcntl(sock, F_GETFL, 0);
545 
546 	flags &= ~O_NONBLOCK;
547 
548 	return fcntl(sock, F_SETFL, flags);
549 
550 }
551 
552 #endif
553 
554 
establish_logical_layer(wsh_t * wsh)555 int establish_logical_layer(wsh_t *wsh)
556 {
557 
558 	if (!wsh->sanity) {
559 		return -1;
560 	}
561 
562 	if (wsh->logical_established) {
563 		return 0;
564 	}
565 
566 	if (wsh->secure && !wsh->secure_established) {
567 		int code;
568 
569 		if (!wsh->ssl) {
570 			wsh->ssl = SSL_new(wsh->ssl_ctx);
571 			assert(wsh->ssl);
572 
573 			SSL_set_fd(wsh->ssl, wsh->sock);
574 		}
575 
576 		do {
577 			code = SSL_accept(wsh->ssl);
578 
579 			if (code == 1) {
580 				wsh->secure_established = 1;
581 				break;
582 			}
583 
584 			if (code == 0) {
585 				return -1;
586 			}
587 
588 			if (code < 0) {
589 				int ssl_err = SSL_get_error(wsh->ssl, code);
590 				if (!SSL_WANT_READ_WRITE(ssl_err)) {
591 					return -1;
592 				}
593 			}
594 
595 			if (wsh->block) {
596 				ms_sleep(10);
597 			} else {
598 				ms_sleep(1);
599 			}
600 
601 			wsh->sanity--;
602 
603 			if (!wsh->block) {
604 				return -2;
605 			}
606 
607 		} while (wsh->sanity > 0);
608 
609 		if (!wsh->sanity) {
610 			return -1;
611 		}
612 
613 	}
614 
615 	while (!wsh->down && !wsh->handshake) {
616 		int r = ws_handshake(wsh);
617 
618 		if (r < 0) {
619 			wsh->down = 1;
620 			return -1;
621 		}
622 
623 		if (!wsh->handshake && !wsh->block) {
624 			return -2;
625 		}
626 
627 	}
628 
629 	wsh->logical_established = 1;
630 
631 	return 0;
632 }
633 
634 
ws_init(wsh_t * wsh,ws_socket_t sock,SSL_CTX * ssl_ctx,int close_sock,int block,int stay_open)635 int ws_init(wsh_t *wsh, ws_socket_t sock, SSL_CTX *ssl_ctx, int close_sock, int block, int stay_open)
636 {
637 	memset(wsh, 0, sizeof(*wsh));
638 
639 	wsh->sock = sock;
640 	wsh->block = block;
641 	wsh->sanity = WS_INIT_SANITY;
642 	wsh->ssl_ctx = ssl_ctx;
643 	wsh->stay_open = stay_open;
644 
645 	if (!ssl_ctx) {
646 		ssl_ctx = ws_globals.ssl_ctx;
647 	}
648 
649 	if (close_sock) {
650 		wsh->close_sock = 1;
651 	}
652 
653 	wsh->buflen = 1024 * 64;
654 	wsh->bbuflen = wsh->buflen;
655 
656 	wsh->buffer = malloc(wsh->buflen);
657 	wsh->bbuffer = malloc(wsh->bbuflen);
658 	//printf("init %p %ld\n", (void *) wsh->bbuffer, wsh->bbuflen);
659 	//memset(wsh->buffer, 0, wsh->buflen);
660 	//memset(wsh->bbuffer, 0, wsh->bbuflen);
661 
662 	wsh->secure = ssl_ctx ? 1 : 0;
663 
664 	setup_socket(sock);
665 
666 	if (establish_logical_layer(wsh) == -1) {
667 		return -1;
668 	}
669 
670 	if (wsh->down) {
671 		return -1;
672 	}
673 
674 	return 0;
675 }
676 
ws_destroy(wsh_t * wsh)677 void ws_destroy(wsh_t *wsh)
678 {
679 
680 	if (!wsh) {
681 		return;
682 	}
683 
684 	if (!wsh->down) {
685 		ws_close(wsh, WS_NONE);
686 	}
687 
688 	if (wsh->down > 1) {
689 		return;
690 	}
691 
692 	wsh->down = 2;
693 
694 	if (wsh->write_buffer) {
695 		free(wsh->write_buffer);
696 		wsh->write_buffer = NULL;
697 		wsh->write_buffer_len = 0;
698 	}
699 
700 	if (wsh->ssl) {
701 		SSL_free(wsh->ssl);
702 		wsh->ssl = NULL;
703 	}
704 
705 	if (wsh->buffer) free(wsh->buffer);
706 	if (wsh->bbuffer) free(wsh->bbuffer);
707 
708 	wsh->buffer = wsh->bbuffer = NULL;
709 
710 }
711 
ws_close(wsh_t * wsh,int16_t reason)712 ssize_t ws_close(wsh_t *wsh, int16_t reason)
713 {
714 
715 	if (wsh->down) {
716 		return -1;
717 	}
718 
719 	wsh->down = 1;
720 
721 	if (wsh->uri) {
722 		free(wsh->uri);
723 		wsh->uri = NULL;
724 	}
725 
726 	if (reason && wsh->sock != ws_sock_invalid) {
727 		uint16_t *u16;
728 		uint8_t fr[4] = {WSOC_CLOSE | 0x80, 2, 0};
729 
730 		u16 = (uint16_t *) &fr[2];
731 		*u16 = htons((int16_t)reason);
732 		ws_raw_write(wsh, fr, 4);
733 	}
734 
735 	if (wsh->ssl && wsh->sock != ws_sock_invalid) {
736 		/* first invocation of SSL_shutdown() would normally return 0 and just try to send SSL protocol close request.
737 		   we just slightly polite, since we want to close socket fast and
738 		   not bother waiting for SSL protocol close response before closing socket,
739 		   since we want cleanup to be done fast for scenarios like:
740 		   client change NAT (like jump from one WiFi to another) and now unreachable from old ip:port, however
741 		   immidiately reconnect with new ip:port but old session id (and thus should replace the old session/channel)
742 		*/
743 		SSL_shutdown(wsh->ssl);
744 	}
745 
746 	/* restore to blocking here, so any further read/writes will block */
747 	restore_socket(wsh->sock);
748 
749 	if (wsh->close_sock && wsh->sock != ws_sock_invalid) {
750 		/* signal socket to shutdown() before close(): FIN-ACK-FIN-ACK insead of RST-RST
751 		   do not really handle errors here since it all going to die anyway.
752 		   all buffered writes if any(like SSL_shutdown() ones) will still be sent.
753 		 */
754 #ifndef WIN32
755 		shutdown(wsh->sock, SHUT_RDWR);
756 		close(wsh->sock);
757 #else
758 		shutdown(wsh->sock, SD_BOTH);
759 		closesocket(wsh->sock);
760 #endif
761 	}
762 
763 	wsh->sock = ws_sock_invalid;
764 
765 	return reason * -1;
766 
767 }
768 
769 
hton64(uint64_t val)770 uint64_t hton64(uint64_t val)
771 {
772 	if (__BYTE_ORDER == __BIG_ENDIAN) return (val);
773 	else return __bswap_64(val);
774 }
775 
ntoh64(uint64_t val)776 uint64_t ntoh64(uint64_t val)
777 {
778 	if (__BYTE_ORDER == __BIG_ENDIAN) return (val);
779 	else return __bswap_64(val);
780 }
781 
782 
ws_read_frame(wsh_t * wsh,ws_opcode_t * oc,uint8_t ** data)783 ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
784 {
785 
786 	ssize_t need = 2;
787 	char *maskp;
788 	int ll = 0;
789 	int frag = 0;
790 	int blen;
791 
792 	wsh->body = wsh->bbuffer;
793 	wsh->packetlen = 0;
794 
795  again:
796 	need = 2;
797 	maskp = NULL;
798 	*data = NULL;
799 
800 	ll = establish_logical_layer(wsh);
801 
802 	if (ll < 0) {
803 		return ll;
804 	}
805 
806 	if (wsh->down) {
807 		return -1;
808 	}
809 
810 	if (!wsh->handshake) {
811 		return ws_close(wsh, WS_NONE);
812 	}
813 
814 	if ((wsh->datalen = ws_raw_read(wsh, wsh->buffer, 9, wsh->block)) < 0) {
815 		if (wsh->datalen == -2) {
816 			return -2;
817 		}
818 		return ws_close(wsh, WS_NONE);
819 	}
820 
821 	if (wsh->datalen < need) {
822 		ssize_t bytes = ws_raw_read(wsh, wsh->buffer + wsh->datalen, 9 - wsh->datalen, WS_BLOCK);
823 
824 		if (bytes < 0 || (wsh->datalen + bytes) < need) {
825 			/* too small - protocol err */
826 			return ws_close(wsh, WS_NONE);
827 		}
828 	}
829 
830 	*oc = *wsh->buffer & 0xf;
831 
832 	switch(*oc) {
833 	case WSOC_CLOSE:
834 		{
835 			wsh->plen = wsh->buffer[1] & 0x7f;
836 			*data = (uint8_t *) &wsh->buffer[2];
837 			return ws_close(wsh, WS_RECV_CLOSE);
838 		}
839 		break;
840 	case WSOC_CONTINUATION:
841 	case WSOC_TEXT:
842 	case WSOC_BINARY:
843 	case WSOC_PING:
844 	case WSOC_PONG:
845 		{
846 			int fin = (wsh->buffer[0] >> 7) & 1;
847 			int mask = (wsh->buffer[1] >> 7) & 1;
848 
849 
850 			if (!fin && *oc != WSOC_CONTINUATION) {
851 				frag = 1;
852 			} else if (fin && *oc == WSOC_CONTINUATION) {
853 				frag = 0;
854 			}
855 
856 			if (mask) {
857 				need += 4;
858 
859 				if (need > wsh->datalen) {
860 					/* too small - protocol err */
861 					*oc = WSOC_CLOSE;
862 					return ws_close(wsh, WS_NONE);
863 				}
864 			}
865 
866 			wsh->plen = wsh->buffer[1] & 0x7f;
867 			wsh->payload = &wsh->buffer[2];
868 
869 			if (wsh->plen == 127) {
870 				uint64_t *u64;
871 				int more = 0;
872 
873 				need += 8;
874 
875 				if (need > wsh->datalen) {
876 					/* too small - protocol err */
877 					//*oc = WSOC_CLOSE;
878 					//return ws_close(wsh, WS_PROTO_ERR);
879 
880 					more = ws_raw_read(wsh, wsh->buffer + wsh->datalen, need - wsh->datalen, WS_BLOCK);
881 
882 					if (more < 0 || more < need - wsh->datalen) {
883 						*oc = WSOC_CLOSE;
884 						return ws_close(wsh, WS_NONE);
885 					} else {
886 						wsh->datalen += more;
887 					}
888 
889 
890 				}
891 
892 				u64 = (uint64_t *) wsh->payload;
893 				wsh->payload += 8;
894 				wsh->plen = ntoh64(*u64);
895 			} else if (wsh->plen == 126) {
896 				uint16_t *u16;
897 
898 				need += 2;
899 
900 				if (need > wsh->datalen) {
901 					/* too small - protocol err */
902 					*oc = WSOC_CLOSE;
903 					return ws_close(wsh, WS_NONE);
904 				}
905 
906 				u16 = (uint16_t *) wsh->payload;
907 				wsh->payload += 2;
908 				wsh->plen = ntohs(*u16);
909 			}
910 
911 			if (mask) {
912 				maskp = (char *)wsh->payload;
913 				wsh->payload += 4;
914 			}
915 
916 			need = (wsh->plen - (wsh->datalen - need));
917 
918 			if (need < 0) {
919 				/* invalid read - protocol err .. */
920 				*oc = WSOC_CLOSE;
921 				return ws_close(wsh, WS_NONE);
922 			}
923 
924 			blen = wsh->body - wsh->bbuffer;
925 
926 			if (need + blen > (ssize_t)wsh->bbuflen) {
927 				void *tmp;
928 
929 				wsh->bbuflen = need + blen + wsh->rplen;
930 
931 				if ((tmp = realloc(wsh->bbuffer, wsh->bbuflen))) {
932 					wsh->bbuffer = tmp;
933 				} else {
934 					abort();
935 				}
936 
937 				wsh->body = wsh->bbuffer + blen;
938 			}
939 
940 			wsh->rplen = wsh->plen - need;
941 
942 			if (wsh->rplen) {
943 				memcpy(wsh->body, wsh->payload, wsh->rplen);
944 			}
945 
946 			while(need) {
947 				ssize_t r = ws_raw_read(wsh, wsh->body + wsh->rplen, need, WS_BLOCK);
948 
949 				if (r < 1) {
950 					/* invalid read - protocol err .. */
951 					*oc = WSOC_CLOSE;
952 					return ws_close(wsh, WS_NONE);
953 				}
954 
955 				wsh->datalen += r;
956 				wsh->rplen += r;
957 				need -= r;
958 			}
959 
960 			if (mask && maskp) {
961 				ssize_t i;
962 
963 				for (i = 0; i < wsh->datalen; i++) {
964 					wsh->body[i] ^= maskp[i % 4];
965 				}
966 			}
967 
968 
969 			if (*oc == WSOC_PING) {
970 				ws_write_frame(wsh, WSOC_PONG, wsh->body, wsh->rplen);
971 				goto again;
972 			}
973 
974 			*(wsh->body+wsh->rplen) = '\0';
975 			wsh->packetlen += wsh->rplen;
976 			wsh->body += wsh->rplen;
977 
978 			if (frag) {
979 				goto again;
980 			}
981 
982 			*data = (uint8_t *)wsh->bbuffer;
983 
984 			//printf("READ[%ld][%d]-----------------------------:\n[%s]\n-------------------------------\n", wsh->packetlen, *oc, (char *)*data);
985 
986 
987 			return wsh->packetlen;
988 		}
989 		break;
990 	default:
991 		{
992 			/* invalid op code - protocol err .. */
993 			*oc = WSOC_CLOSE;
994 			return ws_close(wsh, WS_PROTO_ERR);
995 		}
996 		break;
997 	}
998 }
999 
ws_write_frame(wsh_t * wsh,ws_opcode_t oc,void * data,size_t bytes)1000 ssize_t ws_write_frame(wsh_t *wsh, ws_opcode_t oc, void *data, size_t bytes)
1001 {
1002 	uint8_t hdr[14] = { 0 };
1003 	size_t hlen = 2;
1004 	uint8_t *bp;
1005 	ssize_t raw_ret = 0;
1006 
1007 	if (wsh->down) {
1008 		return -1;
1009 	}
1010 
1011 	//printf("WRITE[%ld]-----------------------------:\n[%s]\n-----------------------------------\n", bytes, (char *) data);
1012 
1013 	hdr[0] = (uint8_t)(oc | 0x80);
1014 
1015 	if (bytes < 126) {
1016 		hdr[1] = (uint8_t)bytes;
1017 	} else if (bytes < 0x10000) {
1018 		uint16_t *u16;
1019 
1020 		hdr[1] = 126;
1021 		hlen += 2;
1022 
1023 		u16 = (uint16_t *) &hdr[2];
1024 		*u16 = htons((uint16_t) bytes);
1025 
1026 	} else {
1027 		uint64_t *u64;
1028 
1029 		hdr[1] = 127;
1030 		hlen += 8;
1031 
1032 		u64 = (uint64_t *) &hdr[2];
1033 		*u64 = hton64(bytes);
1034 	}
1035 
1036 	if (wsh->write_buffer_len < (hlen + bytes + 1)) {
1037 		void *tmp;
1038 
1039 		wsh->write_buffer_len = hlen + bytes + 1;
1040 		if ((tmp = realloc(wsh->write_buffer, wsh->write_buffer_len))) {
1041 			wsh->write_buffer = tmp;
1042 		} else {
1043 			abort();
1044 		}
1045 	}
1046 
1047 	bp = (uint8_t *) wsh->write_buffer;
1048 	memcpy(bp, (void *) &hdr[0], hlen);
1049 	memcpy(bp + hlen, data, bytes);
1050 
1051 	raw_ret = ws_raw_write(wsh, bp, (hlen + bytes));
1052 
1053 	if (raw_ret != (ssize_t) (hlen + bytes)) {
1054 		return raw_ret;
1055 	}
1056 
1057 	return bytes;
1058 }
1059 
1060 #ifdef _MSC_VER
1061 
xp_errno(void)1062 int xp_errno(void)
1063 {
1064 	return WSAGetLastError();
1065 }
1066 
xp_is_blocking(int errcode)1067 int xp_is_blocking(int errcode)
1068 {
1069 	return errcode == WSAEWOULDBLOCK || errcode == WSAEINPROGRESS;
1070 }
1071 
1072 #else
1073 
xp_errno(void)1074 int xp_errno(void)
1075 {
1076 	return errno;
1077 }
1078 
xp_is_blocking(int errcode)1079 int xp_is_blocking(int errcode)
1080 {
1081   return errcode == EAGAIN || errcode == EWOULDBLOCK || errcode == EINPROGRESS || errcode == EINTR || errcode == ETIMEDOUT;
1082 }
1083 
1084 #endif
1085