Compare commits
193 commits
v2.2-stabl
...
master
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 | ||
![]() |
3b0066cb3f | ||
![]() |
faa1526b39 | ||
![]() |
632a0acc99 | ||
![]() |
dbd9262ac5 | ||
![]() |
d5f960f14b | ||
![]() |
5106e9141f | ||
![]() |
61cc61817e | ||
![]() |
3077b7776e | ||
![]() |
81d5899c89 | ||
![]() |
a15007269e | ||
![]() |
ffa5898afe | ||
![]() |
6f2a470ee2 | ||
![]() |
e2a926de2f | ||
![]() |
05d74e45dc | ||
![]() |
1b41322c28 | ||
![]() |
9b4fa24909 | ||
![]() |
7262e14dc1 | ||
![]() |
6a89c7e931 | ||
![]() |
ff9a24de1c | ||
![]() |
e4d8acc85a | ||
![]() |
a637d8f41f | ||
![]() |
8f4f692945 | ||
![]() |
0b629d4037 | ||
![]() |
0e222ab084 | ||
![]() |
5939d3a961 | ||
![]() |
55d9037c32 | ||
![]() |
bd23a401f6 | ||
![]() |
47da96664f | ||
![]() |
04830cceef | ||
![]() |
eb7233ae97 | ||
![]() |
34ef9743d2 | ||
![]() |
12a9592426 | ||
![]() |
ede9ad2b13 | ||
![]() |
abc2a5cd2e | ||
![]() |
d6394b6dba | ||
![]() |
c70f6692f8 | ||
![]() |
3ff720ff66 | ||
![]() |
1725332d47 | ||
![]() |
be4efcfe58 | ||
![]() |
31e26a4fab | ||
![]() |
1e762dcde4 | ||
![]() |
581b86efd0 | ||
![]() |
449eec9b54 | ||
![]() |
af718ff5c2 | ||
![]() |
0be9e98aae | ||
![]() |
568aae9c2d | ||
![]() |
02638f6758 | ||
![]() |
37053b3a9c | ||
![]() |
393b38aed9 | ||
![]() |
156363f3de | ||
![]() |
af7f943e05 | ||
![]() |
2ce39fe26c | ||
![]() |
a4f88d543e | ||
![]() |
ce2e74e5e3 | ||
![]() |
978605b39e | ||
![]() |
989ff82ca0 | ||
![]() |
5d1d756106 | ||
![]() |
348887ea53 | ||
![]() |
3ec32b1762 | ||
![]() |
49769a7c24 | ||
![]() |
decbbc506b | ||
![]() |
c28f436098 | ||
![]() |
a369b42910 | ||
![]() |
d12b3df953 | ||
![]() |
3844988b6c | ||
![]() |
a6a68785f7 | ||
![]() |
de12c860db | ||
![]() |
ed92b6dfe7 | ||
![]() |
8f16f92cac | ||
![]() |
3cf570ec52 | ||
![]() |
3198446d3c | ||
![]() |
fbc1ff6e7b | ||
![]() |
b778cc54ca | ||
![]() |
b2f8bc5638 | ||
![]() |
54236bd437 | ||
![]() |
a7def3ce44 | ||
![]() |
aff8d237f8 | ||
![]() |
2790d5b28c | ||
![]() |
5468812946 | ||
![]() |
57e020a826 | ||
![]() |
e304d7bba7 | ||
![]() |
a1210f73af | ||
![]() |
f13db3e722 | ||
![]() |
d1aa92011b | ||
![]() |
6384eb79e0 | ||
![]() |
98218bd6b7 | ||
![]() |
991f6ec644 | ||
![]() |
aeb3397c8f | ||
![]() |
ca6242a1d3 | ||
![]() |
0b9686224d | ||
![]() |
ff151d0710 | ||
![]() |
6018c0519a | ||
![]() |
f58241c4f2 | ||
![]() |
ba9d639792 | ||
![]() |
b4b3da06a1 | ||
![]() |
4adf590e71 | ||
![]() |
8a74348839 | ||
![]() |
47bbb044ad | ||
![]() |
2b9fff73f9 | ||
![]() |
d7d8c081aa | ||
![]() |
19242db55b | ||
![]() |
54c22623ab | ||
![]() |
00081a2b1f | ||
![]() |
6cae994750 | ||
![]() |
a7326fc8b5 | ||
![]() |
36e04f33f5 | ||
![]() |
89212d6668 | ||
![]() |
4ae029c3a1 | ||
![]() |
d1dda25c6d | ||
![]() |
34822f190d | ||
![]() |
30195eb79d | ||
![]() |
7faa71637f | ||
![]() |
00ae90978b | ||
![]() |
422f56c9dc | ||
![]() |
db64bfcefa | ||
![]() |
73e12e7b93 | ||
![]() |
7a0dead82a | ||
![]() |
d58353f98a | ||
![]() |
7aadd14398 | ||
![]() |
92f0200204 | ||
![]() |
a4d23648f7 | ||
![]() |
311e3a585d | ||
![]() |
629e356bb2 | ||
![]() |
73ff23e288 | ||
![]() |
49036d571f | ||
![]() |
ec50ebac12 | ||
![]() |
f84338ac1c | ||
![]() |
c35661c45c | ||
![]() |
9287f7d1b3 | ||
f0c800ada6 | |||
![]() |
2e874dea50 | ||
![]() |
ed27be42c9 | ||
![]() |
e769af41db | ||
![]() |
102d40e6b6 | ||
![]() |
e0572d3bef | ||
![]() |
4198c20920 | ||
![]() |
c1b5c8cabd | ||
![]() |
3c02868408 | ||
![]() |
34842d7492 |
79 changed files with 9233 additions and 1742 deletions
|
@ -11,10 +11,10 @@ env:
|
|||
- LWS_METHOD=noext CMAKE_ARGS="-DLWS_WITHOUT_EXTENSIONS=ON"
|
||||
- LWS_METHOD=libev CMAKE_ARGS="-DLWS_WITH_LIBEV=ON"
|
||||
- LWS_METHOD=noipv6 CMAKE_ARGS="-DLWS_IPV6=OFF"
|
||||
- LWS_METHOD=http2 CMAKE_ARGS="-DLWS_WITH_HTTP2=ON"
|
||||
- LWS_METHOD=nossl CMAKE_ARGS="-DLWS_WITH_SSL=OFF"
|
||||
- LWS_METHOD=nodaemon CMAKE_ARGS="-DLWS_WITHOUT_DAEMONIZE=ON"
|
||||
- LWS_METHOD=cgi CMAKE_ARGS="-DLWS_WITH_CGI=ON"
|
||||
- LWS_METHOD=nologs CMAKE_ARGS="-DLWS_WITH_NO_LOGS=ON"
|
||||
|
||||
os:
|
||||
- linux
|
||||
|
|
166
CMakeLists.txt
166
CMakeLists.txt
|
@ -9,12 +9,12 @@ project(libwebsockets C)
|
|||
set(PACKAGE "libwebsockets")
|
||||
set(CPACK_PACKAGE_NAME "${PACKAGE}")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR "2")
|
||||
set(CPACK_PACKAGE_VERSION_MINOR "2")
|
||||
set(CPACK_PACKAGE_VERSION_PATCH "2")
|
||||
set(CPACK_PACKAGE_VERSION_MINOR "3")
|
||||
set(CPACK_PACKAGE_VERSION_PATCH "0")
|
||||
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
|
||||
set(CPACK_PACKAGE_VENDOR "andy@warmcat.com")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PACKAGE} ${PACKAGE_VERSION}")
|
||||
set(SOVERSION "10")
|
||||
set(SOVERSION "11")
|
||||
if(NOT CPACK_GENERATOR)
|
||||
if(UNIX)
|
||||
set(CPACK_GENERATOR "TGZ")
|
||||
|
@ -75,6 +75,7 @@ option(LWS_USE_WOLFSSL "Use wolfSSL replacement for OpenSSL. When setting this,
|
|||
option(LWS_WITH_ZLIB "Include zlib support (required for extensions)" ON)
|
||||
option(LWS_WITH_LIBEV "Compile with support for libev" OFF)
|
||||
option(LWS_WITH_LIBUV "Compile with support for libuv" OFF)
|
||||
option(LWS_WITH_LIBEVENT "Compile with support for libevent" OFF)
|
||||
option(LWS_USE_BUNDLED_ZLIB "Use bundled zlib version (Windows only)" ${LWS_USE_BUNDLED_ZLIB_DEFAULT})
|
||||
option(LWS_SSL_CLIENT_USE_OS_CA_CERTS "SSL support should make use of the OS-installed CA root certs" ON)
|
||||
option(LWS_WITHOUT_BUILTIN_GETIFADDRS "Don't use the BSD getifaddrs implementation from libwebsockets if it is missing (this will result in a compilation error) ... The default is to assume that your libc provides it. On some systems such as uclibc it doesn't exist." OFF)
|
||||
|
@ -94,10 +95,10 @@ option(LWS_WITH_LATENCY "Build latency measuring code into the library" OFF)
|
|||
option(LWS_WITHOUT_DAEMONIZE "Don't build the daemonization api" ON)
|
||||
option(LWS_IPV6 "Compile with support for ipv6" OFF)
|
||||
option(LWS_UNIX_SOCK "Compile with support for UNIX domain socket" OFF)
|
||||
option(LWS_WITH_HTTP2 "Compile with support for http2" OFF)
|
||||
#option(LWS_WITH_HTTP2 "Compile with support for http2" OFF)
|
||||
option(LWS_SSL_SERVER_WITH_ECDH_CERT "Include SSL server use ECDH certificate" OFF)
|
||||
option(LWS_WITH_CGI "Include CGI (spawn process with network-connected stdin/out/err) APIs" OFF)
|
||||
option(LWS_WITH_HTTP_PROXY "Support for rewriting HTTP proxying" OFF)
|
||||
option(LWS_WITH_HTTP_PROXY "Support for rewriting HTTP proxying (requires libhubbub)" OFF)
|
||||
option(LWS_WITH_LWSWS "Libwebsockets Webserver" OFF)
|
||||
option(LWS_WITH_PLUGINS "Support plugins for protocols and extensions" OFF)
|
||||
option(LWS_WITH_ACCESS_LOG "Support generating Apache-compatible access logs" OFF)
|
||||
|
@ -115,6 +116,9 @@ option(LWS_STATIC_PIC "Build the static version of the library with position-ind
|
|||
option(LWS_WITH_RANGES "Support http ranges (RFC7233)" ON)
|
||||
option(LWS_FALLBACK_GETHOSTBYNAME "Also try to do dns resolution using gethostbyname if getaddrinfo fails" OFF)
|
||||
option(LWS_WITH_ZIP_FOPS "Support serving pre-zipped files" ON)
|
||||
option(LWS_AVOID_SIGPIPE_IGN "Android 7+ seems to need this" OFF)
|
||||
option(LWS_WITH_STATS "Keep statistics of lws internal operations" OFF)
|
||||
option(LWS_WITH_SOCKS5 "Allow use of SOCKS5 proxy on client connections" OFF)
|
||||
|
||||
if (LWS_WITH_LWSWS)
|
||||
message(STATUS "LWS_WITH_LWSWS --> Enabling LWS_WITH_PLUGINS and LWS_WITH_LIBUV")
|
||||
|
@ -165,12 +169,10 @@ endif()
|
|||
|
||||
if (LWS_WITH_ESP32)
|
||||
set(LWS_WITH_SHARED OFF)
|
||||
set(LWS_WITH_SSL OFF)
|
||||
set(LWS_WITH_ZLIB OFF)
|
||||
# set(LWS_WITHOUT_CLIENT ON)
|
||||
set(LWS_WITH_SSL ON)
|
||||
# set(LWS_WITHOUT_CLIENT ON)
|
||||
set(LWS_WITHOUT_TESTAPPS ON)
|
||||
set(LWS_WITHOUT_EXTENSIONS ON)
|
||||
set(LWS_WITHOUT_CLIENT ON)
|
||||
set(LWS_WITH_PLUGINS OFF)
|
||||
set(LWS_WITH_RANGES ON)
|
||||
# this implies no pthreads in the lib
|
||||
|
@ -178,7 +180,7 @@ if (LWS_WITH_ESP32)
|
|||
set(LWS_HAVE_MALLOC 1)
|
||||
set(LWS_HAVE_REALLOC 1)
|
||||
set(LWS_HAVE_GETIFADDRS 1)
|
||||
set(LWS_WITH_ZIP_FOPS 0)
|
||||
set(LWS_WITH_ZIP_FOPS 1)
|
||||
endif()
|
||||
|
||||
|
||||
|
@ -239,6 +241,8 @@ set(LWS_LIBUV_LIBRARIES CACHE PATH "Path to the libuv library")
|
|||
set(LWS_LIBUV_INCLUDE_DIRS CACHE PATH "Path to the libuv include directory")
|
||||
set(LWS_SQLITE3_LIBRARIES CACHE PATH "Path to the sqlite3 library")
|
||||
set(LWS_SQLITE3_INCLUDE_DIRS CACHE PATH "Path to the sqlite3 include directory")
|
||||
set(LWS_LIBEVENT_INCLUDE_DIRS CACHE PATH "Path to the libevent include directory")
|
||||
set(LWS_LIBEVENT_LIBRARIES CACHE PATH "Path to the libevent library")
|
||||
|
||||
|
||||
if (NOT LWS_WITH_SSL)
|
||||
|
@ -303,6 +307,15 @@ if (LWS_WITH_LIBUV)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LIBEVENT)
|
||||
if ("${LWS_LIBEVENT_LIBRARIES}" STREQUAL "" OR "${LWS_LIBEVENT_INCLUDE_DIRS}" STREQUAL "")
|
||||
else()
|
||||
set(LIBEVENT_LIBRARIES ${LWS_LIBEVENT_LIBRARIES})
|
||||
set(LIBEVENT_INCLUDE_DIRS ${LWS_LIBEVENT_INCLUDE_DIRS})
|
||||
set(LIBEVENT_FOUND 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_SQLITE3)
|
||||
if ("${LWS_SQLITE3_LIBRARIES}" STREQUAL "" OR "${LWS_SQLITE3_INCLUDE_DIRS}" STREQUAL "")
|
||||
else()
|
||||
|
@ -362,6 +375,10 @@ if (LWS_WITH_LIBUV)
|
|||
set(LWS_USE_LIBUV 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LIBEVENT)
|
||||
set(LWS_USE_LIBEVENT 1)
|
||||
endif()
|
||||
|
||||
if (LWS_IPV6)
|
||||
set(LWS_USE_IPV6 1)
|
||||
endif()
|
||||
|
@ -375,7 +392,7 @@ if (LWS_WITH_HTTP2)
|
|||
endif()
|
||||
|
||||
if ("${LWS_MAX_SMP}" STREQUAL "")
|
||||
set(LWS_MAX_SMP 32)
|
||||
set(LWS_MAX_SMP 1)
|
||||
endif()
|
||||
|
||||
|
||||
|
@ -453,6 +470,9 @@ CHECK_FUNCTION_EXISTS(snprintf LWS_HAVE_SNPRINTF)
|
|||
CHECK_FUNCTION_EXISTS(_snprintf LWS_HAVE__SNPRINTF)
|
||||
CHECK_FUNCTION_EXISTS(_vsnprintf LWS_HAVE__VSNPRINTF)
|
||||
CHECK_FUNCTION_EXISTS(getloadavg LWS_HAVE_GETLOADAVG)
|
||||
CHECK_FUNCTION_EXISTS(atoll LWS_HAVE_ATOLL)
|
||||
CHECK_FUNCTION_EXISTS(_atoi64 LWS_HAVE__ATOI64)
|
||||
CHECK_FUNCTION_EXISTS(_stat32i64 LWS_HAVE__STAT32I64)
|
||||
|
||||
if (NOT LWS_HAVE_GETIFADDRS)
|
||||
if (LWS_WITHOUT_BUILTIN_GETIFADDRS)
|
||||
|
@ -478,6 +498,9 @@ CHECK_INCLUDE_FILE(sys/stat.h LWS_HAVE_SYS_STAT_H)
|
|||
CHECK_INCLUDE_FILE(sys/types.h LWS_HAVE_SYS_TYPES_H)
|
||||
CHECK_INCLUDE_FILE(unistd.h LWS_HAVE_UNISTD_H)
|
||||
CHECK_INCLUDE_FILE(vfork.h LWS_HAVE_VFORK_H)
|
||||
CHECK_INCLUDE_FILE(sys/capability.h LWS_HAVE_SYS_CAPABILITY_H)
|
||||
|
||||
CHECK_LIBRARY_EXISTS(cap cap_set_flag "" LWS_HAVE_LIBCAP)
|
||||
|
||||
if (LWS_WITH_LIBUV)
|
||||
CHECK_INCLUDE_FILE(uv-version.h LWS_HAVE_UV_VERSION_H)
|
||||
|
@ -494,6 +517,12 @@ set(LWS_HAVE_WORKING_VFORK LWS_HAVE_VFORK)
|
|||
|
||||
CHECK_INCLUDE_FILES("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)
|
||||
|
||||
CHECK_C_SOURCE_COMPILES("#include <stdint.h>
|
||||
int main(void) {
|
||||
intptr_t test = 1;
|
||||
return 0;
|
||||
}" LWS_HAS_INTPTR_T)
|
||||
|
||||
# These don't work Cross...
|
||||
#CHECK_TYPE_SIZE(pid_t PID_T_SIZE)
|
||||
#CHECK_TYPE_SIZE(size_t SIZE_T_SIZE)
|
||||
|
@ -632,6 +661,11 @@ if (LWS_WITH_LIBUV)
|
|||
lib/libuv.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LIBEVENT)
|
||||
list(APPEND SOURCES
|
||||
lib/libevent.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LEJP)
|
||||
list(APPEND SOURCES
|
||||
lib/lejp.c)
|
||||
|
@ -707,7 +741,7 @@ if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR (CMAKE_C_COMPILER_ID
|
|||
endif ()
|
||||
|
||||
if ((CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) AND NOT LWS_WITHOUT_TESTAPPS)
|
||||
if (UNIX)
|
||||
if (UNIX AND LWS_MAX_SMP GREATER 1)
|
||||
# jeez clang understands -pthread but dies if he sees it at link time!
|
||||
# http://stackoverflow.com/questions/2391194/what-is-gs-pthread-equiv-in-clang
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread" )
|
||||
|
@ -946,6 +980,20 @@ if (LWS_WITH_LIBUV)
|
|||
list(APPEND LIB_LIST ${LIBUV_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LIBEVENT)
|
||||
if (NOT LIBEVENT_FOUND)
|
||||
find_path(LIBEVENT_INCLUDE_DIRS NAMES event2/event.h)
|
||||
find_library(LIBEVENT_LIBRARIES NAMES event)
|
||||
if(LIBEVENT_INCLUDE_DIRS AND LIBEVENT_LIBRARIES)
|
||||
set(LIBEVENT_FOUND 1)
|
||||
endif()
|
||||
endif()
|
||||
message("libevent include dir: ${LIBEVENT_INCLUDE_DIRS}")
|
||||
message("libevent libraries: ${LIBEVENT_LIBRARIES}")
|
||||
include_directories("${LIBEVENT_INCLUDE_DIRS}")
|
||||
list(APPEND LIB_LIST ${LIBEVENT_LIBRARIES})
|
||||
endif(LWS_WITH_LIBEVENT)
|
||||
|
||||
if (LWS_WITH_SQLITE3)
|
||||
if (NOT SQLITE3_FOUND)
|
||||
find_path(SQLITE3_INCLUDE_DIRS NAMES sqlite3.h)
|
||||
|
@ -980,6 +1028,12 @@ if (UNIX)
|
|||
list(APPEND LIB_LIST m)
|
||||
endif()
|
||||
|
||||
if (LWS_HAVE_LIBCAP)
|
||||
list(APPEND LIB_LIST cap )
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
# Setup the linking for all libs.
|
||||
foreach (lib ${LWS_LIBRARIES})
|
||||
target_link_libraries(${lib} ${LIB_LIST})
|
||||
|
@ -988,9 +1042,14 @@ endforeach()
|
|||
set (temp ${CMAKE_REQUIRED_LIBRARIES})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${LIB_LIST})
|
||||
CHECK_FUNCTION_EXISTS(SSL_CTX_set1_param LWS_HAVE_SSL_CTX_set1_param)
|
||||
CHECK_FUNCTION_EXISTS(SSL_set_info_callback LWS_HAVE_SSL_SET_INFO_CALLBACK)
|
||||
CHECK_FUNCTION_EXISTS(X509_VERIFY_PARAM_set1_host LWS_HAVE_X509_VERIFY_PARAM_set1_host)
|
||||
if (LWS_WITH_ESP32)
|
||||
set(LWS_HAVE_TLS_CLIENT_METHOD 1)
|
||||
else()
|
||||
CHECK_FUNCTION_EXISTS(TLS_client_method LWS_HAVE_TLS_CLIENT_METHOD)
|
||||
CHECK_FUNCTION_EXISTS(TLSv1_2_client_method LWS_HAVE_TLSV1_2_CLIENT_METHOD)
|
||||
endif()
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${temp})
|
||||
# Generate the lws_config.h that includes all the public compilation settings.
|
||||
configure_file(
|
||||
|
@ -1074,7 +1133,8 @@ if (GENCERTS)
|
|||
COMMAND "${OPENSSL_EXECUTABLE}"
|
||||
req -new -newkey rsa:1024 -days 10000 -nodes -x509 -keyout "${TEST_SERVER_SSL_KEY}" -out "${TEST_SERVER_SSL_CERT}"
|
||||
RESULT_VARIABLE OPENSSL_RETURN_CODE
|
||||
OUTPUT_QUIET ERROR_QUIET)
|
||||
# OUTPUT_QUIET ERROR_QUIET
|
||||
)
|
||||
|
||||
if (OPENSSL_RETURN_CODE)
|
||||
message(WARNING "!!! Failed to generate SSL certificate for Test Server!!!:\nOpenSSL return code = ${OPENSSL_RETURN_CODE}")
|
||||
|
@ -1187,9 +1247,9 @@ if (NOT LWS_WITHOUT_TESTAPPS)
|
|||
create_test_app(test-server "test-server/test-server.c"
|
||||
"test-server/test-server-http.c"
|
||||
"test-server/test-server-dumb-increment.c"
|
||||
"test-server/test-server-mirror.c"
|
||||
"test-server/test-server-status.c"
|
||||
"test-server/test-server-echogen.c")
|
||||
""
|
||||
""
|
||||
"")
|
||||
if (UNIX)
|
||||
create_test_app(test-fuzxy "test-server/fuzxy.c"
|
||||
""
|
||||
|
@ -1198,14 +1258,14 @@ if (NOT LWS_WITHOUT_TESTAPPS)
|
|||
""
|
||||
"")
|
||||
endif()
|
||||
if (UNIX AND NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")))
|
||||
if (UNIX AND NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) AND LWS_MAX_SMP GREATER 1)
|
||||
create_test_app(test-server-pthreads
|
||||
"test-server/test-server-pthreads.c"
|
||||
"test-server/test-server-http.c"
|
||||
"test-server/test-server-dumb-increment.c"
|
||||
"test-server/test-server-mirror.c"
|
||||
"test-server/test-server-status.c"
|
||||
"test-server/test-server-echogen.c")
|
||||
""
|
||||
""
|
||||
"")
|
||||
endif()
|
||||
if (NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
|
||||
AND LWS_WITH_LIBEV)
|
||||
|
@ -1213,19 +1273,31 @@ if (NOT LWS_WITHOUT_TESTAPPS)
|
|||
"test-server/test-server-libev.c"
|
||||
"test-server/test-server-http.c"
|
||||
"test-server/test-server-dumb-increment.c"
|
||||
"test-server/test-server-mirror.c"
|
||||
"test-server/test-server-status.c"
|
||||
"test-server/test-server-echogen.c")
|
||||
""
|
||||
""
|
||||
"")
|
||||
# libev generates a big mess of warnings with gcc, maintainers blame gcc
|
||||
set_source_files_properties( test-server/test-server-libev.c PROPERTIES COMPILE_FLAGS "-Wno-error" )
|
||||
endif()
|
||||
if (NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
|
||||
AND LWS_WITH_LIBUV)
|
||||
create_test_app(test-server-libuv
|
||||
"test-server/test-server-libuv.c"
|
||||
"test-server/test-server-http.c"
|
||||
""
|
||||
""
|
||||
""
|
||||
"")
|
||||
endif()
|
||||
if (NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
|
||||
AND LWS_WITH_LIBEVENT)
|
||||
create_test_app(test-server-libevent
|
||||
"test-server/test-server-libevent.c"
|
||||
"test-server/test-server-http.c"
|
||||
"test-server/test-server-dumb-increment.c"
|
||||
"test-server/test-server-mirror.c"
|
||||
"test-server/test-server-status.c"
|
||||
"test-server/test-server-echogen.c")
|
||||
""
|
||||
""
|
||||
"")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@ -1236,9 +1308,9 @@ if (NOT LWS_WITHOUT_TESTAPPS)
|
|||
create_test_app(test-server-extpoll "test-server/test-server.c"
|
||||
"test-server/test-server-http.c"
|
||||
"test-server/test-server-dumb-increment.c"
|
||||
"test-server/test-server-mirror.c"
|
||||
"test-server/test-server-status.c"
|
||||
"test-server/test-server-echogen.c")
|
||||
""
|
||||
""
|
||||
"")
|
||||
# Set defines for this executable only.
|
||||
set_property(
|
||||
TARGET test-server-extpoll
|
||||
|
@ -1371,6 +1443,8 @@ if (NOT LWS_WITHOUT_TESTAPPS)
|
|||
endmacro()
|
||||
|
||||
|
||||
create_plugin(protocol_lws_meta
|
||||
"plugins/protocol_lws_meta.c" "" "")
|
||||
create_plugin(protocol_dumb_increment
|
||||
"plugins/protocol_dumb_increment.c" "" "")
|
||||
create_plugin(protocol_lws_mirror
|
||||
|
@ -1495,6 +1569,26 @@ Cflags: -I\${includedir}"
|
|||
|
||||
install(FILES "${PROJECT_BINARY_DIR}/libwebsockets.pc"
|
||||
DESTINATION lib${LIB_SUFFIX}/pkgconfig)
|
||||
|
||||
file(WRITE "${PROJECT_BINARY_DIR}/libwebsockets_static.pc"
|
||||
"prefix=\"${CMAKE_INSTALL_PREFIX}\"
|
||||
exec_prefix=\${prefix}
|
||||
libdir=\${exec_prefix}/lib${LIB_SUFFIX}
|
||||
includedir=\${prefix}/include
|
||||
|
||||
Name: libwebsockets_static
|
||||
Description: Websockets server and client static library
|
||||
Version: ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}
|
||||
|
||||
Libs: -L\${libdir} -lwebsockets_static
|
||||
Libs.private:
|
||||
Cflags: -I\${includedir}"
|
||||
)
|
||||
|
||||
install(FILES "${PROJECT_BINARY_DIR}/libwebsockets_static.pc"
|
||||
DESTINATION lib${LIB_SUFFIX}/pkgconfig)
|
||||
|
||||
|
||||
endif(UNIX)
|
||||
|
||||
#
|
||||
|
@ -1564,8 +1658,8 @@ set(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "Libraries")
|
|||
set(CPACK_COMPONENT_DEV_DISPLAY_NAME "Development files")
|
||||
|
||||
# Install test apps.
|
||||
if (NOT LWS_WITHOUT_TESTAPPS AND NOT LWS_WITHOUT_CLIENT)
|
||||
install(TARGETS test-client ${TEST_APP_LIST}
|
||||
if (NOT LWS_WITHOUT_TESTAPPS)
|
||||
install(TARGETS ${TEST_APP_LIST}
|
||||
RUNTIME DESTINATION ${LWS_INSTALL_EXAMPLES_DIR}
|
||||
COMPONENT examples)
|
||||
set(CPACK_COMPONENT_EXAMPLES_DISPLAY_NAME "Example files")
|
||||
|
@ -1690,6 +1784,7 @@ message(" LWS_WITH_LATENCY = ${LWS_WITH_LATENCY}")
|
|||
message(" LWS_WITHOUT_DAEMONIZE = ${LWS_WITHOUT_DAEMONIZE}")
|
||||
message(" LWS_USE_LIBEV = ${LWS_USE_LIBEV}")
|
||||
message(" LWS_USE_LIBUV = ${LWS_USE_LIBUV}")
|
||||
message(" LWS_USE_LIBEVENT = ${LWS_USE_LIBEVENT}")
|
||||
message(" LWS_IPV6 = ${LWS_IPV6}")
|
||||
message(" LWS_UNIX_SOCK = ${LWS_UNIX_SOCK}")
|
||||
message(" LWS_WITH_HTTP2 = ${LWS_WITH_HTTP2}")
|
||||
|
@ -1712,6 +1807,15 @@ message(" LWS_WITH_RANGES = ${LWS_WITH_RANGES}")
|
|||
message(" LWS_PLAT_OPTEE = ${LWS_PLAT_OPTEE}")
|
||||
message(" LWS_WITH_ESP32 = ${LWS_WITH_ESP32}")
|
||||
message(" LWS_WITH_ZIP_FOPS = ${LWS_WITH_ZIP_FOPS}")
|
||||
message(" LWS_AVOID_SIGPIPE_IGN = ${LWS_AVOID_SIGPIPE_IGN}")
|
||||
message(" LWS_WITH_STATS = ${LWS_WITH_STATS}")
|
||||
message(" LWS_WITH_SOCKS5 = ${LWS_WITH_SOCKS5}")
|
||||
message(" LWS_HAVE_SYS_CAPABILITY_H = ${LWS_HAVE_SYS_CAPABILITY_H}")
|
||||
message(" LWS_HAVE_LIBCAP = ${LWS_HAVE_LIBCAP}")
|
||||
message(" LWS_HAVE_ATOLL = ${LWS_HAVE_ATOLL}")
|
||||
message(" LWS_HAVE__ATOI64 = ${LWS_HAVE__ATOI64}")
|
||||
message(" LWS_HAVE_STAT32I64 = ${LWS_HAVE_STAT32I64}")
|
||||
message(" LWS_HAS_INTPTR_T = ${LWS_HAS_INTPTR_T}")
|
||||
|
||||
message("---------------------------------------------------------------------")
|
||||
|
||||
|
|
33
Kconfig
33
Kconfig
|
@ -1,9 +1,32 @@
|
|||
menu "Libwebsockets"
|
||||
|
||||
config LWS
|
||||
bool "Enable Libwebsockets"
|
||||
default n
|
||||
help
|
||||
Enable Libwebsockets Library
|
||||
config LWS_MODEL_NAME
|
||||
string "Model name of device firmware is for"
|
||||
default "lws"
|
||||
|
||||
config LWS_IS_FACTORY_APPLICATION
|
||||
bool "Is this application is designed for the FACTORY flash slot"
|
||||
default "n"
|
||||
|
||||
config LWS_OTA_SERVER_FQDN
|
||||
depends on LWS_IS_FACTORY_APPLICATION
|
||||
string "Domain name of OTA update server, eg, warmcat.com"
|
||||
default ""
|
||||
|
||||
config LWS_OTA_SERVER_BASE_URL
|
||||
depends on LWS_IS_FACTORY_APPLICATION
|
||||
string "Base URL on OTA update server, eg, /esp32-ota (model is added)"
|
||||
default "/esp32-ota"
|
||||
|
||||
config LWS_OTA_SERVER_UPLOAD_USER
|
||||
depends on LWS_IS_FACTORY_APPLICATION
|
||||
string "User to scp to upload server with"
|
||||
default "root"
|
||||
|
||||
config LWS_OTA_SERVER_UPLOAD_PATH
|
||||
depends on LWS_IS_FACTORY_APPLICATION
|
||||
string "Path served in upload server (eg, \"/var/www/libwebsockets.org\""
|
||||
default "/var/www/libwebsockets.org"
|
||||
|
||||
endmenu
|
||||
|
||||
|
|
|
@ -122,12 +122,25 @@ and libnsl, and only builds in 64bit mode.
|
|||
$ make
|
||||
```
|
||||
|
||||
@section lcap Linux Capabilities
|
||||
|
||||
On Linux, lws now lets you retain selected root capabilities when dropping
|
||||
privileges. If libcap-dev or similar package is installed providing
|
||||
sys/capabilities.h, and libcap or similar package is installed providing
|
||||
libcap.so, CMake will enable the capability features.
|
||||
|
||||
The context creation info struct .caps[] and .count_caps members can then
|
||||
be set by user code to enable selected root capabilities to survive the
|
||||
transition to running under an unprivileged user.
|
||||
|
||||
@section cmq Quirk of cmake
|
||||
|
||||
When changing cmake options, for some reason the only way to get it to see the
|
||||
changes sometimes is delete the contents of your build directory and do the
|
||||
cmake from scratch.
|
||||
|
||||
deleting build/CMakeCache.txt may be enough.
|
||||
|
||||
|
||||
@section cmw Building on Windows (Visual Studio)
|
||||
|
||||
|
@ -176,7 +189,7 @@ cmake from scratch.
|
|||
|
||||
2. Fix up MinGW headers
|
||||
|
||||
a) (32-bit) Add the following lines to C:\MinGW\include\winsock2.h:
|
||||
a) If still necessary, sdd the following lines to C:\MinGW\include\winsock2.h:
|
||||
```
|
||||
#if(_WIN32_WINNT >= 0x0600)
|
||||
|
||||
|
@ -193,16 +206,15 @@ cmake from scratch.
|
|||
#endif // (_WIN32_WINNT >= 0x0600)
|
||||
```
|
||||
|
||||
(64 bit) Update crtdefs.h line 47 to say:
|
||||
Update crtdefs.h line 47 to say:
|
||||
|
||||
```
|
||||
typedef __int64 ssize_t;
|
||||
```
|
||||
|
||||
b) Create C:\MinGW\include\mstcpip.h and copy and paste the content from following link into it:
|
||||
|
||||
(32-bit) http://wine-unstable.sourcearchive.com/documentation/1.1.32/mstcpip_8h-source.html
|
||||
(64-bit) https://github.com/Alexpux/mingw-w64/blob/master/mingw-w64-headers/include/mstcpip.h
|
||||
|
||||
https://github.com/Alexpux/mingw-w64/blob/master/mingw-w64-headers/include/mstcpip.h
|
||||
|
||||
3. Install CMake 2.6 or greater: http://cmake.org/cmake/resources/software.html
|
||||
|
||||
|
|
|
@ -568,6 +568,32 @@ ECDH Certs are now supported. Enable the CMake option
|
|||
|
||||
to build in support and select it at runtime.
|
||||
|
||||
@section sslinfo SSL info callbacks
|
||||
|
||||
OpenSSL allows you to receive callbacks for various events defined in a
|
||||
bitmask in openssl/ssl.h. The events include stuff like TLS Alerts.
|
||||
|
||||
By default, lws doesn't register for these callbacks.
|
||||
|
||||
However if you set the info.ssl_info_event_mask to nonzero (ie, set some
|
||||
of the bits in it like `SSL_CB_ALERT` at vhost creation time, then
|
||||
connections to that vhost will call back using LWS_CALLBACK_SSL_INFO
|
||||
for the wsi, and the `in` parameter will be pointing to a struct of
|
||||
related args:
|
||||
|
||||
```
|
||||
struct lws_ssl_info {
|
||||
int where;
|
||||
int ret;
|
||||
};
|
||||
```
|
||||
|
||||
The default callback handler in lws has a handler for LWS_CALLBACK_SSL_INFO
|
||||
which prints the related information, You can test it using the switch
|
||||
-S -s on `libwebsockets-test-server-v2.0`.
|
||||
|
||||
Returning nonzero from the callback will close the wsi.
|
||||
|
||||
@section smp SMP / Multithreaded service
|
||||
|
||||
SMP support is integrated into LWS without any internal threading. It's
|
||||
|
@ -862,6 +888,40 @@ This allocation is only deleted / replaced when the connection accesses a
|
|||
URL region with a different protocol (or the default protocols[0] if no
|
||||
CALLBACK area matches it).
|
||||
|
||||
@section BINDTODEV SO_BIND_TO_DEVICE
|
||||
|
||||
The .bind_iface flag in the context / vhost creation struct lets you
|
||||
declare that you want all traffic for listen and transport on that
|
||||
vhost to be strictly bound to the network interface named in .iface.
|
||||
|
||||
This Linux-only feature requires SO_BIND_TO_DEVICE, which in turn
|
||||
requires CAP_NET_RAW capability... root has this capability.
|
||||
|
||||
However this feature needs to apply the binding also to accepted
|
||||
sockets during normal operation, which implies the server must run
|
||||
the whole time as root.
|
||||
|
||||
You can avoid this by using the Linux capabilities feature to have
|
||||
the unprivileged user inherit just the CAP_NET_RAW capability.
|
||||
|
||||
You can confirm this with the test server
|
||||
|
||||
|
||||
```
|
||||
$ sudo /usr/local/bin/libwebsockets-test-server -u agreen -i eno1 -k
|
||||
```
|
||||
|
||||
The part that ensures the capability is inherited by the unprivileged
|
||||
user is
|
||||
|
||||
```
|
||||
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
|
||||
info.caps[0] = CAP_NET_RAW;
|
||||
info.count_caps = 1;
|
||||
#endif
|
||||
```
|
||||
|
||||
|
||||
@section dim Dimming webpage when connection lost
|
||||
|
||||
The lws test plugins' html provides useful feedback on the webpage about if it
|
||||
|
|
23
README.esp32.md
Normal file
23
README.esp32.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
ESP32 Support
|
||||
=============
|
||||
|
||||
Lws provides a "factory" application
|
||||
|
||||
https://github.com/warmcat/lws-esp32-factory
|
||||
|
||||
and a test application which implements the generic lws server test apps
|
||||
|
||||
https://github.com/warmcat/lws-esp32-test-server-demos
|
||||
|
||||
The behaviours of the generic factory are are quite rich, and cover uploading SSL certs through factory and user configuration, AP selection and passphrase entry, and managing a switch to allow the user to force entry to user setup mode at boot subsequently.
|
||||
|
||||
The factory app comes with partitioning for a 1MB factory partition containing that app and data, and a single 2.9MB OTA partition containing the main app.
|
||||
|
||||
The factory app is able to do OTA updates for both the factory and OTA partition slots; updating the factory slot first writes the new image to the OTA slot and copies it into place at the next boot, after which the user can reload the OTA slot.
|
||||
|
||||
State|Image|AP SSID|Port|URL|Mode
|
||||
---|---|---|---|---|---
|
||||
Factory Reset or Uninitialized|Factory|AP: ESP_012345|80|http://192.168.4.1|factory.html - to set certificates and serial
|
||||
User configuration|Factory|AP: config-model-serial|443|https://192.168.4.1|index.html - user set up his AP information
|
||||
Operation|OTA|Station only|443|https://model-serial.local|OTA application
|
||||
|
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.
|
|
@ -292,6 +292,20 @@ Mount protocols are used to control what kind of translation happens
|
|||
```
|
||||
would cause the url /git/myrepo to pass "myrepo" to the cgi /var/www/cgi-bin/cgit and send the results to the client.
|
||||
|
||||
- http:// or https:// these perform reverse proxying, serving the remote origin content from the mountpoint. Eg
|
||||
|
||||
```
|
||||
{
|
||||
"mountpoint": "/proxytest",
|
||||
"origin": "https://libwebsockets.org"
|
||||
}
|
||||
```
|
||||
|
||||
This will cause your local url `/proxytest` to serve content fetched from libwebsockets.org over ssl; whether it's served from your server using ssl is unrelated and depends how you configured your local server. Notice if you will use the proxying feature, `LWS_WITH_HTTP_PROXY` is required to be enabled at cmake, and for `https` proxy origins, your lwsws configuration must include `"init-ssl": "1"` and the vhost with the proxy mount must have `"enable-client-ssl": "1"`, even if you are not using ssl to serve.
|
||||
|
||||
`/proxytest/abc`, or `/proxytest/abc?def=ghi` etc map to the origin + the part past `/proxytest`, so links and img src urls etc work as do all urls under the origin path.
|
||||
|
||||
In addition link and src urls in the document are rewritten so / or the origin url part are rewritten to the mountpoint part.
|
||||
|
||||
|
||||
@section lwswsomo Lwsws Other mount options
|
||||
|
@ -562,3 +576,26 @@ Prepare the log directory like this
|
|||
sudo mkdir /var/log/lwsws
|
||||
sudo chmod 700 /var/log/lwsws
|
||||
```
|
||||
|
||||
@section lwswsgdb Debugging lwsws with gdb
|
||||
|
||||
Hopefully you won't need to debug lwsws itself, but you may want to debug your plugins. start lwsws like this to have everything running under gdb
|
||||
|
||||
```
|
||||
sudo gdb -ex "set follow-fork-mode child" -ex "run" --args /usr/local/bin/lwsws
|
||||
|
||||
```
|
||||
|
||||
this will give nice backtraces in lwsws itself and in plugins, if they were built with symbols.
|
||||
|
||||
@section lwswsvgd Running lwsws under valgrind
|
||||
|
||||
You can just run lwsws under galgrind as usual and get valid results. However the results / analysis part of valgrind runs
|
||||
after the plugins have removed themselves, this means valgrind backtraces into plugin code is opaque, without
|
||||
source-level info because the dynamic library is gone.
|
||||
|
||||
There's a simple workaround, use LD_PRELOAD=<plugin.so> before running lwsws, this has the loader bring the plugin
|
||||
in before executing lwsws as if it was a direct dependency. That means it's still mapped until the whole process
|
||||
exits after valgtind has done its thing.
|
||||
|
||||
|
||||
|
|
14
README.md
14
README.md
|
@ -5,10 +5,16 @@
|
|||
libwebsockets
|
||||
-------------
|
||||
|
||||
| News |
|
||||
------
|
||||
| ESP32 is now supported in lws! https://libwebsockets.org/lws-api-doc-master/html/md_README_8build.html |
|
||||
| v2.2 is out... see the changelog https://github.com/warmcat/libwebsockets/blob/v2.2-stable/changelog |
|
||||
News
|
||||
----
|
||||
|
||||
v2.3 is out... see the changelog https://github.com/warmcat/libwebsockets/blob/v2.3-stable/changelog
|
||||
|
||||
ESP32 is now supported in lws! Download the
|
||||
|
||||
- factory https://github.com/warmcat/lws-esp32-factory and
|
||||
- test server app https://github.com/warmcat/lws-esp32-test-server-demos
|
||||
|
||||
|
||||
This is the libwebsockets C library for lightweight websocket clients and
|
||||
servers. For support, visit
|
||||
|
|
|
@ -103,6 +103,13 @@ same.
|
|||
[test-server.c](test-server/test-server.c) is all that is needed to use libwebsockets for
|
||||
serving both the script html over http and websockets.
|
||||
|
||||
@section lwstsdynvhost Dynamic Vhosts
|
||||
|
||||
You can send libwebsockets-test-server or libwebsockets-test-server-v2.0 a SIGUSR1
|
||||
to toggle the creation and destruction of an identical second vhost on port + 1.
|
||||
|
||||
This is intended as a test and demonstration for how to bring up and remove
|
||||
vhosts dynamically.
|
||||
|
||||
@section wscl Testing websocket client support
|
||||
|
||||
|
|
|
@ -22,8 +22,8 @@ install:
|
|||
- mkdir c:\assets\libuv
|
||||
- 7z x -oc:\assets\libuv win-libuv.zip
|
||||
# - appveyor DownloadFile https://slproweb.com/download/Win32OpenSSL-1_0_2h.exe
|
||||
- appveyor DownloadFile https://libwebsockets.org:444/Win32OpenSSL-1_0_2h.exe
|
||||
- Win32OpenSSL-1_0_2h.exe /silent /verysilent /sp- /suppressmsgboxes
|
||||
# - appveyor DownloadFile https://libwebsockets.org:444/Win32OpenSSL-1_0_2L.exe
|
||||
# - Win32OpenSSL-1_0_2L.exe /silent /verysilent /sp- /suppressmsgboxes
|
||||
- appveyor DownloadFile https://libwebsockets.org:444/nsis-3.0rc1-setup.exe
|
||||
- cmd /c start /wait nsis-3.0rc1-setup.exe /S /D=C:\nsis
|
||||
- appveyor DownloadFile https://libwebsockets.org:444/sqlite-dll-win32-x86-3130000.zip
|
||||
|
@ -51,8 +51,8 @@ artifacts:
|
|||
name: lws.zip
|
||||
type: Zip
|
||||
|
||||
cache:
|
||||
- C:\OpenSSL-Win32
|
||||
#cache:
|
||||
# - C:\OpenSSL-Win32
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
|
|
@ -6,7 +6,7 @@ N=1
|
|||
OS=`uname`
|
||||
|
||||
for i in '1.1.1' '1.1.2' '1.1.3' '1.1.4' '1.1.5' '1.1.6' '1.1.7' '1.1.8' '1.2.1' '1.2.2' '1.2.3' '1.2.4' '1.2.5' '1.2.6' '1.2.7' '1.2.8' '2.1' '2.2' '2.3' '2.4' '2.5' '2.6' '2.7' '2.8' '2.9' '2.10' '2.11' '3.1' '3.2' '3.3' '3.4' '3.5' '3.6' '3.7' '4.1.1' '4.1.2' '4.1.3' '4.1.4' '4.1.5' '4.2.1' '4.2.2' '4.2.3' '4.2.4' '4.2.5' '5.1' '5.2' '5.3' '5.4' '5.5' '5.6' '5.7' '5.8' '5.9' '5.10' '5.11' '5.12' '5.13' '5.14' '5.15' '5.16' '5.17' '5.18' '5.19' '5.20' '6.1.1' '6.1.2' '6.1.3' '6.2.1' '6.2.2' '6.2.3' '6.2.4' '6.3.1' '6.3.2' '6.4.1' '6.4.2' '6.4.3' '6.4.4' '6.5.1' '6.5.2' '6.5.3' '6.5.4' '6.5.5' '6.6.1' '6.6.2' '6.6.3' '6.6.4' '6.6.5' '6.6.6' '6.6.7' '6.6.8' '6.6.9' '6.6.10' '6.6.11' '6.7.1' '6.7.2' '6.7.3' '6.7.4' '6.8.1' '6.8.2' '6.9.1' '6.9.2' '6.9.3' '6.9.4' '6.10.1' '6.10.2' '6.10.3' '6.11.1' '6.11.2' '6.11.3' '6.11.4' '6.11.5' '6.12.1' '6.12.2' '6.12.3' '6.12.4' '6.12.5' '6.12.6' '6.12.7' '6.12.8' '6.13.1' '6.13.2' '6.13.3' '6.13.4' '6.13.5' '6.14.1' '6.14.2' '6.14.3' '6.14.4' '6.14.5' '6.14.6' '6.14.7' '6.14.8' '6.14.9' '6.14.10' '6.15.1' '6.16.1' '6.16.2' '6.16.3' '6.17.1' '6.17.2' '6.17.3' '6.17.4' '6.17.5' '6.18.1' '6.18.2' '6.18.3' '6.18.4' '6.18.5' '6.19.1' '6.19.2' '6.19.3' '6.19.4' '6.19.5' '6.20.1' '6.20.2' '6.20.3' '6.20.4' '6.20.5' '6.20.6' '6.20.7' '6.21.1' '6.21.2' '6.21.3' '6.21.4' '6.21.5' '6.21.6' '6.21.7' '6.21.8' '6.22.1' '6.22.2' '6.22.3' '6.22.4' '6.22.5' '6.22.6' '6.22.7' '6.22.8' '6.22.9' '6.22.10' '6.22.11' '6.22.12' '6.22.13' '6.22.14' '6.22.15' '6.22.16' '6.22.17' '6.22.18' '6.22.19' '6.22.20' '6.22.21' '6.22.22' '6.22.23' '6.22.24' '6.22.25' '6.22.26' '6.22.27' '6.22.28' '6.22.29' '6.22.30' '6.22.31' '6.22.32' '6.22.33' '6.22.34' '6.23.1' '6.23.2' '6.23.3' '6.23.4' '6.23.5' '6.23.6' '6.23.7' '7.1.1' '7.1.2' '7.1.3' '7.1.4' '7.1.5' '7.1.6' '7.3.1' '7.3.2' '7.3.3' '7.3.4' '7.3.5' '7.3.6' '7.5.1' '7.7.1' '7.7.2' '7.7.3' '7.7.4' '7.7.5' '7.7.6' '7.7.7' '7.7.8' '7.7.9' '7.7.10' '7.7.11' '7.7.12' '7.7.13' '7.9.1' '7.9.2' '7.9.3' '7.9.4' '7.9.5' '7.9.6' '7.9.7' '7.9.8' '7.9.9' '7.9.10' '7.9.11' '7.9.12' '7.9.13' '7.13.1' '7.13.2' '9.1.1' '9.1.2' '9.1.3' '9.1.4' '9.1.5' '9.1.6' '9.2.1' '9.2.2' '9.2.3' '9.2.4' '9.2.5' '9.2.6' '9.3.1' '9.3.2' '9.3.3' '9.3.4' '9.3.5' '9.3.6' '9.3.7' '9.3.8' '9.3.9' '9.4.1' '9.4.2' '9.4.3' '9.4.4' '9.4.5' '9.4.6' '9.4.7' '9.4.8' '9.4.9' '9.5.1' '9.5.2' '9.5.3' '9.5.4' '9.5.5' '9.5.6' '9.6.1' '9.6.2' '9.6.3' '9.6.4' '9.6.5' '9.6.6' '9.7.1' '9.7.2' '9.7.3' '9.7.4' '9.7.5' '9.7.6' '9.8.1' '9.8.2' '9.8.3' '9.8.4' '9.8.5' '9.8.6' '10.1.1' '12.1.1' '12.1.2' '12.1.3' '12.1.4' '12.1.5' '12.1.6' '12.1.7' '12.1.8' '12.1.9' '12.1.10' '12.1.11' '12.1.12' '12.1.13' '12.1.14' '12.1.15' '12.1.16' '12.1.17' '12.1.18' '12.2.1' '12.2.2' '12.2.3' '12.2.4' '12.2.5' '12.2.6' '12.2.7' '12.2.8' '12.2.9' '12.2.10' '12.2.11' '12.2.12' '12.2.13' '12.2.14' '12.2.15' '12.2.16' '12.2.17' '12.2.18' '12.3.1' '12.3.2' '12.3.3' '12.3.4' '12.3.5' '12.3.6' '12.3.7' '12.3.8' '12.3.9' '12.3.10' '12.3.11' '12.3.12' '12.3.13' '12.3.14' '12.3.15' '12.3.16' '12.3.17' '12.3.18' '12.4.1' '12.4.2' '12.4.3' '12.4.4' '12.4.5' '12.4.6' '12.4.7' '12.4.8' '12.4.9' '12.4.10' '12.4.11' '12.4.12' '12.4.13' '12.4.14' '12.4.15' '12.4.16' '12.4.17' '12.4.18' '12.5.1' '12.5.2' '12.5.3' '12.5.4' '12.5.5' '12.5.6' '12.5.7' '12.5.8' '12.5.9' '12.5.10' '12.5.11' '12.5.12' '12.5.13' '12.5.14' '12.5.15' '12.5.16' '12.5.17' '12.5.18' '13.1.1' '13.1.2' '13.1.3' '13.1.4' '13.1.5' '13.1.6' '13.1.7' '13.1.8' '13.1.9' '13.1.10' '13.1.11' '13.1.12' '13.1.13' '13.1.14' '13.1.15' '13.1.16' '13.1.17' '13.1.18' '13.2.1' '13.2.2' '13.2.3' '13.2.4' '13.2.5' '13.2.6' '13.2.7' '13.2.8' '13.2.9' '13.2.10' '13.2.11' '13.2.12' '13.2.13' '13.2.14' '13.2.15' '13.2.16' '13.2.17' '13.2.18' '13.3.1' '13.3.2' '13.3.3' '13.3.4' '13.3.5' '13.3.6' '13.3.7' '13.3.8' '13.3.9' '13.3.10' '13.3.11' '13.3.12' '13.3.13' '13.3.14' '13.3.15' '13.3.16' '13.3.17' '13.3.18' '13.4.1' '13.4.2' '13.4.3' '13.4.4' '13.4.5' '13.4.6' '13.4.7' '13.4.8' '13.4.9' '13.4.10' '13.4.11' '13.4.12' '13.4.13' '13.4.14' '13.4.15' '13.4.16' '13.4.17' '13.4.18' '13.5.1' '13.5.2' '13.5.3' '13.5.4' '13.5.5' '13.5.6' '13.5.7' '13.5.8' '13.5.9' '13.5.10' '13.5.11' '13.5.12' '13.5.13' '13.5.14' '13.5.15' '13.5.16' '13.5.17' '13.5.18' '13.6.1' '13.6.2' '13.6.3' '13.6.4' '13.6.5' '13.6.6' '13.6.7' '13.6.8' '13.6.9' '13.6.10' '13.6.11' '13.6.12' '13.6.13' '13.6.14' '13.6.15' '13.6.16' '13.6.17' '13.6.18' '13.7.1' '13.7.2' '13.7.3' '13.7.4' '13.7.5' '13.7.6' '13.7.7' '13.7.8' '13.7.9' '13.7.10' '13.7.11' '13.7.12' '13.7.13' '13.7.14' '13.7.15' '13.7.16' '13.7.17' '13.7.18' ; do
|
||||
libwebsockets-test-echo --client localhost --port 9001 -u "/runCase?case=$N&agent=libwebsockets" -v -n 1 &
|
||||
libwebsockets-test-echo --client 127.0.0.1 --port 9001 -u "/runCase?case=$N&agent=libwebsockets" -v -n 1 &
|
||||
|
||||
C=99
|
||||
while [ $C -gt 8 ] ; do
|
||||
|
|
37
changelog
37
changelog
|
@ -1,6 +1,43 @@
|
|||
Changelog
|
||||
---------
|
||||
|
||||
v2.3.0
|
||||
======
|
||||
|
||||
- ESP32 OpenSSL support for client and server
|
||||
|
||||
- ESP32 4 x WLAN credential slots may be configured
|
||||
|
||||
- Libevent event loop support
|
||||
|
||||
- SOCKS5 proxy support
|
||||
|
||||
- lws_meta protocol for websocket connection multiplexing
|
||||
|
||||
- lws_vhost_destroy() added... allows dynamic removal of listening
|
||||
vhosts. Vhosts with shared listen sockets adopt the listen socket
|
||||
automatically if the owner is destroyed.
|
||||
|
||||
- IPv6 on Windows
|
||||
|
||||
- Improved CGI handling suitable for general CGI scripting, eg, PHP
|
||||
|
||||
- Convert even the "old style" test servers to use statically included
|
||||
plugin sources
|
||||
|
||||
- LWS_WITH_STATS cmake option dumps resource usage and timing information
|
||||
every few seconds to debug log, including latency information about
|
||||
delay from asking for writeable callback to getting it
|
||||
|
||||
- Large (> 2GB) files may be served
|
||||
|
||||
- LWS_WITH_HTTP_PROXY Cmake option adds proxying mounts
|
||||
|
||||
- Workaround for libev build by disabling -Werror on the test app
|
||||
|
||||
- HTTP2 support disabled since no way to serve websockets on it
|
||||
|
||||
|
||||
v2.2.0
|
||||
======
|
||||
|
||||
|
|
19
component.mk
19
component.mk
|
@ -1,4 +1,4 @@
|
|||
COMPONENT_ADD_INCLUDEDIRS := ../../../../../../../../../$(COMPONENT_BUILD_DIR)/include
|
||||
COMPONENT_ADD_INCLUDEDIRS := ../../../../../../../../../../../../../../../../../../$(COMPONENT_BUILD_DIR)/include
|
||||
|
||||
COMPONENT_OWNBUILDTARGET:= 1
|
||||
|
||||
|
@ -10,21 +10,26 @@ CROSS_PATH:= $(shell dirname $(CROSS_PATH1) )/..
|
|||
# -DOPENSSL_LIBRARIES="${PWD}/../../boringssl/build/ssl/libssl.a;${PWD}/../../boringssl/build/crypto/libcrypto.a" \
|
||||
# -DOPENSSL_INCLUDE_DIRS="${PWD}/../../boringssl/include" \
|
||||
|
||||
# -DNDEBUG=1 after cflags
|
||||
# -DOPENSSL_LIBRARIES=x \
|
||||
# -DCOMPONENT_PATH=$(COMPONENT_PATH) \
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
cd $(COMPONENT_BUILD_DIR) ; \
|
||||
echo "doing lws cmake" ; \
|
||||
cmake $(COMPONENT_PATH) -DLWS_C_FLAGS="$(CFLAGS)" \
|
||||
cmake $(COMPONENT_PATH) -DLWS_C_FLAGS="$(CFLAGS) -DNDEBUG=1" \
|
||||
-DIDF_PATH=$(IDF_PATH) \
|
||||
-DCROSS_PATH=$(CROSS_PATH) \
|
||||
-DCOMPONENT_PATH=$(COMPONENT_PATH) \
|
||||
-DBUILD_DIR_BASE=$(BUILD_DIR_BASE) \
|
||||
-DCMAKE_TOOLCHAIN_FILE=$(COMPONENT_PATH)/cross-esp32.cmake \
|
||||
-DCMAKE_BUILD_TYPE=RELEASE \
|
||||
-DLWS_WITH_NO_LOGS=0 \
|
||||
-DOPENSSL_INCLUDE_DIR=${COMPONENT_PATH}/../openssl/include \
|
||||
-DOPENSSL_LIBRARIES=x \
|
||||
-DOPENSSL_INCLUDE_DIR=${IDF_PATH}/components/openssl/include \
|
||||
-DLWS_WITH_STATS=0 \
|
||||
-DZLIB_LIBRARY=$(BUILD_DIR_BASE)/zlib/libzlib.a \
|
||||
-DZLIB_INCLUDE_DIR=$(COMPONENT_PATH)/../zlib \
|
||||
-DLWS_WITH_ESP32=1 ;\
|
||||
make VERBOSE=1 && \
|
||||
make && \
|
||||
cp ${COMPONENT_BUILD_DIR}/lib/libwebsockets.a ${COMPONENT_BUILD_DIR}/liblibwebsockets.a
|
||||
|
||||
clean: myclean
|
||||
|
|
|
@ -10,9 +10,28 @@
|
|||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
|
||||
# Name of C compiler.
|
||||
set(CMAKE_C_COMPILER "${CROSS_PATH}/bin/xtensa-esp32-elf-gcc")
|
||||
set(CMAKE_C_COMPILER "${CROSS_PATH}/bin/xtensa-esp32-elf-gcc")
|
||||
set(CMAKE_AR "${CROSS_PATH}/bin/xtensa-esp32-elf-ar")
|
||||
set(CMAKE_RANLIB "${CROSS_PATH}/bin/xtensa-esp32-elf-ranlib")
|
||||
set(CMAKE_LINKER "${CROSS_PATH}/bin/xtensa-esp32-elf-ld")
|
||||
|
||||
SET(CMAKE_C_FLAGS "-nostdlib -Wall -Werror -I${BUILD_DIR_BASE}/include -I${COMPONENT_PATH}/../driver/include -I${COMPONENT_PATH}/../spi_flash/include -I${COMPONENT_PATH}/../nvs_flash/include -I${COMPONENT_PATH}/../tcpip_adapter/include -I${COMPONENT_PATH}/../lwip/include/lwip/posix -I${COMPONENT_PATH}/../lwip/include/lwip -I${COMPONENT_PATH}/../lwip/include/lwip/port -I${COMPONENT_PATH}/../esp32/include/ ${LWS_C_FLAGS} -I${COMPONENT_PATH}/../nvs_flash/test_nvs_host -I${COMPONENT_PATH}/../freertos/include -Os" CACHE STRING "" FORCE)
|
||||
SET(CMAKE_C_FLAGS "-nostdlib -Wall -Werror \
|
||||
-I${BUILD_DIR_BASE}/include \
|
||||
-I${IDF_PATH}/components/mdns/include \
|
||||
-I${IDF_PATH}/components/driver/include \
|
||||
-I${IDF_PATH}/components/spi_flash/include \
|
||||
-I${IDF_PATH}/components/nvs_flash/include \
|
||||
-I${IDF_PATH}/components/tcpip_adapter/include \
|
||||
-I${IDF_PATH}/components/lwip/include/lwip/posix \
|
||||
-I${IDF_PATH}/components/lwip/include/lwip \
|
||||
-I${IDF_PATH}/components/lwip/include/lwip/port \
|
||||
-I${IDF_PATH}/components/esp32/include/ \
|
||||
-I${IDF_PATH}/components/bootloader_support/include/ \
|
||||
-I${IDF_PATH}/components/app_update/include/ \
|
||||
-I$(IDF_PATH)/components/soc/esp32/include/ \
|
||||
${LWS_C_FLAGS} -Os \
|
||||
-I${IDF_PATH}/components/nvs_flash/test_nvs_host \
|
||||
-I${IDF_PATH}/components/freertos/include" CACHE STRING "" FORCE)
|
||||
|
||||
# Where to look for the target environment. (More paths can be added here)
|
||||
set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}")
|
||||
|
|
|
@ -1,20 +1,51 @@
|
|||
#include "private-libwebsockets.h"
|
||||
|
||||
static int
|
||||
lws_getaddrinfo46(struct lws *wsi, const char *ads, struct addrinfo **result)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
*result = NULL;
|
||||
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (wsi->ipv6) {
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
hints.ai_family = AF_INET6;
|
||||
hints.ai_flags = AI_V4MAPPED;
|
||||
#endif
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
}
|
||||
|
||||
return getaddrinfo(ads, NULL, &hints, result);
|
||||
}
|
||||
|
||||
struct lws *
|
||||
lws_client_connect_2(struct lws *wsi)
|
||||
{
|
||||
#ifdef LWS_USE_IPV6
|
||||
struct sockaddr_in6 server_addr6;
|
||||
struct addrinfo hints, *result;
|
||||
#endif
|
||||
sockaddr46 sa46;
|
||||
struct addrinfo *result;
|
||||
struct lws_context *context = wsi->context;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
struct sockaddr_in server_addr4;
|
||||
struct lws_pollfd pfd;
|
||||
struct sockaddr *v;
|
||||
const char *cce = "";
|
||||
int n, plen = 0;
|
||||
const char *cce = "", *iface;
|
||||
int n, plen = 0, port;
|
||||
const char *ads;
|
||||
#ifdef LWS_USE_IPV6
|
||||
char ipv6only = lws_check_opt(wsi->vhost->options,
|
||||
LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY |
|
||||
LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE);
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
ipv6only = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
lwsl_client("%s\n", __func__);
|
||||
|
||||
|
@ -24,7 +55,14 @@ lws_client_connect_2(struct lws *wsi)
|
|||
goto oom4;
|
||||
}
|
||||
|
||||
/* proxy? */
|
||||
/*
|
||||
* start off allowing ipv6 on connection if vhost allows it
|
||||
*/
|
||||
wsi->ipv6 = LWS_IPV6_ENABLED(wsi->vhost);
|
||||
|
||||
/* Decide what it is we need to connect to:
|
||||
*
|
||||
* Priority 1: connect to http proxy */
|
||||
|
||||
if (wsi->vhost->http_proxy_port) {
|
||||
plen = sprintf((char *)pt->serv_buf,
|
||||
|
@ -40,69 +78,71 @@ lws_client_connect_2(struct lws *wsi)
|
|||
|
||||
plen += sprintf((char *)pt->serv_buf + plen, "\x0d\x0a");
|
||||
ads = wsi->vhost->http_proxy_address;
|
||||
port = wsi->vhost->http_proxy_port;
|
||||
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (LWS_IPV6_ENABLED(wsi->vhost)) {
|
||||
memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
|
||||
server_addr6.sin6_port = htons(wsi->vhost->http_proxy_port);
|
||||
} else
|
||||
#if defined(LWS_WITH_SOCKS5)
|
||||
|
||||
/* Priority 2: Connect to SOCK5 Proxy */
|
||||
|
||||
} else if (wsi->vhost->socks_proxy_port) {
|
||||
socks_generate_msg(wsi, SOCKS_MSG_GREETING, (size_t *)&plen);
|
||||
lwsl_client("%s\n", "Sending SOCKS Greeting.");
|
||||
|
||||
ads = wsi->vhost->socks_proxy_address;
|
||||
port = wsi->vhost->socks_proxy_port;
|
||||
#endif
|
||||
server_addr4.sin_port = htons(wsi->vhost->http_proxy_port);
|
||||
|
||||
} else {
|
||||
|
||||
/* Priority 3: Connect directly */
|
||||
|
||||
ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (LWS_IPV6_ENABLED(wsi->vhost)) {
|
||||
memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
|
||||
server_addr6.sin6_port = htons(wsi->c_port);
|
||||
} else
|
||||
#endif
|
||||
server_addr4.sin_port = htons(wsi->c_port);
|
||||
port = wsi->c_port;
|
||||
}
|
||||
|
||||
/*
|
||||
* prepare the actual connection (to the proxy, if any)
|
||||
* prepare the actual connection
|
||||
* to whatever we decided to connect to
|
||||
*/
|
||||
lwsl_notice("%s: address %s\n", __func__, ads);
|
||||
|
||||
lwsl_notice("%s: %p: address %s\n", __func__, wsi, ads);
|
||||
|
||||
n = lws_getaddrinfo46(wsi, ads, &result);
|
||||
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (LWS_IPV6_ENABLED(wsi->vhost)) {
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
#if !defined(__ANDROID__)
|
||||
hints.ai_family = AF_INET6;
|
||||
hints.ai_flags = AI_V4MAPPED;
|
||||
#endif
|
||||
n = getaddrinfo(ads, NULL, &hints, &result);
|
||||
if (wsi->ipv6) {
|
||||
|
||||
if (n) {
|
||||
#ifdef _WIN32
|
||||
lwsl_err("getaddrinfo: %ls\n", gai_strerrorW(n));
|
||||
#else
|
||||
lwsl_err("getaddrinfo: %s\n", gai_strerror(n));
|
||||
#endif
|
||||
cce = "getaddrinfo (ipv6) failed";
|
||||
/* 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;
|
||||
}
|
||||
|
||||
server_addr6.sin6_family = AF_INET6;
|
||||
memset(&sa46, 0, sizeof(sa46));
|
||||
|
||||
sa46.sa6.sin6_family = AF_INET6;
|
||||
switch (result->ai_family) {
|
||||
#if defined(__ANDROID__)
|
||||
case AF_INET:
|
||||
if (ipv6only)
|
||||
break;
|
||||
/* map IPv4 to IPv6 */
|
||||
bzero((char *)&server_addr6.sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
server_addr6.sin6_addr.s6_addr[10] = 0xff;
|
||||
server_addr6.sin6_addr.s6_addr[11] = 0xff;
|
||||
memcpy(&server_addr6.sin6_addr.s6_addr[12],
|
||||
bzero((char *)&sa46.sa6.sin6_addr,
|
||||
sizeof(sa46.sa6.sin6_addr));
|
||||
sa46.sa6.sin6_addr.s6_addr[10] = 0xff;
|
||||
sa46.sa6.sin6_addr.s6_addr[11] = 0xff;
|
||||
memcpy(&sa46.sa6.sin6_addr.s6_addr[12],
|
||||
&((struct sockaddr_in *)result->ai_addr)->sin_addr,
|
||||
sizeof(struct in_addr));
|
||||
lwsl_notice("uplevelling AF_INET to AF_INET6\n");
|
||||
break;
|
||||
#endif
|
||||
|
||||
case AF_INET6:
|
||||
memcpy(&server_addr6.sin6_addr,
|
||||
memcpy(&sa46.sa6.sin6_addr,
|
||||
&((struct sockaddr_in6 *)result->ai_addr)->sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
server_addr6.sin6_scope_id = ((struct sockaddr_in6 *)result->ai_addr)->sin6_scope_id;
|
||||
server_addr6.sin6_flowinfo = ((struct sockaddr_in6 *)result->ai_addr)->sin6_flowinfo;
|
||||
sa46.sa6.sin6_scope_id = ((struct sockaddr_in6 *)result->ai_addr)->sin6_scope_id;
|
||||
sa46.sa6.sin6_flowinfo = ((struct sockaddr_in6 *)result->ai_addr)->sin6_flowinfo;
|
||||
break;
|
||||
default:
|
||||
lwsl_err("Unknown address family\n");
|
||||
|
@ -110,23 +150,18 @@ lws_client_connect_2(struct lws *wsi)
|
|||
cce = "unknown address family";
|
||||
goto oom4;
|
||||
}
|
||||
|
||||
freeaddrinfo(result);
|
||||
} else
|
||||
#endif
|
||||
#endif /* use ipv6 */
|
||||
|
||||
/* use ipv4 */
|
||||
{
|
||||
struct addrinfo ai, *res, *result = NULL;
|
||||
void *p = NULL;
|
||||
int addr_rv;
|
||||
|
||||
memset (&ai, 0, sizeof ai);
|
||||
ai.ai_family = PF_UNSPEC;
|
||||
ai.ai_socktype = SOCK_STREAM;
|
||||
ai.ai_flags = AI_CANONNAME;
|
||||
if (!n) {
|
||||
struct addrinfo *res = result;
|
||||
|
||||
/* pick the first AF_INET (IPv4) result */
|
||||
|
||||
addr_rv = getaddrinfo(ads, NULL, &ai, &result);
|
||||
if (!addr_rv) {
|
||||
res = result;
|
||||
while (!p && res) {
|
||||
switch (res->ai_family) {
|
||||
case AF_INET:
|
||||
|
@ -137,7 +172,7 @@ lws_client_connect_2(struct lws *wsi)
|
|||
res = res->ai_next;
|
||||
}
|
||||
#if defined(LWS_FALLBACK_GETHOSTBYNAME)
|
||||
} else if (addr_rv == EAI_SYSTEM) {
|
||||
} else if (n == EAI_SYSTEM) {
|
||||
struct hostent *host;
|
||||
|
||||
lwsl_info("getaddrinfo (ipv4) failed, trying gethostbyname\n");
|
||||
|
@ -152,7 +187,7 @@ lws_client_connect_2(struct lws *wsi)
|
|||
#endif
|
||||
} else {
|
||||
lwsl_err("getaddrinfo failed\n");
|
||||
cce = "getaddrinfo (ipv4) failed";
|
||||
cce = "getaddrinfo failed";
|
||||
goto oom4;
|
||||
}
|
||||
|
||||
|
@ -164,17 +199,29 @@ lws_client_connect_2(struct lws *wsi)
|
|||
goto oom4;
|
||||
}
|
||||
|
||||
server_addr4.sin_family = AF_INET;
|
||||
server_addr4.sin_addr = *((struct in_addr *)p);
|
||||
bzero(&server_addr4.sin_zero, 8);
|
||||
if (result)
|
||||
freeaddrinfo(result);
|
||||
sa46.sa4.sin_family = AF_INET;
|
||||
sa46.sa4.sin_addr = *((struct in_addr *)p);
|
||||
bzero(&sa46.sa4.sin_zero, 8);
|
||||
}
|
||||
|
||||
if (result)
|
||||
freeaddrinfo(result);
|
||||
|
||||
/* now we decided on ipv4 or ipv6, set the port */
|
||||
|
||||
if (!lws_socket_is_valid(wsi->desc.sockfd)) {
|
||||
|
||||
#if defined(LWS_USE_LIBUV)
|
||||
if (LWS_LIBUV_ENABLED(context))
|
||||
if (lws_libuv_check_watcher_active(wsi)) {
|
||||
lwsl_warn("Waiting for libuv watcher to close\n");
|
||||
cce = "waiting for libuv watcher to close";
|
||||
goto oom4;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (LWS_IPV6_ENABLED(wsi->vhost))
|
||||
if (wsi->ipv6)
|
||||
wsi->desc.sockfd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
else
|
||||
#endif
|
||||
|
@ -197,6 +244,8 @@ lws_client_connect_2(struct lws *wsi)
|
|||
|
||||
lws_libev_accept(wsi, wsi->desc);
|
||||
lws_libuv_accept(wsi, wsi->desc);
|
||||
lws_libevent_accept(wsi, wsi->desc);
|
||||
|
||||
if (insert_wsi_socket_into_fds(context, wsi)) {
|
||||
compatible_close(wsi->desc.sockfd);
|
||||
cce = "insert wsi failed";
|
||||
|
@ -219,25 +268,30 @@ lws_client_connect_2(struct lws *wsi)
|
|||
lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
|
||||
AWAITING_TIMEOUT);
|
||||
|
||||
n = lws_socket_bind(wsi->vhost, wsi->desc.sockfd, 0, wsi->vhost->iface);
|
||||
if (n < 0) {
|
||||
cce = "unable to bind socket";
|
||||
goto failed;
|
||||
iface = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_IFACE);
|
||||
|
||||
if (iface) {
|
||||
n = lws_socket_bind(wsi->vhost, wsi->desc.sockfd, 0, iface);
|
||||
if (n < 0) {
|
||||
cce = "unable to bind socket";
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LWS_USE_IPV6
|
||||
if (LWS_IPV6_ENABLED(wsi->vhost)) {
|
||||
v = (struct sockaddr *)&server_addr6;
|
||||
if (wsi->ipv6) {
|
||||
sa46.sa6.sin6_port = htons(port);
|
||||
n = sizeof(struct sockaddr_in6);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
v = (struct sockaddr *)&server_addr4;
|
||||
sa46.sa4.sin_port = htons(port);
|
||||
n = sizeof(struct sockaddr);
|
||||
}
|
||||
|
||||
if (connect(wsi->desc.sockfd, v, n) == -1 || LWS_ERRNO == LWS_EISCONN) {
|
||||
if (connect(wsi->desc.sockfd, (const struct sockaddr *)&sa46, n) == -1 ||
|
||||
LWS_ERRNO == LWS_EISCONN) {
|
||||
if (LWS_ERRNO == LWS_EALREADY ||
|
||||
LWS_ERRNO == LWS_EINPROGRESS ||
|
||||
LWS_ERRNO == LWS_EWOULDBLOCK
|
||||
|
@ -276,6 +330,7 @@ lws_client_connect_2(struct lws *wsi)
|
|||
|
||||
/* we are connected to server, or proxy */
|
||||
|
||||
/* http proxy */
|
||||
if (wsi->vhost->http_proxy_port) {
|
||||
|
||||
/*
|
||||
|
@ -304,6 +359,26 @@ lws_client_connect_2(struct lws *wsi)
|
|||
|
||||
return wsi;
|
||||
}
|
||||
#if defined(LWS_WITH_SOCKS5)
|
||||
/* socks proxy */
|
||||
else if (wsi->vhost->socks_proxy_port) {
|
||||
n = send(wsi->desc.sockfd, (char *)pt->serv_buf, plen,
|
||||
MSG_NOSIGNAL);
|
||||
if (n < 0) {
|
||||
lwsl_debug("ERROR writing greeting to socks proxy"
|
||||
"socket.\n");
|
||||
cce = "socks write failed";
|
||||
goto failed;
|
||||
}
|
||||
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY,
|
||||
AWAITING_TIMEOUT);
|
||||
|
||||
wsi->mode = LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY;
|
||||
|
||||
return wsi;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* provoke service to issue the handshake directly
|
||||
|
@ -335,8 +410,8 @@ lws_client_connect_2(struct lws *wsi)
|
|||
|
||||
oom4:
|
||||
/* we're closing, losing some rx is OK */
|
||||
if (wsi->u.hdr.ah)
|
||||
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
|
||||
lws_header_table_force_to_detachable_state(wsi);
|
||||
|
||||
if (wsi->mode == LWSCM_HTTP_CLIENT ||
|
||||
wsi->mode == LWSCM_HTTP_CLIENT_ACCEPTED ||
|
||||
wsi->mode == LWSCM_WSCL_WAITING_CONNECT) {
|
||||
|
@ -378,7 +453,7 @@ LWS_VISIBLE struct lws *
|
|||
lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
|
||||
const char *path, const char *host)
|
||||
{
|
||||
char origin[300] = "", protocol[300] = "", method[32] = "", *p;
|
||||
char origin[300] = "", protocol[300] = "", method[32] = "", iface[16] = "", *p;
|
||||
struct lws *wsi = *pwsi;
|
||||
|
||||
if (wsi->redirects == 3) {
|
||||
|
@ -387,15 +462,6 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
|
|||
}
|
||||
wsi->redirects++;
|
||||
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
wsi->use_ssl = ssl;
|
||||
#else
|
||||
if (ssl) {
|
||||
lwsl_err("%s: not configured for ssl\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN);
|
||||
if (p)
|
||||
strncpy(origin, p, sizeof(origin) - 1);
|
||||
|
@ -408,14 +474,46 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
|
|||
if (p)
|
||||
strncpy(method, p, sizeof(method) - 1);
|
||||
|
||||
lwsl_debug("redirect ads='%s', port=%d, path='%s', ssl = %d\n",
|
||||
p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_IFACE);
|
||||
if (p)
|
||||
strncpy(method, p, sizeof(iface) - 1);
|
||||
|
||||
lwsl_notice("redirect ads='%s', port=%d, path='%s', ssl = %d\n",
|
||||
address, port, path, ssl);
|
||||
|
||||
/* close the connection by hand */
|
||||
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
lws_ssl_close(wsi);
|
||||
#endif
|
||||
|
||||
#ifdef LWS_USE_LIBUV
|
||||
if (LWS_LIBUV_ENABLED(wsi->context)) {
|
||||
lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi);
|
||||
/*
|
||||
* libuv has to do his own close handle processing asynchronously
|
||||
* but once it starts we can do everything else synchronously,
|
||||
* including trash wsi->desc.sockfd since it took a copy.
|
||||
*
|
||||
* When it completes it will call compatible_close()
|
||||
*/
|
||||
lws_libuv_closehandle_manually(wsi);
|
||||
} else
|
||||
#else
|
||||
compatible_close(wsi->desc.sockfd);
|
||||
#endif
|
||||
|
||||
remove_wsi_socket_from_fds(wsi);
|
||||
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
wsi->use_ssl = ssl;
|
||||
#else
|
||||
if (ssl) {
|
||||
lwsl_err("%s: not configured for ssl\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
wsi->desc.sockfd = LWS_SOCK_INVALID;
|
||||
wsi->state = LWSS_CLIENT_UNCONNECTED;
|
||||
wsi->protocol = NULL;
|
||||
|
@ -443,6 +541,11 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
|
|||
method))
|
||||
return NULL;
|
||||
|
||||
if (iface[0])
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_IFACE,
|
||||
iface))
|
||||
return NULL;
|
||||
|
||||
origin[0] = '/';
|
||||
strncpy(&origin[1], path, sizeof(origin) - 2);
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, origin))
|
||||
|
@ -472,14 +575,14 @@ html_parser_cb(const hubbub_token *token, void *pw)
|
|||
"(force-quirks) " : "");
|
||||
|
||||
if (token->data.doctype.public_missing)
|
||||
printf("\tpublic: missing\n");
|
||||
lwsl_debug("\tpublic: missing\n");
|
||||
else
|
||||
p += lws_snprintf(p, end - p, "PUBLIC \"%.*s\"\n",
|
||||
(int) token->data.doctype.public_id.len,
|
||||
token->data.doctype.public_id.ptr);
|
||||
|
||||
if (token->data.doctype.system_missing)
|
||||
printf("\tsystem: missing\n");
|
||||
lwsl_debug("\tsystem: missing\n");
|
||||
else
|
||||
p += lws_snprintf(p, end - p, " \"%.*s\">\n",
|
||||
(int) token->data.doctype.system_id.len,
|
||||
|
@ -502,25 +605,28 @@ html_parser_cb(const hubbub_token *token, void *pw)
|
|||
const char *pp = (const char *)token->data.tag.attributes[i].value.ptr;
|
||||
int plen = (int) token->data.tag.attributes[i].value.len;
|
||||
|
||||
if (!hstrcmp(&token->data.tag.attributes[i].value,
|
||||
r->from, r->from_len)) {
|
||||
pp += r->from_len;
|
||||
plen -= r->from_len;
|
||||
if (strncmp(pp, "http:", 5) && strncmp(pp, "https:", 6)) {
|
||||
|
||||
if (!hstrcmp(&token->data.tag.attributes[i].value,
|
||||
r->from, r->from_len)) {
|
||||
pp += r->from_len;
|
||||
plen -= r->from_len;
|
||||
}
|
||||
p += lws_snprintf(p, end - p, " %.*s=\"%s/%.*s\"",
|
||||
(int) token->data.tag.attributes[i].name.len,
|
||||
token->data.tag.attributes[i].name.ptr,
|
||||
r->to, plen, pp);
|
||||
continue;
|
||||
}
|
||||
p += lws_snprintf(p, end - p, " %.*s=\"%s/%.*s\"",
|
||||
(int) token->data.tag.attributes[i].name.len,
|
||||
token->data.tag.attributes[i].name.ptr,
|
||||
r->to, plen, pp);
|
||||
}
|
||||
|
||||
} else
|
||||
|
||||
p += lws_snprintf(p, end - p, " %.*s=\"%.*s\"",
|
||||
(int) token->data.tag.attributes[i].name.len,
|
||||
token->data.tag.attributes[i].name.ptr,
|
||||
(int) token->data.tag.attributes[i].value.len,
|
||||
token->data.tag.attributes[i].value.ptr);
|
||||
p += lws_snprintf(p, end - p, " %.*s=\"%.*s\"",
|
||||
(int) token->data.tag.attributes[i].name.len,
|
||||
token->data.tag.attributes[i].name.ptr,
|
||||
(int) token->data.tag.attributes[i].value.len,
|
||||
token->data.tag.attributes[i].value.ptr);
|
||||
}
|
||||
p += lws_snprintf(p, end - p, ">\n");
|
||||
p += lws_snprintf(p, end - p, ">");
|
||||
break;
|
||||
case HUBBUB_TOKEN_END_TAG:
|
||||
p += lws_snprintf(p, end - p, "</%.*s", (int) token->data.tag.name.len,
|
||||
|
@ -538,7 +644,7 @@ html_parser_cb(const hubbub_token *token, void *pw)
|
|||
(int) token->data.tag.attributes[i].value.len,
|
||||
token->data.tag.attributes[i].value.ptr);
|
||||
}
|
||||
p += lws_snprintf(p, end - p, ">\n");
|
||||
p += lws_snprintf(p, end - p, ">");
|
||||
break;
|
||||
case HUBBUB_TOKEN_COMMENT:
|
||||
p += lws_snprintf(p, end - p, "<!-- %.*s -->\n",
|
||||
|
@ -546,6 +652,21 @@ html_parser_cb(const hubbub_token *token, void *pw)
|
|||
token->data.comment.ptr);
|
||||
break;
|
||||
case HUBBUB_TOKEN_CHARACTER:
|
||||
if (token->data.character.len == 1) {
|
||||
if (*token->data.character.ptr == '<') {
|
||||
p += lws_snprintf(p, end - p, "<");
|
||||
break;
|
||||
}
|
||||
if (*token->data.character.ptr == '>') {
|
||||
p += lws_snprintf(p, end - p, ">");
|
||||
break;
|
||||
}
|
||||
if (*token->data.character.ptr == '&') {
|
||||
p += lws_snprintf(p, end - p, "&");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p += lws_snprintf(p, end - p, "%.*s", (int) token->data.character.len,
|
||||
token->data.character.ptr);
|
||||
break;
|
||||
|
@ -649,6 +770,7 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
|
|||
wsi->u.hdr.stash->origin[0] = '\0';
|
||||
wsi->u.hdr.stash->protocol[0] = '\0';
|
||||
wsi->u.hdr.stash->method[0] = '\0';
|
||||
wsi->u.hdr.stash->iface[0] = '\0';
|
||||
|
||||
strncpy(wsi->u.hdr.stash->address, i->address,
|
||||
sizeof(wsi->u.hdr.stash->address) - 1);
|
||||
|
@ -665,6 +787,9 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
|
|||
if (i->method)
|
||||
strncpy(wsi->u.hdr.stash->method, i->method,
|
||||
sizeof(wsi->u.hdr.stash->method) - 1);
|
||||
if (i->iface)
|
||||
strncpy(wsi->u.hdr.stash->iface, i->iface,
|
||||
sizeof(wsi->u.hdr.stash->iface) - 1);
|
||||
|
||||
wsi->u.hdr.stash->address[sizeof(wsi->u.hdr.stash->address) - 1] = '\0';
|
||||
wsi->u.hdr.stash->path[sizeof(wsi->u.hdr.stash->path) - 1] = '\0';
|
||||
|
@ -672,6 +797,7 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
|
|||
wsi->u.hdr.stash->origin[sizeof(wsi->u.hdr.stash->origin) - 1] = '\0';
|
||||
wsi->u.hdr.stash->protocol[sizeof(wsi->u.hdr.stash->protocol) - 1] = '\0';
|
||||
wsi->u.hdr.stash->method[sizeof(wsi->u.hdr.stash->method) - 1] = '\0';
|
||||
wsi->u.hdr.stash->iface[sizeof(wsi->u.hdr.stash->iface) - 1] = '\0';
|
||||
|
||||
if (i->pwsi)
|
||||
*i->pwsi = wsi;
|
||||
|
@ -754,8 +880,15 @@ lws_client_connect_via_info2(struct lws *wsi)
|
|||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_METHOD,
|
||||
stash->method))
|
||||
goto bail1;
|
||||
if (stash->iface[0])
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_IFACE,
|
||||
stash->iface))
|
||||
goto bail1;
|
||||
|
||||
lws_free_set_NULL(wsi->u.hdr.stash);
|
||||
#if defined(LWS_WITH_SOCKS5)
|
||||
if (!wsi->vhost->socks_proxy_port)
|
||||
lws_free_set_NULL(wsi->u.hdr.stash);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check with each extension if it is able to route and proxy this
|
||||
|
@ -783,7 +916,10 @@ lws_client_connect_via_info2(struct lws *wsi)
|
|||
return lws_client_connect_2(wsi);
|
||||
|
||||
bail1:
|
||||
lws_free_set_NULL(wsi->u.hdr.stash);
|
||||
#if defined(LWS_WITH_SOCKS5)
|
||||
if (!wsi->vhost->socks_proxy_port)
|
||||
lws_free_set_NULL(wsi->u.hdr.stash);
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -837,3 +973,73 @@ lws_client_connect(struct lws_context *context, const char *address,
|
|||
return lws_client_connect_via_info(&i);
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_SOCKS5)
|
||||
void socks_generate_msg(struct lws *wsi, enum socks_msg_type type,
|
||||
size_t *msg_len)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
size_t len = 0;
|
||||
|
||||
if (type == SOCKS_MSG_GREETING) {
|
||||
/* socks version, version 5 only */
|
||||
pt->serv_buf[len++] = SOCKS_VERSION_5;
|
||||
/* number of methods */
|
||||
pt->serv_buf[len++] = 2;
|
||||
/* username password method */
|
||||
pt->serv_buf[len++] = SOCKS_AUTH_USERNAME_PASSWORD;
|
||||
/* no authentication method */
|
||||
pt->serv_buf[len++] = SOCKS_AUTH_NO_AUTH;
|
||||
}
|
||||
else if (type == SOCKS_MSG_USERNAME_PASSWORD) {
|
||||
size_t user_len = 0;
|
||||
size_t passwd_len = 0;
|
||||
|
||||
user_len = strlen(wsi->vhost->socks_user);
|
||||
passwd_len = strlen(wsi->vhost->socks_password);
|
||||
|
||||
/* the subnegotiation version */
|
||||
pt->serv_buf[len++] = SOCKS_SUBNEGOTIATION_VERSION_1;
|
||||
/* length of the user name */
|
||||
pt->serv_buf[len++] = user_len;
|
||||
/* user name */
|
||||
strncpy((char *)&pt->serv_buf[len], wsi->vhost->socks_user,
|
||||
context->pt_serv_buf_size - len);
|
||||
len += user_len;
|
||||
/* length of the password */
|
||||
pt->serv_buf[len++] = passwd_len;
|
||||
/* password */
|
||||
strncpy((char *)&pt->serv_buf[len], wsi->vhost->socks_password,
|
||||
context->pt_serv_buf_size - len);
|
||||
len += passwd_len;
|
||||
}
|
||||
else if (type == SOCKS_MSG_CONNECT) {
|
||||
size_t len_index = 0;
|
||||
short net_num = 0;
|
||||
char *net_buf = (char*)&net_num;
|
||||
|
||||
/* socks version */
|
||||
pt->serv_buf[len++] = SOCKS_VERSION_5;
|
||||
/* socks command */
|
||||
pt->serv_buf[len++] = SOCKS_COMMAND_CONNECT;
|
||||
/* reserved */
|
||||
pt->serv_buf[len++] = 0;
|
||||
/* address type */
|
||||
pt->serv_buf[len++] = SOCKS_ATYP_DOMAINNAME;
|
||||
len_index = len;
|
||||
len++;
|
||||
/* the address we tell SOCKS proxy to connect to */
|
||||
strncpy((char *)&(pt->serv_buf[len]), wsi->u.hdr.stash->address,
|
||||
context->pt_serv_buf_size - len);
|
||||
len += strlen(wsi->u.hdr.stash->address);
|
||||
net_num = htons((short)wsi->c_port);
|
||||
/* the port we tell SOCKS proxy to connect to */
|
||||
pt->serv_buf[len++] = net_buf[0];
|
||||
pt->serv_buf[len++] = net_buf[1];
|
||||
/* the length of the address, excluding port */
|
||||
pt->serv_buf[len_index] = strlen(wsi->u.hdr.stash->address);
|
||||
}
|
||||
|
||||
*msg_len = len;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -558,6 +558,7 @@ utf8_fail: lwsl_info("utf8 error\n");
|
|||
lws_remove_wsi_from_draining_ext_list(wsi);
|
||||
|
||||
if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY ||
|
||||
wsi->state == LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION ||
|
||||
wsi->state == LWSS_AWAITING_CLOSE_ACK)
|
||||
goto already_done;
|
||||
|
||||
|
|
239
lib/client.c
239
lib/client.c
|
@ -42,7 +42,12 @@ lws_handshake_client(struct lws *wsi, unsigned char **buf, size_t len)
|
|||
return 0;
|
||||
}
|
||||
if (wsi->u.ws.rx_draining_ext) {
|
||||
m = lws_rx_sm(wsi, 0);
|
||||
#if !defined(LWS_NO_CLIENT)
|
||||
if (wsi->mode == LWSCM_WS_CLIENT)
|
||||
m = lws_client_rx_sm(wsi, 0);
|
||||
else
|
||||
#endif
|
||||
m = lws_rx_sm(wsi, 0);
|
||||
if (m < 0)
|
||||
return -1;
|
||||
continue;
|
||||
|
@ -81,7 +86,10 @@ lws_client_socket_service(struct lws_context *context, struct lws *wsi,
|
|||
const char *cce = NULL;
|
||||
unsigned char c;
|
||||
char *sb = p;
|
||||
int n, len;
|
||||
int n = 0, len = 0;
|
||||
#if defined(LWS_WITH_SOCKS5)
|
||||
char conn_mode = 0, pending_timeout = 0;
|
||||
#endif
|
||||
|
||||
switch (wsi->mode) {
|
||||
|
||||
|
@ -101,6 +109,195 @@ lws_client_socket_service(struct lws_context *context, struct lws *wsi,
|
|||
/* either still pending connection, or changed mode */
|
||||
return 0;
|
||||
|
||||
#if defined(LWS_WITH_SOCKS5)
|
||||
/* SOCKS Greeting Reply */
|
||||
case LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY:
|
||||
|
||||
/* handle proxy hung up on us */
|
||||
|
||||
if (pollfd->revents & LWS_POLLHUP) {
|
||||
|
||||
lwsl_warn("SOCKS connection %p (fd=%d) dead\n",
|
||||
(void *)wsi, pollfd->fd);
|
||||
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n = recv(wsi->desc.sockfd, sb, context->pt_serv_buf_size, 0);
|
||||
if (n < 0) {
|
||||
if (LWS_ERRNO == LWS_EAGAIN) {
|
||||
lwsl_debug("SOCKS read returned EAGAIN..."
|
||||
"retrying\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
|
||||
lwsl_err("ERROR reading from SOCKS socket\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* processing greeting reply */
|
||||
if (pt->serv_buf[0] == SOCKS_VERSION_5
|
||||
&& pt->serv_buf[1] == SOCKS_AUTH_NO_AUTH)
|
||||
{
|
||||
lwsl_client("%s\n", "SOCKS greeting reply received "
|
||||
"- No Authentication Method");
|
||||
socks_generate_msg(wsi, SOCKS_MSG_CONNECT, (size_t *)&len);
|
||||
|
||||
conn_mode = LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY;
|
||||
pending_timeout = PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY;
|
||||
lwsl_client("%s\n", "Sending SOCKS connect command");
|
||||
}
|
||||
else if (pt->serv_buf[0] == SOCKS_VERSION_5
|
||||
&& pt->serv_buf[1] == SOCKS_AUTH_USERNAME_PASSWORD)
|
||||
{
|
||||
lwsl_client("%s\n", "SOCKS greeting reply received "
|
||||
"- User Name Password Method");
|
||||
socks_generate_msg(wsi, SOCKS_MSG_USERNAME_PASSWORD,
|
||||
(size_t *)&len);
|
||||
|
||||
conn_mode = LWSCM_WSCL_WAITING_SOCKS_AUTH_REPLY;
|
||||
pending_timeout = PENDING_TIMEOUT_AWAITING_SOCKS_AUTH_REPLY;
|
||||
lwsl_client("%s\n", "Sending SOCKS user/password");
|
||||
}
|
||||
else
|
||||
{
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
|
||||
lwsl_err("ERROR SOCKS greeting reply failed, method "
|
||||
"code: %d\n", pt->serv_buf[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n = send(wsi->desc.sockfd, (char *)pt->serv_buf, len,
|
||||
MSG_NOSIGNAL);
|
||||
if (n < 0) {
|
||||
lwsl_debug("ERROR writing socks command to socks proxy "
|
||||
"socket\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lws_set_timeout(wsi, pending_timeout, AWAITING_TIMEOUT);
|
||||
wsi->mode = conn_mode;
|
||||
|
||||
break;
|
||||
/* SOCKS auth Reply */
|
||||
case LWSCM_WSCL_WAITING_SOCKS_AUTH_REPLY:
|
||||
|
||||
/* handle proxy hung up on us */
|
||||
|
||||
if (pollfd->revents & LWS_POLLHUP) {
|
||||
|
||||
lwsl_warn("SOCKS connection %p (fd=%d) dead\n",
|
||||
(void *)wsi, pollfd->fd);
|
||||
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n = recv(wsi->desc.sockfd, sb, context->pt_serv_buf_size, 0);
|
||||
if (n < 0) {
|
||||
if (LWS_ERRNO == LWS_EAGAIN) {
|
||||
lwsl_debug("SOCKS read returned EAGAIN... "
|
||||
"retrying\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
|
||||
lwsl_err("ERROR reading from socks socket\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* processing auth reply */
|
||||
if (pt->serv_buf[0] == SOCKS_SUBNEGOTIATION_VERSION_1
|
||||
&& pt->serv_buf[1] == SOCKS_SUBNEGOTIATION_STATUS_SUCCESS)
|
||||
{
|
||||
lwsl_client("%s\n", "SOCKS password reply recieved - "
|
||||
"successful");
|
||||
socks_generate_msg(wsi, SOCKS_MSG_CONNECT, (size_t *)&len);
|
||||
|
||||
conn_mode = LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY;
|
||||
pending_timeout =
|
||||
PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY;
|
||||
lwsl_client("%s\n", "Sending SOCKS connect command");
|
||||
}
|
||||
else
|
||||
{
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
|
||||
lwsl_err("ERROR : SOCKS user/password reply failed, "
|
||||
"error code: %d\n", pt->serv_buf[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n = send(wsi->desc.sockfd, (char *)pt->serv_buf, len,
|
||||
MSG_NOSIGNAL);
|
||||
if (n < 0) {
|
||||
lwsl_debug("ERROR writing connect command to SOCKS "
|
||||
"socket\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lws_set_timeout(wsi, pending_timeout, AWAITING_TIMEOUT);
|
||||
wsi->mode = conn_mode;
|
||||
|
||||
break;
|
||||
|
||||
/* SOCKS connect command Reply */
|
||||
case LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY:
|
||||
|
||||
/* handle proxy hung up on us */
|
||||
|
||||
if (pollfd->revents & LWS_POLLHUP) {
|
||||
|
||||
lwsl_warn("SOCKS connection %p (fd=%d) dead\n",
|
||||
(void *)wsi, pollfd->fd);
|
||||
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n = recv(wsi->desc.sockfd, sb, context->pt_serv_buf_size, 0);
|
||||
if (n < 0) {
|
||||
if (LWS_ERRNO == LWS_EAGAIN) {
|
||||
lwsl_debug("SOCKS read returned EAGAIN... "
|
||||
"retrying\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
|
||||
lwsl_err("ERROR reading from socks socket\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* processing connect reply */
|
||||
if (pt->serv_buf[0] == SOCKS_VERSION_5
|
||||
&& pt->serv_buf[1] == SOCKS_REQUEST_REPLY_SUCCESS)
|
||||
{
|
||||
lwsl_client("%s\n", "SOCKS connect reply recieved - "
|
||||
"successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
|
||||
lwsl_err("ERROR SOCKS connect reply failed, error "
|
||||
"code: %d\n", pt->serv_buf[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* free stash since we are done with it */
|
||||
lws_free_set_NULL(wsi->u.hdr.stash);
|
||||
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
|
||||
wsi->vhost->socks_proxy_address))
|
||||
goto bail3;
|
||||
wsi->c_port = wsi->vhost->socks_proxy_port;
|
||||
|
||||
/* clear his proxy connection timeout */
|
||||
|
||||
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
||||
|
||||
goto start_ws_hanshake;
|
||||
#endif
|
||||
case LWSCM_WSCL_WAITING_PROXY_REPLY:
|
||||
|
||||
/* handle proxy hung up on us */
|
||||
|
@ -149,6 +346,9 @@ lws_client_socket_service(struct lws_context *context, struct lws *wsi,
|
|||
* take care of our lws_callback_on_writable
|
||||
* happening at a time when there's no real connection yet
|
||||
*/
|
||||
#if defined(LWS_WITH_SOCKS5)
|
||||
start_ws_hanshake:
|
||||
#endif
|
||||
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
|
||||
return -1;
|
||||
|
||||
|
@ -320,7 +520,9 @@ client_http_body_sent:
|
|||
|
||||
bail3:
|
||||
lwsl_info("closing conn at LWS_CONNMODE...SERVER_REPLY\n");
|
||||
wsi->vhost->protocols[0].callback(wsi,
|
||||
if (cce)
|
||||
lwsl_info("reason: %s\n", cce);
|
||||
wsi->protocol->callback(wsi,
|
||||
LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
|
||||
wsi->user_space, (void *)cce, cce ? strlen(cce) : 0);
|
||||
wsi->already_did_cce = 1;
|
||||
|
@ -369,6 +571,9 @@ lws_http_transaction_completed_client(struct lws *wsi)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* we don't support chained client connections yet */
|
||||
return 1;
|
||||
#if 0
|
||||
/* otherwise set ourselves up ready to go again */
|
||||
wsi->state = LWSS_CLIENT_HTTP_ESTABLISHED;
|
||||
wsi->mode = LWSCM_HTTP_CLIENT_ACCEPTED;
|
||||
|
@ -383,7 +588,7 @@ lws_http_transaction_completed_client(struct lws *wsi)
|
|||
* we can drop the ah, if any
|
||||
*/
|
||||
if (wsi->u.hdr.ah) {
|
||||
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
|
||||
lws_header_table_force_to_detachable_state(wsi);
|
||||
lws_header_table_detach(wsi, 0);
|
||||
}
|
||||
|
||||
|
@ -393,6 +598,7 @@ lws_http_transaction_completed_client(struct lws *wsi)
|
|||
lwsl_info("%s: %p: keep-alive await new transaction\n", __func__, wsi);
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN unsigned int
|
||||
|
@ -425,6 +631,8 @@ lws_client_interpret_server_handshake(struct lws *wsi)
|
|||
int more = 1;
|
||||
void *v;
|
||||
#endif
|
||||
if (wsi->u.hdr.stash)
|
||||
lws_free_set_NULL(wsi->u.hdr.stash);
|
||||
|
||||
ah = wsi->u.hdr.ah;
|
||||
if (!wsi->do_ws) {
|
||||
|
@ -549,9 +757,9 @@ lws_client_interpret_server_handshake(struct lws *wsi)
|
|||
}
|
||||
|
||||
if (!wsi->do_ws) {
|
||||
if (n != 200 && n != 304) {
|
||||
if (n != 200 && n != 201 && n != 304 && n != 401) {
|
||||
lwsl_notice("Connection failed with code %d\n", n);
|
||||
cce = "HS: Server did not return 200 or 304";
|
||||
cce = "HS: Server unrecognized response code";
|
||||
goto bail2;
|
||||
}
|
||||
|
||||
|
@ -584,10 +792,10 @@ lws_client_interpret_server_handshake(struct lws *wsi)
|
|||
|
||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
|
||||
wsi->u.http.content_length =
|
||||
atoi(lws_hdr_simple_ptr(wsi,
|
||||
atoll(lws_hdr_simple_ptr(wsi,
|
||||
WSI_TOKEN_HTTP_CONTENT_LENGTH));
|
||||
lwsl_notice("%s: incoming content length %d\n", __func__,
|
||||
wsi->u.http.content_length);
|
||||
lwsl_notice("%s: incoming content length %llu\n", __func__,
|
||||
(unsigned long long)wsi->u.http.content_length);
|
||||
wsi->u.http.content_remain = wsi->u.http.content_length;
|
||||
} else /* can't do 1.1 without a content length or chunked */
|
||||
if (!wsi->chunked)
|
||||
|
@ -955,12 +1163,14 @@ check_accept:
|
|||
wsi->u.ws.rx_ubuf_alloc = n;
|
||||
lwsl_info("Allocating client RX buffer %d\n", n);
|
||||
|
||||
#if !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);
|
||||
cce = "HS: SO_SNDBUF failed";
|
||||
goto bail3;
|
||||
}
|
||||
#endif
|
||||
|
||||
lwsl_debug("handshake OK for protocol %s\n", wsi->protocol->name);
|
||||
|
||||
|
@ -1022,19 +1232,21 @@ lws_generate_client_handshake(struct lws *wsi, char *pkt)
|
|||
const struct lws_extension *ext;
|
||||
int ext_count = 0;
|
||||
#endif
|
||||
const char *pp = lws_hdr_simple_ptr(wsi,
|
||||
_WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
|
||||
|
||||
meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
|
||||
if (!meth) {
|
||||
meth = "GET";
|
||||
wsi->do_ws = 1;
|
||||
} else
|
||||
} else {
|
||||
wsi->do_ws = 0;
|
||||
}
|
||||
|
||||
if (!strcmp(meth, "RAW")) {
|
||||
const char *pp = lws_hdr_simple_ptr(wsi,
|
||||
_WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
|
||||
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
||||
lwsl_notice("client transition to raw\n");
|
||||
|
||||
if (pp) {
|
||||
const struct lws_protocols *pr;
|
||||
|
||||
|
@ -1048,12 +1260,13 @@ lws_generate_client_handshake(struct lws *wsi, char *pkt)
|
|||
|
||||
lws_bind_protocol(wsi, pr);
|
||||
}
|
||||
|
||||
if ((wsi->protocol->callback)(wsi,
|
||||
LWS_CALLBACK_RAW_ADOPT,
|
||||
wsi->user_space, NULL, 0))
|
||||
return NULL;
|
||||
|
||||
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
|
||||
lws_header_table_force_to_detachable_state(wsi);
|
||||
lws_union_transition(wsi, LWSCM_RAW);
|
||||
lws_header_table_detach(wsi, 1);
|
||||
|
||||
|
|
489
lib/context.c
489
lib/context.c
|
@ -40,7 +40,6 @@ lws_get_library_version(void)
|
|||
return library_version;
|
||||
}
|
||||
|
||||
#if !defined(LWS_WITH_NO_LOGS)
|
||||
static const char * const mount_protocols[] = {
|
||||
"http://",
|
||||
"https://",
|
||||
|
@ -50,7 +49,6 @@ static const char * const mount_protocols[] = {
|
|||
">https://",
|
||||
"callback://"
|
||||
};
|
||||
#endif
|
||||
|
||||
LWS_VISIBLE void *
|
||||
lws_protocol_vh_priv_zalloc(struct lws_vhost *vhost, const struct lws_protocols *prot,
|
||||
|
@ -222,10 +220,13 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
{
|
||||
#ifdef LWS_WITH_CGI
|
||||
struct lws_cgi_args *args;
|
||||
char buf[128];
|
||||
#endif
|
||||
#if defined(LWS_WITH_CGI) || defined(LWS_WITH_HTTP_PROXY)
|
||||
char buf[512];
|
||||
int n;
|
||||
#endif
|
||||
|
||||
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_HTTP:
|
||||
#ifndef LWS_NO_SERVER
|
||||
|
@ -236,20 +237,119 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
#endif
|
||||
return -1;
|
||||
break;
|
||||
#if !defined(LWS_NO_SERVER)
|
||||
case LWS_CALLBACK_HTTP_FILE_COMPLETION:
|
||||
if (lws_http_transaction_completed(wsi))
|
||||
return -1;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case LWS_CALLBACK_HTTP_WRITEABLE:
|
||||
#ifdef LWS_WITH_CGI
|
||||
if (wsi->reason_bf & 1) {
|
||||
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI) {
|
||||
if (lws_cgi_write_split_stdout_headers(wsi) < 0)
|
||||
return -1;
|
||||
|
||||
wsi->reason_bf &= ~1;
|
||||
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_HEADERS)
|
||||
wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__CGI_HEADERS;
|
||||
else
|
||||
wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__CGI;
|
||||
break;
|
||||
}
|
||||
|
||||
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_CHUNK_END) {
|
||||
n = lws_write(wsi, (unsigned char *)"0\x0d\x0a\x0d\x0a",
|
||||
5, LWS_WRITE_HTTP);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if defined(LWS_WITH_HTTP_PROXY)
|
||||
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__PROXY) {
|
||||
char *px = buf + LWS_PRE;
|
||||
int lenx = sizeof(buf) - LWS_PRE;
|
||||
/*
|
||||
* our sink is writeable and our source has something
|
||||
* to read. So read a lump of source material of
|
||||
* suitable size to send or what's available, whichever
|
||||
* is the smaller.
|
||||
*/
|
||||
|
||||
wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__PROXY;
|
||||
if (!lws_get_child(wsi))
|
||||
break;
|
||||
if (lws_http_client_read(lws_get_child(wsi), &px, &lenx) < 0)
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
#if defined(LWS_WITH_HTTP_PROXY)
|
||||
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
|
||||
//lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP: wsi %p\n", wsi);
|
||||
assert(lws_get_parent(wsi));
|
||||
if (!lws_get_parent(wsi))
|
||||
break;
|
||||
lws_get_parent(wsi)->reason_bf |= LWS_CB_REASON_AUX_BF__PROXY;
|
||||
lws_callback_on_writable(lws_get_parent(wsi));
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
|
||||
//lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ len %d\n", (int)len);
|
||||
assert(lws_get_parent(wsi));
|
||||
n = lws_write(lws_get_parent(wsi), (unsigned char *)in,
|
||||
len, LWS_WRITE_HTTP);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: {
|
||||
unsigned char *p, *end;
|
||||
char ctype[64], ctlen = 0;
|
||||
|
||||
//lwsl_err("LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP\n");
|
||||
|
||||
p = (unsigned char *)buf + LWS_PRE;
|
||||
end = p + sizeof(buf) - LWS_PRE;
|
||||
|
||||
if (lws_add_http_header_status(lws_get_parent(wsi), HTTP_STATUS_OK, &p, end))
|
||||
return 1;
|
||||
if (lws_add_http_header_by_token(lws_get_parent(wsi),
|
||||
WSI_TOKEN_HTTP_SERVER,
|
||||
(unsigned char *)"libwebsockets",
|
||||
13, &p, end))
|
||||
return 1;
|
||||
|
||||
ctlen = lws_hdr_copy(wsi, ctype, sizeof(ctype), WSI_TOKEN_HTTP_CONTENT_TYPE);
|
||||
if (ctlen > 0) {
|
||||
if (lws_add_http_header_by_token(lws_get_parent(wsi),
|
||||
WSI_TOKEN_HTTP_CONTENT_TYPE,
|
||||
(unsigned char *)ctype, ctlen, &p, end))
|
||||
return 1;
|
||||
}
|
||||
#if 0
|
||||
if (lws_add_http_header_content_length(lws_get_parent(wsi),
|
||||
file_len, &p, end))
|
||||
return 1;
|
||||
#endif
|
||||
if (lws_finalize_http_header(lws_get_parent(wsi), &p, end))
|
||||
return 1;
|
||||
|
||||
*p = '\0';
|
||||
// lwsl_info("%s\n", buf + LWS_PRE);
|
||||
|
||||
n = lws_write(lws_get_parent(wsi), (unsigned char *)buf + LWS_PRE,
|
||||
p - ((unsigned char *)buf + LWS_PRE),
|
||||
LWS_WRITE_HTTP_HEADERS);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
|
||||
break; }
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef LWS_WITH_CGI
|
||||
/* CGI IO events (POLLIN/OUT) appear here, our default policy is:
|
||||
*
|
||||
|
@ -264,7 +364,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
/* TBD stdin rx flow control */
|
||||
break;
|
||||
case LWS_STDOUT:
|
||||
wsi->reason_bf |= 1;
|
||||
wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI;
|
||||
/* when writing to MASTER would not block */
|
||||
lws_callback_on_writable(wsi);
|
||||
break;
|
||||
|
@ -282,6 +382,11 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
break;
|
||||
|
||||
case LWS_CALLBACK_CGI_TERMINATED:
|
||||
if (!wsi->cgi->explicitly_chunked && !wsi->cgi->content_length) {
|
||||
/* send terminating chunk */
|
||||
wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI_CHUNK_END;
|
||||
lws_callback_on_writable(wsi);
|
||||
}
|
||||
return -1;
|
||||
|
||||
case LWS_CALLBACK_CGI_STDIN_DATA: /* POST body for stdin */
|
||||
|
@ -294,6 +399,17 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
"sent %d only %d went", n, args->len);
|
||||
return n;
|
||||
#endif
|
||||
|
||||
case LWS_CALLBACK_SSL_INFO:
|
||||
{
|
||||
struct lws_ssl_info *si = in;
|
||||
|
||||
(void)si;
|
||||
lwsl_notice("LWS_CALLBACK_SSL_INFO: where: 0x%x, ret: 0x%x\n",
|
||||
si->where, si->ret);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -311,12 +427,12 @@ static const struct lws_protocols protocols_dummy[] = {
|
|||
lws_callback_http_dummy, /* callback */
|
||||
0, /* per_session_data_size */
|
||||
0, /* max frame size / rx buffer */
|
||||
0, NULL
|
||||
0, NULL, 0
|
||||
},
|
||||
/*
|
||||
* the other protocols are provided by lws plugins
|
||||
*/
|
||||
{ NULL, NULL, 0, 0, 0, NULL} /* terminator */
|
||||
{ NULL, NULL, 0, 0, 0, NULL, 0} /* terminator */
|
||||
};
|
||||
|
||||
#ifdef LWS_PLAT_OPTEE
|
||||
|
@ -354,6 +470,10 @@ lws_create_vhost(struct lws_context *context,
|
|||
vh->name = info->vhost_name;
|
||||
|
||||
vh->iface = info->iface;
|
||||
#if !defined(LWS_WITH_ESP8266) && !defined(LWS_WITH_ESP32) && !defined(OPTEE_TA) && !defined(WIN32)
|
||||
vh->bind_iface = info->bind_iface;
|
||||
#endif
|
||||
|
||||
for (vh->count_protocols = 0;
|
||||
info->protocols[vh->count_protocols].callback;
|
||||
vh->count_protocols++)
|
||||
|
@ -362,11 +482,17 @@ lws_create_vhost(struct lws_context *context,
|
|||
vh->options = info->options;
|
||||
vh->pvo = info->pvo;
|
||||
vh->headers = info->headers;
|
||||
vh->ssl_info_event_mask = info->ssl_info_event_mask;
|
||||
if (info->keepalive_timeout)
|
||||
vh->keepalive_timeout = info->keepalive_timeout;
|
||||
else
|
||||
vh->keepalive_timeout = 5;
|
||||
|
||||
if (info->timeout_secs_ah_idle)
|
||||
vh->timeout_secs_ah_idle = info->timeout_secs_ah_idle;
|
||||
else
|
||||
vh->timeout_secs_ah_idle = 10;
|
||||
|
||||
/*
|
||||
* give the vhost a unified list of protocols including the
|
||||
* ones that came from plugins
|
||||
|
@ -387,7 +513,7 @@ lws_create_vhost(struct lws_context *context,
|
|||
* for a protocol get it enabled.
|
||||
*/
|
||||
|
||||
if (info->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
|
||||
if (context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
|
||||
f = 0;
|
||||
(void)f;
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
|
@ -417,7 +543,7 @@ lws_create_vhost(struct lws_context *context,
|
|||
#ifdef LWS_WITH_PLUGINS
|
||||
(context->plugin_list) ||
|
||||
#endif
|
||||
info->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
|
||||
context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
|
||||
vh->protocols = lwsp;
|
||||
else {
|
||||
vh->protocols = info->protocols;
|
||||
|
@ -440,6 +566,7 @@ lws_create_vhost(struct lws_context *context,
|
|||
|
||||
mounts = info->mounts;
|
||||
while (mounts) {
|
||||
(void)mount_protocols[0];
|
||||
lwsl_notice(" mounting %s%s to %s\n",
|
||||
mount_protocols[mounts->origin_protocol],
|
||||
mounts->origin, mounts->mountpoint);
|
||||
|
@ -450,7 +577,7 @@ lws_create_vhost(struct lws_context *context,
|
|||
for (n = 0; n < vh->count_protocols; n++)
|
||||
if (!strcmp(pvo->value, vh->protocols[n].name)) {
|
||||
((struct lws_protocol_vhost_options *)pvo)->value =
|
||||
(const char *)(long)n;
|
||||
(const char *)(lws_intptr_t)n;
|
||||
break;
|
||||
}
|
||||
if (n == vh->count_protocols)
|
||||
|
@ -499,9 +626,14 @@ lws_create_vhost(struct lws_context *context,
|
|||
#if !defined(LWS_WITH_ESP8266)
|
||||
vh->http_proxy_port = 0;
|
||||
vh->http_proxy_address[0] = '\0';
|
||||
#if defined(LWS_WITH_SOCKS5)
|
||||
vh->socks_proxy_port = 0;
|
||||
vh->socks_proxy_address[0] = '\0';
|
||||
#endif
|
||||
|
||||
/* either use proxy from info, or try get it from env var */
|
||||
|
||||
/* http proxy */
|
||||
if (info->http_proxy_address) {
|
||||
/* override for backwards compatibility */
|
||||
if (info->http_proxy_port)
|
||||
|
@ -514,7 +646,23 @@ lws_create_vhost(struct lws_context *context,
|
|||
lws_set_proxy(vh, p);
|
||||
#endif
|
||||
}
|
||||
#if defined(LWS_WITH_SOCKS5)
|
||||
/* socks proxy */
|
||||
if (info->socks_proxy_address) {
|
||||
/* override for backwards compatibility */
|
||||
if (info->socks_proxy_port)
|
||||
vh->socks_proxy_port = info->socks_proxy_port;
|
||||
lws_set_socks(vh, info->socks_proxy_address);
|
||||
} else {
|
||||
#ifdef LWS_HAVE_GETENV
|
||||
p = getenv("socks_proxy");
|
||||
if (p)
|
||||
lws_set_socks(vh, p);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
vh->ka_time = info->ka_time;
|
||||
vh->ka_interval = info->ka_interval;
|
||||
vh->ka_probes = info->ka_probes;
|
||||
|
@ -618,6 +766,9 @@ lws_create_context(struct lws_context_creation_info *info)
|
|||
lwsl_info(" LWS_MAX_SMP : %u\n", LWS_MAX_SMP);
|
||||
lwsl_info(" SPEC_LATEST_SUPPORTED : %u\n", SPEC_LATEST_SUPPORTED);
|
||||
lwsl_info(" sizeof (*info) : %ld\n", (long)sizeof(*info));
|
||||
#if defined(LWS_WITH_STATS)
|
||||
lwsl_notice(" LWS_WITH_STATS : on\n");
|
||||
#endif
|
||||
#if LWS_POSIX
|
||||
lwsl_info(" SYSTEM_RANDOM_FILEPATH: '%s'\n", SYSTEM_RANDOM_FILEPATH);
|
||||
#endif
|
||||
|
@ -672,6 +823,8 @@ lws_create_context(struct lws_context_creation_info *info)
|
|||
|
||||
context->time_up = time(NULL);
|
||||
|
||||
context->simultaneous_ssl_restriction = info->simultaneous_ssl_restriction;
|
||||
|
||||
#ifndef LWS_NO_DAEMONIZE
|
||||
if (pid_daemon) {
|
||||
context->started_with_parent = pid_daemon;
|
||||
|
@ -789,6 +942,16 @@ lws_create_context(struct lws_context_creation_info *info)
|
|||
context->use_ev_sigint = 1;
|
||||
context->lws_uv_sigint_cb = &lws_uv_sigint_cb;
|
||||
#endif
|
||||
#ifdef LWS_USE_LIBEVENT
|
||||
/* (Issue #264) In order to *avoid breaking backwards compatibility*, we
|
||||
* enable libev mediated SIGINT handling with a default handler of
|
||||
* lws_sigint_cb. The handler can be overridden or disabled
|
||||
* by invoking lws_sigint_cfg after creating the context, but
|
||||
* before invoking lws_initloop:
|
||||
*/
|
||||
context->use_ev_sigint = 1;
|
||||
context->lws_event_sigint_cb = &lws_event_sigint_cb;
|
||||
#endif /* LWS_USE_LIBEVENT */
|
||||
|
||||
lwsl_info(" mem: context: %5lu bytes (%ld ctx + (%ld thr x %d))\n",
|
||||
(long)sizeof(struct lws_context) +
|
||||
|
@ -855,6 +1018,11 @@ lws_create_context(struct lws_context_creation_info *info)
|
|||
context->uid = info->uid;
|
||||
context->gid = info->gid;
|
||||
|
||||
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
|
||||
memcpy(context->caps, info->caps, sizeof(context->caps));
|
||||
context->count_caps = info->count_caps;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* drop any root privs for this process
|
||||
* to listen on port < 1023 we would have needed root, but now we are
|
||||
|
@ -933,10 +1101,242 @@ lws_context_is_deprecated(struct lws_context *context)
|
|||
LWS_VISIBLE void
|
||||
lws_context_destroy2(struct lws_context *context);
|
||||
|
||||
|
||||
static void
|
||||
lws_vhost_destroy1(struct lws_vhost *vh)
|
||||
{
|
||||
const struct lws_protocols *protocol = NULL;
|
||||
struct lws_context_per_thread *pt;
|
||||
int n, m = vh->context->count_threads;
|
||||
struct lws_context *context = vh->context;
|
||||
struct lws wsi;
|
||||
|
||||
lwsl_notice("%s\n", __func__);
|
||||
|
||||
if (vh->being_destroyed)
|
||||
return;
|
||||
|
||||
vh->being_destroyed = 1;
|
||||
|
||||
/*
|
||||
* Are there other vhosts that are piggybacking on our listen socket?
|
||||
* If so we need to hand the listen socket off to one of the others
|
||||
* so it will remain open. If not, leave it attached to the closing
|
||||
* vhost and it will get closed.
|
||||
*/
|
||||
|
||||
if (vh->lserv_wsi)
|
||||
lws_start_foreach_ll(struct lws_vhost *, v, context->vhost_list) {
|
||||
if (v != vh &&
|
||||
!v->being_destroyed &&
|
||||
v->listen_port == vh->listen_port &&
|
||||
((!v->iface && !vh->iface) ||
|
||||
(v->iface && vh->iface &&
|
||||
!strcmp(v->iface, vh->iface)))) {
|
||||
/*
|
||||
* this can only be a listen wsi, which is
|
||||
* restricted... it has no protocol or other
|
||||
* bindings or states. So we can simply
|
||||
* swap it to a vhost that has the same
|
||||
* iface + port, but is not closing.
|
||||
*/
|
||||
assert(v->lserv_wsi == NULL);
|
||||
v->lserv_wsi = vh->lserv_wsi;
|
||||
vh->lserv_wsi = NULL;
|
||||
v->lserv_wsi->vhost = v;
|
||||
|
||||
lwsl_notice("%s: listen skt from %s to %s\n",
|
||||
__func__, vh->name, v->name);
|
||||
break;
|
||||
}
|
||||
} lws_end_foreach_ll(v, vhost_next);
|
||||
|
||||
/*
|
||||
* Forcibly close every wsi assoicated with this vhost. That will
|
||||
* include the listen socket if it is still associated with the closing
|
||||
* vhost.
|
||||
*/
|
||||
|
||||
while (m--) {
|
||||
pt = &context->pt[m];
|
||||
|
||||
for (n = 0; (unsigned int)n < context->pt[m].fds_count; n++) {
|
||||
struct lws *wsi = wsi_from_fd(context, pt->fds[n].fd);
|
||||
if (!wsi)
|
||||
continue;
|
||||
if (wsi->vhost != vh)
|
||||
continue;
|
||||
|
||||
lws_close_free_wsi(wsi,
|
||||
LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY
|
||||
/* no protocol close */);
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* let the protocols destroy the per-vhost protocol objects
|
||||
*/
|
||||
|
||||
memset(&wsi, 0, sizeof(wsi));
|
||||
wsi.context = vh->context;
|
||||
wsi.vhost = vh;
|
||||
protocol = vh->protocols;
|
||||
if (protocol) {
|
||||
n = 0;
|
||||
while (n < vh->count_protocols) {
|
||||
wsi.protocol = protocol;
|
||||
protocol->callback(&wsi, LWS_CALLBACK_PROTOCOL_DESTROY,
|
||||
NULL, NULL, 0);
|
||||
protocol++;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* remove vhost from context list of vhosts
|
||||
*/
|
||||
|
||||
lws_start_foreach_llp(struct lws_vhost **, pv, context->vhost_list) {
|
||||
if (*pv == vh) {
|
||||
*pv = vh->vhost_next;
|
||||
break;
|
||||
}
|
||||
} lws_end_foreach_llp(pv, vhost_next);
|
||||
|
||||
/* add ourselves to the pending destruction list */
|
||||
|
||||
vh->vhost_next = vh->context->vhost_pending_destruction_list;
|
||||
vh->context->vhost_pending_destruction_list = vh;
|
||||
}
|
||||
|
||||
static void
|
||||
lws_vhost_destroy2(struct lws_vhost *vh)
|
||||
{
|
||||
const struct lws_protocols *protocol = NULL;
|
||||
struct lws_context *context = vh->context;
|
||||
struct lws_deferred_free *df;
|
||||
int n;
|
||||
|
||||
lwsl_notice("%s: %p\n", __func__, vh);
|
||||
|
||||
/* if we are still on deferred free list, remove ourselves */
|
||||
|
||||
lws_start_foreach_llp(struct lws_deferred_free **, pdf, context->deferred_free_list) {
|
||||
if ((*pdf)->payload == vh) {
|
||||
df = *pdf;
|
||||
*pdf = df->next;
|
||||
lws_free(df);
|
||||
break;
|
||||
}
|
||||
} lws_end_foreach_llp(pdf, next);
|
||||
|
||||
/* remove ourselves from the pending destruction list */
|
||||
|
||||
lws_start_foreach_llp(struct lws_vhost **, pv, context->vhost_pending_destruction_list) {
|
||||
if ((*pv) == vh) {
|
||||
*pv = (*pv)->vhost_next;
|
||||
break;
|
||||
}
|
||||
} lws_end_foreach_llp(pv, vhost_next);
|
||||
|
||||
/*
|
||||
* Free all the allocations associated with the vhost
|
||||
*/
|
||||
|
||||
protocol = vh->protocols;
|
||||
if (protocol) {
|
||||
n = 0;
|
||||
while (n < vh->count_protocols) {
|
||||
if (vh->protocol_vh_privs &&
|
||||
vh->protocol_vh_privs[n]) {
|
||||
lws_free(vh->protocol_vh_privs[n]);
|
||||
vh->protocol_vh_privs[n] = NULL;
|
||||
}
|
||||
protocol++;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
if (vh->protocol_vh_privs)
|
||||
lws_free(vh->protocol_vh_privs);
|
||||
lws_ssl_SSL_CTX_destroy(vh);
|
||||
lws_free(vh->same_vh_protocol_list);
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
if (LWS_LIBUV_ENABLED(context)) {
|
||||
if (context->plugin_list)
|
||||
lws_free((void *)vh->protocols);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
|
||||
lws_free((void *)vh->protocols);
|
||||
}
|
||||
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
if (context->plugin_extension_count)
|
||||
lws_free((void *)vh->extensions);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef LWS_WITH_ACCESS_LOG
|
||||
if (vh->log_fd != (int)LWS_INVALID_FILE)
|
||||
close(vh->log_fd);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* although async event callbacks may still come for wsi handles with
|
||||
* pending close in the case of asycn event library like libuv,
|
||||
* they do not refer to the vhost. So it's safe to free.
|
||||
*/
|
||||
|
||||
lwsl_notice(" %s: Freeing vhost %p\n", __func__, vh);
|
||||
|
||||
memset(vh, 0, sizeof(*vh));
|
||||
free(vh);
|
||||
}
|
||||
|
||||
int
|
||||
lws_check_deferred_free(struct lws_context *context, int force)
|
||||
{
|
||||
struct lws_deferred_free *df;
|
||||
time_t now = lws_now_secs();
|
||||
|
||||
lws_start_foreach_llp(struct lws_deferred_free **, pdf, context->deferred_free_list) {
|
||||
if (now > (*pdf)->deadline || force) {
|
||||
df = *pdf;
|
||||
*pdf = df->next;
|
||||
/* finalize vh destruction */
|
||||
lwsl_notice("doing deferred vh %p destroy\n", df->payload);
|
||||
lws_vhost_destroy2(df->payload);
|
||||
lws_free(df);
|
||||
continue; /* after deletion we already point to next */
|
||||
}
|
||||
} lws_end_foreach_llp(pdf, next);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_vhost_destroy(struct lws_vhost *vh)
|
||||
{
|
||||
struct lws_deferred_free *df = malloc(sizeof(*df));
|
||||
|
||||
if (!df)
|
||||
return;
|
||||
|
||||
lws_vhost_destroy1(vh);
|
||||
|
||||
/* part 2 is deferred to allow all the handle closes to complete */
|
||||
|
||||
df->next = vh->context->deferred_free_list;
|
||||
df->deadline = lws_now_secs() + 5;
|
||||
df->payload = vh;
|
||||
vh->context->deferred_free_list = df;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_context_destroy(struct lws_context *context)
|
||||
{
|
||||
const struct lws_protocols *protocol = NULL;
|
||||
struct lws_context_per_thread *pt;
|
||||
struct lws_vhost *vh = NULL;
|
||||
struct lws wsi;
|
||||
|
@ -1001,19 +1401,7 @@ lws_context_destroy(struct lws_context *context)
|
|||
if (context->protocol_init_done)
|
||||
vh = context->vhost_list;
|
||||
while (vh) {
|
||||
wsi.vhost = vh;
|
||||
protocol = vh->protocols;
|
||||
if (protocol) {
|
||||
n = 0;
|
||||
while (n < vh->count_protocols) {
|
||||
wsi.protocol = protocol;
|
||||
protocol->callback(&wsi, LWS_CALLBACK_PROTOCOL_DESTROY,
|
||||
NULL, NULL, 0);
|
||||
protocol++;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
lws_vhost_destroy1(vh);
|
||||
vh = vh->vhost_next;
|
||||
}
|
||||
|
||||
|
@ -1022,6 +1410,7 @@ lws_context_destroy(struct lws_context *context)
|
|||
|
||||
lws_libev_destroyloop(context, n);
|
||||
lws_libuv_destroyloop(context, n);
|
||||
lws_libevent_destroyloop(context, n);
|
||||
|
||||
lws_free_set_NULL(context->pt[n].serv_buf);
|
||||
if (pt->ah_pool)
|
||||
|
@ -1045,9 +1434,7 @@ lws_context_destroy(struct lws_context *context)
|
|||
LWS_VISIBLE void
|
||||
lws_context_destroy2(struct lws_context *context)
|
||||
{
|
||||
const struct lws_protocols *protocol = NULL;
|
||||
struct lws_vhost *vh = NULL, *vh1;
|
||||
int n;
|
||||
|
||||
lwsl_notice("%s: ctx %p\n", __func__, context);
|
||||
|
||||
|
@ -1057,53 +1444,27 @@ lws_context_destroy2(struct lws_context *context)
|
|||
|
||||
vh = context->vhost_list;
|
||||
while (vh) {
|
||||
protocol = vh->protocols;
|
||||
if (protocol) {
|
||||
n = 0;
|
||||
while (n < vh->count_protocols) {
|
||||
if (vh->protocol_vh_privs &&
|
||||
vh->protocol_vh_privs[n]) {
|
||||
// lwsl_notice(" %s: freeing per-vhost protocol data %p\n", __func__, vh->protocol_vh_privs[n]);
|
||||
lws_free(vh->protocol_vh_privs[n]);
|
||||
vh->protocol_vh_privs[n] = NULL;
|
||||
}
|
||||
protocol++;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
if (vh->protocol_vh_privs)
|
||||
lws_free(vh->protocol_vh_privs);
|
||||
lws_ssl_SSL_CTX_destroy(vh);
|
||||
lws_free(vh->same_vh_protocol_list);
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
if (context->plugin_list)
|
||||
lws_free((void *)vh->protocols);
|
||||
#else
|
||||
if (vh->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
|
||||
lws_free((void *)vh->protocols);
|
||||
#endif
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
if (context->plugin_extension_count)
|
||||
lws_free((void *)vh->extensions);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef LWS_WITH_ACCESS_LOG
|
||||
if (vh->log_fd != (int)LWS_INVALID_FILE)
|
||||
close(vh->log_fd);
|
||||
#endif
|
||||
|
||||
vh1 = vh->vhost_next;
|
||||
lws_free(vh);
|
||||
lws_vhost_destroy2(vh);
|
||||
vh = vh1;
|
||||
}
|
||||
|
||||
/* remove ourselves from the pending destruction list */
|
||||
|
||||
while (context->vhost_pending_destruction_list)
|
||||
/* removes itself from list */
|
||||
lws_vhost_destroy2(context->vhost_pending_destruction_list);
|
||||
|
||||
|
||||
lws_stats_log_dump(context);
|
||||
|
||||
lws_ssl_context_destroy(context);
|
||||
lws_plat_context_late_destroy(context);
|
||||
|
||||
if (context->external_baggage_free_on_destroy)
|
||||
free(context->external_baggage_free_on_destroy);
|
||||
|
||||
lws_check_deferred_free(context, 1);
|
||||
|
||||
lws_free(context);
|
||||
}
|
||||
|
|
|
@ -94,13 +94,16 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
|
|||
|
||||
case LWS_EXT_CB_OPTION_SET:
|
||||
oa = in;
|
||||
lwsl_info("%s: option set: idx %d, %s, len %d\n", __func__,
|
||||
lwsl_notice("%s: option set: idx %d, %s, len %d\n", __func__,
|
||||
oa->option_index, oa->start, oa->len);
|
||||
if (oa->start)
|
||||
priv->args[oa->option_index] = atoi(oa->start);
|
||||
else
|
||||
priv->args[oa->option_index] = 1;
|
||||
|
||||
if (priv->args[PMD_CLIENT_MAX_WINDOW_BITS] == 8)
|
||||
priv->args[PMD_CLIENT_MAX_WINDOW_BITS] = 9;
|
||||
|
||||
lws_extension_pmdeflate_restrict_args(wsi, priv);
|
||||
break;
|
||||
|
||||
|
@ -325,16 +328,18 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
|
|||
|
||||
case LWS_EXT_CB_PAYLOAD_TX:
|
||||
|
||||
if (!priv->tx_init)
|
||||
if (deflateInit2(&priv->tx, priv->args[PMD_COMP_LEVEL],
|
||||
if (!priv->tx_init) {
|
||||
n = deflateInit2(&priv->tx, priv->args[PMD_COMP_LEVEL],
|
||||
Z_DEFLATED,
|
||||
-priv->args[PMD_CLIENT_MAX_WINDOW_BITS +
|
||||
!wsi->vhost->listen_port],
|
||||
-priv->args[PMD_SERVER_MAX_WINDOW_BITS +
|
||||
(wsi->vhost->listen_port <= 0)],
|
||||
priv->args[PMD_MEM_LEVEL],
|
||||
Z_DEFAULT_STRATEGY) != Z_OK) {
|
||||
lwsl_ext("inflateInit2 failed\n");
|
||||
Z_DEFAULT_STRATEGY);
|
||||
if (n != Z_OK) {
|
||||
lwsl_ext("inflateInit2 failed %d\n", n);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
priv->tx_init = 1;
|
||||
if (!priv->buf_tx_deflated)
|
||||
priv->buf_tx_deflated = lws_malloc(LWS_PRE + 7 + 5 +
|
||||
|
@ -436,7 +441,9 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
|
|||
break;
|
||||
priv->compressed_out = 0;
|
||||
|
||||
if ((*(eff_buf->token) & 0x80) && priv->args[PMD_CLIENT_NO_CONTEXT_TAKEOVER]) {
|
||||
if ((*(eff_buf->token) & 0x80) &&
|
||||
priv->args[PMD_CLIENT_NO_CONTEXT_TAKEOVER]) {
|
||||
lwsl_debug("PMD_CLIENT_NO_CONTEXT_TAKEOVER\n");
|
||||
(void)deflateEnd(&priv->tx);
|
||||
priv->tx_init = 0;
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ lws_ext_parse_options(const struct lws_extension *ext, struct lws *wsi,
|
|||
oa.option_index = n;
|
||||
lwsl_ext("hit %d\n", oa.option_index);
|
||||
leap = LEAPS_SEEK_VAL;
|
||||
if (len ==1)
|
||||
if (len == 1)
|
||||
goto set_arg;
|
||||
break;
|
||||
}
|
||||
|
@ -195,7 +195,7 @@ int lws_ext_cb_all_exts(struct lws_context *context, struct lws *wsi,
|
|||
|
||||
while (ext && ext->callback && !handled) {
|
||||
m = ext->callback(context, ext, wsi, reason,
|
||||
(void *)(long)n, arg, len);
|
||||
(void *)(lws_intptr_t)n, arg, len);
|
||||
if (m < 0) {
|
||||
lwsl_ext("Ext '%s' failed to handle callback %d!\n",
|
||||
wsi->active_extensions[n]->name, reason);
|
||||
|
|
|
@ -178,7 +178,7 @@ int
|
|||
lws_fops_zip_scan(lws_fops_zip_t priv, const char *name, int len)
|
||||
{
|
||||
lws_filepos_t amount;
|
||||
uint8_t buf[64];
|
||||
uint8_t buf[96];
|
||||
int i;
|
||||
|
||||
if (lws_vfs_file_seek_end(priv->zip_fop_fd, -ZE_DIRECTORY_LENGTH) < 0)
|
||||
|
@ -535,7 +535,7 @@ lws_fops_zip_read(lws_fop_fd_t fd, lws_filepos_t *amount, uint8_t *buf,
|
|||
*amount = 0;
|
||||
}
|
||||
|
||||
priv->inflate.avail_out = len;
|
||||
priv->inflate.avail_out = (unsigned int)len;
|
||||
priv->inflate.next_out = buf;
|
||||
|
||||
spin:
|
||||
|
@ -554,7 +554,7 @@ spin:
|
|||
|
||||
cur += ramount;
|
||||
|
||||
priv->inflate.avail_in = ramount;
|
||||
priv->inflate.avail_in = (unsigned int)ramount;
|
||||
priv->inflate.next_in = priv->rbuf;
|
||||
}
|
||||
|
||||
|
@ -596,7 +596,7 @@ spin:
|
|||
if (rlen > len)
|
||||
rlen = len;
|
||||
/* provide stuff from canned header */
|
||||
memcpy(buf, hd + fd->pos, rlen);
|
||||
memcpy(buf, hd + fd->pos, (size_t)rlen);
|
||||
fd->pos += rlen;
|
||||
buf += rlen;
|
||||
len -= rlen;
|
||||
|
@ -636,7 +636,7 @@ spin:
|
|||
if (rlen > len)
|
||||
rlen = len;
|
||||
|
||||
memcpy(buf, priv->u.trailer8 + cur, rlen);
|
||||
memcpy(buf, priv->u.trailer8 + cur, (size_t)rlen);
|
||||
|
||||
*amount += rlen;
|
||||
fd->pos += rlen;
|
||||
|
|
|
@ -229,7 +229,7 @@ print_addr(const char *s, struct sockaddr *sa)
|
|||
printf(" %s=%d/", s, sa->sa_family);
|
||||
#ifdef LWS_HAVE_STRUCT_SOCKADDR_SA_LEN
|
||||
for (i = 0;
|
||||
i < sa->sa_len - ((long)sa->sa_data - (long)&sa->sa_family); i++)
|
||||
i < sa->sa_len - ((lws_intptr_t)sa->sa_data - (lws_intptr_t)&sa->sa_family); i++)
|
||||
printf("%02x", ((unsigned char *)sa->sa_data)[i]);
|
||||
#else
|
||||
for (i = 0; i < sizeof(sa->sa_data); i++)
|
||||
|
|
|
@ -60,10 +60,10 @@
|
|||
*/
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_read(struct lws *wsi, unsigned char *buf, size_t len)
|
||||
lws_read(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
|
||||
{
|
||||
unsigned char *last_char, *oldbuf = buf;
|
||||
int body_chunk_len;
|
||||
lws_filepos_t body_chunk_len;
|
||||
size_t n;
|
||||
|
||||
lwsl_debug("%s: incoming len %d state %d\n", __func__, (int)len, wsi->state);
|
||||
|
@ -95,17 +95,16 @@ lws_read(struct lws *wsi, unsigned char *buf, size_t len)
|
|||
break;
|
||||
#endif
|
||||
|
||||
case LWSS_HTTP_ISSUING_FILE:
|
||||
return 0;
|
||||
|
||||
case LWSS_CLIENT_HTTP_ESTABLISHED:
|
||||
break;
|
||||
|
||||
case LWSS_HTTP:
|
||||
wsi->hdr_parsing_completed = 0;
|
||||
/* fallthru */
|
||||
case LWSS_HTTP_ISSUING_FILE:
|
||||
wsi->state = LWSS_HTTP_HEADERS;
|
||||
wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
|
||||
wsi->u.hdr.lextable_pos = 0;
|
||||
/* fallthru */
|
||||
|
||||
case LWSS_HTTP_HEADERS:
|
||||
if (!wsi->u.hdr.ah) {
|
||||
lwsl_err("%s: LWSS_HTTP_HEADERS: NULL ah\n", __func__);
|
||||
|
@ -113,11 +112,11 @@ lws_read(struct lws *wsi, unsigned char *buf, size_t len)
|
|||
}
|
||||
lwsl_parser("issuing %d bytes to parser\n", (int)len);
|
||||
|
||||
if (lws_handshake_client(wsi, &buf, len))
|
||||
if (lws_handshake_client(wsi, &buf, (size_t)len))
|
||||
goto bail;
|
||||
|
||||
last_char = buf;
|
||||
if (lws_handshake_server(wsi, &buf, len))
|
||||
if (lws_handshake_server(wsi, &buf, (size_t)len))
|
||||
/* Handshake indicates this session is done. */
|
||||
goto bail;
|
||||
|
||||
|
@ -190,10 +189,10 @@ http_postbody:
|
|||
#endif
|
||||
n = wsi->protocol->callback(wsi,
|
||||
LWS_CALLBACK_HTTP_BODY, wsi->user_space,
|
||||
buf, body_chunk_len);
|
||||
buf, (size_t)body_chunk_len);
|
||||
if (n)
|
||||
goto bail;
|
||||
n = body_chunk_len;
|
||||
n = (size_t)body_chunk_len;
|
||||
#ifdef LWS_WITH_CGI
|
||||
}
|
||||
#endif
|
||||
|
@ -230,13 +229,14 @@ postbody_completion:
|
|||
|
||||
case LWSS_ESTABLISHED:
|
||||
case LWSS_AWAITING_CLOSE_ACK:
|
||||
case LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION:
|
||||
case LWSS_SHUTDOWN:
|
||||
if (lws_handshake_client(wsi, &buf, len))
|
||||
if (lws_handshake_client(wsi, &buf, (size_t)len))
|
||||
goto bail;
|
||||
switch (wsi->mode) {
|
||||
case LWSCM_WS_SERVING:
|
||||
|
||||
if (lws_interpret_incoming_packet(wsi, &buf, len) < 0) {
|
||||
if (lws_interpret_incoming_packet(wsi, &buf, (size_t)len) < 0) {
|
||||
lwsl_info("interpret_incoming_packet has bailed\n");
|
||||
goto bail;
|
||||
}
|
||||
|
|
43
lib/header.c
43
lib/header.c
|
@ -71,7 +71,7 @@ int lws_finalize_http_header(struct lws *wsi, unsigned char **p,
|
|||
#else
|
||||
(void)wsi;
|
||||
#endif
|
||||
if ((long)(end - *p) < 3)
|
||||
if ((lws_intptr_t)(end - *p) < 3)
|
||||
return 1;
|
||||
*((*p)++) = '\x0d';
|
||||
*((*p)++) = '\x0a';
|
||||
|
@ -96,13 +96,13 @@ lws_add_http_header_by_token(struct lws *wsi, enum lws_token_indexes token,
|
|||
}
|
||||
|
||||
int lws_add_http_header_content_length(struct lws *wsi,
|
||||
unsigned long content_length,
|
||||
lws_filepos_t content_length,
|
||||
unsigned char **p, unsigned char *end)
|
||||
{
|
||||
char b[24];
|
||||
int n;
|
||||
|
||||
n = sprintf(b, "%lu", content_length);
|
||||
n = sprintf(b, "%llu", (unsigned long long)content_length);
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
|
||||
(unsigned char *)b, n, p, end))
|
||||
return 1;
|
||||
|
@ -222,17 +222,14 @@ lws_return_http_status(struct lws *wsi, unsigned int code,
|
|||
struct lws_context *context = lws_get_context(wsi);
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
unsigned char *p = pt->serv_buf + LWS_PRE;
|
||||
unsigned char *start = p, *body = p + 512;
|
||||
unsigned char *start = p;
|
||||
unsigned char *end = p + context->pt_serv_buf_size - LWS_PRE;
|
||||
int n, m, len;
|
||||
int n = 0, m, len;
|
||||
char slen[20];
|
||||
|
||||
if (!html_body)
|
||||
html_body = "";
|
||||
|
||||
len = sprintf((char *)body, "<html><body><h1>%u</h1>%s</body></html>",
|
||||
code, html_body);
|
||||
|
||||
if (lws_add_http_header_status(wsi, code, &p, end))
|
||||
return 1;
|
||||
|
||||
|
@ -240,7 +237,10 @@ lws_return_http_status(struct lws *wsi, unsigned int code,
|
|||
(unsigned char *)"text/html", 9,
|
||||
&p, end))
|
||||
return 1;
|
||||
|
||||
len = 35 + strlen(html_body) + sprintf(slen, "%d", code);
|
||||
n = sprintf(slen, "%d", len);
|
||||
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
|
||||
(unsigned char *)slen, n,
|
||||
&p, end))
|
||||
|
@ -249,11 +249,30 @@ lws_return_http_status(struct lws *wsi, unsigned int code,
|
|||
if (lws_finalize_http_header(wsi, &p, end))
|
||||
return 1;
|
||||
|
||||
m = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
|
||||
if (m != (int)(p - start))
|
||||
return 1;
|
||||
#if defined(LWS_USE_HTTP2)
|
||||
{
|
||||
unsigned char *body = p + 512;
|
||||
|
||||
m = lws_write(wsi, body, len, LWS_WRITE_HTTP);
|
||||
m = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
|
||||
if (m != (int)(p - start))
|
||||
return 1;
|
||||
|
||||
len = sprintf((char *)body, "<html><body><h1>%u</h1>%s</body></html>",
|
||||
code, html_body);
|
||||
|
||||
n = len;
|
||||
m = lws_write(wsi, body, len, LWS_WRITE_HTTP);
|
||||
}
|
||||
#else
|
||||
p += lws_snprintf((char *)p, end - p - 1,
|
||||
"<html><body><h1>%u</h1>%s</body></html>",
|
||||
code, html_body);
|
||||
|
||||
n = (int)(p - start);
|
||||
m = lws_write(wsi, start, n, LWS_WRITE_HTTP);
|
||||
if (m != n)
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
return m != n;
|
||||
}
|
||||
|
|
|
@ -320,7 +320,7 @@ lws_http2_parser(struct lws *wsi, unsigned char c)
|
|||
break;
|
||||
case LWS_HTTP2_FRAME_TYPE_WINDOW_UPDATE:
|
||||
wsi->u.http2.hpack_e_dep &= ~(1 << 31);
|
||||
if ((long long)swsi->u.http2.tx_credit + (unsigned long long)wsi->u.http2.hpack_e_dep > (~(1 << 31)))
|
||||
if ((lws_intptr_t)swsi->u.http2.tx_credit + (lws_intptr_t)wsi->u.http2.hpack_e_dep > (~(1 << 31)))
|
||||
return 1; /* actually need to close swsi not the whole show */
|
||||
swsi->u.http2.tx_credit += wsi->u.http2.hpack_e_dep;
|
||||
if (swsi->u.http2.waiting_tx_credit && swsi->u.http2.tx_credit > 0) {
|
||||
|
|
|
@ -199,8 +199,8 @@ struct jpargs {
|
|||
static void *
|
||||
lwsws_align(struct jpargs *a)
|
||||
{
|
||||
if ((unsigned long)(a->p) & 15)
|
||||
a->p += 16 - ((unsigned long)(a->p) & 15);
|
||||
if ((lws_intptr_t)(a->p) & 15)
|
||||
a->p += 16 - ((lws_intptr_t)(a->p) & 15);
|
||||
|
||||
return a->p;
|
||||
}
|
||||
|
@ -776,7 +776,8 @@ lwsws_get_config_d(void *user, const char *d, const char * const *paths,
|
|||
|
||||
bail:
|
||||
uv_fs_req_cleanup(&req);
|
||||
uv_loop_close(&loop);
|
||||
while (uv_loop_close(&loop))
|
||||
;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
249
lib/libevent.c
Normal file
249
lib/libevent.c
Normal file
|
@ -0,0 +1,249 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "private-libwebsockets.h"
|
||||
|
||||
void lws_feature_status_libevent(struct lws_context_creation_info *info)
|
||||
{
|
||||
if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBEVENT))
|
||||
lwsl_notice("libevent support compiled in and enabled\n");
|
||||
else
|
||||
lwsl_notice("libevent support compiled in but disabled\n");
|
||||
}
|
||||
|
||||
static void
|
||||
lws_event_cb(evutil_socket_t sock_fd, short revents, void *ctx)
|
||||
{
|
||||
struct lws_io_watcher *lws_io = (struct lws_io_watcher *)ctx;
|
||||
struct lws_context *context = lws_io->context;
|
||||
struct lws_pollfd eventfd;
|
||||
|
||||
if (revents & EV_TIMEOUT)
|
||||
return;
|
||||
|
||||
/* !!! EV_CLOSED doesn't exist in libevent2 */
|
||||
#if LIBEVENT_VERSION_NUMBER < 0x02000000
|
||||
if (revents & EV_CLOSED)
|
||||
{
|
||||
event_del(lws_io->event_watcher);
|
||||
event_free(lws_io->event_watcher);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
eventfd.fd = sock_fd;
|
||||
eventfd.events = 0;
|
||||
eventfd.revents = 0;
|
||||
if (revents & EV_READ)
|
||||
{
|
||||
eventfd.events |= LWS_POLLIN;
|
||||
eventfd.revents |= LWS_POLLIN;
|
||||
}
|
||||
if (revents & EV_WRITE)
|
||||
{
|
||||
eventfd.events |= LWS_POLLOUT;
|
||||
eventfd.revents |= LWS_POLLOUT;
|
||||
}
|
||||
lws_service_fd(context, &eventfd);
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_event_sigint_cb(evutil_socket_t sock_fd, short revents, void *ctx)
|
||||
{
|
||||
struct lws_context_per_thread *pt = ctx;
|
||||
if (!pt->ev_loop_foreign)
|
||||
event_base_loopbreak(pt->io_loop_event_base);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_event_sigint_cfg(struct lws_context *context, int use_event_sigint,
|
||||
lws_event_signal_cb_t *cb)
|
||||
{
|
||||
context->use_ev_sigint = use_event_sigint;
|
||||
if (cb)
|
||||
context->lws_event_sigint_cb = cb;
|
||||
else
|
||||
context->lws_event_sigint_cb = &lws_event_sigint_cb;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_event_initloop(struct lws_context *context, struct event_base *loop,
|
||||
int tsi)
|
||||
{
|
||||
if (!loop)
|
||||
{
|
||||
context->pt[tsi].io_loop_event_base = event_base_new();
|
||||
}
|
||||
else
|
||||
{
|
||||
context->pt[tsi].ev_loop_foreign = 1;
|
||||
context->pt[tsi].io_loop_event_base = loop;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize all events with the listening sockets
|
||||
* and register a callback for read operations
|
||||
*/
|
||||
struct lws_vhost *vh = context->vhost_list;
|
||||
while (vh)
|
||||
{
|
||||
if (vh->lserv_wsi)
|
||||
{
|
||||
vh->lserv_wsi->w_read.context = context;
|
||||
vh->lserv_wsi->w_read.event_watcher = event_new(
|
||||
loop,
|
||||
vh->lserv_wsi->desc.sockfd,
|
||||
(EV_READ | EV_PERSIST),
|
||||
lws_event_cb,
|
||||
&vh->lserv_wsi->w_read);
|
||||
event_add(vh->lserv_wsi->w_read.event_watcher, NULL);
|
||||
}
|
||||
vh = vh->vhost_next;
|
||||
}
|
||||
|
||||
/* Register the signal watcher unless the user says not to */
|
||||
if (context->use_ev_sigint)
|
||||
{
|
||||
struct event *w_sigint = evsignal_new(loop, SIGINT,
|
||||
context->lws_event_sigint_cb, &context->pt[tsi]);
|
||||
context->pt[tsi].w_sigint.event_watcher = w_sigint;
|
||||
event_add(w_sigint, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_libevent_destroyloop(struct lws_context *context, int tsi)
|
||||
{
|
||||
if (!lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEVENT))
|
||||
return;
|
||||
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
if (!pt->io_loop_event_base)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Free all events with the listening sockets
|
||||
*/
|
||||
struct lws_vhost *vh = context->vhost_list;
|
||||
while (vh)
|
||||
{
|
||||
if (vh->lserv_wsi)
|
||||
{
|
||||
event_free(vh->lserv_wsi->w_read.event_watcher);
|
||||
vh->lserv_wsi->w_read.event_watcher = NULL;
|
||||
}
|
||||
vh = vh->vhost_next;
|
||||
}
|
||||
|
||||
if (context->use_ev_sigint)
|
||||
event_free(pt->w_sigint.event_watcher);
|
||||
if (!pt->ev_loop_foreign)
|
||||
event_base_free(pt->io_loop_event_base);
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_libevent_accept(struct lws *new_wsi, lws_sock_file_fd_type desc)
|
||||
{
|
||||
struct lws_context *context = lws_get_context(new_wsi);
|
||||
if (!LWS_LIBEVENT_ENABLED(context))
|
||||
return;
|
||||
|
||||
new_wsi->w_read.context = context;
|
||||
new_wsi->w_write.context = context;
|
||||
|
||||
// Initialize the event
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)new_wsi->tsi];
|
||||
int fd;
|
||||
if (new_wsi->mode == LWSCM_RAW_FILEDESC)
|
||||
fd = desc.filefd;
|
||||
else
|
||||
fd = desc.sockfd;
|
||||
new_wsi->w_read.event_watcher = event_new(pt->io_loop_event_base, fd,
|
||||
(EV_READ | EV_PERSIST), lws_event_cb, &new_wsi->w_read);
|
||||
new_wsi->w_write.event_watcher = event_new(pt->io_loop_event_base, fd,
|
||||
(EV_WRITE | EV_PERSIST), lws_event_cb, &new_wsi->w_write);
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_libevent_io(struct lws *wsi, int flags)
|
||||
{
|
||||
struct lws_context *context = lws_get_context(wsi);
|
||||
|
||||
if (!LWS_LIBEVENT_ENABLED(context))
|
||||
return;
|
||||
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
if (!pt->io_loop_event_base || context->being_destroyed)
|
||||
return;
|
||||
|
||||
assert((flags & (LWS_EV_START | LWS_EV_STOP)) &&
|
||||
(flags & (LWS_EV_READ | LWS_EV_WRITE)));
|
||||
|
||||
if (flags & LWS_EV_START)
|
||||
{
|
||||
if (flags & LWS_EV_WRITE)
|
||||
{
|
||||
event_add(wsi->w_write.event_watcher, NULL);
|
||||
}
|
||||
if (flags & LWS_EV_READ)
|
||||
{
|
||||
event_add(wsi->w_read.event_watcher, NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flags & LWS_EV_WRITE)
|
||||
{
|
||||
event_del(wsi->w_write.event_watcher);
|
||||
}
|
||||
if (flags & LWS_EV_READ)
|
||||
{
|
||||
event_del(wsi->w_read.event_watcher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_libevent_init_fd_table(struct lws_context *context)
|
||||
{
|
||||
if (!LWS_LIBEVENT_ENABLED(context))
|
||||
return 0;
|
||||
|
||||
int n;
|
||||
for (n = 0; n < context->count_threads; n++)
|
||||
{
|
||||
context->pt[n].w_sigint.context = context;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_libevent_run(const struct lws_context *context, int tsi)
|
||||
{
|
||||
// Run/Dispatch the event_base loop
|
||||
if (context->pt[tsi].io_loop_event_base && LWS_LIBEVENT_ENABLED(context))
|
||||
event_base_dispatch(context->pt[tsi].io_loop_event_base);
|
||||
}
|
55
lib/libuv.c
55
lib/libuv.c
|
@ -58,7 +58,7 @@ lws_uv_idle(uv_idle_t *handle
|
|||
/* there is nobody who needs service forcing, shut down idle */
|
||||
uv_idle_stop(handle);
|
||||
|
||||
lwsl_debug("%s: done stop\n", __func__);
|
||||
//lwsl_debug("%s: done stop\n", __func__);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -167,7 +167,7 @@ lws_uv_initvhost(struct lws_vhost* vh, struct lws* wsi)
|
|||
&wsi->w_read.uv_watcher, wsi->desc.sockfd);
|
||||
if (n) {
|
||||
lwsl_err("uv_poll_init failed %d, sockfd=%p\n",
|
||||
n, (void *)(long)wsi->desc.sockfd);
|
||||
n, (void *)(lws_intptr_t)wsi->desc.sockfd);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@ -262,6 +262,12 @@ static void lws_uv_walk_cb(uv_handle_t *handle, void *arg)
|
|||
uv_close(handle, lws_uv_close_cb);
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_close_all_handles_in_loop(uv_loop_t *loop)
|
||||
{
|
||||
uv_walk(loop, lws_uv_walk_cb, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
lws_libuv_destroyloop(struct lws_context *context, int tsi)
|
||||
{
|
||||
|
@ -520,13 +526,39 @@ lws_libuv_closehandle(struct lws *wsi)
|
|||
struct lws_context *context = lws_get_context(wsi);
|
||||
|
||||
/* required to defer actual deletion until libuv has processed it */
|
||||
|
||||
uv_close((uv_handle_t*)&wsi->w_read.uv_watcher, lws_libuv_closewsi);
|
||||
|
||||
if (context->requested_kill && context->count_wsi_allocated == 0)
|
||||
lws_libuv_kill(context);
|
||||
}
|
||||
|
||||
static void
|
||||
lws_libuv_closewsi_m(uv_handle_t* handle)
|
||||
{
|
||||
lws_sockfd_type sockfd = (lws_sockfd_type)(lws_intptr_t)handle->data;
|
||||
|
||||
compatible_close(sockfd);
|
||||
}
|
||||
|
||||
void
|
||||
lws_libuv_closehandle_manually(struct lws *wsi)
|
||||
{
|
||||
uv_handle_t *h = (void *)&wsi->w_read.uv_watcher;
|
||||
|
||||
h->data = (void *)(lws_intptr_t)wsi->desc.sockfd;
|
||||
/* required to defer actual deletion until libuv has processed it */
|
||||
uv_close((uv_handle_t*)&wsi->w_read.uv_watcher, lws_libuv_closewsi_m);
|
||||
}
|
||||
|
||||
int
|
||||
lws_libuv_check_watcher_active(struct lws *wsi)
|
||||
{
|
||||
uv_handle_t *h = (void *)&wsi->w_read.uv_watcher;
|
||||
|
||||
return uv_is_active(h);
|
||||
}
|
||||
|
||||
|
||||
#if defined(LWS_WITH_PLUGINS) && (UV_VERSION_MAJOR > 0)
|
||||
|
||||
LWS_VISIBLE int
|
||||
|
@ -540,7 +572,6 @@ lws_plat_plugins_init(struct lws_context *context, const char * const *d)
|
|||
uv_dirent_t dent;
|
||||
uv_fs_t req;
|
||||
char path[256];
|
||||
uv_loop_t loop;
|
||||
uv_lib_t lib;
|
||||
int pofs = 0;
|
||||
|
||||
|
@ -551,14 +582,14 @@ lws_plat_plugins_init(struct lws_context *context, const char * const *d)
|
|||
lib.errmsg = NULL;
|
||||
lib.handle = NULL;
|
||||
|
||||
uv_loop_init(&loop);
|
||||
uv_loop_init(&context->pu_loop);
|
||||
|
||||
lwsl_notice(" Plugins:\n");
|
||||
|
||||
while (d && *d) {
|
||||
|
||||
lwsl_notice(" Scanning %s\n", *d);
|
||||
m =uv_fs_scandir(&loop, &req, *d, 0, NULL);
|
||||
m =uv_fs_scandir(&context->pu_loop, &req, *d, 0, NULL);
|
||||
if (m < 1) {
|
||||
lwsl_err("Scandir on %s failed\n", *d);
|
||||
return 1;
|
||||
|
@ -574,10 +605,12 @@ lws_plat_plugins_init(struct lws_context *context, const char * const *d)
|
|||
if (uv_dlopen(path, &lib)) {
|
||||
uv_dlerror(&lib);
|
||||
lwsl_err("Error loading DSO: %s\n", lib.errmsg);
|
||||
uv_dlclose(&lib);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* we could open it, can we get his init function? */
|
||||
|
||||
#if !defined(WIN32) && !defined(__MINGW32__)
|
||||
m = lws_snprintf(path, sizeof(path) - 1, "init_%s",
|
||||
dent.name + pofs /* snip lib... */);
|
||||
|
@ -591,6 +624,7 @@ lws_plat_plugins_init(struct lws_context *context, const char * const *d)
|
|||
uv_dlerror(&lib);
|
||||
lwsl_err("Failed to get %s on %s: %s", path,
|
||||
dent.name, lib.errmsg);
|
||||
uv_dlclose(&lib);
|
||||
goto bail;
|
||||
}
|
||||
initfunc = (lws_plugin_init_func)v;
|
||||
|
@ -603,6 +637,7 @@ lws_plat_plugins_init(struct lws_context *context, const char * const *d)
|
|||
|
||||
plugin = lws_malloc(sizeof(*plugin));
|
||||
if (!plugin) {
|
||||
uv_dlclose(&lib);
|
||||
lwsl_err("OOM\n");
|
||||
goto bail;
|
||||
}
|
||||
|
@ -625,11 +660,7 @@ bail:
|
|||
d++;
|
||||
}
|
||||
|
||||
uv_run(&loop, UV_RUN_NOWAIT);
|
||||
uv_loop_close(&loop);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
|
@ -653,6 +684,7 @@ lws_plat_plugins_destroy(struct lws_context *context)
|
|||
|
||||
while (plugin) {
|
||||
p = plugin;
|
||||
|
||||
#if !defined(WIN32) && !defined(__MINGW32__)
|
||||
m = lws_snprintf(path, sizeof(path) - 1, "destroy_%s", plugin->name + pofs);
|
||||
path[m - 3] = '\0';
|
||||
|
@ -681,6 +713,9 @@ lws_plat_plugins_destroy(struct lws_context *context)
|
|||
|
||||
context->plugin_list = NULL;
|
||||
|
||||
while (uv_loop_close(&context->pu_loop))
|
||||
;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -33,6 +33,12 @@ extern "C" {
|
|||
#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
#include "lws_config.h"
|
||||
|
||||
/*
|
||||
* CARE: everything using cmake defines needs to be below here
|
||||
*/
|
||||
|
||||
#if defined(LWS_WITH_ESP8266)
|
||||
struct sockaddr_in;
|
||||
#define LWS_POSIX 0
|
||||
|
@ -40,7 +46,12 @@ struct sockaddr_in;
|
|||
#define LWS_POSIX 1
|
||||
#endif
|
||||
|
||||
#include "lws_config.h"
|
||||
#if defined(LWS_HAS_INTPTR_T)
|
||||
#include <stdint.h>
|
||||
#define lws_intptr_t intptr_t
|
||||
#else
|
||||
typedef unsigned long long lws_intptr_t;
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
|
@ -84,6 +95,9 @@ struct sockaddr_in;
|
|||
|
||||
#define LWS_INVALID_FILE INVALID_HANDLE_VALUE
|
||||
#define LWS_O_RDONLY _O_RDONLY
|
||||
#define LWS_O_WRONLY _O_WRONLY
|
||||
#define LWS_O_CREAT _O_CREAT
|
||||
#define LWS_O_TRUNC _O_TRUNC
|
||||
|
||||
#if !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER < 1900) /* Visual Studio 2015 already defines this in <stdio.h> */
|
||||
#define lws_snprintf _snprintf
|
||||
|
@ -99,6 +113,9 @@ struct sockaddr_in;
|
|||
|
||||
#else /* NOT WIN32 */
|
||||
#include <unistd.h>
|
||||
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
|
||||
#include <sys/capability.h>
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__) || defined(__FreeBSD__)
|
||||
#include <netinet/in.h>
|
||||
|
@ -106,13 +123,16 @@ struct sockaddr_in;
|
|||
|
||||
#define LWS_INLINE inline
|
||||
#define LWS_O_RDONLY O_RDONLY
|
||||
#define LWS_O_WRONLY O_WRONLY
|
||||
#define LWS_O_CREAT O_CREAT
|
||||
#define LWS_O_TRUNC O_TRUNC
|
||||
|
||||
#if !defined(LWS_WITH_ESP8266) && !defined(OPTEE_TA) && !defined(LWS_WITH_ESP32)
|
||||
#include <poll.h>
|
||||
#include <netdb.h>
|
||||
#define LWS_INVALID_FILE -1
|
||||
#else
|
||||
#define getdtablesize() (20)
|
||||
#define getdtablesize() (30)
|
||||
#if defined(LWS_WITH_ESP32)
|
||||
#define LWS_INVALID_FILE NULL
|
||||
#else
|
||||
|
@ -155,6 +175,9 @@ struct sockaddr_in;
|
|||
#include <uv-version.h>
|
||||
#endif
|
||||
#endif /* LWS_USE_LIBUV */
|
||||
#ifdef LWS_USE_LIBEVENT
|
||||
#include <event2/event.h>
|
||||
#endif /* LWS_USE_LIBEVENT */
|
||||
|
||||
#ifndef LWS_EXTERN
|
||||
#define LWS_EXTERN extern
|
||||
|
@ -503,7 +526,7 @@ extern void esp32_uvtimer_cb(TimerHandle_t t);
|
|||
|
||||
static inline void uv_timer_start(uv_timer_t *t, uv_cb_t *cb, int first, int rep)
|
||||
{
|
||||
struct timer_mapping *tm = malloc(sizeof(*tm));
|
||||
struct timer_mapping *tm = (struct timer_mapping *)malloc(sizeof(*tm));
|
||||
|
||||
if (!tm)
|
||||
return;
|
||||
|
@ -529,34 +552,123 @@ static inline void uv_close(uv_handle_t *h, void *v)
|
|||
|
||||
/* ESP32 helper declarations */
|
||||
|
||||
#include <mdns.h>
|
||||
#include <esp_partition.h>
|
||||
|
||||
#define LWS_PLUGIN_STATIC
|
||||
#define LWS_MAGIC_REBOOT_TYPE_ADS 0x50001ffc
|
||||
#define LWS_MAGIC_REBOOT_TYPE_REQ_FACTORY 0xb00bcafe
|
||||
#define LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY 0xfaceb00b
|
||||
#define LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON 0xf0cedfac
|
||||
|
||||
|
||||
/* user code provides these */
|
||||
|
||||
extern char lws_esp32_model[16];
|
||||
|
||||
extern int
|
||||
lws_esp32_is_booting_in_ap_mode(void);
|
||||
extern void
|
||||
lws_esp32_identify_physical_device(void);
|
||||
|
||||
/* lws-plat-esp32 provides these */
|
||||
|
||||
extern void (*lws_cb_scan_done)(void *);
|
||||
extern void *lws_cb_scan_done_arg;
|
||||
typedef void (*lws_cb_scan_done)(uint16_t count, wifi_ap_record_t *recs, void *arg);
|
||||
|
||||
extern char lws_esp32_serial[], lws_esp32_force_ap, lws_esp32_region;
|
||||
enum genled_state {
|
||||
LWSESP32_GENLED__INIT,
|
||||
LWSESP32_GENLED__LOST_NETWORK,
|
||||
LWSESP32_GENLED__NO_NETWORK,
|
||||
LWSESP32_GENLED__CONN_AP,
|
||||
LWSESP32_GENLED__GOT_IP,
|
||||
LWSESP32_GENLED__OK,
|
||||
};
|
||||
|
||||
struct lws_group_member {
|
||||
struct lws_group_member *next;
|
||||
uint64_t last_seen;
|
||||
char model[16];
|
||||
char role[16];
|
||||
char host[32];
|
||||
char mac[20];
|
||||
int width, height;
|
||||
struct ip4_addr addr;
|
||||
struct ip6_addr addrv6;
|
||||
uint8_t flags;
|
||||
};
|
||||
|
||||
#define LWS_SYSTEM_GROUP_MEMBER_ADD 1
|
||||
#define LWS_SYSTEM_GROUP_MEMBER_CHANGE 2
|
||||
#define LWS_SYSTEM_GROUP_MEMBER_REMOVE 3
|
||||
|
||||
#define LWS_GROUP_FLAG_SELF 1
|
||||
|
||||
struct lws_esp32 {
|
||||
char sta_ip[16];
|
||||
char sta_mask[16];
|
||||
char sta_gw[16];
|
||||
char serial[16];
|
||||
char opts[16];
|
||||
char model[16];
|
||||
char group[16];
|
||||
char role[16];
|
||||
char ssid[4][16];
|
||||
char password[4][32];
|
||||
char active_ssid[32];
|
||||
char access_pw[16];
|
||||
char hostname[32];
|
||||
char mac[20];
|
||||
mdns_server_t *mdns;
|
||||
char region;
|
||||
char inet;
|
||||
char conn_ap;
|
||||
|
||||
enum genled_state genled;
|
||||
uint64_t genled_t;
|
||||
|
||||
lws_cb_scan_done scan_consumer;
|
||||
void *scan_consumer_arg;
|
||||
struct lws_group_member *first;
|
||||
int extant_group_members;
|
||||
};
|
||||
|
||||
struct lws_esp32_image {
|
||||
uint32_t romfs;
|
||||
uint32_t romfs_len;
|
||||
uint32_t json;
|
||||
uint32_t json_len;
|
||||
};
|
||||
|
||||
extern struct lws_esp32 lws_esp32;
|
||||
struct lws_vhost;
|
||||
|
||||
extern esp_err_t
|
||||
lws_esp32_event_passthru(void *ctx, system_event_t *event);
|
||||
extern void
|
||||
lws_esp32_wlan_config(void);
|
||||
extern void
|
||||
lws_esp32_wlan_start(void);
|
||||
lws_esp32_wlan_start_ap(void);
|
||||
extern void
|
||||
lws_esp32_wlan_start_station(void);
|
||||
struct lws_context_creation_info;
|
||||
extern void
|
||||
lws_esp32_set_creation_defaults(struct lws_context_creation_info *info);
|
||||
extern struct lws_context *
|
||||
lws_esp32_init(struct lws_context_creation_info *, unsigned int _romfs);
|
||||
lws_esp32_init(struct lws_context_creation_info *, struct lws_vhost **pvh);
|
||||
extern int
|
||||
lws_esp32_wlan_nvs_get(int retry);
|
||||
extern esp_err_t
|
||||
lws_nvs_set_str(nvs_handle handle, const char* key, const char* value);
|
||||
extern void
|
||||
lws_esp32_restart_guided(uint32_t type);
|
||||
extern const esp_partition_t *
|
||||
lws_esp_ota_get_boot_partition(void);
|
||||
extern int
|
||||
lws_esp32_get_image_info(const esp_partition_t *part, struct lws_esp32_image *i, char *json, int json_len);
|
||||
extern int
|
||||
lws_esp32_leds_network_indication(void);
|
||||
|
||||
extern uint32_t lws_esp32_get_reboot_type(void);
|
||||
extern uint16_t lws_esp32_sine_interp(int n);
|
||||
|
||||
/* required in external code by esp32 plat (may just return if no leds) */
|
||||
extern void lws_esp32_leds_timer_cb(TimerHandle_t th);
|
||||
#else
|
||||
typedef int lws_sockfd_type;
|
||||
typedef int lws_filefd_type;
|
||||
|
@ -570,6 +682,36 @@ typedef int lws_filefd_type;
|
|||
#define LWS_POLLOUT (POLLOUT)
|
||||
#endif
|
||||
|
||||
|
||||
#if (defined(WIN32) || defined(_WIN32)) && !defined(__MINGW32__)
|
||||
/* ... */
|
||||
#define ssize_t SSIZE_T
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) && defined(LWS_HAVE__STAT32I64)
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#if defined(LWS_HAVE_STDINT_H)
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
/* !!! >:-[ */
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
#else
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned char uint8_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef unsigned long long lws_filepos_t;
|
||||
typedef long long lws_fileofs_t;
|
||||
typedef uint32_t lws_fop_flags_t;
|
||||
|
||||
/** struct lws_pollargs - argument structure for all external poll related calls
|
||||
* passed in via 'in' */
|
||||
struct lws_pollargs {
|
||||
|
@ -686,6 +828,38 @@ struct lws_context;
|
|||
/* needed even with extensions disabled for create context */
|
||||
struct lws_extension;
|
||||
|
||||
/*! \defgroup lwsmeta lws-meta
|
||||
*
|
||||
* ##lws-meta protocol
|
||||
*
|
||||
* The protocol wraps other muxed connections inside one tcp connection.
|
||||
*
|
||||
* Commands are assigned from 0x41 up (so they are valid unicode)
|
||||
*/
|
||||
///@{
|
||||
|
||||
enum lws_meta_commands {
|
||||
LWS_META_CMD_OPEN_SUBCHANNEL = 'A',
|
||||
/**< Client requests to open new subchannel
|
||||
*/
|
||||
LWS_META_CMD_OPEN_RESULT,
|
||||
/**< Result of client request to open new subchannel */
|
||||
LWS_META_CMD_CLOSE_NOTIFY,
|
||||
/**< Notification of subchannel closure */
|
||||
LWS_META_CMD_CLOSE_RQ,
|
||||
/**< client requests to close a subchannel */
|
||||
LWS_META_CMD_WRITE,
|
||||
/**< connection writes something to specific channel index */
|
||||
|
||||
/****** add new things just above ---^ ******/
|
||||
};
|
||||
|
||||
/* channel numbers are transported offset by 0x20 so they are valid unicode */
|
||||
|
||||
#define LWS_META_TRANSPORT_OFFSET 0x20
|
||||
|
||||
///@}
|
||||
|
||||
/*! \defgroup usercb User Callback
|
||||
*
|
||||
* ##User protocol callback
|
||||
|
@ -699,6 +873,10 @@ struct lws_extension;
|
|||
*/
|
||||
///@{
|
||||
|
||||
struct lws_ssl_info {
|
||||
int where;
|
||||
int ret;
|
||||
};
|
||||
|
||||
/*
|
||||
* NOTE: These public enums are part of the abi. If you want to add one,
|
||||
|
@ -919,8 +1097,7 @@ enum lws_callback_reasons {
|
|||
* and with in being the extension name, len is 0 and user is
|
||||
* valid. Note though at this time the ESTABLISHED callback hasn't
|
||||
* happened yet so if you initialize user content there, user
|
||||
* content during this callback might not be useful for anything.
|
||||
* Notice this callback comes to protocols[0]. */
|
||||
* content during this callback might not be useful for anything. */
|
||||
LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED = 26,
|
||||
/**< When a client
|
||||
* connection is being prepared to start a handshake to a server,
|
||||
|
@ -1106,6 +1283,22 @@ enum lws_callback_reasons {
|
|||
/**< RAW mode file is writeable */
|
||||
LWS_CALLBACK_RAW_CLOSE_FILE = 66,
|
||||
/**< RAW mode wsi that adopted a file is closing */
|
||||
LWS_CALLBACK_SSL_INFO = 67,
|
||||
/**< SSL connections only. An event you registered an
|
||||
* interest in at the vhost has occurred on a connection
|
||||
* using the vhost. @in is a pointer to a
|
||||
* struct lws_ssl_info containing information about the
|
||||
* event*/
|
||||
LWS_CALLBACK_CHILD_WRITE_VIA_PARENT = 68,
|
||||
/**< Child has been marked with parent_carries_io attribute, so
|
||||
* lws_write directs the to this callback at the parent,
|
||||
* @in is a struct lws_write_passthru containing the args
|
||||
* the lws_write() was called with.
|
||||
*/
|
||||
LWS_CALLBACK_CHILD_CLOSING = 69,
|
||||
/**< Sent to parent to notify them a child is closing / being
|
||||
* destroyed. @in is the child wsi.
|
||||
*/
|
||||
|
||||
/****** add new things just above ---^ ******/
|
||||
|
||||
|
@ -1133,6 +1326,11 @@ enum lws_callback_reasons {
|
|||
typedef int
|
||||
lws_callback_function(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len);
|
||||
|
||||
#define LWS_CB_REASON_AUX_BF__CGI 1
|
||||
#define LWS_CB_REASON_AUX_BF__PROXY 2
|
||||
#define LWS_CB_REASON_AUX_BF__CGI_CHUNK_END 4
|
||||
#define LWS_CB_REASON_AUX_BF__CGI_HEADERS 8
|
||||
///@}
|
||||
|
||||
/*! \defgroup extensions
|
||||
|
@ -1388,8 +1586,8 @@ struct lws_protocols {
|
|||
* be able to consume it all without having to return to the event
|
||||
* loop. That is supported in lws.
|
||||
*
|
||||
* This also controls how much may be sent at once at the moment,
|
||||
* although this is likely to change.
|
||||
* If .tx_packet_size is 0, this also controls how much may be sent at once
|
||||
* for backwards compatibility.
|
||||
*/
|
||||
unsigned int id;
|
||||
/**< ignored by lws, but useful to contain user information bound
|
||||
|
@ -1400,6 +1598,15 @@ struct lws_protocols {
|
|||
* capability flags based on selected protocol version, etc. */
|
||||
void *user; /**< ignored by lws, but user code can pass a pointer
|
||||
here it can later access from the protocol callback */
|
||||
size_t tx_packet_size;
|
||||
/**< 0 indicates restrict send() size to .rx_buffer_size for backwards-
|
||||
* compatibility.
|
||||
* If greater than zero, a single send() is restricted to this amount
|
||||
* and any remainder is buffered by lws and sent afterwards also in
|
||||
* these size chunks. Since that is expensive, it's preferable
|
||||
* to restrict one fragment you are trying to send to match this
|
||||
* size.
|
||||
*/
|
||||
|
||||
/* Add new things just above here ---^
|
||||
* This is part of the ABI, don't needlessly break compatibility */
|
||||
|
@ -1646,6 +1853,18 @@ enum lws_context_options {
|
|||
*/
|
||||
LWS_SERVER_OPTION_FALLBACK_TO_RAW = (1 << 20),
|
||||
/**< (VH) if invalid http is coming in the first line, */
|
||||
LWS_SERVER_OPTION_LIBEVENT = (1 << 21),
|
||||
/**< (CTX) Use libevent event loop */
|
||||
LWS_SERVER_OPTION_ONLY_RAW = (1 << 22),
|
||||
/**< (VH) All connections to this vhost / port are RAW as soon as
|
||||
* the connection is accepted, no HTTP is going to be coming.
|
||||
*/
|
||||
LWS_SERVER_OPTION_ALLOW_LISTEN_SHARE = (1 << 23),
|
||||
/**< (VH) Set to allow multiple listen sockets on one interface +
|
||||
* address + port. The default is to strictly allow only one
|
||||
* listen socket at a time. This is automatically selected if you
|
||||
* have multiple service threads.
|
||||
*/
|
||||
|
||||
/****** add new things just above ---^ ******/
|
||||
};
|
||||
|
@ -1717,7 +1936,7 @@ struct lws_context_creation_info {
|
|||
/**< VHOST + CONTEXT: 0, or LWS_SERVER_OPTION_... bitfields */
|
||||
void *user;
|
||||
/**< CONTEXT: optional user pointer that can be recovered via the context
|
||||
* pointer using lws_context_user */
|
||||
* pointer using lws_context_user */
|
||||
int ka_time;
|
||||
/**< CONTEXT: 0 for no TCP keepalive, otherwise apply this keepalive
|
||||
* timeout to all libwebsocket sockets, client or server */
|
||||
|
@ -1858,6 +2077,36 @@ struct lws_context_creation_info {
|
|||
* If NULL, lws provides just the platform file operations struct for
|
||||
* backwards compatibility.
|
||||
*/
|
||||
int simultaneous_ssl_restriction;
|
||||
/**< CONTEXT: 0 (no limit) or limit of simultaneous SSL sessions possible.*/
|
||||
const char *socks_proxy_address;
|
||||
/**< VHOST: If non-NULL, attempts to proxy via the given address.
|
||||
* If proxy auth is required, use format "username:password\@server:port" */
|
||||
unsigned int socks_proxy_port;
|
||||
/**< VHOST: If socks_proxy_address was non-NULL, uses this port */
|
||||
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
|
||||
cap_value_t caps[4];
|
||||
/**< CONTEXT: array holding Linux capabilities you want to
|
||||
* continue to be available to the server after it transitions
|
||||
* to a noprivileged user. Usually none are needed but for, eg,
|
||||
* .bind_iface, CAP_NET_RAW is required. This gives you a way
|
||||
* to still have the capability but drop root.
|
||||
*/
|
||||
char count_caps;
|
||||
/**< CONTEXT: count of Linux capabilities in .caps[]. 0 means
|
||||
* no capabilities will be inherited from root (the default) */
|
||||
#endif
|
||||
int bind_iface;
|
||||
/**< VHOST: nonzero to strictly bind sockets to the interface name in
|
||||
* .iface (eg, "eth2"), using SO_BIND_TO_DEVICE.
|
||||
*
|
||||
* Requires SO_BINDTODEVICE support from your OS and CAP_NET_RAW
|
||||
* capability.
|
||||
*
|
||||
* Notice that common things like access network interface IP from
|
||||
* your local machine use your lo / loopback interface and will be
|
||||
* disallowed by this.
|
||||
*/
|
||||
|
||||
/* Add new things just above here ---^
|
||||
* This is part of the ABI, don't needlessly break compatibility
|
||||
|
@ -1866,6 +2115,15 @@ struct lws_context_creation_info {
|
|||
* members added above will see 0 (default) even if the app
|
||||
* was not built against the newer headers.
|
||||
*/
|
||||
int ssl_info_event_mask;
|
||||
/**< VHOST: mask of ssl events to be reported on LWS_CALLBACK_SSL_INFO
|
||||
* callback for connections on this vhost. The mask values are of
|
||||
* the form SSL_CB_ALERT, defined in openssl/ssl.h. The default of
|
||||
* 0 means no info events will be reported.
|
||||
*/
|
||||
unsigned int timeout_secs_ah_idle;
|
||||
/**< VHOST: seconds to allow a client to hold an ah without using it.
|
||||
* 0 defaults to 10s. */
|
||||
|
||||
void *_unused[8]; /**< dummy */
|
||||
};
|
||||
|
@ -1973,6 +2231,25 @@ lws_context_is_deprecated(struct lws_context *context);
|
|||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_set_proxy(struct lws_vhost *vhost, const char *proxy);
|
||||
|
||||
/**
|
||||
* lws_set_socks() - Setup socks to lws_context.
|
||||
* \param vhost: pointer to struct lws_vhost you want set socks for
|
||||
* \param socks: pointer to c string containing socks in format address:port
|
||||
*
|
||||
* Returns 0 if socks string was parsed and socks was setup.
|
||||
* Returns -1 if socks is NULL or has incorrect format.
|
||||
*
|
||||
* This is only required if your OS does not provide the socks_proxy
|
||||
* environment variable (eg, OSX)
|
||||
*
|
||||
* IMPORTANT! You should call this function right after creation of the
|
||||
* lws_context and before call to connect. If you call this
|
||||
* function after connect behavior is undefined.
|
||||
* This function will override proxy settings made on lws_context
|
||||
* creation with genenv() call.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_set_socks(struct lws_vhost *vhost, const char *socks);
|
||||
|
||||
struct lws_vhost;
|
||||
|
||||
|
@ -1985,10 +2262,22 @@ struct lws_vhost;
|
|||
* members of the info struct. You can create many vhosts inside one context
|
||||
* if you created the context with the option LWS_SERVER_OPTION_EXPLICIT_VHOSTS
|
||||
*/
|
||||
LWS_EXTERN LWS_VISIBLE struct lws_vhost *
|
||||
LWS_VISIBLE LWS_EXTERN struct lws_vhost *
|
||||
lws_create_vhost(struct lws_context *context,
|
||||
struct lws_context_creation_info *info);
|
||||
|
||||
/**
|
||||
* lws_destroy_vhost() - Destroy a vhost (virtual server context)
|
||||
* \param vhost: pointer to result of lws_create_vhost()
|
||||
*
|
||||
* This function destroys a vhost. Normally, if you just want to exit,
|
||||
* then lws_destroy_context() will take care of everything. If you want
|
||||
* to destroy an individual vhost and all connections and allocations, you
|
||||
* can do it with this.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_vhost_destroy(struct lws_vhost *vh);
|
||||
|
||||
/**
|
||||
* lwsws_get_config_globals() - Parse a JSON server config file
|
||||
* \param info: pointer to struct with parameters
|
||||
|
@ -2096,8 +2385,8 @@ struct lws_protocol_vhost_options {
|
|||
* served from a filesystem, or it is a cgi etc.
|
||||
*/
|
||||
enum lws_mount_protocols {
|
||||
LWSMPRO_HTTP = 0, /**< not supported yet */
|
||||
LWSMPRO_HTTPS = 1, /**< not supported yet */
|
||||
LWSMPRO_HTTP = 0, /**< http reverse proxy */
|
||||
LWSMPRO_HTTPS = 1, /**< https reverse proxy */
|
||||
LWSMPRO_FILE = 2, /**< serve from filesystem directory */
|
||||
LWSMPRO_CGI = 3, /**< pass to CGI to handle */
|
||||
LWSMPRO_REDIR_HTTP = 4, /**< redirect to http:// url */
|
||||
|
@ -2230,6 +2519,9 @@ struct lws_client_connect_info {
|
|||
* even before the new wsi is returned and even if ultimately no wsi
|
||||
* is returned.
|
||||
*/
|
||||
const char *iface;
|
||||
/**< NULL to allow routing on any interface, or interface name or IP
|
||||
* to bind the socket to */
|
||||
|
||||
/* Add new things just above here ---^
|
||||
* This is part of the ABI, don't needlessly break compatibility
|
||||
|
@ -2334,7 +2626,6 @@ lws_client_connect_extended(struct lws_context *clients, const char *address,
|
|||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_init_vhost_client_ssl(const struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost);
|
||||
|
||||
/**
|
||||
* lws_http_client_read() - consume waiting received http client data
|
||||
*
|
||||
|
@ -2547,6 +2838,9 @@ lws_service_adjust_timeout(struct lws_context *context, int timeout_ms, int tsi)
|
|||
/* Backwards compatibility */
|
||||
#define lws_plat_service_tsi lws_service_tsi
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd);
|
||||
|
||||
///@}
|
||||
|
||||
/*! \defgroup http HTTP
|
||||
|
@ -2828,6 +3122,7 @@ enum lws_token_indexes {
|
|||
_WSI_TOKEN_CLIENT_HOST,
|
||||
_WSI_TOKEN_CLIENT_ORIGIN,
|
||||
_WSI_TOKEN_CLIENT_METHOD,
|
||||
_WSI_TOKEN_CLIENT_IFACE,
|
||||
|
||||
/* always last real token index*/
|
||||
WSI_TOKEN_COUNT,
|
||||
|
@ -2998,7 +3293,7 @@ lws_add_http_header_by_token(struct lws *wsi, enum lws_token_indexes token,
|
|||
const unsigned char *value, int length,
|
||||
unsigned char **p, unsigned char *end);
|
||||
/**
|
||||
* lws_add_http_header_by_name() - append content-length helper
|
||||
* lws_add_http_header_content_length() - append content-length helper
|
||||
*
|
||||
* \param wsi: the connection to check
|
||||
* \param content_length: the content length to use
|
||||
|
@ -3009,7 +3304,7 @@ lws_add_http_header_by_token(struct lws *wsi, enum lws_token_indexes token,
|
|||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
|
||||
lws_add_http_header_content_length(struct lws *wsi,
|
||||
unsigned long content_length,
|
||||
lws_filepos_t content_length,
|
||||
unsigned char **p, unsigned char *end);
|
||||
/**
|
||||
* lws_finalize_http_header() - terminate header block
|
||||
|
@ -3315,9 +3610,39 @@ lws_uv_getloop(struct lws_context *context, int tsi);
|
|||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_uv_sigint_cb(uv_signal_t *watcher, int signum);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_close_all_handles_in_loop(uv_loop_t *loop);
|
||||
#endif /* LWS_USE_LIBUV */
|
||||
///@}
|
||||
|
||||
/*! \defgroup event libevent helpers
|
||||
*
|
||||
* ##libevent helpers
|
||||
*
|
||||
* APIs specific to libevent event loop itegration
|
||||
*/
|
||||
///@{
|
||||
|
||||
#ifdef LWS_USE_LIBEVENT
|
||||
typedef void (lws_event_signal_cb_t) (evutil_socket_t sock_fd, short revents,
|
||||
void *ctx);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_event_sigint_cfg(struct lws_context *context, int use_event_sigint,
|
||||
lws_event_signal_cb_t cb);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_event_initloop(struct lws_context *context, struct event_base *loop,
|
||||
int tsi);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_event_sigint_cb(evutil_socket_t sock_fd, short revents,
|
||||
void *ctx);
|
||||
#endif /* LWS_USE_LIBEVENT */
|
||||
|
||||
///@}
|
||||
|
||||
/*! \defgroup timeout Connection timeouts
|
||||
|
||||
APIs related to setting connection timeouts
|
||||
|
@ -3348,10 +3673,30 @@ enum pending_timeout {
|
|||
PENDING_TIMEOUT_WS_PONG_CHECK_SEND_PING = 16,
|
||||
PENDING_TIMEOUT_WS_PONG_CHECK_GET_PONG = 17,
|
||||
PENDING_TIMEOUT_CLIENT_ISSUE_PAYLOAD = 18,
|
||||
PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY = 19,
|
||||
PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY = 20,
|
||||
PENDING_TIMEOUT_AWAITING_SOCKS_AUTH_REPLY = 21,
|
||||
PENDING_TIMEOUT_KILLED_BY_SSL_INFO = 22,
|
||||
PENDING_TIMEOUT_KILLED_BY_PARENT = 23,
|
||||
PENDING_TIMEOUT_CLOSE_SEND = 24,
|
||||
PENDING_TIMEOUT_HOLDING_AH = 25,
|
||||
|
||||
/****** add new things just above ---^ ******/
|
||||
};
|
||||
|
||||
#define LWS_TO_KILL_ASYNC -1
|
||||
/**< If LWS_TO_KILL_ASYNC is given as the timeout sec in a lws_set_timeout()
|
||||
* call, then the connection is marked to be killed at the next timeout
|
||||
* check. This is how you should force-close the wsi being serviced if
|
||||
* you are doing it outside the callback (where you should close by nonzero
|
||||
* return).
|
||||
*/
|
||||
#define LWS_TO_KILL_SYNC -2
|
||||
/**< If LWS_TO_KILL_SYNC is given as the timeout sec in a lws_set_timeout()
|
||||
* call, then the connection is closed before returning (which may delete
|
||||
* the wsi). This should only be used where the wsi being closed is not the
|
||||
* wsi currently being serviced.
|
||||
*/
|
||||
/**
|
||||
* lws_set_timeout() - marks the wsi as subject to a timeout
|
||||
*
|
||||
|
@ -3359,7 +3704,10 @@ enum pending_timeout {
|
|||
*
|
||||
* \param wsi: Websocket connection instance
|
||||
* \param reason: timeout reason
|
||||
* \param secs: how many seconds
|
||||
* \param secs: how many seconds. You may set to LWS_TO_KILL_ASYNC to
|
||||
* force the connection to timeout at the next opportunity, or
|
||||
* LWS_TO_KILL_SYNC to close it synchronously if you know the
|
||||
* wsi is not the one currently being serviced.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs);
|
||||
|
@ -3384,7 +3732,8 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs);
|
|||
#endif
|
||||
#define _LWS_PAD(n) (((n) % _LWS_PAD_SIZE) ? \
|
||||
((n) + (_LWS_PAD_SIZE - ((n) % _LWS_PAD_SIZE))) : (n))
|
||||
#define LWS_PRE _LWS_PAD(4 + 10)
|
||||
/* last 2 is for lws-meta */
|
||||
#define LWS_PRE _LWS_PAD(4 + 10 + 2)
|
||||
/* used prior to 1.7 and retained for backward compatibility */
|
||||
#define LWS_SEND_BUFFER_PRE_PADDING LWS_PRE
|
||||
#define LWS_SEND_BUFFER_POST_PADDING 0
|
||||
|
@ -3436,6 +3785,15 @@ enum lws_write_protocol {
|
|||
* decode the content if used */
|
||||
};
|
||||
|
||||
/* used with LWS_CALLBACK_CHILD_WRITE_VIA_PARENT */
|
||||
|
||||
struct lws_write_passthru {
|
||||
struct lws *wsi;
|
||||
unsigned char *buf;
|
||||
size_t len;
|
||||
enum lws_write_protocol wp;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* lws_write() - Apply protocol then write data to client
|
||||
|
@ -3622,10 +3980,11 @@ lws_callback_all_protocol(struct lws_context *context,
|
|||
|
||||
/**
|
||||
* lws_callback_all_protocol_vhost() - Callback all connections using
|
||||
* the given protocol with the given reason
|
||||
* the given protocol with the given reason. This is
|
||||
* deprecated since v2.4: use lws_callback_all_protocol_vhost_args
|
||||
*
|
||||
* \param vh: Vhost whose connections will get callbacks
|
||||
* \param protocol: Which protocol to match
|
||||
* \param protocol: Which protocol to match. NULL means all.
|
||||
* \param reason: Callback reason index
|
||||
*
|
||||
* - Which: connections using this protocol on GIVEN VHOST ONLY
|
||||
|
@ -3634,7 +3993,27 @@ lws_callback_all_protocol(struct lws_context *context,
|
|||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_callback_all_protocol_vhost(struct lws_vhost *vh,
|
||||
const struct lws_protocols *protocol, int reason);
|
||||
const struct lws_protocols *protocol, int reason)
|
||||
LWS_WARN_DEPRECATED;
|
||||
|
||||
/**
|
||||
* lws_callback_all_protocol_vhost_args() - Callback all connections using
|
||||
* the given protocol with the given reason and args
|
||||
*
|
||||
* \param vh: Vhost whose connections will get callbacks
|
||||
* \param protocol: Which protocol to match. NULL means all.
|
||||
* \param reason: Callback reason index
|
||||
* \param argp: Callback "in" parameter
|
||||
* \param len: Callback "len" parameter
|
||||
*
|
||||
* - Which: connections using this protocol on GIVEN VHOST ONLY
|
||||
* - When: now
|
||||
* - What: reason
|
||||
*/
|
||||
LWS_VISIBLE int
|
||||
lws_callback_all_protocol_vhost_args(struct lws_vhost *vh,
|
||||
const struct lws_protocols *protocol, int reason,
|
||||
void *argp, size_t len);
|
||||
|
||||
/**
|
||||
* lws_callback_vhost_protocols() - Callback all protocols enabled on a vhost
|
||||
|
@ -3780,7 +4159,11 @@ typedef enum {
|
|||
LWS_ADOPT_RAW_FILE_DESC = 0, /* convenience constant */
|
||||
LWS_ADOPT_HTTP = 1, /* flag: absent implies RAW */
|
||||
LWS_ADOPT_SOCKET = 2, /* flag: absent implies file descr */
|
||||
LWS_ADOPT_ALLOW_SSL = 4 /* flag: if set requires LWS_ADOPT_SOCKET */
|
||||
LWS_ADOPT_ALLOW_SSL = 4, /* flag: if set requires LWS_ADOPT_SOCKET */
|
||||
LWS_ADOPT_WS_PARENTIO = 8, /* flag: ws mode parent handles IO
|
||||
* if given must be only flag
|
||||
* wsi put directly into ws mode
|
||||
*/
|
||||
} lws_adoption_type;
|
||||
|
||||
typedef union {
|
||||
|
@ -3807,7 +4190,7 @@ typedef union {
|
|||
* parent may be NULL, if given it should be an existing wsi that will become the
|
||||
* parent of the new wsi created by this call.
|
||||
*/
|
||||
LWS_VISIBLE struct lws *
|
||||
LWS_VISIBLE LWS_EXTERN struct lws *
|
||||
lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
|
||||
lws_sock_file_fd_type fd, const char *vh_prot_name,
|
||||
struct lws *parent);
|
||||
|
@ -3940,6 +4323,74 @@ lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
|
|||
*/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* lws_start_foreach_ll(): linkedlist iterator helper start
|
||||
*
|
||||
* \param type: type of iteration, eg, struct xyz *
|
||||
* \param it: iterator var name to create
|
||||
* \param start: start of list
|
||||
*
|
||||
* This helper creates an iterator and starts a while (it) {
|
||||
* loop. The iterator runs through the linked list starting at start and
|
||||
* ends when it gets a NULL.
|
||||
* The while loop should be terminated using lws_start_foreach_ll().
|
||||
*/
|
||||
#define lws_start_foreach_ll(type, it, start)\
|
||||
{ \
|
||||
type it = start; \
|
||||
while (it) {
|
||||
|
||||
/**
|
||||
* lws_end_foreach_ll(): linkedlist iterator helper end
|
||||
*
|
||||
* \param it: same iterator var name given when starting
|
||||
* \param nxt: member name in the iterator pointing to next list element
|
||||
*
|
||||
* This helper is the partner for lws_start_foreach_ll() that ends the
|
||||
* while loop.
|
||||
*/
|
||||
|
||||
#define lws_end_foreach_ll(it, nxt) \
|
||||
it = it->nxt; \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* lws_start_foreach_llp(): linkedlist pointer iterator helper start
|
||||
*
|
||||
* \param type: type of iteration, eg, struct xyz **
|
||||
* \param it: iterator var name to create
|
||||
* \param start: start of list
|
||||
*
|
||||
* This helper creates an iterator and starts a while (it) {
|
||||
* loop. The iterator runs through the linked list starting at the
|
||||
* address of start and ends when it gets a NULL.
|
||||
* The while loop should be terminated using lws_start_foreach_llp().
|
||||
*
|
||||
* This helper variant iterates using a pointer to the previous linked-list
|
||||
* element. That allows you to easily delete list members by rewriting the
|
||||
* previous pointer to the element's next pointer.
|
||||
*/
|
||||
#define lws_start_foreach_llp(type, it, start)\
|
||||
{ \
|
||||
type it = &(start); \
|
||||
while (*(it)) {
|
||||
|
||||
/**
|
||||
* lws_end_foreach_llp(): linkedlist pointer iterator helper end
|
||||
*
|
||||
* \param it: same iterator var name given when starting
|
||||
* \param nxt: member name in the iterator pointing to next list element
|
||||
*
|
||||
* This helper is the partner for lws_start_foreach_llp() that ends the
|
||||
* while loop.
|
||||
*/
|
||||
|
||||
#define lws_end_foreach_llp(it, nxt) \
|
||||
it = &(*(it))->nxt; \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* lws_snprintf(): snprintf that truncates the returned length too
|
||||
*
|
||||
|
@ -4070,6 +4521,32 @@ lws_get_parent(const struct lws *wsi);
|
|||
LWS_VISIBLE LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT
|
||||
lws_get_child(const struct lws *wsi);
|
||||
|
||||
/**
|
||||
* lws_parent_carries_io() - mark wsi as needing to send messages via parent
|
||||
*
|
||||
* \param wsi: child lws connection
|
||||
*/
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_set_parent_carries_io(struct lws *wsi);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void *
|
||||
lws_get_opaque_parent_data(const struct lws *wsi);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_set_opaque_parent_data(struct lws *wsi, void *data);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_get_child_pending_on_writable(const struct lws *wsi);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_clear_child_pending_on_writable(struct lws *wsi);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_get_close_length(struct lws *wsi);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN unsigned char *
|
||||
lws_get_close_payload(struct lws *wsi);
|
||||
|
||||
/*
|
||||
* \deprecated DEPRECATED Note: this is not normally needed as a user api.
|
||||
|
@ -4077,7 +4554,7 @@ lws_get_child(const struct lws *wsi);
|
|||
* useful when integrating with other app poll loop service code.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_read(struct lws *wsi, unsigned char *buf, size_t len);
|
||||
lws_read(struct lws *wsi, unsigned char *buf, lws_filepos_t len);
|
||||
|
||||
/**
|
||||
* lws_set_allocator() - custom allocator support
|
||||
|
@ -4107,11 +4584,20 @@ lws_send_pipe_choked(struct lws *wsi);
|
|||
|
||||
/**
|
||||
* lws_is_final_fragment() - tests if last part of ws message
|
||||
*
|
||||
* \param wsi: lws connection
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_is_final_fragment(struct lws *wsi);
|
||||
|
||||
/**
|
||||
* lws_is_first_fragment() - tests if first part of ws message
|
||||
*
|
||||
* \param wsi: lws connection
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_is_first_fragment(struct lws *wsi);
|
||||
|
||||
/**
|
||||
* lws_get_reserved_bits() - access reserved bits of ws frame
|
||||
* \param wsi: lws connection
|
||||
|
@ -4249,6 +4735,8 @@ enum lws_cgi_hdr_state {
|
|||
LCHS_LF1,
|
||||
LCHS_CR2,
|
||||
LCHS_LF2,
|
||||
LHCS_RESPONSE,
|
||||
LHCS_DUMP_HEADERS,
|
||||
LHCS_PAYLOAD,
|
||||
LCHS_SINGLE_0A,
|
||||
};
|
||||
|
@ -4341,32 +4829,6 @@ lws_cgi_kill(struct lws *wsi);
|
|||
|
||||
struct lws_plat_file_ops;
|
||||
|
||||
#if (defined(WIN32) || defined(_WIN32)) && !defined(__MINGW32__)
|
||||
/* ... */
|
||||
#if !defined(ssize_t)
|
||||
typedef SSIZE_T ssize_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(LWS_HAVE_STDINT_H)
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
/* !!! >:-[ */
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
#else
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned char uint8_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef size_t lws_filepos_t;
|
||||
typedef ssize_t lws_fileofs_t;
|
||||
typedef uint32_t lws_fop_flags_t;
|
||||
|
||||
struct lws_fop_fd {
|
||||
lws_filefd_type fd;
|
||||
/**< real file descriptor related to the file... */
|
||||
|
@ -4563,6 +5025,9 @@ LWS_VISIBLE LWS_EXTERN int
|
|||
_lws_plat_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
|
||||
uint8_t *buf, lws_filepos_t len);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_alloc_vfs_file(struct lws_context *context, const char *filename, uint8_t **buf,
|
||||
lws_filepos_t *amount);
|
||||
//@}
|
||||
|
||||
/** \defgroup smtp
|
||||
|
@ -4689,6 +5154,56 @@ lws_email_destroy(struct lws_email *email);
|
|||
#endif
|
||||
//@}
|
||||
|
||||
/*
|
||||
* Stats are all uint64_t numbers that start at 0.
|
||||
* Index names here have the convention
|
||||
*
|
||||
* _C_ counter
|
||||
* _B_ byte count
|
||||
* _MS_ millisecond count
|
||||
*/
|
||||
|
||||
enum {
|
||||
LWSSTATS_C_CONNECTIONS, /**< count incoming connections */
|
||||
LWSSTATS_C_API_CLOSE, /**< count calls to close api */
|
||||
LWSSTATS_C_API_READ, /**< count calls to read from socket api */
|
||||
LWSSTATS_C_API_LWS_WRITE, /**< count calls to lws_write API */
|
||||
LWSSTATS_C_API_WRITE, /**< count calls to write API */
|
||||
LWSSTATS_C_WRITE_PARTIALS, /**< count of partial writes */
|
||||
LWSSTATS_C_WRITEABLE_CB_REQ, /**< count of writable callback requests */
|
||||
LWSSTATS_C_WRITEABLE_CB_EFF_REQ, /**< count of effective writable callback requests */
|
||||
LWSSTATS_C_WRITEABLE_CB, /**< count of writable callbacks */
|
||||
LWSSTATS_C_SSL_CONNECTIONS_FAILED, /**< count of failed SSL connections */
|
||||
LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED, /**< count of accepted SSL connections */
|
||||
LWSSTATS_C_SSL_CONNS_HAD_RX, /**< count of accepted SSL conns that have had some RX */
|
||||
LWSSTATS_C_TIMEOUTS, /**< count of timed-out connections */
|
||||
LWSSTATS_C_SERVICE_ENTRY, /**< count of entries to lws service loop */
|
||||
LWSSTATS_B_READ, /**< aggregate bytes read */
|
||||
LWSSTATS_B_WRITE, /**< aggregate bytes written */
|
||||
LWSSTATS_B_PARTIALS_ACCEPTED_PARTS, /**< aggreate of size of accepted write data from new partials */
|
||||
LWSSTATS_MS_SSL_CONNECTIONS_ACCEPTED_DELAY, /**< aggregate delay in accepting connection */
|
||||
LWSSTATS_MS_WRITABLE_DELAY, /**< aggregate delay between asking for writable and getting cb */
|
||||
LWSSTATS_MS_WORST_WRITABLE_DELAY, /**< single worst delay between asking for writable and getting cb */
|
||||
LWSSTATS_MS_SSL_RX_DELAY, /**< aggregate delay between ssl accept complete and first RX */
|
||||
|
||||
/* Add new things just above here ---^
|
||||
* This is part of the ABI, don't needlessly break compatibility */
|
||||
LWSSTATS_SIZE
|
||||
};
|
||||
|
||||
#if defined(LWS_WITH_STATS)
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN uint64_t
|
||||
lws_stats_get(struct lws_context *context, int index);
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_stats_log_dump(struct lws_context *context);
|
||||
#else
|
||||
static LWS_INLINE uint64_t
|
||||
lws_stats_get(struct lws_context *context, int index) { return 0; }
|
||||
static LWS_INLINE void
|
||||
lws_stats_log_dump(struct lws_context *context) { }
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
1151
lib/lws-plat-esp32.c
1151
lib/lws-plat-esp32.c
File diff suppressed because it is too large
Load diff
|
@ -630,6 +630,13 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
|
|||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_inet_pton(int af, const char *src, void *dst)
|
||||
{
|
||||
//return inet_pton(af, src, dst);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_init(struct lws_context *context,
|
||||
struct lws_context_creation_info *info)
|
||||
|
@ -663,7 +670,8 @@ lws_plat_init(struct lws_context *context,
|
|||
os_timer_arm(&context->to_timer, 1000, 1);
|
||||
|
||||
if (!lws_libev_init_fd_table(context) &&
|
||||
!lws_libuv_init_fd_table(context)) {
|
||||
!lws_libuv_init_fd_table(context) &&
|
||||
!lws_libevent_init_fd_table(context)) {
|
||||
/* otherwise libev handled it instead */
|
||||
#if 0
|
||||
while (n--) {
|
||||
|
|
|
@ -261,6 +261,13 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
|
|||
return "lws_plat_inet_ntop";
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_inet_pton(int af, const char *src, void *dst)
|
||||
{
|
||||
//return inet_pton(af, src, dst);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE lws_fop_fd_t
|
||||
_lws_plat_file_open(lws_plat_file_open(struct lws_plat_file_ops *fops,
|
||||
const char *filename, lws_fop_flags_t *flags)
|
||||
|
|
|
@ -114,11 +114,14 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
|
|||
|
||||
pt = &context->pt[tsi];
|
||||
|
||||
lws_stats_atomic_bump(context, pt, LWSSTATS_C_SERVICE_ENTRY, 1);
|
||||
|
||||
if (timeout_ms < 0)
|
||||
goto faked_service;
|
||||
|
||||
lws_libev_run(context, tsi);
|
||||
lws_libuv_run(context, tsi);
|
||||
lws_libevent_run(context, tsi);
|
||||
|
||||
if (!context->service_tid_detected) {
|
||||
struct lws _lws;
|
||||
|
@ -252,6 +255,17 @@ lws_plat_set_socket_options(struct lws_vhost *vhost, int fd)
|
|||
#endif
|
||||
}
|
||||
|
||||
#if defined(SO_BINDTODEVICE)
|
||||
if (vhost->bind_iface && vhost->iface) {
|
||||
lwsl_info("binding listen skt to %s using SO_BINDTODEVICE\n", vhost->iface);
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, vhost->iface,
|
||||
strlen(vhost->iface)) < 0) {
|
||||
lwsl_warn("Failed to bind to device %s\n", vhost->iface);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Disable Nagle */
|
||||
optval = 1;
|
||||
#if defined (__sun)
|
||||
|
@ -276,9 +290,31 @@ lws_plat_set_socket_options(struct lws_vhost *vhost, int fd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
|
||||
static void
|
||||
_lws_plat_apply_caps(int mode, cap_value_t *cv, int count)
|
||||
{
|
||||
cap_t caps;
|
||||
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
caps = cap_get_proc();
|
||||
|
||||
cap_set_flag(caps, mode, count, cv, CAP_SET);
|
||||
cap_set_proc(caps);
|
||||
prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
|
||||
cap_free(caps);
|
||||
}
|
||||
#endif
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
|
||||
{
|
||||
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
|
||||
int n;
|
||||
#endif
|
||||
|
||||
if (info->gid != -1)
|
||||
if (setgid(info->gid))
|
||||
lwsl_warn("setgid: %s\n", strerror(LWS_ERRNO));
|
||||
|
@ -287,11 +323,25 @@ lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
|
|||
struct passwd *p = getpwuid(info->uid);
|
||||
|
||||
if (p) {
|
||||
|
||||
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
|
||||
_lws_plat_apply_caps(CAP_PERMITTED, info->caps, info->count_caps);
|
||||
#endif
|
||||
|
||||
initgroups(p->pw_name, info->gid);
|
||||
if (setuid(info->uid))
|
||||
lwsl_warn("setuid: %s\n", strerror(LWS_ERRNO));
|
||||
else
|
||||
lwsl_notice("Set privs to user '%s'\n", p->pw_name);
|
||||
|
||||
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
|
||||
_lws_plat_apply_caps(CAP_EFFECTIVE, info->caps, info->count_caps);
|
||||
|
||||
if (info->count_caps)
|
||||
for (n = 0; n < info->count_caps; n++)
|
||||
lwsl_notice(" RETAINING CAPABILITY %d\n", (int)info->caps[n]);
|
||||
#endif
|
||||
|
||||
} else
|
||||
lwsl_warn("getpwuid: unable to find uid %d", info->uid);
|
||||
}
|
||||
|
@ -454,7 +504,9 @@ sigabrt_handler(int x)
|
|||
LWS_VISIBLE int
|
||||
lws_plat_context_early_init(void)
|
||||
{
|
||||
#if !defined(LWS_AVOID_SIGPIPE_IGN)
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
// signal(SIGABRT, sigabrt_handler);
|
||||
|
||||
|
@ -571,6 +623,7 @@ lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
|
|||
|
||||
lws_libev_io(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
lws_libuv_io(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
lws_libevent_io(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
|
||||
pt->fds[pt->fds_count++].revents = 0;
|
||||
}
|
||||
|
@ -583,6 +636,7 @@ lws_plat_delete_socket_from_fds(struct lws_context *context,
|
|||
|
||||
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);
|
||||
lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);
|
||||
lws_libevent_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);
|
||||
|
||||
pt->fds_count--;
|
||||
}
|
||||
|
@ -609,6 +663,12 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
|
|||
return inet_ntop(af, src, dst, cnt);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_inet_pton(int af, const char *src, void *dst)
|
||||
{
|
||||
return inet_pton(af, src, dst);
|
||||
}
|
||||
|
||||
LWS_VISIBLE lws_fop_fd_t
|
||||
_lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
|
||||
const char *vpath, lws_fop_flags_t *flags)
|
||||
|
@ -740,7 +800,8 @@ lws_plat_init(struct lws_context *context,
|
|||
}
|
||||
|
||||
if (!lws_libev_init_fd_table(context) &&
|
||||
!lws_libuv_init_fd_table(context)) {
|
||||
!lws_libuv_init_fd_table(context) &&
|
||||
!lws_libevent_init_fd_table(context)) {
|
||||
/* otherwise libev handled it instead */
|
||||
|
||||
while (n--) {
|
||||
|
|
|
@ -218,6 +218,9 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
|
|||
/* if something closed, retry this slot */
|
||||
if (n)
|
||||
i--;
|
||||
|
||||
if (wsi->trunc_len)
|
||||
WSASetEvent(pt->events[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -398,6 +401,16 @@ LWS_VISIBLE LWS_EXTERN int
|
|||
lws_interface_to_sa(int ipv6,
|
||||
const char *ifname, struct sockaddr_in *addr, size_t addrlen)
|
||||
{
|
||||
#ifdef LWS_USE_IPV6
|
||||
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
|
||||
|
||||
if (ipv6) {
|
||||
if (lws_plat_inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
long long address = inet_addr(ifname);
|
||||
|
||||
if (address == INADDR_NONE) {
|
||||
|
@ -409,7 +422,7 @@ lws_interface_to_sa(int ipv6,
|
|||
if (address == INADDR_NONE)
|
||||
return -1;
|
||||
|
||||
addr->sin_addr.s_addr = (unsigned long)address;
|
||||
addr->sin_addr.s_addr = (lws_intptr_t)address;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -525,6 +538,59 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
|
|||
return ok ? dst : NULL;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_inet_pton(int af, const char *src, void *dst)
|
||||
{
|
||||
WCHAR *buffer;
|
||||
DWORD bufferlen = strlen(src) + 1;
|
||||
BOOL ok = FALSE;
|
||||
|
||||
buffer = lws_malloc(bufferlen * 2);
|
||||
if (!buffer) {
|
||||
lwsl_err("Out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (MultiByteToWideChar(CP_ACP, 0, src, bufferlen, buffer, bufferlen) <= 0) {
|
||||
lwsl_err("Failed to convert multi byte to wide char\n");
|
||||
lws_free(buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (af == AF_INET) {
|
||||
struct sockaddr_in dstaddr;
|
||||
int dstaddrlen = sizeof(dstaddr);
|
||||
bzero(&dstaddr, sizeof(dstaddr));
|
||||
dstaddr.sin_family = AF_INET;
|
||||
|
||||
if (!WSAStringToAddressW(buffer, af, 0, (struct sockaddr *) &dstaddr, &dstaddrlen)) {
|
||||
ok = TRUE;
|
||||
memcpy(dst, &dstaddr.sin_addr, sizeof(dstaddr.sin_addr));
|
||||
}
|
||||
#ifdef LWS_USE_IPV6
|
||||
} else if (af == AF_INET6) {
|
||||
struct sockaddr_in6 dstaddr;
|
||||
int dstaddrlen = sizeof(dstaddr);
|
||||
bzero(&dstaddr, sizeof(dstaddr));
|
||||
dstaddr.sin6_family = AF_INET6;
|
||||
|
||||
if (!WSAStringToAddressW(buffer, af, 0, (struct sockaddr *) &dstaddr, &dstaddrlen)) {
|
||||
ok = TRUE;
|
||||
memcpy(dst, &dstaddr.sin6_addr, sizeof(dstaddr.sin6_addr));
|
||||
}
|
||||
#endif
|
||||
} else
|
||||
lwsl_err("Unsupported type\n");
|
||||
|
||||
if (!ok) {
|
||||
int rv = WSAGetLastError();
|
||||
lwsl_err("WSAAddressToString() : %d\n", rv);
|
||||
}
|
||||
|
||||
lws_free(buffer);
|
||||
return ok ? 1 : -1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE lws_fop_fd_t
|
||||
_lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
|
||||
const char *vpath, lws_fop_flags_t *flags)
|
||||
|
@ -532,14 +598,15 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
|
|||
HANDLE ret;
|
||||
WCHAR buf[MAX_PATH];
|
||||
lws_fop_fd_t fop_fd;
|
||||
LARGE_INTEGER llFileSize = {0};
|
||||
|
||||
MultiByteToWideChar(CP_UTF8, 0, filename, -1, buf, ARRAY_SIZE(buf));
|
||||
if (((*flags) & 7) == _O_RDONLY) {
|
||||
ret = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
} else {
|
||||
lwsl_err("%s: open for write not implemented\n", __func__);
|
||||
goto bail;
|
||||
ret = CreateFileW(buf, GENERIC_WRITE, 0, NULL,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
}
|
||||
|
||||
if (ret == LWS_INVALID_FILE)
|
||||
|
@ -554,6 +621,9 @@ _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename,
|
|||
fop_fd->filesystem_priv = NULL; /* we don't use it */
|
||||
fop_fd->flags = *flags;
|
||||
fop_fd->len = GetFileSize(ret, NULL);
|
||||
if(GetFileSizeEx(ret, &llFileSize))
|
||||
fop_fd->len = llFileSize.QuadPart;
|
||||
|
||||
fop_fd->pos = 0;
|
||||
|
||||
return fop_fd;
|
||||
|
@ -578,7 +648,10 @@ _lws_plat_file_close(lws_fop_fd_t *fop_fd)
|
|||
LWS_VISIBLE lws_fileofs_t
|
||||
_lws_plat_file_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset)
|
||||
{
|
||||
return SetFilePointer((HANDLE)fop_fd->fd, offset, NULL, FILE_CURRENT);
|
||||
LARGE_INTEGER l;
|
||||
|
||||
l.QuadPart = offset;
|
||||
return SetFilePointerEx((HANDLE)fop_fd->fd, l, NULL, FILE_CURRENT);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
|
@ -603,16 +676,18 @@ LWS_VISIBLE int
|
|||
_lws_plat_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
|
||||
uint8_t* buf, lws_filepos_t len)
|
||||
{
|
||||
(void)fop_fd;
|
||||
(void)amount;
|
||||
(void)buf;
|
||||
(void)len;
|
||||
DWORD _amount;
|
||||
|
||||
fop_fd->pos += len;
|
||||
if (!WriteFile((HANDLE)fop_fd->fd, buf, (DWORD)len, &_amount, NULL)) {
|
||||
*amount = 0;
|
||||
|
||||
lwsl_err("%s: not implemented yet on this platform\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
fop_fd->pos += _amount;
|
||||
*amount = (unsigned long)_amount;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
|
|
88
lib/output.c
88
lib/output.c
|
@ -95,10 +95,13 @@ LWS_VISIBLE void lwsl_hexdump(void *vbuf, size_t len)
|
|||
int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
|
||||
{
|
||||
struct lws_context *context = lws_get_context(wsi);
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
size_t real_len = len;
|
||||
unsigned int n;
|
||||
int m;
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_API_WRITE, 1);
|
||||
|
||||
if (!len)
|
||||
return 0;
|
||||
/* just ignore sends after we cleared the truncation buffer */
|
||||
|
@ -137,9 +140,13 @@ int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
|
|||
lwsl_warn("** error invalid sock but expected to send\n");
|
||||
|
||||
/* limit sending */
|
||||
n = wsi->protocol->rx_buffer_size;
|
||||
if (!n)
|
||||
n = context->pt_serv_buf_size;
|
||||
if (wsi->protocol->tx_packet_size)
|
||||
n = wsi->protocol->tx_packet_size;
|
||||
else {
|
||||
n = wsi->protocol->rx_buffer_size;
|
||||
if (!n)
|
||||
n = context->pt_serv_buf_size;
|
||||
}
|
||||
n += LWS_PRE + 4;
|
||||
if (n > len)
|
||||
n = len;
|
||||
|
@ -155,6 +162,8 @@ int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
|
|||
n = lws_ssl_capable_write(wsi, buf, n);
|
||||
lws_latency(context, wsi, "send lws_issue_raw", n, n == len);
|
||||
|
||||
//lwsl_notice("lws_ssl_capable_write: %d\n", n);
|
||||
|
||||
switch (n) {
|
||||
case LWS_SSL_CAPABLE_ERROR:
|
||||
/* we're going to close, let close know sends aren't possible */
|
||||
|
@ -198,9 +207,12 @@ handle_truncated_send:
|
|||
* Newly truncated send. Buffer the remainder (it will get
|
||||
* first priority next time the socket is writable)
|
||||
*/
|
||||
lwsl_info("%p new partial sent %d from %lu total\n", wsi, n,
|
||||
lwsl_debug("%p new partial sent %d from %lu total\n", wsi, n,
|
||||
(unsigned long)real_len);
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITE_PARTIALS, 1);
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_B_PARTIALS_ACCEPTED_PARTS, n);
|
||||
|
||||
/*
|
||||
* - if we still have a suitable malloc lying around, use it
|
||||
* - or, if too small, reallocate it
|
||||
|
@ -238,6 +250,33 @@ LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len,
|
|||
int pre = 0, n;
|
||||
size_t orig_len = len;
|
||||
|
||||
if (wsi->parent_carries_io) {
|
||||
struct lws_write_passthru pas;
|
||||
|
||||
pas.buf = buf;
|
||||
pas.len = len;
|
||||
pas.wp = wp;
|
||||
pas.wsi = wsi;
|
||||
|
||||
if (wsi->parent->protocol->callback(wsi->parent,
|
||||
LWS_CALLBACK_CHILD_WRITE_VIA_PARENT,
|
||||
wsi->parent->user_space,
|
||||
(void *)&pas, 0))
|
||||
return 1;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_API_LWS_WRITE, 1);
|
||||
|
||||
if ((int)len < 0) {
|
||||
lwsl_err("%s: suspicious len int %d, ulong %lu\n", __func__,
|
||||
(int)len, (unsigned long)len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_B_WRITE, len);
|
||||
|
||||
#ifdef LWS_WITH_ACCESS_LOG
|
||||
wsi->access_log.sent += len;
|
||||
#endif
|
||||
|
@ -247,7 +286,8 @@ LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len,
|
|||
if (wsi->state == LWSS_ESTABLISHED && wsi->u.ws.tx_draining_ext) {
|
||||
/* remove us from the list */
|
||||
struct lws **w = &pt->tx_draining_ext_list;
|
||||
lwsl_debug("%s: TX EXT DRAINING: Remove from list\n", __func__);
|
||||
|
||||
// lwsl_notice("%s: TX EXT DRAINING: Remove from list\n", __func__);
|
||||
wsi->u.ws.tx_draining_ext = 0;
|
||||
/* remove us from context draining ext list */
|
||||
while (*w) {
|
||||
|
@ -310,11 +350,13 @@ LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len,
|
|||
case LWS_WRITE_CLOSE:
|
||||
break;
|
||||
default:
|
||||
lwsl_debug("LWS_EXT_CB_PAYLOAD_TX\n");
|
||||
n = lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_TX, &eff_buf, wp);
|
||||
if (n < 0)
|
||||
return -1;
|
||||
|
||||
if (n && eff_buf.token_len) {
|
||||
lwsl_debug("drain len %d\n", (int)eff_buf.token_len);
|
||||
/* extension requires further draining */
|
||||
wsi->u.ws.tx_draining_ext = 1;
|
||||
wsi->u.ws.tx_draining_ext_list = pt->tx_draining_ext_list;
|
||||
|
@ -348,8 +390,8 @@ LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len,
|
|||
*/
|
||||
if ((char *)buf != eff_buf.token) {
|
||||
/*
|
||||
* ext might eat it, but no have anything to issue yet
|
||||
* in that case we have to follow his lead, but stash and
|
||||
* ext might eat it, but not have anything to issue yet.
|
||||
* In that case we have to follow his lead, but stash and
|
||||
* replace the write type that was lost here the first time.
|
||||
*/
|
||||
if (len && !eff_buf.token_len) {
|
||||
|
@ -368,6 +410,13 @@ LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len,
|
|||
buf = (unsigned char *)eff_buf.token;
|
||||
len = eff_buf.token_len;
|
||||
|
||||
lwsl_debug("%p / %d\n", buf, (int)len);
|
||||
|
||||
if (!buf) {
|
||||
lwsl_err("null buf (%d)\n", (int)len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (wsi->ietf_spec_revision) {
|
||||
case 13:
|
||||
if (masked7) {
|
||||
|
@ -491,8 +540,8 @@ send_raw:
|
|||
wp == LWS_WRITE_HTTP_FINAL) &&
|
||||
wsi->u.http.content_length) {
|
||||
wsi->u.http.content_remain -= len;
|
||||
lwsl_info("%s: content_remain = %lu\n", __func__,
|
||||
(unsigned long)wsi->u.http.content_remain);
|
||||
lwsl_info("%s: content_remain = %llu\n", __func__,
|
||||
(unsigned long long)wsi->u.http.content_remain);
|
||||
if (!wsi->u.http.content_remain) {
|
||||
lwsl_info("%s: selecting final write mode\n", __func__);
|
||||
wp = LWS_WRITE_HTTP_FINAL;
|
||||
|
@ -591,7 +640,7 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
|
|||
|
||||
lwsl_notice("%s: doing range start %llu\n", __func__, wsi->u.http.range.start);
|
||||
|
||||
if ((long)lws_vfs_file_seek_cur(wsi->u.http.fop_fd,
|
||||
if ((long long)lws_vfs_file_seek_cur(wsi->u.http.fop_fd,
|
||||
wsi->u.http.range.start -
|
||||
wsi->u.http.filepos) < 0)
|
||||
goto file_had_it;
|
||||
|
@ -618,6 +667,14 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
|
|||
#endif
|
||||
|
||||
poss = context->pt_serv_buf_size - n;
|
||||
|
||||
/*
|
||||
* if there is a hint about how much we will do well to send at one time,
|
||||
* restrict ourselves to only trying to send that.
|
||||
*/
|
||||
if (wsi->protocol->tx_packet_size && poss > wsi->protocol->tx_packet_size)
|
||||
poss = wsi->protocol->tx_packet_size;
|
||||
|
||||
#if defined(LWS_WITH_RANGES)
|
||||
if (wsi->u.http.range.count_ranges) {
|
||||
if (wsi->u.http.range.count_ranges > 1)
|
||||
|
@ -649,7 +706,7 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi)
|
|||
if (wsi->sending_chunked) {
|
||||
args.p = (char *)p;
|
||||
args.len = n;
|
||||
args.max_len = poss + 128;
|
||||
args.max_len = (unsigned int)poss + 128;
|
||||
args.final = wsi->u.http.filepos + n ==
|
||||
wsi->u.http.filelen;
|
||||
if (user_callback_handle_rxflow(
|
||||
|
@ -746,12 +803,17 @@ file_had_it:
|
|||
LWS_VISIBLE int
|
||||
lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
int n;
|
||||
|
||||
lws_stats_atomic_bump(context, pt, LWSSTATS_C_API_READ, 1);
|
||||
|
||||
n = recv(wsi->desc.sockfd, (char *)buf, len, 0);
|
||||
if (n >= 0) {
|
||||
if (wsi->vhost)
|
||||
wsi->vhost->conn_stats.rx += n;
|
||||
lws_stats_atomic_bump(context, pt, LWSSTATS_B_READ, n);
|
||||
lws_restart_ws_ping_pong_timer(wsi);
|
||||
return n;
|
||||
}
|
||||
|
@ -801,5 +863,9 @@ LWS_VISIBLE int
|
|||
lws_ssl_pending_no_ssl(struct lws *wsi)
|
||||
{
|
||||
(void)wsi;
|
||||
#if defined(LWS_WITH_ESP32)
|
||||
return 100;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
|
113
lib/parsers.c
113
lib/parsers.c
|
@ -86,8 +86,15 @@ lws_header_table_reset(struct lws *wsi, int autoservice)
|
|||
|
||||
_lws_header_table_reset(ah);
|
||||
|
||||
wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
|
||||
wsi->u.hdr.lextable_pos = 0;
|
||||
|
||||
/* 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
|
||||
|
@ -181,7 +188,7 @@ lws_header_table_attach(struct lws *wsi, int autoservice)
|
|||
|
||||
_lws_change_pollfd(wsi, 0, LWS_POLLIN, &pa);
|
||||
|
||||
lwsl_info("%s: wsi %p: ah %p: count %d (on exit)\n", __func__,
|
||||
lwsl_info("%s: did attach wsi %p: ah %p: count %d (on exit)\n", __func__,
|
||||
(void *)wsi, (void *)wsi->u.hdr.ah, pt->ah_count_in_use);
|
||||
|
||||
lws_pt_unlock(pt);
|
||||
|
@ -212,6 +219,47 @@ bail:
|
|||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
lws_header_table_force_to_detachable_state(struct lws *wsi)
|
||||
{
|
||||
if (wsi->u.hdr.ah) {
|
||||
wsi->u.hdr.ah->rxpos = -1;
|
||||
wsi->u.hdr.ah->rxlen = -1;
|
||||
wsi->hdr_parsing_completed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
lws_header_table_is_in_detachable_state(struct lws *wsi)
|
||||
{
|
||||
struct allocated_headers *ah = wsi->u.hdr.ah;
|
||||
|
||||
return ah && ah->rxpos == ah->rxlen && wsi->hdr_parsing_completed;
|
||||
}
|
||||
|
||||
void
|
||||
__lws_remove_from_ah_waiting_list(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
struct lws **pwsi =&pt->ah_wait_list;
|
||||
|
||||
if (wsi->u.hdr.ah)
|
||||
return;
|
||||
|
||||
while (*pwsi) {
|
||||
if (*pwsi == wsi) {
|
||||
lwsl_info("%s: wsi %p, remv wait\n",
|
||||
__func__, wsi);
|
||||
*pwsi = wsi->u.hdr.ah_wait_list;
|
||||
wsi->u.hdr.ah_wait_list = NULL;
|
||||
pt->ah_wait_list_length--;
|
||||
return;
|
||||
}
|
||||
pwsi = &(*pwsi)->u.hdr.ah_wait_list;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int lws_header_table_detach(struct lws *wsi, int autoservice)
|
||||
{
|
||||
struct lws_context *context = wsi->context;
|
||||
|
@ -221,6 +269,13 @@ int lws_header_table_detach(struct lws *wsi, int autoservice)
|
|||
struct lws **pwsi;
|
||||
time_t now;
|
||||
|
||||
lws_pt_lock(pt);
|
||||
__lws_remove_from_ah_waiting_list(wsi);
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
if (!ah)
|
||||
return 0;
|
||||
|
||||
lwsl_info("%s: wsi %p: ah %p (tsi=%d, count = %d)\n", __func__,
|
||||
(void *)wsi, (void *)ah, wsi->tsi,
|
||||
pt->ah_count_in_use);
|
||||
|
@ -229,32 +284,14 @@ int lws_header_table_detach(struct lws *wsi, int autoservice)
|
|||
lws_free_set_NULL(wsi->u.hdr.preamble_rx);
|
||||
|
||||
/* may not be detached while he still has unprocessed rx */
|
||||
if (ah && ah->rxpos != ah->rxlen) {
|
||||
lwsl_err("%s: %p: CANNOT DETACH rxpos:%d, rxlen:%d\n", __func__, wsi,
|
||||
ah->rxpos, ah->rxlen);
|
||||
assert(ah->rxpos == ah->rxlen);
|
||||
|
||||
if (!lws_header_table_is_in_detachable_state(wsi)) {
|
||||
lwsl_err("%s: %p: CANNOT DETACH rxpos:%d, rxlen:%d, wsi->hdr_parsing_completed = %d\n", __func__, wsi,
|
||||
ah->rxpos, ah->rxlen, wsi->hdr_parsing_completed);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lws_pt_lock(pt);
|
||||
|
||||
pwsi = &pt->ah_wait_list;
|
||||
if (!ah) { /* remove from wait list if none attached */
|
||||
while (*pwsi) {
|
||||
if (*pwsi == wsi) {
|
||||
lwsl_info("%s: wsi %p, remv wait\n",
|
||||
__func__, wsi);
|
||||
*pwsi = wsi->u.hdr.ah_wait_list;
|
||||
wsi->u.hdr.ah_wait_list = NULL;
|
||||
pt->ah_wait_list_length--;
|
||||
goto bail;
|
||||
}
|
||||
pwsi = &(*pwsi)->u.hdr.ah_wait_list;
|
||||
}
|
||||
/* no ah, not on list... no more business here */
|
||||
goto bail;
|
||||
}
|
||||
/* we did have an ah attached */
|
||||
time(&now);
|
||||
if (ah->assigned && now - ah->assigned > 3) {
|
||||
|
@ -279,6 +316,8 @@ int lws_header_table_detach(struct lws *wsi, int autoservice)
|
|||
wsi->u.hdr.ah = NULL;
|
||||
ah->wsi = NULL; /* no owner */
|
||||
|
||||
pwsi = &pt->ah_wait_list;
|
||||
|
||||
/* oh there is nobody on the waiting list... leave it at that then */
|
||||
if (!*pwsi) {
|
||||
ah->in_use = 0;
|
||||
|
@ -321,18 +360,21 @@ int lws_header_table_detach(struct lws *wsi, int autoservice)
|
|||
pt->ah_wait_list_length--;
|
||||
|
||||
#ifndef LWS_NO_CLIENT
|
||||
if (wsi->state == LWSS_CLIENT_UNCONNECTED)
|
||||
if (wsi->state == LWSS_CLIENT_UNCONNECTED) {
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
if (!lws_client_connect_via_info2(wsi)) {
|
||||
/* our client connect has failed, the wsi
|
||||
* has been closed
|
||||
*/
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
assert(!!pt->ah_wait_list_length == !!(int)(long)pt->ah_wait_list);
|
||||
assert(!!pt->ah_wait_list_length == !!(lws_intptr_t)pt->ah_wait_list);
|
||||
bail:
|
||||
lwsl_info("%s: wsi %p: ah %p (tsi=%d, count = %d)\n", __func__,
|
||||
(void *)wsi, (void *)ah, wsi->tsi,
|
||||
|
@ -347,6 +389,9 @@ lws_hdr_fragment_length(struct lws *wsi, enum lws_token_indexes h, int frag_idx)
|
|||
{
|
||||
int n;
|
||||
|
||||
if (!wsi->u.hdr.ah)
|
||||
return 0;
|
||||
|
||||
n = wsi->u.hdr.ah->frag_index[h];
|
||||
if (!n)
|
||||
return 0;
|
||||
|
@ -364,6 +409,9 @@ LWS_VISIBLE int lws_hdr_total_length(struct lws *wsi, enum lws_token_indexes h)
|
|||
int n;
|
||||
int len = 0;
|
||||
|
||||
if (!wsi->u.hdr.ah)
|
||||
return 0;
|
||||
|
||||
n = wsi->u.hdr.ah->frag_index[h];
|
||||
if (!n)
|
||||
return 0;
|
||||
|
@ -379,7 +427,12 @@ LWS_VISIBLE int lws_hdr_copy_fragment(struct lws *wsi, char *dst, int len,
|
|||
enum lws_token_indexes h, int frag_idx)
|
||||
{
|
||||
int n = 0;
|
||||
int f = wsi->u.hdr.ah->frag_index[h];
|
||||
int f;
|
||||
|
||||
if (!wsi->u.hdr.ah)
|
||||
return -1;
|
||||
|
||||
f = wsi->u.hdr.ah->frag_index[h];
|
||||
|
||||
if (!f)
|
||||
return -1;
|
||||
|
@ -410,6 +463,9 @@ LWS_VISIBLE int lws_hdr_copy(struct lws *wsi, char *dst, int len,
|
|||
if (toklen >= len)
|
||||
return -1;
|
||||
|
||||
if (!wsi->u.hdr.ah)
|
||||
return -1;
|
||||
|
||||
n = wsi->u.hdr.ah->frag_index[h];
|
||||
if (!n)
|
||||
return 0;
|
||||
|
@ -1009,7 +1065,6 @@ lws_rx_sm(struct lws *wsi, unsigned char c)
|
|||
|
||||
eff_buf.token = NULL;
|
||||
eff_buf.token_len = 0;
|
||||
|
||||
if (wsi->socket_is_permanently_unusable)
|
||||
return -1;
|
||||
|
||||
|
@ -1108,6 +1163,7 @@ handle_first:
|
|||
wsi->u.ws.rsv_first_msg = (c & 0x70);
|
||||
wsi->u.ws.frame_is_binary =
|
||||
wsi->u.ws.opcode == LWSWSOPC_BINARY_FRAME;
|
||||
wsi->u.ws.first_fragment = 1;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
|
@ -1455,6 +1511,7 @@ drain_extension:
|
|||
/* eff_buf may be pointing somewhere completely different now,
|
||||
* it's the output
|
||||
*/
|
||||
wsi->u.ws.first_fragment = 0;
|
||||
if (n < 0) {
|
||||
/*
|
||||
* we may rely on this to get RX, just drop connection
|
||||
|
|
123
lib/pollfd.c
123
lib/pollfd.c
|
@ -78,18 +78,22 @@ _lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa)
|
|||
if (_and & LWS_POLLIN) {
|
||||
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_READ);
|
||||
lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_READ);
|
||||
lws_libevent_io(wsi, LWS_EV_STOP | LWS_EV_READ);
|
||||
}
|
||||
if (_or & LWS_POLLIN) {
|
||||
lws_libev_io(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
lws_libuv_io(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
lws_libevent_io(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
}
|
||||
if (_and & LWS_POLLOUT) {
|
||||
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_WRITE);
|
||||
lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_WRITE);
|
||||
lws_libevent_io(wsi, LWS_EV_STOP | LWS_EV_WRITE);
|
||||
}
|
||||
if (_or & LWS_POLLOUT) {
|
||||
lws_libev_io(wsi, LWS_EV_START | LWS_EV_WRITE);
|
||||
lws_libuv_io(wsi, LWS_EV_START | LWS_EV_WRITE);
|
||||
lws_libevent_io(wsi, LWS_EV_START | LWS_EV_WRITE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -232,6 +236,11 @@ remove_wsi_socket_from_fds(struct lws *wsi)
|
|||
#endif
|
||||
int m, ret = 0;
|
||||
|
||||
if (wsi->parent_carries_io) {
|
||||
lws_same_vh_protocol_remove(wsi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) && !defined(LWS_WITH_ESP8266)
|
||||
if (wsi->desc.sockfd > context->max_fds) {
|
||||
lwsl_err("fd %d too high (%d)\n", wsi->desc.sockfd, context->max_fds);
|
||||
|
@ -243,31 +252,7 @@ remove_wsi_socket_from_fds(struct lws *wsi)
|
|||
wsi->user_space, (void *)&pa, 1))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* detach ourselves from vh protocol list if we're on one
|
||||
* A -> B -> C
|
||||
* A -> C , or, B -> C, or A -> B
|
||||
*/
|
||||
lwsl_info("%s: removing same prot wsi %p\n", __func__, wsi);
|
||||
if (wsi->same_vh_protocol_prev) {
|
||||
assert (*(wsi->same_vh_protocol_prev) == wsi);
|
||||
lwsl_info("have prev %p, setting him to our next %p\n",
|
||||
wsi->same_vh_protocol_prev,
|
||||
wsi->same_vh_protocol_next);
|
||||
|
||||
/* guy who pointed to us should point to our next */
|
||||
*(wsi->same_vh_protocol_prev) = wsi->same_vh_protocol_next;
|
||||
} //else
|
||||
//lwsl_err("null wsi->prev\n");
|
||||
/* our next should point back to our prev */
|
||||
if (wsi->same_vh_protocol_next) {
|
||||
wsi->same_vh_protocol_next->same_vh_protocol_prev =
|
||||
wsi->same_vh_protocol_prev;
|
||||
} //else
|
||||
//lwsl_err("null wsi->next\n");
|
||||
|
||||
wsi->same_vh_protocol_prev = NULL;
|
||||
wsi->same_vh_protocol_next = NULL;
|
||||
lws_same_vh_protocol_remove(wsi);
|
||||
|
||||
/* the guy who is to be deleted's slot index in pt->fds */
|
||||
m = wsi->position_in_fds_table;
|
||||
|
@ -356,6 +341,7 @@ lws_change_pollfd(struct lws *wsi, int _and, int _or)
|
|||
LWS_VISIBLE int
|
||||
lws_callback_on_writable(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt;
|
||||
#ifdef LWS_USE_HTTP2
|
||||
struct lws *network_wsi, *wsi2;
|
||||
int already;
|
||||
|
@ -367,6 +353,25 @@ lws_callback_on_writable(struct lws *wsi)
|
|||
if (wsi->socket_is_permanently_unusable)
|
||||
return 0;
|
||||
|
||||
if (wsi->parent_carries_io) {
|
||||
int n = lws_callback_on_writable(wsi->parent);
|
||||
|
||||
if (n < 0)
|
||||
return n;
|
||||
|
||||
wsi->parent_pending_cb_on_writable = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB_REQ, 1);
|
||||
#if defined(LWS_WITH_STATS)
|
||||
if (!wsi->active_writable_req_us) {
|
||||
wsi->active_writable_req_us = time_in_microseconds();
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB_EFF_REQ, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LWS_USE_HTTP2
|
||||
lwsl_info("%s: %p\n", __func__, wsi);
|
||||
|
||||
|
@ -426,6 +431,74 @@ network_sock:
|
|||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* stitch protocol choice into the vh protocol linked list
|
||||
* We always insert ourselves at the start of the list
|
||||
*
|
||||
* X <-> B
|
||||
* X <-> pAn <-> pB
|
||||
*
|
||||
* Illegal to attach more than once without detach inbetween
|
||||
*/
|
||||
void
|
||||
lws_same_vh_protocol_insert(struct lws *wsi, int n)
|
||||
{
|
||||
//lwsl_err("%s: pre insert vhost start wsi %p, that wsi prev == %p\n",
|
||||
// __func__,
|
||||
// wsi->vhost->same_vh_protocol_list[n],
|
||||
// wsi->same_vh_protocol_prev);
|
||||
|
||||
if (wsi->same_vh_protocol_prev || wsi->same_vh_protocol_next) {
|
||||
lws_same_vh_protocol_remove(wsi);
|
||||
lwsl_notice("Attempted to attach wsi twice to same vh prot\n");
|
||||
}
|
||||
|
||||
wsi->same_vh_protocol_prev = /* guy who points to us */
|
||||
&wsi->vhost->same_vh_protocol_list[n];
|
||||
wsi->same_vh_protocol_next = /* old first guy is our next */
|
||||
wsi->vhost->same_vh_protocol_list[n];
|
||||
/* we become the new first guy */
|
||||
wsi->vhost->same_vh_protocol_list[n] = wsi;
|
||||
|
||||
if (wsi->same_vh_protocol_next)
|
||||
/* old first guy points back to us now */
|
||||
wsi->same_vh_protocol_next->same_vh_protocol_prev =
|
||||
&wsi->same_vh_protocol_next;
|
||||
}
|
||||
|
||||
void
|
||||
lws_same_vh_protocol_remove(struct lws *wsi)
|
||||
{
|
||||
/*
|
||||
* detach ourselves from vh protocol list if we're on one
|
||||
* A -> B -> C
|
||||
* A -> C , or, B -> C, or A -> B
|
||||
*
|
||||
* OK to call on already-detached wsi
|
||||
*/
|
||||
lwsl_info("%s: removing same prot wsi %p\n", __func__, wsi);
|
||||
|
||||
if (wsi->same_vh_protocol_prev) {
|
||||
assert (*(wsi->same_vh_protocol_prev) == wsi);
|
||||
lwsl_info("have prev %p, setting him to our next %p\n",
|
||||
wsi->same_vh_protocol_prev,
|
||||
wsi->same_vh_protocol_next);
|
||||
|
||||
/* guy who pointed to us should point to our next */
|
||||
*(wsi->same_vh_protocol_prev) = wsi->same_vh_protocol_next;
|
||||
}
|
||||
|
||||
/* our next should point back to our prev */
|
||||
if (wsi->same_vh_protocol_next) {
|
||||
wsi->same_vh_protocol_next->same_vh_protocol_prev =
|
||||
wsi->same_vh_protocol_prev;
|
||||
}
|
||||
|
||||
wsi->same_vh_protocol_prev = NULL;
|
||||
wsi->same_vh_protocol_next = NULL;
|
||||
}
|
||||
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_callback_on_writable_all_protocol_vhost(const struct lws_vhost *vhost,
|
||||
const struct lws_protocols *protocol)
|
||||
|
|
|
@ -134,6 +134,15 @@ char *ets_strchr(const char *s, int c);
|
|||
#include <mstcpip.h>
|
||||
#include <io.h>
|
||||
|
||||
#if !defined(LWS_HAVE_ATOLL)
|
||||
#if defined(LWS_HAVE__ATOI64)
|
||||
#define atoll _atoi64
|
||||
#else
|
||||
#warning No atoll or _atoi64 available, using atoi
|
||||
#define atoll atoi
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef __func__
|
||||
#define __func__ __FUNCTION__
|
||||
#endif
|
||||
|
@ -208,6 +217,9 @@ int kill(int pid, int sig);
|
|||
#ifdef LWS_USE_LIBUV
|
||||
#include <uv.h>
|
||||
#endif
|
||||
#ifdef LWS_USE_LIBEVENT
|
||||
#include <event2/event.h>
|
||||
#endif
|
||||
|
||||
#ifndef LWS_NO_FORK
|
||||
#ifdef LWS_HAVE_SYS_PRCTL_H
|
||||
|
@ -476,6 +488,7 @@ enum lws_connection_states {
|
|||
LWSS_ESTABLISHED,
|
||||
LWSS_CLIENT_HTTP_ESTABLISHED,
|
||||
LWSS_CLIENT_UNCONNECTED,
|
||||
LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION,
|
||||
LWSS_RETURNED_CLOSE_ALREADY,
|
||||
LWSS_AWAITING_CLOSE_ACK,
|
||||
LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE,
|
||||
|
@ -571,12 +584,75 @@ enum connection_mode {
|
|||
LWSCM_WSCL_WAITING_SERVER_REPLY,
|
||||
LWSCM_WSCL_WAITING_EXTENSION_CONNECT,
|
||||
LWSCM_WSCL_PENDING_CANDIDATE_CHILD,
|
||||
LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY,
|
||||
LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY,
|
||||
LWSCM_WSCL_WAITING_SOCKS_AUTH_REPLY,
|
||||
|
||||
/****** add new things just above ---^ ******/
|
||||
|
||||
|
||||
};
|
||||
|
||||
/* enums of socks version */
|
||||
enum socks_version {
|
||||
SOCKS_VERSION_4 = 4,
|
||||
SOCKS_VERSION_5 = 5
|
||||
};
|
||||
|
||||
/* enums of subnegotiation version */
|
||||
enum socks_subnegotiation_version {
|
||||
SOCKS_SUBNEGOTIATION_VERSION_1 = 1,
|
||||
};
|
||||
|
||||
/* enums of socks commands */
|
||||
enum socks_command {
|
||||
SOCKS_COMMAND_CONNECT = 1,
|
||||
SOCKS_COMMAND_BIND = 2,
|
||||
SOCKS_COMMAND_UDP_ASSOCIATE = 3
|
||||
};
|
||||
|
||||
/* enums of socks address type */
|
||||
enum socks_atyp {
|
||||
SOCKS_ATYP_IPV4 = 1,
|
||||
SOCKS_ATYP_DOMAINNAME = 3,
|
||||
SOCKS_ATYP_IPV6 = 4
|
||||
};
|
||||
|
||||
/* enums of socks authentication methods */
|
||||
enum socks_auth_method {
|
||||
SOCKS_AUTH_NO_AUTH = 0,
|
||||
SOCKS_AUTH_GSSAPI = 1,
|
||||
SOCKS_AUTH_USERNAME_PASSWORD = 2
|
||||
};
|
||||
|
||||
/* enums of subnegotiation status */
|
||||
enum socks_subnegotiation_status {
|
||||
SOCKS_SUBNEGOTIATION_STATUS_SUCCESS = 0,
|
||||
};
|
||||
|
||||
/* enums of socks request reply */
|
||||
enum socks_request_reply {
|
||||
SOCKS_REQUEST_REPLY_SUCCESS = 0,
|
||||
SOCKS_REQUEST_REPLY_FAILURE_GENERAL = 1,
|
||||
SOCKS_REQUEST_REPLY_CONNECTION_NOT_ALLOWED = 2,
|
||||
SOCKS_REQUEST_REPLY_NETWORK_UNREACHABLE = 3,
|
||||
SOCKS_REQUEST_REPLY_HOST_UNREACHABLE = 4,
|
||||
SOCKS_REQUEST_REPLY_CONNECTION_REFUSED = 5,
|
||||
SOCKS_REQUEST_REPLY_TTL_EXPIRED = 6,
|
||||
SOCKS_REQUEST_REPLY_COMMAND_NOT_SUPPORTED = 7,
|
||||
SOCKS_REQUEST_REPLY_ATYP_NOT_SUPPORTED = 8
|
||||
};
|
||||
|
||||
/* enums used to generate socks messages */
|
||||
enum socks_msg_type {
|
||||
/* greeting */
|
||||
SOCKS_MSG_GREETING,
|
||||
/* credential, user name and password */
|
||||
SOCKS_MSG_USERNAME_PASSWORD,
|
||||
/* connect command */
|
||||
SOCKS_MSG_CONNECT
|
||||
};
|
||||
|
||||
enum {
|
||||
LWS_RXFLOW_ALLOW = (1 << 0),
|
||||
LWS_RXFLOW_PENDING_CHANGE = (1 << 1),
|
||||
|
@ -588,7 +664,7 @@ enum {
|
|||
struct lws_protocols;
|
||||
struct lws;
|
||||
|
||||
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV)
|
||||
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV) || defined(LWS_USE_LIBEVENT)
|
||||
|
||||
struct lws_io_watcher {
|
||||
#ifdef LWS_USE_LIBEV
|
||||
|
@ -596,6 +672,9 @@ struct lws_io_watcher {
|
|||
#endif
|
||||
#ifdef LWS_USE_LIBUV
|
||||
uv_poll_t uv_watcher;
|
||||
#endif
|
||||
#ifdef LWS_USE_LIBEVENT
|
||||
struct event *event_watcher;
|
||||
#endif
|
||||
struct lws_context *context;
|
||||
};
|
||||
|
@ -606,6 +685,9 @@ struct lws_signal_watcher {
|
|||
#endif
|
||||
#ifdef LWS_USE_LIBUV
|
||||
uv_signal_t uv_watcher;
|
||||
#endif
|
||||
#ifdef LWS_USE_LIBEVENT
|
||||
struct event *event_watcher;
|
||||
#endif
|
||||
struct lws_context *context;
|
||||
};
|
||||
|
@ -683,7 +765,7 @@ struct lws_context_per_thread {
|
|||
struct lws *rx_draining_ext_list;
|
||||
struct lws *tx_draining_ext_list;
|
||||
struct lws *timeout_list;
|
||||
#ifdef LWS_USE_LIBUV
|
||||
#if defined(LWS_USE_LIBUV) || defined(LWS_USE_LIBEVENT)
|
||||
struct lws_context *context;
|
||||
#endif
|
||||
#ifdef LWS_WITH_CGI
|
||||
|
@ -705,10 +787,13 @@ struct lws_context_per_thread {
|
|||
uv_timer_t uv_timeout_watcher;
|
||||
uv_idle_t uv_idle;
|
||||
#endif
|
||||
#if defined(LWS_USE_LIBEVENT)
|
||||
struct event_base *io_loop_event_base;
|
||||
#endif
|
||||
#if defined(LWS_USE_LIBEV)
|
||||
struct lws_io_watcher w_accept;
|
||||
#endif
|
||||
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV)
|
||||
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV) || defined(LWS_USE_LIBEVENT)
|
||||
struct lws_signal_watcher w_sigint;
|
||||
unsigned char ev_loop_foreign:1;
|
||||
#endif
|
||||
|
@ -762,6 +847,11 @@ struct lws_vhost {
|
|||
#if !defined(LWS_WITH_ESP8266)
|
||||
char http_proxy_address[128];
|
||||
char proxy_basic_auth_token[128];
|
||||
#if defined(LWS_WITH_SOCKS5)
|
||||
char socks_proxy_address[128];
|
||||
char socks_user[96];
|
||||
char socks_password[96];
|
||||
#endif
|
||||
#endif
|
||||
#if defined(LWS_WITH_ESP8266)
|
||||
/* listen sockets need a place to hang their hat */
|
||||
|
@ -774,6 +864,9 @@ struct lws_vhost {
|
|||
struct lws *lserv_wsi;
|
||||
const char *name;
|
||||
const char *iface;
|
||||
#if !defined(LWS_WITH_ESP8266) && !defined(LWS_WITH_ESP32) && !defined(OPTEE_TA) && !defined(WIN32)
|
||||
int bind_iface;
|
||||
#endif
|
||||
const struct lws_protocols *protocols;
|
||||
void **protocol_vh_privs;
|
||||
const struct lws_protocol_vhost_options *pvo;
|
||||
|
@ -789,12 +882,17 @@ struct lws_vhost {
|
|||
|
||||
int listen_port;
|
||||
unsigned int http_proxy_port;
|
||||
#if defined(LWS_WITH_SOCKS5)
|
||||
unsigned int socks_proxy_port;
|
||||
#endif
|
||||
unsigned int options;
|
||||
int count_protocols;
|
||||
int ka_time;
|
||||
int ka_probes;
|
||||
int ka_interval;
|
||||
int keepalive_timeout;
|
||||
int timeout_secs_ah_idle;
|
||||
int ssl_info_event_mask;
|
||||
#ifdef LWS_WITH_ACCESS_LOG
|
||||
int log_fd;
|
||||
#endif
|
||||
|
@ -806,11 +904,19 @@ struct lws_vhost {
|
|||
#endif
|
||||
|
||||
unsigned int created_vhost_protocols:1;
|
||||
unsigned int being_destroyed:1;
|
||||
|
||||
unsigned char default_protocol_index;
|
||||
unsigned char raw_protocol_index;
|
||||
};
|
||||
|
||||
struct lws_deferred_free
|
||||
{
|
||||
struct lws_deferred_free *next;
|
||||
time_t deadline;
|
||||
void *payload;
|
||||
};
|
||||
|
||||
/*
|
||||
* the rest is managed per-context, that includes
|
||||
*
|
||||
|
@ -843,7 +949,9 @@ struct lws_context {
|
|||
#endif
|
||||
#endif
|
||||
struct lws_vhost *vhost_list;
|
||||
struct lws_vhost *vhost_pending_destruction_list;
|
||||
struct lws_plugin *plugin_list;
|
||||
struct lws_deferred_free *deferred_free_list;
|
||||
|
||||
void *external_baggage_free_on_destroy;
|
||||
const struct lws_token_limits *token_limits;
|
||||
|
@ -852,11 +960,20 @@ struct lws_context {
|
|||
const struct lws_protocol_vhost_options *reject_service_keywords;
|
||||
lws_reload_func deprecation_cb;
|
||||
|
||||
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
|
||||
cap_value_t caps[4];
|
||||
char count_caps;
|
||||
#endif
|
||||
|
||||
#if defined(LWS_USE_LIBEV)
|
||||
lws_ev_signal_cb_t * lws_ev_sigint_cb;
|
||||
#endif
|
||||
#if defined(LWS_USE_LIBUV)
|
||||
uv_signal_cb lws_uv_sigint_cb;
|
||||
uv_loop_t pu_loop;
|
||||
#endif
|
||||
#if defined(LWS_USE_LIBEVENT)
|
||||
lws_event_signal_cb_t * lws_event_sigint_cb;
|
||||
#endif
|
||||
char canonical_hostname[128];
|
||||
#ifdef LWS_LATENCY
|
||||
|
@ -864,8 +981,14 @@ struct lws_context {
|
|||
char worst_latency_info[256];
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_STATS)
|
||||
uint64_t lws_stats[LWSSTATS_SIZE];
|
||||
uint64_t last_dump;
|
||||
int updated;
|
||||
#endif
|
||||
|
||||
int max_fds;
|
||||
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV)
|
||||
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV) || defined(LWS_USE_LIBEVENT)
|
||||
int use_ev_sigint;
|
||||
#endif
|
||||
int started_with_parent;
|
||||
|
@ -890,13 +1013,15 @@ struct lws_context {
|
|||
unsigned int timeout_secs;
|
||||
unsigned int pt_serv_buf_size;
|
||||
int max_http_header_data;
|
||||
int simultaneous_ssl_restriction;
|
||||
int simultaneous_ssl;
|
||||
|
||||
unsigned int deprecated:1;
|
||||
unsigned int being_destroyed:1;
|
||||
unsigned int being_destroyed1:1;
|
||||
unsigned int requested_kill:1;
|
||||
unsigned int protocol_init_done:1;
|
||||
|
||||
unsigned int ssl_gate_accepts:1;
|
||||
/*
|
||||
* set to the Thread ID that's doing the service loop just before entry
|
||||
* to poll indicates service thread likely idling in poll()
|
||||
|
@ -916,6 +1041,9 @@ struct lws_context {
|
|||
uint8_t max_fi;
|
||||
};
|
||||
|
||||
int
|
||||
lws_check_deferred_free(struct lws_context *context, int force);
|
||||
|
||||
#define lws_get_context_protocol(ctx, x) ctx->vhost_list->protocols[x]
|
||||
#define lws_get_vh_protocol(vh, x) vh->protocols[x]
|
||||
|
||||
|
@ -923,6 +1051,10 @@ LWS_EXTERN void
|
|||
lws_close_free_wsi_final(struct lws *wsi);
|
||||
LWS_EXTERN void
|
||||
lws_libuv_closehandle(struct lws *wsi);
|
||||
LWS_EXTERN void
|
||||
lws_libuv_closehandle_manually(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_libuv_check_watcher_active(struct lws *wsi);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_plat_plugins_init(struct lws_context * context, const char * const *d);
|
||||
|
@ -1004,6 +1136,34 @@ LWS_EXTERN void lws_feature_status_libuv(struct lws_context_creation_info *info)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(LWS_USE_LIBEVENT)
|
||||
LWS_EXTERN void
|
||||
lws_libevent_accept(struct lws *new_wsi, lws_sock_file_fd_type desc);
|
||||
LWS_EXTERN void
|
||||
lws_libevent_io(struct lws *wsi, int flags);
|
||||
LWS_EXTERN int
|
||||
lws_libevent_init_fd_table(struct lws_context *context);
|
||||
LWS_EXTERN void
|
||||
lws_libevent_destroyloop(struct lws_context *context, int tsi);
|
||||
LWS_EXTERN void
|
||||
lws_libevent_run(const struct lws_context *context, int tsi);
|
||||
#define LWS_LIBEVENT_ENABLED(context) lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEVENT)
|
||||
LWS_EXTERN void lws_feature_status_libevent(struct lws_context_creation_info *info);
|
||||
#else
|
||||
#define lws_libevent_accept(_a, _b) ((void) 0)
|
||||
#define lws_libevent_io(_a, _b) ((void) 0)
|
||||
#define lws_libevent_init_fd_table(_a) (0)
|
||||
#define lws_libevent_run(_a, _b) ((void) 0)
|
||||
#define lws_libevent_destroyloop(_a, _b) ((void) 0)
|
||||
#define LWS_LIBEVENT_ENABLED(context) (0)
|
||||
#if LWS_POSIX && !defined(LWS_WITH_ESP32)
|
||||
#define lws_feature_status_libevent(_a) \
|
||||
lwsl_notice("libevent support not compiled in\n")
|
||||
#else
|
||||
#define lws_feature_status_libevent(_a)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef LWS_USE_IPV6
|
||||
#define LWS_IPV6_ENABLED(vh) \
|
||||
|
@ -1019,6 +1179,14 @@ LWS_EXTERN void lws_feature_status_libuv(struct lws_context_creation_info *info)
|
|||
#else
|
||||
#define LWS_UNIX_SOCK_ENABLED(vhost) (0)
|
||||
#endif
|
||||
|
||||
typedef union {
|
||||
#ifdef LWS_USE_IPV6
|
||||
struct sockaddr_in6 sa6;
|
||||
#endif
|
||||
struct sockaddr_in sa4;
|
||||
} sockaddr46;
|
||||
|
||||
enum uri_path_states {
|
||||
URIPS_IDLE,
|
||||
URIPS_SEEN_SLASH,
|
||||
|
@ -1053,6 +1221,7 @@ struct client_info_stash {
|
|||
char origin[256];
|
||||
char protocol[256];
|
||||
char method[16];
|
||||
char iface[16];
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -1123,8 +1292,8 @@ struct _lws_http_mode_related {
|
|||
|
||||
enum http_version request_version;
|
||||
enum http_connection_type connection_type;
|
||||
unsigned int content_length;
|
||||
unsigned int content_remain;
|
||||
lws_filepos_t content_length;
|
||||
lws_filepos_t content_remain;
|
||||
};
|
||||
|
||||
#ifdef LWS_USE_HTTP2
|
||||
|
@ -1316,22 +1485,43 @@ struct _lws_websocket_related {
|
|||
unsigned int rx_draining_ext:1;
|
||||
unsigned int tx_draining_ext:1;
|
||||
unsigned int send_check_ping:1;
|
||||
unsigned int first_fragment:1;
|
||||
};
|
||||
|
||||
#ifdef LWS_WITH_CGI
|
||||
|
||||
#define LWS_HTTP_CHUNK_HDR_SIZE 16
|
||||
|
||||
enum {
|
||||
SIGNIFICANT_HDR_CONTENT_LENGTH,
|
||||
SIGNIFICANT_HDR_LOCATION,
|
||||
SIGNIFICANT_HDR_STATUS,
|
||||
SIGNIFICANT_HDR_TRANSFER_ENCODING,
|
||||
|
||||
SIGNIFICANT_HDR_COUNT
|
||||
};
|
||||
|
||||
/* wsi who is master of the cgi points to an lws_cgi */
|
||||
|
||||
struct lws_cgi {
|
||||
struct lws_cgi *cgi_list;
|
||||
struct lws *stdwsi[3]; /* points to the associated stdin/out/err wsis */
|
||||
struct lws *wsi; /* owner */
|
||||
unsigned long content_length;
|
||||
unsigned long content_length_seen;
|
||||
unsigned char *headers_buf;
|
||||
unsigned char *headers_pos;
|
||||
unsigned char *headers_dumped;
|
||||
unsigned char *headers_end;
|
||||
lws_filepos_t content_length;
|
||||
lws_filepos_t content_length_seen;
|
||||
int pipe_fds[3][2];
|
||||
int match[SIGNIFICANT_HDR_COUNT];
|
||||
int pid;
|
||||
int response_code;
|
||||
int lp;
|
||||
char l[12];
|
||||
|
||||
unsigned int being_closed:1;
|
||||
unsigned int explicitly_chunked:1;
|
||||
|
||||
unsigned char chunked_grace;
|
||||
};
|
||||
|
@ -1355,6 +1545,7 @@ struct lws_rewrite;
|
|||
struct lws_access_log {
|
||||
char *header_log;
|
||||
char *user_agent;
|
||||
char *referrer;
|
||||
unsigned long sent;
|
||||
int response;
|
||||
};
|
||||
|
@ -1376,10 +1567,10 @@ struct lws {
|
|||
|
||||
/* lifetime members */
|
||||
|
||||
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV)
|
||||
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV) || defined(LWS_USE_LIBEVENT)
|
||||
struct lws_io_watcher w_read;
|
||||
#endif
|
||||
#if defined(LWS_USE_LIBEV)
|
||||
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBEVENT)
|
||||
struct lws_io_watcher w_write;
|
||||
#endif
|
||||
time_t pending_timeout_limit;
|
||||
|
@ -1402,6 +1593,7 @@ struct lws {
|
|||
struct lws_access_log access_log;
|
||||
#endif
|
||||
void *user_space;
|
||||
void *opaque_parent_data;
|
||||
/* rxflow handling */
|
||||
unsigned char *rxflow_buffer;
|
||||
/* truncated send handling */
|
||||
|
@ -1420,6 +1612,10 @@ struct lws {
|
|||
SSL *ssl;
|
||||
BIO *client_bio;
|
||||
struct lws *pending_read_list_prev, *pending_read_list_next;
|
||||
#if defined(LWS_WITH_STATS)
|
||||
uint64_t accept_start_us;
|
||||
char seen_rx;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef LWS_WITH_HTTP_PROXY
|
||||
struct lws_rewrite *rw;
|
||||
|
@ -1429,7 +1625,9 @@ struct lws {
|
|||
unsigned long latency_start;
|
||||
#endif
|
||||
lws_sock_file_fd_type desc; /* .filefd / .sockfd */
|
||||
|
||||
#if defined(LWS_WITH_STATS)
|
||||
uint64_t active_writable_req_us;
|
||||
#endif
|
||||
/* ints */
|
||||
int position_in_fds_table;
|
||||
int rxflow_len;
|
||||
|
@ -1457,6 +1655,10 @@ struct lws {
|
|||
unsigned int sending_chunked:1;
|
||||
unsigned int already_did_cce:1;
|
||||
unsigned int told_user_closed:1;
|
||||
unsigned int waiting_to_send_close_frame:1;
|
||||
unsigned int ipv6:1;
|
||||
unsigned int parent_carries_io:1;
|
||||
unsigned int parent_pending_cb_on_writable:1;
|
||||
|
||||
#if defined(LWS_WITH_ESP8266)
|
||||
unsigned int pending_send_completion:3;
|
||||
|
@ -1528,6 +1730,11 @@ LWS_EXTERN int
|
|||
lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port,
|
||||
const char *iface);
|
||||
|
||||
#if defined(LWS_USE_IPV6)
|
||||
LWS_EXTERN unsigned long
|
||||
lws_get_addr_scope(const char *ipaddr);
|
||||
#endif
|
||||
|
||||
LWS_EXTERN void
|
||||
lws_close_free_wsi(struct lws *wsi, enum lws_close_status);
|
||||
|
||||
|
@ -1721,6 +1928,11 @@ lws_header_table_reset(struct lws *wsi, int autoservice);
|
|||
void
|
||||
_lws_header_table_reset(struct allocated_headers *ah);
|
||||
|
||||
void
|
||||
lws_header_table_force_to_detachable_state(struct lws *wsi);
|
||||
int
|
||||
lws_header_table_is_in_detachable_state(struct lws *wsi);
|
||||
|
||||
LWS_EXTERN char * LWS_WARN_UNUSED_RESULT
|
||||
lws_hdr_simple_ptr(struct lws *wsi, enum lws_token_indexes h);
|
||||
|
||||
|
@ -1821,7 +2033,6 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
|
|||
#endif
|
||||
LWS_EXTERN void
|
||||
lws_ssl_destroy(struct lws_vhost *vhost);
|
||||
|
||||
/* HTTP2-related */
|
||||
|
||||
#ifdef LWS_USE_HTTP2
|
||||
|
@ -1909,6 +2120,10 @@ lws_http_transaction_completed_client(struct lws *wsi);
|
|||
LWS_EXTERN int
|
||||
lws_context_init_client_ssl(struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost);
|
||||
|
||||
LWS_EXTERN void
|
||||
lws_ssl_info_callback(const SSL *ssl, int where, int ret);
|
||||
|
||||
#else
|
||||
#define lws_context_init_client_ssl(_a, _b) (0)
|
||||
#endif
|
||||
|
@ -2018,11 +2233,40 @@ LWS_EXTERN unsigned long long
|
|||
time_in_microseconds(void);
|
||||
LWS_EXTERN const char * LWS_WARN_UNUSED_RESULT
|
||||
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt);
|
||||
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
|
||||
lws_plat_inet_pton(int af, const char *src, void *dst);
|
||||
|
||||
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
|
||||
lws_check_utf8(unsigned char *state, unsigned char *buf, size_t len);
|
||||
LWS_EXTERN int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
|
||||
lws_filepos_t *amount);
|
||||
LWS_EXTERN int alloc_pem_to_der_file(struct lws_context *context, const char *filename, uint8_t **buf,
|
||||
lws_filepos_t *amount);
|
||||
|
||||
LWS_EXTERN void
|
||||
lws_same_vh_protocol_remove(struct lws *wsi);
|
||||
LWS_EXTERN void
|
||||
lws_same_vh_protocol_insert(struct lws *wsi, int n);
|
||||
|
||||
#if defined(LWS_WITH_STATS)
|
||||
void
|
||||
lws_stats_atomic_bump(struct lws_context * context,
|
||||
struct lws_context_per_thread *pt, int index, uint64_t bump);
|
||||
void
|
||||
lws_stats_atomic_max(struct lws_context * context,
|
||||
struct lws_context_per_thread *pt, int index, uint64_t val);
|
||||
#else
|
||||
static inline uint64_t lws_stats_atomic_bump(struct lws_context * context,
|
||||
struct lws_context_per_thread *pt, int index, uint64_t bump) {
|
||||
(void)context; (void)pt; (void)index; (void)bump; return 0; }
|
||||
static inline uint64_t lws_stats_atomic_max(struct lws_context * context,
|
||||
struct lws_context_per_thread *pt, int index, uint64_t val) {
|
||||
(void)context; (void)pt; (void)index; (void)val; return 0; }
|
||||
#endif
|
||||
|
||||
/* socks */
|
||||
void socks_generate_msg(struct lws *wsi, enum socks_msg_type type,
|
||||
size_t *msg_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
|
|
16
lib/romfs.c
16
lib/romfs.c
|
@ -37,7 +37,7 @@
|
|||
#include "romfs.h"
|
||||
#include "esp_spi_flash.h"
|
||||
|
||||
#define RFS_STRING_MAX 64
|
||||
#define RFS_STRING_MAX 96
|
||||
|
||||
static u32_be_t cache[(RFS_STRING_MAX + 32) / 4];
|
||||
static romfs_inode_t ci = (romfs_inode_t)cache;
|
||||
|
@ -118,7 +118,7 @@ dir_link(romfs_t romfs, romfs_inode_t i)
|
|||
static romfs_inode_t
|
||||
romfs_lookup(romfs_t romfs, romfs_inode_t start, const char *path)
|
||||
{
|
||||
romfs_inode_t level, i = start;
|
||||
romfs_inode_t level, i = start, i_in;
|
||||
const char *p, *n, *cp;
|
||||
uint32_t next_be;
|
||||
|
||||
|
@ -128,6 +128,7 @@ romfs_lookup(romfs_t romfs, romfs_inode_t start, const char *path)
|
|||
while (i != (romfs_inode_t)romfs) {
|
||||
p = path;
|
||||
n = ((const char *)i) + sizeof(*i);
|
||||
i_in = i;
|
||||
|
||||
set_cache(i, sizeof(*i));
|
||||
next_be = ci->next;
|
||||
|
@ -135,7 +136,7 @@ romfs_lookup(romfs_t romfs, romfs_inode_t start, const char *path)
|
|||
cp = (const char *)cache;
|
||||
set_cache((romfs_inode_t)n, RFS_STRING_MAX);
|
||||
|
||||
while (*p && *p != '/' && *cp && *p == *cp) {
|
||||
while (*p && *p != '/' && *cp && *p == *cp && (p - path) < RFS_STRING_MAX) {
|
||||
p++;
|
||||
n++;
|
||||
cp++;
|
||||
|
@ -158,6 +159,9 @@ romfs_lookup(romfs_t romfs, romfs_inode_t start, const char *path)
|
|||
return i;
|
||||
}
|
||||
|
||||
if (!*p && *cp == '/')
|
||||
return NULL;
|
||||
|
||||
if (*p == '/' && !*cp) {
|
||||
set_cache(i, sizeof(*i));
|
||||
switch (ntohl(ci->next) & 7) {
|
||||
|
@ -191,13 +195,15 @@ romfs_lookup(romfs_t romfs, romfs_inode_t start, const char *path)
|
|||
|
||||
i = (romfs_inode_t)((const uint8_t *)romfs +
|
||||
(ntohl(ci->next) & ~15));
|
||||
if (i == i_in)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const void *
|
||||
romfs_get_info(romfs_t romfs, const char *path, size_t *len)
|
||||
romfs_get_info(romfs_t romfs, const char *path, size_t *len, size_t *csum)
|
||||
{
|
||||
romfs_inode_t i;
|
||||
|
||||
|
@ -211,6 +217,8 @@ romfs_get_info(romfs_t romfs, const char *path, size_t *len)
|
|||
|
||||
set_cache(i, sizeof(*i));
|
||||
*len = ntohl(ci->size);
|
||||
if (csum)
|
||||
*csum = ntohl(ci->checksum);
|
||||
|
||||
return (void *)skip_and_pad(i);
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ typedef const struct romfs_i *romfs_inode_t;
|
|||
typedef const struct romfs_superblock *romfs_t;
|
||||
|
||||
const void *
|
||||
romfs_get_info(romfs_t romfs, const char *path, size_t *len);
|
||||
romfs_get_info(romfs_t romfs, const char *path, size_t *len, size_t *csum);
|
||||
size_t
|
||||
romfs_mount_check(romfs_t romfs);
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ lws_extension_server_handshake(struct lws *wsi, char **p, int budget)
|
|||
* ask user code if it's OK to apply it on this
|
||||
* particular connection + protocol
|
||||
*/
|
||||
m = wsi->vhost->protocols[0].callback(wsi,
|
||||
m = (wsi->protocol->callback)(wsi,
|
||||
LWS_CALLBACK_CONFIRM_EXTENSION_OKAY,
|
||||
wsi->user_space, ext_name, 0);
|
||||
|
||||
|
@ -156,7 +156,7 @@ lws_extension_server_handshake(struct lws *wsi, char **p, int budget)
|
|||
LWS_EXT_CB_CONSTRUCT,
|
||||
(void *)&wsi->act_ext_user[
|
||||
wsi->count_act_ext],
|
||||
&opts, 0)) {
|
||||
(void *)&opts, 0)) {
|
||||
lwsl_notice("ext %s failed construction\n",
|
||||
ext_name);
|
||||
ext_count--;
|
||||
|
|
567
lib/server.c
567
lib/server.c
|
@ -65,6 +65,7 @@ lws_context_init_server(struct lws_context_creation_info *info,
|
|||
}
|
||||
|
||||
#if LWS_POSIX
|
||||
(void)n;
|
||||
#if defined(__linux__)
|
||||
limit = vhost->context->count_threads;
|
||||
#endif
|
||||
|
@ -93,6 +94,24 @@ lws_context_init_server(struct lws_context_creation_info *info,
|
|||
return 1;
|
||||
}
|
||||
#if LWS_POSIX && !defined(LWS_WITH_ESP32)
|
||||
|
||||
#if (defined(WIN32) || defined(_WIN32)) && defined(SO_EXCLUSIVEADDRUSE)
|
||||
/*
|
||||
* only accept that we are the only listener on the port
|
||||
* https://msdn.microsoft.com/zh-tw/library/windows/desktop/ms740621(v=vs.85).aspx
|
||||
*
|
||||
* for lws, to match Linux, we default to exclusive listen
|
||||
*/
|
||||
if (!lws_check_opt(vhost->options, LWS_SERVER_OPTION_ALLOW_LISTEN_SHARE)) {
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
|
||||
(const void *)&opt, sizeof(opt)) < 0) {
|
||||
lwsl_err("reuseaddr failed\n");
|
||||
compatible_close(sockfd);
|
||||
return 1;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
|
||||
/*
|
||||
* allow us to restart even if old sockets in TIME_WAIT
|
||||
*/
|
||||
|
@ -116,13 +135,19 @@ lws_context_init_server(struct lws_context_creation_info *info,
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && defined(SO_REUSEPORT) && LWS_MAX_SMP > 1
|
||||
if (vhost->context->count_threads > 1)
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT,
|
||||
(const void *)&opt, sizeof(opt)) < 0) {
|
||||
compatible_close(sockfd);
|
||||
return 1;
|
||||
}
|
||||
#if defined(__linux__) && defined(SO_REUSEPORT)
|
||||
n = lws_check_opt(vhost->options, LWS_SERVER_OPTION_ALLOW_LISTEN_SHARE);
|
||||
#if LWS_MAX_SMP > 1
|
||||
n = 1;
|
||||
#endif
|
||||
|
||||
if (n)
|
||||
if (vhost->context->count_threads > 1)
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT,
|
||||
(const void *)&opt, sizeof(opt)) < 0) {
|
||||
compatible_close(sockfd);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
lws_plat_set_socket_options(vhost, sockfd);
|
||||
|
@ -308,6 +333,9 @@ lws_get_mimetype(const char *file, const struct lws_http_mount *m)
|
|||
if (!strcmp(&file[n - 4], ".ttf"))
|
||||
return "application/x-font-ttf";
|
||||
|
||||
if (!strcmp(&file[n - 4], ".otf"))
|
||||
return "application/font-woff";
|
||||
|
||||
if (!strcmp(&file[n - 5], ".woff"))
|
||||
return "application/font-woff";
|
||||
|
||||
|
@ -350,12 +378,15 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
|
|||
const struct lws_protocol_vhost_options *pvo = m->interpret;
|
||||
struct lws_process_html_args args;
|
||||
const char *mimetype;
|
||||
#if !defined(_WIN32_WCE) && !defined(LWS_WITH_ESP8266) && \
|
||||
!defined(LWS_WITH_ESP32)
|
||||
#if !defined(_WIN32_WCE) && !defined(LWS_WITH_ESP8266)
|
||||
const struct lws_plat_file_ops *fops;
|
||||
const char *vpath;
|
||||
lws_fop_flags_t fflags = LWS_O_RDONLY;
|
||||
#if defined(WIN32) && defined(LWS_HAVE__STAT32I64)
|
||||
struct _stat32i64 st;
|
||||
#else
|
||||
struct stat st;
|
||||
#endif
|
||||
int spin = 0;
|
||||
#endif
|
||||
char path[256], sym[512];
|
||||
|
@ -368,8 +399,7 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
|
|||
|
||||
lws_snprintf(path, sizeof(path) - 1, "%s/%s", origin, uri);
|
||||
|
||||
#if !defined(_WIN32_WCE) && !defined(LWS_WITH_ESP8266) && \
|
||||
!defined(LWS_WITH_ESP32)
|
||||
#if !defined(_WIN32_WCE) && !defined(LWS_WITH_ESP8266)
|
||||
|
||||
fflags |= lws_vfs_prepare_flags(wsi);
|
||||
|
||||
|
@ -391,23 +421,33 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
|
|||
/* if it can't be statted, don't try */
|
||||
if (fflags & LWS_FOP_FLAG_VIRTUAL)
|
||||
break;
|
||||
#if defined(LWS_WITH_ESP32)
|
||||
break;
|
||||
#endif
|
||||
#if !defined(WIN32)
|
||||
if (fstat(wsi->u.http.fop_fd->fd, &st)) {
|
||||
lwsl_info("unable to stat %s\n", path);
|
||||
goto bail;
|
||||
}
|
||||
#else
|
||||
#if defined(LWS_HAVE__STAT32I64)
|
||||
if (_stat32i64(path, &st)) {
|
||||
lwsl_info("unable to stat %s\n", path);
|
||||
goto bail;
|
||||
}
|
||||
#else
|
||||
if (stat(path, &st)) {
|
||||
lwsl_info("unable to stat %s\n", path);
|
||||
goto bail;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
wsi->u.http.fop_fd->mod_time = (uint32_t)st.st_mtime;
|
||||
fflags |= LWS_FOP_FLAG_MOD_TIME_VALID;
|
||||
|
||||
lwsl_debug(" %s mode %d\n", path, S_IFMT & st.st_mode);
|
||||
#if !defined(WIN32) && LWS_POSIX
|
||||
#if !defined(WIN32) && LWS_POSIX && !defined(LWS_WITH_ESP32)
|
||||
if ((S_IFMT & st.st_mode) == S_IFLNK) {
|
||||
len = readlink(path, sym, sizeof(sym) - 1);
|
||||
if (len) {
|
||||
|
@ -430,8 +470,8 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
|
|||
if (spin == 5)
|
||||
lwsl_err("symlink loop %s \n", path);
|
||||
|
||||
n = sprintf(sym, "%08lX%08lX",
|
||||
(unsigned long)lws_vfs_get_length(wsi->u.http.fop_fd),
|
||||
n = sprintf(sym, "%08llX%08lX",
|
||||
(unsigned long long)lws_vfs_get_length(wsi->u.http.fop_fd),
|
||||
(unsigned long)lws_vfs_get_mod_time(wsi->u.http.fop_fd));
|
||||
|
||||
/* disable ranges if IF_RANGE token invalid */
|
||||
|
@ -503,10 +543,10 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin,
|
|||
if (n > (int)strlen(pvo->name) &&
|
||||
!strcmp(&path[n - strlen(pvo->name)], pvo->name)) {
|
||||
wsi->sending_chunked = 1;
|
||||
wsi->protocol_interpret_idx = (char)(long)pvo->value;
|
||||
wsi->protocol_interpret_idx = (char)(lws_intptr_t)pvo->value;
|
||||
lwsl_info("want %s interpreted by %s\n", path,
|
||||
wsi->vhost->protocols[(int)(long)(pvo->value)].name);
|
||||
wsi->protocol = &wsi->vhost->protocols[(int)(long)(pvo->value)];
|
||||
wsi->vhost->protocols[(int)(lws_intptr_t)(pvo->value)].name);
|
||||
wsi->protocol = &wsi->vhost->protocols[(int)(lws_intptr_t)(pvo->value)];
|
||||
if (lws_ensure_user_space(wsi))
|
||||
return -1;
|
||||
break;
|
||||
|
@ -647,6 +687,34 @@ lws_unauthorised_basic_auth(struct lws *wsi)
|
|||
|
||||
#endif
|
||||
|
||||
int lws_clean_url(char *p)
|
||||
{
|
||||
if (p[0] == 'h' && p[1] == 't' && p[2] == 't' && p[3] == 'p') {
|
||||
p += 4;
|
||||
if (*p == 's')
|
||||
p++;
|
||||
if (*p == ':') {
|
||||
p++;
|
||||
if (*p == '/')
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
while (*p) {
|
||||
if (p[0] == '/' && p[1] == '/') {
|
||||
char *p1 = p;
|
||||
while (*p1) {
|
||||
*p1 = p1[1];
|
||||
p1++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_http_action(struct lws *wsi)
|
||||
{
|
||||
|
@ -720,7 +788,7 @@ lws_http_action(struct lws *wsi)
|
|||
|
||||
/* we insist on absolute paths */
|
||||
|
||||
if (uri_ptr[0] != '/') {
|
||||
if (!uri_ptr || uri_ptr[0] != '/') {
|
||||
lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
|
||||
|
||||
goto bail_nuke_ah;
|
||||
|
@ -738,7 +806,7 @@ lws_http_action(struct lws *wsi)
|
|||
lws_hdr_copy(wsi, content_length_str,
|
||||
sizeof(content_length_str) - 1,
|
||||
WSI_TOKEN_HTTP_CONTENT_LENGTH);
|
||||
wsi->u.http.content_length = atoi(content_length_str);
|
||||
wsi->u.http.content_length = atoll(content_length_str);
|
||||
}
|
||||
|
||||
if (wsi->http2_substream) {
|
||||
|
@ -838,7 +906,7 @@ lws_http_action(struct lws *wsi)
|
|||
const char *pa, *me;
|
||||
struct tm *tmp;
|
||||
time_t t = time(NULL);
|
||||
int l = 256;
|
||||
int l = 256, m;
|
||||
|
||||
if (wsi->access_log_pending)
|
||||
lws_access_log(wsi);
|
||||
|
@ -856,10 +924,7 @@ lws_http_action(struct lws *wsi)
|
|||
if (!pa)
|
||||
pa = "(unknown)";
|
||||
|
||||
if (meth >= 0)
|
||||
me = method_names[meth];
|
||||
else
|
||||
me = "unknown";
|
||||
me = method_names[meth];
|
||||
|
||||
lws_snprintf(wsi->access_log.header_log, l,
|
||||
"%s - - [%s] \"%s %s %s\"",
|
||||
|
@ -874,6 +939,23 @@ lws_http_action(struct lws *wsi)
|
|||
l + 1, WSI_TOKEN_HTTP_USER_AGENT);
|
||||
else
|
||||
lwsl_err("OOM getting user agent\n");
|
||||
|
||||
for (m = 0; m < l; m++)
|
||||
if (wsi->access_log.user_agent[m] == '\"')
|
||||
wsi->access_log.user_agent[m] = '\'';
|
||||
}
|
||||
l = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_REFERER);
|
||||
if (l) {
|
||||
wsi->access_log.referrer = lws_malloc(l + 2);
|
||||
if (wsi->access_log.referrer)
|
||||
lws_hdr_copy(wsi, wsi->access_log.referrer,
|
||||
l + 1, WSI_TOKEN_HTTP_REFERER);
|
||||
else
|
||||
lwsl_err("OOM getting user agent\n");
|
||||
|
||||
for (m = 0; m < l; m++)
|
||||
if (wsi->access_log.referrer[m] == '\"')
|
||||
wsi->access_log.referrer[m] = '\'';
|
||||
}
|
||||
wsi->access_log_pending = 1;
|
||||
}
|
||||
|
@ -940,10 +1022,14 @@ lws_http_action(struct lws *wsi)
|
|||
hit->origin);
|
||||
else
|
||||
n = lws_snprintf((char *)end, 256,
|
||||
"%s%s%s/", oprot[lws_is_ssl(wsi)],
|
||||
"%s%s%s/", oprot[!!lws_is_ssl(wsi)],
|
||||
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST),
|
||||
uri_ptr);
|
||||
|
||||
lwsl_notice("%s\n", end);
|
||||
lws_clean_url((char *)end);
|
||||
lwsl_notice("%s\n", end);
|
||||
|
||||
n = lws_http_redirect(wsi, HTTP_STATUS_MOVED_PERMANENTLY,
|
||||
end, n, &p, end);
|
||||
if ((int)n < 0)
|
||||
|
@ -998,6 +1084,84 @@ lws_http_action(struct lws *wsi)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_HTTP_PROXY)
|
||||
/*
|
||||
* The mount is a reverse proxy?
|
||||
*/
|
||||
|
||||
if (hit->origin_protocol == LWSMPRO_HTTPS ||
|
||||
hit->origin_protocol == LWSMPRO_HTTP) {
|
||||
struct lws_client_connect_info i;
|
||||
char ads[96], rpath[256], *pcolon, *pslash, *p;
|
||||
int n, na;
|
||||
|
||||
memset(&i, 0, sizeof(i));
|
||||
i.context = lws_get_context(wsi);
|
||||
|
||||
pcolon = strchr(hit->origin, ':');
|
||||
pslash = strchr(hit->origin, '/');
|
||||
if (!pslash) {
|
||||
lwsl_err("Proxy mount origin '%s' must have /\n", hit->origin);
|
||||
return -1;
|
||||
}
|
||||
if (pcolon > pslash)
|
||||
pcolon = NULL;
|
||||
|
||||
if (pcolon)
|
||||
n = pcolon - hit->origin;
|
||||
else
|
||||
n = pslash - hit->origin;
|
||||
|
||||
if (n >= sizeof(ads) - 2)
|
||||
n = sizeof(ads) - 2;
|
||||
|
||||
memcpy(ads, hit->origin, n);
|
||||
ads[n] = '\0';
|
||||
|
||||
i.address = ads;
|
||||
i.port = 80;
|
||||
if (hit->origin_protocol == LWSMPRO_HTTPS) {
|
||||
i.port = 443;
|
||||
i.ssl_connection = 1;
|
||||
}
|
||||
if (pcolon)
|
||||
i.port = atoi(pcolon + 1);
|
||||
|
||||
lws_snprintf(rpath, sizeof(rpath) - 1, "/%s/%s", pslash + 1, uri_ptr + hit->mountpoint_len);
|
||||
lws_clean_url(rpath);
|
||||
na = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_URI_ARGS);
|
||||
if (na) {
|
||||
p = rpath + strlen(rpath);
|
||||
*p++ = '?';
|
||||
lws_hdr_copy(wsi, p, &rpath[sizeof(rpath) - 1] - p, WSI_TOKEN_HTTP_URI_ARGS);
|
||||
while (--na) {
|
||||
if (*p == '\0')
|
||||
*p = '&';
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
i.path = rpath;
|
||||
i.host = i.address;
|
||||
i.origin = NULL;
|
||||
i.method = "GET";
|
||||
i.parent_wsi = wsi;
|
||||
i.uri_replace_from = hit->origin;
|
||||
i.uri_replace_to = hit->mountpoint;
|
||||
|
||||
lwsl_notice("proxying to %s port %d url %s, ssl %d, from %s, to %s\n",
|
||||
i.address, i.port, i.path, i.ssl_connection, i.uri_replace_from, i.uri_replace_to);
|
||||
|
||||
if (!lws_client_connect_via_info(&i)) {
|
||||
lwsl_err("proxy connect fail\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A particular protocol callback is mounted here?
|
||||
*
|
||||
|
@ -1057,7 +1221,6 @@ lws_http_action(struct lws *wsi)
|
|||
NULL, /* replace with cgi path */
|
||||
NULL
|
||||
};
|
||||
unsigned char *p, *end, buffer[1024];
|
||||
|
||||
lwsl_debug("%s: cgi\n", __func__);
|
||||
cmd[0] = hit->origin;
|
||||
|
@ -1072,17 +1235,6 @@ lws_http_action(struct lws *wsi)
|
|||
lwsl_err("%s: cgi failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
p = buffer + LWS_PRE;
|
||||
end = p + sizeof(buffer) - LWS_PRE;
|
||||
|
||||
if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
|
||||
return 1;
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_CONNECTION,
|
||||
(unsigned char *)"close", 5, &p, end))
|
||||
return 1;
|
||||
n = lws_write(wsi, buffer + LWS_PRE,
|
||||
p - (buffer + LWS_PRE),
|
||||
LWS_WRITE_HTTP_HEADERS);
|
||||
|
||||
goto deal_body;
|
||||
}
|
||||
|
@ -1147,7 +1299,7 @@ deal_body:
|
|||
|
||||
bail_nuke_ah:
|
||||
/* we're closing, losing some rx is OK */
|
||||
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
|
||||
lws_header_table_force_to_detachable_state(wsi);
|
||||
// lwsl_notice("%s: drop1\n", __func__);
|
||||
lws_header_table_detach(wsi, 1);
|
||||
|
||||
|
@ -1160,6 +1312,56 @@ transaction_result_n:
|
|||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
lws_server_init_wsi_for_ws(struct lws *wsi)
|
||||
{
|
||||
int n;
|
||||
|
||||
wsi->state = LWSS_ESTABLISHED;
|
||||
lws_restart_ws_ping_pong_timer(wsi);
|
||||
|
||||
/*
|
||||
* create the frame buffer for this connection according to the
|
||||
* size mentioned in the protocol definition. If 0 there, use
|
||||
* a big default for compatibility
|
||||
*/
|
||||
|
||||
n = wsi->protocol->rx_buffer_size;
|
||||
if (!n)
|
||||
n = wsi->context->pt_serv_buf_size;
|
||||
n += LWS_PRE;
|
||||
wsi->u.ws.rx_ubuf = lws_malloc(n + 4 /* 0x0000ffff zlib */);
|
||||
if (!wsi->u.ws.rx_ubuf) {
|
||||
lwsl_err("Out of Mem allocating rx buffer %d\n", n);
|
||||
return 1;
|
||||
}
|
||||
wsi->u.ws.rx_ubuf_alloc = n;
|
||||
lwsl_debug("Allocating RX buffer %d\n", n);
|
||||
|
||||
#if LWS_POSIX && !defined(LWS_WITH_ESP32)
|
||||
if (!wsi->parent_carries_io)
|
||||
if (setsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_SNDBUF,
|
||||
(const char *)&n, sizeof n)) {
|
||||
lwsl_warn("Failed to set SNDBUF to %d", n);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* notify user code that we're ready to roll */
|
||||
|
||||
if (wsi->protocol->callback)
|
||||
if (wsi->protocol->callback(wsi, LWS_CALLBACK_ESTABLISHED,
|
||||
wsi->user_space,
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
wsi->ssl,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
0))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
|
||||
|
@ -1215,7 +1417,7 @@ raw_transition:
|
|||
wsi->user_space, NULL, 0))
|
||||
goto bail_nuke_ah;
|
||||
|
||||
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
|
||||
lws_header_table_force_to_detachable_state(wsi);
|
||||
lws_union_transition(wsi, LWSCM_RAW);
|
||||
lws_header_table_detach(wsi, 1);
|
||||
|
||||
|
@ -1456,7 +1658,7 @@ upgrade_ws:
|
|||
*/
|
||||
lwsl_info("defaulting to prot handler %d\n",
|
||||
wsi->vhost->default_protocol_index);
|
||||
n = 0;
|
||||
n = wsi->vhost->default_protocol_index;
|
||||
wsi->protocol = &wsi->vhost->protocols[
|
||||
(int)wsi->vhost->default_protocol_index];
|
||||
}
|
||||
|
@ -1497,30 +1699,7 @@ upgrade_ws:
|
|||
goto bail_nuke_ah;
|
||||
}
|
||||
|
||||
/*
|
||||
* stitch protocol choice into the vh protocol linked list
|
||||
* We always insert ourselves at the start of the list
|
||||
*
|
||||
* X <-> B
|
||||
* X <-> pAn <-> pB
|
||||
*/
|
||||
//lwsl_err("%s: pre insert vhost start wsi %p, that wsi prev == %p\n",
|
||||
// __func__,
|
||||
// wsi->vhost->same_vh_protocol_list[n],
|
||||
// wsi->same_vh_protocol_prev);
|
||||
wsi->same_vh_protocol_prev = /* guy who points to us */
|
||||
&wsi->vhost->same_vh_protocol_list[n];
|
||||
wsi->same_vh_protocol_next = /* old first guy is our next */
|
||||
wsi->vhost->same_vh_protocol_list[n];
|
||||
/* we become the new first guy */
|
||||
wsi->vhost->same_vh_protocol_list[n] = wsi;
|
||||
|
||||
if (wsi->same_vh_protocol_next)
|
||||
/* old first guy points back to us now */
|
||||
wsi->same_vh_protocol_next->same_vh_protocol_prev =
|
||||
&wsi->same_vh_protocol_next;
|
||||
|
||||
|
||||
lws_same_vh_protocol_insert(wsi, n);
|
||||
|
||||
/* we are upgrading to ws, so http/1.1 and keepalive +
|
||||
* pipelined header considerations about keeping the ah around
|
||||
|
@ -1552,52 +1731,13 @@ upgrade_ws:
|
|||
wsi->u.hdr = hdr;
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
lws_restart_ws_ping_pong_timer(wsi);
|
||||
|
||||
/*
|
||||
* create the frame buffer for this connection according to the
|
||||
* size mentioned in the protocol definition. If 0 there, use
|
||||
* a big default for compatibility
|
||||
*/
|
||||
|
||||
n = wsi->protocol->rx_buffer_size;
|
||||
if (!n)
|
||||
n = context->pt_serv_buf_size;
|
||||
n += LWS_PRE;
|
||||
wsi->u.ws.rx_ubuf = lws_malloc(n + 4 /* 0x0000ffff zlib */);
|
||||
if (!wsi->u.ws.rx_ubuf) {
|
||||
lwsl_err("Out of Mem allocating rx buffer %d\n", n);
|
||||
return 1;
|
||||
}
|
||||
wsi->u.ws.rx_ubuf_alloc = n;
|
||||
lwsl_debug("Allocating RX buffer %d\n", n);
|
||||
#if LWS_POSIX && !defined(LWS_WITH_ESP32)
|
||||
if (setsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_SNDBUF,
|
||||
(const char *)&n, sizeof n)) {
|
||||
lwsl_warn("Failed to set SNDBUF to %d", n);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
lws_server_init_wsi_for_ws(wsi);
|
||||
lwsl_parser("accepted v%02d connection\n",
|
||||
wsi->ietf_spec_revision);
|
||||
|
||||
/* notify user code that we're ready to roll */
|
||||
|
||||
if (wsi->protocol->callback)
|
||||
if (wsi->protocol->callback(wsi, LWS_CALLBACK_ESTABLISHED,
|
||||
wsi->user_space,
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
wsi->ssl,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
0))
|
||||
return 1;
|
||||
|
||||
/* !!! drop ah unreservedly after ESTABLISHED */
|
||||
if (!wsi->more_rx_waiting) {
|
||||
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
|
||||
lws_header_table_force_to_detachable_state(wsi);
|
||||
|
||||
//lwsl_notice("%p: dropping ah EST\n", wsi);
|
||||
lws_header_table_detach(wsi, 1);
|
||||
|
@ -1611,7 +1751,7 @@ upgrade_ws:
|
|||
bail_nuke_ah:
|
||||
/* drop the header info */
|
||||
/* we're closing, losing some rx is OK */
|
||||
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
|
||||
lws_header_table_force_to_detachable_state(wsi);
|
||||
//lwsl_notice("%s: drop2\n", __func__);
|
||||
lws_header_table_detach(wsi, 1);
|
||||
|
||||
|
@ -1682,6 +1822,8 @@ lws_create_new_server_wsi(struct lws_vhost *vhost)
|
|||
new_wsi->user_space = NULL;
|
||||
new_wsi->ietf_spec_revision = 0;
|
||||
new_wsi->desc.sockfd = LWS_SOCK_INVALID;
|
||||
new_wsi->position_in_fds_table = -1;
|
||||
|
||||
vhost->context->count_wsi_allocated++;
|
||||
|
||||
/*
|
||||
|
@ -1701,7 +1843,12 @@ lws_http_transaction_completed(struct lws *wsi)
|
|||
|
||||
lws_access_log(wsi);
|
||||
|
||||
lwsl_info("%s: wsi %p\n", __func__, wsi);
|
||||
if (!wsi->hdr_parsing_completed) {
|
||||
lwsl_notice("%s: ignoring, ah parsing incomplete\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lwsl_debug("%s: wsi %p\n", __func__, wsi);
|
||||
/* if we can't go back to accept new headers, drop the connection */
|
||||
if (wsi->u.http.connection_type != HTTP_CONNECTION_KEEP_ALIVE) {
|
||||
lwsl_info("%s: %p: close connection\n", __func__, wsi);
|
||||
|
@ -1742,8 +1889,23 @@ lws_http_transaction_completed(struct lws *wsi)
|
|||
wsi->more_rx_waiting);
|
||||
|
||||
if (!wsi->more_rx_waiting) {
|
||||
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
|
||||
lws_header_table_force_to_detachable_state(wsi);
|
||||
lws_header_table_detach(wsi, 1);
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
/*
|
||||
* additionally... if we are hogging an SSL instance
|
||||
* with no pending pipelined headers (or ah now), and
|
||||
* SSL is scarce, drop this connection without waiting
|
||||
*/
|
||||
|
||||
if (wsi->vhost->use_ssl &&
|
||||
wsi->context->simultaneous_ssl_restriction &&
|
||||
wsi->context->simultaneous_ssl ==
|
||||
wsi->context->simultaneous_ssl_restriction) {
|
||||
lwsl_info("%s: simultaneous_ssl_restriction and nothing pipelined\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
lws_header_table_reset(wsi, 1);
|
||||
/*
|
||||
|
@ -1752,7 +1914,7 @@ lws_http_transaction_completed(struct lws *wsi)
|
|||
* will be bound the whole time the connection remains
|
||||
* open.
|
||||
*/
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE,
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_HOLDING_AH,
|
||||
wsi->vhost->keepalive_timeout);
|
||||
}
|
||||
}
|
||||
|
@ -1774,18 +1936,24 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
|
|||
{
|
||||
struct lws_context *context = vh->context;
|
||||
struct lws *new_wsi = lws_create_new_server_wsi(vh);
|
||||
struct lws_context_per_thread *pt;
|
||||
int n, ssl = 0;
|
||||
|
||||
if (!new_wsi) {
|
||||
if (type & LWS_ADOPT_SOCKET)
|
||||
if (type & LWS_ADOPT_SOCKET && !(type & LWS_ADOPT_WS_PARENTIO))
|
||||
compatible_close(fd.sockfd);
|
||||
return NULL;
|
||||
}
|
||||
pt = &context->pt[(int)new_wsi->tsi];
|
||||
lws_stats_atomic_bump(context, pt, LWSSTATS_C_CONNECTIONS, 1);
|
||||
|
||||
if (parent) {
|
||||
new_wsi->parent = parent;
|
||||
new_wsi->sibling_list = parent->child_list;
|
||||
parent->child_list = new_wsi;
|
||||
|
||||
if (type & LWS_ADOPT_WS_PARENTIO)
|
||||
new_wsi->parent_carries_io = 1;
|
||||
}
|
||||
|
||||
new_wsi->desc = fd;
|
||||
|
@ -1798,19 +1966,39 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
|
|||
vh_prot_name, new_wsi->vhost->name);
|
||||
goto bail;
|
||||
}
|
||||
if (lws_ensure_user_space(new_wsi))
|
||||
if (lws_ensure_user_space(new_wsi)) {
|
||||
lwsl_notice("OOM trying to get user_space\n");
|
||||
goto bail;
|
||||
}
|
||||
if (type & LWS_ADOPT_WS_PARENTIO) {
|
||||
new_wsi->desc.sockfd = LWS_SOCK_INVALID;
|
||||
lwsl_debug("binding to %s\n", new_wsi->protocol->name);
|
||||
lws_bind_protocol(new_wsi, new_wsi->protocol);
|
||||
lws_union_transition(new_wsi, LWSCM_WS_SERVING);
|
||||
lws_server_init_wsi_for_ws(new_wsi);
|
||||
|
||||
return new_wsi;
|
||||
}
|
||||
} else
|
||||
new_wsi->protocol = &context->vhost_list->
|
||||
protocols[vh->default_protocol_index];
|
||||
if (type & LWS_ADOPT_HTTP) /* he will transition later */
|
||||
new_wsi->protocol =
|
||||
&vh->protocols[vh->default_protocol_index];
|
||||
else { /* this is the only time he will transition */
|
||||
lws_bind_protocol(new_wsi,
|
||||
&vh->protocols[vh->raw_protocol_index]);
|
||||
lws_union_transition(new_wsi, LWSCM_RAW);
|
||||
}
|
||||
|
||||
if (type & LWS_ADOPT_SOCKET) { /* socket desc */
|
||||
lwsl_debug("%s: new wsi %p, sockfd %d\n", __func__, new_wsi,
|
||||
(int)(size_t)fd.sockfd);
|
||||
(int)(lws_intptr_t)fd.sockfd);
|
||||
|
||||
/* the transport is accepted... give him time to negotiate */
|
||||
lws_set_timeout(new_wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
|
||||
context->timeout_secs);
|
||||
if (type & LWS_ADOPT_HTTP)
|
||||
/* the transport is accepted...
|
||||
* give him time to negotiate */
|
||||
lws_set_timeout(new_wsi,
|
||||
PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
|
||||
context->timeout_secs);
|
||||
|
||||
#if LWS_POSIX == 0
|
||||
#if defined(LWS_WITH_ESP8266)
|
||||
|
@ -1819,7 +2007,7 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
|
|||
#endif
|
||||
} else /* file desc */
|
||||
lwsl_debug("%s: new wsi %p, filefd %d\n", __func__, new_wsi,
|
||||
(int)(size_t)fd.filefd);
|
||||
(int)(lws_intptr_t)fd.filefd);
|
||||
|
||||
/*
|
||||
* A new connection was accepted. Give the user a chance to
|
||||
|
@ -1834,15 +2022,6 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
|
|||
else
|
||||
n = LWS_CALLBACK_RAW_ADOPT;
|
||||
}
|
||||
if ((new_wsi->protocol->callback)(
|
||||
new_wsi, n, NULL, NULL, 0)) {
|
||||
if (type & LWS_ADOPT_SOCKET) {
|
||||
/* force us off the timeout list by hand */
|
||||
lws_set_timeout(new_wsi, NO_PENDING_TIMEOUT, 0);
|
||||
compatible_close(new_wsi->desc.sockfd);
|
||||
}
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (!LWS_SSL_ENABLED(new_wsi->vhost) || !(type & LWS_ADOPT_ALLOW_SSL) ||
|
||||
!(type & LWS_ADOPT_SOCKET)) {
|
||||
|
@ -1865,6 +2044,7 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
|
|||
|
||||
lws_libev_accept(new_wsi, new_wsi->desc);
|
||||
lws_libuv_accept(new_wsi, new_wsi->desc);
|
||||
lws_libevent_accept(new_wsi, new_wsi->desc);
|
||||
|
||||
if (!ssl) {
|
||||
if (insert_wsi_socket_into_fds(context, new_wsi)) {
|
||||
|
@ -1877,9 +2057,20 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (type & LWS_ADOPT_HTTP)
|
||||
/*
|
||||
* by deferring callback to this point, after insertion to fds,
|
||||
* lws_callback_on_writable() can work from the callback
|
||||
*/
|
||||
if ((new_wsi->protocol->callback)(
|
||||
new_wsi, n, new_wsi->user_space, NULL, 0))
|
||||
goto fail;
|
||||
|
||||
if (type & LWS_ADOPT_HTTP) {
|
||||
if (!lws_header_table_attach(new_wsi, 0))
|
||||
lwsl_debug("Attached ah immediately\n");
|
||||
else
|
||||
lwsl_info("%s: waiting for ah\n", __func__);
|
||||
}
|
||||
|
||||
return new_wsi;
|
||||
|
||||
|
@ -1890,11 +2081,13 @@ fail:
|
|||
return NULL;
|
||||
|
||||
bail:
|
||||
lwsl_notice("%s: exiting on bail\n", __func__);
|
||||
if (parent)
|
||||
parent->child_list = new_wsi->sibling_list;
|
||||
if (new_wsi->user_space)
|
||||
lws_free(new_wsi->user_space);
|
||||
lws_free(new_wsi);
|
||||
compatible_close(fd.sockfd);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2012,6 +2205,8 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
|
|||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
lws_sockfd_type accept_fd = LWS_SOCK_INVALID;
|
||||
struct allocated_headers *ah;
|
||||
lws_sock_file_fd_type fd;
|
||||
int opts = LWS_ADOPT_SOCKET | LWS_ADOPT_ALLOW_SSL;
|
||||
#if LWS_POSIX
|
||||
struct sockaddr_storage cli_addr;
|
||||
socklen_t clilen;
|
||||
|
@ -2105,6 +2300,13 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
|
|||
ah->rxlen = ah->rxpos = 0;
|
||||
goto try_pollout;
|
||||
}
|
||||
|
||||
/*
|
||||
* make sure ah does not get detached if we
|
||||
* have live data in the rx
|
||||
*/
|
||||
if (ah->rxlen)
|
||||
wsi->more_rx_waiting = 1;
|
||||
}
|
||||
|
||||
if (!(ah->rxpos != ah->rxlen && ah->rxlen)) {
|
||||
|
@ -2115,7 +2317,8 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
|
|||
}
|
||||
|
||||
/* just ignore incoming if waiting for close */
|
||||
if (wsi->state != LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
|
||||
if (wsi->state != LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE &&
|
||||
wsi->state != LWSS_HTTP_ISSUING_FILE) {
|
||||
n = lws_read(wsi, ah->rx + ah->rxpos,
|
||||
ah->rxlen - ah->rxpos);
|
||||
if (n < 0) /* we closed wsi */
|
||||
|
@ -2126,7 +2329,7 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
|
|||
|
||||
lwsl_debug("%s: wsi %p: ah read rxpos %d, rxlen %d\n", __func__, wsi, wsi->u.hdr.ah->rxpos, wsi->u.hdr.ah->rxlen);
|
||||
|
||||
if (wsi->u.hdr.ah->rxpos == wsi->u.hdr.ah->rxlen &&
|
||||
if (lws_header_table_is_in_detachable_state(wsi) &&
|
||||
(wsi->mode != LWSCM_HTTP_SERVING &&
|
||||
wsi->mode != LWSCM_HTTP_SERVING_ACCEPTED &&
|
||||
wsi->mode != LWSCM_HTTP2_SERVING))
|
||||
|
@ -2166,7 +2369,8 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
|
|||
}
|
||||
|
||||
/* just ignore incoming if waiting for close */
|
||||
if (wsi->state != LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
|
||||
if (wsi->state != LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE &&
|
||||
wsi->state != LWSS_HTTP_ISSUING_FILE) {
|
||||
/*
|
||||
* this may want to send
|
||||
* (via HTTP callback for example)
|
||||
|
@ -2198,6 +2402,16 @@ try_pollout:
|
|||
}
|
||||
|
||||
if (wsi->mode == LWSCM_RAW) {
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB, 1);
|
||||
#if defined(LWS_WITH_STATS)
|
||||
{
|
||||
uint64_t ul = time_in_microseconds() - wsi->active_writable_req_us;
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_MS_WRITABLE_DELAY, ul);
|
||||
lws_stats_atomic_max(wsi->context, pt, LWSSTATS_MS_WORST_WRITABLE_DELAY, ul);
|
||||
wsi->active_writable_req_us = 0;
|
||||
}
|
||||
#endif
|
||||
n = user_callback_handle_rxflow(wsi->protocol->callback,
|
||||
wsi, LWS_CALLBACK_RAW_WRITEABLE,
|
||||
wsi->user_space, NULL, 0);
|
||||
|
@ -2212,6 +2426,18 @@ try_pollout:
|
|||
break;
|
||||
|
||||
if (wsi->state != LWSS_HTTP_ISSUING_FILE) {
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB, 1);
|
||||
#if defined(LWS_WITH_STATS)
|
||||
{
|
||||
uint64_t ul = time_in_microseconds() - wsi->active_writable_req_us;
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_MS_WRITABLE_DELAY, ul);
|
||||
lws_stats_atomic_max(wsi->context, pt, LWSSTATS_MS_WORST_WRITABLE_DELAY, ul);
|
||||
wsi->active_writable_req_us = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
n = user_callback_handle_rxflow(wsi->protocol->callback,
|
||||
wsi, LWS_CALLBACK_HTTP_WRITEABLE,
|
||||
wsi->user_space, NULL, 0);
|
||||
|
@ -2222,12 +2448,15 @@ try_pollout:
|
|||
break;
|
||||
}
|
||||
|
||||
/* >0 == completion, <0 == error */
|
||||
/* >0 == completion, <0 == error
|
||||
*
|
||||
* We'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when
|
||||
* it's done. That's the case even if we just completed the
|
||||
* send, so wait for that.
|
||||
*/
|
||||
n = lws_serve_http_file_fragment(wsi);
|
||||
if (n < 0 || (n > 0 && lws_http_transaction_completed(wsi))) {
|
||||
lwsl_info("completed\n");
|
||||
if (n < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
@ -2240,6 +2469,23 @@ try_pollout:
|
|||
if (!(pollfd->revents & LWS_POLLIN) || !(pollfd->events & LWS_POLLIN))
|
||||
break;
|
||||
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
/*
|
||||
* can we really accept it, with regards to SSL limit?
|
||||
* another vhost may also have had POLLIN on his listener this
|
||||
* round and used it up already
|
||||
*/
|
||||
|
||||
if (wsi->vhost->use_ssl &&
|
||||
context->simultaneous_ssl_restriction &&
|
||||
context->simultaneous_ssl ==
|
||||
context->simultaneous_ssl_restriction)
|
||||
/* no... ignore it, he won't come again until we are
|
||||
* below the simultaneous_ssl_restriction limit and
|
||||
* POLLIN is enabled on him again
|
||||
*/
|
||||
break;
|
||||
#endif
|
||||
/* listen socket got an unencrypted connection... */
|
||||
|
||||
clilen = sizeof(cli_addr);
|
||||
|
@ -2283,13 +2529,18 @@ try_pollout:
|
|||
*/
|
||||
if ((wsi->vhost->protocols[0].callback)(wsi,
|
||||
LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
|
||||
NULL, (void *)(long)accept_fd, 0)) {
|
||||
NULL, (void *)(lws_intptr_t)accept_fd, 0)) {
|
||||
lwsl_debug("Callback denied network connection\n");
|
||||
compatible_close(accept_fd);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!lws_adopt_socket_vhost(wsi->vhost, accept_fd))
|
||||
if (!(wsi->vhost->options & LWS_SERVER_OPTION_ONLY_RAW))
|
||||
opts |= LWS_ADOPT_HTTP;
|
||||
|
||||
fd.sockfd = accept_fd;
|
||||
if (!lws_adopt_descriptor_vhost(wsi->vhost, opts, fd,
|
||||
NULL, NULL))
|
||||
/* already closed cleanly as necessary */
|
||||
return 1;
|
||||
|
||||
|
@ -2326,7 +2577,7 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
|
|||
unsigned char *response = pt->serv_buf + LWS_PRE;
|
||||
unsigned char *p = response;
|
||||
unsigned char *end = p + context->pt_serv_buf_size - LWS_PRE;
|
||||
unsigned long computed_total_content_length;
|
||||
lws_filepos_t computed_total_content_length;
|
||||
int ret = 0, cclen = 8, n = HTTP_STATUS_OK;
|
||||
lws_fop_flags_t fflags = LWS_O_RDONLY;
|
||||
#if defined(LWS_WITH_RANGES)
|
||||
|
@ -2427,7 +2678,7 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
|
|||
* Precompute it for the main response header
|
||||
*/
|
||||
|
||||
computed_total_content_length = (unsigned long)rp->agg +
|
||||
computed_total_content_length = (lws_filepos_t)rp->agg +
|
||||
6 /* final _lws\r\n */;
|
||||
|
||||
lws_ranges_reset(rp);
|
||||
|
@ -2448,7 +2699,7 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
|
|||
}
|
||||
|
||||
if (ranges == 1) {
|
||||
computed_total_content_length = (unsigned long)rp->agg;
|
||||
computed_total_content_length = (lws_filepos_t)rp->agg;
|
||||
n = lws_snprintf(cache_control, sizeof(cache_control), "bytes %llu-%llu/%llu",
|
||||
rp->start, rp->end, rp->extent);
|
||||
|
||||
|
@ -2973,6 +3224,8 @@ struct lws_spa {
|
|||
char *storage;
|
||||
char *end;
|
||||
int max_storage;
|
||||
|
||||
char finalized;
|
||||
};
|
||||
|
||||
static int
|
||||
|
@ -3088,6 +3341,10 @@ lws_spa_process(struct lws_spa *ludspa, const char *in, int len)
|
|||
lwsl_err("%s: NULL spa\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
/* we reject any junk after the last part arrived and we finalized */
|
||||
if (ludspa->finalized)
|
||||
return 0;
|
||||
|
||||
return lws_urldecode_s_process(ludspa->s, in, len);
|
||||
}
|
||||
|
||||
|
@ -3117,9 +3374,37 @@ lws_spa_finalize(struct lws_spa *spa)
|
|||
spa->s = NULL;
|
||||
}
|
||||
|
||||
spa->finalized = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_spa_destroy(struct lws_spa *spa)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
lwsl_notice("%s: destroy spa %p\n", __func__, spa);
|
||||
|
||||
if (spa->s)
|
||||
lws_urldecode_s_destroy(spa->s);
|
||||
|
||||
lwsl_debug("%s %p %p %p %p\n", __func__,
|
||||
spa->param_length,
|
||||
spa->params,
|
||||
spa->storage,
|
||||
spa
|
||||
);
|
||||
|
||||
lws_free(spa->param_length);
|
||||
lws_free(spa->params);
|
||||
lws_free(spa->storage);
|
||||
lws_free(spa);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
#if 0
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_spa_destroy(struct lws_spa *spa)
|
||||
{
|
||||
|
@ -3139,7 +3424,7 @@ lws_spa_destroy(struct lws_spa *spa)
|
|||
|
||||
return n;
|
||||
}
|
||||
|
||||
#endif
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_chunked_html_process(struct lws_process_html_args *args,
|
||||
struct lws_process_html_state *s)
|
||||
|
|
171
lib/service.c
171
lib/service.c
|
@ -24,8 +24,20 @@
|
|||
static int
|
||||
lws_calllback_as_writeable(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
int n;
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB, 1);
|
||||
#if defined(LWS_WITH_STATS)
|
||||
{
|
||||
uint64_t ul = time_in_microseconds() - wsi->active_writable_req_us;
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_MS_WRITABLE_DELAY, ul);
|
||||
lws_stats_atomic_max(wsi->context, pt, LWSSTATS_MS_WORST_WRITABLE_DELAY, ul);
|
||||
wsi->active_writable_req_us = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (wsi->mode) {
|
||||
case LWSCM_RAW:
|
||||
n = LWS_CALLBACK_RAW_WRITEABLE;
|
||||
|
@ -46,13 +58,13 @@ lws_calllback_as_writeable(struct lws *wsi)
|
|||
n = LWS_CALLBACK_HTTP_WRITEABLE;
|
||||
break;
|
||||
}
|
||||
lwsl_debug("%s: %p (user=%p)\n", __func__, wsi, wsi->user_space);
|
||||
|
||||
return user_callback_handle_rxflow(wsi->protocol->callback,
|
||||
wsi, (enum lws_callback_reasons) n,
|
||||
wsi->user_space, NULL, 0);
|
||||
}
|
||||
|
||||
int
|
||||
LWS_VISIBLE int
|
||||
lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
|
||||
{
|
||||
int write_type = LWS_WRITE_PONG;
|
||||
|
@ -62,7 +74,7 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
|
|||
#endif
|
||||
int ret, m, n;
|
||||
|
||||
//lwsl_err("%s: %p\n", __func__, wsi);
|
||||
// lwsl_err("%s: %p\n", __func__, wsi);
|
||||
|
||||
wsi->leave_pollout_active = 0;
|
||||
wsi->handling_pollout = 1;
|
||||
|
@ -90,8 +102,10 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
|
|||
/* leave POLLOUT active either way */
|
||||
goto bail_ok;
|
||||
} else
|
||||
if (wsi->state == LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE)
|
||||
if (wsi->state == LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
|
||||
wsi->socket_is_permanently_unusable = 1;
|
||||
goto bail_die; /* retry closing now */
|
||||
}
|
||||
|
||||
if (wsi->mode == LWSCM_WSCL_ISSUE_HTTP_BODY)
|
||||
goto user_service;
|
||||
|
@ -118,12 +132,41 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
|
|||
#endif
|
||||
|
||||
#ifdef LWS_WITH_CGI
|
||||
if (wsi->cgi)
|
||||
if (wsi->cgi) {
|
||||
/* also one shot */
|
||||
if (pollfd)
|
||||
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
|
||||
lwsl_info("failed at set pollfd\n");
|
||||
return 1;
|
||||
}
|
||||
goto user_service_go_again;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Priority 3: pending control packets (pong or close)
|
||||
*
|
||||
* 3a: close notification packet requested from close api
|
||||
*/
|
||||
|
||||
if (wsi->state == LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION) {
|
||||
lwsl_debug("sending close packet\n");
|
||||
wsi->waiting_to_send_close_frame = 0;
|
||||
n = lws_write(wsi, &wsi->u.ws.ping_payload_buf[LWS_PRE],
|
||||
wsi->u.ws.close_in_ping_buffer_len,
|
||||
LWS_WRITE_CLOSE);
|
||||
if (n >= 0) {
|
||||
wsi->state = LWSS_AWAITING_CLOSE_ACK;
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_ACK, 1);
|
||||
lwsl_debug("sent close indication, awaiting ack\n");
|
||||
|
||||
goto bail_ok;
|
||||
}
|
||||
|
||||
goto bail_die;
|
||||
}
|
||||
|
||||
/* else, the send failed and we should just hang up */
|
||||
|
||||
if ((wsi->state == LWSS_ESTABLISHED &&
|
||||
wsi->u.ws.ping_pending_flag) ||
|
||||
(wsi->state == LWSS_RETURNED_CLOSE_ALREADY &&
|
||||
|
@ -286,6 +329,13 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
|
|||
user_service:
|
||||
/* one shot */
|
||||
|
||||
if (wsi->parent_carries_io) {
|
||||
wsi->handling_pollout = 0;
|
||||
wsi->leave_pollout_active = 0;
|
||||
|
||||
return lws_calllback_as_writeable(wsi);
|
||||
}
|
||||
|
||||
if (pollfd) {
|
||||
int eff = wsi->leave_pollout_active;
|
||||
|
||||
|
@ -298,7 +348,6 @@ user_service:
|
|||
wsi->handling_pollout = 0;
|
||||
|
||||
/* cannot get leave_pollout_active set after the above */
|
||||
|
||||
if (!eff && wsi->leave_pollout_active)
|
||||
/* got set inbetween sampling eff and clearing
|
||||
* handling_pollout, force POLLOUT on */
|
||||
|
@ -416,6 +465,8 @@ lws_service_timeout_check(struct lws *wsi, unsigned int sec)
|
|||
if (wsi->desc.sockfd != LWS_SOCK_INVALID && wsi->position_in_fds_table >= 0)
|
||||
n = pt->fds[wsi->position_in_fds_table].events;
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_TIMEOUTS, 1);
|
||||
|
||||
/* no need to log normal idle keepalive timeout */
|
||||
if (wsi->pending_timeout != PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE)
|
||||
lwsl_notice("wsi %p: TIMEDOUT WAITING on %d (did hdr %d, ah %p, wl %d, pfd events %d) %llu vs %llu\n",
|
||||
|
@ -604,7 +655,10 @@ lws_http_client_read(struct lws *wsi, char **buf, int *len)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (rlen <= 0)
|
||||
if (rlen == 0)
|
||||
return -1;
|
||||
|
||||
if (rlen < 0)
|
||||
return 0;
|
||||
|
||||
*len = rlen;
|
||||
|
@ -671,8 +725,8 @@ spin_chunks:
|
|||
return 0;
|
||||
|
||||
if (wsi->u.http.content_remain &&
|
||||
(int)wsi->u.http.content_remain < *len)
|
||||
n = wsi->u.http.content_remain;
|
||||
wsi->u.http.content_remain < *len)
|
||||
n = (int)wsi->u.http.content_remain;
|
||||
else
|
||||
n = *len;
|
||||
|
||||
|
@ -774,8 +828,17 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
|
|||
if (context->last_timeout_check_s != now) {
|
||||
context->last_timeout_check_s = now;
|
||||
|
||||
#if defined(LWS_WITH_STATS)
|
||||
if (!tsi && now - context->last_dump > 10) {
|
||||
lws_stats_log_dump(context);
|
||||
context->last_dump = now;
|
||||
}
|
||||
#endif
|
||||
|
||||
lws_plat_service_periodic(context);
|
||||
|
||||
lws_check_deferred_free(context, 0);
|
||||
|
||||
/* retire unused deprecated context */
|
||||
#if !defined(LWS_PLAT_OPTEE) && !defined(LWS_WITH_ESP32)
|
||||
#if LWS_POSIX && !defined(_WIN32)
|
||||
|
@ -791,6 +854,10 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
|
|||
if (pollfd)
|
||||
our_fd = pollfd->fd;
|
||||
|
||||
/*
|
||||
* Phase 1: check every wsi on the timeout check list
|
||||
*/
|
||||
|
||||
wsi = context->pt[tsi].timeout_list;
|
||||
while (wsi) {
|
||||
/* we have to take copies, because he may be deleted */
|
||||
|
@ -805,7 +872,70 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
|
|||
}
|
||||
wsi = wsi1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Phase 2: double-check active ah timeouts independent of wsi
|
||||
* timeout status
|
||||
*/
|
||||
|
||||
for (n = 0; n < context->max_http_header_pool; n++)
|
||||
if (pt->ah_pool[n].in_use && pt->ah_pool[n].wsi &&
|
||||
pt->ah_pool[n].assigned &&
|
||||
now - pt->ah_pool[n].assigned > 60) {
|
||||
int len;
|
||||
char buf[256];
|
||||
const unsigned char *c;
|
||||
|
||||
/*
|
||||
* a single ah session somehow got held for
|
||||
* an unreasonable amount of time.
|
||||
*
|
||||
* Dump info on the connection...
|
||||
*/
|
||||
|
||||
wsi = pt->ah_pool[n].wsi;
|
||||
buf[0] = '\0';
|
||||
lws_get_peer_simple(wsi, buf, sizeof(buf));
|
||||
lwsl_notice("ah excessive hold: wsi %p\n"
|
||||
" peer address: %s\n"
|
||||
" ah rxpos %u, rxlen %u, pos %u\n",
|
||||
wsi, buf, pt->ah_pool[n].rxpos,
|
||||
pt->ah_pool[n].rxlen,
|
||||
pt->ah_pool[n].pos);
|
||||
|
||||
m = 0;
|
||||
do {
|
||||
c = lws_token_to_string(m);
|
||||
if (!c)
|
||||
break;
|
||||
|
||||
len = lws_hdr_total_length(wsi, m);
|
||||
if (!len || len > sizeof(buf) - 1) {
|
||||
m++;
|
||||
continue;
|
||||
}
|
||||
|
||||
lws_hdr_copy(wsi, buf, sizeof buf, m);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
|
||||
lwsl_notice(" %s = %s\n",
|
||||
(const char *)c, buf);
|
||||
m++;
|
||||
} while (1);
|
||||
|
||||
/* ... and then drop the connection */
|
||||
|
||||
if (wsi->desc.sockfd == our_fd)
|
||||
/* it was the guy we came to service! */
|
||||
timed_out = 1;
|
||||
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
|
||||
}
|
||||
|
||||
#ifdef LWS_WITH_CGI
|
||||
/*
|
||||
* Phase 3: handle cgi timeouts
|
||||
*/
|
||||
lws_cgi_kill_terminated(pt);
|
||||
#endif
|
||||
#if 0
|
||||
|
@ -896,8 +1026,12 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
|
|||
#endif
|
||||
|
||||
// lwsl_debug("fd=%d, revents=%d, mode=%d, state=%d\n", pollfd->fd, pollfd->revents, (int)wsi->mode, (int)wsi->state);
|
||||
if (pollfd->revents & LWS_POLLHUP)
|
||||
if ((!(pollfd->revents & pollfd->events & LWS_POLLIN)) &&
|
||||
(pollfd->revents & LWS_POLLHUP)) {
|
||||
lwsl_debug("pollhup\n");
|
||||
wsi->socket_is_permanently_unusable = 1;
|
||||
goto close_and_handled;
|
||||
}
|
||||
|
||||
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
|
@ -1001,11 +1135,15 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
|
|||
|
||||
/* 1: something requested a callback when it was OK to write */
|
||||
|
||||
if (wsi->state == LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION)
|
||||
lwsl_notice("xxx\n");
|
||||
|
||||
if ((pollfd->revents & LWS_POLLOUT) &&
|
||||
((wsi->state == LWSS_ESTABLISHED ||
|
||||
wsi->state == LWSS_HTTP2_ESTABLISHED ||
|
||||
wsi->state == LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS ||
|
||||
wsi->state == LWSS_RETURNED_CLOSE_ALREADY ||
|
||||
wsi->state == LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION ||
|
||||
wsi->state == LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE)) &&
|
||||
lws_handle_POLLOUT_event(wsi, pollfd)) {
|
||||
if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY)
|
||||
|
@ -1015,6 +1153,7 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
|
|||
}
|
||||
|
||||
if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY ||
|
||||
wsi->state == LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION ||
|
||||
wsi->state == LWSS_AWAITING_CLOSE_ACK) {
|
||||
/*
|
||||
* we stopped caring about anything except control
|
||||
|
@ -1116,7 +1255,7 @@ read:
|
|||
eff_buf.token_len = context->pt_serv_buf_size;
|
||||
}
|
||||
|
||||
if (eff_buf.token_len > context->pt_serv_buf_size)
|
||||
if ((unsigned int)eff_buf.token_len > context->pt_serv_buf_size)
|
||||
eff_buf.token_len = context->pt_serv_buf_size;
|
||||
|
||||
eff_buf.token_len = lws_ssl_capable_read(wsi,
|
||||
|
@ -1164,9 +1303,12 @@ drain:
|
|||
wsi->protocol->callback,
|
||||
wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP,
|
||||
wsi->user_space, NULL, 0)) {
|
||||
lwsl_debug("LWS_CALLBACK_RECEIVE_CLIENT_HTTP closed it\n");
|
||||
lwsl_notice("LWS_CALLBACK_RECEIVE_CLIENT_HTTP closed it\n");
|
||||
goto close_and_handled;
|
||||
}
|
||||
|
||||
n = 0;
|
||||
goto handled;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
|
@ -1218,8 +1360,7 @@ drain:
|
|||
if (wsi->u.hdr.ah) {
|
||||
lwsl_notice("%s: %p: detaching\n",
|
||||
__func__, wsi);
|
||||
/* show we used all the pending rx up */
|
||||
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
|
||||
lws_header_table_force_to_detachable_state(wsi);
|
||||
/* we can run the normal ah detach flow despite
|
||||
* being in ws union mode, since all union members
|
||||
* start with hdr */
|
||||
|
@ -1308,7 +1449,7 @@ drain:
|
|||
goto handled;
|
||||
|
||||
close_and_handled:
|
||||
lwsl_debug("Close and handled\n");
|
||||
lwsl_debug("%p: Close and handled\n", wsi);
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
|
||||
/*
|
||||
* pollfd may point to something else after the close
|
||||
|
|
|
@ -29,12 +29,18 @@ lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info
|
|||
|
||||
extern int lws_ssl_get_error(struct lws *wsi, int n);
|
||||
|
||||
#ifdef USE_WOLFSSL
|
||||
#if defined(USE_WOLFSSL)
|
||||
#else
|
||||
|
||||
static int
|
||||
OpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
||||
{
|
||||
#if defined(LWS_WITH_ESP32)
|
||||
// long gvr = ssl_pm_get_verify_result(
|
||||
lwsl_notice("%s\n", __func__);
|
||||
|
||||
return 0;
|
||||
#else
|
||||
SSL *ssl;
|
||||
int n;
|
||||
struct lws *wsi;
|
||||
|
@ -87,6 +93,7 @@ OpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
|||
}
|
||||
/* convert callback return code from 0 = OK to verify callback return value 1 = OK */
|
||||
return !n;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -119,10 +126,15 @@ lws_ssl_client_bio_create(struct lws *wsi)
|
|||
if (!wsi->ssl) {
|
||||
lwsl_err("SSL_new failed: %s\n",
|
||||
ERR_error_string(lws_ssl_get_error(wsi, 0), NULL));
|
||||
lws_decode_ssl_error();
|
||||
lws_ssl_elaborate_error();
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
|
||||
if (wsi->vhost->ssl_info_event_mask)
|
||||
SSL_set_info_callback(wsi->ssl, lws_ssl_info_callback);
|
||||
#endif
|
||||
|
||||
#if defined LWS_HAVE_X509_VERIFY_PARAM_set1_host
|
||||
X509_VERIFY_PARAM *param;
|
||||
(void)param;
|
||||
|
@ -137,14 +149,14 @@ lws_ssl_client_bio_create(struct lws *wsi)
|
|||
|
||||
#endif
|
||||
|
||||
#ifndef USE_WOLFSSL
|
||||
#if !defined(USE_WOLFSSL) && !defined(LWS_WITH_ESP32)
|
||||
#ifndef USE_OLD_CYASSL
|
||||
/* OpenSSL_client_verify_callback will be called @ SSL_connect() */
|
||||
SSL_set_verify(wsi->ssl, SSL_VERIFY_PEER, OpenSSL_client_verify_callback);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef USE_WOLFSSL
|
||||
#if !defined(USE_WOLFSSL) && !defined(LWS_WITH_ESP32)
|
||||
SSL_set_mode(wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||
#endif
|
||||
/*
|
||||
|
@ -161,11 +173,18 @@ lws_ssl_client_bio_create(struct lws *wsi)
|
|||
wolfSSL_UseSNI(wsi->ssl, WOLFSSL_SNI_HOST_NAME, hostname, strlen(hostname));
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#if defined(LWS_WITH_ESP32)
|
||||
// esp-idf openssl shim does not seem ready for this
|
||||
// SSL_set_verify(wsi->ssl, SSL_VERIFY_PEER, OpenSSL_client_verify_callback);
|
||||
SSL_set_verify(wsi->ssl, SSL_VERIFY_NONE, OpenSSL_client_verify_callback);
|
||||
|
||||
#else
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
SSL_set_tlsext_host_name(wsi->ssl, hostname);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_WOLFSSL
|
||||
/*
|
||||
|
@ -184,8 +203,12 @@ lws_ssl_client_bio_create(struct lws *wsi)
|
|||
#endif
|
||||
#endif /* USE_WOLFSSL */
|
||||
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
wsi->client_bio = BIO_new_socket(wsi->desc.sockfd, BIO_NOCLOSE);
|
||||
SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio);
|
||||
#else
|
||||
SSL_set_fd(wsi->ssl, wsi->desc.sockfd);
|
||||
#endif
|
||||
|
||||
#ifdef USE_WOLFSSL
|
||||
#ifdef USE_OLD_CYASSL
|
||||
|
@ -194,15 +217,26 @@ lws_ssl_client_bio_create(struct lws *wsi)
|
|||
wolfSSL_set_using_nonblock(wsi->ssl, 1);
|
||||
#endif
|
||||
#else
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
BIO_set_nbio(wsi->client_bio, 1); /* nonblocking */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
SSL_set_ex_data(wsi->ssl, openssl_websocket_private_data_index,
|
||||
wsi);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_ESP32)
|
||||
int ERR_get_error(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
lws_ssl_client_connect1(struct lws *wsi)
|
||||
{
|
||||
|
@ -289,7 +323,7 @@ lws_ssl_client_connect2(struct lws *wsi)
|
|||
if (wsi->mode == LWSCM_WSCL_WAITING_SSL) {
|
||||
lws_latency_pre(context, wsi);
|
||||
n = SSL_connect(wsi->ssl);
|
||||
lwsl_notice("%s: SSL_connect says %d\n", __func__, n);
|
||||
lwsl_debug("%s: SSL_connect says %d\n", __func__, n);
|
||||
|
||||
lws_latency(context, wsi,
|
||||
"SSL_connect LWSCM_WSCL_WAITING_SSL", n, n > 0);
|
||||
|
@ -343,6 +377,19 @@ lws_ssl_client_connect2(struct lws *wsi)
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_ESP32)
|
||||
{
|
||||
X509 *peer = SSL_get_peer_certificate(wsi->ssl);
|
||||
|
||||
if (!peer) {
|
||||
lwsl_notice("peer did not provide cert\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
lwsl_notice("peer provided cert\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef USE_WOLFSSL
|
||||
/*
|
||||
* See comment above about wolfSSL certificate
|
||||
|
@ -353,6 +400,8 @@ lws_ssl_client_connect2(struct lws *wsi)
|
|||
lws_latency(context, wsi,
|
||||
"SSL_get_verify_result LWS_CONNMODE..HANDSHAKE", n, n > 0);
|
||||
|
||||
lwsl_debug("get_verify says %d\n", n);
|
||||
|
||||
if (n != X509_V_OK) {
|
||||
if ((n == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
|
||||
n == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) &&
|
||||
|
@ -385,10 +434,12 @@ int lws_context_init_client_ssl(struct lws_context_creation_info *info,
|
|||
SSL_METHOD *method = NULL;
|
||||
struct lws wsi;
|
||||
unsigned long error;
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
const char *cipher_list = info->ssl_cipher_list;
|
||||
const char *ca_filepath = info->ssl_ca_filepath;
|
||||
const char *cert_filepath = info->ssl_cert_filepath;
|
||||
const char *private_key_filepath = info->ssl_private_key_filepath;
|
||||
const char *cert_filepath = info->ssl_cert_filepath;
|
||||
|
||||
int n;
|
||||
|
||||
/*
|
||||
|
@ -403,10 +454,14 @@ int lws_context_init_client_ssl(struct lws_context_creation_info *info,
|
|||
cert_filepath = info->client_ssl_cert_filepath;
|
||||
if (info->client_ssl_private_key_filepath)
|
||||
private_key_filepath = info->client_ssl_private_key_filepath;
|
||||
#endif
|
||||
|
||||
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))
|
||||
return 0;
|
||||
|
||||
if (vhost->ssl_client_ctx)
|
||||
return 0;
|
||||
|
||||
if (info->provided_client_ssl_ctx) {
|
||||
/* use the provided OpenSSL context if given one */
|
||||
vhost->ssl_client_ctx = info->provided_client_ssl_ctx;
|
||||
|
@ -416,9 +471,6 @@ int lws_context_init_client_ssl(struct lws_context_creation_info *info,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (info->port != CONTEXT_PORT_NO_LISTEN)
|
||||
return 0;
|
||||
|
||||
/* basic openssl init already happened in context init */
|
||||
|
||||
/* choose the most recent spin of the api */
|
||||
|
@ -449,8 +501,11 @@ int lws_context_init_client_ssl(struct lws_context_creation_info *info,
|
|||
#ifdef SSL_OP_NO_COMPRESSION
|
||||
SSL_CTX_set_options(vhost->ssl_client_ctx, SSL_OP_NO_COMPRESSION);
|
||||
#endif
|
||||
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
SSL_CTX_set_options(vhost->ssl_client_ctx,
|
||||
SSL_OP_CIPHER_SERVER_PREFERENCE);
|
||||
|
||||
if (cipher_list)
|
||||
SSL_CTX_set_cipher_list(vhost->ssl_client_ctx, cipher_list);
|
||||
|
||||
|
@ -481,11 +536,12 @@ int lws_context_init_client_ssl(struct lws_context_creation_info *info,
|
|||
}
|
||||
else
|
||||
lwsl_info("loaded ssl_ca_filepath\n");
|
||||
|
||||
#endif
|
||||
/*
|
||||
* callback allowing user code to load extra verification certs
|
||||
* helping the client to verify server identity
|
||||
*/
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
|
||||
/* support for client-side certificate authentication */
|
||||
if (cert_filepath) {
|
||||
|
@ -500,7 +556,6 @@ int lws_context_init_client_ssl(struct lws_context_creation_info *info,
|
|||
}
|
||||
lwsl_notice("Loaded client cert %s\n", cert_filepath);
|
||||
}
|
||||
|
||||
if (private_key_filepath) {
|
||||
lwsl_notice("%s: doing private key filepath\n", __func__);
|
||||
lws_ssl_bind_passphrase(vhost->ssl_client_ctx, info);
|
||||
|
@ -521,7 +576,7 @@ int lws_context_init_client_ssl(struct lws_context_creation_info *info,
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
* give him a fake wsi with context set, so he can use
|
||||
* lws_get_context() in the callback
|
||||
|
|
|
@ -27,6 +27,7 @@ extern int openssl_websocket_private_data_index,
|
|||
extern void
|
||||
lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info);
|
||||
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
static int
|
||||
OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
||||
{
|
||||
|
@ -50,6 +51,7 @@ OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
|||
/* convert return code from 0 = OK to 1 = OK */
|
||||
return !n;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
lws_context_ssl_init_ecdh(struct lws_vhost *vhost)
|
||||
|
@ -128,7 +130,9 @@ lws_context_ssl_init_ecdh_curve(struct lws_context_creation_info *info,
|
|||
|
||||
lwsl_notice(" SSL ECDH curve '%s'\n", ecdh_curve);
|
||||
#else
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
lwsl_notice(" OpenSSL doesn't support ECDH\n");
|
||||
#endif
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -156,7 +160,7 @@ lws_ssl_server_name_cb(SSL *ssl, int *ad, void *arg)
|
|||
*/
|
||||
vh = context->vhost_list;
|
||||
while (vh) {
|
||||
if (vh->ssl_ctx == SSL_get_SSL_CTX(ssl))
|
||||
if (!vh->being_destroyed && vh->ssl_ctx == SSL_get_SSL_CTX(ssl))
|
||||
break;
|
||||
vh = vh->vhost_next;
|
||||
}
|
||||
|
@ -226,7 +230,7 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
|
|||
* versions", compared to e.g. TLSv1_2_server_method() which only allows
|
||||
* tlsv1.2. Unwanted versions must be disabled using SSL_CTX_set_options()
|
||||
*/
|
||||
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
{
|
||||
SSL_METHOD *method;
|
||||
|
||||
|
@ -247,12 +251,24 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
const SSL_METHOD *method = TLSv1_2_server_method();
|
||||
|
||||
vhost->ssl_ctx = SSL_CTX_new(method); /* create context */
|
||||
if (!vhost->ssl_ctx) {
|
||||
lwsl_err("problem creating ssl context\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
|
||||
/* associate the lws context with the SSL_CTX */
|
||||
|
||||
SSL_CTX_set_ex_data(vhost->ssl_ctx,
|
||||
openssl_SSL_CTX_private_data_index, vhost->context);
|
||||
|
||||
openssl_SSL_CTX_private_data_index, (char *)vhost->context);
|
||||
/* Disable SSLv2 and SSLv3 */
|
||||
SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
||||
#ifdef SSL_OP_NO_COMPRESSION
|
||||
|
@ -260,9 +276,11 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
|
|||
#endif
|
||||
SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_SINGLE_DH_USE);
|
||||
SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
|
||||
|
||||
if (info->ssl_cipher_list)
|
||||
SSL_CTX_set_cipher_list(vhost->ssl_ctx,
|
||||
info->ssl_cipher_list);
|
||||
#endif
|
||||
|
||||
/* as a server, are we requiring clients to identify themselves? */
|
||||
|
||||
|
@ -274,6 +292,7 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
|
|||
LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED))
|
||||
verify_options |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
|
||||
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
SSL_CTX_set_session_id_context(vhost->ssl_ctx,
|
||||
(unsigned char *)context, sizeof(void *));
|
||||
|
||||
|
@ -281,6 +300,7 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
|
|||
|
||||
SSL_CTX_set_verify(vhost->ssl_ctx,
|
||||
verify_options, OpenSSL_verify_callback);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
|
@ -292,13 +312,13 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
|
|||
* give user code a chance to load certs into the server
|
||||
* allowing it to verify incoming client certs
|
||||
*/
|
||||
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
if (info->ssl_ca_filepath &&
|
||||
!SSL_CTX_load_verify_locations(vhost->ssl_ctx,
|
||||
info->ssl_ca_filepath, NULL)) {
|
||||
lwsl_err("%s: SSL_CTX_load_verify_locations unhappy\n", __func__);
|
||||
}
|
||||
|
||||
#endif
|
||||
if (vhost->use_ssl) {
|
||||
if (lws_context_ssl_init_ecdh_curve(info, vhost))
|
||||
return -1;
|
||||
|
@ -326,7 +346,7 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
|
|||
|
||||
if (vhost->use_ssl) {
|
||||
/* openssl init for server sockets */
|
||||
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
/* set the local certificate from CertFile */
|
||||
n = SSL_CTX_use_certificate_chain_file(vhost->ssl_ctx,
|
||||
info->ssl_cert_filepath);
|
||||
|
@ -340,8 +360,42 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
|
|||
return 1;
|
||||
}
|
||||
lws_ssl_bind_passphrase(vhost->ssl_ctx, info);
|
||||
#else
|
||||
uint8_t *p;
|
||||
lws_filepos_t flen;
|
||||
int err;
|
||||
|
||||
if (alloc_pem_to_der_file(vhost->context, info->ssl_cert_filepath, &p,
|
||||
&flen)) {
|
||||
lwsl_err("couldn't find cert file %s\n",
|
||||
info->ssl_cert_filepath);
|
||||
|
||||
return 1;
|
||||
}
|
||||
err = SSL_CTX_use_certificate_ASN1(vhost->ssl_ctx, flen, p);
|
||||
if (!err) {
|
||||
lwsl_err("Problem loading cert\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (alloc_pem_to_der_file(vhost->context,
|
||||
info->ssl_private_key_filepath, &p, &flen)) {
|
||||
lwsl_err("couldn't find cert file %s\n",
|
||||
info->ssl_cert_filepath);
|
||||
|
||||
return 1;
|
||||
}
|
||||
err = SSL_CTX_use_PrivateKey_ASN1(0, vhost->ssl_ctx, p, flen);
|
||||
if (!err) {
|
||||
lwsl_err("Problem loading key\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// free(p);
|
||||
#endif
|
||||
if (info->ssl_private_key_filepath != NULL) {
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
/* set the private key from KeyFile */
|
||||
if (SSL_CTX_use_PrivateKey_file(vhost->ssl_ctx,
|
||||
info->ssl_private_key_filepath,
|
||||
|
@ -353,6 +407,7 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
|
|||
(char *)context->pt[0].serv_buf));
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
} else
|
||||
if (vhost->protocols[0].callback(&wsi,
|
||||
LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY,
|
||||
|
@ -361,13 +416,13 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
|
|||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
/* verify private key */
|
||||
if (!SSL_CTX_check_private_key(vhost->ssl_ctx)) {
|
||||
lwsl_err("Private SSL key doesn't match cert\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
if (lws_context_ssl_init_ecdh(vhost))
|
||||
return 1;
|
||||
|
||||
|
|
376
lib/ssl.c
376
lib/ssl.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
|
||||
* Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -26,11 +26,129 @@
|
|||
#define ECONNABORTED 103
|
||||
#endif
|
||||
|
||||
int lws_alloc_vfs_file(struct lws_context *context, const char *filename, uint8_t **buf,
|
||||
lws_filepos_t *amount)
|
||||
{
|
||||
lws_filepos_t len;
|
||||
lws_fop_flags_t flags = LWS_O_RDONLY;
|
||||
lws_fop_fd_t fops_fd = lws_vfs_file_open(
|
||||
lws_get_fops(context), filename, &flags);
|
||||
int ret = 1;
|
||||
|
||||
if (!fops_fd)
|
||||
return 1;
|
||||
|
||||
len = lws_vfs_get_length(fops_fd);
|
||||
|
||||
*buf = malloc((size_t)len);
|
||||
if (!*buf)
|
||||
goto bail;
|
||||
|
||||
if (lws_vfs_file_read(fops_fd, amount, *buf, len))
|
||||
goto bail;
|
||||
|
||||
ret = 0;
|
||||
bail:
|
||||
lws_vfs_file_close(&fops_fd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_ESP32)
|
||||
int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
|
||||
lws_filepos_t *amount)
|
||||
{
|
||||
nvs_handle nvh;
|
||||
size_t s;
|
||||
int n = 0;
|
||||
|
||||
ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
|
||||
if (nvs_get_blob(nvh, filename, NULL, &s) != ESP_OK) {
|
||||
n = 1;
|
||||
goto bail;
|
||||
}
|
||||
*buf = malloc(s);
|
||||
if (!*buf) {
|
||||
n = 2;
|
||||
goto bail;
|
||||
}
|
||||
if (nvs_get_blob(nvh, filename, (char *)*buf, &s) != ESP_OK) {
|
||||
free(*buf);
|
||||
n = 1;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
*amount = s;
|
||||
|
||||
bail:
|
||||
nvs_close(nvh);
|
||||
|
||||
return n;
|
||||
}
|
||||
int alloc_pem_to_der_file(struct lws_context *context, const char *filename, uint8_t **buf,
|
||||
lws_filepos_t *amount)
|
||||
{
|
||||
uint8_t *pem, *p, *q, *end;
|
||||
lws_filepos_t len;
|
||||
int n;
|
||||
|
||||
n = alloc_file(context, filename, &pem, &len);
|
||||
if (n)
|
||||
return n;
|
||||
|
||||
/* trim the first line */
|
||||
|
||||
p = pem;
|
||||
end = p + len;
|
||||
if (strncmp((char *)p, "-----", 5))
|
||||
goto bail;
|
||||
p += 5;
|
||||
while (p < end && *p != '\n' && *p != '-')
|
||||
p++;
|
||||
|
||||
if (*p != '-')
|
||||
goto bail;
|
||||
|
||||
while (p < end && *p != '\n')
|
||||
p++;
|
||||
|
||||
if (p >= end)
|
||||
goto bail;
|
||||
|
||||
p++;
|
||||
|
||||
/* trim the last line */
|
||||
|
||||
q = end - 2;
|
||||
|
||||
while (q > pem && *q != '\n')
|
||||
q--;
|
||||
|
||||
if (*q != '\n')
|
||||
goto bail;
|
||||
|
||||
*q = '\0';
|
||||
|
||||
*amount = lws_b64_decode_string((char *)p, (char *)pem, len);
|
||||
*buf = pem;
|
||||
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
free(pem);
|
||||
|
||||
return 4;
|
||||
}
|
||||
#endif
|
||||
|
||||
int openssl_websocket_private_data_index,
|
||||
openssl_SSL_CTX_private_data_index;
|
||||
|
||||
int lws_ssl_get_error(struct lws *wsi, int n)
|
||||
{
|
||||
if (!wsi->ssl)
|
||||
return 99;
|
||||
lwsl_debug("%s: %p %d\n", __func__, wsi->ssl, n);
|
||||
return SSL_get_error(wsi->ssl, n);
|
||||
}
|
||||
|
||||
|
@ -81,6 +199,8 @@ char* lws_ssl_get_error_string(int status, int ret, char *buf, size_t len) {
|
|||
void
|
||||
lws_ssl_elaborate_error(void)
|
||||
{
|
||||
#if defined(LWS_WITH_ESP32)
|
||||
#else
|
||||
char buf[256];
|
||||
u_long err;
|
||||
|
||||
|
@ -88,8 +208,11 @@ lws_ssl_elaborate_error(void)
|
|||
ERR_error_string_n(err, buf, sizeof(buf));
|
||||
lwsl_err("*** %s\n", buf);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
|
||||
static int
|
||||
lws_context_init_ssl_pem_passwd_cb(char * buf, int size, int rwflag, void *userdata)
|
||||
{
|
||||
|
@ -107,7 +230,6 @@ lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info
|
|||
{
|
||||
if (!info->ssl_private_key_password)
|
||||
return;
|
||||
|
||||
/*
|
||||
* password provided, set ssl callback and user data
|
||||
* for checking password which will be trigered during
|
||||
|
@ -116,6 +238,7 @@ lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info
|
|||
SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, (void *)info);
|
||||
SSL_CTX_set_default_passwd_cb(ssl_ctx, lws_context_init_ssl_pem_passwd_cb);
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
lws_context_init_ssl_library(struct lws_context_creation_info *info)
|
||||
|
@ -142,8 +265,8 @@ lws_context_init_ssl_library(struct lws_context_creation_info *info)
|
|||
|
||||
lwsl_notice("Doing SSL library init\n");
|
||||
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
SSL_library_init();
|
||||
|
||||
OpenSSL_add_all_algorithms();
|
||||
SSL_load_error_strings();
|
||||
|
||||
|
@ -152,11 +275,11 @@ lws_context_init_ssl_library(struct lws_context_creation_info *info)
|
|||
|
||||
openssl_SSL_CTX_private_data_index = SSL_CTX_get_ex_new_index(0,
|
||||
NULL, NULL, NULL, NULL);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_ssl_destroy(struct lws_vhost *vhost)
|
||||
{
|
||||
|
@ -168,6 +291,7 @@ lws_ssl_destroy(struct lws_vhost *vhost)
|
|||
SSL_CTX_free(vhost->ssl_ctx);
|
||||
if (!vhost->user_supplied_ssl_ctx && vhost->ssl_client_ctx)
|
||||
SSL_CTX_free(vhost->ssl_client_ctx);
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
|
||||
// after 1.1.0 no need
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10100000)
|
||||
|
@ -182,22 +306,16 @@ lws_ssl_destroy(struct lws_vhost *vhost)
|
|||
#else
|
||||
ERR_remove_thread_state(NULL);
|
||||
#endif
|
||||
#endif
|
||||
// after 1.1.0 no need
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10002000) && (OPENSSL_VERSION_NUMBER <= 0x10100000)
|
||||
SSL_COMP_free_compression_methods();
|
||||
#endif
|
||||
ERR_free_strings();
|
||||
EVP_cleanup();
|
||||
CRYPTO_cleanup_all_ex_data();
|
||||
#endif
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_decode_ssl_error(void)
|
||||
{
|
||||
char buf[256];
|
||||
u_long err;
|
||||
while ((err = ERR_get_error()) != 0) {
|
||||
ERR_error_string_n(err, buf, sizeof(buf));
|
||||
lwsl_err("*** %lu %s\n", err, buf);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
|
@ -234,48 +352,82 @@ lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len)
|
|||
struct lws_context *context = wsi->context;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
int n = 0;
|
||||
int ssl_read_errno = 0;
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
int ssl_read_errno = 0;
|
||||
#endif
|
||||
|
||||
if (!wsi->ssl)
|
||||
return lws_ssl_capable_read_no_ssl(wsi, buf, len);
|
||||
|
||||
n = SSL_read(wsi->ssl, buf, len);
|
||||
lws_stats_atomic_bump(context, pt, LWSSTATS_C_API_READ, 1);
|
||||
|
||||
errno = 0;
|
||||
n = SSL_read(wsi->ssl, buf, len);
|
||||
#if defined(LWS_WITH_ESP32)
|
||||
if (!n && errno == ENOTCONN) {
|
||||
lwsl_debug("%p: SSL_read ENOTCONN\n", wsi);
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
#endif
|
||||
#if defined(LWS_WITH_STATS)
|
||||
if (!wsi->seen_rx) {
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_MS_SSL_RX_DELAY,
|
||||
time_in_microseconds() - wsi->accept_start_us);
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_SSL_CONNS_HAD_RX, 1);
|
||||
wsi->seen_rx = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
lwsl_debug("%p: SSL_read says %d\n", wsi, n);
|
||||
/* manpage: returning 0 means connection shut down */
|
||||
if (!n) {
|
||||
n = lws_ssl_get_error(wsi, n);
|
||||
n = lws_ssl_get_error(wsi, n);
|
||||
lwsl_debug("%p: ssl err %d errno %d\n", wsi, n, errno);
|
||||
if (n == SSL_ERROR_ZERO_RETURN)
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
|
||||
if (n == SSL_ERROR_ZERO_RETURN)
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
|
||||
if (n == SSL_ERROR_SYSCALL) {
|
||||
int err = ERR_get_error();
|
||||
if (err == 0
|
||||
&& (ssl_read_errno == EPIPE
|
||||
|| ssl_read_errno == ECONNABORTED
|
||||
|| ssl_read_errno == 0))
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
if (n == SSL_ERROR_SYSCALL) {
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
int err = ERR_get_error();
|
||||
if (err == 0 && (ssl_read_errno == EPIPE ||
|
||||
ssl_read_errno == ECONNABORTED ||
|
||||
ssl_read_errno == 0))
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
lwsl_err("%s failed: %s\n",__func__,
|
||||
ERR_error_string(lws_ssl_get_error(wsi, 0), NULL));
|
||||
lws_decode_ssl_error();
|
||||
lws_ssl_elaborate_error();
|
||||
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
|
||||
if (n < 0) {
|
||||
n = lws_ssl_get_error(wsi, n);
|
||||
if (n == SSL_ERROR_WANT_READ || n == SSL_ERROR_WANT_WRITE)
|
||||
// lwsl_notice("get_ssl_err result %d\n", n);
|
||||
if (n == SSL_ERROR_WANT_READ || SSL_want_read(wsi->ssl)) {
|
||||
lwsl_debug("%s: WANT_READ\n", __func__);
|
||||
lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi);
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE;
|
||||
}
|
||||
if (n == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->ssl)) {
|
||||
lwsl_debug("%s: WANT_WRITE\n", __func__);
|
||||
lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi);
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE;
|
||||
}
|
||||
|
||||
|
||||
lwsl_err("%s failed2: %s\n",__func__,
|
||||
ERR_error_string(lws_ssl_get_error(wsi, 0), NULL));
|
||||
lws_decode_ssl_error();
|
||||
lws_ssl_elaborate_error();
|
||||
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
|
||||
lws_stats_atomic_bump(context, pt, LWSSTATS_B_READ, n);
|
||||
|
||||
if (wsi->vhost)
|
||||
wsi->vhost->conn_stats.rx += n;
|
||||
|
||||
|
@ -331,7 +483,9 @@ LWS_VISIBLE int
|
|||
lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len)
|
||||
{
|
||||
int n;
|
||||
int ssl_read_errno = 0;
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
int ssl_read_errno = 0;
|
||||
#endif
|
||||
|
||||
if (!wsi->ssl)
|
||||
return lws_ssl_capable_write_no_ssl(wsi, buf, len);
|
||||
|
@ -342,15 +496,19 @@ lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len)
|
|||
|
||||
n = lws_ssl_get_error(wsi, n);
|
||||
if (n == SSL_ERROR_WANT_READ || n == SSL_ERROR_WANT_WRITE) {
|
||||
if (n == SSL_ERROR_WANT_WRITE)
|
||||
if (n == SSL_ERROR_WANT_WRITE) {
|
||||
lwsl_debug("%s: WANT_WRITE\n", __func__);
|
||||
lws_set_blocking_send(wsi);
|
||||
}
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE;
|
||||
}
|
||||
|
||||
if (n == SSL_ERROR_ZERO_RETURN)
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
if (n == SSL_ERROR_SYSCALL) {
|
||||
|
||||
int err = ERR_get_error();
|
||||
if (err == 0
|
||||
&& (ssl_read_errno == EPIPE
|
||||
|
@ -358,28 +516,97 @@ lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len)
|
|||
|| ssl_read_errno == 0))
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
lwsl_err("%s failed: %s\n",__func__,
|
||||
ERR_error_string(lws_ssl_get_error(wsi, 0), NULL));
|
||||
lws_decode_ssl_error();
|
||||
lws_ssl_elaborate_error();
|
||||
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_gate_accepts(struct lws_context *context, int on)
|
||||
{
|
||||
struct lws_vhost *v = context->vhost_list;
|
||||
|
||||
lwsl_info("gating accepts %d\n", on);
|
||||
context->ssl_gate_accepts = !on;
|
||||
#if defined(LWS_WITH_STATS)
|
||||
context->updated = 1;
|
||||
#endif
|
||||
|
||||
while (v) {
|
||||
if (v->use_ssl && v->lserv_wsi) /* gate ability to accept incoming connections */
|
||||
if (lws_change_pollfd(v->lserv_wsi, (LWS_POLLIN) * !on, (LWS_POLLIN) * on))
|
||||
lwsl_err("Unable to set accept POLLIN %d\n", on);
|
||||
|
||||
v = v->vhost_next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_ssl_info_callback(const SSL *ssl, int where, int ret)
|
||||
{
|
||||
struct lws *wsi;
|
||||
struct lws_context *context;
|
||||
struct lws_ssl_info si;
|
||||
|
||||
context = (struct lws_context *)SSL_CTX_get_ex_data(
|
||||
SSL_get_SSL_CTX(ssl),
|
||||
openssl_SSL_CTX_private_data_index);
|
||||
if (!context)
|
||||
return;
|
||||
wsi = wsi_from_fd(context, SSL_get_fd(ssl));
|
||||
if (!wsi)
|
||||
return;
|
||||
|
||||
if (!(where & wsi->vhost->ssl_info_event_mask))
|
||||
return;
|
||||
|
||||
si.where = where;
|
||||
si.ret = ret;
|
||||
|
||||
if (user_callback_handle_rxflow(wsi->protocol->callback,
|
||||
wsi, LWS_CALLBACK_SSL_INFO,
|
||||
wsi->user_space, &si, 0))
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_KILLED_BY_SSL_INFO, -1);
|
||||
}
|
||||
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_ssl_close(struct lws *wsi)
|
||||
{
|
||||
int n;
|
||||
lws_sockfd_type n;
|
||||
|
||||
if (!wsi->ssl)
|
||||
return 0; /* not handled */
|
||||
|
||||
#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
|
||||
/* kill ssl callbacks, becausse we will remove the fd from the
|
||||
* table linking it to the wsi
|
||||
*/
|
||||
if (wsi->vhost->ssl_info_event_mask)
|
||||
SSL_set_info_callback(wsi->ssl, NULL);
|
||||
#endif
|
||||
|
||||
n = SSL_get_fd(wsi->ssl);
|
||||
SSL_shutdown(wsi->ssl);
|
||||
compatible_close(n);
|
||||
SSL_free(wsi->ssl);
|
||||
wsi->ssl = NULL;
|
||||
|
||||
if (wsi->context->simultaneous_ssl_restriction &&
|
||||
wsi->context->simultaneous_ssl-- ==
|
||||
wsi->context->simultaneous_ssl_restriction)
|
||||
/* we made space and can do an accept */
|
||||
lws_gate_accepts(wsi->context, 1);
|
||||
#if defined(LWS_WITH_STATS)
|
||||
wsi->context->updated = 1;
|
||||
#endif
|
||||
|
||||
return 1; /* handled */
|
||||
}
|
||||
|
||||
|
@ -391,7 +618,7 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
|
|||
struct lws_context *context = wsi->context;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
int n, m;
|
||||
#if !defined(USE_WOLFSSL)
|
||||
#if !defined(USE_WOLFSSL) && !defined(LWS_WITH_ESP32)
|
||||
BIO *bio;
|
||||
#endif
|
||||
char buf[256];
|
||||
|
@ -406,20 +633,38 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
|
|||
lwsl_err("%s: leaking ssl\n", __func__);
|
||||
if (accept_fd == LWS_SOCK_INVALID)
|
||||
assert(0);
|
||||
|
||||
if (context->simultaneous_ssl_restriction &&
|
||||
context->simultaneous_ssl >= context->simultaneous_ssl_restriction) {
|
||||
lwsl_notice("unable to deal with SSL connection\n");
|
||||
return 1;
|
||||
}
|
||||
errno = 0;
|
||||
wsi->ssl = SSL_new(wsi->vhost->ssl_ctx);
|
||||
if (wsi->ssl == NULL) {
|
||||
lwsl_err("SSL_new failed: %s\n",
|
||||
ERR_error_string(lws_ssl_get_error(wsi, 0), NULL));
|
||||
lws_decode_ssl_error();
|
||||
lwsl_err("SSL_new failed: %d (errno %d)\n",
|
||||
lws_ssl_get_error(wsi, 0), errno);
|
||||
|
||||
lws_ssl_elaborate_error();
|
||||
if (accept_fd != LWS_SOCK_INVALID)
|
||||
compatible_close(accept_fd);
|
||||
goto fail;
|
||||
}
|
||||
#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
|
||||
if (wsi->vhost->ssl_info_event_mask)
|
||||
SSL_set_info_callback(wsi->ssl, lws_ssl_info_callback);
|
||||
#endif
|
||||
if (context->simultaneous_ssl_restriction &&
|
||||
++context->simultaneous_ssl == context->simultaneous_ssl_restriction)
|
||||
/* that was the last allowed SSL connection */
|
||||
lws_gate_accepts(context, 0);
|
||||
#if defined(LWS_WITH_STATS)
|
||||
context->updated = 1;
|
||||
#endif
|
||||
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
SSL_set_ex_data(wsi->ssl,
|
||||
openssl_websocket_private_data_index, wsi);
|
||||
|
||||
#endif
|
||||
SSL_set_fd(wsi->ssl, accept_fd);
|
||||
|
||||
#ifdef USE_WOLFSSL
|
||||
|
@ -428,6 +673,9 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
|
|||
#else
|
||||
wolfSSL_set_using_nonblock(wsi->ssl, 1);
|
||||
#endif
|
||||
#else
|
||||
#if defined(LWS_WITH_ESP32)
|
||||
lws_plat_set_socket_options(wsi->vhost, accept_fd);
|
||||
#else
|
||||
SSL_set_mode(wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||
bio = SSL_get_rbio(wsi->ssl);
|
||||
|
@ -440,6 +688,7 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
|
|||
BIO_set_nbio(bio, 1); /* nonblocking */
|
||||
else
|
||||
lwsl_notice("NULL rbio\n");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -461,7 +710,7 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
|
|||
lws_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT,
|
||||
context->timeout_secs);
|
||||
|
||||
lwsl_info("inserted SSL accept into fds, trying SSL_accept\n");
|
||||
lwsl_debug("inserted SSL accept into fds, trying SSL_accept\n");
|
||||
|
||||
/* fallthru */
|
||||
|
||||
|
@ -474,8 +723,10 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
|
|||
|
||||
lws_latency_pre(context, wsi);
|
||||
|
||||
n = recv(wsi->desc.sockfd, (char *)pt->serv_buf, context->pt_serv_buf_size,
|
||||
MSG_PEEK);
|
||||
if (wsi->vhost->allow_non_ssl_on_ssl_port) {
|
||||
|
||||
n = recv(wsi->desc.sockfd, (char *)pt->serv_buf, context->pt_serv_buf_size,
|
||||
MSG_PEEK);
|
||||
|
||||
/*
|
||||
* optionally allow non-SSL connect on SSL listening socket
|
||||
|
@ -484,7 +735,6 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
|
|||
* it disabled unless you know it's not a problem for you
|
||||
*/
|
||||
|
||||
if (wsi->vhost->allow_non_ssl_on_ssl_port) {
|
||||
if (n >= 1 && pt->serv_buf[0] >= ' ') {
|
||||
/*
|
||||
* TLS content-type for Handshake is 0x16, and
|
||||
|
@ -527,16 +777,27 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
|
|||
|
||||
/* normal SSL connection processing path */
|
||||
|
||||
#if defined(LWS_WITH_STATS)
|
||||
if (!wsi->accept_start_us)
|
||||
wsi->accept_start_us = time_in_microseconds();
|
||||
#endif
|
||||
|
||||
n = SSL_accept(wsi->ssl);
|
||||
lws_latency(context, wsi,
|
||||
"SSL_accept LWSCM_SSL_ACK_PENDING\n", n, n == 1);
|
||||
|
||||
lwsl_info("SSL_accept says %d\n", n);
|
||||
if (n == 1)
|
||||
goto accepted;
|
||||
|
||||
m = lws_ssl_get_error(wsi, n);
|
||||
|
||||
#if defined(LWS_WITH_ESP32)
|
||||
if (m == 5 && errno == 11)
|
||||
m = SSL_ERROR_WANT_READ;
|
||||
#endif
|
||||
|
||||
go_again:
|
||||
if (m == SSL_ERROR_WANT_READ) {
|
||||
if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->ssl)) {
|
||||
if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
|
||||
lwsl_err("%s: WANT_READ change_pollfd failed\n", __func__);
|
||||
goto fail;
|
||||
|
@ -545,7 +806,9 @@ go_again:
|
|||
lwsl_info("SSL_ERROR_WANT_READ\n");
|
||||
break;
|
||||
}
|
||||
if (m == SSL_ERROR_WANT_WRITE) {
|
||||
if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->ssl)) {
|
||||
lwsl_debug("%s: WANT_WRITE\n", __func__);
|
||||
|
||||
if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) {
|
||||
lwsl_err("%s: WANT_WRITE change_pollfd failed\n", __func__);
|
||||
goto fail;
|
||||
|
@ -553,13 +816,19 @@ go_again:
|
|||
|
||||
break;
|
||||
}
|
||||
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_SSL_CONNECTIONS_FAILED, 1);
|
||||
lwsl_err("SSL_accept failed socket %u: %s\n", wsi->desc.sockfd,
|
||||
lws_ssl_get_error_string(m, n, buf, sizeof(buf)));
|
||||
lws_ssl_elaborate_error();
|
||||
goto fail;
|
||||
|
||||
accepted:
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED, 1);
|
||||
#if defined(LWS_WITH_STATS)
|
||||
lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_MS_SSL_CONNECTIONS_ACCEPTED_DELAY, time_in_microseconds() - wsi->accept_start_us);
|
||||
wsi->accept_start_us = time_in_microseconds();
|
||||
#endif
|
||||
|
||||
/* OK, we are accepted... give him some time to negotiate */
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
|
||||
context->timeout_secs);
|
||||
|
@ -595,6 +864,8 @@ void
|
|||
lws_ssl_context_destroy(struct lws_context *context)
|
||||
{
|
||||
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
|
||||
// after 1.1.0 no need
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10100000)
|
||||
// <= 1.0.1f = old api, 1.0.1g+ = new api
|
||||
|
@ -608,9 +879,14 @@ lws_ssl_context_destroy(struct lws_context *context)
|
|||
#else
|
||||
ERR_remove_thread_state(NULL);
|
||||
#endif
|
||||
#endif
|
||||
// after 1.1.0 no need
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10002000) && (OPENSSL_VERSION_NUMBER <= 0x10100000)
|
||||
SSL_COMP_free_compression_methods();
|
||||
#endif
|
||||
ERR_free_strings();
|
||||
EVP_cleanup();
|
||||
CRYPTO_cleanup_all_ex_data();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Name: libwebsockets
|
||||
Version: 2.2.2
|
||||
Version: 2.3.0
|
||||
Release: 1%{?dist}
|
||||
Summary: Websocket Server and Client Library
|
||||
|
||||
|
@ -49,13 +49,12 @@ rm -rf $RPM_BUILD_ROOT
|
|||
%attr(755,root,root)
|
||||
/usr/bin/libwebsockets-test-server
|
||||
/usr/bin/libwebsockets-test-server-extpoll
|
||||
/usr/bin/libwebsockets-test-server-pthreads
|
||||
/usr/bin/libwebsockets-test-client
|
||||
/usr/bin/libwebsockets-test-ping
|
||||
/usr/bin/libwebsockets-test-echo
|
||||
/usr/bin/libwebsockets-test-fraggle
|
||||
/usr/bin/libwebsockets-test-fuzxy
|
||||
/%{_libdir}/libwebsockets.so.10
|
||||
/%{_libdir}/libwebsockets.so.11
|
||||
/%{_libdir}/libwebsockets.so
|
||||
/%{_libdir}/cmake/libwebsockets/LibwebsocketsConfig.cmake
|
||||
/%{_libdir}/cmake/libwebsockets/LibwebsocketsConfigVersion.cmake
|
||||
|
@ -70,10 +69,11 @@ rm -rf $RPM_BUILD_ROOT
|
|||
%attr(755,root,root)
|
||||
/%{_libdir}/libwebsockets.a
|
||||
/%{_libdir}/pkgconfig/libwebsockets.pc
|
||||
/%{_libdir}/pkgconfig/libwebsockets_static.pc
|
||||
|
||||
%changelog
|
||||
* Mon Mar 06 2017 Andy Green <andy@warmcat.com> 2.2.2-1
|
||||
- MINOR Upstream 2.2.2 release
|
||||
* Fri Jul 28 2017 Andy Green <andy@warmcat.com> 2.3.0-1
|
||||
- MAJOR SONAMEBUMP APICHANGES Upstream 2.3.0 release
|
||||
|
||||
* Mon Mar 06 2017 Andy Green <andy@warmcat.com> 2.2.0-1
|
||||
- MAJOR SONAMEBUMP APICHANGES Upstream 2.2.0 release
|
||||
|
|
|
@ -55,6 +55,9 @@
|
|||
/* Enable libuv io loop */
|
||||
#cmakedefine LWS_USE_LIBUV
|
||||
|
||||
/* Enable libevent io loop */
|
||||
#cmakedefine LWS_USE_LIBEVENT
|
||||
|
||||
/* Build with support for ipv6 */
|
||||
#cmakedefine LWS_USE_IPV6
|
||||
|
||||
|
@ -126,11 +129,26 @@
|
|||
#cmakedefine LWS_WITH_ZIP_FOPS
|
||||
#cmakedefine LWS_HAVE_STDINT_H
|
||||
|
||||
#cmakedefine LWS_AVOID_SIGPIPE_IGN
|
||||
|
||||
#cmakedefine LWS_FALLBACK_GETHOSTBYNAME
|
||||
|
||||
#cmakedefine LWS_WITH_STATS
|
||||
#cmakedefine LWS_WITH_SOCKS5
|
||||
|
||||
#cmakedefine LWS_HAVE_SYS_CAPABILITY_H
|
||||
#cmakedefine LWS_HAVE_LIBCAP
|
||||
|
||||
#cmakedefine LWS_HAVE_ATOLL
|
||||
#cmakedefine LWS_HAVE__ATOI64
|
||||
#cmakedefine LWS_HAVE__STAT32I64
|
||||
|
||||
/* OpenSSL various APIs */
|
||||
|
||||
#cmakedefine LWS_HAVE_TLS_CLIENT_METHOD
|
||||
#cmakedefine LWS_HAVE_TLSV1_2_CLIENT_METHOD
|
||||
#cmakedefine LWS_HAVE_SSL_SET_INFO_CALLBACK
|
||||
|
||||
#cmakedefine LWS_HAS_INTPTR_T
|
||||
|
||||
${LWS_SIZEOFPTR_CODE}
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
# vhost-specific config options for the protocol
|
||||
#
|
||||
"ws-protocols": [{
|
||||
"lws-meta": {
|
||||
"status": "ok"
|
||||
},
|
||||
"dumb-increment-protocol": {
|
||||
"status": "ok"
|
||||
},
|
||||
|
|
10
lwsws/main.c
10
lwsws/main.c
|
@ -58,11 +58,13 @@ static int pids[32];
|
|||
#define LWSWS_CONFIG_STRING_SIZE (32 * 1024)
|
||||
|
||||
static const struct lws_extension exts[] = {
|
||||
#if !defined(LWS_NO_EXTENSIONS)
|
||||
{
|
||||
"permessage-deflate",
|
||||
lws_extension_callback_pm_deflate,
|
||||
"permessage-deflate"
|
||||
},
|
||||
#endif
|
||||
{ NULL, NULL, NULL /* terminator */ }
|
||||
};
|
||||
|
||||
|
@ -199,8 +201,9 @@ reload_handler(int signum)
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int n = 0, m, debug_level = 7;
|
||||
int n = 0, debug_level = 7;
|
||||
#ifndef _WIN32
|
||||
int m;
|
||||
int status, syslog_options = LOG_PID | LOG_PERROR;
|
||||
#endif
|
||||
|
||||
|
@ -302,8 +305,9 @@ int main(int argc, char **argv)
|
|||
lws_context_destroy(context);
|
||||
|
||||
#if (UV_VERSION_MAJOR > 0) // Travis...
|
||||
lws_close_all_handles_in_loop(&loop);
|
||||
n = 0;
|
||||
while (n++ < 1024 && uv_loop_close(&loop))
|
||||
while (n++ < 4096 && uv_loop_close(&loop))
|
||||
uv_run(&loop, UV_RUN_NOWAIT);
|
||||
#endif
|
||||
|
||||
|
@ -315,5 +319,7 @@ int main(int argc, char **argv)
|
|||
closelog();
|
||||
#endif
|
||||
|
||||
context = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -474,7 +474,7 @@ callback_generic_sessions(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
WSI_TOKEN_HOST) < 0)
|
||||
return 1;
|
||||
lws_snprintf(pss->onward, sizeof(pss->onward) - 1,
|
||||
"%s%s%s", oprot[lws_is_ssl(wsi)],
|
||||
"%s%s%s", oprot[!!lws_is_ssl(wsi)],
|
||||
cookie, args->p);
|
||||
lwsl_notice("redirecting to ourselves with cookie refresh\n");
|
||||
/* we need a redirect to ourselves, session cookie is expired */
|
||||
|
|
|
@ -88,7 +88,7 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
case LWS_CALLBACK_PROTOCOL_DESTROY:
|
||||
if (!vhd)
|
||||
break;
|
||||
// lwsl_notice("di: LWS_CALLBACK_PROTOCOL_DESTROY: v=%p, ctx=%p\n", vhd, vhd->context);
|
||||
lwsl_notice("di: LWS_CALLBACK_PROTOCOL_DESTROY: v=%p, ctx=%p\n", vhd, vhd->context);
|
||||
uv_timer_stop(&vhd->timeout_watcher);
|
||||
uv_close((uv_handle_t *)&vhd->timeout_watcher, NULL);
|
||||
break;
|
||||
|
|
239
plugins/protocol_esp32_lws_group.c
Normal file
239
plugins/protocol_esp32_lws_group.c
Normal file
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* ESP32 Group 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*
|
||||
*
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <nvs.h>
|
||||
#include <esp_ota_ops.h>
|
||||
|
||||
typedef enum {
|
||||
GROUP_STATE_NONE,
|
||||
GROUP_STATE_INITIAL,
|
||||
GROUP_STATE_MEMBERS,
|
||||
GROUP_STATE_FINAL
|
||||
} group_state;
|
||||
|
||||
struct per_session_data__lws_group {
|
||||
struct per_session_data__lws_group *next;
|
||||
group_state group_state;
|
||||
|
||||
struct lws_group_member *member;
|
||||
|
||||
unsigned char subsequent:1;
|
||||
unsigned char changed_partway:1;
|
||||
};
|
||||
|
||||
struct per_vhost_data__lws_group {
|
||||
struct per_session_data__lws_group *live_pss_list;
|
||||
struct lws_context *context;
|
||||
struct lws_vhost *vhost;
|
||||
const struct lws_protocols *protocol;
|
||||
int count_live_pss;
|
||||
};
|
||||
|
||||
static void render_ip4(char *dest, int len, uint8_t *ip)
|
||||
{
|
||||
snprintf(dest, len, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
callback_lws_group(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
struct per_session_data__lws_group *pss =
|
||||
(struct per_session_data__lws_group *)user;
|
||||
struct per_vhost_data__lws_group *vhd =
|
||||
(struct per_vhost_data__lws_group *)
|
||||
lws_protocol_vh_priv_get(lws_get_vhost(wsi),
|
||||
lws_get_protocol(wsi));
|
||||
char buffer[1024 + LWS_PRE], ipv4[20];
|
||||
char *start = buffer + LWS_PRE - 1, *p = start,
|
||||
*end = buffer + sizeof(buffer) - 1;
|
||||
struct lws_group_member *mbr;
|
||||
int n, m;
|
||||
|
||||
switch (reason) {
|
||||
|
||||
case LWS_CALLBACK_PROTOCOL_INIT:
|
||||
vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
|
||||
lws_get_protocol(wsi),
|
||||
sizeof(struct per_vhost_data__lws_group));
|
||||
vhd->context = lws_get_context(wsi);
|
||||
vhd->protocol = lws_get_protocol(wsi);
|
||||
vhd->vhost = lws_get_vhost(wsi);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_PROTOCOL_DESTROY:
|
||||
if (!vhd)
|
||||
break;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
lwsl_notice("%s: ESTABLISHED\n", __func__);
|
||||
vhd->count_live_pss++;
|
||||
pss->next = vhd->live_pss_list;
|
||||
vhd->live_pss_list = pss;
|
||||
pss->group_state = GROUP_STATE_INITIAL;
|
||||
lws_callback_on_writable(wsi);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_SERVER_WRITEABLE:
|
||||
|
||||
switch (pss->group_state) {
|
||||
|
||||
case GROUP_STATE_NONE:
|
||||
/* fallthru */
|
||||
|
||||
case GROUP_STATE_INITIAL:
|
||||
|
||||
p += snprintf((char *)p, end - p,
|
||||
"{\n"
|
||||
" \"group\":\"%s\","
|
||||
" \"members\":[\n",
|
||||
lws_esp32.group);
|
||||
|
||||
n = LWS_WRITE_TEXT | LWS_WRITE_NO_FIN;
|
||||
pss->group_state = GROUP_STATE_MEMBERS;
|
||||
pss->subsequent = 0;
|
||||
pss->changed_partway = 0;
|
||||
pss->member = lws_esp32.first;
|
||||
break;
|
||||
|
||||
case GROUP_STATE_MEMBERS:
|
||||
|
||||
/* confirm pss->member is still in the list... */
|
||||
|
||||
mbr = lws_esp32.first;
|
||||
while (mbr && mbr != pss->member)
|
||||
mbr = mbr->next;
|
||||
|
||||
if (!mbr) { /* no longer exists... */
|
||||
if (lws_esp32.first || pss->member)
|
||||
pss->changed_partway = 1;
|
||||
*p++ = ' ';
|
||||
pss->member = NULL;
|
||||
|
||||
/*
|
||||
* finish the list where we got to, then
|
||||
* immediately reissue it
|
||||
*/
|
||||
}
|
||||
|
||||
while (end - p > 100 && pss->member) {
|
||||
|
||||
if (pss->subsequent)
|
||||
*p++ = ',';
|
||||
|
||||
pss->subsequent = 1;
|
||||
render_ip4(ipv4, sizeof(ipv4), (uint8_t *)&pss->member->addr);
|
||||
|
||||
p += snprintf((char *)p, end - p,
|
||||
" {\n"
|
||||
" \"mac\":\"%s\",\n"
|
||||
" \"model\":\"%s\",\n"
|
||||
" \"role\":\"%s\",\n"
|
||||
" \"width\":\"%d\",\n"
|
||||
" \"height\":\"%d\",\n"
|
||||
" \"ipv4\":\"%s\"\n"
|
||||
" }\n",
|
||||
pss->member->mac,
|
||||
pss->member->model,
|
||||
pss->member->role,
|
||||
pss->member->width,
|
||||
pss->member->height,
|
||||
ipv4
|
||||
);
|
||||
pss->member = pss->member->next;
|
||||
}
|
||||
|
||||
lwsl_notice("%s\n", p);
|
||||
|
||||
n = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN;
|
||||
if (!pss->member)
|
||||
pss->group_state = GROUP_STATE_FINAL;
|
||||
break;
|
||||
|
||||
case GROUP_STATE_FINAL:
|
||||
n = LWS_WRITE_CONTINUATION;
|
||||
p += sprintf((char *)p, "],\n \"discard\":\"%d\"}\n",
|
||||
pss->changed_partway);
|
||||
if (pss->changed_partway)
|
||||
pss->group_state = GROUP_STATE_INITIAL;
|
||||
else
|
||||
pss->group_state = GROUP_STATE_NONE;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
// lwsl_notice("issue: %d (%d)\n", p - start, n);
|
||||
m = lws_write(wsi, (unsigned char *)start, p - start, n);
|
||||
if (m < 0) {
|
||||
lwsl_err("ERROR %d writing to di socket\n", m);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pss->group_state != GROUP_STATE_NONE)
|
||||
lws_callback_on_writable(wsi);
|
||||
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RECEIVE:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case LWS_CALLBACK_CLOSED:
|
||||
{
|
||||
struct per_session_data__lws_group **p = &vhd->live_pss_list;
|
||||
|
||||
while (*p) {
|
||||
if ((*p) == pss) {
|
||||
*p = pss->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
p = &((*p)->next);
|
||||
}
|
||||
|
||||
vhd->count_live_pss--;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
|
||||
/* called when our wsi user_space is going to be destroyed */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define LWS_PLUGIN_PROTOCOL_LWS_GROUP \
|
||||
{ \
|
||||
"lws-group", \
|
||||
callback_lws_group, \
|
||||
sizeof(struct per_session_data__lws_group), \
|
||||
1024, 0, NULL, 900 \
|
||||
}
|
||||
|
279
plugins/protocol_esp32_lws_ota.c
Normal file
279
plugins/protocol_esp32_lws_ota.c
Normal file
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* ESP32 OTA update 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
|
||||
*
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <esp_partition.h>
|
||||
#include <esp_ota_ops.h>
|
||||
#include <nvs.h>
|
||||
|
||||
struct per_session_data__esplws_ota {
|
||||
struct lws_spa *spa;
|
||||
char filename[32];
|
||||
char result[LWS_PRE + 512];
|
||||
int result_len;
|
||||
int filename_length;
|
||||
esp_ota_handle_t otahandle;
|
||||
const esp_partition_t *part;
|
||||
long file_length;
|
||||
nvs_handle nvh;
|
||||
TimerHandle_t reboot_timer;
|
||||
};
|
||||
|
||||
struct per_vhost_data__esplws_ota {
|
||||
struct lws_context *context;
|
||||
struct lws_vhost *vhost;
|
||||
const struct lws_protocols *protocol;
|
||||
};
|
||||
|
||||
static const char * const ota_param_names[] = {
|
||||
"upload",
|
||||
};
|
||||
|
||||
enum enum_ota_param_names {
|
||||
EPN_UPLOAD,
|
||||
};
|
||||
|
||||
static void ota_reboot_timer_cb(TimerHandle_t t)
|
||||
{
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
const esp_partition_t *
|
||||
ota_choose_part(void)
|
||||
{
|
||||
const esp_partition_t *bootpart, *part = NULL;
|
||||
esp_partition_iterator_t i;
|
||||
|
||||
bootpart = lws_esp_ota_get_boot_partition();
|
||||
i = esp_partition_find(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL);
|
||||
while (i) {
|
||||
part = esp_partition_get(i);
|
||||
|
||||
/* cannot update ourselves */
|
||||
if (part == bootpart)
|
||||
goto next;
|
||||
|
||||
if (part->subtype < ESP_PARTITION_SUBTYPE_APP_OTA_MIN ||
|
||||
part->subtype >= ESP_PARTITION_SUBTYPE_APP_OTA_MIN +
|
||||
ESP_PARTITION_SUBTYPE_APP_OTA_MAX)
|
||||
goto next;
|
||||
|
||||
break;
|
||||
|
||||
next:
|
||||
i = esp_partition_next(i);
|
||||
}
|
||||
|
||||
if (!i) {
|
||||
lwsl_err("Can't find good OTA part\n");
|
||||
return NULL;
|
||||
}
|
||||
lwsl_notice("Directing OTA to part type %d/%d start 0x%x\n",
|
||||
part->type, part->subtype,
|
||||
(uint32_t)part->address);
|
||||
|
||||
return part;
|
||||
}
|
||||
|
||||
static int
|
||||
ota_file_upload_cb(void *data, const char *name, const char *filename,
|
||||
char *buf, int len, enum lws_spa_fileupload_states state)
|
||||
{
|
||||
struct per_session_data__esplws_ota *pss =
|
||||
(struct per_session_data__esplws_ota *)data;
|
||||
|
||||
switch (state) {
|
||||
case LWS_UFS_OPEN:
|
||||
lwsl_notice("LWS_UFS_OPEN Filename %s\n", filename);
|
||||
strncpy(pss->filename, filename, sizeof(pss->filename) - 1);
|
||||
if (strcmp(name, "ota"))
|
||||
return 1;
|
||||
|
||||
pss->part = ota_choose_part();
|
||||
if (!pss->part)
|
||||
return 1;
|
||||
|
||||
if (esp_ota_begin(pss->part, (long)-1, &pss->otahandle) != ESP_OK) {
|
||||
lwsl_err("OTA: Failed to begin\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
pss->file_length = 0;
|
||||
break;
|
||||
|
||||
case LWS_UFS_FINAL_CONTENT:
|
||||
case LWS_UFS_CONTENT:
|
||||
if (pss->file_length + len > pss->part->size) {
|
||||
lwsl_err("OTA: incoming file too large\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
lwsl_debug("writing 0x%lx... 0x%lx\n",
|
||||
pss->part->address + pss->file_length,
|
||||
pss->part->address + pss->file_length + len);
|
||||
if (esp_ota_write(pss->otahandle, buf, len) != ESP_OK) {
|
||||
lwsl_err("OTA: Failed to write\n");
|
||||
return 1;
|
||||
}
|
||||
pss->file_length += len;
|
||||
|
||||
if (state == LWS_UFS_CONTENT)
|
||||
break;
|
||||
|
||||
lwsl_notice("LWS_UFS_FINAL_CONTENT\n");
|
||||
if (esp_ota_end(pss->otahandle) != ESP_OK) {
|
||||
lwsl_err("OTA: end failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (esp_ota_set_boot_partition(pss->part) != ESP_OK) {
|
||||
lwsl_err("OTA: set boot part failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
pss->reboot_timer = xTimerCreate("x", pdMS_TO_TICKS(250), 0, NULL,
|
||||
ota_reboot_timer_cb);
|
||||
xTimerStart(pss->reboot_timer, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
callback_esplws_ota(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
struct per_session_data__esplws_ota *pss =
|
||||
(struct per_session_data__esplws_ota *)user;
|
||||
struct per_vhost_data__esplws_ota *vhd =
|
||||
(struct per_vhost_data__esplws_ota *)
|
||||
lws_protocol_vh_priv_get(lws_get_vhost(wsi),
|
||||
lws_get_protocol(wsi));
|
||||
unsigned char buf[LWS_PRE + 384], *start = buf + LWS_PRE - 1, *p = start,
|
||||
*end = buf + sizeof(buf) - 1;
|
||||
int n;
|
||||
|
||||
switch (reason) {
|
||||
|
||||
case LWS_CALLBACK_PROTOCOL_INIT:
|
||||
vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
|
||||
lws_get_protocol(wsi),
|
||||
sizeof(struct per_vhost_data__esplws_ota));
|
||||
vhd->context = lws_get_context(wsi);
|
||||
vhd->protocol = lws_get_protocol(wsi);
|
||||
vhd->vhost = lws_get_vhost(wsi);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_PROTOCOL_DESTROY:
|
||||
if (!vhd)
|
||||
break;
|
||||
break;
|
||||
|
||||
/* OTA POST handling */
|
||||
|
||||
case LWS_CALLBACK_HTTP_BODY:
|
||||
/* create the POST argument parser if not already existing */
|
||||
//lwsl_notice("LWS_CALLBACK_HTTP_BODY (ota) %d %d %p\n", (int)pss->file_length, (int)len, pss->spa);
|
||||
if (!pss->spa) {
|
||||
pss->spa = lws_spa_create(wsi, ota_param_names,
|
||||
ARRAY_SIZE(ota_param_names), 4096,
|
||||
ota_file_upload_cb, pss);
|
||||
if (!pss->spa)
|
||||
return -1;
|
||||
|
||||
pss->filename[0] = '\0';
|
||||
pss->file_length = 0;
|
||||
}
|
||||
|
||||
/* let it parse the POST data */
|
||||
if (lws_spa_process(pss->spa, in, len))
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_HTTP_BODY_COMPLETION:
|
||||
lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION (ota)\n");
|
||||
/* call to inform no more payload data coming */
|
||||
lws_spa_finalize(pss->spa);
|
||||
|
||||
pss->result_len = snprintf(pss->result + LWS_PRE, sizeof(pss->result) - LWS_PRE - 1,
|
||||
"Rebooting after OTA update");
|
||||
|
||||
if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
|
||||
goto bail;
|
||||
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
|
||||
(unsigned char *)"text/html", 9, &p, end))
|
||||
goto bail;
|
||||
if (lws_add_http_header_content_length(wsi, pss->result_len, &p, end))
|
||||
goto bail;
|
||||
if (lws_finalize_http_header(wsi, &p, end))
|
||||
goto bail;
|
||||
|
||||
n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
|
||||
if (n < 0)
|
||||
goto bail;
|
||||
|
||||
lws_callback_on_writable(wsi);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_HTTP_WRITEABLE:
|
||||
lwsl_debug("LWS_CALLBACK_HTTP_WRITEABLE: sending %d\n",
|
||||
pss->result_len);
|
||||
n = lws_write(wsi, (unsigned char *)pss->result + LWS_PRE,
|
||||
pss->result_len, LWS_WRITE_HTTP);
|
||||
if (n < 0)
|
||||
return 1;
|
||||
|
||||
if (lws_http_transaction_completed(wsi))
|
||||
return 1;
|
||||
|
||||
/* stop further service so we don't serve the probe GET to see if we rebooted */
|
||||
while (1);
|
||||
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
|
||||
/* called when our wsi user_space is going to be destroyed */
|
||||
if (pss->spa) {
|
||||
lws_spa_destroy(pss->spa);
|
||||
pss->spa = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define LWS_PLUGIN_PROTOCOL_ESPLWS_OTA \
|
||||
{ \
|
||||
"esplws-ota", \
|
||||
callback_esplws_ota, \
|
||||
sizeof(struct per_session_data__esplws_ota), \
|
||||
4096, 0, NULL, 900 \
|
||||
}
|
||||
|
58
plugins/protocol_esp32_lws_reboot_to_factory.c
Normal file
58
plugins/protocol_esp32_lws_reboot_to_factory.c
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Example ESP32 app code using Libwebsockets
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* This is intended to be mounted somewhere in your ESP32 user app... if the
|
||||
* client touched the mount, the plugin hangs up and reboots into the
|
||||
* factory mode one second later.
|
||||
*
|
||||
* The factory mode will reassociate with the same IP with the same MAC
|
||||
* shortly afterwards and be accessible by the same IP / mDNS name.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <esp_partition.h>
|
||||
#include <esp_ota_ops.h>
|
||||
#include <nvs.h>
|
||||
|
||||
static int
|
||||
callback_esplws_rtf(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
switch (reason) {
|
||||
|
||||
case LWS_CALLBACK_HTTP:
|
||||
|
||||
lws_esp32_restart_guided(LWS_MAGIC_REBOOT_TYPE_REQ_FACTORY);
|
||||
return 1;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define LWS_PLUGIN_PROTOCOL_ESPLWS_RTF \
|
||||
{ \
|
||||
"esplws-rtf", \
|
||||
callback_esplws_rtf, \
|
||||
0, \
|
||||
10, 0, NULL, 0 \
|
||||
}
|
||||
|
|
@ -1,29 +1,33 @@
|
|||
/*
|
||||
* Example ESP32 app code using Libwebsockets
|
||||
* ESP32 Scan / Factory protocol handler
|
||||
*
|
||||
* Copyright (C) 2017 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
* 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.
|
||||
*
|
||||
* The person who associated a work with this deed has dedicated
|
||||
* the work to the public domain by waiving all of his or her rights
|
||||
* to the work worldwide under copyright law, including all related
|
||||
* and neighboring rights, to the extent allowed by law. You can copy,
|
||||
* modify, distribute and perform the work, even for commercial purposes,
|
||||
* all without asking permission.
|
||||
* 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.
|
||||
*
|
||||
* The test apps are intended to be adapted for use in your code, which
|
||||
* may be proprietary. So unlike the library itself, they are licensed
|
||||
* Public Domain.
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA*
|
||||
*
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <nvs.h>
|
||||
#include <esp_ota_ops.h>
|
||||
|
||||
typedef enum {
|
||||
SCAN_STATE_NONE,
|
||||
SCAN_STATE_INITIAL,
|
||||
SCAN_STATE_INITIAL_MANIFEST,
|
||||
SCAN_STATE_KNOWN,
|
||||
SCAN_STATE_LIST,
|
||||
SCAN_STATE_FINAL
|
||||
} scan_state;
|
||||
|
@ -36,29 +40,62 @@ struct store_json {
|
|||
struct per_session_data__esplws_scan {
|
||||
struct per_session_data__esplws_scan *next;
|
||||
scan_state scan_state;
|
||||
struct timeval last_send;
|
||||
|
||||
struct lws_spa *spa;
|
||||
char filename[32];
|
||||
char result[LWS_PRE + 512];
|
||||
unsigned char buffer[4096];
|
||||
int result_len;
|
||||
int filename_length;
|
||||
long file_length;
|
||||
nvs_handle nvh;
|
||||
|
||||
char ap_record;
|
||||
unsigned char subsequent:1;
|
||||
unsigned char changed_partway:1;
|
||||
};
|
||||
|
||||
struct per_vhost_data__esplws_scan {
|
||||
wifi_ap_record_t ap_records[20];
|
||||
TimerHandle_t timer;
|
||||
wifi_ap_record_t ap_records[10];
|
||||
TimerHandle_t timer, reboot_timer;
|
||||
struct per_session_data__esplws_scan *live_pss_list;
|
||||
struct lws_context *context;
|
||||
struct lws_vhost *vhost;
|
||||
const struct lws_protocols *protocol;
|
||||
|
||||
const esp_partition_t *part;
|
||||
esp_ota_handle_t otahandle;
|
||||
long file_length;
|
||||
long content_length;
|
||||
|
||||
struct lws *cwsi;
|
||||
char json[1024];
|
||||
int json_len;
|
||||
|
||||
uint16_t count_ap_records;
|
||||
char count_live_pss;
|
||||
unsigned char scan_ongoing:1;
|
||||
unsigned char completed_any_scan:1;
|
||||
unsigned char reboot:1;
|
||||
unsigned char changed_settings:1;
|
||||
unsigned char checked_updates:1;
|
||||
unsigned char autonomous_update:1;
|
||||
unsigned char autonomous_update_sampled:1;
|
||||
};
|
||||
|
||||
static const struct store_json store_json[] = {
|
||||
{ "ssid\":\"", "ssid" },
|
||||
{ ",\"pw\":\"", "password" },
|
||||
{ ",\"serial\":\"", "serial" },
|
||||
{ "\"ssid0\":\"", "0ssid" },
|
||||
{ ",\"pw0\":\"", "0password" },
|
||||
{ "\"ssid1\":\"", "1ssid" },
|
||||
{ ",\"pw1\":\"", "1password" },
|
||||
{ "\"ssid2\":\"", "2ssid" },
|
||||
{ ",\"pw2\":\"", "2password" },
|
||||
{ "\"ssid3\":\"", "3ssid" },
|
||||
{ ",\"pw3\":\"", "3password" },
|
||||
{ ",\"access_pw\":\"", "access_pw" },
|
||||
{ "{\"group\":\"", "group" },
|
||||
{ "{\"role\":\"", "role" },
|
||||
{ ",\"region\":\"", "region" },
|
||||
};
|
||||
|
||||
|
@ -69,12 +106,28 @@ static wifi_scan_config_t scan_config = {
|
|||
.show_hidden = true
|
||||
};
|
||||
|
||||
extern void (*lws_cb_scan_done)(void *);
|
||||
extern void *lws_cb_scan_done_arg;
|
||||
const esp_partition_t *
|
||||
ota_choose_part(void);
|
||||
|
||||
static const char * const param_names[] = {
|
||||
"text",
|
||||
"pub",
|
||||
"pri",
|
||||
"serial",
|
||||
"opts",
|
||||
};
|
||||
|
||||
enum enum_param_names {
|
||||
EPN_TEXT,
|
||||
EPN_PUB,
|
||||
EPN_PRI,
|
||||
EPN_SERIAL,
|
||||
EPN_OPTS,
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
scan_finished(void *v);
|
||||
scan_finished(uint16_t count, wifi_ap_record_t *recs, void *v);
|
||||
|
||||
static int
|
||||
esplws_simple_arg(char *dest, int len, const char *in, const char *match)
|
||||
|
@ -82,10 +135,8 @@ esplws_simple_arg(char *dest, int len, const char *in, const char *match)
|
|||
const char *p = strstr(in, match);
|
||||
int n = 0;
|
||||
|
||||
if (!p) {
|
||||
lwsl_err("No match %s\n", match);
|
||||
if (!p)
|
||||
return 1;
|
||||
}
|
||||
|
||||
p += strlen(match);
|
||||
while (*p && *p != '\"' && n < len - 1)
|
||||
|
@ -107,8 +158,8 @@ scan_start(struct per_vhost_data__esplws_scan *vhd)
|
|||
return;
|
||||
|
||||
vhd->scan_ongoing = 1;
|
||||
lws_cb_scan_done = scan_finished;
|
||||
lws_cb_scan_done_arg = vhd;
|
||||
lws_esp32.scan_consumer = scan_finished;
|
||||
lws_esp32.scan_consumer_arg = vhd;
|
||||
n = esp_wifi_scan_start(&scan_config, false);
|
||||
if (n != ESP_OK)
|
||||
lwsl_err("scan start failed %d\n", n);
|
||||
|
@ -121,19 +172,62 @@ static void timer_cb(TimerHandle_t t)
|
|||
scan_start(vhd);
|
||||
}
|
||||
|
||||
static void reboot_timer_cb(TimerHandle_t t)
|
||||
{
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
static int
|
||||
client_connection(struct per_vhost_data__esplws_scan *vhd, const char *file)
|
||||
{
|
||||
#if CONFIG_LWS_IS_FACTORY_APPLICATION == 'y' && defined(CONFIG_LWS_OTA_SERVER_BASE_URL) && \
|
||||
defined(CONFIG_LWS_OTA_SERVER_FQDN)
|
||||
static struct lws_client_connect_info i;
|
||||
char path[256];
|
||||
|
||||
memset(&i, 0, sizeof i);
|
||||
|
||||
snprintf(path, sizeof(path) - 1, CONFIG_LWS_OTA_SERVER_BASE_URL "/" CONFIG_LWS_MODEL_NAME "/%s", file);
|
||||
|
||||
lwsl_notice("Fetching %s\n", path);
|
||||
|
||||
i.port = 443;
|
||||
i.context = vhd->context;
|
||||
i.address = CONFIG_LWS_OTA_SERVER_FQDN;
|
||||
i.ssl_connection = 1;
|
||||
i.host = i.address;
|
||||
i.origin = i.host;
|
||||
i.vhost = vhd->vhost;
|
||||
i.method = "GET";
|
||||
i.path = path;
|
||||
i.protocol = "esplws-scan";
|
||||
i.pwsi = &vhd->cwsi;
|
||||
|
||||
vhd->cwsi = lws_client_connect_via_info(&i);
|
||||
if (!vhd->cwsi) {
|
||||
lwsl_notice("NULL return\n");
|
||||
return 1; /* fail */
|
||||
}
|
||||
#endif
|
||||
return 0; /* ongoing */
|
||||
}
|
||||
|
||||
static void
|
||||
scan_finished(void *v)
|
||||
scan_finished(uint16_t count, wifi_ap_record_t *recs, void *v)
|
||||
{
|
||||
struct per_vhost_data__esplws_scan *vhd = v;
|
||||
struct per_session_data__esplws_scan *p = vhd->live_pss_list;
|
||||
|
||||
lwsl_notice("%s: count %d\n", __func__, count);
|
||||
|
||||
vhd->scan_ongoing = 0;
|
||||
|
||||
vhd->count_ap_records = ARRAY_SIZE(vhd->ap_records);
|
||||
if (esp_wifi_scan_get_ap_records(&vhd->count_ap_records, vhd->ap_records) != ESP_OK) {
|
||||
lwsl_err("%s: failed\n", __func__);
|
||||
return;
|
||||
}
|
||||
if (count < ARRAY_SIZE(vhd->ap_records))
|
||||
vhd->count_ap_records = count;
|
||||
else
|
||||
vhd->count_ap_records = ARRAY_SIZE(vhd->ap_records);
|
||||
|
||||
memcpy(vhd->ap_records, recs, vhd->count_ap_records * sizeof(*recs));
|
||||
|
||||
while (p) {
|
||||
if (p->scan_state != SCAN_STATE_INITIAL && p->scan_state != SCAN_STATE_NONE)
|
||||
|
@ -144,6 +238,70 @@ scan_finished(void *v)
|
|||
}
|
||||
|
||||
lws_callback_on_writable_all_protocol(vhd->context, vhd->protocol);
|
||||
|
||||
if (lws_esp32.inet && !vhd->cwsi && !vhd->checked_updates)
|
||||
client_connection(vhd, "manifest.json");
|
||||
|
||||
if (vhd->changed_settings) {
|
||||
lws_esp32_wlan_nvs_get(1);
|
||||
vhd->changed_settings = 0;
|
||||
} else
|
||||
esp_wifi_connect();
|
||||
}
|
||||
|
||||
static const char *ssl_names[] = { "ssl-pub.pem", "ssl-pri.pem" };
|
||||
|
||||
static int
|
||||
file_upload_cb(void *data, const char *name, const char *filename,
|
||||
char *buf, int len, enum lws_spa_fileupload_states state)
|
||||
{
|
||||
struct per_session_data__esplws_scan *pss =
|
||||
(struct per_session_data__esplws_scan *)data;
|
||||
int n;
|
||||
|
||||
switch (state) {
|
||||
case LWS_UFS_OPEN:
|
||||
if (lws_esp32_get_reboot_type() != LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON)
|
||||
return -1;
|
||||
|
||||
lwsl_notice("LWS_UFS_OPEN Filename %s\n", filename);
|
||||
strncpy(pss->filename, filename, sizeof(pss->filename) - 1);
|
||||
if (!strcmp(name, "pub") || !strcmp(name, "pri")) {
|
||||
if (nvs_open("lws-station", NVS_READWRITE, &pss->nvh))
|
||||
return 1;
|
||||
} else
|
||||
return 1;
|
||||
pss->file_length = 0;
|
||||
break;
|
||||
|
||||
case LWS_UFS_FINAL_CONTENT:
|
||||
case LWS_UFS_CONTENT:
|
||||
if (len) {
|
||||
/* if the file length is too big, drop it */
|
||||
if (pss->file_length + len > sizeof(pss->buffer))
|
||||
return 1;
|
||||
|
||||
memcpy(pss->buffer + pss->file_length, buf, len);
|
||||
}
|
||||
pss->file_length += len;
|
||||
|
||||
if (state == LWS_UFS_CONTENT)
|
||||
break;
|
||||
|
||||
lwsl_notice("LWS_UFS_FINAL_CONTENT\n");
|
||||
n = 0;
|
||||
if (!strcmp(name, "pri"))
|
||||
n = 1;
|
||||
n = nvs_set_blob(pss->nvh, ssl_names[n], pss->buffer, pss->file_length);
|
||||
if (n == ESP_OK)
|
||||
nvs_commit(pss->nvh);
|
||||
nvs_close(pss->nvh);
|
||||
if (n != ESP_OK)
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -156,10 +314,13 @@ callback_esplws_scan(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
(struct per_vhost_data__esplws_scan *)
|
||||
lws_protocol_vh_priv_get(lws_get_vhost(wsi),
|
||||
lws_get_protocol(wsi));
|
||||
char buf[LWS_PRE + 384], /*ip[24],*/ *start = buf + LWS_PRE - 1, *p = start,
|
||||
*end = buf + sizeof(buf) - 1;
|
||||
unsigned char *start = pss->buffer + LWS_PRE - 1, *p = start,
|
||||
*end = pss->buffer + sizeof(pss->buffer) - 1;
|
||||
wifi_ap_record_t *r;
|
||||
int n, m;
|
||||
nvs_handle nvh;
|
||||
size_t s;
|
||||
|
||||
|
||||
switch (reason) {
|
||||
|
||||
|
@ -172,8 +333,8 @@ callback_esplws_scan(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
vhd->vhost = lws_get_vhost(wsi);
|
||||
vhd->timer = xTimerCreate("x", pdMS_TO_TICKS(10000), 1, vhd,
|
||||
(TimerCallbackFunction_t)timer_cb);
|
||||
xTimerStart(vhd->timer, 0);
|
||||
vhd->scan_ongoing = 0;
|
||||
strcpy(vhd->json, " { }");
|
||||
scan_start(vhd);
|
||||
break;
|
||||
|
||||
|
@ -185,6 +346,11 @@ callback_esplws_scan(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
break;
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
lwsl_notice("%s: ESTABLISHED\n", __func__);
|
||||
if (!vhd->live_pss_list) {
|
||||
scan_start(vhd);
|
||||
xTimerStart(vhd->timer, 0);
|
||||
}
|
||||
vhd->count_live_pss++;
|
||||
pss->next = vhd->live_pss_list;
|
||||
vhd->live_pss_list = pss;
|
||||
|
@ -196,61 +362,207 @@ callback_esplws_scan(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
break;
|
||||
|
||||
case LWS_CALLBACK_SERVER_WRITEABLE:
|
||||
|
||||
if (vhd->autonomous_update_sampled) {
|
||||
p += snprintf((char *)p, end - p,
|
||||
" {\n \"auton\":\"1\",\n \"pos\": \"%ld\",\n"
|
||||
" \"len\":\"%ld\"\n}\n",
|
||||
vhd->file_length,
|
||||
vhd->content_length);
|
||||
|
||||
n = LWS_WRITE_TEXT;
|
||||
goto issue;
|
||||
}
|
||||
|
||||
switch (pss->scan_state) {
|
||||
struct timeval t;
|
||||
uint8_t mac[6];
|
||||
struct lws_esp32_image i;
|
||||
char img_factory[512], img_ota[512], group[16], role[16];
|
||||
int grt;
|
||||
|
||||
case SCAN_STATE_INITIAL:
|
||||
n = LWS_WRITE_TEXT | LWS_WRITE_NO_FIN;;
|
||||
p += snprintf(p, end - p,
|
||||
"{ \"model\":\"%s\","
|
||||
" \"serial\":\"%s\","
|
||||
" \"host\":\"%s-%s\","
|
||||
" \"region\":\"%d\","
|
||||
" \"aps\":[",
|
||||
lws_esp32_model,
|
||||
lws_esp32_serial,
|
||||
lws_esp32_model, lws_esp32_serial,
|
||||
lws_esp32_region);
|
||||
pss->scan_state = SCAN_STATE_LIST;
|
||||
|
||||
gettimeofday(&t, NULL);
|
||||
if (t.tv_sec - pss->last_send.tv_sec < 10)
|
||||
return 0;
|
||||
|
||||
pss->last_send = t;
|
||||
|
||||
if (nvs_open("lws-station", NVS_READWRITE, &nvh)) {
|
||||
lwsl_err("unable to open nvs\n");
|
||||
return -1;
|
||||
}
|
||||
n = 0;
|
||||
if (nvs_get_blob(nvh, "ssl-pub.pem", NULL, &s) == ESP_OK)
|
||||
n = 1;
|
||||
if (nvs_get_blob(nvh, "ssl-pri.pem", NULL, &s) == ESP_OK)
|
||||
n |= 2;
|
||||
s = sizeof(group) - 1;
|
||||
group[0] = '\0';
|
||||
role[0] = '\0';
|
||||
nvs_get_str(nvh, "group", group, &s);
|
||||
nvs_get_str(nvh, "role", role, &s);
|
||||
|
||||
nvs_close(nvh);
|
||||
|
||||
/*
|
||||
* this value in the JSON is just
|
||||
* used for UI indication. Each conditional feature confirms
|
||||
* it itself before it allows itself to be used.
|
||||
*/
|
||||
|
||||
grt = lws_esp32_get_reboot_type();
|
||||
|
||||
esp_efuse_mac_get_default(mac);
|
||||
strcpy(img_factory, " { \"date\": \"Empty\" }");
|
||||
strcpy(img_ota, " { \"date\": \"Empty\" }");
|
||||
|
||||
lws_esp32_get_image_info(esp_partition_find_first(ESP_PARTITION_TYPE_APP,
|
||||
ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL), &i,
|
||||
img_factory, sizeof(img_factory));
|
||||
lws_esp32_get_image_info(esp_partition_find_first(ESP_PARTITION_TYPE_APP,
|
||||
ESP_PARTITION_SUBTYPE_APP_OTA_0, NULL), &i,
|
||||
img_ota, sizeof(img_ota));
|
||||
|
||||
p += snprintf((char *)p, end - p,
|
||||
"{ \"model\":\"%s\",\n"
|
||||
" \"forced_button\":\"%d\",\n"
|
||||
" \"serial\":\"%s\",\n"
|
||||
" \"opts\":\"%s\",\n"
|
||||
" \"host\":\"%s-%s\",\n"
|
||||
" \"region\":\"%d\",\n"
|
||||
" \"ssl_pub\":\"%d\",\n"
|
||||
" \"ssl_pri\":\"%d\",\n"
|
||||
" \"mac\":\"%02X%02X%02X%02X%02X%02X\",\n"
|
||||
" \"ssid\":\"%s\",\n"
|
||||
" \"conn_ip\":\"%s\",\n"
|
||||
" \"conn_mask\":\"%s\",\n"
|
||||
" \"conn_gw\":\"%s\",\n"
|
||||
" \"group\":\"%s\",\n"
|
||||
" \"role\":\"%s\",\n"
|
||||
" \"img_factory\": %s,\n"
|
||||
" \"img_ota\": %s,\n",
|
||||
lws_esp32.model,
|
||||
grt == LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON,
|
||||
lws_esp32.serial,
|
||||
lws_esp32.opts,
|
||||
lws_esp32.model, lws_esp32.serial,
|
||||
lws_esp32.region,
|
||||
n & 1, (n >> 1) & 1,
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] | 1,
|
||||
lws_esp32.active_ssid,
|
||||
lws_esp32.sta_ip,
|
||||
lws_esp32.sta_mask,
|
||||
lws_esp32.sta_gw,
|
||||
group, role,
|
||||
img_factory,
|
||||
img_ota
|
||||
);
|
||||
|
||||
n = LWS_WRITE_TEXT | LWS_WRITE_NO_FIN;
|
||||
pss->scan_state = SCAN_STATE_INITIAL_MANIFEST;
|
||||
pss->ap_record = 0;
|
||||
pss->subsequent = 0;
|
||||
break;
|
||||
case SCAN_STATE_LIST:
|
||||
|
||||
case SCAN_STATE_INITIAL_MANIFEST:
|
||||
p += snprintf((char *)p, end - p,
|
||||
" \"latest\": %s,\n"
|
||||
" \"inet\":\"%d\",\n",
|
||||
vhd->json,
|
||||
lws_esp32.inet
|
||||
);
|
||||
|
||||
p += snprintf((char *)p, end - p,
|
||||
" \"known\":[\n");
|
||||
|
||||
n = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN;
|
||||
if (pss->ap_record >= vhd->count_ap_records)
|
||||
goto scan_state_final;
|
||||
pss->scan_state = SCAN_STATE_KNOWN;
|
||||
break;
|
||||
|
||||
if (pss->subsequent)
|
||||
*p++ = ',';
|
||||
pss->subsequent = 1;
|
||||
case SCAN_STATE_KNOWN:
|
||||
if (nvs_open("lws-station", NVS_READONLY, &nvh)) {
|
||||
lwsl_notice("unable to open nvh\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = &vhd->ap_records[(int)pss->ap_record++];
|
||||
p += snprintf(p, end - p,
|
||||
"{\"ssid\":\"%s\","
|
||||
"\"bssid\":\"%02X:%02X:%02X:%02X:%02X:%02X\","
|
||||
"\"rssi\":\"%d\","
|
||||
"\"chan\":\"%d\","
|
||||
"\"auth\":\"%d\"}",
|
||||
r->ssid,
|
||||
r->bssid[0], r->bssid[1], r->bssid[2],
|
||||
r->bssid[3], r->bssid[4], r->bssid[5],
|
||||
r->rssi, r->primary, r->authmode);
|
||||
if (pss->ap_record >= vhd->count_ap_records)
|
||||
pss->scan_state = SCAN_STATE_FINAL;
|
||||
for (m = 0; m < 4; m++) {
|
||||
char name[10], ssid[32];
|
||||
unsigned int pp = 0, use = 0;
|
||||
|
||||
if (m)
|
||||
*p++ = ',';
|
||||
|
||||
s = sizeof(ssid) - 1;
|
||||
ssid[0] = '\0';
|
||||
lws_snprintf(name, sizeof(name) - 1, "%dssid", m);
|
||||
nvs_get_str(nvh, name, ssid, &s);
|
||||
lws_snprintf(name, sizeof(name) - 1, "%dpassword", m);
|
||||
s = 10;
|
||||
nvs_get_str(nvh, name, NULL, &s);
|
||||
pp = !!s;
|
||||
lws_snprintf(name, sizeof(name) - 1, "%duse", m);
|
||||
nvs_get_u32(nvh, name, &use);
|
||||
|
||||
p += snprintf((char *)p, end - p,
|
||||
"{\"ssid\":\"%s\",\n"
|
||||
" \"pp\":\"%u\",\n"
|
||||
"\"use\":\"%u\"}\n",
|
||||
ssid, pp, use);
|
||||
}
|
||||
nvs_close(nvh);
|
||||
|
||||
p += snprintf((char *)p, end - p,
|
||||
"], \"aps\":[\n");
|
||||
|
||||
n = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN;
|
||||
pss->scan_state = SCAN_STATE_LIST;
|
||||
break;
|
||||
|
||||
case SCAN_STATE_LIST:
|
||||
for (m = 0; m < 6; m++) {
|
||||
n = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN;
|
||||
if (pss->ap_record >= vhd->count_ap_records)
|
||||
goto scan_state_final;
|
||||
|
||||
if (pss->subsequent)
|
||||
*p++ = ',';
|
||||
pss->subsequent = 1;
|
||||
|
||||
r = &vhd->ap_records[(int)pss->ap_record++];
|
||||
p += snprintf((char *)p, end - p,
|
||||
"{\"ssid\":\"%s\",\n"
|
||||
"\"bssid\":\"%02X:%02X:%02X:%02X:%02X:%02X\",\n"
|
||||
"\"rssi\":\"%d\",\n"
|
||||
"\"chan\":\"%d\",\n"
|
||||
"\"auth\":\"%d\"}\n",
|
||||
r->ssid,
|
||||
r->bssid[0], r->bssid[1], r->bssid[2],
|
||||
r->bssid[3], r->bssid[4], r->bssid[5],
|
||||
r->rssi, r->primary, r->authmode);
|
||||
if (pss->ap_record >= vhd->count_ap_records)
|
||||
pss->scan_state = SCAN_STATE_FINAL;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCAN_STATE_FINAL:
|
||||
scan_state_final:
|
||||
n = LWS_WRITE_CONTINUATION;
|
||||
p += sprintf(p, "]}");
|
||||
p += sprintf((char *)p, "]\n}\n");
|
||||
if (pss->changed_partway) {
|
||||
pss->subsequent = 0;
|
||||
pss->scan_state = SCAN_STATE_INITIAL;
|
||||
} else
|
||||
} else {
|
||||
pss->scan_state = SCAN_STATE_NONE;
|
||||
vhd->autonomous_update_sampled = vhd->autonomous_update;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
issue:
|
||||
// lwsl_notice("issue: %d (%d)\n", p - start, n);
|
||||
m = lws_write(wsi, (unsigned char *)start, p - start, n);
|
||||
if (m < 0) {
|
||||
lwsl_err("ERROR %d writing to di socket\n", m);
|
||||
|
@ -264,40 +576,149 @@ scan_state_final:
|
|||
|
||||
case LWS_CALLBACK_RECEIVE:
|
||||
{
|
||||
const char *sect = "\"app\": {", *b;
|
||||
nvs_handle nvh;
|
||||
char p[64];
|
||||
int n;
|
||||
char p[64], use[6];
|
||||
int n, si = -1;
|
||||
|
||||
if (strstr((const char *)in, "identify")) {
|
||||
lws_esp32_identify_physical_device();
|
||||
break;
|
||||
}
|
||||
|
||||
if (vhd->json_len && strstr((const char *)in, "update-factory")) {
|
||||
sect = "\"factory\": {";
|
||||
goto auton;
|
||||
}
|
||||
if (vhd->json_len && strstr((const char *)in, "update-ota"))
|
||||
goto auton;
|
||||
|
||||
if (strstr((const char *)in, "\"reset\""))
|
||||
goto sched_reset;
|
||||
|
||||
if (nvs_open("lws-station", NVS_READWRITE, &nvh) != ESP_OK) {
|
||||
lwsl_err("Unable to open nvs\n");
|
||||
break;
|
||||
}
|
||||
|
||||
for (n = 0; n < ARRAY_SIZE(store_json); n++) {
|
||||
if (esplws_simple_arg(p, sizeof(p), in, store_json[n].j))
|
||||
goto bail_nvs;
|
||||
if (!esplws_simple_arg(p, sizeof(p), in, ",\"slot\":\""))
|
||||
si = atoi(p);
|
||||
|
||||
if (nvs_set_str(nvh, store_json[n].nvs, p) != ESP_OK) {
|
||||
lwsl_notice("si %d\n", si);
|
||||
|
||||
for (n = 0; n < ARRAY_SIZE(store_json); n++) {
|
||||
if (esplws_simple_arg(p, sizeof(p), in, store_json[n].j))
|
||||
continue;
|
||||
|
||||
/* only change access password if he has physical access to device */
|
||||
if (n == 8 && lws_esp32_get_reboot_type() != LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON)
|
||||
continue;
|
||||
|
||||
//lwsl_notice("%s: %s '%s'\n", __func__, store_json[n].nvs, p);
|
||||
if (n == 9) {
|
||||
strncpy(lws_esp32.group, p, sizeof(lws_esp32.group) - 1);
|
||||
lws_esp32.group[sizeof(lws_esp32.group) - 1] = '\0';
|
||||
}
|
||||
if (n == 10) {
|
||||
strncpy(lws_esp32.role, p, sizeof(lws_esp32.role) - 1);
|
||||
lws_esp32.role[sizeof(lws_esp32.role) - 1] = '\0';
|
||||
}
|
||||
|
||||
if (lws_nvs_set_str(nvh, store_json[n].nvs, p) != ESP_OK) {
|
||||
lwsl_err("Unable to store %s in nvm\n", store_json[n].nvs);
|
||||
goto bail_nvs;
|
||||
}
|
||||
|
||||
if (si != -1 && n < 8) {
|
||||
if (!(n & 1)) {
|
||||
strncpy(lws_esp32.ssid[(n >> 1) & 3], p,
|
||||
sizeof(lws_esp32.ssid[0]));
|
||||
lws_esp32.ssid[(n >> 1) & 3]
|
||||
[sizeof(lws_esp32.ssid[0]) - 1] = '\0';
|
||||
lws_snprintf(use, sizeof(use) - 1, "%duse", si);
|
||||
lwsl_notice("resetting %s to 0\n", use);
|
||||
nvs_set_u32(nvh, use, 0);
|
||||
|
||||
} else {
|
||||
strncpy(lws_esp32.password[(n >> 1) & 3], p,
|
||||
sizeof(lws_esp32.password[0]));
|
||||
lws_esp32.password[(n >> 1) & 3]
|
||||
[sizeof(lws_esp32.password[0]) - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
nvs_commit(nvh);
|
||||
nvs_close(nvh);
|
||||
|
||||
vhd->reboot = 1;
|
||||
if (strstr((const char *)in, "\"factory-reset\"")) {
|
||||
if (lws_esp32_get_reboot_type() ==
|
||||
LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON) {
|
||||
|
||||
lwsl_notice("Doing factory reset\n");
|
||||
ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
|
||||
n = nvs_erase_all(nvh);
|
||||
if (n)
|
||||
lwsl_notice("erase_all failed %d\n", n);
|
||||
nvs_commit(nvh);
|
||||
nvs_close(nvh);
|
||||
|
||||
goto sched_reset;
|
||||
} else
|
||||
lwsl_notice("failed on factory button boot\n");
|
||||
}
|
||||
|
||||
if (vhd->scan_ongoing)
|
||||
vhd->changed_settings = 1;
|
||||
else
|
||||
lws_esp32_wlan_nvs_get(1);
|
||||
|
||||
lwsl_notice("set Join AP info\n");
|
||||
break;
|
||||
|
||||
bail_nvs:
|
||||
nvs_close(nvh);
|
||||
|
||||
return 1;
|
||||
|
||||
sched_reset:
|
||||
vhd->reboot_timer = xTimerCreate("x", pdMS_TO_TICKS(250), 0, vhd,
|
||||
(TimerCallbackFunction_t)reboot_timer_cb);
|
||||
xTimerStart(vhd->reboot_timer, 0);
|
||||
|
||||
return 1;
|
||||
|
||||
auton:
|
||||
lwsl_notice("Autonomous upload\n");
|
||||
b = strstr(vhd->json, sect);
|
||||
if (!b) {
|
||||
lwsl_notice("Can't find %s in JSON\n", sect);
|
||||
return 1;
|
||||
}
|
||||
b = strstr(b, "\"file\": \"");
|
||||
if (!b) {
|
||||
lwsl_notice("Can't find \"file\": JSON\n");
|
||||
return 1;
|
||||
}
|
||||
vhd->autonomous_update = 1;
|
||||
if (pss->scan_state == SCAN_STATE_NONE)
|
||||
vhd->autonomous_update_sampled = 1;
|
||||
b += 9;
|
||||
n = 0;
|
||||
while ((*b != '\"') && n < sizeof(p) - 1)
|
||||
p[n++] = *b++;
|
||||
|
||||
p[n] = '\0';
|
||||
|
||||
vhd->part = ota_choose_part();
|
||||
if (!vhd->part)
|
||||
return 1;
|
||||
|
||||
if (client_connection(vhd, p))
|
||||
vhd->autonomous_update = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LWS_CALLBACK_CLOSED:
|
||||
|
@ -315,12 +736,235 @@ bail_nvs:
|
|||
|
||||
vhd->count_live_pss--;
|
||||
}
|
||||
if (!vhd->live_pss_list)
|
||||
xTimerStop(vhd->timer, 0);
|
||||
break;
|
||||
|
||||
/* "factory" POST handling */
|
||||
|
||||
case LWS_CALLBACK_HTTP_BODY:
|
||||
/* create the POST argument parser if not already existing */
|
||||
lwsl_notice("LWS_CALLBACK_HTTP_BODY (scan)\n");
|
||||
if (!pss->spa) {
|
||||
pss->spa = lws_spa_create(wsi, param_names,
|
||||
ARRAY_SIZE(param_names), 1024,
|
||||
file_upload_cb, pss);
|
||||
if (!pss->spa)
|
||||
return -1;
|
||||
|
||||
pss->filename[0] = '\0';
|
||||
pss->file_length = 0;
|
||||
}
|
||||
|
||||
/* let it parse the POST data */
|
||||
if (lws_spa_process(pss->spa, in, len))
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_HTTP_BODY_COMPLETION:
|
||||
lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION (scan)\n");
|
||||
/* call to inform no more payload data coming */
|
||||
lws_spa_finalize(pss->spa);
|
||||
|
||||
if (nvs_open("lws-station", NVS_READWRITE, &nvh) != ESP_OK) {
|
||||
lwsl_err("Unable to open nvs\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (lws_esp32_get_reboot_type() == LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON) {
|
||||
|
||||
if (lws_spa_get_string(pss->spa, EPN_SERIAL)) {
|
||||
if (lws_nvs_set_str(nvh, "serial", lws_spa_get_string(pss->spa, EPN_SERIAL)) != ESP_OK) {
|
||||
lwsl_err("Unable to store serial in nvm\n");
|
||||
goto bail_nvs;
|
||||
}
|
||||
|
||||
nvs_commit(nvh);
|
||||
}
|
||||
|
||||
if (lws_spa_get_string(pss->spa, EPN_OPTS)) {
|
||||
if (lws_nvs_set_str(nvh, "opts", lws_spa_get_string(pss->spa, EPN_OPTS)) != ESP_OK) {
|
||||
lwsl_err("Unable to store options in nvm\n");
|
||||
goto bail_nvs;
|
||||
}
|
||||
|
||||
nvs_commit(nvh);
|
||||
}
|
||||
}
|
||||
nvs_close(nvh);
|
||||
|
||||
pss->result_len = snprintf(pss->result + LWS_PRE, sizeof(pss->result) - LWS_PRE - 1,
|
||||
"<html>Rebooting after storing certs...<br>connect to AP '<b>config-%s-%s</b>' and continue here: "
|
||||
"<a href=\"https://192.168.4.1\">https://192.168.4.1</a></html>",
|
||||
lws_esp32.model, lws_spa_get_string(pss->spa, EPN_SERIAL));
|
||||
|
||||
if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
|
||||
goto bail;
|
||||
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
|
||||
(unsigned char *)"text/html", 9, &p, end))
|
||||
goto bail;
|
||||
if (lws_add_http_header_content_length(wsi, pss->result_len, &p, end))
|
||||
goto bail;
|
||||
if (lws_finalize_http_header(wsi, &p, end))
|
||||
goto bail;
|
||||
|
||||
n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
|
||||
if (n < 0)
|
||||
goto bail;
|
||||
|
||||
lws_callback_on_writable(wsi);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_HTTP_WRITEABLE:
|
||||
lwsl_debug("LWS_CALLBACK_HTTP_WRITEABLE: sending %d\n",
|
||||
pss->result_len);
|
||||
n = lws_write(wsi, (unsigned char *)pss->result + LWS_PRE,
|
||||
pss->result_len, LWS_WRITE_HTTP);
|
||||
if (n < 0)
|
||||
return 1;
|
||||
|
||||
vhd->reboot_timer = xTimerCreate("x", pdMS_TO_TICKS(3000), 0, vhd,
|
||||
(TimerCallbackFunction_t)reboot_timer_cb);
|
||||
xTimerStart(vhd->reboot_timer, 0);
|
||||
|
||||
return 1; // hang up since we will reset
|
||||
|
||||
/* ----- client handling ----- */
|
||||
|
||||
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
|
||||
lwsl_notice("Client connection error %s\n", (char *)in);
|
||||
vhd->cwsi = NULL;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
|
||||
if (!vhd->autonomous_update)
|
||||
break;
|
||||
|
||||
{
|
||||
char pp[20];
|
||||
|
||||
if (lws_hdr_copy(wsi, pp, sizeof(pp) - 1, WSI_TOKEN_HTTP_CONTENT_LENGTH) < 0)
|
||||
return -1;
|
||||
|
||||
vhd->content_length = atoi(pp);
|
||||
if (vhd->content_length <= 0 ||
|
||||
vhd->content_length > vhd->part->size)
|
||||
return -1;
|
||||
|
||||
if (esp_ota_begin(vhd->part, (long)-1, &vhd->otahandle) != ESP_OK) {
|
||||
lwsl_err("OTA: Failed to begin\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
vhd->file_length = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
|
||||
//lwsl_notice("LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: %ld\n",
|
||||
// (long)len);
|
||||
|
||||
if (!vhd->autonomous_update) {
|
||||
if (sizeof(vhd->json) - vhd->json_len - 1 < len)
|
||||
len = sizeof(vhd->json) - vhd->json_len - 1;
|
||||
memcpy(vhd->json + vhd->json_len, in, len);
|
||||
vhd->json_len += len;
|
||||
vhd->json[vhd->json_len] = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
/* autonomous download */
|
||||
|
||||
|
||||
if (vhd->file_length + len > vhd->part->size) {
|
||||
lwsl_err("OTA: incoming file too large\n");
|
||||
goto abort_ota;
|
||||
}
|
||||
|
||||
lwsl_debug("writing 0x%lx... 0x%lx\n",
|
||||
vhd->part->address + vhd->file_length,
|
||||
vhd->part->address + vhd->file_length + len);
|
||||
if (esp_ota_write(vhd->otahandle, in, len) != ESP_OK) {
|
||||
lwsl_err("OTA: Failed to write\n");
|
||||
goto abort_ota;
|
||||
}
|
||||
vhd->file_length += len;
|
||||
|
||||
lws_callback_on_writable_all_protocol(vhd->context, vhd->protocol);
|
||||
break;
|
||||
|
||||
abort_ota:
|
||||
esp_ota_end(vhd->otahandle);
|
||||
vhd->otahandle = 0;
|
||||
vhd->autonomous_update = 0;
|
||||
|
||||
return 1;
|
||||
|
||||
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
|
||||
{
|
||||
char *px = (char *)pss->buffer + LWS_PRE;
|
||||
int lenx = sizeof(pss->buffer) - LWS_PRE - 1;
|
||||
|
||||
//lwsl_notice("LWS_CALLBACK_RECEIVE_CLIENT_HTTP: %d\n", len);
|
||||
|
||||
if (lws_http_client_read(wsi, &px, &lenx) < 0)
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
|
||||
lwsl_notice("LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n");
|
||||
vhd->cwsi = NULL;
|
||||
if (!vhd->autonomous_update) {
|
||||
|
||||
vhd->checked_updates = 1;
|
||||
puts(vhd->json);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* autonomous download */
|
||||
|
||||
lwsl_notice("auton complete\n");
|
||||
|
||||
if (esp_ota_end(vhd->otahandle) != ESP_OK) {
|
||||
lwsl_err("OTA: end failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (esp_ota_set_boot_partition(vhd->part) != ESP_OK) {
|
||||
lwsl_err("OTA: set boot part failed\n");
|
||||
return 1;
|
||||
}
|
||||
vhd->otahandle = 0;
|
||||
vhd->autonomous_update = 0;
|
||||
|
||||
vhd->reboot_timer = xTimerCreate("x", pdMS_TO_TICKS(250), 0, vhd,
|
||||
(TimerCallbackFunction_t)reboot_timer_cb);
|
||||
xTimerStart(vhd->reboot_timer, 0);
|
||||
return -1;
|
||||
|
||||
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
|
||||
lwsl_notice("LWS_CALLBACK_CLOSED_CLIENT_HTTP\n");
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_HTTP_DROP_PROTOCOL:
|
||||
/* called when our wsi user_space is going to be destroyed */
|
||||
if (pss->spa) {
|
||||
lws_spa_destroy(pss->spa);
|
||||
pss->spa = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define LWS_PLUGIN_PROTOCOL_ESPLWS_SCAN \
|
||||
|
@ -328,6 +972,6 @@ bail_nvs:
|
|||
"esplws-scan", \
|
||||
callback_esplws_scan, \
|
||||
sizeof(struct per_session_data__esplws_scan), \
|
||||
512, 0, NULL \
|
||||
1024, 0, NULL, 900 \
|
||||
}
|
||||
|
||||
|
|
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
|
|
@ -34,8 +34,15 @@
|
|||
#else
|
||||
#define MAX_MESSAGE_QUEUE 512
|
||||
#endif
|
||||
|
||||
#define MAX_MIRROR_INSTANCES 10
|
||||
|
||||
struct lws_mirror_instance;
|
||||
|
||||
struct per_session_data__lws_mirror {
|
||||
struct lws *wsi;
|
||||
struct lws_mirror_instance *mi;
|
||||
struct per_session_data__lws_mirror *same_mi_pss_list;
|
||||
int ringbuffer_tail;
|
||||
};
|
||||
|
||||
|
@ -44,11 +51,18 @@ struct a_message {
|
|||
size_t len;
|
||||
};
|
||||
|
||||
struct per_vhost_data__lws_mirror {
|
||||
struct lws_mirror_instance {
|
||||
struct lws_mirror_instance *next;
|
||||
struct per_session_data__lws_mirror *same_mi_pss_list;
|
||||
char name[30];
|
||||
struct a_message ringbuffer[MAX_MESSAGE_QUEUE];
|
||||
int ringbuffer_head;
|
||||
};
|
||||
|
||||
struct per_vhost_data__lws_mirror {
|
||||
struct lws_mirror_instance *mi_list;
|
||||
};
|
||||
|
||||
static int
|
||||
callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
|
@ -59,14 +73,112 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
(struct per_vhost_data__lws_mirror *)
|
||||
lws_protocol_vh_priv_get(lws_get_vhost(wsi),
|
||||
lws_get_protocol(wsi));
|
||||
int n, m;
|
||||
struct lws_mirror_instance *mi = NULL;
|
||||
char name[30];
|
||||
int n, m, count_mi = 0;
|
||||
|
||||
switch (reason) {
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
lwsl_info("%s: LWS_CALLBACK_ESTABLISHED\n", __func__);
|
||||
pss->ringbuffer_tail = v->ringbuffer_head;
|
||||
|
||||
/*
|
||||
* mirror instance name... defaults to "", but if URL includes
|
||||
* "?mirror=xxx", will be "xxx"
|
||||
*/
|
||||
|
||||
name[0] = '\0';
|
||||
lws_get_urlarg_by_name(wsi, "mirror", name, sizeof(name) - 1);
|
||||
|
||||
lwsl_notice("mirror %s\n", name);
|
||||
|
||||
/* is there already a mirror instance of this name? */
|
||||
|
||||
lws_start_foreach_ll(struct lws_mirror_instance *,
|
||||
mi1, v->mi_list) {
|
||||
count_mi++;
|
||||
if (strcmp(name, mi1->name))
|
||||
continue;
|
||||
/* yes... we will join it */
|
||||
lwsl_notice("Joining existing mi %p '%s'\n", mi1, name);
|
||||
mi = mi1;
|
||||
break;
|
||||
} lws_end_foreach_ll(mi1, next);
|
||||
|
||||
if (!mi) {
|
||||
|
||||
/* no existing mirror instance for name */
|
||||
|
||||
if (count_mi == MAX_MIRROR_INSTANCES)
|
||||
return -1;
|
||||
|
||||
/* create one with this name, and join it */
|
||||
|
||||
mi = malloc(sizeof(*mi));
|
||||
memset(mi, 0, sizeof(*mi));
|
||||
mi->next = v->mi_list;
|
||||
v->mi_list = mi;
|
||||
strcpy(mi->name, name);
|
||||
mi->ringbuffer_head = 0;
|
||||
|
||||
lwsl_notice("Created new mi %p '%s'\n", mi, name);
|
||||
}
|
||||
|
||||
/* add our pss to list of guys bound to this mi */
|
||||
|
||||
pss->same_mi_pss_list = mi->same_mi_pss_list;
|
||||
mi->same_mi_pss_list = pss;
|
||||
|
||||
/* init the pss */
|
||||
|
||||
pss->mi = mi;
|
||||
pss->ringbuffer_tail = mi->ringbuffer_head;
|
||||
pss->wsi = wsi;
|
||||
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLOSED:
|
||||
|
||||
/* detach our pss from the mirror instance */
|
||||
|
||||
mi = pss->mi;
|
||||
if (!mi)
|
||||
break;
|
||||
|
||||
lws_start_foreach_llp(struct per_session_data__lws_mirror **,
|
||||
ppss, mi->same_mi_pss_list) {
|
||||
if (*ppss == pss) {
|
||||
|
||||
*ppss = pss->same_mi_pss_list;
|
||||
break;
|
||||
}
|
||||
} lws_end_foreach_llp(ppss, same_mi_pss_list);
|
||||
|
||||
pss->mi = NULL;
|
||||
|
||||
if (mi->same_mi_pss_list)
|
||||
break;
|
||||
|
||||
/* last pss unbound from mi... delete mi */
|
||||
|
||||
lws_start_foreach_llp(struct lws_mirror_instance **,
|
||||
pmi, v->mi_list) {
|
||||
if (*pmi != mi)
|
||||
continue;
|
||||
|
||||
*pmi = (*pmi)->next;
|
||||
|
||||
lwsl_info("%s: mirror cleaniup %p\n", __func__, v);
|
||||
for (n = 0; n < ARRAY_SIZE(mi->ringbuffer); n++)
|
||||
if (mi->ringbuffer[n].payload) {
|
||||
free(mi->ringbuffer[n].payload);
|
||||
mi->ringbuffer[n].payload = NULL;
|
||||
}
|
||||
|
||||
free(mi);
|
||||
break;
|
||||
} lws_end_foreach_llp(pmi, next);
|
||||
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */
|
||||
|
@ -76,21 +188,13 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
break;
|
||||
|
||||
case LWS_CALLBACK_PROTOCOL_DESTROY: /* per vhost */
|
||||
if (!v)
|
||||
break;
|
||||
lwsl_info("%s: mirror protocol cleaning up %p\n", __func__, v);
|
||||
for (n = 0; n < ARRAY_SIZE(v->ringbuffer); n++)
|
||||
if (v->ringbuffer[n].payload) {
|
||||
free(v->ringbuffer[n].payload);
|
||||
v->ringbuffer[n].payload = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_SERVER_WRITEABLE:
|
||||
while (pss->ringbuffer_tail != v->ringbuffer_head) {
|
||||
m = v->ringbuffer[pss->ringbuffer_tail].len;
|
||||
while (pss->ringbuffer_tail != pss->mi->ringbuffer_head) {
|
||||
m = pss->mi->ringbuffer[pss->ringbuffer_tail].len;
|
||||
n = lws_write(wsi, (unsigned char *)
|
||||
v->ringbuffer[pss->ringbuffer_tail].payload +
|
||||
pss->mi->ringbuffer[pss->ringbuffer_tail].payload +
|
||||
LWS_PRE, m, LWS_WRITE_TEXT);
|
||||
if (n < 0) {
|
||||
lwsl_err("ERROR %d writing to mirror socket\n", n);
|
||||
|
@ -104,7 +208,7 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
else
|
||||
pss->ringbuffer_tail++;
|
||||
|
||||
if (((v->ringbuffer_head - pss->ringbuffer_tail) &
|
||||
if (((pss->mi->ringbuffer_head - pss->ringbuffer_tail) &
|
||||
(MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 15))
|
||||
lws_rx_flow_allow_all_protocol(lws_get_context(wsi),
|
||||
lws_get_protocol(wsi));
|
||||
|
@ -117,25 +221,25 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
break;
|
||||
|
||||
case LWS_CALLBACK_RECEIVE:
|
||||
if (((v->ringbuffer_head - pss->ringbuffer_tail) &
|
||||
if (((pss->mi->ringbuffer_head - pss->ringbuffer_tail) &
|
||||
(MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 1)) {
|
||||
lwsl_err("dropping!\n");
|
||||
goto choke;
|
||||
}
|
||||
|
||||
if (v->ringbuffer[v->ringbuffer_head].payload)
|
||||
free(v->ringbuffer[v->ringbuffer_head].payload);
|
||||
if (pss->mi->ringbuffer[pss->mi->ringbuffer_head].payload)
|
||||
free(pss->mi->ringbuffer[pss->mi->ringbuffer_head].payload);
|
||||
|
||||
v->ringbuffer[v->ringbuffer_head].payload = malloc(LWS_PRE + len);
|
||||
v->ringbuffer[v->ringbuffer_head].len = len;
|
||||
memcpy((char *)v->ringbuffer[v->ringbuffer_head].payload +
|
||||
pss->mi->ringbuffer[pss->mi->ringbuffer_head].payload = malloc(LWS_PRE + len);
|
||||
pss->mi->ringbuffer[pss->mi->ringbuffer_head].len = len;
|
||||
memcpy((char *)pss->mi->ringbuffer[pss->mi->ringbuffer_head].payload +
|
||||
LWS_PRE, in, len);
|
||||
if (v->ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
|
||||
v->ringbuffer_head = 0;
|
||||
if (pss->mi->ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
|
||||
pss->mi->ringbuffer_head = 0;
|
||||
else
|
||||
v->ringbuffer_head++;
|
||||
pss->mi->ringbuffer_head++;
|
||||
|
||||
if (((v->ringbuffer_head - pss->ringbuffer_tail) &
|
||||
if (((pss->mi->ringbuffer_head - pss->ringbuffer_tail) &
|
||||
(MAX_MESSAGE_QUEUE - 1)) != (MAX_MESSAGE_QUEUE - 2))
|
||||
goto done;
|
||||
|
||||
|
@ -144,8 +248,14 @@ choke:
|
|||
lws_rx_flow_control(wsi, 0);
|
||||
|
||||
done:
|
||||
lws_callback_on_writable_all_protocol(lws_get_context(wsi),
|
||||
lws_get_protocol(wsi));
|
||||
/*
|
||||
* ask for WRITABLE callback for every wsi bound to this
|
||||
* mirror instance
|
||||
*/
|
||||
lws_start_foreach_ll(struct per_session_data__lws_mirror *,
|
||||
pss1, pss->mi->same_mi_pss_list) {
|
||||
lws_callback_on_writable(pss1->wsi);
|
||||
} lws_end_foreach_ll(pss1, same_mi_pss_list);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "../lib/libwebsockets.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
struct lws_ss_load_sample {
|
||||
time_t t;
|
||||
|
|
121
scripts/esp32.mk
Normal file
121
scripts/esp32.mk
Normal file
|
@ -0,0 +1,121 @@
|
|||
#
|
||||
# LWS-style images are composed like this
|
||||
#
|
||||
# [ OTA or Factory standard xpressif image ]
|
||||
# [ 32-b LE len ] [ ROMFS ]
|
||||
# [ 32-b LE len ] [ Image information JSON ]
|
||||
#
|
||||
|
||||
SHELL=/bin/bash
|
||||
|
||||
ESPPORT ?= $(CONFIG_ESPTOOLPY_PORT)
|
||||
|
||||
LWS_BUILD_PATH=$(PROJECT_PATH)/build
|
||||
|
||||
jbi=$(LWS_BUILD_PATH)/json-buildinfo
|
||||
|
||||
FAC=$(CONFIG_LWS_IS_FACTORY_APPLICATION)
|
||||
ifeq ($(FAC),)
|
||||
FAC=0
|
||||
endif
|
||||
export FAC
|
||||
DIRNAME:=$(shell basename $$(pwd) | tr -d '\n')
|
||||
|
||||
$(LWS_BUILD_PATH)/pack.img: $(APP_BIN)
|
||||
GNUSTAT=stat ;\
|
||||
if [ `which gstat 2>/dev/null` ] ; then GNUSTAT=gstat ; fi ;\
|
||||
DIRNAME=$$(basename $$(pwd) | tr -d '\n') ;\
|
||||
genromfs -f $(LWS_BUILD_PATH)/romfs.img -d $(PROJECT_PATH)/romfs-files ; \
|
||||
RLEN=$$($$GNUSTAT -c %s $(LWS_BUILD_PATH)/romfs.img) ;\
|
||||
LEN=$$($$GNUSTAT -c %s $(LWS_BUILD_PATH)/$$DIRNAME.bin) ;\
|
||||
printf " Original length: 0x%06x (%8d)\n" $$LEN $$LEN ; \
|
||||
printf %02x $$(( $$RLEN % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
|
||||
printf %02x $$(( ( $$RLEN / 256 ) % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
|
||||
printf %02x $$(( ( $$RLEN / 65536 ) % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
|
||||
printf %02x $$(( ( $$RLEN / 16777216 ) % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
|
||||
cat $(LWS_BUILD_PATH)/romfs.img >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ; \
|
||||
LEN=$$($$GNUSTAT -c %s $(LWS_BUILD_PATH)/$$DIRNAME.bin) ;\
|
||||
UNIXTIME=$$(date +%s | tr -d '\n') ; \
|
||||
echo -n -e "{\r\n \"schema\": \"lws1\",\r\n \"model\": \"$(CONFIG_LWS_MODEL_NAME)\",\r\n \"builder\": \"" > $(jbi) ;\
|
||||
hostname | tr -d '\n' >> $(jbi) ;\
|
||||
echo -n -e "\",\r\n \"app\": \"" >> $(jbi) ;\
|
||||
echo -n $$DIRNAME >> $(jbi) ;\
|
||||
echo -n -e "\",\r\n \"user\": \"" >> $(jbi) ;\
|
||||
whoami | tr -d '\n' >>$(jbi) ;\
|
||||
echo -n -e "\",\r\n \"git\": \"" >> $(jbi) ;\
|
||||
git describe --dirty --always | tr -d '\n' >> $(jbi) ;\
|
||||
echo -n -e "\",\r\n \"date\": \"" >> $(jbi) ;\
|
||||
date | tr -d '\n' >> $(jbi) ;\
|
||||
echo -n -e "\",\r\n \"unixtime\": \"" >> $(jbi) ;\
|
||||
echo -n $$UNIXTIME >> $(jbi) ;\
|
||||
echo -n -e "\",\r\n \"file\": \""$$DIRNAME-$$UNIXTIME.bin >> $(jbi) ;\
|
||||
echo -n -e "\",\r\n \"factory\": \"$(FAC)" >> $(jbi) ;\
|
||||
echo -n -e "\"\r\n}" >> $(jbi) ;\
|
||||
JLEN=$$($$GNUSTAT -c %s $(jbi)) ;\
|
||||
printf %02x $$(( $$JLEN % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
|
||||
printf %02x $$(( ( $$JLEN / 256 ) % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
|
||||
printf %02x $$(( ( $$JLEN / 65536 ) % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
|
||||
printf %02x $$(( ( $$JLEN / 16777216 ) % 256 )) | xxd -r -p >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
|
||||
cat $(jbi) >> $(LWS_BUILD_PATH)/$$DIRNAME.bin ;\
|
||||
cp $(LWS_BUILD_PATH)/$$DIRNAME.bin $(LWS_BUILD_PATH)/pack.img ;\
|
||||
LEN=$$($$GNUSTAT -c %s $(LWS_BUILD_PATH)/$$DIRNAME.bin) ;\
|
||||
cp $(LWS_BUILD_PATH)/$$DIRNAME.bin $(LWS_BUILD_PATH)/$$DIRNAME-$$UNIXTIME.bin ;\
|
||||
printf " After ROMFS + Build info: 0x%06x (%8d)\n" $$LEN $$LEN
|
||||
|
||||
.PHONY: manifest
|
||||
manifest:
|
||||
ifeq ($F,)
|
||||
echo "Usage make F=<factory app dir> A=<app dir> manifest"
|
||||
exit 1
|
||||
endif
|
||||
ifeq ($A,)
|
||||
echo "Usage make F=<factory app dir> A=<app dir> manifest"
|
||||
exit 1
|
||||
endif
|
||||
echo -n -e "{\r\n\"app\": " > build/manifest.json
|
||||
cat $(A)/build/json-buildinfo >> build/manifest.json
|
||||
echo -n -e ", \"factory\": " >> build/manifest.json
|
||||
cat $(F)/build/json-buildinfo >> build/manifest.json
|
||||
echo -n -e "\r\n}\r\n" >> build/manifest.json
|
||||
|
||||
all: $(LWS_BUILD_PATH)/pack.img
|
||||
|
||||
flash: $(LWS_BUILD_PATH)/pack.img
|
||||
|
||||
flash_ota: $(LWS_BUILD_PATH)/pack.img
|
||||
DIRNAME=$$(basename $$(pwd) | tr -d '\n') ;\
|
||||
$(IDF_PATH)/components/esptool_py/esptool/esptool.py \
|
||||
--chip esp32 \
|
||||
--port $(ESPPORT) \
|
||||
--baud $(CONFIG_ESPTOOLPY_BAUD) \
|
||||
write_flash 0x110000 $(LWS_BUILD_PATH)/$$DIRNAME.bin
|
||||
|
||||
erase_ota:
|
||||
$(IDF_PATH)/components/esptool_py/esptool/esptool.py \
|
||||
--chip esp32 \
|
||||
--port $(ESPPORT) \
|
||||
--baud $(CONFIG_ESPTOOLPY_BAUD) \
|
||||
erase_region 0x110000 0x2f0000
|
||||
|
||||
|
||||
export A
|
||||
export F
|
||||
.PHONY: upload
|
||||
upload: manifest
|
||||
ifeq ($F,)
|
||||
echo "Usage make F=<factory app dir> A=<app dir> manifest"
|
||||
exit 1
|
||||
endif
|
||||
ifeq ($A,)
|
||||
echo "Usage make F=<factory app dir> A=<app dir> manifest"
|
||||
exit 1
|
||||
endif
|
||||
UPL=$(CONFIG_LWS_OTA_SERVER_UPLOAD_USER)@$(CONFIG_LWS_OTA_SERVER_FQDN):$(CONFIG_LWS_OTA_SERVER_UPLOAD_PATH)/$(CONFIG_LWS_OTA_SERVER_BASE_URL)/$(CONFIG_LWS_MODEL_NAME)/ ;\
|
||||
AFILE=$(A)/build/$$(cat $$A/build/json-buildinfo | grep -- \"file\"\: |cut -d' ' -f3 |cut -d'"' -f2) ;\
|
||||
echo " Uploading $$AFILE to " $$UPL ;\
|
||||
scp $$AFILE $$UPL ;\
|
||||
FFILE=$(F)/build/$$(cat $$F/build/json-buildinfo | grep -- \"file\"\: |cut -d' ' -f3 |cut -d'"' -f2) ;\
|
||||
echo " Uploading $$FFILE" ;\
|
||||
scp $$FFILE $$UPL ;\
|
||||
echo " Uploading manifest" ;\
|
||||
scp build/manifest.json $$UPL
|
|
@ -29,10 +29,10 @@ function check {
|
|||
fi
|
||||
if [ "$1" = "defaultplusforbidden" ] ; then
|
||||
cat $INSTALLED/../share/libwebsockets-test-server/test.html > /tmp/plusforb
|
||||
echo -e -n "HTTP/1.1 403 Forbidden\x0d\x0aserver: libwebsockets\x0d\x0acontent-type: text/html\x0d\x0acontent-length: 38\x0d\x0a\x0d\x0a<html><body><h1>403</h1></body></html>" >> /tmp/plusforb
|
||||
echo -e -n "HTTP/1.1 403 Forbidden\x0d\x0acontent-type: text/html\x0d\x0acontent-length: 38\x0d\x0a\x0d\x0a<html><body><h1>403</h1></body></html>" >> /tmp/plusforb
|
||||
diff /tmp/lwscap /tmp/plusforb > /dev/null
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "FAIL: got something other than test.html back"
|
||||
echo "FAIL: got something other than test.html + forbidden back"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
@ -101,7 +101,9 @@ killall libwebsockets-test-server 2>/dev/null
|
|||
libwebsockets-test-server -d15 2>> $LOG &
|
||||
CPID=$!
|
||||
|
||||
while [ -z "`grep Listening $LOG`" ] ; do
|
||||
echo "Started server on PID $CPID"
|
||||
|
||||
while [ -z "`grep ort\ 7681 $LOG`" ] ; do
|
||||
sleep 0.5s
|
||||
done
|
||||
check
|
||||
|
@ -220,7 +222,7 @@ echo -e "GET ...................................................................
|
|||
check
|
||||
|
||||
echo
|
||||
echo "---- good request but http payload coming too (should be ignored and test.html served)"
|
||||
echo "---- good request but http payload coming too (test.html served then forbidden)"
|
||||
echo -e "GET /test.html HTTP/1.1\x0d\x0a\x0d\x0aILLEGAL-PAYLOAD........................................" \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
|
|
|
@ -263,19 +263,19 @@ static const struct test tests[] = {
|
|||
}, { 0, 4 }, 1 },
|
||||
};
|
||||
|
||||
static const int ring_size(struct ring *r)
|
||||
static int ring_size(struct ring *r)
|
||||
{
|
||||
return sizeof(r->buf);
|
||||
}
|
||||
static const int ring_used(struct ring *r)
|
||||
static int ring_used(struct ring *r)
|
||||
{
|
||||
return (r->head - r->tail) & (ring_size(r) - 1);
|
||||
}
|
||||
static const int ring_free(struct ring *r)
|
||||
static int ring_free(struct ring *r)
|
||||
{
|
||||
return (ring_size(r) - 1) - ring_used(r);
|
||||
}
|
||||
static const int ring_get_one(struct ring *r)
|
||||
static int ring_get_one(struct ring *r)
|
||||
{
|
||||
int n = r->buf[r->tail] & 255;
|
||||
|
||||
|
@ -842,6 +842,7 @@ main(int argc, char **argv)
|
|||
construct_state(pfds, FZY_S_LISTENING, POLLIN | POLLERR);
|
||||
pfds++;
|
||||
|
||||
(void)interface_name_local;
|
||||
lwsl_notice("Local side listening on %s:%u\n",
|
||||
interface_name_local, port_local);
|
||||
|
||||
|
|
|
@ -108,6 +108,285 @@ function removeEvent( obj, type, fn ) {
|
|||
* end of grayOut related stuff
|
||||
*/
|
||||
|
||||
/*
|
||||
* lws-meta helpers
|
||||
*/
|
||||
|
||||
var lws_meta_cmd = {
|
||||
OPEN_SUBCHANNEL: 0x41,
|
||||
/**< Client requests to open new subchannel
|
||||
*/
|
||||
OPEN_RESULT: 0x42,
|
||||
/**< Result of client request to open new subchannel */
|
||||
CLOSE_NOT: 0x43,
|
||||
CLOSE_RQ: 0x44,
|
||||
/**< client requests to close a subchannel */
|
||||
WRITE: 0x45,
|
||||
/**< connection writes something to specific channel index */
|
||||
RX: 0x46,
|
||||
};
|
||||
|
||||
function new_ws(urlpath, protocol)
|
||||
{
|
||||
if (typeof MozWebSocket != "undefined")
|
||||
return new MozWebSocket(urlpath, protocol);
|
||||
|
||||
return new WebSocket(urlpath, protocol);
|
||||
}
|
||||
|
||||
function lws_meta_ws() {
|
||||
var real;
|
||||
|
||||
var channel_id_to_child;
|
||||
var pending_children;
|
||||
var active_children;
|
||||
}
|
||||
|
||||
function lws_meta_ws_child() {
|
||||
var onopen;
|
||||
var onmessage;
|
||||
var onclose;
|
||||
|
||||
var channel_id;
|
||||
|
||||
var subprotocol;
|
||||
var suburl;
|
||||
var cookie;
|
||||
|
||||
var extensions;
|
||||
|
||||
var parent;
|
||||
}
|
||||
|
||||
lws_meta_ws_child.prototype.send = function(data)
|
||||
{
|
||||
|
||||
if (typeof data == "string") {
|
||||
data = String.fromCharCode(lws_meta_cmd.WRITE) +
|
||||
String.fromCharCode(this.channel_id) +
|
||||
data;
|
||||
|
||||
return this.parent.real.send(data);
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
var ab = new Uint8Array(data.length + 2);
|
||||
|
||||
ab[0] = lws_meta_cmd.WRITE;
|
||||
ab[1] = this.channel_id;
|
||||
ab.set(data, 2);
|
||||
|
||||
return this.parent.real.send(ab);
|
||||
}
|
||||
}
|
||||
|
||||
lws_meta_ws_child.prototype.close = function(close_code, close_string)
|
||||
{
|
||||
var pkt = new Uint8Array(129), m = 0, pkt1;
|
||||
|
||||
pkt[m++] = lws_meta_cmd.CLOSE_RQ;
|
||||
pkt[m++] = this.channel_id;
|
||||
|
||||
pkt[m++] = close_string.length + 0x20;
|
||||
|
||||
pkt[m++] = close_code / 256;
|
||||
pkt[m++] = close_code % 256;
|
||||
|
||||
for (i = 0; i < close_string.length; i++)
|
||||
pkt[m++] = close_string.charCodeAt(i);
|
||||
|
||||
pkt1 = new Uint8Array(m);
|
||||
for (n = 0; n < m; n++)
|
||||
pkt1[n] = pkt[n];
|
||||
|
||||
this.parent.real.send(pkt1.buffer);
|
||||
}
|
||||
|
||||
/* make a real ws connection using lws_meta*/
|
||||
lws_meta_ws.prototype.new_parent = function(urlpath)
|
||||
{
|
||||
var n, i, m = 0, pkt1;
|
||||
|
||||
this.ordinal = 1;
|
||||
this.pending_children = [];
|
||||
this.active_children = [];
|
||||
this.real = new_ws(urlpath, "lws-meta");
|
||||
|
||||
this.real.binaryType = 'arraybuffer';
|
||||
this.real.myparent = this;
|
||||
|
||||
this.real.onopen = function() {
|
||||
pkt = new Uint8Array(1024);
|
||||
var n, i, m = 0, pkt1;
|
||||
console.log("real open - pending children " + this.myparent.pending_children.length);
|
||||
for (n = 0; n < this.myparent.pending_children.length; n++) {
|
||||
|
||||
var p = this.myparent.pending_children[n];
|
||||
|
||||
pkt[m++] = lws_meta_cmd.OPEN_SUBCHANNEL;
|
||||
for (i = 0; i < p.subprotocol.length; i++)
|
||||
pkt[m++] = p.subprotocol.charCodeAt(i);
|
||||
pkt[m++] = 0;
|
||||
for (i = 0; i < p.suburl.length; i++)
|
||||
pkt[m++] = p.suburl.charCodeAt(i);
|
||||
pkt[m++] = 0;
|
||||
for (i = 0; i < p.cookie.length; i++)
|
||||
pkt[m++] = p.cookie.charCodeAt(i);
|
||||
pkt[m++] = 0;
|
||||
}
|
||||
|
||||
pkt1 = new Uint8Array(m);
|
||||
for (n = 0; n < m; n++)
|
||||
pkt1[n] = pkt[n];
|
||||
|
||||
console.log(this.myparent.pending_children[0].subprotocol);
|
||||
console.log(pkt1);
|
||||
|
||||
this.send(pkt1.buffer);
|
||||
}
|
||||
|
||||
|
||||
this.real.onmessage = function(msg) {
|
||||
|
||||
if (typeof msg.data != "string") {
|
||||
var ba = new Uint8Array(msg.data), n = 0;
|
||||
|
||||
while (n < ba.length) {
|
||||
|
||||
switch (ba[n++]) {
|
||||
case lws_meta_cmd.OPEN_RESULT:
|
||||
{
|
||||
var m = 0, cookie = "", protocol = "", ch = 0;
|
||||
var ws = this.myparent;
|
||||
/* cookie NUL
|
||||
* channel index + 0x20
|
||||
* protocol NUL
|
||||
*/
|
||||
while (ba[n])
|
||||
cookie = cookie + String.fromCharCode(ba[n++]);
|
||||
n++;
|
||||
ch = ba[n++];
|
||||
|
||||
while (ba[n])
|
||||
protocol = protocol + String.fromCharCode(ba[n++]);
|
||||
|
||||
console.log("open result " + cookie + " " + protocol + " " + ch + " pending len " + ws.pending_children.length);
|
||||
|
||||
for (m = 0; m < ws.pending_children.length; m++) {
|
||||
if (ws.pending_children[m].cookie == cookie) {
|
||||
var newchild = ws.pending_children[m];
|
||||
|
||||
/* found it */
|
||||
ws.pending_children[m].channel_id = ch;
|
||||
/* add to active children array */
|
||||
ws.active_children.push(ws.pending_children[m]);
|
||||
/* remove from pending children array */
|
||||
ws.pending_children.splice(m, 1);
|
||||
|
||||
newchild.parent = ws;
|
||||
newchild.extensions = this.extensions;
|
||||
|
||||
newchild.onopen();
|
||||
|
||||
console.log("made active " + cookie);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case lws_meta_cmd.CLOSE_NOT:
|
||||
{
|
||||
var code = 0, str = "", ch = 0, m, le;
|
||||
var ba = new Uint8Array(msg.data);
|
||||
/*
|
||||
* BYTE: channel
|
||||
* BYTE: MSB status code
|
||||
* BYTE: LSB status code
|
||||
* BYTES: rest of message is close status string
|
||||
*/
|
||||
|
||||
ch = ba[n++];
|
||||
le = ba[n++] - 0x20;
|
||||
code = ba[n++] * 256;
|
||||
code += ba[n++];
|
||||
|
||||
while (le--)
|
||||
str += String.fromCharCode(ba[n++]);
|
||||
|
||||
console.log("channel id " + ch + " code " + code + " str " + str + " len " + str.length);
|
||||
|
||||
for (m = 0; m < this.myparent.active_children.length; m++)
|
||||
if (this.myparent.active_children[m].channel_id == ch) {
|
||||
var child = this.myparent.active_children[m];
|
||||
var ms = new CloseEvent("close", { code:code, reason:str } );
|
||||
|
||||
/* reply with close ack */
|
||||
this.send(msg.data);
|
||||
|
||||
if (child.onclose)
|
||||
child.onclose(ms);
|
||||
|
||||
this.myparent.active_children.splice(m, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
} // switch
|
||||
}
|
||||
} else {
|
||||
if (msg.data.charCodeAt(0) == lws_meta_cmd.WRITE ) {
|
||||
var ch = msg.data.charCodeAt(1), m, ms;
|
||||
var ws = this.myparent, ms;
|
||||
|
||||
for (m = 0; m < ws.active_children.length; m++) {
|
||||
if (ws.active_children[m].channel_id == ch) {
|
||||
ms = new MessageEvent("WebSocket", { data: msg.data.substr(2, msg.data.length - 2) } );
|
||||
if (ws.active_children[m].onmessage)
|
||||
ws.active_children[m].onmessage(ms);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.real.onclose = function() {
|
||||
var ws = this.myparent, m;
|
||||
for (m = 0; m < ws.active_children.length; m++) {
|
||||
var child = ws.active_children[m];
|
||||
var ms = new CloseEvent("close", { code:1000, reason:"parent closed" } );
|
||||
|
||||
if (child.onclose)
|
||||
child.onclose(ms);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* make a child connection using existing lws_meta real ws connection */
|
||||
lws_meta_ws.prototype.new_ws = function(suburl, protocol)
|
||||
{
|
||||
var ch = new lws_meta_ws_child();
|
||||
|
||||
ch.suburl = suburl;
|
||||
ch.subprotocol = protocol;
|
||||
ch.cookie = "C" + this.ordinal++;
|
||||
|
||||
this.pending_children.push(ch);
|
||||
|
||||
if (this.real.readyState == 1)
|
||||
this.real.onopen();
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* end of lws-meta helpers
|
||||
*/
|
||||
|
||||
function lws_san(s)
|
||||
{
|
||||
|
|
|
@ -168,11 +168,6 @@ do_rx:
|
|||
}
|
||||
break;
|
||||
#endif
|
||||
case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED:
|
||||
/* reject everything else except permessage-deflate */
|
||||
if (strcmp(in, "permessage-deflate"))
|
||||
return 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
@ -203,11 +198,6 @@ static const struct lws_extension exts[] = {
|
|||
lws_extension_callback_pm_deflate,
|
||||
"permessage-deflate; client_no_context_takeover; client_max_window_bits"
|
||||
},
|
||||
{
|
||||
"deflate-frame",
|
||||
lws_extension_callback_pm_deflate,
|
||||
"deflate_frame"
|
||||
},
|
||||
{ NULL, NULL, NULL /* terminator */ }
|
||||
};
|
||||
|
||||
|
|
|
@ -162,7 +162,7 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
l = 0;
|
||||
|
||||
while (shift >= 0) {
|
||||
l |= ((unsigned long long)*p++) << shift;
|
||||
l |= ((lws_intptr_t)*p++) << shift;
|
||||
shift -= 8;
|
||||
}
|
||||
|
||||
|
@ -536,7 +536,8 @@ int main(int argc, char **argv)
|
|||
|
||||
/* stats */
|
||||
|
||||
fprintf(stderr, "\n--- %s websocket ping statistics "
|
||||
if (global_rx_count && global_tx_count)
|
||||
fprintf(stderr, "\n--- %s websocket ping statistics "
|
||||
"using %d connections ---\n"
|
||||
"%lu packets transmitted, %lu received, "
|
||||
"%lu%% packet loss, time %ldms\n"
|
||||
|
|
|
@ -1,122 +0,0 @@
|
|||
/*
|
||||
* libwebsockets-test-server - libwebsockets test implementation
|
||||
*
|
||||
* Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
*
|
||||
* The person who associated a work with this deed has dedicated
|
||||
* the work to the public domain by waiving all of his or her rights
|
||||
* to the work worldwide under copyright law, including all related
|
||||
* and neighboring rights, to the extent allowed by law. You can copy,
|
||||
* modify, distribute and perform the work, even for commercial purposes,
|
||||
* all without asking permission.
|
||||
*
|
||||
* The test apps are intended to be adapted for use in your code, which
|
||||
* may be proprietary. So unlike the library itself, they are licensed
|
||||
* Public Domain.
|
||||
*/
|
||||
#include "test-server.h"
|
||||
|
||||
/* echogen protocol
|
||||
*
|
||||
* if you connect to him using his protocol, he'll send you a file chopped
|
||||
* up in various frame sizes repeated until he reaches a limit.
|
||||
*/
|
||||
|
||||
#define TOTAL 993840
|
||||
|
||||
int
|
||||
callback_lws_echogen(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
unsigned char buf[LWS_PRE + 8192];
|
||||
struct per_session_data__echogen *pss =
|
||||
(struct per_session_data__echogen *)user;
|
||||
unsigned char *p = &buf[LWS_PRE];
|
||||
int n, m;
|
||||
|
||||
switch (reason) {
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
pss->total = TOTAL;
|
||||
pss->fragsize = 2048;
|
||||
pss->total_rx = 0;
|
||||
sprintf((char *)buf, "%s/test.html", resource_path);
|
||||
pss->fd = open((char *)buf, LWS_O_RDONLY);
|
||||
if (pss->fd < 0) {
|
||||
lwsl_err("Failed to open %s\n", buf);
|
||||
return -1;
|
||||
}
|
||||
pss->wr = LWS_WRITE_TEXT | LWS_WRITE_NO_FIN;
|
||||
lws_callback_on_writable(wsi);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLOSED:
|
||||
if (pss->fd >= 0)
|
||||
close(pss->fd);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_SERVER_WRITEABLE:
|
||||
|
||||
// pss->fragsize += 16;
|
||||
// if (pss->fragsize >= 4096)
|
||||
// pss->fragsize = 32;
|
||||
|
||||
lwsl_err("%s: cb writeable, total left %ld\n", __func__, (long)pss->total);
|
||||
m = pss->fragsize;
|
||||
if ((size_t)m >= pss->total) {
|
||||
m = (int)pss->total;
|
||||
pss->wr = LWS_WRITE_CONTINUATION; /* ie, FIN */
|
||||
}
|
||||
n = read(pss->fd, p, m);
|
||||
if (n < 0) {
|
||||
lwsl_err("failed read\n");
|
||||
return -1;
|
||||
}
|
||||
if (n < m) {
|
||||
lseek(pss->fd, 0, SEEK_SET);
|
||||
m = read(pss->fd, p + n, m - n);
|
||||
if (m < 0)
|
||||
return -1;
|
||||
} else
|
||||
m = 0;
|
||||
pss->total -= n + m;
|
||||
m = lws_write(wsi, p, n + m, pss->wr);
|
||||
if (m < n) {
|
||||
lwsl_err("ERROR %d writing to di socket\n", n);
|
||||
return -1;
|
||||
}
|
||||
if (!pss->total) {
|
||||
lwsl_err("Completed OK\n");
|
||||
break;
|
||||
}
|
||||
pss->wr = LWS_WRITE_CONTINUATION | LWS_WRITE_NO_FIN;
|
||||
lws_callback_on_writable(wsi);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RECEIVE:
|
||||
pss->total_rx += len;
|
||||
lwsl_err("rx %ld\n", (long)pss->total_rx);
|
||||
if (pss->total_rx == TOTAL) {
|
||||
lws_close_reason(wsi, LWS_CLOSE_STATUS_NORMAL,
|
||||
(unsigned char *)"done", 4);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE:
|
||||
lwsl_notice("LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: len %lu\n",
|
||||
(unsigned long)len);
|
||||
for (n = 0; n < (int)len; n++)
|
||||
lwsl_notice(" %d: 0x%02X\n", n,
|
||||
((unsigned char *)in)[n]);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -141,6 +141,8 @@ file_upload_cb(void *data, const char *name, const char *filename,
|
|||
(struct per_session_data__http *)data;
|
||||
int n;
|
||||
|
||||
(void)n;
|
||||
|
||||
switch (state) {
|
||||
case LWS_UFS_OPEN:
|
||||
strncpy(pss->filename, filename, sizeof(pss->filename) - 1);
|
||||
|
@ -230,38 +232,37 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
|
|||
goto try_to_reuse;
|
||||
}
|
||||
|
||||
#ifndef LWS_NO_CLIENT
|
||||
#if !defined(LWS_NO_CLIENT) && defined(LWS_OPENSSL_SUPPORT)
|
||||
if (!strncmp(in, "/proxytest", 10)) {
|
||||
struct lws_client_connect_info i;
|
||||
char *rootpath = "/";
|
||||
char *rootpath = "/git/";
|
||||
const char *p = (const char *)in;
|
||||
|
||||
if (lws_get_child(wsi))
|
||||
break;
|
||||
|
||||
pss->client_finished = 0;
|
||||
memset(&i,0, sizeof(i));
|
||||
memset(&i, 0, sizeof(i));
|
||||
i.context = lws_get_context(wsi);
|
||||
i.address = "git.libwebsockets.org";
|
||||
i.port = 80;
|
||||
i.ssl_connection = 0;
|
||||
i.address = "libwebsockets.org";
|
||||
i.port = 443;
|
||||
i.ssl_connection = 1;
|
||||
if (p[10])
|
||||
i.path = (char *)in + 10;
|
||||
else
|
||||
i.path = rootpath;
|
||||
i.host = "git.libwebsockets.org";
|
||||
i.host = i.address;
|
||||
i.origin = NULL;
|
||||
i.method = "GET";
|
||||
i.parent_wsi = wsi;
|
||||
i.uri_replace_from = "git.libwebsockets.org/";
|
||||
i.uri_replace_from = "libwebsockets.org/git/";
|
||||
i.uri_replace_to = "/proxytest/";
|
||||
|
||||
if (!lws_client_connect_via_info(&i)) {
|
||||
lwsl_err("proxy connect fail\n");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
@ -377,7 +378,7 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
|
|||
if (!mimetype) {
|
||||
lwsl_err("Unknown mimetype for %s\n", buf);
|
||||
lws_return_http_status(wsi,
|
||||
HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL);
|
||||
HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, "Unknown Mimetype");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -411,16 +412,22 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
|
|||
n = (char *)p - leaf_path;
|
||||
|
||||
n = lws_serve_http_file(wsi, buf, mimetype, other_headers, n);
|
||||
if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi)))
|
||||
return -1; /* error or can't reuse connection: close the socket */
|
||||
if (n < 0)
|
||||
return -1; /* error*/
|
||||
|
||||
/*
|
||||
* notice that the sending of the file completes asynchronously,
|
||||
* we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when
|
||||
* it's done
|
||||
* it's done. That's the case even if we just completed the
|
||||
* send, so wait for that.
|
||||
*/
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_RECEIVE:
|
||||
((char *)in)[len] = '\0';
|
||||
lwsl_info("rx %d '%s'\n", (int)len, (char *)in);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_HTTP_BODY:
|
||||
/* create the POST argument parser if not already existing */
|
||||
if (!pss->spa) {
|
||||
|
@ -511,11 +518,13 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
|
|||
if (pss->client_finished)
|
||||
return -1;
|
||||
|
||||
if (!pss->fop_fd)
|
||||
if (!lws_get_child(wsi) && !pss->fop_fd) {
|
||||
lwsl_notice("fop_fd NULL\n");
|
||||
goto try_to_reuse;
|
||||
}
|
||||
|
||||
#ifndef LWS_NO_CLIENT
|
||||
if (pss->reason_bf & 2) {
|
||||
if (pss->reason_bf & LWS_CB_REASON_AUX_BF__PROXY) {
|
||||
char *px = buf + LWS_PRE;
|
||||
int lenx = sizeof(buf) - LWS_PRE;
|
||||
/*
|
||||
|
@ -524,17 +533,24 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
|
|||
* suitable size to send or what's available, whichever
|
||||
* is the smaller.
|
||||
*/
|
||||
pss->reason_bf &= ~2;
|
||||
|
||||
|
||||
pss->reason_bf &= ~LWS_CB_REASON_AUX_BF__PROXY;
|
||||
wsi1 = lws_get_child(wsi);
|
||||
if (!wsi1)
|
||||
break;
|
||||
if (lws_http_client_read(wsi1, &px, &lenx) < 0)
|
||||
goto bail;
|
||||
return -1;
|
||||
|
||||
if (pss->client_finished)
|
||||
return -1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (lws_get_child(wsi))
|
||||
break;
|
||||
|
||||
#endif
|
||||
/*
|
||||
* we can send more of whatever it is we were sending
|
||||
|
@ -657,16 +673,12 @@ bail:
|
|||
assert(lws_get_parent(wsi));
|
||||
if (!lws_get_parent(wsi))
|
||||
break;
|
||||
// lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP: wsi %p: sock: %d, parent_wsi: %p, parent_sock:%d, len %d\n",
|
||||
// wsi, lws_get_socket_fd(wsi),
|
||||
// lws_get_parent(wsi),
|
||||
// lws_get_socket_fd(lws_get_parent(wsi)), len);
|
||||
pss1 = lws_wsi_user(lws_get_parent(wsi));
|
||||
pss1->reason_bf |= 2;
|
||||
pss1->reason_bf |= LWS_CB_REASON_AUX_BF__PROXY;
|
||||
lws_callback_on_writable(lws_get_parent(wsi));
|
||||
break;
|
||||
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
|
||||
//lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ len %d\n", len);
|
||||
//lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ len %d\n", (int)len);
|
||||
assert(lws_get_parent(wsi));
|
||||
m = lws_write(lws_get_parent(wsi), (unsigned char *)in,
|
||||
len, LWS_WRITE_HTTP);
|
||||
|
|
|
@ -34,35 +34,9 @@ char *resource_path = LOCAL_RESOURCE_PATH;
|
|||
char crl_path[1024] = "";
|
||||
#endif
|
||||
|
||||
/*
|
||||
* libev dumps their hygiene problems on their users blaming compiler
|
||||
* http://lists.schmorp.de/pipermail/libev/2008q4/000442.html
|
||||
*/
|
||||
|
||||
#if EV_MINPRI == EV_MAXPRI
|
||||
# define _ev_set_priority(ev, pri) ((ev), (pri))
|
||||
#else
|
||||
# define _ev_set_priority(ev, pri) { \
|
||||
ev_watcher *evw = (ev_watcher *)(void *)ev; \
|
||||
evw->priority = pri; \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define _ev_init(ev,cb_) { \
|
||||
ev_watcher *evw = (ev_watcher *)(void *)ev; \
|
||||
\
|
||||
evw->active = evw->pending = 0; \
|
||||
_ev_set_priority((ev), 0); \
|
||||
ev_set_cb((ev), cb_); \
|
||||
}
|
||||
|
||||
#define _ev_timer_init(ev, cb, after, _repeat) { \
|
||||
ev_watcher_time *evwt = (ev_watcher_time *)(void *)ev; \
|
||||
\
|
||||
_ev_init(ev, cb); \
|
||||
evwt->at = after; \
|
||||
(ev)->repeat = _repeat; \
|
||||
}
|
||||
#define LWS_PLUGIN_STATIC
|
||||
#include "../plugins/protocol_lws_mirror.c"
|
||||
#include "../plugins/protocol_lws_status.c"
|
||||
|
||||
/* singlethreaded version --> no locks */
|
||||
|
||||
|
@ -94,6 +68,7 @@ enum demo_protocols {
|
|||
|
||||
PROTOCOL_DUMB_INCREMENT,
|
||||
PROTOCOL_LWS_MIRROR,
|
||||
PROTOCOL_LWS_STATUS,
|
||||
|
||||
/* always last */
|
||||
DEMO_PROTOCOL_COUNT
|
||||
|
@ -114,20 +89,13 @@ static struct lws_protocols protocols[] = {
|
|||
"dumb-increment-protocol",
|
||||
callback_dumb_increment,
|
||||
sizeof(struct per_session_data__dumb_increment),
|
||||
10,
|
||||
},
|
||||
{
|
||||
"lws-mirror-protocol",
|
||||
callback_lws_mirror,
|
||||
sizeof(struct per_session_data__lws_mirror),
|
||||
128,
|
||||
},
|
||||
{
|
||||
"lws-status",
|
||||
callback_lws_status,
|
||||
sizeof(struct per_session_data__lws_status),
|
||||
128,
|
||||
10, /* rx buf size must be >= permessage-deflate rx size
|
||||
* dumb-increment only sends very small packets, so we set
|
||||
* this accordingly. If your protocol will send bigger
|
||||
* things, adjust this to match */
|
||||
},
|
||||
LWS_PLUGIN_PROTOCOL_MIRROR,
|
||||
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
|
||||
{ NULL, NULL, 0, 0 } /* terminator */
|
||||
};
|
||||
|
||||
|
@ -296,7 +264,7 @@ int main(int argc, char **argv)
|
|||
#endif
|
||||
|
||||
for (n = 0; n < ARRAY_SIZE(sigs); n++) {
|
||||
_ev_init(&signals[n], signal_cb);
|
||||
ev_init(&signals[n], signal_cb);
|
||||
ev_signal_set(&signals[n], sigs[n]);
|
||||
ev_signal_start(loop, &signals[n]);
|
||||
}
|
||||
|
@ -364,7 +332,7 @@ int main(int argc, char **argv)
|
|||
|
||||
lws_ev_initloop(context, loop, 0);
|
||||
|
||||
_ev_timer_init(&timeout_watcher, ev_timeout_cb, 0.05, 0.05);
|
||||
ev_timer_init(&timeout_watcher, ev_timeout_cb, 0.05, 0.05);
|
||||
ev_timer_start(loop, &timeout_watcher);
|
||||
ev_run(loop, 0);
|
||||
|
||||
|
|
345
test-server/test-server-libevent.c
Normal file
345
test-server/test-server-libevent.c
Normal file
|
@ -0,0 +1,345 @@
|
|||
/*
|
||||
* libwebsockets-test-server - libwebsockets test implementation
|
||||
*
|
||||
* Copyright (C) 2011-2017 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
*
|
||||
* The person who associated a work with this deed has dedicated
|
||||
* the work to the public domain by waiving all of his or her rights
|
||||
* to the work worldwide under copyright law, including all related
|
||||
* and neighboring rights, to the extent allowed by law. You can copy,
|
||||
* modify, distribute and perform the work, even for commercial purposes,
|
||||
* all without asking permission.
|
||||
*
|
||||
* The test apps are intended to be adapted for use in your code, which
|
||||
* may be proprietary. So unlike the library itself, they are licensed
|
||||
* Public Domain.
|
||||
*/
|
||||
#include "test-server.h"
|
||||
|
||||
int close_testing;
|
||||
int max_poll_elements;
|
||||
int debug_level = 7;
|
||||
volatile int force_exit = 0;
|
||||
struct lws_context *context;
|
||||
struct lws_plat_file_ops fops_plat;
|
||||
|
||||
/* http server gets files from this path */
|
||||
#define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server"
|
||||
char *resource_path = LOCAL_RESOURCE_PATH;
|
||||
|
||||
#if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param)
|
||||
char crl_path[1024] = "";
|
||||
#endif
|
||||
|
||||
#define LWS_PLUGIN_STATIC
|
||||
#include "../plugins/protocol_lws_mirror.c"
|
||||
#include "../plugins/protocol_lws_status.c"
|
||||
#include "../plugins/protocol_lws_meta.c"
|
||||
|
||||
/* singlethreaded version --> no locks */
|
||||
|
||||
void test_server_lock(int care)
|
||||
{
|
||||
}
|
||||
void test_server_unlock(int care)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* This demo server shows how to use libwebsockets for one or more
|
||||
* websocket protocols in the same server
|
||||
*
|
||||
* It defines the following websocket protocols:
|
||||
*
|
||||
* dumb-increment-protocol: once the socket is opened, an incrementing
|
||||
* ascii string is sent down it every 50ms.
|
||||
* If you send "reset\n" on the websocket, then
|
||||
* the incrementing number is reset to 0.
|
||||
*
|
||||
* lws-mirror-protocol: copies any received packet to every connection also
|
||||
* using this protocol, including the sender
|
||||
*/
|
||||
|
||||
enum demo_protocols {
|
||||
/* always first */
|
||||
PROTOCOL_HTTP = 0,
|
||||
|
||||
PROTOCOL_DUMB_INCREMENT,
|
||||
PROTOCOL_LWS_MIRROR,
|
||||
PROTOCOL_LWS_META,
|
||||
|
||||
/* always last */
|
||||
DEMO_PROTOCOL_COUNT
|
||||
};
|
||||
|
||||
/* list of supported protocols and callbacks */
|
||||
|
||||
static struct lws_protocols protocols[] = {
|
||||
/* first protocol must always be HTTP handler */
|
||||
|
||||
{
|
||||
"http-only", /* name */
|
||||
callback_http, /* callback */
|
||||
sizeof (struct per_session_data__http), /* per_session_data_size */
|
||||
0, /* max frame size / rx buffer */
|
||||
},
|
||||
{
|
||||
"dumb-increment-protocol",
|
||||
callback_dumb_increment,
|
||||
sizeof(struct per_session_data__dumb_increment),
|
||||
10,
|
||||
},
|
||||
|
||||
LWS_PLUGIN_PROTOCOL_MIRROR,
|
||||
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
|
||||
LWS_PLUGIN_PROTOCOL_LWS_META,
|
||||
{ NULL, NULL, 0, 0 } /* terminator */
|
||||
};
|
||||
|
||||
static const struct lws_extension exts[] = {
|
||||
{
|
||||
"permessage-deflate",
|
||||
lws_extension_callback_pm_deflate,
|
||||
"permessage-deflate; client_no_context_takeover; client_max_window_bits"
|
||||
},
|
||||
{
|
||||
"deflate-frame",
|
||||
lws_extension_callback_pm_deflate,
|
||||
"deflate_frame"
|
||||
},
|
||||
{ NULL, NULL, NULL /* terminator */ }
|
||||
};
|
||||
|
||||
/* this shows how to override the lws file operations. You don't need
|
||||
* to do any of this unless you have a reason (eg, want to serve
|
||||
* compressed files without decompressing the whole archive)
|
||||
*/
|
||||
static lws_fop_fd_t
|
||||
test_server_fops_open(const struct lws_plat_file_ops *fops,
|
||||
const char *vfs_path, const char *vpath,
|
||||
lws_fop_flags_t *flags)
|
||||
{
|
||||
lws_fop_fd_t n;
|
||||
|
||||
/* call through to original platform implementation */
|
||||
n = fops_plat.open(fops, vfs_path, vpath, flags);
|
||||
|
||||
lwsl_notice("%s: opening %s, ret %p\n", __func__, vfs_path, n);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void signal_cb(evutil_socket_t sock_fd, short events, void *ctx)
|
||||
{
|
||||
struct event_base *event_base_loop = ctx;
|
||||
|
||||
lwsl_notice("Signal caught, exiting...\n");
|
||||
force_exit = 1;
|
||||
if (events & EV_SIGNAL)
|
||||
event_base_loopbreak(event_base_loop);
|
||||
}
|
||||
|
||||
static void
|
||||
ev_timeout_cb (evutil_socket_t sock_fd, short events, void *ctx)
|
||||
{
|
||||
lws_callback_on_writable_all_protocol(context,
|
||||
&protocols[PROTOCOL_DUMB_INCREMENT]);
|
||||
}
|
||||
|
||||
static struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "debug", required_argument, NULL, 'd' },
|
||||
{ "port", required_argument, NULL, 'p' },
|
||||
{ "ssl", no_argument, NULL, 's' },
|
||||
{ "allow-non-ssl", no_argument, NULL, 'a' },
|
||||
{ "interface", required_argument, NULL, 'i' },
|
||||
{ "closetest", no_argument, NULL, 'c' },
|
||||
{ "libevent", no_argument, NULL, 'e' },
|
||||
#ifndef LWS_NO_DAEMONIZE
|
||||
{ "daemonize", no_argument, NULL, 'D' },
|
||||
#endif
|
||||
{ "resource_path", required_argument, NULL, 'r' },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int sigs[] = { SIGINT, SIGKILL, SIGTERM, SIGSEGV, SIGFPE };
|
||||
struct event *signals[ARRAY_SIZE(sigs)];
|
||||
struct event_base *event_base_loop = event_base_new();
|
||||
struct lws_context_creation_info info;
|
||||
char interface_name[128] = "";
|
||||
const char *iface = NULL;
|
||||
struct event *timeout_watcher;
|
||||
char cert_path[1024];
|
||||
char key_path[1024];
|
||||
int use_ssl = 0;
|
||||
int opts = 0;
|
||||
int n = 0;
|
||||
#ifndef _WIN32
|
||||
int syslog_options = LOG_PID | LOG_PERROR;
|
||||
#endif
|
||||
#ifndef LWS_NO_DAEMONIZE
|
||||
int daemonize = 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* take care to zero down the info struct, he contains random garbaage
|
||||
* from the stack otherwise
|
||||
*/
|
||||
memset(&info, 0, sizeof info);
|
||||
info.port = 7681;
|
||||
|
||||
while (n >= 0) {
|
||||
n = getopt_long(argc, argv, "eci:hsap:d:Dr:", options, NULL);
|
||||
if (n < 0)
|
||||
continue;
|
||||
switch (n) {
|
||||
case 'e':
|
||||
opts |= LWS_SERVER_OPTION_LIBEVENT;
|
||||
break;
|
||||
#ifndef LWS_NO_DAEMONIZE
|
||||
case 'D':
|
||||
daemonize = 1;
|
||||
#ifndef _WIN32
|
||||
syslog_options &= ~LOG_PERROR;
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
case 'd':
|
||||
debug_level = atoi(optarg);
|
||||
break;
|
||||
case 's':
|
||||
use_ssl = 1;
|
||||
break;
|
||||
case 'a':
|
||||
opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
|
||||
break;
|
||||
case 'p':
|
||||
info.port = atoi(optarg);
|
||||
break;
|
||||
case 'i':
|
||||
strncpy(interface_name, optarg, sizeof interface_name);
|
||||
interface_name[(sizeof interface_name) - 1] = '\0';
|
||||
iface = interface_name;
|
||||
break;
|
||||
case 'c':
|
||||
close_testing = 1;
|
||||
fprintf(stderr, " Close testing mode -- closes on "
|
||||
"client after 50 dumb increments"
|
||||
"and suppresses lws_mirror spam\n");
|
||||
break;
|
||||
case 'r':
|
||||
resource_path = optarg;
|
||||
printf("Setting resource path to \"%s\"\n", resource_path);
|
||||
break;
|
||||
case 'h':
|
||||
fprintf(stderr, "Usage: test-server "
|
||||
"[--port=<p>] [--ssl] "
|
||||
"[-d <log bitfield>] "
|
||||
"[--resource_path <path>]\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32)
|
||||
/*
|
||||
* normally lock path would be /var/lock/lwsts or similar, to
|
||||
* simplify getting started without having to take care about
|
||||
* permissions or running as root, set to /tmp/.lwsts-lock
|
||||
*/
|
||||
if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) {
|
||||
fprintf(stderr, "Failed to daemonize\n");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (n = 0; n < ARRAY_SIZE(sigs); n++) {
|
||||
signals[n] = evsignal_new(event_base_loop, sigs[n], signal_cb, event_base_loop);
|
||||
|
||||
evsignal_add(signals[n], NULL);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
/* we will only try to log things according to our debug_level */
|
||||
setlogmask(LOG_UPTO (LOG_DEBUG));
|
||||
openlog("lwsts", syslog_options, LOG_DAEMON);
|
||||
#endif
|
||||
|
||||
/* tell the library what debug level to emit and to send it to syslog */
|
||||
lws_set_log_level(debug_level, lwsl_emit_syslog);
|
||||
|
||||
lwsl_notice("libwebsockets test server libevent - license LGPL2.1+SLE\n");
|
||||
lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n");
|
||||
|
||||
printf("Using resource path \"%s\"\n", resource_path);
|
||||
|
||||
info.iface = iface;
|
||||
info.protocols = protocols;
|
||||
info.extensions = exts;
|
||||
|
||||
info.ssl_cert_filepath = NULL;
|
||||
info.ssl_private_key_filepath = NULL;
|
||||
|
||||
if (use_ssl) {
|
||||
if (strlen(resource_path) > sizeof(cert_path) - 32) {
|
||||
lwsl_err("resource path too long\n");
|
||||
return -1;
|
||||
}
|
||||
sprintf(cert_path, "%s/libwebsockets-test-server.pem",
|
||||
resource_path);
|
||||
if (strlen(resource_path) > sizeof(key_path) - 32) {
|
||||
lwsl_err("resource path too long\n");
|
||||
return -1;
|
||||
}
|
||||
sprintf(key_path, "%s/libwebsockets-test-server.key.pem",
|
||||
resource_path);
|
||||
|
||||
info.ssl_cert_filepath = cert_path;
|
||||
info.ssl_private_key_filepath = key_path;
|
||||
|
||||
opts |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||
}
|
||||
info.gid = -1;
|
||||
info.uid = -1;
|
||||
info.max_http_header_pool = 1;
|
||||
info.options = opts | LWS_SERVER_OPTION_LIBEVENT;
|
||||
|
||||
context = lws_create_context(&info);
|
||||
if (context == NULL) {
|
||||
lwsl_err("libwebsocket init failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* this shows how to override the lws file operations. You don't need
|
||||
* to do any of this unless you have a reason (eg, want to serve
|
||||
* compressed files without decompressing the whole archive)
|
||||
*/
|
||||
/* stash original platform fops */
|
||||
fops_plat = *(lws_get_fops(context));
|
||||
/* override the active fops */
|
||||
lws_get_fops(context)->open = test_server_fops_open;
|
||||
|
||||
// Don't use the default Signal Event Watcher & Handler
|
||||
lws_event_sigint_cfg(context, 0, NULL);
|
||||
// Initialize the LWS with libevent loop
|
||||
lws_event_initloop(context, event_base_loop, 0);
|
||||
|
||||
timeout_watcher = event_new(event_base_loop, -1, EV_PERSIST, ev_timeout_cb, NULL);
|
||||
struct timeval tv = {0, 50000};
|
||||
evtimer_add(timeout_watcher, &tv);
|
||||
event_base_dispatch(event_base_loop);
|
||||
|
||||
lws_context_destroy(context);
|
||||
lwsl_notice("libwebsockets-test-server exited cleanly\n");
|
||||
|
||||
#ifndef _WIN32
|
||||
closelog();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -19,6 +19,7 @@
|
|||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define DI_HANDLED_BY_PLUGIN
|
||||
#include "test-server.h"
|
||||
#include <uv.h>
|
||||
|
||||
|
@ -45,6 +46,12 @@ void test_server_unlock(int care)
|
|||
{
|
||||
}
|
||||
|
||||
#define LWS_PLUGIN_STATIC
|
||||
#include "../plugins/protocol_dumb_increment.c"
|
||||
#include "../plugins/protocol_lws_mirror.c"
|
||||
#include "../plugins/protocol_lws_status.c"
|
||||
#include "../plugins/protocol_lws_meta.c"
|
||||
|
||||
/*
|
||||
* This demo server shows how to use libwebsockets for one or more
|
||||
* websocket protocols in the same server
|
||||
|
@ -66,6 +73,8 @@ enum demo_protocols {
|
|||
|
||||
PROTOCOL_DUMB_INCREMENT,
|
||||
PROTOCOL_LWS_MIRROR,
|
||||
PROTOCOL_LWS_STATUS,
|
||||
PROTOCOL_LWS_META,
|
||||
|
||||
/* always last */
|
||||
DEMO_PROTOCOL_COUNT
|
||||
|
@ -82,24 +91,10 @@ static struct lws_protocols protocols[] = {
|
|||
sizeof (struct per_session_data__http), /* per_session_data_size */
|
||||
0, /* max frame size / rx buffer */
|
||||
},
|
||||
{
|
||||
"dumb-increment-protocol",
|
||||
callback_dumb_increment,
|
||||
sizeof(struct per_session_data__dumb_increment),
|
||||
10,
|
||||
},
|
||||
{
|
||||
"lws-mirror-protocol",
|
||||
callback_lws_mirror,
|
||||
sizeof(struct per_session_data__lws_mirror),
|
||||
128,
|
||||
},
|
||||
{
|
||||
"lws-status",
|
||||
callback_lws_status,
|
||||
sizeof(struct per_session_data__lws_status),
|
||||
128,
|
||||
},
|
||||
LWS_PLUGIN_PROTOCOL_DUMB_INCREMENT,
|
||||
LWS_PLUGIN_PROTOCOL_MIRROR,
|
||||
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
|
||||
LWS_PLUGIN_PROTOCOL_LWS_META,
|
||||
{ NULL, NULL, 0, 0 } /* terminator */
|
||||
};
|
||||
|
||||
|
@ -132,16 +127,6 @@ void signal_cb(uv_signal_t *watcher, int signum)
|
|||
lws_libuv_stop(context);
|
||||
}
|
||||
|
||||
static void
|
||||
uv_timeout_cb_dumb_increment(uv_timer_t *w
|
||||
#if UV_VERSION_MAJOR == 0
|
||||
, int status
|
||||
#endif
|
||||
)
|
||||
{
|
||||
lws_callback_on_writable_all_protocol(context,
|
||||
&protocols[PROTOCOL_DUMB_INCREMENT]);
|
||||
}
|
||||
|
||||
static struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
|
@ -222,7 +207,6 @@ int main(int argc, char **argv)
|
|||
int foreign_libuv_loop = 0;
|
||||
/* <--- only needed for foreign loop test --- */
|
||||
#endif
|
||||
uv_timer_t timeout_watcher;
|
||||
const char *iface = NULL;
|
||||
char cert_path[1024];
|
||||
char key_path[1024];
|
||||
|
@ -406,9 +390,6 @@ int main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
uv_timer_init(lws_uv_getloop(context, 0), &timeout_watcher);
|
||||
uv_timer_start(&timeout_watcher, uv_timeout_cb_dumb_increment, 50, 50);
|
||||
|
||||
#if UV_VERSION_MAJOR > 0
|
||||
if (foreign_libuv_loop) {
|
||||
/*
|
||||
|
@ -437,8 +418,6 @@ int main(int argc, char **argv)
|
|||
uv_timer_stop(&timer_inner);
|
||||
uv_close((uv_handle_t*)&timer_inner, timer_close_cb);
|
||||
|
||||
/* stop the dumb increment timer */
|
||||
uv_timer_stop(&timeout_watcher);
|
||||
|
||||
lwsl_notice("Destroying lws context\n");
|
||||
|
||||
|
@ -480,6 +459,9 @@ int main(int argc, char **argv)
|
|||
lwsl_notice("uv loop close rc %s\n",
|
||||
e ? uv_strerror(e) : "ok");
|
||||
|
||||
/* PHASE 4: finalize context destruction */
|
||||
|
||||
lws_context_destroy2(context);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
|
@ -487,9 +469,12 @@ int main(int argc, char **argv)
|
|||
|
||||
bail:
|
||||
lws_context_destroy(context);
|
||||
lws_context_destroy2(context);
|
||||
}
|
||||
|
||||
lwsl_notice("libwebsockets-test-server exited cleanly\n");
|
||||
|
||||
context = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,137 +0,0 @@
|
|||
/*
|
||||
* libwebsockets-test-server - libwebsockets test implementation
|
||||
*
|
||||
* Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
*
|
||||
* The person who associated a work with this deed has dedicated
|
||||
* the work to the public domain by waiving all of his or her rights
|
||||
* to the work worldwide under copyright law, including all related
|
||||
* and neighboring rights, to the extent allowed by law. You can copy,
|
||||
* modify, distribute and perform the work, even for commercial purposes,
|
||||
* all without asking permission.
|
||||
*
|
||||
* The test apps are intended to be adapted for use in your code, which
|
||||
* may be proprietary. So unlike the library itself, they are licensed
|
||||
* Public Domain.
|
||||
*/
|
||||
#include "test-server.h"
|
||||
|
||||
/* lws-mirror_protocol */
|
||||
|
||||
#define MAX_MESSAGE_QUEUE 512
|
||||
|
||||
struct a_message {
|
||||
void *payload;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
static struct a_message ringbuffer[MAX_MESSAGE_QUEUE];
|
||||
static int ringbuffer_head;
|
||||
|
||||
int
|
||||
callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
struct per_session_data__lws_mirror *pss =
|
||||
(struct per_session_data__lws_mirror *)user;
|
||||
int n, m;
|
||||
|
||||
switch (reason) {
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
lwsl_info("%s: LWS_CALLBACK_ESTABLISHED\n", __func__);
|
||||
pss->ringbuffer_tail = ringbuffer_head;
|
||||
pss->wsi = wsi;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_PROTOCOL_DESTROY:
|
||||
lwsl_notice("%s: mirror protocol cleaning up\n", __func__);
|
||||
for (n = 0; n < sizeof ringbuffer / sizeof ringbuffer[0]; n++)
|
||||
if (ringbuffer[n].payload)
|
||||
free(ringbuffer[n].payload);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_SERVER_WRITEABLE:
|
||||
if (close_testing)
|
||||
break;
|
||||
while (pss->ringbuffer_tail != ringbuffer_head) {
|
||||
m = ringbuffer[pss->ringbuffer_tail].len;
|
||||
n = lws_write(wsi, (unsigned char *)
|
||||
ringbuffer[pss->ringbuffer_tail].payload +
|
||||
LWS_PRE, m, LWS_WRITE_TEXT);
|
||||
if (n < 0) {
|
||||
lwsl_err("ERROR %d writing to mirror socket\n", n);
|
||||
return -1;
|
||||
}
|
||||
if (n < m)
|
||||
lwsl_err("mirror partial write %d vs %d\n", n, m);
|
||||
|
||||
if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1))
|
||||
pss->ringbuffer_tail = 0;
|
||||
else
|
||||
pss->ringbuffer_tail++;
|
||||
|
||||
if (((ringbuffer_head - pss->ringbuffer_tail) &
|
||||
(MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 15))
|
||||
lws_rx_flow_allow_all_protocol(lws_get_context(wsi),
|
||||
lws_get_protocol(wsi));
|
||||
|
||||
if (lws_send_pipe_choked(wsi)) {
|
||||
lws_callback_on_writable(wsi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RECEIVE:
|
||||
if (((ringbuffer_head - pss->ringbuffer_tail) &
|
||||
(MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 1)) {
|
||||
lwsl_err("dropping!\n");
|
||||
goto choke;
|
||||
}
|
||||
|
||||
if (ringbuffer[ringbuffer_head].payload)
|
||||
free(ringbuffer[ringbuffer_head].payload);
|
||||
|
||||
ringbuffer[ringbuffer_head].payload = malloc(LWS_PRE + len);
|
||||
ringbuffer[ringbuffer_head].len = len;
|
||||
memcpy((char *)ringbuffer[ringbuffer_head].payload +
|
||||
LWS_PRE, in, len);
|
||||
if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
|
||||
ringbuffer_head = 0;
|
||||
else
|
||||
ringbuffer_head++;
|
||||
|
||||
if (((ringbuffer_head - pss->ringbuffer_tail) &
|
||||
(MAX_MESSAGE_QUEUE - 1)) != (MAX_MESSAGE_QUEUE - 2))
|
||||
goto done;
|
||||
|
||||
choke:
|
||||
lwsl_debug("LWS_CALLBACK_RECEIVE: throttling %p\n", wsi);
|
||||
lws_rx_flow_control(wsi, 0);
|
||||
|
||||
done:
|
||||
lws_callback_on_writable_all_protocol(lws_get_context(wsi),
|
||||
lws_get_protocol(wsi));
|
||||
break;
|
||||
|
||||
/*
|
||||
* this just demonstrates how to use the protocol filter. If you won't
|
||||
* study and reject connections based on header content, you don't need
|
||||
* to handle this callback
|
||||
*/
|
||||
|
||||
case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
|
||||
dump_handshake_info(wsi);
|
||||
/* you could return non-zero here and kill the connection */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -37,6 +37,10 @@ struct lws_context *context;
|
|||
char crl_path[1024] = "";
|
||||
#endif
|
||||
|
||||
#define LWS_PLUGIN_STATIC
|
||||
#include "../plugins/protocol_lws_mirror.c"
|
||||
#include "../plugins/protocol_lws_status.c"
|
||||
|
||||
/*
|
||||
* This mutex lock protects code that changes or relies on wsi list outside of
|
||||
* the service thread. The service thread will acquire it when changing the
|
||||
|
@ -87,6 +91,7 @@ enum demo_protocols {
|
|||
|
||||
PROTOCOL_DUMB_INCREMENT,
|
||||
PROTOCOL_LWS_MIRROR,
|
||||
PROTOCOL_LWS_STATUS,
|
||||
|
||||
/* always last */
|
||||
DEMO_PROTOCOL_COUNT
|
||||
|
@ -107,14 +112,13 @@ static struct lws_protocols protocols[] = {
|
|||
"dumb-increment-protocol",
|
||||
callback_dumb_increment,
|
||||
sizeof(struct per_session_data__dumb_increment),
|
||||
10,
|
||||
},
|
||||
{
|
||||
"lws-mirror-protocol",
|
||||
callback_lws_mirror,
|
||||
sizeof(struct per_session_data__lws_mirror),
|
||||
128,
|
||||
10, /* rx buf size must be >= permessage-deflate rx size
|
||||
* dumb-increment only sends very small packets, so we set
|
||||
* this accordingly. If your protocol will send bigger
|
||||
* things, adjust this to match */
|
||||
},
|
||||
LWS_PLUGIN_PROTOCOL_MIRROR,
|
||||
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
|
||||
{ NULL, NULL, 0, 0 } /* terminator */
|
||||
};
|
||||
|
||||
|
@ -138,7 +142,7 @@ void *thread_dumb_increment(void *threadid)
|
|||
|
||||
void *thread_service(void *threadid)
|
||||
{
|
||||
while (lws_service_tsi(context, 50, (int)(long)threadid) >= 0 && !force_exit)
|
||||
while (lws_service_tsi(context, 50, (int)(lws_intptr_t)threadid) >= 0 && !force_exit)
|
||||
;
|
||||
|
||||
pthread_exit(NULL);
|
||||
|
@ -364,7 +368,7 @@ int main(int argc, char **argv)
|
|||
|
||||
for (n = 0; n < lws_get_count_threads(context); n++)
|
||||
if (pthread_create(&pthread_service[n], NULL, thread_service,
|
||||
(void *)(long)n))
|
||||
(void *)(lws_intptr_t)n))
|
||||
lwsl_err("Failed to start service thread\n");
|
||||
|
||||
/* wait for all the service threads to exit */
|
||||
|
|
|
@ -1,173 +0,0 @@
|
|||
/*
|
||||
* libwebsockets-test-server - libwebsockets test implementation
|
||||
*
|
||||
* Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
*
|
||||
* The person who associated a work with this deed has dedicated
|
||||
* the work to the public domain by waiving all of his or her rights
|
||||
* to the work worldwide under copyright law, including all related
|
||||
* and neighboring rights, to the extent allowed by law. You can copy,
|
||||
* modify, distribute and perform the work, even for commercial purposes,
|
||||
* all without asking permission.
|
||||
*
|
||||
* The test apps are intended to be adapted for use in your code, which
|
||||
* may be proprietary. So unlike the library itself, they are licensed
|
||||
* Public Domain.
|
||||
*/
|
||||
#include "test-server.h"
|
||||
#include <time.h>
|
||||
|
||||
static unsigned char server_info[1024];
|
||||
static int server_info_len;
|
||||
static int current;
|
||||
static char cache[16384];
|
||||
static int cache_len;
|
||||
static struct per_session_data__lws_status *list;
|
||||
static int live_wsi;
|
||||
|
||||
|
||||
static void
|
||||
update_status(struct lws *wsi, struct per_session_data__lws_status *pss)
|
||||
{
|
||||
struct per_session_data__lws_status **pp = &list;
|
||||
int subsequent = 0;
|
||||
char *p = cache + LWS_PRE, *start = p;
|
||||
char date[128];
|
||||
time_t t;
|
||||
struct tm *ptm;
|
||||
#ifndef WIN32
|
||||
struct tm tm;
|
||||
#endif
|
||||
|
||||
p += lws_snprintf(p, 512, " { %s, \"wsi\":\"%d\", \"conns\":[",
|
||||
server_info, live_wsi);
|
||||
|
||||
/* render the list */
|
||||
while (*pp) {
|
||||
t = (*pp)->tv_established.tv_sec;
|
||||
#ifdef WIN32
|
||||
ptm = localtime(&t);
|
||||
if (!ptm)
|
||||
#else
|
||||
ptm = &tm;
|
||||
if (!localtime_r(&t, &tm))
|
||||
#endif
|
||||
strcpy(date, "unknown");
|
||||
else
|
||||
#ifdef WIN32
|
||||
strftime(date, sizeof(date), "%Y %H:%M %Z", ptm);
|
||||
#else
|
||||
strftime(date, sizeof(date), "%F %H:%M %Z", ptm);
|
||||
#endif
|
||||
if ((p - start) > (sizeof(cache) - 512))
|
||||
break;
|
||||
if (subsequent)
|
||||
*p++ = ',';
|
||||
subsequent = 1;
|
||||
p += lws_snprintf(p, sizeof(cache) - (p - start) - 1,
|
||||
"{\"peer\":\"%s\",\"time\":\"%s\","
|
||||
"\"ua\":\"%s\"}",
|
||||
(*pp)->ip, date, (*pp)->user_agent);
|
||||
pp = &((*pp)->list);
|
||||
}
|
||||
|
||||
p += sprintf(p, "]}");
|
||||
cache_len = p - start;
|
||||
lwsl_err("cache_len %d\n", cache_len);
|
||||
*p = '\0';
|
||||
|
||||
/* since we changed the list, increment the 'version' */
|
||||
current++;
|
||||
/* update everyone */
|
||||
lws_callback_on_writable_all_protocol(lws_get_context(wsi),
|
||||
lws_get_protocol(wsi));
|
||||
}
|
||||
|
||||
|
||||
/* lws-status protocol */
|
||||
|
||||
int
|
||||
callback_lws_status(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
struct per_session_data__lws_status *pss =
|
||||
(struct per_session_data__lws_status *)user,
|
||||
**pp;
|
||||
char name[128], rip[128];
|
||||
int m;
|
||||
|
||||
switch (reason) {
|
||||
|
||||
case LWS_CALLBACK_PROTOCOL_INIT:
|
||||
/*
|
||||
* Prepare the static server info
|
||||
*/
|
||||
server_info_len = sprintf((char *)server_info,
|
||||
"\"version\":\"%s\","
|
||||
" \"hostname\":\"%s\"",
|
||||
lws_get_library_version(),
|
||||
lws_canonical_hostname(
|
||||
lws_get_context(wsi)));
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
/*
|
||||
* we keep a linked list of live pss, so we can walk it
|
||||
*/
|
||||
pss->last = 0;
|
||||
pss->list = list;
|
||||
list = pss;
|
||||
live_wsi++;
|
||||
lws_get_peer_addresses(wsi, lws_get_socket_fd(wsi), name,
|
||||
sizeof(name), rip, sizeof(rip));
|
||||
sprintf(pss->ip, "%s (%s)", name, rip);
|
||||
gettimeofday(&pss->tv_established, NULL);
|
||||
strcpy(pss->user_agent, "unknown");
|
||||
lws_hdr_copy(wsi, pss->user_agent, sizeof(pss->user_agent),
|
||||
WSI_TOKEN_HTTP_USER_AGENT);
|
||||
update_status(wsi, pss);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RECEIVE:
|
||||
lwsl_notice("pmd test: RX len %d\n", (int)len);
|
||||
puts(in);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_SERVER_WRITEABLE:
|
||||
m = lws_write(wsi, (unsigned char *)cache + LWS_PRE, cache_len,
|
||||
LWS_WRITE_TEXT);
|
||||
if (m < server_info_len) {
|
||||
lwsl_err("ERROR %d writing to di socket\n", m);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLOSED:
|
||||
/*
|
||||
* remove ourselves from live pss list
|
||||
*/
|
||||
lwsl_err("CLOSING pss %p ********\n", pss);
|
||||
|
||||
pp = &list;
|
||||
while (*pp) {
|
||||
if (*pp == pss) {
|
||||
*pp = pss->list;
|
||||
pss->list = NULL;
|
||||
live_wsi--;
|
||||
break;
|
||||
}
|
||||
pp = &((*pp)->list);
|
||||
}
|
||||
|
||||
update_status(wsi, pss);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -19,14 +19,27 @@
|
|||
*/
|
||||
|
||||
#include <libwebsockets.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#ifndef WIN32
|
||||
#include <syslog.h>
|
||||
#endif
|
||||
|
||||
/* windows has no SIGUSR1 */
|
||||
#if !defined(WIN32) && !defined(_WIN32)
|
||||
#define TEST_DYNAMIC_VHOST
|
||||
#endif
|
||||
|
||||
struct lws_context_creation_info info;
|
||||
int debug_level = 7;
|
||||
struct lws_context *context;
|
||||
|
||||
#if defined(TEST_DYNAMIC_VHOST)
|
||||
volatile int dynamic_vhost_enable = 0;
|
||||
struct lws_vhost *dynamic_vhost;
|
||||
uv_timer_t timeout_watcher;
|
||||
#endif
|
||||
|
||||
/* http server gets files from this path */
|
||||
#define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server"
|
||||
char *resource_path = LOCAL_RESOURCE_PATH;
|
||||
|
@ -47,6 +60,44 @@ char crl_path[1024] = "";
|
|||
* You can find the individual protocol plugin sources in ../plugins
|
||||
*/
|
||||
|
||||
#if defined(TEST_DYNAMIC_VHOST)
|
||||
|
||||
/*
|
||||
* to test dynamic vhost creation, fire a SIGUSR1 at the test server.
|
||||
* It will toggle the existence of a second identical vhost at port + 1
|
||||
*
|
||||
* To synchronize with the event loop, it uses a libuv timer with 0 delay
|
||||
* to get the business end called as the next event.
|
||||
*/
|
||||
|
||||
static void
|
||||
uv_timeout_dynamic_vhost_toggle(uv_timer_t *w
|
||||
#if UV_VERSION_MAJOR == 0
|
||||
, int status
|
||||
#endif
|
||||
)
|
||||
{
|
||||
if (dynamic_vhost_enable && !dynamic_vhost) {
|
||||
lwsl_notice("creating dynamic vhost...\n");
|
||||
dynamic_vhost = lws_create_vhost(context, &info);
|
||||
} else
|
||||
if (!dynamic_vhost_enable && dynamic_vhost) {
|
||||
lwsl_notice("destroying dynamic vhost...\n");
|
||||
lws_vhost_destroy(dynamic_vhost);
|
||||
dynamic_vhost = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void sighandler_USR1(int sig)
|
||||
{
|
||||
dynamic_vhost_enable ^= 1;
|
||||
lwsl_notice("SIGUSR1: dynamic_vhost_enable: %d\n",
|
||||
dynamic_vhost_enable);
|
||||
uv_timer_start(&timeout_watcher,
|
||||
uv_timeout_dynamic_vhost_toggle, 0, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void sighandler(int sig)
|
||||
{
|
||||
lws_cancel_service(context);
|
||||
|
@ -147,13 +198,14 @@ static const struct lws_http_mount mount = {
|
|||
* the effect is to set this protocol to be the default one for the vhost,
|
||||
* ie, selected if no Protocol: header is sent with the ws upgrade.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
static const struct lws_protocol_vhost_options pvo_opt = {
|
||||
NULL,
|
||||
NULL,
|
||||
"default",
|
||||
"1"
|
||||
};
|
||||
#endif
|
||||
|
||||
static const struct lws_protocol_vhost_options pvo_opt4a = {
|
||||
NULL,
|
||||
|
@ -174,8 +226,15 @@ static const struct lws_protocol_vhost_options pvo_opt4 = {
|
|||
* linked-list. We can also give the plugin per-vhost options here.
|
||||
*/
|
||||
|
||||
static const struct lws_protocol_vhost_options pvo_4 = {
|
||||
static const struct lws_protocol_vhost_options pvo_5 = {
|
||||
NULL,
|
||||
NULL,
|
||||
"lws-meta",
|
||||
"" /* ignored, just matches the protocol name above */
|
||||
};
|
||||
|
||||
static const struct lws_protocol_vhost_options pvo_4 = {
|
||||
&pvo_5,
|
||||
&pvo_opt4, /* set us as the protocol who gets raw connections */
|
||||
"protocol-lws-raw-test",
|
||||
"" /* ignored, just matches the protocol name above */
|
||||
|
@ -204,7 +263,7 @@ static const struct lws_protocol_vhost_options pvo_1 = {
|
|||
|
||||
static const struct lws_protocol_vhost_options pvo = {
|
||||
&pvo_1,
|
||||
&pvo_opt,
|
||||
NULL, // &pvo_opt,
|
||||
"dumb-increment-protocol",
|
||||
""
|
||||
};
|
||||
|
@ -229,6 +288,7 @@ static const struct option options[] = {
|
|||
{ "debug", required_argument, NULL, 'd' },
|
||||
{ "port", required_argument, NULL, 'p' },
|
||||
{ "ssl", no_argument, NULL, 's' },
|
||||
{ "ssl-alerts", no_argument, NULL, 'S' },
|
||||
{ "allow-non-ssl", no_argument, NULL, 'a' },
|
||||
{ "interface", required_argument, NULL, 'i' },
|
||||
{ "ssl-cert", required_argument, NULL, 'C' },
|
||||
|
@ -254,7 +314,7 @@ static const char * const plugin_dirs[] = {
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct lws_context_creation_info info;
|
||||
struct lws_vhost *vhost;
|
||||
char interface_name[128] = "";
|
||||
const char *iface = NULL;
|
||||
char cert_path[1024] = "";
|
||||
|
@ -279,7 +339,7 @@ int main(int argc, char **argv)
|
|||
info.port = 7681;
|
||||
|
||||
while (n >= 0) {
|
||||
n = getopt_long(argc, argv, "i:hsap:d:Dr:C:K:A:R:vu:g:",
|
||||
n = getopt_long(argc, argv, "i:hsap:d:Dr:C:K:A:R:vu:g:S",
|
||||
(struct option *)options, NULL);
|
||||
if (n < 0)
|
||||
continue;
|
||||
|
@ -304,6 +364,11 @@ int main(int argc, char **argv)
|
|||
case 's':
|
||||
use_ssl = 1;
|
||||
break;
|
||||
case 'S':
|
||||
#if defined(LWS_OPENSSL_SUPPORT)
|
||||
info.ssl_info_event_mask |= SSL_CB_ALERT;
|
||||
#endif
|
||||
break;
|
||||
case 'a':
|
||||
opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
|
||||
break;
|
||||
|
@ -366,6 +431,9 @@ int main(int argc, char **argv)
|
|||
#endif
|
||||
|
||||
signal(SIGINT, sighandler);
|
||||
#if defined(TEST_DYNAMIC_VHOST)
|
||||
signal(SIGUSR1, sighandler_USR1);
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
/* we will only try to log things according to our debug_level */
|
||||
|
@ -377,7 +445,7 @@ int main(int argc, char **argv)
|
|||
lws_set_log_level(debug_level, lwsl_emit_syslog);
|
||||
|
||||
lwsl_notice("libwebsockets test server - license LGPL2.1+SLE\n");
|
||||
lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n");
|
||||
lwsl_notice("(C) Copyright 2010-2017 Andy Green <andy@warmcat.com>\n");
|
||||
|
||||
lwsl_notice(" Using resource path \"%s\"\n", resource_path);
|
||||
|
||||
|
@ -388,7 +456,8 @@ int main(int argc, char **argv)
|
|||
info.gid = gid;
|
||||
info.uid = uid;
|
||||
info.max_http_header_pool = 16;
|
||||
info.options = opts | LWS_SERVER_OPTION_FALLBACK_TO_RAW |
|
||||
info.options = opts | LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
|
||||
LWS_SERVER_OPTION_FALLBACK_TO_RAW |
|
||||
LWS_SERVER_OPTION_VALIDATE_UTF8 |
|
||||
LWS_SERVER_OPTION_LIBUV; /* plugins require this */
|
||||
|
||||
|
@ -439,17 +508,16 @@ int main(int argc, char **argv)
|
|||
/* tell lws about our mount we want */
|
||||
info.mounts = &mount;
|
||||
/*
|
||||
* give it our linked-list of Per-Vhost Options, these control
|
||||
* give it our linked-list of Per-Vhost Options, these control
|
||||
* which protocols (from plugins) are allowed to be enabled on
|
||||
* our vhost
|
||||
*/
|
||||
info.pvo = &pvo;
|
||||
|
||||
/*
|
||||
* As it is, this creates the context and a single Vhost at the same
|
||||
* time. You can use LWS_SERVER_OPTION_EXPLICIT_VHOSTS option above
|
||||
* to just create the context, and call lws_create_vhost() afterwards
|
||||
* multiple times with different info to get multiple listening vhosts.
|
||||
* Since we used LWS_SERVER_OPTION_EXPLICIT_VHOSTS, this only creates
|
||||
* the context. We can modify info and create as many vhosts as we
|
||||
* like subsequently.
|
||||
*/
|
||||
context = lws_create_context(&info);
|
||||
if (context == NULL) {
|
||||
|
@ -457,15 +525,42 @@ int main(int argc, char **argv)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* normally we would adapt at least info.name to reflect the
|
||||
* external hostname for this server.
|
||||
*/
|
||||
vhost = lws_create_vhost(context, &info);
|
||||
if (!vhost) {
|
||||
lwsl_err("vhost creation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(TEST_DYNAMIC_VHOST)
|
||||
/* our dynamic vhost is on port + 1 */
|
||||
info.port++;
|
||||
#endif
|
||||
|
||||
/* libuv event loop */
|
||||
lws_uv_sigint_cfg(context, 1, signal_cb);
|
||||
if (lws_uv_initloop(context, NULL, 0))
|
||||
if (lws_uv_initloop(context, NULL, 0)) {
|
||||
lwsl_err("lws_uv_initloop failed\n");
|
||||
else
|
||||
lws_libuv_run(context, 0);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
#if defined(TEST_DYNAMIC_VHOST)
|
||||
uv_timer_init(lws_uv_getloop(context, 0), &timeout_watcher);
|
||||
#endif
|
||||
lws_libuv_run(context, 0);
|
||||
|
||||
#if defined(TEST_DYNAMIC_VHOST)
|
||||
uv_timer_stop(&timeout_watcher);
|
||||
uv_close((uv_handle_t *)&timeout_watcher, NULL);
|
||||
#endif
|
||||
|
||||
bail:
|
||||
/* when we decided to exit the event loop */
|
||||
lws_context_destroy(context);
|
||||
lws_context_destroy2(context);
|
||||
lwsl_notice("libwebsockets-test-server exited cleanly\n");
|
||||
|
||||
#ifndef _WIN32
|
||||
|
|
|
@ -29,7 +29,8 @@ struct lws_pollfd *pollfds;
|
|||
int *fd_lookup;
|
||||
int count_pollfds;
|
||||
#endif
|
||||
volatile int force_exit = 0;
|
||||
volatile int force_exit = 0, dynamic_vhost_enable = 0;
|
||||
struct lws_vhost *dynamic_vhost;
|
||||
struct lws_context *context;
|
||||
struct lws_plat_file_ops fops_plat;
|
||||
|
||||
|
@ -40,6 +41,35 @@ char *resource_path = LOCAL_RESOURCE_PATH;
|
|||
char crl_path[1024] = "";
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This demonstrates how to use the clean protocol service separation of
|
||||
* plugins, but with static inclusion instead of runtime dynamic loading
|
||||
* (which requires libuv).
|
||||
*
|
||||
* dumb-increment doesn't use the plugin, both to demonstrate how to
|
||||
* do the protocols directly, and because it wants libuv for a timer.
|
||||
*
|
||||
* Please consider using test-server-v2.0.c instead of this: it has the
|
||||
* same functionality but
|
||||
*
|
||||
* 1) uses lws built-in http handling so you don't need to deal with it in
|
||||
* your callback
|
||||
*
|
||||
* 2) Links with libuv and uses the plugins at runtime
|
||||
*
|
||||
* 3) Uses advanced lws features like mounts to bind parts of the filesystem
|
||||
* to the served URL space
|
||||
*
|
||||
* Another option is lwsws, this operates like test-server-v2,0.c but is
|
||||
* configured using JSON, do you do not need to provide any code for the
|
||||
* serving action at all, just implement your protocols in plugins.
|
||||
*/
|
||||
|
||||
#define LWS_PLUGIN_STATIC
|
||||
#include "../plugins/protocol_lws_mirror.c"
|
||||
#include "../plugins/protocol_lws_status.c"
|
||||
#include "../plugins/protocol_lws_meta.c"
|
||||
|
||||
/* singlethreaded version --> no locks */
|
||||
|
||||
void test_server_lock(int care)
|
||||
|
@ -62,6 +92,9 @@ void test_server_unlock(int care)
|
|||
*
|
||||
* lws-mirror-protocol: copies any received packet to every connection also
|
||||
* using this protocol, including the sender
|
||||
*
|
||||
* lws-status: informs connected browsers of who else is
|
||||
* connected.
|
||||
*/
|
||||
|
||||
enum demo_protocols {
|
||||
|
@ -70,9 +103,10 @@ enum demo_protocols {
|
|||
|
||||
PROTOCOL_DUMB_INCREMENT,
|
||||
PROTOCOL_LWS_MIRROR,
|
||||
PROTOCOL_LWS_ECHOGEN,
|
||||
PROTOCOL_LWS_STATUS,
|
||||
|
||||
PROTOCOL_LWS_META,
|
||||
|
||||
/* always last */
|
||||
DEMO_PROTOCOL_COUNT
|
||||
};
|
||||
|
@ -92,26 +126,15 @@ static struct lws_protocols protocols[] = {
|
|||
"dumb-increment-protocol",
|
||||
callback_dumb_increment,
|
||||
sizeof(struct per_session_data__dumb_increment),
|
||||
10, /* rx buf size must be >= permessage-deflate rx size */
|
||||
},
|
||||
{
|
||||
"lws-mirror-protocol",
|
||||
callback_lws_mirror,
|
||||
sizeof(struct per_session_data__lws_mirror),
|
||||
128, /* rx buf size must be >= permessage-deflate rx size */
|
||||
},
|
||||
{
|
||||
"lws-echogen",
|
||||
callback_lws_echogen,
|
||||
sizeof(struct per_session_data__echogen),
|
||||
128, /* rx buf size must be >= permessage-deflate rx size */
|
||||
},
|
||||
{
|
||||
"lws-status",
|
||||
callback_lws_status,
|
||||
sizeof(struct per_session_data__lws_status),
|
||||
128, /* rx buf size must be >= permessage-deflate rx size */
|
||||
10, /* rx buf size must be >= permessage-deflate rx size
|
||||
* dumb-increment only sends very small packets, so we set
|
||||
* this accordingly. If your protocol will send bigger
|
||||
* things, adjust this to match */
|
||||
},
|
||||
LWS_PLUGIN_PROTOCOL_MIRROR,
|
||||
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
|
||||
|
||||
LWS_PLUGIN_PROTOCOL_LWS_META,
|
||||
{ NULL, NULL, 0, 0 } /* terminator */
|
||||
};
|
||||
|
||||
|
@ -142,6 +165,20 @@ test_server_fops_open(const struct lws_plat_file_ops *fops,
|
|||
|
||||
void sighandler(int sig)
|
||||
{
|
||||
#if !defined(WIN32) && !defined(_WIN32)
|
||||
/* because windows is too dumb to have SIGUSR1... */
|
||||
if (sig == SIGUSR1) {
|
||||
/*
|
||||
* For testing, you can fire a SIGUSR1 at the test server
|
||||
* to toggle the existence of an identical server on
|
||||
* port + 1
|
||||
*/
|
||||
dynamic_vhost_enable ^= 1;
|
||||
lwsl_notice("SIGUSR1: dynamic_vhost_enable: %d\n",
|
||||
dynamic_vhost_enable);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
force_exit = 1;
|
||||
lws_cancel_service(context);
|
||||
}
|
||||
|
@ -191,6 +228,7 @@ static struct option options[] = {
|
|||
int main(int argc, char **argv)
|
||||
{
|
||||
struct lws_context_creation_info info;
|
||||
struct lws_vhost *vhost;
|
||||
char interface_name[128] = "";
|
||||
unsigned int ms, oldms = 0;
|
||||
const char *iface = NULL;
|
||||
|
@ -222,7 +260,7 @@ int main(int argc, char **argv)
|
|||
info.port = 7681;
|
||||
|
||||
while (n >= 0) {
|
||||
n = getopt_long(argc, argv, "eci:hsap:d:Dr:C:K:A:R:vu:g:P:", options, NULL);
|
||||
n = getopt_long(argc, argv, "eci:hsap:d:Dr:C:K:A:R:vu:g:P:k", options, NULL);
|
||||
if (n < 0)
|
||||
continue;
|
||||
switch (n) {
|
||||
|
@ -248,6 +286,7 @@ int main(int argc, char **argv)
|
|||
break;
|
||||
case 's':
|
||||
use_ssl = 1;
|
||||
opts |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||
break;
|
||||
case 'a':
|
||||
opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
|
||||
|
@ -260,6 +299,13 @@ int main(int argc, char **argv)
|
|||
interface_name[(sizeof interface_name) - 1] = '\0';
|
||||
iface = interface_name;
|
||||
break;
|
||||
case 'k':
|
||||
info.bind_iface = 1;
|
||||
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
|
||||
info.caps[0] = CAP_NET_RAW;
|
||||
info.count_caps = 1;
|
||||
#endif
|
||||
break;
|
||||
case 'c':
|
||||
close_testing = 1;
|
||||
fprintf(stderr, " Close testing mode -- closes on "
|
||||
|
@ -321,6 +367,11 @@ int main(int argc, char **argv)
|
|||
#endif
|
||||
|
||||
signal(SIGINT, sighandler);
|
||||
#if !defined(WIN32) && !defined(_WIN32)
|
||||
/* because windows is too dumb to have SIGUSR1... */
|
||||
/* dynamic vhost create / destroy toggle (on port + 1) */
|
||||
signal(SIGUSR1, sighandler);
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
/* we will only try to log things according to our debug_level */
|
||||
|
@ -375,7 +426,7 @@ int main(int argc, char **argv)
|
|||
info.gid = gid;
|
||||
info.uid = uid;
|
||||
info.max_http_header_pool = 16;
|
||||
info.options = opts | LWS_SERVER_OPTION_VALIDATE_UTF8;
|
||||
info.options = opts | LWS_SERVER_OPTION_VALIDATE_UTF8 | LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
|
||||
info.extensions = exts;
|
||||
info.timeout_secs = 5;
|
||||
info.ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
|
||||
|
@ -402,6 +453,24 @@ int main(int argc, char **argv)
|
|||
return -1;
|
||||
}
|
||||
|
||||
vhost = lws_create_vhost(context, &info);
|
||||
if (!vhost) {
|
||||
lwsl_err("vhost creation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* For testing dynamic vhost create / destroy later, we use port + 1
|
||||
* Normally if you were creating more vhosts, you would set info.name
|
||||
* for each to be the hostname external clients use to reach it
|
||||
*/
|
||||
|
||||
info.port++;
|
||||
|
||||
#if !defined(LWS_NO_CLIENT) && defined(LWS_OPENSSL_SUPPORT)
|
||||
lws_init_vhost_client_ssl(&info, vhost);
|
||||
#endif
|
||||
|
||||
/* this shows how to override the lws file operations. You don't need
|
||||
* to do any of this unless you have a reason (eg, want to serve
|
||||
* compressed files without decompressing the whole archive)
|
||||
|
@ -480,6 +549,17 @@ int main(int argc, char **argv)
|
|||
|
||||
n = lws_service(context, 50);
|
||||
#endif
|
||||
|
||||
if (dynamic_vhost_enable && !dynamic_vhost) {
|
||||
lwsl_notice("creating dynamic vhost...\n");
|
||||
dynamic_vhost = lws_create_vhost(context, &info);
|
||||
} else
|
||||
if (!dynamic_vhost_enable && dynamic_vhost) {
|
||||
lwsl_notice("destroying dynamic vhost...\n");
|
||||
lws_vhost_destroy(dynamic_vhost);
|
||||
dynamic_vhost = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef EXTERNAL_POLL
|
||||
|
|
|
@ -96,48 +96,22 @@ struct per_session_data__http {
|
|||
* connection.
|
||||
*/
|
||||
|
||||
#if !defined(DI_HANDLED_BY_PLUGIN)
|
||||
struct per_session_data__dumb_increment {
|
||||
int number;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct per_session_data__lws_mirror {
|
||||
struct lws *wsi;
|
||||
int ringbuffer_tail;
|
||||
};
|
||||
|
||||
struct per_session_data__echogen {
|
||||
size_t total;
|
||||
size_t total_rx;
|
||||
int fd;
|
||||
int fragsize;
|
||||
int wr;
|
||||
};
|
||||
|
||||
struct per_session_data__lws_status {
|
||||
struct per_session_data__lws_status *list;
|
||||
struct timeval tv_established;
|
||||
int last;
|
||||
char ip[270];
|
||||
char user_agent[512];
|
||||
const char *pos;
|
||||
int len;
|
||||
};
|
||||
|
||||
extern int
|
||||
callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
|
||||
void *in, size_t len);
|
||||
extern int
|
||||
callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len);
|
||||
|
||||
#if !defined(DI_HANDLED_BY_PLUGIN)
|
||||
extern int
|
||||
callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len);
|
||||
extern int
|
||||
callback_lws_echogen(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len);
|
||||
extern int
|
||||
callback_lws_status(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len);
|
||||
#endif
|
||||
|
||||
|
||||
extern void
|
||||
|
|
|
@ -490,7 +490,7 @@ document.getElementById("brow").textContent = " " + BrowserDetect.browser + " "
|
|||
|
||||
var pos = 0;
|
||||
|
||||
function get_appropriate_ws_url()
|
||||
function get_appropriate_ws_url(extra_url)
|
||||
{
|
||||
var pcol;
|
||||
var u = document.URL;
|
||||
|
@ -513,24 +513,51 @@ function get_appropriate_ws_url()
|
|||
|
||||
/* + "/xxx" bit is for IE10 workaround */
|
||||
|
||||
return pcol + u[0] + "/xxx";
|
||||
return pcol + u[0] + "/" + extra_url;
|
||||
}
|
||||
|
||||
var params = {};
|
||||
|
||||
document.getElementById("number").textContent = get_appropriate_ws_url();
|
||||
if (location.search) {
|
||||
var parts = location.search.substring(1).split('&');
|
||||
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
var nv = parts[i].split('=');
|
||||
if (!nv[0]) continue;
|
||||
params[nv[0]] = nv[1] || true;
|
||||
}
|
||||
}
|
||||
|
||||
var mirror_name = "";
|
||||
if (params.mirror)
|
||||
mirror_name = params.mirror;
|
||||
|
||||
console.log(mirror_name);
|
||||
|
||||
|
||||
/*
|
||||
* if using lws-meta to carry the other ws connections, declare the
|
||||
* parent connection object and start its connection to the server.
|
||||
*
|
||||
* These helpers are defined in lws-common.js
|
||||
*/
|
||||
|
||||
|
||||
var lws_meta = new lws_meta_ws();
|
||||
lws_meta.new_parent(get_appropriate_ws_url("?mirror=" + mirror_name));
|
||||
|
||||
|
||||
document.getElementById("number").textContent = get_appropriate_ws_url(mirror_name);
|
||||
|
||||
/* dumb increment protocol */
|
||||
|
||||
/*
|
||||
* to connect via an lws-meta connection, start the connection using
|
||||
* lws_meta.new_ws(). To connect by independent connection, start
|
||||
* the connection using just new_ws()
|
||||
*/
|
||||
|
||||
var socket_di;
|
||||
|
||||
if (typeof MozWebSocket != "undefined") {
|
||||
socket_di = new MozWebSocket(get_appropriate_ws_url(),
|
||||
"dumb-increment-protocol");
|
||||
} else {
|
||||
socket_di = new WebSocket(get_appropriate_ws_url(),
|
||||
"dumb-increment-protocol");
|
||||
}
|
||||
|
||||
var socket_di = lws_meta.new_ws("", "dumb-increment-protocol");
|
||||
|
||||
try {
|
||||
socket_di.onopen = function() {
|
||||
|
@ -554,14 +581,8 @@ document.getElementById("number").textContent = get_appropriate_ws_url();
|
|||
|
||||
var socket_status, jso, s;
|
||||
|
||||
if (typeof MozWebSocket != "undefined") {
|
||||
socket_status = new MozWebSocket(get_appropriate_ws_url(),
|
||||
"lws-status");
|
||||
} else {
|
||||
socket_status = new WebSocket(get_appropriate_ws_url(),
|
||||
"lws-status");
|
||||
}
|
||||
|
||||
socket_status = lws_meta.new_ws(get_appropriate_ws_url(""), "lws-status");
|
||||
|
||||
try {
|
||||
socket_status.onopen = function() {
|
||||
|
@ -574,6 +595,8 @@ document.getElementById("number").textContent = get_appropriate_ws_url();
|
|||
socket_status.onmessage =function got_packet(msg) {
|
||||
var s;
|
||||
|
||||
console.log(msg.data);
|
||||
|
||||
jso = JSON.parse(msg.data);
|
||||
|
||||
document.getElementById("servinfo").innerHTML =
|
||||
|
@ -625,13 +648,11 @@ function on_pmd() {
|
|||
var socket_ot;
|
||||
|
||||
function ot_open() {
|
||||
if (typeof MozWebSocket != "undefined") {
|
||||
socket_ot = new MozWebSocket(get_appropriate_ws_url(),
|
||||
"dumb-increment-protocol");
|
||||
} else {
|
||||
socket_ot = new WebSocket(get_appropriate_ws_url(),
|
||||
"dumb-increment-protocol");
|
||||
}
|
||||
|
||||
socket_ot = lws_meta.new_ws(get_appropriate_ws_url(""), "dumb-increment-protocol");
|
||||
|
||||
console.log("ot_open");
|
||||
|
||||
try {
|
||||
socket_ot.onopen = function() {
|
||||
document.getElementById("ot_statustd").style.backgroundColor = "#40ff40";
|
||||
|
@ -639,6 +660,7 @@ function ot_open() {
|
|||
document.getElementById("ot_open_btn").disabled = true;
|
||||
document.getElementById("ot_close_btn").disabled = false;
|
||||
document.getElementById("ot_req_close_btn").disabled = false;
|
||||
console.log("ot_open.onopen");
|
||||
}
|
||||
|
||||
socket_ot.onclose = function(e){
|
||||
|
@ -673,14 +695,8 @@ function ot_req_close() {
|
|||
var socket_lm;
|
||||
var color = "#000000";
|
||||
|
||||
if (typeof MozWebSocket != "undefined") {
|
||||
socket_lm = new MozWebSocket(get_appropriate_ws_url(),
|
||||
"lws-mirror-protocol");
|
||||
} else {
|
||||
socket_lm = new WebSocket(get_appropriate_ws_url(),
|
||||
"lws-mirror-protocol");
|
||||
}
|
||||
|
||||
socket_lm = lws_meta.new_ws(get_appropriate_ws_url("?mirror=" + mirror_name),
|
||||
"lws-mirror-protocol");
|
||||
|
||||
try {
|
||||
socket_lm.onopen = function() {
|
||||
|
|
Loading…
Add table
Reference in a new issue