aboutsummaryrefslogtreecommitdiff
path: root/src/supplemental
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 /src/supplemental
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.
Diffstat (limited to 'src/supplemental')
-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
11 files changed, 392 insertions, 270 deletions
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