Compare commits

...
Sign in to create a new pull request.

87 commits

Author SHA1 Message Date
Andy Green
c47fda7119 service: always restrict rx to serve_buf_size 2017-03-28 08:53:35 +08:00
Andy Green
ad2dac0659 pmd: handle case we are already on drain list
Provide internal helper for adding to list that takes care of the
case we are already on the list.

https://github.com/warmcat/libwebsockets/issues/847
2017-03-26 10:12:44 +08:00
Andy Green
7bc6f5699c ext: pmd: improve dealing with partial input usage with drain
https://github.com/warmcat/libwebsockets/issues/841
2017-03-20 19:38:39 +08:00
Michael Behrns-Miller [case-ubuntu]
f9e16eacd9 Subject: Buffer index protection in the case where client does not
receive content length from HTTP server
2017-03-03 05:43:55 +08:00
Silas Parker
eb76310c52 fix close packet index coding
https://github.com/warmcat/libwebsockets/issues/792
2017-02-14 23:26:13 +08:00
Tobias
7270aebadf ignore leading spaces when checking for a suitable subprotocol
My Browsers send as Subprotocols e.g. chat, superchat, mySubprotocol (with spaces after the ,). Libwebsockets now checked if ' mySubprotocol' was equal to 'mySubprotocol' which failed. With this fix the leading space is ignored and uses 'mySubprotocol' for comparision.
2017-01-17 06:31:09 +08:00
Andy Green
2ee30ebdf1 polarssl: turn off missing tlsext 2017-01-07 10:25:34 +08:00
Andy Green
c8b8dc8c07 openssl: deal with missing OPENSSL_NO_TLSEXT on ancient versions 2017-01-07 10:25:31 +08:00
Andy Green
eefcaa762e client: protect against possible NULL deref path 2017-01-04 14:38:05 +08:00
Denis Osvald
10eacf2873 server: check listen(2) return value
The `listen` call can fail with EADDRINUSE after bind() succeeds, for
example because another process called listen on that port in the
meantime, or under some circumstances with IPv6-mapped-IPv4. This was
causing EINVAL on accept, with an infinite loop in case of libuv.

A reproducible example was to run nc -l -p 5555 ( OpenBSD netcat (Debian
patchlevel 1)) before starting test-server

Signed-off-by: Denis Osvald <denis.osvald@sartura.hr>
2017-01-03 02:06:37 +08:00
namowen
15b35bcc63 lws_plat_service_tsi: accessing context before checking for NULL
https://github.com/warmcat/libwebsockets/issues/730
2016-12-24 08:02:04 +08:00
Namowen
f5f9196936 echo: fix debug build
https://github.com/warmcat/libwebsockets/issues/716#issuecomment-267377856
2016-12-16 07:06:02 +08:00
Andy Green
27d650b89b client ssl hostname check: trim any port on host header 2016-12-15 13:31:09 +08:00
Andy Green
647fa47f25 test-client: fix broken protocol names 2016-12-15 13:30:47 +08:00
Andy Green
a310c13bf0 ipv6-allow-binding-to-ipv6-address-in-iface
ipv4 and ipv6 binding to a named interface works OK.  ipv4 binding to an IP also
works, but we need some extra ipv6 magic to identify the ipv6 interface from an
ipv6 address.

This patch based on code from "user3546716" at
http://stackoverflow.com/questions/13504934/binding-sockets-to-ipv6-addresses

adds the necessary magic.

https://github.com/warmcat/libwebsockets/issues/717
2016-12-15 10:10:23 +08:00
Andy Green
bc10edb359 client ssl add flag to control server cert hostname check
This is a simplified version of a patch that went on master before v2.1

675c349cc5

It enforces hostname checking for client SSL certs; perviously it was
not performed.

On v2.1+, you can control if this checking is applied or not.  But to
avoid changing to public API, it is enforced on v2.0-stable.

There is no legit reason to disable this check... if you want to disable it,
upgrade to v2.1+ or stay on v2.0-stable behind this patch.

https://github.com/warmcat/libwebsockets/issues/715
2016-12-14 19:27:46 +08:00
Andy Green
b75680a15f client: avoid possible NULL deref on error path
https://github.com/warmcat/libwebsockets/issues/672
2016-12-12 20:39:03 +08:00
Andy Green
dff4f2613d ws-server: restrict returned Sec-Websocket-Protocol to the chosen name only
https://libwebsockets.org/pipermail/libwebsockets/2016-November/002948.html

Updated to fix a problem with no protocol

https://github.com/warmcat/libwebsockets/issues/705
2016-12-10 09:14:37 +08:00
sjames1958gm
65cefdf879 client stash: update path variable to larger size 2016-11-22 09:01:34 +08:00
Andy Green
ba5f80a00a lws_socket_bind: use lws_sockfd_type 2016-11-16 09:01:02 +08:00
Andy Green
aba9ad0ea0 client: protect againt losing ah by lws_client_connect_2 2016-11-15 17:00:35 +08:00
Joerg Pommnitz
b40c0b8f1c some compilers need void param explicitly 2016-10-10 20:07:46 +08:00
Yuchen Xie
a9db080b6c Correct the library name of LIBHUBBUB_LIBRARIES
It should be `hubbub` in `find_library` to make the function work.
2016-10-10 20:07:37 +08:00
Andy Green
67f2bfe4da docs: explain lws_write handling of truncated sends better 2016-10-08 18:13:24 +08:00
Andy Green
3213c56516 document extpoll forced service problem on v2.0 2016-10-07 20:04:19 +08:00
Andy Green
7fc6515dc6 travis: explicitly point to openssl on osx
One day this started failing at CMake autofind. This forces it to look at the right place.
2016-10-05 10:16:28 +08:00
Andy Green
f7dd9d027a port forced service checking from libuv
Related to second part of

https://github.com/warmcat/libwebsockets/issues/638
2016-10-05 08:49:53 +08:00
Andy Green
846a3caf80 closing drops any pending ah rx immediately 2016-10-05 08:46:54 +08:00
Andy Piper
0a0377b143 windows detect client connection error 2016-10-04 21:43:22 +08:00
Peter Pentchev
01c47d0622 Remove the cleanup functions with OpenSSL 1.1. 2016-10-03 21:20:54 +08:00
Peter Pentchev
0af47a0b8d Subject: Fix some typographical and grammatical errors. 2016-10-03 21:19:06 +08:00
Andy Green
ab9c2f329c lws_header_table_reset: make caller responsibility to clear down ah rx buffer
There are two kinds of reaason to call lws_header_table_reset(), one is we are reallocating
a destroyed ah to another wsi, and the other is we are moving to the next pipelined header set
still on the same wsi, and we need a "weaker" reset that only clears down the state related
to the header parsing, not everything about the ah context including the ah rx buffer.

This patch moves the ah rxbuffer rxpos and rxlen resetting out of lws_header_table_reset() and to
be the responsibility of the caller.  Callers who are moving the ah to another wsi are
patched to deal with resetting rxpos and rxlen and lws_http_transaction_completed() who only
resets the ah when moving to the next pipelined headers, no longer wrongly clears the ah rxbuf.

https://github.com/warmcat/libwebsockets/issues/638
2016-09-29 10:38:26 +08:00
Brown, Matthew
3d48ce8f09 Added option to build the static library with PIC 2016-09-27 05:37:58 +08:00
Patrick Gansterer
a2241384e7 Add SVG to lws_get_mimetype() 2016-09-23 06:31:50 +08:00
Andy Green
5a247a57d2 v2.0.3 2016-09-15 03:07:47 +08:00
Andy Green
1f02bd2e66 lws_snprintf
Thanks to Fabrice Gilot for reporting the problem that led to uncovering this.

Due to a misunderstanding of the return value of snprintf (it is not truncated according
to the max size passed in) in several places relying on snprintf to truncate the length
overflows are possible.

This patch wraps snprintf with a new lws_snprintf() which does truncate its length to allow
the buffer limiting scheme to work properly.

All users should update with these fixes.
2016-09-15 02:54:32 +08:00
Andy Green
d7fb6ad9cf handle rx flow control active when consuming payload
https://github.com/warmcat/libwebsockets/issues/622
2016-09-10 04:44:56 +08:00
Andy Green
2aa6f1bccd adopt_socket_vhost: error path doesn't remove us from timeout list
As found by "github user 7"

https://github.com/warmcat/libwebsockets/issues/621
2016-09-09 08:31:56 +08:00
Andy Green
0f7e4dbd48 coverity 169271 - take care about sockfd of -1 on close 2016-08-28 09:54:30 +08:00
Patrick Gansterer
6a75dca024 Update badges in README.md
Fix the link to Appveyor and use SVG images.
2016-08-27 05:59:43 +08:00
Patrick Gansterer
b7473a354d Remove unneeded #include <stdint.h>
This fixes the build for Visual Studio 2008.
2016-08-26 19:41:31 +08:00
Andy Green
a86666cfe5 update changelog for v2.0.2 release that went out without it 2016-08-26 07:37:25 +08:00
Patrick Gansterer
4324ea598b Add error handling for SSL_new() of clients
Do not access wsi->ssl if SSL_new() failed and log the error.
2016-08-14 19:54:12 +08:00
Andy Green
d4410f1d07 server max protocol element 64
https://github.com/warmcat/libwebsockets/issues/601
2016-08-11 05:53:54 +08:00
Andy Green
f0789545e7 SNI-vhost-matching-fallback-to-wildcard 2016-07-11 09:56:56 +08:00
Robin Rowe
7d45a746d6 fix __x86_64__ check
https://github.com/warmcat/libwebsockets/issues/574
2016-06-30 02:14:03 +08:00
Andy Green
3382efe5d6 client confirm server hostname in cert
Openssl v1.0.2 and above have support for checking the hostname
the client side connected to against the hostname on the cert the
server presented.

This enables that feature if the necessary API is available in the
openssl version, meaning the connection will fail at ssl negotiation if the
cert isn't for the requested server

It's very easy to test, add a fake entry to /etc/hosts for the server IP with
a different name, using that will fail at ssl but using the correct dns name
matching the certificate will work.
2016-06-28 20:25:46 +08:00
Gadkari Mugdha
c1e14e7f6c fix for https connection code 2016-06-13 17:20:27 +08:00
Karl Palsson
27b7055ac6 non-openssl: only check for openssl ecdh in openssl builds
See also
https://github.com/warmcat/libwebsockets/issues/559

Signed-off-by: Karl Palsson <karlp@etactica.com>
2016-06-07 19:52:13 +08:00
Andy Green
f6f2dfc7fd client CONNECTION_ERROR also allow in LWSS_CLIENT_UNCONNECTED
Signed-off-by: Andy Green <andy@warmcat.com>
2016-06-07 17:26:11 +08:00
Andy Green
e746a993d0 lws_ssl_client_connect2 remove duplicate close on error path
https://github.com/warmcat/libwebsockets/issues/532

Signed-off-by: Andy Green <andy@warmcat.com>
2016-06-07 01:34:02 +08:00
Andy Green
5f0dc8f4e6 ARRAY_SIZE dont redefine
Signed-off-by: Andy Green <andy@warmcat.com>
2016-06-06 20:34:33 +08:00
Andy Green
b064fb5bc9 v2.0.2
Signed-off-by: Andy Green <andy@warmcat.com>
2016-06-06 19:59:30 +08:00
Martin C Drohmann
15bb297fbb Revert changes in daemonize.c from commit 22d6f39e7f 2016-06-02 13:06:32 +08:00
Young
83a79ec381 update document for lws_get_context 2016-06-01 08:38:39 +08:00
Fabian Kurz
9694e5194c lwsl_timestamp month off by one 2016-06-01 08:38:27 +08:00
Andy Green
0f222cdc77 output size trimming with default rxbuf fix
5e203f78e2 accidentally
trashed the "zero rz_buffer_size means 4096" handling
for tx chunking.

Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-15 09:01:43 +08:00
Andy Green
62a8b0cb33 appveyor libuv integration
Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-15 09:01:30 +08:00
Andy Green
73f859d9e7 lwsws conf mount extra mimetypes
This patch adds the ability to provide extra mimtypes on a mount.

lwsws conf learns how to do them.

Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-14 10:48:28 +08:00
Andy Green
37320ced18 lejp handle name elements starting with dot
Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-14 10:25:52 +08:00
Andy Green
3bd3a41e97 lwsws conf allow setting cipher list and ecdh curve
Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-14 08:34:29 +08:00
Andy Green
bc3f77e977 win32 more build fixes
After alexgille

https://github.com/warmcat/libwebsockets/issues/526

Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-14 06:56:31 +08:00
Andy Green
7d259d885a access_log ensure no reuse of freed log area
Valgrind caught http/1.1 pipelining using dead user agent alloc
for logging... NULL it when we free it since the wsi can be
reused with keepalive

==16208== Invalid free() / delete / delete[] / realloc()
==16208==    at 0x4847ACC: free (vg_replace_malloc.c:530)
==16208==    by 0x4888DC3: _realloc (alloc.c:8)
==16208==    by 0x4888DFF: lws_realloc (alloc.c:16)
==16208==    by 0x487DBCB: lws_access_log (libwebsockets.c:2352)
==16208==    by 0x48956DF: lws_http_transaction_completed (server.c:1245)
==16208==    by 0x4893757: lws_http_serve (server.c:340)
==16208==    by 0x48946EF: lws_http_action (server.c:748)
==16208==    by 0x4894CEF: lws_handshake_server (server.c:900)
==16208==    by 0x48786BF: lws_read (handshake.c:120)
==16208==    by 0x4896103: lws_server_socket_service (server.c:1580)
==16208==    by 0x487FB6B: lws_service_fd_tsi (service.c:779)
==16208==    by 0x48803B7: lws_service_fd (service.c:1079)
==16208==  Address 0x552e5f8 is 0 bytes inside a block of size 86 free'd
==16208==    at 0x4847ACC: free (vg_replace_malloc.c:530)
==16208==    by 0x4888DC3: _realloc (alloc.c:8)
==16208==    by 0x4888DFF: lws_realloc (alloc.c:16)
==16208==    by 0x487DBCB: lws_access_log (libwebsockets.c:2352)
==16208==    by 0x48956DF: lws_http_transaction_completed (server.c:1245)
==16208==    by 0x4893757: lws_http_serve (server.c:340)
==16208==    by 0x48946EF: lws_http_action (server.c:748)
==16208==    by 0x4894CEF: lws_handshake_server (server.c:900)
==16208==    by 0x48786BF: lws_read (handshake.c:120)
==16208==    by 0x4896103: lws_server_socket_service (server.c:1580)
==16208==    by 0x487FB6B: lws_service_fd_tsi (service.c:779)
==16208==    by 0x48803B7: lws_service_fd (service.c:1079)
==16208==  Block was alloc'd at
==16208==    at 0x4846498: malloc (vg_replace_malloc.c:298)
==16208==    by 0x4848D57: realloc (vg_replace_malloc.c:785)
==16208==    by 0x4888DA7: _realloc (alloc.c:6)
==16208==    by 0x4888DFF: lws_realloc (alloc.c:16)
==16208==    by 0x4893EAF: lws_http_action (server.c:565)
==16208==    by 0x4894CEF: lws_handshake_server (server.c:900)
==16208==    by 0x48786BF: lws_read (handshake.c:120)
==16208==    by 0x4896103: lws_server_socket_service (server.c:1580)
==16208==    by 0x487FB6B: lws_service_fd_tsi (service.c:779)
==16208==    by 0x48803B7: lws_service_fd (service.c:1079)
==16208==    by 0x48994B7: lws_io_cb (libuv.c:101)
==16208==    by 0x4AE7B1F: ??? (in /usr/lib/libuv.so.1.0.0)


Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-13 11:00:45 +08:00
Andy Green
9c0cc42707 asserts log which
Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-13 10:59:44 +08:00
Sterling Jensen
85213516d3 Fix leak caused by undestroyed pthread mutex 2016-05-13 09:42:58 +08:00
Andy Green
f92ed9c7a7 win32 libuv related build fixes
https://github.com/warmcat/libwebsockets/issues/526

Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-13 08:22:03 +08:00
Andy Green
36699d6ecb v2.0.1
Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-12 22:29:06 +08:00
Andy Green
1cea325a42 check oom on lws_malloc
Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-12 21:53:57 +08:00
Andy Green
d5c43f4a6e windows no chown on log file generation
https://github.com/warmcat/libwebsockets/issues/524

Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-11 19:00:15 +08:00
Andy Green
3baed037c9 output allow LWS_PRE+4 on top of rx_buffer_size for max send chunk
https://github.com/warmcat/libwebsockets/issues/522

Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-10 21:37:58 +08:00
Andy Green
0b208559e0 logging migrate user stimulated logging to info
https://github.com/warmcat/libwebsockets/issues/520

Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-09 13:32:53 +08:00
Andy Green
fc29185b9f POST handling dont autocomplete transaction
Until now lws has finished the HTTP transaction when the POST body was
completely received.

However that needlessly makes it impossible to send a HTTP 200 and a
response without a redirect.

This changes lws behaviour after sending the LWS_CALLBACK_HTTP_BODY_COMPLETION
callback to no longer terminate the HTTP transaction.

If you want the old behaviour, you can terminate the transaction with
lws_http_transaction_completed() in the LWS_CALLBACK_HTTP_BODY_COMPLETION
callback.

Otherwise it's now possible to call lws_callback_on_writable() from
LWS_CALLBACK_HTTP_BODY_COMPLETION.

Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-09 10:08:13 +08:00
Andy Green
0daa1869b2 libuv tidy up destroy and disable timer races during shutdown
Also don't make us wait 1s for init to finish.

Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-08 17:11:19 +08:00
Andy Green
b1150df2f5 client fix for operation with libuv
- libuv socket init binding was missing for client

 - failures like no ws protocol match are deferred until the
   ah is bound.  Check for these failures and make sure we
   tell the guy trying to set up the client connection the
   wsi is NULL if it has already failed and closed.

 - pfd.events was not initialized for the client init path

With this general client function is more robust but also
client connections work properly with libuv.

Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-08 17:11:07 +08:00
Andy Green
465e2660e3 context only destroy protocols if init got sent
If for some reason we exit before the protocol init action
(which is delayed for libuv) we should not send the protocol
destroy messages

Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-08 17:10:51 +08:00
Andy Green
792713f2c1 client handle connection fail at second phase properly
Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-08 17:10:38 +08:00
Andy Green
e36ce9b20e test server post also take care about POST len termination
Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-08 17:10:24 +08:00
Andy Green
7624a8b128 update api docs v2.0
Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-07 14:26:32 +08:00
Andy Green
179b3ed9ff fix %3d handling in path part and add attack.sh
https://github.com/warmcat/libwebsockets/issues/518

Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-07 08:32:44 +08:00
Andy Green
79b1519b01 protocol plugins default also add example in test server v2.0
This shows how to deliver per-vhost, per-protocol option
name:value pairs using code.

Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-06 15:57:17 +08:00
Andy Green
172c78a43a protocol plugins set default
Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-06 14:42:37 +08:00
Andy Green
e2bf142912 mimetypes add additional canned
Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-06 08:08:48 +08:00
OndraCo
bd462c0b46 MSVC from 2015 up has vsnprintf 2016-05-06 07:50:44 +08:00
OndraCo
f0a16ce17b Disabled static link handling for WIN_CE to temporarily avoid the fact that it has no stat struct 2016-05-06 07:50:30 +08:00
OndraCo
2f9da92e48 Changes to enable WIN CE support 2016-05-06 07:50:17 +08:00
Enno Boland
f522895234 lib/server.c: fix ipv6 support 2016-05-06 07:50:04 +08:00
Enno Boland
5f4890b7ff lib/ssl.c: fix libre- and boringssl 2016-05-06 07:49:49 +08:00
52 changed files with 1349 additions and 374 deletions

View file

@ -23,7 +23,7 @@ language: generic
install:
- ./travis_install.sh
script:
- if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then mkdir build && cd build && cmake $CMAKE_ARGS .. && cmake --build .; fi
- if [ "$COVERITY_SCAN_BRANCH" != 1 -a "$TRAVIS_OS_NAME" = "osx" ]; then mkdir build && cd build && cmake -DOPENSSL_ROOT_DIR="/usr/local/opt/openssl" $CMAKE_ARGS .. && cmake --build .; else if [ "$COVERITY_SCAN_BRANCH" != 1 -a "$TRAVIS_OS_NAME" = "linux" ]; then mkdir build && cd build && cmake $CMAKE_ARGS .. && cmake --build . ; fi ; fi
sudo: required
dist: trusty
addons:

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 2.8)
cmake_minimum_required(VERSION 2.8.9)
if(NOT DEFINED CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type")
@ -10,11 +10,11 @@ set(PACKAGE "libwebsockets")
set(CPACK_PACKAGE_NAME "${PACKAGE}")
set(CPACK_PACKAGE_VERSION_MAJOR "2")
set(CPACK_PACKAGE_VERSION_MINOR "0")
set(CPACK_PACKAGE_VERSION_PATCH "0")
set(CPACK_PACKAGE_VERSION_PATCH "3")
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
set(CPACK_PACKAGE_VENDOR "andy@warmcat.com")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PACKAGE} ${PACKAGE_VERSION}")
set(SOVERSION "8")
set(SOVERSION "8.1")
set(CPACK_SOURCE_GENERATOR "TGZ")
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
set(VERSION "${CPACK_PACKAGE_VERSION}")
@ -97,6 +97,7 @@ option(LWS_WITH_LWSWS "Libwebsockets Webserver" OFF)
option(LWS_WITH_PLUGINS "Support plugins for protocols and extensions" OFF)
option(LWS_WITH_ACCESS_LOG "Support generating Apache-compatible access logs" OFF)
option(LWS_WITH_SERVER_STATUS "Support json + jscript server monitoring" OFF)
option(LWS_STATIC_PIC "Build the static version of the library with position-independent code" OFF)
if (LWS_WITH_LWSWS)
message(STATUS "LWS_WITH_LWSWS --> Enabling LWS_WITH_PLUGINS and LWS_WITH_LIBUV")
@ -378,7 +379,7 @@ if (NOT LWS_HAVE_inline)
endif()
endif()
# Put the libaries and binaries that get built into directories at the
# Put the libraries and binaries that get built into directories at the
# top of the build tree rather than in hard-to-find leaf directories.
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
@ -631,6 +632,9 @@ source_group("Sources" FILES ${SOURCES})
set(LWS_LIBRARIES)
if (LWS_WITH_STATIC)
if (LWS_STATIC_PIC)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
add_library(websockets STATIC
${HDR_PRIVATE}
${HDR_PUBLIC}
@ -799,7 +803,6 @@ if (LWS_WITH_SSL)
include_directories("${OPENSSL_INCLUDE_DIRS}")
list(APPEND LIB_LIST ${OPENSSL_LIBRARIES})
endif()
# older (0.98) Openssl lacks this
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS})
@ -808,6 +811,7 @@ if (LWS_WITH_SSL)
if (LWS_SSL_SERVER_WITH_ECDH_CERT AND NOT LWS_HAVE_OPENSSL_ECDH_H)
message(FATAL_ERROR "Missing openssl/ecdh.h, so cannot use LWS_SSL_SERVER_WITH_ECDH_CERT")
endif()
endif()
endif(LWS_WITH_SSL)
@ -839,7 +843,7 @@ if (LWS_WITH_LIBUV)
list(APPEND LIB_LIST ${LIBUV_LIBRARIES})
endif()
if (LWS_WITH_HTTP_PROXY)
find_library(LIBHUBBUB_LIBRARIES NAMES libhubbub)
find_library(LIBHUBBUB_LIBRARIES NAMES hubbub)
list(APPEND LIB_LIST ${LIBHUBBUB_LIBRARIES} )
endif()
@ -865,6 +869,7 @@ endforeach()
set (temp ${CMAKE_REQUIRED_LIBRARIES})
set(CMAKE_REQUIRED_LIBRARIES ${LIB_LIST})
CHECK_FUNCTION_EXISTS(SSL_CTX_set1_param LWS_HAVE_SSL_CTX_set1_param)
CHECK_FUNCTION_EXISTS(X509_VERIFY_PARAM_set1_host LWS_HAVE_X509_VERIFY_PARAM_set1_host)
set(CMAKE_REQUIRED_LIBRARIES ${temp})
# Generate the lws_config.h that includes all the public compilation settings.
configure_file(
@ -1177,7 +1182,7 @@ if (NOT LWS_WITHOUT_TESTAPPS)
set(PLUGIN_SRCS ${MAIN_SRC})
if (WIN32)
list(APPEND PLUGIN_SRCSset_property
list(APPEND PLUGIN_SRCS
${WIN32_HELPERS_PATH}/getopt.c
${WIN32_HELPERS_PATH}/getopt_long.c
${WIN32_HELPERS_PATH}/gettimeofday.c
@ -1493,6 +1498,8 @@ message(" LIBHUBBUB_LIBRARIES = ${LIBHUBBUB_LIBRARIES}")
message(" PLUGINS = ${PLUGINS_LIST}")
message(" LWS_WITH_ACCESS_LOG = ${LWS_WITH_ACCESS_LOG}")
message(" LWS_WITH_SERVER_STATUS = ${LWS_WITH_SERVER_STATUS}")
message(" LWS_STATIC_PIC = ${LWS_STATIC_PIC}")
message("---------------------------------------------------------------------")
# These will be available to parent projects including libwebsockets using add_subdirectory()

View file

@ -225,11 +225,11 @@ Setting compile options
-----------------------
To set compile time flags you can either use one of the CMake gui applications
or do it via command line.
or do it via the command line.
Command line
------------
To list avaialable options (ommit the H if you don't want the help text):
To list available options (omit the H if you don't want the help text):
cmake -LH ..

View file

@ -21,7 +21,7 @@ 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
similar to change the available number of file descriptors, and when restarted
**libwebsockets** will adapt accordingly.
@ -167,6 +167,14 @@ whereas info is ignored by default.
External Polling Loop support
-----------------------------
NOTE: You should use v2.1 or later (or master) for external polling loop
support. After v2.0 was released a problem was found meaning some internal
APIs needed to be exposed to deal with connections that need service even
without any new network activity. For normal poll() and libuv/ev loops,
lws takes care of this internally but external polling loop needs it doing
externally. Since we can't change the API on a released version that
means you need to use v2.1 or later for this feature to work properly.
**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
@ -497,6 +505,25 @@ There are some new members but mainly it's stuff you used to set at
context creation time.
How lws matches hostname or SNI to a vhost
------------------------------------------
LWS first strips any trailing :port number.
Then it tries to find an exact name match for a vhost listening on the correct
port, ie, if SNI or the Host: header provided abc.com:1234, it will match on a
vhost named abc.com that is listening on port 1234.
If there is no exact match, lws will consider wildcard matches, for example
if cats.abc.com:1234 is provided by the client by SNI or Host: header, it will
accept a vhost "abc.com" listening on port 1234. If there was a better, exact,
match, it will have been chosen in preference to this.
Connections with SSL will still have the client go on to check the
certificate allows wildcards and error out if not.
Using lws v2 mounts on a vhost
------------------------------

View file

@ -146,7 +146,7 @@ Vhosts can select which plugins they want to offer and give them per-vhost setti
```
"ws-protocols": [{
"warmcat,timezoom": {
"warmcat-timezoom": {
"status": "ok"
}
}]
@ -157,6 +157,19 @@ The "x":"y" parameters like "status":"ok" are made available to the protocol dur
LWS_CALLBACK_PROTOCOL_INIT (@in is a pointer to a linked list of struct lws_protocol_vhost_options
containing the name and value pointers).
To indicate that a protocol should be used when no Protocol: header is sent
by the client, you can use "default": "1"
```
"ws-protocols": [{
"warmcat-timezoom": {
"status": "ok",
"default": "1"
}
}]
```
Other vhost options
-------------------
@ -175,6 +188,12 @@ Other vhost options
- "`access-log`": "filepath" sets where apache-compatible access logs will be written
- "`ciphers`": "<cipher list>" sets the allowed list of ciphers and key exchange protocols for the vhost. The default list is restricted to only those providing PFS (Perfect Forward Secrecy) on the author's Fedora system.
If you need to allow weaker ciphers,you can provide an alternative list here per-vhost.
- "`ecdh-curve`": "<curve name>" The default ecdh curve is "prime256v1", but you can override it here, per-vhost
Mounts
------
@ -222,7 +241,7 @@ Note: currently only a fixed set of mimetypes are supported.
Other mount options
-------------------
1) When using a cgi:// protcol origin at a mountpoint, you may also give cgi environment variables specific to the mountpoint like this
1) When using a cgi:// protocol origin at a mountpoint, you may also give cgi environment variables specific to the mountpoint like this
```
{
@ -256,6 +275,14 @@ options are given, the content is marked uncacheable.
}
4) You can also define a list of additional mimetypes per-mount
"extra-mimetypes": {
".zip": "application/zip",
".doc": "text/evil"
}
Plugins
-------

View file

@ -1,5 +1,5 @@
[![Travis Build Status](https://travis-ci.org/warmcat/libwebsockets.png)](https://travis-ci.org/warmcat/libwebsockets)
[![Appveyor Build status](https://ci.appveyor.com/api/projects/status/qfasji8mnfnd2r8t)](https://ci.appveyor.com/project/warmcat/libwebsockets)
[![Travis Build Status](https://travis-ci.org/warmcat/libwebsockets.svg)](https://travis-ci.org/warmcat/libwebsockets)
[![Appveyor Build status](https://ci.appveyor.com/api/projects/status/qfasji8mnfnd2r8t?svg=true)](https://ci.appveyor.com/project/lws-team/libwebsockets)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/3576/badge.svg)](https://scan.coverity.com/projects/3576)
libwebsockets

View file

@ -84,7 +84,7 @@ The test client supports SSL too, use
$ libwebsockets-test-client localhost --ssl -s
```
the -s tells it to accept the default selfsigned cert from the server,
the -s tells it to accept the default self-signed cert from the server,
otherwise it will strictly fail the connection if there is no CA cert to
validate the server's certificate.
@ -141,7 +141,7 @@ 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
By default the client test applet is set to accept self-signed
certificates used by the test server, this is indicated by the
`use_ssl` var being set to `2`. Set it to `1` to reject any server
certificate that it doesn't have a trusted CA cert for.
@ -192,7 +192,7 @@ 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
another server, you can specify the protocol to handshake with
by `--protocol=protocolname`
@ -350,7 +350,7 @@ Autobahn Test Notes
-------------------
1) Autobahn tests the user code + lws implementation. So to get the same
results, you need to follow test-echo.c in terms of user implmentation.
results, you need to follow test-echo.c in terms of user implementation.
2) Some of the tests make no sense for Libwebsockets to support and we fail them.

View file

@ -1,5 +1,8 @@
environment:
matrix:
- LWS_METHOD: lwsws
CMAKE_ARGS: -DLWS_WITH_LWSWS=1 -DLIBUV_INCLUDE_DIRS=C:\assets\libuv\include -DLIBUV_LIBRARIES=C:\assets\libuv\libuv.lib
- LWS_METHOD: default
- LWS_METHOD: noserver
@ -14,10 +17,16 @@ environment:
- LWS_METHOD: nossl
CMAKE_ARGS: -DLWS_WITH_SSL=OFF
install:
- appveyor DownloadFile https://slproweb.com/download/Win32OpenSSL-1_0_2h.exe
- appveyor DownloadFile https://libwebsockets.org:444/win-libuv.zip
- mkdir c:\assets
- mkdir c:\assets\libuv
- 7z x -oc:\assets\libuv win-libuv.zip
# - appveyor DownloadFile https://slproweb.com/download/Win32OpenSSL-1_0_2h.exe
- appveyor DownloadFile https://libwebsockets.org:444/Win32OpenSSL-1_0_2h.exe
- Win32OpenSSL-1_0_2h.exe /silent /verysilent /sp- /suppressmsgboxes
- cinst -y nsis
- SET PATH=C:\Program Files\NSIS\;C:\Program Files (x86)\NSIS\;%PATH%
- appveyor DownloadFile https://libwebsockets.org:444/nsis-3.0rc1-setup.exe
- cmd /c start /wait nsis-3.0rc1-setup.exe /S /D=C:\nsis
- SET PATH=C:\Program Files\NSIS\;C:\Program Files (x86)\NSIS\;c:\nsis;%PATH%
build:
build_script:

View file

@ -1,6 +1,103 @@
Changelog
---------
v2.0.3
======
NB New api lws_snprintf() -> SONAME bump to 8.1
Fixes
-----
1) Remove duplicate close in one error path
2) Build fix for ecdh and non-openssl
3) Client confirms server cert
4) SNI falls back to match wildcard DNS names (this is later checked against
the cert for actual validity at SSL level)
5) Fix one error path on vhost adopt_socket where we are left on timeout list
6) lws_snprintf() - fix critical problem with snprintf not truncating buffer
lengths (it truncated the buffer write) as (wrongly) expected
v2.0.2
======
Fixes
-----
1) Fix possible pthread mutex leak
2) Make sure ACCESS_LOG can't touch freed area
3) extra options in lwsws conf for cipher list and ecdh curve
4) extra options in lwsws conf for extra mimetypes
5) fix default rxbuf trimming for output
6) lwsl_timestamp month number was off-by-one
7) fix daemonize.c
v2.0.1
======
Fixes
-----
1) OpenSSL version tests not needed on LibreSSL and BoringSSL
2) Fix IPV6 build breakage
3) Some fixes for WinCE build
4) Additional canned mimetypes for mounts, the full list is
.ico image/x-icon
.gif image/gif
.js text/javascript
.png image/png
.jpg image/jpeg
.gz application/gzip
.JPG image/jpeg
.html text/html
.css text/css
.txt text/plain
.ttf application/x-font-ttf
.woff application/font-woff
.xml application/xml
5) Allow per-vhost setting of which protocol should get used
when the protocol: header is not sent by the client
6) MINOR: user_space arg was mistakenly NULL on
LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER
7) MINOR: treating recv() returning 0 as peer close destroyed throughput on ab
tests, reverted
8) MINOR: %3d on URL part was always turned to _... this should only happen in
?na%3dme=x part of the URL
9) MINOR: some malloc escaped check for NULL / OOM
10) MINOR: libuv cleanups and client connections can operate correctly with
libuv
11) MINOR: POST used to hang up the connection when the body had all arrived.
Change it so you can reply with a 200 directly rather than requiring a
redirect
12) MINOR: API docs were a little behind the docs in the code
v2.0.0
======

View file

@ -17,6 +17,12 @@ lws_client_connect_2(struct lws *wsi)
lwsl_client("%s\n", __func__);
if (!wsi->u.hdr.ah) {
lwsl_err("ah was NULL at cc2\n");
goto oom4;
}
/* proxy? */
if (wsi->vhost->http_proxy_port) {
@ -163,6 +169,7 @@ lws_client_connect_2(struct lws *wsi)
wsi->mode = LWSCM_WSCL_WAITING_CONNECT;
lws_libev_accept(wsi, wsi->sock);
lws_libuv_accept(wsi, wsi->sock);
if (insert_wsi_socket_into_fds(context, wsi)) {
compatible_close(wsi->sock);
goto oom4;
@ -206,7 +213,11 @@ lws_client_connect_2(struct lws *wsi)
|| LWS_ERRNO == WSAEINVAL
#endif
) {
lwsl_client("nonblocking connect retry\n");
lwsl_client("nonblocking connect retry (errno = %d)\n",
LWS_ERRNO);
if (lws_plat_check_connection_error(wsi))
goto failed;
/*
* must do specifically a POLLOUT poll to hear
@ -271,6 +282,7 @@ lws_client_connect_2(struct lws *wsi)
wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE;
pfd.fd = wsi->sock;
pfd.events = LWS_POLLIN;
pfd.revents = LWS_POLLIN;
n = lws_service_fd(context, &pfd);
@ -283,8 +295,9 @@ lws_client_connect_2(struct lws *wsi)
oom4:
/* we're closing, losing some rx is OK */
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
//lwsl_err("%d\n", wsi->mode);
if (wsi->u.hdr.ah)
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
if (wsi->mode == LWSCM_HTTP_CLIENT)
wsi->vhost->protocols[0].callback(wsi,
LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
@ -364,7 +377,7 @@ html_parser_cb(const hubbub_token *token, void *pw)
switch (token->type) {
case HUBBUB_TOKEN_DOCTYPE:
p += snprintf(p, end - p, "<!DOCTYPE %.*s %s ",
p += lws_snprintf(p, end - p, "<!DOCTYPE %.*s %s ",
(int) token->data.doctype.name.len,
token->data.doctype.name.ptr,
token->data.doctype.force_quirks ?
@ -373,20 +386,20 @@ html_parser_cb(const hubbub_token *token, void *pw)
if (token->data.doctype.public_missing)
printf("\tpublic: missing\n");
else
p += snprintf(p, end - p, "PUBLIC \"%.*s\"\n",
p += lws_snprintf(p, end - p, "PUBLIC \"%.*s\"\n",
(int) token->data.doctype.public_id.len,
token->data.doctype.public_id.ptr);
if (token->data.doctype.system_missing)
printf("\tsystem: missing\n");
else
p += snprintf(p, end - p, " \"%.*s\">\n",
p += lws_snprintf(p, end - p, " \"%.*s\">\n",
(int) token->data.doctype.system_id.len,
token->data.doctype.system_id.ptr);
break;
case HUBBUB_TOKEN_START_TAG:
p += snprintf(p, end - p, "<%.*s", (int)token->data.tag.name.len,
p += lws_snprintf(p, end - p, "<%.*s", (int)token->data.tag.name.len,
token->data.tag.name.ptr);
/* (token->data.tag.self_closing) ?
@ -406,23 +419,23 @@ html_parser_cb(const hubbub_token *token, void *pw)
pp += r->from_len;
plen -= r->from_len;
}
p += snprintf(p, end - p, " %.*s=\"%s/%.*s\"",
p += lws_snprintf(p, end - p, " %.*s=\"%s/%.*s\"",
(int) token->data.tag.attributes[i].name.len,
token->data.tag.attributes[i].name.ptr,
r->to, plen, pp);
} else
p += snprintf(p, end - p, " %.*s=\"%.*s\"",
p += lws_snprintf(p, end - p, " %.*s=\"%.*s\"",
(int) token->data.tag.attributes[i].name.len,
token->data.tag.attributes[i].name.ptr,
(int) token->data.tag.attributes[i].value.len,
token->data.tag.attributes[i].value.ptr);
}
p += snprintf(p, end - p, ">\n");
p += lws_snprintf(p, end - p, ">\n");
break;
case HUBBUB_TOKEN_END_TAG:
p += snprintf(p, end - p, "</%.*s", (int) token->data.tag.name.len,
p += lws_snprintf(p, end - p, "</%.*s", (int) token->data.tag.name.len,
token->data.tag.name.ptr);
/*
(token->data.tag.self_closing) ?
@ -431,25 +444,25 @@ html_parser_cb(const hubbub_token *token, void *pw)
"attributes:" : "");
*/
for (i = 0; i < token->data.tag.n_attributes; i++) {
p += snprintf(p, end - p, " %.*s='%.*s'\n",
p += lws_snprintf(p, end - p, " %.*s='%.*s'\n",
(int) token->data.tag.attributes[i].name.len,
token->data.tag.attributes[i].name.ptr,
(int) token->data.tag.attributes[i].value.len,
token->data.tag.attributes[i].value.ptr);
}
p += snprintf(p, end - p, ">\n");
p += lws_snprintf(p, end - p, ">\n");
break;
case HUBBUB_TOKEN_COMMENT:
p += snprintf(p, end - p, "<!-- %.*s -->\n",
p += lws_snprintf(p, end - p, "<!-- %.*s -->\n",
(int) token->data.comment.len,
token->data.comment.ptr);
break;
case HUBBUB_TOKEN_CHARACTER:
p += snprintf(p, end - p, "%.*s", (int) token->data.character.len,
p += lws_snprintf(p, end - p, "%.*s", (int) token->data.character.len,
token->data.character.ptr);
break;
case HUBBUB_TOKEN_EOF:
p += snprintf(p, end - p, "\n");
p += lws_snprintf(p, end - p, "\n");
break;
}
@ -475,6 +488,9 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
struct lws *wsi;
int v = SPEC_LATEST_SUPPORTED;
if (i->context->requested_kill)
return NULL;
wsi = lws_zalloc(sizeof(struct lws));
if (wsi == NULL)
goto bail;
@ -566,10 +582,10 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
/* if we went on the waiting list, no probs just return the wsi
* when we get the ah, now or later, he will call
* lws_client_connect_via_info2() below
* lws_client_connect_via_info2() below.
*/
if (lws_header_table_attach(wsi, 0))
lwsl_debug("%s: went on ah wait list\n", __func__);
if (lws_header_table_attach(wsi, 0) < 0)
return NULL;
if (i->parent_wsi) {
lwsl_info("%s: created child %p of parent %p\n", __func__,

View file

@ -23,7 +23,6 @@
int lws_client_rx_sm(struct lws *wsi, unsigned char c)
{
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
int callback_action = LWS_CALLBACK_CLIENT_RECEIVE;
int handled, n, m, rx_draining_ext = 0;
unsigned short close_code;
@ -31,21 +30,10 @@ int lws_client_rx_sm(struct lws *wsi, unsigned char c)
unsigned char *pp;
if (wsi->u.ws.rx_draining_ext) {
struct lws **w = &pt->rx_draining_ext_list;
lwsl_ext("%s: RX EXT DRAINING: Removing from list\n", __func__, c);
assert(!c);
eff_buf.token = NULL;
eff_buf.token_len = 0;
wsi->u.ws.rx_draining_ext = 0;
/* remove us from context draining ext list */
while (*w) {
if (*w == wsi) {
*w = wsi->u.ws.rx_draining_ext_list;
break;
}
w = &((*w)->u.ws.rx_draining_ext_list);
}
wsi->u.ws.rx_draining_ext_list = NULL;
lws_remove_wsi_from_draining_ext_list(wsi);
rx_draining_ext = 1;
goto drain_extension;
@ -523,17 +511,16 @@ utf8_fail: lwsl_info("utf8 error\n");
if (callback_action == LWS_CALLBACK_CLIENT_RECEIVE_PONG)
lwsl_info("Client doing pong callback\n");
if (n && eff_buf.token_len) {
if (n && eff_buf.token_len)
/* extension had more... main loop will come back
* we want callback to be done with this set, if so,
* because lws_is_final() hides it was final until the
* last chunk
*/
wsi->u.ws.rx_draining_ext = 1;
wsi->u.ws.rx_draining_ext_list = pt->rx_draining_ext_list;
pt->rx_draining_ext_list = wsi;
lwsl_ext("%s: RX EXT DRAINING: Adding to list\n", __func__);
}
lws_add_wsi_to_draining_ext_list(wsi);
else
lws_remove_wsi_from_draining_ext_list(wsi);
if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY ||
wsi->state == LWSS_AWAITING_CLOSE_ACK)
goto already_done;

6
lib/client.c Normal file → Executable file
View file

@ -148,8 +148,10 @@ lws_client_socket_service(struct lws_context *context, struct lws *wsi,
#ifdef LWS_OPENSSL_SUPPORT
/* we can retry this... just cook the SSL BIO the first time */
if (wsi->use_ssl && !wsi->ssl)
lws_ssl_client_bio_create(wsi);
if (wsi->use_ssl && !wsi->ssl) {
if (lws_ssl_client_bio_create(wsi))
return -1;
}
if (wsi->use_ssl) {
n = lws_ssl_client_connect1(wsi);

View file

@ -111,13 +111,15 @@ int
lws_protocol_init(struct lws_context *context)
{
struct lws_vhost *vh = context->vhost_list;
const struct lws_protocol_vhost_options *pvo;
const struct lws_protocol_vhost_options *pvo, *pvo1;
struct lws wsi;
int n;
memset(&wsi, 0, sizeof(wsi));
wsi.context = context;
lwsl_notice("%s\n", __func__);
while (vh) {
wsi.vhost = vh;
@ -128,12 +130,32 @@ lws_protocol_init(struct lws_context *context)
pvo = lws_vhost_protocol_options(vh,
vh->protocols[n].name);
if (pvo)
if (pvo) {
/*
* linked list of options specific to
* vh + protocol
*/
pvo = pvo->options;
pvo1 = pvo;
pvo = pvo1->options;
while (pvo) {
lwsl_notice(" vh %s prot %s opt %s\n",
vh->name,
vh->protocols[n].name,
pvo->name);
if (!strcmp(pvo->name, "default")) {
lwsl_notice("Setting default "
"protocol for vh %s to %s\n",
vh->name,
vh->protocols[n].name);
vh->default_protocol_index = n;
}
pvo = pvo->next;
}
pvo = pvo1->options;
}
/*
* inform all the protocols that they are doing their one-time
@ -351,11 +373,13 @@ lws_create_vhost(struct lws_context *context,
info->log_filepath);
goto bail;
}
#ifndef WIN32
if (context->uid != -1)
if (chown(info->log_filepath, context->uid,
context->gid) == -1)
lwsl_err("unable to chown log file %s\n",
info->log_filepath);
#endif
} else
vh->log_fd = LWS_INVALID_FILE;
#endif
@ -681,7 +705,7 @@ lws_context_destroy(struct lws_context *context)
{
const struct lws_protocols *protocol = NULL;
struct lws_context_per_thread *pt;
struct lws_vhost *vh, *vh1;
struct lws_vhost *vh = NULL, *vh1;
struct lws wsi;
int n, m;
@ -714,6 +738,7 @@ lws_context_destroy(struct lws_context *context)
/* no protocol close */);
n--;
}
lws_pt_mutex_destroy(pt);
}
/*
* give all extensions a chance to clean up any per-context
@ -732,7 +757,8 @@ lws_context_destroy(struct lws_context *context)
*
* We can't free things until after the event loop shuts down.
*/
vh = context->vhost_list;
if (context->protocol_init_done)
vh = context->vhost_list;
while (vh) {
wsi.vhost = vh;
protocol = vh->protocols;

View file

@ -142,9 +142,20 @@ lws_daemonize(const char *_lock_path)
exit(9);
}
/* If we got a good PID, then we can exit the parent process. */
if (pid_daemon > 0)
exit(0);
/* If we got a good PID, then we can exit the parent process. */
if (pid_daemon > 0) {
/*
* Wait for confirmation signal from the child via
* SIGCHILD / USR1, or for two seconds to elapse
* (SIGALRM). pause() should not return.
*/
alarm(2);
pause();
/* should not be reachable */
exit(1);
}
/* At this point we are executing as the child process */
parent = getppid();

View file

@ -202,7 +202,7 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
* rx buffer by the caller, so this assumption is safe while
* we block new rx while draining the existing rx
*/
if (eff_buf->token && eff_buf->token_len) {
if (!priv->rx.avail_in && eff_buf->token && eff_buf->token_len) {
priv->rx.next_in = (unsigned char *)eff_buf->token;
priv->rx.avail_in = eff_buf->token_len;
}

View file

@ -107,8 +107,10 @@ lws_read(struct lws *wsi, unsigned char *buf, size_t len)
wsi->u.hdr.lextable_pos = 0;
/* fallthru */
case LWSS_HTTP_HEADERS:
assert(wsi->u.hdr.ah);
if (!wsi->u.hdr.ah) {
lwsl_err("%s: LWSS_HTTP_HEADERS: NULL ah\n", __func__);
assert(0);
}
lwsl_parser("issuing %d bytes to parser\n", (int)len);
if (lws_handshake_client(wsi, &buf, len))
@ -211,7 +213,7 @@ postbody_completion:
goto bail;
}
goto http_complete;
break;
}
break;
@ -241,20 +243,6 @@ read_ok:
return buf - oldbuf;
http_complete:
lwsl_debug("%s: http_complete\n", __func__);
#ifndef LWS_NO_SERVER
/* Did the client want to keep the HTTP connection going? */
if (lws_http_transaction_completed(wsi))
goto bail;
#endif
/* we may have next header set already, but return to event loop first
* so a heaily-pipelined http/1.1 connection cannot monopolize the
* service thread with GET hugefile.bin GET hugefile.bin etc
*/
goto read_ok;
bail:
lwsl_debug("closing connection at lws_read bail:\n");
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);

View file

@ -479,7 +479,7 @@ int lws_http2_do_pps_send(struct lws_context *context, struct lws *wsi)
wsi->u.http.fd = LWS_INVALID_FILE;
if (lws_is_ssl(lws_http2_get_network_wsi(wsi))) {
lwsl_info("skipping nonexistant ssl upgrade headers\n");
lwsl_info("skipping nonexistent ssl upgrade headers\n");
break;
}

View file

@ -40,7 +40,7 @@ lws_uv_idle(uv_idle_t *handle
struct lws_context_per_thread *pt = lws_container_of(handle,
struct lws_context_per_thread, uv_idle);
lwsl_debug("%s\n", __func__);
// lwsl_debug("%s\n", __func__);
/*
* is there anybody with pending stuff that needs service forcing?
@ -51,8 +51,8 @@ lws_uv_idle(uv_idle_t *handle
/* still somebody left who wants forced service? */
if (!lws_service_adjust_timeout(pt->context, 1, pt->tid))
/* yes... come back again later */
lwsl_debug("%s: done again\n", __func__);
return;
// lwsl_debug("%s: done again\n", __func__);
return;
}
/* there is nobody who needs service forcing, shut down idle */
@ -133,6 +133,9 @@ lws_uv_timeout_cb(uv_timer_t *timer
struct lws_context_per_thread *pt = lws_container_of(timer,
struct lws_context_per_thread, uv_timeout_watcher);
if (pt->context->requested_kill)
return;
lwsl_debug("%s\n", __func__);
lws_service_fd_tsi(pt->context, NULL, pt->tid);
@ -149,6 +152,10 @@ lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi)
if (!loop) {
loop = lws_malloc(sizeof(*loop));
if (!loop) {
lwsl_err("OOM\n");
return -1;
}
#if UV_VERSION_MAJOR > 0
uv_loop_init(loop);
#else
@ -199,14 +206,14 @@ lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi)
}
uv_timer_init(pt->io_loop_uv, &pt->uv_timeout_watcher);
uv_timer_start(&pt->uv_timeout_watcher, lws_uv_timeout_cb, 1000, 1000);
uv_timer_start(&pt->uv_timeout_watcher, lws_uv_timeout_cb, 10, 1000);
return status;
}
static void lws_uv_close_cb(uv_handle_t *handle)
{
//lwsl_err("%s\n", __func__);
//lwsl_err("%s: handle %p\n", __func__, handle);
}
static void lws_uv_walk_cb(uv_handle_t *handle, void *arg)
@ -226,12 +233,13 @@ lws_libuv_destroyloop(struct lws_context *context, int tsi)
if (!pt->io_loop_uv)
return;
if (context->use_ev_sigint)
if (context->use_ev_sigint) {
uv_signal_stop(&pt->w_sigint.uv_watcher);
for (m = 0; m < ARRAY_SIZE(sigs); m++) {
uv_signal_stop(&pt->signals[m]);
uv_close((uv_handle_t *)&pt->signals[m], lws_uv_close_cb);
for (m = 0; m < ARRAY_SIZE(sigs); m++) {
uv_signal_stop(&pt->signals[m]);
uv_close((uv_handle_t *)&pt->signals[m], lws_uv_close_cb);
}
}
uv_timer_stop(&pt->uv_timeout_watcher);
@ -243,15 +251,12 @@ lws_libuv_destroyloop(struct lws_context *context, int tsi)
while (budget-- && uv_run(pt->io_loop_uv, UV_RUN_NOWAIT))
;
if (!pt->ev_loop_foreign)
uv_stop(pt->io_loop_uv);
if (pt->ev_loop_foreign)
return;
uv_stop(pt->io_loop_uv);
uv_walk(pt->io_loop_uv, lws_uv_walk_cb, NULL);
if (pt->ev_loop_foreign)
return;
while (uv_run(pt->io_loop_uv, UV_RUN_NOWAIT))
;
@ -296,15 +301,18 @@ lws_libuv_io(struct lws *wsi, int flags)
if (!LWS_LIBUV_ENABLED(context))
return;
lwsl_debug("%s: wsi: %p, flags:0x%x\n", __func__, wsi, flags);
// lwsl_notice("%s: wsi: %p, flags:0x%x\n", __func__, wsi, flags);
if (!pt->io_loop_uv) {
lwsl_info("%s: no io loop yet\n", __func__);
return;
}
assert((flags & (LWS_EV_START | LWS_EV_STOP)) &&
(flags & (LWS_EV_READ | LWS_EV_WRITE)));
if (!((flags & (LWS_EV_START | LWS_EV_STOP)) &&
(flags & (LWS_EV_READ | LWS_EV_WRITE)))) {
lwsl_err("%s: assert: flags %d", __func__, flags);
assert(0);
}
if (flags & LWS_EV_START) {
if (flags & LWS_EV_WRITE)
@ -375,6 +383,9 @@ lws_libuv_stop(struct lws_context *context)
struct lws_context_per_thread *pt;
int n, m;
if (context->requested_kill)
return;
context->requested_kill = 1;
m = context->count_threads;
@ -473,14 +484,14 @@ lws_plat_plugins_init(struct lws_context * context, const char * const *d)
lwsl_notice(" %s\n", dent.name);
snprintf(path, sizeof(path) - 1, "%s/%s", *d, dent.name);
lws_snprintf(path, sizeof(path) - 1, "%s/%s", *d, dent.name);
if (uv_dlopen(path, &lib)) {
uv_dlerror(&lib);
lwsl_err("Error loading DSO: %s\n", lib.errmsg);
goto bail;
}
/* we could open it, can we get his init function? */
m = snprintf(path, sizeof(path) - 1, "init_%s",
m = lws_snprintf(path, sizeof(path) - 1, "init_%s",
dent.name + 3 /* snip lib... */);
path[m - 3] = '\0'; /* snip the .so */
if (uv_dlsym(&lib, path, &v)) {
@ -539,11 +550,11 @@ lws_plat_plugins_destroy(struct lws_context * context)
if (!plugin)
return 0;
lwsl_notice("%s\n", __func__);
// lwsl_notice("%s\n", __func__);
while (plugin) {
p = plugin;
m = snprintf(path, sizeof(path) - 1, "destroy_%s", plugin->name + 3);
m = lws_snprintf(path, sizeof(path) - 1, "destroy_%s", plugin->name + 3);
path[m - 3] = '\0';
if (uv_dlsym(&plugin->lib, path, &v)) {

191
lib/libwebsockets.c Normal file → Executable file
View file

@ -30,6 +30,14 @@
#include <sys/wait.h>
#endif
#ifdef LWS_USE_IPV6
#if defined(WIN32) || defined(_WIN32)
#include <Iphlpapi.h>
#else
#include <net/if.h>
#endif
#endif
int log_level = LLL_ERR | LLL_WARN | LLL_NOTICE;
static void (*lwsl_emit)(int level, const char *line) = lwsl_emit_stderr;
@ -62,10 +70,6 @@ lws_free_wsi(struct lws *wsi)
lws_free_set_NULL(wsi->rxflow_buffer);
lws_free_set_NULL(wsi->trunc_alloc);
if (wsi->u.hdr.ah)
/* we're closing, losing some rx is OK */
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
/* we may not have an ah, but may be on the waiting list... */
lws_header_table_detach(wsi, 0);
@ -153,6 +157,10 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
lws_access_log(wsi);
if (wsi->u.hdr.ah)
/* we're closing, losing some rx is OK */
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
context = wsi->context;
pt = &context->pt[(int)wsi->tsi];
@ -323,7 +331,7 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
if (!wsi->u.ws.close_in_ping_buffer_len) {
wsi->u.ws.close_in_ping_buffer_len = 2;
wsi->u.ws.ping_payload_buf[LWS_PRE] =
(reason >> 16) & 0xff;
(reason >> 8) & 0xff;
wsi->u.ws.ping_payload_buf[LWS_PRE + 1] =
reason & 0xff;
}
@ -420,7 +428,8 @@ just_kill_connection:
lws_remove_from_timeout_list(wsi);
/* checking return redundant since we anyway close */
remove_wsi_socket_from_fds(wsi);
if (wsi->sock != LWS_SOCK_INVALID)
remove_wsi_socket_from_fds(wsi);
wsi->state = LWSS_DEAD_SOCKET;
@ -487,10 +496,22 @@ just_kill_connection:
wsi->user_space, NULL, 0 );
} else if (wsi->mode == LWSCM_WSCL_WAITING_SERVER_REPLY ||
wsi->mode == LWSCM_WSCL_WAITING_CONNECT) {
char* errorString;
lwsl_debug("Connection closed before server reply\n");
wsi->vhost->protocols[0].callback(wsi,
errorString = NULL;
if (wsi->u.hdr.ah)
errorString = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP);
if (errorString) {
wsi->vhost->protocols[0].callback(wsi,
LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
wsi->user_space, errorString,
(unsigned int)strlen(errorString));
} else {
wsi->vhost->protocols[0].callback(wsi,
LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
wsi->user_space, NULL, 0);
}
} else
lwsl_debug("not calling back closed mode=%d state=%d\n",
wsi->mode, wsi->state_pre_close);
@ -1154,17 +1175,17 @@ lwsl_timestamp(int level, char *p, int len)
continue;
now = time_in_microseconds() / 100;
if (ptm)
n = snprintf(p, len,
n = lws_snprintf(p, len,
"[%04d/%02d/%02d %02d:%02d:%02d:%04d] %s: ",
ptm->tm_year + 1900,
ptm->tm_mon,
ptm->tm_mon + 1,
ptm->tm_mday,
ptm->tm_hour,
ptm->tm_min,
ptm->tm_sec,
(int)(now % 10000), log_level_names[n]);
else
n = snprintf(p, len, "[%llu:%04d] %s: ",
n = lws_snprintf(p, len, "[%llu:%04d] %s: ",
(unsigned long long) now / 10000,
(int)(now % 10000), log_level_names[n]);
return n;
@ -1309,6 +1330,16 @@ lws_get_fops(struct lws_context *context)
return &context->fops;
}
/**
* lws_get_context - Allow getting lws_context from a Websocket connection
* instance
*
* With this function, users can access context in the callback function.
* Otherwise users may have to declare context as a global variable.
*
* @wsi: Websocket connection instance
*/
LWS_VISIBLE LWS_EXTERN struct lws_context *
lws_get_context(const struct lws *wsi)
{
@ -1536,7 +1567,7 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
#endif
LWS_EXTERN int
lws_socket_bind(struct lws_vhost *vhost, int sockfd, int port,
lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port,
const char *iface)
{
#if LWS_POSIX
@ -1574,7 +1605,46 @@ lws_socket_bind(struct lws_vhost *vhost, int sockfd, int port,
v = (struct sockaddr *)&serv_addr6;
n = sizeof(struct sockaddr_in6);
bzero((char *) &serv_addr6, sizeof(serv_addr6));
serv_addr6.sin6_addr = in6addr_any;
if (iface &&
interface_to_sa(vhost->context, iface,
(struct sockaddr_in *)v, n) < 0) {
lwsl_err("Unable to find interface %s\n", iface);
return -1;
}
if (iface) {
struct ifaddrs *addrs, *addr;
char ip[NI_MAXHOST];
unsigned int i;
getifaddrs(&addrs);
for (addr = addrs; addr; addr = addr->ifa_next) {
if (!addr->ifa_addr ||
addr->ifa_addr->sa_family != AF_INET6)
continue;
getnameinfo(addr->ifa_addr,
sizeof(struct sockaddr_in6),
ip, sizeof(ip),
NULL, 0, NI_NUMERICHOST);
i = 0;
while (ip[i])
if (ip[i++] == '%') {
ip[i - 1] = '\0';
break;
}
if (!strcmp(ip, iface)) {
serv_addr6.sin6_scope_id =
if_nametoindex(addr->ifa_name);
break;
}
}
freeifaddrs(addrs);
}
serv_addr6.sin6_family = AF_INET6;
serv_addr6.sin6_port = htons(port);
} else
@ -1662,6 +1732,24 @@ lws_finalize_startup(struct lws_context *context)
return 0;
}
int
lws_snprintf(char *str, size_t size, const char *format, ...)
{
va_list ap;
int n;
if (!size)
return 0;
va_start(ap, format);
n = vsnprintf(str, size, format, ap);
va_end(ap);
if (n >= size)
return size;
return n;
}
LWS_VISIBLE LWS_EXTERN int
lws_is_cgi(struct lws *wsi) {
@ -1696,7 +1784,7 @@ lws_create_basic_wsi(struct lws_context *context, int tsi)
new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
/* intialize the instance struct */
/* initialize the instance struct */
new_wsi->state = LWSS_CGI;
new_wsi->mode = LWSCM_CGI;
@ -1810,7 +1898,7 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len
if (wsi->u.hdr.ah) {
if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
uritok = WSI_TOKEN_POST_URI;
snprintf(cgi_path, sizeof(cgi_path) - 1, "REQUEST_URI=%s",
lws_snprintf(cgi_path, sizeof(cgi_path) - 1, "REQUEST_URI=%s",
lws_hdr_simple_ptr(wsi, uritok));
cgi_path[sizeof(cgi_path) - 1] = '\0';
env_array[n++] = cgi_path;
@ -1820,7 +1908,7 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len
env_array[n++] = "REQUEST_METHOD=GET";
env_array[n++] = p;
p += snprintf(p, end - p, "QUERY_STRING=");
p += lws_snprintf(p, end - p, "QUERY_STRING=");
/* dump the individual URI Arg parameters */
m = 0;
while (1) {
@ -1845,55 +1933,55 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len
*p++ = '\0';
env_array[n++] = p;
p += snprintf(p, end - p, "PATH_INFO=%s",
p += lws_snprintf(p, end - p, "PATH_INFO=%s",
lws_hdr_simple_ptr(wsi, uritok) +
script_uri_path_len);
p++;
}
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_REFERER)) {
env_array[n++] = p;
p += snprintf(p, end - p, "HTTP_REFERER=%s",
p += lws_snprintf(p, end - p, "HTTP_REFERER=%s",
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_REFERER));
p++;
}
if (lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {
env_array[n++] = p;
p += snprintf(p, end - p, "HTTP_HOST=%s",
p += lws_snprintf(p, end - p, "HTTP_HOST=%s",
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));
p++;
}
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) {
env_array[n++] = p;
p += snprintf(p, end - p, "HTTP_COOKIE=%s",
p += lws_snprintf(p, end - p, "HTTP_COOKIE=%s",
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COOKIE));
p++;
}
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT)) {
env_array[n++] = p;
p += snprintf(p, end - p, "USER_AGENT=%s",
p += lws_snprintf(p, end - p, "USER_AGENT=%s",
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_USER_AGENT));
p++;
}
if (uritok == WSI_TOKEN_POST_URI) {
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)) {
env_array[n++] = p;
p += snprintf(p, end - p, "CONTENT_TYPE=%s",
p += lws_snprintf(p, end - p, "CONTENT_TYPE=%s",
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE));
p++;
}
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
env_array[n++] = p;
p += snprintf(p, end - p, "CONTENT_LENGTH=%s",
p += lws_snprintf(p, end - p, "CONTENT_LENGTH=%s",
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH));
p++;
}
}
env_array[n++] = p;
p += snprintf(p, end - p, "SCRIPT_PATH=%s", exec_array[0]) + 1;
p += lws_snprintf(p, end - p, "SCRIPT_PATH=%s", exec_array[0]) + 1;
while (mp_cgienv) {
env_array[n++] = p;
p += snprintf(p, end - p, "%s=%s", mp_cgienv->name,
p += lws_snprintf(p, end - p, "%s=%s", mp_cgienv->name,
mp_cgienv->value);
lwsl_debug(" Applying mount-specific cgi env '%s'\n",
env_array[n - 1]);
@ -2333,10 +2421,13 @@ lws_access_log(struct lws *wsi)
if (!wsi->access_log_pending)
return 0;
if (!wsi->access_log.header_log)
return 0;
if (!p)
p = "";
l = snprintf(ass, sizeof(ass) - 1, "%s %d %lu %s\n",
l = lws_snprintf(ass, sizeof(ass) - 1, "%s %d %lu %s\n",
wsi->access_log.header_log,
wsi->access_log.response, wsi->access_log.sent, p);
@ -2346,10 +2437,14 @@ lws_access_log(struct lws *wsi)
} else
lwsl_err("%s", ass);
if (wsi->access_log.header_log)
if (wsi->access_log.header_log) {
lws_free(wsi->access_log.header_log);
if (wsi->access_log.user_agent)
wsi->access_log.header_log = NULL;
}
if (wsi->access_log.user_agent) {
lws_free(wsi->access_log.user_agent);
wsi->access_log.user_agent = NULL;
}
wsi->access_log_pending = 0;
return 0;
@ -2375,7 +2470,7 @@ lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len)
if (len < 100)
return 0;
buf += snprintf(buf, end - buf,
buf += lws_snprintf(buf, end - buf,
"{\n \"name\":\"%s\",\n"
" \"port\":\"%d\",\n"
" \"use_ssl\":\"%d\",\n"
@ -2401,11 +2496,11 @@ lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len)
if (vh->mount_list) {
const struct lws_http_mount *m = vh->mount_list;
buf += snprintf(buf, end - buf, ",\n \"mounts\":[");
buf += lws_snprintf(buf, end - buf, ",\n \"mounts\":[");
while (m) {
if (!first)
buf += snprintf(buf, end - buf, ",");
buf += snprintf(buf, end - buf,
buf += lws_snprintf(buf, end - buf, ",");
buf += lws_snprintf(buf, end - buf,
"\n {\n \"mountpoint\":\"%s\",\n"
" \"origin\":\"%s%s\",\n"
" \"cache_max_age\":\"%d\",\n"
@ -2421,25 +2516,25 @@ lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len)
m->cache_revalidate,
m->cache_intermediaries);
if (m->def)
buf += snprintf(buf, end - buf,
buf += lws_snprintf(buf, end - buf,
",\n \"default\":\"%s\"",
m->def);
buf += snprintf(buf, end - buf, "\n }");
buf += lws_snprintf(buf, end - buf, "\n }");
first = 0;
m = m->mount_next;
}
buf += snprintf(buf, end - buf, "\n ]");
buf += lws_snprintf(buf, end - buf, "\n ]");
}
if (vh->protocols) {
n = 0;
first = 1;
buf += snprintf(buf, end - buf, ",\n \"ws-protocols\":[");
buf += lws_snprintf(buf, end - buf, ",\n \"ws-protocols\":[");
while (n < vh->count_protocols) {
if (!first)
buf += snprintf(buf, end - buf, ",");
buf += snprintf(buf, end - buf,
buf += lws_snprintf(buf, end - buf, ",");
buf += lws_snprintf(buf, end - buf,
"\n {\n \"%s\":\{\n"
" \"status\":\"ok\"\n }\n }"
,
@ -2447,10 +2542,10 @@ lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len)
first = 0;
n++;
}
buf += snprintf(buf, end - buf, "\n ]");
buf += lws_snprintf(buf, end - buf, "\n ]");
}
buf += snprintf(buf, end - buf, "\n}");
buf += lws_snprintf(buf, end - buf, "\n}");
return buf - orig;
}
@ -2469,7 +2564,7 @@ lws_json_dump_context(const struct lws_context *context, char *buf, int len)
time_t t = time(NULL);
int listening = 0, cgi_count = 0, n;
buf += snprintf(buf, end - buf, "{ "
buf += lws_snprintf(buf, end - buf, "{ "
"\"version\":\"%s\",\n"
"\"uptime\":\"%ld\",\n"
"\"cgi_spawned\":\"%d\",\n"
@ -2489,19 +2584,19 @@ lws_json_dump_context(const struct lws_context *context, char *buf, int len)
m = getloadavg(d, 3);
for (n = 0; n < m; n++) {
buf += snprintf(buf, end - buf,
buf += lws_snprintf(buf, end - buf,
"\"l%d\":\"%.2f\",\n",
n + 1, d[n]);
}
}
#endif
buf += snprintf(buf, end - buf, "\"pt\":[\n ");
buf += lws_snprintf(buf, end - buf, "\"pt\":[\n ");
for (n = 0; n < context->count_threads; n++) {
pt = &context->pt[n];
if (n)
buf += snprintf(buf, end - buf, ",");
buf += snprintf(buf, end - buf,
buf += lws_snprintf(buf, end - buf, ",");
buf += lws_snprintf(buf, end - buf,
"\n {\n"
" \"fds_count\":\"%d\",\n"
" \"ah_pool_inuse\":\"%d\",\n"
@ -2512,7 +2607,7 @@ lws_json_dump_context(const struct lws_context *context, char *buf, int len)
pt->ah_wait_list_length);
}
buf += snprintf(buf, end - buf, "], \"vhosts\":[\n ");
buf += lws_snprintf(buf, end - buf, "], \"vhosts\":[\n ");
while (vh) {
if (!first)
@ -2525,7 +2620,7 @@ lws_json_dump_context(const struct lws_context *context, char *buf, int len)
vh = vh->vhost_next;
}
buf += snprintf(buf, end - buf, "],\n\"listen_wsi\":\"%d\"",
buf += lws_snprintf(buf, end - buf, "],\n\"listen_wsi\":\"%d\"",
listening);
#ifdef LWS_WITH_CGI
@ -2540,10 +2635,10 @@ lws_json_dump_context(const struct lws_context *context, char *buf, int len)
}
}
#endif
buf += snprintf(buf, end - buf, ",\n \"cgi_alive\":\"%d\"\n ",
buf += lws_snprintf(buf, end - buf, ",\n \"cgi_alive\":\"%d\"\n ",
cgi_count);
buf += snprintf(buf, end - buf, "}\n ");
buf += lws_snprintf(buf, end - buf, "}\n ");
return buf - orig;
}

View file

@ -112,7 +112,6 @@ struct sockaddr_in;
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stddef.h>
#include <stdint.h>
#include <basetsd.h>
#ifndef _WIN32_WCE
#include <fcntl.h>
@ -121,7 +120,8 @@ struct sockaddr_in;
#define O_RDONLY _O_RDONLY
#endif
#ifdef _WIN32_WCE
// Visual studio older than 2015 and WIN_CE has only _stricmp
#if (defined(_MSC_VER) && _MSC_VER < 1900) || defined(_WIN32_WCE)
#define strcasecmp _stricmp
#else
#define strcasecmp stricmp
@ -147,7 +147,11 @@ struct sockaddr_in;
#define LWS_O_RDONLY _O_RDONLY
#if !defined(_MSC_VER) || _MSC_VER < 1900 /* Visual Studio 2015 already defines this in <stdio.h> */
#define snprintf _snprintf
#define lws_snprintf _snprintf
#endif
#ifndef __func__
#define __func__ __FUNCTION__
#endif
#else /* NOT WIN32 */
@ -306,7 +310,9 @@ LWS_VISIBLE LWS_EXTERN void lwsl_hexdump(void *buf, size_t len);
struct lws;
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
#endif
/* api change list for user code to test against */
@ -343,7 +349,6 @@ enum lws_context_options {
(1 << 12),
LWS_SERVER_OPTION_LIBUV = (1 << 10),
LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS = (1 << 11) |
(1 << 3) |
(1 << 12),
LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT = (1 << 12),
LWS_SERVER_OPTION_EXPLICIT_VHOSTS = (1 << 13),
@ -1006,7 +1011,7 @@ struct lws_extension;
*
* 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
* to load extra certificates into the server which allow it to
* verify the validity of certificates returned by clients. @user
* is the server's OpenSSL SSL_CTX*
*
@ -1362,12 +1367,13 @@ struct lws_plugin {
* If we add more extensions, publish the callback here ------v
*/
extern int lws_extension_callback_pm_deflate(
LWS_EXTERN
int lws_extension_callback_pm_deflate(
struct lws_context *context, const struct lws_extension *ext,
struct lws *wsi, enum lws_extension_callback_reasons reason,
void *user, void *in, size_t len);
LWS_EXTERN int
LWS_VISIBLE LWS_EXTERN int
lws_set_extension_option(struct lws *wsi, const char *ext_name,
const char *opt_name, const char *opt_val);
@ -1385,6 +1391,7 @@ struct lws_http_mount {
const char *def; /* default target, eg, "index.html" */
const struct lws_protocol_vhost_options *cgienv;
const struct lws_protocol_vhost_options *extra_mimetypes;
int cgi_timeout;
int cache_max_age;
@ -1607,10 +1614,10 @@ enum {
LWSMPRO_REDIR_HTTPS,
};
LWS_EXTERN int
LWS_VISIBLE LWS_EXTERN int
lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len);
LWS_EXTERN int
LWS_VISIBLE LWS_EXTERN int
lws_json_dump_context(const struct lws_context *context, char *buf, int len);
LWS_VISIBLE LWS_EXTERN void
@ -1625,20 +1632,20 @@ lws_create_context(struct lws_context_creation_info *info);
struct lws_vhost;
LWS_VISIBLE struct lws_vhost *
LWS_EXTERN LWS_VISIBLE struct lws_vhost *
lws_create_vhost(struct lws_context *context,
struct lws_context_creation_info *info);
LWS_VISIBLE struct lws_vhost *
LWS_VISIBLE LWS_EXTERN struct lws_vhost *
lws_vhost_get(struct lws *wsi);
LWS_VISIBLE const struct lws_protocols *
LWS_VISIBLE LWS_EXTERN const struct lws_protocols *
lws_protocol_get(struct lws *wsi);
LWS_VISIBLE void *
LWS_VISIBLE LWS_EXTERN void *
lws_protocol_vh_priv_zalloc(struct lws_vhost *vhost, const struct lws_protocols *prot,
int size);
LWS_VISIBLE void *
LWS_VISIBLE LWS_EXTERN void *
lws_protocol_vh_priv_get(struct lws_vhost *vhost, const struct lws_protocols *prot);
LWS_VISIBLE LWS_EXTERN int
@ -1708,7 +1715,7 @@ lws_ev_sigint_cfg(struct lws_context *context, int use_ev_sigint,
LWS_VISIBLE LWS_EXTERN int
lws_ev_initloop(struct lws_context *context, struct ev_loop *loop, int tsi);
LWS_VISIBLE void
LWS_VISIBLE LWS_EXTERN void
lws_ev_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents);
#endif /* LWS_USE_LIBEV */
@ -1720,7 +1727,7 @@ lws_uv_sigint_cfg(struct lws_context *context, int use_uv_sigint,
LWS_VISIBLE LWS_EXTERN void
lws_libuv_run(const struct lws_context *context, int tsi);
LWS_VISIBLE void
LWS_VISIBLE LWS_EXTERN void
lws_libuv_stop(struct lws_context *context);
LWS_VISIBLE LWS_EXTERN int
@ -1729,7 +1736,7 @@ lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi);
LWS_VISIBLE LWS_EXTERN uv_loop_t *
lws_uv_getloop(struct lws_context *context, int tsi);
LWS_VISIBLE void
LWS_VISIBLE LWS_EXTERN void
lws_uv_sigint_cb(uv_signal_t *watcher, int signum);
#endif /* LWS_USE_LIBUV */
@ -1818,6 +1825,23 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs);
* to the address immediately after the padding won't cause an unaligned access
* error. Sometimes for performance reasons the recommended padding is even
* larger than sizeof(void *).
*
* Truncated Writes
* ================
*
* The OS may not accept everything you asked to write on the connection.
*
* Posix defines POLLOUT indication from poll() to show that the connection
* will accept more write data, but it doesn't specifiy how much. It may just
* accept one byte of whatever you wanted to send.
*
* LWS will buffer the remainder automatically, and send it out autonomously.
*
* During that time, WRITABLE callbacks will be suppressed.
*
* This is to handle corner cases where unexpectedly the OS refuses what we
* usually expect it to accept. You should try to send in chunks that are
* almost always accepted in order to avoid the inefficiency of the buffering.
*/
#if !defined(LWS_SIZEOFPTR)
@ -1827,7 +1851,7 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs);
#define u_int64_t unsigned long long
#endif
#if __x86_64__
#if defined(__x86_64__)
#define _LWS_PAD_SIZE 16 /* Intel recommended for best performance */
#else
#define _LWS_PAD_SIZE LWS_SIZEOFPTR /* Size of a pointer on the target arch */
@ -1883,7 +1907,7 @@ LWS_VISIBLE LWS_EXTERN int
lws_callback_on_writable_all_protocol(const struct lws_context *context,
const struct lws_protocols *protocol);
LWS_VISIBLE int
LWS_VISIBLE LWS_EXTERN int
lws_callback_on_writable_all_protocol_vhost(const struct lws_vhost *vhost,
const struct lws_protocols *protocol);
@ -1891,7 +1915,7 @@ LWS_VISIBLE LWS_EXTERN int
lws_callback_all_protocol(struct lws_context *context,
const struct lws_protocols *protocol, int reason);
LWS_VISIBLE int
LWS_VISIBLE LWS_EXTERN int
lws_callback_all_protocol_vhost(struct lws_vhost *vh,
const struct lws_protocols *protocol, int reason);
@ -2169,7 +2193,7 @@ lws_read(struct lws *wsi, unsigned char *buf, size_t len);
* client and server for how to do.
*/
static LWS_INLINE LWS_WARN_DEPRECATED const struct lws_extension *
lws_get_internal_extensions() { return NULL; }
lws_get_internal_extensions(void) { return NULL; }
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_ext_parse_options(const struct lws_extension *ext, struct lws *wsi,
void *ext_user, const struct lws_ext_options *opts,
@ -2182,6 +2206,20 @@ lws_ext_parse_options(const struct lws_extension *ext, struct lws *wsi,
LWS_VISIBLE LWS_EXTERN void
lws_set_allocator(void *(*realloc)(void *ptr, size_t size));
/**
* lws_snprintf(): lws_snprintf that truncates the returned length too
*
* \param str: destination buffer
* \param size: bytes left in destination buffer
* \param format: format string
* \param ...: args for format
*
* This lets you correctly truncate buffers by concatenating lengths, if you
* reach the limit the reported length doesn't exceed the limit.
*/
LWS_VISIBLE LWS_EXTERN int
lws_snprintf(char *str, size_t size, const char *format, ...);
#ifdef __cplusplus
}
#endif

View file

@ -81,6 +81,12 @@ lws_plat_change_pollfd(struct lws_context *context,
return 0;
}
extern "C" LWS_VISIBLE int
lws_plat_check_connection_error(struct lws *wsi)
{
return 0;
}
extern "C" LWS_VISIBLE int
lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len)
{

View file

@ -116,7 +116,7 @@ LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
LWS_VISIBLE int
lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
{
struct lws_context_per_thread *pt = &context->pt[tsi];
struct lws_context_per_thread *pt;
int n = -1, m, c;
char buf;
@ -125,6 +125,8 @@ lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
if (!context || !context->vhost_list)
return 1;
pt = &context->pt[tsi];
if (timeout_ms < 0)
goto faked_service;
@ -144,6 +146,19 @@ lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
context->service_tid = context->service_tid_detected;
timeout_ms = lws_service_adjust_timeout(context, timeout_ms, tsi);
/*
* is there anybody with pending stuff that needs service forcing?
*/
if (!timeout_ms) {
/* -1 timeout means just do forced service */
lws_plat_service_tsi(context, -1, pt->tid);
/* still somebody left who wants forced service? */
if (!lws_service_adjust_timeout(context, 1, pt->tid)) {
/* yes... come back again later */
lwsl_debug("%s: done again\n", __func__);
}
return 0;
}
n = poll(pt->fds, pt->fds_count, timeout_ms);
@ -193,6 +208,12 @@ faked_service:
return 0;
}
LWS_VISIBLE int
lws_plat_check_connection_error(struct lws *wsi)
{
return 0;
}
LWS_VISIBLE int
lws_plat_service(struct lws_context *context, int timeout_ms)
{
@ -331,7 +352,7 @@ lws_plat_plugins_init(struct lws_context * context, const char * const *d)
lwsl_notice(" %s\n", namelist[i]->d_name);
snprintf(path, sizeof(path) - 1, "%s/%s", *d,
lws_snprintf(path, sizeof(path) - 1, "%s/%s", *d,
namelist[i]->d_name);
l = dlopen(path, RTLD_NOW);
if (!l) {
@ -341,7 +362,7 @@ lws_plat_plugins_init(struct lws_context * context, const char * const *d)
goto bail;
}
/* we could open it, can we get his init function? */
m = snprintf(path, sizeof(path) - 1, "init_%s",
m = lws_snprintf(path, sizeof(path) - 1, "init_%s",
namelist[i]->d_name + 3 /* snip lib... */);
path[m - 3] = '\0'; /* snip the .so */
initfunc = dlsym(l, path);
@ -406,7 +427,7 @@ lws_plat_plugins_destroy(struct lws_context * context)
while (plugin) {
p = plugin;
m = snprintf(path, sizeof(path) - 1, "destroy_%s", plugin->name + 3);
m = lws_snprintf(path, sizeof(path) - 1, "destroy_%s", plugin->name + 3);
path[m - 3] = '\0';
func = dlsym(plugin->l, path);
if (!func) {
@ -538,7 +559,7 @@ lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
freeifaddrs(ifr);
if (rc == -1) {
/* check if bind to IP adddress */
/* check if bind to IP address */
#ifdef LWS_USE_IPV6
if (inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1)
rc = 0;

View file

@ -31,7 +31,10 @@ time_in_microseconds()
time_t time(time_t *t)
{
time_t ret = time_in_microseconds() / 1000000;
*t = ret;
if(t != NULL)
*t = ret;
return ret;
}
#endif
@ -153,7 +156,7 @@ LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
LWS_VISIBLE int
lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
{
struct lws_context_per_thread *pt = &context->pt[tsi];
struct lws_context_per_thread *pt;
WSANETWORKEVENTS networkevents;
struct lws_pollfd *pfd;
struct lws *wsi;
@ -165,6 +168,8 @@ lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
if (context == NULL)
return 1;
pt = &context->pt[tsi];
if (!context->service_tid_detected) {
struct lws _lws;
@ -231,7 +236,17 @@ lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
return -1;
}
pfd->revents = (short)networkevents.lNetworkEvents;
if ((networkevents.lNetworkEvents & FD_CONNECT) &&
networkevents.iErrorCode[FD_CONNECT_BIT] &&
networkevents.iErrorCode[FD_CONNECT_BIT] != LWS_EALREADY &&
networkevents.iErrorCode[FD_CONNECT_BIT] != LWS_EINPROGRESS &&
networkevents.iErrorCode[FD_CONNECT_BIT] != LWS_EWOULDBLOCK &&
networkevents.iErrorCode[FD_CONNECT_BIT] != WSAEINVAL) {
lwsl_debug("Unable to connect errno=%d\n",
networkevents.iErrorCode[FD_CONNECT_BIT]);
pfd->revents = LWS_POLLHUP;
} else
pfd->revents = (short)networkevents.lNetworkEvents;
if (pfd->revents & LWS_POLLOUT) {
wsi = wsi_from_fd(context, pfd->fd);
@ -406,7 +421,7 @@ lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
pt->fds[pt->fds_count++].revents = 0;
pt->events[pt->fds_count] = WSACreateEvent();
WSAEventSelect(wsi->sock, pt->events[pt->fds_count],
LWS_POLLIN | LWS_POLLHUP);
LWS_POLLIN | LWS_POLLHUP | FD_CONNECT);
}
LWS_VISIBLE void
@ -424,12 +439,29 @@ lws_plat_service_periodic(struct lws_context *context)
{
}
LWS_VISIBLE int
lws_plat_check_connection_error(struct lws *wsi)
{
int optVal;
int optLen = sizeof(int);
if (getsockopt(wsi->sock, SOL_SOCKET, SO_ERROR,
(char*)&optVal, &optLen) != SOCKET_ERROR && optVal &&
optVal != LWS_EALREADY && optVal != LWS_EINPROGRESS &&
optVal != LWS_EWOULDBLOCK && optVal != WSAEINVAL) {
lwsl_debug("Connect failed SO_ERROR=%d\n", optVal);
return 1;
}
return 0;
}
LWS_VISIBLE int
lws_plat_change_pollfd(struct lws_context *context,
struct lws *wsi, struct lws_pollfd *pfd)
{
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
long networkevents = LWS_POLLHUP;
long networkevents = LWS_POLLHUP | FD_CONNECT;
if ((pfd->events & LWS_POLLIN))
networkevents |= LWS_POLLIN;

View file

@ -130,6 +130,7 @@ int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
n = wsi->protocol->rx_buffer_size;
if (!n)
n = LWS_MAX_SOCKET_IO_BUF;
n += LWS_PRE + 4;
if (n > len)
n = len;

View file

@ -60,6 +60,8 @@ lextable_decode(int pos, char c)
}
}
// doesn't scrub the ah rxbuffer by default, parent must do if needed
void
lws_header_table_reset(struct lws *wsi, int autoservice)
{
@ -77,10 +79,6 @@ lws_header_table_reset(struct lws *wsi, int autoservice)
ah->nfrag = 0;
ah->pos = 0;
/* and reset the rx state */
ah->rxpos = 0;
ah->rxlen = 0;
/* since we will restart the ah, our new headers are not completed */
wsi->hdr_parsing_completed = 0;
@ -182,12 +180,21 @@ lws_header_table_attach(struct lws *wsi, int autoservice)
lws_pt_unlock(pt);
reset:
/* and reset the rx state */
wsi->u.hdr.ah->rxpos = 0;
wsi->u.hdr.ah->rxlen = 0;
lws_header_table_reset(wsi, autoservice);
time(&wsi->u.hdr.ah->assigned);
#ifndef LWS_NO_CLIENT
if (wsi->state == LWSS_CLIENT_UNCONNECTED)
lws_client_connect_via_info2(wsi);
if (!lws_client_connect_via_info2(wsi))
/* our client connect has failed, the wsi
* has been closed
*/
return -1;
#endif
return 0;
@ -280,6 +287,9 @@ int lws_header_table_detach(struct lws *wsi, int autoservice)
wsi->u.hdr.ah = ah;
ah->wsi = wsi; /* new owner */
/* and reset the rx state */
ah->rxpos = 0;
ah->rxlen = 0;
lws_header_table_reset(wsi, autoservice);
time(&wsi->u.hdr.ah->assigned);
@ -300,7 +310,14 @@ int lws_header_table_detach(struct lws *wsi, int autoservice)
#ifndef LWS_NO_CLIENT
if (wsi->state == LWSS_CLIENT_UNCONNECTED)
lws_client_connect_via_info2(wsi);
if (!lws_client_connect_via_info2(wsi)) {
/* our client connect has failed, the wsi
* has been closed
*/
lws_pt_unlock(pt);
return -1;
}
#endif
assert(!!pt->ah_wait_list_length == !!(int)(long)pt->ah_wait_list);
@ -675,7 +692,9 @@ lws_parse(struct lws *wsi, unsigned char c)
goto swallow;
}
/* uriencoded = in the name part, disallow */
if (c == '=' && enc && !wsi->u.hdr.post_literal_equal)
if (c == '=' && enc &&
ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] &&
!wsi->u.hdr.post_literal_equal)
c = '_';
/* after the real =, we don't care how many = */
@ -968,34 +987,67 @@ LWS_VISIBLE int lws_frame_is_binary(struct lws *wsi)
return wsi->u.ws.frame_is_binary;
}
void
lws_add_wsi_to_draining_ext_list(struct lws *wsi)
{
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
if (wsi->u.ws.rx_draining_ext)
return;
lwsl_ext("%s: RX EXT DRAINING: Adding to list\n", __func__);
wsi->u.ws.rx_draining_ext = 1;
wsi->u.ws.rx_draining_ext_list = pt->rx_draining_ext_list;
pt->rx_draining_ext_list = wsi;
}
void
lws_remove_wsi_from_draining_ext_list(struct lws *wsi)
{
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
struct lws **w = &pt->rx_draining_ext_list;
if (!wsi->u.ws.rx_draining_ext)
return;
lwsl_ext("%s: RX EXT DRAINING: Removing from list\n", __func__);
wsi->u.ws.rx_draining_ext = 0;
/* remove us from context draining ext list */
while (*w) {
if (*w == wsi) {
/* if us, point it instead to who we were pointing to */
*w = wsi->u.ws.rx_draining_ext_list;
break;
}
w = &((*w)->u.ws.rx_draining_ext_list);
}
wsi->u.ws.rx_draining_ext_list = NULL;
}
int
lws_rx_sm(struct lws *wsi, unsigned char c)
{
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
int callback_action = LWS_CALLBACK_RECEIVE;
int ret = 0, n, rx_draining_ext = 0;
struct lws_tokens eff_buf;
eff_buf.token = NULL;
eff_buf.token_len = 0;
if (wsi->socket_is_permanently_unusable)
return -1;
switch (wsi->lws_rx_parse_state) {
case LWS_RXPS_NEW:
if (wsi->u.ws.rx_draining_ext) {
struct lws **w = &pt->rx_draining_ext_list;
eff_buf.token = NULL;
eff_buf.token_len = 0;
wsi->u.ws.rx_draining_ext = 0;
/* remove us from context draining ext list */
while (*w) {
if (*w == wsi) {
*w = wsi->u.ws.rx_draining_ext_list;
break;
}
w = &((*w)->u.ws.rx_draining_ext_list);
}
wsi->u.ws.rx_draining_ext_list = NULL;
lws_remove_wsi_from_draining_ext_list(wsi);
rx_draining_ext = 1;
lwsl_err("%s: doing draining flow\n", __func__);
@ -1251,6 +1303,9 @@ handle_first:
case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
assert(wsi->u.ws.rx_ubuf);
if (wsi->u.ws.rx_draining_ext)
goto drain_extension;
if (wsi->u.ws.rx_ubuf_head + LWS_PRE >=
wsi->u.ws.rx_ubuf_alloc) {
lwsl_err("Attempted overflow \n");
@ -1411,6 +1466,9 @@ drain_extension:
goto already_done;
n = lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_RX, &eff_buf, 0);
/* eff_buf may be pointing somewhere completely different now,
* it's the output
*/
if (n < 0) {
/*
* we may rely on this to get RX, just drop connection
@ -1422,12 +1480,11 @@ drain_extension:
if (rx_draining_ext && eff_buf.token_len == 0)
goto already_done;
if (n && eff_buf.token_len) {
if (n && eff_buf.token_len)
/* extension had more... main loop will come back */
wsi->u.ws.rx_draining_ext = 1;
wsi->u.ws.rx_draining_ext_list = pt->rx_draining_ext_list;
pt->rx_draining_ext_list = wsi;
}
lws_add_wsi_to_draining_ext_list(wsi);
else
lws_remove_wsi_from_draining_ext_list(wsi);
if (eff_buf.token_len > 0 ||
callback_action == LWS_CALLBACK_RECEIVE_PONG) {
@ -1492,7 +1549,7 @@ lws_remaining_packet_payload(struct lws *wsi)
* to expect in that state and can deal with it in bulk more efficiently.
*/
void
int
lws_payload_until_length_exhausted(struct lws *wsi, unsigned char **buf,
size_t *len)
{
@ -1517,7 +1574,7 @@ lws_payload_until_length_exhausted(struct lws *wsi, unsigned char **buf,
/* we want to leave 1 byte for the parser to handle properly */
if (avail <= 1)
return;
return 0;
avail--;
rx_ubuf = wsi->u.ws.rx_ubuf + LWS_PRE + wsi->u.ws.rx_ubuf_head;
@ -1547,4 +1604,6 @@ lws_payload_until_length_exhausted(struct lws *wsi, unsigned char **buf,
wsi->u.ws.rx_ubuf_head += avail;
wsi->u.ws.rx_packet_length -= avail;
*len -= avail;
return avail;
}

View file

@ -82,12 +82,13 @@
#include <in6addr.h>
#endif
#include <mstcpip.h>
#include <io.h>
#ifndef __func__
#define __func__ __FUNCTION__
#endif
#ifdef _WIN32_WCE
#if (defined(_MSC_VER) && _MSC_VER < 1900) || defined(_WIN32_WCE)
#define vsnprintf _vsnprintf
#else
#ifdef LWS_HAVE__VSNPRINTF
@ -96,7 +97,7 @@
#endif
#ifdef LWS_HAVE__SNPRINTF
#define snprintf _snprintf
#define lws_snprintf _snprintf
#endif
#else /* not windows --> */
@ -193,6 +194,7 @@ static inline int compatible_close(int fd) { return close(fd); }
#else
#include <wolfssl/openssl/ssl.h>
#include <wolfssl/error-ssl.h>
#define OPENSSL_NO_TLSEXT
#endif /* not USE_OLD_CYASSL */
#else
#if defined(LWS_USE_POLARSSL)
@ -220,6 +222,16 @@ static inline int compatible_close(int fd) { return close(fd); }
#ifdef LWS_HAVE_OPENSSL_ECDH_H
#include <openssl/ecdh.h>
#endif
#include <openssl/x509v3.h>
#if (OPENSSL_VERSION_NUMBER < 0x0009080afL)
/* later openssl defines this to negate the presence of tlsext... but it was only
* introduced at 0.9.8j. Earlier versions don't know it exists so don't
* define it... making it look like the feature exists...
*/
#define OPENSSL_NO_TLSEXT
#endif
#endif /* not USE_MBEDTLS */
#endif /* not USE_POLARSSL */
#endif /* not USE_WOLFSSL */
@ -625,7 +637,7 @@ struct lws_context_per_thread {
* vhostwide SSL context
* vhostwide proxy
*
* heirarchy:
* hierarchy:
*
* context -> vhost -> wsi
*
@ -678,6 +690,7 @@ struct lws_vhost {
int allow_non_ssl_on_ssl_port;
unsigned int user_supplied_ssl_ctx:1;
#endif
unsigned char default_protocol_index;
};
/*
@ -884,7 +897,7 @@ enum uri_esc_states {
#ifndef LWS_NO_CLIENT
struct client_info_stash {
char address[256];
char path[1024];
char path[4096];
char host[256];
char origin[256];
char protocol[256];
@ -1269,7 +1282,7 @@ struct lws {
unsigned int extension_data_pending:1;
#endif
#ifdef LWS_OPENSSL_SUPPORT
unsigned int use_ssl:2;
unsigned int use_ssl:3;
unsigned int upgraded:1;
#endif
#ifdef _WIN32
@ -1304,7 +1317,7 @@ struct lws {
LWS_EXTERN int log_level;
LWS_EXTERN int
lws_socket_bind(struct lws_vhost *vhost, int sockfd, int port,
lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port,
const char *iface);
LWS_EXTERN void
@ -1432,7 +1445,7 @@ lws_client_interpret_server_handshake(struct lws *wsi);
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_rx_sm(struct lws *wsi, unsigned char c);
LWS_EXTERN void
LWS_EXTERN int
lws_payload_until_length_exhausted(struct lws *wsi, unsigned char **buf, size_t *len);
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
@ -1486,6 +1499,9 @@ void lws_http2_configure_if_upgraded(struct lws *wsi);
LWS_EXTERN int
lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd);
LWS_EXTERN int
lws_plat_check_connection_error(struct lws *wsi);
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_header_table_attach(struct lws *wsi, int autoservice);
@ -1612,6 +1628,13 @@ lws_pt_mutex_init(struct lws_context_per_thread *pt)
{
pthread_mutex_init(&pt->lock, NULL);
}
static LWS_INLINE void
lws_pt_mutex_destroy(struct lws_context_per_thread *pt)
{
pthread_mutex_destroy(&pt->lock);
}
static LWS_INLINE void
lws_pt_lock(struct lws_context_per_thread *pt)
{
@ -1625,6 +1648,7 @@ lws_pt_unlock(struct lws_context_per_thread *pt)
}
#else
#define lws_pt_mutex_init(_a) (void)(_a)
#define lws_pt_mutex_destroy(_a) (void)(_a)
#define lws_pt_lock(_a) (void)(_a)
#define lws_pt_unlock(_a) (void)(_a)
#endif
@ -1751,6 +1775,10 @@ lws_plat_service_periodic(struct lws_context *context);
LWS_EXTERN int
lws_plat_change_pollfd(struct lws_context *context, struct lws *wsi,
struct lws_pollfd *pfd);
LWS_EXTERN void
lws_add_wsi_to_draining_ext_list(struct lws *wsi);
LWS_EXTERN void
lws_remove_wsi_from_draining_ext_list(struct lws *wsi);
LWS_EXTERN int
lws_plat_context_early_init(void);
LWS_EXTERN void

View file

@ -6,6 +6,11 @@ lws_rewrite_create(struct lws *wsi, hubbub_callback_t cb, const char *from, cons
{
struct lws_rewrite *r = lws_malloc(sizeof(*r));
if (!r) {
lwsl_err("OOM\n");
return NULL;
}
if (hubbub_parser_create("UTF-8", false, &r->parser) != HUBBUB_OK) {
lws_free(r);

View file

@ -214,12 +214,14 @@ handshake_0405(struct lws_context *context, struct lws *wsi)
strcpy(p, (char *)pt->serv_buf);
p += accept_len;
if (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL)) {
/* we can only return the protocol header if:
* - one came in, and ... */
if (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL) &&
/* - it is not an empty string */
wsi->protocol->name &&
wsi->protocol->name[0]) {
LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: ");
n = lws_hdr_copy(wsi, p, 128, WSI_TOKEN_PROTOCOL);
if (n < 0)
goto bail;
p += n;
p += lws_snprintf(p, 128, "%s", wsi->protocol->name);
}
#ifndef LWS_NO_EXTENSIONS

View file

@ -67,7 +67,7 @@ lws_context_init_server(struct lws_context_creation_info *info,
else
#endif
#ifdef LWS_USE_IPV6
if (LWS_IPV6_ENABLED(context))
if (LWS_IPV6_ENABLED(vhost->context))
sockfd = socket(AF_INET6, SOCK_STREAM, 0);
else
#endif
@ -132,7 +132,15 @@ lws_context_init_server(struct lws_context_creation_info *info,
vhost->lserv_wsi = wsi;
#if LWS_POSIX
listen(wsi->sock, LWS_SOMAXCONN);
n = listen(wsi->sock, LWS_SOMAXCONN);
if (n < 0) {
lwsl_err("listen failed with error %d\n", LWS_ERRNO);
vhost->lserv_wsi = NULL;
vhost->context->count_wsi_allocated--;
remove_wsi_socket_from_fds(wsi);
vhost->context->pt[m].wsi_listening = NULL;
goto bail;
}
} /* for each thread able to independently listen */
#else
mbed3_tcp_stream_bind(wsi->sock, info->port, wsi);
@ -179,22 +187,59 @@ struct lws_vhost *
lws_select_vhost(struct lws_context *context, int port, const char *servername)
{
struct lws_vhost *vhost = context->vhost_list;
const char *p;
int n, m, colon;
n = strlen(servername);
colon = n;
p = strchr(servername, ':');
if (p)
colon = p - servername;
/* first try exact matches */
while (vhost) {
if (port == vhost->listen_port &&
!strcmp(vhost->name, servername)) {
!strncmp(vhost->name, servername, colon)) {
lwsl_info("SNI: Found: %s\n", servername);
return vhost;
}
vhost = vhost->vhost_next;
}
/*
* if no exact matches, try matching *.vhost-name
* unintentional matches are possible but resolve to x.com for *.x.com
* which is reasonable. If exact match exists we already chose it and
* never reach here. SSL will still fail it if the cert doesn't allow
* *.x.com.
*/
vhost = context->vhost_list;
while (vhost) {
m = strlen(vhost->name);
if (port == vhost->listen_port &&
m <= (colon - 2) &&
servername[colon - m - 1] == '.' &&
!strncmp(vhost->name, servername + colon - m, m)) {
lwsl_info("SNI: Found %s on wildcard: %s\n",
servername, vhost->name);
return vhost;
}
vhost = vhost->vhost_next;
}
return NULL;
}
static const char * get_mimetype(const char *file)
static const char *
get_mimetype(const char *file, const struct lws_http_mount *m)
{
int n = strlen(file);
const struct lws_protocol_vhost_options *pvo = NULL;
if (m)
pvo = m->extra_mimetypes;
if (n < 5)
return NULL;
@ -214,22 +259,51 @@ static const char * get_mimetype(const char *file)
if (!strcmp(&file[n - 4], ".jpg"))
return "image/jpeg";
if (!strcmp(&file[n - 3], ".gz"))
return "application/gzip";
if (!strcmp(&file[n - 4], ".JPG"))
return "image/jpeg";
if (!strcmp(&file[n - 5], ".html"))
return "text/html";
if (!strcmp(&file[n - 4], ".css"))
return "text/css";
if (!strcmp(&file[n - 4], ".txt"))
return "text/plain";
if (!strcmp(&file[n - 4], ".svg"))
return "image/svg+xml";
if (!strcmp(&file[n - 4], ".ttf"))
return "application/x-font-ttf";
if (!strcmp(&file[n - 5], ".woff"))
return "application/font-woff";
if (!strcmp(&file[n - 4], ".xml"))
return "application/xml";
while (pvo) {
if (!strcmp(&file[n - strlen(pvo->name)], pvo->name))
return pvo->value;
pvo = pvo->next;
}
return NULL;
}
int lws_http_serve(struct lws *wsi, char *uri, const char *origin)
static int
lws_http_serve(struct lws *wsi, char *uri, const char *origin,
const struct lws_http_mount *m)
{
const char *mimetype;
#ifndef _WIN32_WCE
struct stat st;
#endif
char path[256], sym[256];
unsigned char *p = (unsigned char *)sym + 32 + LWS_PRE, *start = p;
unsigned char *end = p + sizeof(sym) - 32 - LWS_PRE;
@ -238,8 +312,9 @@ int lws_http_serve(struct lws *wsi, char *uri, const char *origin)
#endif
int n, spin = 0;
snprintf(path, sizeof(path) - 1, "%s/%s", origin, uri);
lws_snprintf(path, sizeof(path) - 1, "%s/%s", origin, uri);
#ifndef _WIN32_WCE
do {
spin++;
@ -258,12 +333,12 @@ int lws_http_serve(struct lws *wsi, char *uri, const char *origin)
}
sym[len] = '\0';
lwsl_debug("symlink %s -> %s\n", path, sym);
snprintf(path, sizeof(path) - 1, "%s", sym);
lws_snprintf(path, sizeof(path) - 1, "%s", sym);
}
#endif
if ((S_IFMT & st.st_mode) == S_IFDIR) {
lwsl_debug("default filename append to dir\n");
snprintf(path, sizeof(path) - 1, "%s/%s/index.html",
lws_snprintf(path, sizeof(path) - 1, "%s/%s/index.html",
origin, uri);
}
@ -309,8 +384,9 @@ int lws_http_serve(struct lws *wsi, char *uri, const char *origin)
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_ETAG,
(unsigned char *)sym, n, &p, end))
return -1;
#endif
mimetype = get_mimetype(path);
mimetype = get_mimetype(path, m);
if (!mimetype) {
lwsl_err("unknown mimetype for %s", path);
goto bail;
@ -519,34 +595,39 @@ lws_http_action(struct lws *wsi)
lws_access_log(wsi);
wsi->access_log.header_log = lws_malloc(l);
if (wsi->access_log.header_log) {
tmp = localtime(&t);
if (tmp)
strftime(da, sizeof(da), "%d/%b/%Y:%H:%M:%S %z", tmp);
else
strcpy(da, "01/Jan/1970:00:00:00 +0000");
tmp = localtime(&t);
if (tmp)
strftime(da, sizeof(da), "%d/%b/%Y:%H:%M:%S %z", tmp);
else
strcpy(da, "01/Jan/1970:00:00:00 +0000");
pa = lws_get_peer_simple(wsi, ads, sizeof(ads));
if (!pa)
pa = "(unknown)";
pa = lws_get_peer_simple(wsi, ads, sizeof(ads));
if (!pa)
pa = "(unknown)";
if (meth >= 0)
me = method_names[meth];
else
me = "unknown";
if (meth >= 0)
me = method_names[meth];
else
me = "unknown";
snprintf(wsi->access_log.header_log, l,
"%s - - [%s] \"%s %s %s\"",
pa, da, me, uri_ptr,
hver[wsi->u.http.request_version]);
lws_snprintf(wsi->access_log.header_log, l,
"%s - - [%s] \"%s %s %s\"",
pa, da, me, uri_ptr,
hver[wsi->u.http.request_version]);
l = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT);
if (l) {
wsi->access_log.user_agent = lws_malloc(l + 2);
lws_hdr_copy(wsi, wsi->access_log.user_agent,
l + 1, WSI_TOKEN_HTTP_USER_AGENT);
l = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT);
if (l) {
wsi->access_log.user_agent = lws_malloc(l + 2);
if (wsi->access_log.user_agent)
lws_hdr_copy(wsi, wsi->access_log.user_agent,
l + 1, WSI_TOKEN_HTTP_USER_AGENT);
else
lwsl_err("OOM getting user agent\n");
}
wsi->access_log_pending = 1;
}
wsi->access_log_pending = 1;
}
#endif
@ -606,11 +687,11 @@ lws_http_action(struct lws *wsi)
/* > at start indicates deal with by redirect */
if (hit->origin_protocol & 4)
n = snprintf((char *)end, 256, "%s%s",
n = lws_snprintf((char *)end, 256, "%s%s",
oprot[hit->origin_protocol & 1],
hit->origin);
else
n = snprintf((char *)end, 256,
n = lws_snprintf((char *)end, 256,
"https://%s/%s/",
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST),
uri_ptr);
@ -672,7 +753,7 @@ lws_http_action(struct lws *wsi)
wsi->cache_revalidate = hit->cache_revalidate;
wsi->cache_intermediaries = hit->cache_intermediaries;
n = lws_http_serve(wsi, s, hit->origin);
n = lws_http_serve(wsi, s, hit->origin, hit);
if (n) {
/*
* lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
@ -726,11 +807,18 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
struct allocated_headers *ah;
int protocol_len, n, hit;
char protocol_list[128];
char protocol_name[32];
char protocol_name[64];
char *p;
assert(len < 10000000);
assert(wsi->u.hdr.ah);
if (len >= 10000000) {
lwsl_err("%s: assert: len %ld\n", __func__, (long)len);
assert(0);
}
if (!wsi->u.hdr.ah) {
lwsl_err("%s: assert: NULL ah\n", __func__);
assert(0);
}
while (len--) {
wsi->more_rx_waiting = !!len;
@ -762,7 +850,8 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
if (vhost)
wsi->vhost = vhost;
}
} else
lwsl_info("no host\n");
wsi->vhost->trans++;
if (!wsi->conn_stat_done) {
@ -790,7 +879,7 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
goto upgrade_h2c;
}
#endif
lwsl_err("Unknown upgrade\n");
lwsl_info("Unknown upgrade\n");
/* dunno what he wanted to upgrade to */
goto bail_nuke_ah;
}
@ -816,11 +905,11 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
#ifdef LWS_USE_HTTP2
upgrade_h2c:
if (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP2_SETTINGS)) {
lwsl_err("missing http2_settings\n");
lwsl_info("missing http2_settings\n");
goto bail_nuke_ah;
}
lwsl_err("h2c upgrade...\n");
lwsl_info("h2c upgrade...\n");
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP2_SETTINGS);
/* convert the peer's HTTP-Settings */
@ -916,18 +1005,21 @@ upgrade_ws:
if (!hit) {
if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL)) {
lwsl_err("No protocol from \"%s\" supported\n",
lwsl_info("No protocol from \"%s\" supported\n",
protocol_list);
goto bail_nuke_ah;
}
/*
* some clients only have one protocol and
* do not send the protocol list header...
* allow it and match to protocol 0
* allow it and match to the vhost's default
* protocol (which itself defaults to zero)
*/
lwsl_info("defaulting to prot 0 handler\n");
lwsl_info("defaulting to prot handler %d\n",
wsi->vhost->default_protocol_index);
n = 0;
wsi->protocol = &wsi->vhost->protocols[0];
wsi->protocol = &wsi->vhost->protocols[
(int)wsi->vhost->default_protocol_index];
}
/* allocate wsi->user storage */
@ -961,7 +1053,7 @@ upgrade_ws:
break;
default:
lwsl_warn("Unknown client spec version %d\n",
lwsl_info("Unknown client spec version %d\n",
wsi->ietf_spec_revision);
goto bail_nuke_ah;
}
@ -1105,7 +1197,7 @@ lws_create_new_server_wsi(struct lws_vhost *vhost)
new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
/* intialize the instance struct */
/* initialize the instance struct */
new_wsi->state = LWSS_HTTP;
new_wsi->mode = LWSCM_HTTP_SERVING;
@ -1234,6 +1326,8 @@ lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)
*/
if ((context->vhost_list->protocols[0].callback)(new_wsi,
LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, NULL, NULL, 0)) {
/* force us off the timeout list by hand */
lws_set_timeout(new_wsi, NO_PENDING_TIMEOUT, 0);
compatible_close(new_wsi->sock);
lws_free(new_wsi);
return NULL;
@ -1369,6 +1463,10 @@ lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd,
* below to the rx buffer (via lws_header_table_reset()).
*/
wsi->u.hdr.preamble_rx = lws_malloc(len);
if (!wsi->u.hdr.preamble_rx) {
lwsl_err("OOM\n");
goto bail;
}
memcpy(wsi->u.hdr.preamble_rx, readbuf, len);
wsi->u.hdr.preamble_rx_len = len;
@ -1443,7 +1541,7 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
wsi->state == LWSS_HTTP_ISSUING_FILE ||
wsi->state == LWSS_HTTP_HEADERS) {
if (!wsi->u.hdr.ah)
/* no autoservice beacuse we will do it next */
/* no autoservice because we will do it next */
if (lws_header_table_attach(wsi, 0))
goto try_pollout;
@ -1473,7 +1571,12 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
goto try_pollout;
}
}
assert(ah->rxpos != ah->rxlen && ah->rxlen);
if (!(ah->rxpos != ah->rxlen && ah->rxlen)) {
lwsl_err("%s: assert: rxpos %d, rxlen %d\n",
__func__, ah->rxpos, ah->rxlen);
assert(0);
}
/* just ignore incoming if waiting for close */
if (wsi->state != LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
n = lws_read(wsi, ah->rx + ah->rxpos,
@ -1484,6 +1587,8 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
if ( wsi->u.hdr.ah->rxlen)
wsi->u.hdr.ah->rxpos += n;
lwsl_debug("%s: wsi %p: ah read rxpos %d, rxlen %d\n", __func__, wsi, wsi->u.hdr.ah->rxpos, wsi->u.hdr.ah->rxlen);
if (wsi->u.hdr.ah->rxpos == wsi->u.hdr.ah->rxlen &&
(wsi->mode != LWSCM_HTTP_SERVING &&
wsi->mode != LWSCM_HTTP_SERVING_ACCEPTED &&
@ -1585,7 +1690,7 @@ try_pollout:
if (accept_fd < 0) {
if (LWS_ERRNO == LWS_EAGAIN ||
LWS_ERRNO == LWS_EWOULDBLOCK) {
lwsl_err("accept asks to try again\n");
// lwsl_err("accept asks to try again\n");
break;
}
lwsl_err("ERROR on accept: %s\n", strerror(LWS_ERRNO));
@ -1749,6 +1854,7 @@ lws_interpret_incoming_packet(struct lws *wsi, unsigned char **buf, size_t len)
}
if (wsi->u.ws.rx_draining_ext) {
// lwsl_notice("draining with 0\n");
m = lws_rx_sm(wsi, 0);
if (m < 0)
return -1;
@ -1760,9 +1866,13 @@ lws_interpret_incoming_packet(struct lws *wsi, unsigned char **buf, size_t len)
wsi->rxflow_pos++;
/* consume payload bytes efficiently */
if (wsi->lws_rx_parse_state ==
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED)
lws_payload_until_length_exhausted(wsi, buf, &len);
if (
wsi->lws_rx_parse_state ==
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED) {
m = lws_payload_until_length_exhausted(wsi, buf, &len);
if (wsi->rxflow_buffer)
wsi->rxflow_pos += m;
}
/* process the byte */
m = lws_rx_sm(wsi, *(*buf)++);

View file

@ -368,6 +368,8 @@ int lws_rxflow_cache(struct lws *wsi, unsigned char *buf, int n, int len)
/* 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);
if (!wsi->rxflow_buffer)
return -1;
wsi->rxflow_len = len - n;
wsi->rxflow_pos = 0;
memcpy(wsi->rxflow_buffer, buf + n, len - n);
@ -406,7 +408,10 @@ lws_service_adjust_timeout(struct lws_context *context, int timeout_ms, int tsi)
for (n = 0; n < context->max_http_header_pool; n++)
if (pt->ah_pool[n].rxpos != pt->ah_pool[n].rxlen) {
/* any ah with pending rx must be attached to someone */
assert(pt->ah_pool[n].wsi);
if (!pt->ah_pool[n].wsi) {
lwsl_err("%s: assert: no wsi attached to ah\n", __func__);
assert(0);
}
return 0;
}
@ -440,9 +445,10 @@ lws_service_flag_pending(struct lws_context *context, int tsi)
while (wsi) {
pt->fds[wsi->position_in_fds_table].revents |=
pt->fds[wsi->position_in_fds_table].events & LWS_POLLIN;
if (pt->fds[wsi->position_in_fds_table].revents &
LWS_POLLIN)
if (pt->fds[wsi->position_in_fds_table].revents & LWS_POLLIN) {
forced = 1;
break;
}
wsi = wsi->u.ws.rx_draining_ext_list;
}
@ -605,7 +611,10 @@ spin_chunks:
if (wsi->chunked)
return 0;
wsi->u.http.content_remain -= n;
/* if we know the content length, decrement the content remaining */
if (wsi->u.http.content_length > 0)
wsi->u.http.content_remain -= n;
if (wsi->u.http.content_remain || !wsi->u.http.content_length)
return 0;
@ -622,6 +631,17 @@ completed:
}
#endif
static int
lws_is_ws_with_ext(struct lws *wsi)
{
#if defined(LWS_NO_EXTENSIONS)
return 0;
#else
return wsi->state == LWSS_ESTABLISHED &&
!!wsi->count_act_ext;
#endif
}
/**
* lws_service_fd() - Service polled socket with something waiting
* @context: Websocket context
@ -886,9 +906,24 @@ read:
wsi->u.hdr.ah->rxpos;
} else {
if (wsi->mode != LWSCM_HTTP_CLIENT_ACCEPTED) {
/*
* extension may not consume everything (eg, pmd may be constrained
* as to what it can output...) has to go in per-wsi rx buf area.
* Otherwise in large temp serv_buf area.
*/
eff_buf.token = (char *)pt->serv_buf;
if (lws_is_ws_with_ext(wsi)) {
eff_buf.token_len = wsi->u.ws.rx_ubuf_alloc;
} else {
eff_buf.token_len = LWS_MAX_SOCKET_IO_BUF;
}
if (eff_buf.token_len > LWS_MAX_SOCKET_IO_BUF)
eff_buf.token_len = LWS_MAX_SOCKET_IO_BUF;
eff_buf.token_len = lws_ssl_capable_read(wsi,
pt->serv_buf, pending ? pending :
LWS_MAX_SOCKET_IO_BUF);
(unsigned char *)eff_buf.token, pending ? pending :
eff_buf.token_len);
switch (eff_buf.token_len) {
case 0:
lwsl_info("%s: zero length read\n", __func__);
@ -901,8 +936,7 @@ read:
lwsl_info("Closing when error\n");
goto close_and_handled;
}
eff_buf.token = (char *)pt->serv_buf;
// lwsl_notice("Actual RX %d\n", eff_buf.token_len);
}
}
@ -918,7 +952,7 @@ drain:
lws_change_pollfd(wsi, LWS_POLLIN, 0);
/* let user code know, he'll usually ask for writeable
* callback and drain / reenable it there
* callback and drain / re-enable it there
*/
if (user_callback_handle_rxflow(
wsi->protocol->callback,
@ -958,6 +992,8 @@ drain:
* around again it will pick up from where it
* left off.
*/
// lwsl_notice("doing lws_read from pt->serv_buf %p %p for len %d\n", pt->serv_buf, eff_buf.token, (int)eff_buf.token_len);
n = lws_read(wsi, (unsigned char *)eff_buf.token,
eff_buf.token_len);
if (n < 0) {
@ -984,7 +1020,11 @@ drain:
pending = lws_ssl_pending(wsi);
if (pending) {
pending = pending > LWS_MAX_SOCKET_IO_BUF ?
if (lws_is_ws_with_ext(wsi))
pending = pending > wsi->u.ws.rx_ubuf_alloc ?
wsi->u.ws.rx_ubuf_alloc : pending;
else
pending = pending > LWS_MAX_SOCKET_IO_BUF ?
LWS_MAX_SOCKET_IO_BUF : pending;
goto read;
}

View file

@ -38,11 +38,51 @@ lws_ssl_client_bio_create(struct lws *wsi)
#if defined(LWS_USE_MBEDTLS)
#else
struct lws_context *context = wsi->context;
#if defined(CYASSL_SNI_HOST_NAME) || defined(WOLFSSL_SNI_HOST_NAME) || defined(SSL_CTRL_SET_TLSEXT_HOSTNAME)
const char *hostname = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST);
char hostname[128], *p;
#if defined LWS_HAVE_X509_VERIFY_PARAM_set1_host
X509_VERIFY_PARAM *param;
#endif
if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
_WSI_TOKEN_CLIENT_HOST) <= 0) {
lwsl_err("%s: Unable to get hostname\n", __func__);
return -1;
}
/*
* remove any :port part on the hostname... necessary for network
* connection but typical certificates do not contain it
*/
p = hostname;
while (*p) {
if (*p == ':') {
*p = '\0';
break;
}
p++;
}
wsi->ssl = SSL_new(wsi->vhost->ssl_client_ctx);
if (!wsi->ssl) {
lwsl_err("SSL_new failed: %s\n",
ERR_error_string(lws_ssl_get_error(wsi, 0), NULL));
lws_decode_ssl_error();
return -1;
}
#if defined LWS_HAVE_X509_VERIFY_PARAM_set1_host
{
param = SSL_get0_param(wsi->ssl);
/* Enable automatic hostname checks */
X509_VERIFY_PARAM_set_hostflags(param,
X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
X509_VERIFY_PARAM_set1_host(param, hostname, 0);
/* Configure a non-zero callback if desired */
SSL_set_verify(wsi->ssl, SSL_VERIFY_PEER, 0);
}
#endif
#ifndef USE_WOLFSSL
SSL_set_mode(wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
#endif
@ -267,18 +307,17 @@ lws_ssl_client_connect2(struct lws *wsi)
lws_latency_pre(context, wsi);
n = SSL_get_verify_result(wsi->ssl);
lws_latency(context, wsi,
"SSL_get_verify_result LWS_CONNMODE..HANDSHAKE",
n, n > 0);
"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) {
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, sb));
lws_ssl_elaborate_error();
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
return -1;
}
}

View file

@ -194,10 +194,13 @@ lws_ssl_destroy(struct lws_vhost *vhost)
if (!vhost->user_supplied_ssl_ctx && vhost->ssl_client_ctx)
SSL_CTX_free(vhost->ssl_client_ctx);
#if (OPENSSL_VERSION_NUMBER < 0x10100006L)
#if (OPENSSL_VERSION_NUMBER < 0x01000000) || defined(USE_WOLFSSL)
ERR_remove_state(0);
#else
#if (OPENSSL_VERSION_NUMBER >= 0x10100005L)
#if (OPENSSL_VERSION_NUMBER >= 0x10100005L) && \
!defined(LIBRESSL_VERSION_NUMBER) && \
!defined(OPENSSL_IS_BORINGSSL)
ERR_remove_thread_state();
#else
ERR_remove_thread_state(NULL);
@ -208,6 +211,7 @@ lws_ssl_destroy(struct lws_vhost *vhost)
CRYPTO_cleanup_all_ex_data();
#endif
#endif
#endif
}
LWS_VISIBLE void
@ -686,10 +690,13 @@ lws_ssl_context_destroy(struct lws_context *context)
#else
#if defined(LWS_USE_MBEDTLS)
#else
#if (OPENSSL_VERSION_NUMBER < 0x10100006L)
#if (OPENSSL_VERSION_NUMBER < 0x01000000) || defined(USE_WOLFSSL)
ERR_remove_state(0);
#else
#if (OPENSSL_VERSION_NUMBER >= 0x10100005L)
#if (OPENSSL_VERSION_NUMBER >= 0x10100005L) && \
!defined(LIBRESSL_VERSION_NUMBER) && \
!defined(OPENSSL_IS_BORINGSSL)
ERR_remove_thread_state();
#else
ERR_remove_thread_state(NULL);
@ -700,4 +707,5 @@ lws_ssl_context_destroy(struct lws_context *context)
CRYPTO_cleanup_all_ex_data();
#endif
#endif
#endif
}

View file

@ -219,6 +219,25 @@ context. After calling this, any further use of the context is
undefined.
</blockquote>
<hr>
<h2>lws_set_extension_option - </h2>
<i>int</i>
<b>lws_set_extension_option</b>
(<i>struct lws *</i> <b>wsi</b>,
<i>const char *</i> <b>ext_name</b>,
<i>const char *</i> <b>opt_name</b>,
<i>const char *</i> <b>opt_val</b>)
<h3>Arguments</h3>
<dl>
<dt><b>wsi</b>
<dd>websocket connection
<dt><b>ext_name</b>
<dd>name of ext, like "permessage-deflate"
<dt><b>opt_name</b>
<dd>name of option, like "rx_buf_size"
<dt><b>opt_val</b>
<dd>value to set option to
</dl>
<hr>
<h2>lws_return_http_status - Return simple http status</h2>
<i>int</i>
<b>lws_return_http_status</b>
@ -324,6 +343,22 @@ using globals statics in the user code.
<dd>Callback reason index
</dl>
<hr>
<h2>lws_callback_all_protocol_vhost - Callback all connections using the given protocol with the given reason</h2>
<i>int</i>
<b>lws_callback_all_protocol_vhost</b>
(<i>struct lws_vhost *</i> <b>vh</b>,
<i>const struct lws_protocols *</i> <b>protocol</b>,
<i>int</i> <b>reason</b>)
<h3>Arguments</h3>
<dl>
<dt><b>vh</b>
<dd>Vhost whose connections will get callbacks
<dt><b>protocol</b>
<dd>Which protocol to match
<dt><b>reason</b>
<dd>Callback reason index
</dl>
<hr>
<h2>lws_get_socket_fd - returns the socket file descriptor</h2>
<i>int</i>
<b>lws_get_socket_fd</b>
@ -396,12 +431,10 @@ has been created.
<h2>lws_set_proxy - Setups proxy to lws_context.</h2>
<i>int</i>
<b>lws_set_proxy</b>
(<i>struct lws_context *</i> <b>context</b>,
(<i>struct lws_vhost *</i> <b>vhost</b>,
<i>const char *</i> <b>proxy</b>)
<h3>Arguments</h3>
<dl>
<dt><b>context</b>
<dd>pointer to struct lws_context you want set proxy to
<dt><b>proxy</b>
<dd>pointer to c string containing proxy in format address:port
</dl>
@ -512,6 +545,22 @@ This is never set at the start of a writeable callback, but any write
may set it.
</blockquote>
<hr>
<h2>lws_get_context - Allow geting lws_context from a Websocket connection instance</h2>
<i>LWS_EXTERN struct lws_context *</i>
<b>lws_get_context</b>
(<i>const struct lws *</i> <b>wsi</b>)
<h3>Arguments</h3>
<dl>
<dt><b>wsi</b>
<dd>Websocket connection instance
</dl>
<h3>Description</h3>
<blockquote>
<p>
With this function, users can access context in the callback function.
Otherwise users may have to declare context as a global variable.
</blockquote>
<hr>
<h2>lws_parse_uri - </h2>
<i>LWS_EXTERN int</i>
<b>lws_parse_uri</b>
@ -543,8 +592,10 @@ and the leading / on the path is consequently lost
<i>LWS_EXTERN int</i>
<b>lws_cgi</b>
(<i>struct lws *</i> <b>wsi</b>,
<i>char *const *</i> <b>exec_array</b>,
<i>int</i> <b>timeout_secs</b>)
<i>const char *const *</i> <b>exec_array</b>,
<i>int</i> <b>script_uri_path_len</b>,
<i>int</i> <b>timeout_secs</b>,
<i>const struct lws_protocol_vhost_options *</i> <b>mp_cgienv</b>)
<h3>Arguments</h3>
<dl>
<dt><b>wsi</b>
@ -553,6 +604,16 @@ and the leading / on the path is consequently lost
<dd>array of "exec-name" "arg1" ... "argn" NULL
</dl>
<hr>
<h2>lws_cgi_write_split_stdout_headers - </h2>
<i>LWS_EXTERN int</i>
<b>lws_cgi_write_split_stdout_headers</b>
(<i>struct lws *</i> <b>wsi</b>)
<h3>Arguments</h3>
<dl>
<dt><b>wsi</b>
<dd>connection to own the process
</dl>
<hr>
<h2>lws_cgi_kill - </h2>
<i>LWS_EXTERN int</i>
<b>lws_cgi_kill</b>
@ -800,6 +861,25 @@ Many protocols won't care becuse their packets are always small.
<dd>Websocket connection instance to get callback for
</dl>
<hr>
<h2>lws_callback_on_writable_all_protocol_vhost - Request a callback for all connections using the given protocol when it becomes possible to write to each socket without blocking in turn.</h2>
<i>int</i>
<b>lws_callback_on_writable_all_protocol_vhost</b>
(<i>const struct lws_vhost *</i> <b>vhost</b>,
<i>const struct lws_protocols *</i> <b>protocol</b>)
<h3>Arguments</h3>
<dl>
<dt><b>vhost</b>
<dd>Only consider connections on this lws_vhost
<dt><b>protocol</b>
<dd>Protocol whose connections will get callbacks
</dl>
<h3>Description</h3>
<blockquote>
<p>
This calls back connections with the same protocol ON THE SAME
VHOST ONLY.
</blockquote>
<hr>
<h2>lws_callback_on_writable_all_protocol - Request a callback for all connections using the given protocol when it becomes possible to write to each socket without blocking in turn.</h2>
<i>int</i>
<b>lws_callback_on_writable_all_protocol</b>
@ -812,6 +892,12 @@ Many protocols won't care becuse their packets are always small.
<dt><b>protocol</b>
<dd>Protocol whose connections will get callbacks
</dl>
<h3>Description</h3>
<blockquote>
<p>
This calls back any connection using the same protocol on ANY
VHOST.
</blockquote>
<hr>
<h2>lws_http_transaction_completed - wait for new http transaction or close</h2>
<i>int LWS_WARN_UNUSED_RESULT</i>
@ -1615,104 +1701,149 @@ header.
&nbsp; &nbsp; <i>unsigned int</i> <b>fd_limit_per_thread</b>;<br>
&nbsp; &nbsp; <i>unsigned int</i> <b>timeout_secs</b>;<br>
&nbsp; &nbsp; <i>const char *</i> <b>ecdh_curve</b>;<br>
&nbsp; &nbsp; <i>const char *</i> <b>vhost_name</b>;<br>
&nbsp; &nbsp; <i>const char *const *</i> <b>plugin_dirs</b>;<br>
&nbsp; &nbsp; <i>const struct lws_protocol_vhost_options *</i> <b>pvo</b>;<br>
&nbsp; &nbsp; <i>int</i> <b>keepalive_timeout</b>;<br>
&nbsp; &nbsp; <i>const char *</i> <b>log_filepath</b>;<br>
&nbsp; &nbsp; <i>const struct lws_http_mount *</i> <b>mounts</b>;<br>
&nbsp; &nbsp; <i>const char *</i> <b>server_string</b>;<br>
};<br>
<h3>Members</h3>
<dl>
<dt><b>port</b>
<dd>Port to listen on... you can use CONTEXT_PORT_NO_LISTEN to
<dd>VHOST: 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
<dt><b>iface</b>
<dd>NULL to bind the listen socket to all interfaces, or the
<dd>VHOST: NULL to bind the listen socket to all interfaces, or the
interface name, eg, "eth2"
If options specifies LWS_SERVER_OPTION_UNIX_SOCK, this member is
the pathname of a UNIX domain socket. you can use the UNIX domain
sockets in abstract namespace, by prepending an @ symbole to the
socket name.
<dt><b>protocols</b>
<dd>Array of structures listing supported protocols and a protocol-
<dd>VHOST: 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
<dt><b>extensions</b>
<dd>NULL or array of lws_extension structs listing the
<dd>VHOST: NULL or array of lws_extension structs listing the
extensions this context supports. If you configured with
--without-extensions, you should give NULL here.
<dt><b>token_limits</b>
<dd>NULL or struct lws_token_limits pointer which is initialized
<dd>CONTEXT: NULL or struct lws_token_limits pointer which is initialized
with a token length limit for each possible WSI_TOKEN_***
<dt><b>ssl_cert_filepath</b>
<dd>If libwebsockets was compiled to use ssl, and you want
<dd>VHOST: 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
<dt><b>ssl_private_key_filepath</b>
<dd>filepath to private key if wanting SSL mode;
<dd>VHOST: 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
<dt><b>ssl_ca_filepath</b>
<dd>CA certificate filepath or NULL
<dd>VHOST: CA certificate filepath or NULL
<dt><b>ssl_cipher_list</b>
<dd>List of valid ciphers to use (eg,
<dd>VHOST: 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"
<dt><b>http_proxy_address</b>
<dd>If non-NULL, attempts to proxy via the given address.
<dd>VHOST: If non-NULL, attempts to proxy via the given address.
If proxy auth is required, use format
"username:password<tt><b>server</b></tt>:port"
<dt><b>http_proxy_port</b>
<dd>If http_proxy_address was non-NULL, uses this port at
<dd>VHOST: If http_proxy_address was non-NULL, uses this port at
the address
<dt><b>gid</b>
<dd>group id to change to after setting listen socket, or -1.
<dd>CONTEXT: group id to change to after setting listen socket, or -1.
<dt><b>uid</b>
<dd>user id to change to after setting listen socket, or -1.
<dd>CONTEXT: user id to change to after setting listen socket, or -1.
<dt><b>options</b>
<dd>0, or LWS_SERVER_OPTION_... bitfields
<dd>VHOST + CONTEXT: 0, or LWS_SERVER_OPTION_... bitfields
<dt><b>user</b>
<dd>optional user pointer that can be recovered via the context
<dd>CONTEXT: optional user pointer that can be recovered via the context
pointer using lws_context_user
<dt><b>ka_time</b>
<dd>0 for no keepalive, otherwise apply this keepalive timeout to
<dd>CONTEXT: 0 for no keepalive, otherwise apply this keepalive timeout to
all libwebsocket sockets, client or server
<dt><b>ka_probes</b>
<dd>if ka_time was nonzero, after the timeout expires how many
<dd>CONTEXT: 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
<dt><b>ka_interval</b>
<dd>if ka_time was nonzero, how long to wait before each ka_probes
<dd>CONTEXT: if ka_time was nonzero, how long to wait before each ka_probes
attempt
<dt><b>provided_client_ssl_ctx</b>
<dd>If non-null, swap out libwebsockets ssl
<dd>CONTEXT: 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.
<dt><b>provided_client_ssl_ctx</b>
<dd>If non-null, swap out libwebsockets ssl
<dd>CONTEXT: 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.
<dt><b>max_http_header_data</b>
<dd>The max amount of header payload that can be handled
<dd>CONTEXT: The max amount of header payload that can be handled
in an http request (unrecognized header payload is dropped)
<dt><b>max_http_header_pool</b>
<dd>The max number of connections with http headers that
<dd>CONTEXT: The max number of connections with http headers that
can be processed simultaneously (the corresponding memory is
allocated for the lifetime of the context). If the pool is
busy new incoming connections must wait for accept until one
becomes free.
<dt><b>count_threads</b>
<dd>how many contexts to create in an array, 0 = 1
<dd>CONTEXT: how many contexts to create in an array, 0 = 1
<dt><b>fd_limit_per_thread</b>
<dd>nonzero means restrict each service thread to this
<dd>CONTEXT: nonzero means restrict each service thread to this
many fds, 0 means the default which is divide the process fd
limit by the number of threads.
<dt><b>timeout_secs</b>
<dd>various processes involving network roundtrips in the
<dd>VHOST: various processes involving network roundtrips in the
library are protected from hanging forever by timeouts. If
nonzero, this member lets you set the timeout used in seconds.
Otherwise a default timeout is used.
<dt><b>ecdh_curve</b>
<dd>if NULL, defaults to initializing server with "prime256v1"
<dd>VHOST: if NULL, defaults to initializing server with "prime256v1"
<dt><b>vhost_name</b>
<dd>VHOST: name of vhost, must match external DNS name used to
access the site, like "warmcat.com" as it's used to match
<dt><b>plugin_dirs</b>
<dd>CONTEXT: NULL, or NULL-terminated array of directories to
scan for lws protocol plugins at context creation time
<dt><b>pvo</b>
<dd>VHOST: pointer to optional linked list of per-vhost
options made accessible to protocols
<dt><b>keepalive_timeout</b>
<dd>VHOST: (default = 0 = 60s) seconds to allow remote
client to hold on to an idle HTTP/1.1 connection
<dt><b>log_filepath</b>
<dd>VHOST: filepath to append logs to... this is opened before
any dropping of initial privileges
<dt><b>mounts</b>
<dd>VHOST: optional linked list of mounts for this vhost
<dt><b>server_string</b>
<dd>CONTEXT: string used in HTTP headers to identify server
software, if NULL, "libwebsockets".
</dl>
<h3>Description</h3>
<blockquote>
<p>
This is also used to create vhosts.... if LWS_SERVER_OPTION_EXPLICIT_VHOSTS
is not given, then for backwards compatibility one vhost is created at
context-creation time using the info from this struct.
<p>
If LWS_SERVER_OPTION_EXPLICIT_VHOSTS is given, then no vhosts are created
at the same time as the context, they are expected to be created afterwards.
</blockquote>
<h3>Host</h3>
<blockquote>
header and / or SNI name for SSL.
</blockquote>
<hr>
<h2>struct lws_client_connect_info - parameters to connect with when using lws_client_connect_via_info()</h2>
<b>struct lws_client_connect_info</b> {<br>
@ -1728,6 +1859,10 @@ Otherwise a default timeout is used.
&nbsp; &nbsp; <i>void *</i> <b>userdata</b>;<br>
&nbsp; &nbsp; <i>const struct lws_extension *</i> <b>client_exts</b>;<br>
&nbsp; &nbsp; <i>const char *</i> <b>method</b>;<br>
&nbsp; &nbsp; <i>struct lws *</i> <b>parent_wsi</b>;<br>
&nbsp; &nbsp; <i>const char *</i> <b>uri_replace_from</b>;<br>
&nbsp; &nbsp; <i>const char *</i> <b>uri_replace_to</b>;<br>
&nbsp; &nbsp; <i>struct lws_vhost *</i> <b>vhost</b>;<br>
};<br>
<h3>Members</h3>
<dl>
@ -1756,6 +1891,17 @@ Otherwise a default timeout is used.
<dt><b>method</b>
<dd>if non-NULL, do this http method instead of ws[s] upgrade.
use "GET" to be a simple http client connection
<dt><b>parent_wsi</b>
<dd>if another wsi is responsible for this connection, give it here.
this is used to make sure if the parent closes so do any
child connections first.
<dt><b>uri_replace_from</b>
<dd>if non-NULL, when this string is found in URIs in
text/html content-encoding, it's replaced with <tt><b>uri_replace_to</b></tt>
<dt><b>uri_replace_to</b>
<dd>see above
<dt><b>vhost</b>
<dd>vhost to bind to (used to determine related SSL_CTX)
</dl>
<hr>
<h2>lws_close_reason - Set reason and aux data to send with Close packet If you are going to return nonzero from the callback requesting the connection to close, you can optionally call this to set the reason the peer will be told if possible.</h2>
@ -1777,3 +1923,27 @@ use "GET" to be a simple http client connection
<dd>Length of data in <tt><b>buf</b></tt> to send
</dl>
<hr>
<h2>lws_snprintf - </h2>
<i>LWS_EXTERN int</i>
<b>lws_snprintf</b>
(<i>char *</i> <b>str</b>,
<i>size_t</i> <b>size</b>,
<i>const char *</i> <b>format</b>,
<i></i> <b>...</b>)
<h3>Arguments</h3>
<dl>
<dt><b>...</b>
<dd>variable arguments
</dl>
<h3>Description</h3>
<blockquote>
<p>
\param str: destination buffer
\param size: bytes left in destination buffer
\param format: format string
\param ...: args for format
<p>
This lets you correctly truncate buffers by concatenating lengths, if you
reach the limit the reported length doesn't exceed the limit.
</blockquote>
<hr>

View file

@ -1,5 +1,5 @@
Name: libwebsockets
Version: 2.0.0
Version: 2.0.3
Release: 1%{?dist}
Summary: Websocket Server and Client Library
@ -55,7 +55,7 @@ rm -rf $RPM_BUILD_ROOT
/usr/bin/libwebsockets-test-echo
/usr/bin/libwebsockets-test-fraggle
/usr/bin/libwebsockets-test-fuzxy
/%{_libdir}/libwebsockets.so.8
/%{_libdir}/libwebsockets.so.8.1
/%{_libdir}/libwebsockets.so
/%{_libdir}/cmake/libwebsockets/LibwebsocketsConfig.cmake
/%{_libdir}/cmake/libwebsockets/LibwebsocketsConfigVersion.cmake
@ -70,6 +70,15 @@ rm -rf $RPM_BUILD_ROOT
/%{_libdir}/pkgconfig/libwebsockets.pc
%changelog
* Thu Sep 15 2016 Andy Green <andy@warmcat.com> 2.0.3-1
- MAJOR Upstream 2.0.3 release
* Mon Jun 06 2016 Andy Green <andy@warmcat.com> 2.0.2-1
- MINOR Upstream 2.0.2 release
* Thu May 12 2016 Andy Green <andy@warmcat.com> 2.0.1-1
- MINOR Upstream 2.0.1 release
* Thu May 05 2016 Andy Green <andy@warmcat.com> 2.0.0-1
- MAJOR SONAMEBUMP APICHANGES Upstream 2.0.0 release

View file

@ -82,6 +82,7 @@
/* SSL server using ECDH certificate */
#cmakedefine LWS_SSL_SERVER_WITH_ECDH_CERT
#cmakedefine LWS_HAVE_SSL_CTX_set1_param
#cmakedefine LWS_HAVE_X509_VERIFY_PARAM_set1_host
/* CGI apis */
#cmakedefine LWS_WITH_CGI

View file

@ -60,10 +60,13 @@ static const char * const paths_vhosts[] = {
"vhosts[].mounts[].cache-reuse",
"vhosts[].mounts[].cache-revalidate",
"vhosts[].mounts[].cache-intermediaries",
"vhosts[].mounts[].extra-mimetypes.*",
"vhosts[].ws-protocols[].*.*",
"vhosts[].ws-protocols[].*",
"vhosts[].ws-protocols[]",
"vhosts[].keepalive_timeout",
"vhosts[].ciphers",
"vhosts[].ecdh-curve",
};
enum lejp_vhost_paths {
@ -87,10 +90,13 @@ enum lejp_vhost_paths {
LEJPVP_MOUNT_CACHE_REUSE,
LEJPVP_MOUNT_CACHE_REVALIDATE,
LEJPVP_MOUNT_CACHE_INTERMEDIARIES,
LEJPVP_MOUNT_EXTRA_MIMETYPES,
LEJPVP_PROTOCOL_NAME_OPT,
LEJPVP_PROTOCOL_NAME,
LEJPVP_PROTOCOL,
LEJPVP_KEEPALIVE_TIMEOUT,
LEJPVP_CIPHERS,
LEJPVP_ECDH_CURVE,
};
#define MAX_PLUGIN_DIRS 10
@ -104,9 +110,12 @@ struct jpargs {
struct lws_http_mount *head, *last;
struct lws_protocol_vhost_options *pvo;
struct lws_protocol_vhost_options *pvo_em;
struct lws_http_mount m;
const char **plugin_dirs;
int count_plugin_dirs;
unsigned int fresh_mount:1;
};
static void *
@ -172,7 +181,7 @@ lejp_globals_cb(struct lejp_ctx *ctx, char reason)
return 0;
}
a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
a->p += lws_snprintf(a->p, a->end - a->p, "%s", ctx->buf);
return 0;
}
@ -225,8 +234,10 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
}
if (reason == LEJPCB_OBJECT_START &&
ctx->path_match == LEJPVP_MOUNTS + 1)
ctx->path_match == LEJPVP_MOUNTS + 1) {
a->fresh_mount = 1;
memset(&a->m, 0, sizeof(a->m));
}
/* this catches, eg, vhosts[].ws-protocols[].xxx-protocol */
if (reason == LEJPCB_OBJECT_START &&
@ -239,11 +250,11 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
a->pvo->next = a->info->pvo;
a->info->pvo = a->pvo;
a->pvo->name = a->p;
lwsl_err("adding %s\n", a->p);
lwsl_notice(" adding protocol %s\n", a->p);
a->p += n;
a->pvo->value = a->p;
a->pvo->options = NULL;
a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
a->p += lws_snprintf(a->p, a->end - a->p, "%s", ctx->buf);
*(a->p)++ = '\0';
}
@ -279,10 +290,14 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
">https://",
};
if (!a->fresh_mount)
return 0;
if (!a->m.mountpoint || !a->m.origin) {
lwsl_err("mountpoint and origin required\n");
return 1;
}
lwsl_debug("adding mount %s\n", a->m.mountpoint);
m = lwsws_align(a);
memcpy(m, &a->m, sizeof(*m));
if (a->last)
@ -306,6 +321,7 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
a->head = m;
a->last = m;
a->fresh_mount = 0;
}
/* we only match on the prepared path strings */
@ -374,6 +390,12 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
case LEJPVP_KEEPALIVE_TIMEOUT:
a->info->keepalive_timeout = atoi(ctx->buf);
return 0;
case LEJPVP_CIPHERS:
a->info->ssl_cipher_list = a->p;
break;
case LEJPVP_ECDH_CURVE:
a->info->ecdh_curve = a->p;
break;
case LEJPVP_CGI_ENV:
mp_cgienv = lwsws_align(a);
a->p += sizeof(*a->m.cgienv);
@ -386,7 +408,7 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
a->p += n;
mp_cgienv->value = a->p;
mp_cgienv->options = NULL;
a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
a->p += lws_snprintf(a->p, a->end - a->p, "%s", ctx->buf);
*(a->p)++ = '\0';
lwsl_notice(" adding cgi-env '%s' = '%s'\n", mp_cgienv->name,
@ -409,15 +431,28 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
a->p += n;
pvo->value = a->p;
pvo->options = NULL;
a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
*(a->p)++ = '\0';
break;
case LEJPVP_MOUNT_EXTRA_MIMETYPES:
a->pvo_em = lwsws_align(a);
a->p += sizeof(*a->pvo_em);
n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
/* ie, enable this protocol, no options yet */
a->pvo_em->next = a->m.extra_mimetypes;
a->m.extra_mimetypes = a->pvo_em;
a->pvo_em->name = a->p;
lwsl_notice(" adding extra-mimetypes %s -> %s\n", a->p, ctx->buf);
a->p += n;
a->pvo_em->value = a->p;
a->pvo_em->options = NULL;
break;
default:
return 0;
}
a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
a->p += lws_snprintf(a->p, a->end - a->p, "%s", ctx->buf);
*(a->p)++ = '\0';
return 0;
@ -483,7 +518,7 @@ lwsws_get_config_d(void *user, const char *d, const char * const *paths,
}
while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
snprintf(path, sizeof(path) - 1, "%s/%s", d, dent.name);
lws_snprintf(path, sizeof(path) - 1, "%s/%s", d, dent.name);
ret = lwsws_get_config(user, path, paths, count_paths, cb);
if (ret)
goto bail;
@ -523,7 +558,7 @@ lwsws_get_config_d(void *user, const char *d, const char * const *paths,
}
for (i = 0; i < n; i++) {
snprintf(path, sizeof(path) - 1, "%s/%s", d,
lws_snprintf(path, sizeof(path) - 1, "%s/%s", d,
namelist[i]->d_name);
ret = lwsws_get_config(user, path, paths, count_paths, cb);
if (ret) {

View file

@ -149,7 +149,7 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
#endif
if (strlen(in) >= 12 &&
!strncmp(in + strlen(in) - 12, "/postresults", 12)) {
!strncmp((char *)in + strlen(in) - 12, "/postresults", 12)) {
m = sprintf(buf, "<html><body>Form results: '%s'<br>"
"</body></html>", pss->post_string);

View file

@ -115,7 +115,15 @@ lejp_check_path_match(struct lejp_ctx *ctx)
}
ctx->wild[ctx->wildcount++] = p - ctx->path;
q++;
while (*p && *p != '.')
/*
* if * has something after it, match to .
* if ends with *, eat everything.
* This implies match sequences must be ordered like
* x.*.*
* x.*
* if both options are possible
*/
while (*p && (*p != '.' || !*q))
p++;
}
if (*p || *q)
@ -140,7 +148,7 @@ lejp_get_wildcard(struct lejp_ctx *ctx, int wildcard, char *dest, int len)
n = ctx->wild[wildcard];
while (--len && n < ctx->ppos && ctx->path[n] != '.')
while (--len && n < ctx->ppos && (n == ctx->wild[wildcard] || ctx->path[n] != '.'))
*dest++ = ctx->path[n++];
*dest = '\0';

View file

@ -1,3 +1,5 @@
#include "../lib/libwebsockets.h"
struct lejp_ctx;
@ -140,7 +142,7 @@ enum lejp_callbacks {
*
* LEJPCB_OBJECT_END: An object ended
*/
extern char _lejp_callback(struct lejp_ctx *ctx, char reason);
LWS_EXTERN char _lejp_callback(struct lejp_ctx *ctx, char reason);
typedef char (*lejp_callback)(struct lejp_ctx *ctx, char reason);
@ -213,20 +215,20 @@ struct lejp_ctx {
unsigned char wildcount;
};
extern void
LWS_EXTERN void
lejp_construct(struct lejp_ctx *ctx,
char (*callback)(struct lejp_ctx *ctx, char reason), void *user,
const char * const *paths, unsigned char paths_count);
extern void
LWS_EXTERN void
lejp_destruct(struct lejp_ctx *ctx);
extern int
LWS_EXTERN int
lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len);
extern void
LWS_EXTERN void
lejp_change_callback(struct lejp_ctx *ctx,
char (*callback)(struct lejp_ctx *ctx, char reason));
extern int
LWS_EXTERN int
lejp_get_wildcard(struct lejp_ctx *ctx, int wildcard, char *dest, int len);

View file

@ -62,7 +62,7 @@ static struct lws_protocols protocols[] = {
sizeof (struct per_session_data__http), /* per_session_data_size */
0, /* max frame size / rx buffer */
},
{ }
{ NULL, NULL, 0, 0 }
};
void sighandler(int sig)

View file

@ -39,7 +39,7 @@ struct per_session_data__server_status {
int pos;
};
static const struct lws_protocols protocols[];
static const struct lws_protocols protocols[1];
static void
uv_timeout_cb_server_status(uv_timer_t *w

View file

@ -20,6 +20,10 @@
#include "../lib/libwebsockets.h"
#include <time.h>
#include <string.h>
#ifdef WIN32
#include <gettimeofday.h>
#endif
struct per_session_data__lws_status {
struct per_session_data__lws_status *list;
@ -54,7 +58,7 @@ update_status(struct lws *wsi, struct per_session_data__lws_status *pss)
struct tm tm;
#endif
p += snprintf(p, 512, " { %s, \"wsi\":\"%d\", \"conns\":[",
p += lws_snprintf(p, 512, " { %s, \"wsi\":\"%d\", \"conns\":[",
server_info, live_wsi);
/* render the list */
@ -75,7 +79,7 @@ update_status(struct lws *wsi, struct per_session_data__lws_status *pss)
if (subsequent)
*p++ = ',';
subsequent = 1;
p += snprintf(p, sizeof(cache) - (p - start) - 1,
p += lws_snprintf(p, sizeof(cache) - (p - start) - 1,
"{\"peer\":\"%s\",\"time\":\"%s\","
"\"ua\":\"%s\"}",
(*pp)->ip, date, (*pp)->user_agent);
@ -147,6 +151,11 @@ callback_lws_status(struct lws *wsi, enum lws_callback_reasons reason,
}
break;
case LWS_CALLBACK_RECEIVE:
lwsl_notice("pmd test: RX len %d\n", (int)len);
puts(in);
break;
case LWS_CALLBACK_CLOSED:
pp = &list;
while (*pp) {

View file

@ -82,11 +82,16 @@ Release Checklist
- Bump version to 1.6.4
- MINOR fix xyz
6) signed tag
6) update api docs
$ cmake ..
$ cp doc/* ..
7) signed tag
git tag -s vX.Y[.Z]
7) git
8) git
a) push

View file

@ -50,6 +50,14 @@ function check {
fi
fi
if [ "$1" == "0" ] ; then
a="`dd if=$LOG bs=1 skip=$LEN 2>/dev/null |grep "get\ \ =" | tr -s ' ' | cut -d' ' -f4-`"
if [ "$a" != "$2" ] ; then
echo "URL path '$a' not $2"
exit 1
fi
fi
if [ "$1" == "1" ] ; then
a="`dd if=$LOG bs=1 skip=$LEN 2>/dev/null |grep URI\ Arg\ 1\: | tr -s ' ' | cut -d' ' -f5-`"
if [ "$a" != "$2" ] ; then
@ -106,9 +114,10 @@ check 1 "key1=value1"
check
echo
echo "---- ? processing (/test?key1%3d2=value1)"
echo "---- ? processing (/t%3dest?key1%3d2=value1)"
rm -f /tmp/lwscap
echo -e "GET /test?key1%3d2=value1 HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
echo -e "GET /t%3dest?key1%3d2=value1 HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
check 0 "/t=est"
check 1 "key1_2=value1"
check
@ -224,7 +233,7 @@ check default
check
echo
echo "---- nonexistant file"
echo "---- nonexistent file"
rm -f /tmp/lwscap
echo -e "GET /nope HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
check media

View file

@ -271,13 +271,13 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
static struct lws_protocols protocols[] = {
{
"dumb-increment-protocol,fake-nonexistant-protocol",
"dumb-increment-protocol",
callback_dumb_increment,
0,
20,
},
{
"fake-nonexistant-protocol,lws-mirror-protocol",
"lws-mirror-protocol",
callback_lws_mirror,
0,
128,

View file

@ -66,6 +66,11 @@ callback_echo(struct lws *wsi, enum lws_callback_reasons reason, void *user,
#ifndef LWS_NO_SERVER
case LWS_CALLBACK_ESTABLISHED:
pss->index = 0;
pss->len = -1;
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
do_tx:
@ -182,7 +187,7 @@ static struct lws_protocols protocols[] = {
/* first protocol must always be HTTP handler */
{
"", /* name - can be overriden with -e */
"", /* name - can be overridden with -e */
callback_echo,
sizeof(struct per_session_data__echo), /* per_session_data_size */
MAX_ECHO_PAYLOAD,

View file

@ -349,7 +349,7 @@ int main(int argc, char **argv)
struct lws_client_connect_info i;
address = argv[optind];
snprintf(ads_port, sizeof(ads_port), "%s:%u",
lws_snprintf(ads_port, sizeof(ads_port), "%s:%u",
address, port & 65535);
memset(&i, 0, sizeof(i));
i.context = context;

View file

@ -78,7 +78,7 @@ struct ping {
};
struct per_session_data__ping {
uint64_t ping_index;
unsigned long long ping_index;
struct ping ringbuffer[PING_RINGBUFFER_SIZE];
int ringbuffer_head;
@ -110,7 +110,7 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
unsigned char *p;
unsigned long iv;
int match = 0;
uint64_t l;
unsigned long long l;
int shift;
int n;
@ -158,7 +158,7 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
l = 0;
while (shift >= 0) {
l |= ((uint64_t)*p++) << shift;
l |= ((unsigned long long)*p++) << shift;
shift -= 8;
}
@ -396,7 +396,7 @@ int main(int argc, char **argv)
case 'r':
clients = atoi(optarg);
if (clients > MAX_PING_CLIENTS || clients < 1) {
fprintf(stderr, "Max clients supportd = %d\n",
fprintf(stderr, "Max clients supported = %d\n",
MAX_PING_CLIENTS);
return 1;
}
@ -453,7 +453,7 @@ int main(int argc, char **argv)
/* create client websockets using dumb increment protocol */
address = argv[optind];
snprintf(ads_port, sizeof(ads_port), "%s:%u",
lws_snprintf(ads_port, sizeof(ads_port), "%s:%u",
address, port & 65535);
lwsl_notice("Connecting to %s...\n", ads_port);
memset(&i, 0, sizeof(i));

View file

@ -279,7 +279,7 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
LWS_O_RDONLY);
if (pss->fd == LWS_INVALID_FILE) {
lwsl_err("faild to open file %s\n", leaf_path);
lwsl_err("failed to open file %s\n", leaf_path);
return -1;
}
@ -407,6 +407,8 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
lwsl_notice("LWS_CALLBACK_HTTP_BODY: len %d\n", (int)len);
strncpy(pss->post_string, in, sizeof (pss->post_string) -1);
pss->post_string[sizeof(pss->post_string) - 1] = '\0';
if (len < sizeof(pss->post_string) - 1)
pss->post_string[len] = '\0';
break;
case LWS_CALLBACK_HTTP_BODY_COMPLETION:

View file

@ -42,7 +42,7 @@ update_status(struct lws *wsi, struct per_session_data__lws_status *pss)
struct tm tm;
#endif
p += snprintf(p, 512, " { %s, \"wsi\":\"%d\", \"conns\":[",
p += lws_snprintf(p, 512, " { %s, \"wsi\":\"%d\", \"conns\":[",
server_info, live_wsi);
/* render the list */
@ -67,7 +67,7 @@ update_status(struct lws *wsi, struct per_session_data__lws_status *pss)
if (subsequent)
*p++ = ',';
subsequent = 1;
p += snprintf(p, sizeof(cache) - (p - start) - 1,
p += lws_snprintf(p, sizeof(cache) - (p - start) - 1,
"{\"peer\":\"%s\",\"time\":\"%s\","
"\"ua\":\"%s\"}",
(*pp)->ip, date, (*pp)->user_agent);
@ -131,6 +131,11 @@ callback_lws_status(struct lws *wsi, enum lws_callback_reasons reason,
update_status(wsi, pss);
break;
case LWS_CALLBACK_RECEIVE:
lwsl_notice("pmd test: RX len %d\n", (int)len);
puts(in);
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
m = lws_write(wsi, (unsigned char *)cache + LWS_PRE, cache_len,
LWS_WRITE_TEXT);

View file

@ -20,7 +20,9 @@
#include <libwebsockets.h>
#include <getopt.h>
#ifndef WIN32
#include <syslog.h>
#endif
int debug_level = 7;
struct lws_context *context;
@ -81,6 +83,7 @@ static const struct lws_http_mount mount = {
LOCAL_RESOURCE_PATH, /* where to go on the filesystem for that */
"test.html", /* default filename if none given */
NULL,
NULL,
0,
0,
0,
@ -90,6 +93,19 @@ static const struct lws_http_mount mount = {
1, /* strlen("/"), ie length of the mountpoint */
};
/*
* this sets a per-vhost, per-protocol option name:value pair
* the effect is to set this protocol to be the default one for the vhost,
* ie, selected if no Protocol: header is sent with the ws upgrade.
*/
static const struct lws_protocol_vhost_options pvo_opt = {
NULL,
NULL,
"default",
"1"
};
/*
* We must enable the plugin protocols we want into our vhost with a
* linked-list. We can also give the plugin per-vhost options here.
@ -111,7 +127,7 @@ static const struct lws_protocol_vhost_options pvo_1 = {
static const struct lws_protocol_vhost_options pvo = {
&pvo_1,
NULL,
&pvo_opt,
"dumb-increment-protocol",
""
};

File diff suppressed because one or more lines are too long