Compare commits

...
Sign in to create a new pull request.

54 commits
temp ... master

Author SHA1 Message Date
7f6db4fe8d fix Spec file by adding / removing new files to the package 2017-08-27 14:59:52 +02:00
Andy Green
debb7aa043 LWS_WITH_ACCESS_LOG: add referrer to log format and quotes around user agent
This also forces any double-quotes in the UA or referrer to be single-quotes.

This aligns to log to the "combined log format" described here

https://httpd.apache.org/docs/1.3/logs.html#combined
2017-08-27 20:18:48 +08:00
Andy Green
ca045d4a8e docs: lwsws under gdb / valgrind from ml 2017-08-27 09:50:04 +08:00
Andy Green
4ce725903d lwsws: survive LWS_WITHOUT_EXTENSIONS 2017-08-26 12:18:47 +08:00
Petar Paradzik
a2943ca41d cgi: fix killing cgi before draining its output
CGI's which don't have content-length nor they are explicitly chunked
are killed immediately after being reaped even if their output has not
being drained. This is fixed by deferring from killing them like those
which are explicitly chunked.

Signed-off-by: Petar Paradzik <petar.paradzik@sartura.hr>
2017-08-26 12:16:33 +08:00
Petar Paradzik
04134742f9 cgi: fix overriding 'PATH' environment variable
Signed-off-by: Petar Paradzik <petar.paradzik@sartura.hr>
2017-08-26 12:15:51 +08:00
Andy Green
2e5110e731 cgi: provide constants for reason_bf 2017-08-26 12:15:40 +08:00
Petar Paradzik
afc9c0ac26 cgi: add support for manual chunking of CGI output
In cases when CGI output doesn't contain content-length nor it is
explicitly chunked, do manual chunking of CGI output.

Signed-off-by: Petar Paradzik <petar.paradzik@sartura.hr>
2017-08-26 12:04:15 +08:00
Petar Paradzik
5b23b8c99f cgi: remove and kill CGI after closing its STDOUT handler
Signed-off-by: Petar Paradzik <petar.paradzik@sartura.hr>
2017-08-26 12:00:16 +08:00
Petar Paradzik
b66e8e1898 cgi: fix not getting POLLHUP on fd associated to CGI STDOUT
Signed-off-by: Petar Paradzik <petar.paradzik@sartura.hr>
2017-08-26 11:59:58 +08:00
Mike Messina
0bb3646256 win32: skip delay in WSAWaitForMultipleEvents if POLLOUT expected
https://github.com/warmcat/libwebsockets/issues/994
2017-08-22 21:32:47 +08:00
Andy Green
c60b2413a4 ah: double-check timeouts on all active ah independent of wsi and dump info 2017-08-21 08:55:13 +08:00
Andy Green
58195fbc1e esp-idf v3: account for optional SHA256 when walking segments 2017-08-19 13:14:34 +08:00
Andy Green
c2abf59c68 esp32: align build system for esp-idf v3 2017-08-19 08:14:49 +08:00
Cory McWilliams
4b24369d64 Subject: Mismatched lws_zalloc / free 2017-08-17 07:30:23 +08:00
Andy Green
872e8d7e9d docs: swap _all_protocol_vhost cut and paste
https://github.com/warmcat/libwebsockets/issues/989
2017-08-16 15:21:22 +08:00
Andy Green
5da9ce2f06 ah: reuse at end of transaction has no timeout
If we complete a transaction but end up keeping the ah, we must force
a timeout on it.  Otherwise a bad bot could keep the socket open and
exhaust the ah pool.
2017-08-15 07:58:53 +08:00
lnmx
b93c057472 send content-type when LWS_WITH_RANGES=OFF
https://github.com/warmcat/libwebsockets/pull/987

With the RANGES feature disabled, lws_serve_http_file would
not add the content-type header to the response.
2017-08-12 20:50:25 +08:00
Andy Green
5a38d88fdd handle same vh protocol reinsert 2017-08-12 20:50:21 +08:00
Andy Green
a9f74f2dbe lwsws: remove no longer extant D option from help string
https://github.com/warmcat/libwebsockets/issues/986
2017-08-09 07:40:19 +08:00
Andy Green
219a367a4c esp32: allow return of default vhost at init time 2017-08-06 06:53:38 +08:00
Andy Green
93a5b586a3 lws_callback_all_protocol_vhost_args 2017-08-05 10:38:59 +08:00
Andy Green
040b408029 ping test app: avoid FPE when no packets received 2017-08-04 13:28:01 +08:00
Andy Green
16ef37ef5d close path: make sure a second time timeout and ssl buffered lists are scrubbed
lws_meta children can have a different close path
2017-08-04 13:27:34 +08:00
Andy Green
e6bd6296bd v2.3.0 2017-07-28 14:27:25 +08:00
Andy Green
4a9c23e9ec coverity 182069: coverity confused by use of bool as array index 2017-07-28 14:25:25 +08:00
Andy Green
c6233ce403 coverity 182068: 155650: unnecessary check against illegal NULL 2017-07-28 14:19:24 +08:00
Andy Green
7849c5a8ad pmd: autobahn fixes 2017-07-28 13:12:03 +08:00
Andy Green
414f114b8f attack.sh: adapt to changes 2017-07-28 07:04:54 +08:00
Andy Green
855f7e8712 log: downgrade logging for ah wait 2017-07-28 07:04:47 +08:00
Andy Green
9f31e94e09 correct status payload size 2017-07-28 07:03:57 +08:00
Andy Green
855453d1ae lws_meta: explicitly declare all of lws_protocols members for ESP32 2017-07-27 08:27:34 +08:00
Andy Green
d86641ed3a libevent: update to use static plugins and work with new libevent2
Plus fix broken indent style
2017-07-27 07:57:59 +08:00
Andy Green
41c15511eb test-server-libuv: add lws_meta 2017-07-27 07:29:56 +08:00
Andy Green
d766c99861 dummy handler: LWS_CALLBACK_HTTP_FILE_COMPLETION 2017-07-27 07:26:00 +08:00
Andy Green
ba45f7cf9f ah: allow configurable ah hold timeout 2017-07-26 11:49:41 +08:00
Andy Green
19a320a578 http2: remove cmake option leave code in for now
https://github.com/warmcat/libwebsockets/issues/979
2017-07-25 17:36:31 +08:00
namowen
61e58885f4 client: ipv6 reject when lws_getaddrinfo46 failed
https://github.com/warmcat/libwebsockets/issues/978
2017-07-25 17:14:37 +08:00
Andy Green
3562e441e3 client-fix-header-stash-leak-on-close-before-success 2017-07-21 21:49:24 +08:00
Andy Green
003bd7dcee client: fix hdr stash leak 2017-07-21 21:34:46 +08:00
Andy Green
75bbb3b2c0 client: always set port even if sockfd already created 2017-07-21 21:34:46 +08:00
Andy Green
8ccc64679f client: fix redirect ssl to ssl 2017-07-21 20:25:32 +08:00
Andy Green
6c09952065 url cleaning: leave // after http[s]: alone 2017-07-21 20:04:02 +08:00
Andy Green
09f3947b4c lws_intptr_t: fix ordering
https://github.com/warmcat/libwebsockets/issues/973
2017-07-21 19:25:41 +08:00
Andy Green
941e93ea33 test-server-libuv: also call context_destroy2 when using foreign loop
https://github.com/warmcat/libwebsockets/issues/972
2017-07-21 11:09:03 +08:00
Andy Green
c9da1ffa2e appveyor: remove cache 2017-07-19 15:29:38 +08:00
Andy Green
ad15082563 coverity-181580: supposedly dead code 2017-07-19 14:47:30 +08:00
Andy Green
2d313bdc02 coverity 181577: lejp_conf loop on calling uv_loop_close to keep coverity happy 2017-07-19 14:37:04 +08:00
Andy Green
3526fde154 coverity 181573: false positive since lws_is_ssl returns a bool 2017-07-19 14:37:04 +08:00
Andy Green
bd1dd7efd4 coverity 181576: remove dead code to keep coverity happy 2017-07-19 14:37:04 +08:00
Andy Green
1690581cd2 coverity 181574: confirm uri_ptr non-null before deref 2017-07-19 14:19:03 +08:00
Andy Green
3c360d5192 coverity 181579: check result of malloc as intended 2017-07-19 14:17:39 +08:00
Andy Green
8a4881a142 coverity 181575: check vhost iface non-null if using via bind_iface 2017-07-19 14:16:32 +08:00
Andy Green
6f11c1361a lws-meta 2017-07-19 08:59:42 +08:00
43 changed files with 2214 additions and 447 deletions

View file

@ -11,7 +11,6 @@ env:
- LWS_METHOD=noext CMAKE_ARGS="-DLWS_WITHOUT_EXTENSIONS=ON"
- LWS_METHOD=libev CMAKE_ARGS="-DLWS_WITH_LIBEV=ON"
- LWS_METHOD=noipv6 CMAKE_ARGS="-DLWS_IPV6=OFF"
- LWS_METHOD=http2 CMAKE_ARGS="-DLWS_WITH_HTTP2=ON"
- LWS_METHOD=nossl CMAKE_ARGS="-DLWS_WITH_SSL=OFF"
- LWS_METHOD=nodaemon CMAKE_ARGS="-DLWS_WITHOUT_DAEMONIZE=ON"
- LWS_METHOD=cgi CMAKE_ARGS="-DLWS_WITH_CGI=ON"

View file

@ -9,12 +9,12 @@ project(libwebsockets C)
set(PACKAGE "libwebsockets")
set(CPACK_PACKAGE_NAME "${PACKAGE}")
set(CPACK_PACKAGE_VERSION_MAJOR "2")
set(CPACK_PACKAGE_VERSION_MINOR "2")
set(CPACK_PACKAGE_VERSION_MINOR "3")
set(CPACK_PACKAGE_VERSION_PATCH "0")
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
set(CPACK_PACKAGE_VENDOR "andy@warmcat.com")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PACKAGE} ${PACKAGE_VERSION}")
set(SOVERSION "10")
set(SOVERSION "11")
if(NOT CPACK_GENERATOR)
if(UNIX)
set(CPACK_GENERATOR "TGZ")
@ -95,7 +95,7 @@ option(LWS_WITH_LATENCY "Build latency measuring code into the library" OFF)
option(LWS_WITHOUT_DAEMONIZE "Don't build the daemonization api" ON)
option(LWS_IPV6 "Compile with support for ipv6" OFF)
option(LWS_UNIX_SOCK "Compile with support for UNIX domain socket" OFF)
option(LWS_WITH_HTTP2 "Compile with support for http2" OFF)
#option(LWS_WITH_HTTP2 "Compile with support for http2" OFF)
option(LWS_SSL_SERVER_WITH_ECDH_CERT "Include SSL server use ECDH certificate" OFF)
option(LWS_WITH_CGI "Include CGI (spawn process with network-connected stdin/out/err) APIs" OFF)
option(LWS_WITH_HTTP_PROXY "Support for rewriting HTTP proxying (requires libhubbub)" OFF)
@ -1443,6 +1443,8 @@ if (NOT LWS_WITHOUT_TESTAPPS)
endmacro()
create_plugin(protocol_lws_meta
"plugins/protocol_lws_meta.c" "" "")
create_plugin(protocol_dumb_increment
"plugins/protocol_dumb_increment.c" "" "")
create_plugin(protocol_lws_mirror

192
README.lws-meta.md Normal file
View file

@ -0,0 +1,192 @@
# lws-meta protocol
lws-meta is a lightweight ws subprotocol that accepts other ws connections
to the same server inside it and multiplexes their access to the connection.
```
Client Server
conn1: \ / :conn1
conn2: = mux ------ lws-meta ws protocol ----- mux = :conn2
conn3: / \ :conn3
```
You may have n client ws connections back to the server, but you now
only have one tcp connection (and one SSL wrapper if using SSL) instead
of n of those.
If you currently make multiple ws connections back to the server, so you
can have different protocols active in one webpage, this if for you.
- The subprotocol code for the connections inside a lws-meta connection
need zero changes from being a normal ws connection. It is unaware
it is inside an lws-meta parent connection.
- The traffic on the lws-meta connection is indistinguishable from
standard ws traffic, so intermediaries won't object to it
- The multiplexing is done in the protocol, **not by an extension**. So
it's compatible with all browsers.
- Javascript helper code is provided to very simply use lws-meta
protocol instead of direct connections. The lws test server has
been converted to use this by default.
# Converting your server
1) include the provided lws-meta plugin (plugins/protocl_lws_meta.c) as an
active protocol for your server. You can do that using runtime plugins, or
include the plugin sources into your server at build-time. The lws test
server uses the latter approach.
That's all you need to do on the server side.
# Converting your browser JS
1) import lws-common.js
2) Instantiate a parent lws-meta connection object
```
var lws_meta = new lws_meta_ws();
```
3) Connect the lws-meta object to your server
```
lws_meta.new_parent(get_appropriate_ws_url("?mirror=" + mirror_name));
```
4) Convert your actual ws connections to go via the lws_meta object
```
var my_ws = lws_meta.new_ws("", "dumb-increment-protocol");
```
The first arg is the URL path, the second arg is the ws protocol you want.
That's it. my_ws will get `onopen()`, `onmessage()` etc calls as before.
# lws-meta wire protocol
lws-meta works by adding some bytes at the start of a message indicating
which channel the message applies to.
Channel messages are atomic on the wire. The reason is if we tried to
intersperse other channel fragments between one channels message fragments,
an intermediary would observe violations of the ws framing rule about
having to start a message with TEXT or BINARY, and use only CONTINUATION
for the subsequent fragments. Eg
```
[ ch1 TEXT NOFIN ] [ ch2 BINARY FIN ] [ ch1 CONTINUATION FIN ]
```
is illegal to an observer that doesn't understand lws-meta headers in the
packet payloads. So to avoid this situation, only complete messages may
be sent from one subchannel in each direction at a time.
Consequently, only the first fragment of each message is modified to
have the extra two bytes identifying the subchannel it is aimed at, since
the rest of the message from the same subchannel is defined to follow.
If it makes latencies, modify the protocol sending large messages to
send smaller messages, so the transmission of messages from other channels
can be sent inbetween the smaller messages.
## lws-meta commands
1) CSTRING indicates a string terminated by 0x00 byte
2) Channel IDs are sent with 0x20 added to them, to guarantee valid UTF-8
### 0x41: RX: LWS_META_CMD_OPEN_SUBCHANNEL
- CSTRING: protocol name
- CSTRING: url
- CSTRING: cookie (7 bytes max)
Client is requesting to open a new channel with the given protocol name,
at the given url. The cookie (eg, channel name) is only used in
LWS_META_CMD_OPEN_RESULT, when the channel id is assigned, so it is
applied to the right channel.
### 0x42: TX: LWS_META_CMD_OPEN_RESULT
- CSTRING cookie
- BYTE channel id (0 indicates failed)
- CSTRING: selected protocol name
The server is informing the client of the results of a previous
open request. The cookie the client sent to identify the request
is returned along with a channel id to be used subsequently. If
the channel ID is 0 (after subtracting the transport offset of
0x20) then the open request has failed.
### 0x43: TX: LWS_META_CMD_CLOSE_NOTIFY
- BYTE channel id
- BYTE: payload length + 0x20
- BYTE: close code MSB
- BYTE: close code LSB
- PAYLOAD: payload (< 123 bytes)
Server notifies the client that a child has closed, for whatever reason.
### 0x44: RX: LWS_META_CMD_CLOSE_RQ
- BYTE: channel id
- BYTE: payload length + 0x20
- BYTE: close code MSB
- BYTE: close code LSB
- PAYLOAD: payload (< 123 bytes)
The client requests to close a child connection
### 0x45: TX: LWS_META_CMD_WRITE
- BYTE: channel id
Normal write of payload n from lws-meta perspective is actually
LWS_META_CMD_WRITE, channel id, then (n - 2) bytes of payload
The command only appears at the start of a message, continuations do
not have the command.
## Protocol Notes
- Once the subchannel is up, overhead is only +2 bytes per message
- Close reasons are supported in both directions
- Ping and Pong are only supported at the lws-meta level, using normal ws ping and pong packets.
- Only the final close of the tcp lws-meta connection itself goes out as
a normal ws close frame. Subchannels close is done in a normal TEXT
message using LWS_META_CMD_CLOSE_RQ and then the close packet payload.
This is so intermediaries do not mistake subchannel closures for the
tcp / ws link going down.
Messages that start with LWS_META_CMD_OPEN_SUBCHANNEL only contain those
commands but may contain any number of them for the whole duration of the
message. The lws-meta js support collects child open requests made before
the parent lws-meta connection is open, and dumps them all in a single
message when it does open.
Messages that start with LWS_META_CMD_OPEN_RESULT or LWS_META_CMD_CLOSE_NOTIFY
only contain those two commands, but they may contain any number of them
for the whole duration of the message.
# Current Implemention Limitations
- only server side is supported in lws. The client side JS for
a browser is supported.
- max number of child connections per parent at the moment is 8
- child connection URL paramter when opening the connection is
ignored
- there is no ah attached when the child connections are
established inside the lws-meta parent. So header access
functions will fail.

View file

@ -576,3 +576,26 @@ Prepare the log directory like this
sudo mkdir /var/log/lwsws
sudo chmod 700 /var/log/lwsws
```
@section lwswsgdb Debugging lwsws with gdb
Hopefully you won't need to debug lwsws itself, but you may want to debug your plugins. start lwsws like this to have everything running under gdb
```
sudo gdb -ex "set follow-fork-mode child" -ex "run" --args /usr/local/bin/lwsws
```
this will give nice backtraces in lwsws itself and in plugins, if they were built with symbols.
@section lwswsvgd Running lwsws under valgrind
You can just run lwsws under galgrind as usual and get valid results. However the results / analysis part of valgrind runs
after the plugins have removed themselves, this means valgrind backtraces into plugin code is opaque, without
source-level info because the dynamic library is gone.
There's a simple workaround, use LD_PRELOAD=<plugin.so> before running lwsws, this has the loader bring the plugin
in before executing lwsws as if it was a direct dependency. That means it's still mapped until the whole process
exits after valgtind has done its thing.

View file

@ -8,14 +8,13 @@ libwebsockets
News
----
v2.3 is out... see the changelog https://github.com/warmcat/libwebsockets/blob/v2.3-stable/changelog
ESP32 is now supported in lws! Download the
- factory https://github.com/warmcat/lws-esp32-factory and
- test server app https://github.com/warmcat/lws-esp32-test-server-demos
v2.2 is out... see the changelog https://github.com/warmcat/libwebsockets/blob/v2.2-stable/changelog
This is the libwebsockets C library for lightweight websocket clients and
servers. For support, visit

View file

@ -22,8 +22,8 @@ install:
- mkdir c:\assets\libuv
- 7z x -oc:\assets\libuv win-libuv.zip
# - appveyor DownloadFile https://slproweb.com/download/Win32OpenSSL-1_0_2h.exe
- appveyor DownloadFile https://libwebsockets.org:444/Win32OpenSSL-1_0_2h.exe
- Win32OpenSSL-1_0_2h.exe /silent /verysilent /sp- /suppressmsgboxes
# - appveyor DownloadFile https://libwebsockets.org:444/Win32OpenSSL-1_0_2L.exe
# - Win32OpenSSL-1_0_2L.exe /silent /verysilent /sp- /suppressmsgboxes
- appveyor DownloadFile https://libwebsockets.org:444/nsis-3.0rc1-setup.exe
- cmd /c start /wait nsis-3.0rc1-setup.exe /S /D=C:\nsis
- appveyor DownloadFile https://libwebsockets.org:444/sqlite-dll-win32-x86-3130000.zip
@ -51,8 +51,8 @@ artifacts:
name: lws.zip
type: Zip
cache:
- C:\OpenSSL-Win32
#cache:
# - C:\OpenSSL-Win32
matrix:
fast_finish: true

View file

@ -6,7 +6,7 @@ N=1
OS=`uname`
for i in '1.1.1' '1.1.2' '1.1.3' '1.1.4' '1.1.5' '1.1.6' '1.1.7' '1.1.8' '1.2.1' '1.2.2' '1.2.3' '1.2.4' '1.2.5' '1.2.6' '1.2.7' '1.2.8' '2.1' '2.2' '2.3' '2.4' '2.5' '2.6' '2.7' '2.8' '2.9' '2.10' '2.11' '3.1' '3.2' '3.3' '3.4' '3.5' '3.6' '3.7' '4.1.1' '4.1.2' '4.1.3' '4.1.4' '4.1.5' '4.2.1' '4.2.2' '4.2.3' '4.2.4' '4.2.5' '5.1' '5.2' '5.3' '5.4' '5.5' '5.6' '5.7' '5.8' '5.9' '5.10' '5.11' '5.12' '5.13' '5.14' '5.15' '5.16' '5.17' '5.18' '5.19' '5.20' '6.1.1' '6.1.2' '6.1.3' '6.2.1' '6.2.2' '6.2.3' '6.2.4' '6.3.1' '6.3.2' '6.4.1' '6.4.2' '6.4.3' '6.4.4' '6.5.1' '6.5.2' '6.5.3' '6.5.4' '6.5.5' '6.6.1' '6.6.2' '6.6.3' '6.6.4' '6.6.5' '6.6.6' '6.6.7' '6.6.8' '6.6.9' '6.6.10' '6.6.11' '6.7.1' '6.7.2' '6.7.3' '6.7.4' '6.8.1' '6.8.2' '6.9.1' '6.9.2' '6.9.3' '6.9.4' '6.10.1' '6.10.2' '6.10.3' '6.11.1' '6.11.2' '6.11.3' '6.11.4' '6.11.5' '6.12.1' '6.12.2' '6.12.3' '6.12.4' '6.12.5' '6.12.6' '6.12.7' '6.12.8' '6.13.1' '6.13.2' '6.13.3' '6.13.4' '6.13.5' '6.14.1' '6.14.2' '6.14.3' '6.14.4' '6.14.5' '6.14.6' '6.14.7' '6.14.8' '6.14.9' '6.14.10' '6.15.1' '6.16.1' '6.16.2' '6.16.3' '6.17.1' '6.17.2' '6.17.3' '6.17.4' '6.17.5' '6.18.1' '6.18.2' '6.18.3' '6.18.4' '6.18.5' '6.19.1' '6.19.2' '6.19.3' '6.19.4' '6.19.5' '6.20.1' '6.20.2' '6.20.3' '6.20.4' '6.20.5' '6.20.6' '6.20.7' '6.21.1' '6.21.2' '6.21.3' '6.21.4' '6.21.5' '6.21.6' '6.21.7' '6.21.8' '6.22.1' '6.22.2' '6.22.3' '6.22.4' '6.22.5' '6.22.6' '6.22.7' '6.22.8' '6.22.9' '6.22.10' '6.22.11' '6.22.12' '6.22.13' '6.22.14' '6.22.15' '6.22.16' '6.22.17' '6.22.18' '6.22.19' '6.22.20' '6.22.21' '6.22.22' '6.22.23' '6.22.24' '6.22.25' '6.22.26' '6.22.27' '6.22.28' '6.22.29' '6.22.30' '6.22.31' '6.22.32' '6.22.33' '6.22.34' '6.23.1' '6.23.2' '6.23.3' '6.23.4' '6.23.5' '6.23.6' '6.23.7' '7.1.1' '7.1.2' '7.1.3' '7.1.4' '7.1.5' '7.1.6' '7.3.1' '7.3.2' '7.3.3' '7.3.4' '7.3.5' '7.3.6' '7.5.1' '7.7.1' '7.7.2' '7.7.3' '7.7.4' '7.7.5' '7.7.6' '7.7.7' '7.7.8' '7.7.9' '7.7.10' '7.7.11' '7.7.12' '7.7.13' '7.9.1' '7.9.2' '7.9.3' '7.9.4' '7.9.5' '7.9.6' '7.9.7' '7.9.8' '7.9.9' '7.9.10' '7.9.11' '7.9.12' '7.9.13' '7.13.1' '7.13.2' '9.1.1' '9.1.2' '9.1.3' '9.1.4' '9.1.5' '9.1.6' '9.2.1' '9.2.2' '9.2.3' '9.2.4' '9.2.5' '9.2.6' '9.3.1' '9.3.2' '9.3.3' '9.3.4' '9.3.5' '9.3.6' '9.3.7' '9.3.8' '9.3.9' '9.4.1' '9.4.2' '9.4.3' '9.4.4' '9.4.5' '9.4.6' '9.4.7' '9.4.8' '9.4.9' '9.5.1' '9.5.2' '9.5.3' '9.5.4' '9.5.5' '9.5.6' '9.6.1' '9.6.2' '9.6.3' '9.6.4' '9.6.5' '9.6.6' '9.7.1' '9.7.2' '9.7.3' '9.7.4' '9.7.5' '9.7.6' '9.8.1' '9.8.2' '9.8.3' '9.8.4' '9.8.5' '9.8.6' '10.1.1' '12.1.1' '12.1.2' '12.1.3' '12.1.4' '12.1.5' '12.1.6' '12.1.7' '12.1.8' '12.1.9' '12.1.10' '12.1.11' '12.1.12' '12.1.13' '12.1.14' '12.1.15' '12.1.16' '12.1.17' '12.1.18' '12.2.1' '12.2.2' '12.2.3' '12.2.4' '12.2.5' '12.2.6' '12.2.7' '12.2.8' '12.2.9' '12.2.10' '12.2.11' '12.2.12' '12.2.13' '12.2.14' '12.2.15' '12.2.16' '12.2.17' '12.2.18' '12.3.1' '12.3.2' '12.3.3' '12.3.4' '12.3.5' '12.3.6' '12.3.7' '12.3.8' '12.3.9' '12.3.10' '12.3.11' '12.3.12' '12.3.13' '12.3.14' '12.3.15' '12.3.16' '12.3.17' '12.3.18' '12.4.1' '12.4.2' '12.4.3' '12.4.4' '12.4.5' '12.4.6' '12.4.7' '12.4.8' '12.4.9' '12.4.10' '12.4.11' '12.4.12' '12.4.13' '12.4.14' '12.4.15' '12.4.16' '12.4.17' '12.4.18' '12.5.1' '12.5.2' '12.5.3' '12.5.4' '12.5.5' '12.5.6' '12.5.7' '12.5.8' '12.5.9' '12.5.10' '12.5.11' '12.5.12' '12.5.13' '12.5.14' '12.5.15' '12.5.16' '12.5.17' '12.5.18' '13.1.1' '13.1.2' '13.1.3' '13.1.4' '13.1.5' '13.1.6' '13.1.7' '13.1.8' '13.1.9' '13.1.10' '13.1.11' '13.1.12' '13.1.13' '13.1.14' '13.1.15' '13.1.16' '13.1.17' '13.1.18' '13.2.1' '13.2.2' '13.2.3' '13.2.4' '13.2.5' '13.2.6' '13.2.7' '13.2.8' '13.2.9' '13.2.10' '13.2.11' '13.2.12' '13.2.13' '13.2.14' '13.2.15' '13.2.16' '13.2.17' '13.2.18' '13.3.1' '13.3.2' '13.3.3' '13.3.4' '13.3.5' '13.3.6' '13.3.7' '13.3.8' '13.3.9' '13.3.10' '13.3.11' '13.3.12' '13.3.13' '13.3.14' '13.3.15' '13.3.16' '13.3.17' '13.3.18' '13.4.1' '13.4.2' '13.4.3' '13.4.4' '13.4.5' '13.4.6' '13.4.7' '13.4.8' '13.4.9' '13.4.10' '13.4.11' '13.4.12' '13.4.13' '13.4.14' '13.4.15' '13.4.16' '13.4.17' '13.4.18' '13.5.1' '13.5.2' '13.5.3' '13.5.4' '13.5.5' '13.5.6' '13.5.7' '13.5.8' '13.5.9' '13.5.10' '13.5.11' '13.5.12' '13.5.13' '13.5.14' '13.5.15' '13.5.16' '13.5.17' '13.5.18' '13.6.1' '13.6.2' '13.6.3' '13.6.4' '13.6.5' '13.6.6' '13.6.7' '13.6.8' '13.6.9' '13.6.10' '13.6.11' '13.6.12' '13.6.13' '13.6.14' '13.6.15' '13.6.16' '13.6.17' '13.6.18' '13.7.1' '13.7.2' '13.7.3' '13.7.4' '13.7.5' '13.7.6' '13.7.7' '13.7.8' '13.7.9' '13.7.10' '13.7.11' '13.7.12' '13.7.13' '13.7.14' '13.7.15' '13.7.16' '13.7.17' '13.7.18' ; do
libwebsockets-test-echo --client localhost --port 9001 -u "/runCase?case=$N&agent=libwebsockets" -v -n 1 &
libwebsockets-test-echo --client 127.0.0.1 --port 9001 -u "/runCase?case=$N&agent=libwebsockets" -v -n 1 &
C=99
while [ $C -gt 8 ] ; do

View file

@ -1,6 +1,43 @@
Changelog
---------
v2.3.0
======
- ESP32 OpenSSL support for client and server
- ESP32 4 x WLAN credential slots may be configured
- Libevent event loop support
- SOCKS5 proxy support
- lws_meta protocol for websocket connection multiplexing
- lws_vhost_destroy() added... allows dynamic removal of listening
vhosts. Vhosts with shared listen sockets adopt the listen socket
automatically if the owner is destroyed.
- IPv6 on Windows
- Improved CGI handling suitable for general CGI scripting, eg, PHP
- Convert even the "old style" test servers to use statically included
plugin sources
- LWS_WITH_STATS cmake option dumps resource usage and timing information
every few seconds to debug log, including latency information about
delay from asking for writeable callback to getting it
- Large (> 2GB) files may be served
- LWS_WITH_HTTP_PROXY Cmake option adds proxying mounts
- Workaround for libev build by disabling -Werror on the test app
- HTTP2 support disabled since no way to serve websockets on it
v2.2.0
======

View file

@ -111,6 +111,14 @@ lws_client_connect_2(struct lws *wsi)
#ifdef LWS_USE_IPV6
if (wsi->ipv6) {
if (n) {
/* lws_getaddrinfo46 failed, there is no usable result */
lwsl_notice("%s: lws_getaddrinfo46 failed %d\n",
__func__, n);
cce = "ipv6 lws_getaddrinfo46 failed";
goto oom4;
}
memset(&sa46, 0, sizeof(sa46));
sa46.sa6.sin6_family = AF_INET6;
@ -213,15 +221,11 @@ lws_client_connect_2(struct lws *wsi)
#endif
#ifdef LWS_USE_IPV6
if (wsi->ipv6) {
sa46.sa6.sin6_port = htons(port);
if (wsi->ipv6)
wsi->desc.sockfd = socket(AF_INET6, SOCK_STREAM, 0);
} else
else
#endif
{
sa46.sa4.sin_port = htons(port);
wsi->desc.sockfd = socket(AF_INET, SOCK_STREAM, 0);
}
if (!lws_socket_is_valid(wsi->desc.sockfd)) {
lwsl_warn("Unable to open socket\n");
@ -276,11 +280,15 @@ lws_client_connect_2(struct lws *wsi)
}
#ifdef LWS_USE_IPV6
if (wsi->ipv6)
if (wsi->ipv6) {
sa46.sa6.sin6_port = htons(port);
n = sizeof(struct sockaddr_in6);
else
} else
#endif
{
sa46.sa4.sin_port = htons(port);
n = sizeof(struct sockaddr);
}
if (connect(wsi->desc.sockfd, (const struct sockaddr *)&sa46, n) == -1 ||
LWS_ERRNO == LWS_EISCONN) {
@ -454,15 +462,6 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
}
wsi->redirects++;
#ifdef LWS_OPENSSL_SUPPORT
wsi->use_ssl = ssl;
#else
if (ssl) {
lwsl_err("%s: not configured for ssl\n", __func__);
return NULL;
}
#endif
p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN);
if (p)
strncpy(origin, p, sizeof(origin) - 1);
@ -479,11 +478,15 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
if (p)
strncpy(method, p, sizeof(iface) - 1);
lwsl_debug("redirect ads='%s', port=%d, path='%s', ssl = %d\n",
lwsl_notice("redirect ads='%s', port=%d, path='%s', ssl = %d\n",
address, port, path, ssl);
/* close the connection by hand */
#ifdef LWS_OPENSSL_SUPPORT
lws_ssl_close(wsi);
#endif
#ifdef LWS_USE_LIBUV
if (LWS_LIBUV_ENABLED(wsi->context)) {
lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi);
@ -502,6 +505,15 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
remove_wsi_socket_from_fds(wsi);
#ifdef LWS_OPENSSL_SUPPORT
wsi->use_ssl = ssl;
#else
if (ssl) {
lwsl_err("%s: not configured for ssl\n", __func__);
return NULL;
}
#endif
wsi->desc.sockfd = LWS_SOCK_INVALID;
wsi->state = LWSS_CLIENT_UNCONNECTED;
wsi->protocol = NULL;

View file

@ -573,7 +573,7 @@ lws_http_transaction_completed_client(struct lws *wsi)
/* we don't support chained client connections yet */
return 1;
#if 0
/* otherwise set ourselves up ready to go again */
wsi->state = LWSS_CLIENT_HTTP_ESTABLISHED;
wsi->mode = LWSCM_HTTP_CLIENT_ACCEPTED;
@ -598,6 +598,7 @@ lws_http_transaction_completed_client(struct lws *wsi)
lwsl_info("%s: %p: keep-alive await new transaction\n", __func__, wsi);
return 0;
#endif
}
LWS_VISIBLE LWS_EXTERN unsigned int
@ -630,6 +631,8 @@ lws_client_interpret_server_handshake(struct lws *wsi)
int more = 1;
void *v;
#endif
if (wsi->u.hdr.stash)
lws_free_set_NULL(wsi->u.hdr.stash);
ah = wsi->u.hdr.ah;
if (!wsi->do_ws) {

View file

@ -237,22 +237,36 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
#endif
return -1;
break;
#if !defined(LWS_NO_SERVER)
case LWS_CALLBACK_HTTP_FILE_COMPLETION:
if (lws_http_transaction_completed(wsi))
return -1;
break;
#endif
case LWS_CALLBACK_HTTP_WRITEABLE:
#ifdef LWS_WITH_CGI
if (wsi->reason_bf & 1) {
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI) {
if (lws_cgi_write_split_stdout_headers(wsi) < 0)
return -1;
if (wsi->reason_bf & 8)
wsi->reason_bf &= ~8;
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_HEADERS)
wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__CGI_HEADERS;
else
wsi->reason_bf &= ~1;
wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__CGI;
break;
}
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_CHUNK_END) {
n = lws_write(wsi, (unsigned char *)"0\x0d\x0a\x0d\x0a",
5, LWS_WRITE_HTTP);
if (n < 0)
return -1;
break;
}
#endif
#if defined(LWS_WITH_HTTP_PROXY)
if (wsi->reason_bf & 2) {
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__PROXY) {
char *px = buf + LWS_PRE;
int lenx = sizeof(buf) - LWS_PRE;
/*
@ -262,8 +276,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
* is the smaller.
*/
wsi->reason_bf &= ~2;
wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__PROXY;
if (!lws_get_child(wsi))
break;
if (lws_http_client_read(lws_get_child(wsi), &px, &lenx) < 0)
@ -279,7 +292,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
assert(lws_get_parent(wsi));
if (!lws_get_parent(wsi))
break;
lws_get_parent(wsi)->reason_bf |= 2;
lws_get_parent(wsi)->reason_bf |= LWS_CB_REASON_AUX_BF__PROXY;
lws_callback_on_writable(lws_get_parent(wsi));
break;
@ -351,7 +364,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
/* TBD stdin rx flow control */
break;
case LWS_STDOUT:
wsi->reason_bf |= 1;
wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI;
/* when writing to MASTER would not block */
lws_callback_on_writable(wsi);
break;
@ -369,6 +382,11 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
break;
case LWS_CALLBACK_CGI_TERMINATED:
if (!wsi->cgi->explicitly_chunked && !wsi->cgi->content_length) {
/* send terminating chunk */
wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI_CHUNK_END;
lws_callback_on_writable(wsi);
}
return -1;
case LWS_CALLBACK_CGI_STDIN_DATA: /* POST body for stdin */
@ -470,6 +488,11 @@ lws_create_vhost(struct lws_context *context,
else
vh->keepalive_timeout = 5;
if (info->timeout_secs_ah_idle)
vh->timeout_secs_ah_idle = info->timeout_secs_ah_idle;
else
vh->timeout_secs_ah_idle = 10;
/*
* give the vhost a unified list of protocols including the
* ones that came from plugins
@ -524,7 +547,7 @@ lws_create_vhost(struct lws_context *context,
vh->protocols = lwsp;
else {
vh->protocols = info->protocols;
free(lwsp);
lws_free(lwsp);
}
vh->same_vh_protocol_list = (struct lws **)

View file

@ -94,13 +94,16 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
case LWS_EXT_CB_OPTION_SET:
oa = in;
lwsl_info("%s: option set: idx %d, %s, len %d\n", __func__,
lwsl_notice("%s: option set: idx %d, %s, len %d\n", __func__,
oa->option_index, oa->start, oa->len);
if (oa->start)
priv->args[oa->option_index] = atoi(oa->start);
else
priv->args[oa->option_index] = 1;
if (priv->args[PMD_CLIENT_MAX_WINDOW_BITS] == 8)
priv->args[PMD_CLIENT_MAX_WINDOW_BITS] = 9;
lws_extension_pmdeflate_restrict_args(wsi, priv);
break;
@ -325,16 +328,18 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
case LWS_EXT_CB_PAYLOAD_TX:
if (!priv->tx_init)
if (deflateInit2(&priv->tx, priv->args[PMD_COMP_LEVEL],
if (!priv->tx_init) {
n = deflateInit2(&priv->tx, priv->args[PMD_COMP_LEVEL],
Z_DEFLATED,
-priv->args[PMD_CLIENT_MAX_WINDOW_BITS +
!wsi->vhost->listen_port],
-priv->args[PMD_SERVER_MAX_WINDOW_BITS +
(wsi->vhost->listen_port <= 0)],
priv->args[PMD_MEM_LEVEL],
Z_DEFAULT_STRATEGY) != Z_OK) {
lwsl_ext("inflateInit2 failed\n");
Z_DEFAULT_STRATEGY);
if (n != Z_OK) {
lwsl_ext("inflateInit2 failed %d\n", n);
return 1;
}
}
priv->tx_init = 1;
if (!priv->buf_tx_deflated)
priv->buf_tx_deflated = lws_malloc(LWS_PRE + 7 + 5 +
@ -436,7 +441,9 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
break;
priv->compressed_out = 0;
if ((*(eff_buf->token) & 0x80) && priv->args[PMD_CLIENT_NO_CONTEXT_TAKEOVER]) {
if ((*(eff_buf->token) & 0x80) &&
priv->args[PMD_CLIENT_NO_CONTEXT_TAKEOVER]) {
lwsl_debug("PMD_CLIENT_NO_CONTEXT_TAKEOVER\n");
(void)deflateEnd(&priv->tx);
priv->tx_init = 0;
}

View file

@ -62,7 +62,7 @@ lws_ext_parse_options(const struct lws_extension *ext, struct lws *wsi,
oa.option_index = n;
lwsl_ext("hit %d\n", oa.option_index);
leap = LEAPS_SEEK_VAL;
if (len ==1)
if (len == 1)
goto set_arg;
break;
}

View file

@ -238,7 +238,7 @@ lws_return_http_status(struct lws *wsi, unsigned int code,
&p, end))
return 1;
len = 37 + strlen(html_body) + sprintf(slen, "%d", code);
len = 35 + strlen(html_body) + sprintf(slen, "%d", code);
n = sprintf(slen, "%d", len);
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,

View file

@ -776,7 +776,8 @@ lwsws_get_config_d(void *user, const char *d, const char * const *paths,
bail:
uv_fs_req_cleanup(&req);
uv_loop_close(&loop);
while (uv_loop_close(&loop))
;
return ret;
}

View file

@ -39,12 +39,15 @@ lws_event_cb(evutil_socket_t sock_fd, short revents, void *ctx)
if (revents & EV_TIMEOUT)
return;
/* !!! EV_CLOSED doesn't exist in libevent2 */
#if LIBEVENT_VERSION_NUMBER < 0x02000000
if (revents & EV_CLOSED)
{
event_del(lws_io->event_watcher);
event_free(lws_io->event_watcher);
return;
}
#endif
eventfd.fd = sock_fd;
eventfd.events = 0;

View file

@ -65,9 +65,14 @@ static const char * const log_level_names[] = {
void
lws_free_wsi(struct lws *wsi)
{
struct lws_context_per_thread *pt;
int n;
if (!wsi)
return;
pt = &wsi->context->pt[(int)wsi->tsi];
/* Protocol user data may be allocated either internally by lws
* or by specified the user.
* We should only free what we allocated. */
@ -80,8 +85,27 @@ lws_free_wsi(struct lws *wsi)
/* we may not have an ah, but may be on the waiting list... */
lwsl_info("ah det due to close\n");
/* we're closing, losing some rx is OK */
lws_header_table_force_to_detachable_state(wsi);
lws_header_table_detach(wsi, 0);
lws_pt_lock(pt);
for (n = 0; n < wsi->context->max_http_header_pool; n++) {
if (pt->ah_pool[n].in_use &&
pt->ah_pool[n].wsi == wsi) {
lwsl_err("%s: ah leak: wsi %p\n", __func__, wsi);
pt->ah_pool[n].in_use = 0;
pt->ah_pool[n].wsi = NULL;
pt->ah_count_in_use--;
}
}
lws_pt_unlock(pt);
/* since we will destroy the wsi, make absolutely sure now */
lws_ssl_remove_wsi_from_buffered_list(wsi);
lws_remove_from_timeout_list(wsi);
wsi->context->count_wsi_allocated--;
lwsl_debug("%s: %p, remaining wsi %d\n", __func__, wsi,
wsi->context->count_wsi_allocated);
@ -116,6 +140,13 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs)
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
time_t now;
if (secs == LWS_TO_KILL_SYNC) {
lws_remove_from_timeout_list(wsi);
lwsl_debug("synchronously killing %p\n", wsi);
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
return;
}
lws_pt_lock(pt);
time(&now);
@ -157,6 +188,12 @@ lws_remove_child_from_any_parent(struct lws *wsi)
if (*pwsi == wsi) {
lwsl_info("%s: detach %p from parent %p\n",
__func__, wsi, wsi->parent);
if (wsi->parent->protocol)
wsi->parent->protocol->callback(wsi,
LWS_CALLBACK_CHILD_CLOSING,
wsi->parent->user_space, wsi, 0);
*pwsi = wsi->sibling_list;
seen = 1;
break;
@ -219,6 +256,33 @@ lws_bind_protocol(struct lws *wsi, const struct lws_protocols *p)
return 0;
}
#ifdef LWS_WITH_CGI
static void
lws_cgi_remove_and_kill(struct lws *wsi)
{
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
struct lws_cgi **pcgi = &pt->cgi_list;
/* remove us from the cgi list */
lwsl_debug("%s: remove cgi %p from list\n", __func__, wsi->cgi);
while (*pcgi) {
if (*pcgi == wsi->cgi) {
/* drop us from the pt cgi list */
*pcgi = (*pcgi)->cgi_list;
break;
}
pcgi = &(*pcgi)->cgi_list;
}
if (wsi->cgi->headers_buf) {
lwsl_debug("close: freed cgi headers\n");
lws_free_set_NULL(wsi->cgi->headers_buf);
}
/* we have a cgi going, we must kill it */
wsi->cgi->being_closed = 1;
lws_cgi_kill(wsi);
}
#endif
void
lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
{
@ -228,6 +292,8 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
struct lws_tokens eff_buf;
int n, m, ret;
lwsl_debug("%s: %p\n", __func__, wsi);
if (!wsi)
return;
@ -280,35 +346,38 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
#ifdef LWS_WITH_CGI
if (wsi->mode == LWSCM_CGI) {
/* we are not a network connection, but a handler for CGI io */
if (wsi->parent && wsi->parent->cgi)
if (wsi->parent && wsi->parent->cgi) {
if (wsi->cgi_channel == LWS_STDOUT)
lws_cgi_remove_and_kill(wsi->parent);
/* end the binding between us and master */
wsi->parent->cgi->stdwsi[(int)wsi->cgi_channel] = NULL;
}
wsi->socket_is_permanently_unusable = 1;
lwsl_debug("------ %s: detected cgi fdhandler wsi %p\n", __func__, wsi);
goto just_kill_connection;
}
if (wsi->cgi) {
struct lws_cgi **pcgi = &pt->cgi_list;
/* remove us from the cgi list */
lwsl_debug("%s: remove cgi %p from list\n", __func__, wsi->cgi);
while (*pcgi) {
if (*pcgi == wsi->cgi) {
/* drop us from the pt cgi list */
*pcgi = (*pcgi)->cgi_list;
break;
}
pcgi = &(*pcgi)->cgi_list;
}
if (wsi->cgi->headers_buf) {
lwsl_debug("close: freed cgi headers\n");
lws_free_set_NULL(wsi->cgi->headers_buf);
}
/* we have a cgi going, we must kill it */
wsi->cgi->being_closed = 1;
lws_cgi_kill(wsi);
}
if (wsi->cgi)
lws_cgi_remove_and_kill(wsi);
#endif
#if !defined(LWS_NO_CLIENT)
if (wsi->mode == LWSCM_HTTP_CLIENT ||
wsi->mode == LWSCM_WSCL_WAITING_CONNECT ||
wsi->mode == LWSCM_WSCL_WAITING_PROXY_REPLY ||
wsi->mode == LWSCM_WSCL_ISSUE_HANDSHAKE ||
wsi->mode == LWSCM_WSCL_ISSUE_HANDSHAKE2 ||
wsi->mode == LWSCM_WSCL_WAITING_SSL ||
wsi->mode == LWSCM_WSCL_WAITING_SERVER_REPLY ||
wsi->mode == LWSCM_WSCL_WAITING_EXTENSION_CONNECT ||
wsi->mode == LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY ||
wsi->mode == LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY ||
wsi->mode == LWSCM_WSCL_WAITING_SOCKS_AUTH_REPLY)
if (wsi->u.hdr.stash)
lws_free_set_NULL(wsi->u.hdr.stash);
#endif
if (wsi->mode == LWSCM_RAW) {
@ -568,6 +637,8 @@ just_kill_connection:
/* checking return redundant since we anyway close */
if (wsi->desc.sockfd != LWS_SOCK_INVALID)
remove_wsi_socket_from_fds(wsi);
else
lws_same_vh_protocol_remove(wsi);
#if defined(LWS_WITH_ESP8266)
espconn_disconnect(wsi->desc.sockfd);
@ -670,17 +741,18 @@ async_close:
wsi->socket_is_permanently_unusable = 1;
#ifdef LWS_USE_LIBUV
if (LWS_LIBUV_ENABLED(context)) {
if (wsi->listener) {
lwsl_debug("%s: stopping listner libuv poll\n", __func__);
uv_poll_stop(&wsi->w_read.uv_watcher);
}
lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi);
/* libuv has to do his own close handle processing asynchronously */
lws_libuv_closehandle(wsi);
if (!wsi->parent_carries_io)
if (LWS_LIBUV_ENABLED(context)) {
if (wsi->listener) {
lwsl_debug("%s: stopping listner libuv poll\n", __func__);
uv_poll_stop(&wsi->w_read.uv_watcher);
}
lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi);
/* libuv has to do his own close handle processing asynchronously */
lws_libuv_closehandle(wsi);
return;
}
return;
}
#endif
lws_close_free_wsi_final(wsi);
@ -711,12 +783,13 @@ lws_close_free_wsi_final(struct lws *wsi)
#ifdef LWS_WITH_CGI
if (wsi->cgi) {
for (n = 0; n < 6; n++) {
if (wsi->cgi->pipe_fds[n / 2][n & 1] == 0)
for (n = 0; n < 3; n++) {
if (wsi->cgi->pipe_fds[n][!!(n == 0)] == 0)
lwsl_err("ZERO FD IN CGI CLOSE");
if (wsi->cgi->pipe_fds[n / 2][n & 1] >= 0)
close(wsi->cgi->pipe_fds[n / 2][n & 1]);
if (wsi->cgi->pipe_fds[n][!!(n == 0)] >= 0)
close(wsi->cgi->pipe_fds[n][!!(n == 0)]);
}
lws_free(wsi->cgi);
@ -767,8 +840,7 @@ lws_get_addresses(struct lws_vhost *vh, void *ads, char *name,
struct addrinfo ai, *res;
struct sockaddr_in addr4;
if (rip)
rip[0] = '\0';
rip[0] = '\0';
name[0] = '\0';
addr4.sin_family = AF_UNSPEC;
@ -803,8 +875,6 @@ lws_get_addresses(struct lws_vhost *vh, void *ads, char *name,
name, name_len, NULL, 0, 0))
return -1;
#endif
if (!rip)
return 0;
if (getaddrinfo(name, NULL, &ai, &result))
return -1;
@ -856,6 +926,9 @@ lws_get_peer_simple(struct lws *wsi, char *name, int namelen)
int af = AF_INET;
void *p, *q;
if (wsi->parent_carries_io)
wsi = wsi->parent;
#ifdef LWS_USE_IPV6
if (LWS_IPV6_ENABLED(wsi->vhost)) {
len = sizeof(sin6);
@ -998,8 +1071,9 @@ lws_callback_all_protocol(struct lws_context *context,
}
LWS_VISIBLE int
lws_callback_all_protocol_vhost(struct lws_vhost *vh,
const struct lws_protocols *protocol, int reason)
lws_callback_all_protocol_vhost_args(struct lws_vhost *vh,
const struct lws_protocols *protocol, int reason,
void *argp, size_t len)
{
struct lws_context *context = vh->context;
struct lws_context_per_thread *pt = &context->pt[0];
@ -1011,9 +1085,10 @@ lws_callback_all_protocol_vhost(struct lws_vhost *vh,
wsi = wsi_from_fd(context, pt->fds[n].fd);
if (!wsi)
continue;
if (wsi->vhost == vh && wsi->protocol == protocol)
protocol->callback(wsi, reason, wsi->user_space,
NULL, 0);
if (wsi->vhost == vh && (wsi->protocol == protocol ||
!protocol))
wsi->protocol->callback(wsi, reason,
wsi->user_space, argp, len);
}
pt++;
}
@ -1021,6 +1096,13 @@ lws_callback_all_protocol_vhost(struct lws_vhost *vh,
return 0;
}
LWS_VISIBLE int
lws_callback_all_protocol_vhost(struct lws_vhost *vh,
const struct lws_protocols *protocol, int reason)
{
return lws_callback_all_protocol_vhost_args(vh, protocol, reason, NULL, 0);
}
LWS_VISIBLE LWS_EXTERN int
lws_callback_vhost_protocols(struct lws *wsi, int reason, void *in, int len)
{
@ -1407,6 +1489,12 @@ lws_is_final_fragment(struct lws *wsi)
return wsi->u.ws.final && !wsi->u.ws.rx_packet_length && !wsi->u.ws.rx_draining_ext;
}
LWS_VISIBLE int
lws_is_first_fragment(struct lws *wsi)
{
return wsi->u.ws.first_fragment;
}
LWS_VISIBLE unsigned char
lws_get_reserved_bits(struct lws *wsi)
{
@ -1650,6 +1738,48 @@ lws_get_child(const struct lws *wsi)
return wsi->child_list;
}
LWS_VISIBLE LWS_EXTERN void
lws_set_parent_carries_io(struct lws *wsi)
{
wsi->parent_carries_io = 1;
}
LWS_VISIBLE LWS_EXTERN void *
lws_get_opaque_parent_data(const struct lws *wsi)
{
return wsi->opaque_parent_data;
}
LWS_VISIBLE LWS_EXTERN void
lws_set_opaque_parent_data(struct lws *wsi, void *data)
{
wsi->opaque_parent_data = data;
}
LWS_VISIBLE LWS_EXTERN int
lws_get_child_pending_on_writable(const struct lws *wsi)
{
return wsi->parent_pending_cb_on_writable;
}
LWS_VISIBLE LWS_EXTERN void
lws_clear_child_pending_on_writable(struct lws *wsi)
{
wsi->parent_pending_cb_on_writable = 0;
}
LWS_VISIBLE LWS_EXTERN int
lws_get_close_length(struct lws *wsi)
{
return wsi->u.ws.close_in_ping_buffer_len;
}
LWS_VISIBLE LWS_EXTERN unsigned char *
lws_get_close_payload(struct lws *wsi)
{
return &wsi->u.ws.ping_payload_buf[LWS_PRE];
}
LWS_VISIBLE LWS_EXTERN void
lws_close_reason(struct lws *wsi, enum lws_close_status status,
unsigned char *buf, size_t len)
@ -2516,6 +2646,8 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len
p++;
}
}
env_array[n++] = "PATH=/bin:/usr/bin:/usr/local/bin:/var/www/cgi-bin";
env_array[n++] = p;
p += lws_snprintf(p, end - p, "SCRIPT_PATH=%s", exec_array[0]) + 1;
@ -2530,7 +2662,6 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len
}
env_array[n++] = "SERVER_SOFTWARE=libwebsockets";
env_array[n++] = "PATH=/bin:/usr/bin:/usr/local/bin:/var/www/cgi-bin";
env_array[n] = NULL;
#if 0
@ -2565,6 +2696,10 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len
/* we are the parent process */
wsi->context->count_cgi_spawned++;
lwsl_debug("%s: cgi %p spawned PID %d\n", __func__, cgi, cgi->pid);
for (n = 0; n < 3; n++)
close(cgi->pipe_fds[n][!(n == 0)]);
return 0;
}
@ -2647,11 +2782,11 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi)
return -1;
while (wsi->hdr_state != LHCS_PAYLOAD) {
/* we have to separate header / finalize and
/*
* we have to separate header / finalize and
* payload chunks, since they need to be
* handled separately
*/
switch (wsi->hdr_state) {
case LHCS_RESPONSE:
@ -2659,6 +2794,12 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi)
wsi->cgi->response_code);
if (lws_add_http_header_status(wsi, wsi->cgi->response_code, &p, end))
return 1;
if (!wsi->cgi->explicitly_chunked &&
!wsi->cgi->content_length &&
lws_add_http_header_by_token(wsi,
WSI_TOKEN_HTTP_TRANSFER_ENCODING,
(unsigned char *)"chunked", 7, &p, end))
return 1;
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_CONNECTION,
(unsigned char *)"close", 5, &p, end))
return 1;
@ -2675,7 +2816,7 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi)
}
wsi->hdr_state = LHCS_DUMP_HEADERS;
wsi->reason_bf |= 8;
wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI_HEADERS;
lws_callback_on_writable(wsi);
/* back to the loop for writeability again */
return 0;
@ -2700,7 +2841,7 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi)
lws_free_set_NULL(wsi->cgi->headers_buf);
lwsl_debug("freed cgi headers\n");
} else {
wsi->reason_bf |= 8;
wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI_HEADERS;
lws_callback_on_writable(wsi);
}
@ -2856,14 +2997,24 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi)
/* payload processing */
m = !wsi->cgi->explicitly_chunked && !wsi->cgi->content_length;
n = read(lws_get_socket_fd(wsi->cgi->stdwsi[LWS_STDOUT]),
start, sizeof(buf) - LWS_PRE);
start, sizeof(buf) - LWS_PRE - (m ? LWS_HTTP_CHUNK_HDR_SIZE : 0));
if (n < 0 && errno != EAGAIN) {
lwsl_debug("%s: stdout read says %d\n", __func__, n);
return -1;
}
if (n > 0) {
if (m) {
char chdr[LWS_HTTP_CHUNK_HDR_SIZE];
m = lws_snprintf(chdr, LWS_HTTP_CHUNK_HDR_SIZE - 3, "%X\x0d\x0a", n);
memmove(start + m, start, n);
memcpy(start, chdr, m);
memcpy(start + m + n, "\x0d\x0a", 2);
n += m + 2;
}
m = lws_write(wsi, (unsigned char *)start, n, LWS_WRITE_HTTP);
//lwsl_notice("write %d\n", m);
if (m < 0) {
@ -2994,7 +3145,7 @@ lws_cgi_kill_terminated(struct lws_context_per_thread *pt)
lwsl_debug("%s: found PID %d on cgi list\n",
__func__, n);
if (!cgi->content_length && cgi->explicitly_chunked) {
if (!cgi->content_length) {
/*
* well, if he sends chunked... give him 5s after the
* cgi terminated to send buffered
@ -3097,7 +3248,8 @@ lws_set_extension_option(struct lws *wsi, const char *ext_name,
int
lws_access_log(struct lws *wsi)
{
char *p = wsi->access_log.user_agent, ass[512];
char *p = wsi->access_log.user_agent, ass[512],
*p1 = wsi->access_log.referrer;
int l;
if (!wsi->access_log_pending)
@ -3109,9 +3261,12 @@ lws_access_log(struct lws *wsi)
if (!p)
p = "";
l = lws_snprintf(ass, sizeof(ass) - 1, "%s %d %lu %s\n",
if (!p1)
p1 = "";
l = lws_snprintf(ass, sizeof(ass) - 1, "%s %d %lu \"%s\" \"%s\"\n",
wsi->access_log.header_log,
wsi->access_log.response, wsi->access_log.sent, p);
wsi->access_log.response, wsi->access_log.sent, p1, p);
if (wsi->vhost->log_fd != (int)LWS_INVALID_FILE) {
if (write(wsi->vhost->log_fd, ass, l) != l)
@ -3127,6 +3282,10 @@ lws_access_log(struct lws *wsi)
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;

View file

@ -33,12 +33,11 @@ extern "C" {
#include <stdarg.h>
#endif
#if defined(LWS_HAS_INTPTR_T)
#include <stdint.h>
#define lws_intptr_t intptr_t
#else
typedef unsigned long long lws_intptr_t;
#endif
#include "lws_config.h"
/*
* CARE: everything using cmake defines needs to be below here
*/
#if defined(LWS_WITH_ESP8266)
struct sockaddr_in;
@ -47,7 +46,12 @@ struct sockaddr_in;
#define LWS_POSIX 1
#endif
#include "lws_config.h"
#if defined(LWS_HAS_INTPTR_T)
#include <stdint.h>
#define lws_intptr_t intptr_t
#else
typedef unsigned long long lws_intptr_t;
#endif
#if defined(WIN32) || defined(_WIN32)
#ifndef WIN32_LEAN_AND_MEAN
@ -632,6 +636,7 @@ struct lws_esp32_image {
};
extern struct lws_esp32 lws_esp32;
struct lws_vhost;
extern esp_err_t
lws_esp32_event_passthru(void *ctx, system_event_t *event);
@ -645,7 +650,7 @@ struct lws_context_creation_info;
extern void
lws_esp32_set_creation_defaults(struct lws_context_creation_info *info);
extern struct lws_context *
lws_esp32_init(struct lws_context_creation_info *);
lws_esp32_init(struct lws_context_creation_info *, struct lws_vhost **pvh);
extern int
lws_esp32_wlan_nvs_get(int retry);
extern esp_err_t
@ -823,6 +828,38 @@ struct lws_context;
/* needed even with extensions disabled for create context */
struct lws_extension;
/*! \defgroup lwsmeta lws-meta
*
* ##lws-meta protocol
*
* The protocol wraps other muxed connections inside one tcp connection.
*
* Commands are assigned from 0x41 up (so they are valid unicode)
*/
///@{
enum lws_meta_commands {
LWS_META_CMD_OPEN_SUBCHANNEL = 'A',
/**< Client requests to open new subchannel
*/
LWS_META_CMD_OPEN_RESULT,
/**< Result of client request to open new subchannel */
LWS_META_CMD_CLOSE_NOTIFY,
/**< Notification of subchannel closure */
LWS_META_CMD_CLOSE_RQ,
/**< client requests to close a subchannel */
LWS_META_CMD_WRITE,
/**< connection writes something to specific channel index */
/****** add new things just above ---^ ******/
};
/* channel numbers are transported offset by 0x20 so they are valid unicode */
#define LWS_META_TRANSPORT_OFFSET 0x20
///@}
/*! \defgroup usercb User Callback
*
* ##User protocol callback
@ -1252,6 +1289,16 @@ enum lws_callback_reasons {
* using the vhost. @in is a pointer to a
* struct lws_ssl_info containing information about the
* event*/
LWS_CALLBACK_CHILD_WRITE_VIA_PARENT = 68,
/**< Child has been marked with parent_carries_io attribute, so
* lws_write directs the to this callback at the parent,
* @in is a struct lws_write_passthru containing the args
* the lws_write() was called with.
*/
LWS_CALLBACK_CHILD_CLOSING = 69,
/**< Sent to parent to notify them a child is closing / being
* destroyed. @in is the child wsi.
*/
/****** add new things just above ---^ ******/
@ -1279,6 +1326,11 @@ enum lws_callback_reasons {
typedef int
lws_callback_function(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len);
#define LWS_CB_REASON_AUX_BF__CGI 1
#define LWS_CB_REASON_AUX_BF__PROXY 2
#define LWS_CB_REASON_AUX_BF__CGI_CHUNK_END 4
#define LWS_CB_REASON_AUX_BF__CGI_HEADERS 8
///@}
/*! \defgroup extensions
@ -2069,6 +2121,9 @@ struct lws_context_creation_info {
* the form SSL_CB_ALERT, defined in openssl/ssl.h. The default of
* 0 means no info events will be reported.
*/
unsigned int timeout_secs_ah_idle;
/**< VHOST: seconds to allow a client to hold an ah without using it.
* 0 defaults to 10s. */
void *_unused[8]; /**< dummy */
};
@ -2783,6 +2838,9 @@ lws_service_adjust_timeout(struct lws_context *context, int timeout_ms, int tsi)
/* Backwards compatibility */
#define lws_plat_service_tsi lws_service_tsi
LWS_VISIBLE LWS_EXTERN int
lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd);
///@}
/*! \defgroup http HTTP
@ -3621,10 +3679,24 @@ enum pending_timeout {
PENDING_TIMEOUT_KILLED_BY_SSL_INFO = 22,
PENDING_TIMEOUT_KILLED_BY_PARENT = 23,
PENDING_TIMEOUT_CLOSE_SEND = 24,
PENDING_TIMEOUT_HOLDING_AH = 25,
/****** add new things just above ---^ ******/
};
#define LWS_TO_KILL_ASYNC -1
/**< If LWS_TO_KILL_ASYNC is given as the timeout sec in a lws_set_timeout()
* call, then the connection is marked to be killed at the next timeout
* check. This is how you should force-close the wsi being serviced if
* you are doing it outside the callback (where you should close by nonzero
* return).
*/
#define LWS_TO_KILL_SYNC -2
/**< If LWS_TO_KILL_SYNC is given as the timeout sec in a lws_set_timeout()
* call, then the connection is closed before returning (which may delete
* the wsi). This should only be used where the wsi being closed is not the
* wsi currently being serviced.
*/
/**
* lws_set_timeout() - marks the wsi as subject to a timeout
*
@ -3632,7 +3704,10 @@ enum pending_timeout {
*
* \param wsi: Websocket connection instance
* \param reason: timeout reason
* \param secs: how many seconds
* \param secs: how many seconds. You may set to LWS_TO_KILL_ASYNC to
* force the connection to timeout at the next opportunity, or
* LWS_TO_KILL_SYNC to close it synchronously if you know the
* wsi is not the one currently being serviced.
*/
LWS_VISIBLE LWS_EXTERN void
lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs);
@ -3657,7 +3732,8 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs);
#endif
#define _LWS_PAD(n) (((n) % _LWS_PAD_SIZE) ? \
((n) + (_LWS_PAD_SIZE - ((n) % _LWS_PAD_SIZE))) : (n))
#define LWS_PRE _LWS_PAD(4 + 10)
/* last 2 is for lws-meta */
#define LWS_PRE _LWS_PAD(4 + 10 + 2)
/* used prior to 1.7 and retained for backward compatibility */
#define LWS_SEND_BUFFER_PRE_PADDING LWS_PRE
#define LWS_SEND_BUFFER_POST_PADDING 0
@ -3709,6 +3785,15 @@ enum lws_write_protocol {
* decode the content if used */
};
/* used with LWS_CALLBACK_CHILD_WRITE_VIA_PARENT */
struct lws_write_passthru {
struct lws *wsi;
unsigned char *buf;
size_t len;
enum lws_write_protocol wp;
};
/**
* lws_write() - Apply protocol then write data to client
@ -3841,7 +3926,7 @@ lws_callback_on_writable(struct lws *wsi);
/**
* lws_callback_on_writable_all_protocol() - Request a callback for all
* connections on same vhost using the given protocol when it
* connections using the given protocol when it
* becomes possible to write to each socket without
* blocking in turn.
*
@ -3858,8 +3943,8 @@ lws_callback_on_writable_all_protocol(const struct lws_context *context,
/**
* lws_callback_on_writable_all_protocol_vhost() - Request a callback for
* all connections using the given protocol when it
* becomes possible to write to each socket without
* all connections on same vhost using the given protocol
* when it becomes possible to write to each socket without
* blocking in turn.
*
* \param vhost: Only consider connections on this lws_vhost
@ -3895,10 +3980,11 @@ lws_callback_all_protocol(struct lws_context *context,
/**
* lws_callback_all_protocol_vhost() - Callback all connections using
* the given protocol with the given reason
* the given protocol with the given reason. This is
* deprecated since v2.4: use lws_callback_all_protocol_vhost_args
*
* \param vh: Vhost whose connections will get callbacks
* \param protocol: Which protocol to match
* \param protocol: Which protocol to match. NULL means all.
* \param reason: Callback reason index
*
* - Which: connections using this protocol on GIVEN VHOST ONLY
@ -3907,7 +3993,27 @@ lws_callback_all_protocol(struct lws_context *context,
*/
LWS_VISIBLE LWS_EXTERN int
lws_callback_all_protocol_vhost(struct lws_vhost *vh,
const struct lws_protocols *protocol, int reason);
const struct lws_protocols *protocol, int reason)
LWS_WARN_DEPRECATED;
/**
* lws_callback_all_protocol_vhost_args() - Callback all connections using
* the given protocol with the given reason and args
*
* \param vh: Vhost whose connections will get callbacks
* \param protocol: Which protocol to match. NULL means all.
* \param reason: Callback reason index
* \param argp: Callback "in" parameter
* \param len: Callback "len" parameter
*
* - Which: connections using this protocol on GIVEN VHOST ONLY
* - When: now
* - What: reason
*/
LWS_VISIBLE int
lws_callback_all_protocol_vhost_args(struct lws_vhost *vh,
const struct lws_protocols *protocol, int reason,
void *argp, size_t len);
/**
* lws_callback_vhost_protocols() - Callback all protocols enabled on a vhost
@ -4053,7 +4159,11 @@ typedef enum {
LWS_ADOPT_RAW_FILE_DESC = 0, /* convenience constant */
LWS_ADOPT_HTTP = 1, /* flag: absent implies RAW */
LWS_ADOPT_SOCKET = 2, /* flag: absent implies file descr */
LWS_ADOPT_ALLOW_SSL = 4 /* flag: if set requires LWS_ADOPT_SOCKET */
LWS_ADOPT_ALLOW_SSL = 4, /* flag: if set requires LWS_ADOPT_SOCKET */
LWS_ADOPT_WS_PARENTIO = 8, /* flag: ws mode parent handles IO
* if given must be only flag
* wsi put directly into ws mode
*/
} lws_adoption_type;
typedef union {
@ -4411,6 +4521,32 @@ lws_get_parent(const struct lws *wsi);
LWS_VISIBLE LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT
lws_get_child(const struct lws *wsi);
/**
* lws_parent_carries_io() - mark wsi as needing to send messages via parent
*
* \param wsi: child lws connection
*/
LWS_VISIBLE LWS_EXTERN void
lws_set_parent_carries_io(struct lws *wsi);
LWS_VISIBLE LWS_EXTERN void *
lws_get_opaque_parent_data(const struct lws *wsi);
LWS_VISIBLE LWS_EXTERN void
lws_set_opaque_parent_data(struct lws *wsi, void *data);
LWS_VISIBLE LWS_EXTERN int
lws_get_child_pending_on_writable(const struct lws *wsi);
LWS_VISIBLE LWS_EXTERN void
lws_clear_child_pending_on_writable(struct lws *wsi);
LWS_VISIBLE LWS_EXTERN int
lws_get_close_length(struct lws *wsi);
LWS_VISIBLE LWS_EXTERN unsigned char *
lws_get_close_payload(struct lws *wsi);
/*
* \deprecated DEPRECATED Note: this is not normally needed as a user api.
@ -4448,11 +4584,20 @@ lws_send_pipe_choked(struct lws *wsi);
/**
* lws_is_final_fragment() - tests if last part of ws message
*
* \param wsi: lws connection
*/
LWS_VISIBLE LWS_EXTERN int
lws_is_final_fragment(struct lws *wsi);
/**
* lws_is_first_fragment() - tests if first part of ws message
*
* \param wsi: lws connection
*/
LWS_VISIBLE LWS_EXTERN int
lws_is_first_fragment(struct lws *wsi);
/**
* lws_get_reserved_bits() - access reserved bits of ws frame
* \param wsi: lws connection

View file

@ -1613,7 +1613,12 @@ lws_esp32_get_image_info(const esp_partition_t *part, struct lws_esp32_image *i,
}
hdr += (~hdr & 15) + 1;
i->romfs = hdr + 4;
if (eih.hash_appended)
hdr += 0x20;
// lwsl_notice("romfs estimated at 0x%x\n", hdr);
i->romfs = hdr + 0x4;
spi_flash_read(hdr, &i->romfs_len, sizeof(i->romfs_len));
i->json = i->romfs + i->romfs_len + 4;
spi_flash_read(i->json - 4, &i->json_len, sizeof(i->json_len));
@ -1627,7 +1632,7 @@ lws_esp32_get_image_info(const esp_partition_t *part, struct lws_esp32_image *i,
}
struct lws_context *
lws_esp32_init(struct lws_context_creation_info *info)
lws_esp32_init(struct lws_context_creation_info *info, struct lws_vhost **pvh)
{
const esp_partition_t *part = lws_esp_ota_get_boot_partition();
struct lws_context *context;
@ -1683,6 +1688,9 @@ lws_esp32_init(struct lws_context_creation_info *info)
else
lws_init_vhost_client_ssl(info, vhost);
if (pvh)
*pvh = vhost;
lws_protocol_init(context);
return context;

View file

@ -256,7 +256,7 @@ lws_plat_set_socket_options(struct lws_vhost *vhost, int fd)
}
#if defined(SO_BINDTODEVICE)
if (vhost->bind_iface) {
if (vhost->bind_iface && vhost->iface) {
lwsl_info("binding listen skt to %s using SO_BINDTODEVICE\n", vhost->iface);
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, vhost->iface,
strlen(vhost->iface)) < 0) {

View file

@ -218,6 +218,9 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
/* if something closed, retry this slot */
if (n)
i--;
if (wsi->trunc_len)
WSASetEvent(pt->events[0]);
}
/*

View file

@ -250,6 +250,23 @@ LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len,
int pre = 0, n;
size_t orig_len = len;
if (wsi->parent_carries_io) {
struct lws_write_passthru pas;
pas.buf = buf;
pas.len = len;
pas.wp = wp;
pas.wsi = wsi;
if (wsi->parent->protocol->callback(wsi->parent,
LWS_CALLBACK_CHILD_WRITE_VIA_PARENT,
wsi->parent->user_space,
(void *)&pas, 0))
return 1;
return len;
}
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_API_LWS_WRITE, 1);
if ((int)len < 0) {
@ -269,7 +286,8 @@ LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t 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__);
// lwsl_notice("%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) {
@ -332,11 +350,13 @@ LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len,
case LWS_WRITE_CLOSE:
break;
default:
lwsl_debug("LWS_EXT_CB_PAYLOAD_TX\n");
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) {
lwsl_debug("drain len %d\n", (int)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;
@ -370,8 +390,8 @@ LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len,
*/
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
* ext might eat it, but not 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) {
@ -390,6 +410,13 @@ LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len,
buf = (unsigned char *)eff_buf.token;
len = eff_buf.token_len;
lwsl_debug("%p / %d\n", buf, (int)len);
if (!buf) {
lwsl_err("null buf (%d)\n", (int)len);
return -1;
}
switch (wsi->ietf_spec_revision) {
case 13:
if (masked7) {

View file

@ -92,6 +92,10 @@ lws_header_table_reset(struct lws *wsi, int autoservice)
/* since we will restart the ah, our new headers are not completed */
wsi->hdr_parsing_completed = 0;
/* while we hold the ah, keep a timeout on the wsi */
lws_set_timeout(wsi, PENDING_TIMEOUT_HOLDING_AH,
wsi->vhost->timeout_secs_ah_idle);
/*
* if we inherited pending rx (from socket adoption deferred
* processing), apply and free it.
@ -385,6 +389,9 @@ lws_hdr_fragment_length(struct lws *wsi, enum lws_token_indexes h, int frag_idx)
{
int n;
if (!wsi->u.hdr.ah)
return 0;
n = wsi->u.hdr.ah->frag_index[h];
if (!n)
return 0;
@ -402,6 +409,9 @@ LWS_VISIBLE int lws_hdr_total_length(struct lws *wsi, enum lws_token_indexes h)
int n;
int len = 0;
if (!wsi->u.hdr.ah)
return 0;
n = wsi->u.hdr.ah->frag_index[h];
if (!n)
return 0;
@ -417,7 +427,12 @@ LWS_VISIBLE int lws_hdr_copy_fragment(struct lws *wsi, char *dst, int len,
enum lws_token_indexes h, int frag_idx)
{
int n = 0;
int f = wsi->u.hdr.ah->frag_index[h];
int f;
if (!wsi->u.hdr.ah)
return -1;
f = wsi->u.hdr.ah->frag_index[h];
if (!f)
return -1;
@ -448,6 +463,9 @@ LWS_VISIBLE int lws_hdr_copy(struct lws *wsi, char *dst, int len,
if (toklen >= len)
return -1;
if (!wsi->u.hdr.ah)
return -1;
n = wsi->u.hdr.ah->frag_index[h];
if (!n)
return 0;
@ -1145,6 +1163,7 @@ handle_first:
wsi->u.ws.rsv_first_msg = (c & 0x70);
wsi->u.ws.frame_is_binary =
wsi->u.ws.opcode == LWSWSOPC_BINARY_FRAME;
wsi->u.ws.first_fragment = 1;
break;
case 3:
case 4:
@ -1492,6 +1511,7 @@ drain_extension:
/* eff_buf may be pointing somewhere completely different now,
* it's the output
*/
wsi->u.ws.first_fragment = 0;
if (n < 0) {
/*
* we may rely on this to get RX, just drop connection

View file

@ -236,6 +236,11 @@ remove_wsi_socket_from_fds(struct lws *wsi)
#endif
int m, ret = 0;
if (wsi->parent_carries_io) {
lws_same_vh_protocol_remove(wsi);
return 0;
}
#if !defined(_WIN32) && !defined(LWS_WITH_ESP8266)
if (wsi->desc.sockfd > context->max_fds) {
lwsl_err("fd %d too high (%d)\n", wsi->desc.sockfd, context->max_fds);
@ -348,6 +353,16 @@ lws_callback_on_writable(struct lws *wsi)
if (wsi->socket_is_permanently_unusable)
return 0;
if (wsi->parent_carries_io) {
int n = lws_callback_on_writable(wsi->parent);
if (n < 0)
return n;
wsi->parent_pending_cb_on_writable = 1;
return 1;
}
pt = &wsi->context->pt[(int)wsi->tsi];
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB_REQ, 1);
#if defined(LWS_WITH_STATS)
@ -434,8 +449,8 @@ lws_same_vh_protocol_insert(struct lws *wsi, int n)
// wsi->same_vh_protocol_prev);
if (wsi->same_vh_protocol_prev || wsi->same_vh_protocol_next) {
lwsl_err("Attempted to attach wsi twice to same vh prot\n");
assert(0);
lws_same_vh_protocol_remove(wsi);
lwsl_notice("Attempted to attach wsi twice to same vh prot\n");
}
wsi->same_vh_protocol_prev = /* guy who points to us */

View file

@ -891,6 +891,7 @@ struct lws_vhost {
int ka_probes;
int ka_interval;
int keepalive_timeout;
int timeout_secs_ah_idle;
int ssl_info_event_mask;
#ifdef LWS_WITH_ACCESS_LOG
int log_fd;
@ -1484,10 +1485,13 @@ struct _lws_websocket_related {
unsigned int rx_draining_ext:1;
unsigned int tx_draining_ext:1;
unsigned int send_check_ping:1;
unsigned int first_fragment:1;
};
#ifdef LWS_WITH_CGI
#define LWS_HTTP_CHUNK_HDR_SIZE 16
enum {
SIGNIFICANT_HDR_CONTENT_LENGTH,
SIGNIFICANT_HDR_LOCATION,
@ -1541,6 +1545,7 @@ struct lws_rewrite;
struct lws_access_log {
char *header_log;
char *user_agent;
char *referrer;
unsigned long sent;
int response;
};
@ -1588,6 +1593,7 @@ struct lws {
struct lws_access_log access_log;
#endif
void *user_space;
void *opaque_parent_data;
/* rxflow handling */
unsigned char *rxflow_buffer;
/* truncated send handling */
@ -1651,6 +1657,8 @@ struct lws {
unsigned int told_user_closed:1;
unsigned int waiting_to_send_close_frame:1;
unsigned int ipv6:1;
unsigned int parent_carries_io:1;
unsigned int parent_pending_cb_on_writable:1;
#if defined(LWS_WITH_ESP8266)
unsigned int pending_send_completion:3;

View file

@ -689,6 +689,17 @@ lws_unauthorised_basic_auth(struct lws *wsi)
int lws_clean_url(char *p)
{
if (p[0] == 'h' && p[1] == 't' && p[2] == 't' && p[3] == 'p') {
p += 4;
if (*p == 's')
p++;
if (*p == ':') {
p++;
if (*p == '/')
p++;
}
}
while (*p) {
if (p[0] == '/' && p[1] == '/') {
char *p1 = p;
@ -777,7 +788,7 @@ lws_http_action(struct lws *wsi)
/* we insist on absolute paths */
if (uri_ptr[0] != '/') {
if (!uri_ptr || uri_ptr[0] != '/') {
lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
goto bail_nuke_ah;
@ -895,7 +906,7 @@ lws_http_action(struct lws *wsi)
const char *pa, *me;
struct tm *tmp;
time_t t = time(NULL);
int l = 256;
int l = 256, m;
if (wsi->access_log_pending)
lws_access_log(wsi);
@ -913,10 +924,7 @@ lws_http_action(struct lws *wsi)
if (!pa)
pa = "(unknown)";
if (meth >= 0)
me = method_names[meth];
else
me = "unknown";
me = method_names[meth];
lws_snprintf(wsi->access_log.header_log, l,
"%s - - [%s] \"%s %s %s\"",
@ -931,6 +939,23 @@ lws_http_action(struct lws *wsi)
l + 1, WSI_TOKEN_HTTP_USER_AGENT);
else
lwsl_err("OOM getting user agent\n");
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);
if (wsi->access_log.referrer)
lws_hdr_copy(wsi, wsi->access_log.referrer,
l + 1, WSI_TOKEN_HTTP_REFERER);
else
lwsl_err("OOM getting user agent\n");
for (m = 0; m < l; m++)
if (wsi->access_log.referrer[m] == '\"')
wsi->access_log.referrer[m] = '\'';
}
wsi->access_log_pending = 1;
}
@ -997,10 +1022,13 @@ lws_http_action(struct lws *wsi)
hit->origin);
else
n = lws_snprintf((char *)end, 256,
"%s%s%s/", oprot[lws_is_ssl(wsi)],
"%s%s%s/", oprot[!!lws_is_ssl(wsi)],
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST),
uri_ptr);
lwsl_notice("%s\n", end);
lws_clean_url((char *)end);
lwsl_notice("%s\n", end);
n = lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,
end, n, &p, end);
@ -1284,6 +1312,57 @@ transaction_result_n:
#endif
}
static int
lws_server_init_wsi_for_ws(struct lws *wsi)
{
int n;
wsi->state = LWSS_ESTABLISHED;
lws_restart_ws_ping_pong_timer(wsi);
/*
* create the frame buffer for this connection according to the
* size mentioned in the protocol definition. If 0 there, use
* a big default for compatibility
*/
n = wsi->protocol->rx_buffer_size;
if (!n)
n = wsi->context->pt_serv_buf_size;
n += LWS_PRE;
wsi->u.ws.rx_ubuf = lws_malloc(n + 4 /* 0x0000ffff zlib */);
if (!wsi->u.ws.rx_ubuf) {
lwsl_err("Out of Mem allocating rx buffer %d\n", n);
return 1;
}
wsi->u.ws.rx_ubuf_alloc = n;
lwsl_debug("Allocating RX buffer %d\n", n);
#if LWS_POSIX && !defined(LWS_WITH_ESP32)
if (!wsi->parent_carries_io)
if (setsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_SNDBUF,
(const char *)&n, sizeof n)) {
lwsl_warn("Failed to set SNDBUF to %d", n);
return 1;
}
#endif
/* notify user code that we're ready to roll */
if (wsi->protocol->callback)
if (wsi->protocol->callback(wsi, LWS_CALLBACK_ESTABLISHED,
wsi->user_space,
#ifdef LWS_OPENSSL_SUPPORT
wsi->ssl,
#else
NULL,
#endif
0))
return 1;
return 0;
}
int
lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
{
@ -1652,49 +1731,10 @@ upgrade_ws:
wsi->u.hdr = hdr;
lws_pt_unlock(pt);
lws_restart_ws_ping_pong_timer(wsi);
/*
* create the frame buffer for this connection according to the
* size mentioned in the protocol definition. If 0 there, use
* a big default for compatibility
*/
n = wsi->protocol->rx_buffer_size;
if (!n)
n = context->pt_serv_buf_size;
n += LWS_PRE;
wsi->u.ws.rx_ubuf = lws_malloc(n + 4 /* 0x0000ffff zlib */);
if (!wsi->u.ws.rx_ubuf) {
lwsl_err("Out of Mem allocating rx buffer %d\n", n);
return 1;
}
wsi->u.ws.rx_ubuf_alloc = n;
lwsl_debug("Allocating RX buffer %d\n", n);
#if LWS_POSIX && !defined(LWS_WITH_ESP32)
if (setsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_SNDBUF,
(const char *)&n, sizeof n)) {
lwsl_warn("Failed to set SNDBUF to %d", n);
return 1;
}
#endif
lws_server_init_wsi_for_ws(wsi);
lwsl_parser("accepted v%02d connection\n",
wsi->ietf_spec_revision);
/* notify user code that we're ready to roll */
if (wsi->protocol->callback)
if (wsi->protocol->callback(wsi, LWS_CALLBACK_ESTABLISHED,
wsi->user_space,
#ifdef LWS_OPENSSL_SUPPORT
wsi->ssl,
#else
NULL,
#endif
0))
return 1;
/* !!! drop ah unreservedly after ESTABLISHED */
if (!wsi->more_rx_waiting) {
lws_header_table_force_to_detachable_state(wsi);
@ -1782,6 +1822,8 @@ lws_create_new_server_wsi(struct lws_vhost *vhost)
new_wsi->user_space = NULL;
new_wsi->ietf_spec_revision = 0;
new_wsi->desc.sockfd = LWS_SOCK_INVALID;
new_wsi->position_in_fds_table = -1;
vhost->context->count_wsi_allocated++;
/*
@ -1864,8 +1906,17 @@ lws_http_transaction_completed(struct lws *wsi)
return 1;
}
#endif
} else
} else {
lws_header_table_reset(wsi, 1);
/*
* If we kept the ah, we should restrict the amount
* of time we are willing to keep it. Otherwise it
* will be bound the whole time the connection remains
* open.
*/
lws_set_timeout(wsi, PENDING_TIMEOUT_HOLDING_AH,
wsi->vhost->keepalive_timeout);
}
}
/* If we're (re)starting on headers, need other implied init */
@ -1889,7 +1940,7 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
int n, ssl = 0;
if (!new_wsi) {
if (type & LWS_ADOPT_SOCKET)
if (type & LWS_ADOPT_SOCKET && !(type & LWS_ADOPT_WS_PARENTIO))
compatible_close(fd.sockfd);
return NULL;
}
@ -1900,6 +1951,9 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
new_wsi->parent = parent;
new_wsi->sibling_list = parent->child_list;
parent->child_list = new_wsi;
if (type & LWS_ADOPT_WS_PARENTIO)
new_wsi->parent_carries_io = 1;
}
new_wsi->desc = fd;
@ -1916,6 +1970,15 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
lwsl_notice("OOM trying to get user_space\n");
goto bail;
}
if (type & LWS_ADOPT_WS_PARENTIO) {
new_wsi->desc.sockfd = LWS_SOCK_INVALID;
lwsl_debug("binding to %s\n", new_wsi->protocol->name);
lws_bind_protocol(new_wsi, new_wsi->protocol);
lws_union_transition(new_wsi, LWSCM_WS_SERVING);
lws_server_init_wsi_for_ws(new_wsi);
return new_wsi;
}
} else
if (type & LWS_ADOPT_HTTP) /* he will transition later */
new_wsi->protocol =
@ -2003,11 +2066,10 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
goto fail;
if (type & LWS_ADOPT_HTTP) {
if (!lws_header_table_attach(new_wsi, 0)) {
if (!lws_header_table_attach(new_wsi, 0))
lwsl_debug("Attached ah immediately\n");
} else {
lwsl_notice("%s: waiting for ah\n", __func__);
}
else
lwsl_info("%s: waiting for ah\n", __func__);
}
return new_wsi;
@ -2583,13 +2645,17 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
lwsl_info("file is being provided in gzip\n");
}
if (
#if defined(LWS_WITH_RANGES)
if (ranges < 2 && content_type && content_type[0])
ranges < 2 &&
#endif
content_type && content_type[0])
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
(unsigned char *)content_type,
strlen(content_type), &p, end))
return -1;
#if defined(LWS_WITH_RANGES)
if (ranges >= 2) { /* multipart byteranges */
strncpy(wsi->u.http.multipart_content_type, content_type,
sizeof(wsi->u.http.multipart_content_type) - 1);

View file

@ -329,6 +329,13 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
user_service:
/* one shot */
if (wsi->parent_carries_io) {
wsi->handling_pollout = 0;
wsi->leave_pollout_active = 0;
return lws_calllback_as_writeable(wsi);
}
if (pollfd) {
int eff = wsi->leave_pollout_active;
@ -847,6 +854,10 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
if (pollfd)
our_fd = pollfd->fd;
/*
* Phase 1: check every wsi on the timeout check list
*/
wsi = context->pt[tsi].timeout_list;
while (wsi) {
/* we have to take copies, because he may be deleted */
@ -861,7 +872,70 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
}
wsi = wsi1;
}
/*
* Phase 2: double-check active ah timeouts independent of wsi
* timeout status
*/
for (n = 0; n < context->max_http_header_pool; n++)
if (pt->ah_pool[n].in_use && pt->ah_pool[n].wsi &&
pt->ah_pool[n].assigned &&
now - pt->ah_pool[n].assigned > 60) {
int len;
char buf[256];
const unsigned char *c;
/*
* a single ah session somehow got held for
* an unreasonable amount of time.
*
* Dump info on the connection...
*/
wsi = pt->ah_pool[n].wsi;
buf[0] = '\0';
lws_get_peer_simple(wsi, buf, sizeof(buf));
lwsl_notice("ah excessive hold: wsi %p\n"
" peer address: %s\n"
" ah rxpos %u, rxlen %u, pos %u\n",
wsi, buf, pt->ah_pool[n].rxpos,
pt->ah_pool[n].rxlen,
pt->ah_pool[n].pos);
m = 0;
do {
c = lws_token_to_string(m);
if (!c)
break;
len = lws_hdr_total_length(wsi, m);
if (!len || len > sizeof(buf) - 1) {
m++;
continue;
}
lws_hdr_copy(wsi, buf, sizeof buf, m);
buf[sizeof(buf) - 1] = '\0';
lwsl_notice(" %s = %s\n",
(const char *)c, buf);
m++;
} while (1);
/* ... and then drop the connection */
if (wsi->desc.sockfd == our_fd)
/* it was the guy we came to service! */
timed_out = 1;
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
}
#ifdef LWS_WITH_CGI
/*
* Phase 3: handle cgi timeouts
*/
lws_cgi_kill_terminated(pt);
#endif
#if 0
@ -952,7 +1026,8 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
#endif
// lwsl_debug("fd=%d, revents=%d, mode=%d, state=%d\n", pollfd->fd, pollfd->revents, (int)wsi->mode, (int)wsi->state);
if (pollfd->revents & LWS_POLLHUP) {
if ((!(pollfd->revents & pollfd->events & LWS_POLLIN)) &&
(pollfd->revents & LWS_POLLHUP)) {
lwsl_debug("pollhup\n");
wsi->socket_is_permanently_unusable = 1;
goto close_and_handled;

View file

@ -41,7 +41,7 @@ int lws_alloc_vfs_file(struct lws_context *context, const char *filename, uint8_
len = lws_vfs_get_length(fops_fd);
*buf = malloc((size_t)len);
if (!buf)
if (!*buf)
goto bail;
if (lws_vfs_file_read(fops_fd, amount, *buf, len))

View file

@ -1,5 +1,5 @@
Name: libwebsockets
Version: 2.2.0
Version: 2.3.0
Release: 1%{?dist}
Summary: Websocket Server and Client Library
@ -49,13 +49,12 @@ rm -rf $RPM_BUILD_ROOT
%attr(755,root,root)
/usr/bin/libwebsockets-test-server
/usr/bin/libwebsockets-test-server-extpoll
/usr/bin/libwebsockets-test-server-pthreads
/usr/bin/libwebsockets-test-client
/usr/bin/libwebsockets-test-ping
/usr/bin/libwebsockets-test-echo
/usr/bin/libwebsockets-test-fraggle
/usr/bin/libwebsockets-test-fuzxy
/%{_libdir}/libwebsockets.so.10
/%{_libdir}/libwebsockets.so.11
/%{_libdir}/libwebsockets.so
/%{_libdir}/cmake/libwebsockets/LibwebsocketsConfig.cmake
/%{_libdir}/cmake/libwebsockets/LibwebsocketsConfigVersion.cmake
@ -70,8 +69,12 @@ rm -rf $RPM_BUILD_ROOT
%attr(755,root,root)
/%{_libdir}/libwebsockets.a
/%{_libdir}/pkgconfig/libwebsockets.pc
/%{_libdir}/pkgconfig/libwebsockets_static.pc
%changelog
* Fri Jul 28 2017 Andy Green <andy@warmcat.com> 2.3.0-1
- MAJOR SONAMEBUMP APICHANGES Upstream 2.3.0 release
* Mon Mar 06 2017 Andy Green <andy@warmcat.com> 2.2.0-1
- MAJOR SONAMEBUMP APICHANGES Upstream 2.2.0 release

View file

@ -32,6 +32,9 @@
# vhost-specific config options for the protocol
#
"ws-protocols": [{
"lws-meta": {
"status": "ok"
},
"dumb-increment-protocol": {
"status": "ok"
},

View file

@ -58,11 +58,13 @@ static int pids[32];
#define LWSWS_CONFIG_STRING_SIZE (32 * 1024)
static const struct lws_extension exts[] = {
#if !defined(LWS_NO_EXTENSIONS)
{
"permessage-deflate",
lws_extension_callback_pm_deflate,
"permessage-deflate"
},
#endif
{ NULL, NULL, NULL /* terminator */ }
};
@ -220,7 +222,7 @@ int main(int argc, char **argv)
break;
case 'h':
fprintf(stderr, "Usage: lwsws [-c <config dir>] "
"[-d <log bitfield>] [-D] [--help]\n");
"[-d <log bitfield>] [--help]\n");
exit(1);
}
}

View file

@ -474,7 +474,7 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason,
WSI_TOKEN_HOST) < 0)
return 1;
lws_snprintf(pss->onward, sizeof(pss->onward) - 1,
"%s%s%s", oprot[lws_is_ssl(wsi)],
"%s%s%s", oprot[!!lws_is_ssl(wsi)],
cookie, args->p);
lwsl_notice("redirecting to ourselves with cookie refresh\n");
/* we need a redirect to ourselves, session cookie is expired */

616
plugins/protocol_lws_meta.c Normal file
View file

@ -0,0 +1,616 @@
/*
* lws meta protocol handler
*
* 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
*
*/
#if !defined (LWS_PLUGIN_STATIC)
#define LWS_DLL
#define LWS_INTERNAL
#include "../lib/libwebsockets.h"
#endif
#include <string.h>
#include <stdlib.h>
#define MAX_SUBCHANNELS 8
enum lws_meta_parser_state {
MP_IDLE, /* in body of message */
MP_CMD, /* await cmd */
MP_OPEN_SUBCHANNEL_PROTOCOL,
MP_OPEN_SUBCHANNEL_URL,
MP_OPEN_SUBCHANNEL_COOKIE,
MP_CLOSE_CHID,
MP_CLOSE_LEN,
MP_CLOSE_CODEM,
MP_CLOSE_CODEL,
MP_CLOSE_PAYLOAD,
MP_WRITE_CHID,
};
enum {
PENDING_TYPE_OPEN_RESULT = 0,
PENDING_TYPE_CHILD_CLOSE
};
/*
* while we haven't reported the result yet, we keep a linked-list of
* connection opens and their result.
*/
struct pending_conn {
struct pending_conn *next;
char protocol[123];
char cookie[8];
int ch;
int len;
unsigned char type;
};
/*
* the parent, lws-meta connection
*/
struct per_session_data__lws_meta {
struct lws *wsi[MAX_SUBCHANNELS + 1];
char told_closing[MAX_SUBCHANNELS + 1];
struct pending_conn *first;
struct pending_conn *pend;
char suburl[64];
unsigned char close[126];
int active_subchannel_tx, active_subchannel_rx;
enum lws_meta_parser_state state;
int pos;
int count_pending;
int round_robin;
int close_status_16;
int close_len;
int which_close;
int ch;
};
static int
lws_find_free_channel(struct per_session_data__lws_meta *pss)
{
int n;
for (n = 1; n <= MAX_SUBCHANNELS; n++)
if (pss->wsi[n] == NULL)
return n;
return 0; /* none free */
}
static struct lws *
lws_get_channel_wsi(struct per_session_data__lws_meta *pss, int ch)
{
if (!ch)
return 0;
return pss->wsi[ch];
}
static int
lws_get_channel_id(struct lws *wsi)
{
return (lws_intptr_t)lws_get_opaque_parent_data(wsi);
}
static void
lws_set_channel_id(struct lws *wsi, int id)
{
lws_set_opaque_parent_data(wsi, (void *)(lws_intptr_t)id);
}
static struct pending_conn *
new_pending(struct per_session_data__lws_meta *pss)
{
struct pending_conn *pend;
if (pss->count_pending >= MAX_SUBCHANNELS * 2) {
lwsl_notice("too many pending open subchannel\n");
return NULL;
}
pss->count_pending++;
pend = malloc(sizeof(*pend));
if (!pend) {
lwsl_notice("OOM\n");
return NULL;
}
memset(pend, 0, sizeof(*pend));
return pend;
}
static int
callback_lws_meta(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len)
{
struct per_session_data__lws_meta *pss =
(struct per_session_data__lws_meta *)user;
struct lws_write_passthru *pas;
struct pending_conn *pend, *pend1;
struct lws *cwsi;
lws_sock_file_fd_type fd;
unsigned char *bin, buf[LWS_PRE + 512], *start = &buf[LWS_PRE],
*end = &buf[sizeof(buf) - 1], *p = start;
int n, m;
switch (reason) {
case LWS_CALLBACK_ESTABLISHED:
lwsl_info("%s: LWS_CALLBACK_ESTABLISHED\n", __func__);
pss->state = MP_CMD;
pss->pos = 0;
break;
case LWS_CALLBACK_CLOSED:
break;
case LWS_CALLBACK_CHILD_CLOSING:
cwsi = (struct lws *)in;
/* remove it from our tracking */
pss->wsi[lws_get_channel_id(cwsi)] = NULL;
if (pss->told_closing[lws_get_channel_id(cwsi)]) {
pss->told_closing[lws_get_channel_id(cwsi)] = 0;
break;
}
pend = new_pending(pss);
if (!pend)
return -1;
/* note which channel id */
pend->ch = lws_get_channel_id(cwsi);
if (lws_get_close_length(cwsi)) {
pend->len = lws_get_close_length(cwsi);
memcpy(pend->protocol, lws_get_close_payload(cwsi),
pend->len);
}
pend->type = PENDING_TYPE_CHILD_CLOSE;
pend->next = pss->first;
pss->first = pend;
/*
* nothing else will complete from this wsi, so abandon
* tracking in-process messages from this wsi.
*/
if (pss->active_subchannel_tx == pend->ch)
pss->active_subchannel_tx = 0;
if (pss->active_subchannel_rx == pend->ch)
pss->active_subchannel_rx = 0;
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
if (!pss->active_subchannel_tx) {
/* not in the middle of a message...
*
* PRIORITY 1: pending open and close notifications
*/
pend = pss->first;
while (pend && p < end - 128) {
switch (pend->type) {
case PENDING_TYPE_OPEN_RESULT:
lwsl_debug("open result %s %s\n",
pend->cookie, pend->protocol);
*p++ = LWS_META_CMD_OPEN_RESULT;
memcpy(p, pend->cookie,
strlen(pend->cookie) + 1);
p += strlen(pend->cookie) + 1;
*p++ = LWS_META_TRANSPORT_OFFSET +
pend->ch;
memcpy(p, pend->protocol,
strlen(pend->protocol) + 1);
p += strlen(pend->protocol) + 1;
break;
case PENDING_TYPE_CHILD_CLOSE:
*p++ = LWS_META_CMD_CLOSE_NOTIFY;
*p++ = LWS_META_TRANSPORT_OFFSET +
pend->ch;
for (n = 0; n < pend->len; n++)
*p++ = pend->protocol[n];
break;
}
pss->count_pending--;
pend1 = pend;
pend = pend->next;
free(pend1);
pss->first = pend;
}
if (p != start) {
if (lws_write(wsi, start, p - start,
LWS_WRITE_BINARY) < 0)
return 1;
if (pend) /* still more */
lws_callback_on_writable(wsi);
break;
}
/* PRIORITY 2: pick a child for the writable callback */
cwsi = NULL;
for (n = 0; n < MAX_SUBCHANNELS; n++) {
m = ((pss->round_robin + n) % MAX_SUBCHANNELS) + 1;
if (pss->wsi[m] &&
lws_get_child_pending_on_writable(pss->wsi[m])) {
pss->round_robin = m;
cwsi = pss->wsi[m];
break;
}
}
} else
/* one child is in middle of message, stay with it */
cwsi = pss->wsi[pss->active_subchannel_tx];
if (!cwsi)
break;
lws_clear_child_pending_on_writable(cwsi);
if (lws_handle_POLLOUT_event(cwsi, NULL))
return -1;
break;
case LWS_CALLBACK_RECEIVE:
bin = (unsigned char *)in;
/*
* at the start of a message, we may have one or more
* lws_meta command blocks.
*/
while (pss->state != MP_IDLE &&
(unsigned int)(bin - (unsigned char *)in) < len) {
switch (pss->state) {
case MP_IDLE: /* in body of message */
if (!lws_is_first_fragment(wsi))
break;
pss->state = MP_CMD;
/* fallthru */
case MP_CMD: /* await cmd */
pss->pos = 0;
switch (*bin++) {
case LWS_META_CMD_OPEN_SUBCHANNEL:
pss->pend = new_pending(pss);
if (!pss->pend)
return -1;
pss->state = MP_OPEN_SUBCHANNEL_PROTOCOL;
break;
case LWS_META_CMD_CLOSE_NOTIFY:
case LWS_META_CMD_CLOSE_RQ:
pss->which_close = bin[-1];
pss->state = MP_CLOSE_CHID;
break;
case LWS_META_CMD_WRITE:
pss->state = MP_WRITE_CHID;
break;
// open result is also illegal to receive
default:
lwsl_notice("bad lws_meta cmd 0x%x\n",
bin[-1]);
return -1;
}
break;
case MP_OPEN_SUBCHANNEL_PROTOCOL:
pss->pend->protocol[pss->pos++] = *bin++;
if (pss->pos == sizeof(pss->pend->protocol) - 1) {
lwsl_notice("protocol name too long\n");
return -1;
}
if (bin[-1] != '\0')
break;
pss->state = MP_OPEN_SUBCHANNEL_URL;
pss->pos = 0;
break;
case MP_OPEN_SUBCHANNEL_URL:
pss->suburl[pss->pos++] = *bin++;
if (pss->pos == sizeof(pss->suburl) - 1) {
lwsl_notice("suburl too long\n");
return -1;
}
if (bin[-1] != '\0')
break;
pss->state = MP_OPEN_SUBCHANNEL_COOKIE;
pss->pos = 0;
break;
case MP_OPEN_SUBCHANNEL_COOKIE:
pss->pend->cookie[pss->pos++] = *bin++;
if (pss->pos == sizeof(pss->pend->cookie) - 1) {
lwsl_notice("cookie too long\n");
return -1;
}
if (bin[-1] != '\0')
break;
lwsl_debug("%s: %s / %s / %s\n", __func__,
pss->pend->protocol,
pss->suburl,
pss->pend->cookie);
pss->pend->ch = lws_find_free_channel(pss);
if (pss->pend->ch) {
fd.sockfd = 0; // not going to be used
cwsi = lws_adopt_descriptor_vhost(
lws_get_vhost(wsi),
LWS_ADOPT_WS_PARENTIO,
fd, pss->pend->protocol,
wsi);
if (!cwsi) {
lwsl_notice("open failed\n");
pss->pend->ch = 0;
} else {
pss->wsi[pss->pend->ch] = cwsi;
lws_set_channel_id(cwsi,
pss->pend->ch);
lwsl_debug("cwsi %p on parent %p open OK %s\n",
cwsi, wsi, pss->pend->protocol);
}
} else
lwsl_notice("no free subchannels\n");
pss->pend->type = PENDING_TYPE_OPEN_RESULT;
pss->pend->next = pss->first;
pss->first = pss->pend;
lws_callback_on_writable(wsi);
pss->state = MP_CMD;
pss->pos = 0;
break;
case MP_CLOSE_CHID:
pss->ch = (*bin++) - LWS_META_TRANSPORT_OFFSET;
pss->state = MP_CLOSE_LEN;
pss->pos = 0;
break;
case MP_CLOSE_LEN:
pss->close_len = (*bin++) -
LWS_META_TRANSPORT_OFFSET;
lwsl_debug("close len %d\n", pss->close_len);
pss->state = MP_CLOSE_CODEM;
pss->pos = 0;
break;
case MP_CLOSE_CODEM:
pss->close[pss->pos++] = *bin;
pss->close_status_16 = (*bin++) * 256;
pss->state = MP_CLOSE_CODEL;
break;
case MP_CLOSE_CODEL:
pss->close[pss->pos++] = *bin;
pss->close_status_16 |= *bin++;
pss->state = MP_CLOSE_PAYLOAD;
break;
case MP_CLOSE_PAYLOAD:
pss->close[pss->pos++] = *bin++;
if (pss->pos == sizeof(pss->close) - 1) {
lwsl_notice("close payload too long\n");
return -1;
}
if (--pss->close_len)
break;
pss->state = MP_CMD;
cwsi = lws_get_channel_wsi(pss, pss->ch);
if (!cwsi) {
lwsl_notice("close (%d) bad ch %d\n",
pss->which_close, pss->ch);
break;
}
if (pss->which_close == LWS_META_CMD_CLOSE_RQ) {
if (lws_get_protocol(cwsi)->callback(
cwsi,
LWS_CALLBACK_WS_PEER_INITIATED_CLOSE,
lws_wsi_user(cwsi), &pss->close,
pss->pos))
return -1;
/*
* we need to echo back the close payload
* when we send the close notification
*/
lws_close_reason(cwsi,
pss->close_status_16,
&pss->close[2],
pss->pos - 2);
}
/* so force him closed */
lws_set_timeout(cwsi,
PENDING_TIMEOUT_KILLED_BY_PARENT,
LWS_TO_KILL_SYNC);
break;
case MP_WRITE_CHID:
pss->active_subchannel_rx = (*bin++) -
LWS_META_TRANSPORT_OFFSET;
pss->state = MP_IDLE;
break;
}
}
len -= bin - (unsigned char *)in;
if (!len)
break;
cwsi = lws_get_channel_wsi(pss, pss->active_subchannel_rx);
if (!cwsi) {
lwsl_notice("bad ch %d\n", pss->active_subchannel_rx);
return -1;
}
lwsl_debug("%s: RX len %d\n", __func__, (int)len);
if (lws_get_protocol(cwsi)->callback(cwsi,
LWS_CALLBACK_RECEIVE,
lws_wsi_user(cwsi), bin, len))
lws_set_timeout(cwsi,
PENDING_TIMEOUT_KILLED_BY_PARENT,
LWS_TO_KILL_SYNC);
if (lws_is_final_fragment(wsi)) {
pss->active_subchannel_rx = 0;
pss->state = MP_CMD;
}
break;
/*
* child wrote something via lws_write.... which passed it up to us to
* deal with, because we are the parent. Prepend two bytes for
* lws-meta command and channel index, and send it out on parent
*/
case LWS_CALLBACK_CHILD_WRITE_VIA_PARENT:
pas = in;
bin = ((unsigned char *)pas->buf);
if ((pas->wp & 7) == 4 /*LWS_WRITE_CLOSE */) {
*p++ = LWS_META_CMD_CLOSE_NOTIFY;
*p++ = LWS_META_TRANSPORT_OFFSET +
lws_get_channel_id(pas->wsi);
*p++ = (unsigned char)pas->len +
LWS_META_TRANSPORT_OFFSET - 2;
*p++ = *bin++;
*p++ = *bin++;
for (n = 0; n < (int)pas->len - 2; n++)
*p++ = bin[n];
if (lws_write(wsi, start, p - start,
LWS_WRITE_BINARY) < 0)
return 1;
pss->told_closing[lws_get_channel_id(pas->wsi)] = 1;
break;
}
if ((pas->wp & 7) == LWS_WRITE_TEXT ||
(pas->wp & 7) == LWS_WRITE_BINARY) {
if (pas->wp & LWS_WRITE_NO_FIN)
pss->active_subchannel_tx =
lws_get_channel_id(pas->wsi);
/* start of message, prepend the subchannel id */
bin -= 2;
bin[0] = LWS_META_CMD_WRITE;
bin[1] = lws_get_channel_id(pas->wsi) +
LWS_META_TRANSPORT_OFFSET;
if (lws_write(wsi, bin, pas->len + 2, pas->wp) < 0)
return 1;
} else
if (lws_write(wsi, bin, pas->len, pas->wp) < 0)
return 1;
/* track EOM */
if (!(pas->wp & LWS_WRITE_NO_FIN))
pss->active_subchannel_tx = 0;
break;
default:
break;
}
return 0;
}
#define LWS_PLUGIN_PROTOCOL_LWS_META { \
"lws-meta", \
callback_lws_meta, \
sizeof(struct per_session_data__lws_meta), \
1024, /* rx buf size must be >= permessage-deflate rx size */ \
0, NULL, 0 \
}
#if !defined (LWS_PLUGIN_STATIC)
static const struct lws_protocols protocols[] = {
LWS_PLUGIN_PROTOCOL_LWS_META
};
LWS_EXTERN LWS_VISIBLE int
init_protocol_lws_meta(struct lws_context *context,
struct lws_plugin_capability *c)
{
if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
c->api_magic);
return 1;
}
c->protocols = protocols;
c->count_protocols = ARRAY_SIZE(protocols);
c->extensions = NULL;
c->count_extensions = 0;
return 0;
}
LWS_EXTERN LWS_VISIBLE int
destroy_protocol_lws_meta(struct lws_context *context)
{
return 0;
}
#endif

View file

@ -10,7 +10,9 @@ SHELL=/bin/bash
ESPPORT ?= $(CONFIG_ESPTOOLPY_PORT)
jbi=$(COMPONENT_PATH)/../build/json-buildinfo
LWS_BUILD_PATH=$(PROJECT_PATH)/build
jbi=$(LWS_BUILD_PATH)/json-buildinfo
FAC=$(CONFIG_LWS_IS_FACTORY_APPLICATION)
ifeq ($(FAC),)
@ -19,20 +21,20 @@ endif
export FAC
DIRNAME:=$(shell basename $$(pwd) | tr -d '\n')
$(COMPONENT_PATH)/../build/pack.img: $(APP_BIN)
$(LWS_BUILD_PATH)/pack.img: $(APP_BIN)
GNUSTAT=stat ;\
if [ `which gstat 2>/dev/null` ] ; then GNUSTAT=gstat ; fi ;\
DIRNAME=$$(basename $$(pwd) | tr -d '\n') ;\
genromfs -f $(COMPONENT_PATH)/../build/romfs.img -d $(COMPONENT_PATH)/../romfs-files ; \
RLEN=$$($$GNUSTAT -c %s $(COMPONENT_PATH)/../build/romfs.img) ;\
LEN=$$($$GNUSTAT -c %s $(COMPONENT_PATH)/../build/$$DIRNAME.bin) ;\
genromfs -f $(LWS_BUILD_PATH)/romfs.img -d $(PROJECT_PATH)/romfs-files ; \
RLEN=$$($$GNUSTAT -c %s $(LWS_BUILD_PATH)/romfs.img) ;\
LEN=$$($$GNUSTAT -c %s $(LWS_BUILD_PATH)/$$DIRNAME.bin) ;\
printf " Original length: 0x%06x (%8d)\n" $$LEN $$LEN ; \
printf %02x $$(( $$RLEN % 256 )) | xxd -r -p >> $(COMPONENT_PATH)/../build/$$DIRNAME.bin ;\
printf %02x $$(( ( $$RLEN / 256 ) % 256 )) | xxd -r -p >> $(COMPONENT_PATH)/../build/$$DIRNAME.bin ;\
printf %02x $$(( ( $$RLEN / 65536 ) % 256 )) | xxd -r -p >> $(COMPONENT_PATH)/../build/$$DIRNAME.bin ;\
printf %02x $$(( ( $$RLEN / 16777216 ) % 256 )) | xxd -r -p >> $(COMPONENT_PATH)/../build/$$DIRNAME.bin ;\
cat $(COMPONENT_PATH)/../build/romfs.img >>$(COMPONENT_PATH)/../build/$$DIRNAME.bin ; \
LEN=$$($$GNUSTAT -c %s $(COMPONENT_PATH)/../build/$$DIRNAME.bin) ;\
printf %02x $$(( $$RLEN % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
printf %02x $$(( ( $$RLEN / 256 ) % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
printf %02x $$(( ( $$RLEN / 65536 ) % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
printf %02x $$(( ( $$RLEN / 16777216 ) % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
cat $(LWS_BUILD_PATH)/romfs.img >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ; \
LEN=$$($$GNUSTAT -c %s $(LWS_BUILD_PATH)/$$DIRNAME.bin) ;\
UNIXTIME=$$(date +%s | tr -d '\n') ; \
echo -n -e "{\r\n \"schema\": \"lws1\",\r\n \"model\": \"$(CONFIG_LWS_MODEL_NAME)\",\r\n \"builder\": \"" > $(jbi) ;\
hostname | tr -d '\n' >> $(jbi) ;\
@ -50,14 +52,14 @@ $(COMPONENT_PATH)/../build/pack.img: $(APP_BIN)
echo -n -e "\",\r\n \"factory\": \"$(FAC)" >> $(jbi) ;\
echo -n -e "\"\r\n}" >> $(jbi) ;\
JLEN=$$($$GNUSTAT -c %s $(jbi)) ;\
printf %02x $$(( $$JLEN % 256 )) | xxd -r -p >> $(COMPONENT_PATH)/../build/$$DIRNAME.bin ;\
printf %02x $$(( ( $$JLEN / 256 ) % 256 )) | xxd -r -p >> $(COMPONENT_PATH)/../build/$$DIRNAME.bin ;\
printf %02x $$(( ( $$JLEN / 65536 ) % 256 )) | xxd -r -p >> $(COMPONENT_PATH)/../build/$$DIRNAME.bin ;\
printf %02x $$(( ( $$JLEN / 16777216 ) % 256 )) | xxd -r -p >> $(COMPONENT_PATH)/../build/$$DIRNAME.bin ;\
cat $(jbi) >> $(COMPONENT_PATH)/../build/$$DIRNAME.bin ;\
cp $(COMPONENT_PATH)/../build/$$DIRNAME.bin $(COMPONENT_PATH)/../build/pack.img ;\
LEN=$$($$GNUSTAT -c %s $(COMPONENT_PATH)/../build/$$DIRNAME.bin) ;\
cp $(COMPONENT_PATH)/../build/$$DIRNAME.bin $(COMPONENT_PATH)/../build/$$DIRNAME-$$UNIXTIME.bin ;\
printf %02x $$(( $$JLEN % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
printf %02x $$(( ( $$JLEN / 256 ) % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
printf %02x $$(( ( $$JLEN / 65536 ) % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
printf %02x $$(( ( $$JLEN / 16777216 ) % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
cat $(jbi) >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
cp $(LWS_BUILD_PATH)/$$DIRNAME.bin $(LWS_BUILD_PATH)/pack.img ;\
LEN=$$($$GNUSTAT -c %s $(LWS_BUILD_PATH)/$$DIRNAME.bin) ;\
cp $(LWS_BUILD_PATH)/$$DIRNAME.bin $(LWS_BUILD_PATH)/$$DIRNAME-$$UNIXTIME.bin ;\
printf " After ROMFS + Build info: 0x%06x (%8d)\n" $$LEN $$LEN
.PHONY: manifest
@ -76,17 +78,17 @@ endif
cat $(F)/build/json-buildinfo >> build/manifest.json
echo -n -e "\r\n}\r\n" >> build/manifest.json
all: $(COMPONENT_PATH)/../build/pack.img
all: $(LWS_BUILD_PATH)/pack.img
flash: $(COMPONENT_PATH)/../build/pack.img
flash: $(LWS_BUILD_PATH)/pack.img
flash_ota: $(COMPONENT_PATH)/../build/pack.img
flash_ota: $(LWS_BUILD_PATH)/pack.img
DIRNAME=$$(basename $$(pwd) | tr -d '\n') ;\
$(IDF_PATH)/components/esptool_py/esptool/esptool.py \
--chip esp32 \
--port $(ESPPORT) \
--baud $(CONFIG_ESPTOOLPY_BAUD) \
write_flash 0x110000 $(COMPONENT_PATH)/../build/$$DIRNAME.bin
write_flash 0x110000 $(LWS_BUILD_PATH)/$$DIRNAME.bin
erase_ota:
$(IDF_PATH)/components/esptool_py/esptool/esptool.py \

View file

@ -29,10 +29,10 @@ function check {
fi
if [ "$1" = "defaultplusforbidden" ] ; then
cat $INSTALLED/../share/libwebsockets-test-server/test.html > /tmp/plusforb
echo -e -n "HTTP/1.1 403 Forbidden\x0d\x0aserver: libwebsockets\x0d\x0acontent-type: text/html\x0d\x0acontent-length: 38\x0d\x0a\x0d\x0a<html><body><h1>403</h1></body></html>" >> /tmp/plusforb
echo -e -n "HTTP/1.1 403 Forbidden\x0d\x0acontent-type: text/html\x0d\x0acontent-length: 38\x0d\x0a\x0d\x0a<html><body><h1>403</h1></body></html>" >> /tmp/plusforb
diff /tmp/lwscap /tmp/plusforb > /dev/null
if [ $? -ne 0 ] ; then
echo "FAIL: got something other than test.html back"
echo "FAIL: got something other than test.html + forbidden back"
exit 1
fi
fi
@ -101,7 +101,9 @@ killall libwebsockets-test-server 2>/dev/null
libwebsockets-test-server -d15 2>> $LOG &
CPID=$!
while [ -z "`grep Listening $LOG`" ] ; do
echo "Started server on PID $CPID"
while [ -z "`grep ort\ 7681 $LOG`" ] ; do
sleep 0.5s
done
check
@ -220,7 +222,7 @@ echo -e "GET ...................................................................
check
echo
echo "---- good request but http payload coming too (should be ignored and test.html served)"
echo "---- good request but http payload coming too (test.html served then forbidden)"
echo -e "GET /test.html HTTP/1.1\x0d\x0a\x0d\x0aILLEGAL-PAYLOAD........................................" \
"......................................................................................................................." \
"......................................................................................................................." \

View file

@ -108,6 +108,285 @@ function removeEvent( obj, type, fn ) {
* end of grayOut related stuff
*/
/*
* lws-meta helpers
*/
var lws_meta_cmd = {
OPEN_SUBCHANNEL: 0x41,
/**< Client requests to open new subchannel
*/
OPEN_RESULT: 0x42,
/**< Result of client request to open new subchannel */
CLOSE_NOT: 0x43,
CLOSE_RQ: 0x44,
/**< client requests to close a subchannel */
WRITE: 0x45,
/**< connection writes something to specific channel index */
RX: 0x46,
};
function new_ws(urlpath, protocol)
{
if (typeof MozWebSocket != "undefined")
return new MozWebSocket(urlpath, protocol);
return new WebSocket(urlpath, protocol);
}
function lws_meta_ws() {
var real;
var channel_id_to_child;
var pending_children;
var active_children;
}
function lws_meta_ws_child() {
var onopen;
var onmessage;
var onclose;
var channel_id;
var subprotocol;
var suburl;
var cookie;
var extensions;
var parent;
}
lws_meta_ws_child.prototype.send = function(data)
{
if (typeof data == "string") {
data = String.fromCharCode(lws_meta_cmd.WRITE) +
String.fromCharCode(this.channel_id) +
data;
return this.parent.real.send(data);
}
{
var ab = new Uint8Array(data.length + 2);
ab[0] = lws_meta_cmd.WRITE;
ab[1] = this.channel_id;
ab.set(data, 2);
return this.parent.real.send(ab);
}
}
lws_meta_ws_child.prototype.close = function(close_code, close_string)
{
var pkt = new Uint8Array(129), m = 0, pkt1;
pkt[m++] = lws_meta_cmd.CLOSE_RQ;
pkt[m++] = this.channel_id;
pkt[m++] = close_string.length + 0x20;
pkt[m++] = close_code / 256;
pkt[m++] = close_code % 256;
for (i = 0; i < close_string.length; i++)
pkt[m++] = close_string.charCodeAt(i);
pkt1 = new Uint8Array(m);
for (n = 0; n < m; n++)
pkt1[n] = pkt[n];
this.parent.real.send(pkt1.buffer);
}
/* make a real ws connection using lws_meta*/
lws_meta_ws.prototype.new_parent = function(urlpath)
{
var n, i, m = 0, pkt1;
this.ordinal = 1;
this.pending_children = [];
this.active_children = [];
this.real = new_ws(urlpath, "lws-meta");
this.real.binaryType = 'arraybuffer';
this.real.myparent = this;
this.real.onopen = function() {
pkt = new Uint8Array(1024);
var n, i, m = 0, pkt1;
console.log("real open - pending children " + this.myparent.pending_children.length);
for (n = 0; n < this.myparent.pending_children.length; n++) {
var p = this.myparent.pending_children[n];
pkt[m++] = lws_meta_cmd.OPEN_SUBCHANNEL;
for (i = 0; i < p.subprotocol.length; i++)
pkt[m++] = p.subprotocol.charCodeAt(i);
pkt[m++] = 0;
for (i = 0; i < p.suburl.length; i++)
pkt[m++] = p.suburl.charCodeAt(i);
pkt[m++] = 0;
for (i = 0; i < p.cookie.length; i++)
pkt[m++] = p.cookie.charCodeAt(i);
pkt[m++] = 0;
}
pkt1 = new Uint8Array(m);
for (n = 0; n < m; n++)
pkt1[n] = pkt[n];
console.log(this.myparent.pending_children[0].subprotocol);
console.log(pkt1);
this.send(pkt1.buffer);
}
this.real.onmessage = function(msg) {
if (typeof msg.data != "string") {
var ba = new Uint8Array(msg.data), n = 0;
while (n < ba.length) {
switch (ba[n++]) {
case lws_meta_cmd.OPEN_RESULT:
{
var m = 0, cookie = "", protocol = "", ch = 0;
var ws = this.myparent;
/* cookie NUL
* channel index + 0x20
* protocol NUL
*/
while (ba[n])
cookie = cookie + String.fromCharCode(ba[n++]);
n++;
ch = ba[n++];
while (ba[n])
protocol = protocol + String.fromCharCode(ba[n++]);
console.log("open result " + cookie + " " + protocol + " " + ch + " pending len " + ws.pending_children.length);
for (m = 0; m < ws.pending_children.length; m++) {
if (ws.pending_children[m].cookie == cookie) {
var newchild = ws.pending_children[m];
/* found it */
ws.pending_children[m].channel_id = ch;
/* add to active children array */
ws.active_children.push(ws.pending_children[m]);
/* remove from pending children array */
ws.pending_children.splice(m, 1);
newchild.parent = ws;
newchild.extensions = this.extensions;
newchild.onopen();
console.log("made active " + cookie);
break;
}
}
break;
}
case lws_meta_cmd.CLOSE_NOT:
{
var code = 0, str = "", ch = 0, m, le;
var ba = new Uint8Array(msg.data);
/*
* BYTE: channel
* BYTE: MSB status code
* BYTE: LSB status code
* BYTES: rest of message is close status string
*/
ch = ba[n++];
le = ba[n++] - 0x20;
code = ba[n++] * 256;
code += ba[n++];
while (le--)
str += String.fromCharCode(ba[n++]);
console.log("channel id " + ch + " code " + code + " str " + str + " len " + str.length);
for (m = 0; m < this.myparent.active_children.length; m++)
if (this.myparent.active_children[m].channel_id == ch) {
var child = this.myparent.active_children[m];
var ms = new CloseEvent("close", { code:code, reason:str } );
/* reply with close ack */
this.send(msg.data);
if (child.onclose)
child.onclose(ms);
this.myparent.active_children.splice(m, 1);
break;
}
}
} // switch
}
} else {
if (msg.data.charCodeAt(0) == lws_meta_cmd.WRITE ) {
var ch = msg.data.charCodeAt(1), m, ms;
var ws = this.myparent, ms;
for (m = 0; m < ws.active_children.length; m++) {
if (ws.active_children[m].channel_id == ch) {
ms = new MessageEvent("WebSocket", { data: msg.data.substr(2, msg.data.length - 2) } );
if (ws.active_children[m].onmessage)
ws.active_children[m].onmessage(ms);
break;
}
}
}
}
}
this.real.onclose = function() {
var ws = this.myparent, m;
for (m = 0; m < ws.active_children.length; m++) {
var child = ws.active_children[m];
var ms = new CloseEvent("close", { code:1000, reason:"parent closed" } );
if (child.onclose)
child.onclose(ms);
}
}
}
/* make a child connection using existing lws_meta real ws connection */
lws_meta_ws.prototype.new_ws = function(suburl, protocol)
{
var ch = new lws_meta_ws_child();
ch.suburl = suburl;
ch.subprotocol = protocol;
ch.cookie = "C" + this.ordinal++;
this.pending_children.push(ch);
if (this.real.readyState == 1)
this.real.onopen();
return ch;
}
/*
* end of lws-meta helpers
*/
function lws_san(s)
{

View file

@ -536,7 +536,8 @@ int main(int argc, char **argv)
/* stats */
fprintf(stderr, "\n--- %s websocket ping statistics "
if (global_rx_count && global_tx_count)
fprintf(stderr, "\n--- %s websocket ping statistics "
"using %d connections ---\n"
"%lu packets transmitted, %lu received, "
"%lu%% packet loss, time %ldms\n"

View file

@ -524,7 +524,7 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
}
#ifndef LWS_NO_CLIENT
if (pss->reason_bf & 2) {
if (pss->reason_bf & LWS_CB_REASON_AUX_BF__PROXY) {
char *px = buf + LWS_PRE;
int lenx = sizeof(buf) - LWS_PRE;
/*
@ -535,7 +535,7 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
*/
pss->reason_bf &= ~2;
pss->reason_bf &= ~LWS_CB_REASON_AUX_BF__PROXY;
wsi1 = lws_get_child(wsi);
if (!wsi1)
break;
@ -674,7 +674,7 @@ bail:
if (!lws_get_parent(wsi))
break;
pss1 = lws_wsi_user(lws_get_parent(wsi));
pss1->reason_bf |= 2;
pss1->reason_bf |= LWS_CB_REASON_AUX_BF__PROXY;
lws_callback_on_writable(lws_get_parent(wsi));
break;
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:

View file

@ -1,7 +1,7 @@
/*
* libwebsockets-test-server - libwebsockets test implementation
*
* Copyright (C) 2011-2016 Andy Green <andy@warmcat.com>
* Copyright (C) 2011-2017 Andy Green <andy@warmcat.com>
*
* This file is made available under the Creative Commons CC0 1.0
* Universal Public Domain Dedication.
@ -34,6 +34,11 @@ char *resource_path = LOCAL_RESOURCE_PATH;
char crl_path[1024] = "";
#endif
#define LWS_PLUGIN_STATIC
#include "../plugins/protocol_lws_mirror.c"
#include "../plugins/protocol_lws_status.c"
#include "../plugins/protocol_lws_meta.c"
/* singlethreaded version --> no locks */
void test_server_lock(int care)
@ -59,60 +64,53 @@ void test_server_unlock(int care)
*/
enum demo_protocols {
/* always first */
PROTOCOL_HTTP = 0,
/* always first */
PROTOCOL_HTTP = 0,
PROTOCOL_DUMB_INCREMENT,
PROTOCOL_LWS_MIRROR,
PROTOCOL_DUMB_INCREMENT,
PROTOCOL_LWS_MIRROR,
PROTOCOL_LWS_META,
/* always last */
DEMO_PROTOCOL_COUNT
/* always last */
DEMO_PROTOCOL_COUNT
};
/* list of supported protocols and callbacks */
static struct lws_protocols protocols[] = {
/* first protocol must always be HTTP handler */
/* first protocol must always be HTTP handler */
{
"http-only", /* name */
callback_http, /* callback */
sizeof (struct per_session_data__http), /* per_session_data_size */
0, /* max frame size / rx buffer */
},
{
"dumb-increment-protocol",
callback_dumb_increment,
sizeof(struct per_session_data__dumb_increment),
10,
},
{
"lws-mirror-protocol",
callback_lws_mirror,
sizeof(struct per_session_data__lws_mirror),
128,
},
{
"lws-status",
callback_lws_status,
sizeof(struct per_session_data__lws_status),
128,
},
{ NULL, NULL, 0, 0 } /* terminator */
{
"http-only", /* name */
callback_http, /* callback */
sizeof (struct per_session_data__http), /* per_session_data_size */
0, /* max frame size / rx buffer */
},
{
"dumb-increment-protocol",
callback_dumb_increment,
sizeof(struct per_session_data__dumb_increment),
10,
},
LWS_PLUGIN_PROTOCOL_MIRROR,
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
LWS_PLUGIN_PROTOCOL_LWS_META,
{ NULL, NULL, 0, 0 } /* terminator */
};
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 */ }
{
"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 */ }
};
/* this shows how to override the lws file operations. You don't need
@ -121,226 +119,227 @@ static const struct lws_extension exts[] = {
*/
static lws_fop_fd_t
test_server_fops_open(const struct lws_plat_file_ops *fops,
const char *vfs_path, const char *vpath,
lws_fop_flags_t *flags)
const char *vfs_path, const char *vpath,
lws_fop_flags_t *flags)
{
lws_fop_fd_t n;
lws_fop_fd_t n;
/* call through to original platform implementation */
n = fops_plat.open(fops, vfs_path, vpath, flags);
/* call through to original platform implementation */
n = fops_plat.open(fops, vfs_path, vpath, flags);
lwsl_notice("%s: opening %s, ret %p\n", __func__, vfs_path, n);
lwsl_notice("%s: opening %s, ret %p\n", __func__, vfs_path, n);
return n;
return n;
}
void signal_cb(evutil_socket_t sock_fd, short events, void *ctx)
{
lwsl_notice("Signal caught, exiting...\n");
force_exit = 1;
if (events & EV_SIGNAL) {
struct event_base *event_base_loop = event_get_base((struct event *) ctx);
event_base_loopbreak(event_base_loop);
}
struct event_base *event_base_loop = ctx;
lwsl_notice("Signal caught, exiting...\n");
force_exit = 1;
if (events & EV_SIGNAL)
event_base_loopbreak(event_base_loop);
}
static void
ev_timeout_cb (evutil_socket_t sock_fd, short events, void *ctx)
{
lws_callback_on_writable_all_protocol(context,
&protocols[PROTOCOL_DUMB_INCREMENT]);
lws_callback_on_writable_all_protocol(context,
&protocols[PROTOCOL_DUMB_INCREMENT]);
}
static struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "debug", required_argument, NULL, 'd' },
{ "port", required_argument, NULL, 'p' },
{ "ssl", no_argument, NULL, 's' },
{ "allow-non-ssl", no_argument, NULL, 'a' },
{ "interface", required_argument, NULL, 'i' },
{ "closetest", no_argument, NULL, 'c' },
{ "libevent", no_argument, NULL, 'e' },
{ "help", no_argument, NULL, 'h' },
{ "debug", required_argument, NULL, 'd' },
{ "port", required_argument, NULL, 'p' },
{ "ssl", no_argument, NULL, 's' },
{ "allow-non-ssl", no_argument, NULL, 'a' },
{ "interface", required_argument, NULL, 'i' },
{ "closetest", no_argument, NULL, 'c' },
{ "libevent", no_argument, NULL, 'e' },
#ifndef LWS_NO_DAEMONIZE
{ "daemonize", no_argument, NULL, 'D' },
{ "daemonize", no_argument, NULL, 'D' },
#endif
{ "resource_path", required_argument, NULL, 'r' },
{ NULL, 0, 0, 0 }
{ "resource_path", required_argument, NULL, 'r' },
{ NULL, 0, 0, 0 }
};
int main(int argc, char **argv)
{
int sigs[] = { SIGINT, SIGKILL, SIGTERM, SIGSEGV, SIGFPE };
struct event *signals[ARRAY_SIZE(sigs)];
struct event_base *event_base_loop = event_base_new();
struct lws_context_creation_info info;
char interface_name[128] = "";
const char *iface = NULL;
struct event *timeout_watcher;
char cert_path[1024];
char key_path[1024];
int use_ssl = 0;
int opts = 0;
int n = 0;
int sigs[] = { SIGINT, SIGKILL, SIGTERM, SIGSEGV, SIGFPE };
struct event *signals[ARRAY_SIZE(sigs)];
struct event_base *event_base_loop = event_base_new();
struct lws_context_creation_info info;
char interface_name[128] = "";
const char *iface = NULL;
struct event *timeout_watcher;
char cert_path[1024];
char key_path[1024];
int use_ssl = 0;
int opts = 0;
int n = 0;
#ifndef _WIN32
int syslog_options = LOG_PID | LOG_PERROR;
int syslog_options = LOG_PID | LOG_PERROR;
#endif
#ifndef LWS_NO_DAEMONIZE
int daemonize = 0;
int daemonize = 0;
#endif
/*
* take care to zero down the info struct, he contains random garbaage
* from the stack otherwise
*/
memset(&info, 0, sizeof info);
info.port = 7681;
/*
* take care to zero down the info struct, he contains random garbaage
* from the stack otherwise
*/
memset(&info, 0, sizeof info);
info.port = 7681;
while (n >= 0) {
n = getopt_long(argc, argv, "eci:hsap:d:Dr:", options, NULL);
if (n < 0)
continue;
switch (n) {
case 'e':
opts |= LWS_SERVER_OPTION_LIBEVENT;
break;
while (n >= 0) {
n = getopt_long(argc, argv, "eci:hsap:d:Dr:", options, NULL);
if (n < 0)
continue;
switch (n) {
case 'e':
opts |= LWS_SERVER_OPTION_LIBEVENT;
break;
#ifndef LWS_NO_DAEMONIZE
case 'D':
daemonize = 1;
#ifndef _WIN32
syslog_options &= ~LOG_PERROR;
#endif
break;
case 'D':
daemonize = 1;
#ifndef _WIN32
syslog_options &= ~LOG_PERROR;
#endif
case 'd':
debug_level = atoi(optarg);
break;
case 's':
use_ssl = 1;
break;
case 'a':
opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
break;
case 'p':
info.port = atoi(optarg);
break;
case 'i':
strncpy(interface_name, optarg, sizeof interface_name);
interface_name[(sizeof interface_name) - 1] = '\0';
iface = interface_name;
break;
case 'c':
close_testing = 1;
fprintf(stderr, " Close testing mode -- closes on "
"client after 50 dumb increments"
"and suppresses lws_mirror spam\n");
break;
case 'r':
resource_path = optarg;
printf("Setting resource path to \"%s\"\n", resource_path);
break;
case 'h':
fprintf(stderr, "Usage: test-server "
"[--port=<p>] [--ssl] "
"[-d <log bitfield>] "
"[--resource_path <path>]\n");
exit(1);
}
}
break;
#endif
case 'd':
debug_level = atoi(optarg);
break;
case 's':
use_ssl = 1;
break;
case 'a':
opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
break;
case 'p':
info.port = atoi(optarg);
break;
case 'i':
strncpy(interface_name, optarg, sizeof interface_name);
interface_name[(sizeof interface_name) - 1] = '\0';
iface = interface_name;
break;
case 'c':
close_testing = 1;
fprintf(stderr, " Close testing mode -- closes on "
"client after 50 dumb increments"
"and suppresses lws_mirror spam\n");
break;
case 'r':
resource_path = optarg;
printf("Setting resource path to \"%s\"\n", resource_path);
break;
case 'h':
fprintf(stderr, "Usage: test-server "
"[--port=<p>] [--ssl] "
"[-d <log bitfield>] "
"[--resource_path <path>]\n");
exit(1);
}
}
#if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32)
/*
* normally lock path would be /var/lock/lwsts or similar, to
* simplify getting started without having to take care about
* permissions or running as root, set to /tmp/.lwsts-lock
*/
if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) {
fprintf(stderr, "Failed to daemonize\n");
return 1;
}
/*
* normally lock path would be /var/lock/lwsts or similar, to
* simplify getting started without having to take care about
* permissions or running as root, set to /tmp/.lwsts-lock
*/
if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) {
fprintf(stderr, "Failed to daemonize\n");
return 1;
}
#endif
for (n = 0; n < ARRAY_SIZE(sigs); n++) {
signals[n] = evsignal_new(event_base_loop, sigs[n], signal_cb, event_self_cbarg());
evsignal_add(signals[n], NULL);
}
for (n = 0; n < ARRAY_SIZE(sigs); n++) {
signals[n] = evsignal_new(event_base_loop, sigs[n], signal_cb, event_base_loop);
evsignal_add(signals[n], NULL);
}
#ifndef _WIN32
/* we will only try to log things according to our debug_level */
setlogmask(LOG_UPTO (LOG_DEBUG));
openlog("lwsts", syslog_options, LOG_DAEMON);
/* we will only try to log things according to our debug_level */
setlogmask(LOG_UPTO (LOG_DEBUG));
openlog("lwsts", syslog_options, LOG_DAEMON);
#endif
/* tell the library what debug level to emit and to send it to syslog */
lws_set_log_level(debug_level, lwsl_emit_syslog);
/* tell the library what debug level to emit and to send it to syslog */
lws_set_log_level(debug_level, lwsl_emit_syslog);
lwsl_notice("libwebsockets test server libevent - license LGPL2.1+SLE\n");
lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n");
lwsl_notice("libwebsockets test server libevent - license LGPL2.1+SLE\n");
lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n");
printf("Using resource path \"%s\"\n", resource_path);
printf("Using resource path \"%s\"\n", resource_path);
info.iface = iface;
info.protocols = protocols;
info.extensions = exts;
info.iface = iface;
info.protocols = protocols;
info.extensions = exts;
info.ssl_cert_filepath = NULL;
info.ssl_private_key_filepath = NULL;
info.ssl_cert_filepath = NULL;
info.ssl_private_key_filepath = NULL;
if (use_ssl) {
if (strlen(resource_path) > sizeof(cert_path) - 32) {
lwsl_err("resource path too long\n");
return -1;
}
sprintf(cert_path, "%s/libwebsockets-test-server.pem",
resource_path);
if (strlen(resource_path) > sizeof(key_path) - 32) {
lwsl_err("resource path too long\n");
return -1;
}
sprintf(key_path, "%s/libwebsockets-test-server.key.pem",
resource_path);
if (use_ssl) {
if (strlen(resource_path) > sizeof(cert_path) - 32) {
lwsl_err("resource path too long\n");
return -1;
}
sprintf(cert_path, "%s/libwebsockets-test-server.pem",
resource_path);
if (strlen(resource_path) > sizeof(key_path) - 32) {
lwsl_err("resource path too long\n");
return -1;
}
sprintf(key_path, "%s/libwebsockets-test-server.key.pem",
resource_path);
info.ssl_cert_filepath = cert_path;
info.ssl_private_key_filepath = key_path;
info.ssl_cert_filepath = cert_path;
info.ssl_private_key_filepath = key_path;
opts |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
}
info.gid = -1;
info.uid = -1;
info.max_http_header_pool = 1;
info.options = opts | LWS_SERVER_OPTION_LIBEVENT;
opts |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
}
info.gid = -1;
info.uid = -1;
info.max_http_header_pool = 1;
info.options = opts | LWS_SERVER_OPTION_LIBEVENT;
context = lws_create_context(&info);
if (context == NULL) {
lwsl_err("libwebsocket init failed\n");
return -1;
}
context = lws_create_context(&info);
if (context == NULL) {
lwsl_err("libwebsocket init failed\n");
return -1;
}
/*
* this shows how to override the lws file operations. You don't need
* to do any of this unless you have a reason (eg, want to serve
* compressed files without decompressing the whole archive)
*/
/* stash original platform fops */
fops_plat = *(lws_get_fops(context));
/* override the active fops */
lws_get_fops(context)->open = test_server_fops_open;
/*
* this shows how to override the lws file operations. You don't need
* to do any of this unless you have a reason (eg, want to serve
* compressed files without decompressing the whole archive)
*/
/* stash original platform fops */
fops_plat = *(lws_get_fops(context));
/* override the active fops */
lws_get_fops(context)->open = test_server_fops_open;
// Don't use the default Signal Event Watcher & Handler
lws_event_sigint_cfg(context, 0, NULL);
// Initialize the LWS with libevent loop
lws_event_initloop(context, event_base_loop, 0);
// Don't use the default Signal Event Watcher & Handler
lws_event_sigint_cfg(context, 0, NULL);
// Initialize the LWS with libevent loop
lws_event_initloop(context, event_base_loop, 0);
timeout_watcher = evtimer_new(event_base_loop, ev_timeout_cb, NULL);
struct timeval tv = {0, 50000};
evtimer_add(timeout_watcher, &tv);
event_base_dispatch(event_base_loop);
timeout_watcher = event_new(event_base_loop, -1, EV_PERSIST, ev_timeout_cb, NULL);
struct timeval tv = {0, 50000};
evtimer_add(timeout_watcher, &tv);
event_base_dispatch(event_base_loop);
lws_context_destroy(context);
lwsl_notice("libwebsockets-test-server exited cleanly\n");
lws_context_destroy(context);
lwsl_notice("libwebsockets-test-server exited cleanly\n");
#ifndef _WIN32
closelog();
closelog();
#endif
return 0;
return 0;
}

View file

@ -50,6 +50,7 @@ void test_server_unlock(int care)
#include "../plugins/protocol_dumb_increment.c"
#include "../plugins/protocol_lws_mirror.c"
#include "../plugins/protocol_lws_status.c"
#include "../plugins/protocol_lws_meta.c"
/*
* This demo server shows how to use libwebsockets for one or more
@ -73,6 +74,7 @@ enum demo_protocols {
PROTOCOL_DUMB_INCREMENT,
PROTOCOL_LWS_MIRROR,
PROTOCOL_LWS_STATUS,
PROTOCOL_LWS_META,
/* always last */
DEMO_PROTOCOL_COUNT
@ -92,6 +94,7 @@ static struct lws_protocols protocols[] = {
LWS_PLUGIN_PROTOCOL_DUMB_INCREMENT,
LWS_PLUGIN_PROTOCOL_MIRROR,
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
LWS_PLUGIN_PROTOCOL_LWS_META,
{ NULL, NULL, 0, 0 } /* terminator */
};
@ -456,6 +459,9 @@ int main(int argc, char **argv)
lwsl_notice("uv loop close rc %s\n",
e ? uv_strerror(e) : "ok");
/* PHASE 4: finalize context destruction */
lws_context_destroy2(context);
} else
#endif
{

View file

@ -226,8 +226,15 @@ static const struct lws_protocol_vhost_options pvo_opt4 = {
* linked-list. We can also give the plugin per-vhost options here.
*/
static const struct lws_protocol_vhost_options pvo_4 = {
static const struct lws_protocol_vhost_options pvo_5 = {
NULL,
NULL,
"lws-meta",
"" /* ignored, just matches the protocol name above */
};
static const struct lws_protocol_vhost_options pvo_4 = {
&pvo_5,
&pvo_opt4, /* set us as the protocol who gets raw connections */
"protocol-lws-raw-test",
"" /* ignored, just matches the protocol name above */

View file

@ -68,6 +68,7 @@ char crl_path[1024] = "";
#define LWS_PLUGIN_STATIC
#include "../plugins/protocol_lws_mirror.c"
#include "../plugins/protocol_lws_status.c"
#include "../plugins/protocol_lws_meta.c"
/* singlethreaded version --> no locks */
@ -104,6 +105,8 @@ enum demo_protocols {
PROTOCOL_LWS_MIRROR,
PROTOCOL_LWS_STATUS,
PROTOCOL_LWS_META,
/* always last */
DEMO_PROTOCOL_COUNT
};
@ -130,6 +133,8 @@ static struct lws_protocols protocols[] = {
},
LWS_PLUGIN_PROTOCOL_MIRROR,
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
LWS_PLUGIN_PROTOCOL_LWS_META,
{ NULL, NULL, 0, 0 } /* terminator */
};

View file

@ -533,21 +533,31 @@ if (params.mirror)
mirror_name = params.mirror;
console.log(mirror_name);
function new_ws(urlpath, protocol)
{
if (typeof MozWebSocket != "undefined")
return new MozWebSocket(urlpath, protocol);
/*
* if using lws-meta to carry the other ws connections, declare the
* parent connection object and start its connection to the server.
*
* These helpers are defined in lws-common.js
*/
return new WebSocket(get_appropriate_ws_url(urlpath), protocol);
}
var lws_meta = new lws_meta_ws();
lws_meta.new_parent(get_appropriate_ws_url("?mirror=" + mirror_name));
document.getElementById("number").textContent = get_appropriate_ws_url(mirror_name);
/* dumb increment protocol */
/*
* to connect via an lws-meta connection, start the connection using
* lws_meta.new_ws(). To connect by independent connection, start
* the connection using just new_ws()
*/
var socket_di = new_ws("", "dumb-increment-protocol");
var socket_di = lws_meta.new_ws("", "dumb-increment-protocol");
try {
socket_di.onopen = function() {
@ -571,8 +581,8 @@ document.getElementById("number").textContent = get_appropriate_ws_url(mirror_na
var socket_status, jso, s;
socket_status = new_ws(get_appropriate_ws_url(""), "lws-status");
socket_status = lws_meta.new_ws(get_appropriate_ws_url(""), "lws-status");
try {
socket_status.onopen = function() {
@ -585,6 +595,8 @@ document.getElementById("number").textContent = get_appropriate_ws_url(mirror_na
socket_status.onmessage =function got_packet(msg) {
var s;
console.log(msg.data);
jso = JSON.parse(msg.data);
document.getElementById("servinfo").innerHTML =
@ -637,7 +649,9 @@ var socket_ot;
function ot_open() {
socket_ot = new_ws(get_appropriate_ws_url(""), "dumb-increment-protocol");
socket_ot = lws_meta.new_ws(get_appropriate_ws_url(""), "dumb-increment-protocol");
console.log("ot_open");
try {
socket_ot.onopen = function() {
@ -646,6 +660,7 @@ function ot_open() {
document.getElementById("ot_open_btn").disabled = true;
document.getElementById("ot_close_btn").disabled = false;
document.getElementById("ot_req_close_btn").disabled = false;
console.log("ot_open.onopen");
}
socket_ot.onclose = function(e){
@ -680,7 +695,7 @@ function ot_req_close() {
var socket_lm;
var color = "#000000";
socket_lm = new_ws(get_appropriate_ws_url("?mirror=" + mirror_name),
socket_lm = lws_meta.new_ws(get_appropriate_ws_url("?mirror=" + mirror_name),
"lws-mirror-protocol");
try {