• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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