mirror of
https://github.com/outbackdingo/wlan-ap.git
synced 2026-01-28 18:20:54 +00:00
opensync: Remote ssh session feature
The feature provides ability to create a remote ssh session. libwebsocket is a modified version of library hence included as a package. Signed-off-by: Ammad Rehmat <ammad.rehmat@connectus.ai>
This commit is contained in:
committed by
John Crispin
parent
0cb7073abb
commit
bd2412f02e
39
feeds/wlan-ap/libwebsocket/Makefile
Normal file
39
feeds/wlan-ap/libwebsocket/Makefile
Normal file
@@ -0,0 +1,39 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=libwebsocket
|
||||
PKG_RELEASE:=1.0.0
|
||||
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/libwebsocket
|
||||
SECTION:=base
|
||||
CATEGORY:=Base system
|
||||
TITLE:=Websocket client library
|
||||
DEPENDS:=+libopenssl
|
||||
endef
|
||||
|
||||
define Package/libwebsocket/description
|
||||
websocket library.
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
[ ! -d ./src/ ] || $(CP) ./src/* $(PKG_BUILD_DIR)
|
||||
endef
|
||||
|
||||
define Build/InstallDev
|
||||
$(INSTALL_DIR) $(1)/usr/lib
|
||||
$(INSTALL_DIR) $(1)/usr/include/websocket
|
||||
$(CP) $(PKG_BUILD_DIR)/include/websocket/* $(1)/usr/include/websocket/
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/libwebsocket.so $(1)/usr/lib/
|
||||
endef
|
||||
|
||||
define Package/libwebsocket/install
|
||||
$(INSTALL_DIR) $(1)/usr/lib
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/libwebsocket.so $(1)/usr/lib/
|
||||
endef
|
||||
$(eval $(call BuildPackage,libwebsocket))
|
||||
22
feeds/wlan-ap/libwebsocket/src/Makefile
Normal file
22
feeds/wlan-ap/libwebsocket/src/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
#/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
CC=gcc
|
||||
WFLAGS=-Wall
|
||||
CFLAGS=-O2
|
||||
INCLUDES=-Iinclude
|
||||
LIBS= -lssl
|
||||
LIBNAME=libwebsocket.so
|
||||
|
||||
CFLAGS += -O -Wall -Werror -Wshadow -fPIC
|
||||
|
||||
all: $(LIBNAME)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(WFLAGS) -c -o $@ $(INCLUDES) $(CFLAGS) $<
|
||||
|
||||
OBJS=alloc.o base64-decode.o client.o client-handshake.o client-parser.o context.o getifaddrs.o handshake.o header.o libwebsockets.o lws-plat-unix.o output.o parsers.o pollfd.o server.o server-handshake.o service.o sha-1.o ssl.o ssl-client.o ssl-server.o
|
||||
|
||||
$(LIBNAME): $(OBJS)
|
||||
$(CC) $(CFLAGS) -Wl,-Bsymbolic-functions -shared -o $@ $^ $(LIBS)
|
||||
|
||||
clean:
|
||||
$(RM) -f libwebsocket.so $(OBJS)
|
||||
31
feeds/wlan-ap/libwebsocket/src/alloc.c
Normal file
31
feeds/wlan-ap/libwebsocket/src/alloc.c
Normal file
@@ -0,0 +1,31 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
#include "websocket/private-libwebsockets.h"
|
||||
|
||||
static void *_realloc(void *ptr, size_t size)
|
||||
{
|
||||
if (size)
|
||||
return (void *)realloc(ptr, size);
|
||||
else if (ptr)
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *(*_lws_realloc)(void *ptr, size_t size) = _realloc;
|
||||
|
||||
void *lws_realloc(void *ptr, size_t size)
|
||||
{
|
||||
return _lws_realloc(ptr, size);
|
||||
}
|
||||
|
||||
void *lws_zalloc(size_t size)
|
||||
{
|
||||
void *ptr = _lws_realloc(NULL, size);
|
||||
if (ptr)
|
||||
memset(ptr, 0, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void lws_set_allocator(void *(*cb)(void *ptr, size_t size))
|
||||
{
|
||||
_lws_realloc = cb;
|
||||
}
|
||||
168
feeds/wlan-ap/libwebsocket/src/base64-decode.c
Normal file
168
feeds/wlan-ap/libwebsocket/src/base64-decode.c
Normal file
@@ -0,0 +1,168 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "websocket/private-libwebsockets.h"
|
||||
|
||||
static const char encode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static const char decode[] = "|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW"
|
||||
"$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_b64_encode_string(const char *in, int in_len, char *out, int out_size)
|
||||
{
|
||||
unsigned char triple[3];
|
||||
int i;
|
||||
int len;
|
||||
int line = 0;
|
||||
int done = 0;
|
||||
|
||||
while (in_len) {
|
||||
len = 0;
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (in_len) {
|
||||
triple[i] = *in++;
|
||||
len++;
|
||||
in_len--;
|
||||
} else
|
||||
triple[i] = 0;
|
||||
}
|
||||
|
||||
if (done + 4 >= out_size)
|
||||
return -1;
|
||||
|
||||
*out++ = encode[triple[0] >> 2];
|
||||
*out++ = encode[((triple[0] & 0x03) << 4) |
|
||||
((triple[1] & 0xf0) >> 4)];
|
||||
*out++ = (len > 1 ? encode[((triple[1] & 0x0f) << 2) |
|
||||
((triple[2] & 0xc0) >> 6)] : '=');
|
||||
*out++ = (len > 2 ? encode[triple[2] & 0x3f] : '=');
|
||||
|
||||
done += 4;
|
||||
line += 4;
|
||||
}
|
||||
|
||||
if (done + 1 >= out_size)
|
||||
return -1;
|
||||
|
||||
*out++ = '\0';
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns length of decoded string in out, or -1 if out was too small
|
||||
* according to out_size
|
||||
*/
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_b64_decode_string(const char *in, char *out, int out_size)
|
||||
{
|
||||
int len, i, c = 0, done = 0;
|
||||
unsigned char v, quad[4];
|
||||
|
||||
while (*in) {
|
||||
|
||||
len = 0;
|
||||
for (i = 0; i < 4 && *in; i++) {
|
||||
|
||||
v = 0;
|
||||
c = 0;
|
||||
while (*in && !v) {
|
||||
c = v = *in++;
|
||||
v = (v < 43 || v > 122) ? 0 : decode[v - 43];
|
||||
if (v)
|
||||
v = (v == '$') ? 0 : v - 61;
|
||||
}
|
||||
if (c) {
|
||||
len++;
|
||||
if (v)
|
||||
quad[i] = v - 1;
|
||||
} else
|
||||
quad[i] = 0;
|
||||
}
|
||||
|
||||
if (out_size < (done + len - 1))
|
||||
/* out buffer is too small */
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* "The '==' sequence indicates that the last group contained
|
||||
* only one byte, and '=' indicates that it contained two
|
||||
* bytes." (wikipedia)
|
||||
*/
|
||||
|
||||
if (!*in && c == '=')
|
||||
len--;
|
||||
|
||||
if (len >= 2)
|
||||
*out++ = quad[0] << 2 | quad[1] >> 4;
|
||||
if (len >= 3)
|
||||
*out++ = quad[1] << 4 | quad[2] >> 2;
|
||||
if (len >= 4)
|
||||
*out++ = ((quad[2] << 6) & 0xc0) | quad[3];
|
||||
|
||||
done += len - 1;
|
||||
}
|
||||
|
||||
if (done + 1 >= out_size)
|
||||
return -1;
|
||||
|
||||
*out = '\0';
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int
|
||||
lws_b64_selftest(void)
|
||||
{
|
||||
char buf[64];
|
||||
unsigned int n, r = 0;
|
||||
unsigned int test;
|
||||
/* examples from https://en.wikipedia.org/wiki/Base64 */
|
||||
static const char * const plaintext[] = {
|
||||
"any carnal pleasure.",
|
||||
"any carnal pleasure",
|
||||
"any carnal pleasur",
|
||||
"any carnal pleasu",
|
||||
"any carnal pleas",
|
||||
"Admin:kloikloi"
|
||||
};
|
||||
static const char * const coded[] = {
|
||||
"YW55IGNhcm5hbCBwbGVhc3VyZS4=",
|
||||
"YW55IGNhcm5hbCBwbGVhc3VyZQ==",
|
||||
"YW55IGNhcm5hbCBwbGVhc3Vy",
|
||||
"YW55IGNhcm5hbCBwbGVhc3U=",
|
||||
"YW55IGNhcm5hbCBwbGVhcw==",
|
||||
"QWRtaW46a2xvaWtsb2k="
|
||||
};
|
||||
|
||||
for (test = 0; test < sizeof plaintext / sizeof(plaintext[0]); test++) {
|
||||
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
n = lws_b64_encode_string(plaintext[test],
|
||||
strlen(plaintext[test]), buf, sizeof buf);
|
||||
if (n != strlen(coded[test]) || strcmp(buf, coded[test])) {
|
||||
lwsl_err("Failed lws_b64 encode selftest "
|
||||
"%d result '%s' %d\n", test, buf, n);
|
||||
r = -1;
|
||||
}
|
||||
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
n = lws_b64_decode_string(coded[test], buf, sizeof buf);
|
||||
if (n != strlen(plaintext[test]) ||
|
||||
strcmp(buf, plaintext[test])) {
|
||||
lwsl_err("Failed lws_b64 decode selftest "
|
||||
"%d result '%s' / '%s', %d / %d\n",
|
||||
test, buf, plaintext[test], n, strlen(plaintext[test]));
|
||||
r = -1;
|
||||
}
|
||||
}
|
||||
|
||||
lwsl_notice("Base 64 selftests passed\n");
|
||||
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
752
feeds/wlan-ap/libwebsocket/src/client-handshake.c
Normal file
752
feeds/wlan-ap/libwebsocket/src/client-handshake.c
Normal file
@@ -0,0 +1,752 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
#include "websocket/private-libwebsockets.h"
|
||||
|
||||
struct lws *
|
||||
lws_client_connect_2(struct lws *wsi)
|
||||
{
|
||||
#ifdef LWS_USE_IPV6
|
||||
struct sockaddr_in6 server_addr6;
|
||||
struct addrinfo hints, *result;
|
||||
#endif
|
||||
struct lws_context *context = wsi->context;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
struct sockaddr_in server_addr4;
|
||||
struct lws_pollfd pfd;
|
||||
struct sockaddr *v;
|
||||
const char *cce = "";
|
||||
int n, plen = 0;
|
||||
const char *ads;
|
||||
|
||||
lwsl_client("%s\n", __func__);
|
||||
|
||||
if (!wsi->u.hdr.ah) {
|
||||
cce = "ah was NULL at cc2";
|
||||
lwsl_err("%s\n", cce);
|
||||
goto oom4;
|
||||
}
|
||||
|
||||
/* proxy? */
|
||||
|
||||
if (wsi->vhost->http_proxy_port) {
|
||||
plen = sprintf((char *)pt->serv_buf,
|
||||
"CONNECT %s:%u HTTP/1.0\x0d\x0a"
|
||||
"User-agent: libwebsockets\x0d\x0a",
|
||||
lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS),
|
||||
wsi->u.hdr.c_port);
|
||||
|
||||
if (wsi->vhost->proxy_basic_auth_token[0])
|
||||
plen += sprintf((char *)pt->serv_buf + plen,
|
||||
"Proxy-authorization: basic %s\x0d\x0a",
|
||||
wsi->vhost->proxy_basic_auth_token);
|
||||
|
||||
plen += sprintf((char *)pt->serv_buf + plen, "\x0d\x0a");
|
||||
ads = wsi->vhost->http_proxy_address;
|
||||
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (LWS_IPV6_ENABLED(wsi->vhost)) {
|
||||
memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
|
||||
server_addr6.sin6_port = htons(wsi->vhost->http_proxy_port);
|
||||
} else
|
||||
#endif
|
||||
server_addr4.sin_port = htons(wsi->vhost->http_proxy_port);
|
||||
|
||||
} else {
|
||||
ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (LWS_IPV6_ENABLED(wsi->vhost)) {
|
||||
memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
|
||||
server_addr6.sin6_port = htons(wsi->u.hdr.c_port);
|
||||
} else
|
||||
#endif
|
||||
server_addr4.sin_port = htons(wsi->u.hdr.c_port);
|
||||
}
|
||||
|
||||
/*
|
||||
* prepare the actual connection (to the proxy, if any)
|
||||
*/
|
||||
lwsl_client("%s: address %s\n", __func__, ads);
|
||||
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (LWS_IPV6_ENABLED(wsi->vhost)) {
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
#if !defined(__ANDROID__)
|
||||
hints.ai_family = AF_INET6;
|
||||
hints.ai_flags = AI_V4MAPPED;
|
||||
#endif
|
||||
n = getaddrinfo(ads, NULL, &hints, &result);
|
||||
if (n) {
|
||||
#ifdef _WIN32
|
||||
lwsl_err("getaddrinfo: %ls\n", gai_strerrorW(n));
|
||||
#else
|
||||
lwsl_err("getaddrinfo: %s\n", gai_strerror(n));
|
||||
#endif
|
||||
cce = "getaddrinfo (ipv6) failed";
|
||||
goto oom4;
|
||||
}
|
||||
|
||||
server_addr6.sin6_family = AF_INET6;
|
||||
switch (result->ai_family) {
|
||||
#if defined(__ANDROID__)
|
||||
case AF_INET:
|
||||
/* map IPv4 to IPv6 */
|
||||
bzero((char *)&server_addr6.sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
server_addr6.sin6_addr.s6_addr[10] = 0xff;
|
||||
server_addr6.sin6_addr.s6_addr[11] = 0xff;
|
||||
memcpy(&server_addr6.sin6_addr.s6_addr[12],
|
||||
&((struct sockaddr_in *)result->ai_addr)->sin_addr,
|
||||
sizeof(struct in_addr));
|
||||
break;
|
||||
#endif
|
||||
case AF_INET6:
|
||||
memcpy(&server_addr6.sin6_addr,
|
||||
&((struct sockaddr_in6 *)result->ai_addr)->sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
break;
|
||||
default:
|
||||
lwsl_err("Unknown address family\n");
|
||||
freeaddrinfo(result);
|
||||
cce = "unknown address family";
|
||||
goto oom4;
|
||||
}
|
||||
|
||||
freeaddrinfo(result);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
struct addrinfo ai, *res, *result;
|
||||
void *p = NULL;
|
||||
|
||||
memset (&ai, 0, sizeof ai);
|
||||
ai.ai_family = PF_UNSPEC;
|
||||
ai.ai_socktype = SOCK_STREAM;
|
||||
ai.ai_flags = AI_CANONNAME;
|
||||
|
||||
if (getaddrinfo(ads, NULL, &ai, &result)) {
|
||||
lwsl_err("getaddrinfo failed\n");
|
||||
cce = "getaddrinfo (ipv4) failed";
|
||||
goto oom4;
|
||||
}
|
||||
|
||||
res = result;
|
||||
while (!p && res) {
|
||||
switch (res->ai_family) {
|
||||
case AF_INET:
|
||||
p = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
|
||||
break;
|
||||
}
|
||||
|
||||
res = res->ai_next;
|
||||
}
|
||||
|
||||
if (!p) {
|
||||
lwsl_err("Couldn't identify address\n");
|
||||
freeaddrinfo(result);
|
||||
goto oom4;
|
||||
}
|
||||
|
||||
server_addr4.sin_family = AF_INET;
|
||||
server_addr4.sin_addr = *((struct in_addr *)p);
|
||||
bzero(&server_addr4.sin_zero, 8);
|
||||
freeaddrinfo(result);
|
||||
}
|
||||
|
||||
if (!lws_socket_is_valid(wsi->sock)) {
|
||||
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (LWS_IPV6_ENABLED(wsi->vhost))
|
||||
wsi->sock = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
else
|
||||
#endif
|
||||
wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if (!lws_socket_is_valid(wsi->sock)) {
|
||||
lwsl_warn("Unable to open socket\n");
|
||||
goto oom4;
|
||||
}
|
||||
|
||||
if (lws_plat_set_socket_options(wsi->vhost, wsi->sock)) {
|
||||
lwsl_err("Failed to set wsi socket options\n");
|
||||
compatible_close(wsi->sock);
|
||||
cce = "set socket opts failed";
|
||||
goto oom4;
|
||||
}
|
||||
|
||||
wsi->mode = LWSCM_WSCL_WAITING_CONNECT;
|
||||
|
||||
lws_libev_accept(wsi, wsi->sock);
|
||||
lws_libuv_accept(wsi, wsi->sock);
|
||||
if (insert_wsi_socket_into_fds(context, wsi)) {
|
||||
compatible_close(wsi->sock);
|
||||
cce = "insert wsi failed";
|
||||
goto oom4;
|
||||
}
|
||||
|
||||
lws_change_pollfd(wsi, 0, LWS_POLLIN);
|
||||
|
||||
/*
|
||||
* past here, we can't simply free the structs as error
|
||||
* handling as oom4 does. We have to run the whole close flow.
|
||||
*/
|
||||
|
||||
if (!wsi->protocol)
|
||||
wsi->protocol = &wsi->vhost->protocols[0];
|
||||
|
||||
wsi->protocol->callback(wsi, LWS_CALLBACK_WSI_CREATE,
|
||||
wsi->user_space, NULL, 0);
|
||||
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
|
||||
AWAITING_TIMEOUT);
|
||||
|
||||
n = lws_socket_bind(wsi->vhost, wsi->sock, 0, wsi->vhost->iface);
|
||||
if (n < 0)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (LWS_IPV6_ENABLED(wsi->vhost)) {
|
||||
v = (struct sockaddr *)&server_addr6;
|
||||
n = sizeof(struct sockaddr_in6);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
v = (struct sockaddr *)&server_addr4;
|
||||
n = sizeof(struct sockaddr);
|
||||
}
|
||||
|
||||
if (connect(wsi->sock, v, n) == -1 || LWS_ERRNO == LWS_EISCONN) {
|
||||
if (LWS_ERRNO == LWS_EALREADY ||
|
||||
LWS_ERRNO == LWS_EINPROGRESS ||
|
||||
LWS_ERRNO == LWS_EWOULDBLOCK
|
||||
#ifdef _WIN32
|
||||
|| LWS_ERRNO == WSAEINVAL
|
||||
#endif
|
||||
) {
|
||||
lwsl_client("nonblocking connect retry (errno = %d)\n",
|
||||
LWS_ERRNO);
|
||||
|
||||
if (lws_plat_check_connection_error(wsi))
|
||||
goto failed;
|
||||
|
||||
/*
|
||||
* must do specifically a POLLOUT poll to hear
|
||||
* about the connect completion
|
||||
*/
|
||||
if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
|
||||
goto failed;
|
||||
|
||||
return wsi;
|
||||
}
|
||||
|
||||
if (LWS_ERRNO != LWS_EISCONN) {
|
||||
lwsl_debug("Connect failed errno=%d\n", LWS_ERRNO);
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
lwsl_client("connected\n");
|
||||
|
||||
/* we are connected to server, or proxy */
|
||||
|
||||
if (wsi->vhost->http_proxy_port) {
|
||||
|
||||
/*
|
||||
* OK from now on we talk via the proxy, so connect to that
|
||||
*
|
||||
* (will overwrite existing pointer,
|
||||
* leaving old string/frag there but unreferenced)
|
||||
*/
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
|
||||
wsi->vhost->http_proxy_address))
|
||||
goto failed;
|
||||
wsi->u.hdr.c_port = wsi->vhost->http_proxy_port;
|
||||
|
||||
n = send(wsi->sock, (char *)pt->serv_buf, plen,
|
||||
MSG_NOSIGNAL);
|
||||
if (n < 0) {
|
||||
lwsl_debug("ERROR writing to proxy socket\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
|
||||
AWAITING_TIMEOUT);
|
||||
|
||||
wsi->mode = LWSCM_WSCL_WAITING_PROXY_REPLY;
|
||||
|
||||
return wsi;
|
||||
}
|
||||
|
||||
/*
|
||||
* provoke service to issue the handshake directly
|
||||
* we need to do it this way because in the proxy case, this is the
|
||||
* next state and executed only if and when we get a good proxy
|
||||
* response inside the state machine... but notice in SSL case this
|
||||
* may not have sent anything yet with 0 return, and won't until some
|
||||
* many retries from main loop. To stop that becoming endless,
|
||||
* cover with a timeout.
|
||||
*/
|
||||
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
|
||||
AWAITING_TIMEOUT);
|
||||
|
||||
wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE;
|
||||
pfd.fd = wsi->sock;
|
||||
pfd.events = LWS_POLLIN;
|
||||
pfd.revents = LWS_POLLIN;
|
||||
|
||||
n = lws_service_fd(context, &pfd);
|
||||
if (n < 0)
|
||||
goto failed;
|
||||
if (n) /* returns 1 on failure after closing wsi */
|
||||
return NULL;
|
||||
|
||||
return wsi;
|
||||
|
||||
oom4:
|
||||
/* we're closing, losing some rx is OK */
|
||||
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
|
||||
//lwsl_err("%d\n", wsi->mode);
|
||||
if (wsi->mode == LWSCM_HTTP_CLIENT) {
|
||||
wsi->vhost->protocols[0].callback(wsi,
|
||||
LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
|
||||
wsi->user_space, (void *)cce, strlen(cce));
|
||||
wsi->already_did_cce = 1;
|
||||
}
|
||||
/* take care that we might be inserted in fds already */
|
||||
if (wsi->position_in_fds_table != -1)
|
||||
goto failed;
|
||||
lws_header_table_detach(wsi, 0);
|
||||
lws_free(wsi);
|
||||
|
||||
return NULL;
|
||||
|
||||
failed:
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* lws_client_reset() - retarget a connected wsi to start over with a new connection (ie, redirect)
|
||||
* this only works if still in HTTP, ie, not upgraded yet
|
||||
* wsi: connection to reset
|
||||
* address: network address of the new server
|
||||
* port: port to connect to
|
||||
* path: uri path to connect to on the new server
|
||||
* host: host header to send to the new server
|
||||
*/
|
||||
LWS_VISIBLE struct lws *
|
||||
lws_client_reset(struct lws *wsi, int ssl, const char *address, int port, const char *path, const char *host)
|
||||
{
|
||||
if (wsi->u.hdr.redirects == 3) {
|
||||
lwsl_err("%s: Too many redirects\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
wsi->u.hdr.redirects++;
|
||||
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
wsi->use_ssl = ssl;
|
||||
#else
|
||||
if (ssl) {
|
||||
lwsl_err("%s: not configured for ssl\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
lwsl_notice("redirect ads='%s', port=%d, path='%s'\n", address, port, path);
|
||||
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
|
||||
return NULL;
|
||||
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, path))
|
||||
return NULL;
|
||||
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
|
||||
return NULL;
|
||||
|
||||
compatible_close(wsi->sock);
|
||||
remove_wsi_socket_from_fds(wsi);
|
||||
wsi->sock = LWS_SOCK_INVALID;
|
||||
wsi->state = LWSS_CLIENT_UNCONNECTED;
|
||||
wsi->protocol = NULL;
|
||||
wsi->pending_timeout = NO_PENDING_TIMEOUT;
|
||||
wsi->u.hdr.c_port = port;
|
||||
|
||||
return lws_client_connect_2(wsi);
|
||||
}
|
||||
|
||||
#ifdef LWS_WITH_HTTP_PROXY
|
||||
static hubbub_error
|
||||
html_parser_cb(const hubbub_token *token, void *pw)
|
||||
{
|
||||
struct lws_rewrite *r = (struct lws_rewrite *)pw;
|
||||
char buf[1024], *start = buf + LWS_PRE, *p = start,
|
||||
*end = &buf[sizeof(buf) - 1];
|
||||
size_t i;
|
||||
|
||||
switch (token->type) {
|
||||
case HUBBUB_TOKEN_DOCTYPE:
|
||||
|
||||
p += lws_snprintf(p, end - p, "<!DOCTYPE %.*s %s ",
|
||||
(int) token->data.doctype.name.len,
|
||||
token->data.doctype.name.ptr,
|
||||
token->data.doctype.force_quirks ?
|
||||
"(force-quirks) " : "");
|
||||
|
||||
if (token->data.doctype.public_missing)
|
||||
printf("\tpublic: missing\n");
|
||||
else
|
||||
p += lws_snprintf(p, end - p, "PUBLIC \"%.*s\"\n",
|
||||
(int) token->data.doctype.public_id.len,
|
||||
token->data.doctype.public_id.ptr);
|
||||
|
||||
if (token->data.doctype.system_missing)
|
||||
printf("\tsystem: missing\n");
|
||||
else
|
||||
p += lws_snprintf(p, end - p, " \"%.*s\">\n",
|
||||
(int) token->data.doctype.system_id.len,
|
||||
token->data.doctype.system_id.ptr);
|
||||
|
||||
break;
|
||||
case HUBBUB_TOKEN_START_TAG:
|
||||
p += lws_snprintf(p, end - p, "<%.*s", (int)token->data.tag.name.len,
|
||||
token->data.tag.name.ptr);
|
||||
|
||||
/* (token->data.tag.self_closing) ?
|
||||
"(self-closing) " : "",
|
||||
(token->data.tag.n_attributes > 0) ?
|
||||
"attributes:" : "");
|
||||
*/
|
||||
for (i = 0; i < token->data.tag.n_attributes; i++) {
|
||||
if (!hstrcmp(&token->data.tag.attributes[i].name, "href", 4) ||
|
||||
!hstrcmp(&token->data.tag.attributes[i].name, "action", 6) ||
|
||||
!hstrcmp(&token->data.tag.attributes[i].name, "src", 3)) {
|
||||
const char *pp = (const char *)token->data.tag.attributes[i].value.ptr;
|
||||
int plen = (int) token->data.tag.attributes[i].value.len;
|
||||
|
||||
if (!hstrcmp(&token->data.tag.attributes[i].value,
|
||||
r->from, r->from_len)) {
|
||||
pp += r->from_len;
|
||||
plen -= r->from_len;
|
||||
}
|
||||
p += lws_snprintf(p, end - p, " %.*s=\"%s/%.*s\"",
|
||||
(int) token->data.tag.attributes[i].name.len,
|
||||
token->data.tag.attributes[i].name.ptr,
|
||||
r->to, plen, pp);
|
||||
|
||||
} else
|
||||
|
||||
p += lws_snprintf(p, end - p, " %.*s=\"%.*s\"",
|
||||
(int) token->data.tag.attributes[i].name.len,
|
||||
token->data.tag.attributes[i].name.ptr,
|
||||
(int) token->data.tag.attributes[i].value.len,
|
||||
token->data.tag.attributes[i].value.ptr);
|
||||
}
|
||||
p += lws_snprintf(p, end - p, ">\n");
|
||||
break;
|
||||
case HUBBUB_TOKEN_END_TAG:
|
||||
p += lws_snprintf(p, end - p, "</%.*s", (int) token->data.tag.name.len,
|
||||
token->data.tag.name.ptr);
|
||||
/*
|
||||
(token->data.tag.self_closing) ?
|
||||
"(self-closing) " : "",
|
||||
(token->data.tag.n_attributes > 0) ?
|
||||
"attributes:" : "");
|
||||
*/
|
||||
for (i = 0; i < token->data.tag.n_attributes; i++) {
|
||||
p += lws_snprintf(p, end - p, " %.*s='%.*s'\n",
|
||||
(int) token->data.tag.attributes[i].name.len,
|
||||
token->data.tag.attributes[i].name.ptr,
|
||||
(int) token->data.tag.attributes[i].value.len,
|
||||
token->data.tag.attributes[i].value.ptr);
|
||||
}
|
||||
p += lws_snprintf(p, end - p, ">\n");
|
||||
break;
|
||||
case HUBBUB_TOKEN_COMMENT:
|
||||
p += lws_snprintf(p, end - p, "<!-- %.*s -->\n",
|
||||
(int) token->data.comment.len,
|
||||
token->data.comment.ptr);
|
||||
break;
|
||||
case HUBBUB_TOKEN_CHARACTER:
|
||||
p += lws_snprintf(p, end - p, "%.*s", (int) token->data.character.len,
|
||||
token->data.character.ptr);
|
||||
break;
|
||||
case HUBBUB_TOKEN_EOF:
|
||||
p += lws_snprintf(p, end - p, "\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (user_callback_handle_rxflow(r->wsi->protocol->callback,
|
||||
r->wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,
|
||||
r->wsi->user_space, start, p - start))
|
||||
return -1;
|
||||
|
||||
return HUBBUB_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
LWS_VISIBLE struct lws *
|
||||
lws_client_connect_via_info(struct lws_client_connect_info *i)
|
||||
{
|
||||
struct lws *wsi;
|
||||
int v = SPEC_LATEST_SUPPORTED;
|
||||
|
||||
if (i->context->requested_kill)
|
||||
return NULL;
|
||||
|
||||
if (!i->context->protocol_init_done)
|
||||
lws_protocol_init(i->context);
|
||||
|
||||
wsi = lws_zalloc(sizeof(struct lws));
|
||||
if (wsi == NULL)
|
||||
goto bail;
|
||||
|
||||
wsi->context = i->context;
|
||||
/* assert the mode and union status (hdr) clearly */
|
||||
lws_union_transition(wsi, LWSCM_HTTP_CLIENT);
|
||||
wsi->sock = LWS_SOCK_INVALID;
|
||||
|
||||
/* 1) fill up the wsi with stuff from the connect_info as far as it
|
||||
* can go. It's because not only is our connection async, we might
|
||||
* not even be able to get ahold of an ah at this point.
|
||||
*/
|
||||
|
||||
/* -1 means just use latest supported */
|
||||
if (i->ietf_version_or_minus_one != -1 && i->ietf_version_or_minus_one)
|
||||
v = i->ietf_version_or_minus_one;
|
||||
|
||||
wsi->ietf_spec_revision = v;
|
||||
wsi->user_space = NULL;
|
||||
wsi->state = LWSS_CLIENT_UNCONNECTED;
|
||||
wsi->protocol = NULL;
|
||||
wsi->pending_timeout = NO_PENDING_TIMEOUT;
|
||||
wsi->position_in_fds_table = -1;
|
||||
wsi->u.hdr.c_port = i->port;
|
||||
wsi->vhost = i->vhost;
|
||||
if (!wsi->vhost)
|
||||
wsi->vhost = i->context->vhost_list;
|
||||
|
||||
wsi->protocol = &wsi->vhost->protocols[0];
|
||||
if (wsi && !wsi->user_space && i->userdata) {
|
||||
wsi->user_space_externally_allocated = 1;
|
||||
wsi->user_space = i->userdata;
|
||||
} else
|
||||
/* if we stay in http, we can assign the user space now,
|
||||
* otherwise do it after the protocol negotiated
|
||||
*/
|
||||
if (i->method)
|
||||
if (lws_ensure_user_space(wsi))
|
||||
goto bail;
|
||||
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
wsi->use_ssl = i->ssl_connection;
|
||||
#else
|
||||
if (i->ssl_connection) {
|
||||
lwsl_err("libwebsockets not configured for ssl\n");
|
||||
goto bail;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 2) stash the things from connect_info that we can't process without
|
||||
* an ah. Because if no ah, we will go on the ah waiting list and
|
||||
* process those things later (after the connect_info and maybe the
|
||||
* things pointed to have gone out of scope.
|
||||
*/
|
||||
|
||||
wsi->u.hdr.stash = lws_malloc(sizeof(*wsi->u.hdr.stash));
|
||||
if (!wsi->u.hdr.stash) {
|
||||
lwsl_err("%s: OOM\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
wsi->u.hdr.stash->origin[0] = '\0';
|
||||
wsi->u.hdr.stash->protocol[0] = '\0';
|
||||
wsi->u.hdr.stash->method[0] = '\0';
|
||||
|
||||
strncpy(wsi->u.hdr.stash->address, i->address,
|
||||
sizeof(wsi->u.hdr.stash->address) - 1);
|
||||
strncpy(wsi->u.hdr.stash->path, i->path,
|
||||
sizeof(wsi->u.hdr.stash->path) - 1);
|
||||
strncpy(wsi->u.hdr.stash->host, i->host,
|
||||
sizeof(wsi->u.hdr.stash->host) - 1);
|
||||
if (i->origin)
|
||||
strncpy(wsi->u.hdr.stash->origin, i->origin,
|
||||
sizeof(wsi->u.hdr.stash->origin) - 1);
|
||||
if (i->protocol)
|
||||
strncpy(wsi->u.hdr.stash->protocol, i->protocol,
|
||||
sizeof(wsi->u.hdr.stash->protocol) - 1);
|
||||
if (i->method)
|
||||
strncpy(wsi->u.hdr.stash->method, i->method,
|
||||
sizeof(wsi->u.hdr.stash->method) - 1);
|
||||
|
||||
wsi->u.hdr.stash->address[sizeof(wsi->u.hdr.stash->address) - 1] = '\0';
|
||||
wsi->u.hdr.stash->path[sizeof(wsi->u.hdr.stash->path) - 1] = '\0';
|
||||
wsi->u.hdr.stash->host[sizeof(wsi->u.hdr.stash->host) - 1] = '\0';
|
||||
wsi->u.hdr.stash->origin[sizeof(wsi->u.hdr.stash->origin) - 1] = '\0';
|
||||
wsi->u.hdr.stash->protocol[sizeof(wsi->u.hdr.stash->protocol) - 1] = '\0';
|
||||
wsi->u.hdr.stash->method[sizeof(wsi->u.hdr.stash->method) - 1] = '\0';
|
||||
|
||||
if (i->pwsi)
|
||||
*i->pwsi = wsi;
|
||||
|
||||
/* if we went on the waiting list, no probs just return the wsi
|
||||
* when we get the ah, now or later, he will call
|
||||
* lws_client_connect_via_info2() below.
|
||||
*/
|
||||
if (lws_header_table_attach(wsi, 0) < 0) {
|
||||
/*
|
||||
* if we failed here, the connection is already closed
|
||||
* and freed.
|
||||
*/
|
||||
goto bail1;
|
||||
}
|
||||
|
||||
if (i->parent_wsi) {
|
||||
lwsl_info("%s: created child %p of parent %p\n", __func__,
|
||||
wsi, i->parent_wsi);
|
||||
wsi->parent = i->parent_wsi;
|
||||
wsi->sibling_list = i->parent_wsi->child_list;
|
||||
i->parent_wsi->child_list = wsi;
|
||||
}
|
||||
#ifdef LWS_WITH_HTTP_PROXY
|
||||
if (i->uri_replace_to)
|
||||
wsi->rw = lws_rewrite_create(wsi, html_parser_cb,
|
||||
i->uri_replace_from,
|
||||
i->uri_replace_to);
|
||||
#endif
|
||||
|
||||
return wsi;
|
||||
|
||||
bail:
|
||||
lws_free(wsi);
|
||||
|
||||
bail1:
|
||||
if (i->pwsi)
|
||||
*i->pwsi = NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct lws *
|
||||
lws_client_connect_via_info2(struct lws *wsi)
|
||||
{
|
||||
struct client_info_stash *stash = wsi->u.hdr.stash;
|
||||
|
||||
if (!stash)
|
||||
return wsi;
|
||||
|
||||
/*
|
||||
* we're not necessarily in a position to action these right away,
|
||||
* stash them... we only need during connect phase so u.hdr is fine
|
||||
*/
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
|
||||
stash->address))
|
||||
goto bail1;
|
||||
|
||||
/* these only need u.hdr lifetime as well */
|
||||
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, stash->path))
|
||||
goto bail1;
|
||||
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, stash->host))
|
||||
goto bail1;
|
||||
|
||||
if (stash->origin[0])
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN,
|
||||
stash->origin))
|
||||
goto bail1;
|
||||
/*
|
||||
* this is a list of protocols we tell the server we're okay with
|
||||
* stash it for later when we compare server response with it
|
||||
*/
|
||||
if (stash->protocol[0])
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
|
||||
stash->protocol))
|
||||
goto bail1;
|
||||
if (stash->method[0])
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_METHOD,
|
||||
stash->method))
|
||||
goto bail1;
|
||||
|
||||
lws_free_set_NULL(wsi->u.hdr.stash);
|
||||
|
||||
/*
|
||||
* Check with each extension if it is able to route and proxy this
|
||||
* connection for us. For example, an extension like x-google-mux
|
||||
* can handle this and then we don't need an actual socket for this
|
||||
* connection.
|
||||
*/
|
||||
|
||||
if (lws_ext_cb_all_exts(wsi->context, wsi,
|
||||
LWS_EXT_CB_CAN_PROXY_CLIENT_CONNECTION,
|
||||
(void *)stash->address,
|
||||
wsi->u.hdr.c_port) > 0) {
|
||||
lwsl_client("lws_client_connect: ext handling conn\n");
|
||||
|
||||
lws_set_timeout(wsi,
|
||||
PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE,
|
||||
AWAITING_TIMEOUT);
|
||||
|
||||
wsi->mode = LWSCM_WSCL_WAITING_EXTENSION_CONNECT;
|
||||
return wsi;
|
||||
}
|
||||
lwsl_client("lws_client_connect: direct conn\n");
|
||||
wsi->context->count_wsi_allocated++;
|
||||
|
||||
return lws_client_connect_2(wsi);
|
||||
|
||||
bail1:
|
||||
lws_free_set_NULL(wsi->u.hdr.stash);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LWS_VISIBLE struct lws *
|
||||
lws_client_connect_extended(struct lws_context *context, const char *address,
|
||||
int port, int ssl_connection, const char *path,
|
||||
const char *host, const char *origin,
|
||||
const char *protocol, int ietf_version_or_minus_one,
|
||||
void *userdata)
|
||||
{
|
||||
struct lws_client_connect_info i;
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
|
||||
i.context = context;
|
||||
i.address = address;
|
||||
i.port = port;
|
||||
i.ssl_connection = ssl_connection;
|
||||
i.path = path;
|
||||
i.host = host;
|
||||
i.origin = origin;
|
||||
i.protocol = protocol;
|
||||
i.ietf_version_or_minus_one = ietf_version_or_minus_one;
|
||||
i.userdata = userdata;
|
||||
|
||||
return lws_client_connect_via_info(&i);
|
||||
}
|
||||
|
||||
LWS_VISIBLE struct lws *
|
||||
lws_client_connect(struct lws_context *context, const char *address,
|
||||
int port, int ssl_connection, const char *path,
|
||||
const char *host, const char *origin,
|
||||
const char *protocol, int ietf_version_or_minus_one)
|
||||
{
|
||||
struct lws_client_connect_info i;
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
|
||||
i.context = context;
|
||||
i.address = address;
|
||||
i.port = port;
|
||||
i.ssl_connection = ssl_connection;
|
||||
i.path = path;
|
||||
i.host = host;
|
||||
i.origin = origin;
|
||||
i.protocol = protocol;
|
||||
i.ietf_version_or_minus_one = ietf_version_or_minus_one;
|
||||
i.userdata = NULL;
|
||||
|
||||
return lws_client_connect_via_info(&i);
|
||||
}
|
||||
|
||||
551
feeds/wlan-ap/libwebsocket/src/client-parser.c
Normal file
551
feeds/wlan-ap/libwebsocket/src/client-parser.c
Normal file
@@ -0,0 +1,551 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#include "websocket/private-libwebsockets.h"
|
||||
|
||||
int lws_client_rx_sm(struct lws *wsi, unsigned char c)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
int callback_action = LWS_CALLBACK_CLIENT_RECEIVE;
|
||||
int handled, n, m, rx_draining_ext = 0;
|
||||
unsigned short close_code;
|
||||
struct lws_tokens eff_buf;
|
||||
unsigned char *pp;
|
||||
|
||||
if (wsi->u.ws.rx_draining_ext) {
|
||||
struct lws **w = &pt->rx_draining_ext_list;
|
||||
lwsl_ext("%s: RX EXT DRAINING: Removing from list\n", __func__, c);
|
||||
assert(!c);
|
||||
eff_buf.token = NULL;
|
||||
eff_buf.token_len = 0;
|
||||
wsi->u.ws.rx_draining_ext = 0;
|
||||
/* remove us from context draining ext list */
|
||||
while (*w) {
|
||||
if (*w == wsi) {
|
||||
*w = wsi->u.ws.rx_draining_ext_list;
|
||||
break;
|
||||
}
|
||||
w = &((*w)->u.ws.rx_draining_ext_list);
|
||||
}
|
||||
wsi->u.ws.rx_draining_ext_list = NULL;
|
||||
rx_draining_ext = 1;
|
||||
|
||||
goto drain_extension;
|
||||
}
|
||||
|
||||
switch (wsi->lws_rx_parse_state) {
|
||||
case LWS_RXPS_NEW:
|
||||
/* control frames (PING) may interrupt checkable sequences */
|
||||
wsi->u.ws.defeat_check_utf8 = 0;
|
||||
|
||||
switch (wsi->ietf_spec_revision) {
|
||||
case 13:
|
||||
wsi->u.ws.opcode = c & 0xf;
|
||||
/* revisit if an extension wants them... */
|
||||
switch (wsi->u.ws.opcode) {
|
||||
case LWSWSOPC_TEXT_FRAME:
|
||||
wsi->u.ws.rsv_first_msg = (c & 0x70);
|
||||
wsi->u.ws.continuation_possible = 1;
|
||||
wsi->u.ws.check_utf8 = lws_check_opt(
|
||||
wsi->context->options,
|
||||
LWS_SERVER_OPTION_VALIDATE_UTF8);
|
||||
wsi->u.ws.utf8 = 0;
|
||||
break;
|
||||
case LWSWSOPC_BINARY_FRAME:
|
||||
wsi->u.ws.rsv_first_msg = (c & 0x70);
|
||||
wsi->u.ws.check_utf8 = 0;
|
||||
wsi->u.ws.continuation_possible = 1;
|
||||
break;
|
||||
case LWSWSOPC_CONTINUATION:
|
||||
if (!wsi->u.ws.continuation_possible) {
|
||||
lwsl_info("disordered continuation\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case LWSWSOPC_CLOSE:
|
||||
wsi->u.ws.check_utf8 = 0;
|
||||
wsi->u.ws.utf8 = 0;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 0xb:
|
||||
case 0xc:
|
||||
case 0xd:
|
||||
case 0xe:
|
||||
case 0xf:
|
||||
lwsl_info("illegal opcode\n");
|
||||
return -1;
|
||||
default:
|
||||
wsi->u.ws.defeat_check_utf8 = 1;
|
||||
break;
|
||||
}
|
||||
wsi->u.ws.rsv = (c & 0x70);
|
||||
/* revisit if an extension wants them... */
|
||||
if (
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
!wsi->count_act_ext &&
|
||||
#endif
|
||||
wsi->u.ws.rsv) {
|
||||
lwsl_info("illegal rsv bits set\n");
|
||||
return -1;
|
||||
}
|
||||
wsi->u.ws.final = !!((c >> 7) & 1);
|
||||
lwsl_ext("%s: This RX frame Final %d\n", __func__, wsi->u.ws.final);
|
||||
|
||||
if (wsi->u.ws.owed_a_fin &&
|
||||
(wsi->u.ws.opcode == LWSWSOPC_TEXT_FRAME ||
|
||||
wsi->u.ws.opcode == LWSWSOPC_BINARY_FRAME)) {
|
||||
lwsl_info("hey you owed us a FIN\n");
|
||||
return -1;
|
||||
}
|
||||
if ((!(wsi->u.ws.opcode & 8)) && wsi->u.ws.final) {
|
||||
wsi->u.ws.continuation_possible = 0;
|
||||
wsi->u.ws.owed_a_fin = 0;
|
||||
}
|
||||
|
||||
if ((wsi->u.ws.opcode & 8) && !wsi->u.ws.final) {
|
||||
lwsl_info("control message cannot be fragmented\n");
|
||||
return -1;
|
||||
}
|
||||
if (!wsi->u.ws.final)
|
||||
wsi->u.ws.owed_a_fin = 1;
|
||||
|
||||
switch (wsi->u.ws.opcode) {
|
||||
case LWSWSOPC_TEXT_FRAME:
|
||||
case LWSWSOPC_BINARY_FRAME:
|
||||
wsi->u.ws.frame_is_binary = wsi->u.ws.opcode ==
|
||||
LWSWSOPC_BINARY_FRAME;
|
||||
break;
|
||||
}
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
|
||||
break;
|
||||
|
||||
default:
|
||||
lwsl_err("unknown spec version %02d\n",
|
||||
wsi->ietf_spec_revision);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN:
|
||||
|
||||
wsi->u.ws.this_frame_masked = !!(c & 0x80);
|
||||
|
||||
switch (c & 0x7f) {
|
||||
case 126:
|
||||
/* control frames are not allowed to have big lengths */
|
||||
if (wsi->u.ws.opcode & 8)
|
||||
goto illegal_ctl_length;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
|
||||
break;
|
||||
case 127:
|
||||
/* control frames are not allowed to have big lengths */
|
||||
if (wsi->u.ws.opcode & 8)
|
||||
goto illegal_ctl_length;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
|
||||
break;
|
||||
default:
|
||||
wsi->u.ws.rx_packet_length = c;
|
||||
if (wsi->u.ws.this_frame_masked)
|
||||
wsi->lws_rx_parse_state =
|
||||
LWS_RXPS_07_COLLECT_FRAME_KEY_1;
|
||||
else {
|
||||
if (c)
|
||||
wsi->lws_rx_parse_state =
|
||||
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
|
||||
else {
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
|
||||
goto spill;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN16_2:
|
||||
wsi->u.ws.rx_packet_length = c << 8;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN16_1:
|
||||
wsi->u.ws.rx_packet_length |= c;
|
||||
if (wsi->u.ws.this_frame_masked)
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_1;
|
||||
else {
|
||||
if (wsi->u.ws.rx_packet_length)
|
||||
wsi->lws_rx_parse_state =
|
||||
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
|
||||
else {
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
|
||||
goto spill;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_8:
|
||||
if (c & 0x80) {
|
||||
lwsl_warn("b63 of length must be zero\n");
|
||||
/* kill the connection */
|
||||
return -1;
|
||||
}
|
||||
#if defined __LP64__
|
||||
wsi->u.ws.rx_packet_length = ((size_t)c) << 56;
|
||||
#else
|
||||
wsi->u.ws.rx_packet_length = 0;
|
||||
#endif
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_7:
|
||||
#if defined __LP64__
|
||||
wsi->u.ws.rx_packet_length |= ((size_t)c) << 48;
|
||||
#endif
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_6:
|
||||
#if defined __LP64__
|
||||
wsi->u.ws.rx_packet_length |= ((size_t)c) << 40;
|
||||
#endif
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_5:
|
||||
#if defined __LP64__
|
||||
wsi->u.ws.rx_packet_length |= ((size_t)c) << 32;
|
||||
#endif
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_4:
|
||||
wsi->u.ws.rx_packet_length |= ((size_t)c) << 24;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_3:
|
||||
wsi->u.ws.rx_packet_length |= ((size_t)c) << 16;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_2:
|
||||
wsi->u.ws.rx_packet_length |= ((size_t)c) << 8;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_04_FRAME_HDR_LEN64_1:
|
||||
wsi->u.ws.rx_packet_length |= (size_t)c;
|
||||
if (wsi->u.ws.this_frame_masked)
|
||||
wsi->lws_rx_parse_state =
|
||||
LWS_RXPS_07_COLLECT_FRAME_KEY_1;
|
||||
else {
|
||||
if (wsi->u.ws.rx_packet_length)
|
||||
wsi->lws_rx_parse_state =
|
||||
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
|
||||
else {
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
|
||||
goto spill;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
|
||||
wsi->u.ws.mask[0] = c;
|
||||
if (c)
|
||||
wsi->u.ws.all_zero_nonce = 0;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
|
||||
wsi->u.ws.mask[1] = c;
|
||||
if (c)
|
||||
wsi->u.ws.all_zero_nonce = 0;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
|
||||
wsi->u.ws.mask[2] = c;
|
||||
if (c)
|
||||
wsi->u.ws.all_zero_nonce = 0;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
|
||||
break;
|
||||
|
||||
case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
|
||||
wsi->u.ws.mask[3] = c;
|
||||
if (c)
|
||||
wsi->u.ws.all_zero_nonce = 0;
|
||||
|
||||
if (wsi->u.ws.rx_packet_length)
|
||||
wsi->lws_rx_parse_state =
|
||||
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
|
||||
else {
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
|
||||
goto spill;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
|
||||
|
||||
assert(wsi->u.ws.rx_ubuf);
|
||||
|
||||
if (wsi->u.ws.this_frame_masked && !wsi->u.ws.all_zero_nonce)
|
||||
c ^= wsi->u.ws.mask[(wsi->u.ws.mask_idx++) & 3];
|
||||
|
||||
wsi->u.ws.rx_ubuf[LWS_PRE + (wsi->u.ws.rx_ubuf_head++)] = c;
|
||||
|
||||
if (--wsi->u.ws.rx_packet_length == 0) {
|
||||
/* spill because we have the whole frame */
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
|
||||
goto spill;
|
||||
}
|
||||
|
||||
/*
|
||||
* if there's no protocol max frame size given, we are
|
||||
* supposed to default to context->pt_serv_buf_size
|
||||
*/
|
||||
if (!wsi->protocol->rx_buffer_size &&
|
||||
wsi->u.ws.rx_ubuf_head != wsi->context->pt_serv_buf_size)
|
||||
break;
|
||||
|
||||
if (wsi->protocol->rx_buffer_size &&
|
||||
wsi->u.ws.rx_ubuf_head != wsi->protocol->rx_buffer_size)
|
||||
break;
|
||||
|
||||
/* spill because we filled our rx buffer */
|
||||
spill:
|
||||
|
||||
handled = 0;
|
||||
|
||||
/*
|
||||
* is this frame a control packet we should take care of at this
|
||||
* layer? If so service it and hide it from the user callback
|
||||
*/
|
||||
|
||||
switch (wsi->u.ws.opcode) {
|
||||
case LWSWSOPC_CLOSE:
|
||||
pp = (unsigned char *)&wsi->u.ws.rx_ubuf[LWS_PRE];
|
||||
if (lws_check_opt(wsi->context->options,
|
||||
LWS_SERVER_OPTION_VALIDATE_UTF8) &&
|
||||
wsi->u.ws.rx_ubuf_head > 2 &&
|
||||
lws_check_utf8(&wsi->u.ws.utf8, pp + 2,
|
||||
wsi->u.ws.rx_ubuf_head - 2))
|
||||
goto utf8_fail;
|
||||
|
||||
/* is this an acknowledgement of our close? */
|
||||
if (wsi->state == LWSS_AWAITING_CLOSE_ACK) {
|
||||
/*
|
||||
* fine he has told us he is closing too, let's
|
||||
* finish our close
|
||||
*/
|
||||
lwsl_parser("seen server's close ack\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
lwsl_parser("client sees server close len = %d\n",
|
||||
wsi->u.ws.rx_ubuf_head);
|
||||
if (wsi->u.ws.rx_ubuf_head >= 2) {
|
||||
close_code = (pp[0] << 8) | pp[1];
|
||||
if (close_code < 1000 || close_code == 1004 ||
|
||||
close_code == 1005 || close_code == 1006 ||
|
||||
close_code == 1012 || close_code == 1013 ||
|
||||
close_code == 1014 || close_code == 1015 ||
|
||||
(close_code >= 1016 && close_code < 3000)
|
||||
) {
|
||||
pp[0] = (LWS_CLOSE_STATUS_PROTOCOL_ERR >> 8) & 0xff;
|
||||
pp[1] = LWS_CLOSE_STATUS_PROTOCOL_ERR & 0xff;
|
||||
}
|
||||
}
|
||||
if (user_callback_handle_rxflow(
|
||||
wsi->protocol->callback, wsi,
|
||||
LWS_CALLBACK_WS_PEER_INITIATED_CLOSE,
|
||||
wsi->user_space, pp,
|
||||
wsi->u.ws.rx_ubuf_head))
|
||||
return -1;
|
||||
/*
|
||||
* parrot the close packet payload back
|
||||
* we do not care about how it went, we are closing
|
||||
* immediately afterwards
|
||||
*/
|
||||
lws_write(wsi, (unsigned char *)&wsi->u.ws.rx_ubuf[LWS_PRE],
|
||||
wsi->u.ws.rx_ubuf_head, LWS_WRITE_CLOSE);
|
||||
wsi->state = LWSS_RETURNED_CLOSE_ALREADY;
|
||||
/* close the connection */
|
||||
return -1;
|
||||
|
||||
case LWSWSOPC_PING:
|
||||
lwsl_info("received %d byte ping, sending pong\n",
|
||||
wsi->u.ws.rx_ubuf_head);
|
||||
|
||||
/* he set a close reason on this guy, ignore PING */
|
||||
if (wsi->u.ws.close_in_ping_buffer_len)
|
||||
goto ping_drop;
|
||||
|
||||
if (wsi->u.ws.ping_pending_flag) {
|
||||
/*
|
||||
* there is already a pending ping payload
|
||||
* we should just log and drop
|
||||
*/
|
||||
lwsl_parser("DROP PING since one pending\n");
|
||||
goto ping_drop;
|
||||
}
|
||||
|
||||
/* control packets can only be < 128 bytes long */
|
||||
if (wsi->u.ws.rx_ubuf_head > 128 - 3) {
|
||||
lwsl_parser("DROP PING payload too large\n");
|
||||
goto ping_drop;
|
||||
}
|
||||
|
||||
/* stash the pong payload */
|
||||
memcpy(wsi->u.ws.ping_payload_buf + LWS_PRE,
|
||||
&wsi->u.ws.rx_ubuf[LWS_PRE],
|
||||
wsi->u.ws.rx_ubuf_head);
|
||||
|
||||
wsi->u.ws.ping_payload_len = wsi->u.ws.rx_ubuf_head;
|
||||
wsi->u.ws.ping_pending_flag = 1;
|
||||
|
||||
/* get it sent as soon as possible */
|
||||
lws_callback_on_writable(wsi);
|
||||
ping_drop:
|
||||
wsi->u.ws.rx_ubuf_head = 0;
|
||||
handled = 1;
|
||||
break;
|
||||
|
||||
case LWSWSOPC_PONG:
|
||||
lwsl_info("client receied pong\n");
|
||||
lwsl_hexdump(&wsi->u.ws.rx_ubuf[LWS_PRE],
|
||||
wsi->u.ws.rx_ubuf_head);
|
||||
|
||||
if (wsi->pending_timeout == PENDING_TIMEOUT_WS_PONG_CHECK_GET_PONG) {
|
||||
lwsl_info("received expected PONG on wsi %p\n", wsi);
|
||||
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
||||
}
|
||||
|
||||
/* issue it */
|
||||
callback_action = LWS_CALLBACK_CLIENT_RECEIVE_PONG;
|
||||
break;
|
||||
|
||||
case LWSWSOPC_CONTINUATION:
|
||||
case LWSWSOPC_TEXT_FRAME:
|
||||
case LWSWSOPC_BINARY_FRAME:
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
lwsl_parser("Reserved opc 0x%2X\n", wsi->u.ws.opcode);
|
||||
|
||||
/*
|
||||
* It's something special we can't understand here.
|
||||
* Pass the payload up to the extension's parsing
|
||||
* state machine.
|
||||
*/
|
||||
|
||||
eff_buf.token = &wsi->u.ws.rx_ubuf[LWS_PRE];
|
||||
eff_buf.token_len = wsi->u.ws.rx_ubuf_head;
|
||||
|
||||
if (lws_ext_cb_active(wsi,
|
||||
LWS_EXT_CB_EXTENDED_PAYLOAD_RX,
|
||||
&eff_buf, 0) <= 0) { /* not handle or fail */
|
||||
|
||||
lwsl_ext("Unhandled ext opc 0x%x\n", wsi->u.ws.opcode);
|
||||
wsi->u.ws.rx_ubuf_head = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
handled = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* No it's real payload, pass it up to the user callback.
|
||||
* It's nicely buffered with the pre-padding taken care of
|
||||
* so it can be sent straight out again using lws_write
|
||||
*/
|
||||
if (handled)
|
||||
goto already_done;
|
||||
|
||||
eff_buf.token = &wsi->u.ws.rx_ubuf[LWS_PRE];
|
||||
eff_buf.token_len = wsi->u.ws.rx_ubuf_head;
|
||||
|
||||
drain_extension:
|
||||
n = lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_RX, &eff_buf, 0);
|
||||
lwsl_ext("Ext RX returned %d\n", n);
|
||||
if (n < 0) /* fail */
|
||||
return -1;
|
||||
|
||||
lwsl_ext("post inflate eff_buf len %d\n", eff_buf.token_len);
|
||||
|
||||
if (rx_draining_ext && !eff_buf.token_len) {
|
||||
lwsl_err(" --- ignoring zero drain result, ending drain\n");
|
||||
goto already_done;
|
||||
}
|
||||
|
||||
if (wsi->u.ws.check_utf8 && !wsi->u.ws.defeat_check_utf8) {
|
||||
if (lws_check_utf8(&wsi->u.ws.utf8,
|
||||
(unsigned char *)eff_buf.token,
|
||||
eff_buf.token_len))
|
||||
goto utf8_fail;
|
||||
|
||||
/* we are ending partway through utf-8 character? */
|
||||
if (!wsi->u.ws.rx_packet_length && wsi->u.ws.final && wsi->u.ws.utf8 && !n) {
|
||||
lwsl_info("FINAL utf8 error\n");
|
||||
utf8_fail: lwsl_info("utf8 error\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (eff_buf.token_len < 0 &&
|
||||
callback_action != LWS_CALLBACK_CLIENT_RECEIVE_PONG)
|
||||
goto already_done;
|
||||
|
||||
if (!eff_buf.token)
|
||||
goto already_done;
|
||||
|
||||
eff_buf.token[eff_buf.token_len] = '\0';
|
||||
|
||||
if (!wsi->protocol->callback)
|
||||
goto already_done;
|
||||
|
||||
if (callback_action == LWS_CALLBACK_CLIENT_RECEIVE_PONG)
|
||||
lwsl_info("Client doing pong callback\n");
|
||||
|
||||
if (n && eff_buf.token_len) {
|
||||
/* extension had more... main loop will come back
|
||||
* we want callback to be done with this set, if so,
|
||||
* because lws_is_final() hides it was final until the
|
||||
* last chunk
|
||||
*/
|
||||
wsi->u.ws.rx_draining_ext = 1;
|
||||
wsi->u.ws.rx_draining_ext_list = pt->rx_draining_ext_list;
|
||||
pt->rx_draining_ext_list = wsi;
|
||||
lwsl_ext("%s: RX EXT DRAINING: Adding to list\n", __func__);
|
||||
}
|
||||
if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY ||
|
||||
wsi->state == LWSS_AWAITING_CLOSE_ACK)
|
||||
goto already_done;
|
||||
|
||||
m = wsi->protocol->callback(wsi,
|
||||
(enum lws_callback_reasons)callback_action,
|
||||
wsi->user_space, eff_buf.token, eff_buf.token_len);
|
||||
|
||||
/* if user code wants to close, let caller know */
|
||||
if (m)
|
||||
return 1;
|
||||
|
||||
already_done:
|
||||
wsi->u.ws.rx_ubuf_head = 0;
|
||||
break;
|
||||
default:
|
||||
lwsl_err("client rx illegal state\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
illegal_ctl_length:
|
||||
lwsl_warn("Control frame asking for extended length is illegal\n");
|
||||
/* kill the connection */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
1073
feeds/wlan-ap/libwebsocket/src/client.c
Executable file
1073
feeds/wlan-ap/libwebsocket/src/client.c
Executable file
File diff suppressed because it is too large
Load Diff
928
feeds/wlan-ap/libwebsocket/src/context.c
Normal file
928
feeds/wlan-ap/libwebsocket/src/context.c
Normal file
@@ -0,0 +1,928 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#include "websocket/private-libwebsockets.h"
|
||||
|
||||
#ifndef LWS_BUILD_HASH
|
||||
#define LWS_BUILD_HASH "unknown-build-hash"
|
||||
#endif
|
||||
|
||||
static const char *library_version = LWS_LIBRARY_VERSION " " LWS_BUILD_HASH;
|
||||
|
||||
/**
|
||||
* lws_get_library_version: get version and git hash library built from
|
||||
*
|
||||
* returns a const char * to a string like "1.1 178d78c"
|
||||
* representing the library version followed by the git head hash it
|
||||
* was built from
|
||||
*/
|
||||
LWS_VISIBLE const char *
|
||||
lws_get_library_version(void)
|
||||
{
|
||||
return library_version;
|
||||
}
|
||||
|
||||
static const char * const mount_protocols[] = {
|
||||
"http://",
|
||||
"https://",
|
||||
"file://",
|
||||
"cgi://",
|
||||
">http://",
|
||||
">https://",
|
||||
"callback://"
|
||||
};
|
||||
|
||||
LWS_VISIBLE void *
|
||||
lws_protocol_vh_priv_zalloc(struct lws_vhost *vhost, const struct lws_protocols *prot,
|
||||
int size)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
/* allocate the vh priv array only on demand */
|
||||
if (!vhost->protocol_vh_privs) {
|
||||
vhost->protocol_vh_privs = (void **)lws_zalloc(
|
||||
vhost->count_protocols * sizeof(void *));
|
||||
if (!vhost->protocol_vh_privs)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (n < vhost->count_protocols && &vhost->protocols[n] != prot)
|
||||
n++;
|
||||
|
||||
if (n == vhost->count_protocols) {
|
||||
n = 0;
|
||||
while (n < vhost->count_protocols &&
|
||||
strcmp(vhost->protocols[n].name, prot->name))
|
||||
n++;
|
||||
|
||||
if (n == vhost->count_protocols)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vhost->protocol_vh_privs[n] = lws_zalloc(size);
|
||||
return vhost->protocol_vh_privs[n];
|
||||
}
|
||||
|
||||
LWS_VISIBLE void *
|
||||
lws_protocol_vh_priv_get(struct lws_vhost *vhost, const struct lws_protocols *prot)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
if (!vhost->protocol_vh_privs)
|
||||
return NULL;
|
||||
|
||||
while (n < vhost->count_protocols && &vhost->protocols[n] != prot)
|
||||
n++;
|
||||
|
||||
if (n == vhost->count_protocols) {
|
||||
n = 0;
|
||||
while (n < vhost->count_protocols &&
|
||||
strcmp(vhost->protocols[n].name, prot->name))
|
||||
n++;
|
||||
|
||||
if (n == vhost->count_protocols) {
|
||||
lwsl_err("%s: unknown protocol %p\n", __func__, prot);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return vhost->protocol_vh_privs[n];
|
||||
}
|
||||
|
||||
static const struct lws_protocol_vhost_options *
|
||||
lws_vhost_protocol_options(struct lws_vhost *vh, const char *name)
|
||||
{
|
||||
const struct lws_protocol_vhost_options *pvo = vh->pvo;
|
||||
|
||||
while (pvo) {
|
||||
// lwsl_notice("%s: '%s' '%s'\n", __func__, pvo->name, name);
|
||||
if (!strcmp(pvo->name, name))
|
||||
return pvo;
|
||||
pvo = pvo->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
lws_protocol_init(struct lws_context *context)
|
||||
{
|
||||
struct lws_vhost *vh = context->vhost_list;
|
||||
const struct lws_protocol_vhost_options *pvo, *pvo1;
|
||||
struct lws wsi;
|
||||
int n;
|
||||
|
||||
memset(&wsi, 0, sizeof(wsi));
|
||||
wsi.context = context;
|
||||
|
||||
lwsl_notice("%s\n", __func__);
|
||||
|
||||
while (vh) {
|
||||
wsi.vhost = vh;
|
||||
|
||||
/* initialize supported protocols on this vhost */
|
||||
|
||||
for (n = 0; n < vh->count_protocols; n++) {
|
||||
wsi.protocol = &vh->protocols[n];
|
||||
|
||||
pvo = lws_vhost_protocol_options(vh,
|
||||
vh->protocols[n].name);
|
||||
if (pvo) {
|
||||
/*
|
||||
* linked list of options specific to
|
||||
* vh + protocol
|
||||
*/
|
||||
pvo1 = pvo;
|
||||
pvo = pvo1->options;
|
||||
|
||||
while (pvo) {
|
||||
lwsl_notice(" vh %s prot %s opt %s\n",
|
||||
vh->name,
|
||||
vh->protocols[n].name,
|
||||
pvo->name);
|
||||
|
||||
if (!strcmp(pvo->name, "default")) {
|
||||
lwsl_notice("Setting default "
|
||||
"protocol for vh %s to %s\n",
|
||||
vh->name,
|
||||
vh->protocols[n].name);
|
||||
vh->default_protocol_index = n;
|
||||
}
|
||||
pvo = pvo->next;
|
||||
}
|
||||
|
||||
pvo = pvo1->options;
|
||||
}
|
||||
|
||||
/*
|
||||
* inform all the protocols that they are doing their one-time
|
||||
* initialization if they want to.
|
||||
*
|
||||
* NOTE the wsi is all zeros except for the context, vh and
|
||||
* protocol ptrs so lws_get_context(wsi) etc can work
|
||||
*/
|
||||
if (vh->protocols[n].callback(&wsi,
|
||||
LWS_CALLBACK_PROTOCOL_INIT, NULL,
|
||||
(void *)pvo, 0))
|
||||
return 1;
|
||||
}
|
||||
|
||||
vh = vh->vhost_next;
|
||||
}
|
||||
|
||||
context->protocol_init_done = 1;
|
||||
lws_finalize_startup(context);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
#ifdef LWS_WITH_CGI
|
||||
struct lws_cgi_args *args;
|
||||
char buf[128];
|
||||
int n;
|
||||
#endif
|
||||
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_HTTP:
|
||||
#ifndef LWS_NO_SERVER
|
||||
if (lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL))
|
||||
return -1;
|
||||
|
||||
if (lws_http_transaction_completed(wsi))
|
||||
#endif
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_HTTP_WRITEABLE:
|
||||
#ifdef LWS_WITH_CGI
|
||||
if (wsi->reason_bf & 1) {
|
||||
if (lws_cgi_write_split_stdout_headers(wsi) < 0)
|
||||
return -1;
|
||||
|
||||
wsi->reason_bf &= ~1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
|
||||
#ifdef LWS_WITH_CGI
|
||||
/* CGI IO events (POLLIN/OUT) appear here, our default policy is:
|
||||
*
|
||||
* - POST data goes on subprocess stdin
|
||||
* - subprocess stdout goes on http via writeable callback
|
||||
* - subprocess stderr goes to the logs
|
||||
*/
|
||||
case LWS_CALLBACK_CGI:
|
||||
args = (struct lws_cgi_args *)in;
|
||||
switch (args->ch) { /* which of stdin/out/err ? */
|
||||
case LWS_STDIN:
|
||||
/* TBD stdin rx flow control */
|
||||
break;
|
||||
case LWS_STDOUT:
|
||||
wsi->reason_bf |= 1;
|
||||
/* when writing to MASTER would not block */
|
||||
lws_callback_on_writable(wsi);
|
||||
break;
|
||||
case LWS_STDERR:
|
||||
n = read(lws_get_socket_fd(args->stdwsi[LWS_STDERR]),
|
||||
buf, sizeof(buf) - 2);
|
||||
if (n > 0) {
|
||||
if (buf[n - 1] != '\n')
|
||||
buf[n++] = '\n';
|
||||
buf[n] = '\0';
|
||||
lwsl_notice("CGI-stderr: %s\n", buf);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CGI_TERMINATED:
|
||||
return -1;
|
||||
|
||||
case LWS_CALLBACK_CGI_STDIN_DATA: /* POST body for stdin */
|
||||
args = (struct lws_cgi_args *)in;
|
||||
args->data[args->len] = '\0';
|
||||
n = write(lws_get_socket_fd(args->stdwsi[LWS_STDIN]),
|
||||
args->data, args->len);
|
||||
if (n < args->len)
|
||||
lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA: "
|
||||
"sent %d only %d went", n, args->len);
|
||||
return n;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* list of supported protocols and callbacks */
|
||||
|
||||
static const struct lws_protocols protocols_dummy[] = {
|
||||
/* first protocol must always be HTTP handler */
|
||||
|
||||
{
|
||||
"http-only", /* name */
|
||||
lws_callback_http_dummy, /* callback */
|
||||
0, /* per_session_data_size */
|
||||
0, /* max frame size / rx buffer */
|
||||
},
|
||||
/*
|
||||
* the other protocols are provided by lws plugins
|
||||
*/
|
||||
{ NULL, NULL, 0, 0 } /* terminator */
|
||||
};
|
||||
|
||||
LWS_VISIBLE struct lws_vhost *
|
||||
lws_create_vhost(struct lws_context *context,
|
||||
struct lws_context_creation_info *info)
|
||||
{
|
||||
struct lws_vhost *vh = lws_zalloc(sizeof(*vh)),
|
||||
**vh1 = &context->vhost_list;
|
||||
const struct lws_http_mount *mounts;
|
||||
const struct lws_protocol_vhost_options *pvo;
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
struct lws_plugin *plugin = context->plugin_list;
|
||||
struct lws_protocols *lwsp;
|
||||
int m, f = !info->pvo;
|
||||
#endif
|
||||
#ifdef LWS_HAVE_GETENV
|
||||
char *p;
|
||||
#endif
|
||||
int n;
|
||||
|
||||
if (!vh)
|
||||
return NULL;
|
||||
|
||||
if (!info->protocols)
|
||||
info->protocols = &protocols_dummy[0];
|
||||
|
||||
vh->context = context;
|
||||
if (!info->vhost_name)
|
||||
vh->name = "default";
|
||||
else
|
||||
vh->name = info->vhost_name;
|
||||
|
||||
vh->iface = info->iface;
|
||||
for (vh->count_protocols = 0;
|
||||
info->protocols[vh->count_protocols].callback;
|
||||
vh->count_protocols++)
|
||||
;
|
||||
|
||||
vh->options = info->options;
|
||||
vh->pvo = info->pvo;
|
||||
vh->headers = info->headers;
|
||||
if (info->keepalive_timeout)
|
||||
vh->keepalive_timeout = info->keepalive_timeout;
|
||||
else
|
||||
vh->keepalive_timeout = 5;
|
||||
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
if (plugin) {
|
||||
/*
|
||||
* give the vhost a unified list of protocols including the
|
||||
* ones that came from plugins
|
||||
*/
|
||||
lwsp = lws_zalloc(sizeof(struct lws_protocols) *
|
||||
(vh->count_protocols +
|
||||
context->plugin_protocol_count + 1));
|
||||
if (!lwsp)
|
||||
return NULL;
|
||||
|
||||
m = vh->count_protocols;
|
||||
memcpy(lwsp, info->protocols,
|
||||
sizeof(struct lws_protocols) * m);
|
||||
|
||||
/* for compatibility, all protocols enabled on vhost if only
|
||||
* the default vhost exists. Otherwise only vhosts who ask
|
||||
* for a protocol get it enabled.
|
||||
*/
|
||||
|
||||
if (info->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
|
||||
f = 0;
|
||||
|
||||
while (plugin) {
|
||||
for (n = 0; n < plugin->caps.count_protocols; n++) {
|
||||
/*
|
||||
* for compatibility's sake, no pvo implies
|
||||
* allow all protocols
|
||||
*/
|
||||
if (f || lws_vhost_protocol_options(vh,
|
||||
plugin->caps.protocols[n].name)) {
|
||||
memcpy(&lwsp[m],
|
||||
&plugin->caps.protocols[n],
|
||||
sizeof(struct lws_protocols));
|
||||
m++;
|
||||
vh->count_protocols++;
|
||||
}
|
||||
}
|
||||
plugin = plugin->list;
|
||||
}
|
||||
vh->protocols = lwsp;
|
||||
} else
|
||||
#endif
|
||||
vh->protocols = info->protocols;
|
||||
|
||||
vh->same_vh_protocol_list = (struct lws **)
|
||||
lws_zalloc(sizeof(struct lws *) * vh->count_protocols);
|
||||
|
||||
vh->mount_list = info->mounts;
|
||||
|
||||
#ifdef LWS_USE_UNIX_SOCK
|
||||
if (LWS_UNIX_SOCK_ENABLED(context)) {
|
||||
lwsl_notice("Creating Vhost '%s' path \"%s\", %d protocols\n",
|
||||
vh->name, info->iface, vh->count_protocols);
|
||||
} else
|
||||
#endif
|
||||
lwsl_notice("Creating Vhost '%s' port %d, %d protocols, IPv6 %s\n",
|
||||
vh->name, info->port, vh->count_protocols, LWS_IPV6_ENABLED(vh) ? "on" : "off");
|
||||
|
||||
mounts = info->mounts;
|
||||
while (mounts) {
|
||||
lwsl_notice(" mounting %s%s to %s\n",
|
||||
mount_protocols[mounts->origin_protocol],
|
||||
mounts->origin, mounts->mountpoint);
|
||||
|
||||
/* convert interpreter protocol names to pointers */
|
||||
pvo = mounts->interpret;
|
||||
while (pvo) {
|
||||
for (n = 0; n < vh->count_protocols; n++)
|
||||
if (!strcmp(pvo->value, vh->protocols[n].name)) {
|
||||
((struct lws_protocol_vhost_options *)pvo)->value =
|
||||
(const char *)(long)n;
|
||||
break;
|
||||
}
|
||||
if (n == vh->count_protocols)
|
||||
lwsl_err("ignoring unknown interpret protocol %s\n", pvo->value);
|
||||
pvo = pvo->next;
|
||||
}
|
||||
|
||||
mounts = mounts->mount_next;
|
||||
}
|
||||
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
if (context->plugin_extension_count) {
|
||||
|
||||
m = 0;
|
||||
while (info->extensions && info->extensions[m].callback)
|
||||
m++;
|
||||
|
||||
/*
|
||||
* give the vhost a unified list of extensions including the
|
||||
* ones that came from plugins
|
||||
*/
|
||||
vh->extensions = lws_zalloc(sizeof(struct lws_extension) *
|
||||
(m +
|
||||
context->plugin_extension_count + 1));
|
||||
if (!vh->extensions)
|
||||
return NULL;
|
||||
|
||||
memcpy((struct lws_extension *)vh->extensions, info->extensions,
|
||||
sizeof(struct lws_extension) * m);
|
||||
plugin = context->plugin_list;
|
||||
while (plugin) {
|
||||
memcpy((struct lws_extension *)&vh->extensions[m],
|
||||
plugin->caps.extensions,
|
||||
sizeof(struct lws_extension) *
|
||||
plugin->caps.count_extensions);
|
||||
m += plugin->caps.count_extensions;
|
||||
plugin = plugin->list;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
vh->extensions = info->extensions;
|
||||
#endif
|
||||
|
||||
vh->listen_port = info->port;
|
||||
#if !defined(LWS_WITH_ESP8266)
|
||||
vh->http_proxy_port = 0;
|
||||
vh->http_proxy_address[0] = '\0';
|
||||
|
||||
/* either use proxy from info, or try get it from env var */
|
||||
|
||||
if (info->http_proxy_address) {
|
||||
/* override for backwards compatibility */
|
||||
if (info->http_proxy_port)
|
||||
vh->http_proxy_port = info->http_proxy_port;
|
||||
lws_set_proxy(vh, info->http_proxy_address);
|
||||
} else {
|
||||
#ifdef LWS_HAVE_GETENV
|
||||
p = getenv("http_proxy");
|
||||
if (p)
|
||||
lws_set_proxy(vh, p);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
vh->ka_time = info->ka_time;
|
||||
vh->ka_interval = info->ka_interval;
|
||||
vh->ka_probes = info->ka_probes;
|
||||
|
||||
if (vh->options & LWS_SERVER_OPTION_STS)
|
||||
lwsl_notice(" STS enabled\n");
|
||||
|
||||
#ifdef LWS_WITH_ACCESS_LOG
|
||||
if (info->log_filepath) {
|
||||
vh->log_fd = open(info->log_filepath, O_CREAT | O_APPEND | O_RDWR, 0600);
|
||||
if (vh->log_fd == (int)LWS_INVALID_FILE) {
|
||||
lwsl_err("unable to open log filepath %s\n",
|
||||
info->log_filepath);
|
||||
goto bail;
|
||||
}
|
||||
#ifndef WIN32
|
||||
if (context->uid != -1)
|
||||
if (chown(info->log_filepath, context->uid,
|
||||
context->gid) == -1)
|
||||
lwsl_err("unable to chown log file %s\n",
|
||||
info->log_filepath);
|
||||
#endif
|
||||
} else
|
||||
vh->log_fd = (int)LWS_INVALID_FILE;
|
||||
#endif
|
||||
|
||||
if (lws_context_init_server_ssl(info, vh))
|
||||
goto bail;
|
||||
|
||||
if (lws_context_init_client_ssl(info, vh))
|
||||
goto bail;
|
||||
|
||||
if (lws_context_init_server(info, vh))
|
||||
goto bail;
|
||||
|
||||
while (1) {
|
||||
if (!(*vh1)) {
|
||||
*vh1 = vh;
|
||||
break;
|
||||
}
|
||||
vh1 = &(*vh1)->vhost_next;
|
||||
};
|
||||
|
||||
return vh;
|
||||
|
||||
bail:
|
||||
lws_free(vh);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_init_vhost_client_ssl(const struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost)
|
||||
{
|
||||
struct lws_context_creation_info i;
|
||||
|
||||
memcpy(&i, info, sizeof(i));
|
||||
i.port = CONTEXT_PORT_NO_LISTEN;
|
||||
|
||||
return lws_context_init_client_ssl(&i, vhost);
|
||||
}
|
||||
|
||||
|
||||
LWS_VISIBLE struct lws_context *
|
||||
lws_create_context(struct lws_context_creation_info *info)
|
||||
{
|
||||
struct lws_context *context = NULL;
|
||||
#ifndef LWS_NO_DAEMONIZE
|
||||
int pid_daemon = get_daemonize_pid();
|
||||
#endif
|
||||
int n, m;
|
||||
#if defined(__ANDROID__)
|
||||
struct rlimit rt;
|
||||
#endif
|
||||
|
||||
lwsl_notice("Initial logging level %d\n", log_level);
|
||||
lwsl_notice("Libwebsockets version: %s\n", library_version);
|
||||
#if LWS_POSIX
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DISABLE_IPV6))
|
||||
lwsl_notice("IPV6 compiled in and enabled\n");
|
||||
else
|
||||
lwsl_notice("IPV6 compiled in but disabled\n");
|
||||
#else
|
||||
lwsl_notice("IPV6 not compiled in\n");
|
||||
#endif
|
||||
lws_feature_status_libev(info);
|
||||
lws_feature_status_libuv(info);
|
||||
#endif
|
||||
lwsl_info(" LWS_DEF_HEADER_LEN : %u\n", LWS_DEF_HEADER_LEN);
|
||||
lwsl_info(" LWS_MAX_PROTOCOLS : %u\n", LWS_MAX_PROTOCOLS);
|
||||
lwsl_info(" LWS_MAX_SMP : %u\n", LWS_MAX_SMP);
|
||||
lwsl_info(" SPEC_LATEST_SUPPORTED : %u\n", SPEC_LATEST_SUPPORTED);
|
||||
lwsl_info(" sizeof (*info) : %u\n", sizeof(*info));
|
||||
#if LWS_POSIX
|
||||
lwsl_info(" SYSTEM_RANDOM_FILEPATH: '%s'\n", SYSTEM_RANDOM_FILEPATH);
|
||||
#endif
|
||||
if (lws_plat_context_early_init())
|
||||
return NULL;
|
||||
|
||||
context = lws_zalloc(sizeof(struct lws_context));
|
||||
if (!context) {
|
||||
lwsl_err("No memory for websocket context\n");
|
||||
return NULL;
|
||||
}
|
||||
if (info->pt_serv_buf_size)
|
||||
context->pt_serv_buf_size = info->pt_serv_buf_size;
|
||||
else
|
||||
context->pt_serv_buf_size = (4096*5);
|
||||
|
||||
context->reject_service_keywords = info->reject_service_keywords;
|
||||
|
||||
context->time_up = time(NULL);
|
||||
#ifndef LWS_NO_DAEMONIZE
|
||||
if (pid_daemon) {
|
||||
context->started_with_parent = pid_daemon;
|
||||
lwsl_notice(" Started with daemon pid %d\n", pid_daemon);
|
||||
}
|
||||
#endif
|
||||
#if defined(__ANDROID__)
|
||||
n = getrlimit ( RLIMIT_NOFILE,&rt);
|
||||
if (-1 == n) {
|
||||
lwsl_err("Get RLIMIT_NOFILE failed!\n");
|
||||
return NULL;
|
||||
}
|
||||
context->max_fds = rt.rlim_cur;
|
||||
#else
|
||||
context->max_fds = getdtablesize();
|
||||
#endif
|
||||
|
||||
if (info->count_threads)
|
||||
context->count_threads = info->count_threads;
|
||||
else
|
||||
context->count_threads = 1;
|
||||
|
||||
if (context->count_threads > LWS_MAX_SMP)
|
||||
context->count_threads = LWS_MAX_SMP;
|
||||
|
||||
context->token_limits = info->token_limits;
|
||||
|
||||
context->options = info->options;
|
||||
|
||||
if (info->timeout_secs)
|
||||
context->timeout_secs = info->timeout_secs;
|
||||
else
|
||||
context->timeout_secs = AWAITING_TIMEOUT;
|
||||
|
||||
context->ws_ping_pong_interval = info->ws_ping_pong_interval;
|
||||
|
||||
lwsl_info(" default timeout (secs): %u\n", context->timeout_secs);
|
||||
|
||||
if (info->max_http_header_data)
|
||||
context->max_http_header_data = info->max_http_header_data;
|
||||
else
|
||||
if (info->max_http_header_data2)
|
||||
context->max_http_header_data =
|
||||
info->max_http_header_data2;
|
||||
else
|
||||
context->max_http_header_data = LWS_DEF_HEADER_LEN;
|
||||
if (info->max_http_header_pool)
|
||||
context->max_http_header_pool = info->max_http_header_pool;
|
||||
else
|
||||
context->max_http_header_pool = LWS_DEF_HEADER_POOL;
|
||||
|
||||
/*
|
||||
* Allocate the per-thread storage for scratchpad buffers,
|
||||
* and header data pool
|
||||
*/
|
||||
for (n = 0; n < context->count_threads; n++) {
|
||||
context->pt[n].serv_buf = lws_zalloc(context->pt_serv_buf_size);
|
||||
if (!context->pt[n].serv_buf) {
|
||||
lwsl_err("OOM\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef LWS_USE_LIBUV
|
||||
context->pt[n].context = context;
|
||||
#endif
|
||||
context->pt[n].tid = n;
|
||||
context->pt[n].http_header_data = lws_malloc(context->max_http_header_data *
|
||||
context->max_http_header_pool);
|
||||
if (!context->pt[n].http_header_data)
|
||||
goto bail;
|
||||
|
||||
context->pt[n].ah_pool = lws_zalloc(sizeof(struct allocated_headers) *
|
||||
context->max_http_header_pool);
|
||||
for (m = 0; m < context->max_http_header_pool; m++)
|
||||
context->pt[n].ah_pool[m].data =
|
||||
(char *)context->pt[n].http_header_data +
|
||||
(m * context->max_http_header_data);
|
||||
if (!context->pt[n].ah_pool)
|
||||
goto bail;
|
||||
|
||||
lws_pt_mutex_init(&context->pt[n]);
|
||||
}
|
||||
|
||||
if (info->fd_limit_per_thread)
|
||||
context->fd_limit_per_thread = info->fd_limit_per_thread;
|
||||
else
|
||||
context->fd_limit_per_thread = context->max_fds /
|
||||
context->count_threads;
|
||||
|
||||
lwsl_notice(" Threads: %d each %d fds\n", context->count_threads,
|
||||
context->fd_limit_per_thread);
|
||||
struct lws wsi;
|
||||
memset(&wsi, 0, sizeof(wsi));
|
||||
wsi.context = context;
|
||||
|
||||
if (!info->ka_interval && info->ka_time > 0) {
|
||||
lwsl_err("info->ka_interval can't be 0 if ka_time used\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef LWS_USE_LIBEV
|
||||
/* (Issue #264) In order to *avoid breaking backwards compatibility*, we
|
||||
* enable libev mediated SIGINT handling with a default handler of
|
||||
* lws_sigint_cb. The handler can be overridden or disabled
|
||||
* by invoking lws_sigint_cfg after creating the context, but
|
||||
* before invoking lws_initloop:
|
||||
*/
|
||||
context->use_ev_sigint = 1;
|
||||
context->lws_ev_sigint_cb = &lws_ev_sigint_cb;
|
||||
#endif /* LWS_USE_LIBEV */
|
||||
#ifdef LWS_USE_LIBUV
|
||||
/* (Issue #264) In order to *avoid breaking backwards compatibility*, we
|
||||
* enable libev mediated SIGINT handling with a default handler of
|
||||
* lws_sigint_cb. The handler can be overridden or disabled
|
||||
* by invoking lws_sigint_cfg after creating the context, but
|
||||
* before invoking lws_initloop:
|
||||
*/
|
||||
context->use_ev_sigint = 1;
|
||||
context->lws_uv_sigint_cb = &lws_uv_sigint_cb;
|
||||
#endif
|
||||
|
||||
lwsl_info(" mem: context: %5u bytes (%d ctx + (%d thr x %d))\n",
|
||||
sizeof(struct lws_context) +
|
||||
(context->count_threads * context->pt_serv_buf_size),
|
||||
sizeof(struct lws_context),
|
||||
context->count_threads,
|
||||
context->pt_serv_buf_size);
|
||||
|
||||
lwsl_info(" mem: http hdr rsvd: %5u bytes (%u thr x (%u + %u) x %u))\n",
|
||||
(context->max_http_header_data +
|
||||
sizeof(struct allocated_headers)) *
|
||||
context->max_http_header_pool * context->count_threads,
|
||||
context->count_threads,
|
||||
context->max_http_header_data,
|
||||
sizeof(struct allocated_headers),
|
||||
context->max_http_header_pool);
|
||||
n = sizeof(struct lws_pollfd) * context->count_threads *
|
||||
context->fd_limit_per_thread;
|
||||
context->pt[0].fds = lws_zalloc(n);
|
||||
if (context->pt[0].fds == NULL) {
|
||||
lwsl_err("OOM allocating %d fds\n", context->max_fds);
|
||||
goto bail;
|
||||
}
|
||||
lwsl_info(" mem: pollfd map: %5u\n", n);
|
||||
|
||||
if (info->server_string) {
|
||||
context->server_string = info->server_string;
|
||||
context->server_string_len = (short)
|
||||
strlen(context->server_string);
|
||||
} else {
|
||||
context->server_string = "libwebsockets";
|
||||
context->server_string_len = 13;
|
||||
}
|
||||
|
||||
#if LWS_MAX_SMP > 1
|
||||
/* each thread serves his own chunk of fds */
|
||||
for (n = 1; n < (int)info->count_threads; n++)
|
||||
context->pt[n].fds = context->pt[n - 1].fds +
|
||||
context->fd_limit_per_thread;
|
||||
#endif
|
||||
|
||||
if (lws_plat_init(context, info))
|
||||
goto bail;
|
||||
|
||||
lws_context_init_ssl_library(info);
|
||||
|
||||
context->user_space = info->user;
|
||||
|
||||
/*
|
||||
* if he's not saying he'll make his own vhosts later then act
|
||||
* compatibly and make a default vhost using the data in the info
|
||||
*/
|
||||
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
|
||||
if (!lws_create_vhost(context, info)) {
|
||||
lwsl_err("Failed to create default vhost\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lws_context_init_extensions(info, context);
|
||||
|
||||
lwsl_notice(" mem: per-conn: %5u bytes + protocol rx buf\n",
|
||||
sizeof(struct lws));
|
||||
|
||||
strcpy(context->canonical_hostname, "unknown");
|
||||
lws_server_get_canonical_hostname(context, info);
|
||||
|
||||
context->uid = info->uid;
|
||||
context->gid = info->gid;
|
||||
|
||||
/*
|
||||
* drop any root privs for this process
|
||||
* to listen on port < 1023 we would have needed root, but now we are
|
||||
* listening, we don't want the power for anything else
|
||||
*/
|
||||
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
|
||||
lws_plat_drop_app_privileges(info);
|
||||
|
||||
/*
|
||||
* give all extensions a chance to create any per-context
|
||||
* allocations they need
|
||||
*/
|
||||
if (info->port != CONTEXT_PORT_NO_LISTEN) {
|
||||
if (lws_ext_cb_all_exts(context, NULL,
|
||||
LWS_EXT_CB_SERVER_CONTEXT_CONSTRUCT, NULL, 0) < 0)
|
||||
goto bail;
|
||||
} else
|
||||
if (lws_ext_cb_all_exts(context, NULL,
|
||||
LWS_EXT_CB_CLIENT_CONTEXT_CONSTRUCT, NULL, 0) < 0)
|
||||
goto bail;
|
||||
|
||||
return context;
|
||||
|
||||
bail:
|
||||
lws_context_destroy(context);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_context_destroy(struct lws_context *context)
|
||||
{
|
||||
const struct lws_protocols *protocol = NULL;
|
||||
struct lws_context_per_thread *pt;
|
||||
struct lws_vhost *vh = NULL, *vh1;
|
||||
struct lws wsi;
|
||||
int n, m;
|
||||
|
||||
lwsl_notice("%s\n", __func__);
|
||||
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
m = context->count_threads;
|
||||
context->being_destroyed = 1;
|
||||
|
||||
memset(&wsi, 0, sizeof(wsi));
|
||||
wsi.context = context;
|
||||
|
||||
#ifdef LWS_LATENCY
|
||||
if (context->worst_latency_info[0])
|
||||
lwsl_notice("Worst latency: %s\n", context->worst_latency_info);
|
||||
#endif
|
||||
|
||||
while (m--) {
|
||||
pt = &context->pt[m];
|
||||
|
||||
for (n = 0; (unsigned int)n < context->pt[m].fds_count; n++) {
|
||||
struct lws *wsi1 = wsi_from_fd(context, pt->fds[n].fd);
|
||||
if (!wsi1)
|
||||
continue;
|
||||
|
||||
lws_close_free_wsi(wsi1,
|
||||
LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY
|
||||
/* no protocol close */);
|
||||
n--;
|
||||
}
|
||||
lws_pt_mutex_destroy(pt);
|
||||
}
|
||||
/*
|
||||
* give all extensions a chance to clean up any per-context
|
||||
* allocations they might have made
|
||||
*/
|
||||
|
||||
n = lws_ext_cb_all_exts(context, NULL,
|
||||
LWS_EXT_CB_SERVER_CONTEXT_DESTRUCT, NULL, 0);
|
||||
|
||||
n = lws_ext_cb_all_exts(context, NULL,
|
||||
LWS_EXT_CB_CLIENT_CONTEXT_DESTRUCT, NULL, 0);
|
||||
|
||||
/*
|
||||
* inform all the protocols that they are done and will have no more
|
||||
* callbacks.
|
||||
*
|
||||
* We can't free things until after the event loop shuts down.
|
||||
*/
|
||||
if (context->protocol_init_done)
|
||||
vh = context->vhost_list;
|
||||
while (vh) {
|
||||
wsi.vhost = vh;
|
||||
protocol = vh->protocols;
|
||||
if (protocol) {
|
||||
n = 0;
|
||||
while (n < vh->count_protocols) {
|
||||
wsi.protocol = protocol;
|
||||
protocol->callback(&wsi, LWS_CALLBACK_PROTOCOL_DESTROY,
|
||||
NULL, NULL, 0);
|
||||
protocol++;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
vh = vh->vhost_next;
|
||||
}
|
||||
|
||||
for (n = 0; n < context->count_threads; n++) {
|
||||
pt = &context->pt[n];
|
||||
|
||||
lws_libev_destroyloop(context, n);
|
||||
lws_libuv_destroyloop(context, n);
|
||||
|
||||
lws_free_set_NULL(context->pt[n].serv_buf);
|
||||
if (pt->ah_pool)
|
||||
lws_free(pt->ah_pool);
|
||||
if (pt->http_header_data)
|
||||
lws_free(pt->http_header_data);
|
||||
}
|
||||
lws_plat_context_early_destroy(context);
|
||||
lws_ssl_context_destroy(context);
|
||||
|
||||
if (context->pt[0].fds)
|
||||
lws_free_set_NULL(context->pt[0].fds);
|
||||
|
||||
/* free all the vhost allocations */
|
||||
|
||||
vh = context->vhost_list;
|
||||
while (vh) {
|
||||
protocol = vh->protocols;
|
||||
if (protocol) {
|
||||
n = 0;
|
||||
while (n < vh->count_protocols) {
|
||||
if (vh->protocol_vh_privs &&
|
||||
vh->protocol_vh_privs[n]) {
|
||||
lws_free(vh->protocol_vh_privs[n]);
|
||||
vh->protocol_vh_privs[n] = NULL;
|
||||
}
|
||||
protocol++;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
if (vh->protocol_vh_privs)
|
||||
lws_free(vh->protocol_vh_privs);
|
||||
lws_ssl_SSL_CTX_destroy(vh);
|
||||
lws_free(vh->same_vh_protocol_list);
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
if (context->plugin_list)
|
||||
lws_free((void *)vh->protocols);
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
if (context->plugin_extension_count)
|
||||
lws_free((void *)vh->extensions);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef LWS_WITH_ACCESS_LOG
|
||||
if (vh->log_fd != (int)LWS_INVALID_FILE)
|
||||
close(vh->log_fd);
|
||||
#endif
|
||||
|
||||
vh1 = vh->vhost_next;
|
||||
lws_free(vh);
|
||||
vh = vh1;
|
||||
}
|
||||
|
||||
lws_plat_context_late_destroy(context);
|
||||
|
||||
lws_free(context);
|
||||
}
|
||||
238
feeds/wlan-ap/libwebsocket/src/getifaddrs.c
Normal file
238
feeds/wlan-ap/libwebsocket/src/getifaddrs.c
Normal file
@@ -0,0 +1,238 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#if !LWS_HAVE_GETIFADDRS
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include "websocket/private-libwebsockets.h"
|
||||
|
||||
#ifdef LWS_HAVE_SYS_SOCKIO_H
|
||||
#include <sys/sockio.h>
|
||||
#endif
|
||||
|
||||
#ifdef LWS_HAVE_NETINET_IN6_VAR_H
|
||||
#include <netinet/in6_var.h>
|
||||
#endif
|
||||
|
||||
#ifndef max
|
||||
#define max(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#include "websocket/getifaddrs.h"
|
||||
|
||||
static int
|
||||
getifaddrs2(struct ifaddrs **ifap, int af, int siocgifconf, int siocgifflags,
|
||||
size_t ifreq_sz)
|
||||
{
|
||||
int ret;
|
||||
int fd;
|
||||
size_t buf_size;
|
||||
char *buf;
|
||||
struct ifconf ifconf;
|
||||
char *p;
|
||||
size_t sz;
|
||||
struct sockaddr sa_zero;
|
||||
struct ifreq *ifr;
|
||||
struct ifaddrs *start, **end = &start;
|
||||
|
||||
buf = NULL;
|
||||
|
||||
memset(&sa_zero, 0, sizeof(sa_zero));
|
||||
fd = socket(af, SOCK_DGRAM, 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
buf_size = 8192;
|
||||
for (;;) {
|
||||
buf = lws_zalloc(buf_size);
|
||||
if (buf == NULL) {
|
||||
ret = ENOMEM;
|
||||
goto error_out;
|
||||
}
|
||||
ifconf.ifc_len = buf_size;
|
||||
ifconf.ifc_buf = buf;
|
||||
|
||||
/*
|
||||
* Solaris returns EINVAL when the buffer is too small.
|
||||
*/
|
||||
if (ioctl(fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) {
|
||||
ret = errno;
|
||||
goto error_out;
|
||||
}
|
||||
/*
|
||||
* Can the difference between a full and a overfull buf
|
||||
* be determined?
|
||||
*/
|
||||
|
||||
if (ifconf.ifc_len < (int)buf_size)
|
||||
break;
|
||||
lws_free(buf);
|
||||
buf_size *= 2;
|
||||
}
|
||||
|
||||
for (p = ifconf.ifc_buf; p < ifconf.ifc_buf + ifconf.ifc_len; p += sz) {
|
||||
struct ifreq ifreq;
|
||||
struct sockaddr *sa;
|
||||
size_t salen;
|
||||
|
||||
ifr = (struct ifreq *)p;
|
||||
sa = &ifr->ifr_addr;
|
||||
|
||||
sz = ifreq_sz;
|
||||
salen = sizeof(struct sockaddr);
|
||||
#ifdef LWS_HAVE_STRUCT_SOCKADDR_SA_LEN
|
||||
salen = sa->sa_len;
|
||||
sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len);
|
||||
#endif
|
||||
#ifdef SA_LEN
|
||||
salen = SA_LEN(sa);
|
||||
sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa));
|
||||
#endif
|
||||
memset(&ifreq, 0, sizeof(ifreq));
|
||||
memcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifr->ifr_name));
|
||||
|
||||
if (ioctl(fd, siocgifflags, &ifreq) < 0) {
|
||||
ret = errno;
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
*end = lws_malloc(sizeof(**end));
|
||||
|
||||
(*end)->ifa_next = NULL;
|
||||
(*end)->ifa_name = strdup(ifr->ifr_name);
|
||||
(*end)->ifa_flags = ifreq.ifr_flags;
|
||||
(*end)->ifa_addr = lws_malloc(salen);
|
||||
memcpy((*end)->ifa_addr, sa, salen);
|
||||
(*end)->ifa_netmask = NULL;
|
||||
|
||||
#if 0
|
||||
/* fix these when we actually need them */
|
||||
if (ifreq.ifr_flags & IFF_BROADCAST) {
|
||||
(*end)->ifa_broadaddr =
|
||||
lws_malloc(sizeof(ifr->ifr_broadaddr));
|
||||
memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr,
|
||||
sizeof(ifr->ifr_broadaddr));
|
||||
} else if (ifreq.ifr_flags & IFF_POINTOPOINT) {
|
||||
(*end)->ifa_dstaddr =
|
||||
lws_malloc(sizeof(ifr->ifr_dstaddr));
|
||||
memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr,
|
||||
sizeof(ifr->ifr_dstaddr));
|
||||
} else
|
||||
(*end)->ifa_dstaddr = NULL;
|
||||
#else
|
||||
(*end)->ifa_dstaddr = NULL;
|
||||
#endif
|
||||
(*end)->ifa_data = NULL;
|
||||
|
||||
end = &(*end)->ifa_next;
|
||||
|
||||
}
|
||||
*ifap = start;
|
||||
close(fd);
|
||||
lws_free(buf);
|
||||
return 0;
|
||||
|
||||
error_out:
|
||||
close(fd);
|
||||
lws_free(buf);
|
||||
errno = ret;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
getifaddrs(struct ifaddrs **ifap)
|
||||
{
|
||||
int ret = -1;
|
||||
errno = ENXIO;
|
||||
#if defined(AF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS)
|
||||
if (ret)
|
||||
ret = getifaddrs2(ifap, AF_INET6, SIOCGIF6CONF, SIOCGIF6FLAGS,
|
||||
sizeof(struct in6_ifreq));
|
||||
#endif
|
||||
#if defined(LWS_HAVE_IPV6) && defined(SIOCGIFCONF)
|
||||
if (ret)
|
||||
ret = getifaddrs2(ifap, AF_INET6, SIOCGIFCONF, SIOCGIFFLAGS,
|
||||
sizeof(struct ifreq));
|
||||
#endif
|
||||
#if defined(AF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS)
|
||||
if (ret)
|
||||
ret = getifaddrs2(ifap, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,
|
||||
sizeof(struct ifreq));
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
freeifaddrs(struct ifaddrs *ifp)
|
||||
{
|
||||
struct ifaddrs *p, *q;
|
||||
|
||||
for (p = ifp; p; ) {
|
||||
lws_free(p->ifa_name);
|
||||
lws_free(p->ifa_addr);
|
||||
lws_free(p->ifa_dstaddr);
|
||||
lws_free(p->ifa_netmask);
|
||||
lws_free(p->ifa_data);
|
||||
q = p;
|
||||
p = p->ifa_next;
|
||||
lws_free(q);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
void
|
||||
print_addr(const char *s, struct sockaddr *sa)
|
||||
{
|
||||
int i;
|
||||
printf(" %s=%d/", s, sa->sa_family);
|
||||
#ifdef LWS_HAVE_STRUCT_SOCKADDR_SA_LEN
|
||||
for (i = 0;
|
||||
i < sa->sa_len - ((long)sa->sa_data - (long)&sa->sa_family); i++)
|
||||
printf("%02x", ((unsigned char *)sa->sa_data)[i]);
|
||||
#else
|
||||
for (i = 0; i < sizeof(sa->sa_data); i++)
|
||||
printf("%02x", ((unsigned char *)sa->sa_data)[i]);
|
||||
#endif
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void
|
||||
print_ifaddrs(struct ifaddrs *x)
|
||||
{
|
||||
struct ifaddrs *p;
|
||||
|
||||
for (p = x; p; p = p->ifa_next) {
|
||||
printf("%s\n", p->ifa_name);
|
||||
printf(" flags=%x\n", p->ifa_flags);
|
||||
if (p->ifa_addr)
|
||||
print_addr("addr", p->ifa_addr);
|
||||
if (p->ifa_dstaddr)
|
||||
print_addr("dstaddr", p->ifa_dstaddr);
|
||||
if (p->ifa_netmask)
|
||||
print_addr("netmask", p->ifa_netmask);
|
||||
printf(" %p\n", p->ifa_data);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
struct ifaddrs *a = NULL, *b;
|
||||
getifaddrs2(&a, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,
|
||||
sizeof(struct ifreq));
|
||||
print_ifaddrs(a);
|
||||
printf("---\n");
|
||||
getifaddrs(&b);
|
||||
print_ifaddrs(b);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
238
feeds/wlan-ap/libwebsocket/src/handshake.c
Normal file
238
feeds/wlan-ap/libwebsocket/src/handshake.c
Normal file
@@ -0,0 +1,238 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#include "websocket/private-libwebsockets.h"
|
||||
|
||||
/*
|
||||
* -04 of the protocol (actually the 80th version) has a radically different
|
||||
* handshake. The 04 spec gives the following idea
|
||||
*
|
||||
* The handshake from the client looks as follows:
|
||||
*
|
||||
* GET /chat HTTP/1.1
|
||||
* Host: server.example.com
|
||||
* Upgrade: websocket
|
||||
* Connection: Upgrade
|
||||
* Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
|
||||
* Sec-WebSocket-Origin: http://example.com
|
||||
* Sec-WebSocket-Protocol: chat, superchat
|
||||
* Sec-WebSocket-Version: 4
|
||||
*
|
||||
* The handshake from the server looks as follows:
|
||||
*
|
||||
* HTTP/1.1 101 Switching Protocols
|
||||
* Upgrade: websocket
|
||||
* Connection: Upgrade
|
||||
* Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo=
|
||||
* Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC==
|
||||
* Sec-WebSocket-Protocol: chat
|
||||
*/
|
||||
|
||||
#ifndef min
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We have to take care about parsing because the headers may be split
|
||||
* into multiple fragments. They may contain unknown headers with arbitrary
|
||||
* argument lengths. So, we parse using a single-character at a time state
|
||||
* machine that is completely independent of packet size.
|
||||
*
|
||||
* Returns <0 for error or length of chars consumed from buf (up to len)
|
||||
*/
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_read(struct lws *wsi, unsigned char *buf, size_t len)
|
||||
{
|
||||
unsigned char *last_char, *oldbuf = buf;
|
||||
int body_chunk_len;
|
||||
size_t n;
|
||||
|
||||
lwsl_debug("%s: incoming len %d state %d\n", __func__, (int)len, wsi->state);
|
||||
|
||||
switch (wsi->state) {
|
||||
#ifdef LWS_USE_HTTP2
|
||||
case LWSS_HTTP2_AWAIT_CLIENT_PREFACE:
|
||||
case LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS:
|
||||
case LWSS_HTTP2_ESTABLISHED:
|
||||
n = 0;
|
||||
while (n < len) {
|
||||
/*
|
||||
* we were accepting input but now we stopped doing so
|
||||
*/
|
||||
if (!(wsi->rxflow_change_to & LWS_RXFLOW_ALLOW)) {
|
||||
lws_rxflow_cache(wsi, buf, n, len);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* account for what we're using in rxflow buffer */
|
||||
if (wsi->rxflow_buffer)
|
||||
wsi->rxflow_pos++;
|
||||
if (lws_http2_parser(wsi, buf[n++])) {
|
||||
lwsl_debug("%s: http2_parser bailed\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case LWSS_CLIENT_HTTP_ESTABLISHED:
|
||||
break;
|
||||
|
||||
case LWSS_HTTP:
|
||||
wsi->hdr_parsing_completed = 0;
|
||||
/* fallthru */
|
||||
case LWSS_HTTP_ISSUING_FILE:
|
||||
wsi->state = LWSS_HTTP_HEADERS;
|
||||
wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
|
||||
wsi->u.hdr.lextable_pos = 0;
|
||||
/* fallthru */
|
||||
case LWSS_HTTP_HEADERS:
|
||||
if (!wsi->u.hdr.ah) {
|
||||
lwsl_err("%s: LWSS_HTTP_HEADERS: NULL ah\n", __func__);
|
||||
assert(0);
|
||||
}
|
||||
lwsl_parser("issuing %d bytes to parser\n", (int)len);
|
||||
|
||||
if (lws_handshake_client(wsi, &buf, len))
|
||||
goto bail;
|
||||
|
||||
last_char = buf;
|
||||
if (lws_handshake_server(wsi, &buf, len))
|
||||
/* Handshake indicates this session is done. */
|
||||
goto bail;
|
||||
|
||||
/*
|
||||
* It's possible that we've exhausted our data already, or
|
||||
* rx flow control has stopped us dealing with this early,
|
||||
* but lws_handshake_server doesn't update len for us.
|
||||
* Figure out how much was read, so that we can proceed
|
||||
* appropriately:
|
||||
*/
|
||||
len -= (buf - last_char);
|
||||
lwsl_debug("%s: thinks we have used %d\n", __func__, len);
|
||||
|
||||
if (!wsi->hdr_parsing_completed)
|
||||
/* More header content on the way */
|
||||
goto read_ok;
|
||||
|
||||
switch (wsi->state) {
|
||||
case LWSS_HTTP:
|
||||
case LWSS_HTTP_HEADERS:
|
||||
goto read_ok;
|
||||
case LWSS_HTTP_ISSUING_FILE:
|
||||
goto read_ok;
|
||||
case LWSS_HTTP_BODY:
|
||||
wsi->u.http.content_remain =
|
||||
wsi->u.http.content_length;
|
||||
if (wsi->u.http.content_remain)
|
||||
goto http_postbody;
|
||||
|
||||
/* there is no POST content */
|
||||
goto postbody_completion;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWSS_HTTP_BODY:
|
||||
http_postbody:
|
||||
while (len && wsi->u.http.content_remain) {
|
||||
/* Copy as much as possible, up to the limit of:
|
||||
* what we have in the read buffer (len)
|
||||
* remaining portion of the POST body (content_remain)
|
||||
*/
|
||||
body_chunk_len = min(wsi->u.http.content_remain,len);
|
||||
wsi->u.http.content_remain -= body_chunk_len;
|
||||
len -= body_chunk_len;
|
||||
#ifdef LWS_WITH_CGI
|
||||
if (wsi->cgi) {
|
||||
struct lws_cgi_args args;
|
||||
|
||||
args.ch = LWS_STDIN;
|
||||
args.stdwsi = &wsi->cgi->stdwsi[0];
|
||||
args.data = buf;
|
||||
args.len = body_chunk_len;
|
||||
|
||||
/* returns how much used */
|
||||
n = user_callback_handle_rxflow(
|
||||
wsi->protocol->callback,
|
||||
wsi, LWS_CALLBACK_CGI_STDIN_DATA,
|
||||
wsi->user_space,
|
||||
(void *)&args, 0);
|
||||
if ((int)n < 0)
|
||||
goto bail;
|
||||
} else {
|
||||
#endif
|
||||
n = wsi->protocol->callback(wsi,
|
||||
LWS_CALLBACK_HTTP_BODY, wsi->user_space,
|
||||
buf, body_chunk_len);
|
||||
if (n)
|
||||
goto bail;
|
||||
n = body_chunk_len;
|
||||
#ifdef LWS_WITH_CGI
|
||||
}
|
||||
#endif
|
||||
buf += n;
|
||||
|
||||
if (wsi->u.http.content_remain) {
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,
|
||||
wsi->context->timeout_secs);
|
||||
break;
|
||||
}
|
||||
/* he sent all the content in time */
|
||||
postbody_completion:
|
||||
#ifdef LWS_WITH_CGI
|
||||
/* if we're running a cgi, we can't let him off the hook just because he sent his POST data */
|
||||
if (wsi->cgi)
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, wsi->context->timeout_secs);
|
||||
else
|
||||
#endif
|
||||
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
||||
#ifdef LWS_WITH_CGI
|
||||
if (!wsi->cgi)
|
||||
#endif
|
||||
{
|
||||
n = wsi->protocol->callback(wsi,
|
||||
LWS_CALLBACK_HTTP_BODY_COMPLETION,
|
||||
wsi->user_space, NULL, 0);
|
||||
if (n)
|
||||
goto bail;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWSS_ESTABLISHED:
|
||||
case LWSS_AWAITING_CLOSE_ACK:
|
||||
case LWSS_SHUTDOWN:
|
||||
if (lws_handshake_client(wsi, &buf, len))
|
||||
goto bail;
|
||||
switch (wsi->mode) {
|
||||
case LWSCM_WS_SERVING:
|
||||
|
||||
if (lws_interpret_incoming_packet(wsi, &buf, len) < 0) {
|
||||
lwsl_info("interpret_incoming_packet has bailed\n");
|
||||
goto bail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
lwsl_err("%s: Unhandled state %d\n", __func__, wsi->state);
|
||||
break;
|
||||
}
|
||||
|
||||
read_ok:
|
||||
/* Nothing more to do for now */
|
||||
lwsl_info("%s: read_ok, used %d\n", __func__, buf - oldbuf);
|
||||
|
||||
return buf - oldbuf;
|
||||
|
||||
bail:
|
||||
//lwsl_notice("closing connection at lws_read bail:\n");
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
|
||||
|
||||
return -1;
|
||||
}
|
||||
280
feeds/wlan-ap/libwebsocket/src/header.c
Normal file
280
feeds/wlan-ap/libwebsocket/src/header.c
Normal file
@@ -0,0 +1,280 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#include "websocket/private-libwebsockets.h"
|
||||
|
||||
#include "websocket/lextable-strings.h"
|
||||
|
||||
|
||||
const unsigned char *lws_token_to_string(enum lws_token_indexes token)
|
||||
{
|
||||
if ((unsigned int)token >= ARRAY_SIZE(set))
|
||||
return NULL;
|
||||
|
||||
return (unsigned char *)set[token];
|
||||
}
|
||||
|
||||
int
|
||||
lws_add_http_header_by_name(struct lws *wsi, const unsigned char *name,
|
||||
const unsigned char *value, int length,
|
||||
unsigned char **p, unsigned char *end)
|
||||
{
|
||||
#ifdef LWS_USE_HTTP2
|
||||
if (wsi->mode == LWSCM_HTTP2_SERVING)
|
||||
return lws_add_http2_header_by_name(wsi, name,
|
||||
value, length, p, end);
|
||||
#else
|
||||
(void)wsi;
|
||||
#endif
|
||||
if (name) {
|
||||
while (*p < end && *name)
|
||||
*((*p)++) = *name++;
|
||||
if (*p == end)
|
||||
return 1;
|
||||
*((*p)++) = ' ';
|
||||
}
|
||||
if (*p + length + 3 >= end)
|
||||
return 1;
|
||||
|
||||
memcpy(*p, value, length);
|
||||
*p += length;
|
||||
*((*p)++) = '\x0d';
|
||||
*((*p)++) = '\x0a';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lws_finalize_http_header(struct lws *wsi, unsigned char **p,
|
||||
unsigned char *end)
|
||||
{
|
||||
#ifdef LWS_USE_HTTP2
|
||||
if (wsi->mode == LWSCM_HTTP2_SERVING)
|
||||
return 0;
|
||||
#else
|
||||
(void)wsi;
|
||||
#endif
|
||||
if ((long)(end - *p) < 3)
|
||||
return 1;
|
||||
*((*p)++) = '\x0d';
|
||||
*((*p)++) = '\x0a';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_add_http_header_by_token(struct lws *wsi, enum lws_token_indexes token,
|
||||
const unsigned char *value, int length,
|
||||
unsigned char **p, unsigned char *end)
|
||||
{
|
||||
const unsigned char *name;
|
||||
#ifdef LWS_USE_HTTP2
|
||||
if (wsi->mode == LWSCM_HTTP2_SERVING)
|
||||
return lws_add_http2_header_by_token(wsi, token, value, length, p, end);
|
||||
#endif
|
||||
name = lws_token_to_string(token);
|
||||
if (!name)
|
||||
return 1;
|
||||
return lws_add_http_header_by_name(wsi, name, value, length, p, end);
|
||||
}
|
||||
|
||||
int lws_add_http_header_content_length(struct lws *wsi,
|
||||
unsigned long content_length,
|
||||
unsigned char **p, unsigned char *end)
|
||||
{
|
||||
char b[24];
|
||||
int n;
|
||||
|
||||
n = sprintf(b, "%lu", content_length);
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
|
||||
(unsigned char *)b, n, p, end))
|
||||
return 1;
|
||||
wsi->u.http.content_length = content_length;
|
||||
wsi->u.http.content_remain = content_length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
STORE_IN_ROM static const char * const err400[] = {
|
||||
"Bad Request",
|
||||
"Unauthorized",
|
||||
"Payment Required",
|
||||
"Forbidden",
|
||||
"Not Found",
|
||||
"Method Not Allowed",
|
||||
"Not Acceptable",
|
||||
"Proxy Auth Required",
|
||||
"Request Timeout",
|
||||
"Conflict",
|
||||
"Gone",
|
||||
"Length Required",
|
||||
"Precondition Failed",
|
||||
"Request Entity Too Large",
|
||||
"Request URI too Long",
|
||||
"Unsupported Media Type",
|
||||
"Requested Range Not Satisfiable",
|
||||
"Expectation Failed"
|
||||
};
|
||||
|
||||
STORE_IN_ROM static const char * const err500[] = {
|
||||
"Internal Server Error",
|
||||
"Not Implemented",
|
||||
"Bad Gateway",
|
||||
"Service Unavailable",
|
||||
"Gateway Timeout",
|
||||
"HTTP Version Not Supported"
|
||||
};
|
||||
|
||||
int
|
||||
lws_add_http_header_status(struct lws *wsi, unsigned int code,
|
||||
unsigned char **p, unsigned char *end)
|
||||
{
|
||||
const struct lws_protocol_vhost_options *headers;
|
||||
unsigned char code_and_desc[60];
|
||||
const char *description = "", *p1;
|
||||
int n;
|
||||
STORE_IN_ROM static const char * const hver[] = {
|
||||
"HTTP/1.0", "HTTP/1.1", "HTTP/2"
|
||||
};
|
||||
|
||||
#ifdef LWS_WITH_ACCESS_LOG
|
||||
wsi->access_log.response = code;
|
||||
#endif
|
||||
|
||||
#ifdef LWS_USE_HTTP2
|
||||
if (wsi->mode == LWSCM_HTTP2_SERVING)
|
||||
return lws_add_http2_header_status(wsi, code, p, end);
|
||||
#endif
|
||||
if (code >= 400 && code < (400 + ARRAY_SIZE(err400)))
|
||||
description = err400[code - 400];
|
||||
if (code >= 500 && code < (500 + ARRAY_SIZE(err500)))
|
||||
description = err500[code - 500];
|
||||
|
||||
if (code == 200)
|
||||
description = "OK";
|
||||
|
||||
if (code == 304)
|
||||
description = "Not Modified";
|
||||
else
|
||||
if (code >= 300 && code < 400)
|
||||
description = "Redirect";
|
||||
|
||||
if (wsi->u.http.request_version < ARRAY_SIZE(hver))
|
||||
p1 = hver[wsi->u.http.request_version];
|
||||
else
|
||||
p1 = hver[0];
|
||||
|
||||
n = sprintf((char *)code_and_desc, "%s %u %s",
|
||||
p1, code, description);
|
||||
|
||||
if (lws_add_http_header_by_name(wsi, NULL, code_and_desc,
|
||||
n, p, end))
|
||||
return 1;
|
||||
|
||||
headers = wsi->vhost->headers;
|
||||
while (headers) {
|
||||
if (lws_add_http_header_by_name(wsi,
|
||||
(const unsigned char *)headers->name,
|
||||
(unsigned char *)headers->value,
|
||||
strlen(headers->value), p, end))
|
||||
return 1;
|
||||
|
||||
headers = headers->next;
|
||||
}
|
||||
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER,
|
||||
(unsigned char *)
|
||||
wsi->context->server_string,
|
||||
wsi->context->server_string_len,
|
||||
p, end))
|
||||
return 1;
|
||||
|
||||
if (wsi->vhost->options & LWS_SERVER_OPTION_STS)
|
||||
if (lws_add_http_header_by_name(wsi, (unsigned char *)
|
||||
"Strict-Transport-Security:",
|
||||
(unsigned char *)"max-age=15768000 ; "
|
||||
"includeSubDomains", 36, p, end))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_return_http_status(struct lws *wsi, unsigned int code,
|
||||
const char *html_body)
|
||||
{
|
||||
struct lws_context *context = lws_get_context(wsi);
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
unsigned char *p = pt->serv_buf + LWS_PRE;
|
||||
unsigned char *start = p, *body = p + 512;
|
||||
unsigned char *end = p + context->pt_serv_buf_size - LWS_PRE;
|
||||
int n, m, len;
|
||||
char slen[20];
|
||||
|
||||
if (!html_body)
|
||||
html_body = "";
|
||||
|
||||
len = sprintf((char *)body, "<html><body><h1>%u</h1>%s</body></html>",
|
||||
code, html_body);
|
||||
|
||||
if (lws_add_http_header_status(wsi, code, &p, end))
|
||||
return 1;
|
||||
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
|
||||
(unsigned char *)"text/html", 9,
|
||||
&p, end))
|
||||
return 1;
|
||||
n = sprintf(slen, "%d", len);
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
|
||||
(unsigned char *)slen, n,
|
||||
&p, end))
|
||||
return 1;
|
||||
|
||||
if (lws_finalize_http_header(wsi, &p, end))
|
||||
return 1;
|
||||
|
||||
m = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
|
||||
if (m != (int)(p - start))
|
||||
return 1;
|
||||
|
||||
m = lws_write(wsi, body, len, LWS_WRITE_HTTP);
|
||||
|
||||
return m != n;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_http_redirect(struct lws *wsi, int code, const unsigned char *loc, int len,
|
||||
unsigned char **p, unsigned char *end)
|
||||
{
|
||||
unsigned char *start = *p;
|
||||
int n;
|
||||
|
||||
if (lws_add_http_header_status(wsi, code, p, end))
|
||||
return -1;
|
||||
|
||||
if (lws_add_http_header_by_token(wsi,
|
||||
WSI_TOKEN_HTTP_LOCATION,
|
||||
loc, len, p, end))
|
||||
return -1;
|
||||
/*
|
||||
* if we're going with http/1.1 and keepalive,
|
||||
* we have to give fake content metadata so the
|
||||
* client knows we completed the transaction and
|
||||
* it can do the redirect...
|
||||
*/
|
||||
if (lws_add_http_header_by_token(wsi,
|
||||
WSI_TOKEN_HTTP_CONTENT_TYPE,
|
||||
(unsigned char *)"text/html", 9,
|
||||
p, end))
|
||||
return -1;
|
||||
if (lws_add_http_header_by_token(wsi,
|
||||
WSI_TOKEN_HTTP_CONTENT_LENGTH,
|
||||
(unsigned char *)"0", 1, p, end))
|
||||
return -1;
|
||||
|
||||
if (lws_finalize_http_header(wsi, p, end))
|
||||
return -1;
|
||||
|
||||
n = lws_write(wsi, start, *p - start,
|
||||
LWS_WRITE_HTTP_HEADERS);
|
||||
|
||||
return n;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#ifndef LWS_HAVE_GETIFADDRS
|
||||
#define LWS_HAVE_GETIFADDRS 0
|
||||
#endif
|
||||
|
||||
#if LWS_HAVE_GETIFADDRS
|
||||
#include <sys/types.h>
|
||||
#include <ifaddrs.h>
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef ifaddrs_h_7467027A95AD4B5C8DDD40FE7D973791
|
||||
#define ifaddrs_h_7467027A95AD4B5C8DDD40FE7D973791
|
||||
|
||||
/*
|
||||
* the interface is defined in terms of the fields below, and this is
|
||||
* sometimes #define'd, so there seems to be no simple way of solving
|
||||
* this and this seemed the best. */
|
||||
|
||||
#undef ifa_dstaddr
|
||||
|
||||
struct ifaddrs {
|
||||
struct ifaddrs *ifa_next;
|
||||
char *ifa_name;
|
||||
unsigned int ifa_flags;
|
||||
struct sockaddr *ifa_addr;
|
||||
struct sockaddr *ifa_netmask;
|
||||
struct sockaddr *ifa_dstaddr;
|
||||
void *ifa_data;
|
||||
};
|
||||
|
||||
#ifndef ifa_broadaddr
|
||||
#define ifa_broadaddr ifa_dstaddr
|
||||
#endif
|
||||
|
||||
int getifaddrs(struct ifaddrs **);
|
||||
|
||||
void freeifaddrs(struct ifaddrs *);
|
||||
|
||||
#endif /* __ifaddrs_h__ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,100 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
/* set of parsable strings -- ALL LOWER CASE */
|
||||
|
||||
#if !defined(STORE_IN_ROM)
|
||||
#define STORE_IN_ROM
|
||||
#endif
|
||||
|
||||
STORE_IN_ROM static const char * const set[] = {
|
||||
"get ",
|
||||
"post ",
|
||||
"options ",
|
||||
"host:",
|
||||
"connection:",
|
||||
"upgrade:",
|
||||
"origin:",
|
||||
"sec-websocket-draft:",
|
||||
"\x0d\x0a",
|
||||
|
||||
"sec-websocket-extensions:",
|
||||
"sec-websocket-key1:",
|
||||
"sec-websocket-key2:",
|
||||
"sec-websocket-protocol:",
|
||||
|
||||
"sec-websocket-accept:",
|
||||
"sec-websocket-nonce:",
|
||||
"http/1.1 ",
|
||||
"http2-settings:",
|
||||
|
||||
"accept:",
|
||||
"access-control-request-headers:",
|
||||
"if-modified-since:",
|
||||
"if-none-match:",
|
||||
"accept-encoding:",
|
||||
"accept-language:",
|
||||
"pragma:",
|
||||
"cache-control:",
|
||||
"authorization:",
|
||||
"cookie:",
|
||||
"content-length:",
|
||||
"content-type:",
|
||||
"date:",
|
||||
"range:",
|
||||
"referer:",
|
||||
"sec-websocket-key:",
|
||||
"sec-websocket-version:",
|
||||
"sec-websocket-origin:",
|
||||
|
||||
":authority",
|
||||
":method",
|
||||
":path",
|
||||
":scheme",
|
||||
":status",
|
||||
|
||||
"accept-charset:",
|
||||
"accept-ranges:",
|
||||
"access-control-allow-origin:",
|
||||
"age:",
|
||||
"allow:",
|
||||
"content-disposition:",
|
||||
"content-encoding:",
|
||||
"content-language:",
|
||||
"content-location:",
|
||||
"content-range:",
|
||||
"etag:",
|
||||
"expect:",
|
||||
"expires:",
|
||||
"from:",
|
||||
"if-match:",
|
||||
"if-range:",
|
||||
"if-unmodified-since:",
|
||||
"last-modified:",
|
||||
"link:",
|
||||
"location:",
|
||||
"max-forwards:",
|
||||
"proxy-authenticate:",
|
||||
"proxy-authorization:",
|
||||
"refresh:",
|
||||
"retry-after:",
|
||||
"server:",
|
||||
"set-cookie:",
|
||||
"strict-transport-security:",
|
||||
"transfer-encoding:",
|
||||
"user-agent:",
|
||||
"vary:",
|
||||
"via:",
|
||||
"www-authenticate:",
|
||||
|
||||
"patch",
|
||||
"put",
|
||||
"delete",
|
||||
|
||||
"uri-args", /* fake header used for uri-only storage */
|
||||
|
||||
"proxy ",
|
||||
"x-real-ip:",
|
||||
"http/1.0 ",
|
||||
|
||||
"", /* not matchable */
|
||||
|
||||
};
|
||||
780
feeds/wlan-ap/libwebsocket/src/include/websocket/lextable.h
Normal file
780
feeds/wlan-ap/libwebsocket/src/include/websocket/lextable.h
Normal file
@@ -0,0 +1,780 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
/* pos 0000: 0 */ 0x67 /* 'g' */, 0x40, 0x00 /* (to 0x0040 state 1) */,
|
||||
0x70 /* 'p' */, 0x42, 0x00 /* (to 0x0045 state 5) */,
|
||||
0x6F /* 'o' */, 0x51, 0x00 /* (to 0x0057 state 10) */,
|
||||
0x68 /* 'h' */, 0x5D, 0x00 /* (to 0x0066 state 18) */,
|
||||
0x63 /* 'c' */, 0x66, 0x00 /* (to 0x0072 state 23) */,
|
||||
0x75 /* 'u' */, 0x81, 0x00 /* (to 0x0090 state 34) */,
|
||||
0x73 /* 's' */, 0x97, 0x00 /* (to 0x00A9 state 48) */,
|
||||
0x0D /* '.' */, 0xD0, 0x00 /* (to 0x00E5 state 68) */,
|
||||
0x61 /* 'a' */, 0x28, 0x01 /* (to 0x0140 state 129) */,
|
||||
0x69 /* 'i' */, 0x67, 0x01 /* (to 0x0182 state 163) */,
|
||||
0x64 /* 'd' */, 0x10, 0x02 /* (to 0x022E state 265) */,
|
||||
0x72 /* 'r' */, 0x19, 0x02 /* (to 0x023A state 270) */,
|
||||
0x3A /* ':' */, 0x4A, 0x02 /* (to 0x026E state 299) */,
|
||||
0x65 /* 'e' */, 0xD6, 0x02 /* (to 0x02FD state 409) */,
|
||||
0x66 /* 'f' */, 0xF2, 0x02 /* (to 0x031C state 425) */,
|
||||
0x6C /* 'l' */, 0x14, 0x03 /* (to 0x0341 state 458) */,
|
||||
0x6D /* 'm' */, 0x37, 0x03 /* (to 0x0367 state 484) */,
|
||||
0x74 /* 't' */, 0xA6, 0x03 /* (to 0x03D9 state 578) */,
|
||||
0x76 /* 'v' */, 0xC1, 0x03 /* (to 0x03F7 state 606) */,
|
||||
0x77 /* 'w' */, 0xCE, 0x03 /* (to 0x0407 state 614) */,
|
||||
0x78 /* 'x' */, 0xF5, 0x03 /* (to 0x0431 state 650) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0040: 1 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0041: 2 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0042: 3 */ 0xA0 /* ' ' -> */,
|
||||
/* pos 0043: 4 */ 0x00, 0x00 /* - terminal marker 0 - */,
|
||||
/* pos 0045: 5 */ 0x6F /* 'o' */, 0x0D, 0x00 /* (to 0x0052 state 6) */,
|
||||
0x72 /* 'r' */, 0x8C, 0x01 /* (to 0x01D4 state 211) */,
|
||||
0x61 /* 'a' */, 0xCE, 0x03 /* (to 0x0419 state 631) */,
|
||||
0x75 /* 'u' */, 0xD0, 0x03 /* (to 0x041E state 635) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0052: 6 */ 0xF3 /* 's' -> */,
|
||||
/* pos 0053: 7 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0054: 8 */ 0xA0 /* ' ' -> */,
|
||||
/* pos 0055: 9 */ 0x00, 0x01 /* - terminal marker 1 - */,
|
||||
/* pos 0057: 10 */ 0x70 /* 'p' */, 0x07, 0x00 /* (to 0x005E state 11) */,
|
||||
0x72 /* 'r' */, 0x48, 0x00 /* (to 0x00A2 state 42) */,
|
||||
0x08, /* fail */
|
||||
/* pos 005e: 11 */ 0xF4 /* 't' -> */,
|
||||
/* pos 005f: 12 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0060: 13 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0061: 14 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0062: 15 */ 0xF3 /* 's' -> */,
|
||||
/* pos 0063: 16 */ 0xA0 /* ' ' -> */,
|
||||
/* pos 0064: 17 */ 0x00, 0x02 /* - terminal marker 2 - */,
|
||||
/* pos 0066: 18 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x006D state 19) */,
|
||||
0x74 /* 't' */, 0xB6, 0x00 /* (to 0x011F state 110) */,
|
||||
0x08, /* fail */
|
||||
/* pos 006d: 19 */ 0xF3 /* 's' -> */,
|
||||
/* pos 006e: 20 */ 0xF4 /* 't' -> */,
|
||||
/* pos 006f: 21 */ 0xBA /* ':' -> */,
|
||||
/* pos 0070: 22 */ 0x00, 0x03 /* - terminal marker 3 - */,
|
||||
/* pos 0072: 23 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x0079 state 24) */,
|
||||
0x61 /* 'a' */, 0x6C, 0x01 /* (to 0x01E1 state 217) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0079: 24 */ 0x6E /* 'n' */, 0x07, 0x00 /* (to 0x0080 state 25) */,
|
||||
0x6F /* 'o' */, 0x81, 0x01 /* (to 0x01FD state 243) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0080: 25 */ 0x6E /* 'n' */, 0x07, 0x00 /* (to 0x0087 state 26) */,
|
||||
0x74 /* 't' */, 0x80, 0x01 /* (to 0x0203 state 248) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0087: 26 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0088: 27 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0089: 28 */ 0xF4 /* 't' -> */,
|
||||
/* pos 008a: 29 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 008b: 30 */ 0xEF /* 'o' -> */,
|
||||
/* pos 008c: 31 */ 0xEE /* 'n' -> */,
|
||||
/* pos 008d: 32 */ 0xBA /* ':' -> */,
|
||||
/* pos 008e: 33 */ 0x00, 0x04 /* - terminal marker 4 - */,
|
||||
/* pos 0090: 34 */ 0x70 /* 'p' */, 0x0A, 0x00 /* (to 0x009A state 35) */,
|
||||
0x73 /* 's' */, 0x59, 0x03 /* (to 0x03EC state 596) */,
|
||||
0x72 /* 'r' */, 0x91, 0x03 /* (to 0x0427 state 642) */,
|
||||
0x08, /* fail */
|
||||
/* pos 009a: 35 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 009b: 36 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 009c: 37 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 009d: 38 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 009e: 39 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 009f: 40 */ 0xBA /* ':' -> */,
|
||||
/* pos 00a0: 41 */ 0x00, 0x05 /* - terminal marker 5 - */,
|
||||
/* pos 00a2: 42 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 00a3: 43 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 00a4: 44 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 00a5: 45 */ 0xEE /* 'n' -> */,
|
||||
/* pos 00a6: 46 */ 0xBA /* ':' -> */,
|
||||
/* pos 00a7: 47 */ 0x00, 0x06 /* - terminal marker 6 - */,
|
||||
/* pos 00a9: 48 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x00B0 state 49) */,
|
||||
0x74 /* 't' */, 0x13, 0x03 /* (to 0x03BF state 553) */,
|
||||
0x08, /* fail */
|
||||
/* pos 00b0: 49 */ 0x63 /* 'c' */, 0x0A, 0x00 /* (to 0x00BA state 50) */,
|
||||
0x72 /* 'r' */, 0xFC, 0x02 /* (to 0x03AF state 539) */,
|
||||
0x74 /* 't' */, 0xFF, 0x02 /* (to 0x03B5 state 544) */,
|
||||
0x08, /* fail */
|
||||
/* pos 00ba: 50 */ 0xAD /* '-' -> */,
|
||||
/* pos 00bb: 51 */ 0xF7 /* 'w' -> */,
|
||||
/* pos 00bc: 52 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 00bd: 53 */ 0xE2 /* 'b' -> */,
|
||||
/* pos 00be: 54 */ 0xF3 /* 's' -> */,
|
||||
/* pos 00bf: 55 */ 0xEF /* 'o' -> */,
|
||||
/* pos 00c0: 56 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 00c1: 57 */ 0xEB /* 'k' -> */,
|
||||
/* pos 00c2: 58 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 00c3: 59 */ 0xF4 /* 't' -> */,
|
||||
/* pos 00c4: 60 */ 0xAD /* '-' -> */,
|
||||
/* pos 00c5: 61 */ 0x64 /* 'd' */, 0x19, 0x00 /* (to 0x00DE state 62) */,
|
||||
0x65 /* 'e' */, 0x20, 0x00 /* (to 0x00E8 state 70) */,
|
||||
0x6B /* 'k' */, 0x29, 0x00 /* (to 0x00F4 state 81) */,
|
||||
0x70 /* 'p' */, 0x38, 0x00 /* (to 0x0106 state 88) */,
|
||||
0x61 /* 'a' */, 0x3F, 0x00 /* (to 0x0110 state 97) */,
|
||||
0x6E /* 'n' */, 0x44, 0x00 /* (to 0x0118 state 104) */,
|
||||
0x76 /* 'v' */, 0x86, 0x01 /* (to 0x025D state 284) */,
|
||||
0x6F /* 'o' */, 0x8C, 0x01 /* (to 0x0266 state 292) */,
|
||||
0x08, /* fail */
|
||||
/* pos 00de: 62 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 00df: 63 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 00e0: 64 */ 0xE6 /* 'f' -> */,
|
||||
/* pos 00e1: 65 */ 0xF4 /* 't' -> */,
|
||||
/* pos 00e2: 66 */ 0xBA /* ':' -> */,
|
||||
/* pos 00e3: 67 */ 0x00, 0x07 /* - terminal marker 7 - */,
|
||||
/* pos 00e5: 68 */ 0x8A /* '.' -> */,
|
||||
/* pos 00e6: 69 */ 0x00, 0x08 /* - terminal marker 8 - */,
|
||||
/* pos 00e8: 70 */ 0xF8 /* 'x' -> */,
|
||||
/* pos 00e9: 71 */ 0xF4 /* 't' -> */,
|
||||
/* pos 00ea: 72 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 00eb: 73 */ 0xEE /* 'n' -> */,
|
||||
/* pos 00ec: 74 */ 0xF3 /* 's' -> */,
|
||||
/* pos 00ed: 75 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 00ee: 76 */ 0xEF /* 'o' -> */,
|
||||
/* pos 00ef: 77 */ 0xEE /* 'n' -> */,
|
||||
/* pos 00f0: 78 */ 0xF3 /* 's' -> */,
|
||||
/* pos 00f1: 79 */ 0xBA /* ':' -> */,
|
||||
/* pos 00f2: 80 */ 0x00, 0x09 /* - terminal marker 9 - */,
|
||||
/* pos 00f4: 81 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 00f5: 82 */ 0xF9 /* 'y' -> */,
|
||||
/* pos 00f6: 83 */ 0x31 /* '1' */, 0x0A, 0x00 /* (to 0x0100 state 84) */,
|
||||
0x32 /* '2' */, 0x0A, 0x00 /* (to 0x0103 state 86) */,
|
||||
0x3A /* ':' */, 0x5F, 0x01 /* (to 0x025B state 283) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0100: 84 */ 0xBA /* ':' -> */,
|
||||
/* pos 0101: 85 */ 0x00, 0x0A /* - terminal marker 10 - */,
|
||||
/* pos 0103: 86 */ 0xBA /* ':' -> */,
|
||||
/* pos 0104: 87 */ 0x00, 0x0B /* - terminal marker 11 - */,
|
||||
/* pos 0106: 88 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0107: 89 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0108: 90 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0109: 91 */ 0xEF /* 'o' -> */,
|
||||
/* pos 010a: 92 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 010b: 93 */ 0xEF /* 'o' -> */,
|
||||
/* pos 010c: 94 */ 0xEC /* 'l' -> */,
|
||||
/* pos 010d: 95 */ 0xBA /* ':' -> */,
|
||||
/* pos 010e: 96 */ 0x00, 0x0C /* - terminal marker 12 - */,
|
||||
/* pos 0110: 97 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0111: 98 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0112: 99 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0113: 100 */ 0xF0 /* 'p' -> */,
|
||||
/* pos 0114: 101 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0115: 102 */ 0xBA /* ':' -> */,
|
||||
/* pos 0116: 103 */ 0x00, 0x0D /* - terminal marker 13 - */,
|
||||
/* pos 0118: 104 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0119: 105 */ 0xEE /* 'n' -> */,
|
||||
/* pos 011a: 106 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 011b: 107 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 011c: 108 */ 0xBA /* ':' -> */,
|
||||
/* pos 011d: 109 */ 0x00, 0x0E /* - terminal marker 14 - */,
|
||||
/* pos 011f: 110 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0120: 111 */ 0xF0 /* 'p' -> */,
|
||||
/* pos 0121: 112 */ 0x2F /* '/' */, 0x07, 0x00 /* (to 0x0128 state 113) */,
|
||||
0x32 /* '2' */, 0x10, 0x00 /* (to 0x0134 state 118) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0128: 113 */ 0xB1 /* '1' -> */,
|
||||
/* pos 0129: 114 */ 0xAE /* '.' -> */,
|
||||
/* pos 012a: 115 */ 0x31 /* '1' */, 0x07, 0x00 /* (to 0x0131 state 116) */,
|
||||
0x30 /* '0' */, 0x0F, 0x03 /* (to 0x043C state 660) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0131: 116 */ 0xA0 /* ' ' -> */,
|
||||
/* pos 0132: 117 */ 0x00, 0x0F /* - terminal marker 15 - */,
|
||||
/* pos 0134: 118 */ 0xAD /* '-' -> */,
|
||||
/* pos 0135: 119 */ 0xF3 /* 's' -> */,
|
||||
/* pos 0136: 120 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0137: 121 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0138: 122 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0139: 123 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 013a: 124 */ 0xEE /* 'n' -> */,
|
||||
/* pos 013b: 125 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 013c: 126 */ 0xF3 /* 's' -> */,
|
||||
/* pos 013d: 127 */ 0xBA /* ':' -> */,
|
||||
/* pos 013e: 128 */ 0x00, 0x10 /* - terminal marker 16 - */,
|
||||
/* pos 0140: 129 */ 0x63 /* 'c' */, 0x0D, 0x00 /* (to 0x014D state 130) */,
|
||||
0x75 /* 'u' */, 0xAC, 0x00 /* (to 0x01EF state 230) */,
|
||||
0x67 /* 'g' */, 0x7D, 0x01 /* (to 0x02C3 state 358) */,
|
||||
0x6C /* 'l' */, 0x7E, 0x01 /* (to 0x02C7 state 361) */,
|
||||
0x08, /* fail */
|
||||
/* pos 014d: 130 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 014e: 131 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 014f: 132 */ 0x70 /* 'p' */, 0x07, 0x00 /* (to 0x0156 state 133) */,
|
||||
0x73 /* 's' */, 0x0E, 0x00 /* (to 0x0160 state 136) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0156: 133 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0157: 134 */ 0x3A /* ':' */, 0x07, 0x00 /* (to 0x015E state 135) */,
|
||||
0x2D /* '-' */, 0x59, 0x00 /* (to 0x01B3 state 192) */,
|
||||
0x08, /* fail */
|
||||
/* pos 015e: 135 */ 0x00, 0x11 /* - terminal marker 17 - */,
|
||||
/* pos 0160: 136 */ 0xF3 /* 's' -> */,
|
||||
/* pos 0161: 137 */ 0xAD /* '-' -> */,
|
||||
/* pos 0162: 138 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0163: 139 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0164: 140 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0165: 141 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0166: 142 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0167: 143 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0168: 144 */ 0xEC /* 'l' -> */,
|
||||
/* pos 0169: 145 */ 0xAD /* '-' -> */,
|
||||
/* pos 016a: 146 */ 0x72 /* 'r' */, 0x07, 0x00 /* (to 0x0171 state 147) */,
|
||||
0x61 /* 'a' */, 0x48, 0x01 /* (to 0x02B5 state 345) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0171: 147 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0172: 148 */ 0xF1 /* 'q' -> */,
|
||||
/* pos 0173: 149 */ 0xF5 /* 'u' -> */,
|
||||
/* pos 0174: 150 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0175: 151 */ 0xF3 /* 's' -> */,
|
||||
/* pos 0176: 152 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0177: 153 */ 0xAD /* '-' -> */,
|
||||
/* pos 0178: 154 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 0179: 155 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 017a: 156 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 017b: 157 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 017c: 158 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 017d: 159 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 017e: 160 */ 0xF3 /* 's' -> */,
|
||||
/* pos 017f: 161 */ 0xBA /* ':' -> */,
|
||||
/* pos 0180: 162 */ 0x00, 0x12 /* - terminal marker 18 - */,
|
||||
/* pos 0182: 163 */ 0xE6 /* 'f' -> */,
|
||||
/* pos 0183: 164 */ 0xAD /* '-' -> */,
|
||||
/* pos 0184: 165 */ 0x6D /* 'm' */, 0x0D, 0x00 /* (to 0x0191 state 166) */,
|
||||
0x6E /* 'n' */, 0x20, 0x00 /* (to 0x01A7 state 181) */,
|
||||
0x72 /* 'r' */, 0x9E, 0x01 /* (to 0x0328 state 435) */,
|
||||
0x75 /* 'u' */, 0xA2, 0x01 /* (to 0x032F state 441) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0191: 166 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x0198 state 167) */,
|
||||
0x61 /* 'a' */, 0x8E, 0x01 /* (to 0x0322 state 430) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0198: 167 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 0199: 168 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 019a: 169 */ 0xE6 /* 'f' -> */,
|
||||
/* pos 019b: 170 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 019c: 171 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 019d: 172 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 019e: 173 */ 0xAD /* '-' -> */,
|
||||
/* pos 019f: 174 */ 0xF3 /* 's' -> */,
|
||||
/* pos 01a0: 175 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 01a1: 176 */ 0xEE /* 'n' -> */,
|
||||
/* pos 01a2: 177 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 01a3: 178 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 01a4: 179 */ 0xBA /* ':' -> */,
|
||||
/* pos 01a5: 180 */ 0x00, 0x13 /* - terminal marker 19 - */,
|
||||
/* pos 01a7: 181 */ 0xEF /* 'o' -> */,
|
||||
/* pos 01a8: 182 */ 0xEE /* 'n' -> */,
|
||||
/* pos 01a9: 183 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 01aa: 184 */ 0xAD /* '-' -> */,
|
||||
/* pos 01ab: 185 */ 0xED /* 'm' -> */,
|
||||
/* pos 01ac: 186 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 01ad: 187 */ 0xF4 /* 't' -> */,
|
||||
/* pos 01ae: 188 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 01af: 189 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 01b0: 190 */ 0xBA /* ':' -> */,
|
||||
/* pos 01b1: 191 */ 0x00, 0x14 /* - terminal marker 20 - */,
|
||||
/* pos 01b3: 192 */ 0x65 /* 'e' */, 0x0D, 0x00 /* (to 0x01C0 state 193) */,
|
||||
0x6C /* 'l' */, 0x14, 0x00 /* (to 0x01CA state 202) */,
|
||||
0x63 /* 'c' */, 0xEB, 0x00 /* (to 0x02A4 state 330) */,
|
||||
0x72 /* 'r' */, 0xF1, 0x00 /* (to 0x02AD state 338) */,
|
||||
0x08, /* fail */
|
||||
/* pos 01c0: 193 */ 0xEE /* 'n' -> */,
|
||||
/* pos 01c1: 194 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 01c2: 195 */ 0xEF /* 'o' -> */,
|
||||
/* pos 01c3: 196 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 01c4: 197 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 01c5: 198 */ 0xEE /* 'n' -> */,
|
||||
/* pos 01c6: 199 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 01c7: 200 */ 0xBA /* ':' -> */,
|
||||
/* pos 01c8: 201 */ 0x00, 0x15 /* - terminal marker 21 - */,
|
||||
/* pos 01ca: 202 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 01cb: 203 */ 0xEE /* 'n' -> */,
|
||||
/* pos 01cc: 204 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 01cd: 205 */ 0xF5 /* 'u' -> */,
|
||||
/* pos 01ce: 206 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 01cf: 207 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 01d0: 208 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 01d1: 209 */ 0xBA /* ':' -> */,
|
||||
/* pos 01d2: 210 */ 0x00, 0x16 /* - terminal marker 22 - */,
|
||||
/* pos 01d4: 211 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x01DB state 212) */,
|
||||
0x6F /* 'o' */, 0x9E, 0x01 /* (to 0x0375 state 497) */,
|
||||
0x08, /* fail */
|
||||
/* pos 01db: 212 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 01dc: 213 */ 0xED /* 'm' -> */,
|
||||
/* pos 01dd: 214 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 01de: 215 */ 0xBA /* ':' -> */,
|
||||
/* pos 01df: 216 */ 0x00, 0x17 /* - terminal marker 23 - */,
|
||||
/* pos 01e1: 217 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 01e2: 218 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 01e3: 219 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 01e4: 220 */ 0xAD /* '-' -> */,
|
||||
/* pos 01e5: 221 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 01e6: 222 */ 0xEF /* 'o' -> */,
|
||||
/* pos 01e7: 223 */ 0xEE /* 'n' -> */,
|
||||
/* pos 01e8: 224 */ 0xF4 /* 't' -> */,
|
||||
/* pos 01e9: 225 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 01ea: 226 */ 0xEF /* 'o' -> */,
|
||||
/* pos 01eb: 227 */ 0xEC /* 'l' -> */,
|
||||
/* pos 01ec: 228 */ 0xBA /* ':' -> */,
|
||||
/* pos 01ed: 229 */ 0x00, 0x18 /* - terminal marker 24 - */,
|
||||
/* pos 01ef: 230 */ 0xF4 /* 't' -> */,
|
||||
/* pos 01f0: 231 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 01f1: 232 */ 0xEF /* 'o' -> */,
|
||||
/* pos 01f2: 233 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 01f3: 234 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 01f4: 235 */ 0xFA /* 'z' -> */,
|
||||
/* pos 01f5: 236 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 01f6: 237 */ 0xF4 /* 't' -> */,
|
||||
/* pos 01f7: 238 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 01f8: 239 */ 0xEF /* 'o' -> */,
|
||||
/* pos 01f9: 240 */ 0xEE /* 'n' -> */,
|
||||
/* pos 01fa: 241 */ 0xBA /* ':' -> */,
|
||||
/* pos 01fb: 242 */ 0x00, 0x19 /* - terminal marker 25 - */,
|
||||
/* pos 01fd: 243 */ 0xEB /* 'k' -> */,
|
||||
/* pos 01fe: 244 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 01ff: 245 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0200: 246 */ 0xBA /* ':' -> */,
|
||||
/* pos 0201: 247 */ 0x00, 0x1A /* - terminal marker 26 - */,
|
||||
/* pos 0203: 248 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0204: 249 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0205: 250 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0206: 251 */ 0xAD /* '-' -> */,
|
||||
/* pos 0207: 252 */ 0x6C /* 'l' */, 0x10, 0x00 /* (to 0x0217 state 253) */,
|
||||
0x74 /* 't' */, 0x1E, 0x00 /* (to 0x0228 state 260) */,
|
||||
0x64 /* 'd' */, 0xC0, 0x00 /* (to 0x02CD state 366) */,
|
||||
0x65 /* 'e' */, 0xCA, 0x00 /* (to 0x02DA state 378) */,
|
||||
0x72 /* 'r' */, 0xE3, 0x00 /* (to 0x02F6 state 403) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0217: 253 */ 0x65 /* 'e' */, 0x0A, 0x00 /* (to 0x0221 state 254) */,
|
||||
0x61 /* 'a' */, 0xCA, 0x00 /* (to 0x02E4 state 387) */,
|
||||
0x6F /* 'o' */, 0xD0, 0x00 /* (to 0x02ED state 395) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0221: 254 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0222: 255 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 0223: 256 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0224: 257 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 0225: 258 */ 0xBA /* ':' -> */,
|
||||
/* pos 0226: 259 */ 0x00, 0x1B /* - terminal marker 27 - */,
|
||||
/* pos 0228: 260 */ 0xF9 /* 'y' -> */,
|
||||
/* pos 0229: 261 */ 0xF0 /* 'p' -> */,
|
||||
/* pos 022a: 262 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 022b: 263 */ 0xBA /* ':' -> */,
|
||||
/* pos 022c: 264 */ 0x00, 0x1C /* - terminal marker 28 - */,
|
||||
/* pos 022e: 265 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x0235 state 266) */,
|
||||
0x65 /* 'e' */, 0xF0, 0x01 /* (to 0x0421 state 637) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0235: 266 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0236: 267 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0237: 268 */ 0xBA /* ':' -> */,
|
||||
/* pos 0238: 269 */ 0x00, 0x1D /* - terminal marker 29 - */,
|
||||
/* pos 023a: 270 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x0241 state 271) */,
|
||||
0x65 /* 'e' */, 0x0A, 0x00 /* (to 0x0247 state 276) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0241: 271 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0242: 272 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 0243: 273 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0244: 274 */ 0xBA /* ':' -> */,
|
||||
/* pos 0245: 275 */ 0x00, 0x1E /* - terminal marker 30 - */,
|
||||
/* pos 0247: 276 */ 0x66 /* 'f' */, 0x07, 0x00 /* (to 0x024E state 277) */,
|
||||
0x74 /* 't' */, 0x5A, 0x01 /* (to 0x03A4 state 529) */,
|
||||
0x08, /* fail */
|
||||
/* pos 024e: 277 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x0255 state 278) */,
|
||||
0x72 /* 'r' */, 0x4D, 0x01 /* (to 0x039E state 524) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0255: 278 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0256: 279 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0257: 280 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0258: 281 */ 0xBA /* ':' -> */,
|
||||
/* pos 0259: 282 */ 0x00, 0x1F /* - terminal marker 31 - */,
|
||||
/* pos 025b: 283 */ 0x00, 0x20 /* - terminal marker 32 - */,
|
||||
/* pos 025d: 284 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 025e: 285 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 025f: 286 */ 0xF3 /* 's' -> */,
|
||||
/* pos 0260: 287 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0261: 288 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0262: 289 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0263: 290 */ 0xBA /* ':' -> */,
|
||||
/* pos 0264: 291 */ 0x00, 0x21 /* - terminal marker 33 - */,
|
||||
/* pos 0266: 292 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0267: 293 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0268: 294 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 0269: 295 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 026a: 296 */ 0xEE /* 'n' -> */,
|
||||
/* pos 026b: 297 */ 0xBA /* ':' -> */,
|
||||
/* pos 026c: 298 */ 0x00, 0x22 /* - terminal marker 34 - */,
|
||||
/* pos 026e: 299 */ 0x61 /* 'a' */, 0x0D, 0x00 /* (to 0x027B state 300) */,
|
||||
0x6D /* 'm' */, 0x14, 0x00 /* (to 0x0285 state 309) */,
|
||||
0x70 /* 'p' */, 0x18, 0x00 /* (to 0x028C state 315) */,
|
||||
0x73 /* 's' */, 0x1A, 0x00 /* (to 0x0291 state 319) */,
|
||||
0x08, /* fail */
|
||||
/* pos 027b: 300 */ 0xF5 /* 'u' -> */,
|
||||
/* pos 027c: 301 */ 0xF4 /* 't' -> */,
|
||||
/* pos 027d: 302 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 027e: 303 */ 0xEF /* 'o' -> */,
|
||||
/* pos 027f: 304 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0280: 305 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0281: 306 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0282: 307 */ 0xF9 /* 'y' -> */,
|
||||
/* pos 0283: 308 */ 0x00, 0x23 /* - terminal marker 35 - */,
|
||||
/* pos 0285: 309 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0286: 310 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0287: 311 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 0288: 312 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0289: 313 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 028a: 314 */ 0x00, 0x24 /* - terminal marker 36 - */,
|
||||
/* pos 028c: 315 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 028d: 316 */ 0xF4 /* 't' -> */,
|
||||
/* pos 028e: 317 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 028f: 318 */ 0x00, 0x25 /* - terminal marker 37 - */,
|
||||
/* pos 0291: 319 */ 0x63 /* 'c' */, 0x07, 0x00 /* (to 0x0298 state 320) */,
|
||||
0x74 /* 't' */, 0x0A, 0x00 /* (to 0x029E state 325) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0298: 320 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 0299: 321 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 029a: 322 */ 0xED /* 'm' -> */,
|
||||
/* pos 029b: 323 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 029c: 324 */ 0x00, 0x26 /* - terminal marker 38 - */,
|
||||
/* pos 029e: 325 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 029f: 326 */ 0xF4 /* 't' -> */,
|
||||
/* pos 02a0: 327 */ 0xF5 /* 'u' -> */,
|
||||
/* pos 02a1: 328 */ 0xF3 /* 's' -> */,
|
||||
/* pos 02a2: 329 */ 0x00, 0x27 /* - terminal marker 39 - */,
|
||||
/* pos 02a4: 330 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 02a5: 331 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 02a6: 332 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 02a7: 333 */ 0xF3 /* 's' -> */,
|
||||
/* pos 02a8: 334 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 02a9: 335 */ 0xF4 /* 't' -> */,
|
||||
/* pos 02aa: 336 */ 0xBA /* ':' -> */,
|
||||
/* pos 02ab: 337 */ 0x00, 0x28 /* - terminal marker 40 - */,
|
||||
/* pos 02ad: 338 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 02ae: 339 */ 0xEE /* 'n' -> */,
|
||||
/* pos 02af: 340 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 02b0: 341 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 02b1: 342 */ 0xF3 /* 's' -> */,
|
||||
/* pos 02b2: 343 */ 0xBA /* ':' -> */,
|
||||
/* pos 02b3: 344 */ 0x00, 0x29 /* - terminal marker 41 - */,
|
||||
/* pos 02b5: 345 */ 0xEC /* 'l' -> */,
|
||||
/* pos 02b6: 346 */ 0xEC /* 'l' -> */,
|
||||
/* pos 02b7: 347 */ 0xEF /* 'o' -> */,
|
||||
/* pos 02b8: 348 */ 0xF7 /* 'w' -> */,
|
||||
/* pos 02b9: 349 */ 0xAD /* '-' -> */,
|
||||
/* pos 02ba: 350 */ 0xEF /* 'o' -> */,
|
||||
/* pos 02bb: 351 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 02bc: 352 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 02bd: 353 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 02be: 354 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 02bf: 355 */ 0xEE /* 'n' -> */,
|
||||
/* pos 02c0: 356 */ 0xBA /* ':' -> */,
|
||||
/* pos 02c1: 357 */ 0x00, 0x2A /* - terminal marker 42 - */,
|
||||
/* pos 02c3: 358 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 02c4: 359 */ 0xBA /* ':' -> */,
|
||||
/* pos 02c5: 360 */ 0x00, 0x2B /* - terminal marker 43 - */,
|
||||
/* pos 02c7: 361 */ 0xEC /* 'l' -> */,
|
||||
/* pos 02c8: 362 */ 0xEF /* 'o' -> */,
|
||||
/* pos 02c9: 363 */ 0xF7 /* 'w' -> */,
|
||||
/* pos 02ca: 364 */ 0xBA /* ':' -> */,
|
||||
/* pos 02cb: 365 */ 0x00, 0x2C /* - terminal marker 44 - */,
|
||||
/* pos 02cd: 366 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 02ce: 367 */ 0xF3 /* 's' -> */,
|
||||
/* pos 02cf: 368 */ 0xF0 /* 'p' -> */,
|
||||
/* pos 02d0: 369 */ 0xEF /* 'o' -> */,
|
||||
/* pos 02d1: 370 */ 0xF3 /* 's' -> */,
|
||||
/* pos 02d2: 371 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 02d3: 372 */ 0xF4 /* 't' -> */,
|
||||
/* pos 02d4: 373 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 02d5: 374 */ 0xEF /* 'o' -> */,
|
||||
/* pos 02d6: 375 */ 0xEE /* 'n' -> */,
|
||||
/* pos 02d7: 376 */ 0xBA /* ':' -> */,
|
||||
/* pos 02d8: 377 */ 0x00, 0x2D /* - terminal marker 45 - */,
|
||||
/* pos 02da: 378 */ 0xEE /* 'n' -> */,
|
||||
/* pos 02db: 379 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 02dc: 380 */ 0xEF /* 'o' -> */,
|
||||
/* pos 02dd: 381 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 02de: 382 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 02df: 383 */ 0xEE /* 'n' -> */,
|
||||
/* pos 02e0: 384 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 02e1: 385 */ 0xBA /* ':' -> */,
|
||||
/* pos 02e2: 386 */ 0x00, 0x2E /* - terminal marker 46 - */,
|
||||
/* pos 02e4: 387 */ 0xEE /* 'n' -> */,
|
||||
/* pos 02e5: 388 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 02e6: 389 */ 0xF5 /* 'u' -> */,
|
||||
/* pos 02e7: 390 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 02e8: 391 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 02e9: 392 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 02ea: 393 */ 0xBA /* ':' -> */,
|
||||
/* pos 02eb: 394 */ 0x00, 0x2F /* - terminal marker 47 - */,
|
||||
/* pos 02ed: 395 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 02ee: 396 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 02ef: 397 */ 0xF4 /* 't' -> */,
|
||||
/* pos 02f0: 398 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 02f1: 399 */ 0xEF /* 'o' -> */,
|
||||
/* pos 02f2: 400 */ 0xEE /* 'n' -> */,
|
||||
/* pos 02f3: 401 */ 0xBA /* ':' -> */,
|
||||
/* pos 02f4: 402 */ 0x00, 0x30 /* - terminal marker 48 - */,
|
||||
/* pos 02f6: 403 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 02f7: 404 */ 0xEE /* 'n' -> */,
|
||||
/* pos 02f8: 405 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 02f9: 406 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 02fa: 407 */ 0xBA /* ':' -> */,
|
||||
/* pos 02fb: 408 */ 0x00, 0x31 /* - terminal marker 49 - */,
|
||||
/* pos 02fd: 409 */ 0x74 /* 't' */, 0x07, 0x00 /* (to 0x0304 state 410) */,
|
||||
0x78 /* 'x' */, 0x09, 0x00 /* (to 0x0309 state 414) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0304: 410 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0305: 411 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 0306: 412 */ 0xBA /* ':' -> */,
|
||||
/* pos 0307: 413 */ 0x00, 0x32 /* - terminal marker 50 - */,
|
||||
/* pos 0309: 414 */ 0xF0 /* 'p' -> */,
|
||||
/* pos 030a: 415 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x0311 state 416) */,
|
||||
0x69 /* 'i' */, 0x09, 0x00 /* (to 0x0316 state 420) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0311: 416 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0312: 417 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0313: 418 */ 0xBA /* ':' -> */,
|
||||
/* pos 0314: 419 */ 0x00, 0x33 /* - terminal marker 51 - */,
|
||||
/* pos 0316: 420 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0317: 421 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0318: 422 */ 0xF3 /* 's' -> */,
|
||||
/* pos 0319: 423 */ 0xBA /* ':' -> */,
|
||||
/* pos 031a: 424 */ 0x00, 0x34 /* - terminal marker 52 - */,
|
||||
/* pos 031c: 425 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 031d: 426 */ 0xEF /* 'o' -> */,
|
||||
/* pos 031e: 427 */ 0xED /* 'm' -> */,
|
||||
/* pos 031f: 428 */ 0xBA /* ':' -> */,
|
||||
/* pos 0320: 429 */ 0x00, 0x35 /* - terminal marker 53 - */,
|
||||
/* pos 0322: 430 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0323: 431 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0324: 432 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 0325: 433 */ 0xBA /* ':' -> */,
|
||||
/* pos 0326: 434 */ 0x00, 0x36 /* - terminal marker 54 - */,
|
||||
/* pos 0328: 435 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0329: 436 */ 0xEE /* 'n' -> */,
|
||||
/* pos 032a: 437 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 032b: 438 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 032c: 439 */ 0xBA /* ':' -> */,
|
||||
/* pos 032d: 440 */ 0x00, 0x37 /* - terminal marker 55 - */,
|
||||
/* pos 032f: 441 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0330: 442 */ 0xED /* 'm' -> */,
|
||||
/* pos 0331: 443 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0332: 444 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 0333: 445 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0334: 446 */ 0xE6 /* 'f' -> */,
|
||||
/* pos 0335: 447 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0336: 448 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0337: 449 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 0338: 450 */ 0xAD /* '-' -> */,
|
||||
/* pos 0339: 451 */ 0xF3 /* 's' -> */,
|
||||
/* pos 033a: 452 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 033b: 453 */ 0xEE /* 'n' -> */,
|
||||
/* pos 033c: 454 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 033d: 455 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 033e: 456 */ 0xBA /* ':' -> */,
|
||||
/* pos 033f: 457 */ 0x00, 0x38 /* - terminal marker 56 - */,
|
||||
/* pos 0341: 458 */ 0x61 /* 'a' */, 0x0A, 0x00 /* (to 0x034B state 459) */,
|
||||
0x69 /* 'i' */, 0x15, 0x00 /* (to 0x0359 state 472) */,
|
||||
0x6F /* 'o' */, 0x17, 0x00 /* (to 0x035E state 476) */,
|
||||
0x08, /* fail */
|
||||
/* pos 034b: 459 */ 0xF3 /* 's' -> */,
|
||||
/* pos 034c: 460 */ 0xF4 /* 't' -> */,
|
||||
/* pos 034d: 461 */ 0xAD /* '-' -> */,
|
||||
/* pos 034e: 462 */ 0xED /* 'm' -> */,
|
||||
/* pos 034f: 463 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0350: 464 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 0351: 465 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0352: 466 */ 0xE6 /* 'f' -> */,
|
||||
/* pos 0353: 467 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0354: 468 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0355: 469 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 0356: 470 */ 0xBA /* ':' -> */,
|
||||
/* pos 0357: 471 */ 0x00, 0x39 /* - terminal marker 57 - */,
|
||||
/* pos 0359: 472 */ 0xEE /* 'n' -> */,
|
||||
/* pos 035a: 473 */ 0xEB /* 'k' -> */,
|
||||
/* pos 035b: 474 */ 0xBA /* ':' -> */,
|
||||
/* pos 035c: 475 */ 0x00, 0x3A /* - terminal marker 58 - */,
|
||||
/* pos 035e: 476 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 035f: 477 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0360: 478 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0361: 479 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0362: 480 */ 0xEF /* 'o' -> */,
|
||||
/* pos 0363: 481 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0364: 482 */ 0xBA /* ':' -> */,
|
||||
/* pos 0365: 483 */ 0x00, 0x3B /* - terminal marker 59 - */,
|
||||
/* pos 0367: 484 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0368: 485 */ 0xF8 /* 'x' -> */,
|
||||
/* pos 0369: 486 */ 0xAD /* '-' -> */,
|
||||
/* pos 036a: 487 */ 0xE6 /* 'f' -> */,
|
||||
/* pos 036b: 488 */ 0xEF /* 'o' -> */,
|
||||
/* pos 036c: 489 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 036d: 490 */ 0xF7 /* 'w' -> */,
|
||||
/* pos 036e: 491 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 036f: 492 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0370: 493 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 0371: 494 */ 0xF3 /* 's' -> */,
|
||||
/* pos 0372: 495 */ 0xBA /* ':' -> */,
|
||||
/* pos 0373: 496 */ 0x00, 0x3C /* - terminal marker 60 - */,
|
||||
/* pos 0375: 497 */ 0xF8 /* 'x' -> */,
|
||||
/* pos 0376: 498 */ 0xF9 /* 'y' -> */,
|
||||
/* pos 0377: 499 */ 0x2D /* '-' */, 0x07, 0x00 /* (to 0x037E state 500) */,
|
||||
0x20 /* ' ' */, 0xB5, 0x00 /* (to 0x042F state 649) */,
|
||||
0x08, /* fail */
|
||||
/* pos 037e: 500 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 037f: 501 */ 0xF5 /* 'u' -> */,
|
||||
/* pos 0380: 502 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0381: 503 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 0382: 504 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x0389 state 505) */,
|
||||
0x6F /* 'o' */, 0x0E, 0x00 /* (to 0x0393 state 514) */,
|
||||
0x08, /* fail */
|
||||
/* pos 0389: 505 */ 0xEE /* 'n' -> */,
|
||||
/* pos 038a: 506 */ 0xF4 /* 't' -> */,
|
||||
/* pos 038b: 507 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 038c: 508 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 038d: 509 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 038e: 510 */ 0xF4 /* 't' -> */,
|
||||
/* pos 038f: 511 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0390: 512 */ 0xBA /* ':' -> */,
|
||||
/* pos 0391: 513 */ 0x00, 0x3D /* - terminal marker 61 - */,
|
||||
/* pos 0393: 514 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0394: 515 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0395: 516 */ 0xFA /* 'z' -> */,
|
||||
/* pos 0396: 517 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0397: 518 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0398: 519 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0399: 520 */ 0xEF /* 'o' -> */,
|
||||
/* pos 039a: 521 */ 0xEE /* 'n' -> */,
|
||||
/* pos 039b: 522 */ 0xBA /* ':' -> */,
|
||||
/* pos 039c: 523 */ 0x00, 0x3E /* - terminal marker 62 - */,
|
||||
/* pos 039e: 524 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 039f: 525 */ 0xF3 /* 's' -> */,
|
||||
/* pos 03a0: 526 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 03a1: 527 */ 0xBA /* ':' -> */,
|
||||
/* pos 03a2: 528 */ 0x00, 0x3F /* - terminal marker 63 - */,
|
||||
/* pos 03a4: 529 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 03a5: 530 */ 0xF9 /* 'y' -> */,
|
||||
/* pos 03a6: 531 */ 0xAD /* '-' -> */,
|
||||
/* pos 03a7: 532 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 03a8: 533 */ 0xE6 /* 'f' -> */,
|
||||
/* pos 03a9: 534 */ 0xF4 /* 't' -> */,
|
||||
/* pos 03aa: 535 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 03ab: 536 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 03ac: 537 */ 0xBA /* ':' -> */,
|
||||
/* pos 03ad: 538 */ 0x00, 0x40 /* - terminal marker 64 - */,
|
||||
/* pos 03af: 539 */ 0xF6 /* 'v' -> */,
|
||||
/* pos 03b0: 540 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 03b1: 541 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 03b2: 542 */ 0xBA /* ':' -> */,
|
||||
/* pos 03b3: 543 */ 0x00, 0x41 /* - terminal marker 65 - */,
|
||||
/* pos 03b5: 544 */ 0xAD /* '-' -> */,
|
||||
/* pos 03b6: 545 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 03b7: 546 */ 0xEF /* 'o' -> */,
|
||||
/* pos 03b8: 547 */ 0xEF /* 'o' -> */,
|
||||
/* pos 03b9: 548 */ 0xEB /* 'k' -> */,
|
||||
/* pos 03ba: 549 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 03bb: 550 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 03bc: 551 */ 0xBA /* ':' -> */,
|
||||
/* pos 03bd: 552 */ 0x00, 0x42 /* - terminal marker 66 - */,
|
||||
/* pos 03bf: 553 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 03c0: 554 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 03c1: 555 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 03c2: 556 */ 0xF4 /* 't' -> */,
|
||||
/* pos 03c3: 557 */ 0xAD /* '-' -> */,
|
||||
/* pos 03c4: 558 */ 0xF4 /* 't' -> */,
|
||||
/* pos 03c5: 559 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 03c6: 560 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 03c7: 561 */ 0xEE /* 'n' -> */,
|
||||
/* pos 03c8: 562 */ 0xF3 /* 's' -> */,
|
||||
/* pos 03c9: 563 */ 0xF0 /* 'p' -> */,
|
||||
/* pos 03ca: 564 */ 0xEF /* 'o' -> */,
|
||||
/* pos 03cb: 565 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 03cc: 566 */ 0xF4 /* 't' -> */,
|
||||
/* pos 03cd: 567 */ 0xAD /* '-' -> */,
|
||||
/* pos 03ce: 568 */ 0xF3 /* 's' -> */,
|
||||
/* pos 03cf: 569 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 03d0: 570 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 03d1: 571 */ 0xF5 /* 'u' -> */,
|
||||
/* pos 03d2: 572 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 03d3: 573 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 03d4: 574 */ 0xF4 /* 't' -> */,
|
||||
/* pos 03d5: 575 */ 0xF9 /* 'y' -> */,
|
||||
/* pos 03d6: 576 */ 0xBA /* ':' -> */,
|
||||
/* pos 03d7: 577 */ 0x00, 0x43 /* - terminal marker 67 - */,
|
||||
/* pos 03d9: 578 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 03da: 579 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 03db: 580 */ 0xEE /* 'n' -> */,
|
||||
/* pos 03dc: 581 */ 0xF3 /* 's' -> */,
|
||||
/* pos 03dd: 582 */ 0xE6 /* 'f' -> */,
|
||||
/* pos 03de: 583 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 03df: 584 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 03e0: 585 */ 0xAD /* '-' -> */,
|
||||
/* pos 03e1: 586 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 03e2: 587 */ 0xEE /* 'n' -> */,
|
||||
/* pos 03e3: 588 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 03e4: 589 */ 0xEF /* 'o' -> */,
|
||||
/* pos 03e5: 590 */ 0xE4 /* 'd' -> */,
|
||||
/* pos 03e6: 591 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 03e7: 592 */ 0xEE /* 'n' -> */,
|
||||
/* pos 03e8: 593 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 03e9: 594 */ 0xBA /* ':' -> */,
|
||||
/* pos 03ea: 595 */ 0x00, 0x44 /* - terminal marker 68 - */,
|
||||
/* pos 03ec: 596 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 03ed: 597 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 03ee: 598 */ 0xAD /* '-' -> */,
|
||||
/* pos 03ef: 599 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 03f0: 600 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 03f1: 601 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 03f2: 602 */ 0xEE /* 'n' -> */,
|
||||
/* pos 03f3: 603 */ 0xF4 /* 't' -> */,
|
||||
/* pos 03f4: 604 */ 0xBA /* ':' -> */,
|
||||
/* pos 03f5: 605 */ 0x00, 0x45 /* - terminal marker 69 - */,
|
||||
/* pos 03f7: 606 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x03FE state 607) */,
|
||||
0x69 /* 'i' */, 0x09, 0x00 /* (to 0x0403 state 611) */,
|
||||
0x08, /* fail */
|
||||
/* pos 03fe: 607 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 03ff: 608 */ 0xF9 /* 'y' -> */,
|
||||
/* pos 0400: 609 */ 0xBA /* ':' -> */,
|
||||
/* pos 0401: 610 */ 0x00, 0x46 /* - terminal marker 70 - */,
|
||||
/* pos 0403: 611 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0404: 612 */ 0xBA /* ':' -> */,
|
||||
/* pos 0405: 613 */ 0x00, 0x47 /* - terminal marker 71 - */,
|
||||
/* pos 0407: 614 */ 0xF7 /* 'w' -> */,
|
||||
/* pos 0408: 615 */ 0xF7 /* 'w' -> */,
|
||||
/* pos 0409: 616 */ 0xAD /* '-' -> */,
|
||||
/* pos 040a: 617 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 040b: 618 */ 0xF5 /* 'u' -> */,
|
||||
/* pos 040c: 619 */ 0xF4 /* 't' -> */,
|
||||
/* pos 040d: 620 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 040e: 621 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 040f: 622 */ 0xEE /* 'n' -> */,
|
||||
/* pos 0410: 623 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0411: 624 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0412: 625 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 0413: 626 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0414: 627 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0415: 628 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0416: 629 */ 0xBA /* ':' -> */,
|
||||
/* pos 0417: 630 */ 0x00, 0x48 /* - terminal marker 72 - */,
|
||||
/* pos 0419: 631 */ 0xF4 /* 't' -> */,
|
||||
/* pos 041a: 632 */ 0xE3 /* 'c' -> */,
|
||||
/* pos 041b: 633 */ 0xE8 /* 'h' -> */,
|
||||
/* pos 041c: 634 */ 0x00, 0x49 /* - terminal marker 73 - */,
|
||||
/* pos 041e: 635 */ 0xF4 /* 't' -> */,
|
||||
/* pos 041f: 636 */ 0x00, 0x4A /* - terminal marker 74 - */,
|
||||
/* pos 0421: 637 */ 0xEC /* 'l' -> */,
|
||||
/* pos 0422: 638 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0423: 639 */ 0xF4 /* 't' -> */,
|
||||
/* pos 0424: 640 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0425: 641 */ 0x00, 0x4B /* - terminal marker 75 - */,
|
||||
/* pos 0427: 642 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0428: 643 */ 0xAD /* '-' -> */,
|
||||
/* pos 0429: 644 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 042a: 645 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 042b: 646 */ 0xE7 /* 'g' -> */,
|
||||
/* pos 042c: 647 */ 0xF3 /* 's' -> */,
|
||||
/* pos 042d: 648 */ 0x00, 0x4C /* - terminal marker 76 - */,
|
||||
/* pos 042f: 649 */ 0x00, 0x4D /* - terminal marker 77 - */,
|
||||
/* pos 0431: 650 */ 0xAD /* '-' -> */,
|
||||
/* pos 0432: 651 */ 0xF2 /* 'r' -> */,
|
||||
/* pos 0433: 652 */ 0xE5 /* 'e' -> */,
|
||||
/* pos 0434: 653 */ 0xE1 /* 'a' -> */,
|
||||
/* pos 0435: 654 */ 0xEC /* 'l' -> */,
|
||||
/* pos 0436: 655 */ 0xAD /* '-' -> */,
|
||||
/* pos 0437: 656 */ 0xE9 /* 'i' -> */,
|
||||
/* pos 0438: 657 */ 0xF0 /* 'p' -> */,
|
||||
/* pos 0439: 658 */ 0xBA /* ':' -> */,
|
||||
/* pos 043a: 659 */ 0x00, 0x4E /* - terminal marker 78 - */,
|
||||
/* pos 043c: 660 */ 0xA0 /* ' ' -> */,
|
||||
/* pos 043d: 661 */ 0x00, 0x4F /* - terminal marker 79 - */,
|
||||
/* total size 1087 bytes */
|
||||
470
feeds/wlan-ap/libwebsocket/src/include/websocket/libwcf.h
Executable file
470
feeds/wlan-ap/libwebsocket/src/include/websocket/libwcf.h
Executable file
@@ -0,0 +1,470 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#ifndef _LIBBRIDGE_H
|
||||
#define _LIBBRIDGE_H
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/time.h>
|
||||
//#include <linux/if_bridge.h>
|
||||
|
||||
/* defined in net/if.h but that conflicts with linux/if.h... */
|
||||
extern unsigned int if_nametoindex (const char *__ifname);
|
||||
extern char *if_indextoname (unsigned int __ifindex, char *__ifname);
|
||||
|
||||
|
||||
#define APC_MAX_NEIGHBORS 100
|
||||
|
||||
struct bridge_id
|
||||
{
|
||||
unsigned char prio[2];
|
||||
unsigned char addr[6];
|
||||
};
|
||||
|
||||
struct fdb_entry
|
||||
{
|
||||
unsigned int mac_addr[6];
|
||||
unsigned int port_no;
|
||||
unsigned char is_local;
|
||||
struct timeval ageing_timer_value;
|
||||
};
|
||||
|
||||
struct port_info
|
||||
{
|
||||
unsigned port_no;
|
||||
struct bridge_id designated_root;
|
||||
struct bridge_id designated_bridge;
|
||||
unsigned int port_id;
|
||||
unsigned int designated_port;
|
||||
unsigned int priority;
|
||||
unsigned char top_change_ack;
|
||||
unsigned char config_pending;
|
||||
unsigned char state;
|
||||
unsigned path_cost;
|
||||
unsigned designated_cost;
|
||||
struct timeval message_age_timer_value;
|
||||
struct timeval forward_delay_timer_value;
|
||||
struct timeval hold_timer_value;
|
||||
};
|
||||
|
||||
struct sip_call_start
|
||||
{
|
||||
unsigned long long SessionId;
|
||||
unsigned char CltMac[6];
|
||||
int WifiIf; /* To get WiFi session ID */
|
||||
char Url[50];
|
||||
char Codecs[15][30];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct sip_call_end
|
||||
{
|
||||
unsigned long long SessionId;
|
||||
unsigned char CltMac[6];
|
||||
int WifiIf; /* To get WiFi session ID */
|
||||
unsigned int CltMos;
|
||||
unsigned int Reason;
|
||||
unsigned char Codecs[4];
|
||||
unsigned int Latency;
|
||||
unsigned int Jitter;
|
||||
unsigned int PktLostPerc;
|
||||
unsigned int PktLostCons;
|
||||
unsigned int VideoCodec;
|
||||
unsigned int TotalPktSent;
|
||||
unsigned int TotalPktLost;
|
||||
unsigned int RtpSeqFirst;
|
||||
unsigned int RtpSeqLast;
|
||||
unsigned int SipReportIdx;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct sip_call_report
|
||||
{
|
||||
unsigned int Latency;
|
||||
unsigned int Jitter;
|
||||
unsigned int PacketLoss;
|
||||
unsigned int Mos;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct streaming_video_start
|
||||
{
|
||||
unsigned long long SessionId;
|
||||
unsigned char CltMac[6];
|
||||
int WifiIf; /* To get WiFi session ID */
|
||||
unsigned int ServerIp;
|
||||
unsigned int Type;
|
||||
char ServerDnsName[100];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct streaming_video_stop
|
||||
{
|
||||
unsigned long long SessionId;
|
||||
unsigned char CltMac[6];
|
||||
int WifiIf; /* To get WiFi session ID */
|
||||
unsigned long long TotalBytes;
|
||||
unsigned int Duration;
|
||||
unsigned int Type;
|
||||
unsigned int ServerIp;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct http_user_agent
|
||||
{
|
||||
unsigned char macAddress[6];
|
||||
char userAgent[200];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct add_tun_parms
|
||||
{
|
||||
unsigned int MyIp;
|
||||
unsigned int PeerIp;
|
||||
unsigned int Primary;
|
||||
unsigned char MyMac[6];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct del_tun_parms
|
||||
{
|
||||
unsigned int PeerIp;
|
||||
unsigned char PeerMac[6];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct wc_log_line
|
||||
{
|
||||
unsigned int Num;
|
||||
unsigned int Level;
|
||||
unsigned int TimeStamp;
|
||||
unsigned char Message[200];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct fr_record
|
||||
{
|
||||
unsigned int Round;
|
||||
unsigned int Timestamp;
|
||||
char Message[504];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct wc_tunnel_stats
|
||||
{
|
||||
unsigned int Ip;
|
||||
unsigned int ConfTime;
|
||||
unsigned int UpTime;
|
||||
unsigned int Active;
|
||||
unsigned int PingsSent;
|
||||
unsigned int PingsReceived;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct radius_report_stats
|
||||
{
|
||||
unsigned int Entry;
|
||||
unsigned int ServerIp;
|
||||
unsigned int NoAnswers;
|
||||
/* All times are in milliseconds */
|
||||
unsigned int TimeMin;
|
||||
unsigned int TimeMax;
|
||||
unsigned int TimeAve;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct local_mac_set
|
||||
{
|
||||
unsigned int Status;
|
||||
unsigned int Vlan;
|
||||
unsigned char Mac[6];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct wc_capt_buf
|
||||
{
|
||||
unsigned long long TimeStamp;
|
||||
unsigned long long tsInUs;
|
||||
unsigned long long SessionId;
|
||||
unsigned char Type;
|
||||
unsigned char From;
|
||||
unsigned int Len;
|
||||
unsigned int Channel;
|
||||
unsigned int Direction;
|
||||
unsigned int Count;
|
||||
int Rssi;
|
||||
unsigned int DataRate;
|
||||
int wifiIf; // for dhcp
|
||||
char staMac[6]; // for dhcp
|
||||
unsigned char Buff[500];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct wc_arp_entry
|
||||
{
|
||||
unsigned char mac[6];
|
||||
unsigned int ip;
|
||||
unsigned long long TimeStamp;
|
||||
unsigned int action;
|
||||
unsigned int vlan;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define NUM_OF_NEIGH_IN_REQUEST 160
|
||||
|
||||
struct wc_ngbr_capt_buf
|
||||
{
|
||||
unsigned char Type;
|
||||
unsigned long long TimeStamp;
|
||||
unsigned int Channel;
|
||||
int Rssi;
|
||||
unsigned char Bssid[6];
|
||||
unsigned char SrcMac[6];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct wc_perf_stats
|
||||
{
|
||||
unsigned int MemFree;
|
||||
unsigned int EthPackets;
|
||||
unsigned int WiFiPackets;
|
||||
unsigned int CpuBusy[2];
|
||||
unsigned int AppRestarted[4];
|
||||
unsigned int MgmtBytesTx[2];
|
||||
unsigned int MgmtBytesRx[2];
|
||||
int EthLinkState;
|
||||
int EthSpeed;
|
||||
int EthDuplex;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct clt_hash_info
|
||||
{
|
||||
unsigned int VbrInd;
|
||||
unsigned int Num;
|
||||
void * EntryPtr;
|
||||
unsigned short Vlan;
|
||||
unsigned char Mac[6];
|
||||
unsigned int ApIp;
|
||||
unsigned int Age;
|
||||
|
||||
unsigned int CpTimeout;
|
||||
unsigned int CpBpsUp;
|
||||
unsigned int CpBpsDown;
|
||||
unsigned int CpWhitelist;
|
||||
|
||||
unsigned int SipPort;
|
||||
unsigned int SipState;
|
||||
unsigned int RtpPortsFrom;
|
||||
unsigned int RtpPortsTo;
|
||||
unsigned int RtpIpFrom;
|
||||
unsigned int RtpIpTo;
|
||||
|
||||
unsigned int FpAge;
|
||||
unsigned int NbrAge;
|
||||
unsigned int ArpAge;
|
||||
unsigned int ArpIp;
|
||||
|
||||
unsigned int UaFlag;
|
||||
unsigned int UaTimeOut;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct mac_hash_info
|
||||
{
|
||||
unsigned int VbrInd;
|
||||
unsigned int Num;
|
||||
void * EntryPtr;
|
||||
unsigned short Vlan;
|
||||
unsigned short Age;
|
||||
unsigned char Mac[6];
|
||||
unsigned char IfName[20];
|
||||
unsigned int CreditsFrom;
|
||||
unsigned int CreditsTo;
|
||||
unsigned int DroppedFrom;
|
||||
unsigned int DroppedTo;
|
||||
unsigned char Flags;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct wc_iac_register
|
||||
{
|
||||
unsigned int MessCode;
|
||||
unsigned int UdpPort;
|
||||
unsigned int Status; /* 1 - register; 0 - deregister */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct wc_iac_send
|
||||
{
|
||||
unsigned int DestIp;
|
||||
unsigned int MessCode;
|
||||
unsigned int MessLen;
|
||||
unsigned char Body[15000];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct wc_apc_neigh
|
||||
{
|
||||
unsigned int Ip;
|
||||
unsigned char BasicMac[6];
|
||||
} __attribute__((packed));
|
||||
|
||||
#define APC_UNKNOWN 0
|
||||
#define I_AM_APC 1
|
||||
#define I_AM_BAPC 2
|
||||
|
||||
struct wc_apc_spec
|
||||
{
|
||||
unsigned int IsApc;
|
||||
unsigned int Changed;
|
||||
unsigned int FloatIp;
|
||||
struct wc_apc_neigh Neighbors[APC_MAX_NEIGHBORS];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct wc_mac_ident
|
||||
{
|
||||
unsigned char Mac[6];
|
||||
unsigned char Ident[20];
|
||||
unsigned long long SessionId;
|
||||
unsigned int IdentLen;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct wc_subnet_filter
|
||||
{
|
||||
char IfName[20];
|
||||
unsigned int SubnetBase[5];
|
||||
unsigned int SubnetMask[5];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct wc_dhcp_release
|
||||
{
|
||||
unsigned int Vlan;
|
||||
unsigned int DestIp;
|
||||
unsigned int SrcIp;
|
||||
unsigned char DestMac[6];
|
||||
unsigned char SrcMac[6];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct wc_arp_sweep
|
||||
{
|
||||
unsigned int Vlan;
|
||||
unsigned int Subnet; //subnet = IP OR netMask e.g. 172.16.10.0
|
||||
unsigned int SrcIp; //Src IP
|
||||
unsigned char DestMac[6];
|
||||
unsigned char SrcMac[6];
|
||||
unsigned int SubnetSize; //num of IPs in subnet e.g. 255
|
||||
} __attribute__((packed));
|
||||
|
||||
struct wc_cp_whitelist
|
||||
{
|
||||
int Type;
|
||||
char Hostname[256];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct cp_auth_failed
|
||||
{
|
||||
unsigned char Mac[10][6];
|
||||
unsigned int Count[10];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct cp_auth_attempt
|
||||
{
|
||||
unsigned char Mac[6];
|
||||
unsigned char Uname[52];
|
||||
unsigned int Status;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct band_limit
|
||||
{
|
||||
char IfName[20];
|
||||
unsigned int ToLimit; /* Downstream */
|
||||
unsigned int FromLimit; /* Upstream */
|
||||
unsigned int Type;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bss_upstream_stats
|
||||
{
|
||||
char IfName[20];
|
||||
unsigned int PktsForwToLocal;
|
||||
unsigned int PktsForwToLocalOver;
|
||||
unsigned int BytesForwToLocal;
|
||||
unsigned int BytesForwToLocalOver;
|
||||
unsigned int PktsForwToIntern;
|
||||
unsigned int PktsForwToInternOver;
|
||||
unsigned int BytesForwToIntern;
|
||||
unsigned int BytesForwToInternOver;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bonjour_forw_rule
|
||||
{
|
||||
char RuleName[20];
|
||||
unsigned int VLAN[5];
|
||||
unsigned char Services[5][100];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct vlan_ssid
|
||||
{
|
||||
char IfName[20];
|
||||
unsigned int VLAN;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bj_profile_set
|
||||
{
|
||||
char IfName[20];
|
||||
char ProfileName[20];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct rogue_ap_macs
|
||||
{
|
||||
unsigned int MacHigh;
|
||||
unsigned int MacLow;
|
||||
unsigned int MaskBits;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct raw_pkt_throttle
|
||||
{
|
||||
unsigned int Type;
|
||||
unsigned int Interval;
|
||||
unsigned int Limit;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct forw_mode_set
|
||||
{
|
||||
char IfName[20];
|
||||
int ForwMode;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct wc_ethports_stats
|
||||
{
|
||||
int port0LinkState;
|
||||
int port1LinkState;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ua_timeout_upd
|
||||
{
|
||||
unsigned char cltMac[6];
|
||||
unsigned int uaTimeout;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct delClient
|
||||
{
|
||||
unsigned char cltMac[6];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct stream_srvr
|
||||
{
|
||||
unsigned int IpAddr;
|
||||
unsigned int Type;
|
||||
unsigned char DnsName[100];
|
||||
} __attribute__((packed));
|
||||
|
||||
extern int br_init(void);
|
||||
extern int br_refresh(void);
|
||||
extern void br_shutdown(void);
|
||||
|
||||
//extern int br_foreach_bridge(int (*iterator)(const char *brname, void *), void *arg);
|
||||
extern int br_foreach_port(const char *brname,
|
||||
int (*iterator)(const char *brname, const char *port,
|
||||
void *arg ),
|
||||
void *arg);
|
||||
extern const char *br_get_state_name(int state);
|
||||
|
||||
//extern int br_get_bridge_info(const char *br, struct bridge_info *info);
|
||||
extern int br_get_port_info(const char *brname, const char *port,
|
||||
struct port_info *info);
|
||||
extern int wc_add_vbr( const char * name );
|
||||
extern int wc_del_vbr( const char * name );
|
||||
extern int wc_add_interface( const char * vbr, const char * dev );
|
||||
extern int wc_del_interface( const char * vbr, const char * dev );
|
||||
//extern int br_set_bridge_forward_delay(const char *br, struct timeval *tv);
|
||||
//extern int br_set_bridge_hello_time(const char *br, struct timeval *tv);
|
||||
//extern int br_set_bridge_max_age(const char *br, struct timeval *tv);
|
||||
//extern int br_set_ageing_time(const char *br, struct timeval *tv);
|
||||
//extern int br_set_stp_state(const char *br, int stp_state);
|
||||
//extern int br_set_bridge_priority(const char *br, int bridge_priority);
|
||||
//extern int br_set_port_priority(const char *br, const char *p, int port_priority);
|
||||
int wc_set_socket( void );
|
||||
|
||||
//extern int br_set_path_cost(const char *br, const char *p, int path_cost);
|
||||
//extern int br_read_fdb(const char *br, struct fdb_entry *fdbs, unsigned long skip, int num);
|
||||
#endif
|
||||
28
feeds/wlan-ap/libwebsocket/src/include/websocket/libwcf_debug.h
Executable file
28
feeds/wlan-ap/libwebsocket/src/include/websocket/libwcf_debug.h
Executable file
@@ -0,0 +1,28 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#define WRITE_TO_FR 0x40000000
|
||||
|
||||
#define DEBUG_LEVEL_1 0x00000001
|
||||
#define DEBUG_LEVEL_2 0x00000002
|
||||
#define DEBUG_LEVEL_3 0x00000004
|
||||
#define DEBUG_LEVEL_4 0x00000008
|
||||
#define APP_LOG_CAMI 0x00000010
|
||||
#define APP_LOG_REDIR 0x00000020
|
||||
#define APP_LOG_DMAN 0x00000040
|
||||
#define APP_LOG_SYSLOG 0x00000080
|
||||
#define APP_LOG_WCFCTL 0x00000100
|
||||
#define APP_LOG_CORE 0x00000200
|
||||
#define APP_LOG_WEBSOCK 0x00000400
|
||||
#define APP_LOG_DHCP_DISC 0x00000800
|
||||
#define APP_LOG_STATUS_AGENT_DISC 0x00001000
|
||||
#define APP_LOG_APC 0x00002000
|
||||
#define APP_LOG_RADIUS_PROXY 0x00004000
|
||||
#define APP_LOG_NANNY 0x00008000
|
||||
#define APP_LOG_CP_UAP 0x00010000
|
||||
#define APP_LOG_RADIUS_PROBE 0x00020000
|
||||
#define APP_LOG_RTLS 0x00040000
|
||||
#define APP_LOG_HOSTAP 0x00080000
|
||||
#define APP_LOG_BESTAP 0x00100000
|
||||
|
||||
extern int wc_put_logline( unsigned int Mask, const char * format, ... );
|
||||
|
||||
38
feeds/wlan-ap/libwebsocket/src/include/websocket/libwcf_private.h
Executable file
38
feeds/wlan-ap/libwebsocket/src/include/websocket/libwcf_private.h
Executable file
@@ -0,0 +1,38 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#ifndef _LIBBRIDGE_PRIVATE_H
|
||||
#define _LIBBRIDGE_PRIVATE_H
|
||||
|
||||
#include <linux/sockios.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/if_bridge.h>
|
||||
|
||||
#define MAX_BRIDGES 1024
|
||||
#define MAX_PORTS 1024
|
||||
|
||||
#define SYSFS_CLASS_NET "/sys/class/net/"
|
||||
#define SYSFS_PATH_MAX 256
|
||||
|
||||
#define dprintf(fmt,arg...)
|
||||
|
||||
extern int br_socket_fd;
|
||||
|
||||
static inline unsigned long __tv_to_jiffies(const struct timeval *tv)
|
||||
{
|
||||
unsigned long long jif;
|
||||
|
||||
jif = 1000000ULL * tv->tv_sec + tv->tv_usec;
|
||||
|
||||
return jif/10000;
|
||||
}
|
||||
|
||||
static inline void __jiffies_to_tv(struct timeval *tv, unsigned long jiffies)
|
||||
{
|
||||
unsigned long long tvusec;
|
||||
|
||||
tvusec = 10000ULL*jiffies;
|
||||
tv->tv_sec = tvusec/1000000;
|
||||
tv->tv_usec = tvusec - 1000000 * tv->tv_sec;
|
||||
}
|
||||
#endif
|
||||
4197
feeds/wlan-ap/libwebsocket/src/include/websocket/libwebsockets.h
Normal file
4197
feeds/wlan-ap/libwebsocket/src/include/websocket/libwebsockets.h
Normal file
File diff suppressed because it is too large
Load Diff
119
feeds/wlan-ap/libwebsocket/src/include/websocket/lws_config.h
Normal file
119
feeds/wlan-ap/libwebsocket/src/include/websocket/lws_config.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
/* lws_config.h Generated from lws_config.h.in */
|
||||
|
||||
#ifndef NDEBUG
|
||||
#ifndef _DEBUG
|
||||
#define _DEBUG
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define LWS_INSTALL_DATADIR "/usr/local/share"
|
||||
|
||||
/* Define to 1 to use wolfSSL/CyaSSL as a replacement for OpenSSL.
|
||||
* LWS_OPENSSL_SUPPORT needs to be set also for this to work. */
|
||||
/* #undef USE_WOLFSSL */
|
||||
|
||||
/* Also define to 1 (in addition to USE_WOLFSSL) when using the
|
||||
(older) CyaSSL library */
|
||||
/* #undef USE_OLD_CYASSL */
|
||||
|
||||
/* #undef LWS_USE_MBEDTLS */
|
||||
/* #undef LWS_USE_POLARSSL */
|
||||
/* #undef LWS_WITH_ESP8266 */
|
||||
|
||||
/* #undef LWS_WITH_PLUGINS */
|
||||
/* #undef LWS_WITH_NO_LOGS */
|
||||
|
||||
/* The Libwebsocket version */
|
||||
#define LWS_LIBRARY_VERSION "2.1.0"
|
||||
|
||||
#define LWS_LIBRARY_VERSION_MAJOR 2
|
||||
#define LWS_LIBRARY_VERSION_MINOR 1
|
||||
#define LWS_LIBRARY_VERSION_PATCH 0
|
||||
/* LWS_LIBRARY_VERSION_NUMBER looks like 1005001 for e.g. version 1.5.1 */
|
||||
#define LWS_LIBRARY_VERSION_NUMBER (LWS_LIBRARY_VERSION_MAJOR*1000000)+(LWS_LIBRARY_VERSION_MINOR*1000)+LWS_LIBRARY_VERSION_PATCH
|
||||
|
||||
/* The current git commit hash that we're building from */
|
||||
#define LWS_BUILD_HASH "broadcom@localhost.localdomain-v2.0.0-189-g2357f7b"
|
||||
|
||||
/* Build with OpenSSL support */
|
||||
#define LWS_OPENSSL_SUPPORT
|
||||
|
||||
/* The client should load and trust CA root certs it finds in the OS */
|
||||
#define LWS_SSL_CLIENT_USE_OS_CA_CERTS
|
||||
|
||||
/* Sets the path where the client certs should be installed. */
|
||||
#define LWS_OPENSSL_CLIENT_CERTS "../share"
|
||||
|
||||
/* Turn off websocket extensions */
|
||||
#define LWS_NO_EXTENSIONS
|
||||
|
||||
/* Enable libev io loop */
|
||||
/* #undef LWS_USE_LIBEV */
|
||||
|
||||
/* Enable libuv io loop */
|
||||
/* #undef LWS_USE_LIBUV */
|
||||
|
||||
/* Build with support for ipv6 */
|
||||
/* #undef LWS_USE_IPV6 */
|
||||
|
||||
/* Build with support for UNIX domain socket */
|
||||
/* #undef LWS_USE_UNIX_SOCK */
|
||||
|
||||
/* Build with support for HTTP2 */
|
||||
/* #undef LWS_USE_HTTP2 */
|
||||
|
||||
/* Turn on latency measuring code */
|
||||
/* #undef LWS_LATENCY */
|
||||
|
||||
/* Don't build the daemonizeation api */
|
||||
#define LWS_NO_DAEMONIZE
|
||||
|
||||
/* Build without server support */
|
||||
/* #undef LWS_NO_SERVER */
|
||||
|
||||
/* Build without client support */
|
||||
/* #undef LWS_NO_CLIENT */
|
||||
|
||||
/* If we should compile with MinGW support */
|
||||
/* #undef LWS_MINGW_SUPPORT */
|
||||
|
||||
/* Use the BSD getifaddrs that comes with libwebsocket, for uclibc support */
|
||||
#define LWS_BUILTIN_GETIFADDRS
|
||||
|
||||
/* use SHA1() not internal libwebsockets_SHA1 */
|
||||
/* #undef LWS_SHA1_USE_OPENSSL_NAME */
|
||||
|
||||
/* SSL server using ECDH certificate */
|
||||
/* #undef LWS_SSL_SERVER_WITH_ECDH_CERT */
|
||||
#define LWS_HAVE_SSL_CTX_set1_param
|
||||
/* #undef LWS_HAVE_X509_VERIFY_PARAM_set1_host */
|
||||
|
||||
/* #undef LWS_HAVE_UV_VERSION_H */
|
||||
|
||||
/* CGI apis */
|
||||
/* #undef LWS_WITH_CGI */
|
||||
|
||||
/* whether the Openssl is recent enough, and / or built with, ecdh */
|
||||
/* #undef LWS_HAVE_OPENSSL_ECDH_H */
|
||||
|
||||
/* HTTP Proxy support */
|
||||
/* #undef LWS_WITH_HTTP_PROXY */
|
||||
|
||||
/* Http access log support */
|
||||
/* #undef LWS_WITH_ACCESS_LOG */
|
||||
/* #undef LWS_WITH_SERVER_STATUS */
|
||||
|
||||
/* #undef LWS_WITH_STATEFUL_URLDECODE */
|
||||
|
||||
/* Maximum supported service threads */
|
||||
#define LWS_MAX_SMP 32
|
||||
|
||||
/* Lightweight JSON Parser */
|
||||
/* #undef LWS_WITH_LEJP */
|
||||
|
||||
/* SMTP */
|
||||
/* #undef LWS_WITH_SMTP */
|
||||
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
/* lws_config_private.h.in. Private compilation options. */
|
||||
|
||||
#ifndef NDEBUG
|
||||
#ifndef _DEBUG
|
||||
#define _DEBUG
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Define to 1 to use CyaSSL as a replacement for OpenSSL.
|
||||
* LWS_OPENSSL_SUPPORT needs to be set also for this to work. */
|
||||
/* #undef USE_CYASSL */
|
||||
|
||||
/* Define to 1 if you have the `bzero' function. */
|
||||
#define LWS_HAVE_BZERO
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define LWS_HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#define LWS_HAVE_FCNTL_H
|
||||
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
#define LWS_HAVE_FORK
|
||||
|
||||
/* Define to 1 if you have the `getenv’ function. */
|
||||
#define LWS_HAVE_GETENV
|
||||
|
||||
/* Define to 1 if you have the <in6addr.h> header file. */
|
||||
/* #undef LWS_HAVE_IN6ADDR_H */
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define LWS_HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the `ssl' library (-lssl). */
|
||||
/* #undef LWS_HAVE_LIBSSL */
|
||||
|
||||
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
|
||||
to 0 otherwise. */
|
||||
#define LWS_HAVE_MALLOC
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define LWS_HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `memset' function. */
|
||||
#define LWS_HAVE_MEMSET
|
||||
|
||||
/* Define to 1 if you have the <netinet/in.h> header file. */
|
||||
#define LWS_HAVE_NETINET_IN_H
|
||||
|
||||
/* Define to 1 if your system has a GNU libc compatible `realloc' function,
|
||||
and to 0 otherwise. */
|
||||
#define LWS_HAVE_REALLOC
|
||||
|
||||
/* Define to 1 if you have the `socket' function. */
|
||||
#define LWS_HAVE_SOCKET
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define LWS_HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define LWS_HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#define LWS_HAVE_STRERROR
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define LWS_HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define LWS_HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/prctl.h> header file. */
|
||||
#define LWS_HAVE_SYS_PRCTL_H
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#define LWS_HAVE_SYS_SOCKET_H
|
||||
|
||||
/* Define to 1 if you have the <sys/sockio.h> header file. */
|
||||
/* #undef LWS_HAVE_SYS_SOCKIO_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define LWS_HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define LWS_HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define LWS_HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if you have the `vfork' function. */
|
||||
#define LWS_HAVE_VFORK
|
||||
|
||||
/* Define to 1 if you have the <vfork.h> header file. */
|
||||
/* #undef LWS_HAVE_VFORK_H */
|
||||
|
||||
/* Define to 1 if `fork' works. */
|
||||
#define LWS_HAVE_WORKING_FORK
|
||||
|
||||
/* Define to 1 if `vfork' works. */
|
||||
#define LWS_HAVE_WORKING_VFORK
|
||||
|
||||
/* Define to 1 if execvpe() exists */
|
||||
#define LWS_HAVE_EXECVPE
|
||||
|
||||
/* Define to 1 if you have the <zlib.h> header file. */
|
||||
#define LWS_HAVE_ZLIB_H
|
||||
|
||||
#define LWS_HAVE_GETLOADAVG
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#undef LT_OBJDIR // We're not using libtool
|
||||
|
||||
/* Define to rpl_malloc if the replacement function should be used. */
|
||||
/* #undef malloc */
|
||||
|
||||
/* Define to rpl_realloc if the replacement function should be used. */
|
||||
/* #undef realloc */
|
||||
|
||||
/* Define to 1 if we have getifaddrs */
|
||||
/* #undef LWS_HAVE_GETIFADDRS */
|
||||
|
||||
/* Define if the inline keyword doesn't exist. */
|
||||
/* #undef inline */
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
2668
feeds/wlan-ap/libwebsocket/src/libwebsockets.c
Executable file
2668
feeds/wlan-ap/libwebsocket/src/libwebsockets.c
Executable file
File diff suppressed because it is too large
Load Diff
730
feeds/wlan-ap/libwebsocket/src/lws-plat-unix.c
Normal file
730
feeds/wlan-ap/libwebsocket/src/lws-plat-unix.c
Normal file
@@ -0,0 +1,730 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#include "websocket/private-libwebsockets.h"
|
||||
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
#include <dirent.h>
|
||||
|
||||
|
||||
/*
|
||||
* included from libwebsockets.c for unix builds
|
||||
*/
|
||||
|
||||
unsigned long long time_in_microseconds(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return ((unsigned long long)tv.tv_sec * 1000000LL) + tv.tv_usec;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_get_random(struct lws_context *context, void *buf, int len)
|
||||
{
|
||||
return read(context->fd_random, (char *)buf, len);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_send_pipe_choked(struct lws *wsi)
|
||||
{
|
||||
struct lws_pollfd fds;
|
||||
|
||||
/* treat the fact we got a truncated send pending as if we're choked */
|
||||
if (wsi->trunc_len)
|
||||
return 1;
|
||||
|
||||
fds.fd = wsi->sock;
|
||||
fds.events = POLLOUT;
|
||||
fds.revents = 0;
|
||||
|
||||
if (poll(&fds, 1, 0) != 1)
|
||||
return 1;
|
||||
|
||||
if ((fds.revents & POLLOUT) == 0)
|
||||
return 1;
|
||||
|
||||
/* okay to send another packet without blocking */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_poll_listen_fd(struct lws_pollfd *fd)
|
||||
{
|
||||
return poll(fd, 1, 0);
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_cancel_service_pt(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
char buf = 0;
|
||||
|
||||
if (write(pt->dummy_pipe_fds[1], &buf, sizeof(buf)) != 1)
|
||||
lwsl_err("Cannot write to dummy pipe");
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_cancel_service(struct lws_context *context)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[0];
|
||||
char buf = 0, m = context->count_threads;
|
||||
|
||||
while (m--) {
|
||||
if (write(pt->dummy_pipe_fds[1], &buf, sizeof(buf)) != 1)
|
||||
lwsl_err("Cannot write to dummy pipe");
|
||||
pt++;
|
||||
}
|
||||
}
|
||||
|
||||
LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
|
||||
{
|
||||
int syslog_level = LOG_DEBUG;
|
||||
|
||||
switch (level) {
|
||||
case LLL_ERR:
|
||||
syslog_level = LOG_ERR;
|
||||
break;
|
||||
case LLL_WARN:
|
||||
syslog_level = LOG_WARNING;
|
||||
break;
|
||||
case LLL_NOTICE:
|
||||
syslog_level = LOG_NOTICE;
|
||||
break;
|
||||
case LLL_INFO:
|
||||
syslog_level = LOG_INFO;
|
||||
break;
|
||||
}
|
||||
syslog(syslog_level, "%s", line);
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
int n = -1, m, c;
|
||||
char buf;
|
||||
|
||||
/* stay dead once we are dead */
|
||||
|
||||
if (!context || !context->vhost_list)
|
||||
return 1;
|
||||
|
||||
if (timeout_ms < 0)
|
||||
goto faked_service;
|
||||
|
||||
lws_libev_run(context, tsi);
|
||||
lws_libuv_run(context, tsi);
|
||||
|
||||
if (!context->service_tid_detected) {
|
||||
struct lws _lws;
|
||||
|
||||
memset(&_lws, 0, sizeof(_lws));
|
||||
_lws.context = context;
|
||||
|
||||
context->service_tid_detected =
|
||||
context->vhost_list->protocols[0].callback(
|
||||
&_lws, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
|
||||
}
|
||||
context->service_tid = context->service_tid_detected;
|
||||
|
||||
/*
|
||||
* is there anybody with pending stuff that needs service forcing?
|
||||
*/
|
||||
if (!lws_service_adjust_timeout(context, 1, tsi)) {
|
||||
/* -1 timeout means just do forced service */
|
||||
_lws_plat_service_tsi(context, -1, pt->tid);
|
||||
/* still somebody left who wants forced service? */
|
||||
if (!lws_service_adjust_timeout(context, 1, pt->tid))
|
||||
/* yes... come back again quickly */
|
||||
timeout_ms = 0;
|
||||
}
|
||||
|
||||
n = poll(pt->fds, pt->fds_count, timeout_ms);
|
||||
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
if (!pt->rx_draining_ext_list &&
|
||||
!lws_ssl_anybody_has_buffered_read_tsi(context, tsi) && !n) {
|
||||
#else
|
||||
if (!pt->rx_draining_ext_list && !n) /* poll timeout */ {
|
||||
#endif
|
||||
lws_service_fd_tsi(context, NULL, tsi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
faked_service:
|
||||
m = lws_service_flag_pending(context, tsi);
|
||||
if (m)
|
||||
c = -1; /* unknown limit */
|
||||
else
|
||||
if (n < 0) {
|
||||
if (LWS_ERRNO != LWS_EINTR)
|
||||
return -1;
|
||||
return 0;
|
||||
} else
|
||||
c = n;
|
||||
|
||||
/* any socket with events to service? */
|
||||
for (n = 0; n < pt->fds_count && c; n++) {
|
||||
if (!pt->fds[n].revents)
|
||||
continue;
|
||||
|
||||
c--;
|
||||
|
||||
if (pt->fds[n].fd == pt->dummy_pipe_fds[0]) {
|
||||
if (read(pt->fds[n].fd, &buf, 1) != 1)
|
||||
lwsl_err("Cannot read from dummy pipe.");
|
||||
continue;
|
||||
}
|
||||
|
||||
m = lws_service_fd_tsi(context, &pt->fds[n], tsi);
|
||||
if (m < 0)
|
||||
return -1;
|
||||
/* if something closed, retry this slot */
|
||||
if (m)
|
||||
n--;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_check_connection_error(struct lws *wsi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_service(struct lws_context *context, int timeout_ms)
|
||||
{
|
||||
return _lws_plat_service_tsi(context, timeout_ms, 0);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_set_socket_options(struct lws_vhost *vhost, int fd)
|
||||
{
|
||||
int optval = 1;
|
||||
socklen_t optlen = sizeof(optval);
|
||||
|
||||
#if defined(__APPLE__) || \
|
||||
defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
|
||||
defined(__NetBSD__) || \
|
||||
defined(__OpenBSD__)
|
||||
struct protoent *tcp_proto;
|
||||
#endif
|
||||
|
||||
if (vhost->ka_time) {
|
||||
/* enable keepalive on this socket */
|
||||
optval = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
|
||||
(const void *)&optval, optlen) < 0)
|
||||
return 1;
|
||||
|
||||
#if defined(__APPLE__) || \
|
||||
defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
|
||||
defined(__NetBSD__) || \
|
||||
defined(__CYGWIN__) || defined(__OpenBSD__) || defined (__sun)
|
||||
|
||||
/*
|
||||
* didn't find a way to set these per-socket, need to
|
||||
* tune kernel systemwide values
|
||||
*/
|
||||
#else
|
||||
/* set the keepalive conditions we want on it too */
|
||||
optval = vhost->ka_time;
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE,
|
||||
(const void *)&optval, optlen) < 0)
|
||||
return 1;
|
||||
|
||||
optval = vhost->ka_interval;
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL,
|
||||
(const void *)&optval, optlen) < 0)
|
||||
return 1;
|
||||
|
||||
optval = vhost->ka_probes;
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT,
|
||||
(const void *)&optval, optlen) < 0)
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Disable Nagle */
|
||||
optval = 1;
|
||||
#if defined (__sun)
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void *)&optval, optlen) < 0)
|
||||
return 1;
|
||||
#elif !defined(__APPLE__) && \
|
||||
!defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) && \
|
||||
!defined(__NetBSD__) && \
|
||||
!defined(__OpenBSD__)
|
||||
if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen) < 0)
|
||||
return 1;
|
||||
#else
|
||||
tcp_proto = getprotobyname("TCP");
|
||||
if (setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen) < 0)
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
/* We are nonblocking... */
|
||||
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
|
||||
{
|
||||
if (info->gid != -1)
|
||||
if (setgid(info->gid))
|
||||
lwsl_warn("setgid: %s\n", strerror(LWS_ERRNO));
|
||||
|
||||
if (info->uid != -1) {
|
||||
struct passwd *p = getpwuid(info->uid);
|
||||
|
||||
if (p) {
|
||||
initgroups(p->pw_name, info->gid);
|
||||
if (setuid(info->uid))
|
||||
lwsl_warn("setuid: %s\n", strerror(LWS_ERRNO));
|
||||
else
|
||||
lwsl_notice("Set privs to user '%s'\n", p->pw_name);
|
||||
} else
|
||||
lwsl_warn("getpwuid: unable to find uid %d", info->uid);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
|
||||
#if defined(LWS_USE_LIBUV) && UV_VERSION_MAJOR > 0
|
||||
|
||||
/* libuv.c implements these in a cross-platform way */
|
||||
|
||||
#else
|
||||
|
||||
static int filter(const struct dirent *ent)
|
||||
{
|
||||
if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_plugins_init(struct lws_context * context, const char * const *d)
|
||||
{
|
||||
struct lws_plugin_capability lcaps;
|
||||
struct lws_plugin *plugin;
|
||||
lws_plugin_init_func initfunc;
|
||||
struct dirent **namelist;
|
||||
int n, i, m, ret = 0;
|
||||
char path[256];
|
||||
void *l;
|
||||
|
||||
lwsl_notice(" Plugins:\n");
|
||||
|
||||
while (d && *d) {
|
||||
n = scandir(*d, &namelist, filter, alphasort);
|
||||
if (n < 0) {
|
||||
lwsl_err("Scandir on %s failed\n", *d);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (strlen(namelist[i]->d_name) < 7)
|
||||
goto inval;
|
||||
|
||||
lwsl_notice(" %s\n", namelist[i]->d_name);
|
||||
|
||||
lws_snprintf(path, sizeof(path) - 1, "%s/%s", *d,
|
||||
namelist[i]->d_name);
|
||||
l = dlopen(path, RTLD_NOW);
|
||||
if (!l) {
|
||||
lwsl_err("Error loading DSO: %s\n", dlerror());
|
||||
while (i++ < n)
|
||||
free(namelist[i]);
|
||||
goto bail;
|
||||
}
|
||||
/* we could open it, can we get his init function? */
|
||||
m = lws_snprintf(path, sizeof(path) - 1, "init_%s",
|
||||
namelist[i]->d_name + 3 /* snip lib... */);
|
||||
path[m - 3] = '\0'; /* snip the .so */
|
||||
initfunc = dlsym(l, path);
|
||||
if (!initfunc) {
|
||||
lwsl_err("Failed to get init on %s: %s",
|
||||
namelist[i]->d_name, dlerror());
|
||||
dlclose(l);
|
||||
}
|
||||
lcaps.api_magic = LWS_PLUGIN_API_MAGIC;
|
||||
m = initfunc(context, &lcaps);
|
||||
if (m) {
|
||||
lwsl_err("Initializing %s failed %d\n",
|
||||
namelist[i]->d_name, m);
|
||||
dlclose(l);
|
||||
goto skip;
|
||||
}
|
||||
|
||||
plugin = lws_malloc(sizeof(*plugin));
|
||||
if (!plugin) {
|
||||
lwsl_err("OOM\n");
|
||||
goto bail;
|
||||
}
|
||||
plugin->list = context->plugin_list;
|
||||
context->plugin_list = plugin;
|
||||
strncpy(plugin->name, namelist[i]->d_name, sizeof(plugin->name) - 1);
|
||||
plugin->name[sizeof(plugin->name) - 1] = '\0';
|
||||
plugin->l = l;
|
||||
plugin->caps = lcaps;
|
||||
context->plugin_protocol_count += lcaps.count_protocols;
|
||||
context->plugin_extension_count += lcaps.count_extensions;
|
||||
|
||||
free(namelist[i]);
|
||||
continue;
|
||||
|
||||
skip:
|
||||
dlclose(l);
|
||||
inval:
|
||||
free(namelist[i]);
|
||||
}
|
||||
free(namelist);
|
||||
d++;
|
||||
}
|
||||
|
||||
bail:
|
||||
free(namelist);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_plugins_destroy(struct lws_context * context)
|
||||
{
|
||||
struct lws_plugin *plugin = context->plugin_list, *p;
|
||||
lws_plugin_destroy_func func;
|
||||
char path[256];
|
||||
int m;
|
||||
|
||||
if (!plugin)
|
||||
return 0;
|
||||
|
||||
lwsl_notice("%s\n", __func__);
|
||||
|
||||
while (plugin) {
|
||||
p = plugin;
|
||||
m = lws_snprintf(path, sizeof(path) - 1, "destroy_%s", plugin->name + 3);
|
||||
path[m - 3] = '\0';
|
||||
func = dlsym(plugin->l, path);
|
||||
if (!func) {
|
||||
lwsl_err("Failed to get destroy on %s: %s",
|
||||
plugin->name, dlerror());
|
||||
goto next;
|
||||
}
|
||||
m = func(context);
|
||||
if (m)
|
||||
lwsl_err("Initializing %s failed %d\n",
|
||||
plugin->name, m);
|
||||
next:
|
||||
dlclose(p->l);
|
||||
plugin = p->list;
|
||||
p->list = NULL;
|
||||
free(p);
|
||||
}
|
||||
|
||||
context->plugin_list = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
static void
|
||||
sigabrt_handler(int x)
|
||||
{
|
||||
printf("%s\n", __func__);
|
||||
//*(char *)0 = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_context_early_init(void)
|
||||
{
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
// signal(SIGABRT, sigabrt_handler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_context_early_destroy(struct lws_context *context)
|
||||
{
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_context_late_destroy(struct lws_context *context)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[0];
|
||||
int m = context->count_threads;
|
||||
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
if (context->plugin_list)
|
||||
lws_plat_plugins_destroy(context);
|
||||
#endif
|
||||
|
||||
if (context->lws_lookup)
|
||||
lws_free(context->lws_lookup);
|
||||
|
||||
while (m--) {
|
||||
close(pt->dummy_pipe_fds[0]);
|
||||
close(pt->dummy_pipe_fds[1]);
|
||||
pt++;
|
||||
}
|
||||
close(context->fd_random);
|
||||
}
|
||||
|
||||
/* cast a struct sockaddr_in6 * into addr for ipv6 */
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
|
||||
size_t addrlen)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
struct ifaddrs *ifr;
|
||||
struct ifaddrs *ifc;
|
||||
#ifdef LWS_USE_IPV6
|
||||
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
|
||||
#endif
|
||||
|
||||
getifaddrs(&ifr);
|
||||
for (ifc = ifr; ifc != NULL && rc; ifc = ifc->ifa_next) {
|
||||
if (!ifc->ifa_addr)
|
||||
continue;
|
||||
|
||||
lwsl_info(" interface %s vs %s\n", ifc->ifa_name, ifname);
|
||||
|
||||
if (strcmp(ifc->ifa_name, ifname))
|
||||
continue;
|
||||
|
||||
switch (ifc->ifa_addr->sa_family) {
|
||||
case AF_INET:
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (ipv6) {
|
||||
/* map IPv4 to IPv6 */
|
||||
bzero((char *)&addr6->sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
addr6->sin6_addr.s6_addr[10] = 0xff;
|
||||
addr6->sin6_addr.s6_addr[11] = 0xff;
|
||||
memcpy(&addr6->sin6_addr.s6_addr[12],
|
||||
&((struct sockaddr_in *)ifc->ifa_addr)->sin_addr,
|
||||
sizeof(struct in_addr));
|
||||
} else
|
||||
#endif
|
||||
memcpy(addr,
|
||||
(struct sockaddr_in *)ifc->ifa_addr,
|
||||
sizeof(struct sockaddr_in));
|
||||
break;
|
||||
#ifdef LWS_USE_IPV6
|
||||
case AF_INET6:
|
||||
memcpy(&addr6->sin6_addr,
|
||||
&((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
freeifaddrs(ifr);
|
||||
|
||||
if (rc == -1) {
|
||||
/* check if bind to IP address */
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1)
|
||||
rc = 0;
|
||||
else
|
||||
#endif
|
||||
if (inet_pton(AF_INET, ifname, &addr->sin_addr) == 1)
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
|
||||
lws_libev_io(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
lws_libuv_io(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
|
||||
pt->fds[pt->fds_count++].revents = 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_delete_socket_from_fds(struct lws_context *context,
|
||||
struct lws *wsi, int m)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
|
||||
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);
|
||||
lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);
|
||||
|
||||
pt->fds_count--;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_service_periodic(struct lws_context *context)
|
||||
{
|
||||
/* if our parent went down, don't linger around */
|
||||
if (context->started_with_parent &&
|
||||
kill(context->started_with_parent, 0) < 0)
|
||||
kill(getpid(), SIGTERM);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_change_pollfd(struct lws_context *context,
|
||||
struct lws *wsi, struct lws_pollfd *pfd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE const char *
|
||||
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
|
||||
{
|
||||
return inet_ntop(af, src, dst, cnt);
|
||||
}
|
||||
|
||||
static lws_filefd_type
|
||||
_lws_plat_file_open(struct lws *wsi, const char *filename,
|
||||
unsigned long *filelen, int flags)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
int ret = open(filename, flags, 0664);
|
||||
|
||||
if (ret < 0)
|
||||
return LWS_INVALID_FILE;
|
||||
|
||||
if (fstat(ret, &stat_buf) < 0) {
|
||||
close(ret);
|
||||
return LWS_INVALID_FILE;
|
||||
}
|
||||
*filelen = stat_buf.st_size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
_lws_plat_file_close(struct lws *wsi, lws_filefd_type fd)
|
||||
{
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
unsigned long
|
||||
_lws_plat_file_seek_cur(struct lws *wsi, lws_filefd_type fd, long offset)
|
||||
{
|
||||
return lseek(fd, offset, SEEK_CUR);
|
||||
}
|
||||
|
||||
static int
|
||||
_lws_plat_file_read(struct lws *wsi, lws_filefd_type fd, unsigned long *amount,
|
||||
unsigned char *buf, unsigned long len)
|
||||
{
|
||||
long n;
|
||||
|
||||
n = read((int)fd, buf, len);
|
||||
if (n == -1) {
|
||||
*amount = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*amount = n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_lws_plat_file_write(struct lws *wsi, lws_filefd_type fd, unsigned long *amount,
|
||||
unsigned char *buf, unsigned long len)
|
||||
{
|
||||
long n;
|
||||
|
||||
n = write((int)fd, buf, len);
|
||||
if (n == -1) {
|
||||
*amount = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*amount = n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_init(struct lws_context *context,
|
||||
struct lws_context_creation_info *info)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[0];
|
||||
int n = context->count_threads, fd;
|
||||
|
||||
/* master context has the global fd lookup array */
|
||||
context->lws_lookup = lws_zalloc(sizeof(struct lws *) *
|
||||
context->max_fds);
|
||||
if (context->lws_lookup == NULL) {
|
||||
lwsl_err("OOM on lws_lookup array for %d connections\n",
|
||||
context->max_fds);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lwsl_notice(" mem: platform fd map: %5u bytes\n",
|
||||
sizeof(struct lws *) * context->max_fds);
|
||||
fd = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
|
||||
|
||||
context->fd_random = fd;
|
||||
if (context->fd_random < 0) {
|
||||
lwsl_err("Unable to open random device %s %d\n",
|
||||
SYSTEM_RANDOM_FILEPATH, context->fd_random);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!lws_libev_init_fd_table(context) &&
|
||||
!lws_libuv_init_fd_table(context)) {
|
||||
/* otherwise libev handled it instead */
|
||||
|
||||
while (n--) {
|
||||
if (pipe(pt->dummy_pipe_fds)) {
|
||||
lwsl_err("Unable to create pipe\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* use the read end of pipe as first item */
|
||||
pt->fds[0].fd = pt->dummy_pipe_fds[0];
|
||||
pt->fds[0].events = LWS_POLLIN;
|
||||
pt->fds[0].revents = 0;
|
||||
pt->fds_count = 1;
|
||||
pt++;
|
||||
}
|
||||
}
|
||||
|
||||
context->fops.open = _lws_plat_file_open;
|
||||
context->fops.close = _lws_plat_file_close;
|
||||
context->fops.seek_cur = _lws_plat_file_seek_cur;
|
||||
context->fops.read = _lws_plat_file_read;
|
||||
context->fops.write = _lws_plat_file_write;
|
||||
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
if (info->plugin_dirs)
|
||||
lws_plat_plugins_init(context, info->plugin_dirs);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
700
feeds/wlan-ap/libwebsocket/src/output.c
Normal file
700
feeds/wlan-ap/libwebsocket/src/output.c
Normal file
@@ -0,0 +1,700 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#include "websocket/private-libwebsockets.h"
|
||||
|
||||
static int
|
||||
lws_0405_frame_mask_generate(struct lws *wsi)
|
||||
{
|
||||
#if 0
|
||||
wsi->u.ws.mask[0] = 0;
|
||||
wsi->u.ws.mask[1] = 0;
|
||||
wsi->u.ws.mask[2] = 0;
|
||||
wsi->u.ws.mask[3] = 0;
|
||||
#else
|
||||
int n;
|
||||
/* fetch the per-frame nonce */
|
||||
|
||||
n = lws_get_random(lws_get_context(wsi), wsi->u.ws.mask, 4);
|
||||
if (n != 4) {
|
||||
lwsl_parser("Unable to read from random device %s %d\n",
|
||||
SYSTEM_RANDOM_FILEPATH, n);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
/* start masking from first byte of masking key buffer */
|
||||
wsi->u.ws.mask_idx = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
LWS_VISIBLE void lwsl_hexdump(void *vbuf, size_t len)
|
||||
{
|
||||
unsigned char *buf = (unsigned char *)vbuf;
|
||||
unsigned int n, m, start;
|
||||
char line[80];
|
||||
char *p;
|
||||
|
||||
lwsl_parser("\n");
|
||||
|
||||
for (n = 0; n < len;) {
|
||||
start = n;
|
||||
p = line;
|
||||
|
||||
p += sprintf(p, "%04X: ", start);
|
||||
|
||||
for (m = 0; m < 16 && n < len; m++)
|
||||
p += sprintf(p, "%02X ", buf[n++]);
|
||||
while (m++ < 16)
|
||||
p += sprintf(p, " ");
|
||||
|
||||
p += sprintf(p, " ");
|
||||
|
||||
for (m = 0; m < 16 && (start + m) < len; m++) {
|
||||
if (buf[start + m] >= ' ' && buf[start + m] < 127)
|
||||
*p++ = buf[start + m];
|
||||
else
|
||||
*p++ = '.';
|
||||
}
|
||||
while (m++ < 16)
|
||||
*p++ = ' ';
|
||||
|
||||
*p++ = '\n';
|
||||
*p = '\0';
|
||||
lwsl_debug("%s", line);
|
||||
}
|
||||
lwsl_debug("\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* notice this returns number of bytes consumed, or -1
|
||||
*/
|
||||
|
||||
int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
|
||||
{
|
||||
struct lws_context *context = lws_get_context(wsi);
|
||||
size_t real_len = len;
|
||||
unsigned int n;
|
||||
int m;
|
||||
|
||||
if (!len)
|
||||
return 0;
|
||||
/* just ignore sends after we cleared the truncation buffer */
|
||||
if (wsi->state == LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE &&
|
||||
!wsi->trunc_len)
|
||||
return len;
|
||||
|
||||
if (wsi->trunc_len && (buf < wsi->trunc_alloc ||
|
||||
buf > (wsi->trunc_alloc + wsi->trunc_len + wsi->trunc_offset))) {
|
||||
char dump[20];
|
||||
strncpy(dump, (char *)buf, sizeof(dump) - 1);
|
||||
dump[sizeof(dump) - 1] = '\0';
|
||||
#if defined(LWS_WITH_ESP8266)
|
||||
lwsl_err("****** %p: Sending new %d (%s), pending truncated ...\n",
|
||||
wsi, len, dump);
|
||||
#else
|
||||
lwsl_err("****** %p: Sending new %d (%s), pending truncated ...\n"
|
||||
" It's illegal to do an lws_write outside of\n"
|
||||
" the writable callback: fix your code",
|
||||
wsi, len, dump);
|
||||
#endif
|
||||
a2w_logfr_and_reboot( "truncated" );
|
||||
#if 0
|
||||
assert(0);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
m = lws_ext_cb_active(wsi, LWS_EXT_CB_PACKET_TX_DO_SEND, &buf, len);
|
||||
if (m < 0)
|
||||
return -1;
|
||||
if (m) /* handled */ {
|
||||
n = m;
|
||||
goto handle_truncated_send;
|
||||
}
|
||||
|
||||
if (!lws_socket_is_valid(wsi->sock))
|
||||
lwsl_warn("** error invalid sock but expected to send\n");
|
||||
|
||||
/* limit sending */
|
||||
n = wsi->protocol->rx_buffer_size;
|
||||
if (!n)
|
||||
n = context->pt_serv_buf_size;
|
||||
n += LWS_PRE + 4;
|
||||
if (n > len)
|
||||
n = len;
|
||||
#if defined(LWS_WITH_ESP8266)
|
||||
if (wsi->pending_send_completion) {
|
||||
n = 0;
|
||||
goto handle_truncated_send;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* nope, send it on the socket directly */
|
||||
lws_latency_pre(context, wsi);
|
||||
n = lws_ssl_capable_write(wsi, buf, n);
|
||||
lws_latency(context, wsi, "send lws_issue_raw", n, n == len);
|
||||
|
||||
switch (n) {
|
||||
case LWS_SSL_CAPABLE_ERROR:
|
||||
/* we're going to close, let close know sends aren't possible */
|
||||
wsi->socket_is_permanently_unusable = 1;
|
||||
return -1;
|
||||
case LWS_SSL_CAPABLE_MORE_SERVICE:
|
||||
/* nothing got sent, not fatal, retry the whole thing later */
|
||||
n = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
handle_truncated_send:
|
||||
/*
|
||||
* we were already handling a truncated send?
|
||||
*/
|
||||
if (wsi->trunc_len) {
|
||||
lwsl_info("%p partial adv %d (vs %d)\n", wsi, n, real_len);
|
||||
wsi->trunc_offset += n;
|
||||
wsi->trunc_len -= n;
|
||||
|
||||
if (!wsi->trunc_len) {
|
||||
lwsl_info("***** %x partial send completed\n", wsi);
|
||||
/* done with it, but don't free it */
|
||||
n = real_len;
|
||||
if (wsi->state == LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
|
||||
lwsl_info("***** %x signalling to close now\n", wsi);
|
||||
return -1; /* retry closing now */
|
||||
}
|
||||
}
|
||||
/* always callback on writeable */
|
||||
lws_callback_on_writable(wsi);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
if ((unsigned int)n == real_len)
|
||||
/* what we just sent went out cleanly */
|
||||
return n;
|
||||
|
||||
/*
|
||||
* Newly truncated send. Buffer the remainder (it will get
|
||||
* first priority next time the socket is writable)
|
||||
*/
|
||||
lwsl_notice("%p new partial sent %d from %d total\n", wsi, n, real_len);
|
||||
|
||||
/*
|
||||
* - if we still have a suitable malloc lying around, use it
|
||||
* - or, if too small, reallocate it
|
||||
* - or, if no buffer, create it
|
||||
*/
|
||||
if (!wsi->trunc_alloc || real_len - n > wsi->trunc_alloc_len) {
|
||||
lws_free(wsi->trunc_alloc);
|
||||
|
||||
wsi->trunc_alloc_len = real_len - n;
|
||||
wsi->trunc_alloc = lws_malloc(real_len - n);
|
||||
if (!wsi->trunc_alloc) {
|
||||
lwsl_err("truncated send: unable to malloc %d\n",
|
||||
real_len - n);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
wsi->trunc_offset = 0;
|
||||
wsi->trunc_len = real_len - n;
|
||||
memcpy(wsi->trunc_alloc, buf + n, real_len - n);
|
||||
|
||||
/* since something buffered, force it to get another chance to send */
|
||||
lws_callback_on_writable(wsi);
|
||||
|
||||
return real_len;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len,
|
||||
enum lws_write_protocol wp)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
int masked7 = (wsi->mode == LWSCM_WS_CLIENT);
|
||||
unsigned char is_masked_bit = 0;
|
||||
unsigned char *dropmask = NULL;
|
||||
struct lws_tokens eff_buf;
|
||||
int pre = 0, n;
|
||||
size_t orig_len = len;
|
||||
|
||||
#ifdef LWS_WITH_ACCESS_LOG
|
||||
wsi->access_log.sent += len;
|
||||
#endif
|
||||
if (wsi->vhost)
|
||||
wsi->vhost->tx += len;
|
||||
|
||||
if (wsi->state == LWSS_ESTABLISHED && wsi->u.ws.tx_draining_ext) {
|
||||
/* remove us from the list */
|
||||
struct lws **w = &pt->tx_draining_ext_list;
|
||||
lwsl_debug("%s: TX EXT DRAINING: Remove from list\n", __func__);
|
||||
wsi->u.ws.tx_draining_ext = 0;
|
||||
/* remove us from context draining ext list */
|
||||
while (*w) {
|
||||
if (*w == wsi) {
|
||||
*w = wsi->u.ws.tx_draining_ext_list;
|
||||
break;
|
||||
}
|
||||
w = &((*w)->u.ws.tx_draining_ext_list);
|
||||
}
|
||||
wsi->u.ws.tx_draining_ext_list = NULL;
|
||||
wp = (wsi->u.ws.tx_draining_stashed_wp & 0xc0) |
|
||||
LWS_WRITE_CONTINUATION;
|
||||
|
||||
lwsl_ext("FORCED draining wp to 0x%02X\n", wp);
|
||||
}
|
||||
|
||||
lws_restart_ws_ping_pong_timer(wsi);
|
||||
|
||||
if (wp == LWS_WRITE_HTTP ||
|
||||
wp == LWS_WRITE_HTTP_FINAL ||
|
||||
wp == LWS_WRITE_HTTP_HEADERS)
|
||||
goto send_raw;
|
||||
|
||||
/* if not in a state to send stuff, then just send nothing */
|
||||
|
||||
if (wsi->state != LWSS_ESTABLISHED &&
|
||||
((wsi->state != LWSS_RETURNED_CLOSE_ALREADY &&
|
||||
wsi->state != LWSS_AWAITING_CLOSE_ACK) ||
|
||||
wp != LWS_WRITE_CLOSE))
|
||||
return 0;
|
||||
|
||||
/* if we are continuing a frame that already had its header done */
|
||||
|
||||
if (wsi->u.ws.inside_frame) {
|
||||
lwsl_debug("INSIDE FRAME\n");
|
||||
goto do_more_inside_frame;
|
||||
}
|
||||
|
||||
wsi->u.ws.clean_buffer = 1;
|
||||
|
||||
/*
|
||||
* give a chance to the extensions to modify payload
|
||||
* the extension may decide to produce unlimited payload erratically
|
||||
* (eg, compression extension), so we require only that if he produces
|
||||
* something, it will be a complete fragment of the length known at
|
||||
* the time (just the fragment length known), and if he has
|
||||
* more we will come back next time he is writeable and allow him to
|
||||
* produce more fragments until he's drained.
|
||||
*
|
||||
* This allows what is sent each time it is writeable to be limited to
|
||||
* a size that can be sent without partial sends or blocking, allows
|
||||
* interleaving of control frames and other connection service.
|
||||
*/
|
||||
eff_buf.token = (char *)buf;
|
||||
eff_buf.token_len = len;
|
||||
|
||||
switch ((int)wp) {
|
||||
case LWS_WRITE_PING:
|
||||
case LWS_WRITE_PONG:
|
||||
case LWS_WRITE_CLOSE:
|
||||
break;
|
||||
default:
|
||||
n = lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_TX, &eff_buf, wp);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
|
||||
if (n && eff_buf.token_len) {
|
||||
/* extension requires further draining */
|
||||
wsi->u.ws.tx_draining_ext = 1;
|
||||
wsi->u.ws.tx_draining_ext_list = pt->tx_draining_ext_list;
|
||||
pt->tx_draining_ext_list = wsi;
|
||||
/* we must come back to do more */
|
||||
lws_callback_on_writable(wsi);
|
||||
/*
|
||||
* keep a copy of the write type for the overall
|
||||
* action that has provoked generation of these
|
||||
* fragments, so the last guy can use its FIN state.
|
||||
*/
|
||||
wsi->u.ws.tx_draining_stashed_wp = wp;
|
||||
/* this is definitely not actually the last fragment
|
||||
* because the extension asserted he has more coming
|
||||
* So make sure this intermediate one doesn't go out
|
||||
* with a FIN.
|
||||
*/
|
||||
wp |= LWS_WRITE_NO_FIN;
|
||||
}
|
||||
|
||||
if (eff_buf.token_len && wsi->u.ws.stashed_write_pending) {
|
||||
wsi->u.ws.stashed_write_pending = 0;
|
||||
wp = (wp &0xc0) | (int)wsi->u.ws.stashed_write_type;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* an extension did something we need to keep... for example, if
|
||||
* compression extension, it has already updated its state according
|
||||
* to this being issued
|
||||
*/
|
||||
if ((char *)buf != eff_buf.token) {
|
||||
/*
|
||||
* ext might eat it, but no have anything to issue yet
|
||||
* in that case we have to follow his lead, but stash and
|
||||
* replace the write type that was lost here the first time.
|
||||
*/
|
||||
if (len && !eff_buf.token_len) {
|
||||
if (!wsi->u.ws.stashed_write_pending)
|
||||
wsi->u.ws.stashed_write_type = (char)wp & 0x3f;
|
||||
wsi->u.ws.stashed_write_pending = 1;
|
||||
return len;
|
||||
}
|
||||
/*
|
||||
* extension recreated it:
|
||||
* need to buffer this if not all sent
|
||||
*/
|
||||
wsi->u.ws.clean_buffer = 0;
|
||||
}
|
||||
|
||||
buf = (unsigned char *)eff_buf.token;
|
||||
len = eff_buf.token_len;
|
||||
|
||||
switch (wsi->ietf_spec_revision) {
|
||||
case 13:
|
||||
if (masked7) {
|
||||
pre += 4;
|
||||
dropmask = &buf[0 - pre];
|
||||
is_masked_bit = 0x80;
|
||||
}
|
||||
|
||||
switch (wp & 0xf) {
|
||||
case LWS_WRITE_TEXT:
|
||||
n = LWSWSOPC_TEXT_FRAME;
|
||||
break;
|
||||
case LWS_WRITE_BINARY:
|
||||
n = LWSWSOPC_BINARY_FRAME;
|
||||
break;
|
||||
case LWS_WRITE_CONTINUATION:
|
||||
n = LWSWSOPC_CONTINUATION;
|
||||
break;
|
||||
|
||||
case LWS_WRITE_CLOSE:
|
||||
n = LWSWSOPC_CLOSE;
|
||||
break;
|
||||
case LWS_WRITE_PING:
|
||||
n = LWSWSOPC_PING;
|
||||
break;
|
||||
case LWS_WRITE_PONG:
|
||||
n = LWSWSOPC_PONG;
|
||||
break;
|
||||
default:
|
||||
lwsl_warn("lws_write: unknown write opc / wp\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(wp & LWS_WRITE_NO_FIN))
|
||||
n |= 1 << 7;
|
||||
|
||||
if (len < 126) {
|
||||
pre += 2;
|
||||
buf[-pre] = n;
|
||||
buf[-pre + 1] = (unsigned char)(len | is_masked_bit);
|
||||
} else {
|
||||
if (len < 65536) {
|
||||
pre += 4;
|
||||
buf[-pre] = n;
|
||||
buf[-pre + 1] = 126 | is_masked_bit;
|
||||
buf[-pre + 2] = (unsigned char)(len >> 8);
|
||||
buf[-pre + 3] = (unsigned char)len;
|
||||
} else {
|
||||
pre += 10;
|
||||
buf[-pre] = n;
|
||||
buf[-pre + 1] = 127 | is_masked_bit;
|
||||
#if defined __LP64__
|
||||
buf[-pre + 2] = (len >> 56) & 0x7f;
|
||||
buf[-pre + 3] = len >> 48;
|
||||
buf[-pre + 4] = len >> 40;
|
||||
buf[-pre + 5] = len >> 32;
|
||||
#else
|
||||
buf[-pre + 2] = 0;
|
||||
buf[-pre + 3] = 0;
|
||||
buf[-pre + 4] = 0;
|
||||
buf[-pre + 5] = 0;
|
||||
#endif
|
||||
buf[-pre + 6] = (unsigned char)(len >> 24);
|
||||
buf[-pre + 7] = (unsigned char)(len >> 16);
|
||||
buf[-pre + 8] = (unsigned char)(len >> 8);
|
||||
buf[-pre + 9] = (unsigned char)len;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
do_more_inside_frame:
|
||||
|
||||
/*
|
||||
* Deal with masking if we are in client -> server direction and
|
||||
* the wp demands it
|
||||
*/
|
||||
|
||||
if (masked7) {
|
||||
if (!wsi->u.ws.inside_frame)
|
||||
if (lws_0405_frame_mask_generate(wsi)) {
|
||||
lwsl_err("frame mask generation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* in v7, just mask the payload
|
||||
*/
|
||||
if (dropmask) { /* never set if already inside frame */
|
||||
for (n = 4; n < (int)len + 4; n++)
|
||||
dropmask[n] = dropmask[n] ^ wsi->u.ws.mask[
|
||||
(wsi->u.ws.mask_idx++) & 3];
|
||||
|
||||
/* copy the frame nonce into place */
|
||||
memcpy(dropmask, wsi->u.ws.mask, 4);
|
||||
}
|
||||
}
|
||||
|
||||
send_raw:
|
||||
switch ((int)wp) {
|
||||
case LWS_WRITE_CLOSE:
|
||||
/* lwsl_hexdump(&buf[-pre], len); */
|
||||
case LWS_WRITE_HTTP:
|
||||
case LWS_WRITE_HTTP_FINAL:
|
||||
case LWS_WRITE_HTTP_HEADERS:
|
||||
case LWS_WRITE_PONG:
|
||||
case LWS_WRITE_PING:
|
||||
#ifdef LWS_USE_HTTP2
|
||||
if (wsi->mode == LWSCM_HTTP2_SERVING) {
|
||||
unsigned char flags = 0;
|
||||
|
||||
n = LWS_HTTP2_FRAME_TYPE_DATA;
|
||||
if (wp == LWS_WRITE_HTTP_HEADERS) {
|
||||
n = LWS_HTTP2_FRAME_TYPE_HEADERS;
|
||||
flags = LWS_HTTP2_FLAG_END_HEADERS;
|
||||
if (wsi->u.http2.send_END_STREAM)
|
||||
flags |= LWS_HTTP2_FLAG_END_STREAM;
|
||||
}
|
||||
|
||||
if ((wp == LWS_WRITE_HTTP ||
|
||||
wp == LWS_WRITE_HTTP_FINAL) &&
|
||||
wsi->u.http.content_length) {
|
||||
wsi->u.http.content_remain -= len;
|
||||
lwsl_info("%s: content_remain = %lu\n", __func__,
|
||||
wsi->u.http.content_remain);
|
||||
if (!wsi->u.http.content_remain) {
|
||||
lwsl_info("%s: selecting final write mode\n", __func__);
|
||||
wp = LWS_WRITE_HTTP_FINAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (wp == LWS_WRITE_HTTP_FINAL && wsi->u.http2.END_STREAM) {
|
||||
lwsl_info("%s: setting END_STREAM\n", __func__);
|
||||
flags |= LWS_HTTP2_FLAG_END_STREAM;
|
||||
}
|
||||
|
||||
return lws_http2_frame_write(wsi, n, flags,
|
||||
wsi->u.http2.my_stream_id, len, buf);
|
||||
}
|
||||
#endif
|
||||
return lws_issue_raw(wsi, (unsigned char *)buf - pre, len + pre);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* give any active extensions a chance to munge the buffer
|
||||
* before send. We pass in a pointer to an lws_tokens struct
|
||||
* prepared with the default buffer and content length that's in
|
||||
* there. Rather than rewrite the default buffer, extensions
|
||||
* that expect to grow the buffer can adapt .token to
|
||||
* point to their own per-connection buffer in the extension
|
||||
* user allocation. By default with no extensions or no
|
||||
* extension callback handling, just the normal input buffer is
|
||||
* used then so it is efficient.
|
||||
*
|
||||
* callback returns 1 in case it wants to spill more buffers
|
||||
*
|
||||
* This takes care of holding the buffer if send is incomplete, ie,
|
||||
* if wsi->u.ws.clean_buffer is 0 (meaning an extension meddled with
|
||||
* the buffer). If wsi->u.ws.clean_buffer is 1, it will instead
|
||||
* return to the user code how much OF THE USER BUFFER was consumed.
|
||||
*/
|
||||
|
||||
n = lws_issue_raw_ext_access(wsi, buf - pre, len + pre);
|
||||
wsi->u.ws.inside_frame = 1;
|
||||
if (n <= 0)
|
||||
return n;
|
||||
|
||||
if (n == (int)len + pre) {
|
||||
/* everything in the buffer was handled (or rebuffered...) */
|
||||
wsi->u.ws.inside_frame = 0;
|
||||
return orig_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* it is how many bytes of user buffer got sent... may be < orig_len
|
||||
* in which case callback when writable has already been arranged
|
||||
* and user code can call lws_write() again with the rest
|
||||
* later.
|
||||
*/
|
||||
|
||||
return n - pre;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
struct lws_process_html_args args;
|
||||
unsigned long amount, poss;
|
||||
unsigned char *p = pt->serv_buf;
|
||||
int n, m;
|
||||
|
||||
// lwsl_notice("%s (trunc len %d)\n", __func__, wsi->trunc_len);
|
||||
|
||||
while (wsi->http2_substream || !lws_send_pipe_choked(wsi)) {
|
||||
if (wsi->trunc_len) {
|
||||
if (lws_issue_raw(wsi, wsi->trunc_alloc +
|
||||
wsi->trunc_offset,
|
||||
wsi->trunc_len) < 0) {
|
||||
lwsl_info("%s: closing\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (wsi->u.http.filepos == wsi->u.http.filelen)
|
||||
goto all_sent;
|
||||
|
||||
poss = context->pt_serv_buf_size;
|
||||
|
||||
if (wsi->sending_chunked) {
|
||||
/* we need to drop the chunk size in here */
|
||||
p += 10;
|
||||
/* allow for the chunk to grow by 128 in translation */
|
||||
poss -= 10 + 128;
|
||||
}
|
||||
|
||||
if (lws_plat_file_read(wsi, wsi->u.http.fd, &amount, p, poss) < 0)
|
||||
return -1; /* caller will close */
|
||||
|
||||
//lwsl_notice("amount %ld\n", amount);
|
||||
|
||||
n = (int)amount;
|
||||
if (n) {
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,
|
||||
context->timeout_secs);
|
||||
|
||||
if (wsi->sending_chunked) {
|
||||
args.p = (char *)p;
|
||||
args.len = n;
|
||||
args.max_len = poss + 128;
|
||||
args.final = wsi->u.http.filepos + n ==
|
||||
wsi->u.http.filelen;
|
||||
if (user_callback_handle_rxflow(
|
||||
wsi->vhost->protocols[(int)wsi->protocol_interpret_idx].callback, wsi,
|
||||
LWS_CALLBACK_PROCESS_HTML,
|
||||
wsi->user_space, &args, 0) < 0)
|
||||
return -1;
|
||||
n = args.len;
|
||||
p = (unsigned char *)args.p;
|
||||
}
|
||||
|
||||
m = lws_write(wsi, p, n,
|
||||
wsi->u.http.filepos == wsi->u.http.filelen ?
|
||||
LWS_WRITE_HTTP_FINAL :
|
||||
LWS_WRITE_HTTP
|
||||
);
|
||||
if (m < 0)
|
||||
return -1;
|
||||
|
||||
wsi->u.http.filepos += amount;
|
||||
if (m != n) {
|
||||
/* adjust for what was not sent */
|
||||
if (lws_plat_file_seek_cur(wsi, wsi->u.http.fd,
|
||||
m - n) ==
|
||||
(unsigned long)-1)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
all_sent:
|
||||
if (!wsi->trunc_len &&
|
||||
wsi->u.http.filepos == wsi->u.http.filelen) {
|
||||
wsi->state = LWSS_HTTP;
|
||||
/* we might be in keepalive, so close it off here */
|
||||
lws_plat_file_close(wsi, wsi->u.http.fd);
|
||||
wsi->u.http.fd = LWS_INVALID_FILE;
|
||||
|
||||
lwsl_debug("file completed\n");
|
||||
|
||||
if (wsi->protocol->callback)
|
||||
/* ignore callback returned value */
|
||||
if (user_callback_handle_rxflow(
|
||||
wsi->protocol->callback, wsi,
|
||||
LWS_CALLBACK_HTTP_FILE_COMPLETION,
|
||||
wsi->user_space, NULL, 0) < 0)
|
||||
return -1;
|
||||
|
||||
return 1; /* >0 indicates completed */
|
||||
}
|
||||
}
|
||||
|
||||
lws_callback_on_writable(wsi);
|
||||
|
||||
return 0; /* indicates further processing must be done */
|
||||
}
|
||||
|
||||
#if LWS_POSIX
|
||||
LWS_VISIBLE int
|
||||
lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = recv(wsi->sock, (char *)buf, len, 0);
|
||||
if (n >= 0) {
|
||||
if (wsi->vhost)
|
||||
wsi->vhost->rx += n;
|
||||
lws_restart_ws_ping_pong_timer(wsi);
|
||||
return n;
|
||||
}
|
||||
#if LWS_POSIX
|
||||
if (LWS_ERRNO == LWS_EAGAIN ||
|
||||
LWS_ERRNO == LWS_EWOULDBLOCK ||
|
||||
LWS_ERRNO == LWS_EINTR)
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE;
|
||||
#endif
|
||||
lwsl_notice("error on reading from skt : %d\n", LWS_ERRNO);
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, int len)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
#if LWS_POSIX
|
||||
n = send(wsi->sock, (char *)buf, len, MSG_NOSIGNAL);
|
||||
// lwsl_info("%s: sent len %d result %d", __func__, len, n);
|
||||
if (n >= 0)
|
||||
return n;
|
||||
|
||||
if (LWS_ERRNO == LWS_EAGAIN ||
|
||||
LWS_ERRNO == LWS_EWOULDBLOCK ||
|
||||
LWS_ERRNO == LWS_EINTR) {
|
||||
if (LWS_ERRNO == LWS_EWOULDBLOCK)
|
||||
lws_set_blocking_send(wsi);
|
||||
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE;
|
||||
}
|
||||
#else
|
||||
(void)n;
|
||||
(void)wsi;
|
||||
(void)buf;
|
||||
(void)len;
|
||||
// !!!
|
||||
#endif
|
||||
|
||||
lwsl_debug("ERROR writing len %d to skt fd %d err %d / errno %d\n", len, wsi->sock, n, LWS_ERRNO);
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
#endif
|
||||
LWS_VISIBLE int
|
||||
lws_ssl_pending_no_ssl(struct lws *wsi)
|
||||
{
|
||||
(void)wsi;
|
||||
return 0;
|
||||
}
|
||||
1503
feeds/wlan-ap/libwebsocket/src/parsers.c
Normal file
1503
feeds/wlan-ap/libwebsocket/src/parsers.c
Normal file
File diff suppressed because it is too large
Load Diff
426
feeds/wlan-ap/libwebsocket/src/pollfd.c
Normal file
426
feeds/wlan-ap/libwebsocket/src/pollfd.c
Normal file
@@ -0,0 +1,426 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#include "websocket/private-libwebsockets.h"
|
||||
|
||||
int
|
||||
_lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa)
|
||||
{
|
||||
struct lws_context_per_thread *pt;
|
||||
struct lws_context *context;
|
||||
int ret = 0, pa_events = 1;
|
||||
struct lws_pollfd *pfd;
|
||||
int sampled_tid, tid;
|
||||
|
||||
if (!wsi || wsi->position_in_fds_table < 0)
|
||||
return 0;
|
||||
|
||||
context = wsi->context;
|
||||
pt = &context->pt[(int)wsi->tsi];
|
||||
assert(wsi->position_in_fds_table >= 0 &&
|
||||
wsi->position_in_fds_table < pt->fds_count);
|
||||
|
||||
pfd = &pt->fds[wsi->position_in_fds_table];
|
||||
pa->fd = wsi->sock;
|
||||
pa->prev_events = pfd->events;
|
||||
pa->events = pfd->events = (pfd->events & ~_and) | _or;
|
||||
|
||||
//lwsl_notice("%s: wsi %p, posin %d. from %d -> %d\n", __func__, wsi, wsi->position_in_fds_table, pa->prev_events, pa->events);
|
||||
|
||||
|
||||
if (wsi->http2_substream)
|
||||
return 0;
|
||||
|
||||
if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_CHANGE_MODE_POLL_FD,
|
||||
wsi->user_space, (void *)pa, 0)) {
|
||||
ret = -1;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (_and & LWS_POLLIN) {
|
||||
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_READ);
|
||||
lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_READ);
|
||||
}
|
||||
if (_or & LWS_POLLIN) {
|
||||
lws_libev_io(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
lws_libuv_io(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
}
|
||||
if (_and & LWS_POLLOUT) {
|
||||
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_WRITE);
|
||||
lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_WRITE);
|
||||
}
|
||||
if (_or & LWS_POLLOUT) {
|
||||
lws_libev_io(wsi, LWS_EV_START | LWS_EV_WRITE);
|
||||
lws_libuv_io(wsi, LWS_EV_START | LWS_EV_WRITE);
|
||||
}
|
||||
|
||||
/*
|
||||
* if we changed something in this pollfd...
|
||||
* ... and we're running in a different thread context
|
||||
* than the service thread...
|
||||
* ... and the service thread is waiting ...
|
||||
* then cancel it to force a restart with our changed events
|
||||
*/
|
||||
#if LWS_POSIX
|
||||
pa_events = pa->prev_events != pa->events;
|
||||
#endif
|
||||
|
||||
if (pa_events) {
|
||||
|
||||
if (lws_plat_change_pollfd(context, wsi, pfd)) {
|
||||
lwsl_info("%s failed\n", __func__);
|
||||
ret = -1;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
sampled_tid = context->service_tid;
|
||||
if (sampled_tid) {
|
||||
tid = wsi->vhost->protocols[0].callback(wsi,
|
||||
LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
|
||||
if (tid == -1) {
|
||||
ret = -1;
|
||||
goto bail;
|
||||
}
|
||||
if (tid != sampled_tid)
|
||||
lws_cancel_service_pt(wsi);
|
||||
}
|
||||
}
|
||||
bail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi)
|
||||
{
|
||||
struct lws_pollargs pa = { wsi->sock, LWS_POLLIN, 0 };
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
int ret = 0;
|
||||
#ifndef LWS_NO_SERVER
|
||||
struct lws_pollargs pa1;
|
||||
#endif
|
||||
|
||||
lwsl_debug("%s: %p: tsi=%d, sock=%d, pos-in-fds=%d\n",
|
||||
__func__, wsi, wsi->tsi, wsi->sock, pt->fds_count);
|
||||
|
||||
if ((unsigned int)pt->fds_count >= context->fd_limit_per_thread) {
|
||||
lwsl_err("Too many fds (%d vs %d)\n", context->max_fds,
|
||||
context->fd_limit_per_thread );
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) && !defined(MBED_OPERATORS) && !defined(LWS_WITH_ESP8266)
|
||||
if (wsi->sock >= context->max_fds) {
|
||||
lwsl_err("Socket fd %d is too high (%d)\n",
|
||||
wsi->sock, context->max_fds);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
assert(wsi);
|
||||
assert(wsi->vhost);
|
||||
assert(lws_socket_is_valid(wsi->sock));
|
||||
|
||||
if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL,
|
||||
wsi->user_space, (void *) &pa, 1))
|
||||
return -1;
|
||||
|
||||
lws_pt_lock(pt);
|
||||
pt->count_conns++;
|
||||
insert_wsi(context, wsi);
|
||||
#if defined(LWS_WITH_ESP8266)
|
||||
if (wsi->position_in_fds_table == -1)
|
||||
#endif
|
||||
wsi->position_in_fds_table = pt->fds_count;
|
||||
|
||||
// lwsl_notice("%s: %p: setting posinfds %d\n", __func__, wsi, wsi->position_in_fds_table);
|
||||
|
||||
pt->fds[wsi->position_in_fds_table].fd = wsi->sock;
|
||||
#if LWS_POSIX
|
||||
pt->fds[wsi->position_in_fds_table].events = LWS_POLLIN;
|
||||
#else
|
||||
pt->fds[wsi->position_in_fds_table].events = 0; // LWS_POLLIN;
|
||||
#endif
|
||||
pa.events = pt->fds[pt->fds_count].events;
|
||||
|
||||
lws_plat_insert_socket_into_fds(context, wsi);
|
||||
|
||||
/* external POLL support via protocol 0 */
|
||||
if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_ADD_POLL_FD,
|
||||
wsi->user_space, (void *) &pa, 0))
|
||||
ret = -1;
|
||||
#ifndef LWS_NO_SERVER
|
||||
/* if no more room, defeat accepts on this thread */
|
||||
if ((unsigned int)pt->fds_count == context->fd_limit_per_thread - 1)
|
||||
_lws_change_pollfd(pt->wsi_listening, LWS_POLLIN, 0, &pa1);
|
||||
#endif
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_UNLOCK_POLL,
|
||||
wsi->user_space, (void *)&pa, 1))
|
||||
ret = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
remove_wsi_socket_from_fds(struct lws *wsi)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
struct lws_pollargs pa = { wsi->sock, 0, 0 };
|
||||
#if !defined(LWS_WITH_ESP8266)
|
||||
#ifndef LWS_NO_SERVER
|
||||
struct lws_pollargs pa1;
|
||||
#endif
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
struct lws *end_wsi;
|
||||
int v;
|
||||
#endif
|
||||
int m, ret = 0;
|
||||
|
||||
#if !defined(_WIN32) && !defined(MBED_OPERATORS) && !defined(LWS_WITH_ESP8266)
|
||||
if (wsi->sock > context->max_fds) {
|
||||
lwsl_err("fd %d too high (%d)\n", wsi->sock, context->max_fds);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL,
|
||||
wsi->user_space, (void *)&pa, 1))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* detach ourselves from vh protocol list if we're on one
|
||||
* A -> B -> C
|
||||
* A -> C , or, B -> C, or A -> B
|
||||
*/
|
||||
lwsl_info("%s: removing same prot wsi %p\n", __func__, wsi);
|
||||
if (wsi->same_vh_protocol_prev) {
|
||||
assert (*(wsi->same_vh_protocol_prev) == wsi);
|
||||
lwsl_info("have prev %p, setting him to our next %p\n",
|
||||
wsi->same_vh_protocol_prev,
|
||||
wsi->same_vh_protocol_next);
|
||||
|
||||
/* guy who pointed to us should point to our next */
|
||||
*(wsi->same_vh_protocol_prev) = wsi->same_vh_protocol_next;
|
||||
} //else
|
||||
//lwsl_err("null wsi->prev\n");
|
||||
/* our next should point back to our prev */
|
||||
if (wsi->same_vh_protocol_next) {
|
||||
lwsl_info("have next %p\n");
|
||||
wsi->same_vh_protocol_next->same_vh_protocol_prev =
|
||||
wsi->same_vh_protocol_prev;
|
||||
} //else
|
||||
//lwsl_err("null wsi->next\n");
|
||||
|
||||
/* the guy who is to be deleted's slot index in pt->fds */
|
||||
m = wsi->position_in_fds_table;
|
||||
|
||||
#if !defined(LWS_WITH_ESP8266)
|
||||
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE | LWS_EV_PREPARE_DELETION);
|
||||
lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE | LWS_EV_PREPARE_DELETION);
|
||||
|
||||
lws_pt_lock(pt);
|
||||
|
||||
lwsl_debug("%s: wsi=%p, sock=%d, fds pos=%d, end guy pos=%d, endfd=%d\n",
|
||||
__func__, wsi, wsi->sock, wsi->position_in_fds_table,
|
||||
pt->fds_count, pt->fds[pt->fds_count].fd);
|
||||
|
||||
/* have the last guy take up the now vacant slot */
|
||||
pt->fds[m] = pt->fds[pt->fds_count - 1];
|
||||
#endif
|
||||
/* this decrements pt->fds_count */
|
||||
lws_plat_delete_socket_from_fds(context, wsi, m);
|
||||
#if !defined(LWS_WITH_ESP8266)
|
||||
v = (int) pt->fds[m].fd;
|
||||
/* end guy's "position in fds table" is now the deletion guy's old one */
|
||||
end_wsi = wsi_from_fd(context, v);
|
||||
if (!end_wsi) {
|
||||
lwsl_err("no wsi found for sock fd %d at pos %d, pt->fds_count=%d\n", (int)pt->fds[m].fd, m, pt->fds_count);
|
||||
assert(0);
|
||||
} else
|
||||
end_wsi->position_in_fds_table = m;
|
||||
|
||||
/* deletion guy's lws_lookup entry needs nuking */
|
||||
delete_from_fd(context, wsi->sock);
|
||||
/* removed wsi has no position any more */
|
||||
wsi->position_in_fds_table = -1;
|
||||
|
||||
/* remove also from external POLL support via protocol 0 */
|
||||
if (lws_socket_is_valid(wsi->sock))
|
||||
if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_DEL_POLL_FD,
|
||||
wsi->user_space, (void *) &pa, 0))
|
||||
ret = -1;
|
||||
#ifndef LWS_NO_SERVER
|
||||
if (!context->being_destroyed)
|
||||
/* if this made some room, accept connects on this thread */
|
||||
if ((unsigned int)pt->fds_count < context->fd_limit_per_thread - 1)
|
||||
_lws_change_pollfd(pt->wsi_listening, 0, LWS_POLLIN, &pa1);
|
||||
#endif
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_UNLOCK_POLL,
|
||||
wsi->user_space, (void *) &pa, 1))
|
||||
ret = -1;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
lws_change_pollfd(struct lws *wsi, int _and, int _or)
|
||||
{
|
||||
struct lws_context_per_thread *pt;
|
||||
struct lws_context *context;
|
||||
struct lws_pollargs pa;
|
||||
int ret = 0;
|
||||
|
||||
if (!wsi || !wsi->protocol || wsi->position_in_fds_table < 0)
|
||||
return 1;
|
||||
|
||||
context = lws_get_context(wsi);
|
||||
if (!context)
|
||||
return 1;
|
||||
|
||||
if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL,
|
||||
wsi->user_space, (void *) &pa, 0))
|
||||
return -1;
|
||||
|
||||
pt = &context->pt[(int)wsi->tsi];
|
||||
|
||||
lws_pt_lock(pt);
|
||||
ret = _lws_change_pollfd(wsi, _and, _or, &pa);
|
||||
lws_pt_unlock(pt);
|
||||
if (wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_UNLOCK_POLL,
|
||||
wsi->user_space, (void *) &pa, 0))
|
||||
ret = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_callback_on_writable(struct lws *wsi)
|
||||
{
|
||||
#ifdef LWS_USE_HTTP2
|
||||
struct lws *network_wsi, *wsi2;
|
||||
int already;
|
||||
#endif
|
||||
|
||||
if (wsi->state == LWSS_SHUTDOWN)
|
||||
return 0;
|
||||
|
||||
if (wsi->socket_is_permanently_unusable)
|
||||
return 0;
|
||||
|
||||
#ifdef LWS_USE_HTTP2
|
||||
lwsl_info("%s: %p\n", __func__, wsi);
|
||||
|
||||
if (wsi->mode != LWSCM_HTTP2_SERVING)
|
||||
goto network_sock;
|
||||
|
||||
if (wsi->u.http2.requested_POLLOUT) {
|
||||
lwsl_info("already pending writable\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (wsi->u.http2.tx_credit <= 0) {
|
||||
/*
|
||||
* other side is not able to cope with us sending
|
||||
* anything so no matter if we have POLLOUT on our side.
|
||||
*
|
||||
* Delay waiting for our POLLOUT until peer indicates he has
|
||||
* space for more using tx window command in http2 layer
|
||||
*/
|
||||
lwsl_info("%s: %p: waiting_tx_credit (%d)\n", __func__, wsi,
|
||||
wsi->u.http2.tx_credit);
|
||||
wsi->u.http2.waiting_tx_credit = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
network_wsi = lws_http2_get_network_wsi(wsi);
|
||||
already = network_wsi->u.http2.requested_POLLOUT;
|
||||
|
||||
/* mark everybody above him as requesting pollout */
|
||||
|
||||
wsi2 = wsi;
|
||||
while (wsi2) {
|
||||
wsi2->u.http2.requested_POLLOUT = 1;
|
||||
lwsl_info("mark %p pending writable\n", wsi2);
|
||||
wsi2 = wsi2->u.http2.parent_wsi;
|
||||
}
|
||||
|
||||
/* for network action, act only on the network wsi */
|
||||
|
||||
wsi = network_wsi;
|
||||
if (already)
|
||||
return 1;
|
||||
network_sock:
|
||||
#endif
|
||||
|
||||
if (lws_ext_cb_active(wsi, LWS_EXT_CB_REQUEST_ON_WRITEABLE, NULL, 0))
|
||||
return 1;
|
||||
|
||||
if (wsi->position_in_fds_table < 0) {
|
||||
lwsl_err("%s: failed to find socket %d\n", __func__, wsi->sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_callback_on_writable_all_protocol_vhost(const struct lws_vhost *vhost,
|
||||
const struct lws_protocols *protocol)
|
||||
{
|
||||
struct lws *wsi;
|
||||
|
||||
if (protocol < vhost->protocols ||
|
||||
protocol >= (vhost->protocols + vhost->count_protocols)) {
|
||||
lwsl_err("%s: protocol is not from vhost\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
wsi = vhost->same_vh_protocol_list[protocol - vhost->protocols];
|
||||
//lwsl_notice("%s: protocol %p, start wsi %p\n", __func__, protocol, wsi);
|
||||
while (wsi) {
|
||||
//lwsl_notice("%s: protocol %p, this wsi %p (wsi->protocol=%p)\n",
|
||||
// __func__, protocol, wsi, wsi->protocol);
|
||||
assert(wsi->protocol == protocol);
|
||||
assert(*wsi->same_vh_protocol_prev == wsi);
|
||||
if (wsi->same_vh_protocol_next) {
|
||||
// lwsl_err("my next says %p\n", wsi->same_vh_protocol_next);
|
||||
// lwsl_err("my next's prev says %p\n",
|
||||
// wsi->same_vh_protocol_next->same_vh_protocol_prev);
|
||||
assert(wsi->same_vh_protocol_next->same_vh_protocol_prev == &wsi->same_vh_protocol_next);
|
||||
}
|
||||
//lwsl_notice(" apv: %p\n", wsi);
|
||||
lws_callback_on_writable(wsi);
|
||||
wsi = wsi->same_vh_protocol_next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_callback_on_writable_all_protocol(const struct lws_context *context,
|
||||
const struct lws_protocols *protocol)
|
||||
{
|
||||
struct lws_vhost *vhost = context->vhost_list;
|
||||
int n;
|
||||
|
||||
while (vhost) {
|
||||
for (n = 0; n < vhost->count_protocols; n++)
|
||||
if (protocol->callback ==
|
||||
vhost->protocols[n].callback &&
|
||||
!strcmp(protocol->name, vhost->protocols[n].name))
|
||||
break;
|
||||
if (n != vhost->count_protocols)
|
||||
lws_callback_on_writable_all_protocol_vhost(
|
||||
vhost, &vhost->protocols[n]);
|
||||
|
||||
vhost = vhost->vhost_next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
263
feeds/wlan-ap/libwebsocket/src/server-handshake.c
Normal file
263
feeds/wlan-ap/libwebsocket/src/server-handshake.c
Normal file
@@ -0,0 +1,263 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#include "websocket/private-libwebsockets.h"
|
||||
|
||||
#define LWS_CPYAPP(ptr, str) { strcpy(ptr, str); ptr += strlen(str); }
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
LWS_VISIBLE int
|
||||
lws_extension_server_handshake(struct lws *wsi, char **p)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
const struct lws_extension *ext;
|
||||
char ext_name[128];
|
||||
int ext_count = 0;
|
||||
int more = 1;
|
||||
char ignore;
|
||||
int n, m;
|
||||
char *c;
|
||||
|
||||
/*
|
||||
* Figure out which extensions the client has that we want to
|
||||
* enable on this connection, and give him back the list
|
||||
*/
|
||||
if (!lws_hdr_total_length(wsi, WSI_TOKEN_EXTENSIONS))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* break down the list of client extensions
|
||||
* and go through them
|
||||
*/
|
||||
|
||||
if (lws_hdr_copy(wsi, (char *)pt->serv_buf, context->pt_serv_buf_size,
|
||||
WSI_TOKEN_EXTENSIONS) < 0)
|
||||
return 1;
|
||||
|
||||
c = (char *)pt->serv_buf;
|
||||
lwsl_parser("WSI_TOKEN_EXTENSIONS = '%s'\n", c);
|
||||
wsi->count_act_ext = 0;
|
||||
n = 0;
|
||||
ignore = 0;
|
||||
while (more) {
|
||||
|
||||
if (*c && (*c != ',' && *c != '\t')) {
|
||||
if (*c == ';')
|
||||
ignore = 1;
|
||||
if (ignore || *c == ' ') {
|
||||
c++;
|
||||
continue;
|
||||
}
|
||||
ext_name[n] = *c++;
|
||||
if (n < sizeof(ext_name) - 1)
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
ext_name[n] = '\0';
|
||||
|
||||
ignore = 0;
|
||||
if (!*c)
|
||||
more = 0;
|
||||
else {
|
||||
c++;
|
||||
if (!n)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check a client's extension against our support */
|
||||
|
||||
ext = wsi->vhost->extensions;
|
||||
|
||||
while (ext && ext->callback) {
|
||||
|
||||
if (strcmp(ext_name, ext->name)) {
|
||||
ext++;
|
||||
continue;
|
||||
}
|
||||
#if 0
|
||||
m = ext->callback(lws_get_context(wsi), ext, wsi,
|
||||
LWS_EXT_CB_ARGS_VALIDATE,
|
||||
NULL, start + n, 0);
|
||||
if (m) {
|
||||
ext++;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* oh, we do support this one he asked for... but let's
|
||||
* ask user code if it's OK to apply it on this
|
||||
* particular connection + protocol
|
||||
*/
|
||||
m = wsi->vhost->protocols[0].callback(wsi,
|
||||
LWS_CALLBACK_CONFIRM_EXTENSION_OKAY,
|
||||
wsi->user_space, ext_name, 0);
|
||||
|
||||
/*
|
||||
* zero return from callback means go ahead and allow
|
||||
* the extension, it's what we get if the callback is
|
||||
* unhandled
|
||||
*/
|
||||
|
||||
if (m) {
|
||||
ext++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* apply it */
|
||||
|
||||
ext_count++;
|
||||
|
||||
/* instantiate the extension on this conn */
|
||||
|
||||
wsi->active_extensions[wsi->count_act_ext] = ext;
|
||||
|
||||
/* allow him to construct his context */
|
||||
|
||||
if (ext->callback(lws_get_context(wsi), ext, wsi,
|
||||
LWS_EXT_CB_CONSTRUCT,
|
||||
(void *)&wsi->act_ext_user[wsi->count_act_ext],
|
||||
NULL, 0)) {
|
||||
lwsl_notice("ext %s failed construction\n", ext_name);
|
||||
ext_count--;
|
||||
ext++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ext_count > 1)
|
||||
*(*p)++ = ',';
|
||||
else
|
||||
LWS_CPYAPP(*p, "\x0d\x0aSec-WebSocket-Extensions: ");
|
||||
*p += sprintf(*p, "%s", ext_name);
|
||||
|
||||
wsi->count_act_ext++;
|
||||
lwsl_parser("count_act_ext <- %d\n", wsi->count_act_ext);
|
||||
|
||||
ext++;
|
||||
}
|
||||
|
||||
n = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
int
|
||||
handshake_0405(struct lws_context *context, struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
unsigned char hash[20];
|
||||
int n, accept_len;
|
||||
char *response;
|
||||
char *p;
|
||||
|
||||
if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST) ||
|
||||
!lws_hdr_total_length(wsi, WSI_TOKEN_KEY)) {
|
||||
lwsl_parser("handshake_04 missing pieces\n");
|
||||
/* completed header processing, but missing some bits */
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_KEY) >= MAX_WEBSOCKET_04_KEY_LEN) {
|
||||
lwsl_warn("Client key too long %d\n", MAX_WEBSOCKET_04_KEY_LEN);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/*
|
||||
* since key length is restricted above (currently 128), cannot
|
||||
* overflow
|
||||
*/
|
||||
n = sprintf((char *)pt->serv_buf,
|
||||
"%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11",
|
||||
lws_hdr_simple_ptr(wsi, WSI_TOKEN_KEY));
|
||||
|
||||
lws_SHA1(pt->serv_buf, n, hash);
|
||||
|
||||
accept_len = lws_b64_encode_string((char *)hash, 20, (char *)pt->serv_buf,
|
||||
context->pt_serv_buf_size);
|
||||
if (accept_len < 0) {
|
||||
lwsl_warn("Base64 encoded hash too long\n");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* allocate the per-connection user memory (if any) */
|
||||
if (lws_ensure_user_space(wsi))
|
||||
goto bail;
|
||||
|
||||
/* create the response packet */
|
||||
|
||||
/* make a buffer big enough for everything */
|
||||
|
||||
response = (char *)pt->serv_buf + MAX_WEBSOCKET_04_KEY_LEN + LWS_PRE;
|
||||
p = response;
|
||||
LWS_CPYAPP(p, "HTTP/1.1 101 Switching Protocols\x0d\x0a"
|
||||
"Upgrade: WebSocket\x0d\x0a"
|
||||
"Connection: Upgrade\x0d\x0a"
|
||||
"Sec-WebSocket-Accept: ");
|
||||
strcpy(p, (char *)pt->serv_buf);
|
||||
p += accept_len;
|
||||
|
||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL)) {
|
||||
LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: ");
|
||||
n = lws_hdr_copy(wsi, p, 128, WSI_TOKEN_PROTOCOL);
|
||||
if (n < 0)
|
||||
goto bail;
|
||||
p += n;
|
||||
}
|
||||
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
/*
|
||||
* Figure out which extensions the client has that we want to
|
||||
* enable on this connection, and give him back the list
|
||||
*/
|
||||
if (lws_extension_server_handshake(wsi, &p))
|
||||
goto bail;
|
||||
#endif
|
||||
|
||||
//LWS_CPYAPP(p, "\x0d\x0a""An-unknown-header: blah");
|
||||
|
||||
/* end of response packet */
|
||||
|
||||
LWS_CPYAPP(p, "\x0d\x0a\x0d\x0a");
|
||||
|
||||
if (!lws_any_extension_handled(wsi, LWS_EXT_CB_HANDSHAKE_REPLY_TX,
|
||||
response, p - response)) {
|
||||
|
||||
/* okay send the handshake response accepting the connection */
|
||||
|
||||
lwsl_parser("issuing resp pkt %d len\n", (int)(p - response));
|
||||
#if defined(DEBUG) && ! defined(LWS_WITH_ESP8266)
|
||||
fwrite(response, 1, p - response, stderr);
|
||||
#endif
|
||||
n = lws_write(wsi, (unsigned char *)response,
|
||||
p - response, LWS_WRITE_HTTP_HEADERS);
|
||||
if (n != (p - response)) {
|
||||
lwsl_debug("handshake_0405: ERROR writing to socket\n");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* alright clean up and set ourselves into established state */
|
||||
|
||||
wsi->state = LWSS_ESTABLISHED;
|
||||
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
|
||||
|
||||
{
|
||||
const char * uri_ptr =
|
||||
lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI);
|
||||
int uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI);
|
||||
const struct lws_http_mount *hit =
|
||||
lws_find_mount(wsi, uri_ptr, uri_len);
|
||||
if (hit && hit->cgienv &&
|
||||
wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP_PMO,
|
||||
wsi->user_space, (void *)hit->cgienv, 0))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
bail:
|
||||
/* caller will free up his parsing allocations */
|
||||
return -1;
|
||||
}
|
||||
|
||||
2751
feeds/wlan-ap/libwebsocket/src/server.c
Normal file
2751
feeds/wlan-ap/libwebsocket/src/server.c
Normal file
File diff suppressed because it is too large
Load Diff
1128
feeds/wlan-ap/libwebsocket/src/service.c
Normal file
1128
feeds/wlan-ap/libwebsocket/src/service.c
Normal file
File diff suppressed because it is too large
Load Diff
268
feeds/wlan-ap/libwebsocket/src/sha-1.c
Normal file
268
feeds/wlan-ap/libwebsocket/src/sha-1.c
Normal file
@@ -0,0 +1,268 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#include "websocket/private-libwebsockets.h"
|
||||
|
||||
#ifdef LWS_HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
struct sha1_ctxt {
|
||||
union {
|
||||
unsigned char b8[20];
|
||||
unsigned int b32[5];
|
||||
} h;
|
||||
union {
|
||||
unsigned char b8[8];
|
||||
u_int64_t b64[1];
|
||||
} c;
|
||||
union {
|
||||
unsigned char b8[64];
|
||||
unsigned int b32[16];
|
||||
} m;
|
||||
unsigned char count;
|
||||
};
|
||||
|
||||
/* sanity check */
|
||||
#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN)
|
||||
# define unsupported 1
|
||||
#elif BYTE_ORDER != BIG_ENDIAN
|
||||
# if BYTE_ORDER != LITTLE_ENDIAN
|
||||
# define unsupported 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef unsupported
|
||||
|
||||
/* constant table */
|
||||
static const unsigned int _K[] =
|
||||
{ 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 };
|
||||
#define K(t) _K[(t) / 20]
|
||||
|
||||
#define F0(b, c, d) (((b) & (c)) | ((~(b)) & (d)))
|
||||
#define F1(b, c, d) (((b) ^ (c)) ^ (d))
|
||||
#define F2(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d)))
|
||||
#define F3(b, c, d) (((b) ^ (c)) ^ (d))
|
||||
|
||||
#define S(n, x) (((x) << (n)) | ((x) >> (32 - n)))
|
||||
|
||||
#define H(n) (ctxt->h.b32[(n)])
|
||||
#define COUNT (ctxt->count)
|
||||
#define BCOUNT (ctxt->c.b64[0] / 8)
|
||||
#define W(n) (ctxt->m.b32[(n)])
|
||||
|
||||
#define PUTBYTE(x) { \
|
||||
ctxt->m.b8[(COUNT % 64)] = (x); \
|
||||
COUNT++; \
|
||||
COUNT %= 64; \
|
||||
ctxt->c.b64[0] += 8; \
|
||||
if (COUNT % 64 == 0) \
|
||||
sha1_step(ctxt); \
|
||||
}
|
||||
|
||||
#define PUTPAD(x) { \
|
||||
ctxt->m.b8[(COUNT % 64)] = (x); \
|
||||
COUNT++; \
|
||||
COUNT %= 64; \
|
||||
if (COUNT % 64 == 0) \
|
||||
sha1_step(ctxt); \
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sha1_step(struct sha1_ctxt *ctxt)
|
||||
{
|
||||
unsigned int a, b, c, d, e, tmp;
|
||||
size_t t, s;
|
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
struct sha1_ctxt tctxt;
|
||||
|
||||
memcpy(&tctxt.m.b8[0], &ctxt->m.b8[0], 64);
|
||||
ctxt->m.b8[0] = tctxt.m.b8[3]; ctxt->m.b8[1] = tctxt.m.b8[2];
|
||||
ctxt->m.b8[2] = tctxt.m.b8[1]; ctxt->m.b8[3] = tctxt.m.b8[0];
|
||||
ctxt->m.b8[4] = tctxt.m.b8[7]; ctxt->m.b8[5] = tctxt.m.b8[6];
|
||||
ctxt->m.b8[6] = tctxt.m.b8[5]; ctxt->m.b8[7] = tctxt.m.b8[4];
|
||||
ctxt->m.b8[8] = tctxt.m.b8[11]; ctxt->m.b8[9] = tctxt.m.b8[10];
|
||||
ctxt->m.b8[10] = tctxt.m.b8[9]; ctxt->m.b8[11] = tctxt.m.b8[8];
|
||||
ctxt->m.b8[12] = tctxt.m.b8[15]; ctxt->m.b8[13] = tctxt.m.b8[14];
|
||||
ctxt->m.b8[14] = tctxt.m.b8[13]; ctxt->m.b8[15] = tctxt.m.b8[12];
|
||||
ctxt->m.b8[16] = tctxt.m.b8[19]; ctxt->m.b8[17] = tctxt.m.b8[18];
|
||||
ctxt->m.b8[18] = tctxt.m.b8[17]; ctxt->m.b8[19] = tctxt.m.b8[16];
|
||||
ctxt->m.b8[20] = tctxt.m.b8[23]; ctxt->m.b8[21] = tctxt.m.b8[22];
|
||||
ctxt->m.b8[22] = tctxt.m.b8[21]; ctxt->m.b8[23] = tctxt.m.b8[20];
|
||||
ctxt->m.b8[24] = tctxt.m.b8[27]; ctxt->m.b8[25] = tctxt.m.b8[26];
|
||||
ctxt->m.b8[26] = tctxt.m.b8[25]; ctxt->m.b8[27] = tctxt.m.b8[24];
|
||||
ctxt->m.b8[28] = tctxt.m.b8[31]; ctxt->m.b8[29] = tctxt.m.b8[30];
|
||||
ctxt->m.b8[30] = tctxt.m.b8[29]; ctxt->m.b8[31] = tctxt.m.b8[28];
|
||||
ctxt->m.b8[32] = tctxt.m.b8[35]; ctxt->m.b8[33] = tctxt.m.b8[34];
|
||||
ctxt->m.b8[34] = tctxt.m.b8[33]; ctxt->m.b8[35] = tctxt.m.b8[32];
|
||||
ctxt->m.b8[36] = tctxt.m.b8[39]; ctxt->m.b8[37] = tctxt.m.b8[38];
|
||||
ctxt->m.b8[38] = tctxt.m.b8[37]; ctxt->m.b8[39] = tctxt.m.b8[36];
|
||||
ctxt->m.b8[40] = tctxt.m.b8[43]; ctxt->m.b8[41] = tctxt.m.b8[42];
|
||||
ctxt->m.b8[42] = tctxt.m.b8[41]; ctxt->m.b8[43] = tctxt.m.b8[40];
|
||||
ctxt->m.b8[44] = tctxt.m.b8[47]; ctxt->m.b8[45] = tctxt.m.b8[46];
|
||||
ctxt->m.b8[46] = tctxt.m.b8[45]; ctxt->m.b8[47] = tctxt.m.b8[44];
|
||||
ctxt->m.b8[48] = tctxt.m.b8[51]; ctxt->m.b8[49] = tctxt.m.b8[50];
|
||||
ctxt->m.b8[50] = tctxt.m.b8[49]; ctxt->m.b8[51] = tctxt.m.b8[48];
|
||||
ctxt->m.b8[52] = tctxt.m.b8[55]; ctxt->m.b8[53] = tctxt.m.b8[54];
|
||||
ctxt->m.b8[54] = tctxt.m.b8[53]; ctxt->m.b8[55] = tctxt.m.b8[52];
|
||||
ctxt->m.b8[56] = tctxt.m.b8[59]; ctxt->m.b8[57] = tctxt.m.b8[58];
|
||||
ctxt->m.b8[58] = tctxt.m.b8[57]; ctxt->m.b8[59] = tctxt.m.b8[56];
|
||||
ctxt->m.b8[60] = tctxt.m.b8[63]; ctxt->m.b8[61] = tctxt.m.b8[62];
|
||||
ctxt->m.b8[62] = tctxt.m.b8[61]; ctxt->m.b8[63] = tctxt.m.b8[60];
|
||||
#endif
|
||||
|
||||
a = H(0); b = H(1); c = H(2); d = H(3); e = H(4);
|
||||
|
||||
for (t = 0; t < 20; t++) {
|
||||
s = t & 0x0f;
|
||||
if (t >= 16)
|
||||
W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
|
||||
W((s+2) & 0x0f) ^ W(s));
|
||||
|
||||
tmp = S(5, a) + F0(b, c, d) + e + W(s) + K(t);
|
||||
e = d; d = c; c = S(30, b); b = a; a = tmp;
|
||||
}
|
||||
for (t = 20; t < 40; t++) {
|
||||
s = t & 0x0f;
|
||||
W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
|
||||
W((s+2) & 0x0f) ^ W(s));
|
||||
tmp = S(5, a) + F1(b, c, d) + e + W(s) + K(t);
|
||||
e = d; d = c; c = S(30, b); b = a; a = tmp;
|
||||
}
|
||||
for (t = 40; t < 60; t++) {
|
||||
s = t & 0x0f;
|
||||
W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
|
||||
W((s+2) & 0x0f) ^ W(s));
|
||||
tmp = S(5, a) + F2(b, c, d) + e + W(s) + K(t);
|
||||
e = d; d = c; c = S(30, b); b = a; a = tmp;
|
||||
}
|
||||
for (t = 60; t < 80; t++) {
|
||||
s = t & 0x0f;
|
||||
W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
|
||||
W((s+2) & 0x0f) ^ W(s));
|
||||
tmp = S(5, a) + F3(b, c, d) + e + W(s) + K(t);
|
||||
e = d; d = c; c = S(30, b); b = a; a = tmp;
|
||||
}
|
||||
|
||||
H(0) = H(0) + a;
|
||||
H(1) = H(1) + b;
|
||||
H(2) = H(2) + c;
|
||||
H(3) = H(3) + d;
|
||||
H(4) = H(4) + e;
|
||||
|
||||
bzero(&ctxt->m.b8[0], 64);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------*/
|
||||
|
||||
static void
|
||||
_sha1_init(struct sha1_ctxt *ctxt)
|
||||
{
|
||||
bzero(ctxt, sizeof(struct sha1_ctxt));
|
||||
H(0) = 0x67452301;
|
||||
H(1) = 0xefcdab89;
|
||||
H(2) = 0x98badcfe;
|
||||
H(3) = 0x10325476;
|
||||
H(4) = 0xc3d2e1f0;
|
||||
}
|
||||
|
||||
void
|
||||
sha1_pad(struct sha1_ctxt *ctxt)
|
||||
{
|
||||
size_t padlen; /*pad length in bytes*/
|
||||
size_t padstart;
|
||||
|
||||
PUTPAD(0x80);
|
||||
|
||||
padstart = COUNT % 64;
|
||||
padlen = 64 - padstart;
|
||||
if (padlen < 8) {
|
||||
bzero(&ctxt->m.b8[padstart], padlen);
|
||||
COUNT += (unsigned char)padlen;
|
||||
COUNT %= 64;
|
||||
sha1_step(ctxt);
|
||||
padstart = COUNT % 64; /* should be 0 */
|
||||
padlen = 64 - padstart; /* should be 64 */
|
||||
}
|
||||
bzero(&ctxt->m.b8[padstart], padlen - 8);
|
||||
COUNT += ((unsigned char)padlen - 8);
|
||||
COUNT %= 64;
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
PUTPAD(ctxt->c.b8[0]); PUTPAD(ctxt->c.b8[1]);
|
||||
PUTPAD(ctxt->c.b8[2]); PUTPAD(ctxt->c.b8[3]);
|
||||
PUTPAD(ctxt->c.b8[4]); PUTPAD(ctxt->c.b8[5]);
|
||||
PUTPAD(ctxt->c.b8[6]); PUTPAD(ctxt->c.b8[7]);
|
||||
#else
|
||||
PUTPAD(ctxt->c.b8[7]); PUTPAD(ctxt->c.b8[6]);
|
||||
PUTPAD(ctxt->c.b8[5]); PUTPAD(ctxt->c.b8[4]);
|
||||
PUTPAD(ctxt->c.b8[3]); PUTPAD(ctxt->c.b8[2]);
|
||||
PUTPAD(ctxt->c.b8[1]); PUTPAD(ctxt->c.b8[0]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
sha1_loop(struct sha1_ctxt *ctxt, const unsigned char *input, size_t len)
|
||||
{
|
||||
size_t gaplen;
|
||||
size_t gapstart;
|
||||
size_t off;
|
||||
size_t copysiz;
|
||||
|
||||
off = 0;
|
||||
|
||||
while (off < len) {
|
||||
gapstart = COUNT % 64;
|
||||
gaplen = 64 - gapstart;
|
||||
|
||||
copysiz = (gaplen < len - off) ? gaplen : len - off;
|
||||
memcpy(&ctxt->m.b8[gapstart], &input[off], copysiz);
|
||||
COUNT += (unsigned char)copysiz;
|
||||
COUNT %= 64;
|
||||
ctxt->c.b64[0] += copysiz * 8;
|
||||
if (COUNT % 64 == 0)
|
||||
sha1_step(ctxt);
|
||||
off += copysiz;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sha1_result(struct sha1_ctxt *ctxt, void *digest0)
|
||||
{
|
||||
unsigned char *digest;
|
||||
|
||||
digest = (unsigned char *)digest0;
|
||||
sha1_pad(ctxt);
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
memcpy(digest, &ctxt->h.b8[0], 20);
|
||||
#else
|
||||
digest[0] = ctxt->h.b8[3]; digest[1] = ctxt->h.b8[2];
|
||||
digest[2] = ctxt->h.b8[1]; digest[3] = ctxt->h.b8[0];
|
||||
digest[4] = ctxt->h.b8[7]; digest[5] = ctxt->h.b8[6];
|
||||
digest[6] = ctxt->h.b8[5]; digest[7] = ctxt->h.b8[4];
|
||||
digest[8] = ctxt->h.b8[11]; digest[9] = ctxt->h.b8[10];
|
||||
digest[10] = ctxt->h.b8[9]; digest[11] = ctxt->h.b8[8];
|
||||
digest[12] = ctxt->h.b8[15]; digest[13] = ctxt->h.b8[14];
|
||||
digest[14] = ctxt->h.b8[13]; digest[15] = ctxt->h.b8[12];
|
||||
digest[16] = ctxt->h.b8[19]; digest[17] = ctxt->h.b8[18];
|
||||
digest[18] = ctxt->h.b8[17]; digest[19] = ctxt->h.b8[16];
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* This should look and work like the libcrypto implementation
|
||||
*/
|
||||
|
||||
LWS_VISIBLE unsigned char *
|
||||
lws_SHA1(const unsigned char *d, size_t n, unsigned char *md)
|
||||
{
|
||||
struct sha1_ctxt ctx;
|
||||
|
||||
_sha1_init(&ctx);
|
||||
sha1_loop(&ctx, d, n);
|
||||
sha1_result(&ctx, (void *)md);
|
||||
|
||||
return md;
|
||||
}
|
||||
|
||||
#endif /*unsupported*/
|
||||
436
feeds/wlan-ap/libwebsocket/src/ssl-client.c
Normal file
436
feeds/wlan-ap/libwebsocket/src/ssl-client.c
Normal file
@@ -0,0 +1,436 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#include "websocket/private-libwebsockets.h"
|
||||
|
||||
extern int openssl_websocket_private_data_index,
|
||||
openssl_SSL_CTX_private_data_index;
|
||||
|
||||
extern void
|
||||
lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info);
|
||||
|
||||
extern int lws_ssl_get_error(struct lws *wsi, int n);
|
||||
|
||||
int
|
||||
lws_ssl_client_bio_create(struct lws *wsi)
|
||||
{
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
return 0;
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
struct lws_context *context = wsi->context;
|
||||
const char *hostname = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST);
|
||||
|
||||
(void)hostname;
|
||||
|
||||
wsi->ssl = SSL_new(wsi->vhost->ssl_client_ctx);
|
||||
if (!wsi->ssl) {
|
||||
lwsl_err("SSL_new failed: %s\n",
|
||||
ERR_error_string(lws_ssl_get_error(wsi, 0), NULL));
|
||||
lws_decode_ssl_error();
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined LWS_HAVE_X509_VERIFY_PARAM_set1_host
|
||||
X509_VERIFY_PARAM *param;
|
||||
(void)param;
|
||||
|
||||
if (!(wsi->use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) {
|
||||
param = SSL_get0_param(wsi->ssl);
|
||||
/* Enable automatic hostname checks */
|
||||
X509_VERIFY_PARAM_set_hostflags(param,
|
||||
X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
|
||||
X509_VERIFY_PARAM_set1_host(param, hostname, 0);
|
||||
/* Configure a non-zero callback if desired */
|
||||
SSL_set_verify(wsi->ssl, SSL_VERIFY_PEER, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef USE_WOLFSSL
|
||||
SSL_set_mode(wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||
#endif
|
||||
/*
|
||||
* use server name indication (SNI), if supported,
|
||||
* when establishing connection
|
||||
*/
|
||||
#ifdef USE_WOLFSSL
|
||||
#ifdef USE_OLD_CYASSL
|
||||
#ifdef CYASSL_SNI_HOST_NAME
|
||||
CyaSSL_UseSNI(wsi->ssl, CYASSL_SNI_HOST_NAME, hostname, strlen(hostname));
|
||||
#endif
|
||||
#else
|
||||
#ifdef WOLFSSL_SNI_HOST_NAME
|
||||
wolfSSL_UseSNI(wsi->ssl, WOLFSSL_SNI_HOST_NAME, hostname, strlen(hostname));
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
SSL_set_tlsext_host_name(wsi->ssl, hostname);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_WOLFSSL
|
||||
/*
|
||||
* wolfSSL/CyaSSL does certificate verification differently
|
||||
* from OpenSSL.
|
||||
* If we should ignore the certificate, we need to set
|
||||
* this before SSL_new and SSL_connect is called.
|
||||
* Otherwise the connect will simply fail with error code -155
|
||||
*/
|
||||
#ifdef USE_OLD_CYASSL
|
||||
if (wsi->use_ssl == 2)
|
||||
CyaSSL_set_verify(wsi->ssl, SSL_VERIFY_NONE, NULL);
|
||||
#else
|
||||
if (wsi->use_ssl == 2)
|
||||
wolfSSL_set_verify(wsi->ssl, SSL_VERIFY_NONE, NULL);
|
||||
#endif
|
||||
#endif /* USE_WOLFSSL */
|
||||
|
||||
wsi->client_bio = BIO_new_socket(wsi->sock, BIO_NOCLOSE);
|
||||
SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio);
|
||||
|
||||
#ifdef USE_WOLFSSL
|
||||
#ifdef USE_OLD_CYASSL
|
||||
CyaSSL_set_using_nonblock(wsi->ssl, 1);
|
||||
#else
|
||||
wolfSSL_set_using_nonblock(wsi->ssl, 1);
|
||||
#endif
|
||||
#else
|
||||
BIO_set_nbio(wsi->client_bio, 1); /* nonblocking */
|
||||
#endif
|
||||
|
||||
SSL_set_ex_data(wsi->ssl, openssl_websocket_private_data_index,
|
||||
context);
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
lws_ssl_client_connect1(struct lws *wsi)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
int n = 0;
|
||||
|
||||
lws_latency_pre(context, wsi);
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
n = SSL_connect(wsi->ssl);
|
||||
#endif
|
||||
#endif
|
||||
lws_latency(context, wsi,
|
||||
"SSL_connect LWSCM_WSCL_ISSUE_HANDSHAKE", n, n > 0);
|
||||
|
||||
if (n < 0) {
|
||||
n = lws_ssl_get_error(wsi, n);
|
||||
|
||||
if (n == SSL_ERROR_WANT_READ)
|
||||
goto some_wait;
|
||||
|
||||
if (n == SSL_ERROR_WANT_WRITE) {
|
||||
/*
|
||||
* wants us to retry connect due to
|
||||
* state of the underlying ssl layer...
|
||||
* but since it may be stalled on
|
||||
* blocked write, no incoming data may
|
||||
* arrive to trigger the retry.
|
||||
* Force (possibly many times if the SSL
|
||||
* state persists in returning the
|
||||
* condition code, but other sockets
|
||||
* are getting serviced inbetweentimes)
|
||||
* us to get called back when writable.
|
||||
*/
|
||||
lwsl_info("%s: WANT_WRITE... retrying\n", __func__);
|
||||
lws_callback_on_writable(wsi);
|
||||
some_wait:
|
||||
wsi->mode = LWSCM_WSCL_WAITING_SSL;
|
||||
|
||||
return 0; /* no error */
|
||||
}
|
||||
n = -1;
|
||||
}
|
||||
|
||||
if (n <= 0) {
|
||||
/*
|
||||
* retry if new data comes until we
|
||||
* run into the connection timeout or win
|
||||
*/
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
n = ERR_get_error();
|
||||
|
||||
if (n != SSL_ERROR_NONE) {
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
char *p = (char *)&pt->serv_buf[0];
|
||||
char *sb = p;
|
||||
lwsl_err("SSL connect error %lu: %s\n",
|
||||
n, ERR_error_string(n, sb));
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
lws_ssl_client_connect2(struct lws *wsi)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
char *p = (char *)&pt->serv_buf[0];
|
||||
char *sb = p;
|
||||
#endif
|
||||
#endif
|
||||
int n = 0;
|
||||
|
||||
if (wsi->mode == LWSCM_WSCL_WAITING_SSL) {
|
||||
lws_latency_pre(context, wsi);
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
n = SSL_connect(wsi->ssl);
|
||||
#endif
|
||||
#endif
|
||||
lws_latency(context, wsi,
|
||||
"SSL_connect LWSCM_WSCL_WAITING_SSL", n, n > 0);
|
||||
|
||||
if (n < 0) {
|
||||
n = lws_ssl_get_error(wsi, n);
|
||||
|
||||
if (n == SSL_ERROR_WANT_READ) {
|
||||
wsi->mode = LWSCM_WSCL_WAITING_SSL;
|
||||
|
||||
return 0; /* no error */
|
||||
}
|
||||
|
||||
if (n == SSL_ERROR_WANT_WRITE) {
|
||||
/*
|
||||
* wants us to retry connect due to
|
||||
* state of the underlying ssl layer...
|
||||
* but since it may be stalled on
|
||||
* blocked write, no incoming data may
|
||||
* arrive to trigger the retry.
|
||||
* Force (possibly many times if the SSL
|
||||
* state persists in returning the
|
||||
* condition code, but other sockets
|
||||
* are getting serviced inbetweentimes)
|
||||
* us to get called back when writable.
|
||||
*/
|
||||
lwsl_info("SSL_connect WANT_WRITE... retrying\n");
|
||||
lws_callback_on_writable(wsi);
|
||||
|
||||
wsi->mode = LWSCM_WSCL_WAITING_SSL;
|
||||
|
||||
return 0; /* no error */
|
||||
}
|
||||
n = -1;
|
||||
}
|
||||
|
||||
if (n <= 0) {
|
||||
/*
|
||||
* retry if new data comes until we
|
||||
* run into the connection timeout or win
|
||||
*/
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
n = ERR_get_error();
|
||||
if (n != SSL_ERROR_NONE) {
|
||||
lwsl_err("SSL connect error %lu: %s\n",
|
||||
n, ERR_error_string(n, sb));
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
#ifndef USE_WOLFSSL
|
||||
/*
|
||||
* See comment above about wolfSSL certificate
|
||||
* verification
|
||||
*/
|
||||
lws_latency_pre(context, wsi);
|
||||
n = SSL_get_verify_result(wsi->ssl);
|
||||
lws_latency(context, wsi,
|
||||
"SSL_get_verify_result LWS_CONNMODE..HANDSHAKE", n, n > 0);
|
||||
|
||||
if (n != X509_V_OK) {
|
||||
if ((n == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
|
||||
n == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) &&
|
||||
wsi->use_ssl & LCCSCF_ALLOW_SELFSIGNED) {
|
||||
lwsl_notice("accepting self-signed certificate\n");
|
||||
} else if ((n == X509_V_ERR_CERT_NOT_YET_VALID ||
|
||||
n == X509_V_ERR_CERT_HAS_EXPIRED) &&
|
||||
wsi->use_ssl & LCCSCF_ALLOW_EXPIRED) {
|
||||
lwsl_notice("accepting expired certificate\n");
|
||||
} else {
|
||||
lwsl_err("server's cert didn't look good, X509_V_ERR = %d: %s\n",
|
||||
n, ERR_error_string(n, sb));
|
||||
lws_ssl_elaborate_error();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif /* USE_WOLFSSL */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int lws_context_init_client_ssl(struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost)
|
||||
{
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
return 0;
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
SSL_METHOD *method;
|
||||
struct lws wsi;
|
||||
int error;
|
||||
int n;
|
||||
|
||||
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))
|
||||
return 0;
|
||||
|
||||
if (info->provided_client_ssl_ctx) {
|
||||
/* use the provided OpenSSL context if given one */
|
||||
vhost->ssl_client_ctx = info->provided_client_ssl_ctx;
|
||||
/* nothing for lib to delete */
|
||||
vhost->user_supplied_ssl_ctx = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info->port != CONTEXT_PORT_NO_LISTEN)
|
||||
return 0;
|
||||
|
||||
/* basic openssl init already happened in context init */
|
||||
|
||||
method = (SSL_METHOD *)TLS_client_method();
|
||||
if (!method) {
|
||||
error = ERR_get_error();
|
||||
lwsl_err("problem creating ssl method %lu: %s\n",
|
||||
error, ERR_error_string(error,
|
||||
(char *)vhost->context->pt[0].serv_buf));
|
||||
return 1;
|
||||
}
|
||||
/* create context */
|
||||
vhost->ssl_client_ctx = SSL_CTX_new(method);
|
||||
if (!vhost->ssl_client_ctx) {
|
||||
error = ERR_get_error();
|
||||
lwsl_err("problem creating ssl context %lu: %s\n",
|
||||
error, ERR_error_string(error,
|
||||
(char *)vhost->context->pt[0].serv_buf));
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef SSL_OP_NO_COMPRESSION
|
||||
SSL_CTX_set_options(vhost->ssl_client_ctx, SSL_OP_NO_COMPRESSION);
|
||||
#endif
|
||||
SSL_CTX_set_options(vhost->ssl_client_ctx,
|
||||
SSL_OP_CIPHER_SERVER_PREFERENCE);
|
||||
if (info->ssl_cipher_list)
|
||||
SSL_CTX_set_cipher_list(vhost->ssl_client_ctx,
|
||||
info->ssl_cipher_list);
|
||||
|
||||
#ifdef LWS_SSL_CLIENT_USE_OS_CA_CERTS
|
||||
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS))
|
||||
/* loads OS default CA certs */
|
||||
SSL_CTX_set_default_verify_paths(vhost->ssl_client_ctx);
|
||||
#endif
|
||||
|
||||
/* openssl init for cert verification (for client sockets) */
|
||||
if (!info->ssl_ca_filepath) {
|
||||
if (!SSL_CTX_load_verify_locations(
|
||||
vhost->ssl_client_ctx, NULL,
|
||||
LWS_OPENSSL_CLIENT_CERTS))
|
||||
lwsl_err(
|
||||
"Unable to load SSL Client certs from %s "
|
||||
"(set by --with-client-cert-dir= "
|
||||
"in configure) -- client ssl isn't "
|
||||
"going to work", LWS_OPENSSL_CLIENT_CERTS);
|
||||
} else
|
||||
if (!SSL_CTX_load_verify_locations(
|
||||
vhost->ssl_client_ctx, info->ssl_ca_filepath,
|
||||
NULL))
|
||||
lwsl_err(
|
||||
"Unable to load SSL Client certs "
|
||||
"file from %s -- client ssl isn't "
|
||||
"going to work", info->ssl_ca_filepath);
|
||||
else
|
||||
lwsl_info("loaded ssl_ca_filepath\n");
|
||||
|
||||
/*
|
||||
* callback allowing user code to load extra verification certs
|
||||
* helping the client to verify server identity
|
||||
*/
|
||||
|
||||
/* support for client-side certificate authentication */
|
||||
if (info->ssl_cert_filepath) {
|
||||
n = SSL_CTX_use_certificate_chain_file(vhost->ssl_client_ctx,
|
||||
info->ssl_cert_filepath);
|
||||
if (n != 1) {
|
||||
lwsl_err("problem getting cert '%s' %lu: %s\n",
|
||||
info->ssl_cert_filepath,
|
||||
ERR_get_error(),
|
||||
ERR_error_string(ERR_get_error(),
|
||||
(char *)vhost->context->pt[0].serv_buf));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (info->ssl_private_key_filepath) {
|
||||
lws_ssl_bind_passphrase(vhost->ssl_client_ctx, info);
|
||||
/* set the private key from KeyFile */
|
||||
if (SSL_CTX_use_PrivateKey_file(vhost->ssl_client_ctx,
|
||||
info->ssl_private_key_filepath, SSL_FILETYPE_PEM) != 1) {
|
||||
lwsl_err("use_PrivateKey_file '%s' %lu: %s\n",
|
||||
info->ssl_private_key_filepath,
|
||||
ERR_get_error(),
|
||||
ERR_error_string(ERR_get_error(),
|
||||
(char *)vhost->context->pt[0].serv_buf));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* verify private key */
|
||||
if (!SSL_CTX_check_private_key(vhost->ssl_client_ctx)) {
|
||||
lwsl_err("Private SSL key doesn't match cert\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* give him a fake wsi with context set, so he can use
|
||||
* lws_get_context() in the callback
|
||||
*/
|
||||
memset(&wsi, 0, sizeof(wsi));
|
||||
wsi.vhost = vhost;
|
||||
wsi.context = vhost->context;
|
||||
|
||||
vhost->protocols[0].callback(&wsi,
|
||||
LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS,
|
||||
vhost->ssl_client_ctx, NULL, 0);
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
442
feeds/wlan-ap/libwebsocket/src/ssl-server.c
Normal file
442
feeds/wlan-ap/libwebsocket/src/ssl-server.c
Normal file
@@ -0,0 +1,442 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#include "websocket/private-libwebsockets.h"
|
||||
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
|
||||
extern int openssl_websocket_private_data_index,
|
||||
openssl_SSL_CTX_private_data_index;
|
||||
|
||||
extern void
|
||||
lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info);
|
||||
|
||||
static int
|
||||
OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
||||
{
|
||||
SSL *ssl;
|
||||
int n;
|
||||
struct lws_vhost *vh;
|
||||
struct lws wsi;
|
||||
|
||||
ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
|
||||
SSL_get_ex_data_X509_STORE_CTX_idx());
|
||||
|
||||
/*
|
||||
* !!! nasty openssl requires the index to come as a library-scope
|
||||
* static
|
||||
*/
|
||||
vh = SSL_get_ex_data(ssl, openssl_websocket_private_data_index);
|
||||
|
||||
/*
|
||||
* give him a fake wsi with context set, so he can use lws_get_context()
|
||||
* in the callback
|
||||
*/
|
||||
memset(&wsi, 0, sizeof(wsi));
|
||||
wsi.vhost = vh;
|
||||
wsi.context = vh->context;
|
||||
|
||||
n = vh->protocols[0].callback(&wsi,
|
||||
LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION,
|
||||
x509_ctx, ssl, preverify_ok);
|
||||
|
||||
/* convert return code from 0 = OK to 1 = OK */
|
||||
return !n;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_context_ssl_init_ecdh(struct lws_vhost *vhost)
|
||||
{
|
||||
#ifdef LWS_SSL_SERVER_WITH_ECDH_CERT
|
||||
EC_KEY *EC_key = NULL;
|
||||
EVP_PKEY *pkey;
|
||||
int KeyType;
|
||||
X509 *x;
|
||||
|
||||
if (!lws_check_opt(vhost->context->options, LWS_SERVER_OPTION_SSL_ECDH))
|
||||
return 0;
|
||||
|
||||
lwsl_notice(" Using ECDH certificate support\n");
|
||||
|
||||
/* Get X509 certificate from ssl context */
|
||||
x = sk_X509_value(vhost->ssl_ctx->extra_certs, 0);
|
||||
if (!x) {
|
||||
lwsl_err("%s: x is NULL\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
/* Get the public key from certificate */
|
||||
pkey = X509_get_pubkey(x);
|
||||
if (!pkey) {
|
||||
lwsl_err("%s: pkey is NULL\n", __func__);
|
||||
|
||||
return 1;
|
||||
}
|
||||
/* Get the key type */
|
||||
KeyType = EVP_PKEY_type(pkey->type);
|
||||
|
||||
if (EVP_PKEY_EC != KeyType) {
|
||||
lwsl_notice("Key type is not EC\n");
|
||||
return 0;
|
||||
}
|
||||
/* Get the key */
|
||||
EC_key = EVP_PKEY_get1_EC_KEY(pkey);
|
||||
/* Set ECDH parameter */
|
||||
if (!EC_key) {
|
||||
lwsl_err("%s: ECDH key is NULL \n", __func__);
|
||||
return 1;
|
||||
}
|
||||
SSL_CTX_set_tmp_ecdh(vhost->ssl_ctx, EC_key);
|
||||
EC_KEY_free(EC_key);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_context_ssl_init_ecdh_curve(struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost)
|
||||
{
|
||||
#ifdef LWS_HAVE_OPENSSL_ECDH_H
|
||||
EC_KEY *ecdh;
|
||||
int ecdh_nid;
|
||||
const char *ecdh_curve = "prime256v1";
|
||||
|
||||
if (info->ecdh_curve)
|
||||
ecdh_curve = info->ecdh_curve;
|
||||
|
||||
ecdh_nid = OBJ_sn2nid(ecdh_curve);
|
||||
if (NID_undef == ecdh_nid) {
|
||||
lwsl_err("SSL: Unknown curve name '%s'", ecdh_curve);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ecdh = EC_KEY_new_by_curve_name(ecdh_nid);
|
||||
if (NULL == ecdh) {
|
||||
lwsl_err("SSL: Unable to create curve '%s'", ecdh_curve);
|
||||
return 1;
|
||||
}
|
||||
SSL_CTX_set_tmp_ecdh(vhost->ssl_ctx, ecdh);
|
||||
EC_KEY_free(ecdh);
|
||||
|
||||
SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_SINGLE_ECDH_USE);
|
||||
|
||||
lwsl_notice(" SSL ECDH curve '%s'\n", ecdh_curve);
|
||||
#else
|
||||
lwsl_notice(" OpenSSL doesn't support ECDH\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
static int
|
||||
lws_ssl_server_name_cb(SSL *ssl, int *ad, void *arg)
|
||||
{
|
||||
struct lws_context *context;
|
||||
struct lws_vhost *vhost, *vh;
|
||||
const char *servername;
|
||||
int port;
|
||||
|
||||
if (!ssl)
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
|
||||
context = (struct lws_context *)SSL_CTX_get_ex_data(
|
||||
SSL_get_SSL_CTX(ssl),
|
||||
openssl_SSL_CTX_private_data_index);
|
||||
|
||||
/*
|
||||
* We can only get ssl accepted connections by using a vhost's ssl_ctx
|
||||
* find out which listening one took us and only match vhosts on the
|
||||
* same port.
|
||||
*/
|
||||
vh = context->vhost_list;
|
||||
while (vh) {
|
||||
if (vh->ssl_ctx == SSL_get_SSL_CTX(ssl))
|
||||
break;
|
||||
vh = vh->vhost_next;
|
||||
}
|
||||
|
||||
assert(vh); /* we cannot get an ssl without using a vhost ssl_ctx */
|
||||
port = vh->listen_port;
|
||||
|
||||
servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
|
||||
|
||||
if (servername) {
|
||||
vhost = lws_select_vhost(context, port, servername);
|
||||
if (vhost) {
|
||||
lwsl_debug("SNI: Found: %s (port %d)\n",
|
||||
servername, port);
|
||||
SSL_set_SSL_CTX(ssl, vhost->ssl_ctx);
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
lwsl_err("SNI: Unknown ServerName: %s\n", servername);
|
||||
}
|
||||
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_context_init_server_ssl(struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost)
|
||||
{
|
||||
struct lws_context *context = vhost->context;
|
||||
struct lws wsi;
|
||||
int error;
|
||||
int n;
|
||||
|
||||
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) {
|
||||
vhost->use_ssl = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info->port != CONTEXT_PORT_NO_LISTEN) {
|
||||
|
||||
vhost->use_ssl = info->ssl_cert_filepath != NULL;
|
||||
|
||||
if (vhost->use_ssl && info->ssl_cipher_list)
|
||||
lwsl_notice(" SSL ciphers: '%s'\n", info->ssl_cipher_list);
|
||||
|
||||
if (vhost->use_ssl)
|
||||
lwsl_notice(" Using SSL mode\n");
|
||||
else
|
||||
lwsl_notice(" Using non-SSL mode\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* give him a fake wsi with context + vhost set, so he can use
|
||||
* lws_get_context() in the callback
|
||||
*/
|
||||
memset(&wsi, 0, sizeof(wsi));
|
||||
wsi.vhost = vhost;
|
||||
wsi.context = context;
|
||||
|
||||
(void)n;
|
||||
(void)error;
|
||||
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
lwsl_notice(" Compiled with PolarSSL support\n");
|
||||
|
||||
vhost->ssl_ctx = lws_zalloc(sizeof (*vhost->ssl_ctx));
|
||||
|
||||
/* Load the trusted CA */
|
||||
|
||||
if (info->ssl_ca_filepath) {
|
||||
n = x509_crt_parse_file(&vhost->ssl_ctx->ca,
|
||||
info->ssl_ca_filepath);
|
||||
|
||||
if (n < 0) {
|
||||
// error_strerror(ret, errorbuf, sizeof(errorbuf));
|
||||
lwsl_err("%s: Failed to load ca cert\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Load our cert */
|
||||
|
||||
if (info->ssl_cert_filepath) {
|
||||
n = x509_crt_parse_file(&vhost->ssl_ctx->certificate,
|
||||
info->ssl_cert_filepath);
|
||||
|
||||
if (n < 0) {
|
||||
// error_strerror(ret, errorbuf, sizeof(errorbuf));
|
||||
lwsl_err("%s: Failed to load cert\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Load cert private key */
|
||||
|
||||
if (info->ssl_private_key_filepath) {
|
||||
pk_context pk;
|
||||
pk_init(&pk);
|
||||
n = pk_parse_keyfile(&pk, info->ssl_private_key_filepath,
|
||||
info->ssl_private_key_password);
|
||||
|
||||
if (!n && !pk_can_do(&pk, POLARSSL_PK_RSA))
|
||||
n = POLARSSL_ERR_PK_TYPE_MISMATCH;
|
||||
|
||||
if (!n)
|
||||
rsa_copy(&vhost->ssl_ctx->key, pk_rsa(pk));
|
||||
else
|
||||
rsa_free(&vhost->ssl_ctx->key);
|
||||
pk_free(&pk);
|
||||
|
||||
if (n) {
|
||||
//error_strerror(ret, errorbuf, sizeof(errorbuf));
|
||||
lwsl_err("%s: error reading private key\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
lwsl_notice(" Compiled with mbedTLS support\n");
|
||||
#else
|
||||
|
||||
/*
|
||||
* Firefox insists on SSLv23 not SSLv3
|
||||
* Konq disables SSLv2 by default now, SSLv23 works
|
||||
*
|
||||
* SSLv23_server_method() is the openssl method for "allow all TLS
|
||||
* versions", compared to e.g. TLSv1_2_server_method() which only allows
|
||||
* tlsv1.2. Unwanted versions must be disabled using SSL_CTX_set_options()
|
||||
*/
|
||||
|
||||
{
|
||||
SSL_METHOD *method;
|
||||
|
||||
method = (SSL_METHOD *)TLS_server_method();
|
||||
if (!method) {
|
||||
error = ERR_get_error();
|
||||
lwsl_err("problem creating ssl method %lu: %s\n",
|
||||
error, ERR_error_string(error,
|
||||
(char *)context->pt[0].serv_buf));
|
||||
return 1;
|
||||
}
|
||||
vhost->ssl_ctx = SSL_CTX_new(method); /* create context */
|
||||
if (!vhost->ssl_ctx) {
|
||||
error = ERR_get_error();
|
||||
lwsl_err("problem creating ssl context %lu: %s\n",
|
||||
error, ERR_error_string(error,
|
||||
(char *)context->pt[0].serv_buf));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* associate the lws context with the SSL_CTX */
|
||||
|
||||
SSL_CTX_set_ex_data(vhost->ssl_ctx,
|
||||
openssl_SSL_CTX_private_data_index, vhost->context);
|
||||
|
||||
/* Disable SSLv2 and SSLv3 */
|
||||
SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
||||
#ifdef SSL_OP_NO_COMPRESSION
|
||||
SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_NO_COMPRESSION);
|
||||
#endif
|
||||
SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_SINGLE_DH_USE);
|
||||
SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
|
||||
if (info->ssl_cipher_list)
|
||||
SSL_CTX_set_cipher_list(vhost->ssl_ctx,
|
||||
info->ssl_cipher_list);
|
||||
|
||||
/* as a server, are we requiring clients to identify themselves? */
|
||||
|
||||
if (lws_check_opt(info->options,
|
||||
LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT)) {
|
||||
int verify_options = SSL_VERIFY_PEER;
|
||||
|
||||
if (!lws_check_opt(info->options,
|
||||
LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED))
|
||||
verify_options |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
|
||||
|
||||
SSL_CTX_set_session_id_context(vhost->ssl_ctx,
|
||||
(unsigned char *)context, sizeof(void *));
|
||||
|
||||
/* absolutely require the client cert */
|
||||
|
||||
SSL_CTX_set_verify(vhost->ssl_ctx,
|
||||
verify_options, OpenSSL_verify_callback);
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
SSL_CTX_set_tlsext_servername_callback(vhost->ssl_ctx,
|
||||
lws_ssl_server_name_cb);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* give user code a chance to load certs into the server
|
||||
* allowing it to verify incoming client certs
|
||||
*/
|
||||
|
||||
if (info->ssl_ca_filepath &&
|
||||
!SSL_CTX_load_verify_locations(vhost->ssl_ctx,
|
||||
info->ssl_ca_filepath, NULL)) {
|
||||
lwsl_err("%s: SSL_CTX_load_verify_locations unhappy\n", __func__);
|
||||
}
|
||||
|
||||
if (vhost->use_ssl) {
|
||||
if (lws_context_ssl_init_ecdh_curve(info, vhost))
|
||||
return -1;
|
||||
|
||||
vhost->protocols[0].callback(&wsi,
|
||||
LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS,
|
||||
vhost->ssl_ctx, NULL, 0);
|
||||
}
|
||||
|
||||
if (lws_check_opt(info->options, LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT))
|
||||
/* Normally SSL listener rejects non-ssl, optionally allow */
|
||||
vhost->allow_non_ssl_on_ssl_port = 1;
|
||||
|
||||
if (info->ssl_options_set)
|
||||
SSL_CTX_set_options(vhost->ssl_ctx, info->ssl_options_set);
|
||||
if (info->ssl_options_clear)
|
||||
SSL_CTX_clear_options(vhost->ssl_ctx, info->ssl_options_clear);
|
||||
|
||||
lwsl_info(" SSL options 0x%X\n",
|
||||
SSL_CTX_get_options(vhost->ssl_ctx));
|
||||
|
||||
if (vhost->use_ssl) {
|
||||
/* openssl init for server sockets */
|
||||
|
||||
/* set the local certificate from CertFile */
|
||||
n = SSL_CTX_use_certificate_chain_file(vhost->ssl_ctx,
|
||||
info->ssl_cert_filepath);
|
||||
if (n != 1) {
|
||||
error = ERR_get_error();
|
||||
lwsl_err("problem getting cert '%s' %lu: %s\n",
|
||||
info->ssl_cert_filepath,
|
||||
error,
|
||||
ERR_error_string(error,
|
||||
(char *)context->pt[0].serv_buf));
|
||||
return 1;
|
||||
}
|
||||
lws_ssl_bind_passphrase(vhost->ssl_ctx, info);
|
||||
|
||||
if (info->ssl_private_key_filepath != NULL) {
|
||||
/* set the private key from KeyFile */
|
||||
if (SSL_CTX_use_PrivateKey_file(vhost->ssl_ctx,
|
||||
info->ssl_private_key_filepath,
|
||||
SSL_FILETYPE_PEM) != 1) {
|
||||
error = ERR_get_error();
|
||||
lwsl_err("ssl problem getting key '%s' %lu: %s\n",
|
||||
info->ssl_private_key_filepath, error,
|
||||
ERR_error_string(error,
|
||||
(char *)context->pt[0].serv_buf));
|
||||
return 1;
|
||||
}
|
||||
} else
|
||||
if (vhost->protocols[0].callback(&wsi,
|
||||
LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY,
|
||||
vhost->ssl_ctx, NULL, 0)) {
|
||||
lwsl_err("ssl private key not set\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* verify private key */
|
||||
if (!SSL_CTX_check_private_key(vhost->ssl_ctx)) {
|
||||
lwsl_err("Private SSL key doesn't match cert\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (lws_context_ssl_init_ecdh(vhost))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* SSL is happy and has a cert it's content with
|
||||
* If we're supporting HTTP2, initialize that
|
||||
*/
|
||||
|
||||
lws_context_init_http2_ssl(vhost);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
694
feeds/wlan-ap/libwebsocket/src/ssl.c
Normal file
694
feeds/wlan-ap/libwebsocket/src/ssl.c
Normal file
@@ -0,0 +1,694 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#include "websocket/private-libwebsockets.h"
|
||||
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
static const int ciphers[] =
|
||||
{
|
||||
TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
|
||||
TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
0
|
||||
};
|
||||
|
||||
static int urandom_bytes(void *ctx, unsigned char *dest, size_t len)
|
||||
{
|
||||
int cur;
|
||||
int fd = open("/dev/urandom", O_RDONLY);
|
||||
|
||||
while (len) {
|
||||
cur = read(fd, dest, len);
|
||||
if (cur < 0)
|
||||
continue;
|
||||
len -= cur;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pssl_debug(void *ctx, int level, const char *str)
|
||||
{
|
||||
lwsl_err("PolarSSL [level %d]: %s", level, str);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int openssl_websocket_private_data_index,
|
||||
openssl_SSL_CTX_private_data_index;
|
||||
|
||||
int lws_ssl_get_error(struct lws *wsi, int n)
|
||||
{
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
#define ERR_error_string(a, b) ""
|
||||
return n;
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
return n;
|
||||
#else
|
||||
return SSL_get_error(wsi->ssl, n);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
lws_ssl_elaborate_error(void)
|
||||
{
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
|
||||
char buf[256];
|
||||
u_long err;
|
||||
|
||||
while ((err = ERR_get_error()) != 0) {
|
||||
ERR_error_string_n(err, buf, sizeof(buf));
|
||||
lwsl_err("*** %s\n", buf);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
static int
|
||||
lws_context_init_ssl_pem_passwd_cb(char * buf, int size, int rwflag, void *userdata)
|
||||
{
|
||||
struct lws_context_creation_info * info =
|
||||
(struct lws_context_creation_info *)userdata;
|
||||
|
||||
strncpy(buf, info->ssl_private_key_password, size);
|
||||
buf[size - 1] = '\0';
|
||||
|
||||
return strlen(buf);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void
|
||||
lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info)
|
||||
{
|
||||
if (!info->ssl_private_key_password)
|
||||
return;
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
/*
|
||||
* password provided, set ssl callback and user data
|
||||
* for checking password which will be trigered during
|
||||
* SSL_CTX_use_PrivateKey_file function
|
||||
*/
|
||||
SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, (void *)info);
|
||||
SSL_CTX_set_default_passwd_cb(ssl_ctx, lws_context_init_ssl_pem_passwd_cb);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
lws_context_init_ssl_library(struct lws_context_creation_info *info)
|
||||
{
|
||||
#ifdef USE_WOLFSSL
|
||||
#ifdef USE_OLD_CYASSL
|
||||
lwsl_notice(" Compiled with CyaSSL support\n");
|
||||
#else
|
||||
lwsl_notice(" Compiled with wolfSSL support\n");
|
||||
#endif
|
||||
#else
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
lwsl_notice(" Compiled with PolarSSL support\n");
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
lwsl_notice(" Compiled with mbedTLS support\n");
|
||||
#else
|
||||
lwsl_notice(" Compiled with OpenSSL support\n");
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) {
|
||||
lwsl_notice(" SSL disabled: no LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* basic openssl init */
|
||||
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
SSL_library_init();
|
||||
|
||||
OpenSSL_add_all_algorithms();
|
||||
SSL_load_error_strings();
|
||||
|
||||
openssl_websocket_private_data_index =
|
||||
SSL_get_ex_new_index(0, "lws", NULL, NULL, NULL);
|
||||
|
||||
openssl_SSL_CTX_private_data_index = SSL_CTX_get_ex_new_index(0,
|
||||
NULL, NULL, NULL, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_ssl_destroy(struct lws_vhost *vhost)
|
||||
{
|
||||
if (!lws_check_opt(vhost->context->options,
|
||||
LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))
|
||||
return;
|
||||
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
|
||||
if (vhost->ssl_ctx)
|
||||
SSL_CTX_free(vhost->ssl_ctx);
|
||||
if (!vhost->user_supplied_ssl_ctx && vhost->ssl_client_ctx)
|
||||
SSL_CTX_free(vhost->ssl_client_ctx);
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10100006L)
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x01000000) || defined(USE_WOLFSSL)
|
||||
ERR_remove_state(0);
|
||||
#else
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10100005L) && \
|
||||
!defined(LIBRESSL_VERSION_NUMBER) && \
|
||||
!defined(OPENSSL_IS_BORINGSSL)
|
||||
ERR_remove_thread_state();
|
||||
#else
|
||||
ERR_remove_thread_state(NULL);
|
||||
#endif
|
||||
#endif
|
||||
ERR_free_strings();
|
||||
EVP_cleanup();
|
||||
CRYPTO_cleanup_all_ex_data();
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_decode_ssl_error(void)
|
||||
{
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
char buf[256];
|
||||
u_long err;
|
||||
while ((err = ERR_get_error()) != 0) {
|
||||
ERR_error_string_n(err, buf, sizeof(buf));
|
||||
lwsl_err("*** %lu %s\n", err, buf);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
|
||||
if (!wsi->pending_read_list_prev &&
|
||||
!wsi->pending_read_list_next &&
|
||||
pt->pending_read_list != wsi)
|
||||
/* we are not on the list */
|
||||
return;
|
||||
|
||||
/* point previous guy's next to our next */
|
||||
if (!wsi->pending_read_list_prev)
|
||||
pt->pending_read_list = wsi->pending_read_list_next;
|
||||
else
|
||||
wsi->pending_read_list_prev->pending_read_list_next =
|
||||
wsi->pending_read_list_next;
|
||||
|
||||
/* point next guy's previous to our previous */
|
||||
if (wsi->pending_read_list_next)
|
||||
wsi->pending_read_list_next->pending_read_list_prev =
|
||||
wsi->pending_read_list_prev;
|
||||
|
||||
wsi->pending_read_list_prev = NULL;
|
||||
wsi->pending_read_list_next = NULL;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
int n = 0;
|
||||
|
||||
if (!wsi->ssl)
|
||||
return lws_ssl_capable_read_no_ssl(wsi, buf, len);
|
||||
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
n = SSL_read(wsi->ssl, buf, len);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* manpage: returning 0 means connection shut down */
|
||||
if (!n)
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
|
||||
if (n < 0) {
|
||||
n = lws_ssl_get_error(wsi, n);
|
||||
if (n == SSL_ERROR_WANT_READ || n == SSL_ERROR_WANT_WRITE)
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE;
|
||||
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
|
||||
if (wsi->vhost)
|
||||
wsi->vhost->rx += n;
|
||||
|
||||
lws_restart_ws_ping_pong_timer(wsi);
|
||||
|
||||
/*
|
||||
* if it was our buffer that limited what we read,
|
||||
* check if SSL has additional data pending inside SSL buffers.
|
||||
*
|
||||
* Because these won't signal at the network layer with POLLIN
|
||||
* and if we don't realize, this data will sit there forever
|
||||
*/
|
||||
if (n != len)
|
||||
goto bail;
|
||||
if (!wsi->ssl)
|
||||
goto bail;
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
if (ssl_get_bytes_avail(wsi->ssl) <= 0)
|
||||
goto bail;
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
if (!SSL_pending(wsi->ssl))
|
||||
goto bail;
|
||||
#endif
|
||||
#endif
|
||||
if (wsi->pending_read_list_next)
|
||||
return n;
|
||||
if (wsi->pending_read_list_prev)
|
||||
return n;
|
||||
if (pt->pending_read_list == wsi)
|
||||
return n;
|
||||
|
||||
/* add us to the linked list of guys with pending ssl */
|
||||
if (pt->pending_read_list)
|
||||
pt->pending_read_list->pending_read_list_prev = wsi;
|
||||
|
||||
wsi->pending_read_list_next = pt->pending_read_list;
|
||||
wsi->pending_read_list_prev = NULL;
|
||||
pt->pending_read_list = wsi;
|
||||
|
||||
return n;
|
||||
bail:
|
||||
lws_ssl_remove_wsi_from_buffered_list(wsi);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_ssl_pending(struct lws *wsi)
|
||||
{
|
||||
if (!wsi->ssl)
|
||||
return 0;
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
return ssl_get_bytes_avail(wsi->ssl) > 0;
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
return ssl_get_bytes_avail(wsi->ssl) > 0;;
|
||||
#else
|
||||
return SSL_pending(wsi->ssl);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (!wsi->ssl)
|
||||
return lws_ssl_capable_write_no_ssl(wsi, buf, len);
|
||||
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
n = ssl_write(wsi->ssl, buf, len);
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
n = SSL_write(wsi->ssl, buf, len);
|
||||
#endif
|
||||
#endif
|
||||
if (n > 0)
|
||||
return n;
|
||||
|
||||
n = lws_ssl_get_error(wsi, n);
|
||||
if (n == SSL_ERROR_WANT_READ || n == SSL_ERROR_WANT_WRITE) {
|
||||
if (n == SSL_ERROR_WANT_WRITE)
|
||||
lws_set_blocking_send(wsi);
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE;
|
||||
}
|
||||
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_ssl_close(struct lws *wsi)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (!wsi->ssl)
|
||||
return 0; /* not handled */
|
||||
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
ssl_close_notify(wsi->ssl);
|
||||
(void)n; /* we need to close the fd? */
|
||||
ssl_free(wsi->ssl);
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
n = SSL_get_fd(wsi->ssl);
|
||||
SSL_shutdown(wsi->ssl);
|
||||
compatible_close(n);
|
||||
SSL_free(wsi->ssl);
|
||||
#endif
|
||||
#endif
|
||||
wsi->ssl = NULL;
|
||||
|
||||
return 1; /* handled */
|
||||
}
|
||||
|
||||
/* leave all wsi close processing to the caller */
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
int n, m;
|
||||
#if !defined(USE_WOLFSSL) && !defined(LWS_USE_POLARSSL) && !defined(LWS_USE_MBEDTLS)
|
||||
BIO *bio;
|
||||
#endif
|
||||
|
||||
if (!LWS_SSL_ENABLED(wsi->vhost))
|
||||
return 0;
|
||||
|
||||
switch (wsi->mode) {
|
||||
case LWSCM_SSL_INIT:
|
||||
|
||||
if (wsi->ssl)
|
||||
lwsl_err("%s: leaking ssl\n", __func__);
|
||||
if (accept_fd == LWS_SOCK_INVALID)
|
||||
assert(0);
|
||||
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
{
|
||||
ssl_session *ssn;
|
||||
int rc;
|
||||
|
||||
wsi->ssl = lws_zalloc(sizeof(ssl_context));
|
||||
ssn = lws_zalloc(sizeof(ssl_session));
|
||||
|
||||
rc = ssl_init(wsi->ssl);
|
||||
if (rc) {
|
||||
lwsl_err("ssl_init failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ssl_set_endpoint(wsi->ssl, SSL_IS_SERVER);
|
||||
ssl_set_authmode(wsi->ssl, SSL_VERIFY_OPTIONAL);
|
||||
ssl_set_rng(wsi->ssl, urandom_bytes, NULL);
|
||||
ssl_set_dbg(wsi->ssl, pssl_debug, NULL);
|
||||
ssl_set_bio(wsi->ssl, net_recv, &wsi->sock, net_send, &wsi->sock);
|
||||
|
||||
ssl_set_ciphersuites(wsi->ssl, ciphers);
|
||||
|
||||
ssl_set_session(wsi->ssl, ssn);
|
||||
|
||||
ssl_set_ca_chain(wsi->ssl, &wsi->vhost->ssl_ctx->ca,
|
||||
NULL, NULL);
|
||||
|
||||
ssl_set_own_cert_rsa(wsi->ssl,
|
||||
&wsi->vhost->ssl_ctx->certificate,
|
||||
&wsi->vhost->ssl_ctx->key);
|
||||
|
||||
// ssl_set_dh_param(wsi->ssl, my_dhm_P, my_dhm_G);
|
||||
|
||||
lwsl_err("%s: polarssl init done\n", __func__);
|
||||
}
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
wsi->ssl = SSL_new(wsi->vhost->ssl_ctx);
|
||||
if (wsi->ssl == NULL) {
|
||||
lwsl_err("SSL_new failed: %s\n",
|
||||
ERR_error_string(lws_ssl_get_error(wsi, 0), NULL));
|
||||
lws_decode_ssl_error();
|
||||
if (accept_fd != LWS_SOCK_INVALID)
|
||||
compatible_close(accept_fd);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
SSL_set_ex_data(wsi->ssl,
|
||||
openssl_websocket_private_data_index, wsi->vhost);
|
||||
|
||||
SSL_set_fd(wsi->ssl, accept_fd);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_WOLFSSL
|
||||
#ifdef USE_OLD_CYASSL
|
||||
CyaSSL_set_using_nonblock(wsi->ssl, 1);
|
||||
#else
|
||||
wolfSSL_set_using_nonblock(wsi->ssl, 1);
|
||||
#endif
|
||||
#else
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
SSL_set_mode(wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||
bio = SSL_get_rbio(wsi->ssl);
|
||||
if (bio)
|
||||
BIO_set_nbio(bio, 1); /* nonblocking */
|
||||
else
|
||||
lwsl_notice("NULL rbio\n");
|
||||
bio = SSL_get_wbio(wsi->ssl);
|
||||
if (bio)
|
||||
BIO_set_nbio(bio, 1); /* nonblocking */
|
||||
else
|
||||
lwsl_notice("NULL rbio\n");
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* we are not accepted yet, but we need to enter ourselves
|
||||
* as a live connection. That way we can retry when more
|
||||
* pieces come if we're not sorted yet
|
||||
*/
|
||||
|
||||
wsi->mode = LWSCM_SSL_ACK_PENDING;
|
||||
if (insert_wsi_socket_into_fds(context, wsi)) {
|
||||
lwsl_err("%s: failed to insert into fds\n", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT,
|
||||
context->timeout_secs);
|
||||
|
||||
lwsl_info("inserted SSL accept into fds, trying SSL_accept\n");
|
||||
|
||||
/* fallthru */
|
||||
|
||||
case LWSCM_SSL_ACK_PENDING:
|
||||
|
||||
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
|
||||
lwsl_err("%s: lws_change_pollfd failed\n", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
lws_latency_pre(context, wsi);
|
||||
|
||||
n = recv(wsi->sock, (char *)pt->serv_buf, context->pt_serv_buf_size,
|
||||
MSG_PEEK);
|
||||
|
||||
/*
|
||||
* optionally allow non-SSL connect on SSL listening socket
|
||||
* This is disabled by default, if enabled it goes around any
|
||||
* SSL-level access control (eg, client-side certs) so leave
|
||||
* it disabled unless you know it's not a problem for you
|
||||
*/
|
||||
|
||||
if (wsi->vhost->allow_non_ssl_on_ssl_port) {
|
||||
if (n >= 1 && pt->serv_buf[0] >= ' ') {
|
||||
/*
|
||||
* TLS content-type for Handshake is 0x16, and
|
||||
* for ChangeCipherSpec Record, it's 0x14
|
||||
*
|
||||
* A non-ssl session will start with the HTTP
|
||||
* method in ASCII. If we see it's not a legit
|
||||
* SSL handshake kill the SSL for this
|
||||
* connection and try to handle as a HTTP
|
||||
* connection upgrade directly.
|
||||
*/
|
||||
wsi->use_ssl = 0;
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
ssl_close_notify(wsi->ssl);
|
||||
ssl_free(wsi->ssl);
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
SSL_shutdown(wsi->ssl);
|
||||
SSL_free(wsi->ssl);
|
||||
#endif
|
||||
#endif
|
||||
wsi->ssl = NULL;
|
||||
if (lws_check_opt(context->options,
|
||||
LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS))
|
||||
wsi->redirect_to_https = 1;
|
||||
goto accepted;
|
||||
}
|
||||
if (!n) /*
|
||||
* connection is gone, or nothing to read
|
||||
* if it's gone, we will timeout on
|
||||
* PENDING_TIMEOUT_SSL_ACCEPT
|
||||
*/
|
||||
break;
|
||||
if (n < 0 && (LWS_ERRNO == LWS_EAGAIN ||
|
||||
LWS_ERRNO == LWS_EWOULDBLOCK)) {
|
||||
/*
|
||||
* well, we get no way to know ssl or not
|
||||
* so go around again waiting for something
|
||||
* to come and give us a hint, or timeout the
|
||||
* connection.
|
||||
*/
|
||||
m = SSL_ERROR_WANT_READ;
|
||||
goto go_again;
|
||||
}
|
||||
}
|
||||
|
||||
/* normal SSL connection processing path */
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
n = ssl_handshake(wsi->ssl);
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
n = SSL_accept(wsi->ssl);
|
||||
#endif
|
||||
#endif
|
||||
lws_latency(context, wsi,
|
||||
"SSL_accept LWSCM_SSL_ACK_PENDING\n", n, n == 1);
|
||||
|
||||
if (n == 1)
|
||||
goto accepted;
|
||||
|
||||
m = lws_ssl_get_error(wsi, n);
|
||||
lwsl_debug("SSL_accept failed %d / %s\n",
|
||||
m, ERR_error_string(m, NULL));
|
||||
go_again:
|
||||
if (m == SSL_ERROR_WANT_READ) {
|
||||
if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
|
||||
lwsl_err("%s: WANT_READ change_pollfd failed\n", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
lwsl_info("SSL_ERROR_WANT_READ\n");
|
||||
break;
|
||||
}
|
||||
if (m == SSL_ERROR_WANT_WRITE) {
|
||||
if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) {
|
||||
lwsl_err("%s: WANT_WRITE change_pollfd failed\n", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
lwsl_err("SSL_accept failed skt %u: %s\n",
|
||||
wsi->sock, ERR_error_string(m, NULL));
|
||||
|
||||
lws_ssl_elaborate_error();
|
||||
goto fail;
|
||||
|
||||
accepted:
|
||||
/* OK, we are accepted... give him some time to negotiate */
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
|
||||
context->timeout_secs);
|
||||
|
||||
wsi->mode = LWSCM_HTTP_SERVING;
|
||||
|
||||
lws_http2_configure_if_upgraded(wsi);
|
||||
|
||||
lwsl_debug("accepted new SSL conn\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
lws_ssl_SSL_CTX_destroy(struct lws_vhost *vhost)
|
||||
{
|
||||
if (vhost->ssl_ctx) {
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
lws_free(vhost->ssl_ctx);
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
SSL_CTX_free(vhost->ssl_ctx);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
if (!vhost->user_supplied_ssl_ctx && vhost->ssl_client_ctx) {
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
lws_free(vhost->ssl_client_ctx);
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
SSL_CTX_free(vhost->ssl_client_ctx);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lws_ssl_context_destroy(struct lws_context *context)
|
||||
{
|
||||
#if defined(LWS_USE_POLARSSL)
|
||||
#else
|
||||
#if defined(LWS_USE_MBEDTLS)
|
||||
#else
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10100006L)
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x01000000) || defined(USE_WOLFSSL)
|
||||
ERR_remove_state(0);
|
||||
#else
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10100005L) && \
|
||||
!defined(LIBRESSL_VERSION_NUMBER) && \
|
||||
!defined(OPENSSL_IS_BORINGSSL)
|
||||
ERR_remove_thread_state();
|
||||
#else
|
||||
ERR_remove_thread_state(NULL);
|
||||
#endif
|
||||
#endif
|
||||
ERR_free_strings();
|
||||
EVP_cleanup();
|
||||
CRYPTO_cleanup_all_ex_data();
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@@ -30,7 +30,7 @@ endef
|
||||
define Package/opensync
|
||||
CATEGORY:=Network
|
||||
TITLE:=cloud network management system
|
||||
DEPENDS:=+libev +jansson +protobuf +libprotobuf-c +libmosquitto +libopenssl +openvswitch +libpcap +libuci +libcurl +libnl-tiny +libubus +libblobmsg-json +tcpdump +curl +lldpd +wlan-ap-keys +libradiusclient
|
||||
DEPENDS:=+libev +jansson +protobuf +libprotobuf-c +libmosquitto +libopenssl +openvswitch +libpcap +libuci +libcurl +libnl-tiny +libubus +libblobmsg-json +tcpdump +curl +lldpd +wlan-ap-keys +libradiusclient +libwebsocket
|
||||
endef
|
||||
|
||||
define Package/opensync/description
|
||||
|
||||
@@ -49,5 +49,7 @@ extern void node_config_init(void);
|
||||
extern void webserver_init(void);
|
||||
extern void crashlog_init(void);
|
||||
extern pid_t cmd_handler_crashlog(struct task *task);
|
||||
extern pid_t cmd_handler_port_forwarding(struct task *task);
|
||||
extern int port_forwarding(char *ipAddress, char *port);
|
||||
|
||||
#endif
|
||||
|
||||
2687
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/inc/libwebsockets.c
Executable file
2687
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/inc/libwebsockets.c
Executable file
File diff suppressed because it is too large
Load Diff
54
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/inc/redirclient.h
Executable file
54
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/inc/redirclient.h
Executable file
@@ -0,0 +1,54 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#ifndef _REDIRCLIENT_H_
|
||||
#define _REDIRCLIENT_H_
|
||||
|
||||
#define MAX_REDIR_CLIENTS 5
|
||||
|
||||
#define WS_PING_INTERVAL 20 // in seconds
|
||||
#define WS_RESET_LINK_INTERVAL (3*WS_PING_INTERVAL)
|
||||
#define WS_DEFAULT_PORT 7681
|
||||
#define REDIR_RCV_ARRAY_MAX 10
|
||||
|
||||
typedef struct _redirConfig
|
||||
{
|
||||
int use_mirror;
|
||||
int use_ssl;
|
||||
int port;
|
||||
int loglevel;
|
||||
unsigned int size;
|
||||
unsigned int pingsize;
|
||||
int flood;
|
||||
int clients;
|
||||
int wsLinkIsReady;
|
||||
unsigned int write_options;
|
||||
unsigned int pingIntervalSec;
|
||||
unsigned int wsResetIntervalSec;
|
||||
int ietf_version;
|
||||
int cfgDataLen;
|
||||
char *pCfgData;
|
||||
char address[30];
|
||||
char protocol_name[256];
|
||||
char urlname[30];
|
||||
char ssl_certdir[1024];
|
||||
} redirConfig;
|
||||
|
||||
typedef struct _redirStatus
|
||||
{
|
||||
int wsIsReady;
|
||||
unsigned long lastSentSec; // in seconds
|
||||
unsigned long lastRecvSec; // in seconds
|
||||
} redirStatus;
|
||||
|
||||
|
||||
extern redirConfig redircfg;
|
||||
extern redirStatus redirst;
|
||||
|
||||
extern void* redirClientTask(void *handler);
|
||||
extern int redirConfigInit( void );
|
||||
extern int redirNotifyTxMessageIsReady(struct lws_context *context, unsigned long lastSentSec);
|
||||
extern int redirWsLinkIsNotReady();
|
||||
extern void redirDisableMsgSending();
|
||||
|
||||
#endif /* _REDIRCLIENT_H_ */
|
||||
|
||||
35
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/inc/redirdebug.h
Executable file
35
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/inc/redirdebug.h
Executable file
@@ -0,0 +1,35 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#ifndef _REDIR_DEBUG_H_
|
||||
#define _REDIR_DEBUG_H_
|
||||
|
||||
#define D_NORMAL 1
|
||||
#ifdef BCM_AP_ENTERPRISE
|
||||
|
||||
#if 1
|
||||
|
||||
#include <libwcf_debug.h>
|
||||
|
||||
//#define wlog(...) wc_put_logline( (APP_LOG_REDIR | DEBUG_LEVEL_1), __VA_ARGS__ )
|
||||
//#define wdbg( level, ... ) wc_put_logline( level, __VA_ARGS__ )
|
||||
|
||||
#else
|
||||
|
||||
//#//define wlog(...) printf(__VA_ARGS__)
|
||||
//#define wdbg(level, ...)
|
||||
// if (level) printf(__VA_ARGS__)
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
//#define wlog(...) printf(__VA_ARGS__)
|
||||
//#define wdbg(level, ...)
|
||||
// if (level) printf(__VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
||||
//#define linetest() wlog("%s %d \n", __func__, __LINE__)
|
||||
|
||||
#endif
|
||||
|
||||
20
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/inc/redirintercomm.h
Executable file
20
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/inc/redirintercomm.h
Executable file
@@ -0,0 +1,20 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#ifndef _REDIRINTERCOMM_H_
|
||||
#define _REDIRINTERCOMM_H_
|
||||
|
||||
typedef struct _redirNotify {
|
||||
unsigned int seqnum;
|
||||
} redirNotify_t;
|
||||
|
||||
extern int redirInitInterComm();
|
||||
extern int redirGetReceiveFd();
|
||||
extern int redirGetWriteFd();
|
||||
extern int redirAddPOnePollFd(int fd, int events);
|
||||
extern int redirRemoveOnePollFd(int fd);
|
||||
extern int redirChangeModePollFd(int fd, int events);
|
||||
extern int redirInitializePollFd();
|
||||
extern int redirWaitforFds(struct lws_context *context, int timeout);
|
||||
|
||||
#endif /* _REDIRINTERCOMM_H_ */
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#ifndef __REDIR_MSG_DEF_H__
|
||||
#define __REDIR_MSG_DEF_H__
|
||||
|
||||
#include "redirdebug.h"
|
||||
|
||||
#define GCC_PACKED __attribute__((packed))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char msgId;
|
||||
unsigned char seqNum;
|
||||
unsigned short msgLen; // asn.1 message length
|
||||
unsigned char buf[0];
|
||||
} GCC_PACKED redirGenMsgHeader_t;
|
||||
|
||||
#endif // __REDIR_MSG_DEF_H__
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#ifndef _REDIRMSGDISPATCH_H_
|
||||
#define _REDIRMSGDISPATCH_H_
|
||||
|
||||
#define REDIR_MSG_MAX_SIZE 8192
|
||||
|
||||
typedef struct _msgDispData
|
||||
{
|
||||
int needToPing;
|
||||
int txMsgIsReady;
|
||||
unsigned char newCfgSeqCnt;
|
||||
unsigned char expectNewCfgSeq;
|
||||
|
||||
// state machine parameters.
|
||||
int absTimeToWait; // absolute time in second.
|
||||
int waitForMsg;
|
||||
int backOffTime; // in seconds.
|
||||
int waitTimedOut; // Timed out for the wait.
|
||||
int dropAllMsgBackOff; // Drop all the frames during back off time.
|
||||
|
||||
int wsIsReady; // web socket is ready.
|
||||
int applyFailedNum;
|
||||
|
||||
int applyNewCfgFailedNum;
|
||||
unsigned char smSeqCnt;
|
||||
unsigned char expectSeq; //expected seqNum from Response message.
|
||||
|
||||
} msgDispData_t;
|
||||
|
||||
|
||||
extern msgDispData_t gmsgdd;
|
||||
|
||||
extern int redirOpenRedirSocket( unsigned short Port );
|
||||
extern void redirCloseRedirSocket( void );
|
||||
extern void redirMessageRedirect( unsigned char * Msg, size_t Len );
|
||||
extern void* redirMsgDispatchTaskFunc(void *x_void_ptr);
|
||||
extern int redirNotifyWebSocketIsReady();
|
||||
|
||||
|
||||
#endif /* _REDIRMSGDISPATCH_H_ */
|
||||
31
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/inc/redirtask.h
Executable file
31
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/inc/redirtask.h
Executable file
@@ -0,0 +1,31 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#ifndef _REDIRTASK_H_
|
||||
#define _REDIRTASK_H_
|
||||
|
||||
#define REDIR_MAX_TASKS 50
|
||||
#define REDIR_TASK_ID_BASE 0x10000000
|
||||
|
||||
typedef unsigned long Address;
|
||||
|
||||
typedef struct _redirTask
|
||||
{
|
||||
struct _redirTask *nextFreeTask; // pointer to the next redirTask entry
|
||||
int entryId; // Unique ID for this entry. We could add type to it if needed.
|
||||
int allocated; // Whether this entry is used or not.
|
||||
char name[16]; // Name of the pthread.
|
||||
unsigned priority;
|
||||
pthread_t threadSelf; // The pthread that is associated with this entry.
|
||||
pthread_attr_t threadAttr;
|
||||
void (*taskFunc)(void); // The start routine what runs in the pthread.
|
||||
} redirTask;
|
||||
|
||||
extern redirTask* allocTaskFromPool();
|
||||
extern void releaseTaskBackToPool(redirTask *pTask);
|
||||
extern int createOneTask(Address taskFunc, char *Name, int *taskId);
|
||||
extern int redirInitTasks();
|
||||
extern void waitForOtherTaskesToFinish();
|
||||
|
||||
|
||||
#endif /* _REDIRTASK_H_ */
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#include <libubox/list.h>
|
||||
#include <evsched.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include "command.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
static void cmd_handler_port_forwarding_cb(struct ev_loop *loop, ev_child *child, int revents)
|
||||
{
|
||||
struct task *task = container_of(child, struct task, child);
|
||||
|
||||
ev_child_stop(loop, child);
|
||||
task_status(task, TASK_COMPLETE, NULL);
|
||||
}
|
||||
|
||||
pid_t cmd_handler_port_forwarding(struct task *task)
|
||||
{
|
||||
char *gateway = NULL;
|
||||
char *port = NULL;
|
||||
pid_t pid;
|
||||
|
||||
gateway = SCHEMA_KEY_VAL(task->conf.payload, "gateway_hostname");
|
||||
port = SCHEMA_KEY_VAL(task->conf.payload, "gateway_port");
|
||||
|
||||
LOG(ERR, "gateway : %s , port: %s ", gateway, port);
|
||||
pid = fork();
|
||||
if (pid == 0) {
|
||||
port_forwarding(gateway, port);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pid < 0) {
|
||||
LOG(ERR, "portforwarding, failed to fork");
|
||||
task_status(task, TASK_FAILED, "forking portforwarding failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ev_child_init(&task->child, cmd_handler_port_forwarding_cb, pid, 0);
|
||||
ev_child_start(EV_DEFAULT, &task->child);
|
||||
|
||||
LOGN("portforwarding: started");
|
||||
return pid;
|
||||
}
|
||||
1216
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/src/libwcf_devif.c
Executable file
1216
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/src/libwcf_devif.c
Executable file
File diff suppressed because it is too large
Load Diff
747
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/src/redirclient.c
Executable file
747
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/src/redirclient.c
Executable file
@@ -0,0 +1,747 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#ifdef CMAKE_BUILD
|
||||
#include <websocket/lws_config.h>
|
||||
#endif
|
||||
#include <websocket/libwebsockets.h>
|
||||
#include <libwebsockets.c>
|
||||
|
||||
#include "redirclient.h"
|
||||
#include "redirintercomm.h"
|
||||
#include "redirmessagedef.h"
|
||||
#include "redirmsgdispatch.h"
|
||||
|
||||
#define REDIR_BUFF_MAX 200
|
||||
|
||||
|
||||
typedef struct redirBufDes_s
|
||||
{
|
||||
int isValid;
|
||||
int size;
|
||||
unsigned char * pBuf;
|
||||
}redirBufDes_t;
|
||||
|
||||
typedef struct redirBufferPool_s
|
||||
{
|
||||
pthread_mutex_t txBufLock;
|
||||
pthread_mutex_t rxBufLock;
|
||||
int numBuf;
|
||||
redirBufDes_t bufTxDes[REDIR_BUFF_MAX];
|
||||
redirBufDes_t bufRxDes[REDIR_BUFF_MAX];
|
||||
} redirBufferPool_t;
|
||||
|
||||
|
||||
redirBufferPool_t commBuf;
|
||||
|
||||
struct list_head
|
||||
{
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
|
||||
static LIST_HEAD( redirMsgHd );
|
||||
|
||||
struct redirTxMsg
|
||||
{
|
||||
struct list_head pend;
|
||||
int size;
|
||||
unsigned char * pBuf;
|
||||
};
|
||||
|
||||
static inline void __list_add( struct list_head *new,
|
||||
struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
next->prev = new;
|
||||
new->next = next;
|
||||
new->prev = prev;
|
||||
prev->next = new;
|
||||
}
|
||||
|
||||
static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head->prev, head);
|
||||
}
|
||||
|
||||
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof(((type *)0)->member) * __mptr = (ptr); \
|
||||
(type *)((char *)__mptr - offsetof(type, member)); })
|
||||
|
||||
#define list_entry(ptr, type, member) \
|
||||
container_of(ptr, type, member)
|
||||
|
||||
|
||||
static inline void __list_del(struct list_head * prev, struct list_head * next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
static inline void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
}
|
||||
|
||||
static inline int list_empty(const struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
|
||||
#define list_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
|
||||
|
||||
// global configuration
|
||||
redirConfig redircfg;
|
||||
redirStatus redirst;
|
||||
|
||||
int RedirWsTxErr = 0;
|
||||
|
||||
/*
|
||||
* this is specified in the 04 standard, control frames can only have small
|
||||
* payload length styles
|
||||
*/
|
||||
#define MAX_PING_PAYLOAD 125
|
||||
#define MAX_REDIR_PAYLOAD 8192
|
||||
|
||||
#define PING_RINGBUFFER_SIZE 256
|
||||
|
||||
struct lws * redir_wsi[MAX_REDIR_CLIENTS];
|
||||
static unsigned char pingbuf[LWS_PRE + MAX_REDIR_PAYLOAD];
|
||||
static char peer_name[128];
|
||||
static unsigned long started;
|
||||
|
||||
static unsigned long rtt_min = 100000000;
|
||||
static unsigned long rtt_max;
|
||||
static unsigned long rtt_avg;
|
||||
static unsigned long global_rx_count;
|
||||
static unsigned long global_tx_count;
|
||||
|
||||
struct ping {
|
||||
unsigned long issue_timestamp;
|
||||
unsigned long index;
|
||||
unsigned int seen;
|
||||
};
|
||||
|
||||
struct per_session_data__ping {
|
||||
unsigned long ping_index;
|
||||
|
||||
struct ping ringbuffer[PING_RINGBUFFER_SIZE];
|
||||
int ringbuffer_head;
|
||||
int ringbuffer_tail;
|
||||
|
||||
unsigned long rx_count;
|
||||
};
|
||||
|
||||
|
||||
int redirAddOneTxBuffToPool( unsigned char * Buffer, unsigned int len )
|
||||
{
|
||||
int i;
|
||||
int found = 0;
|
||||
|
||||
pthread_mutex_lock( &commBuf.txBufLock );
|
||||
for( i=0; i<commBuf.numBuf; i++ )
|
||||
{
|
||||
if( commBuf.bufTxDes[i].isValid == 0 )
|
||||
{
|
||||
commBuf.bufTxDes[i].pBuf = Buffer;
|
||||
commBuf.bufTxDes[i].isValid = 1;
|
||||
commBuf.bufTxDes[i].size = len;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( found )
|
||||
gmsgdd.txMsgIsReady = 1;
|
||||
else
|
||||
{
|
||||
free( Buffer );
|
||||
}
|
||||
pthread_mutex_unlock( &commBuf.txBufLock );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int redirLinkClientMsgWritableHandler( struct lws *wsi, struct per_session_data__ping *psd, unsigned char *buff, int len)
|
||||
{
|
||||
int n;
|
||||
unsigned char * p;
|
||||
|
||||
p = &pingbuf[LWS_PRE];
|
||||
|
||||
memcpy(p, buff, len);
|
||||
|
||||
global_tx_count++;
|
||||
|
||||
n = lws_write(wsi, &pingbuf[LWS_PRE],
|
||||
len, redircfg.write_options | LWS_WRITE_BINARY);
|
||||
|
||||
if( n < 0 )
|
||||
{
|
||||
RedirWsTxErr = 1;
|
||||
return -1;
|
||||
}
|
||||
if (n < len) {
|
||||
lwsl_err("Partial write\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int redirLinkClientPongReceiveHandler(struct lws *wsi, struct per_session_data__ping *psd, void *in,
|
||||
size_t len)
|
||||
{
|
||||
struct timespec tv;
|
||||
unsigned char *p;
|
||||
int shift, n;
|
||||
unsigned long l;
|
||||
int match = 0;
|
||||
unsigned long iv;
|
||||
|
||||
|
||||
clock_gettime( CLOCK_MONOTONIC, &tv );
|
||||
iv = (tv.tv_sec * 1000000) + tv.tv_nsec/1000;
|
||||
|
||||
psd->rx_count++;
|
||||
|
||||
shift = 56;
|
||||
p = in;
|
||||
l = 0;
|
||||
|
||||
while (shift >= 0) {
|
||||
l |= (*p++) << shift;
|
||||
shift -= 8;
|
||||
}
|
||||
|
||||
/* find it in the ringbuffer, look backwards from head */
|
||||
n = psd->ringbuffer_head;
|
||||
while (!match) {
|
||||
|
||||
if (psd->ringbuffer[n].index == l) {
|
||||
psd->ringbuffer[n].seen++;
|
||||
match = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n == psd->ringbuffer_tail) {
|
||||
match = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n == 0)
|
||||
n = PING_RINGBUFFER_SIZE - 1;
|
||||
else
|
||||
n--;
|
||||
}
|
||||
|
||||
if (match < 1) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (psd->ringbuffer[n].seen > 1)
|
||||
//wlog("DUP! ");
|
||||
|
||||
if ((iv - psd->ringbuffer[n].issue_timestamp) < rtt_min)
|
||||
rtt_min = iv - psd->ringbuffer[n].issue_timestamp;
|
||||
|
||||
if ((iv - psd->ringbuffer[n].issue_timestamp) > rtt_max)
|
||||
rtt_max = iv - psd->ringbuffer[n].issue_timestamp;
|
||||
|
||||
rtt_avg += iv - psd->ringbuffer[n].issue_timestamp;
|
||||
global_rx_count++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int redirLinkClientMsgReceiveHandler( struct lws * wsi, struct per_session_data__ping * psd, void * in,
|
||||
size_t len )
|
||||
{
|
||||
int tlen;
|
||||
unsigned char * CharBuf;
|
||||
|
||||
psd->rx_count++;
|
||||
|
||||
tlen = len;
|
||||
if( tlen > REDIR_MSG_MAX_SIZE )
|
||||
tlen = REDIR_MSG_MAX_SIZE;
|
||||
|
||||
CharBuf = (unsigned char *)in;
|
||||
|
||||
if( strstr( (char *)CharBuf, "connect_to_CE_port" ) )
|
||||
{
|
||||
redirOpenRedirSocket( 22 );
|
||||
return( 0 );
|
||||
}
|
||||
if( strstr( (char *)CharBuf, "disconnect_from_CE_port" ) )
|
||||
{
|
||||
redirCloseRedirSocket( );
|
||||
return( 0 );
|
||||
}
|
||||
if( (*(CharBuf+0) == 0) && (*(CharBuf+1) == 0) )
|
||||
{
|
||||
redirMessageRedirect( CharBuf+4, tlen-4 );
|
||||
return( 0 );
|
||||
}
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
||||
void redirInitLastReceivedTime()
|
||||
{
|
||||
struct timespec tv;
|
||||
|
||||
clock_gettime( CLOCK_MONOTONIC, &tv );
|
||||
redirst.lastRecvSec = tv.tv_sec;
|
||||
}
|
||||
|
||||
|
||||
void redirUpdateLastReceivedTime()
|
||||
{
|
||||
struct timespec tv;
|
||||
static int cnt = 0;
|
||||
|
||||
cnt++;
|
||||
#if 1
|
||||
clock_gettime( CLOCK_MONOTONIC, &tv );
|
||||
redirst.lastRecvSec = tv.tv_sec;
|
||||
#else
|
||||
if (cnt >= 7 && cnt <= 17) {
|
||||
;
|
||||
} else {
|
||||
gettimeofday(&tv, NULL);
|
||||
redirst.lastRecvSec = tv.tv_sec;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int callback_redir_link(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
int n;
|
||||
struct per_session_data__ping *psd = user;
|
||||
struct lws_pollargs *pa = (struct lws_pollargs *)in;
|
||||
//struct timeval tv;
|
||||
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_CLOSED:
|
||||
/* remove closed guy */
|
||||
for (n = 0; n < redircfg.clients; n++)
|
||||
if (redir_wsi[n] == wsi) {
|
||||
redircfg.clients--;
|
||||
while (n < redircfg.clients) {
|
||||
redir_wsi[n] = redir_wsi[n + 1];
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_ESTABLISHED:
|
||||
psd->rx_count = 0;
|
||||
psd->ping_index = 1;
|
||||
psd->ringbuffer_head = 0;
|
||||
psd->ringbuffer_tail = 0;
|
||||
|
||||
/*
|
||||
* start the ball rolling,
|
||||
* LWS_CALLBACK_CLIENT_WRITEABLE will come next service
|
||||
*/
|
||||
|
||||
lws_callback_on_writable( wsi);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_RECEIVE:
|
||||
case LWS_CALLBACK_CLIENT_RECEIVE_PONG:
|
||||
redirUpdateLastReceivedTime();
|
||||
if (reason == LWS_CALLBACK_CLIENT_RECEIVE) {
|
||||
redirLinkClientMsgReceiveHandler( wsi, psd, in, len);
|
||||
} else {
|
||||
redirLinkClientPongReceiveHandler( wsi, psd, in, len);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_WRITEABLE:
|
||||
if( lws_partial_buffered( wsi ) )
|
||||
{
|
||||
//wlog( "******************************** writable, wait for nexttime \n" );
|
||||
lws_callback_on_writable( wsi );
|
||||
break;
|
||||
}
|
||||
if( gmsgdd.txMsgIsReady )
|
||||
{
|
||||
int done, i;
|
||||
redirBufDes_t tmpBTD[REDIR_BUFF_MAX];
|
||||
|
||||
pthread_mutex_lock( &(commBuf.txBufLock) );
|
||||
memcpy( tmpBTD, commBuf.bufTxDes, sizeof( commBuf.bufTxDes ) );
|
||||
memset( commBuf.bufTxDes, '\0', sizeof( commBuf.bufTxDes ) );
|
||||
pthread_mutex_unlock( &(commBuf.txBufLock) );
|
||||
|
||||
// construct the linked list
|
||||
for( i = 0; i < REDIR_BUFF_MAX; i++ )
|
||||
{
|
||||
if( tmpBTD[i].isValid )
|
||||
{
|
||||
struct redirTxMsg * ctm = calloc( 1, sizeof( struct redirTxMsg ) );
|
||||
ctm->pBuf = tmpBTD[i].pBuf;
|
||||
ctm->size = tmpBTD[i].size;
|
||||
list_add_tail(&ctm->pend, &redirMsgHd);
|
||||
//wlog( "===www adding to list %d", ctm->size );
|
||||
}
|
||||
}
|
||||
|
||||
// now to send the list
|
||||
done = 1;
|
||||
{
|
||||
struct list_head *p, *n;
|
||||
struct redirTxMsg *ctm;
|
||||
|
||||
list_for_each_safe(p, n, &redirMsgHd)
|
||||
{
|
||||
ctm = list_entry(p, struct redirTxMsg, pend);
|
||||
|
||||
//wlog("*** send client msg cnt %d pbuf %p\n", cnt, ctm->pBuf);
|
||||
//wlog( "===www processing from list %d", ctm->size );
|
||||
redirLinkClientMsgWritableHandler( wsi, psd, ctm->pBuf, ctm->size );
|
||||
//wlog("--- send client msg cnt %d done\n", cnt);
|
||||
|
||||
list_del(&ctm->pend);
|
||||
free(ctm->pBuf);
|
||||
free(ctm);
|
||||
|
||||
if (lws_partial_buffered(wsi))
|
||||
{
|
||||
//wlog("***** skip rest messages for this time\n");
|
||||
lws_callback_on_writable( wsi);
|
||||
done = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( done )
|
||||
gmsgdd.txMsgIsReady = 0;
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
case LWS_CALLBACK_CLIENT_WRITEABLE:
|
||||
gettimeofday(&tv, NULL);
|
||||
redirst.lastSentSec = tv.tv_sec;
|
||||
//wlog("send ws frame, lastSentUs updated %ld sec \n", tv.tv_sec);
|
||||
if (gmsgdd.needToPing) {
|
||||
gmsgdd.needToPing = 0;
|
||||
redirLinkClientPingWritableHandler(this, wsi, psd);
|
||||
}
|
||||
if (gmsgdd.txMsgIsReady) {
|
||||
int i;
|
||||
int idx = 1;
|
||||
redirBufDes_t tmpBTD[REDIR_BUFF_MAX];
|
||||
redirGetAndClearAllTxBufDescritors(redircfg.rcvArray[idx].pBP, tmpBTD);
|
||||
for (i=0; i<REDIR_BUFF_MAX; i++ ) {
|
||||
if (tmpBTD[i].isValid) {
|
||||
redirLinkClientMsgWritableHandler(this, wsi, psd, tmpBTD[i].pBuf);
|
||||
free(tmpBTD[i].pBuf);
|
||||
} else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
gmsgdd.txMsgIsReady = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
|
||||
//wlog("LWS_CALLBACK_CLIENT_CONNECTION_ERROR **********************\n");
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_ADD_POLL_FD:
|
||||
redirAddPOnePollFd(pa->fd, pa->events);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_DEL_POLL_FD:
|
||||
redirRemoveOnePollFd(pa->fd);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CHANGE_MODE_POLL_FD:
|
||||
redirChangeModePollFd(pa->fd, pa->events);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* list of supported protocols and callbacks */
|
||||
|
||||
static struct lws_protocols protocols[] = {
|
||||
{
|
||||
"redir-link-protocol", callback_redir_link,
|
||||
sizeof(struct per_session_data__ping), 0, 0, NULL
|
||||
},
|
||||
{
|
||||
NULL, NULL, 0, 0, 0, NULL /* end of list */
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int redirNotifyTxMessageIsReady(struct lws_context *context, unsigned long lastSentSec)
|
||||
{
|
||||
int n;
|
||||
struct timespec tv;
|
||||
|
||||
if( lastSentSec == 0 )
|
||||
{
|
||||
clock_gettime( CLOCK_MONOTONIC, &tv );
|
||||
lastSentSec = tv.tv_sec;
|
||||
}
|
||||
|
||||
for( n = 0; n < redircfg.clients; n++ )
|
||||
lws_callback_on_writable( redir_wsi[n] );
|
||||
redirst.lastSentSec = lastSentSec;
|
||||
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
static const struct lws_extension exts[] = {
|
||||
{
|
||||
"permessage-deflate",
|
||||
lws_extension_callback_pm_deflate,
|
||||
"permessage-deflate; client_no_context_takeover; client_max_window_bits"
|
||||
},
|
||||
{
|
||||
"deflate-frame",
|
||||
lws_extension_callback_pm_deflate,
|
||||
"deflate_frame"
|
||||
},
|
||||
{ NULL, NULL, NULL /* terminator */ }
|
||||
};
|
||||
|
||||
|
||||
static int redirStartWebSocketConnection( struct lws_context_creation_info * pInfo )
|
||||
{
|
||||
struct lws_context * context;
|
||||
char ip[30];
|
||||
struct timespec tv;
|
||||
int n;
|
||||
unsigned long l;
|
||||
//int rc = 0;
|
||||
int ret = 0;
|
||||
struct lws_client_connect_info i;
|
||||
|
||||
|
||||
redircfg.clients = 1;
|
||||
|
||||
context = lws_create_context( pInfo );
|
||||
if( context == NULL )
|
||||
{
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
i.context = context;
|
||||
i.address = redircfg.address;
|
||||
i.port = redircfg.port;
|
||||
i.ssl_connection = redircfg.use_ssl;
|
||||
i.path = redircfg.urlname;
|
||||
i.origin = "origin";
|
||||
i.protocol = protocols[0].name;
|
||||
i.client_exts = exts;
|
||||
i.host = i.address;
|
||||
i.ietf_version_or_minus_one = redircfg.ietf_version;
|
||||
|
||||
do
|
||||
{
|
||||
redir_wsi[0] = lws_client_connect_via_info(&i);
|
||||
if (redir_wsi[0] == NULL)
|
||||
{
|
||||
printf( "cmClient failed to connect\n" );
|
||||
sleep( 5 );
|
||||
// return NULL;
|
||||
}
|
||||
} while( redir_wsi[0] == NULL );
|
||||
|
||||
|
||||
memset( peer_name, '\0', sizeof( peer_name ) );
|
||||
|
||||
if( redir_wsi[0] )
|
||||
{
|
||||
lws_get_peer_addresses( redir_wsi[0], lws_get_socket_fd(redir_wsi[0]), peer_name,
|
||||
sizeof( peer_name ), ip, sizeof( ip ) );
|
||||
}
|
||||
|
||||
clock_gettime( CLOCK_MONOTONIC, &tv );
|
||||
started = (tv.tv_sec * 1000000) + tv.tv_nsec/1000;
|
||||
|
||||
redircfg.wsLinkIsReady = 1;
|
||||
redirNotifyWebSocketIsReady( );
|
||||
redirInitLastReceivedTime( );
|
||||
/* service loop */
|
||||
n = 0;
|
||||
|
||||
while( n >= 0 )
|
||||
{
|
||||
clock_gettime( CLOCK_MONOTONIC, &tv );
|
||||
l = tv.tv_sec;
|
||||
|
||||
/* servers can hang up on us */
|
||||
if (redircfg.clients == 0) {
|
||||
n = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( RedirWsTxErr )
|
||||
{
|
||||
n = -4;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (l- redirst.lastRecvSec > redircfg.wsResetIntervalSec) {
|
||||
n = -3;
|
||||
redirDisableMsgSending();
|
||||
continue;
|
||||
}
|
||||
if ((l - redirst.lastSentSec) > redircfg.pingIntervalSec) {
|
||||
gmsgdd.needToPing = 1;
|
||||
redirNotifyTxMessageIsReady( context, l );
|
||||
}
|
||||
|
||||
/*
|
||||
* this represents an existing server's single poll action
|
||||
* which also includes libwebsocket sockets
|
||||
*/
|
||||
redirWaitforFds( context, 2000 );
|
||||
}
|
||||
|
||||
/* stats */
|
||||
redircfg.wsLinkIsReady = 0;
|
||||
lws_context_destroy( context );
|
||||
ret = n;
|
||||
return( ret );
|
||||
}
|
||||
|
||||
|
||||
void * redirClientTask( void * handler )
|
||||
{
|
||||
struct lws_context_creation_info info;
|
||||
char ca_filepath[1032];
|
||||
char cert_filepath[1035];
|
||||
char key_filepath[1039];
|
||||
FILE *fptr;
|
||||
|
||||
memset( &info, 0, sizeof info );
|
||||
memset( &commBuf, 0, sizeof( commBuf ) );
|
||||
pthread_mutex_init( &(commBuf.txBufLock), NULL );
|
||||
pthread_mutex_init( &(commBuf.rxBufLock), NULL );
|
||||
commBuf.numBuf = REDIR_BUFF_MAX;
|
||||
|
||||
redirInitializePollFd( );
|
||||
|
||||
info.port = CONTEXT_PORT_NO_LISTEN;
|
||||
info.protocols = protocols;
|
||||
info.extensions = exts;
|
||||
if( redircfg.use_ssl )
|
||||
{
|
||||
fprintf( stderr, "use_ssl %d (%s) \n", redircfg.use_ssl, redircfg.ssl_certdir );
|
||||
{
|
||||
snprintf( ca_filepath, sizeof( ca_filepath ), "%s/%s", redircfg.ssl_certdir, "ca.pem" ); //ca.crt
|
||||
snprintf( cert_filepath, sizeof( cert_filepath ), "%s/%s", redircfg.ssl_certdir, "client.pem" ); //client.crt
|
||||
snprintf( key_filepath, sizeof( key_filepath ), "%s/%s", redircfg.ssl_certdir, "client_dec.key" ); //client.key
|
||||
fprintf( stderr, "use pathhhhh %s \n", ca_filepath );
|
||||
}
|
||||
info.ssl_ca_filepath = ca_filepath;
|
||||
info.ssl_cert_filepath = cert_filepath;
|
||||
info.ssl_private_key_filepath = key_filepath;
|
||||
}
|
||||
info.gid = -1;
|
||||
info.uid = -1;
|
||||
|
||||
if( redircfg.use_ssl )
|
||||
{
|
||||
info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||
fptr = fopen( ca_filepath, "r" );
|
||||
if( fptr != NULL )
|
||||
{
|
||||
fclose( fptr );
|
||||
|
||||
do
|
||||
{
|
||||
if( redirStartWebSocketConnection( &info ) < 0 )
|
||||
break;
|
||||
} while( 1 );
|
||||
}
|
||||
else
|
||||
printf("No certificate files present \n");
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
if( redirStartWebSocketConnection( &info ) < 0 )
|
||||
break;
|
||||
} while( 1 );
|
||||
}
|
||||
printf("exiting websockets\n");
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
int redirConfigInit( void )
|
||||
{
|
||||
memset( &redircfg, '\0', sizeof( redircfg ) );
|
||||
|
||||
redircfg.port = WS_DEFAULT_PORT;
|
||||
redircfg.pingIntervalSec = WS_PING_INTERVAL;
|
||||
redircfg.wsResetIntervalSec = WS_RESET_LINK_INTERVAL;
|
||||
redircfg.size = 64;
|
||||
redircfg.pingsize = MAX_PING_PAYLOAD;
|
||||
redircfg.flood = 0;
|
||||
redircfg.wsLinkIsReady = 0;
|
||||
redircfg.clients = 1;
|
||||
redircfg.ietf_version = -1;
|
||||
strcpy( redircfg.urlname, "/" );
|
||||
|
||||
memset( &redirst, '\0', sizeof( redirst ) );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
||||
int redirWsLinkIsNotReady()
|
||||
{
|
||||
return( !redircfg.wsLinkIsReady );
|
||||
}
|
||||
|
||||
|
||||
void redirDisableMsgSending()
|
||||
{
|
||||
redircfg.wsLinkIsReady = 0;
|
||||
}
|
||||
|
||||
160
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/src/redirintercomm.c
Executable file
160
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/src/redirintercomm.c
Executable file
@@ -0,0 +1,160 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#ifdef CMAKE_BUILD
|
||||
#include <lws_config.h>
|
||||
#endif
|
||||
|
||||
#include <websocket/libwebsockets.h>
|
||||
#include "redirtask.h"
|
||||
#include "redirclient.h"
|
||||
#include "redirmessagedef.h"
|
||||
#include "redirintercomm.h"
|
||||
#include "redirmsgdispatch.h"
|
||||
|
||||
int max_poll_elements;
|
||||
struct pollfd *pollfds;
|
||||
int *fd_lookup;
|
||||
int count_pollfds;
|
||||
|
||||
static int fd[2];
|
||||
|
||||
int redirInitInterComm()
|
||||
{
|
||||
pipe(fd);
|
||||
max_poll_elements = getdtablesize();
|
||||
pollfds = malloc(max_poll_elements * sizeof(struct pollfd));
|
||||
fd_lookup = malloc(max_poll_elements * sizeof(int));
|
||||
if (pollfds == NULL || fd_lookup == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int redirGetReceiveFd()
|
||||
{
|
||||
return fd[0];
|
||||
}
|
||||
|
||||
int redirGetWriteFd()
|
||||
{
|
||||
return fd[1];
|
||||
}
|
||||
|
||||
static unsigned int cnSendSeqNum = 0;
|
||||
|
||||
int redirSendNotification( redirNotify_t * cNotify )
|
||||
{
|
||||
ssize_t ret;
|
||||
int wfd = -1;
|
||||
|
||||
cNotify->seqnum = cnSendSeqNum++;
|
||||
wfd = redirGetWriteFd();
|
||||
ret = write( wfd, cNotify, sizeof( redirNotify_t ) );
|
||||
if( ret < 0 )
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int redirReceiveNotificationFromOtherEngines(struct lws_context *context, int rfd)
|
||||
{
|
||||
char readbuffer[200];
|
||||
|
||||
read(rfd, readbuffer, sizeof(readbuffer));
|
||||
redirNotifyTxMessageIsReady(context, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int redirAddPOnePollFd(int fd, int events)
|
||||
{
|
||||
if (count_pollfds >= max_poll_elements) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd_lookup[fd] = count_pollfds;
|
||||
pollfds[count_pollfds].fd = fd;
|
||||
pollfds[count_pollfds].events = events;
|
||||
pollfds[count_pollfds++].revents = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int redirRemoveOnePollFd(int fd)
|
||||
{
|
||||
int temp;
|
||||
|
||||
if (--count_pollfds <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
temp = fd_lookup[fd];
|
||||
/* have the last guy take up the vacant slot */
|
||||
pollfds[temp] = pollfds[count_pollfds];
|
||||
fd_lookup[pollfds[count_pollfds].fd] = temp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int redirChangeModePollFd(int fd, int events)
|
||||
{
|
||||
pollfds[fd_lookup[fd]].events = events;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int redirInitializePollFd()
|
||||
{
|
||||
int rfd = -1;
|
||||
|
||||
rfd = redirGetReceiveFd();
|
||||
fd_lookup[rfd] = count_pollfds;
|
||||
pollfds[count_pollfds].fd = rfd;
|
||||
pollfds[count_pollfds].events = POLLIN;
|
||||
pollfds[count_pollfds++].revents = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int redirWaitforFds(struct lws_context *context, int timeout)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
// wait for 5 seconds.
|
||||
n = poll(pollfds, count_pollfds, timeout);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
|
||||
if (n) {
|
||||
if (pollfds[0].revents & POLLIN) {
|
||||
redirReceiveNotificationFromOtherEngines(context, pollfds[0].fd);
|
||||
}
|
||||
}
|
||||
|
||||
for (n = 1; n < count_pollfds; n++) {
|
||||
if (pollfds[n].revents) {
|
||||
/*
|
||||
* returns immediately if the fd does not
|
||||
* match anything under libwebsockets
|
||||
* control
|
||||
*/
|
||||
if (lws_service_fd(context, &pollfds[n]) < 0) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
106
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/src/redirmain.c
Executable file
106
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/src/redirmain.c
Executable file
@@ -0,0 +1,106 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <websocket/libwebsockets.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include "command.h"
|
||||
#include "redirdebug.h"
|
||||
#include "redirtask.h"
|
||||
#include "redirclient.h"
|
||||
#include "redirintercomm.h"
|
||||
#include "redirmsgdispatch.h"
|
||||
#include "websocket/libwcf.h"
|
||||
|
||||
|
||||
static int redirInit( void )
|
||||
{
|
||||
if( redirInitInterComm( ) < 0 )
|
||||
return( 0 );
|
||||
|
||||
if( redirInitTasks( ) < 0 )
|
||||
{
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int port_forwarding(char *ipAddress, char *port)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *result;
|
||||
int s;
|
||||
int waitForAddrInfo = 1;
|
||||
int waitForCnt = 0;
|
||||
int taskIds[REDIR_MAX_TASKS];
|
||||
|
||||
memset( taskIds, 0, sizeof( taskIds ) );
|
||||
wc_set_socket( );
|
||||
redirConfigInit( );
|
||||
|
||||
strcpy( redircfg.address, ipAddress);
|
||||
redircfg.port = atoi(port);
|
||||
redircfg.use_ssl = 1;
|
||||
strncpy(redircfg.ssl_certdir, "/usr/opensync/certs/", sizeof( redircfg.ssl_certdir )-1); /* copy the root directory of the certificate */
|
||||
redircfg.ssl_certdir[sizeof( redircfg.ssl_certdir )-1] = '\0';
|
||||
|
||||
|
||||
optind++;
|
||||
|
||||
memset( &hints, 0, sizeof( struct addrinfo ) );
|
||||
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
|
||||
hints.ai_socktype = 0; /* Datagram socket */
|
||||
hints.ai_flags = 0;
|
||||
hints.ai_protocol = 0; /* Any protocol */
|
||||
do
|
||||
{
|
||||
s = getaddrinfo( redircfg.address, NULL, &hints, &result );
|
||||
if( s != 0 )
|
||||
{
|
||||
sleep( 2 );
|
||||
waitForCnt++;
|
||||
}
|
||||
else
|
||||
{
|
||||
waitForAddrInfo = 0;
|
||||
}
|
||||
if( waitForCnt > 1000 )
|
||||
{
|
||||
LOG(ERR, "could not resolve address");
|
||||
return( -1 );
|
||||
}
|
||||
if( !result ){
|
||||
freeaddrinfo( result );
|
||||
}
|
||||
} while( waitForAddrInfo );
|
||||
|
||||
// Some general initialization.
|
||||
redirInit( );
|
||||
createOneTask( (Address)redirClientTask, "redirClient", &taskIds[0] );
|
||||
createOneTask( (Address)redirMsgDispatchTaskFunc, "redirMsgDispatcher", &taskIds[1] );
|
||||
/* wait for the other tasks to finish */
|
||||
waitForOtherTaskesToFinish( );
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
|
||||
159
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/src/redirmsgdispatch.c
Executable file
159
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/src/redirmsgdispatch.c
Executable file
@@ -0,0 +1,159 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <websocket/libwebsockets.h>
|
||||
|
||||
#include "redirmessagedef.h"
|
||||
#include "redirclient.h"
|
||||
#include "redirintercomm.h"
|
||||
#include "redirmsgdispatch.h"
|
||||
|
||||
msgDispData_t gmsgdd;
|
||||
|
||||
pthread_mutex_t state_machine_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_cond_t state_machine_cv = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
int hasCloudMsg = 0;
|
||||
pthread_mutex_t waitForMessageResp_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_cond_t waitForMessageResp_cv = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
extern struct lws * redir_wsi[MAX_REDIR_CLIENTS];
|
||||
extern int RedirWsTxErr;
|
||||
|
||||
extern int redirAddOneTxBuffToPool( unsigned char * Buffer, unsigned int len );
|
||||
extern int redirSendNotification( redirNotify_t * cNotify );
|
||||
|
||||
int RedirSockFd = -1;
|
||||
|
||||
|
||||
int redirOpenRedirSocket( unsigned short Port )
|
||||
{
|
||||
struct sockaddr_in serv_addr;
|
||||
int nn;
|
||||
char RedirBuf[50];
|
||||
|
||||
RedirSockFd = socket( AF_INET, SOCK_STREAM, 0 );
|
||||
if( RedirSockFd < 0 )
|
||||
{
|
||||
RedirSockFd = -1;
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
serv_addr.sin_family = AF_INET;
|
||||
serv_addr.sin_port = htons( Port );
|
||||
serv_addr.sin_addr.s_addr = htonl( INADDR_LOOPBACK );
|
||||
if( connect( RedirSockFd, (struct sockaddr *)&serv_addr, sizeof( serv_addr ) ) < 0 )
|
||||
{
|
||||
RedirSockFd = -1;
|
||||
return( -1 );
|
||||
}
|
||||
sprintf( RedirBuf, "connected_to_CE_port:%d", 22 );
|
||||
nn = lws_write( redir_wsi[0], (unsigned char *)RedirBuf, strlen( RedirBuf ), redircfg.write_options );
|
||||
if( nn < 0 )
|
||||
RedirWsTxErr = 1;
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
||||
void redirCloseRedirSocket( void )
|
||||
{
|
||||
if( RedirSockFd != -1 )
|
||||
{
|
||||
close( RedirSockFd );
|
||||
RedirSockFd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void redirMessageRedirect( unsigned char * Msg, size_t Len )
|
||||
{
|
||||
if( RedirSockFd == -1 )
|
||||
return;
|
||||
write( RedirSockFd, Msg, Len );
|
||||
}
|
||||
|
||||
|
||||
static int redirWaitForWebSocketToEstablish( )
|
||||
{
|
||||
pthread_mutex_lock( &state_machine_mutex );
|
||||
if( !redirst.wsIsReady )
|
||||
pthread_cond_wait( &state_machine_cv, &state_machine_mutex );
|
||||
|
||||
pthread_mutex_unlock( &state_machine_mutex );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int redirNotifyWebSocketIsReady( )
|
||||
{
|
||||
pthread_mutex_lock( &state_machine_mutex );
|
||||
redirst.wsIsReady = 1;
|
||||
|
||||
pthread_cond_signal( &state_machine_cv );
|
||||
pthread_mutex_unlock( &state_machine_mutex );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
void redirResetStateMachine()
|
||||
{
|
||||
gmsgdd.backOffTime = 5;
|
||||
gmsgdd.dropAllMsgBackOff = 1;
|
||||
gmsgdd.applyFailedNum = 0;
|
||||
}
|
||||
|
||||
|
||||
unsigned char RecBuf[REDIR_MSG_MAX_SIZE];
|
||||
unsigned char RedirBuf[REDIR_MSG_MAX_SIZE];
|
||||
|
||||
void * redirMsgDispatchTaskFunc( void * x_void_ptr )
|
||||
{
|
||||
int n;
|
||||
|
||||
// initialize some global configuration.
|
||||
memset( &gmsgdd, '\0', sizeof gmsgdd );
|
||||
|
||||
// wait for the websocket link to establish first.
|
||||
redirWaitForWebSocketToEstablish( );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
while( redirWsLinkIsNotReady( ) )
|
||||
{
|
||||
sleep( 3 );
|
||||
}
|
||||
if( RedirSockFd != -1 )
|
||||
{
|
||||
n = recv( RedirSockFd, (void *)RecBuf, sizeof( RecBuf ) - 100, 0 );
|
||||
if( n > 0 )
|
||||
{
|
||||
unsigned char * SendBuf = calloc( 1, n+4 );
|
||||
|
||||
if( SendBuf )
|
||||
{
|
||||
redirNotify_t cn;
|
||||
|
||||
*(SendBuf+3) = 22;
|
||||
memcpy( SendBuf+4, RecBuf, n );
|
||||
redirAddOneTxBuffToPool( SendBuf, n+4 );
|
||||
redirSendNotification( &cn );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
144
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/src/redirtask.c
Executable file
144
feeds/wlan-ap/opensync/src/platform/openwrt/src/command/src/redirtask.c
Executable file
@@ -0,0 +1,144 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include "redirmessagedef.h"
|
||||
#include "redirtask.h"
|
||||
|
||||
static int numTasks = 0;
|
||||
static redirTask *tasks = NULL;
|
||||
static redirTask *freeTasks = NULL;
|
||||
static pthread_mutex_t tasksMutex;
|
||||
static int numAllocatedTasks = 0;
|
||||
|
||||
redirTask* allocTaskFromPool()
|
||||
{
|
||||
redirTask *pTask = NULL;
|
||||
|
||||
pthread_mutex_lock(&tasksMutex);
|
||||
if (freeTasks) {
|
||||
pTask = freeTasks;
|
||||
pTask->allocated = 1;
|
||||
freeTasks = freeTasks->nextFreeTask;
|
||||
++numAllocatedTasks;
|
||||
}
|
||||
pthread_mutex_unlock(&tasksMutex);
|
||||
return pTask;
|
||||
}
|
||||
|
||||
void releaseTaskBackToPool(redirTask *pTask)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (pTask->allocated) {
|
||||
pthread_mutex_lock(&tasksMutex);
|
||||
if ((rc = pthread_attr_destroy(&pTask->threadAttr)) != 0) {
|
||||
}
|
||||
pTask->allocated = 0;
|
||||
pTask->threadSelf = 0;
|
||||
pTask->nextFreeTask = freeTasks;
|
||||
freeTasks = pTask;
|
||||
numAllocatedTasks--;
|
||||
pthread_mutex_unlock(&tasksMutex);
|
||||
}
|
||||
}
|
||||
|
||||
int createOneTask(Address taskFunc, char *Name, int *entryId)
|
||||
{
|
||||
redirTask *pTask = NULL;
|
||||
|
||||
pTask = allocTaskFromPool();
|
||||
|
||||
if (pTask) {
|
||||
int rc;
|
||||
|
||||
*entryId = pTask->entryId;
|
||||
strncpy(&pTask->name[0], Name, 16);
|
||||
pTask->name[15] = '\0';
|
||||
pTask->taskFunc = (void (*)(void))taskFunc;
|
||||
|
||||
if ((rc = pthread_attr_init(&pTask->threadAttr)) != 0) {
|
||||
}
|
||||
|
||||
if ((rc = pthread_create(&pTask->threadSelf, &pTask->threadAttr, (void *)taskFunc, pTask)) != 0) {
|
||||
releaseTaskBackToPool(pTask);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int redirInitTasks()
|
||||
{
|
||||
int i, rc;
|
||||
redirTask *pTask;
|
||||
pthread_mutexattr_t mAttr;
|
||||
|
||||
numTasks = REDIR_MAX_TASKS;
|
||||
tasks = calloc(numTasks, sizeof(redirTask));
|
||||
if (!tasks) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pTask = tasks;
|
||||
for (i = 0; i < numTasks; i++) {
|
||||
pTask->entryId = REDIR_TASK_ID_BASE | i;
|
||||
pTask->allocated = 0;
|
||||
pTask->nextFreeTask = pTask + 1;
|
||||
pTask++;
|
||||
}
|
||||
|
||||
tasks[numTasks - 1].nextFreeTask = NULL;
|
||||
freeTasks = tasks;
|
||||
|
||||
pthread_mutexattr_init(&mAttr);
|
||||
|
||||
if ((rc = pthread_mutex_init(&tasksMutex, &mAttr)) != 0) {
|
||||
free(tasks);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// setup main pTask up in the table.
|
||||
pTask = allocTaskFromPool();
|
||||
|
||||
strncpy(&pTask->name[0], "main", 16);
|
||||
pTask->taskFunc = NULL;
|
||||
pTask->threadSelf = pthread_self();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void waitForOtherTaskesToFinish()
|
||||
{
|
||||
redirTask *pTask = tasks;
|
||||
void *ret = NULL;
|
||||
int i;
|
||||
|
||||
pTask++;
|
||||
for (i = 1; i < REDIR_MAX_TASKS; i++) {
|
||||
if (pTask->allocated) {
|
||||
printf("TASK %d\n", i);
|
||||
if (pthread_join(pTask->threadSelf, &ret)) {
|
||||
printf("returning\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
pTask++;
|
||||
pthread_kill(pTask->threadSelf,0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,9 @@ static struct cmd_handler {
|
||||
}, {
|
||||
.cmd = "crashlog",
|
||||
.cb = cmd_handler_crashlog,
|
||||
}, {
|
||||
.cmd = "startPortForwardingSession",
|
||||
.cb = cmd_handler_port_forwarding,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -42,12 +42,19 @@ UNIT_SRC += src/cmd_tcpdump.c
|
||||
UNIT_SRC += src/webserver.c
|
||||
UNIT_SRC += src/crashlog.c
|
||||
UNIT_SRC += src/cmd_crashlog.c
|
||||
UNIT_SRC += src/redirclient.c
|
||||
UNIT_SRC += src/redirintercomm.c
|
||||
UNIT_SRC += src/redirmain.c
|
||||
UNIT_SRC += src/redirmsgdispatch.c
|
||||
UNIT_SRC += src/redirtask.c
|
||||
UNIT_SRC += src/libwcf_devif.c
|
||||
UNIT_SRC += src/cmd_portforwarding.c
|
||||
|
||||
UNIT_CFLAGS := -I$(UNIT_PATH)/inc
|
||||
UNIT_CFLAGS += -Isrc/lib/common/inc/
|
||||
UNIT_CFLAGS += -Isrc/lib/version/inc/
|
||||
|
||||
UNIT_LDFLAGS += -lev -lubox -luci -lubus
|
||||
UNIT_LDFLAGS += -lev -lubox -luci -lubus -lwebsocket
|
||||
UNIT_LDFLAGS += -lrt
|
||||
|
||||
UNIT_EXPORT_CFLAGS := $(UNIT_CFLAGS)
|
||||
|
||||
Reference in New Issue
Block a user