2 * libwebsockets - small server side websockets and web server implementation
4 * Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation:
9 * version 2.1 of the License.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 #include "core/private.h"
24 #ifdef LWS_HAVE_SYS_TYPES_H
25 #include <sys/types.h>
28 signed char char_to_hex(const char c)
30 if (c >= '0' && c <= '9')
33 if (c >= 'a' && c <= 'f')
36 if (c >= 'A' && c <= 'F')
43 lws_hex_to_byte_array(const char *h, uint8_t *dest, int max)
45 uint8_t *odest = dest;
48 int t = char_to_hex(*h++), t1;
53 t1 = char_to_hex(*h++);
57 *dest++ = (t << 4) | t1;
67 #if !defined(LWS_PLAT_OPTEE)
69 #if !defined(LWS_AMAZON_RTOS)
70 int lws_open(const char *__file, int __oflag, ...)
75 va_start(ap, __oflag);
76 if (((__oflag & O_CREAT) == O_CREAT)
77 #if defined(O_TMPFILE)
78 || ((__oflag & O_TMPFILE) == O_TMPFILE)
81 /* last arg is really a mode_t. But windows... */
82 n = open(__file, __oflag, va_arg(ap, uint32_t));
84 n = open(__file, __oflag);
87 if (n != -1 && lws_plat_apply_FD_CLOEXEC(n)) {
99 lws_pthread_self_to_tsi(struct lws_context *context)
102 pthread_t ps = pthread_self();
103 struct lws_context_per_thread *pt = &context->pt[0];
106 for (n = 0; n < context->count_threads; n++) {
107 if (pthread_equal(ps, pt->self))
119 lws_context_user(struct lws_context *context)
121 return context->user_space;
125 lws_explicit_bzero(void *p, size_t len)
127 volatile uint8_t *vp = p;
133 #if !(defined(LWS_PLAT_OPTEE) && !defined(LWS_WITH_NETWORK))
136 * lws_now_secs() - seconds since 1970-1-1
139 LWS_VISIBLE LWS_EXTERN unsigned long
144 gettimeofday(&tv, NULL);
150 LWS_VISIBLE extern const char *
151 lws_canonical_hostname(struct lws_context *context)
153 return (const char *)context->canonical_hostname;
156 #if defined(LWS_WITH_SOCKS5)
158 lws_set_socks(struct lws_vhost *vhost, const char *socks)
160 char *p_at, *p_colon;
167 vhost->socks_user[0] = '\0';
168 vhost->socks_password[0] = '\0';
170 p_at = strrchr(socks, '@');
171 if (p_at) { /* auth is around */
172 if ((unsigned int)(p_at - socks) > (sizeof(user)
173 + sizeof(password) - 2)) {
174 lwsl_err("Socks auth too long\n");
178 p_colon = strchr(socks, ':');
180 if ((unsigned int)(p_colon - socks) > (sizeof(user)
182 lwsl_err("Socks user too long\n");
185 if ((unsigned int)(p_at - p_colon) > (sizeof(password)
187 lwsl_err("Socks password too long\n");
191 lws_strncpy(vhost->socks_user, socks, p_colon - socks + 1);
192 lws_strncpy(vhost->socks_password, p_colon + 1,
193 p_at - (p_colon + 1) + 1);
196 lwsl_info(" Socks auth, user: %s, password: %s\n",
197 vhost->socks_user, vhost->socks_password );
202 lws_strncpy(vhost->socks_proxy_address, socks,
203 sizeof(vhost->socks_proxy_address));
205 p_colon = strchr(vhost->socks_proxy_address, ':');
206 if (!p_colon && !vhost->socks_proxy_port) {
207 lwsl_err("socks_proxy needs to be address:port\n");
212 vhost->socks_proxy_port = atoi(p_colon + 1);
216 lwsl_info(" Socks %s:%u\n", vhost->socks_proxy_address,
217 vhost->socks_proxy_port);
228 LWS_VISIBLE LWS_EXTERN int
229 lws_get_count_threads(struct lws_context *context)
231 return context->count_threads;
234 static const unsigned char e0f4[] = {
235 0xa0 | ((2 - 1) << 2) | 1, /* e0 */
236 0x80 | ((4 - 1) << 2) | 1, /* e1 */
237 0x80 | ((4 - 1) << 2) | 1, /* e2 */
238 0x80 | ((4 - 1) << 2) | 1, /* e3 */
239 0x80 | ((4 - 1) << 2) | 1, /* e4 */
240 0x80 | ((4 - 1) << 2) | 1, /* e5 */
241 0x80 | ((4 - 1) << 2) | 1, /* e6 */
242 0x80 | ((4 - 1) << 2) | 1, /* e7 */
243 0x80 | ((4 - 1) << 2) | 1, /* e8 */
244 0x80 | ((4 - 1) << 2) | 1, /* e9 */
245 0x80 | ((4 - 1) << 2) | 1, /* ea */
246 0x80 | ((4 - 1) << 2) | 1, /* eb */
247 0x80 | ((4 - 1) << 2) | 1, /* ec */
248 0x80 | ((2 - 1) << 2) | 1, /* ed */
249 0x80 | ((4 - 1) << 2) | 1, /* ee */
250 0x80 | ((4 - 1) << 2) | 1, /* ef */
251 0x90 | ((3 - 1) << 2) | 2, /* f0 */
252 0x80 | ((4 - 1) << 2) | 2, /* f1 */
253 0x80 | ((4 - 1) << 2) | 2, /* f2 */
254 0x80 | ((4 - 1) << 2) | 2, /* f3 */
255 0x80 | ((1 - 1) << 2) | 2, /* f4 */
258 0x80 | ((4 - 1) << 2) | 0, /* s2 */
259 0x80 | ((4 - 1) << 2) | 1, /* s3 */
263 lws_check_byte_utf8(unsigned char state, unsigned char c)
265 unsigned char s = state;
269 if (c < 0xc2 || c > 0xf4)
272 return 0x80 | ((4 - 1) << 2);
274 return e0f4[c - 0xe0];
279 if (c < (s & 0xf0) || c >= (s & 0xf0) + 0x10 + ((s << 2) & 0x30))
282 return e0f4[21 + (s & 3)];
286 lws_check_utf8(unsigned char *state, unsigned char *buf, size_t len)
288 unsigned char s = *state;
291 unsigned char c = *buf++;
295 if (c < 0xc2 || c > 0xf4)
298 s = 0x80 | ((4 - 1) << 2);
303 if (c < (s & 0xf0) ||
304 c >= (s & 0xf0) + 0x10 + ((s << 2) & 0x30))
306 s = e0f4[21 + (s & 3)];
317 lws_strdup(const char *s)
319 char *d = lws_malloc(strlen(s) + 1, "strdup");
327 static const char *hex = "0123456789ABCDEF";
329 LWS_VISIBLE LWS_EXTERN const char *
330 lws_sql_purify(char *escaped, const char *string, int len)
332 const char *p = string;
335 while (*p && len-- > 2) {
349 LWS_VISIBLE LWS_EXTERN const char *
350 lws_json_purify(char *escaped, const char *string, int len)
352 const char *p = string;
360 while (*p && len-- > 6) {
382 if (*p == '\"' || *p == '\\' || *p < 0x20) {
387 *q++ = hex[((*p) >> 4) & 15];
388 *q++ = hex[(*p) & 15];
399 LWS_VISIBLE LWS_EXTERN void
400 lws_filename_purify_inplace(char *filename)
404 if (*filename == '.' && filename[1] == '.') {
409 if (*filename == ':' ||
419 LWS_VISIBLE LWS_EXTERN const char *
420 lws_urlencode(char *escaped, const char *string, int len)
422 const char *p = string;
425 while (*p && len-- > 3) {
431 if ((*p >= '0' && *p <= '9') ||
432 (*p >= 'A' && *p <= 'Z') ||
433 (*p >= 'a' && *p <= 'z')) {
438 *q++ = hex[(*p >> 4) & 0xf];
439 *q++ = hex[*p & 0xf];
449 LWS_VISIBLE LWS_EXTERN int
450 lws_urldecode(char *string, const char *escaped, int len)
455 while (*escaped && len) {
458 if (*escaped == '%') {
463 if (*escaped == '+') {
469 *string++ = *escaped++;
473 n = char_to_hex(*escaped);
482 n = char_to_hex(*escaped);
498 LWS_VISIBLE LWS_EXTERN int
499 lws_finalize_startup(struct lws_context *context)
501 if (lws_check_opt(context->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
502 if (lws_plat_drop_app_privileges(context, 1))
508 LWS_VISIBLE LWS_EXTERN void
509 lws_get_effective_uid_gid(struct lws_context *context, int *uid, int *gid)
516 lws_snprintf(char *str, size_t size, const char *format, ...)
524 va_start(ap, format);
525 n = vsnprintf(str, size, format, ap);
535 lws_strncpy(char *dest, const char *src, size_t size)
537 strncpy(dest, src, size - 1);
538 dest[size - 1] = '\0';
544 lws_timingsafe_bcmp(const void *a, const void *b, uint32_t len)
546 const uint8_t *pa = a, *pb = b;
550 sum |= (*pa++ ^ *pb++);
557 LWS_TOKZS_LEADING_WHITESPACE,
558 LWS_TOKZS_QUOTED_STRING,
560 LWS_TOKZS_TOKEN_POST_TERMINAL
561 } lws_tokenize_state;
563 #if defined(LWS_AMAZON_RTOS)
568 lws_tokenize(struct lws_tokenize *ts)
570 const char *rfc7230_delims = "(),/:;<=>?@[\\]{}";
571 lws_tokenize_state state = LWS_TOKZS_LEADING_WHITESPACE;
572 char c, flo = 0, d_minus = '-', d_dot = '.', s_minus = '\0',
574 signed char num = ts->flags & LWS_TOKENIZE_F_NO_INTEGERS ? 0 : -1;
577 /* for speed, compute the effect of the flags outside the loop */
579 if (ts->flags & LWS_TOKENIZE_F_MINUS_NONTERM) {
583 if (ts->flags & LWS_TOKENIZE_F_DOT_NONTERM) {
595 utf8 = lws_check_byte_utf8((unsigned char)utf8, c);
597 return LWS_TOKZE_ERR_BROKEN_UTF8;
604 if (c == ' ' || c == '\t' || c == '\n' || c == '\r' ||
607 case LWS_TOKZS_LEADING_WHITESPACE:
608 case LWS_TOKZS_TOKEN_POST_TERMINAL:
610 case LWS_TOKZS_QUOTED_STRING:
613 case LWS_TOKZS_TOKEN:
614 /* we want to scan forward to look for = */
616 state = LWS_TOKZS_TOKEN_POST_TERMINAL;
624 if (state == LWS_TOKZS_QUOTED_STRING)
625 return LWS_TOKZE_QUOTED_STRING;
627 /* starting a quoted string */
629 if (ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) {
630 if (ts->delim == LWSTZ_DT_NEED_DELIM)
631 return LWS_TOKZE_ERR_COMMA_LIST;
632 ts->delim = LWSTZ_DT_NEED_DELIM;
635 state = LWS_TOKZS_QUOTED_STRING;
636 ts->token = ts->start;
642 /* token= aggregation */
644 if (c == '=' && (state == LWS_TOKZS_TOKEN_POST_TERMINAL ||
645 state == LWS_TOKZS_TOKEN)) {
647 return LWS_TOKZE_ERR_NUM_ON_LHS;
649 return LWS_TOKZE_TOKEN_NAME_EQUALS;
652 /* optional token: aggregation */
654 if ((ts->flags & LWS_TOKENIZE_F_AGG_COLON) && c == ':' &&
655 (state == LWS_TOKZS_TOKEN_POST_TERMINAL ||
656 state == LWS_TOKZS_TOKEN))
658 return LWS_TOKZE_TOKEN_NAME_COLON;
660 /* aggregate . in a number as a float */
662 if (c == '.' && !(ts->flags & LWS_TOKENIZE_F_NO_FLOATS) &&
663 state == LWS_TOKZS_TOKEN && num == 1) {
665 return LWS_TOKZE_ERR_MALFORMED_FLOAT;
672 * Delimiter... by default anything that:
674 * - isn't matched earlier, or
675 * - is [A-Z, a-z, 0-9, _], and
676 * - is not a partial utf8 char
678 * is a "delimiter", it marks the end of a token and is itself
679 * reported as a single LWS_TOKZE_DELIMITER each time.
681 * However with LWS_TOKENIZE_F_RFC7230_DELIMS flag, tokens may
682 * contain any noncontrol character that isn't defined in
683 * rfc7230_delims, and only characters listed there are treated
688 ((ts->flags & LWS_TOKENIZE_F_RFC7230_DELIMS &&
689 strchr(rfc7230_delims, c) && c > 32) ||
690 ((!(ts->flags & LWS_TOKENIZE_F_RFC7230_DELIMS) &&
691 (c < '0' || c > '9') && (c < 'A' || c > 'Z') &&
692 (c < 'a' || c > 'z') && c != '_') &&
693 c != s_minus && c != s_dot) ||
694 c == d_minus || c == d_dot
697 case LWS_TOKZS_LEADING_WHITESPACE:
698 if (ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) {
700 ts->delim != LWSTZ_DT_NEED_DELIM)
701 return LWS_TOKZE_ERR_COMMA_LIST;
702 ts->delim = LWSTZ_DT_NEED_NEXT_CONTENT;
705 ts->token = ts->start - 1;
707 return LWS_TOKZE_DELIMITER;
709 case LWS_TOKZS_QUOTED_STRING:
713 case LWS_TOKZS_TOKEN_POST_TERMINAL:
714 case LWS_TOKZS_TOKEN:
715 /* report the delimiter next time */
718 goto token_or_numeric;
722 /* anything that's not whitespace or delimiter is payload */
725 case LWS_TOKZS_LEADING_WHITESPACE:
727 if (ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) {
728 if (ts->delim == LWSTZ_DT_NEED_DELIM)
729 return LWS_TOKZE_ERR_COMMA_LIST;
730 ts->delim = LWSTZ_DT_NEED_DELIM;
733 state = LWS_TOKZS_TOKEN;
734 ts->token = ts->start - 1;
738 case LWS_TOKZS_QUOTED_STRING:
739 case LWS_TOKZS_TOKEN:
742 if (!(ts->flags & LWS_TOKENIZE_F_NO_INTEGERS)) {
743 if (c < '0' || c > '9')
751 case LWS_TOKZS_TOKEN_POST_TERMINAL:
752 /* report the new token next time */
755 goto token_or_numeric;
759 /* we ran out of content */
761 if (utf8) /* ended partway through a multibyte char */
762 return LWS_TOKZE_ERR_BROKEN_UTF8;
764 if (state == LWS_TOKZS_QUOTED_STRING)
765 return LWS_TOKZE_ERR_UNTERM_STRING;
767 if (state != LWS_TOKZS_TOKEN_POST_TERMINAL &&
768 state != LWS_TOKZS_TOKEN) {
769 if ((ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) &&
770 ts->delim == LWSTZ_DT_NEED_NEXT_CONTENT)
771 return LWS_TOKZE_ERR_COMMA_LIST;
773 return LWS_TOKZE_ENDED;
776 /* report the pending token */
781 return LWS_TOKZE_TOKEN;
783 return LWS_TOKZE_FLOAT;
785 return LWS_TOKZE_INTEGER;
789 LWS_VISIBLE LWS_EXTERN int
790 lws_tokenize_cstr(struct lws_tokenize *ts, char *str, int max)
792 if (ts->token_len + 1 >= max)
795 memcpy(str, ts->token, ts->token_len);
796 str[ts->token_len] = '\0';
801 LWS_VISIBLE LWS_EXTERN void
802 lws_tokenize_init(struct lws_tokenize *ts, const char *start, int flags)
805 ts->len = 0x7fffffff;
807 ts->delim = LWSTZ_DT_NEED_FIRST_CONTENT;
813 lws_mutex_refcount_init(struct lws_mutex_refcount *mr)
815 pthread_mutex_init(&mr->lock, NULL);
816 mr->last_lock_reason = NULL;
823 lws_mutex_refcount_destroy(struct lws_mutex_refcount *mr)
825 pthread_mutex_destroy(&mr->lock);
829 lws_mutex_refcount_lock(struct lws_mutex_refcount *mr, const char *reason)
831 /* if true, this sequence is atomic because our thread has the lock
833 * - if true, only guy who can race to make it untrue is our thread,
836 * - if false, only guy who could race to make it true is our thread,
839 * - it can be false and change to a different tid that is also false
841 if (mr->lock_owner == pthread_self()) {
842 /* atomic because we only change it if we own the lock */
847 pthread_mutex_lock(&mr->lock);
848 /* atomic because only we can have the lock */
849 mr->last_lock_reason = reason;
850 mr->lock_owner = pthread_self();
852 //lwsl_notice("tid %d: lock %s\n", mr->tid, reason);
856 lws_mutex_refcount_unlock(struct lws_mutex_refcount *mr)
858 if (--mr->lock_depth)
859 /* atomic because only thread that has the lock can unlock */
862 mr->last_lock_reason = "free";
864 //lwsl_notice("tid %d: unlock %s\n", mr->tid, mr->last_lock_reason);
865 pthread_mutex_unlock(&mr->lock);
872 lws_cmdline_option(int argc, const char **argv, const char *val)
874 int n = (int)strlen(val), c = argc;
878 if (!strncmp(argv[c], val, n)) {
879 if (!*(argv[c] + n) && c < argc - 1) {
880 /* coverity treats unchecked argv as "tainted" */
881 if (!argv[c + 1] || strlen(argv[c + 1]) > 1024)
894 const lws_humanize_unit_t humanize_schema_si[] = {
895 { "Pi ", LWS_PI }, { "Ti ", LWS_TI }, { "Gi ", LWS_GI },
896 { "Mi ", LWS_MI }, { "Ki ", LWS_KI }, { " ", 1 },
899 const lws_humanize_unit_t humanize_schema_si_bytes[] = {
900 { "PiB", LWS_PI }, { "TiB", LWS_TI }, { "GiB", LWS_GI },
901 { "MiB", LWS_MI }, { "KiB", LWS_KI }, { "B ", 1 },
904 const lws_humanize_unit_t humanize_schema_us[] = {
905 { "y ", (uint64_t)365 * 24 * 3600 * LWS_US_PER_SEC },
906 { "d ", (uint64_t)24 * 3600 * LWS_US_PER_SEC },
907 { "hr ", (uint64_t)3600 * LWS_US_PER_SEC },
908 { "min", 60 * LWS_US_PER_SEC },
909 { "s ", LWS_US_PER_SEC },
910 { "ms ", LWS_US_PER_MS },
916 lws_humanize(char *p, int len, uint64_t v, const lws_humanize_unit_t *schema)
919 if (v >= schema->factor || schema->factor == 1) {
920 if (schema->factor == 1)
921 return lws_snprintf(p, len,
923 v / schema->factor, schema->name);
925 return lws_snprintf(p, len, " %4"PRIu64".%03"PRIu64"%s",
927 (v % schema->factor) / (schema->factor / 1000),
931 } while (schema->name);
939 lws_system_get_info(struct lws_context *context, lws_system_item_t item,
940 lws_system_arg_t arg, size_t *len)
942 if (!context->system_ops || !context->system_ops->get_info)
945 return context->system_ops->get_info(item, arg, len);
949 lws_system_reboot(struct lws_context *context)
951 if (!context->system_ops || !context->system_ops->reboot)
954 return context->system_ops->reboot();