Bug Summary

File:ws.c
Warning:line 842, column 4
Value stored to 'code' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ws.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-11/lib/clang/11.0.1 -D HAVE_CONFIG_H -I . -I ../.. -I ../../libsofia-sip-ua/su/sofia-sip -I ./../bnf -I ../bnf -I ./../stun -I ../stun -I ./../ipt -I ../ipt -I ./../msg -I ../msg -I ./../http -I ../http -I ./../url -I ../url -I ./../sip -I ../sip -I ./../su -I ../su -I ./include -D SU_DEBUG=0 -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-11/lib/clang/11.0.1/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir /drone/src/libsofia-sip-ua/tport -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-output=html -faddrsig -o /drone/src/scan-build/2023-10-25-225327-13-1 -x c ws.c
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__1) || defined(__GLIBC__2)
10#include <byteswap.h>
11#endif
12
13#ifndef _MSC_VER
14#define ms_sleep(x)usleep( x * 1000); usleep( x * 1000);
15#else
16#define ms_sleep(x)usleep( x * 1000); 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_BLOCK1 1
25#define WS_NOBLOCK0 0
26
27#define WS_INIT_SANITY5000 5000
28#define WS_WRITE_SANITY200 200
29
30#define SHA1_HASH_SIZE20 20
31static struct ws_globals_s ws_globals;
32ssize_t ws_global_payload_size_max = 0;
33
34#ifndef WSS_STANDALONE
35
36void init_ssl(void)
37{
38 // SSL_library_init();
39 SSL_load_error_strings()OPENSSL_init_ssl(0x00200000L | 0x00000002L, ((void*)0));
40}
41void deinit_ssl(void)
42{
43 return;
44}
45
46#else
47static void pthreads_thread_id(CRYPTO_THREADID *id);
48static void pthreads_locking_callback(int mode, int type, const char *file, int line);
49
50static pthread_mutex_t *lock_cs;
51static long *lock_count;
52
53
54
55static void thread_setup(void)
56{
57 int i;
58
59 lock_cs = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t))CRYPTO_malloc((1) * sizeof(pthread_mutex_t), "ws.c", 59);
60 lock_count = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long))CRYPTO_malloc((1) * sizeof(long), "ws.c", 60);
61
62 for (i = 0; i < CRYPTO_num_locks()(1); i++) {
63 lock_count[i] = 0;
64 pthread_mutex_init(&(lock_cs[i]), NULL((void*)0));
65 }
66
67 CRYPTO_THREADID_set_callback(pthreads_thread_id)(0);
68 CRYPTO_set_locking_callback(pthreads_locking_callback);
69}
70
71static void thread_cleanup(void)
72{
73 int i;
74
75 CRYPTO_set_locking_callback(NULL);
76
77 for (i=0; i<CRYPTO_num_locks()(1); i++) {
78 pthread_mutex_destroy(&(lock_cs[i]));
79 }
80 OPENSSL_free(lock_cs)CRYPTO_free(lock_cs, "ws.c", 80);
81 OPENSSL_free(lock_count)CRYPTO_free(lock_count, "ws.c", 81);
82
83}
84
85static void pthreads_locking_callback(int mode, int type, const char *file, int line)
86{
87
88 if (mode & CRYPTO_LOCK1) {
89 pthread_mutex_lock(&(lock_cs[type]));
90 lock_count[type]++;
91 } else {
92 pthread_mutex_unlock(&(lock_cs[type]));
93 }
94}
95
96
97
98static void pthreads_thread_id(CRYPTO_THREADID *id)
99{
100 CRYPTO_THREADID_set_numeric(id, (unsigned long)pthread_self());
101}
102
103
104void init_ssl(void) {
105 SSL_library_init()OPENSSL_init_ssl(0, ((void*)0));
106
107
108 OpenSSL_add_all_algorithms()OPENSSL_init_crypto(0x00000004L | 0x00000008L, ((void*)0)); /* load & register cryptos */
109 SSL_load_error_strings()OPENSSL_init_ssl(0x00200000L | 0x00000002L, ((void*)0)); /* load all error messages */
110 ws_globals.ssl_method = SSLv23_server_methodTLS_server_method(); /* create server instance */
111 ws_globals.ssl_ctx = SSL_CTX_new(ws_globals.ssl_method); /* create context */
112 assert(ws_globals.ssl_ctx)((void) sizeof ((ws_globals.ssl_ctx) ? 1 : 0), __extension__ (
{ if (ws_globals.ssl_ctx) ; else __assert_fail ("ws_globals.ssl_ctx"
, "ws.c", 112, __extension__ __PRETTY_FUNCTION__); }))
;
113
114 /* Disable SSLv2 */
115 SSL_CTX_set_options(ws_globals.ssl_ctx, SSL_OP_NO_SSLv20x0);
116 /* Disable SSLv3 */
117 SSL_CTX_set_options(ws_globals.ssl_ctx, SSL_OP_NO_SSLv30x02000000U);
118 /* Disable TLSv1 */
119 SSL_CTX_set_options(ws_globals.ssl_ctx, SSL_OP_NO_TLSv10x04000000U);
120 /* Disable Compression CRIME (Compression Ratio Info-leak Made Easy) */
121 SSL_CTX_set_options(ws_globals.ssl_ctx, SSL_OP_NO_COMPRESSION0x00020000U);
122 /* set the local certificate from CertFile */
123 SSL_CTX_use_certificate_file(ws_globals.ssl_ctx, ws_globals.cert, SSL_FILETYPE_PEM1);
124 /* set the private key from KeyFile */
125 SSL_CTX_use_PrivateKey_file(ws_globals.ssl_ctx, ws_globals.key, SSL_FILETYPE_PEM1);
126 /* verify private key */
127 if ( !SSL_CTX_check_private_key(ws_globals.ssl_ctx) ) {
128 abort();
129 }
130
131 SSL_CTX_set_cipher_list(ws_globals.ssl_ctx, "HIGH:!DSS:!aNULL@STRENGTH");
132
133 thread_setup();
134}
135
136
137void deinit_ssl(void) {
138 thread_cleanup();
139}
140
141#endif
142
143static const char c64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
144
145
146static int cheezy_get_var(char *data, char *name, char *buf, size_t buflen)
147{
148 char *p=data;
149
150 /* the old way didnt make sure that variable values were used for the name hunt
151 * and didnt ensure that only a full match of the variable name was used
152 */
153
154 do {
155 if(!strncasecmp(p,name,strlen(name)) && *(p+strlen(name))==':') break;
156 } while((p = (strstr(p,"\n")+1))!=(char *)1);
157
158
159 if (p && p != (char *)1 && *p!='\0') {
160 char *v, *e = 0;
161
162 v = strchr(p, ':');
163 if (v) {
164 v++;
165 while(v && *v == ' ') {
166 v++;
167 }
168 if (v) {
169 e = strchr(v, '\r');
170 if (!e) {
171 e = strchr(v, '\n');
172 }
173 }
174
175 if (v && e) {
176 int cplen;
177 size_t len = e - v;
178
179 if (len > buflen - 1) {
180 cplen = buflen -1;
181 } else {
182 cplen = len;
183 }
184
185 strncpy(buf, v, cplen);
186 *(buf+cplen) = '\0';
187 return 1;
188 }
189
190 }
191 }
192 return 0;
193}
194
195static int b64encode(unsigned char *in, size_t ilen, unsigned char *out, size_t olen)
196{
197 int y=0,bytes=0;
198 size_t x=0;
199 unsigned int b=0,l=0;
200
201 if(olen) {
202 }
203
204 for(x=0;x<ilen;x++) {
205 b = (b<<8) + in[x];
206 l += 8;
207 while (l >= 6) {
208 out[bytes++] = c64[(b>>(l-=6))%64];
209 if(++y!=72) {
210 continue;
211 }
212 //out[bytes++] = '\n';
213 y=0;
214 }
215 }
216
217 if (l > 0) {
218 out[bytes++] = c64[((b%16)<<(6-l))%64];
219 }
220 if (l != 0) while (l < 6) {
221 out[bytes++] = '=', l += 2;
222 }
223
224 return 0;
225}
226
227#ifdef NO_OPENSSL
228static void sha1_digest(char *digest, unsigned char *in)
229{
230 SHA1Context sha;
231 char *p;
232 int x;
233
234
235 SHA1Init(&sha);
236 SHA1Update(&sha, in, strlen(in));
237 SHA1Final(&sha, digest);
238}
239#else
240
241static void sha1_digest(unsigned char *digest, char *in)
242{
243 SHA_CTX sha;
244
245 SHA1_Init(&sha);
246 SHA1_Update(&sha, in, strlen(in));
247 SHA1_Final(digest, &sha);
248
249}
250
251#endif
252
253int ws_handshake(wsh_t *wsh)
254{
255 char key[256] = "";
256 char version[5] = "";
257 char proto[256] = "";
258 char proto_buf[384] = "";
259 char input[512] = "";
260 unsigned char output[SHA1_HASH_SIZE20] = "";
261 char b64[256] = "";
262 char respond[1024] = "";
263 ssize_t bytes;
264 char *p, *e = 0;
265
266 if (wsh->sock == ws_sock_invalid(ws_socket_t)-1) {
267 return -3;
268 }
269
270 while((bytes = ws_raw_read(wsh, wsh->buffer + wsh->datalen, wsh->buflen - wsh->datalen, WS_BLOCK1)) > 0) {
271 wsh->datalen += bytes;
272 if (strstr(wsh->buffer, "\r\n\r\n") || strstr(wsh->buffer, "\n\n")) {
273 break;
274 }
275 }
276
277 if (bytes < 0 || bytes > wsh->buflen -1) {
278 goto err;
279 }
280
281 *(wsh->buffer + wsh->datalen) = '\0';
282
283 if (strncasecmp(wsh->buffer, "GET ", 4)) {
284 goto err;
285 }
286
287 p = wsh->buffer + 4;
288
289 e = strchr(p, ' ');
290 if (!e) {
291 goto err;
292 }
293
294 wsh->uri = malloc((e-p) + 1);
295
296 if (!wsh->uri) goto err;
297
298 strncpy(wsh->uri, p, e-p);
299 *(wsh->uri + (e-p)) = '\0';
300
301 cheezy_get_var(wsh->buffer, "Sec-WebSocket-Key", key, sizeof(key));
302 cheezy_get_var(wsh->buffer, "Sec-WebSocket-Version", version, sizeof(version));
303 cheezy_get_var(wsh->buffer, "Sec-WebSocket-Protocol", proto, sizeof(proto));
304
305 if (!*key) {
306 goto err;
307 }
308
309 snprintf(input, sizeof(input), "%s%s", key, WEBSOCKET_GUID"258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
310 sha1_digest(output, input);
311 b64encode((unsigned char *)output, SHA1_HASH_SIZE20, (unsigned char *)b64, sizeof(b64));
312
313 if (*proto) {
314 snprintf(proto_buf, sizeof(proto_buf), "Sec-WebSocket-Protocol: %s\r\n", proto);
315 }
316
317 snprintf(respond, sizeof(respond),
318 "HTTP/1.1 101 Switching Protocols\r\n"
319 "Upgrade: websocket\r\n"
320 "Connection: Upgrade\r\n"
321 "Sec-WebSocket-Accept: %s\r\n"
322 "%s\r\n",
323 b64,
324 proto_buf);
325 respond[511] = 0;
326
327 if (ws_raw_write(wsh, respond, strlen(respond)) != (ssize_t)strlen(respond)) {
328 goto err;
329 }
330
331 wsh->handshake = 1;
332
333 return 0;
334
335 err:
336
337 if (!wsh->stay_open) {
338
339 if (bytes > 0) {
340 snprintf(respond, sizeof(respond), "HTTP/1.1 400 Bad Request\r\n"
341 "Sec-WebSocket-Version: 13\r\n\r\n");
342 respond[511] = 0;
343
344 ws_raw_write(wsh, respond, strlen(respond));
345 }
346
347 ws_close(wsh, WS_NONE);
348 }
349
350 return -1;
351
352}
353
354#define SSL_WANT_READ_WRITE(err)(err == 2 || err == 3) (err == SSL_ERROR_WANT_READ2 || err == SSL_ERROR_WANT_WRITE3)
355int wss_error(wsh_t *wsh, int ssl_err, char const *who);
356
357ssize_t ws_raw_read(wsh_t *wsh, void *data, size_t bytes, int block)
358{
359 ssize_t r;
360 int ssl_err = 0;
361
362 wsh->x++;
363 if (wsh->x > 250) ms_sleep(1)usleep( 1 * 1000);;
364
365 if (wsh->ssl) {
366 do {
367 //ERR_clear_error();
368 r = SSL_read(wsh->ssl, data, bytes);
369
370 if (r < 0) {
371 ssl_err = SSL_get_error(wsh->ssl, r);
372
373 if (SSL_WANT_READ_WRITE(ssl_err)(ssl_err == 2 || ssl_err == 3)) {
374 if (!block) {
375 r = -2;
376 goto end;
377 }
378 wsh->x++;
379 ms_sleep(10)usleep( 10 * 1000);;
380 } else {
381 wss_error(wsh, ssl_err, "ws_raw_read: SSL_read");
382 r = -1;
383 goto end;
384 }
385 }
386
387 } while (r < 0 && SSL_WANT_READ_WRITE(ssl_err)(ssl_err == 2 || ssl_err == 3) && wsh->x < 1000);
388
389 goto end;
390 }
391
392 do {
393
394 r = recv(wsh->sock, data, bytes, 0);
395
396 if (r == -1) {
397 if (!block && xp_is_blocking(xp_errno())) {
398 r = -2;
399 goto end;
400 }
401
402 if (block) {
403 wsh->x++;
404 ms_sleep(10)usleep( 10 * 1000);;
405 }
406 }
407 } while (r == -1 && xp_is_blocking(xp_errno()) && wsh->x < 1000);
408
409 end:
410
411 if (wsh->x >= 10000 || (block && wsh->x >= 1000)) {
412 r = -1;
413 }
414
415 if (r > 0) {
416 *((char *)data + r) = '\0';
417 }
418
419 if (r >= 0) {
420 wsh->x = 0;
421 }
422
423 return r;
424}
425
426/** Log WSS error(s).
427 *
428 * Log the WSS error specified by the error code @a e and all the errors in
429 * the queue. The error code @a e implies no error, and it is not logged.
430 */
431void wss_log_errors(unsigned level, char const *s, unsigned long e)
432{
433 if (e == 0)
434 e = ERR_get_error();
435
436 if (!tport_log->log_init)
437 su_log_init(tport_log);
438
439 if (s == NULL((void*)0)) s = "tls";
440
441 for (; e != 0; e = ERR_get_error()) {
442 if (level <= tport_log->log_level) {
443 const char *error = ERR_lib_error_string(e);
444 const char *func = ERR_func_error_string(e);
445 const char *reason = ERR_reason_error_string(e);
446
447 su_llog(tport_log, level, "%s: %08lx:%s:%s:%s\n",_su_llog(tport_log, level, "ws.c", (const char *)__func__, 448
, "%s: %08lx:%s:%s:%s\n", s, e, error, func, reason)
448 s, e, error, func, reason)_su_llog(tport_log, level, "ws.c", (const char *)__func__, 448
, "%s: %08lx:%s:%s:%s\n", s, e, error, func, reason)
;
449 }
450 }
451}
452
453int wss_error(wsh_t *wsh, int ssl_err, char const *who)
454{
455 switch (ssl_err) {
456 case SSL_ERROR_ZERO_RETURN6:
457 return 0;
458
459 case SSL_ERROR_SYSCALL5:
460 ERR_clear_error();
461 if (SSL_get_shutdown(wsh->ssl) & SSL_RECEIVED_SHUTDOWN2)
462 return 0; /* EOS */
463 if (errno(*__errno_location ()) == 0)
464 return 0; /* EOS */
465
466 errno(*__errno_location ()) = EIO5;
467 return -1;
468
469 default:
470 wss_log_errors(1, who, ssl_err);
471 errno(*__errno_location ()) = EIO5;
472 return -1;
473 }
474}
475
476/*
477 * Blocking read until bytes have been received, failure, or too many retries.
478 */
479static ssize_t ws_raw_read_blocking(wsh_t *wsh, char *data, size_t max_bytes, int max_retries)
480{
481 ssize_t total_bytes_read = 0;
482 while (total_bytes_read < max_bytes && max_retries-- > 0) {
483 ssize_t bytes_read = ws_raw_read(wsh, data + total_bytes_read, max_bytes - total_bytes_read, WS_BLOCK1);
484 if (bytes_read < 0) {
485 break;
486 }
487 total_bytes_read += bytes_read;
488 }
489 return total_bytes_read;
490}
491
492ssize_t ws_raw_write(wsh_t *wsh, void *data, size_t bytes)
493{
494 ssize_t r;
495 int sanity = WS_WRITE_SANITY200;
496 int ssl_err = 0;
497 size_t wrote = 0;
498
499 if (wsh == NULL((void*)0) || data == NULL((void*)0)) {
500 errno(*__errno_location ()) = EINVAL22;
501 return -1;
502 }
503
504 if (wsh->ssl) {
505 do {
506 void *buf = (void *)((unsigned char *)data + wrote);
507 int size = bytes - wrote;
508
509 //ERR_clear_error();
510 r = SSL_write(wsh->ssl, buf, size);
511
512 if (r == 0) {
513 ssl_err = -42;
514 break;
515 }
516
517 if (r > 0) {
518 wrote += r;
519 }
520
521 if (sanity < WS_WRITE_SANITY200) {
522 int ms = 1;
523
524 if (wsh->block) {
525 if (sanity < WS_WRITE_SANITY200 / 2) {
526 ms = 25;
527 } else if (sanity < WS_WRITE_SANITY200 * 3 / 4) {
528 ms = 50;
529 }
530 }
531 ms_sleep(ms)usleep( ms * 1000);;
532 }
533
534 if (r < 0) {
535 ssl_err = SSL_get_error(wsh->ssl, r);
536
537 if (!SSL_WANT_READ_WRITE(ssl_err)(ssl_err == 2 || ssl_err == 3)) {
538 ssl_err = wss_error(wsh, ssl_err, "ws_raw_write: SSL_write");
539 break;
540 }
541 ssl_err = 0;
542 }
543
544 } while (--sanity > 0 && wrote < bytes);
545
546 if (!sanity) ssl_err = -56;
547
548 if (ssl_err) {
549 r = ssl_err;
550 }
551
552 return r < 0 ? r : wrote;
553 }
554
555 do {
556 r = send(wsh->sock, (void *)((unsigned char *)data + wrote), bytes - wrote, 0);
557
558 if (r > 0) {
559 wrote += r;
560 }
561
562 if (sanity < WS_WRITE_SANITY200) {
563 int ms = 1;
564
565 if (wsh->block) {
566 if (sanity < WS_WRITE_SANITY200 / 2) {
567 ms = 25;
568 } else if (sanity < WS_WRITE_SANITY200 * 3 / 4) {
569 ms = 50;
570 }
571 }
572 ms_sleep(ms)usleep( ms * 1000);;
573 }
574
575 if (r == -1) {
576 if (!xp_is_blocking(xp_errno())) {
577 break;
578 }
579 }
580
581 } while (--sanity > 0 && wrote < bytes);
582
583 //if (r<0) {
584 //printf("wRITE FAIL: %s\n", strerror(errno));
585 //}
586
587 return r < 0 ? r : wrote;
588}
589
590#ifdef _MSC_VER
591static int setup_socket(ws_socket_t sock)
592{
593 unsigned long v = 1;
594
595 if (ioctlsocket(sock, FIONBIO0x5421, &v) == SOCKET_ERRORSOCKET_ERROR) {
596 return -1;
597 }
598
599 return 0;
600
601}
602
603static int restore_socket(ws_socket_t sock)
604{
605 unsigned long v = 0;
606
607 if (ioctlsocket(sock, FIONBIO0x5421, &v) == SOCKET_ERRORSOCKET_ERROR) {
608 return -1;
609 }
610
611 return 0;
612
613}
614
615#else
616
617static int setup_socket(ws_socket_t sock)
618{
619 int flags = fcntl(sock, F_GETFL3, 0);
620 return fcntl(sock, F_SETFL4, flags | O_NONBLOCK04000);
621}
622
623static int restore_socket(ws_socket_t sock)
624{
625 int flags = fcntl(sock, F_GETFL3, 0);
626
627 flags &= ~O_NONBLOCK04000;
628
629 return fcntl(sock, F_SETFL4, flags);
630
631}
632
633#endif
634
635
636int establish_logical_layer(wsh_t *wsh)
637{
638
639 if (!wsh->sanity) {
640 return -1;
641 }
642
643 if (wsh->logical_established) {
644 return 0;
645 }
646
647 if (wsh->secure && !wsh->secure_established) {
648 int code;
649
650 if (!wsh->ssl) {
651 wsh->ssl = SSL_new(wsh->ssl_ctx);
652 assert(wsh->ssl)((void) sizeof ((wsh->ssl) ? 1 : 0), __extension__ ({ if (
wsh->ssl) ; else __assert_fail ("wsh->ssl", "ws.c", 652
, __extension__ __PRETTY_FUNCTION__); }))
;
653
654 SSL_set_fd(wsh->ssl, wsh->sock);
655 }
656
657 do {
658 code = SSL_accept(wsh->ssl);
659
660 if (code == 1) {
661 wsh->secure_established = 1;
662 break;
663 }
664
665 if (code == 0) {
666 return -1;
667 }
668
669 if (code < 0) {
670 int ssl_err = SSL_get_error(wsh->ssl, code);
671 if (!SSL_WANT_READ_WRITE(ssl_err)(ssl_err == 2 || ssl_err == 3)) {
672 wss_error(wsh, ssl_err, "establish_logical_layer: SSL_accept");
673 return -1;
674 }
675 }
676
677 if (wsh->block) {
678 ms_sleep(10)usleep( 10 * 1000);;
679 } else {
680 ms_sleep(1)usleep( 1 * 1000);;
681 }
682
683 wsh->sanity--;
684
685 if (!wsh->block) {
686 return -2;
687 }
688
689 } while (wsh->sanity > 0);
690
691 if (!wsh->sanity) {
692 return -1;
693 }
694
695 }
696
697 while (!wsh->down && !wsh->handshake) {
698 int r = ws_handshake(wsh);
699
700 if (r < 0) {
701 wsh->down = 1;
702 return -1;
703 }
704
705 if (!wsh->handshake && !wsh->block) {
706 return -2;
707 }
708
709 }
710
711 wsh->logical_established = 1;
712
713 return 0;
714}
715
716void ws_set_global_payload_size_max(ssize_t bytes)
717{
718 ws_global_payload_size_max = bytes;
719}
720
721int ws_init(wsh_t *wsh, ws_socket_t sock, SSL_CTX *ssl_ctx, int close_sock, int block, int stay_open)
722{
723 memset(wsh, 0, sizeof(*wsh));
724
725 wsh->payload_size_max = ws_global_payload_size_max;
726 wsh->sock = sock;
727 wsh->block = block;
728 wsh->sanity = WS_INIT_SANITY5000;
729 wsh->ssl_ctx = ssl_ctx;
730 wsh->stay_open = stay_open;
731
732 if (!ssl_ctx) {
733 ssl_ctx = ws_globals.ssl_ctx;
734 }
735
736 if (close_sock) {
737 wsh->close_sock = 1;
738 }
739
740 wsh->buflen = 1024 * 64;
741 wsh->bbuflen = wsh->buflen;
742
743 wsh->buffer = malloc(wsh->buflen);
744 wsh->bbuffer = malloc(wsh->bbuflen);
745 //printf("init %p %ld\n", (void *) wsh->bbuffer, wsh->bbuflen);
746 //memset(wsh->buffer, 0, wsh->buflen);
747 //memset(wsh->bbuffer, 0, wsh->bbuflen);
748
749 wsh->secure = ssl_ctx ? 1 : 0;
750
751 setup_socket(sock);
752
753 if (establish_logical_layer(wsh) == -1) {
754 return -1;
755 }
756
757 if (wsh->down) {
758 return -1;
759 }
760
761 return 0;
762}
763
764void ws_destroy(wsh_t *wsh)
765{
766
767 if (!wsh) {
768 return;
769 }
770
771 if (!wsh->down) {
772 ws_close(wsh, WS_NONE);
773 }
774
775 if (wsh->down > 1) {
776 return;
777 }
778
779 wsh->down = 2;
780
781 if (wsh->write_buffer) {
782 free(wsh->write_buffer);
783 wsh->write_buffer = NULL((void*)0);
784 wsh->write_buffer_len = 0;
785 }
786
787 if (wsh->buffer) free(wsh->buffer);
788 if (wsh->bbuffer) free(wsh->bbuffer);
789
790 wsh->buffer = wsh->bbuffer = NULL((void*)0);
791
792}
793
794ssize_t ws_close(wsh_t *wsh, int16_t reason)
795{
796
797 if (wsh->down) {
798 return -1;
799 }
800
801 wsh->down = 1;
802
803 if (wsh->uri) {
804 free(wsh->uri);
805 wsh->uri = NULL((void*)0);
806 }
807
808 if (reason && wsh->sock != ws_sock_invalid(ws_socket_t)-1) {
809 uint16_t *u16;
810 uint8_t fr[4] = {WSOC_CLOSE | 0x80, 2, 0};
811
812 u16 = (uint16_t *) &fr[2];
813 *u16 = htons((int16_t)reason);
814 ws_raw_write(wsh, fr, 4);
815 }
816
817 if (wsh->ssl) {
818 int code = 0, rcode = 0;
819 int ssl_error = 0;
820 const char* buf = "0";
821
822 /* SSL layer was never established */
823 if (!wsh->secure_established) {
824 goto ssl_finish_it;
825 }
826
827 /* connection has been already closed */
828 if (SSL_get_shutdown(wsh->ssl) & SSL_SENT_SHUTDOWN1) {
829 goto ssl_finish_it;
830 }
831
832 restore_socket(wsh->sock);
833
834 /* peer closes the connection */
835 if (SSL_get_shutdown(wsh->ssl) & SSL_RECEIVED_SHUTDOWN2) {
836 code = SSL_write(wsh->ssl, buf, 1);
837 ssl_error = SSL_get_error(wsh->ssl, code);
838 if (ssl_error == SSL_ERROR_SYSCALL5 || ssl_error == SSL_ERROR_SSL1) {
839 goto ssl_finish_it;
840 }
841
842 code = SSL_shutdown(wsh->ssl);
Value stored to 'code' is never read
843 goto ssl_finish_it;
844 }
845
846 /* us closes the connection. We do bidirection shutdown handshake */
847 code = SSL_write(wsh->ssl, buf, 1);
848 ssl_error = SSL_get_error(wsh->ssl, code);
849 if (ssl_error == SSL_ERROR_SYSCALL5 || ssl_error == SSL_ERROR_SSL1) {
850 goto ssl_finish_it;
851 }
852
853 do {
854 code = SSL_shutdown(wsh->ssl);
855 if (code == 0) {
856 /* need to make sure there are no more data to read */
857 do {
858 if ((rcode = SSL_read(wsh->ssl, wsh->buffer, 9)) <= 0) {
859 ssl_error = SSL_get_error(wsh->ssl, rcode);
860 if (ssl_error == SSL_ERROR_ZERO_RETURN6 || ssl_error == SSL_ERROR_SYSCALL5 || ssl_error == SSL_ERROR_SSL1) {
861 break;
862 }
863 }
864 } while (rcode >= 0);
865 }
866 } while (code == 0);
867
868ssl_finish_it:
869 SSL_free(wsh->ssl);
870 wsh->ssl = NULL((void*)0);
871 }
872
873 if (wsh->close_sock && wsh->sock != ws_sock_invalid(ws_socket_t)-1) {
874#ifndef WIN32
875 close(wsh->sock);
876#else
877 closesocket(wsh->sock);
878#endif
879 }
880
881 wsh->sock = ws_sock_invalid(ws_socket_t)-1;
882
883 return reason * -1;
884
885}
886
887
888uint64_t hton64(uint64_t val)
889{
890 if (__BYTE_ORDER1234 == __BIG_ENDIAN4321) return (val);
891 else return __bswap_64(val);
892}
893
894uint64_t ntoh64(uint64_t val)
895{
896 if (__BYTE_ORDER1234 == __BIG_ENDIAN4321) return (val);
897 else return __bswap_64(val);
898}
899
900
901ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
902{
903
904 ssize_t need = 2;
905 char *maskp;
906 int ll = 0;
907 int frag = 0;
908 int blen;
909
910 wsh->body = wsh->bbuffer;
911 wsh->packetlen = 0;
912
913 again:
914 need = 2;
915 maskp = NULL((void*)0);
916 *data = NULL((void*)0);
917
918 ll = establish_logical_layer(wsh);
919
920 if (ll < 0) {
921 return ll;
922 }
923
924 if (wsh->down) {
925 return -1;
926 }
927
928 if (!wsh->handshake) {
929 return ws_close(wsh, WS_NONE);
930 }
931
932 if ((wsh->datalen = ws_raw_read(wsh, wsh->buffer, 9, wsh->block)) < 0) {
933 if (wsh->datalen == -2) {
934 return -2;
935 }
936 return ws_close(wsh, WS_NONE);
937 }
938
939 if (wsh->datalen < need) {
940 ssize_t bytes = ws_raw_read(wsh, wsh->buffer + wsh->datalen, 9 - wsh->datalen, WS_BLOCK1);
941
942 if (bytes < 0 || (wsh->datalen += bytes) < need) {
943 /* too small - protocol err */
944 return ws_close(wsh, WS_NONE);
945 }
946 }
947
948 *oc = *wsh->buffer & 0xf;
949
950 switch(*oc) {
951 case WSOC_CLOSE:
952 {
953 wsh->plen = wsh->buffer[1] & 0x7f;
954 *data = (uint8_t *) &wsh->buffer[2];
955 return ws_close(wsh, 1000);
956 }
957 break;
958 case WSOC_CONTINUATION:
959 case WSOC_TEXT:
960 case WSOC_BINARY:
961 case WSOC_PING:
962 case WSOC_PONG:
963 {
964 int fin = (wsh->buffer[0] >> 7) & 1;
965 int mask = (wsh->buffer[1] >> 7) & 1;
966
967
968 if (!fin && *oc != WSOC_CONTINUATION) {
969 frag = 1;
970 } else if (fin && *oc == WSOC_CONTINUATION) {
971 frag = 0;
972 }
973
974 if (mask) {
975 need += 4;
976
977 if (need > wsh->datalen) {
978 ssize_t bytes = ws_raw_read_blocking(wsh, wsh->buffer + wsh->datalen, need - wsh->datalen, 10);
979 if (bytes < 0 || (wsh->datalen += bytes) < need) {
980 /* too small - protocol err */
981 *oc = WSOC_CLOSE;
982 return ws_close(wsh, WS_NONE);
983 }
984 }
985 }
986
987 wsh->plen = wsh->buffer[1] & 0x7f;
988 wsh->payload = &wsh->buffer[2];
989
990 if (wsh->plen == 127) {
991 uint64_t *u64;
992
993 need += 8;
994
995 if (need > wsh->datalen) {
996 ssize_t bytes = ws_raw_read_blocking(wsh, wsh->buffer + wsh->datalen, need - wsh->datalen, 10);
997 if (bytes < 0 || (wsh->datalen += bytes) < need) {
998 /* too small - protocol err */
999 *oc = WSOC_CLOSE;
1000 return ws_close(wsh, WS_NONE);
1001 }
1002 }
1003
1004 u64 = (uint64_t *) wsh->payload;
1005 wsh->payload += 8;
1006 wsh->plen = ntoh64(*u64);
1007 } else if (wsh->plen == 126) {
1008 uint16_t *u16;
1009
1010 need += 2;
1011
1012 if (need > wsh->datalen) {
1013 ssize_t bytes = ws_raw_read_blocking(wsh, wsh->buffer + wsh->datalen, need - wsh->datalen, 10);
1014 if (bytes < 0 || (wsh->datalen += bytes) < need) {
1015 /* too small - protocol err */
1016 *oc = WSOC_CLOSE;
1017 return ws_close(wsh, WS_NONE);
1018 }
1019 }
1020
1021 u16 = (uint16_t *) wsh->payload;
1022 wsh->payload += 2;
1023 wsh->plen = ntohs(*u16);
1024 }
1025
1026 if (mask) {
1027 maskp = (char *)wsh->payload;
1028 wsh->payload += 4;
1029 }
1030
1031 need = (wsh->plen - (wsh->datalen - need));
1032
1033 if (need < 0) {
1034 /* invalid read - protocol err .. */
1035 *oc = WSOC_CLOSE;
1036 return ws_close(wsh, WS_NONE);
1037 }
1038
1039 blen = wsh->body - wsh->bbuffer;
1040
1041 if (need + blen > (ssize_t)wsh->bbuflen) {
1042 void *tmp;
1043
1044 wsh->bbuflen = need + blen + wsh->rplen;
1045
1046 if (wsh->payload_size_max && wsh->bbuflen > wsh->payload_size_max) {
1047 /* size limit */
1048 *oc = WSOC_CLOSE;
1049 return ws_close(wsh, WS_NONE);
1050 }
1051
1052 if ((tmp = realloc(wsh->bbuffer, wsh->bbuflen))) {
1053 wsh->bbuffer = tmp;
1054 } else {
1055 abort();
1056 }
1057
1058 wsh->body = wsh->bbuffer + blen;
1059 }
1060
1061 wsh->rplen = wsh->plen - need;
1062
1063 if (wsh->rplen) {
1064 memcpy(wsh->body, wsh->payload, wsh->rplen);
1065 }
1066
1067 while(need) {
1068 ssize_t r = ws_raw_read(wsh, wsh->body + wsh->rplen, need, WS_BLOCK1);
1069
1070 if (r < 1) {
1071 /* invalid read - protocol err .. */
1072 *oc = WSOC_CLOSE;
1073 return ws_close(wsh, WS_NONE);
1074 }
1075
1076 wsh->datalen += r;
1077 wsh->rplen += r;
1078 need -= r;
1079 }
1080
1081 if (mask && maskp) {
1082 ssize_t i;
1083
1084 for (i = 0; i < wsh->datalen; i++) {
1085 wsh->body[i] ^= maskp[i % 4];
1086 }
1087 }
1088
1089
1090 if (*oc == WSOC_PING) {
1091 ws_write_frame(wsh, WSOC_PONG, wsh->body, wsh->rplen);
1092 goto again;
1093 }
1094
1095 *(wsh->body+wsh->rplen) = '\0';
1096 wsh->packetlen += wsh->rplen;
1097 wsh->body += wsh->rplen;
1098
1099 if (frag) {
1100 goto again;
1101 }
1102
1103 *data = (uint8_t *)wsh->bbuffer;
1104
1105 //printf("READ[%ld][%d]-----------------------------:\n[%s]\n-------------------------------\n", wsh->packetlen, *oc, (char *)*data);
1106
1107
1108 return wsh->packetlen;
1109 }
1110 break;
1111 default:
1112 {
1113 /* invalid op code - protocol err .. */
1114 *oc = WSOC_CLOSE;
1115 return ws_close(wsh, WS_PROTO_ERR);
1116 }
1117 break;
1118 }
1119}
1120
1121ssize_t ws_write_frame(wsh_t *wsh, ws_opcode_t oc, void *data, size_t bytes)
1122{
1123 uint8_t hdr[14] = { 0 };
1124 size_t hlen = 2;
1125 uint8_t *bp;
1126 ssize_t raw_ret = 0;
1127
1128 if (wsh->down) {
1129 errno(*__errno_location ()) = EIO5;
1130 return -1;
1131 }
1132
1133 //printf("WRITE[%ld]-----------------------------:\n[%s]\n-----------------------------------\n", bytes, (char *) data);
1134
1135 hdr[0] = (uint8_t)(oc | 0x80);
1136
1137 if (bytes < 126) {
1138 hdr[1] = (uint8_t)bytes;
1139 } else if (bytes < 0x10000) {
1140 uint16_t *u16;
1141
1142 hdr[1] = 126;
1143 hlen += 2;
1144
1145 u16 = (uint16_t *) &hdr[2];
1146 *u16 = htons((uint16_t) bytes);
1147
1148 } else {
1149 uint64_t *u64;
1150
1151 hdr[1] = 127;
1152 hlen += 8;
1153
1154 u64 = (uint64_t *) &hdr[2];
1155 *u64 = hton64(bytes);
1156 }
1157
1158 if (wsh->write_buffer_len < (hlen + bytes + 1)) {
1159 void *tmp;
1160
1161 wsh->write_buffer_len = hlen + bytes + 1;
1162 if ((tmp = realloc(wsh->write_buffer, wsh->write_buffer_len))) {
1163 wsh->write_buffer = tmp;
1164 } else {
1165 abort();
1166 }
1167 }
1168
1169 bp = (uint8_t *) wsh->write_buffer;
1170 memcpy(bp, (void *) &hdr[0], hlen);
1171 memcpy(bp + hlen, data, bytes);
1172
1173 raw_ret = ws_raw_write(wsh, bp, (hlen + bytes));
1174
1175 if (raw_ret <= 0 || raw_ret != (ssize_t) (hlen + bytes)) {
1176 return raw_ret;
1177 }
1178
1179 return bytes;
1180}
1181
1182#ifdef _MSC_VER
1183
1184int xp_errno(void)
1185{
1186 return WSAGetLastError();
1187}
1188
1189int xp_is_blocking(int errcode)
1190{
1191 return errcode == WSAEWOULDBLOCK || errcode == WSAEINPROGRESS;
1192}
1193
1194#else
1195
1196int xp_errno(void)
1197{
1198 return errno(*__errno_location ());
1199}
1200
1201int xp_is_blocking(int errcode)
1202{
1203 return errcode == EAGAIN11 || errcode == EWOULDBLOCK11 || errcode == EINPROGRESS115 || errcode == EINTR4 || errcode == ETIMEDOUT110;
1204}
1205
1206#endif