1/* 2 * libwebsockets - small server side websockets and web server implementation 3 * 4 * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to 8 * deal in the Software without restriction, including without limitation the 9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 * IN THE SOFTWARE. 23 */ 24 25#include "private-lib-core.h" 26 27#ifdef LWS_HAVE_SYS_TYPES_H 28#include <sys/types.h> 29#endif 30#include <signal.h> 31 32void 33lws_ser_wu16be(uint8_t *b, uint16_t u) 34{ 35 *b++ = (uint8_t)(u >> 8); 36 *b = (uint8_t)u; 37} 38 39void 40lws_ser_wu32be(uint8_t *b, uint32_t u32) 41{ 42 *b++ = (uint8_t)(u32 >> 24); 43 *b++ = (uint8_t)(u32 >> 16); 44 *b++ = (uint8_t)(u32 >> 8); 45 *b = (uint8_t)u32; 46} 47 48void 49lws_ser_wu64be(uint8_t *b, uint64_t u64) 50{ 51 lws_ser_wu32be(b, (uint32_t)(u64 >> 32)); 52 lws_ser_wu32be(b + 4, (uint32_t)u64); 53} 54 55uint16_t 56lws_ser_ru16be(const uint8_t *b) 57{ 58 return (uint16_t)((b[0] << 8) | b[1]); 59} 60 61uint32_t 62lws_ser_ru32be(const uint8_t *b) 63{ 64 return (unsigned int)((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]); 65} 66 67uint64_t 68lws_ser_ru64be(const uint8_t *b) 69{ 70 return (((uint64_t)lws_ser_ru32be(b)) << 32) | lws_ser_ru32be(b + 4); 71} 72 73int 74lws_vbi_encode(uint64_t value, void *buf) 75{ 76 uint8_t *p = (uint8_t *)buf, b; 77 78 if (value > 0xfffffff) { 79 assert(0); 80 return -1; 81 } 82 83 do { 84 b = value & 0x7f; 85 value >>= 7; 86 if (value) 87 *p++ = (0x80 | b); 88 else 89 *p++ = b; 90 } while (value); 91 92 return lws_ptr_diff(p, buf); 93} 94 95int 96lws_vbi_decode(const void *buf, uint64_t *value, size_t len) 97{ 98 const uint8_t *p = (const uint8_t *)buf, *end = p + len; 99 uint64_t v = 0; 100 int s = 0; 101 102 while (p < end) { 103 v |= (((uint64_t)(*p)) & 0x7f) << s; 104 if (*p & 0x80) { 105 *value = v; 106 107 return lws_ptr_diff(p, buf); 108 } 109 s += 7; 110 if (s >= 64) 111 return 0; 112 p++; 113 } 114 115 return 0; 116} 117 118signed char char_to_hex(const char c) 119{ 120 if (c >= '0' && c <= '9') 121 return (signed char)(c - '0'); 122 123 if (c >= 'a' && c <= 'f') 124 return (signed char)(c - 'a' + 10); 125 126 if (c >= 'A' && c <= 'F') 127 return (signed char)(c - 'A' + 10); 128 129 return (signed char)-1; 130} 131 132int 133lws_hex_to_byte_array(const char *h, uint8_t *dest, int max) 134{ 135 uint8_t *odest = dest; 136 137 while (max-- && *h) { 138 int t = char_to_hex(*h++), t1; 139 140 if (!*h || t < 0) 141 return -1; 142 143 t1 = char_to_hex(*h++); 144 if (t1 < 0) 145 return -1; 146 147 *dest++ = (uint8_t)((t << 4) | t1); 148 } 149 150 if (max < 0) 151 return -1; 152 153 return lws_ptr_diff(dest, odest); 154} 155 156static char *hexch = "0123456789abcdef"; 157 158void 159lws_hex_from_byte_array(const uint8_t *src, size_t slen, char *dest, size_t len) 160{ 161 char *end = &dest[len - 1]; 162 163 while (slen-- && dest != end) { 164 uint8_t b = *src++; 165 *dest++ = hexch[b >> 4]; 166 if (dest == end) 167 break; 168 *dest++ = hexch[b & 0xf]; 169 } 170 171 *dest = '\0'; 172} 173 174int 175lws_hex_random(struct lws_context *context, char *dest, size_t len) 176{ 177 size_t n = ((len - 1) / 2) + 1; 178 uint8_t b, *r = (uint8_t *)dest + len - n; 179 180 if (lws_get_random(context, r, n) != n) 181 return 1; 182 183 while (len >= 3) { 184 b = *r++; 185 *dest++ = hexch[b >> 4]; 186 *dest++ = hexch[b & 0xf]; 187 len -= 2; 188 } 189 190 if (len == 2) 191 *dest++ = hexch[(*r) >> 4]; 192 193 *dest = '\0'; 194 195 return 0; 196} 197 198#if !defined(LWS_PLAT_OPTEE) 199 200#if defined(LWS_WITH_FILE_OPS) 201int lws_open(const char *__file, int __oflag, ...) 202{ 203 va_list ap; 204 int n; 205 206 va_start(ap, __oflag); 207 if (((__oflag & O_CREAT) == O_CREAT) 208#if defined(O_TMPFILE) 209 || ((__oflag & O_TMPFILE) == O_TMPFILE) 210#endif 211 ) 212#if defined(WIN32) 213 /* last arg is really a mode_t. But windows... */ 214 n = open(__file, __oflag, va_arg(ap, uint32_t)); 215#else 216 /* ... and some other toolchains... 217 * 218 * error: second argument to 'va_arg' is of promotable type 'mode_t' 219 * (aka 'unsigned short'); this va_arg has undefined behavior because 220 * arguments will be promoted to 'int' 221 */ 222 n = open(__file, __oflag, (mode_t)va_arg(ap, unsigned int)); 223#endif 224 else 225 n = open(__file, __oflag); 226 va_end(ap); 227 228 if (n != -1 && lws_plat_apply_FD_CLOEXEC(n)) { 229 close(n); 230 231 return -1; 232 } 233 234 return n; 235} 236#endif 237#endif 238 239int 240lws_pthread_self_to_tsi(struct lws_context *context) 241{ 242#if LWS_MAX_SMP > 1 243 pthread_t ps = pthread_self(); 244 struct lws_context_per_thread *pt = &context->pt[0]; 245 int n; 246 247 /* case that we have SMP build, but don't use it */ 248 if (context->count_threads == 1) 249 return 0; 250 251 for (n = 0; n < context->count_threads; n++) { 252 if (pthread_equal(ps, pt->self)) 253 return n; 254 pt++; 255 } 256 257 return -1; 258#else 259 return 0; 260#endif 261} 262 263void * 264lws_context_user(struct lws_context *context) 265{ 266 return context->user_space; 267} 268 269void 270lws_explicit_bzero(void *p, size_t len) 271{ 272 volatile uint8_t *vp = p; 273 274 while (len--) 275 *vp++ = 0; 276} 277 278#if !(defined(LWS_PLAT_OPTEE) && !defined(LWS_WITH_NETWORK)) 279 280/** 281 * lws_now_secs() - seconds since 1970-1-1 282 * 283 */ 284unsigned long 285lws_now_secs(void) 286{ 287 struct timeval tv; 288 289 gettimeofday(&tv, NULL); 290 291 return (unsigned long)tv.tv_sec; 292} 293 294#endif 295 296#if defined(LWS_WITH_SERVER) 297const char * 298lws_canonical_hostname(struct lws_context *context) 299{ 300 return (const char *)context->canonical_hostname; 301} 302#endif 303 304int 305lws_get_count_threads(struct lws_context *context) 306{ 307 return context->count_threads; 308} 309 310static const unsigned char e0f4[] = { 311 0xa0 | ((2 - 1) << 2) | 1, /* e0 */ 312 0x80 | ((4 - 1) << 2) | 1, /* e1 */ 313 0x80 | ((4 - 1) << 2) | 1, /* e2 */ 314 0x80 | ((4 - 1) << 2) | 1, /* e3 */ 315 0x80 | ((4 - 1) << 2) | 1, /* e4 */ 316 0x80 | ((4 - 1) << 2) | 1, /* e5 */ 317 0x80 | ((4 - 1) << 2) | 1, /* e6 */ 318 0x80 | ((4 - 1) << 2) | 1, /* e7 */ 319 0x80 | ((4 - 1) << 2) | 1, /* e8 */ 320 0x80 | ((4 - 1) << 2) | 1, /* e9 */ 321 0x80 | ((4 - 1) << 2) | 1, /* ea */ 322 0x80 | ((4 - 1) << 2) | 1, /* eb */ 323 0x80 | ((4 - 1) << 2) | 1, /* ec */ 324 0x80 | ((2 - 1) << 2) | 1, /* ed */ 325 0x80 | ((4 - 1) << 2) | 1, /* ee */ 326 0x80 | ((4 - 1) << 2) | 1, /* ef */ 327 0x90 | ((3 - 1) << 2) | 2, /* f0 */ 328 0x80 | ((4 - 1) << 2) | 2, /* f1 */ 329 0x80 | ((4 - 1) << 2) | 2, /* f2 */ 330 0x80 | ((4 - 1) << 2) | 2, /* f3 */ 331 0x80 | ((1 - 1) << 2) | 2, /* f4 */ 332 333 0, /* s0 */ 334 0x80 | ((4 - 1) << 2) | 0, /* s2 */ 335 0x80 | ((4 - 1) << 2) | 1, /* s3 */ 336}; 337 338int 339lws_check_byte_utf8(unsigned char state, unsigned char c) 340{ 341 unsigned char s = state; 342 343 if (!s) { 344 if (c >= 0x80) { 345 if (c < 0xc2 || c > 0xf4) 346 return -1; 347 if (c < 0xe0) 348 return 0x80 | ((4 - 1) << 2); 349 else 350 return e0f4[c - 0xe0]; 351 } 352 353 return s; 354 } 355 if (c < (s & 0xf0) || c >= (s & 0xf0) + 0x10 + ((s << 2) & 0x30)) 356 return -1; 357 358 return e0f4[21 + (s & 3)]; 359} 360 361int 362lws_check_utf8(unsigned char *state, unsigned char *buf, size_t len) 363{ 364 unsigned char s = *state; 365 366 while (len--) { 367 unsigned char c = *buf++; 368 369 if (!s) { 370 if (c >= 0x80) { 371 if (c < 0xc2 || c > 0xf4) 372 return 1; 373 if (c < 0xe0) 374 s = 0x80 | ((4 - 1) << 2); 375 else 376 s = e0f4[c - 0xe0]; 377 } 378 } else { 379 if (c < (s & 0xf0) || 380 c >= (s & 0xf0) + 0x10 + ((s << 2) & 0x30)) 381 return 1; 382 s = e0f4[21 + (s & 3)]; 383 } 384 } 385 386 *state = s; 387 388 return 0; 389} 390 391 392char * 393lws_strdup(const char *s) 394{ 395 char *d = lws_malloc(strlen(s) + 1, "strdup"); 396 397 if (d) 398 strcpy(d, s); 399 400 return d; 401} 402 403const char * 404lws_nstrstr(const char *buf, size_t len, const char *name, size_t nl) 405{ 406 const char *end = buf + len - nl + 1; 407 size_t n; 408 409 if (nl > len) 410 /* it cannot be found if the needle is longer than the haystack */ 411 return NULL; 412 413 while (buf < end) { 414 if (*buf != name[0]) { 415 buf++; 416 continue; 417 } 418 419 if (nl == 1) 420 /* single char match, we are done */ 421 return buf; 422 423 if (buf[nl - 1] == name[nl - 1]) { 424 /* 425 * This is looking interesting then... the first 426 * and last chars match, let's check the insides 427 */ 428 n = 1; 429 while (n < nl && buf[n] == name[n]) 430 n++; 431 432 if (n == nl) 433 /* it's a hit */ 434 return buf; 435 } 436 437 buf++; 438 } 439 440 return NULL; 441} 442 443/* 444 * name wants to be something like "\"myname\":" 445 */ 446 447const char * 448lws_json_simple_find(const char *buf, size_t len, const char *name, size_t *alen) 449{ 450 size_t nl = strlen(name); 451 const char *np = lws_nstrstr(buf, len, name, nl), 452 *end = buf + len, *as; 453 int qu = 0; 454 455 if (!np) 456 return NULL; 457 458 np += nl; 459 460 while (np < end && (*np == ' ' || *np == '\t')) 461 np++; 462 463 if (np >= end) 464 return NULL; 465 466 /* 467 * The arg could be lots of things after "name": with JSON, commonly a 468 * string like "mystring", true, false, null, [...] or {...} ... we want 469 * to handle common, simple cases cheaply with this; the user can choose 470 * a full JSON parser like lejp if it's complicated. So if no opening 471 * quote, return until a terminator like , ] }. If there's an opening 472 * quote, return until closing quote, handling escaped quotes. 473 */ 474 475 if (*np == '\"') { 476 qu = 1; 477 np++; 478 } 479 480 as = np; 481 while (np < end && 482 (!qu || *np != '\"') && /* end quote is EOT if quoted */ 483 (qu || (*np != '}' && *np != ']' && *np != ',')) /* delimiters */ 484 ) { 485 if (qu && *np == '\\') /* skip next char if quoted escape */ 486 np++; 487 np++; 488 } 489 490 *alen = (unsigned int)lws_ptr_diff(np, as); 491 492 return as; 493} 494 495int 496lws_json_simple_strcmp(const char *buf, size_t len, const char *name, 497 const char *comp) 498{ 499 size_t al; 500 const char *hit = lws_json_simple_find(buf, len, name, &al); 501 502 if (!hit) 503 return -1; 504 505 if (al != strlen(comp)) 506 return -1; 507 508 return strncmp(hit, comp, al); 509} 510 511static const char *hex = "0123456789ABCDEF"; 512 513const char * 514lws_sql_purify(char *escaped, const char *string, size_t len) 515{ 516 const char *p = string; 517 char *q = escaped; 518 519 while (*p && len-- > 2) { 520 if (*p == '\'') { 521 *q++ = '\''; 522 *q++ = '\''; 523 len --; 524 p++; 525 } else 526 *q++ = *p++; 527 } 528 *q = '\0'; 529 530 return escaped; 531} 532 533int 534lws_sql_purify_len(const char *p) 535{ 536 int olen = 0; 537 538 while (*p) { 539 if (*p++ == '\'') 540 olen++; 541 olen++; 542 } 543 544 return olen; 545} 546 547const char * 548lws_json_purify(char *escaped, const char *string, int len, int *in_used) 549{ 550 const char *p = string; 551 char *q = escaped; 552 553 if (!p) { 554 escaped[0] = '\0'; 555 return escaped; 556 } 557 558 while (*p && len-- > 6) { 559 if (*p == '\t') { 560 p++; 561 *q++ = '\\'; 562 *q++ = 't'; 563 continue; 564 } 565 566 if (*p == '\n') { 567 p++; 568 *q++ = '\\'; 569 *q++ = 'n'; 570 continue; 571 } 572 573 if (*p == '\r') { 574 p++; 575 *q++ = '\\'; 576 *q++ = 'r'; 577 continue; 578 } 579 580 if (*p == '\\') { 581 p++; 582 *q++ = '\\'; 583 *q++ = '\\'; 584 continue; 585 } 586 587 if (*p == '\"' || *p < 0x20) { 588 *q++ = '\\'; 589 *q++ = 'u'; 590 *q++ = '0'; 591 *q++ = '0'; 592 *q++ = hex[((*p) >> 4) & 15]; 593 *q++ = hex[(*p) & 15]; 594 len -= 5; 595 p++; 596 } else 597 *q++ = *p++; 598 } 599 *q = '\0'; 600 601 if (in_used) 602 *in_used = lws_ptr_diff(p, string); 603 604 return escaped; 605} 606 607int 608lws_json_purify_len(const char *string) 609{ 610 int len = 0; 611 const char *p = string; 612 613 while (*p) { 614 if (*p == '\t' || *p == '\n' || *p == '\r') { 615 p++; 616 len += 2; 617 continue; 618 } 619 620 if (*p == '\"' || *p == '\\' || *p < 0x20) { 621 len += 6; 622 p++; 623 continue; 624 } 625 p++; 626 len++; 627 } 628 629 return len; 630} 631 632void 633lws_filename_purify_inplace(char *filename) 634{ 635 while (*filename) { 636 637 if (*filename == '.' && filename[1] == '.') { 638 *filename = '_'; 639 filename[1] = '_'; 640 } 641 642 if (*filename == ':' || 643#if !defined(WIN32) 644 *filename == '\\' || 645#endif 646 *filename == '$' || 647 *filename == '%') 648 *filename = '_'; 649 650 filename++; 651 } 652} 653 654const char * 655lws_urlencode(char *escaped, const char *string, int len) 656{ 657 const char *p = string; 658 char *q = escaped; 659 660 while (*p && len-- > 3) { 661 if (*p == ' ') { 662 *q++ = '+'; 663 p++; 664 continue; 665 } 666 if ((*p >= '0' && *p <= '9') || 667 (*p >= 'A' && *p <= 'Z') || 668 (*p >= 'a' && *p <= 'z')) { 669 *q++ = *p++; 670 continue; 671 } 672 *q++ = '%'; 673 *q++ = hex[(*p >> 4) & 0xf]; 674 *q++ = hex[*p & 0xf]; 675 676 len -= 2; 677 p++; 678 } 679 *q = '\0'; 680 681 return escaped; 682} 683 684int 685lws_urldecode(char *string, const char *escaped, int len) 686{ 687 int state = 0, n; 688 char sum = 0; 689 690 while (*escaped && len) { 691 switch (state) { 692 case 0: 693 if (*escaped == '%') { 694 state++; 695 escaped++; 696 continue; 697 } 698 if (*escaped == '+') { 699 escaped++; 700 *string++ = ' '; 701 len--; 702 continue; 703 } 704 *string++ = *escaped++; 705 len--; 706 break; 707 case 1: 708 n = char_to_hex(*escaped); 709 if (n < 0) 710 return -1; 711 escaped++; 712 sum = (char)(n << 4); 713 state++; 714 break; 715 716 case 2: 717 n = char_to_hex(*escaped); 718 if (n < 0) 719 return -1; 720 escaped++; 721 *string++ = (char)(sum | n); 722 len--; 723 state = 0; 724 break; 725 } 726 727 } 728 *string = '\0'; 729 730 return 0; 731} 732 733int 734lws_finalize_startup(struct lws_context *context) 735{ 736 if (lws_check_opt(context->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) 737 if (lws_plat_drop_app_privileges(context, 1)) 738 return 1; 739 740 return 0; 741} 742 743#if !defined(LWS_PLAT_FREERTOS) 744void 745lws_get_effective_uid_gid(struct lws_context *context, uid_t *uid, gid_t *gid) 746{ 747 *uid = context->uid; 748 *gid = context->gid; 749} 750#endif 751 752int 753lws_snprintf(char *str, size_t size, const char *format, ...) 754{ 755 va_list ap; 756 int n; 757 758 if (!size) 759 return 0; 760 761 va_start(ap, format); 762 n = vsnprintf(str, size, format, ap); 763 va_end(ap); 764 765 if (n >= (int)size) 766 return (int)size; 767 768 return n; 769} 770 771char * 772lws_strncpy(char *dest, const char *src, size_t size) 773{ 774 strncpy(dest, src, size - 1); 775 dest[size - 1] = '\0'; 776 777 return dest; 778} 779 780int 781lws_timingsafe_bcmp(const void *a, const void *b, uint32_t len) 782{ 783 const uint8_t *pa = a, *pb = b; 784 uint8_t sum = 0; 785 786 while (len--) 787 sum |= (uint8_t)(*pa++ ^ *pb++); 788 789 return sum; 790} 791 792 793typedef enum { 794 LWS_TOKZS_LEADING_WHITESPACE, 795 LWS_TOKZS_QUOTED_STRING, 796 LWS_TOKZS_TOKEN, 797 LWS_TOKZS_TOKEN_POST_TERMINAL 798} lws_tokenize_state; 799 800lws_tokenize_elem 801lws_tokenize(struct lws_tokenize *ts) 802{ 803 const char *rfc7230_delims = "(),/:;<=>?@[\\]{}"; 804 lws_tokenize_state state = LWS_TOKZS_LEADING_WHITESPACE; 805 char c, flo = 0, d_minus = '-', d_dot = '.', d_star = '*', s_minus = '\0', 806 s_dot = '\0', s_star = '\0', d_eq = '=', s_eq = '\0', skipping = 0; 807 signed char num = (ts->flags & LWS_TOKENIZE_F_NO_INTEGERS) ? 0 : -1; 808 int utf8 = 0; 809 810 /* for speed, compute the effect of the flags outside the loop */ 811 812 if (ts->flags & LWS_TOKENIZE_F_MINUS_NONTERM) { 813 d_minus = '\0'; 814 s_minus = '-'; 815 } 816 if (ts->flags & LWS_TOKENIZE_F_DOT_NONTERM) { 817 d_dot = '\0'; 818 s_dot = '.'; 819 } 820 if (ts->flags & LWS_TOKENIZE_F_ASTERISK_NONTERM) { 821 d_star = '\0'; 822 s_star = '*'; 823 } 824 if (ts->flags & LWS_TOKENIZE_F_EQUALS_NONTERM) { 825 d_eq = '\0'; 826 s_eq = '='; 827 } 828 829 ts->token = NULL; 830 ts->token_len = 0; 831 832 while (ts->len) { 833 c = *ts->start++; 834 ts->len--; 835 836 utf8 = lws_check_byte_utf8((unsigned char)utf8, (unsigned char)c); 837 if (utf8 < 0) 838 return LWS_TOKZE_ERR_BROKEN_UTF8; 839 840 if (!c) 841 break; 842 843 if (skipping) { 844 if (c != '\r' && c != '\n') 845 continue; 846 else 847 skipping = 0; 848 } 849 850 /* comment */ 851 852 if (ts->flags & LWS_TOKENIZE_F_HASH_COMMENT && 853 state != LWS_TOKZS_QUOTED_STRING && 854 c == '#') { 855 skipping = 1; 856 continue; 857 } 858 859 /* whitespace */ 860 861 if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || 862 c == '\f') { 863 switch (state) { 864 case LWS_TOKZS_LEADING_WHITESPACE: 865 case LWS_TOKZS_TOKEN_POST_TERMINAL: 866 continue; 867 case LWS_TOKZS_QUOTED_STRING: 868 ts->token_len++; 869 continue; 870 case LWS_TOKZS_TOKEN: 871 /* we want to scan forward to look for = */ 872 873 state = LWS_TOKZS_TOKEN_POST_TERMINAL; 874 continue; 875 } 876 } 877 878 /* quoted string */ 879 880 if (c == '\"') { 881 if (state == LWS_TOKZS_QUOTED_STRING) 882 return LWS_TOKZE_QUOTED_STRING; 883 884 /* starting a quoted string */ 885 886 if (ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) { 887 if (ts->delim == LWSTZ_DT_NEED_DELIM) 888 return LWS_TOKZE_ERR_COMMA_LIST; 889 ts->delim = LWSTZ_DT_NEED_DELIM; 890 } 891 892 state = LWS_TOKZS_QUOTED_STRING; 893 ts->token = ts->start; 894 ts->token_len = 0; 895 896 continue; 897 } 898 899 /* token= aggregation */ 900 901 if (!(ts->flags & LWS_TOKENIZE_F_EQUALS_NONTERM) && 902 c == '=' && (state == LWS_TOKZS_TOKEN_POST_TERMINAL || 903 state == LWS_TOKZS_TOKEN)) { 904 if (num == 1) 905 return LWS_TOKZE_ERR_NUM_ON_LHS; 906 /* swallow the = */ 907 return LWS_TOKZE_TOKEN_NAME_EQUALS; 908 } 909 910 /* optional token: aggregation */ 911 912 if ((ts->flags & LWS_TOKENIZE_F_AGG_COLON) && c == ':' && 913 (state == LWS_TOKZS_TOKEN_POST_TERMINAL || 914 state == LWS_TOKZS_TOKEN)) 915 /* swallow the : */ 916 return LWS_TOKZE_TOKEN_NAME_COLON; 917 918 /* aggregate . in a number as a float */ 919 920 if (c == '.' && !(ts->flags & LWS_TOKENIZE_F_NO_FLOATS) && 921 state == LWS_TOKZS_TOKEN && num == 1) { 922 if (flo) 923 return LWS_TOKZE_ERR_MALFORMED_FLOAT; 924 flo = 1; 925 ts->token_len++; 926 continue; 927 } 928 929 /* 930 * Delimiter... by default anything that: 931 * 932 * - isn't matched earlier, or 933 * - is [A-Z, a-z, 0-9, _], and 934 * - is not a partial utf8 char 935 * 936 * is a "delimiter", it marks the end of a token and is itself 937 * reported as a single LWS_TOKZE_DELIMITER each time. 938 * 939 * However with LWS_TOKENIZE_F_RFC7230_DELIMS flag, tokens may 940 * contain any noncontrol character that isn't defined in 941 * rfc7230_delims, and only characters listed there are treated 942 * as delimiters. 943 */ 944 945 if (!utf8 && 946 ((ts->flags & LWS_TOKENIZE_F_RFC7230_DELIMS && 947 strchr(rfc7230_delims, c) && c > 32) || 948 ((!(ts->flags & LWS_TOKENIZE_F_RFC7230_DELIMS) && 949 (c < '0' || c > '9') && (c < 'A' || c > 'Z') && 950 (c < 'a' || c > 'z') && c != '_') && 951 c != s_minus && c != s_dot && c != s_star && c != s_eq) || 952 c == d_minus || c == d_dot || c == d_star || c == d_eq 953 ) && 954 !((ts->flags & LWS_TOKENIZE_F_SLASH_NONTERM) && c == '/')) { 955 switch (state) { 956 case LWS_TOKZS_LEADING_WHITESPACE: 957 if (ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) { 958 if (c != ',' || 959 ts->delim != LWSTZ_DT_NEED_DELIM) 960 return LWS_TOKZE_ERR_COMMA_LIST; 961 ts->delim = LWSTZ_DT_NEED_NEXT_CONTENT; 962 } 963 964 ts->token = ts->start - 1; 965 ts->token_len = 1; 966 return LWS_TOKZE_DELIMITER; 967 968 case LWS_TOKZS_QUOTED_STRING: 969 ts->token_len++; 970 continue; 971 972 case LWS_TOKZS_TOKEN_POST_TERMINAL: 973 case LWS_TOKZS_TOKEN: 974 /* report the delimiter next time */ 975 ts->start--; 976 ts->len++; 977 goto token_or_numeric; 978 } 979 } 980 981 /* anything that's not whitespace or delimiter is payload */ 982 983 switch (state) { 984 case LWS_TOKZS_LEADING_WHITESPACE: 985 986 if (ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) { 987 if (ts->delim == LWSTZ_DT_NEED_DELIM) 988 return LWS_TOKZE_ERR_COMMA_LIST; 989 ts->delim = LWSTZ_DT_NEED_DELIM; 990 } 991 992 state = LWS_TOKZS_TOKEN; 993 ts->token = ts->start - 1; 994 ts->token_len = 1; 995 goto checknum; 996 997 case LWS_TOKZS_QUOTED_STRING: 998 case LWS_TOKZS_TOKEN: 999 ts->token_len++; 1000checknum: 1001 if (!(ts->flags & LWS_TOKENIZE_F_NO_INTEGERS)) { 1002 if (c < '0' || c > '9') 1003 num = 0; 1004 else 1005 if (num < 0) 1006 num = 1; 1007 } 1008 continue; 1009 1010 case LWS_TOKZS_TOKEN_POST_TERMINAL: 1011 /* report the new token next time */ 1012 ts->start--; 1013 ts->len++; 1014 goto token_or_numeric; 1015 } 1016 } 1017 1018 /* we ran out of content */ 1019 1020 if (utf8) /* ended partway through a multibyte char */ 1021 return LWS_TOKZE_ERR_BROKEN_UTF8; 1022 1023 if (state == LWS_TOKZS_QUOTED_STRING) 1024 return LWS_TOKZE_ERR_UNTERM_STRING; 1025 1026 if (state != LWS_TOKZS_TOKEN_POST_TERMINAL && 1027 state != LWS_TOKZS_TOKEN) { 1028 if ((ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) && 1029 ts->delim == LWSTZ_DT_NEED_NEXT_CONTENT) 1030 return LWS_TOKZE_ERR_COMMA_LIST; 1031 1032 return LWS_TOKZE_ENDED; 1033 } 1034 1035 /* report the pending token */ 1036 1037token_or_numeric: 1038 1039 if (num != 1) 1040 return LWS_TOKZE_TOKEN; 1041 if (flo) 1042 return LWS_TOKZE_FLOAT; 1043 1044 return LWS_TOKZE_INTEGER; 1045} 1046 1047 1048int 1049lws_tokenize_cstr(struct lws_tokenize *ts, char *str, size_t max) 1050{ 1051 if (ts->token_len + 1 >= max) 1052 return 1; 1053 1054 memcpy(str, ts->token, ts->token_len); 1055 str[ts->token_len] = '\0'; 1056 1057 return 0; 1058} 1059 1060void 1061lws_tokenize_init(struct lws_tokenize *ts, const char *start, int flags) 1062{ 1063 ts->start = start; 1064 ts->len = 0x7fffffff; 1065 ts->flags = (uint16_t)(unsigned int)flags; 1066 ts->delim = LWSTZ_DT_NEED_FIRST_CONTENT; 1067} 1068 1069 1070typedef enum { 1071 LWS_EXPS_LITERAL, 1072 LWS_EXPS_OPEN_OR_LIT, 1073 LWS_EXPS_NAME_OR_CLOSE, 1074 LWS_EXPS_DRAIN, 1075} lws_strexp_state; 1076 1077void 1078lws_strexp_init(lws_strexp_t *exp, void *priv, lws_strexp_expand_cb cb, 1079 char *out, size_t olen) 1080{ 1081 memset(exp, 0, sizeof(*exp)); 1082 exp->cb = cb; 1083 exp->out = out; 1084 exp->olen = olen; 1085 exp->state = LWS_EXPS_LITERAL; 1086 exp->priv = priv; 1087} 1088 1089void 1090lws_strexp_reset_out(lws_strexp_t *exp, char *out, size_t olen) 1091{ 1092 exp->out = out; 1093 exp->olen = olen; 1094 exp->pos = 0; 1095} 1096 1097int 1098lws_strexp_expand(lws_strexp_t *exp, const char *in, size_t len, 1099 size_t *pused_in, size_t *pused_out) 1100{ 1101 size_t used = 0; 1102 int n; 1103 1104 while (used < len) { 1105 1106 switch (exp->state) { 1107 case LWS_EXPS_LITERAL: 1108 if (*in == '$') { 1109 exp->state = LWS_EXPS_OPEN_OR_LIT; 1110 break; 1111 } 1112 1113 if (exp->out) 1114 exp->out[exp->pos] = *in; 1115 exp->pos++; 1116 if (exp->olen - exp->pos < 1) { 1117 *pused_in = used + 1; 1118 *pused_out = exp->pos; 1119 return LSTRX_FILLED_OUT; 1120 } 1121 break; 1122 1123 case LWS_EXPS_OPEN_OR_LIT: 1124 if (*in == '{') { 1125 exp->state = LWS_EXPS_NAME_OR_CLOSE; 1126 exp->name_pos = 0; 1127 exp->exp_ofs = 0; 1128 break; 1129 } 1130 /* treat as a literal */ 1131 if (exp->olen - exp->pos < 3) 1132 return -1; 1133 1134 if (exp->out) { 1135 exp->out[exp->pos++] = '$'; 1136 exp->out[exp->pos++] = *in; 1137 } else 1138 exp->pos += 2; 1139 if (*in != '$') 1140 exp->state = LWS_EXPS_LITERAL; 1141 break; 1142 1143 case LWS_EXPS_NAME_OR_CLOSE: 1144 if (*in == '}') { 1145 exp->name[exp->name_pos] = '\0'; 1146 exp->state = LWS_EXPS_DRAIN; 1147 goto drain; 1148 } 1149 if (exp->name_pos >= sizeof(exp->name) - 1) 1150 return LSTRX_FATAL_NAME_TOO_LONG; 1151 1152 exp->name[exp->name_pos++] = *in; 1153 break; 1154 1155 case LWS_EXPS_DRAIN: 1156drain: 1157 *pused_in = used; 1158 n = exp->cb(exp->priv, exp->name, exp->out, &exp->pos, 1159 exp->olen, &exp->exp_ofs); 1160 *pused_out = exp->pos; 1161 if (n == LSTRX_FILLED_OUT || 1162 n == LSTRX_FATAL_NAME_UNKNOWN) 1163 return n; 1164 1165 exp->state = LWS_EXPS_LITERAL; 1166 break; 1167 } 1168 1169 used++; 1170 in++; 1171 } 1172 1173 if (exp->out) 1174 exp->out[exp->pos] = '\0'; 1175 *pused_in = used; 1176 *pused_out = exp->pos; 1177 1178 return LSTRX_DONE; 1179} 1180 1181int 1182lws_strcmp_wildcard(const char *wildcard, size_t wlen, const char *check, 1183 size_t clen) 1184{ 1185 const char *match[3], *wc[3], *wc_end = wildcard + wlen, 1186 *cend = check + clen; 1187 int sp = 0; 1188 1189 do { 1190 1191 if (wildcard == wc_end) { 1192 /* 1193 * We reached the end of wildcard, but not of check, 1194 * and the last thing in wildcard was not a * or we 1195 * would have completed already... if we can rewind, 1196 * let's try that... 1197 */ 1198 if (sp) { 1199 wildcard = wc[sp - 1]; 1200 check = match[--sp]; 1201 1202 continue; 1203 } 1204 1205 /* otherwise it's the end of the road for this one */ 1206 1207 return 1; 1208 } 1209 1210 if (*wildcard == '*') { 1211 1212 if (++wildcard == wc_end) 1213 /* 1214 * Wildcard ended on a *, so we know we will 1215 * match unconditionally 1216 */ 1217 return 0; 1218 1219 /* 1220 * Now we need to stick wildcard here and see if there 1221 * is any remaining match exists, for eg b of "a*b" 1222 */ 1223 1224 if (sp == LWS_ARRAY_SIZE(match)) { 1225 lwsl_err("%s: exceeds * stack\n", __func__); 1226 return 1; /* we can't deal with it */ 1227 } 1228 1229 wc[sp] = wildcard; 1230 /* if we ever pop and come back here, pick up from +1 */ 1231 match[sp++] = check + 1; 1232 continue; 1233 } 1234 1235 if (*(check++) == *wildcard) { 1236 1237 if (wildcard == wc_end) 1238 return 0; 1239 /* 1240 * We're still compatible with wildcard... keep going 1241 */ 1242 wildcard++; 1243 1244 continue; 1245 } 1246 1247 if (!sp) 1248 /* 1249 * We're just trying to match literals, and failed... 1250 */ 1251 return 1; 1252 1253 /* we're looking for a post-* match... keep looking... */ 1254 1255 } while (check < cend); 1256 1257 /* 1258 * We reached the end of check, if also at end of wildcard we're OK 1259 */ 1260 1261 return wildcard != wc_end; 1262} 1263 1264#if LWS_MAX_SMP > 1 1265 1266void 1267lws_mutex_refcount_init(struct lws_mutex_refcount *mr) 1268{ 1269 pthread_mutex_init(&mr->lock, NULL); 1270 mr->last_lock_reason = NULL; 1271 mr->lock_depth = 0; 1272 mr->metadata = 0; 1273#ifdef __PTW32_H 1274 /* If we use implementation of PThreads for Win that is 1275 * distributed by VCPKG */ 1276 memset(&mr->lock_owner, 0, sizeof(pthread_t)); 1277#else 1278 mr->lock_owner = 0; 1279#endif 1280} 1281 1282void 1283lws_mutex_refcount_destroy(struct lws_mutex_refcount *mr) 1284{ 1285 pthread_mutex_destroy(&mr->lock); 1286} 1287 1288void 1289lws_mutex_refcount_lock(struct lws_mutex_refcount *mr, const char *reason) 1290{ 1291 /* if true, this sequence is atomic because our thread has the lock 1292 * 1293 * - if true, only guy who can race to make it untrue is our thread, 1294 * and we are here. 1295 * 1296 * - if false, only guy who could race to make it true is our thread, 1297 * and we are here 1298 * 1299 * - it can be false and change to a different tid that is also false 1300 */ 1301#ifdef __PTW32_H 1302 /* If we use implementation of PThreads for Win that is 1303 * distributed by VCPKG */ 1304 if (pthread_equal(mr->lock_owner, pthread_self())) 1305#else 1306 if (mr->lock_owner == pthread_self()) 1307#endif 1308 { 1309 /* atomic because we only change it if we own the lock */ 1310 mr->lock_depth++; 1311 return; 1312 } 1313 1314 pthread_mutex_lock(&mr->lock); 1315 /* atomic because only we can have the lock */ 1316 mr->last_lock_reason = reason; 1317 mr->lock_owner = pthread_self(); 1318 mr->lock_depth = 1; 1319 //lwsl_notice("tid %d: lock %s\n", mr->tid, reason); 1320} 1321 1322void 1323lws_mutex_refcount_unlock(struct lws_mutex_refcount *mr) 1324{ 1325 if (--mr->lock_depth) 1326 /* atomic because only thread that has the lock can unlock */ 1327 return; 1328 1329 mr->last_lock_reason = "free"; 1330#ifdef __PTW32_H 1331 /* If we use implementation of PThreads for Win that is 1332 * distributed by VCPKG */ 1333 memset(&mr->lock_owner, 0, sizeof(pthread_t)); 1334#else 1335 mr->lock_owner = 0; 1336#endif 1337 // lwsl_notice("tid %d: unlock %s\n", mr->tid, mr->last_lock_reason); 1338 pthread_mutex_unlock(&mr->lock); 1339} 1340 1341void 1342lws_mutex_refcount_assert_held(struct lws_mutex_refcount *mr) 1343{ 1344#ifdef __PTW32_H 1345 /* If we use implementation of PThreads for Win that is 1346 * distributed by VCPKG */ 1347 assert(pthread_equal(mr->lock_owner, pthread_self()) && mr->lock_depth); 1348#else 1349 assert(mr->lock_owner == pthread_self() && mr->lock_depth); 1350#endif 1351} 1352 1353#endif /* SMP */ 1354 1355 1356const char * 1357lws_cmdline_option(int argc, const char **argv, const char *val) 1358{ 1359 size_t n = strlen(val); 1360 int c = argc; 1361 1362 while (--c > 0) { 1363 1364 if (!strncmp(argv[c], val, n)) { 1365 if (!*(argv[c] + n) && c < argc - 1) { 1366 /* coverity treats unchecked argv as "tainted" */ 1367 if (!argv[c + 1] || strlen(argv[c + 1]) > 1024) 1368 return NULL; 1369 return argv[c + 1]; 1370 } 1371 1372 if (argv[c][n] == '=') 1373 return &argv[c][n + 1]; 1374 return argv[c] + n; 1375 } 1376 } 1377 1378 return NULL; 1379} 1380 1381static const char * const builtins[] = { 1382 "-d", 1383 "--fault-injection", 1384 "--fault-seed", 1385 "--ignore-sigterm" 1386}; 1387 1388enum opts { 1389 OPT_DEBUGLEVEL, 1390 OPT_FAULTINJECTION, 1391 OPT_FAULT_SEED, 1392 OPT_IGNORE_SIGTERM, 1393}; 1394 1395#if !defined(LWS_PLAT_FREERTOS) 1396static void 1397lws_sigterm_catch(int sig) 1398{ 1399} 1400#endif 1401 1402void 1403lws_cmdline_option_handle_builtin(int argc, const char **argv, 1404 struct lws_context_creation_info *info) 1405{ 1406 const char *p; 1407 int n, m, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE; 1408#if defined(LWS_WITH_SYS_FAULT_INJECTION) 1409 uint64_t seed = (uint64_t)lws_now_usecs(); 1410#endif 1411 1412 for (n = 0; n < (int)LWS_ARRAY_SIZE(builtins); n++) { 1413 p = lws_cmdline_option(argc, argv, builtins[n]); 1414 if (!p) 1415 continue; 1416 1417 m = atoi(p); 1418 1419 switch (n) { 1420 case OPT_DEBUGLEVEL: 1421 logs = m; 1422 break; 1423 1424 case OPT_FAULTINJECTION: 1425#if !defined(LWS_WITH_SYS_FAULT_INJECTION) 1426 lwsl_err("%s: FAULT_INJECTION not built\n", __func__); 1427#endif 1428 lws_fi_deserialize(&info->fic, p); 1429 break; 1430 1431 case OPT_FAULT_SEED: 1432#if defined(LWS_WITH_SYS_FAULT_INJECTION) 1433 seed = (uint64_t)atoll(p); 1434#endif 1435 break; 1436 1437 case OPT_IGNORE_SIGTERM: 1438#if !defined(LWS_PLAT_FREERTOS) 1439 signal(SIGTERM, lws_sigterm_catch); 1440#endif 1441 break; 1442 } 1443 } 1444 1445#if defined(LWS_WITH_SYS_FAULT_INJECTION) 1446 lws_xos_init(&info->fic.xos, seed); 1447#endif 1448 lws_set_log_level(logs, NULL); 1449 1450#if defined(LWS_WITH_SYS_FAULT_INJECTION) 1451 if (info->fic.fi_owner.count) 1452 lwsl_notice("%s: Fault Injection seed %llu\n", __func__, 1453 (unsigned long long)seed); 1454#endif 1455} 1456 1457 1458const lws_humanize_unit_t humanize_schema_si[] = { 1459 { "Pi", LWS_PI }, { "Ti", LWS_TI }, { "Gi", LWS_GI }, 1460 { "Mi", LWS_MI }, { "Ki", LWS_KI }, { "", 1 }, 1461 { NULL, 0 } 1462}; 1463const lws_humanize_unit_t humanize_schema_si_bytes[] = { 1464 { "PiB", LWS_PI }, { "TiB", LWS_TI }, { "GiB", LWS_GI }, 1465 { "MiB", LWS_MI }, { "KiB", LWS_KI }, { "B", 1 }, 1466 { NULL, 0 } 1467}; 1468const lws_humanize_unit_t humanize_schema_us[] = { 1469 { "y", (uint64_t)365 * 24 * 3600 * LWS_US_PER_SEC }, 1470 { "d", (uint64_t)24 * 3600 * LWS_US_PER_SEC }, 1471 { "hr", (uint64_t)3600 * LWS_US_PER_SEC }, 1472 { "min", 60 * LWS_US_PER_SEC }, 1473 { "s", LWS_US_PER_SEC }, 1474 { "ms", LWS_US_PER_MS }, 1475#if defined(WIN32) 1476 { "us", 1 }, 1477#else 1478 { "μs", 1 }, 1479#endif 1480 { NULL, 0 } 1481}; 1482 1483/* biggest ull is 18446744073709551615 (20 chars) */ 1484 1485static int 1486decim(char *r, uint64_t v, char chars, char leading) 1487{ 1488 uint64_t q = 1; 1489 char *ro = r; 1490 int n = 1; 1491 1492 while ((leading || v > (q * 10) - 1) && n < 20 && n < chars) { 1493 q = q * 10; 1494 n++; 1495 } 1496 1497 /* n is how many chars needed */ 1498 1499 while (n--) { 1500 *r++ = (char)('0' + (char)((v / q) % 10)); 1501 q = q / 10; 1502 } 1503 1504 *r = '\0'; 1505 1506 return lws_ptr_diff(r, ro); 1507} 1508 1509int 1510lws_humanize(char *p, size_t len, uint64_t v, const lws_humanize_unit_t *schema) 1511{ 1512 char *obuf = p, *end = p + len; 1513 1514 do { 1515 if (v >= schema->factor || schema->factor == 1) { 1516 if (schema->factor == 1) { 1517 p += decim(p, v, 4, 0); 1518 p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), 1519 "%s", schema->name); 1520 return lws_ptr_diff(p, obuf); 1521 } 1522 1523 p += decim(p, v / schema->factor, 4, 0); 1524 *p++ = '.'; 1525 p += decim(p, (v % schema->factor) / 1526 (schema->factor / 1000), 3, 1); 1527 1528 p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), 1529 "%s", schema->name); 1530 return lws_ptr_diff(p, obuf); 1531 } 1532 schema++; 1533 } while (schema->name); 1534 1535 assert(0); 1536 strncpy(p, "unknown value", len); 1537 1538 return 0; 1539} 1540