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
31 void
lws_ser_wu16be(uint8_t * b,uint16_t u)32 lws_ser_wu16be(uint8_t *b, uint16_t u)
33 {
34 *b++ = (uint8_t)(u >> 8);
35 *b = (uint8_t)u;
36 }
37
38 void
lws_ser_wu32be(uint8_t * b,uint32_t u32)39 lws_ser_wu32be(uint8_t *b, uint32_t u32)
40 {
41 *b++ = (uint8_t)(u32 >> 24);
42 *b++ = (uint8_t)(u32 >> 16);
43 *b++ = (uint8_t)(u32 >> 8);
44 *b = (uint8_t)u32;
45 }
46
47 void
lws_ser_wu64be(uint8_t * b,uint64_t u64)48 lws_ser_wu64be(uint8_t *b, uint64_t u64)
49 {
50 lws_ser_wu32be(b, (uint32_t)(u64 >> 32));
51 lws_ser_wu32be(b + 4, (uint32_t)u64);
52 }
53
54 uint16_t
lws_ser_ru16be(const uint8_t * b)55 lws_ser_ru16be(const uint8_t *b)
56 {
57 return (b[0] << 8) | b[1];
58 }
59
60 uint32_t
lws_ser_ru32be(const uint8_t * b)61 lws_ser_ru32be(const uint8_t *b)
62 {
63 return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
64 }
65
66 uint64_t
lws_ser_ru64be(const uint8_t * b)67 lws_ser_ru64be(const uint8_t *b)
68 {
69 return (((uint64_t)lws_ser_ru32be(b)) << 32) | lws_ser_ru32be(b + 4);
70 }
71
72 int
lws_vbi_encode(uint64_t value,void * buf)73 lws_vbi_encode(uint64_t value, void *buf)
74 {
75 uint8_t *p = (uint8_t *)buf, b;
76
77 if (value > 0xfffffff) {
78 assert(0);
79 return -1;
80 }
81
82 do {
83 b = value & 0x7f;
84 value >>= 7;
85 if (value)
86 *p++ = (0x80 | b);
87 else
88 *p++ = b;
89 } while (value);
90
91 return lws_ptr_diff(p, buf);
92 }
93
94 int
lws_vbi_decode(const void * buf,uint64_t * value,size_t len)95 lws_vbi_decode(const void *buf, uint64_t *value, size_t len)
96 {
97 const uint8_t *p = (const uint8_t *)buf, *end = p + len;
98 uint64_t v = 0;
99 int s = 0;
100
101 while (p < end) {
102 v |= (((uint64_t)(*p)) & 0x7f) << s;
103 if (*p & 0x80) {
104 *value = v;
105
106 return lws_ptr_diff(p, buf);
107 }
108 s += 7;
109 if (s >= 64)
110 return 0;
111 p++;
112 }
113
114 return 0;
115 }
116
char_to_hex(const char c)117 signed char char_to_hex(const char c)
118 {
119 if (c >= '0' && c <= '9')
120 return c - '0';
121
122 if (c >= 'a' && c <= 'f')
123 return c - 'a' + 10;
124
125 if (c >= 'A' && c <= 'F')
126 return c - 'A' + 10;
127
128 return -1;
129 }
130
131 int
lws_hex_to_byte_array(const char * h,uint8_t * dest,int max)132 lws_hex_to_byte_array(const char *h, uint8_t *dest, int max)
133 {
134 uint8_t *odest = dest;
135
136 while (max-- && *h) {
137 int t = char_to_hex(*h++), t1;
138
139 if (!*h || t < 0)
140 return -1;
141
142 t1 = char_to_hex(*h++);
143 if (t1 < 0)
144 return -1;
145
146 *dest++ = (t << 4) | t1;
147 }
148
149 if (max < 0)
150 return -1;
151
152 return lws_ptr_diff(dest, odest);
153 }
154
155
156 #if !defined(LWS_PLAT_OPTEE)
157
158 #if defined(LWS_WITH_FILE_OPS)
lws_open(const char * __file,int __oflag,...)159 int lws_open(const char *__file, int __oflag, ...)
160 {
161 va_list ap;
162 int n;
163
164 va_start(ap, __oflag);
165 if (((__oflag & O_CREAT) == O_CREAT)
166 #if defined(O_TMPFILE)
167 || ((__oflag & O_TMPFILE) == O_TMPFILE)
168 #endif
169 )
170 /* last arg is really a mode_t. But windows... */
171 n = open(__file, __oflag, va_arg(ap, uint32_t));
172 else
173 n = open(__file, __oflag);
174 va_end(ap);
175
176 if (n != -1 && lws_plat_apply_FD_CLOEXEC(n)) {
177 close(n);
178
179 return -1;
180 }
181
182 return n;
183 }
184 #endif
185 #endif
186
187 int
lws_pthread_self_to_tsi(struct lws_context * context)188 lws_pthread_self_to_tsi(struct lws_context *context)
189 {
190 #if LWS_MAX_SMP > 1
191 pthread_t ps = pthread_self();
192 struct lws_context_per_thread *pt = &context->pt[0];
193 int n;
194
195 for (n = 0; n < context->count_threads; n++) {
196 if (pthread_equal(ps, pt->self))
197 return n;
198 pt++;
199 }
200
201 return -1;
202 #else
203 return 0;
204 #endif
205 }
206
207 void *
lws_context_user(struct lws_context * context)208 lws_context_user(struct lws_context *context)
209 {
210 return context->user_space;
211 }
212
213 void
lws_explicit_bzero(void * p,size_t len)214 lws_explicit_bzero(void *p, size_t len)
215 {
216 volatile uint8_t *vp = p;
217
218 while (len--)
219 *vp++ = 0;
220 }
221
222 #if !(defined(LWS_PLAT_OPTEE) && !defined(LWS_WITH_NETWORK))
223
224 /**
225 * lws_now_secs() - seconds since 1970-1-1
226 *
227 */
228 unsigned long
lws_now_secs(void)229 lws_now_secs(void)
230 {
231 struct timeval tv;
232
233 gettimeofday(&tv, NULL);
234
235 return tv.tv_sec;
236 }
237
238 #endif
239
240 #if defined(LWS_WITH_SERVER)
241 const char *
lws_canonical_hostname(struct lws_context * context)242 lws_canonical_hostname(struct lws_context *context)
243 {
244 return (const char *)context->canonical_hostname;
245 }
246 #endif
247
248 int
lws_get_count_threads(struct lws_context * context)249 lws_get_count_threads(struct lws_context *context)
250 {
251 return context->count_threads;
252 }
253
254 static const unsigned char e0f4[] = {
255 0xa0 | ((2 - 1) << 2) | 1, /* e0 */
256 0x80 | ((4 - 1) << 2) | 1, /* e1 */
257 0x80 | ((4 - 1) << 2) | 1, /* e2 */
258 0x80 | ((4 - 1) << 2) | 1, /* e3 */
259 0x80 | ((4 - 1) << 2) | 1, /* e4 */
260 0x80 | ((4 - 1) << 2) | 1, /* e5 */
261 0x80 | ((4 - 1) << 2) | 1, /* e6 */
262 0x80 | ((4 - 1) << 2) | 1, /* e7 */
263 0x80 | ((4 - 1) << 2) | 1, /* e8 */
264 0x80 | ((4 - 1) << 2) | 1, /* e9 */
265 0x80 | ((4 - 1) << 2) | 1, /* ea */
266 0x80 | ((4 - 1) << 2) | 1, /* eb */
267 0x80 | ((4 - 1) << 2) | 1, /* ec */
268 0x80 | ((2 - 1) << 2) | 1, /* ed */
269 0x80 | ((4 - 1) << 2) | 1, /* ee */
270 0x80 | ((4 - 1) << 2) | 1, /* ef */
271 0x90 | ((3 - 1) << 2) | 2, /* f0 */
272 0x80 | ((4 - 1) << 2) | 2, /* f1 */
273 0x80 | ((4 - 1) << 2) | 2, /* f2 */
274 0x80 | ((4 - 1) << 2) | 2, /* f3 */
275 0x80 | ((1 - 1) << 2) | 2, /* f4 */
276
277 0, /* s0 */
278 0x80 | ((4 - 1) << 2) | 0, /* s2 */
279 0x80 | ((4 - 1) << 2) | 1, /* s3 */
280 };
281
282 int
lws_check_byte_utf8(unsigned char state,unsigned char c)283 lws_check_byte_utf8(unsigned char state, unsigned char c)
284 {
285 unsigned char s = state;
286
287 if (!s) {
288 if (c >= 0x80) {
289 if (c < 0xc2 || c > 0xf4)
290 return -1;
291 if (c < 0xe0)
292 return 0x80 | ((4 - 1) << 2);
293 else
294 return e0f4[c - 0xe0];
295 }
296
297 return s;
298 }
299 if (c < (s & 0xf0) || c >= (s & 0xf0) + 0x10 + ((s << 2) & 0x30))
300 return -1;
301
302 return e0f4[21 + (s & 3)];
303 }
304
305 int
lws_check_utf8(unsigned char * state,unsigned char * buf,size_t len)306 lws_check_utf8(unsigned char *state, unsigned char *buf, size_t len)
307 {
308 unsigned char s = *state;
309
310 while (len--) {
311 unsigned char c = *buf++;
312
313 if (!s) {
314 if (c >= 0x80) {
315 if (c < 0xc2 || c > 0xf4)
316 return 1;
317 if (c < 0xe0)
318 s = 0x80 | ((4 - 1) << 2);
319 else
320 s = e0f4[c - 0xe0];
321 }
322 } else {
323 if (c < (s & 0xf0) ||
324 c >= (s & 0xf0) + 0x10 + ((s << 2) & 0x30))
325 return 1;
326 s = e0f4[21 + (s & 3)];
327 }
328 }
329
330 *state = s;
331
332 return 0;
333 }
334
335
336 char *
lws_strdup(const char * s)337 lws_strdup(const char *s)
338 {
339 char *d = lws_malloc(strlen(s) + 1, "strdup");
340
341 if (d)
342 strcpy(d, s);
343
344 return d;
345 }
346
347 static const char *hex = "0123456789ABCDEF";
348
349 const char *
lws_sql_purify(char * escaped,const char * string,int len)350 lws_sql_purify(char *escaped, const char *string, int len)
351 {
352 const char *p = string;
353 char *q = escaped;
354
355 while (*p && len-- > 2) {
356 if (*p == '\'') {
357 *q++ = '\'';
358 *q++ = '\'';
359 len --;
360 p++;
361 } else
362 *q++ = *p++;
363 }
364 *q = '\0';
365
366 return escaped;
367 }
368
369 int
lws_sql_purify_len(const char * p)370 lws_sql_purify_len(const char *p)
371 {
372 int olen = 0;
373
374 while (*p) {
375 if (*p++ == '\'')
376 olen++;
377 olen++;
378 }
379
380 return olen;
381 }
382
383 const char *
lws_json_purify(char * escaped,const char * string,int len,int * in_used)384 lws_json_purify(char *escaped, const char *string, int len, int *in_used)
385 {
386 const char *p = string;
387 char *q = escaped;
388
389 if (!p) {
390 escaped[0] = '\0';
391 return escaped;
392 }
393
394 while (*p && len-- > 6) {
395 if (*p == '\t') {
396 p++;
397 *q++ = '\\';
398 *q++ = 't';
399 continue;
400 }
401
402 if (*p == '\n') {
403 p++;
404 *q++ = '\\';
405 *q++ = 'n';
406 continue;
407 }
408
409 if (*p == '\r') {
410 p++;
411 *q++ = '\\';
412 *q++ = 'r';
413 continue;
414 }
415
416 if (*p == '\"' || *p == '\\' || *p < 0x20) {
417 *q++ = '\\';
418 *q++ = 'u';
419 *q++ = '0';
420 *q++ = '0';
421 *q++ = hex[((*p) >> 4) & 15];
422 *q++ = hex[(*p) & 15];
423 len -= 5;
424 p++;
425 } else
426 *q++ = *p++;
427 }
428 *q = '\0';
429
430 if (in_used)
431 *in_used = lws_ptr_diff(p, string);
432
433 return escaped;
434 }
435
436 int
lws_json_purify_len(const char * string)437 lws_json_purify_len(const char *string)
438 {
439 int len = 0;
440 const char *p = string;
441
442 while (*p) {
443 if (*p == '\t' || *p == '\n' || *p == '\r') {
444 p++;
445 len += 2;
446 continue;
447 }
448
449 if (*p == '\"' || *p == '\\' || *p < 0x20) {
450 len += 6;
451 p++;
452 continue;
453 }
454 p++;
455 len++;
456 }
457
458 return len;
459 }
460
461 void
lws_filename_purify_inplace(char * filename)462 lws_filename_purify_inplace(char *filename)
463 {
464 while (*filename) {
465
466 if (*filename == '.' && filename[1] == '.') {
467 *filename = '_';
468 filename[1] = '_';
469 }
470
471 if (*filename == ':' ||
472 *filename == '\\' ||
473 *filename == '$' ||
474 *filename == '%')
475 *filename = '_';
476
477 filename++;
478 }
479 }
480
481 const char *
lws_urlencode(char * escaped,const char * string,int len)482 lws_urlencode(char *escaped, const char *string, int len)
483 {
484 const char *p = string;
485 char *q = escaped;
486
487 while (*p && len-- > 3) {
488 if (*p == ' ') {
489 *q++ = '+';
490 p++;
491 continue;
492 }
493 if ((*p >= '0' && *p <= '9') ||
494 (*p >= 'A' && *p <= 'Z') ||
495 (*p >= 'a' && *p <= 'z')) {
496 *q++ = *p++;
497 continue;
498 }
499 *q++ = '%';
500 *q++ = hex[(*p >> 4) & 0xf];
501 *q++ = hex[*p & 0xf];
502
503 len -= 2;
504 p++;
505 }
506 *q = '\0';
507
508 return escaped;
509 }
510
511 int
lws_urldecode(char * string,const char * escaped,int len)512 lws_urldecode(char *string, const char *escaped, int len)
513 {
514 int state = 0, n;
515 char sum = 0;
516
517 while (*escaped && len) {
518 switch (state) {
519 case 0:
520 if (*escaped == '%') {
521 state++;
522 escaped++;
523 continue;
524 }
525 if (*escaped == '+') {
526 escaped++;
527 *string++ = ' ';
528 len--;
529 continue;
530 }
531 *string++ = *escaped++;
532 len--;
533 break;
534 case 1:
535 n = char_to_hex(*escaped);
536 if (n < 0)
537 return -1;
538 escaped++;
539 sum = n << 4;
540 state++;
541 break;
542
543 case 2:
544 n = char_to_hex(*escaped);
545 if (n < 0)
546 return -1;
547 escaped++;
548 *string++ = sum | n;
549 len--;
550 state = 0;
551 break;
552 }
553
554 }
555 *string = '\0';
556
557 return 0;
558 }
559
560 int
lws_finalize_startup(struct lws_context * context)561 lws_finalize_startup(struct lws_context *context)
562 {
563 if (lws_check_opt(context->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
564 if (lws_plat_drop_app_privileges(context, 1))
565 return 1;
566
567 return 0;
568 }
569
570 void
lws_get_effective_uid_gid(struct lws_context * context,int * uid,int * gid)571 lws_get_effective_uid_gid(struct lws_context *context, int *uid, int *gid)
572 {
573 *uid = context->uid;
574 *gid = context->gid;
575 }
576
577 int
lws_snprintf(char * str,size_t size,const char * format,...)578 lws_snprintf(char *str, size_t size, const char *format, ...)
579 {
580 va_list ap;
581 int n;
582
583 if (!size)
584 return 0;
585
586 va_start(ap, format);
587 n = vsnprintf(str, size, format, ap);
588 va_end(ap);
589
590 if (n >= (int)size)
591 return (int)size;
592
593 return n;
594 }
595
596 char *
lws_strncpy(char * dest,const char * src,size_t size)597 lws_strncpy(char *dest, const char *src, size_t size)
598 {
599 strncpy(dest, src, size - 1);
600 dest[size - 1] = '\0';
601
602 return dest;
603 }
604
605 int
lws_timingsafe_bcmp(const void * a,const void * b,uint32_t len)606 lws_timingsafe_bcmp(const void *a, const void *b, uint32_t len)
607 {
608 const uint8_t *pa = a, *pb = b;
609 uint8_t sum = 0;
610
611 while (len--)
612 sum |= (*pa++ ^ *pb++);
613
614 return sum;
615 }
616
617
618 typedef enum {
619 LWS_TOKZS_LEADING_WHITESPACE,
620 LWS_TOKZS_QUOTED_STRING,
621 LWS_TOKZS_TOKEN,
622 LWS_TOKZS_TOKEN_POST_TERMINAL
623 } lws_tokenize_state;
624
625 lws_tokenize_elem
lws_tokenize(struct lws_tokenize * ts)626 lws_tokenize(struct lws_tokenize *ts)
627 {
628 const char *rfc7230_delims = "(),/:;<=>?@[\\]{}";
629 lws_tokenize_state state = LWS_TOKZS_LEADING_WHITESPACE;
630 char c, flo = 0, d_minus = '-', d_dot = '.', s_minus = '\0',
631 s_dot = '\0', skipping = 0;
632 signed char num = (ts->flags & LWS_TOKENIZE_F_NO_INTEGERS) ? 0 : -1;
633 int utf8 = 0;
634
635 /* for speed, compute the effect of the flags outside the loop */
636
637 if (ts->flags & LWS_TOKENIZE_F_MINUS_NONTERM) {
638 d_minus = '\0';
639 s_minus = '-';
640 }
641 if (ts->flags & LWS_TOKENIZE_F_DOT_NONTERM) {
642 d_dot = '\0';
643 s_dot = '.';
644 }
645
646 ts->token = NULL;
647 ts->token_len = 0;
648
649 while (ts->len) {
650 c = *ts->start++;
651 ts->len--;
652
653 utf8 = lws_check_byte_utf8((unsigned char)utf8, c);
654 if (utf8 < 0)
655 return LWS_TOKZE_ERR_BROKEN_UTF8;
656
657 if (!c)
658 break;
659
660 if (skipping) {
661 if (c != '\r' && c != '\n')
662 continue;
663 else
664 skipping = 0;
665 }
666
667 /* comment */
668
669 if (ts->flags & LWS_TOKENIZE_F_HASH_COMMENT &&
670 state != LWS_TOKZS_QUOTED_STRING &&
671 c == '#') {
672 skipping = 1;
673 continue;
674 }
675
676 /* whitespace */
677
678 if (c == ' ' || c == '\t' || c == '\n' || c == '\r' ||
679 c == '\f') {
680 switch (state) {
681 case LWS_TOKZS_LEADING_WHITESPACE:
682 case LWS_TOKZS_TOKEN_POST_TERMINAL:
683 continue;
684 case LWS_TOKZS_QUOTED_STRING:
685 ts->token_len++;
686 continue;
687 case LWS_TOKZS_TOKEN:
688 /* we want to scan forward to look for = */
689
690 state = LWS_TOKZS_TOKEN_POST_TERMINAL;
691 continue;
692 }
693 }
694
695 /* quoted string */
696
697 if (c == '\"') {
698 if (state == LWS_TOKZS_QUOTED_STRING)
699 return LWS_TOKZE_QUOTED_STRING;
700
701 /* starting a quoted string */
702
703 if (ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) {
704 if (ts->delim == LWSTZ_DT_NEED_DELIM)
705 return LWS_TOKZE_ERR_COMMA_LIST;
706 ts->delim = LWSTZ_DT_NEED_DELIM;
707 }
708
709 state = LWS_TOKZS_QUOTED_STRING;
710 ts->token = ts->start;
711 ts->token_len = 0;
712
713 continue;
714 }
715
716 /* token= aggregation */
717
718 if (c == '=' && (state == LWS_TOKZS_TOKEN_POST_TERMINAL ||
719 state == LWS_TOKZS_TOKEN)) {
720 if (num == 1)
721 return LWS_TOKZE_ERR_NUM_ON_LHS;
722 /* swallow the = */
723 return LWS_TOKZE_TOKEN_NAME_EQUALS;
724 }
725
726 /* optional token: aggregation */
727
728 if ((ts->flags & LWS_TOKENIZE_F_AGG_COLON) && c == ':' &&
729 (state == LWS_TOKZS_TOKEN_POST_TERMINAL ||
730 state == LWS_TOKZS_TOKEN))
731 /* swallow the : */
732 return LWS_TOKZE_TOKEN_NAME_COLON;
733
734 /* aggregate . in a number as a float */
735
736 if (c == '.' && !(ts->flags & LWS_TOKENIZE_F_NO_FLOATS) &&
737 state == LWS_TOKZS_TOKEN && num == 1) {
738 if (flo)
739 return LWS_TOKZE_ERR_MALFORMED_FLOAT;
740 flo = 1;
741 ts->token_len++;
742 continue;
743 }
744
745 /*
746 * Delimiter... by default anything that:
747 *
748 * - isn't matched earlier, or
749 * - is [A-Z, a-z, 0-9, _], and
750 * - is not a partial utf8 char
751 *
752 * is a "delimiter", it marks the end of a token and is itself
753 * reported as a single LWS_TOKZE_DELIMITER each time.
754 *
755 * However with LWS_TOKENIZE_F_RFC7230_DELIMS flag, tokens may
756 * contain any noncontrol character that isn't defined in
757 * rfc7230_delims, and only characters listed there are treated
758 * as delimiters.
759 */
760
761 if (!utf8 &&
762 ((ts->flags & LWS_TOKENIZE_F_RFC7230_DELIMS &&
763 strchr(rfc7230_delims, c) && c > 32) ||
764 ((!(ts->flags & LWS_TOKENIZE_F_RFC7230_DELIMS) &&
765 (c < '0' || c > '9') && (c < 'A' || c > 'Z') &&
766 (c < 'a' || c > 'z') && c != '_') &&
767 c != s_minus && c != s_dot) ||
768 c == d_minus || c == d_dot
769 ) &&
770 !((ts->flags & LWS_TOKENIZE_F_SLASH_NONTERM) && c == '/')) {
771 switch (state) {
772 case LWS_TOKZS_LEADING_WHITESPACE:
773 if (ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) {
774 if (c != ',' ||
775 ts->delim != LWSTZ_DT_NEED_DELIM)
776 return LWS_TOKZE_ERR_COMMA_LIST;
777 ts->delim = LWSTZ_DT_NEED_NEXT_CONTENT;
778 }
779
780 ts->token = ts->start - 1;
781 ts->token_len = 1;
782 return LWS_TOKZE_DELIMITER;
783
784 case LWS_TOKZS_QUOTED_STRING:
785 ts->token_len++;
786 continue;
787
788 case LWS_TOKZS_TOKEN_POST_TERMINAL:
789 case LWS_TOKZS_TOKEN:
790 /* report the delimiter next time */
791 ts->start--;
792 ts->len++;
793 goto token_or_numeric;
794 }
795 }
796
797 /* anything that's not whitespace or delimiter is payload */
798
799 switch (state) {
800 case LWS_TOKZS_LEADING_WHITESPACE:
801
802 if (ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) {
803 if (ts->delim == LWSTZ_DT_NEED_DELIM)
804 return LWS_TOKZE_ERR_COMMA_LIST;
805 ts->delim = LWSTZ_DT_NEED_DELIM;
806 }
807
808 state = LWS_TOKZS_TOKEN;
809 ts->token = ts->start - 1;
810 ts->token_len = 1;
811 goto checknum;
812
813 case LWS_TOKZS_QUOTED_STRING:
814 case LWS_TOKZS_TOKEN:
815 ts->token_len++;
816 checknum:
817 if (!(ts->flags & LWS_TOKENIZE_F_NO_INTEGERS)) {
818 if (c < '0' || c > '9')
819 num = 0;
820 else
821 if (num < 0)
822 num = 1;
823 }
824 continue;
825
826 case LWS_TOKZS_TOKEN_POST_TERMINAL:
827 /* report the new token next time */
828 ts->start--;
829 ts->len++;
830 goto token_or_numeric;
831 }
832 }
833
834 /* we ran out of content */
835
836 if (utf8) /* ended partway through a multibyte char */
837 return LWS_TOKZE_ERR_BROKEN_UTF8;
838
839 if (state == LWS_TOKZS_QUOTED_STRING)
840 return LWS_TOKZE_ERR_UNTERM_STRING;
841
842 if (state != LWS_TOKZS_TOKEN_POST_TERMINAL &&
843 state != LWS_TOKZS_TOKEN) {
844 if ((ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) &&
845 ts->delim == LWSTZ_DT_NEED_NEXT_CONTENT)
846 return LWS_TOKZE_ERR_COMMA_LIST;
847
848 return LWS_TOKZE_ENDED;
849 }
850
851 /* report the pending token */
852
853 token_or_numeric:
854
855 if (num != 1)
856 return LWS_TOKZE_TOKEN;
857 if (flo)
858 return LWS_TOKZE_FLOAT;
859
860 return LWS_TOKZE_INTEGER;
861 }
862
863
864 int
lws_tokenize_cstr(struct lws_tokenize * ts,char * str,size_t max)865 lws_tokenize_cstr(struct lws_tokenize *ts, char *str, size_t max)
866 {
867 if (ts->token_len + 1 >= max)
868 return 1;
869
870 memcpy(str, ts->token, ts->token_len);
871 str[ts->token_len] = '\0';
872
873 return 0;
874 }
875
876 void
lws_tokenize_init(struct lws_tokenize * ts,const char * start,int flags)877 lws_tokenize_init(struct lws_tokenize *ts, const char *start, int flags)
878 {
879 ts->start = start;
880 ts->len = 0x7fffffff;
881 ts->flags = flags;
882 ts->delim = LWSTZ_DT_NEED_FIRST_CONTENT;
883 }
884
885
886 typedef enum {
887 LWS_EXPS_LITERAL,
888 LWS_EXPS_OPEN_OR_LIT,
889 LWS_EXPS_NAME_OR_CLOSE,
890 LWS_EXPS_DRAIN,
891 } lws_strexp_state;
892
893 void
lws_strexp_init(lws_strexp_t * exp,void * priv,lws_strexp_expand_cb cb,char * out,size_t olen)894 lws_strexp_init(lws_strexp_t *exp, void *priv, lws_strexp_expand_cb cb,
895 char *out, size_t olen)
896 {
897 memset(exp, 0, sizeof(*exp));
898 exp->cb = cb;
899 exp->out = out;
900 exp->olen = olen;
901 exp->state = LWS_EXPS_LITERAL;
902 exp->priv = priv;
903 }
904
905 void
lws_strexp_reset_out(lws_strexp_t * exp,char * out,size_t olen)906 lws_strexp_reset_out(lws_strexp_t *exp, char *out, size_t olen)
907 {
908 exp->out = out;
909 exp->olen = olen;
910 exp->pos = 0;
911 }
912
913 int
lws_strexp_expand(lws_strexp_t * exp,const char * in,size_t len,size_t * pused_in,size_t * pused_out)914 lws_strexp_expand(lws_strexp_t *exp, const char *in, size_t len,
915 size_t *pused_in, size_t *pused_out)
916 {
917 size_t used = 0;
918 int n;
919
920 while (used < len) {
921
922 switch (exp->state) {
923 case LWS_EXPS_LITERAL:
924 if (*in == '$') {
925 exp->state = LWS_EXPS_OPEN_OR_LIT;
926 break;
927 }
928
929 exp->out[exp->pos++] = *in;
930 if (exp->olen - exp->pos < 1) {
931 *pused_in = used + 1;
932 *pused_out = exp->pos;
933 return LSTRX_FILLED_OUT;
934 }
935 break;
936
937 case LWS_EXPS_OPEN_OR_LIT:
938 if (*in == '{') {
939 exp->state = LWS_EXPS_NAME_OR_CLOSE;
940 exp->name_pos = 0;
941 break;
942 }
943 /* treat as a literal */
944 if (exp->olen - exp->pos < 3)
945 return -1;
946
947 exp->out[exp->pos++] = '$';
948 exp->out[exp->pos++] = *in;
949 if (*in != '$')
950 exp->state = LWS_EXPS_LITERAL;
951 break;
952
953 case LWS_EXPS_NAME_OR_CLOSE:
954 if (*in == '}') {
955 exp->name[exp->name_pos] = '\0';
956 exp->state = LWS_EXPS_DRAIN;
957 goto drain;
958 }
959 if (exp->name_pos >= sizeof(exp->name) - 1)
960 return LSTRX_FATAL_NAME_TOO_LONG;
961
962 exp->name[exp->name_pos++] = *in;
963 break;
964
965 case LWS_EXPS_DRAIN:
966 drain:
967 *pused_in = used;
968 n = exp->cb(exp->priv, exp->name, exp->out, &exp->pos,
969 exp->olen, &exp->exp_ofs);
970 *pused_out = exp->pos;
971 if (n == LSTRX_FILLED_OUT ||
972 n == LSTRX_FATAL_NAME_UNKNOWN)
973 return n;
974
975 exp->state = LWS_EXPS_LITERAL;
976 break;
977 }
978
979 used++;
980 in++;
981 }
982
983 exp->out[exp->pos] = '\0';
984 *pused_in = used;
985 *pused_out = exp->pos;
986
987 return LSTRX_DONE;
988 }
989
990
991 #if LWS_MAX_SMP > 1
992
993 void
lws_mutex_refcount_init(struct lws_mutex_refcount * mr)994 lws_mutex_refcount_init(struct lws_mutex_refcount *mr)
995 {
996 pthread_mutex_init(&mr->lock, NULL);
997 mr->last_lock_reason = NULL;
998 mr->lock_depth = 0;
999 mr->metadata = 0;
1000 mr->lock_owner = 0;
1001 }
1002
1003 void
lws_mutex_refcount_destroy(struct lws_mutex_refcount * mr)1004 lws_mutex_refcount_destroy(struct lws_mutex_refcount *mr)
1005 {
1006 pthread_mutex_destroy(&mr->lock);
1007 }
1008
1009 void
lws_mutex_refcount_lock(struct lws_mutex_refcount * mr,const char * reason)1010 lws_mutex_refcount_lock(struct lws_mutex_refcount *mr, const char *reason)
1011 {
1012 /* if true, this sequence is atomic because our thread has the lock
1013 *
1014 * - if true, only guy who can race to make it untrue is our thread,
1015 * and we are here.
1016 *
1017 * - if false, only guy who could race to make it true is our thread,
1018 * and we are here
1019 *
1020 * - it can be false and change to a different tid that is also false
1021 */
1022 if (mr->lock_owner == pthread_self()) {
1023 /* atomic because we only change it if we own the lock */
1024 mr->lock_depth++;
1025 return;
1026 }
1027
1028 pthread_mutex_lock(&mr->lock);
1029 /* atomic because only we can have the lock */
1030 mr->last_lock_reason = reason;
1031 mr->lock_owner = pthread_self();
1032 mr->lock_depth = 1;
1033 //lwsl_notice("tid %d: lock %s\n", mr->tid, reason);
1034 }
1035
1036 void
lws_mutex_refcount_unlock(struct lws_mutex_refcount * mr)1037 lws_mutex_refcount_unlock(struct lws_mutex_refcount *mr)
1038 {
1039 if (--mr->lock_depth)
1040 /* atomic because only thread that has the lock can unlock */
1041 return;
1042
1043 mr->last_lock_reason = "free";
1044 mr->lock_owner = 0;
1045 //lwsl_notice("tid %d: unlock %s\n", mr->tid, mr->last_lock_reason);
1046 pthread_mutex_unlock(&mr->lock);
1047 }
1048
1049 #endif /* SMP */
1050
1051
1052 const char *
lws_cmdline_option(int argc,const char ** argv,const char * val)1053 lws_cmdline_option(int argc, const char **argv, const char *val)
1054 {
1055 int n = (int)strlen(val), c = argc;
1056
1057 while (--c > 0) {
1058
1059 if (!strncmp(argv[c], val, n)) {
1060 if (!*(argv[c] + n) && c < argc - 1) {
1061 /* coverity treats unchecked argv as "tainted" */
1062 if (!argv[c + 1] || strlen(argv[c + 1]) > 1024)
1063 return NULL;
1064 return argv[c + 1];
1065 }
1066
1067 if (argv[c][n] == '=')
1068 return &argv[c][n + 1];
1069 return argv[c] + n;
1070 }
1071 }
1072
1073 return NULL;
1074 }
1075
1076 static const char * const builtins[] = {
1077 "-d",
1078 "--udp-tx-loss",
1079 "--udp-rx-loss"
1080 };
1081
1082 void
lws_cmdline_option_handle_builtin(int argc,const char ** argv,struct lws_context_creation_info * info)1083 lws_cmdline_option_handle_builtin(int argc, const char **argv,
1084 struct lws_context_creation_info *info)
1085 {
1086 const char *p;
1087 int n, m, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
1088
1089 for (n = 0; n < (int)LWS_ARRAY_SIZE(builtins); n++) {
1090 p = lws_cmdline_option(argc, argv, builtins[n]);
1091 if (!p)
1092 continue;
1093
1094 m = atoi(p);
1095
1096 switch (n) {
1097 case 0:
1098 logs = m;
1099 break;
1100 case 1:
1101 info->udp_loss_sim_tx_pc = m;
1102 break;
1103 case 2:
1104 info->udp_loss_sim_rx_pc = m;
1105 break;
1106 }
1107 }
1108
1109 lws_set_log_level(logs, NULL);
1110 }
1111
1112
1113 const lws_humanize_unit_t humanize_schema_si[] = {
1114 { "Pi ", LWS_PI }, { "Ti ", LWS_TI }, { "Gi ", LWS_GI },
1115 { "Mi ", LWS_MI }, { "Ki ", LWS_KI }, { " ", 1 },
1116 { NULL, 0 }
1117 };
1118 const lws_humanize_unit_t humanize_schema_si_bytes[] = {
1119 { "PiB", LWS_PI }, { "TiB", LWS_TI }, { "GiB", LWS_GI },
1120 { "MiB", LWS_MI }, { "KiB", LWS_KI }, { "B ", 1 },
1121 { NULL, 0 }
1122 };
1123 const lws_humanize_unit_t humanize_schema_us[] = {
1124 { "y ", (uint64_t)365 * 24 * 3600 * LWS_US_PER_SEC },
1125 { "d ", (uint64_t)24 * 3600 * LWS_US_PER_SEC },
1126 { "hr ", (uint64_t)3600 * LWS_US_PER_SEC },
1127 { "min", 60 * LWS_US_PER_SEC },
1128 { "s ", LWS_US_PER_SEC },
1129 { "ms ", LWS_US_PER_MS },
1130 { "us ", 1 },
1131 { NULL, 0 }
1132 };
1133
1134 static int
decim(char * r,uint64_t v,char chars,char leading)1135 decim(char *r, uint64_t v, char chars, char leading)
1136 {
1137 int n = chars - 1;
1138 uint64_t q = 1;
1139
1140 r += n;
1141
1142 while (n >= 0) {
1143 if (v / q)
1144 *r-- = '0' + ((v / q) % 10);
1145 else
1146 *r-- = leading ? '0' : ' ';
1147 q = q * 10;
1148 n--;
1149 }
1150
1151 if (v / q)
1152 /* the number is bigger than the allowed chars! */
1153 r[1] = '!';
1154
1155 return chars;
1156 }
1157
1158 int
lws_humanize(char * p,int len,uint64_t v,const lws_humanize_unit_t * schema)1159 lws_humanize(char *p, int len, uint64_t v, const lws_humanize_unit_t *schema)
1160 {
1161 char *end = p + len;
1162
1163 do {
1164 if (v >= schema->factor || schema->factor == 1) {
1165 if (schema->factor == 1) {
1166 *p++ = ' ';
1167 p += decim(p, v, 4, 0);
1168 return lws_snprintf(p, lws_ptr_diff(end, p),
1169 "%s ", schema->name);
1170 }
1171
1172 *p++ = ' ';
1173 p += decim(p, v / schema->factor, 4, 0);
1174 *p++ = '.';
1175 p += decim(p, (v % schema->factor) /
1176 (schema->factor / 1000), 3, 1);
1177
1178 return lws_snprintf(p, lws_ptr_diff(end, p),
1179 "%s", schema->name);
1180 }
1181 schema++;
1182 } while (schema->name);
1183
1184 assert(0);
1185 strncpy(p, "unknown value", len);
1186
1187 return 0;
1188 }
1189