Compare commits

..

44 commits

Author SHA1 Message Date
Cory McWilliams
fff2bb5b21 Subject: Mismatched lws_zalloc / free 2017-08-17 07:33:54 +08:00
Andy Green
12a00ea821 docs: swap _all_protocol_vhost cut and paste
https://github.com/warmcat/libwebsockets/issues/989
2017-08-16 15:23:08 +08:00
Andy Green
e99d725e76 ah: reuse at end of transaction has no timeout
If we complete a transaction but end up keeping the ah, we must force
a timeout on it.  Otherwise a bad bot could keep the socket open and
exhaust the ah pool.
2017-08-15 08:06:32 +08:00
lnmx
dc4323f837 send content-type when LWS_WITH_RANGES=OFF
https://github.com/warmcat/libwebsockets/pull/987

With the RANGES feature disabled, lws_serve_http_file would
not add the content-type header to the response.
2017-08-12 20:55:14 +08:00
Andy Green
ffbefebc24 lwsws: remove no longer extant D option from help string
https://github.com/warmcat/libwebsockets/issues/986
2017-08-09 07:44:19 +08:00
Andy Green
4cca86926f v2.2.2 2017-07-19 01:05:49 +08:00
Andy Green
31b1029234 LWS_WITH_NO_LOGS: take care about unused array for log generation 2017-06-09 21:48:03 +08:00
Leonardo Maccari Rufino
5a473e0dc3 Subject: Support to IPv6 on Windows 2017-06-01 06:57:59 +08:00
Sergey Kovalevich
2e8c0256c0 Subject: Fixed value of LIBWEBSOCKETS_LIBRARIES_STATIC 2017-05-30 09:02:48 +08:00
Sergey Kovalevich
a64bdff642 Subject: Fixed build in scope of a project (add_subdirectory) 2017-05-30 09:02:45 +08:00
Petar Paradzik
a5463053e8 Subject: libuv: Fix closing handle multiple times
Sometimes "Assertion failed: !uv__is_closing(handle)" happens because
handle is being closed multiple times. To fix this, "uv_is_closing"
is added before calling "uv_close".

Signed-off-by: Petar Paradzik <petar.paradzik@sartura.hr>
2017-05-23 23:50:04 +08:00
Andy Green
7a8741ec0b LICENSE: clarify exceptions also apply to LGPL self-refernences
via Mike Atamas, Counsel for Epic Games
2017-05-19 09:27:54 +08:00
Andy Green
fe45fe1860 plugin-standalone: refactor cmake part to ease multiple sources 2017-05-06 06:40:23 +08:00
Andy Green
f6facad476 non-ssl: return 0 on pending
https://github.com/warmcat/libwebsockets/issues/887
2017-05-03 21:25:23 +08:00
Andy Green
ccecbb99ab snprintf: move contributed ssl patch to lws_snprintf 2017-05-03 20:26:58 +08:00
Andy Green
a68539492f mings: adjust plugin export name gen 2017-04-28 11:47:21 +08:00
Andy Green
36239951be mingw: use win32 plugin names 2017-04-28 10:14:40 +08:00
Andy Green
786e6dbf35 mingw: updates 2017-04-28 07:51:34 +08:00
Martin Milata
2238857ea4 Subject: ssl: stop spinning on close 2017-04-19 20:53:51 +08:00
dspname
2d6fd20c60 windows: constify first arg of plat fops open
https://github.com/warmcat/libwebsockets/issues/871
2017-04-19 20:41:57 +08:00
Andy Green
ba16f5172c windows: align choked trunc checking with unix 2017-04-18 15:18:14 +08:00
Gecko
2977272f0e Subject: Save copy of ah pointer even with WS client so that HTTP
error can be captured by calling lws_http_client_http_response.
2017-04-10 12:38:35 +08:00
Andy Green
6da41353ce boilerplate: add back missing Lesser that cut-and-pasted itself around 2017-04-06 23:12:30 +08:00
Martin Milata
8d511c834f Subject: ssl: fix OpenSSL client method detection 2017-04-06 23:12:11 +08:00
Andy Green
8e2fe3f12b ssl: OpenSSL v1.1 deprecated TLSv1_2_client_method 2017-04-06 08:51:17 +08:00
Andy Green
be333ac420 pollout: handle request for pollout during pollout service 2017-04-05 08:30:04 +08:00
Renyaow
89ad5714d6 windows: _snprintf_s
https://github.com/warmcat/libwebsockets/issues/859
2017-04-05 02:05:01 +08:00
Andy Green
a36ca4dc08 logs: reduce ah err to info 2017-04-02 13:02:28 +08:00
paularmitt
db26ccc38b windows: need LWS_INLINE 2017-03-31 19:59:50 +08:00
Olivier Basson
6f13ccf7c3 ev: stop event listeners during context destroy
I think I've found a bug in libev backend, in function lws_libev_io(). I'm using latest version from master branch.

When deleting a context with active connections via lws_context_destroy(), context->being_destroyed is set to 1 early in the function, before the loop calling lws_close_free_wsi() on each active connection.
lws_close_free_wsi() calls remove_wsi_socket_from_fds(), which calls lws_libev_io(), and here is my problem :

lws_libev_io() returns without doing anything if context->being_destroyed is set, so libev callbacks for deleted connections file descriptors stay registered after context is destroyed, which may lead to segfault/undefined behaviour if these file descriptors get reused later (which would trigger the callbacks).

I think the "if (!pt->io_loop_ev || context->being_destroyed) return;" statement should be replaced with " if (!pt->io_loop_ev) return;"

This fixes the problem for me and I have not seen any side effect yet. Moreover, libuv backend does not have such a test.
2017-03-29 08:22:54 +08:00
Andy Green
f80967b6c1 service: always restrict rx to serve_buf_size 2017-03-28 08:52:20 +08:00
Andy Green
d2d87776f9 pmd: handle case we are already on drain list
Provide internal helper for adding to list that takes care of the
case we are already on the list.

https://github.com/warmcat/libwebsockets/issues/847
2017-03-26 10:11:06 +08:00
Andy Green
5a354ae44a pmd: align client rx sm with server one 2017-03-25 08:51:06 +08:00
luk65
253ef2180e solaris: handle big-endian
https://github.com/warmcat/libwebsockets/issues/846
2017-03-23 23:58:01 +08:00
Andy Green
42ea3bd703 ext: pmd: improve dealing with partial input usage with drain
https://github.com/warmcat/libwebsockets/issues/841
2017-03-20 19:34:49 +08:00
a7e7d4ea08 rpm: added missing file to %files section of spec file 2017-03-18 11:20:46 +08:00
Andy Green
b4d2ad04bd windows: cannot use fstat 2017-03-17 11:44:47 +08:00
Andy Green
f8a995e8d5 docs: lws_callback_all_protocol: fix cut-n-paste error and explain it is probably not what you want 2017-03-15 07:29:55 +08:00
Andy Green
dca17ff614 windows: don't use LWS_EXTERN outside of function declarations 2017-03-15 07:29:45 +08:00
Andy Green
839b1af4e4 esp32: move helper code into lws 2017-03-10 14:33:25 +08:00
Silas Parker
906f137794 ssl: close sometimes continuously asserting POLLIN until timeout
https://github.com/warmcat/libwebsockets/issues/831
2017-03-10 07:48:27 +08:00
Silas Parker
98eed1871a fops_zip: require libz 2017-03-09 20:26:26 +08:00
Silas Parker
0be5279eb2 gcc-format-strings: 32-bit build 2017-03-09 18:48:55 +08:00
honjane
486e72f2cb http2: fix log compile errors 2017-03-09 13:30:44 +08:00
79 changed files with 1753 additions and 9244 deletions

View file

@ -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

View file

@ -9,12 +9,12 @@ project(libwebsockets C)
set(PACKAGE "libwebsockets")
set(CPACK_PACKAGE_NAME "${PACKAGE}")
set(CPACK_PACKAGE_VERSION_MAJOR "2")
set(CPACK_PACKAGE_VERSION_MINOR "3")
set(CPACK_PACKAGE_VERSION_PATCH "0")
set(CPACK_PACKAGE_VERSION_MINOR "2")
set(CPACK_PACKAGE_VERSION_PATCH "2")
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 "11")
set(SOVERSION "10")
if(NOT CPACK_GENERATOR)
if(UNIX)
set(CPACK_GENERATOR "TGZ")
@ -75,7 +75,6 @@ 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)
@ -95,10 +94,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 (requires libhubbub)" OFF)
option(LWS_WITH_HTTP_PROXY "Support for rewriting HTTP proxying" 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)
@ -116,9 +115,6 @@ 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")
@ -169,10 +165,12 @@ endif()
if (LWS_WITH_ESP32)
set(LWS_WITH_SHARED OFF)
set(LWS_WITH_SSL ON)
# set(LWS_WITHOUT_CLIENT ON)
set(LWS_WITH_SSL OFF)
set(LWS_WITH_ZLIB OFF)
# 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
@ -180,7 +178,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 1)
set(LWS_WITH_ZIP_FOPS 0)
endif()
@ -241,8 +239,6 @@ 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)
@ -307,15 +303,6 @@ 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()
@ -375,10 +362,6 @@ 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()
@ -392,7 +375,7 @@ if (LWS_WITH_HTTP2)
endif()
if ("${LWS_MAX_SMP}" STREQUAL "")
set(LWS_MAX_SMP 1)
set(LWS_MAX_SMP 32)
endif()
@ -470,9 +453,6 @@ 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)
@ -498,9 +478,6 @@ 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)
@ -517,12 +494,6 @@ 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)
@ -661,11 +632,6 @@ 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)
@ -741,7 +707,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 AND LWS_MAX_SMP GREATER 1)
if (UNIX)
# 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" )
@ -980,20 +946,6 @@ 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)
@ -1028,12 +980,6 @@ 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})
@ -1042,14 +988,9 @@ 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(
@ -1133,8 +1074,7 @@ 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}")
@ -1247,9 +1187,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"
""
@ -1258,14 +1198,14 @@ if (NOT LWS_WITHOUT_TESTAPPS)
""
"")
endif()
if (UNIX AND NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) AND LWS_MAX_SMP GREATER 1)
if (UNIX AND NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")))
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)
@ -1273,31 +1213,19 @@ if (NOT LWS_WITHOUT_TESTAPPS)
"test-server/test-server-libev.c"
"test-server/test-server-http.c"
"test-server/test-server-dumb-increment.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" )
"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_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()
@ -1308,9 +1236,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
@ -1443,8 +1371,6 @@ 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
@ -1569,26 +1495,6 @@ 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)
#
@ -1658,8 +1564,8 @@ set(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "Libraries")
set(CPACK_COMPONENT_DEV_DISPLAY_NAME "Development files")
# Install test apps.
if (NOT LWS_WITHOUT_TESTAPPS)
install(TARGETS ${TEST_APP_LIST}
if (NOT LWS_WITHOUT_TESTAPPS AND NOT LWS_WITHOUT_CLIENT)
install(TARGETS test-client ${TEST_APP_LIST}
RUNTIME DESTINATION ${LWS_INSTALL_EXAMPLES_DIR}
COMPONENT examples)
set(CPACK_COMPONENT_EXAMPLES_DISPLAY_NAME "Example files")
@ -1784,7 +1690,6 @@ 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}")
@ -1807,15 +1712,6 @@ 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
View file

@ -1,32 +1,9 @@
menu "Libwebsockets"
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"
config LWS
bool "Enable Libwebsockets"
default n
help
Enable Libwebsockets Library
endmenu

View file

@ -122,25 +122,12 @@ 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)
@ -189,7 +176,7 @@ deleting build/CMakeCache.txt may be enough.
2. Fix up MinGW headers
a) If still necessary, sdd the following lines to C:\MinGW\include\winsock2.h:
a) (32-bit) Add the following lines to C:\MinGW\include\winsock2.h:
```
#if(_WIN32_WINNT >= 0x0600)
@ -206,15 +193,16 @@ deleting build/CMakeCache.txt may be enough.
#endif // (_WIN32_WINNT >= 0x0600)
```
Update crtdefs.h line 47 to say:
(64 bit) 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:
https://github.com/Alexpux/mingw-w64/blob/master/mingw-w64-headers/include/mstcpip.h
(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
3. Install CMake 2.6 or greater: http://cmake.org/cmake/resources/software.html

View file

@ -568,32 +568,6 @@ 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
@ -888,40 +862,6 @@ 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

View file

@ -1,23 +0,0 @@
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

View file

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

View file

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

View file

@ -5,16 +5,10 @@
libwebsockets
-------------
News
----
v2.3 is out... see the changelog https://github.com/warmcat/libwebsockets/blob/v2.3-stable/changelog
ESP32 is now supported in lws! Download the
- factory https://github.com/warmcat/lws-esp32-factory and
- test server app https://github.com/warmcat/lws-esp32-test-server-demos
| 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 |
This is the libwebsockets C library for lightweight websocket clients and
servers. For support, visit

View file

@ -103,13 +103,6 @@ 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

View file

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

View file

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

View file

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

View file

@ -1,4 +1,4 @@
COMPONENT_ADD_INCLUDEDIRS := ../../../../../../../../../../../../../../../../../../$(COMPONENT_BUILD_DIR)/include
COMPONENT_ADD_INCLUDEDIRS := ../../../../../../../../../$(COMPONENT_BUILD_DIR)/include
COMPONENT_OWNBUILDTARGET:= 1
@ -10,26 +10,21 @@ 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) -DNDEBUG=1" \
-DIDF_PATH=$(IDF_PATH) \
cmake $(COMPONENT_PATH) -DLWS_C_FLAGS="$(CFLAGS)" \
-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 \
-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_NO_LOGS=0 \
-DOPENSSL_INCLUDE_DIR=${COMPONENT_PATH}/../openssl/include \
-DOPENSSL_LIBRARIES=x \
-DLWS_WITH_ESP32=1 ;\
make && \
make VERBOSE=1 && \
cp ${COMPONENT_BUILD_DIR}/lib/libwebsockets.a ${COMPONENT_BUILD_DIR}/liblibwebsockets.a
clean: myclean

View file

@ -10,28 +10,9 @@
set(CMAKE_SYSTEM_NAME Linux)
# Name of C compiler.
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_COMPILER "${CROSS_PATH}/bin/xtensa-esp32-elf-gcc")
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)
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)
# Where to look for the target environment. (More paths can be added here)
set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}")

View file

@ -1,51 +1,20 @@
#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)
{
sockaddr46 sa46;
struct addrinfo *result;
#ifdef LWS_USE_IPV6
struct sockaddr_in6 server_addr6;
struct addrinfo hints, *result;
#endif
struct lws_context *context = wsi->context;
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
struct sockaddr_in server_addr4;
struct lws_pollfd pfd;
const char *cce = "", *iface;
int n, plen = 0, port;
struct sockaddr *v;
const char *cce = "";
int n, plen = 0;
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__);
@ -55,14 +24,7 @@ lws_client_connect_2(struct lws *wsi)
goto oom4;
}
/*
* 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 */
/* proxy? */
if (wsi->vhost->http_proxy_port) {
plen = sprintf((char *)pt->serv_buf,
@ -78,71 +40,69 @@ 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;
#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;
#ifdef LWS_USE_IPV6
if (LWS_IPV6_ENABLED(wsi->vhost)) {
memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
server_addr6.sin6_port = htons(wsi->vhost->http_proxy_port);
} else
#endif
server_addr4.sin_port = htons(wsi->vhost->http_proxy_port);
} else {
/* Priority 3: Connect directly */
ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
port = wsi->c_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->c_port);
} else
#endif
server_addr4.sin_port = htons(wsi->c_port);
}
/*
* prepare the actual connection
* to whatever we decided to connect to
* prepare the actual connection (to the proxy, if any)
*/
lwsl_notice("%s: %p: address %s\n", __func__, wsi, ads);
n = lws_getaddrinfo46(wsi, ads, &result);
lwsl_notice("%s: address %s\n", __func__, ads);
#ifdef LWS_USE_IPV6
if (wsi->ipv6) {
if (LWS_IPV6_ENABLED(wsi->vhost)) {
memset(&hints, 0, sizeof(struct addrinfo));
#if !defined(__ANDROID__)
hints.ai_family = AF_INET6;
hints.ai_flags = AI_V4MAPPED;
#endif
n = getaddrinfo(ads, NULL, &hints, &result);
if (n) {
/* lws_getaddrinfo46 failed, there is no usable result */
lwsl_notice("%s: lws_getaddrinfo46 failed %d\n",
__func__, n);
cce = "ipv6 lws_getaddrinfo46 failed";
#ifdef _WIN32
lwsl_err("getaddrinfo: %ls\n", gai_strerrorW(n));
#else
lwsl_err("getaddrinfo: %s\n", gai_strerror(n));
#endif
cce = "getaddrinfo (ipv6) failed";
goto oom4;
}
memset(&sa46, 0, sizeof(sa46));
sa46.sa6.sin6_family = AF_INET6;
server_addr6.sin6_family = AF_INET6;
switch (result->ai_family) {
#if defined(__ANDROID__)
case AF_INET:
if (ipv6only)
break;
/* map IPv4 to IPv6 */
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],
bzero((char *)&server_addr6.sin6_addr,
sizeof(struct in6_addr));
server_addr6.sin6_addr.s6_addr[10] = 0xff;
server_addr6.sin6_addr.s6_addr[11] = 0xff;
memcpy(&server_addr6.sin6_addr.s6_addr[12],
&((struct sockaddr_in *)result->ai_addr)->sin_addr,
sizeof(struct in_addr));
lwsl_notice("uplevelling AF_INET to AF_INET6\n");
break;
#endif
case AF_INET6:
memcpy(&sa46.sa6.sin6_addr,
memcpy(&server_addr6.sin6_addr,
&((struct sockaddr_in6 *)result->ai_addr)->sin6_addr,
sizeof(struct in6_addr));
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;
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;
break;
default:
lwsl_err("Unknown address family\n");
@ -150,18 +110,23 @@ lws_client_connect_2(struct lws *wsi)
cce = "unknown address family";
goto oom4;
}
freeaddrinfo(result);
} else
#endif /* use ipv6 */
/* use ipv4 */
#endif
{
struct addrinfo ai, *res, *result = NULL;
void *p = NULL;
int addr_rv;
if (!n) {
struct addrinfo *res = result;
/* pick the first AF_INET (IPv4) result */
memset (&ai, 0, sizeof ai);
ai.ai_family = PF_UNSPEC;
ai.ai_socktype = SOCK_STREAM;
ai.ai_flags = AI_CANONNAME;
addr_rv = getaddrinfo(ads, NULL, &ai, &result);
if (!addr_rv) {
res = result;
while (!p && res) {
switch (res->ai_family) {
case AF_INET:
@ -172,7 +137,7 @@ lws_client_connect_2(struct lws *wsi)
res = res->ai_next;
}
#if defined(LWS_FALLBACK_GETHOSTBYNAME)
} else if (n == EAI_SYSTEM) {
} else if (addr_rv == EAI_SYSTEM) {
struct hostent *host;
lwsl_info("getaddrinfo (ipv4) failed, trying gethostbyname\n");
@ -187,7 +152,7 @@ lws_client_connect_2(struct lws *wsi)
#endif
} else {
lwsl_err("getaddrinfo failed\n");
cce = "getaddrinfo failed";
cce = "getaddrinfo (ipv4) failed";
goto oom4;
}
@ -199,29 +164,17 @@ lws_client_connect_2(struct lws *wsi)
goto oom4;
}
sa46.sa4.sin_family = AF_INET;
sa46.sa4.sin_addr = *((struct in_addr *)p);
bzero(&sa46.sa4.sin_zero, 8);
server_addr4.sin_family = AF_INET;
server_addr4.sin_addr = *((struct in_addr *)p);
bzero(&server_addr4.sin_zero, 8);
if (result)
freeaddrinfo(result);
}
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 (wsi->ipv6)
if (LWS_IPV6_ENABLED(wsi->vhost))
wsi->desc.sockfd = socket(AF_INET6, SOCK_STREAM, 0);
else
#endif
@ -244,8 +197,6 @@ 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";
@ -268,30 +219,25 @@ lws_client_connect_2(struct lws *wsi)
lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
AWAITING_TIMEOUT);
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;
}
n = lws_socket_bind(wsi->vhost, wsi->desc.sockfd, 0, wsi->vhost->iface);
if (n < 0) {
cce = "unable to bind socket";
goto failed;
}
}
#ifdef LWS_USE_IPV6
if (wsi->ipv6) {
sa46.sa6.sin6_port = htons(port);
if (LWS_IPV6_ENABLED(wsi->vhost)) {
v = (struct sockaddr *)&server_addr6;
n = sizeof(struct sockaddr_in6);
} else
#endif
{
sa46.sa4.sin_port = htons(port);
v = (struct sockaddr *)&server_addr4;
n = sizeof(struct sockaddr);
}
if (connect(wsi->desc.sockfd, (const struct sockaddr *)&sa46, n) == -1 ||
LWS_ERRNO == LWS_EISCONN) {
if (connect(wsi->desc.sockfd, v, n) == -1 || LWS_ERRNO == LWS_EISCONN) {
if (LWS_ERRNO == LWS_EALREADY ||
LWS_ERRNO == LWS_EINPROGRESS ||
LWS_ERRNO == LWS_EWOULDBLOCK
@ -330,7 +276,6 @@ lws_client_connect_2(struct lws *wsi)
/* we are connected to server, or proxy */
/* http proxy */
if (wsi->vhost->http_proxy_port) {
/*
@ -359,26 +304,6 @@ 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
@ -410,8 +335,8 @@ lws_client_connect_2(struct lws *wsi)
oom4:
/* we're closing, losing some rx is OK */
lws_header_table_force_to_detachable_state(wsi);
if (wsi->u.hdr.ah)
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
if (wsi->mode == LWSCM_HTTP_CLIENT ||
wsi->mode == LWSCM_HTTP_CLIENT_ACCEPTED ||
wsi->mode == LWSCM_WSCL_WAITING_CONNECT) {
@ -453,7 +378,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] = "", iface[16] = "", *p;
char origin[300] = "", protocol[300] = "", method[32] = "", *p;
struct lws *wsi = *pwsi;
if (wsi->redirects == 3) {
@ -462,6 +387,15 @@ 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);
@ -474,46 +408,14 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
if (p)
strncpy(method, p, sizeof(method) - 1);
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",
lwsl_debug("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;
@ -541,11 +443,6 @@ 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))
@ -575,14 +472,14 @@ html_parser_cb(const hubbub_token *token, void *pw)
"(force-quirks) " : "");
if (token->data.doctype.public_missing)
lwsl_debug("\tpublic: missing\n");
printf("\tpublic: missing\n");
else
p += lws_snprintf(p, end - p, "PUBLIC \"%.*s\"\n",
(int) token->data.doctype.public_id.len,
token->data.doctype.public_id.ptr);
if (token->data.doctype.system_missing)
lwsl_debug("\tsystem: missing\n");
printf("\tsystem: missing\n");
else
p += lws_snprintf(p, end - p, " \"%.*s\">\n",
(int) token->data.doctype.system_id.len,
@ -605,28 +502,25 @@ 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 (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;
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);
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);
} 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, ">");
p += lws_snprintf(p, end - p, ">\n");
break;
case HUBBUB_TOKEN_END_TAG:
p += lws_snprintf(p, end - p, "</%.*s", (int) token->data.tag.name.len,
@ -644,7 +538,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, ">");
p += lws_snprintf(p, end - p, ">\n");
break;
case HUBBUB_TOKEN_COMMENT:
p += lws_snprintf(p, end - p, "<!-- %.*s -->\n",
@ -652,21 +546,6 @@ 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, "&lt;");
break;
}
if (*token->data.character.ptr == '>') {
p += lws_snprintf(p, end - p, "&gt;");
break;
}
if (*token->data.character.ptr == '&') {
p += lws_snprintf(p, end - p, "&amp;");
break;
}
}
p += lws_snprintf(p, end - p, "%.*s", (int) token->data.character.len,
token->data.character.ptr);
break;
@ -770,7 +649,6 @@ 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);
@ -787,9 +665,6 @@ 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';
@ -797,7 +672,6 @@ 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;
@ -880,15 +754,8 @@ 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;
#if defined(LWS_WITH_SOCKS5)
if (!wsi->vhost->socks_proxy_port)
lws_free_set_NULL(wsi->u.hdr.stash);
#endif
lws_free_set_NULL(wsi->u.hdr.stash);
/*
* Check with each extension if it is able to route and proxy this
@ -916,10 +783,7 @@ lws_client_connect_via_info2(struct lws *wsi)
return lws_client_connect_2(wsi);
bail1:
#if defined(LWS_WITH_SOCKS5)
if (!wsi->vhost->socks_proxy_port)
lws_free_set_NULL(wsi->u.hdr.stash);
#endif
lws_free_set_NULL(wsi->u.hdr.stash);
return NULL;
}
@ -973,73 +837,3 @@ 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

View file

@ -558,7 +558,6 @@ 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;

View file

@ -42,12 +42,7 @@ lws_handshake_client(struct lws *wsi, unsigned char **buf, size_t len)
return 0;
}
if (wsi->u.ws.rx_draining_ext) {
#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);
m = lws_rx_sm(wsi, 0);
if (m < 0)
return -1;
continue;
@ -86,10 +81,7 @@ lws_client_socket_service(struct lws_context *context, struct lws *wsi,
const char *cce = NULL;
unsigned char c;
char *sb = p;
int n = 0, len = 0;
#if defined(LWS_WITH_SOCKS5)
char conn_mode = 0, pending_timeout = 0;
#endif
int n, len;
switch (wsi->mode) {
@ -109,195 +101,6 @@ 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 */
@ -346,9 +149,6 @@ 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;
@ -520,9 +320,7 @@ client_http_body_sent:
bail3:
lwsl_info("closing conn at LWS_CONNMODE...SERVER_REPLY\n");
if (cce)
lwsl_info("reason: %s\n", cce);
wsi->protocol->callback(wsi,
wsi->vhost->protocols[0].callback(wsi,
LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
wsi->user_space, (void *)cce, cce ? strlen(cce) : 0);
wsi->already_did_cce = 1;
@ -571,9 +369,6 @@ 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;
@ -588,7 +383,7 @@ lws_http_transaction_completed_client(struct lws *wsi)
* we can drop the ah, if any
*/
if (wsi->u.hdr.ah) {
lws_header_table_force_to_detachable_state(wsi);
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
lws_header_table_detach(wsi, 0);
}
@ -598,7 +393,6 @@ 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
@ -631,8 +425,6 @@ 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) {
@ -757,9 +549,9 @@ lws_client_interpret_server_handshake(struct lws *wsi)
}
if (!wsi->do_ws) {
if (n != 200 && n != 201 && n != 304 && n != 401) {
if (n != 200 && n != 304) {
lwsl_notice("Connection failed with code %d\n", n);
cce = "HS: Server unrecognized response code";
cce = "HS: Server did not return 200 or 304";
goto bail2;
}
@ -792,10 +584,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 =
atoll(lws_hdr_simple_ptr(wsi,
atoi(lws_hdr_simple_ptr(wsi,
WSI_TOKEN_HTTP_CONTENT_LENGTH));
lwsl_notice("%s: incoming content length %llu\n", __func__,
(unsigned long long)wsi->u.http.content_length);
lwsl_notice("%s: incoming content length %d\n", __func__,
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)
@ -1163,14 +955,12 @@ 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);
@ -1232,21 +1022,19 @@ 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;
@ -1260,13 +1048,12 @@ 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;
lws_header_table_force_to_detachable_state(wsi);
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
lws_union_transition(wsi, LWSCM_RAW);
lws_header_table_detach(wsi, 1);

View file

@ -40,6 +40,7 @@ lws_get_library_version(void)
return library_version;
}
#if !defined(LWS_WITH_NO_LOGS)
static const char * const mount_protocols[] = {
"http://",
"https://",
@ -49,6 +50,7 @@ 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,
@ -220,13 +222,10 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
{
#ifdef LWS_WITH_CGI
struct lws_cgi_args *args;
#endif
#if defined(LWS_WITH_CGI) || defined(LWS_WITH_HTTP_PROXY)
char buf[512];
char buf[128];
int n;
#endif
switch (reason) {
case LWS_CALLBACK_HTTP:
#ifndef LWS_NO_SERVER
@ -237,119 +236,20 @@ 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 & LWS_CB_REASON_AUX_BF__CGI) {
if (wsi->reason_bf & 1) {
if (lws_cgi_write_split_stdout_headers(wsi) < 0)
return -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;
wsi->reason_bf &= ~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:
*
@ -364,7 +264,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 |= LWS_CB_REASON_AUX_BF__CGI;
wsi->reason_bf |= 1;
/* when writing to MASTER would not block */
lws_callback_on_writable(wsi);
break;
@ -382,11 +282,6 @@ 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 */
@ -399,17 +294,6 @@ 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;
}
@ -427,12 +311,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
0, NULL
},
/*
* the other protocols are provided by lws plugins
*/
{ NULL, NULL, 0, 0, 0, NULL, 0} /* terminator */
{ NULL, NULL, 0, 0, 0, NULL} /* terminator */
};
#ifdef LWS_PLAT_OPTEE
@ -470,10 +354,6 @@ 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++)
@ -482,17 +362,11 @@ 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
@ -513,7 +387,7 @@ lws_create_vhost(struct lws_context *context,
* for a protocol get it enabled.
*/
if (context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
if (info->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
f = 0;
(void)f;
#ifdef LWS_WITH_PLUGINS
@ -543,7 +417,7 @@ lws_create_vhost(struct lws_context *context,
#ifdef LWS_WITH_PLUGINS
(context->plugin_list) ||
#endif
context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
info->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
vh->protocols = lwsp;
else {
vh->protocols = info->protocols;
@ -566,7 +440,6 @@ 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);
@ -577,7 +450,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 *)(lws_intptr_t)n;
(const char *)(long)n;
break;
}
if (n == vh->count_protocols)
@ -626,14 +499,9 @@ 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)
@ -646,23 +514,7 @@ 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;
@ -766,9 +618,6 @@ 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
@ -823,8 +672,6 @@ 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;
@ -942,16 +789,6 @@ 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) +
@ -1018,11 +855,6 @@ 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
@ -1101,242 +933,10 @@ 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;
@ -1401,7 +1001,19 @@ lws_context_destroy(struct lws_context *context)
if (context->protocol_init_done)
vh = context->vhost_list;
while (vh) {
lws_vhost_destroy1(vh);
wsi.vhost = vh;
protocol = vh->protocols;
if (protocol) {
n = 0;
while (n < vh->count_protocols) {
wsi.protocol = protocol;
protocol->callback(&wsi, LWS_CALLBACK_PROTOCOL_DESTROY,
NULL, NULL, 0);
protocol++;
n++;
}
}
vh = vh->vhost_next;
}
@ -1410,7 +1022,6 @@ 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)
@ -1434,7 +1045,9 @@ 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);
@ -1444,27 +1057,53 @@ 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_vhost_destroy2(vh);
lws_free(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);
}

View file

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

View file

@ -62,7 +62,7 @@ lws_ext_parse_options(const struct lws_extension *ext, struct lws *wsi,
oa.option_index = n;
lwsl_ext("hit %d\n", oa.option_index);
leap = LEAPS_SEEK_VAL;
if (len == 1)
if (len ==1)
goto set_arg;
break;
}
@ -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 *)(lws_intptr_t)n, arg, len);
(void *)(long)n, arg, len);
if (m < 0) {
lwsl_ext("Ext '%s' failed to handle callback %d!\n",
wsi->active_extensions[n]->name, reason);

View file

@ -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[96];
uint8_t buf[64];
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 = (unsigned int)len;
priv->inflate.avail_out = len;
priv->inflate.next_out = buf;
spin:
@ -554,7 +554,7 @@ spin:
cur += ramount;
priv->inflate.avail_in = (unsigned int)ramount;
priv->inflate.avail_in = 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, (size_t)rlen);
memcpy(buf, hd + fd->pos, rlen);
fd->pos += rlen;
buf += rlen;
len -= rlen;
@ -636,7 +636,7 @@ spin:
if (rlen > len)
rlen = len;
memcpy(buf, priv->u.trailer8 + cur, (size_t)rlen);
memcpy(buf, priv->u.trailer8 + cur, rlen);
*amount += rlen;
fd->pos += rlen;

View file

@ -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 - ((lws_intptr_t)sa->sa_data - (lws_intptr_t)&sa->sa_family); i++)
i < sa->sa_len - ((long)sa->sa_data - (long)&sa->sa_family); i++)
printf("%02x", ((unsigned char *)sa->sa_data)[i]);
#else
for (i = 0; i < sizeof(sa->sa_data); i++)

View file

@ -60,10 +60,10 @@
*/
LWS_VISIBLE int
lws_read(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
lws_read(struct lws *wsi, unsigned char *buf, size_t len)
{
unsigned char *last_char, *oldbuf = buf;
lws_filepos_t body_chunk_len;
int body_chunk_len;
size_t n;
lwsl_debug("%s: incoming len %d state %d\n", __func__, (int)len, wsi->state);
@ -95,16 +95,17 @@ lws_read(struct lws *wsi, unsigned char *buf, lws_filepos_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__);
@ -112,11 +113,11 @@ lws_read(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
}
lwsl_parser("issuing %d bytes to parser\n", (int)len);
if (lws_handshake_client(wsi, &buf, (size_t)len))
if (lws_handshake_client(wsi, &buf, len))
goto bail;
last_char = buf;
if (lws_handshake_server(wsi, &buf, (size_t)len))
if (lws_handshake_server(wsi, &buf, len))
/* Handshake indicates this session is done. */
goto bail;
@ -189,10 +190,10 @@ http_postbody:
#endif
n = wsi->protocol->callback(wsi,
LWS_CALLBACK_HTTP_BODY, wsi->user_space,
buf, (size_t)body_chunk_len);
buf, body_chunk_len);
if (n)
goto bail;
n = (size_t)body_chunk_len;
n = body_chunk_len;
#ifdef LWS_WITH_CGI
}
#endif
@ -229,14 +230,13 @@ 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, (size_t)len))
if (lws_handshake_client(wsi, &buf, len))
goto bail;
switch (wsi->mode) {
case LWSCM_WS_SERVING:
if (lws_interpret_incoming_packet(wsi, &buf, (size_t)len) < 0) {
if (lws_interpret_incoming_packet(wsi, &buf, len) < 0) {
lwsl_info("interpret_incoming_packet has bailed\n");
goto bail;
}

View file

@ -71,7 +71,7 @@ int lws_finalize_http_header(struct lws *wsi, unsigned char **p,
#else
(void)wsi;
#endif
if ((lws_intptr_t)(end - *p) < 3)
if ((long)(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,
lws_filepos_t content_length,
unsigned long content_length,
unsigned char **p, unsigned char *end)
{
char b[24];
int n;
n = sprintf(b, "%llu", (unsigned long long)content_length);
n = sprintf(b, "%lu", content_length);
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
(unsigned char *)b, n, p, end))
return 1;
@ -222,14 +222,17 @@ 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;
unsigned char *start = p, *body = p + 512;
unsigned char *end = p + context->pt_serv_buf_size - LWS_PRE;
int n = 0, m, len;
int n, m, len;
char slen[20];
if (!html_body)
html_body = "";
len = sprintf((char *)body, "<html><body><h1>%u</h1>%s</body></html>",
code, html_body);
if (lws_add_http_header_status(wsi, code, &p, end))
return 1;
@ -237,10 +240,7 @@ 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,30 +249,11 @@ lws_return_http_status(struct lws *wsi, unsigned int code,
if (lws_finalize_http_header(wsi, &p, end))
return 1;
#if defined(LWS_USE_HTTP2)
{
unsigned char *body = p + 512;
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)
m = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
if (m != (int)(p - start))
return 1;
#endif
m = lws_write(wsi, body, len, LWS_WRITE_HTTP);
return m != n;
}

View file

@ -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 ((lws_intptr_t)swsi->u.http2.tx_credit + (lws_intptr_t)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)))
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) {

View file

@ -199,8 +199,8 @@ struct jpargs {
static void *
lwsws_align(struct jpargs *a)
{
if ((lws_intptr_t)(a->p) & 15)
a->p += 16 - ((lws_intptr_t)(a->p) & 15);
if ((unsigned long)(a->p) & 15)
a->p += 16 - ((unsigned long)(a->p) & 15);
return a->p;
}
@ -776,8 +776,7 @@ lwsws_get_config_d(void *user, const char *d, const char * const *paths,
bail:
uv_fs_req_cleanup(&req);
while (uv_loop_close(&loop))
;
uv_loop_close(&loop);
return ret;
}

View file

@ -1,249 +0,0 @@
/*
* 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);
}

View file

@ -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 *)(lws_intptr_t)wsi->desc.sockfd);
n, (void *)(long)wsi->desc.sockfd);
return -1;
}
@ -262,12 +262,6 @@ 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)
{
@ -526,39 +520,13 @@ 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
@ -572,6 +540,7 @@ 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;
@ -582,14 +551,14 @@ lws_plat_plugins_init(struct lws_context *context, const char * const *d)
lib.errmsg = NULL;
lib.handle = NULL;
uv_loop_init(&context->pu_loop);
uv_loop_init(&loop);
lwsl_notice(" Plugins:\n");
while (d && *d) {
lwsl_notice(" Scanning %s\n", *d);
m =uv_fs_scandir(&context->pu_loop, &req, *d, 0, NULL);
m =uv_fs_scandir(&loop, &req, *d, 0, NULL);
if (m < 1) {
lwsl_err("Scandir on %s failed\n", *d);
return 1;
@ -605,12 +574,10 @@ 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... */);
@ -624,7 +591,6 @@ 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;
@ -637,7 +603,6 @@ 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;
}
@ -660,7 +625,11 @@ bail:
d++;
}
uv_run(&loop, UV_RUN_NOWAIT);
uv_loop_close(&loop);
return ret;
}
LWS_VISIBLE int
@ -684,7 +653,6 @@ 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';
@ -713,9 +681,6 @@ 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

View file

@ -33,12 +33,6 @@ 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
@ -46,12 +40,7 @@ struct sockaddr_in;
#define LWS_POSIX 1
#endif
#if defined(LWS_HAS_INTPTR_T)
#include <stdint.h>
#define lws_intptr_t intptr_t
#else
typedef unsigned long long lws_intptr_t;
#endif
#include "lws_config.h"
#if defined(WIN32) || defined(_WIN32)
#ifndef WIN32_LEAN_AND_MEAN
@ -95,9 +84,6 @@ typedef unsigned long long lws_intptr_t;
#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
@ -113,9 +99,6 @@ typedef unsigned long long lws_intptr_t;
#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>
@ -123,16 +106,13 @@ typedef unsigned long long lws_intptr_t;
#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() (30)
#define getdtablesize() (20)
#if defined(LWS_WITH_ESP32)
#define LWS_INVALID_FILE NULL
#else
@ -175,9 +155,6 @@ typedef unsigned long long lws_intptr_t;
#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
@ -526,7 +503,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 = (struct timer_mapping *)malloc(sizeof(*tm));
struct timer_mapping *tm = malloc(sizeof(*tm));
if (!tm)
return;
@ -552,123 +529,34 @@ 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 */
typedef void (*lws_cb_scan_done)(uint16_t count, wifi_ap_record_t *recs, void *arg);
extern void (*lws_cb_scan_done)(void *);
extern void *lws_cb_scan_done_arg;
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 char lws_esp32_serial[], lws_esp32_force_ap, lws_esp32_region;
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_ap(void);
extern void
lws_esp32_wlan_start_station(void);
lws_esp32_wlan_start(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 *, 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);
lws_esp32_init(struct lws_context_creation_info *, unsigned int _romfs);
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;
@ -682,36 +570,6 @@ 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 {
@ -828,38 +686,6 @@ 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
@ -873,10 +699,6 @@ enum lws_meta_commands {
*/
///@{
struct lws_ssl_info {
int where;
int ret;
};
/*
* NOTE: These public enums are part of the abi. If you want to add one,
@ -1097,7 +919,8 @@ 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. */
* content during this callback might not be useful for anything.
* Notice this callback comes to protocols[0]. */
LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED = 26,
/**< When a client
* connection is being prepared to start a handshake to a server,
@ -1283,22 +1106,6 @@ 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 ---^ ******/
@ -1326,11 +1133,6 @@ 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
@ -1586,8 +1388,8 @@ struct lws_protocols {
* be able to consume it all without having to return to the event
* loop. That is supported in lws.
*
* If .tx_packet_size is 0, this also controls how much may be sent at once
* for backwards compatibility.
* This also controls how much may be sent at once at the moment,
* although this is likely to change.
*/
unsigned int id;
/**< ignored by lws, but useful to contain user information bound
@ -1598,15 +1400,6 @@ 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 */
@ -1853,18 +1646,6 @@ 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 ---^ ******/
};
@ -1936,7 +1717,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 */
@ -2077,36 +1858,6 @@ 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
@ -2115,15 +1866,6 @@ 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 */
};
@ -2231,25 +1973,6 @@ 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;
@ -2262,22 +1985,10 @@ 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_VISIBLE LWS_EXTERN struct lws_vhost *
LWS_EXTERN LWS_VISIBLE 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
@ -2385,8 +2096,8 @@ struct lws_protocol_vhost_options {
* served from a filesystem, or it is a cgi etc.
*/
enum lws_mount_protocols {
LWSMPRO_HTTP = 0, /**< http reverse proxy */
LWSMPRO_HTTPS = 1, /**< https reverse proxy */
LWSMPRO_HTTP = 0, /**< not supported yet */
LWSMPRO_HTTPS = 1, /**< not supported yet */
LWSMPRO_FILE = 2, /**< serve from filesystem directory */
LWSMPRO_CGI = 3, /**< pass to CGI to handle */
LWSMPRO_REDIR_HTTP = 4, /**< redirect to http:// url */
@ -2519,9 +2230,6 @@ 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
@ -2626,6 +2334,7 @@ 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
*
@ -2838,9 +2547,6 @@ 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
@ -3122,7 +2828,6 @@ 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,
@ -3293,7 +2998,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_content_length() - append content-length helper
* lws_add_http_header_by_name() - append content-length helper
*
* \param wsi: the connection to check
* \param content_length: the content length to use
@ -3304,7 +3009,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,
lws_filepos_t content_length,
unsigned long content_length,
unsigned char **p, unsigned char *end);
/**
* lws_finalize_http_header() - terminate header block
@ -3610,39 +3315,9 @@ 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
@ -3673,30 +3348,10 @@ 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
*
@ -3704,10 +3359,7 @@ enum pending_timeout {
*
* \param wsi: Websocket connection instance
* \param reason: timeout reason
* \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.
* \param secs: how many seconds
*/
LWS_VISIBLE LWS_EXTERN void
lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs);
@ -3732,8 +3384,7 @@ 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))
/* last 2 is for lws-meta */
#define LWS_PRE _LWS_PAD(4 + 10 + 2)
#define LWS_PRE _LWS_PAD(4 + 10)
/* 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
@ -3785,15 +3436,6 @@ 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
@ -3980,11 +3622,10 @@ lws_callback_all_protocol(struct lws_context *context,
/**
* lws_callback_all_protocol_vhost() - Callback all connections using
* the given protocol with the given reason. This is
* deprecated since v2.4: use lws_callback_all_protocol_vhost_args
* the given protocol with the given reason
*
* \param vh: Vhost whose connections will get callbacks
* \param protocol: Which protocol to match. NULL means all.
* \param protocol: Which protocol to match
* \param reason: Callback reason index
*
* - Which: connections using this protocol on GIVEN VHOST ONLY
@ -3993,27 +3634,7 @@ 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)
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);
const struct lws_protocols *protocol, int reason);
/**
* lws_callback_vhost_protocols() - Callback all protocols enabled on a vhost
@ -4159,11 +3780,7 @@ 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_WS_PARENTIO = 8, /* flag: ws mode parent handles IO
* if given must be only flag
* wsi put directly into ws mode
*/
LWS_ADOPT_ALLOW_SSL = 4 /* flag: if set requires LWS_ADOPT_SOCKET */
} lws_adoption_type;
typedef union {
@ -4190,7 +3807,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 LWS_EXTERN struct lws *
LWS_VISIBLE 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);
@ -4323,74 +3940,6 @@ 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
*
@ -4521,32 +4070,6 @@ 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.
@ -4554,7 +4077,7 @@ lws_get_close_payload(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, lws_filepos_t len);
lws_read(struct lws *wsi, unsigned char *buf, size_t len);
/**
* lws_set_allocator() - custom allocator support
@ -4584,20 +4107,11 @@ 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
@ -4735,8 +4249,6 @@ enum lws_cgi_hdr_state {
LCHS_LF1,
LCHS_CR2,
LCHS_LF2,
LHCS_RESPONSE,
LHCS_DUMP_HEADERS,
LHCS_PAYLOAD,
LCHS_SINGLE_0A,
};
@ -4829,6 +4341,32 @@ 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... */
@ -5025,9 +4563,6 @@ 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
@ -5154,56 +4689,6 @@ 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

File diff suppressed because it is too large Load diff

View file

@ -630,13 +630,6 @@ 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)
@ -670,8 +663,7 @@ 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_libevent_init_fd_table(context)) {
!lws_libuv_init_fd_table(context)) {
/* otherwise libev handled it instead */
#if 0
while (n--) {

View file

@ -261,13 +261,6 @@ 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)

View file

@ -114,14 +114,11 @@ _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;
@ -255,17 +252,6 @@ 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)
@ -290,31 +276,9 @@ 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));
@ -323,25 +287,11 @@ 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);
}
@ -504,9 +454,7 @@ 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);
@ -623,7 +571,6 @@ 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;
}
@ -636,7 +583,6 @@ 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--;
}
@ -663,12 +609,6 @@ 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)
@ -800,8 +740,7 @@ lws_plat_init(struct lws_context *context,
}
if (!lws_libev_init_fd_table(context) &&
!lws_libuv_init_fd_table(context) &&
!lws_libevent_init_fd_table(context)) {
!lws_libuv_init_fd_table(context)) {
/* otherwise libev handled it instead */
while (n--) {

View file

@ -218,9 +218,6 @@ _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]);
}
/*
@ -401,16 +398,6 @@ 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) {
@ -422,7 +409,7 @@ lws_interface_to_sa(int ipv6,
if (address == INADDR_NONE)
return -1;
addr->sin_addr.s_addr = (lws_intptr_t)address;
addr->sin_addr.s_addr = (unsigned long)address;
return 0;
}
@ -538,59 +525,6 @@ 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)
@ -598,15 +532,14 @@ _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 {
ret = CreateFileW(buf, GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
lwsl_err("%s: open for write not implemented\n", __func__);
goto bail;
}
if (ret == LWS_INVALID_FILE)
@ -621,9 +554,6 @@ _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;
@ -648,10 +578,7 @@ _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)
{
LARGE_INTEGER l;
l.QuadPart = offset;
return SetFilePointerEx((HANDLE)fop_fd->fd, l, NULL, FILE_CURRENT);
return SetFilePointer((HANDLE)fop_fd->fd, offset, NULL, FILE_CURRENT);
}
LWS_VISIBLE int
@ -676,18 +603,16 @@ LWS_VISIBLE int
_lws_plat_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
uint8_t* buf, lws_filepos_t len)
{
DWORD _amount;
(void)fop_fd;
(void)amount;
(void)buf;
(void)len;
if (!WriteFile((HANDLE)fop_fd->fd, buf, (DWORD)len, &_amount, NULL)) {
*amount = 0;
fop_fd->pos += len;
return 1;
}
lwsl_err("%s: not implemented yet on this platform\n", __func__);
fop_fd->pos += _amount;
*amount = (unsigned long)_amount;
return 0;
return -1;
}
LWS_VISIBLE int

View file

@ -95,13 +95,10 @@ 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 */
@ -140,13 +137,9 @@ 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 */
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 = wsi->protocol->rx_buffer_size;
if (!n)
n = context->pt_serv_buf_size;
n += LWS_PRE + 4;
if (n > len)
n = len;
@ -162,8 +155,6 @@ 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 */
@ -207,12 +198,9 @@ handle_truncated_send:
* Newly truncated send. Buffer the remainder (it will get
* first priority next time the socket is writable)
*/
lwsl_debug("%p new partial sent %d from %lu total\n", wsi, n,
lwsl_info("%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
@ -250,33 +238,6 @@ 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
@ -286,8 +247,7 @@ 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_notice("%s: TX EXT DRAINING: Remove from list\n", __func__);
lwsl_debug("%s: TX EXT DRAINING: Remove from list\n", __func__);
wsi->u.ws.tx_draining_ext = 0;
/* remove us from context draining ext list */
while (*w) {
@ -350,13 +310,11 @@ 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;
@ -390,8 +348,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 not have anything to issue yet.
* In that case we have to follow his lead, but stash and
* ext might eat it, but no have anything to issue yet
* in that case we have to follow his lead, but stash and
* replace the write type that was lost here the first time.
*/
if (len && !eff_buf.token_len) {
@ -410,13 +368,6 @@ 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) {
@ -540,8 +491,8 @@ send_raw:
wp == LWS_WRITE_HTTP_FINAL) &&
wsi->u.http.content_length) {
wsi->u.http.content_remain -= len;
lwsl_info("%s: content_remain = %llu\n", __func__,
(unsigned long long)wsi->u.http.content_remain);
lwsl_info("%s: content_remain = %lu\n", __func__,
(unsigned 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;
@ -640,7 +591,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 long)lws_vfs_file_seek_cur(wsi->u.http.fop_fd,
if ((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;
@ -667,14 +618,6 @@ 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)
@ -706,7 +649,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 = (unsigned int)poss + 128;
args.max_len = poss + 128;
args.final = wsi->u.http.filepos + n ==
wsi->u.http.filelen;
if (user_callback_handle_rxflow(
@ -803,17 +746,12 @@ 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;
}
@ -863,9 +801,5 @@ LWS_VISIBLE int
lws_ssl_pending_no_ssl(struct lws *wsi)
{
(void)wsi;
#if defined(LWS_WITH_ESP32)
return 100;
#else
return 0;
#endif
}

View file

@ -86,15 +86,8 @@ 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;
/* 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);
// wsi->hdr_parsing_completed = 0;
/*
* if we inherited pending rx (from socket adoption deferred
@ -188,7 +181,7 @@ lws_header_table_attach(struct lws *wsi, int autoservice)
_lws_change_pollfd(wsi, 0, LWS_POLLIN, &pa);
lwsl_info("%s: did attach wsi %p: ah %p: count %d (on exit)\n", __func__,
lwsl_info("%s: 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);
@ -219,47 +212,6 @@ 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;
@ -269,13 +221,6 @@ 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);
@ -284,14 +229,32 @@ 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 (!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);
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);
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) {
@ -316,8 +279,6 @@ 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;
@ -360,21 +321,18 @@ 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) {
lws_pt_unlock(pt);
if (wsi->state == LWSS_CLIENT_UNCONNECTED)
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 == !!(lws_intptr_t)pt->ah_wait_list);
assert(!!pt->ah_wait_list_length == !!(int)(long)pt->ah_wait_list);
bail:
lwsl_info("%s: wsi %p: ah %p (tsi=%d, count = %d)\n", __func__,
(void *)wsi, (void *)ah, wsi->tsi,
@ -389,9 +347,6 @@ 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;
@ -409,9 +364,6 @@ 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;
@ -427,12 +379,7 @@ 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;
if (!wsi->u.hdr.ah)
return -1;
f = wsi->u.hdr.ah->frag_index[h];
int f = wsi->u.hdr.ah->frag_index[h];
if (!f)
return -1;
@ -463,9 +410,6 @@ 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;
@ -1065,6 +1009,7 @@ 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;
@ -1163,7 +1108,6 @@ 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:
@ -1511,7 +1455,6 @@ drain_extension:
/* eff_buf may be pointing somewhere completely different now,
* it's the output
*/
wsi->u.ws.first_fragment = 0;
if (n < 0) {
/*
* we may rely on this to get RX, just drop connection

View file

@ -78,22 +78,18 @@ _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);
}
/*
@ -236,11 +232,6 @@ 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);
@ -252,7 +243,31 @@ remove_wsi_socket_from_fds(struct lws *wsi)
wsi->user_space, (void *)&pa, 1))
return -1;
lws_same_vh_protocol_remove(wsi);
/*
* 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;
/* the guy who is to be deleted's slot index in pt->fds */
m = wsi->position_in_fds_table;
@ -341,7 +356,6 @@ 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;
@ -353,25 +367,6 @@ 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);
@ -431,74 +426,6 @@ 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)

View file

@ -134,15 +134,6 @@ 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
@ -217,9 +208,6 @@ 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
@ -488,7 +476,6 @@ 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,
@ -584,75 +571,12 @@ 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),
@ -664,7 +588,7 @@ enum {
struct lws_protocols;
struct lws;
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV) || defined(LWS_USE_LIBEVENT)
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV)
struct lws_io_watcher {
#ifdef LWS_USE_LIBEV
@ -672,9 +596,6 @@ 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;
};
@ -685,9 +606,6 @@ 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;
};
@ -765,7 +683,7 @@ struct lws_context_per_thread {
struct lws *rx_draining_ext_list;
struct lws *tx_draining_ext_list;
struct lws *timeout_list;
#if defined(LWS_USE_LIBUV) || defined(LWS_USE_LIBEVENT)
#ifdef LWS_USE_LIBUV
struct lws_context *context;
#endif
#ifdef LWS_WITH_CGI
@ -787,13 +705,10 @@ 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) || defined(LWS_USE_LIBEVENT)
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV)
struct lws_signal_watcher w_sigint;
unsigned char ev_loop_foreign:1;
#endif
@ -847,11 +762,6 @@ 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 */
@ -864,9 +774,6 @@ 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;
@ -882,17 +789,12 @@ 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
@ -904,19 +806,11 @@ 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
*
@ -949,9 +843,7 @@ 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;
@ -960,20 +852,11 @@ 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
@ -981,14 +864,8 @@ 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) || defined(LWS_USE_LIBEVENT)
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV)
int use_ev_sigint;
#endif
int started_with_parent;
@ -1013,15 +890,13 @@ 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()
@ -1041,9 +916,6 @@ 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]
@ -1051,10 +923,6 @@ 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);
@ -1136,34 +1004,6 @@ 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) \
@ -1179,14 +1019,6 @@ LWS_EXTERN void lws_feature_status_libevent(struct lws_context_creation_info *in
#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,
@ -1221,7 +1053,6 @@ struct client_info_stash {
char origin[256];
char protocol[256];
char method[16];
char iface[16];
};
#endif
@ -1292,8 +1123,8 @@ struct _lws_http_mode_related {
enum http_version request_version;
enum http_connection_type connection_type;
lws_filepos_t content_length;
lws_filepos_t content_remain;
unsigned int content_length;
unsigned int content_remain;
};
#ifdef LWS_USE_HTTP2
@ -1485,43 +1316,22 @@ 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 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;
unsigned long content_length;
unsigned long 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;
};
@ -1545,7 +1355,6 @@ struct lws_rewrite;
struct lws_access_log {
char *header_log;
char *user_agent;
char *referrer;
unsigned long sent;
int response;
};
@ -1567,10 +1376,10 @@ struct lws {
/* lifetime members */
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV) || defined(LWS_USE_LIBEVENT)
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV)
struct lws_io_watcher w_read;
#endif
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBEVENT)
#if defined(LWS_USE_LIBEV)
struct lws_io_watcher w_write;
#endif
time_t pending_timeout_limit;
@ -1593,7 +1402,6 @@ 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 */
@ -1612,10 +1420,6 @@ 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;
@ -1625,9 +1429,7 @@ 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;
@ -1655,10 +1457,6 @@ 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;
@ -1730,11 +1528,6 @@ 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);
@ -1928,11 +1721,6 @@ 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);
@ -2033,6 +1821,7 @@ 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
@ -2120,10 +1909,6 @@ 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
@ -2233,40 +2018,11 @@ 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
};

View file

@ -37,7 +37,7 @@
#include "romfs.h"
#include "esp_spi_flash.h"
#define RFS_STRING_MAX 96
#define RFS_STRING_MAX 64
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, i_in;
romfs_inode_t level, i = start;
const char *p, *n, *cp;
uint32_t next_be;
@ -128,7 +128,6 @@ 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;
@ -136,7 +135,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 && (p - path) < RFS_STRING_MAX) {
while (*p && *p != '/' && *cp && *p == *cp) {
p++;
n++;
cp++;
@ -159,9 +158,6 @@ 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) {
@ -195,15 +191,13 @@ 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, size_t *csum)
romfs_get_info(romfs_t romfs, const char *path, size_t *len)
{
romfs_inode_t i;
@ -217,8 +211,6 @@ romfs_get_info(romfs_t romfs, const char *path, size_t *len, size_t *csum)
set_cache(i, sizeof(*i));
*len = ntohl(ci->size);
if (csum)
*csum = ntohl(ci->checksum);
return (void *)skip_and_pad(i);
}

View file

@ -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, size_t *csum);
romfs_get_info(romfs_t romfs, const char *path, size_t *len);
size_t
romfs_mount_check(romfs_t romfs);

View file

@ -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->protocol->callback)(wsi,
m = wsi->vhost->protocols[0].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],
(void *)&opts, 0)) {
&opts, 0)) {
lwsl_notice("ext %s failed construction\n",
ext_name);
ext_count--;

View file

@ -65,7 +65,6 @@ lws_context_init_server(struct lws_context_creation_info *info,
}
#if LWS_POSIX
(void)n;
#if defined(__linux__)
limit = vhost->context->count_threads;
#endif
@ -94,24 +93,6 @@ 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
*/
@ -135,19 +116,13 @@ lws_context_init_server(struct lws_context_creation_info *info,
}
#endif
#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;
}
#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;
}
#endif
#endif
lws_plat_set_socket_options(vhost, sockfd);
@ -333,9 +308,6 @@ 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";
@ -378,15 +350,12 @@ 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)
#if !defined(_WIN32_WCE) && !defined(LWS_WITH_ESP8266) && \
!defined(LWS_WITH_ESP32)
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];
@ -399,7 +368,8 @@ 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)
#if !defined(_WIN32_WCE) && !defined(LWS_WITH_ESP8266) && \
!defined(LWS_WITH_ESP32)
fflags |= lws_vfs_prepare_flags(wsi);
@ -421,33 +391,23 @@ 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 && !defined(LWS_WITH_ESP32)
#if !defined(WIN32) && LWS_POSIX
if ((S_IFMT & st.st_mode) == S_IFLNK) {
len = readlink(path, sym, sizeof(sym) - 1);
if (len) {
@ -470,8 +430,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, "%08llX%08lX",
(unsigned long long)lws_vfs_get_length(wsi->u.http.fop_fd),
n = sprintf(sym, "%08lX%08lX",
(unsigned 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 */
@ -543,10 +503,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)(lws_intptr_t)pvo->value;
wsi->protocol_interpret_idx = (char)(long)pvo->value;
lwsl_info("want %s interpreted by %s\n", path,
wsi->vhost->protocols[(int)(lws_intptr_t)(pvo->value)].name);
wsi->protocol = &wsi->vhost->protocols[(int)(lws_intptr_t)(pvo->value)];
wsi->vhost->protocols[(int)(long)(pvo->value)].name);
wsi->protocol = &wsi->vhost->protocols[(int)(long)(pvo->value)];
if (lws_ensure_user_space(wsi))
return -1;
break;
@ -687,34 +647,6 @@ 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)
{
@ -788,7 +720,7 @@ lws_http_action(struct lws *wsi)
/* we insist on absolute paths */
if (!uri_ptr || uri_ptr[0] != '/') {
if (uri_ptr[0] != '/') {
lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
goto bail_nuke_ah;
@ -806,7 +738,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 = atoll(content_length_str);
wsi->u.http.content_length = atoi(content_length_str);
}
if (wsi->http2_substream) {
@ -906,7 +838,7 @@ lws_http_action(struct lws *wsi)
const char *pa, *me;
struct tm *tmp;
time_t t = time(NULL);
int l = 256, m;
int l = 256;
if (wsi->access_log_pending)
lws_access_log(wsi);
@ -924,7 +856,10 @@ lws_http_action(struct lws *wsi)
if (!pa)
pa = "(unknown)";
me = method_names[meth];
if (meth >= 0)
me = method_names[meth];
else
me = "unknown";
lws_snprintf(wsi->access_log.header_log, l,
"%s - - [%s] \"%s %s %s\"",
@ -939,23 +874,6 @@ 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;
}
@ -1022,14 +940,10 @@ 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)
@ -1084,84 +998,6 @@ 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?
*
@ -1221,6 +1057,7 @@ 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;
@ -1235,6 +1072,17 @@ 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;
}
@ -1299,7 +1147,7 @@ deal_body:
bail_nuke_ah:
/* we're closing, losing some rx is OK */
lws_header_table_force_to_detachable_state(wsi);
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
// lwsl_notice("%s: drop1\n", __func__);
lws_header_table_detach(wsi, 1);
@ -1312,56 +1160,6 @@ 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)
@ -1417,7 +1215,7 @@ raw_transition:
wsi->user_space, NULL, 0))
goto bail_nuke_ah;
lws_header_table_force_to_detachable_state(wsi);
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
lws_union_transition(wsi, LWSCM_RAW);
lws_header_table_detach(wsi, 1);
@ -1658,7 +1456,7 @@ upgrade_ws:
*/
lwsl_info("defaulting to prot handler %d\n",
wsi->vhost->default_protocol_index);
n = wsi->vhost->default_protocol_index;
n = 0;
wsi->protocol = &wsi->vhost->protocols[
(int)wsi->vhost->default_protocol_index];
}
@ -1699,7 +1497,30 @@ upgrade_ws:
goto bail_nuke_ah;
}
lws_same_vh_protocol_insert(wsi, n);
/*
* 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;
/* we are upgrading to ws, so http/1.1 and keepalive +
* pipelined header considerations about keeping the ah around
@ -1731,13 +1552,52 @@ upgrade_ws:
wsi->u.hdr = hdr;
lws_pt_unlock(pt);
lws_server_init_wsi_for_ws(wsi);
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
lwsl_parser("accepted v%02d connection\n",
wsi->ietf_spec_revision);
/* notify user code that we're ready to roll */
if (wsi->protocol->callback)
if (wsi->protocol->callback(wsi, LWS_CALLBACK_ESTABLISHED,
wsi->user_space,
#ifdef LWS_OPENSSL_SUPPORT
wsi->ssl,
#else
NULL,
#endif
0))
return 1;
/* !!! drop ah unreservedly after ESTABLISHED */
if (!wsi->more_rx_waiting) {
lws_header_table_force_to_detachable_state(wsi);
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
//lwsl_notice("%p: dropping ah EST\n", wsi);
lws_header_table_detach(wsi, 1);
@ -1751,7 +1611,7 @@ upgrade_ws:
bail_nuke_ah:
/* drop the header info */
/* we're closing, losing some rx is OK */
lws_header_table_force_to_detachable_state(wsi);
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
//lwsl_notice("%s: drop2\n", __func__);
lws_header_table_detach(wsi, 1);
@ -1822,8 +1682,6 @@ 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++;
/*
@ -1843,12 +1701,7 @@ lws_http_transaction_completed(struct lws *wsi)
lws_access_log(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);
lwsl_info("%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);
@ -1889,23 +1742,8 @@ lws_http_transaction_completed(struct lws *wsi)
wsi->more_rx_waiting);
if (!wsi->more_rx_waiting) {
lws_header_table_force_to_detachable_state(wsi);
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
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);
/*
@ -1914,7 +1752,7 @@ lws_http_transaction_completed(struct lws *wsi)
* will be bound the whole time the connection remains
* open.
*/
lws_set_timeout(wsi, PENDING_TIMEOUT_HOLDING_AH,
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE,
wsi->vhost->keepalive_timeout);
}
}
@ -1936,24 +1774,18 @@ 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 && !(type & LWS_ADOPT_WS_PARENTIO))
if (type & LWS_ADOPT_SOCKET)
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;
@ -1966,39 +1798,19 @@ 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)) {
lwsl_notice("OOM trying to get user_space\n");
if (lws_ensure_user_space(new_wsi))
goto bail;
}
if (type & LWS_ADOPT_WS_PARENTIO) {
new_wsi->desc.sockfd = LWS_SOCK_INVALID;
lwsl_debug("binding to %s\n", new_wsi->protocol->name);
lws_bind_protocol(new_wsi, new_wsi->protocol);
lws_union_transition(new_wsi, LWSCM_WS_SERVING);
lws_server_init_wsi_for_ws(new_wsi);
return new_wsi;
}
} else
if (type & LWS_ADOPT_HTTP) /* he will transition later */
new_wsi->protocol =
&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);
}
new_wsi->protocol = &context->vhost_list->
protocols[vh->default_protocol_index];
if (type & LWS_ADOPT_SOCKET) { /* socket desc */
lwsl_debug("%s: new wsi %p, sockfd %d\n", __func__, new_wsi,
(int)(lws_intptr_t)fd.sockfd);
(int)(size_t)fd.sockfd);
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);
/* 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)
@ -2007,7 +1819,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)(lws_intptr_t)fd.filefd);
(int)(size_t)fd.filefd);
/*
* A new connection was accepted. Give the user a chance to
@ -2022,6 +1834,15 @@ 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)) {
@ -2044,7 +1865,6 @@ 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)) {
@ -2057,20 +1877,9 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
goto fail;
}
/*
* 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 (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;
@ -2081,13 +1890,11 @@ 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;
}
@ -2205,8 +2012,6 @@ 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;
@ -2300,13 +2105,6 @@ 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)) {
@ -2317,8 +2115,7 @@ 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 &&
wsi->state != LWSS_HTTP_ISSUING_FILE) {
if (wsi->state != LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
n = lws_read(wsi, ah->rx + ah->rxpos,
ah->rxlen - ah->rxpos);
if (n < 0) /* we closed wsi */
@ -2329,7 +2126,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 (lws_header_table_is_in_detachable_state(wsi) &&
if (wsi->u.hdr.ah->rxpos == wsi->u.hdr.ah->rxlen &&
(wsi->mode != LWSCM_HTTP_SERVING &&
wsi->mode != LWSCM_HTTP_SERVING_ACCEPTED &&
wsi->mode != LWSCM_HTTP2_SERVING))
@ -2369,8 +2166,7 @@ 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 &&
wsi->state != LWSS_HTTP_ISSUING_FILE) {
if (wsi->state != LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
/*
* this may want to send
* (via HTTP callback for example)
@ -2402,16 +2198,6 @@ 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);
@ -2426,18 +2212,6 @@ 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);
@ -2448,15 +2222,12 @@ try_pollout:
break;
}
/* >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.
*/
/* >0 == completion, <0 == error */
n = lws_serve_http_file_fragment(wsi);
if (n < 0)
if (n < 0 || (n > 0 && lws_http_transaction_completed(wsi))) {
lwsl_info("completed\n");
goto fail;
}
break;
@ -2469,23 +2240,6 @@ 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);
@ -2529,18 +2283,13 @@ try_pollout:
*/
if ((wsi->vhost->protocols[0].callback)(wsi,
LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
NULL, (void *)(lws_intptr_t)accept_fd, 0)) {
NULL, (void *)(long)accept_fd, 0)) {
lwsl_debug("Callback denied network connection\n");
compatible_close(accept_fd);
break;
}
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))
if (!lws_adopt_socket_vhost(wsi->vhost, accept_fd))
/* already closed cleanly as necessary */
return 1;
@ -2577,7 +2326,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;
lws_filepos_t computed_total_content_length;
unsigned long 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)
@ -2678,7 +2427,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 = (lws_filepos_t)rp->agg +
computed_total_content_length = (unsigned long)rp->agg +
6 /* final _lws\r\n */;
lws_ranges_reset(rp);
@ -2699,7 +2448,7 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
}
if (ranges == 1) {
computed_total_content_length = (lws_filepos_t)rp->agg;
computed_total_content_length = (unsigned long)rp->agg;
n = lws_snprintf(cache_control, sizeof(cache_control), "bytes %llu-%llu/%llu",
rp->start, rp->end, rp->extent);
@ -3224,8 +2973,6 @@ struct lws_spa {
char *storage;
char *end;
int max_storage;
char finalized;
};
static int
@ -3341,10 +3088,6 @@ 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);
}
@ -3374,37 +3117,9 @@ 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)
{
@ -3424,7 +3139,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)

View file

@ -24,20 +24,8 @@
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;
@ -58,13 +46,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);
}
LWS_VISIBLE int
int
lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
{
int write_type = LWS_WRITE_PONG;
@ -74,7 +62,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;
@ -102,10 +90,8 @@ 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) {
wsi->socket_is_permanently_unusable = 1;
if (wsi->state == LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE)
goto bail_die; /* retry closing now */
}
if (wsi->mode == LWSCM_WSCL_ISSUE_HTTP_BODY)
goto user_service;
@ -132,41 +118,12 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
#endif
#ifdef LWS_WITH_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;
}
if (wsi->cgi)
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 &&
@ -329,13 +286,6 @@ 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;
@ -348,6 +298,7 @@ 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 */
@ -465,8 +416,6 @@ 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",
@ -655,10 +604,7 @@ lws_http_client_read(struct lws *wsi, char **buf, int *len)
return -1;
}
if (rlen == 0)
return -1;
if (rlen < 0)
if (rlen <= 0)
return 0;
*len = rlen;
@ -725,8 +671,8 @@ spin_chunks:
return 0;
if (wsi->u.http.content_remain &&
wsi->u.http.content_remain < *len)
n = (int)wsi->u.http.content_remain;
(int)wsi->u.http.content_remain < *len)
n = wsi->u.http.content_remain;
else
n = *len;
@ -828,17 +774,8 @@ 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)
@ -854,10 +791,6 @@ 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 */
@ -872,70 +805,7 @@ 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
@ -1026,12 +896,8 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
#endif
// lwsl_debug("fd=%d, revents=%d, mode=%d, state=%d\n", pollfd->fd, pollfd->revents, (int)wsi->mode, (int)wsi->state);
if ((!(pollfd->revents & pollfd->events & LWS_POLLIN)) &&
(pollfd->revents & LWS_POLLHUP)) {
lwsl_debug("pollhup\n");
wsi->socket_is_permanently_unusable = 1;
if (pollfd->revents & LWS_POLLHUP)
goto close_and_handled;
}
#ifdef LWS_OPENSSL_SUPPORT
@ -1135,15 +1001,11 @@ 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)
@ -1153,7 +1015,6 @@ 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
@ -1255,7 +1116,7 @@ read:
eff_buf.token_len = context->pt_serv_buf_size;
}
if ((unsigned int)eff_buf.token_len > context->pt_serv_buf_size)
if (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,
@ -1303,12 +1164,9 @@ drain:
wsi->protocol->callback,
wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP,
wsi->user_space, NULL, 0)) {
lwsl_notice("LWS_CALLBACK_RECEIVE_CLIENT_HTTP closed it\n");
lwsl_debug("LWS_CALLBACK_RECEIVE_CLIENT_HTTP closed it\n");
goto close_and_handled;
}
n = 0;
goto handled;
}
#endif
/*
@ -1360,7 +1218,8 @@ drain:
if (wsi->u.hdr.ah) {
lwsl_notice("%s: %p: detaching\n",
__func__, wsi);
lws_header_table_force_to_detachable_state(wsi);
/* show we used all the pending rx up */
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
/* we can run the normal ah detach flow despite
* being in ws union mode, since all union members
* start with hdr */
@ -1449,7 +1308,7 @@ drain:
goto handled;
close_and_handled:
lwsl_debug("%p: Close and handled\n", wsi);
lwsl_debug("Close and handled\n");
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
/*
* pollfd may point to something else after the close

View file

@ -29,18 +29,12 @@ 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);
#if defined(USE_WOLFSSL)
#ifdef 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;
@ -93,7 +87,6 @@ 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
@ -126,15 +119,10 @@ 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_ssl_elaborate_error();
lws_decode_ssl_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;
@ -149,14 +137,14 @@ lws_ssl_client_bio_create(struct lws *wsi)
#endif
#if !defined(USE_WOLFSSL) && !defined(LWS_WITH_ESP32)
#ifndef USE_WOLFSSL
#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
#if !defined(USE_WOLFSSL) && !defined(LWS_WITH_ESP32)
#ifndef USE_WOLFSSL
SSL_set_mode(wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
#endif
/*
@ -173,18 +161,11 @@ 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
/*
@ -203,12 +184,8 @@ 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
@ -217,26 +194,15 @@ 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)
{
@ -323,7 +289,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_debug("%s: SSL_connect says %d\n", __func__, n);
lwsl_notice("%s: SSL_connect says %d\n", __func__, n);
lws_latency(context, wsi,
"SSL_connect LWSCM_WSCL_WAITING_SSL", n, n > 0);
@ -377,19 +343,6 @@ 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
@ -400,8 +353,6 @@ 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) &&
@ -434,12 +385,10 @@ 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 *private_key_filepath = info->ssl_private_key_filepath;
const char *cert_filepath = info->ssl_cert_filepath;
const char *private_key_filepath = info->ssl_private_key_filepath;
int n;
/*
@ -454,14 +403,10 @@ 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;
@ -471,6 +416,9 @@ 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 */
@ -501,11 +449,8 @@ 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);
@ -536,12 +481,11 @@ 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) {
@ -556,6 +500,7 @@ 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);
@ -576,7 +521,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

View file

@ -27,7 +27,6 @@ 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)
{
@ -51,7 +50,6 @@ 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)
@ -130,9 +128,7 @@ 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;
}
@ -160,7 +156,7 @@ lws_ssl_server_name_cb(SSL *ssl, int *ad, void *arg)
*/
vh = context->vhost_list;
while (vh) {
if (!vh->being_destroyed && vh->ssl_ctx == SSL_get_SSL_CTX(ssl))
if (vh->ssl_ctx == SSL_get_SSL_CTX(ssl))
break;
vh = vh->vhost_next;
}
@ -230,7 +226,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;
@ -251,24 +247,12 @@ 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, (char *)vhost->context);
openssl_SSL_CTX_private_data_index, vhost->context);
/* Disable SSLv2 and SSLv3 */
SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
#ifdef SSL_OP_NO_COMPRESSION
@ -276,11 +260,9 @@ 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? */
@ -292,7 +274,6 @@ 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 *));
@ -300,7 +281,6 @@ 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
@ -312,13 +292,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;
@ -346,7 +326,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);
@ -360,42 +340,8 @@ 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,
@ -407,7 +353,6 @@ 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,
@ -416,13 +361,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;

374
lib/ssl.c
View file

@ -1,7 +1,7 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
* Copyright (C) 2010-2016 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,129 +26,11 @@
#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);
}
@ -199,8 +81,6 @@ 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;
@ -208,11 +88,8 @@ 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)
{
@ -230,6 +107,7 @@ 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
@ -238,7 +116,6 @@ 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)
@ -265,8 +142,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();
@ -275,11 +152,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)
{
@ -291,7 +168,6 @@ 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)
@ -306,16 +182,22 @@ 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
#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);
}
}
LWS_VISIBLE void
@ -352,82 +234,48 @@ lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len)
struct lws_context *context = wsi->context;
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
int n = 0;
#if !defined(LWS_WITH_ESP32)
int ssl_read_errno = 0;
#endif
int ssl_read_errno = 0;
if (!wsi->ssl)
return lws_ssl_capable_read_no_ssl(wsi, 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);
lwsl_debug("%p: ssl err %d errno %d\n", wsi, n, errno);
if (n == SSL_ERROR_ZERO_RETURN)
return LWS_SSL_CAPABLE_ERROR;
n = lws_ssl_get_error(wsi, n);
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
}
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;
}
lwsl_err("%s failed: %s\n",__func__,
ERR_error_string(lws_ssl_get_error(wsi, 0), NULL));
lws_ssl_elaborate_error();
lws_decode_ssl_error();
return LWS_SSL_CAPABLE_ERROR;
}
if (n < 0) {
n = lws_ssl_get_error(wsi, n);
// 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);
if (n == SSL_ERROR_WANT_READ || n == SSL_ERROR_WANT_WRITE)
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_ssl_elaborate_error();
lws_decode_ssl_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;
@ -483,9 +331,7 @@ LWS_VISIBLE int
lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len)
{
int n;
#if !defined(LWS_WITH_ESP32)
int ssl_read_errno = 0;
#endif
int ssl_read_errno = 0;
if (!wsi->ssl)
return lws_ssl_capable_write_no_ssl(wsi, buf, len);
@ -496,19 +342,15 @@ 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) {
lwsl_debug("%s: WANT_WRITE\n", __func__);
if (n == SSL_ERROR_WANT_WRITE)
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
@ -516,97 +358,28 @@ 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_ssl_elaborate_error();
lws_decode_ssl_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)
{
lws_sockfd_type n;
int 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 */
}
@ -618,7 +391,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) && !defined(LWS_WITH_ESP32)
#if !defined(USE_WOLFSSL)
BIO *bio;
#endif
char buf[256];
@ -633,38 +406,20 @@ 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: %d (errno %d)\n",
lws_ssl_get_error(wsi, 0), errno);
lws_ssl_elaborate_error();
lwsl_err("SSL_new failed: %s\n",
ERR_error_string(lws_ssl_get_error(wsi, 0), NULL));
lws_decode_ssl_error();
if (accept_fd != LWS_SOCK_INVALID)
compatible_close(accept_fd);
goto fail;
}
#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
@ -673,9 +428,6 @@ 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);
@ -688,7 +440,6 @@ 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
/*
@ -710,7 +461,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_debug("inserted SSL accept into fds, trying SSL_accept\n");
lwsl_info("inserted SSL accept into fds, trying SSL_accept\n");
/* fallthru */
@ -723,10 +474,8 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
lws_latency_pre(context, wsi);
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);
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
@ -735,6 +484,7 @@ 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
@ -777,27 +527,16 @@ 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 || SSL_want_read(wsi->ssl)) {
if (m == SSL_ERROR_WANT_READ) {
if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
lwsl_err("%s: WANT_READ change_pollfd failed\n", __func__);
goto fail;
@ -806,9 +545,7 @@ go_again:
lwsl_info("SSL_ERROR_WANT_READ\n");
break;
}
if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->ssl)) {
lwsl_debug("%s: WANT_WRITE\n", __func__);
if (m == SSL_ERROR_WANT_WRITE) {
if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) {
lwsl_err("%s: WANT_WRITE change_pollfd failed\n", __func__);
goto fail;
@ -816,19 +553,13 @@ 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);
@ -864,8 +595,6 @@ 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
@ -879,14 +608,9 @@ 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
}

View file

@ -1,5 +1,5 @@
Name: libwebsockets
Version: 2.3.0
Version: 2.2.2
Release: 1%{?dist}
Summary: Websocket Server and Client Library
@ -49,12 +49,13 @@ 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.11
/%{_libdir}/libwebsockets.so.10
/%{_libdir}/libwebsockets.so
/%{_libdir}/cmake/libwebsockets/LibwebsocketsConfig.cmake
/%{_libdir}/cmake/libwebsockets/LibwebsocketsConfigVersion.cmake
@ -69,11 +70,10 @@ rm -rf $RPM_BUILD_ROOT
%attr(755,root,root)
/%{_libdir}/libwebsockets.a
/%{_libdir}/pkgconfig/libwebsockets.pc
/%{_libdir}/pkgconfig/libwebsockets_static.pc
%changelog
* Fri Jul 28 2017 Andy Green <andy@warmcat.com> 2.3.0-1
- MAJOR SONAMEBUMP APICHANGES Upstream 2.3.0 release
* Mon Mar 06 2017 Andy Green <andy@warmcat.com> 2.2.2-1
- MINOR Upstream 2.2.2 release
* Mon Mar 06 2017 Andy Green <andy@warmcat.com> 2.2.0-1
- MAJOR SONAMEBUMP APICHANGES Upstream 2.2.0 release

View file

@ -55,9 +55,6 @@
/* 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
@ -129,26 +126,11 @@
#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}

View file

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

View file

@ -58,13 +58,11 @@ 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 */ }
};
@ -201,9 +199,8 @@ reload_handler(int signum)
int main(int argc, char **argv)
{
int n = 0, debug_level = 7;
int n = 0, m, debug_level = 7;
#ifndef _WIN32
int m;
int status, syslog_options = LOG_PID | LOG_PERROR;
#endif
@ -305,9 +302,8 @@ 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++ < 4096 && uv_loop_close(&loop))
while (n++ < 1024 && uv_loop_close(&loop))
uv_run(&loop, UV_RUN_NOWAIT);
#endif
@ -319,7 +315,5 @@ int main(int argc, char **argv)
closelog();
#endif
context = NULL;
return 0;
}

View file

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

View file

@ -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;

View file

@ -1,239 +0,0 @@
/*
* 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 \
}

View file

@ -1,279 +0,0 @@
/*
* 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 \
}

View file

@ -1,58 +0,0 @@
/*
* 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 \
}

View file

@ -1,33 +1,29 @@
/*
* ESP32 Scan / Factory protocol handler
* 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 file is made available under the Creative Commons CC0 1.0
* Universal Public Domain Dedication.
*
* 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 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.
*
* 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*
* 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 <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;
@ -40,62 +36,29 @@ 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[10];
TimerHandle_t timer, reboot_timer;
wifi_ap_record_t ap_records[20];
TimerHandle_t 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[] = {
{ "\"ssid0\":\"", "0ssid" },
{ ",\"pw0\":\"", "0password" },
{ "\"ssid1\":\"", "1ssid" },
{ ",\"pw1\":\"", "1password" },
{ "\"ssid2\":\"", "2ssid" },
{ ",\"pw2\":\"", "2password" },
{ "\"ssid3\":\"", "3ssid" },
{ ",\"pw3\":\"", "3password" },
{ ",\"access_pw\":\"", "access_pw" },
{ "{\"group\":\"", "group" },
{ "{\"role\":\"", "role" },
{ "ssid\":\"", "ssid" },
{ ",\"pw\":\"", "password" },
{ ",\"serial\":\"", "serial" },
{ ",\"region\":\"", "region" },
};
@ -106,28 +69,12 @@ static wifi_scan_config_t scan_config = {
.show_hidden = true
};
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,
};
extern void (*lws_cb_scan_done)(void *);
extern void *lws_cb_scan_done_arg;
static void
scan_finished(uint16_t count, wifi_ap_record_t *recs, void *v);
scan_finished(void *v);
static int
esplws_simple_arg(char *dest, int len, const char *in, const char *match)
@ -135,8 +82,10 @@ esplws_simple_arg(char *dest, int len, const char *in, const char *match)
const char *p = strstr(in, match);
int n = 0;
if (!p)
if (!p) {
lwsl_err("No match %s\n", match);
return 1;
}
p += strlen(match);
while (*p && *p != '\"' && n < len - 1)
@ -158,8 +107,8 @@ scan_start(struct per_vhost_data__esplws_scan *vhd)
return;
vhd->scan_ongoing = 1;
lws_esp32.scan_consumer = scan_finished;
lws_esp32.scan_consumer_arg = vhd;
lws_cb_scan_done = scan_finished;
lws_cb_scan_done_arg = vhd;
n = esp_wifi_scan_start(&scan_config, false);
if (n != ESP_OK)
lwsl_err("scan start failed %d\n", n);
@ -172,62 +121,19 @@ 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(uint16_t count, wifi_ap_record_t *recs, void *v)
scan_finished(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;
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));
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;
}
while (p) {
if (p->scan_state != SCAN_STATE_INITIAL && p->scan_state != SCAN_STATE_NONE)
@ -238,70 +144,6 @@ scan_finished(uint16_t count, wifi_ap_record_t *recs, 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
@ -314,13 +156,10 @@ 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));
unsigned char *start = pss->buffer + LWS_PRE - 1, *p = start,
*end = pss->buffer + sizeof(pss->buffer) - 1;
char buf[LWS_PRE + 384], /*ip[24],*/ *start = buf + LWS_PRE - 1, *p = start,
*end = buf + sizeof(buf) - 1;
wifi_ap_record_t *r;
int n, m;
nvs_handle nvh;
size_t s;
switch (reason) {
@ -333,8 +172,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;
@ -346,11 +185,6 @@ 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;
@ -362,207 +196,61 @@ 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:
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;
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;
pss->ap_record = 0;
pss->subsequent = 0;
break;
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;
pss->scan_state = SCAN_STATE_KNOWN;
break;
case SCAN_STATE_KNOWN:
if (nvs_open("lws-station", NVS_READONLY, &nvh)) {
lwsl_notice("unable to open nvh\n");
return -1;
}
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;
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;
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;
}
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;
break;
case SCAN_STATE_FINAL:
scan_state_final:
n = LWS_WRITE_CONTINUATION;
p += sprintf((char *)p, "]\n}\n");
p += sprintf(p, "]}");
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);
@ -576,149 +264,40 @@ issue:
case LWS_CALLBACK_RECEIVE:
{
const char *sect = "\"app\": {", *b;
nvs_handle nvh;
char p[64], use[6];
int n, si = -1;
char p[64];
int n;
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;
}
if (!esplws_simple_arg(p, sizeof(p), in, ",\"slot\":\""))
si = atoi(p);
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;
if (esplws_simple_arg(p, sizeof(p), in, store_json[n].j))
goto bail_nvs;
/* 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) {
if (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);
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");
vhd->reboot = 1;
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:
@ -736,235 +315,12 @@ auton:
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 \
@ -972,6 +328,6 @@ bail:
"esplws-scan", \
callback_esplws_scan, \
sizeof(struct per_session_data__esplws_scan), \
1024, 0, NULL, 900 \
512, 0, NULL \
}

View file

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

View file

@ -34,15 +34,8 @@
#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;
};
@ -51,18 +44,11 @@ struct a_message {
size_t len;
};
struct lws_mirror_instance {
struct lws_mirror_instance *next;
struct per_session_data__lws_mirror *same_mi_pss_list;
char name[30];
struct per_vhost_data__lws_mirror {
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)
@ -73,112 +59,14 @@ 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));
struct lws_mirror_instance *mi = NULL;
char name[30];
int n, m, count_mi = 0;
int n, m;
switch (reason) {
case LWS_CALLBACK_ESTABLISHED:
lwsl_info("%s: LWS_CALLBACK_ESTABLISHED\n", __func__);
/*
* 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->ringbuffer_tail = v->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 */
@ -188,13 +76,21 @@ 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 != pss->mi->ringbuffer_head) {
m = pss->mi->ringbuffer[pss->ringbuffer_tail].len;
while (pss->ringbuffer_tail != v->ringbuffer_head) {
m = v->ringbuffer[pss->ringbuffer_tail].len;
n = lws_write(wsi, (unsigned char *)
pss->mi->ringbuffer[pss->ringbuffer_tail].payload +
v->ringbuffer[pss->ringbuffer_tail].payload +
LWS_PRE, m, LWS_WRITE_TEXT);
if (n < 0) {
lwsl_err("ERROR %d writing to mirror socket\n", n);
@ -208,7 +104,7 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
else
pss->ringbuffer_tail++;
if (((pss->mi->ringbuffer_head - pss->ringbuffer_tail) &
if (((v->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));
@ -221,25 +117,25 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
break;
case LWS_CALLBACK_RECEIVE:
if (((pss->mi->ringbuffer_head - pss->ringbuffer_tail) &
if (((v->ringbuffer_head - pss->ringbuffer_tail) &
(MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 1)) {
lwsl_err("dropping!\n");
goto choke;
}
if (pss->mi->ringbuffer[pss->mi->ringbuffer_head].payload)
free(pss->mi->ringbuffer[pss->mi->ringbuffer_head].payload);
if (v->ringbuffer[v->ringbuffer_head].payload)
free(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 +
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 +
LWS_PRE, in, len);
if (pss->mi->ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
pss->mi->ringbuffer_head = 0;
if (v->ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
v->ringbuffer_head = 0;
else
pss->mi->ringbuffer_head++;
v->ringbuffer_head++;
if (((pss->mi->ringbuffer_head - pss->ringbuffer_tail) &
if (((v->ringbuffer_head - pss->ringbuffer_tail) &
(MAX_MESSAGE_QUEUE - 1)) != (MAX_MESSAGE_QUEUE - 2))
goto done;
@ -248,14 +144,8 @@ choke:
lws_rx_flow_control(wsi, 0);
done:
/*
* 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);
lws_callback_on_writable_all_protocol(lws_get_context(wsi),
lws_get_protocol(wsi));
break;
default:

View file

@ -23,7 +23,6 @@
#include "../lib/libwebsockets.h"
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
struct lws_ss_load_sample {
time_t t;

View file

@ -1,121 +0,0 @@
#
# 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

View file

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

View file

@ -263,19 +263,19 @@ static const struct test tests[] = {
}, { 0, 4 }, 1 },
};
static int ring_size(struct ring *r)
static const int ring_size(struct ring *r)
{
return sizeof(r->buf);
}
static int ring_used(struct ring *r)
static const int ring_used(struct ring *r)
{
return (r->head - r->tail) & (ring_size(r) - 1);
}
static int ring_free(struct ring *r)
static const int ring_free(struct ring *r)
{
return (ring_size(r) - 1) - ring_used(r);
}
static int ring_get_one(struct ring *r)
static const int ring_get_one(struct ring *r)
{
int n = r->buf[r->tail] & 255;
@ -842,7 +842,6 @@ 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);

View file

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

View file

@ -168,6 +168,11 @@ 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;
@ -198,6 +203,11 @@ 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 */ }
};

View file

@ -162,7 +162,7 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
l = 0;
while (shift >= 0) {
l |= ((lws_intptr_t)*p++) << shift;
l |= ((unsigned long long)*p++) << shift;
shift -= 8;
}
@ -536,8 +536,7 @@ int main(int argc, char **argv)
/* stats */
if (global_rx_count && global_tx_count)
fprintf(stderr, "\n--- %s websocket ping statistics "
fprintf(stderr, "\n--- %s websocket ping statistics "
"using %d connections ---\n"
"%lu packets transmitted, %lu received, "
"%lu%% packet loss, time %ldms\n"

View file

@ -0,0 +1,122 @@
/*
* 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;
}

View file

@ -141,8 +141,6 @@ 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);
@ -232,37 +230,38 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
goto try_to_reuse;
}
#if !defined(LWS_NO_CLIENT) && defined(LWS_OPENSSL_SUPPORT)
#ifndef LWS_NO_CLIENT
if (!strncmp(in, "/proxytest", 10)) {
struct lws_client_connect_info i;
char *rootpath = "/git/";
char *rootpath = "/";
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 = "libwebsockets.org";
i.port = 443;
i.ssl_connection = 1;
i.address = "git.libwebsockets.org";
i.port = 80;
i.ssl_connection = 0;
if (p[10])
i.path = (char *)in + 10;
else
i.path = rootpath;
i.host = i.address;
i.host = "git.libwebsockets.org";
i.origin = NULL;
i.method = "GET";
i.parent_wsi = wsi;
i.uri_replace_from = "libwebsockets.org/git/";
i.uri_replace_from = "git.libwebsockets.org/";
i.uri_replace_to = "/proxytest/";
if (!lws_client_connect_via_info(&i)) {
lwsl_err("proxy connect fail\n");
break;
}
break;
}
#endif
@ -378,7 +377,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, "Unknown Mimetype");
HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL);
return -1;
}
@ -412,22 +411,16 @@ 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)
return -1; /* error*/
if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi)))
return -1; /* error or can't reuse connection: close the socket */
/*
* notice that the sending of the file completes asynchronously,
* 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.
* it's done
*/
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) {
@ -518,13 +511,11 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
if (pss->client_finished)
return -1;
if (!lws_get_child(wsi) && !pss->fop_fd) {
lwsl_notice("fop_fd NULL\n");
if (!pss->fop_fd)
goto try_to_reuse;
}
#ifndef LWS_NO_CLIENT
if (pss->reason_bf & LWS_CB_REASON_AUX_BF__PROXY) {
if (pss->reason_bf & 2) {
char *px = buf + LWS_PRE;
int lenx = sizeof(buf) - LWS_PRE;
/*
@ -533,24 +524,17 @@ 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 &= ~LWS_CB_REASON_AUX_BF__PROXY;
pss->reason_bf &= ~2;
wsi1 = lws_get_child(wsi);
if (!wsi1)
break;
if (lws_http_client_read(wsi1, &px, &lenx) < 0)
return -1;
goto bail;
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
@ -673,12 +657,16 @@ 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 |= LWS_CB_REASON_AUX_BF__PROXY;
pss1->reason_bf |= 2;
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);
//lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ len %d\n", len);
assert(lws_get_parent(wsi));
m = lws_write(lws_get_parent(wsi), (unsigned char *)in,
len, LWS_WRITE_HTTP);

View file

@ -34,9 +34,35 @@ char *resource_path = LOCAL_RESOURCE_PATH;
char crl_path[1024] = "";
#endif
#define LWS_PLUGIN_STATIC
#include "../plugins/protocol_lws_mirror.c"
#include "../plugins/protocol_lws_status.c"
/*
* 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; \
}
/* singlethreaded version --> no locks */
@ -68,7 +94,6 @@ enum demo_protocols {
PROTOCOL_DUMB_INCREMENT,
PROTOCOL_LWS_MIRROR,
PROTOCOL_LWS_STATUS,
/* always last */
DEMO_PROTOCOL_COUNT
@ -89,13 +114,20 @@ 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
* dumb-increment only sends very small packets, so we set
* this accordingly. If your protocol will send bigger
* things, adjust this to match */
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_MIRROR,
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
{ NULL, NULL, 0, 0 } /* terminator */
};
@ -264,7 +296,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]);
}
@ -332,7 +364,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);

View file

@ -1,345 +0,0 @@
/*
* 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;
}

View file

@ -19,7 +19,6 @@
* MA 02110-1301 USA
*/
#define DI_HANDLED_BY_PLUGIN
#include "test-server.h"
#include <uv.h>
@ -46,12 +45,6 @@ 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
@ -73,8 +66,6 @@ enum demo_protocols {
PROTOCOL_DUMB_INCREMENT,
PROTOCOL_LWS_MIRROR,
PROTOCOL_LWS_STATUS,
PROTOCOL_LWS_META,
/* always last */
DEMO_PROTOCOL_COUNT
@ -91,10 +82,24 @@ static struct lws_protocols protocols[] = {
sizeof (struct per_session_data__http), /* per_session_data_size */
0, /* max frame size / rx buffer */
},
LWS_PLUGIN_PROTOCOL_DUMB_INCREMENT,
LWS_PLUGIN_PROTOCOL_MIRROR,
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
LWS_PLUGIN_PROTOCOL_LWS_META,
{
"dumb-increment-protocol",
callback_dumb_increment,
sizeof(struct per_session_data__dumb_increment),
10,
},
{
"lws-mirror-protocol",
callback_lws_mirror,
sizeof(struct per_session_data__lws_mirror),
128,
},
{
"lws-status",
callback_lws_status,
sizeof(struct per_session_data__lws_status),
128,
},
{ NULL, NULL, 0, 0 } /* terminator */
};
@ -127,6 +132,16 @@ 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' },
@ -207,6 +222,7 @@ 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];
@ -390,6 +406,9 @@ 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) {
/*
@ -418,6 +437,8 @@ 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");
@ -459,9 +480,6 @@ 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
{
@ -469,12 +487,9 @@ 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;
}

View file

@ -0,0 +1,137 @@
/*
* 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;
}

View file

@ -37,10 +37,6 @@ 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
@ -91,7 +87,6 @@ enum demo_protocols {
PROTOCOL_DUMB_INCREMENT,
PROTOCOL_LWS_MIRROR,
PROTOCOL_LWS_STATUS,
/* always last */
DEMO_PROTOCOL_COUNT
@ -112,13 +107,14 @@ 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
* dumb-increment only sends very small packets, so we set
* this accordingly. If your protocol will send bigger
* things, adjust this to match */
10,
},
{
"lws-mirror-protocol",
callback_lws_mirror,
sizeof(struct per_session_data__lws_mirror),
128,
},
LWS_PLUGIN_PROTOCOL_MIRROR,
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
{ NULL, NULL, 0, 0 } /* terminator */
};
@ -142,7 +138,7 @@ void *thread_dumb_increment(void *threadid)
void *thread_service(void *threadid)
{
while (lws_service_tsi(context, 50, (int)(lws_intptr_t)threadid) >= 0 && !force_exit)
while (lws_service_tsi(context, 50, (int)(long)threadid) >= 0 && !force_exit)
;
pthread_exit(NULL);
@ -368,7 +364,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 *)(lws_intptr_t)n))
(void *)(long)n))
lwsl_err("Failed to start service thread\n");
/* wait for all the service threads to exit */

View file

@ -0,0 +1,173 @@
/*
* 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;
}

View file

@ -19,27 +19,14 @@
*/
#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;
@ -60,44 +47,6 @@ 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);
@ -198,14 +147,13 @@ 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,
@ -226,15 +174,8 @@ 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_5 = {
NULL,
NULL,
"lws-meta",
"" /* ignored, just matches the protocol name above */
};
static const struct lws_protocol_vhost_options pvo_4 = {
&pvo_5,
NULL,
&pvo_opt4, /* set us as the protocol who gets raw connections */
"protocol-lws-raw-test",
"" /* ignored, just matches the protocol name above */
@ -263,7 +204,7 @@ static const struct lws_protocol_vhost_options pvo_1 = {
static const struct lws_protocol_vhost_options pvo = {
&pvo_1,
NULL, // &pvo_opt,
&pvo_opt,
"dumb-increment-protocol",
""
};
@ -288,7 +229,6 @@ 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' },
@ -314,7 +254,7 @@ static const char * const plugin_dirs[] = {
int main(int argc, char **argv)
{
struct lws_vhost *vhost;
struct lws_context_creation_info info;
char interface_name[128] = "";
const char *iface = NULL;
char cert_path[1024] = "";
@ -339,7 +279,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:S",
n = getopt_long(argc, argv, "i:hsap:d:Dr:C:K:A:R:vu:g:",
(struct option *)options, NULL);
if (n < 0)
continue;
@ -364,11 +304,6 @@ 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;
@ -431,9 +366,6 @@ 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 */
@ -445,7 +377,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-2017 Andy Green <andy@warmcat.com>\n");
lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n");
lwsl_notice(" Using resource path \"%s\"\n", resource_path);
@ -456,8 +388,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_EXPLICIT_VHOSTS |
LWS_SERVER_OPTION_FALLBACK_TO_RAW |
info.options = opts | LWS_SERVER_OPTION_FALLBACK_TO_RAW |
LWS_SERVER_OPTION_VALIDATE_UTF8 |
LWS_SERVER_OPTION_LIBUV; /* plugins require this */
@ -508,16 +439,17 @@ 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;
/*
* 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.
* 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.
*/
context = lws_create_context(&info);
if (context == NULL) {
@ -525,42 +457,15 @@ 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");
goto bail;
}
else
lws_libuv_run(context, 0);
#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

View file

@ -29,8 +29,7 @@ struct lws_pollfd *pollfds;
int *fd_lookup;
int count_pollfds;
#endif
volatile int force_exit = 0, dynamic_vhost_enable = 0;
struct lws_vhost *dynamic_vhost;
volatile int force_exit = 0;
struct lws_context *context;
struct lws_plat_file_ops fops_plat;
@ -41,35 +40,6 @@ 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)
@ -92,9 +62,6 @@ 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 {
@ -103,10 +70,9 @@ enum demo_protocols {
PROTOCOL_DUMB_INCREMENT,
PROTOCOL_LWS_MIRROR,
PROTOCOL_LWS_ECHOGEN,
PROTOCOL_LWS_STATUS,
PROTOCOL_LWS_META,
/* always last */
DEMO_PROTOCOL_COUNT
};
@ -126,15 +92,26 @@ 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
* dumb-increment only sends very small packets, so we set
* this accordingly. If your protocol will send bigger
* things, adjust this to match */
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 */
},
LWS_PLUGIN_PROTOCOL_MIRROR,
LWS_PLUGIN_PROTOCOL_LWS_STATUS,
LWS_PLUGIN_PROTOCOL_LWS_META,
{ NULL, NULL, 0, 0 } /* terminator */
};
@ -165,20 +142,6 @@ 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);
}
@ -228,7 +191,6 @@ 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;
@ -260,7 +222,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:k", options, NULL);
n = getopt_long(argc, argv, "eci:hsap:d:Dr:C:K:A:R:vu:g:P:", options, NULL);
if (n < 0)
continue;
switch (n) {
@ -286,7 +248,6 @@ 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;
@ -299,13 +260,6 @@ 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 "
@ -367,11 +321,6 @@ 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 */
@ -426,7 +375,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 | LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
info.options = opts | LWS_SERVER_OPTION_VALIDATE_UTF8;
info.extensions = exts;
info.timeout_secs = 5;
info.ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
@ -453,24 +402,6 @@ 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)
@ -549,17 +480,6 @@ 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

View file

@ -96,22 +96,48 @@ 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);
#if !defined(DI_HANDLED_BY_PLUGIN)
extern int
callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len);
extern int
callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len);
#endif
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);
extern void

View file

@ -490,7 +490,7 @@ document.getElementById("brow").textContent = " " + BrowserDetect.browser + " "
var pos = 0;
function get_appropriate_ws_url(extra_url)
function get_appropriate_ws_url()
{
var pcol;
var u = document.URL;
@ -513,51 +513,24 @@ function get_appropriate_ws_url(extra_url)
/* + "/xxx" bit is for IE10 workaround */
return pcol + u[0] + "/" + extra_url;
return pcol + u[0] + "/xxx";
}
var params = {};
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);
document.getElementById("number").textContent = get_appropriate_ws_url();
/* 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 = lws_meta.new_ws("", "dumb-increment-protocol");
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");
}
try {
socket_di.onopen = function() {
@ -581,8 +554,14 @@ document.getElementById("number").textContent = get_appropriate_ws_url(mirror_na
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() {
@ -595,8 +574,6 @@ document.getElementById("number").textContent = get_appropriate_ws_url(mirror_na
socket_status.onmessage =function got_packet(msg) {
var s;
console.log(msg.data);
jso = JSON.parse(msg.data);
document.getElementById("servinfo").innerHTML =
@ -648,11 +625,13 @@ function on_pmd() {
var socket_ot;
function ot_open() {
socket_ot = lws_meta.new_ws(get_appropriate_ws_url(""), "dumb-increment-protocol");
console.log("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");
}
try {
socket_ot.onopen = function() {
document.getElementById("ot_statustd").style.backgroundColor = "#40ff40";
@ -660,7 +639,6 @@ 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){
@ -695,8 +673,14 @@ function ot_req_close() {
var socket_lm;
var color = "#000000";
socket_lm = lws_meta.new_ws(get_appropriate_ws_url("?mirror=" + mirror_name),
"lws-mirror-protocol");
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");
}
try {
socket_lm.onopen = function() {