mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
refactor: subdirs for source in lib
Split out some optional code into own sources to shrink down libwebsockets.c and server.c a bit
This commit is contained in:
parent
904a9c0920
commit
c83afc66e6
53 changed files with 2818 additions and 2509 deletions
|
@ -250,7 +250,7 @@ set(LWS_OPENSSL_LIBRARIES CACHE PATH "Path to the OpenSSL library")
|
|||
set(LWS_OPENSSL_INCLUDE_DIRS CACHE PATH "Path to the OpenSSL include directory")
|
||||
set(LWS_WOLFSSL_LIBRARIES CACHE PATH "Path to the wolfSSL library")
|
||||
set(LWS_WOLFSSL_INCLUDE_DIRS CACHE PATH "Path to the wolfSSL include directory")
|
||||
set( CACHE PATH "Path to the libev library")
|
||||
set(LWS_LIBEV_LIBRARIES CACHE PATH "Path to the libev library")
|
||||
set(LWS_LIBEV_INCLUDE_DIRS CACHE PATH "Path to the libev include directory")
|
||||
set(LWS_LIBUV_LIBRARIES CACHE PATH "Path to the libuv library")
|
||||
set(LWS_LIBUV_INCLUDE_DIRS CACHE PATH "Path to the libuv include directory")
|
||||
|
@ -610,22 +610,38 @@ set(HDR_PUBLIC
|
|||
)
|
||||
|
||||
set(SOURCES
|
||||
lib/base64-decode.c
|
||||
lib/misc/base64-decode.c
|
||||
lib/handshake.c
|
||||
lib/libwebsockets.c
|
||||
lib/service.c
|
||||
lib/pollfd.c
|
||||
lib/output.c
|
||||
lib/parsers.c
|
||||
lib/server/parsers.c
|
||||
lib/context.c
|
||||
lib/alloc.c
|
||||
lib/header.c)
|
||||
lib/header.c
|
||||
lib/misc/lws-ring.c)
|
||||
|
||||
if (LWS_WITH_CGI)
|
||||
list(APPEND SOURCES
|
||||
lib/server/cgi.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_ACCESS_LOG)
|
||||
list(APPEND SOURCES
|
||||
lib/server/access-log.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_PEER_LIMITS)
|
||||
list(APPEND SOURCES
|
||||
lib/server/peer-limits.c)
|
||||
endif()
|
||||
|
||||
if (NOT LWS_WITHOUT_CLIENT)
|
||||
list(APPEND SOURCES
|
||||
lib/client.c
|
||||
lib/client-handshake.c
|
||||
lib/client-parser.c)
|
||||
lib/client/client.c
|
||||
lib/client/client-handshake.c
|
||||
lib/client/client-parser.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_MBEDTLS)
|
||||
|
@ -673,51 +689,51 @@ endif()
|
|||
if (LWS_WITH_SSL)
|
||||
list(APPEND SOURCES
|
||||
lib/ssl.c
|
||||
lib/lws-genhash.c)
|
||||
lib/misc/lws-genhash.c)
|
||||
|
||||
if (NOT LWS_WITHOUT_SERVER)
|
||||
list(APPEND SOURCES
|
||||
lib/ssl-server.c)
|
||||
lib/server/ssl-server.c)
|
||||
endif()
|
||||
if (NOT LWS_WITHOUT_CLIENT)
|
||||
list(APPEND SOURCES
|
||||
lib/ssl-client.c)
|
||||
lib/client/ssl-client.c)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (NOT LWS_WITHOUT_BUILTIN_SHA1)
|
||||
list(APPEND SOURCES
|
||||
lib/sha-1.c)
|
||||
lib/misc/sha-1.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_HTTP2)
|
||||
list(APPEND SOURCES
|
||||
lib/http2.c
|
||||
lib/hpack.c
|
||||
lib/ssl-http2.c)
|
||||
lib/http2/http2.c
|
||||
lib/http2/hpack.c
|
||||
lib/http2/ssl-http2.c)
|
||||
endif()
|
||||
# select the active platform files
|
||||
|
||||
if (WIN32)
|
||||
list(APPEND SOURCES
|
||||
lib/lws-plat-win.c)
|
||||
lib/plat/lws-plat-win.c)
|
||||
else()
|
||||
|
||||
if (LWS_WITH_ESP8266)
|
||||
list(APPEND SOURCES
|
||||
lib/lws-plat-esp8266.c)
|
||||
lib/plat/lws-plat-esp8266.c)
|
||||
else()
|
||||
if (LWS_PLAT_OPTEE)
|
||||
list(APPEND SOURCES
|
||||
lib/lws-plat-optee.c)
|
||||
lib/plat/lws-plat-optee.c)
|
||||
else()
|
||||
if (LWS_WITH_ESP32)
|
||||
list(APPEND SOURCES
|
||||
lib/lws-plat-esp32.c
|
||||
lib/romfs.c)
|
||||
lib/plat/lws-plat-esp32.c
|
||||
lib/misc/romfs.c)
|
||||
else()
|
||||
list(APPEND SOURCES
|
||||
lib/lws-plat-unix.c)
|
||||
lib/plat/lws-plat-unix.c)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
@ -725,64 +741,65 @@ endif()
|
|||
|
||||
if (NOT LWS_WITHOUT_SERVER)
|
||||
list(APPEND SOURCES
|
||||
lib/server.c
|
||||
lib/server-handshake.c)
|
||||
lib/server/server.c
|
||||
lib/server/lws-spa.c
|
||||
lib/server/server-handshake.c)
|
||||
endif()
|
||||
|
||||
if (NOT LWS_WITHOUT_EXTENSIONS)
|
||||
list(APPEND HDR_PRIVATE
|
||||
lib/extension-permessage-deflate.h)
|
||||
lib/ext/extension-permessage-deflate.h)
|
||||
list(APPEND SOURCES
|
||||
lib/extension.c
|
||||
lib/extension-permessage-deflate.c)
|
||||
lib/ext/extension.c
|
||||
lib/ext/extension-permessage-deflate.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_HTTP_PROXY)
|
||||
list(APPEND SOURCES
|
||||
lib/rewrite.c)
|
||||
lib/server/rewrite.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LIBEV)
|
||||
list(APPEND SOURCES
|
||||
lib/libev.c)
|
||||
lib/event-libs/libev.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LIBUV)
|
||||
list(APPEND SOURCES
|
||||
lib/libuv.c)
|
||||
lib/event-libs/libuv.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LIBEVENT)
|
||||
list(APPEND SOURCES
|
||||
lib/libevent.c)
|
||||
lib/event-libs/libevent.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LEJP)
|
||||
list(APPEND SOURCES
|
||||
lib/lejp.c)
|
||||
lib/misc/lejp.c)
|
||||
list(APPEND HDR_PUBLIC
|
||||
lib/lejp.h)
|
||||
lib/misc/lejp.h)
|
||||
endif()
|
||||
if (LWS_WITH_LEJP_CONF)
|
||||
list(APPEND SOURCES
|
||||
"lib/lejp-conf.c"
|
||||
"lib/server/lejp-conf.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_SMTP)
|
||||
list(APPEND SOURCES
|
||||
lib/smtp.c)
|
||||
lib/misc/smtp.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_RANGES)
|
||||
list(APPEND SOURCES
|
||||
lib/ranges.c)
|
||||
lib/server/ranges.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_ZIP_FOPS)
|
||||
if (LWS_WITH_ZLIB)
|
||||
list(APPEND SOURCES
|
||||
lib/fops-zip.c)
|
||||
lib/server/fops-zip.c)
|
||||
else()
|
||||
message(FATAL_ERROR "Pre-zipped file support (LWS_WITH_ZIP_FOPS) requires ZLIB (LWS_WITH_ZLIB)")
|
||||
endif()
|
||||
|
@ -807,14 +824,14 @@ else()
|
|||
# Unix.
|
||||
if (NOT LWS_WITHOUT_DAEMONIZE)
|
||||
list(APPEND SOURCES
|
||||
lib/daemonize.c)
|
||||
lib/server/daemonize.c)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (UNIX)
|
||||
if (NOT LWS_HAVE_GETIFADDRS)
|
||||
list(APPEND HDR_PRIVATE lib/getifaddrs.h)
|
||||
list(APPEND SOURCES lib/getifaddrs.c)
|
||||
list(APPEND HDR_PRIVATE lib/misc/getifaddrs.h)
|
||||
list(APPEND SOURCES lib/misc/getifaddrs.c)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
|
|
@ -4,20 +4,81 @@ Notes about coding with lws
|
|||
@section era Old lws and lws v2.0
|
||||
|
||||
Originally lws only supported the "manual" method of handling everything in the
|
||||
user callback found in test-server.c.
|
||||
user callback found in test-server.c / test-server-http.c.
|
||||
|
||||
Since v2.0, the need for most or all of this manual boilerplate has been eliminated:
|
||||
the protocols[0] http stuff is provided by a lib export `lws_callback_http_dummy()`.
|
||||
You can serve parts of your filesystem at part of the URL space using mounts.
|
||||
Since v2.0, the need for most or all of this manual boilerplate has been
|
||||
eliminated: the protocols[0] http stuff is provided by a generic lib export
|
||||
`lws_callback_http_dummy()`. You can serve parts of your filesystem at part of
|
||||
the URL space using mounts, the dummy http callback will do the right thing.
|
||||
|
||||
It's much preferred to use the "automated" v2.0 type scheme, because it's less
|
||||
code and it's easier to support.
|
||||
|
||||
You can see an example of the new way in test-server-v2.0.c.
|
||||
|
||||
If you just need generic serving capability, consider not writing any server code
|
||||
and instead use lwsws and writing your user code in a standalone plugin. The
|
||||
server is configured for mounts etc using JSON, see README.lwsws.md.
|
||||
If you just need generic serving capability, without the need to integrate lws
|
||||
to some other app, consider not writing any server code at all, and instead use
|
||||
the generic server `lwsws`, and writing your special user code in a standalone
|
||||
"plugin". The server is configured for mounts etc using JSON, see
|
||||
./READMEs/README.lwsws.md.
|
||||
|
||||
Although the "plugins" are dynamically loaded if you use lwsws or lws built
|
||||
with libuv, actually they may perfectly well be statically included if that
|
||||
suits your situation better, eg, ESP32 test server, where the platform does
|
||||
not support processes or dynamic loading, just #includes the plugins
|
||||
one after the other and gets the same benefit from the same code.
|
||||
|
||||
Isolating and collating the protocol code in one place also makes it very easy
|
||||
to maintain and understand.
|
||||
|
||||
So it if highly recommended you put your protocol-specific code into the
|
||||
form of a "plugin" at the source level, even if you have no immediate plan to
|
||||
use it dynamically-loaded.
|
||||
|
||||
@section writeable Only send data when socket writeable
|
||||
|
||||
You should only send data on a websocket connection from the user callback
|
||||
`LWS_CALLBACK_SERVER_WRITEABLE` (or `LWS_CALLBACK_CLIENT_WRITEABLE` for
|
||||
clients).
|
||||
|
||||
If you want to send something, do NOT just send it but request a callback
|
||||
when the socket is writeable using
|
||||
|
||||
- `lws_callback_on_writable(context, wsi)` for a specific `wsi`, or
|
||||
|
||||
- `lws_callback_on_writable_all_protocol(protocol)` for all connections
|
||||
using that protocol to get a callback when next writeable.
|
||||
|
||||
Usually you will get called back immediately next time around the service
|
||||
loop, but if your peer is slow or temporarily inactive the callback will be
|
||||
delayed accordingly. Generating what to write and sending it should be done
|
||||
in the ...WRITEABLE callback.
|
||||
|
||||
See the test server code for an example of how to do this.
|
||||
|
||||
Otherwise evolved libs like libuv get this wrong, they will allow you to "send"
|
||||
anything you want but it only uses up your local memory (and costs you
|
||||
memcpys) until the socket can actually accept it. It is much better to regulate
|
||||
your send action by the downstream peer readiness to take new data in the first
|
||||
place, avoiding all the wasted buffering.
|
||||
|
||||
Libwebsockets' concept is that the downstream peer is truly the boss, if he,
|
||||
or our connection to him, cannot handle anything new, we should not generate
|
||||
anything new for him. This is how unix shell piping works, you may have
|
||||
`cat a.txt | grep xyz > remote", but actually that does not cat anything from
|
||||
a.txt while remote cannot accept anything new.
|
||||
|
||||
@section otherwr Do not rely on only your own WRITEABLE requests appearing
|
||||
|
||||
Libwebsockets may generate additional `LWS_CALLBACK_CLIENT_WRITEABLE` events
|
||||
if it met network conditions where it had to buffer your send data internally.
|
||||
|
||||
So your code for `LWS_CALLBACK_CLIENT_WRITEABLE` needs to own the decision
|
||||
about what to send, it can't assume that just because the writeable callback
|
||||
came it really is time to send something.
|
||||
|
||||
It's quite possible you get an 'extra' writeable callback at any time and
|
||||
just need to `return 0` and wait for the expected callback later.
|
||||
|
||||
@section dae Daemonization
|
||||
|
||||
|
@ -28,8 +89,7 @@ headless background process and exit the starting process.
|
|||
|
||||
Notice stdout, stderr, stdin are all redirected to /dev/null to enforce your
|
||||
daemon is headless, so you'll need to sort out alternative logging, by, eg,
|
||||
syslog.
|
||||
|
||||
syslog via `lws_set_log_level(..., lwsl_emit_syslog)`.
|
||||
|
||||
@section conns Maximum number of connections
|
||||
|
||||
|
@ -81,7 +141,9 @@ repeat that in other words:
|
|||
There is another network-programming truism that surprises some people which
|
||||
is if the sink for the data cannot accept more:
|
||||
|
||||
***YOU MUST PERFORM RX FLOW CONTROL***
|
||||
***YOU MUST PERFORM RX FLOW CONTROL*** to stop taking new input. TCP will make
|
||||
this situation known to the upstream sender by making it impossible for him to
|
||||
send anything more on the connection until we start accepting things again.
|
||||
|
||||
See the mirror protocol implementations for example code.
|
||||
|
||||
|
@ -99,42 +161,6 @@ you might simultaneously create more than one context from different threads.
|
|||
SSL_library_init() is called from the context create api and it also is not
|
||||
reentrant. So at least create the contexts sequentially.
|
||||
|
||||
|
||||
@section writeable Only send data when socket writeable
|
||||
|
||||
You should only send data on a websocket connection from the user callback
|
||||
`LWS_CALLBACK_SERVER_WRITEABLE` (or `LWS_CALLBACK_CLIENT_WRITEABLE` for
|
||||
clients).
|
||||
|
||||
If you want to send something, do not just send it but request a callback
|
||||
when the socket is writeable using
|
||||
|
||||
- `lws_callback_on_writable(context, wsi)` for a specific `wsi`, or
|
||||
|
||||
- `lws_callback_on_writable_all_protocol(protocol)` for all connections
|
||||
using that protocol to get a callback when next writeable.
|
||||
|
||||
Usually you will get called back immediately next time around the service
|
||||
loop, but if your peer is slow or temporarily inactive the callback will be
|
||||
delayed accordingly. Generating what to write and sending it should be done
|
||||
in the ...WRITEABLE callback.
|
||||
|
||||
See the test server code for an example of how to do this.
|
||||
|
||||
|
||||
@section otherwr Do not rely on only your own WRITEABLE requests appearing
|
||||
|
||||
Libwebsockets may generate additional `LWS_CALLBACK_CLIENT_WRITEABLE` events
|
||||
if it met network conditions where it had to buffer your send data internally.
|
||||
|
||||
So your code for `LWS_CALLBACK_CLIENT_WRITEABLE` needs to own the decision
|
||||
about what to send, it can't assume that just because the writeable callback
|
||||
came it really is time to send something.
|
||||
|
||||
It's quite possible you get an 'extra' writeable callback at any time and
|
||||
just need to `return 0` and wait for the expected callback later.
|
||||
|
||||
|
||||
@section closing Closing connections from the user side
|
||||
|
||||
When you want to close a connection, you do it by returning `-1` from a
|
||||
|
|
8
lib/.gitignore
vendored
8
lib/.gitignore
vendored
|
@ -1,8 +0,0 @@
|
|||
#Ignore build files
|
||||
Makefile
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
.libs
|
||||
.deps
|
||||
|
0
lib/client.c → lib/client/client.c
Executable file → Normal file
0
lib/client.c → lib/client/client.c
Executable file → Normal file
|
@ -84,7 +84,7 @@ const struct http2_settings lws_h2_defaults = { {
|
|||
|
||||
const struct http2_settings lws_h2_stock_settings = { {
|
||||
1,
|
||||
/* H2SET_HEADER_TABLE_SIZE */ 512,
|
||||
/* H2SET_HEADER_TABLE_SIZE */ 4096,
|
||||
/* *** This controls how many entries in the dynamic table ***
|
||||
* Allows the sender to inform the remote endpoint of the maximum
|
||||
* size of the header compression table used to decode header
|
||||
|
@ -92,6 +92,8 @@ const struct http2_settings lws_h2_stock_settings = { {
|
|||
* less than this value by using signaling specific to the header
|
||||
* compression format inside a header block (see [COMPRESSION]).
|
||||
* The initial value is 4,096 octets.
|
||||
*
|
||||
* Can't pass h2spec with less than 4096 here...
|
||||
*/
|
||||
/* H2SET_ENABLE_PUSH */ 1,
|
||||
/* H2SET_MAX_CONCURRENT_STREAMS */ 24,
|
||||
|
|
|
@ -384,7 +384,8 @@ lws_token_from_index(struct lws *wsi, int index, const char **arg, int *len,
|
|||
if (index < 0)
|
||||
index += dyn->num_entries;
|
||||
|
||||
lwsl_header("%s: dyn index %d, tok %d\n", __func__, index, dyn->entries[index].lws_hdr_idx);
|
||||
lwsl_header("%s: dyn index %d, tok %d\n", __func__, index,
|
||||
dyn->entries[index].lws_hdr_idx);
|
||||
|
||||
if (arg && len) {
|
||||
*arg = dyn->entries[index].value;
|
||||
|
@ -410,9 +411,11 @@ lws_h2_dynamic_table_dump(struct lws *wsi)
|
|||
return 1;
|
||||
dyn = &nwsi->u.h2.h2n->hpack_dyn_table;
|
||||
|
||||
lwsl_header("Dump dyn table for nwsi %p (%d / %d members, pos = %d, start index %d, virt used %d / %d)\n", nwsi,
|
||||
dyn->used_entries, dyn->num_entries, dyn->pos, (uint32_t)ARRAY_SIZE(static_token),
|
||||
dyn->virtual_payload_usage, dyn->virtual_payload_max);
|
||||
lwsl_header("Dump dyn table for nwsi %p (%d / %d members, pos = %d, "
|
||||
"start index %d, virt used %d / %d)\n", nwsi,
|
||||
dyn->used_entries, dyn->num_entries, dyn->pos,
|
||||
(uint32_t)ARRAY_SIZE(static_token),
|
||||
dyn->virtual_payload_usage, dyn->virtual_payload_max);
|
||||
|
||||
for (n = 0; n < dyn->used_entries; n++) {
|
||||
m = (dyn->pos - 1 - n) % dyn->num_entries;
|
||||
|
@ -424,8 +427,9 @@ lws_h2_dynamic_table_dump(struct lws *wsi)
|
|||
else
|
||||
p = "(ignored)";
|
||||
lwsl_header(" %3d: tok %s: (len %d) val '%s'\n",
|
||||
(int)(n + ARRAY_SIZE(static_token)), p, dyn->entries[m].hdr_len,
|
||||
dyn->entries[m].value ? dyn->entries[m].value : "null");
|
||||
(int)(n + ARRAY_SIZE(static_token)), p,
|
||||
dyn->entries[m].hdr_len, dyn->entries[m].value ?
|
||||
dyn->entries[m].value : "null");
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
|
@ -509,6 +513,8 @@ lws_dynamic_token_insert(struct lws *wsi, int hdr_len,
|
|||
dyn->entries[new_index].value_len = 0;
|
||||
|
||||
if (lws_hdr_index != LWS_HPACK_IGNORE_ENTRY) {
|
||||
if (dyn->entries[new_index].value)
|
||||
lws_free_set_NULL(dyn->entries[new_index].value);
|
||||
dyn->entries[new_index].value = lws_malloc(len + 1, "hpack dyn");
|
||||
if (!dyn->entries[new_index].value)
|
||||
return 1;
|
||||
|
@ -565,7 +571,9 @@ lws_hpack_dynamic_size(struct lws *wsi, int size)
|
|||
goto bail;
|
||||
|
||||
dyn = &nwsi->u.h2.h2n->hpack_dyn_table;
|
||||
lwsl_info("%s: from %d to %d\n", __func__, (int)dyn->num_entries, size);
|
||||
lwsl_info("%s: from %d to %d, lim %d\n", __func__,
|
||||
(int)dyn->num_entries, size,
|
||||
nwsi->u.h2.h2n->set.s[H2SET_HEADER_TABLE_SIZE]);
|
||||
|
||||
if (size > nwsi->u.h2.h2n->set.s[H2SET_HEADER_TABLE_SIZE]) {
|
||||
lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
|
||||
|
@ -615,7 +623,10 @@ lws_hpack_dynamic_size(struct lws *wsi, int size)
|
|||
dyn->entries = dte;
|
||||
dyn->num_entries = size;
|
||||
dyn->used_entries = min;
|
||||
dyn->pos = min % size;
|
||||
if (size)
|
||||
dyn->pos = min % size;
|
||||
else
|
||||
dyn->pos = 0;
|
||||
|
||||
lws_h2_dynamic_table_dump(wsi);
|
||||
|
||||
|
@ -732,7 +743,6 @@ int lws_hpack_interpret(struct lws *wsi, unsigned char c)
|
|||
h2n->ext_count = 0;
|
||||
h2n->hpack_hdr_len = 0;
|
||||
h2n->unknown_header = 0;
|
||||
h2n->seen_nonpseudoheader = 0;
|
||||
|
||||
if (c & 0x80) { /* 1.... indexed header field only */
|
||||
/* just a possibly-extended integer */
|
||||
|
@ -930,7 +940,8 @@ pre_data:
|
|||
} else
|
||||
h2n->hdr_idx = 1;
|
||||
} else {
|
||||
n = lws_token_from_index(wsi, h2n->hdr_idx, NULL, NULL, NULL);
|
||||
n = lws_token_from_index(wsi, h2n->hdr_idx, NULL,
|
||||
NULL, NULL);
|
||||
lwsl_header(" lws_tok_from_idx(%d) says %d\n",
|
||||
h2n->hdr_idx, n);
|
||||
}
|
||||
|
@ -1010,9 +1021,11 @@ pre_data:
|
|||
if (h2n->hdr_idx &&
|
||||
h2n->hdr_idx != LWS_HPACK_IGNORE_ENTRY) {
|
||||
|
||||
if (ah->hdr_token_idx == WSI_TOKEN_HTTP_COLON_PATH) {
|
||||
if (ah->hdr_token_idx ==
|
||||
WSI_TOKEN_HTTP_COLON_PATH) {
|
||||
|
||||
switch (lws_parse_urldecode(wsi, &c1)) {
|
||||
switch (lws_parse_urldecode(
|
||||
wsi, &c1)) {
|
||||
case LPUR_CONTINUE:
|
||||
break;
|
||||
case LPUR_SWALLOW:
|
||||
|
@ -1020,8 +1033,8 @@ pre_data:
|
|||
case LPUR_EXCESSIVE:
|
||||
case LPUR_FORBID:
|
||||
lws_h2_goaway(nwsi,
|
||||
H2_ERR_PROTOCOL_ERROR,
|
||||
"Evil URI");
|
||||
H2_ERR_PROTOCOL_ERROR,
|
||||
"Evil URI");
|
||||
return 1;
|
||||
|
||||
default:
|
||||
|
@ -1030,11 +1043,11 @@ pre_data:
|
|||
}
|
||||
if (lws_frag_append(wsi, c1)) {
|
||||
lwsl_notice("%s: frag app fail\n",
|
||||
__func__);
|
||||
__func__);
|
||||
return 1;
|
||||
}
|
||||
} else
|
||||
lwsl_header("ignoring %c\n", c1);
|
||||
} //else
|
||||
//lwsl_header("ignoring %c\n", c1);
|
||||
} else {
|
||||
/*
|
||||
* Convert name using existing parser,
|
||||
|
@ -1140,7 +1153,8 @@ swallow:
|
|||
wsi->u.hdr.parser_state == WSI_TOKEN_NAME_PART ||
|
||||
wsi->u.hdr.parser_state == WSI_TOKEN_SKIPPING) {
|
||||
if (h2n->first_hdr_char == ':') {
|
||||
lwsl_info("HPKT_LITERAL_HDR_VALUE_INCR: end parser state %d unk hdr %d\n",
|
||||
lwsl_info("HPKT_LITERAL_HDR_VALUE_INCR:"
|
||||
" end state %d unk hdr %d\n",
|
||||
wsi->u.hdr.parser_state,
|
||||
h2n->unknown_header);
|
||||
/* unknown pseudoheaders are illegal */
|
||||
|
@ -1180,7 +1194,8 @@ add_it:
|
|||
if (m == 255)
|
||||
m = -1;
|
||||
} else
|
||||
m = lws_token_from_index(wsi, h2n->hdr_idx, NULL, NULL, NULL);
|
||||
m = lws_token_from_index(wsi, h2n->hdr_idx, NULL, NULL,
|
||||
NULL);
|
||||
if (m != -1 && m != LWS_HPACK_IGNORE_ENTRY)
|
||||
lws_dump_header(wsi, m);
|
||||
|
|
@ -189,7 +189,8 @@ lws_wsi_server_new(struct lws_vhost *vh, struct lws *parent_wsi,
|
|||
|
||||
wsi->vhost->conn_stats.h2_subs++;
|
||||
|
||||
lwsl_info("%s: %p new ch %p, sid %d, usersp=%p, tx cr %d, peer_credit %d (nwsi tx_cr %d)\n",
|
||||
lwsl_info("%s: %p new ch %p, sid %d, usersp=%p, tx cr %d, "
|
||||
"peer_credit %d (nwsi tx_cr %d)\n",
|
||||
__func__, parent_wsi, wsi, sid, wsi->user_space,
|
||||
wsi->u.h2.tx_cr, wsi->u.h2.peer_tx_cr_est, nwsi->u.h2.tx_cr);
|
||||
|
||||
|
@ -274,6 +275,7 @@ lws_h2_goaway(struct lws *wsi, uint32_t err, const char *reason)
|
|||
lwsl_info("%s: %p: ERR 0x%x, '%s'\n", __func__, wsi, err, reason);
|
||||
|
||||
pps->u.ga.err = err;
|
||||
pps->u.ga.highest_sid = h2n->highest_sid;
|
||||
strncpy(pps->u.ga.str, reason, sizeof(pps->u.ga.str) - 1);
|
||||
pps->u.ga.str[sizeof(pps->u.ga.str) - 1] = '\0';
|
||||
lws_pps_schedule(wsi, pps);
|
||||
|
@ -334,7 +336,7 @@ lws_h2_settings(struct lws *wsi, struct http2_settings *settings,
|
|||
case H2SET_ENABLE_PUSH:
|
||||
if (b > 1) {
|
||||
lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,
|
||||
"ENABLE_PUSH invalid arg");
|
||||
"ENABLE_PUSH invalid arg");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
@ -343,7 +345,7 @@ lws_h2_settings(struct lws *wsi, struct http2_settings *settings,
|
|||
case H2SET_INITIAL_WINDOW_SIZE:
|
||||
if (b > 0x7fffffff) {
|
||||
lws_h2_goaway(nwsi, H2_ERR_FLOW_CONTROL_ERROR,
|
||||
"Inital Window beyond max");
|
||||
"Inital Window beyond max");
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
|
@ -621,9 +623,9 @@ int lws_h2_do_pps_send(struct lws *wsi)
|
|||
*p++ = pps->u.ga.err >> 16;
|
||||
*p++ = pps->u.ga.err >> 8;
|
||||
*p++ = pps->u.ga.err;
|
||||
q = (unsigned char *)h2n->goaway_str;
|
||||
q = (unsigned char *)pps->u.ga.str;
|
||||
n = 0;
|
||||
while (*q && n++ < sizeof(h2n->goaway_str))
|
||||
while (*q && n++ < sizeof(pps->u.ga.str))
|
||||
*p++ = *q++;
|
||||
h2n->we_told_goaway = 1;
|
||||
n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_GOAWAY, 0,
|
||||
|
@ -653,13 +655,16 @@ int lws_h2_do_pps_send(struct lws *wsi)
|
|||
break;
|
||||
|
||||
case LWS_H2_PPS_UPDATE_WINDOW:
|
||||
lwsl_notice("LWS_H2_PPS_UPDATE_WINDOW: sid %d: add %d\n", pps->u.update_window.sid, pps->u.update_window.credit);
|
||||
lwsl_notice("LWS_H2_PPS_UPDATE_WINDOW: sid %d: add %d\n",
|
||||
pps->u.update_window.sid,
|
||||
pps->u.update_window.credit);
|
||||
*p++ = pps->u.update_window.credit >> 24;
|
||||
*p++ = pps->u.update_window.credit >> 16;
|
||||
*p++ = pps->u.update_window.credit >> 8;
|
||||
*p++ = pps->u.update_window.credit;
|
||||
n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_WINDOW_UPDATE,
|
||||
0, pps->u.update_window.sid, 4, &set[LWS_PRE]);
|
||||
0, pps->u.update_window.sid, 4,
|
||||
&set[LWS_PRE]);
|
||||
if (n != 4) {
|
||||
lwsl_info("send %d %d\n", n, m);
|
||||
goto bail;
|
||||
|
@ -802,7 +807,8 @@ lws_h2_parse_frame_header(struct lws *wsi)
|
|||
break;
|
||||
|
||||
h2n->swsi->u.h2.peer_tx_cr_est -= h2n->length;
|
||||
lwsl_debug(" peer_tx_cr_est %d\n", h2n->swsi->u.h2.peer_tx_cr_est);
|
||||
lwsl_debug(" peer_tx_cr_est %d\n",
|
||||
h2n->swsi->u.h2.peer_tx_cr_est);
|
||||
if (h2n->swsi->u.h2.peer_tx_cr_est < 32768) {
|
||||
h2n->swsi->u.h2.peer_tx_cr_est += 65536;
|
||||
pps = lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);
|
||||
|
@ -819,9 +825,9 @@ lws_h2_parse_frame_header(struct lws *wsi)
|
|||
lws_pps_schedule(wsi, pps);
|
||||
}
|
||||
|
||||
if ((
|
||||
if (
|
||||
h2n->swsi->u.h2.h2_state == LWS_H2_STATE_HALF_CLOSED_REMOTE ||
|
||||
h2n->swsi->u.h2.h2_state == LWS_H2_STATE_CLOSED)) {
|
||||
h2n->swsi->u.h2.h2_state == LWS_H2_STATE_CLOSED) {
|
||||
lws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED, "conn closed");
|
||||
break;
|
||||
}
|
||||
|
@ -950,7 +956,8 @@ lws_h2_parse_frame_header(struct lws *wsi)
|
|||
return 1;
|
||||
}
|
||||
|
||||
h2n->swsi = lws_wsi_server_new(wsi->vhost, wsi, h2n->sid);
|
||||
h2n->swsi = lws_wsi_server_new(wsi->vhost, wsi,
|
||||
h2n->sid);
|
||||
if (!h2n->swsi) {
|
||||
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, "OOM");
|
||||
|
||||
|
@ -986,7 +993,8 @@ lws_h2_parse_frame_header(struct lws *wsi)
|
|||
|
||||
|
||||
/* END_STREAM means after servicing this, close the stream */
|
||||
h2n->swsi->u.h2.END_STREAM = !!(h2n->flags & LWS_H2_FLAG_END_STREAM);
|
||||
h2n->swsi->u.h2.END_STREAM =
|
||||
!!(h2n->flags & LWS_H2_FLAG_END_STREAM);
|
||||
lwsl_info("%s: hdr END_STREAM = %d\n",__func__,
|
||||
h2n->swsi->u.h2.END_STREAM);
|
||||
|
||||
|
@ -1187,7 +1195,9 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
|
|||
|
||||
lwsl_info(" action start...\n");
|
||||
n = lws_http_action(h2n->swsi);
|
||||
lwsl_info(" action result %d (wsi->u.http.rx_content_remain %lld)\n", n, h2n->swsi->u.http.rx_content_remain);
|
||||
lwsl_info(" action result %d "
|
||||
"(wsi->u.http.rx_content_remain %lld)\n",
|
||||
n, h2n->swsi->u.http.rx_content_remain);
|
||||
|
||||
/*
|
||||
* Commonly we only managed to start a larger transfer that will
|
||||
|
@ -1206,7 +1216,8 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
|
|||
break;
|
||||
|
||||
if (lws_hdr_total_length(h2n->swsi, WSI_TOKEN_HTTP_CONTENT_LENGTH) &&
|
||||
h2n->swsi->u.h2.END_STREAM && h2n->swsi->u.http.rx_content_length &&
|
||||
h2n->swsi->u.h2.END_STREAM &&
|
||||
h2n->swsi->u.http.rx_content_length &&
|
||||
h2n->swsi->u.http.rx_content_remain) {
|
||||
lws_h2_rst_stream(h2n->swsi, H2_ERR_PROTOCOL_ERROR,
|
||||
"Not enough rx content");
|
||||
|
@ -1291,7 +1302,8 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
|
|||
|
||||
case LWS_H2_FRAME_TYPE_GOAWAY:
|
||||
lwsl_info("GOAWAY: last sid %d, error 0x%08X, string '%s'\n",
|
||||
h2n->goaway_last_sid, h2n->goaway_err, h2n->goaway_str);
|
||||
h2n->goaway_last_sid, h2n->goaway_err,
|
||||
h2n->goaway_str);
|
||||
wsi->u.h2.GOING_AWAY = 1;
|
||||
|
||||
return 1;
|
||||
|
@ -1446,17 +1458,11 @@ lws_h2_parser(struct lws *wsi, unsigned char c)
|
|||
}
|
||||
|
||||
h2n->swsi->state = LWSS_HTTP_BODY;
|
||||
|
||||
h2n->inside++;
|
||||
/* because the HTTP_BODY stuff will handle it */
|
||||
//h2n->swsi->u.http.rx_content_remain--;
|
||||
//lwsl_info("remain %lld, %d / %d",
|
||||
// (long long)h2n->swsi->u.http.rx_content_remain,
|
||||
// h2n->inside, h2n->length);
|
||||
if (lws_hdr_total_length(h2n->swsi,
|
||||
WSI_TOKEN_HTTP_CONTENT_LENGTH) &&
|
||||
h2n->swsi->u.http.rx_content_length &&
|
||||
h2n->swsi->u.http.rx_content_remain == 1 && /* last byte */
|
||||
h2n->swsi->u.http.rx_content_remain == 1 && /* last */
|
||||
h2n->inside < h2n->length) { /* unread data in frame */
|
||||
lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,
|
||||
"More rx than content_length told");
|
|
@ -52,7 +52,8 @@
|
|||
#if !defined(LWS_NO_SERVER)
|
||||
#if defined(LWS_OPENSSL_SUPPORT)
|
||||
|
||||
#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||
#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
|
||||
OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||
|
||||
struct alpn_ctx {
|
||||
unsigned char *data;
|
||||
|
@ -79,7 +80,8 @@ alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen,
|
|||
LWS_VISIBLE void
|
||||
lws_context_init_http2_ssl(struct lws_vhost *vhost)
|
||||
{
|
||||
#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||
#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
|
||||
OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||
static struct alpn_ctx protos = { (unsigned char *)"\x02h2"
|
||||
"\x08http/1.1", 6 + 9 };
|
||||
|
||||
|
@ -94,7 +96,8 @@ lws_context_init_http2_ssl(struct lws_vhost *vhost)
|
|||
|
||||
int lws_h2_configure_if_upgraded(struct lws *wsi)
|
||||
{
|
||||
#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||
#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
|
||||
OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||
struct allocated_headers *ah;
|
||||
const unsigned char *name = NULL;
|
||||
char cstr[10];
|
1400
lib/libwebsockets.c
Executable file → Normal file
1400
lib/libwebsockets.c
Executable file → Normal file
File diff suppressed because it is too large
Load diff
|
@ -313,14 +313,35 @@ lwsl_timestamp(int level, char *p, int len);
|
|||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* lwsl_hexdump() - helper to hexdump a buffer
|
||||
*
|
||||
* \param level: one of LLL_ constants
|
||||
* \param buf: buffer start to dump
|
||||
* \param len: length of buffer to dump
|
||||
*
|
||||
* If \p level is visible, does a nice hexdump -C style dump of \p buf for
|
||||
* \p len bytes. This can be extremely convenient while debugging.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lwsl_hexdump_level(int level, const void *vbuf, size_t len);
|
||||
|
||||
/**
|
||||
* lwsl_hexdump() - helper to hexdump a buffer (DEBUG builds only)
|
||||
*
|
||||
* \param buf: buffer start to dump
|
||||
* \param len: length of buffer to dump
|
||||
*
|
||||
* Calls through to lwsl_hexdump_level(LLL_DEBUG, ... for compatability.
|
||||
* It's better to use lwsl_hexdump_level(level, ... directly so you can control
|
||||
* the visibility.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void lwsl_hexdump(const void *buf, size_t len);
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lwsl_hexdump(const void *buf, size_t len);
|
||||
|
||||
/**
|
||||
* lws_is_be() - returns nonzero if the platform is Big Endian
|
||||
*/
|
||||
static LWS_INLINE int lws_is_be(void) {
|
||||
const int probe = ~0xff;
|
||||
|
||||
|
@ -335,7 +356,8 @@ static LWS_INLINE int lws_is_be(void) {
|
|||
* the default stderr one.
|
||||
*
|
||||
* log level defaults to "err", "warn" and "notice" contexts enabled and
|
||||
* emission on stderr.
|
||||
* emission on stderr. If stderr is a tty (according to isatty()) then
|
||||
* the output is coloured according to the log level using ANSI escapes.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_set_log_level(int level,
|
||||
|
|
280
lib/misc/lws-ring.c
Normal file
280
lib/misc/lws-ring.c
Normal file
|
@ -0,0 +1,280 @@
|
|||
/*
|
||||
* libwebsockets - lws-ring multi-tail abstract ringbuffer api
|
||||
*
|
||||
* Copyright (C) 2017 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN struct lws_ring *
|
||||
lws_ring_create(size_t element_len, size_t count,
|
||||
void (*destroy_element)(void *))
|
||||
{
|
||||
struct lws_ring *ring = lws_malloc(sizeof(*ring), "ring create");
|
||||
|
||||
if (!ring)
|
||||
return NULL;
|
||||
|
||||
ring->buflen = count * element_len;
|
||||
ring->element_len = element_len;
|
||||
ring->head = 0;
|
||||
ring->oldest_tail = 0;
|
||||
ring->destroy_element = destroy_element;
|
||||
|
||||
ring->buf = lws_malloc(ring->buflen, "ring buf");
|
||||
if (!ring->buf) {
|
||||
lws_free(ring);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ring;
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_ring_destroy(struct lws_ring *ring)
|
||||
{
|
||||
if (ring->destroy_element)
|
||||
while (ring->oldest_tail != ring->head) {
|
||||
ring->destroy_element((uint8_t *)ring->buf +
|
||||
ring->oldest_tail);
|
||||
ring->oldest_tail =
|
||||
(ring->oldest_tail + ring->element_len) %
|
||||
ring->buflen;
|
||||
}
|
||||
if (ring->buf)
|
||||
lws_free_set_NULL(ring->buf);
|
||||
|
||||
lws_free(ring);
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN size_t
|
||||
lws_ring_get_count_free_elements(struct lws_ring *ring)
|
||||
{
|
||||
int f;
|
||||
|
||||
/*
|
||||
* possible ringbuf patterns
|
||||
*
|
||||
* h == t
|
||||
* |--------t***h---|
|
||||
* |**h-----------t*|
|
||||
* |t**************h|
|
||||
* |*****ht*********|
|
||||
*/
|
||||
if (ring->head == ring->oldest_tail)
|
||||
f = ring->buflen - ring->element_len;
|
||||
else
|
||||
if (ring->head < ring->oldest_tail)
|
||||
f = (ring->oldest_tail - ring->head) -
|
||||
ring->element_len;
|
||||
else
|
||||
f = (ring->buflen - ring->head) + ring->oldest_tail -
|
||||
ring->element_len;
|
||||
|
||||
if (f < 2)
|
||||
return 0;
|
||||
|
||||
return f / ring->element_len;
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN size_t
|
||||
lws_ring_get_count_waiting_elements(struct lws_ring *ring, uint32_t *tail)
|
||||
{ int f;
|
||||
|
||||
if (!tail)
|
||||
tail = &ring->oldest_tail;
|
||||
/*
|
||||
* possible ringbuf patterns
|
||||
*
|
||||
* h == t
|
||||
* |--------t***h---|
|
||||
* |**h-----------t*|
|
||||
* |t**************h|
|
||||
* |*****ht*********|
|
||||
*/
|
||||
if (ring->head == *tail)
|
||||
f = 0;
|
||||
else
|
||||
if (ring->head > *tail)
|
||||
f = (ring->head - *tail);
|
||||
else
|
||||
f = (ring->buflen - *tail) + ring->head;
|
||||
|
||||
return f / ring->element_len;
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_ring_next_linear_insert_range(struct lws_ring *ring, void **start,
|
||||
size_t *bytes)
|
||||
{
|
||||
int n;
|
||||
|
||||
/* n is how many bytes the whole fifo can take */
|
||||
n = lws_ring_get_count_free_elements(ring) * ring->element_len;
|
||||
|
||||
if (!n)
|
||||
return 1;
|
||||
|
||||
if (ring->head + n > ring->buflen) {
|
||||
*start = (void *)(((uint8_t *)ring->buf) + ring->head);
|
||||
*bytes = ring->buflen - ring->head;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
*start = (void *)(((uint8_t *)ring->buf) + ring->head);
|
||||
*bytes = n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_ring_bump_head(struct lws_ring *ring, size_t bytes)
|
||||
{
|
||||
ring->head = (ring->head + bytes) % ring->buflen;
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN size_t
|
||||
lws_ring_insert(struct lws_ring *ring, const void *src, size_t max_count)
|
||||
{
|
||||
const uint8_t *osrc = src;
|
||||
int m, n;
|
||||
|
||||
/* n is how many bytes the whole fifo can take */
|
||||
n = lws_ring_get_count_free_elements(ring) * ring->element_len;
|
||||
|
||||
/* restrict n to how much we want to insert */
|
||||
if ((size_t)n > max_count * ring->element_len)
|
||||
n = max_count * ring->element_len;
|
||||
|
||||
/*
|
||||
* n is legal to insert, but as an optimization we can cut the
|
||||
* insert into one or two memcpys, depending on if it wraps
|
||||
*/
|
||||
if (ring->head + n > ring->buflen) {
|
||||
|
||||
/*
|
||||
* He does wrap. The first memcpy should take us up to
|
||||
* the end of the buffer
|
||||
*/
|
||||
|
||||
m = ring->buflen - ring->head;
|
||||
memcpy(((uint8_t *)ring->buf) + ring->head, src, m);
|
||||
/* we know it will wrap exactly back to zero */
|
||||
ring->head = 0;
|
||||
|
||||
/* adapt the second memcpy for what we already did */
|
||||
|
||||
src = ((uint8_t *)src) + m;
|
||||
n -= m;
|
||||
}
|
||||
|
||||
memcpy(((uint8_t *)ring->buf) + ring->head, src, n);
|
||||
ring->head = (ring->head + n) % ring->buflen;
|
||||
|
||||
return (((uint8_t *)src + n) - osrc) / ring->element_len;
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN size_t
|
||||
lws_ring_consume(struct lws_ring *ring, uint32_t *tail, void *dest,
|
||||
size_t max_count)
|
||||
{
|
||||
uint8_t *odest = dest;
|
||||
void *orig_tail = tail;
|
||||
uint32_t fake_tail;
|
||||
int m, n;
|
||||
|
||||
if (!tail) {
|
||||
fake_tail = ring->oldest_tail;
|
||||
tail = &fake_tail;
|
||||
}
|
||||
|
||||
/* n is how many bytes the whole fifo has for us */
|
||||
n = lws_ring_get_count_waiting_elements(ring, tail) * ring->element_len;
|
||||
|
||||
/* restrict n to how much we want to insert */
|
||||
if ((size_t)n > max_count * ring->element_len)
|
||||
n = max_count * ring->element_len;
|
||||
|
||||
if (!dest) {
|
||||
*tail = ((*tail) + n) % ring->buflen;
|
||||
if (!orig_tail) /* single tail */
|
||||
lws_ring_update_oldest_tail(ring, *tail);
|
||||
|
||||
return n / ring->element_len;
|
||||
}
|
||||
if (*tail + n > ring->buflen) {
|
||||
|
||||
/*
|
||||
* He does wrap. The first memcpy should take us up to
|
||||
* the end of the buffer
|
||||
*/
|
||||
|
||||
m = ring->buflen - *tail;
|
||||
memcpy(dest, ((uint8_t *)ring->buf) + *tail, m);
|
||||
/* we know it will wrap exactly back to zero */
|
||||
*tail = 0;
|
||||
|
||||
/* adapt the second memcpy for what we already did */
|
||||
|
||||
dest = ((uint8_t *)dest) + m;
|
||||
n -= m;
|
||||
}
|
||||
|
||||
memcpy(dest, ((uint8_t *)ring->buf) + *tail, n);
|
||||
|
||||
*tail = ((*tail) + n) % ring->buflen;
|
||||
if (!orig_tail) /* single tail */
|
||||
lws_ring_update_oldest_tail(ring, *tail);
|
||||
|
||||
return (((uint8_t *)dest + n) - odest) / ring->element_len;
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN const void *
|
||||
lws_ring_get_element(struct lws_ring *ring, uint32_t *tail)
|
||||
{
|
||||
if (!tail)
|
||||
tail = &ring->oldest_tail;
|
||||
|
||||
if (*tail == ring->head)
|
||||
return NULL;
|
||||
|
||||
return ((uint8_t *)ring->buf) + *tail;
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_ring_update_oldest_tail(struct lws_ring *ring, uint32_t tail)
|
||||
{
|
||||
if (!ring->destroy_element) {
|
||||
ring->oldest_tail = tail;
|
||||
return;
|
||||
}
|
||||
|
||||
while (ring->oldest_tail != tail) {
|
||||
ring->destroy_element((uint8_t *)ring->buf + ring->oldest_tail);
|
||||
ring->oldest_tail = (ring->oldest_tail + ring->element_len) %
|
||||
ring->buflen;
|
||||
}
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN uint32_t
|
||||
lws_ring_get_oldest_tail(struct lws_ring *ring)
|
||||
{
|
||||
return ring->oldest_tail;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* SMTP support for libwebsockets
|
||||
*
|
||||
* Copyright (C) 2016 Andy Green <andy@warmcat.com>
|
||||
* Copyright (C) 2016-2017 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -93,7 +93,8 @@ lwsgs_email_read(struct uv_stream_s *s, ssize_t nread, const uv_buf_t *buf)
|
|||
email->estate = LGSSMTP_SENT_HELO;
|
||||
break;
|
||||
case LGSSMTP_SENT_HELO:
|
||||
n = sprintf(email->content, "MAIL FROM: <%s>\n", email->email_from);
|
||||
n = sprintf(email->content, "MAIL FROM: <%s>\n",
|
||||
email->email_from);
|
||||
email->estate = LGSSMTP_SENT_FROM;
|
||||
break;
|
||||
case LGSSMTP_SENT_FROM:
|
||||
|
@ -105,7 +106,8 @@ lwsgs_email_read(struct uv_stream_s *s, ssize_t nread, const uv_buf_t *buf)
|
|||
email->estate = LGSSMTP_SENT_DATA;
|
||||
break;
|
||||
case LGSSMTP_SENT_DATA:
|
||||
if (email->on_get_body(email, email->content, email->max_content_size))
|
||||
if (email->on_get_body(email, email->content,
|
||||
email->max_content_size))
|
||||
return;
|
||||
n = strlen(email->content);
|
||||
email->estate = LGSSMTP_SENT_BODY;
|
||||
|
@ -238,4 +240,3 @@ lws_email_destroy(struct lws_email *email)
|
|||
uv_timer_stop(&email->timeout_email);
|
||||
uv_close((uv_handle_t *)&email->timeout_email, NULL);
|
||||
}
|
||||
|
40
lib/output.c
40
lib/output.c
|
@ -46,49 +46,9 @@ lws_0405_frame_mask_generate(struct lws *wsi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void lwsl_hexdump(const void *vbuf, size_t len)
|
||||
{
|
||||
unsigned char *buf = (unsigned char *)vbuf;
|
||||
unsigned int n, m, start;
|
||||
char line[80];
|
||||
char *p;
|
||||
|
||||
lwsl_debug("\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);
|
||||
(void)line;
|
||||
}
|
||||
lwsl_debug("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
|
|
@ -1094,17 +1094,7 @@ struct lws_context {
|
|||
int uid, gid;
|
||||
|
||||
int fd_random;
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
#define lws_ssl_anybody_has_buffered_read(w) \
|
||||
(w->vhost->use_ssl && \
|
||||
w->context->pt[(int)w->tsi].pending_read_list)
|
||||
#define lws_ssl_anybody_has_buffered_read_tsi(c, t) \
|
||||
(/*c->use_ssl && */ \
|
||||
c->pt[(int)t].pending_read_list)
|
||||
#else
|
||||
#define lws_ssl_anybody_has_buffered_read(ctx) (0)
|
||||
#define lws_ssl_anybody_has_buffered_read_tsi(ctx, t) (0)
|
||||
#endif
|
||||
|
||||
int count_wsi_allocated;
|
||||
int count_cgi_spawned;
|
||||
unsigned int options;
|
||||
|
@ -2023,6 +2013,9 @@ lws_get_addr_scope(const char *ipaddr);
|
|||
LWS_EXTERN void
|
||||
lws_close_free_wsi(struct lws *wsi, enum lws_close_status);
|
||||
|
||||
LWS_EXTERN void
|
||||
lws_free_wsi(struct lws *wsi);
|
||||
|
||||
LWS_EXTERN int
|
||||
remove_wsi_socket_from_fds(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
|
@ -2297,6 +2290,7 @@ enum lws_ssl_capable_status {
|
|||
#define lws_ssl_SSL_CTX_destroy(_a)
|
||||
#define lws_ssl_remove_wsi_from_buffered_list(_a)
|
||||
#define lws_context_init_ssl_library(_a)
|
||||
#define lws_ssl_anybody_has_buffered_read_tsi(_a, _b) (0)
|
||||
#else
|
||||
#define LWS_SSL_ENABLED(context) (context->use_ssl)
|
||||
LWS_EXTERN int openssl_websocket_private_data_index;
|
||||
|
@ -2326,6 +2320,8 @@ LWS_EXTERN int
|
|||
lws_ssl_client_connect2(struct lws *wsi);
|
||||
LWS_EXTERN void
|
||||
lws_ssl_elaborate_error(void);
|
||||
LWS_EXTERN int
|
||||
lws_ssl_anybody_has_buffered_read_tsi(struct lws_context *context, int tsi);
|
||||
#ifndef LWS_NO_SERVER
|
||||
LWS_EXTERN int
|
||||
lws_context_init_server_ssl(struct lws_context_creation_info *info,
|
||||
|
@ -2474,6 +2470,8 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len);
|
|||
#ifdef LWS_WITH_ACCESS_LOG
|
||||
LWS_EXTERN int
|
||||
lws_access_log(struct lws *wsi);
|
||||
LWS_EXTERN void
|
||||
lws_prepare_access_log_info(struct lws *wsi, char *uri_ptr, int meth);
|
||||
#else
|
||||
#define lws_access_log(_a)
|
||||
#endif
|
||||
|
@ -2481,6 +2479,9 @@ lws_access_log(struct lws *wsi);
|
|||
LWS_EXTERN int
|
||||
lws_cgi_kill_terminated(struct lws_context_per_thread *pt);
|
||||
|
||||
LWS_EXTERN void
|
||||
lws_cgi_remove_and_kill(struct lws *wsi);
|
||||
|
||||
int
|
||||
lws_protocol_init(struct lws_context *context);
|
||||
|
||||
|
@ -2595,6 +2596,11 @@ void
|
|||
lws_peer_track_ah_detach(struct lws_context *context, struct lws_peer *peer);
|
||||
void
|
||||
lws_peer_cull_peer_wait_list(struct lws_context *context);
|
||||
struct lws_peer *
|
||||
lws_get_or_create_peer(struct lws_vhost *vhost, lws_sockfd_type sockfd);
|
||||
void
|
||||
lws_peer_add_wsi(struct lws_context *context, struct lws_peer *peer,
|
||||
struct lws *wsi);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
172
lib/server/access-log.c
Normal file
172
lib/server/access-log.c
Normal file
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* libwebsockets - server access log handling
|
||||
*
|
||||
* Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
/*
|
||||
* Produce Apache-compatible log string for wsi, like this:
|
||||
*
|
||||
* 2.31.234.19 - - [27/Mar/2016:03:22:44 +0800]
|
||||
* "GET /aep-screen.png HTTP/1.1"
|
||||
* 200 152987 "https://libwebsockets.org/index.html"
|
||||
* "Mozilla/5.0 (Macint... Chrome/49.0.2623.87 Safari/537.36"
|
||||
*
|
||||
*/
|
||||
|
||||
extern const char * const method_names[];
|
||||
|
||||
static const char * const hver[] = {
|
||||
"HTTP/1.0", "HTTP/1.1", "HTTP/2"
|
||||
};
|
||||
|
||||
void
|
||||
lws_prepare_access_log_info(struct lws *wsi, char *uri_ptr, int meth)
|
||||
{
|
||||
#ifdef LWS_WITH_IPV6
|
||||
char ads[INET6_ADDRSTRLEN];
|
||||
#else
|
||||
char ads[INET_ADDRSTRLEN];
|
||||
#endif
|
||||
char da[64];
|
||||
const char *pa, *me;
|
||||
struct tm *tmp;
|
||||
time_t t = time(NULL);
|
||||
int l = 256, m;
|
||||
|
||||
if (wsi->access_log_pending)
|
||||
lws_access_log(wsi);
|
||||
|
||||
wsi->access_log.header_log = lws_malloc(l, "access log");
|
||||
if (wsi->access_log.header_log) {
|
||||
|
||||
tmp = localtime(&t);
|
||||
if (tmp)
|
||||
strftime(da, sizeof(da), "%d/%b/%Y:%H:%M:%S %z", tmp);
|
||||
else
|
||||
strcpy(da, "01/Jan/1970:00:00:00 +0000");
|
||||
|
||||
pa = lws_get_peer_simple(wsi, ads, sizeof(ads));
|
||||
if (!pa)
|
||||
pa = "(unknown)";
|
||||
|
||||
if (wsi->http2_substream)
|
||||
me = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD);
|
||||
else
|
||||
me = method_names[meth];
|
||||
if (!me)
|
||||
me = "(null)";
|
||||
|
||||
lws_snprintf(wsi->access_log.header_log, l,
|
||||
"%s - - [%s] \"%s %s %s\"",
|
||||
pa, da, me, uri_ptr,
|
||||
hver[wsi->u.http.request_version]);
|
||||
|
||||
l = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT);
|
||||
if (l) {
|
||||
wsi->access_log.user_agent = lws_malloc(l + 2, "access log");
|
||||
if (!wsi->access_log.user_agent) {
|
||||
lwsl_err("OOM getting user agent\n");
|
||||
lws_free_set_NULL(wsi->access_log.header_log);
|
||||
return;
|
||||
}
|
||||
|
||||
lws_hdr_copy(wsi, wsi->access_log.user_agent,
|
||||
l + 1, WSI_TOKEN_HTTP_USER_AGENT);
|
||||
|
||||
for (m = 0; m < l; m++)
|
||||
if (wsi->access_log.user_agent[m] == '\"')
|
||||
wsi->access_log.user_agent[m] = '\'';
|
||||
}
|
||||
l = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_REFERER);
|
||||
if (l) {
|
||||
wsi->access_log.referrer = lws_malloc(l + 2, "referrer");
|
||||
if (!wsi->access_log.referrer) {
|
||||
lwsl_err("OOM getting user agent\n");
|
||||
lws_free_set_NULL(wsi->access_log.user_agent);
|
||||
lws_free_set_NULL(wsi->access_log.header_log);
|
||||
return;
|
||||
}
|
||||
lws_hdr_copy(wsi, wsi->access_log.referrer,
|
||||
l + 1, WSI_TOKEN_HTTP_REFERER);
|
||||
|
||||
for (m = 0; m < l; m++)
|
||||
if (wsi->access_log.referrer[m] == '\"')
|
||||
wsi->access_log.referrer[m] = '\'';
|
||||
}
|
||||
wsi->access_log_pending = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lws_access_log(struct lws *wsi)
|
||||
{
|
||||
char *p = wsi->access_log.user_agent, ass[512],
|
||||
*p1 = wsi->access_log.referrer;
|
||||
int l;
|
||||
|
||||
if (!wsi->access_log_pending)
|
||||
return 0;
|
||||
|
||||
if (!wsi->access_log.header_log)
|
||||
return 0;
|
||||
|
||||
if (!p)
|
||||
p = "";
|
||||
|
||||
if (!p1)
|
||||
p1 = "";
|
||||
|
||||
/*
|
||||
* We do this in two parts to restrict an oversize referrer such that
|
||||
* we will always have space left to append an empty useragent, while
|
||||
* maintaining the structure of the log text
|
||||
*/
|
||||
l = lws_snprintf(ass, sizeof(ass) - 7, "%s %d %lu \"%s",
|
||||
wsi->access_log.header_log,
|
||||
wsi->access_log.response, wsi->access_log.sent, p1);
|
||||
if (strlen(p) > sizeof(ass) - 6 - l)
|
||||
p[sizeof(ass) - 6 - l] = '\0';
|
||||
l += lws_snprintf(ass + l, sizeof(ass) - 1 - l, "\" \"%s\"\n", p);
|
||||
|
||||
if (wsi->vhost->log_fd != (int)LWS_INVALID_FILE) {
|
||||
if (write(wsi->vhost->log_fd, ass, l) != l)
|
||||
lwsl_err("Failed to write log\n");
|
||||
} else
|
||||
lwsl_err("%s", ass);
|
||||
|
||||
if (wsi->access_log.header_log) {
|
||||
lws_free(wsi->access_log.header_log);
|
||||
wsi->access_log.header_log = NULL;
|
||||
}
|
||||
if (wsi->access_log.user_agent) {
|
||||
lws_free(wsi->access_log.user_agent);
|
||||
wsi->access_log.user_agent = NULL;
|
||||
}
|
||||
if (wsi->access_log.referrer) {
|
||||
lws_free(wsi->access_log.referrer);
|
||||
wsi->access_log.referrer = NULL;
|
||||
}
|
||||
wsi->access_log_pending = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
1103
lib/server/cgi.c
Normal file
1103
lib/server/cgi.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -20,7 +20,7 @@
|
|||
*/
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
#include "lejp.h"
|
||||
#include "../misc/lejp.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
/* this is needed for Travis CI */
|
586
lib/server/lws-spa.c
Normal file
586
lib/server/lws-spa.c
Normal file
|
@ -0,0 +1,586 @@
|
|||
/*
|
||||
* libwebsockets - Stateful urldecode for POST
|
||||
*
|
||||
* Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
#define LWS_MAX_ELEM_NAME 32
|
||||
|
||||
enum urldecode_stateful {
|
||||
US_NAME,
|
||||
US_IDLE,
|
||||
US_PC1,
|
||||
US_PC2,
|
||||
|
||||
MT_LOOK_BOUND_IN,
|
||||
MT_HNAME,
|
||||
MT_DISP,
|
||||
MT_TYPE,
|
||||
MT_IGNORE1,
|
||||
MT_IGNORE2,
|
||||
};
|
||||
|
||||
static const char * const mp_hdr[] = {
|
||||
"content-disposition: ",
|
||||
"content-type: ",
|
||||
"\x0d\x0a"
|
||||
};
|
||||
|
||||
typedef int (*lws_urldecode_stateful_cb)(void *data,
|
||||
const char *name, char **buf, int len, int final);
|
||||
|
||||
struct lws_urldecode_stateful {
|
||||
char *out;
|
||||
void *data;
|
||||
char name[LWS_MAX_ELEM_NAME];
|
||||
char temp[LWS_MAX_ELEM_NAME];
|
||||
char content_type[32];
|
||||
char content_disp[32];
|
||||
char content_disp_filename[256];
|
||||
char mime_boundary[128];
|
||||
int out_len;
|
||||
int pos;
|
||||
int hdr_idx;
|
||||
int mp;
|
||||
int sum;
|
||||
|
||||
unsigned int multipart_form_data:1;
|
||||
unsigned int inside_quote:1;
|
||||
unsigned int subname:1;
|
||||
unsigned int boundary_real_crlf:1;
|
||||
|
||||
enum urldecode_stateful state;
|
||||
|
||||
lws_urldecode_stateful_cb output;
|
||||
};
|
||||
|
||||
static struct lws_urldecode_stateful *
|
||||
lws_urldecode_s_create(struct lws *wsi, char *out, int out_len, void *data,
|
||||
lws_urldecode_stateful_cb output)
|
||||
{
|
||||
struct lws_urldecode_stateful *s = lws_zalloc(sizeof(*s),
|
||||
"stateful urldecode");
|
||||
char buf[200], *p;
|
||||
int m = 0;
|
||||
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
s->out = out;
|
||||
s->out_len = out_len;
|
||||
s->output = output;
|
||||
s->pos = 0;
|
||||
s->sum = 0;
|
||||
s->mp = 0;
|
||||
s->state = US_NAME;
|
||||
s->name[0] = '\0';
|
||||
s->data = data;
|
||||
|
||||
if (lws_hdr_copy(wsi, buf, sizeof(buf),
|
||||
WSI_TOKEN_HTTP_CONTENT_TYPE) > 0) {
|
||||
/* multipart/form-data; boundary=----WebKitFormBoundarycc7YgAPEIHvgE9Bf */
|
||||
|
||||
if (!strncmp(buf, "multipart/form-data", 19)) {
|
||||
s->multipart_form_data = 1;
|
||||
s->state = MT_LOOK_BOUND_IN;
|
||||
s->mp = 2;
|
||||
p = strstr(buf, "boundary=");
|
||||
if (p) {
|
||||
p += 9;
|
||||
s->mime_boundary[m++] = '\x0d';
|
||||
s->mime_boundary[m++] = '\x0a';
|
||||
s->mime_boundary[m++] = '-';
|
||||
s->mime_boundary[m++] = '-';
|
||||
while (m < sizeof(s->mime_boundary) - 1 &&
|
||||
*p && *p != ' ')
|
||||
s->mime_boundary[m++] = *p++;
|
||||
|
||||
s->mime_boundary[m] = '\0';
|
||||
|
||||
lwsl_notice("boundary '%s'\n", s->mime_boundary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_urldecode_s_process(struct lws_urldecode_stateful *s, const char *in,
|
||||
int len)
|
||||
{
|
||||
int n, m, hit = 0;
|
||||
char c, was_end = 0;
|
||||
|
||||
while (len--) {
|
||||
if (s->pos == s->out_len - s->mp - 1) {
|
||||
if (s->output(s->data, s->name, &s->out, s->pos, 0))
|
||||
return -1;
|
||||
|
||||
was_end = s->pos;
|
||||
s->pos = 0;
|
||||
}
|
||||
switch (s->state) {
|
||||
|
||||
/* states for url arg style */
|
||||
|
||||
case US_NAME:
|
||||
s->inside_quote = 0;
|
||||
if (*in == '=') {
|
||||
s->name[s->pos] = '\0';
|
||||
s->pos = 0;
|
||||
s->state = US_IDLE;
|
||||
in++;
|
||||
continue;
|
||||
}
|
||||
if (*in == '&') {
|
||||
s->name[s->pos] = '\0';
|
||||
if (s->output(s->data, s->name, &s->out,
|
||||
s->pos, 1))
|
||||
return -1;
|
||||
s->pos = 0;
|
||||
s->state = US_IDLE;
|
||||
in++;
|
||||
continue;
|
||||
}
|
||||
if (s->pos >= sizeof(s->name) - 1) {
|
||||
lwsl_notice("Name too long\n");
|
||||
return -1;
|
||||
}
|
||||
s->name[s->pos++] = *in++;
|
||||
break;
|
||||
case US_IDLE:
|
||||
if (*in == '%') {
|
||||
s->state++;
|
||||
in++;
|
||||
continue;
|
||||
}
|
||||
if (*in == '&') {
|
||||
s->out[s->pos] = '\0';
|
||||
if (s->output(s->data, s->name, &s->out,
|
||||
s->pos, 1))
|
||||
return -1;
|
||||
s->pos = 0;
|
||||
s->state = US_NAME;
|
||||
in++;
|
||||
continue;
|
||||
}
|
||||
if (*in == '+') {
|
||||
in++;
|
||||
s->out[s->pos++] = ' ';
|
||||
continue;
|
||||
}
|
||||
s->out[s->pos++] = *in++;
|
||||
break;
|
||||
case US_PC1:
|
||||
n = char_to_hex(*in);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
|
||||
in++;
|
||||
s->sum = n << 4;
|
||||
s->state++;
|
||||
break;
|
||||
|
||||
case US_PC2:
|
||||
n = char_to_hex(*in);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
|
||||
in++;
|
||||
s->out[s->pos++] = s->sum | n;
|
||||
s->state = US_IDLE;
|
||||
break;
|
||||
|
||||
|
||||
/* states for multipart / mime style */
|
||||
|
||||
case MT_LOOK_BOUND_IN:
|
||||
retry_as_first:
|
||||
if (*in == s->mime_boundary[s->mp] &&
|
||||
s->mime_boundary[s->mp]) {
|
||||
in++;
|
||||
s->mp++;
|
||||
if (!s->mime_boundary[s->mp]) {
|
||||
s->mp = 0;
|
||||
s->state = MT_IGNORE1;
|
||||
|
||||
if (s->pos || was_end)
|
||||
if (s->output(s->data, s->name,
|
||||
&s->out, s->pos, 1))
|
||||
return -1;
|
||||
|
||||
s->pos = 0;
|
||||
|
||||
s->content_disp[0] = '\0';
|
||||
s->name[0] = '\0';
|
||||
s->content_disp_filename[0] = '\0';
|
||||
s->boundary_real_crlf = 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (s->mp) {
|
||||
n = 0;
|
||||
if (!s->boundary_real_crlf)
|
||||
n = 2;
|
||||
|
||||
memcpy(s->out + s->pos, s->mime_boundary + n,
|
||||
s->mp - n);
|
||||
s->pos += s->mp;
|
||||
s->mp = 0;
|
||||
goto retry_as_first;
|
||||
}
|
||||
|
||||
s->out[s->pos++] = *in;
|
||||
in++;
|
||||
s->mp = 0;
|
||||
break;
|
||||
|
||||
case MT_HNAME:
|
||||
m = 0;
|
||||
c =*in;
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
c += 'a' - 'A';
|
||||
for (n = 0; n < ARRAY_SIZE(mp_hdr); n++)
|
||||
if (c == mp_hdr[n][s->mp]) {
|
||||
m++;
|
||||
hit = n;
|
||||
}
|
||||
in++;
|
||||
if (!m) {
|
||||
s->mp = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
s->mp++;
|
||||
if (m != 1)
|
||||
continue;
|
||||
|
||||
if (mp_hdr[hit][s->mp])
|
||||
continue;
|
||||
|
||||
s->mp = 0;
|
||||
s->temp[0] = '\0';
|
||||
s->subname = 0;
|
||||
|
||||
if (hit == 2)
|
||||
s->state = MT_LOOK_BOUND_IN;
|
||||
else
|
||||
s->state += hit + 1;
|
||||
break;
|
||||
|
||||
case MT_DISP:
|
||||
/* form-data; name="file"; filename="t.txt" */
|
||||
|
||||
if (*in == '\x0d') {
|
||||
if (s->content_disp_filename[0])
|
||||
if (s->output(s->data, s->name,
|
||||
&s->out, s->pos,
|
||||
LWS_UFS_OPEN))
|
||||
return -1;
|
||||
s->state = MT_IGNORE2;
|
||||
goto done;
|
||||
}
|
||||
if (*in == ';') {
|
||||
s->subname = 1;
|
||||
s->temp[0] = '\0';
|
||||
s->mp = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (*in == '\"') {
|
||||
s->inside_quote ^= 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (s->subname) {
|
||||
if (*in == '=') {
|
||||
s->temp[s->mp] = '\0';
|
||||
s->subname = 0;
|
||||
s->mp = 0;
|
||||
goto done;
|
||||
}
|
||||
if (s->mp < sizeof(s->temp) - 1 &&
|
||||
(*in != ' ' || s->inside_quote))
|
||||
s->temp[s->mp++] = *in;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!s->temp[0]) {
|
||||
if (s->mp < sizeof(s->content_disp) - 1)
|
||||
s->content_disp[s->mp++] = *in;
|
||||
s->content_disp[s->mp] = '\0';
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!strcmp(s->temp, "name")) {
|
||||
if (s->mp < sizeof(s->name) - 1)
|
||||
s->name[s->mp++] = *in;
|
||||
s->name[s->mp] = '\0';
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!strcmp(s->temp, "filename")) {
|
||||
if (s->mp < sizeof(s->content_disp_filename) - 1)
|
||||
s->content_disp_filename[s->mp++] = *in;
|
||||
s->content_disp_filename[s->mp] = '\0';
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
in++;
|
||||
break;
|
||||
|
||||
case MT_TYPE:
|
||||
if (*in == '\x0d')
|
||||
s->state = MT_IGNORE2;
|
||||
else {
|
||||
if (s->mp < sizeof(s->content_type) - 1)
|
||||
s->content_type[s->mp++] = *in;
|
||||
s->content_type[s->mp] = '\0';
|
||||
}
|
||||
in++;
|
||||
break;
|
||||
|
||||
case MT_IGNORE1:
|
||||
if (*in == '\x0d')
|
||||
s->state = MT_IGNORE2;
|
||||
in++;
|
||||
break;
|
||||
|
||||
case MT_IGNORE2:
|
||||
s->mp = 0;
|
||||
if (*in == '\x0a')
|
||||
s->state = MT_HNAME;
|
||||
in++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_urldecode_s_destroy(struct lws_urldecode_stateful *s)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (s->state != US_IDLE)
|
||||
ret = -1;
|
||||
|
||||
if (!ret)
|
||||
if (s->output(s->data, s->name, &s->out, s->pos, 1))
|
||||
ret = -1;
|
||||
|
||||
lws_free(s);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct lws_spa {
|
||||
struct lws_urldecode_stateful *s;
|
||||
lws_spa_fileupload_cb opt_cb;
|
||||
const char * const *param_names;
|
||||
int count_params;
|
||||
char **params;
|
||||
int *param_length;
|
||||
void *opt_data;
|
||||
|
||||
char *storage;
|
||||
char *end;
|
||||
int max_storage;
|
||||
|
||||
char finalized;
|
||||
};
|
||||
|
||||
static int
|
||||
lws_urldecode_spa_lookup(struct lws_spa *spa,
|
||||
const char *name)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; n < spa->count_params; n++)
|
||||
if (!strcmp(spa->param_names[n], name))
|
||||
return n;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_urldecode_spa_cb(void *data, const char *name, char **buf, int len,
|
||||
int final)
|
||||
{
|
||||
struct lws_spa *spa =
|
||||
(struct lws_spa *)data;
|
||||
int n;
|
||||
|
||||
if (spa->s->content_disp_filename[0]) {
|
||||
if (spa->opt_cb) {
|
||||
n = spa->opt_cb(spa->opt_data, name,
|
||||
spa->s->content_disp_filename,
|
||||
*buf, len, final);
|
||||
|
||||
if (n < 0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
n = lws_urldecode_spa_lookup(spa, name);
|
||||
|
||||
if (n == -1 || !len) /* unrecognized */
|
||||
return 0;
|
||||
|
||||
if (!spa->params[n])
|
||||
spa->params[n] = *buf;
|
||||
|
||||
if ((*buf) + len >= spa->end) {
|
||||
lwsl_notice("%s: exceeded storage\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
spa->param_length[n] += len;
|
||||
|
||||
/* move it on inside storage */
|
||||
(*buf) += len;
|
||||
*((*buf)++) = '\0';
|
||||
|
||||
spa->s->out_len -= len + 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN struct lws_spa *
|
||||
lws_spa_create(struct lws *wsi, const char * const *param_names,
|
||||
int count_params, int max_storage,
|
||||
lws_spa_fileupload_cb opt_cb, void *opt_data)
|
||||
{
|
||||
struct lws_spa *spa = lws_zalloc(sizeof(*spa), "spa");
|
||||
|
||||
if (!spa)
|
||||
return NULL;
|
||||
|
||||
spa->param_names = param_names;
|
||||
spa->count_params = count_params;
|
||||
spa->max_storage = max_storage;
|
||||
spa->opt_cb = opt_cb;
|
||||
spa->opt_data = opt_data;
|
||||
|
||||
spa->storage = lws_malloc(max_storage, "spa");
|
||||
if (!spa->storage)
|
||||
goto bail2;
|
||||
spa->end = spa->storage + max_storage - 1;
|
||||
|
||||
spa->params = lws_zalloc(sizeof(char *) * count_params, "spa params");
|
||||
if (!spa->params)
|
||||
goto bail3;
|
||||
|
||||
spa->s = lws_urldecode_s_create(wsi, spa->storage, max_storage, spa,
|
||||
lws_urldecode_spa_cb);
|
||||
if (!spa->s)
|
||||
goto bail4;
|
||||
|
||||
spa->param_length = lws_zalloc(sizeof(int) * count_params,
|
||||
"spa param len");
|
||||
if (!spa->param_length)
|
||||
goto bail5;
|
||||
|
||||
lwsl_info("%s: Created SPA %p\n", __func__, spa);
|
||||
|
||||
return spa;
|
||||
|
||||
bail5:
|
||||
lws_urldecode_s_destroy(spa->s);
|
||||
bail4:
|
||||
lws_free(spa->params);
|
||||
bail3:
|
||||
lws_free(spa->storage);
|
||||
bail2:
|
||||
lws_free(spa);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_spa_process(struct lws_spa *ludspa, const char *in, int len)
|
||||
{
|
||||
if (!ludspa) {
|
||||
lwsl_err("%s: NULL spa\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
/* we reject any junk after the last part arrived and we finalized */
|
||||
if (ludspa->finalized)
|
||||
return 0;
|
||||
|
||||
return lws_urldecode_s_process(ludspa->s, in, len);
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_spa_get_length(struct lws_spa *ludspa, int n)
|
||||
{
|
||||
if (n >= ludspa->count_params)
|
||||
return 0;
|
||||
|
||||
return ludspa->param_length[n];
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN const char *
|
||||
lws_spa_get_string(struct lws_spa *ludspa, int n)
|
||||
{
|
||||
if (n >= ludspa->count_params)
|
||||
return NULL;
|
||||
|
||||
return ludspa->params[n];
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_spa_finalize(struct lws_spa *spa)
|
||||
{
|
||||
if (spa->s) {
|
||||
lws_urldecode_s_destroy(spa->s);
|
||||
spa->s = NULL;
|
||||
}
|
||||
|
||||
spa->finalized = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_spa_destroy(struct lws_spa *spa)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
lwsl_notice("%s: destroy spa %p\n", __func__, spa);
|
||||
|
||||
if (spa->s)
|
||||
lws_urldecode_s_destroy(spa->s);
|
||||
|
||||
lwsl_debug("%s %p %p %p %p\n", __func__,
|
||||
spa->param_length,
|
||||
spa->params,
|
||||
spa->storage,
|
||||
spa);
|
||||
|
||||
lws_free(spa->param_length);
|
||||
lws_free(spa->params);
|
||||
lws_free(spa->storage);
|
||||
lws_free(spa);
|
||||
|
||||
return n;
|
||||
}
|
252
lib/server/peer-limits.c
Normal file
252
lib/server/peer-limits.c
Normal file
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* libwebsockets - peer limits tracking
|
||||
*
|
||||
* Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
/* requires context->lock */
|
||||
static void
|
||||
__lws_peer_remove_from_peer_wait_list(struct lws_context *context,
|
||||
struct lws_peer *peer)
|
||||
{
|
||||
struct lws_peer *df;
|
||||
|
||||
lws_start_foreach_llp(struct lws_peer **, p, context->peer_wait_list) {
|
||||
if (*p == peer) {
|
||||
df = *p;
|
||||
|
||||
*p = df->peer_wait_list;
|
||||
df->peer_wait_list = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
} lws_end_foreach_llp(p, peer_wait_list);
|
||||
}
|
||||
|
||||
/* requires context->lock */
|
||||
static void
|
||||
__lws_peer_add_to_peer_wait_list(struct lws_context *context,
|
||||
struct lws_peer *peer)
|
||||
{
|
||||
__lws_peer_remove_from_peer_wait_list(context, peer);
|
||||
|
||||
peer->peer_wait_list = context->peer_wait_list;
|
||||
context->peer_wait_list = peer;
|
||||
}
|
||||
|
||||
|
||||
struct lws_peer *
|
||||
lws_get_or_create_peer(struct lws_vhost *vhost, lws_sockfd_type sockfd)
|
||||
{
|
||||
struct lws_context *context = vhost->context;
|
||||
socklen_t rlen = 0;
|
||||
void *q;
|
||||
uint8_t *q8;
|
||||
struct lws_peer *peer;
|
||||
uint32_t hash = 0;
|
||||
int n, af = AF_INET;
|
||||
struct sockaddr_storage addr;
|
||||
|
||||
#ifdef LWS_WITH_IPV6
|
||||
if (LWS_IPV6_ENABLED(vhost)) {
|
||||
af = AF_INET6;
|
||||
}
|
||||
#endif
|
||||
rlen = sizeof(addr);
|
||||
if (getpeername(sockfd, (struct sockaddr*)&addr, &rlen))
|
||||
return NULL;
|
||||
|
||||
if (af == AF_INET) {
|
||||
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
|
||||
q = &s->sin_addr;
|
||||
rlen = sizeof(s->sin_addr);
|
||||
} else
|
||||
#ifdef LWS_WITH_IPV6
|
||||
{
|
||||
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
|
||||
q = &s->sin6_addr;
|
||||
rlen = sizeof(s->sin6_addr);
|
||||
}
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
q8 = q;
|
||||
for (n = 0; n < rlen; n++)
|
||||
hash = (((hash << 4) | (hash >> 28)) * n) ^ q8[n];
|
||||
|
||||
hash = hash % context->pl_hash_elements;
|
||||
|
||||
lws_context_lock(context); /* <====================================== */
|
||||
|
||||
lws_start_foreach_ll(struct lws_peer *, peerx,
|
||||
context->pl_hash_table[hash]) {
|
||||
if (peerx->af == af && !memcmp(q, peerx->addr, rlen)) {
|
||||
lws_context_unlock(context); /* === */
|
||||
return peerx;
|
||||
}
|
||||
} lws_end_foreach_ll(peerx, next);
|
||||
|
||||
lwsl_info("%s: creating new peer\n", __func__);
|
||||
|
||||
peer = lws_zalloc(sizeof(*peer), "peer");
|
||||
if (!peer) {
|
||||
lws_context_unlock(context); /* === */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
context->count_peers++;
|
||||
peer->next = context->pl_hash_table[hash];
|
||||
peer->hash = hash;
|
||||
peer->af = af;
|
||||
context->pl_hash_table[hash] = peer;
|
||||
memcpy(peer->addr, q, rlen);
|
||||
time(&peer->time_created);
|
||||
/*
|
||||
* On creation, the peer has no wsi attached, so is created on the
|
||||
* wait list. When a wsi is added it is removed from the wait list.
|
||||
*/
|
||||
time(&peer->time_closed_all);
|
||||
__lws_peer_add_to_peer_wait_list(context, peer);
|
||||
|
||||
lws_context_unlock(context); /* ====================================> */
|
||||
|
||||
return peer;
|
||||
}
|
||||
|
||||
/* requires context->lock */
|
||||
static int
|
||||
__lws_peer_destroy(struct lws_context *context, struct lws_peer *peer)
|
||||
{
|
||||
lws_start_foreach_llp(struct lws_peer **, p,
|
||||
context->pl_hash_table[peer->hash]) {
|
||||
if (*p == peer) {
|
||||
struct lws_peer *df = *p;
|
||||
*p = df->next;
|
||||
lws_free(df);
|
||||
context->count_peers--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
} lws_end_foreach_llp(p, next);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
lws_peer_cull_peer_wait_list(struct lws_context *context)
|
||||
{
|
||||
struct lws_peer *df;
|
||||
time_t t;
|
||||
|
||||
time(&t);
|
||||
|
||||
if (context->next_cull && t < context->next_cull)
|
||||
return;
|
||||
|
||||
lws_context_lock(context); /* <====================================== */
|
||||
|
||||
context->next_cull = t + 5;
|
||||
|
||||
lws_start_foreach_llp(struct lws_peer **, p, context->peer_wait_list) {
|
||||
if (t - (*p)->time_closed_all > 10) {
|
||||
df = *p;
|
||||
|
||||
/* remove us from the peer wait list */
|
||||
*p = df->peer_wait_list;
|
||||
df->peer_wait_list = NULL;
|
||||
|
||||
__lws_peer_destroy(context, df);
|
||||
continue; /* we already point to next, if any */
|
||||
}
|
||||
} lws_end_foreach_llp(p, peer_wait_list);
|
||||
|
||||
lws_context_unlock(context); /* ====================================> */
|
||||
}
|
||||
|
||||
void
|
||||
lws_peer_add_wsi(struct lws_context *context, struct lws_peer *peer,
|
||||
struct lws *wsi)
|
||||
{
|
||||
if (!peer)
|
||||
return;
|
||||
|
||||
lws_context_lock(context); /* <====================================== */
|
||||
|
||||
peer->count_wsi++;
|
||||
wsi->peer = peer;
|
||||
__lws_peer_remove_from_peer_wait_list(context, peer);
|
||||
|
||||
lws_context_unlock(context); /* ====================================> */
|
||||
}
|
||||
|
||||
void
|
||||
lws_peer_track_wsi_close(struct lws_context *context, struct lws_peer *peer)
|
||||
{
|
||||
if (!peer)
|
||||
return;
|
||||
|
||||
lws_context_lock(context); /* <====================================== */
|
||||
|
||||
assert(peer->count_wsi);
|
||||
peer->count_wsi--;
|
||||
|
||||
if (!peer->count_wsi && !peer->count_ah) {
|
||||
/*
|
||||
* in order that we can accumulate peer activity correctly
|
||||
* allowing for periods when the peer has no connections,
|
||||
* we don't synchronously destroy the peer when his last
|
||||
* wsi closes. Instead we mark the time his last wsi
|
||||
* closed and add him to a peer_wait_list to be reaped
|
||||
* later if no further activity is coming.
|
||||
*/
|
||||
time(&peer->time_closed_all);
|
||||
__lws_peer_add_to_peer_wait_list(context, peer);
|
||||
}
|
||||
|
||||
lws_context_unlock(context); /* ====================================> */
|
||||
}
|
||||
|
||||
int
|
||||
lws_peer_confirm_ah_attach_ok(struct lws_context *context, struct lws_peer *peer)
|
||||
{
|
||||
if (!peer)
|
||||
return 0;
|
||||
|
||||
if (context->ip_limit_ah && peer->count_ah >= context->ip_limit_ah) {
|
||||
lwsl_info("peer reached ah limit %d, deferring\n",
|
||||
context->ip_limit_ah);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_peer_track_ah_detach(struct lws_context *context, struct lws_peer *peer)
|
||||
{
|
||||
if (!peer)
|
||||
return;
|
||||
|
||||
assert(peer->count_ah);
|
||||
peer->count_ah--;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load diff
20
lib/ssl.c
20
lib/ssl.c
|
@ -383,6 +383,26 @@ lws_ssl_destroy(struct lws_vhost *vhost)
|
|||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
lws_ssl_anybody_has_buffered_read_tsi(struct lws_context *context, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
struct lws *wsi, *wsi_next;
|
||||
|
||||
wsi = pt->pending_read_list;
|
||||
while (wsi) {
|
||||
wsi_next = wsi->pending_read_list_next;
|
||||
pt->fds[wsi->position_in_fds_table].revents |=
|
||||
pt->fds[wsi->position_in_fds_table].events & LWS_POLLIN;
|
||||
if (pt->fds[wsi->position_in_fds_table].revents & LWS_POLLIN)
|
||||
return 1;
|
||||
|
||||
wsi = wsi_next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue