2011-03-07 17:54:06 +00:00
|
|
|
/*
|
2010-11-08 17:12:19 +00:00
|
|
|
* libwebsockets - small server side websockets and web server implementation
|
2010-12-19 22:13:26 +00:00
|
|
|
*
|
2020-02-21 07:52:45 +00:00
|
|
|
* Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
|
2010-11-08 17:12:19 +00:00
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to
|
|
|
|
* deal in the Software without restriction, including without limitation the
|
|
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
2010-11-08 17:12:19 +00:00
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
2010-11-08 17:12:19 +00:00
|
|
|
*
|
2019-08-14 10:44:14 +01:00
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
|
* IN THE SOFTWARE.
|
2010-10-31 17:51:39 +00:00
|
|
|
*/
|
|
|
|
|
2019-08-15 10:49:52 +01:00
|
|
|
#include "private-lib-core.h"
|
2016-02-29 18:48:55 +08:00
|
|
|
|
|
|
|
#ifdef LWS_HAVE_SYS_TYPES_H
|
2016-02-21 21:25:48 +08:00
|
|
|
#include <sys/types.h>
|
2016-02-29 18:48:55 +08:00
|
|
|
#endif
|
2020-04-14 19:04:13 +01:00
|
|
|
#include <signal.h>
|
2016-02-29 18:48:55 +08:00
|
|
|
|
2019-08-23 15:30:20 +01:00
|
|
|
void
|
|
|
|
lws_ser_wu16be(uint8_t *b, uint16_t u)
|
|
|
|
{
|
|
|
|
*b++ = (uint8_t)(u >> 8);
|
|
|
|
*b = (uint8_t)u;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
lws_ser_wu32be(uint8_t *b, uint32_t u32)
|
|
|
|
{
|
|
|
|
*b++ = (uint8_t)(u32 >> 24);
|
|
|
|
*b++ = (uint8_t)(u32 >> 16);
|
|
|
|
*b++ = (uint8_t)(u32 >> 8);
|
|
|
|
*b = (uint8_t)u32;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
lws_ser_wu64be(uint8_t *b, uint64_t u64)
|
|
|
|
{
|
|
|
|
lws_ser_wu32be(b, (uint32_t)(u64 >> 32));
|
|
|
|
lws_ser_wu32be(b + 4, (uint32_t)u64);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t
|
|
|
|
lws_ser_ru16be(const uint8_t *b)
|
|
|
|
{
|
2020-12-12 06:21:40 +00:00
|
|
|
return (uint16_t)((b[0] << 8) | b[1]);
|
2019-08-23 15:30:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t
|
|
|
|
lws_ser_ru32be(const uint8_t *b)
|
|
|
|
{
|
2020-12-12 06:21:40 +00:00
|
|
|
return (unsigned int)((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]);
|
2019-08-23 15:30:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t
|
|
|
|
lws_ser_ru64be(const uint8_t *b)
|
|
|
|
{
|
|
|
|
return (((uint64_t)lws_ser_ru32be(b)) << 32) | lws_ser_ru32be(b + 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
lws_vbi_encode(uint64_t value, void *buf)
|
|
|
|
{
|
|
|
|
uint8_t *p = (uint8_t *)buf, b;
|
|
|
|
|
|
|
|
if (value > 0xfffffff) {
|
|
|
|
assert(0);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
|
|
|
b = value & 0x7f;
|
|
|
|
value >>= 7;
|
|
|
|
if (value)
|
|
|
|
*p++ = (0x80 | b);
|
|
|
|
else
|
|
|
|
*p++ = b;
|
|
|
|
} while (value);
|
|
|
|
|
2020-01-11 14:04:50 +00:00
|
|
|
return lws_ptr_diff(p, buf);
|
2019-08-23 15:30:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
lws_vbi_decode(const void *buf, uint64_t *value, size_t len)
|
|
|
|
{
|
|
|
|
const uint8_t *p = (const uint8_t *)buf, *end = p + len;
|
|
|
|
uint64_t v = 0;
|
|
|
|
int s = 0;
|
|
|
|
|
|
|
|
while (p < end) {
|
|
|
|
v |= (((uint64_t)(*p)) & 0x7f) << s;
|
|
|
|
if (*p & 0x80) {
|
|
|
|
*value = v;
|
|
|
|
|
|
|
|
return lws_ptr_diff(p, buf);
|
|
|
|
}
|
|
|
|
s += 7;
|
|
|
|
if (s >= 64)
|
|
|
|
return 0;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-04-27 19:16:50 +08:00
|
|
|
signed char char_to_hex(const char c)
|
|
|
|
{
|
|
|
|
if (c >= '0' && c <= '9')
|
2020-12-12 06:21:40 +00:00
|
|
|
return (signed char)(c - '0');
|
2018-04-27 19:16:50 +08:00
|
|
|
|
|
|
|
if (c >= 'a' && c <= 'f')
|
2020-12-12 06:21:40 +00:00
|
|
|
return (signed char)(c - 'a' + 10);
|
2018-04-27 19:16:50 +08:00
|
|
|
|
|
|
|
if (c >= 'A' && c <= 'F')
|
2020-12-12 06:21:40 +00:00
|
|
|
return (signed char)(c - 'A' + 10);
|
2018-04-27 19:16:50 +08:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
return (signed char)-1;
|
2018-04-27 19:16:50 +08:00
|
|
|
}
|
2019-03-23 12:41:29 +08:00
|
|
|
|
|
|
|
int
|
|
|
|
lws_hex_to_byte_array(const char *h, uint8_t *dest, int max)
|
|
|
|
{
|
|
|
|
uint8_t *odest = dest;
|
|
|
|
|
|
|
|
while (max-- && *h) {
|
|
|
|
int t = char_to_hex(*h++), t1;
|
|
|
|
|
|
|
|
if (!*h || t < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
t1 = char_to_hex(*h++);
|
|
|
|
if (t1 < 0)
|
|
|
|
return -1;
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
*dest++ = (uint8_t)((t << 4) | t1);
|
2019-03-23 12:41:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (max < 0)
|
|
|
|
return -1;
|
|
|
|
|
2019-10-21 23:56:32 +00:00
|
|
|
return lws_ptr_diff(dest, odest);
|
2019-03-23 12:41:29 +08:00
|
|
|
}
|
|
|
|
|
2020-07-11 07:16:16 +01:00
|
|
|
static char *hexch = "0123456789abcdef";
|
|
|
|
|
2021-03-20 16:33:29 +00:00
|
|
|
void
|
|
|
|
lws_hex_from_byte_array(const uint8_t *src, size_t slen, char *dest, size_t len)
|
|
|
|
{
|
|
|
|
char *end = &dest[len - 1];
|
|
|
|
|
|
|
|
while (slen-- && dest != end) {
|
|
|
|
uint8_t b = *src++;
|
|
|
|
*dest++ = hexch[b >> 4];
|
|
|
|
if (dest == end)
|
|
|
|
break;
|
|
|
|
*dest++ = hexch[b & 0xf];
|
|
|
|
}
|
|
|
|
|
|
|
|
*dest = '\0';
|
|
|
|
}
|
|
|
|
|
2020-07-11 07:16:16 +01:00
|
|
|
int
|
|
|
|
lws_hex_random(struct lws_context *context, char *dest, size_t len)
|
|
|
|
{
|
2021-03-02 16:34:33 +00:00
|
|
|
size_t n = ((len - 1) / 2) + 1;
|
2020-07-11 07:16:16 +01:00
|
|
|
uint8_t b, *r = (uint8_t *)dest + len - n;
|
|
|
|
|
|
|
|
if (lws_get_random(context, r, n) != n)
|
|
|
|
return 1;
|
|
|
|
|
2021-03-02 16:34:33 +00:00
|
|
|
while (len >= 3) {
|
2020-07-11 07:16:16 +01:00
|
|
|
b = *r++;
|
|
|
|
*dest++ = hexch[b >> 4];
|
|
|
|
*dest++ = hexch[b & 0xf];
|
2021-03-02 16:34:33 +00:00
|
|
|
len -= 2;
|
2020-07-11 07:16:16 +01:00
|
|
|
}
|
|
|
|
|
2021-03-02 16:34:33 +00:00
|
|
|
if (len == 2)
|
|
|
|
*dest++ = hexch[(*r) >> 4];
|
|
|
|
|
2020-07-11 07:16:16 +01:00
|
|
|
*dest = '\0';
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2019-03-23 12:41:29 +08:00
|
|
|
|
2019-01-15 06:59:48 +08:00
|
|
|
#if !defined(LWS_PLAT_OPTEE)
|
2018-04-27 19:16:50 +08:00
|
|
|
|
2019-08-18 10:35:43 +01:00
|
|
|
#if defined(LWS_WITH_FILE_OPS)
|
2018-06-23 12:56:21 +08:00
|
|
|
int lws_open(const char *__file, int __oflag, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
va_start(ap, __oflag);
|
|
|
|
if (((__oflag & O_CREAT) == O_CREAT)
|
|
|
|
#if defined(O_TMPFILE)
|
|
|
|
|| ((__oflag & O_TMPFILE) == O_TMPFILE)
|
|
|
|
#endif
|
|
|
|
)
|
2021-06-20 06:00:48 +01:00
|
|
|
#if defined(WIN32)
|
2018-06-23 12:56:21 +08:00
|
|
|
/* last arg is really a mode_t. But windows... */
|
|
|
|
n = open(__file, __oflag, va_arg(ap, uint32_t));
|
2021-06-20 06:00:48 +01:00
|
|
|
#else
|
|
|
|
/* ... and some other toolchains...
|
|
|
|
*
|
|
|
|
* error: second argument to 'va_arg' is of promotable type 'mode_t'
|
|
|
|
* (aka 'unsigned short'); this va_arg has undefined behavior because
|
|
|
|
* arguments will be promoted to 'int'
|
|
|
|
*/
|
|
|
|
n = open(__file, __oflag, (mode_t)va_arg(ap, unsigned int));
|
|
|
|
#endif
|
2018-06-23 12:56:21 +08:00
|
|
|
else
|
|
|
|
n = open(__file, __oflag);
|
|
|
|
va_end(ap);
|
|
|
|
|
2018-08-01 06:52:03 +08:00
|
|
|
if (n != -1 && lws_plat_apply_FD_CLOEXEC(n)) {
|
|
|
|
close(n);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
2018-06-23 12:56:21 +08:00
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
2019-01-15 06:59:48 +08:00
|
|
|
#endif
|
2019-06-05 05:04:17 +01:00
|
|
|
#endif
|
2015-06-25 17:51:07 +02:00
|
|
|
|
2018-11-15 16:33:54 +08:00
|
|
|
int
|
|
|
|
lws_pthread_self_to_tsi(struct lws_context *context)
|
|
|
|
{
|
|
|
|
#if LWS_MAX_SMP > 1
|
|
|
|
pthread_t ps = pthread_self();
|
|
|
|
struct lws_context_per_thread *pt = &context->pt[0];
|
|
|
|
int n;
|
|
|
|
|
2021-05-11 14:34:30 +01:00
|
|
|
/* case that we have SMP build, but don't use it */
|
|
|
|
if (context->count_threads == 1)
|
|
|
|
return 0;
|
|
|
|
|
2018-11-15 16:33:54 +08:00
|
|
|
for (n = 0; n < context->count_threads; n++) {
|
|
|
|
if (pthread_equal(ps, pt->self))
|
|
|
|
return n;
|
|
|
|
pt++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2020-01-04 10:04:23 +00:00
|
|
|
void *
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_context_user(struct lws_context *context)
|
2013-01-17 16:50:35 +08:00
|
|
|
{
|
2019-01-13 06:58:21 +08:00
|
|
|
return context->user_space;
|
2013-01-17 16:50:35 +08:00
|
|
|
}
|
|
|
|
|
2020-01-04 10:04:23 +00:00
|
|
|
void
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_explicit_bzero(void *p, size_t len)
|
2013-10-24 22:12:03 +08:00
|
|
|
{
|
2019-01-13 06:58:21 +08:00
|
|
|
volatile uint8_t *vp = p;
|
2015-11-08 10:15:01 +08:00
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
while (len--)
|
|
|
|
*vp++ = 0;
|
|
|
|
}
|
2015-11-08 10:15:01 +08:00
|
|
|
|
2019-01-15 06:59:48 +08:00
|
|
|
#if !(defined(LWS_PLAT_OPTEE) && !defined(LWS_WITH_NETWORK))
|
2015-12-14 08:52:03 +08:00
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
/**
|
|
|
|
* lws_now_secs() - seconds since 1970-1-1
|
|
|
|
*
|
|
|
|
*/
|
2020-01-04 10:04:23 +00:00
|
|
|
unsigned long
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_now_secs(void)
|
|
|
|
{
|
|
|
|
struct timeval tv;
|
2015-11-08 10:15:01 +08:00
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
gettimeofday(&tv, NULL);
|
2015-11-08 10:15:01 +08:00
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
return (unsigned long)tv.tv_sec;
|
2019-01-13 06:58:21 +08:00
|
|
|
}
|
2013-10-24 22:12:03 +08:00
|
|
|
|
2019-01-15 06:59:48 +08:00
|
|
|
#endif
|
2019-08-18 06:29:34 +01:00
|
|
|
|
|
|
|
#if defined(LWS_WITH_SERVER)
|
2020-01-04 10:04:23 +00:00
|
|
|
const char *
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_canonical_hostname(struct lws_context *context)
|
|
|
|
{
|
|
|
|
return (const char *)context->canonical_hostname;
|
2013-10-24 22:12:03 +08:00
|
|
|
}
|
2019-08-18 06:29:34 +01:00
|
|
|
#endif
|
2013-10-24 22:12:03 +08:00
|
|
|
|
2020-01-04 10:04:23 +00:00
|
|
|
int
|
2019-01-13 06:58:21 +08:00
|
|
|
lws_get_count_threads(struct lws_context *context)
|
|
|
|
{
|
|
|
|
return context->count_threads;
|
2015-12-28 14:24:49 +08:00
|
|
|
}
|
2015-12-30 11:43:36 +08:00
|
|
|
|
2018-10-09 10:29:42 +08:00
|
|
|
static const unsigned char e0f4[] = {
|
|
|
|
0xa0 | ((2 - 1) << 2) | 1, /* e0 */
|
|
|
|
0x80 | ((4 - 1) << 2) | 1, /* e1 */
|
|
|
|
0x80 | ((4 - 1) << 2) | 1, /* e2 */
|
|
|
|
0x80 | ((4 - 1) << 2) | 1, /* e3 */
|
|
|
|
0x80 | ((4 - 1) << 2) | 1, /* e4 */
|
|
|
|
0x80 | ((4 - 1) << 2) | 1, /* e5 */
|
|
|
|
0x80 | ((4 - 1) << 2) | 1, /* e6 */
|
|
|
|
0x80 | ((4 - 1) << 2) | 1, /* e7 */
|
|
|
|
0x80 | ((4 - 1) << 2) | 1, /* e8 */
|
|
|
|
0x80 | ((4 - 1) << 2) | 1, /* e9 */
|
|
|
|
0x80 | ((4 - 1) << 2) | 1, /* ea */
|
|
|
|
0x80 | ((4 - 1) << 2) | 1, /* eb */
|
|
|
|
0x80 | ((4 - 1) << 2) | 1, /* ec */
|
|
|
|
0x80 | ((2 - 1) << 2) | 1, /* ed */
|
|
|
|
0x80 | ((4 - 1) << 2) | 1, /* ee */
|
|
|
|
0x80 | ((4 - 1) << 2) | 1, /* ef */
|
|
|
|
0x90 | ((3 - 1) << 2) | 2, /* f0 */
|
|
|
|
0x80 | ((4 - 1) << 2) | 2, /* f1 */
|
|
|
|
0x80 | ((4 - 1) << 2) | 2, /* f2 */
|
|
|
|
0x80 | ((4 - 1) << 2) | 2, /* f3 */
|
|
|
|
0x80 | ((1 - 1) << 2) | 2, /* f4 */
|
|
|
|
|
|
|
|
0, /* s0 */
|
|
|
|
0x80 | ((4 - 1) << 2) | 0, /* s2 */
|
|
|
|
0x80 | ((4 - 1) << 2) | 1, /* s3 */
|
|
|
|
};
|
|
|
|
|
2020-01-04 10:04:23 +00:00
|
|
|
int
|
2018-10-09 10:29:42 +08:00
|
|
|
lws_check_byte_utf8(unsigned char state, unsigned char c)
|
|
|
|
{
|
|
|
|
unsigned char s = state;
|
|
|
|
|
|
|
|
if (!s) {
|
|
|
|
if (c >= 0x80) {
|
|
|
|
if (c < 0xc2 || c > 0xf4)
|
|
|
|
return -1;
|
|
|
|
if (c < 0xe0)
|
|
|
|
return 0x80 | ((4 - 1) << 2);
|
|
|
|
else
|
|
|
|
return e0f4[c - 0xe0];
|
|
|
|
}
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
if (c < (s & 0xf0) || c >= (s & 0xf0) + 0x10 + ((s << 2) & 0x30))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return e0f4[21 + (s & 3)];
|
|
|
|
}
|
|
|
|
|
2020-01-04 10:04:23 +00:00
|
|
|
int
|
2015-12-30 11:43:36 +08:00
|
|
|
lws_check_utf8(unsigned char *state, unsigned char *buf, size_t len)
|
|
|
|
{
|
|
|
|
unsigned char s = *state;
|
|
|
|
|
|
|
|
while (len--) {
|
|
|
|
unsigned char c = *buf++;
|
|
|
|
|
|
|
|
if (!s) {
|
|
|
|
if (c >= 0x80) {
|
|
|
|
if (c < 0xc2 || c > 0xf4)
|
|
|
|
return 1;
|
|
|
|
if (c < 0xe0)
|
|
|
|
s = 0x80 | ((4 - 1) << 2);
|
|
|
|
else
|
|
|
|
s = e0f4[c - 0xe0];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (c < (s & 0xf0) ||
|
|
|
|
c >= (s & 0xf0) + 0x10 + ((s << 2) & 0x30))
|
|
|
|
return 1;
|
|
|
|
s = e0f4[21 + (s & 3)];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*state = s;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2016-01-11 11:34:01 +08:00
|
|
|
|
2016-01-14 13:39:02 +08:00
|
|
|
|
2018-05-10 16:13:26 +08:00
|
|
|
char *
|
|
|
|
lws_strdup(const char *s)
|
|
|
|
{
|
|
|
|
char *d = lws_malloc(strlen(s) + 1, "strdup");
|
|
|
|
|
|
|
|
if (d)
|
|
|
|
strcpy(d, s);
|
|
|
|
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
2020-06-19 11:10:56 +01:00
|
|
|
const char *
|
|
|
|
lws_nstrstr(const char *buf, size_t len, const char *name, size_t nl)
|
|
|
|
{
|
|
|
|
const char *end = buf + len - nl + 1;
|
|
|
|
size_t n;
|
|
|
|
|
|
|
|
if (nl > len)
|
|
|
|
/* it cannot be found if the needle is longer than the haystack */
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
while (buf < end) {
|
|
|
|
if (*buf != name[0]) {
|
|
|
|
buf++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nl == 1)
|
|
|
|
/* single char match, we are done */
|
|
|
|
return buf;
|
|
|
|
|
|
|
|
if (buf[nl - 1] == name[nl - 1]) {
|
|
|
|
/*
|
|
|
|
* This is looking interesting then... the first
|
|
|
|
* and last chars match, let's check the insides
|
|
|
|
*/
|
|
|
|
n = 1;
|
|
|
|
while (n < nl && buf[n] == name[n])
|
|
|
|
n++;
|
|
|
|
|
|
|
|
if (n == nl)
|
|
|
|
/* it's a hit */
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* name wants to be something like "\"myname\":"
|
|
|
|
*/
|
|
|
|
|
|
|
|
const char *
|
|
|
|
lws_json_simple_find(const char *buf, size_t len, const char *name, size_t *alen)
|
|
|
|
{
|
|
|
|
size_t nl = strlen(name);
|
|
|
|
const char *np = lws_nstrstr(buf, len, name, nl),
|
|
|
|
*end = buf + len, *as;
|
|
|
|
int qu = 0;
|
|
|
|
|
|
|
|
if (!np)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
np += nl;
|
|
|
|
|
|
|
|
while (np < end && (*np == ' ' || *np == '\t'))
|
|
|
|
np++;
|
|
|
|
|
2020-07-12 15:09:16 +01:00
|
|
|
if (np >= end)
|
2020-06-19 11:10:56 +01:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The arg could be lots of things after "name": with JSON, commonly a
|
|
|
|
* string like "mystring", true, false, null, [...] or {...} ... we want
|
|
|
|
* to handle common, simple cases cheaply with this; the user can choose
|
|
|
|
* a full JSON parser like lejp if it's complicated. So if no opening
|
|
|
|
* quote, return until a terminator like , ] }. If there's an opening
|
|
|
|
* quote, return until closing quote, handling escaped quotes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (*np == '\"') {
|
|
|
|
qu = 1;
|
|
|
|
np++;
|
|
|
|
}
|
|
|
|
|
|
|
|
as = np;
|
|
|
|
while (np < end &&
|
|
|
|
(!qu || *np != '\"') && /* end quote is EOT if quoted */
|
|
|
|
(qu || (*np != '}' && *np != ']' && *np != ',')) /* delimiters */
|
|
|
|
) {
|
|
|
|
if (qu && *np == '\\') /* skip next char if quoted escape */
|
|
|
|
np++;
|
|
|
|
np++;
|
|
|
|
}
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
*alen = (unsigned int)lws_ptr_diff(np, as);
|
2020-06-19 11:10:56 +01:00
|
|
|
|
|
|
|
return as;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
lws_json_simple_strcmp(const char *buf, size_t len, const char *name,
|
|
|
|
const char *comp)
|
|
|
|
{
|
|
|
|
size_t al;
|
|
|
|
const char *hit = lws_json_simple_find(buf, len, name, &al);
|
|
|
|
|
|
|
|
if (!hit)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (al != strlen(comp))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return strncmp(hit, comp, al);
|
|
|
|
}
|
|
|
|
|
2016-06-08 10:07:02 +08:00
|
|
|
static const char *hex = "0123456789ABCDEF";
|
|
|
|
|
2020-01-04 10:04:23 +00:00
|
|
|
const char *
|
2020-12-12 06:21:40 +00:00
|
|
|
lws_sql_purify(char *escaped, const char *string, size_t len)
|
2016-06-08 10:07:02 +08:00
|
|
|
{
|
|
|
|
const char *p = string;
|
|
|
|
char *q = escaped;
|
|
|
|
|
|
|
|
while (*p && len-- > 2) {
|
|
|
|
if (*p == '\'') {
|
2016-05-19 15:28:31 +08:00
|
|
|
*q++ = '\'';
|
2016-06-08 10:07:02 +08:00
|
|
|
*q++ = '\'';
|
|
|
|
len --;
|
|
|
|
p++;
|
|
|
|
} else
|
|
|
|
*q++ = *p++;
|
|
|
|
}
|
|
|
|
*q = '\0';
|
|
|
|
|
|
|
|
return escaped;
|
|
|
|
}
|
|
|
|
|
2020-02-21 07:52:45 +00:00
|
|
|
int
|
|
|
|
lws_sql_purify_len(const char *p)
|
|
|
|
{
|
|
|
|
int olen = 0;
|
|
|
|
|
|
|
|
while (*p) {
|
|
|
|
if (*p++ == '\'')
|
|
|
|
olen++;
|
|
|
|
olen++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return olen;
|
|
|
|
}
|
|
|
|
|
2020-01-04 10:04:23 +00:00
|
|
|
const char *
|
2020-02-21 07:52:45 +00:00
|
|
|
lws_json_purify(char *escaped, const char *string, int len, int *in_used)
|
2016-06-17 10:05:23 +08:00
|
|
|
{
|
|
|
|
const char *p = string;
|
|
|
|
char *q = escaped;
|
|
|
|
|
2016-06-26 06:29:20 +08:00
|
|
|
if (!p) {
|
|
|
|
escaped[0] = '\0';
|
|
|
|
return escaped;
|
|
|
|
}
|
|
|
|
|
2016-06-17 10:05:23 +08:00
|
|
|
while (*p && len-- > 6) {
|
2018-08-14 08:00:25 +08:00
|
|
|
if (*p == '\t') {
|
|
|
|
p++;
|
|
|
|
*q++ = '\\';
|
|
|
|
*q++ = 't';
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*p == '\n') {
|
|
|
|
p++;
|
|
|
|
*q++ = '\\';
|
|
|
|
*q++ = 'n';
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*p == '\r') {
|
|
|
|
p++;
|
|
|
|
*q++ = '\\';
|
|
|
|
*q++ = 'r';
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-04-07 06:35:00 +01:00
|
|
|
if (*p == '\\') {
|
|
|
|
p++;
|
|
|
|
*q++ = '\\';
|
|
|
|
*q++ = '\\';
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*p == '\"' || *p < 0x20) {
|
2016-06-17 10:05:23 +08:00
|
|
|
*q++ = '\\';
|
|
|
|
*q++ = 'u';
|
|
|
|
*q++ = '0';
|
|
|
|
*q++ = '0';
|
|
|
|
*q++ = hex[((*p) >> 4) & 15];
|
|
|
|
*q++ = hex[(*p) & 15];
|
|
|
|
len -= 5;
|
|
|
|
p++;
|
|
|
|
} else
|
|
|
|
*q++ = *p++;
|
|
|
|
}
|
|
|
|
*q = '\0';
|
|
|
|
|
2020-02-21 07:52:45 +00:00
|
|
|
if (in_used)
|
|
|
|
*in_used = lws_ptr_diff(p, string);
|
|
|
|
|
2016-06-17 10:05:23 +08:00
|
|
|
return escaped;
|
|
|
|
}
|
|
|
|
|
2020-02-21 07:52:45 +00:00
|
|
|
int
|
|
|
|
lws_json_purify_len(const char *string)
|
|
|
|
{
|
|
|
|
int len = 0;
|
|
|
|
const char *p = string;
|
|
|
|
|
|
|
|
while (*p) {
|
|
|
|
if (*p == '\t' || *p == '\n' || *p == '\r') {
|
|
|
|
p++;
|
|
|
|
len += 2;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*p == '\"' || *p == '\\' || *p < 0x20) {
|
|
|
|
len += 6;
|
|
|
|
p++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
len++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2020-01-04 10:04:23 +00:00
|
|
|
void
|
2018-03-29 09:28:41 +08:00
|
|
|
lws_filename_purify_inplace(char *filename)
|
|
|
|
{
|
|
|
|
while (*filename) {
|
|
|
|
|
|
|
|
if (*filename == '.' && filename[1] == '.') {
|
|
|
|
*filename = '_';
|
|
|
|
filename[1] = '_';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*filename == ':' ||
|
2020-04-07 06:35:00 +01:00
|
|
|
#if !defined(WIN32)
|
2018-03-29 09:28:41 +08:00
|
|
|
*filename == '\\' ||
|
2020-04-07 06:35:00 +01:00
|
|
|
#endif
|
2018-03-29 09:28:41 +08:00
|
|
|
*filename == '$' ||
|
|
|
|
*filename == '%')
|
|
|
|
*filename = '_';
|
|
|
|
|
|
|
|
filename++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-04 10:04:23 +00:00
|
|
|
const char *
|
2016-06-08 10:07:02 +08:00
|
|
|
lws_urlencode(char *escaped, const char *string, int len)
|
|
|
|
{
|
|
|
|
const char *p = string;
|
|
|
|
char *q = escaped;
|
|
|
|
|
|
|
|
while (*p && len-- > 3) {
|
|
|
|
if (*p == ' ') {
|
|
|
|
*q++ = '+';
|
|
|
|
p++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ((*p >= '0' && *p <= '9') ||
|
|
|
|
(*p >= 'A' && *p <= 'Z') ||
|
|
|
|
(*p >= 'a' && *p <= 'z')) {
|
|
|
|
*q++ = *p++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
*q++ = '%';
|
|
|
|
*q++ = hex[(*p >> 4) & 0xf];
|
|
|
|
*q++ = hex[*p & 0xf];
|
|
|
|
|
|
|
|
len -= 2;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
*q = '\0';
|
|
|
|
|
|
|
|
return escaped;
|
|
|
|
}
|
|
|
|
|
2020-01-04 10:04:23 +00:00
|
|
|
int
|
2016-06-08 10:07:02 +08:00
|
|
|
lws_urldecode(char *string, const char *escaped, int len)
|
|
|
|
{
|
|
|
|
int state = 0, n;
|
|
|
|
char sum = 0;
|
|
|
|
|
|
|
|
while (*escaped && len) {
|
|
|
|
switch (state) {
|
|
|
|
case 0:
|
|
|
|
if (*escaped == '%') {
|
|
|
|
state++;
|
|
|
|
escaped++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (*escaped == '+') {
|
|
|
|
escaped++;
|
|
|
|
*string++ = ' ';
|
|
|
|
len--;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
*string++ = *escaped++;
|
|
|
|
len--;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
n = char_to_hex(*escaped);
|
|
|
|
if (n < 0)
|
|
|
|
return -1;
|
|
|
|
escaped++;
|
2020-12-12 06:21:40 +00:00
|
|
|
sum = (char)(n << 4);
|
2016-06-08 10:07:02 +08:00
|
|
|
state++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
n = char_to_hex(*escaped);
|
|
|
|
if (n < 0)
|
|
|
|
return -1;
|
|
|
|
escaped++;
|
2020-12-12 06:21:40 +00:00
|
|
|
*string++ = (char)(sum | n);
|
2016-06-08 10:07:02 +08:00
|
|
|
len--;
|
|
|
|
state = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
*string = '\0';
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-04 10:04:23 +00:00
|
|
|
int
|
2016-03-28 10:10:43 +08:00
|
|
|
lws_finalize_startup(struct lws_context *context)
|
|
|
|
{
|
|
|
|
if (lws_check_opt(context->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
|
2019-04-21 19:51:03 +01:00
|
|
|
if (lws_plat_drop_app_privileges(context, 1))
|
2019-03-24 17:54:48 +08:00
|
|
|
return 1;
|
2016-03-28 10:10:43 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
#if !defined(LWS_PLAT_FREERTOS)
|
2020-01-04 10:04:23 +00:00
|
|
|
void
|
2020-12-12 06:21:40 +00:00
|
|
|
lws_get_effective_uid_gid(struct lws_context *context, uid_t *uid, gid_t *gid)
|
2018-08-02 19:15:19 +08:00
|
|
|
{
|
|
|
|
*uid = context->uid;
|
|
|
|
*gid = context->gid;
|
|
|
|
}
|
fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.
This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it. Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.
Helpers are added when fakewsi is used and referenced.
If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure. There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.
If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach. For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes. The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.
Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined. However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.
User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with. Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-19 08:33:46 +01:00
|
|
|
#endif
|
2018-08-02 19:15:19 +08:00
|
|
|
|
2016-09-15 02:22:57 +08:00
|
|
|
int
|
|
|
|
lws_snprintf(char *str, size_t size, const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
if (!size)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
va_start(ap, format);
|
|
|
|
n = vsnprintf(str, size, format, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
2017-06-09 20:20:42 +08:00
|
|
|
if (n >= (int)size)
|
2017-10-25 08:00:23 +08:00
|
|
|
return (int)size;
|
2016-09-15 02:22:57 +08:00
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2018-03-12 09:28:26 +08:00
|
|
|
char *
|
|
|
|
lws_strncpy(char *dest, const char *src, size_t size)
|
|
|
|
{
|
|
|
|
strncpy(dest, src, size - 1);
|
|
|
|
dest[size - 1] = '\0';
|
|
|
|
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
2018-12-13 20:05:12 +08:00
|
|
|
int
|
|
|
|
lws_timingsafe_bcmp(const void *a, const void *b, uint32_t len)
|
|
|
|
{
|
|
|
|
const uint8_t *pa = a, *pb = b;
|
|
|
|
uint8_t sum = 0;
|
|
|
|
|
|
|
|
while (len--)
|
2020-12-12 06:21:40 +00:00
|
|
|
sum |= (uint8_t)(*pa++ ^ *pb++);
|
2018-12-13 20:05:12 +08:00
|
|
|
|
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
|
2018-10-09 10:29:42 +08:00
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
LWS_TOKZS_LEADING_WHITESPACE,
|
|
|
|
LWS_TOKZS_QUOTED_STRING,
|
|
|
|
LWS_TOKZS_TOKEN,
|
|
|
|
LWS_TOKZS_TOKEN_POST_TERMINAL
|
|
|
|
} lws_tokenize_state;
|
|
|
|
|
2019-06-05 05:04:17 +01:00
|
|
|
lws_tokenize_elem
|
2018-10-09 10:29:42 +08:00
|
|
|
lws_tokenize(struct lws_tokenize *ts)
|
|
|
|
{
|
|
|
|
const char *rfc7230_delims = "(),/:;<=>?@[\\]{}";
|
|
|
|
lws_tokenize_state state = LWS_TOKZS_LEADING_WHITESPACE;
|
2021-01-17 09:29:51 +00:00
|
|
|
char c, flo = 0, d_minus = '-', d_dot = '.', d_star = '*', s_minus = '\0',
|
2021-03-10 10:52:08 +00:00
|
|
|
s_dot = '\0', s_star = '\0', d_eq = '=', s_eq = '\0', skipping = 0;
|
2020-01-02 08:32:23 +00:00
|
|
|
signed char num = (ts->flags & LWS_TOKENIZE_F_NO_INTEGERS) ? 0 : -1;
|
2018-10-09 10:29:42 +08:00
|
|
|
int utf8 = 0;
|
|
|
|
|
2018-11-13 09:34:10 +08:00
|
|
|
/* for speed, compute the effect of the flags outside the loop */
|
|
|
|
|
|
|
|
if (ts->flags & LWS_TOKENIZE_F_MINUS_NONTERM) {
|
|
|
|
d_minus = '\0';
|
|
|
|
s_minus = '-';
|
|
|
|
}
|
|
|
|
if (ts->flags & LWS_TOKENIZE_F_DOT_NONTERM) {
|
|
|
|
d_dot = '\0';
|
|
|
|
s_dot = '.';
|
|
|
|
}
|
2021-01-17 09:29:51 +00:00
|
|
|
if (ts->flags & LWS_TOKENIZE_F_ASTERISK_NONTERM) {
|
|
|
|
d_star = '\0';
|
|
|
|
s_star = '*';
|
|
|
|
}
|
2021-03-10 10:52:08 +00:00
|
|
|
if (ts->flags & LWS_TOKENIZE_F_EQUALS_NONTERM) {
|
|
|
|
d_eq = '\0';
|
|
|
|
s_eq = '=';
|
|
|
|
}
|
2018-11-13 09:34:10 +08:00
|
|
|
|
2018-10-09 10:29:42 +08:00
|
|
|
ts->token = NULL;
|
|
|
|
ts->token_len = 0;
|
|
|
|
|
|
|
|
while (ts->len) {
|
|
|
|
c = *ts->start++;
|
|
|
|
ts->len--;
|
|
|
|
|
2020-12-12 06:21:40 +00:00
|
|
|
utf8 = lws_check_byte_utf8((unsigned char)utf8, (unsigned char)c);
|
2018-10-09 10:29:42 +08:00
|
|
|
if (utf8 < 0)
|
|
|
|
return LWS_TOKZE_ERR_BROKEN_UTF8;
|
|
|
|
|
|
|
|
if (!c)
|
|
|
|
break;
|
|
|
|
|
2019-09-15 11:06:11 +01:00
|
|
|
if (skipping) {
|
|
|
|
if (c != '\r' && c != '\n')
|
|
|
|
continue;
|
|
|
|
else
|
|
|
|
skipping = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* comment */
|
|
|
|
|
|
|
|
if (ts->flags & LWS_TOKENIZE_F_HASH_COMMENT &&
|
|
|
|
state != LWS_TOKZS_QUOTED_STRING &&
|
|
|
|
c == '#') {
|
|
|
|
skipping = 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-10-09 10:29:42 +08:00
|
|
|
/* whitespace */
|
|
|
|
|
|
|
|
if (c == ' ' || c == '\t' || c == '\n' || c == '\r' ||
|
|
|
|
c == '\f') {
|
|
|
|
switch (state) {
|
|
|
|
case LWS_TOKZS_LEADING_WHITESPACE:
|
|
|
|
case LWS_TOKZS_TOKEN_POST_TERMINAL:
|
|
|
|
continue;
|
|
|
|
case LWS_TOKZS_QUOTED_STRING:
|
|
|
|
ts->token_len++;
|
|
|
|
continue;
|
|
|
|
case LWS_TOKZS_TOKEN:
|
|
|
|
/* we want to scan forward to look for = */
|
|
|
|
|
|
|
|
state = LWS_TOKZS_TOKEN_POST_TERMINAL;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* quoted string */
|
|
|
|
|
|
|
|
if (c == '\"') {
|
|
|
|
if (state == LWS_TOKZS_QUOTED_STRING)
|
|
|
|
return LWS_TOKZE_QUOTED_STRING;
|
|
|
|
|
|
|
|
/* starting a quoted string */
|
|
|
|
|
|
|
|
if (ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) {
|
|
|
|
if (ts->delim == LWSTZ_DT_NEED_DELIM)
|
|
|
|
return LWS_TOKZE_ERR_COMMA_LIST;
|
|
|
|
ts->delim = LWSTZ_DT_NEED_DELIM;
|
|
|
|
}
|
|
|
|
|
|
|
|
state = LWS_TOKZS_QUOTED_STRING;
|
|
|
|
ts->token = ts->start;
|
|
|
|
ts->token_len = 0;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* token= aggregation */
|
|
|
|
|
2021-03-10 10:52:08 +00:00
|
|
|
if (!(ts->flags & LWS_TOKENIZE_F_EQUALS_NONTERM) &&
|
|
|
|
c == '=' && (state == LWS_TOKZS_TOKEN_POST_TERMINAL ||
|
2018-10-09 10:29:42 +08:00
|
|
|
state == LWS_TOKZS_TOKEN)) {
|
|
|
|
if (num == 1)
|
|
|
|
return LWS_TOKZE_ERR_NUM_ON_LHS;
|
|
|
|
/* swallow the = */
|
|
|
|
return LWS_TOKZE_TOKEN_NAME_EQUALS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* optional token: aggregation */
|
|
|
|
|
|
|
|
if ((ts->flags & LWS_TOKENIZE_F_AGG_COLON) && c == ':' &&
|
|
|
|
(state == LWS_TOKZS_TOKEN_POST_TERMINAL ||
|
|
|
|
state == LWS_TOKZS_TOKEN))
|
|
|
|
/* swallow the : */
|
|
|
|
return LWS_TOKZE_TOKEN_NAME_COLON;
|
|
|
|
|
|
|
|
/* aggregate . in a number as a float */
|
|
|
|
|
2018-11-13 09:34:10 +08:00
|
|
|
if (c == '.' && !(ts->flags & LWS_TOKENIZE_F_NO_FLOATS) &&
|
|
|
|
state == LWS_TOKZS_TOKEN && num == 1) {
|
2018-10-09 10:29:42 +08:00
|
|
|
if (flo)
|
|
|
|
return LWS_TOKZE_ERR_MALFORMED_FLOAT;
|
|
|
|
flo = 1;
|
|
|
|
ts->token_len++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delimiter... by default anything that:
|
|
|
|
*
|
|
|
|
* - isn't matched earlier, or
|
|
|
|
* - is [A-Z, a-z, 0-9, _], and
|
|
|
|
* - is not a partial utf8 char
|
|
|
|
*
|
|
|
|
* is a "delimiter", it marks the end of a token and is itself
|
|
|
|
* reported as a single LWS_TOKZE_DELIMITER each time.
|
|
|
|
*
|
|
|
|
* However with LWS_TOKENIZE_F_RFC7230_DELIMS flag, tokens may
|
|
|
|
* contain any noncontrol character that isn't defined in
|
|
|
|
* rfc7230_delims, and only characters listed there are treated
|
|
|
|
* as delimiters.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!utf8 &&
|
|
|
|
((ts->flags & LWS_TOKENIZE_F_RFC7230_DELIMS &&
|
|
|
|
strchr(rfc7230_delims, c) && c > 32) ||
|
|
|
|
((!(ts->flags & LWS_TOKENIZE_F_RFC7230_DELIMS) &&
|
|
|
|
(c < '0' || c > '9') && (c < 'A' || c > 'Z') &&
|
2018-11-13 09:34:10 +08:00
|
|
|
(c < 'a' || c > 'z') && c != '_') &&
|
2021-03-10 10:52:08 +00:00
|
|
|
c != s_minus && c != s_dot && c != s_star && c != s_eq) ||
|
|
|
|
c == d_minus || c == d_dot || c == d_star || c == d_eq
|
2020-01-04 10:04:23 +00:00
|
|
|
) &&
|
|
|
|
!((ts->flags & LWS_TOKENIZE_F_SLASH_NONTERM) && c == '/')) {
|
2018-10-09 10:29:42 +08:00
|
|
|
switch (state) {
|
|
|
|
case LWS_TOKZS_LEADING_WHITESPACE:
|
|
|
|
if (ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) {
|
|
|
|
if (c != ',' ||
|
|
|
|
ts->delim != LWSTZ_DT_NEED_DELIM)
|
|
|
|
return LWS_TOKZE_ERR_COMMA_LIST;
|
|
|
|
ts->delim = LWSTZ_DT_NEED_NEXT_CONTENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
ts->token = ts->start - 1;
|
|
|
|
ts->token_len = 1;
|
|
|
|
return LWS_TOKZE_DELIMITER;
|
|
|
|
|
|
|
|
case LWS_TOKZS_QUOTED_STRING:
|
|
|
|
ts->token_len++;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case LWS_TOKZS_TOKEN_POST_TERMINAL:
|
|
|
|
case LWS_TOKZS_TOKEN:
|
|
|
|
/* report the delimiter next time */
|
|
|
|
ts->start--;
|
|
|
|
ts->len++;
|
|
|
|
goto token_or_numeric;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* anything that's not whitespace or delimiter is payload */
|
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
case LWS_TOKZS_LEADING_WHITESPACE:
|
|
|
|
|
|
|
|
if (ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) {
|
|
|
|
if (ts->delim == LWSTZ_DT_NEED_DELIM)
|
|
|
|
return LWS_TOKZE_ERR_COMMA_LIST;
|
|
|
|
ts->delim = LWSTZ_DT_NEED_DELIM;
|
|
|
|
}
|
|
|
|
|
|
|
|
state = LWS_TOKZS_TOKEN;
|
|
|
|
ts->token = ts->start - 1;
|
|
|
|
ts->token_len = 1;
|
2019-07-20 11:26:58 -07:00
|
|
|
goto checknum;
|
|
|
|
|
2018-10-09 10:29:42 +08:00
|
|
|
case LWS_TOKZS_QUOTED_STRING:
|
|
|
|
case LWS_TOKZS_TOKEN:
|
|
|
|
ts->token_len++;
|
2019-07-20 11:26:58 -07:00
|
|
|
checknum:
|
|
|
|
if (!(ts->flags & LWS_TOKENIZE_F_NO_INTEGERS)) {
|
|
|
|
if (c < '0' || c > '9')
|
|
|
|
num = 0;
|
|
|
|
else
|
|
|
|
if (num < 0)
|
|
|
|
num = 1;
|
|
|
|
}
|
2018-10-09 10:29:42 +08:00
|
|
|
continue;
|
2019-07-20 11:26:58 -07:00
|
|
|
|
2018-10-09 10:29:42 +08:00
|
|
|
case LWS_TOKZS_TOKEN_POST_TERMINAL:
|
|
|
|
/* report the new token next time */
|
|
|
|
ts->start--;
|
|
|
|
ts->len++;
|
|
|
|
goto token_or_numeric;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we ran out of content */
|
|
|
|
|
|
|
|
if (utf8) /* ended partway through a multibyte char */
|
|
|
|
return LWS_TOKZE_ERR_BROKEN_UTF8;
|
|
|
|
|
|
|
|
if (state == LWS_TOKZS_QUOTED_STRING)
|
|
|
|
return LWS_TOKZE_ERR_UNTERM_STRING;
|
|
|
|
|
|
|
|
if (state != LWS_TOKZS_TOKEN_POST_TERMINAL &&
|
|
|
|
state != LWS_TOKZS_TOKEN) {
|
|
|
|
if ((ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) &&
|
|
|
|
ts->delim == LWSTZ_DT_NEED_NEXT_CONTENT)
|
|
|
|
return LWS_TOKZE_ERR_COMMA_LIST;
|
|
|
|
|
|
|
|
return LWS_TOKZE_ENDED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* report the pending token */
|
|
|
|
|
|
|
|
token_or_numeric:
|
|
|
|
|
|
|
|
if (num != 1)
|
|
|
|
return LWS_TOKZE_TOKEN;
|
|
|
|
if (flo)
|
|
|
|
return LWS_TOKZE_FLOAT;
|
|
|
|
|
|
|
|
return LWS_TOKZE_INTEGER;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-01-04 10:04:23 +00:00
|
|
|
int
|
2020-01-11 14:04:50 +00:00
|
|
|
lws_tokenize_cstr(struct lws_tokenize *ts, char *str, size_t max)
|
2018-10-09 10:29:42 +08:00
|
|
|
{
|
|
|
|
if (ts->token_len + 1 >= max)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
memcpy(str, ts->token, ts->token_len);
|
|
|
|
str[ts->token_len] = '\0';
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-04 10:04:23 +00:00
|
|
|
void
|
2018-10-09 10:29:42 +08:00
|
|
|
lws_tokenize_init(struct lws_tokenize *ts, const char *start, int flags)
|
|
|
|
{
|
|
|
|
ts->start = start;
|
|
|
|
ts->len = 0x7fffffff;
|
2020-12-12 06:21:40 +00:00
|
|
|
ts->flags = (uint16_t)(unsigned int)flags;
|
2018-10-09 10:29:42 +08:00
|
|
|
ts->delim = LWSTZ_DT_NEED_FIRST_CONTENT;
|
|
|
|
}
|
|
|
|
|
2019-12-16 18:16:01 +00:00
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
LWS_EXPS_LITERAL,
|
|
|
|
LWS_EXPS_OPEN_OR_LIT,
|
|
|
|
LWS_EXPS_NAME_OR_CLOSE,
|
|
|
|
LWS_EXPS_DRAIN,
|
|
|
|
} lws_strexp_state;
|
|
|
|
|
|
|
|
void
|
|
|
|
lws_strexp_init(lws_strexp_t *exp, void *priv, lws_strexp_expand_cb cb,
|
|
|
|
char *out, size_t olen)
|
|
|
|
{
|
|
|
|
memset(exp, 0, sizeof(*exp));
|
|
|
|
exp->cb = cb;
|
|
|
|
exp->out = out;
|
|
|
|
exp->olen = olen;
|
|
|
|
exp->state = LWS_EXPS_LITERAL;
|
|
|
|
exp->priv = priv;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
lws_strexp_reset_out(lws_strexp_t *exp, char *out, size_t olen)
|
|
|
|
{
|
|
|
|
exp->out = out;
|
|
|
|
exp->olen = olen;
|
|
|
|
exp->pos = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
lws_strexp_expand(lws_strexp_t *exp, const char *in, size_t len,
|
|
|
|
size_t *pused_in, size_t *pused_out)
|
|
|
|
{
|
|
|
|
size_t used = 0;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
while (used < len) {
|
|
|
|
|
|
|
|
switch (exp->state) {
|
|
|
|
case LWS_EXPS_LITERAL:
|
|
|
|
if (*in == '$') {
|
|
|
|
exp->state = LWS_EXPS_OPEN_OR_LIT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-06-15 15:01:35 +01:00
|
|
|
if (exp->out)
|
|
|
|
exp->out[exp->pos] = *in;
|
|
|
|
exp->pos++;
|
2019-12-16 18:16:01 +00:00
|
|
|
if (exp->olen - exp->pos < 1) {
|
|
|
|
*pused_in = used + 1;
|
|
|
|
*pused_out = exp->pos;
|
|
|
|
return LSTRX_FILLED_OUT;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LWS_EXPS_OPEN_OR_LIT:
|
|
|
|
if (*in == '{') {
|
|
|
|
exp->state = LWS_EXPS_NAME_OR_CLOSE;
|
|
|
|
exp->name_pos = 0;
|
2020-04-30 20:26:19 +01:00
|
|
|
exp->exp_ofs = 0;
|
2019-12-16 18:16:01 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* treat as a literal */
|
|
|
|
if (exp->olen - exp->pos < 3)
|
|
|
|
return -1;
|
|
|
|
|
2020-06-15 15:01:35 +01:00
|
|
|
if (exp->out) {
|
|
|
|
exp->out[exp->pos++] = '$';
|
|
|
|
exp->out[exp->pos++] = *in;
|
|
|
|
} else
|
|
|
|
exp->pos += 2;
|
2019-12-16 18:16:01 +00:00
|
|
|
if (*in != '$')
|
|
|
|
exp->state = LWS_EXPS_LITERAL;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LWS_EXPS_NAME_OR_CLOSE:
|
|
|
|
if (*in == '}') {
|
|
|
|
exp->name[exp->name_pos] = '\0';
|
|
|
|
exp->state = LWS_EXPS_DRAIN;
|
|
|
|
goto drain;
|
|
|
|
}
|
|
|
|
if (exp->name_pos >= sizeof(exp->name) - 1)
|
|
|
|
return LSTRX_FATAL_NAME_TOO_LONG;
|
|
|
|
|
|
|
|
exp->name[exp->name_pos++] = *in;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LWS_EXPS_DRAIN:
|
|
|
|
drain:
|
|
|
|
*pused_in = used;
|
|
|
|
n = exp->cb(exp->priv, exp->name, exp->out, &exp->pos,
|
|
|
|
exp->olen, &exp->exp_ofs);
|
|
|
|
*pused_out = exp->pos;
|
|
|
|
if (n == LSTRX_FILLED_OUT ||
|
|
|
|
n == LSTRX_FATAL_NAME_UNKNOWN)
|
|
|
|
return n;
|
|
|
|
|
|
|
|
exp->state = LWS_EXPS_LITERAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
used++;
|
|
|
|
in++;
|
|
|
|
}
|
|
|
|
|
2020-06-15 15:01:35 +01:00
|
|
|
if (exp->out)
|
|
|
|
exp->out[exp->pos] = '\0';
|
2019-12-16 18:16:01 +00:00
|
|
|
*pused_in = used;
|
|
|
|
*pused_out = exp->pos;
|
|
|
|
|
|
|
|
return LSTRX_DONE;
|
|
|
|
}
|
|
|
|
|
2021-01-16 07:30:25 +00:00
|
|
|
int
|
2021-06-07 14:54:35 +01:00
|
|
|
lws_strcmp_wildcard(const char *wildcard, size_t wlen, const char *check,
|
|
|
|
size_t clen)
|
2021-01-16 07:30:25 +00:00
|
|
|
{
|
2021-06-07 14:54:35 +01:00
|
|
|
const char *match[3], *wc[3], *wc_end = wildcard + wlen,
|
|
|
|
*cend = check + clen;
|
2021-01-16 07:30:25 +00:00
|
|
|
int sp = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
|
|
if (wildcard == wc_end) {
|
|
|
|
/*
|
|
|
|
* We reached the end of wildcard, but not of check,
|
|
|
|
* and the last thing in wildcard was not a * or we
|
|
|
|
* would have completed already... if we can rewind,
|
|
|
|
* let's try that...
|
|
|
|
*/
|
|
|
|
if (sp) {
|
|
|
|
wildcard = wc[sp - 1];
|
|
|
|
check = match[--sp];
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* otherwise it's the end of the road for this one */
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*wildcard == '*') {
|
|
|
|
|
|
|
|
if (++wildcard == wc_end)
|
|
|
|
/*
|
|
|
|
* Wildcard ended on a *, so we know we will
|
|
|
|
* match unconditionally
|
|
|
|
*/
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now we need to stick wildcard here and see if there
|
|
|
|
* is any remaining match exists, for eg b of "a*b"
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (sp == LWS_ARRAY_SIZE(match)) {
|
|
|
|
lwsl_err("%s: exceeds * stack\n", __func__);
|
|
|
|
return 1; /* we can't deal with it */
|
|
|
|
}
|
|
|
|
|
|
|
|
wc[sp] = wildcard;
|
|
|
|
/* if we ever pop and come back here, pick up from +1 */
|
|
|
|
match[sp++] = check + 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*(check++) == *wildcard) {
|
|
|
|
|
|
|
|
if (wildcard == wc_end)
|
|
|
|
return 0;
|
|
|
|
/*
|
|
|
|
* We're still compatible with wildcard... keep going
|
|
|
|
*/
|
|
|
|
wildcard++;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sp)
|
|
|
|
/*
|
|
|
|
* We're just trying to match literals, and failed...
|
|
|
|
*/
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* we're looking for a post-* match... keep looking... */
|
|
|
|
|
2021-06-07 14:54:35 +01:00
|
|
|
} while (check < cend);
|
2021-01-16 07:30:25 +00:00
|
|
|
|
2021-06-07 14:54:35 +01:00
|
|
|
/*
|
|
|
|
* We reached the end of check, if also at end of wildcard we're OK
|
|
|
|
*/
|
|
|
|
|
|
|
|
return wildcard != wc_end;
|
2021-01-16 07:30:25 +00:00
|
|
|
}
|
2019-12-16 18:16:01 +00:00
|
|
|
|
2018-06-27 07:15:39 +08:00
|
|
|
#if LWS_MAX_SMP > 1
|
|
|
|
|
|
|
|
void
|
|
|
|
lws_mutex_refcount_init(struct lws_mutex_refcount *mr)
|
|
|
|
{
|
|
|
|
pthread_mutex_init(&mr->lock, NULL);
|
|
|
|
mr->last_lock_reason = NULL;
|
|
|
|
mr->lock_depth = 0;
|
|
|
|
mr->metadata = 0;
|
2021-04-04 18:50:05 +01:00
|
|
|
#ifdef __PTW32_H
|
|
|
|
/* If we use implementation of PThreads for Win that is
|
|
|
|
* distributed by VCPKG */
|
|
|
|
memset(&mr->lock_owner, 0, sizeof(pthread_t));
|
|
|
|
#else
|
2018-06-27 07:15:39 +08:00
|
|
|
mr->lock_owner = 0;
|
2021-04-04 18:50:05 +01:00
|
|
|
#endif
|
2018-06-27 07:15:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
lws_mutex_refcount_destroy(struct lws_mutex_refcount *mr)
|
|
|
|
{
|
|
|
|
pthread_mutex_destroy(&mr->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
lws_mutex_refcount_lock(struct lws_mutex_refcount *mr, const char *reason)
|
|
|
|
{
|
|
|
|
/* if true, this sequence is atomic because our thread has the lock
|
|
|
|
*
|
|
|
|
* - if true, only guy who can race to make it untrue is our thread,
|
|
|
|
* and we are here.
|
|
|
|
*
|
|
|
|
* - if false, only guy who could race to make it true is our thread,
|
|
|
|
* and we are here
|
|
|
|
*
|
|
|
|
* - it can be false and change to a different tid that is also false
|
|
|
|
*/
|
2021-04-04 18:50:05 +01:00
|
|
|
#ifdef __PTW32_H
|
|
|
|
/* If we use implementation of PThreads for Win that is
|
|
|
|
* distributed by VCPKG */
|
|
|
|
if (pthread_equal(mr->lock_owner, pthread_self()))
|
|
|
|
#else
|
|
|
|
if (mr->lock_owner == pthread_self())
|
|
|
|
#endif
|
|
|
|
{
|
2018-06-27 07:15:39 +08:00
|
|
|
/* atomic because we only change it if we own the lock */
|
|
|
|
mr->lock_depth++;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pthread_mutex_lock(&mr->lock);
|
|
|
|
/* atomic because only we can have the lock */
|
|
|
|
mr->last_lock_reason = reason;
|
|
|
|
mr->lock_owner = pthread_self();
|
|
|
|
mr->lock_depth = 1;
|
|
|
|
//lwsl_notice("tid %d: lock %s\n", mr->tid, reason);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
lws_mutex_refcount_unlock(struct lws_mutex_refcount *mr)
|
|
|
|
{
|
|
|
|
if (--mr->lock_depth)
|
|
|
|
/* atomic because only thread that has the lock can unlock */
|
|
|
|
return;
|
|
|
|
|
|
|
|
mr->last_lock_reason = "free";
|
2021-04-04 18:50:05 +01:00
|
|
|
#ifdef __PTW32_H
|
|
|
|
/* If we use implementation of PThreads for Win that is
|
|
|
|
* distributed by VCPKG */
|
|
|
|
memset(&mr->lock_owner, 0, sizeof(pthread_t));
|
|
|
|
#else
|
2018-06-27 07:15:39 +08:00
|
|
|
mr->lock_owner = 0;
|
2021-04-04 18:50:05 +01:00
|
|
|
#endif
|
|
|
|
// lwsl_notice("tid %d: unlock %s\n", mr->tid, mr->last_lock_reason);
|
2018-06-27 07:15:39 +08:00
|
|
|
pthread_mutex_unlock(&mr->lock);
|
|
|
|
}
|
|
|
|
|
2020-08-31 08:12:16 +01:00
|
|
|
void
|
|
|
|
lws_mutex_refcount_assert_held(struct lws_mutex_refcount *mr)
|
|
|
|
{
|
2021-04-04 18:50:05 +01:00
|
|
|
#ifdef __PTW32_H
|
|
|
|
/* If we use implementation of PThreads for Win that is
|
|
|
|
* distributed by VCPKG */
|
|
|
|
assert(pthread_equal(mr->lock_owner, pthread_self()) && mr->lock_depth);
|
|
|
|
#else
|
2020-08-31 08:12:16 +01:00
|
|
|
assert(mr->lock_owner == pthread_self() && mr->lock_depth);
|
2021-04-04 18:50:05 +01:00
|
|
|
#endif
|
2020-08-31 08:12:16 +01:00
|
|
|
}
|
|
|
|
|
2018-06-27 07:15:39 +08:00
|
|
|
#endif /* SMP */
|
2016-09-15 02:22:57 +08:00
|
|
|
|
context deprecation
1) This makes lwsws run a parent process with the original permissions.
But this process is only able to respond to SIGHUP, it doesn't do anything
else.
2) You can send this parent process a SIGHUP now to cause it to
- close listening sockets in existing lwsws processes
- mark those processes as to exit when the number of active connections
on the falls to zero
- spawn a fresh child process from scratch, using latest configuration
file content, latest plugins, etc. It can now reopen listening sockets
if it chooses to, or open different listen ports or whatever.
Notes:
1) lws_context_destroy() has been split into two pieces... the reason for
the split is the first part closes the per-vhost protocols, but since
they may have created libuv objects in the per-vhost protocol storage,
these cannot be freed until after the loop has been run.
That's the purpose of the second part of the context destruction,
lws_context_destroy2().
For compatibility, if you are not using libuv, the first part calls the
second part. However if you are using libuv, you must now call the
second part from your own main.c after the first part.
2016-12-16 07:37:43 +08:00
|
|
|
|
2018-04-12 15:56:38 +08:00
|
|
|
const char *
|
|
|
|
lws_cmdline_option(int argc, const char **argv, const char *val)
|
|
|
|
{
|
2020-12-12 06:21:40 +00:00
|
|
|
size_t n = strlen(val);
|
|
|
|
int c = argc;
|
2018-04-12 15:56:38 +08:00
|
|
|
|
2018-05-05 06:58:52 +08:00
|
|
|
while (--c > 0) {
|
2018-05-05 10:16:54 +08:00
|
|
|
|
2018-04-16 07:32:02 +08:00
|
|
|
if (!strncmp(argv[c], val, n)) {
|
2018-05-05 10:16:54 +08:00
|
|
|
if (!*(argv[c] + n) && c < argc - 1) {
|
|
|
|
/* coverity treats unchecked argv as "tainted" */
|
|
|
|
if (!argv[c + 1] || strlen(argv[c + 1]) > 1024)
|
|
|
|
return NULL;
|
2018-04-12 15:56:38 +08:00
|
|
|
return argv[c + 1];
|
2018-05-05 10:16:54 +08:00
|
|
|
}
|
2018-04-12 15:56:38 +08:00
|
|
|
|
2019-09-22 03:31:07 -07:00
|
|
|
if (argv[c][n] == '=')
|
|
|
|
return &argv[c][n + 1];
|
2018-04-12 15:56:38 +08:00
|
|
|
return argv[c] + n;
|
|
|
|
}
|
2018-05-05 06:58:52 +08:00
|
|
|
}
|
2018-04-12 15:56:38 +08:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-09-22 03:31:07 -07:00
|
|
|
static const char * const builtins[] = {
|
|
|
|
"-d",
|
2021-03-16 13:32:05 +00:00
|
|
|
"--fault-injection",
|
|
|
|
"--fault-seed",
|
2020-04-14 19:04:13 +01:00
|
|
|
"--ignore-sigterm"
|
2019-09-22 03:31:07 -07:00
|
|
|
};
|
|
|
|
|
2021-03-16 13:32:05 +00:00
|
|
|
enum opts {
|
|
|
|
OPT_DEBUGLEVEL,
|
|
|
|
OPT_FAULTINJECTION,
|
|
|
|
OPT_FAULT_SEED,
|
|
|
|
OPT_IGNORE_SIGTERM,
|
|
|
|
};
|
|
|
|
|
2020-05-14 21:28:48 +01:00
|
|
|
#if !defined(LWS_PLAT_FREERTOS)
|
2020-04-14 19:04:13 +01:00
|
|
|
static void
|
|
|
|
lws_sigterm_catch(int sig)
|
|
|
|
{
|
|
|
|
}
|
2020-05-14 21:28:48 +01:00
|
|
|
#endif
|
2020-04-14 19:04:13 +01:00
|
|
|
|
2019-09-22 03:31:07 -07:00
|
|
|
void
|
|
|
|
lws_cmdline_option_handle_builtin(int argc, const char **argv,
|
|
|
|
struct lws_context_creation_info *info)
|
|
|
|
{
|
|
|
|
const char *p;
|
|
|
|
int n, m, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
|
2021-03-16 13:32:05 +00:00
|
|
|
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
|
|
|
uint64_t seed = (uint64_t)lws_now_usecs();
|
|
|
|
#endif
|
2019-09-22 03:31:07 -07:00
|
|
|
|
|
|
|
for (n = 0; n < (int)LWS_ARRAY_SIZE(builtins); n++) {
|
|
|
|
p = lws_cmdline_option(argc, argv, builtins[n]);
|
|
|
|
if (!p)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
m = atoi(p);
|
|
|
|
|
|
|
|
switch (n) {
|
2021-03-16 13:32:05 +00:00
|
|
|
case OPT_DEBUGLEVEL:
|
2019-09-22 03:31:07 -07:00
|
|
|
logs = m;
|
|
|
|
break;
|
2021-03-16 13:32:05 +00:00
|
|
|
|
|
|
|
case OPT_FAULTINJECTION:
|
|
|
|
#if !defined(LWS_WITH_SYS_FAULT_INJECTION)
|
|
|
|
lwsl_err("%s: FAULT_INJECTION not built\n", __func__);
|
|
|
|
#endif
|
|
|
|
lws_fi_deserialize(&info->fic, p);
|
2019-09-22 03:31:07 -07:00
|
|
|
break;
|
2021-03-16 13:32:05 +00:00
|
|
|
|
|
|
|
case OPT_FAULT_SEED:
|
|
|
|
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
|
|
|
seed = (uint64_t)atoll(p);
|
2020-06-17 11:13:01 +01:00
|
|
|
#endif
|
2021-03-16 13:32:05 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OPT_IGNORE_SIGTERM:
|
2020-05-14 21:28:48 +01:00
|
|
|
#if !defined(LWS_PLAT_FREERTOS)
|
2020-04-14 19:04:13 +01:00
|
|
|
signal(SIGTERM, lws_sigterm_catch);
|
2020-05-14 21:28:48 +01:00
|
|
|
#endif
|
2020-04-14 19:04:13 +01:00
|
|
|
break;
|
2019-09-22 03:31:07 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-16 13:32:05 +00:00
|
|
|
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
|
|
|
lws_xos_init(&info->fic.xos, seed);
|
|
|
|
#endif
|
2019-09-22 03:31:07 -07:00
|
|
|
lws_set_log_level(logs, NULL);
|
2021-03-16 13:32:05 +00:00
|
|
|
|
|
|
|
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
|
|
|
|
if (info->fic.fi_owner.count)
|
|
|
|
lwsl_notice("%s: Fault Injection seed %llu\n", __func__,
|
|
|
|
(unsigned long long)seed);
|
|
|
|
#endif
|
2019-09-22 03:31:07 -07:00
|
|
|
}
|
|
|
|
|
2019-08-10 07:32:32 +01:00
|
|
|
|
|
|
|
const lws_humanize_unit_t humanize_schema_si[] = {
|
2021-01-16 07:33:37 +00:00
|
|
|
{ "Pi", LWS_PI }, { "Ti", LWS_TI }, { "Gi", LWS_GI },
|
|
|
|
{ "Mi", LWS_MI }, { "Ki", LWS_KI }, { "", 1 },
|
2019-08-10 07:32:32 +01:00
|
|
|
{ NULL, 0 }
|
|
|
|
};
|
|
|
|
const lws_humanize_unit_t humanize_schema_si_bytes[] = {
|
|
|
|
{ "PiB", LWS_PI }, { "TiB", LWS_TI }, { "GiB", LWS_GI },
|
2021-01-16 07:33:37 +00:00
|
|
|
{ "MiB", LWS_MI }, { "KiB", LWS_KI }, { "B", 1 },
|
2019-08-10 07:32:32 +01:00
|
|
|
{ NULL, 0 }
|
|
|
|
};
|
|
|
|
const lws_humanize_unit_t humanize_schema_us[] = {
|
2021-01-16 07:33:37 +00:00
|
|
|
{ "y", (uint64_t)365 * 24 * 3600 * LWS_US_PER_SEC },
|
|
|
|
{ "d", (uint64_t)24 * 3600 * LWS_US_PER_SEC },
|
|
|
|
{ "hr", (uint64_t)3600 * LWS_US_PER_SEC },
|
2019-08-10 07:32:32 +01:00
|
|
|
{ "min", 60 * LWS_US_PER_SEC },
|
2021-01-16 07:33:37 +00:00
|
|
|
{ "s", LWS_US_PER_SEC },
|
|
|
|
{ "ms", LWS_US_PER_MS },
|
|
|
|
#if defined(WIN32)
|
|
|
|
{ "us", 1 },
|
|
|
|
#else
|
|
|
|
{ "μs", 1 },
|
|
|
|
#endif
|
2019-08-10 07:32:32 +01:00
|
|
|
{ NULL, 0 }
|
|
|
|
};
|
|
|
|
|
2021-01-16 07:33:37 +00:00
|
|
|
/* biggest ull is 18446744073709551615 (20 chars) */
|
|
|
|
|
2019-11-04 14:21:11 +00:00
|
|
|
static int
|
|
|
|
decim(char *r, uint64_t v, char chars, char leading)
|
|
|
|
{
|
|
|
|
uint64_t q = 1;
|
2021-01-16 07:33:37 +00:00
|
|
|
char *ro = r;
|
|
|
|
int n = 1;
|
2019-11-04 14:21:11 +00:00
|
|
|
|
2021-01-16 07:33:37 +00:00
|
|
|
while ((leading || v > (q * 10) - 1) && n < 20 && n < chars) {
|
2019-11-04 14:21:11 +00:00
|
|
|
q = q * 10;
|
2021-01-16 07:33:37 +00:00
|
|
|
n++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* n is how many chars needed */
|
|
|
|
|
|
|
|
while (n--) {
|
|
|
|
*r++ = (char)('0' + (char)((v / q) % 10));
|
|
|
|
q = q / 10;
|
2019-11-04 14:21:11 +00:00
|
|
|
}
|
|
|
|
|
2021-01-16 07:33:37 +00:00
|
|
|
*r = '\0';
|
2019-11-04 14:21:11 +00:00
|
|
|
|
2021-01-16 07:33:37 +00:00
|
|
|
return lws_ptr_diff(r, ro);
|
2019-11-04 14:21:11 +00:00
|
|
|
}
|
|
|
|
|
2019-08-10 07:32:32 +01:00
|
|
|
int
|
2020-12-12 06:21:40 +00:00
|
|
|
lws_humanize(char *p, size_t len, uint64_t v, const lws_humanize_unit_t *schema)
|
2019-08-10 07:32:32 +01:00
|
|
|
{
|
2021-01-16 07:33:37 +00:00
|
|
|
char *obuf = p, *end = p + len;
|
2019-11-04 14:21:11 +00:00
|
|
|
|
2019-08-10 07:32:32 +01:00
|
|
|
do {
|
|
|
|
if (v >= schema->factor || schema->factor == 1) {
|
2019-11-04 14:21:11 +00:00
|
|
|
if (schema->factor == 1) {
|
|
|
|
p += decim(p, v, 4, 0);
|
2021-01-16 07:33:37 +00:00
|
|
|
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
|
|
|
|
"%s", schema->name);
|
|
|
|
return lws_ptr_diff(p, obuf);
|
2019-11-04 14:21:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
p += decim(p, v / schema->factor, 4, 0);
|
|
|
|
*p++ = '.';
|
|
|
|
p += decim(p, (v % schema->factor) /
|
|
|
|
(schema->factor / 1000), 3, 1);
|
|
|
|
|
2021-01-16 07:33:37 +00:00
|
|
|
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
|
2019-11-04 14:21:11 +00:00
|
|
|
"%s", schema->name);
|
2021-01-16 07:33:37 +00:00
|
|
|
return lws_ptr_diff(p, obuf);
|
2019-08-10 07:32:32 +01:00
|
|
|
}
|
|
|
|
schema++;
|
|
|
|
} while (schema->name);
|
|
|
|
|
|
|
|
assert(0);
|
2019-11-04 14:21:11 +00:00
|
|
|
strncpy(p, "unknown value", len);
|
2019-08-10 07:32:32 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|