diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f8e76c675..ff9a24e046 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,15 +1,15 @@ -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 2.6) -project(libwebsockets C) +project(libwebsockets) set(PACKAGE "libwebsockets") set(CPACK_PACKAGE_NAME "${PACKAGE}") set(CPACK_PACKAGE_VERSION_MAJOR "1") -set(CPACK_PACKAGE_VERSION_MINOR "4") +set(CPACK_PACKAGE_VERSION_MINOR "3") set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}") set(CPACK_PACKAGE_VENDOR "andy@warmcat.com") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PACKAGE} ${PACKAGE_VERSION}") -set(SOVERSION "5") +set(SOVERSION "4.0.0") set(CPACK_SOURCE_GENERATOR "TGZ") set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") set(VERSION "${CPACK_PACKAGE_VERSION}") @@ -52,7 +52,7 @@ option(LWS_WITHOUT_EXTENSIONS "Don't compile with extensions" OFF) option(LWS_WITH_LATENCY "Build latency measuring code into the library" OFF) option(LWS_WITHOUT_DAEMONIZE "Don't build the daemonization api" OFF) option(LWS_WITH_LIBEV "Compile with support for libev" OFF) -option(LWS_IPV6 "Compile with support for ipv6" OFF) +option(LWS_IPV6 "Compile with support for ipv6" ON) option(LWS_WITH_HTTP2 "Compile with support for http2" OFF) # Allow the user to override installation directories. @@ -260,11 +260,11 @@ include_directories("${PROJECT_SOURCE_DIR}/lib") # Some IDEs use this for nicer file structure. set(HDR_PRIVATE lib/private-libwebsockets.h + "${PROJECT_BINARY_DIR}/lws_config.h" ) set(HDR_PUBLIC "${PROJECT_SOURCE_DIR}/lib/libwebsockets.h" - "${PROJECT_BINARY_DIR}/lws_config.h" ) set(SOURCES @@ -277,7 +277,6 @@ set(SOURCES lib/parsers.c lib/context.c lib/sha-1.c - lib/alloc.c ) if (NOT LWS_WITHOUT_CLIENT) @@ -296,8 +295,6 @@ endif() if (LWS_WITH_HTTP2) list(APPEND SOURCES - lib/http2.c - lib/hpack.c lib/ssl-http2.c ) endif() @@ -361,15 +358,10 @@ endif(UNIX) if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) - include (CheckCCompilerFlag) - CHECK_C_COMPILER_FLAG(-fvisibility=hidden HAVE_VISIBILITY) - if (HAVE_VISIBILITY) - set(VISIBILITY_FLAG -fvisibility=hidden) - endif() if (UNIX) - set( CMAKE_C_FLAGS "-Wall -Werror -O3 ${VISIBILITY_FLAG} ${CMAKE_C_FLAGS}" ) + set( CMAKE_C_FLAGS "-Wall -Werror -O4 -fvisibility=hidden ${CMAKE_C_FLAGS}" ) else(UNIX) - set( CMAKE_C_FLAGS "-Wall -O3 ${VISIBILITY_FLAG} ${CMAKE_C_FLAGS}" ) + set( CMAKE_C_FLAGS "-Wall -O4 -fvisibility=hidden ${CMAKE_C_FLAGS}" ) endif(UNIX) endif () @@ -499,14 +491,8 @@ if (LWS_WITH_SSL) list(APPEND LIB_LIST "${LWS_CYASSL_LIB}") else() - if (OPENSSL_ROOT_DIR) - set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/include") - set(OPENSSL_LIBRARIES "${OPENSSL_ROOT_DIR}/lib/libssl.so" "${OPENSSL_ROOT_DIR}/lib/libcrypto.so") - else(OPENSSL_ROOT_DIR) - # TODO: Add support for STATIC also. find_package(OpenSSL REQUIRED) - endif(OPENSSL_ROOT_DIR) message("OpenSSL include dir: ${OPENSSL_INCLUDE_DIR}") message("OpenSSL libraries: ${OPENSSL_LIBRARIES}") diff --git a/README.build b/README.build new file mode 100644 index 0000000000..4620661d7a --- /dev/null +++ b/README.build @@ -0,0 +1,225 @@ +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 (both OpenSSL/CyaSSL): + +- Windows +- Linux (x86 and ARM) +- OSX +- NetBSD + +Building the library and test apps +---------------------------------- + +The project settings used by CMake to generate the platform specific build +files is called 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. + +Building on Unix: +----------------- + +1. Install CMake 2.6 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 .. + + (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 + 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, + + -DOPENSSL_ROOT_DIR=/usr/local/ssl + +4. Finally you can build using the generated Makefile: + + make + + +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. + + +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 + (Preferably in the default location to make it easier for CMake to find them) + +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) + +4. Now you should have a generated Visual Studio Solution in your + /build directory, which can be used to build. + +Setting compile options +----------------------- + +To set compile time flags you can either use one of the CMake gui applications +or do it via command line. + +Command line +------------ +To list avaialable options (ommit 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 .. + +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 + +Windows GUI +----------- +On windows CMake comes with a gui application: + Start -> Programs -> CMake -> CMake (cmake-gui) + +CyaSSL replacement for OpenSSL +------------------------------ +CyaSSL is a lightweight SSL library targeted at embedded system: +http://www.yassl.com/yaSSL/Products-cyassl.html + +It contains a OpenSSL compatability layer which makes it possible to pretty +much link to it instead of OpenSSL, giving a much smaller footprint. + +NOTE: cyassl needs to be compiled using the --enable-opensslextra flag for +this to work. + +Compiling libwebsockets with CyaSSL +----------------------------------- + +cmake .. -DLWS_USE_CYASSL=1 \ + -DLWS_CYASSL_INCLUDE_DIRS=/path/to/cyassl \ + -DLWS_CYASSL_LIB=/path/to/cyassl/cyassl.a .. + +NOTE: On windows use the .lib file extension for LWS_CYASSL_LIB instead. + +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 +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 \ + -DWITHOUT_EXTENSIONS=1 -DWITH_SSL=0 + +The example shows how to build with no external cross lib dependencies, you +need to proide 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 + + +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 noticable, 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 b/README.coding new file mode 100644 index 0000000000..333011caed --- /dev/null +++ b/README.coding @@ -0,0 +1,267 @@ +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. + + +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 avaiable number of file descriptors, and when restarted +libwebsockets will adapt accordingly. + + +Libwebsockets is singlethreaded +------------------------------- + +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. + +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. + + +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 + + - libwebsocket_callback_on_writable(context, wsi) for a specific wsi, or + - libwebsocket_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. + + +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. + + +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 libwebsocket_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) + + +Fragmented messages +------------------- + +To support fragmented messages you need to check for the final +frame of a message with libwebsocket_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 = libwebsockets_remaining_packet_payload(wsi); + + if (!remaining && libwebsocket_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 llibwebsockets-test-fraggle sources also show how to +deal with fragmented messages. + + +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. + + +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 libwebsocket_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. + + +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. + + +Availability of header information +---------------------------------- + +From v1.2 of the library onwards, the HTTP header content is free()d as soon +as the websocket connection is established. For websocket servers, you can +copy interesting headers by handling LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION +callback, for clients there's a new callback just for this purpose +LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH. + + +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 / inteveral 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. + +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 ciher 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. + + +Async nature of client connections +---------------------------------- + +When you call libwebsocket_client_connect(..) and get a wsi back, it does not +mean your connection is active. It just mean 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 libwebsocket_service() until one of the above callbacks occurs. + +As usual, see test-client.c for example code. + diff --git a/README.test-apps b/README.test-apps new file mode 100644 index 0000000000..f8fb0503ca --- /dev/null +++ b/README.test-apps @@ -0,0 +1,272 @@ +Testing server with a browser +----------------------------- + +If you run libwebsockets-test-server 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. + + +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.s + + +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 is all that is needed to use libwebsockets for +serving both the script html over http and websockets. + + +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. + + +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. + + +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 selfsigned +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. + + +Using the websocket ping utility +-------------------------------- + +libwebsockets-test-ping connects as a client to a remote +websocket server using 04 protocol 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 protcol to handshake with +by --protocol=protocolname + + +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. + + +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 + + +debug logging +------------- + +By default logging of severity "notice", "warn" or "err" is enabled to stderr. + +Again by default other logging is comiled in but disabled from printing. + +If you want to eliminate the debug logging below notice in severity, use the +--disable-debug configure option to have it removed from the code by the +preprocesser. + +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 + + +Websocket version supported +--------------------------- + +The final IETF standard is supported for both client and server, protocol +version 13. + + +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. + diff --git a/android/android.toolchain.cmake b/android/android.toolchain.cmake index e9a3c01d5e..588e695f47 100644 --- a/android/android.toolchain.cmake +++ b/android/android.toolchain.cmake @@ -1,5 +1,5 @@ # Copyright (c) 2010-2011, Ethan Rublee -# Copyright (c) 2011-2013, Andrey Kamaev +# Copyright (c) 2011-2014, Andrey Kamaev # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -12,9 +12,9 @@ # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # -# 3. The name of the copyright holders may be used to endorse or promote -# products derived from this software without specific prior written -# permission. +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -29,7 +29,7 @@ # POSSIBILITY OF SUCH DAMAGE. # ------------------------------------------------------------------------------ -# Android CMake toolchain file, for use with the Android NDK r5-r8 +# Android CMake toolchain file, for use with the Android NDK r5-r9 # Requires cmake 2.6.3 or newer (2.8.5 or newer is recommended). # See home page: https://github.com/taka-no-me/android-cmake # @@ -85,13 +85,18 @@ # "armeabi-v7a with VFPV3" - same as armeabi-v7a, but # sets VFPV3 as floating-point unit (has 32 registers instead of 16). # "armeabi-v6 with VFP" - tuned for ARMv6 processors having VFP. +# "arm64-v8a" - matches to the NDK ABI with the same name. +# See ${ANDROID_NDK}/docs/CPU-ARCH-ABIS.html for the documentation. # "x86" - matches to the NDK ABI with the same name. # See ${ANDROID_NDK}/docs/CPU-ARCH-ABIS.html for the documentation. -# "mips" - matches to the NDK ABI with the same name -# (It is not tested on real devices by the authos of this toolchain) +# "x86_64" - matches to the NDK ABI with the same name. +# See ${ANDROID_NDK}/docs/CPU-ARCH-ABIS.html for the documentation. +# "mips" - matches to the NDK ABI with the same name. +# See ${ANDROID_NDK}/docs/CPU-ARCH-ABIS.html for the documentation. +# "mips64" - matches to the NDK ABI with the same name. # See ${ANDROID_NDK}/docs/CPU-ARCH-ABIS.html for the documentation. # -# ANDROID_NATIVE_API_LEVEL=android-8 - level of Android API compile for. +# ANDROID_NATIVE_API_LEVEL=android-21 - level of Android API compile for. # Option is read-only when standalone toolchain is used. # # ANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.6 - the name of compiler @@ -182,13 +187,13 @@ # ANDROID and BUILD_ANDROID will be set to true, you may test any of these # variables to make necessary Android-specific configuration changes. # -# Also ARMEABI or ARMEABI_V7A or X86 or MIPS will be set true, mutually +# Also ARMEABI or ARMEABI_V7A or ARM64_V8A or X86 or X86_64 or MIPS or MIPS64 will be set true, mutually # exclusive. NEON option will be set true if VFP is set to NEON. # # LIBRARY_OUTPUT_PATH_ROOT should be set in cache to determine where Android # libraries will be installed. # Default is ${CMAKE_SOURCE_DIR}, and the android libs will always be -# under the ${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME} +# under the ${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_OUTPUT_ABI_NAME} # (depending on the target ABI). This is convenient for Android packaging. # # Change Log: @@ -292,6 +297,21 @@ # - April 2013 # [+] support non-release NDK layouts (from Linaro git and Android git) # [~] automatically detect if explicit link to crtbegin_*.o is needed +# - June 2013 +# [~] fixed stl include path for standalone toolchain made by NDK >= r8c +# - July 2013 +# [+] updated for NDK r9 +# - November 2013 +# [+] updated for NDK r9b +# - December 2013 +# [+] updated for NDK r9c +# - January 2014 +# [~] fix copying of shared STL +# - April 2014 +# [+] updated for NDK r9d +# - July 2014 +# [+] updated for NDK r10 +# [+] arm64_v8a, x86_64, mips64 toolchain support (experimental) # ------------------------------------------------------------------------------ cmake_minimum_required( VERSION 2.6.3 ) @@ -318,7 +338,7 @@ set( CMAKE_SYSTEM_VERSION 1 ) # rpath makes low sence for Android set( CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries." ) -set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" ) +set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r10 -r9d -r9c -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" ) if(NOT DEFINED ANDROID_NDK_SEARCH_PATHS) if( CMAKE_HOST_WIN32 ) file( TO_CMAKE_PATH "$ENV{PROGRAMFILES}" ANDROID_NDK_SEARCH_PATHS ) @@ -333,12 +353,18 @@ if(NOT DEFINED ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH) endif() set( ANDROID_SUPPORTED_ABIS_arm "armeabi-v7a;armeabi;armeabi-v7a with NEON;armeabi-v7a with VFPV3;armeabi-v6 with VFP" ) +set( ANDROID_SUPPORTED_ABIS_arm64 "arm64-v8a" ) set( ANDROID_SUPPORTED_ABIS_x86 "x86" ) +set( ANDROID_SUPPORTED_ABIS_x86_64 "x86_64" ) set( ANDROID_SUPPORTED_ABIS_mipsel "mips" ) +set( ANDROID_SUPPORTED_ABIS_mips64el "mips64" ) set( ANDROID_DEFAULT_NDK_API_LEVEL 8 ) set( ANDROID_DEFAULT_NDK_API_LEVEL_x86 9 ) set( ANDROID_DEFAULT_NDK_API_LEVEL_mips 9 ) +set( ANDROID_DEFAULT_NDK_API_LEVEL_arm64 "21" ) +set( ANDROID_DEFAULT_NDK_API_LEVEL_x86_64 "21" ) +set( ANDROID_DEFAULT_NDK_API_LEVEL_mips64 "21" ) macro( __LIST_FILTER listvar regex ) @@ -464,7 +490,7 @@ endif() # detect current host platform -if( NOT DEFINED ANDROID_NDK_HOST_X64 AND CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64") +if( NOT DEFINED ANDROID_NDK_HOST_X64 AND (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64" OR CMAKE_HOST_APPLE) ) set( ANDROID_NDK_HOST_X64 1 CACHE BOOL "Try to use 64-bit compiler toolchain" ) mark_as_advanced( ANDROID_NDK_HOST_X64 ) endif() @@ -613,11 +639,13 @@ if( BUILD_WITH_STANDALONE_TOOLCHAIN ) message( FATAL_ERROR "Could not determine machine name of your toolchain. Probably your Android standalone toolchain is broken." ) endif() if( __availableToolchainMachines MATCHES i686 ) - set( __availableToolchainArchs "x86" ) - elseif( __availableToolchainMachines MATCHES arm ) - set( __availableToolchainArchs "arm" ) + set( __availableToolchainArchs "x86" ) + elseif( __availableToolchainMachines MATCHES x86_64 ) + set( __availableToolchainArchs "x86_64" ) + elseif( __availableToolchainMachines MATCHES arm ) + set( __availableToolchainArchs "arm" ) elseif( __availableToolchainMachines MATCHES mipsel ) - set( __availableToolchainArchs "mipsel" ) + set( __availableToolchainArchs "mipsel" ) endif() execute_process( COMMAND "${ANDROID_STANDALONE_TOOLCHAIN}/bin/${__availableToolchainMachines}-gcc${TOOL_OS_SUFFIX}" -dumpversion OUTPUT_VARIABLE __availableToolchainCompilerVersions OUTPUT_STRIP_TRAILING_WHITESPACE ) @@ -642,10 +670,16 @@ macro( __GLOB_NDK_TOOLCHAINS __availableToolchainsVar __availableToolchainsLst _ string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9x]+)?$" __version "${__gcc_toolchain}" ) if( __machine MATCHES i686 ) set( __arch "x86" ) + elseif( __machine MATCHES x86_64 ) + set( __arch "x86_64" ) elseif( __machine MATCHES arm ) set( __arch "arm" ) + elseif( __machine MATCHES aarch64 ) + set( __arch "arm64" ) elseif( __machine MATCHES mipsel ) set( __arch "mipsel" ) + elseif( __machine MATCHES mips64el ) + set( __arch "mips64el" ) endif() list( APPEND __availableToolchainMachines "${__machine}" ) list( APPEND __availableToolchainArchs "${__arch}" ) @@ -682,6 +716,7 @@ if( BUILD_WITH_ANDROID_NDK ) endif() __LIST_FILTER( __availableToolchainsLst "^[.]" ) __LIST_FILTER( __availableToolchainsLst "llvm" ) + __LIST_FILTER( __availableToolchainsLst "renderscript" ) __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 ) __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" ) @@ -713,7 +748,7 @@ __INIT_VARIABLE( ANDROID_ABI OBSOLETE_ARM_TARGET OBSOLETE_ARM_TARGETS VALUES ${A # verify that target ABI is supported list( FIND ANDROID_SUPPORTED_ABIS "${ANDROID_ABI}" __androidAbiIdx ) if( __androidAbiIdx EQUAL -1 ) - string( REPLACE ";" "\", \"", PRINTABLE_ANDROID_SUPPORTED_ABIS "${ANDROID_SUPPORTED_ABIS}" ) + string( REPLACE ";" "\", \"" PRINTABLE_ANDROID_SUPPORTED_ABIS "${ANDROID_SUPPORTED_ABIS}" ) message( FATAL_ERROR "Specified ANDROID_ABI = \"${ANDROID_ABI}\" is not supported by this cmake toolchain or your NDK/toolchain. Supported values are: \"${PRINTABLE_ANDROID_SUPPORTED_ABIS}\" " ) @@ -728,6 +763,13 @@ if( ANDROID_ABI STREQUAL "x86" ) set( ANDROID_ARCH_FULLNAME "x86" ) set( ANDROID_LLVM_TRIPLE "i686-none-linux-android" ) set( CMAKE_SYSTEM_PROCESSOR "i686" ) +elseif( ANDROID_ABI STREQUAL "x86_64" ) + set( X86_64 true ) + set( ANDROID_NDK_ABI_NAME "x86_64" ) + set( ANDROID_ARCH_NAME "x86_64" ) + set( ANDROID_ARCH_FULLNAME "x86_64" ) + set( ANDROID_LLVM_TRIPLE "x86_64-none-linux-android" ) + set( CMAKE_SYSTEM_PROCESSOR "x86_64" ) elseif( ANDROID_ABI STREQUAL "mips" ) set( MIPS true ) set( ANDROID_NDK_ABI_NAME "mips" ) @@ -735,6 +777,13 @@ elseif( ANDROID_ABI STREQUAL "mips" ) set( ANDROID_ARCH_FULLNAME "mipsel" ) set( ANDROID_LLVM_TRIPLE "mipsel-none-linux-android" ) set( CMAKE_SYSTEM_PROCESSOR "mips" ) +elseif( ANDROID_ABI STREQUAL "mips64" ) + set( MIPS64 true ) + set( ANDROID_NDK_ABI_NAME "mips64" ) + set( ANDROID_ARCH_NAME "mips64" ) + set( ANDROID_ARCH_FULLNAME "mips64el" ) + set( ANDROID_LLVM_TRIPLE "mips64el-none-linux-android" ) + set( CMAKE_SYSTEM_PROCESSOR "mips64" ) elseif( ANDROID_ABI STREQUAL "armeabi" ) set( ARMEABI true ) set( ANDROID_NDK_ABI_NAME "armeabi" ) @@ -775,10 +824,25 @@ elseif( ANDROID_ABI STREQUAL "armeabi-v7a with NEON" ) set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) set( VFPV3 true ) set( NEON true ) +elseif( ANDROID_ABI STREQUAL "arm64-v8a" ) + set( ARM64_V8A true ) + set( ANDROID_NDK_ABI_NAME "arm64-v8a" ) + set( ANDROID_ARCH_NAME "arm64" ) + set( ANDROID_ARCH_FULLNAME "arm64" ) + set( ANDROID_LLVM_TRIPLE "armv8-none-linux-androideabi" ) + set( CMAKE_SYSTEM_PROCESSOR "aarch64" ) + set( VFPV3 true ) + set( NEON true ) else() message( SEND_ERROR "Unknown ANDROID_ABI=\"${ANDROID_ABI}\" is specified." ) endif() +if( X86_64 ) + set( ANDROID_NDK_OUTPUT_ABI_NAME "x86-64" ) +else() + set( ANDROID_NDK_OUTPUT_ABI_NAME ${ANDROID_NDK_ABI_NAME} ) +endif() + if( CMAKE_BINARY_DIR AND EXISTS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" ) # really dirty hack # it is not possible to change CMAKE_SYSTEM_PROCESSOR after the first run... @@ -970,7 +1034,11 @@ if( BUILD_WITH_STANDALONE_TOOLCHAIN ) set( ANDROID_SYSROOT "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot" ) if( NOT ANDROID_STL STREQUAL "none" ) - set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}" ) + set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/include/c++/${ANDROID_COMPILER_VERSION}" ) + if( NOT EXISTS "${ANDROID_STL_INCLUDE_DIRS}" ) + # old location ( pre r8c ) + set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}" ) + endif() if( ARMEABI_V7A AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}/bits" ) list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}" ) elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb/bits" ) @@ -986,7 +1054,11 @@ if( BUILD_WITH_STANDALONE_TOOLCHAIN ) elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libstdc++.a" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb" ) elseif( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libstdc++.a" ) - set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib" ) + if ( X86_64 ) + set (__libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib64" ) + else() + set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib" ) + endif() endif() if( __libstl ) set( __libsupcxx "${__libstl}/libsupc++.a" ) @@ -1125,15 +1197,7 @@ endif() # case of shared STL linkage if( ANDROID_STL MATCHES "shared" AND DEFINED __libstl ) string( REPLACE "_static.a" "_shared.so" __libstl "${__libstl}" ) - if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" ) - get_filename_component( __libstlname "${__libstl}" NAME ) - execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess ) - if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}") - message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" ) - endif() - unset( __fileCopyProcess ) - unset( __libstlname ) - endif() + # TODO: check if .so file exists before the renaming endif() @@ -1200,7 +1264,11 @@ if( ANDROID_COMPILER_IS_CLANG ) set( CMAKE_C_COMPILER_ID Clang) endif() set( CMAKE_C_PLATFORM_ID Linux ) -set( CMAKE_C_SIZEOF_DATA_PTR 4 ) +if( ARM64_V8A OR X86_64 OR MIPS64 ) + set( CMAKE_C_SIZEOF_DATA_PTR 8 ) +else() + set( CMAKE_C_SIZEOF_DATA_PTR 4 ) +endif() set( CMAKE_C_HAS_ISYSROOT 1 ) set( CMAKE_C_COMPILER_ABI ELF ) CMAKE_FORCE_CXX_COMPILER( "${CMAKE_CXX_COMPILER}" GNU ) @@ -1208,7 +1276,11 @@ if( ANDROID_COMPILER_IS_CLANG ) set( CMAKE_CXX_COMPILER_ID Clang) endif() set( CMAKE_CXX_PLATFORM_ID Linux ) -set( CMAKE_CXX_SIZEOF_DATA_PTR 4 ) +if( ARM64_V8A OR X86_64 OR MIPS64 ) + set( CMAKE_CXX_SIZEOF_DATA_PTR 8 ) +else() + set( CMAKE_CXX_SIZEOF_DATA_PTR 4 ) +endif() set( CMAKE_CXX_HAS_ISYSROOT 1 ) set( CMAKE_CXX_COMPILER_ABI ELF ) set( CMAKE_CXX_SOURCE_FILE_EXTENSIONS cc cp cxx cpp CPP c++ C ) @@ -1265,7 +1337,7 @@ if( ARMEABI OR ARMEABI_V7A ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" ) endif() endif() -elseif( X86 ) +elseif( X86 OR X86_64 ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) if( NOT ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" ) @@ -1274,7 +1346,7 @@ elseif( X86 ) endif() set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" ) set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" ) -elseif( MIPS ) +elseif( MIPS OR MIPS64 ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -fno-strict-aliasing -finline-functions -ffunction-sections -funwind-tables -fmessage-length=0" ) set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer" ) set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer" ) @@ -1311,6 +1383,8 @@ elseif( ARMEABI_V6 ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv6 -mfloat-abi=softfp -mfpu=vfp" ) # vfp == vfpv2 elseif( ARMEABI ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv5te -mtune=xscale -msoft-float" ) +elseif( ARM64_V8A ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv8-a" ) endif() if( ANDROID_STL MATCHES "gnustl" AND (EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}") ) @@ -1387,10 +1461,10 @@ if( ANDROID_NO_UNDEFINED ) if( MIPS ) # there is some sysroot-related problem in mips linker... if( NOT ANDROID_SYSROOT MATCHES "[ ;\"]" ) - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} --sysroot=${ANDROID_SYSROOT} -Wl,--no-undefined -Wl,-rpath-link,${ANDROID_SYSROOT}/usr/lib" ) + set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined -Wl,-rpath-link,${ANDROID_SYSROOT}/usr/lib" ) endif() else() - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} --sysroot=${ANDROID_SYSROOT} -Wl,--no-undefined" ) + set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined" ) endif() endif() @@ -1459,8 +1533,6 @@ set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE}" CACHE INTERNAL "An set( ANDROID_CXX_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG}" CACHE INTERNAL "Android specific c/c++ Debug flags" ) set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS}" CACHE INTERNAL "Android specific c/c++ linker flags" ) - - # finish flags set( CMAKE_CXX_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_CXX_FLAGS}" ) set( CMAKE_C_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_C_FLAGS}" ) @@ -1500,7 +1572,8 @@ endif() # global includes and link directories include_directories( SYSTEM "${ANDROID_SYSROOT}/usr/include" ${ANDROID_STL_INCLUDE_DIRS} ) -link_directories( "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" ) +get_filename_component(__android_install_path "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" ABSOLUTE) # avoid CMP0015 policy warning +link_directories( "${__android_install_path}" ) # detect if need link crtbegin_so.o explicitly if( NOT DEFINED ANDROID_EXPLICIT_CRT_LINK ) @@ -1545,13 +1618,25 @@ set( CMAKE_INSTALL_PREFIX "${ANDROID_TOOLCHAIN_ROOT}/user" CACHE STRING "path fo if(NOT _CMAKE_IN_TRY_COMPILE) if( EXISTS "${CMAKE_SOURCE_DIR}/jni/CMakeLists.txt" ) - set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for applications" ) + set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ANDROID_NDK_OUTPUT_ABI_NAME}" CACHE PATH "Output directory for applications" ) else() set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin" CACHE PATH "Output directory for applications" ) endif() - set( LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}" CACHE PATH "path for android libs" ) + set( LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_OUTPUT_ABI_NAME}" CACHE PATH "path for android libs" ) endif() +# copy shaed stl library to build directory +if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" ) + get_filename_component( __libstlname "${__libstl}" NAME ) + execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess ) + if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}") + message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" ) + endif() + unset( __fileCopyProcess ) + unset( __libstlname ) +endif() + + # set these global flags for cmake client scripts to change behavior set( ANDROID True ) set( BUILD_ANDROID True ) @@ -1560,9 +1645,11 @@ set( BUILD_ANDROID True ) set( CMAKE_FIND_ROOT_PATH "${ANDROID_TOOLCHAIN_ROOT}/bin" "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" "${ANDROID_SYSROOT}" "${CMAKE_INSTALL_PREFIX}" "${CMAKE_INSTALL_PREFIX}/share" ) # only search for libraries and includes in the ndk toolchain -set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) -set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) -set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) +# Disabled by adrianmn +# it messes up java detection - required for APK build +#set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) +#set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) +#set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) # macro to find packages on the host OS @@ -1614,10 +1701,16 @@ macro( ANDROID_GET_ABI_RAWNAME TOOLCHAIN_FLAG VAR ) set( ${VAR} "armeabi" ) elseif( "${TOOLCHAIN_FLAG}" STREQUAL "ARMEABI_V7A" ) set( ${VAR} "armeabi-v7a" ) + elseif( "${TOOLCHAIN_FLAG}" STREQUAL "ARM64_V8A" ) + set( ${VAR} "arm64-v8a" ) elseif( "${TOOLCHAIN_FLAG}" STREQUAL "X86" ) set( ${VAR} "x86" ) + elseif( "${TOOLCHAIN_FLAG}" STREQUAL "X86_64" ) + set( ${VAR} "x86_64" ) elseif( "${TOOLCHAIN_FLAG}" STREQUAL "MIPS" ) set( ${VAR} "mips" ) + elseif( "${TOOLCHAIN_FLAG}" STREQUAL "MIPS64" ) + set( ${VAR} "mips64" ) else() set( ${VAR} "unknown" ) endif() @@ -1660,6 +1753,19 @@ if( NOT PROJECT_NAME STREQUAL "CMAKE_TRY_COMPILE" ) endif() +# force cmake to produce / instead of \ in build commands for Ninja generator +if( CMAKE_GENERATOR MATCHES "Ninja" AND CMAKE_HOST_WIN32 ) + # it is a bad hack after all + # CMake generates Ninja makefiles with UNIX paths only if it thinks that we are going to build with MinGW + set( CMAKE_COMPILER_IS_MINGW TRUE ) # tell CMake that we are MinGW + set( CMAKE_CROSSCOMPILING TRUE ) # stop recursion + enable_language( C ) + enable_language( CXX ) + # unset( CMAKE_COMPILER_IS_MINGW ) # can't unset because CMake does not convert back-slashes in response files without it + unset( MINGW ) +endif() + + # set some obsolete variables for backward compatibility set( ANDROID_SET_OBSOLETE_VARIABLES ON CACHE BOOL "Define obsolete Andrid-specific cmake variables" ) mark_as_advanced( ANDROID_SET_OBSOLETE_VARIABLES ) @@ -1671,7 +1777,7 @@ endif() # Variables controlling behavior or set by cmake toolchain: -# ANDROID_ABI : "armeabi-v7a" (default), "armeabi", "armeabi-v7a with NEON", "armeabi-v7a with VFPV3", "armeabi-v6 with VFP", "x86", "mips" +# ANDROID_ABI : "armeabi-v7a" (default), "armeabi", "armeabi-v7a with NEON", "armeabi-v7a with VFPV3", "armeabi-v6 with VFP", "arm64-v8a", "x86", "x86_64", "mips", "mips64" # ANDROID_NATIVE_API_LEVEL : 3,4,5,8,9,14 (depends on NDK version) # ANDROID_STL : gnustl_static/gnustl_shared/stlport_static/stlport_shared/gabi++_static/gabi++_shared/system_re/system/none # ANDROID_FORBID_SYGWIN : ON/OFF @@ -1705,16 +1811,19 @@ endif() # ARMEABI : TRUE for arm v6 and older devices # ARMEABI_V6 : TRUE for arm v6 # ARMEABI_V7A : TRUE for arm v7a +# ARM64_V8A : TRUE for arm64 v8a # NEON : TRUE if NEON unit is enabled # VFPV3 : TRUE if VFP version 3 is enabled # X86 : TRUE if configured for x86 +# X86_64 : TRUE if configured for x86_64 # MIPS : TRUE if configured for mips +# MIPS64 : TRUE if configured for mips64 # BUILD_ANDROID : always TRUE # BUILD_WITH_ANDROID_NDK : TRUE if NDK is used # BUILD_WITH_STANDALONE_TOOLCHAIN : TRUE if standalone toolchain is used # ANDROID_NDK_HOST_SYSTEM_NAME : "windows", "linux-x86" or "darwin-x86" depending on host platform # ANDROID_NDK_ABI_NAME : "armeabi", "armeabi-v7a", "x86" or "mips" depending on ANDROID_ABI -# ANDROID_NDK_RELEASE : one of r5, r5b, r5c, r6, r6b, r7, r7b, r7c, r8, r8b, r8c, r8d, r8e; set only for NDK +# ANDROID_NDK_RELEASE : one of r5, r5b, r5c, r6, r6b, r7, r7b, r7c, r8, r8b, r8c, r8d, r8e, r9, r9b, r9c, r9d, r10; set only for NDK # ANDROID_ARCH_NAME : "arm" or "x86" or "mips" depending on ANDROID_ABI # ANDROID_SYSROOT : path to the compiler sysroot # TOOL_OS_SUFFIX : "" or ".exe" depending on host platform @@ -1743,4 +1852,4 @@ endif() # ANDROID_NDK_SEARCH_PATHS # ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH # ANDROID_SUPPORTED_ABIS_${ARCH} -# ANDROID_SUPPORTED_NDK_VERSIONS +# ANDROID_SUPPORTED_NDK_VERSIONS \ No newline at end of file diff --git a/android/build_arm64-v8a/lib/libwebsockets.a b/android/build_arm64-v8a/lib/libwebsockets.a new file mode 100644 index 0000000000..b37212d780 Binary files /dev/null and b/android/build_arm64-v8a/lib/libwebsockets.a differ diff --git a/android/build_arm64-v8a/lib/libwebsockets.so b/android/build_arm64-v8a/lib/libwebsockets.so new file mode 100644 index 0000000000..5d9359c816 Binary files /dev/null and b/android/build_arm64-v8a/lib/libwebsockets.so differ diff --git a/android/build_arm64-v8a/lib/libwebsockets.so.4.0.0 b/android/build_arm64-v8a/lib/libwebsockets.so.4.0.0 new file mode 100644 index 0000000000..5d9359c816 Binary files /dev/null and b/android/build_arm64-v8a/lib/libwebsockets.so.4.0.0 differ diff --git a/android/build_arm64-v8a/lws_config.h b/android/build_arm64-v8a/lws_config.h new file mode 100644 index 0000000000..f4df814eed --- /dev/null +++ b/android/build_arm64-v8a/lws_config.h @@ -0,0 +1,174 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +#ifndef WIN32 +#define _DEBUG +#endif + +/* Define to 1 to use CyaSSL as a replacement for OpenSSL. + * LWS_OPENSSL_SUPPORT needs to be set also for this to work. */ +/* #undef USE_CYASSL */ + +/* The Libwebsocket version */ +#define LWS_LIBRARY_VERSION "1.3" + +/* The current git commit hash that we're building from */ +/* #undef LWS_BUILD_HASH */ + +/* Build with OpenSSL support */ +/* #undef LWS_OPENSSL_SUPPORT */ + +/* The client should load and trust CA root certs it finds in the OS */ +#define LWS_SSL_CLIENT_USE_OS_CA_CERTS + +/* Sets the path where the client certs should be installed. */ +#define LWS_OPENSSL_CLIENT_CERTS "../share" + +/* Turn off websocket extensions */ +/* #undef LWS_NO_EXTENSIONS */ + +/* Enable libev io loop */ +/* #undef LWS_USE_LIBEV */ + +/* Build with support for ipv6 */ +#define LWS_USE_IPV6 + +/* Build with support for HTTP2 */ +/* #undef LWS_USE_HTTP2 */ + +/* Turn on latency measuring code */ +/* #undef LWS_LATENCY */ + +/* Don't build the daemonizeation api */ +/* #undef LWS_NO_DAEMONIZE */ + +/* Build without server support */ +#define LWS_NO_SERVER + +/* Build without client support */ +/* #undef LWS_NO_CLIENT */ + +/* If we should compile with MinGW support */ +/* #undef LWS_MINGW_SUPPORT */ + +/* Use the BSD getifaddrs that comes with libwebsocket, for uclibc support */ +#define LWS_BUILTIN_GETIFADDRS + +/* Define to 1 if you have the `bzero' function. */ +/* #undef HAVE_BZERO */ + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H + +/* Define to 1 if you have the `fork' function. */ +#define HAVE_FORK + +/* Define to 1 if you have the `getenv’ function. */ +#define HAVE_GETENV + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_IN6ADDR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H + +/* Define to 1 if you have the `ssl' library (-lssl). */ +/* #undef HAVE_LIBSSL */ + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#define HAVE_REALLOC + +/* Define to 1 if you have the `socket' function. */ +#define HAVE_SOCKET + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PRCTL_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H + +/* Define to 1 if you have the `vfork' function. */ +#define HAVE_VFORK + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VFORK_H */ + +/* Define to 1 if `fork' works. */ +#define HAVE_WORKING_FORK + +/* Define to 1 if `vfork' works. */ +#define HAVE_WORKING_VFORK + +/* Define to 1 if you have the header file. */ +#define HAVE_ZLIB_H + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR // We're not using libtool + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS + +/* Version number of package */ +#define VERSION + +/* Define to rpl_malloc if the replacement function should be used. */ +/* #undef malloc */ + +/* Define to `int' if does not define. */ +/* #undef pid_t */ + +/* Define to rpl_realloc if the replacement function should be used. */ +/* #undef realloc */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to 1 if we have getifaddrs */ +/* #undef HAVE_GETIFADDRS */ + +/* Define as `fork' if `vfork' does not work. */ +/* #undef vfork */ + +/* Define if the inline keyword doesn't exist. */ +/* #undef inline */ diff --git a/android/build_armeabi-v7a/lib/libwebsockets.a b/android/build_armeabi-v7a/lib/libwebsockets.a new file mode 100644 index 0000000000..3abf133704 Binary files /dev/null and b/android/build_armeabi-v7a/lib/libwebsockets.a differ diff --git a/android/build_armeabi-v7a/lib/libwebsockets.so b/android/build_armeabi-v7a/lib/libwebsockets.so new file mode 100644 index 0000000000..7628871f95 Binary files /dev/null and b/android/build_armeabi-v7a/lib/libwebsockets.so differ diff --git a/android/build_armeabi-v7a/lib/libwebsockets.so.4.0.0 b/android/build_armeabi-v7a/lib/libwebsockets.so.4.0.0 new file mode 100644 index 0000000000..7628871f95 Binary files /dev/null and b/android/build_armeabi-v7a/lib/libwebsockets.so.4.0.0 differ diff --git a/android/build_armeabi-v7a/lws_config.h b/android/build_armeabi-v7a/lws_config.h new file mode 100644 index 0000000000..77ad3bf163 --- /dev/null +++ b/android/build_armeabi-v7a/lws_config.h @@ -0,0 +1,174 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +#ifndef WIN32 +#define _DEBUG +#endif + +/* Define to 1 to use CyaSSL as a replacement for OpenSSL. + * LWS_OPENSSL_SUPPORT needs to be set also for this to work. */ +/* #undef USE_CYASSL */ + +/* The Libwebsocket version */ +#define LWS_LIBRARY_VERSION "1.3" + +/* The current git commit hash that we're building from */ +/* #undef LWS_BUILD_HASH */ + +/* Build with OpenSSL support */ +/* #undef LWS_OPENSSL_SUPPORT */ + +/* The client should load and trust CA root certs it finds in the OS */ +#define LWS_SSL_CLIENT_USE_OS_CA_CERTS + +/* Sets the path where the client certs should be installed. */ +#define LWS_OPENSSL_CLIENT_CERTS "../share" + +/* Turn off websocket extensions */ +/* #undef LWS_NO_EXTENSIONS */ + +/* Enable libev io loop */ +/* #undef LWS_USE_LIBEV */ + +/* Build with support for ipv6 */ +#define LWS_USE_IPV6 + +/* Build with support for HTTP2 */ +/* #undef LWS_USE_HTTP2 */ + +/* Turn on latency measuring code */ +/* #undef LWS_LATENCY */ + +/* Don't build the daemonizeation api */ +/* #undef LWS_NO_DAEMONIZE */ + +/* Build without server support */ +#define LWS_NO_SERVER + +/* Build without client support */ +/* #undef LWS_NO_CLIENT */ + +/* If we should compile with MinGW support */ +/* #undef LWS_MINGW_SUPPORT */ + +/* Use the BSD getifaddrs that comes with libwebsocket, for uclibc support */ +#define LWS_BUILTIN_GETIFADDRS + +/* Define to 1 if you have the `bzero' function. */ +#define HAVE_BZERO + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H + +/* Define to 1 if you have the `fork' function. */ +#define HAVE_FORK + +/* Define to 1 if you have the `getenv’ function. */ +#define HAVE_GETENV + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_IN6ADDR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H + +/* Define to 1 if you have the `ssl' library (-lssl). */ +/* #undef HAVE_LIBSSL */ + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#define HAVE_REALLOC + +/* Define to 1 if you have the `socket' function. */ +#define HAVE_SOCKET + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PRCTL_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H + +/* Define to 1 if you have the `vfork' function. */ +#define HAVE_VFORK + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VFORK_H */ + +/* Define to 1 if `fork' works. */ +#define HAVE_WORKING_FORK + +/* Define to 1 if `vfork' works. */ +#define HAVE_WORKING_VFORK + +/* Define to 1 if you have the header file. */ +#define HAVE_ZLIB_H + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR // We're not using libtool + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS + +/* Version number of package */ +#define VERSION + +/* Define to rpl_malloc if the replacement function should be used. */ +/* #undef malloc */ + +/* Define to `int' if does not define. */ +/* #undef pid_t */ + +/* Define to rpl_realloc if the replacement function should be used. */ +/* #undef realloc */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to 1 if we have getifaddrs */ +/* #undef HAVE_GETIFADDRS */ + +/* Define as `fork' if `vfork' does not work. */ +/* #undef vfork */ + +/* Define if the inline keyword doesn't exist. */ +/* #undef inline */ diff --git a/android/build_armeabi/lib/libwebsockets.a b/android/build_armeabi/lib/libwebsockets.a new file mode 100644 index 0000000000..68105c8143 Binary files /dev/null and b/android/build_armeabi/lib/libwebsockets.a differ diff --git a/android/build_armeabi/lib/libwebsockets.so b/android/build_armeabi/lib/libwebsockets.so new file mode 100644 index 0000000000..b967cc3461 Binary files /dev/null and b/android/build_armeabi/lib/libwebsockets.so differ diff --git a/android/build_armeabi/lib/libwebsockets.so.4.0.0 b/android/build_armeabi/lib/libwebsockets.so.4.0.0 new file mode 100644 index 0000000000..b967cc3461 Binary files /dev/null and b/android/build_armeabi/lib/libwebsockets.so.4.0.0 differ diff --git a/android/build_armeabi/lws_config.h b/android/build_armeabi/lws_config.h new file mode 100644 index 0000000000..77ad3bf163 --- /dev/null +++ b/android/build_armeabi/lws_config.h @@ -0,0 +1,174 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +#ifndef WIN32 +#define _DEBUG +#endif + +/* Define to 1 to use CyaSSL as a replacement for OpenSSL. + * LWS_OPENSSL_SUPPORT needs to be set also for this to work. */ +/* #undef USE_CYASSL */ + +/* The Libwebsocket version */ +#define LWS_LIBRARY_VERSION "1.3" + +/* The current git commit hash that we're building from */ +/* #undef LWS_BUILD_HASH */ + +/* Build with OpenSSL support */ +/* #undef LWS_OPENSSL_SUPPORT */ + +/* The client should load and trust CA root certs it finds in the OS */ +#define LWS_SSL_CLIENT_USE_OS_CA_CERTS + +/* Sets the path where the client certs should be installed. */ +#define LWS_OPENSSL_CLIENT_CERTS "../share" + +/* Turn off websocket extensions */ +/* #undef LWS_NO_EXTENSIONS */ + +/* Enable libev io loop */ +/* #undef LWS_USE_LIBEV */ + +/* Build with support for ipv6 */ +#define LWS_USE_IPV6 + +/* Build with support for HTTP2 */ +/* #undef LWS_USE_HTTP2 */ + +/* Turn on latency measuring code */ +/* #undef LWS_LATENCY */ + +/* Don't build the daemonizeation api */ +/* #undef LWS_NO_DAEMONIZE */ + +/* Build without server support */ +#define LWS_NO_SERVER + +/* Build without client support */ +/* #undef LWS_NO_CLIENT */ + +/* If we should compile with MinGW support */ +/* #undef LWS_MINGW_SUPPORT */ + +/* Use the BSD getifaddrs that comes with libwebsocket, for uclibc support */ +#define LWS_BUILTIN_GETIFADDRS + +/* Define to 1 if you have the `bzero' function. */ +#define HAVE_BZERO + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H + +/* Define to 1 if you have the `fork' function. */ +#define HAVE_FORK + +/* Define to 1 if you have the `getenv’ function. */ +#define HAVE_GETENV + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_IN6ADDR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H + +/* Define to 1 if you have the `ssl' library (-lssl). */ +/* #undef HAVE_LIBSSL */ + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#define HAVE_REALLOC + +/* Define to 1 if you have the `socket' function. */ +#define HAVE_SOCKET + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PRCTL_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H + +/* Define to 1 if you have the `vfork' function. */ +#define HAVE_VFORK + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VFORK_H */ + +/* Define to 1 if `fork' works. */ +#define HAVE_WORKING_FORK + +/* Define to 1 if `vfork' works. */ +#define HAVE_WORKING_VFORK + +/* Define to 1 if you have the header file. */ +#define HAVE_ZLIB_H + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR // We're not using libtool + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS + +/* Version number of package */ +#define VERSION + +/* Define to rpl_malloc if the replacement function should be used. */ +/* #undef malloc */ + +/* Define to `int' if does not define. */ +/* #undef pid_t */ + +/* Define to rpl_realloc if the replacement function should be used. */ +/* #undef realloc */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to 1 if we have getifaddrs */ +/* #undef HAVE_GETIFADDRS */ + +/* Define as `fork' if `vfork' does not work. */ +/* #undef vfork */ + +/* Define if the inline keyword doesn't exist. */ +/* #undef inline */ diff --git a/android/build_x86/lib/libwebsockets.a b/android/build_x86/lib/libwebsockets.a new file mode 100644 index 0000000000..737b4f64b6 Binary files /dev/null and b/android/build_x86/lib/libwebsockets.a differ diff --git a/android/build_x86/lib/libwebsockets.so b/android/build_x86/lib/libwebsockets.so new file mode 100644 index 0000000000..43ee4795e6 Binary files /dev/null and b/android/build_x86/lib/libwebsockets.so differ diff --git a/android/build_x86/lib/libwebsockets.so.4.0.0 b/android/build_x86/lib/libwebsockets.so.4.0.0 new file mode 100644 index 0000000000..43ee4795e6 Binary files /dev/null and b/android/build_x86/lib/libwebsockets.so.4.0.0 differ diff --git a/android/build_x86/lws_config.h b/android/build_x86/lws_config.h new file mode 100644 index 0000000000..77ad3bf163 --- /dev/null +++ b/android/build_x86/lws_config.h @@ -0,0 +1,174 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +#ifndef WIN32 +#define _DEBUG +#endif + +/* Define to 1 to use CyaSSL as a replacement for OpenSSL. + * LWS_OPENSSL_SUPPORT needs to be set also for this to work. */ +/* #undef USE_CYASSL */ + +/* The Libwebsocket version */ +#define LWS_LIBRARY_VERSION "1.3" + +/* The current git commit hash that we're building from */ +/* #undef LWS_BUILD_HASH */ + +/* Build with OpenSSL support */ +/* #undef LWS_OPENSSL_SUPPORT */ + +/* The client should load and trust CA root certs it finds in the OS */ +#define LWS_SSL_CLIENT_USE_OS_CA_CERTS + +/* Sets the path where the client certs should be installed. */ +#define LWS_OPENSSL_CLIENT_CERTS "../share" + +/* Turn off websocket extensions */ +/* #undef LWS_NO_EXTENSIONS */ + +/* Enable libev io loop */ +/* #undef LWS_USE_LIBEV */ + +/* Build with support for ipv6 */ +#define LWS_USE_IPV6 + +/* Build with support for HTTP2 */ +/* #undef LWS_USE_HTTP2 */ + +/* Turn on latency measuring code */ +/* #undef LWS_LATENCY */ + +/* Don't build the daemonizeation api */ +/* #undef LWS_NO_DAEMONIZE */ + +/* Build without server support */ +#define LWS_NO_SERVER + +/* Build without client support */ +/* #undef LWS_NO_CLIENT */ + +/* If we should compile with MinGW support */ +/* #undef LWS_MINGW_SUPPORT */ + +/* Use the BSD getifaddrs that comes with libwebsocket, for uclibc support */ +#define LWS_BUILTIN_GETIFADDRS + +/* Define to 1 if you have the `bzero' function. */ +#define HAVE_BZERO + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H + +/* Define to 1 if you have the `fork' function. */ +#define HAVE_FORK + +/* Define to 1 if you have the `getenv’ function. */ +#define HAVE_GETENV + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_IN6ADDR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H + +/* Define to 1 if you have the `ssl' library (-lssl). */ +/* #undef HAVE_LIBSSL */ + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#define HAVE_REALLOC + +/* Define to 1 if you have the `socket' function. */ +#define HAVE_SOCKET + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PRCTL_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H + +/* Define to 1 if you have the `vfork' function. */ +#define HAVE_VFORK + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VFORK_H */ + +/* Define to 1 if `fork' works. */ +#define HAVE_WORKING_FORK + +/* Define to 1 if `vfork' works. */ +#define HAVE_WORKING_VFORK + +/* Define to 1 if you have the header file. */ +#define HAVE_ZLIB_H + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR // We're not using libtool + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS + +/* Version number of package */ +#define VERSION + +/* Define to rpl_malloc if the replacement function should be used. */ +/* #undef malloc */ + +/* Define to `int' if does not define. */ +/* #undef pid_t */ + +/* Define to rpl_realloc if the replacement function should be used. */ +/* #undef realloc */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to 1 if we have getifaddrs */ +/* #undef HAVE_GETIFADDRS */ + +/* Define as `fork' if `vfork' does not work. */ +/* #undef vfork */ + +/* Define if the inline keyword doesn't exist. */ +/* #undef inline */ diff --git a/android/dist/armv5/include/libwebsockets.h b/android/dist/armv5/include/libwebsockets.h new file mode 100644 index 0000000000..0bb67f57bc --- /dev/null +++ b/android/dist/armv5/include/libwebsockets.h @@ -0,0 +1,1207 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010-2013 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef LIBWEBSOCKET_H_3060898B846849FF9F88F5DB59B5950C +#define LIBWEBSOCKET_H_3060898B846849FF9F88F5DB59B5950C + +#ifdef __cplusplus +extern "C" { +#include +#endif + +#ifdef CMAKE_BUILD +#include "lws_config.h" +#endif + +#if defined(WIN32) || defined(_WIN32) + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include +#include + +#define strcasecmp stricmp +#define getdtablesize() 30000 + +#define LWS_VISIBLE + +#ifdef LWS_DLL +#ifdef LWS_INTERNAL +#define LWS_EXTERN extern __declspec(dllexport) +#else +#define LWS_EXTERN extern __declspec(dllimport) +#endif +#else +#define LWS_EXTERN +#endif + +#else // NOT WIN32 + +#include +#include + +#if defined(__GNUC__) +#define LWS_VISIBLE __attribute__((visibility("default"))) +#else +#define LWS_VISIBLE +#endif + +#endif + +#ifdef LWS_USE_LIBEV +#include +#endif /* LWS_USE_LIBEV */ + +#include + +#ifndef LWS_EXTERN +#define LWS_EXTERN extern +#endif + +#ifdef _WIN32 +#define random rand +#else +#include +#include +#endif + +#define CONTEXT_PORT_NO_LISTEN -1 +#define MAX_MUX_RECURSION 2 + +enum lws_log_levels { + LLL_ERR = 1 << 0, + LLL_WARN = 1 << 1, + LLL_NOTICE = 1 << 2, + LLL_INFO = 1 << 3, + LLL_DEBUG = 1 << 4, + LLL_PARSER = 1 << 5, + LLL_HEADER = 1 << 6, + LLL_EXT = 1 << 7, + LLL_CLIENT = 1 << 8, + LLL_LATENCY = 1 << 9, + + LLL_COUNT = 10 /* set to count of valid flags */ +}; + +LWS_VISIBLE LWS_EXTERN void _lws_log(int filter, const char *format, ...); + +/* notice, warn and log are always compiled in */ +#define lwsl_notice(...) _lws_log(LLL_NOTICE, __VA_ARGS__) +#define lwsl_warn(...) _lws_log(LLL_WARN, __VA_ARGS__) +#define lwsl_err(...) _lws_log(LLL_ERR, __VA_ARGS__) +/* + * weaker logging can be deselected at configure time using --disable-debug + * that gets rid of the overhead of checking while keeping _warn and _err + * active + */ +#ifdef _DEBUG + +#define lwsl_info(...) _lws_log(LLL_INFO, __VA_ARGS__) +#define lwsl_debug(...) _lws_log(LLL_DEBUG, __VA_ARGS__) +#define lwsl_parser(...) _lws_log(LLL_PARSER, __VA_ARGS__) +#define lwsl_header(...) _lws_log(LLL_HEADER, __VA_ARGS__) +#define lwsl_ext(...) _lws_log(LLL_EXT, __VA_ARGS__) +#define lwsl_client(...) _lws_log(LLL_CLIENT, __VA_ARGS__) +#define lwsl_latency(...) _lws_log(LLL_LATENCY, __VA_ARGS__) +LWS_VISIBLE LWS_EXTERN void lwsl_hexdump(void *buf, size_t len); + +#else /* no debug */ + +#define lwsl_info(...) +#define lwsl_debug(...) +#define lwsl_parser(...) +#define lwsl_header(...) +#define lwsl_ext(...) +#define lwsl_client(...) +#define lwsl_latency(...) +#define lwsl_hexdump(a, b) + +#endif + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +/* api change list for user code to test against */ + +#define LWS_FEATURE_SERVE_HTTP_FILE_HAS_OTHER_HEADERS_ARG + + +enum libwebsocket_context_options { + LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT = 2, + LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME = 4, + LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT = 8, + LWS_SERVER_OPTION_LIBEV = 16, + LWS_SERVER_OPTION_DISABLE_IPV6 = 32, + LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS = 64, +}; + +enum libwebsocket_callback_reasons { + LWS_CALLBACK_ESTABLISHED, + LWS_CALLBACK_CLIENT_CONNECTION_ERROR, + LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH, + LWS_CALLBACK_CLIENT_ESTABLISHED, + LWS_CALLBACK_CLOSED, + LWS_CALLBACK_CLOSED_HTTP, + LWS_CALLBACK_RECEIVE, + LWS_CALLBACK_CLIENT_RECEIVE, + LWS_CALLBACK_CLIENT_RECEIVE_PONG, + LWS_CALLBACK_CLIENT_WRITEABLE, + LWS_CALLBACK_SERVER_WRITEABLE, + LWS_CALLBACK_HTTP, + LWS_CALLBACK_HTTP_BODY, + LWS_CALLBACK_HTTP_BODY_COMPLETION, + LWS_CALLBACK_HTTP_FILE_COMPLETION, + LWS_CALLBACK_HTTP_WRITEABLE, + LWS_CALLBACK_FILTER_NETWORK_CONNECTION, + LWS_CALLBACK_FILTER_HTTP_CONNECTION, + LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, + LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, + LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION, + LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, + LWS_CALLBACK_CONFIRM_EXTENSION_OKAY, + LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED, + LWS_CALLBACK_PROTOCOL_INIT, + LWS_CALLBACK_PROTOCOL_DESTROY, + LWS_CALLBACK_WSI_CREATE, /* always protocol[0] */ + LWS_CALLBACK_WSI_DESTROY, /* always protocol[0] */ + LWS_CALLBACK_GET_THREAD_ID, + + /* external poll() management support */ + LWS_CALLBACK_ADD_POLL_FD, + LWS_CALLBACK_DEL_POLL_FD, + LWS_CALLBACK_CHANGE_MODE_POLL_FD, + LWS_CALLBACK_LOCK_POLL, + LWS_CALLBACK_UNLOCK_POLL, + + LWS_CALLBACK_USER = 1000, /* user code can use any including / above */ +}; + +// argument structure for all external poll related calls +// passed in via 'in' +struct libwebsocket_pollargs { + int fd; // applicable file descriptor + int events; // the new event mask + int prev_events; // the previous event mask +}; + +#ifdef _WIN32 +struct libwebsocket_pollfd { + SOCKET fd; + SHORT events; + SHORT revents; +}; +#else +#define libwebsocket_pollfd pollfd +#endif + +enum libwebsocket_extension_callback_reasons { + LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT, + LWS_EXT_CALLBACK_SERVER_CONTEXT_DESTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_DESTRUCT, + LWS_EXT_CALLBACK_CONSTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONSTRUCT, + LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE, + LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION, + LWS_EXT_CALLBACK_DESTROY, + LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING, + LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED, + LWS_EXT_CALLBACK_PACKET_RX_PREPARSE, + LWS_EXT_CALLBACK_PACKET_TX_PRESEND, + LWS_EXT_CALLBACK_PACKET_TX_DO_SEND, + LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX, + LWS_EXT_CALLBACK_FLUSH_PENDING_TX, + LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX, + LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION, + LWS_EXT_CALLBACK_1HZ, + LWS_EXT_CALLBACK_REQUEST_ON_WRITEABLE, + LWS_EXT_CALLBACK_IS_WRITEABLE, + LWS_EXT_CALLBACK_PAYLOAD_TX, + LWS_EXT_CALLBACK_PAYLOAD_RX, +}; + +enum libwebsocket_write_protocol { + LWS_WRITE_TEXT, + LWS_WRITE_BINARY, + LWS_WRITE_CONTINUATION, + LWS_WRITE_HTTP, + + /* special 04+ opcodes */ + + LWS_WRITE_CLOSE, + LWS_WRITE_PING, + LWS_WRITE_PONG, + + /* flags */ + + LWS_WRITE_NO_FIN = 0x40, + /* + * client packet payload goes out on wire unmunged + * only useful for security tests since normal servers cannot + * decode the content if used + */ + LWS_WRITE_CLIENT_IGNORE_XOR_MASK = 0x80 +}; + +/* + * you need these to look at headers that have been parsed if using the + * LWS_CALLBACK_FILTER_CONNECTION callback. If a header from the enum + * list below is absent, .token = NULL and token_len = 0. Otherwise .token + * points to .token_len chars containing that header content. + */ + +struct lws_tokens { + char *token; + int token_len; +}; + +enum lws_token_indexes { + WSI_TOKEN_GET_URI, + WSI_TOKEN_POST_URI, + WSI_TOKEN_OPTIONS_URI, + WSI_TOKEN_HOST, + WSI_TOKEN_CONNECTION, + WSI_TOKEN_KEY1, + WSI_TOKEN_KEY2, + WSI_TOKEN_PROTOCOL, + WSI_TOKEN_UPGRADE, + WSI_TOKEN_ORIGIN, + WSI_TOKEN_DRAFT, + WSI_TOKEN_CHALLENGE, + + /* new for 04 */ + WSI_TOKEN_KEY, + WSI_TOKEN_VERSION, + WSI_TOKEN_SWORIGIN, + + /* new for 05 */ + WSI_TOKEN_EXTENSIONS, + + /* client receives these */ + WSI_TOKEN_ACCEPT, + WSI_TOKEN_NONCE, + WSI_TOKEN_HTTP, + + /* http-related */ + WSI_TOKEN_HTTP_ACCEPT, + WSI_TOKEN_HTTP_AC_REQUEST_HEADERS, + WSI_TOKEN_HTTP_IF_MODIFIED_SINCE, + WSI_TOKEN_HTTP_IF_NONE_MATCH, + WSI_TOKEN_HTTP_ACCEPT_ENCODING, + WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, + WSI_TOKEN_HTTP_PRAGMA, + WSI_TOKEN_HTTP_CACHE_CONTROL, + WSI_TOKEN_HTTP_AUTHORIZATION, + WSI_TOKEN_HTTP_COOKIE, + WSI_TOKEN_HTTP_CONTENT_LENGTH, + WSI_TOKEN_HTTP_CONTENT_TYPE, + WSI_TOKEN_HTTP_DATE, + WSI_TOKEN_HTTP_RANGE, + WSI_TOKEN_HTTP_REFERER, + WSI_TOKEN_HTTP_URI_ARGS, + + + WSI_TOKEN_MUXURL, + + /* use token storage to stash these */ + + _WSI_TOKEN_CLIENT_SENT_PROTOCOLS, + _WSI_TOKEN_CLIENT_PEER_ADDRESS, + _WSI_TOKEN_CLIENT_URI, + _WSI_TOKEN_CLIENT_HOST, + _WSI_TOKEN_CLIENT_ORIGIN, + + /* always last real token index*/ + WSI_TOKEN_COUNT, + /* parser state additions */ + WSI_TOKEN_NAME_PART, + WSI_TOKEN_SKIPPING, + WSI_TOKEN_SKIPPING_SAW_CR, + WSI_PARSING_COMPLETE, + WSI_INIT_TOKEN_MUXURL, +}; + +struct lws_token_limits { + unsigned short token_limit[WSI_TOKEN_COUNT]; +}; + +/* + * From RFC 6455 + 1000 + + 1000 indicates a normal closure, meaning that the purpose for + which the connection was established has been fulfilled. + + 1001 + + 1001 indicates that an endpoint is "going away", such as a server + going down or a browser having navigated away from a page. + + 1002 + + 1002 indicates that an endpoint is terminating the connection due + to a protocol error. + + 1003 + + 1003 indicates that an endpoint is terminating the connection + because it has received a type of data it cannot accept (e.g., an + endpoint that understands only text data MAY send this if it + receives a binary message). + + 1004 + + Reserved. The specific meaning might be defined in the future. + + 1005 + + 1005 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that no status + code was actually present. + + 1006 + + 1006 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that the + connection was closed abnormally, e.g., without sending or + receiving a Close control frame. + + 1007 + + 1007 indicates that an endpoint is terminating the connection + because it has received data within a message that was not + consistent with the type of the message (e.g., non-UTF-8 [RFC3629] + data within a text message). + + 1008 + + 1008 indicates that an endpoint is terminating the connection + because it has received a message that violates its policy. This + is a generic status code that can be returned when there is no + other more suitable status code (e.g., 1003 or 1009) or if there + is a need to hide specific details about the policy. + + 1009 + + 1009 indicates that an endpoint is terminating the connection + because it has received a message that is too big for it to + process. + + 1010 + + 1010 indicates that an endpoint (client) is terminating the + connection because it has expected the server to negotiate one or + more extension, but the server didn't return them in the response + message of the WebSocket handshake. The list of extensions that + are needed SHOULD appear in the /reason/ part of the Close frame. + Note that this status code is not used by the server, because it + can fail the WebSocket handshake instead. + + 1011 + + 1011 indicates that a server is terminating the connection because + it encountered an unexpected condition that prevented it from + fulfilling the request. + + 1015 + + 1015 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that the + connection was closed due to a failure to perform a TLS handshake + (e.g., the server certificate can't be verified). +*/ + +enum lws_close_status { + LWS_CLOSE_STATUS_NOSTATUS = 0, + LWS_CLOSE_STATUS_NORMAL = 1000, + LWS_CLOSE_STATUS_GOINGAWAY = 1001, + LWS_CLOSE_STATUS_PROTOCOL_ERR = 1002, + LWS_CLOSE_STATUS_UNACCEPTABLE_OPCODE = 1003, + LWS_CLOSE_STATUS_RESERVED = 1004, + LWS_CLOSE_STATUS_NO_STATUS = 1005, + LWS_CLOSE_STATUS_ABNORMAL_CLOSE = 1006, + LWS_CLOSE_STATUS_INVALID_PAYLOAD = 1007, + LWS_CLOSE_STATUS_POLICY_VIOLATION = 1008, + LWS_CLOSE_STATUS_MESSAGE_TOO_LARGE = 1009, + LWS_CLOSE_STATUS_EXTENSION_REQUIRED = 1010, + LWS_CLOSE_STATUS_UNEXPECTED_CONDITION = 1011, + LWS_CLOSE_STATUS_TLS_FAILURE = 1015, +}; + +enum http_status { + HTTP_STATUS_OK = 200, + HTTP_STATUS_NO_CONTENT = 204, + + HTTP_STATUS_BAD_REQUEST = 400, + HTTP_STATUS_UNAUTHORIZED, + HTTP_STATUS_PAYMENT_REQUIRED, + HTTP_STATUS_FORBIDDEN, + HTTP_STATUS_NOT_FOUND, + HTTP_STATUS_METHOD_NOT_ALLOWED, + HTTP_STATUS_NOT_ACCEPTABLE, + HTTP_STATUS_PROXY_AUTH_REQUIRED, + HTTP_STATUS_REQUEST_TIMEOUT, + HTTP_STATUS_CONFLICT, + HTTP_STATUS_GONE, + HTTP_STATUS_LENGTH_REQUIRED, + HTTP_STATUS_PRECONDITION_FAILED, + HTTP_STATUS_REQ_ENTITY_TOO_LARGE, + HTTP_STATUS_REQ_URI_TOO_LONG, + HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, + HTTP_STATUS_REQ_RANGE_NOT_SATISFIABLE, + HTTP_STATUS_EXPECTATION_FAILED, + + HTTP_STATUS_INTERNAL_SERVER_ERROR = 500, + HTTP_STATUS_NOT_IMPLEMENTED, + HTTP_STATUS_BAD_GATEWAY, + HTTP_STATUS_SERVICE_UNAVAILABLE, + HTTP_STATUS_GATEWAY_TIMEOUT, + HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED, +}; + +struct libwebsocket; +struct libwebsocket_context; +/* needed even with extensions disabled for create context */ +struct libwebsocket_extension; + +/** + * callback_function() - User server actions + * @context: Websockets context + * @wsi: Opaque websocket instance pointer + * @reason: The reason for the call + * @user: Pointer to per-session user data allocated by library + * @in: Pointer used for some callback reasons + * @len: Length set for some callback reasons + * + * This callback is the way the user controls what is served. All the + * protocol detail is hidden and handled by the library. + * + * For each connection / session there is user data allocated that is + * pointed to by "user". You set the size of this user data area when + * the library is initialized with libwebsocket_create_server. + * + * You get an opportunity to initialize user data when called back with + * LWS_CALLBACK_ESTABLISHED reason. + * + * LWS_CALLBACK_ESTABLISHED: after the server completes a handshake with + * an incoming client + * + * LWS_CALLBACK_CLIENT_CONNECTION_ERROR: the request client connection has + * been unable to complete a handshake with the remote server + * + * LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH: this is the last chance for the + * client user code to examine the http headers + * and decide to reject the connection. If the + * content in the headers is interesting to the + * client (url, etc) it needs to copy it out at + * this point since it will be destroyed before + * the CLIENT_ESTABLISHED call + * + * LWS_CALLBACK_CLIENT_ESTABLISHED: after your client connection completed + * a handshake with the remote server + * + * LWS_CALLBACK_CLOSED: when the websocket session ends + * + * LWS_CALLBACK_CLOSED_HTTP: when a HTTP (non-websocket) session ends + * + * LWS_CALLBACK_RECEIVE: data has appeared for this server endpoint from a + * remote client, it can be found at *in and is + * len bytes long + * + * LWS_CALLBACK_CLIENT_RECEIVE_PONG: if you elected to see PONG packets, + * they appear with this callback reason. PONG + * packets only exist in 04+ protocol + * + * LWS_CALLBACK_CLIENT_RECEIVE: data has appeared from the server for the + * client connection, it can be found at *in and + * is len bytes long + * + * LWS_CALLBACK_HTTP: an http request has come from a client that is not + * asking to upgrade the connection to a websocket + * one. This is a chance to serve http content, + * for example, to send a script to the client + * which will then open the websockets connection. + * @in points to the URI path requested and + * libwebsockets_serve_http_file() makes it very + * simple to send back a file to the client. + * Normally after sending the file you are done + * with the http connection, since the rest of the + * activity will come by websockets from the script + * that was delivered by http, so you will want to + * return 1; to close and free up the connection. + * That's important because it uses a slot in the + * total number of client connections allowed set + * by MAX_CLIENTS. + * + * LWS_CALLBACK_HTTP_BODY: the next @len bytes data from the http + * request body HTTP connection is now available in @in. + * + * LWS_CALLBACK_HTTP_BODY_COMPLETION: the expected amount of http request + * body has been delivered + * + * LWS_CALLBACK_HTTP_WRITEABLE: you can write more down the http protocol + * link now. + * + * LWS_CALLBACK_HTTP_FILE_COMPLETION: a file requested to be send down + * http link has completed. + * + * LWS_CALLBACK_CLIENT_WRITEABLE: + * LWS_CALLBACK_SERVER_WRITEABLE: If you call + * libwebsocket_callback_on_writable() on a connection, you will + * get one of these callbacks coming when the connection socket + * is able to accept another write packet without blocking. + * If it already was able to take another packet without blocking, + * you'll get this callback at the next call to the service loop + * function. Notice that CLIENTs get LWS_CALLBACK_CLIENT_WRITEABLE + * and servers get LWS_CALLBACK_SERVER_WRITEABLE. + * + * LWS_CALLBACK_FILTER_NETWORK_CONNECTION: called when a client connects to + * the server at network level; the connection is accepted but then + * passed to this callback to decide whether to hang up immediately + * or not, based on the client IP. @in contains the connection + * socket's descriptor. Since the client connection information is + * not available yet, @wsi still pointing to the main server socket. + * Return non-zero to terminate the connection before sending or + * receiving anything. Because this happens immediately after the + * network connection from the client, there's no websocket protocol + * selected yet so this callback is issued only to protocol 0. + * + * LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED: A new client just had + * been connected, accepted, and instantiated into the pool. This + * callback allows setting any relevant property to it. Because this + * happens immediately after the instantiation of a new client, + * there's no websocket protocol selected yet so this callback is + * issued only to protocol 0. Only @wsi is defined, pointing to the + * new client, and the return value is ignored. + * + * LWS_CALLBACK_FILTER_HTTP_CONNECTION: called when the request has + * been received and parsed from the client, but the response is + * not sent yet. Return non-zero to disallow the connection. + * @user is a pointer to the connection user space allocation, + * @in is the URI, eg, "/" + * In your handler you can use the public APIs + * lws_hdr_total_length() / lws_hdr_copy() to access all of the + * headers using the header enums lws_token_indexes from + * libwebsockets.h to check for and read the supported header + * presence and content before deciding to allow the http + * connection to proceed or to kill the connection. + * + * LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: called when the handshake has + * been received and parsed from the client, but the response is + * not sent yet. Return non-zero to disallow the connection. + * @user is a pointer to the connection user space allocation, + * @in is the requested protocol name + * In your handler you can use the public APIs + * lws_hdr_total_length() / lws_hdr_copy() to access all of the + * headers using the header enums lws_token_indexes from + * libwebsockets.h to check for and read the supported header + * presence and content before deciding to allow the handshake + * to proceed or to kill the connection. + * + * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: if configured for + * including OpenSSL support, this callback allows your user code + * to perform extra SSL_CTX_load_verify_locations() or similar + * calls to direct OpenSSL where to find certificates the client + * can use to confirm the remote server identity. @user is the + * OpenSSL SSL_CTX* + * + * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: if configured for + * including OpenSSL support, this callback allows your user code + * to load extra certifcates into the server which allow it to + * verify the validity of certificates returned by clients. @user + * is the server's OpenSSL SSL_CTX* + * + * LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: if the + * libwebsockets context was created with the option + * LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT, then this + * callback is generated during OpenSSL verification of the cert + * sent from the client. It is sent to protocol[0] callback as + * no protocol has been negotiated on the connection yet. + * Notice that the libwebsockets context and wsi are both NULL + * during this callback. See + * http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html + * to understand more detail about the OpenSSL callback that + * generates this libwebsockets callback and the meanings of the + * arguments passed. In this callback, @user is the x509_ctx, + * @in is the ssl pointer and @len is preverify_ok + * Notice that this callback maintains libwebsocket return + * conventions, return 0 to mean the cert is OK or 1 to fail it. + * This also means that if you don't handle this callback then + * the default callback action of returning 0 allows the client + * certificates. + * + * LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: this callback happens + * when a client handshake is being compiled. @user is NULL, + * @in is a char **, it's pointing to a char * which holds the + * next location in the header buffer where you can add + * headers, and @len is the remaining space in the header buffer, + * which is typically some hundreds of bytes. So, to add a canned + * cookie, your handler code might look similar to: + * + * char **p = (char **)in; + * + * if (len < 100) + * return 1; + * + * *p += sprintf(*p, "Cookie: a=b\x0d\x0a"); + * + * return 0; + * + * Notice if you add anything, you just have to take care about + * the CRLF on the line you added. Obviously this callback is + * optional, if you don't handle it everything is fine. + * + * Notice the callback is coming to protocols[0] all the time, + * because there is no specific protocol handshook yet. + * + * LWS_CALLBACK_CONFIRM_EXTENSION_OKAY: When the server handshake code + * sees that it does support a requested extension, before + * accepting the extension by additing to the list sent back to + * the client it gives this callback just to check that it's okay + * to use that extension. It calls back to the requested protocol + * and with @in being the extension name, @len is 0 and @user is + * valid. Note though at this time the ESTABLISHED callback hasn't + * happened yet so if you initialize @user content there, @user + * content during this callback might not be useful for anything. + * Notice this callback comes to protocols[0]. + * + * LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: When a client + * connection is being prepared to start a handshake to a server, + * each supported extension is checked with protocols[0] callback + * with this reason, giving the user code a chance to suppress the + * claim to support that extension by returning non-zero. If + * unhandled, by default 0 will be returned and the extension + * support included in the header to the server. Notice this + * callback comes to protocols[0]. + * + * LWS_CALLBACK_PROTOCOL_INIT: One-time call per protocol so it can + * do initial setup / allocations etc + * + * LWS_CALLBACK_PROTOCOL_DESTROY: One-time call per protocol indicating + * this protocol won't get used at all after this callback, the + * context is getting destroyed. Take the opportunity to + * deallocate everything that was allocated by the protocol. + * + * LWS_CALLBACK_WSI_CREATE: outermost (earliest) wsi create notification + * + * LWS_CALLBACK_WSI_DESTROY: outermost (latest) wsi destroy notification + * + * The next five reasons are optional and only need taking care of if you + * will be integrating libwebsockets sockets into an external polling + * array. + * + * For these calls, @in points to a struct libwebsocket_pollargs that + * contains @fd, @events and @prev_events members + * + * LWS_CALLBACK_ADD_POLL_FD: libwebsocket deals with its poll() loop + * internally, but in the case you are integrating with another + * server you will need to have libwebsocket sockets share a + * polling array with the other server. This and the other + * POLL_FD related callbacks let you put your specialized + * poll array interface code in the callback for protocol 0, the + * first protocol you support, usually the HTTP protocol in the + * serving case. + * This callback happens when a socket needs to be + * added to the polling loop: @in points to a struct + * libwebsocket_pollargs; the @fd member of the struct is the file + * descriptor, and @events contains the active events. + * + * If you are using the internal polling loop (the "service" + * callback), you can just ignore these callbacks. + * + * LWS_CALLBACK_DEL_POLL_FD: This callback happens when a socket descriptor + * needs to be removed from an external polling array. @in is + * again the struct libwebsocket_pollargs containing the @fd member + * to be removed. If you are using the internal polling + * loop, you can just ignore it. + * + * LWS_CALLBACK_CHANGE_MODE_POLL_FD: This callback happens when + * libwebsockets wants to modify the events for a connectiion. + * @in is the struct libwebsocket_pollargs with the @fd to change. + * The new event mask is in @events member and the old mask is in + * the @prev_events member. + * If you are using the internal polling loop, you can just ignore + * it. + * + * LWS_CALLBACK_LOCK_POLL: + * LWS_CALLBACK_UNLOCK_POLL: These allow the external poll changes driven + * by libwebsockets to participate in an external thread locking + * scheme around the changes, so the whole thing is threadsafe. + */ +LWS_VISIBLE LWS_EXTERN int callback(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len); + +typedef int (callback_function)(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len); + +#ifndef LWS_NO_EXTENSIONS +/** + * extension_callback_function() - Hooks to allow extensions to operate + * @context: Websockets context + * @ext: This extension + * @wsi: Opaque websocket instance pointer + * @reason: The reason for the call + * @user: Pointer to per-session user data allocated by library + * @in: Pointer used for some callback reasons + * @len: Length set for some callback reasons + * + * Each extension that is active on a particular connection receives + * callbacks during the connection lifetime to allow the extension to + * operate on websocket data and manage itself. + * + * Libwebsockets takes care of allocating and freeing "user" memory for + * each active extension on each connection. That is what is pointed to + * by the @user parameter. + * + * LWS_EXT_CALLBACK_CONSTRUCT: called when the server has decided to + * select this extension from the list provided by the client, + * just before the server will send back the handshake accepting + * the connection with this extension active. This gives the + * extension a chance to initialize its connection context found + * in @user. + * + * LWS_EXT_CALLBACK_CLIENT_CONSTRUCT: same as LWS_EXT_CALLBACK_CONSTRUCT + * but called when client is instantiating this extension. Some + * extensions will work the same on client and server side and then + * you can just merge handlers for both CONSTRUCTS. + * + * LWS_EXT_CALLBACK_DESTROY: called when the connection the extension was + * being used on is about to be closed and deallocated. It's the + * last chance for the extension to deallocate anything it has + * allocated in the user data (pointed to by @user) before the + * user data is deleted. This same callback is used whether you + * are in client or server instantiation context. + * + * LWS_EXT_CALLBACK_PACKET_RX_PREPARSE: when this extension was active on + * a connection, and a packet of data arrived at the connection, + * it is passed to this callback to give the extension a chance to + * change the data, eg, decompress it. @user is pointing to the + * extension's private connection context data, @in is pointing + * to an lws_tokens struct, it consists of a char * pointer called + * token, and an int called token_len. At entry, these are + * set to point to the received buffer and set to the content + * length. If the extension will grow the content, it should use + * a new buffer allocated in its private user context data and + * set the pointed-to lws_tokens members to point to its buffer. + * + * LWS_EXT_CALLBACK_PACKET_TX_PRESEND: this works the same way as + * LWS_EXT_CALLBACK_PACKET_RX_PREPARSE above, except it gives the + * extension a chance to change websocket data just before it will + * be sent out. Using the same lws_token pointer scheme in @in, + * the extension can change the buffer and the length to be + * transmitted how it likes. Again if it wants to grow the + * buffer safely, it should copy the data into its own buffer and + * set the lws_tokens token pointer to it. + */ +LWS_VISIBLE LWS_EXTERN int extension_callback(struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); + +typedef int (extension_callback_function)(struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); +#endif + +/** + * struct libwebsocket_protocols - List of protocols and handlers server + * supports. + * @name: Protocol name that must match the one given in the client + * Javascript new WebSocket(url, 'protocol') name + * @callback: The service callback used for this protocol. It allows the + * service action for an entire protocol to be encapsulated in + * the protocol-specific callback + * @per_session_data_size: Each new connection using this protocol gets + * this much memory allocated on connection establishment and + * freed on connection takedown. A pointer to this per-connection + * allocation is passed into the callback in the 'user' parameter + * @rx_buffer_size: if you want atomic frames delivered to the callback, you + * should set this to the size of the biggest legal frame that + * you support. If the frame size is exceeded, there is no + * error, but the buffer will spill to the user callback when + * full, which you can detect by using + * libwebsockets_remaining_packet_payload(). Notice that you + * just talk about frame size here, the LWS_SEND_BUFFER_PRE_PADDING + * and post-padding are automatically also allocated on top. + * @no_buffer_all_partial_tx: Leave at zero if you want the library to take + * care of all partial tx for you. It's useful if you only have + * small tx packets and the chance of any truncated send is small + * enough any additional malloc / buffering overhead is less + * painful than writing the code to deal with partial sends. For + * protocols where you stream big blocks, set to nonzero and use + * the return value from libwebsocket_write() to manage how much + * got send yourself. + * @owning_server: the server init call fills in this opaque pointer when + * registering this protocol with the server. + * @protocol_index: which protocol we are starting from zero + * + * This structure represents one protocol supported by the server. An + * array of these structures is passed to libwebsocket_create_server() + * allows as many protocols as you like to be handled by one server. + */ + +struct libwebsocket_protocols { + const char *name; + callback_function *callback; + size_t per_session_data_size; + size_t rx_buffer_size; + int no_buffer_all_partial_tx; + + /* + * below are filled in on server init and can be left uninitialized, + * no need for user to use them directly either + */ + + struct libwebsocket_context *owning_server; + int protocol_index; +}; + +#ifndef LWS_NO_EXTENSIONS +/** + * struct libwebsocket_extension - An extension we know how to cope with + * + * @name: Formal extension name, eg, "deflate-stream" + * @callback: Service callback + * @per_session_data_size: Libwebsockets will auto-malloc this much + * memory for the use of the extension, a pointer + * to it comes in the @user callback parameter + * @per_context_private_data: Optional storage for this extension that + * is per-context, so it can track stuff across + * all sessions, etc, if it wants + */ + +struct libwebsocket_extension { + const char *name; + extension_callback_function *callback; + size_t per_session_data_size; + void *per_context_private_data; +}; +#endif + +/** + * struct lws_context_creation_info: parameters to create context with + * + * @port: Port to listen on... you can use 0 to suppress listening on + * any port, that's what you want if you are not running a + * websocket server at all but just using it as a client + * @iface: NULL to bind the listen socket to all interfaces, or the + * interface name, eg, "eth2" + * @protocols: Array of structures listing supported protocols and a protocol- + * specific callback for each one. The list is ended with an + * entry that has a NULL callback pointer. + * It's not const because we write the owning_server member + * @extensions: NULL or array of libwebsocket_extension structs listing the + * extensions this context supports. If you configured with + * --without-extensions, you should give NULL here. + * @token_limits: NULL or struct lws_token_limits pointer which is initialized + * with a token length limit for each possible WSI_TOKEN_*** + * @ssl_cert_filepath: If libwebsockets was compiled to use ssl, and you want + * to listen using SSL, set to the filepath to fetch the + * server cert from, otherwise NULL for unencrypted + * @ssl_private_key_filepath: filepath to private key if wanting SSL mode, + * else ignored + * @ssl_ca_filepath: CA certificate filepath or NULL + * @ssl_cipher_list: List of valid ciphers to use (eg, + * "RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL" + * or you can leave it as NULL to get "DEFAULT" + * @gid: group id to change to after setting listen socket, or -1. + * @uid: user id to change to after setting listen socket, or -1. + * @options: 0, or LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK + * @user: optional user pointer that can be recovered via the context + * pointer using libwebsocket_context_user + * @ka_time: 0 for no keepalive, otherwise apply this keepalive timeout to + * all libwebsocket sockets, client or server + * @ka_probes: if ka_time was nonzero, after the timeout expires how many + * times to try to get a response from the peer before giving up + * and killing the connection + * @ka_interval: if ka_time was nonzero, how long to wait before each ka_probes + * attempt + */ + +struct lws_context_creation_info { + int port; + const char *iface; + struct libwebsocket_protocols *protocols; + struct libwebsocket_extension *extensions; + struct lws_token_limits *token_limits; + const char *ssl_cert_filepath; + const char *ssl_private_key_filepath; + const char *ssl_ca_filepath; + const char *ssl_cipher_list; + const char *http_proxy_address; + unsigned int http_proxy_port; + int gid; + int uid; + unsigned int options; + void *user; + int ka_time; + int ka_probes; + int ka_interval; + +}; + +LWS_VISIBLE LWS_EXTERN +void lws_set_log_level(int level, + void (*log_emit_function)(int level, const char *line)); + +LWS_VISIBLE LWS_EXTERN void +lwsl_emit_syslog(int level, const char *line); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket_context * +libwebsocket_create_context(struct lws_context_creation_info *info); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_set_proxy(struct libwebsocket_context *context, const char *proxy); + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_context_destroy(struct libwebsocket_context *context); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_service(struct libwebsocket_context *context, int timeout_ms); + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_cancel_service(struct libwebsocket_context *context); + +#ifdef LWS_USE_LIBEV +LWS_VISIBLE LWS_EXTERN int +libwebsocket_initloop( + struct libwebsocket_context *context, struct ev_loop *loop); + +LWS_VISIBLE void +libwebsocket_sigint_cb( + struct ev_loop *loop, struct ev_signal *watcher, int revents); +#endif /* LWS_USE_LIBEV */ + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_service_fd(struct libwebsocket_context *context, + struct libwebsocket_pollfd *pollfd); + +LWS_VISIBLE LWS_EXTERN void * +libwebsocket_context_user(struct libwebsocket_context *context); + +enum pending_timeout { + NO_PENDING_TIMEOUT = 0, + PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE, + PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE, + PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, + PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE, + PENDING_TIMEOUT_AWAITING_PING, + PENDING_TIMEOUT_CLOSE_ACK, + PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE, + PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE, + PENDING_TIMEOUT_SSL_ACCEPT, + PENDING_TIMEOUT_HTTP_CONTENT, + PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND, +}; + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_set_timeout(struct libwebsocket *wsi, + enum pending_timeout reason, int secs); + +/* + * IMPORTANT NOTICE! + * + * When sending with websocket protocol (LWS_WRITE_TEXT or LWS_WRITE_BINARY) + * the send buffer has to have LWS_SEND_BUFFER_PRE_PADDING bytes valid BEFORE + * buf, and LWS_SEND_BUFFER_POST_PADDING bytes valid AFTER (buf + len). + * + * This allows us to add protocol info before and after the data, and send as + * one packet on the network without payload copying, for maximum efficiency. + * + * So for example you need this kind of code to use libwebsocket_write with a + * 128-byte payload + * + * char buf[LWS_SEND_BUFFER_PRE_PADDING + 128 + LWS_SEND_BUFFER_POST_PADDING]; + * + * // fill your part of the buffer... for example here it's all zeros + * memset(&buf[LWS_SEND_BUFFER_PRE_PADDING], 0, 128); + * + * libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], 128, + * LWS_WRITE_TEXT); + * + * When sending LWS_WRITE_HTTP, there is no protocol addition and you can just + * use the whole buffer without taking care of the above. + */ + +/* + * this is the frame nonce plus two header plus 8 length + * there's an additional two for mux extension per mux nesting level + * 2 byte prepend on close will already fit because control frames cannot use + * the big length style + */ + +#define LWS_SEND_BUFFER_PRE_PADDING (4 + 10 + (2 * MAX_MUX_RECURSION)) +#define LWS_SEND_BUFFER_POST_PADDING 4 + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, size_t len, + enum libwebsocket_write_protocol protocol); + +/* helper for case where buffer may be const */ +#define libwebsocket_write_http(wsi, buf, len) \ + libwebsocket_write(wsi, (unsigned char *)(buf), len, LWS_WRITE_HTTP) + +LWS_VISIBLE LWS_EXTERN int +libwebsockets_serve_http_file(struct libwebsocket_context *context, + struct libwebsocket *wsi, const char *file, + const char *content_type, const char *other_headers); +LWS_VISIBLE LWS_EXTERN int +libwebsockets_serve_http_file_fragment(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int libwebsockets_return_http_status( + struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned int code, + const char *html_body); + +LWS_VISIBLE LWS_EXTERN const struct libwebsocket_protocols * +libwebsockets_get_protocol(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_callback_on_writable(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_callback_on_writable_all_protocol( + const struct libwebsocket_protocols *protocol); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_callback_all_protocol( + const struct libwebsocket_protocols *protocol, int reason); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_get_socket_fd(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_is_final_fragment(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN unsigned char +libwebsocket_get_reserved_bits(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable); + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_rx_flow_allow_all_protocol( + const struct libwebsocket_protocols *protocol); + +LWS_VISIBLE LWS_EXTERN size_t +libwebsockets_remaining_packet_payload(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket * +libwebsocket_client_connect(struct libwebsocket_context *clients, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket * +libwebsocket_client_connect_extended(struct libwebsocket_context *clients, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one, + void *userdata); + +LWS_VISIBLE LWS_EXTERN const char * +libwebsocket_canonical_hostname(struct libwebsocket_context *context); + + +LWS_VISIBLE LWS_EXTERN void +libwebsockets_get_peer_addresses(struct libwebsocket_context *context, + struct libwebsocket *wsi, int fd, char *name, int name_len, + char *rip, int rip_len); + +LWS_VISIBLE LWS_EXTERN int +libwebsockets_get_random(struct libwebsocket_context *context, + void *buf, int len); + +LWS_VISIBLE LWS_EXTERN int +lws_daemonize(const char *_lock_path); + +LWS_VISIBLE LWS_EXTERN int +lws_send_pipe_choked(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +lws_frame_is_binary(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN unsigned char * +libwebsockets_SHA1(const unsigned char *d, size_t n, unsigned char *md); + +LWS_VISIBLE LWS_EXTERN int +lws_b64_encode_string(const char *in, int in_len, char *out, int out_size); + +LWS_VISIBLE LWS_EXTERN int +lws_b64_decode_string(const char *in, char *out, int out_size); + +LWS_VISIBLE LWS_EXTERN const char * +lws_get_library_version(void); + +/* access to headers... only valid while headers valid */ + +LWS_VISIBLE LWS_EXTERN int +lws_hdr_total_length(struct libwebsocket *wsi, enum lws_token_indexes h); + +LWS_VISIBLE LWS_EXTERN int +lws_hdr_copy(struct libwebsocket *wsi, char *dest, int len, + enum lws_token_indexes h); + +/* + * Note: this is not normally needed as a user api. It's provided in case it is + * useful when integrating with other app poll loop service code. + */ + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_read(struct libwebsocket_context *context, + struct libwebsocket *wsi, + unsigned char *buf, size_t len); + +#ifndef LWS_NO_EXTENSIONS +LWS_VISIBLE LWS_EXTERN struct libwebsocket_extension *libwebsocket_get_internal_extensions(); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/android/dist/armv5/lib/cmake/libwebsockets/LibwebsocketsTargets-noconfig.cmake b/android/dist/armv5/lib/cmake/libwebsockets/LibwebsocketsTargets-noconfig.cmake new file mode 100644 index 0000000000..ece070d53d --- /dev/null +++ b/android/dist/armv5/lib/cmake/libwebsockets/LibwebsocketsTargets-noconfig.cmake @@ -0,0 +1,31 @@ +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "websockets" for configuration "" +set_property(TARGET websockets APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG) +set_target_properties(websockets PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_NOCONFIG "C" + IMPORTED_LINK_INTERFACE_LIBRARIES_NOCONFIG "/opt/android-ndk-r10e/platforms/android-8/arch-arm/usr/lib/libz.so;m" + IMPORTED_LOCATION_NOCONFIG "${_IMPORT_PREFIX}/lib/libwebsockets.a" + ) + +list(APPEND _IMPORT_CHECK_TARGETS websockets ) +list(APPEND _IMPORT_CHECK_FILES_FOR_websockets "${_IMPORT_PREFIX}/lib/libwebsockets.a" ) + +# Import target "websockets_shared" for configuration "" +set_property(TARGET websockets_shared APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG) +set_target_properties(websockets_shared PROPERTIES + IMPORTED_LINK_INTERFACE_LIBRARIES_NOCONFIG "/opt/android-ndk-r10e/platforms/android-8/arch-arm/usr/lib/libz.so;m" + IMPORTED_LOCATION_NOCONFIG "${_IMPORT_PREFIX}/lib/libwebsockets.so.4.0.0" + IMPORTED_SONAME_NOCONFIG "libwebsockets.so.4.0.0" + ) + +list(APPEND _IMPORT_CHECK_TARGETS websockets_shared ) +list(APPEND _IMPORT_CHECK_FILES_FOR_websockets_shared "${_IMPORT_PREFIX}/lib/libwebsockets.so.4.0.0" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/android/dist/armv5/lib/cmake/libwebsockets/LibwebsocketsTargets.cmake b/android/dist/armv5/lib/cmake/libwebsockets/LibwebsocketsTargets.cmake new file mode 100644 index 0000000000..848b03ccc2 --- /dev/null +++ b/android/dist/armv5/lib/cmake/libwebsockets/LibwebsocketsTargets.cmake @@ -0,0 +1,93 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5) + message(FATAL_ERROR "CMake >= 2.6.0 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 2.6) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_targetsDefined) +set(_targetsNotDefined) +set(_expectedTargets) +foreach(_expectedTarget websockets websockets_shared) + list(APPEND _expectedTargets ${_expectedTarget}) + if(NOT TARGET ${_expectedTarget}) + list(APPEND _targetsNotDefined ${_expectedTarget}) + endif() + if(TARGET ${_expectedTarget}) + list(APPEND _targetsDefined ${_expectedTarget}) + endif() +endforeach() +if("${_targetsDefined}" STREQUAL "${_expectedTargets}") + unset(_targetsDefined) + unset(_targetsNotDefined) + unset(_expectedTargets) + set(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT "${_targetsDefined}" STREQUAL "") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n") +endif() +unset(_targetsDefined) +unset(_targetsNotDefined) +unset(_expectedTargets) + + +# Compute the installation prefix relative to this file. +get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +if(_IMPORT_PREFIX STREQUAL "/") + set(_IMPORT_PREFIX "") +endif() + +# Create imported target websockets +add_library(websockets STATIC IMPORTED) + +# Create imported target websockets_shared +add_library(websockets_shared SHARED IMPORTED) + +# Load information for each installed configuration. +get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +file(GLOB CONFIG_FILES "${_DIR}/LibwebsocketsTargets-*.cmake") +foreach(f ${CONFIG_FILES}) + include(${f}) +endforeach() + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(target ${_IMPORT_CHECK_TARGETS} ) + foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} ) + if(NOT EXISTS "${file}" ) + message(FATAL_ERROR "The imported target \"${target}\" references the file + \"${file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() + endforeach() + unset(_IMPORT_CHECK_FILES_FOR_${target}) +endforeach() +unset(_IMPORT_CHECK_TARGETS) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/android/dist/armv5/lib/libwebsockets.a b/android/dist/armv5/lib/libwebsockets.a new file mode 100644 index 0000000000..68105c8143 Binary files /dev/null and b/android/dist/armv5/lib/libwebsockets.a differ diff --git a/android/dist/armv5/lib/libwebsockets.so b/android/dist/armv5/lib/libwebsockets.so new file mode 100644 index 0000000000..b967cc3461 Binary files /dev/null and b/android/dist/armv5/lib/libwebsockets.so differ diff --git a/android/dist/armv5/lib/libwebsockets.so.4.0.0 b/android/dist/armv5/lib/libwebsockets.so.4.0.0 new file mode 100644 index 0000000000..b967cc3461 Binary files /dev/null and b/android/dist/armv5/lib/libwebsockets.so.4.0.0 differ diff --git a/android/dist/armv7a/include/libwebsockets.h b/android/dist/armv7a/include/libwebsockets.h new file mode 100644 index 0000000000..0bb67f57bc --- /dev/null +++ b/android/dist/armv7a/include/libwebsockets.h @@ -0,0 +1,1207 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010-2013 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef LIBWEBSOCKET_H_3060898B846849FF9F88F5DB59B5950C +#define LIBWEBSOCKET_H_3060898B846849FF9F88F5DB59B5950C + +#ifdef __cplusplus +extern "C" { +#include +#endif + +#ifdef CMAKE_BUILD +#include "lws_config.h" +#endif + +#if defined(WIN32) || defined(_WIN32) + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include +#include + +#define strcasecmp stricmp +#define getdtablesize() 30000 + +#define LWS_VISIBLE + +#ifdef LWS_DLL +#ifdef LWS_INTERNAL +#define LWS_EXTERN extern __declspec(dllexport) +#else +#define LWS_EXTERN extern __declspec(dllimport) +#endif +#else +#define LWS_EXTERN +#endif + +#else // NOT WIN32 + +#include +#include + +#if defined(__GNUC__) +#define LWS_VISIBLE __attribute__((visibility("default"))) +#else +#define LWS_VISIBLE +#endif + +#endif + +#ifdef LWS_USE_LIBEV +#include +#endif /* LWS_USE_LIBEV */ + +#include + +#ifndef LWS_EXTERN +#define LWS_EXTERN extern +#endif + +#ifdef _WIN32 +#define random rand +#else +#include +#include +#endif + +#define CONTEXT_PORT_NO_LISTEN -1 +#define MAX_MUX_RECURSION 2 + +enum lws_log_levels { + LLL_ERR = 1 << 0, + LLL_WARN = 1 << 1, + LLL_NOTICE = 1 << 2, + LLL_INFO = 1 << 3, + LLL_DEBUG = 1 << 4, + LLL_PARSER = 1 << 5, + LLL_HEADER = 1 << 6, + LLL_EXT = 1 << 7, + LLL_CLIENT = 1 << 8, + LLL_LATENCY = 1 << 9, + + LLL_COUNT = 10 /* set to count of valid flags */ +}; + +LWS_VISIBLE LWS_EXTERN void _lws_log(int filter, const char *format, ...); + +/* notice, warn and log are always compiled in */ +#define lwsl_notice(...) _lws_log(LLL_NOTICE, __VA_ARGS__) +#define lwsl_warn(...) _lws_log(LLL_WARN, __VA_ARGS__) +#define lwsl_err(...) _lws_log(LLL_ERR, __VA_ARGS__) +/* + * weaker logging can be deselected at configure time using --disable-debug + * that gets rid of the overhead of checking while keeping _warn and _err + * active + */ +#ifdef _DEBUG + +#define lwsl_info(...) _lws_log(LLL_INFO, __VA_ARGS__) +#define lwsl_debug(...) _lws_log(LLL_DEBUG, __VA_ARGS__) +#define lwsl_parser(...) _lws_log(LLL_PARSER, __VA_ARGS__) +#define lwsl_header(...) _lws_log(LLL_HEADER, __VA_ARGS__) +#define lwsl_ext(...) _lws_log(LLL_EXT, __VA_ARGS__) +#define lwsl_client(...) _lws_log(LLL_CLIENT, __VA_ARGS__) +#define lwsl_latency(...) _lws_log(LLL_LATENCY, __VA_ARGS__) +LWS_VISIBLE LWS_EXTERN void lwsl_hexdump(void *buf, size_t len); + +#else /* no debug */ + +#define lwsl_info(...) +#define lwsl_debug(...) +#define lwsl_parser(...) +#define lwsl_header(...) +#define lwsl_ext(...) +#define lwsl_client(...) +#define lwsl_latency(...) +#define lwsl_hexdump(a, b) + +#endif + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +/* api change list for user code to test against */ + +#define LWS_FEATURE_SERVE_HTTP_FILE_HAS_OTHER_HEADERS_ARG + + +enum libwebsocket_context_options { + LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT = 2, + LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME = 4, + LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT = 8, + LWS_SERVER_OPTION_LIBEV = 16, + LWS_SERVER_OPTION_DISABLE_IPV6 = 32, + LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS = 64, +}; + +enum libwebsocket_callback_reasons { + LWS_CALLBACK_ESTABLISHED, + LWS_CALLBACK_CLIENT_CONNECTION_ERROR, + LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH, + LWS_CALLBACK_CLIENT_ESTABLISHED, + LWS_CALLBACK_CLOSED, + LWS_CALLBACK_CLOSED_HTTP, + LWS_CALLBACK_RECEIVE, + LWS_CALLBACK_CLIENT_RECEIVE, + LWS_CALLBACK_CLIENT_RECEIVE_PONG, + LWS_CALLBACK_CLIENT_WRITEABLE, + LWS_CALLBACK_SERVER_WRITEABLE, + LWS_CALLBACK_HTTP, + LWS_CALLBACK_HTTP_BODY, + LWS_CALLBACK_HTTP_BODY_COMPLETION, + LWS_CALLBACK_HTTP_FILE_COMPLETION, + LWS_CALLBACK_HTTP_WRITEABLE, + LWS_CALLBACK_FILTER_NETWORK_CONNECTION, + LWS_CALLBACK_FILTER_HTTP_CONNECTION, + LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, + LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, + LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION, + LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, + LWS_CALLBACK_CONFIRM_EXTENSION_OKAY, + LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED, + LWS_CALLBACK_PROTOCOL_INIT, + LWS_CALLBACK_PROTOCOL_DESTROY, + LWS_CALLBACK_WSI_CREATE, /* always protocol[0] */ + LWS_CALLBACK_WSI_DESTROY, /* always protocol[0] */ + LWS_CALLBACK_GET_THREAD_ID, + + /* external poll() management support */ + LWS_CALLBACK_ADD_POLL_FD, + LWS_CALLBACK_DEL_POLL_FD, + LWS_CALLBACK_CHANGE_MODE_POLL_FD, + LWS_CALLBACK_LOCK_POLL, + LWS_CALLBACK_UNLOCK_POLL, + + LWS_CALLBACK_USER = 1000, /* user code can use any including / above */ +}; + +// argument structure for all external poll related calls +// passed in via 'in' +struct libwebsocket_pollargs { + int fd; // applicable file descriptor + int events; // the new event mask + int prev_events; // the previous event mask +}; + +#ifdef _WIN32 +struct libwebsocket_pollfd { + SOCKET fd; + SHORT events; + SHORT revents; +}; +#else +#define libwebsocket_pollfd pollfd +#endif + +enum libwebsocket_extension_callback_reasons { + LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT, + LWS_EXT_CALLBACK_SERVER_CONTEXT_DESTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_DESTRUCT, + LWS_EXT_CALLBACK_CONSTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONSTRUCT, + LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE, + LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION, + LWS_EXT_CALLBACK_DESTROY, + LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING, + LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED, + LWS_EXT_CALLBACK_PACKET_RX_PREPARSE, + LWS_EXT_CALLBACK_PACKET_TX_PRESEND, + LWS_EXT_CALLBACK_PACKET_TX_DO_SEND, + LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX, + LWS_EXT_CALLBACK_FLUSH_PENDING_TX, + LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX, + LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION, + LWS_EXT_CALLBACK_1HZ, + LWS_EXT_CALLBACK_REQUEST_ON_WRITEABLE, + LWS_EXT_CALLBACK_IS_WRITEABLE, + LWS_EXT_CALLBACK_PAYLOAD_TX, + LWS_EXT_CALLBACK_PAYLOAD_RX, +}; + +enum libwebsocket_write_protocol { + LWS_WRITE_TEXT, + LWS_WRITE_BINARY, + LWS_WRITE_CONTINUATION, + LWS_WRITE_HTTP, + + /* special 04+ opcodes */ + + LWS_WRITE_CLOSE, + LWS_WRITE_PING, + LWS_WRITE_PONG, + + /* flags */ + + LWS_WRITE_NO_FIN = 0x40, + /* + * client packet payload goes out on wire unmunged + * only useful for security tests since normal servers cannot + * decode the content if used + */ + LWS_WRITE_CLIENT_IGNORE_XOR_MASK = 0x80 +}; + +/* + * you need these to look at headers that have been parsed if using the + * LWS_CALLBACK_FILTER_CONNECTION callback. If a header from the enum + * list below is absent, .token = NULL and token_len = 0. Otherwise .token + * points to .token_len chars containing that header content. + */ + +struct lws_tokens { + char *token; + int token_len; +}; + +enum lws_token_indexes { + WSI_TOKEN_GET_URI, + WSI_TOKEN_POST_URI, + WSI_TOKEN_OPTIONS_URI, + WSI_TOKEN_HOST, + WSI_TOKEN_CONNECTION, + WSI_TOKEN_KEY1, + WSI_TOKEN_KEY2, + WSI_TOKEN_PROTOCOL, + WSI_TOKEN_UPGRADE, + WSI_TOKEN_ORIGIN, + WSI_TOKEN_DRAFT, + WSI_TOKEN_CHALLENGE, + + /* new for 04 */ + WSI_TOKEN_KEY, + WSI_TOKEN_VERSION, + WSI_TOKEN_SWORIGIN, + + /* new for 05 */ + WSI_TOKEN_EXTENSIONS, + + /* client receives these */ + WSI_TOKEN_ACCEPT, + WSI_TOKEN_NONCE, + WSI_TOKEN_HTTP, + + /* http-related */ + WSI_TOKEN_HTTP_ACCEPT, + WSI_TOKEN_HTTP_AC_REQUEST_HEADERS, + WSI_TOKEN_HTTP_IF_MODIFIED_SINCE, + WSI_TOKEN_HTTP_IF_NONE_MATCH, + WSI_TOKEN_HTTP_ACCEPT_ENCODING, + WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, + WSI_TOKEN_HTTP_PRAGMA, + WSI_TOKEN_HTTP_CACHE_CONTROL, + WSI_TOKEN_HTTP_AUTHORIZATION, + WSI_TOKEN_HTTP_COOKIE, + WSI_TOKEN_HTTP_CONTENT_LENGTH, + WSI_TOKEN_HTTP_CONTENT_TYPE, + WSI_TOKEN_HTTP_DATE, + WSI_TOKEN_HTTP_RANGE, + WSI_TOKEN_HTTP_REFERER, + WSI_TOKEN_HTTP_URI_ARGS, + + + WSI_TOKEN_MUXURL, + + /* use token storage to stash these */ + + _WSI_TOKEN_CLIENT_SENT_PROTOCOLS, + _WSI_TOKEN_CLIENT_PEER_ADDRESS, + _WSI_TOKEN_CLIENT_URI, + _WSI_TOKEN_CLIENT_HOST, + _WSI_TOKEN_CLIENT_ORIGIN, + + /* always last real token index*/ + WSI_TOKEN_COUNT, + /* parser state additions */ + WSI_TOKEN_NAME_PART, + WSI_TOKEN_SKIPPING, + WSI_TOKEN_SKIPPING_SAW_CR, + WSI_PARSING_COMPLETE, + WSI_INIT_TOKEN_MUXURL, +}; + +struct lws_token_limits { + unsigned short token_limit[WSI_TOKEN_COUNT]; +}; + +/* + * From RFC 6455 + 1000 + + 1000 indicates a normal closure, meaning that the purpose for + which the connection was established has been fulfilled. + + 1001 + + 1001 indicates that an endpoint is "going away", such as a server + going down or a browser having navigated away from a page. + + 1002 + + 1002 indicates that an endpoint is terminating the connection due + to a protocol error. + + 1003 + + 1003 indicates that an endpoint is terminating the connection + because it has received a type of data it cannot accept (e.g., an + endpoint that understands only text data MAY send this if it + receives a binary message). + + 1004 + + Reserved. The specific meaning might be defined in the future. + + 1005 + + 1005 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that no status + code was actually present. + + 1006 + + 1006 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that the + connection was closed abnormally, e.g., without sending or + receiving a Close control frame. + + 1007 + + 1007 indicates that an endpoint is terminating the connection + because it has received data within a message that was not + consistent with the type of the message (e.g., non-UTF-8 [RFC3629] + data within a text message). + + 1008 + + 1008 indicates that an endpoint is terminating the connection + because it has received a message that violates its policy. This + is a generic status code that can be returned when there is no + other more suitable status code (e.g., 1003 or 1009) or if there + is a need to hide specific details about the policy. + + 1009 + + 1009 indicates that an endpoint is terminating the connection + because it has received a message that is too big for it to + process. + + 1010 + + 1010 indicates that an endpoint (client) is terminating the + connection because it has expected the server to negotiate one or + more extension, but the server didn't return them in the response + message of the WebSocket handshake. The list of extensions that + are needed SHOULD appear in the /reason/ part of the Close frame. + Note that this status code is not used by the server, because it + can fail the WebSocket handshake instead. + + 1011 + + 1011 indicates that a server is terminating the connection because + it encountered an unexpected condition that prevented it from + fulfilling the request. + + 1015 + + 1015 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that the + connection was closed due to a failure to perform a TLS handshake + (e.g., the server certificate can't be verified). +*/ + +enum lws_close_status { + LWS_CLOSE_STATUS_NOSTATUS = 0, + LWS_CLOSE_STATUS_NORMAL = 1000, + LWS_CLOSE_STATUS_GOINGAWAY = 1001, + LWS_CLOSE_STATUS_PROTOCOL_ERR = 1002, + LWS_CLOSE_STATUS_UNACCEPTABLE_OPCODE = 1003, + LWS_CLOSE_STATUS_RESERVED = 1004, + LWS_CLOSE_STATUS_NO_STATUS = 1005, + LWS_CLOSE_STATUS_ABNORMAL_CLOSE = 1006, + LWS_CLOSE_STATUS_INVALID_PAYLOAD = 1007, + LWS_CLOSE_STATUS_POLICY_VIOLATION = 1008, + LWS_CLOSE_STATUS_MESSAGE_TOO_LARGE = 1009, + LWS_CLOSE_STATUS_EXTENSION_REQUIRED = 1010, + LWS_CLOSE_STATUS_UNEXPECTED_CONDITION = 1011, + LWS_CLOSE_STATUS_TLS_FAILURE = 1015, +}; + +enum http_status { + HTTP_STATUS_OK = 200, + HTTP_STATUS_NO_CONTENT = 204, + + HTTP_STATUS_BAD_REQUEST = 400, + HTTP_STATUS_UNAUTHORIZED, + HTTP_STATUS_PAYMENT_REQUIRED, + HTTP_STATUS_FORBIDDEN, + HTTP_STATUS_NOT_FOUND, + HTTP_STATUS_METHOD_NOT_ALLOWED, + HTTP_STATUS_NOT_ACCEPTABLE, + HTTP_STATUS_PROXY_AUTH_REQUIRED, + HTTP_STATUS_REQUEST_TIMEOUT, + HTTP_STATUS_CONFLICT, + HTTP_STATUS_GONE, + HTTP_STATUS_LENGTH_REQUIRED, + HTTP_STATUS_PRECONDITION_FAILED, + HTTP_STATUS_REQ_ENTITY_TOO_LARGE, + HTTP_STATUS_REQ_URI_TOO_LONG, + HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, + HTTP_STATUS_REQ_RANGE_NOT_SATISFIABLE, + HTTP_STATUS_EXPECTATION_FAILED, + + HTTP_STATUS_INTERNAL_SERVER_ERROR = 500, + HTTP_STATUS_NOT_IMPLEMENTED, + HTTP_STATUS_BAD_GATEWAY, + HTTP_STATUS_SERVICE_UNAVAILABLE, + HTTP_STATUS_GATEWAY_TIMEOUT, + HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED, +}; + +struct libwebsocket; +struct libwebsocket_context; +/* needed even with extensions disabled for create context */ +struct libwebsocket_extension; + +/** + * callback_function() - User server actions + * @context: Websockets context + * @wsi: Opaque websocket instance pointer + * @reason: The reason for the call + * @user: Pointer to per-session user data allocated by library + * @in: Pointer used for some callback reasons + * @len: Length set for some callback reasons + * + * This callback is the way the user controls what is served. All the + * protocol detail is hidden and handled by the library. + * + * For each connection / session there is user data allocated that is + * pointed to by "user". You set the size of this user data area when + * the library is initialized with libwebsocket_create_server. + * + * You get an opportunity to initialize user data when called back with + * LWS_CALLBACK_ESTABLISHED reason. + * + * LWS_CALLBACK_ESTABLISHED: after the server completes a handshake with + * an incoming client + * + * LWS_CALLBACK_CLIENT_CONNECTION_ERROR: the request client connection has + * been unable to complete a handshake with the remote server + * + * LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH: this is the last chance for the + * client user code to examine the http headers + * and decide to reject the connection. If the + * content in the headers is interesting to the + * client (url, etc) it needs to copy it out at + * this point since it will be destroyed before + * the CLIENT_ESTABLISHED call + * + * LWS_CALLBACK_CLIENT_ESTABLISHED: after your client connection completed + * a handshake with the remote server + * + * LWS_CALLBACK_CLOSED: when the websocket session ends + * + * LWS_CALLBACK_CLOSED_HTTP: when a HTTP (non-websocket) session ends + * + * LWS_CALLBACK_RECEIVE: data has appeared for this server endpoint from a + * remote client, it can be found at *in and is + * len bytes long + * + * LWS_CALLBACK_CLIENT_RECEIVE_PONG: if you elected to see PONG packets, + * they appear with this callback reason. PONG + * packets only exist in 04+ protocol + * + * LWS_CALLBACK_CLIENT_RECEIVE: data has appeared from the server for the + * client connection, it can be found at *in and + * is len bytes long + * + * LWS_CALLBACK_HTTP: an http request has come from a client that is not + * asking to upgrade the connection to a websocket + * one. This is a chance to serve http content, + * for example, to send a script to the client + * which will then open the websockets connection. + * @in points to the URI path requested and + * libwebsockets_serve_http_file() makes it very + * simple to send back a file to the client. + * Normally after sending the file you are done + * with the http connection, since the rest of the + * activity will come by websockets from the script + * that was delivered by http, so you will want to + * return 1; to close and free up the connection. + * That's important because it uses a slot in the + * total number of client connections allowed set + * by MAX_CLIENTS. + * + * LWS_CALLBACK_HTTP_BODY: the next @len bytes data from the http + * request body HTTP connection is now available in @in. + * + * LWS_CALLBACK_HTTP_BODY_COMPLETION: the expected amount of http request + * body has been delivered + * + * LWS_CALLBACK_HTTP_WRITEABLE: you can write more down the http protocol + * link now. + * + * LWS_CALLBACK_HTTP_FILE_COMPLETION: a file requested to be send down + * http link has completed. + * + * LWS_CALLBACK_CLIENT_WRITEABLE: + * LWS_CALLBACK_SERVER_WRITEABLE: If you call + * libwebsocket_callback_on_writable() on a connection, you will + * get one of these callbacks coming when the connection socket + * is able to accept another write packet without blocking. + * If it already was able to take another packet without blocking, + * you'll get this callback at the next call to the service loop + * function. Notice that CLIENTs get LWS_CALLBACK_CLIENT_WRITEABLE + * and servers get LWS_CALLBACK_SERVER_WRITEABLE. + * + * LWS_CALLBACK_FILTER_NETWORK_CONNECTION: called when a client connects to + * the server at network level; the connection is accepted but then + * passed to this callback to decide whether to hang up immediately + * or not, based on the client IP. @in contains the connection + * socket's descriptor. Since the client connection information is + * not available yet, @wsi still pointing to the main server socket. + * Return non-zero to terminate the connection before sending or + * receiving anything. Because this happens immediately after the + * network connection from the client, there's no websocket protocol + * selected yet so this callback is issued only to protocol 0. + * + * LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED: A new client just had + * been connected, accepted, and instantiated into the pool. This + * callback allows setting any relevant property to it. Because this + * happens immediately after the instantiation of a new client, + * there's no websocket protocol selected yet so this callback is + * issued only to protocol 0. Only @wsi is defined, pointing to the + * new client, and the return value is ignored. + * + * LWS_CALLBACK_FILTER_HTTP_CONNECTION: called when the request has + * been received and parsed from the client, but the response is + * not sent yet. Return non-zero to disallow the connection. + * @user is a pointer to the connection user space allocation, + * @in is the URI, eg, "/" + * In your handler you can use the public APIs + * lws_hdr_total_length() / lws_hdr_copy() to access all of the + * headers using the header enums lws_token_indexes from + * libwebsockets.h to check for and read the supported header + * presence and content before deciding to allow the http + * connection to proceed or to kill the connection. + * + * LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: called when the handshake has + * been received and parsed from the client, but the response is + * not sent yet. Return non-zero to disallow the connection. + * @user is a pointer to the connection user space allocation, + * @in is the requested protocol name + * In your handler you can use the public APIs + * lws_hdr_total_length() / lws_hdr_copy() to access all of the + * headers using the header enums lws_token_indexes from + * libwebsockets.h to check for and read the supported header + * presence and content before deciding to allow the handshake + * to proceed or to kill the connection. + * + * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: if configured for + * including OpenSSL support, this callback allows your user code + * to perform extra SSL_CTX_load_verify_locations() or similar + * calls to direct OpenSSL where to find certificates the client + * can use to confirm the remote server identity. @user is the + * OpenSSL SSL_CTX* + * + * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: if configured for + * including OpenSSL support, this callback allows your user code + * to load extra certifcates into the server which allow it to + * verify the validity of certificates returned by clients. @user + * is the server's OpenSSL SSL_CTX* + * + * LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: if the + * libwebsockets context was created with the option + * LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT, then this + * callback is generated during OpenSSL verification of the cert + * sent from the client. It is sent to protocol[0] callback as + * no protocol has been negotiated on the connection yet. + * Notice that the libwebsockets context and wsi are both NULL + * during this callback. See + * http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html + * to understand more detail about the OpenSSL callback that + * generates this libwebsockets callback and the meanings of the + * arguments passed. In this callback, @user is the x509_ctx, + * @in is the ssl pointer and @len is preverify_ok + * Notice that this callback maintains libwebsocket return + * conventions, return 0 to mean the cert is OK or 1 to fail it. + * This also means that if you don't handle this callback then + * the default callback action of returning 0 allows the client + * certificates. + * + * LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: this callback happens + * when a client handshake is being compiled. @user is NULL, + * @in is a char **, it's pointing to a char * which holds the + * next location in the header buffer where you can add + * headers, and @len is the remaining space in the header buffer, + * which is typically some hundreds of bytes. So, to add a canned + * cookie, your handler code might look similar to: + * + * char **p = (char **)in; + * + * if (len < 100) + * return 1; + * + * *p += sprintf(*p, "Cookie: a=b\x0d\x0a"); + * + * return 0; + * + * Notice if you add anything, you just have to take care about + * the CRLF on the line you added. Obviously this callback is + * optional, if you don't handle it everything is fine. + * + * Notice the callback is coming to protocols[0] all the time, + * because there is no specific protocol handshook yet. + * + * LWS_CALLBACK_CONFIRM_EXTENSION_OKAY: When the server handshake code + * sees that it does support a requested extension, before + * accepting the extension by additing to the list sent back to + * the client it gives this callback just to check that it's okay + * to use that extension. It calls back to the requested protocol + * and with @in being the extension name, @len is 0 and @user is + * valid. Note though at this time the ESTABLISHED callback hasn't + * happened yet so if you initialize @user content there, @user + * content during this callback might not be useful for anything. + * Notice this callback comes to protocols[0]. + * + * LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: When a client + * connection is being prepared to start a handshake to a server, + * each supported extension is checked with protocols[0] callback + * with this reason, giving the user code a chance to suppress the + * claim to support that extension by returning non-zero. If + * unhandled, by default 0 will be returned and the extension + * support included in the header to the server. Notice this + * callback comes to protocols[0]. + * + * LWS_CALLBACK_PROTOCOL_INIT: One-time call per protocol so it can + * do initial setup / allocations etc + * + * LWS_CALLBACK_PROTOCOL_DESTROY: One-time call per protocol indicating + * this protocol won't get used at all after this callback, the + * context is getting destroyed. Take the opportunity to + * deallocate everything that was allocated by the protocol. + * + * LWS_CALLBACK_WSI_CREATE: outermost (earliest) wsi create notification + * + * LWS_CALLBACK_WSI_DESTROY: outermost (latest) wsi destroy notification + * + * The next five reasons are optional and only need taking care of if you + * will be integrating libwebsockets sockets into an external polling + * array. + * + * For these calls, @in points to a struct libwebsocket_pollargs that + * contains @fd, @events and @prev_events members + * + * LWS_CALLBACK_ADD_POLL_FD: libwebsocket deals with its poll() loop + * internally, but in the case you are integrating with another + * server you will need to have libwebsocket sockets share a + * polling array with the other server. This and the other + * POLL_FD related callbacks let you put your specialized + * poll array interface code in the callback for protocol 0, the + * first protocol you support, usually the HTTP protocol in the + * serving case. + * This callback happens when a socket needs to be + * added to the polling loop: @in points to a struct + * libwebsocket_pollargs; the @fd member of the struct is the file + * descriptor, and @events contains the active events. + * + * If you are using the internal polling loop (the "service" + * callback), you can just ignore these callbacks. + * + * LWS_CALLBACK_DEL_POLL_FD: This callback happens when a socket descriptor + * needs to be removed from an external polling array. @in is + * again the struct libwebsocket_pollargs containing the @fd member + * to be removed. If you are using the internal polling + * loop, you can just ignore it. + * + * LWS_CALLBACK_CHANGE_MODE_POLL_FD: This callback happens when + * libwebsockets wants to modify the events for a connectiion. + * @in is the struct libwebsocket_pollargs with the @fd to change. + * The new event mask is in @events member and the old mask is in + * the @prev_events member. + * If you are using the internal polling loop, you can just ignore + * it. + * + * LWS_CALLBACK_LOCK_POLL: + * LWS_CALLBACK_UNLOCK_POLL: These allow the external poll changes driven + * by libwebsockets to participate in an external thread locking + * scheme around the changes, so the whole thing is threadsafe. + */ +LWS_VISIBLE LWS_EXTERN int callback(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len); + +typedef int (callback_function)(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len); + +#ifndef LWS_NO_EXTENSIONS +/** + * extension_callback_function() - Hooks to allow extensions to operate + * @context: Websockets context + * @ext: This extension + * @wsi: Opaque websocket instance pointer + * @reason: The reason for the call + * @user: Pointer to per-session user data allocated by library + * @in: Pointer used for some callback reasons + * @len: Length set for some callback reasons + * + * Each extension that is active on a particular connection receives + * callbacks during the connection lifetime to allow the extension to + * operate on websocket data and manage itself. + * + * Libwebsockets takes care of allocating and freeing "user" memory for + * each active extension on each connection. That is what is pointed to + * by the @user parameter. + * + * LWS_EXT_CALLBACK_CONSTRUCT: called when the server has decided to + * select this extension from the list provided by the client, + * just before the server will send back the handshake accepting + * the connection with this extension active. This gives the + * extension a chance to initialize its connection context found + * in @user. + * + * LWS_EXT_CALLBACK_CLIENT_CONSTRUCT: same as LWS_EXT_CALLBACK_CONSTRUCT + * but called when client is instantiating this extension. Some + * extensions will work the same on client and server side and then + * you can just merge handlers for both CONSTRUCTS. + * + * LWS_EXT_CALLBACK_DESTROY: called when the connection the extension was + * being used on is about to be closed and deallocated. It's the + * last chance for the extension to deallocate anything it has + * allocated in the user data (pointed to by @user) before the + * user data is deleted. This same callback is used whether you + * are in client or server instantiation context. + * + * LWS_EXT_CALLBACK_PACKET_RX_PREPARSE: when this extension was active on + * a connection, and a packet of data arrived at the connection, + * it is passed to this callback to give the extension a chance to + * change the data, eg, decompress it. @user is pointing to the + * extension's private connection context data, @in is pointing + * to an lws_tokens struct, it consists of a char * pointer called + * token, and an int called token_len. At entry, these are + * set to point to the received buffer and set to the content + * length. If the extension will grow the content, it should use + * a new buffer allocated in its private user context data and + * set the pointed-to lws_tokens members to point to its buffer. + * + * LWS_EXT_CALLBACK_PACKET_TX_PRESEND: this works the same way as + * LWS_EXT_CALLBACK_PACKET_RX_PREPARSE above, except it gives the + * extension a chance to change websocket data just before it will + * be sent out. Using the same lws_token pointer scheme in @in, + * the extension can change the buffer and the length to be + * transmitted how it likes. Again if it wants to grow the + * buffer safely, it should copy the data into its own buffer and + * set the lws_tokens token pointer to it. + */ +LWS_VISIBLE LWS_EXTERN int extension_callback(struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); + +typedef int (extension_callback_function)(struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); +#endif + +/** + * struct libwebsocket_protocols - List of protocols and handlers server + * supports. + * @name: Protocol name that must match the one given in the client + * Javascript new WebSocket(url, 'protocol') name + * @callback: The service callback used for this protocol. It allows the + * service action for an entire protocol to be encapsulated in + * the protocol-specific callback + * @per_session_data_size: Each new connection using this protocol gets + * this much memory allocated on connection establishment and + * freed on connection takedown. A pointer to this per-connection + * allocation is passed into the callback in the 'user' parameter + * @rx_buffer_size: if you want atomic frames delivered to the callback, you + * should set this to the size of the biggest legal frame that + * you support. If the frame size is exceeded, there is no + * error, but the buffer will spill to the user callback when + * full, which you can detect by using + * libwebsockets_remaining_packet_payload(). Notice that you + * just talk about frame size here, the LWS_SEND_BUFFER_PRE_PADDING + * and post-padding are automatically also allocated on top. + * @no_buffer_all_partial_tx: Leave at zero if you want the library to take + * care of all partial tx for you. It's useful if you only have + * small tx packets and the chance of any truncated send is small + * enough any additional malloc / buffering overhead is less + * painful than writing the code to deal with partial sends. For + * protocols where you stream big blocks, set to nonzero and use + * the return value from libwebsocket_write() to manage how much + * got send yourself. + * @owning_server: the server init call fills in this opaque pointer when + * registering this protocol with the server. + * @protocol_index: which protocol we are starting from zero + * + * This structure represents one protocol supported by the server. An + * array of these structures is passed to libwebsocket_create_server() + * allows as many protocols as you like to be handled by one server. + */ + +struct libwebsocket_protocols { + const char *name; + callback_function *callback; + size_t per_session_data_size; + size_t rx_buffer_size; + int no_buffer_all_partial_tx; + + /* + * below are filled in on server init and can be left uninitialized, + * no need for user to use them directly either + */ + + struct libwebsocket_context *owning_server; + int protocol_index; +}; + +#ifndef LWS_NO_EXTENSIONS +/** + * struct libwebsocket_extension - An extension we know how to cope with + * + * @name: Formal extension name, eg, "deflate-stream" + * @callback: Service callback + * @per_session_data_size: Libwebsockets will auto-malloc this much + * memory for the use of the extension, a pointer + * to it comes in the @user callback parameter + * @per_context_private_data: Optional storage for this extension that + * is per-context, so it can track stuff across + * all sessions, etc, if it wants + */ + +struct libwebsocket_extension { + const char *name; + extension_callback_function *callback; + size_t per_session_data_size; + void *per_context_private_data; +}; +#endif + +/** + * struct lws_context_creation_info: parameters to create context with + * + * @port: Port to listen on... you can use 0 to suppress listening on + * any port, that's what you want if you are not running a + * websocket server at all but just using it as a client + * @iface: NULL to bind the listen socket to all interfaces, or the + * interface name, eg, "eth2" + * @protocols: Array of structures listing supported protocols and a protocol- + * specific callback for each one. The list is ended with an + * entry that has a NULL callback pointer. + * It's not const because we write the owning_server member + * @extensions: NULL or array of libwebsocket_extension structs listing the + * extensions this context supports. If you configured with + * --without-extensions, you should give NULL here. + * @token_limits: NULL or struct lws_token_limits pointer which is initialized + * with a token length limit for each possible WSI_TOKEN_*** + * @ssl_cert_filepath: If libwebsockets was compiled to use ssl, and you want + * to listen using SSL, set to the filepath to fetch the + * server cert from, otherwise NULL for unencrypted + * @ssl_private_key_filepath: filepath to private key if wanting SSL mode, + * else ignored + * @ssl_ca_filepath: CA certificate filepath or NULL + * @ssl_cipher_list: List of valid ciphers to use (eg, + * "RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL" + * or you can leave it as NULL to get "DEFAULT" + * @gid: group id to change to after setting listen socket, or -1. + * @uid: user id to change to after setting listen socket, or -1. + * @options: 0, or LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK + * @user: optional user pointer that can be recovered via the context + * pointer using libwebsocket_context_user + * @ka_time: 0 for no keepalive, otherwise apply this keepalive timeout to + * all libwebsocket sockets, client or server + * @ka_probes: if ka_time was nonzero, after the timeout expires how many + * times to try to get a response from the peer before giving up + * and killing the connection + * @ka_interval: if ka_time was nonzero, how long to wait before each ka_probes + * attempt + */ + +struct lws_context_creation_info { + int port; + const char *iface; + struct libwebsocket_protocols *protocols; + struct libwebsocket_extension *extensions; + struct lws_token_limits *token_limits; + const char *ssl_cert_filepath; + const char *ssl_private_key_filepath; + const char *ssl_ca_filepath; + const char *ssl_cipher_list; + const char *http_proxy_address; + unsigned int http_proxy_port; + int gid; + int uid; + unsigned int options; + void *user; + int ka_time; + int ka_probes; + int ka_interval; + +}; + +LWS_VISIBLE LWS_EXTERN +void lws_set_log_level(int level, + void (*log_emit_function)(int level, const char *line)); + +LWS_VISIBLE LWS_EXTERN void +lwsl_emit_syslog(int level, const char *line); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket_context * +libwebsocket_create_context(struct lws_context_creation_info *info); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_set_proxy(struct libwebsocket_context *context, const char *proxy); + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_context_destroy(struct libwebsocket_context *context); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_service(struct libwebsocket_context *context, int timeout_ms); + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_cancel_service(struct libwebsocket_context *context); + +#ifdef LWS_USE_LIBEV +LWS_VISIBLE LWS_EXTERN int +libwebsocket_initloop( + struct libwebsocket_context *context, struct ev_loop *loop); + +LWS_VISIBLE void +libwebsocket_sigint_cb( + struct ev_loop *loop, struct ev_signal *watcher, int revents); +#endif /* LWS_USE_LIBEV */ + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_service_fd(struct libwebsocket_context *context, + struct libwebsocket_pollfd *pollfd); + +LWS_VISIBLE LWS_EXTERN void * +libwebsocket_context_user(struct libwebsocket_context *context); + +enum pending_timeout { + NO_PENDING_TIMEOUT = 0, + PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE, + PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE, + PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, + PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE, + PENDING_TIMEOUT_AWAITING_PING, + PENDING_TIMEOUT_CLOSE_ACK, + PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE, + PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE, + PENDING_TIMEOUT_SSL_ACCEPT, + PENDING_TIMEOUT_HTTP_CONTENT, + PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND, +}; + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_set_timeout(struct libwebsocket *wsi, + enum pending_timeout reason, int secs); + +/* + * IMPORTANT NOTICE! + * + * When sending with websocket protocol (LWS_WRITE_TEXT or LWS_WRITE_BINARY) + * the send buffer has to have LWS_SEND_BUFFER_PRE_PADDING bytes valid BEFORE + * buf, and LWS_SEND_BUFFER_POST_PADDING bytes valid AFTER (buf + len). + * + * This allows us to add protocol info before and after the data, and send as + * one packet on the network without payload copying, for maximum efficiency. + * + * So for example you need this kind of code to use libwebsocket_write with a + * 128-byte payload + * + * char buf[LWS_SEND_BUFFER_PRE_PADDING + 128 + LWS_SEND_BUFFER_POST_PADDING]; + * + * // fill your part of the buffer... for example here it's all zeros + * memset(&buf[LWS_SEND_BUFFER_PRE_PADDING], 0, 128); + * + * libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], 128, + * LWS_WRITE_TEXT); + * + * When sending LWS_WRITE_HTTP, there is no protocol addition and you can just + * use the whole buffer without taking care of the above. + */ + +/* + * this is the frame nonce plus two header plus 8 length + * there's an additional two for mux extension per mux nesting level + * 2 byte prepend on close will already fit because control frames cannot use + * the big length style + */ + +#define LWS_SEND_BUFFER_PRE_PADDING (4 + 10 + (2 * MAX_MUX_RECURSION)) +#define LWS_SEND_BUFFER_POST_PADDING 4 + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, size_t len, + enum libwebsocket_write_protocol protocol); + +/* helper for case where buffer may be const */ +#define libwebsocket_write_http(wsi, buf, len) \ + libwebsocket_write(wsi, (unsigned char *)(buf), len, LWS_WRITE_HTTP) + +LWS_VISIBLE LWS_EXTERN int +libwebsockets_serve_http_file(struct libwebsocket_context *context, + struct libwebsocket *wsi, const char *file, + const char *content_type, const char *other_headers); +LWS_VISIBLE LWS_EXTERN int +libwebsockets_serve_http_file_fragment(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int libwebsockets_return_http_status( + struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned int code, + const char *html_body); + +LWS_VISIBLE LWS_EXTERN const struct libwebsocket_protocols * +libwebsockets_get_protocol(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_callback_on_writable(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_callback_on_writable_all_protocol( + const struct libwebsocket_protocols *protocol); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_callback_all_protocol( + const struct libwebsocket_protocols *protocol, int reason); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_get_socket_fd(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_is_final_fragment(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN unsigned char +libwebsocket_get_reserved_bits(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable); + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_rx_flow_allow_all_protocol( + const struct libwebsocket_protocols *protocol); + +LWS_VISIBLE LWS_EXTERN size_t +libwebsockets_remaining_packet_payload(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket * +libwebsocket_client_connect(struct libwebsocket_context *clients, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket * +libwebsocket_client_connect_extended(struct libwebsocket_context *clients, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one, + void *userdata); + +LWS_VISIBLE LWS_EXTERN const char * +libwebsocket_canonical_hostname(struct libwebsocket_context *context); + + +LWS_VISIBLE LWS_EXTERN void +libwebsockets_get_peer_addresses(struct libwebsocket_context *context, + struct libwebsocket *wsi, int fd, char *name, int name_len, + char *rip, int rip_len); + +LWS_VISIBLE LWS_EXTERN int +libwebsockets_get_random(struct libwebsocket_context *context, + void *buf, int len); + +LWS_VISIBLE LWS_EXTERN int +lws_daemonize(const char *_lock_path); + +LWS_VISIBLE LWS_EXTERN int +lws_send_pipe_choked(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +lws_frame_is_binary(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN unsigned char * +libwebsockets_SHA1(const unsigned char *d, size_t n, unsigned char *md); + +LWS_VISIBLE LWS_EXTERN int +lws_b64_encode_string(const char *in, int in_len, char *out, int out_size); + +LWS_VISIBLE LWS_EXTERN int +lws_b64_decode_string(const char *in, char *out, int out_size); + +LWS_VISIBLE LWS_EXTERN const char * +lws_get_library_version(void); + +/* access to headers... only valid while headers valid */ + +LWS_VISIBLE LWS_EXTERN int +lws_hdr_total_length(struct libwebsocket *wsi, enum lws_token_indexes h); + +LWS_VISIBLE LWS_EXTERN int +lws_hdr_copy(struct libwebsocket *wsi, char *dest, int len, + enum lws_token_indexes h); + +/* + * Note: this is not normally needed as a user api. It's provided in case it is + * useful when integrating with other app poll loop service code. + */ + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_read(struct libwebsocket_context *context, + struct libwebsocket *wsi, + unsigned char *buf, size_t len); + +#ifndef LWS_NO_EXTENSIONS +LWS_VISIBLE LWS_EXTERN struct libwebsocket_extension *libwebsocket_get_internal_extensions(); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/android/dist/armv7a/lib/cmake/libwebsockets/LibwebsocketsTargets-noconfig.cmake b/android/dist/armv7a/lib/cmake/libwebsockets/LibwebsocketsTargets-noconfig.cmake new file mode 100644 index 0000000000..ece070d53d --- /dev/null +++ b/android/dist/armv7a/lib/cmake/libwebsockets/LibwebsocketsTargets-noconfig.cmake @@ -0,0 +1,31 @@ +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "websockets" for configuration "" +set_property(TARGET websockets APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG) +set_target_properties(websockets PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_NOCONFIG "C" + IMPORTED_LINK_INTERFACE_LIBRARIES_NOCONFIG "/opt/android-ndk-r10e/platforms/android-8/arch-arm/usr/lib/libz.so;m" + IMPORTED_LOCATION_NOCONFIG "${_IMPORT_PREFIX}/lib/libwebsockets.a" + ) + +list(APPEND _IMPORT_CHECK_TARGETS websockets ) +list(APPEND _IMPORT_CHECK_FILES_FOR_websockets "${_IMPORT_PREFIX}/lib/libwebsockets.a" ) + +# Import target "websockets_shared" for configuration "" +set_property(TARGET websockets_shared APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG) +set_target_properties(websockets_shared PROPERTIES + IMPORTED_LINK_INTERFACE_LIBRARIES_NOCONFIG "/opt/android-ndk-r10e/platforms/android-8/arch-arm/usr/lib/libz.so;m" + IMPORTED_LOCATION_NOCONFIG "${_IMPORT_PREFIX}/lib/libwebsockets.so.4.0.0" + IMPORTED_SONAME_NOCONFIG "libwebsockets.so.4.0.0" + ) + +list(APPEND _IMPORT_CHECK_TARGETS websockets_shared ) +list(APPEND _IMPORT_CHECK_FILES_FOR_websockets_shared "${_IMPORT_PREFIX}/lib/libwebsockets.so.4.0.0" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/android/dist/armv7a/lib/cmake/libwebsockets/LibwebsocketsTargets.cmake b/android/dist/armv7a/lib/cmake/libwebsockets/LibwebsocketsTargets.cmake new file mode 100644 index 0000000000..848b03ccc2 --- /dev/null +++ b/android/dist/armv7a/lib/cmake/libwebsockets/LibwebsocketsTargets.cmake @@ -0,0 +1,93 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5) + message(FATAL_ERROR "CMake >= 2.6.0 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 2.6) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_targetsDefined) +set(_targetsNotDefined) +set(_expectedTargets) +foreach(_expectedTarget websockets websockets_shared) + list(APPEND _expectedTargets ${_expectedTarget}) + if(NOT TARGET ${_expectedTarget}) + list(APPEND _targetsNotDefined ${_expectedTarget}) + endif() + if(TARGET ${_expectedTarget}) + list(APPEND _targetsDefined ${_expectedTarget}) + endif() +endforeach() +if("${_targetsDefined}" STREQUAL "${_expectedTargets}") + unset(_targetsDefined) + unset(_targetsNotDefined) + unset(_expectedTargets) + set(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT "${_targetsDefined}" STREQUAL "") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n") +endif() +unset(_targetsDefined) +unset(_targetsNotDefined) +unset(_expectedTargets) + + +# Compute the installation prefix relative to this file. +get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +if(_IMPORT_PREFIX STREQUAL "/") + set(_IMPORT_PREFIX "") +endif() + +# Create imported target websockets +add_library(websockets STATIC IMPORTED) + +# Create imported target websockets_shared +add_library(websockets_shared SHARED IMPORTED) + +# Load information for each installed configuration. +get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +file(GLOB CONFIG_FILES "${_DIR}/LibwebsocketsTargets-*.cmake") +foreach(f ${CONFIG_FILES}) + include(${f}) +endforeach() + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(target ${_IMPORT_CHECK_TARGETS} ) + foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} ) + if(NOT EXISTS "${file}" ) + message(FATAL_ERROR "The imported target \"${target}\" references the file + \"${file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() + endforeach() + unset(_IMPORT_CHECK_FILES_FOR_${target}) +endforeach() +unset(_IMPORT_CHECK_TARGETS) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/android/dist/armv7a/lib/libwebsockets.a b/android/dist/armv7a/lib/libwebsockets.a new file mode 100644 index 0000000000..3abf133704 Binary files /dev/null and b/android/dist/armv7a/lib/libwebsockets.a differ diff --git a/android/dist/armv7a/lib/libwebsockets.so b/android/dist/armv7a/lib/libwebsockets.so new file mode 100644 index 0000000000..7628871f95 Binary files /dev/null and b/android/dist/armv7a/lib/libwebsockets.so differ diff --git a/android/dist/armv7a/lib/libwebsockets.so.4.0.0 b/android/dist/armv7a/lib/libwebsockets.so.4.0.0 new file mode 100644 index 0000000000..7628871f95 Binary files /dev/null and b/android/dist/armv7a/lib/libwebsockets.so.4.0.0 differ diff --git a/android/dist/armv8a/include/libwebsockets.h b/android/dist/armv8a/include/libwebsockets.h new file mode 100644 index 0000000000..0bb67f57bc --- /dev/null +++ b/android/dist/armv8a/include/libwebsockets.h @@ -0,0 +1,1207 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010-2013 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef LIBWEBSOCKET_H_3060898B846849FF9F88F5DB59B5950C +#define LIBWEBSOCKET_H_3060898B846849FF9F88F5DB59B5950C + +#ifdef __cplusplus +extern "C" { +#include +#endif + +#ifdef CMAKE_BUILD +#include "lws_config.h" +#endif + +#if defined(WIN32) || defined(_WIN32) + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include +#include + +#define strcasecmp stricmp +#define getdtablesize() 30000 + +#define LWS_VISIBLE + +#ifdef LWS_DLL +#ifdef LWS_INTERNAL +#define LWS_EXTERN extern __declspec(dllexport) +#else +#define LWS_EXTERN extern __declspec(dllimport) +#endif +#else +#define LWS_EXTERN +#endif + +#else // NOT WIN32 + +#include +#include + +#if defined(__GNUC__) +#define LWS_VISIBLE __attribute__((visibility("default"))) +#else +#define LWS_VISIBLE +#endif + +#endif + +#ifdef LWS_USE_LIBEV +#include +#endif /* LWS_USE_LIBEV */ + +#include + +#ifndef LWS_EXTERN +#define LWS_EXTERN extern +#endif + +#ifdef _WIN32 +#define random rand +#else +#include +#include +#endif + +#define CONTEXT_PORT_NO_LISTEN -1 +#define MAX_MUX_RECURSION 2 + +enum lws_log_levels { + LLL_ERR = 1 << 0, + LLL_WARN = 1 << 1, + LLL_NOTICE = 1 << 2, + LLL_INFO = 1 << 3, + LLL_DEBUG = 1 << 4, + LLL_PARSER = 1 << 5, + LLL_HEADER = 1 << 6, + LLL_EXT = 1 << 7, + LLL_CLIENT = 1 << 8, + LLL_LATENCY = 1 << 9, + + LLL_COUNT = 10 /* set to count of valid flags */ +}; + +LWS_VISIBLE LWS_EXTERN void _lws_log(int filter, const char *format, ...); + +/* notice, warn and log are always compiled in */ +#define lwsl_notice(...) _lws_log(LLL_NOTICE, __VA_ARGS__) +#define lwsl_warn(...) _lws_log(LLL_WARN, __VA_ARGS__) +#define lwsl_err(...) _lws_log(LLL_ERR, __VA_ARGS__) +/* + * weaker logging can be deselected at configure time using --disable-debug + * that gets rid of the overhead of checking while keeping _warn and _err + * active + */ +#ifdef _DEBUG + +#define lwsl_info(...) _lws_log(LLL_INFO, __VA_ARGS__) +#define lwsl_debug(...) _lws_log(LLL_DEBUG, __VA_ARGS__) +#define lwsl_parser(...) _lws_log(LLL_PARSER, __VA_ARGS__) +#define lwsl_header(...) _lws_log(LLL_HEADER, __VA_ARGS__) +#define lwsl_ext(...) _lws_log(LLL_EXT, __VA_ARGS__) +#define lwsl_client(...) _lws_log(LLL_CLIENT, __VA_ARGS__) +#define lwsl_latency(...) _lws_log(LLL_LATENCY, __VA_ARGS__) +LWS_VISIBLE LWS_EXTERN void lwsl_hexdump(void *buf, size_t len); + +#else /* no debug */ + +#define lwsl_info(...) +#define lwsl_debug(...) +#define lwsl_parser(...) +#define lwsl_header(...) +#define lwsl_ext(...) +#define lwsl_client(...) +#define lwsl_latency(...) +#define lwsl_hexdump(a, b) + +#endif + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +/* api change list for user code to test against */ + +#define LWS_FEATURE_SERVE_HTTP_FILE_HAS_OTHER_HEADERS_ARG + + +enum libwebsocket_context_options { + LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT = 2, + LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME = 4, + LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT = 8, + LWS_SERVER_OPTION_LIBEV = 16, + LWS_SERVER_OPTION_DISABLE_IPV6 = 32, + LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS = 64, +}; + +enum libwebsocket_callback_reasons { + LWS_CALLBACK_ESTABLISHED, + LWS_CALLBACK_CLIENT_CONNECTION_ERROR, + LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH, + LWS_CALLBACK_CLIENT_ESTABLISHED, + LWS_CALLBACK_CLOSED, + LWS_CALLBACK_CLOSED_HTTP, + LWS_CALLBACK_RECEIVE, + LWS_CALLBACK_CLIENT_RECEIVE, + LWS_CALLBACK_CLIENT_RECEIVE_PONG, + LWS_CALLBACK_CLIENT_WRITEABLE, + LWS_CALLBACK_SERVER_WRITEABLE, + LWS_CALLBACK_HTTP, + LWS_CALLBACK_HTTP_BODY, + LWS_CALLBACK_HTTP_BODY_COMPLETION, + LWS_CALLBACK_HTTP_FILE_COMPLETION, + LWS_CALLBACK_HTTP_WRITEABLE, + LWS_CALLBACK_FILTER_NETWORK_CONNECTION, + LWS_CALLBACK_FILTER_HTTP_CONNECTION, + LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, + LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, + LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION, + LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, + LWS_CALLBACK_CONFIRM_EXTENSION_OKAY, + LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED, + LWS_CALLBACK_PROTOCOL_INIT, + LWS_CALLBACK_PROTOCOL_DESTROY, + LWS_CALLBACK_WSI_CREATE, /* always protocol[0] */ + LWS_CALLBACK_WSI_DESTROY, /* always protocol[0] */ + LWS_CALLBACK_GET_THREAD_ID, + + /* external poll() management support */ + LWS_CALLBACK_ADD_POLL_FD, + LWS_CALLBACK_DEL_POLL_FD, + LWS_CALLBACK_CHANGE_MODE_POLL_FD, + LWS_CALLBACK_LOCK_POLL, + LWS_CALLBACK_UNLOCK_POLL, + + LWS_CALLBACK_USER = 1000, /* user code can use any including / above */ +}; + +// argument structure for all external poll related calls +// passed in via 'in' +struct libwebsocket_pollargs { + int fd; // applicable file descriptor + int events; // the new event mask + int prev_events; // the previous event mask +}; + +#ifdef _WIN32 +struct libwebsocket_pollfd { + SOCKET fd; + SHORT events; + SHORT revents; +}; +#else +#define libwebsocket_pollfd pollfd +#endif + +enum libwebsocket_extension_callback_reasons { + LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT, + LWS_EXT_CALLBACK_SERVER_CONTEXT_DESTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_DESTRUCT, + LWS_EXT_CALLBACK_CONSTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONSTRUCT, + LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE, + LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION, + LWS_EXT_CALLBACK_DESTROY, + LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING, + LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED, + LWS_EXT_CALLBACK_PACKET_RX_PREPARSE, + LWS_EXT_CALLBACK_PACKET_TX_PRESEND, + LWS_EXT_CALLBACK_PACKET_TX_DO_SEND, + LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX, + LWS_EXT_CALLBACK_FLUSH_PENDING_TX, + LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX, + LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION, + LWS_EXT_CALLBACK_1HZ, + LWS_EXT_CALLBACK_REQUEST_ON_WRITEABLE, + LWS_EXT_CALLBACK_IS_WRITEABLE, + LWS_EXT_CALLBACK_PAYLOAD_TX, + LWS_EXT_CALLBACK_PAYLOAD_RX, +}; + +enum libwebsocket_write_protocol { + LWS_WRITE_TEXT, + LWS_WRITE_BINARY, + LWS_WRITE_CONTINUATION, + LWS_WRITE_HTTP, + + /* special 04+ opcodes */ + + LWS_WRITE_CLOSE, + LWS_WRITE_PING, + LWS_WRITE_PONG, + + /* flags */ + + LWS_WRITE_NO_FIN = 0x40, + /* + * client packet payload goes out on wire unmunged + * only useful for security tests since normal servers cannot + * decode the content if used + */ + LWS_WRITE_CLIENT_IGNORE_XOR_MASK = 0x80 +}; + +/* + * you need these to look at headers that have been parsed if using the + * LWS_CALLBACK_FILTER_CONNECTION callback. If a header from the enum + * list below is absent, .token = NULL and token_len = 0. Otherwise .token + * points to .token_len chars containing that header content. + */ + +struct lws_tokens { + char *token; + int token_len; +}; + +enum lws_token_indexes { + WSI_TOKEN_GET_URI, + WSI_TOKEN_POST_URI, + WSI_TOKEN_OPTIONS_URI, + WSI_TOKEN_HOST, + WSI_TOKEN_CONNECTION, + WSI_TOKEN_KEY1, + WSI_TOKEN_KEY2, + WSI_TOKEN_PROTOCOL, + WSI_TOKEN_UPGRADE, + WSI_TOKEN_ORIGIN, + WSI_TOKEN_DRAFT, + WSI_TOKEN_CHALLENGE, + + /* new for 04 */ + WSI_TOKEN_KEY, + WSI_TOKEN_VERSION, + WSI_TOKEN_SWORIGIN, + + /* new for 05 */ + WSI_TOKEN_EXTENSIONS, + + /* client receives these */ + WSI_TOKEN_ACCEPT, + WSI_TOKEN_NONCE, + WSI_TOKEN_HTTP, + + /* http-related */ + WSI_TOKEN_HTTP_ACCEPT, + WSI_TOKEN_HTTP_AC_REQUEST_HEADERS, + WSI_TOKEN_HTTP_IF_MODIFIED_SINCE, + WSI_TOKEN_HTTP_IF_NONE_MATCH, + WSI_TOKEN_HTTP_ACCEPT_ENCODING, + WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, + WSI_TOKEN_HTTP_PRAGMA, + WSI_TOKEN_HTTP_CACHE_CONTROL, + WSI_TOKEN_HTTP_AUTHORIZATION, + WSI_TOKEN_HTTP_COOKIE, + WSI_TOKEN_HTTP_CONTENT_LENGTH, + WSI_TOKEN_HTTP_CONTENT_TYPE, + WSI_TOKEN_HTTP_DATE, + WSI_TOKEN_HTTP_RANGE, + WSI_TOKEN_HTTP_REFERER, + WSI_TOKEN_HTTP_URI_ARGS, + + + WSI_TOKEN_MUXURL, + + /* use token storage to stash these */ + + _WSI_TOKEN_CLIENT_SENT_PROTOCOLS, + _WSI_TOKEN_CLIENT_PEER_ADDRESS, + _WSI_TOKEN_CLIENT_URI, + _WSI_TOKEN_CLIENT_HOST, + _WSI_TOKEN_CLIENT_ORIGIN, + + /* always last real token index*/ + WSI_TOKEN_COUNT, + /* parser state additions */ + WSI_TOKEN_NAME_PART, + WSI_TOKEN_SKIPPING, + WSI_TOKEN_SKIPPING_SAW_CR, + WSI_PARSING_COMPLETE, + WSI_INIT_TOKEN_MUXURL, +}; + +struct lws_token_limits { + unsigned short token_limit[WSI_TOKEN_COUNT]; +}; + +/* + * From RFC 6455 + 1000 + + 1000 indicates a normal closure, meaning that the purpose for + which the connection was established has been fulfilled. + + 1001 + + 1001 indicates that an endpoint is "going away", such as a server + going down or a browser having navigated away from a page. + + 1002 + + 1002 indicates that an endpoint is terminating the connection due + to a protocol error. + + 1003 + + 1003 indicates that an endpoint is terminating the connection + because it has received a type of data it cannot accept (e.g., an + endpoint that understands only text data MAY send this if it + receives a binary message). + + 1004 + + Reserved. The specific meaning might be defined in the future. + + 1005 + + 1005 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that no status + code was actually present. + + 1006 + + 1006 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that the + connection was closed abnormally, e.g., without sending or + receiving a Close control frame. + + 1007 + + 1007 indicates that an endpoint is terminating the connection + because it has received data within a message that was not + consistent with the type of the message (e.g., non-UTF-8 [RFC3629] + data within a text message). + + 1008 + + 1008 indicates that an endpoint is terminating the connection + because it has received a message that violates its policy. This + is a generic status code that can be returned when there is no + other more suitable status code (e.g., 1003 or 1009) or if there + is a need to hide specific details about the policy. + + 1009 + + 1009 indicates that an endpoint is terminating the connection + because it has received a message that is too big for it to + process. + + 1010 + + 1010 indicates that an endpoint (client) is terminating the + connection because it has expected the server to negotiate one or + more extension, but the server didn't return them in the response + message of the WebSocket handshake. The list of extensions that + are needed SHOULD appear in the /reason/ part of the Close frame. + Note that this status code is not used by the server, because it + can fail the WebSocket handshake instead. + + 1011 + + 1011 indicates that a server is terminating the connection because + it encountered an unexpected condition that prevented it from + fulfilling the request. + + 1015 + + 1015 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that the + connection was closed due to a failure to perform a TLS handshake + (e.g., the server certificate can't be verified). +*/ + +enum lws_close_status { + LWS_CLOSE_STATUS_NOSTATUS = 0, + LWS_CLOSE_STATUS_NORMAL = 1000, + LWS_CLOSE_STATUS_GOINGAWAY = 1001, + LWS_CLOSE_STATUS_PROTOCOL_ERR = 1002, + LWS_CLOSE_STATUS_UNACCEPTABLE_OPCODE = 1003, + LWS_CLOSE_STATUS_RESERVED = 1004, + LWS_CLOSE_STATUS_NO_STATUS = 1005, + LWS_CLOSE_STATUS_ABNORMAL_CLOSE = 1006, + LWS_CLOSE_STATUS_INVALID_PAYLOAD = 1007, + LWS_CLOSE_STATUS_POLICY_VIOLATION = 1008, + LWS_CLOSE_STATUS_MESSAGE_TOO_LARGE = 1009, + LWS_CLOSE_STATUS_EXTENSION_REQUIRED = 1010, + LWS_CLOSE_STATUS_UNEXPECTED_CONDITION = 1011, + LWS_CLOSE_STATUS_TLS_FAILURE = 1015, +}; + +enum http_status { + HTTP_STATUS_OK = 200, + HTTP_STATUS_NO_CONTENT = 204, + + HTTP_STATUS_BAD_REQUEST = 400, + HTTP_STATUS_UNAUTHORIZED, + HTTP_STATUS_PAYMENT_REQUIRED, + HTTP_STATUS_FORBIDDEN, + HTTP_STATUS_NOT_FOUND, + HTTP_STATUS_METHOD_NOT_ALLOWED, + HTTP_STATUS_NOT_ACCEPTABLE, + HTTP_STATUS_PROXY_AUTH_REQUIRED, + HTTP_STATUS_REQUEST_TIMEOUT, + HTTP_STATUS_CONFLICT, + HTTP_STATUS_GONE, + HTTP_STATUS_LENGTH_REQUIRED, + HTTP_STATUS_PRECONDITION_FAILED, + HTTP_STATUS_REQ_ENTITY_TOO_LARGE, + HTTP_STATUS_REQ_URI_TOO_LONG, + HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, + HTTP_STATUS_REQ_RANGE_NOT_SATISFIABLE, + HTTP_STATUS_EXPECTATION_FAILED, + + HTTP_STATUS_INTERNAL_SERVER_ERROR = 500, + HTTP_STATUS_NOT_IMPLEMENTED, + HTTP_STATUS_BAD_GATEWAY, + HTTP_STATUS_SERVICE_UNAVAILABLE, + HTTP_STATUS_GATEWAY_TIMEOUT, + HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED, +}; + +struct libwebsocket; +struct libwebsocket_context; +/* needed even with extensions disabled for create context */ +struct libwebsocket_extension; + +/** + * callback_function() - User server actions + * @context: Websockets context + * @wsi: Opaque websocket instance pointer + * @reason: The reason for the call + * @user: Pointer to per-session user data allocated by library + * @in: Pointer used for some callback reasons + * @len: Length set for some callback reasons + * + * This callback is the way the user controls what is served. All the + * protocol detail is hidden and handled by the library. + * + * For each connection / session there is user data allocated that is + * pointed to by "user". You set the size of this user data area when + * the library is initialized with libwebsocket_create_server. + * + * You get an opportunity to initialize user data when called back with + * LWS_CALLBACK_ESTABLISHED reason. + * + * LWS_CALLBACK_ESTABLISHED: after the server completes a handshake with + * an incoming client + * + * LWS_CALLBACK_CLIENT_CONNECTION_ERROR: the request client connection has + * been unable to complete a handshake with the remote server + * + * LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH: this is the last chance for the + * client user code to examine the http headers + * and decide to reject the connection. If the + * content in the headers is interesting to the + * client (url, etc) it needs to copy it out at + * this point since it will be destroyed before + * the CLIENT_ESTABLISHED call + * + * LWS_CALLBACK_CLIENT_ESTABLISHED: after your client connection completed + * a handshake with the remote server + * + * LWS_CALLBACK_CLOSED: when the websocket session ends + * + * LWS_CALLBACK_CLOSED_HTTP: when a HTTP (non-websocket) session ends + * + * LWS_CALLBACK_RECEIVE: data has appeared for this server endpoint from a + * remote client, it can be found at *in and is + * len bytes long + * + * LWS_CALLBACK_CLIENT_RECEIVE_PONG: if you elected to see PONG packets, + * they appear with this callback reason. PONG + * packets only exist in 04+ protocol + * + * LWS_CALLBACK_CLIENT_RECEIVE: data has appeared from the server for the + * client connection, it can be found at *in and + * is len bytes long + * + * LWS_CALLBACK_HTTP: an http request has come from a client that is not + * asking to upgrade the connection to a websocket + * one. This is a chance to serve http content, + * for example, to send a script to the client + * which will then open the websockets connection. + * @in points to the URI path requested and + * libwebsockets_serve_http_file() makes it very + * simple to send back a file to the client. + * Normally after sending the file you are done + * with the http connection, since the rest of the + * activity will come by websockets from the script + * that was delivered by http, so you will want to + * return 1; to close and free up the connection. + * That's important because it uses a slot in the + * total number of client connections allowed set + * by MAX_CLIENTS. + * + * LWS_CALLBACK_HTTP_BODY: the next @len bytes data from the http + * request body HTTP connection is now available in @in. + * + * LWS_CALLBACK_HTTP_BODY_COMPLETION: the expected amount of http request + * body has been delivered + * + * LWS_CALLBACK_HTTP_WRITEABLE: you can write more down the http protocol + * link now. + * + * LWS_CALLBACK_HTTP_FILE_COMPLETION: a file requested to be send down + * http link has completed. + * + * LWS_CALLBACK_CLIENT_WRITEABLE: + * LWS_CALLBACK_SERVER_WRITEABLE: If you call + * libwebsocket_callback_on_writable() on a connection, you will + * get one of these callbacks coming when the connection socket + * is able to accept another write packet without blocking. + * If it already was able to take another packet without blocking, + * you'll get this callback at the next call to the service loop + * function. Notice that CLIENTs get LWS_CALLBACK_CLIENT_WRITEABLE + * and servers get LWS_CALLBACK_SERVER_WRITEABLE. + * + * LWS_CALLBACK_FILTER_NETWORK_CONNECTION: called when a client connects to + * the server at network level; the connection is accepted but then + * passed to this callback to decide whether to hang up immediately + * or not, based on the client IP. @in contains the connection + * socket's descriptor. Since the client connection information is + * not available yet, @wsi still pointing to the main server socket. + * Return non-zero to terminate the connection before sending or + * receiving anything. Because this happens immediately after the + * network connection from the client, there's no websocket protocol + * selected yet so this callback is issued only to protocol 0. + * + * LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED: A new client just had + * been connected, accepted, and instantiated into the pool. This + * callback allows setting any relevant property to it. Because this + * happens immediately after the instantiation of a new client, + * there's no websocket protocol selected yet so this callback is + * issued only to protocol 0. Only @wsi is defined, pointing to the + * new client, and the return value is ignored. + * + * LWS_CALLBACK_FILTER_HTTP_CONNECTION: called when the request has + * been received and parsed from the client, but the response is + * not sent yet. Return non-zero to disallow the connection. + * @user is a pointer to the connection user space allocation, + * @in is the URI, eg, "/" + * In your handler you can use the public APIs + * lws_hdr_total_length() / lws_hdr_copy() to access all of the + * headers using the header enums lws_token_indexes from + * libwebsockets.h to check for and read the supported header + * presence and content before deciding to allow the http + * connection to proceed or to kill the connection. + * + * LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: called when the handshake has + * been received and parsed from the client, but the response is + * not sent yet. Return non-zero to disallow the connection. + * @user is a pointer to the connection user space allocation, + * @in is the requested protocol name + * In your handler you can use the public APIs + * lws_hdr_total_length() / lws_hdr_copy() to access all of the + * headers using the header enums lws_token_indexes from + * libwebsockets.h to check for and read the supported header + * presence and content before deciding to allow the handshake + * to proceed or to kill the connection. + * + * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: if configured for + * including OpenSSL support, this callback allows your user code + * to perform extra SSL_CTX_load_verify_locations() or similar + * calls to direct OpenSSL where to find certificates the client + * can use to confirm the remote server identity. @user is the + * OpenSSL SSL_CTX* + * + * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: if configured for + * including OpenSSL support, this callback allows your user code + * to load extra certifcates into the server which allow it to + * verify the validity of certificates returned by clients. @user + * is the server's OpenSSL SSL_CTX* + * + * LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: if the + * libwebsockets context was created with the option + * LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT, then this + * callback is generated during OpenSSL verification of the cert + * sent from the client. It is sent to protocol[0] callback as + * no protocol has been negotiated on the connection yet. + * Notice that the libwebsockets context and wsi are both NULL + * during this callback. See + * http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html + * to understand more detail about the OpenSSL callback that + * generates this libwebsockets callback and the meanings of the + * arguments passed. In this callback, @user is the x509_ctx, + * @in is the ssl pointer and @len is preverify_ok + * Notice that this callback maintains libwebsocket return + * conventions, return 0 to mean the cert is OK or 1 to fail it. + * This also means that if you don't handle this callback then + * the default callback action of returning 0 allows the client + * certificates. + * + * LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: this callback happens + * when a client handshake is being compiled. @user is NULL, + * @in is a char **, it's pointing to a char * which holds the + * next location in the header buffer where you can add + * headers, and @len is the remaining space in the header buffer, + * which is typically some hundreds of bytes. So, to add a canned + * cookie, your handler code might look similar to: + * + * char **p = (char **)in; + * + * if (len < 100) + * return 1; + * + * *p += sprintf(*p, "Cookie: a=b\x0d\x0a"); + * + * return 0; + * + * Notice if you add anything, you just have to take care about + * the CRLF on the line you added. Obviously this callback is + * optional, if you don't handle it everything is fine. + * + * Notice the callback is coming to protocols[0] all the time, + * because there is no specific protocol handshook yet. + * + * LWS_CALLBACK_CONFIRM_EXTENSION_OKAY: When the server handshake code + * sees that it does support a requested extension, before + * accepting the extension by additing to the list sent back to + * the client it gives this callback just to check that it's okay + * to use that extension. It calls back to the requested protocol + * and with @in being the extension name, @len is 0 and @user is + * valid. Note though at this time the ESTABLISHED callback hasn't + * happened yet so if you initialize @user content there, @user + * content during this callback might not be useful for anything. + * Notice this callback comes to protocols[0]. + * + * LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: When a client + * connection is being prepared to start a handshake to a server, + * each supported extension is checked with protocols[0] callback + * with this reason, giving the user code a chance to suppress the + * claim to support that extension by returning non-zero. If + * unhandled, by default 0 will be returned and the extension + * support included in the header to the server. Notice this + * callback comes to protocols[0]. + * + * LWS_CALLBACK_PROTOCOL_INIT: One-time call per protocol so it can + * do initial setup / allocations etc + * + * LWS_CALLBACK_PROTOCOL_DESTROY: One-time call per protocol indicating + * this protocol won't get used at all after this callback, the + * context is getting destroyed. Take the opportunity to + * deallocate everything that was allocated by the protocol. + * + * LWS_CALLBACK_WSI_CREATE: outermost (earliest) wsi create notification + * + * LWS_CALLBACK_WSI_DESTROY: outermost (latest) wsi destroy notification + * + * The next five reasons are optional and only need taking care of if you + * will be integrating libwebsockets sockets into an external polling + * array. + * + * For these calls, @in points to a struct libwebsocket_pollargs that + * contains @fd, @events and @prev_events members + * + * LWS_CALLBACK_ADD_POLL_FD: libwebsocket deals with its poll() loop + * internally, but in the case you are integrating with another + * server you will need to have libwebsocket sockets share a + * polling array with the other server. This and the other + * POLL_FD related callbacks let you put your specialized + * poll array interface code in the callback for protocol 0, the + * first protocol you support, usually the HTTP protocol in the + * serving case. + * This callback happens when a socket needs to be + * added to the polling loop: @in points to a struct + * libwebsocket_pollargs; the @fd member of the struct is the file + * descriptor, and @events contains the active events. + * + * If you are using the internal polling loop (the "service" + * callback), you can just ignore these callbacks. + * + * LWS_CALLBACK_DEL_POLL_FD: This callback happens when a socket descriptor + * needs to be removed from an external polling array. @in is + * again the struct libwebsocket_pollargs containing the @fd member + * to be removed. If you are using the internal polling + * loop, you can just ignore it. + * + * LWS_CALLBACK_CHANGE_MODE_POLL_FD: This callback happens when + * libwebsockets wants to modify the events for a connectiion. + * @in is the struct libwebsocket_pollargs with the @fd to change. + * The new event mask is in @events member and the old mask is in + * the @prev_events member. + * If you are using the internal polling loop, you can just ignore + * it. + * + * LWS_CALLBACK_LOCK_POLL: + * LWS_CALLBACK_UNLOCK_POLL: These allow the external poll changes driven + * by libwebsockets to participate in an external thread locking + * scheme around the changes, so the whole thing is threadsafe. + */ +LWS_VISIBLE LWS_EXTERN int callback(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len); + +typedef int (callback_function)(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len); + +#ifndef LWS_NO_EXTENSIONS +/** + * extension_callback_function() - Hooks to allow extensions to operate + * @context: Websockets context + * @ext: This extension + * @wsi: Opaque websocket instance pointer + * @reason: The reason for the call + * @user: Pointer to per-session user data allocated by library + * @in: Pointer used for some callback reasons + * @len: Length set for some callback reasons + * + * Each extension that is active on a particular connection receives + * callbacks during the connection lifetime to allow the extension to + * operate on websocket data and manage itself. + * + * Libwebsockets takes care of allocating and freeing "user" memory for + * each active extension on each connection. That is what is pointed to + * by the @user parameter. + * + * LWS_EXT_CALLBACK_CONSTRUCT: called when the server has decided to + * select this extension from the list provided by the client, + * just before the server will send back the handshake accepting + * the connection with this extension active. This gives the + * extension a chance to initialize its connection context found + * in @user. + * + * LWS_EXT_CALLBACK_CLIENT_CONSTRUCT: same as LWS_EXT_CALLBACK_CONSTRUCT + * but called when client is instantiating this extension. Some + * extensions will work the same on client and server side and then + * you can just merge handlers for both CONSTRUCTS. + * + * LWS_EXT_CALLBACK_DESTROY: called when the connection the extension was + * being used on is about to be closed and deallocated. It's the + * last chance for the extension to deallocate anything it has + * allocated in the user data (pointed to by @user) before the + * user data is deleted. This same callback is used whether you + * are in client or server instantiation context. + * + * LWS_EXT_CALLBACK_PACKET_RX_PREPARSE: when this extension was active on + * a connection, and a packet of data arrived at the connection, + * it is passed to this callback to give the extension a chance to + * change the data, eg, decompress it. @user is pointing to the + * extension's private connection context data, @in is pointing + * to an lws_tokens struct, it consists of a char * pointer called + * token, and an int called token_len. At entry, these are + * set to point to the received buffer and set to the content + * length. If the extension will grow the content, it should use + * a new buffer allocated in its private user context data and + * set the pointed-to lws_tokens members to point to its buffer. + * + * LWS_EXT_CALLBACK_PACKET_TX_PRESEND: this works the same way as + * LWS_EXT_CALLBACK_PACKET_RX_PREPARSE above, except it gives the + * extension a chance to change websocket data just before it will + * be sent out. Using the same lws_token pointer scheme in @in, + * the extension can change the buffer and the length to be + * transmitted how it likes. Again if it wants to grow the + * buffer safely, it should copy the data into its own buffer and + * set the lws_tokens token pointer to it. + */ +LWS_VISIBLE LWS_EXTERN int extension_callback(struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); + +typedef int (extension_callback_function)(struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); +#endif + +/** + * struct libwebsocket_protocols - List of protocols and handlers server + * supports. + * @name: Protocol name that must match the one given in the client + * Javascript new WebSocket(url, 'protocol') name + * @callback: The service callback used for this protocol. It allows the + * service action for an entire protocol to be encapsulated in + * the protocol-specific callback + * @per_session_data_size: Each new connection using this protocol gets + * this much memory allocated on connection establishment and + * freed on connection takedown. A pointer to this per-connection + * allocation is passed into the callback in the 'user' parameter + * @rx_buffer_size: if you want atomic frames delivered to the callback, you + * should set this to the size of the biggest legal frame that + * you support. If the frame size is exceeded, there is no + * error, but the buffer will spill to the user callback when + * full, which you can detect by using + * libwebsockets_remaining_packet_payload(). Notice that you + * just talk about frame size here, the LWS_SEND_BUFFER_PRE_PADDING + * and post-padding are automatically also allocated on top. + * @no_buffer_all_partial_tx: Leave at zero if you want the library to take + * care of all partial tx for you. It's useful if you only have + * small tx packets and the chance of any truncated send is small + * enough any additional malloc / buffering overhead is less + * painful than writing the code to deal with partial sends. For + * protocols where you stream big blocks, set to nonzero and use + * the return value from libwebsocket_write() to manage how much + * got send yourself. + * @owning_server: the server init call fills in this opaque pointer when + * registering this protocol with the server. + * @protocol_index: which protocol we are starting from zero + * + * This structure represents one protocol supported by the server. An + * array of these structures is passed to libwebsocket_create_server() + * allows as many protocols as you like to be handled by one server. + */ + +struct libwebsocket_protocols { + const char *name; + callback_function *callback; + size_t per_session_data_size; + size_t rx_buffer_size; + int no_buffer_all_partial_tx; + + /* + * below are filled in on server init and can be left uninitialized, + * no need for user to use them directly either + */ + + struct libwebsocket_context *owning_server; + int protocol_index; +}; + +#ifndef LWS_NO_EXTENSIONS +/** + * struct libwebsocket_extension - An extension we know how to cope with + * + * @name: Formal extension name, eg, "deflate-stream" + * @callback: Service callback + * @per_session_data_size: Libwebsockets will auto-malloc this much + * memory for the use of the extension, a pointer + * to it comes in the @user callback parameter + * @per_context_private_data: Optional storage for this extension that + * is per-context, so it can track stuff across + * all sessions, etc, if it wants + */ + +struct libwebsocket_extension { + const char *name; + extension_callback_function *callback; + size_t per_session_data_size; + void *per_context_private_data; +}; +#endif + +/** + * struct lws_context_creation_info: parameters to create context with + * + * @port: Port to listen on... you can use 0 to suppress listening on + * any port, that's what you want if you are not running a + * websocket server at all but just using it as a client + * @iface: NULL to bind the listen socket to all interfaces, or the + * interface name, eg, "eth2" + * @protocols: Array of structures listing supported protocols and a protocol- + * specific callback for each one. The list is ended with an + * entry that has a NULL callback pointer. + * It's not const because we write the owning_server member + * @extensions: NULL or array of libwebsocket_extension structs listing the + * extensions this context supports. If you configured with + * --without-extensions, you should give NULL here. + * @token_limits: NULL or struct lws_token_limits pointer which is initialized + * with a token length limit for each possible WSI_TOKEN_*** + * @ssl_cert_filepath: If libwebsockets was compiled to use ssl, and you want + * to listen using SSL, set to the filepath to fetch the + * server cert from, otherwise NULL for unencrypted + * @ssl_private_key_filepath: filepath to private key if wanting SSL mode, + * else ignored + * @ssl_ca_filepath: CA certificate filepath or NULL + * @ssl_cipher_list: List of valid ciphers to use (eg, + * "RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL" + * or you can leave it as NULL to get "DEFAULT" + * @gid: group id to change to after setting listen socket, or -1. + * @uid: user id to change to after setting listen socket, or -1. + * @options: 0, or LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK + * @user: optional user pointer that can be recovered via the context + * pointer using libwebsocket_context_user + * @ka_time: 0 for no keepalive, otherwise apply this keepalive timeout to + * all libwebsocket sockets, client or server + * @ka_probes: if ka_time was nonzero, after the timeout expires how many + * times to try to get a response from the peer before giving up + * and killing the connection + * @ka_interval: if ka_time was nonzero, how long to wait before each ka_probes + * attempt + */ + +struct lws_context_creation_info { + int port; + const char *iface; + struct libwebsocket_protocols *protocols; + struct libwebsocket_extension *extensions; + struct lws_token_limits *token_limits; + const char *ssl_cert_filepath; + const char *ssl_private_key_filepath; + const char *ssl_ca_filepath; + const char *ssl_cipher_list; + const char *http_proxy_address; + unsigned int http_proxy_port; + int gid; + int uid; + unsigned int options; + void *user; + int ka_time; + int ka_probes; + int ka_interval; + +}; + +LWS_VISIBLE LWS_EXTERN +void lws_set_log_level(int level, + void (*log_emit_function)(int level, const char *line)); + +LWS_VISIBLE LWS_EXTERN void +lwsl_emit_syslog(int level, const char *line); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket_context * +libwebsocket_create_context(struct lws_context_creation_info *info); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_set_proxy(struct libwebsocket_context *context, const char *proxy); + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_context_destroy(struct libwebsocket_context *context); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_service(struct libwebsocket_context *context, int timeout_ms); + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_cancel_service(struct libwebsocket_context *context); + +#ifdef LWS_USE_LIBEV +LWS_VISIBLE LWS_EXTERN int +libwebsocket_initloop( + struct libwebsocket_context *context, struct ev_loop *loop); + +LWS_VISIBLE void +libwebsocket_sigint_cb( + struct ev_loop *loop, struct ev_signal *watcher, int revents); +#endif /* LWS_USE_LIBEV */ + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_service_fd(struct libwebsocket_context *context, + struct libwebsocket_pollfd *pollfd); + +LWS_VISIBLE LWS_EXTERN void * +libwebsocket_context_user(struct libwebsocket_context *context); + +enum pending_timeout { + NO_PENDING_TIMEOUT = 0, + PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE, + PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE, + PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, + PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE, + PENDING_TIMEOUT_AWAITING_PING, + PENDING_TIMEOUT_CLOSE_ACK, + PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE, + PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE, + PENDING_TIMEOUT_SSL_ACCEPT, + PENDING_TIMEOUT_HTTP_CONTENT, + PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND, +}; + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_set_timeout(struct libwebsocket *wsi, + enum pending_timeout reason, int secs); + +/* + * IMPORTANT NOTICE! + * + * When sending with websocket protocol (LWS_WRITE_TEXT or LWS_WRITE_BINARY) + * the send buffer has to have LWS_SEND_BUFFER_PRE_PADDING bytes valid BEFORE + * buf, and LWS_SEND_BUFFER_POST_PADDING bytes valid AFTER (buf + len). + * + * This allows us to add protocol info before and after the data, and send as + * one packet on the network without payload copying, for maximum efficiency. + * + * So for example you need this kind of code to use libwebsocket_write with a + * 128-byte payload + * + * char buf[LWS_SEND_BUFFER_PRE_PADDING + 128 + LWS_SEND_BUFFER_POST_PADDING]; + * + * // fill your part of the buffer... for example here it's all zeros + * memset(&buf[LWS_SEND_BUFFER_PRE_PADDING], 0, 128); + * + * libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], 128, + * LWS_WRITE_TEXT); + * + * When sending LWS_WRITE_HTTP, there is no protocol addition and you can just + * use the whole buffer without taking care of the above. + */ + +/* + * this is the frame nonce plus two header plus 8 length + * there's an additional two for mux extension per mux nesting level + * 2 byte prepend on close will already fit because control frames cannot use + * the big length style + */ + +#define LWS_SEND_BUFFER_PRE_PADDING (4 + 10 + (2 * MAX_MUX_RECURSION)) +#define LWS_SEND_BUFFER_POST_PADDING 4 + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, size_t len, + enum libwebsocket_write_protocol protocol); + +/* helper for case where buffer may be const */ +#define libwebsocket_write_http(wsi, buf, len) \ + libwebsocket_write(wsi, (unsigned char *)(buf), len, LWS_WRITE_HTTP) + +LWS_VISIBLE LWS_EXTERN int +libwebsockets_serve_http_file(struct libwebsocket_context *context, + struct libwebsocket *wsi, const char *file, + const char *content_type, const char *other_headers); +LWS_VISIBLE LWS_EXTERN int +libwebsockets_serve_http_file_fragment(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int libwebsockets_return_http_status( + struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned int code, + const char *html_body); + +LWS_VISIBLE LWS_EXTERN const struct libwebsocket_protocols * +libwebsockets_get_protocol(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_callback_on_writable(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_callback_on_writable_all_protocol( + const struct libwebsocket_protocols *protocol); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_callback_all_protocol( + const struct libwebsocket_protocols *protocol, int reason); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_get_socket_fd(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_is_final_fragment(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN unsigned char +libwebsocket_get_reserved_bits(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable); + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_rx_flow_allow_all_protocol( + const struct libwebsocket_protocols *protocol); + +LWS_VISIBLE LWS_EXTERN size_t +libwebsockets_remaining_packet_payload(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket * +libwebsocket_client_connect(struct libwebsocket_context *clients, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket * +libwebsocket_client_connect_extended(struct libwebsocket_context *clients, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one, + void *userdata); + +LWS_VISIBLE LWS_EXTERN const char * +libwebsocket_canonical_hostname(struct libwebsocket_context *context); + + +LWS_VISIBLE LWS_EXTERN void +libwebsockets_get_peer_addresses(struct libwebsocket_context *context, + struct libwebsocket *wsi, int fd, char *name, int name_len, + char *rip, int rip_len); + +LWS_VISIBLE LWS_EXTERN int +libwebsockets_get_random(struct libwebsocket_context *context, + void *buf, int len); + +LWS_VISIBLE LWS_EXTERN int +lws_daemonize(const char *_lock_path); + +LWS_VISIBLE LWS_EXTERN int +lws_send_pipe_choked(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +lws_frame_is_binary(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN unsigned char * +libwebsockets_SHA1(const unsigned char *d, size_t n, unsigned char *md); + +LWS_VISIBLE LWS_EXTERN int +lws_b64_encode_string(const char *in, int in_len, char *out, int out_size); + +LWS_VISIBLE LWS_EXTERN int +lws_b64_decode_string(const char *in, char *out, int out_size); + +LWS_VISIBLE LWS_EXTERN const char * +lws_get_library_version(void); + +/* access to headers... only valid while headers valid */ + +LWS_VISIBLE LWS_EXTERN int +lws_hdr_total_length(struct libwebsocket *wsi, enum lws_token_indexes h); + +LWS_VISIBLE LWS_EXTERN int +lws_hdr_copy(struct libwebsocket *wsi, char *dest, int len, + enum lws_token_indexes h); + +/* + * Note: this is not normally needed as a user api. It's provided in case it is + * useful when integrating with other app poll loop service code. + */ + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_read(struct libwebsocket_context *context, + struct libwebsocket *wsi, + unsigned char *buf, size_t len); + +#ifndef LWS_NO_EXTENSIONS +LWS_VISIBLE LWS_EXTERN struct libwebsocket_extension *libwebsocket_get_internal_extensions(); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/android/dist/armv8a/lib/cmake/libwebsockets/LibwebsocketsTargets-noconfig.cmake b/android/dist/armv8a/lib/cmake/libwebsockets/LibwebsocketsTargets-noconfig.cmake new file mode 100644 index 0000000000..6a61cb5e9a --- /dev/null +++ b/android/dist/armv8a/lib/cmake/libwebsockets/LibwebsocketsTargets-noconfig.cmake @@ -0,0 +1,31 @@ +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "websockets" for configuration "" +set_property(TARGET websockets APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG) +set_target_properties(websockets PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_NOCONFIG "C" + IMPORTED_LINK_INTERFACE_LIBRARIES_NOCONFIG "/opt/android-ndk-r10e/platforms/android-21/arch-arm64/usr/lib/libz.so;m" + IMPORTED_LOCATION_NOCONFIG "${_IMPORT_PREFIX}/lib/libwebsockets.a" + ) + +list(APPEND _IMPORT_CHECK_TARGETS websockets ) +list(APPEND _IMPORT_CHECK_FILES_FOR_websockets "${_IMPORT_PREFIX}/lib/libwebsockets.a" ) + +# Import target "websockets_shared" for configuration "" +set_property(TARGET websockets_shared APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG) +set_target_properties(websockets_shared PROPERTIES + IMPORTED_LINK_INTERFACE_LIBRARIES_NOCONFIG "/opt/android-ndk-r10e/platforms/android-21/arch-arm64/usr/lib/libz.so;m" + IMPORTED_LOCATION_NOCONFIG "${_IMPORT_PREFIX}/lib/libwebsockets.so.4.0.0" + IMPORTED_SONAME_NOCONFIG "libwebsockets.so.4.0.0" + ) + +list(APPEND _IMPORT_CHECK_TARGETS websockets_shared ) +list(APPEND _IMPORT_CHECK_FILES_FOR_websockets_shared "${_IMPORT_PREFIX}/lib/libwebsockets.so.4.0.0" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/android/dist/armv8a/lib/cmake/libwebsockets/LibwebsocketsTargets.cmake b/android/dist/armv8a/lib/cmake/libwebsockets/LibwebsocketsTargets.cmake new file mode 100644 index 0000000000..848b03ccc2 --- /dev/null +++ b/android/dist/armv8a/lib/cmake/libwebsockets/LibwebsocketsTargets.cmake @@ -0,0 +1,93 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5) + message(FATAL_ERROR "CMake >= 2.6.0 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 2.6) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_targetsDefined) +set(_targetsNotDefined) +set(_expectedTargets) +foreach(_expectedTarget websockets websockets_shared) + list(APPEND _expectedTargets ${_expectedTarget}) + if(NOT TARGET ${_expectedTarget}) + list(APPEND _targetsNotDefined ${_expectedTarget}) + endif() + if(TARGET ${_expectedTarget}) + list(APPEND _targetsDefined ${_expectedTarget}) + endif() +endforeach() +if("${_targetsDefined}" STREQUAL "${_expectedTargets}") + unset(_targetsDefined) + unset(_targetsNotDefined) + unset(_expectedTargets) + set(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT "${_targetsDefined}" STREQUAL "") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n") +endif() +unset(_targetsDefined) +unset(_targetsNotDefined) +unset(_expectedTargets) + + +# Compute the installation prefix relative to this file. +get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +if(_IMPORT_PREFIX STREQUAL "/") + set(_IMPORT_PREFIX "") +endif() + +# Create imported target websockets +add_library(websockets STATIC IMPORTED) + +# Create imported target websockets_shared +add_library(websockets_shared SHARED IMPORTED) + +# Load information for each installed configuration. +get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +file(GLOB CONFIG_FILES "${_DIR}/LibwebsocketsTargets-*.cmake") +foreach(f ${CONFIG_FILES}) + include(${f}) +endforeach() + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(target ${_IMPORT_CHECK_TARGETS} ) + foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} ) + if(NOT EXISTS "${file}" ) + message(FATAL_ERROR "The imported target \"${target}\" references the file + \"${file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() + endforeach() + unset(_IMPORT_CHECK_FILES_FOR_${target}) +endforeach() +unset(_IMPORT_CHECK_TARGETS) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/android/dist/armv8a/lib/libwebsockets.a b/android/dist/armv8a/lib/libwebsockets.a new file mode 100644 index 0000000000..b37212d780 Binary files /dev/null and b/android/dist/armv8a/lib/libwebsockets.a differ diff --git a/android/dist/armv8a/lib/libwebsockets.so b/android/dist/armv8a/lib/libwebsockets.so new file mode 100644 index 0000000000..5d9359c816 Binary files /dev/null and b/android/dist/armv8a/lib/libwebsockets.so differ diff --git a/android/dist/armv8a/lib/libwebsockets.so.4.0.0 b/android/dist/armv8a/lib/libwebsockets.so.4.0.0 new file mode 100644 index 0000000000..5d9359c816 Binary files /dev/null and b/android/dist/armv8a/lib/libwebsockets.so.4.0.0 differ diff --git a/android/dist/x86/include/libwebsockets.h b/android/dist/x86/include/libwebsockets.h new file mode 100644 index 0000000000..0bb67f57bc --- /dev/null +++ b/android/dist/x86/include/libwebsockets.h @@ -0,0 +1,1207 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010-2013 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef LIBWEBSOCKET_H_3060898B846849FF9F88F5DB59B5950C +#define LIBWEBSOCKET_H_3060898B846849FF9F88F5DB59B5950C + +#ifdef __cplusplus +extern "C" { +#include +#endif + +#ifdef CMAKE_BUILD +#include "lws_config.h" +#endif + +#if defined(WIN32) || defined(_WIN32) + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include +#include + +#define strcasecmp stricmp +#define getdtablesize() 30000 + +#define LWS_VISIBLE + +#ifdef LWS_DLL +#ifdef LWS_INTERNAL +#define LWS_EXTERN extern __declspec(dllexport) +#else +#define LWS_EXTERN extern __declspec(dllimport) +#endif +#else +#define LWS_EXTERN +#endif + +#else // NOT WIN32 + +#include +#include + +#if defined(__GNUC__) +#define LWS_VISIBLE __attribute__((visibility("default"))) +#else +#define LWS_VISIBLE +#endif + +#endif + +#ifdef LWS_USE_LIBEV +#include +#endif /* LWS_USE_LIBEV */ + +#include + +#ifndef LWS_EXTERN +#define LWS_EXTERN extern +#endif + +#ifdef _WIN32 +#define random rand +#else +#include +#include +#endif + +#define CONTEXT_PORT_NO_LISTEN -1 +#define MAX_MUX_RECURSION 2 + +enum lws_log_levels { + LLL_ERR = 1 << 0, + LLL_WARN = 1 << 1, + LLL_NOTICE = 1 << 2, + LLL_INFO = 1 << 3, + LLL_DEBUG = 1 << 4, + LLL_PARSER = 1 << 5, + LLL_HEADER = 1 << 6, + LLL_EXT = 1 << 7, + LLL_CLIENT = 1 << 8, + LLL_LATENCY = 1 << 9, + + LLL_COUNT = 10 /* set to count of valid flags */ +}; + +LWS_VISIBLE LWS_EXTERN void _lws_log(int filter, const char *format, ...); + +/* notice, warn and log are always compiled in */ +#define lwsl_notice(...) _lws_log(LLL_NOTICE, __VA_ARGS__) +#define lwsl_warn(...) _lws_log(LLL_WARN, __VA_ARGS__) +#define lwsl_err(...) _lws_log(LLL_ERR, __VA_ARGS__) +/* + * weaker logging can be deselected at configure time using --disable-debug + * that gets rid of the overhead of checking while keeping _warn and _err + * active + */ +#ifdef _DEBUG + +#define lwsl_info(...) _lws_log(LLL_INFO, __VA_ARGS__) +#define lwsl_debug(...) _lws_log(LLL_DEBUG, __VA_ARGS__) +#define lwsl_parser(...) _lws_log(LLL_PARSER, __VA_ARGS__) +#define lwsl_header(...) _lws_log(LLL_HEADER, __VA_ARGS__) +#define lwsl_ext(...) _lws_log(LLL_EXT, __VA_ARGS__) +#define lwsl_client(...) _lws_log(LLL_CLIENT, __VA_ARGS__) +#define lwsl_latency(...) _lws_log(LLL_LATENCY, __VA_ARGS__) +LWS_VISIBLE LWS_EXTERN void lwsl_hexdump(void *buf, size_t len); + +#else /* no debug */ + +#define lwsl_info(...) +#define lwsl_debug(...) +#define lwsl_parser(...) +#define lwsl_header(...) +#define lwsl_ext(...) +#define lwsl_client(...) +#define lwsl_latency(...) +#define lwsl_hexdump(a, b) + +#endif + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +/* api change list for user code to test against */ + +#define LWS_FEATURE_SERVE_HTTP_FILE_HAS_OTHER_HEADERS_ARG + + +enum libwebsocket_context_options { + LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT = 2, + LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME = 4, + LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT = 8, + LWS_SERVER_OPTION_LIBEV = 16, + LWS_SERVER_OPTION_DISABLE_IPV6 = 32, + LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS = 64, +}; + +enum libwebsocket_callback_reasons { + LWS_CALLBACK_ESTABLISHED, + LWS_CALLBACK_CLIENT_CONNECTION_ERROR, + LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH, + LWS_CALLBACK_CLIENT_ESTABLISHED, + LWS_CALLBACK_CLOSED, + LWS_CALLBACK_CLOSED_HTTP, + LWS_CALLBACK_RECEIVE, + LWS_CALLBACK_CLIENT_RECEIVE, + LWS_CALLBACK_CLIENT_RECEIVE_PONG, + LWS_CALLBACK_CLIENT_WRITEABLE, + LWS_CALLBACK_SERVER_WRITEABLE, + LWS_CALLBACK_HTTP, + LWS_CALLBACK_HTTP_BODY, + LWS_CALLBACK_HTTP_BODY_COMPLETION, + LWS_CALLBACK_HTTP_FILE_COMPLETION, + LWS_CALLBACK_HTTP_WRITEABLE, + LWS_CALLBACK_FILTER_NETWORK_CONNECTION, + LWS_CALLBACK_FILTER_HTTP_CONNECTION, + LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, + LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS, + LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, + LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION, + LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, + LWS_CALLBACK_CONFIRM_EXTENSION_OKAY, + LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED, + LWS_CALLBACK_PROTOCOL_INIT, + LWS_CALLBACK_PROTOCOL_DESTROY, + LWS_CALLBACK_WSI_CREATE, /* always protocol[0] */ + LWS_CALLBACK_WSI_DESTROY, /* always protocol[0] */ + LWS_CALLBACK_GET_THREAD_ID, + + /* external poll() management support */ + LWS_CALLBACK_ADD_POLL_FD, + LWS_CALLBACK_DEL_POLL_FD, + LWS_CALLBACK_CHANGE_MODE_POLL_FD, + LWS_CALLBACK_LOCK_POLL, + LWS_CALLBACK_UNLOCK_POLL, + + LWS_CALLBACK_USER = 1000, /* user code can use any including / above */ +}; + +// argument structure for all external poll related calls +// passed in via 'in' +struct libwebsocket_pollargs { + int fd; // applicable file descriptor + int events; // the new event mask + int prev_events; // the previous event mask +}; + +#ifdef _WIN32 +struct libwebsocket_pollfd { + SOCKET fd; + SHORT events; + SHORT revents; +}; +#else +#define libwebsocket_pollfd pollfd +#endif + +enum libwebsocket_extension_callback_reasons { + LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT, + LWS_EXT_CALLBACK_SERVER_CONTEXT_DESTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONTEXT_DESTRUCT, + LWS_EXT_CALLBACK_CONSTRUCT, + LWS_EXT_CALLBACK_CLIENT_CONSTRUCT, + LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE, + LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION, + LWS_EXT_CALLBACK_DESTROY, + LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING, + LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED, + LWS_EXT_CALLBACK_PACKET_RX_PREPARSE, + LWS_EXT_CALLBACK_PACKET_TX_PRESEND, + LWS_EXT_CALLBACK_PACKET_TX_DO_SEND, + LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX, + LWS_EXT_CALLBACK_FLUSH_PENDING_TX, + LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX, + LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION, + LWS_EXT_CALLBACK_1HZ, + LWS_EXT_CALLBACK_REQUEST_ON_WRITEABLE, + LWS_EXT_CALLBACK_IS_WRITEABLE, + LWS_EXT_CALLBACK_PAYLOAD_TX, + LWS_EXT_CALLBACK_PAYLOAD_RX, +}; + +enum libwebsocket_write_protocol { + LWS_WRITE_TEXT, + LWS_WRITE_BINARY, + LWS_WRITE_CONTINUATION, + LWS_WRITE_HTTP, + + /* special 04+ opcodes */ + + LWS_WRITE_CLOSE, + LWS_WRITE_PING, + LWS_WRITE_PONG, + + /* flags */ + + LWS_WRITE_NO_FIN = 0x40, + /* + * client packet payload goes out on wire unmunged + * only useful for security tests since normal servers cannot + * decode the content if used + */ + LWS_WRITE_CLIENT_IGNORE_XOR_MASK = 0x80 +}; + +/* + * you need these to look at headers that have been parsed if using the + * LWS_CALLBACK_FILTER_CONNECTION callback. If a header from the enum + * list below is absent, .token = NULL and token_len = 0. Otherwise .token + * points to .token_len chars containing that header content. + */ + +struct lws_tokens { + char *token; + int token_len; +}; + +enum lws_token_indexes { + WSI_TOKEN_GET_URI, + WSI_TOKEN_POST_URI, + WSI_TOKEN_OPTIONS_URI, + WSI_TOKEN_HOST, + WSI_TOKEN_CONNECTION, + WSI_TOKEN_KEY1, + WSI_TOKEN_KEY2, + WSI_TOKEN_PROTOCOL, + WSI_TOKEN_UPGRADE, + WSI_TOKEN_ORIGIN, + WSI_TOKEN_DRAFT, + WSI_TOKEN_CHALLENGE, + + /* new for 04 */ + WSI_TOKEN_KEY, + WSI_TOKEN_VERSION, + WSI_TOKEN_SWORIGIN, + + /* new for 05 */ + WSI_TOKEN_EXTENSIONS, + + /* client receives these */ + WSI_TOKEN_ACCEPT, + WSI_TOKEN_NONCE, + WSI_TOKEN_HTTP, + + /* http-related */ + WSI_TOKEN_HTTP_ACCEPT, + WSI_TOKEN_HTTP_AC_REQUEST_HEADERS, + WSI_TOKEN_HTTP_IF_MODIFIED_SINCE, + WSI_TOKEN_HTTP_IF_NONE_MATCH, + WSI_TOKEN_HTTP_ACCEPT_ENCODING, + WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, + WSI_TOKEN_HTTP_PRAGMA, + WSI_TOKEN_HTTP_CACHE_CONTROL, + WSI_TOKEN_HTTP_AUTHORIZATION, + WSI_TOKEN_HTTP_COOKIE, + WSI_TOKEN_HTTP_CONTENT_LENGTH, + WSI_TOKEN_HTTP_CONTENT_TYPE, + WSI_TOKEN_HTTP_DATE, + WSI_TOKEN_HTTP_RANGE, + WSI_TOKEN_HTTP_REFERER, + WSI_TOKEN_HTTP_URI_ARGS, + + + WSI_TOKEN_MUXURL, + + /* use token storage to stash these */ + + _WSI_TOKEN_CLIENT_SENT_PROTOCOLS, + _WSI_TOKEN_CLIENT_PEER_ADDRESS, + _WSI_TOKEN_CLIENT_URI, + _WSI_TOKEN_CLIENT_HOST, + _WSI_TOKEN_CLIENT_ORIGIN, + + /* always last real token index*/ + WSI_TOKEN_COUNT, + /* parser state additions */ + WSI_TOKEN_NAME_PART, + WSI_TOKEN_SKIPPING, + WSI_TOKEN_SKIPPING_SAW_CR, + WSI_PARSING_COMPLETE, + WSI_INIT_TOKEN_MUXURL, +}; + +struct lws_token_limits { + unsigned short token_limit[WSI_TOKEN_COUNT]; +}; + +/* + * From RFC 6455 + 1000 + + 1000 indicates a normal closure, meaning that the purpose for + which the connection was established has been fulfilled. + + 1001 + + 1001 indicates that an endpoint is "going away", such as a server + going down or a browser having navigated away from a page. + + 1002 + + 1002 indicates that an endpoint is terminating the connection due + to a protocol error. + + 1003 + + 1003 indicates that an endpoint is terminating the connection + because it has received a type of data it cannot accept (e.g., an + endpoint that understands only text data MAY send this if it + receives a binary message). + + 1004 + + Reserved. The specific meaning might be defined in the future. + + 1005 + + 1005 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that no status + code was actually present. + + 1006 + + 1006 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that the + connection was closed abnormally, e.g., without sending or + receiving a Close control frame. + + 1007 + + 1007 indicates that an endpoint is terminating the connection + because it has received data within a message that was not + consistent with the type of the message (e.g., non-UTF-8 [RFC3629] + data within a text message). + + 1008 + + 1008 indicates that an endpoint is terminating the connection + because it has received a message that violates its policy. This + is a generic status code that can be returned when there is no + other more suitable status code (e.g., 1003 or 1009) or if there + is a need to hide specific details about the policy. + + 1009 + + 1009 indicates that an endpoint is terminating the connection + because it has received a message that is too big for it to + process. + + 1010 + + 1010 indicates that an endpoint (client) is terminating the + connection because it has expected the server to negotiate one or + more extension, but the server didn't return them in the response + message of the WebSocket handshake. The list of extensions that + are needed SHOULD appear in the /reason/ part of the Close frame. + Note that this status code is not used by the server, because it + can fail the WebSocket handshake instead. + + 1011 + + 1011 indicates that a server is terminating the connection because + it encountered an unexpected condition that prevented it from + fulfilling the request. + + 1015 + + 1015 is a reserved value and MUST NOT be set as a status code in a + Close control frame by an endpoint. It is designated for use in + applications expecting a status code to indicate that the + connection was closed due to a failure to perform a TLS handshake + (e.g., the server certificate can't be verified). +*/ + +enum lws_close_status { + LWS_CLOSE_STATUS_NOSTATUS = 0, + LWS_CLOSE_STATUS_NORMAL = 1000, + LWS_CLOSE_STATUS_GOINGAWAY = 1001, + LWS_CLOSE_STATUS_PROTOCOL_ERR = 1002, + LWS_CLOSE_STATUS_UNACCEPTABLE_OPCODE = 1003, + LWS_CLOSE_STATUS_RESERVED = 1004, + LWS_CLOSE_STATUS_NO_STATUS = 1005, + LWS_CLOSE_STATUS_ABNORMAL_CLOSE = 1006, + LWS_CLOSE_STATUS_INVALID_PAYLOAD = 1007, + LWS_CLOSE_STATUS_POLICY_VIOLATION = 1008, + LWS_CLOSE_STATUS_MESSAGE_TOO_LARGE = 1009, + LWS_CLOSE_STATUS_EXTENSION_REQUIRED = 1010, + LWS_CLOSE_STATUS_UNEXPECTED_CONDITION = 1011, + LWS_CLOSE_STATUS_TLS_FAILURE = 1015, +}; + +enum http_status { + HTTP_STATUS_OK = 200, + HTTP_STATUS_NO_CONTENT = 204, + + HTTP_STATUS_BAD_REQUEST = 400, + HTTP_STATUS_UNAUTHORIZED, + HTTP_STATUS_PAYMENT_REQUIRED, + HTTP_STATUS_FORBIDDEN, + HTTP_STATUS_NOT_FOUND, + HTTP_STATUS_METHOD_NOT_ALLOWED, + HTTP_STATUS_NOT_ACCEPTABLE, + HTTP_STATUS_PROXY_AUTH_REQUIRED, + HTTP_STATUS_REQUEST_TIMEOUT, + HTTP_STATUS_CONFLICT, + HTTP_STATUS_GONE, + HTTP_STATUS_LENGTH_REQUIRED, + HTTP_STATUS_PRECONDITION_FAILED, + HTTP_STATUS_REQ_ENTITY_TOO_LARGE, + HTTP_STATUS_REQ_URI_TOO_LONG, + HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, + HTTP_STATUS_REQ_RANGE_NOT_SATISFIABLE, + HTTP_STATUS_EXPECTATION_FAILED, + + HTTP_STATUS_INTERNAL_SERVER_ERROR = 500, + HTTP_STATUS_NOT_IMPLEMENTED, + HTTP_STATUS_BAD_GATEWAY, + HTTP_STATUS_SERVICE_UNAVAILABLE, + HTTP_STATUS_GATEWAY_TIMEOUT, + HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED, +}; + +struct libwebsocket; +struct libwebsocket_context; +/* needed even with extensions disabled for create context */ +struct libwebsocket_extension; + +/** + * callback_function() - User server actions + * @context: Websockets context + * @wsi: Opaque websocket instance pointer + * @reason: The reason for the call + * @user: Pointer to per-session user data allocated by library + * @in: Pointer used for some callback reasons + * @len: Length set for some callback reasons + * + * This callback is the way the user controls what is served. All the + * protocol detail is hidden and handled by the library. + * + * For each connection / session there is user data allocated that is + * pointed to by "user". You set the size of this user data area when + * the library is initialized with libwebsocket_create_server. + * + * You get an opportunity to initialize user data when called back with + * LWS_CALLBACK_ESTABLISHED reason. + * + * LWS_CALLBACK_ESTABLISHED: after the server completes a handshake with + * an incoming client + * + * LWS_CALLBACK_CLIENT_CONNECTION_ERROR: the request client connection has + * been unable to complete a handshake with the remote server + * + * LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH: this is the last chance for the + * client user code to examine the http headers + * and decide to reject the connection. If the + * content in the headers is interesting to the + * client (url, etc) it needs to copy it out at + * this point since it will be destroyed before + * the CLIENT_ESTABLISHED call + * + * LWS_CALLBACK_CLIENT_ESTABLISHED: after your client connection completed + * a handshake with the remote server + * + * LWS_CALLBACK_CLOSED: when the websocket session ends + * + * LWS_CALLBACK_CLOSED_HTTP: when a HTTP (non-websocket) session ends + * + * LWS_CALLBACK_RECEIVE: data has appeared for this server endpoint from a + * remote client, it can be found at *in and is + * len bytes long + * + * LWS_CALLBACK_CLIENT_RECEIVE_PONG: if you elected to see PONG packets, + * they appear with this callback reason. PONG + * packets only exist in 04+ protocol + * + * LWS_CALLBACK_CLIENT_RECEIVE: data has appeared from the server for the + * client connection, it can be found at *in and + * is len bytes long + * + * LWS_CALLBACK_HTTP: an http request has come from a client that is not + * asking to upgrade the connection to a websocket + * one. This is a chance to serve http content, + * for example, to send a script to the client + * which will then open the websockets connection. + * @in points to the URI path requested and + * libwebsockets_serve_http_file() makes it very + * simple to send back a file to the client. + * Normally after sending the file you are done + * with the http connection, since the rest of the + * activity will come by websockets from the script + * that was delivered by http, so you will want to + * return 1; to close and free up the connection. + * That's important because it uses a slot in the + * total number of client connections allowed set + * by MAX_CLIENTS. + * + * LWS_CALLBACK_HTTP_BODY: the next @len bytes data from the http + * request body HTTP connection is now available in @in. + * + * LWS_CALLBACK_HTTP_BODY_COMPLETION: the expected amount of http request + * body has been delivered + * + * LWS_CALLBACK_HTTP_WRITEABLE: you can write more down the http protocol + * link now. + * + * LWS_CALLBACK_HTTP_FILE_COMPLETION: a file requested to be send down + * http link has completed. + * + * LWS_CALLBACK_CLIENT_WRITEABLE: + * LWS_CALLBACK_SERVER_WRITEABLE: If you call + * libwebsocket_callback_on_writable() on a connection, you will + * get one of these callbacks coming when the connection socket + * is able to accept another write packet without blocking. + * If it already was able to take another packet without blocking, + * you'll get this callback at the next call to the service loop + * function. Notice that CLIENTs get LWS_CALLBACK_CLIENT_WRITEABLE + * and servers get LWS_CALLBACK_SERVER_WRITEABLE. + * + * LWS_CALLBACK_FILTER_NETWORK_CONNECTION: called when a client connects to + * the server at network level; the connection is accepted but then + * passed to this callback to decide whether to hang up immediately + * or not, based on the client IP. @in contains the connection + * socket's descriptor. Since the client connection information is + * not available yet, @wsi still pointing to the main server socket. + * Return non-zero to terminate the connection before sending or + * receiving anything. Because this happens immediately after the + * network connection from the client, there's no websocket protocol + * selected yet so this callback is issued only to protocol 0. + * + * LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED: A new client just had + * been connected, accepted, and instantiated into the pool. This + * callback allows setting any relevant property to it. Because this + * happens immediately after the instantiation of a new client, + * there's no websocket protocol selected yet so this callback is + * issued only to protocol 0. Only @wsi is defined, pointing to the + * new client, and the return value is ignored. + * + * LWS_CALLBACK_FILTER_HTTP_CONNECTION: called when the request has + * been received and parsed from the client, but the response is + * not sent yet. Return non-zero to disallow the connection. + * @user is a pointer to the connection user space allocation, + * @in is the URI, eg, "/" + * In your handler you can use the public APIs + * lws_hdr_total_length() / lws_hdr_copy() to access all of the + * headers using the header enums lws_token_indexes from + * libwebsockets.h to check for and read the supported header + * presence and content before deciding to allow the http + * connection to proceed or to kill the connection. + * + * LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: called when the handshake has + * been received and parsed from the client, but the response is + * not sent yet. Return non-zero to disallow the connection. + * @user is a pointer to the connection user space allocation, + * @in is the requested protocol name + * In your handler you can use the public APIs + * lws_hdr_total_length() / lws_hdr_copy() to access all of the + * headers using the header enums lws_token_indexes from + * libwebsockets.h to check for and read the supported header + * presence and content before deciding to allow the handshake + * to proceed or to kill the connection. + * + * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: if configured for + * including OpenSSL support, this callback allows your user code + * to perform extra SSL_CTX_load_verify_locations() or similar + * calls to direct OpenSSL where to find certificates the client + * can use to confirm the remote server identity. @user is the + * OpenSSL SSL_CTX* + * + * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: if configured for + * including OpenSSL support, this callback allows your user code + * to load extra certifcates into the server which allow it to + * verify the validity of certificates returned by clients. @user + * is the server's OpenSSL SSL_CTX* + * + * LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: if the + * libwebsockets context was created with the option + * LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT, then this + * callback is generated during OpenSSL verification of the cert + * sent from the client. It is sent to protocol[0] callback as + * no protocol has been negotiated on the connection yet. + * Notice that the libwebsockets context and wsi are both NULL + * during this callback. See + * http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html + * to understand more detail about the OpenSSL callback that + * generates this libwebsockets callback and the meanings of the + * arguments passed. In this callback, @user is the x509_ctx, + * @in is the ssl pointer and @len is preverify_ok + * Notice that this callback maintains libwebsocket return + * conventions, return 0 to mean the cert is OK or 1 to fail it. + * This also means that if you don't handle this callback then + * the default callback action of returning 0 allows the client + * certificates. + * + * LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: this callback happens + * when a client handshake is being compiled. @user is NULL, + * @in is a char **, it's pointing to a char * which holds the + * next location in the header buffer where you can add + * headers, and @len is the remaining space in the header buffer, + * which is typically some hundreds of bytes. So, to add a canned + * cookie, your handler code might look similar to: + * + * char **p = (char **)in; + * + * if (len < 100) + * return 1; + * + * *p += sprintf(*p, "Cookie: a=b\x0d\x0a"); + * + * return 0; + * + * Notice if you add anything, you just have to take care about + * the CRLF on the line you added. Obviously this callback is + * optional, if you don't handle it everything is fine. + * + * Notice the callback is coming to protocols[0] all the time, + * because there is no specific protocol handshook yet. + * + * LWS_CALLBACK_CONFIRM_EXTENSION_OKAY: When the server handshake code + * sees that it does support a requested extension, before + * accepting the extension by additing to the list sent back to + * the client it gives this callback just to check that it's okay + * to use that extension. It calls back to the requested protocol + * and with @in being the extension name, @len is 0 and @user is + * valid. Note though at this time the ESTABLISHED callback hasn't + * happened yet so if you initialize @user content there, @user + * content during this callback might not be useful for anything. + * Notice this callback comes to protocols[0]. + * + * LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: When a client + * connection is being prepared to start a handshake to a server, + * each supported extension is checked with protocols[0] callback + * with this reason, giving the user code a chance to suppress the + * claim to support that extension by returning non-zero. If + * unhandled, by default 0 will be returned and the extension + * support included in the header to the server. Notice this + * callback comes to protocols[0]. + * + * LWS_CALLBACK_PROTOCOL_INIT: One-time call per protocol so it can + * do initial setup / allocations etc + * + * LWS_CALLBACK_PROTOCOL_DESTROY: One-time call per protocol indicating + * this protocol won't get used at all after this callback, the + * context is getting destroyed. Take the opportunity to + * deallocate everything that was allocated by the protocol. + * + * LWS_CALLBACK_WSI_CREATE: outermost (earliest) wsi create notification + * + * LWS_CALLBACK_WSI_DESTROY: outermost (latest) wsi destroy notification + * + * The next five reasons are optional and only need taking care of if you + * will be integrating libwebsockets sockets into an external polling + * array. + * + * For these calls, @in points to a struct libwebsocket_pollargs that + * contains @fd, @events and @prev_events members + * + * LWS_CALLBACK_ADD_POLL_FD: libwebsocket deals with its poll() loop + * internally, but in the case you are integrating with another + * server you will need to have libwebsocket sockets share a + * polling array with the other server. This and the other + * POLL_FD related callbacks let you put your specialized + * poll array interface code in the callback for protocol 0, the + * first protocol you support, usually the HTTP protocol in the + * serving case. + * This callback happens when a socket needs to be + * added to the polling loop: @in points to a struct + * libwebsocket_pollargs; the @fd member of the struct is the file + * descriptor, and @events contains the active events. + * + * If you are using the internal polling loop (the "service" + * callback), you can just ignore these callbacks. + * + * LWS_CALLBACK_DEL_POLL_FD: This callback happens when a socket descriptor + * needs to be removed from an external polling array. @in is + * again the struct libwebsocket_pollargs containing the @fd member + * to be removed. If you are using the internal polling + * loop, you can just ignore it. + * + * LWS_CALLBACK_CHANGE_MODE_POLL_FD: This callback happens when + * libwebsockets wants to modify the events for a connectiion. + * @in is the struct libwebsocket_pollargs with the @fd to change. + * The new event mask is in @events member and the old mask is in + * the @prev_events member. + * If you are using the internal polling loop, you can just ignore + * it. + * + * LWS_CALLBACK_LOCK_POLL: + * LWS_CALLBACK_UNLOCK_POLL: These allow the external poll changes driven + * by libwebsockets to participate in an external thread locking + * scheme around the changes, so the whole thing is threadsafe. + */ +LWS_VISIBLE LWS_EXTERN int callback(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len); + +typedef int (callback_function)(struct libwebsocket_context *context, + struct libwebsocket *wsi, + enum libwebsocket_callback_reasons reason, void *user, + void *in, size_t len); + +#ifndef LWS_NO_EXTENSIONS +/** + * extension_callback_function() - Hooks to allow extensions to operate + * @context: Websockets context + * @ext: This extension + * @wsi: Opaque websocket instance pointer + * @reason: The reason for the call + * @user: Pointer to per-session user data allocated by library + * @in: Pointer used for some callback reasons + * @len: Length set for some callback reasons + * + * Each extension that is active on a particular connection receives + * callbacks during the connection lifetime to allow the extension to + * operate on websocket data and manage itself. + * + * Libwebsockets takes care of allocating and freeing "user" memory for + * each active extension on each connection. That is what is pointed to + * by the @user parameter. + * + * LWS_EXT_CALLBACK_CONSTRUCT: called when the server has decided to + * select this extension from the list provided by the client, + * just before the server will send back the handshake accepting + * the connection with this extension active. This gives the + * extension a chance to initialize its connection context found + * in @user. + * + * LWS_EXT_CALLBACK_CLIENT_CONSTRUCT: same as LWS_EXT_CALLBACK_CONSTRUCT + * but called when client is instantiating this extension. Some + * extensions will work the same on client and server side and then + * you can just merge handlers for both CONSTRUCTS. + * + * LWS_EXT_CALLBACK_DESTROY: called when the connection the extension was + * being used on is about to be closed and deallocated. It's the + * last chance for the extension to deallocate anything it has + * allocated in the user data (pointed to by @user) before the + * user data is deleted. This same callback is used whether you + * are in client or server instantiation context. + * + * LWS_EXT_CALLBACK_PACKET_RX_PREPARSE: when this extension was active on + * a connection, and a packet of data arrived at the connection, + * it is passed to this callback to give the extension a chance to + * change the data, eg, decompress it. @user is pointing to the + * extension's private connection context data, @in is pointing + * to an lws_tokens struct, it consists of a char * pointer called + * token, and an int called token_len. At entry, these are + * set to point to the received buffer and set to the content + * length. If the extension will grow the content, it should use + * a new buffer allocated in its private user context data and + * set the pointed-to lws_tokens members to point to its buffer. + * + * LWS_EXT_CALLBACK_PACKET_TX_PRESEND: this works the same way as + * LWS_EXT_CALLBACK_PACKET_RX_PREPARSE above, except it gives the + * extension a chance to change websocket data just before it will + * be sent out. Using the same lws_token pointer scheme in @in, + * the extension can change the buffer and the length to be + * transmitted how it likes. Again if it wants to grow the + * buffer safely, it should copy the data into its own buffer and + * set the lws_tokens token pointer to it. + */ +LWS_VISIBLE LWS_EXTERN int extension_callback(struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); + +typedef int (extension_callback_function)(struct libwebsocket_context *context, + struct libwebsocket_extension *ext, + struct libwebsocket *wsi, + enum libwebsocket_extension_callback_reasons reason, + void *user, void *in, size_t len); +#endif + +/** + * struct libwebsocket_protocols - List of protocols and handlers server + * supports. + * @name: Protocol name that must match the one given in the client + * Javascript new WebSocket(url, 'protocol') name + * @callback: The service callback used for this protocol. It allows the + * service action for an entire protocol to be encapsulated in + * the protocol-specific callback + * @per_session_data_size: Each new connection using this protocol gets + * this much memory allocated on connection establishment and + * freed on connection takedown. A pointer to this per-connection + * allocation is passed into the callback in the 'user' parameter + * @rx_buffer_size: if you want atomic frames delivered to the callback, you + * should set this to the size of the biggest legal frame that + * you support. If the frame size is exceeded, there is no + * error, but the buffer will spill to the user callback when + * full, which you can detect by using + * libwebsockets_remaining_packet_payload(). Notice that you + * just talk about frame size here, the LWS_SEND_BUFFER_PRE_PADDING + * and post-padding are automatically also allocated on top. + * @no_buffer_all_partial_tx: Leave at zero if you want the library to take + * care of all partial tx for you. It's useful if you only have + * small tx packets and the chance of any truncated send is small + * enough any additional malloc / buffering overhead is less + * painful than writing the code to deal with partial sends. For + * protocols where you stream big blocks, set to nonzero and use + * the return value from libwebsocket_write() to manage how much + * got send yourself. + * @owning_server: the server init call fills in this opaque pointer when + * registering this protocol with the server. + * @protocol_index: which protocol we are starting from zero + * + * This structure represents one protocol supported by the server. An + * array of these structures is passed to libwebsocket_create_server() + * allows as many protocols as you like to be handled by one server. + */ + +struct libwebsocket_protocols { + const char *name; + callback_function *callback; + size_t per_session_data_size; + size_t rx_buffer_size; + int no_buffer_all_partial_tx; + + /* + * below are filled in on server init and can be left uninitialized, + * no need for user to use them directly either + */ + + struct libwebsocket_context *owning_server; + int protocol_index; +}; + +#ifndef LWS_NO_EXTENSIONS +/** + * struct libwebsocket_extension - An extension we know how to cope with + * + * @name: Formal extension name, eg, "deflate-stream" + * @callback: Service callback + * @per_session_data_size: Libwebsockets will auto-malloc this much + * memory for the use of the extension, a pointer + * to it comes in the @user callback parameter + * @per_context_private_data: Optional storage for this extension that + * is per-context, so it can track stuff across + * all sessions, etc, if it wants + */ + +struct libwebsocket_extension { + const char *name; + extension_callback_function *callback; + size_t per_session_data_size; + void *per_context_private_data; +}; +#endif + +/** + * struct lws_context_creation_info: parameters to create context with + * + * @port: Port to listen on... you can use 0 to suppress listening on + * any port, that's what you want if you are not running a + * websocket server at all but just using it as a client + * @iface: NULL to bind the listen socket to all interfaces, or the + * interface name, eg, "eth2" + * @protocols: Array of structures listing supported protocols and a protocol- + * specific callback for each one. The list is ended with an + * entry that has a NULL callback pointer. + * It's not const because we write the owning_server member + * @extensions: NULL or array of libwebsocket_extension structs listing the + * extensions this context supports. If you configured with + * --without-extensions, you should give NULL here. + * @token_limits: NULL or struct lws_token_limits pointer which is initialized + * with a token length limit for each possible WSI_TOKEN_*** + * @ssl_cert_filepath: If libwebsockets was compiled to use ssl, and you want + * to listen using SSL, set to the filepath to fetch the + * server cert from, otherwise NULL for unencrypted + * @ssl_private_key_filepath: filepath to private key if wanting SSL mode, + * else ignored + * @ssl_ca_filepath: CA certificate filepath or NULL + * @ssl_cipher_list: List of valid ciphers to use (eg, + * "RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL" + * or you can leave it as NULL to get "DEFAULT" + * @gid: group id to change to after setting listen socket, or -1. + * @uid: user id to change to after setting listen socket, or -1. + * @options: 0, or LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK + * @user: optional user pointer that can be recovered via the context + * pointer using libwebsocket_context_user + * @ka_time: 0 for no keepalive, otherwise apply this keepalive timeout to + * all libwebsocket sockets, client or server + * @ka_probes: if ka_time was nonzero, after the timeout expires how many + * times to try to get a response from the peer before giving up + * and killing the connection + * @ka_interval: if ka_time was nonzero, how long to wait before each ka_probes + * attempt + */ + +struct lws_context_creation_info { + int port; + const char *iface; + struct libwebsocket_protocols *protocols; + struct libwebsocket_extension *extensions; + struct lws_token_limits *token_limits; + const char *ssl_cert_filepath; + const char *ssl_private_key_filepath; + const char *ssl_ca_filepath; + const char *ssl_cipher_list; + const char *http_proxy_address; + unsigned int http_proxy_port; + int gid; + int uid; + unsigned int options; + void *user; + int ka_time; + int ka_probes; + int ka_interval; + +}; + +LWS_VISIBLE LWS_EXTERN +void lws_set_log_level(int level, + void (*log_emit_function)(int level, const char *line)); + +LWS_VISIBLE LWS_EXTERN void +lwsl_emit_syslog(int level, const char *line); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket_context * +libwebsocket_create_context(struct lws_context_creation_info *info); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_set_proxy(struct libwebsocket_context *context, const char *proxy); + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_context_destroy(struct libwebsocket_context *context); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_service(struct libwebsocket_context *context, int timeout_ms); + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_cancel_service(struct libwebsocket_context *context); + +#ifdef LWS_USE_LIBEV +LWS_VISIBLE LWS_EXTERN int +libwebsocket_initloop( + struct libwebsocket_context *context, struct ev_loop *loop); + +LWS_VISIBLE void +libwebsocket_sigint_cb( + struct ev_loop *loop, struct ev_signal *watcher, int revents); +#endif /* LWS_USE_LIBEV */ + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_service_fd(struct libwebsocket_context *context, + struct libwebsocket_pollfd *pollfd); + +LWS_VISIBLE LWS_EXTERN void * +libwebsocket_context_user(struct libwebsocket_context *context); + +enum pending_timeout { + NO_PENDING_TIMEOUT = 0, + PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE, + PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE, + PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, + PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE, + PENDING_TIMEOUT_AWAITING_PING, + PENDING_TIMEOUT_CLOSE_ACK, + PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE, + PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE, + PENDING_TIMEOUT_SSL_ACCEPT, + PENDING_TIMEOUT_HTTP_CONTENT, + PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND, +}; + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_set_timeout(struct libwebsocket *wsi, + enum pending_timeout reason, int secs); + +/* + * IMPORTANT NOTICE! + * + * When sending with websocket protocol (LWS_WRITE_TEXT or LWS_WRITE_BINARY) + * the send buffer has to have LWS_SEND_BUFFER_PRE_PADDING bytes valid BEFORE + * buf, and LWS_SEND_BUFFER_POST_PADDING bytes valid AFTER (buf + len). + * + * This allows us to add protocol info before and after the data, and send as + * one packet on the network without payload copying, for maximum efficiency. + * + * So for example you need this kind of code to use libwebsocket_write with a + * 128-byte payload + * + * char buf[LWS_SEND_BUFFER_PRE_PADDING + 128 + LWS_SEND_BUFFER_POST_PADDING]; + * + * // fill your part of the buffer... for example here it's all zeros + * memset(&buf[LWS_SEND_BUFFER_PRE_PADDING], 0, 128); + * + * libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], 128, + * LWS_WRITE_TEXT); + * + * When sending LWS_WRITE_HTTP, there is no protocol addition and you can just + * use the whole buffer without taking care of the above. + */ + +/* + * this is the frame nonce plus two header plus 8 length + * there's an additional two for mux extension per mux nesting level + * 2 byte prepend on close will already fit because control frames cannot use + * the big length style + */ + +#define LWS_SEND_BUFFER_PRE_PADDING (4 + 10 + (2 * MAX_MUX_RECURSION)) +#define LWS_SEND_BUFFER_POST_PADDING 4 + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, size_t len, + enum libwebsocket_write_protocol protocol); + +/* helper for case where buffer may be const */ +#define libwebsocket_write_http(wsi, buf, len) \ + libwebsocket_write(wsi, (unsigned char *)(buf), len, LWS_WRITE_HTTP) + +LWS_VISIBLE LWS_EXTERN int +libwebsockets_serve_http_file(struct libwebsocket_context *context, + struct libwebsocket *wsi, const char *file, + const char *content_type, const char *other_headers); +LWS_VISIBLE LWS_EXTERN int +libwebsockets_serve_http_file_fragment(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int libwebsockets_return_http_status( + struct libwebsocket_context *context, + struct libwebsocket *wsi, unsigned int code, + const char *html_body); + +LWS_VISIBLE LWS_EXTERN const struct libwebsocket_protocols * +libwebsockets_get_protocol(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_callback_on_writable(struct libwebsocket_context *context, + struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_callback_on_writable_all_protocol( + const struct libwebsocket_protocols *protocol); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_callback_all_protocol( + const struct libwebsocket_protocols *protocol, int reason); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_get_socket_fd(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_is_final_fragment(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN unsigned char +libwebsocket_get_reserved_bits(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable); + +LWS_VISIBLE LWS_EXTERN void +libwebsocket_rx_flow_allow_all_protocol( + const struct libwebsocket_protocols *protocol); + +LWS_VISIBLE LWS_EXTERN size_t +libwebsockets_remaining_packet_payload(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket * +libwebsocket_client_connect(struct libwebsocket_context *clients, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one); + +LWS_VISIBLE LWS_EXTERN struct libwebsocket * +libwebsocket_client_connect_extended(struct libwebsocket_context *clients, + const char *address, + int port, + int ssl_connection, + const char *path, + const char *host, + const char *origin, + const char *protocol, + int ietf_version_or_minus_one, + void *userdata); + +LWS_VISIBLE LWS_EXTERN const char * +libwebsocket_canonical_hostname(struct libwebsocket_context *context); + + +LWS_VISIBLE LWS_EXTERN void +libwebsockets_get_peer_addresses(struct libwebsocket_context *context, + struct libwebsocket *wsi, int fd, char *name, int name_len, + char *rip, int rip_len); + +LWS_VISIBLE LWS_EXTERN int +libwebsockets_get_random(struct libwebsocket_context *context, + void *buf, int len); + +LWS_VISIBLE LWS_EXTERN int +lws_daemonize(const char *_lock_path); + +LWS_VISIBLE LWS_EXTERN int +lws_send_pipe_choked(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN int +lws_frame_is_binary(struct libwebsocket *wsi); + +LWS_VISIBLE LWS_EXTERN unsigned char * +libwebsockets_SHA1(const unsigned char *d, size_t n, unsigned char *md); + +LWS_VISIBLE LWS_EXTERN int +lws_b64_encode_string(const char *in, int in_len, char *out, int out_size); + +LWS_VISIBLE LWS_EXTERN int +lws_b64_decode_string(const char *in, char *out, int out_size); + +LWS_VISIBLE LWS_EXTERN const char * +lws_get_library_version(void); + +/* access to headers... only valid while headers valid */ + +LWS_VISIBLE LWS_EXTERN int +lws_hdr_total_length(struct libwebsocket *wsi, enum lws_token_indexes h); + +LWS_VISIBLE LWS_EXTERN int +lws_hdr_copy(struct libwebsocket *wsi, char *dest, int len, + enum lws_token_indexes h); + +/* + * Note: this is not normally needed as a user api. It's provided in case it is + * useful when integrating with other app poll loop service code. + */ + +LWS_VISIBLE LWS_EXTERN int +libwebsocket_read(struct libwebsocket_context *context, + struct libwebsocket *wsi, + unsigned char *buf, size_t len); + +#ifndef LWS_NO_EXTENSIONS +LWS_VISIBLE LWS_EXTERN struct libwebsocket_extension *libwebsocket_get_internal_extensions(); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/android/dist/x86/lib/cmake/libwebsockets/LibwebsocketsTargets-noconfig.cmake b/android/dist/x86/lib/cmake/libwebsockets/LibwebsocketsTargets-noconfig.cmake new file mode 100644 index 0000000000..8d425bd1fb --- /dev/null +++ b/android/dist/x86/lib/cmake/libwebsockets/LibwebsocketsTargets-noconfig.cmake @@ -0,0 +1,31 @@ +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "websockets" for configuration "" +set_property(TARGET websockets APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG) +set_target_properties(websockets PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_NOCONFIG "C" + IMPORTED_LINK_INTERFACE_LIBRARIES_NOCONFIG "/opt/android-ndk-r10e/platforms/android-9/arch-x86/usr/lib/libz.so;m" + IMPORTED_LOCATION_NOCONFIG "${_IMPORT_PREFIX}/lib/libwebsockets.a" + ) + +list(APPEND _IMPORT_CHECK_TARGETS websockets ) +list(APPEND _IMPORT_CHECK_FILES_FOR_websockets "${_IMPORT_PREFIX}/lib/libwebsockets.a" ) + +# Import target "websockets_shared" for configuration "" +set_property(TARGET websockets_shared APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG) +set_target_properties(websockets_shared PROPERTIES + IMPORTED_LINK_INTERFACE_LIBRARIES_NOCONFIG "/opt/android-ndk-r10e/platforms/android-9/arch-x86/usr/lib/libz.so;m" + IMPORTED_LOCATION_NOCONFIG "${_IMPORT_PREFIX}/lib/libwebsockets.so.4.0.0" + IMPORTED_SONAME_NOCONFIG "libwebsockets.so.4.0.0" + ) + +list(APPEND _IMPORT_CHECK_TARGETS websockets_shared ) +list(APPEND _IMPORT_CHECK_FILES_FOR_websockets_shared "${_IMPORT_PREFIX}/lib/libwebsockets.so.4.0.0" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/android/dist/x86/lib/cmake/libwebsockets/LibwebsocketsTargets.cmake b/android/dist/x86/lib/cmake/libwebsockets/LibwebsocketsTargets.cmake new file mode 100644 index 0000000000..848b03ccc2 --- /dev/null +++ b/android/dist/x86/lib/cmake/libwebsockets/LibwebsocketsTargets.cmake @@ -0,0 +1,93 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5) + message(FATAL_ERROR "CMake >= 2.6.0 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 2.6) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_targetsDefined) +set(_targetsNotDefined) +set(_expectedTargets) +foreach(_expectedTarget websockets websockets_shared) + list(APPEND _expectedTargets ${_expectedTarget}) + if(NOT TARGET ${_expectedTarget}) + list(APPEND _targetsNotDefined ${_expectedTarget}) + endif() + if(TARGET ${_expectedTarget}) + list(APPEND _targetsDefined ${_expectedTarget}) + endif() +endforeach() +if("${_targetsDefined}" STREQUAL "${_expectedTargets}") + unset(_targetsDefined) + unset(_targetsNotDefined) + unset(_expectedTargets) + set(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT "${_targetsDefined}" STREQUAL "") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n") +endif() +unset(_targetsDefined) +unset(_targetsNotDefined) +unset(_expectedTargets) + + +# Compute the installation prefix relative to this file. +get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +if(_IMPORT_PREFIX STREQUAL "/") + set(_IMPORT_PREFIX "") +endif() + +# Create imported target websockets +add_library(websockets STATIC IMPORTED) + +# Create imported target websockets_shared +add_library(websockets_shared SHARED IMPORTED) + +# Load information for each installed configuration. +get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +file(GLOB CONFIG_FILES "${_DIR}/LibwebsocketsTargets-*.cmake") +foreach(f ${CONFIG_FILES}) + include(${f}) +endforeach() + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(target ${_IMPORT_CHECK_TARGETS} ) + foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} ) + if(NOT EXISTS "${file}" ) + message(FATAL_ERROR "The imported target \"${target}\" references the file + \"${file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() + endforeach() + unset(_IMPORT_CHECK_FILES_FOR_${target}) +endforeach() +unset(_IMPORT_CHECK_TARGETS) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/android/dist/x86/lib/libwebsockets.a b/android/dist/x86/lib/libwebsockets.a new file mode 100644 index 0000000000..737b4f64b6 Binary files /dev/null and b/android/dist/x86/lib/libwebsockets.a differ diff --git a/android/dist/x86/lib/libwebsockets.so b/android/dist/x86/lib/libwebsockets.so new file mode 100644 index 0000000000..43ee4795e6 Binary files /dev/null and b/android/dist/x86/lib/libwebsockets.so differ diff --git a/android/dist/x86/lib/libwebsockets.so.4.0.0 b/android/dist/x86/lib/libwebsockets.so.4.0.0 new file mode 100644 index 0000000000..43ee4795e6 Binary files /dev/null and b/android/dist/x86/lib/libwebsockets.so.4.0.0 differ diff --git a/android/scripts/cmake_android_armeabi.sh b/android/scripts/cmake_android_armeabi.sh index 0f47ef2978..4f09d07ae3 100755 --- a/android/scripts/cmake_android_armeabi.sh +++ b/android/scripts/cmake_android_armeabi.sh @@ -22,6 +22,14 @@ cmake -DANDROID_ABI=armeabi-v7a -DCMAKE_TOOLCHAIN_FILE=../android.toolchain.cmak make make install +cd ../ +mkdir -p build_arm64-v8a +cd build_arm64-v8a + +cmake -DANDROID_ABI=arm64-v8a -DCMAKE_TOOLCHAIN_FILE=../android.toolchain.cmake -DLWS_WITH_SSL=OFF -DLWS_WITHOUT_SERVER=ON -DLWS_WITHOUT_TESTAPPS=ON -DCMAKE_INSTALL_PREFIX:PATH=$OUTPUT/dist/armv8a $@ ../.. +make +make install + cd ../ mkdir -p build_x86 cd build_x86 @@ -30,5 +38,5 @@ cmake -DANDROID_ABI=x86 -DCMAKE_TOOLCHAIN_FILE=../android.toolchain.cmake -DLWS_ make make install -# cmake -DANDROID_ABI=armeabi -DCMAKE_TOOLCHAIN_FILE=../scripts/toolchain-android-ndk-r8e.cmake $@ ../.. +# cmake -DANDROID_ABI=armeabi -DCMAKE_TOOLCHAIN_FILE=../scripts/toolchain-android-ndk-r8e.cmake $@ ../.. \ No newline at end of file diff --git a/lib/base64-decode.c b/lib/base64-decode.c index 92501b0327..b89db7ac30 100644 --- a/lib/base64-decode.c +++ b/lib/base64-decode.c @@ -67,6 +67,8 @@ lws_b64_encode_string(const char *in, int in_len, char *out, int out_size) } else triple[i] = 0; } + if (!len) + continue; if (done + 4 >= out_size) return -1; @@ -89,97 +91,3 @@ lws_b64_encode_string(const char *in, int in_len, char *out, int out_size) return done; } - -/* - * returns length of decoded string in out, or -1 if out was too small - * according to out_size - */ - -LWS_VISIBLE int -lws_b64_decode_string(const char *in, char *out, int out_size) -{ - int len; - int i; - int done = 0; - unsigned char v; - unsigned char quad[4]; - - while (*in) { - - len = 0; - for (i = 0; i < 4 && *in; i++) { - - v = 0; - while (*in && !v) { - - v = *in++; - v = (v < 43 || v > 122) ? 0 : decode[v - 43]; - if (v) - v = (v == '$') ? 0 : v - 61; - if (*in) { - len++; - if (v) - quad[i] = v - 1; - } else - quad[i] = 0; - } - } - - if (out_size < (done + len - 1)) - /* out buffer is too small */ - return -1; - - if (len >= 2) - *out++ = quad[0] << 2 | quad[1] >> 4; - if (len >= 3) - *out++ = quad[1] << 4 | quad[2] >> 2; - if (len >= 4) - *out++ = ((quad[2] << 6) & 0xc0) | quad[3]; - - done += len - 1; - } - - if (done + 1 >= out_size) - return -1; - - *out++ = '\0'; - - return done; -} - -int -lws_b64_selftest(void) -{ - char buf[64]; - int n; - int test; - static const char * const plaintext[] = { - "sanity check base 64" - }; - static const char * const coded[] = { - "c2FuaXR5IGNoZWNrIGJhc2UgNjQ=" - }; - - for (test = 0; test < sizeof plaintext / sizeof(plaintext[0]); test++) { - - buf[sizeof(buf) - 1] = '\0'; - n = lws_b64_encode_string(plaintext[test], - strlen(plaintext[test]), buf, sizeof buf); - if (n != strlen(coded[test]) || strcmp(buf, coded[test])) { - lwsl_err("Failed lws_b64 encode selftest " - "%d result '%s' %d\n", test, buf, n); - return -1; - } - - buf[sizeof(buf) - 1] = '\0'; - n = lws_b64_decode_string(coded[test], buf, sizeof buf); - if (n != strlen(plaintext[test]) || - strcmp(buf, plaintext[test])) { - lwsl_err("Failed lws_b64 decode selftest " - "%d result '%s' %d\n", test, buf, n); - return -1; - } - } - - return 0; -} diff --git a/lib/client-handshake.c b/lib/client-handshake.c index 40916d6bc4..e25c368cf3 100644 --- a/lib/client-handshake.c +++ b/lib/client-handshake.c @@ -12,6 +12,7 @@ struct libwebsocket *libwebsocket_client_connect_2( #endif struct sockaddr_in server_addr4; struct sockaddr_in client_addr4; + struct hostent *server_hostent; struct sockaddr *v; int n; @@ -96,32 +97,15 @@ struct libwebsocket *libwebsocket_client_connect_2( } else #endif { - struct addrinfo ai, *res; - void *p = NULL; - - memset (&ai, 0, sizeof ai); - ai.ai_family = PF_UNSPEC; - ai.ai_socktype = SOCK_STREAM; - ai.ai_flags = AI_CANONNAME; - - if (getaddrinfo(ads, NULL, &ai, &res)) + server_hostent = gethostbyname(ads); + if (!server_hostent) { + lwsl_err("Unable to get host name from %s\n", ads); goto oom4; - - while (!p && res) { - switch (res->ai_family) { - case AF_INET: - p = &((struct sockaddr_in *)res->ai_addr)->sin_addr; - break; - } - - res = res->ai_next; } - - if (!p) - goto oom4; server_addr4.sin_family = AF_INET; - server_addr4.sin_addr = *((struct in_addr *)p); + server_addr4.sin_addr = + *((struct in_addr *)server_hostent->h_addr); bzero(&server_addr4.sin_zero, 8); } @@ -278,8 +262,8 @@ struct libwebsocket *libwebsocket_client_connect_2( return wsi; oom4: - lws_free(wsi->u.hdr.ah); - lws_free(wsi); + free(wsi->u.hdr.ah); + free(wsi); return NULL; failed: @@ -300,8 +284,7 @@ struct libwebsocket *libwebsocket_client_connect_2( * @origin: Socket origin name * @protocol: Comma-separated list of protocols being asked for from * the server, or just one. The server will pick the one it - * likes best. If you don't want to specify a protocol, which is - * legal, use NULL here. + * likes best. * @ietf_version_or_minus_one: -1 to ask to connect using the default, latest * protocol supported, or the specific protocol ordinal * @@ -321,10 +304,11 @@ libwebsocket_client_connect(struct libwebsocket_context *context, { struct libwebsocket *wsi; - wsi = lws_zalloc(sizeof(struct libwebsocket)); + wsi = (struct libwebsocket *) malloc(sizeof(struct libwebsocket)); if (wsi == NULL) goto bail; + memset(wsi, 0, sizeof(*wsi)); wsi->sock = -1; /* -1 means just use latest supported */ @@ -405,9 +389,9 @@ libwebsocket_client_connect(struct libwebsocket_context *context, return libwebsocket_client_connect_2(context, wsi); bail1: - lws_free(wsi->u.hdr.ah); + free(wsi->u.hdr.ah); bail: - lws_free(wsi); + free(wsi); return NULL; } diff --git a/lib/client-parser.c b/lib/client-parser.c index 30fc47d039..d7b97cc3ed 100644 --- a/lib/client-parser.c +++ b/lib/client-parser.c @@ -214,10 +214,8 @@ int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c) case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED: - if (!wsi->u.ws.rx_user_buffer) { + if (!wsi->u.ws.rx_user_buffer) lwsl_err("NULL client rx_user_buffer\n"); - return 1; - } if ((!wsi->u.ws.this_frame_masked) || wsi->u.ws.all_zero_nonce) wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING + @@ -286,49 +284,17 @@ int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c) return -1; case LWS_WS_OPCODE_07__PING: - lwsl_info("received %d byte ping, sending pong\n", - wsi->u.ws.rx_user_buffer_head); - - if (wsi->u.ws.ping_pending_flag) { - /* - * there is already a pending ping payload - * we should just log and drop - */ - lwsl_parser("DROP PING since one pending\n"); - goto ping_drop; - } - - /* control packets can only be < 128 bytes long */ - if (wsi->u.ws.rx_user_buffer_head > 128 - 4) { - lwsl_parser("DROP PING payload too large\n"); - goto ping_drop; - } - - /* if existing buffer is too small, drop it */ - if (wsi->u.ws.ping_payload_buf && - wsi->u.ws.ping_payload_alloc < wsi->u.ws.rx_user_buffer_head) - lws_free2(wsi->u.ws.ping_payload_buf); - - /* if no buffer, allocate it */ - if (!wsi->u.ws.ping_payload_buf) { - wsi->u.ws.ping_payload_buf = lws_malloc(wsi->u.ws.rx_user_buffer_head - + LWS_SEND_BUFFER_PRE_PADDING); - wsi->u.ws.ping_payload_alloc = - wsi->u.ws.rx_user_buffer_head; - } - - /* stash the pong payload */ - memcpy(wsi->u.ws.ping_payload_buf + LWS_SEND_BUFFER_PRE_PADDING, - &wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING], - wsi->u.ws.rx_user_buffer_head); - - wsi->u.ws.ping_payload_len = wsi->u.ws.rx_user_buffer_head; - wsi->u.ws.ping_pending_flag = 1; - - /* get it sent as soon as possible */ - libwebsocket_callback_on_writable(wsi->protocol->owning_server, wsi); -ping_drop: - wsi->u.ws.rx_user_buffer_head = 0; + lwsl_info("client received ping, doing pong\n"); + /* + * parrot the ping packet payload back as a pong + * !!! this may block or have partial write or fail + * !!! very unlikely if the ping size is small + */ + libwebsocket_write(wsi, (unsigned char *) + &wsi->u.ws.rx_user_buffer[ + LWS_SEND_BUFFER_PRE_PADDING], + wsi->u.ws.rx_user_buffer_head, + LWS_WRITE_PONG); handled = 1; break; diff --git a/lib/client.c b/lib/client.c index c9cd156a5a..2b9a943cc4 100644 --- a/lib/client.c +++ b/lib/client.c @@ -309,18 +309,15 @@ int lws_client_socket_service(struct libwebsocket_context *context, lws_latency(context, wsi, "SSL_get_verify_result LWS_CONNMODE..HANDSHAKE", n, n > 0); - - if (n != X509_V_OK) { - if ((n == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || - n == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) && wsi->use_ssl == 2) { - lwsl_notice("accepting self-signed certificate\n"); - } else { - lwsl_err("server's cert didn't look good, X509_V_ERR = %d: %s\n", - n, ERR_error_string(n, (char *)context->service_buffer)); - libwebsocket_close_and_free_session(context, - wsi, LWS_CLOSE_STATUS_NOSTATUS); - return 0; - } + if ((n != X509_V_OK) && ( + n != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || + wsi->use_ssl != 2)) { + + lwsl_err( + "server's cert didn't look good %d\n", n); + libwebsocket_close_and_free_session(context, + wsi, LWS_CLOSE_STATUS_NOSTATUS); + return 0; } #endif /* USE_CYASSL */ } else @@ -405,7 +402,7 @@ int lws_client_socket_service(struct libwebsocket_context *context, len = 1; while (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE && len > 0) { - n = lws_ssl_capable_read(context, wsi, &c, 1); + n = lws_ssl_capable_read(wsi, &c, 1); lws_latency(context, wsi, "send lws_issue_raw", n, n == 1); switch (n) { case LWS_SSL_CAPABLE_ERROR: @@ -560,15 +557,15 @@ lws_client_interpret_server_handshake(struct libwebsocket_context *context, p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL); len = strlen(p); - while (pc && *pc && !okay) { + while (*pc && !okay) { if (!strncmp(pc, p, len) && - (pc[len] == ',' || pc[len] == '\0')) { + (pc[len] == ',' || pc[len] == '\0')) { okay = 1; continue; } - while (*pc && *pc++ != ',') - ; - while (*pc && *pc == ' ') + while (*pc && *pc != ',') + pc++; + while (*pc && *pc != ' ') pc++; } @@ -656,12 +653,15 @@ lws_client_interpret_server_handshake(struct libwebsocket_context *context, wsi->active_extensions_user[ wsi->count_active_extensions] = - lws_zalloc(ext->per_session_data_size); + malloc(ext->per_session_data_size); if (wsi->active_extensions_user[ wsi->count_active_extensions] == NULL) { lwsl_err("Out of mem\n"); goto bail2; } + memset(wsi->active_extensions_user[ + wsi->count_active_extensions], 0, + ext->per_session_data_size); wsi->active_extensions[ wsi->count_active_extensions] = ext; @@ -721,13 +721,19 @@ lws_client_interpret_server_handshake(struct libwebsocket_context *context, libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); /* free up his parsing allocations */ + if (wsi->u.hdr.ah) + free(wsi->u.hdr.ah); - lws_free(wsi->u.hdr.ah); + /* mark him as being alive */ - lws_union_transition(wsi, LWS_CONNMODE_WS_CLIENT); wsi->state = WSI_STATE_ESTABLISHED; + wsi->mode = LWS_CONNMODE_WS_CLIENT; + + /* union transition */ + + memset(&wsi->u, 0, sizeof(wsi->u)); - wsi->rxflow_change_to = LWS_RXFLOW_ALLOW; + wsi->u.ws.rxflow_change_to = LWS_RXFLOW_ALLOW; /* * create the frame buffer for this connection according to the @@ -739,7 +745,7 @@ lws_client_interpret_server_handshake(struct libwebsocket_context *context, if (!n) n = LWS_MAX_SOCKET_IO_BUF; n += LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING; - wsi->u.ws.rx_user_buffer = lws_malloc(n); + wsi->u.ws.rx_user_buffer = malloc(n); if (!wsi->u.ws.rx_user_buffer) { lwsl_err("Out of Mem allocating rx buffer %d\n", n); goto bail2; @@ -781,7 +787,8 @@ lws_client_interpret_server_handshake(struct libwebsocket_context *context, return 0; bail3: - lws_free2(wsi->u.ws.rx_user_buffer); + free(wsi->u.ws.rx_user_buffer); + wsi->u.ws.rx_user_buffer = NULL; close_reason = LWS_CLOSE_STATUS_NOSTATUS; bail2: @@ -794,7 +801,8 @@ lws_client_interpret_server_handshake(struct libwebsocket_context *context, /* free up his parsing allocations */ - lws_free2(wsi->u.hdr.ah); + if (wsi->u.hdr.ah) + free(wsi->u.hdr.ah); libwebsocket_close_and_free_session(context, wsi, close_reason); @@ -939,7 +947,7 @@ libwebsockets_generate_client_handshake(struct libwebsocket_context *context, key_b64[39] = '\0'; /* enforce composed length below buf sizeof */ n = sprintf(buf, "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", key_b64); - libwebsockets_SHA1((unsigned char *)buf, n, (unsigned char *)hash); + SHA1((unsigned char *)buf, n, (unsigned char *)hash); lws_b64_encode_string(hash, 20, wsi->u.hdr.ah->initial_handshake_hash_base64, diff --git a/lib/context.c b/lib/context.c index 23f0575cd6..a699d96b93 100755 --- a/lib/context.c +++ b/lib/context.c @@ -76,9 +76,7 @@ libwebsocket_create_context(struct lws_context_creation_info *info) { struct libwebsocket_context *context = NULL; char *p; -#ifdef _WIN32 - int i; -#endif + int pid_daemon = get_daemonize_pid(); lwsl_notice("Initial logging level %d\n", log_level); @@ -103,11 +101,13 @@ libwebsocket_create_context(struct lws_context_creation_info *info) if (lws_plat_context_early_init()) return NULL; - context = lws_zalloc(sizeof(struct libwebsocket_context)); + context = (struct libwebsocket_context *) + malloc(sizeof(struct libwebsocket_context)); if (!context) { lwsl_err("No memory for websocket context\n"); return NULL; } + memset(context, 0, sizeof(*context)); if (pid_daemon) { context->started_with_parent = pid_daemon; @@ -122,12 +122,13 @@ libwebsocket_create_context(struct lws_context_creation_info *info) context->http_proxy_address[0] = '\0'; context->options = info->options; context->iface = info->iface; - context->ka_time = info->ka_time; - context->ka_interval = info->ka_interval; - context->ka_probes = info->ka_probes; - /* to reduce this allocation, */ - context->max_fds = getdtablesize(); + //context->max_fds = getdtablesize(); + context->max_fds = OPEN_MAX; + struct rlimit rl; + if (getrlimit(RLIMIT_NOFILE, &rl) != -1) { + context->max_fds = rl.rlim_cur; + } lwsl_notice(" static allocation: %u + (%u x %u fds) = %u bytes\n", sizeof(struct libwebsocket_context), sizeof(struct libwebsocket_pollfd) + @@ -138,41 +139,33 @@ libwebsocket_create_context(struct lws_context_creation_info *info) sizeof(struct libwebsocket *)) * context->max_fds)); - context->fds = lws_zalloc(sizeof(struct libwebsocket_pollfd) * - context->max_fds); + context->fds = (struct libwebsocket_pollfd *) + malloc(sizeof(struct libwebsocket_pollfd) * + context->max_fds); if (context->fds == NULL) { lwsl_err("Unable to allocate fds array for %d connections\n", context->max_fds); - lws_free(context); + free(context); return NULL; } -#ifdef _WIN32 - for (i = 0; i < FD_HASHTABLE_MODULUS; i++) { - context->fd_hashtable[i].wsi = lws_zalloc(sizeof(struct libwebsocket*) * context->max_fds); - } -#else - context->lws_lookup = lws_zalloc(sizeof(struct libwebsocket *) * context->max_fds); + context->lws_lookup = (struct libwebsocket **) + malloc(sizeof(struct libwebsocket *) * context->max_fds); if (context->lws_lookup == NULL) { lwsl_err( "Unable to allocate lws_lookup array for %d connections\n", context->max_fds); - lws_free(context->fds); - lws_free(context); + free(context->fds); + free(context); return NULL; } -#endif + memset(context->lws_lookup, 0, sizeof(struct libwebsocket *) * + context->max_fds); if (lws_plat_init_fd_tables(context)) { -#ifdef _WIN32 - for (i = 0; i < FD_HASHTABLE_MODULUS; i++) { - lws_free(context->fd_hashtable[i].wsi); - } -#else - lws_free(context->lws_lookup); -#endif - lws_free(context->fds); - lws_free(context); + free(context->lws_lookup); + free(context->fds); + free(context); return NULL; } @@ -221,10 +214,10 @@ libwebsocket_create_context(struct lws_context_creation_info *info) " per-conn mem: %u + %u headers + protocol rx buf\n", sizeof(struct libwebsocket), sizeof(struct allocated_headers)); - + if (lws_context_init_server_ssl(info, context)) goto bail; - + if (lws_context_init_client_ssl(info, context)) goto bail; @@ -306,11 +299,11 @@ libwebsocket_context_destroy(struct libwebsocket_context *context) for (n = 0; n < context->fds_count; n++) { struct libwebsocket *wsi = - wsi_from_fd(context, context->fds[n].fd); + context->lws_lookup[context->fds[n].fd]; if (!wsi) continue; libwebsocket_close_and_free_session(context, - wsi, LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY /* no protocol close */); + wsi, LWS_CLOSE_STATUS_NOSTATUS /* no protocol close */); n--; } @@ -318,7 +311,7 @@ libwebsocket_context_destroy(struct libwebsocket_context *context) * give all extensions a chance to clean up any per-context * allocations they might have made */ - if (context->listen_port != CONTEXT_PORT_NO_LISTEN) { + if (context->listen_port) { if (lws_ext_callback_for_each_extension_type(context, NULL, LWS_EXT_CALLBACK_SERVER_CONTEXT_DESTRUCT, NULL, 0) < 0) return; @@ -342,15 +335,12 @@ libwebsocket_context_destroy(struct libwebsocket_context *context) lws_ssl_context_destroy(context); - lws_free(context->fds); -#ifdef _WIN32 - for (n = 0; n < FD_HASHTABLE_MODULUS; n++) { - lws_free(context->fd_hashtable[n].wsi); - } -#else - lws_free(context->lws_lookup); -#endif + if (context->fds) + free(context->fds); + if (context->lws_lookup) + free(context->lws_lookup); + lws_plat_context_late_destroy(context); - lws_free(context); + free(context); } diff --git a/lib/daemonize.c b/lib/daemonize.c index f5caf0b199..4130764ba1 100644 --- a/lib/daemonize.c +++ b/lib/daemonize.c @@ -76,7 +76,8 @@ static void lws_daemon_closing(int sigact) if (getpid() == pid_daemon) if (lock_path) { unlink(lock_path); - lws_free2(lock_path); + free(lock_path); + lock_path = NULL; } kill(getpid(), SIGKILL); @@ -104,7 +105,7 @@ lws_daemonize(const char *_lock_path) return 1; fd = open(_lock_path, O_RDONLY); - if (fd >= 0) { + if (fd > 0) { n = read(fd, buf, sizeof(buf)); close(fd); if (n) { @@ -123,7 +124,7 @@ lws_daemonize(const char *_lock_path) } n = strlen(_lock_path) + 1; - lock_path = lws_malloc(n); + lock_path = malloc(n); if (!lock_path) { fprintf(stderr, "Out of mem in lws_daemonize\n"); return 1; diff --git a/lib/extension-deflate-frame.c b/lib/extension-deflate-frame.c index 96285a9a17..6cf6ac0161 100644 --- a/lib/extension-deflate-frame.c +++ b/lib/extension-deflate-frame.c @@ -54,14 +54,16 @@ int lws_extension_callback_deflate_frame( conn->buf_out_length = sizeof(conn->buf_out); conn->compressed_out = 0; conn->buf_pre = NULL; - conn->buf_in = lws_malloc(LWS_SEND_BUFFER_PRE_PADDING + - conn->buf_in_length + - LWS_SEND_BUFFER_POST_PADDING); + conn->buf_in = (unsigned char *) + malloc(LWS_SEND_BUFFER_PRE_PADDING + + conn->buf_in_length + + LWS_SEND_BUFFER_POST_PADDING); if (!conn->buf_in) goto bail; - conn->buf_out = lws_malloc(LWS_SEND_BUFFER_PRE_PADDING + - conn->buf_out_length + - LWS_SEND_BUFFER_POST_PADDING); + conn->buf_out = (unsigned char *) + malloc(LWS_SEND_BUFFER_PRE_PADDING + + conn->buf_out_length + + LWS_SEND_BUFFER_POST_PADDING); if (!conn->buf_out) goto bail; lwsl_ext("zlibs constructed\n"); @@ -73,9 +75,10 @@ int lws_extension_callback_deflate_frame( return -1; case LWS_EXT_CALLBACK_DESTROY: - lws_free(conn->buf_pre); - lws_free(conn->buf_in); - lws_free(conn->buf_out); + if (conn->buf_pre) + free(conn->buf_pre); + free(conn->buf_in); + free(conn->buf_out); conn->buf_pre_used = 0; conn->buf_pre_length = 0; conn->buf_in_length = 0; @@ -103,8 +106,10 @@ int lws_extension_callback_deflate_frame( if (conn->buf_pre_length < total_payload) { conn->buf_pre_length = total_payload; - lws_free(conn->buf_pre); - conn->buf_pre = lws_malloc(total_payload + 4); + if (conn->buf_pre) + free(conn->buf_pre); + conn->buf_pre = + (unsigned char *)malloc(total_payload + 4); if (!conn->buf_pre) { lwsl_err("Out of memory\n"); return -1; @@ -175,10 +180,10 @@ int lws_extension_callback_deflate_frame( LWS_MAX_ZLIB_CONN_BUFFER); return -1; } - conn->buf_in = lws_realloc(conn->buf_in, - LWS_SEND_BUFFER_PRE_PADDING + - conn->buf_in_length + - LWS_SEND_BUFFER_POST_PADDING); + conn->buf_in = (unsigned char *)realloc(conn->buf_in, + LWS_SEND_BUFFER_PRE_PADDING + + conn->buf_in_length + + LWS_SEND_BUFFER_POST_PADDING); if (!conn->buf_in) { lwsl_err("Out of memory\n"); return -1; @@ -238,17 +243,18 @@ int lws_extension_callback_deflate_frame( LWS_MAX_ZLIB_CONN_BUFFER); return -1; } - conn->buf_out = lws_realloc(conn->buf_out, - LWS_SEND_BUFFER_PRE_PADDING + - conn->buf_out_length + - LWS_SEND_BUFFER_POST_PADDING); + conn->buf_out = (unsigned char *)realloc( + conn->buf_out, + LWS_SEND_BUFFER_PRE_PADDING + + conn->buf_out_length + + LWS_SEND_BUFFER_POST_PADDING); if (!conn->buf_out) { lwsl_err("Out of memory\n"); return -1; } lwsl_debug( "deflate-frame ext TX did realloc to %ld\n", - conn->buf_out_length); + conn->buf_in_length); conn->zs_out.next_out = (conn->buf_out + LWS_SEND_BUFFER_PRE_PADDING + len_so_far); diff --git a/lib/extension.c b/lib/extension.c index b7a5792bf4..1e8370c51f 100644 --- a/lib/extension.c +++ b/lib/extension.c @@ -144,8 +144,11 @@ lws_issue_raw_ext_access(struct libwebsocket *wsi, } /* always either sent it all or privately buffered */ - if (wsi->u.ws.clean_buffer) + if (wsi->u.ws.clean_buffer) { + eff_buf.token_len = n; len = n; + } + } lwsl_parser("written %d bytes to client\n", n); diff --git a/lib/getifaddrs.c b/lib/getifaddrs.c index c9ed464c56..1fa47cea4a 100644 --- a/lib/getifaddrs.c +++ b/lib/getifaddrs.c @@ -44,7 +44,6 @@ #include #include #include -#include "private-libwebsockets.h" #ifdef HAVE_SYS_SOCKIO_H #include @@ -86,7 +85,7 @@ getifaddrs2(struct ifaddrs **ifap, buf_size = 8192; for (;;) { - buf = lws_zalloc(buf_size); + buf = calloc(1, buf_size); if (buf == NULL) { ret = ENOMEM; goto error_out; @@ -108,7 +107,7 @@ getifaddrs2(struct ifaddrs **ifap, if (ifconf.ifc_len < (int)buf_size) break; - lws_free(buf); + free(buf); buf_size *= 2; } @@ -138,12 +137,12 @@ getifaddrs2(struct ifaddrs **ifap, goto error_out; } - *end = lws_malloc(sizeof(**end)); + *end = malloc(sizeof(**end)); (*end)->ifa_next = NULL; (*end)->ifa_name = strdup(ifr->ifr_name); (*end)->ifa_flags = ifreq.ifr_flags; - (*end)->ifa_addr = lws_malloc(salen); + (*end)->ifa_addr = malloc(salen); memcpy((*end)->ifa_addr, sa, salen); (*end)->ifa_netmask = NULL; @@ -151,12 +150,11 @@ getifaddrs2(struct ifaddrs **ifap, /* fix these when we actually need them */ if (ifreq.ifr_flags & IFF_BROADCAST) { (*end)->ifa_broadaddr = - lws_malloc(sizeof(ifr->ifr_broadaddr)); + malloc(sizeof(ifr->ifr_broadaddr)); memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr, sizeof(ifr->ifr_broadaddr)); } else if (ifreq.ifr_flags & IFF_POINTOPOINT) { - (*end)->ifa_dstaddr = - lws_malloc(sizeof(ifr->ifr_dstaddr)); + (*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr)); memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr, sizeof(ifr->ifr_dstaddr)); } else @@ -171,12 +169,12 @@ getifaddrs2(struct ifaddrs **ifap, } *ifap = start; close(fd); - lws_free(buf); + free(buf); return 0; error_out: close(fd); - lws_free(buf); + free(buf); errno = ret; return -1; @@ -211,14 +209,18 @@ freeifaddrs(struct ifaddrs *ifp) struct ifaddrs *p, *q; for (p = ifp; p; ) { - lws_free(p->ifa_name); - lws_free(p->ifa_addr); - lws_free(p->ifa_dstaddr); - lws_free(p->ifa_netmask); - lws_free(p->ifa_data); + free(p->ifa_name); + if (p->ifa_addr) + free(p->ifa_addr); + if (p->ifa_dstaddr) + free(p->ifa_dstaddr); + if (p->ifa_netmask) + free(p->ifa_netmask); + if (p->ifa_data) + free(p->ifa_data); q = p; p = p->ifa_next; - lws_free(q); + free(q); } } diff --git a/lib/handshake.c b/lib/handshake.c index 856297db2a..25dd3cc6fe 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -46,9 +46,6 @@ * Sec-WebSocket-Protocol: chat */ -#ifndef min -#define min(a, b) ((a) < (b) ? (a) : (b)) -#endif /* * We have to take care about parsing because the headers may be split * into multiple fragments. They may contain unknown headers with arbitrary @@ -61,118 +58,90 @@ libwebsocket_read(struct libwebsocket_context *context, struct libwebsocket *wsi, unsigned char *buf, size_t len) { size_t n; - int body_chunk_len; - unsigned char *last_char; switch (wsi->state) { -#ifdef LWS_USE_HTTP2 - case WSI_STATE_HTTP2_AWAIT_CLIENT_PREFACE: - case WSI_STATE_HTTP2_ESTABLISHED_PRE_SETTINGS: - case WSI_STATE_HTTP2_ESTABLISHED: - n = 0; - while (n < len) { - /* - * we were accepting input but now we stopped doing so - */ - if (!(wsi->rxflow_change_to & LWS_RXFLOW_ALLOW)) { - lws_rxflow_cache(wsi, buf, n, len); - - return 1; + + case WSI_STATE_HTTP_BODY: +http_postbody: + while (len--) { + + if (wsi->u.http.content_length_seen >= wsi->u.http.content_length) + break; + + wsi->u.http.post_buffer[wsi->u.http.body_index++] = *buf++; + wsi->u.http.content_length_seen++; + n = wsi->protocol->rx_buffer_size; + if (!n) + n = LWS_MAX_SOCKET_IO_BUF; + + if (wsi->u.http.body_index != n && + wsi->u.http.content_length_seen != wsi->u.http.content_length) + continue; + + if (wsi->protocol->callback) { + n = wsi->protocol->callback( + wsi->protocol->owning_server, wsi, + LWS_CALLBACK_HTTP_BODY, + wsi->user_space, wsi->u.http.post_buffer, + wsi->u.http.body_index); + wsi->u.http.body_index = 0; + if (n) + goto bail; } - /* account for what we're using in rxflow buffer */ - if (wsi->rxflow_buffer) - wsi->rxflow_pos++; - if (lws_http2_parser(context, wsi, buf[n++])) + if (wsi->u.http.content_length_seen == wsi->u.http.content_length) { + /* he sent the content in time */ + libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); + n = wsi->protocol->callback( + wsi->protocol->owning_server, wsi, + LWS_CALLBACK_HTTP_BODY_COMPLETION, + wsi->user_space, NULL, 0); + wsi->u.http.body_index = 0; + if (n) + goto bail; + } + + } + + /* + * we need to spill here so everything is seen in the case + * there is no content-length + */ + if (wsi->u.http.body_index && wsi->protocol->callback) { + n = wsi->protocol->callback( + wsi->protocol->owning_server, wsi, + LWS_CALLBACK_HTTP_BODY, + wsi->user_space, wsi->u.http.post_buffer, + wsi->u.http.body_index); + wsi->u.http.body_index = 0; + if (n) goto bail; } break; -#endif -http_new: - case WSI_STATE_HTTP: - wsi->hdr_parsing_completed = 0; - /* fallthru */ + case WSI_STATE_HTTP_ISSUING_FILE: + case WSI_STATE_HTTP: wsi->state = WSI_STATE_HTTP_HEADERS; wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART; wsi->u.hdr.lextable_pos = 0; /* fallthru */ case WSI_STATE_HTTP_HEADERS: + lwsl_parser("issuing %d bytes to parser\n", (int)len); if (lws_handshake_client(wsi, &buf, len)) goto bail; - last_char = buf; - if (lws_handshake_server(context, wsi, &buf, len)) - /* Handshake indicates this session is done. */ + switch (lws_handshake_server(context, wsi, &buf, len)) { + case 1: goto bail; - - /* It's possible that we've exhausted our data already, but - * lws_handshake_server doesn't update len for us. Figure out how - * much was read, so that we can proceed appropriately: */ - len -= (buf - last_char); - - if (!wsi->hdr_parsing_completed) - /* More header content on the way */ - goto read_ok; - - switch (wsi->state) { - case WSI_STATE_HTTP: - case WSI_STATE_HTTP_HEADERS: - goto http_complete; - case WSI_STATE_HTTP_ISSUING_FILE: - goto read_ok; - case WSI_STATE_HTTP_BODY: - wsi->u.http.content_remain = wsi->u.http.content_length; - goto http_postbody; - default: - break; + case 2: + goto http_postbody; } break; - case WSI_STATE_HTTP_BODY: -http_postbody: - while (len && wsi->u.http.content_remain) { - /* Copy as much as possible, up to the limit of: - * what we have in the read buffer (len) - * remaining portion of the POST body (content_remain) - */ - body_chunk_len = min(wsi->u.http.content_remain,len); - wsi->u.http.content_remain -= body_chunk_len; - len -= body_chunk_len; - - if (wsi->protocol->callback) { - n = wsi->protocol->callback( - wsi->protocol->owning_server, wsi, - LWS_CALLBACK_HTTP_BODY, wsi->user_space, - buf, body_chunk_len); - if (n) - goto bail; - } - buf += body_chunk_len; - - if (!wsi->u.http.content_remain) { - /* he sent the content in time */ - libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); - if (wsi->protocol->callback) { - n = wsi->protocol->callback( - wsi->protocol->owning_server, wsi, - LWS_CALLBACK_HTTP_BODY_COMPLETION, - wsi->user_space, NULL, 0); - if (n) - goto bail; - } - goto http_complete; - } else - libwebsocket_set_timeout(wsi, - PENDING_TIMEOUT_HTTP_CONTENT, - AWAITING_TIMEOUT); - } - break; - - case WSI_STATE_ESTABLISHED: case WSI_STATE_AWAITING_CLOSE_ACK: + case WSI_STATE_ESTABLISHED: if (lws_handshake_client(wsi, &buf, len)) goto bail; switch (wsi->mode) { @@ -190,38 +159,8 @@ libwebsocket_read(struct libwebsocket_context *context, break; } -read_ok: - /* Nothing more to do for now. */ - lwsl_debug("libwebsocket_read: read_ok\n"); - return 0; -http_complete: - lwsl_debug("libwebsocket_read: http_complete\n"); - - /* Did the client want to keep the HTTP connection going? */ - - if (wsi->u.http.connection_type == HTTP_CONNECTION_KEEP_ALIVE) { - lwsl_debug("libwebsocket_read: keep-alive\n"); - wsi->state = WSI_STATE_HTTP; - wsi->mode = LWS_CONNMODE_HTTP_SERVING; - - /* He asked for it to stay alive indefinitely */ - libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); - - if (lws_allocate_header_table(wsi)) - goto bail; - - /* If we're (re)starting on headers, need other implied init */ - wsi->u.hdr.ues = URIES_IDLE; - - /* If we have more data, loop back around: */ - if (len) - goto http_new; - - return 0; - } - bail: lwsl_debug("closing connection at libwebsocket_read bail:\n"); diff --git a/lib/lextable.h b/lib/lextable.h index 73c92d438c..9d86577a5f 100755 --- a/lib/lextable.h +++ b/lib/lextable.h @@ -1,760 +1,338 @@ -/* pos 0000: 0 */ 0x67 /* 'g' */, 0x3D, 0x00 /* (to 0x003D state 1) */, - 0x70 /* 'p' */, 0x3F, 0x00 /* (to 0x0042 state 5) */, - 0x6F /* 'o' */, 0x4E, 0x00 /* (to 0x0054 state 10) */, - 0x68 /* 'h' */, 0x5A, 0x00 /* (to 0x0063 state 18) */, - 0x63 /* 'c' */, 0x63, 0x00 /* (to 0x006F state 23) */, - 0x75 /* 'u' */, 0x7E, 0x00 /* (to 0x008D state 34) */, - 0x73 /* 's' */, 0x91, 0x00 /* (to 0x00A3 state 48) */, - 0x0D /* '.' */, 0xCA, 0x00 /* (to 0x00DF state 68) */, - 0x61 /* 'a' */, 0x1C, 0x01 /* (to 0x0134 state 129) */, - 0x69 /* 'i' */, 0x5B, 0x01 /* (to 0x0176 state 163) */, - 0x64 /* 'd' */, 0x04, 0x02 /* (to 0x0222 state 265) */, - 0x72 /* 'r' */, 0x0D, 0x02 /* (to 0x022E state 270) */, - 0x3A /* ':' */, 0x3E, 0x02 /* (to 0x0262 state 299) */, - 0x65 /* 'e' */, 0xCF, 0x02 /* (to 0x02F6 state 414) */, - 0x66 /* 'f' */, 0xEB, 0x02 /* (to 0x0315 state 430) */, - 0x6C /* 'l' */, 0x0D, 0x03 /* (to 0x033A state 463) */, - 0x6D /* 'm' */, 0x30, 0x03 /* (to 0x0360 state 489) */, - 0x74 /* 't' */, 0x9F, 0x03 /* (to 0x03D2 state 583) */, - 0x76 /* 'v' */, 0xBA, 0x03 /* (to 0x03F0 state 611) */, - 0x77 /* 'w' */, 0xC7, 0x03 /* (to 0x0400 state 619) */, - 0x08, /* fail */ -/* pos 003d: 1 */ 0xE5 /* 'e' -> */, -/* pos 003e: 2 */ 0xF4 /* 't' -> */, -/* pos 003f: 3 */ 0xA0 /* ' ' -> */, -/* pos 0040: 4 */ 0x00, 0x00 /* - terminal marker 0 - */, -/* pos 0042: 5 */ 0x6F /* 'o' */, 0x0D, 0x00 /* (to 0x004F state 6) */, - 0x72 /* 'r' */, 0x83, 0x01 /* (to 0x01C8 state 211) */, - 0x61 /* 'a' */, 0xCC, 0x03 /* (to 0x0414 state 637) */, - 0x75 /* 'u' */, 0xCE, 0x03 /* (to 0x0419 state 641) */, - 0x08, /* fail */ -/* pos 004f: 6 */ 0xF3 /* 's' -> */, -/* pos 0050: 7 */ 0xF4 /* 't' -> */, -/* pos 0051: 8 */ 0xA0 /* ' ' -> */, -/* pos 0052: 9 */ 0x00, 0x01 /* - terminal marker 1 - */, -/* pos 0054: 10 */ 0x70 /* 'p' */, 0x07, 0x00 /* (to 0x005B state 11) */, - 0x72 /* 'r' */, 0x45, 0x00 /* (to 0x009C state 42) */, - 0x08, /* fail */ -/* pos 005b: 11 */ 0xF4 /* 't' -> */, -/* pos 005c: 12 */ 0xE9 /* 'i' -> */, -/* pos 005d: 13 */ 0xEF /* 'o' -> */, -/* pos 005e: 14 */ 0xEE /* 'n' -> */, -/* pos 005f: 15 */ 0xF3 /* 's' -> */, -/* pos 0060: 16 */ 0xA0 /* ' ' -> */, -/* pos 0061: 17 */ 0x00, 0x02 /* - terminal marker 2 - */, -/* pos 0063: 18 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x006A state 19) */, - 0x74 /* 't' */, 0xB3, 0x00 /* (to 0x0119 state 110) */, - 0x08, /* fail */ -/* pos 006a: 19 */ 0xF3 /* 's' -> */, -/* pos 006b: 20 */ 0xF4 /* 't' -> */, -/* pos 006c: 21 */ 0xBA /* ':' -> */, -/* pos 006d: 22 */ 0x00, 0x03 /* - terminal marker 3 - */, -/* pos 006f: 23 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x0076 state 24) */, - 0x61 /* 'a' */, 0x63, 0x01 /* (to 0x01D5 state 217) */, - 0x08, /* fail */ -/* pos 0076: 24 */ 0x6E /* 'n' */, 0x07, 0x00 /* (to 0x007D state 25) */, - 0x6F /* 'o' */, 0x78, 0x01 /* (to 0x01F1 state 243) */, - 0x08, /* fail */ -/* pos 007d: 25 */ 0x6E /* 'n' */, 0x07, 0x00 /* (to 0x0084 state 26) */, - 0x74 /* 't' */, 0x77, 0x01 /* (to 0x01F7 state 248) */, - 0x08, /* fail */ -/* pos 0084: 26 */ 0xE5 /* 'e' -> */, -/* pos 0085: 27 */ 0xE3 /* 'c' -> */, -/* pos 0086: 28 */ 0xF4 /* 't' -> */, -/* pos 0087: 29 */ 0xE9 /* 'i' -> */, -/* pos 0088: 30 */ 0xEF /* 'o' -> */, -/* pos 0089: 31 */ 0xEE /* 'n' -> */, -/* pos 008a: 32 */ 0xBA /* ':' -> */, -/* pos 008b: 33 */ 0x00, 0x04 /* - terminal marker 4 - */, -/* pos 008d: 34 */ 0x70 /* 'p' */, 0x07, 0x00 /* (to 0x0094 state 35) */, - 0x73 /* 's' */, 0x55, 0x03 /* (to 0x03E5 state 601) */, - 0x08, /* fail */ -/* pos 0094: 35 */ 0xE7 /* 'g' -> */, -/* pos 0095: 36 */ 0xF2 /* 'r' -> */, -/* pos 0096: 37 */ 0xE1 /* 'a' -> */, -/* pos 0097: 38 */ 0xE4 /* 'd' -> */, -/* pos 0098: 39 */ 0xE5 /* 'e' -> */, -/* pos 0099: 40 */ 0xBA /* ':' -> */, -/* pos 009a: 41 */ 0x00, 0x05 /* - terminal marker 5 - */, -/* pos 009c: 42 */ 0xE9 /* 'i' -> */, -/* pos 009d: 43 */ 0xE7 /* 'g' -> */, -/* pos 009e: 44 */ 0xE9 /* 'i' -> */, -/* pos 009f: 45 */ 0xEE /* 'n' -> */, -/* pos 00a0: 46 */ 0xBA /* ':' -> */, -/* pos 00a1: 47 */ 0x00, 0x06 /* - terminal marker 6 - */, -/* pos 00a3: 48 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x00AA state 49) */, - 0x74 /* 't' */, 0x12, 0x03 /* (to 0x03B8 state 558) */, - 0x08, /* fail */ -/* pos 00aa: 49 */ 0x63 /* 'c' */, 0x0A, 0x00 /* (to 0x00B4 state 50) */, - 0x72 /* 'r' */, 0xFB, 0x02 /* (to 0x03A8 state 544) */, - 0x74 /* 't' */, 0xFE, 0x02 /* (to 0x03AE state 549) */, - 0x08, /* fail */ -/* pos 00b4: 50 */ 0xAD /* '-' -> */, -/* pos 00b5: 51 */ 0xF7 /* 'w' -> */, -/* pos 00b6: 52 */ 0xE5 /* 'e' -> */, -/* pos 00b7: 53 */ 0xE2 /* 'b' -> */, -/* pos 00b8: 54 */ 0xF3 /* 's' -> */, -/* pos 00b9: 55 */ 0xEF /* 'o' -> */, -/* pos 00ba: 56 */ 0xE3 /* 'c' -> */, -/* pos 00bb: 57 */ 0xEB /* 'k' -> */, -/* pos 00bc: 58 */ 0xE5 /* 'e' -> */, -/* pos 00bd: 59 */ 0xF4 /* 't' -> */, -/* pos 00be: 60 */ 0xAD /* '-' -> */, -/* pos 00bf: 61 */ 0x64 /* 'd' */, 0x19, 0x00 /* (to 0x00D8 state 62) */, - 0x65 /* 'e' */, 0x20, 0x00 /* (to 0x00E2 state 70) */, - 0x6B /* 'k' */, 0x29, 0x00 /* (to 0x00EE state 81) */, - 0x70 /* 'p' */, 0x38, 0x00 /* (to 0x0100 state 88) */, - 0x61 /* 'a' */, 0x3F, 0x00 /* (to 0x010A state 97) */, - 0x6E /* 'n' */, 0x44, 0x00 /* (to 0x0112 state 104) */, - 0x76 /* 'v' */, 0x80, 0x01 /* (to 0x0251 state 284) */, - 0x6F /* 'o' */, 0x86, 0x01 /* (to 0x025A state 292) */, - 0x08, /* fail */ -/* pos 00d8: 62 */ 0xF2 /* 'r' -> */, -/* pos 00d9: 63 */ 0xE1 /* 'a' -> */, -/* pos 00da: 64 */ 0xE6 /* 'f' -> */, -/* pos 00db: 65 */ 0xF4 /* 't' -> */, -/* pos 00dc: 66 */ 0xBA /* ':' -> */, -/* pos 00dd: 67 */ 0x00, 0x07 /* - terminal marker 7 - */, -/* pos 00df: 68 */ 0x8A /* '.' -> */, -/* pos 00e0: 69 */ 0x00, 0x08 /* - terminal marker 8 - */, -/* pos 00e2: 70 */ 0xF8 /* 'x' -> */, -/* pos 00e3: 71 */ 0xF4 /* 't' -> */, -/* pos 00e4: 72 */ 0xE5 /* 'e' -> */, -/* pos 00e5: 73 */ 0xEE /* 'n' -> */, -/* pos 00e6: 74 */ 0xF3 /* 's' -> */, -/* pos 00e7: 75 */ 0xE9 /* 'i' -> */, -/* pos 00e8: 76 */ 0xEF /* 'o' -> */, -/* pos 00e9: 77 */ 0xEE /* 'n' -> */, -/* pos 00ea: 78 */ 0xF3 /* 's' -> */, -/* pos 00eb: 79 */ 0xBA /* ':' -> */, -/* pos 00ec: 80 */ 0x00, 0x09 /* - terminal marker 9 - */, -/* pos 00ee: 81 */ 0xE5 /* 'e' -> */, -/* pos 00ef: 82 */ 0xF9 /* 'y' -> */, -/* pos 00f0: 83 */ 0x31 /* '1' */, 0x0A, 0x00 /* (to 0x00FA state 84) */, - 0x32 /* '2' */, 0x0A, 0x00 /* (to 0x00FD state 86) */, - 0x3A /* ':' */, 0x59, 0x01 /* (to 0x024F state 283) */, - 0x08, /* fail */ -/* pos 00fa: 84 */ 0xBA /* ':' -> */, -/* pos 00fb: 85 */ 0x00, 0x0A /* - terminal marker 10 - */, -/* pos 00fd: 86 */ 0xBA /* ':' -> */, -/* pos 00fe: 87 */ 0x00, 0x0B /* - terminal marker 11 - */, -/* pos 0100: 88 */ 0xF2 /* 'r' -> */, -/* pos 0101: 89 */ 0xEF /* 'o' -> */, -/* pos 0102: 90 */ 0xF4 /* 't' -> */, -/* pos 0103: 91 */ 0xEF /* 'o' -> */, -/* pos 0104: 92 */ 0xE3 /* 'c' -> */, -/* pos 0105: 93 */ 0xEF /* 'o' -> */, -/* pos 0106: 94 */ 0xEC /* 'l' -> */, -/* pos 0107: 95 */ 0xBA /* ':' -> */, -/* pos 0108: 96 */ 0x00, 0x0C /* - terminal marker 12 - */, -/* pos 010a: 97 */ 0xE3 /* 'c' -> */, -/* pos 010b: 98 */ 0xE3 /* 'c' -> */, -/* pos 010c: 99 */ 0xE5 /* 'e' -> */, -/* pos 010d: 100 */ 0xF0 /* 'p' -> */, -/* pos 010e: 101 */ 0xF4 /* 't' -> */, -/* pos 010f: 102 */ 0xBA /* ':' -> */, -/* pos 0110: 103 */ 0x00, 0x0D /* - terminal marker 13 - */, -/* pos 0112: 104 */ 0xEF /* 'o' -> */, -/* pos 0113: 105 */ 0xEE /* 'n' -> */, -/* pos 0114: 106 */ 0xE3 /* 'c' -> */, -/* pos 0115: 107 */ 0xE5 /* 'e' -> */, -/* pos 0116: 108 */ 0xBA /* ':' -> */, -/* pos 0117: 109 */ 0x00, 0x0E /* - terminal marker 14 - */, -/* pos 0119: 110 */ 0xF4 /* 't' -> */, -/* pos 011a: 111 */ 0xF0 /* 'p' -> */, -/* pos 011b: 112 */ 0x2F /* '/' */, 0x07, 0x00 /* (to 0x0122 state 113) */, - 0x32 /* '2' */, 0x0A, 0x00 /* (to 0x0128 state 118) */, - 0x08, /* fail */ -/* pos 0122: 113 */ 0xB1 /* '1' -> */, -/* pos 0123: 114 */ 0xAE /* '.' -> */, -/* pos 0124: 115 */ 0xB1 /* '1' -> */, -/* pos 0125: 116 */ 0xA0 /* ' ' -> */, -/* pos 0126: 117 */ 0x00, 0x0F /* - terminal marker 15 - */, -/* pos 0128: 118 */ 0xAD /* '-' -> */, -/* pos 0129: 119 */ 0xF3 /* 's' -> */, -/* pos 012a: 120 */ 0xE5 /* 'e' -> */, -/* pos 012b: 121 */ 0xF4 /* 't' -> */, -/* pos 012c: 122 */ 0xF4 /* 't' -> */, -/* pos 012d: 123 */ 0xE9 /* 'i' -> */, -/* pos 012e: 124 */ 0xEE /* 'n' -> */, -/* pos 012f: 125 */ 0xE7 /* 'g' -> */, -/* pos 0130: 126 */ 0xF3 /* 's' -> */, -/* pos 0131: 127 */ 0xBA /* ':' -> */, -/* pos 0132: 128 */ 0x00, 0x10 /* - terminal marker 16 - */, -/* pos 0134: 129 */ 0x63 /* 'c' */, 0x0D, 0x00 /* (to 0x0141 state 130) */, - 0x75 /* 'u' */, 0xAC, 0x00 /* (to 0x01E3 state 230) */, - 0x67 /* 'g' */, 0x82, 0x01 /* (to 0x02BC state 363) */, - 0x6C /* 'l' */, 0x83, 0x01 /* (to 0x02C0 state 366) */, - 0x08, /* fail */ -/* pos 0141: 130 */ 0xE3 /* 'c' -> */, -/* pos 0142: 131 */ 0xE5 /* 'e' -> */, -/* pos 0143: 132 */ 0x70 /* 'p' */, 0x07, 0x00 /* (to 0x014A state 133) */, - 0x73 /* 's' */, 0x0E, 0x00 /* (to 0x0154 state 136) */, - 0x08, /* fail */ -/* pos 014a: 133 */ 0xF4 /* 't' -> */, -/* pos 014b: 134 */ 0x3A /* ':' */, 0x07, 0x00 /* (to 0x0152 state 135) */, - 0x2D /* '-' */, 0x59, 0x00 /* (to 0x01A7 state 192) */, - 0x08, /* fail */ -/* pos 0152: 135 */ 0x00, 0x11 /* - terminal marker 17 - */, -/* pos 0154: 136 */ 0xF3 /* 's' -> */, -/* pos 0155: 137 */ 0xAD /* '-' -> */, -/* pos 0156: 138 */ 0xE3 /* 'c' -> */, -/* pos 0157: 139 */ 0xEF /* 'o' -> */, -/* pos 0158: 140 */ 0xEE /* 'n' -> */, -/* pos 0159: 141 */ 0xF4 /* 't' -> */, -/* pos 015a: 142 */ 0xF2 /* 'r' -> */, -/* pos 015b: 143 */ 0xEF /* 'o' -> */, -/* pos 015c: 144 */ 0xEC /* 'l' -> */, -/* pos 015d: 145 */ 0xAD /* '-' -> */, -/* pos 015e: 146 */ 0x72 /* 'r' */, 0x07, 0x00 /* (to 0x0165 state 147) */, - 0x61 /* 'a' */, 0x4D, 0x01 /* (to 0x02AE state 350) */, - 0x08, /* fail */ -/* pos 0165: 147 */ 0xE5 /* 'e' -> */, -/* pos 0166: 148 */ 0xF1 /* 'q' -> */, -/* pos 0167: 149 */ 0xF5 /* 'u' -> */, -/* pos 0168: 150 */ 0xE5 /* 'e' -> */, -/* pos 0169: 151 */ 0xF3 /* 's' -> */, -/* pos 016a: 152 */ 0xF4 /* 't' -> */, -/* pos 016b: 153 */ 0xAD /* '-' -> */, -/* pos 016c: 154 */ 0xE8 /* 'h' -> */, -/* pos 016d: 155 */ 0xE5 /* 'e' -> */, -/* pos 016e: 156 */ 0xE1 /* 'a' -> */, -/* pos 016f: 157 */ 0xE4 /* 'd' -> */, -/* pos 0170: 158 */ 0xE5 /* 'e' -> */, -/* pos 0171: 159 */ 0xF2 /* 'r' -> */, -/* pos 0172: 160 */ 0xF3 /* 's' -> */, -/* pos 0173: 161 */ 0xBA /* ':' -> */, -/* pos 0174: 162 */ 0x00, 0x12 /* - terminal marker 18 - */, -/* pos 0176: 163 */ 0xE6 /* 'f' -> */, -/* pos 0177: 164 */ 0xAD /* '-' -> */, -/* pos 0178: 165 */ 0x6D /* 'm' */, 0x0D, 0x00 /* (to 0x0185 state 166) */, - 0x6E /* 'n' */, 0x20, 0x00 /* (to 0x019B state 181) */, - 0x72 /* 'r' */, 0xA3, 0x01 /* (to 0x0321 state 440) */, - 0x75 /* 'u' */, 0xA7, 0x01 /* (to 0x0328 state 446) */, - 0x08, /* fail */ -/* pos 0185: 166 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x018C state 167) */, - 0x61 /* 'a' */, 0x93, 0x01 /* (to 0x031B state 435) */, - 0x08, /* fail */ -/* pos 018c: 167 */ 0xE4 /* 'd' -> */, -/* pos 018d: 168 */ 0xE9 /* 'i' -> */, -/* pos 018e: 169 */ 0xE6 /* 'f' -> */, -/* pos 018f: 170 */ 0xE9 /* 'i' -> */, -/* pos 0190: 171 */ 0xE5 /* 'e' -> */, -/* pos 0191: 172 */ 0xE4 /* 'd' -> */, -/* pos 0192: 173 */ 0xAD /* '-' -> */, -/* pos 0193: 174 */ 0xF3 /* 's' -> */, -/* pos 0194: 175 */ 0xE9 /* 'i' -> */, -/* pos 0195: 176 */ 0xEE /* 'n' -> */, -/* pos 0196: 177 */ 0xE3 /* 'c' -> */, -/* pos 0197: 178 */ 0xE5 /* 'e' -> */, -/* pos 0198: 179 */ 0xBA /* ':' -> */, -/* pos 0199: 180 */ 0x00, 0x13 /* - terminal marker 19 - */, -/* pos 019b: 181 */ 0xEF /* 'o' -> */, -/* pos 019c: 182 */ 0xEE /* 'n' -> */, -/* pos 019d: 183 */ 0xE5 /* 'e' -> */, -/* pos 019e: 184 */ 0xAD /* '-' -> */, -/* pos 019f: 185 */ 0xED /* 'm' -> */, -/* pos 01a0: 186 */ 0xE1 /* 'a' -> */, -/* pos 01a1: 187 */ 0xF4 /* 't' -> */, -/* pos 01a2: 188 */ 0xE3 /* 'c' -> */, -/* pos 01a3: 189 */ 0xE8 /* 'h' -> */, -/* pos 01a4: 190 */ 0xBA /* ':' -> */, -/* pos 01a5: 191 */ 0x00, 0x14 /* - terminal marker 20 - */, -/* pos 01a7: 192 */ 0x65 /* 'e' */, 0x0D, 0x00 /* (to 0x01B4 state 193) */, - 0x6C /* 'l' */, 0x14, 0x00 /* (to 0x01BE state 202) */, - 0x63 /* 'c' */, 0xF0, 0x00 /* (to 0x029D state 335) */, - 0x72 /* 'r' */, 0xF6, 0x00 /* (to 0x02A6 state 343) */, - 0x08, /* fail */ -/* pos 01b4: 193 */ 0xEE /* 'n' -> */, -/* pos 01b5: 194 */ 0xE3 /* 'c' -> */, -/* pos 01b6: 195 */ 0xEF /* 'o' -> */, -/* pos 01b7: 196 */ 0xE4 /* 'd' -> */, -/* pos 01b8: 197 */ 0xE9 /* 'i' -> */, -/* pos 01b9: 198 */ 0xEE /* 'n' -> */, -/* pos 01ba: 199 */ 0xE7 /* 'g' -> */, -/* pos 01bb: 200 */ 0xBA /* ':' -> */, -/* pos 01bc: 201 */ 0x00, 0x15 /* - terminal marker 21 - */, -/* pos 01be: 202 */ 0xE1 /* 'a' -> */, -/* pos 01bf: 203 */ 0xEE /* 'n' -> */, -/* pos 01c0: 204 */ 0xE7 /* 'g' -> */, -/* pos 01c1: 205 */ 0xF5 /* 'u' -> */, -/* pos 01c2: 206 */ 0xE1 /* 'a' -> */, -/* pos 01c3: 207 */ 0xE7 /* 'g' -> */, -/* pos 01c4: 208 */ 0xE5 /* 'e' -> */, -/* pos 01c5: 209 */ 0xBA /* ':' -> */, -/* pos 01c6: 210 */ 0x00, 0x16 /* - terminal marker 22 - */, -/* pos 01c8: 211 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x01CF state 212) */, - 0x6F /* 'o' */, 0xA3, 0x01 /* (to 0x036E state 502) */, - 0x08, /* fail */ -/* pos 01cf: 212 */ 0xE7 /* 'g' -> */, -/* pos 01d0: 213 */ 0xED /* 'm' -> */, -/* pos 01d1: 214 */ 0xE1 /* 'a' -> */, -/* pos 01d2: 215 */ 0xBA /* ':' -> */, -/* pos 01d3: 216 */ 0x00, 0x17 /* - terminal marker 23 - */, -/* pos 01d5: 217 */ 0xE3 /* 'c' -> */, -/* pos 01d6: 218 */ 0xE8 /* 'h' -> */, -/* pos 01d7: 219 */ 0xE5 /* 'e' -> */, -/* pos 01d8: 220 */ 0xAD /* '-' -> */, -/* pos 01d9: 221 */ 0xE3 /* 'c' -> */, -/* pos 01da: 222 */ 0xEF /* 'o' -> */, -/* pos 01db: 223 */ 0xEE /* 'n' -> */, -/* pos 01dc: 224 */ 0xF4 /* 't' -> */, -/* pos 01dd: 225 */ 0xF2 /* 'r' -> */, -/* pos 01de: 226 */ 0xEF /* 'o' -> */, -/* pos 01df: 227 */ 0xEC /* 'l' -> */, -/* pos 01e0: 228 */ 0xBA /* ':' -> */, -/* pos 01e1: 229 */ 0x00, 0x18 /* - terminal marker 24 - */, -/* pos 01e3: 230 */ 0xF4 /* 't' -> */, -/* pos 01e4: 231 */ 0xE8 /* 'h' -> */, -/* pos 01e5: 232 */ 0xEF /* 'o' -> */, -/* pos 01e6: 233 */ 0xF2 /* 'r' -> */, -/* pos 01e7: 234 */ 0xE9 /* 'i' -> */, -/* pos 01e8: 235 */ 0xFA /* 'z' -> */, -/* pos 01e9: 236 */ 0xE1 /* 'a' -> */, -/* pos 01ea: 237 */ 0xF4 /* 't' -> */, -/* pos 01eb: 238 */ 0xE9 /* 'i' -> */, -/* pos 01ec: 239 */ 0xEF /* 'o' -> */, -/* pos 01ed: 240 */ 0xEE /* 'n' -> */, -/* pos 01ee: 241 */ 0xBA /* ':' -> */, -/* pos 01ef: 242 */ 0x00, 0x19 /* - terminal marker 25 - */, -/* pos 01f1: 243 */ 0xEB /* 'k' -> */, -/* pos 01f2: 244 */ 0xE9 /* 'i' -> */, -/* pos 01f3: 245 */ 0xE5 /* 'e' -> */, -/* pos 01f4: 246 */ 0xBA /* ':' -> */, -/* pos 01f5: 247 */ 0x00, 0x1A /* - terminal marker 26 - */, -/* pos 01f7: 248 */ 0xE5 /* 'e' -> */, -/* pos 01f8: 249 */ 0xEE /* 'n' -> */, -/* pos 01f9: 250 */ 0xF4 /* 't' -> */, -/* pos 01fa: 251 */ 0xAD /* '-' -> */, -/* pos 01fb: 252 */ 0x6C /* 'l' */, 0x10, 0x00 /* (to 0x020B state 253) */, - 0x74 /* 't' */, 0x1E, 0x00 /* (to 0x021C state 260) */, - 0x64 /* 'd' */, 0xC5, 0x00 /* (to 0x02C6 state 371) */, - 0x65 /* 'e' */, 0xCF, 0x00 /* (to 0x02D3 state 383) */, - 0x72 /* 'r' */, 0xE8, 0x00 /* (to 0x02EF state 408) */, - 0x08, /* fail */ -/* pos 020b: 253 */ 0x65 /* 'e' */, 0x0A, 0x00 /* (to 0x0215 state 254) */, - 0x61 /* 'a' */, 0xCF, 0x00 /* (to 0x02DD state 392) */, - 0x6F /* 'o' */, 0xD5, 0x00 /* (to 0x02E6 state 400) */, - 0x08, /* fail */ -/* pos 0215: 254 */ 0xEE /* 'n' -> */, -/* pos 0216: 255 */ 0xE7 /* 'g' -> */, -/* pos 0217: 256 */ 0xF4 /* 't' -> */, -/* pos 0218: 257 */ 0xE8 /* 'h' -> */, -/* pos 0219: 258 */ 0xBA /* ':' -> */, -/* pos 021a: 259 */ 0x00, 0x1B /* - terminal marker 27 - */, -/* pos 021c: 260 */ 0xF9 /* 'y' -> */, -/* pos 021d: 261 */ 0xF0 /* 'p' -> */, -/* pos 021e: 262 */ 0xE5 /* 'e' -> */, -/* pos 021f: 263 */ 0xBA /* ':' -> */, -/* pos 0220: 264 */ 0x00, 0x1C /* - terminal marker 28 - */, -/* pos 0222: 265 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x0229 state 266) */, - 0x65 /* 'e' */, 0xF7, 0x01 /* (to 0x041C state 643) */, - 0x08, /* fail */ -/* pos 0229: 266 */ 0xF4 /* 't' -> */, -/* pos 022a: 267 */ 0xE5 /* 'e' -> */, -/* pos 022b: 268 */ 0xBA /* ':' -> */, -/* pos 022c: 269 */ 0x00, 0x1D /* - terminal marker 29 - */, -/* pos 022e: 270 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x0235 state 271) */, - 0x65 /* 'e' */, 0x0A, 0x00 /* (to 0x023B state 276) */, - 0x08, /* fail */ -/* pos 0235: 271 */ 0xEE /* 'n' -> */, -/* pos 0236: 272 */ 0xE7 /* 'g' -> */, -/* pos 0237: 273 */ 0xE5 /* 'e' -> */, -/* pos 0238: 274 */ 0xBA /* ':' -> */, -/* pos 0239: 275 */ 0x00, 0x1E /* - terminal marker 30 - */, -/* pos 023b: 276 */ 0x66 /* 'f' */, 0x07, 0x00 /* (to 0x0242 state 277) */, - 0x74 /* 't' */, 0x5F, 0x01 /* (to 0x039D state 534) */, - 0x08, /* fail */ -/* pos 0242: 277 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x0249 state 278) */, - 0x72 /* 'r' */, 0x52, 0x01 /* (to 0x0397 state 529) */, - 0x08, /* fail */ -/* pos 0249: 278 */ 0xF2 /* 'r' -> */, -/* pos 024a: 279 */ 0xE5 /* 'e' -> */, -/* pos 024b: 280 */ 0xF2 /* 'r' -> */, -/* pos 024c: 281 */ 0xBA /* ':' -> */, -/* pos 024d: 282 */ 0x00, 0x1F /* - terminal marker 31 - */, -/* pos 024f: 283 */ 0x00, 0x20 /* - terminal marker 32 - */, -/* pos 0251: 284 */ 0xE5 /* 'e' -> */, -/* pos 0252: 285 */ 0xF2 /* 'r' -> */, -/* pos 0253: 286 */ 0xF3 /* 's' -> */, -/* pos 0254: 287 */ 0xE9 /* 'i' -> */, -/* pos 0255: 288 */ 0xEF /* 'o' -> */, -/* pos 0256: 289 */ 0xEE /* 'n' -> */, -/* pos 0257: 290 */ 0xBA /* ':' -> */, -/* pos 0258: 291 */ 0x00, 0x21 /* - terminal marker 33 - */, -/* pos 025a: 292 */ 0xF2 /* 'r' -> */, -/* pos 025b: 293 */ 0xE9 /* 'i' -> */, -/* pos 025c: 294 */ 0xE7 /* 'g' -> */, -/* pos 025d: 295 */ 0xE9 /* 'i' -> */, -/* pos 025e: 296 */ 0xEE /* 'n' -> */, -/* pos 025f: 297 */ 0xBA /* ':' -> */, -/* pos 0260: 298 */ 0x00, 0x22 /* - terminal marker 34 - */, -/* pos 0262: 299 */ 0x61 /* 'a' */, 0x0D, 0x00 /* (to 0x026F state 300) */, - 0x6D /* 'm' */, 0x15, 0x00 /* (to 0x027A state 310) */, - 0x70 /* 'p' */, 0x1A, 0x00 /* (to 0x0282 state 317) */, - 0x73 /* 's' */, 0x1D, 0x00 /* (to 0x0288 state 322) */, - 0x08, /* fail */ -/* pos 026f: 300 */ 0xF5 /* 'u' -> */, -/* pos 0270: 301 */ 0xF4 /* 't' -> */, -/* pos 0271: 302 */ 0xE8 /* 'h' -> */, -/* pos 0272: 303 */ 0xEF /* 'o' -> */, -/* pos 0273: 304 */ 0xF2 /* 'r' -> */, -/* pos 0274: 305 */ 0xE9 /* 'i' -> */, -/* pos 0275: 306 */ 0xF4 /* 't' -> */, -/* pos 0276: 307 */ 0xF9 /* 'y' -> */, -/* pos 0277: 308 */ 0xBA /* ':' -> */, -/* pos 0278: 309 */ 0x00, 0x23 /* - terminal marker 35 - */, -/* pos 027a: 310 */ 0xE5 /* 'e' -> */, -/* pos 027b: 311 */ 0xF4 /* 't' -> */, -/* pos 027c: 312 */ 0xE8 /* 'h' -> */, -/* pos 027d: 313 */ 0xEF /* 'o' -> */, -/* pos 027e: 314 */ 0xE4 /* 'd' -> */, -/* pos 027f: 315 */ 0xBA /* ':' -> */, -/* pos 0280: 316 */ 0x00, 0x24 /* - terminal marker 36 - */, -/* pos 0282: 317 */ 0xE1 /* 'a' -> */, -/* pos 0283: 318 */ 0xF4 /* 't' -> */, -/* pos 0284: 319 */ 0xE8 /* 'h' -> */, -/* pos 0285: 320 */ 0xBA /* ':' -> */, -/* pos 0286: 321 */ 0x00, 0x25 /* - terminal marker 37 - */, -/* pos 0288: 322 */ 0x63 /* 'c' */, 0x07, 0x00 /* (to 0x028F state 323) */, - 0x74 /* 't' */, 0x0B, 0x00 /* (to 0x0296 state 329) */, - 0x08, /* fail */ -/* pos 028f: 323 */ 0xE8 /* 'h' -> */, -/* pos 0290: 324 */ 0xE5 /* 'e' -> */, -/* pos 0291: 325 */ 0xED /* 'm' -> */, -/* pos 0292: 326 */ 0xE5 /* 'e' -> */, -/* pos 0293: 327 */ 0xBA /* ':' -> */, -/* pos 0294: 328 */ 0x00, 0x26 /* - terminal marker 38 - */, -/* pos 0296: 329 */ 0xE1 /* 'a' -> */, -/* pos 0297: 330 */ 0xF4 /* 't' -> */, -/* pos 0298: 331 */ 0xF5 /* 'u' -> */, -/* pos 0299: 332 */ 0xF3 /* 's' -> */, -/* pos 029a: 333 */ 0xBA /* ':' -> */, -/* pos 029b: 334 */ 0x00, 0x27 /* - terminal marker 39 - */, -/* pos 029d: 335 */ 0xE8 /* 'h' -> */, -/* pos 029e: 336 */ 0xE1 /* 'a' -> */, -/* pos 029f: 337 */ 0xF2 /* 'r' -> */, -/* pos 02a0: 338 */ 0xF3 /* 's' -> */, -/* pos 02a1: 339 */ 0xE5 /* 'e' -> */, -/* pos 02a2: 340 */ 0xF4 /* 't' -> */, -/* pos 02a3: 341 */ 0xBA /* ':' -> */, -/* pos 02a4: 342 */ 0x00, 0x28 /* - terminal marker 40 - */, -/* pos 02a6: 343 */ 0xE1 /* 'a' -> */, -/* pos 02a7: 344 */ 0xEE /* 'n' -> */, -/* pos 02a8: 345 */ 0xE7 /* 'g' -> */, -/* pos 02a9: 346 */ 0xE5 /* 'e' -> */, -/* pos 02aa: 347 */ 0xF3 /* 's' -> */, -/* pos 02ab: 348 */ 0xBA /* ':' -> */, -/* pos 02ac: 349 */ 0x00, 0x29 /* - terminal marker 41 - */, -/* pos 02ae: 350 */ 0xEC /* 'l' -> */, -/* pos 02af: 351 */ 0xEC /* 'l' -> */, -/* pos 02b0: 352 */ 0xEF /* 'o' -> */, -/* pos 02b1: 353 */ 0xF7 /* 'w' -> */, -/* pos 02b2: 354 */ 0xAD /* '-' -> */, -/* pos 02b3: 355 */ 0xEF /* 'o' -> */, -/* pos 02b4: 356 */ 0xF2 /* 'r' -> */, -/* pos 02b5: 357 */ 0xE9 /* 'i' -> */, -/* pos 02b6: 358 */ 0xE7 /* 'g' -> */, -/* pos 02b7: 359 */ 0xE9 /* 'i' -> */, -/* pos 02b8: 360 */ 0xEE /* 'n' -> */, -/* pos 02b9: 361 */ 0xBA /* ':' -> */, -/* pos 02ba: 362 */ 0x00, 0x2A /* - terminal marker 42 - */, -/* pos 02bc: 363 */ 0xE5 /* 'e' -> */, -/* pos 02bd: 364 */ 0xBA /* ':' -> */, -/* pos 02be: 365 */ 0x00, 0x2B /* - terminal marker 43 - */, -/* pos 02c0: 366 */ 0xEC /* 'l' -> */, -/* pos 02c1: 367 */ 0xEF /* 'o' -> */, -/* pos 02c2: 368 */ 0xF7 /* 'w' -> */, -/* pos 02c3: 369 */ 0xBA /* ':' -> */, -/* pos 02c4: 370 */ 0x00, 0x2C /* - terminal marker 44 - */, -/* pos 02c6: 371 */ 0xE9 /* 'i' -> */, -/* pos 02c7: 372 */ 0xF3 /* 's' -> */, -/* pos 02c8: 373 */ 0xF0 /* 'p' -> */, -/* pos 02c9: 374 */ 0xEF /* 'o' -> */, -/* pos 02ca: 375 */ 0xF3 /* 's' -> */, -/* pos 02cb: 376 */ 0xE9 /* 'i' -> */, -/* pos 02cc: 377 */ 0xF4 /* 't' -> */, -/* pos 02cd: 378 */ 0xE9 /* 'i' -> */, -/* pos 02ce: 379 */ 0xEF /* 'o' -> */, -/* pos 02cf: 380 */ 0xEE /* 'n' -> */, -/* pos 02d0: 381 */ 0xBA /* ':' -> */, -/* pos 02d1: 382 */ 0x00, 0x2D /* - terminal marker 45 - */, -/* pos 02d3: 383 */ 0xEE /* 'n' -> */, -/* pos 02d4: 384 */ 0xE3 /* 'c' -> */, -/* pos 02d5: 385 */ 0xEF /* 'o' -> */, -/* pos 02d6: 386 */ 0xE4 /* 'd' -> */, -/* pos 02d7: 387 */ 0xE9 /* 'i' -> */, -/* pos 02d8: 388 */ 0xEE /* 'n' -> */, -/* pos 02d9: 389 */ 0xE7 /* 'g' -> */, -/* pos 02da: 390 */ 0xBA /* ':' -> */, -/* pos 02db: 391 */ 0x00, 0x2E /* - terminal marker 46 - */, -/* pos 02dd: 392 */ 0xEE /* 'n' -> */, -/* pos 02de: 393 */ 0xE7 /* 'g' -> */, -/* pos 02df: 394 */ 0xF5 /* 'u' -> */, -/* pos 02e0: 395 */ 0xE1 /* 'a' -> */, -/* pos 02e1: 396 */ 0xE7 /* 'g' -> */, -/* pos 02e2: 397 */ 0xE5 /* 'e' -> */, -/* pos 02e3: 398 */ 0xBA /* ':' -> */, -/* pos 02e4: 399 */ 0x00, 0x2F /* - terminal marker 47 - */, -/* pos 02e6: 400 */ 0xE3 /* 'c' -> */, -/* pos 02e7: 401 */ 0xE1 /* 'a' -> */, -/* pos 02e8: 402 */ 0xF4 /* 't' -> */, -/* pos 02e9: 403 */ 0xE9 /* 'i' -> */, -/* pos 02ea: 404 */ 0xEF /* 'o' -> */, -/* pos 02eb: 405 */ 0xEE /* 'n' -> */, -/* pos 02ec: 406 */ 0xBA /* ':' -> */, -/* pos 02ed: 407 */ 0x00, 0x30 /* - terminal marker 48 - */, -/* pos 02ef: 408 */ 0xE1 /* 'a' -> */, -/* pos 02f0: 409 */ 0xEE /* 'n' -> */, -/* pos 02f1: 410 */ 0xE7 /* 'g' -> */, -/* pos 02f2: 411 */ 0xE5 /* 'e' -> */, -/* pos 02f3: 412 */ 0xBA /* ':' -> */, -/* pos 02f4: 413 */ 0x00, 0x31 /* - terminal marker 49 - */, -/* pos 02f6: 414 */ 0x74 /* 't' */, 0x07, 0x00 /* (to 0x02FD state 415) */, - 0x78 /* 'x' */, 0x09, 0x00 /* (to 0x0302 state 419) */, - 0x08, /* fail */ -/* pos 02fd: 415 */ 0xE1 /* 'a' -> */, -/* pos 02fe: 416 */ 0xE7 /* 'g' -> */, -/* pos 02ff: 417 */ 0xBA /* ':' -> */, -/* pos 0300: 418 */ 0x00, 0x32 /* - terminal marker 50 - */, -/* pos 0302: 419 */ 0xF0 /* 'p' -> */, -/* pos 0303: 420 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x030A state 421) */, - 0x69 /* 'i' */, 0x09, 0x00 /* (to 0x030F state 425) */, - 0x08, /* fail */ -/* pos 030a: 421 */ 0xE3 /* 'c' -> */, -/* pos 030b: 422 */ 0xF4 /* 't' -> */, -/* pos 030c: 423 */ 0xBA /* ':' -> */, -/* pos 030d: 424 */ 0x00, 0x33 /* - terminal marker 51 - */, -/* pos 030f: 425 */ 0xF2 /* 'r' -> */, -/* pos 0310: 426 */ 0xE5 /* 'e' -> */, -/* pos 0311: 427 */ 0xF3 /* 's' -> */, -/* pos 0312: 428 */ 0xBA /* ':' -> */, -/* pos 0313: 429 */ 0x00, 0x34 /* - terminal marker 52 - */, -/* pos 0315: 430 */ 0xF2 /* 'r' -> */, -/* pos 0316: 431 */ 0xEF /* 'o' -> */, -/* pos 0317: 432 */ 0xED /* 'm' -> */, -/* pos 0318: 433 */ 0xBA /* ':' -> */, -/* pos 0319: 434 */ 0x00, 0x35 /* - terminal marker 53 - */, -/* pos 031b: 435 */ 0xF4 /* 't' -> */, -/* pos 031c: 436 */ 0xE3 /* 'c' -> */, -/* pos 031d: 437 */ 0xE8 /* 'h' -> */, -/* pos 031e: 438 */ 0xBA /* ':' -> */, -/* pos 031f: 439 */ 0x00, 0x36 /* - terminal marker 54 - */, -/* pos 0321: 440 */ 0xE1 /* 'a' -> */, -/* pos 0322: 441 */ 0xEE /* 'n' -> */, -/* pos 0323: 442 */ 0xE7 /* 'g' -> */, -/* pos 0324: 443 */ 0xE5 /* 'e' -> */, -/* pos 0325: 444 */ 0xBA /* ':' -> */, -/* pos 0326: 445 */ 0x00, 0x37 /* - terminal marker 55 - */, -/* pos 0328: 446 */ 0xEE /* 'n' -> */, -/* pos 0329: 447 */ 0xED /* 'm' -> */, -/* pos 032a: 448 */ 0xEF /* 'o' -> */, -/* pos 032b: 449 */ 0xE4 /* 'd' -> */, -/* pos 032c: 450 */ 0xE9 /* 'i' -> */, -/* pos 032d: 451 */ 0xE6 /* 'f' -> */, -/* pos 032e: 452 */ 0xE9 /* 'i' -> */, -/* pos 032f: 453 */ 0xE5 /* 'e' -> */, -/* pos 0330: 454 */ 0xE4 /* 'd' -> */, -/* pos 0331: 455 */ 0xAD /* '-' -> */, -/* pos 0332: 456 */ 0xF3 /* 's' -> */, -/* pos 0333: 457 */ 0xE9 /* 'i' -> */, -/* pos 0334: 458 */ 0xEE /* 'n' -> */, -/* pos 0335: 459 */ 0xE3 /* 'c' -> */, -/* pos 0336: 460 */ 0xE5 /* 'e' -> */, -/* pos 0337: 461 */ 0xBA /* ':' -> */, -/* pos 0338: 462 */ 0x00, 0x38 /* - terminal marker 56 - */, -/* pos 033a: 463 */ 0x61 /* 'a' */, 0x0A, 0x00 /* (to 0x0344 state 464) */, - 0x69 /* 'i' */, 0x15, 0x00 /* (to 0x0352 state 477) */, - 0x6F /* 'o' */, 0x17, 0x00 /* (to 0x0357 state 481) */, - 0x08, /* fail */ -/* pos 0344: 464 */ 0xF3 /* 's' -> */, -/* pos 0345: 465 */ 0xF4 /* 't' -> */, -/* pos 0346: 466 */ 0xAD /* '-' -> */, -/* pos 0347: 467 */ 0xED /* 'm' -> */, -/* pos 0348: 468 */ 0xEF /* 'o' -> */, -/* pos 0349: 469 */ 0xE4 /* 'd' -> */, -/* pos 034a: 470 */ 0xE9 /* 'i' -> */, -/* pos 034b: 471 */ 0xE6 /* 'f' -> */, -/* pos 034c: 472 */ 0xE9 /* 'i' -> */, -/* pos 034d: 473 */ 0xE5 /* 'e' -> */, -/* pos 034e: 474 */ 0xE4 /* 'd' -> */, -/* pos 034f: 475 */ 0xBA /* ':' -> */, -/* pos 0350: 476 */ 0x00, 0x39 /* - terminal marker 57 - */, -/* pos 0352: 477 */ 0xEE /* 'n' -> */, -/* pos 0353: 478 */ 0xEB /* 'k' -> */, -/* pos 0354: 479 */ 0xBA /* ':' -> */, -/* pos 0355: 480 */ 0x00, 0x3A /* - terminal marker 58 - */, -/* pos 0357: 481 */ 0xE3 /* 'c' -> */, -/* pos 0358: 482 */ 0xE1 /* 'a' -> */, -/* pos 0359: 483 */ 0xF4 /* 't' -> */, -/* pos 035a: 484 */ 0xE9 /* 'i' -> */, -/* pos 035b: 485 */ 0xEF /* 'o' -> */, -/* pos 035c: 486 */ 0xEE /* 'n' -> */, -/* pos 035d: 487 */ 0xBA /* ':' -> */, -/* pos 035e: 488 */ 0x00, 0x3B /* - terminal marker 59 - */, -/* pos 0360: 489 */ 0xE1 /* 'a' -> */, -/* pos 0361: 490 */ 0xF8 /* 'x' -> */, -/* pos 0362: 491 */ 0xAD /* '-' -> */, -/* pos 0363: 492 */ 0xE6 /* 'f' -> */, -/* pos 0364: 493 */ 0xEF /* 'o' -> */, -/* pos 0365: 494 */ 0xF2 /* 'r' -> */, -/* pos 0366: 495 */ 0xF7 /* 'w' -> */, -/* pos 0367: 496 */ 0xE1 /* 'a' -> */, -/* pos 0368: 497 */ 0xF2 /* 'r' -> */, -/* pos 0369: 498 */ 0xE4 /* 'd' -> */, -/* pos 036a: 499 */ 0xF3 /* 's' -> */, -/* pos 036b: 500 */ 0xBA /* ':' -> */, -/* pos 036c: 501 */ 0x00, 0x3C /* - terminal marker 60 - */, -/* pos 036e: 502 */ 0xF8 /* 'x' -> */, -/* pos 036f: 503 */ 0xF9 /* 'y' -> */, -/* pos 0370: 504 */ 0x2D /* '-' */, 0x07, 0x00 /* (to 0x0377 state 505) */, - 0x20 /* ' ' */, 0x9F, 0x00 /* (to 0x0412 state 636) */, - 0x08, /* fail */ -/* pos 0377: 505 */ 0xE1 /* 'a' -> */, -/* pos 0378: 506 */ 0xF5 /* 'u' -> */, -/* pos 0379: 507 */ 0xF4 /* 't' -> */, -/* pos 037a: 508 */ 0xE8 /* 'h' -> */, -/* pos 037b: 509 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x0382 state 510) */, - 0x6F /* 'o' */, 0x0E, 0x00 /* (to 0x038C state 519) */, - 0x08, /* fail */ -/* pos 0382: 510 */ 0xEE /* 'n' -> */, -/* pos 0383: 511 */ 0xF4 /* 't' -> */, -/* pos 0384: 512 */ 0xE9 /* 'i' -> */, -/* pos 0385: 513 */ 0xE3 /* 'c' -> */, -/* pos 0386: 514 */ 0xE1 /* 'a' -> */, -/* pos 0387: 515 */ 0xF4 /* 't' -> */, -/* pos 0388: 516 */ 0xE5 /* 'e' -> */, -/* pos 0389: 517 */ 0xBA /* ':' -> */, -/* pos 038a: 518 */ 0x00, 0x3D /* - terminal marker 61 - */, -/* pos 038c: 519 */ 0xF2 /* 'r' -> */, -/* pos 038d: 520 */ 0xE9 /* 'i' -> */, -/* pos 038e: 521 */ 0xFA /* 'z' -> */, -/* pos 038f: 522 */ 0xE1 /* 'a' -> */, -/* pos 0390: 523 */ 0xF4 /* 't' -> */, -/* pos 0391: 524 */ 0xE9 /* 'i' -> */, -/* pos 0392: 525 */ 0xEF /* 'o' -> */, -/* pos 0393: 526 */ 0xEE /* 'n' -> */, -/* pos 0394: 527 */ 0xBA /* ':' -> */, -/* pos 0395: 528 */ 0x00, 0x3E /* - terminal marker 62 - */, -/* pos 0397: 529 */ 0xE5 /* 'e' -> */, -/* pos 0398: 530 */ 0xF3 /* 's' -> */, -/* pos 0399: 531 */ 0xE8 /* 'h' -> */, -/* pos 039a: 532 */ 0xBA /* ':' -> */, -/* pos 039b: 533 */ 0x00, 0x3F /* - terminal marker 63 - */, -/* pos 039d: 534 */ 0xF2 /* 'r' -> */, -/* pos 039e: 535 */ 0xF9 /* 'y' -> */, -/* pos 039f: 536 */ 0xAD /* '-' -> */, -/* pos 03a0: 537 */ 0xE1 /* 'a' -> */, -/* pos 03a1: 538 */ 0xE6 /* 'f' -> */, -/* pos 03a2: 539 */ 0xF4 /* 't' -> */, -/* pos 03a3: 540 */ 0xE5 /* 'e' -> */, -/* pos 03a4: 541 */ 0xF2 /* 'r' -> */, -/* pos 03a5: 542 */ 0xBA /* ':' -> */, -/* pos 03a6: 543 */ 0x00, 0x40 /* - terminal marker 64 - */, -/* pos 03a8: 544 */ 0xF6 /* 'v' -> */, -/* pos 03a9: 545 */ 0xE5 /* 'e' -> */, -/* pos 03aa: 546 */ 0xF2 /* 'r' -> */, -/* pos 03ab: 547 */ 0xBA /* ':' -> */, -/* pos 03ac: 548 */ 0x00, 0x41 /* - terminal marker 65 - */, -/* pos 03ae: 549 */ 0xAD /* '-' -> */, -/* pos 03af: 550 */ 0xE3 /* 'c' -> */, -/* pos 03b0: 551 */ 0xEF /* 'o' -> */, -/* pos 03b1: 552 */ 0xEF /* 'o' -> */, -/* pos 03b2: 553 */ 0xEB /* 'k' -> */, -/* pos 03b3: 554 */ 0xE9 /* 'i' -> */, -/* pos 03b4: 555 */ 0xE5 /* 'e' -> */, -/* pos 03b5: 556 */ 0xBA /* ':' -> */, -/* pos 03b6: 557 */ 0x00, 0x42 /* - terminal marker 66 - */, -/* pos 03b8: 558 */ 0xF2 /* 'r' -> */, -/* pos 03b9: 559 */ 0xE9 /* 'i' -> */, -/* pos 03ba: 560 */ 0xE3 /* 'c' -> */, -/* pos 03bb: 561 */ 0xF4 /* 't' -> */, -/* pos 03bc: 562 */ 0xAD /* '-' -> */, -/* pos 03bd: 563 */ 0xF4 /* 't' -> */, -/* pos 03be: 564 */ 0xF2 /* 'r' -> */, -/* pos 03bf: 565 */ 0xE1 /* 'a' -> */, -/* pos 03c0: 566 */ 0xEE /* 'n' -> */, -/* pos 03c1: 567 */ 0xF3 /* 's' -> */, -/* pos 03c2: 568 */ 0xF0 /* 'p' -> */, -/* pos 03c3: 569 */ 0xEF /* 'o' -> */, -/* pos 03c4: 570 */ 0xF2 /* 'r' -> */, -/* pos 03c5: 571 */ 0xF4 /* 't' -> */, -/* pos 03c6: 572 */ 0xAD /* '-' -> */, -/* pos 03c7: 573 */ 0xF3 /* 's' -> */, -/* pos 03c8: 574 */ 0xE5 /* 'e' -> */, -/* pos 03c9: 575 */ 0xE3 /* 'c' -> */, -/* pos 03ca: 576 */ 0xF5 /* 'u' -> */, -/* pos 03cb: 577 */ 0xF2 /* 'r' -> */, -/* pos 03cc: 578 */ 0xE9 /* 'i' -> */, -/* pos 03cd: 579 */ 0xF4 /* 't' -> */, -/* pos 03ce: 580 */ 0xF9 /* 'y' -> */, -/* pos 03cf: 581 */ 0xBA /* ':' -> */, -/* pos 03d0: 582 */ 0x00, 0x43 /* - terminal marker 67 - */, -/* pos 03d2: 583 */ 0xF2 /* 'r' -> */, -/* pos 03d3: 584 */ 0xE1 /* 'a' -> */, -/* pos 03d4: 585 */ 0xEE /* 'n' -> */, -/* pos 03d5: 586 */ 0xF3 /* 's' -> */, -/* pos 03d6: 587 */ 0xE6 /* 'f' -> */, -/* pos 03d7: 588 */ 0xE5 /* 'e' -> */, -/* pos 03d8: 589 */ 0xF2 /* 'r' -> */, -/* pos 03d9: 590 */ 0xAD /* '-' -> */, -/* pos 03da: 591 */ 0xE5 /* 'e' -> */, -/* pos 03db: 592 */ 0xEE /* 'n' -> */, -/* pos 03dc: 593 */ 0xE3 /* 'c' -> */, -/* pos 03dd: 594 */ 0xEF /* 'o' -> */, -/* pos 03de: 595 */ 0xE4 /* 'd' -> */, -/* pos 03df: 596 */ 0xE9 /* 'i' -> */, -/* pos 03e0: 597 */ 0xEE /* 'n' -> */, -/* pos 03e1: 598 */ 0xE7 /* 'g' -> */, -/* pos 03e2: 599 */ 0xBA /* ':' -> */, -/* pos 03e3: 600 */ 0x00, 0x44 /* - terminal marker 68 - */, -/* pos 03e5: 601 */ 0xE5 /* 'e' -> */, -/* pos 03e6: 602 */ 0xF2 /* 'r' -> */, -/* pos 03e7: 603 */ 0xAD /* '-' -> */, -/* pos 03e8: 604 */ 0xE1 /* 'a' -> */, -/* pos 03e9: 605 */ 0xE7 /* 'g' -> */, -/* pos 03ea: 606 */ 0xE5 /* 'e' -> */, -/* pos 03eb: 607 */ 0xEE /* 'n' -> */, -/* pos 03ec: 608 */ 0xF4 /* 't' -> */, -/* pos 03ed: 609 */ 0xBA /* ':' -> */, -/* pos 03ee: 610 */ 0x00, 0x45 /* - terminal marker 69 - */, -/* pos 03f0: 611 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x03F7 state 612) */, - 0x69 /* 'i' */, 0x09, 0x00 /* (to 0x03FC state 616) */, - 0x08, /* fail */ -/* pos 03f7: 612 */ 0xF2 /* 'r' -> */, -/* pos 03f8: 613 */ 0xF9 /* 'y' -> */, -/* pos 03f9: 614 */ 0xBA /* ':' -> */, -/* pos 03fa: 615 */ 0x00, 0x46 /* - terminal marker 70 - */, -/* pos 03fc: 616 */ 0xE1 /* 'a' -> */, -/* pos 03fd: 617 */ 0xBA /* ':' -> */, -/* pos 03fe: 618 */ 0x00, 0x47 /* - terminal marker 71 - */, -/* pos 0400: 619 */ 0xF7 /* 'w' -> */, -/* pos 0401: 620 */ 0xF7 /* 'w' -> */, -/* pos 0402: 621 */ 0xAD /* '-' -> */, -/* pos 0403: 622 */ 0xE1 /* 'a' -> */, -/* pos 0404: 623 */ 0xF5 /* 'u' -> */, -/* pos 0405: 624 */ 0xF4 /* 't' -> */, -/* pos 0406: 625 */ 0xE8 /* 'h' -> */, -/* pos 0407: 626 */ 0xE5 /* 'e' -> */, -/* pos 0408: 627 */ 0xEE /* 'n' -> */, -/* pos 0409: 628 */ 0xF4 /* 't' -> */, -/* pos 040a: 629 */ 0xE9 /* 'i' -> */, -/* pos 040b: 630 */ 0xE3 /* 'c' -> */, -/* pos 040c: 631 */ 0xE1 /* 'a' -> */, -/* pos 040d: 632 */ 0xF4 /* 't' -> */, -/* pos 040e: 633 */ 0xE5 /* 'e' -> */, -/* pos 040f: 634 */ 0xBA /* ':' -> */, -/* pos 0410: 635 */ 0x00, 0x48 /* - terminal marker 72 - */, -/* pos 0412: 636 */ 0x00, 0x49 /* - terminal marker 73 - */, -/* pos 0414: 637 */ 0xF4 /* 't' -> */, -/* pos 0415: 638 */ 0xE3 /* 'c' -> */, -/* pos 0416: 639 */ 0xE8 /* 'h' -> */, -/* pos 0417: 640 */ 0x00, 0x4A /* - terminal marker 74 - */, -/* pos 0419: 641 */ 0xF4 /* 't' -> */, -/* pos 041a: 642 */ 0x00, 0x4B /* - terminal marker 75 - */, -/* pos 041c: 643 */ 0xEC /* 'l' -> */, -/* pos 041d: 644 */ 0xE5 /* 'e' -> */, -/* pos 041e: 645 */ 0xF4 /* 't' -> */, -/* pos 041f: 646 */ 0xE5 /* 'e' -> */, -/* pos 0420: 647 */ 0x00, 0x4C /* - terminal marker 76 - */, -/* total size 1058 bytes */ +/* pos 0000: 0 */ 0x67 /* 'g' */, 0x25, 0x00 /* (to 0x0025 state 1) */, + 0x70 /* 'p' */, 0x27, 0x00 /* (to 0x002A state 5) */, + 0x6F /* 'o' */, 0x30, 0x00 /* (to 0x0036 state 10) */, + 0x68 /* 'h' */, 0x3C, 0x00 /* (to 0x0045 state 18) */, + 0x63 /* 'c' */, 0x45, 0x00 /* (to 0x0051 state 23) */, + 0x73 /* 's' */, 0x60, 0x00 /* (to 0x006F state 34) */, + 0x75 /* 'u' */, 0x9F, 0x00 /* (to 0x00B1 state 64) */, + 0x0D /* '.' */, 0xB3, 0x00 /* (to 0x00C8 state 84) */, + 0x61 /* 'a' */, 0xEA, 0x00 /* (to 0x0102 state 134) */, + 0x69 /* 'i' */, 0x1D, 0x01 /* (to 0x0138 state 168) */, + 0x64 /* 'd' */, 0x9C, 0x01 /* (to 0x01BA state 270) */, + 0x72 /* 'r' */, 0x9F, 0x01 /* (to 0x01C0 state 275) */, + 0x08, /* fail */ +/* pos 0025: 1 */ 0xE5 /* 'e' -> */, +/* pos 0026: 2 */ 0xF4 /* 't' -> */, +/* pos 0027: 3 */ 0xA0 /* ' ' -> */, +/* pos 0028: 4 */ 0x00, 0x00 /* - terminal marker 0 - */, +/* pos 002a: 5 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x0031 state 6) */, + 0x72 /* 'r' */, 0x4B, 0x01 /* (to 0x0178 state 216) */, + 0x08, /* fail */ +/* pos 0031: 6 */ 0xF3 /* 's' -> */, +/* pos 0032: 7 */ 0xF4 /* 't' -> */, +/* pos 0033: 8 */ 0xA0 /* ' ' -> */, +/* pos 0034: 9 */ 0x00, 0x01 /* - terminal marker 1 - */, +/* pos 0036: 10 */ 0x70 /* 'p' */, 0x07, 0x00 /* (to 0x003D state 11) */, + 0x72 /* 'r' */, 0x81, 0x00 /* (to 0x00BA state 72) */, + 0x08, /* fail */ +/* pos 003d: 11 */ 0xF4 /* 't' -> */, +/* pos 003e: 12 */ 0xE9 /* 'i' -> */, +/* pos 003f: 13 */ 0xEF /* 'o' -> */, +/* pos 0040: 14 */ 0xEE /* 'n' -> */, +/* pos 0041: 15 */ 0xF3 /* 's' -> */, +/* pos 0042: 16 */ 0xA0 /* ' ' -> */, +/* pos 0043: 17 */ 0x00, 0x02 /* - terminal marker 2 - */, +/* pos 0045: 18 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x004C state 19) */, + 0x74 /* 't' */, 0xB1, 0x00 /* (to 0x00F9 state 126) */, + 0x08, /* fail */ +/* pos 004c: 19 */ 0xF3 /* 's' -> */, +/* pos 004d: 20 */ 0xF4 /* 't' -> */, +/* pos 004e: 21 */ 0xBA /* ':' -> */, +/* pos 004f: 22 */ 0x00, 0x03 /* - terminal marker 3 - */, +/* pos 0051: 23 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x0058 state 24) */, + 0x61 /* 'a' */, 0x2B, 0x01 /* (to 0x017F state 222) */, + 0x08, /* fail */ +/* pos 0058: 24 */ 0x6E /* 'n' */, 0x07, 0x00 /* (to 0x005F state 25) */, + 0x6F /* 'o' */, 0x40, 0x01 /* (to 0x019B state 248) */, + 0x08, /* fail */ +/* pos 005f: 25 */ 0x6E /* 'n' */, 0x07, 0x00 /* (to 0x0066 state 26) */, + 0x74 /* 't' */, 0x3F, 0x01 /* (to 0x01A1 state 253) */, + 0x08, /* fail */ +/* pos 0066: 26 */ 0xE5 /* 'e' -> */, +/* pos 0067: 27 */ 0xE3 /* 'c' -> */, +/* pos 0068: 28 */ 0xF4 /* 't' -> */, +/* pos 0069: 29 */ 0xE9 /* 'i' -> */, +/* pos 006a: 30 */ 0xEF /* 'o' -> */, +/* pos 006b: 31 */ 0xEE /* 'n' -> */, +/* pos 006c: 32 */ 0xBA /* ':' -> */, +/* pos 006d: 33 */ 0x00, 0x04 /* - terminal marker 4 - */, +/* pos 006f: 34 */ 0xE5 /* 'e' -> */, +/* pos 0070: 35 */ 0xE3 /* 'c' -> */, +/* pos 0071: 36 */ 0xAD /* '-' -> */, +/* pos 0072: 37 */ 0xF7 /* 'w' -> */, +/* pos 0073: 38 */ 0xE5 /* 'e' -> */, +/* pos 0074: 39 */ 0xE2 /* 'b' -> */, +/* pos 0075: 40 */ 0xF3 /* 's' -> */, +/* pos 0076: 41 */ 0xEF /* 'o' -> */, +/* pos 0077: 42 */ 0xE3 /* 'c' -> */, +/* pos 0078: 43 */ 0xEB /* 'k' -> */, +/* pos 0079: 44 */ 0xE5 /* 'e' -> */, +/* pos 007a: 45 */ 0xF4 /* 't' -> */, +/* pos 007b: 46 */ 0xAD /* '-' -> */, +/* pos 007c: 47 */ 0x6B /* 'k' */, 0x19, 0x00 /* (to 0x0095 state 48) */, + 0x70 /* 'p' */, 0x28, 0x00 /* (to 0x00A7 state 55) */, + 0x64 /* 'd' */, 0x3F, 0x00 /* (to 0x00C1 state 78) */, + 0x76 /* 'v' */, 0x48, 0x00 /* (to 0x00CD state 87) */, + 0x6F /* 'o' */, 0x4E, 0x00 /* (to 0x00D6 state 95) */, + 0x65 /* 'e' */, 0x53, 0x00 /* (to 0x00DE state 102) */, + 0x61 /* 'a' */, 0x5C, 0x00 /* (to 0x00EA state 113) */, + 0x6E /* 'n' */, 0x61, 0x00 /* (to 0x00F2 state 120) */, + 0x08, /* fail */ +/* pos 0095: 48 */ 0xE5 /* 'e' -> */, +/* pos 0096: 49 */ 0xF9 /* 'y' -> */, +/* pos 0097: 50 */ 0x31 /* '1' */, 0x0A, 0x00 /* (to 0x00A1 state 51) */, + 0x32 /* '2' */, 0x0A, 0x00 /* (to 0x00A4 state 53) */, + 0x3A /* ':' */, 0x2E, 0x00 /* (to 0x00CB state 86) */, + 0x08, /* fail */ +/* pos 00a1: 51 */ 0xBA /* ':' -> */, +/* pos 00a2: 52 */ 0x00, 0x05 /* - terminal marker 5 - */, +/* pos 00a4: 53 */ 0xBA /* ':' -> */, +/* pos 00a5: 54 */ 0x00, 0x06 /* - terminal marker 6 - */, +/* pos 00a7: 55 */ 0xF2 /* 'r' -> */, +/* pos 00a8: 56 */ 0xEF /* 'o' -> */, +/* pos 00a9: 57 */ 0xF4 /* 't' -> */, +/* pos 00aa: 58 */ 0xEF /* 'o' -> */, +/* pos 00ab: 59 */ 0xE3 /* 'c' -> */, +/* pos 00ac: 60 */ 0xEF /* 'o' -> */, +/* pos 00ad: 61 */ 0xEC /* 'l' -> */, +/* pos 00ae: 62 */ 0xBA /* ':' -> */, +/* pos 00af: 63 */ 0x00, 0x07 /* - terminal marker 7 - */, +/* pos 00b1: 64 */ 0xF0 /* 'p' -> */, +/* pos 00b2: 65 */ 0xE7 /* 'g' -> */, +/* pos 00b3: 66 */ 0xF2 /* 'r' -> */, +/* pos 00b4: 67 */ 0xE1 /* 'a' -> */, +/* pos 00b5: 68 */ 0xE4 /* 'd' -> */, +/* pos 00b6: 69 */ 0xE5 /* 'e' -> */, +/* pos 00b7: 70 */ 0xBA /* ':' -> */, +/* pos 00b8: 71 */ 0x00, 0x08 /* - terminal marker 8 - */, +/* pos 00ba: 72 */ 0xE9 /* 'i' -> */, +/* pos 00bb: 73 */ 0xE7 /* 'g' -> */, +/* pos 00bc: 74 */ 0xE9 /* 'i' -> */, +/* pos 00bd: 75 */ 0xEE /* 'n' -> */, +/* pos 00be: 76 */ 0xBA /* ':' -> */, +/* pos 00bf: 77 */ 0x00, 0x09 /* - terminal marker 9 - */, +/* pos 00c1: 78 */ 0xF2 /* 'r' -> */, +/* pos 00c2: 79 */ 0xE1 /* 'a' -> */, +/* pos 00c3: 80 */ 0xE6 /* 'f' -> */, +/* pos 00c4: 81 */ 0xF4 /* 't' -> */, +/* pos 00c5: 82 */ 0xBA /* ':' -> */, +/* pos 00c6: 83 */ 0x00, 0x0A /* - terminal marker 10 - */, +/* pos 00c8: 84 */ 0x8A /* '.' -> */, +/* pos 00c9: 85 */ 0x00, 0x0B /* - terminal marker 11 - */, +/* pos 00cb: 86 */ 0x00, 0x0C /* - terminal marker 12 - */, +/* pos 00cd: 87 */ 0xE5 /* 'e' -> */, +/* pos 00ce: 88 */ 0xF2 /* 'r' -> */, +/* pos 00cf: 89 */ 0xF3 /* 's' -> */, +/* pos 00d0: 90 */ 0xE9 /* 'i' -> */, +/* pos 00d1: 91 */ 0xEF /* 'o' -> */, +/* pos 00d2: 92 */ 0xEE /* 'n' -> */, +/* pos 00d3: 93 */ 0xBA /* ':' -> */, +/* pos 00d4: 94 */ 0x00, 0x0D /* - terminal marker 13 - */, +/* pos 00d6: 95 */ 0xF2 /* 'r' -> */, +/* pos 00d7: 96 */ 0xE9 /* 'i' -> */, +/* pos 00d8: 97 */ 0xE7 /* 'g' -> */, +/* pos 00d9: 98 */ 0xE9 /* 'i' -> */, +/* pos 00da: 99 */ 0xEE /* 'n' -> */, +/* pos 00db: 100 */ 0xBA /* ':' -> */, +/* pos 00dc: 101 */ 0x00, 0x0E /* - terminal marker 14 - */, +/* pos 00de: 102 */ 0xF8 /* 'x' -> */, +/* pos 00df: 103 */ 0xF4 /* 't' -> */, +/* pos 00e0: 104 */ 0xE5 /* 'e' -> */, +/* pos 00e1: 105 */ 0xEE /* 'n' -> */, +/* pos 00e2: 106 */ 0xF3 /* 's' -> */, +/* pos 00e3: 107 */ 0xE9 /* 'i' -> */, +/* pos 00e4: 108 */ 0xEF /* 'o' -> */, +/* pos 00e5: 109 */ 0xEE /* 'n' -> */, +/* pos 00e6: 110 */ 0xF3 /* 's' -> */, +/* pos 00e7: 111 */ 0xBA /* ':' -> */, +/* pos 00e8: 112 */ 0x00, 0x0F /* - terminal marker 15 - */, +/* pos 00ea: 113 */ 0xE3 /* 'c' -> */, +/* pos 00eb: 114 */ 0xE3 /* 'c' -> */, +/* pos 00ec: 115 */ 0xE5 /* 'e' -> */, +/* pos 00ed: 116 */ 0xF0 /* 'p' -> */, +/* pos 00ee: 117 */ 0xF4 /* 't' -> */, +/* pos 00ef: 118 */ 0xBA /* ':' -> */, +/* pos 00f0: 119 */ 0x00, 0x10 /* - terminal marker 16 - */, +/* pos 00f2: 120 */ 0xEF /* 'o' -> */, +/* pos 00f3: 121 */ 0xEE /* 'n' -> */, +/* pos 00f4: 122 */ 0xE3 /* 'c' -> */, +/* pos 00f5: 123 */ 0xE5 /* 'e' -> */, +/* pos 00f6: 124 */ 0xBA /* ':' -> */, +/* pos 00f7: 125 */ 0x00, 0x11 /* - terminal marker 17 - */, +/* pos 00f9: 126 */ 0xF4 /* 't' -> */, +/* pos 00fa: 127 */ 0xF0 /* 'p' -> */, +/* pos 00fb: 128 */ 0xAF /* '/' -> */, +/* pos 00fc: 129 */ 0xB1 /* '1' -> */, +/* pos 00fd: 130 */ 0xAE /* '.' -> */, +/* pos 00fe: 131 */ 0xB1 /* '1' -> */, +/* pos 00ff: 132 */ 0xA0 /* ' ' -> */, +/* pos 0100: 133 */ 0x00, 0x12 /* - terminal marker 18 - */, +/* pos 0102: 134 */ 0x63 /* 'c' */, 0x07, 0x00 /* (to 0x0109 state 135) */, + 0x75 /* 'u' */, 0x88, 0x00 /* (to 0x018D state 235) */, + 0x08, /* fail */ +/* pos 0109: 135 */ 0xE3 /* 'c' -> */, +/* pos 010a: 136 */ 0xE5 /* 'e' -> */, +/* pos 010b: 137 */ 0x70 /* 'p' */, 0x07, 0x00 /* (to 0x0112 state 138) */, + 0x73 /* 's' */, 0x0E, 0x00 /* (to 0x011C state 141) */, + 0x08, /* fail */ +/* pos 0112: 138 */ 0xF4 /* 't' -> */, +/* pos 0113: 139 */ 0x3A /* ':' */, 0x07, 0x00 /* (to 0x011A state 140) */, + 0x2D /* '-' */, 0x47, 0x00 /* (to 0x015D state 197) */, + 0x08, /* fail */ +/* pos 011a: 140 */ 0x00, 0x13 /* - terminal marker 19 - */, +/* pos 011c: 141 */ 0xF3 /* 's' -> */, +/* pos 011d: 142 */ 0xAD /* '-' -> */, +/* pos 011e: 143 */ 0xE3 /* 'c' -> */, +/* pos 011f: 144 */ 0xEF /* 'o' -> */, +/* pos 0120: 145 */ 0xEE /* 'n' -> */, +/* pos 0121: 146 */ 0xF4 /* 't' -> */, +/* pos 0122: 147 */ 0xF2 /* 'r' -> */, +/* pos 0123: 148 */ 0xEF /* 'o' -> */, +/* pos 0124: 149 */ 0xEC /* 'l' -> */, +/* pos 0125: 150 */ 0xAD /* '-' -> */, +/* pos 0126: 151 */ 0xF2 /* 'r' -> */, +/* pos 0127: 152 */ 0xE5 /* 'e' -> */, +/* pos 0128: 153 */ 0xF1 /* 'q' -> */, +/* pos 0129: 154 */ 0xF5 /* 'u' -> */, +/* pos 012a: 155 */ 0xE5 /* 'e' -> */, +/* pos 012b: 156 */ 0xF3 /* 's' -> */, +/* pos 012c: 157 */ 0xF4 /* 't' -> */, +/* pos 012d: 158 */ 0xAD /* '-' -> */, +/* pos 012e: 159 */ 0xE8 /* 'h' -> */, +/* pos 012f: 160 */ 0xE5 /* 'e' -> */, +/* pos 0130: 161 */ 0xE1 /* 'a' -> */, +/* pos 0131: 162 */ 0xE4 /* 'd' -> */, +/* pos 0132: 163 */ 0xE5 /* 'e' -> */, +/* pos 0133: 164 */ 0xF2 /* 'r' -> */, +/* pos 0134: 165 */ 0xF3 /* 's' -> */, +/* pos 0135: 166 */ 0xBA /* ':' -> */, +/* pos 0136: 167 */ 0x00, 0x14 /* - terminal marker 20 - */, +/* pos 0138: 168 */ 0xE6 /* 'f' -> */, +/* pos 0139: 169 */ 0xAD /* '-' -> */, +/* pos 013a: 170 */ 0x6D /* 'm' */, 0x07, 0x00 /* (to 0x0141 state 171) */, + 0x6E /* 'n' */, 0x14, 0x00 /* (to 0x0151 state 186) */, + 0x08, /* fail */ +/* pos 0141: 171 */ 0xEF /* 'o' -> */, +/* pos 0142: 172 */ 0xE4 /* 'd' -> */, +/* pos 0143: 173 */ 0xE9 /* 'i' -> */, +/* pos 0144: 174 */ 0xE6 /* 'f' -> */, +/* pos 0145: 175 */ 0xE9 /* 'i' -> */, +/* pos 0146: 176 */ 0xE5 /* 'e' -> */, +/* pos 0147: 177 */ 0xE4 /* 'd' -> */, +/* pos 0148: 178 */ 0xAD /* '-' -> */, +/* pos 0149: 179 */ 0xF3 /* 's' -> */, +/* pos 014a: 180 */ 0xE9 /* 'i' -> */, +/* pos 014b: 181 */ 0xEE /* 'n' -> */, +/* pos 014c: 182 */ 0xE3 /* 'c' -> */, +/* pos 014d: 183 */ 0xE5 /* 'e' -> */, +/* pos 014e: 184 */ 0xBA /* ':' -> */, +/* pos 014f: 185 */ 0x00, 0x15 /* - terminal marker 21 - */, +/* pos 0151: 186 */ 0xEF /* 'o' -> */, +/* pos 0152: 187 */ 0xEE /* 'n' -> */, +/* pos 0153: 188 */ 0xE5 /* 'e' -> */, +/* pos 0154: 189 */ 0xAD /* '-' -> */, +/* pos 0155: 190 */ 0xED /* 'm' -> */, +/* pos 0156: 191 */ 0xE1 /* 'a' -> */, +/* pos 0157: 192 */ 0xF4 /* 't' -> */, +/* pos 0158: 193 */ 0xE3 /* 'c' -> */, +/* pos 0159: 194 */ 0xE8 /* 'h' -> */, +/* pos 015a: 195 */ 0xBA /* ':' -> */, +/* pos 015b: 196 */ 0x00, 0x16 /* - terminal marker 22 - */, +/* pos 015d: 197 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x0164 state 198) */, + 0x6C /* 'l' */, 0x0E, 0x00 /* (to 0x016E state 207) */, + 0x08, /* fail */ +/* pos 0164: 198 */ 0xEE /* 'n' -> */, +/* pos 0165: 199 */ 0xE3 /* 'c' -> */, +/* pos 0166: 200 */ 0xEF /* 'o' -> */, +/* pos 0167: 201 */ 0xE4 /* 'd' -> */, +/* pos 0168: 202 */ 0xE9 /* 'i' -> */, +/* pos 0169: 203 */ 0xEE /* 'n' -> */, +/* pos 016a: 204 */ 0xE7 /* 'g' -> */, +/* pos 016b: 205 */ 0xBA /* ':' -> */, +/* pos 016c: 206 */ 0x00, 0x17 /* - terminal marker 23 - */, +/* pos 016e: 207 */ 0xE1 /* 'a' -> */, +/* pos 016f: 208 */ 0xEE /* 'n' -> */, +/* pos 0170: 209 */ 0xE7 /* 'g' -> */, +/* pos 0171: 210 */ 0xF5 /* 'u' -> */, +/* pos 0172: 211 */ 0xE1 /* 'a' -> */, +/* pos 0173: 212 */ 0xE7 /* 'g' -> */, +/* pos 0174: 213 */ 0xE5 /* 'e' -> */, +/* pos 0175: 214 */ 0xBA /* ':' -> */, +/* pos 0176: 215 */ 0x00, 0x18 /* - terminal marker 24 - */, +/* pos 0178: 216 */ 0xE1 /* 'a' -> */, +/* pos 0179: 217 */ 0xE7 /* 'g' -> */, +/* pos 017a: 218 */ 0xED /* 'm' -> */, +/* pos 017b: 219 */ 0xE1 /* 'a' -> */, +/* pos 017c: 220 */ 0xBA /* ':' -> */, +/* pos 017d: 221 */ 0x00, 0x19 /* - terminal marker 25 - */, +/* pos 017f: 222 */ 0xE3 /* 'c' -> */, +/* pos 0180: 223 */ 0xE8 /* 'h' -> */, +/* pos 0181: 224 */ 0xE5 /* 'e' -> */, +/* pos 0182: 225 */ 0xAD /* '-' -> */, +/* pos 0183: 226 */ 0xE3 /* 'c' -> */, +/* pos 0184: 227 */ 0xEF /* 'o' -> */, +/* pos 0185: 228 */ 0xEE /* 'n' -> */, +/* pos 0186: 229 */ 0xF4 /* 't' -> */, +/* pos 0187: 230 */ 0xF2 /* 'r' -> */, +/* pos 0188: 231 */ 0xEF /* 'o' -> */, +/* pos 0189: 232 */ 0xEC /* 'l' -> */, +/* pos 018a: 233 */ 0xBA /* ':' -> */, +/* pos 018b: 234 */ 0x00, 0x1A /* - terminal marker 26 - */, +/* pos 018d: 235 */ 0xF4 /* 't' -> */, +/* pos 018e: 236 */ 0xE8 /* 'h' -> */, +/* pos 018f: 237 */ 0xEF /* 'o' -> */, +/* pos 0190: 238 */ 0xF2 /* 'r' -> */, +/* pos 0191: 239 */ 0xE9 /* 'i' -> */, +/* pos 0192: 240 */ 0xFA /* 'z' -> */, +/* pos 0193: 241 */ 0xE1 /* 'a' -> */, +/* pos 0194: 242 */ 0xF4 /* 't' -> */, +/* pos 0195: 243 */ 0xE9 /* 'i' -> */, +/* pos 0196: 244 */ 0xEF /* 'o' -> */, +/* pos 0197: 245 */ 0xEE /* 'n' -> */, +/* pos 0198: 246 */ 0xBA /* ':' -> */, +/* pos 0199: 247 */ 0x00, 0x1B /* - terminal marker 27 - */, +/* pos 019b: 248 */ 0xEB /* 'k' -> */, +/* pos 019c: 249 */ 0xE9 /* 'i' -> */, +/* pos 019d: 250 */ 0xE5 /* 'e' -> */, +/* pos 019e: 251 */ 0xBA /* ':' -> */, +/* pos 019f: 252 */ 0x00, 0x1C /* - terminal marker 28 - */, +/* pos 01a1: 253 */ 0xE5 /* 'e' -> */, +/* pos 01a2: 254 */ 0xEE /* 'n' -> */, +/* pos 01a3: 255 */ 0xF4 /* 't' -> */, +/* pos 01a4: 256 */ 0xAD /* '-' -> */, +/* pos 01a5: 257 */ 0x6C /* 'l' */, 0x07, 0x00 /* (to 0x01AC state 258) */, + 0x74 /* 't' */, 0x0C, 0x00 /* (to 0x01B4 state 265) */, + 0x08, /* fail */ +/* pos 01ac: 258 */ 0xE5 /* 'e' -> */, +/* pos 01ad: 259 */ 0xEE /* 'n' -> */, +/* pos 01ae: 260 */ 0xE7 /* 'g' -> */, +/* pos 01af: 261 */ 0xF4 /* 't' -> */, +/* pos 01b0: 262 */ 0xE8 /* 'h' -> */, +/* pos 01b1: 263 */ 0xBA /* ':' -> */, +/* pos 01b2: 264 */ 0x00, 0x1D /* - terminal marker 29 - */, +/* pos 01b4: 265 */ 0xF9 /* 'y' -> */, +/* pos 01b5: 266 */ 0xF0 /* 'p' -> */, +/* pos 01b6: 267 */ 0xE5 /* 'e' -> */, +/* pos 01b7: 268 */ 0xBA /* ':' -> */, +/* pos 01b8: 269 */ 0x00, 0x1E /* - terminal marker 30 - */, +/* pos 01ba: 270 */ 0xE1 /* 'a' -> */, +/* pos 01bb: 271 */ 0xF4 /* 't' -> */, +/* pos 01bc: 272 */ 0xE5 /* 'e' -> */, +/* pos 01bd: 273 */ 0xBA /* ':' -> */, +/* pos 01be: 274 */ 0x00, 0x1F /* - terminal marker 31 - */, +/* pos 01c0: 275 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x01C7 state 276) */, + 0x65 /* 'e' */, 0x0A, 0x00 /* (to 0x01CD state 281) */, + 0x08, /* fail */ +/* pos 01c7: 276 */ 0xEE /* 'n' -> */, +/* pos 01c8: 277 */ 0xE7 /* 'g' -> */, +/* pos 01c9: 278 */ 0xE5 /* 'e' -> */, +/* pos 01ca: 279 */ 0xBA /* ':' -> */, +/* pos 01cb: 280 */ 0x00, 0x20 /* - terminal marker 32 - */, +/* pos 01cd: 281 */ 0xE6 /* 'f' -> */, +/* pos 01ce: 282 */ 0xE5 /* 'e' -> */, +/* pos 01cf: 283 */ 0xF2 /* 'r' -> */, +/* pos 01d0: 284 */ 0xE5 /* 'e' -> */, +/* pos 01d1: 285 */ 0xF2 /* 'r' -> */, +/* pos 01d2: 286 */ 0xBA /* ':' -> */, +/* pos 01d3: 287 */ 0x00, 0x21 /* - terminal marker 33 - */, +/* total size 469 bytes */ diff --git a/lib/libev.c b/lib/libev.c index eff7197f34..04a4b5be47 100755 --- a/lib/libev.c +++ b/lib/libev.c @@ -33,7 +33,7 @@ static void libwebsocket_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) { struct libwebsocket_pollfd eventfd; - struct lws_io_watcher *lws_io = container_of(watcher, struct lws_io_watcher, watcher); + struct lws_io_watcher *lws_io = (struct lws_io_watcher *)watcher; struct libwebsocket_context *context = lws_io->context; if (revents & EV_ERROR) @@ -65,8 +65,8 @@ libwebsocket_initloop( int status = 0; int backend; const char * backend_name; - struct ev_io *w_accept = &context->w_accept.watcher; - struct ev_signal *w_sigint = &context->w_sigint.watcher; + struct ev_io *w_accept = (ev_io *)&context->w_accept; + struct ev_signal *w_sigint = (ev_signal *)&context->w_sigint; if (!loop) loop = ev_default_loop(0); diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index ada190937c..6bebc605ac 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -37,6 +37,7 @@ static const char * const log_level_names[] = { "LATENCY", }; + void libwebsocket_close_and_free_session(struct libwebsocket_context *context, struct libwebsocket *wsi, enum lws_close_status reason) @@ -52,9 +53,6 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context, old_state = wsi->state; - if (wsi->socket_is_permanently_unusable || reason == LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY) - goto just_kill_connection; - switch (old_state) { case WSI_STATE_DEAD_SOCKET: return; @@ -74,7 +72,6 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context, if (wsi->truncated_send_len) { lwsl_info("wsi %p entering WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE\n", wsi); wsi->state = WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE; - libwebsocket_set_timeout(wsi, PENDING_FLUSH_STORED_SEND_BEFORE_CLOSE, 5); return; } break; @@ -86,17 +83,17 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context, wsi->mode == LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE) { context->protocols[0].callback(context, wsi, - LWS_CALLBACK_CLIENT_CONNECTION_ERROR, wsi->user_space, NULL, 0); + LWS_CALLBACK_CLIENT_CONNECTION_ERROR, NULL, NULL, 0); - lws_free_header_table(wsi); + free(wsi->u.hdr.ah); goto just_kill_connection; } - if (wsi->mode == LWS_CONNMODE_HTTP_SERVING) - context->protocols[0].callback(context, wsi, - LWS_CALLBACK_CLOSED_HTTP, wsi->user_space, NULL, 0); - if (wsi->mode == LWS_CONNMODE_HTTP_SERVING_ACCEPTED) { + if (wsi->u.http.post_buffer) { + free(wsi->u.http.post_buffer); + wsi->u.http.post_buffer = NULL; + } if (wsi->u.http.fd != LWS_INVALID_FILE) { lwsl_debug("closing http file\n"); compatible_file_close(wsi->u.http.fd); @@ -153,7 +150,7 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context, } while (ret); /* - * signal we are closing, libwebsocket_write will + * signal we are closing, libsocket_write will * add any necessary version-specific stuff. If the write fails, * no worries we are closing anyway. If we didn't initiate this * close, then our state has been changed to @@ -165,8 +162,7 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context, */ if (old_state == WSI_STATE_ESTABLISHED && - reason != LWS_CLOSE_STATUS_NOSTATUS && - reason != LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY) { + reason != LWS_CLOSE_STATUS_NOSTATUS) { lwsl_debug("sending close indication...\n"); @@ -210,35 +206,28 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context, * delete socket from the internal poll list if still present */ - lws_ssl_remove_wsi_from_buffered_list(context, wsi); - remove_wsi_socket_from_fds(context, wsi); wsi->state = WSI_STATE_DEAD_SOCKET; - lws_free2(wsi->rxflow_buffer); - - if (wsi->mode == LWS_CONNMODE_HTTP2_SERVING && wsi->u.hdr.ah) { - lws_free2(wsi->u.hdr.ah); - } - if ((old_state == WSI_STATE_ESTABLISHED || wsi->mode == LWS_CONNMODE_WS_SERVING || wsi->mode == LWS_CONNMODE_WS_CLIENT)) { - lws_free2(wsi->u.ws.rx_user_buffer); - + if (wsi->u.ws.rx_user_buffer) { + free(wsi->u.ws.rx_user_buffer); + wsi->u.ws.rx_user_buffer = NULL; + } + if (wsi->u.ws.rxflow_buffer) { + free(wsi->u.ws.rxflow_buffer); + wsi->u.ws.rxflow_buffer = NULL; + } if (wsi->truncated_send_malloc) { /* not going to be completed... nuke it */ - lws_free2(wsi->truncated_send_malloc); + free(wsi->truncated_send_malloc); + wsi->truncated_send_malloc = NULL; wsi->truncated_send_len = 0; } - if (wsi->u.ws.ping_payload_buf) { - lws_free2(wsi->u.ws.ping_payload_buf); - wsi->u.ws.ping_payload_alloc = 0; - wsi->u.ws.ping_payload_len = 0; - wsi->u.ws.ping_pending_flag = 0; - } } /* tell the user it's all over for this guy */ @@ -246,8 +235,7 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context, if (wsi->protocol && wsi->protocol->callback && ((old_state == WSI_STATE_ESTABLISHED) || (old_state == WSI_STATE_RETURNED_CLOSE_ALREADY) || - (old_state == WSI_STATE_AWAITING_CLOSE_ACK) || - (old_state == WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE))) { + (old_state == WSI_STATE_AWAITING_CLOSE_ACK))) { lwsl_debug("calling back CLOSED\n"); wsi->protocol->callback(context, wsi, LWS_CALLBACK_CLOSED, wsi->user_space, NULL, 0); @@ -264,7 +252,7 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context, lwsl_warn("extension destruction failed\n"); #ifndef LWS_NO_EXTENSIONS for (n = 0; n < wsi->count_active_extensions; n++) - lws_free(wsi->active_extensions_user[n]); + free(wsi->active_extensions_user[n]); #endif /* * inform all extensions in case they tracked this guy out of band @@ -292,76 +280,9 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context, if (wsi->protocol && wsi->protocol->per_session_data_size && wsi->user_space && !wsi->user_space_externally_allocated) - lws_free(wsi->user_space); + free(wsi->user_space); - /* As a precaution, free the header table in case it lingered: */ - lws_free_header_table(wsi); - lws_free(wsi); -} - -LWS_VISIBLE int -libwebsockets_get_addresses(struct libwebsocket_context *context, - void *ads, char *name, int name_len, - char *rip, int rip_len) -{ - struct addrinfo ai, *res; - void *p = NULL; - - rip[0] = '\0'; - name[0] = '\0'; - -#ifdef LWS_USE_IPV6 - if (LWS_IPV6_ENABLED(context)) { - if (!lws_plat_inet_ntop(AF_INET6, &((struct sockaddr_in6 *)ads)->sin6_addr, rip, rip_len)) { - lwsl_err("inet_ntop", strerror(LWS_ERRNO)); - return -1; - } - - // Strip off the IPv4 to IPv6 header if one exists - if (strncmp(rip, "::ffff:", 7) == 0) - memmove(rip, rip + 7, strlen(rip) - 6); - - getnameinfo((struct sockaddr *)ads, - sizeof(struct sockaddr_in6), name, - name_len, NULL, 0, 0); - - return 0; - } else -#endif - { - memset(&ai, 0, sizeof ai); - ai.ai_family = PF_UNSPEC; - ai.ai_socktype = SOCK_STREAM; - ai.ai_flags = AI_CANONNAME; - - if (getnameinfo((struct sockaddr *)ads, - sizeof(struct sockaddr_in), - name, name_len, NULL, 0, 0)) - return -1; - - if (!rip) - return 0; - - if (getaddrinfo(name, NULL, &ai, &res)) - return -1; - - while (!p && res) { - switch (res->ai_family) { - case AF_INET: - p = &((struct sockaddr_in *)res->ai_addr)->sin_addr; - break; - } - - res = res->ai_next; - } - } - - if (!p) - return -1; - - lws_plat_inet_ntop(AF_INET, p, rip, rip_len); - - return 0; + free(wsi); } /** @@ -371,7 +292,7 @@ libwebsockets_get_addresses(struct libwebsocket_context *context, * @fd: Connection socket descriptor * @name: Buffer to take client address name * @name_len: Length of client address name buffer - * @rip: Buffer to take client address IP dotted quad + * @rip: Buffer to take client address IP qotted quad * @rip_len: Length of client address IP buffer * * This function fills in @name and @rip with the name and IP of @@ -390,8 +311,15 @@ libwebsockets_get_peer_addresses(struct libwebsocket_context *context, struct sockaddr_in6 sin6; #endif struct sockaddr_in sin4; + struct hostent *host; + struct hostent *host1; + char ip[128]; + unsigned char *p; + int n; +#ifdef AF_LOCAL + struct sockaddr_un *un; +#endif int ret = -1; - void *p; rip[0] = '\0'; name[0] = '\0'; @@ -400,26 +328,83 @@ libwebsockets_get_peer_addresses(struct libwebsocket_context *context, #ifdef LWS_USE_IPV6 if (LWS_IPV6_ENABLED(context)) { + len = sizeof(sin6); - p = &sin6; + if (getpeername(fd, (struct sockaddr *) &sin6, &len) < 0) { + lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO)); + goto bail; + } + + if (!lws_plat_inet_ntop(AF_INET6, &sin6.sin6_addr, rip, rip_len)) { + lwsl_err("inet_ntop", strerror(LWS_ERRNO)); + goto bail; + } + + // Strip off the IPv4 to IPv6 header if one exists + if (strncmp(rip, "::ffff:", 7) == 0) + memmove(rip, rip + 7, strlen(rip) - 6); + + getnameinfo((struct sockaddr *)&sin6, + sizeof(struct sockaddr_in6), name, + name_len, NULL, 0, 0); + } else #endif { len = sizeof(sin4); - p = &sin4; - } + if (getpeername(fd, (struct sockaddr *) &sin4, &len) < 0) { + lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO)); + goto bail; + } + host = gethostbyaddr((char *) &sin4.sin_addr, + sizeof(sin4.sin_addr), AF_INET); + if (host == NULL) { + lwsl_warn("gethostbyaddr: %s\n", strerror(LWS_ERRNO)); + goto bail; + } - if (getpeername(fd, p, &len) < 0) { - lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO)); - goto bail; + strncpy(name, host->h_name, name_len); + name[name_len - 1] = '\0'; + + host1 = gethostbyname(host->h_name); + if (host1 == NULL) + goto bail; + p = (unsigned char *)host1; + n = 0; + while (p != NULL) { + p = (unsigned char *)host1->h_addr_list[n++]; + if (p == NULL) + continue; + if ((host1->h_addrtype != AF_INET) +#ifdef AF_LOCAL + && (host1->h_addrtype != AF_LOCAL) +#endif + ) + continue; + + if (host1->h_addrtype == AF_INET) + sprintf(ip, "%u.%u.%u.%u", + p[0], p[1], p[2], p[3]); +#ifdef AF_LOCAL + else { + un = (struct sockaddr_un *)p; + strncpy(ip, un->sun_path, sizeof(ip) - 1); + ip[sizeof(ip) - 1] = '\0'; + } +#endif + p = NULL; + strncpy(rip, ip, rip_len); + rip[rip_len - 1] = '\0'; + } } - - ret = libwebsockets_get_addresses(context, p, name, name_len, rip, rip_len); + ret = 0; bail: lws_latency(context, wsi, "libwebsockets_get_peer_addresses", ret, 1); } + + /** * libwebsocket_context_user() - get the user data associated with the context * @context: Websocket context @@ -453,7 +438,7 @@ libwebsocket_callback_all_protocol( struct libwebsocket *wsi; for (n = 0; n < context->fds_count; n++) { - wsi = wsi_from_fd(context, context->fds[n].fd); + wsi = context->lws_lookup[context->fds[n].fd]; if (!wsi) continue; if (wsi->protocol == protocol) @@ -546,7 +531,7 @@ lws_latency(struct libwebsocket_context *context, struct libwebsocket *wsi, /** * libwebsocket_rx_flow_control() - Enable and disable socket servicing for - * received packets. + * receieved packets. * * If the output side of a server process becomes choked, this allows flow * control for the input side. @@ -558,11 +543,11 @@ lws_latency(struct libwebsocket_context *context, struct libwebsocket *wsi, LWS_VISIBLE int libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable) { - if (enable == (wsi->rxflow_change_to & LWS_RXFLOW_ALLOW)) + if (enable == (wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW)) return 0; lwsl_info("libwebsocket_rx_flow_control(0x%p, %d)\n", wsi, enable); - wsi->rxflow_change_to = LWS_RXFLOW_PENDING_CHANGE | !!enable; + wsi->u.ws.rxflow_change_to = LWS_RXFLOW_PENDING_CHANGE | !!enable; return 0; } @@ -586,7 +571,7 @@ libwebsocket_rx_flow_allow_all_protocol( struct libwebsocket *wsi; for (n = 0; n < context->fds_count; n++) { - wsi = wsi_from_fd(context, context->fds[n].fd); + wsi = context->lws_lookup[context->fds[n].fd]; if (!wsi) continue; if (wsi->protocol == protocol) @@ -635,7 +620,7 @@ int user_callback_handle_rxflow(callback_function callback_function, * Returns -1 if @proxy is NULL or has incorrect format. * * This is only required if your OS does not provide the http_proxy - * environment variable (eg, OSX) + * enviroment variable (eg, OSX) * * IMPORTANT! You should call this function right after creation of the * libwebsocket_context and before call to connect. If you call this @@ -703,20 +688,21 @@ libwebsocket_get_reserved_bits(struct libwebsocket *wsi) int libwebsocket_ensure_user_space(struct libwebsocket *wsi) { - lwsl_info("%s: %p protocol %p\n", __func__, wsi, wsi->protocol); if (!wsi->protocol) return 1; /* allocate the per-connection user memory (if any) */ if (wsi->protocol->per_session_data_size && !wsi->user_space) { - wsi->user_space = lws_zalloc(wsi->protocol->per_session_data_size); + wsi->user_space = malloc( + wsi->protocol->per_session_data_size); if (wsi->user_space == NULL) { lwsl_err("Out of memory for conn user space\n"); return 1; } - } else - lwsl_info("%s: %p protocol pss %u, user_space=%d\n", __func__, wsi, wsi->protocol->per_session_data_size, wsi->user_space); + memset(wsi->user_space, 0, + wsi->protocol->per_session_data_size); + } return 0; } @@ -730,7 +716,7 @@ LWS_VISIBLE void lwsl_emit_stderr(int level, const char *line) for (n = 0; n < LLL_COUNT; n++) if (level == (1 << n)) { now = time_in_microseconds() / 100; - sprintf(buf, "[%llu:%04d] %s: ", (unsigned long long) now / 10000, + sprintf(buf, "[%lu:%04d] %s: ", (unsigned long) now / 10000, (int)(now % 10000), log_level_names[n]); break; } @@ -739,28 +725,22 @@ LWS_VISIBLE void lwsl_emit_stderr(int level, const char *line) } -LWS_VISIBLE void _lws_logv(int filter, const char *format, va_list vl) +LWS_VISIBLE void _lws_log(int filter, const char *format, ...) { char buf[256]; + va_list ap; if (!(log_level & filter)) return; - vsnprintf(buf, sizeof(buf), format, vl); + va_start(ap, format); + vsnprintf(buf, sizeof(buf), format, ap); buf[sizeof(buf) - 1] = '\0'; + va_end(ap); lwsl_emit(filter, buf); } -LWS_VISIBLE void _lws_log(int filter, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - _lws_logv(filter, format, ap); - va_end(ap); -} - /** * lws_set_log_level() - Set the logging bitfield * @level: OR together the LLL_ debug contexts you want output from @@ -779,81 +759,3 @@ LWS_VISIBLE void lws_set_log_level(int level, void (*log_emit_function)(int leve if (log_emit_function) lwsl_emit = log_emit_function; } - -/** - * lws_use_ssl() - Find out if connection is using SSL - * @wsi: websocket connection to check - * - * Returns 0 if the connection is not using SSL, 1 if using SSL and - * using verified cert, and 2 if using SSL but the cert was not - * checked (appears for client wsi told to skip check on connection) - */ -LWS_VISIBLE int -lws_is_ssl(struct libwebsocket *wsi) -{ -#ifdef LWS_OPENSSL_SUPPORT - return wsi->use_ssl; -#else - return 0; -#endif -} - -/** - * lws_partial_buffered() - find out if lws buffered the last write - * @wsi: websocket connection to check - * - * Returns 1 if you cannot use libwebsocket_write because the last - * write on this connection is still buffered, and can't be cleared without - * returning to the service loop and waiting for the connection to be - * writeable again. - * - * If you will try to do >1 libwebsocket_write call inside a single - * WRITEABLE callback, you must check this after every write and bail if - * set, ask for a new writeable callback and continue writing from there. - * - * This is never set at the start of a writeable callback, but any write - * may set it. - */ - -LWS_VISIBLE int -lws_partial_buffered(struct libwebsocket *wsi) -{ - return !!wsi->truncated_send_len; -} - -void lws_set_protocol_write_pending(struct libwebsocket_context *context, - struct libwebsocket *wsi, - enum lws_pending_protocol_send pend) -{ - lwsl_info("setting pps %d\n", pend); - - if (wsi->pps) - lwsl_err("pps overwrite\n"); - wsi->pps = pend; - libwebsocket_rx_flow_control(wsi, 0); - libwebsocket_callback_on_writable(context, wsi); -} - -LWS_VISIBLE size_t -lws_get_peer_write_allowance(struct libwebsocket *wsi) -{ -#ifdef LWS_USE_HTTP2 - /* only if we are using HTTP2 on this connection */ - if (wsi->mode != LWS_CONNMODE_HTTP2_SERVING) - return -1; - /* user is only interested in how much he can send, or that he can't */ - if (wsi->u.http2.tx_credit <= 0) - return 0; - - return wsi->u.http2.tx_credit; -#else - return -1; -#endif -} - -LWS_VISIBLE void -lws_union_transition(struct libwebsocket *wsi, enum connection_mode mode) -{ - memset(&wsi->u, 0, sizeof(wsi->u)); - wsi->mode = mode; -} diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index 5dc97c73f9..0bb67f57bc 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -1,7 +1,7 @@ /* * libwebsockets - small server side websockets and web server implementation * - * Copyright (C) 2010-2015 Andy Green + * Copyright (C) 2010-2013 Andy Green * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,11 +23,8 @@ #define LIBWEBSOCKET_H_3060898B846849FF9F88F5DB59B5950C #ifdef __cplusplus -#include -#include extern "C" { -#else -#include +#include #endif #ifdef CMAKE_BUILD @@ -42,7 +39,6 @@ extern "C" { #include #include #include -#include #include #define strcasecmp stricmp @@ -64,7 +60,6 @@ extern "C" { #include #include -#include #if defined(__GNUC__) #define LWS_VISIBLE __attribute__((visibility("default"))) @@ -91,14 +86,6 @@ extern "C" { #include #endif -#ifdef LWS_OPENSSL_SUPPORT -#ifdef USE_CYASSL -#include -#else -#include -#endif /* not USE_CYASSL */ -#endif - #define CONTEXT_PORT_NO_LISTEN -1 #define MAX_MUX_RECURSION 2 @@ -118,7 +105,6 @@ enum lws_log_levels { }; LWS_VISIBLE LWS_EXTERN void _lws_log(int filter, const char *format, ...); -LWS_VISIBLE LWS_EXTERN void _lws_logv(int filter, const char *format, va_list vl); /* notice, warn and log are always compiled in */ #define lwsl_notice(...) _lws_log(LLL_NOTICE, __VA_ARGS__) @@ -159,14 +145,6 @@ LWS_VISIBLE LWS_EXTERN void lwsl_hexdump(void *buf, size_t len); #define LWS_FEATURE_SERVE_HTTP_FILE_HAS_OTHER_HEADERS_ARG -/* the struct libwebsocket_protocols has the id field present */ -#define LWS_FEATURE_PROTOCOLS_HAS_ID_FIELD - -/* you can call lws_get_peer_write_allowance */ -#define LWS_FEATURE_PROTOCOLS_HAS_PEER_WRITE_ALLOWANCE - -/* extra parameter introduced in 917f43ab821 */ -#define LWS_FEATURE_SERVE_HTTP_FILE_HAS_OTHER_HEADERS_LEN enum libwebsocket_context_options { LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT = 2, @@ -217,8 +195,6 @@ enum libwebsocket_callback_reasons { LWS_CALLBACK_LOCK_POLL, LWS_CALLBACK_UNLOCK_POLL, - LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY, - LWS_CALLBACK_USER = 1000, /* user code can use any including / above */ }; @@ -278,13 +254,6 @@ enum libwebsocket_write_protocol { LWS_WRITE_PING, LWS_WRITE_PONG, - /* Same as write_http but we know this write ends the transaction */ - LWS_WRITE_HTTP_FINAL, - - /* HTTP2 */ - - LWS_WRITE_HTTP_HEADERS, - /* flags */ LWS_WRITE_NO_FIN = 0x40, @@ -308,30 +277,34 @@ struct lws_tokens { int token_len; }; -/* - * don't forget to update test server header dump accordingly - * - * these have to be kept in sync with lextable.h / minilex.c - */ - enum lws_token_indexes { WSI_TOKEN_GET_URI, WSI_TOKEN_POST_URI, WSI_TOKEN_OPTIONS_URI, WSI_TOKEN_HOST, WSI_TOKEN_CONNECTION, + WSI_TOKEN_KEY1, + WSI_TOKEN_KEY2, + WSI_TOKEN_PROTOCOL, WSI_TOKEN_UPGRADE, WSI_TOKEN_ORIGIN, WSI_TOKEN_DRAFT, WSI_TOKEN_CHALLENGE, + + /* new for 04 */ + WSI_TOKEN_KEY, + WSI_TOKEN_VERSION, + WSI_TOKEN_SWORIGIN, + + /* new for 05 */ WSI_TOKEN_EXTENSIONS, - WSI_TOKEN_KEY1, - WSI_TOKEN_KEY2, - WSI_TOKEN_PROTOCOL, + + /* client receives these */ WSI_TOKEN_ACCEPT, WSI_TOKEN_NONCE, WSI_TOKEN_HTTP, - WSI_TOKEN_HTTP2_SETTINGS, + + /* http-related */ WSI_TOKEN_HTTP_ACCEPT, WSI_TOKEN_HTTP_AC_REQUEST_HEADERS, WSI_TOKEN_HTTP_IF_MODIFIED_SINCE, @@ -347,57 +320,11 @@ enum lws_token_indexes { WSI_TOKEN_HTTP_DATE, WSI_TOKEN_HTTP_RANGE, WSI_TOKEN_HTTP_REFERER, - WSI_TOKEN_KEY, - WSI_TOKEN_VERSION, - WSI_TOKEN_SWORIGIN, - - WSI_TOKEN_HTTP_COLON_AUTHORITY, - WSI_TOKEN_HTTP_COLON_METHOD, - WSI_TOKEN_HTTP_COLON_PATH, - WSI_TOKEN_HTTP_COLON_SCHEME, - WSI_TOKEN_HTTP_COLON_STATUS, - - WSI_TOKEN_HTTP_ACCEPT_CHARSET, - WSI_TOKEN_HTTP_ACCEPT_RANGES, - WSI_TOKEN_HTTP_ACCESS_CONTROL_ALLOW_ORIGIN, - WSI_TOKEN_HTTP_AGE, - WSI_TOKEN_HTTP_ALLOW, - WSI_TOKEN_HTTP_CONTENT_DISPOSITION, - WSI_TOKEN_HTTP_CONTENT_ENCODING, - WSI_TOKEN_HTTP_CONTENT_LANGUAGE, - WSI_TOKEN_HTTP_CONTENT_LOCATION, - WSI_TOKEN_HTTP_CONTENT_RANGE, - WSI_TOKEN_HTTP_ETAG, - WSI_TOKEN_HTTP_EXPECT, - WSI_TOKEN_HTTP_EXPIRES, - WSI_TOKEN_HTTP_FROM, - WSI_TOKEN_HTTP_IF_MATCH, - WSI_TOKEN_HTTP_IF_RANGE, - WSI_TOKEN_HTTP_IF_UNMODIFIED_SINCE, - WSI_TOKEN_HTTP_LAST_MODIFIED, - WSI_TOKEN_HTTP_LINK, - WSI_TOKEN_HTTP_LOCATION, - WSI_TOKEN_HTTP_MAX_FORWARDS, - WSI_TOKEN_HTTP_PROXY_AUTHENTICATE, - WSI_TOKEN_HTTP_PROXY_AUTHORIZATION, - WSI_TOKEN_HTTP_REFRESH, - WSI_TOKEN_HTTP_RETRY_AFTER, - WSI_TOKEN_HTTP_SERVER, - WSI_TOKEN_HTTP_SET_COOKIE, - WSI_TOKEN_HTTP_STRICT_TRANSPORT_SECURITY, - WSI_TOKEN_HTTP_TRANSFER_ENCODING, - WSI_TOKEN_HTTP_USER_AGENT, - WSI_TOKEN_HTTP_VARY, - WSI_TOKEN_HTTP_VIA, - WSI_TOKEN_HTTP_WWW_AUTHENTICATE, - WSI_TOKEN_PROXY, - - WSI_TOKEN_PATCH_URI, - WSI_TOKEN_PUT_URI, - WSI_TOKEN_DELETE_URI, - WSI_TOKEN_HTTP_URI_ARGS, - + + + WSI_TOKEN_MUXURL, + /* use token storage to stash these */ _WSI_TOKEN_CLIENT_SENT_PROTOCOLS, @@ -405,7 +332,7 @@ enum lws_token_indexes { _WSI_TOKEN_CLIENT_URI, _WSI_TOKEN_CLIENT_HOST, _WSI_TOKEN_CLIENT_ORIGIN, - + /* always last real token index*/ WSI_TOKEN_COUNT, /* parser state additions */ @@ -524,8 +451,6 @@ enum lws_close_status { LWS_CLOSE_STATUS_EXTENSION_REQUIRED = 1010, LWS_CLOSE_STATUS_UNEXPECTED_CONDITION = 1011, LWS_CLOSE_STATUS_TLS_FAILURE = 1015, - - LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY = 9999, }; enum http_status { @@ -711,15 +636,6 @@ struct libwebsocket_extension; * verify the validity of certificates returned by clients. @user * is the server's OpenSSL SSL_CTX* * - * LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY: if configured for - * including OpenSSL support but no private key file has been specified - * (ssl_private_key_filepath is NULL), this callback is called to - * allow the user to set the private key directly via libopenssl - * and perform further operations if required; this might be useful - * in situations where the private key is not directly accessible by - * the OS, for example if it is stored on a smartcard - * @user is the server's OpenSSL SSL_CTX* - * * LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: if the * libwebsockets context was created with the option * LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT, then this @@ -923,7 +839,7 @@ typedef int (extension_callback_function)(struct libwebsocket_context *context, * struct libwebsocket_protocols - List of protocols and handlers server * supports. * @name: Protocol name that must match the one given in the client - * Javascript new WebSocket(url, 'protocol') name. + * Javascript new WebSocket(url, 'protocol') name * @callback: The service callback used for this protocol. It allows the * service action for an entire protocol to be encapsulated in * the protocol-specific callback @@ -939,16 +855,14 @@ typedef int (extension_callback_function)(struct libwebsocket_context *context, * libwebsockets_remaining_packet_payload(). Notice that you * just talk about frame size here, the LWS_SEND_BUFFER_PRE_PADDING * and post-padding are automatically also allocated on top. - * @id: ignored by lws, but useful to contain user information bound - * to the selected protocol. For example if this protocol was - * called "myprotocol-v2", you might set id to 2, and the user - * code that acts differently according to the version can do so by - * switch (wsi->protocol->id), user code might use some bits as - * capability flags based on selected protocol version, etc. - * @user: User provided context data at the protocol level. - * Accessible via libwebsockets_get_protocol(wsi)->user - * This should not be confused with wsi->user, it is not the same. - * The library completely ignores any value in here. + * @no_buffer_all_partial_tx: Leave at zero if you want the library to take + * care of all partial tx for you. It's useful if you only have + * small tx packets and the chance of any truncated send is small + * enough any additional malloc / buffering overhead is less + * painful than writing the code to deal with partial sends. For + * protocols where you stream big blocks, set to nonzero and use + * the return value from libwebsocket_write() to manage how much + * got send yourself. * @owning_server: the server init call fills in this opaque pointer when * registering this protocol with the server. * @protocol_index: which protocol we are starting from zero @@ -956,10 +870,6 @@ typedef int (extension_callback_function)(struct libwebsocket_context *context, * This structure represents one protocol supported by the server. An * array of these structures is passed to libwebsocket_create_server() * allows as many protocols as you like to be handled by one server. - * - * The first protocol given has its callback used for user callbacks when - * there is no agreed protocol name, that's true during HTTP part of the - * connection and true if the client did not send a Protocol: header. */ struct libwebsocket_protocols { @@ -967,8 +877,7 @@ struct libwebsocket_protocols { callback_function *callback; size_t per_session_data_size; size_t rx_buffer_size; - unsigned int id; - void *user; + int no_buffer_all_partial_tx; /* * below are filled in on server init and can be left uninitialized, @@ -1004,10 +913,9 @@ struct libwebsocket_extension { /** * struct lws_context_creation_info: parameters to create context with * - * @port: Port to listen on... you can use CONTEXT_PORT_NO_LISTEN to - * suppress listening on any port, that's what you want if you are - * not running a websocket server at all but just using it as a - * client + * @port: Port to listen on... you can use 0 to suppress listening on + * any port, that's what you want if you are not running a + * websocket server at all but just using it as a client * @iface: NULL to bind the listen socket to all interfaces, or the * interface name, eg, "eth2" * @protocols: Array of structures listing supported protocols and a protocol- @@ -1022,16 +930,12 @@ struct libwebsocket_extension { * @ssl_cert_filepath: If libwebsockets was compiled to use ssl, and you want * to listen using SSL, set to the filepath to fetch the * server cert from, otherwise NULL for unencrypted - * @ssl_private_key_filepath: filepath to private key if wanting SSL mode; - * if this is set to NULL but sll_cert_filepath is set, the - * OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY callback is called to allow - * setting of the private key directly via openSSL library calls + * @ssl_private_key_filepath: filepath to private key if wanting SSL mode, + * else ignored * @ssl_ca_filepath: CA certificate filepath or NULL * @ssl_cipher_list: List of valid ciphers to use (eg, * "RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL" * or you can leave it as NULL to get "DEFAULT" - * @http_proxy_address: If non-NULL, attempts to proxy via the given address - * @http_proxy_port: If http_proxy_address was non-NULL, uses this port at the address * @gid: group id to change to after setting listen socket, or -1. * @uid: user id to change to after setting listen socket, or -1. * @options: 0, or LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK @@ -1044,10 +948,6 @@ struct libwebsocket_extension { * and killing the connection * @ka_interval: if ka_time was nonzero, how long to wait before each ka_probes * attempt - * @provided_client_ssl_ctx: If non-null, swap out libwebsockets ssl - * implementation for the one provided by provided_ssl_ctx. - * Libwebsockets no longer is responsible for freeing the context - * if this option is selected. */ struct lws_context_creation_info { @@ -1055,8 +955,7 @@ struct lws_context_creation_info { const char *iface; struct libwebsocket_protocols *protocols; struct libwebsocket_extension *extensions; - struct lws_token_limits *token_limits; - const char *ssl_private_key_password; + struct lws_token_limits *token_limits; const char *ssl_cert_filepath; const char *ssl_private_key_filepath; const char *ssl_ca_filepath; @@ -1070,11 +969,7 @@ struct lws_context_creation_info { int ka_time; int ka_probes; int ka_interval; -#ifdef LWS_OPENSSL_SUPPORT - SSL_CTX *provided_client_ssl_ctx; -#else /* maintain structure layout either way */ - void *provided_client_ssl_ctx; -#endif + }; LWS_VISIBLE LWS_EXTERN @@ -1099,44 +994,6 @@ libwebsocket_service(struct libwebsocket_context *context, int timeout_ms); LWS_VISIBLE LWS_EXTERN void libwebsocket_cancel_service(struct libwebsocket_context *context); -LWS_VISIBLE LWS_EXTERN const unsigned char * -lws_token_to_string(enum lws_token_indexes token); - -LWS_VISIBLE LWS_EXTERN int -lws_add_http_header_by_name(struct libwebsocket_context *context, - struct libwebsocket *wsi, - const unsigned char *name, - const unsigned char *value, - int length, - unsigned char **p, - unsigned char *end); -LWS_VISIBLE LWS_EXTERN int -lws_finalize_http_header(struct libwebsocket_context *context, - struct libwebsocket *wsi, - unsigned char **p, - unsigned char *end); -LWS_VISIBLE LWS_EXTERN int -lws_add_http_header_by_token(struct libwebsocket_context *context, - struct libwebsocket *wsi, - enum lws_token_indexes token, - const unsigned char *value, - int length, - unsigned char **p, - unsigned char *end); -LWS_VISIBLE LWS_EXTERN int lws_add_http_header_content_length(struct libwebsocket_context *context, - struct libwebsocket *wsi, - unsigned long content_length, - unsigned char **p, - unsigned char *end); -LWS_VISIBLE LWS_EXTERN int -lws_add_http_header_status(struct libwebsocket_context *context, - struct libwebsocket *wsi, - unsigned int code, - unsigned char **p, - unsigned char *end); - -LWS_EXTERN int lws_http_transaction_completed(struct libwebsocket *wsi); - #ifdef LWS_USE_LIBEV LWS_VISIBLE LWS_EXTERN int libwebsocket_initloop( @@ -1167,7 +1024,6 @@ enum pending_timeout { PENDING_TIMEOUT_SSL_ACCEPT, PENDING_TIMEOUT_HTTP_CONTENT, PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND, - PENDING_FLUSH_STORED_SEND_BEFORE_CLOSE, }; LWS_VISIBLE LWS_EXTERN void @@ -1220,8 +1076,7 @@ libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, size_t len, LWS_VISIBLE LWS_EXTERN int libwebsockets_serve_http_file(struct libwebsocket_context *context, struct libwebsocket *wsi, const char *file, - const char *content_type, const char *other_headers, - int other_headers_len); + const char *content_type, const char *other_headers); LWS_VISIBLE LWS_EXTERN int libwebsockets_serve_http_file_fragment(struct libwebsocket_context *context, struct libwebsocket *wsi); @@ -1265,25 +1120,6 @@ libwebsocket_rx_flow_allow_all_protocol( LWS_VISIBLE LWS_EXTERN size_t libwebsockets_remaining_packet_payload(struct libwebsocket *wsi); -/* - * if the protocol does not have any guidence, returns -1. Currently only - * http2 connections get send window information from this API. But your code - * should use it so it can work properly with any protocol. - * - * If nonzero return is the amount of payload data the peer or intermediary has - * reported it has buffer space for. That has NO relationship with the amount - * of buffer space your OS can accept on this connection for a write action. - * - * This number represents the maximum you could send to the peer or intermediary - * on this connection right now without it complaining. - * - * lws manages accounting for send window updates and payload writes - * automatically, so this number reflects the situation at the peer or - * intermediary dynamically. - */ -LWS_VISIBLE LWS_EXTERN size_t -lws_get_peer_write_allowance(struct libwebsocket *wsi); - LWS_VISIBLE LWS_EXTERN struct libwebsocket * libwebsocket_client_connect(struct libwebsocket_context *clients, const char *address, @@ -1326,15 +1162,9 @@ lws_daemonize(const char *_lock_path); LWS_VISIBLE LWS_EXTERN int lws_send_pipe_choked(struct libwebsocket *wsi); -LWS_VISIBLE LWS_EXTERN int -lws_partial_buffered(struct libwebsocket *wsi); - LWS_VISIBLE LWS_EXTERN int lws_frame_is_binary(struct libwebsocket *wsi); -LWS_VISIBLE LWS_EXTERN int -lws_is_ssl(struct libwebsocket *wsi); - LWS_VISIBLE LWS_EXTERN unsigned char * libwebsockets_SHA1(const unsigned char *d, size_t n, unsigned char *md); @@ -1370,12 +1200,6 @@ libwebsocket_read(struct libwebsocket_context *context, LWS_VISIBLE LWS_EXTERN struct libwebsocket_extension *libwebsocket_get_internal_extensions(); #endif -/* - * custom allocator support - */ -LWS_VISIBLE LWS_EXTERN void -lws_set_allocator(void *(*realloc)(void *ptr, size_t size)); - #ifdef __cplusplus } #endif diff --git a/lib/lws-plat-unix.c b/lib/lws-plat-unix.c index 9d10acff46..78fb6e4a31 100755 --- a/lib/lws-plat-unix.c +++ b/lib/lws-plat-unix.c @@ -1,8 +1,5 @@ #include "private-libwebsockets.h" -#include -#include - /* * included from libwebsockets.c for unix builds */ @@ -11,7 +8,7 @@ unsigned long long time_in_microseconds(void) { struct timeval tv; gettimeofday(&tv, NULL); - return ((unsigned long long)tv.tv_sec * 1000000LL) + tv.tv_usec; + return (tv.tv_sec * 1000000) + tv.tv_usec; } LWS_VISIBLE int libwebsockets_get_random(struct libwebsocket_context *context, @@ -100,9 +97,6 @@ lws_plat_service(struct libwebsocket_context *context, int timeout_ms) int n; int m; char buf; -#ifdef LWS_OPENSSL_SUPPORT - struct libwebsocket *wsi, *wsi_next; -#endif /* stay dead once we are dead */ @@ -114,19 +108,10 @@ lws_plat_service(struct libwebsocket_context *context, int timeout_ms) context->service_tid = context->protocols[0].callback(context, NULL, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0); -#ifdef LWS_OPENSSL_SUPPORT - /* if we know we have non-network pending data, do not wait in poll */ - if (lws_ssl_anybody_has_buffered_read(context)) - timeout_ms = 0; -#endif n = poll(context->fds, context->fds_count, timeout_ms); context->service_tid = 0; -#ifdef LWS_OPENSSL_SUPPORT - if (!lws_ssl_anybody_has_buffered_read(context) && n == 0) { -#else if (n == 0) /* poll timeout */ { -#endif libwebsocket_service_fd(context, NULL); return 0; } @@ -137,36 +122,9 @@ lws_plat_service(struct libwebsocket_context *context, int timeout_ms) return 0; } -#ifdef LWS_OPENSSL_SUPPORT - /* - * For all guys with buffered SSL read data already saved up, if they - * are not flowcontrolled, fake their POLLIN status so they'll get - * service to use up the buffered incoming data, even though their - * network socket may have nothing - */ - - wsi = context->pending_read_list; - while (wsi) { - wsi_next = wsi->pending_read_list_next; - context->fds[wsi->sock].revents |= - context->fds[wsi->sock].events & POLLIN; - if (context->fds[wsi->sock].revents & POLLIN) { - /* - * he's going to get serviced now, take him off the - * list of guys with buffered SSL. If he still has some - * at the end of the service, he'll get put back on the - * list then. - */ - lws_ssl_remove_wsi_from_buffered_list(context, wsi); - } - wsi = wsi_next; - } -#endif - /* any socket with events to service? */ for (n = 0; n < context->fds_count; n++) { - if (!context->fds[n].revents) continue; @@ -215,17 +173,17 @@ lws_plat_set_socket_options(struct libwebsocket_context *context, int fd) #else /* set the keepalive conditions we want on it too */ optval = context->ka_time; - if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, + if (setsockopt(fd, IPPROTO_IP, TCP_KEEPIDLE, (const void *)&optval, optlen) < 0) return 1; optval = context->ka_interval; - if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, + if (setsockopt(fd, IPPROTO_IP, TCP_KEEPINTVL, (const void *)&optval, optlen) < 0) return 1; optval = context->ka_probes; - if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, + if (setsockopt(fd, IPPROTO_IP, TCP_KEEPCNT, (const void *)&optval, optlen) < 0) return 1; #endif @@ -235,17 +193,14 @@ lws_plat_set_socket_options(struct libwebsocket_context *context, int fd) optval = 1; #if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \ !defined(__OpenBSD__) - if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen) < 0) - return 1; + setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen); #else tcp_proto = getprotobyname("TCP"); - if (setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen) < 0) - return 1; + setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen); #endif /* We are nonblocking... */ - if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) - return 1; + fcntl(fd, F_SETFL, O_NONBLOCK); return 0; } @@ -253,22 +208,12 @@ lws_plat_set_socket_options(struct libwebsocket_context *context, int fd) LWS_VISIBLE void lws_plat_drop_app_privileges(struct lws_context_creation_info *info) { - if (info->uid != -1) { - struct passwd *p = getpwuid(info->uid); - - if (p) { - initgroups(p->pw_name, info->gid); - if (setuid(info->uid)) - lwsl_warn("setuid: %s\n", strerror(LWS_ERRNO)); - else - lwsl_notice(" Set privs to user '%s'\n", p->pw_name); - } else - lwsl_warn("getpwuid: unable to find uid %d", info->uid); - } if (info->gid != -1) if (setgid(info->gid)) lwsl_warn("setgid: %s\n", strerror(LWS_ERRNO)); - + if (info->uid != -1) + if (setuid(info->uid)) + lwsl_warn("setuid: %s\n", strerror(LWS_ERRNO)); } LWS_VISIBLE int @@ -288,7 +233,7 @@ lws_plat_init_fd_tables(struct libwebsocket_context *context) context->fds[0].events = LWS_POLLIN; context->fds[0].revents = 0; context->fds_count = 1; - + context->fd_random = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY); if (context->fd_random < 0) { lwsl_err("Unable to open random device %s %d\n", @@ -314,7 +259,7 @@ lws_plat_context_early_init(void) sigaddset(&mask, SIGUSR2); sigprocmask(SIG_BLOCK, &mask, NULL); - + signal(SIGPIPE, sigpipe_handler); return 0; @@ -377,6 +322,8 @@ interface_to_sa(struct libwebsocket_context *context, break; #ifdef LWS_USE_IPV6 case AF_INET6: + if (rc >= 0) + break; memcpy(&addr6->sin6_addr, &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr, sizeof(struct in6_addr)); @@ -389,7 +336,7 @@ interface_to_sa(struct libwebsocket_context *context, } freeifaddrs(ifr); - + if (rc == -1) { /* check if bind to IP adddress */ #ifdef LWS_USE_IPV6 @@ -443,16 +390,15 @@ lws_plat_open_file(const char* filename, unsigned long* filelen) if (ret < 0) return LWS_INVALID_FILE; - if (fstat(ret, &stat_buf) < 0) { - close(ret); - return LWS_INVALID_FILE; - } + fstat(ret, &stat_buf); *filelen = stat_buf.st_size; return ret; } +#ifdef LWS_USE_IPV6 LWS_VISIBLE const char * lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt) -{ +{ return inet_ntop(af, src, dst, cnt); } +#endif diff --git a/lib/lws-plat-win.c b/lib/lws-plat-win.c index 63e3bcb15c..b33f79c25f 100755 --- a/lib/lws-plat-win.c +++ b/lib/lws-plat-win.c @@ -33,59 +33,6 @@ time_t time(time_t *t) } #endif -/* file descriptor hash management */ - -struct libwebsocket * -wsi_from_fd(struct libwebsocket_context *context, int fd) -{ - int h = LWS_FD_HASH(fd); - int n = 0; - - for (n = 0; n < context->fd_hashtable[h].length; n++) - if (context->fd_hashtable[h].wsi[n]->sock == fd) - return context->fd_hashtable[h].wsi[n]; - - return NULL; -} - -int -insert_wsi(struct libwebsocket_context *context, struct libwebsocket *wsi) -{ - int h = LWS_FD_HASH(wsi->sock); - - if (context->fd_hashtable[h].length == (getdtablesize() - 1)) { - lwsl_err("hash table overflow\n"); - return 1; - } - - context->fd_hashtable[h].wsi[context->fd_hashtable[h].length++] = wsi; - - return 0; -} - -int -delete_from_fd(struct libwebsocket_context *context, int fd) -{ - int h = LWS_FD_HASH(fd); - int n = 0; - - for (n = 0; n < context->fd_hashtable[h].length; n++) - if (context->fd_hashtable[h].wsi[n]->sock == fd) { - while (n < context->fd_hashtable[h].length) { - context->fd_hashtable[h].wsi[n] = - context->fd_hashtable[h].wsi[n + 1]; - n++; - } - context->fd_hashtable[h].length--; - - return 0; - } - - lwsl_err("Failed to find fd %d requested for " - "delete in hashtable\n", fd); - return 1; -} - LWS_VISIBLE int libwebsockets_get_random(struct libwebsocket_context *context, void *buf, int len) { @@ -157,7 +104,7 @@ lws_plat_service(struct libwebsocket_context *context, int timeout_ms) continue; if (pfd->events & LWS_POLLOUT) { - if (wsi_from_fd(context,pfd->fd)->sock_send_blocking) + if (context->lws_lookup[pfd->fd]->sock_send_blocking) continue; pfd->revents = LWS_POLLOUT; n = libwebsocket_service_fd(context, pfd); @@ -196,7 +143,7 @@ lws_plat_service(struct libwebsocket_context *context, int timeout_ms) pfd->revents = networkevents.lNetworkEvents; if (pfd->revents & LWS_POLLOUT) - wsi_from_fd(context,pfd->fd)->sock_send_blocking = FALSE; + context->lws_lookup[pfd->fd]->sock_send_blocking = FALSE; return libwebsocket_service_fd(context, pfd); } @@ -246,16 +193,17 @@ lws_plat_drop_app_privileges(struct lws_context_creation_info *info) LWS_VISIBLE int lws_plat_init_fd_tables(struct libwebsocket_context *context) { - context->events = lws_malloc(sizeof(WSAEVENT) * (context->max_fds + 1)); + context->events = (WSAEVENT *)malloc(sizeof(WSAEVENT) * + (context->max_fds + 1)); if (context->events == NULL) { lwsl_err("Unable to allocate events array for %d connections\n", context->max_fds); return 1; } - + context->fds_count = 0; context->events[0] = WSACreateEvent(); - + context->fd_random = 0; return 0; @@ -288,7 +236,7 @@ lws_plat_context_early_destroy(struct libwebsocket_context *context) { if (context->events) { WSACloseEvent(context->events[0]); - lws_free(context->events); + free(context->events); } } @@ -302,20 +250,7 @@ LWS_VISIBLE int interface_to_sa(struct libwebsocket_context *context, const char *ifname, struct sockaddr_in *addr, size_t addrlen) { - long long address = inet_addr(ifname); - - if (address == INADDR_NONE) { - struct hostent *entry = gethostbyname(ifname); - if (entry) - address = ((struct in_addr *)entry->h_addr_list[0])->s_addr; - } - - if (address == INADDR_NONE) - return -1; - - addr->sin_addr.s_addr = address; - - return 0; + return -1; } LWS_VISIBLE void @@ -383,7 +318,7 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt) DWORD bufferlen = cnt; BOOL ok = FALSE; - buffer = lws_malloc(bufferlen); + buffer = malloc(bufferlen); if (!buffer) { lwsl_err("Out of memory\n"); return NULL; @@ -418,6 +353,6 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt) ok = FALSE; } - lws_free(buffer); + free(buffer); return ok ? dst : NULL; } diff --git a/lib/minilex.c b/lib/minilex.c index 1aea0f6a08..cdc500ed23 100644 --- a/lib/minilex.c +++ b/lib/minilex.c @@ -16,7 +16,50 @@ #include #include -#include "lextable-strings.h" +/* set of parsable strings -- ALL LOWER CASE */ + +const char *set[] = { + "get ", + "post ", + "options ", + "host:", + "connection:", + "sec-websocket-key1:", + "sec-websocket-key2:", + "sec-websocket-protocol:", + "upgrade:", + "origin:", + "sec-websocket-draft:", + "\x0d\x0a", + + "sec-websocket-key:", + "sec-websocket-version:", + "sec-websocket-origin:", + + "sec-websocket-extensions:", + + "sec-websocket-accept:", + "sec-websocket-nonce:", + "http/1.1 ", + + "accept:", + "access-control-request-headers:", + "if-modified-since:", + "if-none-match:", + "accept-encoding:", + "accept-language:", + "pragma:", + "cache-control:", + "authorization:", + "cookie:", + "content-length:", + "content-type:", + "date:", + "range:", + "referer:", + "", /* not matchable */ + +}; /* * b7 = 0 = 1-byte seq diff --git a/lib/output.c b/lib/output.c index b914f281cb..28e15a6d41 100644 --- a/lib/output.c +++ b/lib/output.c @@ -132,8 +132,6 @@ int lws_issue_raw(struct libwebsocket *wsi, unsigned char *buf, size_t len) switch (n) { case LWS_SSL_CAPABLE_ERROR: - /* we're going to close, let close know sends aren't possible */ - wsi->socket_is_permanently_unusable = 1; return -1; case LWS_SSL_CAPABLE_MORE_SERVICE: /* nothing got sent, not fatal, retry the whole thing later */ @@ -195,10 +193,11 @@ int lws_issue_raw(struct libwebsocket *wsi, unsigned char *buf, size_t len) */ if (!wsi->truncated_send_malloc || real_len - n > wsi->truncated_send_allocation) { - lws_free(wsi->truncated_send_malloc); + if (wsi->truncated_send_malloc) + free(wsi->truncated_send_malloc); wsi->truncated_send_allocation = real_len - n; - wsi->truncated_send_malloc = lws_malloc(real_len - n); + wsi->truncated_send_malloc = malloc(real_len - n); if (!wsi->truncated_send_malloc) { lwsl_err("truncated send: unable to malloc %d\n", real_len - n); @@ -263,9 +262,7 @@ LWS_VISIBLE int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, return 0; } - if (protocol == LWS_WRITE_HTTP || - protocol == LWS_WRITE_HTTP_FINAL || - protocol == LWS_WRITE_HTTP_HEADERS) + if (protocol == LWS_WRITE_HTTP) goto send_raw; /* websocket protocol, either binary or text */ @@ -278,7 +275,8 @@ LWS_VISIBLE int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, if (wsi->u.ws.inside_frame) goto do_more_inside_frame; - wsi->u.ws.clean_buffer = 1; + /* if he wants all partials buffered, never have a clean_buffer */ + wsi->u.ws.clean_buffer = !wsi->protocol->no_buffer_all_partial_tx; /* * give a chance to the extensions to modify payload @@ -432,39 +430,8 @@ LWS_VISIBLE int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, case LWS_WRITE_CLOSE: /* lwsl_hexdump(&buf[-pre], len + post); */ case LWS_WRITE_HTTP: - case LWS_WRITE_HTTP_FINAL: - case LWS_WRITE_HTTP_HEADERS: case LWS_WRITE_PONG: case LWS_WRITE_PING: -#ifdef LWS_USE_HTTP2 - if (wsi->mode == LWS_CONNMODE_HTTP2_SERVING) { - unsigned char flags = 0; - - n = LWS_HTTP2_FRAME_TYPE_DATA; - if (protocol == LWS_WRITE_HTTP_HEADERS) { - n = LWS_HTTP2_FRAME_TYPE_HEADERS; - flags = LWS_HTTP2_FLAG_END_HEADERS; - if (wsi->u.http2.send_END_STREAM) - flags |= LWS_HTTP2_FLAG_END_STREAM; - } - - if ((protocol == LWS_WRITE_HTTP || protocol == LWS_WRITE_HTTP_FINAL) && wsi->u.http.content_length) { - wsi->u.http.content_remain -= len; - lwsl_info("%s: content_remain = %lu\n", __func__, wsi->u.http.content_remain); - if (!wsi->u.http.content_remain) { - lwsl_info("%s: selecting final write mode\n", __func__); - protocol = LWS_WRITE_HTTP_FINAL; - } - } - - if (protocol == LWS_WRITE_HTTP_FINAL && wsi->u.http2.END_STREAM) { - lwsl_info("%s: setting END_STREAM\n", __func__); - flags |= LWS_HTTP2_FLAG_END_STREAM; - } - - return lws_http2_frame_write(wsi, n, flags, wsi->u.http2.my_stream_id, len, buf); - } -#endif return lws_issue_raw(wsi, (unsigned char *)buf - pre, len + pre + post); default: @@ -538,16 +505,15 @@ LWS_VISIBLE int libwebsockets_serve_http_file_fragment( if (n < 0) return -1; /* caller will close */ if (n) { - wsi->u.http.filepos += n; m = libwebsocket_write(wsi, context->service_buffer, n, - wsi->u.http.filepos == wsi->u.http.filelen ? LWS_WRITE_HTTP_FINAL : LWS_WRITE_HTTP); + LWS_WRITE_HTTP); if (m < 0) return -1; + wsi->u.http.filepos += m; if (m != n) /* adjust for what was not sent */ - if (compatible_file_seek_cur(wsi->u.http.fd, m - n) < 0) - return -1; + compatible_file_seek_cur(wsi->u.http.fd, m - n); } all_sent: if (!wsi->truncated_send_len && @@ -571,8 +537,7 @@ LWS_VISIBLE int libwebsockets_serve_http_file_fragment( } LWS_VISIBLE int -lws_ssl_capable_read_no_ssl(struct libwebsocket_context *context, - struct libwebsocket *wsi, unsigned char *buf, int len) +lws_ssl_capable_read_no_ssl(struct libwebsocket *wsi, unsigned char *buf, int len) { int n; diff --git a/lib/parsers.c b/lib/parsers.c index bcf1d305b6..a8d0a5ea95 100644 --- a/lib/parsers.c +++ b/lib/parsers.c @@ -42,10 +42,6 @@ int lextable_decode(int pos, char c) return -1; return pos; } - - if (lextable[pos] == FAIL_CHAR) - return -1; - /* b7 = 0, end or 3-byte */ if (lextable[pos] < FAIL_CHAR) /* terminal marker */ return pos; @@ -61,9 +57,7 @@ int lextable_decode(int pos, char c) int lws_allocate_header_table(struct libwebsocket *wsi) { - /* Be sure to free any existing header data to avoid mem leak: */ - lws_free_header_table(wsi); - wsi->u.hdr.ah = lws_malloc(sizeof(*wsi->u.hdr.ah)); + wsi->u.hdr.ah = malloc(sizeof(*wsi->u.hdr.ah)); if (wsi->u.hdr.ah == NULL) { lwsl_err("Out of memory\n"); return -1; @@ -75,13 +69,6 @@ int lws_allocate_header_table(struct libwebsocket *wsi) return 0; } -int lws_free_header_table(struct libwebsocket *wsi) -{ - lws_free2(wsi->u.hdr.ah); - wsi->u.hdr.ah = NULL; - return 0; -}; - LWS_VISIBLE int lws_hdr_total_length(struct libwebsocket *wsi, enum lws_token_indexes h) { int n; @@ -164,7 +151,7 @@ int lws_hdr_simple_create(struct libwebsocket *wsi, return 0; } -static signed char char_to_hex(const char c) +static char char_to_hex(const char c) { if (c >= '0' && c <= '9') return c - '0'; @@ -202,18 +189,44 @@ int libwebsocket_parse( struct libwebsocket_context *context, struct libwebsocket *wsi, unsigned char c) { - static const unsigned char methods[] = { - WSI_TOKEN_GET_URI, - WSI_TOKEN_POST_URI, - WSI_TOKEN_OPTIONS_URI, - WSI_TOKEN_PUT_URI, - WSI_TOKEN_PATCH_URI, - WSI_TOKEN_DELETE_URI, - }; - int n, m; + int n; switch (wsi->u.hdr.parser_state) { - default: + case WSI_TOKEN_GET_URI: + case WSI_TOKEN_POST_URI: + case WSI_TOKEN_OPTIONS_URI: + case WSI_TOKEN_HOST: + case WSI_TOKEN_CONNECTION: + case WSI_TOKEN_KEY1: + case WSI_TOKEN_KEY2: + case WSI_TOKEN_PROTOCOL: + case WSI_TOKEN_UPGRADE: + case WSI_TOKEN_ORIGIN: + case WSI_TOKEN_SWORIGIN: + case WSI_TOKEN_DRAFT: + case WSI_TOKEN_CHALLENGE: + case WSI_TOKEN_KEY: + case WSI_TOKEN_VERSION: + case WSI_TOKEN_ACCEPT: + case WSI_TOKEN_NONCE: + case WSI_TOKEN_EXTENSIONS: + case WSI_TOKEN_HTTP: + case WSI_TOKEN_HTTP_ACCEPT: + case WSI_TOKEN_HTTP_AC_REQUEST_HEADERS: + case WSI_TOKEN_HTTP_IF_MODIFIED_SINCE: + case WSI_TOKEN_HTTP_IF_NONE_MATCH: + case WSI_TOKEN_HTTP_ACCEPT_ENCODING: + case WSI_TOKEN_HTTP_ACCEPT_LANGUAGE: + case WSI_TOKEN_HTTP_PRAGMA: + case WSI_TOKEN_HTTP_CACHE_CONTROL: + case WSI_TOKEN_HTTP_AUTHORIZATION: + case WSI_TOKEN_HTTP_COOKIE: + case WSI_TOKEN_HTTP_CONTENT_LENGTH: + case WSI_TOKEN_HTTP_CONTENT_TYPE: + case WSI_TOKEN_HTTP_DATE: + case WSI_TOKEN_HTTP_RANGE: + case WSI_TOKEN_HTTP_REFERER: + lwsl_parser("WSI_TOK_(%d) '%c'\n", wsi->u.hdr.parser_state, c); @@ -223,11 +236,9 @@ int libwebsocket_parse( wsi->u.hdr.parser_state]].len && c == ' ') break; - for (m = 0; m < ARRAY_SIZE(methods); m++) - if (wsi->u.hdr.parser_state == methods[m]) - break; - if (m == ARRAY_SIZE(methods)) - /* it was not any of the methods */ + if ((wsi->u.hdr.parser_state != WSI_TOKEN_GET_URI) && + (wsi->u.hdr.parser_state != WSI_TOKEN_POST_URI) && + (wsi->u.hdr.parser_state != WSI_TOKEN_OPTIONS_URI)) goto check_eol; /* special URI processing... end at space */ @@ -237,12 +248,9 @@ int libwebsocket_parse( if (!wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len) if (issue_char(wsi, '/') < 0) return -1; - - /* begin parsing HTTP version: */ - if (issue_char(wsi, '\0') < 0) - return -1; - wsi->u.hdr.parser_state = WSI_TOKEN_HTTP; - goto start_fragment; + c = '\0'; + wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING; + goto spill; } /* special URI processing... convert %xx */ @@ -306,8 +314,8 @@ int libwebsocket_parse( if (c == '.') { wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT; goto swallow; - } - wsi->u.hdr.ups = URIPS_IDLE; + } else + wsi->u.hdr.ups = URIPS_IDLE; break; case URIPS_SEEN_SLASH_DOT: /* swallow second . */ @@ -346,14 +354,24 @@ int libwebsocket_parse( /* last issued was /, so another / == // */ if (c == '/') goto swallow; - /* last we issued was / so SEEN_SLASH */ - wsi->u.hdr.ups = URIPS_SEEN_SLASH; + else /* last we issued was / so SEEN_SLASH */ + wsi->u.hdr.ups = URIPS_SEEN_SLASH; break; case URIPS_ARGUMENTS: /* leave them alone */ break; } +check_eol: + + /* bail at EOL */ + if (wsi->u.hdr.parser_state != WSI_TOKEN_CHALLENGE && + c == '\x0d') { + c = '\0'; + wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR; + lwsl_parser("*\n"); + } + if (c == '?') { /* start of URI arguments */ /* seal off uri header */ wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = '\0'; @@ -376,22 +394,16 @@ int libwebsocket_parse( goto swallow; } -check_eol: - - /* bail at EOL */ - if (wsi->u.hdr.parser_state != WSI_TOKEN_CHALLENGE && - c == '\x0d') { - c = '\0'; - wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR; - lwsl_parser("*\n"); - } - - n = issue_char(wsi, c); - if (n < 0) - return -1; - if (n > 0) - wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING; - +spill: + { + int issue_result = issue_char(wsi, c); + if (issue_result < 0) { + return -1; + } + else if(issue_result > 0) { + wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING; + }; + }; swallow: /* per-protocol end of headers management */ @@ -401,58 +413,52 @@ int libwebsocket_parse( /* collecting and checking a name part */ case WSI_TOKEN_NAME_PART: - lwsl_parser("WSI_TOKEN_NAME_PART '%c' (mode=%d)\n", c, wsi->mode); + lwsl_parser("WSI_TOKEN_NAME_PART '%c'\n", c); wsi->u.hdr.lextable_pos = lextable_decode(wsi->u.hdr.lextable_pos, c); - /* - * Server needs to look out for unknown methods... - */ - if (wsi->u.hdr.lextable_pos < 0 && - wsi->mode == LWS_CONNMODE_HTTP_SERVING) { + + if (wsi->u.hdr.lextable_pos < 0) { /* this is not a header we know about */ - for (m = 0; m < ARRAY_SIZE(methods); m++) - if (wsi->u.hdr.ah->frag_index[methods[m]]) { - /* - * already had the method, no idea what - * this crap from the client is, ignore - */ - wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING; - break; - } + if (wsi->u.hdr.ah->frag_index[WSI_TOKEN_GET_URI] || + wsi->u.hdr.ah->frag_index[WSI_TOKEN_POST_URI] || + wsi->u.hdr.ah->frag_index[WSI_TOKEN_OPTIONS_URI] || + wsi->u.hdr.ah->frag_index[WSI_TOKEN_HTTP]) { + /* + * altready had the method, no idea what + * this crap is, ignore + */ + wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING; + break; + } /* - * hm it's an unknown http method from a client in fact, + * hm it's an unknown http method in fact, * treat as dangerous */ - if (m == ARRAY_SIZE(methods)) { - lwsl_info("Unknown method - dropping\n"); - return -1; - } - break; - } - /* - * ...otherwise for a client, let him ignore unknown headers - * coming from the server - */ - if (wsi->u.hdr.lextable_pos < 0) { - wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING; - break; - } + lwsl_info("Unknown method - dropping\n"); + return -1; + } if (lextable[wsi->u.hdr.lextable_pos] < FAIL_CHAR) { + /* terminal state */ - n = ((unsigned int)lextable[wsi->u.hdr.lextable_pos] << 8) | - lextable[wsi->u.hdr.lextable_pos + 1]; + n = (lextable[wsi->u.hdr.lextable_pos] << 8) | lextable[wsi->u.hdr.lextable_pos + 1]; lwsl_parser("known hdr %d\n", n); - for (m = 0; m < ARRAY_SIZE(methods); m++) - if (n == methods[m] && - wsi->u.hdr.ah->frag_index[ - methods[m]]) { - lwsl_warn("Duplicated method\n"); - return -1; - } + if (n == WSI_TOKEN_GET_URI && + wsi->u.hdr.ah->frag_index[WSI_TOKEN_GET_URI]) { + lwsl_warn("Duplicated GET\n"); + return -1; + } else if (n == WSI_TOKEN_POST_URI && + wsi->u.hdr.ah->frag_index[WSI_TOKEN_POST_URI]) { + lwsl_warn("Duplicated POST\n"); + return -1; + } else if (n == WSI_TOKEN_OPTIONS_URI && + wsi->u.hdr.ah->frag_index[WSI_TOKEN_OPTIONS_URI]) { + lwsl_warn("Duplicated OPTIONS\n"); + return -1; + } /* * WSORIGIN is protocol equiv to ORIGIN, @@ -464,11 +470,13 @@ int libwebsocket_parse( wsi->u.hdr.parser_state = (enum lws_token_indexes) (WSI_TOKEN_GET_URI + n); - if (context->token_limits) - wsi->u.hdr.current_token_limit = + if( context->token_limits ) { + wsi->u.hdr.current_token_limit = \ context->token_limits->token_limit[wsi->u.hdr.parser_state]; - else + } + else { wsi->u.hdr.current_token_limit = sizeof(wsi->u.hdr.ah->data); + }; if (wsi->u.hdr.parser_state == WSI_TOKEN_CHALLENGE) goto set_parsing_complete; @@ -534,6 +542,9 @@ int libwebsocket_parse( case WSI_PARSING_COMPLETE: lwsl_parser("WSI_PARSING_COMPLETE '%c'\n", c); break; + + default: /* keep gcc happy */ + break; } return 0; @@ -815,10 +826,8 @@ libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c) case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED: - if (!wsi->u.ws.rx_user_buffer) { + if (!wsi->u.ws.rx_user_buffer) lwsl_err("NULL user buffer...\n"); - return 1; - } if (wsi->u.ws.all_zero_nonce) wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING + @@ -886,46 +895,16 @@ libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c) case LWS_WS_OPCODE_07__PING: lwsl_info("received %d byte ping, sending pong\n", wsi->u.ws.rx_user_buffer_head); - - if (wsi->u.ws.ping_pending_flag) { - /* - * there is already a pending ping payload - * we should just log and drop - */ - lwsl_parser("DROP PING since one pending\n"); - goto ping_drop; - } - - /* control packets can only be < 128 bytes long */ - if (wsi->u.ws.rx_user_buffer_head > 128 - 4) { - lwsl_parser("DROP PING payload too large\n"); - goto ping_drop; - } - - /* if existing buffer is too small, drop it */ - if (wsi->u.ws.ping_payload_buf && - wsi->u.ws.ping_payload_alloc < wsi->u.ws.rx_user_buffer_head) { - lws_free2(wsi->u.ws.ping_payload_buf); - } - - /* if no buffer, allocate it */ - if (!wsi->u.ws.ping_payload_buf) { - wsi->u.ws.ping_payload_buf = lws_malloc(wsi->u.ws.rx_user_buffer_head - + LWS_SEND_BUFFER_PRE_PADDING); - wsi->u.ws.ping_payload_alloc = wsi->u.ws.rx_user_buffer_head; - } - - /* stash the pong payload */ - memcpy(wsi->u.ws.ping_payload_buf + LWS_SEND_BUFFER_PRE_PADDING, - &wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING], - wsi->u.ws.rx_user_buffer_head); - - wsi->u.ws.ping_payload_len = wsi->u.ws.rx_user_buffer_head; - wsi->u.ws.ping_pending_flag = 1; - - /* get it sent as soon as possible */ - libwebsocket_callback_on_writable(wsi->protocol->owning_server, wsi); -ping_drop: + lwsl_hexdump(&wsi->u.ws.rx_user_buffer[ + LWS_SEND_BUFFER_PRE_PADDING], + wsi->u.ws.rx_user_buffer_head); + /* parrot the ping packet payload back as a pong */ + n = libwebsocket_write(wsi, (unsigned char *) + &wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING], + wsi->u.ws.rx_user_buffer_head, LWS_WRITE_PONG); + if (n < 0) + return -1; + /* ... then just drop it */ wsi->u.ws.rx_user_buffer_head = 0; return 0; diff --git a/lib/pollfd.c b/lib/pollfd.c index 19905eff78..3995a378ac 100755 --- a/lib/pollfd.c +++ b/lib/pollfd.c @@ -32,13 +32,11 @@ insert_wsi_socket_into_fds(struct libwebsocket_context *context, return 1; } -#ifndef _WIN32 if (wsi->sock >= context->max_fds) { lwsl_err("Socket fd %d is too high (%d)\n", wsi->sock, context->max_fds); return 1; } -#endif assert(wsi); assert(wsi->sock >= 0); @@ -50,7 +48,7 @@ insert_wsi_socket_into_fds(struct libwebsocket_context *context, LWS_CALLBACK_LOCK_POLL, wsi->user_space, (void *) &pa, 0); - insert_wsi(context, wsi); + context->lws_lookup[wsi->sock] = wsi; wsi->position_in_fds_table = context->fds_count; context->fds[context->fds_count].fd = wsi->sock; context->fds[context->fds_count].events = LWS_POLLIN; @@ -110,10 +108,10 @@ remove_wsi_socket_from_fds(struct libwebsocket_context *context, * (still same fd pointing to same wsi) */ /* end guy's "position in fds table" changed */ - wsi_from_fd(context,context->fds[context->fds_count].fd)-> - position_in_fds_table = m; + context->lws_lookup[context->fds[context->fds_count].fd]-> + position_in_fds_table = m; /* deletion guy's lws_lookup entry needs nuking */ - delete_from_fd(context,wsi->sock); + context->lws_lookup[wsi->sock] = NULL; /* removed wsi has no position any more */ wsi->position_in_fds_table = -1; @@ -133,19 +131,12 @@ remove_wsi_socket_from_fds(struct libwebsocket_context *context, int lws_change_pollfd(struct libwebsocket *wsi, int _and, int _or) { - struct libwebsocket_context *context; + struct libwebsocket_context *context = wsi->protocol->owning_server; int tid; int sampled_tid; struct libwebsocket_pollfd *pfd; struct libwebsocket_pollargs pa; - if (!wsi || !wsi->protocol || wsi->position_in_fds_table < 0) - return 1; - - context = wsi->protocol->owning_server; - if (!context) - return 1; - pfd = &context->fds[wsi->position_in_fds_table]; pa.fd = wsi->sock; @@ -202,53 +193,6 @@ LWS_VISIBLE int libwebsocket_callback_on_writable(struct libwebsocket_context *context, struct libwebsocket *wsi) { -#ifdef LWS_USE_HTTP2 - struct libwebsocket *network_wsi, *wsi2; - int already; - - lwsl_info("%s: %p\n", __func__, wsi); - - if (wsi->mode != LWS_CONNMODE_HTTP2_SERVING) - goto network_sock; - - if (wsi->u.http2.requested_POLLOUT) { - lwsl_info("already pending writable\n"); - return 1; - } - - if (wsi->u.http2.tx_credit <= 0) { - /* - * other side is not able to cope with us sending - * anything so no matter if we have POLLOUT on our side. - * - * Delay waiting for our POLLOUT until peer indicates he has - * space for more using tx window command in http2 layer - */ - lwsl_info("%s: %p: waiting_tx_credit (%d)\n", __func__, wsi, wsi->u.http2.tx_credit); - wsi->u.http2.waiting_tx_credit = 1; - return 0; - } - - network_wsi = lws_http2_get_network_wsi(wsi); - already = network_wsi->u.http2.requested_POLLOUT; - - /* mark everybody above him as requesting pollout */ - - wsi2 = wsi; - while (wsi2) { - wsi2->u.http2.requested_POLLOUT = 1; - lwsl_info("mark %p pending writable\n", wsi2); - wsi2 = wsi2->u.http2.parent_wsi; - } - - /* for network action, act only on the network wsi */ - - wsi = network_wsi; - if (already) - return 1; -network_sock: -#endif - if (lws_ext_callback_for_each_active(wsi, LWS_EXT_CALLBACK_REQUEST_ON_WRITEABLE, NULL, 0)) return 1; @@ -284,7 +228,7 @@ libwebsocket_callback_on_writable_all_protocol( struct libwebsocket *wsi; for (n = 0; n < context->fds_count; n++) { - wsi = wsi_from_fd(context,context->fds[n].fd); + wsi = context->lws_lookup[context->fds[n].fd]; if (!wsi) continue; if (wsi->protocol == protocol) diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 5e73dff3b6..235be7f0c5 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -106,9 +106,11 @@ #include #endif #if defined (__ANDROID__) -#include + #include + #include #else -#include + #include + #include #endif #include #include @@ -161,7 +163,9 @@ #ifdef LWS_OPENSSL_SUPPORT #ifdef USE_CYASSL #include -#include +#include +unsigned char * +SHA1(const unsigned char *d, size_t n, unsigned char *md); #else #include #include @@ -209,26 +213,6 @@ typedef unsigned __int64 u_int64_t; #include #endif -#include - -#ifndef container_of -#define container_of(P,T,M) ((T *)((char *)(P) - offsetof(T, M))) -#endif - -#if defined(__QNX__) - #include - #if defined(__LITTLEENDIAN__) - #define BYTE_ORDER __LITTLEENDIAN__ - #define LITTLE_ENDIAN __LITTLEENDIAN__ - #define BIG_ENDIAN 4321 /* to show byte order (taken from gcc); for suppres warning that BIG_ENDIAN is not defined. */ - #endif - #if defined(__BIGENDIAN__) - #define BYTE_ORDER __BIGENDIAN__ - #define LITTLE_ENDIAN 1234 /* to show byte order (taken from gcc); for suppres warning that LITTLE_ENDIAN is not defined. */ - #define BIG_ENDIAN __BIGENDIAN__ - #endif -#endif - #if !defined(BYTE_ORDER) # define BYTE_ORDER __BYTE_ORDER #endif @@ -249,12 +233,6 @@ typedef unsigned __int64 u_int64_t; #define MSG_NOSIGNAL SO_NOSIGPIPE #endif -#ifdef _WIN32 -#ifndef FD_HASHTABLE_MODULUS -#define FD_HASHTABLE_MODULUS 32 -#endif -#endif - #ifndef LWS_MAX_HEADER_LEN #define LWS_MAX_HEADER_LEN 1024 #endif @@ -319,27 +297,6 @@ enum lws_connection_states { WSI_STATE_RETURNED_CLOSE_ALREADY, WSI_STATE_AWAITING_CLOSE_ACK, WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE, - - WSI_STATE_HTTP2_AWAIT_CLIENT_PREFACE, - WSI_STATE_HTTP2_ESTABLISHED_PRE_SETTINGS, - WSI_STATE_HTTP2_ESTABLISHED, -}; - -enum http_version { - HTTP_VERSION_1_0, - HTTP_VERSION_1_1, -}; - -enum http_connection_type { - HTTP_CONNECTION_CLOSE, - HTTP_CONNECTION_KEEP_ALIVE -}; - -enum lws_pending_protocol_send { - LWS_PPS_NONE, - LWS_PPS_HTTP2_MY_SETTINGS, - LWS_PPS_HTTP2_ACK_SETTINGS, - LWS_PPS_HTTP2_PONG, }; enum lws_rx_parse_state { @@ -378,8 +335,6 @@ enum connection_mode { LWS_CONNMODE_WS_SERVING, LWS_CONNMODE_WS_CLIENT, - - LWS_CONNMODE_HTTP2_SERVING, /* transient, ssl delay hiding */ LWS_CONNMODE_SSL_ACK_PENDING, @@ -418,25 +373,12 @@ struct lws_signal_watcher { }; #endif /* LWS_USE_LIBEV */ -#ifdef _WIN32 -#define LWS_FD_HASH(fd) ((fd ^ (fd >> 8) ^ (fd >> 16)) % FD_HASHTABLE_MODULUS) -struct libwebsocket_fd_hashtable { - struct libwebsocket **wsi; - int length; -}; -#endif - struct libwebsocket_context { #ifdef _WIN32 WSAEVENT *events; #endif struct libwebsocket_pollfd *fds; -#ifdef _WIN32 -/* different implementation between unix and windows */ - struct libwebsocket_fd_hashtable fd_hashtable[FD_HASHTABLE_MODULUS]; -#else - struct libwebsocket **lws_lookup; /* fd to wsi */ -#endif + struct libwebsocket **lws_lookup; /* fd to wsi */ int fds_count; #ifdef LWS_USE_LIBEV struct ev_loop* io_loop; @@ -490,13 +432,8 @@ struct libwebsocket_context { #ifdef LWS_OPENSSL_SUPPORT int use_ssl; int allow_non_ssl_on_ssl_port; - unsigned int user_supplied_ssl_ctx:1; SSL_CTX *ssl_ctx; SSL_CTX *ssl_client_ctx; - struct libwebsocket *pending_read_list; /* linked list */ -#define lws_ssl_anybody_has_buffered_read(ctx) (ctx->use_ssl && ctx->pending_read_list) -#else -#define lws_ssl_anybody_has_buffered_read(ctx) (0) #endif struct libwebsocket_protocols *protocols; int count_protocols; @@ -569,18 +506,6 @@ struct lws_fragments { unsigned char next_frag_index; }; -/* notice that these union members: - * - * hdr - * http - * http2 - * - * all have a pointer to allocated_headers struct as their first member. - * - * It means for allocated_headers access, the three union paths can all be - * used interchangably to access the same data - */ - struct allocated_headers { unsigned short next_frag_index; unsigned short pos; @@ -594,7 +519,6 @@ struct allocated_headers { }; struct _lws_http_mode_related { - /* MUST be first in struct */ struct allocated_headers *ah; /* mirroring _lws_header_related */ #if defined(WIN32) || defined(_WIN32) HANDLE fd; @@ -604,168 +528,13 @@ struct _lws_http_mode_related { unsigned long filepos; unsigned long filelen; - enum http_version request_version; - enum http_connection_type connection_type; int content_length; - int content_remain; -}; - - -#ifdef LWS_USE_HTTP2 - -enum lws_http2_settings { - LWS_HTTP2_SETTINGS__HEADER_TABLE_SIZE = 1, - LWS_HTTP2_SETTINGS__ENABLE_PUSH, - LWS_HTTP2_SETTINGS__MAX_CONCURRENT_STREAMS, - LWS_HTTP2_SETTINGS__INITIAL_WINDOW_SIZE, - LWS_HTTP2_SETTINGS__MAX_FRAME_SIZE, - LWS_HTTP2_SETTINGS__MAX_HEADER_LIST_SIZE, - - LWS_HTTP2_SETTINGS__COUNT /* always last */ -}; - -enum lws_http2_wellknown_frame_types { - LWS_HTTP2_FRAME_TYPE_DATA, - LWS_HTTP2_FRAME_TYPE_HEADERS, - LWS_HTTP2_FRAME_TYPE_PRIORITY, - LWS_HTTP2_FRAME_TYPE_RST_STREAM, - LWS_HTTP2_FRAME_TYPE_SETTINGS, - LWS_HTTP2_FRAME_TYPE_PUSH_PROMISE, - LWS_HTTP2_FRAME_TYPE_PING, - LWS_HTTP2_FRAME_TYPE_GOAWAY, - LWS_HTTP2_FRAME_TYPE_WINDOW_UPDATE, - LWS_HTTP2_FRAME_TYPE_CONTINUATION, - - LWS_HTTP2_FRAME_TYPE_COUNT /* always last */ -}; - -enum lws_http2_flags { - LWS_HTTP2_FLAG_END_STREAM = 1, - LWS_HTTP2_FLAG_END_HEADERS = 4, - LWS_HTTP2_FLAG_PADDED = 8, - LWS_HTTP2_FLAG_PRIORITY = 0x20, - - LWS_HTTP2_FLAG_SETTINGS_ACK = 1, -}; - -#define LWS_HTTP2_STREAM_ID_MASTER 0 -#define LWS_HTTP2_FRAME_HEADER_LENGTH 9 -#define LWS_HTTP2_SETTINGS_LENGTH 6 - -struct http2_settings { - unsigned int setting[LWS_HTTP2_SETTINGS__COUNT]; -}; - -enum http2_hpack_state { - - /* optional before first header block */ - HPKS_OPT_PADDING, - HKPS_OPT_E_DEPENDENCY, - HKPS_OPT_WEIGHT, - - /* header block */ - HPKS_TYPE, - - HPKS_IDX_EXT, - - HPKS_HLEN, - HPKS_HLEN_EXT, - - HPKS_DATA, - - /* optional after last header block */ - HKPS_OPT_DISCARD_PADDING, -}; - -enum http2_hpack_type { - HPKT_INDEXED_HDR_7, - HPKT_INDEXED_HDR_6_VALUE_INCR, - HPKT_LITERAL_HDR_VALUE_INCR, - HPKT_INDEXED_HDR_4_VALUE, - HPKT_LITERAL_HDR_VALUE, - HPKT_SIZE_5 -}; - -struct hpack_dt_entry { - int token; /* additions that don't map to a token are ignored */ - int arg_offset; - int arg_len; -}; - -struct hpack_dynamic_table { - struct hpack_dt_entry *entries; - char *args; - int pos; - int next; - int num_entries; - int args_length; -}; - -struct _lws_http2_related { - /* - * having this first lets us also re-use all HTTP union code - * and in turn, http_mode_related has allocated headers in right - * place so we can use the header apis on the wsi directly still - */ - struct _lws_http_mode_related http; /* MUST BE FIRST IN STRUCT */ - - struct http2_settings my_settings; - struct http2_settings peer_settings; - - struct libwebsocket *parent_wsi; - struct libwebsocket *next_child_wsi; - - struct hpack_dynamic_table *hpack_dyn_table; - - unsigned int count; - - /* frame */ - unsigned int length; - unsigned int stream_id; - struct libwebsocket *stream_wsi; - unsigned char type; - unsigned char flags; - unsigned char frame_state; - unsigned char padding; - - unsigned char ping_payload[8]; - - unsigned short round_robin_POLLOUT; - unsigned short count_POLLOUT_children; - - unsigned int END_STREAM:1; - unsigned int END_HEADERS:1; - unsigned int send_END_STREAM:1; - unsigned int GOING_AWAY; - unsigned int requested_POLLOUT:1; - unsigned int waiting_tx_credit:1; - - /* hpack */ - enum http2_hpack_state hpack; - enum http2_hpack_type hpack_type; - unsigned int header_index; - unsigned int hpack_len; - unsigned short hpack_pos; - unsigned char hpack_m; - unsigned int hpack_e_dep; - unsigned int huff:1; - unsigned int value:1; - - /* negative credit is mandated by the spec */ - int tx_credit; - unsigned int my_stream_id; - unsigned int child_count; - int my_priority; - unsigned char initialized; - unsigned char one_setting[LWS_HTTP2_SETTINGS_LENGTH]; + int content_length_seen; + int body_index; + unsigned char *post_buffer; }; -#define HTTP2_IS_TOPLEVEL_WSI(wsi) (!wsi->u.http2.parent_wsi) - -#endif - struct _lws_header_related { - /* MUST be first in struct */ struct allocated_headers *ah; short lextable_pos; unsigned short current_token_limit; @@ -787,15 +556,13 @@ struct _lws_websocket_related { unsigned int frame_is_binary:1; unsigned int all_zero_nonce:1; short close_reason; /* enum lws_close_status */ - + unsigned char *rxflow_buffer; + int rxflow_len; + int rxflow_pos; + unsigned int rxflow_change_to:2; unsigned int this_frame_masked:1; unsigned int inside_frame:1; /* next write will be more of frame */ unsigned int clean_buffer:1; /* buffer not rewritten by extension */ - - unsigned char *ping_payload_buf; /* non-NULL if malloc'd */ - unsigned int ping_payload_alloc; /* length malloc'd */ - unsigned int ping_payload_len; - unsigned char ping_pending_flag; }; struct libwebsocket { @@ -815,7 +582,6 @@ struct libwebsocket { unsigned int extension_data_pending:1; #endif unsigned char ietf_spec_revision; - enum lws_pending_protocol_send pps; char mode; /* enum connection_mode */ char state; /* enum lws_connection_states */ @@ -824,21 +590,16 @@ struct libwebsocket { unsigned int hdr_parsing_completed:1; unsigned int user_space_externally_allocated:1; - unsigned int socket_is_permanently_unusable:1; char pending_timeout; /* enum pending_timeout */ time_t pending_timeout_limit; + int sock; int position_in_fds_table; #ifdef LWS_LATENCY unsigned long action_start; unsigned long latency_start; #endif - /* rxflow handling */ - unsigned char *rxflow_buffer; - int rxflow_len; - int rxflow_pos; - unsigned int rxflow_change_to:2; /* truncated send handling */ unsigned char *truncated_send_malloc; /* non-NULL means buffering in progress */ @@ -852,9 +613,6 @@ struct libwebsocket { union u { struct _lws_http_mode_related http; -#ifdef LWS_USE_HTTP2 - struct _lws_http2_related http2; -#endif struct _lws_header_related hdr; struct _lws_websocket_related ws; } u; @@ -862,9 +620,7 @@ struct libwebsocket { #ifdef LWS_OPENSSL_SUPPORT SSL *ssl; BIO *client_bio; - struct libwebsocket *pending_read_list_prev, *pending_read_list_next; unsigned int use_ssl:2; - unsigned int upgraded:1; #endif #ifdef _WIN32 @@ -881,15 +637,13 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context, LWS_EXTERN int remove_wsi_socket_from_fds(struct libwebsocket_context *context, struct libwebsocket *wsi); -LWS_EXTERN int -lws_rxflow_cache(struct libwebsocket *wsi, unsigned char *buf, int n, int len); #ifndef LWS_LATENCY static inline void lws_latency(struct libwebsocket_context *context, struct libwebsocket *wsi, const char *action, - int ret, int completion) { do { } while (0); } + int ret, int completion) { while (0); } static inline void lws_latency_pre(struct libwebsocket_context *context, - struct libwebsocket *wsi) { do { } while (0); } + struct libwebsocket *wsi) { while (0); } #else #define lws_latency_pre(_context, _wsi) lws_latency(_context, _wsi, NULL, 0, 0) extern void @@ -898,9 +652,6 @@ lws_latency(struct libwebsocket_context *context, int ret, int completion); #endif -LWS_EXTERN void lws_set_protocol_write_pending(struct libwebsocket_context *context, - struct libwebsocket *wsi, - enum lws_pending_protocol_send pend); LWS_EXTERN int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c); @@ -908,27 +659,12 @@ LWS_EXTERN int libwebsocket_parse(struct libwebsocket_context *context, struct libwebsocket *wsi, unsigned char c); -LWS_EXTERN int -lws_http_action(struct libwebsocket_context *context, struct libwebsocket *wsi); - LWS_EXTERN int lws_b64_selftest(void); -#ifdef _WIN32 LWS_EXTERN struct libwebsocket * wsi_from_fd(struct libwebsocket_context *context, int fd); -LWS_EXTERN int -insert_wsi(struct libwebsocket_context *context, struct libwebsocket *wsi); - -LWS_EXTERN int -delete_from_fd(struct libwebsocket_context *context, int fd); -#else -#define wsi_from_fd(A,B) A->lws_lookup[B] -#define insert_wsi(A,B) A->lws_lookup[B->sock]=B -#define delete_from_fd(A,B) A->lws_lookup[B]=0 -#endif - LWS_EXTERN int insert_wsi_socket_into_fds(struct libwebsocket_context *context, struct libwebsocket *wsi); @@ -955,7 +691,6 @@ libwebsockets_generate_client_handshake(struct libwebsocket_context *context, LWS_EXTERN int lws_handle_POLLOUT_event(struct libwebsocket_context *context, struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd); - /* * EXTENSIONS */ @@ -999,58 +734,12 @@ lws_issue_raw_ext_access(struct libwebsocket *wsi, LWS_EXTERN int _libwebsocket_rx_flow_control(struct libwebsocket *wsi); -LWS_EXTERN void -lws_union_transition(struct libwebsocket *wsi, enum connection_mode mode); - LWS_EXTERN int user_callback_handle_rxflow(callback_function, struct libwebsocket_context *context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len); -#ifdef LWS_USE_HTTP2 -LWS_EXTERN struct libwebsocket *lws_http2_get_network_wsi(struct libwebsocket *wsi); -struct libwebsocket * lws_http2_get_nth_child(struct libwebsocket *wsi, int n); -LWS_EXTERN int -lws_http2_interpret_settings_payload(struct http2_settings *settings, unsigned char *buf, int len); -LWS_EXTERN void lws_http2_init(struct http2_settings *settings); -LWS_EXTERN int -lws_http2_parser(struct libwebsocket_context *context, - struct libwebsocket *wsi, unsigned char c); -LWS_EXTERN int lws_http2_do_pps_send(struct libwebsocket_context *context, struct libwebsocket *wsi); -LWS_EXTERN int lws_http2_frame_write(struct libwebsocket *wsi, int type, int flags, unsigned int sid, unsigned int len, unsigned char *buf); -LWS_EXTERN struct libwebsocket * -lws_http2_wsi_from_id(struct libwebsocket *wsi, unsigned int sid); -LWS_EXTERN int lws_hpack_interpret(struct libwebsocket_context *context, - struct libwebsocket *wsi, - unsigned char c); -LWS_EXTERN int -lws_add_http2_header_by_name(struct libwebsocket_context *context, - struct libwebsocket *wsi, - const unsigned char *name, - const unsigned char *value, - int length, - unsigned char **p, - unsigned char *end); -LWS_EXTERN int -lws_add_http2_header_by_token(struct libwebsocket_context *context, - struct libwebsocket *wsi, - enum lws_token_indexes token, - const unsigned char *value, - int length, - unsigned char **p, - unsigned char *end); -LWS_EXTERN int -lws_add_http2_header_status(struct libwebsocket_context *context, - struct libwebsocket *wsi, - unsigned int code, - unsigned char **p, - unsigned char *end); -LWS_EXTERN -void lws_http2_configure_if_upgraded(struct libwebsocket *wsi); -#else -#define lws_http2_configure_if_upgraded(x) -#endif LWS_EXTERN int lws_plat_set_socket_options(struct libwebsocket_context *context, int fd); @@ -1058,9 +747,6 @@ lws_plat_set_socket_options(struct libwebsocket_context *context, int fd); LWS_EXTERN int lws_allocate_header_table(struct libwebsocket *wsi); -LWS_EXTERN int -lws_free_header_table(struct libwebsocket *wsi); - LWS_EXTERN char * lws_hdr_simple_ptr(struct libwebsocket *wsi, enum lws_token_indexes h); @@ -1115,21 +801,23 @@ enum lws_ssl_capable_status { #ifndef LWS_OPENSSL_SUPPORT #define LWS_SSL_ENABLED(context) (0) +unsigned char * +SHA1(const unsigned char *d, size_t n, unsigned char *md); #define lws_context_init_server_ssl(_a, _b) (0) #define lws_ssl_destroy(_a) #define lws_context_init_http2_ssl(_a) +#define lws_ssl_pending(_a) (0) #define lws_ssl_capable_read lws_ssl_capable_read_no_ssl #define lws_ssl_capable_write lws_ssl_capable_write_no_ssl #define lws_server_socket_service_ssl(_a, _b, _c, _d, _e) (0) #define lws_ssl_close(_a) (0) #define lws_ssl_context_destroy(_a) -#define lws_ssl_remove_wsi_from_buffered_list(_a, _b) #else #define LWS_SSL_ENABLED(context) (context->use_ssl) +LWS_EXTERN int lws_ssl_pending(struct libwebsocket *wsi); LWS_EXTERN int openssl_websocket_private_data_index; LWS_EXTERN int -lws_ssl_capable_read(struct libwebsocket_context *context, - struct libwebsocket *wsi, unsigned char *buf, int len); +lws_ssl_capable_read(struct libwebsocket *wsi, unsigned char *buf, int len); LWS_EXTERN int lws_ssl_capable_write(struct libwebsocket *wsi, unsigned char *buf, int len); @@ -1141,9 +829,6 @@ LWS_EXTERN int lws_ssl_close(struct libwebsocket *wsi); LWS_EXTERN void lws_ssl_context_destroy(struct libwebsocket_context *context); -LWS_VISIBLE void -lws_ssl_remove_wsi_from_buffered_list(struct libwebsocket_context *context, - struct libwebsocket *wsi); #ifndef LWS_NO_SERVER LWS_EXTERN int lws_context_init_server_ssl(struct lws_context_creation_info *info, @@ -1165,8 +850,7 @@ lws_context_init_http2_ssl(struct libwebsocket_context *context); #endif LWS_EXTERN int -lws_ssl_capable_read_no_ssl(struct libwebsocket_context *context, - struct libwebsocket *wsi, unsigned char *buf, int len); +lws_ssl_capable_read_no_ssl(struct libwebsocket *wsi, unsigned char *buf, int len); LWS_EXTERN int lws_ssl_capable_write_no_ssl(struct libwebsocket *wsi, unsigned char *buf, int len); @@ -1200,23 +884,6 @@ lws_ssl_capable_write_no_ssl(struct libwebsocket *wsi, unsigned char *buf, int l #define _libwebsocket_rx_flow_control(_a) (0) #define lws_handshake_server(_a, _b, _c, _d) (0) #endif - -LWS_EXTERN int libwebsockets_get_addresses(struct libwebsocket_context *context, - void *ads, char *name, int name_len, - char *rip, int rip_len); - -/* - * custom allocator - */ -LWS_EXTERN void* -lws_realloc(void *ptr, size_t size); - -LWS_EXTERN void* -lws_zalloc(size_t size); - -#define lws_malloc(S) lws_realloc(NULL, S) -#define lws_free(P) lws_realloc(P, 0) -#define lws_free2(P) do { lws_realloc(P, 0); (P) = NULL; } while(0) /* * lws_plat_ diff --git a/lib/server-handshake.c b/lib/server-handshake.c index 298fae4387..56cf9a13e4 100644 --- a/lib/server-handshake.c +++ b/lib/server-handshake.c @@ -124,12 +124,15 @@ lws_extension_server_handshake(struct libwebsocket_context *context, wsi->active_extensions_user[ wsi->count_active_extensions] = - lws_zalloc(ext->per_session_data_size); + malloc(ext->per_session_data_size); if (wsi->active_extensions_user[ wsi->count_active_extensions] == NULL) { lwsl_err("Out of mem\n"); return 1; } + memset(wsi->active_extensions_user[ + wsi->count_active_extensions], 0, + ext->per_session_data_size); wsi->active_extensions[ wsi->count_active_extensions] = ext; @@ -151,7 +154,7 @@ lws_extension_server_handshake(struct libwebsocket_context *context, n = 0; } - + return 0; } #endif @@ -185,7 +188,7 @@ handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi) "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", lws_hdr_simple_ptr(wsi, WSI_TOKEN_KEY)); - libwebsockets_SHA1(context->service_buffer, n, hash); + SHA1(context->service_buffer, n, hash); accept_len = lws_b64_encode_string((char *)hash, 20, (char *)context->service_buffer, @@ -203,7 +206,7 @@ handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi) /* make a buffer big enough for everything */ - response = (char *)context->service_buffer + MAX_WEBSOCKET_04_KEY_LEN + LWS_SEND_BUFFER_PRE_PADDING; + response = (char *)context->service_buffer + MAX_WEBSOCKET_04_KEY_LEN; p = response; LWS_CPYAPP(p, "HTTP/1.1 101 Switching Protocols\x0d\x0a" "Upgrade: WebSocket\x0d\x0a" @@ -228,9 +231,6 @@ handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi) if (lws_extension_server_handshake(context, wsi, &p)) goto bail; #endif - - //LWS_CPYAPP(p, "\x0d\x0a""An-unknown-header: blah"); - /* end of response packet */ LWS_CPYAPP(p, "\x0d\x0a\x0d\x0a"); @@ -246,7 +246,7 @@ handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi) fwrite(response, 1, p - response, stderr); #endif n = libwebsocket_write(wsi, (unsigned char *)response, - p - response, LWS_WRITE_HTTP_HEADERS); + p - response, LWS_WRITE_HTTP); if (n != (p - response)) { lwsl_debug("handshake_0405: ERROR writing to socket\n"); goto bail; @@ -271,7 +271,10 @@ handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi) bail: /* free up his parsing allocations */ - lws_free_header_table(wsi); + + if (wsi->u.hdr.ah) + free(wsi->u.hdr.ah); + return -1; } diff --git a/lib/server.c b/lib/server.c index d8f00c2e69..6afd570e29 100644 --- a/lib/server.c +++ b/lib/server.c @@ -57,11 +57,8 @@ int lws_context_init_server(struct lws_context_creation_info *info, /* * allow us to restart even if old sockets in TIME_WAIT */ - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, - (const void *)&opt, sizeof(opt)) < 0) { - compatible_close(sockfd); - return 1; - } + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, + (const void *)&opt, sizeof(opt)); lws_plat_set_socket_options(context, sockfd); @@ -102,7 +99,7 @@ int lws_context_init_server(struct lws_context_creation_info *info, compatible_close(sockfd); return 1; } - + if (getsockname(sockfd, (struct sockaddr *)&sin, &len) == -1) lwsl_warn("getsockname: %s\n", strerror(LWS_ERRNO)); else @@ -110,12 +107,13 @@ int lws_context_init_server(struct lws_context_creation_info *info, context->listen_port = info->port; - wsi = lws_zalloc(sizeof(struct libwebsocket)); + wsi = (struct libwebsocket *)malloc(sizeof(struct libwebsocket)); if (wsi == NULL) { lwsl_err("Out of mem\n"); compatible_close(sockfd); return 1; } + memset(wsi, 0, sizeof(struct libwebsocket)); wsi->sock = sockfd; wsi->mode = LWS_CONNMODE_SERVER_LISTENER; @@ -127,7 +125,7 @@ int lws_context_init_server(struct lws_context_creation_info *info, listen(sockfd, LWS_SOMAXCONN); lwsl_notice(" Listening on port %d\n", info->port); - + return 0; } @@ -137,11 +135,11 @@ _libwebsocket_rx_flow_control(struct libwebsocket *wsi) struct libwebsocket_context *context = wsi->protocol->owning_server; /* there is no pending change */ - if (!(wsi->rxflow_change_to & LWS_RXFLOW_PENDING_CHANGE)) + if (!(wsi->u.ws.rxflow_change_to & LWS_RXFLOW_PENDING_CHANGE)) return 0; /* stuff is still buffered, not ready to really accept new input */ - if (wsi->rxflow_buffer) { + if (wsi->u.ws.rxflow_buffer) { /* get ourselves called back to deal with stashed buffer */ libwebsocket_callback_on_writable(context, wsi); return 0; @@ -149,14 +147,14 @@ _libwebsocket_rx_flow_control(struct libwebsocket *wsi) /* pending is cleared, we can change rxflow state */ - wsi->rxflow_change_to &= ~LWS_RXFLOW_PENDING_CHANGE; + wsi->u.ws.rxflow_change_to &= ~LWS_RXFLOW_PENDING_CHANGE; lwsl_info("rxflow: wsi %p change_to %d\n", wsi, - wsi->rxflow_change_to & LWS_RXFLOW_ALLOW); + wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW); /* adjust the pollfd for this wsi */ - if (wsi->rxflow_change_to & LWS_RXFLOW_ALLOW) { + if (wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW) { if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) { lwsl_info("%s: fail\n", __func__); return -1; @@ -168,171 +166,15 @@ _libwebsocket_rx_flow_control(struct libwebsocket *wsi) return 0; } -int lws_http_action(struct libwebsocket_context *context, - struct libwebsocket *wsi) -{ - char *uri_ptr = NULL; - int uri_len = 0; - enum http_version request_version; - enum http_connection_type connection_type; - int http_version_len; - char content_length_str[32]; - char http_version_str[10]; - char http_conn_str[20]; - int n, count = 0; - static const unsigned char methods[] = { - WSI_TOKEN_GET_URI, - WSI_TOKEN_POST_URI, - WSI_TOKEN_OPTIONS_URI, - WSI_TOKEN_PUT_URI, - WSI_TOKEN_PATCH_URI, - WSI_TOKEN_DELETE_URI, -#ifdef LWS_USE_HTTP2 - WSI_TOKEN_HTTP_COLON_PATH, -#endif - }; -#ifdef _DEBUG - static const char * const method_names[] = { - "GET", "POST", "OPTIONS", "PUT", "PATCH", "DELETE", -#ifdef LWS_USE_HTTP2 - ":path", -#endif - }; -#endif - - /* it's not websocket.... shall we accept it as http? */ - - for (n = 0; n < ARRAY_SIZE(methods); n++) - if (lws_hdr_total_length(wsi, methods[n])) - count++; - if (!count) { - lwsl_warn("Missing URI in HTTP request\n"); - goto bail_nuke_ah; - } - - if (count != 1) { - lwsl_warn("multiple methods?\n"); - goto bail_nuke_ah; - } - - if (libwebsocket_ensure_user_space(wsi)) - goto bail_nuke_ah; - - for (n = 0; n < ARRAY_SIZE(methods); n++) - if (lws_hdr_total_length(wsi, methods[n])) { - uri_ptr = lws_hdr_simple_ptr(wsi, methods[n]); - uri_len = lws_hdr_total_length(wsi, methods[n]); - lwsl_info("Method: %s request for '%s'\n", - method_names[n], uri_ptr); - break; - } - - /* HTTP header had a content length? */ - - wsi->u.http.content_length = 0; - if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) || - lws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI) || - lws_hdr_total_length(wsi, WSI_TOKEN_PUT_URI)) - wsi->u.http.content_length = 100 * 1024 * 1024; - - if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) { - lws_hdr_copy(wsi, content_length_str, - sizeof(content_length_str) - 1, - WSI_TOKEN_HTTP_CONTENT_LENGTH); - wsi->u.http.content_length = atoi(content_length_str); - } - - /* http_version? Default to 1.0, override with token: */ - request_version = HTTP_VERSION_1_0; - - /* Works for single digit HTTP versions. : */ - http_version_len = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP); - if (http_version_len > 7) { - lws_hdr_copy(wsi, http_version_str, - sizeof(http_version_str) - 1, WSI_TOKEN_HTTP); - if (http_version_str[5] == '1' && http_version_str[7] == '1') - request_version = HTTP_VERSION_1_1; - } - wsi->u.http.request_version = request_version; - - /* HTTP/1.1 defaults to "keep-alive", 1.0 to "close" */ - if (request_version == HTTP_VERSION_1_1) - connection_type = HTTP_CONNECTION_KEEP_ALIVE; - else - connection_type = HTTP_CONNECTION_CLOSE; - - /* Override default if http "Connection:" header: */ - if (lws_hdr_total_length(wsi, WSI_TOKEN_CONNECTION)) { - lws_hdr_copy(wsi, http_conn_str, sizeof(http_conn_str) - 1, - WSI_TOKEN_CONNECTION); - http_conn_str[sizeof(http_conn_str) - 1] = '\0'; - if (!strcasecmp(http_conn_str, "keep-alive")) - connection_type = HTTP_CONNECTION_KEEP_ALIVE; - else - if (strcasecmp(http_conn_str, "close")) - connection_type = HTTP_CONNECTION_CLOSE; - } - wsi->u.http.connection_type = connection_type; - - n = 0; - if (wsi->protocol->callback) - n = wsi->protocol->callback(context, wsi, - LWS_CALLBACK_FILTER_HTTP_CONNECTION, - wsi->user_space, uri_ptr, uri_len); - - if (!n) { - /* - * if there is content supposed to be coming, - * put a timeout on it having arrived - */ - libwebsocket_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT, - AWAITING_TIMEOUT); - - if (wsi->protocol->callback) - n = wsi->protocol->callback(context, wsi, - LWS_CALLBACK_HTTP, - wsi->user_space, uri_ptr, uri_len); - } - - /* now drop the header info we kept a pointer to */ - lws_free2(wsi->u.http.ah); - - if (n) { - lwsl_info("LWS_CALLBACK_HTTP closing\n"); - return 1; /* struct ah ptr already nuked */ } - - /* - * If we're not issuing a file, check for content_length or - * HTTP keep-alive. No keep-alive header allocation for - * ISSUING_FILE, as this uses HTTP/1.0. - * - * In any case, return 0 and let libwebsocket_read decide how to - * proceed based on state - */ - if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE) - /* Prepare to read body if we have a content length: */ - if (wsi->u.http.content_length > 0) - wsi->state = WSI_STATE_HTTP_BODY; - - return 0; - -bail_nuke_ah: - /* drop the header info */ - lws_free2(wsi->u.hdr.ah); - - return 1; -} - int lws_handshake_server(struct libwebsocket_context *context, struct libwebsocket *wsi, unsigned char **buf, size_t len) { struct allocated_headers *ah; - int protocol_len; - char protocol_list[128]; - char protocol_name[32]; - char *p; - int n, hit; + char *uri_ptr = NULL; + int uri_len = 0; + char content_length_str[32]; + int n; /* LWS_CONNMODE_WS_SERVING */ @@ -354,148 +196,166 @@ int lws_handshake_server(struct libwebsocket_context *context, if (!lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE) || !lws_hdr_total_length(wsi, WSI_TOKEN_CONNECTION)) { - + + /* it's not websocket.... shall we accept it as http? */ + + if (!lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) && + !lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) && + !lws_hdr_total_length(wsi, WSI_TOKEN_OPTIONS_URI)) { + lwsl_warn("Missing URI in HTTP request\n"); + goto bail_nuke_ah; + } + + if (lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) && + lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) { + lwsl_warn("GET and POST methods?\n"); + goto bail_nuke_ah; + } + + if (libwebsocket_ensure_user_space(wsi)) + goto bail_nuke_ah; + + if (lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI)) { + uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI); + uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI); + lwsl_info("HTTP GET request for '%s'\n", + lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI)); + + } + if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) { + lwsl_info("HTTP POST request for '%s'\n", + lws_hdr_simple_ptr(wsi, WSI_TOKEN_POST_URI)); + uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_POST_URI); + uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI); + } + if (lws_hdr_total_length(wsi, WSI_TOKEN_OPTIONS_URI)) { + lwsl_info("HTTP OPTIONS request for '%s'\n", + lws_hdr_simple_ptr(wsi, WSI_TOKEN_OPTIONS_URI)); + uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_OPTIONS_URI); + uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_OPTIONS_URI); + } + + /* + * Hm we still need the headers so the + * callback can look at leaders like the URI, but we + * need to transition to http union state.... hold a + * copy of u.hdr.ah and deallocate afterwards + */ ah = wsi->u.hdr.ah; - - lws_union_transition(wsi, LWS_CONNMODE_HTTP_SERVING_ACCEPTED); + + /* union transition */ + memset(&wsi->u, 0, sizeof(wsi->u)); + wsi->mode = LWS_CONNMODE_HTTP_SERVING_ACCEPTED; wsi->state = WSI_STATE_HTTP; wsi->u.http.fd = LWS_INVALID_FILE; /* expose it at the same offset as u.hdr */ wsi->u.http.ah = ah; - - n = lws_http_action(context, wsi); - return n; - } + /* HTTP header had a content length? */ - if (!strcasecmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE), - "websocket")) - goto upgrade_ws; -#ifdef LWS_USE_HTTP2 - if (!strcasecmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE), - "h2c-14")) - goto upgrade_h2c; -#endif - /* dunno what he wanted to upgrade to */ - goto bail_nuke_ah; + wsi->u.http.content_length = 0; + if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) + wsi->u.http.content_length = 100 * 1024 * 1024; -#ifdef LWS_USE_HTTP2 -upgrade_h2c: - if (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP2_SETTINGS)) { - lwsl_err("missing http2_settings\n"); - goto bail_nuke_ah; - } + if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) { + lws_hdr_copy(wsi, content_length_str, + sizeof(content_length_str) - 1, + WSI_TOKEN_HTTP_CONTENT_LENGTH); + wsi->u.http.content_length = atoi(content_length_str); + } - lwsl_err("h2c upgrade...\n"); + if (wsi->u.http.content_length > 0) { + wsi->u.http.body_index = 0; + n = wsi->protocol->rx_buffer_size; + if (!n) + n = LWS_MAX_SOCKET_IO_BUF; + wsi->u.http.post_buffer = malloc(n); + if (!wsi->u.http.post_buffer) { + lwsl_err("Unable to allocate post buffer\n"); + n = -1; + goto cleanup; + } + } - p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP2_SETTINGS); - /* convert the peer's HTTP-Settings */ - n = lws_b64_decode_string(p, protocol_list, sizeof(protocol_list)); - if (n < 0) { - lwsl_parser("HTTP2_SETTINGS too long\n"); - return 1; - } + n = 0; + if (wsi->protocol->callback) + n = wsi->protocol->callback(context, wsi, + LWS_CALLBACK_FILTER_HTTP_CONNECTION, + wsi->user_space, uri_ptr, uri_len); - /* adopt the header info */ + if (!n) { + /* + * if there is content supposed to be coming, + * put a timeout on it having arrived + */ + libwebsocket_set_timeout(wsi, + PENDING_TIMEOUT_HTTP_CONTENT, + AWAITING_TIMEOUT); - ah = wsi->u.hdr.ah; + if (wsi->protocol->callback) + n = wsi->protocol->callback(context, wsi, + LWS_CALLBACK_HTTP, + wsi->user_space, uri_ptr, uri_len); + } - lws_union_transition(wsi, LWS_CONNMODE_HTTP2_SERVING); - - /* http2 union member has http union struct at start */ - wsi->u.http.ah = ah; - - lws_http2_init(&wsi->u.http2.peer_settings); - lws_http2_init(&wsi->u.http2.my_settings); - - /* HTTP2 union */ - - lws_http2_interpret_settings_payload(&wsi->u.http2.peer_settings, (unsigned char *)protocol_list, n); - - strcpy(protocol_list, - "HTTP/1.1 101 Switching Protocols\x0d\x0a" - "Connection: Upgrade\x0d\x0a" - "Upgrade: h2c\x0d\x0a\x0d\x0a"); - n = lws_issue_raw(wsi, (unsigned char *)protocol_list, - strlen(protocol_list)); - if (n != strlen(protocol_list)) { - lwsl_debug("http2 switch: ERROR writing to socket\n"); - return 1; +cleanup: + /* now drop the header info we kept a pointer to */ + if (ah) + free(ah); + /* not possible to continue to use past here */ + wsi->u.http.ah = NULL; + + if (n) { + lwsl_info("LWS_CALLBACK_HTTP closing\n"); + return 1; /* struct ah ptr already nuked */ + } + + /* + * (if callback didn't start sending a file) + * deal with anything else as body, whether + * there was a content-length or not + */ + + if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE) + wsi->state = WSI_STATE_HTTP_BODY; + return 2; /* goto http_postbody; */ } - - wsi->state = WSI_STATE_HTTP2_AWAIT_CLIENT_PREFACE; - - return 0; -#endif -upgrade_ws: if (!wsi->protocol) lwsl_err("NULL protocol at libwebsocket_read\n"); /* * It's websocket * - * Select the first protocol we support from the list - * the client sent us. - * - * Copy it to remove header fragmentation + * Make sure user side is happy about protocol */ - if (lws_hdr_copy(wsi, protocol_list, sizeof(protocol_list) - 1, - WSI_TOKEN_PROTOCOL) < 0) { - lwsl_err("protocol list too long"); - goto bail_nuke_ah; - } + while (wsi->protocol->callback) { - protocol_len = lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL); - protocol_list[protocol_len] = '\0'; - p = protocol_list; - hit = 0; - - while (*p && !hit) { - n = 0; - while (n < sizeof(protocol_name) - 1 && *p && *p !=',') - protocol_name[n++] = *p++; - protocol_name[n] = '\0'; - if (*p) - p++; - - lwsl_info("checking %s\n", protocol_name); - - n = 0; - while (wsi->protocol && context->protocols[n].callback) { - if (!wsi->protocol->name) { - n++; - continue; - } - if (!strcmp(context->protocols[n].name, - protocol_name)) { - lwsl_info("prot match %d\n", n); - wsi->protocol = &context->protocols[n]; - hit = 1; + if (!lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL)) { + if (wsi->protocol->name == NULL) + break; + } else + if (wsi->protocol->name && strcmp( + lws_hdr_simple_ptr(wsi, + WSI_TOKEN_PROTOCOL), + wsi->protocol->name) == 0) break; - } - n++; - } + wsi->protocol++; } /* we didn't find a protocol he wanted? */ - if (!hit) { + if (wsi->protocol->callback == NULL) { if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL) == NULL) { - /* - * some clients only have one protocol and - * do not sent the protocol list header... - * allow it and match to protocol 0 - */ - lwsl_info("defaulting to prot 0 handler\n"); + lwsl_info("no protocol -> prot 0 handler\n"); wsi->protocol = &context->protocols[0]; } else { - lwsl_err("No protocol from list \"%s\" supported\n", - protocol_list); + lwsl_err("Req protocol %s not supported\n", + lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL)); goto bail_nuke_ah; } } @@ -539,9 +399,15 @@ int lws_handshake_server(struct libwebsocket_context *context, } /* drop the header info -- no bail_nuke_ah after this */ - lws_free_header_table(wsi); - lws_union_transition(wsi, LWS_CONNMODE_WS_SERVING); + if (wsi->u.hdr.ah) + free(wsi->u.hdr.ah); + + wsi->mode = LWS_CONNMODE_WS_SERVING; + + /* union transition */ + memset(&wsi->u, 0, sizeof(wsi->u)); + wsi->u.ws.rxflow_change_to = LWS_RXFLOW_ALLOW; /* * create the frame buffer for this connection according to the @@ -553,7 +419,7 @@ int lws_handshake_server(struct libwebsocket_context *context, if (!n) n = LWS_MAX_SOCKET_IO_BUF; n += LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING; - wsi->u.ws.rx_user_buffer = lws_malloc(n); + wsi->u.ws.rx_user_buffer = malloc(n); if (!wsi->u.ws.rx_user_buffer) { lwsl_err("Out of Mem allocating rx buffer %d\n", n); return 1; @@ -573,7 +439,8 @@ int lws_handshake_server(struct libwebsocket_context *context, bail_nuke_ah: /* drop the header info */ - lws_free_header_table(wsi); + if (wsi->u.hdr.ah) + free(wsi->u.hdr.ah); return 1; } @@ -582,14 +449,14 @@ libwebsocket_create_new_server_wsi(struct libwebsocket_context *context) { struct libwebsocket *new_wsi; - new_wsi = lws_zalloc(sizeof(struct libwebsocket)); + new_wsi = (struct libwebsocket *)malloc(sizeof(struct libwebsocket)); if (new_wsi == NULL) { lwsl_err("Out of memory for new connection\n"); return NULL; } + memset(new_wsi, 0, sizeof(struct libwebsocket)); new_wsi->pending_timeout = NO_PENDING_TIMEOUT; - new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW; /* intialize the instance struct */ @@ -597,12 +464,8 @@ libwebsocket_create_new_server_wsi(struct libwebsocket_context *context) new_wsi->mode = LWS_CONNMODE_HTTP_SERVING; new_wsi->hdr_parsing_completed = 0; -#ifdef LWS_OPENSSL_SUPPORT - new_wsi->use_ssl = LWS_SSL_ENABLED(context); -#endif - if (lws_allocate_header_table(new_wsi)) { - lws_free(new_wsi); + free(new_wsi); return NULL; } @@ -626,32 +489,6 @@ libwebsocket_create_new_server_wsi(struct libwebsocket_context *context) return new_wsi; } -/** - * lws_http_transaction_completed() - wait for new http transaction or close - * @wsi: websocket connection - * - * Returns 1 if the HTTP connection must close now - * Returns 0 and resets connection to wait for new HTTP header / - * transaction if possible - */ - -LWS_VISIBLE -int lws_http_transaction_completed(struct libwebsocket *wsi) -{ - /* if we can't go back to accept new headers, drop the connection */ - if (wsi->u.http.connection_type != HTTP_CONNECTION_KEEP_ALIVE) { - lwsl_info("%s: close connection\n", __func__); - return 1; - } - - /* otherwise set ourselves up ready to go again */ - wsi->state = WSI_STATE_HTTP; - - lwsl_info("%s: await new transaction\n", __func__); - - return 0; -} - int lws_server_socket_service(struct libwebsocket_context *context, struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd) { @@ -666,13 +503,12 @@ int lws_server_socket_service(struct libwebsocket_context *context, case LWS_CONNMODE_HTTP_SERVING: case LWS_CONNMODE_HTTP_SERVING_ACCEPTED: - case LWS_CONNMODE_HTTP2_SERVING: /* handle http headers coming in */ /* pending truncated sends have uber priority */ - if (wsi->truncated_send_len) { + if (wsi->truncated_send_malloc) { if (pollfd->revents & LWS_POLLOUT) if (lws_issue_raw(wsi, wsi->truncated_send_malloc + wsi->truncated_send_offset, @@ -691,7 +527,7 @@ int lws_server_socket_service(struct libwebsocket_context *context, /* any incoming data ready? */ if (pollfd->revents & LWS_POLLIN) { - len = lws_ssl_capable_read(context, wsi, + len = lws_ssl_capable_read(wsi, context->service_buffer, sizeof(context->service_buffer)); switch (len) { @@ -699,7 +535,7 @@ int lws_server_socket_service(struct libwebsocket_context *context, lwsl_info("lws_server_skt_srv: read 0 len\n"); /* lwsl_info(" state=%d\n", wsi->state); */ if (!wsi->hdr_parsing_completed) - lws_free_header_table(wsi); + free(wsi->u.hdr.ah); /* fallthru */ case LWS_SSL_CAPABLE_ERROR: libwebsocket_close_and_free_session( @@ -707,13 +543,14 @@ int lws_server_socket_service(struct libwebsocket_context *context, LWS_CLOSE_STATUS_NOSTATUS); return 0; case LWS_SSL_CAPABLE_MORE_SERVICE: - goto try_pollout; + break; } /* just ignore incoming if waiting for close */ if (wsi->state != WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE) { /* hm this may want to send (via HTTP callback for example) */ + n = libwebsocket_read(context, wsi, context->service_buffer, len); if (n < 0) @@ -725,7 +562,6 @@ int lws_server_socket_service(struct libwebsocket_context *context, } } -try_pollout: /* this handles POLLOUT for http serving fragments */ if (!(pollfd->revents & LWS_POLLOUT)) @@ -746,14 +582,15 @@ int lws_server_socket_service(struct libwebsocket_context *context, NULL, 0); if (n < 0) - goto fail; + libwebsocket_close_and_free_session( + context, wsi, LWS_CLOSE_STATUS_NOSTATUS); break; } - /* >0 == completion, <0 == error */ - n = libwebsockets_serve_http_file_fragment(context, wsi); - if (n < 0 || (n > 0 && lws_http_transaction_completed(wsi))) - goto fail; + /* nonzero for completion or error */ + if (libwebsockets_serve_http_file_fragment(context, wsi)) + libwebsocket_close_and_free_session(context, wsi, + LWS_CLOSE_STATUS_NOSTATUS); break; case LWS_CONNMODE_SERVER_LISTENER: @@ -833,8 +670,7 @@ int lws_server_socket_service(struct libwebsocket_context *context, break; } - if (lws_server_socket_service_ssl(context, &wsi, new_wsi, - accept_fd, pollfd)) + if (lws_server_socket_service_ssl(context, &wsi, new_wsi, accept_fd, pollfd)) goto fail; return 0; @@ -845,105 +681,6 @@ int lws_server_socket_service(struct libwebsocket_context *context, return 1; } -#include "lextable-strings.h" - -const unsigned char *lws_token_to_string(enum lws_token_indexes token) -{ - if ((unsigned int)token >= ARRAY_SIZE(set)) - return NULL; - - return (unsigned char *)set[token]; -} - -int lws_add_http_header_by_name(struct libwebsocket_context *context, - struct libwebsocket *wsi, - const unsigned char *name, - const unsigned char *value, - int length, - unsigned char **p, - unsigned char *end) -{ -#ifdef LWS_USE_HTTP2 - if (wsi->mode == LWS_CONNMODE_HTTP2_SERVING) - return lws_add_http2_header_by_name(context, wsi, name, value, length, p, end); -#endif - if (name) { - while (*p < end && *name) - *((*p)++) = *name++; - - if (*p == end) - return 1; - - *((*p)++) = ' '; - } - if (*p + length + 3 >= end) - return 1; - - memcpy(*p, value, length); - *p += length; - - *((*p)++) = '\x0d'; - *((*p)++) = '\x0a'; - - return 0; -} - -int lws_finalize_http_header(struct libwebsocket_context *context, - struct libwebsocket *wsi, - unsigned char **p, - unsigned char *end) -{ -#ifdef LWS_USE_HTTP2 - if (wsi->mode == LWS_CONNMODE_HTTP2_SERVING) - return 0; -#endif - - if ((long)(end - *p) < 3) - return 1; - - *((*p)++) = '\x0d'; - *((*p)++) = '\x0a'; - - return 0; -} - -int lws_add_http_header_by_token(struct libwebsocket_context *context, - struct libwebsocket *wsi, - enum lws_token_indexes token, - const unsigned char *value, - int length, - unsigned char **p, - unsigned char *end) -{ - const unsigned char *name; -#ifdef LWS_USE_HTTP2 - if (wsi->mode == LWS_CONNMODE_HTTP2_SERVING) - return lws_add_http2_header_by_token(context, wsi, token, value, length, p, end); -#endif - name = lws_token_to_string(token); - if (!name) - return 1; - - return lws_add_http_header_by_name(context, wsi, name, value, length, p, end); -} - -int lws_add_http_header_content_length(struct libwebsocket_context *context, - struct libwebsocket *wsi, - unsigned long content_length, - unsigned char **p, - unsigned char *end) -{ - char b[24]; - int n; - - n = sprintf(b, "%lu", content_length); - if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH, (unsigned char *)b, n, p, end)) - return 1; - wsi->u.http.content_length = content_length; - wsi->u.http.content_remain = content_length; - - return 0; -} static const char *err400[] = { "Bad Request", @@ -975,36 +712,12 @@ static const char *err500[] = { "HTTP Version Not Supported" }; -int lws_add_http_header_status(struct libwebsocket_context *context, - struct libwebsocket *wsi, - unsigned int code, - unsigned char **p, - unsigned char *end) -{ - unsigned char code_and_desc[60]; - const char *description = ""; - int n; - -#ifdef LWS_USE_HTTP2 - if (wsi->mode == LWS_CONNMODE_HTTP2_SERVING) - return lws_add_http2_header_status(context, wsi, code, p, end); -#endif - if (code >= 400 && code < (400 + ARRAY_SIZE(err400))) - description = err400[code - 400]; - if (code >= 500 && code < (500 + ARRAY_SIZE(err500))) - description = err500[code - 500]; - - n = sprintf((char *)code_and_desc, "HTTP/1.0 %u %s", code, description); - - return lws_add_http_header_by_name(context, wsi, NULL, code_and_desc, n, p, end); -} - /** * libwebsockets_return_http_status() - Return simple http status * @context: libwebsockets context * @wsi: Websocket instance (available from user callback) * @code: Status index, eg, 404 - * @html_body: User-readable HTML description < 1KB, or NULL + * @html_body: User-readable HTML description, or NULL * * Helper to report HTTP errors back to the client cleanly and * consistently @@ -1014,32 +727,28 @@ LWS_VISIBLE int libwebsockets_return_http_status( unsigned int code, const char *html_body) { int n, m; - - unsigned char *p = context->service_buffer + LWS_SEND_BUFFER_PRE_PADDING; - unsigned char *start = p; - unsigned char *end = p + sizeof(context->service_buffer) - - LWS_SEND_BUFFER_PRE_PADDING; + const char *description = ""; if (!html_body) html_body = ""; - if (lws_add_http_header_status(context, wsi, code, &p, end)) - return 1; - if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_SERVER, (unsigned char *)"libwebsockets", 13, &p, end)) - return 1; - if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)"text/html", 9, &p, end)) - return 1; - if (lws_finalize_http_header(context, wsi, &p, end)) - return 1; + if (code >= 400 && code < (400 + ARRAY_SIZE(err400))) + description = err400[code - 400]; + if (code >= 500 && code < (500 + ARRAY_SIZE(err500))) + description = err500[code - 500]; - m = libwebsocket_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS); - if (m != (int)(p - start)) - return 1; + n = sprintf((char *)context->service_buffer, + "HTTP/1.0 %u %s\x0d\x0a" + "Server: libwebsockets\x0d\x0a" + "Content-Type: text/html\x0d\x0a\x0d\x0a" + "

%u %s

%s", + code, description, code, description, html_body); + + lwsl_info((const char *)context->service_buffer); - n = sprintf((char *)start, "

%u

%s", code, html_body); - m = libwebsocket_write(wsi, start, n, LWS_WRITE_HTTP); + m = libwebsocket_write(wsi, context->service_buffer, n, LWS_WRITE_HTTP); - return m != n; + return m; } /** @@ -1055,8 +764,7 @@ LWS_VISIBLE int libwebsockets_return_http_status( * local files down the http link in a single step. * * Returning <0 indicates error and the wsi should be closed. Returning - * >0 indicates the file was completely sent and - * lws_http_transaction_completed() called on the wsi (and close if != 0) + * >0 indicates the file was completely sent and the wsi should be closed. * ==0 indicates the file transfer is started and needs more service later, * the wsi should be left alone. */ @@ -1064,14 +772,11 @@ LWS_VISIBLE int libwebsockets_return_http_status( LWS_VISIBLE int libwebsockets_serve_http_file( struct libwebsocket_context *context, struct libwebsocket *wsi, const char *file, - const char *content_type, const char *other_headers, - int other_headers_len) + const char *content_type, const char *other_headers) { - unsigned char *response = context->service_buffer + LWS_SEND_BUFFER_PRE_PADDING; - unsigned char *p = response; - unsigned char *end = p + sizeof(context->service_buffer) - - LWS_SEND_BUFFER_PRE_PADDING; + unsigned char *p = context->service_buffer; int ret = 0; + int n; wsi->u.http.fd = lws_plat_open_file(file, &wsi->u.http.filelen); @@ -1082,29 +787,21 @@ LWS_VISIBLE int libwebsockets_serve_http_file( return -1; } - if (lws_add_http_header_status(context, wsi, 200, &p, end)) - return -1; - if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_SERVER, (unsigned char *)"libwebsockets", 13, &p, end)) - return -1; - if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)content_type, strlen(content_type), &p, end)) - return -1; - if (lws_add_http_header_content_length(context, wsi, wsi->u.http.filelen, &p, end)) - return -1; - + p += sprintf((char *)p, +"HTTP/1.0 200 OK\x0d\x0aServer: libwebsockets\x0d\x0a""Content-Type: %s\x0d\x0a", + content_type); if (other_headers) { - if ((end - p) < other_headers_len) - return -1; - memcpy(p, other_headers, other_headers_len); - p += other_headers_len; + n = strlen(other_headers); + memcpy(p, other_headers, n); + p += n; } + p += sprintf((char *)p, + "Content-Length: %lu\x0d\x0a\x0d\x0a", wsi->u.http.filelen); - if (lws_finalize_http_header(context, wsi, &p, end)) - return -1; - - ret = libwebsocket_write(wsi, response, - p - response, LWS_WRITE_HTTP_HEADERS); - if (ret != (p - response)) { - lwsl_err("_write returned %d from %d\n", ret, (p - response)); + ret = libwebsocket_write(wsi, context->service_buffer, + p - context->service_buffer, LWS_WRITE_HTTP); + if (ret != (p - context->service_buffer)) { + lwsl_err("_write returned %d from %d\n", ret, (p - context->service_buffer)); return -1; } @@ -1132,15 +829,28 @@ int libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi, /* * we were accepting input but now we stopped doing so */ - if (!(wsi->rxflow_change_to & LWS_RXFLOW_ALLOW)) { - lws_rxflow_cache(wsi, buf, n, len); + if (!(wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW)) { + /* his RX is flowcontrolled, don't send remaining now */ + if (!wsi->u.ws.rxflow_buffer) { + /* a new rxflow, buffer it and warn caller */ + lwsl_info("new rxflow input buffer len %d\n", + len - n); + wsi->u.ws.rxflow_buffer = + (unsigned char *)malloc(len - n); + wsi->u.ws.rxflow_len = len - n; + wsi->u.ws.rxflow_pos = 0; + memcpy(wsi->u.ws.rxflow_buffer, + buf + n, len - n); + } else + /* rxflow while we were spilling prev rxflow */ + lwsl_info("stalling in existing rxflow buf\n"); return 1; } /* account for what we're using in rxflow buffer */ - if (wsi->rxflow_buffer) - wsi->rxflow_pos++; + if (wsi->u.ws.rxflow_buffer) + wsi->u.ws.rxflow_pos++; /* process the byte */ m = libwebsocket_rx_sm(wsi, buf[n++]); diff --git a/lib/service.c b/lib/service.c index a94e6793d1..1eeaf99fed 100755 --- a/lib/service.c +++ b/lib/service.c @@ -21,40 +21,15 @@ #include "private-libwebsockets.h" -static int -lws_calllback_as_writeable(struct libwebsocket_context *context, - struct libwebsocket *wsi) -{ - int n; - - switch (wsi->mode) { - case LWS_CONNMODE_WS_CLIENT: - n = LWS_CALLBACK_CLIENT_WRITEABLE; - break; - case LWS_CONNMODE_WS_SERVING: - n = LWS_CALLBACK_SERVER_WRITEABLE; - break; - default: - n = LWS_CALLBACK_HTTP_WRITEABLE; - break; - } - lwsl_info("%s: %p (user=%p)\n", __func__, wsi, wsi->user_space); - return user_callback_handle_rxflow(wsi->protocol->callback, context, - wsi, (enum libwebsocket_callback_reasons) n, - wsi->user_space, NULL, 0); -} - int lws_handle_POLLOUT_event(struct libwebsocket_context *context, struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd) { int n; struct lws_tokens eff_buf; -#ifdef LWS_USE_HTTP2 - struct libwebsocket *wsi2; -#endif int ret; int m; + int handled = 0; /* pending truncated sends have uber priority */ @@ -72,47 +47,14 @@ lws_handle_POLLOUT_event(struct libwebsocket_context *context, lwsl_info("***** %x signalling to close in POLLOUT handler\n", wsi); return -1; /* retry closing now */ } -#ifdef LWS_USE_HTTP2 - /* protocol packets are next */ - if (wsi->pps) { - lwsl_info("servicing pps %d\n", wsi->pps); - switch (wsi->pps) { - case LWS_PPS_HTTP2_MY_SETTINGS: - case LWS_PPS_HTTP2_ACK_SETTINGS: - lws_http2_do_pps_send(context, wsi); - break; - default: - break; - } - wsi->pps = LWS_PPS_NONE; - libwebsocket_rx_flow_control(wsi, 1); - - return 0; /* leave POLLOUT active */ - } -#endif - /* pending control packets have next priority */ - - if (wsi->state == WSI_STATE_ESTABLISHED && - wsi->u.ws.ping_pending_flag) { - n = libwebsocket_write(wsi, - &wsi->u.ws.ping_payload_buf[ - LWS_SEND_BUFFER_PRE_PADDING], - wsi->u.ws.ping_payload_len, - LWS_WRITE_PONG); - if (n < 0) - return -1; - /* well he is sent, mark him done */ - wsi->u.ws.ping_pending_flag = 0; - /* leave POLLOUT active either way */ - return 0; - } - /* if nothing critical, user can get the callback */ - + m = lws_ext_callback_for_each_active(wsi, LWS_EXT_CALLBACK_IS_WRITEABLE, NULL, 0); + if (handled == 1) + goto notify_action; #ifndef LWS_NO_EXTENSIONS - if (!wsi->extension_data_pending) + if (!wsi->extension_data_pending || handled == 2) goto user_service; #endif /* @@ -201,64 +143,21 @@ lws_handle_POLLOUT_event(struct libwebsocket_context *context, /* one shot */ if (pollfd) { - if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) { - lwsl_info("failled at set pollfd\n"); + if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) return 1; - } lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_WRITE); } -#ifdef LWS_USE_HTTP2 - /* - * we are the 'network wsi' for potentially many muxed child wsi with - * no network connection of their own, who have to use us for all their - * network actions. So we use a round-robin scheme to share out the - * POLLOUT notifications to our children. - * - * But because any child could exhaust the socket's ability to take - * writes, we can only let one child get notified each time. - * - * In addition children may be closed / deleted / added between POLLOUT - * notifications, so we can't hold pointers - */ - - if (wsi->mode != LWS_CONNMODE_HTTP2_SERVING) { - lwsl_info("%s: non http2\n", __func__); - goto notify; - } +notify_action: + if (wsi->mode == LWS_CONNMODE_WS_CLIENT) + n = LWS_CALLBACK_CLIENT_WRITEABLE; + else + n = LWS_CALLBACK_SERVER_WRITEABLE; - wsi->u.http2.requested_POLLOUT = 0; - if (!wsi->u.http2.initialized) { - lwsl_info("pollout on uninitialized http2 conn\n"); - return 0; - } - - lwsl_info("%s: doing children\n", __func__); - - wsi2 = wsi; - do { - wsi2 = wsi2->u.http2.next_child_wsi; - lwsl_info("%s: child %p\n", __func__, wsi2); - if (!wsi2) - continue; - if (!wsi2->u.http2.requested_POLLOUT) - continue; - wsi2->u.http2.requested_POLLOUT = 0; - if (lws_calllback_as_writeable(context, wsi2)) { - lwsl_debug("Closing POLLOUT child\n"); - libwebsocket_close_and_free_session(context, wsi2, - LWS_CLOSE_STATUS_NOSTATUS); - } - wsi2 = wsi; - } while (wsi2 != NULL && !lws_send_pipe_choked(wsi)); - - lwsl_info("%s: completed\n", __func__); - - return 0; -notify: -#endif - return lws_calllback_as_writeable(context, wsi); + return user_callback_handle_rxflow(wsi->protocol->callback, context, + wsi, (enum libwebsocket_callback_reasons) n, + wsi->user_space, NULL, 0); } @@ -291,25 +190,6 @@ libwebsocket_service_timeout_check(struct libwebsocket_context *context, return 0; } -int lws_rxflow_cache(struct libwebsocket *wsi, unsigned char *buf, int n, int len) -{ - /* his RX is flowcontrolled, don't send remaining now */ - if (wsi->rxflow_buffer) { - /* rxflow while we were spilling prev rxflow */ - lwsl_info("stalling in existing rxflow buf\n"); - return 1; - } - - /* a new rxflow, buffer it and warn caller */ - lwsl_info("new rxflow input buffer len %d\n", len - n); - wsi->rxflow_buffer = lws_malloc(len - n); - wsi->rxflow_len = len - n; - wsi->rxflow_pos = 0; - memcpy(wsi->rxflow_buffer, buf + n, len - n); - - return 0; -} - /** * libwebsocket_service_fd() - Service polled socket with something waiting * @context: Websocket context @@ -349,9 +229,10 @@ libwebsocket_service_fd(struct libwebsocket_context *context, struct lws_tokens eff_buf; if (context->listen_service_fd) - listen_socket_fds_index = wsi_from_fd(context,context->listen_service_fd)->position_in_fds_table; + listen_socket_fds_index = context->lws_lookup[ + context->listen_service_fd]->position_in_fds_table; - /* + /* * you can call us with pollfd = NULL to just allow the once-per-second * global timeout checks; if less than a second since the last check * it returns immediately then. @@ -372,7 +253,7 @@ libwebsocket_service_fd(struct libwebsocket_context *context, for (n = 0; n < context->fds_count; n++) { m = context->fds[n].fd; - wsi = wsi_from_fd(context,m); + wsi = context->lws_lookup[m]; if (!wsi) continue; @@ -382,8 +263,7 @@ libwebsocket_service_fd(struct libwebsocket_context *context, /* it was the guy we came to service! */ timed_out = 1; /* mark as handled */ - if (pollfd) - pollfd->revents = 0; + pollfd->revents = 0; } } } @@ -397,7 +277,7 @@ libwebsocket_service_fd(struct libwebsocket_context *context, return 0; /* no, here to service a socket descriptor */ - wsi = wsi_from_fd(context,pollfd->fd); + wsi = context->lws_lookup[pollfd->fd]; if (wsi == NULL) /* not lws connection ... leave revents alone and return */ return 0; @@ -473,25 +353,25 @@ libwebsocket_service_fd(struct libwebsocket_context *context, case LWS_CONNMODE_WS_SERVING: case LWS_CONNMODE_WS_CLIENT: - case LWS_CONNMODE_HTTP2_SERVING: /* the guy requested a callback when it was OK to write */ if ((pollfd->revents & LWS_POLLOUT) && - (wsi->state == WSI_STATE_ESTABLISHED || wsi->state == WSI_STATE_HTTP2_ESTABLISHED || wsi->state == WSI_STATE_HTTP2_ESTABLISHED_PRE_SETTINGS || + (wsi->state == WSI_STATE_ESTABLISHED || wsi->state == WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE) && lws_handle_POLLOUT_event(context, wsi, pollfd)) { lwsl_info("libwebsocket_service_fd: closing\n"); goto close_and_handled; } - if (wsi->rxflow_buffer && - (wsi->rxflow_change_to & LWS_RXFLOW_ALLOW)) { + if (wsi->u.ws.rxflow_buffer && + (wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW)) { lwsl_info("draining rxflow\n"); /* well, drain it */ - eff_buf.token = (char *)wsi->rxflow_buffer + - wsi->rxflow_pos; - eff_buf.token_len = wsi->rxflow_len - wsi->rxflow_pos; + eff_buf.token = (char *)wsi->u.ws.rxflow_buffer + + wsi->u.ws.rxflow_pos; + eff_buf.token_len = wsi->u.ws.rxflow_len - + wsi->u.ws.rxflow_pos; draining_flow = 1; goto drain; } @@ -501,7 +381,8 @@ libwebsocket_service_fd(struct libwebsocket_context *context, if (!(pollfd->revents & LWS_POLLIN)) break; - eff_buf.token_len = lws_ssl_capable_read(context, wsi, +read_pending: + eff_buf.token_len = lws_ssl_capable_read(wsi, context->service_buffer, sizeof(context->service_buffer)); switch (eff_buf.token_len) { @@ -560,17 +441,17 @@ libwebsocket_service_fd(struct libwebsocket_context *context, eff_buf.token_len = 0; } while (more); - if (draining_flow && wsi->rxflow_buffer && - wsi->rxflow_pos == wsi->rxflow_len) { + if (draining_flow && wsi->u.ws.rxflow_buffer && + wsi->u.ws.rxflow_pos == wsi->u.ws.rxflow_len) { lwsl_info("flow buffer: drained\n"); - lws_free2(wsi->rxflow_buffer); + free(wsi->u.ws.rxflow_buffer); + wsi->u.ws.rxflow_buffer = NULL; /* having drained the rxflow buffer, can rearm POLLIN */ -#ifdef LWS_NO_SERVER - n = -#endif - _libwebsocket_rx_flow_control(wsi); /* n ignored, needed for NO_SERVER case */ + n = _libwebsocket_rx_flow_control(wsi); /* n ignored, needed for NO_SERVER case */ } + if (lws_ssl_pending(wsi)) + goto read_pending; break; default: diff --git a/lib/sha-1.c b/lib/sha-1.c index e68ee38d6f..98b208b220 100644 --- a/lib/sha-1.c +++ b/lib/sha-1.c @@ -286,8 +286,8 @@ sha1_result(struct sha1_ctxt *ctxt, void *digest0) * This should look and work like the libcrypto implementation */ -LWS_VISIBLE unsigned char * -libwebsockets_SHA1(const unsigned char *d, size_t n, unsigned char *md) +unsigned char * +SHA1(const unsigned char *d, size_t n, unsigned char *md) { struct sha1_ctxt ctx; diff --git a/lib/ssl-http2.c b/lib/ssl-http2.c index 0a72d80a5f..237f43cddb 100755 --- a/lib/ssl-http2.c +++ b/lib/ssl-http2.c @@ -50,38 +50,16 @@ #include "private-libwebsockets.h" #ifndef LWS_NO_SERVER -#ifdef LWS_OPENSSL_SUPPORT #if OPENSSL_VERSION_NUMBER >= 0x10002000L - -struct alpn_ctx { - unsigned char *data; - unsigned short len; -}; - -static int npn_cb(SSL *s, const unsigned char **data, unsigned int *len, void *arg) -{ - struct alpn_ctx *alpn_ctx = arg; - - lwsl_info("%s\n", __func__); - *data = alpn_ctx->data; - *len = alpn_ctx->len; - - return SSL_TLSEXT_ERR_OK; -} - -static int alpn_cb(SSL *s, const unsigned char **out, - unsigned char *outlen, const unsigned char *in, - unsigned int inlen, void *arg) +static int alpn_select_proto_cb(SSL* ssl, + const unsigned char **out, + unsigned char *outlen, + const unsigned char *in, unsigned int inlen, + void *arg) { - struct alpn_ctx *alpn_ctx = arg; - - if (SSL_select_next_proto((unsigned char **)out, outlen, - alpn_ctx->data, alpn_ctx->len, in, inlen) != - OPENSSL_NPN_NEGOTIATED) - return SSL_TLSEXT_ERR_NOACK; - - return SSL_TLSEXT_ERR_OK; + lwsl_err((char *)in); + return SSL_TLSEXT_ERR_OK; /* SSL_TLSEXT_ERR_NOACK */ } #endif @@ -89,66 +67,12 @@ LWS_VISIBLE void lws_context_init_http2_ssl(struct libwebsocket_context *context) { #if OPENSSL_VERSION_NUMBER >= 0x10002000L - static struct alpn_ctx protos = { (unsigned char *) - "\x05h2-14" - "\x08http/1.1", - 6 + 9 }; - - SSL_CTX_set_next_protos_advertised_cb(context->ssl_ctx, npn_cb, &protos); - // ALPN selection callback - SSL_CTX_set_alpn_select_cb(context->ssl_ctx, alpn_cb, &protos); + SSL_CTX_set_alpn_select_cb(context->ssl_ctx, alpn_select_proto_cb, NULL); lwsl_notice(" HTTP2 / ALPN enabled\n"); #else - lwsl_notice( - " HTTP2 / ALPN configured but not supported by OpenSSL 0x%x\n", - OPENSSL_VERSION_NUMBER); + lwsl_notice(" HTTP2 / ALPN configured but not supported by OpenSSL version\n"); #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L } -void lws_http2_configure_if_upgraded(struct libwebsocket *wsi) -{ -#if OPENSSL_VERSION_NUMBER >= 0x10002000L - struct allocated_headers *ah; - const unsigned char *name; - unsigned len; - const char *method = "alpn"; - - SSL_get0_alpn_selected(wsi->ssl, &name, &len); - - if (!len) { - SSL_get0_next_proto_negotiated(wsi->ssl, &name, &len); - method = "npn"; - } - - if (!len) { - lwsl_info("no npn/alpn upgrade\n"); - return; - } - - lwsl_info("negotiated %s using %s\n", name, method); - wsi->use_ssl = 1; - if (strncmp((char *)name, "http/1.1", 8) == 0) - return; - - /* http2 */ - - /* adopt the header info */ - - ah = wsi->u.hdr.ah; - - lws_union_transition(wsi, LWS_CONNMODE_HTTP2_SERVING); - wsi->state = WSI_STATE_HTTP2_AWAIT_CLIENT_PREFACE; - - /* http2 union member has http union struct at start */ - wsi->u.http.ah = ah; - - lws_http2_init(&wsi->u.http2.peer_settings); - lws_http2_init(&wsi->u.http2.my_settings); - - /* HTTP2 union */ -#endif -} - -#endif -#endif +#endif \ No newline at end of file diff --git a/lib/ssl.c b/lib/ssl.c index f6276932fe..940e00df9e 100755 --- a/lib/ssl.c +++ b/lib/ssl.c @@ -20,36 +20,9 @@ */ #include "private-libwebsockets.h" - #include int openssl_websocket_private_data_index; -static int lws_context_init_ssl_pem_passwd_cb(char * buf, int size, int rwflag, void *userdata) -{ - struct lws_context_creation_info * info = (struct lws_context_creation_info *)userdata; - - strncpy(buf, info->ssl_private_key_password, size); - buf[size - 1] = '\0'; - - return strlen(buf); -} - -static void lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, - struct lws_context_creation_info *info) -{ - if (!info->ssl_private_key_password) - return; - /* - * password provided, set ssl callback and user data - * for checking password which will be trigered during - * SSL_CTX_use_PrivateKey_file function - */ - SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, (void *)info); - SSL_CTX_set_default_passwd_cb(ssl_ctx, - lws_context_init_ssl_pem_passwd_cb); -} - -#ifndef LWS_NO_SERVER static int OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) { @@ -82,10 +55,11 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info, int error; int n; +#ifndef LWS_NO_SERVER if (info->port != CONTEXT_PORT_NO_LISTEN) { - context->use_ssl = info->ssl_cert_filepath != NULL; - + context->use_ssl = info->ssl_cert_filepath != NULL && + info->ssl_private_key_filepath != NULL; #ifdef USE_CYASSL lwsl_notice(" Compiled with CYASSL support\n"); #else @@ -101,6 +75,16 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info, lwsl_notice(" Using non-SSL mode\n"); } +#else + if (info->ssl_cert_filepath != NULL && + info->ssl_private_key_filepath != NULL) { + lwsl_notice(" Not compiled for OpenSSl support!\n"); + return 1; + } + lwsl_notice(" Compiled without SSL support\n"); + } +#endif /* no server */ + /* basic openssl init */ SSL_library_init(); @@ -114,10 +98,6 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info, /* * Firefox insists on SSLv23 not SSLv3 * Konq disables SSLv2 by default now, SSLv23 works - * - * SSLv23_server_method() is the openssl method for "allow all TLS - * versions", compared to e.g. TLSv1_2_server_method() which only allows - * tlsv1.2. Unwanted versions must be disabled using SSL_CTX_set_options() */ method = (SSL_METHOD *)SSLv23_server_method(); @@ -137,8 +117,6 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info, return 1; } - /* Disable SSLv2 and SSLv3 */ - SSL_CTX_set_options(context->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); #ifdef SSL_OP_NO_COMPRESSION SSL_CTX_set_options(context->ssl_ctx, SSL_OP_NO_COMPRESSION); #endif @@ -189,31 +167,18 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info, (char *)context->service_buffer)); return 1; } - lws_ssl_bind_passphrase(context->ssl_ctx, info); - - if (info->ssl_private_key_filepath != NULL) { - /* set the private key from KeyFile */ - if (SSL_CTX_use_PrivateKey_file(context->ssl_ctx, - info->ssl_private_key_filepath, + /* set the private key from KeyFile */ + if (SSL_CTX_use_PrivateKey_file(context->ssl_ctx, + info->ssl_private_key_filepath, SSL_FILETYPE_PEM) != 1) { - error = ERR_get_error(); - lwsl_err("ssl problem getting key '%s' %lu: %s\n", - info->ssl_private_key_filepath, - error, - ERR_error_string(error, - (char *)context->service_buffer)); - return 1; - } - } - else { - if (context->protocols[0].callback(context, NULL, - LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY, - context->ssl_ctx, NULL, 0)) { - lwsl_err("ssl private key not set\n"); - return 1; - } + error = ERR_get_error(); + lwsl_err("ssl problem getting key '%s' %lu: %s\n", + info->ssl_private_key_filepath, + error, + ERR_error_string(error, + (char *)context->service_buffer)); + return 1; } - /* verify private key */ if (!SSL_CTX_check_private_key(context->ssl_ctx)) { lwsl_err("Private SSL key doesn't match cert\n"); @@ -230,21 +195,16 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info, return 0; } -#endif LWS_VISIBLE void lws_ssl_destroy(struct libwebsocket_context *context) { if (context->ssl_ctx) SSL_CTX_free(context->ssl_ctx); - if (!context->user_supplied_ssl_ctx && context->ssl_client_ctx) + if (context->ssl_client_ctx) SSL_CTX_free(context->ssl_client_ctx); -#if (OPENSSL_VERSION_NUMBER < 0x01000000) || defined(USE_CYASSL) ERR_remove_state(0); -#else - ERR_remove_thread_state(NULL); -#endif ERR_free_strings(); EVP_cleanup(); CRYPTO_cleanup_all_ex_data(); @@ -263,7 +223,6 @@ libwebsockets_decode_ssl_error(void) } #ifndef LWS_NO_CLIENT - int lws_context_init_client_ssl(struct lws_context_creation_info *info, struct libwebsocket_context *context) { @@ -271,24 +230,9 @@ int lws_context_init_client_ssl(struct lws_context_creation_info *info, int n; SSL_METHOD *method; - if (info->provided_client_ssl_ctx) { - /* use the provided OpenSSL context if given one */ - context->ssl_client_ctx = info->provided_client_ssl_ctx; - /* nothing for lib to delete */ - context->user_supplied_ssl_ctx = 1; - return 0; - } - if (info->port != CONTEXT_PORT_NO_LISTEN) return 0; - /* basic openssl init */ - - SSL_library_init(); - - OpenSSL_add_all_algorithms(); - SSL_load_error_strings(); - method = (SSL_METHOD *)SSLv23_client_method(); if (!method) { error = ERR_get_error(); @@ -341,8 +285,6 @@ int lws_context_init_client_ssl(struct lws_context_creation_info *info, "Unable to load SSL Client certs " "file from %s -- client ssl isn't " "going to work", info->ssl_ca_filepath); - else - lwsl_info("loaded ssl_ca_filepath\n"); /* * callback allowing user code to load extra verification certs @@ -364,10 +306,10 @@ int lws_context_init_client_ssl(struct lws_context_creation_info *info, } } if (info->ssl_private_key_filepath) { - lws_ssl_bind_passphrase(context->ssl_client_ctx, info); /* set the private key from KeyFile */ if (SSL_CTX_use_PrivateKey_file(context->ssl_client_ctx, - info->ssl_private_key_filepath, SSL_FILETYPE_PEM) != 1) { + info->ssl_private_key_filepath, + SSL_FILETYPE_PEM) != 1) { lwsl_err("use_PrivateKey_file '%s' %lu: %s\n", info->ssl_private_key_filepath, ERR_get_error(), @@ -392,64 +334,18 @@ int lws_context_init_client_ssl(struct lws_context_creation_info *info, } #endif -LWS_VISIBLE void -lws_ssl_remove_wsi_from_buffered_list(struct libwebsocket_context *context, - struct libwebsocket *wsi) -{ - if (!wsi->pending_read_list_prev && - !wsi->pending_read_list_next && - context->pending_read_list != wsi) - /* we are not on the list */ - return; - - /* point previous guy's next to our next */ - if (!wsi->pending_read_list_prev) - context->pending_read_list = wsi->pending_read_list_next; - else - wsi->pending_read_list_prev->pending_read_list_next = - wsi->pending_read_list_next; - - /* point next guy's previous to our previous */ - if (wsi->pending_read_list_next) - wsi->pending_read_list_next->pending_read_list_prev = - wsi->pending_read_list_prev; - - wsi->pending_read_list_prev = NULL; - wsi->pending_read_list_next = NULL; -} - LWS_VISIBLE int -lws_ssl_capable_read(struct libwebsocket_context *context, - struct libwebsocket *wsi, unsigned char *buf, int len) +lws_ssl_capable_read(struct libwebsocket *wsi, unsigned char *buf, int len) { int n; if (!wsi->ssl) - return lws_ssl_capable_read_no_ssl(context, wsi, buf, len); + return lws_ssl_capable_read_no_ssl(wsi, buf, len); n = SSL_read(wsi->ssl, buf, len); - if (n >= 0) { - /* - * if it was our buffer that limited what we read, - * check if SSL has additional data pending inside SSL buffers. - * - * Because these won't signal at the network layer with POLLIN - * and if we don't realize, this data will sit there forever - */ - if (n == len && wsi->ssl && SSL_pending(wsi->ssl)) { - if (!wsi->pending_read_list_next && !wsi->pending_read_list_prev) { - /* add us to the linked list of guys with pending ssl */ - if (context->pending_read_list) - context->pending_read_list->pending_read_list_prev = wsi; - wsi->pending_read_list_next = context->pending_read_list; - wsi->pending_read_list_prev = NULL; - context->pending_read_list = wsi; - } - } else - lws_ssl_remove_wsi_from_buffered_list(context, wsi); - + if (n >= 0) return n; - } + n = SSL_get_error(wsi->ssl, n); if (n == SSL_ERROR_WANT_READ || n == SSL_ERROR_WANT_WRITE) return LWS_SSL_CAPABLE_MORE_SERVICE; @@ -479,6 +375,14 @@ lws_ssl_capable_write(struct libwebsocket *wsi, unsigned char *buf, int len) return LWS_SSL_CAPABLE_ERROR; } +LWS_VISIBLE int +lws_ssl_pending(struct libwebsocket *wsi) +{ + if (wsi->ssl) + return SSL_pending(wsi->ssl); + return 0; +} + LWS_VISIBLE int lws_ssl_close(struct libwebsocket *wsi) { @@ -512,18 +416,13 @@ lws_server_socket_service_ssl(struct libwebsocket_context *context, switch (wsi->mode) { case LWS_CONNMODE_SERVER_LISTENER: - if (!new_wsi) { - lwsl_err("no new_wsi\n"); - return 0; - } - new_wsi->ssl = SSL_new(context->ssl_ctx); if (new_wsi->ssl == NULL) { lwsl_err("SSL_new failed: %s\n", ERR_error_string(SSL_get_error( new_wsi->ssl, 0), NULL)); libwebsockets_decode_ssl_error(); - lws_free(new_wsi); + free(new_wsi); compatible_close(accept_fd); break; } @@ -635,7 +534,9 @@ lws_server_socket_service_ssl(struct libwebsocket_context *context, } lwsl_debug("SSL_accept failed skt %u: %s\n", pollfd->fd, ERR_error_string(m, NULL)); - goto fail; + libwebsocket_close_and_free_session(context, wsi, + LWS_CLOSE_STATUS_NOSTATUS); + break; accepted: /* OK, we are accepted... give him some time to negotiate */ @@ -645,8 +546,6 @@ lws_server_socket_service_ssl(struct libwebsocket_context *context, wsi->mode = LWS_CONNMODE_HTTP_SERVING; - lws_http2_configure_if_upgraded(wsi); - lwsl_debug("accepted new SSL conn\n"); break; } @@ -662,14 +561,10 @@ lws_ssl_context_destroy(struct libwebsocket_context *context) { if (context->ssl_ctx) SSL_CTX_free(context->ssl_ctx); - if (!context->user_supplied_ssl_ctx && context->ssl_client_ctx) + if (context->ssl_client_ctx) SSL_CTX_free(context->ssl_client_ctx); -#if (OPENSSL_VERSION_NUMBER < 0x01000000) || defined(USE_CYASSL) ERR_remove_state(0); -#else - ERR_remove_thread_state(NULL); -#endif ERR_free_strings(); EVP_cleanup(); CRYPTO_cleanup_all_ex_data(); diff --git a/libwebsockets.spec b/libwebsockets.spec index d2bfb31180..10015dd1a0 100644 --- a/libwebsockets.spec +++ b/libwebsockets.spec @@ -1,6 +1,6 @@ Name: libwebsockets -Version: 1.4 -Release: 48.gmaster_16fb0132%{?dist} +Version: 1.3 +Release: 47.gmaster_b89f21c%{?dist} Summary: Websocket Server Library Group: System @@ -10,7 +10,7 @@ Source0: %{name}-%{version}.tar.gz BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) BuildRequires: openssl-devel -Requires: openssl +Requires: openssl-devel %description Webserver server library @@ -51,7 +51,7 @@ rm -rf $RPM_BUILD_ROOT %attr(755,root,root) /usr/bin/libwebsockets-test-echo %attr(755,root,root) /usr/bin/libwebsockets-test-fraggle %attr(755,root,root) -/%{_libdir}/libwebsockets.so.5 +/%{_libdir}/libwebsockets.so.4.0.0 /%{_libdir}/libwebsockets.so %attr(755,root,root) /usr/share/libwebsockets-test-server %doc