Compare commits

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

117 commits

Author SHA1 Message Date
Andy Green
da49e47daa LICENSE: clarify exceptions also apply to LGPL self-refernences
via Mike Atamas, Counsel for Epic Games
2017-05-19 10:49:02 +08:00
Silas Parker
3b58cc4617 fix close packet index coding
https://github.com/warmcat/libwebsockets/issues/792
2017-02-14 23:26:43 +08:00
Andy Green
249b2d049b client: protect against possible NULL deref path 2017-01-04 14:38:39 +08:00
Namowen
09d8720034 echo: fix debug build
https://github.com/warmcat/libwebsockets/issues/716#issuecomment-267377856
2016-12-16 07:06:33 +08:00
Andy Green
72d78ed4f8 test-client: fix broken protocol names 2016-12-15 13:34:06 +08:00
Andy Green
31d2a2c6dd client: avoid possible NULL deref on error path
https://github.com/warmcat/libwebsockets/issues/672
2016-12-12 20:41:05 +08:00
Andy Green
386365d4bb ws-server: restrict returned Sec-Websocket-Protocol to the chosen name only
https://libwebsockets.org/pipermail/libwebsockets/2016-November/002948.html
2016-11-29 20:42:29 +08:00
Andy Green
bfffba9e09 client: protect againt losing ah by lws_client_connect_2 2016-11-15 17:01:19 +08:00
Peter Pentchev
fa7acb3b88 Remove the cleanup functions with OpenSSL 1.1. 2016-11-03 05:23:53 +08:00
Andy Green
821a97ac66 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-08 20:15:13 +08:00
Andy Green
98fd8e626f docs: explain lws_write handling of truncated sends better 2016-10-08 18:12:49 +08:00
Andy Green
0650cd0fe7 windows: fix snprintf vs _snprintf 2016-09-27 06:55:58 +08:00
Andy Green
8d8e9bec9b appveyor: get nsis from libwebsockets.org 2016-09-27 06:47:33 +08:00
Andy Green
6ed189965f appveyor: get windows openssl from libwebsockets.org 2016-09-27 06:44:20 +08:00
Andy Green
50b9259cb2 travis: update to trusty for CMake version 2016-09-27 06:42:10 +08:00
Brown, Matthew
1fc082eb7f Added option to build the static library with PIC 2016-09-27 05:36:02 +08:00
Fabrice GILOT
47671fe504 CMakeLists: move config file generation to after LWS_HAVE_OPENSSL_ECDH_H
This is already fixed in v2.0 and master
2016-09-16 09:03:22 +08:00
Andy Green
a085a0ab38 v1.7.9
SONAME to 7.1 because of lws_snprintf()
2016-09-15 02:43:37 +08:00
Andy Green
151aa809a6 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 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.

In 1.7.x, there's no affected code in the library itself, just a couple on instances in the
test app code.
2016-09-15 02:36:22 +08:00
Gadkari Mugdha
8d4c673d02 fix for https connection code 2016-06-13 17:19:55 +08:00
Andy Green
499954a096 client CONNECTION_ERROR also allow in LWSS_CLIENT_UNCONNECTED
Signed-off-by: Andy Green <andy@warmcat.com>
2016-06-07 20:12:10 +08:00
Sterling Jensen
e4ea29bd51 Fix leak caused by undestroyed pthread mutex 2016-05-13 09:43:12 +08:00
Andy Green
6d19521b90 v1.7.8
Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-12 22:15:15 +08:00
Andy Green
60d656fb0f check oom on lws_malloc
Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-12 21:54:29 +08:00
Andy Green
5cd457626a appveyor openssl 1.0.2h
Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-07 09:39:15 +08:00
Andy Green
9a90ed20ac 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:33:07 +08:00
Andy Green
d2feeee1d6 recv revert treating zero as hangup
While checking with ab, I found
commit 30cdb3ac8f
Author: Justin Chen <justinchen00@github.invalid.com>
Date:   Thu Apr 14 21:40:53 2016 +0800

    recv treat zero return as error

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

turned ab performance to crap, reverting it made everything fast again.

recv manpage says there is three ways to get zero returned

1)       When a stream socket peer has performed an orderly shutdown, the return value will be 0  (the  traditional  "end-of-file"
       return).

2)       Datagram  sockets  in  various  domains  (e.g., the UNIX and Internet domains) permit zero-length datagrams.  When such a
       datagram is received, the return value is 0.

3)       The value 0 may also be returned if the requested number of bytes to receive from a stream socket was 0.

we can't just assume it means the peer shut down.

If the peer shut down, then the event loop should get an event on the socket like POLLHUP and deal with it that way.

So the patch mentioned above is simply reverted here.

Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-05 09:23:05 +08:00
Andy Green
f89e90f6a2 client provide user_space on LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER
https://github.com/warmcat/libwebsockets/issues/509

Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-03 21:41:24 +08:00
Andy Green
29458b105d v1.7.7
Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-03 14:29:07 +08:00
Andy Green
381cbf2dc1 client fix reaction to tls failure
https://github.com/warmcat/libwebsockets/issues/508

Signed-off-by: Andy Green <andy@warmcat.com>
2016-05-03 08:08:32 +08:00
Patrick Farrell
c6e497ea48 Add warn_unused_result check, attribute only supported by GCC 3.4 or later
warn_unused_result was introduced in GCC version 3.4.

Change-Id: I6c2cc938d2b868ddfe0889cc41d7fa9d70e1b907
2016-04-30 02:08:11 +08:00
Alexander Bruines
96487167dd Android needs sys/resource.h 2016-04-23 17:19:07 +08:00
Andy Green
449e73433c v1.7.6
Signed-off-by: Andy Green <andy@warmcat.com>
2016-04-23 10:09:33 +08:00
Andy Green
659fefe330 cruft remove sigusr2 handling
Signed-off-by: Andy Green <andy@warmcat.com>
2016-04-22 21:58:38 +08:00
Andy Green
12df0f0acd client account for retries
Signed-off-by: Andy Green <andy@warmcat.com>
2016-04-22 12:40:44 +08:00
hgrundy
461a9068f5 Update libwebsockets.h
Fix for FreeBSD
2016-04-21 17:52:39 +08:00
Justin Chen
edb92ee3c7 recv treat zero return as error
https://github.com/warmcat/libwebsockets/issues/475
2016-04-14 21:42:11 +08:00
Meir Yanovich
c06ea5c7d7 windows snprintf is _snprintf
https://github.com/warmcat/libwebsockets/issues/411#issuecomment-207290650
2016-04-08 16:07:46 +08:00
Galen Ma
1458e7079c android fix rlimit
https://github.com/warmcat/libwebsockets/issues/488
2016-04-08 16:04:58 +08:00
Andy Green
82753d8db6 urldecode forbid malformed
And update attack.sh to confirm the new test cases

Signed-off-by: Andy Green <andy@warmcat.com>
2016-04-07 18:57:28 +08:00
Andy Green
3564e3d5e9 libuv add idle processing to force service where needed
https://github.com/warmcat/libwebsockets/issues/485

Signed-off-by: Andy Green <andy@warmcat.com>
2016-04-07 18:56:40 +08:00
Andy Green
101bd4272a lws_service_adjust_timeout optimize
Make it exit quicker if something is pending

Signed-off-by: Andy Green <andy@warmcat.com>
2016-04-07 18:56:40 +08:00
Andy Green
9ec343d795 revert 622d9f2 ssl pending handcrank
https://github.com/warmcat/libwebsockets/issues/483

Signed-off-by: Andy Green <andy@warmcat.com>
2016-04-05 19:51:55 +08:00
Meir Yanovich
900204e3af win32 libuv build notes 2016-04-05 19:51:43 +08:00
Meir Yanovich
ec81fd460b win32 needs strange strftime args 2016-04-05 19:51:25 +08:00
Meir Yanovich
b1f80eeeb7 libuv win32 fixes 2
https://github.com/warmcat/libwebsockets/issues/411#issuecomment-204284368
2016-04-05 07:31:16 +08:00
Andy Green
934cc80d95 libuv win32 fixes
Signed-off-by: Andy Green <andy@warmcat.com>
2016-04-05 07:31:11 +08:00
Andy Green
8b83266301 uri processing reject paths not starting with slash
https://github.com/warmcat/libwebsockets/issues/481

Return 403 Forbidden if we don't end up with a uri path starting with /

Test server already did this, but this makes it built into the
library.

Signed-off-by: Andy Green <andy@warmcat.com>
2016-04-02 08:03:48 +08:00
Andy Green
e3e89a7241 v1.7.5
Signed-off-by: Andy Green <andy@warmcat.com>
2016-04-01 09:45:57 +08:00
Andy Green
8cd06ca315 test server align rxbuf with permessage deflate rx buf size
Add a test html button that will send 9KB of junk to confirm it

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

permessage-deflate now checks the protocol rx buffer size for being
>=128, if not, permessage-deflate is disabled on that connection.

If it is >=128 but less than the zlib decompress buffer size, the
zlib decompress buffer size for that connection is reduced to the
nearest power of two of the protocol rx buf size.

To test this, dumb_increment is left violating the >= 128 rx buffer
size and permessage-deflte can be seen to be disabled on his
connections in the test html.

Signed-off-by: Andy Green <andy@warmcat.com>
2016-04-01 09:30:09 +08:00
V.Krishn
1ba878cdd5 Fix build with musl libc
Fix building libwebsockets with the musl C libary.

<sys/cdefs.h> is an internal glibc header and should be avoided in user code.

__P() was used for compatibility with some old K&R C compilers, when there were
no prototypes (which were introduced to C with C89). As supporting legacy
non-ANSI compilers is nowadays not necessary anymore get rid of the unnecessary
function prototype using __P().
2016-03-30 06:24:24 +08:00
Andy Green
674609e69a revert cmake remove targets from install path
Signed-off-by: Andy Green <andy@warmcat.com>
2016-03-29 21:49:47 +08:00
Andy Green
b45054ed39 http2 build with alpn capable ssl no debug
Signed-off-by: Andy Green <andy@warmcat.com>
2016-03-25 21:03:01 +08:00
Denis Osvald
3d033984f5 libuv: handle signals only if requested
Signed-off-by: Denis Osvald <denis.osvald@sartura.hr>
2016-03-23 08:04:39 +08:00
Andy Green
18c328a631 v1.7.4
Signed-off-by: Andy Green <andy@warmcat.com>
2016-03-22 09:19:32 +08:00
Andy Green
7dbdb776d9 b64decode correct decode of some strings
https://github.com/warmcat/libwebsockets/issues/467

Signed-off-by: Andy Green <andy@warmcat.com>
2016-03-19 07:48:24 +08:00
Alex Hultman
5594735115 Optimize payload exhaustion
https://github.com/warmcat/libwebsockets/pull/462

AG refactor and do loop unrolling
2016-03-17 09:42:10 +08:00
Andy Green
a09b3cf569 appveyor update 1.0.2g
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-03-17 08:58:12 +08:00
Andy Green
20f18e0b1e clang fixes 1
https://github.com/warmcat/libwebsockets/issues/461

Signed-off-by: Andy Green <andy.green@linaro.org>
2016-03-15 21:24:04 +08:00
bjqiwei
934cc2a8ce client perform WSI_CREATE callback 2016-03-15 16:27:49 +08:00
Joakim Soderberg
d36fa29ac4 ssl ecdh adapt if missing ecdh.h include
https://github.com/warmcat/libwebsockets/issues/457
2016-03-12 08:49:09 +08:00
Andy Green
f192c01a13 client ext hdr skip if no arg
https://github.com/warmcat/libwebsockets/issues/453

Signed-off-by: Andy Green <andy.green@linaro.org>
2016-03-09 23:35:41 +08:00
Andy Green
a4330f313a release checklist specfile install soname
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-03-09 10:48:49 +08:00
Andy Green
ef1f035681 rpm specfile so install list bump
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-03-09 10:45:00 +08:00
Andy Green
ec11114182 libev set foreign loop properly
After gaby64

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

Signed-off-by: Andy Green <andy.green@linaro.org>
2016-03-09 07:47:34 +08:00
Andy Green
dc410bfb78 windows deal with no snprintf
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-03-04 10:58:52 +08:00
Alex Hultman
3eb59c90bf libuv.c: Service fd with LWS_POLLHUP on poll errors 2016-03-02 18:59:55 +08:00
Ondraco
3816a05c4f wince minor adaptations
https://github.com/warmcat/libwebsockets/issues/444
2016-03-01 07:33:56 +08:00
Andy Green
7c8ef84848 v1.7.3
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-29 11:30:07 +08:00
Andy Green
980ca50c39 libuv when in use skip shutdown close phase
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-29 11:11:48 +08:00
Andy Green
ea3cf82769 windows listen for pollhup
After Ondraco

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

Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-29 10:09:15 +08:00
Andy Green
814a7d28c1 test server libuv support status protocol
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-29 01:11:55 +08:00
Andy Green
6671327c8d libuv create 1Hz background timeout check
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-29 01:09:01 +08:00
Andy Green
360c0a8ee4 ah move more_rx_waiting to wsi scope
Originally this was alright in wsi->u.hdr, because ah implied header
processing.  But since we allowed ah to be held across http
keep-alive transactions if we saw we had more header data, it means
we were trying to read this union member out of scope after it had
transitioned.

Moving the more_rx_waiting member to be a 1-bit bifield in the wsi
solves it and lets us check the state any time later at http
transaction completion.

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

Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-28 11:02:42 +08:00
Kamil Rytarowski
e841206653 Don't include <sys/cdefs.h> for NetBSD
We needed it for the BSD symbol to be defined, while __NetBSD__ is defined
with a compiler.

Thanks Andy Green for the initial fix.

Signed-off-by: Kamil Rytarowski <n54@gmx.com>
2016-02-27 10:24:40 +08:00
Andy Green
8df3ef15ab netbsd netinet include
https://github.com/warmcat/libwebsockets/issues/442

Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-27 09:34:48 +08:00
Andy Green
5e091c62a8 force service properly when unconsumed rxbuf in ah
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-26 10:50:04 +08:00
Andy Green
00aaa3aa12 close wsi must do detatch ah flow even if no ah
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-25 21:55:06 +08:00
Andy Green
12369b0c91 improve timeout and ah list comments
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-25 21:54:31 +08:00
Andy Green
d19dec7922 remove ah scan
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-25 21:54:06 +08:00
Andy Green
b55ea5eaed fix missing callback return check
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-25 20:23:45 +08:00
Andy Green
d2a95e0c82 unix privs change group before user
Otherwise we no longer have privs to change the group after doing the user

Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-25 15:15:41 +08:00
Andy Green
314ca966a0 test server log LWS_CALLBACK_HTTP
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-25 15:08:03 +08:00
Andy Green
34266b7861 v1.7.2
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-25 10:11:01 +08:00
Andy Green
7bb600f0c7 lws status fix LWS_PRE
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-25 09:27:02 +08:00
Andy Green
ee2f1ea667 defeat POLLOUT if socket in shutdown wait
After andrejs.hanins@ubnt.com

Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-24 21:32:31 +08:00
Andy Green
3daefb876a ws union member must have actual struct at start not pointer
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-24 19:18:51 +08:00
Andrejs Hanins
b14f842891 client callback closed if not upgraded also for server connection
https://github.com/warmcat/libwebsockets/issues/437
https://github.com/warmcat/libwebsockets/pull/440
2016-02-24 19:18:46 +08:00
Andrejs Hanins
171d29695f client connect must init position_in_fds_table 2016-02-22 23:35:31 +08:00
Andy Green
969212e1dd windows doesnt have localtime_r
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-21 21:41:22 +08:00
Andy Green
b33c72c770 test server status no ssl include time header
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-21 15:12:20 +08:00
Andy Green
4038721baf test server add lws_status
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-21 13:44:07 +08:00
Andy Green
9c6bd66859 LWS_BUILD_HASH improve
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-21 13:43:53 +08:00
Andy Green
466defa72d test html add tabs
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-21 13:43:41 +08:00
Andy Green
228ecc6e56 libwebsockets.org url updates
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-21 10:49:04 +08:00
Sebastian Reimer
00919de84e lwsl stderr sink use formatted time
AG change to use localtime_r for threadsafety and leave old method as fallback
2016-02-21 07:45:03 +08:00
Andy Green
a3f688c189 ssl get rid of build_cert_chain
It's not supported on major distro SSL (Fedora is 1.1) and
libressl (on 2.x) doesn't have it either.

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

Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-21 07:10:55 +08:00
Alex Hultman
1499ab6b33 Stop uv loop in default signal handler, clean-ups 2016-02-20 23:06:32 +08:00
Alex Hultman
a3a0792012 Make sure every handle is closed before destroying the uv loop 2016-02-20 22:50:53 +08:00
Alex Hultman
f2ee57e734 Don't destroy ev/uv loops if they haven't been created yet 2016-02-20 19:35:33 +08:00
Andy Green
2209ceb3f5 v1.7.1
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-20 09:20:36 +08:00
Andy Green
daf7ca4fa9 changelog sync
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-20 09:20:36 +08:00
Andy Green
90a73cc45f attack.sh add check for nonexistant file processing
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-20 08:11:35 +08:00
Andy Green
81c461f5de lws_return_http_status send content length
If we're sending content, we must do so with a
content-length on http/1.1

Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-20 08:04:56 +08:00
Andy Green
78468e08b3 test server example systemd service file
Make sure you have daemonization enabled to use this

make .. -DLWS_WITHOUT_DAEMONIZE=0

Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-20 08:04:53 +08:00
Andy Green
df9be06522 daemonize work under systemd
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-20 08:04:32 +08:00
Andy Green
3310dd19b5 ah pool lifetime use dynamic rxpos
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-20 08:04:09 +08:00
Andy Green
1610223737 test server allow set uid gid from cmdline
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-20 08:03:51 +08:00
Andy Green
4cdf00e04c windows plat correct assert test in lws_poll_listen_fd
After https://github.com/warmcat/libwebsockets/issues/430

Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-18 21:02:34 +08:00
Andy Green
737049b065 test server SSL STS header delivery example
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-18 19:39:24 +08:00
Andy Green
922f68c85e test server allow only best quality ciphers
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-18 19:27:08 +08:00
Andy Green
48a967d4e7 ssl add server ecdh curve init
Using "real" SSL certs requires some init for openssl ECDH
curve.  Add a default curve "prime256v1" and allow overriding it
at context creation time.

Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-18 19:25:46 +08:00
Andy Green
835ad120aa test server allow external certs
Allow the test server to use external certs for testing

libwebsockets-test-server --ssl -C libwebsockets.org.crt -K libwebsockets.org.key -A libwebsockets.org.cer

Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-17 12:00:40 +08:00
Andy Green
59cb88f1fe ssl ecdh check errors properly
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-17 11:10:39 +08:00
Andy Green
1b78f7946f more documentation typos
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-17 07:47:42 +08:00
Peter Pentchev
1c9c278f49 Fix some typos. 2016-02-16 21:48:38 +08:00
Andy Green
7714f71e4e debug reduce noise
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-16 18:47:24 +08:00
51 changed files with 2304 additions and 423 deletions

View file

@ -20,7 +20,9 @@ language: c
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:
coverity_scan:
project:

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 "1")
set(CPACK_PACKAGE_VERSION_MINOR "7")
set(CPACK_PACKAGE_VERSION_PATCH "0")
set(CPACK_PACKAGE_VERSION_PATCH "9")
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 "7")
set(SOVERSION "7.1")
set(CPACK_SOURCE_GENERATOR "TGZ")
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
set(VERSION "${CPACK_PACKAGE_VERSION}")
@ -33,12 +33,23 @@ find_package(Git)
if(GIT_EXECUTABLE)
execute_process(
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMAND "${GIT_EXECUTABLE}" log -n 1 --pretty=%h
COMMAND "${GIT_EXECUTABLE}" describe
OUTPUT_VARIABLE GIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(LWS_BUILD_HASH ${GIT_HASH})
execute_process(
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMAND "whoami"
OUTPUT_VARIABLE GIT_USER
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMAND "hostname"
OUTPUT_VARIABLE GIT_HOST
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(LWS_BUILD_HASH ${GIT_USER}@${GIT_HOST}-${GIT_HASH})
message("Git commit hash: ${LWS_BUILD_HASH}")
endif()
@ -76,6 +87,7 @@ option(LWS_IPV6 "Compile with support for ipv6" OFF)
option(LWS_WITH_HTTP2 "Compile with support for http2" OFF)
option(LWS_MBED3 "Platform is MBED3" OFF)
option(LWS_SSL_SERVER_WITH_ECDH_CERT "Include SSL server use ECDH certificate" OFF)
option(LWS_STATIC_PIC "Build the static version of the library with position-independent code" OFF)
if (DEFINED YOTTA_WEBSOCKETS_VERSION_STRING)
@ -327,6 +339,9 @@ CHECK_FUNCTION_EXISTS(socket LWS_HAVE_SOCKET)
CHECK_FUNCTION_EXISTS(strerror LWS_HAVE_STRERROR)
CHECK_FUNCTION_EXISTS(vfork LWS_HAVE_VFORK)
CHECK_FUNCTION_EXISTS(getifaddrs LWS_HAVE_GETIFADDRS)
CHECK_FUNCTION_EXISTS(snprintf LWS_HAVE_SNPRINTF)
CHECK_FUNCTION_EXISTS(_snprintf LWS_HAVE__SNPRINTF)
CHECK_FUNCTION_EXISTS(_vsnprintf LWS_HAVE__VSNPRINTF)
if (NOT LWS_HAVE_GETIFADDRS)
if (LWS_WITHOUT_BUILTIN_GETIFADDRS)
@ -383,16 +398,6 @@ if (NOT LWS_HAVE_REALLOC)
set(realloc rpl_realloc)
endif()
# Generate the lws_config.h that includes all the public compilation settings.
configure_file(
"${PROJECT_SOURCE_DIR}/lws_config.h.in"
"${PROJECT_BINARY_DIR}/lws_config.h")
# Generate the lws_config.h that includes all the private compilation settings.
configure_file(
"${PROJECT_SOURCE_DIR}/lws_config_private.h.in"
"${PROJECT_BINARY_DIR}/lws_config_private.h")
if (MSVC)
# Turn off stupid microsoft security warnings.
add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE)
@ -539,6 +544,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}
@ -681,6 +689,15 @@ 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})
check_include_file(openssl/ecdh.h LWS_HAVE_OPENSSL_ECDH_H)
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(LWS_WITH_SSL)
if (LWS_WITH_LIBEV)
@ -711,6 +728,18 @@ if (LWS_WITH_LIBUV)
list(APPEND LIB_LIST ${LIBUV_LIBRARIES})
endif()
# Generate the lws_config.h that includes all the public compilation settings.
configure_file(
"${PROJECT_SOURCE_DIR}/lws_config.h.in"
"${PROJECT_BINARY_DIR}/lws_config.h")
# Generate the lws_config.h that includes all the private compilation settings.
configure_file(
"${PROJECT_SOURCE_DIR}/lws_config_private.h.in"
"${PROJECT_BINARY_DIR}/lws_config_private.h")
#
# Platform specific libs.
#
@ -737,7 +766,7 @@ if (NOT LWS_WITHOUT_TESTAPPS)
#
# Helper function for adding a test app.
#
macro(create_test_app TEST_NAME MAIN_SRC S2 S3 S4 S5)
macro(create_test_app TEST_NAME MAIN_SRC S2 S3 S4 S5 S6)
set(TEST_SRCS ${MAIN_SRC})
set(TEST_HDR)
@ -757,6 +786,10 @@ if (NOT LWS_WITHOUT_TESTAPPS)
else()
list(APPEND TEST_SRCS ${S5})
endif()
if ("${S6}" STREQUAL "")
else()
list(APPEND TEST_SRCS ${S6})
endif()
if (WIN32)
list(APPEND TEST_SRCS
${WIN32_HELPERS_PATH}/getopt.c
@ -818,12 +851,14 @@ if (NOT LWS_WITHOUT_TESTAPPS)
"test-server/test-server-http.c"
"test-server/test-server-dumb-increment.c"
"test-server/test-server-mirror.c"
"test-server/test-server-status.c"
"test-server/test-server-echogen.c")
if (UNIX)
create_test_app(test-fuzxy "test-server/fuzxy.c"
""
""
""
""
"")
endif()
if (UNIX AND NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")))
@ -832,24 +867,27 @@ if (NOT LWS_WITHOUT_TESTAPPS)
"test-server/test-server-http.c"
"test-server/test-server-dumb-increment.c"
"test-server/test-server-mirror.c"
"test-server/test-server-status.c"
"test-server/test-server-echogen.c")
endif()
if (UNIX AND NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
if (NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
AND LWS_WITH_LIBEV)
create_test_app(test-server-libev
"test-server/test-server-libev.c"
"test-server/test-server-http.c"
"test-server/test-server-dumb-increment.c"
"test-server/test-server-mirror.c"
"test-server/test-server-status.c"
"test-server/test-server-echogen.c")
endif()
if (UNIX AND NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
if (NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
AND LWS_WITH_LIBUV)
create_test_app(test-server-libuv
"test-server/test-server-libuv.c"
"test-server/test-server-http.c"
"test-server/test-server-dumb-increment.c"
"test-server/test-server-mirror.c"
"test-server/test-server-status.c"
"test-server/test-server-echogen.c")
endif()
endif()
@ -862,6 +900,7 @@ if (NOT LWS_WITHOUT_TESTAPPS)
"test-server/test-server-http.c"
"test-server/test-server-dumb-increment.c"
"test-server/test-server-mirror.c"
"test-server/test-server-status.c"
"test-server/test-server-echogen.c")
# Set defines for this executable only.
set_property(
@ -967,27 +1006,27 @@ if (NOT LWS_WITHOUT_TESTAPPS)
# test-client
#
if (NOT LWS_WITHOUT_TEST_CLIENT)
create_test_app(test-client "test-server/test-client.c" "" "" "" "")
create_test_app(test-client "test-server/test-client.c" "" "" "" "" "")
endif()
#
# test-fraggle
#
if (NOT LWS_WITHOUT_TEST_FRAGGLE)
create_test_app(test-fraggle "test-server/test-fraggle.c" "" "" "" "")
create_test_app(test-fraggle "test-server/test-fraggle.c" "" "" "" "" "")
endif()
#
# test-ping
#
if (NOT LWS_WITHOUT_TEST_PING)
create_test_app(test-ping "test-server/test-ping.c" "" "" "" "")
create_test_app(test-ping "test-server/test-ping.c" "" "" "" "" "")
endif()
#
# test-echo
#
if (NOT LWS_WITHOUT_TEST_ECHO)
create_test_app(test-echo "test-server/test-echo.c" "" "" "" "")
create_test_app(test-echo "test-server/test-echo.c" "" "" "" "" "")
endif()
endif(NOT LWS_WITHOUT_CLIENT)
@ -1139,6 +1178,10 @@ install(FILES
"${PROJECT_BINARY_DIR}/LibwebsocketsConfigVersion.cmake"
DESTINATION "${LWS_INSTALL_CMAKE_DIR}" COMPONENT dev)
# Install exports for the install-tree.
install(EXPORT LibwebsocketsTargets
DESTINATION "${LWS_INSTALL_CMAKE_DIR}" COMPONENT dev)
# build subdir is not part of sources
set(CPACK_SOURCE_IGNORE_FILES $(CPACK_SOURCE_IGNORE_FILES) ".git" "build" "tgz" "tar.gz")
@ -1184,6 +1227,8 @@ message(" LWS_WITH_HTTP2 = ${LWS_WITH_HTTP2}")
message(" LWS_MBED3 = ${LWS_MBED3}")
message(" LWS_SSL_SERVER_WITH_ECDH_CERT = ${LWS_SSL_SERVER_WITH_ECDH_CERT}")
message(" LWS_MAX_SMP = ${LWS_MAX_SMP}")
message(" LWS_HAVE_OPENSSL_ECDH_H = ${LWS_HAVE_OPENSSL_ECDH_H}")
message(" LWS_STATIC_PIC = ${LWS_STATIC_PIC}")
message("---------------------------------------------------------------------")
# These will be available to parent projects including libwebsockets using add_subdirectory()

17
LICENSE
View file

@ -1,7 +1,13 @@
Libwebsockets and included programs are provided under the terms of the GNU
Library General Public License (LGPL) 2.1, with the following exceptions:
1) Static linking of programs with the libwebsockets library does not
1) Any reference, whether in these modifications or in the GNU
Library General Public License 2.1, to this License, these terms, the
GNU Lesser Public License, GNU Library General Public License, LGPL, or
any similar reference shall refer to the GNU Library General Public
License 2.1 as modified by these paragraphs 1) through 4).
2) Static linking of programs with the libwebsockets library does not
constitute a derivative work and does not require the author to provide
source code for the program, use the shared libwebsockets libraries, or
link their program against a user-supplied version of libwebsockets.
@ -10,7 +16,7 @@ If you link the program to a modified version of libwebsockets, then the
changes to libwebsockets must be provided under the terms of the LGPL in
sections 1, 2, and 4.
2) You do not have to provide a copy of the libwebsockets license with
3) You do not have to provide a copy of the libwebsockets license with
programs that are linked to the libwebsockets library, nor do you have to
identify the libwebsockets license in your program or documentation as
required by section 6 of the LGPL.
@ -20,9 +26,9 @@ following example statement can be included in user documentation to
satisfy this requirement:
"[program] is based in part on the work of the libwebsockets project
(http://libwebsockets.org)"
(https://libwebsockets.org)"
3) Some sources included have their own, more liberal licenses, or options
4) Some sources included have their own, more liberal licenses, or options
to get original sources with the liberal terms.
Original liberal license retained
@ -41,7 +47,8 @@ Public Domain (CC-zero) to simplify reuse
- test-server/*.c
- test-server/*.h
------ end of exceptions
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999

View file

@ -137,6 +137,15 @@ Building on Windows (Visual Studio)
4. Now you should have a generated Visual Studio Solution in your
`<path to src>/build` directory, which can be used to build.
5. Some additional deps may be needed
- iphlpapi.lib
- psapi.lib
- userenv.lib
6. If you're using libuv, you must make sure to compile libuv with the same multithread-dll / Mtd attributes as libwebsockets itself
Building on Windows (MinGW)
---------------------------
1. Install MinGW: http://sourceforge.net/projects/mingw/files

View file

@ -326,7 +326,7 @@ cmake .. -DLWS_SSL_SERVER_WITH_ECDH_CERT=1
**and** the info->options flag
LWS_SERVER_OPTION_SSL_ECD
LWS_SERVER_OPTION_SSL_ECDH
to build in support and select it at runtime.

View file

@ -8,16 +8,21 @@ libwebsockets
This is the libwebsockets C library for lightweight websocket clients and
servers. For support, visit
http://libwebsockets.org
https://libwebsockets.org
https://github.com/warmcat/libwebsockets
and consider joining the project mailing list at
http://ml.libwebsockets.org/mailman/listinfo/libwebsockets
https://libwebsockets.org/mailman/listinfo/libwebsockets
You can get the latest version of the library from git
| News |
------
| We have updated https://libwebsockets.org, if you would like your project using lws featured in the image carousel, send an image, project URL and brief summary to andy@warmcat.com |
You can get the latest version of the library from git:
- http://git.libwebsockets.org
- https://github.com/warmcat/libwebsockets
- https://libwebsockets.org/git
for more information:

View file

@ -78,6 +78,16 @@ same time as drawing random circles in the mirror protocol;
if you connect to the test server using a browser at the
same time you will be able to see the circles being drawn.
The test client supports SSL too, use
```bash
$ libwebsockets-test-client localhost --ssl -s
```
the -s tells it to accept the default selfsigned cert from the server,
otherwise it will strictly fail the connection if there is no CA cert to
validate the server's certificate.
Testing simple echo
-------------------

View file

@ -14,9 +14,10 @@ environment:
- LWS_METHOD: nossl
CMAKE_ARGS: -DLWS_WITH_SSL=OFF
install:
- appveyor DownloadFile https://slproweb.com/download/Win32OpenSSL-1_0_2f.exe
- Win32OpenSSL-1_0_2f.exe /silent /verysilent /sp- /suppressmsgboxes
- cinst -y nsis
- appveyor DownloadFile https://libwebsockets.org:444/Win32OpenSSL-1_0_2h.exe
- Win32OpenSSL-1_0_2h.exe /silent /verysilent /sp- /suppressmsgboxes
- appveyor DownloadFile https://libwebsockets.org:444/nsis-3.0rc1-setup.exe
- cmd /c start /wait nsis-3.0rc1-setup.exe /S /D=C:\nsis
- SET PATH=C:\Program Files\NSIS\;C:\Program Files (x86)\NSIS\;%PATH%
build:

211
changelog
View file

@ -1,6 +1,211 @@
Changelog
---------
v1.7.9
======
NB: lws_snprintf() added, but only used in library and test apps
SONAME bump to 7.1
Fixes:
1) Fix leak caused by undestroyed pthread mutex
2) Add CLIENT_CONNECTION_ERROR callbacks for more failure paths
3) Fix for client close to callback on one error path
4) lws_snprintf() needed in a couple of test apps (1.7.x lib doesn't use it
for aggregated buffer truncation)
v1.7.8
======
NB: No API change since v1.7.0
Fixes:
1) MINOR: user_space arg was mistakenly NULL on LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER
2) MINOR: treating recv() returning 0 as peer close destroyed throughput on ab
tests, reverted
3) MINOR: %3d on URL part was always turned to _... this should only happen in
?na%3dme=x part of the URL
4) MINOR: some malloc escaped check for NULL / OOM
v1.7.7
======
NB: No API change since v1.7.0
Fixes:
1) MINOR: Android add needed include file
2) MINOR: Allow build on GCC < 3.4
3) MINOR: Fix client problems recovering cleanly from SSL negotiation failure
v1.7.6
======
NB: No API change since v1.7.0
Fixes
-----
1) MINOR: libuv-specific fixes
2) MINOR: urldecode forbids malformed %xx in the library
3) MINOR: small fixes for Android and Windows
4) MINOR: handle 0 read() as closed connection
v1.7.5
======
NB: No API change since v1.7.0
Fixes
-----
1) MINOR: fix build with musl C library
2) MINOR: libuv handle signals only if requested
3) MINOR: Fix compile warning if HTTP2 + RELEASE + ALPN-capable SSL
4) MINOR: produce and package
%{_libdir}/cmake/libwebsockets/LibwebsocketsTargets.cmake
5) MAJOR: make permessage-deflate enforce protocol rx buffer size requirement
v1.7.4
======
NB: No API change since v1.7.0
Fixes
-----
1) MINOR: don't send ext hdr if no exts to discuss
2) MINOR: libuv + libev small fixes
3) MINOR: some windows build environments have no snprintf
4) MINOR: cmake adapts better to ecdh.h cmake situation
5) MINOR: client missed WSI_CREATE callback
6) MINOR: base64 decode api worked fine for all ws key handling, however
it was broken for some general decode if user code wanted to use it.
7) MINOR: add optimized parsing path for bulk incoming ws data
v1.7.3
======
NB: No API change since v1.7.0
Fixes
-----
1) MAJOR connections on ah waiting list that closed did not get removed from
the waiting list...
2) MAJOR since we added the ability to hold an ah across http keepalive
transactions where more headers had already arrived, we broke the ability
to tell if more headers had arrived. Result was if the browser didn't
close the keepalive, we retained ah for the lifetime of the keepalive,
using up the pool.
3) MAJOR windows-only-POLLHUP was not coming
4) Fix build on NetBSD
v1.7.2
======
NB: No API change since v1.7.0
Fixes
-----
1) libuv one-per-session valgrind leak fixed
2) MINOR An error about hdr struct in _lws_ws_related is corrected, it's not
known to affect anything added until after it was fixed
3) MINOR During the close shutdown wait state introduced at v1.7, if something
requests callback on writeable for the socket it will busywait until the
socket closes
4) MINOR update URLs in test html for libwebsockets.org https STS changes
Changes
-------
1) test server html is updated with tabs and a new live server monitoring
feature. Input sanitization added to the js.
v1.7.1
======
NB: No API change since v1.7.0
Fixes
-----
1) MAJOR (Windows-only) fix assert firing
2) MAJOR http:/1.1 connections handled by lws_return_http_status() did not
get sent a content-length resulting in the link hanging until the peer closed
it. attack.sh updated to add a test for this.
Changes
-------
1) MINOR test-server gained some new switches
-C <file> use external SSL cert file
-K <file> use external SSL key file
-A <file> use external SSL CA cert file
-u <uid> set effective uid
-g <gid> set effective gid
together you can use them like this to have the test-server work with the
usual purchased SSL certs from an official CA.
--ssl -C your.crt -K your.key -A your.cer -u 99 -g 99
2) MINOR the OpenSSL magic to setup ECDH cipher usage is implemented in the
library, and the ciphers restricted to use ECDH only.
Using this, the lws test server can score an A at SSLLABS test
3) MINOR STS (SSL always) header is added to the test server if you use --ssl. With
that, we score A+ at SSLLABS test
4) MINOR daemonize function (disabled at cmake by default) is updated to work
with systemd
5) MINOR example systemd .service file now provided for test server
(not installed by default)
v1.7.0
======
@ -164,11 +369,11 @@ cmake .. -DLWS_SSL_SERVER_WITH_ECDH_CERT=1
**and** the info->options flag
LWS_SERVER_OPTION_SSL_ECD
LWS_SERVER_OPTION_SSL_ECDH
to build in support and select it at runtime.
6) There's a new api lws_parse_uri() that simplies chopping up
6) There's a new api lws_parse_uri() that simplifies chopping up
https://xxx:yyy/zzz uris into parts nicely. The test client now uses this
to allow proper uris as well as the old address style.
@ -299,7 +504,7 @@ lws_ev_initloop (was lws_initloop) gets an extra argument for the
thread service index (use 0 if you will just have 1 service thread).
LWS_VISIBLE LWS_EXTERN int
lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi);
lws_ev_initloop(struct lws_context *context, ev_loop_t *loop, int tsi);
v1.6.0-chrome48-firefox42

View file

@ -99,7 +99,7 @@ LWS_VISIBLE int
lws_b64_decode_string(const char *in, char *out, int out_size)
{
int len;
int i;
int i, c;
int done = 0;
unsigned char v;
unsigned char quad[4];
@ -110,19 +110,19 @@ lws_b64_decode_string(const char *in, char *out, int out_size)
for (i = 0; i < 4 && *in; i++) {
v = 0;
c = 0;
while (*in && !v) {
v = *in++;
c = v = *in++;
v = (v < 43 || v > 122) ? 0 : decode[v - 43];
if (v)
v = (v == '$') ? 0 : v - 61;
if (*in) {
len++;
if (v)
quad[i] = v - 1;
} else
quad[i] = 0;
}
if (c) {
len++;
if (v)
quad[i] = v - 1;
} else
quad[i] = 0;
}
if (out_size < (done + len - 1))
@ -147,6 +147,7 @@ lws_b64_decode_string(const char *in, char *out, int out_size)
return done;
}
#if 0
int
lws_b64_selftest(void)
{
@ -183,3 +184,4 @@ lws_b64_selftest(void)
return 0;
}
#endif

View file

@ -19,6 +19,11 @@ 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 (context->http_proxy_port) {
@ -171,7 +176,11 @@ lws_client_connect_2(struct lws *wsi)
* past here, we can't simply free the structs as error
* handling as oom4 does. We have to run the whole close flow.
*/
if (!wsi->protocol)
wsi->protocol = &wsi->context->protocols[0];
wsi->protocol->callback(wsi, LWS_CALLBACK_WSI_CREATE,
wsi->user_space, NULL, 0);
lws_set_timeout(wsi,
PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
AWAITING_TIMEOUT);
@ -302,8 +311,14 @@ 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;
if (wsi->u.hdr.ah)
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
lws_header_table_detach(wsi);
/* take care that we might be inserted in fds already */
if (wsi->position_in_fds_table != -1)
goto failed;
lws_free(wsi);
return NULL;
@ -394,6 +409,7 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
wsi->state = LWSS_CLIENT_UNCONNECTED;
wsi->protocol = NULL;
wsi->pending_timeout = NO_PENDING_TIMEOUT;
wsi->position_in_fds_table = -1;
#ifdef LWS_OPENSSL_SUPPORT
wsi->use_ssl = i->ssl_connection;

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

@ -264,7 +264,7 @@ some_wait:
if (n != SSL_ERROR_NONE) {
lwsl_err("SSL connect error %lu: %s\n",
n, ERR_error_string(n, sb));
return 0;
goto bail3;
}
}
} else
@ -318,7 +318,7 @@ some_wait:
if (n != SSL_ERROR_NONE) {
lwsl_err("SSL connect error %lu: %s\n",
n, ERR_error_string(n, sb));
return 0;
goto bail3;
}
}
}
@ -343,7 +343,7 @@ some_wait:
n, ERR_error_string(n, sb));
lws_close_free_wsi(wsi,
LWS_CLOSE_STATUS_NOSTATUS);
return 0;
return -1;
}
}
#endif /* USE_WOLFSSL */
@ -462,6 +462,10 @@ some_wait:
bail3:
lwsl_info("closing conn at LWS_CONNMODE...SERVER_REPLY\n");
wsi->context->protocols[0].callback(wsi,
LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
wsi->user_space, NULL, 0);
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
return -1;
@ -640,7 +644,7 @@ check_extensions:
/* instantiate the accepted extensions */
if (!lws_hdr_total_length(wsi, WSI_TOKEN_EXTENSIONS)) {
lwsl_ext("no client extenstions allowed by server\n");
lwsl_ext("no client extensions allowed by server\n");
goto check_accept;
}
@ -707,10 +711,14 @@ check_extensions:
/* allow him to construct his ext instance */
ext->callback(lws_get_context(wsi), ext, wsi,
if (ext->callback(lws_get_context(wsi), ext, wsi,
LWS_EXT_CB_CLIENT_CONSTRUCT,
(void *)&wsi->act_ext_user[wsi->count_act_ext],
(void *)&opts, 0);
(void *)&opts, 0)) {
lwsl_notice(" ext %s failed construction\n", ext_name);
ext++;
continue;
}
/*
* allow the user code to override ext defaults if it
@ -956,7 +964,6 @@ lws_generate_client_handshake(struct lws *wsi, char *pkt)
/* tell the server what extensions we could support */
p += sprintf(p, "Sec-WebSocket-Extensions: ");
#ifndef LWS_NO_EXTENSIONS
ext = context->extensions;
while (ext && ext->callback) {
@ -988,13 +995,17 @@ lws_generate_client_handshake(struct lws *wsi, char *pkt)
if (ext_count)
*p++ = ',';
else
p += sprintf(p, "Sec-WebSocket-Extensions: ");
p += sprintf(p, "%s", ext->client_offer);
ext_count++;
ext++;
}
if (ext_count)
p += sprintf(p, "\x0d\x0a");
#endif
p += sprintf(p, "\x0d\x0a");
if (wsi->ietf_spec_revision)
p += sprintf(p, "Sec-WebSocket-Version: %d\x0d\x0a",
@ -1003,7 +1014,7 @@ lws_generate_client_handshake(struct lws *wsi, char *pkt)
/* give userland a chance to append, eg, cookies */
context->protocols[0].callback(wsi, LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
NULL, &p, (pkt + LWS_MAX_SOCKET_IO_BUF) - p - 12);
wsi->user_space, &p, (pkt + LWS_MAX_SOCKET_IO_BUF) - p - 12);
p += sprintf(p, "\x0d\x0a");

View file

@ -79,6 +79,10 @@ lws_create_context(struct lws_context_creation_info *info)
#endif
char *p;
int n, m;
#if defined(__ANDROID__)
struct rlimit rt;
#endif
lwsl_notice("Initial logging level %d\n", log_level);
lwsl_notice("Libwebsockets version: %s\n", library_version);
@ -115,7 +119,16 @@ lws_create_context(struct lws_context_creation_info *info)
lwsl_notice(" Started with daemon pid %d\n", pid_daemon);
}
#endif
context->max_fds = getdtablesize();
#if defined(__ANDROID__)
n = getrlimit ( RLIMIT_NOFILE,&rt);
if (-1 == n) {
lwsl_err("Get RLIMIT_NOFILE failed!\n");
return NULL;
}
context->max_fds = rt.rlim_cur;
#else
context->max_fds = getdtablesize();
#endif
if (info->count_threads)
context->count_threads = info->count_threads;
@ -162,6 +175,8 @@ lws_create_context(struct lws_context_creation_info *info)
return NULL;
}
context->pt[n].context = context;
context->pt[n].tid = n;
context->pt[n].http_header_data = lws_malloc(context->max_http_header_data *
context->max_http_header_pool);
if (!context->pt[n].http_header_data)
@ -372,6 +387,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

View file

@ -41,7 +41,7 @@ child_handler(int signum)
switch (signum) {
case SIGALRM: /* timed out daemonizing */
exit(1);
exit(0);
break;
case SIGUSR1: /* positive confirmation we daemonized well */
@ -52,7 +52,7 @@ child_handler(int signum)
fprintf(stderr,
"unable to create lock file %s, code=%d (%s)\n",
lock_path, errno, strerror(errno));
exit(1);
exit(5);
}
len = sprintf(sz, "%u", pid_daemon);
sent = write(fd, sz, len);
@ -62,10 +62,11 @@ child_handler(int signum)
lock_path, errno, strerror(errno));
close(fd);
exit(!!(sent == len));
exit(0);
//!!(sent == len));
case SIGCHLD: /* daemonization failed */
exit(1);
exit(6);
break;
}
}
@ -98,8 +99,8 @@ lws_daemonize(const char *_lock_path)
char buf[10];
/* already a daemon */
if (getppid() == 1)
return 1;
// if (getppid() == 1)
// return 1;
fd = open(_lock_path, O_RDONLY);
if (fd >= 0) {
@ -138,7 +139,7 @@ lws_daemonize(const char *_lock_path)
if (pid_daemon < 0) {
fprintf(stderr, "unable to fork daemon, code=%d (%s)",
errno, strerror(errno));
exit(1);
exit(9);
}
/* If we got a good PID, then we can exit the parent process. */
@ -153,7 +154,7 @@ lws_daemonize(const char *_lock_path)
pause();
/* should not be reachable */
exit(1);
exit(0);
}
/* At this point we are executing as the child process */
@ -176,7 +177,7 @@ lws_daemonize(const char *_lock_path)
fprintf(stderr,
"unable to create a new session, code %d (%s)",
errno, strerror(errno));
exit(1);
exit(2);
}
/*
@ -187,7 +188,7 @@ lws_daemonize(const char *_lock_path)
fprintf(stderr,
"unable to change directory to %s, code %d (%s)",
"/", errno, strerror(errno));
exit(1);
exit(3);
}
/* Redirect standard files to /dev/null */

View file

@ -75,6 +75,17 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
case LWS_EXT_CB_CLIENT_CONSTRUCT:
case LWS_EXT_CB_CONSTRUCT:
n = LWS_MAX_SOCKET_IO_BUF;
if (wsi->protocol->rx_buffer_size)
n = wsi->protocol->rx_buffer_size;
if (n < 128) {
lwsl_err(" permessage-deflate requires the protocol (%s) to have an RX buffer >= 128\n",
wsi->protocol->name);
return -1;
}
/* fill in **user */
priv = lws_zalloc(sizeof(*priv));
*((void **)user) = priv;
@ -102,6 +113,23 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
priv->args[PMD_TX_BUF_PWR2] = 10; /* ie, 1024 */
priv->args[PMD_COMP_LEVEL] = 1;
priv->args[PMD_MEM_LEVEL] = 8;
/* cap the RX buf at the nearest power of 2 to protocol rx buf */
n = LWS_MAX_SOCKET_IO_BUF;
if (wsi->protocol->rx_buffer_size)
n = wsi->protocol->rx_buffer_size;
extra = 7;
while (n >= 1 << (extra + 1))
extra++;
if (extra < priv->args[PMD_RX_BUF_PWR2]) {
priv->args[PMD_RX_BUF_PWR2] = extra;
lwsl_err(" Capping pmd rx to %d\n", 1 << extra);
}
lwsl_err(" ok\n");
break;
case LWS_EXT_CB_DESTROY:
@ -197,7 +225,7 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
* If we did not already send in the 00 00 FF FF, and he's
* out of input, he did not EXACTLY fill the output buffer
* (which is ambiguous and we will force it to go around
* again by witholding a byte), and he's otherwise working on
* again by withholding a byte), and he's otherwise working on
* being a FIN fragment, then do the FIN message processing
* of faking up the 00 00 FF FF that the sender stripped.
*/
@ -232,7 +260,7 @@ lws_extension_callback_pm_deflate(struct lws_context *context,
* more in the pipeline.
*
* So to work around that safely, if it used all output space
* exactly, we ALWAYS say there is more coming and we withold
* exactly, we ALWAYS say there is more coming and we withhold
* the last byte of the buffer to guarantee that is true.
*
* That still leaves us at least one byte to finish with a FIN

View file

@ -173,18 +173,23 @@ lws_add_http_header_status(struct lws *wsi, unsigned int code,
* consistently
*/
LWS_VISIBLE int
lws_return_http_status(struct lws *wsi, unsigned int code, const char *html_body)
lws_return_http_status(struct lws *wsi, unsigned int code,
const char *html_body)
{
int n, m;
struct lws_context *context = lws_get_context(wsi);
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
unsigned char *p = pt->serv_buf + LWS_PRE;
unsigned char *start = p;
unsigned char *start = p, *body = p + 512;
unsigned char *end = p + LWS_MAX_SOCKET_IO_BUF - LWS_PRE;
int n, m, len;
char slen[20];
if (!html_body)
html_body = "";
len = sprintf((char *)body, "<html><body><h1>%u</h1>%s</body></html>",
code, html_body);
if (lws_add_http_header_status(wsi, code, &p, end))
return 1;
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER,
@ -195,6 +200,12 @@ lws_return_http_status(struct lws *wsi, unsigned int code, const char *html_body
(unsigned char *)"text/html", 9,
&p, end))
return 1;
n = sprintf(slen, "%d", len);
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
(unsigned char *)slen, n,
&p, end))
return 1;
if (lws_finalize_http_header(wsi, &p, end))
return 1;
@ -202,9 +213,7 @@ lws_return_http_status(struct lws *wsi, unsigned int code, const char *html_body
if (m != (int)(p - start))
return 1;
n = sprintf((char *)start, "<html><body><h1>%u</h1>%s</body></html>",
code, html_body);
m = lws_write(wsi, start, n, LWS_WRITE_HTTP);
m = lws_write(wsi, body, len, LWS_WRITE_HTTP);
return m != n;
}

View file

@ -84,6 +84,8 @@ lws_ev_initloop(struct lws_context *context, struct ev_loop *loop, int tsi)
if (!loop)
loop = ev_loop_new(0);
else
context->pt[tsi].ev_loop_foreign = 1;
context->pt[tsi].io_loop_ev = loop;
@ -138,6 +140,9 @@ lws_libev_destroyloop(struct lws_context *context, int tsi)
if (!(context->options & LWS_SERVER_OPTION_LIBEV))
return;
if (!pt->io_loop_ev)
return;
ev_io_stop(pt->io_loop_ev, &pt->w_accept.ev_watcher);
if (context->use_ev_sigint)
ev_signal_stop(pt->io_loop_ev,

View file

@ -31,34 +31,76 @@ lws_feature_status_libuv(struct lws_context_creation_info *info)
}
static void
lws_accept_cb(uv_poll_t *watcher, int status, int revents)
lws_uv_idle(uv_idle_t *handle)
{
struct lws_context_per_thread *pt = container_of(handle,
struct lws_context_per_thread, uv_idle);
lwsl_debug("%s\n", __func__);
/*
* is there anybody with pending stuff that needs service forcing?
*/
if (!lws_service_adjust_timeout(pt->context, 1, pt->tid)) {
/* -1 timeout means just do forced service */
lws_plat_service_tsi(pt->context, -1, pt->tid);
/* still somebody left who wants forced service? */
if (!lws_service_adjust_timeout(pt->context, 1, pt->tid))
/* yes... come back again later */
return;
}
/* there is nobody who needs service forcing, shut down idle */
uv_idle_stop(handle);
}
static void
lws_io_cb(uv_poll_t *watcher, int status, int revents)
{
struct lws_io_watcher *lws_io = container_of(watcher,
struct lws_io_watcher, uv_watcher);
struct lws *wsi = container_of(lws_io, struct lws, w_read);
struct lws_context *context = lws_io->context;
struct lws_pollfd eventfd;
if (status < 0)
return;
#if defined(WIN32) || defined(_WIN32)
eventfd.fd = watcher->socket;
#else
eventfd.fd = watcher->io_watcher.fd;
#endif
eventfd.events = 0;
eventfd.revents = 0;//EV_NONE;
if (revents & UV_READABLE) {
eventfd.events |= LWS_POLLIN;
eventfd.revents |= LWS_POLLIN;
}
if (revents & UV_WRITABLE) {
eventfd.events |= LWS_POLLOUT;
eventfd.revents |= LWS_POLLOUT;
eventfd.revents = 0;
if (status < 0) {
/* at this point status will be an UV error, like UV_EBADF,
we treat all errors as LWS_POLLHUP */
/* you might want to return; instead of servicing the fd in some cases */
if (status == UV_EAGAIN)
return;
eventfd.events |= LWS_POLLHUP;
eventfd.revents |= LWS_POLLHUP;
} else {
if (revents & UV_READABLE) {
eventfd.events |= LWS_POLLIN;
eventfd.revents |= LWS_POLLIN;
}
if (revents & UV_WRITABLE) {
eventfd.events |= LWS_POLLOUT;
eventfd.revents |= LWS_POLLOUT;
}
}
lws_service_fd(context, &eventfd);
uv_idle_start(&context->pt[(int)wsi->tsi].uv_idle, lws_uv_idle);
}
LWS_VISIBLE void
lws_uv_sigint_cb(uv_loop_t *loop, uv_signal_t *watcher, int revents)
lws_uv_sigint_cb(uv_loop_t *loop, uv_signal_t *watcher, int signum)
{
//ev_break(loop, EVBREAK_ALL);
lwsl_info("internal signal handler caught signal %d\n", signum);
lws_libuv_stop(watcher->data);
}
LWS_VISIBLE int
@ -74,8 +116,31 @@ lws_uv_sigint_cfg(struct lws_context *context, int use_uv_sigint,
return 0;
}
static void
lws_uv_timeout_cb(uv_timer_t *timer)
{
struct lws_context_per_thread *pt = container_of(timer,
struct lws_context_per_thread, uv_timeout_watcher);
lwsl_debug("%s\n", __func__);
lws_service_fd_tsi(pt->context, NULL, pt->tid);
}
static const int sigs[] = { SIGINT, SIGTERM, SIGSEGV, SIGFPE };
struct lws_uv_sigint_ctx {
struct lws_context *context;
lws_uv_signal_cb_t *cb;
};
static void lws_uv_sigint_cb_wrapper(uv_signal_t *signal, int signum)
{
struct lws_uv_sigint_ctx *p = signal->data;
uv_signal_t signal_fwd = *signal;
signal_fwd.data = p->context;
p->cb(signal->loop, &signal_fwd, signum);
}
LWS_VISIBLE int
lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, uv_signal_cb cb,
int tsi)
@ -86,17 +151,28 @@ lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, uv_signal_cb cb,
if (!loop) {
loop = lws_malloc(sizeof(*loop));
if (!loop) {
lwsl_err("OOM\n");
return -1;
}
uv_loop_init(loop);
pt->ev_loop_foreign = 0;
} else
pt->ev_loop_foreign = 1;
pt->io_loop_uv = loop;
uv_idle_init(loop, &pt->uv_idle);
assert(ARRAY_SIZE(sigs) <= ARRAY_SIZE(pt->signals));
for (n = 0; n < ARRAY_SIZE(sigs); n++) {
uv_signal_init(loop, &pt->signals[n]);
uv_signal_start(&pt->signals[n], cb, sigs[n]);
if (pt->context->use_ev_sigint) {
assert(ARRAY_SIZE(sigs) <= ARRAY_SIZE(pt->signals));
for (n = 0; n < ARRAY_SIZE(sigs); n++) {
struct lws_uv_sigint_ctx *wrap_ctx = lws_malloc(sizeof(*wrap_ctx));
wrap_ctx->context = pt->context;
wrap_ctx->cb = context->lws_uv_sigint_cb;
uv_signal_init(loop, &pt->signals[n]);
pt->signals[n].data = wrap_ctx;
uv_signal_start(&pt->signals[n], lws_uv_sigint_cb_wrapper, sigs[n]);
}
}
/*
@ -106,15 +182,31 @@ lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, uv_signal_cb cb,
* We have to do it here because the uv loop(s) are not
* initialized until after context creation.
*/
if (wsi) {
wsi->w_read.context = context;
uv_poll_init(pt->io_loop_uv, &wsi->w_read.uv_watcher, pt->lserv_fd);
uv_poll_start(&wsi->w_read.uv_watcher, UV_READABLE, lws_accept_cb);
uv_poll_init_socket(pt->io_loop_uv, &wsi->w_read.uv_watcher,
pt->lserv_fd);
uv_poll_start(&wsi->w_read.uv_watcher, UV_READABLE,
lws_io_cb);
}
uv_timer_init(pt->io_loop_uv, &pt->uv_timeout_watcher);
uv_timer_start(&pt->uv_timeout_watcher, lws_uv_timeout_cb, 1000, 1000);
return status;
}
void lws_uv_close_cb(uv_handle_t *handle)
{
}
void lws_uv_walk_cb(uv_handle_t *handle, void *arg)
{
uv_close(handle, lws_uv_close_cb);
}
void
lws_libuv_destroyloop(struct lws_context *context, int tsi)
{
@ -124,13 +216,22 @@ lws_libuv_destroyloop(struct lws_context *context, int tsi)
if (!(context->options & LWS_SERVER_OPTION_LIBUV))
return;
if (!pt->io_loop_uv)
return;
if (context->use_ev_sigint)
uv_signal_stop(&pt->w_sigint.uv_watcher);
for (m = 0; m < ARRAY_SIZE(sigs); m++)
for (m = 0; m < ARRAY_SIZE(sigs); m++) {
uv_signal_stop(&pt->signals[m]);
lws_free(pt->signals[m].data);
}
if (!pt->ev_loop_foreign) {
uv_stop(pt->io_loop_uv);
uv_walk(pt->io_loop_uv, lws_uv_walk_cb, NULL);
while (uv_run(pt->io_loop_uv, UV_RUN_NOWAIT));
m = uv_loop_close(pt->io_loop_uv);
lwsl_debug("%s: uv_loop_close: %d\n", __func__, m);
if (m == UV_EBUSY)
lwsl_debug("%s: uv_loop_close: UV_EBUSY\n", __func__);
lws_free(pt->io_loop_uv);
}
}
@ -156,8 +257,13 @@ lws_libuv_io(struct lws *wsi, int flags)
{
struct lws_context *context = lws_get_context(wsi);
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
#if defined(WIN32) || defined(_WIN32)
int current_events = wsi->w_read.uv_watcher.events &
(UV_READABLE | UV_WRITABLE);
#else
int current_events = wsi->w_read.uv_watcher.io_watcher.pevents &
(UV_READABLE | UV_WRITABLE);
#endif
struct lws_io_watcher *w = &wsi->w_read;
if (!LWS_LIBUV_ENABLED(context))
@ -180,7 +286,7 @@ lws_libuv_io(struct lws *wsi, int flags)
if (flags & LWS_EV_READ)
current_events |= UV_READABLE;
uv_poll_start(&w->uv_watcher, current_events, lws_accept_cb);
uv_poll_start(&w->uv_watcher, current_events, lws_io_cb);
} else {
if (flags & LWS_EV_WRITE)
current_events &= ~UV_WRITABLE;
@ -192,7 +298,7 @@ lws_libuv_io(struct lws *wsi, int flags)
uv_poll_stop(&w->uv_watcher);
else
uv_poll_start(&w->uv_watcher, current_events,
lws_accept_cb);
lws_io_cb);
}
}
@ -226,6 +332,7 @@ lws_libuv_kill(const struct lws_context *context)
for (n = 0; n < context->count_threads; n++)
if (context->pt[n].io_loop_uv && LWS_LIBUV_ENABLED(context))
uv_stop(context->pt[n].io_loop_uv);
// TODO uv_stop check foreign loop? or not?
}
/*
@ -277,8 +384,8 @@ lws_uv_getloop(struct lws_context *context, int tsi)
static void
lws_libuv_closewsi(uv_handle_t* handle)
{
struct lws *n = NULL, *wsi = (struct lws *)(((void *)handle) -
(void *)(&n->w_read.uv_watcher));
struct lws *n = NULL, *wsi = (struct lws *)(((char *)handle) -
(char *)(&n->w_read.uv_watcher));
struct lws_context *context = lws_get_context(wsi);
lws_close_free_wsi_final(wsi);

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

@ -21,6 +21,10 @@
#include "private-libwebsockets.h"
#ifdef LWS_HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
int log_level = LLL_ERR | LLL_WARN | LLL_NOTICE;
static void (*lwsl_emit)(int level, const char *line) = lwsl_emit_stderr;
@ -53,11 +57,12 @@ 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) {
if (wsi->u.hdr.ah)
/* we're closing, losing some rx is OK */
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
lws_header_table_detach(wsi);
}
/* we may not have an ah, but may be on the waiting list... */
lws_header_table_detach(wsi);
wsi->context->count_wsi_allocated--;
lwsl_debug("%s: %p, remaining wsi %d\n", __func__, wsi,
@ -71,14 +76,17 @@ lws_remove_from_timeout_list(struct lws *wsi)
{
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
if (!wsi->timeout_list_prev)
if (!wsi->timeout_list_prev) /* ie, not part of the list */
return;
lws_pt_lock(pt);
/* if we have a next guy, set his prev to our prev */
if (wsi->timeout_list)
wsi->timeout_list->timeout_list_prev = wsi->timeout_list_prev;
/* set our prev guy to our next guy instead of us */
*wsi->timeout_list_prev = wsi->timeout_list;
/* we're out of the list, we should not point anywhere any more */
wsi->timeout_list_prev = NULL;
wsi->timeout_list = NULL;
lws_pt_unlock(pt);
@ -104,11 +112,15 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs)
time(&now);
if (!wsi->pending_timeout && reason) {
if (reason && !wsi->timeout_list_prev) {
/* our next guy is current first guy */
wsi->timeout_list = pt->timeout_list;
/* if there is a next guy, set his prev ptr to our next ptr */
if (wsi->timeout_list)
wsi->timeout_list->timeout_list_prev = &wsi->timeout_list;
/* our prev ptr is first ptr */
wsi->timeout_list_prev = &pt->timeout_list;
/* set the first guy to be us */
*wsi->timeout_list_prev = wsi;
}
@ -252,7 +264,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;
}
@ -299,11 +311,20 @@ just_kill_connection:
n = shutdown(wsi->sock, SHUT_WR);
if (n)
lwsl_debug("closing: shutdown ret %d\n", LWS_ERRNO);
wsi->state = LWSS_SHUTDOWN;
lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLIN);
lws_set_timeout(wsi, PENDING_TIMEOUT_SHUTDOWN_FLUSH,
context->timeout_secs);
return;
// This causes problems with disconnection when the events are half closing connection
// FD_READ | FD_CLOSE (33)
#ifndef _WIN32_WCE
/* libuv: no event available to guarantee completion */
if (!LWS_LIBUV_ENABLED(context)) {
lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLIN);
wsi->state = LWSS_SHUTDOWN;
lws_set_timeout(wsi, PENDING_TIMEOUT_SHUTDOWN_FLUSH,
context->timeout_secs);
return;
}
#endif
}
#endif
@ -372,7 +393,9 @@ just_kill_connection:
((wsi->state_pre_close == LWSS_ESTABLISHED) ||
(wsi->state_pre_close == LWSS_RETURNED_CLOSE_ALREADY) ||
(wsi->state_pre_close == LWSS_AWAITING_CLOSE_ACK) ||
(wsi->state_pre_close == LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE))) {
(wsi->state_pre_close == LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) ||
(wsi->mode == LWSCM_WS_CLIENT && wsi->state_pre_close == LWSS_HTTP) ||
(wsi->mode == LWSCM_WS_SERVING && wsi->state_pre_close == LWSS_HTTP))) {
lwsl_debug("calling back CLOSED\n");
wsi->protocol->callback(wsi, LWS_CALLBACK_CLOSED,
wsi->user_space, NULL, 0);
@ -382,10 +405,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");
context->protocols[0].callback(wsi,
errorString = NULL;
if (wsi->u.hdr.ah)
errorString = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP);
if (errorString) {
context->protocols[0].callback(wsi,
LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
wsi->user_space, errorString,
(unsigned int)strlen(errorString));
} else {
context->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);
@ -922,18 +957,41 @@ lws_ensure_user_space(struct lws *wsi)
LWS_VISIBLE void lwsl_emit_stderr(int level, const char *line)
{
time_t o_now = time(NULL);
unsigned long long now;
struct tm *ptm = NULL;
char buf[300];
#ifndef WIN32
struct tm tm;
#endif
int n;
#ifndef _WIN32_WCE
#ifdef WIN32
ptm = localtime(&o_now);
#else
if (localtime_r(&o_now, &tm))
ptm = &tm;
#endif
#endif
buf[0] = '\0';
for (n = 0; n < LLL_COUNT; n++) {
if (level != (1 << n))
continue;
now = time_in_microseconds() / 100;
sprintf(buf, "[%llu:%04d] %s: ",
(unsigned long long) now / 10000,
(int)(now % 10000), log_level_names[n]);
if (ptm)
sprintf(buf, "[%04d/%02d/%02d %02d:%02d:%02d:%04d] %s: ",
ptm->tm_year + 1900,
ptm->tm_mon,
ptm->tm_mday,
ptm->tm_hour,
ptm->tm_min,
ptm->tm_sec,
(int)(now % 10000), log_level_names[n]);
else
sprintf(buf, "[%llu:%04d] %s: ",
(unsigned long long) now / 10000,
(int)(now % 10000), log_level_names[n]);
break;
}
@ -1255,6 +1313,25 @@ lws_parse_uri(char *p, const char **prot, const char **ads, int *port,
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;
}
#ifdef LWS_NO_EXTENSIONS
/* we need to provide dummy callbacks for internal exts

View file

@ -114,9 +114,18 @@ struct sockaddr_in;
#include <stddef.h>
#include <stdint.h>
#include <basetsd.h>
#ifndef _WIN32_WCE
#include <fcntl.h>
#else
#define _O_RDONLY 0x0000
#define O_RDONLY _O_RDONLY
#endif
#ifdef _WIN32_WCE
#define strcasecmp _stricmp
#else
#define strcasecmp stricmp
#endif
#define getdtablesize() 30000
#define LWS_INLINE __inline
@ -137,9 +146,15 @@ struct sockaddr_in;
#define LWS_INVALID_FILE INVALID_HANDLE_VALUE
#define LWS_O_RDONLY _O_RDONLY
#define snprintf _snprintf
#else /* NOT WIN32 */
#include <unistd.h>
#if defined(__NetBSD__) || defined(__FreeBSD__)
#include <netinet/in.h>
#endif
#define LWS_INLINE inline
#define LWS_O_RDONLY O_RDONLY
@ -153,8 +168,15 @@ struct sockaddr_in;
#endif
#if defined(__GNUC__)
/* warn_unused_result attribute only supported by GCC 3.4 or later */
#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
#define LWS_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#else
#define LWS_WARN_UNUSED_RESULT
#endif
#define LWS_VISIBLE __attribute__((visibility("default")))
#define LWS_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
#define LWS_WARN_DEPRECATED __attribute__ ((deprecated))
#else
#define LWS_VISIBLE
@ -423,7 +445,7 @@ struct lws_plat_file_ops {
unsigned char *buf, unsigned long len);
/* Add new things just above here ---^
* This is part of the ABI, don't needlessly break compatibilty */
* This is part of the ABI, don't needlessly break compatibility */
};
/*
@ -1190,7 +1212,7 @@ struct lws_protocols {
void *user;
/* Add new things just above here ---^
* This is part of the ABI, don't needlessly break compatibilty */
* This is part of the ABI, don't needlessly break compatibility */
};
enum lws_ext_options_types {
@ -1199,7 +1221,7 @@ enum lws_ext_options_types {
EXTARG_OPT_DEC
/* Add new things just above here ---^
* This is part of the ABI, don't needlessly break compatibilty */
* This is part of the ABI, don't needlessly break compatibility */
};
/**
@ -1216,7 +1238,7 @@ struct lws_ext_options {
enum lws_ext_options_types type;
/* Add new things just above here ---^
* This is part of the ABI, don't needlessly break compatibilty */
* This is part of the ABI, don't needlessly break compatibility */
};
struct lws_ext_option_arg {
@ -1239,7 +1261,7 @@ struct lws_extension {
const char *client_offer;
/* Add new things just above here ---^
* This is part of the ABI, don't needlessly break compatibilty */
* This is part of the ABI, don't needlessly break compatibility */
};
/*
@ -1479,7 +1501,7 @@ lws_ev_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents);
#endif /* LWS_USE_LIBEV */
#ifdef LWS_USE_LIBUV
typedef void (lws_uv_signal_cb_t)(uv_loop_t *l, uv_signal_t *w, int revents);
typedef void (lws_uv_signal_cb_t)(uv_loop_t *l, uv_signal_t *w, int signum);
LWS_VISIBLE LWS_EXTERN int
lws_uv_sigint_cfg(struct lws_context *context, int use_uv_sigint,
@ -1498,7 +1520,7 @@ LWS_VISIBLE LWS_EXTERN uv_loop_t *
lws_uv_getloop(struct lws_context *context, int tsi);
LWS_VISIBLE void
lws_uv_sigint_cb(uv_loop_t *loop, uv_signal_t *watcher, int revents);
lws_uv_sigint_cb(uv_loop_t *loop, uv_signal_t *watcher, int signum);
#endif /* LWS_USE_LIBUV */
LWS_VISIBLE LWS_EXTERN int
@ -1584,6 +1606,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)
@ -1887,6 +1926,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

@ -50,15 +50,6 @@ lws_poll_listen_fd(struct lws_pollfd *fd)
return poll(fd, 1, 0);
}
/*
* This is just used to interrupt poll waiting
* we don't have to do anything with it.
*/
static void
lws_sigusr2(int sig)
{
}
/**
* lws_cancel_service_pt() - Cancel servicing of pending socket activity
* on one thread
@ -122,7 +113,7 @@ 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];
int n, m, c;
int n = -1, m, c;
char buf;
/* stay dead once we are dead */
@ -130,6 +121,9 @@ lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
if (!context)
return 1;
if (timeout_ms < 0)
goto faked_service;
lws_libev_run(context, tsi);
lws_libuv_run(context, tsi);
@ -158,15 +152,17 @@ lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
return 0;
}
if (n < 0) {
if (LWS_ERRNO != LWS_EINTR)
return -1;
return 0;
}
c = n;
lws_service_flag_pending(context, tsi);
faked_service:
m = lws_service_flag_pending(context, tsi);
if (m)
c = -1; /* unknown limit */
else
if (n < 0) {
if (LWS_ERRNO != LWS_EINTR)
return -1;
return 0;
} else
c = n;
/* any socket with events to service? */
for (n = 0; n < pt->fds_count && c; n++) {
@ -270,6 +266,10 @@ lws_plat_set_socket_options(struct lws_context *context, int fd)
LWS_VISIBLE void
lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
{
if (info->gid != -1)
if (setgid(info->gid))
lwsl_warn("setgid: %s\n", strerror(LWS_ERRNO));
if (info->uid != -1) {
struct passwd *p = getpwuid(info->uid);
@ -282,10 +282,6 @@ lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
} else
lwsl_warn("getpwuid: unable to find uid %d", info->uid);
}
if (info->gid != -1)
if (setgid(info->gid))
lwsl_warn("setgid: %s\n", strerror(LWS_ERRNO));
}
static void
@ -296,14 +292,6 @@ sigpipe_handler(int x)
LWS_VISIBLE int
lws_plat_context_early_init(void)
{
sigset_t mask;
signal(SIGUSR2, lws_sigusr2);
sigemptyset(&mask);
sigaddset(&mask, SIGUSR2);
sigprocmask(SIG_BLOCK, &mask, NULL);
signal(SIGPIPE, sigpipe_handler);
return 0;

View file

@ -111,7 +111,7 @@ LWS_VISIBLE int lws_poll_listen_fd(struct lws_pollfd *fd)
fd_set readfds;
struct timeval tv = { 0, 0 };
assert(fd->events == LWS_POLLIN);
assert((fd->events & LWS_POLLIN) == LWS_POLLIN);
FD_ZERO(&readfds);
FD_SET(fd->fd, &readfds);
@ -176,6 +176,9 @@ lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
}
context->service_tid = context->service_tid_detected;
if (timeout_ms < 0)
goto faked_service;
for (i = 0; i < pt->fds_count; ++i) {
pfd = &pt->fds[i];
if (pfd->fd == pt->lserv_fd)
@ -234,6 +237,8 @@ lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
wsi->sock_send_blocking = 0;
}
faked_service:
/* if someone faked their LWS_POLLIN, then go through all active fds */
if (lws_service_flag_pending(context, tsi)) {
@ -252,6 +257,9 @@ lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
return 0;
}
if (timeout_ms < 0)
return 0;
/* otherwise just do the one... must be a way to improve that... */
return lws_service_fd_tsi(context, pfd, tsi);
@ -271,7 +279,10 @@ lws_plat_set_socket_options(struct lws_context *context, lws_sockfd_type fd)
u_long optl = 1;
DWORD dwBytesRet;
struct tcp_keepalive alive;
int protonbr;
#ifndef _WIN32_WCE
struct protoent *tcp_proto;
#endif
if (context->ka_time) {
/* enable keepalive on this socket */
@ -291,13 +302,18 @@ lws_plat_set_socket_options(struct lws_context *context, lws_sockfd_type fd)
/* Disable Nagle */
optval = 1;
#ifndef _WIN32_WCE
tcp_proto = getprotobyname("TCP");
if (!tcp_proto) {
lwsl_err("getprotobyname() failed with error %d\n", LWS_ERRNO);
return 1;
}
protonbr = tcp_proto->p_proto;
#else
protonbr = 6;
#endif
setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, (const char *)&optval, optlen);
setsockopt(fd, protonbr, TCP_NODELAY, (const char *)&optval, optlen);
/* We are nonblocking... */
ioctlsocket(fd, FIONBIO, &optl);
@ -387,7 +403,8 @@ 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);
WSAEventSelect(wsi->sock, pt->events[pt->fds_count],
LWS_POLLIN | LWS_POLLHUP);
}
LWS_VISIBLE void

View file

@ -97,7 +97,7 @@ lws_header_table_attach(struct lws *wsi)
/* if we are already bound to one, just clear it down */
if (wsi->u.hdr.ah) {
lwsl_err("cleardown\n");
lwsl_info("cleardown\n");
goto reset;
}
@ -112,8 +112,8 @@ lws_header_table_attach(struct lws *wsi)
goto bail;
}
/* new ah.... remove ourselves from waiting list */
*pwsi = wsi->u.hdr.ah_wait_list;
wsi->u.hdr.ah_wait_list = NULL;
*pwsi = wsi->u.hdr.ah_wait_list; /* set our prev to our next */
wsi->u.hdr.ah_wait_list = NULL; /* no next any more */
pt->ah_wait_list_length--;
break;
}
@ -189,26 +189,35 @@ int lws_header_table_detach(struct lws *wsi)
lws_pt_lock(pt);
pwsi = &pt->ah_wait_list;
if (!ah) { /* remove from wait list if that's all */
if (wsi->socket_is_permanently_unusable)
while (*pwsi) {
if (*pwsi == wsi) {
lwsl_info("%s: wsi %p, remv wait\n",
__func__, wsi);
*pwsi = wsi->u.hdr.ah_wait_list;
wsi->u.hdr.ah_wait_list = NULL;
pt->ah_wait_list_length--;
goto bail;
}
pwsi = &(*pwsi)->u.hdr.ah_wait_list;
if (!ah) { /* remove from wait list if none attached */
while (*pwsi) {
if (*pwsi == wsi) {
lwsl_info("%s: wsi %p, remv wait\n",
__func__, wsi);
*pwsi = wsi->u.hdr.ah_wait_list;
wsi->u.hdr.ah_wait_list = NULL;
pt->ah_wait_list_length--;
goto bail;
}
pwsi = &(*pwsi)->u.hdr.ah_wait_list;
}
/* no ah, not on list... no more business here */
goto bail;
}
/* we did have an ah attached */
time(&now);
if (now - wsi->u.hdr.ah->assigned > 3)
lwsl_err("header assign - free time %d\n",
(int)(now - wsi->u.hdr.ah->assigned));
if (now - wsi->u.hdr.ah->assigned > 3) {
/*
* we're detaching the ah, but it was held an
* unreasonably long time
*/
lwsl_notice("%s: wsi %p: ah held %ds, "
"ah.rxpos %d, ah.rxlen %d, mode/state %d %d,"
"wsi->more_rx_waiting %d\n", __func__, wsi,
(int)(now - wsi->u.hdr.ah->assigned),
ah->rxpos, ah->rxlen, wsi->mode, wsi->state,
wsi->more_rx_waiting);
}
/* if we think we're detaching one, there should be one in use */
assert(pt->ah_count_in_use > 0);
@ -217,6 +226,7 @@ int lws_header_table_detach(struct lws *wsi)
wsi->u.hdr.ah = NULL;
ah->wsi = NULL; /* no owner */
/* oh there is nobody on the waiting list... leave it at that then */
if (!*pwsi) {
ah->in_use = 0;
pt->ah_count_in_use--;
@ -224,7 +234,7 @@ int lws_header_table_detach(struct lws *wsi)
goto bail;
}
/* somebody else on same tsi is waiting, give it to him */
/* somebody else on same tsi is waiting, give it to oldest guy */
lwsl_info("pt wait list %p\n", *pwsi);
while ((*pwsi)->u.hdr.ah_wait_list)
@ -249,6 +259,7 @@ int lws_header_table_detach(struct lws *wsi)
/* point prev guy to next guy in list instead */
*pwsi = wsi->u.hdr.ah_wait_list;
/* the guy who got one is out of the list */
wsi->u.hdr.ah_wait_list = NULL;
pt->ah_wait_list_length--;
@ -535,6 +546,23 @@ lws_parse(struct lws *wsi, unsigned char c)
if (issue_char(wsi, '/') < 0)
return -1;
if (wsi->u.hdr.ups == URIPS_SEEN_SLASH_DOT_DOT) {
/*
* back up one dir level if possible
* safe against header fragmentation because
* the method URI can only be in 1 fragment
*/
if (ah->frags[ah->nfrag].len > 2) {
ah->pos--;
ah->frags[ah->nfrag].len--;
do {
ah->pos--;
ah->frags[ah->nfrag].len--;
} while (ah->frags[ah->nfrag].len > 1 &&
ah->data[ah->pos] != '/');
}
}
/* begin parsing HTTP version: */
if (issue_char(wsi, '\0') < 0)
return -1;
@ -542,7 +570,10 @@ lws_parse(struct lws *wsi, unsigned char c)
goto start_fragment;
}
/* special URI processing... convert %xx */
/*
* PRIORITY 1
* special URI processing... convert %xx
*/
switch (wsi->u.hdr.ues) {
case URIES_IDLE:
@ -552,30 +583,19 @@ lws_parse(struct lws *wsi, unsigned char c)
}
break;
case URIES_SEEN_PERCENT:
if (char_to_hex(c) < 0) {
/* regurgitate */
if (issue_char(wsi, '%') < 0)
return -1;
wsi->u.hdr.ues = URIES_IDLE;
/* continue on to assess c */
break;
}
if (char_to_hex(c) < 0)
/* illegal post-% char */
goto forbid;
wsi->u.hdr.esc_stash = c;
wsi->u.hdr.ues = URIES_SEEN_PERCENT_H1;
goto swallow;
case URIES_SEEN_PERCENT_H1:
if (char_to_hex(c) < 0) {
/* regurgitate */
if (issue_char(wsi, '%') < 0)
return -1;
wsi->u.hdr.ues = URIES_IDLE;
/* regurgitate + assess */
if (lws_parse(wsi, wsi->u.hdr.esc_stash) < 0)
return -1;
/* continue on to assess c */
break;
}
if (char_to_hex(c) < 0)
/* illegal post-% char */
goto forbid;
c = (char_to_hex(wsi->u.hdr.esc_stash) << 4) |
char_to_hex(c);
enc = 1;
@ -584,6 +604,7 @@ lws_parse(struct lws *wsi, unsigned char c)
}
/*
* PRIORITY 2
* special URI processing...
* convert /.. or /... or /../ etc to /
* convert /./ to /
@ -614,7 +635,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 = */
@ -642,20 +665,6 @@ lws_parse(struct lws *wsi, unsigned char c)
case URIPS_SEEN_SLASH_DOT:
/* swallow second . */
if (c == '.') {
/*
* back up one dir level if possible
* safe against header fragmentation because
* the method URI can only be in 1 fragment
*/
if (ah->frags[ah->nfrag].len > 2) {
ah->pos--;
ah->frags[ah->nfrag].len--;
do {
ah->pos--;
ah->frags[ah->nfrag].len--;
} while (ah->frags[ah->nfrag].len > 1 &&
ah->data[ah->pos] != '/');
}
wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT_DOT;
goto swallow;
}
@ -671,19 +680,44 @@ lws_parse(struct lws *wsi, unsigned char c)
break;
case URIPS_SEEN_SLASH_DOT_DOT:
/* swallow prior .. chars and any subsequent . */
if (c == '.')
/* /../ or /..[End of URI] --> backup to last / */
if (c == '/' || c == '?') {
/*
* back up one dir level if possible
* safe against header fragmentation because
* the method URI can only be in 1 fragment
*/
if (ah->frags[ah->nfrag].len > 2) {
ah->pos--;
ah->frags[ah->nfrag].len--;
do {
ah->pos--;
ah->frags[ah->nfrag].len--;
} while (ah->frags[ah->nfrag].len > 1 &&
ah->data[ah->pos] != '/');
}
wsi->u.hdr.ups = URIPS_SEEN_SLASH;
if (ah->frags[ah->nfrag].len > 1)
break;
goto swallow;
/* last issued was /, so another / == // */
if (c == '/')
goto swallow;
/* last we issued was / so SEEN_SLASH */
wsi->u.hdr.ups = URIPS_SEEN_SLASH;
}
/* /..[^/] ... regurgitate and allow */
if (issue_char(wsi, '.') < 0)
return -1;
if (issue_char(wsi, '.') < 0)
return -1;
wsi->u.hdr.ups = URIPS_IDLE;
break;
}
if (c == '?' && !enc &&
!ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS]) { /* start of URI arguments */
if (wsi->u.hdr.ues != URIES_IDLE)
goto forbid;
/* seal off uri header */
if (issue_char(wsi, '\0') < 0)
return -1;
@ -703,10 +737,12 @@ lws_parse(struct lws *wsi, unsigned char c)
}
check_eol:
/* bail at EOL */
if (wsi->u.hdr.parser_state != WSI_TOKEN_CHALLENGE &&
c == '\x0d') {
if (wsi->u.hdr.ues != URIES_IDLE)
goto forbid;
c = '\0';
wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
lwsl_parser("*\n");
@ -752,7 +788,7 @@ swallow:
*/
if (m == ARRAY_SIZE(methods)) {
lwsl_info("Unknown method - dropping\n");
return -1;
goto forbid;
}
break;
}
@ -840,6 +876,8 @@ excessive:
case WSI_TOKEN_SKIPPING_SAW_CR:
lwsl_parser("WSI_TOKEN_SKIPPING_SAW_CR '%c'\n", c);
if (wsi->u.hdr.ues != URIES_IDLE)
goto forbid;
if (c == '\x0a') {
wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
wsi->u.hdr.lextable_pos = 0;
@ -856,7 +894,8 @@ excessive:
return 0;
set_parsing_complete:
if (wsi->u.hdr.ues != URIES_IDLE)
goto forbid;
if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {
if (lws_hdr_total_length(wsi, WSI_TOKEN_VERSION))
wsi->ietf_spec_revision =
@ -868,6 +907,11 @@ set_parsing_complete:
wsi->hdr_parsing_completed = 1;
return 0;
forbid:
lwsl_notice(" forbidding on uri sanitation\n");
lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
return -1;
}
@ -1404,3 +1448,63 @@ lws_remaining_packet_payload(struct lws *wsi)
{
return wsi->u.ws.rx_packet_length;
}
/* Once we reach LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED, we know how much
* to expect in that state and can deal with it in bulk more efficiently.
*/
void
lws_payload_until_length_exhausted(struct lws *wsi, unsigned char **buf,
size_t *len)
{
unsigned char *buffer = *buf, mask[4];
int buffer_size, avail, n;
char *rx_ubuf;
if (wsi->protocol->rx_buffer_size)
buffer_size = wsi->protocol->rx_buffer_size;
else
buffer_size = LWS_MAX_SOCKET_IO_BUF;
avail = buffer_size - wsi->u.ws.rx_ubuf_head;
/* do not consume more than we should */
if (avail > wsi->u.ws.rx_packet_length)
avail = wsi->u.ws.rx_packet_length;
/* do not consume more than what is in the buffer */
if (avail > *len)
avail = *len;
/* we want to leave 1 byte for the parser to handle properly */
if (avail <= 1)
return;
avail--;
rx_ubuf = wsi->u.ws.rx_ubuf + LWS_PRE + wsi->u.ws.rx_ubuf_head;
if (wsi->u.ws.all_zero_nonce)
memcpy(rx_ubuf, buffer, avail);
else {
for (n = 0; n < 4; n++)
mask[n] = wsi->u.ws.mask[(wsi->u.ws.mask_idx + n) & 3];
/* deal with 4-byte chunks using unwrapped loop */
n = avail >> 2;
while (n--) {
*(rx_ubuf++) = *(buffer++) ^ mask[0];
*(rx_ubuf++) = *(buffer++) ^ mask[1];
*(rx_ubuf++) = *(buffer++) ^ mask[2];
*(rx_ubuf++) = *(buffer++) ^ mask[3];
}
/* and the remaining bytes bytewise */
for (n = 0; n < (avail & 3); n++)
*(rx_ubuf++) = *(buffer++) ^ mask[n];
wsi->u.ws.mask_idx = (wsi->u.ws.mask_idx + avail) & 3;
}
(*buf) += avail;
wsi->u.ws.rx_ubuf_head += avail;
wsi->u.ws.rx_packet_length -= avail;
*len -= avail;
}

View file

@ -277,7 +277,12 @@ lws_callback_on_writable(struct lws *wsi)
#ifdef LWS_USE_HTTP2
struct lws *network_wsi, *wsi2;
int already;
#endif
if (wsi->state == LWSS_SHUTDOWN)
return 0;
#ifdef LWS_USE_HTTP2
lwsl_info("%s: %p\n", __func__, wsi);
if (wsi->mode != LWSCM_HTTP2_SERVING)

View file

@ -84,6 +84,14 @@
#ifdef _WIN32_WCE
#define vsnprintf _vsnprintf
#else
#ifdef LWS_HAVE__VSNPRINTF
#define vsnprintf _vsnprintf
#endif
#endif
#ifdef LWS_HAVE__SNPRINTF
#define lws_snprintf _snprintf
#endif
#else /* not windows --> */
@ -106,6 +114,7 @@
#endif
#if defined (__ANDROID__)
#include <syslog.h>
#include <sys/resource.h>
#else
#include <sys/syslog.h>
#endif
@ -224,10 +233,15 @@ typedef unsigned __int64 u_int64_t;
#endif
#endif
#include <stddef.h>
#ifndef container_of
#define container_of(P,T,M) ((T *)((char *)(P) - offsetof(T, M)))
#endif
#else
#include <sys/stat.h>
#include <sys/cdefs.h>
#include <sys/time.h>
#if defined(__APPLE__)
@ -530,6 +544,7 @@ struct lws_context_per_thread {
struct lws *rx_draining_ext_list;
struct lws *tx_draining_ext_list;
struct lws *timeout_list;
struct lws_context *context;
void *http_header_data;
struct allocated_headers *ah_pool;
struct lws *ah_wait_list;
@ -546,6 +561,8 @@ struct lws_context_per_thread {
#if defined(LWS_USE_LIBUV)
uv_loop_t *io_loop_uv;
uv_signal_t signals[8];
uv_timer_t uv_timeout_watcher;
uv_idle_t uv_idle;
#endif
#if defined(LWS_USE_LIBEV)
struct lws_io_watcher w_accept;
@ -571,6 +588,7 @@ struct lws_context_per_thread {
unsigned int fds_count;
short ah_count_in_use;
unsigned char tid;
};
/*
@ -948,12 +966,11 @@ struct _lws_header_related {
char post_literal_equal;
unsigned char parser_state; /* enum lws_token_indexes */
char redirects;
char more_rx_waiting;
};
struct _lws_websocket_related {
/* cheapest way to deal with ah overlap with ws union transition */
struct _lws_header_related *hdr;
struct _lws_header_related hdr;
char *rx_ubuf;
unsigned int rx_ubuf_alloc;
struct lws *rx_draining_ext_list;
@ -1056,6 +1073,7 @@ struct lws {
unsigned int user_space_externally_allocated:1;
unsigned int socket_is_permanently_unusable:1;
unsigned int rxflow_change_to:2;
unsigned int more_rx_waiting:1; /* has to live here since ah may stick to end */
#ifndef LWS_NO_EXTENSIONS
unsigned int extension_data_pending:1;
#endif
@ -1206,6 +1224,9 @@ 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_payload_until_length_exhausted(struct lws *wsi, unsigned char **buf, size_t *len);
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_issue_raw_ext_access(struct lws *wsi, unsigned char *buf, size_t len);
@ -1367,6 +1388,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)
{
@ -1380,6 +1408,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

View file

@ -123,11 +123,6 @@ lws_extension_server_handshake(struct lws *wsi, char **p)
/* apply it */
if (ext_count)
*(*p)++ = ',';
else
LWS_CPYAPP(*p, "\x0d\x0aSec-WebSocket-Extensions: ");
*p += sprintf(*p, "%s", ext_name);
ext_count++;
/* instantiate the extension on this conn */
@ -136,10 +131,21 @@ lws_extension_server_handshake(struct lws *wsi, char **p)
/* allow him to construct his context */
ext->callback(lws_get_context(wsi), ext, wsi,
if (ext->callback(lws_get_context(wsi), ext, wsi,
LWS_EXT_CB_CONSTRUCT,
(void *)&wsi->act_ext_user[wsi->count_act_ext],
NULL, 0);
NULL, 0)) {
lwsl_notice("ext %s failed construction\n", ext_name);
ext_count--;
ext++;
continue;
}
if (ext_count > 1)
*(*p)++ = ',';
else
LWS_CPYAPP(*p, "\x0d\x0aSec-WebSocket-Extensions: ");
*p += sprintf(*p, "%s", ext_name);
wsi->count_act_ext++;
lwsl_parser("count_act_ext <- %d\n", wsi->count_act_ext);
@ -208,12 +214,9 @@ 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)) {
if (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

@ -243,6 +243,14 @@ lws_http_action(struct lws *wsi)
break;
}
/* we insist on absolute paths */
if (uri_ptr[0] != '/') {
lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
goto bail_nuke_ah;
}
/* HTTP header had a content length? */
wsi->u.http.content_length = 0;
@ -306,6 +314,11 @@ lws_http_action(struct lws *wsi)
n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP,
wsi->user_space, uri_ptr, uri_len);
if (n) {
lwsl_info("LWS_CALLBACK_HTTP closing\n");
return 1;
}
/*
* If we're not issuing a file, check for content_length or
@ -347,7 +360,7 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
assert(wsi->u.hdr.ah);
while (len--) {
wsi->u.hdr.more_rx_waiting = !!len;
wsi->more_rx_waiting = !!len;
assert(wsi->mode == LWSCM_HTTP_SERVING);
@ -359,7 +372,9 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
if (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE)
continue;
lwsl_parser("lws_parse sees parsing complete\n");
lwsl_parser("%s: lws_parse sees parsing complete\n", __func__);
lwsl_debug("%s: wsi->more_rx_waiting=%d\n", __func__,
wsi->more_rx_waiting);
wsi->mode = LWSCM_PRE_WS_SERVING_ACCEPT;
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
@ -551,7 +566,7 @@ upgrade_ws:
default:
lwsl_warn("Unknown client spec version %d\n",
wsi->ietf_spec_revision);
wsi->ietf_spec_revision);
goto bail_nuke_ah;
}
@ -562,8 +577,9 @@ upgrade_ws:
* upgrade request and to already be in the ah rx buffer.
*/
lwsl_err("%s: %p: inheriting ah in ws mode (rxpos: %d, rxlen: %d)\n",
__func__, wsi, wsi->u.hdr.ah->rxpos, wsi->u.hdr.ah->rxlen);
lwsl_info("%s: %p: inheriting ah in ws mode (rxpos:%d, rxlen:%d)\n",
__func__, wsi, wsi->u.hdr.ah->rxpos,
wsi->u.hdr.ah->rxlen);
lws_pt_lock(pt);
hdr = wsi->u.hdr;
@ -574,7 +590,7 @@ upgrade_ws:
* mode any more then... ah_temp member is at start the same
* though)
*
* Beacuse rxpos/rxlen shows something in the ah, we will get
* Because rxpos/rxlen shows something in the ah, we will get
* service guaranteed next time around the event loop
*
* All union members begin with hdr, so we can use it even
@ -738,9 +754,13 @@ lws_http_transaction_completed(struct lws *wsi)
* reset the existing header table and keep it.
*/
if (wsi->u.hdr.ah) {
if (wsi->u.hdr.ah->rxpos == wsi->u.hdr.ah->rxlen)
lwsl_info("%s: wsi->more_rx_waiting=%d\n", __func__,
wsi->more_rx_waiting);
if (!wsi->more_rx_waiting) {
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
lws_header_table_detach(wsi);
else
} else
lws_header_table_reset(wsi);
}
@ -1162,6 +1182,11 @@ lws_interpret_incoming_packet(struct lws *wsi, unsigned char **buf, size_t len)
if (wsi->rxflow_buffer)
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);
/* process the byte */
m = lws_rx_sm(wsi, *(*buf)++);
if (m < 0)

View file

@ -143,6 +143,8 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
/* Priority 6: user can get the callback
*/
m = lws_ext_cb_active(wsi, LWS_EXT_CB_IS_WRITEABLE, NULL, 0);
if (m)
return -1;
#ifndef LWS_NO_EXTENSIONS
if (!wsi->extension_data_pending)
goto user_service;
@ -292,7 +294,6 @@ int
lws_service_timeout_check(struct lws *wsi, unsigned int sec)
{
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
struct lws **pwsi;
/*
* if extensions want in on it (eg, we are a mux parent)
@ -316,21 +317,6 @@ lws_service_timeout_check(struct lws *wsi, unsigned int sec)
pt->ah_wait_list_length,
pt->fds[wsi->sock].events);
#endif
lws_pt_lock(pt);
pwsi = &pt->ah_wait_list;
if (!pwsi)
return 0;
while (*pwsi) {
if (*pwsi == wsi)
break;
pwsi = &(*pwsi)->u.hdr.ah_wait_list;
lwsl_err("%s: pwsi=%p\n", __func__, pwsi);
}
lws_pt_unlock(pt);
if (!*pwsi)
lwsl_err("*** not on ah wait list ***\n");
/*
* Since he failed a timeout, he already had a chance to do
* something and was unable to... that includes situations like
@ -339,6 +325,10 @@ lws_service_timeout_check(struct lws *wsi, unsigned int sec)
* cleanup like flush partials.
*/
wsi->socket_is_permanently_unusable = 1;
if (wsi->mode == LWSCM_WSCL_WAITING_SSL)
wsi->context->protocols[0].callback(wsi,
LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
wsi->user_space, NULL, 0);
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
return 1;
@ -359,6 +349,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);
@ -383,13 +375,13 @@ lws_service_adjust_timeout(struct lws_context *context, int timeout_ms, int tsi)
/* 1) if we know we are draining rx ext, do not wait in poll */
if (pt->rx_draining_ext_list)
timeout_ms = 0;
return 0;
#ifdef LWS_OPENSSL_SUPPORT
/* 2) if we know we have non-network pending data, do not wait in poll */
if (lws_ssl_anybody_has_buffered_read_tsi(context, tsi)) {
timeout_ms = 0;
lwsl_err("ssl buffered read\n");
lwsl_info("ssl buffered read\n");
return 0;
}
#endif
@ -398,8 +390,7 @@ lws_service_adjust_timeout(struct lws_context *context, int timeout_ms, int tsi)
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);
timeout_ms = 0;
break;
return 0;
}
return timeout_ms;
@ -617,9 +608,6 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
n = lws_server_socket_service(context, wsi, pollfd);
if (n) /* closed by above */
return 1;
pending = lws_ssl_pending(wsi);
if (pending)
goto handle_pending;
goto handled;
case LWSCM_WS_SERVING:
@ -806,7 +794,6 @@ drain:
pending = lws_ssl_pending(wsi);
if (pending) {
handle_pending:
pending = pending > LWS_MAX_SOCKET_IO_BUF ?
LWS_MAX_SOCKET_IO_BUF : pending;
goto read;

View file

@ -99,7 +99,6 @@ static const unsigned int _K[] =
sha1_step(ctxt); \
}
static void sha1_step __P((struct sha1_ctxt *));
static void
sha1_step(struct sha1_ctxt *ctxt)

View file

@ -125,6 +125,7 @@ void lws_http2_configure_if_upgraded(struct lws *wsi)
return;
}
(void)method;
lwsl_info("negotiated %s using %s\n", name, method);
wsi->use_ssl = 1;
if (strncmp((char *)name, "http/1.1", 8) == 0)

144
lib/ssl.c
View file

@ -24,6 +24,10 @@
#include <openssl/err.h>
#endif
#ifdef LWS_HAVE_OPENSSL_ECDH_H
#include <openssl/ecdh.h>
#endif
int openssl_websocket_private_data_index;
static int
@ -84,6 +88,85 @@ OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
return !n;
}
static int
lws_context_ssl_init_ecdh(struct lws_context *context)
{
#ifdef LWS_SSL_SERVER_WITH_ECDH_CERT
int KeyType;
EC_KEY *EC_key = NULL;
X509 *x;
EVP_PKEY *pkey;
if (!(context->options & LWS_SERVER_OPTION_SSL_ECDH))
return 0;
lwsl_notice(" Using ECDH certificate support\n");
/* Get X509 certificate from ssl context */
x = sk_X509_value(context->ssl_ctx->extra_certs, 0);
if (!x) {
lwsl_err("%s: x is NULL\n", __func__);
return 1;
}
/* Get the public key from certificate */
pkey = X509_get_pubkey(x);
if (!pkey) {
lwsl_err("%s: pkey is NULL\n", __func__);
return 1;
}
/* Get the key type */
KeyType = EVP_PKEY_type(pkey->type);
if (EVP_PKEY_EC != KeyType) {
lwsl_notice("Key type is not EC\n");
return 0;
}
/* Get the key */
EC_key = EVP_PKEY_get1_EC_KEY(pkey);
/* Set ECDH parameter */
if (!EC_key) {
lwsl_err("%s: ECDH key is NULL \n", __func__);
return 1;
}
SSL_CTX_set_tmp_ecdh(context->ssl_ctx, EC_key);
EC_KEY_free(EC_key);
#endif
return 0;
}
static int
lws_context_ssl_init_ecdh_curve(struct lws_context_creation_info *info,
struct lws_context *context)
{
#ifdef LWS_HAVE_OPENSSL_ECDH_H
EC_KEY *ecdh;
int ecdh_nid;
const char *ecdh_curve = "prime256v1";
ecdh_nid = OBJ_sn2nid(ecdh_curve);
if (NID_undef == ecdh_nid) {
lwsl_err("SSL: Unknown curve name '%s'", ecdh_curve);
return 1;
}
ecdh = EC_KEY_new_by_curve_name(ecdh_nid);
if (NULL == ecdh) {
lwsl_err("SSL: Unable to create curve '%s'", ecdh_curve);
return 1;
}
SSL_CTX_set_tmp_ecdh(context->ssl_ctx, ecdh);
EC_KEY_free(ecdh);
SSL_CTX_set_options(context->ssl_ctx, SSL_OP_SINGLE_ECDH_USE);
lwsl_notice(" SSL ECDH curve '%s'\n", ecdh_curve);
#else
lwsl_notice(" OpenSSL doesn't support ECDH\n");
#endif
return 0;
}
LWS_VISIBLE int
lws_context_init_server_ssl(struct lws_context_creation_info *info,
struct lws_context *context)
@ -92,12 +175,6 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
struct lws wsi;
int error;
int n;
#ifdef LWS_SSL_SERVER_WITH_ECDH_CERT
int KeyType;
EC_KEY *EC_key = NULL;
X509 *x;
EVP_PKEY *pkey;
#endif
if (info->port != CONTEXT_PORT_NO_LISTEN) {
@ -170,6 +247,7 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
#ifdef SSL_OP_NO_COMPRESSION
SSL_CTX_set_options(context->ssl_ctx, SSL_OP_NO_COMPRESSION);
#endif
SSL_CTX_set_options(context->ssl_ctx, SSL_OP_SINGLE_DH_USE);
SSL_CTX_set_options(context->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
if (info->ssl_cipher_list)
SSL_CTX_set_cipher_list(context->ssl_ctx,
@ -190,16 +268,25 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
SSL_CTX_set_verify(context->ssl_ctx,
verify_options, OpenSSL_verify_callback);
}
/*
* give user code a chance to load certs into the server
* allowing it to verify incoming client certs
*/
/*
* give user code a chance to load certs into the server
* allowing it to verify incoming client certs
*/
context->protocols[0].callback(&wsi,
if (info->ssl_ca_filepath &&
!SSL_CTX_load_verify_locations(context->ssl_ctx,
info->ssl_ca_filepath, NULL)) {
lwsl_err("%s: SSL_CTX_load_verify_locations unhappy\n");
}
if (lws_context_ssl_init_ecdh_curve(info, context))
return -1;
context->protocols[0].callback(&wsi,
LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS,
context->ssl_ctx, NULL, 0);
}
if (info->options & LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT)
/* Normally SSL listener rejects non-ssl, optionally allow */
@ -249,33 +336,8 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
return 1;
}
#ifdef LWS_SSL_SERVER_WITH_ECDH_CERT
if (context->options & LWS_SERVER_OPTION_SSL_ECDH) {
lwsl_notice(" Using ECDH certificate support\n");
/* Get X509 certificate from ssl context */
x = sk_X509_value(context->ssl_ctx->extra_certs, 0);
/* Get the public key from certificate */
pkey = X509_get_pubkey(x);
/* Get the key type */
KeyType = EVP_PKEY_type(pkey->type);
if (EVP_PKEY_EC != KeyType) {
lwsl_err("Key type is not EC\n");
return 1;
}
/* Get the key */
EC_key = EVP_PKEY_get1_EC_KEY(pkey);
/* Set ECDH parameter */
if (!EC_key) {
error = ERR_get_error();
lwsl_err("ECDH key is NULL \n");
return 1;
}
SSL_CTX_set_tmp_ecdh(context->ssl_ctx, EC_key);
EC_KEY_free(EC_key);
}
#endif
if (lws_context_ssl_init_ecdh(context))
return 1;
/*
* SSL is happy and has a cert it's content with
@ -297,6 +359,7 @@ lws_ssl_destroy(struct lws_context *context)
if (!context->user_supplied_ssl_ctx && context->ssl_client_ctx)
SSL_CTX_free(context->ssl_client_ctx);
#if (OPENSSL_VERSION_NUMBER < 0x10100006L)
#if (OPENSSL_VERSION_NUMBER < 0x01000000) || defined(USE_WOLFSSL)
ERR_remove_state(0);
#else
@ -305,6 +368,7 @@ lws_ssl_destroy(struct lws_context *context)
ERR_free_strings();
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
#endif
}
LWS_VISIBLE void
@ -770,6 +834,7 @@ lws_ssl_context_destroy(struct lws_context *context)
if (!context->user_supplied_ssl_ctx && context->ssl_client_ctx)
SSL_CTX_free(context->ssl_client_ctx);
#if (OPENSSL_VERSION_NUMBER < 0x10100006L)
#if (OPENSSL_VERSION_NUMBER < 0x01000000) || defined(USE_WOLFSSL)
ERR_remove_state(0);
#else
@ -778,4 +843,5 @@ lws_ssl_context_destroy(struct lws_context *context)
ERR_free_strings();
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
#endif
}

View file

@ -1674,3 +1674,27 @@ Otherwise a default timeout is used.
<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,11 +1,11 @@
Name: libwebsockets
Version: 1.7.0
Version: 1.7.9
Release: 1%{?dist}
Summary: Websocket Server and Client Library
Group: System Environment/Libraries
License: LGPLv2 with exceptions
URL: http://warmcat.com
URL: https://libwebsockets.org
Source0: %{name}-%{version}.tar.gz
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
@ -55,10 +55,11 @@ rm -rf $RPM_BUILD_ROOT
/usr/bin/libwebsockets-test-echo
/usr/bin/libwebsockets-test-fraggle
/usr/bin/libwebsockets-test-fuzxy
/%{_libdir}/libwebsockets.so.6
/%{_libdir}/libwebsockets.so.7.1
/%{_libdir}/libwebsockets.so
/%{_libdir}/cmake/libwebsockets/LibwebsocketsConfig.cmake
/%{_libdir}/cmake/libwebsockets/LibwebsocketsConfigVersion.cmake
/%{_libdir}/cmake/libwebsockets/LibwebsocketsTargets.cmake
/usr/share/libwebsockets-test-server
%doc
%files devel
@ -69,6 +70,37 @@ rm -rf $RPM_BUILD_ROOT
/%{_libdir}/pkgconfig/libwebsockets.pc
%changelog
* Thu Sep 15 2016 Andy Green <andy@warmcat.com> 1.7.9-1
- MINOR fixes Upstream 1.7.9 release (see changelog)
* Thu May 12 2016 Andy Green <andy@warmcat.com> 1.7.8-1
- MINOR fixes Upstream 1.7.8 release (see changelog)
* Sat May 03 2016 Andy Green <andy@warmcat.com> 1.7.7-1
- MINOR fixes Upstream 1.7.7 release (see changelog)
* Sat Apr 22 2016 Andy Green <andy@warmcat.com> 1.7.6-1
- MINOR fixes Upstream 1.7.6 release (see changelog)
* Fri Apr 1 2016 Andy Green <andy@warmcat.com> 1.7.5-1
- MAJOR fixes Upstream 1.7.5 release (see changelog)
* Tue Mar 29 2016 Andy Green <andy@warmcat.com> 1.7.4-2
- MINOR added LibwebsocketsTargets.cmake
* Mon Mar 22 2016 Andy Green <andy@warmcat.com> 1.7.4-1
- MINOR fixes Upstream 1.7.4 release (see changelog)
* Mon Feb 29 2016 Andy Green <andy@warmcat.com> 1.7.3-1
- MAJOR fixes Upstream 1.7.3 release (see changelog)
* Thu Feb 25 2016 Andy Green <andy@warmcat.com> 1.7.2-1
- MINOR Upstream 1.7.2 release (see changelog)
* Sat Feb 20 2016 Andy Green <andy@warmcat.com> 1.7.1-1
- MINOR Upstream 1.7.1 release (see changelog)
* Tue Feb 16 2016 Andy Green <andy@warmcat.com> 1.7.0-1
- MAJOR SONAMEBUMP APICHANGES Upstream 1.7.0 release

View file

@ -74,6 +74,9 @@
/* SSL server using ECDH certificate */
#cmakedefine LWS_SSL_SERVER_WITH_ECDH_CERT
/* whether the Openssl is recent enough, and / or built with, ecdh */
#cmakedefine LWS_HAVE_OPENSSL_ECDH_H
/* Maximum supported service threads */
#define LWS_MAX_SMP ${LWS_MAX_SMP}

View file

@ -38,6 +38,11 @@ Release Checklist
set(SOVERSION "6")
libwebsockets.spec
-/%{_libdir}/libwebsockets.so.6
+/%{_libdir}/libwebsockets.so.7
3) changelog
a) Add next version tag header.

View file

@ -35,6 +35,29 @@ function check {
fi
fi
if [ "$1" = "rejected" ] ; then
if [ -z "`grep '<h1>406</h1>' /tmp/lwscap`" ] ; then
echo "FAIL: should have told forbidden (test server has no dirs)"
exit 1
fi
fi
if [ "$1" = "media" ] ; then
if [ -z "`grep '<h1>415</h1>' /tmp/lwscap`" ] ; then
echo "FAIL: should have told unknown media type"
exit 1
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
@ -66,7 +89,7 @@ function check {
rm -rf $LOG
killall libwebsockets-test-server 2>/dev/null
libwebsockets-test-server -d31 2>> $LOG &
libwebsockets-test-server -d15 2>> $LOG &
CPID=$!
while [ -z "`grep Listening $LOG`" ] ; do
@ -91,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
@ -208,11 +232,18 @@ echo -e "GET /test.html HTTP/1.1\x0d\x0a\x0d\x0aILLEGAL-PAYLOAD.................
check default
check
echo
echo "---- nonexistant 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
check
echo
echo "---- directory attack 1 (/../../../../etc/passwd should be /etc/passswd)"
rm -f /tmp/lwscap
echo -e "GET /../../../../etc/passwd HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
check forbidden
check rejected
check
echo
@ -254,14 +285,14 @@ echo
echo "---- directory attack 7 (/%2e%2e%2f../../../etc/passwd should be /etc/passswd)"
rm -f /tmp/lwscap
echo -e "GET /%2e%2e%2f../../../etc/passwd HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
check forbidden
check rejected
check
echo
echo "---- directory attack 8 (%2f%2e%2e%2f%2e./.%2e/.%2e%2fetc/passwd should be /etc/passswd)"
rm -f /tmp/lwscap
echo -e "GET %2f%2e%2e%2f%2e./.%2e/.%2e%2fetc/passwd HTTP/1.1\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
check forbidden
check rejected
check
echo
@ -274,6 +305,449 @@ if [ "$good" != "`md5sum /tmp/lwsdump | cut -d' ' -f 1`" ] ; then
exit 1
fi
echo
echo "---- mass testing uri variations"
rm -f /tmp/results
for i in \
/..../ \
/.../. \
/...// \
/.../a \
/.../w \
/.../? \
/.../% \
/../.. \
/.././ \
/../.a \
/../.w \
/../.. \
/../.% \
/..//. \
/../// \
/..//a \
/..//w \
/..//? \
/..//% \
/../a. \
/../a/ \
/../aa \
/../aw \
/../a? \
/../a% \
/../w. \
/../w/ \
/../wa \
/../ww \
/../w? \
/../w% \
/../?. \
/../?/ \
/../?a \
/../?w \
/../?? \
/../?% \
/../%. \
/../%/ \
/../%a \
/../%w \
/../%? \
/../%% \
/./... \
/./../ \
/./..a \
/./..w \
/./..? \
/./..% \
/.//.. \
/.a../ \
/.a/.. \
/.w../ \
/.w/.. \
/.?../ \
/../.. \
/.%../ \
/.%/.. \
//.... \
//.../ \
//...a \
//...w \
//...? \
//...% \
//../. \
//..// \
//../a \
//../w \
//../? \
//../% \
//..a. \
//..a/ \
//..aa \
//..aw \
//..a? \
//..a% \
//..w. \
//..w/ \
//..wa \
//..ww \
//..w? \
//..w% \
//..?. \
//..?/ \
//..?a \
//..?w \
//..?? \
//..?% \
//..%. \
//..%/ \
//..%a \
//..%w \
//..%? \
//..%% \
//./.. \
///... \
///../ \
///..a \
///..w \
///..? \
///..% \
////.. \
//a../ \
//a/.. \
//w../ \
//w/.. \
//?../ \
//?/.. \
//%../ \
//%/.. \
/a.../ \
/a../. \
/a..// \
/a../a \
/a../w \
/a../? \
/a../% \
/a./.. \
/a/... \
/a/../ \
/a/..a \
/a/..w \
/a/..? \
/a/..% \
/a//.. \
/aa../ \
/aa/.. \
/aw../ \
/aw/.. \
/a?../ \
/a?/.. \
/a%../ \
/a%/.. \
/w.../ \
/w../. \
/w..// \
/w../a \
/w../w \
/w../? \
/w../% \
/w./.. \
/w/... \
/w/../ \
/w/..a \
/w/..w \
/w/..? \
/w/..% \
/w//.. \
/wa../ \
/wa/.. \
/ww../ \
/ww/.. \
/w?../ \
/w?/.. \
/w%../ \
/w%/.. \
/?.../ \
/?../. \
/?..// \
/?../a \
/?../w \
/?../? \
/?../% \
/?./.. \
/?/... \
/?/../ \
/?/..a \
/?/..w \
/?/..? \
/?/..% \
/?//.. \
/?a../ \
/?a/.. \
/?w../ \
/?w/.. \
/??../ \
/??/.. \
/?%../ \
/?%/.. \
/%.../ \
/%../. \
/%..// \
/%../a \
/%../w \
/%../? \
/%../% \
/%./.. \
/%/... \
/%/../ \
/%/..a \
/%/..w \
/%/..? \
/%/..% \
/%//.. \
/%a../ \
/%a/.. \
/%w../ \
/%w/.. \
/%?../ \
/%?/.. \
/%%../ \
/%%/.. \
/a/w/../a \
/path/to/dir/../other/dir \
; do
R=`rm -f /tmp/lwscap ; echo -n -e "GET $i HTTP/1.0\r\n\r\n" | nc localhost 7681 2>/dev/null >/tmp/lwscap; head -n1 /tmp/lwscap| cut -d' ' -f2`
cat /tmp/lwscap | head -n1
echo ==== $R
if [ "$R" != "403" ]; then
U=`cat $LOG | grep lws_http_serve | tail -n 1 | cut -d':' -f3 | cut -d' ' -f2`
echo $U
echo "- \"$i\" -> $R \"$U\"" >>/tmp/results
else
echo "- \"$i\" -> $R" >>/tmp/results
fi
done
cat <<EOF >/tmp/lwsresult1
- "/..../" -> 406 "/..../"
- "/.../." -> 406 "/.../"
- "/...//" -> 406 "/.../"
- "/.../a" -> 406 "/.../a"
- "/.../w" -> 406 "/.../w"
- "/.../?" -> 406 "/.../"
- "/.../%" -> 403
- "/../.." -> 200 "/"
- "/.././" -> 200 "/"
- "/../.a" -> 415 "/.a"
- "/../.w" -> 415 "/.w"
- "/../.." -> 200 "/"
- "/../.%" -> 403
- "/..//." -> 200 "/"
- "/..///" -> 200 "/"
- "/..//a" -> 415 "/a"
- "/..//w" -> 415 "/w"
- "/..//?" -> 200 "/"
- "/..//%" -> 403
- "/../a." -> 415 "/a."
- "/../a/" -> 406 "/a/"
- "/../aa" -> 415 "/aa"
- "/../aw" -> 415 "/aw"
- "/../a?" -> 415 "/a"
- "/../a%" -> 403
- "/../w." -> 415 "/w."
- "/../w/" -> 406 "/w/"
- "/../wa" -> 415 "/wa"
- "/../ww" -> 415 "/ww"
- "/../w?" -> 415 "/w"
- "/../w%" -> 403
- "/../?." -> 200 "/"
- "/../?/" -> 200 "/"
- "/../?a" -> 200 "/"
- "/../?w" -> 200 "/"
- "/../??" -> 200 "/"
- "/../?%" -> 403
- "/../%." -> 403
- "/../%/" -> 403
- "/../%a" -> 403
- "/../%w" -> 403
- "/../%?" -> 403
- "/../%%" -> 403
- "/./..." -> 415 "/..."
- "/./../" -> 200 "/"
- "/./..a" -> 415 "/..a"
- "/./..w" -> 415 "/..w"
- "/./..?" -> 200 "/"
- "/./..%" -> 403
- "/.//.." -> 200 "/"
- "/.a../" -> 406 "/.a../"
- "/.a/.." -> 200 "/"
- "/.w../" -> 406 "/.w../"
- "/.w/.." -> 200 "/"
- "/.?../" -> 415 "/."
- "/../.." -> 200 "/"
- "/.%../" -> 403
- "/.%/.." -> 403
- "//...." -> 415 "/...."
- "//.../" -> 406 "/.../"
- "//...a" -> 415 "/...a"
- "//...w" -> 415 "/...w"
- "//...?" -> 415 "/..."
- "//...%" -> 403
- "//../." -> 200 "/"
- "//..//" -> 200 "/"
- "//../a" -> 415 "/a"
- "//../w" -> 415 "/w"
- "//../?" -> 200 "/"
- "//../%" -> 403
- "//..a." -> 415 "/..a."
- "//..a/" -> 406 "/..a/"
- "//..aa" -> 415 "/..aa"
- "//..aw" -> 415 "/..aw"
- "//..a?" -> 415 "/..a"
- "//..a%" -> 403
- "//..w." -> 415 "/..w."
- "//..w/" -> 406 "/..w/"
- "//..wa" -> 415 "/..wa"
- "//..ww" -> 415 "/..ww"
- "//..w?" -> 415 "/..w"
- "//..w%" -> 403
- "//..?." -> 200 "/"
- "//..?/" -> 200 "/"
- "//..?a" -> 415 "/a"
- "//..?w" -> 415 "/w"
- "//..??" -> 200 "/"
- "//..?%" -> 403
- "//..%." -> 403
- "//..%/" -> 403
- "//..%a" -> 403
- "//..%w" -> 403
- "//..%?" -> 403
- "//..%%" -> 403
- "//./.." -> 200 "/"
- "///..." -> 415 "/..."
- "///../" -> 200 "/"
- "///..a" -> 415 "/..a"
- "///..w" -> 415 "/..w"
- "///..?" -> 200 "/"
- "///..%" -> 403
- "////.." -> 200 "/"
- "//a../" -> 406 "/a../"
- "//a/.." -> 200 "/"
- "//w../" -> 406 "/w../"
- "//w/.." -> 200 "/"
- "//?../" -> 200 "/"
- "//?/.." -> 200 "/"
- "//%../" -> 403
- "//%/.." -> 403
- "/a.../" -> 406 "/a.../"
- "/a../." -> 406 "/a../"
- "/a..//" -> 406 "/a../"
- "/a../a" -> 406 "/a../a"
- "/a../w" -> 406 "/a../w"
- "/a../?" -> 406 "/a../"
- "/a../%" -> 403
- "/a./.." -> 200 "/"
- "/a/..." -> 406 "/a/..."
- "/a/../" -> 200 "/"
- "/a/..a" -> 406 "/a/..a"
- "/a/..w" -> 406 "/a/..w"
- "/a/..?" -> 200 "/"
- "/a/..%" -> 403
- "/a//.." -> 200 "/"
- "/aa../" -> 406 "/aa../"
- "/aa/.." -> 200 "/"
- "/aw../" -> 406 "/aw../"
- "/aw/.." -> 200 "/"
- "/a?../" -> 415 "/a"
- "/a?/.." -> 415 "/a"
- "/a%../" -> 403
- "/a%/.." -> 403
- "/w.../" -> 406 "/w.../"
- "/w../." -> 406 "/w../"
- "/w..//" -> 406 "/w../"
- "/w../a" -> 406 "/w../a"
- "/w../w" -> 406 "/w../w"
- "/w../?" -> 406 "/w../"
- "/w../%" -> 403
- "/w./.." -> 200 "/"
- "/w/..." -> 406 "/w/..."
- "/w/../" -> 200 "/"
- "/w/..a" -> 406 "/w/..a"
- "/w/..w" -> 406 "/w/..w"
- "/w/..?" -> 200 "/"
- "/w/..%" -> 403
- "/w//.." -> 200 "/"
- "/wa../" -> 406 "/wa../"
- "/wa/.." -> 200 "/"
- "/ww../" -> 406 "/ww../"
- "/ww/.." -> 200 "/"
- "/w?../" -> 415 "/w"
- "/w?/.." -> 415 "/w"
- "/w%../" -> 403
- "/w%/.." -> 403
- "/?.../" -> 200 "/"
- "/?../." -> 200 "/"
- "/?..//" -> 200 "/"
- "/?../a" -> 200 "/"
- "/?../w" -> 200 "/"
- "/?../?" -> 200 "/"
- "/?../%" -> 403
- "/?./.." -> 200 "/"
- "/?/..." -> 200 "/"
- "/?/../" -> 200 "/"
- "/?/..a" -> 200 "/"
- "/?/..w" -> 200 "/"
- "/?/..?" -> 200 "/"
- "/?/..%" -> 403
- "/?//.." -> 200 "/"
- "/?a../" -> 200 "/"
- "/?a/.." -> 200 "/"
- "/?w../" -> 200 "/"
- "/?w/.." -> 200 "/"
- "/??../" -> 200 "/"
- "/??/.." -> 200 "/"
- "/?%../" -> 403
- "/?%/.." -> 403
- "/%.../" -> 403
- "/%../." -> 403
- "/%..//" -> 403
- "/%../a" -> 403
- "/%../w" -> 403
- "/%../?" -> 403
- "/%../%" -> 403
- "/%./.." -> 403
- "/%/..." -> 403
- "/%/../" -> 403
- "/%/..a" -> 403
- "/%/..w" -> 403
- "/%/..?" -> 403
- "/%/..%" -> 403
- "/%//.." -> 403
- "/%a../" -> 403
- "/%a/.." -> 403
- "/%w../" -> 403
- "/%w/.." -> 403
- "/%?../" -> 403
- "/%?/.." -> 403
- "/%%../" -> 403
- "/%%/.." -> 403
- "/a/w/../a" -> 406 "/a/a"
- "/path/to/dir/../other/dir" -> 406 "/path/to/other/dir"
EOF
if [ "`md5sum /tmp/results | cut -d' ' -f 1`" != "`md5sum /tmp/lwsresult1 | cut -d' ' -f1`" ] ; then
echo "Differences..."
diff -urN /tmp/results /tmp/lwsresult1
exit 1
else
echo "OK"
fi
echo
echo "--- survived OK ---"
kill -2 $CPID

View file

@ -62,6 +62,10 @@
#include <sys/socket.h>
#endif
#if defined(__NetBSD__)
#include <netinet/in.h>
#endif
#define MAX_FUZZ_BUF (1024 * 1024)
enum types {
@ -953,4 +957,3 @@ bail1:
return 0;
}

View file

@ -0,0 +1,12 @@
[Unit]
Description=Libwebsockets test server
After=syslog.target
[Service]
ExecStart=/usr/local/bin/libwebsockets-test-server --ssl -C /etc/pki/tls/certs/libwebsockets.org.crt -K /etc/pki/tls/private/libwebsockets.org.key -A /etc/pki/tls/certs/libwebsockets.org.cer --port 7681 -u 99 -g 99 --daemonize
Type=forking
PIDFile=/tmp/.lwsts-lock
[Install]
WantedBy=multi-user.target

View file

@ -206,13 +206,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,
@ -335,7 +335,15 @@ int main(int argc, char **argv)
if (!strcmp(prot, "http") || !strcmp(prot, "ws"))
use_ssl = 0;
if (!strcmp(prot, "https") || !strcmp(prot, "wss"))
use_ssl = 1;
if (!use_ssl)
use_ssl = 1;
if (use_ssl) {
if (use_ssl == 1)
lwsl_notice(" Cert must validate correctly (use -s to allow selfsigned)\n");
else
lwsl_notice(" Selfsigned certs allowed\n");
}
/*
* create the websockets context. This tracks open connections and

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:

View file

@ -346,7 +346,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

@ -450,7 +450,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

@ -134,9 +134,12 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
struct lws_pollargs *pa = (struct lws_pollargs *)in;
#endif
switch (reason) {
case LWS_CALLBACK_HTTP:
lwsl_notice("lws_http_serve: %s\n",in);
if (debug_level & LLL_INFO) {
dump_handshake_info(wsi);
@ -147,6 +150,15 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
lwsl_notice("URI Arg %d: %s\n", ++n, buf);
}
}
{
char name[100], rip[50];
lws_get_peer_addresses(wsi, lws_get_socket_fd(wsi), name,
sizeof(name), rip, sizeof(rip));
sprintf(buf, "%s (%s)", name, rip);
lwsl_notice("HTTP connect from %s\n", buf);
}
if (len < 1) {
lws_return_http_status(wsi,
HTTP_STATUS_BAD_REQUEST, NULL);
@ -155,7 +167,7 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
/* this example server has no concept of directories */
if (strchr((const char *)in + 1, '/')) {
lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
lws_return_http_status(wsi, HTTP_STATUS_NOT_ACCEPTABLE, NULL);
goto try_to_reuse;
}
@ -259,8 +271,8 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
/* demonstrates how to set a cookie on / */
other_headers = NULL;
n = 0;
other_headers = leaf_path;
p = (unsigned char *)leaf_path;
if (!strcmp((const char *)in, "/") &&
!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) {
/* this isn't very unguessable but it'll do for us */
@ -269,16 +281,22 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
(unsigned int)tv.tv_sec,
(unsigned int)tv.tv_usec);
p = (unsigned char *)leaf_path;
if (lws_add_http_header_by_name(wsi,
(unsigned char *)"set-cookie:",
(unsigned char *)b64, n, &p,
(unsigned char *)leaf_path + sizeof(leaf_path)))
return 1;
n = (char *)p - leaf_path;
other_headers = leaf_path;
}
if (lws_is_ssl(wsi) && lws_add_http_header_by_name(wsi,
(unsigned char *)
"Strict-Transport-Security:",
(unsigned char *)
"max-age=15768000 ; "
"includeSubDomains", 36, &p,
(unsigned char *)leaf_path +
sizeof(leaf_path)))
return 1;
n = (char *)p - leaf_path;
n = lws_serve_http_file(wsi, buf, mimetype, other_headers, n);
if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi)))

View file

@ -31,7 +31,7 @@ struct lws_plat_file_ops fops_plat;
char *resource_path = LOCAL_RESOURCE_PATH;
/*
* libev dumps their hygeine problems on their users blaming compiler
* libev dumps their hygiene problems on their users blaming compiler
* http://lists.schmorp.de/pipermail/libev/2008q4/000442.html
*/

View file

@ -89,6 +89,12 @@ static struct lws_protocols protocols[] = {
sizeof(struct per_session_data__lws_mirror),
128,
},
{
"lws-status",
callback_lws_status,
sizeof(struct per_session_data__lws_status),
128,
},
{ NULL, NULL, 0, 0 } /* terminator */
};
@ -106,7 +112,7 @@ static const struct lws_extension exts[] = {
{ NULL, NULL, NULL /* terminator */ }
};
void signal_cb(uv_signal_t *watcher, int revents)
void signal_cb(uv_loop_t *loop, uv_signal_t *watcher, int signum)
{
lwsl_err("Signal %d caught, exiting...\n", watcher->signum);
switch (watcher->signum) {
@ -122,9 +128,8 @@ void signal_cb(uv_signal_t *watcher, int revents)
}
static void
uv_timeout_cb(uv_timer_t *w)
uv_timeout_cb_dumb_increment(uv_timer_t *w)
{
lwsl_info("%s\n", __func__);
lws_callback_on_writable_all_protocol(context,
&protocols[PROTOCOL_DUMB_INCREMENT]);
}
@ -222,7 +227,8 @@ int main(int argc, char **argv)
}
}
#if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32)
#if !defined(WIN32)
#if !defined(LWS_NO_DAEMONIZE)
/*
* normally lock path would be /var/lock/lwsts or similar, to
* simplify getting started without having to take care about
@ -237,6 +243,7 @@ int main(int argc, char **argv)
/* we will only try to log things according to our debug_level */
setlogmask(LOG_UPTO (LOG_DEBUG));
openlog("lwsts", syslog_options, LOG_DAEMON);
#endif
/* tell the library what debug level to emit and to send it to syslog */
lws_set_log_level(debug_level, lwsl_emit_syslog);
@ -273,6 +280,7 @@ int main(int argc, char **argv)
info.gid = -1;
info.uid = -1;
info.max_http_header_pool = 1;
info.timeout_secs = 5;
info.options = opts | LWS_SERVER_OPTION_LIBUV;
context = lws_create_context(&info);
@ -281,10 +289,12 @@ int main(int argc, char **argv)
return -1;
}
lws_uv_initloop(context, NULL, signal_cb, 0);
lws_uv_sigint_cfg(context, 1, signal_cb);
lws_uv_initloop(context, NULL, NULL, 0);
uv_timer_init(lws_uv_getloop(context, 0), &timeout_watcher);
uv_timer_start(&timeout_watcher, uv_timeout_cb, 50, 50);
uv_timer_start(&timeout_watcher, uv_timeout_cb_dumb_increment, 50, 50);
lws_libuv_run(context, 0);

View file

@ -360,7 +360,7 @@ int main(int argc, char **argv)
/* wait for all the service threads to exit */
for (n = 0; n < lws_get_count_threads(context); n++)
while ((--n) >= 0)
pthread_join(pthread_service[n], &retval);
/* wait for pthread_dumb to exit */

View file

@ -0,0 +1,168 @@
/*
* libwebsockets-test-server - libwebsockets test implementation
*
* Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
*
* This file is made available under the Creative Commons CC0 1.0
* Universal Public Domain Dedication.
*
* The person who associated a work with this deed has dedicated
* the work to the public domain by waiving all of his or her rights
* to the work worldwide under copyright law, including all related
* and neighboring rights, to the extent allowed by law. You can copy,
* modify, distribute and perform the work, even for commercial purposes,
* all without asking permission.
*
* The test apps are intended to be adapted for use in your code, which
* may be proprietary. So unlike the library itself, they are licensed
* Public Domain.
*/
#include "test-server.h"
#include <time.h>
static unsigned char server_info[1024];
static int server_info_len;
static int current;
static char cache[16384];
static int cache_len;
static struct per_session_data__lws_status *list;
static int live_wsi;
static void
update_status(struct lws *wsi, struct per_session_data__lws_status *pss)
{
struct per_session_data__lws_status **pp = &list;
int subsequent = 0;
char *p = cache + LWS_PRE, *start = p;
char date[128];
time_t t;
struct tm *ptm;
#ifndef WIN32
struct tm tm;
#endif
p += lws_snprintf(p, 512, " { %s, \"wsi\":\"%d\", \"conns\":[",
server_info, live_wsi);
/* render the list */
while (*pp) {
t = (*pp)->tv_established.tv_sec;
#ifdef WIN32
ptm = localtime(&t);
if (!ptm)
#else
ptm = &tm;
if (!localtime_r(&t, &tm))
#endif
strcpy(date, "unknown");
else
#ifdef WIN32
strftime(date, sizeof(date), "%Y %H:%M %Z", ptm);
#else
strftime(date, sizeof(date), "%F %H:%M %Z", ptm);
#endif
if ((p - start) > (sizeof(cache) - 512))
break;
if (subsequent)
*p++ = ',';
subsequent = 1;
p += lws_snprintf(p, sizeof(cache) - (p - start) - 1,
"{\"peer\":\"%s\",\"time\":\"%s\","
"\"ua\":\"%s\"}",
(*pp)->ip, date, (*pp)->user_agent);
pp = &((*pp)->list);
}
p += sprintf(p, "]}");
cache_len = p - start;
lwsl_err("cache_len %d\n", cache_len);
*p = '\0';
/* since we changed the list, increment the 'version' */
current++;
/* update everyone */
lws_callback_on_writable_all_protocol(lws_get_context(wsi),
lws_get_protocol(wsi));
}
/* lws-status protocol */
int
callback_lws_status(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len)
{
struct per_session_data__lws_status *pss =
(struct per_session_data__lws_status *)user,
**pp;
char name[128], rip[128];
int m;
switch (reason) {
case LWS_CALLBACK_PROTOCOL_INIT:
/*
* Prepare the static server info
*/
server_info_len = sprintf((char *)server_info,
"\"version\":\"%s\","
" \"hostname\":\"%s\"",
lws_get_library_version(),
lws_canonical_hostname(
lws_get_context(wsi)));
break;
case LWS_CALLBACK_ESTABLISHED:
/*
* we keep a linked list of live pss, so we can walk it
*/
pss->last = 0;
pss->list = list;
list = pss;
live_wsi++;
lws_get_peer_addresses(wsi, lws_get_socket_fd(wsi), name,
sizeof(name), rip, sizeof(rip));
sprintf(pss->ip, "%s (%s)", name, rip);
gettimeofday(&pss->tv_established, NULL);
strcpy(pss->user_agent, "unknown");
lws_hdr_copy(wsi, pss->user_agent, sizeof(pss->user_agent),
WSI_TOKEN_HTTP_USER_AGENT);
update_status(wsi, pss);
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
m = lws_write(wsi, (unsigned char *)cache + LWS_PRE, cache_len,
LWS_WRITE_TEXT);
if (m < server_info_len) {
lwsl_err("ERROR %d writing to di socket\n", m);
return -1;
}
break;
case LWS_CALLBACK_CLOSED:
/*
* remove ourselves from live pss list
*/
lwsl_err("CLOSING pss %p ********\n", pss);
pp = &list;
while (*pp) {
if (*pp == pss) {
*pp = pss->list;
pss->list = NULL;
live_wsi--;
break;
}
pp = &((*pp)->list);
}
update_status(wsi, pss);
break;
default:
break;
}
return 0;
}

View file

@ -68,6 +68,7 @@ enum demo_protocols {
PROTOCOL_DUMB_INCREMENT,
PROTOCOL_LWS_MIRROR,
PROTOCOL_LWS_ECHOGEN,
PROTOCOL_LWS_STATUS,
/* always last */
DEMO_PROTOCOL_COUNT
@ -88,19 +89,25 @@ static struct lws_protocols protocols[] = {
"dumb-increment-protocol",
callback_dumb_increment,
sizeof(struct per_session_data__dumb_increment),
10,
10, /* rx buf size must be >= permessage-deflate rx size */
},
{
"lws-mirror-protocol",
callback_lws_mirror,
sizeof(struct per_session_data__lws_mirror),
128,
128, /* rx buf size must be >= permessage-deflate rx size */
},
{
"lws-echogen",
callback_lws_echogen,
sizeof(struct per_session_data__echogen),
128,
128, /* rx buf size must be >= permessage-deflate rx size */
},
{
"lws-status",
callback_lws_status,
sizeof(struct per_session_data__lws_status),
128, /* rx buf size must be >= permessage-deflate rx size */
},
{ NULL, NULL, 0, 0 } /* terminator */
};
@ -155,6 +162,9 @@ static struct option options[] = {
{ "allow-non-ssl", no_argument, NULL, 'a' },
{ "interface", required_argument, NULL, 'i' },
{ "closetest", no_argument, NULL, 'c' },
{ "ssl-cert", required_argument, NULL, 'C' },
{ "ssl-key", required_argument, NULL, 'K' },
{ "ssl-ca", required_argument, NULL, 'A' },
{ "libev", no_argument, NULL, 'e' },
#ifndef LWS_NO_DAEMONIZE
{ "daemonize", no_argument, NULL, 'D' },
@ -169,8 +179,10 @@ int main(int argc, char **argv)
char interface_name[128] = "";
unsigned int ms, oldms = 0;
const char *iface = NULL;
char cert_path[1024];
char key_path[1024];
char cert_path[1024] = "";
char key_path[1024] = "";
char ca_path[1024] = "";
int uid = -1, gid = -1;
int use_ssl = 0;
int opts = 0;
int n = 0;
@ -189,7 +201,7 @@ int main(int argc, char **argv)
info.port = 7681;
while (n >= 0) {
n = getopt_long(argc, argv, "eci:hsap:d:Dr:", options, NULL);
n = getopt_long(argc, argv, "eci:hsap:d:Dr:C:K:A:u:g:", options, NULL);
if (n < 0)
continue;
switch (n) {
@ -204,6 +216,12 @@ int main(int argc, char **argv)
#endif
break;
#endif
case 'u':
uid = atoi(optarg);
break;
case 'g':
gid = atoi(optarg);
break;
case 'd':
debug_level = atoi(optarg);
break;
@ -231,6 +249,15 @@ int main(int argc, char **argv)
resource_path = optarg;
printf("Setting resource path to \"%s\"\n", resource_path);
break;
case 'C':
strncpy(cert_path, optarg, sizeof cert_path);
break;
case 'K':
strncpy(key_path, optarg, sizeof key_path);
break;
case 'A':
strncpy(ca_path, optarg, sizeof ca_path);
break;
case 'h':
fprintf(stderr, "Usage: test-server "
"[--port=<p>] [--ssl] "
@ -248,7 +275,7 @@ int main(int argc, char **argv)
*/
if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) {
fprintf(stderr, "Failed to daemonize\n");
return 1;
return 10;
}
#endif
@ -287,23 +314,41 @@ int main(int argc, char **argv)
lwsl_err("resource path too long\n");
return -1;
}
sprintf(cert_path, "%s/libwebsockets-test-server.pem",
if (!cert_path[0])
sprintf(cert_path, "%s/libwebsockets-test-server.pem",
resource_path);
if (strlen(resource_path) > sizeof(key_path) - 32) {
lwsl_err("resource path too long\n");
return -1;
}
sprintf(key_path, "%s/libwebsockets-test-server.key.pem",
if (!key_path[0])
sprintf(key_path, "%s/libwebsockets-test-server.key.pem",
resource_path);
info.ssl_cert_filepath = cert_path;
info.ssl_private_key_filepath = key_path;
if (ca_path[0])
info.ssl_ca_filepath = ca_path;
}
info.gid = -1;
info.uid = -1;
info.max_http_header_pool = 1;
info.gid = gid;
info.uid = uid;
info.max_http_header_pool = 16;
info.options = opts | LWS_SERVER_OPTION_VALIDATE_UTF8;
info.extensions = exts;
info.timeout_secs = 5;
info.ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
"ECDHE-RSA-AES256-GCM-SHA384:"
"DHE-RSA-AES256-GCM-SHA384:"
"ECDHE-RSA-AES256-SHA384:"
"HIGH:!aNULL:!eNULL:!EXPORT:"
"!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:"
"!SHA1:!DHE-RSA-AES128-GCM-SHA256:"
"!DHE-RSA-AES128-SHA256:"
"!AES128-GCM-SHA256:"
"!AES128-SHA256:"
"!DHE-RSA-AES256-SHA256:"
"!AES256-GCM-SHA384:"
"!AES256-SHA256";
context = lws_create_context(&info);
if (context == NULL) {
lwsl_err("libwebsocket init failed\n");

View file

@ -94,6 +94,16 @@ struct per_session_data__echogen {
int wr;
};
struct per_session_data__lws_status {
struct per_session_data__lws_status *list;
struct timeval tv_established;
int last;
char ip[270];
char user_agent[512];
const char *pos;
int len;
};
extern int
callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
void *in, size_t len);
@ -106,6 +116,10 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
extern int
callback_lws_echogen(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len);
extern int
callback_lws_status(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len);
extern void
dump_handshake_info(struct lws *wsi);

View file

@ -4,12 +4,76 @@
<meta charset=utf-8 http-equiv="Content-Language" content="en"/>
<title>Minimal Websocket test app</title>
<style type="text/css">
div.title { font-size:18pt; font: Arial; font-weight:normal; text-align:center; color:#000000; }
span.title { font-size:18pt; font: Arial; font-weight:normal; text-align:center; color:#000000; }
.browser { font-size:18pt; font: Arial; font-weight:normal; text-align:center; color:#ffff00; vertical-align:middle; text-align:center; background:#d0b070; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px;}
.group2 { width:600px; vertical-align:middle; text-align:center; background:#f0f0e0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; }
.explain { vertical-align:middle; text-align:center; background:#f0f0c0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; color:#404000; }
.group2 { vertical-align:middle;
text-align:center;
background:#f0f0e0;
padding:12px;
-webkit-border-radius:10px;
-moz-border-radius:10px;
border-radius:10px; }
.explain { vertical-align:middle;
text-align:center;
background:#f0f0c0; padding:12px;
-webkit-border-radius:10px;
-moz-border-radius:10px;
border-radius:10px;
color:#404000; }
td.wsstatus { vertical-align:middle; width:200px; height:50px;
text-align:center;
background:#f0f0c0; padding:6px;
-webkit-border-radius:8px;
-moz-border-radius:8px;
border-radius:8px;
color:#404000; }
td.l { vertical-align:middle;
text-align:center;
background:#d0d0b0;
padding:3px;
-webkit-border-radius:3px;
-moz-border-radius:3px;
border-radius:3px; }
.content { vertical-align:top; text-align:center; background:#fffff0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; }
.canvas { vertical-align:top; text-align:center; background:#efefd0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; }
.tabs {
position: relative;
min-height: 750px; /* This part sucks */
clear: both;
margin: 25px 0;
}
.tab {
float: left;
}
.tab label {
background: #eee;
padding: 10px;
border: 1px solid #ccc;
margin-left: -1px;
position: relative;
left: 1px;
}
.tab [type=radio] {
display: none;
}
.content {
position: absolute;
top: 28px;
left: 0;
background: white;
right: 0;
bottom: 0;
padding: 20px;
border: 1px solid #ccc;
}
[type=radio]:checked ~ label {
background: white;
border-bottom: 1px solid white;
z-index: 2;
}
[type=radio]:checked ~ label ~ .content {
z-index: 1;
}
</style>
</head>
@ -19,33 +83,76 @@
<table><tr><td>
<table width="100%"><tr><td valign=middle align=center><a href="http://libwebsockets.org"><img src="/libwebsockets.org-logo.png"></a></td><td>
<section class="browser">Detected Browser: <div id=brow>...</div></section></td></tr></table>
<table width=600px>
<tr>
<td valign=middle align=center>
<a href="https://libwebsockets.org">
<img src="/libwebsockets.org-logo.png"></a></td><td>
<section class="browser">Detected Browser:
<div id=brow>...</div></section>
</td>
</tr>
</td></tr><tr><td>
<section id="increment" class="group2">
<div class="title">libwebsockets "dumb-increment-protocol"</div>
<table><tr><td>
<table class="content" width="200px">
<tr><td align=center><input type=button id=offset value="Reset counter" onclick="reset();" ></td></tr>
<tr><td width=200px align=center><div id=number> </div></td></tr>
<tr><td id=wsdi_statustd align=center class="explain"><div id=wsdi_status>Not initialized</div></td></tr>
</tr>
</table>
</td><td class="explain">
The incrementing number is coming from the server and is individual for
</td></tr>
<tr><td colspan=2 align=center>
Click <a href="/leaf.jpg" target="_blank">Here</a> to
have the test server send a big picture by http.
</td></tr>
<tr><td colspan=2>
<div class="tabs">
<div class="tab">
<input type="radio" id="tab-1" name="tab-group-1" checked>
<label for="tab-1">Dumb Increment Demo</label>
<div class="content">
<div id="dumb" class="group2">
<table>
<tr>
<td id=wsdi_statustd align=center class="wsstatus">
<span id=wsdi_status>Websocket connection not initialized</span></td>
<td><span class="title">dumb increment-protocol</span></td>
</tr>
<tr>
<td class="explain" colspan=2>
The incrementing number is coming from the server at 20Hz and is individual for
each connection to the server... try opening a second browser window.
<br/><br/>
The button zeros just this connection's number.
<br/><br/>
Click <a href="/leaf.jpg" target="_blank">Here</a> to have the test server send a big picture by http.
</td></tr></table>
</section>
<br>
<section id="mirror" class="group2">
<div class="title">libwebsockets "lws-mirror-protocol"</div>
<div class="explain">
The button sends a message over the websocket link to ask the server
to zero just this connection's number.
</td>
</tr>
<tr>
<td align=center><div id=number style="font-size:120%;"> </div></td>
<td align=center>
<input type=button id=offset value="Reset counter" onclick="reset();" >
<input type=button id=junk value="Send junk" onclick="junk();" >
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="tab">
<input type="radio" id="tab-2" name="tab-group-1">
<label for="tab-2">Mirror Demo</label>
<div class="content">
<div id="mirror" class="group2">
<table>
<tr>
<td colspan=1 id=wslm_statustd align=center class="wsstatus">
<span id=wslm_status>Websocket connection not initialized</span>
</td>
<td>
<span class="title">lws-mirror-protocol</span>
</td>
</tr>
<tr>
<td colspan=2>
<div class="explain">
Use the mouse to draw on the canvas below -- all other browser windows open
on this page see your drawing in realtime and you can see any of theirs as
well.
@ -56,57 +163,118 @@ protocol, including the guy who sent the packet.
<br/><br/>
<b>libwebsockets-test-client</b> joins in by spamming circles on to this shared canvas when
run.
</div>
<table class="content">
<tr>
<td>Drawing color:
<select id="color" onchange="update_color();">
<option value=#000000>Black</option>
<option value=#0000ff>Blue</option>
<option value=#20ff20>Green</option>
<option value=#802020>Dark Red</option>
</select>
</td>
<td id=wslm_statustd align=center class="explain"><div id=wslm_status>Not initialized</div></td>
</tr>
<tr>
<td colspan=2 width=500 class="content">
<div id="wslm_drawing">
</div></td>
</tr>
</table>
</section>
</div>
</td>
</tr>
<tr>
<td colspan=2>Drawing color:
<select id="color" onchange="update_color();">
<option value=#000000>Black</option>
<option value=#0000ff>Blue</option>
<option value=#20ff20>Green</option>
<option value=#802020>Dark Red</option>
</select>
</tr>
<tr>
<td colspan=2 width=500 height=320>
<div id="wslm_drawing" style="background:white"></div>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="tab">
<input type="radio" id="tab-3" name="tab-group-1">
<label for="tab-3">Close Testing</label>
<div class="content">
<div id="ot" class="group2">
<table>
<tr>
<td>
<section id="ot" class="group2">
<div class="title">libwebsockets "open and close testing"</div>
<table><tr><td>
<table class="content" width="200px">
</td></tr>
<tr><td id=ot_statustd align=center class="wsstatus">
<span id=ot_status>Websocket connection not initialized</span>
</td>
<td colspan=2><span class="title">Open and close testing</span></td>
</tr>
<tr>
<td class="explain" colspan=3 style="padding:3">
To help with open and close testing, you can open and close a connection by hand using
the buttons.<br>
"<b>Close</b>" closes the connection from the browser with code 3000
and reason 'Bye!".<br>
"<b>Request Server Close</b>" sends a message asking the server to
initiate the close, which it does with code 1001 and reason "Seeya".
</td></tr>
<tr>
<td align=center><input type=button id=ot_open_btn value="Open" onclick="ot_open();" ></td>
<td align=center><input type=button id=ot_close_btn disabled value="Close" onclick="ot_close();" ></td>
<td align=center><input type=button id=ot_req_close_btn disabled value="Request Server Close" onclick="ot_req_close();" ></td>
</tr>
<tr><td colspan="3" id=ot_statustd align=center class="explain"><div id=ot_status>Not initialized</div></td></tr>
</table>
</div>
</div>
</div>
<div class="tab">
<input type="radio" id="tab-4" name="tab-group-1">
<label for="tab-4">Server info</label>
<div class="content">
<div id="ot" class="group2">
<table>
<tr>
<td id=s_statustd align=center class="wsstatus">
<div id=s_status>Websocket connection not initialized</div>
</td>
<td colspan=1>
<span class="title">Server Info</span>
</td>
</tr><tr>
<td class="explain" colspan=2>
This information is sent by the server over a ws[s] link and updated live
whenever the information changes server-side.
</td></tr>
<tr>
<td align=center colspan=2><div id=servinfo></</div></td>
</tr>
<tr>
<td align=center colspan=2><div id=conninfo style="border : solid 2px #e0d040; padding : 4px; width : 500px; height : 350px; overflow : auto; "></</div></td>
</tr>
</table>
</td><td class="explain">
To help with open and close testing, you can open and close a connection by hand using
the buttons. "Request Server Close" sends a message asking the server to
initiate the close.
</td></tr></table>
</section>
<br>
</td></tr><tr><td>
Looking for support? <a href="http://libwebsockets.org">http://libwebsockets.org</a><br/>
Join the mailing list: <a href="http://ml.libwebsockets.org/mailman/listinfo/libwebsockets">http://ml.libwebsockets.org/mailman/listinfo/libwebsockets</a>
</div>
</div>
</div>
</div>
</td></tr></table>
Looking for support? <a href="https://libwebsockets.org">https://libwebsockets.org</a>, <a href="https://github.com/warmcat/libwebsockets">https://github.com/warmcat/libwebsockets</a></a><br/>
Join the mailing list: <a href="https://libwebsockets.org/mailman/listinfo/libwebsockets">https://libwebsockets.org/mailman/listinfo/libwebsockets</a>
</article>
<script>
/*
* We display untrusted stuff in html context... reject anything
* that has HTML stuff in it
*/
function san(s)
{
if (s.search("<") != -1)
return "invalid string";
return s;
}
/* BrowserDetect came from http://www.quirksmode.org/js/detect.html */
var BrowserDetect = {
@ -277,7 +445,9 @@ document.getElementById("number").textContent = get_appropriate_ws_url();
try {
socket_di.onopen = function() {
document.getElementById("wsdi_statustd").style.backgroundColor = "#40ff40";
document.getElementById("wsdi_status").innerHTML = " <b>websocket connection opened</b><br>" + socket_di.extensions;
document.getElementById("wsdi_status").innerHTML =
" <b>websocket connection opened</b><br>" +
san(socket_di.extensions);
}
socket_di.onmessage =function got_packet(msg) {
@ -291,11 +461,66 @@ document.getElementById("number").textContent = get_appropriate_ws_url();
} catch(exception) {
alert('<p>Error' + exception);
}
var socket_status, jso, s;
if (typeof MozWebSocket != "undefined") {
socket_status = new MozWebSocket(get_appropriate_ws_url(),
"lws-status");
} else {
socket_status = new WebSocket(get_appropriate_ws_url(),
"lws-status");
}
try {
socket_status.onopen = function() {
document.getElementById("s_statustd").style.backgroundColor = "#40ff40";
document.getElementById("s_status").innerHTML =
" <b>websocket connection opened</b><br>" +
san(socket_status.extensions);
}
socket_status.onmessage =function got_packet(msg) {
jso = JSON.parse(msg.data);
document.getElementById("servinfo").innerHTML =
"<table><tr><td class=l>Build info</td><td>"+
san(jso.version) + "</td></tr>" +
"<tr><td class=l>Server info</td><td>" +
san(jso.hostname) + "</td></tr>" +
"</table>";
s="<table>";
var n;
for (n = 0; n < jso.conns.length; n++)
s = s + "<tr><td class=l>client " + (n + 1) +
"</td><td><b>" + san(jso.conns[n].peer) +
"</b><br>" + san(jso.conns[n].time) +
"<br>" + san(jso.conns[n].ua) +
"</td></tr>";
s = s + "</table>";
document.getElementById("conninfo").innerHTML = s;
}
socket_status.onclose = function(){
document.getElementById("s_statustd").style.backgroundColor = "#ff4040";
document.getElementById("s_status").textContent = " websocket connection CLOSED ";
}
} catch(exception) {
alert('<p>Error' + exception);
}
function reset() {
socket_di.send("reset\n");
}
function junk() {
for(var word = ''; word.length < 9000; word += 'a'){}
socket_di.send(word);
}
var socket_ot;
function ot_open() {
@ -309,7 +534,7 @@ function ot_open() {
try {
socket_ot.onopen = function() {
document.getElementById("ot_statustd").style.backgroundColor = "#40ff40";
document.getElementById("ot_status").innerHTML = " <b>websocket connection opened</b><br>" + socket_di.extensions;
document.getElementById("ot_status").innerHTML = " <b>websocket connection opened</b><br>" + san(socket_di.extensions);
document.getElementById("ot_open_btn").disabled = true;
document.getElementById("ot_close_btn").disabled = false;
document.getElementById("ot_req_close_btn").disabled = false;
@ -359,7 +584,9 @@ function ot_req_close() {
try {
socket_lm.onopen = function() {
document.getElementById("wslm_statustd").style.backgroundColor = "#40ff40";
document.getElementById("wslm_status").innerHTML = " <b>websocket connection opened</b><br>" + socket_di.extensions;
document.getElementById("wslm_status").innerHTML =
" <b>websocket connection opened</b><br>" +
san(socket_lm.extensions);
}
socket_lm.onmessage =function got_packet(msg) {

View file

@ -69,7 +69,7 @@ Section "Files" SecInstall
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libwebsockets" "DisplayName" "libwebsockets library and clients"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libwebsockets" "UninstallString" "$\"$INSTDIR\Uninstall.exe$\""
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libwebsockets" "QuietUninstallString" "$\"$INSTDIR\Uninstall.exe$\" /S"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libwebsockets" "HelpLink" "http://libwebsockets.org/"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libwebsockets" "HelpLink" "https://libwebsockets.org/"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libwebsockets" "URLInfoAbout" "http://libwebsockets.org/"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libwebsockets" "DisplayVersion" "${VERSION}"
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libwebsockets" "NoModify" "1"