Author: Andy Green Date: Fri Sep 22 02:46:58 2017 +0100 clean up top level of project diff --git a/.travis.yml b/.travis.yml index 3f5293c..f6f0e2e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,7 @@ os: - osx language: generic install: - - ./travis_install.sh + - ./scripts/travis_install.sh script: - if [ "$COVERITY_SCAN_BRANCH" != 1 -a "$TRAVIS_OS_NAME" = "osx" ]; then mkdir build && cd build && cmake -DOPENSSL_ROOT_DIR="/usr/local/opt/openssl" $CMAKE_ARGS .. && cmake --build .; else if [ "$COVERITY_SCAN_BRANCH" != 1 -a "$TRAVIS_OS_NAME" = "linux" ]; then mkdir build && cd build && cmake $CMAKE_ARGS .. && cmake --build .; fi ; fi sudo: required diff --git a/Android.mk b/Android.mk deleted file mode 100644 index 20b2e10..0000000 --- a/Android.mk +++ /dev/null @@ -1,29 +0,0 @@ -# example Android Native Library makefile -# contributed by Gregory Junker - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := libwebsockets -LOCAL_CFLAGS := -DLWS_BUILTIN_GETIFADDRS -LWS_LIB_PATH := ../../../shared/libwebsockets/lib -LOCAL_C_INCLUDES:= $(LOCAL_PATH)/$(LWS_LIB_PATH) -LOCAL_SRC_FILES := \ - $(LWS_LIB_PATH)/base64-decode.c \ - $(LWS_LIB_PATH)/client.c \ - $(LWS_LIB_PATH)/client-handshake.c \ - $(LWS_LIB_PATH)/client-parser.c \ - $(LWS_LIB_PATH)/daemonize.c \ - $(LWS_LIB_PATH)/extension.c \ - $(LWS_LIB_PATH)/extension-deflate-frame.c \ - $(LWS_LIB_PATH)/extension-deflate-stream.c \ - $(LWS_LIB_PATH)/getifaddrs.c \ - $(LWS_LIB_PATH)/handshake.c \ - $(LWS_LIB_PATH)/libwebsockets.c \ - $(LWS_LIB_PATH)/md5.c \ - $(LWS_LIB_PATH)/output.c \ - $(LWS_LIB_PATH)/parsers.c \ - $(LWS_LIB_PATH)/sha-1.c - -include $(BUILD_STATIC_LIBRARY) diff --git a/CMakeLists.txt b/CMakeLists.txt index d33dcda..e888191 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1158,12 +1158,12 @@ endif() set(CMAKE_REQUIRED_LIBRARIES ${temp}) # Generate the lws_config.h that includes all the public compilation settings. configure_file( - "${PROJECT_SOURCE_DIR}/lws_config.h.in" + "${PROJECT_SOURCE_DIR}/cmake/lws_config.h.in" "${PROJECT_BINARY_DIR}/lws_config.h") # Generate the lws_config.h that includes all the private compilation settings. configure_file( - "${PROJECT_SOURCE_DIR}/lws_config_private.h.in" + "${PROJECT_SOURCE_DIR}/cmake/lws_config_private.h.in" "${PROJECT_BINARY_DIR}/lws_config_private.h") # Generate self-signed SSL certs for the test-server. @@ -1349,14 +1349,14 @@ if (NOT LWS_WITHOUT_TESTAPPS) # test-server # if (NOT LWS_WITHOUT_TEST_SERVER) - create_test_app(test-server "test-server/test-server.c" - "test-server/test-server-http.c" - "test-server/test-server-dumb-increment.c" + create_test_app(test-server "test-apps/test-server.c" + "test-apps/test-server-http.c" + "test-apps/test-server-dumb-increment.c" "" "" "") if (UNIX) - create_test_app(test-fuzxy "test-server/fuzxy.c" + create_test_app(test-fuzxy "test-apps/fuzxy.c" "" "" "" @@ -1365,9 +1365,9 @@ 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) 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-apps/test-server-pthreads.c" + "test-apps/test-server-http.c" + "test-apps/test-server-dumb-increment.c" "" "" "") @@ -1375,20 +1375,20 @@ if (NOT LWS_WITHOUT_TESTAPPS) if (NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) AND LWS_WITH_LIBEV) create_test_app(test-server-libev - "test-server/test-server-libev.c" - "test-server/test-server-http.c" - "test-server/test-server-dumb-increment.c" + "test-apps/test-server-libev.c" + "test-apps/test-server-http.c" + "test-apps/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" ) + set_source_files_properties( test-apps/test-server-libev.c PROPERTIES COMPILE_FLAGS "-Wno-error" ) endif() if (NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) AND LWS_WITH_LIBUV) create_test_app(test-server-libuv - "test-server/test-server-libuv.c" - "test-server/test-server-http.c" + "test-apps/test-server-libuv.c" + "test-apps/test-server-http.c" "" "" "" @@ -1397,9 +1397,9 @@ if (NOT LWS_WITHOUT_TESTAPPS) 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-apps/test-server-libevent.c" + "test-apps/test-server-http.c" + "test-apps/test-server-dumb-increment.c" "" "" "") @@ -1410,9 +1410,9 @@ if (NOT LWS_WITHOUT_TESTAPPS) # test-server-extpoll # if (NOT LWS_WITHOUT_TEST_SERVER_EXTPOLL) - create_test_app(test-server-extpoll "test-server/test-server.c" - "test-server/test-server-http.c" - "test-server/test-server-dumb-increment.c" + create_test_app(test-server-extpoll "test-apps/test-server.c" + "test-apps/test-server-http.c" + "test-apps/test-server-dumb-increment.c" "" "" "") @@ -1436,7 +1436,7 @@ if (NOT LWS_WITHOUT_TESTAPPS) if (LWS_WITH_PLUGINS) create_test_app( test-server-v2.0 - "test-server/test-server-v2.0.c" + "test-apps/test-server-v2.0.c" "" "" "" @@ -1446,12 +1446,12 @@ if (NOT LWS_WITHOUT_TESTAPPS) # Data files for running the test server. set(TEST_SERVER_DATA - "${PROJECT_SOURCE_DIR}/test-server/favicon.ico" - "${PROJECT_SOURCE_DIR}/test-server/leaf.jpg" - "${PROJECT_SOURCE_DIR}/test-server/candide.zip" - "${PROJECT_SOURCE_DIR}/test-server/libwebsockets.org-logo.png" - "${PROJECT_SOURCE_DIR}/test-server/lws-common.js" - "${PROJECT_SOURCE_DIR}/test-server/test.html") + "${PROJECT_SOURCE_DIR}/test-apps/favicon.ico" + "${PROJECT_SOURCE_DIR}/test-apps/leaf.jpg" + "${PROJECT_SOURCE_DIR}/test-apps/candide.zip" + "${PROJECT_SOURCE_DIR}/test-apps/libwebsockets.org-logo.png" + "${PROJECT_SOURCE_DIR}/test-apps/lws-common.js" + "${PROJECT_SOURCE_DIR}/test-apps/test.html") add_custom_command(TARGET test-server POST_BUILD @@ -1473,27 +1473,27 @@ if (NOT LWS_WITHOUT_TESTAPPS) # test-client # if (NOT LWS_WITHOUT_TEST_CLIENT) - create_test_app(test-client "test-server/test-client.c" "" "" "" "" "") + create_test_app(test-client "test-apps/test-client.c" "" "" "" "" "") endif() # # test-fraggle # if (NOT LWS_WITHOUT_TEST_FRAGGLE) - create_test_app(test-fraggle "test-server/test-fraggle.c" "" "" "" "" "") + create_test_app(test-fraggle "test-apps/test-fraggle.c" "" "" "" "" "") endif() # # test-ping # if (NOT LWS_WITHOUT_TEST_PING) - create_test_app(test-ping "test-server/test-ping.c" "" "" "" "" "") + create_test_app(test-ping "test-apps/test-ping.c" "" "" "" "" "") endif() # # test-echo # if (NOT LWS_WITHOUT_TEST_ECHO) - create_test_app(test-echo "test-server/test-echo.c" "" "" "" "" "") + create_test_app(test-echo "test-apps/test-echo.c" "" "" "" "" "") endif() endif(NOT LWS_WITHOUT_CLIENT) @@ -1782,11 +1782,11 @@ if (NOT LWS_WITHOUT_TESTAPPS AND NOT LWS_WITHOUT_SERVER) DESTINATION share/libwebsockets-test-server COMPONENT examples) - install(FILES "${PROJECT_SOURCE_DIR}/test-server/private/index.html" + install(FILES "${PROJECT_SOURCE_DIR}/test-apps/private/index.html" DESTINATION share/libwebsockets-test-server/private COMPONENT examples) if (LWS_WITH_CGI) - set(CGI_TEST_SCRIPT "${PROJECT_SOURCE_DIR}/test-server/lws-cgi-test.sh") + set(CGI_TEST_SCRIPT "${PROJECT_SOURCE_DIR}/test-apps/lws-cgi-test.sh") install(FILES ${CGI_TEST_SCRIPT} PERMISSIONS OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE OWNER_READ GROUP_READ WORLD_READ DESTINATION share/libwebsockets-test-server @@ -1857,7 +1857,7 @@ add_custom_target(dist COMMAND "${CMAKE_MAKE_PROGRAM}" package_source) include(UseRPMTools) if (RPMTools_FOUND) - RPMTools_ADD_RPM_TARGETS(libwebsockets libwebsockets.spec) + RPMTools_ADD_RPM_TARGETS(libwebsockets scripts/libwebsockets.spec) endif() message("---------------------------------------------------------------------") diff --git a/FindLibWebSockets.cmake b/FindLibWebSockets.cmake deleted file mode 100644 index 1dfe115..0000000 --- a/FindLibWebSockets.cmake +++ /dev/null @@ -1,33 +0,0 @@ -# This module tries to find libWebsockets library and include files -# -# LIBWEBSOCKETS_INCLUDE_DIR, path where to find libwebsockets.h -# LIBWEBSOCKETS_LIBRARY_DIR, path where to find libwebsockets.so -# LIBWEBSOCKETS_LIBRARIES, the library to link against -# LIBWEBSOCKETS_FOUND, If false, do not try to use libWebSockets -# -# This currently works probably only for Linux - -FIND_PATH ( LIBWEBSOCKETS_INCLUDE_DIR libwebsockets.h - /usr/local/include - /usr/include -) - -FIND_LIBRARY ( LIBWEBSOCKETS_LIBRARIES websockets - /usr/local/lib - /usr/lib -) - -GET_FILENAME_COMPONENT( LIBWEBSOCKETS_LIBRARY_DIR ${LIBWEBSOCKETS_LIBRARIES} PATH ) - -SET ( LIBWEBSOCKETS_FOUND "NO" ) -IF ( LIBWEBSOCKETS_INCLUDE_DIR ) - IF ( LIBWEBSOCKETS_LIBRARIES ) - SET ( LIBWEBSOCKETS_FOUND "YES" ) - ENDIF ( LIBWEBSOCKETS_LIBRARIES ) -ENDIF ( LIBWEBSOCKETS_INCLUDE_DIR ) - -MARK_AS_ADVANCED( - LIBWEBSOCKETS_LIBRARY_DIR - LIBWEBSOCKETS_INCLUDE_DIR - LIBWEBSOCKETS_LIBRARIES -) \ No newline at end of file diff --git a/LICENSE b/LICENSE index 48a1863..c2f3dca 100644 --- a/LICENSE +++ b/LICENSE @@ -45,8 +45,8 @@ Relicensed to libwebsocket license Public Domain (CC-zero) to simplify reuse - - test-server/*.c - - test-server/*.h + - test-apps/*.c + - test-apps/*.h - lwsws/* ------ end of exceptions diff --git a/README.build.md b/README.build.md deleted file mode 100644 index dd3494a..0000000 --- a/README.build.md +++ /dev/null @@ -1,469 +0,0 @@ -Notes about building lws -======================== - - -@section cm Introduction to CMake - -CMake is a multi-platform build tool that can generate build files for many -different target platforms. See more info at http://www.cmake.org - -CMake also allows/recommends you to do "out of source"-builds, that is, -the build files are separated from your sources, so there is no need to -create elaborate clean scripts to get a clean source tree, instead you -simply remove your build directory. - -Libwebsockets has been tested to build successfully on the following platforms -with SSL support (for OpenSSL/wolfSSL/BoringSSL): - -- Windows (Visual Studio) -- Windows (MinGW) -- Linux (x86 and ARM) -- OSX -- NetBSD - - -@section build1 Building the library and test apps - -The project settings used by CMake to generate the platform specific build -files is called [CMakeLists.txt](CMakeLists.txt). CMake then uses one of its "Generators" to -output a Visual Studio project or Make file for instance. To see a list of -the available generators for your platform, simply run the "cmake" command. - -Note that by default OpenSSL will be linked, if you don't want SSL support -see below on how to toggle compile options. - - -@section bu Building on Unix: - -1. Install CMake 2.8 or greater: http://cmake.org/cmake/resources/software.html - (Most Unix distributions comes with a packaged version also) - -2. Install OpenSSL. - -3. Generate the build files (default is Make files): -``` - $ cd /path/to/src - $ mkdir build - $ cd build - $ cmake .. -``` - -4. Finally you can build using the generated Makefile: -``` - $ make && sudo make install -``` -**NOTE**: The `build/`` directory can have any name and be located anywhere - on your filesystem, and that the argument `..` given to cmake is simply - the source directory of **libwebsockets** containing the [CMakeLists.txt](CMakeLists.txt) - project file. All examples in this file assumes you use ".." - -**NOTE2**: -A common option you may want to give is to set the install path, same -as --prefix= with autotools. It defaults to /usr/local. -You can do this by, eg -``` - $ cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr . -``` - -**NOTE3**: -On machines that want libraries in lib64, you can also add the -following to the cmake line -``` - -DLIB_SUFFIX=64 -``` - -**NOTE4**: -If you are building against a non-distro OpenSSL (eg, in order to get -access to ALPN support only in newer OpenSSL versions) the nice way to -express that in one cmake command is eg, -``` - $ cmake .. -DOPENSSL_ROOT_DIR=/usr/local/ssl \ - -DCMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE=/usr/local/ssl \ - -DLWS_WITH_HTTP2=1 -``` - -When you run the test apps using non-distro SSL, you have to force them -to use your libs, not the distro ones -``` - $ LD_LIBRARY_PATH=/usr/local/ssl/lib libwebsockets-test-server --ssl -``` - -To get it to build on latest openssl (2016-04-10) it needed this approach -``` - cmake .. -DLWS_WITH_HTTP2=1 -DLWS_OPENSSL_INCLUDE_DIRS=/usr/local/include/openssl -DLWS_OPENSSL_LIBRARIES="/usr/local/lib64/libssl.so;/usr/local/lib64/libcrypto.so" -``` - -Mac users have reported - -``` - $ export OPENSSL_ROOT_DIR=/usr/local/Cellar/openssl/1.0.2k; cmake ..; make -j4 -``` - -worked for them when using "homebrew" OpenSSL - -**NOTE5**: -To build with debug info and _DEBUG for lower priority debug messages -compiled in, use -``` - $ cmake .. -DCMAKE_BUILD_TYPE=DEBUG -``` - -**NOTE6** -To build on Solaris the linker needs to be informed to use lib socket -and libnsl, and only builds in 64bit mode. - -```bash - $ cmake .. -DCMAKE_C_FLAGS=-m64 -DCMAKE_EXE_LINKER_FLAGS="-lsocket -lnsl" -``` - -4. Finally you can build using the generated Makefile: - -```bash - $ 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) - -1. Install CMake 2.6 or greater: http://cmake.org/cmake/resources/software.html - -2. Install OpenSSL binaries. http://www.openssl.org/related/binaries.html - - (**NOTE**: Preferably in the default location to make it easier for CMake to find them) - - **NOTE2**: - Be sure that OPENSSL_CONF environment variable is defined and points at - \bin\openssl.cfg - -3. Generate the Visual studio project by opening the Visual Studio cmd prompt: - -``` - cd - md build - cd build - cmake -G "Visual Studio 10" .. -``` - - (**NOTE**: There is also a cmake-gui available on Windows if you prefer that) - - **NOTE2**: - See this link to find out the version number corresponding to your Visual Studio edition: - http://superuser.com/a/194065 - -4. Now you should have a generated Visual Studio Solution in your - `/build` directory, which can be used to build. - -5. Some additional deps may be needed - - - iphlpapi.lib - - psapi.lib - - userenv.lib - -6. If you're using libuv, you must make sure to compile libuv with the same multithread-dll / Mtd attributes as libwebsockets itself - - -@section cmwmgw Building on Windows (MinGW) - -1. Install MinGW: http://sourceforge.net/projects/mingw/files - - (**NOTE**: Preferably in the default location C:\MinGW) - -2. Fix up MinGW headers - - a) If still necessary, sdd the following lines to C:\MinGW\include\winsock2.h: -``` - #if(_WIN32_WINNT >= 0x0600) - - typedef struct pollfd { - - SOCKET fd; - SHORT events; - SHORT revents; - - } WSAPOLLFD, *PWSAPOLLFD, FAR *LPWSAPOLLFD; - - WINSOCK_API_LINKAGE int WSAAPI WSAPoll(LPWSAPOLLFD fdArray, ULONG fds, INT timeout); - - #endif // (_WIN32_WINNT >= 0x0600) -``` - - 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 - -3. Install CMake 2.6 or greater: http://cmake.org/cmake/resources/software.html - -4. Install OpenSSL binaries. http://www.openssl.org/related/binaries.html - - (**NOTE**: Preferably in the default location to make it easier for CMake to find them) - - **NOTE2**: - Be sure that OPENSSL_CONF environment variable is defined and points at - \bin\openssl.cfg - -5. Generate the build files (default is Make files) using MSYS shell: -``` - $ cd /drive/path/to/src - $ mkdir build - $ cd build - $ cmake -G "MSYS Makefiles" -DCMAKE_INSTALL_PREFIX=C:/MinGW .. -``` - (**NOTE**: The `build/`` directory can have any name and be located anywhere - on your filesystem, and that the argument `..` given to cmake is simply - the source directory of **libwebsockets** containing the [CMakeLists.txt](CMakeLists.txt) - project file. All examples in this file assumes you use "..") - - **NOTE2**: - To generate build files allowing to create libwebsockets binaries with debug information - set the CMAKE_BUILD_TYPE flag to DEBUG: -``` - $ cmake -G "MSYS Makefiles" -DCMAKE_INSTALL_PREFIX=C:/MinGW -DCMAKE_BUILD_TYPE=DEBUG .. -``` -6. Finally you can build using the generated Makefile and get the results deployed into your MinGW installation: - -``` - $ make - $ make install -``` - -@section optee Building for OP-TEE - -OP-TEE is a "Secure World" Trusted Execution Environment. - -Although lws is only part of the necessary picture to have an https-enabled -TA, it does support OP-TEE as a platform and if you provide the other -pieces, does work very well. - -Select it in cmake with `-DLWS_PLAT_OPTEE=1` - - -@section cmco Setting compile options - -To set compile time flags you can either use one of the CMake gui applications -or do it via the command line. - -@subsection cmcocl Command line - -To list available options (omit the H if you don't want the help text): - - cmake -LH .. - -Then to set an option and build (for example turn off SSL support): - - cmake -DLWS_WITH_SSL=0 .. -or - cmake -DLWS_WITH_SSL:BOOL=OFF .. - -@subsection cmcoug Unix GUI - -If you have a curses-enabled build you simply type: -(not all packages include this, my debian install does not for example). - - ccmake - -@subsection cmcowg Windows GUI - -On windows CMake comes with a gui application: - Start -> Programs -> CMake -> CMake (cmake-gui) - - -@section wolf wolfSSL/CyaSSL replacement for OpenSSL - -wolfSSL/CyaSSL is a lightweight SSL library targeted at embedded systems: -https://www.wolfssl.com/wolfSSL/Products-wolfssl.html - -It contains a OpenSSL compatibility layer which makes it possible to pretty -much link to it instead of OpenSSL, giving a much smaller footprint. - -**NOTE**: wolfssl needs to be compiled using the `--enable-opensslextra` flag for -this to work. - -@section wolf1 Compiling libwebsockets with wolfSSL - -``` - cmake .. -DLWS_USE_WOLFSSL=1 \ - -DLWS_WOLFSSL_INCLUDE_DIRS=/path/to/wolfssl \ - -DLWS_WOLFSSL_LIBRARIES=/path/to/wolfssl/wolfssl.a .. -``` - -**NOTE**: On windows use the .lib file extension for `LWS_WOLFSSL_LIBRARIES` instead. - -@section cya Compiling libwebsockets with CyaSSL - -``` - cmake .. -DLWS_USE_CYASSL=1 \ - -DLWS_CYASSL_INCLUDE_DIRS=/path/to/cyassl \ - -DLWS_CYASSL_LIBRARIES=/path/to/wolfssl/cyassl.a .. -``` - -**NOTE**: On windows use the .lib file extension for `LWS_CYASSL_LIBRARIES` instead. - -@section esp32 Building for ESP32 - -Step 1, get ESP-IDF with lws integrated as a component - -``` - $ git clone --int --recursive https://github.com/lws-team/lws-esp-idf -``` - -Step 2: Get Application including the test plugins - -``` - $ git clone https://github.com/lws-team/lws-esp32 -``` - -Set your IDF_PATH to point to the esp-idf you downloaded in 1) - -There's docs for how to build the lws-esp32 test app and reproduce it in the README.md here - -https://github.com/lws-team/lws-esp32/blob/master/README.md - - -@section extplugins Building plugins outside of lws itself - -The directory ./plugin-standalone/ shows how easy it is to create plugins -outside of lws itself. First build lws itself with -DLWS_WITH_PLUGINS, -then use the same flow to build the standalone plugin -``` - cd ./plugin-standalone - mkdir build - cd build - cmake .. - make && sudo make install -``` - -if you changed the default plugin directory when you built lws, you must -also give the same arguments to cmake here (eg, -` -DCMAKE_INSTALL_PREFIX:PATH=/usr/something/else...` ) - -Otherwise if you run lwsws or libwebsockets-test-server-v2.0, it will now -find the additional plugin "libprotocol_example_standalone.so" -``` - lwsts[21257]: Plugins: - lwsts[21257]: libprotocol_dumb_increment.so - lwsts[21257]: libprotocol_example_standalone.so - lwsts[21257]: libprotocol_lws_mirror.so - lwsts[21257]: libprotocol_lws_server_status.so - lwsts[21257]: libprotocol_lws_status.so -``` -If you have multiple vhosts, you must enable plugins at the vhost -additionally, discovered plugins are not enabled automatically for security -reasons. You do this using info->pvo or for lwsws, in the JSON config. - - -@section http2rp Reproducing HTTP2.0 tests - -You must have built and be running lws against a version of openssl that has -ALPN / NPN. Most distros still have older versions. You'll know it's right by -seeing -``` - lwsts[4752]: Compiled with OpenSSL support - lwsts[4752]: Using SSL mode - lwsts[4752]: HTTP2 / ALPN enabled -``` -at lws startup. - -For non-SSL HTTP2.0 upgrade -``` - $ nghttp -nvasu http://localhost:7681/test.htm -``` -For SSL / ALPN HTTP2.0 upgrade -``` - $ nghttp -nvas https://localhost:7681/test.html -``` - -@section cross Cross compiling - -To enable cross-compiling **libwebsockets** using CMake you need to create -a "Toolchain file" that you supply to CMake when generating your build files. -CMake will then use the cross compilers and build paths specified in this file -to look for dependencies and such. - -**Libwebsockets** includes an example toolchain file [cross-arm-linux-gnueabihf.cmake](cross-arm-linux-gnueabihf.cmake) -you can use as a starting point. - -The commandline to configure for cross with this would look like -``` - $ cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/usr \ - -DCMAKE_TOOLCHAIN_FILE=../cross-arm-linux-gnueabihf.cmake \ - -DLWS_WITHOUT_EXTENSIONS=1 -DLWS_WITH_SSL=0 -``` -The example shows how to build with no external cross lib dependencies, you -need to provide the cross libraries otherwise. - -**NOTE**: start from an EMPTY build directory if you had a non-cross build in there - before the settings will be cached and your changes ignored. - -Additional information on cross compilation with CMake: - http://www.vtk.org/Wiki/CMake_Cross_Compiling - -@section mem Memory efficiency - -Embedded server-only configuration without extensions (ie, no compression -on websocket connections), but with full v13 websocket features and http -server, built on ARM Cortex-A9: - -Update at 8dac94d (2013-02-18) -``` - $ ./configure --without-client --without-extensions --disable-debug --without-daemonize - - Context Creation, 1024 fd limit[2]: 16720 (includes 12 bytes per fd) - Per-connection [3]: 72 bytes, +1328 during headers - - .text .rodata .data .bss - 11512 2784 288 4 -``` -This shows the impact of the major configuration with/without options at -13ba5bbc633ea962d46d using Ubuntu ARM on a PandaBoard ES. - -These are accounting for static allocations from the library elf, there are -additional dynamic allocations via malloc. These are a bit old now but give -the right idea for relative "expense" of features. - -Static allocations, ARM9 - -| | .text | .rodata | .data | .bss | -|--------------------------------|---------|---------|-------|------| -| All (no without) | 35024 | 9940 | 336 | 4104 | -| without client | 25684 | 7144 | 336 | 4104 | -| without client, exts | 21652 | 6288 | 288 | 4104 | -| without client, exts, debug[1] | 19756 | 3768 | 288 | 4104 | -| without server | 30304 | 8160 | 336 | 4104 | -| without server, exts | 25382 | 7204 | 288 | 4104 | -| without server, exts, debug[1] | 23712 | 4256 | 288 | 4104 | - -[1] `--disable-debug` only removes messages below `lwsl_notice`. Since that is -the default logging level the impact is not noticeable, error, warn and notice -logs are all still there. - -[2] `1024` fd per process is the default limit (set by ulimit) in at least Fedora -and Ubuntu. You can make significant savings tailoring this to actual expected -peak fds, ie, at a limit of `20`, context creation allocation reduces to `4432 + -240 = 4672`) - -[3] known header content is freed after connection establishment diff --git a/README.coding.md b/README.coding.md deleted file mode 100644 index 03dc6bf..0000000 --- a/README.coding.md +++ /dev/null @@ -1,1022 +0,0 @@ -Notes about coding with lws -=========================== - -@section era Old lws and lws v2.0 - -Originally lws only supported the "manual" method of handling everything in the -user callback found in test-server.c. - -Since v2.0, the need for most or all of this manual boilerplate has been eliminated: -the protocols[0] http stuff is provided by a lib export `lws_callback_http_dummy()`. -You can serve parts of your filesystem at part of the URL space using mounts. - -It's much preferred to use the "automated" v2.0 type scheme, because it's less -code and it's easier to support. - -You can see an example of the new way in test-server-v2.0.c. - -If you just need generic serving capability, consider not writing any server code -and instead use lwsws and writing your user code in a standalone plugin. The -server is configured for mounts etc using JSON, see README.lwsws.md. - -@section dae Daemonization - -There's a helper api `lws_daemonize` built by default that does everything you -need to daemonize well, including creating a lock file. If you're making -what's basically a daemon, just call this early in your init to fork to a -headless background process and exit the starting process. - -Notice stdout, stderr, stdin are all redirected to /dev/null to enforce your -daemon is headless, so you'll need to sort out alternative logging, by, eg, -syslog. - - -@section conns Maximum number of connections - -The maximum number of connections the library can deal with is decided when -it starts by querying the OS to find out how many file descriptors it is -allowed to open (1024 on Fedora for example). It then allocates arrays that -allow up to that many connections, minus whatever other file descriptors are -in use by the user code. - -If you want to restrict that allocation, or increase it, you can use ulimit or -similar to change the available number of file descriptors, and when restarted -**libwebsockets** will adapt accordingly. - -@section peer_limits optional LWS_WITH_PEER_LIMITS - -If you select `LWS_WITH_PEER_LIMITS` at cmake, then lws will track peer IPs -and monitor how many connections and ah resources they are trying to use -at one time. You can choose to limit these at context creation time, using -`info.ip_limit_ah` and `info.ip_limit_wsi`. - -Note that although the ah limit is 'soft', ie, the connection will just wait -until the IP is under the ah limit again before attaching a new ah, the -wsi limit is 'hard', lws will drop any additional connections from the -IP until it's under the limit again. - -If you use these limits, you should consider multiple clients may simultaneously -try to access the site through NAT, etc. So the limits should err on the side -of being generous, while still making it impossible for one IP to exhaust -all the server resources. - -@section evtloop Libwebsockets is singlethreaded - -Libwebsockets works in a serialized event loop, in a single thread. - -Directly performing websocket actions from other threads is not allowed. -Aside from the internal data being inconsistent in `forked()` processes, -the scope of a `wsi` (`struct websocket`) can end at any time during service -with the socket closing and the `wsi` freed. - -Websocket write activities should only take place in the -`LWS_CALLBACK_SERVER_WRITEABLE` callback as described below. - -[This network-programming necessity to link the issue of new data to -the peer taking the previous data is not obvious to all users so let's -repeat that in other words: - -***ONLY DO LWS_WRITE FROM THE WRITEABLE CALLBACK*** - -There is another network-programming truism that surprises some people which -is if the sink for the data cannot accept more: - -***YOU MUST PERFORM RX FLOW CONTROL*** - -See the mirror protocol implementations for example code. - -Only live connections appear in the user callbacks, so this removes any -possibility of trying to used closed and freed wsis. - -If you need to service other socket or file descriptors as well as the -websocket ones, you can combine them together with the websocket ones -in one poll loop, see "External Polling Loop support" below, and -still do it all in one thread / process context. - -If you insist on trying to use it from multiple threads, take special care if -you might simultaneously create more than one context from different threads. - -SSL_library_init() is called from the context create api and it also is not -reentrant. So at least create the contexts sequentially. - - -@section writeable Only send data when socket writeable - -You should only send data on a websocket connection from the user callback -`LWS_CALLBACK_SERVER_WRITEABLE` (or `LWS_CALLBACK_CLIENT_WRITEABLE` for -clients). - -If you want to send something, do not just send it but request a callback -when the socket is writeable using - - - `lws_callback_on_writable(context, wsi)` for a specific `wsi`, or - - - `lws_callback_on_writable_all_protocol(protocol)` for all connections -using that protocol to get a callback when next writeable. - -Usually you will get called back immediately next time around the service -loop, but if your peer is slow or temporarily inactive the callback will be -delayed accordingly. Generating what to write and sending it should be done -in the ...WRITEABLE callback. - -See the test server code for an example of how to do this. - - -@section otherwr Do not rely on only your own WRITEABLE requests appearing - -Libwebsockets may generate additional `LWS_CALLBACK_CLIENT_WRITEABLE` events -if it met network conditions where it had to buffer your send data internally. - -So your code for `LWS_CALLBACK_CLIENT_WRITEABLE` needs to own the decision -about what to send, it can't assume that just because the writeable callback -came it really is time to send something. - -It's quite possible you get an 'extra' writeable callback at any time and -just need to `return 0` and wait for the expected callback later. - - -@section closing Closing connections from the user side - -When you want to close a connection, you do it by returning `-1` from a -callback for that connection. - -You can provoke a callback by calling `lws_callback_on_writable` on -the wsi, then notice in the callback you want to close it and just return -1. -But usually, the decision to close is made in a callback already and returning --1 is simple. - -If the socket knows the connection is dead, because the peer closed or there -was an affirmitive network error like a FIN coming, then **libwebsockets** will -take care of closing the connection automatically. - -If you have a silently dead connection, it's possible to enter a state where -the send pipe on the connection is choked but no ack will ever come, so the -dead connection will never become writeable. To cover that, you can use TCP -keepalives (see later in this document) or pings. - -@section gzip Serving from inside a zip file - -Lws now supports serving gzipped files from inside a zip container. Thanks to -Per Bothner for contributing the code. - -This has the advtantage that if the client can accept GZIP encoding, lws can -simply send the gzip-compressed file from inside the zip file with no further -processing, saving time and bandwidth. - -In the case the client can't understand gzip compression, lws automatically -decompressed the file and sends it normally. - -Clients with limited storage and RAM will find this useful; the memory needed -for the inflate case is constrained so that only one input buffer at a time -is ever in memory. - -To use this feature, ensure LWS_WITH_ZIP_FOPS is enabled at CMake (it is by -default). - -`libwebsockets-test-server-v2.0` includes a mount using this technology -already, run that test server and navigate to http://localhost:7681/ziptest/candide.html - -This will serve the book Candide in html, together with two jpgs, all from -inside a .zip file in /usr/[local/]share-libwebsockets-test-server/candide.zip - -Usage is otherwise automatic, if you arrange a mount that points to the zipfile, -eg, "/ziptest" -> "mypath/test.zip", then URLs like `/ziptest/index.html` will be -servied from `index.html` inside `mypath/test.zip` - -@section frags Fragmented messages - -To support fragmented messages you need to check for the final -frame of a message with `lws_is_final_fragment`. This -check can be combined with `libwebsockets_remaining_packet_payload` -to gather the whole contents of a message, eg: - -``` - case LWS_CALLBACK_RECEIVE: - { - Client * const client = (Client *)user; - const size_t remaining = lws_remaining_packet_payload(wsi); - - if (!remaining && lws_is_final_fragment(wsi)) { - if (client->HasFragments()) { - client->AppendMessageFragment(in, len, 0); - in = (void *)client->GetMessage(); - len = client->GetMessageLength(); - } - - client->ProcessMessage((char *)in, len, wsi); - client->ResetMessage(); - } else - client->AppendMessageFragment(in, len, remaining); - } - break; -``` - -The test app libwebsockets-test-fraggle sources also show how to -deal with fragmented messages. - - -@section debuglog Debug Logging - -Also using `lws_set_log_level` api you may provide a custom callback to actually -emit the log string. By default, this points to an internal emit function -that sends to stderr. Setting it to `NULL` leaves it as it is instead. - -A helper function `lwsl_emit_syslog()` is exported from the library to simplify -logging to syslog. You still need to use `setlogmask`, `openlog` and `closelog` -in your user code. - -The logging apis are made available for user code. - -- `lwsl_err(...)` -- `lwsl_warn(...)` -- `lwsl_notice(...)` -- `lwsl_info(...)` -- `lwsl_debug(...)` - -The difference between notice and info is that notice will be logged by default -whereas info is ignored by default. - -If you are not building with _DEBUG defined, ie, without this - -``` - $ cmake .. -DCMAKE_BUILD_TYPE=DEBUG -``` - -then log levels below notice do not actually get compiled in. - - - -@section extpoll External Polling Loop support - -**libwebsockets** maintains an internal `poll()` array for all of its -sockets, but you can instead integrate the sockets into an -external polling array. That's needed if **libwebsockets** will -cooperate with an existing poll array maintained by another -server. - -Four callbacks `LWS_CALLBACK_ADD_POLL_FD`, `LWS_CALLBACK_DEL_POLL_FD`, -`LWS_CALLBACK_SET_MODE_POLL_FD` and `LWS_CALLBACK_CLEAR_MODE_POLL_FD` -appear in the callback for protocol 0 and allow interface code to -manage socket descriptors in other poll loops. - -You can pass all pollfds that need service to `lws_service_fd()`, even -if the socket or file does not belong to **libwebsockets** it is safe. - -If **libwebsocket** handled it, it zeros the pollfd `revents` field before returning. -So you can let **libwebsockets** try and if `pollfd->revents` is nonzero on return, -you know it needs handling by your code. - -Also note that when integrating a foreign event loop like libev or libuv where -it doesn't natively use poll() semantics, and you must return a fake pollfd -reflecting the real event: - - - be sure you set .events to .revents value as well in the synthesized pollfd - - - check the built-in support for the event loop if possible (eg, ./lib/libuv.c) - to see how it interfaces to lws - - - use LWS_POLLHUP / LWS_POLLIN / LWS_POLLOUT from libwebsockets.h to avoid - losing windows compatibility - -You also need to take care about "forced service" somehow... these are cases -where the network event was consumed, incoming data was all read, for example, -but the work arising from it was not completed. There will not be any more -network event to trigger the remaining work, Eg, we read compressed data, but -we did not use up all the decompressed data before returning to the event loop -because we had to write some of it. - -Lws provides an API to determine if anyone is waiting for forced service, -`lws_service_adjust_timeout(context, 1, tsi)`, normally tsi is 0. If it returns -0, then at least one connection has pending work you can get done by calling -`lws_service_tsi(context, -1, tsi)`, again normally tsi is 0. - -For eg, the default poll() event loop, or libuv/ev/event, lws does this -checking for you and handles it automatically. But in the external polling -loop case, you must do it explicitly. Handling it after every normal service -triggered by the external poll fd should be enough, since the situations needing -it are initially triggered by actual network events. - -An example of handling it is shown in the test-server code specific to -external polling. - -@section cpp Using with in c++ apps - -The library is ready for use by C++ apps. You can get started quickly by -copying the test server - -``` - $ cp test-server/test-server.c test.cpp -``` - -and building it in C++ like this - -``` - $ g++ -DINSTALL_DATADIR=\"/usr/share\" -ocpptest test.cpp -lwebsockets -``` - -`INSTALL_DATADIR` is only needed because the test server uses it as shipped, if -you remove the references to it in your app you don't need to define it on -the g++ line either. - - -@section headerinfo Availability of header information - -HTTP Header information is managed by a pool of "ah" structs. These are a -limited resource so there is pressure to free the headers and return the ah to -the pool for reuse. - -For that reason header information on HTTP connections that get upgraded to -websockets is lost after the ESTABLISHED callback. Anything important that -isn't processed by user code before then should be copied out for later. - -For HTTP connections that don't upgrade, header info remains available the -whole time. - - -@section ka TCP Keepalive - -It is possible for a connection which is not being used to send to die -silently somewhere between the peer and the side not sending. In this case -by default TCP will just not report anything and you will never get any more -incoming data or sign the link is dead until you try to send. - -To deal with getting a notification of that situation, you can choose to -enable TCP keepalives on all **libwebsockets** sockets, when you create the -context. - -To enable keepalive, set the ka_time member of the context creation parameter -struct to a nonzero value (in seconds) at context creation time. You should -also fill ka_probes and ka_interval in that case. - -With keepalive enabled, the TCP layer will send control packets that should -stimulate a response from the peer without affecting link traffic. If the -response is not coming, the socket will announce an error at `poll()` forcing -a close. - -Note that BSDs don't support keepalive time / probes / interval per-socket -like Linux does. On those systems you can enable keepalive by a nonzero -value in `ka_time`, but the systemwide kernel settings for the time / probes/ -interval are used, regardless of what nonzero value is in `ka_time`. - - -@section sslopt Optimizing SSL connections - -There's a member `ssl_cipher_list` in the `lws_context_creation_info` struct -which allows the user code to restrict the possible cipher selection at -context-creation time. - -You might want to look into that to stop the ssl peers selecting a cipher which -is too computationally expensive. To use it, point it to a string like - - `"RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL"` - -if left `NULL`, then the "DEFAULT" set of ciphers are all possible to select. - -You can also set it to `"ALL"` to allow everything (including insecure ciphers). - - -@section sslcerts Passing your own cert information direct to SSL_CTX - -For most users it's enough to pass the SSL certificate and key information by -giving filepaths to the info.ssl_cert_filepath and info.ssl_private_key_filepath -members when creating the vhost. - -If you want to control that from your own code instead, you can do so by leaving -the related info members NULL, and setting the info.options flag -LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX at vhost creation time. That will create -the vhost SSL_CTX without any certificate, and allow you to use the callback -LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS to add your certificate to -the SSL_CTX directly. The vhost SSL_CTX * is in the user parameter in that -callback. - -@section clientasync Async nature of client connections - -When you call `lws_client_connect_info(..)` and get a `wsi` back, it does not -mean your connection is active. It just means it started trying to connect. - -Your client connection is actually active only when you receive -`LWS_CALLBACK_CLIENT_ESTABLISHED` for it. - -There's a 5 second timeout for the connection, and it may give up or die for -other reasons, if any of that happens you'll get a -`LWS_CALLBACK_CLIENT_CONNECTION_ERROR` callback on protocol 0 instead for the -`wsi`. - -After attempting the connection and getting back a non-`NULL` `wsi` you should -loop calling `lws_service()` until one of the above callbacks occurs. - -As usual, see [test-client.c](test-server/test-client.c) for example code. - -Notice that the client connection api tries to progress the connection -somewhat before returning. That means it's possible to get callbacks like -CONNECTION_ERROR on the new connection before your user code had a chance to -get the wsi returned to identify it (in fact if the connection did fail early, -NULL will be returned instead of the wsi anyway). - -To avoid that problem, you can fill in `pwsi` in the client connection info -struct to point to a struct lws that get filled in early by the client -connection api with the related wsi. You can then check for that in the -callback to confirm the identity of the failing client connection. - - -@section fileapi Lws platform-independent file access apis - -lws now exposes his internal platform file abstraction in a way that can be -both used by user code to make it platform-agnostic, and be overridden or -subclassed by user code. This allows things like handling the URI "directory -space" as a virtual filesystem that may or may not be backed by a regular -filesystem. One example use is serving files from inside large compressed -archive storage without having to unpack anything except the file being -requested. - -The test server shows how to use it, basically the platform-specific part of -lws prepares a file operations structure that lives in the lws context. - -The user code can get a pointer to the file operations struct - -``` - LWS_VISIBLE LWS_EXTERN struct lws_plat_file_ops * - `lws_get_fops`(struct lws_context *context); -``` - -and then can use helpers to also leverage these platform-independent -file handling apis - -``` - lws_fop_fd_t - `lws_plat_file_open`(struct lws_plat_file_ops *fops, const char *filename, - lws_fop_flags_t *flags) - int - `lws_plat_file_close`(lws_fop_fd_t fop_fd) - - unsigned long - `lws_plat_file_seek_cur`(lws_fop_fd_t fop_fd, lws_fileofs_t offset) - - int - `lws_plat_file_read`(lws_fop_fd_t fop_fd, lws_filepos_t *amount, - uint8_t *buf, lws_filepos_t len) - - int - `lws_plat_file_write`(lws_fop_fd_t fop_fd, lws_filepos_t *amount, - uint8_t *buf, lws_filepos_t len ) -``` - -Generic helpers are provided which provide access to generic fops information or -call through to the above fops - -``` -lws_filepos_t -lws_vfs_tell(lws_fop_fd_t fop_fd); - -lws_filepos_t -lws_vfs_get_length(lws_fop_fd_t fop_fd); - -uint32_t -lws_vfs_get_mod_time(lws_fop_fd_t fop_fd); - -lws_fileofs_t -lws_vfs_file_seek_set(lws_fop_fd_t fop_fd, lws_fileofs_t offset); - -lws_fileofs_t -lws_vfs_file_seek_end(lws_fop_fd_t fop_fd, lws_fileofs_t offset); -``` - - -The user code can also override or subclass the file operations, to either -wrap or replace them. An example is shown in test server. - -### Changes from v2.1 and before fops - -There are several changes: - -1) Pre-2.2 fops directly used platform file descriptors. Current fops returns and accepts a wrapper type lws_fop_fd_t which is a pointer to a malloc'd struct containing information specific to the filesystem implementation. - -2) Pre-2.2 fops bound the fops to a wsi. This is completely removed, you just give a pointer to the fops struct that applies to this file when you open it. Afterwards, the operations in the fops just need the lws_fop_fd_t returned from the open. - -3) Everything is wrapped in typedefs. See lws-plat-unix.c for examples of how to implement. - -4) Position in the file, File Length, and a copy of Flags left after open are now generically held in the fop_fd. -VFS implementation must set and manage this generic information now. See the implementations in lws-plat-unix.c for -examples. - -5) The file length is no longer set at a pointer provided by the open() fop. The api `lws_vfs_get_length()` is provided to -get the file length after open. - -6) If your file namespace is virtual, ie, is not reachable by platform fops directly, you must set LWS_FOP_FLAG_VIRTUAL -on the flags during open. - -7) There is an optional `mod_time` uint32_t member in the generic fop_fd. If you are able to set it during open, you -should indicate it by setting `LWS_FOP_FLAG_MOD_TIME_VALID` on the flags. - -@section rawfd RAW file descriptor polling - -LWS allows you to include generic platform file descriptors in the lws service / poll / event loop. - -Open your fd normally and then - -``` - lws_sock_file_fd_type u; - - u.filefd = your_open_file_fd; - - if (!lws_adopt_descriptor_vhost(vhost, 0, u, - "protocol-name-to-bind-to", - optional_wsi_parent_or_NULL)) { - // failed - } - - // OK -``` - -A wsi is created for the file fd that acts like other wsi, you will get these -callbacks on the named protocol - -``` - LWS_CALLBACK_RAW_ADOPT_FILE - LWS_CALLBACK_RAW_RX_FILE - LWS_CALLBACK_RAW_WRITEABLE_FILE - LWS_CALLBACK_RAW_CLOSE_FILE -``` - -starting with LWS_CALLBACK_RAW_ADOPT_FILE. - -`protocol-lws-raw-test` plugin provides a method for testing this with -`libwebsockets-test-server-v2.0`: - -The plugin creates a FIFO on your system called "/tmp/lws-test-raw" - -You can feed it data through the FIFO like this - -``` - $ sudo sh -c "echo hello > /tmp/lws-test-raw" -``` - -This plugin simply prints the data. But it does it through the lws event -loop / service poll. - -@section rawsrvsocket RAW server socket descriptor polling - -You can also enable your vhost to accept RAW socket connections, in addition to -HTTP[s] and WS[s]. If the first bytes written on the connection are not a -valid HTTP method, then the connection switches to RAW mode. - -This is disabled by default, you enable it by setting the `.options` flag -LWS_SERVER_OPTION_FALLBACK_TO_RAW when creating the vhost. - -RAW mode socket connections receive the following callbacks - -``` - LWS_CALLBACK_RAW_ADOPT - LWS_CALLBACK_RAW_RX - LWS_CALLBACK_RAW_WRITEABLE - LWS_CALLBACK_RAW_CLOSE -``` - -You can control which protocol on your vhost handles these RAW mode -incoming connections by marking the selected protocol with a pvo `raw`, eg - -``` - "protocol-lws-raw-test": { - "status": "ok", - "raw": "1" - }, -``` - -The "raw" pvo marks this protocol as being used for RAW connections. - -`protocol-lws-raw-test` plugin provides a method for testing this with -`libwebsockets-test-server-v2.0`: - -Run libwebsockets-test-server-v2.0 and connect to it by telnet, eg - -``` - $ telnet 127.0.0.1 7681 -``` - -type something that isn't a valid HTTP method and enter, before the -connection times out. The connection will switch to RAW mode using this -protocol, and pass the unused rx as a raw RX callback. - -The test protocol echos back what was typed on telnet to telnet. - -@section rawclientsocket RAW client socket descriptor polling - -You can now also open RAW socket connections in client mode. - -Follow the usual method for creating a client connection, but set the -`info.method` to "RAW". When the connection is made, the wsi will be -converted to RAW mode and operate using the same callbacks as the -server RAW sockets described above. - -The libwebsockets-test-client supports this using raw:// URLS. To -test, open a netcat listener in one window - -``` - $ nc -l 9999 -``` - -and in another window, connect to it using the test client - -``` - $ libwebsockets-test-client raw://127.0.0.1:9999 -``` - -The connection should succeed, and text typed in the netcat window (including a CRLF) -will be received in the client. - -@section ecdh ECDH Support - -ECDH Certs are now supported. Enable the CMake option - - cmake .. -DLWS_SSL_SERVER_WITH_ECDH_CERT=1 - -**and** the info->options flag - - LWS_SERVER_OPTION_SSL_ECDH - -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 -very simple to use, libwebsockets-test-server-pthread shows how to do it, -use -j argument there to control the number of service threads up to 32. - -Two new members are added to the info struct - - unsigned int count_threads; - unsigned int fd_limit_per_thread; - -leave them at the default 0 to get the normal singlethreaded service loop. - -Set count_threads to n to tell lws you will have n simultaneous service threads -operating on the context. - -There is still a single listen socket on one port, no matter how many -service threads. - -When a connection is made, it is accepted by the service thread with the least -connections active to perform load balancing. - -The user code is responsible for spawning n threads running the service loop -associated to a specific tsi (Thread Service Index, 0 .. n - 1). See -the libwebsockets-test-server-pthread for how to do. - -If you leave fd_limit_per_thread at 0, then the process limit of fds is shared -between the service threads; if you process was allowed 1024 fds overall then -each thread is limited to 1024 / n. - -You can set fd_limit_per_thread to a nonzero number to control this manually, eg -the overall supported fd limit is less than the process allowance. - -You can control the context basic data allocation for multithreading from Cmake -using -DLWS_MAX_SMP=, if not given it's set to 32. The serv_buf allocation -for the threads (currently 4096) is made at runtime only for active threads. - -Because lws will limit the requested number of actual threads supported -according to LWS_MAX_SMP, there is an api lws_get_count_threads(context) to -discover how many threads were actually allowed when the context was created. - -It's required to implement locking in the user code in the same way that -libwebsockets-test-server-pthread does it, for the FD locking callbacks. - -There is no knowledge or dependency in lws itself about pthreads. How the -locking is implemented is entirely up to the user code. - - -@section libevuv Libev / Libuv support - -You can select either or both - - -DLWS_WITH_LIBEV=1 - -DLWS_WITH_LIBUV=1 - -at cmake configure-time. The user application may use one of the -context init options flags - - LWS_SERVER_OPTION_LIBEV - LWS_SERVER_OPTION_LIBUV - -to indicate it will use either of the event libraries. - - -@section extopts Extension option control from user code - -User code may set per-connection extension options now, using a new api -`lws_set_extension_option()`. - -This should be called from the ESTABLISHED callback like this -``` - lws_set_extension_option(wsi, "permessage-deflate", - "rx_buf_size", "12"); /* 1 << 12 */ -``` - -If the extension is not active (missing or not negotiated for the -connection, or extensions are disabled on the library) the call is -just returns -1. Otherwise the connection's extension has its -named option changed. - -The extension may decide to alter or disallow the change, in the -example above permessage-deflate restricts the size of his rx -output buffer also considering the protocol's rx_buf_size member. - - -@section httpsclient Client connections as HTTP[S] rather than WS[S] - -You may open a generic http client connection using the same -struct lws_client_connect_info used to create client ws[s] -connections. - -To stay in http[s], set the optional info member "method" to -point to the string "GET" instead of the default NULL. - -After the server headers are processed, when payload from the -server is available the callback LWS_CALLBACK_RECEIVE_CLIENT_HTTP -will be made. - -You can choose whether to process the data immediately, or -queue a callback when an outgoing socket is writeable to provide -flow control, and process the data in the writable callback. - -Either way you use the api `lws_http_client_read()` to access the -data, eg - -``` - case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: - { - char buffer[1024 + LWS_PRE]; - char *px = buffer + LWS_PRE; - int lenx = sizeof(buffer) - LWS_PRE; - - lwsl_notice("LWS_CALLBACK_RECEIVE_CLIENT_HTTP\n"); - - /* - * Often you need to flow control this by something - * else being writable. In that case call the api - * to get a callback when writable here, and do the - * pending client read in the writeable callback of - * the output. - */ - if (lws_http_client_read(wsi, &px, &lenx) < 0) - return -1; - while (lenx--) - putchar(*px++); - } - break; -``` - -Notice that if you will use SSL client connections on a vhost, you must -prepare the client SSL context for the vhost after creating the vhost, since -this is not normally done if the vhost was set up to listen / serve. Call -the api lws_init_vhost_client_ssl() to also allow client SSL on the vhost. - - - -@section vhosts Using lws vhosts - -If you set LWS_SERVER_OPTION_EXPLICIT_VHOSTS options flag when you create -your context, it won't create a default vhost using the info struct -members for compatibility. Instead you can call lws_create_vhost() -afterwards to attach one or more vhosts manually. - -``` - LWS_VISIBLE struct lws_vhost * - lws_create_vhost(struct lws_context *context, - struct lws_context_creation_info *info); -``` - -lws_create_vhost() uses the same info struct as lws_create_context(), -it ignores members related to context and uses the ones meaningful -for vhost (marked with VH in libwebsockets.h). - -``` - struct lws_context_creation_info { - int port; /* VH */ - const char *iface; /* VH */ - const struct lws_protocols *protocols; /* VH */ - const struct lws_extension *extensions; /* VH */ - ... -``` - -When you attach the vhost, if the vhost's port already has a listen socket -then both vhosts share it and use SNI (is SSL in use) or the Host: header -from the client to select the right one. Or if no other vhost already -listening the a new listen socket is created. - -There are some new members but mainly it's stuff you used to set at -context creation time. - - -@section sni How lws matches hostname or SNI to a vhost - -LWS first strips any trailing :port number. - -Then it tries to find an exact name match for a vhost listening on the correct -port, ie, if SNI or the Host: header provided abc.com:1234, it will match on a -vhost named abc.com that is listening on port 1234. - -If there is no exact match, lws will consider wildcard matches, for example -if cats.abc.com:1234 is provided by the client by SNI or Host: header, it will -accept a vhost "abc.com" listening on port 1234. If there was a better, exact, -match, it will have been chosen in preference to this. - -Connections with SSL will still have the client go on to check the -certificate allows wildcards and error out if not. - - - -@section mounts Using lws mounts on a vhost - -The last argument to lws_create_vhost() lets you associate a linked -list of lws_http_mount structures with that vhost's URL 'namespace', in -a similar way that unix lets you mount filesystems into areas of your / -filesystem how you like and deal with the contents transparently. - -``` - struct lws_http_mount { - struct lws_http_mount *mount_next; - const char *mountpoint; /* mountpoint in http pathspace, eg, "/" */ - const char *origin; /* path to be mounted, eg, "/var/www/warmcat.com" */ - const char *def; /* default target, eg, "index.html" */ - - struct lws_protocol_vhost_options *cgienv; - - int cgi_timeout; - int cache_max_age; - - unsigned int cache_reusable:1; - unsigned int cache_revalidate:1; - unsigned int cache_intermediaries:1; - - unsigned char origin_protocol; - unsigned char mountpoint_len; - }; -``` - -The last mount structure should have a NULL mount_next, otherwise it should -point to the 'next' mount structure in your list. - -Both the mount structures and the strings must persist until the context is -destroyed, since they are not copied but used in place. - -`.origin_protocol` should be one of - -``` - enum { - LWSMPRO_HTTP, - LWSMPRO_HTTPS, - LWSMPRO_FILE, - LWSMPRO_CGI, - LWSMPRO_REDIR_HTTP, - LWSMPRO_REDIR_HTTPS, - LWSMPRO_CALLBACK, - }; -``` - - - LWSMPRO_FILE is used for mapping url namespace to a filesystem directory and -serve it automatically. - - - LWSMPRO_CGI associates the url namespace with the given CGI executable, which -runs when the URL is accessed and the output provided to the client. - - - LWSMPRO_REDIR_HTTP and LWSMPRO_REDIR_HTTPS auto-redirect clients to the given -origin URL. - - - LWSMPRO_CALLBACK causes the http connection to attach to the callback -associated with the named protocol (which may be a plugin). - - -@section mountcallback Operation of LWSMPRO_CALLBACK mounts - -The feature provided by CALLBACK type mounts is binding a part of the URL -namespace to a named protocol callback handler. - -This allows protocol plugins to handle areas of the URL namespace. For example -in test-server-v2.0.c, the URL area "/formtest" is associated with the plugin -providing "protocol-post-demo" like this - -``` - static const struct lws_http_mount mount_post = { - NULL, /* linked-list pointer to next*/ - "/formtest", /* mountpoint in URL namespace on this vhost */ - "protocol-post-demo", /* handler */ - NULL, /* default filename if none given */ - NULL, - 0, - 0, - 0, - 0, - 0, - LWSMPRO_CALLBACK, /* origin points to a callback */ - 9, /* strlen("/formtest"), ie length of the mountpoint */ - }; -``` - -Client access to /formtest[anything] will be passed to the callback registered -with the named protocol, which in this case is provided by a protocol plugin. - -Access by all methods, eg, GET and POST are handled by the callback. - -protocol-post-demo deals with accepting and responding to the html form that -is in the test server HTML. - -When a connection accesses a URL related to a CALLBACK type mount, the -connection protocol is changed until the next access on the connection to a -URL outside the same CALLBACK mount area. User space on the connection is -arranged to be the size of the new protocol user space allocation as given in -the protocol struct. - -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). - -This "binding connection to a protocol" lifecycle in managed by -`LWS_CALLBACK_HTTP_BIND_PROTOCOL` and `LWS_CALLBACK_HTTP_DROP_PROTOCOL`. -Because of HTTP/1.1 connection pipelining, one connection may perform -many transactions, each of which may map to different URLs and need -binding to different protocols. So these messages are used to -create the binding of the wsi to your protocol including any -allocations, and to destroy the binding, at which point you should -destroy any related allocations. - -@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 -is still connected to the server, by greying out the page if not. You can -also add this to your own html easily - - - include lws-common.js from your HEAD section - - - - - dim the page during initialization, in a script section on your page - - lws_gray_out(true,{'zindex':'499'}); - - - in your ws onOpen(), remove the dimming - - lws_gray_out(false); - - - in your ws onClose(), reapply the dimming - - lws_gray_out(true,{'zindex':'499'}); diff --git a/README.esp32.md b/README.esp32.md deleted file mode 100644 index 6f64891..0000000 --- a/README.esp32.md +++ /dev/null @@ -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 - diff --git a/README.esp8266.md b/README.esp8266.md deleted file mode 100644 index ffcf757..0000000 --- a/README.esp8266.md +++ /dev/null @@ -1,34 +0,0 @@ -ESP8266 lws port ----------------- - -lws can now work well on the ESP8266. - -You should get the ESP8266 Espressif SDK-based project here - -https://github.com/lws-team/esplws - -which includes lws as an "app" in the build. The project provides full AP-based setup over the web, and once the device has been configured to associate to a local AP, a separate station vhost with the lws test protocols. - -Instructions for building that are here - -https://github.com/lws-team/esplws/blob/master/README.md - -There are also instructions there for how to remove the test apps from the build and customize your own station content. - - -Information about lws integration on ESP8266 --------------------------------------------- - -The following existing lws features are used to make a nice integration: - - - vhosts: there are separate vhosts for the configuration AP mode and the normal station mode. - - - file_ops: the lws file operations are overridden and handled by a ROMFS parser - - - mounts: mounts are used to serve files automatically from the ROMFS - - - plugins: standalone protocol plugins are included into the build, so there are clean individual implementations for each protocol, while everything is statically linked - - - lws stability and security features like bytewise parsers, sophisticated timeouts, http/1.1 keepalive support - - diff --git a/README.generic-sessions.md b/README.generic-sessions.md deleted file mode 100644 index 376342a..0000000 --- a/README.generic-sessions.md +++ /dev/null @@ -1,373 +0,0 @@ -Notes about generic-sessions Plugin -=================================== - -@section gseb Enabling lwsgs for build - -Enable at CMake with -DLWS_WITH_GENERIC_SESSIONS=1 - -This also needs sqlite3 (libsqlite3-dev or similar package) - - -@section gsi lwsgs Introduction - -The generic-sessions protocol plugin provides cookie-based login -authentication for lws web and ws connections. - -The plugin handles everything about generic account registration, -email verification, lost password, account deletion, and other generic account -management. - -Other code, in another eg, ws protocol handler, only needs very high-level -state information from generic-sessions, ie, which user the client is -authenticated as. Everything underneath is managed in generic-sessions. - - - - random 20-byte session id managed in a cookie - - - all information related to the session held at the server, nothing managed clientside - - - sqlite3 used at the server to manage active sessions and users - - - defaults to creating anonymous sessions with no user associated - - - admin account (with user-selectable username) is defined in config with a SHA-1 of the password; rest of the accounts are in sqlite3 - - - user account passwords stored as salted SHA-1 with additional confounder - only stored in the JSON config, not the database - - - login, logout, register account + email verification built-in with examples - - - in a mount, some file suffixes (ie, .js) can be associated with a protocol for the purposes of rewriting symbolnames. These are read-only copies of logged-in server state. - - - When your page fetches .js or other rewritten files from that mount, "$lwsgs_user" and so on are rewritten on the fly using chunked transfer encoding - - - Eliminates server-side scripting with a few rewritten symbols and - javascript on client side - - - 32-bit bitfield for authentication sectoring, mounts can provide a mask on the loggin-in session's associated server-side bitfield that must be set for access. - - - No code (just config) required for, eg, private URL namespace that requires login to access. - - -@section gsin Lwsgs Integration to HTML - -Only three steps are needed to integrate lwsgs in your HTML. - -1) lwsgs HTML UI is bundled with the javascript it uses in `lwsgs.js`, so -import that script file in your head section - -2) define an empty div of id "lwsgs" somewhere - -3) Call lwsgs_initial() in your page - -That's it. An example is below - -``` - - - - - - - - - - - -
- - -
-
- - - - - - -``` - -@section gsof Lwsgs Overall Flow@ - -When the protocol is initialized, it gets per-vhost information from the config, such -as where the sqlite3 databases are to be stored. The admin username and sha-1 of the -admin password are also taken from here. - -In the mounts using protocol-generic-sessions, a cookie is maintained against any requests; if no cookie was active on the initial request a new session is -created with no attached user. - -So there should always be an active session after any transactions with the server. - -In the example html going to the mount /lwsgs loads a login / register page as the default. - -The
in the login page contains 'next url' hidden inputs that let the html 'program' where the form handler will go after a successful admin login, a successful user login and a failed login. - -After a successful login, the sqlite record at the server for the current session is updated to have the logged-in username associated with it. - - - -@section gsconf Lwsgs Configuration - -"auth-mask" defines the authorization sector bits that must be enabled on the session to gain access. - -"auth-mask" 0 is the default. - - - b0 is set if you are logged in as a user at all. - - b1 is set if you are logged in with the user configured to be admin - - b2 is set if the account has been verified (the account configured for admin is always verified) - - b3 is set if your session just did the forgot password flow successfully - -``` - { - # things in here can always be served - "mountpoint": "/lwsgs", - "origin": "file:///usr/share/libwebsockets-test-server/generic-sessions", - "origin": "callback://protocol-lws-messageboard", - "default": "generic-sessions-login-example.html", - "auth-mask": "0", - "interpret": { - ".js": "protocol-lws-messageboard" - } - }, { - # things in here can only be served if logged in as a user - "mountpoint": "/lwsgs/needauth", - "origin": "file:///usr/share/libwebsockets-test-server/generic-sessions/needauth", - "origin": "callback://protocol-lws-messageboard", - "default": "generic-sessions-login-example.html", - "auth-mask": "5", # logged in as a verified user - "interpret": { - ".js": "protocol-lws-messageboard" - } - }, { - # things in here can only be served if logged in as admin - "mountpoint": "/lwsgs/needadmin", - "origin": "file:///usr/share/libwebsockets-test-server/generic-sessions/needadmin", - "origin": "callback://protocol-lws-messageboard", - "default": "generic-sessions-login-example.html", - "auth-mask": "7", # b2 = verified (by email / or admin), b1 = admin, b0 = logged in with any user name - "interpret": { - ".js": "protocol-lws-messageboard" - } - } -``` -Note that the name of the real application protocol that uses generic-sessions -is used, not generic-sessions itself. - -The vhost configures the storage dir, admin credentials and session cookie lifetimes: - -``` - "ws-protocols": [{ - "protocol-generic-sessions": { - "status": "ok", - "admin-user": "admin", - - # create the pw hash like this (for the example pw, "jipdocesExunt" ) - # $ echo -n "jipdocesExunt" | sha1sum - # 046ce9a9cca769e85798133be06ef30c9c0122c9 - - # - # Obviously ** change this password hash to a secret one before deploying ** - # - "admin-password-sha1": "046ce9a9cca769e85798133be06ef30c9c0122c9", - "session-db": "/var/www/sessions/lws.sqlite3", - "timeout-idle-secs": "600", - "timeout-anon-idle-secs": "1200", - "timeout-absolute-secs": "6000", - # the confounder is part of the salted password hashes. If this config - # file is in a 0700 root:root dir, an attacker with apache credentials - # will have to get the confounder out of the process image to even try - # to guess the password hashes. - "confounder": "Change to <=31 chars of junk", - - "email-from": "noreply@example.com", - "email-smtp-ip": "127.0.0.1", - "email-expire": "3600", - "email-helo": "myhost.com", - "email-contact-person": "Set Me ", - "email-confirm-url-base": "http://localhost:7681/lwsgs" - } -``` - -The email- related settings control generation of automatic emails for -registration and forgotten password. - - - `email-from`: The email address automatic emails are sent from - - - `email-smtp-ip`: Normally 127.0.0.1, if you have a suitable server on port - 25 on your lan you can use this instead here. - - - `email-expire`: Seconds that links sent in email will work before being - deleted - - - `email-helo`: HELO to use when communicating with your SMTP server - - - `email-contact-person`: mentioned in the automatic emails as a human who can - answer questions - - - `email-confirm-url-base`: the URL to start links with in the emails, so the - recipient can get back to the web server - -The real protocol that makes use of generic-sessions must also be listed and -any configuration it needs given - -``` - "protocol-lws-messageboard": { - "status": "ok", - "message-db": "/var/www/sessions/messageboard.sqlite3" - }, -``` - -Notice the real application uses his own sqlite db, no details about how -generic-sessions works or how it stores data are available to it. - - -@section gspwc Lwsgs Password Confounder - -You can also define a per-vhost confounder shown in the example above, used -when aggregating the password with the salt when it is hashed. Any attacker -will also need to get the confounder along with the database, which you can -make harder by making the config dir only eneterable / readable by root. - - -@section gsprep Lwsgs Preparing the db directory - -You will have to prepare the db directory so it's suitable for the lwsws user to use, -that usually means apache, eg - -``` - # mkdir -p /var/www/sessions - # chown root:apache /var/www/sessions - # chmod 770 /var/www/sessions -``` - -@section gsrmail Lwsgs Email configuration - -lwsgs will can send emails by talking to an SMTP server on localhost:25. That -will usually be sendmail or postfix, you should confirm that works first by -itself using the `mail` application to send on it. - -lwsgs has been tested on stock Fedora sendmail and postfix. - - -@section gsap Lwsgs Integration with another protocol - -lwsgs is designed to provide sessions and accounts in a standalone and generic way. - -But it's not useful by itself, there will always be the actual application who wants -to make use of generic-sessions features. - -We provide the "messageboard" plugin as an example of how to integrate with -your actual application protocol. - -The basic approach is the 'real' protocol handler (usually a plugin itself) -subclasses the generic-sessions plugin and calls through to it by default. - -The "real" protocol handler entirely deals with ws-related stuff itself, since -generic-sessions does not use ws. But for - - - LWS_CALLBACK_HTTP - - LWS_CALLBACK_HTTP_BODY - - LWS_CALLBACK_HTTP_BODY_COMPLETION - - LWS_CALLBACK_HTTP_DROP_PROTOCOL - -the "real" protocol handler checks if it recognizes the activity (eg, his own -POST form URL) and if not, passes stuff through to the generic-sessions protocol callback to handle it. To simplify matters the real protocol can just pass -through any unhandled messages to generic-sessions. - -The "real" protocol can get a pointer to generic-sessions protocol on the -same vhost using - -``` - vhd->gsp = lws_vhost_name_to_protocol(vhd->vh, "protocol-generic-sessions"); -``` - -The "real" protocol must also arrange generic-sessions per_session_data in his -own per-session allocation. To allow keeping generic-sessions opaque, the -real protocol must allocate that space at runtime, using the pss size -the generic-sessions protocol struct exposes - -``` - struct per_session_data__myapp { - void *pss_gs; - ... - - pss->pss_gs = malloc(vhd->gsp->per_session_data_size); -``` - -The allocation reserved for generic-sessions is then used as user_space when -the real protocol calls through to the generic-sessions callback - -``` - vhd->gsp->callback(wsi, reason, &pss->pss_gs, in, len); -``` - -In that way the "real" protocol can subclass generic-sessions functionality. - - -To ease management of these secondary allocations, there are callbacks that -occur when a wsi binds to a protocol and when the binding is dropped. These -should be used to malloc and free and kind of per-connection -secondary allocations. - -``` - case LWS_CALLBACK_HTTP_BIND_PROTOCOL: - if (!pss || pss->pss_gs) - break; - - pss->pss_gs = malloc(vhd->gsp->per_session_data_size); - if (!pss->pss_gs) - return -1; - - memset(pss->pss_gs, 0, vhd->gsp->per_session_data_size); - break; - - case LWS_CALLBACK_HTTP_DROP_PROTOCOL: - if (vhd->gsp->callback(wsi, reason, pss ? pss->pss_gs : NULL, in, len)) - return -1; - - if (pss->pss_gs) { - free(pss->pss_gs); - pss->pss_gs = NULL; - } - break; -``` - - -#section gsapsib Getting session-specific information from another protocol - -At least at the time when someone tries to upgrade an http(s) connection to -ws(s) with your real protocol, it is necessary to confirm the cookie the http(s) -connection has with generic-sessions and find out his username and other info. - -Generic sessions lets another protocol check it again by calling his callback, -and lws itself provides a generic session info struct to pass the related data - -``` - struct lws_session_info { - char username[32]; - char email[100]; - char ip[72]; - unsigned int mask; - char session[42]; - }; - - struct lws_session_info sinfo; - ... - vhd->gsp->callback(wsi, LWS_CALLBACK_SESSION_INFO, - &pss->pss_gs, &sinfo, 0); -``` - -After the call to generic-sessions, the results can be - - - all the strings will be zero-length and .mask zero, there is no usable cookie - - - only .ip and .session are set: the cookie is OK but no user logged in - - - all the strings contain information about the logged-in user - -the real protocol can use this to reject attempts to open ws connections from -http connections that are not authenticated; afterwards there's no need to -check the ws connection auth status again. - diff --git a/README.generic-table.md b/README.generic-table.md deleted file mode 100644 index 7a85809..0000000 --- a/README.generic-table.md +++ /dev/null @@ -1,219 +0,0 @@ -Notes about generic-table -========================= - -@section gtint What is generic-table? - -Generic-table is a JSON schema and client-side JS file that makes it easy to -display live, table structured HTML over a ws link. - -An example plugin and index.html using it are provided, but lwsgt itself doesn't -have its own plugin, it's just a JSON schema and client-side JS that other -plugins can use to simplify displaying live, table-based data without having -to reinvent the wheel each time. - -The ws protocol sends JSON describing the table, and then JSON updating the table -contents when it chooses, the brower table is updated automatically, live. - -\image html lwsgt-overview.png - - - Example protocol plugin (displays directory contents): https://github.com/warmcat/libwebsockets/tree/master/plugins/generic-table/protocol_table_dirlisting.c - - - Example HTML: https://github.com/warmcat/libwebsockets/tree/master/plugins/generic-table/assets/index.html - - - lwsgt.js (client-side table rendering / ws link management): https://github.com/warmcat/libwebsockets/tree/master/plugins/generic-table/assets/lwsgt.js - - -@section gteb Enabling for build - -Enable the demo plugin at CMake with -DLWS_WITH_PLUGINS=1 - - -@section gtinth Integrating with your html - - - In your HEAD section, include lwsgt.js - -``` - -``` - - - Also in your HEAD section, style the lwsgt CSS, eg - -``` - -``` - -You can skip this but the result will be less beautiful until some CSS is -provided. - - - In your body section, declare a div with an id (can be whatever you want) - -``` -
-``` - -lwsgt JS will put its content there. - - - Finally in a -``` - -In the callback, you can recover the ws object by `window[gt].lwsgt_ws`. - - -@section gtc Lwsgt constructor - -To instantiate the ws link and lwsgt instance, your HTML must call a lwsgt -constructor for each region on the page managed by lwsgt. - -`var myvar = new lwsgt_initial(title, ws_protocol, div_id, click_cb, myvar);` - -All of the arguments are strings. - -| Parameter | Description | -|-----------------|---------------------------------------------------------| -| title | Title string to go above the table | -| ws_protocol | Protocol name string to use when making ws connection | -| div_id | HTML id of div to fill with content | -| click_cb | Callback function name string to handle clickable links | -| myvar | Name of var used to hold this instantiation globally | - -Note "myvar" is needed so it can be passed to the click handling callback. - - -@section gtclick Lwsgt click handling function - -When a clickable link produced by lwsgt is clicked, the function named in the -click_cb parameter to lwsgt_initial is called. - -That function is expected to take four parameters, eg - -`function lwsgt_dir_click(gt, u, col, row)` - -| Parameter | Description | -|------- ---|-----------------------------------------------------------| -| gt | Name of global var holding this lwsgt context (ie, myvar) | -| u | Link "url" string | -| col | Table column number link is from | -| row | Table row number link is from | - - - -@section gtgj Generic-table JSON - -### Column layout - -When the ws connection is established, the protocol should send a JSON message -describing the table columns. For example - -``` - "cols": [ - { "name": "Date" }, - { "name": "Size", "align": "right" }, - { "name": "Icon" }, - { "name": "Name", "href": "uri"}, - { "name": "uri", "hide": "1" } - ] - } -``` - - - This describes 5 columns - - - Only four columns (not "uri") should be visible - - - "Name" should be presented as a clickable link using "uri" as the - destination, when a "uri" field is presented. - - - "Size" field should be presented aligned to the right - - ### Breadcrumbs - - When a view is hierarchical, it's useful to provide a "path" with links back - in the "path", known as "breadcrumbs". - - Elements before the last one should provide a "url" member as well as the - displayable name, which is used to create the link destination. - - The last element, being the current displayed page should not have a url - member and be displayed without link style. - - - ``` - "breadcrumbs":[{"name":"top", "url": "/" }, {"name":"mydir"}] - ``` - - ### Table data - - The actual file data consists of an array of rows, containing the columns - mentioned in the original "cols" section. - - ``` - "data":[ - { - "Icon":" ", - "Date":"2015-Feb-06 03:08:35 +0000", - "Size":"1406", - "uri":"./serve//favicon.ico", - "Name":"favicon.ico" - } - ] - - ``` - - @section gtdirl Setting up protocol-lws-table-dirlisting - - The example protocol needs two mounts, one to provide the index.html, js and - the protocol itself - - ``` - { - "mountpoint": "/dirtest", - "origin": "file:///usr/share/libwebsockets-test-server/generic-table", - "origin": "callback://protocol-lws-table-dirlisting", - "default": "index.html", - "pmo": [{ - "dir": "/usr/share/libwebsockets-test-server" - }] - }, -``` - -The protocol wants a per-mount option (PMO) to tell it the base directory it -is serving from, named "dir". - -The other mount is there to simply serve items that get clicked on from the -table in a secure way - -``` - { - "mountpoint": "/dirtest/serve", - "origin": "file:///usr/share/libwebsockets-test-server", - "default": "index.html" - }, -``` - -This last bit is not related to using lwsgt itself. diff --git a/README.lws-meta.md b/README.lws-meta.md deleted file mode 100644 index dbca4c0..0000000 --- a/README.lws-meta.md +++ /dev/null @@ -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. diff --git a/README.lwsws.md b/README.lwsws.md deleted file mode 100644 index df0a878..0000000 --- a/README.lwsws.md +++ /dev/null @@ -1,601 +0,0 @@ -Notes about lwsws -================= - -@section lwsws Libwebsockets Web Server - -lwsws is an implementation of a very lightweight, ws-capable generic web -server, which uses libwebsockets to implement everything underneath. - -If you are basically implementing a standalone server with lws, you can avoid -reinventing the wheel and use a debugged server including lws. - - -@section lwswsb Build - -Just enable -DLWS_WITH_LWSWS=1 at cmake-time. - -It enables libuv and plugin support automatically. - -NOTICE on Ubuntu, the default libuv package is called "libuv-0.10". This is ancient. - -You should replace this with libuv1 and libuv1-dev before proceeding. - -@section lwswsc Lwsws Configuration - -lwsws uses JSON config files, they're pure JSON except: - - - '#' may be used to turn the rest of the line into a comment. - - - There's also a single substitution, if a string contains "_lws_ddir_", then that is -replaced with the LWS install data directory path, eg, "/usr/share" or whatever was -set when LWS was built + installed. That lets you refer to installed paths without -having to change the config if your install path was different. - -There is a single file intended for global settings - -/etc/lwsws/conf -``` - # these are the server global settings - # stuff related to vhosts should go in one - # file per vhost in ../conf.d/ - - { - "global": { - "uid": "48", # apache user - "gid": "48", # apache user - "count-threads": "1", - "server-string": "myserver v1", # returned in http headers - "ws-pingpong-secs": "200", # confirm idle established ws connections this often - "init-ssl": "yes" - } - } -``` -and a config directory intended to take one file per vhost - -/etc/lwsws/conf.d/warmcat.com -``` - { - "vhosts": [{ - "name": "warmcat.com", - "port": "443", - "interface": "eth0", # optional - "host-ssl-key": "/etc/pki/tls/private/warmcat.com.key", # if given enable ssl - "host-ssl-cert": "/etc/pki/tls/certs/warmcat.com.crt", - "host-ssl-ca": "/etc/pki/tls/certs/warmcat.com.cer", - "mounts": [{ # autoserve - "mountpoint": "/", - "origin": "file:///var/www/warmcat.com", - "default": "index.html" - }] - }] - } -``` -To get started quickly, an example config reproducing the old test server -on port 7681, non-SSL is provided. To set it up -``` - # mkdir -p /etc/lwsws/conf.d /var/log/lwsws - # cp ./lwsws/etc-lwsws-conf-EXAMPLE /etc/lwsws/conf - # cp ./lwsws/etc-lwsws-conf.d-localhost-EXAMPLE /etc/lwsws/conf.d/test-server - # sudo lwsws -``` - -@section lwsogo Other Global Options - - - `reject-service-keywords` allows you to return an HTTP error code and message of your choice -if a keyword is found in the user agent - -``` - "reject-service-keywords": [{ - "scumbot": "404 Not Found" - }] -``` - - - `timeout-secs` lets you set the global timeout for various network-related - operations in lws, in seconds. It defaults to 5. - -@section lwswsv Lwsws Vhosts - -One server can run many vhosts, where SSL is in use SNI is used to match -the connection to a vhost and its vhost-specific SSL keys during SSL -negotiation. - -Listing multiple vhosts looks something like this -``` - { - "vhosts": [ { - "name": "localhost", - "port": "443", - "host-ssl-key": "/etc/pki/tls/private/libwebsockets.org.key", - "host-ssl-cert": "/etc/pki/tls/certs/libwebsockets.org.crt", - "host-ssl-ca": "/etc/pki/tls/certs/libwebsockets.org.cer", - "mounts": [{ - "mountpoint": "/", - "origin": "file:///var/www/libwebsockets.org", - "default": "index.html" - }, { - "mountpoint": "/testserver", - "origin": "file:///usr/local/share/libwebsockets-test-server", - "default": "test.html" - }], - # which protocols are enabled for this vhost, and optional - # vhost-specific config options for the protocol - # - "ws-protocols": [{ - "warmcat,timezoom": { - "status": "ok" - } - }] - }, - { - "name": "localhost", - "port": "7681", - "host-ssl-key": "/etc/pki/tls/private/libwebsockets.org.key", - "host-ssl-cert": "/etc/pki/tls/certs/libwebsockets.org.crt", - "host-ssl-ca": "/etc/pki/tls/certs/libwebsockets.org.cer", - "mounts": [{ - "mountpoint": "/", - "origin": ">https://localhost" - }] - }, - { - "name": "localhost", - "port": "80", - "mounts": [{ - "mountpoint": "/", - "origin": ">https://localhost" - }] - } - - ] - } -``` - -That sets up three vhosts all called "localhost" on ports 443 and 7681 with SSL, and port 80 without SSL but with a forced redirect to https://localhost - - -@section lwswsvn Lwsws Vhost name and port sharing - -The vhost name field is used to match on incoming SNI or Host: header, so it -must always be the host name used to reach the vhost externally. - - - Vhosts may have the same name and different ports, these will each create a -listening socket on the appropriate port. - - - Vhosts may also have the same port and different name: these will be treated as -true vhosts on one listening socket and the active vhost decided at SSL -negotiation time (via SNI) or if no SSL, then after the Host: header from -the client has been parsed. - - -@section lwswspr Lwsws Protocols - -Vhosts by default have available the union of any initial protocols from context creation time, and -any protocols exposed by plugins. - -Vhosts can select which plugins they want to offer and give them per-vhost settings using this syntax -``` - "ws-protocols": [{ - "warmcat-timezoom": { - "status": "ok" - } - }] -``` - -The "x":"y" parameters like "status":"ok" are made available to the protocol during its per-vhost -LWS_CALLBACK_PROTOCOL_INIT (@in is a pointer to a linked list of struct lws_protocol_vhost_options -containing the name and value pointers). - -To indicate that a protocol should be used when no Protocol: header is sent -by the client, you can use "default": "1" -``` - "ws-protocols": [{ - "warmcat-timezoom": { - "status": "ok", - "default": "1" - } - }] -``` - - -@section lwswsovo Lwsws Other vhost options - - - If the three options `host-ssl-cert`, `host-ssl-ca` and `host-ssl-key` are given, then the vhost supports SSL. - - Each vhost may have its own certs, SNI is used during the initial connection negotiation to figure out which certs to use by the server name it's asking for from the request DNS name. - - - `keeplive-timeout` (in secs) defaults to 60 for lwsws, it may be set as a vhost option - - - `interface` lets you specify which network interface to listen on, if not given listens on all - - - "`unix-socket`": "1" causes the unix socket specified in the interface option to be used instead of an INET socket - - - "`sts`": "1" causes lwsws to send a Strict Transport Security header with responses that informs the client he should never accept to connect to this address using http. This is needed to get the A+ security rating from SSL Labs for your server. - - - "`access-log`": "filepath" sets where apache-compatible access logs will be written - - - `"enable-client-ssl"`: `"1"` enables the vhost's client SSL context, you will need this if you plan to create client conections on the vhost that will use SSL. You don't need it if you only want http / ws client connections. - - - "`ciphers`": "" sets the allowed list of ciphers and key exchange protocols for the vhost. The default list is restricted to only those providing PFS (Perfect Forward Secrecy) on the author's Fedora system. - - If you need to allow weaker ciphers,you can provide an alternative list here per-vhost. - - - "`ecdh-curve`": "" The default ecdh curve is "prime256v1", but you can override it here, per-vhost - - - "`noipv6`": "on" Disable ipv6 completely for this vhost - - - "`ipv6only`": "on" Only allow ipv6 on this vhost / "off" only allow ipv4 on this vhost - - - "`ssl-option-set`": "" Sets the SSL option flag value for the vhost. - It may be used multiple times and OR's the flags together. - - The values are derived from /usr/include/openssl/ssl.h -``` - # define SSL_OP_NO_TLSv1_1 0x10000000L -``` - - would equate to - -``` - "`ssl-option-set`": "268435456" - ``` - - "`ssl-option-clear'": "" Clears the SSL option flag value for the vhost. - It may be used multiple times and OR's the flags together. - - - "`headers':: [{ "header1": "h1value", "header2": "h2value" }] - -allows you to set arbitrary headers on every file served by the vhost - -recommended vhost headers for good client security are - -``` - "headers": [{ - "Content-Security-Policy": "script-src 'self'", - "X-Content-Type-Options": "nosniff", - "X-XSS-Protection": "1; mode=block", - "X-Frame-Options": "SAMEORIGIN" - }] - -``` - -@section lwswsm Lwsws Mounts - -Where mounts are given in the vhost definition, then directory contents may -be auto-served if it matches the mountpoint. - -Mount protocols are used to control what kind of translation happens - - - file:// serve the uri using the remainder of the url past the mountpoint based on the origin directory. - - Eg, with this mountpoint -``` - { - "mountpoint": "/", - "origin": "file:///var/www/mysite.com", - "default": "/" - } -``` - The uri /file.jpg would serve /var/www/mysite.com/file.jpg, since / matched. - - - ^http:// or ^https:// these cause any url matching the mountpoint to issue a redirect to the origin url - - - cgi:// this causes any matching url to be given to the named cgi, eg -``` - { - "mountpoint": "/git", - "origin": "cgi:///var/www/cgi-bin/cgit", - "default": "/" - }, { - "mountpoint": "/cgit-data", - "origin": "file:///usr/share/cgit", - "default": "/" - }, -``` - 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 - -1) Some protocols may want "per-mount options" in name:value format. You can -provide them using "pmo" - - { - "mountpoint": "/stuff", - "origin": "callback://myprotocol", - "pmo": [{ - "myname": "myvalue" - }] - } - -2) When using a cgi:// protcol origin at a mountpoint, you may also give cgi environment variables specific to the mountpoint like this -``` - { - "mountpoint": "/git", - "origin": "cgi:///var/www/cgi-bin/cgit", - "default": "/", - "cgi-env": [{ - "CGIT_CONFIG": "/etc/cgitrc/libwebsockets.org" - }] - } -``` - This allows you to customize one cgi depending on the mountpoint (and / or vhost). - -3) It's also possible to set the cgi timeout (in secs) per cgi:// mount, like this -``` - "cgi-timeout": "30" -``` -4) `callback://` protocol may be used when defining a mount to associate a -named protocol callback with the URL namespace area. For example -``` - { - "mountpoint": "/formtest", - "origin": "callback://protocol-post-demo" - } -``` -All handling of client access to /formtest[anything] will be passed to the -callback registered to the protocol "protocol-post-demo". - -This is useful for handling POST http body content or general non-cgi http -payload generation inside a plugin. - -See the related notes in README.coding.md - -5) Cache policy of the files in the mount can also be set. If no -options are given, the content is marked uncacheable. -``` - { - "mountpoint": "/", - "origin": "file:///var/www/mysite.com", - "cache-max-age": "60", # seconds - "cache-reuse": "1", # allow reuse at client at all - "cache-revalidate": "1", # check it with server each time - "cache-intermediaries": "1" # allow intermediary caches to hold - } -``` - -6) You can also define a list of additional mimetypes per-mount -``` - "extra-mimetypes": { - ".zip": "application/zip", - ".doc": "text/evil" - } -``` - -Normally a file suffix MUST match one of the canned mimetypes or one of the extra -mimetypes, or the file is not served. This adds a little bit of security because -even if there is a bug somewhere and the mount dirs are circumvented, lws will not -serve, eg, /etc/passwd. - -If you provide an extra mimetype entry - - "*": "" - -Then any file is served, if the mimetype was not known then it is served without a -Content-Type: header. - -7) A mount can be protected by HTTP Basic Auth. This only makes sense when using -https, since otherwise the password can be sniffed. - -You can add a `basic-auth` entry on a mount like this - -``` -{ - "mountpoint": "/basic-auth", - "origin": "file://_lws_ddir_/libwebsockets-test-server/private", - "basic-auth": "/var/www/balogins-private" -} -``` - -Before serving anything, lws will signal to the browser that a username / password -combination is required, and it will pop up a dialog. When the user has filled it -in, lwsws checks the user:password string against the text file named in the `basic-auth` -entry. - -The file should contain user:pass one per line - -``` -testuser:testpass -myuser:hispass -``` - -The file should be readable by lwsws, and for a little bit of extra security not -have a file suffix, so lws would reject to serve it even if it could find it on -a mount. - - -@section lwswspl Lwsws Plugins - -Protcols and extensions may also be provided from "plugins", these are -lightweight dynamic libraries. They are scanned for at init time, and -any protocols and extensions found are added to the list given at context -creation time. - -Protocols receive init (LWS_CALLBACK_PROTOCOL_INIT) and destruction -(LWS_CALLBACK_PROTOCOL_DESTROY) callbacks per-vhost, and there are arrangements -they can make per-vhost allocations and get hold of the correct pointer from -the wsi at the callback. - -This allows a protocol to choose to strictly segregate data on a per-vhost -basis, and also allows the plugin to handle its own initialization and -context storage. - -To help that happen conveniently, there are some new apis - - - lws_vhost_get(wsi) - - lws_protocol_get(wsi) - - lws_callback_on_writable_all_protocol_vhost(vhost, protocol) - - lws_protocol_vh_priv_zalloc(vhost, protocol, size) - - lws_protocol_vh_priv_get(vhost, protocol) - -dumb increment, mirror and status protocol plugins are provided as examples. - - -@section lwswsplaplp Additional plugin search paths - -Packages that have their own lws plugins can install them in their own -preferred dir and ask lwsws to scan there by using a config fragment -like this, in its own conf.d/ file managed by the other package -``` - { - "global": { - "plugin-dir": "/usr/local/share/coherent-timeline/plugins" - } - } -``` - -@section lwswsssp lws-server-status plugin - -One provided protocol can be used to monitor the server status. - -Enable the protocol like this on a vhost's ws-protocols section -``` - "lws-server-status": { - "status": "ok", - "update-ms": "5000" - } -``` -`"update-ms"` is used to control how often updated JSON is sent on a ws link. - -And map the provided HTML into the vhost in the mounts section -``` - { - "mountpoint": "/server-status", - "origin": "file:///usr/local/share/libwebsockets-test-server/server-status", - "default": "server-status.html" - } -``` -You might choose to put it on its own vhost which has "interface": "lo", so it's not -externally visible, or use the Basic Auth support to require authentication to -access it. - -`"hide-vhosts": "{0 | 1}"` lets you control if information about your vhosts is included. -Since this includes mounts, you might not want to leak that information, mount names, -etc. - -`"filespath":"{path}"` lets you give a server filepath which is read and sent to the browser -on each refresh. For example, you can provide server temperature information on most -Linux systems by giving an appropriate path down /sys. - -This may be given multiple times. - - -@section lwswsreload Lwsws Configuration Reload - -You may send lwsws a `HUP` signal, by, eg - -``` -$ sudo killall -HUP lwsws -``` - -This causes lwsws to "deprecate" the existing lwsws process, and remove and close all of -its listen sockets, but otherwise allowing it to continue to run, until all -of its open connections close. - -When a deprecated lwsws process has no open connections left, it is destroyed -automatically. - -After sending the SIGHUP to the main lwsws process, a new lwsws process, which can -pick up the newly-available listen sockets, and use the current configuration -files, is automatically started. - -The new configuration may differ from the original one in arbitrary ways, the new -context is created from scratch each time without reference to the original one. - -Notes - -1) Protocols that provide a "shared world" like mirror will have as many "worlds" -as there are lwsws processes still active. People connected to a deprecated lwsws -process remain connected to the existing peers. - -But any new connections will apply to the new lwsws process, which does not share -per-vhost "shared world" data with the deprecated process. That means no new -connections on the deprecated context, ie a "shrinking world" for those guys, and a -"growing world" for people who connect after the SIGHUP. - -2) The new lwsws process owes nothing to the previous one. It starts with fresh -plugins, fresh configuration, fresh root privileges if that how you start it. - -The plugins may have been updated in arbitrary ways including struct size changes -etc, and lwsws or lws may also have been updated arbitrarily. - -3) A root parent process is left up that is not able to do anything except -respond to SIGHUP or SIGTERM. Actual serving and network listening etc happens -in child processes which use the privileges set in the lwsws config files. - -@section lwswssysd Lwsws Integration with Systemd - -lwsws needs a service file like this as `/usr/lib/systemd/system/lwsws.service` -``` -[Unit] -Description=Libwebsockets Web Server -After=syslog.target - -[Service] -ExecStart=/usr/local/bin/lwsws -ExecReload=/usr/bin/killall -s SIGHUP lwsws ; sleep 1 ; /usr/local/bin/lwsws -StandardError=null - -[Install] -WantedBy=multi-user.target -``` - -You can find this prepared in `./lwsws/usr-lib-systemd-system-lwsws.service` - - -@section lwswslr Lwsws Integration with logrotate - -For correct operation with logrotate, `/etc/logrotate.d/lwsws` (if that's -where we're putting the logs) should contain -``` - /var/log/lwsws/*log { - copytruncate - missingok - notifempty - delaycompress - } -``` -You can find this prepared in `/lwsws/etc-logrotate.d-lwsws` - -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= 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. - - diff --git a/README.md b/README.md index 107ae48..f102b53 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ libwebsockets News ---- +Please note the additional READMEs have moved to ./READMEs/ + 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 diff --git a/README.problems.md b/README.problems.md deleted file mode 100644 index dfd572a..0000000 --- a/README.problems.md +++ /dev/null @@ -1,43 +0,0 @@ -Debugging problems -================== - -Library is a component ----------------------- - -As a library, lws is always just a component in a bigger application. - -When users have a problem involving lws, what is happening in the bigger -application is usually critical to understand what is going on (and where the -solution lies). - -Many users are able to share their sources, but others decide not to, for -presumed "commercial advantage" or whatever. (In any event, it can be painful -looking through large chunks of someone else's sources for problems when that -is not the library author's responsibility.) - -This makes answering questions like "what is wrong with my code I am not -going to show you?" or even "what is wrong with my code?" very difficult. - -Even if it's clear there is a problem somewhere, it cannot be understood or -reproduced by anyone else if it needs user code that isn't provided. - -The biggest question is, "is this an lws problem actually"? - - -Use the test apps as sanity checks ----------------------------------- - -The test server and client are extremely useful for sanity checks and debugging -guidance. - - - test apps work on your platform, then either - - your user code is broken, align it to how the test apps work, or, - - something from your code is required to show an lws problem, provide a - minimal patch on a test app so it can be reproduced - - - test apps break on your platform, but work on, eg, x86_64, either - - toolchain or platform-specific (eg, OS) issue, or - - lws platform support issue - - - test apps break everywhere - - sounds like lws problem, info to reproduce and / or a patch is appreciated diff --git a/README.test-apps.md b/README.test-apps.md deleted file mode 100644 index 06854e0..0000000 --- a/README.test-apps.md +++ /dev/null @@ -1,390 +0,0 @@ -Overview of lws test apps -========================= - -Are you building a client? You just need to look at the test client -[libwebsockets-test-client](test-server/test-client.c). - -If you are building a standalone server, there are three choices, in order of -preferability. - -1) lwsws + protocol plugins - -Lws provides a generic web server app that can be configured with JSON -config files. https://libwebsockets.org itself uses this method. - -With lwsws handling the serving part, you only need to write an lws protocol -plugin. See [plugin-standalone](plugin-standalone) for an example of how -to do that outside lws itself, using lws public apis. - - $ cmake .. -DLWS_WITH_LWSWS=1 - -See [README.lwsws.md](README.lwsws.md) for information on how to configure -lwsws. - -NOTE this method implies libuv is used by lws, to provide crossplatform -implementations of timers, dynamic lib loading etc for plugins and lwsws. - -2) test-server-v2.0.c - -This method lets you configure web serving in code, instead of using lwsws. - -Plugins are still used, which implies libuv needed. - - $ cmake .. -DLWS_WITH_PLUGINS=1 - -See [test-server-v2.0.c](test-server/test-server-v2.0.c) - -3) protocols in the server app - -This is the original way lws implemented servers, plugins and libuv are not -required, but without plugins separating the protocol code directly, the -combined code is all squidged together and is much less maintainable. - -This method is still supported in lws but all ongoing and future work is -being done in protocol plugins only. - - -Notes about lws test apps -========================= - -@section tsb Testing server with a browser - -If you run [libwebsockets-test-server](test-server/test-server.c) and point your browser -(eg, Chrome) to - - http://127.0.0.1:7681 - -It will fetch a script in the form of `test.html`, and then run the -script in there on the browser to open a websocket connection. -Incrementing numbers should appear in the browser display. - -By default the test server logs to both stderr and syslog, you can control -what is logged using `-d `, see later. - - -@section tsd Running test server as a Daemon - -You can use the -D option on the test server to have it fork into the -background and return immediately. In this daemonized mode all stderr is -disabled and logging goes only to syslog, eg, `/var/log/messages` or similar. - -The server maintains a lockfile at `/tmp/.lwsts-lock` that contains the pid -of the master process, and deletes this file when the master process -terminates. - -To stop the daemon, do -``` - $ kill cat /tmp/.lwsts-lock -``` -If it finds a stale lock (the pid mentioned in the file does not exist -any more) it will delete the lock and create a new one during startup. - -If the lock is valid, the daemon will exit with a note on stderr that -it was already running. - - -@section sssl Using SSL on the server side - -To test it using SSL/WSS, just run the test server with -``` - $ libwebsockets-test-server --ssl -``` -and use the URL -``` - https://127.0.0.1:7681 -``` -The connection will be entirely encrypted using some generated -certificates that your browser will not accept, since they are -not signed by any real Certificate Authority. Just accept the -certificates in the browser and the connection will proceed -in first https and then websocket wss, acting exactly the -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 - -If you run the test server as described above, you can also -connect to it using the test client as well as a browser. - -``` - $ libwebsockets-test-client localhost -``` - -will by default connect to the test server on localhost:7681 -and print the dumb increment number from the server at the -same time as drawing random circles in the mirror protocol; -if you connect to the test server using a browser at the -same time you will be able to see the circles being drawn. - -The test client supports SSL too, use - -``` - $ libwebsockets-test-client localhost --ssl -s -``` - -the -s tells it to accept the default self-signed cert from the server, -otherwise it will strictly fail the connection if there is no CA cert to -validate the server's certificate. - - -@section choosingts Choosing between test server variations - -If you will be doing standalone serving with lws, ideally you should avoid -making your own server at all, and use lwsws with your own protocol plugins. - -The second best option is follow test-server-v2.0.c, which uses a mount to -autoserve a directory, and lws protocol plugins for ws, without needing any -user callback code (other than what's needed in the protocol plugin). - -For those two options libuv is needed to support the protocol plugins, if -that's not possible then the other variations with their own protocol code -should be considered. - - -@section echo Testing simple echo - -You can test against `echo.websockets.org` as a sanity test like -this (the client connects to port `80` by default): - -``` - $ libwebsockets-test-echo --client echo.websocket.org -``` - -This echo test is of limited use though because it doesn't -negotiate any protocol. You can run the same test app as a -local server, by default on localhost:7681 -``` - $ libwebsockets-test-echo -``` -and do the echo test against the local echo server -``` - $ libwebsockets-test-echo --client localhost --port 7681 -``` -If you add the `--ssl` switch to both the client and server, you can also test -with an encrypted link. - - -@section tassl Testing SSL on the client side - -To test SSL/WSS client action, just run the client test with -``` - $ libwebsockets-test-client localhost --ssl -``` -By default the client test applet is set to accept self-signed -certificates used by the test server, this is indicated by the -`use_ssl` var being set to `2`. Set it to `1` to reject any server -certificate that it doesn't have a trusted CA cert for. - - -@section taping Using the websocket ping utility - -libwebsockets-test-ping connects as a client to a remote -websocket server and pings it like the -normal unix ping utility. -``` - $ libwebsockets-test-ping localhost - handshake OK for protocol lws-mirror-protocol - Websocket PING localhost.localdomain (127.0.0.1) 64 bytes of data. - 64 bytes from localhost: req=1 time=0.1ms - 64 bytes from localhost: req=2 time=0.1ms - 64 bytes from localhost: req=3 time=0.1ms - 64 bytes from localhost: req=4 time=0.2ms - 64 bytes from localhost: req=5 time=0.1ms - 64 bytes from localhost: req=6 time=0.2ms - 64 bytes from localhost: req=7 time=0.2ms - 64 bytes from localhost: req=8 time=0.1ms - ^C - --- localhost.localdomain websocket ping statistics --- - 8 packets transmitted, 8 received, 0% packet loss, time 7458ms - rtt min/avg/max = 0.110/0.185/0.218 ms - $ -``` -By default it sends 64 byte payload packets using the 04 -PING packet opcode type. You can change the payload size -using the `-s=` flag, up to a maximum of 125 mandated by the -04 standard. - -Using the lws-mirror protocol that is provided by the test -server, libwebsockets-test-ping can also use larger payload -sizes up to 4096 is BINARY packets; lws-mirror will copy -them back to the client and they appear as a PONG. Use the -`-m` flag to select this operation. - -The default interval between pings is 1s, you can use the -i= -flag to set this, including fractions like `-i=0.01` for 10ms -interval. - -Before you can even use the PING opcode that is part of the -standard, you must complete a handshake with a specified -protocol. By default lws-mirror-protocol is used which is -supported by the test server. But if you are using it on -another server, you can specify the protocol to handshake with -by `--protocol=protocolname` - - -@section ta fraggle Fraggle test app - -By default it runs in server mode -``` - $ libwebsockets-test-fraggle - libwebsockets test fraggle - (C) Copyright 2010-2011 Andy Green licensed under LGPL2.1 - Compiled with SSL support, not using it - Listening on port 7681 - server sees client connect - accepted v06 connection - Spamming 360 random fragments - Spamming session over, len = 371913. sum = 0x2D3C0AE - Spamming 895 random fragments - Spamming session over, len = 875970. sum = 0x6A74DA1 - ... -``` -You need to run a second session in client mode, you have to -give the `-c` switch and the server address at least: -``` - $ libwebsockets-test-fraggle -c localhost - libwebsockets test fraggle - (C) Copyright 2010-2011 Andy Green licensed under LGPL2.1 - Client mode - Connecting to localhost:7681 - denied deflate-stream extension - handshake OK for protocol fraggle-protocol - client connects to server - EOM received 371913 correctly from 360 fragments - EOM received 875970 correctly from 895 fragments - EOM received 247140 correctly from 258 fragments - EOM received 695451 correctly from 692 fragments - ... -``` -The fraggle test sends a random number up to 1024 fragmented websocket frames -each of a random size between 1 and 2001 bytes in a single message, then sends -a checksum and starts sending a new randomly sized and fragmented message. - -The fraggle test client receives the same message fragments and computes the -same checksum using websocket framing to see when the message has ended. It -then accepts the server checksum message and compares that to its checksum. - - -@section taproxy proxy support - -The http_proxy environment variable is respected by the client -connection code for both `ws://` and `wss://`. It doesn't support -authentication. - -You use it like this -``` - $ export http_proxy=myproxy.com:3128 - $ libwebsockets-test-client someserver.com -``` - -@section talog debug logging - -By default logging of severity "notice", "warn" or "err" is enabled to stderr. - -Again by default other logging is compiled in but disabled from printing. - -By default debug logs below "notice" in severity are not compiled in. To get -them included, add this option in CMAKE - -``` - $ cmake .. -DCMAKE_BUILD_TYPE=DEBUG -``` - -If you want to see more detailed debug logs, you can control a bitfield to -select which logs types may print using the `lws_set_log_level()` api, in the -test apps you can use `-d ` to control this. The types of logging -available are (OR together the numbers to select multiple) - - - 1 ERR - - 2 WARN - - 4 NOTICE - - 8 INFO - - 16 DEBUG - - 32 PARSER - - 64 HEADER - - 128 EXTENSION - - 256 CLIENT - - 512 LATENCY - - -@section ws13 Websocket version supported - -The final IETF standard is supported for both client and server, protocol -version 13. - - -@section latency Latency Tracking - -Since libwebsockets runs using `poll()` and a single threaded approach, any -unexpected latency coming from system calls would be bad news. There's now -a latency tracking scheme that can be built in with `--with-latency` at -configure-time, logging the time taken for system calls to complete and if -the whole action did complete that time or was deferred. - -You can see the detailed data by enabling logging level 512 (eg, `-d 519` on -the test server to see that and the usual logs), however even without that -the "worst" latency is kept and reported to the logs with NOTICE severity -when the context is destroyed. - -Some care is needed interpreting them, if the action completed the first figure -(in us) is the time taken for the whole action, which may have retried through -the poll loop many times and will depend on network roundtrip times. High -figures here don't indicate a problem. The figure in us reported after "lat" -in the logging is the time taken by this particular attempt. High figures -here may indicate a problem, or if you system is loaded with another app at -that time, such as the browser, it may simply indicate the OS gave preferential -treatment to the other app during that call. - - -@section autobahn Autobahn Test Suite - -Lws can be tested against the autobahn websocket fuzzer. - -1) pip install autobahntestsuite - -2) wstest -m fuzzingserver - -3) Run tests like this - -libwebsockets-test-echo --client localhost --port 9001 -u "/runCase?case=20&agent=libwebsockets" -v -d 65535 -n 1 - -(this runs test 20) - -4) In a browser, go here - -http://localhost:8080/test_browser.html - -fill in "libwebsockets" in "User Agent Identifier" and press "Update Reports (Manual)" - -5) In a browser go to the directory you ran wstest in (eg, /projects/libwebsockets) - -file:///projects/libwebsockets/reports/clients/index.html - -to see the results - - -@section autobahnnotes Autobahn Test Notes - -1) Autobahn tests the user code + lws implementation. So to get the same -results, you need to follow test-echo.c in terms of user implementation. - -2) Two of the tests make no sense for Libwebsockets to support and we fail them. - - - Tests 2.10 + 2.11: sends multiple pings on one connection. Lws policy is to -only allow one active ping in flight on each connection, the rest are dropped. -The autobahn test itself admits this is not part of the standard, just someone's -random opinion about how they think a ws server should act. So we will fail -this by design and it is no problem about RFC6455 compliance. - - - diff --git a/READMEs/README.build.md b/READMEs/README.build.md new file mode 100644 index 0000000..dd3494a --- /dev/null +++ b/READMEs/README.build.md @@ -0,0 +1,469 @@ +Notes about building lws +======================== + + +@section cm Introduction to CMake + +CMake is a multi-platform build tool that can generate build files for many +different target platforms. See more info at http://www.cmake.org + +CMake also allows/recommends you to do "out of source"-builds, that is, +the build files are separated from your sources, so there is no need to +create elaborate clean scripts to get a clean source tree, instead you +simply remove your build directory. + +Libwebsockets has been tested to build successfully on the following platforms +with SSL support (for OpenSSL/wolfSSL/BoringSSL): + +- Windows (Visual Studio) +- Windows (MinGW) +- Linux (x86 and ARM) +- OSX +- NetBSD + + +@section build1 Building the library and test apps + +The project settings used by CMake to generate the platform specific build +files is called [CMakeLists.txt](CMakeLists.txt). CMake then uses one of its "Generators" to +output a Visual Studio project or Make file for instance. To see a list of +the available generators for your platform, simply run the "cmake" command. + +Note that by default OpenSSL will be linked, if you don't want SSL support +see below on how to toggle compile options. + + +@section bu Building on Unix: + +1. Install CMake 2.8 or greater: http://cmake.org/cmake/resources/software.html + (Most Unix distributions comes with a packaged version also) + +2. Install OpenSSL. + +3. Generate the build files (default is Make files): +``` + $ cd /path/to/src + $ mkdir build + $ cd build + $ cmake .. +``` + +4. Finally you can build using the generated Makefile: +``` + $ make && sudo make install +``` +**NOTE**: The `build/`` directory can have any name and be located anywhere + on your filesystem, and that the argument `..` given to cmake is simply + the source directory of **libwebsockets** containing the [CMakeLists.txt](CMakeLists.txt) + project file. All examples in this file assumes you use ".." + +**NOTE2**: +A common option you may want to give is to set the install path, same +as --prefix= with autotools. It defaults to /usr/local. +You can do this by, eg +``` + $ cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr . +``` + +**NOTE3**: +On machines that want libraries in lib64, you can also add the +following to the cmake line +``` + -DLIB_SUFFIX=64 +``` + +**NOTE4**: +If you are building against a non-distro OpenSSL (eg, in order to get +access to ALPN support only in newer OpenSSL versions) the nice way to +express that in one cmake command is eg, +``` + $ cmake .. -DOPENSSL_ROOT_DIR=/usr/local/ssl \ + -DCMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE=/usr/local/ssl \ + -DLWS_WITH_HTTP2=1 +``` + +When you run the test apps using non-distro SSL, you have to force them +to use your libs, not the distro ones +``` + $ LD_LIBRARY_PATH=/usr/local/ssl/lib libwebsockets-test-server --ssl +``` + +To get it to build on latest openssl (2016-04-10) it needed this approach +``` + cmake .. -DLWS_WITH_HTTP2=1 -DLWS_OPENSSL_INCLUDE_DIRS=/usr/local/include/openssl -DLWS_OPENSSL_LIBRARIES="/usr/local/lib64/libssl.so;/usr/local/lib64/libcrypto.so" +``` + +Mac users have reported + +``` + $ export OPENSSL_ROOT_DIR=/usr/local/Cellar/openssl/1.0.2k; cmake ..; make -j4 +``` + +worked for them when using "homebrew" OpenSSL + +**NOTE5**: +To build with debug info and _DEBUG for lower priority debug messages +compiled in, use +``` + $ cmake .. -DCMAKE_BUILD_TYPE=DEBUG +``` + +**NOTE6** +To build on Solaris the linker needs to be informed to use lib socket +and libnsl, and only builds in 64bit mode. + +```bash + $ cmake .. -DCMAKE_C_FLAGS=-m64 -DCMAKE_EXE_LINKER_FLAGS="-lsocket -lnsl" +``` + +4. Finally you can build using the generated Makefile: + +```bash + $ 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) + +1. Install CMake 2.6 or greater: http://cmake.org/cmake/resources/software.html + +2. Install OpenSSL binaries. http://www.openssl.org/related/binaries.html + + (**NOTE**: Preferably in the default location to make it easier for CMake to find them) + + **NOTE2**: + Be sure that OPENSSL_CONF environment variable is defined and points at + \bin\openssl.cfg + +3. Generate the Visual studio project by opening the Visual Studio cmd prompt: + +``` + cd + md build + cd build + cmake -G "Visual Studio 10" .. +``` + + (**NOTE**: There is also a cmake-gui available on Windows if you prefer that) + + **NOTE2**: + See this link to find out the version number corresponding to your Visual Studio edition: + http://superuser.com/a/194065 + +4. Now you should have a generated Visual Studio Solution in your + `/build` directory, which can be used to build. + +5. Some additional deps may be needed + + - iphlpapi.lib + - psapi.lib + - userenv.lib + +6. If you're using libuv, you must make sure to compile libuv with the same multithread-dll / Mtd attributes as libwebsockets itself + + +@section cmwmgw Building on Windows (MinGW) + +1. Install MinGW: http://sourceforge.net/projects/mingw/files + + (**NOTE**: Preferably in the default location C:\MinGW) + +2. Fix up MinGW headers + + a) If still necessary, sdd the following lines to C:\MinGW\include\winsock2.h: +``` + #if(_WIN32_WINNT >= 0x0600) + + typedef struct pollfd { + + SOCKET fd; + SHORT events; + SHORT revents; + + } WSAPOLLFD, *PWSAPOLLFD, FAR *LPWSAPOLLFD; + + WINSOCK_API_LINKAGE int WSAAPI WSAPoll(LPWSAPOLLFD fdArray, ULONG fds, INT timeout); + + #endif // (_WIN32_WINNT >= 0x0600) +``` + + 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 + +3. Install CMake 2.6 or greater: http://cmake.org/cmake/resources/software.html + +4. Install OpenSSL binaries. http://www.openssl.org/related/binaries.html + + (**NOTE**: Preferably in the default location to make it easier for CMake to find them) + + **NOTE2**: + Be sure that OPENSSL_CONF environment variable is defined and points at + \bin\openssl.cfg + +5. Generate the build files (default is Make files) using MSYS shell: +``` + $ cd /drive/path/to/src + $ mkdir build + $ cd build + $ cmake -G "MSYS Makefiles" -DCMAKE_INSTALL_PREFIX=C:/MinGW .. +``` + (**NOTE**: The `build/`` directory can have any name and be located anywhere + on your filesystem, and that the argument `..` given to cmake is simply + the source directory of **libwebsockets** containing the [CMakeLists.txt](CMakeLists.txt) + project file. All examples in this file assumes you use "..") + + **NOTE2**: + To generate build files allowing to create libwebsockets binaries with debug information + set the CMAKE_BUILD_TYPE flag to DEBUG: +``` + $ cmake -G "MSYS Makefiles" -DCMAKE_INSTALL_PREFIX=C:/MinGW -DCMAKE_BUILD_TYPE=DEBUG .. +``` +6. Finally you can build using the generated Makefile and get the results deployed into your MinGW installation: + +``` + $ make + $ make install +``` + +@section optee Building for OP-TEE + +OP-TEE is a "Secure World" Trusted Execution Environment. + +Although lws is only part of the necessary picture to have an https-enabled +TA, it does support OP-TEE as a platform and if you provide the other +pieces, does work very well. + +Select it in cmake with `-DLWS_PLAT_OPTEE=1` + + +@section cmco Setting compile options + +To set compile time flags you can either use one of the CMake gui applications +or do it via the command line. + +@subsection cmcocl Command line + +To list available options (omit the H if you don't want the help text): + + cmake -LH .. + +Then to set an option and build (for example turn off SSL support): + + cmake -DLWS_WITH_SSL=0 .. +or + cmake -DLWS_WITH_SSL:BOOL=OFF .. + +@subsection cmcoug Unix GUI + +If you have a curses-enabled build you simply type: +(not all packages include this, my debian install does not for example). + + ccmake + +@subsection cmcowg Windows GUI + +On windows CMake comes with a gui application: + Start -> Programs -> CMake -> CMake (cmake-gui) + + +@section wolf wolfSSL/CyaSSL replacement for OpenSSL + +wolfSSL/CyaSSL is a lightweight SSL library targeted at embedded systems: +https://www.wolfssl.com/wolfSSL/Products-wolfssl.html + +It contains a OpenSSL compatibility layer which makes it possible to pretty +much link to it instead of OpenSSL, giving a much smaller footprint. + +**NOTE**: wolfssl needs to be compiled using the `--enable-opensslextra` flag for +this to work. + +@section wolf1 Compiling libwebsockets with wolfSSL + +``` + cmake .. -DLWS_USE_WOLFSSL=1 \ + -DLWS_WOLFSSL_INCLUDE_DIRS=/path/to/wolfssl \ + -DLWS_WOLFSSL_LIBRARIES=/path/to/wolfssl/wolfssl.a .. +``` + +**NOTE**: On windows use the .lib file extension for `LWS_WOLFSSL_LIBRARIES` instead. + +@section cya Compiling libwebsockets with CyaSSL + +``` + cmake .. -DLWS_USE_CYASSL=1 \ + -DLWS_CYASSL_INCLUDE_DIRS=/path/to/cyassl \ + -DLWS_CYASSL_LIBRARIES=/path/to/wolfssl/cyassl.a .. +``` + +**NOTE**: On windows use the .lib file extension for `LWS_CYASSL_LIBRARIES` instead. + +@section esp32 Building for ESP32 + +Step 1, get ESP-IDF with lws integrated as a component + +``` + $ git clone --int --recursive https://github.com/lws-team/lws-esp-idf +``` + +Step 2: Get Application including the test plugins + +``` + $ git clone https://github.com/lws-team/lws-esp32 +``` + +Set your IDF_PATH to point to the esp-idf you downloaded in 1) + +There's docs for how to build the lws-esp32 test app and reproduce it in the README.md here + +https://github.com/lws-team/lws-esp32/blob/master/README.md + + +@section extplugins Building plugins outside of lws itself + +The directory ./plugin-standalone/ shows how easy it is to create plugins +outside of lws itself. First build lws itself with -DLWS_WITH_PLUGINS, +then use the same flow to build the standalone plugin +``` + cd ./plugin-standalone + mkdir build + cd build + cmake .. + make && sudo make install +``` + +if you changed the default plugin directory when you built lws, you must +also give the same arguments to cmake here (eg, +` -DCMAKE_INSTALL_PREFIX:PATH=/usr/something/else...` ) + +Otherwise if you run lwsws or libwebsockets-test-server-v2.0, it will now +find the additional plugin "libprotocol_example_standalone.so" +``` + lwsts[21257]: Plugins: + lwsts[21257]: libprotocol_dumb_increment.so + lwsts[21257]: libprotocol_example_standalone.so + lwsts[21257]: libprotocol_lws_mirror.so + lwsts[21257]: libprotocol_lws_server_status.so + lwsts[21257]: libprotocol_lws_status.so +``` +If you have multiple vhosts, you must enable plugins at the vhost +additionally, discovered plugins are not enabled automatically for security +reasons. You do this using info->pvo or for lwsws, in the JSON config. + + +@section http2rp Reproducing HTTP2.0 tests + +You must have built and be running lws against a version of openssl that has +ALPN / NPN. Most distros still have older versions. You'll know it's right by +seeing +``` + lwsts[4752]: Compiled with OpenSSL support + lwsts[4752]: Using SSL mode + lwsts[4752]: HTTP2 / ALPN enabled +``` +at lws startup. + +For non-SSL HTTP2.0 upgrade +``` + $ nghttp -nvasu http://localhost:7681/test.htm +``` +For SSL / ALPN HTTP2.0 upgrade +``` + $ nghttp -nvas https://localhost:7681/test.html +``` + +@section cross Cross compiling + +To enable cross-compiling **libwebsockets** using CMake you need to create +a "Toolchain file" that you supply to CMake when generating your build files. +CMake will then use the cross compilers and build paths specified in this file +to look for dependencies and such. + +**Libwebsockets** includes an example toolchain file [cross-arm-linux-gnueabihf.cmake](cross-arm-linux-gnueabihf.cmake) +you can use as a starting point. + +The commandline to configure for cross with this would look like +``` + $ cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/usr \ + -DCMAKE_TOOLCHAIN_FILE=../cross-arm-linux-gnueabihf.cmake \ + -DLWS_WITHOUT_EXTENSIONS=1 -DLWS_WITH_SSL=0 +``` +The example shows how to build with no external cross lib dependencies, you +need to provide the cross libraries otherwise. + +**NOTE**: start from an EMPTY build directory if you had a non-cross build in there + before the settings will be cached and your changes ignored. + +Additional information on cross compilation with CMake: + http://www.vtk.org/Wiki/CMake_Cross_Compiling + +@section mem Memory efficiency + +Embedded server-only configuration without extensions (ie, no compression +on websocket connections), but with full v13 websocket features and http +server, built on ARM Cortex-A9: + +Update at 8dac94d (2013-02-18) +``` + $ ./configure --without-client --without-extensions --disable-debug --without-daemonize + + Context Creation, 1024 fd limit[2]: 16720 (includes 12 bytes per fd) + Per-connection [3]: 72 bytes, +1328 during headers + + .text .rodata .data .bss + 11512 2784 288 4 +``` +This shows the impact of the major configuration with/without options at +13ba5bbc633ea962d46d using Ubuntu ARM on a PandaBoard ES. + +These are accounting for static allocations from the library elf, there are +additional dynamic allocations via malloc. These are a bit old now but give +the right idea for relative "expense" of features. + +Static allocations, ARM9 + +| | .text | .rodata | .data | .bss | +|--------------------------------|---------|---------|-------|------| +| All (no without) | 35024 | 9940 | 336 | 4104 | +| without client | 25684 | 7144 | 336 | 4104 | +| without client, exts | 21652 | 6288 | 288 | 4104 | +| without client, exts, debug[1] | 19756 | 3768 | 288 | 4104 | +| without server | 30304 | 8160 | 336 | 4104 | +| without server, exts | 25382 | 7204 | 288 | 4104 | +| without server, exts, debug[1] | 23712 | 4256 | 288 | 4104 | + +[1] `--disable-debug` only removes messages below `lwsl_notice`. Since that is +the default logging level the impact is not noticeable, error, warn and notice +logs are all still there. + +[2] `1024` fd per process is the default limit (set by ulimit) in at least Fedora +and Ubuntu. You can make significant savings tailoring this to actual expected +peak fds, ie, at a limit of `20`, context creation allocation reduces to `4432 + +240 = 4672`) + +[3] known header content is freed after connection establishment diff --git a/READMEs/README.coding.md b/READMEs/README.coding.md new file mode 100644 index 0000000..867b647 --- /dev/null +++ b/READMEs/README.coding.md @@ -0,0 +1,1022 @@ +Notes about coding with lws +=========================== + +@section era Old lws and lws v2.0 + +Originally lws only supported the "manual" method of handling everything in the +user callback found in test-server.c. + +Since v2.0, the need for most or all of this manual boilerplate has been eliminated: +the protocols[0] http stuff is provided by a lib export `lws_callback_http_dummy()`. +You can serve parts of your filesystem at part of the URL space using mounts. + +It's much preferred to use the "automated" v2.0 type scheme, because it's less +code and it's easier to support. + +You can see an example of the new way in test-server-v2.0.c. + +If you just need generic serving capability, consider not writing any server code +and instead use lwsws and writing your user code in a standalone plugin. The +server is configured for mounts etc using JSON, see README.lwsws.md. + +@section dae Daemonization + +There's a helper api `lws_daemonize` built by default that does everything you +need to daemonize well, including creating a lock file. If you're making +what's basically a daemon, just call this early in your init to fork to a +headless background process and exit the starting process. + +Notice stdout, stderr, stdin are all redirected to /dev/null to enforce your +daemon is headless, so you'll need to sort out alternative logging, by, eg, +syslog. + + +@section conns Maximum number of connections + +The maximum number of connections the library can deal with is decided when +it starts by querying the OS to find out how many file descriptors it is +allowed to open (1024 on Fedora for example). It then allocates arrays that +allow up to that many connections, minus whatever other file descriptors are +in use by the user code. + +If you want to restrict that allocation, or increase it, you can use ulimit or +similar to change the available number of file descriptors, and when restarted +**libwebsockets** will adapt accordingly. + +@section peer_limits optional LWS_WITH_PEER_LIMITS + +If you select `LWS_WITH_PEER_LIMITS` at cmake, then lws will track peer IPs +and monitor how many connections and ah resources they are trying to use +at one time. You can choose to limit these at context creation time, using +`info.ip_limit_ah` and `info.ip_limit_wsi`. + +Note that although the ah limit is 'soft', ie, the connection will just wait +until the IP is under the ah limit again before attaching a new ah, the +wsi limit is 'hard', lws will drop any additional connections from the +IP until it's under the limit again. + +If you use these limits, you should consider multiple clients may simultaneously +try to access the site through NAT, etc. So the limits should err on the side +of being generous, while still making it impossible for one IP to exhaust +all the server resources. + +@section evtloop Libwebsockets is singlethreaded + +Libwebsockets works in a serialized event loop, in a single thread. + +Directly performing websocket actions from other threads is not allowed. +Aside from the internal data being inconsistent in `forked()` processes, +the scope of a `wsi` (`struct websocket`) can end at any time during service +with the socket closing and the `wsi` freed. + +Websocket write activities should only take place in the +`LWS_CALLBACK_SERVER_WRITEABLE` callback as described below. + +[This network-programming necessity to link the issue of new data to +the peer taking the previous data is not obvious to all users so let's +repeat that in other words: + +***ONLY DO LWS_WRITE FROM THE WRITEABLE CALLBACK*** + +There is another network-programming truism that surprises some people which +is if the sink for the data cannot accept more: + +***YOU MUST PERFORM RX FLOW CONTROL*** + +See the mirror protocol implementations for example code. + +Only live connections appear in the user callbacks, so this removes any +possibility of trying to used closed and freed wsis. + +If you need to service other socket or file descriptors as well as the +websocket ones, you can combine them together with the websocket ones +in one poll loop, see "External Polling Loop support" below, and +still do it all in one thread / process context. + +If you insist on trying to use it from multiple threads, take special care if +you might simultaneously create more than one context from different threads. + +SSL_library_init() is called from the context create api and it also is not +reentrant. So at least create the contexts sequentially. + + +@section writeable Only send data when socket writeable + +You should only send data on a websocket connection from the user callback +`LWS_CALLBACK_SERVER_WRITEABLE` (or `LWS_CALLBACK_CLIENT_WRITEABLE` for +clients). + +If you want to send something, do not just send it but request a callback +when the socket is writeable using + + - `lws_callback_on_writable(context, wsi)` for a specific `wsi`, or + + - `lws_callback_on_writable_all_protocol(protocol)` for all connections +using that protocol to get a callback when next writeable. + +Usually you will get called back immediately next time around the service +loop, but if your peer is slow or temporarily inactive the callback will be +delayed accordingly. Generating what to write and sending it should be done +in the ...WRITEABLE callback. + +See the test server code for an example of how to do this. + + +@section otherwr Do not rely on only your own WRITEABLE requests appearing + +Libwebsockets may generate additional `LWS_CALLBACK_CLIENT_WRITEABLE` events +if it met network conditions where it had to buffer your send data internally. + +So your code for `LWS_CALLBACK_CLIENT_WRITEABLE` needs to own the decision +about what to send, it can't assume that just because the writeable callback +came it really is time to send something. + +It's quite possible you get an 'extra' writeable callback at any time and +just need to `return 0` and wait for the expected callback later. + + +@section closing Closing connections from the user side + +When you want to close a connection, you do it by returning `-1` from a +callback for that connection. + +You can provoke a callback by calling `lws_callback_on_writable` on +the wsi, then notice in the callback you want to close it and just return -1. +But usually, the decision to close is made in a callback already and returning +-1 is simple. + +If the socket knows the connection is dead, because the peer closed or there +was an affirmitive network error like a FIN coming, then **libwebsockets** will +take care of closing the connection automatically. + +If you have a silently dead connection, it's possible to enter a state where +the send pipe on the connection is choked but no ack will ever come, so the +dead connection will never become writeable. To cover that, you can use TCP +keepalives (see later in this document) or pings. + +@section gzip Serving from inside a zip file + +Lws now supports serving gzipped files from inside a zip container. Thanks to +Per Bothner for contributing the code. + +This has the advtantage that if the client can accept GZIP encoding, lws can +simply send the gzip-compressed file from inside the zip file with no further +processing, saving time and bandwidth. + +In the case the client can't understand gzip compression, lws automatically +decompressed the file and sends it normally. + +Clients with limited storage and RAM will find this useful; the memory needed +for the inflate case is constrained so that only one input buffer at a time +is ever in memory. + +To use this feature, ensure LWS_WITH_ZIP_FOPS is enabled at CMake (it is by +default). + +`libwebsockets-test-server-v2.0` includes a mount using this technology +already, run that test server and navigate to http://localhost:7681/ziptest/candide.html + +This will serve the book Candide in html, together with two jpgs, all from +inside a .zip file in /usr/[local/]share-libwebsockets-test-server/candide.zip + +Usage is otherwise automatic, if you arrange a mount that points to the zipfile, +eg, "/ziptest" -> "mypath/test.zip", then URLs like `/ziptest/index.html` will be +servied from `index.html` inside `mypath/test.zip` + +@section frags Fragmented messages + +To support fragmented messages you need to check for the final +frame of a message with `lws_is_final_fragment`. This +check can be combined with `libwebsockets_remaining_packet_payload` +to gather the whole contents of a message, eg: + +``` + case LWS_CALLBACK_RECEIVE: + { + Client * const client = (Client *)user; + const size_t remaining = lws_remaining_packet_payload(wsi); + + if (!remaining && lws_is_final_fragment(wsi)) { + if (client->HasFragments()) { + client->AppendMessageFragment(in, len, 0); + in = (void *)client->GetMessage(); + len = client->GetMessageLength(); + } + + client->ProcessMessage((char *)in, len, wsi); + client->ResetMessage(); + } else + client->AppendMessageFragment(in, len, remaining); + } + break; +``` + +The test app libwebsockets-test-fraggle sources also show how to +deal with fragmented messages. + + +@section debuglog Debug Logging + +Also using `lws_set_log_level` api you may provide a custom callback to actually +emit the log string. By default, this points to an internal emit function +that sends to stderr. Setting it to `NULL` leaves it as it is instead. + +A helper function `lwsl_emit_syslog()` is exported from the library to simplify +logging to syslog. You still need to use `setlogmask`, `openlog` and `closelog` +in your user code. + +The logging apis are made available for user code. + +- `lwsl_err(...)` +- `lwsl_warn(...)` +- `lwsl_notice(...)` +- `lwsl_info(...)` +- `lwsl_debug(...)` + +The difference between notice and info is that notice will be logged by default +whereas info is ignored by default. + +If you are not building with _DEBUG defined, ie, without this + +``` + $ cmake .. -DCMAKE_BUILD_TYPE=DEBUG +``` + +then log levels below notice do not actually get compiled in. + + + +@section extpoll External Polling Loop support + +**libwebsockets** maintains an internal `poll()` array for all of its +sockets, but you can instead integrate the sockets into an +external polling array. That's needed if **libwebsockets** will +cooperate with an existing poll array maintained by another +server. + +Four callbacks `LWS_CALLBACK_ADD_POLL_FD`, `LWS_CALLBACK_DEL_POLL_FD`, +`LWS_CALLBACK_SET_MODE_POLL_FD` and `LWS_CALLBACK_CLEAR_MODE_POLL_FD` +appear in the callback for protocol 0 and allow interface code to +manage socket descriptors in other poll loops. + +You can pass all pollfds that need service to `lws_service_fd()`, even +if the socket or file does not belong to **libwebsockets** it is safe. + +If **libwebsocket** handled it, it zeros the pollfd `revents` field before returning. +So you can let **libwebsockets** try and if `pollfd->revents` is nonzero on return, +you know it needs handling by your code. + +Also note that when integrating a foreign event loop like libev or libuv where +it doesn't natively use poll() semantics, and you must return a fake pollfd +reflecting the real event: + + - be sure you set .events to .revents value as well in the synthesized pollfd + + - check the built-in support for the event loop if possible (eg, ./lib/libuv.c) + to see how it interfaces to lws + + - use LWS_POLLHUP / LWS_POLLIN / LWS_POLLOUT from libwebsockets.h to avoid + losing windows compatibility + +You also need to take care about "forced service" somehow... these are cases +where the network event was consumed, incoming data was all read, for example, +but the work arising from it was not completed. There will not be any more +network event to trigger the remaining work, Eg, we read compressed data, but +we did not use up all the decompressed data before returning to the event loop +because we had to write some of it. + +Lws provides an API to determine if anyone is waiting for forced service, +`lws_service_adjust_timeout(context, 1, tsi)`, normally tsi is 0. If it returns +0, then at least one connection has pending work you can get done by calling +`lws_service_tsi(context, -1, tsi)`, again normally tsi is 0. + +For eg, the default poll() event loop, or libuv/ev/event, lws does this +checking for you and handles it automatically. But in the external polling +loop case, you must do it explicitly. Handling it after every normal service +triggered by the external poll fd should be enough, since the situations needing +it are initially triggered by actual network events. + +An example of handling it is shown in the test-server code specific to +external polling. + +@section cpp Using with in c++ apps + +The library is ready for use by C++ apps. You can get started quickly by +copying the test server + +``` + $ cp test-apps/test-server.c test.cpp +``` + +and building it in C++ like this + +``` + $ g++ -DINSTALL_DATADIR=\"/usr/share\" -ocpptest test.cpp -lwebsockets +``` + +`INSTALL_DATADIR` is only needed because the test server uses it as shipped, if +you remove the references to it in your app you don't need to define it on +the g++ line either. + + +@section headerinfo Availability of header information + +HTTP Header information is managed by a pool of "ah" structs. These are a +limited resource so there is pressure to free the headers and return the ah to +the pool for reuse. + +For that reason header information on HTTP connections that get upgraded to +websockets is lost after the ESTABLISHED callback. Anything important that +isn't processed by user code before then should be copied out for later. + +For HTTP connections that don't upgrade, header info remains available the +whole time. + + +@section ka TCP Keepalive + +It is possible for a connection which is not being used to send to die +silently somewhere between the peer and the side not sending. In this case +by default TCP will just not report anything and you will never get any more +incoming data or sign the link is dead until you try to send. + +To deal with getting a notification of that situation, you can choose to +enable TCP keepalives on all **libwebsockets** sockets, when you create the +context. + +To enable keepalive, set the ka_time member of the context creation parameter +struct to a nonzero value (in seconds) at context creation time. You should +also fill ka_probes and ka_interval in that case. + +With keepalive enabled, the TCP layer will send control packets that should +stimulate a response from the peer without affecting link traffic. If the +response is not coming, the socket will announce an error at `poll()` forcing +a close. + +Note that BSDs don't support keepalive time / probes / interval per-socket +like Linux does. On those systems you can enable keepalive by a nonzero +value in `ka_time`, but the systemwide kernel settings for the time / probes/ +interval are used, regardless of what nonzero value is in `ka_time`. + + +@section sslopt Optimizing SSL connections + +There's a member `ssl_cipher_list` in the `lws_context_creation_info` struct +which allows the user code to restrict the possible cipher selection at +context-creation time. + +You might want to look into that to stop the ssl peers selecting a cipher which +is too computationally expensive. To use it, point it to a string like + + `"RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL"` + +if left `NULL`, then the "DEFAULT" set of ciphers are all possible to select. + +You can also set it to `"ALL"` to allow everything (including insecure ciphers). + + +@section sslcerts Passing your own cert information direct to SSL_CTX + +For most users it's enough to pass the SSL certificate and key information by +giving filepaths to the info.ssl_cert_filepath and info.ssl_private_key_filepath +members when creating the vhost. + +If you want to control that from your own code instead, you can do so by leaving +the related info members NULL, and setting the info.options flag +LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX at vhost creation time. That will create +the vhost SSL_CTX without any certificate, and allow you to use the callback +LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS to add your certificate to +the SSL_CTX directly. The vhost SSL_CTX * is in the user parameter in that +callback. + +@section clientasync Async nature of client connections + +When you call `lws_client_connect_info(..)` and get a `wsi` back, it does not +mean your connection is active. It just means it started trying to connect. + +Your client connection is actually active only when you receive +`LWS_CALLBACK_CLIENT_ESTABLISHED` for it. + +There's a 5 second timeout for the connection, and it may give up or die for +other reasons, if any of that happens you'll get a +`LWS_CALLBACK_CLIENT_CONNECTION_ERROR` callback on protocol 0 instead for the +`wsi`. + +After attempting the connection and getting back a non-`NULL` `wsi` you should +loop calling `lws_service()` until one of the above callbacks occurs. + +As usual, see [test-client.c](test-apps/test-client.c) for example code. + +Notice that the client connection api tries to progress the connection +somewhat before returning. That means it's possible to get callbacks like +CONNECTION_ERROR on the new connection before your user code had a chance to +get the wsi returned to identify it (in fact if the connection did fail early, +NULL will be returned instead of the wsi anyway). + +To avoid that problem, you can fill in `pwsi` in the client connection info +struct to point to a struct lws that get filled in early by the client +connection api with the related wsi. You can then check for that in the +callback to confirm the identity of the failing client connection. + + +@section fileapi Lws platform-independent file access apis + +lws now exposes his internal platform file abstraction in a way that can be +both used by user code to make it platform-agnostic, and be overridden or +subclassed by user code. This allows things like handling the URI "directory +space" as a virtual filesystem that may or may not be backed by a regular +filesystem. One example use is serving files from inside large compressed +archive storage without having to unpack anything except the file being +requested. + +The test server shows how to use it, basically the platform-specific part of +lws prepares a file operations structure that lives in the lws context. + +The user code can get a pointer to the file operations struct + +``` + LWS_VISIBLE LWS_EXTERN struct lws_plat_file_ops * + `lws_get_fops`(struct lws_context *context); +``` + +and then can use helpers to also leverage these platform-independent +file handling apis + +``` + lws_fop_fd_t + `lws_plat_file_open`(struct lws_plat_file_ops *fops, const char *filename, + lws_fop_flags_t *flags) + int + `lws_plat_file_close`(lws_fop_fd_t fop_fd) + + unsigned long + `lws_plat_file_seek_cur`(lws_fop_fd_t fop_fd, lws_fileofs_t offset) + + int + `lws_plat_file_read`(lws_fop_fd_t fop_fd, lws_filepos_t *amount, + uint8_t *buf, lws_filepos_t len) + + int + `lws_plat_file_write`(lws_fop_fd_t fop_fd, lws_filepos_t *amount, + uint8_t *buf, lws_filepos_t len ) +``` + +Generic helpers are provided which provide access to generic fops information or +call through to the above fops + +``` +lws_filepos_t +lws_vfs_tell(lws_fop_fd_t fop_fd); + +lws_filepos_t +lws_vfs_get_length(lws_fop_fd_t fop_fd); + +uint32_t +lws_vfs_get_mod_time(lws_fop_fd_t fop_fd); + +lws_fileofs_t +lws_vfs_file_seek_set(lws_fop_fd_t fop_fd, lws_fileofs_t offset); + +lws_fileofs_t +lws_vfs_file_seek_end(lws_fop_fd_t fop_fd, lws_fileofs_t offset); +``` + + +The user code can also override or subclass the file operations, to either +wrap or replace them. An example is shown in test server. + +### Changes from v2.1 and before fops + +There are several changes: + +1) Pre-2.2 fops directly used platform file descriptors. Current fops returns and accepts a wrapper type lws_fop_fd_t which is a pointer to a malloc'd struct containing information specific to the filesystem implementation. + +2) Pre-2.2 fops bound the fops to a wsi. This is completely removed, you just give a pointer to the fops struct that applies to this file when you open it. Afterwards, the operations in the fops just need the lws_fop_fd_t returned from the open. + +3) Everything is wrapped in typedefs. See lws-plat-unix.c for examples of how to implement. + +4) Position in the file, File Length, and a copy of Flags left after open are now generically held in the fop_fd. +VFS implementation must set and manage this generic information now. See the implementations in lws-plat-unix.c for +examples. + +5) The file length is no longer set at a pointer provided by the open() fop. The api `lws_vfs_get_length()` is provided to +get the file length after open. + +6) If your file namespace is virtual, ie, is not reachable by platform fops directly, you must set LWS_FOP_FLAG_VIRTUAL +on the flags during open. + +7) There is an optional `mod_time` uint32_t member in the generic fop_fd. If you are able to set it during open, you +should indicate it by setting `LWS_FOP_FLAG_MOD_TIME_VALID` on the flags. + +@section rawfd RAW file descriptor polling + +LWS allows you to include generic platform file descriptors in the lws service / poll / event loop. + +Open your fd normally and then + +``` + lws_sock_file_fd_type u; + + u.filefd = your_open_file_fd; + + if (!lws_adopt_descriptor_vhost(vhost, 0, u, + "protocol-name-to-bind-to", + optional_wsi_parent_or_NULL)) { + // failed + } + + // OK +``` + +A wsi is created for the file fd that acts like other wsi, you will get these +callbacks on the named protocol + +``` + LWS_CALLBACK_RAW_ADOPT_FILE + LWS_CALLBACK_RAW_RX_FILE + LWS_CALLBACK_RAW_WRITEABLE_FILE + LWS_CALLBACK_RAW_CLOSE_FILE +``` + +starting with LWS_CALLBACK_RAW_ADOPT_FILE. + +`protocol-lws-raw-test` plugin provides a method for testing this with +`libwebsockets-test-server-v2.0`: + +The plugin creates a FIFO on your system called "/tmp/lws-test-raw" + +You can feed it data through the FIFO like this + +``` + $ sudo sh -c "echo hello > /tmp/lws-test-raw" +``` + +This plugin simply prints the data. But it does it through the lws event +loop / service poll. + +@section rawsrvsocket RAW server socket descriptor polling + +You can also enable your vhost to accept RAW socket connections, in addition to +HTTP[s] and WS[s]. If the first bytes written on the connection are not a +valid HTTP method, then the connection switches to RAW mode. + +This is disabled by default, you enable it by setting the `.options` flag +LWS_SERVER_OPTION_FALLBACK_TO_RAW when creating the vhost. + +RAW mode socket connections receive the following callbacks + +``` + LWS_CALLBACK_RAW_ADOPT + LWS_CALLBACK_RAW_RX + LWS_CALLBACK_RAW_WRITEABLE + LWS_CALLBACK_RAW_CLOSE +``` + +You can control which protocol on your vhost handles these RAW mode +incoming connections by marking the selected protocol with a pvo `raw`, eg + +``` + "protocol-lws-raw-test": { + "status": "ok", + "raw": "1" + }, +``` + +The "raw" pvo marks this protocol as being used for RAW connections. + +`protocol-lws-raw-test` plugin provides a method for testing this with +`libwebsockets-test-server-v2.0`: + +Run libwebsockets-test-server-v2.0 and connect to it by telnet, eg + +``` + $ telnet 127.0.0.1 7681 +``` + +type something that isn't a valid HTTP method and enter, before the +connection times out. The connection will switch to RAW mode using this +protocol, and pass the unused rx as a raw RX callback. + +The test protocol echos back what was typed on telnet to telnet. + +@section rawclientsocket RAW client socket descriptor polling + +You can now also open RAW socket connections in client mode. + +Follow the usual method for creating a client connection, but set the +`info.method` to "RAW". When the connection is made, the wsi will be +converted to RAW mode and operate using the same callbacks as the +server RAW sockets described above. + +The libwebsockets-test-client supports this using raw:// URLS. To +test, open a netcat listener in one window + +``` + $ nc -l 9999 +``` + +and in another window, connect to it using the test client + +``` + $ libwebsockets-test-client raw://127.0.0.1:9999 +``` + +The connection should succeed, and text typed in the netcat window (including a CRLF) +will be received in the client. + +@section ecdh ECDH Support + +ECDH Certs are now supported. Enable the CMake option + + cmake .. -DLWS_SSL_SERVER_WITH_ECDH_CERT=1 + +**and** the info->options flag + + LWS_SERVER_OPTION_SSL_ECDH + +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 +very simple to use, libwebsockets-test-server-pthread shows how to do it, +use -j argument there to control the number of service threads up to 32. + +Two new members are added to the info struct + + unsigned int count_threads; + unsigned int fd_limit_per_thread; + +leave them at the default 0 to get the normal singlethreaded service loop. + +Set count_threads to n to tell lws you will have n simultaneous service threads +operating on the context. + +There is still a single listen socket on one port, no matter how many +service threads. + +When a connection is made, it is accepted by the service thread with the least +connections active to perform load balancing. + +The user code is responsible for spawning n threads running the service loop +associated to a specific tsi (Thread Service Index, 0 .. n - 1). See +the libwebsockets-test-server-pthread for how to do. + +If you leave fd_limit_per_thread at 0, then the process limit of fds is shared +between the service threads; if you process was allowed 1024 fds overall then +each thread is limited to 1024 / n. + +You can set fd_limit_per_thread to a nonzero number to control this manually, eg +the overall supported fd limit is less than the process allowance. + +You can control the context basic data allocation for multithreading from Cmake +using -DLWS_MAX_SMP=, if not given it's set to 32. The serv_buf allocation +for the threads (currently 4096) is made at runtime only for active threads. + +Because lws will limit the requested number of actual threads supported +according to LWS_MAX_SMP, there is an api lws_get_count_threads(context) to +discover how many threads were actually allowed when the context was created. + +It's required to implement locking in the user code in the same way that +libwebsockets-test-server-pthread does it, for the FD locking callbacks. + +There is no knowledge or dependency in lws itself about pthreads. How the +locking is implemented is entirely up to the user code. + + +@section libevuv Libev / Libuv support + +You can select either or both + + -DLWS_WITH_LIBEV=1 + -DLWS_WITH_LIBUV=1 + +at cmake configure-time. The user application may use one of the +context init options flags + + LWS_SERVER_OPTION_LIBEV + LWS_SERVER_OPTION_LIBUV + +to indicate it will use either of the event libraries. + + +@section extopts Extension option control from user code + +User code may set per-connection extension options now, using a new api +`lws_set_extension_option()`. + +This should be called from the ESTABLISHED callback like this +``` + lws_set_extension_option(wsi, "permessage-deflate", + "rx_buf_size", "12"); /* 1 << 12 */ +``` + +If the extension is not active (missing or not negotiated for the +connection, or extensions are disabled on the library) the call is +just returns -1. Otherwise the connection's extension has its +named option changed. + +The extension may decide to alter or disallow the change, in the +example above permessage-deflate restricts the size of his rx +output buffer also considering the protocol's rx_buf_size member. + + +@section httpsclient Client connections as HTTP[S] rather than WS[S] + +You may open a generic http client connection using the same +struct lws_client_connect_info used to create client ws[s] +connections. + +To stay in http[s], set the optional info member "method" to +point to the string "GET" instead of the default NULL. + +After the server headers are processed, when payload from the +server is available the callback LWS_CALLBACK_RECEIVE_CLIENT_HTTP +will be made. + +You can choose whether to process the data immediately, or +queue a callback when an outgoing socket is writeable to provide +flow control, and process the data in the writable callback. + +Either way you use the api `lws_http_client_read()` to access the +data, eg + +``` + case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: + { + char buffer[1024 + LWS_PRE]; + char *px = buffer + LWS_PRE; + int lenx = sizeof(buffer) - LWS_PRE; + + lwsl_notice("LWS_CALLBACK_RECEIVE_CLIENT_HTTP\n"); + + /* + * Often you need to flow control this by something + * else being writable. In that case call the api + * to get a callback when writable here, and do the + * pending client read in the writeable callback of + * the output. + */ + if (lws_http_client_read(wsi, &px, &lenx) < 0) + return -1; + while (lenx--) + putchar(*px++); + } + break; +``` + +Notice that if you will use SSL client connections on a vhost, you must +prepare the client SSL context for the vhost after creating the vhost, since +this is not normally done if the vhost was set up to listen / serve. Call +the api lws_init_vhost_client_ssl() to also allow client SSL on the vhost. + + + +@section vhosts Using lws vhosts + +If you set LWS_SERVER_OPTION_EXPLICIT_VHOSTS options flag when you create +your context, it won't create a default vhost using the info struct +members for compatibility. Instead you can call lws_create_vhost() +afterwards to attach one or more vhosts manually. + +``` + LWS_VISIBLE struct lws_vhost * + lws_create_vhost(struct lws_context *context, + struct lws_context_creation_info *info); +``` + +lws_create_vhost() uses the same info struct as lws_create_context(), +it ignores members related to context and uses the ones meaningful +for vhost (marked with VH in libwebsockets.h). + +``` + struct lws_context_creation_info { + int port; /* VH */ + const char *iface; /* VH */ + const struct lws_protocols *protocols; /* VH */ + const struct lws_extension *extensions; /* VH */ + ... +``` + +When you attach the vhost, if the vhost's port already has a listen socket +then both vhosts share it and use SNI (is SSL in use) or the Host: header +from the client to select the right one. Or if no other vhost already +listening the a new listen socket is created. + +There are some new members but mainly it's stuff you used to set at +context creation time. + + +@section sni How lws matches hostname or SNI to a vhost + +LWS first strips any trailing :port number. + +Then it tries to find an exact name match for a vhost listening on the correct +port, ie, if SNI or the Host: header provided abc.com:1234, it will match on a +vhost named abc.com that is listening on port 1234. + +If there is no exact match, lws will consider wildcard matches, for example +if cats.abc.com:1234 is provided by the client by SNI or Host: header, it will +accept a vhost "abc.com" listening on port 1234. If there was a better, exact, +match, it will have been chosen in preference to this. + +Connections with SSL will still have the client go on to check the +certificate allows wildcards and error out if not. + + + +@section mounts Using lws mounts on a vhost + +The last argument to lws_create_vhost() lets you associate a linked +list of lws_http_mount structures with that vhost's URL 'namespace', in +a similar way that unix lets you mount filesystems into areas of your / +filesystem how you like and deal with the contents transparently. + +``` + struct lws_http_mount { + struct lws_http_mount *mount_next; + const char *mountpoint; /* mountpoint in http pathspace, eg, "/" */ + const char *origin; /* path to be mounted, eg, "/var/www/warmcat.com" */ + const char *def; /* default target, eg, "index.html" */ + + struct lws_protocol_vhost_options *cgienv; + + int cgi_timeout; + int cache_max_age; + + unsigned int cache_reusable:1; + unsigned int cache_revalidate:1; + unsigned int cache_intermediaries:1; + + unsigned char origin_protocol; + unsigned char mountpoint_len; + }; +``` + +The last mount structure should have a NULL mount_next, otherwise it should +point to the 'next' mount structure in your list. + +Both the mount structures and the strings must persist until the context is +destroyed, since they are not copied but used in place. + +`.origin_protocol` should be one of + +``` + enum { + LWSMPRO_HTTP, + LWSMPRO_HTTPS, + LWSMPRO_FILE, + LWSMPRO_CGI, + LWSMPRO_REDIR_HTTP, + LWSMPRO_REDIR_HTTPS, + LWSMPRO_CALLBACK, + }; +``` + + - LWSMPRO_FILE is used for mapping url namespace to a filesystem directory and +serve it automatically. + + - LWSMPRO_CGI associates the url namespace with the given CGI executable, which +runs when the URL is accessed and the output provided to the client. + + - LWSMPRO_REDIR_HTTP and LWSMPRO_REDIR_HTTPS auto-redirect clients to the given +origin URL. + + - LWSMPRO_CALLBACK causes the http connection to attach to the callback +associated with the named protocol (which may be a plugin). + + +@section mountcallback Operation of LWSMPRO_CALLBACK mounts + +The feature provided by CALLBACK type mounts is binding a part of the URL +namespace to a named protocol callback handler. + +This allows protocol plugins to handle areas of the URL namespace. For example +in test-server-v2.0.c, the URL area "/formtest" is associated with the plugin +providing "protocol-post-demo" like this + +``` + static const struct lws_http_mount mount_post = { + NULL, /* linked-list pointer to next*/ + "/formtest", /* mountpoint in URL namespace on this vhost */ + "protocol-post-demo", /* handler */ + NULL, /* default filename if none given */ + NULL, + 0, + 0, + 0, + 0, + 0, + LWSMPRO_CALLBACK, /* origin points to a callback */ + 9, /* strlen("/formtest"), ie length of the mountpoint */ + }; +``` + +Client access to /formtest[anything] will be passed to the callback registered +with the named protocol, which in this case is provided by a protocol plugin. + +Access by all methods, eg, GET and POST are handled by the callback. + +protocol-post-demo deals with accepting and responding to the html form that +is in the test server HTML. + +When a connection accesses a URL related to a CALLBACK type mount, the +connection protocol is changed until the next access on the connection to a +URL outside the same CALLBACK mount area. User space on the connection is +arranged to be the size of the new protocol user space allocation as given in +the protocol struct. + +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). + +This "binding connection to a protocol" lifecycle in managed by +`LWS_CALLBACK_HTTP_BIND_PROTOCOL` and `LWS_CALLBACK_HTTP_DROP_PROTOCOL`. +Because of HTTP/1.1 connection pipelining, one connection may perform +many transactions, each of which may map to different URLs and need +binding to different protocols. So these messages are used to +create the binding of the wsi to your protocol including any +allocations, and to destroy the binding, at which point you should +destroy any related allocations. + +@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 +is still connected to the server, by greying out the page if not. You can +also add this to your own html easily + + - include lws-common.js from your HEAD section + + + + - dim the page during initialization, in a script section on your page + + lws_gray_out(true,{'zindex':'499'}); + + - in your ws onOpen(), remove the dimming + + lws_gray_out(false); + + - in your ws onClose(), reapply the dimming + + lws_gray_out(true,{'zindex':'499'}); diff --git a/READMEs/README.esp32.md b/READMEs/README.esp32.md new file mode 100644 index 0000000..6f64891 --- /dev/null +++ b/READMEs/README.esp32.md @@ -0,0 +1,23 @@ +ESP32 Support +============= + +Lws provides a "factory" application + +https://github.com/warmcat/lws-esp32-factory + +and a test application which implements the generic lws server test apps + +https://github.com/warmcat/lws-esp32-test-server-demos + +The behaviours of the generic factory are are quite rich, and cover uploading SSL certs through factory and user configuration, AP selection and passphrase entry, and managing a switch to allow the user to force entry to user setup mode at boot subsequently. + +The factory app comes with partitioning for a 1MB factory partition containing that app and data, and a single 2.9MB OTA partition containing the main app. + +The factory app is able to do OTA updates for both the factory and OTA partition slots; updating the factory slot first writes the new image to the OTA slot and copies it into place at the next boot, after which the user can reload the OTA slot. + +State|Image|AP SSID|Port|URL|Mode +---|---|---|---|---|--- +Factory Reset or Uninitialized|Factory|AP: ESP_012345|80|http://192.168.4.1|factory.html - to set certificates and serial +User configuration|Factory|AP: config-model-serial|443|https://192.168.4.1|index.html - user set up his AP information +Operation|OTA|Station only|443|https://model-serial.local|OTA application + diff --git a/READMEs/README.esp8266.md b/READMEs/README.esp8266.md new file mode 100644 index 0000000..ffcf757 --- /dev/null +++ b/READMEs/README.esp8266.md @@ -0,0 +1,34 @@ +ESP8266 lws port +---------------- + +lws can now work well on the ESP8266. + +You should get the ESP8266 Espressif SDK-based project here + +https://github.com/lws-team/esplws + +which includes lws as an "app" in the build. The project provides full AP-based setup over the web, and once the device has been configured to associate to a local AP, a separate station vhost with the lws test protocols. + +Instructions for building that are here + +https://github.com/lws-team/esplws/blob/master/README.md + +There are also instructions there for how to remove the test apps from the build and customize your own station content. + + +Information about lws integration on ESP8266 +-------------------------------------------- + +The following existing lws features are used to make a nice integration: + + - vhosts: there are separate vhosts for the configuration AP mode and the normal station mode. + + - file_ops: the lws file operations are overridden and handled by a ROMFS parser + + - mounts: mounts are used to serve files automatically from the ROMFS + + - plugins: standalone protocol plugins are included into the build, so there are clean individual implementations for each protocol, while everything is statically linked + + - lws stability and security features like bytewise parsers, sophisticated timeouts, http/1.1 keepalive support + + diff --git a/READMEs/README.generic-sessions.md b/READMEs/README.generic-sessions.md new file mode 100644 index 0000000..376342a --- /dev/null +++ b/READMEs/README.generic-sessions.md @@ -0,0 +1,373 @@ +Notes about generic-sessions Plugin +=================================== + +@section gseb Enabling lwsgs for build + +Enable at CMake with -DLWS_WITH_GENERIC_SESSIONS=1 + +This also needs sqlite3 (libsqlite3-dev or similar package) + + +@section gsi lwsgs Introduction + +The generic-sessions protocol plugin provides cookie-based login +authentication for lws web and ws connections. + +The plugin handles everything about generic account registration, +email verification, lost password, account deletion, and other generic account +management. + +Other code, in another eg, ws protocol handler, only needs very high-level +state information from generic-sessions, ie, which user the client is +authenticated as. Everything underneath is managed in generic-sessions. + + + - random 20-byte session id managed in a cookie + + - all information related to the session held at the server, nothing managed clientside + + - sqlite3 used at the server to manage active sessions and users + + - defaults to creating anonymous sessions with no user associated + + - admin account (with user-selectable username) is defined in config with a SHA-1 of the password; rest of the accounts are in sqlite3 + + - user account passwords stored as salted SHA-1 with additional confounder + only stored in the JSON config, not the database + + - login, logout, register account + email verification built-in with examples + + - in a mount, some file suffixes (ie, .js) can be associated with a protocol for the purposes of rewriting symbolnames. These are read-only copies of logged-in server state. + + - When your page fetches .js or other rewritten files from that mount, "$lwsgs_user" and so on are rewritten on the fly using chunked transfer encoding + + - Eliminates server-side scripting with a few rewritten symbols and + javascript on client side + + - 32-bit bitfield for authentication sectoring, mounts can provide a mask on the loggin-in session's associated server-side bitfield that must be set for access. + + - No code (just config) required for, eg, private URL namespace that requires login to access. + + +@section gsin Lwsgs Integration to HTML + +Only three steps are needed to integrate lwsgs in your HTML. + +1) lwsgs HTML UI is bundled with the javascript it uses in `lwsgs.js`, so +import that script file in your head section + +2) define an empty div of id "lwsgs" somewhere + +3) Call lwsgs_initial() in your page + +That's it. An example is below + +``` + + + + + + + + + + + +
+ + +
+
+ + + + + + +``` + +@section gsof Lwsgs Overall Flow@ + +When the protocol is initialized, it gets per-vhost information from the config, such +as where the sqlite3 databases are to be stored. The admin username and sha-1 of the +admin password are also taken from here. + +In the mounts using protocol-generic-sessions, a cookie is maintained against any requests; if no cookie was active on the initial request a new session is +created with no attached user. + +So there should always be an active session after any transactions with the server. + +In the example html going to the mount /lwsgs loads a login / register page as the default. + +The
in the login page contains 'next url' hidden inputs that let the html 'program' where the form handler will go after a successful admin login, a successful user login and a failed login. + +After a successful login, the sqlite record at the server for the current session is updated to have the logged-in username associated with it. + + + +@section gsconf Lwsgs Configuration + +"auth-mask" defines the authorization sector bits that must be enabled on the session to gain access. + +"auth-mask" 0 is the default. + + - b0 is set if you are logged in as a user at all. + - b1 is set if you are logged in with the user configured to be admin + - b2 is set if the account has been verified (the account configured for admin is always verified) + - b3 is set if your session just did the forgot password flow successfully + +``` + { + # things in here can always be served + "mountpoint": "/lwsgs", + "origin": "file:///usr/share/libwebsockets-test-server/generic-sessions", + "origin": "callback://protocol-lws-messageboard", + "default": "generic-sessions-login-example.html", + "auth-mask": "0", + "interpret": { + ".js": "protocol-lws-messageboard" + } + }, { + # things in here can only be served if logged in as a user + "mountpoint": "/lwsgs/needauth", + "origin": "file:///usr/share/libwebsockets-test-server/generic-sessions/needauth", + "origin": "callback://protocol-lws-messageboard", + "default": "generic-sessions-login-example.html", + "auth-mask": "5", # logged in as a verified user + "interpret": { + ".js": "protocol-lws-messageboard" + } + }, { + # things in here can only be served if logged in as admin + "mountpoint": "/lwsgs/needadmin", + "origin": "file:///usr/share/libwebsockets-test-server/generic-sessions/needadmin", + "origin": "callback://protocol-lws-messageboard", + "default": "generic-sessions-login-example.html", + "auth-mask": "7", # b2 = verified (by email / or admin), b1 = admin, b0 = logged in with any user name + "interpret": { + ".js": "protocol-lws-messageboard" + } + } +``` +Note that the name of the real application protocol that uses generic-sessions +is used, not generic-sessions itself. + +The vhost configures the storage dir, admin credentials and session cookie lifetimes: + +``` + "ws-protocols": [{ + "protocol-generic-sessions": { + "status": "ok", + "admin-user": "admin", + + # create the pw hash like this (for the example pw, "jipdocesExunt" ) + # $ echo -n "jipdocesExunt" | sha1sum + # 046ce9a9cca769e85798133be06ef30c9c0122c9 - + # + # Obviously ** change this password hash to a secret one before deploying ** + # + "admin-password-sha1": "046ce9a9cca769e85798133be06ef30c9c0122c9", + "session-db": "/var/www/sessions/lws.sqlite3", + "timeout-idle-secs": "600", + "timeout-anon-idle-secs": "1200", + "timeout-absolute-secs": "6000", + # the confounder is part of the salted password hashes. If this config + # file is in a 0700 root:root dir, an attacker with apache credentials + # will have to get the confounder out of the process image to even try + # to guess the password hashes. + "confounder": "Change to <=31 chars of junk", + + "email-from": "noreply@example.com", + "email-smtp-ip": "127.0.0.1", + "email-expire": "3600", + "email-helo": "myhost.com", + "email-contact-person": "Set Me ", + "email-confirm-url-base": "http://localhost:7681/lwsgs" + } +``` + +The email- related settings control generation of automatic emails for +registration and forgotten password. + + - `email-from`: The email address automatic emails are sent from + + - `email-smtp-ip`: Normally 127.0.0.1, if you have a suitable server on port + 25 on your lan you can use this instead here. + + - `email-expire`: Seconds that links sent in email will work before being + deleted + + - `email-helo`: HELO to use when communicating with your SMTP server + + - `email-contact-person`: mentioned in the automatic emails as a human who can + answer questions + + - `email-confirm-url-base`: the URL to start links with in the emails, so the + recipient can get back to the web server + +The real protocol that makes use of generic-sessions must also be listed and +any configuration it needs given + +``` + "protocol-lws-messageboard": { + "status": "ok", + "message-db": "/var/www/sessions/messageboard.sqlite3" + }, +``` + +Notice the real application uses his own sqlite db, no details about how +generic-sessions works or how it stores data are available to it. + + +@section gspwc Lwsgs Password Confounder + +You can also define a per-vhost confounder shown in the example above, used +when aggregating the password with the salt when it is hashed. Any attacker +will also need to get the confounder along with the database, which you can +make harder by making the config dir only eneterable / readable by root. + + +@section gsprep Lwsgs Preparing the db directory + +You will have to prepare the db directory so it's suitable for the lwsws user to use, +that usually means apache, eg + +``` + # mkdir -p /var/www/sessions + # chown root:apache /var/www/sessions + # chmod 770 /var/www/sessions +``` + +@section gsrmail Lwsgs Email configuration + +lwsgs will can send emails by talking to an SMTP server on localhost:25. That +will usually be sendmail or postfix, you should confirm that works first by +itself using the `mail` application to send on it. + +lwsgs has been tested on stock Fedora sendmail and postfix. + + +@section gsap Lwsgs Integration with another protocol + +lwsgs is designed to provide sessions and accounts in a standalone and generic way. + +But it's not useful by itself, there will always be the actual application who wants +to make use of generic-sessions features. + +We provide the "messageboard" plugin as an example of how to integrate with +your actual application protocol. + +The basic approach is the 'real' protocol handler (usually a plugin itself) +subclasses the generic-sessions plugin and calls through to it by default. + +The "real" protocol handler entirely deals with ws-related stuff itself, since +generic-sessions does not use ws. But for + + - LWS_CALLBACK_HTTP + - LWS_CALLBACK_HTTP_BODY + - LWS_CALLBACK_HTTP_BODY_COMPLETION + - LWS_CALLBACK_HTTP_DROP_PROTOCOL + +the "real" protocol handler checks if it recognizes the activity (eg, his own +POST form URL) and if not, passes stuff through to the generic-sessions protocol callback to handle it. To simplify matters the real protocol can just pass +through any unhandled messages to generic-sessions. + +The "real" protocol can get a pointer to generic-sessions protocol on the +same vhost using + +``` + vhd->gsp = lws_vhost_name_to_protocol(vhd->vh, "protocol-generic-sessions"); +``` + +The "real" protocol must also arrange generic-sessions per_session_data in his +own per-session allocation. To allow keeping generic-sessions opaque, the +real protocol must allocate that space at runtime, using the pss size +the generic-sessions protocol struct exposes + +``` + struct per_session_data__myapp { + void *pss_gs; + ... + + pss->pss_gs = malloc(vhd->gsp->per_session_data_size); +``` + +The allocation reserved for generic-sessions is then used as user_space when +the real protocol calls through to the generic-sessions callback + +``` + vhd->gsp->callback(wsi, reason, &pss->pss_gs, in, len); +``` + +In that way the "real" protocol can subclass generic-sessions functionality. + + +To ease management of these secondary allocations, there are callbacks that +occur when a wsi binds to a protocol and when the binding is dropped. These +should be used to malloc and free and kind of per-connection +secondary allocations. + +``` + case LWS_CALLBACK_HTTP_BIND_PROTOCOL: + if (!pss || pss->pss_gs) + break; + + pss->pss_gs = malloc(vhd->gsp->per_session_data_size); + if (!pss->pss_gs) + return -1; + + memset(pss->pss_gs, 0, vhd->gsp->per_session_data_size); + break; + + case LWS_CALLBACK_HTTP_DROP_PROTOCOL: + if (vhd->gsp->callback(wsi, reason, pss ? pss->pss_gs : NULL, in, len)) + return -1; + + if (pss->pss_gs) { + free(pss->pss_gs); + pss->pss_gs = NULL; + } + break; +``` + + +#section gsapsib Getting session-specific information from another protocol + +At least at the time when someone tries to upgrade an http(s) connection to +ws(s) with your real protocol, it is necessary to confirm the cookie the http(s) +connection has with generic-sessions and find out his username and other info. + +Generic sessions lets another protocol check it again by calling his callback, +and lws itself provides a generic session info struct to pass the related data + +``` + struct lws_session_info { + char username[32]; + char email[100]; + char ip[72]; + unsigned int mask; + char session[42]; + }; + + struct lws_session_info sinfo; + ... + vhd->gsp->callback(wsi, LWS_CALLBACK_SESSION_INFO, + &pss->pss_gs, &sinfo, 0); +``` + +After the call to generic-sessions, the results can be + + - all the strings will be zero-length and .mask zero, there is no usable cookie + + - only .ip and .session are set: the cookie is OK but no user logged in + + - all the strings contain information about the logged-in user + +the real protocol can use this to reject attempts to open ws connections from +http connections that are not authenticated; afterwards there's no need to +check the ws connection auth status again. + diff --git a/READMEs/README.generic-table.md b/READMEs/README.generic-table.md new file mode 100644 index 0000000..7a85809 --- /dev/null +++ b/READMEs/README.generic-table.md @@ -0,0 +1,219 @@ +Notes about generic-table +========================= + +@section gtint What is generic-table? + +Generic-table is a JSON schema and client-side JS file that makes it easy to +display live, table structured HTML over a ws link. + +An example plugin and index.html using it are provided, but lwsgt itself doesn't +have its own plugin, it's just a JSON schema and client-side JS that other +plugins can use to simplify displaying live, table-based data without having +to reinvent the wheel each time. + +The ws protocol sends JSON describing the table, and then JSON updating the table +contents when it chooses, the brower table is updated automatically, live. + +\image html lwsgt-overview.png + + - Example protocol plugin (displays directory contents): https://github.com/warmcat/libwebsockets/tree/master/plugins/generic-table/protocol_table_dirlisting.c + + - Example HTML: https://github.com/warmcat/libwebsockets/tree/master/plugins/generic-table/assets/index.html + + - lwsgt.js (client-side table rendering / ws link management): https://github.com/warmcat/libwebsockets/tree/master/plugins/generic-table/assets/lwsgt.js + + +@section gteb Enabling for build + +Enable the demo plugin at CMake with -DLWS_WITH_PLUGINS=1 + + +@section gtinth Integrating with your html + + - In your HEAD section, include lwsgt.js + +``` + +``` + + - Also in your HEAD section, style the lwsgt CSS, eg + +``` + +``` + +You can skip this but the result will be less beautiful until some CSS is +provided. + + - In your body section, declare a div with an id (can be whatever you want) + +``` +
+``` + +lwsgt JS will put its content there. + + - Finally in a +``` + +In the callback, you can recover the ws object by `window[gt].lwsgt_ws`. + + +@section gtc Lwsgt constructor + +To instantiate the ws link and lwsgt instance, your HTML must call a lwsgt +constructor for each region on the page managed by lwsgt. + +`var myvar = new lwsgt_initial(title, ws_protocol, div_id, click_cb, myvar);` + +All of the arguments are strings. + +| Parameter | Description | +|-----------------|---------------------------------------------------------| +| title | Title string to go above the table | +| ws_protocol | Protocol name string to use when making ws connection | +| div_id | HTML id of div to fill with content | +| click_cb | Callback function name string to handle clickable links | +| myvar | Name of var used to hold this instantiation globally | + +Note "myvar" is needed so it can be passed to the click handling callback. + + +@section gtclick Lwsgt click handling function + +When a clickable link produced by lwsgt is clicked, the function named in the +click_cb parameter to lwsgt_initial is called. + +That function is expected to take four parameters, eg + +`function lwsgt_dir_click(gt, u, col, row)` + +| Parameter | Description | +|------- ---|-----------------------------------------------------------| +| gt | Name of global var holding this lwsgt context (ie, myvar) | +| u | Link "url" string | +| col | Table column number link is from | +| row | Table row number link is from | + + + +@section gtgj Generic-table JSON + +### Column layout + +When the ws connection is established, the protocol should send a JSON message +describing the table columns. For example + +``` + "cols": [ + { "name": "Date" }, + { "name": "Size", "align": "right" }, + { "name": "Icon" }, + { "name": "Name", "href": "uri"}, + { "name": "uri", "hide": "1" } + ] + } +``` + + - This describes 5 columns + + - Only four columns (not "uri") should be visible + + - "Name" should be presented as a clickable link using "uri" as the + destination, when a "uri" field is presented. + + - "Size" field should be presented aligned to the right + + ### Breadcrumbs + + When a view is hierarchical, it's useful to provide a "path" with links back + in the "path", known as "breadcrumbs". + + Elements before the last one should provide a "url" member as well as the + displayable name, which is used to create the link destination. + + The last element, being the current displayed page should not have a url + member and be displayed without link style. + + + ``` + "breadcrumbs":[{"name":"top", "url": "/" }, {"name":"mydir"}] + ``` + + ### Table data + + The actual file data consists of an array of rows, containing the columns + mentioned in the original "cols" section. + + ``` + "data":[ + { + "Icon":" ", + "Date":"2015-Feb-06 03:08:35 +0000", + "Size":"1406", + "uri":"./serve//favicon.ico", + "Name":"favicon.ico" + } + ] + + ``` + + @section gtdirl Setting up protocol-lws-table-dirlisting + + The example protocol needs two mounts, one to provide the index.html, js and + the protocol itself + + ``` + { + "mountpoint": "/dirtest", + "origin": "file:///usr/share/libwebsockets-test-server/generic-table", + "origin": "callback://protocol-lws-table-dirlisting", + "default": "index.html", + "pmo": [{ + "dir": "/usr/share/libwebsockets-test-server" + }] + }, +``` + +The protocol wants a per-mount option (PMO) to tell it the base directory it +is serving from, named "dir". + +The other mount is there to simply serve items that get clicked on from the +table in a secure way + +``` + { + "mountpoint": "/dirtest/serve", + "origin": "file:///usr/share/libwebsockets-test-server", + "default": "index.html" + }, +``` + +This last bit is not related to using lwsgt itself. diff --git a/READMEs/README.lws-meta.md b/READMEs/README.lws-meta.md new file mode 100644 index 0000000..dbca4c0 --- /dev/null +++ b/READMEs/README.lws-meta.md @@ -0,0 +1,192 @@ +# lws-meta protocol + +lws-meta is a lightweight ws subprotocol that accepts other ws connections +to the same server inside it and multiplexes their access to the connection. + +``` + Client Server + + conn1: \ / :conn1 + conn2: = mux ------ lws-meta ws protocol ----- mux = :conn2 + conn3: / \ :conn3 +``` + +You may have n client ws connections back to the server, but you now +only have one tcp connection (and one SSL wrapper if using SSL) instead +of n of those. + +If you currently make multiple ws connections back to the server, so you +can have different protocols active in one webpage, this if for you. + + - The subprotocol code for the connections inside a lws-meta connection + need zero changes from being a normal ws connection. It is unaware + it is inside an lws-meta parent connection. + + - The traffic on the lws-meta connection is indistinguishable from + standard ws traffic, so intermediaries won't object to it + + - The multiplexing is done in the protocol, **not by an extension**. So + it's compatible with all browsers. + + - Javascript helper code is provided to very simply use lws-meta + protocol instead of direct connections. The lws test server has + been converted to use this by default. + +# Converting your server + +1) include the provided lws-meta plugin (plugins/protocl_lws_meta.c) as an +active protocol for your server. You can do that using runtime plugins, or +include the plugin sources into your server at build-time. The lws test +server uses the latter approach. + +That's all you need to do on the server side. + +# Converting your browser JS + +1) import lws-common.js + +2) Instantiate a parent lws-meta connection object + +``` +var lws_meta = new lws_meta_ws(); +``` + +3) Connect the lws-meta object to your server + +``` +lws_meta.new_parent(get_appropriate_ws_url("?mirror=" + mirror_name)); +``` + +4) Convert your actual ws connections to go via the lws_meta object + +``` +var my_ws = lws_meta.new_ws("", "dumb-increment-protocol"); +``` + +The first arg is the URL path, the second arg is the ws protocol you want. + +That's it. my_ws will get `onopen()`, `onmessage()` etc calls as before. + +# lws-meta wire protocol + +lws-meta works by adding some bytes at the start of a message indicating +which channel the message applies to. + +Channel messages are atomic on the wire. The reason is if we tried to +intersperse other channel fragments between one channels message fragments, +an intermediary would observe violations of the ws framing rule about +having to start a message with TEXT or BINARY, and use only CONTINUATION +for the subsequent fragments. Eg + +``` + [ ch1 TEXT NOFIN ] [ ch2 BINARY FIN ] [ ch1 CONTINUATION FIN ] +``` + +is illegal to an observer that doesn't understand lws-meta headers in the +packet payloads. So to avoid this situation, only complete messages may +be sent from one subchannel in each direction at a time. + +Consequently, only the first fragment of each message is modified to +have the extra two bytes identifying the subchannel it is aimed at, since +the rest of the message from the same subchannel is defined to follow. + +If it makes latencies, modify the protocol sending large messages to +send smaller messages, so the transmission of messages from other channels +can be sent inbetween the smaller messages. + +## lws-meta commands + +1) CSTRING indicates a string terminated by 0x00 byte + +2) Channel IDs are sent with 0x20 added to them, to guarantee valid UTF-8 + +### 0x41: RX: LWS_META_CMD_OPEN_SUBCHANNEL + + - CSTRING: protocol name + - CSTRING: url + - CSTRING: cookie (7 bytes max) + +Client is requesting to open a new channel with the given protocol name, +at the given url. The cookie (eg, channel name) is only used in +LWS_META_CMD_OPEN_RESULT, when the channel id is assigned, so it is +applied to the right channel. + +### 0x42: TX: LWS_META_CMD_OPEN_RESULT + + - CSTRING cookie + - BYTE channel id (0 indicates failed) + - CSTRING: selected protocol name + +The server is informing the client of the results of a previous +open request. The cookie the client sent to identify the request +is returned along with a channel id to be used subsequently. If +the channel ID is 0 (after subtracting the transport offset of +0x20) then the open request has failed. + +### 0x43: TX: LWS_META_CMD_CLOSE_NOTIFY + + - BYTE channel id + - BYTE: payload length + 0x20 + - BYTE: close code MSB + - BYTE: close code LSB + - PAYLOAD: payload (< 123 bytes) + +Server notifies the client that a child has closed, for whatever reason. + +### 0x44: RX: LWS_META_CMD_CLOSE_RQ + - BYTE: channel id + - BYTE: payload length + 0x20 + - BYTE: close code MSB + - BYTE: close code LSB + - PAYLOAD: payload (< 123 bytes) + +The client requests to close a child connection + +### 0x45: TX: LWS_META_CMD_WRITE + + - BYTE: channel id + +Normal write of payload n from lws-meta perspective is actually +LWS_META_CMD_WRITE, channel id, then (n - 2) bytes of payload + +The command only appears at the start of a message, continuations do +not have the command. + +## Protocol Notes + + - Once the subchannel is up, overhead is only +2 bytes per message + + - Close reasons are supported in both directions + + - Ping and Pong are only supported at the lws-meta level, using normal ws ping and pong packets. + + - Only the final close of the tcp lws-meta connection itself goes out as + a normal ws close frame. Subchannels close is done in a normal TEXT + message using LWS_META_CMD_CLOSE_RQ and then the close packet payload. + This is so intermediaries do not mistake subchannel closures for the + tcp / ws link going down. + + Messages that start with LWS_META_CMD_OPEN_SUBCHANNEL only contain those + commands but may contain any number of them for the whole duration of the + message. The lws-meta js support collects child open requests made before + the parent lws-meta connection is open, and dumps them all in a single + message when it does open. + + Messages that start with LWS_META_CMD_OPEN_RESULT or LWS_META_CMD_CLOSE_NOTIFY + only contain those two commands, but they may contain any number of them + for the whole duration of the message. + + +# Current Implemention Limitations + + - only server side is supported in lws. The client side JS for + a browser is supported. + + - max number of child connections per parent at the moment is 8 + + - child connection URL paramter when opening the connection is + ignored + + - there is no ah attached when the child connections are + established inside the lws-meta parent. So header access + functions will fail. diff --git a/READMEs/README.lwsws.md b/READMEs/README.lwsws.md new file mode 100644 index 0000000..df0a878 --- /dev/null +++ b/READMEs/README.lwsws.md @@ -0,0 +1,601 @@ +Notes about lwsws +================= + +@section lwsws Libwebsockets Web Server + +lwsws is an implementation of a very lightweight, ws-capable generic web +server, which uses libwebsockets to implement everything underneath. + +If you are basically implementing a standalone server with lws, you can avoid +reinventing the wheel and use a debugged server including lws. + + +@section lwswsb Build + +Just enable -DLWS_WITH_LWSWS=1 at cmake-time. + +It enables libuv and plugin support automatically. + +NOTICE on Ubuntu, the default libuv package is called "libuv-0.10". This is ancient. + +You should replace this with libuv1 and libuv1-dev before proceeding. + +@section lwswsc Lwsws Configuration + +lwsws uses JSON config files, they're pure JSON except: + + - '#' may be used to turn the rest of the line into a comment. + + - There's also a single substitution, if a string contains "_lws_ddir_", then that is +replaced with the LWS install data directory path, eg, "/usr/share" or whatever was +set when LWS was built + installed. That lets you refer to installed paths without +having to change the config if your install path was different. + +There is a single file intended for global settings + +/etc/lwsws/conf +``` + # these are the server global settings + # stuff related to vhosts should go in one + # file per vhost in ../conf.d/ + + { + "global": { + "uid": "48", # apache user + "gid": "48", # apache user + "count-threads": "1", + "server-string": "myserver v1", # returned in http headers + "ws-pingpong-secs": "200", # confirm idle established ws connections this often + "init-ssl": "yes" + } + } +``` +and a config directory intended to take one file per vhost + +/etc/lwsws/conf.d/warmcat.com +``` + { + "vhosts": [{ + "name": "warmcat.com", + "port": "443", + "interface": "eth0", # optional + "host-ssl-key": "/etc/pki/tls/private/warmcat.com.key", # if given enable ssl + "host-ssl-cert": "/etc/pki/tls/certs/warmcat.com.crt", + "host-ssl-ca": "/etc/pki/tls/certs/warmcat.com.cer", + "mounts": [{ # autoserve + "mountpoint": "/", + "origin": "file:///var/www/warmcat.com", + "default": "index.html" + }] + }] + } +``` +To get started quickly, an example config reproducing the old test server +on port 7681, non-SSL is provided. To set it up +``` + # mkdir -p /etc/lwsws/conf.d /var/log/lwsws + # cp ./lwsws/etc-lwsws-conf-EXAMPLE /etc/lwsws/conf + # cp ./lwsws/etc-lwsws-conf.d-localhost-EXAMPLE /etc/lwsws/conf.d/test-server + # sudo lwsws +``` + +@section lwsogo Other Global Options + + - `reject-service-keywords` allows you to return an HTTP error code and message of your choice +if a keyword is found in the user agent + +``` + "reject-service-keywords": [{ + "scumbot": "404 Not Found" + }] +``` + + - `timeout-secs` lets you set the global timeout for various network-related + operations in lws, in seconds. It defaults to 5. + +@section lwswsv Lwsws Vhosts + +One server can run many vhosts, where SSL is in use SNI is used to match +the connection to a vhost and its vhost-specific SSL keys during SSL +negotiation. + +Listing multiple vhosts looks something like this +``` + { + "vhosts": [ { + "name": "localhost", + "port": "443", + "host-ssl-key": "/etc/pki/tls/private/libwebsockets.org.key", + "host-ssl-cert": "/etc/pki/tls/certs/libwebsockets.org.crt", + "host-ssl-ca": "/etc/pki/tls/certs/libwebsockets.org.cer", + "mounts": [{ + "mountpoint": "/", + "origin": "file:///var/www/libwebsockets.org", + "default": "index.html" + }, { + "mountpoint": "/testserver", + "origin": "file:///usr/local/share/libwebsockets-test-server", + "default": "test.html" + }], + # which protocols are enabled for this vhost, and optional + # vhost-specific config options for the protocol + # + "ws-protocols": [{ + "warmcat,timezoom": { + "status": "ok" + } + }] + }, + { + "name": "localhost", + "port": "7681", + "host-ssl-key": "/etc/pki/tls/private/libwebsockets.org.key", + "host-ssl-cert": "/etc/pki/tls/certs/libwebsockets.org.crt", + "host-ssl-ca": "/etc/pki/tls/certs/libwebsockets.org.cer", + "mounts": [{ + "mountpoint": "/", + "origin": ">https://localhost" + }] + }, + { + "name": "localhost", + "port": "80", + "mounts": [{ + "mountpoint": "/", + "origin": ">https://localhost" + }] + } + + ] + } +``` + +That sets up three vhosts all called "localhost" on ports 443 and 7681 with SSL, and port 80 without SSL but with a forced redirect to https://localhost + + +@section lwswsvn Lwsws Vhost name and port sharing + +The vhost name field is used to match on incoming SNI or Host: header, so it +must always be the host name used to reach the vhost externally. + + - Vhosts may have the same name and different ports, these will each create a +listening socket on the appropriate port. + + - Vhosts may also have the same port and different name: these will be treated as +true vhosts on one listening socket and the active vhost decided at SSL +negotiation time (via SNI) or if no SSL, then after the Host: header from +the client has been parsed. + + +@section lwswspr Lwsws Protocols + +Vhosts by default have available the union of any initial protocols from context creation time, and +any protocols exposed by plugins. + +Vhosts can select which plugins they want to offer and give them per-vhost settings using this syntax +``` + "ws-protocols": [{ + "warmcat-timezoom": { + "status": "ok" + } + }] +``` + +The "x":"y" parameters like "status":"ok" are made available to the protocol during its per-vhost +LWS_CALLBACK_PROTOCOL_INIT (@in is a pointer to a linked list of struct lws_protocol_vhost_options +containing the name and value pointers). + +To indicate that a protocol should be used when no Protocol: header is sent +by the client, you can use "default": "1" +``` + "ws-protocols": [{ + "warmcat-timezoom": { + "status": "ok", + "default": "1" + } + }] +``` + + +@section lwswsovo Lwsws Other vhost options + + - If the three options `host-ssl-cert`, `host-ssl-ca` and `host-ssl-key` are given, then the vhost supports SSL. + + Each vhost may have its own certs, SNI is used during the initial connection negotiation to figure out which certs to use by the server name it's asking for from the request DNS name. + + - `keeplive-timeout` (in secs) defaults to 60 for lwsws, it may be set as a vhost option + + - `interface` lets you specify which network interface to listen on, if not given listens on all + + - "`unix-socket`": "1" causes the unix socket specified in the interface option to be used instead of an INET socket + + - "`sts`": "1" causes lwsws to send a Strict Transport Security header with responses that informs the client he should never accept to connect to this address using http. This is needed to get the A+ security rating from SSL Labs for your server. + + - "`access-log`": "filepath" sets where apache-compatible access logs will be written + + - `"enable-client-ssl"`: `"1"` enables the vhost's client SSL context, you will need this if you plan to create client conections on the vhost that will use SSL. You don't need it if you only want http / ws client connections. + + - "`ciphers`": "" sets the allowed list of ciphers and key exchange protocols for the vhost. The default list is restricted to only those providing PFS (Perfect Forward Secrecy) on the author's Fedora system. + + If you need to allow weaker ciphers,you can provide an alternative list here per-vhost. + + - "`ecdh-curve`": "" The default ecdh curve is "prime256v1", but you can override it here, per-vhost + + - "`noipv6`": "on" Disable ipv6 completely for this vhost + + - "`ipv6only`": "on" Only allow ipv6 on this vhost / "off" only allow ipv4 on this vhost + + - "`ssl-option-set`": "" Sets the SSL option flag value for the vhost. + It may be used multiple times and OR's the flags together. + + The values are derived from /usr/include/openssl/ssl.h +``` + # define SSL_OP_NO_TLSv1_1 0x10000000L +``` + + would equate to + +``` + "`ssl-option-set`": "268435456" + ``` + - "`ssl-option-clear'": "" Clears the SSL option flag value for the vhost. + It may be used multiple times and OR's the flags together. + + - "`headers':: [{ "header1": "h1value", "header2": "h2value" }] + +allows you to set arbitrary headers on every file served by the vhost + +recommended vhost headers for good client security are + +``` + "headers": [{ + "Content-Security-Policy": "script-src 'self'", + "X-Content-Type-Options": "nosniff", + "X-XSS-Protection": "1; mode=block", + "X-Frame-Options": "SAMEORIGIN" + }] + +``` + +@section lwswsm Lwsws Mounts + +Where mounts are given in the vhost definition, then directory contents may +be auto-served if it matches the mountpoint. + +Mount protocols are used to control what kind of translation happens + + - file:// serve the uri using the remainder of the url past the mountpoint based on the origin directory. + + Eg, with this mountpoint +``` + { + "mountpoint": "/", + "origin": "file:///var/www/mysite.com", + "default": "/" + } +``` + The uri /file.jpg would serve /var/www/mysite.com/file.jpg, since / matched. + + - ^http:// or ^https:// these cause any url matching the mountpoint to issue a redirect to the origin url + + - cgi:// this causes any matching url to be given to the named cgi, eg +``` + { + "mountpoint": "/git", + "origin": "cgi:///var/www/cgi-bin/cgit", + "default": "/" + }, { + "mountpoint": "/cgit-data", + "origin": "file:///usr/share/cgit", + "default": "/" + }, +``` + 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 + +1) Some protocols may want "per-mount options" in name:value format. You can +provide them using "pmo" + + { + "mountpoint": "/stuff", + "origin": "callback://myprotocol", + "pmo": [{ + "myname": "myvalue" + }] + } + +2) When using a cgi:// protcol origin at a mountpoint, you may also give cgi environment variables specific to the mountpoint like this +``` + { + "mountpoint": "/git", + "origin": "cgi:///var/www/cgi-bin/cgit", + "default": "/", + "cgi-env": [{ + "CGIT_CONFIG": "/etc/cgitrc/libwebsockets.org" + }] + } +``` + This allows you to customize one cgi depending on the mountpoint (and / or vhost). + +3) It's also possible to set the cgi timeout (in secs) per cgi:// mount, like this +``` + "cgi-timeout": "30" +``` +4) `callback://` protocol may be used when defining a mount to associate a +named protocol callback with the URL namespace area. For example +``` + { + "mountpoint": "/formtest", + "origin": "callback://protocol-post-demo" + } +``` +All handling of client access to /formtest[anything] will be passed to the +callback registered to the protocol "protocol-post-demo". + +This is useful for handling POST http body content or general non-cgi http +payload generation inside a plugin. + +See the related notes in README.coding.md + +5) Cache policy of the files in the mount can also be set. If no +options are given, the content is marked uncacheable. +``` + { + "mountpoint": "/", + "origin": "file:///var/www/mysite.com", + "cache-max-age": "60", # seconds + "cache-reuse": "1", # allow reuse at client at all + "cache-revalidate": "1", # check it with server each time + "cache-intermediaries": "1" # allow intermediary caches to hold + } +``` + +6) You can also define a list of additional mimetypes per-mount +``` + "extra-mimetypes": { + ".zip": "application/zip", + ".doc": "text/evil" + } +``` + +Normally a file suffix MUST match one of the canned mimetypes or one of the extra +mimetypes, or the file is not served. This adds a little bit of security because +even if there is a bug somewhere and the mount dirs are circumvented, lws will not +serve, eg, /etc/passwd. + +If you provide an extra mimetype entry + + "*": "" + +Then any file is served, if the mimetype was not known then it is served without a +Content-Type: header. + +7) A mount can be protected by HTTP Basic Auth. This only makes sense when using +https, since otherwise the password can be sniffed. + +You can add a `basic-auth` entry on a mount like this + +``` +{ + "mountpoint": "/basic-auth", + "origin": "file://_lws_ddir_/libwebsockets-test-server/private", + "basic-auth": "/var/www/balogins-private" +} +``` + +Before serving anything, lws will signal to the browser that a username / password +combination is required, and it will pop up a dialog. When the user has filled it +in, lwsws checks the user:password string against the text file named in the `basic-auth` +entry. + +The file should contain user:pass one per line + +``` +testuser:testpass +myuser:hispass +``` + +The file should be readable by lwsws, and for a little bit of extra security not +have a file suffix, so lws would reject to serve it even if it could find it on +a mount. + + +@section lwswspl Lwsws Plugins + +Protcols and extensions may also be provided from "plugins", these are +lightweight dynamic libraries. They are scanned for at init time, and +any protocols and extensions found are added to the list given at context +creation time. + +Protocols receive init (LWS_CALLBACK_PROTOCOL_INIT) and destruction +(LWS_CALLBACK_PROTOCOL_DESTROY) callbacks per-vhost, and there are arrangements +they can make per-vhost allocations and get hold of the correct pointer from +the wsi at the callback. + +This allows a protocol to choose to strictly segregate data on a per-vhost +basis, and also allows the plugin to handle its own initialization and +context storage. + +To help that happen conveniently, there are some new apis + + - lws_vhost_get(wsi) + - lws_protocol_get(wsi) + - lws_callback_on_writable_all_protocol_vhost(vhost, protocol) + - lws_protocol_vh_priv_zalloc(vhost, protocol, size) + - lws_protocol_vh_priv_get(vhost, protocol) + +dumb increment, mirror and status protocol plugins are provided as examples. + + +@section lwswsplaplp Additional plugin search paths + +Packages that have their own lws plugins can install them in their own +preferred dir and ask lwsws to scan there by using a config fragment +like this, in its own conf.d/ file managed by the other package +``` + { + "global": { + "plugin-dir": "/usr/local/share/coherent-timeline/plugins" + } + } +``` + +@section lwswsssp lws-server-status plugin + +One provided protocol can be used to monitor the server status. + +Enable the protocol like this on a vhost's ws-protocols section +``` + "lws-server-status": { + "status": "ok", + "update-ms": "5000" + } +``` +`"update-ms"` is used to control how often updated JSON is sent on a ws link. + +And map the provided HTML into the vhost in the mounts section +``` + { + "mountpoint": "/server-status", + "origin": "file:///usr/local/share/libwebsockets-test-server/server-status", + "default": "server-status.html" + } +``` +You might choose to put it on its own vhost which has "interface": "lo", so it's not +externally visible, or use the Basic Auth support to require authentication to +access it. + +`"hide-vhosts": "{0 | 1}"` lets you control if information about your vhosts is included. +Since this includes mounts, you might not want to leak that information, mount names, +etc. + +`"filespath":"{path}"` lets you give a server filepath which is read and sent to the browser +on each refresh. For example, you can provide server temperature information on most +Linux systems by giving an appropriate path down /sys. + +This may be given multiple times. + + +@section lwswsreload Lwsws Configuration Reload + +You may send lwsws a `HUP` signal, by, eg + +``` +$ sudo killall -HUP lwsws +``` + +This causes lwsws to "deprecate" the existing lwsws process, and remove and close all of +its listen sockets, but otherwise allowing it to continue to run, until all +of its open connections close. + +When a deprecated lwsws process has no open connections left, it is destroyed +automatically. + +After sending the SIGHUP to the main lwsws process, a new lwsws process, which can +pick up the newly-available listen sockets, and use the current configuration +files, is automatically started. + +The new configuration may differ from the original one in arbitrary ways, the new +context is created from scratch each time without reference to the original one. + +Notes + +1) Protocols that provide a "shared world" like mirror will have as many "worlds" +as there are lwsws processes still active. People connected to a deprecated lwsws +process remain connected to the existing peers. + +But any new connections will apply to the new lwsws process, which does not share +per-vhost "shared world" data with the deprecated process. That means no new +connections on the deprecated context, ie a "shrinking world" for those guys, and a +"growing world" for people who connect after the SIGHUP. + +2) The new lwsws process owes nothing to the previous one. It starts with fresh +plugins, fresh configuration, fresh root privileges if that how you start it. + +The plugins may have been updated in arbitrary ways including struct size changes +etc, and lwsws or lws may also have been updated arbitrarily. + +3) A root parent process is left up that is not able to do anything except +respond to SIGHUP or SIGTERM. Actual serving and network listening etc happens +in child processes which use the privileges set in the lwsws config files. + +@section lwswssysd Lwsws Integration with Systemd + +lwsws needs a service file like this as `/usr/lib/systemd/system/lwsws.service` +``` +[Unit] +Description=Libwebsockets Web Server +After=syslog.target + +[Service] +ExecStart=/usr/local/bin/lwsws +ExecReload=/usr/bin/killall -s SIGHUP lwsws ; sleep 1 ; /usr/local/bin/lwsws +StandardError=null + +[Install] +WantedBy=multi-user.target +``` + +You can find this prepared in `./lwsws/usr-lib-systemd-system-lwsws.service` + + +@section lwswslr Lwsws Integration with logrotate + +For correct operation with logrotate, `/etc/logrotate.d/lwsws` (if that's +where we're putting the logs) should contain +``` + /var/log/lwsws/*log { + copytruncate + missingok + notifempty + delaycompress + } +``` +You can find this prepared in `/lwsws/etc-logrotate.d-lwsws` + +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= 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. + + diff --git a/READMEs/README.problems.md b/READMEs/README.problems.md new file mode 100644 index 0000000..dfd572a --- /dev/null +++ b/READMEs/README.problems.md @@ -0,0 +1,43 @@ +Debugging problems +================== + +Library is a component +---------------------- + +As a library, lws is always just a component in a bigger application. + +When users have a problem involving lws, what is happening in the bigger +application is usually critical to understand what is going on (and where the +solution lies). + +Many users are able to share their sources, but others decide not to, for +presumed "commercial advantage" or whatever. (In any event, it can be painful +looking through large chunks of someone else's sources for problems when that +is not the library author's responsibility.) + +This makes answering questions like "what is wrong with my code I am not +going to show you?" or even "what is wrong with my code?" very difficult. + +Even if it's clear there is a problem somewhere, it cannot be understood or +reproduced by anyone else if it needs user code that isn't provided. + +The biggest question is, "is this an lws problem actually"? + + +Use the test apps as sanity checks +---------------------------------- + +The test server and client are extremely useful for sanity checks and debugging +guidance. + + - test apps work on your platform, then either + - your user code is broken, align it to how the test apps work, or, + - something from your code is required to show an lws problem, provide a + minimal patch on a test app so it can be reproduced + + - test apps break on your platform, but work on, eg, x86_64, either + - toolchain or platform-specific (eg, OS) issue, or + - lws platform support issue + + - test apps break everywhere + - sounds like lws problem, info to reproduce and / or a patch is appreciated diff --git a/READMEs/README.test-apps.md b/READMEs/README.test-apps.md new file mode 100644 index 0000000..71a2d2d --- /dev/null +++ b/READMEs/README.test-apps.md @@ -0,0 +1,390 @@ +Overview of lws test apps +========================= + +Are you building a client? You just need to look at the test client +[libwebsockets-test-client](test-apps/test-client.c). + +If you are building a standalone server, there are three choices, in order of +preferability. + +1) lwsws + protocol plugins + +Lws provides a generic web server app that can be configured with JSON +config files. https://libwebsockets.org itself uses this method. + +With lwsws handling the serving part, you only need to write an lws protocol +plugin. See [plugin-standalone](plugin-standalone) for an example of how +to do that outside lws itself, using lws public apis. + + $ cmake .. -DLWS_WITH_LWSWS=1 + +See [README.lwsws.md](README.lwsws.md) for information on how to configure +lwsws. + +NOTE this method implies libuv is used by lws, to provide crossplatform +implementations of timers, dynamic lib loading etc for plugins and lwsws. + +2) test-server-v2.0.c + +This method lets you configure web serving in code, instead of using lwsws. + +Plugins are still used, which implies libuv needed. + + $ cmake .. -DLWS_WITH_PLUGINS=1 + +See [test-server-v2.0.c](test-apps/test-server-v2.0.c) + +3) protocols in the server app + +This is the original way lws implemented servers, plugins and libuv are not +required, but without plugins separating the protocol code directly, the +combined code is all squidged together and is much less maintainable. + +This method is still supported in lws but all ongoing and future work is +being done in protocol plugins only. + + +Notes about lws test apps +========================= + +@section tsb Testing server with a browser + +If you run [libwebsockets-test-server](test-apps/test-server.c) and point your browser +(eg, Chrome) to + + http://127.0.0.1:7681 + +It will fetch a script in the form of `test.html`, and then run the +script in there on the browser to open a websocket connection. +Incrementing numbers should appear in the browser display. + +By default the test server logs to both stderr and syslog, you can control +what is logged using `-d `, see later. + + +@section tsd Running test server as a Daemon + +You can use the -D option on the test server to have it fork into the +background and return immediately. In this daemonized mode all stderr is +disabled and logging goes only to syslog, eg, `/var/log/messages` or similar. + +The server maintains a lockfile at `/tmp/.lwsts-lock` that contains the pid +of the master process, and deletes this file when the master process +terminates. + +To stop the daemon, do +``` + $ kill cat /tmp/.lwsts-lock +``` +If it finds a stale lock (the pid mentioned in the file does not exist +any more) it will delete the lock and create a new one during startup. + +If the lock is valid, the daemon will exit with a note on stderr that +it was already running. + + +@section sssl Using SSL on the server side + +To test it using SSL/WSS, just run the test server with +``` + $ libwebsockets-test-server --ssl +``` +and use the URL +``` + https://127.0.0.1:7681 +``` +The connection will be entirely encrypted using some generated +certificates that your browser will not accept, since they are +not signed by any real Certificate Authority. Just accept the +certificates in the browser and the connection will proceed +in first https and then websocket wss, acting exactly the +same. + +[test-server.c](test-apps/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 + +If you run the test server as described above, you can also +connect to it using the test client as well as a browser. + +``` + $ libwebsockets-test-client localhost +``` + +will by default connect to the test server on localhost:7681 +and print the dumb increment number from the server at the +same time as drawing random circles in the mirror protocol; +if you connect to the test server using a browser at the +same time you will be able to see the circles being drawn. + +The test client supports SSL too, use + +``` + $ libwebsockets-test-client localhost --ssl -s +``` + +the -s tells it to accept the default self-signed cert from the server, +otherwise it will strictly fail the connection if there is no CA cert to +validate the server's certificate. + + +@section choosingts Choosing between test server variations + +If you will be doing standalone serving with lws, ideally you should avoid +making your own server at all, and use lwsws with your own protocol plugins. + +The second best option is follow test-server-v2.0.c, which uses a mount to +autoserve a directory, and lws protocol plugins for ws, without needing any +user callback code (other than what's needed in the protocol plugin). + +For those two options libuv is needed to support the protocol plugins, if +that's not possible then the other variations with their own protocol code +should be considered. + + +@section echo Testing simple echo + +You can test against `echo.websockets.org` as a sanity test like +this (the client connects to port `80` by default): + +``` + $ libwebsockets-test-echo --client echo.websocket.org +``` + +This echo test is of limited use though because it doesn't +negotiate any protocol. You can run the same test app as a +local server, by default on localhost:7681 +``` + $ libwebsockets-test-echo +``` +and do the echo test against the local echo server +``` + $ libwebsockets-test-echo --client localhost --port 7681 +``` +If you add the `--ssl` switch to both the client and server, you can also test +with an encrypted link. + + +@section tassl Testing SSL on the client side + +To test SSL/WSS client action, just run the client test with +``` + $ libwebsockets-test-client localhost --ssl +``` +By default the client test applet is set to accept self-signed +certificates used by the test server, this is indicated by the +`use_ssl` var being set to `2`. Set it to `1` to reject any server +certificate that it doesn't have a trusted CA cert for. + + +@section taping Using the websocket ping utility + +libwebsockets-test-ping connects as a client to a remote +websocket server and pings it like the +normal unix ping utility. +``` + $ libwebsockets-test-ping localhost + handshake OK for protocol lws-mirror-protocol + Websocket PING localhost.localdomain (127.0.0.1) 64 bytes of data. + 64 bytes from localhost: req=1 time=0.1ms + 64 bytes from localhost: req=2 time=0.1ms + 64 bytes from localhost: req=3 time=0.1ms + 64 bytes from localhost: req=4 time=0.2ms + 64 bytes from localhost: req=5 time=0.1ms + 64 bytes from localhost: req=6 time=0.2ms + 64 bytes from localhost: req=7 time=0.2ms + 64 bytes from localhost: req=8 time=0.1ms + ^C + --- localhost.localdomain websocket ping statistics --- + 8 packets transmitted, 8 received, 0% packet loss, time 7458ms + rtt min/avg/max = 0.110/0.185/0.218 ms + $ +``` +By default it sends 64 byte payload packets using the 04 +PING packet opcode type. You can change the payload size +using the `-s=` flag, up to a maximum of 125 mandated by the +04 standard. + +Using the lws-mirror protocol that is provided by the test +server, libwebsockets-test-ping can also use larger payload +sizes up to 4096 is BINARY packets; lws-mirror will copy +them back to the client and they appear as a PONG. Use the +`-m` flag to select this operation. + +The default interval between pings is 1s, you can use the -i= +flag to set this, including fractions like `-i=0.01` for 10ms +interval. + +Before you can even use the PING opcode that is part of the +standard, you must complete a handshake with a specified +protocol. By default lws-mirror-protocol is used which is +supported by the test server. But if you are using it on +another server, you can specify the protocol to handshake with +by `--protocol=protocolname` + + +@section ta fraggle Fraggle test app + +By default it runs in server mode +``` + $ libwebsockets-test-fraggle + libwebsockets test fraggle + (C) Copyright 2010-2011 Andy Green licensed under LGPL2.1 + Compiled with SSL support, not using it + Listening on port 7681 + server sees client connect + accepted v06 connection + Spamming 360 random fragments + Spamming session over, len = 371913. sum = 0x2D3C0AE + Spamming 895 random fragments + Spamming session over, len = 875970. sum = 0x6A74DA1 + ... +``` +You need to run a second session in client mode, you have to +give the `-c` switch and the server address at least: +``` + $ libwebsockets-test-fraggle -c localhost + libwebsockets test fraggle + (C) Copyright 2010-2011 Andy Green licensed under LGPL2.1 + Client mode + Connecting to localhost:7681 + denied deflate-stream extension + handshake OK for protocol fraggle-protocol + client connects to server + EOM received 371913 correctly from 360 fragments + EOM received 875970 correctly from 895 fragments + EOM received 247140 correctly from 258 fragments + EOM received 695451 correctly from 692 fragments + ... +``` +The fraggle test sends a random number up to 1024 fragmented websocket frames +each of a random size between 1 and 2001 bytes in a single message, then sends +a checksum and starts sending a new randomly sized and fragmented message. + +The fraggle test client receives the same message fragments and computes the +same checksum using websocket framing to see when the message has ended. It +then accepts the server checksum message and compares that to its checksum. + + +@section taproxy proxy support + +The http_proxy environment variable is respected by the client +connection code for both `ws://` and `wss://`. It doesn't support +authentication. + +You use it like this +``` + $ export http_proxy=myproxy.com:3128 + $ libwebsockets-test-client someserver.com +``` + +@section talog debug logging + +By default logging of severity "notice", "warn" or "err" is enabled to stderr. + +Again by default other logging is compiled in but disabled from printing. + +By default debug logs below "notice" in severity are not compiled in. To get +them included, add this option in CMAKE + +``` + $ cmake .. -DCMAKE_BUILD_TYPE=DEBUG +``` + +If you want to see more detailed debug logs, you can control a bitfield to +select which logs types may print using the `lws_set_log_level()` api, in the +test apps you can use `-d ` to control this. The types of logging +available are (OR together the numbers to select multiple) + + - 1 ERR + - 2 WARN + - 4 NOTICE + - 8 INFO + - 16 DEBUG + - 32 PARSER + - 64 HEADER + - 128 EXTENSION + - 256 CLIENT + - 512 LATENCY + + +@section ws13 Websocket version supported + +The final IETF standard is supported for both client and server, protocol +version 13. + + +@section latency Latency Tracking + +Since libwebsockets runs using `poll()` and a single threaded approach, any +unexpected latency coming from system calls would be bad news. There's now +a latency tracking scheme that can be built in with `--with-latency` at +configure-time, logging the time taken for system calls to complete and if +the whole action did complete that time or was deferred. + +You can see the detailed data by enabling logging level 512 (eg, `-d 519` on +the test server to see that and the usual logs), however even without that +the "worst" latency is kept and reported to the logs with NOTICE severity +when the context is destroyed. + +Some care is needed interpreting them, if the action completed the first figure +(in us) is the time taken for the whole action, which may have retried through +the poll loop many times and will depend on network roundtrip times. High +figures here don't indicate a problem. The figure in us reported after "lat" +in the logging is the time taken by this particular attempt. High figures +here may indicate a problem, or if you system is loaded with another app at +that time, such as the browser, it may simply indicate the OS gave preferential +treatment to the other app during that call. + + +@section autobahn Autobahn Test Suite + +Lws can be tested against the autobahn websocket fuzzer. + +1) pip install autobahntestsuite + +2) wstest -m fuzzingserver + +3) Run tests like this + +libwebsockets-test-echo --client localhost --port 9001 -u "/runCase?case=20&agent=libwebsockets" -v -d 65535 -n 1 + +(this runs test 20) + +4) In a browser, go here + +http://localhost:8080/test_browser.html + +fill in "libwebsockets" in "User Agent Identifier" and press "Update Reports (Manual)" + +5) In a browser go to the directory you ran wstest in (eg, /projects/libwebsockets) + +file:///projects/libwebsockets/reports/clients/index.html + +to see the results + + +@section autobahnnotes Autobahn Test Notes + +1) Autobahn tests the user code + lws implementation. So to get the same +results, you need to follow test-echo.c in terms of user implementation. + +2) Two of the tests make no sense for Libwebsockets to support and we fail them. + + - Tests 2.10 + 2.11: sends multiple pings on one connection. Lws policy is to +only allow one active ping in flight on each connection, the rest are dropped. +The autobahn test itself admits this is not part of the standard, just someone's +random opinion about how they think a ws server should act. So we will fail +this by design and it is no problem about RFC6455 compliance. + + + diff --git a/READMEs/mainpage.md b/READMEs/mainpage.md new file mode 100644 index 0000000..9a427b3 --- /dev/null +++ b/READMEs/mainpage.md @@ -0,0 +1,16 @@ +##Libwebsockets API introduction + +Libwebsockets covers a lot of interesting features for people making embedded servers or clients + + - http(s) serving and client operation + - ws(s) serving and client operation + - http(s) apis for file transfer and upload + - http POST form handling (including multipart) + - cookie-based sessions + - account management (including registration, email verification, lost pw etc) + - strong ssl PFS support (A+ on SSLlabs test) + +You can browse by api category here + +A collection of READMEs for build, coding, lwsws etc are here + diff --git a/READMEs/release-checklist b/READMEs/release-checklist new file mode 100644 index 0000000..2402a7b --- /dev/null +++ b/READMEs/release-checklist @@ -0,0 +1,97 @@ +Release Checklist +----------------- + +0) QA + + a) ab + + $ ab -n 100000 -c 200 http://localhost:7681/ + + b) coverity + + $ ../make-coverity-tarball.sh + https://scan.coverity.com/projects/warmcat-libwebsockets + + c) test servers + client + browser + + d) valgrind test servers + client + browser + + e) attack.sh + + $ ./test-apps/attack.sh + + f) Autobahn + + $ wstest -m fuzzingserver & + $ ./scripts/autobahn-test.sh + + Force update by browser using agent "libwebsockets" + http://localhost:8080/test_browser.html + + rsync -av ./reports/* root@warmcat.com:/var/www/libwebsockets.org + +1) api + + $ cp build/doc/* . + +2) soname bump? + + a) We need one if we added / changed / removed apis + + CMakeLists.txt + + set(SOVERSION "6") + + scripts/libwebsockets.spec + + -/%{_libdir}/libwebsockets.so.6 + +/%{_libdir}/libwebsockets.so.7 + +3) changelog + + a) Add next version tag header. + + b) Classify as + + - MINOR bug fixes + - MAJOR bug fixes + - SECURITY fixes + +4) main version bump + + CMakeLists.txt + + set(CPACK_PACKAGE_VERSION_MAJOR "1") + set(CPACK_PACKAGE_VERSION_MINOR "6") + set(CPACK_PACKAGE_VERSION_PATCH "0") + +5) specfile + + a) rpm version bump to match CMake one + + scripts/libwebsockets.spec + + Version: 1.6.0 + + b) Summarize changelog + + scripts/libwebsockets.spec + +%changelog +* Sun Jan 17 2016 Andrew Cooks 1.6.4-1 +- Bump version to 1.6.4 +- MINOR fix xyz + +6) signed tag + + git tag -s vX.Y[.Z] + +7) git + + a) push + + b) final CI check, if fail delete tag, kill pushed tags, restart flow + +8) website + + a) update latest tag for release branch diff --git a/appveyor.yml b/appveyor.yml index 748ab1d..f862151 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -21,9 +21,6 @@ install: - mkdir c:\assets - 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/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 @@ -38,21 +35,13 @@ build_script: - cmake -DCMAKE_BUILD_TYPE=Release %CMAKE_ARGS% .. - cmake --build . --config Release -# TODO: Keeps breaking Windows build, should be rewritten using CPack properly instead... after_build: - 7z a lws.zip %APPVEYOR_BUILD_FOLDER%\build\lib\Release\websockets.lib %APPVEYOR_BUILD_FOLDER%\build\lib\Release\websockets.exp %APPVEYOR_BUILD_FOLDER%\build\bin\Release\websockets.dll %APPVEYOR_BUILD_FOLDER%\lib\libwebsockets.h %APPVEYOR_BUILD_FOLDER%\build\lws_config.h %APPVEYOR_BUILD_FOLDER%\build\bin\Release\*.exe -# - cd .. -# - cd win32port -# - makensis -DVERSION=%APPVEYOR_BUILD_VERSION% libwebsockets.nsi - artifacts: - path: lws.zip name: lws.zip type: Zip - #cache: - # - C:\OpenSSL-Win32 - matrix: fast_finish: true diff --git a/autobahn-test.sh b/autobahn-test.sh deleted file mode 100755 index 91b9171..0000000 --- a/autobahn-test.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh - -set -u - -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 & - - C=99 - while [ $C -gt 8 ] ; do - if [ $OS=SunOS ] ; then - C=`ps -ef | grep libwebsockets-test-echo | wc -l` - else - C=`ps fax | grep libwebsockets-test-echo | wc -l` - fi - if [ $C -gt 8 ] ; then - sleep 1s - fi - done - - N=$(( $N + 1 )) -done - -echo "waiting for forks to complete..." - -while [ 1 ] ; do - if [ $OS=SunOS ] ; then - n=`ps -ef | grep libwebsocket | grep -v grep | wc -l` - else - n=`ps fax | grep libwebsocket | grep -v grep | wc -l` - fi - echo "$n forks running..." - if [ $n -eq 0 ] ; then - echo "Completed" - exit 0 - fi - sleep 1s -done - diff --git a/cmake/FindLibWebSockets.cmake b/cmake/FindLibWebSockets.cmake new file mode 100644 index 0000000..1dfe115 --- /dev/null +++ b/cmake/FindLibWebSockets.cmake @@ -0,0 +1,33 @@ +# This module tries to find libWebsockets library and include files +# +# LIBWEBSOCKETS_INCLUDE_DIR, path where to find libwebsockets.h +# LIBWEBSOCKETS_LIBRARY_DIR, path where to find libwebsockets.so +# LIBWEBSOCKETS_LIBRARIES, the library to link against +# LIBWEBSOCKETS_FOUND, If false, do not try to use libWebSockets +# +# This currently works probably only for Linux + +FIND_PATH ( LIBWEBSOCKETS_INCLUDE_DIR libwebsockets.h + /usr/local/include + /usr/include +) + +FIND_LIBRARY ( LIBWEBSOCKETS_LIBRARIES websockets + /usr/local/lib + /usr/lib +) + +GET_FILENAME_COMPONENT( LIBWEBSOCKETS_LIBRARY_DIR ${LIBWEBSOCKETS_LIBRARIES} PATH ) + +SET ( LIBWEBSOCKETS_FOUND "NO" ) +IF ( LIBWEBSOCKETS_INCLUDE_DIR ) + IF ( LIBWEBSOCKETS_LIBRARIES ) + SET ( LIBWEBSOCKETS_FOUND "YES" ) + ENDIF ( LIBWEBSOCKETS_LIBRARIES ) +ENDIF ( LIBWEBSOCKETS_INCLUDE_DIR ) + +MARK_AS_ADVANCED( + LIBWEBSOCKETS_LIBRARY_DIR + LIBWEBSOCKETS_INCLUDE_DIR + LIBWEBSOCKETS_LIBRARIES +) \ No newline at end of file diff --git a/cmake/lws_config.h.in b/cmake/lws_config.h.in new file mode 100644 index 0000000..3f2488a --- /dev/null +++ b/cmake/lws_config.h.in @@ -0,0 +1,155 @@ +/* lws_config.h Generated from lws_config.h.in */ + +#ifndef NDEBUG + #ifndef _DEBUG + #define _DEBUG + #endif +#endif + +#define LWS_INSTALL_DATADIR "${CMAKE_INSTALL_PREFIX}/share" + +/* Define to 1 to use wolfSSL/CyaSSL as a replacement for OpenSSL. + * LWS_OPENSSL_SUPPORT needs to be set also for this to work. */ +#cmakedefine USE_WOLFSSL + +/* Also define to 1 (in addition to USE_WOLFSSL) when using the + (older) CyaSSL library */ +#cmakedefine USE_OLD_CYASSL +#cmakedefine LWS_USE_BORINGSSL + +#cmakedefine LWS_USE_MBEDTLS +#cmakedefine LWS_USE_POLARSSL +#cmakedefine LWS_WITH_ESP8266 +#cmakedefine LWS_WITH_ESP32 + +#cmakedefine LWS_WITH_PLUGINS +#cmakedefine LWS_WITH_NO_LOGS + +/* The Libwebsocket version */ +#cmakedefine LWS_LIBRARY_VERSION "${LWS_LIBRARY_VERSION}" + +#define LWS_LIBRARY_VERSION_MAJOR ${LWS_LIBRARY_VERSION_MAJOR} +#define LWS_LIBRARY_VERSION_MINOR ${LWS_LIBRARY_VERSION_MINOR} +#define LWS_LIBRARY_VERSION_PATCH ${LWS_LIBRARY_VERSION_PATCH} +/* LWS_LIBRARY_VERSION_NUMBER looks like 1005001 for e.g. version 1.5.1 */ +#define LWS_LIBRARY_VERSION_NUMBER (LWS_LIBRARY_VERSION_MAJOR*1000000)+(LWS_LIBRARY_VERSION_MINOR*1000)+LWS_LIBRARY_VERSION_PATCH + +/* The current git commit hash that we're building from */ +#cmakedefine LWS_BUILD_HASH "${LWS_BUILD_HASH}" + +/* Build with OpenSSL support */ +#cmakedefine LWS_OPENSSL_SUPPORT + +/* The client should load and trust CA root certs it finds in the OS */ +#cmakedefine LWS_SSL_CLIENT_USE_OS_CA_CERTS + +/* Sets the path where the client certs should be installed. */ +#cmakedefine LWS_OPENSSL_CLIENT_CERTS "${LWS_OPENSSL_CLIENT_CERTS}" + +/* Turn off websocket extensions */ +#cmakedefine LWS_NO_EXTENSIONS + +/* Enable libev io loop */ +#cmakedefine LWS_USE_LIBEV + +/* 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 + +/* Build with support for UNIX domain socket */ +#cmakedefine LWS_USE_UNIX_SOCK + +/* Build with support for HTTP2 */ +#cmakedefine LWS_USE_HTTP2 + +/* Turn on latency measuring code */ +#cmakedefine LWS_LATENCY + +/* Don't build the daemonizeation api */ +#cmakedefine LWS_NO_DAEMONIZE + +/* Build without server support */ +#cmakedefine LWS_NO_SERVER + +/* Build without client support */ +#cmakedefine LWS_NO_CLIENT + +/* If we should compile with MinGW support */ +#cmakedefine LWS_MINGW_SUPPORT + +/* Use the BSD getifaddrs that comes with libwebsocket, for uclibc support */ +#cmakedefine LWS_BUILTIN_GETIFADDRS + +/* use SHA1() not internal libwebsockets_SHA1 */ +#cmakedefine LWS_SHA1_USE_OPENSSL_NAME + +/* SSL server using ECDH certificate */ +#cmakedefine LWS_SSL_SERVER_WITH_ECDH_CERT +#cmakedefine LWS_HAVE_SSL_CTX_set1_param +#cmakedefine LWS_HAVE_X509_VERIFY_PARAM_set1_host + +#cmakedefine LWS_HAVE_UV_VERSION_H + +/* CGI apis */ +#cmakedefine LWS_WITH_CGI + +/* whether the Openssl is recent enough, and / or built with, ecdh */ +#cmakedefine LWS_HAVE_OPENSSL_ECDH_H + +/* HTTP Proxy support */ +#cmakedefine LWS_WITH_HTTP_PROXY + +/* HTTP Ranges support */ +#cmakedefine LWS_WITH_RANGES + +/* Http access log support */ +#cmakedefine LWS_WITH_ACCESS_LOG +#cmakedefine LWS_WITH_SERVER_STATUS + +#cmakedefine LWS_WITH_STATEFUL_URLDECODE +#cmakedefine LWS_WITH_PEER_LIMITS + +/* Maximum supported service threads */ +#define LWS_MAX_SMP ${LWS_MAX_SMP} + +/* Lightweight JSON Parser */ +#cmakedefine LWS_WITH_LEJP + +/* SMTP */ +#cmakedefine LWS_WITH_SMTP + +/* OPTEE */ +#cmakedefine LWS_PLAT_OPTEE + +/* ZIP FOPS */ +#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} diff --git a/cmake/lws_config_private.h.in b/cmake/lws_config_private.h.in new file mode 100644 index 0000000..8ad39a2 --- /dev/null +++ b/cmake/lws_config_private.h.in @@ -0,0 +1,126 @@ +/* lws_config_private.h.in. Private compilation options. */ + +#ifndef NDEBUG + #ifndef _DEBUG + #define _DEBUG + #endif +#endif + +/* Define to 1 to use CyaSSL as a replacement for OpenSSL. + * LWS_OPENSSL_SUPPORT needs to be set also for this to work. */ +#cmakedefine USE_CYASSL + +/* Define to 1 if you have the `bzero' function. */ +#cmakedefine LWS_HAVE_BZERO + +/* Define to 1 if you have the header file. */ +#cmakedefine LWS_HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#cmakedefine LWS_HAVE_FCNTL_H + +/* Define to 1 if you have the `fork' function. */ +#cmakedefine LWS_HAVE_FORK + +/* Define to 1 if you have the `getenv’ function. */ +#cmakedefine LWS_HAVE_GETENV + +/* Define to 1 if you have the header file. */ +#cmakedefine LWS_HAVE_IN6ADDR_H + +/* Define to 1 if you have the header file. */ +#cmakedefine LWS_HAVE_INTTYPES_H + +/* Define to 1 if you have the `ssl' library (-lssl). */ +//#cmakedefine LWS_HAVE_LIBSSL + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#cmakedefine LWS_HAVE_MALLOC + +/* Define to 1 if you have the header file. */ +#cmakedefine LWS_HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#cmakedefine LWS_HAVE_MEMSET + +/* Define to 1 if you have the header file. */ +#cmakedefine LWS_HAVE_NETINET_IN_H + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#cmakedefine LWS_HAVE_REALLOC + +/* Define to 1 if you have the `socket' function. */ +#cmakedefine LWS_HAVE_SOCKET + +/* Define to 1 if you have the header file. */ +#cmakedefine LWS_HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#cmakedefine LWS_HAVE_STDLIB_H + +/* Define to 1 if you have the `strerror' function. */ +#cmakedefine LWS_HAVE_STRERROR + +/* Define to 1 if you have the header file. */ +#cmakedefine LWS_HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#cmakedefine LWS_HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#cmakedefine LWS_HAVE_SYS_PRCTL_H + +/* Define to 1 if you have the header file. */ +#cmakedefine LWS_HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#cmakedefine LWS_HAVE_SYS_SOCKIO_H + +/* Define to 1 if you have the header file. */ +#cmakedefine LWS_HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#cmakedefine LWS_HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#cmakedefine LWS_HAVE_UNISTD_H + +/* Define to 1 if you have the `vfork' function. */ +#cmakedefine LWS_HAVE_VFORK + +/* Define to 1 if you have the header file. */ +#cmakedefine LWS_HAVE_VFORK_H + +/* Define to 1 if `fork' works. */ +#cmakedefine LWS_HAVE_WORKING_FORK + +/* Define to 1 if `vfork' works. */ +#cmakedefine LWS_HAVE_WORKING_VFORK + +/* Define to 1 if execvpe() exists */ +#cmakedefine LWS_HAVE_EXECVPE + +/* Define to 1 if you have the header file. */ +#cmakedefine LWS_HAVE_ZLIB_H + +#cmakedefine LWS_HAVE_GETLOADAVG + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR // We're not using libtool + +/* Define to rpl_malloc if the replacement function should be used. */ +#cmakedefine malloc + +/* Define to rpl_realloc if the replacement function should be used. */ +#cmakedefine realloc + +/* Define to 1 if we have getifaddrs */ +#cmakedefine LWS_HAVE_GETIFADDRS + +/* Define if the inline keyword doesn't exist. */ +#cmakedefine inline ${inline} + + diff --git a/component.mk b/component.mk index 7f47241..b1b8a9c 100644 --- a/component.mk +++ b/component.mk @@ -1,5 +1,5 @@ COMPONENT_DEPENDS:=mbedtls openssl -COMPONENT_ADD_INCLUDEDIRS := ../../../../../../../../../../../../../../../../../../$(COMPONENT_BUILD_DIR)/include +COMPONENT_ADD_INCLUDEDIRS := ../../../../../../../../../../../../../../../../../../../../$(COMPONENT_BUILD_DIR)/include COMPONENT_OWNBUILDTARGET:= 1 @@ -23,7 +23,7 @@ build: -DIDF_PATH=$(IDF_PATH) \ -DCROSS_PATH=$(CROSS_PATH) \ -DBUILD_DIR_BASE=$(BUILD_DIR_BASE) \ - -DCMAKE_TOOLCHAIN_FILE=$(COMPONENT_PATH)/cross-esp32.cmake \ + -DCMAKE_TOOLCHAIN_FILE=$(COMPONENT_PATH)/contrib/cross-esp32.cmake \ -DCMAKE_BUILD_TYPE=RELEASE \ -DLWS_MBEDTLS_INCLUDE_DIRS="${IDF_PATH}/components/openssl/include;${IDF_PATH}/components/mbedtls/include;${IDF_PATH}/components/mbedtls/port/include" \ -DLWS_WITH_STATS=0 \ diff --git a/contrib/Android.mk b/contrib/Android.mk new file mode 100644 index 0000000..20b2e10 --- /dev/null +++ b/contrib/Android.mk @@ -0,0 +1,29 @@ +# example Android Native Library makefile +# contributed by Gregory Junker + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := libwebsockets +LOCAL_CFLAGS := -DLWS_BUILTIN_GETIFADDRS +LWS_LIB_PATH := ../../../shared/libwebsockets/lib +LOCAL_C_INCLUDES:= $(LOCAL_PATH)/$(LWS_LIB_PATH) +LOCAL_SRC_FILES := \ + $(LWS_LIB_PATH)/base64-decode.c \ + $(LWS_LIB_PATH)/client.c \ + $(LWS_LIB_PATH)/client-handshake.c \ + $(LWS_LIB_PATH)/client-parser.c \ + $(LWS_LIB_PATH)/daemonize.c \ + $(LWS_LIB_PATH)/extension.c \ + $(LWS_LIB_PATH)/extension-deflate-frame.c \ + $(LWS_LIB_PATH)/extension-deflate-stream.c \ + $(LWS_LIB_PATH)/getifaddrs.c \ + $(LWS_LIB_PATH)/handshake.c \ + $(LWS_LIB_PATH)/libwebsockets.c \ + $(LWS_LIB_PATH)/md5.c \ + $(LWS_LIB_PATH)/output.c \ + $(LWS_LIB_PATH)/parsers.c \ + $(LWS_LIB_PATH)/sha-1.c + +include $(BUILD_STATIC_LIBRARY) diff --git a/contrib/cross-aarch64.cmake b/contrib/cross-aarch64.cmake new file mode 100644 index 0000000..d85a641 --- /dev/null +++ b/contrib/cross-aarch64.cmake @@ -0,0 +1,32 @@ +# +# CMake Toolchain file for crosscompiling on ARM. +# +# This can be used when running cmake in the following way: +# cd build/ +# cmake .. -DCMAKE_TOOLCHAIN_FILE=../cross-arm-linux-gnueabihf.cmake +# + +# Target operating system name. +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR aarch64) + +# Name of C compiler. +set(CMAKE_C_COMPILER "aarch64-linux-gnu-gcc") +set(CMAKE_CXX_COMPILER "aarch64-linux-gnu-g++") + +#-nostdlib +SET(CMAKE_C_FLAGS "-DGCC_VER=\"\\\"$(GCC_VER)\\\"\" -DARM64=1 -D__LP64__=1 -Os -g3 -fpie -mstrict-align -DOPTEE_DEV_KIT=../../../optee_os/out/arm-plat-hikey/export-ta_arm64/include -fPIC -ffunction-sections -fdata-sections" CACHE STRING "" FORCE) + + +# Where to look for the target environment. (More paths can be added here) +set(CMAKE_FIND_ROOT_PATH "/projects/aist-tb/arm64-tc/") + +# Adjust the default behavior of the FIND_XXX() commands: +# search programs in the host environment only. +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + +# Search headers and libraries in the target environment only. +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + + diff --git a/contrib/cross-arm-linux-gnueabihf.cmake b/contrib/cross-arm-linux-gnueabihf.cmake new file mode 100644 index 0000000..12cf3e9 --- /dev/null +++ b/contrib/cross-arm-linux-gnueabihf.cmake @@ -0,0 +1,28 @@ +# +# CMake Toolchain file for crosscompiling on ARM. +# +# This can be used when running cmake in the following way: +# cd build/ +# cmake .. -DCMAKE_TOOLCHAIN_FILE=../cross-arm-linux-gnueabihf.cmake +# + +set(CROSS_PATH /opt/gcc-linaro-arm-linux-gnueabihf-4.7-2013.02-01-20130221_linux) + +# Target operating system name. +set(CMAKE_SYSTEM_NAME Linux) + +# Name of C compiler. +set(CMAKE_C_COMPILER "${CROSS_PATH}/bin/arm-linux-gnueabihf-gcc") +set(CMAKE_CXX_COMPILER "${CROSS_PATH}/bin/arm-linux-gnueabihf-g++") + +# Where to look for the target environment. (More paths can be added here) +set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}") + +# Adjust the default behavior of the FIND_XXX() commands: +# search programs in the host environment only. +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + +# Search headers and libraries in the target environment only. +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + diff --git a/contrib/cross-esp32.cmake b/contrib/cross-esp32.cmake new file mode 100644 index 0000000..f978e80 --- /dev/null +++ b/contrib/cross-esp32.cmake @@ -0,0 +1,46 @@ +# +# CMake Toolchain file for crosscompiling on ARM. +# +# This can be used when running cmake in the following way: +# cd build/ +# cmake .. -DCMAKE_TOOLCHAIN_FILE=../cross-arm-linux-gnueabihf.cmake +# + +# Target operating system name. +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_FLAGS "-nostdlib -Wall -Werror \ + -I${BUILD_DIR_BASE}/include \ + -I${IDF_PATH}/components/mdns/include \ + -I${IDF_PATH}/components/driver/include \ + -I${IDF_PATH}/components/spi_flash/include \ + -I${IDF_PATH}/components/nvs_flash/include \ + -I${IDF_PATH}/components/tcpip_adapter/include \ + -I${IDF_PATH}/components/lwip/include/lwip/posix \ + -I${IDF_PATH}/components/lwip/include/lwip \ + -I${IDF_PATH}/components/lwip/include/lwip/port \ + -I${IDF_PATH}/components/esp32/include/ \ + -I${IDF_PATH}/components/bootloader_support/include/ \ + -I${IDF_PATH}/components/app_update/include/ \ + -I$(IDF_PATH)/components/soc/esp32/include/ \ + ${LWS_C_FLAGS} -Os \ + -I${IDF_PATH}/components/nvs_flash/test_nvs_host \ + -I${IDF_PATH}/components/freertos/include" CACHE STRING "" FORCE) + +# Where to look for the target environment. (More paths can be added here) +set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}") + +# Adjust the default behavior of the FIND_XXX() commands: +# search programs in the host environment only. +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + +# Search headers and libraries in the target environment only. +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + diff --git a/contrib/cross-ming.cmake b/contrib/cross-ming.cmake new file mode 100644 index 0000000..94989f2 --- /dev/null +++ b/contrib/cross-ming.cmake @@ -0,0 +1,31 @@ +# +# CMake Toolchain file for crosscompiling on MingW. +# +# This can be used when running cmake in the following way: +# cd build/ +# cmake .. -DCMAKE_TOOLCHAIN_FILE=../cross-ming.cmake +# + +set(CROSS_PATH /usr/bin) + +# Target operating system name. +set(CMAKE_SYSTEM_NAME Windows) +set(BUILD_SHARED_LIBS OFF) + +# Name of C compiler. +set(CMAKE_C_COMPILER "${CROSS_PATH}/x86_64-w64-mingw32-gcc") +#set(CMAKE_CXX_COMPILER "${CROSS_PATH}/x86_64-w64-mingw32-g++") +set(CMAKE_RC_COMPILER "${CROSS_PATH}/x86_64-w64-mingw32-windres") +set(CMAKE_C_FLAGS "-Wno-error") + +# Where to look for the target environment. (More paths can be added here) +set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}") + +# Adjust the default behavior of the FIND_XXX() commands: +# search programs in the host environment only. +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + +# Search headers and libraries in the target environment only. +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + diff --git a/contrib/cross-openwrt-makefile b/contrib/cross-openwrt-makefile new file mode 100644 index 0000000..2504370 --- /dev/null +++ b/contrib/cross-openwrt-makefile @@ -0,0 +1,97 @@ +# +# libwebsockets makefile for openwrt +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=libwebsockets +PKG_VERSION:=2014-03-01 +PKG_RELEASE=$(PKG_SOURCE_VERSION) + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://github.com/warmcat/libwebsockets.git +PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) +PKG_SOURCE_VERSION:=388dc7d201d8d123841869fb49ec4d94d6dd7f54 +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz +CMAKE_INSTALL:=1 + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/cmake.mk + +CMAKE_OPTIONS += -DLWS_OPENSSL_CLIENT_CERTS=/etc/ssl/certs +CMAKE_OPTIONS += -DLWS_OPENSSL_SUPPORT=ON +CMAKE_OPTIONS += -DLWS_WITH_SSL=ON +CMAKE_OPTIONS += -DLWS_WITHOUT_TESTAPPS=$(if $(CONFIG_PACKAGE_libwebsockets-examples),"OFF","ON") + +# for wolfssl, define these in addition to LWS_OPENSSL_SUPPORT and +# edit package/libs/wolfssl/Makefile to include --enable-opensslextra +# CMAKE_OPTIONS += -DLWS_USE_WOLFSSL=ON +# CMAKE_OPTIONS += -DLWS_WOLFSSL_LIBRARIES=$(STAGING_DIR)/usr/lib/libwolfssl.so +# CMAKE_OPTIONS += -DLWS_WOLFSSL_INCLUDE_DIRS=$(STAGING_DIR)/usr/include + +# for cyassl, define these in addition to LWS_OPENSSL_SUPPORT and +# edit package/libs/wolfssl/Makefile to include --enable-opensslextra +# CMAKE_OPTIONS += -DLWS_USE_CYASSL=ON +# CMAKE_OPTIONS += -DLWS_CYASSL_LIBRARIES=$(STAGING_DIR)/usr/lib/libcyassl.so +# CMAKE_OPTIONS += -DLWS_CYASSL_INCLUDE_DIRS=$(STAGING_DIR)/usr/include + +# other options worth noting +# CMAKE_OPTIONS += -DLWS_WITHOUT_EXTENSIONS=ON +# CMAKE_OPTIONS += -DLWS_WITHOUT_DAEMONIZE=ON +# CMAKE_OPTIONS += -DLWS_WITHOUT_SERVER=ON +# CMAKE_OPTIONS += -DLWS_WITHOUT_DEBUG=ON + + +define Package/libwebsockets/Default + SECTION:=libs + CATEGORY:=Libraries + TITLE:=libwebsockets + DEPENDS:=+zlib +libopenssl +endef + +define Package/libwebsockets + $(call Package/libwebsockets/Default) + TITLE+= (libraries) +endef + +define Package/libwebsockets/description + libwebsockets + This package contains libwebsocket libraries +endef + +define Package/libwebsockets-examples + $(call Package/libwebsockets/Default) + DEPENDS:=libwebsockets + TITLE+= (examples) +endef + +define Package/libwebsockets-examples/description + libwebsockets examples + This package contains libwebsockets examples +endef + +define Package/libwebsockets/install + $(INSTALL_DIR) $(1)/usr/lib + $(CP) $(PKG_INSTALL_DIR)/usr/lib/libwebsockets.so* $(1)/usr/lib/ +endef + +define Package/libwebsockets-examples/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-client $(1)/usr/bin/ + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-echo $(1)/usr/bin/ + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-fraggle $(1)/usr/bin/ + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-ping $(1)/usr/bin/ + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-server $(1)/usr/bin/ + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-server-extpoll $(1)/usr/bin/ + + $(INSTALL_DIR) $(1)/usr/share/libwebsockets-test-server + $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/favicon.ico $(1)/usr/share/libwebsockets-test-server/ + $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/leaf.jpg $(1)/usr/share/libwebsockets-test-server/ + $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/libwebsockets.org-logo.png $(1)/usr/share/libwebsockets-test-server/ + $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/libwebsockets-test-server.key.pem $(1)/usr/share/libwebsockets-test-server/ + $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/libwebsockets-test-server.pem $(1)/usr/share/libwebsockets-test-server/ + $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/test.html $(1)/usr/share/libwebsockets-test-server/ +endef + +$(eval $(call BuildPackage,libwebsockets)) +$(eval $(call BuildPackage,libwebsockets-examples)) diff --git a/cross-aarch64.cmake b/cross-aarch64.cmake deleted file mode 100644 index d85a641..0000000 --- a/cross-aarch64.cmake +++ /dev/null @@ -1,32 +0,0 @@ -# -# CMake Toolchain file for crosscompiling on ARM. -# -# This can be used when running cmake in the following way: -# cd build/ -# cmake .. -DCMAKE_TOOLCHAIN_FILE=../cross-arm-linux-gnueabihf.cmake -# - -# Target operating system name. -set(CMAKE_SYSTEM_NAME Linux) -set(CMAKE_SYSTEM_PROCESSOR aarch64) - -# Name of C compiler. -set(CMAKE_C_COMPILER "aarch64-linux-gnu-gcc") -set(CMAKE_CXX_COMPILER "aarch64-linux-gnu-g++") - -#-nostdlib -SET(CMAKE_C_FLAGS "-DGCC_VER=\"\\\"$(GCC_VER)\\\"\" -DARM64=1 -D__LP64__=1 -Os -g3 -fpie -mstrict-align -DOPTEE_DEV_KIT=../../../optee_os/out/arm-plat-hikey/export-ta_arm64/include -fPIC -ffunction-sections -fdata-sections" CACHE STRING "" FORCE) - - -# Where to look for the target environment. (More paths can be added here) -set(CMAKE_FIND_ROOT_PATH "/projects/aist-tb/arm64-tc/") - -# Adjust the default behavior of the FIND_XXX() commands: -# search programs in the host environment only. -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - -# Search headers and libraries in the target environment only. -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) - - diff --git a/cross-arm-linux-gnueabihf.cmake b/cross-arm-linux-gnueabihf.cmake deleted file mode 100644 index 12cf3e9..0000000 --- a/cross-arm-linux-gnueabihf.cmake +++ /dev/null @@ -1,28 +0,0 @@ -# -# CMake Toolchain file for crosscompiling on ARM. -# -# This can be used when running cmake in the following way: -# cd build/ -# cmake .. -DCMAKE_TOOLCHAIN_FILE=../cross-arm-linux-gnueabihf.cmake -# - -set(CROSS_PATH /opt/gcc-linaro-arm-linux-gnueabihf-4.7-2013.02-01-20130221_linux) - -# Target operating system name. -set(CMAKE_SYSTEM_NAME Linux) - -# Name of C compiler. -set(CMAKE_C_COMPILER "${CROSS_PATH}/bin/arm-linux-gnueabihf-gcc") -set(CMAKE_CXX_COMPILER "${CROSS_PATH}/bin/arm-linux-gnueabihf-g++") - -# Where to look for the target environment. (More paths can be added here) -set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}") - -# Adjust the default behavior of the FIND_XXX() commands: -# search programs in the host environment only. -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - -# Search headers and libraries in the target environment only. -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) - diff --git a/cross-esp32.cmake b/cross-esp32.cmake deleted file mode 100644 index f978e80..0000000 --- a/cross-esp32.cmake +++ /dev/null @@ -1,46 +0,0 @@ -# -# CMake Toolchain file for crosscompiling on ARM. -# -# This can be used when running cmake in the following way: -# cd build/ -# cmake .. -DCMAKE_TOOLCHAIN_FILE=../cross-arm-linux-gnueabihf.cmake -# - -# Target operating system name. -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_FLAGS "-nostdlib -Wall -Werror \ - -I${BUILD_DIR_BASE}/include \ - -I${IDF_PATH}/components/mdns/include \ - -I${IDF_PATH}/components/driver/include \ - -I${IDF_PATH}/components/spi_flash/include \ - -I${IDF_PATH}/components/nvs_flash/include \ - -I${IDF_PATH}/components/tcpip_adapter/include \ - -I${IDF_PATH}/components/lwip/include/lwip/posix \ - -I${IDF_PATH}/components/lwip/include/lwip \ - -I${IDF_PATH}/components/lwip/include/lwip/port \ - -I${IDF_PATH}/components/esp32/include/ \ - -I${IDF_PATH}/components/bootloader_support/include/ \ - -I${IDF_PATH}/components/app_update/include/ \ - -I$(IDF_PATH)/components/soc/esp32/include/ \ - ${LWS_C_FLAGS} -Os \ - -I${IDF_PATH}/components/nvs_flash/test_nvs_host \ - -I${IDF_PATH}/components/freertos/include" CACHE STRING "" FORCE) - -# Where to look for the target environment. (More paths can be added here) -set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}") - -# Adjust the default behavior of the FIND_XXX() commands: -# search programs in the host environment only. -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - -# Search headers and libraries in the target environment only. -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) - diff --git a/cross-ming.cmake b/cross-ming.cmake deleted file mode 100644 index 94989f2..0000000 --- a/cross-ming.cmake +++ /dev/null @@ -1,31 +0,0 @@ -# -# CMake Toolchain file for crosscompiling on MingW. -# -# This can be used when running cmake in the following way: -# cd build/ -# cmake .. -DCMAKE_TOOLCHAIN_FILE=../cross-ming.cmake -# - -set(CROSS_PATH /usr/bin) - -# Target operating system name. -set(CMAKE_SYSTEM_NAME Windows) -set(BUILD_SHARED_LIBS OFF) - -# Name of C compiler. -set(CMAKE_C_COMPILER "${CROSS_PATH}/x86_64-w64-mingw32-gcc") -#set(CMAKE_CXX_COMPILER "${CROSS_PATH}/x86_64-w64-mingw32-g++") -set(CMAKE_RC_COMPILER "${CROSS_PATH}/x86_64-w64-mingw32-windres") -set(CMAKE_C_FLAGS "-Wno-error") - -# Where to look for the target environment. (More paths can be added here) -set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}") - -# Adjust the default behavior of the FIND_XXX() commands: -# search programs in the host environment only. -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - -# Search headers and libraries in the target environment only. -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) - diff --git a/cross-openwrt-makefile b/cross-openwrt-makefile deleted file mode 100644 index 2504370..0000000 --- a/cross-openwrt-makefile +++ /dev/null @@ -1,97 +0,0 @@ -# -# libwebsockets makefile for openwrt -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=libwebsockets -PKG_VERSION:=2014-03-01 -PKG_RELEASE=$(PKG_SOURCE_VERSION) - -PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL:=https://github.com/warmcat/libwebsockets.git -PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) -PKG_SOURCE_VERSION:=388dc7d201d8d123841869fb49ec4d94d6dd7f54 -PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz -CMAKE_INSTALL:=1 - -include $(INCLUDE_DIR)/package.mk -include $(INCLUDE_DIR)/cmake.mk - -CMAKE_OPTIONS += -DLWS_OPENSSL_CLIENT_CERTS=/etc/ssl/certs -CMAKE_OPTIONS += -DLWS_OPENSSL_SUPPORT=ON -CMAKE_OPTIONS += -DLWS_WITH_SSL=ON -CMAKE_OPTIONS += -DLWS_WITHOUT_TESTAPPS=$(if $(CONFIG_PACKAGE_libwebsockets-examples),"OFF","ON") - -# for wolfssl, define these in addition to LWS_OPENSSL_SUPPORT and -# edit package/libs/wolfssl/Makefile to include --enable-opensslextra -# CMAKE_OPTIONS += -DLWS_USE_WOLFSSL=ON -# CMAKE_OPTIONS += -DLWS_WOLFSSL_LIBRARIES=$(STAGING_DIR)/usr/lib/libwolfssl.so -# CMAKE_OPTIONS += -DLWS_WOLFSSL_INCLUDE_DIRS=$(STAGING_DIR)/usr/include - -# for cyassl, define these in addition to LWS_OPENSSL_SUPPORT and -# edit package/libs/wolfssl/Makefile to include --enable-opensslextra -# CMAKE_OPTIONS += -DLWS_USE_CYASSL=ON -# CMAKE_OPTIONS += -DLWS_CYASSL_LIBRARIES=$(STAGING_DIR)/usr/lib/libcyassl.so -# CMAKE_OPTIONS += -DLWS_CYASSL_INCLUDE_DIRS=$(STAGING_DIR)/usr/include - -# other options worth noting -# CMAKE_OPTIONS += -DLWS_WITHOUT_EXTENSIONS=ON -# CMAKE_OPTIONS += -DLWS_WITHOUT_DAEMONIZE=ON -# CMAKE_OPTIONS += -DLWS_WITHOUT_SERVER=ON -# CMAKE_OPTIONS += -DLWS_WITHOUT_DEBUG=ON - - -define Package/libwebsockets/Default - SECTION:=libs - CATEGORY:=Libraries - TITLE:=libwebsockets - DEPENDS:=+zlib +libopenssl -endef - -define Package/libwebsockets - $(call Package/libwebsockets/Default) - TITLE+= (libraries) -endef - -define Package/libwebsockets/description - libwebsockets - This package contains libwebsocket libraries -endef - -define Package/libwebsockets-examples - $(call Package/libwebsockets/Default) - DEPENDS:=libwebsockets - TITLE+= (examples) -endef - -define Package/libwebsockets-examples/description - libwebsockets examples - This package contains libwebsockets examples -endef - -define Package/libwebsockets/install - $(INSTALL_DIR) $(1)/usr/lib - $(CP) $(PKG_INSTALL_DIR)/usr/lib/libwebsockets.so* $(1)/usr/lib/ -endef - -define Package/libwebsockets-examples/install - $(INSTALL_DIR) $(1)/usr/bin - $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-client $(1)/usr/bin/ - $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-echo $(1)/usr/bin/ - $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-fraggle $(1)/usr/bin/ - $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-ping $(1)/usr/bin/ - $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-server $(1)/usr/bin/ - $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/libwebsockets-test-server-extpoll $(1)/usr/bin/ - - $(INSTALL_DIR) $(1)/usr/share/libwebsockets-test-server - $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/favicon.ico $(1)/usr/share/libwebsockets-test-server/ - $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/leaf.jpg $(1)/usr/share/libwebsockets-test-server/ - $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/libwebsockets.org-logo.png $(1)/usr/share/libwebsockets-test-server/ - $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/libwebsockets-test-server.key.pem $(1)/usr/share/libwebsockets-test-server/ - $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/libwebsockets-test-server.pem $(1)/usr/share/libwebsockets-test-server/ - $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/libwebsockets-test-server/test.html $(1)/usr/share/libwebsockets-test-server/ -endef - -$(eval $(call BuildPackage,libwebsockets)) -$(eval $(call BuildPackage,libwebsockets-examples)) diff --git a/libwebsockets.dox b/libwebsockets.dox index e100285..f7084b0 100644 --- a/libwebsockets.dox +++ b/libwebsockets.dox @@ -7,7 +7,7 @@ DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = "libwebsockets" PROJECT_NUMBER = PROJECT_BRIEF = "Lightweight C library for HTML5 websockets" -PROJECT_LOGO = "./test-server/libwebsockets.org-logo.png" +PROJECT_LOGO = "./test-apps/libwebsockets.org-logo.png" OUTPUT_DIRECTORY = "doc" CREATE_SUBDIRS = NO ALLOW_UNICODE_NAMES = NO @@ -101,7 +101,7 @@ WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- -INPUT = lib/libwebsockets.h mainpage.md README.build.md README.problems.md README.lwsws.md README.coding.md README.generic-sessions.md README.generic-table.md README.test-apps.md doc-assets +INPUT = lib/libwebsockets.h mainpage.md README.build.md README.problems.md README.lwsws.md README.coding.md README.generic-sessions.md README.generic-table.md README.test-apps.md README.lws-meta.md doc-assets INPUT_ENCODING = UTF-8 FILE_PATTERNS = lib/*.c *.md *.png RECURSIVE = NO diff --git a/libwebsockets.spec b/libwebsockets.spec deleted file mode 100644 index 0a7d5db..0000000 --- a/libwebsockets.spec +++ /dev/null @@ -1,91 +0,0 @@ -Name: libwebsockets -Version: 2.3.0 -Release: 1%{?dist} -Summary: Websocket Server and Client Library - -Group: System Environment/Libraries -License: LGPLv2 with exceptions -URL: https://libwebsockets.org -Source0: %{name}-%{version}.tar.gz -BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) - -BuildRequires: openssl-devel cmake -Requires: openssl - -%description -Webserver server and client library - -%package devel -Summary: Development files for libwebsockets -Group: Development/Libraries -Requires: %{name} = %{version}-%{release} -Requires: openssl-devel - -%description devel -Development files for libwebsockets - -%prep -%setup -q - -%build -mkdir -p build -cd build -%cmake .. -make - -%install -rm -rf $RPM_BUILD_ROOT -cd build -make install DESTDIR=$RPM_BUILD_ROOT - -%post -p /sbin/ldconfig -%postun -p /sbin/ldconfig - -%clean -rm -rf $RPM_BUILD_ROOT - -%files -%defattr(-,root,root,-) -%attr(755,root,root) -/usr/bin/libwebsockets-test-server -/usr/bin/libwebsockets-test-server-extpoll -/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 -/%{_libdir}/cmake/libwebsockets/LibwebsocketsConfig.cmake -/%{_libdir}/cmake/libwebsockets/LibwebsocketsConfigVersion.cmake -/%{_libdir}/cmake/libwebsockets/LibwebsocketsTargets.cmake -/%{_libdir}/cmake/libwebsockets/LibwebsocketsTargets-release.cmake - -/usr/share/libwebsockets-test-server -%doc -%files devel -%defattr(-,root,root,-) -/usr/include/* -%attr(755,root,root) -/%{_libdir}/libwebsockets.a -/%{_libdir}/pkgconfig/libwebsockets.pc -/%{_libdir}/pkgconfig/libwebsockets_static.pc - -%changelog -* Fri Jul 28 2017 Andy Green 2.3.0-1 -- MAJOR SONAMEBUMP APICHANGES Upstream 2.3.0 release - -* Mon Mar 06 2017 Andy Green 2.2.0-1 -- MAJOR SONAMEBUMP APICHANGES Upstream 2.2.0 release - -* Thu Oct 06 2016 Andy Green 2.1.0-1 -- MAJOR SONAMEBUMP APICHANGES Upstream 2.1.0 release - -* Thu May 05 2016 Andy Green 2.0.0-1 -- MAJOR SONAMEBUMP APICHANGES Upstream 2.0.0 release - -* Tue Feb 16 2016 Andy Green 1.7.0-1 -- MAJOR SONAMEBUMP APICHANGES Upstream 1.7.0 release - -* Sun Jan 17 2016 Andrew Cooks 1.6.0-1 -- Bump version to 1.6.0 diff --git a/lws_config.h.in b/lws_config.h.in deleted file mode 100644 index 3f2488a..0000000 --- a/lws_config.h.in +++ /dev/null @@ -1,155 +0,0 @@ -/* lws_config.h Generated from lws_config.h.in */ - -#ifndef NDEBUG - #ifndef _DEBUG - #define _DEBUG - #endif -#endif - -#define LWS_INSTALL_DATADIR "${CMAKE_INSTALL_PREFIX}/share" - -/* Define to 1 to use wolfSSL/CyaSSL as a replacement for OpenSSL. - * LWS_OPENSSL_SUPPORT needs to be set also for this to work. */ -#cmakedefine USE_WOLFSSL - -/* Also define to 1 (in addition to USE_WOLFSSL) when using the - (older) CyaSSL library */ -#cmakedefine USE_OLD_CYASSL -#cmakedefine LWS_USE_BORINGSSL - -#cmakedefine LWS_USE_MBEDTLS -#cmakedefine LWS_USE_POLARSSL -#cmakedefine LWS_WITH_ESP8266 -#cmakedefine LWS_WITH_ESP32 - -#cmakedefine LWS_WITH_PLUGINS -#cmakedefine LWS_WITH_NO_LOGS - -/* The Libwebsocket version */ -#cmakedefine LWS_LIBRARY_VERSION "${LWS_LIBRARY_VERSION}" - -#define LWS_LIBRARY_VERSION_MAJOR ${LWS_LIBRARY_VERSION_MAJOR} -#define LWS_LIBRARY_VERSION_MINOR ${LWS_LIBRARY_VERSION_MINOR} -#define LWS_LIBRARY_VERSION_PATCH ${LWS_LIBRARY_VERSION_PATCH} -/* LWS_LIBRARY_VERSION_NUMBER looks like 1005001 for e.g. version 1.5.1 */ -#define LWS_LIBRARY_VERSION_NUMBER (LWS_LIBRARY_VERSION_MAJOR*1000000)+(LWS_LIBRARY_VERSION_MINOR*1000)+LWS_LIBRARY_VERSION_PATCH - -/* The current git commit hash that we're building from */ -#cmakedefine LWS_BUILD_HASH "${LWS_BUILD_HASH}" - -/* Build with OpenSSL support */ -#cmakedefine LWS_OPENSSL_SUPPORT - -/* The client should load and trust CA root certs it finds in the OS */ -#cmakedefine LWS_SSL_CLIENT_USE_OS_CA_CERTS - -/* Sets the path where the client certs should be installed. */ -#cmakedefine LWS_OPENSSL_CLIENT_CERTS "${LWS_OPENSSL_CLIENT_CERTS}" - -/* Turn off websocket extensions */ -#cmakedefine LWS_NO_EXTENSIONS - -/* Enable libev io loop */ -#cmakedefine LWS_USE_LIBEV - -/* 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 - -/* Build with support for UNIX domain socket */ -#cmakedefine LWS_USE_UNIX_SOCK - -/* Build with support for HTTP2 */ -#cmakedefine LWS_USE_HTTP2 - -/* Turn on latency measuring code */ -#cmakedefine LWS_LATENCY - -/* Don't build the daemonizeation api */ -#cmakedefine LWS_NO_DAEMONIZE - -/* Build without server support */ -#cmakedefine LWS_NO_SERVER - -/* Build without client support */ -#cmakedefine LWS_NO_CLIENT - -/* If we should compile with MinGW support */ -#cmakedefine LWS_MINGW_SUPPORT - -/* Use the BSD getifaddrs that comes with libwebsocket, for uclibc support */ -#cmakedefine LWS_BUILTIN_GETIFADDRS - -/* use SHA1() not internal libwebsockets_SHA1 */ -#cmakedefine LWS_SHA1_USE_OPENSSL_NAME - -/* SSL server using ECDH certificate */ -#cmakedefine LWS_SSL_SERVER_WITH_ECDH_CERT -#cmakedefine LWS_HAVE_SSL_CTX_set1_param -#cmakedefine LWS_HAVE_X509_VERIFY_PARAM_set1_host - -#cmakedefine LWS_HAVE_UV_VERSION_H - -/* CGI apis */ -#cmakedefine LWS_WITH_CGI - -/* whether the Openssl is recent enough, and / or built with, ecdh */ -#cmakedefine LWS_HAVE_OPENSSL_ECDH_H - -/* HTTP Proxy support */ -#cmakedefine LWS_WITH_HTTP_PROXY - -/* HTTP Ranges support */ -#cmakedefine LWS_WITH_RANGES - -/* Http access log support */ -#cmakedefine LWS_WITH_ACCESS_LOG -#cmakedefine LWS_WITH_SERVER_STATUS - -#cmakedefine LWS_WITH_STATEFUL_URLDECODE -#cmakedefine LWS_WITH_PEER_LIMITS - -/* Maximum supported service threads */ -#define LWS_MAX_SMP ${LWS_MAX_SMP} - -/* Lightweight JSON Parser */ -#cmakedefine LWS_WITH_LEJP - -/* SMTP */ -#cmakedefine LWS_WITH_SMTP - -/* OPTEE */ -#cmakedefine LWS_PLAT_OPTEE - -/* ZIP FOPS */ -#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} diff --git a/lws_config_private.h.in b/lws_config_private.h.in deleted file mode 100644 index 8ad39a2..0000000 --- a/lws_config_private.h.in +++ /dev/null @@ -1,126 +0,0 @@ -/* lws_config_private.h.in. Private compilation options. */ - -#ifndef NDEBUG - #ifndef _DEBUG - #define _DEBUG - #endif -#endif - -/* Define to 1 to use CyaSSL as a replacement for OpenSSL. - * LWS_OPENSSL_SUPPORT needs to be set also for this to work. */ -#cmakedefine USE_CYASSL - -/* Define to 1 if you have the `bzero' function. */ -#cmakedefine LWS_HAVE_BZERO - -/* Define to 1 if you have the header file. */ -#cmakedefine LWS_HAVE_DLFCN_H - -/* Define to 1 if you have the header file. */ -#cmakedefine LWS_HAVE_FCNTL_H - -/* Define to 1 if you have the `fork' function. */ -#cmakedefine LWS_HAVE_FORK - -/* Define to 1 if you have the `getenv’ function. */ -#cmakedefine LWS_HAVE_GETENV - -/* Define to 1 if you have the header file. */ -#cmakedefine LWS_HAVE_IN6ADDR_H - -/* Define to 1 if you have the header file. */ -#cmakedefine LWS_HAVE_INTTYPES_H - -/* Define to 1 if you have the `ssl' library (-lssl). */ -//#cmakedefine LWS_HAVE_LIBSSL - -/* Define to 1 if your system has a GNU libc compatible `malloc' function, and - to 0 otherwise. */ -#cmakedefine LWS_HAVE_MALLOC - -/* Define to 1 if you have the header file. */ -#cmakedefine LWS_HAVE_MEMORY_H - -/* Define to 1 if you have the `memset' function. */ -#cmakedefine LWS_HAVE_MEMSET - -/* Define to 1 if you have the header file. */ -#cmakedefine LWS_HAVE_NETINET_IN_H - -/* Define to 1 if your system has a GNU libc compatible `realloc' function, - and to 0 otherwise. */ -#cmakedefine LWS_HAVE_REALLOC - -/* Define to 1 if you have the `socket' function. */ -#cmakedefine LWS_HAVE_SOCKET - -/* Define to 1 if you have the header file. */ -#cmakedefine LWS_HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#cmakedefine LWS_HAVE_STDLIB_H - -/* Define to 1 if you have the `strerror' function. */ -#cmakedefine LWS_HAVE_STRERROR - -/* Define to 1 if you have the header file. */ -#cmakedefine LWS_HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#cmakedefine LWS_HAVE_STRING_H - -/* Define to 1 if you have the header file. */ -#cmakedefine LWS_HAVE_SYS_PRCTL_H - -/* Define to 1 if you have the header file. */ -#cmakedefine LWS_HAVE_SYS_SOCKET_H - -/* Define to 1 if you have the header file. */ -#cmakedefine LWS_HAVE_SYS_SOCKIO_H - -/* Define to 1 if you have the header file. */ -#cmakedefine LWS_HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#cmakedefine LWS_HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#cmakedefine LWS_HAVE_UNISTD_H - -/* Define to 1 if you have the `vfork' function. */ -#cmakedefine LWS_HAVE_VFORK - -/* Define to 1 if you have the header file. */ -#cmakedefine LWS_HAVE_VFORK_H - -/* Define to 1 if `fork' works. */ -#cmakedefine LWS_HAVE_WORKING_FORK - -/* Define to 1 if `vfork' works. */ -#cmakedefine LWS_HAVE_WORKING_VFORK - -/* Define to 1 if execvpe() exists */ -#cmakedefine LWS_HAVE_EXECVPE - -/* Define to 1 if you have the header file. */ -#cmakedefine LWS_HAVE_ZLIB_H - -#cmakedefine LWS_HAVE_GETLOADAVG - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#undef LT_OBJDIR // We're not using libtool - -/* Define to rpl_malloc if the replacement function should be used. */ -#cmakedefine malloc - -/* Define to rpl_realloc if the replacement function should be used. */ -#cmakedefine realloc - -/* Define to 1 if we have getifaddrs */ -#cmakedefine LWS_HAVE_GETIFADDRS - -/* Define if the inline keyword doesn't exist. */ -#cmakedefine inline ${inline} - - diff --git a/mainpage.md b/mainpage.md deleted file mode 100644 index 9a427b3..0000000 --- a/mainpage.md +++ /dev/null @@ -1,16 +0,0 @@ -##Libwebsockets API introduction - -Libwebsockets covers a lot of interesting features for people making embedded servers or clients - - - http(s) serving and client operation - - ws(s) serving and client operation - - http(s) apis for file transfer and upload - - http POST form handling (including multipart) - - cookie-based sessions - - account management (including registration, email verification, lost pw etc) - - strong ssl PFS support (A+ on SSLlabs test) - -You can browse by api category here - -A collection of READMEs for build, coding, lwsws etc are here - diff --git a/module.json b/module.json deleted file mode 100644 index ba2c35b..0000000 --- a/module.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "websockets", - "version": "1.6.0", - "description": "Libwebsockets", - "keywords": [ - "lws", - "libwebsockets", - "websockets", - "ws" - ], - "author": "Andy Green ", - "homepage": "https://libwebsockets.org", - "license": "LGPL2.1-SLE", - - "extraIncludes": [ "build/frdm-k64f-gcc/generated/include" ], - "dependencies": { - "mbed-drivers": "", - "sal-stack-lwip": "", - "sockets": "" - } -} diff --git a/release-checklist b/release-checklist deleted file mode 100644 index 69f04a8..0000000 --- a/release-checklist +++ /dev/null @@ -1,102 +0,0 @@ -Release Checklist ------------------ - -0) QA - - a) ab - - $ ab -n 100000 -c 200 http://localhost:7681/ - - b) coverity - - $ ../make-coverity-tarball.sh - https://scan.coverity.com/projects/warmcat-libwebsockets - - c) test servers + client + browser - - d) valgrind test servers + client + browser - - e) attack.sh - - $ ./test-server/attack.sh - - f) Autobahn - - $ wstest -m fuzzingserver & - $ ./autobahn-test.sh - - Force update by browser using agent "libwebsockets" - http://localhost:8080/test_browser.html - - rsync -av ./reports/* root@warmcat.com:/var/www/libwebsockets.org - -1) api - - $ cp build/doc/* . - -2) soname bump? - - a) We need one if we added / changed / removed apis - - CMakeLists.txt - - set(SOVERSION "6") - - libwebsockets.spec - - -/%{_libdir}/libwebsockets.so.6 - +/%{_libdir}/libwebsockets.so.7 - -3) changelog - - a) Add next version tag header. - - b) Classify as - - - MINOR bug fixes - - MAJOR bug fixes - - SECURITY fixes - -4) main version bump - - CMakeLists.txt - - set(CPACK_PACKAGE_VERSION_MAJOR "1") - set(CPACK_PACKAGE_VERSION_MINOR "6") - set(CPACK_PACKAGE_VERSION_PATCH "0") - -5) specfile - - a) rpm version bump to match CMake one - - libwebsockets.spec - - Version: 1.6.0 - - b) Summarize changelog - - libwebsockets.spec - -%changelog -* Sun Jan 17 2016 Andrew Cooks 1.6.4-1 -- Bump version to 1.6.4 -- MINOR fix xyz - -6) update api docs - - $ cmake .. - $ cp doc/* .. - -7) signed tag - - git tag -s vX.Y[.Z] - -8) git - - a) push - - b) final CI check, if fail delete tag, kill pushed tags, restart flow - -8) website - - a) update latest tag for release branch diff --git a/scripts/FindLibWebSockets.cmake b/scripts/FindLibWebSockets.cmake deleted file mode 100644 index e7d2839..0000000 --- a/scripts/FindLibWebSockets.cmake +++ /dev/null @@ -1,33 +0,0 @@ -# This module tries to find libWebsockets library and include files -# -# LIBWEBSOCKETS_INCLUDE_DIR, path where to find libwebsockets.h -# LIBWEBSOCKETS_LIBRARY_DIR, path where to find libwebsockets.so -# LIBWEBSOCKETS_LIBRARIES, the library to link against -# LIBWEBSOCKETS_FOUND, If false, do not try to use libWebSockets -# -# This currently works probably only for Linux - -FIND_PATH ( LIBWEBSOCKETS_INCLUDE_DIR libwebsockets.h - /usr/local/include - /usr/include -) - -FIND_LIBRARY ( LIBWEBSOCKETS_LIBRARIES websockets - /usr/local/lib - /usr/lib -) - -GET_FILENAME_COMPONENT( LIBWEBSOCKETS_LIBRARY_DIR ${LIBWEBSOCKETS_LIBRARIES} PATH ) - -SET ( LIBWEBSOCKETS_FOUND "NO" ) -IF ( LIBWEBSOCKETS_INCLUDE_DIR ) - IF ( LIBWEBSOCKETS_LIBRARIES ) - SET ( LIBWEBSOCKETS_FOUND "YES" ) - ENDIF ( LIBWEBSOCKETS_LIBRARIES ) -ENDIF ( LIBWEBSOCKETS_INCLUDE_DIR ) - -MARK_AS_ADVANCED( - LIBWEBSOCKETS_LIBRARY_DIR - LIBWEBSOCKETS_INCLUDE_DIR - LIBWEBSOCKETS_LIBRARIES -) diff --git a/scripts/autobahn-test.sh b/scripts/autobahn-test.sh new file mode 100755 index 0000000..91b9171 --- /dev/null +++ b/scripts/autobahn-test.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +set -u + +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 & + + C=99 + while [ $C -gt 8 ] ; do + if [ $OS=SunOS ] ; then + C=`ps -ef | grep libwebsockets-test-echo | wc -l` + else + C=`ps fax | grep libwebsockets-test-echo | wc -l` + fi + if [ $C -gt 8 ] ; then + sleep 1s + fi + done + + N=$(( $N + 1 )) +done + +echo "waiting for forks to complete..." + +while [ 1 ] ; do + if [ $OS=SunOS ] ; then + n=`ps -ef | grep libwebsocket | grep -v grep | wc -l` + else + n=`ps fax | grep libwebsocket | grep -v grep | wc -l` + fi + echo "$n forks running..." + if [ $n -eq 0 ] ; then + echo "Completed" + exit 0 + fi + sleep 1s +done + diff --git a/scripts/libwebsockets.spec b/scripts/libwebsockets.spec new file mode 100644 index 0000000..0a7d5db --- /dev/null +++ b/scripts/libwebsockets.spec @@ -0,0 +1,91 @@ +Name: libwebsockets +Version: 2.3.0 +Release: 1%{?dist} +Summary: Websocket Server and Client Library + +Group: System Environment/Libraries +License: LGPLv2 with exceptions +URL: https://libwebsockets.org +Source0: %{name}-%{version}.tar.gz +BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) + +BuildRequires: openssl-devel cmake +Requires: openssl + +%description +Webserver server and client library + +%package devel +Summary: Development files for libwebsockets +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} +Requires: openssl-devel + +%description devel +Development files for libwebsockets + +%prep +%setup -q + +%build +mkdir -p build +cd build +%cmake .. +make + +%install +rm -rf $RPM_BUILD_ROOT +cd build +make install DESTDIR=$RPM_BUILD_ROOT + +%post -p /sbin/ldconfig +%postun -p /sbin/ldconfig + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root,-) +%attr(755,root,root) +/usr/bin/libwebsockets-test-server +/usr/bin/libwebsockets-test-server-extpoll +/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 +/%{_libdir}/cmake/libwebsockets/LibwebsocketsConfig.cmake +/%{_libdir}/cmake/libwebsockets/LibwebsocketsConfigVersion.cmake +/%{_libdir}/cmake/libwebsockets/LibwebsocketsTargets.cmake +/%{_libdir}/cmake/libwebsockets/LibwebsocketsTargets-release.cmake + +/usr/share/libwebsockets-test-server +%doc +%files devel +%defattr(-,root,root,-) +/usr/include/* +%attr(755,root,root) +/%{_libdir}/libwebsockets.a +/%{_libdir}/pkgconfig/libwebsockets.pc +/%{_libdir}/pkgconfig/libwebsockets_static.pc + +%changelog +* Fri Jul 28 2017 Andy Green 2.3.0-1 +- MAJOR SONAMEBUMP APICHANGES Upstream 2.3.0 release + +* Mon Mar 06 2017 Andy Green 2.2.0-1 +- MAJOR SONAMEBUMP APICHANGES Upstream 2.2.0 release + +* Thu Oct 06 2016 Andy Green 2.1.0-1 +- MAJOR SONAMEBUMP APICHANGES Upstream 2.1.0 release + +* Thu May 05 2016 Andy Green 2.0.0-1 +- MAJOR SONAMEBUMP APICHANGES Upstream 2.0.0 release + +* Tue Feb 16 2016 Andy Green 1.7.0-1 +- MAJOR SONAMEBUMP APICHANGES Upstream 1.7.0 release + +* Sun Jan 17 2016 Andrew Cooks 1.6.0-1 +- Bump version to 1.6.0 diff --git a/scripts/travis_install.sh b/scripts/travis_install.sh new file mode 100755 index 0000000..f51f087 --- /dev/null +++ b/scripts/travis_install.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +if [ "$COVERITY_SCAN_BRANCH" == 1 ]; then exit; fi + +if [ "$TRAVIS_OS_NAME" == "linux" ]; +then + sudo apt-get update -qq + + if [ "$LWS_METHOD" == "libev" ]; + then + sudo apt-get install -y -qq libev-dev; + fi + + if [ "$LWS_METHOD" == "libuv" -o "$LWS_METHOD" == "lwsws" ]; + then + sudo apt-get install -y -qq libuv-dev; + fi + +fi + +if [ "$TRAVIS_OS_NAME" == "osx" ]; +then + if [ "$LWS_METHOD" == "libev" ]; + then + brew install libev; + fi + + if [ "$LWS_METHOD" == "libuv" -o "$LWS_METHOD" == "lwsws" ]; + then + brew install libuv; + fi + +fi + + diff --git a/test-apps/.gitignore b/test-apps/.gitignore new file mode 100644 index 0000000..53ba6cb --- /dev/null +++ b/test-apps/.gitignore @@ -0,0 +1,9 @@ +#Ignore build files +libwebsockets-test-* +Makefile +*.o +*.lo +*.la +.libs +.deps + diff --git a/test-apps/android/README b/test-apps/android/README new file mode 100644 index 0000000..09599b7 --- /dev/null +++ b/test-apps/android/README @@ -0,0 +1,51 @@ +/* + * libwebsockets Android client - libwebsockets test application for Android + * + * Copyright (C) 2016 Alexander Bruines + * + * 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. + */ + +This directory contains an Android Studio (2.1.1) project that builds +libwebsockets (+ openssl + zlib) and an Android application that is able +to connect to the 'dumb-increment-protocol' of the libwebsockets test server. + +Building the native libraries requires the Android NDK which can be +installed using the SDK manager. + +The app/src/main/jni/NativeLibs.mk is fully integraded with Gradle but will +only work on Linux and requires the following applications to be available +in addition to the NDK: + + awk cmake egrep git tar wget makedepend + +(makedepend can be installed from (Debian) xutils-dev) + +To build the project: + +- Open an 'existing project' with Android Studio and select this directory. + (answer yes/ok to the question to integrate with Gradle). + +- Open the file app/src/main/jni/Application.mk and make sure NDK_ROOT + is set correctly and that APP_PLATFORM is set to the appropriate API level. + +- Build the project with CTRL+F9 + (open the gradle console to follow the build progress). + +- Install APK to device and run. + +- Connect to libwebsockets test server. + + diff --git a/test-apps/android/app/app.iml b/test-apps/android/app/app.iml new file mode 100644 index 0000000..67ff95a --- /dev/null +++ b/test-apps/android/app/app.iml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test-apps/android/app/build.gradle b/test-apps/android/app/build.gradle new file mode 100644 index 0000000..48069c8 --- /dev/null +++ b/test-apps/android/app/build.gradle @@ -0,0 +1,42 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 23 + buildToolsVersion "23.0.3" + + defaultConfig { + applicationId "org.libwebsockets.client" + minSdkVersion 17 + targetSdkVersion 23 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + sourceSets { + main { + jni.srcDirs = [] + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + testCompile 'junit:junit:4.12' + compile 'com.android.support:appcompat-v7:23.3.0' +} + +task buildNativeLibs(type: Exec, description: "compile the native libraries") { + commandLine 'make', '-f', 'NativeLibs.mk', '-C', 'src/main/jni', 'all' +} + +task cleanNativeLibs(type: Exec, description: "clean the native libraries source tree") { + commandLine 'make', '-f', 'NativeLibs.mk', '-C', 'src/main/jni', 'clean-ndk' +} + +tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn buildNativeLibs } +clean.dependsOn 'cleanNativeLibs' diff --git a/test-apps/android/app/src/main/AndroidManifest.xml b/test-apps/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..8e3b744 --- /dev/null +++ b/test-apps/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test-apps/android/app/src/main/java/org/libwebsockets/client/LwsService.java b/test-apps/android/app/src/main/java/org/libwebsockets/client/LwsService.java new file mode 100644 index 0000000..19f234b --- /dev/null +++ b/test-apps/android/app/src/main/java/org/libwebsockets/client/LwsService.java @@ -0,0 +1,132 @@ +/* + * LwsService.java - libwebsockets test service for Android + * + * Copyright (C) 2016 Alexander Bruines + * + * 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. + */ + +package org.libwebsockets.client; + +import android.os.Message; +import android.os.RemoteException; +import android.util.Log; + +public class LwsService extends ThreadService { + + /** + * Commands that can be send to this service + */ + public final static int MSG_SET_CONNECTION_PARAMETERS = 1; + + /** + * Messages that may be send to output Messenger + * Clients should handle these messages. + **/ + public final static int MSG_DUMB_INCREMENT_PROTOCOL_COUNTER = 1; + public final static int MSG_LWS_CALLBACK_CLIENT_CONNECTION_ERROR = 2; + public final static int MSG_LWS_CALLBACK_CLIENT_ESTABLISHED = 3; + + public static class ConnectionParameters { + String serverAddress; + int serverPort; + + ConnectionParameters( + String serverAddress, + int serverPort + ){ + this.serverAddress = serverAddress; + this.serverPort = serverPort; + } + } + + /** + * Handle incoming messages from clients of this service + */ + @Override + public void handleInputMessage(Message msg) { + Message m; + switch(msg.what) { + case MSG_SET_CONNECTION_PARAMETERS: { + LwsService.ConnectionParameters parameters = (ConnectionParameters) msg.obj; + setConnectionParameters( + parameters.serverAddress, + parameters.serverPort + ); + break; + } + default: + super.handleInputMessage(msg); + break; + } + } + + /** + * The run() function for the thread. + * For this test we implement a very long lived task + * that sends many messages back to the client. + * **/ + public void workerThreadRun() { + + initLws(); + connectLws(); + + while(true) { + + // service the websockets + serviceLws(); + + // Check if we must quit or suspend + synchronized (mThreadLock){ + while(mMustSuspend) { + // We are asked to suspend the thread + try { + mThreadLock.wait(); + + } catch (InterruptedException e) {} + } + if(mMustQuit) { + // The signal to quit was given + break; + } + } + + // Throttle the loop so that it iterates once every 50ms + try { + Thread.sleep(50); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + + } + exitLws(); + } + + /** Load the native libwebsockets code */ + static { + try { + System.loadLibrary("lwsservice"); + } + catch(UnsatisfiedLinkError ule) { + Log.e("LwsService", "Warning: Could not load native library: " + ule.getMessage()); + } + } + public native boolean initLws(); + public native void exitLws(); + public native void serviceLws(); + public native void setConnectionParameters(String serverAddress, int serverPort); + public native boolean connectLws(); +} diff --git a/test-apps/android/app/src/main/java/org/libwebsockets/client/MainActivity.java b/test-apps/android/app/src/main/java/org/libwebsockets/client/MainActivity.java new file mode 100644 index 0000000..b46f5e8 --- /dev/null +++ b/test-apps/android/app/src/main/java/org/libwebsockets/client/MainActivity.java @@ -0,0 +1,246 @@ +/* + * MainActivity.java - libwebsockets test service for Android + * + * Copyright (C) 2016 Alexander Bruines + * + * 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. + */ + +package org.libwebsockets.client; + + +import android.content.ComponentName; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; +import android.support.v7.app.AlertDialog; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.util.Log; +import android.view.inputmethod.InputMethodManager; +import android.view.View; +import android.widget.EditText; +import android.widget.TextView; + +public class MainActivity extends AppCompatActivity implements LwsService.OutputInterface { + + /** This is the Messenger that handles output from the Service */ + private Messenger mMessenger = null; + + /** The Messenger for sending commands to the Service */ + private Messenger mService = null; + private ServiceConnection mServiceConnection = null; + + private boolean mThreadIsRunning = false; + private boolean mThreadIsSuspended = false; + + private TextView tvCounter; + private EditText etServer; + private EditText etPort; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + // Get the layout items + tvCounter = (TextView) findViewById(R.id.textView_counter); + etServer = (EditText) findViewById(R.id.editText_serverLocation); + etPort = (EditText) findViewById(R.id.editText_portNumber); + + // Create the Messenger for handling output from the service + mMessenger = new Messenger(new LwsService.OutputHandler(this)); + + // Restore state from the Bundle when restarting due to a device change. + if(savedInstanceState!=null) { + mThreadIsRunning = savedInstanceState.getBoolean("mThreadIsRunning"); + } + + mServiceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + mService = new Messenger(service); + try { + // Set the output messenger by starting the thread + Message msg = Message.obtain(null, LwsService.MSG_SET_OUTPUT_HANDLER, 0, 0); + msg.replyTo = mMessenger; + mService.send(msg); + if(mThreadIsRunning){ + // If the thread is already running at this point it means + // that the application was restarted after a device change. + // This implies that the thread was suspended by the onStop method. + msg = Message.obtain(null, LwsService.MSG_THREAD_RESUME, 0, 0); + mService.send(msg); + mThreadIsSuspended = false; + } + } + catch(RemoteException e) { + e.printStackTrace(); + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + Log.e("MainActivity","onServiceDisconnected !"); + mService = null; + } + }; + + if(savedInstanceState==null){ + startService(new Intent(getBaseContext(), LwsService.class)); + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean("mThreadIsRunning", mThreadIsRunning); + } + + @Override + protected void onStart() { + super.onStart(); + bindService(new Intent(getBaseContext(), LwsService.class), mServiceConnection, Context.BIND_AUTO_CREATE); + } + + @Override + protected void onStop() { + super.onStop(); + if(mThreadIsRunning) { + if (!mThreadIsSuspended) { + try { + mService.send(Message.obtain(null, LwsService.MSG_THREAD_SUSPEND, 0, 0)); + } catch (RemoteException e) { + e.printStackTrace(); + } + mThreadIsSuspended = true; + } + } + unbindService(mServiceConnection); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if(isFinishing()){ + stopService(new Intent(getBaseContext(), LwsService.class)); + } + } + + /** Implement the interface to receive output from the LwsService */ + @Override + public void handleOutputMessage(Message message) { + switch(message.what) { + case LwsService.MSG_DUMB_INCREMENT_PROTOCOL_COUNTER: + tvCounter.setText((String)message.obj); + break; + case LwsService.MSG_LWS_CALLBACK_CLIENT_CONNECTION_ERROR: + connectErrorListener(); + break; + case LwsService.MSG_LWS_CALLBACK_CLIENT_ESTABLISHED: + break; + case LwsService.MSG_THREAD_STARTED: + // The thread was started + mThreadIsRunning = true; + mThreadIsSuspended = false; + break; + case LwsService.MSG_THREAD_STOPPED: + // The thread was stopped + mThreadIsRunning = false; + mThreadIsSuspended = false; + break; + case LwsService.MSG_THREAD_SUSPENDED: + // The thread is suspended + mThreadIsRunning = true; + mThreadIsSuspended = true; + break; + case LwsService.MSG_THREAD_RESUMED: + // the thread was resumed + mThreadIsRunning = true; + mThreadIsSuspended = false; + break; + default: + break; + } + } + + private void connectErrorListener(){ + try { + Message msg; + if(mThreadIsRunning) { + msg = Message.obtain(null, LwsService.MSG_THREAD_STOP); + mService.send(msg); + } + AlertDialog.Builder adb = new AlertDialog.Builder(this); + adb.setTitle("Error"); + adb.setPositiveButton("OK", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + } + }); + adb.setMessage("Could not connect to the server."); + adb.show(); + } + catch (RemoteException e){} + } + + /** + * Start/Stop Button Handler + */ + + public void clickStart(View v) { + if(!mThreadIsRunning) { + View view = this.getCurrentFocus(); + if (view != null) { + InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + mThreadIsRunning = true; + mThreadIsSuspended = false; + try { + Message msg = Message.obtain(null, LwsService.MSG_SET_CONNECTION_PARAMETERS, 0, 0); + int port = 0; + if(!etPort.getText().toString().equals("")) // prevent NumberformatException + port = Integer.parseInt(etPort.getText().toString()); + LwsService.ConnectionParameters parameters = new LwsService.ConnectionParameters( + etServer.getText().toString(), + port + ); + msg.obj = parameters; + mService.send(msg); + msg = Message.obtain(null, LwsService.MSG_THREAD_START, 0, 0); + mService.send(msg); + } + catch(RemoteException e) { + e.printStackTrace(); + } + } + else { + try { + mService.send(Message.obtain(null, LwsService.MSG_THREAD_STOP, 0, 0)); + } + catch(RemoteException e) { + e.printStackTrace(); + } + mThreadIsRunning = false; + mThreadIsSuspended = false; + } + } + +} diff --git a/test-apps/android/app/src/main/java/org/libwebsockets/client/ThreadService.java b/test-apps/android/app/src/main/java/org/libwebsockets/client/ThreadService.java new file mode 100644 index 0000000..b9ae863 --- /dev/null +++ b/test-apps/android/app/src/main/java/org/libwebsockets/client/ThreadService.java @@ -0,0 +1,284 @@ +/* + * ThreadService.java - libwebsockets test service for Android + * + * Copyright (C) 2016 Alexander Bruines + * + * 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. + */ + +package org.libwebsockets.client; + +import android.app.Service; +import android.content.Intent; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; +import android.util.Log; + +import java.lang.ref.WeakReference; + +public abstract class ThreadService extends Service { + /** Messages that can be send to the Service: **/ + public final static int MSG_SET_OUTPUT_HANDLER = 1001; + public final static int MSG_THREAD_START = 1002; + public final static int MSG_THREAD_STOP = 1003; + public final static int MSG_THREAD_SUSPEND = 1004; + public final static int MSG_THREAD_RESUME = 1005; + + /** + * Messages that may be send from the Service + * (Clients should handle these messages) + **/ + public final static int MSG_THREAD_STARTED = 2001; + public final static int MSG_THREAD_STOPPED = 2002; + public final static int MSG_THREAD_SUSPENDED = 2003; + public final static int MSG_THREAD_RESUMED = 2004; + + /** Data accessed by both worker thread and the UI-thread must be synchronized **/ + public final Object mThreadLock = new Object();; + public volatile boolean mMustQuit; + public volatile boolean mWorkThreadIsRunning; + public volatile boolean mMustSuspend; + + /** Handler for incoming messages **/ + public static class InputHandler extends Handler { + private final WeakReference mService; + InputHandler(ThreadService service) { + mService = new WeakReference(service); + } + @Override + public void handleMessage(Message msg) { + ThreadService service = mService.get(); + if(service != null) { + service.handleInputMessage(msg); + } + } + } + + /** + * Interface and Handler for outgoing messages to clients of this service. + * (Must be implemented by the client.) + */ + public interface OutputInterface { + void handleOutputMessage(Message message); + } + public static class OutputHandler extends Handler { + // Notice that we do NOT use a WeakReference here + // (If we did the service would lose mOutputMessenger the moment + // that garbage collection is performed by the Java VM) + private final OutputInterface mInterface; + OutputHandler(OutputInterface object) { + mInterface = object; + } + @Override + public void handleMessage(Message msg) { + mInterface.handleOutputMessage(msg); + } + } + + /** The Messengers used to communicate with the clients of this service **/ + public final Messenger mInputMessenger = new Messenger(new InputHandler(this)); + public Messenger mOutputMessenger; + + /** The worker thread and its runnable **/ + public static class WorkerThreadRunnable implements Runnable { + private final WeakReference mService; + WorkerThreadRunnable(ThreadService service){ + mService = new WeakReference(service); + } + @Override + public void run() { + ThreadService service = mService.get(); + if(service != null) { + service.mWorkThreadIsRunning = true; + service.workerThreadRun(); + service.mWorkThreadIsRunning = false; + } + } + } + public Thread mWorkerThread; + + /** Handle incoming messages from the client **/ + public void handleInputMessage(Message msg) { + try { + Message m; + switch(msg.what) { + case MSG_SET_OUTPUT_HANDLER: + // set the output messenger then + // send a message indicating the thread status + mOutputMessenger = msg.replyTo; + break; + case MSG_THREAD_START: + try { + // reset thread vars + synchronized (mThreadLock) { + // thread allready running? + if(!mWorkThreadIsRunning){ + // no, start it + mMustQuit = false; + mMustSuspend = false; + mWorkerThread = new Thread(new WorkerThreadRunnable(this)); + mWorkerThread.start(); + } + else { + // yes, resume it + mMustQuit = false; + mMustSuspend = false; + mThreadLock.notifyAll(); + } + } + } + catch(NullPointerException e) { + e.printStackTrace(); + } + if(mOutputMessenger != null) { + m = Message.obtain(null, MSG_THREAD_STARTED, 0, 0); + mOutputMessenger.send(m); + } + break; + case MSG_THREAD_STOP: + try { + synchronized(mThreadLock) { + if(mWorkThreadIsRunning) { + mMustQuit = true; + mMustSuspend = false; + mThreadLock.notifyAll(); + } + } + mWorkerThread.join(); + } + catch(InterruptedException e) { + Log.e("ThreadService","handleInputMessage join() interrupted"); + } + if(mOutputMessenger != null) { + m = Message.obtain(null, MSG_THREAD_STOPPED, 0, 0); + mOutputMessenger.send(m); + } + break; + case MSG_THREAD_SUSPEND: + synchronized (mThreadLock) { + if(mWorkThreadIsRunning) { + mMustSuspend = true; + } + } + if(mOutputMessenger != null) { + m = Message.obtain(null, MSG_THREAD_SUSPENDED, 0, 0); + mOutputMessenger.send(m); + } + break; + case MSG_THREAD_RESUME: + synchronized (mThreadLock) { + if(mWorkThreadIsRunning) { + mMustSuspend = false; + mThreadLock.notifyAll(); + } + } + if(mOutputMessenger != null) { + m = Message.obtain(null, MSG_THREAD_RESUMED, 0, 0); + mOutputMessenger.send(m); + } + break; + default: + break; + } + } + catch(RemoteException e) { + e.printStackTrace(); + } + } + + /** + * This can be called from the JNI functions to send output messages to the client + */ + public void sendMessage(int msg, Object obj){ + Message m = Message.obtain(null, msg, 0, 0); + m.obj = obj; + try { + mOutputMessenger.send(m); + } + catch(RemoteException e) { + e.printStackTrace(); + } + } + + /** The run() function for the worker thread **/ + public abstract void workerThreadRun(); + + /** + * Called when the service is being created. + * ie. When the first client calls bindService() or startService(). + **/ + @Override + public void onCreate() { + super.onCreate(); + // initialize variables + mWorkThreadIsRunning = false; + mMustQuit = false; + mOutputMessenger = null; + mWorkerThread = null; + } + + /** + * Called when the first client is binding to the service with bindService() + * + * If the service was started with bindService() it will automatically stop when the last + * client unbinds from the service. If you want the service to continue running even if it + * is not bound to anything then start the service with startService() before + * calling bindService(). In this case stopService() must be called after unbinding + * to stop the service. + */ + @Override + public IBinder onBind(Intent intent) { + return mInputMessenger.getBinder(); + } + + /** Called if the service is started with startService(). */ + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + return START_STICKY; + } + + /** Called when the first client is binds to the service with bindService() */ + @Override + public void onRebind(Intent intent) {} + + /** Called when all clients have unbound with unbindService() */ + @Override + public boolean onUnbind(Intent intent) { + //mOutputMessenger = null; + return false; // do not allow to rebind. + } + + /** Called when the service is no longer used and is being destroyed */ + @Override + public void onDestroy() { + super.onDestroy(); + try { + if(mWorkThreadIsRunning){ + synchronized(mThreadLock) { + mMustQuit = true; + mMustSuspend = false; + mThreadLock.notifyAll(); + } + mWorkerThread.join(); + } + } + catch(NullPointerException | InterruptedException e) { + e.printStackTrace(); + } + } +} diff --git a/test-apps/android/app/src/main/jni/Android.mk b/test-apps/android/app/src/main/jni/Android.mk new file mode 100644 index 0000000..80720ce --- /dev/null +++ b/test-apps/android/app/src/main/jni/Android.mk @@ -0,0 +1,41 @@ +# get current directory +LOCAL_PATH := $(call my-dir) + +# libz.a +# +include $(CLEAR_VARS) +LOCAL_MODULE := libz +LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/lib/libz.a +include $(PREBUILT_STATIC_LIBRARY) + +# libssl.a +# +include $(CLEAR_VARS) +LOCAL_MODULE := libssl +LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/lib/libssl.a +include $(PREBUILT_STATIC_LIBRARY) + +# libcrypto.a +# +include $(CLEAR_VARS) +LOCAL_MODULE := libcrypto +LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/lib/libcrypto.a +include $(PREBUILT_STATIC_LIBRARY) + +# libwebsockets.a +# +include $(CLEAR_VARS) +LOCAL_MODULE := libwebsockets +LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/lib/libwebsockets.a +include $(PREBUILT_STATIC_LIBRARY) + +# liblwsservice.so +# +include $(CLEAR_VARS) +LOCAL_DISABLE_FATAL_LINKER_WARNINGS := true +LOCAL_MODULE := lwsservice +LOCAL_SRC_FILES := LwsService.cpp +LOCAL_C_INCLUDES := $(LOCAL_PATH) $(TARGET_ARCH_ABI)/include +LOCAL_STATIC_LIBRARIES := websockets z ssl crypto +LOCAL_LDLIBS := -llog +include $(BUILD_SHARED_LIBRARY) diff --git a/test-apps/android/app/src/main/jni/Application.mk b/test-apps/android/app/src/main/jni/Application.mk new file mode 100644 index 0000000..cc638ca --- /dev/null +++ b/test-apps/android/app/src/main/jni/Application.mk @@ -0,0 +1,49 @@ +# +# Zlib, OpenSSL and libwebsockets will be downloaded automatically unless you place +# their source .tar.gz files in the jni directory... +# + +# The location of the NDK +# +NDK_ROOT := /opt/Android/Sdk/ndk-bundle + +# Update these to the latest versions before building +# +ZLIB_VERSION := 1.2.8 +OPENSSL_VERSION := 1.0.2h + +# This will be executed as 'git clone $(LIBWEBSOCKETS_GIT_URL)' +# +LIBWEBSOCKETS_GIT_URL := --branch master https://github.com/warmcat/libwebsockets.git + +# +# Note: If you build for API level 21 or higher in APP_PLATFORM, +# the resulting application will only run on API 21+ devices. +# Even if minSdkVersion has been set to a lower level! +# This is the result of API changes for the native signal() function. +# The recommended solution is to build two packages, one for API 17+ and the other for API 21+ devices. +# http://stackoverflow.com/questions/28740315/android-ndk-getting-java-lang-unsatisfiedlinkerror-dlopen-failed-cannot-loca +# +# Note: If you change the API level the JNI code must be rebuild completely. +# (Run 'make clean' from the app/src/main/jni directory.) +# +APP_PLATFORM := android-23 + +# Builds for armeabi armeabi-v7a x86 mips arm64-v8a x86_64 mips64 +# +#APP_ABI := all + +# The same as above. +# +#APP_ABI := armeabi armeabi-v7a x86 mips arm64-v8a x86_64 mips64 + +# Good enough for most current devices + x86 AVD +# +APP_ABI := armeabi-v7a x86 + +# Enable (GNU) c++11 extentions +APP_CPPFLAGS += -std=gnu++11 + +# Use the GNU standard template library +APP_STL := gnustl_shared + diff --git a/test-apps/android/app/src/main/jni/LwsService.cpp b/test-apps/android/app/src/main/jni/LwsService.cpp new file mode 100644 index 0000000..769011b --- /dev/null +++ b/test-apps/android/app/src/main/jni/LwsService.cpp @@ -0,0 +1,307 @@ +/* + * LwsService.cpp - libwebsockets test service for Android + * + * Copyright (C) 2016 Alexander Bruines + * + * 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 + +#include +#include +#define printf(...) __android_log_print(ANDROID_LOG_VERBOSE, "LwsService", ##__VA_ARGS__) + +///////////////////////////////////////////////////////// +// Code executed when loading the dynamic link library // +///////////////////////////////////////////////////////// + +// The Java class the native functions shall be part of +#define JNIREG_CLASS "org/libwebsockets/client/LwsService" + +JavaVM* gJvm = NULL; +JNIEnv* gEnv = 0; + +JNIEXPORT jboolean JNICALL jni_initLws(JNIEnv *env, jobject obj); +JNIEXPORT void JNICALL jni_exitLws(JNIEnv *env, jobject obj); +JNIEXPORT void JNICALL jni_serviceLws(JNIEnv *env, jobject obj); +JNIEXPORT void JNICALL jni_setConnectionParameters(JNIEnv *env, jobject obj, jstring serverAddress, jint serverPort); +JNIEXPORT jboolean JNICALL jni_connectLws(JNIEnv *env, jobject obj); + +static JNINativeMethod gMethods[] = { + { "initLws", "()Z", (void*)jni_initLws }, + { "exitLws", "()V", (void*)jni_exitLws }, + { "serviceLws", "()V", (void*)jni_serviceLws }, + { "setConnectionParameters", "(Ljava/lang/String;I)V", (void*)jni_setConnectionParameters }, + { "connectLws", "()Z", (void*)jni_connectLws }, +}; + +static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* gMethods, int numMethods) +{ + jclass cls; + cls = env->FindClass(className); + if(cls == NULL) { + return JNI_FALSE; + } + if (env->RegisterNatives(cls, gMethods, numMethods) < 0) { + return JNI_FALSE; + } + + return JNI_TRUE; +} + +static int registerNatives(JNIEnv* env) +{ + if(!registerNativeMethods(env, JNIREG_CLASS, gMethods, sizeof(gMethods) / sizeof(gMethods[0]))) { + return JNI_FALSE; + } + return JNI_TRUE; +} + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void * reserved) { + jint result = -1; + + gJvm = vm; + if(vm->GetEnv((void**)&gEnv, JNI_VERSION_1_6) != JNI_OK) goto bail; + if(vm->AttachCurrentThread(&gEnv, NULL) < 0) goto bail; + if(registerNatives(gEnv) != JNI_TRUE) goto bail; + + result = JNI_VERSION_1_6; + +bail: + return result; +} + +JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) { + gJvm = NULL; +} + +//////////////////////////////////////////////////// +// JNI functions to export: // +//////////////////////////////////////////////////// + +static jclass gLwsServiceCls; +static jobject gLwsServiceObj; +static jmethodID sendMessageId; + +static const int MSG_DUMB_INCREMENT_PROTOCOL_COUNTER = 1; +static const int MSG_LWS_CALLBACK_CLIENT_CONNECTION_ERROR = 2; +static const int MSG_LWS_CALLBACK_CLIENT_ESTABLISHED = 3; + +#define BUFFER_SIZE 4096 + +static struct lws_context *context = NULL; +static struct lws_context_creation_info info; +static struct lws *wsi = NULL; + +// prevents sending messages after jni_exitLws had been called +static int isExit = 0; + +enum websocket_protocols { + PROTOCOL_DUMB_INCREMENT = 0, + PROTOCOL_COUNT +}; + +struct per_session_data { + ;// no data +}; + +static int callback( struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len ); + +static struct lws_protocols protocols[] = { + { + "dumb-increment-protocol", + callback, + sizeof( struct per_session_data ), + BUFFER_SIZE, + }, + { NULL, NULL, 0, 0 } // end of list +}; + +static const struct lws_extension exts[] = { + { + "deflate-frame", + lws_extension_callback_pm_deflate, + "deflate_frame" + }, + { NULL, NULL, NULL } +}; + +static int port = 0; +static int use_ssl = 0; +static int use_ssl_client = 0; +static char address[8192]; + +static char ca_cert[8192]; +static char client_cert[8192]; +static char client_cert_key[8192]; + +static int deny_deflate = 0; +static int deny_mux = 0; + +// Logging function for libwebsockets +static void emit_log(int level, const char *msg) +{ + printf("%s", msg); +} + + +JNIEXPORT jboolean JNICALL jni_initLws(JNIEnv *env, jobject obj) +{ + if(context) return JNI_TRUE; + + // Attach the java virtual machine to this thread + gJvm->AttachCurrentThread(&gEnv, NULL); + + // Set java global references to the class and object + jclass cls = env->GetObjectClass(obj); + gLwsServiceCls = (jclass) env->NewGlobalRef(cls); + gLwsServiceObj = env->NewGlobalRef(obj); + + // Get the sendMessage method from the LwsService class (inherited from class ThreadService) + sendMessageId = gEnv->GetMethodID(gLwsServiceCls, "sendMessage", "(ILjava/lang/Object;)V"); + + memset(&info, 0, sizeof(info)); + info.port = CONTEXT_PORT_NO_LISTEN; + info.protocols = protocols; +#ifndef LWS_NO_EXTENSIONS + info.extensions = exts; +#endif + info.gid = -1; + info.uid = -1; + + lws_set_log_level( LLL_NOTICE | LLL_INFO | LLL_ERR | LLL_WARN | LLL_CLIENT, emit_log ); + + context = lws_create_context(&info); + if( context == NULL ){ + emit_log(LLL_ERR, "Creating libwebsocket context failed"); + return JNI_FALSE; + } + + isExit = 0; + + return JNI_TRUE; +} + +// Send a message to the client of the service +// (must call jni_initLws() first) +static inline void sendMessage(int id, jobject obj) +{ + if(!isExit) gEnv->CallVoidMethod(gLwsServiceObj, sendMessageId, id, obj); +} + +JNIEXPORT void JNICALL jni_exitLws(JNIEnv *env, jobject obj) +{ + if(context){ + isExit = 1; + lws_context_destroy(context); + context = NULL; + env->DeleteGlobalRef(gLwsServiceObj); + env->DeleteGlobalRef(gLwsServiceCls); + } +} + +static int callback( + struct lws *wsi, + enum lws_callback_reasons reason, + void *user, + void *in, + size_t len +) +{ + switch(reason){ + + case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: + sendMessage(MSG_LWS_CALLBACK_CLIENT_CONNECTION_ERROR, NULL); + break; + + case LWS_CALLBACK_CLIENT_ESTABLISHED: + sendMessage(MSG_LWS_CALLBACK_CLIENT_ESTABLISHED, NULL); + break; + + case LWS_CALLBACK_CLIENT_RECEIVE: + ((char *)in)[len] = '\0'; + sendMessage(MSG_DUMB_INCREMENT_PROTOCOL_COUNTER, gEnv->NewStringUTF((const char*)in)); + break; + + case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: + if ((strcmp((const char*)in, "deflate-stream") == 0) && deny_deflate) { + emit_log(LLL_ERR, "websocket: denied deflate-stream extension"); + return 1; + } + if ((strcmp((const char*)in, "deflate-frame") == 0) && deny_deflate) { + emit_log(LLL_ERR, "websocket: denied deflate-frame extension"); + return 1; + } + if ((strcmp((const char*)in, "x-google-mux") == 0) && deny_mux) { + emit_log(LLL_ERR, "websocket: denied x-google-mux extension"); + return 1; + } + break; + + default: + break; + } + + return 0; +} + +JNIEXPORT void JNICALL jni_serviceLws(JNIEnv *env, jobject obj) +{ + if(context){ + lws_service( context, 0 ); + } +} + +JNIEXPORT void JNICALL jni_setConnectionParameters( + JNIEnv *env, + jobject obj, + jstring serverAddress, + jint serverPort +) +{ + address[0] = 0; + port = serverPort; + use_ssl = 0; + use_ssl_client = 0; + snprintf(address, sizeof(address), "%s", env->GetStringUTFChars(serverAddress, 0)); +} + +JNIEXPORT jboolean JNICALL jni_connectLws(JNIEnv *env, jobject obj) +{ + struct lws_client_connect_info info_ws; + memset(&info_ws, 0, sizeof(info_ws)); + + info_ws.port = port; + info_ws.address = address; + info_ws.path = "/"; + info_ws.context = context; + info_ws.ssl_connection = use_ssl; + info_ws.host = address; + info_ws.origin = address; + info_ws.ietf_version_or_minus_one = -1; + info_ws.client_exts = exts; + info_ws.protocol = protocols[PROTOCOL_DUMB_INCREMENT].name; + + // connect + wsi = lws_client_connect_via_info(&info_ws); + if(wsi == NULL ){ + // Error + emit_log(LLL_ERR, "Protocol failed to connect."); + return JNI_FALSE; + } + + return JNI_TRUE; +} diff --git a/test-apps/android/app/src/main/jni/NativeLibs.mk b/test-apps/android/app/src/main/jni/NativeLibs.mk new file mode 100644 index 0000000..14816de --- /dev/null +++ b/test-apps/android/app/src/main/jni/NativeLibs.mk @@ -0,0 +1,1324 @@ +# +# GNU Make makefile for building static libraries for use with the Android NDK +# Copyright (C) 2016, Alexander Bruines +# +# 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. +# + +# +# This makefile is fully intergrated with this Android Studio project and +# it will be called automaticaly when you build the project with Gradle. +# +# The source packages for the libraries will be automaticaly downloaded. +# Alternativly you can provide your own sources by placing the following +# files in the 'jni' directory: +# +# zlib-1.2.8.tar.gz +# openssl-1.0.2g.tar.gz +# libwebsockets.tar.gz +# +# This makefile was tested with the latest NDK/SDK and Android Studio at the +# time of this writing. As these software packages evolve changes to this +# makefile may be needed or it may become obselete... +# +# This makefile was made for use in Linux but you may be able to edit it +# and make it work under Windows. +# +# At least on Debian, building openssl requires package xutils-dev +# for makedepend. Ofcourse the standard development packages must also be +# installed, but xutils-dev is not that obvious in this case... +# +# Makedepend will most likely print a lot of warnings during the 'make depend' +# stage of building openssl. In this case these warnings can be safely ignored. +# + +# Include Application.mk but do not complain if it is not found +# +ifeq ($(MAKE_NO_INCLUDES),) +-include Application.mk +endif + +# Location of the NDK. +# +ifeq ($(NDK_ROOT),) +NDK_ROOT := /opt/Android/SDK/ndk-bundle +endif + +# Select the ABIs to compile for +# +NDK_APP_ABI = $(APP_ABI) +ifeq ($(NDK_APP_ABI),) +# Set to 'all' if APP_ABI is undefined +NDK_APP_ABI = all +endif +ifeq ($(NDK_APP_ABI),all) +# Translate 'all' to the individual targets +NDK_APP_ABI = armeabi armeabi-v7a arm64-v8a mips mips64 x86 x86_64 +else +# Use the targets from APP_ABI +NDK_APP_ABI = $(APP_ABI) +endif + +# Select the Android platform to compile for +# +ifeq ($(APP_PLATFORM),) +# use a level that supports all specified ABIs if none was specified +APP_PLATFORM = android-21 +endif + +NDK_MAKE_TOOLCHAIN := $(NDK_ROOT)/build/tools/make_standalone_toolchain.py + +# +# The source packages we want/need +# Zlib and openssl should be defined in Application.mk, libwebsockets is +# cloned from github +# + +ifeq ($(ZLIB_VERSION),) +ZLIB_VERSION := 1.2.8 +endif +ifeq ($(OPENSSL_VERSION),) +OPENSSL_VERSION := 1.0.2g +endif + +ifeq ($(ZLIB_TGZ_SOURCE),) +ZLIB_TGZ_SOURCE := zlib-$(ZLIB_VERSION).tar.gz +endif +ifeq ($(OPENSSL_TGZ_SOURCE),) +OPENSSL_TGZ_SOURCE := openssl-$(OPENSSL_VERSION).tar.gz +endif +LIBWEBSOCKETS_TGZ_SOURCE := libwebsockets.tar.gz + +# The names of the directories in the source tgz files +ZLIB_DIR := $(basename $(basename $(ZLIB_TGZ_SOURCE))) +OPENSSL_DIR := $(basename $(basename $(OPENSSL_TGZ_SOURCE))) +LIBWEBSOCKETS_DIR := $(basename $(basename $(LIBWEBSOCKETS_TGZ_SOURCE))) + +# The URLs used to fetch the source tgz files +ZLIB_TGZ_URL := http://prdownloads.sourceforge.net/libpng/$(ZLIB_TGZ_SOURCE) +OPENSSL_TGZ_URL := https://openssl.org/source/$(OPENSSL_TGZ_SOURCE) +ifeq ($(LIBWEBSOCKETS_GIT_URL),) +LIBWEBSOCKETS_GIT_URL := https://github.com/warmcat/libwebsockets.git +endif + +# These values are the same as the values for $TARGET_ARCH_ABI in Android.mk +# This way 'make $TARGET_ARCH_ABI' builds libraries for that ABI. +# This is also the name for the directory where the libraries are installed to. +# +TARGET_X86 := x86 +TARGET_X86_64 := x86_64 +TARGET_ARM := armeabi +TARGET_ARM_V7A := armeabi-v7a +TARGET_ARM_V7A_HARD := armeabi-v7a-hard +TARGET_ARM64_V8A := arm64-v8a +TARGET_MIPS := mips +TARGET_MIPS64 := mips64 + +# The Android NDK API version to build the libraries with. +# +# android-9 ... android-19 support arm mips and x86 +# android-21 and higher also support arm64 mips64 and x86_64 +# +# These should be set to the same value as APP_PLATFORM (Application.mk) +# +# http://developer.android.com/ndk/guides/stable_apis.html +# +# If you change these or APP_PLATFORM you must do a 'make clean' +# +# Note: +# libraries compiled for android-21 and upwards are incompatible with devices below that version! +# http://stackoverflow.com/questions/28740315/android-ndk-getting-java-lang-unsatisfiedlinkerror-dlopen-failed-cannot-loca +# +TARGET_X86_NDK_API := $(subst android-,,$(APP_PLATFORM)) +TARGET_X86_64_NDK_API := $(subst android-,,$(APP_PLATFORM)) +TARGET_ARM_NDK_API := $(subst android-,,$(APP_PLATFORM)) +TARGET_ARM_V7A_NDK_API := $(subst android-,,$(APP_PLATFORM)) +TARGET_ARM_V7A_HARD_NDK_API := $(subst android-,,$(APP_PLATFORM)) +TARGET_ARM64_V8A_NDK_API := $(subst android-,,$(APP_PLATFORM)) +TARGET_MIPS_NDK_API := $(subst android-,,$(APP_PLATFORM)) +TARGET_MIPS64_NDK_API := $(subst android-,,$(APP_PLATFORM)) + +# The configure arguments to pass to the OpenSSL Configure script +# (--prefix and --openssldir are added automaticaly). +# (note: use no-asm on x86 and x86_64 to generate fully position independent code) +# +# x86 +TARGET_X86_OPENSSL_CONFIG_TARGET := android-x86 +TARGET_X86_OPENSSL_CONFIG := no-asm no-shared no-idea no-mdc2 no-rc5 no-zlib no-zlib-dynamic enable-tlsext no-ssl2 no-ssl3 enable-ec enable-ecdh enable-ecp +# x86_64 +TARGET_X86_64_OPENSSL_CONFIG_TARGET := linux-x86_64 +TARGET_X86_64_OPENSSL_CONFIG := no-asm no-shared no-idea no-mdc2 no-rc5 no-zlib no-zlib-dynamic enable-tlsext no-ssl2 no-ssl3 enable-ec enable-ecdh enable-ecp enable-ec_nistp_64_gcc_128 +# armeabi +TARGET_ARM_OPENSSL_CONFIG_TARGET := android +TARGET_ARM_OPENSSL_CONFIG := no-shared no-idea no-mdc2 no-rc5 no-zlib no-zlib-dynamic enable-tlsext no-ssl2 no-ssl3 enable-ec enable-ecdh enable-ecp +# armeabi-v7a +TARGET_ARM_V7A_OPENSSL_CONFIG_TARGET := android-armv7 +TARGET_ARM_V7A_OPENSSL_CONFIG := no-shared no-idea no-mdc2 no-rc5 no-zlib no-zlib-dynamic enable-tlsext no-ssl2 no-ssl3 enable-ec enable-ecdh enable-ecp +# armeabi-v7a-hard +TARGET_ARM_V7A_HARD_OPENSSL_CONFIG_TARGET := android-armv7 +TARGET_ARM_V7A_HARD_OPENSSL_CONFIG := no-shared no-idea no-mdc2 no-rc5 no-zlib no-zlib-dynamic enable-tlsext no-ssl2 no-ssl3 enable-ec enable-ecdh enable-ecp +# arm64-v8a +TARGET_ARM64_V8A_OPENSSL_CONFIG_TARGET := android +TARGET_ARM64_V8A_OPENSSL_CONFIG := no-shared no-idea no-mdc2 no-rc5 no-zlib no-zlib-dynamic enable-tlsext no-ssl2 no-ssl3 enable-ec enable-ecdh enable-ecp +# mips +TARGET_MIPS_OPENSSL_CONFIG_TARGET := android-mips +TARGET_MIPS_OPENSSL_CONFIG := no-shared no-idea no-mdc2 no-rc5 no-zlib no-zlib-dynamic enable-tlsext no-ssl2 no-ssl3 enable-ec enable-ecdh enable-ecp +# mips64 +TARGET_MIPS64_OPENSSL_CONFIG_TARGET := android +TARGET_MIPS64_OPENSSL_CONFIG := no-shared no-idea no-mdc2 no-rc5 no-zlib no-zlib-dynamic enable-tlsext no-ssl2 no-ssl3 enable-ec enable-ecdh enable-ecp + +# The cmake configuration options for libwebsockets per target ABI, +# --prefix and openssl library/header paths are set automaticaly and +# the location of zlib should be picked up by CMake +# x86 +TARGET_X86_LWS_OPTIONS = \ + -DCMAKE_C_COMPILER=$(shell pwd)/$(TOOLCHAIN_X86)/bin/$(TOOLCHAIN_X86_PREFIX)-gcc \ + -DCMAKE_AR=$(shell pwd)/$(TOOLCHAIN_X86)/bin/$(TOOLCHAIN_X86_PREFIX)-ar \ + -DCMAKE_RANLIB=$(shell pwd)/$(TOOLCHAIN_X86)/bin/$(TOOLCHAIN_X86_PREFIX)-ranlib \ + -DCMAKE_C_FLAGS="$$CFLAGS" \ + -DLWS_WITH_SHARED=OFF \ + -DLWS_WITH_STATIC=ON \ + -DLWS_WITHOUT_DAEMONIZE=ON \ + -DLWS_WITHOUT_TESTAPPS=ON \ + -DLWS_IPV6=OFF \ + -DLWS_USE_BUNDLED_ZLIB=OFF \ + -DLWS_WITH_SSL=ON \ + -DLWS_WITH_HTTP2=ON \ + -DCMAKE_BUILD_TYPE=Release +# x86_64 +TARGET_X86_64_LWS_OPTIONS = \ + -DCMAKE_C_COMPILER=$(shell pwd)/$(TOOLCHAIN_X86_64)/bin/$(TOOLCHAIN_X86_64_PREFIX)-gcc \ + -DCMAKE_AR=$(shell pwd)/$(TOOLCHAIN_X86_64)/bin/$(TOOLCHAIN_X86_64_PREFIX)-ar \ + -DCMAKE_RANLIB=$(shell pwd)/$(TOOLCHAIN_X86_64)/bin/$(TOOLCHAIN_X86_64_PREFIX)-ranlib \ + -DCMAKE_C_FLAGS="$$CFLAGS" \ + -DLWS_WITH_SHARED=OFF \ + -DLWS_WITH_STATIC=ON \ + -DLWS_WITHOUT_DAEMONIZE=ON \ + -DLWS_WITHOUT_TESTAPPS=ON \ + -DLWS_IPV6=OFF \ + -DLWS_USE_BUNDLED_ZLIB=OFF \ + -DLWS_WITH_SSL=ON \ + -DLWS_WITH_HTTP2=ON \ + -DCMAKE_BUILD_TYPE=Release +# armeabi +TARGET_ARM_LWS_OPTIONS = \ + -DCMAKE_C_COMPILER=$(shell pwd)/$(TOOLCHAIN_ARM)/bin/$(TOOLCHAIN_ARM_PREFIX)-gcc \ + -DCMAKE_AR=$(shell pwd)/$(TOOLCHAIN_ARM)/bin/$(TOOLCHAIN_ARM_PREFIX)-ar \ + -DCMAKE_RANLIB=$(shell pwd)/$(TOOLCHAIN_ARM)/bin/$(TOOLCHAIN_ARM_PREFIX)-ranlib \ + -DCMAKE_C_FLAGS="$$CFLAGS" \ + -DLWS_WITH_SHARED=OFF \ + -DLWS_WITH_STATIC=ON \ + -DLWS_WITHOUT_DAEMONIZE=ON \ + -DLWS_WITHOUT_TESTAPPS=ON \ + -DLWS_IPV6=OFF \ + -DLWS_USE_BUNDLED_ZLIB=OFF \ + -DLWS_WITH_SSL=ON \ + -DLWS_WITH_HTTP2=ON \ + -DCMAKE_BUILD_TYPE=Release +# armeabi-v7a +TARGET_ARM_V7A_LWS_OPTIONS = \ + -DCMAKE_C_COMPILER=$(shell pwd)/$(TOOLCHAIN_ARM_V7A)/bin/$(TOOLCHAIN_ARM_V7A_PREFIX)-gcc \ + -DCMAKE_AR=$(shell pwd)/$(TOOLCHAIN_ARM_V7A)/bin/$(TOOLCHAIN_ARM_V7A_PREFIX)-ar \ + -DCMAKE_RANLIB=$(shell pwd)/$(TOOLCHAIN_ARM_V7A)/bin/$(TOOLCHAIN_ARM_V7A_PREFIX)-ranlib \ + -DCMAKE_C_FLAGS="$$CFLAGS" \ + -DLWS_WITH_SHARED=OFF \ + -DLWS_WITH_STATIC=ON \ + -DLWS_WITHOUT_DAEMONIZE=ON \ + -DLWS_WITHOUT_TESTAPPS=ON \ + -DLWS_IPV6=OFF \ + -DLWS_USE_BUNDLED_ZLIB=OFF \ + -DLWS_WITH_SSL=ON \ + -DLWS_WITH_HTTP2=ON \ + -DCMAKE_BUILD_TYPE=Release +# armeabi-v7a-hard +TARGET_ARM_V7A_HARD_LWS_OPTIONS = \ + -DCMAKE_C_COMPILER=$(shell pwd)/$(TOOLCHAIN_ARM_V7A_HARD)/bin/$(TOOLCHAIN_ARM_V7A_HARD_PREFIX)-gcc \ + -DCMAKE_AR=$(shell pwd)/$(TOOLCHAIN_ARM_V7A_HARD)/bin/$(TOOLCHAIN_ARM_V7A_HARD_PREFIX)-ar \ + -DCMAKE_RANLIB=$(shell pwd)/$(TOOLCHAIN_ARM_V7A_HARD)/bin/$(TOOLCHAIN_ARM_V7A_HARD_PREFIX)-ranlib \ + -DCMAKE_C_FLAGS="$$CFLAGS" \ + -DLWS_WITH_SHARED=OFF \ + -DLWS_WITH_STATIC=ON \ + -DLWS_WITHOUT_DAEMONIZE=ON \ + -DLWS_WITHOUT_TESTAPPS=ON \ + -DLWS_IPV6=OFF \ + -DLWS_USE_BUNDLED_ZLIB=OFF \ + -DLWS_WITH_SSL=ON \ + -DLWS_WITH_HTTP2=ON \ + -DCMAKE_BUILD_TYPE=Release +# arm64-v8a +TARGET_ARM64_V8A_LWS_OPTIONS = \ + -DCMAKE_C_COMPILER=$(shell pwd)/$(TOOLCHAIN_ARM64_V8A)/bin/$(TOOLCHAIN_ARM64_V8A_PREFIX)-gcc \ + -DCMAKE_AR=$(shell pwd)/$(TOOLCHAIN_ARM64_V8A)/bin/$(TOOLCHAIN_ARM64_V8A_PREFIX)-ar \ + -DCMAKE_RANLIB=$(shell pwd)/$(TOOLCHAIN_ARM64_V8A)/bin/$(TOOLCHAIN_ARM64_V8A_PREFIX)-ranlib \ + -DCMAKE_C_FLAGS="$$CFLAGS" \ + -DLWS_WITH_SHARED=OFF \ + -DLWS_WITH_STATIC=ON \ + -DLWS_WITHOUT_DAEMONIZE=ON \ + -DLWS_WITHOUT_TESTAPPS=ON \ + -DLWS_IPV6=OFF \ + -DLWS_USE_BUNDLED_ZLIB=OFF \ + -DLWS_WITH_SSL=ON \ + -DLWS_WITH_HTTP2=ON \ + -DCMAKE_BUILD_TYPE=Release +# mips +TARGET_MIPS_LWS_OPTIONS = \ + -DCMAKE_C_COMPILER=$(shell pwd)/$(TOOLCHAIN_MIPS)/bin/$(TOOLCHAIN_MIPS_PREFIX)-gcc \ + -DCMAKE_AR=$(shell pwd)/$(TOOLCHAIN_MIPS)/bin/$(TOOLCHAIN_MIPS_PREFIX)-ar \ + -DCMAKE_RANLIB=$(shell pwd)/$(TOOLCHAIN_MIPS)/bin/$(TOOLCHAIN_MIPS_PREFIX)-ranlib \ + -DCMAKE_C_FLAGS="$$CFLAGS" \ + -DLWS_WITH_SHARED=OFF \ + -DLWS_WITH_STATIC=ON \ + -DLWS_WITHOUT_DAEMONIZE=ON \ + -DLWS_WITHOUT_TESTAPPS=ON \ + -DLWS_IPV6=OFF \ + -DLWS_USE_BUNDLED_ZLIB=OFF \ + -DLWS_WITH_SSL=ON \ + -DLWS_WITH_HTTP2=ON \ + -DCMAKE_BUILD_TYPE=Release +# mips64 +TARGET_MIPS64_LWS_OPTIONS = \ + -DCMAKE_C_COMPILER=$(shell pwd)/$(TOOLCHAIN_MIPS64)/bin/$(TOOLCHAIN_MIPS64_PREFIX)-gcc \ + -DCMAKE_AR=$(shell pwd)/$(TOOLCHAIN_MIPS64)/bin/$(TOOLCHAIN_MIPS64_PREFIX)-ar \ + -DCMAKE_RANLIB=$(shell pwd)/$(TOOLCHAIN_MIPS64)/bin/$(TOOLCHAIN_MIPS64_PREFIX)-ranlib \ + -DCMAKE_C_FLAGS="$$CFLAGS" \ + -DLWS_WITH_SHARED=OFF \ + -DLWS_WITH_STATIC=ON \ + -DLWS_WITHOUT_DAEMONIZE=ON \ + -DLWS_WITHOUT_TESTAPPS=ON \ + -DLWS_IPV6=OFF \ + -DLWS_USE_BUNDLED_ZLIB=OFF \ + -DLWS_WITH_SSL=ON \ + -DLWS_WITH_HTTP2=ON \ + -DCMAKE_BUILD_TYPE=Release + +# +# Toolchain configuration +# + +# The directory names for the different toolchains +TOOLCHAIN_X86 := toolchains/x86 +TOOLCHAIN_X86_64 := toolchains/x86_64 +TOOLCHAIN_ARM := toolchains/arm +TOOLCHAIN_ARM_V7A := toolchains/arm-v7a +TOOLCHAIN_ARM_V7A_HARD := toolchains/arm-v7a-hard +TOOLCHAIN_ARM64_V8A := toolchains/arm64-v8a +TOOLCHAIN_MIPS := toolchains/mips +TOOLCHAIN_MIPS64 := toolchains/mips64 + +# Use APP_STL to determine what STL to use. +# +ifeq ($(APP_STL),stlport_static) +TOOLCHAIN_STL := stlport +else ifeq ($(APP_STL),stlport_shared) +TOOLCHAIN_STL := stlport +else ifeq ($(APP_STL),gnustl_static) +TOOLCHAIN_STL := gnustl +else ifeq ($(APP_STL),gnustl_shared) +TOOLCHAIN_STL := gnustl +else ifeq ($(APP_STL),c++_static) +TOOLCHAIN_STL := libc++ +else ifeq ($(APP_STL),c++_shared) +TOOLCHAIN_STL := libc++ +endif + +# The settings to use for the individual toolchains: +# x86 +TOOLCHAIN_X86_API := $(TARGET_X86_NDK_API) +TOOLCHAIN_X86_PREFIX := i686-linux-android +TOOLCHAIN_X86_FLAGS := -march=i686 -msse3 -mstackrealign -mfpmath=sse +TOOLCHAIN_X86_LINK := +TOOLCHAIN_X86_PLATFORM_HEADERS := $(shell pwd)/$(TOOLCHAIN_X86)/sysroot/usr/include +TOOLCHAIN_X86_PLATFORM_LIBS := $(shell pwd)/$(TOOLCHAIN_X86)/sysroot/usr/lib +# x86_64 +TOOLCHAIN_X86_64_API := $(TARGET_X86_64_NDK_API) +TOOLCHAIN_X86_64_PREFIX := x86_64-linux-android +TOOLCHAIN_X86_64_FLAGS := +TOOLCHAIN_X86_64_LINK := +TOOLCHAIN_X86_64_PLATFORM_HEADERS := $(shell pwd)/$(TOOLCHAIN_X86_64)/sysroot/usr/include +TOOLCHAIN_X86_64_PLATFORM_LIBS := $(shell pwd)/$(TOOLCHAIN_X86_64)/sysroot/usr/lib +# arm +TOOLCHAIN_ARM_API := $(TARGET_ARM_NDK_API) +TOOLCHAIN_ARM_PREFIX := arm-linux-androideabi +TOOLCHAIN_ARM_FLAGS := -mthumb +TOOLCHAIN_ARM_LINK := +TOOLCHAIN_ARM_PLATFORM_HEADERS := $(shell pwd)/$(TOOLCHAIN_ARM)/sysroot/usr/include +TOOLCHAIN_ARM_PLATFORM_LIBS := $(shell pwd)/$(TOOLCHAIN_ARM)/sysroot/usr/lib +# arm-v7a +TOOLCHAIN_ARM_V7A_API := $(TARGET_ARM_V7A_NDK_API) +TOOLCHAIN_ARM_V7A_PREFIX := arm-linux-androideabi +TOOLCHAIN_ARM_V7A_FLAGS := -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 +TOOLCHAIN_ARM_V7A_LINK := -march=armv7-a -Wl,--fix-cortex-a8 +TOOLCHAIN_ARM_V7A_PLATFORM_HEADERS := $(shell pwd)/$(TOOLCHAIN_ARM_V7A)/sysroot/usr/include +TOOLCHAIN_ARM_V7A_PLATFORM_LIBS := $(shell pwd)/$(TOOLCHAIN_ARM_V7A)/sysroot/usr/lib +# arm-v7a-hard +TOOLCHAIN_ARM_V7A_HARD_API := $(TARGET_ARM_V7A_HARD_NDK_API) +TOOLCHAIN_ARM_V7A_HARD_PREFIX := arm-linux-androideabi +TOOLCHAIN_ARM_V7A_HARD_FLAGS := -march=armv7-a -mfpu=vfpv3-d16 -mhard-float -mfloat-abi=hard -D_NDK_MATH_NO_SOFTFP=1 +TOOLCHAIN_ARM_V7A_HARD_LINK := -march=armv7-a -Wl,--fix-cortex-a8 -Wl,--no-warn-mismatch -lm_hard +TOOLCHAIN_ARM_V7A_HARD_PLATFORM_HEADERS := $(shell pwd)/$(TOOLCHAIN_ARM_V7A_HARD)/sysroot/usr/include +TOOLCHAIN_ARM_V7A_HARD_PLATFORM_LIBS := $(shell pwd)/$(TOOLCHAIN_ARM_V7A_HARD)/sysroot/usr/lib +# arm64-v8a +TOOLCHAIN_ARM64_V8A_API := $(TARGET_ARM64_V8A_NDK_API) +TOOLCHAIN_ARM64_V8A_PREFIX := aarch64-linux-android +TOOLCHAIN_ARM64_V8A_FLAGS := +TOOLCHAIN_ARM64_V8A_LINK := +TOOLCHAIN_ARM64_V8A_PLATFORM_HEADERS := $(shell pwd)/$(TOOLCHAIN_ARM64_V8A)/sysroot/usr/include +TOOLCHAIN_ARM64_V8A_PLATFORM_LIBS := $(shell pwd)/$(TOOLCHAIN_ARM64_V8A)/sysroot/usr/lib +# mips +TOOLCHAIN_MIPS_API := $(TARGET_MIPS_NDK_API) +TOOLCHAIN_MIPS_PREFIX := mipsel-linux-android +TOOLCHAIN_MIPS_FLAGS := +TOOLCHAIN_MIPS_LINK := +TOOLCHAIN_MIPS_PLATFORM_HEADERS := $(shell pwd)/$(TOOLCHAIN_MIPS)/sysroot/usr/include +TOOLCHAIN_MIPS_PLATFORM_LIBS := $(shell pwd)/$(TOOLCHAIN_MIPS)/sysroot/usr/lib +# mips64 +TOOLCHAIN_MIPS64_API := $(TARGET_MIPS64_NDK_API) +TOOLCHAIN_MIPS64_PREFIX := mips64el-linux-android +TOOLCHAIN_MIPS64_FLAGS := +TOOLCHAIN_MIPS64_LINK := +TOOLCHAIN_MIPS64_PLATFORM_HEADERS := $(shell pwd)/$(TOOLCHAIN_MIPS64)/sysroot/usr/include +TOOLCHAIN_MIPS64_PLATFORM_LIBS := $(shell pwd)/$(TOOLCHAIN_MIPS64)/sysroot/usr/lib + +# Environment variables to set while compiling for each ABI +# x86 +TOOLCHAIN_X86_ENV = \ + ANDROID_DEV="$(shell pwd)/$(TOOLCHAIN_X86)/bin" \ + CC=$(TOOLCHAIN_X86_PREFIX)-gcc \ + CXX=$(TOOLCHAIN_X86_PREFIX)-g++ \ + LINK=$(TOOLCHAIN_X86_PREFIX)-g++ \ + LD=$(TOOLCHAIN_X86_PREFIX)-ld \ + AR=$(TOOLCHAIN_X86_PREFIX)-ar \ + RANLIB=$(TOOLCHAIN_X86_PREFIX)-ranlib \ + STRIP=$(TOOLCHAIN_X86_PREFIX)-strip \ + ARCH_FLAGS="$(TOOLCHAIN_X86_FLAGS)" \ + ARCH_LINK="$(TOOLCHAIN_X86_LINK)" \ + CPPFLAGS="-I. $(TOOLCHAIN_X86_FLAGS) -I$(TOOLCHAIN_X86_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64" \ + CXXFLAGS="-I. $(TOOLCHAIN_X86_FLAGS) -I$(TOOLCHAIN_X86_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64 -frtti -fexceptions" \ + CFLAGS="-I. $(TOOLCHAIN_X86_FLAGS) -I$(TOOLCHAIN_X86_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64" \ + LDFLAGS="$(TOOLCHAIN_X86_LINK)" \ + PATH="$(shell pwd)/$(TOOLCHAIN_X86)/bin:$$PATH" +# x86_64 +TOOLCHAIN_X86_64_ENV = \ + ANDROID_DEV="$(shell pwd)/$(TOOLCHAIN_X86_64)/bin" \ + CC=$(TOOLCHAIN_X86_64_PREFIX)-gcc \ + CXX=$(TOOLCHAIN_X86_64_PREFIX)-g++ \ + LINK=$(TOOLCHAIN_X86_64_PREFIX)-g++ \ + LD=$(TOOLCHAIN_X86_64_PREFIX)-ld \ + AR=$(TOOLCHAIN_X86_64_PREFIX)-ar \ + RANLIB=$(TOOLCHAIN_X86_64_PREFIX)-ranlib \ + STRIP=$(TOOLCHAIN_X86_64_PREFIX)-strip \ + ARCH_FLAGS="$(TOOLCHAIN_X86_64_FLAGS)" \ + ARCH_LINK="$(TOOLCHAIN_X86_64_LINK)" \ + CPPFLAGS="-I. $(TOOLCHAIN_X86_64_FLAGS) -I$(TOOLCHAIN_X86_64_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64" \ + CXXFLAGS="-I. $(TOOLCHAIN_X86_64_FLAGS) -I$(TOOLCHAIN_X86_64_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64 -frtti -fexceptions" \ + CFLAGS="-I. $(TOOLCHAIN_X86_64_FLAGS) -I$(TOOLCHAIN_X86_64_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64" \ + LDFLAGS="$(TOOLCHAIN_X86_64_LINK)" \ + PATH="$(shell pwd)/$(TOOLCHAIN_X86_64)/bin:$$PATH" +# arm +TOOLCHAIN_ARM_ENV = \ + ANDROID_DEV="$(shell pwd)/$(TOOLCHAIN_ARM)/bin" \ + CC=$(TOOLCHAIN_ARM_PREFIX)-gcc \ + CXX=$(TOOLCHAIN_ARM_PREFIX)-g++ \ + LINK=$(TOOLCHAIN_ARM_PREFIX)-g++ \ + LD=$(TOOLCHAIN_ARM_PREFIX)-ld \ + AR=$(TOOLCHAIN_ARM_PREFIX)-ar \ + RANLIB=$(TOOLCHAIN_ARM_PREFIX)-ranlib \ + STRIP=$(TOOLCHAIN_ARM_PREFIX)-strip \ + ARCH_FLAGS="$(TOOLCHAIN_ARM_FLAGS)" \ + ARCH_LINK="$(TOOLCHAIN_ARM_LINK)" \ + CPPFLAGS="-I. $(TOOLCHAIN_ARM_FLAGS) -I$(TOOLCHAIN_ARM_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64" \ + CXXFLAGS="-I. $(TOOLCHAIN_ARM_FLAGS) -I$(TOOLCHAIN_ARM_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64 -frtti -fexceptions" \ + CFLAGS="-I. $(TOOLCHAIN_ARM_FLAGS) -I$(TOOLCHAIN_ARM_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64" \ + LDFLAGS="$(TOOLCHAIN_ARM_LINK)" \ + PATH="$(shell pwd)/$(TOOLCHAIN_ARM)/bin:$$PATH" +# arm-v7a +TOOLCHAIN_ARM_V7A_ENV = \ + ANDROID_DEV="$(shell pwd)/$(TOOLCHAIN_ARM_V7A)/bin" \ + CC=$(TOOLCHAIN_ARM_V7A_PREFIX)-gcc \ + CXX=$(TOOLCHAIN_ARM_V7A_PREFIX)-g++ \ + LINK=$(TOOLCHAIN_ARM_V7A_PREFIX)-g++ \ + LD=$(TOOLCHAIN_ARM_V7A_PREFIX)-ld \ + AR=$(TOOLCHAIN_ARM_V7A_PREFIX)-ar \ + RANLIB=$(TOOLCHAIN_ARM_V7A_PREFIX)-ranlib \ + STRIP=$(TOOLCHAIN_ARM_V7A_PREFIX)-strip \ + ARCH_FLAGS="$(TOOLCHAIN_ARM_V7A_FLAGS)" \ + ARCH_LINK="$(TOOLCHAIN_ARM_V7A_LINK)" \ + CPPFLAGS="-I. $(TOOLCHAIN_ARM_V7A_FLAGS) -I$(TOOLCHAIN_ARM_V7A_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64" \ + CXXFLAGS="-I. $(TOOLCHAIN_ARM_V7A_FLAGS) -I$(TOOLCHAIN_ARM_V7A_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64 -frtti -fexceptions" \ + CFLAGS="-I. $(TOOLCHAIN_ARM_V7A_FLAGS) -I$(TOOLCHAIN_ARM_V7A_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64" \ + LDFLAGS="$(TOOLCHAIN_ARM_V7A_LINK)" \ + PATH="$(shell pwd)/$(TOOLCHAIN_ARM_V7A)/bin:$$PATH" +# arm-v7a-hard +TOOLCHAIN_ARM_V7A_HARD_ENV = \ + ANDROID_DEV="$(shell pwd)/$(TOOLCHAIN_ARM_V7A_HARD)/bin" \ + CC=$(TOOLCHAIN_ARM_V7A_HARD_PREFIX)-gcc \ + CXX=$(TOOLCHAIN_ARM_V7A_HARD_PREFIX)-g++ \ + LINK=$(TOOLCHAIN_ARM_V7A_HARD_PREFIX)-g++ \ + LD=$(TOOLCHAIN_ARM_V7A_HARD_PREFIX)-ld \ + AR=$(TOOLCHAIN_ARM_V7A_HARD_PREFIX)-ar \ + RANLIB=$(TOOLCHAIN_ARM_V7A_HARD_PREFIX)-ranlib \ + STRIP=$(TOOLCHAIN_ARM_V7A_HARD_PREFIX)-strip \ + ARCH_FLAGS="$(TOOLCHAIN_ARM_V7A_HARD_FLAGS)" \ + ARCH_LINK="$(TOOLCHAIN_ARM_V7A_HARD_LINK)" \ + CPPFLAGS="-I. $(TOOLCHAIN_ARM_V7A_HARD_FLAGS) -I$(TOOLCHAIN_ARM_V7A_HARD_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64" \ + CXXFLAGS="-I. $(TOOLCHAIN_ARM_V7A_HARD_FLAGS) -I$(TOOLCHAIN_ARM_V7A_HARD_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64 -frtti -fexceptions" \ + CFLAGS="-I. $(TOOLCHAIN_ARM_V7A_HARD_FLAGS) -I$(TOOLCHAIN_ARM_V7A_HARD_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64" \ + LDFLAGS="$(TOOLCHAIN_ARM_V7A_HARD_LINK)" \ + PATH="$(shell pwd)/$(TOOLCHAIN_ARM_V7A_HARD)/bin:$$PATH" +# arm64-v8a +TOOLCHAIN_ARM64_V8A_ENV = \ + ANDROID_DEV="$(shell pwd)/$(TOOLCHAIN_ARM64_V8A)/bin" \ + CC=$(TOOLCHAIN_ARM64_V8A_PREFIX)-gcc \ + CXX=$(TOOLCHAIN_ARM64_V8A_PREFIX)-g++ \ + LINK=$(TOOLCHAIN_ARM64_V8A_PREFIX)-g++ \ + LD=$(TOOLCHAIN_ARM64_V8A_PREFIX)-ld \ + AR=$(TOOLCHAIN_ARM64_V8A_PREFIX)-ar \ + RANLIB=$(TOOLCHAIN_ARM64_V8A_PREFIX)-ranlib \ + STRIP=$(TOOLCHAIN_ARM64_V8A_PREFIX)-strip \ + ARCH_FLAGS="$(TOOLCHAIN_ARM64_V8A_FLAGS)" \ + ARCH_LINK="$(TOOLCHAIN_ARM64_V8A_LINK)" \ + CPPFLAGS="-I. $(TOOLCHAIN_ARM64_V8A_FLAGS) -I$(TOOLCHAIN_ARM64_V8A_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64" \ + CXXFLAGS="-I. $(TOOLCHAIN_ARM64_V8A_FLAGS) -I$(TOOLCHAIN_ARM64_V8A_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64 -frtti -fexceptions" \ + CFLAGS="-I. $(TOOLCHAIN_ARM64_V8A_FLAGS) -I$(TOOLCHAIN_ARM64_V8A_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64" \ + LDFLAGS="$(TOOLCHAIN_ARM64_V8A_LINK)" \ + PATH="$(shell pwd)/$(TOOLCHAIN_ARM64_V8A)/bin:$$PATH" +# mips +TOOLCHAIN_MIPS_ENV = \ + ANDROID_DEV="$(shell pwd)/$(TOOLCHAIN_MIPS)/bin" \ + CC=$(TOOLCHAIN_MIPS_PREFIX)-gcc \ + CXX=$(TOOLCHAIN_MIPS_PREFIX)-g++ \ + LINK=$(TOOLCHAIN_MIPS_PREFIX)-g++ \ + LD=$(TOOLCHAIN_MIPS_PREFIX)-ld \ + AR=$(TOOLCHAIN_MIPS_PREFIX)-ar \ + RANLIB=$(TOOLCHAIN_MIPS_PREFIX)-ranlib \ + STRIP=$(TOOLCHAIN_MIPS_PREFIX)-strip \ + ARCH_FLAGS="$(TOOLCHAIN_MIPS_FLAGS)" \ + ARCH_LINK="$(TOOLCHAIN_MIPS_LINK)" \ + CPPFLAGS="-I. $(TOOLCHAIN_MIPS_FLAGS) -I$(TOOLCHAIN_MIPS_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64" \ + CXXFLAGS="-I. $(TOOLCHAIN_MIPS_FLAGS) -I$(TOOLCHAIN_MIPS_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64 -frtti -fexceptions" \ + CFLAGS="-I. $(TOOLCHAIN_MIPS_FLAGS) -I$(TOOLCHAIN_MIPS_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64" \ + LDFLAGS="$(TOOLCHAIN_MIPS_LINK)" \ + PATH="$(shell pwd)/$(TOOLCHAIN_MIPS)/bin:$$PATH" +# mips64 +TOOLCHAIN_MIPS64_ENV = \ + ANDROID_DEV="$(shell pwd)/$(TOOLCHAIN_MIPS64)/bin" \ + CC=$(TOOLCHAIN_MIPS64_PREFIX)-gcc \ + CXX=$(TOOLCHAIN_MIPS64_PREFIX)-g++ \ + LINK=$(TOOLCHAIN_MIPS64_PREFIX)-g++ \ + LD=$(TOOLCHAIN_MIPS64_PREFIX)-ld \ + AR=$(TOOLCHAIN_MIPS64_PREFIX)-ar \ + RANLIB=$(TOOLCHAIN_MIPS64_PREFIX)-ranlib \ + STRIP=$(TOOLCHAIN_MIPS64_PREFIX)-strip \ + ARCH_FLAGS="$(TOOLCHAIN_MIPS64_FLAGS)" \ + ARCH_LINK="$(TOOLCHAIN_MIPS64_LINK)" \ + CPPFLAGS="-I. $(TOOLCHAIN_MIPS64_FLAGS) -I$(TOOLCHAIN_MIPS64_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64" \ + CXXFLAGS="-I. $(TOOLCHAIN_MIPS64_FLAGS) -I$(TOOLCHAIN_MIPS64_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64 -frtti -fexceptions" \ + CFLAGS="-I. $(TOOLCHAIN_MIPS64_FLAGS) -I$(TOOLCHAIN_MIPS64_PLATFORM_HEADERS) -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64" \ + LDFLAGS="$(TOOLCHAIN_MIPS64_LINK)" \ + PATH="$(shell pwd)/$(TOOLCHAIN_MIPS64)/bin:$$PATH" + +# +# All the external tools we use in this Makefile +# + +AWK := awk +CD := cd +CMAKE := cmake +ECHO := echo +EGREP := egrep +GIT := git +LN := ln +MKDIR := mkdir +RM := rm +SORT := sort +TAR := tar +WGET := wget + +# +# End of user configurable options. +# + +.PHONY: \ + all \ + all-x86 \ + all-x86_64 \ + all-armeabi \ + all-armeabi-v7a \ + all-armeabi-v7a-hard \ + all-arm64-v8a \ + all-mips \ + all-mips64 \ + common \ + sources \ + toolchains \ + toolchain-x86 \ + toolchain-x86_64 \ + toolchain-armeabi \ + toolchain-armeabi-v7a \ + toolchain-armeabi-v7a-hard \ + toolchain-arm64-v8a \ + toolchain-mips \ + toolchain-mips64 \ + zlib \ + zlib-x86 \ + zlib-x86_64 \ + zlib-armeabi \ + zlib-armeabi-v7a \ + zlib-armeabi-v7a-hard \ + zlib-arm64-v8a \ + zlib-mips \ + zlib-mips64 \ + openssl \ + openssl-x86 \ + openssl-x86_64 \ + openssl-armeabi \ + openssl-armeabi-v7a \ + openssl-armeabi-v7a-hard \ + openssl-arm64-v8a \ + openssl-mips \ + openssl-mips64 \ + libwebsockets \ + libwebsockets-x86 \ + libwebsockets-x86_64 \ + libwebsockets-armeabi \ + libwebsockets-armeabi-v7a \ + libwebsockets-armeabi-v7a-hard \ + libwebsockets-arm64-v8a \ + libwebsockets-mips \ + libwebsockets-mips64 \ + clean-ndk \ + clean \ + dist-clean \ + clean-targets \ + clean-target-x86 \ + clean-target-x86_64 \ + clean-target-armeabi \ + clean-target-armeabi-v7a \ + clean-target-armeabi-v7a-hard \ + clean-target-arm64-v8a \ + clean-target-mips \ + clean-target-mips64 \ + clean-sources \ + clean-source-zlib \ + clean-source-openssl \ + clean-source-libwebsockets \ + clean-toolchains \ + clean-toolchain-x86 \ + clean-toolchain-x86_64 \ + clean-toolchain-armeabi \ + clean-toolchain-armeabi-v7a \ + clean-toolchain-armeabi-v7a-hard \ + clean-toolchain-arm64-v8a \ + clean-toolchain-mips \ + clean-toolchain-mips64 \ + list-targets + +# Default rule: build the libraries for all ABIs defined in NDK_APP_ABI then run ndk-build +all: $(NDK_APP_ABI) + $(NDK_ROOT)/ndk-build clean + $(NDK_ROOT)/ndk-build + +# Libraries may also be build per ABI +all-x86: $(TARGET_X86) +all-x86_64: $(TARGET_X86_64) +all-armeabi: $(TARGET_ARM) +all-armeabi-v7a: $(TARGET_ARM_V7A) +all-armeabi-v7a-hard: $(TARGET_ARM_V7A_HARD) +all-arm64-v8a: $(TARGET_ARM64_V8A) +all-mips: $(TARGET_MIPS) +all-mips64: $(TARGET_MIPS64) + +# Common rule all targets depend on +common: ../jniLibs + +# These rules are called from Android.mk when executing ndk-build +$(TARGET_X86): common zlib-x86 openssl-x86 libwebsockets-x86 +$(TARGET_X86_64): common zlib-x86_64 openssl-x86_64 libwebsockets-x86_64 +$(TARGET_ARM): common zlib-armeabi openssl-armeabi libwebsockets-armeabi +$(TARGET_ARM_V7A): common zlib-armeabi-v7a openssl-armeabi-v7a libwebsockets-armeabi-v7a +$(TARGET_ARM_V7A_HARD): common zlib-armeabi-v7a-hard openssl-armeabi-v7a-hard libwebsockets-armeabi-v7a-hard +$(TARGET_ARM64_V8A): common zlib-arm64-v8a openssl-arm64-v8a libwebsockets-arm64-v8a +$(TARGET_MIPS): common zlib-mips openssl-mips libwebsockets-mips +$(TARGET_MIPS64): common zlib-mips64 openssl-mips64 libwebsockets-mips64 + +# +# A rule to ensure ../jniLibs points to ../libs +# (ndk-build creates ../libs but Gradle looks for ../jniLibs) +# + +../libs: + $(MKDIR) ../libs + +../jniLibs: ../libs + $(CD) .. && $(LN) -s libs jniLibs + +# +# Some rules to download the sources +# + +sources: $(ZLIB_TGZ_SOURCE) $(OPENSSL_TGZ_SOURCE) $(LIBWEBSOCKETS_TGZ_SOURCE) + +$(ZLIB_TGZ_SOURCE): + $(WGET) -q $(ZLIB_TGZ_URL) + +$(OPENSSL_TGZ_SOURCE): + $(WGET) -q $(OPENSSL_TGZ_URL) + +$(LIBWEBSOCKETS_TGZ_SOURCE): + if [ -d $(LIBWEBSOCKETS_DIR) ]; then $(RM) -fr $(LIBWEBSOCKETS_DIR); fi + $(GIT) clone $(LIBWEBSOCKETS_GIT_URL) + $(TAR) caf $(LIBWEBSOCKETS_TGZ_SOURCE) $(LIBWEBSOCKETS_DIR) + $(RM) -fR $(LIBWEBSOCKETS_DIR) + +# +# Some rules to install the required toolchains +# + +toolchains: \ + toolchain-x86 \ + toolchain-x86_64 \ + toolchain-armeabi \ + toolchain-armeabi-v7a \ + toolchain-armeabi-v7a-hard \ + toolchain-arm64-v8a \ + toolchain-mips \ + toolchain-mips64 + +toolchain-x86: $(TOOLCHAIN_X86) +toolchain-x86_64: $(TOOLCHAIN_X86_64) +toolchain-armeabi: $(TOOLCHAIN_ARM) +toolchain-armeabi-v7a: $(TOOLCHAIN_ARM_V7A) +toolchain-armeabi-v7a-hard: $(TOOLCHAIN_ARM_V7A_HARD) +toolchain-arm64-v8a: $(TOOLCHAIN_ARM64_V8A) +toolchain-mips: $(TOOLCHAIN_MIPS) +toolchain-mips64: $(TOOLCHAIN_MIPS64) + +$(TOOLCHAIN_X86): +ifneq ($(TOOLCHAIN_STL),) + $(NDK_MAKE_TOOLCHAIN) \ + --stl $(TOOLCHAIN_STL) \ + --api $(TOOLCHAIN_X86_API) \ + --arch x86 \ + --install-dir $(shell pwd)/$(TOOLCHAIN_X86) +else + $(NDK_MAKE_TOOLCHAIN) \ + --api $(TOOLCHAIN_X86_API) \ + --arch x86 \ + --install-dir $(shell pwd)/$(TOOLCHAIN_X86) +endif + +$(TOOLCHAIN_X86_64): +ifneq ($(TOOLCHAIN_STL),) + $(NDK_MAKE_TOOLCHAIN) \ + --stl $(TOOLCHAIN_STL) \ + --api $(TOOLCHAIN_X86_64_API) \ + --arch x86_64 \ + --install-dir $(shell pwd)/$(TOOLCHAIN_X86_64) +else + $(NDK_MAKE_TOOLCHAIN) \ + --api $(TOOLCHAIN_X86_64_API) \ + --arch x86_64 \ + --install-dir $(shell pwd)/$(TOOLCHAIN_X86_64) +endif + +$(TOOLCHAIN_ARM): +ifneq ($(TOOLCHAIN_STL),) + $(NDK_MAKE_TOOLCHAIN) \ + --stl $(TOOLCHAIN_STL) \ + --api $(TOOLCHAIN_ARM_API) \ + --arch arm \ + --install-dir $(shell pwd)/$(TOOLCHAIN_ARM) +else + $(NDK_MAKE_TOOLCHAIN) \ + --api $(TOOLCHAIN_ARM_API) \ + --arch arm \ + --install-dir $(shell pwd)/$(TOOLCHAIN_ARM) +endif + +$(TOOLCHAIN_ARM_V7A): +ifneq ($(TOOLCHAIN_STL),) + $(NDK_MAKE_TOOLCHAIN) \ + --stl $(TOOLCHAIN_STL) \ + --api $(TOOLCHAIN_ARM_V7A_API) \ + --arch arm \ + --install-dir $(shell pwd)/$(TOOLCHAIN_ARM_V7A) +else + $(NDK_MAKE_TOOLCHAIN) \ + --api $(TOOLCHAIN_ARM_V7A_API) \ + --arch arm \ + --install-dir $(shell pwd)/$(TOOLCHAIN_ARM_V7A) +endif + +$(TOOLCHAIN_ARM_V7A_HARD): +ifneq ($(TOOLCHAIN_STL),) + $(NDK_MAKE_TOOLCHAIN) \ + --stl $(TOOLCHAIN_STL) \ + --api $(TOOLCHAIN_ARM_V7A_HARD_API) \ + --arch arm \ + --install-dir $(shell pwd)/$(TOOLCHAIN_ARM_V7A_HARD) +else + $(NDK_MAKE_TOOLCHAIN) \ + --api $(TOOLCHAIN_ARM_V7A_HARD_API) \ + --arch arm \ + --install-dir $(shell pwd)/$(TOOLCHAIN_ARM_V7A_HARD) +endif + +$(TOOLCHAIN_ARM64_V8A): +ifneq ($(TOOLCHAIN_STL),) + $(NDK_MAKE_TOOLCHAIN) \ + --stl $(TOOLCHAIN_STL) \ + --api $(TOOLCHAIN_ARM64_V8A_API) \ + --arch arm64 \ + --install-dir $(shell pwd)/$(TOOLCHAIN_ARM64_V8A) +else + $(NDK_MAKE_TOOLCHAIN) \ + --api $(TOOLCHAIN_ARM64_V8A_API) \ + --arch arm64 \ + --install-dir $(shell pwd)/$(TOOLCHAIN_ARM64_V8A) +endif + +$(TOOLCHAIN_MIPS): +ifneq ($(TOOLCHAIN_STL),) + $(NDK_MAKE_TOOLCHAIN) \ + --stl $(TOOLCHAIN_STL) \ + --api $(TOOLCHAIN_MIPS_API) \ + --arch mips \ + --install-dir $(shell pwd)/$(TOOLCHAIN_MIPS) +else + $(NDK_MAKE_TOOLCHAIN) \ + --api $(TOOLCHAIN_MIPS_API) \ + --arch mips \ + --install-dir $(shell pwd)/$(TOOLCHAIN_MIPS) +endif + +$(TOOLCHAIN_MIPS64): +ifneq ($(TOOLCHAIN_STL),) + $(NDK_MAKE_TOOLCHAIN) \ + --stl $(TOOLCHAIN_STL) \ + --api $(TOOLCHAIN_MIPS64_API) \ + --arch mips64 \ + --install-dir $(shell pwd)/$(TOOLCHAIN_MIPS64) +else + $(NDK_MAKE_TOOLCHAIN) \ + --api $(TOOLCHAIN_MIPS64_API) \ + --arch mips64 \ + --install-dir $(shell pwd)/$(TOOLCHAIN_MIPS64) +endif + +# +# Rules to build zlib +# + +zlib: \ + zlib-x86 \ + zlib-x86_64 \ + zlib-armeabi \ + zlib-armeabi-v7a \ + zlib-armeabi-v7a-hard \ + zlib-arm64-v8a \ + zlib-mips \ + zlib-mips64 + +zlib-x86: $(TARGET_X86)/lib/libz.a +zlib-x86_64: $(TARGET_X86_64)/lib/libz.a +zlib-armeabi: $(TARGET_ARM)/lib/libz.a +zlib-armeabi-v7a: $(TARGET_ARM_V7A)/lib/libz.a +zlib-armeabi-v7a-hard: $(TARGET_ARM_V7A_HARD)/lib/libz.a +zlib-arm64-v8a: $(TARGET_ARM64_V8A)/lib/libz.a +zlib-mips: $(TARGET_MIPS)/lib/libz.a +zlib-mips64: $(TARGET_MIPS64)/lib/libz.a + +# Extracting/configuring sources + +$(TARGET_X86)/src/$(ZLIB_DIR): $(ZLIB_TGZ_SOURCE) $(TOOLCHAIN_X86) + -$(MKDIR) -p $(TARGET_X86)/src + $(TAR) xf $(ZLIB_TGZ_SOURCE) -C $(TARGET_X86)/src + $(CD) $(TARGET_X86)/src/$(ZLIB_DIR) && $(TOOLCHAIN_X86_ENV) \ + ./configure --static --prefix=$(shell pwd)/$(TARGET_X86) + +$(TARGET_X86_64)/src/$(ZLIB_DIR): $(ZLIB_TGZ_SOURCE) $(TOOLCHAIN_X86_64) + -$(MKDIR) -p $(TARGET_X86_64)/src + $(TAR) xf $(ZLIB_TGZ_SOURCE) -C $(TARGET_X86_64)/src + $(CD) $(TARGET_X86_64)/src/$(ZLIB_DIR) && $(TOOLCHAIN_X86_64_ENV) \ + ./configure --static --prefix=$(shell pwd)/$(TARGET_X86_64) + +$(TARGET_ARM)/src/$(ZLIB_DIR): $(ZLIB_TGZ_SOURCE) $(TOOLCHAIN_ARM) + -$(MKDIR) -p $(TARGET_ARM)/src + $(TAR) xf $(ZLIB_TGZ_SOURCE) -C $(TARGET_ARM)/src + $(CD) $(TARGET_ARM)/src/$(ZLIB_DIR) && $(TOOLCHAIN_ARM_ENV) \ + ./configure --static --prefix=$(shell pwd)/$(TARGET_ARM) + +$(TARGET_ARM_V7A)/src/$(ZLIB_DIR): $(ZLIB_TGZ_SOURCE) $(TOOLCHAIN_ARM_V7A) + -$(MKDIR) -p $(TARGET_ARM_V7A)/src + $(TAR) xf $(ZLIB_TGZ_SOURCE) -C $(TARGET_ARM_V7A)/src + $(CD) $(TARGET_ARM_V7A)/src/$(ZLIB_DIR) && $(TOOLCHAIN_ARM_V7A_ENV) \ + ./configure --static --prefix=$(shell pwd)/$(TARGET_ARM_V7A) + +$(TARGET_ARM_V7A_HARD)/src/$(ZLIB_DIR): $(ZLIB_TGZ_SOURCE) $(TOOLCHAIN_ARM_V7A_HARD) + -$(MKDIR) -p $(TARGET_ARM_V7A_HARD)/src + $(TAR) xf $(ZLIB_TGZ_SOURCE) -C $(TARGET_ARM_V7A_HARD)/src + $(CD) $(TARGET_ARM_V7A_HARD)/src/$(ZLIB_DIR) && $(TOOLCHAIN_ARM_V7A_HARD_ENV) \ + ./configure --static --prefix=$(shell pwd)/$(TARGET_ARM_V7A_HARD) + +$(TARGET_ARM64_V8A)/src/$(ZLIB_DIR): $(ZLIB_TGZ_SOURCE) $(TOOLCHAIN_ARM64_V8A) + -$(MKDIR) -p $(TARGET_ARM64_V8A)/src + $(TAR) xf $(ZLIB_TGZ_SOURCE) -C $(TARGET_ARM64_V8A)/src + $(CD) $(TARGET_ARM64_V8A)/src/$(ZLIB_DIR) && $(TOOLCHAIN_ARM64_V8A_ENV) \ + ./configure --static --prefix=$(shell pwd)/$(TARGET_ARM64_V8A) + +$(TARGET_MIPS)/src/$(ZLIB_DIR): $(ZLIB_TGZ_SOURCE) $(TOOLCHAIN_MIPS) + -$(MKDIR) -p $(TARGET_MIPS)/src + $(TAR) xf $(ZLIB_TGZ_SOURCE) -C $(TARGET_MIPS)/src + $(CD) $(TARGET_MIPS)/src/$(ZLIB_DIR) && $(TOOLCHAIN_MIPS_ENV) \ + ./configure --static --prefix=$(shell pwd)/$(TARGET_MIPS) + +$(TARGET_MIPS64)/src/$(ZLIB_DIR): $(ZLIB_TGZ_SOURCE) $(TOOLCHAIN_MIPS64) + -$(MKDIR) -p $(TARGET_MIPS64)/src + $(TAR) xf $(ZLIB_TGZ_SOURCE) -C $(TARGET_MIPS64)/src + $(CD) $(TARGET_MIPS64)/src/$(ZLIB_DIR) && $(TOOLCHAIN_MIPS64_ENV) \ + ./configure --static --prefix=$(shell pwd)/$(TARGET_MIPS64) + +# Build/install library + +$(TARGET_X86)/lib/libz.a: $(TARGET_X86)/src/$(ZLIB_DIR) + $(CD) $(TARGET_X86)/src/$(ZLIB_DIR) && $(TOOLCHAIN_X86_ENV) $(MAKE) libz.a + $(CD) $(TARGET_X86)/src/$(ZLIB_DIR) && $(TOOLCHAIN_X86_ENV) $(MAKE) install + +$(TARGET_X86_64)/lib/libz.a: $(TARGET_X86_64)/src/$(ZLIB_DIR) + $(CD) $(TARGET_X86_64)/src/$(ZLIB_DIR) && $(TOOLCHAIN_X86_64_ENV) $(MAKE) libz.a + $(CD) $(TARGET_X86_64)/src/$(ZLIB_DIR) && $(TOOLCHAIN_X86_64_ENV) $(MAKE) install + +$(TARGET_ARM)/lib/libz.a: $(TARGET_ARM)/src/$(ZLIB_DIR) + $(CD) $(TARGET_ARM)/src/$(ZLIB_DIR) && $(TOOLCHAIN_ARM_ENV) $(MAKE) libz.a + $(CD) $(TARGET_ARM)/src/$(ZLIB_DIR) && $(TOOLCHAIN_ARM_ENV) $(MAKE) install + +$(TARGET_ARM_V7A)/lib/libz.a: $(TARGET_ARM_V7A)/src/$(ZLIB_DIR) + $(CD) $(TARGET_ARM_V7A)/src/$(ZLIB_DIR) && $(TOOLCHAIN_ARM_V7A_ENV) $(MAKE) libz.a + $(CD) $(TARGET_ARM_V7A)/src/$(ZLIB_DIR) && $(TOOLCHAIN_ARM_V7A_ENV) $(MAKE) install + +$(TARGET_ARM_V7A_HARD)/lib/libz.a: $(TARGET_ARM_V7A_HARD)/src/$(ZLIB_DIR) + $(CD) $(TARGET_ARM_V7A_HARD)/src/$(ZLIB_DIR) && $(TOOLCHAIN_ARM_V7A_HARD_ENV) $(MAKE) libz.a + $(CD) $(TARGET_ARM_V7A_HARD)/src/$(ZLIB_DIR) && $(TOOLCHAIN_ARM_V7A_HARD_ENV) $(MAKE) install + +$(TARGET_ARM64_V8A)/lib/libz.a: $(TARGET_ARM64_V8A)/src/$(ZLIB_DIR) + $(CD) $(TARGET_ARM64_V8A)/src/$(ZLIB_DIR) && $(TOOLCHAIN_ARM64_V8A_ENV) $(MAKE) libz.a + $(CD) $(TARGET_ARM64_V8A)/src/$(ZLIB_DIR) && $(TOOLCHAIN_ARM64_V8A_ENV) $(MAKE) install + +$(TARGET_MIPS)/lib/libz.a: $(TARGET_MIPS)/src/$(ZLIB_DIR) + $(CD) $(TARGET_MIPS)/src/$(ZLIB_DIR) && $(TOOLCHAIN_MIPS_ENV) $(MAKE) libz.a + $(CD) $(TARGET_MIPS)/src/$(ZLIB_DIR) && $(TOOLCHAIN_MIPS_ENV) $(MAKE) install + +$(TARGET_MIPS64)/lib/libz.a: $(TARGET_MIPS64)/src/$(ZLIB_DIR) + $(CD) $(TARGET_MIPS64)/src/$(ZLIB_DIR) && $(TOOLCHAIN_MIPS64_ENV) $(MAKE) libz.a + $(CD) $(TARGET_MIPS64)/src/$(ZLIB_DIR) && $(TOOLCHAIN_MIPS64_ENV) $(MAKE) install + +# +# Rules to build OpenSSL +# + +openssl: \ + openssl-x86 \ + openssl-x86_64 \ + openssl-armeabi \ + openssl-armeabi-v7a \ + openssl-armeabi-v7a-hard \ + openssl-arm64-v8a \ + openssl-mips \ + openssl-mips64 + +openssl-x86: $(TARGET_X86)/lib/libssl.a +openssl-x86_64: $(TARGET_X86_64)/lib/libssl.a +openssl-armeabi: $(TARGET_ARM)/lib/libssl.a +openssl-armeabi-v7a: $(TARGET_ARM_V7A)/lib/libssl.a +openssl-armeabi-v7a-hard: $(TARGET_ARM_V7A_HARD)/lib/libssl.a +openssl-arm64-v8a: $(TARGET_ARM64_V8A)/lib/libssl.a +openssl-mips: $(TARGET_MIPS)/lib/libssl.a +openssl-mips64: $(TARGET_MIPS64)/lib/libssl.a + +# Extracting/configuring sources + +$(TARGET_X86)/src/$(OPENSSL_DIR): $(OPENSSL_TGZ_SOURCE) $(TOOLCHAIN_X86) + -$(MKDIR) -p $(TARGET_X86)/src + $(TAR) xf $(OPENSSL_TGZ_SOURCE) -C $(TARGET_X86)/src + $(CD) $(TARGET_X86)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_X86_ENV) \ + ./Configure $(TARGET_X86_OPENSSL_CONFIG_TARGET) \ + --prefix=$(shell pwd)/$(TARGET_X86) \ + --openssldir=$(shell pwd)/$(TARGET_X86)/lib/ssl \ + $(TARGET_X86_OPENSSL_CONFIG) + +$(TARGET_X86_64)/src/$(OPENSSL_DIR): $(OPENSSL_TGZ_SOURCE) $(TOOLCHAIN_X86_64) + -$(MKDIR) -p $(TARGET_X86_64)/src + $(TAR) xf $(OPENSSL_TGZ_SOURCE) -C $(TARGET_X86_64)/src + $(CD) $(TARGET_X86_64)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_X86_64_ENV) \ + ./Configure $(TARGET_X86_64_OPENSSL_CONFIG_TARGET) \ + --prefix=$(shell pwd)/$(TARGET_X86_64) \ + --openssldir=$(shell pwd)/$(TARGET_X86_64)/lib/ssl \ + $(TARGET_X86_64_OPENSSL_CONFIG) + +$(TARGET_ARM)/src/$(OPENSSL_DIR): $(OPENSSL_TGZ_SOURCE) $(TOOLCHAIN_ARM) + -$(MKDIR) -p $(TARGET_ARM)/src + $(TAR) xf $(OPENSSL_TGZ_SOURCE) -C $(TARGET_ARM)/src + $(CD) $(TARGET_ARM)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_ARM_ENV) \ + ./Configure $(TARGET_ARM_OPENSSL_CONFIG_TARGET) \ + --prefix=$(shell pwd)/$(TARGET_ARM) \ + --openssldir=$(shell pwd)/$(TARGET_ARM)/lib/ssl \ + $(TARGET_ARM_OPENSSL_CONFIG) + +$(TARGET_ARM_V7A)/src/$(OPENSSL_DIR): $(OPENSSL_TGZ_SOURCE) $(TOOLCHAIN_ARM_V7A) + -$(MKDIR) -p $(TARGET_ARM_V7A)/src + $(TAR) xf $(OPENSSL_TGZ_SOURCE) -C $(TARGET_ARM_V7A)/src + $(CD) $(TARGET_ARM_V7A)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_ARM_V7A_ENV) \ + ./Configure $(TARGET_ARM_V7A_OPENSSL_CONFIG_TARGET) \ + --prefix=$(shell pwd)/$(TARGET_ARM_V7A) \ + --openssldir=$(shell pwd)/$(TARGET_ARM_V7A)/lib/ssl \ + $(TARGET_ARM_V7A_OPENSSL_CONFIG) + +$(TARGET_ARM_V7A_HARD)/src/$(OPENSSL_DIR): $(OPENSSL_TGZ_SOURCE) $(TOOLCHAIN_ARM_V7A_HARD) + -$(MKDIR) -p $(TARGET_ARM_V7A_HARD)/src + $(TAR) xf $(OPENSSL_TGZ_SOURCE) -C $(TARGET_ARM_V7A_HARD)/src + $(CD) $(TARGET_ARM_V7A_HARD)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_ARM_V7A_HARD_ENV) \ + ./Configure $(TARGET_ARM_V7A_HARD_OPENSSL_CONFIG_TARGET) \ + --prefix=$(shell pwd)/$(TARGET_ARM_V7A_HARD) \ + --openssldir=$(shell pwd)/$(TARGET_ARM_V7A_HARD)/lib/ssl \ + $(TARGET_ARM_V7A_HARD_OPENSSL_CONFIG) + +$(TARGET_ARM64_V8A)/src/$(OPENSSL_DIR): $(OPENSSL_TGZ_SOURCE) $(TOOLCHAIN_ARM64_V8A) + -$(MKDIR) -p $(TARGET_ARM64_V8A)/src + $(TAR) xf $(OPENSSL_TGZ_SOURCE) -C $(TARGET_ARM64_V8A)/src + $(CD) $(TARGET_ARM64_V8A)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_ARM64_V8A_ENV) \ + ./Configure $(TARGET_ARM64_V8A_OPENSSL_CONFIG_TARGET) \ + --prefix=$(shell pwd)/$(TARGET_ARM64_V8A) \ + --openssldir=$(shell pwd)/$(TARGET_ARM64_V8A)/lib/ssl \ + $(TARGET_ARM64_V8A_OPENSSL_CONFIG) + +$(TARGET_MIPS)/src/$(OPENSSL_DIR): $(OPENSSL_TGZ_SOURCE) $(TOOLCHAIN_MIPS) + -$(MKDIR) -p $(TARGET_MIPS)/src + $(TAR) xf $(OPENSSL_TGZ_SOURCE) -C $(TARGET_MIPS)/src + $(CD) $(TARGET_MIPS)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_MIPS_ENV) \ + ./Configure $(TARGET_MIPS_OPENSSL_CONFIG_TARGET) \ + --prefix=$(shell pwd)/$(TARGET_MIPS) \ + --openssldir=$(shell pwd)/$(TARGET_MIPS)/lib/ssl \ + $(TARGET_MIPS_OPENSSL_CONFIG) + +$(TARGET_MIPS64)/src/$(OPENSSL_DIR): $(OPENSSL_TGZ_SOURCE) $(TOOLCHAIN_MIPS64) + -$(MKDIR) -p $(TARGET_MIPS64)/src + $(TAR) xf $(OPENSSL_TGZ_SOURCE) -C $(TARGET_MIPS64)/src + $(CD) $(TARGET_MIPS64)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_MIPS64_ENV) \ + ./Configure $(TARGET_MIPS64_OPENSSL_CONFIG_TARGET) \ + --prefix=$(shell pwd)/$(TARGET_MIPS64) \ + --openssldir=$(shell pwd)/$(TARGET_MIPS64)/lib/ssl \ + $(TARGET_MIPS64_OPENSSL_CONFIG) + +# Build/install library + +$(TARGET_X86)/lib/libssl.a: $(TARGET_X86)/src/$(OPENSSL_DIR) + $(CD) $(TARGET_X86)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_X86_ENV) $(MAKE) depend + $(CD) $(TARGET_X86)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_X86_ENV) $(MAKE) build_libs + $(CD) $(TARGET_X86)/src/$(OPENSSL_DIR) && $(ECHO) '#!/bin/sh\n\nfalse\n' > apps/openssl + $(CD) $(TARGET_X86)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_X86_ENV) $(MAKE) install_sw + +$(TARGET_X86_64)/lib/libssl.a: $(TARGET_X86_64)/src/$(OPENSSL_DIR) + $(CD) $(TARGET_X86_64)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_X86_64_ENV) $(MAKE) depend + $(CD) $(TARGET_X86_64)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_X86_64_ENV) $(MAKE) build_libs + $(CD) $(TARGET_X86_64)/src/$(OPENSSL_DIR) && $(ECHO) '#!/bin/sh\n\nfalse\n' > apps/openssl + $(CD) $(TARGET_X86_64)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_X86_64_ENV) $(MAKE) install_sw + +$(TARGET_ARM)/lib/libssl.a: $(TARGET_ARM)/src/$(OPENSSL_DIR) + $(CD) $(TARGET_ARM)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_ARM_ENV) $(MAKE) depend + $(CD) $(TARGET_ARM)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_ARM_ENV) $(MAKE) build_libs + $(CD) $(TARGET_ARM)/src/$(OPENSSL_DIR) && $(ECHO) '#!/bin/sh\n\nfalse\n' > apps/openssl + $(CD) $(TARGET_ARM)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_ARM_ENV) $(MAKE) install_sw + +$(TARGET_ARM_V7A)/lib/libssl.a: $(TARGET_ARM_V7A)/src/$(OPENSSL_DIR) + $(CD) $(TARGET_ARM_V7A)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_ARM_V7A_ENV) $(MAKE) depend + $(CD) $(TARGET_ARM_V7A)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_ARM_V7A_ENV) $(MAKE) build_libs + $(CD) $(TARGET_ARM_V7A)/src/$(OPENSSL_DIR) && $(ECHO) '#!/bin/sh\n\nfalse\n' > apps/openssl + $(CD) $(TARGET_ARM_V7A)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_ARM_V7A_ENV) $(MAKE) install_sw + +$(TARGET_ARM_V7A_HARD)/lib/libssl.a: $(TARGET_ARM_V7A_HARD)/src/$(OPENSSL_DIR) + $(CD) $(TARGET_ARM_V7A_HARD)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_ARM_V7A_HARD_ENV) $(MAKE) depend + $(CD) $(TARGET_ARM_V7A_HARD)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_ARM_V7A_HARD_ENV) $(MAKE) build_libs + $(CD) $(TARGET_ARM_V7A_HARD)/src/$(OPENSSL_DIR) && $(ECHO) '#!/bin/sh\n\nfalse\n' > apps/openssl + $(CD) $(TARGET_ARM_V7A_HARD)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_ARM_V7A_HARD_ENV) $(MAKE) install_sw + +$(TARGET_ARM64_V8A)/lib/libssl.a: $(TARGET_ARM64_V8A)/src/$(OPENSSL_DIR) + $(CD) $(TARGET_ARM64_V8A)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_ARM64_V8A_ENV) $(MAKE) depend + $(CD) $(TARGET_ARM64_V8A)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_ARM64_V8A_ENV) $(MAKE) build_libs + $(CD) $(TARGET_ARM64_V8A)/src/$(OPENSSL_DIR) && $(ECHO) '#!/bin/sh\n\nfalse\n' > apps/openssl + $(CD) $(TARGET_ARM64_V8A)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_ARM64_V8A_ENV) $(MAKE) install_sw + +$(TARGET_MIPS)/lib/libssl.a: $(TARGET_MIPS)/src/$(OPENSSL_DIR) + $(CD) $(TARGET_MIPS)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_MIPS_ENV) $(MAKE) depend + $(CD) $(TARGET_MIPS)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_MIPS_ENV) $(MAKE) build_libs + $(CD) $(TARGET_MIPS)/src/$(OPENSSL_DIR) && $(ECHO) '#!/bin/sh\n\nfalse\n' > apps/openssl + $(CD) $(TARGET_MIPS)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_MIPS_ENV) $(MAKE) install_sw + +$(TARGET_MIPS64)/lib/libssl.a: $(TARGET_MIPS64)/src/$(OPENSSL_DIR) + $(CD) $(TARGET_MIPS64)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_MIPS64_ENV) $(MAKE) depend + $(CD) $(TARGET_MIPS64)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_MIPS64_ENV) $(MAKE) build_libs + $(CD) $(TARGET_MIPS64)/src/$(OPENSSL_DIR) && $(ECHO) '#!/bin/sh\n\nfalse\n' > apps/openssl + $(CD) $(TARGET_MIPS64)/src/$(OPENSSL_DIR) && $(TOOLCHAIN_MIPS64_ENV) $(MAKE) install_sw + +# +# Rules to build libwebsockets +# + +libwebsockets: \ + libwebsockets-x86 \ + libwebsockets-x86_64 \ + libwebsockets-armeabi \ + libwebsockets-armeabi-v7a \ + libwebsockets-armeabi-v7a-hard \ + libwebsockets-arm64-v8a \ + libwebsockets-mips \ + libwebsockets-mips64 \ + +libwebsockets-x86: $(TARGET_X86)/lib/libwebsockets.a +libwebsockets-x86_64: $(TARGET_X86_64)/lib/libwebsockets.a +libwebsockets-armeabi: $(TARGET_ARM)/lib/libwebsockets.a +libwebsockets-armeabi-v7a: $(TARGET_ARM_V7A)/lib/libwebsockets.a +libwebsockets-armeabi-v7a-hard: $(TARGET_ARM_V7A_HARD)/lib/libwebsockets.a +libwebsockets-arm64-v8a: $(TARGET_ARM64_V8A)/lib/libwebsockets.a +libwebsockets-mips: $(TARGET_MIPS)/lib/libwebsockets.a +libwebsockets-mips64: $(TARGET_MIPS64)/lib/libwebsockets.a + +# Extracting/configuring sources + +$(TARGET_X86)/src/$(LIBWEBSOCKETS_DIR): $(LIBWEBSOCKETS_TGZ_SOURCE) $(TOOLCHAIN_X86) $(TARGET_X86)/lib/libssl.a $(TARGET_X86)/lib/libz.a + -$(MKDIR) -p $(TARGET_X86)/src + $(TAR) xf $(LIBWEBSOCKETS_TGZ_SOURCE) -C $(TARGET_X86)/src + -$(MKDIR) -p $(TARGET_X86)/src/$(LIBWEBSOCKETS_DIR)/build + $(CD) $(TARGET_X86)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_X86_ENV) \ + $(CMAKE) $(TARGET_X86_LWS_OPTIONS) \ + -DCMAKE_INSTALL_PREFIX=$(shell pwd)/$(TARGET_X86) \ + -DLWS_OPENSSL_LIBRARIES="$(shell pwd)/$(TARGET_X86)/lib/libssl.a;$(shell pwd)/$(TARGET_X86)/lib/libcrypto.a" \ + -DLWS_OPENSSL_INCLUDE_DIRS="$(shell pwd)/$(TARGET_X86)/include" \ + .. + +$(TARGET_X86_64)/src/$(LIBWEBSOCKETS_DIR): $(LIBWEBSOCKETS_TGZ_SOURCE) $(TOOLCHAIN_X86_64) $(TARGET_X86_64)/lib/libssl.a $(TARGET_X86_64)/lib/libz.a + -$(MKDIR) -p $(TARGET_X86_64)/src + $(TAR) xf $(LIBWEBSOCKETS_TGZ_SOURCE) -C $(TARGET_X86_64)/src + -$(MKDIR) -p $(TARGET_X86_64)/src/$(LIBWEBSOCKETS_DIR)/build + $(CD) $(TARGET_X86_64)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_X86_64_ENV) \ + $(CMAKE) $(TARGET_X86_64_LWS_OPTIONS) \ + -DCMAKE_INSTALL_PREFIX=$(shell pwd)/$(TARGET_X86_64) \ + -DLWS_OPENSSL_LIBRARIES="$(shell pwd)/$(TARGET_X86_64)/lib/libssl.a;$(shell pwd)/$(TARGET_X86_64)/lib/libcrypto.a" \ + -DLWS_OPENSSL_INCLUDE_DIRS="$(shell pwd)/$(TARGET_X86_64)/include" \ + .. + +$(TARGET_ARM)/src/$(LIBWEBSOCKETS_DIR): $(LIBWEBSOCKETS_TGZ_SOURCE) $(TOOLCHAIN_ARM) $(TARGET_ARM)/lib/libssl.a $(TARGET_ARM)/lib/libz.a + -$(MKDIR) -p $(TARGET_ARM)/src + $(TAR) xf $(LIBWEBSOCKETS_TGZ_SOURCE) -C $(TARGET_ARM)/src + -$(MKDIR) -p $(TARGET_ARM)/src/$(LIBWEBSOCKETS_DIR)/build + $(CD) $(TARGET_ARM)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_ARM_ENV) \ + $(CMAKE) $(TARGET_ARM_LWS_OPTIONS) \ + -DCMAKE_INSTALL_PREFIX=$(shell pwd)/$(TARGET_ARM) \ + -DLWS_OPENSSL_LIBRARIES="$(shell pwd)/$(TARGET_ARM)/lib/libssl.a;$(shell pwd)/$(TARGET_ARM)/lib/libcrypto.a" \ + -DLWS_OPENSSL_INCLUDE_DIRS="$(shell pwd)/$(TARGET_ARM)/include" \ + .. + +$(TARGET_ARM_V7A)/src/$(LIBWEBSOCKETS_DIR): $(LIBWEBSOCKETS_TGZ_SOURCE) $(TOOLCHAIN_ARM_V7A) $(TARGET_ARM_V7A)/lib/libssl.a $(TARGET_ARM_V7A)/lib/libz.a + -$(MKDIR) -p $(TARGET_ARM_V7A)/src + $(TAR) xf $(LIBWEBSOCKETS_TGZ_SOURCE) -C $(TARGET_ARM_V7A)/src + -$(MKDIR) -p $(TARGET_ARM_V7A)/src/$(LIBWEBSOCKETS_DIR)/build + $(CD) $(TARGET_ARM_V7A)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_ARM_V7A_ENV) \ + $(CMAKE) $(TARGET_ARM_V7A_LWS_OPTIONS) \ + -DCMAKE_INSTALL_PREFIX=$(shell pwd)/$(TARGET_ARM_V7A) \ + -DLWS_OPENSSL_LIBRARIES="$(shell pwd)/$(TARGET_ARM_V7A)/lib/libssl.a;$(shell pwd)/$(TARGET_ARM_V7A)/lib/libcrypto.a" \ + -DLWS_OPENSSL_INCLUDE_DIRS="$(shell pwd)/$(TARGET_ARM_V7A)/include" \ + .. + +$(TARGET_ARM_V7A_HARD)/src/$(LIBWEBSOCKETS_DIR): $(LIBWEBSOCKETS_TGZ_SOURCE) $(TOOLCHAIN_ARM_V7A_HARD) $(TARGET_ARM_V7A_HARD)/lib/libssl.a $(TARGET_ARM_V7A_HARD)/lib/libz.a + -$(MKDIR) -p $(TARGET_ARM_V7A_HARD)/src + $(TAR) xf $(LIBWEBSOCKETS_TGZ_SOURCE) -C $(TARGET_ARM_V7A_HARD)/src + -$(MKDIR) -p $(TARGET_ARM_V7A_HARD)/src/$(LIBWEBSOCKETS_DIR)/build + $(CD) $(TARGET_ARM_V7A_HARD)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_ARM_V7A_HARD_ENV) \ + $(CMAKE) $(TARGET_ARM_V7A_HARD_LWS_OPTIONS) \ + -DCMAKE_INSTALL_PREFIX=$(shell pwd)/$(TARGET_ARM_V7A_HARD) \ + -DLWS_OPENSSL_LIBRARIES="$(shell pwd)/$(TARGET_ARM_V7A_HARD)/lib/libssl.a;$(shell pwd)/$(TARGET_ARM_V7A_HARD)/lib/libcrypto.a" \ + -DLWS_OPENSSL_INCLUDE_DIRS="$(shell pwd)/$(TARGET_ARM_V7A_HARD)/include" \ + .. + +$(TARGET_ARM64_V8A)/src/$(LIBWEBSOCKETS_DIR): $(LIBWEBSOCKETS_TGZ_SOURCE) $(TOOLCHAIN_ARM64_V8A) $(TARGET_ARM64_V8A)/lib/libssl.a $(TARGET_ARM64_V8A)/lib/libz.a + -$(MKDIR) -p $(TARGET_ARM64_V8A)/src + $(TAR) xf $(LIBWEBSOCKETS_TGZ_SOURCE) -C $(TARGET_ARM64_V8A)/src + -$(MKDIR) -p $(TARGET_ARM64_V8A)/src/$(LIBWEBSOCKETS_DIR)/build + $(CD) $(TARGET_ARM64_V8A)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_ARM64_V8A_ENV) \ + $(CMAKE) $(TARGET_ARM64_V8A_LWS_OPTIONS) \ + -DCMAKE_INSTALL_PREFIX=$(shell pwd)/$(TARGET_ARM64_V8A) \ + -DLWS_OPENSSL_LIBRARIES="$(shell pwd)/$(TARGET_ARM64_V8A)/lib/libssl.a;$(shell pwd)/$(TARGET_ARM64_V8A)/lib/libcrypto.a" \ + -DLWS_OPENSSL_INCLUDE_DIRS="$(shell pwd)/$(TARGET_ARM64_V8A)/include" \ + .. + +$(TARGET_MIPS)/src/$(LIBWEBSOCKETS_DIR): $(LIBWEBSOCKETS_TGZ_SOURCE) $(TOOLCHAIN_MIPS) $(TARGET_MIPS)/lib/libssl.a $(TARGET_MIPS)/lib/libz.a + -$(MKDIR) -p $(TARGET_MIPS)/src + $(TAR) xf $(LIBWEBSOCKETS_TGZ_SOURCE) -C $(TARGET_MIPS)/src + -$(MKDIR) -p $(TARGET_MIPS)/src/$(LIBWEBSOCKETS_DIR)/build + $(CD) $(TARGET_MIPS)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_MIPS_ENV) \ + $(CMAKE) $(TARGET_MIPS_LWS_OPTIONS) \ + -DCMAKE_INSTALL_PREFIX=$(shell pwd)/$(TARGET_MIPS) \ + -DLWS_OPENSSL_LIBRARIES="$(shell pwd)/$(TARGET_MIPS)/lib/libssl.a;$(shell pwd)/$(TARGET_MIPS)/lib/libcrypto.a" \ + -DLWS_OPENSSL_INCLUDE_DIRS="$(shell pwd)/$(TARGET_MIPS)/include" \ + .. + +$(TARGET_MIPS64)/src/$(LIBWEBSOCKETS_DIR): $(LIBWEBSOCKETS_TGZ_SOURCE) $(TOOLCHAIN_MIPS64) $(TARGET_MIPS64)/lib/libssl.a $(TARGET_MIPS64)/lib/libz.a + -$(MKDIR) -p $(TARGET_MIPS64)/src + $(TAR) xf $(LIBWEBSOCKETS_TGZ_SOURCE) -C $(TARGET_MIPS64)/src + -$(MKDIR) -p $(TARGET_MIPS64)/src/$(LIBWEBSOCKETS_DIR)/build + $(CD) $(TARGET_MIPS64)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_MIPS64_ENV) \ + $(CMAKE) $(TARGET_MIPS64_LWS_OPTIONS) \ + -DCMAKE_INSTALL_PREFIX=$(shell pwd)/$(TARGET_MIPS64) \ + -DLWS_OPENSSL_LIBRARIES="$(shell pwd)/$(TARGET_MIPS64)/lib/libssl.a;$(shell pwd)/$(TARGET_MIPS64)/lib/libcrypto.a" \ + -DLWS_OPENSSL_INCLUDE_DIRS="$(shell pwd)/$(TARGET_MIPS64)/include" \ + .. + +# Build/install library + +$(TARGET_X86)/lib/libwebsockets.a: $(TARGET_X86)/src/$(LIBWEBSOCKETS_DIR) + $(CD) $(TARGET_X86)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_X86_ENV) $(MAKE) + $(CD) $(TARGET_X86)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_X86_ENV) $(MAKE) install + +$(TARGET_X86_64)/lib/libwebsockets.a: $(TARGET_X86_64)/src/$(LIBWEBSOCKETS_DIR) + $(CD) $(TARGET_X86_64)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_X86_64_ENV) $(MAKE) + $(CD) $(TARGET_X86_64)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_X86_64_ENV) $(MAKE) install + +$(TARGET_ARM)/lib/libwebsockets.a: $(TARGET_ARM)/src/$(LIBWEBSOCKETS_DIR) + $(CD) $(TARGET_ARM)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_ARM_ENV) $(MAKE) + $(CD) $(TARGET_ARM)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_ARM_ENV) $(MAKE) install + +$(TARGET_ARM_V7A)/lib/libwebsockets.a: $(TARGET_ARM_V7A)/src/$(LIBWEBSOCKETS_DIR) + $(CD) $(TARGET_ARM_V7A)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_ARM_V7A_ENV) $(MAKE) + $(CD) $(TARGET_ARM_V7A)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_ARM_V7A_ENV) $(MAKE) install + +$(TARGET_ARM_V7A_HARD)/lib/libwebsockets.a: $(TARGET_ARM_V7A_HARD)/src/$(LIBWEBSOCKETS_DIR) + $(CD) $(TARGET_ARM_V7A_HARD)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_ARM_V7A_HARD_ENV) $(MAKE) + $(CD) $(TARGET_ARM_V7A_HARD)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_ARM_V7A_HARD_ENV) $(MAKE) install + +$(TARGET_ARM64_V8A)/lib/libwebsockets.a: $(TARGET_ARM64_V8A)/src/$(LIBWEBSOCKETS_DIR) + $(CD) $(TARGET_ARM64_V8A)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_ARM64_V8A_ENV) $(MAKE) + $(CD) $(TARGET_ARM64_V8A)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_ARM64_V8A_ENV) $(MAKE) install + +$(TARGET_MIPS)/lib/libwebsockets.a: $(TARGET_MIPS)/src/$(LIBWEBSOCKETS_DIR) + $(CD) $(TARGET_MIPS)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_MIPS_ENV) $(MAKE) + $(CD) $(TARGET_MIPS)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_MIPS_ENV) $(MAKE) install + +$(TARGET_MIPS64)/lib/libwebsockets.a: $(TARGET_MIPS64)/src/$(LIBWEBSOCKETS_DIR) + $(CD) $(TARGET_MIPS64)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_MIPS64_ENV) $(MAKE) + $(CD) $(TARGET_MIPS64)/src/$(LIBWEBSOCKETS_DIR)/build && $(TOOLCHAIN_MIPS64_ENV) $(MAKE) install + +# +# Some rules for housekeeping +# + +clean-ndk: + $(NDK_ROOT)/ndk-build clean + +clean: clean-targets clean-toolchains + +dist-clean: clean clean-sources + +clean-targets: \ + clean-target-x86 \ + clean-target-x86_64 \ + clean-target-armeabi \ + clean-target-armeabi-v7a \ + clean-target-armeabi-v7a-hard \ + clean-target-arm64-v8a \ + clean-target-mips \ + clean-target-mips64 + +clean-target-x86: + -$(RM) -fr $(TARGET_X86) + +clean-target-x86_64: + -$(RM) -fr $(TARGET_X86_64) + +clean-target-armeabi: + -$(RM) -fr $(TARGET_ARM) + +clean-target-armeabi-v7a: + -$(RM) -fr $(TARGET_ARM_V7A) + +clean-target-armeabi-v7a-hard: + -$(RM) -fr $(TARGET_ARM_V7A_HARD) + +clean-target-arm64-v8a: + -$(RM) -fr $(TARGET_ARM64_V8A) + +clean-target-mips: + -$(RM) -fr $(TARGET_MIPS) + +clean-target-mips64: + -$(RM) -fr $(TARGET_MIPS64) + +clean-sources: \ + clean-source-zlib \ + clean-source-openssl \ + clean-source-libwebsockets + +clean-source-zlib: + -$(RM) $(ZLIB_TGZ_SOURCE) + +clean-source-openssl: + -$(RM) $(OPENSSL_TGZ_SOURCE) + +clean-source-libwebsockets: + -$(RM) $(LIBWEBSOCKETS_TGZ_SOURCE) + +clean-toolchains: \ + clean-toolchain-x86 \ + clean-toolchain-x86_64 \ + clean-toolchain-armeabi \ + clean-toolchain-armeabi-v7a \ + clean-toolchain-armeabi-v7a-hard \ + clean-toolchain-arm64-v8a \ + clean-toolchain-mips \ + clean-toolchain-mips64 + -$(RM) -fr toolchains + +clean-toolchain-x86: + -$(RM) -fr $(TOOLCHAIN_X86) + +clean-toolchain-x86_64: + -$(RM) -fr $(TOOLCHAIN_X86_64) + +clean-toolchain-armeabi: + -$(RM) -fr $(TOOLCHAIN_ARM) + +clean-toolchain-armeabi-v7a: + -$(RM) -fr $(TOOLCHAIN_ARM_V7A) + +clean-toolchain-armeabi-v7a-hard: + -$(RM) -fr $(TOOLCHAIN_ARM_V7A_HARD) + +clean-toolchain-arm64-v8a: + -$(RM) -fr $(TOOLCHAIN_ARM64_V8A) + +clean-toolchain-mips: + -$(RM) -fr $(TOOLCHAIN_MIPS) + +clean-toolchain-mips64: + -$(RM) -fr $(TOOLCHAIN_MIPS64) + +# 'make list-targets' prints a list of all targets. +# Thanks to: http://stackoverflow.com/questions/4219255/how-do-you-get-the-list-of-targets-in-a-makefile +# Modified to allow us to include files in this Makefile. +list-targets: MAKE_NO_INCLUDES := 1 +export MAKE_NO_INCLUDES +list-targets: + @$(MAKE) -s list-targets-no-includes +list-targets-no-includes: + @$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | $(AWK) -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | $(SORT) | $(EGREP) -v -e '^[^[:alnum:]]' -e '^$@$$' + diff --git a/test-apps/android/app/src/main/libs/placeholder b/test-apps/android/app/src/main/libs/placeholder new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test-apps/android/app/src/main/libs/placeholder diff --git a/test-apps/android/app/src/main/res/drawable/warmcat.png b/test-apps/android/app/src/main/res/drawable/warmcat.png new file mode 100644 index 0000000..2060a10 Binary files /dev/null and b/test-apps/android/app/src/main/res/drawable/warmcat.png differ diff --git a/test-apps/android/app/src/main/res/layout/activity_main.xml b/test-apps/android/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..a852e97 --- /dev/null +++ b/test-apps/android/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + +