summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2017-12-29 14:21:20 -0800
committerGarrett D'Amore <garrett@damore.org>2017-12-30 19:05:41 -0800
commit6a50035b242b972c1d9b659ba63e037a0a8afe71 (patch)
treefe2600235a01e72d1e7bd5fad1d5e2ea62aada2e
parenta0364185784895c4bc748a6e6453a132d618c96c (diff)
downloadnng-6a50035b242b972c1d9b659ba63e037a0a8afe71.tar.gz
nng-6a50035b242b972c1d9b659ba63e037a0a8afe71.tar.bz2
nng-6a50035b242b972c1d9b659ba63e037a0a8afe71.zip
fixes #166 Websocket TLS mapping
This introduces the wss:// scheme, which is available and works like the ws:// scheme if TLS is enabled in the library. The library modularization is refactored somewhat, to make it easier to use. There is now a single NNG_ENABLE_TLS that enables TLS support under the hood. This also adds a new option for the TLS transport, NNG_OPT_TLS_CONFIG (and a similar one for WSS, NNG_OPT_TLS_WSS_CONFIG) that offer access to the underlying TLS configuration object, which now has a public API to go with it as well. Note that it is also possible to use pure HTTPS using the *private* API, which will be exposed in a public form soon.
-rw-r--r--CMakeLists.txt61
-rw-r--r--README.adoc44
-rw-r--r--docs/nng_tls.adoc12
-rw-r--r--docs/nng_ws.adoc20
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/core/options.c13
-rw-r--r--src/core/options.h3
-rw-r--r--src/core/transport.c31
-rw-r--r--src/nng.c39
-rw-r--r--src/nng.h73
-rw-r--r--src/supplemental/http/client.c45
-rw-r--r--src/supplemental/http/http.c84
-rw-r--r--src/supplemental/http/http.h23
-rw-r--r--src/supplemental/http/server.c115
-rw-r--r--src/supplemental/mbedtls/CMakeLists.txt54
-rw-r--r--src/supplemental/tls.h84
-rw-r--r--src/supplemental/tls/CMakeLists.txt38
-rw-r--r--src/supplemental/tls/mbedtls/tls.c (renamed from src/supplemental/mbedtls/tls.c)80
-rw-r--r--src/supplemental/tls/tls.h45
-rw-r--r--src/supplemental/websocket/websocket.c86
-rw-r--r--src/supplemental/websocket/websocket.h8
-rw-r--r--src/transport/tls/tls.c107
-rw-r--r--src/transport/tls/tls.h6
-rw-r--r--src/transport/ws/websocket.c132
-rw-r--r--src/transport/ws/websocket.h22
-rw-r--r--src/transport/zerotier/CMakeLists.txt1
-rw-r--r--src/transport/zerotier/zerotier.c3
-rw-r--r--tests/CMakeLists.txt114
-rw-r--r--tests/multistress.c6
-rw-r--r--tests/tls.c64
-rw-r--r--tests/trantest.h128
-rw-r--r--tests/wss.c206
-rw-r--r--tests/zt.c2
33 files changed, 1274 insertions, 477 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index df8a58f5..5aa87034 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -34,6 +34,7 @@ include (CheckSymbolExists)
include (CheckStructHasMember)
include (CheckLibraryExists)
include (CheckCSourceCompiles)
+include (CMakeDependentOption)
include (GNUInstallDirs)
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
@@ -98,93 +99,126 @@ option (NNG_ENABLE_COVERAGE "Enable coverage reporting." OFF)
# Enable access to private APIs for our own use.
add_definitions (-DNNG_PRIVATE)
+option (NNG_ENABLE_TLS "Enable TLS protocol (requires mbedTLS" OFF)
+if (NNG_ENABLE_TLS)
+ add_definitions(-DNNG_SUPP_TLS)
+ set(NNG_SUPP_TLS ON)
+ endif()
+
option (NNG_PROTO_BUS0 "Enable BUSv0 protocol." ON)
if (NNG_PROTO_BUS0)
add_definitions (-DNNG_HAVE_BUS0)
endif ()
+mark_as_advanced(NNG_PROTO_BUS0)
option (NNG_PROTO_PAIR0 "Enable PAIRv0 protocol." ON)
if (NNG_PROTO_PAIR0)
add_definitions (-DNNG_HAVE_PAIR0)
endif ()
+mark_as_advanced(NNG_PROTO_PAIR0)
option (NNG_PROTO_PAIR1 "Enable PAIRv1 protocol." ON)
if (NNG_PROTO_PAIR1)
add_definitions (-DNNG_HAVE_PAIR1)
endif ()
+mark_as_advanced(NNG_PROTO_PAIR1)
option (NNG_PROTO_REQ0 "Enable REQv0 protocol." ON)
if (NNG_PROTO_REQ0)
add_definitions (-DNNG_HAVE_REQ0)
endif ()
+mark_as_advanced(NNG_PROTO_REQ0)
option (NNG_PROTO_REP0 "Enable REPv0 protocol." ON)
if (NNG_PROTO_REP0)
add_definitions (-DNNG_HAVE_REP0)
endif ()
+mark_as_advanced(NNG_PROTO_REP0)
option (NNG_PROTO_PUB0 "Enable PUBv0 protocol." ON)
if (NNG_PROTO_PUB0)
add_definitions (-DNNG_HAVE_PUB0)
endif ()
+mark_as_advanced(NNG_PROTO_PUB0)
option (NNG_PROTO_SUB0 "Enable SUBv0 protocol." ON)
if (NNG_PROTO_SUB0)
add_definitions (-DNNG_HAVE_SUB0)
endif ()
+mark_as_advanced(NNG_PROTO_SUB0)
option (NNG_PROTO_PUSH0 "Enable PUSHv0 protocol." ON)
if (NNG_PROTO_PUSH0)
add_definitions (-DNNG_HAVE_PUSH0)
endif ()
+mark_as_advanced(NNG_PROTO_PUSH0)
option (NNG_PROTO_PULL0 "Enable PULLv0 protocol." ON)
if (NNG_PROTO_PULL0)
add_definitions (-DNNG_HAVE_PULL0)
endif ()
+mark_as_advanced(NNG_PROTO_PULL0)
option (NNG_PROTO_SURVEYOR0 "Enable SURVEYORv0 protocol." ON)
if (NNG_PROTO_SURVEYOR0)
add_definitions (-DNNG_HAVE_SURVEYOR0)
endif ()
+mark_as_advanced(NNG_PROTO_SURVEYOR0)
option (NNG_PROTO_RESPONDENT0 "Enable RESPONDENTv0 protocol." ON)
if (NNG_PROTO_RESPONDENT0)
add_definitions (-DNNG_HAVE_RESPONDENT0)
endif ()
+mark_as_advanced(NNG_PROTO_RESPONDENT0)
option (NNG_TRANSPORT_INPROC "Enable inproc transport." ON)
if (NNG_TRANSPORT_INPROC)
- add_definitions (-DNNG_HAVE_INPROC)
+ add_definitions (-DNNG_TRANSPORT_INPROC)
endif ()
+mark_as_advanced(NNG_TRANSPORT_INPROC)
option (NNG_TRANSPORT_IPC "Enable IPC transport." ON)
if (NNG_TRANSPORT_IPC)
- add_definitions (-DNNG_HAVE_IPC)
+ add_definitions (-DNNG_TRANSPORT_IPC)
endif ()
+mark_as_advanced(NNG_TRANSPORT_IPC)
option (NNG_TRANSPORT_TCP "Enable TCP transport." ON)
if (NNG_TRANSPORT_TCP)
- add_definitions (-DNNG_HAVE_TCP)
+ add_definitions (-DNNG_TRANSPORT_TCP)
endif ()
+mark_as_advanced(NNG_TRANSPORT_TCP)
+
+CMAKE_DEPENDENT_OPTION(NNG_TRANSPORT_TLS "Enable TLS transport" ON
+ "NNG_ENABLE_TLS" OFF)
+
+if (NNG_TRANSPORT_TLS)
+ set(NNG_SUPP_TLS ON)
+ add_definitions (-DNNG_TRANSPORT_TLS)
+endif()
+mark_as_advanced(NNG_TRANSPORT_TLS)
option (NNG_TRANSPORT_WS "Enable WebSocket transport." ON)
if (NNG_TRANSPORT_WS)
- add_definitions (-DNNG_HAVE_WEBSOCKET)
+ add_definitions (-DNNG_TRANSPORT_WS)
+ set(NNG_SUPP_WEBSOCKET ON)
+endif ()
+mark_as_advanced(NNG_TRANSPORT_WS)
+
+CMAKE_DEPENDENT_OPTION(NNG_TRANSPORT_WSS "Enable WSS transport" ON
+ "NNG_ENABLE_TLS" OFF)
+if (NNG_TRANSPORT_WSS)
+ add_definitions (-DNNG_TRANSPORT_WSS)
set(NNG_SUPP_WEBSOCKET ON)
endif ()
+mark_as_advanced(NNG_TRANSPORT_WSS)
option (NNG_TRANSPORT_ZEROTIER "Enable ZeroTier transport (requires libzerotiercore)." OFF)
if (NNG_TRANSPORT_ZEROTIER)
- add_definitions (-DNNG_HAVE_ZEROTIER)
+ add_definitions (-DNNG_TRANSPORT_ZEROTIER)
endif ()
+mark_as_advanced(NNG_TRANSPORT_ZEROTIER)
-option (NNG_TRANSPORT_TLS "Enable TLS transport (requires mbedtls)" OFF)
-if (NNG_TRANSPORT_TLS)
- set(NNG_MBEDTLS_ENABLE ON)
- add_definitions (-DNNG_MBEDTLS_ENABLE)
- add_definitions (-DNNG_HAVE_TLS)
-endif()
# dependencies
if (NNG_SUPP_WEBSOCKET)
@@ -193,6 +227,11 @@ if (NNG_SUPP_WEBSOCKET)
set(NNG_SUPP_SHA1 ON)
endif()
+# Extra defines.
+if (NNG_SUPP_TLS)
+ add_definitions (-DNNG_SUPP_TLS)
+endif()
+
# Platform checks.
if (NNG_ENABLE_COVERAGE)
diff --git a/README.adoc b/README.adoc
index 29c8e1c2..8912d879 100644
--- a/README.adoc
+++ b/README.adoc
@@ -11,10 +11,10 @@ can start using it for development, as we believe we are getting closer
to release readiness.
Review and testing feedback are appreciated however; but please understand
-that the project is still quite preliminary.
+that the project is still preliminary.
-This is a work in progress, and is *not* suitable for production use or
-publication. When the library is ready for broader consumption, an
+This is a work in progress, and is *not* suitable for production use.
+When the library is ready for broader consumption, an
announcement will be posted on the nanomsg mailing list and website.
Some https://nanomsg.github.io/nng/man/[manual pages] are posted
@@ -24,26 +24,36 @@ If you are looking for the current production version of nanomsg, please
see the https://github.com/nanomsg/nanomsg[nanomsg repo].
If you want to build and test yourself, you need CMake version 3.1, and
-you can use standard CMake build recipes. On a Linux/UNIX system,
-you can for example do:
+you can use standard CMake build recipes. (We highly recommend using
+https://ninja-build.org[Ninja] as it is much faster than traditional
+build systems.) On a Linux/UNIX system, if you have Ninja already
+installed, you can for example do:
[source,sh]
----
$ mkdir build
- $ cmake ..
- $ make
- $ make test
+ $ cmake -G Ninja ..
+ $ ninja
+ $ ninja test
----
-If you want to enable the TLS transport, which is not supported by legacy
-nanomsg, use -DNNG_TRANSPORT_TLS=ON in your cmake command line. You will
-need to have the ARM mbedTLS library installed. (This is available in
-Xenial Ubuntu as libmbedtls-dev).
-
-The API is not yet documented, but if you want to explore using the newer
-API, pleaes have a look at the `nng.h` header file. A legacy compatible
-`nng_compat.h` header is available and offers API compatibility with legacy
-_nanomsg_.
+This library can be compiled with support for TLS, which enables
+the use of the "tls+tcp://" and "wss://" schemes. In order to this,
+configure with `-DNNG_ENABLE_TLS=ON`.
+
+NOTE: The `NNG_ENABLE_TLS` library depends on the ARM
+https://tls.mbed.org[mbedTLS] library. This library is available
+in packaged form for many systems, and can be built for just about
+any of the others. However, please be aware of the licensing
+implications, because the mbedTLS library carries other licensing
+requirements (either Apache or GPL) than _nng_.
+either Apache or GPL licenses.
+
+Documentation is a work in progres -- initial pages are
+https://nanomsg.github.io/nng[online], but there is much missing.
+You can also explore the `nng.h` header file, which provides the public
+API. A legacy compatible `nng_compat.h` header is available and
+offers API compatibility with legacy _nanomsg_.
== Commercial Support
diff --git a/docs/nng_tls.adoc b/docs/nng_tls.adoc
index e6eafdd5..a6737d01 100644
--- a/docs/nng_tls.adoc
+++ b/docs/nng_tls.adoc
@@ -157,6 +157,17 @@ Transport Options
The following transport options are available. Note that
setting these must be done before the transport is started.
+`NNG_OPT_TLS_CONFIG`::
+
+This option is used to set or obtain the TLS configuration
+object (type `nng_tls_config *`), which is passed as a pointer.
+Setting this option adds a reference to the object; obtaining the
+object pointer does not. (Therefore when retrieving this option,
+care must be taken not to access it after the endpoint is closed.)
+
+Note that configuration object is not modifiable once it has been
+used in a running TLS stream.
+
`NNG_OPT_TLS_CA_CERT`::
This is a write-only binay object containing a certificate
@@ -232,6 +243,7 @@ if the `NNG_OPT_TLS_AUTH_MODE` option is set to
SEE ALSO
--------
<<nng.adoc#,nng(7)>>
+<<nng_tls_init#,nng_tls_init(3)>>
COPYRIGHT
---------
diff --git a/docs/nng_ws.adoc b/docs/nng_ws.adoc
index 8073e158..b6185757 100644
--- a/docs/nng_ws.adoc
+++ b/docs/nng_ws.adoc
@@ -25,6 +25,7 @@ SYNOPSIS
#include <nng/transport/websocket/ws.h>
int nng_ws_register(void);
+int nng_wss_register(void);
----------
DESCRIPTION
@@ -46,6 +47,11 @@ register the transport by calling `nng_ws_register`. This function
returns zero on success, or an nng error value if the transport
cannot be initialized for any reason.
+If TLS support is enabled in the library, secure WebSockets (over TLS v1.2)
+can be used as well, but the secure transport may have to be registered using
+the `nng_wss_register` function. (Note that this function will not be
+present if TLS support was not enabled in the library.)
+
URI Format
~~~~~~~~~~
@@ -57,6 +63,10 @@ a path of `/` is assumed.)
For example, the URI `ws://localhost/app/pubsub` would use
port 80 on localhost, with the path `/app/pubsub`.
+Secure WebSockets (if enabled) use the scheme `wss://`, and the default
+TCP port number of 443. Otherwise the format is the same as for regular
+WebSockets.
+
When specifying IPv6 addresses, the address must be enclosed in
square brackets (`[]`) to avoid confusion with the final colon
separating the port.
@@ -141,6 +151,15 @@ by CRLF sequences, that can be used to add furthe headers to the
HTTP response sent when connecting. This option can be set on listeners,
and retrieved from pipes.
+`NNG_OPT_WSS_TLS_CONFIG`::
+
+This option is used on an endpoint to access the underlying TLS
+configuration object. The value is of type `nng_tls_config *`.
+Note that attempts to set this object may fail on a listener if
+the server is already running. Furthermore, attempts to modify the
+configuration object will fail if it is already in active use.
+This object is only available for `wss://` endpoints.
+
// We should also look at a hook mechanism for listeners. Probably this could
// look like NNG_OPT_WS_LISTEN_HOOK_FUNC which would take a function pointer
// along the lines of int hook(void *, char *req_headers, char **res_headers),
@@ -150,6 +169,7 @@ and retrieved from pipes.
SEE ALSO
--------
<<nng.adoc#,nng(7)>>
+<<nng_tls_init#,nng_tls_init(3)>>
COPYRIGHT
---------
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6fae89e0..45dcb4fe 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -123,8 +123,8 @@ endif()
add_subdirectory(supplemental/base64)
add_subdirectory(supplemental/http)
-add_subdirectory(supplemental/mbedtls)
add_subdirectory(supplemental/sha1)
+add_subdirectory(supplemental/tls)
add_subdirectory(supplemental/websocket)
add_subdirectory(protocol/bus0)
diff --git a/src/core/options.c b/src/core/options.c
index 1417d0b3..ef7420d6 100644
--- a/src/core/options.c
+++ b/src/core/options.c
@@ -187,6 +187,19 @@ nni_getopt_size(size_t u, void *val, size_t *sizep)
}
int
+nni_getopt_ptr(void *ptr, void *val, size_t *sizep)
+{
+ size_t sz = sizeof(ptr);
+
+ if (sz > *sizep) {
+ sz = *sizep;
+ }
+ *sizep = sizeof(ptr);
+ memcpy(val, &ptr, sz);
+ return (0);
+}
+
+int
nni_setopt_buf(nni_msgq *mq, const void *val, size_t sz)
{
int len;
diff --git a/src/core/options.h b/src/core/options.h
index d373851f..e9aa16dd 100644
--- a/src/core/options.h
+++ b/src/core/options.h
@@ -58,6 +58,9 @@ extern int nni_setopt_size(size_t *, const void *, size_t, size_t, size_t);
// nni_getopt_size obtains a size_t option.
extern int nni_getopt_size(size_t, void *, size_t *);
+// nni_getopt_ptr obtains a pointer option.
+extern int nni_getopt_ptr(void *, void *, size_t *);
+
extern int nni_chkopt_ms(const void *, size_t);
extern int nni_chkopt_int(const void *, size_t, int, int);
extern int nni_chkopt_size(const void *, size_t, size_t, size_t);
diff --git a/src/core/transport.c b/src/core/transport.c
index 31da773f..9c129a72 100644
--- a/src/core/transport.c
+++ b/src/core/transport.c
@@ -56,12 +56,12 @@ nni_tran_register(const nni_tran *tran)
nni_mtx_lock(&nni_tran_lk);
// Check to see if the transport is already registered...
NNI_LIST_FOREACH (&nni_tran_list, t) {
- if (tran->tran_init == t->t_tran.tran_init) {
- nni_mtx_unlock(&nni_tran_lk);
- // Same transport, duplicate registration.
- return (0);
- }
if (strcmp(tran->tran_scheme, t->t_tran.tran_scheme) == 0) {
+ if (tran->tran_init == t->t_tran.tran_init) {
+ // duplicate.
+ nni_mtx_unlock(&nni_tran_lk);
+ return (0);
+ }
nni_mtx_unlock(&nni_tran_lk);
return (NNG_ESTATE);
}
@@ -208,25 +208,30 @@ nni_tran_chkopt(const char *name, const void *v, size_t sz)
typedef int (*nni_tran_ctor)(void);
+// These are just the statically compiled in constructors.
+// In the future we might want to support dynamic additions.
static nni_tran_ctor nni_tran_ctors[] = {
-#ifdef NNG_HAVE_INPROC
+#ifdef NNG_TRANSPORT_INPROC
nng_inproc_register,
#endif
-#ifdef NNG_HAVE_IPC
+#ifdef NNG_TRANSPORT_IPC
nng_ipc_register,
#endif
-#ifdef NNG_HAVE_TCP
+#ifdef NNG_TRANSPORT_TCP
nng_tcp_register,
#endif
-#ifdef NNG_HAVE_TLS
+#ifdef NNG_TRANSPORT_TLS
nng_tls_register,
#endif
-#ifdef NNG_HAVE_ZEROTIER
- nng_zt_register,
-#endif
-#ifdef NNG_HAVE_WEBSOCKET
+#ifdef NNG_TRANSPORT_WS
nng_ws_register,
#endif
+#ifdef NNG_TRANSPORT_WSS
+ nng_wss_register,
+#endif
+#ifdef NNG_TRANSPORT_ZEROTIER
+ nng_zt_register,
+#endif
NULL,
};
diff --git a/src/nng.c b/src/nng.c
index 6cd78e1d..67eac2c4 100644
--- a/src/nng.c
+++ b/src/nng.c
@@ -405,6 +405,12 @@ nng_dialer_setopt_uint64(nng_dialer id, const char *name, uint64_t val)
}
int
+nng_dialer_setopt_ptr(nng_dialer id, const char *name, void *val)
+{
+ return (nng_dialer_setopt(id, name, &val, sizeof(val)));
+}
+
+int
nng_dialer_getopt(nng_dialer id, const char *name, void *val, size_t *szp)
{
return (nng_ep_getopt(id, name, val, szp, NNI_EP_MODE_DIAL));
@@ -432,6 +438,13 @@ nng_dialer_getopt_uint64(nng_dialer id, const char *name, uint64_t *valp)
}
int
+nng_dialer_getopt_ptr(nng_dialer id, const char *name, void **valp)
+{
+ size_t sz = sizeof(*valp);
+ return (nng_dialer_getopt(id, name, valp, &sz));
+}
+
+int
nng_dialer_getopt_ms(nng_dialer id, const char *name, nng_duration *valp)
{
size_t sz = sizeof(*valp);
@@ -470,6 +483,12 @@ nng_listener_setopt_uint64(nng_listener id, const char *name, uint64_t val)
}
int
+nng_listener_setopt_ptr(nng_listener id, const char *name, void *val)
+{
+ return (nng_listener_setopt(id, name, &val, sizeof(val)));
+}
+
+int
nng_listener_getopt(nng_listener id, const char *name, void *val, size_t *szp)
{
return (nng_ep_getopt(id, name, val, szp, NNI_EP_MODE_LISTEN));
@@ -497,6 +516,13 @@ nng_listener_getopt_uint64(nng_listener id, const char *name, uint64_t *valp)
}
int
+nng_listener_getopt_ptr(nng_listener id, const char *name, void **valp)
+{
+ size_t sz = sizeof(*valp);
+ return (nng_listener_getopt(id, name, valp, &sz));
+}
+
+int
nng_listener_getopt_ms(nng_listener id, const char *name, nng_duration *valp)
{
size_t sz = sizeof(*valp);
@@ -588,6 +614,12 @@ nng_setopt_uint64(nng_socket sid, const char *name, uint64_t val)
}
int
+nng_setopt_ptr(nng_socket sid, const char *name, void *val)
+{
+ return (nng_setopt(sid, name, &val, sizeof(val)));
+}
+
+int
nng_getopt_int(nng_socket sid, const char *name, int *valp)
{
size_t sz = sizeof(*valp);
@@ -616,6 +648,13 @@ nng_getopt_ms(nng_socket sid, const char *name, nng_duration *valp)
}
int
+nng_getopt_ptr(nng_socket sid, const char *name, void **valp)
+{
+ size_t sz = sizeof(*valp);
+ return (nng_getopt(sid, name, valp, &sz));
+}
+
+int
nng_device(nng_socket s1, nng_socket s2)
{
int rv;
diff --git a/src/nng.h b/src/nng.h
index 6d375509..f42bc1a5 100644
--- a/src/nng.h
+++ b/src/nng.h
@@ -21,6 +21,7 @@
extern "C" {
#endif
+#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
@@ -90,6 +91,7 @@ NNG_DECL int nng_getopt_int(nng_socket, const char *, int *);
NNG_DECL int nng_getopt_ms(nng_socket, const char *, nng_duration *);
NNG_DECL int nng_getopt_size(nng_socket, const char *, size_t *);
NNG_DECL int nng_getopt_uint64(nng_socket, const char *, uint64_t *);
+NNG_DECL int nng_getopt_ptr(nng_socket, const char *, void **);
// nng_listen creates a listening endpoint with no special options,
// and starts it listening. It is functionally equivalent to the legacy
@@ -138,6 +140,7 @@ NNG_DECL int nng_dialer_setopt_int(nng_dialer, const char *, int);
NNG_DECL int nng_dialer_setopt_ms(nng_dialer, const char *, nng_duration);
NNG_DECL int nng_dialer_setopt_size(nng_dialer, const char *, size_t);
NNG_DECL int nng_dialer_setopt_uint64(nng_dialer, const char *, uint64_t);
+NNG_DECL int nng_dialer_setopt_ptr(nng_dialer, const char *, void *);
// nng_dialer_getopt obtains the option for a dialer. This will
// fail for options that a particular dialer is not interested in,
@@ -147,6 +150,7 @@ NNG_DECL int nng_dialer_getopt_int(nng_dialer, const char *, int *);
NNG_DECL int nng_dialer_getopt_ms(nng_dialer, const char *, nng_duration *);
NNG_DECL int nng_dialer_getopt_size(nng_dialer, const char *, size_t *);
NNG_DECL int nng_dialer_getopt_uint64(nng_dialer, const char *, uint64_t *);
+NNG_DECL int nng_dialer_getopt_ptr(nng_dialer, const char *, void **);
// nng_listener_setopt sets an option for a dialer. This value is
// not stored in the socket. Subsequent setopts on the socket may
@@ -158,6 +162,7 @@ NNG_DECL int nng_listener_setopt_int(nng_listener, const char *, int);
NNG_DECL int nng_listener_setopt_ms(nng_listener, const char *, nng_duration);
NNG_DECL int nng_listener_setopt_size(nng_listener, const char *, size_t);
NNG_DECL int nng_listener_setopt_uint64(nng_listener, const char *, uint64_t);
+NNG_DECL int nng_listener_setopt_ptr(nng_listener, const char *, void *);
// nng_listener_getopt obtains the option for a listener. This will
// fail for options that a particular listener is not interested in,
@@ -169,6 +174,7 @@ NNG_DECL int nng_listener_getopt_ms(
NNG_DECL int nng_listener_getopt_size(nng_listener, const char *, size_t *);
NNG_DECL int nng_listener_getopt_uint64(
nng_listener, const char *, uint64_t *);
+NNG_DECL int nng_listener_getopt_ptr(nng_listener, const char *, void **);
// nng_strerror returns a human readable string associated with the error
// code supplied.
@@ -574,6 +580,73 @@ enum nng_sockaddr_family {
NNG_AF_ZT = 5, // ZeroTier
};
+// For some transports, we need TLS configuration. This
+// section lets us work with TLS configurations. Note
+// that these symbols are only actually present at link time
+// if TLS support is enabled in your build. Note also that
+// a TLS configuration cannot be changed once it is in use.
+typedef struct nng_tls_config nng_tls_config;
+
+typedef enum nng_tls_mode {
+ NNG_TLS_MODE_CLIENT = 0,
+ NNG_TLS_MODE_SERVER = 1,
+} nng_tls_mode;
+
+typedef enum nng_tls_auth_mode {
+ NNG_TLS_AUTH_MODE_NONE = 0, // No verification is performed
+ NNG_TLS_AUTH_MODE_OPTIONAL = 1, // Verify cert if presented
+ NNG_TLS_AUTH_MODE_REQUIRED = 2, // Verify cert, close if invalid
+} nng_tls_auth_mode;
+
+// nng_tls_config init creates a TLS configuration using
+// reasonable defaults. This configuration can be shared
+// with multiple pipes or services/servers.
+NNG_DECL int nng_tls_config_init(nng_tls_config **, nng_tls_mode);
+
+NNG_DECL void nng_tls_config_fini(nng_tls_config *);
+
+// nng_tls_config_server_name sets the server name. This is
+// called by clients to set the name that the server supplied
+// certificate should be matched against. This can also cause
+// the SNI to be sent to the server to tell it which cert to
+// use if it supports more than one.
+NNG_DECL int nng_tls_config_server_name(nng_tls_config *, const char *);
+
+// nng_tls_config_ca_cert configures one or more CAs used for validation
+// of peer certificates. Multiple CAs (and their chains) may be configured
+// by either calling this multiple times, or by specifying a list of
+// certificates as concatenated data. The certs may be in PEM or DER
+// format.
+NNG_DECL int nng_tls_config_ca_cert(nng_tls_config *, const uint8_t *, size_t);
+
+// nng_tls_config_clr loads a certificate revocation list. Again, these
+// are in X.509 format (either PEM or DER).
+NNG_DECL int nng_tls_config_crl(nng_tls_config *, const uint8_t *, size_t);
+
+// nng_tls_config_cert is used to load our own certificate. For servers,
+// this may be called more than once to configure multiple different keys,
+// for example with different algorithms depending on what the peer supports.
+// On the client, only a single option is available.
+NNG_DECL int nng_tls_config_cert(nng_tls_config *, const uint8_t *, size_t);
+
+// nng_tls_config_key is used to pass our own private key.
+NNG_DECL int nng_tls_config_key(nng_tls_config *, const uint8_t *, size_t);
+
+// nng_tls_config_pass is used to pass a password used to decrypt
+// private keys that are encrypted.
+NNG_DECL int nng_tls_config_pass(nng_tls_config *, const char *);
+
+// nng_tls_config_validate_peer is used to enable validation of the peer
+// and it's certificate. If disabled, the peer's certificate will still
+// be available, but may not be valid.
+NNG_DECL int nng_tls_config_validate_peer(nng_tls_config *, bool);
+
+// nng_tls_config_auth_mode is used to configure the authentication mode use.
+// The default is that servers have this off (i.e. no client authentication)
+// and clients have it on (they verify the server), which matches typical
+// practice.
+NNG_DECL int nng_tls_config_auth_mode(nng_tls_config *, nng_tls_auth_mode);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/supplemental/http/client.c b/src/supplemental/http/client.c
index 8c082a17..4bb517ce 100644
--- a/src/supplemental/http/client.c
+++ b/src/supplemental/http/client.c
@@ -14,6 +14,8 @@
#include <string.h>
#include "core/nng_impl.h"
+#include "supplemental/tls/tls.h"
+
#include "http.h"
struct nni_http_client {
@@ -21,7 +23,7 @@ struct nni_http_client {
nni_list aios;
nni_mtx mtx;
bool closed;
- bool tls;
+ nng_tls_config * tls;
nni_aio * connaio;
nni_plat_tcp_ep *tep;
};
@@ -39,7 +41,6 @@ http_conn_done(void *arg)
nni_aio * aio;
int rv;
nni_plat_tcp_pipe *p;
- nni_http_tran t;
nni_http * http;
nni_mtx_lock(&c->mtx);
@@ -60,17 +61,13 @@ http_conn_done(void *arg)
return;
}
- t.h_data = p;
- t.h_write = (void *) nni_plat_tcp_pipe_send;
- t.h_read = (void *) nni_plat_tcp_pipe_recv;
- t.h_close = (void *) nni_plat_tcp_pipe_close;
- t.h_sock_addr = (void *) nni_plat_tcp_pipe_sockname;
- t.h_peer_addr = (void *) nni_plat_tcp_pipe_peername;
- t.h_fini = (void *) nni_plat_tcp_pipe_fini;
-
- if ((rv = nni_http_init(&http, &t)) != 0) {
+ if (c->tls != NULL) {
+ rv = nni_http_init_tls(&http, c->tls, p);
+ } else {
+ rv = nni_http_init_tcp(&http, p);
+ }
+ if (rv != 0) {
nni_aio_finish_error(aio, rv);
- nni_plat_tcp_pipe_fini(p);
nni_mtx_unlock(&c->mtx);
return;
}
@@ -90,6 +87,11 @@ nni_http_client_fini(nni_http_client *c)
nni_aio_fini(c->connaio);
nni_plat_tcp_ep_fini(c->tep);
nni_mtx_fini(&c->mtx);
+#ifdef NNG_SUPP_TLS
+ if (c->tls != NULL) {
+ nng_tls_config_fini(c->tls);
+ }
+#endif
NNI_FREE_STRUCT(c);
}
@@ -119,6 +121,25 @@ nni_http_client_init(nni_http_client **cp, nng_sockaddr *sa)
return (0);
}
+#ifdef NNG_SUPP_TLS
+int
+nni_http_client_set_tls(nni_http_client *c, nng_tls_config *tls)
+{
+ nng_tls_config *old;
+ nni_mtx_lock(&c->mtx);
+ old = c->tls;
+ c->tls = tls;
+ if (tls != NULL) {
+ nni_tls_config_hold(tls);
+ }
+ nni_mtx_unlock(&c->mtx);
+ if (old != NULL) {
+ nng_tls_config_fini(old);
+ }
+ return (0);
+}
+#endif
+
static void
http_connect_cancel(nni_aio *aio, int rv)
{
diff --git a/src/supplemental/http/http.c b/src/supplemental/http/http.c
index f414c5c7..df5c7588 100644
--- a/src/supplemental/http/http.c
+++ b/src/supplemental/http/http.c
@@ -12,6 +12,8 @@
#include <string.h>
#include "core/nng_impl.h"
+#include "supplemental/tls/tls.h"
+
#include "http.h"
// We insist that individual headers fit in 8K.
@@ -33,6 +35,15 @@ enum write_flavor {
HTTP_WR_RES,
};
+typedef struct nni_http_tran {
+ void (*h_read)(void *, nni_aio *);
+ void (*h_write)(void *, nni_aio *);
+ int (*h_sock_addr)(void *, nni_sockaddr *);
+ int (*h_peer_addr)(void *, nni_sockaddr *);
+ void (*h_close)(void *);
+ void (*h_fini)(void *);
+} nni_http_tran;
+
#define SET_RD_FLAVOR(aio, f) (aio)->a_prov_extra[0] = ((void *) (intptr_t)(f))
#define GET_RD_FLAVOR(aio) (int) ((intptr_t) aio->a_prov_extra[0])
#define SET_WR_FLAVOR(aio, f) (aio)->a_prov_extra[0] = ((void *) (intptr_t)(f))
@@ -76,14 +87,17 @@ http_close(nni_http *http)
http->closed = true;
if (nni_list_first(&http->wrq)) {
nni_aio_cancel(http->wr_aio, NNG_ECLOSED);
- while ((aio = nni_list_first(&http->wrq)) != NULL) {
+ // Abort all operations except the one in flight.
+ while ((aio = nni_list_last(&http->wrq)) !=
+ nni_list_first(&http->wrq)) {
nni_aio_list_remove(aio);
nni_aio_finish_error(aio, NNG_ECLOSED);
}
}
if (nni_list_first(&http->rdq)) {
nni_aio_cancel(http->rd_aio, NNG_ECLOSED);
- while ((aio = nni_list_first(&http->rdq)) != NULL) {
+ while ((aio = nni_list_last(&http->rdq)) !=
+ nni_list_first(&http->rdq)) {
nni_aio_list_remove(aio);
nni_aio_finish_error(aio, NNG_ECLOSED);
}
@@ -591,8 +605,8 @@ nni_http_fini(nni_http *http)
NNI_FREE_STRUCT(http);
}
-int
-nni_http_init(nni_http **httpp, nni_http_tran *tran)
+static int
+http_init(nni_http **httpp, nni_http_tran *tran, void *data)
{
nni_http *http;
int rv;
@@ -609,21 +623,71 @@ nni_http_init(nni_http **httpp, nni_http_tran *tran)
nni_aio_list_init(&http->rdq);
nni_aio_list_init(&http->wrq);
- if (((rv = nni_aio_init(&http->wr_aio, http_wr_cb, http)) != 0) ||
- ((rv = nni_aio_init(&http->rd_aio, http_rd_cb, http)) != 0)) {
- nni_http_fini(http);
- return (rv);
- }
+ http->sock = data;
http->rd_bufsz = HTTP_BUFSIZE;
http->rd = tran->h_read;
http->wr = tran->h_write;
http->close = tran->h_close;
http->fini = tran->h_fini;
- http->sock = tran->h_data;
http->sock_addr = tran->h_sock_addr;
http->peer_addr = tran->h_peer_addr;
+ if (((rv = nni_aio_init(&http->wr_aio, http_wr_cb, http)) != 0) ||
+ ((rv = nni_aio_init(&http->rd_aio, http_rd_cb, http)) != 0)) {
+ nni_http_fini(http);
+ return (rv);
+ }
+
*httpp = http;
return (0);
}
+
+static nni_http_tran http_tcp_ops = {
+ .h_read = (void *) nni_plat_tcp_pipe_recv,
+ .h_write = (void *) nni_plat_tcp_pipe_send,
+ .h_close = (void *) nni_plat_tcp_pipe_close,
+ .h_fini = (void *) nni_plat_tcp_pipe_fini,
+ .h_sock_addr = (void *) nni_plat_tcp_pipe_sockname,
+ .h_peer_addr = (void *) nni_plat_tcp_pipe_peername,
+};
+
+int
+nni_http_init_tcp(nni_http **hpp, void *tcp)
+{
+ return (http_init(hpp, &http_tcp_ops, tcp));
+}
+
+#ifdef NNG_SUPP_TLS
+static nni_http_tran http_tls_ops = {
+ .h_read = (void *) nni_tls_recv,
+ .h_write = (void *) nni_tls_send,
+ .h_close = (void *) nni_tls_close,
+ .h_fini = (void *) nni_tls_fini,
+ .h_sock_addr = (void *) nni_tls_sockname,
+ .h_peer_addr = (void *) nni_tls_peername,
+};
+
+int
+nni_http_init_tls(nni_http **hpp, nng_tls_config *cfg, void *tcp)
+{
+ nni_tls *tls;
+ int rv;
+
+ if ((rv = nni_tls_init(&tls, cfg, tcp)) != 0) {
+ nni_plat_tcp_pipe_fini(tcp);
+ return (rv);
+ }
+
+ return (http_init(hpp, &http_tls_ops, tls));
+}
+#else
+int
+nni_http_init_tls(nni_http **hpp, nng_tls_config *cfg, void *tcp)
+{
+ NNI_ARG_UNUSED(hpp);
+ NNI_ARG_UNUSED(cfg);
+ nni_plat_tcp_pipe_fini(tcp);
+ return (NNG_ENOTSUP);
+}
+#endif // NNG_SUPP_TLS \ No newline at end of file
diff --git a/src/supplemental/http/http.h b/src/supplemental/http/http.h
index 3ecce4c8..d817ba37 100644
--- a/src/supplemental/http/http.h
+++ b/src/supplemental/http/http.h
@@ -18,16 +18,6 @@ typedef struct nni_http_msg nni_http_msg;
typedef struct nni_http_res nni_http_res;
typedef struct nni_http_entity nni_http_entity;
-typedef struct nni_http_tran {
- void *h_data;
- void (*h_read)(void *, nni_aio *);
- void (*h_write)(void *, nni_aio *);
- int (*h_sock_addr)(void *, nni_sockaddr *);
- int (*h_peer_addr)(void *, nni_sockaddr *);
- void (*h_close)(void *);
- void (*h_fini)(void *);
-} nni_http_tran;
-
typedef struct nni_http_req nni_http_req;
extern int nni_http_req_init(nni_http_req **);
@@ -146,7 +136,8 @@ enum { NNI_HTTP_STATUS_CONTINUE = 100,
// the connection.
typedef struct nni_http nni_http;
-extern int nni_http_init(nni_http **, nni_http_tran *);
+extern int nni_http_init_tcp(nni_http **, void *);
+extern int nni_http_init_tls(nni_http **, nng_tls_config *, void *);
extern void nni_http_close(nni_http *);
extern void nni_http_fini(nni_http *);
@@ -254,6 +245,11 @@ extern int nni_http_server_add_handler(
extern void nni_http_server_del_handler(nni_http_server *, void *);
+// nni_http_server_set_tls adds a TLS configuration to the server,
+// and enables the use of it. This returns NNG_EBUSY if the server is
+// already started.
+extern int nni_http_server_set_tls(nni_http_server *, nng_tls_config *);
+
// nni_http_server_start starts listening on the supplied port.
extern int nni_http_server_start(nni_http_server *);
@@ -281,16 +277,13 @@ extern int nni_http_server_add_static(nni_http_server *, const char *host,
extern int nni_http_server_add_file(nni_http_server *, const char *host,
const char *ctype, const char *uri, const char *path);
-// TLS will use
-// extern int nni_http_server_start_tls(nni_http_server *, nng_sockaddr *,
-// nni_tls_config *);
-
// Client stuff.
typedef struct nni_http_client nni_http_client;
extern int nni_http_client_init(nni_http_client **, nng_sockaddr *);
extern void nni_http_client_fini(nni_http_client *);
+extern int nni_http_client_set_tls(nni_http_client *, nng_tls_config *);
extern void nni_http_client_connect(nni_http_client *, nni_aio *);
#endif // NNG_SUPPLEMENTAL_HTTP_HTTP_H
diff --git a/src/supplemental/http/server.c b/src/supplemental/http/server.c
index ea7f15ce..ba74a138 100644
--- a/src/supplemental/http/server.c
+++ b/src/supplemental/http/server.c
@@ -14,6 +14,8 @@
#include <string.h>
#include "core/nng_impl.h"
+#include "supplemental/tls/tls.h"
+
#include "http.h"
static int http_server_sys_init(void);
@@ -50,7 +52,6 @@ typedef struct http_sconn {
nni_aio * rxaio;
nni_aio * txaio;
nni_aio * txdataio;
- nni_http_tran tran;
nni_reap_item reap;
} http_sconn;
@@ -64,7 +65,7 @@ struct nni_http_server {
nni_mtx mtx;
nni_cv cv;
bool closed;
- bool tls;
+ nng_tls_config * tls;
nni_aio * accaio;
nni_plat_tcp_ep *tep;
};
@@ -105,28 +106,48 @@ http_sconn_fini(http_sconn *sc)
}
static void
-http_sconn_close(http_sconn *sc)
+http_sconn_close_locked(http_sconn *sc)
{
nni_http_server *s;
s = sc->server;
+ nni_http *h;
+ if (sc->closed) {
+ return;
+ }
NNI_ASSERT(!sc->finished);
- nni_mtx_lock(&s->mtx);
- if (!sc->closed) {
- nni_http *h;
- sc->closed = true;
- // Close the underlying transport.
- if (nni_list_node_active(&sc->node)) {
- nni_list_remove(&s->conns, sc);
- if (nni_list_empty(&s->conns)) {
- nni_cv_wake(&s->cv);
- }
- }
- if ((h = sc->http) != NULL) {
- nni_http_close(h);
+
+ sc->closed = true;
+ // Close the underlying transport.
+ if (nni_list_node_active(&sc->node)) {
+ nni_list_remove(&s->conns, sc);
+ if (nni_list_empty(&s->conns)) {
+ nni_cv_wake(&s->cv);
}
- http_sconn_fini(sc);
}
+ nni_aio_cancel(sc->rxaio, NNG_ECLOSED);
+ nni_aio_cancel(sc->txaio, NNG_ECLOSED);
+ nni_aio_cancel(sc->txdataio, NNG_ECLOSED);
+ nni_aio_cancel(sc->cbaio, NNG_ECLOSED);
+
+ if ((h = sc->http) != NULL) {
+ nni_http_close(h);
+ }
+ http_sconn_fini(sc);
+}
+
+static void
+http_sconn_close(http_sconn *sc)
+{
+ nni_http_server *s;
+ s = sc->server;
+
+ if (sc->closed) {
+ return;
+ }
+
+ nni_mtx_lock(&s->mtx);
+ http_sconn_close_locked(sc);
nni_mtx_unlock(&s->mtx);
}
@@ -484,14 +505,16 @@ http_sconn_cbdone(void *arg)
}
static int
-http_sconn_init(http_sconn **scp, nni_plat_tcp_pipe *tcp)
+http_sconn_init(http_sconn **scp, nni_http_server *s, nni_plat_tcp_pipe *tcp)
{
http_sconn *sc;
int rv;
if ((sc = NNI_ALLOC_STRUCT(sc)) == NULL) {
+ nni_plat_tcp_pipe_fini(tcp);
return (NNG_ENOMEM);
}
+
if (((rv = nni_http_req_init(&sc->req)) != 0) ||
((rv = nni_aio_init(&sc->rxaio, http_sconn_rxdone, sc)) != 0) ||
((rv = nni_aio_init(&sc->txaio, http_sconn_txdone, sc)) != 0) ||
@@ -502,18 +525,13 @@ http_sconn_init(http_sconn **scp, nni_plat_tcp_pipe *tcp)
http_sconn_close(sc);
return (rv);
}
- // XXX: for HTTPS we would then try to do the TLS negotiation here.
- // That would use a different set of tran values.
- sc->tran.h_data = tcp;
- sc->tran.h_read = (void *) nni_plat_tcp_pipe_recv;
- sc->tran.h_write = (void *) nni_plat_tcp_pipe_send;
- sc->tran.h_close = (void *) nni_plat_tcp_pipe_close; // close implied
- sc->tran.h_fini = (void *) nni_plat_tcp_pipe_fini;
- sc->tran.h_sock_addr = (void *) nni_plat_tcp_pipe_sockname;
- sc->tran.h_peer_addr = (void *) nni_plat_tcp_pipe_peername;
-
- if ((rv = nni_http_init(&sc->http, &sc->tran)) != 0) {
+ if (s->tls != NULL) {
+ rv = nni_http_init_tls(&sc->http, s->tls, tcp);
+ } else {
+ rv = nni_http_init_tcp(&sc->http, tcp);
+ }
+ if (rv != 0) {
http_sconn_close(sc);
return (rv);
}
@@ -539,9 +557,8 @@ http_server_acccb(void *arg)
return;
}
tcp = nni_aio_get_pipe(aio);
- if (http_sconn_init(&sc, tcp) != 0) {
- nni_plat_tcp_pipe_close(tcp);
- nni_plat_tcp_pipe_fini(tcp);
+ if (http_sconn_init(&sc, s, tcp) != 0) {
+ // The TCP structure is already cleaned up.
nni_plat_tcp_ep_accept(s->tep, s->accaio);
return;
@@ -590,6 +607,11 @@ http_server_fini(nni_http_server *s)
http_handler_fini(h);
}
nni_mtx_unlock(&s->mtx);
+#ifdef NNG_SUPP_TLS
+ if (s->tls != NULL) {
+ nng_tls_config_fini(s->tls);
+ }
+#endif
nni_aio_fini(s->accaio);
nni_cv_fini(&s->cv);
nni_mtx_fini(&s->mtx);
@@ -726,11 +748,7 @@ http_server_stop(nni_http_server *s)
// Stopping the server is a hard stop -- it aborts any work being
// done by clients. (No graceful shutdown).
NNI_LIST_FOREACH (&s->conns, sc) {
- nni_list_remove(&s->conns, sc);
- if (sc->http != NULL) {
- nni_http_close(sc->http);
- }
- http_sconn_fini(sc);
+ http_sconn_close_locked(sc);
}
nni_cv_wake(&s->cv);
}
@@ -1073,6 +1091,29 @@ nni_http_server_add_static(nni_http_server *s, const char *host,
return (0);
}
+#ifdef NNG_SUPP_TLS
+int
+nni_http_server_set_tls(nni_http_server *s, nng_tls_config *tcfg)
+{
+ nng_tls_config *old;
+ nni_mtx_lock(&s->mtx);
+ if (s->starts) {
+ nni_mtx_unlock(&s->mtx);
+ return (NNG_EBUSY);
+ }
+ old = s->tls;
+ s->tls = tcfg;
+ if (tcfg) {
+ nni_tls_config_hold(tcfg);
+ }
+ nni_mtx_unlock(&s->mtx);
+ if (old) {
+ nng_tls_config_fini(old);
+ }
+ return (0);
+}
+#endif
+
static int
http_server_sys_init(void)
{
diff --git a/src/supplemental/mbedtls/CMakeLists.txt b/src/supplemental/mbedtls/CMakeLists.txt
deleted file mode 100644
index 5c2de10b..00000000
--- a/src/supplemental/mbedtls/CMakeLists.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-#
-# Copyright 2017 Garrett D'Amore <garrett@damore.org>
-# Copyright 2017 Capitar IT Group BV <info@capitar.com>
-#
-# This software is supplied under the terms of the MIT License, a
-# copy of which should be located in the distribution where this
-# file was obtained (LICENSE.txt). A copy of the license may also be
-# found online at https://opensource.org/licenses/MIT.
-#
-
-# MBEDTLS library
-
-# This requires the mbedTLS library be installed somewhere. You can
-# point this at a suitable installation of mbedTLS by setting
-# MBEDTLS_ROOT_DIR to point at the root of the installation (prefix).
-
-# It is possible to minimize the mbedTLS library quite a bit. We do
-# not require legacy algorithms, the net_sockets layer, the filesystem
-# I/O, as well as various other tidbits. We provide an entropy source,
-# so you can disable that in mbedTLS too. You may disable fallback support,
-# as we only support TLS v1.2 at present. (You may also therefore remove
-# code to support older versions of TLS/SSL.) You may also remove DTLS,
-# since we're not using it now (nor are we likely to in the near feature).
-# Also you may remove support for ZLIB compression, we don't use it either
-# (and it would be insecure to do so.) PEM and X509 writing (encoding)
-# is not needed (but parse support is!) You may also remove session support,
-# as we don't use that either.
-#
-# (Look for a sample config.h in this directory, if you want to build
-# a minimized version just for nng.)
-
-# What we do require is support for TLSv1.2
-
-if (NNG_MBEDTLS_ENABLE)
- set(SUPP_SOURCES supplemental/mbedtls/tls.c supplemental/tls.h)
- Find_Package(mbedTLS REQUIRED)
-
- # If it isn't already in the link list, add the TLS libraries there.
- # or something, so we take care not to duplicate it).
- list(FIND NNG_REQUIRED_LIBRARIES ${MBEDTLS_TLS_LIBRARY} _index)
- if (_index EQUAL -1)
- set(NNG_REQUIRED_LIBRARIES ${NNG_REQUIRED_LIBRARIES} ${MBEDTLS_LIBRARIES})
- set(NNG_REQUIRED_LIBRARIES ${NNG_REQUIRED_LIBRARIES} PARENT_SCOPE)
- endif()
-
- # Likewise for the include search path.
- list(FIND NNG_REQUIRED_INCLUDES ${MBEDTLS_INCLUDE_DIR} _index)
- if (_index EQUAL -1)
- set(NNG_REQUIRED_INCLUDES ${NNG_REQUIRED_INCLUDES} ${MBEDTLS_INCLUDE_DIR})
- set(NNG_REQUIRED_INCLUDES ${NNG_REQUIRED_INCLUDES} PARENT_SCOPE)
- endif()
-endif()
-
-set(NNG_SOURCES ${NNG_SOURCES} ${SUPP_SOURCES} PARENT_SCOPE)
diff --git a/src/supplemental/tls.h b/src/supplemental/tls.h
deleted file mode 100644
index da2fe8cd..00000000
--- a/src/supplemental/tls.h
+++ /dev/null
@@ -1,84 +0,0 @@
-//
-// Copyright 2017 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2017 Capitar IT Group BV <info@capitar.com>
-//
-// This software is supplied under the terms of the MIT License, a
-// copy of which should be located in the distribution where this
-// file was obtained (LICENSE.txt). A copy of the license may also be
-// found online at https://opensource.org/licenses/MIT.
-//
-
-#ifndef NNG_SUPPLEMENTAL_TLS_H
-#define NNG_SUPPLEMENTAL_TLS_H
-
-// nni_tls represents the context for a single TLS stream.
-typedef struct nni_tls nni_tls;
-
-// nni_tls_config is the context for full TLS configuration, normally
-// associated with an endpoint, for example.
-typedef struct nni_tls_config nni_tls_config;
-
-#define NNI_TLS_CONFIG_SERVER 1
-#define NNI_TLS_CONFIG_CLIENT 0
-
-extern int nni_tls_config_init(nni_tls_config **, int);
-extern void nni_tls_config_fini(nni_tls_config *);
-
-// nni_tls_config_server_name is used by clients to set the server name
-// that they expect to be talking to. This may also support the SNI
-// extension for virtual hosting.
-extern int nni_tls_config_server_name(nni_tls_config *, const char *);
-
-// nni_tls_config_ca_cert configures one or more CAs used for validation
-// of peer certificates. Multiple CAs (and their chains) may be configured
-// by either calling this multiple times, or by specifying a list of
-// certificates as concatenated data. The certs may be in PEM or DER
-// format.
-extern int nni_tls_config_ca_cert(nni_tls_config *, const uint8_t *, size_t);
-
-// nni_tls_config_clr loads a certificate revocation list. Again, these
-// are in X.509 format (either PEM or DER).
-extern int nni_tls_config_crl(nni_tls_config *, const uint8_t *, size_t);
-
-// nni_tls_config_cert is used to load our own certificate. For servers,
-// this may be called more than once to configure multiple different keys,
-// for example with different algorithms depending on what the peer supports.
-// On the client, only a single option is available.
-extern int nni_tls_config_cert(nni_tls_config *, const uint8_t *crt, size_t);
-extern int nni_tls_config_key(nni_tls_config *, const uint8_t *, size_t);
-extern int nni_tls_config_pass(nni_tls_config *, const char *);
-
-// nni_tls_config_validate_peer is used to enable validation of the peer
-// and it's certificate. If disabled, the peer's certificate will still
-// be available, but may not be valid.
-extern int nni_tls_config_validate_peer(nni_tls_config *, bool);
-
-// nni_tls_config_auth_mode is a read-ony option that is used to configure
-// the authentication mode use. The default is that servers have this off
-// (i.e. no client authentication) and clients have it on (they verify
-// the server), which matches typical practice.
-extern int nni_tls_config_auth_mode(nni_tls_config *, int);
-#define NNI_TLS_CONFIG_AUTH_MODE_NONE 0 // No verification is performed
-#define NNI_TLS_CONFIG_AUTH_MODE_OPTIONAL 1 // Verify cert if presented
-#define NNI_TLS_CONFIG_AUTH_MODE_REQUIRED 2 // Verify cert, close if invalid
-
-extern int nni_tls_init(nni_tls **, nni_tls_config *, nni_plat_tcp_pipe *);
-extern void nni_tls_close(nni_tls *);
-extern void nni_tls_fini(nni_tls *);
-extern void nni_tls_send(nni_tls *, nni_aio *);
-extern void nni_tls_recv(nni_tls *, nni_aio *);
-
-// nni_tls_verified returns true if the peer, or false if the peer did not
-// verify. (During the handshake phase, the peer is not verified, so this
-// might return false if executed too soon. The verification status will
-// be accurate once the handshake is finished, however.
-extern int nni_tls_verified(nni_tls *);
-
-// nni_tls_ciphersuite_name returns the name of the ciphersuite in use.
-extern const char *nni_tls_ciphersuite_name(nni_tls *);
-
-// TBD: getting additional peer certificate information...
-
-extern void nni_tls_strerror(int, char *, size_t); // review this
-
-#endif // NNG_SUPPLEMENTAL_TLS_H
diff --git a/src/supplemental/tls/CMakeLists.txt b/src/supplemental/tls/CMakeLists.txt
new file mode 100644
index 00000000..e78f1c13
--- /dev/null
+++ b/src/supplemental/tls/CMakeLists.txt
@@ -0,0 +1,38 @@
+#
+# Copyright 2017 Capitar IT Group BV <info@capitar.com>
+# Copyright 2017 Staysail Systems, Inc. <info@staysail.tech>
+#
+# This software is supplied under the terms of the MIT License, a
+# copy of which should be located in the distribution where this
+# file was obtained (LICENSE.txt). A copy of the license may also be
+# found online at https://opensource.org/licenses/MIT.
+#
+
+if (NNG_SUPP_TLS)
+ set(NNG_SUPP_TLS_MBEDTLS ON)
+ set(TLS_SOURCES supplemental/tls/tls.h)
+endif()
+
+# For now we only support the ARM mbedTLS library.
+if (NNG_SUPP_TLS_MBEDTLS)
+
+ Find_Package(mbedTLS REQUIRED)
+
+ # If it isn't already in the link list, add the TLS libraries there.
+ # or something, so we take care not to duplicate it).
+ list(FIND NNG_REQUIRED_LIBRARIES ${MBEDTLS_TLS_LIBRARY} _index)
+ if (_index EQUAL -1)
+ set(NNG_REQUIRED_LIBRARIES ${NNG_REQUIRED_LIBRARIES} ${MBEDTLS_LIBRARIES})
+ set(NNG_REQUIRED_LIBRARIES ${NNG_REQUIRED_LIBRARIES} PARENT_SCOPE)
+ endif()
+
+ # Likewise for the include search path.
+ list(FIND NNG_REQUIRED_INCLUDES ${MBEDTLS_INCLUDE_DIR} _index)
+ if (_index EQUAL -1)
+ set(NNG_REQUIRED_INCLUDES ${NNG_REQUIRED_INCLUDES} ${MBEDTLS_INCLUDE_DIR})
+ set(NNG_REQUIRED_INCLUDES ${NNG_REQUIRED_INCLUDES} PARENT_SCOPE)
+ endif()
+ set(TLS_SOURCES ${TLS_SOURCES} supplemental/tls/mbedtls/tls.c)
+endif()
+
+set(NNG_SOURCES ${NNG_SOURCES} ${TLS_SOURCES} PARENT_SCOPE)
diff --git a/src/supplemental/mbedtls/tls.c b/src/supplemental/tls/mbedtls/tls.c
index d64447ac..3bbf4a33 100644
--- a/src/supplemental/mbedtls/tls.c
+++ b/src/supplemental/tls/mbedtls/tls.c
@@ -8,7 +8,6 @@
// found online at https://opensource.org/licenses/MIT.
//
-#ifdef NNG_MBEDTLS_ENABLE
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@@ -29,7 +28,7 @@
#include "core/nng_impl.h"
-#include "supplemental/tls.h"
+#include "supplemental/tls/tls.h"
// Implementation note. This implementation buffers data between the TLS
// encryption layer (mbedTLS) and the underlying TCP socket. As a result,
@@ -66,6 +65,7 @@ typedef struct nni_tls_certkey {
struct nni_tls {
nni_plat_tcp_pipe * tcp;
mbedtls_ssl_context ctx;
+ nng_tls_config * cfg; // kept so we can release it
nni_mtx lk;
nni_aio * tcp_send;
nni_aio * tcp_recv;
@@ -86,7 +86,7 @@ struct nni_tls {
nni_aio * handshake; // handshake aio (upper)
};
-struct nni_tls_config {
+struct nng_tls_config {
mbedtls_ssl_config cfg_ctx;
nni_mtx lk;
bool active;
@@ -100,6 +100,8 @@ struct nni_tls_config {
bool have_ca_certs;
bool have_crl;
+ int refcnt; // servers increment the reference
+
nni_list certkeys;
};
@@ -142,7 +144,7 @@ nni_tls_random(void *arg, unsigned char *buf, size_t sz)
{
#ifdef NNG_TLS_USE_CTR_DRBG
int rv;
- nni_tls_config *cfg = arg;
+ nng_tls_config *cfg = arg;
NNI_ARG_UNUSED(arg);
nni_mtx_lock(&cfg->rng_lk);
@@ -155,10 +157,18 @@ nni_tls_random(void *arg, unsigned char *buf, size_t sz)
}
void
-nni_tls_config_fini(nni_tls_config *cfg)
+nng_tls_config_fini(nng_tls_config *cfg)
{
nni_tls_certkey *ck;
+ nni_mtx_lock(&cfg->lk);
+ cfg->refcnt--;
+ if (cfg->refcnt != 0) {
+ nni_mtx_unlock(&cfg->lk);
+ return;
+ }
+ nni_mtx_unlock(&cfg->lk);
+
mbedtls_ssl_config_free(&cfg->cfg_ctx);
#ifdef NNG_TLS_USE_CTR_DRBG
mbedtls_ctr_drbg_free(&cfg->rng_ctx);
@@ -189,9 +199,9 @@ nni_tls_config_fini(nni_tls_config *cfg)
}
int
-nni_tls_config_init(nni_tls_config **cpp, int mode)
+nng_tls_config_init(nng_tls_config **cpp, enum nng_tls_mode mode)
{
- nni_tls_config *cfg;
+ nng_tls_config *cfg;
int rv;
int sslmode;
int authmode;
@@ -199,8 +209,9 @@ nni_tls_config_init(nni_tls_config **cpp, int mode)
if ((cfg = NNI_ALLOC_STRUCT(cfg)) == NULL) {
return (NNG_ENOMEM);
}
+ cfg->refcnt = 1;
nni_mtx_init(&cfg->lk);
- if (mode == NNI_TLS_CONFIG_SERVER) {
+ if (mode == NNG_TLS_MODE_SERVER) {
sslmode = MBEDTLS_SSL_IS_SERVER;
authmode = MBEDTLS_SSL_VERIFY_NONE;
} else {
@@ -216,7 +227,7 @@ nni_tls_config_init(nni_tls_config **cpp, int mode)
rv = mbedtls_ssl_config_defaults(&cfg->cfg_ctx, sslmode,
MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
if (rv != 0) {
- nni_tls_config_fini(cfg);
+ nng_tls_config_fini(cfg);
return (rv);
}
@@ -231,7 +242,7 @@ nni_tls_config_init(nni_tls_config **cpp, int mode)
rv = mbedtls_ctr_drbg_seed(
&cfg->rng_ctx, nni_tls_get_entropy, NULL, NULL, 0);
if (rv != 0) {
- nni_tls_config_fini(cfg);
+ nng_tls_config_fini(cfg);
return (rv);
}
#endif
@@ -244,6 +255,14 @@ nni_tls_config_init(nni_tls_config **cpp, int mode)
}
void
+nni_tls_config_hold(nng_tls_config *cfg)
+{
+ nni_mtx_lock(&cfg->lk);
+ cfg->refcnt++;
+ nni_mtx_unlock(&cfg->lk);
+}
+
+void
nni_tls_fini(nni_tls *tp)
{
// Shut it all down first.
@@ -263,6 +282,10 @@ nni_tls_fini(nni_tls *tp)
nni_mtx_fini(&tp->lk);
nni_free(tp->recvbuf, NNG_TLS_MAX_RECV_SIZE);
nni_free(tp->sendbuf, NNG_TLS_MAX_RECV_SIZE);
+ if (tp->cfg != NULL) {
+ // release the hold we got on it
+ nng_tls_config_fini(tp->cfg);
+ }
NNI_FREE_STRUCT(tp);
}
@@ -290,7 +313,7 @@ nni_tls_mkerr(int err)
}
int
-nni_tls_init(nni_tls **tpp, nni_tls_config *cfg, nni_plat_tcp_pipe *tcp)
+nni_tls_init(nni_tls **tpp, nng_tls_config *cfg, nni_plat_tcp_pipe *tcp)
{
nni_tls *tp;
int rv;
@@ -348,6 +371,8 @@ nni_tls_init(nni_tls **tpp, nni_tls_config *cfg, nni_plat_tcp_pipe *tcp)
}
cfg->active = true;
}
+ cfg->refcnt++;
+ tp->cfg = cfg;
nni_mtx_unlock(&cfg->lk);
nni_aio_list_init(&tp->sends);
@@ -595,6 +620,18 @@ nni_tls_recv(nni_tls *tp, nni_aio *aio)
nni_mtx_unlock(&tp->lk);
}
+int
+nni_tls_peername(nni_tls *tp, nni_sockaddr *sa)
+{
+ return (nni_plat_tcp_pipe_peername(tp->tcp, sa));
+}
+
+int
+nni_tls_sockname(nni_tls *tp, nni_sockaddr *sa)
+{
+ return (nni_plat_tcp_pipe_sockname(tp->tcp, sa));
+}
+
void
nni_tls_do_handshake(nni_tls *tp)
{
@@ -758,7 +795,7 @@ nni_tls_verified(nni_tls *tp)
}
int
-nni_tls_config_server_name(nni_tls_config *cfg, const char *name)
+nng_tls_config_server_name(nng_tls_config *cfg, const char *name)
{
int rv;
nni_mtx_lock(&cfg->lk);
@@ -776,7 +813,7 @@ nni_tls_config_server_name(nni_tls_config *cfg, const char *name)
}
int
-nni_tls_config_auth_mode(nni_tls_config *cfg, int mode)
+nng_tls_config_auth_mode(nng_tls_config *cfg, nng_tls_auth_mode mode)
{
nni_mtx_lock(&cfg->lk);
if (cfg->active) {
@@ -784,15 +821,15 @@ nni_tls_config_auth_mode(nni_tls_config *cfg, int mode)
return (NNG_ESTATE);
}
switch (mode) {
- case NNI_TLS_CONFIG_AUTH_MODE_NONE:
+ case NNG_TLS_AUTH_MODE_NONE:
mbedtls_ssl_conf_authmode(
&cfg->cfg_ctx, MBEDTLS_SSL_VERIFY_NONE);
break;
- case NNI_TLS_CONFIG_AUTH_MODE_OPTIONAL:
+ case NNG_TLS_AUTH_MODE_OPTIONAL:
mbedtls_ssl_conf_authmode(
&cfg->cfg_ctx, MBEDTLS_SSL_VERIFY_OPTIONAL);
break;
- case NNI_TLS_CONFIG_AUTH_MODE_REQUIRED:
+ case NNG_TLS_AUTH_MODE_REQUIRED:
mbedtls_ssl_conf_authmode(
&cfg->cfg_ctx, MBEDTLS_SSL_VERIFY_REQUIRED);
break;
@@ -844,7 +881,7 @@ nni_tls_copy_key_cert_material(
}
int
-nni_tls_config_cert(nni_tls_config *cfg, const uint8_t *key, size_t sz)
+nng_tls_config_cert(nng_tls_config *cfg, const uint8_t *key, size_t sz)
{
int rv = 0;
nni_tls_certkey *ck;
@@ -885,7 +922,7 @@ err:
}
int
-nni_tls_config_key(nni_tls_config *cfg, const uint8_t *key, size_t sz)
+nng_tls_config_key(nng_tls_config *cfg, const uint8_t *key, size_t sz)
{
int rv = 0;
nni_tls_certkey *ck;
@@ -924,7 +961,7 @@ err:
}
int
-nni_tls_config_pass(nni_tls_config *cfg, const char *pass)
+nng_tls_config_pass(nng_tls_config *cfg, const char *pass)
{
int rv = 0;
nni_tls_certkey *ck;
@@ -964,7 +1001,7 @@ err:
}
int
-nni_tls_config_ca_cert(nni_tls_config *cfg, const uint8_t *data, size_t sz)
+nng_tls_config_ca_cert(nng_tls_config *cfg, const uint8_t *data, size_t sz)
{
uint8_t *tmp;
size_t len = sz;
@@ -998,7 +1035,7 @@ err:
}
int
-nni_tls_config_crl(nni_tls_config *cfg, const uint8_t *data, size_t sz)
+nng_tls_config_crl(nng_tls_config *cfg, const uint8_t *data, size_t sz)
{
int rv;
uint8_t *tmp;
@@ -1028,4 +1065,3 @@ err:
nni_free(tmp, len);
return (rv);
}
-#endif // NNG_MBEDTLS_ENABLE \ No newline at end of file
diff --git a/src/supplemental/tls/tls.h b/src/supplemental/tls/tls.h
new file mode 100644
index 00000000..0c9e791f
--- /dev/null
+++ b/src/supplemental/tls/tls.h
@@ -0,0 +1,45 @@
+//
+// Copyright 2017 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2017 Capitar IT Group BV <info@capitar.com>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+#ifndef NNG_SUPPLEMENTAL_TLS_TLS_H
+#define NNG_SUPPLEMENTAL_TLS_TLS_H
+
+// nni_tls represents the context for a single TLS stream.
+typedef struct nni_tls nni_tls;
+
+// nni_tls_config_hold is used to get a hold on the config
+// object, preventing it from being released inadvertently.
+// The hold is released with a call to nng_tls_config_fini().
+// Note that a hold need not be acquired at creation, since
+// the configuration object is created with a hold on it.
+extern void nni_tls_config_hold(nng_tls_config *);
+
+extern int nni_tls_init(nni_tls **, nng_tls_config *, nni_plat_tcp_pipe *);
+extern void nni_tls_close(nni_tls *);
+extern void nni_tls_fini(nni_tls *);
+extern void nni_tls_send(nni_tls *, nni_aio *);
+extern void nni_tls_recv(nni_tls *, nni_aio *);
+extern int nni_tls_sockname(nni_tls *, nni_sockaddr *);
+extern int nni_tls_peername(nni_tls *, nni_sockaddr *);
+
+// nni_tls_verified returns true if the peer, or false if the peer did not
+// verify. (During the handshake phase, the peer is not verified, so this
+// might return false if executed too soon. The verification status will
+// be accurate once the handshake is finished, however.
+extern int nni_tls_verified(nni_tls *);
+
+// nni_tls_ciphersuite_name returns the name of the ciphersuite in use.
+extern const char *nni_tls_ciphersuite_name(nni_tls *);
+
+// TBD: getting additional peer certificate information...
+
+extern void nni_tls_strerror(int, char *, size_t); // review this
+
+#endif // NNG_SUPPLEMENTAL_TLS_TLS_H
diff --git a/src/supplemental/websocket/websocket.c b/src/supplemental/websocket/websocket.c
index 06e1c70a..c7181595 100644
--- a/src/supplemental/websocket/websocket.c
+++ b/src/supplemental/websocket/websocket.c
@@ -55,7 +55,6 @@ struct nni_ws {
};
struct nni_ws_listener {
- nni_tls_config * tls;
nni_http_server * server;
char * proto;
char * url;
@@ -82,7 +81,6 @@ struct nni_ws_listener {
// completion of an earlier connection. (We don't want to establish
// requests when we already have connects negotiating.)
struct nni_ws_dialer {
- nni_tls_config * tls;
nni_http_req * req;
nni_http_res * res;
nni_http_client *client;
@@ -1296,6 +1294,13 @@ nni_ws_listener_fini(nni_ws_listener *l)
{
ws_header *hdr;
+ nni_ws_listener_close(l);
+
+ if (l->server != NULL) {
+ nni_http_server_fini(l->server);
+ l->server = NULL;
+ }
+
nni_mtx_fini(&l->mtx);
nni_strfree(l->url);
nni_strfree(l->proto);
@@ -1560,6 +1565,8 @@ nni_ws_listener_init(nni_ws_listener **wslp, const char *url)
{
nni_ws_listener *l;
int rv;
+ nni_aio * aio;
+ nni_sockaddr sa;
if ((l = NNI_ALLOC_STRUCT(l)) == NULL) {
return (NNG_ENOMEM);
@@ -1582,6 +1589,24 @@ nni_ws_listener_init(nni_ws_listener **wslp, const char *url)
l->handler.h_host = l->host;
l->handler.h_cb = ws_handler;
+ if ((rv = nni_aio_init(&aio, NULL, NULL)) != 0) {
+ nni_ws_listener_fini(l);
+ return (rv);
+ }
+ aio->a_addr = &sa;
+ nni_plat_tcp_resolv(l->host, l->serv, NNG_AF_UNSPEC, true, aio);
+ nni_aio_wait(aio);
+ rv = nni_aio_result(aio);
+ nni_aio_fini(aio);
+ if (rv != 0) {
+ nni_ws_listener_fini(l);
+ return (rv);
+ }
+ if ((rv = nni_http_server_init(&l->server, &sa)) != 0) {
+ nni_ws_listener_fini(l);
+ return (rv);
+ }
+
*wslp = l;
return (0);
}
@@ -1658,10 +1683,10 @@ nni_ws_listener_close(nni_ws_listener *l)
return;
}
l->closed = true;
- if (l->server != NULL) {
+ if (l->started) {
nni_http_server_del_handler(l->server, l->hp);
- nni_http_server_fini(l->server);
- l->server = NULL;
+ nni_http_server_stop(l->server);
+ l->started = false;
}
NNI_LIST_FOREACH (&l->pend, ws) {
nni_ws_close_error(ws, WS_CLOSE_GOING_AWAY);
@@ -1675,9 +1700,7 @@ nni_ws_listener_close(nni_ws_listener *l)
int
nni_ws_listener_listen(nni_ws_listener *l)
{
- nng_sockaddr sa;
- nni_aio * aio;
- int rv;
+ int rv;
nni_mtx_lock(&l->mtx);
if (l->closed) {
@@ -1689,25 +1712,6 @@ nni_ws_listener_listen(nni_ws_listener *l)
return (NNG_ESTATE);
}
- if ((rv = nni_aio_init(&aio, NULL, NULL)) != 0) {
- nni_mtx_unlock(&l->mtx);
- return (rv);
- }
- aio->a_addr = &sa;
- nni_plat_tcp_resolv(l->host, l->serv, NNG_AF_UNSPEC, true, aio);
- nni_aio_wait(aio);
- rv = nni_aio_result(aio);
- nni_aio_fini(aio);
- if (rv != 0) {
- nni_mtx_unlock(&l->mtx);
- return (rv);
- }
-
- if ((rv = nni_http_server_init(&l->server, &sa)) != 0) {
- nni_mtx_unlock(&l->mtx);
- return (rv);
- }
-
rv = nni_http_server_add_handler(&l->hp, l->server, &l->handler, l);
if (rv != 0) {
nni_http_server_fini(l->server);
@@ -1716,12 +1720,12 @@ nni_ws_listener_listen(nni_ws_listener *l)
return (rv);
}
- // XXX: DEAL WITH HTTPS here.
-
if ((rv = nni_http_server_start(l->server)) != 0) {
nni_http_server_del_handler(l->server, l->hp);
nni_http_server_fini(l->server);
l->server = NULL;
+ nni_mtx_unlock(&l->mtx);
+ return (rv);
}
l->started = true;
@@ -1740,11 +1744,17 @@ nni_ws_listener_hook(
nni_mtx_unlock(&l->mtx);
}
-void
-nni_ws_listener_tls(nni_ws_listener *l, nni_tls_config *tls)
+#ifdef NNG_SUPP_TLS
+int
+nni_ws_listener_set_tls(nni_ws_listener *l, nng_tls_config *tls)
{
- // We need to add this later.
+ int rv;
+ nni_mtx_lock(&l->mtx);
+ rv = nni_http_server_set_tls(l->server, tls);
+ nni_mtx_unlock(&l->mtx);
+ return (rv);
}
+#endif
void
ws_conn_cb(void *arg)
@@ -1931,6 +1941,18 @@ nni_ws_dialer_init(nni_ws_dialer **dp, const char *url)
return (0);
}
+#ifdef NNG_SUPP_TLS
+int
+nni_ws_dialer_set_tls(nni_ws_dialer *d, nng_tls_config *tls)
+{
+ int rv;
+ nni_mtx_lock(&d->mtx);
+ rv = nni_http_client_set_tls(d->client, tls);
+ nni_mtx_unlock(&d->mtx);
+ return (rv);
+}
+#endif
+
void
nni_ws_dialer_close(nni_ws_dialer *d)
{
diff --git a/src/supplemental/websocket/websocket.h b/src/supplemental/websocket/websocket.h
index 95147a9f..ccf549df 100644
--- a/src/supplemental/websocket/websocket.h
+++ b/src/supplemental/websocket/websocket.h
@@ -12,9 +12,8 @@
#define NNG_SUPPLEMENTAL_WEBSOCKET_WEBSOCKET_H
// Pre-defined types for some prototypes. These are from other subsystems.
-typedef struct nni_tls_config nni_tls_config;
-typedef struct nni_http_req nni_http_req;
-typedef struct nni_http_res nni_http_res;
+typedef struct nni_http_req nni_http_req;
+typedef struct nni_http_res nni_http_res;
typedef struct nni_ws nni_ws;
typedef struct nni_ws_listener nni_ws_listener;
@@ -36,7 +35,7 @@ extern int nni_ws_listener_listen(nni_ws_listener *);
extern void nni_ws_listener_accept(nni_ws_listener *, nni_aio *);
extern void nni_ws_listener_hook(
nni_ws_listener *, nni_ws_listen_hook, void *);
-extern void nni_ws_listener_tls(nni_ws_listener *, nni_tls_config *);
+extern int nni_ws_listener_set_tls(nni_ws_listener *, nng_tls_config *);
extern int nni_ws_dialer_init(nni_ws_dialer **, const char *);
extern void nni_ws_dialer_fini(nni_ws_dialer *);
@@ -44,6 +43,7 @@ extern void nni_ws_dialer_close(nni_ws_dialer *);
extern int nni_ws_dialer_proto(nni_ws_dialer *, const char *);
extern int nni_ws_dialer_header(nni_ws_dialer *, const char *, const char *);
extern void nni_ws_dialer_dial(nni_ws_dialer *, nni_aio *);
+extern int nni_ws_dialer_set_tls(nni_ws_dialer *, nng_tls_config *);
// Dialer does not get a hook chance, as it can examine the request and reply
// after dial is done; this is not a 3-way handshake, so the dialer does
diff --git a/src/transport/tls/tls.c b/src/transport/tls/tls.c
index 9c794e64..f2ca6d35 100644
--- a/src/transport/tls/tls.c
+++ b/src/transport/tls/tls.c
@@ -14,7 +14,7 @@
#include "core/nng_impl.h"
-#include "supplemental/tls.h"
+#include "supplemental/tls/tls.h"
#include "tls.h"
// TLS over TCP transport. Platform specific TCP operations must be
@@ -61,7 +61,7 @@ struct nni_tls_ep {
nni_aio * aio;
nni_aio * user_aio;
nni_mtx mtx;
- nni_tls_config * cfg;
+ nng_tls_config * cfg;
};
static void nni_tls_pipe_send_cb(void *);
@@ -477,7 +477,7 @@ nni_tls_pipe_getopt_locaddr(void *arg, void *v, size_t *szp)
nng_sockaddr sa;
memset(&sa, 0, sizeof(sa));
- if ((rv = nni_plat_tcp_pipe_sockname(p->tcp, &sa)) == 0) {
+ if ((rv = nni_tls_sockname(p->tls, &sa)) == 0) {
rv = nni_getopt_sockaddr(&sa, v, szp);
}
return (rv);
@@ -491,7 +491,7 @@ nni_tls_pipe_getopt_remaddr(void *arg, void *v, size_t *szp)
nng_sockaddr sa;
memset(&sa, 0, sizeof(sa));
- if ((rv = nni_plat_tcp_pipe_peername(p->tcp, &sa)) == 0) {
+ if ((rv = nni_tls_peername(p->tls, &sa)) == 0) {
rv = nni_getopt_sockaddr(&sa, v, szp);
}
return (rv);
@@ -589,7 +589,7 @@ nni_tls_ep_fini(void *arg)
nni_plat_tcp_ep_fini(ep->tep);
}
if (ep->cfg) {
- nni_tls_config_fini(ep->cfg);
+ nng_tls_config_fini(ep->cfg);
}
nni_aio_fini(ep->aio);
nni_mtx_fini(&ep->mtx);
@@ -599,18 +599,18 @@ nni_tls_ep_fini(void *arg)
static int
nni_tls_ep_init(void **epp, const char *url, nni_sock *sock, int mode)
{
- nni_tls_ep * ep;
- int rv;
- char buf[NNG_MAXADDRLEN + 1];
- char * rhost;
- char * rserv;
- char * lhost;
- char * lserv;
- nni_sockaddr rsa, lsa;
- nni_aio * aio;
- int passive;
- int tlsmode;
- int authmode;
+ nni_tls_ep * ep;
+ int rv;
+ char buf[NNG_MAXADDRLEN + 1];
+ char * rhost;
+ char * rserv;
+ char * lhost;
+ char * lserv;
+ nni_sockaddr rsa, lsa;
+ nni_aio * aio;
+ int passive;
+ nng_tls_mode tlsmode;
+ nng_tls_auth_mode authmode;
// Make a copy of the url (to allow for destructive operations)
if (nni_strlcpy(buf, url, sizeof(buf)) >= sizeof(buf)) {
@@ -628,12 +628,12 @@ nni_tls_ep_init(void **epp, const char *url, nni_sock *sock, int mode)
}
if (mode == NNI_EP_MODE_DIAL) {
passive = 0;
- tlsmode = NNI_TLS_CONFIG_CLIENT;
- authmode = NNI_TLS_CONFIG_AUTH_MODE_REQUIRED;
+ tlsmode = NNG_TLS_MODE_CLIENT;
+ authmode = NNG_TLS_AUTH_MODE_REQUIRED;
} else {
passive = 1;
- tlsmode = NNI_TLS_CONFIG_SERVER;
- authmode = NNI_TLS_CONFIG_AUTH_MODE_NONE;
+ tlsmode = NNG_TLS_MODE_SERVER;
+ authmode = NNG_TLS_AUTH_MODE_NONE;
}
// XXX: arguably we could defer this part to the point we do a bind
@@ -684,15 +684,15 @@ nni_tls_ep_init(void **epp, const char *url, nni_sock *sock, int mode)
}
if (((rv = nni_plat_tcp_ep_init(&ep->tep, &lsa, &rsa, mode)) != 0) ||
- ((rv = nni_tls_config_init(&ep->cfg, tlsmode)) != 0) ||
- ((rv = nni_tls_config_auth_mode(ep->cfg, authmode)) != 0) ||
+ ((rv = nng_tls_config_init(&ep->cfg, tlsmode)) != 0) ||
+ ((rv = nng_tls_config_auth_mode(ep->cfg, authmode)) != 0) ||
((rv = nni_aio_init(&ep->aio, nni_tls_ep_cb, ep)) != 0)) {
nni_strfree(rhost);
nni_tls_ep_fini(ep);
return (rv);
}
- if ((tlsmode == NNI_TLS_CONFIG_CLIENT) && (rhost != NULL)) {
- if ((rv = nni_tls_config_server_name(ep->cfg, rhost)) != 0) {
+ if ((tlsmode == NNG_TLS_MODE_CLIENT) && (rhost != NULL)) {
+ if ((rv = nng_tls_config_server_name(ep->cfg, rhost)) != 0) {
nni_strfree(rhost);
nni_tls_ep_fini(ep);
return (rv);
@@ -868,6 +868,38 @@ nni_tls_ep_getopt_linger(void *arg, void *v, size_t *szp)
}
static int
+tls_setopt_config(void *arg, const void *data, size_t sz)
+{
+ nni_tls_ep * ep = arg;
+ nng_tls_config *cfg, *old;
+
+ if (sz != sizeof(cfg)) {
+ return (NNG_EINVAL);
+ }
+ memcpy(&cfg, data, sz);
+ if (cfg == NULL) {
+ return (NNG_EINVAL);
+ }
+ if (ep == NULL) {
+ return (0);
+ }
+ old = ep->cfg;
+ nni_tls_config_hold(cfg);
+ ep->cfg = cfg;
+ if (old != NULL) {
+ nng_tls_config_fini(old);
+ }
+ return (0);
+}
+
+static int
+tls_getopt_config(void *arg, void *v, size_t *szp)
+{
+ nni_tls_ep *ep = arg;
+ return (nni_getopt_ptr(ep->cfg, v, szp));
+}
+
+static int
tls_setopt_ca_cert(void *arg, const void *data, size_t sz)
{
nni_tls_ep *ep = arg;
@@ -875,7 +907,7 @@ tls_setopt_ca_cert(void *arg, const void *data, size_t sz)
if (ep == NULL) {
return (0);
}
- return (nni_tls_config_ca_cert(ep->cfg, data, sz));
+ return (nng_tls_config_ca_cert(ep->cfg, data, sz));
}
static int
@@ -886,7 +918,7 @@ tls_setopt_cert(void *arg, const void *data, size_t sz)
if (ep == NULL) {
return (0);
}
- return (nni_tls_config_cert(ep->cfg, data, sz));
+ return (nng_tls_config_cert(ep->cfg, data, sz));
}
static int
@@ -897,7 +929,7 @@ tls_setopt_private_key(void *arg, const void *data, size_t sz)
if (ep == NULL) {
return (0);
}
- return (nni_tls_config_key(ep->cfg, data, sz));
+ return (nng_tls_config_key(ep->cfg, data, sz));
}
static int
@@ -914,13 +946,9 @@ tls_setopt_pass(void *arg, const void *data, size_t sz)
if (ep == NULL) {
return (0);
}
- return (nni_tls_config_pass(ep->cfg, data));
+ return (nng_tls_config_pass(ep->cfg, data));
}
-int nng_tls_auth_mode_none = NNI_TLS_CONFIG_AUTH_MODE_NONE;
-int nng_tls_auth_mode_required = NNI_TLS_CONFIG_AUTH_MODE_REQUIRED;
-int nng_tls_auth_mode_optional = NNI_TLS_CONFIG_AUTH_MODE_OPTIONAL;
-
static int
tls_getopt_auth_mode(void *arg, void *v, size_t *szp)
{
@@ -938,9 +966,9 @@ tls_setopt_auth_mode(void *arg, const void *data, size_t sz)
rv = nni_setopt_int(&mode, data, sz, -100, 100);
if (rv == 0) {
switch (mode) {
- case NNI_TLS_CONFIG_AUTH_MODE_NONE:
- case NNI_TLS_CONFIG_AUTH_MODE_OPTIONAL:
- case NNI_TLS_CONFIG_AUTH_MODE_REQUIRED:
+ case NNG_TLS_AUTH_MODE_NONE:
+ case NNG_TLS_AUTH_MODE_OPTIONAL:
+ case NNG_TLS_AUTH_MODE_REQUIRED:
break;
default:
rv = NNG_EINVAL;
@@ -952,7 +980,7 @@ tls_setopt_auth_mode(void *arg, const void *data, size_t sz)
return (rv);
}
- if ((rv = nni_tls_config_auth_mode(ep->cfg, mode)) == 0) {
+ if ((rv = nng_tls_config_auth_mode(ep->cfg, mode)) == 0) {
ep->authmode = mode;
}
return (rv);
@@ -998,6 +1026,11 @@ static nni_tran_ep_option nni_tls_ep_options[] = {
.eo_setopt = nni_tls_ep_setopt_linger,
},
{
+ .eo_name = NNG_OPT_TLS_CONFIG,
+ .eo_getopt = tls_getopt_config,
+ .eo_setopt = tls_setopt_config,
+ },
+ {
.eo_name = NNG_OPT_TLS_CA_CERT,
.eo_getopt = NULL,
.eo_setopt = tls_setopt_ca_cert,
diff --git a/src/transport/tls/tls.h b/src/transport/tls/tls.h
index 4317ae55..b36ee774 100644
--- a/src/transport/tls/tls.h
+++ b/src/transport/tls/tls.h
@@ -49,14 +49,12 @@ NNG_DECL int nng_tls_register(void);
// and off on servers/listeners, by default.
#define NNG_OPT_TLS_AUTH_MODE "tls:auth-mode"
-extern int nng_tls_auth_mode_required;
-extern int nng_tls_auth_mode_none;
-extern int nng_tls_auth_mode_optional;
-
// NNG_OPT_TLS_AUTH_VERIFIED is a boolean that can be read on pipes,
// indicating whether the peer certificate is verified.
#define NNG_OPT_TLS_AUTH_VERIFIED "tls:auth-verified"
+#define NNG_OPT_TLS_CONFIG "tls:config"
+
// XXX: TBD: Ciphersuite selection and reporting. Session reuse?
#endif // NNG_TRANSPORT_TLS_TLS_H
diff --git a/src/transport/ws/websocket.c b/src/transport/ws/websocket.c
index 4f948fb7..1162338e 100644
--- a/src/transport/ws/websocket.c
+++ b/src/transport/ws/websocket.c
@@ -15,6 +15,7 @@
#include "core/nng_impl.h"
#include "supplemental/http/http.h"
+#include "supplemental/tls/tls.h"
#include "supplemental/websocket/websocket.h"
#include "websocket.h"
@@ -42,6 +43,7 @@ struct ws_ep {
nni_ws_listener *listener;
nni_ws_dialer * dialer;
nni_list headers; // to send, res or req
+ nng_tls_config * tls;
};
struct ws_pipe {
@@ -368,9 +370,6 @@ ws_ep_setopt_headers(ws_ep *ep, const void *v, size_t sz)
ws_hdr * h;
int rv;
- if (nni_strnlen(v, sz) >= sz) {
- return (NNG_EINVAL);
- }
if (ep == NULL) {
return (0);
}
@@ -449,7 +448,11 @@ ws_ep_setopt_reqhdrs(void *arg, const void *v, size_t sz)
{
ws_ep *ep = arg;
- if (ep->mode == NNI_EP_MODE_LISTEN) {
+ if (nni_strnlen(v, sz) >= sz) {
+ return (NNG_EINVAL);
+ }
+
+ if ((ep != NULL) && (ep->mode == NNI_EP_MODE_LISTEN)) {
return (NNG_EREADONLY);
}
return (ws_ep_setopt_headers(ep, v, sz));
@@ -460,7 +463,11 @@ ws_ep_setopt_reshdrs(void *arg, const void *v, size_t sz)
{
ws_ep *ep = arg;
- if (ep->mode == NNI_EP_MODE_DIAL) {
+ if (nni_strnlen(v, sz) >= sz) {
+ return (NNG_EINVAL);
+ }
+
+ if ((ep != NULL) && (ep->mode == NNI_EP_MODE_DIAL)) {
return (NNG_EREADONLY);
}
return (ws_ep_setopt_headers(ep, v, sz));
@@ -594,6 +601,11 @@ ws_ep_fini(void *arg)
nni_strfree(ep->addr);
nni_strfree(ep->protoname);
nni_mtx_fini(&ep->mtx);
+#ifdef NNG_TRANSPORT_WSS
+ if (ep->tls) {
+ nng_tls_config_fini(ep->tls);
+ }
+#endif
NNI_FREE_STRUCT(ep);
}
@@ -689,10 +701,21 @@ ws_ep_init(void **epp, const char *url, nni_sock *sock, int mode)
if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) {
return (NNG_ENOMEM);
}
-
nni_mtx_init(&ep->mtx);
NNI_LIST_INIT(&ep->headers, ws_hdr, node);
+#ifdef NNG_TRANSPORT_WSS
+ if (strncmp(url, "wss://", 4) == 0) {
+ rv = nng_tls_config_init(&ep->tls,
+ mode == NNI_EP_MODE_DIAL ? NNG_TLS_MODE_CLIENT
+ : NNG_TLS_MODE_SERVER);
+ if (rv != 0) {
+ NNI_FREE_STRUCT(ep);
+ return (rv);
+ }
+ }
+#endif
+
// List of pipes (server only).
nni_aio_list_init(&ep->aios);
@@ -758,3 +781,100 @@ nng_ws_register(void)
{
return (nni_tran_register(&ws_tran));
}
+
+#ifdef NNG_TRANSPORT_WSS
+
+static int
+wss_ep_getopt_tlsconfig(void *arg, void *v, size_t *szp)
+{
+ ws_ep *ep = arg;
+ return (nni_getopt_ptr(ep->tls, v, szp));
+}
+
+static int
+wss_ep_setopt_tlsconfig(void *arg, const void *v, size_t sz)
+{
+ ws_ep * ep = arg;
+ nng_tls_config *cfg;
+ int rv;
+
+ if (sz != sizeof(cfg)) {
+ return (NNG_EINVAL);
+ }
+ memcpy(&cfg, v, sz);
+ if (cfg == NULL) {
+ // NULL is clearly invalid.
+ return (NNG_EINVAL);
+ }
+ if (ep == NULL) {
+ return (0);
+ }
+ nni_mtx_lock(&ep->mtx);
+ if (ep->mode == NNI_EP_MODE_LISTEN) {
+ rv = nni_ws_listener_set_tls(ep->listener, cfg);
+ } else {
+ rv = nni_ws_dialer_set_tls(ep->dialer, cfg);
+ }
+ if (rv == 0) {
+ if (ep->tls != NULL) {
+ nng_tls_config_fini(ep->tls);
+ }
+ nni_tls_config_hold(cfg);
+ ep->tls = cfg;
+ }
+ nni_mtx_unlock(&ep->mtx);
+ return (rv);
+}
+
+static nni_tran_ep_option wss_ep_options[] = {
+ {
+ .eo_name = NNG_OPT_RECVMAXSZ,
+ .eo_getopt = ws_ep_getopt_recvmaxsz,
+ .eo_setopt = ws_ep_setopt_recvmaxsz,
+ },
+ {
+ .eo_name = NNG_OPT_WSS_REQUEST_HEADERS,
+ .eo_getopt = NULL,
+ .eo_setopt = ws_ep_setopt_reqhdrs,
+ },
+ {
+ .eo_name = NNG_OPT_WSS_RESPONSE_HEADERS,
+ .eo_getopt = NULL,
+ .eo_setopt = ws_ep_setopt_reshdrs,
+ },
+ {
+ .eo_name = NNG_OPT_WSS_TLS_CONFIG,
+ .eo_getopt = wss_ep_getopt_tlsconfig,
+ .eo_setopt = wss_ep_setopt_tlsconfig,
+ },
+
+ // terminate list
+ { NULL, NULL, NULL },
+};
+
+static nni_tran_ep wss_ep_ops = {
+ .ep_init = ws_ep_init,
+ .ep_fini = ws_ep_fini,
+ .ep_connect = ws_ep_connect,
+ .ep_bind = ws_ep_bind,
+ .ep_accept = ws_ep_accept,
+ .ep_close = ws_ep_close,
+ .ep_options = wss_ep_options,
+};
+
+static nni_tran wss_tran = {
+ .tran_version = NNI_TRANSPORT_VERSION,
+ .tran_scheme = "wss",
+ .tran_ep = &wss_ep_ops,
+ .tran_pipe = &ws_pipe_ops,
+ .tran_init = ws_tran_init,
+ .tran_fini = ws_tran_fini,
+};
+
+int
+nng_wss_register(void)
+{
+ return (nni_tran_register(&wss_tran));
+}
+
+#endif // NNG_TRANSPORT_WSS
diff --git a/src/transport/ws/websocket.h b/src/transport/ws/websocket.h
index 2e86aaf0..a0d8a6cc 100644
--- a/src/transport/ws/websocket.h
+++ b/src/transport/ws/websocket.h
@@ -15,12 +15,30 @@
NNG_DECL int nng_ws_register(void);
-// NNG_OPT_TLS_REQUEST_HEADERS is a string containing the
+// NNG_OPT_WS_REQUEST_HEADERS is a string containing the
// request headers, formatted as CRLF terminated lines.
#define NNG_OPT_WS_REQUEST_HEADERS "ws:request-headers"
-// NNG_OPT_TLS_RESPONSE_HEADERS is a string containing the
+// NNG_OPT_WS_RESPONSE_HEADERS is a string containing the
// response headers, formatted as CRLF terminated lines.
#define NNG_OPT_WS_RESPONSE_HEADERS "ws:response-headers"
+// NNG_OPT_WSS_TLS_CONFIG is a pointer to a an nng_tls_config
+// object. This property is only available for wss:// style
+// endpoints. Note that when configuring the object, a hold
+// is placed on the TLS configuration. When retrieving the
+// object, no hold is placed, and so the caller must take care
+// not to use the configuration object after the endpoint it
+// is associated with is removed. Furthermore, as this is a
+// pointer, applications must take care to pass only valid
+// data -- incorrect pointer values will lead to undefined
+// behavior.
+#define NNG_OPT_WSS_TLS_CONFIG "wss:tls-config"
+
+// These aliases are for WSS naming consistency.
+#define NNG_OPT_WSS_REQUEST_HEADERS NNG_OPT_WS_REQUEST_HEADERS
+#define NNG_OPT_WSS_RESPONSE_HEADERS NNG_OPT_WS_RESPONSE_HEADERS
+
+NNG_DECL int nng_wss_register(void);
+
#endif // NNG_TRANSPORT_WS_WEBSOCKET_H
diff --git a/src/transport/zerotier/CMakeLists.txt b/src/transport/zerotier/CMakeLists.txt
index c1bb0c35..a4271eb7 100644
--- a/src/transport/zerotier/CMakeLists.txt
+++ b/src/transport/zerotier/CMakeLists.txt
@@ -11,6 +11,7 @@
# ZeroTier protocol
set (NNG_TRANSPORT_ZEROTIER_SOURCE "" CACHE PATH "Location of ZeroTier source tree.")
+mark_as_advanced(NNG_TRANSPORT_ZEROTIER_SOURCE)
if (NNG_TRANSPORT_ZEROTIER)
diff --git a/src/transport/zerotier/zerotier.c b/src/transport/zerotier/zerotier.c
index 3cb2871a..f6594eb3 100644
--- a/src/transport/zerotier/zerotier.c
+++ b/src/transport/zerotier/zerotier.c
@@ -8,7 +8,6 @@
// found online at https://opensource.org/licenses/MIT.
//
-#ifdef NNG_HAVE_ZEROTIER
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
@@ -2804,5 +2803,3 @@ nng_zt_register(void)
{
return (nni_tran_register(&zt_tran));
}
-
-#endif
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 7f37c589..5f1a834f 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -46,19 +46,21 @@ if (NNG_TESTS)
list (APPEND all_tests convey_test)
set (TEST_PORT 12100)
- macro (add_nng_test NAME TIMEOUT)
- list (APPEND all_tests ${NAME})
- add_executable (${NAME} ${NAME}.c convey.c)
- target_link_libraries (${NAME} ${PROJECT_NAME}_static)
- target_link_libraries (${NAME} ${NNG_REQUIRED_LIBRARIES})
- target_compile_definitions(${NAME} PUBLIC -DNNG_STATIC_LIB)
- if (CMAKE_THREAD_LIBS_INIT)
- target_link_libraries (${NAME} "${CMAKE_THREAD_LIBS_INIT}")
- endif()
+ macro (add_nng_test NAME TIMEOUT COND)
+ if (${COND})
+ list (APPEND all_tests ${NAME})
+ add_executable (${NAME} ${NAME}.c convey.c)
+ target_link_libraries (${NAME} ${PROJECT_NAME}_static)
+ target_link_libraries (${NAME} ${NNG_REQUIRED_LIBRARIES})
+ target_compile_definitions(${NAME} PUBLIC -DNNG_STATIC_LIB)
+ if (CMAKE_THREAD_LIBS_INIT)
+ target_link_libraries (${NAME} "${CMAKE_THREAD_LIBS_INIT}")
+ endif()
- add_test (NAME ${NAME} COMMAND ${NAME} -v -p TEST_PORT=${TEST_PORT})
- set_tests_properties (${NAME} PROPERTIES TIMEOUT ${TIMEOUT})
- math (EXPR TEST_PORT "${TEST_PORT}+20")
+ add_test (NAME ${NAME} COMMAND ${NAME} -v -p TEST_PORT=${TEST_PORT})
+ set_tests_properties (${NAME} PROPERTIES TIMEOUT ${TIMEOUT})
+ math (EXPR TEST_PORT "${TEST_PORT}+20")
+ endif()
endmacro (add_nng_test)
# Compatibility tests are only added if all of the legacy protocols
@@ -111,57 +113,61 @@ if (NNG_TESTS)
endif()
endmacro (add_nng_cpp_test)
+ macro (add_nng_proto_test NAME TIMEOUT P1 P2)
+ if (${P1} AND ${P2})
+ add_nng_test(${NAME} ${TIMEOUT} ON)
+ else()
+ message (STATUS "Protocol test ${NAME} disabled (unconfigured)")
+ endif()
+ endmacro()
else ()
- macro (add_nng_test NAME TIMEOUT)
+ macro (add_nng_test NAME TIMEOUT COND)
endmacro (add_nng_test)
macro (add_nng_compat_test NAME TIMEOUT)
endmacro (add_nng_compat_test)
macro (add_nng_cpp_test NAME TIMEOUT)
endmacro (add_nng_cpp_test)
+ macro (add_nng_proto_test NAME TIMEOUT P1 P2)
+ endmacro()
endif ()
-add_nng_test(aio 5)
-add_nng_test(bus 5)
-add_nng_test(files 5)
-add_nng_test(idhash 5)
-add_nng_test(inproc 5)
-add_nng_test(ipc 5)
-add_nng_test(list 5)
-add_nng_test(platform 5)
-add_nng_test(reqrep 5)
-add_nng_test(pipeline 5)
-add_nng_test(pollfd 5)
-add_nng_test(pubsub 5)
-add_nng_test(reconnect 5)
-add_nng_test(resolv 10)
-add_nng_test(sock 5)
-add_nng_test(survey 5)
-add_nng_test(synch 5)
-add_nng_test(transport 5)
-add_nng_test(tls 10)
-add_nng_test(tcp 5)
-add_nng_test(tcp6 5)
-add_nng_test(scalability 20)
-add_nng_test(message 5)
-add_nng_test(device 5)
-add_nng_test(errors 2)
-add_nng_test(pair1 5)
-add_nng_test(udp 5)
-add_nng_test(zt 60)
-add_nng_test(multistress 60)
-add_nng_test(ws 30)
-
-if (NNG_SUPP_BASE64)
- add_nng_test(base64 5)
-endif()
-if (NNG_SUPP_HTTP)
- add_nng_test(httpclient 30)
- add_nng_test(httpserver 30)
-endif()
-if (NNG_SUPP_SHA1)
- add_nng_test(sha1 5)
-endif()
+add_nng_test(aio 5 ON)
+add_nng_test(base64 5 NNG_SUPP_BASE64)
+add_nng_test(device 5 ON)
+add_nng_test(errors 2 ON)
+add_nng_test(files 5 ON)
+add_nng_test(httpclient 30 NNG_SUPP_HTTP)
+add_nng_test(httpserver 30 NNG_SUPP_HTTP)
+add_nng_test(idhash 5 ON)
+add_nng_test(inproc 5 NNG_TRANSPORT_INPROC)
+add_nng_test(ipc 5 NNG_TRANSPORT_IPC)
+add_nng_test(list 5 ON)
+add_nng_test(message 5 ON)
+add_nng_test(multistress 60 ON)
+add_nng_test(platform 5 ON)
+add_nng_test(pollfd 5 ON)
+add_nng_test(reconnect 5 ON)
+add_nng_test(resolv 10 ON)
+add_nng_test(scalability 20 ON)
+add_nng_test(sha1 5 NNG_SUPP_SHA1)
+add_nng_test(sock 5 ON)
+add_nng_test(synch 5 ON)
+add_nng_test(tls 10 NNG_TRANSPORT_TLS)
+add_nng_test(tcp 5 NNG_TRANSPORT_TCP)
+add_nng_test(tcp6 5 NNG_TRANSPORT_TCP)
+add_nng_test(transport 5 ON)
+add_nng_test(udp 5 ON)
+add_nng_test(ws 30 NNG_TRANSPORT_WS)
+add_nng_test(wss 30 NNG_TRANSPORT_WSS)
+add_nng_test(zt 60 NNG_TRANSPORT_ZEROTIER)
+
+add_nng_proto_test(bus 5 NNG_PROTO_BUS0 NNG_PROTO_BUS0)
+add_nng_test(pipeline 5 NNG_PROTO_PULL0 NNG_PROTO_PIPELINE0)
+add_nng_proto_test(pair1 5 NNG_PROTO_PAIR1 NNG_PROTO_PAIR1)
+add_nng_proto_test(pubsub 5 NNG_PROTO_PUB0 NNG_PROTO_SUB0)
+add_nng_proto_test(reqrep 5 NNG_PROTO_REQ0 NNG_PROTO_REP0)
+add_nng_test(survey 5 NNG_PROTO_SURVEYOR0 NNG_PROTO_RESPONDENT0)
# compatbility tests
# We only support these if ALL the legacy protocols are supported. This
diff --git a/tests/multistress.c b/tests/multistress.c
index 7088ac14..6a41a551 100644
--- a/tests/multistress.c
+++ b/tests/multistress.c
@@ -44,7 +44,7 @@ const char *inproc_template = "inproc://nng_multistress_%d";
const char *ipc_template = "ipc:///tmp/nng_multistress_%d";
const char *templates[] = {
-#ifdef NNG_HAVE_TCP
+#ifdef NNG_TRANSPORT_TCP
"tcp://127.0.0.1:%d",
#endif
// It would be nice to test TCPv6, but CI doesn't support it.
@@ -52,10 +52,10 @@ const char *templates[] = {
#ifdef NNG_TEST_TCPV6
"tcp://[::1]:%d",
#endif
-#ifdef NNG_HAVE_INPROC
+#ifdef NNG_TRANSPORT_INPROC
"inproc://nng_multistress_%d",
#endif
-#ifdef NNG_HAVE_IPC
+#ifdef NNG_TRANSPORT_IPC
"ipc:///tmp/nng_multistress_%d",
#endif
};
diff --git a/tests/tls.c b/tests/tls.c
index fa44d9c9..70b22fea 100644
--- a/tests/tls.c
+++ b/tests/tls.c
@@ -105,20 +105,54 @@ check_props_v4(nng_msg *msg, nng_listener l, nng_dialer d)
}
static int
-init_tls(trantest *tt)
+init_dialer_tls(trantest *tt, nng_dialer d)
{
- const char *own[3];
-
- So(nng_setopt(tt->reqsock, NNG_OPT_TLS_CA_CERT, server_cert,
- sizeof(server_cert)) == 0);
- own[0] = server_cert;
- own[1] = server_key;
- own[2] = NULL;
- So(nng_setopt(tt->repsock, NNG_OPT_TLS_CERT, server_cert,
- sizeof(server_cert)) == 0);
- So(nng_setopt(tt->repsock, NNG_OPT_TLS_PRIVATE_KEY, server_key,
- sizeof(server_key)) == 0);
+ nng_tls_config *cfg;
+ int rv;
+
+ if ((rv = nng_tls_config_init(&cfg, NNG_TLS_MODE_CLIENT)) != 0) {
+ return (rv);
+ }
+ if ((rv = nng_tls_config_ca_cert(
+ cfg, (void *) server_cert, sizeof(server_cert))) != 0) {
+ goto out;
+ }
+ if ((rv = nng_tls_config_server_name(cfg, "127.0.0.1")) != 0) {
+ goto out;
+ }
+ nng_tls_config_auth_mode(cfg, NNG_TLS_AUTH_MODE_NONE);
+ rv = nng_dialer_setopt_ptr(d, NNG_OPT_TLS_CONFIG, cfg);
+
+out:
+ nng_tls_config_fini(cfg);
+ return (rv);
+}
+static int
+init_listener_tls(trantest *tt, nng_listener l)
+{
+ nng_tls_config *cfg;
+ int rv;
+
+ if ((rv = nng_tls_config_init(&cfg, NNG_TLS_MODE_SERVER)) != 0) {
+ return (rv);
+ }
+ if ((rv = nng_tls_config_cert(
+ cfg, (void *) server_cert, sizeof(server_cert))) != 0) {
+ nng_tls_config_fini(cfg);
+ return (rv);
+ }
+ if ((rv = nng_tls_config_key(
+ cfg, (void *) server_key, sizeof(server_key))) != 0) {
+ nng_tls_config_fini(cfg);
+ return (rv);
+ }
+
+ if ((rv = nng_listener_setopt_ptr(l, NNG_OPT_TLS_CONFIG, cfg)) != 0) {
+ nng_tls_config_fini(cfg);
+ return (rv);
+ }
+ nng_tls_config_fini(cfg);
return (0);
}
@@ -126,8 +160,10 @@ TestMain("TLS Transport", {
static trantest tt;
- tt.init = init_tls;
- tt.tmpl = "tls+tcp://127.0.0.1:%u";
+ tt.dialer_init = init_dialer_tls;
+ tt.listener_init = init_listener_tls;
+ tt.tmpl = "tls+tcp://127.0.0.1:%u";
+ tt.proptest = check_props_v4;
atexit(nng_fini);
trantest_test(&tt);
diff --git a/tests/trantest.h b/tests/trantest.h
index b1b0ff80..324668dd 100644
--- a/tests/trantest.h
+++ b/tests/trantest.h
@@ -26,41 +26,42 @@ typedef int (*trantest_proptest_t)(nng_msg *, nng_listener, nng_dialer);
typedef struct trantest trantest;
struct trantest {
- const char * tmpl;
- char addr[NNG_MAXADDRLEN + 1];
- nng_socket reqsock;
- nng_socket repsock;
- nni_tran * tran;
- nng_dialer dialer;
- nng_listener listener;
+ const char *tmpl;
+ char addr[NNG_MAXADDRLEN + 1];
+ nng_socket reqsock;
+ nng_socket repsock;
+ nni_tran * tran;
int (*init)(struct trantest *);
void (*fini)(struct trantest *);
- int (*dialer_init)(struct trantest *);
- int (*listener_init)(struct trantest *);
+ int (*dialer_init)(struct trantest *, nng_dialer);
+ int (*listener_init)(struct trantest *, nng_listener);
int (*proptest)(nng_msg *, nng_listener, nng_dialer);
void *private; // transport specific private data
};
unsigned trantest_port = 0;
-#ifndef NNG_HAVE_ZEROTIER
+#ifndef NNG_TRANSPORT_ZEROTIER
#define nng_zt_register notransport
#endif
-#ifndef NNG_HAVE_INPROC
+#ifndef NNG_TRANSPORT_INPROC
#define nng_inproc_register notransport
#endif
-#ifndef NNG_HAVE_IPC
+#ifndef NNG_TRANSPORT_IPC
#define nng_ipc_register notransport
#endif
-#ifndef NNG_HAVE_TCP
+#ifndef NNG_TRANSPORT_TCP
#define nng_tcp_register notransport
#endif
-#ifndef NNG_HAVE_TLS
+#ifndef NNG_TRANSPORT_TLS
#define nng_tls_register notransport
#endif
-#ifndef NNG_HAVE_WEBSOCKET
+#ifndef NNG_TRANSPORT_WS
#define nng_ws_register notransport
#endif
+#ifndef NNG_TRANSPORT_WSS
+#define nng_wss_register notransport
+#endif
int
notransport(void)
@@ -76,24 +77,27 @@ notransport(void)
void
trantest_checktran(const char *url)
{
-#ifndef NNG_HAVE_ZEROTIER
- CHKTRAN(url, "zt:");
-#endif
-#ifndef NNG_HAVE_INPROC
+#ifndef NNG_TRANSPORT_INPROC
CHKTRAN(url, "inproc:");
#endif
-#ifndef NNG_HAVE_IPC
+#ifndef NNG_TRANSPORT_IPC
CHKTRAN(url, "ipc:");
#endif
-#ifndef NNG_HAVE_TCP
+#ifndef NNG_TRANSPORT_TCP
CHKTRAN(url, "tcp:");
#endif
-#ifndef NNG_HAVE_TLS
+#ifndef NNG_TRANSPORT_TLS
CHKTRAN(url, "tls+tcp:");
#endif
-#ifndef NNG_HAVE_WEBSOCKET
+#ifndef NNG_TRANSPORT_WS
CHKTRAN(url, "ws:");
#endif
+#ifndef NNG_TRANSPORT_WSS
+ CHKTRAN(url, "wss:");
+#endif
+#ifndef NNG_TRANSPORT_ZEROTIER
+ CHKTRAN(url, "zt:");
+#endif
(void) url;
}
@@ -149,13 +153,53 @@ trantest_fini(trantest *tt)
}
int
-trantest_dial(trantest *tt)
+trantest_dial(trantest *tt, nng_dialer *dp)
{
- So(nng_dialer_create(&tt->dialer, tt->reqsock, tt->addr) == 0);
+ nng_dialer d;
+ int rv;
+ *dp = 0;
+
+ rv = nng_dialer_create(&d, tt->reqsock, tt->addr);
+ if (rv != 0) {
+ return (rv);
+ }
if (tt->dialer_init != NULL) {
- So(tt->dialer_init(tt) == 0);
+ if ((rv = tt->dialer_init(tt, d)) != 0) {
+ nng_dialer_close(d);
+ return (rv);
+ }
+ }
+ if ((rv = nng_dialer_start(d, 0)) != 0) {
+ nng_dialer_close(d);
+ return (rv);
}
- return (nng_dialer_start(tt->dialer, 0));
+ *dp = d;
+ return (0);
+}
+
+int
+trantest_listen(trantest *tt, nng_listener *lp)
+{
+ int rv;
+ nng_listener l;
+ *lp = 0;
+
+ rv = nng_listener_create(&l, tt->repsock, tt->addr);
+ if (rv != 0) {
+ return (rv);
+ }
+ if (tt->listener_init != NULL) {
+ if ((rv = tt->listener_init(tt, l)) != 0) {
+ nng_listener_close(l);
+ return (rv);
+ }
+ }
+ if ((rv = nng_listener_start(l, 0)) != 0) {
+ nng_listener_close(l);
+ return (rv);
+ }
+ *lp = l;
+ return (rv);
}
void
@@ -174,11 +218,11 @@ trantest_conn_refused(trantest *tt)
Convey("Connection refused works", {
nng_dialer d = 0;
- So(nng_dial(tt->reqsock, tt->addr, &d, 0) == NNG_ECONNREFUSED);
+ So(trantest_dial(tt, &d) == NNG_ECONNREFUSED);
So(d == 0);
- So(nng_dial(tt->repsock, tt->addr, &d, 0) == NNG_ECONNREFUSED);
+ So(trantest_dial(tt, &d) == NNG_ECONNREFUSED);
So(d == 0);
- })
+ });
}
void
@@ -187,13 +231,13 @@ trantest_duplicate_listen(trantest *tt)
Convey("Duplicate listen rejected", {
nng_listener l;
int rv;
- rv = nng_listen(tt->repsock, tt->addr, &l, 0);
+ rv = trantest_listen(tt, &l);
So(rv == 0);
So(l != 0);
l = 0;
- So(nng_listen(tt->repsock, tt->addr, &l, 0) == NNG_EADDRINUSE);
+ So(trantest_listen(tt, &l) == NNG_EADDRINUSE);
So(l == 0);
- })
+ });
}
void
@@ -202,11 +246,11 @@ trantest_listen_accept(trantest *tt)
Convey("Listen and accept", {
nng_listener l;
nng_dialer d;
- So(nng_listen(tt->repsock, tt->addr, &l, 0) == 0);
+ So(trantest_listen(tt, &l) == 0);
So(l != 0);
d = 0;
- So(nng_dial(tt->reqsock, tt->addr, &d, 0) == 0);
+ So(trantest_dial(tt, &d) == 0);
So(d != 0);
})
}
@@ -216,6 +260,7 @@ trantest_send_recv(trantest *tt)
{
Convey("Send and recv", {
nng_listener l;
+ nng_dialer d;
nng_msg * send;
nng_msg * recv;
size_t len;
@@ -223,9 +268,10 @@ trantest_send_recv(trantest *tt)
char url[NNG_MAXADDRLEN];
size_t sz;
- So(nng_listen(tt->repsock, tt->addr, &l, 0) == 0);
+ So(trantest_listen(tt, &l) == 0);
So(l != 0);
- So(trantest_dial(tt) == 0);
+ So(trantest_dial(tt, &d) == 0);
+ So(d != 0);
nng_msleep(200); // listener may be behind slightly
@@ -269,9 +315,9 @@ trantest_check_properties(trantest *tt, trantest_proptest_t f)
nng_msg * recv;
int rv;
- So(nng_listen(tt->repsock, tt->addr, &l, 0) == 0);
+ So(trantest_listen(tt, &l) == 0);
So(l != 0);
- So(nng_dial(tt->reqsock, tt->addr, &d, 0) == 0);
+ So(trantest_dial(tt, &d) == 0);
So(d != 0);
nng_msleep(200); // listener may be behind slightly
@@ -311,9 +357,9 @@ trantest_send_recv_large(trantest *tt)
data[i] = nni_random() & 0xff;
}
- So(nng_listen(tt->repsock, tt->addr, &l, 0) == 0);
+ So(trantest_listen(tt, &l) == 0);
So(l != 0);
- So(nng_dial(tt->reqsock, tt->addr, &d, 0) == 0);
+ So(trantest_dial(tt, &d) == 0);
So(d != 0);
nng_msleep(200); // listener may be behind slightly
diff --git a/tests/wss.c b/tests/wss.c
new file mode 100644
index 00000000..2f701117
--- /dev/null
+++ b/tests/wss.c
@@ -0,0 +1,206 @@
+//
+// Copyright 2017 Garrett D'Amore <garrett@damore.org>
+// Copyright 2017 Capitar IT Group BV <info@capitar.com>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+#include "convey.h"
+#include "nng.h"
+#include "protocol/pair1/pair.h"
+#include "transport/ws/websocket.h"
+#include "trantest.h"
+
+#include "stubs.h"
+// TCP tests.
+
+#ifndef _WIN32
+#include <arpa/inet.h>
+#endif
+
+// These keys are for demonstration purposes ONLY. DO NOT USE.
+// The certificate is valid for 100 years, because I don't want to
+// have to regenerate it ever again. The CN is 127.0.0.1, and self-signed.
+//
+// Generated using openssl:
+//
+// % openssl ecparam -name secp521r1 -noout -genkey -out key.key
+// % openssl req -new -key key.key -out cert.csr
+// % openssl x509 -req -in cert.csr -days 36500 -out cert.crt -signkey key.key
+//
+// Relevant metadata:
+//
+// Certificate:
+// Data:
+// Version: 1 (0x0)
+// Serial Number: 9808857926806240008 (0x882010509b8f7b08)
+// Signature Algorithm: ecdsa-with-SHA1
+// Issuer: C=US, ST=CA, L=San Diego, O=nanomsg, CN=127.0.0.1
+// Validity
+// Not Before: Nov 17 20:08:06 2017 GMT
+// Not After : Oct 24 20:08:06 2117 GMT
+// Subject: C=US, ST=CA, L=San Diego, O=nanomsg, CN=127.0.0.1
+//
+static const char server_cert[] =
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIICIjCCAYMCCQDaC9ARg31kIjAKBggqhkjOPQQDAjBUMQswCQYDVQQGEwJVUzEL\n"
+ "MAkGA1UECAwCQ0ExEjAQBgNVBAcMCVNhbiBEaWVnbzEQMA4GA1UECgwHbmFub21z\n"
+ "ZzESMBAGA1UEAwwJMTI3LjAuMC4xMCAXDTE3MTExNzIwMjczMloYDzIxMTcxMDI0\n"
+ "MjAyNzMyWjBUMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExEjAQBgNVBAcMCVNh\n"
+ "biBEaWVnbzEQMA4GA1UECgwHbmFub21zZzESMBAGA1UEAwwJMTI3LjAuMC4xMIGb\n"
+ "MBAGByqGSM49AgEGBSuBBAAjA4GGAAQAN7vDK6GEiSguMsOuhfOvGyiVc37Sog0b\n"
+ "UkpaiS6+SagTmXFSN1Rgh9isxKFYJvcCtAko3v0I8rAVQucdhf5B3hEBMQlbBIuM\n"
+ "rMKT6ZQJ+eiwyb4O3Scgd7DoL3tc/kOqijwB/5hJ4sZdquDKP5DDFe5fAf4MNtzY\n"
+ "4C+iApWlKq/LoXkwCgYIKoZIzj0EAwIDgYwAMIGIAkIBOuJAWmNSdd6Ovmr6Ebg3\n"
+ "UF9ZrsNwARd9BfYbBk5OQhUOjCLB6d8aLi49WOm1WoRvOS5PaVvmvSfNhaw8b5nV\n"
+ "hnYCQgC+EmJ6C3bEcZrndhfbqvCaOGkc7/SrKhC6fS7mJW4wL90QUV9WjQ2Ll6X5\n"
+ "PxkSj7s0SvD6T8j7rju5LDgkdZc35A==\n"
+ "-----END CERTIFICATE-----\n";
+
+static const char server_key[] =
+ "-----BEGIN EC PRIVATE KEY-----\n"
+ "MIHcAgEBBEIB20OHMntU2UJW2yuQn2f+bLsuhTT5KRGorcocnqxatWLvxuF1cfUA\n"
+ "TjQxRRS6BIUvFt1fMIklp9qedJF00JHy4qWgBwYFK4EEACOhgYkDgYYABAA3u8Mr\n"
+ "oYSJKC4yw66F868bKJVzftKiDRtSSlqJLr5JqBOZcVI3VGCH2KzEoVgm9wK0CSje\n"
+ "/QjysBVC5x2F/kHeEQExCVsEi4yswpPplAn56LDJvg7dJyB3sOgve1z+Q6qKPAH/\n"
+ "mEnixl2q4Mo/kMMV7l8B/gw23NjgL6IClaUqr8uheQ==\n"
+ "-----END EC PRIVATE KEY-----\n";
+
+static int
+check_props_v4(nng_msg *msg, nng_listener l, nng_dialer d)
+{
+ nng_pipe p;
+ size_t z;
+ p = nng_msg_get_pipe(msg);
+ So(p > 0);
+
+ Convey("Local address property works", {
+ nng_sockaddr la;
+ z = sizeof(nng_sockaddr);
+ So(nng_pipe_getopt(p, NNG_OPT_LOCADDR, &la, &z) == 0);
+ So(z == sizeof(la));
+ So(la.s_un.s_family == NNG_AF_INET);
+ So(la.s_un.s_in.sa_port == htons(trantest_port - 1));
+ So(la.s_un.s_in.sa_port != 0);
+ So(la.s_un.s_in.sa_addr == htonl(0x7f000001));
+ });
+
+ Convey("Remote address property works", {
+ nng_sockaddr ra;
+ z = sizeof(nng_sockaddr);
+ So(nng_pipe_getopt(p, NNG_OPT_REMADDR, &ra, &z) == 0);
+ So(z == sizeof(ra));
+ So(ra.s_un.s_family == NNG_AF_INET);
+ So(ra.s_un.s_in.sa_port != 0);
+ So(ra.s_un.s_in.sa_addr == htonl(0x7f000001));
+ });
+
+ Convey("Request header property works", {
+ char * buf;
+ size_t len;
+ z = 0;
+ buf = NULL;
+ So(nng_pipe_getopt(p, NNG_OPT_WS_REQUEST_HEADERS, buf, &z) ==
+ 0);
+ So(z > 0);
+ len = z;
+ So((buf = nni_alloc(len)) != NULL);
+ So(nng_pipe_getopt(p, NNG_OPT_WS_REQUEST_HEADERS, buf, &z) ==
+ 0);
+ So(strstr(buf, "Sec-WebSocket-Key") != NULL);
+ So(z == len);
+ nni_free(buf, len);
+ });
+
+ Convey("Response header property works", {
+ char * buf;
+ size_t len;
+ z = 0;
+ buf = NULL;
+ So(nng_pipe_getopt(p, NNG_OPT_WS_RESPONSE_HEADERS, buf, &z) ==
+ 0);
+ So(z > 0);
+ len = z;
+ So((buf = nni_alloc(len)) != NULL);
+ So(nng_pipe_getopt(p, NNG_OPT_WS_RESPONSE_HEADERS, buf, &z) ==
+ 0);
+ So(strstr(buf, "Sec-WebSocket-Accept") != NULL);
+ So(z == len);
+ nni_free(buf, len);
+ });
+
+ return (0);
+}
+
+static int
+init_dialer_wss(trantest *tt, nng_dialer d)
+{
+ nng_tls_config *cfg;
+ int rv;
+
+ if ((rv = nng_tls_config_init(&cfg, NNG_TLS_MODE_CLIENT)) != 0) {
+ return (rv);
+ }
+ if ((rv = nng_tls_config_ca_cert(
+ cfg, (void *) server_cert, sizeof(server_cert))) != 0) {
+ goto out;
+ }
+ if ((rv = nng_tls_config_server_name(cfg, "127.0.0.1")) != 0) {
+ goto out;
+ }
+ nng_tls_config_auth_mode(cfg, NNG_TLS_AUTH_MODE_NONE);
+ rv = nng_dialer_setopt_ptr(d, NNG_OPT_WSS_TLS_CONFIG, cfg);
+
+out:
+ nng_tls_config_fini(cfg);
+ return (rv);
+}
+
+static int
+init_listener_wss(trantest *tt, nng_listener l)
+{
+ nng_tls_config *cfg;
+ int rv;
+
+ if ((rv = nng_tls_config_init(&cfg, NNG_TLS_MODE_SERVER)) != 0) {
+ return (rv);
+ }
+ if ((rv = nng_tls_config_cert(
+ cfg, (void *) server_cert, sizeof(server_cert))) != 0) {
+ nng_tls_config_fini(cfg);
+ return (rv);
+ }
+ if ((rv = nng_tls_config_key(
+ cfg, (void *) server_key, sizeof(server_key))) != 0) {
+ nng_tls_config_fini(cfg);
+ return (rv);
+ }
+
+ if ((rv = nng_listener_setopt_ptr(l, NNG_OPT_WSS_TLS_CONFIG, cfg)) !=
+ 0) {
+ // We can wind up with EBUSY from the server
+ // already running.
+ if (rv != NNG_EBUSY) {
+ nng_tls_config_fini(cfg);
+ return (rv);
+ }
+ }
+ nng_tls_config_fini(cfg);
+ return (0);
+}
+
+TestMain("WebSocket Secure (TLS) Transport", {
+ static trantest tt;
+
+ tt.dialer_init = init_dialer_wss;
+ tt.listener_init = init_listener_wss;
+ tt.tmpl = "wss://127.0.0.1:%u/test";
+ tt.proptest = check_props_v4;
+
+ trantest_test(&tt);
+
+ nng_fini();
+})
diff --git a/tests/zt.c b/tests/zt.c
index 52f535c9..6c7b35e8 100644
--- a/tests/zt.c
+++ b/tests/zt.c
@@ -39,7 +39,7 @@ mkdir(const char *path, int mode)
#include <unistd.h>
#endif // WIN32
-#ifndef NNG_HAVE_ZEROTIER
+#ifndef NNG_TRANSPORT_ZEROTIER
#define nng_zt_network_status_ok 0
#endif