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
|
|
|
*
|
2019-01-13 06:58:21 +08:00
|
|
|
* Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
|
2010-11-08 17:12:19 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation:
|
|
|
|
* version 2.1 of the License.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
|
|
* MA 02110-1301 USA
|
2010-10-31 17:51:39 +00:00
|
|
|
*/
|
|
|
|
|
2018-05-03 10:49:36 +08:00
|
|
|
#include "core/private.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
|
|
|
|
|
2018-04-27 19:16:50 +08:00
|
|
|
signed char char_to_hex(const char c)
|
|
|
|
{
|
|
|
|
if (c >= '0' && c <= '9')
|
|
|
|
return c - '0';
|
|
|
|
|
|
|
|
if (c >= 'a' && c <= 'f')
|
|
|
|
return c - 'a' + 10;
|
|
|
|
|
|
|
|
if (c >= 'A' && c <= 'F')
|
|
|
|
return c - 'A' + 10;
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
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;
|
|
|
|
|
|
|
|
*dest++ = (t << 4) | t1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (max < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return dest - odest;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-01-15 06:59:48 +08:00
|
|
|
#if !defined(LWS_PLAT_OPTEE)
|
2018-04-27 19:16:50 +08:00
|
|
|
|
2019-06-05 05:04:17 +01:00
|
|
|
#if !defined(LWS_AMAZON_RTOS)
|
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
|
|
|
|
)
|
|
|
|
/* last arg is really a mode_t. But windows... */
|
|
|
|
n = open(__file, __oflag, va_arg(ap, uint32_t));
|
|
|
|
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
|
|
|
|
2019-01-15 06:59:48 +08:00
|
|
|
#if !(defined(LWS_PLAT_OPTEE) && !defined(LWS_WITH_NETWORK))
|
|
|
|
|
2018-09-04 08:06:46 +08:00
|
|
|
LWS_VISIBLE lws_usec_t
|
|
|
|
lws_now_usecs(void)
|
|
|
|
{
|
|
|
|
struct timeval now;
|
|
|
|
|
|
|
|
gettimeofday(&now, NULL);
|
|
|
|
return (now.tv_sec * 1000000ll) + now.tv_usec;
|
|
|
|
}
|
2019-01-15 06:59:48 +08:00
|
|
|
#endif
|
2018-09-04 08:06:46 +08: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;
|
|
|
|
|
|
|
|
for (n = 0; n < context->count_threads; n++) {
|
|
|
|
if (pthread_equal(ps, pt->self))
|
|
|
|
return n;
|
|
|
|
pt++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
LWS_EXTERN void *
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
LWS_VISIBLE void
|
|
|
|
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
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
LWS_VISIBLE LWS_EXTERN unsigned long
|
|
|
|
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
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
return tv.tv_sec;
|
|
|
|
}
|
2013-10-24 22:12:03 +08:00
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
|
|
lws_compare_time_t(struct lws_context *context, time_t t1, time_t t2)
|
|
|
|
{
|
|
|
|
if (t1 < context->time_discontiguity)
|
|
|
|
t1 += context->time_fixup;
|
2015-11-08 10:15:01 +08:00
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
if (t2 < context->time_discontiguity)
|
|
|
|
t2 += context->time_fixup;
|
2015-11-08 10:15:01 +08:00
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
return (int)(t1 - t2);
|
|
|
|
}
|
2019-01-15 06:59:48 +08:00
|
|
|
#endif
|
2019-01-13 06:58:21 +08:00
|
|
|
LWS_VISIBLE extern const char *
|
|
|
|
lws_canonical_hostname(struct lws_context *context)
|
|
|
|
{
|
|
|
|
return (const char *)context->canonical_hostname;
|
2013-10-24 22:12:03 +08:00
|
|
|
}
|
|
|
|
|
2017-05-05 11:38:34 -04:00
|
|
|
#if defined(LWS_WITH_SOCKS5)
|
|
|
|
LWS_VISIBLE int
|
|
|
|
lws_set_socks(struct lws_vhost *vhost, const char *socks)
|
|
|
|
{
|
|
|
|
char *p_at, *p_colon;
|
|
|
|
char user[96];
|
|
|
|
char password[96];
|
|
|
|
|
|
|
|
if (!socks)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
vhost->socks_user[0] = '\0';
|
|
|
|
vhost->socks_password[0] = '\0';
|
|
|
|
|
2018-04-20 10:49:29 +08:00
|
|
|
p_at = strrchr(socks, '@');
|
2017-05-05 11:38:34 -04:00
|
|
|
if (p_at) { /* auth is around */
|
|
|
|
if ((unsigned int)(p_at - socks) > (sizeof(user)
|
|
|
|
+ sizeof(password) - 2)) {
|
|
|
|
lwsl_err("Socks auth too long\n");
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
|
|
|
|
p_colon = strchr(socks, ':');
|
|
|
|
if (p_colon) {
|
|
|
|
if ((unsigned int)(p_colon - socks) > (sizeof(user)
|
|
|
|
- 1) ) {
|
|
|
|
lwsl_err("Socks user too long\n");
|
|
|
|
goto bail;
|
|
|
|
}
|
|
|
|
if ((unsigned int)(p_at - p_colon) > (sizeof(password)
|
|
|
|
- 1) ) {
|
|
|
|
lwsl_err("Socks password too long\n");
|
|
|
|
goto bail;
|
|
|
|
}
|
2017-09-23 13:27:11 +08:00
|
|
|
|
2018-03-12 09:28:26 +08:00
|
|
|
lws_strncpy(vhost->socks_user, socks, p_colon - socks + 1);
|
|
|
|
lws_strncpy(vhost->socks_password, p_colon + 1,
|
|
|
|
p_at - (p_colon + 1) + 1);
|
2017-05-05 11:38:34 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
lwsl_info(" Socks auth, user: %s, password: %s\n",
|
|
|
|
vhost->socks_user, vhost->socks_password );
|
|
|
|
|
|
|
|
socks = p_at + 1;
|
|
|
|
}
|
|
|
|
|
2018-03-12 09:28:26 +08:00
|
|
|
lws_strncpy(vhost->socks_proxy_address, socks,
|
|
|
|
sizeof(vhost->socks_proxy_address));
|
2017-05-05 11:38:34 -04:00
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
p_colon = strchr(vhost->socks_proxy_address, ':');
|
|
|
|
if (!p_colon && !vhost->socks_proxy_port) {
|
|
|
|
lwsl_err("socks_proxy needs to be address:port\n");
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
if (p_colon) {
|
|
|
|
*p_colon = '\0';
|
|
|
|
vhost->socks_proxy_port = atoi(p_colon + 1);
|
|
|
|
}
|
2015-12-28 14:24:49 +08:00
|
|
|
}
|
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
lwsl_info(" Socks %s:%u\n", vhost->socks_proxy_address,
|
|
|
|
vhost->socks_proxy_port);
|
2015-12-28 14:24:49 +08:00
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
return 0;
|
2015-12-28 14:24:49 +08:00
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
bail:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
2015-12-28 14:24:49 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
2019-01-13 06:58:21 +08:00
|
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
|
|
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 */
|
|
|
|
};
|
|
|
|
|
|
|
|
LWS_EXTERN int
|
|
|
|
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)];
|
|
|
|
}
|
|
|
|
|
2015-12-30 11:43:36 +08:00
|
|
|
LWS_EXTERN int
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-06-08 10:07:02 +08:00
|
|
|
static const char *hex = "0123456789ABCDEF";
|
|
|
|
|
|
|
|
LWS_VISIBLE LWS_EXTERN const char *
|
|
|
|
lws_sql_purify(char *escaped, const char *string, int len)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-06-17 10:05:23 +08:00
|
|
|
LWS_VISIBLE LWS_EXTERN const char *
|
|
|
|
lws_json_purify(char *escaped, const char *string, int len)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-06-17 10:05:23 +08:00
|
|
|
if (*p == '\"' || *p == '\\' || *p < 0x20) {
|
|
|
|
*q++ = '\\';
|
|
|
|
*q++ = 'u';
|
|
|
|
*q++ = '0';
|
|
|
|
*q++ = '0';
|
|
|
|
*q++ = hex[((*p) >> 4) & 15];
|
|
|
|
*q++ = hex[(*p) & 15];
|
|
|
|
len -= 5;
|
|
|
|
p++;
|
|
|
|
} else
|
|
|
|
*q++ = *p++;
|
|
|
|
}
|
|
|
|
*q = '\0';
|
|
|
|
|
|
|
|
return escaped;
|
|
|
|
}
|
|
|
|
|
2018-03-29 09:28:41 +08:00
|
|
|
LWS_VISIBLE LWS_EXTERN void
|
|
|
|
lws_filename_purify_inplace(char *filename)
|
|
|
|
{
|
|
|
|
while (*filename) {
|
|
|
|
|
|
|
|
if (*filename == '.' && filename[1] == '.') {
|
|
|
|
*filename = '_';
|
|
|
|
filename[1] = '_';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*filename == ':' ||
|
|
|
|
*filename == '\\' ||
|
|
|
|
*filename == '$' ||
|
|
|
|
*filename == '%')
|
|
|
|
*filename = '_';
|
|
|
|
|
|
|
|
filename++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-08 10:07:02 +08:00
|
|
|
LWS_VISIBLE LWS_EXTERN const char *
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
|
|
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++;
|
|
|
|
sum = n << 4;
|
|
|
|
state++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
n = char_to_hex(*escaped);
|
|
|
|
if (n < 0)
|
|
|
|
return -1;
|
|
|
|
escaped++;
|
|
|
|
*string++ = sum | n;
|
|
|
|
len--;
|
|
|
|
state = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
*string = '\0';
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-03-28 10:10:43 +08:00
|
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-08-02 19:15:19 +08:00
|
|
|
LWS_VISIBLE LWS_EXTERN void
|
|
|
|
lws_get_effective_uid_gid(struct lws_context *context, int *uid, int *gid)
|
|
|
|
{
|
|
|
|
*uid = context->uid;
|
|
|
|
*gid = context->gid;
|
|
|
|
}
|
|
|
|
|
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--)
|
|
|
|
sum |= (*pa++ ^ *pb++);
|
|
|
|
|
|
|
|
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
|
|
|
#if defined(LWS_AMAZON_RTOS)
|
|
|
|
lws_tokenize_elem
|
|
|
|
#else
|
2018-10-09 10:29:42 +08:00
|
|
|
int
|
2019-06-05 05:04:17 +01:00
|
|
|
#endif
|
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;
|
2018-11-13 09:34:10 +08:00
|
|
|
char c, flo = 0, d_minus = '-', d_dot = '.', s_minus = '\0',
|
|
|
|
s_dot = '\0';
|
2019-07-20 11:26:58 -07: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 = '.';
|
|
|
|
}
|
|
|
|
|
2018-10-09 10:29:42 +08:00
|
|
|
ts->token = NULL;
|
|
|
|
ts->token_len = 0;
|
|
|
|
|
|
|
|
while (ts->len) {
|
|
|
|
c = *ts->start++;
|
|
|
|
ts->len--;
|
|
|
|
|
|
|
|
utf8 = lws_check_byte_utf8((unsigned char)utf8, c);
|
|
|
|
if (utf8 < 0)
|
|
|
|
return LWS_TOKZE_ERR_BROKEN_UTF8;
|
|
|
|
|
|
|
|
if (!c)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* 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 */
|
|
|
|
|
|
|
|
if (c == '=' && (state == LWS_TOKZS_TOKEN_POST_TERMINAL ||
|
|
|
|
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 != '_') &&
|
|
|
|
c != s_minus && c != s_dot) ||
|
|
|
|
c == d_minus || c == d_dot
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LWS_VISIBLE LWS_EXTERN int
|
|
|
|
lws_tokenize_cstr(struct lws_tokenize *ts, char *str, int max)
|
|
|
|
{
|
|
|
|
if (ts->token_len + 1 >= max)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
memcpy(str, ts->token, ts->token_len);
|
|
|
|
str[ts->token_len] = '\0';
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
LWS_VISIBLE LWS_EXTERN void
|
|
|
|
lws_tokenize_init(struct lws_tokenize *ts, const char *start, int flags)
|
|
|
|
{
|
|
|
|
ts->start = start;
|
|
|
|
ts->len = 0x7fffffff;
|
|
|
|
ts->flags = flags;
|
|
|
|
ts->delim = LWSTZ_DT_NEED_FIRST_CONTENT;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
mr->lock_owner = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
if (mr->lock_owner == pthread_self()) {
|
|
|
|
/* 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";
|
|
|
|
mr->lock_owner = 0;
|
|
|
|
//lwsl_notice("tid %d: unlock %s\n", mr->tid, mr->last_lock_reason);
|
|
|
|
pthread_mutex_unlock(&mr->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
#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)
|
|
|
|
{
|
2018-04-16 19:52:28 +08:00
|
|
|
int n = (int)strlen(val), 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
|
|
|
|
|
|
|
return argv[c] + n;
|
|
|
|
}
|
2018-05-05 06:58:52 +08:00
|
|
|
}
|
2018-04-12 15:56:38 +08:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|