File: | ws.c |
Warning: | line 842, column 4 Value stored to 'code' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 |
31 | static struct ws_globals_s ws_globals; |
32 | ssize_t ws_global_payload_size_max = 0; |
33 | |
34 | #ifndef WSS_STANDALONE |
35 | |
36 | void init_ssl(void) |
37 | { |
38 | // SSL_library_init(); |
39 | SSL_load_error_strings()OPENSSL_init_ssl(0x00200000L | 0x00000002L, ((void*)0)); |
40 | } |
41 | void deinit_ssl(void) |
42 | { |
43 | return; |
44 | } |
45 | |
46 | #else |
47 | static void pthreads_thread_id(CRYPTO_THREADID *id); |
48 | static void pthreads_locking_callback(int mode, int type, const char *file, int line); |
49 | |
50 | static pthread_mutex_t *lock_cs; |
51 | static long *lock_count; |
52 | |
53 | |
54 | |
55 | static 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 | |
71 | static 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 | |
85 | static 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 | |
98 | static void pthreads_thread_id(CRYPTO_THREADID *id) |
99 | { |
100 | CRYPTO_THREADID_set_numeric(id, (unsigned long)pthread_self()); |
101 | } |
102 | |
103 | |
104 | void 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 | |
137 | void deinit_ssl(void) { |
138 | thread_cleanup(); |
139 | } |
140 | |
141 | #endif |
142 | |
143 | static const char c64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
144 | |
145 | |
146 | static 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 | |
195 | static 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 |
228 | static 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 | |
241 | static 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 | |
253 | int 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) |
355 | int wss_error(wsh_t *wsh, int ssl_err, char const *who); |
356 | |
357 | ssize_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 | */ |
431 | void 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 | |
453 | int 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 | */ |
479 | static 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 | |
492 | ssize_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 |
591 | static 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 | |
603 | static 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 | |
617 | static 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 | |
623 | static 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 | |
636 | int 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 | |
716 | void ws_set_global_payload_size_max(ssize_t bytes) |
717 | { |
718 | ws_global_payload_size_max = bytes; |
719 | } |
720 | |
721 | int 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 | |
764 | void 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 | |
794 | ssize_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 | |
868 | ssl_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 | |
888 | uint64_t hton64(uint64_t val) |
889 | { |
890 | if (__BYTE_ORDER1234 == __BIG_ENDIAN4321) return (val); |
891 | else return __bswap_64(val); |
892 | } |
893 | |
894 | uint64_t ntoh64(uint64_t val) |
895 | { |
896 | if (__BYTE_ORDER1234 == __BIG_ENDIAN4321) return (val); |
897 | else return __bswap_64(val); |
898 | } |
899 | |
900 | |
901 | ssize_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 | |
1121 | ssize_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 | |
1184 | int xp_errno(void) |
1185 | { |
1186 | return WSAGetLastError(); |
1187 | } |
1188 | |
1189 | int xp_is_blocking(int errcode) |
1190 | { |
1191 | return errcode == WSAEWOULDBLOCK || errcode == WSAEINPROGRESS; |
1192 | } |
1193 | |
1194 | #else |
1195 | |
1196 | int xp_errno(void) |
1197 | { |
1198 | return errno(*__errno_location ()); |
1199 | } |
1200 | |
1201 | int xp_is_blocking(int errcode) |
1202 | { |
1203 | return errcode == EAGAIN11 || errcode == EWOULDBLOCK11 || errcode == EINPROGRESS115 || errcode == EINTR4 || errcode == ETIMEDOUT110; |
1204 | } |
1205 | |
1206 | #endif |