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