Compare commits
54 commits
Author | SHA1 | Date | |
---|---|---|---|
7f6db4fe8d | |||
![]() |
debb7aa043 | ||
![]() |
ca045d4a8e | ||
![]() |
4ce725903d | ||
![]() |
a2943ca41d | ||
![]() |
04134742f9 | ||
![]() |
2e5110e731 | ||
![]() |
afc9c0ac26 | ||
![]() |
5b23b8c99f | ||
![]() |
b66e8e1898 | ||
![]() |
0bb3646256 | ||
![]() |
c60b2413a4 | ||
![]() |
58195fbc1e | ||
![]() |
c2abf59c68 | ||
![]() |
4b24369d64 | ||
![]() |
872e8d7e9d | ||
![]() |
5da9ce2f06 | ||
![]() |
b93c057472 | ||
![]() |
5a38d88fdd | ||
![]() |
a9f74f2dbe | ||
![]() |
219a367a4c | ||
![]() |
93a5b586a3 | ||
![]() |
040b408029 | ||
![]() |
16ef37ef5d | ||
![]() |
e6bd6296bd | ||
![]() |
4a9c23e9ec | ||
![]() |
c6233ce403 | ||
![]() |
7849c5a8ad | ||
![]() |
414f114b8f | ||
![]() |
855f7e8712 | ||
![]() |
9f31e94e09 | ||
![]() |
855453d1ae | ||
![]() |
d86641ed3a | ||
![]() |
41c15511eb | ||
![]() |
d766c99861 | ||
![]() |
ba45f7cf9f | ||
![]() |
19a320a578 | ||
![]() |
61e58885f4 | ||
![]() |
3562e441e3 | ||
![]() |
003bd7dcee | ||
![]() |
75bbb3b2c0 | ||
![]() |
8ccc64679f | ||
![]() |
6c09952065 | ||
![]() |
09f3947b4c | ||
![]() |
941e93ea33 | ||
![]() |
c9da1ffa2e | ||
![]() |
ad15082563 | ||
![]() |
2d313bdc02 | ||
![]() |
3526fde154 | ||
![]() |
bd1dd7efd4 | ||
![]() |
1690581cd2 | ||
![]() |
3c360d5192 | ||
![]() |
8a4881a142 | ||
![]() |
6f11c1361a |
43 changed files with 2214 additions and 447 deletions
|
@ -11,7 +11,6 @@ env:
|
||||||
- LWS_METHOD=noext CMAKE_ARGS="-DLWS_WITHOUT_EXTENSIONS=ON"
|
- LWS_METHOD=noext CMAKE_ARGS="-DLWS_WITHOUT_EXTENSIONS=ON"
|
||||||
- LWS_METHOD=libev CMAKE_ARGS="-DLWS_WITH_LIBEV=ON"
|
- LWS_METHOD=libev CMAKE_ARGS="-DLWS_WITH_LIBEV=ON"
|
||||||
- LWS_METHOD=noipv6 CMAKE_ARGS="-DLWS_IPV6=OFF"
|
- 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=nossl CMAKE_ARGS="-DLWS_WITH_SSL=OFF"
|
||||||
- LWS_METHOD=nodaemon CMAKE_ARGS="-DLWS_WITHOUT_DAEMONIZE=ON"
|
- LWS_METHOD=nodaemon CMAKE_ARGS="-DLWS_WITHOUT_DAEMONIZE=ON"
|
||||||
- LWS_METHOD=cgi CMAKE_ARGS="-DLWS_WITH_CGI=ON"
|
- LWS_METHOD=cgi CMAKE_ARGS="-DLWS_WITH_CGI=ON"
|
||||||
|
|
|
@ -9,12 +9,12 @@ project(libwebsockets C)
|
||||||
set(PACKAGE "libwebsockets")
|
set(PACKAGE "libwebsockets")
|
||||||
set(CPACK_PACKAGE_NAME "${PACKAGE}")
|
set(CPACK_PACKAGE_NAME "${PACKAGE}")
|
||||||
set(CPACK_PACKAGE_VERSION_MAJOR "2")
|
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_PATCH "0")
|
||||||
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
|
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_VENDOR "andy@warmcat.com")
|
||||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PACKAGE} ${PACKAGE_VERSION}")
|
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PACKAGE} ${PACKAGE_VERSION}")
|
||||||
set(SOVERSION "10")
|
set(SOVERSION "11")
|
||||||
if(NOT CPACK_GENERATOR)
|
if(NOT CPACK_GENERATOR)
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
set(CPACK_GENERATOR "TGZ")
|
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_WITHOUT_DAEMONIZE "Don't build the daemonization api" ON)
|
||||||
option(LWS_IPV6 "Compile with support for ipv6" OFF)
|
option(LWS_IPV6 "Compile with support for ipv6" OFF)
|
||||||
option(LWS_UNIX_SOCK "Compile with support for UNIX domain socket" 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_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_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)
|
option(LWS_WITH_HTTP_PROXY "Support for rewriting HTTP proxying (requires libhubbub)" OFF)
|
||||||
|
@ -1443,6 +1443,8 @@ if (NOT LWS_WITHOUT_TESTAPPS)
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
|
|
||||||
|
create_plugin(protocol_lws_meta
|
||||||
|
"plugins/protocol_lws_meta.c" "" "")
|
||||||
create_plugin(protocol_dumb_increment
|
create_plugin(protocol_dumb_increment
|
||||||
"plugins/protocol_dumb_increment.c" "" "")
|
"plugins/protocol_dumb_increment.c" "" "")
|
||||||
create_plugin(protocol_lws_mirror
|
create_plugin(protocol_lws_mirror
|
||||||
|
|
192
README.lws-meta.md
Normal file
192
README.lws-meta.md
Normal 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.
|
|
@ -576,3 +576,26 @@ Prepare the log directory like this
|
||||||
sudo mkdir /var/log/lwsws
|
sudo mkdir /var/log/lwsws
|
||||||
sudo chmod 700 /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.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,14 +8,13 @@ libwebsockets
|
||||||
News
|
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
|
ESP32 is now supported in lws! Download the
|
||||||
|
|
||||||
- factory https://github.com/warmcat/lws-esp32-factory and
|
- factory https://github.com/warmcat/lws-esp32-factory and
|
||||||
- test server app https://github.com/warmcat/lws-esp32-test-server-demos
|
- 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
|
This is the libwebsockets C library for lightweight websocket clients and
|
||||||
servers. For support, visit
|
servers. For support, visit
|
||||||
|
|
|
@ -22,8 +22,8 @@ install:
|
||||||
- mkdir c:\assets\libuv
|
- mkdir c:\assets\libuv
|
||||||
- 7z x -oc:\assets\libuv win-libuv.zip
|
- 7z x -oc:\assets\libuv win-libuv.zip
|
||||||
# - appveyor DownloadFile https://slproweb.com/download/Win32OpenSSL-1_0_2h.exe
|
# - appveyor DownloadFile https://slproweb.com/download/Win32OpenSSL-1_0_2h.exe
|
||||||
- appveyor DownloadFile https://libwebsockets.org:444/Win32OpenSSL-1_0_2h.exe
|
# - appveyor DownloadFile https://libwebsockets.org:444/Win32OpenSSL-1_0_2L.exe
|
||||||
- Win32OpenSSL-1_0_2h.exe /silent /verysilent /sp- /suppressmsgboxes
|
# - Win32OpenSSL-1_0_2L.exe /silent /verysilent /sp- /suppressmsgboxes
|
||||||
- appveyor DownloadFile https://libwebsockets.org:444/nsis-3.0rc1-setup.exe
|
- appveyor DownloadFile https://libwebsockets.org:444/nsis-3.0rc1-setup.exe
|
||||||
- cmd /c start /wait nsis-3.0rc1-setup.exe /S /D=C:\nsis
|
- 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
|
- appveyor DownloadFile https://libwebsockets.org:444/sqlite-dll-win32-x86-3130000.zip
|
||||||
|
@ -51,8 +51,8 @@ artifacts:
|
||||||
name: lws.zip
|
name: lws.zip
|
||||||
type: Zip
|
type: Zip
|
||||||
|
|
||||||
cache:
|
#cache:
|
||||||
- C:\OpenSSL-Win32
|
# - C:\OpenSSL-Win32
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
|
|
|
@ -6,7 +6,7 @@ N=1
|
||||||
OS=`uname`
|
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
|
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
|
C=99
|
||||||
while [ $C -gt 8 ] ; do
|
while [ $C -gt 8 ] ; do
|
||||||
|
|
37
changelog
37
changelog
|
@ -1,6 +1,43 @@
|
||||||
Changelog
|
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
|
v2.2.0
|
||||||
======
|
======
|
||||||
|
|
||||||
|
|
|
@ -111,6 +111,14 @@ lws_client_connect_2(struct lws *wsi)
|
||||||
#ifdef LWS_USE_IPV6
|
#ifdef LWS_USE_IPV6
|
||||||
if (wsi->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));
|
memset(&sa46, 0, sizeof(sa46));
|
||||||
|
|
||||||
sa46.sa6.sin6_family = AF_INET6;
|
sa46.sa6.sin6_family = AF_INET6;
|
||||||
|
@ -213,15 +221,11 @@ lws_client_connect_2(struct lws *wsi)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef LWS_USE_IPV6
|
#ifdef LWS_USE_IPV6
|
||||||
if (wsi->ipv6) {
|
if (wsi->ipv6)
|
||||||
sa46.sa6.sin6_port = htons(port);
|
|
||||||
wsi->desc.sockfd = socket(AF_INET6, SOCK_STREAM, 0);
|
wsi->desc.sockfd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||||
} else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
|
||||||
sa46.sa4.sin_port = htons(port);
|
|
||||||
wsi->desc.sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
wsi->desc.sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
}
|
|
||||||
|
|
||||||
if (!lws_socket_is_valid(wsi->desc.sockfd)) {
|
if (!lws_socket_is_valid(wsi->desc.sockfd)) {
|
||||||
lwsl_warn("Unable to open socket\n");
|
lwsl_warn("Unable to open socket\n");
|
||||||
|
@ -276,11 +280,15 @@ lws_client_connect_2(struct lws *wsi)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LWS_USE_IPV6
|
#ifdef LWS_USE_IPV6
|
||||||
if (wsi->ipv6)
|
if (wsi->ipv6) {
|
||||||
|
sa46.sa6.sin6_port = htons(port);
|
||||||
n = sizeof(struct sockaddr_in6);
|
n = sizeof(struct sockaddr_in6);
|
||||||
else
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
|
sa46.sa4.sin_port = htons(port);
|
||||||
n = sizeof(struct sockaddr);
|
n = sizeof(struct sockaddr);
|
||||||
|
}
|
||||||
|
|
||||||
if (connect(wsi->desc.sockfd, (const struct sockaddr *)&sa46, n) == -1 ||
|
if (connect(wsi->desc.sockfd, (const struct sockaddr *)&sa46, n) == -1 ||
|
||||||
LWS_ERRNO == LWS_EISCONN) {
|
LWS_ERRNO == LWS_EISCONN) {
|
||||||
|
@ -454,15 +462,6 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
|
||||||
}
|
}
|
||||||
wsi->redirects++;
|
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);
|
p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN);
|
||||||
if (p)
|
if (p)
|
||||||
strncpy(origin, p, sizeof(origin) - 1);
|
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)
|
if (p)
|
||||||
strncpy(method, p, sizeof(iface) - 1);
|
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);
|
address, port, path, ssl);
|
||||||
|
|
||||||
/* close the connection by hand */
|
/* close the connection by hand */
|
||||||
|
|
||||||
|
#ifdef LWS_OPENSSL_SUPPORT
|
||||||
|
lws_ssl_close(wsi);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef LWS_USE_LIBUV
|
#ifdef LWS_USE_LIBUV
|
||||||
if (LWS_LIBUV_ENABLED(wsi->context)) {
|
if (LWS_LIBUV_ENABLED(wsi->context)) {
|
||||||
lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi);
|
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);
|
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->desc.sockfd = LWS_SOCK_INVALID;
|
||||||
wsi->state = LWSS_CLIENT_UNCONNECTED;
|
wsi->state = LWSS_CLIENT_UNCONNECTED;
|
||||||
wsi->protocol = NULL;
|
wsi->protocol = NULL;
|
||||||
|
|
|
@ -573,7 +573,7 @@ lws_http_transaction_completed_client(struct lws *wsi)
|
||||||
|
|
||||||
/* we don't support chained client connections yet */
|
/* we don't support chained client connections yet */
|
||||||
return 1;
|
return 1;
|
||||||
|
#if 0
|
||||||
/* otherwise set ourselves up ready to go again */
|
/* otherwise set ourselves up ready to go again */
|
||||||
wsi->state = LWSS_CLIENT_HTTP_ESTABLISHED;
|
wsi->state = LWSS_CLIENT_HTTP_ESTABLISHED;
|
||||||
wsi->mode = LWSCM_HTTP_CLIENT_ACCEPTED;
|
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);
|
lwsl_info("%s: %p: keep-alive await new transaction\n", __func__, wsi);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
LWS_VISIBLE LWS_EXTERN unsigned int
|
LWS_VISIBLE LWS_EXTERN unsigned int
|
||||||
|
@ -630,6 +631,8 @@ lws_client_interpret_server_handshake(struct lws *wsi)
|
||||||
int more = 1;
|
int more = 1;
|
||||||
void *v;
|
void *v;
|
||||||
#endif
|
#endif
|
||||||
|
if (wsi->u.hdr.stash)
|
||||||
|
lws_free_set_NULL(wsi->u.hdr.stash);
|
||||||
|
|
||||||
ah = wsi->u.hdr.ah;
|
ah = wsi->u.hdr.ah;
|
||||||
if (!wsi->do_ws) {
|
if (!wsi->do_ws) {
|
||||||
|
|
|
@ -237,22 +237,36 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
|
||||||
#endif
|
#endif
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
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:
|
case LWS_CALLBACK_HTTP_WRITEABLE:
|
||||||
#ifdef LWS_WITH_CGI
|
#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)
|
if (lws_cgi_write_split_stdout_headers(wsi) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (wsi->reason_bf & 8)
|
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_HEADERS)
|
||||||
wsi->reason_bf &= ~8;
|
wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__CGI_HEADERS;
|
||||||
else
|
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;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(LWS_WITH_HTTP_PROXY)
|
#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;
|
char *px = buf + LWS_PRE;
|
||||||
int lenx = sizeof(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.
|
* is the smaller.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__PROXY;
|
||||||
wsi->reason_bf &= ~2;
|
|
||||||
if (!lws_get_child(wsi))
|
if (!lws_get_child(wsi))
|
||||||
break;
|
break;
|
||||||
if (lws_http_client_read(lws_get_child(wsi), &px, &lenx) < 0)
|
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));
|
assert(lws_get_parent(wsi));
|
||||||
if (!lws_get_parent(wsi))
|
if (!lws_get_parent(wsi))
|
||||||
break;
|
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));
|
lws_callback_on_writable(lws_get_parent(wsi));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -351,7 +364,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
|
||||||
/* TBD stdin rx flow control */
|
/* TBD stdin rx flow control */
|
||||||
break;
|
break;
|
||||||
case LWS_STDOUT:
|
case LWS_STDOUT:
|
||||||
wsi->reason_bf |= 1;
|
wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI;
|
||||||
/* when writing to MASTER would not block */
|
/* when writing to MASTER would not block */
|
||||||
lws_callback_on_writable(wsi);
|
lws_callback_on_writable(wsi);
|
||||||
break;
|
break;
|
||||||
|
@ -369,6 +382,11 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LWS_CALLBACK_CGI_TERMINATED:
|
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;
|
return -1;
|
||||||
|
|
||||||
case LWS_CALLBACK_CGI_STDIN_DATA: /* POST body for stdin */
|
case LWS_CALLBACK_CGI_STDIN_DATA: /* POST body for stdin */
|
||||||
|
@ -470,6 +488,11 @@ lws_create_vhost(struct lws_context *context,
|
||||||
else
|
else
|
||||||
vh->keepalive_timeout = 5;
|
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
|
* give the vhost a unified list of protocols including the
|
||||||
* ones that came from plugins
|
* ones that came from plugins
|
||||||
|
@ -524,7 +547,7 @@ lws_create_vhost(struct lws_context *context,
|
||||||
vh->protocols = lwsp;
|
vh->protocols = lwsp;
|
||||||
else {
|
else {
|
||||||
vh->protocols = info->protocols;
|
vh->protocols = info->protocols;
|
||||||
free(lwsp);
|
lws_free(lwsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
vh->same_vh_protocol_list = (struct lws **)
|
vh->same_vh_protocol_list = (struct lws **)
|
||||||
|
|
|
@ -94,13 +94,16 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
|
||||||
|
|
||||||
case LWS_EXT_CB_OPTION_SET:
|
case LWS_EXT_CB_OPTION_SET:
|
||||||
oa = in;
|
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);
|
oa->option_index, oa->start, oa->len);
|
||||||
if (oa->start)
|
if (oa->start)
|
||||||
priv->args[oa->option_index] = atoi(oa->start);
|
priv->args[oa->option_index] = atoi(oa->start);
|
||||||
else
|
else
|
||||||
priv->args[oa->option_index] = 1;
|
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);
|
lws_extension_pmdeflate_restrict_args(wsi, priv);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -325,16 +328,18 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
|
||||||
|
|
||||||
case LWS_EXT_CB_PAYLOAD_TX:
|
case LWS_EXT_CB_PAYLOAD_TX:
|
||||||
|
|
||||||
if (!priv->tx_init)
|
if (!priv->tx_init) {
|
||||||
if (deflateInit2(&priv->tx, priv->args[PMD_COMP_LEVEL],
|
n = deflateInit2(&priv->tx, priv->args[PMD_COMP_LEVEL],
|
||||||
Z_DEFLATED,
|
Z_DEFLATED,
|
||||||
-priv->args[PMD_CLIENT_MAX_WINDOW_BITS +
|
-priv->args[PMD_SERVER_MAX_WINDOW_BITS +
|
||||||
!wsi->vhost->listen_port],
|
(wsi->vhost->listen_port <= 0)],
|
||||||
priv->args[PMD_MEM_LEVEL],
|
priv->args[PMD_MEM_LEVEL],
|
||||||
Z_DEFAULT_STRATEGY) != Z_OK) {
|
Z_DEFAULT_STRATEGY);
|
||||||
lwsl_ext("inflateInit2 failed\n");
|
if (n != Z_OK) {
|
||||||
|
lwsl_ext("inflateInit2 failed %d\n", n);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
priv->tx_init = 1;
|
priv->tx_init = 1;
|
||||||
if (!priv->buf_tx_deflated)
|
if (!priv->buf_tx_deflated)
|
||||||
priv->buf_tx_deflated = lws_malloc(LWS_PRE + 7 + 5 +
|
priv->buf_tx_deflated = lws_malloc(LWS_PRE + 7 + 5 +
|
||||||
|
@ -436,7 +441,9 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
|
||||||
break;
|
break;
|
||||||
priv->compressed_out = 0;
|
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);
|
(void)deflateEnd(&priv->tx);
|
||||||
priv->tx_init = 0;
|
priv->tx_init = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ lws_ext_parse_options(const struct lws_extension *ext, struct lws *wsi,
|
||||||
oa.option_index = n;
|
oa.option_index = n;
|
||||||
lwsl_ext("hit %d\n", oa.option_index);
|
lwsl_ext("hit %d\n", oa.option_index);
|
||||||
leap = LEAPS_SEEK_VAL;
|
leap = LEAPS_SEEK_VAL;
|
||||||
if (len ==1)
|
if (len == 1)
|
||||||
goto set_arg;
|
goto set_arg;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,7 +238,7 @@ lws_return_http_status(struct lws *wsi, unsigned int code,
|
||||||
&p, end))
|
&p, end))
|
||||||
return 1;
|
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);
|
n = sprintf(slen, "%d", len);
|
||||||
|
|
||||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
|
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
|
||||||
|
|
|
@ -776,7 +776,8 @@ lwsws_get_config_d(void *user, const char *d, const char * const *paths,
|
||||||
|
|
||||||
bail:
|
bail:
|
||||||
uv_fs_req_cleanup(&req);
|
uv_fs_req_cleanup(&req);
|
||||||
uv_loop_close(&loop);
|
while (uv_loop_close(&loop))
|
||||||
|
;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,12 +39,15 @@ lws_event_cb(evutil_socket_t sock_fd, short revents, void *ctx)
|
||||||
if (revents & EV_TIMEOUT)
|
if (revents & EV_TIMEOUT)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* !!! EV_CLOSED doesn't exist in libevent2 */
|
||||||
|
#if LIBEVENT_VERSION_NUMBER < 0x02000000
|
||||||
if (revents & EV_CLOSED)
|
if (revents & EV_CLOSED)
|
||||||
{
|
{
|
||||||
event_del(lws_io->event_watcher);
|
event_del(lws_io->event_watcher);
|
||||||
event_free(lws_io->event_watcher);
|
event_free(lws_io->event_watcher);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
eventfd.fd = sock_fd;
|
eventfd.fd = sock_fd;
|
||||||
eventfd.events = 0;
|
eventfd.events = 0;
|
||||||
|
|
|
@ -65,9 +65,14 @@ static const char * const log_level_names[] = {
|
||||||
void
|
void
|
||||||
lws_free_wsi(struct lws *wsi)
|
lws_free_wsi(struct lws *wsi)
|
||||||
{
|
{
|
||||||
|
struct lws_context_per_thread *pt;
|
||||||
|
int n;
|
||||||
|
|
||||||
if (!wsi)
|
if (!wsi)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
pt = &wsi->context->pt[(int)wsi->tsi];
|
||||||
|
|
||||||
/* Protocol user data may be allocated either internally by lws
|
/* Protocol user data may be allocated either internally by lws
|
||||||
* or by specified the user.
|
* or by specified the user.
|
||||||
* We should only free what we allocated. */
|
* 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... */
|
/* we may not have an ah, but may be on the waiting list... */
|
||||||
lwsl_info("ah det due to close\n");
|
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_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--;
|
wsi->context->count_wsi_allocated--;
|
||||||
lwsl_debug("%s: %p, remaining wsi %d\n", __func__, wsi,
|
lwsl_debug("%s: %p, remaining wsi %d\n", __func__, wsi,
|
||||||
wsi->context->count_wsi_allocated);
|
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];
|
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||||
time_t now;
|
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);
|
lws_pt_lock(pt);
|
||||||
|
|
||||||
time(&now);
|
time(&now);
|
||||||
|
@ -157,6 +188,12 @@ lws_remove_child_from_any_parent(struct lws *wsi)
|
||||||
if (*pwsi == wsi) {
|
if (*pwsi == wsi) {
|
||||||
lwsl_info("%s: detach %p from parent %p\n",
|
lwsl_info("%s: detach %p from parent %p\n",
|
||||||
__func__, wsi, wsi->parent);
|
__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;
|
*pwsi = wsi->sibling_list;
|
||||||
seen = 1;
|
seen = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -219,6 +256,33 @@ lws_bind_protocol(struct lws *wsi, const struct lws_protocols *p)
|
||||||
return 0;
|
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
|
void
|
||||||
lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
|
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;
|
struct lws_tokens eff_buf;
|
||||||
int n, m, ret;
|
int n, m, ret;
|
||||||
|
|
||||||
|
lwsl_debug("%s: %p\n", __func__, wsi);
|
||||||
|
|
||||||
if (!wsi)
|
if (!wsi)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -280,35 +346,38 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
|
||||||
#ifdef LWS_WITH_CGI
|
#ifdef LWS_WITH_CGI
|
||||||
if (wsi->mode == LWSCM_CGI) {
|
if (wsi->mode == LWSCM_CGI) {
|
||||||
/* we are not a network connection, but a handler for CGI io */
|
/* 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 */
|
/* end the binding between us and master */
|
||||||
wsi->parent->cgi->stdwsi[(int)wsi->cgi_channel] = NULL;
|
wsi->parent->cgi->stdwsi[(int)wsi->cgi_channel] = NULL;
|
||||||
|
}
|
||||||
wsi->socket_is_permanently_unusable = 1;
|
wsi->socket_is_permanently_unusable = 1;
|
||||||
|
|
||||||
lwsl_debug("------ %s: detected cgi fdhandler wsi %p\n", __func__, wsi);
|
lwsl_debug("------ %s: detected cgi fdhandler wsi %p\n", __func__, wsi);
|
||||||
goto just_kill_connection;
|
goto just_kill_connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wsi->cgi) {
|
if (wsi->cgi)
|
||||||
struct lws_cgi **pcgi = &pt->cgi_list;
|
lws_cgi_remove_and_kill(wsi);
|
||||||
/* remove us from the cgi list */
|
#endif
|
||||||
lwsl_debug("%s: remove cgi %p from list\n", __func__, wsi->cgi);
|
|
||||||
while (*pcgi) {
|
#if !defined(LWS_NO_CLIENT)
|
||||||
if (*pcgi == wsi->cgi) {
|
if (wsi->mode == LWSCM_HTTP_CLIENT ||
|
||||||
/* drop us from the pt cgi list */
|
wsi->mode == LWSCM_WSCL_WAITING_CONNECT ||
|
||||||
*pcgi = (*pcgi)->cgi_list;
|
wsi->mode == LWSCM_WSCL_WAITING_PROXY_REPLY ||
|
||||||
break;
|
wsi->mode == LWSCM_WSCL_ISSUE_HANDSHAKE ||
|
||||||
}
|
wsi->mode == LWSCM_WSCL_ISSUE_HANDSHAKE2 ||
|
||||||
pcgi = &(*pcgi)->cgi_list;
|
wsi->mode == LWSCM_WSCL_WAITING_SSL ||
|
||||||
}
|
wsi->mode == LWSCM_WSCL_WAITING_SERVER_REPLY ||
|
||||||
if (wsi->cgi->headers_buf) {
|
wsi->mode == LWSCM_WSCL_WAITING_EXTENSION_CONNECT ||
|
||||||
lwsl_debug("close: freed cgi headers\n");
|
wsi->mode == LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY ||
|
||||||
lws_free_set_NULL(wsi->cgi->headers_buf);
|
wsi->mode == LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY ||
|
||||||
}
|
wsi->mode == LWSCM_WSCL_WAITING_SOCKS_AUTH_REPLY)
|
||||||
/* we have a cgi going, we must kill it */
|
if (wsi->u.hdr.stash)
|
||||||
wsi->cgi->being_closed = 1;
|
lws_free_set_NULL(wsi->u.hdr.stash);
|
||||||
lws_cgi_kill(wsi);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (wsi->mode == LWSCM_RAW) {
|
if (wsi->mode == LWSCM_RAW) {
|
||||||
|
@ -568,6 +637,8 @@ just_kill_connection:
|
||||||
/* checking return redundant since we anyway close */
|
/* checking return redundant since we anyway close */
|
||||||
if (wsi->desc.sockfd != LWS_SOCK_INVALID)
|
if (wsi->desc.sockfd != LWS_SOCK_INVALID)
|
||||||
remove_wsi_socket_from_fds(wsi);
|
remove_wsi_socket_from_fds(wsi);
|
||||||
|
else
|
||||||
|
lws_same_vh_protocol_remove(wsi);
|
||||||
|
|
||||||
#if defined(LWS_WITH_ESP8266)
|
#if defined(LWS_WITH_ESP8266)
|
||||||
espconn_disconnect(wsi->desc.sockfd);
|
espconn_disconnect(wsi->desc.sockfd);
|
||||||
|
@ -670,17 +741,18 @@ async_close:
|
||||||
wsi->socket_is_permanently_unusable = 1;
|
wsi->socket_is_permanently_unusable = 1;
|
||||||
|
|
||||||
#ifdef LWS_USE_LIBUV
|
#ifdef LWS_USE_LIBUV
|
||||||
if (LWS_LIBUV_ENABLED(context)) {
|
if (!wsi->parent_carries_io)
|
||||||
if (wsi->listener) {
|
if (LWS_LIBUV_ENABLED(context)) {
|
||||||
lwsl_debug("%s: stopping listner libuv poll\n", __func__);
|
if (wsi->listener) {
|
||||||
uv_poll_stop(&wsi->w_read.uv_watcher);
|
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 */
|
lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi);
|
||||||
lws_libuv_closehandle(wsi);
|
/* libuv has to do his own close handle processing asynchronously */
|
||||||
|
lws_libuv_closehandle(wsi);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
lws_close_free_wsi_final(wsi);
|
lws_close_free_wsi_final(wsi);
|
||||||
|
@ -711,12 +783,13 @@ lws_close_free_wsi_final(struct lws *wsi)
|
||||||
|
|
||||||
#ifdef LWS_WITH_CGI
|
#ifdef LWS_WITH_CGI
|
||||||
if (wsi->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");
|
lwsl_err("ZERO FD IN CGI CLOSE");
|
||||||
|
|
||||||
if (wsi->cgi->pipe_fds[n / 2][n & 1] >= 0)
|
if (wsi->cgi->pipe_fds[n][!!(n == 0)] >= 0)
|
||||||
close(wsi->cgi->pipe_fds[n / 2][n & 1]);
|
close(wsi->cgi->pipe_fds[n][!!(n == 0)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
lws_free(wsi->cgi);
|
lws_free(wsi->cgi);
|
||||||
|
@ -767,8 +840,7 @@ lws_get_addresses(struct lws_vhost *vh, void *ads, char *name,
|
||||||
struct addrinfo ai, *res;
|
struct addrinfo ai, *res;
|
||||||
struct sockaddr_in addr4;
|
struct sockaddr_in addr4;
|
||||||
|
|
||||||
if (rip)
|
rip[0] = '\0';
|
||||||
rip[0] = '\0';
|
|
||||||
name[0] = '\0';
|
name[0] = '\0';
|
||||||
addr4.sin_family = AF_UNSPEC;
|
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))
|
name, name_len, NULL, 0, 0))
|
||||||
return -1;
|
return -1;
|
||||||
#endif
|
#endif
|
||||||
if (!rip)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (getaddrinfo(name, NULL, &ai, &result))
|
if (getaddrinfo(name, NULL, &ai, &result))
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -856,6 +926,9 @@ lws_get_peer_simple(struct lws *wsi, char *name, int namelen)
|
||||||
int af = AF_INET;
|
int af = AF_INET;
|
||||||
void *p, *q;
|
void *p, *q;
|
||||||
|
|
||||||
|
if (wsi->parent_carries_io)
|
||||||
|
wsi = wsi->parent;
|
||||||
|
|
||||||
#ifdef LWS_USE_IPV6
|
#ifdef LWS_USE_IPV6
|
||||||
if (LWS_IPV6_ENABLED(wsi->vhost)) {
|
if (LWS_IPV6_ENABLED(wsi->vhost)) {
|
||||||
len = sizeof(sin6);
|
len = sizeof(sin6);
|
||||||
|
@ -998,8 +1071,9 @@ lws_callback_all_protocol(struct lws_context *context,
|
||||||
}
|
}
|
||||||
|
|
||||||
LWS_VISIBLE int
|
LWS_VISIBLE int
|
||||||
lws_callback_all_protocol_vhost(struct lws_vhost *vh,
|
lws_callback_all_protocol_vhost_args(struct lws_vhost *vh,
|
||||||
const struct lws_protocols *protocol, int reason)
|
const struct lws_protocols *protocol, int reason,
|
||||||
|
void *argp, size_t len)
|
||||||
{
|
{
|
||||||
struct lws_context *context = vh->context;
|
struct lws_context *context = vh->context;
|
||||||
struct lws_context_per_thread *pt = &context->pt[0];
|
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);
|
wsi = wsi_from_fd(context, pt->fds[n].fd);
|
||||||
if (!wsi)
|
if (!wsi)
|
||||||
continue;
|
continue;
|
||||||
if (wsi->vhost == vh && wsi->protocol == protocol)
|
if (wsi->vhost == vh && (wsi->protocol == protocol ||
|
||||||
protocol->callback(wsi, reason, wsi->user_space,
|
!protocol))
|
||||||
NULL, 0);
|
wsi->protocol->callback(wsi, reason,
|
||||||
|
wsi->user_space, argp, len);
|
||||||
}
|
}
|
||||||
pt++;
|
pt++;
|
||||||
}
|
}
|
||||||
|
@ -1021,6 +1096,13 @@ lws_callback_all_protocol_vhost(struct lws_vhost *vh,
|
||||||
return 0;
|
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_VISIBLE LWS_EXTERN int
|
||||||
lws_callback_vhost_protocols(struct lws *wsi, int reason, void *in, int len)
|
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;
|
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_VISIBLE unsigned char
|
||||||
lws_get_reserved_bits(struct lws *wsi)
|
lws_get_reserved_bits(struct lws *wsi)
|
||||||
{
|
{
|
||||||
|
@ -1650,6 +1738,48 @@ lws_get_child(const struct lws *wsi)
|
||||||
return wsi->child_list;
|
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_VISIBLE LWS_EXTERN void
|
||||||
lws_close_reason(struct lws *wsi, enum lws_close_status status,
|
lws_close_reason(struct lws *wsi, enum lws_close_status status,
|
||||||
unsigned char *buf, size_t len)
|
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++;
|
p++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
env_array[n++] = "PATH=/bin:/usr/bin:/usr/local/bin:/var/www/cgi-bin";
|
||||||
|
|
||||||
env_array[n++] = p;
|
env_array[n++] = p;
|
||||||
p += lws_snprintf(p, end - p, "SCRIPT_PATH=%s", exec_array[0]) + 1;
|
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++] = "SERVER_SOFTWARE=libwebsockets";
|
||||||
env_array[n++] = "PATH=/bin:/usr/bin:/usr/local/bin:/var/www/cgi-bin";
|
|
||||||
env_array[n] = NULL;
|
env_array[n] = NULL;
|
||||||
|
|
||||||
#if 0
|
#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 */
|
/* we are the parent process */
|
||||||
wsi->context->count_cgi_spawned++;
|
wsi->context->count_cgi_spawned++;
|
||||||
lwsl_debug("%s: cgi %p spawned PID %d\n", __func__, cgi, cgi->pid);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2647,11 +2782,11 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
while (wsi->hdr_state != LHCS_PAYLOAD) {
|
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
|
* payload chunks, since they need to be
|
||||||
* handled separately
|
* handled separately
|
||||||
*/
|
*/
|
||||||
|
|
||||||
switch (wsi->hdr_state) {
|
switch (wsi->hdr_state) {
|
||||||
|
|
||||||
case LHCS_RESPONSE:
|
case LHCS_RESPONSE:
|
||||||
|
@ -2659,6 +2794,12 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi)
|
||||||
wsi->cgi->response_code);
|
wsi->cgi->response_code);
|
||||||
if (lws_add_http_header_status(wsi, wsi->cgi->response_code, &p, end))
|
if (lws_add_http_header_status(wsi, wsi->cgi->response_code, &p, end))
|
||||||
return 1;
|
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,
|
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_CONNECTION,
|
||||||
(unsigned char *)"close", 5, &p, end))
|
(unsigned char *)"close", 5, &p, end))
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -2675,7 +2816,7 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi)
|
||||||
}
|
}
|
||||||
|
|
||||||
wsi->hdr_state = LHCS_DUMP_HEADERS;
|
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);
|
lws_callback_on_writable(wsi);
|
||||||
/* back to the loop for writeability again */
|
/* back to the loop for writeability again */
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2700,7 +2841,7 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi)
|
||||||
lws_free_set_NULL(wsi->cgi->headers_buf);
|
lws_free_set_NULL(wsi->cgi->headers_buf);
|
||||||
lwsl_debug("freed cgi headers\n");
|
lwsl_debug("freed cgi headers\n");
|
||||||
} else {
|
} else {
|
||||||
wsi->reason_bf |= 8;
|
wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI_HEADERS;
|
||||||
lws_callback_on_writable(wsi);
|
lws_callback_on_writable(wsi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2856,14 +2997,24 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi)
|
||||||
|
|
||||||
/* payload processing */
|
/* payload processing */
|
||||||
|
|
||||||
|
m = !wsi->cgi->explicitly_chunked && !wsi->cgi->content_length;
|
||||||
|
|
||||||
n = read(lws_get_socket_fd(wsi->cgi->stdwsi[LWS_STDOUT]),
|
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) {
|
if (n < 0 && errno != EAGAIN) {
|
||||||
lwsl_debug("%s: stdout read says %d\n", __func__, n);
|
lwsl_debug("%s: stdout read says %d\n", __func__, n);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (n > 0) {
|
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);
|
m = lws_write(wsi, (unsigned char *)start, n, LWS_WRITE_HTTP);
|
||||||
//lwsl_notice("write %d\n", m);
|
//lwsl_notice("write %d\n", m);
|
||||||
if (m < 0) {
|
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",
|
lwsl_debug("%s: found PID %d on cgi list\n",
|
||||||
__func__, n);
|
__func__, n);
|
||||||
|
|
||||||
if (!cgi->content_length && cgi->explicitly_chunked) {
|
if (!cgi->content_length) {
|
||||||
/*
|
/*
|
||||||
* well, if he sends chunked... give him 5s after the
|
* well, if he sends chunked... give him 5s after the
|
||||||
* cgi terminated to send buffered
|
* cgi terminated to send buffered
|
||||||
|
@ -3097,7 +3248,8 @@ lws_set_extension_option(struct lws *wsi, const char *ext_name,
|
||||||
int
|
int
|
||||||
lws_access_log(struct lws *wsi)
|
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;
|
int l;
|
||||||
|
|
||||||
if (!wsi->access_log_pending)
|
if (!wsi->access_log_pending)
|
||||||
|
@ -3109,9 +3261,12 @@ lws_access_log(struct lws *wsi)
|
||||||
if (!p)
|
if (!p)
|
||||||
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.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 (wsi->vhost->log_fd != (int)LWS_INVALID_FILE) {
|
||||||
if (write(wsi->vhost->log_fd, ass, l) != l)
|
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);
|
lws_free(wsi->access_log.user_agent);
|
||||||
wsi->access_log.user_agent = NULL;
|
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;
|
wsi->access_log_pending = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -33,12 +33,11 @@ extern "C" {
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(LWS_HAS_INTPTR_T)
|
#include "lws_config.h"
|
||||||
#include <stdint.h>
|
|
||||||
#define lws_intptr_t intptr_t
|
/*
|
||||||
#else
|
* CARE: everything using cmake defines needs to be below here
|
||||||
typedef unsigned long long lws_intptr_t;
|
*/
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(LWS_WITH_ESP8266)
|
#if defined(LWS_WITH_ESP8266)
|
||||||
struct sockaddr_in;
|
struct sockaddr_in;
|
||||||
|
@ -47,7 +46,12 @@ struct sockaddr_in;
|
||||||
#define LWS_POSIX 1
|
#define LWS_POSIX 1
|
||||||
#endif
|
#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)
|
#if defined(WIN32) || defined(_WIN32)
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
@ -632,6 +636,7 @@ struct lws_esp32_image {
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct lws_esp32 lws_esp32;
|
extern struct lws_esp32 lws_esp32;
|
||||||
|
struct lws_vhost;
|
||||||
|
|
||||||
extern esp_err_t
|
extern esp_err_t
|
||||||
lws_esp32_event_passthru(void *ctx, system_event_t *event);
|
lws_esp32_event_passthru(void *ctx, system_event_t *event);
|
||||||
|
@ -645,7 +650,7 @@ struct lws_context_creation_info;
|
||||||
extern void
|
extern void
|
||||||
lws_esp32_set_creation_defaults(struct lws_context_creation_info *info);
|
lws_esp32_set_creation_defaults(struct lws_context_creation_info *info);
|
||||||
extern struct lws_context *
|
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
|
extern int
|
||||||
lws_esp32_wlan_nvs_get(int retry);
|
lws_esp32_wlan_nvs_get(int retry);
|
||||||
extern esp_err_t
|
extern esp_err_t
|
||||||
|
@ -823,6 +828,38 @@ struct lws_context;
|
||||||
/* needed even with extensions disabled for create context */
|
/* needed even with extensions disabled for create context */
|
||||||
struct lws_extension;
|
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
|
/*! \defgroup usercb User Callback
|
||||||
*
|
*
|
||||||
* ##User protocol callback
|
* ##User protocol callback
|
||||||
|
@ -1252,6 +1289,16 @@ enum lws_callback_reasons {
|
||||||
* using the vhost. @in is a pointer to a
|
* using the vhost. @in is a pointer to a
|
||||||
* struct lws_ssl_info containing information about the
|
* struct lws_ssl_info containing information about the
|
||||||
* event*/
|
* 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 ---^ ******/
|
/****** add new things just above ---^ ******/
|
||||||
|
|
||||||
|
@ -1279,6 +1326,11 @@ enum lws_callback_reasons {
|
||||||
typedef int
|
typedef int
|
||||||
lws_callback_function(struct lws *wsi, enum lws_callback_reasons reason,
|
lws_callback_function(struct lws *wsi, enum lws_callback_reasons reason,
|
||||||
void *user, void *in, size_t len);
|
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
|
/*! \defgroup extensions
|
||||||
|
@ -2069,6 +2121,9 @@ struct lws_context_creation_info {
|
||||||
* the form SSL_CB_ALERT, defined in openssl/ssl.h. The default of
|
* the form SSL_CB_ALERT, defined in openssl/ssl.h. The default of
|
||||||
* 0 means no info events will be reported.
|
* 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 */
|
void *_unused[8]; /**< dummy */
|
||||||
};
|
};
|
||||||
|
@ -2783,6 +2838,9 @@ lws_service_adjust_timeout(struct lws_context *context, int timeout_ms, int tsi)
|
||||||
/* Backwards compatibility */
|
/* Backwards compatibility */
|
||||||
#define lws_plat_service_tsi lws_service_tsi
|
#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
|
/*! \defgroup http HTTP
|
||||||
|
@ -3621,10 +3679,24 @@ enum pending_timeout {
|
||||||
PENDING_TIMEOUT_KILLED_BY_SSL_INFO = 22,
|
PENDING_TIMEOUT_KILLED_BY_SSL_INFO = 22,
|
||||||
PENDING_TIMEOUT_KILLED_BY_PARENT = 23,
|
PENDING_TIMEOUT_KILLED_BY_PARENT = 23,
|
||||||
PENDING_TIMEOUT_CLOSE_SEND = 24,
|
PENDING_TIMEOUT_CLOSE_SEND = 24,
|
||||||
|
PENDING_TIMEOUT_HOLDING_AH = 25,
|
||||||
|
|
||||||
/****** add new things just above ---^ ******/
|
/****** 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
|
* lws_set_timeout() - marks the wsi as subject to a timeout
|
||||||
*
|
*
|
||||||
|
@ -3632,7 +3704,10 @@ enum pending_timeout {
|
||||||
*
|
*
|
||||||
* \param wsi: Websocket connection instance
|
* \param wsi: Websocket connection instance
|
||||||
* \param reason: timeout reason
|
* \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_VISIBLE LWS_EXTERN void
|
||||||
lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs);
|
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
|
#endif
|
||||||
#define _LWS_PAD(n) (((n) % _LWS_PAD_SIZE) ? \
|
#define _LWS_PAD(n) (((n) % _LWS_PAD_SIZE) ? \
|
||||||
((n) + (_LWS_PAD_SIZE - ((n) % _LWS_PAD_SIZE))) : (n))
|
((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 */
|
/* used prior to 1.7 and retained for backward compatibility */
|
||||||
#define LWS_SEND_BUFFER_PRE_PADDING LWS_PRE
|
#define LWS_SEND_BUFFER_PRE_PADDING LWS_PRE
|
||||||
#define LWS_SEND_BUFFER_POST_PADDING 0
|
#define LWS_SEND_BUFFER_POST_PADDING 0
|
||||||
|
@ -3709,6 +3785,15 @@ enum lws_write_protocol {
|
||||||
* decode the content if used */
|
* 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
|
* 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
|
* 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
|
* becomes possible to write to each socket without
|
||||||
* blocking in turn.
|
* 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
|
* lws_callback_on_writable_all_protocol_vhost() - Request a callback for
|
||||||
* all connections using the given protocol when it
|
* all connections on same vhost using the given protocol
|
||||||
* becomes possible to write to each socket without
|
* when it becomes possible to write to each socket without
|
||||||
* blocking in turn.
|
* blocking in turn.
|
||||||
*
|
*
|
||||||
* \param vhost: Only consider connections on this lws_vhost
|
* \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
|
* 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 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
|
* \param reason: Callback reason index
|
||||||
*
|
*
|
||||||
* - Which: connections using this protocol on GIVEN VHOST ONLY
|
* - 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_VISIBLE LWS_EXTERN int
|
||||||
lws_callback_all_protocol_vhost(struct lws_vhost *vh,
|
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
|
* 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_RAW_FILE_DESC = 0, /* convenience constant */
|
||||||
LWS_ADOPT_HTTP = 1, /* flag: absent implies RAW */
|
LWS_ADOPT_HTTP = 1, /* flag: absent implies RAW */
|
||||||
LWS_ADOPT_SOCKET = 2, /* flag: absent implies file descr */
|
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;
|
} lws_adoption_type;
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
|
@ -4411,6 +4521,32 @@ lws_get_parent(const struct lws *wsi);
|
||||||
LWS_VISIBLE LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT
|
LWS_VISIBLE LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT
|
||||||
lws_get_child(const struct lws *wsi);
|
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.
|
* \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
|
* lws_is_final_fragment() - tests if last part of ws message
|
||||||
|
*
|
||||||
* \param wsi: lws connection
|
* \param wsi: lws connection
|
||||||
*/
|
*/
|
||||||
LWS_VISIBLE LWS_EXTERN int
|
LWS_VISIBLE LWS_EXTERN int
|
||||||
lws_is_final_fragment(struct lws *wsi);
|
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
|
* lws_get_reserved_bits() - access reserved bits of ws frame
|
||||||
* \param wsi: lws connection
|
* \param wsi: lws connection
|
||||||
|
|
|
@ -1613,7 +1613,12 @@ lws_esp32_get_image_info(const esp_partition_t *part, struct lws_esp32_image *i,
|
||||||
}
|
}
|
||||||
hdr += (~hdr & 15) + 1;
|
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));
|
spi_flash_read(hdr, &i->romfs_len, sizeof(i->romfs_len));
|
||||||
i->json = i->romfs + i->romfs_len + 4;
|
i->json = i->romfs + i->romfs_len + 4;
|
||||||
spi_flash_read(i->json - 4, &i->json_len, sizeof(i->json_len));
|
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 *
|
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();
|
const esp_partition_t *part = lws_esp_ota_get_boot_partition();
|
||||||
struct lws_context *context;
|
struct lws_context *context;
|
||||||
|
@ -1683,6 +1688,9 @@ lws_esp32_init(struct lws_context_creation_info *info)
|
||||||
else
|
else
|
||||||
lws_init_vhost_client_ssl(info, vhost);
|
lws_init_vhost_client_ssl(info, vhost);
|
||||||
|
|
||||||
|
if (pvh)
|
||||||
|
*pvh = vhost;
|
||||||
|
|
||||||
lws_protocol_init(context);
|
lws_protocol_init(context);
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
|
|
|
@ -256,7 +256,7 @@ lws_plat_set_socket_options(struct lws_vhost *vhost, int fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(SO_BINDTODEVICE)
|
#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);
|
lwsl_info("binding listen skt to %s using SO_BINDTODEVICE\n", vhost->iface);
|
||||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, vhost->iface,
|
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, vhost->iface,
|
||||||
strlen(vhost->iface)) < 0) {
|
strlen(vhost->iface)) < 0) {
|
||||||
|
|
|
@ -218,6 +218,9 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
|
||||||
/* if something closed, retry this slot */
|
/* if something closed, retry this slot */
|
||||||
if (n)
|
if (n)
|
||||||
i--;
|
i--;
|
||||||
|
|
||||||
|
if (wsi->trunc_len)
|
||||||
|
WSASetEvent(pt->events[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
33
lib/output.c
33
lib/output.c
|
@ -250,6 +250,23 @@ LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len,
|
||||||
int pre = 0, n;
|
int pre = 0, n;
|
||||||
size_t orig_len = len;
|
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);
|
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_API_LWS_WRITE, 1);
|
||||||
|
|
||||||
if ((int)len < 0) {
|
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) {
|
if (wsi->state == LWSS_ESTABLISHED && wsi->u.ws.tx_draining_ext) {
|
||||||
/* remove us from the list */
|
/* remove us from the list */
|
||||||
struct lws **w = &pt->tx_draining_ext_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;
|
wsi->u.ws.tx_draining_ext = 0;
|
||||||
/* remove us from context draining ext list */
|
/* remove us from context draining ext list */
|
||||||
while (*w) {
|
while (*w) {
|
||||||
|
@ -332,11 +350,13 @@ LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len,
|
||||||
case LWS_WRITE_CLOSE:
|
case LWS_WRITE_CLOSE:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
lwsl_debug("LWS_EXT_CB_PAYLOAD_TX\n");
|
||||||
n = lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_TX, &eff_buf, wp);
|
n = lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_TX, &eff_buf, wp);
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (n && eff_buf.token_len) {
|
if (n && eff_buf.token_len) {
|
||||||
|
lwsl_debug("drain len %d\n", (int)eff_buf.token_len);
|
||||||
/* extension requires further draining */
|
/* extension requires further draining */
|
||||||
wsi->u.ws.tx_draining_ext = 1;
|
wsi->u.ws.tx_draining_ext = 1;
|
||||||
wsi->u.ws.tx_draining_ext_list = pt->tx_draining_ext_list;
|
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) {
|
if ((char *)buf != eff_buf.token) {
|
||||||
/*
|
/*
|
||||||
* ext might eat it, but no have anything to issue yet
|
* ext might eat it, but not have anything to issue yet.
|
||||||
* in that case we have to follow his lead, but stash and
|
* In that case we have to follow his lead, but stash and
|
||||||
* replace the write type that was lost here the first time.
|
* replace the write type that was lost here the first time.
|
||||||
*/
|
*/
|
||||||
if (len && !eff_buf.token_len) {
|
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;
|
buf = (unsigned char *)eff_buf.token;
|
||||||
len = eff_buf.token_len;
|
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) {
|
switch (wsi->ietf_spec_revision) {
|
||||||
case 13:
|
case 13:
|
||||||
if (masked7) {
|
if (masked7) {
|
||||||
|
|
|
@ -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 */
|
/* since we will restart the ah, our new headers are not completed */
|
||||||
wsi->hdr_parsing_completed = 0;
|
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
|
* if we inherited pending rx (from socket adoption deferred
|
||||||
* processing), apply and free it.
|
* 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;
|
int n;
|
||||||
|
|
||||||
|
if (!wsi->u.hdr.ah)
|
||||||
|
return 0;
|
||||||
|
|
||||||
n = wsi->u.hdr.ah->frag_index[h];
|
n = wsi->u.hdr.ah->frag_index[h];
|
||||||
if (!n)
|
if (!n)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -402,6 +409,9 @@ LWS_VISIBLE int lws_hdr_total_length(struct lws *wsi, enum lws_token_indexes h)
|
||||||
int n;
|
int n;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
|
||||||
|
if (!wsi->u.hdr.ah)
|
||||||
|
return 0;
|
||||||
|
|
||||||
n = wsi->u.hdr.ah->frag_index[h];
|
n = wsi->u.hdr.ah->frag_index[h];
|
||||||
if (!n)
|
if (!n)
|
||||||
return 0;
|
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)
|
enum lws_token_indexes h, int frag_idx)
|
||||||
{
|
{
|
||||||
int n = 0;
|
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)
|
if (!f)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -448,6 +463,9 @@ LWS_VISIBLE int lws_hdr_copy(struct lws *wsi, char *dst, int len,
|
||||||
if (toklen >= len)
|
if (toklen >= len)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (!wsi->u.hdr.ah)
|
||||||
|
return -1;
|
||||||
|
|
||||||
n = wsi->u.hdr.ah->frag_index[h];
|
n = wsi->u.hdr.ah->frag_index[h];
|
||||||
if (!n)
|
if (!n)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1145,6 +1163,7 @@ handle_first:
|
||||||
wsi->u.ws.rsv_first_msg = (c & 0x70);
|
wsi->u.ws.rsv_first_msg = (c & 0x70);
|
||||||
wsi->u.ws.frame_is_binary =
|
wsi->u.ws.frame_is_binary =
|
||||||
wsi->u.ws.opcode == LWSWSOPC_BINARY_FRAME;
|
wsi->u.ws.opcode == LWSWSOPC_BINARY_FRAME;
|
||||||
|
wsi->u.ws.first_fragment = 1;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
case 4:
|
case 4:
|
||||||
|
@ -1492,6 +1511,7 @@ drain_extension:
|
||||||
/* eff_buf may be pointing somewhere completely different now,
|
/* eff_buf may be pointing somewhere completely different now,
|
||||||
* it's the output
|
* it's the output
|
||||||
*/
|
*/
|
||||||
|
wsi->u.ws.first_fragment = 0;
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
/*
|
/*
|
||||||
* we may rely on this to get RX, just drop connection
|
* we may rely on this to get RX, just drop connection
|
||||||
|
|
19
lib/pollfd.c
19
lib/pollfd.c
|
@ -236,6 +236,11 @@ remove_wsi_socket_from_fds(struct lws *wsi)
|
||||||
#endif
|
#endif
|
||||||
int m, ret = 0;
|
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 !defined(_WIN32) && !defined(LWS_WITH_ESP8266)
|
||||||
if (wsi->desc.sockfd > context->max_fds) {
|
if (wsi->desc.sockfd > context->max_fds) {
|
||||||
lwsl_err("fd %d too high (%d)\n", 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)
|
if (wsi->socket_is_permanently_unusable)
|
||||||
return 0;
|
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];
|
pt = &wsi->context->pt[(int)wsi->tsi];
|
||||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB_REQ, 1);
|
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB_REQ, 1);
|
||||||
#if defined(LWS_WITH_STATS)
|
#if defined(LWS_WITH_STATS)
|
||||||
|
@ -434,8 +449,8 @@ lws_same_vh_protocol_insert(struct lws *wsi, int n)
|
||||||
// wsi->same_vh_protocol_prev);
|
// wsi->same_vh_protocol_prev);
|
||||||
|
|
||||||
if (wsi->same_vh_protocol_prev || wsi->same_vh_protocol_next) {
|
if (wsi->same_vh_protocol_prev || wsi->same_vh_protocol_next) {
|
||||||
lwsl_err("Attempted to attach wsi twice to same vh prot\n");
|
lws_same_vh_protocol_remove(wsi);
|
||||||
assert(0);
|
lwsl_notice("Attempted to attach wsi twice to same vh prot\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
wsi->same_vh_protocol_prev = /* guy who points to us */
|
wsi->same_vh_protocol_prev = /* guy who points to us */
|
||||||
|
|
|
@ -891,6 +891,7 @@ struct lws_vhost {
|
||||||
int ka_probes;
|
int ka_probes;
|
||||||
int ka_interval;
|
int ka_interval;
|
||||||
int keepalive_timeout;
|
int keepalive_timeout;
|
||||||
|
int timeout_secs_ah_idle;
|
||||||
int ssl_info_event_mask;
|
int ssl_info_event_mask;
|
||||||
#ifdef LWS_WITH_ACCESS_LOG
|
#ifdef LWS_WITH_ACCESS_LOG
|
||||||
int log_fd;
|
int log_fd;
|
||||||
|
@ -1484,10 +1485,13 @@ struct _lws_websocket_related {
|
||||||
unsigned int rx_draining_ext:1;
|
unsigned int rx_draining_ext:1;
|
||||||
unsigned int tx_draining_ext:1;
|
unsigned int tx_draining_ext:1;
|
||||||
unsigned int send_check_ping:1;
|
unsigned int send_check_ping:1;
|
||||||
|
unsigned int first_fragment:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef LWS_WITH_CGI
|
#ifdef LWS_WITH_CGI
|
||||||
|
|
||||||
|
#define LWS_HTTP_CHUNK_HDR_SIZE 16
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
SIGNIFICANT_HDR_CONTENT_LENGTH,
|
SIGNIFICANT_HDR_CONTENT_LENGTH,
|
||||||
SIGNIFICANT_HDR_LOCATION,
|
SIGNIFICANT_HDR_LOCATION,
|
||||||
|
@ -1541,6 +1545,7 @@ struct lws_rewrite;
|
||||||
struct lws_access_log {
|
struct lws_access_log {
|
||||||
char *header_log;
|
char *header_log;
|
||||||
char *user_agent;
|
char *user_agent;
|
||||||
|
char *referrer;
|
||||||
unsigned long sent;
|
unsigned long sent;
|
||||||
int response;
|
int response;
|
||||||
};
|
};
|
||||||
|
@ -1588,6 +1593,7 @@ struct lws {
|
||||||
struct lws_access_log access_log;
|
struct lws_access_log access_log;
|
||||||
#endif
|
#endif
|
||||||
void *user_space;
|
void *user_space;
|
||||||
|
void *opaque_parent_data;
|
||||||
/* rxflow handling */
|
/* rxflow handling */
|
||||||
unsigned char *rxflow_buffer;
|
unsigned char *rxflow_buffer;
|
||||||
/* truncated send handling */
|
/* truncated send handling */
|
||||||
|
@ -1651,6 +1657,8 @@ struct lws {
|
||||||
unsigned int told_user_closed:1;
|
unsigned int told_user_closed:1;
|
||||||
unsigned int waiting_to_send_close_frame:1;
|
unsigned int waiting_to_send_close_frame:1;
|
||||||
unsigned int ipv6:1;
|
unsigned int ipv6:1;
|
||||||
|
unsigned int parent_carries_io:1;
|
||||||
|
unsigned int parent_pending_cb_on_writable:1;
|
||||||
|
|
||||||
#if defined(LWS_WITH_ESP8266)
|
#if defined(LWS_WITH_ESP8266)
|
||||||
unsigned int pending_send_completion:3;
|
unsigned int pending_send_completion:3;
|
||||||
|
|
174
lib/server.c
174
lib/server.c
|
@ -689,6 +689,17 @@ lws_unauthorised_basic_auth(struct lws *wsi)
|
||||||
|
|
||||||
int lws_clean_url(char *p)
|
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) {
|
while (*p) {
|
||||||
if (p[0] == '/' && p[1] == '/') {
|
if (p[0] == '/' && p[1] == '/') {
|
||||||
char *p1 = p;
|
char *p1 = p;
|
||||||
|
@ -777,7 +788,7 @@ lws_http_action(struct lws *wsi)
|
||||||
|
|
||||||
/* we insist on absolute paths */
|
/* we insist on absolute paths */
|
||||||
|
|
||||||
if (uri_ptr[0] != '/') {
|
if (!uri_ptr || uri_ptr[0] != '/') {
|
||||||
lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
|
lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
|
||||||
|
|
||||||
goto bail_nuke_ah;
|
goto bail_nuke_ah;
|
||||||
|
@ -895,7 +906,7 @@ lws_http_action(struct lws *wsi)
|
||||||
const char *pa, *me;
|
const char *pa, *me;
|
||||||
struct tm *tmp;
|
struct tm *tmp;
|
||||||
time_t t = time(NULL);
|
time_t t = time(NULL);
|
||||||
int l = 256;
|
int l = 256, m;
|
||||||
|
|
||||||
if (wsi->access_log_pending)
|
if (wsi->access_log_pending)
|
||||||
lws_access_log(wsi);
|
lws_access_log(wsi);
|
||||||
|
@ -913,10 +924,7 @@ lws_http_action(struct lws *wsi)
|
||||||
if (!pa)
|
if (!pa)
|
||||||
pa = "(unknown)";
|
pa = "(unknown)";
|
||||||
|
|
||||||
if (meth >= 0)
|
me = method_names[meth];
|
||||||
me = method_names[meth];
|
|
||||||
else
|
|
||||||
me = "unknown";
|
|
||||||
|
|
||||||
lws_snprintf(wsi->access_log.header_log, l,
|
lws_snprintf(wsi->access_log.header_log, l,
|
||||||
"%s - - [%s] \"%s %s %s\"",
|
"%s - - [%s] \"%s %s %s\"",
|
||||||
|
@ -931,6 +939,23 @@ lws_http_action(struct lws *wsi)
|
||||||
l + 1, WSI_TOKEN_HTTP_USER_AGENT);
|
l + 1, WSI_TOKEN_HTTP_USER_AGENT);
|
||||||
else
|
else
|
||||||
lwsl_err("OOM getting user agent\n");
|
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;
|
wsi->access_log_pending = 1;
|
||||||
}
|
}
|
||||||
|
@ -997,10 +1022,13 @@ lws_http_action(struct lws *wsi)
|
||||||
hit->origin);
|
hit->origin);
|
||||||
else
|
else
|
||||||
n = lws_snprintf((char *)end, 256,
|
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),
|
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST),
|
||||||
uri_ptr);
|
uri_ptr);
|
||||||
|
|
||||||
|
lwsl_notice("%s\n", end);
|
||||||
lws_clean_url((char *)end);
|
lws_clean_url((char *)end);
|
||||||
|
lwsl_notice("%s\n", end);
|
||||||
|
|
||||||
n = lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,
|
n = lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,
|
||||||
end, n, &p, end);
|
end, n, &p, end);
|
||||||
|
@ -1284,6 +1312,57 @@ transaction_result_n:
|
||||||
#endif
|
#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
|
int
|
||||||
lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
|
lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
|
||||||
{
|
{
|
||||||
|
@ -1652,49 +1731,10 @@ upgrade_ws:
|
||||||
wsi->u.hdr = hdr;
|
wsi->u.hdr = hdr;
|
||||||
lws_pt_unlock(pt);
|
lws_pt_unlock(pt);
|
||||||
|
|
||||||
lws_restart_ws_ping_pong_timer(wsi);
|
lws_server_init_wsi_for_ws(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
|
|
||||||
|
|
||||||
lwsl_parser("accepted v%02d connection\n",
|
lwsl_parser("accepted v%02d connection\n",
|
||||||
wsi->ietf_spec_revision);
|
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 */
|
/* !!! drop ah unreservedly after ESTABLISHED */
|
||||||
if (!wsi->more_rx_waiting) {
|
if (!wsi->more_rx_waiting) {
|
||||||
lws_header_table_force_to_detachable_state(wsi);
|
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->user_space = NULL;
|
||||||
new_wsi->ietf_spec_revision = 0;
|
new_wsi->ietf_spec_revision = 0;
|
||||||
new_wsi->desc.sockfd = LWS_SOCK_INVALID;
|
new_wsi->desc.sockfd = LWS_SOCK_INVALID;
|
||||||
|
new_wsi->position_in_fds_table = -1;
|
||||||
|
|
||||||
vhost->context->count_wsi_allocated++;
|
vhost->context->count_wsi_allocated++;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1864,8 +1906,17 @@ lws_http_transaction_completed(struct lws *wsi)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} else
|
} else {
|
||||||
lws_header_table_reset(wsi, 1);
|
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 */
|
/* 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;
|
int n, ssl = 0;
|
||||||
|
|
||||||
if (!new_wsi) {
|
if (!new_wsi) {
|
||||||
if (type & LWS_ADOPT_SOCKET)
|
if (type & LWS_ADOPT_SOCKET && !(type & LWS_ADOPT_WS_PARENTIO))
|
||||||
compatible_close(fd.sockfd);
|
compatible_close(fd.sockfd);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1900,6 +1951,9 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
|
||||||
new_wsi->parent = parent;
|
new_wsi->parent = parent;
|
||||||
new_wsi->sibling_list = parent->child_list;
|
new_wsi->sibling_list = parent->child_list;
|
||||||
parent->child_list = new_wsi;
|
parent->child_list = new_wsi;
|
||||||
|
|
||||||
|
if (type & LWS_ADOPT_WS_PARENTIO)
|
||||||
|
new_wsi->parent_carries_io = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_wsi->desc = fd;
|
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");
|
lwsl_notice("OOM trying to get user_space\n");
|
||||||
goto bail;
|
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
|
} else
|
||||||
if (type & LWS_ADOPT_HTTP) /* he will transition later */
|
if (type & LWS_ADOPT_HTTP) /* he will transition later */
|
||||||
new_wsi->protocol =
|
new_wsi->protocol =
|
||||||
|
@ -2003,11 +2066,10 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (type & LWS_ADOPT_HTTP) {
|
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");
|
lwsl_debug("Attached ah immediately\n");
|
||||||
} else {
|
else
|
||||||
lwsl_notice("%s: waiting for ah\n", __func__);
|
lwsl_info("%s: waiting for ah\n", __func__);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_wsi;
|
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");
|
lwsl_info("file is being provided in gzip\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
#if defined(LWS_WITH_RANGES)
|
#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,
|
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
|
||||||
(unsigned char *)content_type,
|
(unsigned char *)content_type,
|
||||||
strlen(content_type), &p, end))
|
strlen(content_type), &p, end))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
#if defined(LWS_WITH_RANGES)
|
||||||
if (ranges >= 2) { /* multipart byteranges */
|
if (ranges >= 2) { /* multipart byteranges */
|
||||||
strncpy(wsi->u.http.multipart_content_type, content_type,
|
strncpy(wsi->u.http.multipart_content_type, content_type,
|
||||||
sizeof(wsi->u.http.multipart_content_type) - 1);
|
sizeof(wsi->u.http.multipart_content_type) - 1);
|
||||||
|
|
|
@ -329,6 +329,13 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
|
||||||
user_service:
|
user_service:
|
||||||
/* one shot */
|
/* one shot */
|
||||||
|
|
||||||
|
if (wsi->parent_carries_io) {
|
||||||
|
wsi->handling_pollout = 0;
|
||||||
|
wsi->leave_pollout_active = 0;
|
||||||
|
|
||||||
|
return lws_calllback_as_writeable(wsi);
|
||||||
|
}
|
||||||
|
|
||||||
if (pollfd) {
|
if (pollfd) {
|
||||||
int eff = wsi->leave_pollout_active;
|
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)
|
if (pollfd)
|
||||||
our_fd = pollfd->fd;
|
our_fd = pollfd->fd;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Phase 1: check every wsi on the timeout check list
|
||||||
|
*/
|
||||||
|
|
||||||
wsi = context->pt[tsi].timeout_list;
|
wsi = context->pt[tsi].timeout_list;
|
||||||
while (wsi) {
|
while (wsi) {
|
||||||
/* we have to take copies, because he may be deleted */
|
/* 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;
|
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
|
#ifdef LWS_WITH_CGI
|
||||||
|
/*
|
||||||
|
* Phase 3: handle cgi timeouts
|
||||||
|
*/
|
||||||
lws_cgi_kill_terminated(pt);
|
lws_cgi_kill_terminated(pt);
|
||||||
#endif
|
#endif
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -952,7 +1026,8 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// lwsl_debug("fd=%d, revents=%d, mode=%d, state=%d\n", pollfd->fd, pollfd->revents, (int)wsi->mode, (int)wsi->state);
|
// 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");
|
lwsl_debug("pollhup\n");
|
||||||
wsi->socket_is_permanently_unusable = 1;
|
wsi->socket_is_permanently_unusable = 1;
|
||||||
goto close_and_handled;
|
goto close_and_handled;
|
||||||
|
|
|
@ -41,7 +41,7 @@ int lws_alloc_vfs_file(struct lws_context *context, const char *filename, uint8_
|
||||||
len = lws_vfs_get_length(fops_fd);
|
len = lws_vfs_get_length(fops_fd);
|
||||||
|
|
||||||
*buf = malloc((size_t)len);
|
*buf = malloc((size_t)len);
|
||||||
if (!buf)
|
if (!*buf)
|
||||||
goto bail;
|
goto bail;
|
||||||
|
|
||||||
if (lws_vfs_file_read(fops_fd, amount, *buf, len))
|
if (lws_vfs_file_read(fops_fd, amount, *buf, len))
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
Name: libwebsockets
|
Name: libwebsockets
|
||||||
Version: 2.2.0
|
Version: 2.3.0
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: Websocket Server and Client Library
|
Summary: Websocket Server and Client Library
|
||||||
|
|
||||||
|
@ -49,13 +49,12 @@ rm -rf $RPM_BUILD_ROOT
|
||||||
%attr(755,root,root)
|
%attr(755,root,root)
|
||||||
/usr/bin/libwebsockets-test-server
|
/usr/bin/libwebsockets-test-server
|
||||||
/usr/bin/libwebsockets-test-server-extpoll
|
/usr/bin/libwebsockets-test-server-extpoll
|
||||||
/usr/bin/libwebsockets-test-server-pthreads
|
|
||||||
/usr/bin/libwebsockets-test-client
|
/usr/bin/libwebsockets-test-client
|
||||||
/usr/bin/libwebsockets-test-ping
|
/usr/bin/libwebsockets-test-ping
|
||||||
/usr/bin/libwebsockets-test-echo
|
/usr/bin/libwebsockets-test-echo
|
||||||
/usr/bin/libwebsockets-test-fraggle
|
/usr/bin/libwebsockets-test-fraggle
|
||||||
/usr/bin/libwebsockets-test-fuzxy
|
/usr/bin/libwebsockets-test-fuzxy
|
||||||
/%{_libdir}/libwebsockets.so.10
|
/%{_libdir}/libwebsockets.so.11
|
||||||
/%{_libdir}/libwebsockets.so
|
/%{_libdir}/libwebsockets.so
|
||||||
/%{_libdir}/cmake/libwebsockets/LibwebsocketsConfig.cmake
|
/%{_libdir}/cmake/libwebsockets/LibwebsocketsConfig.cmake
|
||||||
/%{_libdir}/cmake/libwebsockets/LibwebsocketsConfigVersion.cmake
|
/%{_libdir}/cmake/libwebsockets/LibwebsocketsConfigVersion.cmake
|
||||||
|
@ -70,8 +69,12 @@ rm -rf $RPM_BUILD_ROOT
|
||||||
%attr(755,root,root)
|
%attr(755,root,root)
|
||||||
/%{_libdir}/libwebsockets.a
|
/%{_libdir}/libwebsockets.a
|
||||||
/%{_libdir}/pkgconfig/libwebsockets.pc
|
/%{_libdir}/pkgconfig/libwebsockets.pc
|
||||||
|
/%{_libdir}/pkgconfig/libwebsockets_static.pc
|
||||||
|
|
||||||
%changelog
|
%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
|
* Mon Mar 06 2017 Andy Green <andy@warmcat.com> 2.2.0-1
|
||||||
- MAJOR SONAMEBUMP APICHANGES Upstream 2.2.0 release
|
- MAJOR SONAMEBUMP APICHANGES Upstream 2.2.0 release
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,9 @@
|
||||||
# vhost-specific config options for the protocol
|
# vhost-specific config options for the protocol
|
||||||
#
|
#
|
||||||
"ws-protocols": [{
|
"ws-protocols": [{
|
||||||
|
"lws-meta": {
|
||||||
|
"status": "ok"
|
||||||
|
},
|
||||||
"dumb-increment-protocol": {
|
"dumb-increment-protocol": {
|
||||||
"status": "ok"
|
"status": "ok"
|
||||||
},
|
},
|
||||||
|
|
|
@ -58,11 +58,13 @@ static int pids[32];
|
||||||
#define LWSWS_CONFIG_STRING_SIZE (32 * 1024)
|
#define LWSWS_CONFIG_STRING_SIZE (32 * 1024)
|
||||||
|
|
||||||
static const struct lws_extension exts[] = {
|
static const struct lws_extension exts[] = {
|
||||||
|
#if !defined(LWS_NO_EXTENSIONS)
|
||||||
{
|
{
|
||||||
"permessage-deflate",
|
"permessage-deflate",
|
||||||
lws_extension_callback_pm_deflate,
|
lws_extension_callback_pm_deflate,
|
||||||
"permessage-deflate"
|
"permessage-deflate"
|
||||||
},
|
},
|
||||||
|
#endif
|
||||||
{ NULL, NULL, NULL /* terminator */ }
|
{ NULL, NULL, NULL /* terminator */ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -220,7 +222,7 @@ int main(int argc, char **argv)
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
fprintf(stderr, "Usage: lwsws [-c <config dir>] "
|
fprintf(stderr, "Usage: lwsws [-c <config dir>] "
|
||||||
"[-d <log bitfield>] [-D] [--help]\n");
|
"[-d <log bitfield>] [--help]\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -474,7 +474,7 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason,
|
||||||
WSI_TOKEN_HOST) < 0)
|
WSI_TOKEN_HOST) < 0)
|
||||||
return 1;
|
return 1;
|
||||||
lws_snprintf(pss->onward, sizeof(pss->onward) - 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);
|
cookie, args->p);
|
||||||
lwsl_notice("redirecting to ourselves with cookie refresh\n");
|
lwsl_notice("redirecting to ourselves with cookie refresh\n");
|
||||||
/* we need a redirect to ourselves, session cookie is expired */
|
/* we need a redirect to ourselves, session cookie is expired */
|
||||||
|
|
616
plugins/protocol_lws_meta.c
Normal file
616
plugins/protocol_lws_meta.c
Normal 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
|
|
@ -10,7 +10,9 @@ SHELL=/bin/bash
|
||||||
|
|
||||||
ESPPORT ?= $(CONFIG_ESPTOOLPY_PORT)
|
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)
|
FAC=$(CONFIG_LWS_IS_FACTORY_APPLICATION)
|
||||||
ifeq ($(FAC),)
|
ifeq ($(FAC),)
|
||||||
|
@ -19,20 +21,20 @@ endif
|
||||||
export FAC
|
export FAC
|
||||||
DIRNAME:=$(shell basename $$(pwd) | tr -d '\n')
|
DIRNAME:=$(shell basename $$(pwd) | tr -d '\n')
|
||||||
|
|
||||||
$(COMPONENT_PATH)/../build/pack.img: $(APP_BIN)
|
$(LWS_BUILD_PATH)/pack.img: $(APP_BIN)
|
||||||
GNUSTAT=stat ;\
|
GNUSTAT=stat ;\
|
||||||
if [ `which gstat 2>/dev/null` ] ; then GNUSTAT=gstat ; fi ;\
|
if [ `which gstat 2>/dev/null` ] ; then GNUSTAT=gstat ; fi ;\
|
||||||
DIRNAME=$$(basename $$(pwd) | tr -d '\n') ;\
|
DIRNAME=$$(basename $$(pwd) | tr -d '\n') ;\
|
||||||
genromfs -f $(COMPONENT_PATH)/../build/romfs.img -d $(COMPONENT_PATH)/../romfs-files ; \
|
genromfs -f $(LWS_BUILD_PATH)/romfs.img -d $(PROJECT_PATH)/romfs-files ; \
|
||||||
RLEN=$$($$GNUSTAT -c %s $(COMPONENT_PATH)/../build/romfs.img) ;\
|
RLEN=$$($$GNUSTAT -c %s $(LWS_BUILD_PATH)/romfs.img) ;\
|
||||||
LEN=$$($$GNUSTAT -c %s $(COMPONENT_PATH)/../build/$$DIRNAME.bin) ;\
|
LEN=$$($$GNUSTAT -c %s $(LWS_BUILD_PATH)/$$DIRNAME.bin) ;\
|
||||||
printf " Original length: 0x%06x (%8d)\n" $$LEN $$LEN ; \
|
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 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
|
||||||
printf %02x $$(( ( $$RLEN / 256 ) % 256 )) | xxd -r -p >> $(COMPONENT_PATH)/../build/$$DIRNAME.bin ;\
|
printf %02x $$(( ( $$RLEN / 256 ) % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
|
||||||
printf %02x $$(( ( $$RLEN / 65536 ) % 256 )) | xxd -r -p >> $(COMPONENT_PATH)/../build/$$DIRNAME.bin ;\
|
printf %02x $$(( ( $$RLEN / 65536 ) % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
|
||||||
printf %02x $$(( ( $$RLEN / 16777216 ) % 256 )) | xxd -r -p >> $(COMPONENT_PATH)/../build/$$DIRNAME.bin ;\
|
printf %02x $$(( ( $$RLEN / 16777216 ) % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
|
||||||
cat $(COMPONENT_PATH)/../build/romfs.img >>$(COMPONENT_PATH)/../build/$$DIRNAME.bin ; \
|
cat $(LWS_BUILD_PATH)/romfs.img >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ; \
|
||||||
LEN=$$($$GNUSTAT -c %s $(COMPONENT_PATH)/../build/$$DIRNAME.bin) ;\
|
LEN=$$($$GNUSTAT -c %s $(LWS_BUILD_PATH)/$$DIRNAME.bin) ;\
|
||||||
UNIXTIME=$$(date +%s | tr -d '\n') ; \
|
UNIXTIME=$$(date +%s | tr -d '\n') ; \
|
||||||
echo -n -e "{\r\n \"schema\": \"lws1\",\r\n \"model\": \"$(CONFIG_LWS_MODEL_NAME)\",\r\n \"builder\": \"" > $(jbi) ;\
|
echo -n -e "{\r\n \"schema\": \"lws1\",\r\n \"model\": \"$(CONFIG_LWS_MODEL_NAME)\",\r\n \"builder\": \"" > $(jbi) ;\
|
||||||
hostname | tr -d '\n' >> $(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 \"factory\": \"$(FAC)" >> $(jbi) ;\
|
||||||
echo -n -e "\"\r\n}" >> $(jbi) ;\
|
echo -n -e "\"\r\n}" >> $(jbi) ;\
|
||||||
JLEN=$$($$GNUSTAT -c %s $(jbi)) ;\
|
JLEN=$$($$GNUSTAT -c %s $(jbi)) ;\
|
||||||
printf %02x $$(( $$JLEN % 256 )) | xxd -r -p >> $(COMPONENT_PATH)/../build/$$DIRNAME.bin ;\
|
printf %02x $$(( $$JLEN % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
|
||||||
printf %02x $$(( ( $$JLEN / 256 ) % 256 )) | xxd -r -p >> $(COMPONENT_PATH)/../build/$$DIRNAME.bin ;\
|
printf %02x $$(( ( $$JLEN / 256 ) % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
|
||||||
printf %02x $$(( ( $$JLEN / 65536 ) % 256 )) | xxd -r -p >> $(COMPONENT_PATH)/../build/$$DIRNAME.bin ;\
|
printf %02x $$(( ( $$JLEN / 65536 ) % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
|
||||||
printf %02x $$(( ( $$JLEN / 16777216 ) % 256 )) | xxd -r -p >> $(COMPONENT_PATH)/../build/$$DIRNAME.bin ;\
|
printf %02x $$(( ( $$JLEN / 16777216 ) % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
|
||||||
cat $(jbi) >> $(COMPONENT_PATH)/../build/$$DIRNAME.bin ;\
|
cat $(jbi) >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
|
||||||
cp $(COMPONENT_PATH)/../build/$$DIRNAME.bin $(COMPONENT_PATH)/../build/pack.img ;\
|
cp $(LWS_BUILD_PATH)/$$DIRNAME.bin $(LWS_BUILD_PATH)/pack.img ;\
|
||||||
LEN=$$($$GNUSTAT -c %s $(COMPONENT_PATH)/../build/$$DIRNAME.bin) ;\
|
LEN=$$($$GNUSTAT -c %s $(LWS_BUILD_PATH)/$$DIRNAME.bin) ;\
|
||||||
cp $(COMPONENT_PATH)/../build/$$DIRNAME.bin $(COMPONENT_PATH)/../build/$$DIRNAME-$$UNIXTIME.bin ;\
|
cp $(LWS_BUILD_PATH)/$$DIRNAME.bin $(LWS_BUILD_PATH)/$$DIRNAME-$$UNIXTIME.bin ;\
|
||||||
printf " After ROMFS + Build info: 0x%06x (%8d)\n" $$LEN $$LEN
|
printf " After ROMFS + Build info: 0x%06x (%8d)\n" $$LEN $$LEN
|
||||||
|
|
||||||
.PHONY: manifest
|
.PHONY: manifest
|
||||||
|
@ -76,17 +78,17 @@ endif
|
||||||
cat $(F)/build/json-buildinfo >> build/manifest.json
|
cat $(F)/build/json-buildinfo >> build/manifest.json
|
||||||
echo -n -e "\r\n}\r\n" >> 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') ;\
|
DIRNAME=$$(basename $$(pwd) | tr -d '\n') ;\
|
||||||
$(IDF_PATH)/components/esptool_py/esptool/esptool.py \
|
$(IDF_PATH)/components/esptool_py/esptool/esptool.py \
|
||||||
--chip esp32 \
|
--chip esp32 \
|
||||||
--port $(ESPPORT) \
|
--port $(ESPPORT) \
|
||||||
--baud $(CONFIG_ESPTOOLPY_BAUD) \
|
--baud $(CONFIG_ESPTOOLPY_BAUD) \
|
||||||
write_flash 0x110000 $(COMPONENT_PATH)/../build/$$DIRNAME.bin
|
write_flash 0x110000 $(LWS_BUILD_PATH)/$$DIRNAME.bin
|
||||||
|
|
||||||
erase_ota:
|
erase_ota:
|
||||||
$(IDF_PATH)/components/esptool_py/esptool/esptool.py \
|
$(IDF_PATH)/components/esptool_py/esptool/esptool.py \
|
||||||
|
|
|
@ -29,10 +29,10 @@ function check {
|
||||||
fi
|
fi
|
||||||
if [ "$1" = "defaultplusforbidden" ] ; then
|
if [ "$1" = "defaultplusforbidden" ] ; then
|
||||||
cat $INSTALLED/../share/libwebsockets-test-server/test.html > /tmp/plusforb
|
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
|
diff /tmp/lwscap /tmp/plusforb > /dev/null
|
||||||
if [ $? -ne 0 ] ; then
|
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
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
@ -101,7 +101,9 @@ killall libwebsockets-test-server 2>/dev/null
|
||||||
libwebsockets-test-server -d15 2>> $LOG &
|
libwebsockets-test-server -d15 2>> $LOG &
|
||||||
CPID=$!
|
CPID=$!
|
||||||
|
|
||||||
while [ -z "`grep Listening $LOG`" ] ; do
|
echo "Started server on PID $CPID"
|
||||||
|
|
||||||
|
while [ -z "`grep ort\ 7681 $LOG`" ] ; do
|
||||||
sleep 0.5s
|
sleep 0.5s
|
||||||
done
|
done
|
||||||
check
|
check
|
||||||
|
@ -220,7 +222,7 @@ echo -e "GET ...................................................................
|
||||||
check
|
check
|
||||||
|
|
||||||
echo
|
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........................................" \
|
echo -e "GET /test.html HTTP/1.1\x0d\x0a\x0d\x0aILLEGAL-PAYLOAD........................................" \
|
||||||
"......................................................................................................................." \
|
"......................................................................................................................." \
|
||||||
"......................................................................................................................." \
|
"......................................................................................................................." \
|
||||||
|
|
|
@ -108,6 +108,285 @@ function removeEvent( obj, type, fn ) {
|
||||||
* end of grayOut related stuff
|
* 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)
|
function lws_san(s)
|
||||||
{
|
{
|
||||||
|
|
|
@ -536,7 +536,8 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
/* stats */
|
/* 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"
|
"using %d connections ---\n"
|
||||||
"%lu packets transmitted, %lu received, "
|
"%lu packets transmitted, %lu received, "
|
||||||
"%lu%% packet loss, time %ldms\n"
|
"%lu%% packet loss, time %ldms\n"
|
||||||
|
|
|
@ -524,7 +524,7 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef LWS_NO_CLIENT
|
#ifndef LWS_NO_CLIENT
|
||||||
if (pss->reason_bf & 2) {
|
if (pss->reason_bf & LWS_CB_REASON_AUX_BF__PROXY) {
|
||||||
char *px = buf + LWS_PRE;
|
char *px = buf + LWS_PRE;
|
||||||
int lenx = sizeof(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);
|
wsi1 = lws_get_child(wsi);
|
||||||
if (!wsi1)
|
if (!wsi1)
|
||||||
break;
|
break;
|
||||||
|
@ -674,7 +674,7 @@ bail:
|
||||||
if (!lws_get_parent(wsi))
|
if (!lws_get_parent(wsi))
|
||||||
break;
|
break;
|
||||||
pss1 = lws_wsi_user(lws_get_parent(wsi));
|
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));
|
lws_callback_on_writable(lws_get_parent(wsi));
|
||||||
break;
|
break;
|
||||||
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
|
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* libwebsockets-test-server - libwebsockets test implementation
|
* 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
|
* This file is made available under the Creative Commons CC0 1.0
|
||||||
* Universal Public Domain Dedication.
|
* Universal Public Domain Dedication.
|
||||||
|
@ -34,6 +34,11 @@ char *resource_path = LOCAL_RESOURCE_PATH;
|
||||||
char crl_path[1024] = "";
|
char crl_path[1024] = "";
|
||||||
#endif
|
#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 */
|
/* singlethreaded version --> no locks */
|
||||||
|
|
||||||
void test_server_lock(int care)
|
void test_server_lock(int care)
|
||||||
|
@ -59,60 +64,53 @@ void test_server_unlock(int care)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum demo_protocols {
|
enum demo_protocols {
|
||||||
/* always first */
|
/* always first */
|
||||||
PROTOCOL_HTTP = 0,
|
PROTOCOL_HTTP = 0,
|
||||||
|
|
||||||
PROTOCOL_DUMB_INCREMENT,
|
PROTOCOL_DUMB_INCREMENT,
|
||||||
PROTOCOL_LWS_MIRROR,
|
PROTOCOL_LWS_MIRROR,
|
||||||
|
PROTOCOL_LWS_META,
|
||||||
|
|
||||||
/* always last */
|
/* always last */
|
||||||
DEMO_PROTOCOL_COUNT
|
DEMO_PROTOCOL_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
/* list of supported protocols and callbacks */
|
/* list of supported protocols and callbacks */
|
||||||
|
|
||||||
static struct lws_protocols protocols[] = {
|
static struct lws_protocols protocols[] = {
|
||||||
/* first protocol must always be HTTP handler */
|
/* first protocol must always be HTTP handler */
|
||||||
|
|
||||||
{
|
{
|
||||||
"http-only", /* name */
|
"http-only", /* name */
|
||||||
callback_http, /* callback */
|
callback_http, /* callback */
|
||||||
sizeof (struct per_session_data__http), /* per_session_data_size */
|
sizeof (struct per_session_data__http), /* per_session_data_size */
|
||||||
0, /* max frame size / rx buffer */
|
0, /* max frame size / rx buffer */
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"dumb-increment-protocol",
|
"dumb-increment-protocol",
|
||||||
callback_dumb_increment,
|
callback_dumb_increment,
|
||||||
sizeof(struct per_session_data__dumb_increment),
|
sizeof(struct per_session_data__dumb_increment),
|
||||||
10,
|
10,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"lws-mirror-protocol",
|
LWS_PLUGIN_PROTOCOL_MIRROR,
|
||||||
callback_lws_mirror,
|
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
|
||||||
sizeof(struct per_session_data__lws_mirror),
|
LWS_PLUGIN_PROTOCOL_LWS_META,
|
||||||
128,
|
{ NULL, NULL, 0, 0 } /* terminator */
|
||||||
},
|
|
||||||
{
|
|
||||||
"lws-status",
|
|
||||||
callback_lws_status,
|
|
||||||
sizeof(struct per_session_data__lws_status),
|
|
||||||
128,
|
|
||||||
},
|
|
||||||
{ NULL, NULL, 0, 0 } /* terminator */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct lws_extension exts[] = {
|
static const struct lws_extension exts[] = {
|
||||||
{
|
{
|
||||||
"permessage-deflate",
|
"permessage-deflate",
|
||||||
lws_extension_callback_pm_deflate,
|
lws_extension_callback_pm_deflate,
|
||||||
"permessage-deflate; client_no_context_takeover; client_max_window_bits"
|
"permessage-deflate; client_no_context_takeover; client_max_window_bits"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"deflate-frame",
|
"deflate-frame",
|
||||||
lws_extension_callback_pm_deflate,
|
lws_extension_callback_pm_deflate,
|
||||||
"deflate_frame"
|
"deflate_frame"
|
||||||
},
|
},
|
||||||
{ NULL, NULL, NULL /* terminator */ }
|
{ NULL, NULL, NULL /* terminator */ }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* this shows how to override the lws file operations. You don't need
|
/* 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
|
static lws_fop_fd_t
|
||||||
test_server_fops_open(const struct lws_plat_file_ops *fops,
|
test_server_fops_open(const struct lws_plat_file_ops *fops,
|
||||||
const char *vfs_path, const char *vpath,
|
const char *vfs_path, const char *vpath,
|
||||||
lws_fop_flags_t *flags)
|
lws_fop_flags_t *flags)
|
||||||
{
|
{
|
||||||
lws_fop_fd_t n;
|
lws_fop_fd_t n;
|
||||||
|
|
||||||
/* call through to original platform implementation */
|
/* call through to original platform implementation */
|
||||||
n = fops_plat.open(fops, vfs_path, vpath, flags);
|
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)
|
void signal_cb(evutil_socket_t sock_fd, short events, void *ctx)
|
||||||
{
|
{
|
||||||
lwsl_notice("Signal caught, exiting...\n");
|
struct event_base *event_base_loop = ctx;
|
||||||
force_exit = 1;
|
|
||||||
if (events & EV_SIGNAL) {
|
lwsl_notice("Signal caught, exiting...\n");
|
||||||
struct event_base *event_base_loop = event_get_base((struct event *) ctx);
|
force_exit = 1;
|
||||||
event_base_loopbreak(event_base_loop);
|
if (events & EV_SIGNAL)
|
||||||
}
|
event_base_loopbreak(event_base_loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ev_timeout_cb (evutil_socket_t sock_fd, short events, void *ctx)
|
ev_timeout_cb (evutil_socket_t sock_fd, short events, void *ctx)
|
||||||
{
|
{
|
||||||
lws_callback_on_writable_all_protocol(context,
|
lws_callback_on_writable_all_protocol(context,
|
||||||
&protocols[PROTOCOL_DUMB_INCREMENT]);
|
&protocols[PROTOCOL_DUMB_INCREMENT]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct option options[] = {
|
static struct option options[] = {
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ "debug", required_argument, NULL, 'd' },
|
{ "debug", required_argument, NULL, 'd' },
|
||||||
{ "port", required_argument, NULL, 'p' },
|
{ "port", required_argument, NULL, 'p' },
|
||||||
{ "ssl", no_argument, NULL, 's' },
|
{ "ssl", no_argument, NULL, 's' },
|
||||||
{ "allow-non-ssl", no_argument, NULL, 'a' },
|
{ "allow-non-ssl", no_argument, NULL, 'a' },
|
||||||
{ "interface", required_argument, NULL, 'i' },
|
{ "interface", required_argument, NULL, 'i' },
|
||||||
{ "closetest", no_argument, NULL, 'c' },
|
{ "closetest", no_argument, NULL, 'c' },
|
||||||
{ "libevent", no_argument, NULL, 'e' },
|
{ "libevent", no_argument, NULL, 'e' },
|
||||||
#ifndef LWS_NO_DAEMONIZE
|
#ifndef LWS_NO_DAEMONIZE
|
||||||
{ "daemonize", no_argument, NULL, 'D' },
|
{ "daemonize", no_argument, NULL, 'D' },
|
||||||
#endif
|
#endif
|
||||||
{ "resource_path", required_argument, NULL, 'r' },
|
{ "resource_path", required_argument, NULL, 'r' },
|
||||||
{ NULL, 0, 0, 0 }
|
{ NULL, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int sigs[] = { SIGINT, SIGKILL, SIGTERM, SIGSEGV, SIGFPE };
|
int sigs[] = { SIGINT, SIGKILL, SIGTERM, SIGSEGV, SIGFPE };
|
||||||
struct event *signals[ARRAY_SIZE(sigs)];
|
struct event *signals[ARRAY_SIZE(sigs)];
|
||||||
struct event_base *event_base_loop = event_base_new();
|
struct event_base *event_base_loop = event_base_new();
|
||||||
struct lws_context_creation_info info;
|
struct lws_context_creation_info info;
|
||||||
char interface_name[128] = "";
|
char interface_name[128] = "";
|
||||||
const char *iface = NULL;
|
const char *iface = NULL;
|
||||||
struct event *timeout_watcher;
|
struct event *timeout_watcher;
|
||||||
char cert_path[1024];
|
char cert_path[1024];
|
||||||
char key_path[1024];
|
char key_path[1024];
|
||||||
int use_ssl = 0;
|
int use_ssl = 0;
|
||||||
int opts = 0;
|
int opts = 0;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
int syslog_options = LOG_PID | LOG_PERROR;
|
int syslog_options = LOG_PID | LOG_PERROR;
|
||||||
#endif
|
#endif
|
||||||
#ifndef LWS_NO_DAEMONIZE
|
#ifndef LWS_NO_DAEMONIZE
|
||||||
int daemonize = 0;
|
int daemonize = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* take care to zero down the info struct, he contains random garbaage
|
* take care to zero down the info struct, he contains random garbaage
|
||||||
* from the stack otherwise
|
* from the stack otherwise
|
||||||
*/
|
*/
|
||||||
memset(&info, 0, sizeof info);
|
memset(&info, 0, sizeof info);
|
||||||
info.port = 7681;
|
info.port = 7681;
|
||||||
|
|
||||||
while (n >= 0) {
|
while (n >= 0) {
|
||||||
n = getopt_long(argc, argv, "eci:hsap:d:Dr:", options, NULL);
|
n = getopt_long(argc, argv, "eci:hsap:d:Dr:", options, NULL);
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
continue;
|
continue;
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case 'e':
|
case 'e':
|
||||||
opts |= LWS_SERVER_OPTION_LIBEVENT;
|
opts |= LWS_SERVER_OPTION_LIBEVENT;
|
||||||
break;
|
break;
|
||||||
#ifndef LWS_NO_DAEMONIZE
|
#ifndef LWS_NO_DAEMONIZE
|
||||||
case 'D':
|
case 'D':
|
||||||
daemonize = 1;
|
daemonize = 1;
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
syslog_options &= ~LOG_PERROR;
|
syslog_options &= ~LOG_PERROR;
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
case 'd':
|
break;
|
||||||
debug_level = atoi(optarg);
|
#endif
|
||||||
break;
|
case 'd':
|
||||||
case 's':
|
debug_level = atoi(optarg);
|
||||||
use_ssl = 1;
|
break;
|
||||||
break;
|
case 's':
|
||||||
case 'a':
|
use_ssl = 1;
|
||||||
opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
|
break;
|
||||||
break;
|
case 'a':
|
||||||
case 'p':
|
opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
|
||||||
info.port = atoi(optarg);
|
break;
|
||||||
break;
|
case 'p':
|
||||||
case 'i':
|
info.port = atoi(optarg);
|
||||||
strncpy(interface_name, optarg, sizeof interface_name);
|
break;
|
||||||
interface_name[(sizeof interface_name) - 1] = '\0';
|
case 'i':
|
||||||
iface = interface_name;
|
strncpy(interface_name, optarg, sizeof interface_name);
|
||||||
break;
|
interface_name[(sizeof interface_name) - 1] = '\0';
|
||||||
case 'c':
|
iface = interface_name;
|
||||||
close_testing = 1;
|
break;
|
||||||
fprintf(stderr, " Close testing mode -- closes on "
|
case 'c':
|
||||||
"client after 50 dumb increments"
|
close_testing = 1;
|
||||||
"and suppresses lws_mirror spam\n");
|
fprintf(stderr, " Close testing mode -- closes on "
|
||||||
break;
|
"client after 50 dumb increments"
|
||||||
case 'r':
|
"and suppresses lws_mirror spam\n");
|
||||||
resource_path = optarg;
|
break;
|
||||||
printf("Setting resource path to \"%s\"\n", resource_path);
|
case 'r':
|
||||||
break;
|
resource_path = optarg;
|
||||||
case 'h':
|
printf("Setting resource path to \"%s\"\n", resource_path);
|
||||||
fprintf(stderr, "Usage: test-server "
|
break;
|
||||||
"[--port=<p>] [--ssl] "
|
case 'h':
|
||||||
"[-d <log bitfield>] "
|
fprintf(stderr, "Usage: test-server "
|
||||||
"[--resource_path <path>]\n");
|
"[--port=<p>] [--ssl] "
|
||||||
exit(1);
|
"[-d <log bitfield>] "
|
||||||
}
|
"[--resource_path <path>]\n");
|
||||||
}
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32)
|
#if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32)
|
||||||
/*
|
/*
|
||||||
* normally lock path would be /var/lock/lwsts or similar, to
|
* normally lock path would be /var/lock/lwsts or similar, to
|
||||||
* simplify getting started without having to take care about
|
* simplify getting started without having to take care about
|
||||||
* permissions or running as root, set to /tmp/.lwsts-lock
|
* permissions or running as root, set to /tmp/.lwsts-lock
|
||||||
*/
|
*/
|
||||||
if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) {
|
if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) {
|
||||||
fprintf(stderr, "Failed to daemonize\n");
|
fprintf(stderr, "Failed to daemonize\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (n = 0; n < ARRAY_SIZE(sigs); n++) {
|
for (n = 0; n < ARRAY_SIZE(sigs); n++) {
|
||||||
signals[n] = evsignal_new(event_base_loop, sigs[n], signal_cb, event_self_cbarg());
|
signals[n] = evsignal_new(event_base_loop, sigs[n], signal_cb, event_base_loop);
|
||||||
evsignal_add(signals[n], NULL);
|
|
||||||
}
|
evsignal_add(signals[n], NULL);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
/* we will only try to log things according to our debug_level */
|
/* we will only try to log things according to our debug_level */
|
||||||
setlogmask(LOG_UPTO (LOG_DEBUG));
|
setlogmask(LOG_UPTO (LOG_DEBUG));
|
||||||
openlog("lwsts", syslog_options, LOG_DAEMON);
|
openlog("lwsts", syslog_options, LOG_DAEMON);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* tell the library what debug level to emit and to send it to syslog */
|
/* tell the library what debug level to emit and to send it to syslog */
|
||||||
lws_set_log_level(debug_level, lwsl_emit_syslog);
|
lws_set_log_level(debug_level, lwsl_emit_syslog);
|
||||||
|
|
||||||
lwsl_notice("libwebsockets test server libevent - license LGPL2.1+SLE\n");
|
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("(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.iface = iface;
|
||||||
info.protocols = protocols;
|
info.protocols = protocols;
|
||||||
info.extensions = exts;
|
info.extensions = exts;
|
||||||
|
|
||||||
info.ssl_cert_filepath = NULL;
|
info.ssl_cert_filepath = NULL;
|
||||||
info.ssl_private_key_filepath = NULL;
|
info.ssl_private_key_filepath = NULL;
|
||||||
|
|
||||||
if (use_ssl) {
|
if (use_ssl) {
|
||||||
if (strlen(resource_path) > sizeof(cert_path) - 32) {
|
if (strlen(resource_path) > sizeof(cert_path) - 32) {
|
||||||
lwsl_err("resource path too long\n");
|
lwsl_err("resource path too long\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
sprintf(cert_path, "%s/libwebsockets-test-server.pem",
|
sprintf(cert_path, "%s/libwebsockets-test-server.pem",
|
||||||
resource_path);
|
resource_path);
|
||||||
if (strlen(resource_path) > sizeof(key_path) - 32) {
|
if (strlen(resource_path) > sizeof(key_path) - 32) {
|
||||||
lwsl_err("resource path too long\n");
|
lwsl_err("resource path too long\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
sprintf(key_path, "%s/libwebsockets-test-server.key.pem",
|
sprintf(key_path, "%s/libwebsockets-test-server.key.pem",
|
||||||
resource_path);
|
resource_path);
|
||||||
|
|
||||||
info.ssl_cert_filepath = cert_path;
|
info.ssl_cert_filepath = cert_path;
|
||||||
info.ssl_private_key_filepath = key_path;
|
info.ssl_private_key_filepath = key_path;
|
||||||
|
|
||||||
opts |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
opts |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||||
}
|
}
|
||||||
info.gid = -1;
|
info.gid = -1;
|
||||||
info.uid = -1;
|
info.uid = -1;
|
||||||
info.max_http_header_pool = 1;
|
info.max_http_header_pool = 1;
|
||||||
info.options = opts | LWS_SERVER_OPTION_LIBEVENT;
|
info.options = opts | LWS_SERVER_OPTION_LIBEVENT;
|
||||||
|
|
||||||
context = lws_create_context(&info);
|
context = lws_create_context(&info);
|
||||||
if (context == NULL) {
|
if (context == NULL) {
|
||||||
lwsl_err("libwebsocket init failed\n");
|
lwsl_err("libwebsocket init failed\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* this shows how to override the lws file operations. You don't need
|
* 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
|
* to do any of this unless you have a reason (eg, want to serve
|
||||||
* compressed files without decompressing the whole archive)
|
* compressed files without decompressing the whole archive)
|
||||||
*/
|
*/
|
||||||
/* stash original platform fops */
|
/* stash original platform fops */
|
||||||
fops_plat = *(lws_get_fops(context));
|
fops_plat = *(lws_get_fops(context));
|
||||||
/* override the active fops */
|
/* override the active fops */
|
||||||
lws_get_fops(context)->open = test_server_fops_open;
|
lws_get_fops(context)->open = test_server_fops_open;
|
||||||
|
|
||||||
// Don't use the default Signal Event Watcher & Handler
|
// Don't use the default Signal Event Watcher & Handler
|
||||||
lws_event_sigint_cfg(context, 0, NULL);
|
lws_event_sigint_cfg(context, 0, NULL);
|
||||||
// Initialize the LWS with libevent loop
|
// Initialize the LWS with libevent loop
|
||||||
lws_event_initloop(context, event_base_loop, 0);
|
lws_event_initloop(context, event_base_loop, 0);
|
||||||
|
|
||||||
timeout_watcher = evtimer_new(event_base_loop, ev_timeout_cb, NULL);
|
timeout_watcher = event_new(event_base_loop, -1, EV_PERSIST, ev_timeout_cb, NULL);
|
||||||
struct timeval tv = {0, 50000};
|
struct timeval tv = {0, 50000};
|
||||||
evtimer_add(timeout_watcher, &tv);
|
evtimer_add(timeout_watcher, &tv);
|
||||||
event_base_dispatch(event_base_loop);
|
event_base_dispatch(event_base_loop);
|
||||||
|
|
||||||
lws_context_destroy(context);
|
lws_context_destroy(context);
|
||||||
lwsl_notice("libwebsockets-test-server exited cleanly\n");
|
lwsl_notice("libwebsockets-test-server exited cleanly\n");
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
closelog();
|
closelog();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,7 @@ void test_server_unlock(int care)
|
||||||
#include "../plugins/protocol_dumb_increment.c"
|
#include "../plugins/protocol_dumb_increment.c"
|
||||||
#include "../plugins/protocol_lws_mirror.c"
|
#include "../plugins/protocol_lws_mirror.c"
|
||||||
#include "../plugins/protocol_lws_status.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
|
* This demo server shows how to use libwebsockets for one or more
|
||||||
|
@ -73,6 +74,7 @@ enum demo_protocols {
|
||||||
PROTOCOL_DUMB_INCREMENT,
|
PROTOCOL_DUMB_INCREMENT,
|
||||||
PROTOCOL_LWS_MIRROR,
|
PROTOCOL_LWS_MIRROR,
|
||||||
PROTOCOL_LWS_STATUS,
|
PROTOCOL_LWS_STATUS,
|
||||||
|
PROTOCOL_LWS_META,
|
||||||
|
|
||||||
/* always last */
|
/* always last */
|
||||||
DEMO_PROTOCOL_COUNT
|
DEMO_PROTOCOL_COUNT
|
||||||
|
@ -92,6 +94,7 @@ static struct lws_protocols protocols[] = {
|
||||||
LWS_PLUGIN_PROTOCOL_DUMB_INCREMENT,
|
LWS_PLUGIN_PROTOCOL_DUMB_INCREMENT,
|
||||||
LWS_PLUGIN_PROTOCOL_MIRROR,
|
LWS_PLUGIN_PROTOCOL_MIRROR,
|
||||||
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
|
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
|
||||||
|
LWS_PLUGIN_PROTOCOL_LWS_META,
|
||||||
{ NULL, NULL, 0, 0 } /* terminator */
|
{ NULL, NULL, 0, 0 } /* terminator */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -456,6 +459,9 @@ int main(int argc, char **argv)
|
||||||
lwsl_notice("uv loop close rc %s\n",
|
lwsl_notice("uv loop close rc %s\n",
|
||||||
e ? uv_strerror(e) : "ok");
|
e ? uv_strerror(e) : "ok");
|
||||||
|
|
||||||
|
/* PHASE 4: finalize context destruction */
|
||||||
|
|
||||||
|
lws_context_destroy2(context);
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
|
|
@ -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.
|
* 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,
|
||||||
|
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 */
|
&pvo_opt4, /* set us as the protocol who gets raw connections */
|
||||||
"protocol-lws-raw-test",
|
"protocol-lws-raw-test",
|
||||||
"" /* ignored, just matches the protocol name above */
|
"" /* ignored, just matches the protocol name above */
|
||||||
|
|
|
@ -68,6 +68,7 @@ char crl_path[1024] = "";
|
||||||
#define LWS_PLUGIN_STATIC
|
#define LWS_PLUGIN_STATIC
|
||||||
#include "../plugins/protocol_lws_mirror.c"
|
#include "../plugins/protocol_lws_mirror.c"
|
||||||
#include "../plugins/protocol_lws_status.c"
|
#include "../plugins/protocol_lws_status.c"
|
||||||
|
#include "../plugins/protocol_lws_meta.c"
|
||||||
|
|
||||||
/* singlethreaded version --> no locks */
|
/* singlethreaded version --> no locks */
|
||||||
|
|
||||||
|
@ -104,6 +105,8 @@ enum demo_protocols {
|
||||||
PROTOCOL_LWS_MIRROR,
|
PROTOCOL_LWS_MIRROR,
|
||||||
PROTOCOL_LWS_STATUS,
|
PROTOCOL_LWS_STATUS,
|
||||||
|
|
||||||
|
PROTOCOL_LWS_META,
|
||||||
|
|
||||||
/* always last */
|
/* always last */
|
||||||
DEMO_PROTOCOL_COUNT
|
DEMO_PROTOCOL_COUNT
|
||||||
};
|
};
|
||||||
|
@ -130,6 +133,8 @@ static struct lws_protocols protocols[] = {
|
||||||
},
|
},
|
||||||
LWS_PLUGIN_PROTOCOL_MIRROR,
|
LWS_PLUGIN_PROTOCOL_MIRROR,
|
||||||
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
|
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
|
||||||
|
|
||||||
|
LWS_PLUGIN_PROTOCOL_LWS_META,
|
||||||
{ NULL, NULL, 0, 0 } /* terminator */
|
{ NULL, NULL, 0, 0 } /* terminator */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -533,21 +533,31 @@ if (params.mirror)
|
||||||
mirror_name = params.mirror;
|
mirror_name = params.mirror;
|
||||||
|
|
||||||
console.log(mirror_name);
|
console.log(mirror_name);
|
||||||
|
|
||||||
|
|
||||||
function new_ws(urlpath, protocol)
|
/*
|
||||||
{
|
* if using lws-meta to carry the other ws connections, declare the
|
||||||
if (typeof MozWebSocket != "undefined")
|
* parent connection object and start its connection to the server.
|
||||||
return new MozWebSocket(urlpath, protocol);
|
*
|
||||||
|
* 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);
|
document.getElementById("number").textContent = get_appropriate_ws_url(mirror_name);
|
||||||
|
|
||||||
/* dumb increment protocol */
|
/* 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 {
|
try {
|
||||||
socket_di.onopen = function() {
|
socket_di.onopen = function() {
|
||||||
|
@ -571,8 +581,8 @@ document.getElementById("number").textContent = get_appropriate_ws_url(mirror_na
|
||||||
|
|
||||||
var socket_status, jso, s;
|
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 {
|
try {
|
||||||
socket_status.onopen = function() {
|
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) {
|
socket_status.onmessage =function got_packet(msg) {
|
||||||
var s;
|
var s;
|
||||||
|
|
||||||
|
console.log(msg.data);
|
||||||
|
|
||||||
jso = JSON.parse(msg.data);
|
jso = JSON.parse(msg.data);
|
||||||
|
|
||||||
document.getElementById("servinfo").innerHTML =
|
document.getElementById("servinfo").innerHTML =
|
||||||
|
@ -637,7 +649,9 @@ var socket_ot;
|
||||||
|
|
||||||
function ot_open() {
|
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 {
|
try {
|
||||||
socket_ot.onopen = function() {
|
socket_ot.onopen = function() {
|
||||||
|
@ -646,6 +660,7 @@ function ot_open() {
|
||||||
document.getElementById("ot_open_btn").disabled = true;
|
document.getElementById("ot_open_btn").disabled = true;
|
||||||
document.getElementById("ot_close_btn").disabled = false;
|
document.getElementById("ot_close_btn").disabled = false;
|
||||||
document.getElementById("ot_req_close_btn").disabled = false;
|
document.getElementById("ot_req_close_btn").disabled = false;
|
||||||
|
console.log("ot_open.onopen");
|
||||||
}
|
}
|
||||||
|
|
||||||
socket_ot.onclose = function(e){
|
socket_ot.onclose = function(e){
|
||||||
|
@ -680,7 +695,7 @@ function ot_req_close() {
|
||||||
var socket_lm;
|
var socket_lm;
|
||||||
var color = "#000000";
|
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");
|
"lws-mirror-protocol");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Add table
Reference in a new issue