aboutsummaryrefslogtreecommitdiff
path: root/src/supplemental/tls/tls_common.c
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2019-01-21 22:40:10 -0800
committerGarrett D'Amore <garrett@damore.org>2019-02-16 19:22:27 -0800
commit5cf750697624d4fd63cfe26921209d7c30e1a2d2 (patch)
treebf11695e5f1ec5e400c87da0cc6ff23935a2eeff /src/supplemental/tls/tls_common.c
parentca655b9db689ee0e655248b1a9f166b8db6cc984 (diff)
downloadnng-5cf750697624d4fd63cfe26921209d7c30e1a2d2.tar.gz
nng-5cf750697624d4fd63cfe26921209d7c30e1a2d2.tar.bz2
nng-5cf750697624d4fd63cfe26921209d7c30e1a2d2.zip
fixes #872 create unified nng_stream API
This is a major change, and includes changes to use a polymorphic stream API for all transports. There have been related bugs fixed along the way. Additionally the man pages have changed. The old non-polymorphic APIs are removed now. This is a breaking change, but the old APIs were never part of any released public API.
Diffstat (limited to 'src/supplemental/tls/tls_common.c')
-rw-r--r--src/supplemental/tls/tls_common.c754
1 files changed, 438 insertions, 316 deletions
diff --git a/src/supplemental/tls/tls_common.c b/src/supplemental/tls/tls_common.c
index f93ca0ba..990d3add 100644
--- a/src/supplemental/tls/tls_common.c
+++ b/src/supplemental/tls/tls_common.c
@@ -1,5 +1,5 @@
//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
// Copyright 2019 Devolutions <info@devolutions.net>
//
@@ -15,9 +15,9 @@
#include <string.h>
#include "core/nng_impl.h"
+#include "core/tcp.h"
#include "supplemental/tls/tls_api.h"
-#include <nng/supplemental/tcp/tcp.h>
#include <nng/supplemental/tls/tls.h>
// This file contains common code for TLS, and is only compiled if we
@@ -25,126 +25,29 @@
// parts of TLS support that are invariant relative to different TLS
// libraries, such as dialer and listener support.
-struct nng_tls_s {
- nni_tls * c;
- nni_aio * aio; // system aio for connect/accept
- nni_aio * uaio; // user aio for connect/accept
- nng_tls_config *cfg;
-};
-
-// We use a union and share an "endpoint" for both dialers and listeners.
-// This allows us to reuse the bulk of the code for things like option
-// handlers for both dialers and listeners.
-typedef union tls_tcp_ep_u {
- nni_tcp_dialer * d;
- nni_tcp_listener *l;
-} tls_tcp_ep;
-
-typedef struct nng_tls_ep_s {
- tls_tcp_ep tcp;
- nng_tls_config *cfg;
- nni_mtx lk;
-} tls_ep;
-
-void
-nng_tls_close(nng_tls *tls)
-{
- nni_tls_close(tls->c);
-}
+typedef struct {
+ nng_stream_dialer ops;
+ nng_stream_dialer *d; // underlying TCP dialer
+ nng_tls_config * cfg;
+ nni_mtx lk; // protects the config
+} tls_dialer;
-void
-nng_tls_free(nng_tls *tls)
-{
- if (tls != NULL) {
- nni_tls_fini(tls->c);
- nni_aio_fini(tls->aio);
- nng_tls_config_free(tls->cfg);
- NNI_FREE_STRUCT(tls);
- }
-}
-
-void
-nng_tls_send(nng_tls *tls, nng_aio *aio)
-{
- nni_tls_send(tls->c, aio);
-}
-
-void
-nng_tls_recv(nng_tls *tls, nng_aio *aio)
-{
- nni_tls_recv(tls->c, aio);
-}
-
-int
-nni_tls_get(nng_tls *tls, const char *name, void *buf, size_t *szp, nni_type t)
-{
- return (nni_tls_getopt(tls->c, name, buf, szp, t));
-}
-
-int
-nni_tls_set(
- nng_tls *tls, const char *name, const void *buf, size_t sz, nni_type t)
-{
- return (nni_tls_setopt(tls->c, name, buf, sz, t));
-}
-
-int
-nng_tls_getopt(nng_tls *tls, const char *name, void *buf, size_t *szp)
-{
- return (nni_tls_getopt(tls->c, name, buf, szp, NNI_TYPE_OPAQUE));
-}
-
-int
-nng_tls_setopt(nng_tls *tls, const char *name, const void *buf, size_t sz)
-{
- return (nni_tls_setopt(tls->c, name, buf, sz, NNI_TYPE_OPAQUE));
-}
-
-int
-nng_tls_dialer_alloc(nng_tls_dialer **dp)
-{
- tls_ep *ep;
- int rv;
-
- if ((rv = nni_init()) != 0) {
- return (rv);
- }
- if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) {
- return (NNG_ENOMEM);
- }
- nni_mtx_init(&ep->lk);
-
- if ((rv = nni_tcp_dialer_init(&ep->tcp.d)) != 0) {
- nni_mtx_fini(&ep->lk);
- NNI_FREE_STRUCT(ep);
- return (rv);
- }
- if ((rv = nng_tls_config_alloc(&ep->cfg, NNG_TLS_MODE_CLIENT)) != 0) {
- nni_tcp_dialer_fini(ep->tcp.d);
- nni_mtx_fini(&ep->lk);
- NNI_FREE_STRUCT(ep);
- return (rv);
- }
- *dp = (void *) ep;
- return (rv);
-}
-
-void
-nng_tls_dialer_close(nng_tls_dialer *d)
+static void
+tls_dialer_close(void *arg)
{
- tls_ep *ep = (void *) d;
- nni_tcp_dialer_close(ep->tcp.d);
+ tls_dialer *d = arg;
+ nng_stream_dialer_close(d->d);
}
-void
-nng_tls_dialer_free(nng_tls_dialer *d)
+static void
+tls_dialer_free(void *arg)
{
- tls_ep *ep = (void *) d;
- if (ep != NULL) {
- nni_tcp_dialer_fini(ep->tcp.d);
- nng_tls_config_free(ep->cfg);
- nni_mtx_fini(&ep->lk);
- NNI_FREE_STRUCT(ep);
+ tls_dialer *d;
+ if ((d = arg) != NULL) {
+ nng_stream_dialer_free(d->d);
+ nng_tls_config_free(d->cfg);
+ nni_mtx_fini(&d->lk);
+ NNI_FREE_STRUCT(d);
}
}
@@ -154,28 +57,28 @@ nng_tls_dialer_free(nng_tls_dialer *d)
static void
tls_conn_cb(void *arg)
{
- nng_tls * tls = arg;
- nni_tcp_conn *tcp;
- int rv;
+ nng_stream * tls = arg;
+ nni_tls_common *com = arg;
+ nng_stream * tcp;
+ int rv;
- if ((rv = nni_aio_result(tls->aio)) != 0) {
- nni_aio_finish_error(tls->uaio, rv);
- nng_tls_free(tls);
+ if ((rv = nni_aio_result(com->aio)) != 0) {
+ nni_aio_finish_error(com->uaio, rv);
+ nng_stream_free(tls);
return;
}
- tcp = nni_aio_get_output(tls->aio, 0);
+ tcp = nni_aio_get_output(com->aio, 0);
- rv = nni_tls_init(&tls->c, tls->cfg, tcp);
- if (rv != 0) {
- nni_aio_finish_error(tls->uaio, rv);
- nni_tcp_conn_fini(tcp);
- nng_tls_free(tls);
+ if ((rv = nni_tls_start(tls, tcp)) != 0) {
+ nni_aio_finish_error(com->uaio, rv);
+ nng_stream_free(tcp);
+ nng_stream_free(tls);
return;
}
- nni_aio_set_output(tls->uaio, 0, tls);
- nni_aio_finish(tls->uaio, 0, 0);
+ nni_aio_set_output(com->uaio, 0, tls);
+ nni_aio_finish(com->uaio, 0, 0);
}
// Dialer cancel is called when the user has indicated that they no longer
@@ -183,49 +86,52 @@ tls_conn_cb(void *arg)
static void
tls_conn_cancel(nni_aio *aio, void *arg, int rv)
{
- nng_tls *tls = arg;
- NNI_ASSERT(tls->uaio == aio);
+ nni_tls_common *com = arg;
+ NNI_ASSERT(com->uaio == aio);
// Just pass this down. If the connection is already done, this
// will have no effect.
- nni_aio_abort(tls->aio, rv);
+ nni_aio_abort(com->aio, rv);
}
-void
-nng_tls_dialer_dial(nng_tls_dialer *d, const nng_sockaddr *sa, nng_aio *aio)
+static void
+tls_dialer_dial(void *arg, nng_aio *aio)
{
- int rv;
- nng_tls *tls;
- tls_ep * ep = (void *) d;
+ tls_dialer * d = arg;
+ int rv;
+ nng_stream * tls;
+ nni_tls_common *com;
if (nni_aio_begin(aio) != 0) {
return;
}
- if ((tls = NNI_ALLOC_STRUCT(tls)) == NULL) {
- nni_aio_finish_error(aio, NNG_ENOMEM);
+ if ((rv = nni_tls_alloc(&tls)) != 0) {
+ nni_aio_finish_error(aio, rv);
return;
}
- if ((rv = nni_aio_init(&tls->aio, tls_conn_cb, tls)) != 0) {
+
+ com = (void *) tls;
+ if ((rv = nni_aio_init(&com->aio, tls_conn_cb, tls)) != 0) {
nni_aio_finish_error(aio, rv);
- NNI_FREE_STRUCT(tls);
+ nng_stream_free(tls);
return;
}
- tls->uaio = aio;
+ com->uaio = aio;
// Save a copy of the TLS configuration. This way we don't have
// to ensure that the dialer outlives the connection, because the
// only shared data is the configuration which is reference counted.
- nni_mtx_lock(&ep->lk);
- tls->cfg = ep->cfg;
- nng_tls_config_hold(tls->cfg);
- nni_mtx_unlock(&ep->lk);
+ nni_mtx_lock(&d->lk);
+ com->cfg = d->cfg;
+ nng_tls_config_hold(com->cfg);
+ nni_mtx_unlock(&d->lk);
if ((rv = nni_aio_schedule(aio, tls_conn_cancel, tls)) != 0) {
nni_aio_finish_error(aio, rv);
- nng_tls_free(tls);
+ nng_stream_free(tls);
return;
}
- nni_tcp_dialer_dial(ep->tcp.d, sa, tls->aio);
+ nng_stream_dialer_dial(d->d, com->aio);
}
static int
@@ -241,11 +147,12 @@ tls_check_string(const void *v, size_t sz, nni_opt_type t)
}
static int
-tls_ep_set_config(void *arg, const void *buf, size_t sz, nni_type t)
+tls_dialer_set_config(void *arg, const void *buf, size_t sz, nni_type t)
{
int rv;
nng_tls_config *cfg;
- tls_ep * ep;
+ tls_dialer * d = arg;
+ nng_tls_config *old;
if ((rv = nni_copyin_ptr((void **) &cfg, buf, sz, t)) != 0) {
return (rv);
@@ -253,308 +160,523 @@ tls_ep_set_config(void *arg, const void *buf, size_t sz, nni_type t)
if (cfg == NULL) {
return (NNG_EINVAL);
}
- if ((ep = arg) != NULL) {
- nng_tls_config *old;
-
- nni_mtx_lock(&ep->lk);
- old = ep->cfg;
- nng_tls_config_hold(cfg);
- ep->cfg = cfg;
- nni_mtx_unlock(&ep->lk);
- if (old != NULL) {
- nng_tls_config_free(old);
- }
+ nni_mtx_lock(&d->lk);
+ old = d->cfg;
+ nng_tls_config_hold(cfg);
+ d->cfg = cfg;
+ nni_mtx_unlock(&d->lk);
+ if (old != NULL) {
+ nng_tls_config_free(old);
}
return (0);
}
static int
-tls_ep_get_config(void *arg, void *buf, size_t *szp, nni_type t)
+tls_dialer_get_config(void *arg, void *buf, size_t *szp, nni_type t)
{
- tls_ep * ep = arg;
+ tls_dialer * d = arg;
nng_tls_config *cfg;
int rv;
- nni_mtx_lock(&ep->lk);
- if ((cfg = ep->cfg) != NULL) {
+ nni_mtx_lock(&d->lk);
+ if ((cfg = d->cfg) != NULL) {
nng_tls_config_hold(cfg);
}
if ((rv = nni_copyout_ptr(cfg, buf, szp, t)) != 0) {
nng_tls_config_free(cfg);
}
- nni_mtx_unlock(&ep->lk);
+ nni_mtx_unlock(&d->lk);
return (rv);
}
static int
-tls_ep_set_server_name(void *arg, const void *buf, size_t sz, nni_type t)
+tls_dialer_set_server_name(void *arg, const void *buf, size_t sz, nni_type t)
{
- tls_ep *ep = arg;
- int rv;
- if ((rv = tls_check_string(buf, sz, t)) != 0) {
- return (rv);
- }
- if ((ep = arg) != NULL) {
- nni_mtx_lock(&ep->lk);
- rv = nng_tls_config_server_name(ep->cfg, buf);
- nni_mtx_unlock(&ep->lk);
+ tls_dialer *d = arg;
+ int rv;
+ if ((rv = tls_check_string(buf, sz, t)) == 0) {
+ nni_mtx_lock(&d->lk);
+ rv = nng_tls_config_server_name(d->cfg, buf);
+ nni_mtx_unlock(&d->lk);
}
return (rv);
}
static int
-tls_ep_set_auth_mode(void *arg, const void *buf, size_t sz, nni_type t)
+tls_dialer_set_auth_mode(void *arg, const void *buf, size_t sz, nni_type t)
{
- int mode;
- int rv;
- tls_ep *ep;
+ int mode;
+ int rv;
+ tls_dialer *d = arg;
rv = nni_copyin_int(&mode, buf, sz, NNG_TLS_AUTH_MODE_NONE,
NNG_TLS_AUTH_MODE_REQUIRED, t);
- if ((rv == 0) && ((ep = arg) != NULL)) {
- nni_mtx_lock(&ep->lk);
- rv = nng_tls_config_auth_mode(ep->cfg, mode);
- nni_mtx_unlock(&ep->lk);
+ if (rv == 0) {
+ nni_mtx_lock(&d->lk);
+ rv = nng_tls_config_auth_mode(d->cfg, mode);
+ nni_mtx_unlock(&d->lk);
}
return (rv);
}
static int
-tls_ep_set_ca_file(void *arg, const void *buf, size_t sz, nni_opt_type t)
+tls_dialer_set_ca_file(void *arg, const void *buf, size_t sz, nni_opt_type t)
{
- tls_ep *ep;
- int rv;
+ tls_dialer *d = arg;
+ int rv;
- if (((rv = tls_check_string(buf, sz, t)) == 0) &&
- ((ep = arg) != NULL)) {
- nni_mtx_lock(&ep->lk);
- rv = nng_tls_config_ca_file(ep->cfg, buf);
- nni_mtx_unlock(&ep->lk);
+ if ((rv = tls_check_string(buf, sz, t)) == 0) {
+ nni_mtx_lock(&d->lk);
+ rv = nng_tls_config_ca_file(d->cfg, buf);
+ nni_mtx_unlock(&d->lk);
}
return (rv);
}
static int
-tls_ep_set_cert_key_file(void *arg, const void *buf, size_t sz, nni_opt_type t)
+tls_dialer_set_cert_key_file(
+ void *arg, const void *buf, size_t sz, nni_opt_type t)
{
- tls_ep *ep;
- int rv;
+ tls_dialer *d = arg;
+ int rv;
- if (((rv = tls_check_string(buf, sz, t)) == 0) &&
- ((ep = arg) != NULL)) {
- nni_mtx_lock(&ep->lk);
- rv = nng_tls_config_cert_key_file(ep->cfg, buf, NULL);
- nni_mtx_unlock(&ep->lk);
+ if ((rv = tls_check_string(buf, sz, t)) == 0) {
+ nni_mtx_lock(&d->lk);
+ rv = nng_tls_config_cert_key_file(d->cfg, buf, NULL);
+ nni_mtx_unlock(&d->lk);
}
return (rv);
}
-static const nni_option tls_ep_opts[] = {
+static const nni_option tls_dialer_opts[] = {
{
.o_name = NNG_OPT_TLS_CONFIG,
- .o_get = tls_ep_get_config,
- .o_set = tls_ep_set_config,
+ .o_get = tls_dialer_get_config,
+ .o_set = tls_dialer_set_config,
},
{
.o_name = NNG_OPT_TLS_SERVER_NAME,
- .o_set = tls_ep_set_server_name,
+ .o_set = tls_dialer_set_server_name,
},
{
.o_name = NNG_OPT_TLS_CA_FILE,
- .o_set = tls_ep_set_ca_file,
+ .o_set = tls_dialer_set_ca_file,
},
{
.o_name = NNG_OPT_TLS_CERT_KEY_FILE,
- .o_set = tls_ep_set_cert_key_file,
+ .o_set = tls_dialer_set_cert_key_file,
},
{
.o_name = NNG_OPT_TLS_AUTH_MODE,
- .o_set = tls_ep_set_auth_mode,
+ .o_set = tls_dialer_set_auth_mode,
},
{
.o_name = NULL,
},
};
-// private version of getopt and setopt take the type
-int
-nni_tls_dialer_getopt(
- nng_tls_dialer *d, const char *name, void *buf, size_t *szp, nni_type t)
+static int
+tls_dialer_getx(
+ void *arg, const char *name, void *buf, size_t *szp, nni_type t)
{
- int rv;
- tls_ep *ep = (void *) d;
+ tls_dialer *d = arg;
+ int rv;
- rv = nni_tcp_dialer_getopt(ep->tcp.d, name, buf, szp, t);
+ rv = nni_stream_dialer_getx(d->d, name, buf, szp, t);
if (rv == NNG_ENOTSUP) {
- rv = nni_getopt(tls_ep_opts, name, ep, buf, szp, t);
+ rv = nni_getopt(tls_dialer_opts, name, d, buf, szp, t);
}
return (rv);
}
-int
-nni_tls_dialer_setopt(nng_tls_dialer *d, const char *name, const void *buf,
- size_t sz, nni_type t)
+static int
+tls_dialer_setx(
+ void *arg, const char *name, const void *buf, size_t sz, nni_type t)
{
- int rv;
- tls_ep *ep = (void *) d;
+ tls_dialer *d = arg;
+ int rv;
- rv = nni_tcp_dialer_setopt(
- ep != NULL ? ep->tcp.d : NULL, name, buf, sz, t);
+ rv = nni_stream_dialer_setx(d->d, name, buf, sz, t);
if (rv == NNG_ENOTSUP) {
- rv = nni_setopt(tls_ep_opts, name, ep, buf, sz, t);
+ rv = nni_setopt(tls_dialer_opts, name, d, buf, sz, t);
}
return (rv);
}
-// public versions of option handlers here
-
-int
-nng_tls_dialer_getopt(
- nng_tls_dialer *d, const char *name, void *buf, size_t *szp)
-{
- return (nni_tls_dialer_getopt(d, name, buf, szp, NNI_TYPE_OPAQUE));
-}
-
int
-nng_tls_dialer_setopt(
- nng_tls_dialer *d, const char *name, const void *buf, size_t sz)
+nni_tls_dialer_alloc(nng_stream_dialer **dp, const nng_url *url)
{
- return (nni_tls_dialer_setopt(d, name, buf, sz, NNI_TYPE_OPAQUE));
-}
+ tls_dialer *d;
+ int rv;
+ nng_url myurl;
-void
-nng_tls_listener_close(nng_tls_listener *l)
-{
- tls_ep *ep = (void *) l;
- nni_tcp_listener_close(ep->tcp.l);
-}
-
-void
-nng_tls_listener_free(nng_tls_listener *l)
-{
- tls_ep *ep = (void *) l;
- if (ep != NULL) {
- nng_tls_listener_close(l);
- nng_tls_config_free(ep->cfg);
- nni_mtx_fini(&ep->lk);
- NNI_FREE_STRUCT(ep);
- }
-}
-
-int
-nng_tls_listener_alloc(nng_tls_listener **lp)
-{
- tls_ep *ep;
- int rv;
+ memcpy(&myurl, url, sizeof(myurl));
+ myurl.u_scheme = url->u_scheme + strlen("tls+");
if ((rv = nni_init()) != 0) {
return (rv);
}
- if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) {
+ if ((d = NNI_ALLOC_STRUCT(d)) == NULL) {
return (NNG_ENOMEM);
}
- nni_mtx_init(&ep->lk);
+ nni_mtx_init(&d->lk);
- if ((rv = nni_tcp_listener_init(&ep->tcp.l)) != 0) {
- nni_mtx_fini(&ep->lk);
- NNI_FREE_STRUCT(ep);
+ if ((rv = nng_stream_dialer_alloc_url(&d->d, &myurl)) != 0) {
+ nni_mtx_fini(&d->lk);
+ NNI_FREE_STRUCT(d);
return (rv);
}
- if ((rv = nng_tls_config_alloc(&ep->cfg, NNG_TLS_MODE_SERVER)) != 0) {
- nni_tcp_listener_fini(ep->tcp.l);
- nni_mtx_fini(&ep->lk);
- NNI_FREE_STRUCT(ep);
+ if ((rv = nng_tls_config_alloc(&d->cfg, NNG_TLS_MODE_CLIENT)) != 0) {
+ nng_stream_dialer_free(d->d);
+ nni_mtx_fini(&d->lk);
+ NNI_FREE_STRUCT(d);
return (rv);
}
- *lp = (void *) ep;
- return (0);
+
+ // Set the expected outbound hostname
+ nng_tls_config_server_name(d->cfg, url->u_hostname);
+
+ d->ops.sd_close = tls_dialer_close;
+ d->ops.sd_free = tls_dialer_free;
+ d->ops.sd_dial = tls_dialer_dial;
+ d->ops.sd_getx = tls_dialer_getx;
+ d->ops.sd_setx = tls_dialer_setx;
+ *dp = (void *) d;
+ return (rv);
}
-int
-nng_tls_listener_listen(nng_tls_listener *l, const nng_sockaddr *sa)
+typedef struct {
+ nng_stream_listener ops;
+ nng_stream_listener *l;
+ nng_tls_config * cfg;
+ nni_mtx lk;
+} tls_listener;
+
+static void
+tls_listener_close(void *arg)
{
- tls_ep *ep = (void *) l;
- return (nni_tcp_listener_listen(ep->tcp.l, sa));
+ tls_listener *l = arg;
+ nng_stream_listener_close(l->l);
}
-void
-nng_tls_listener_accept(nng_tls_listener *l, nng_aio *aio)
+static void
+tls_listener_free(void *arg)
{
- int rv;
- nng_tls *tls;
- tls_ep * ep = (void *) l;
+ tls_listener *l;
+ if ((l = arg) != NULL) {
+ tls_listener_close(l);
+ nng_tls_config_free(l->cfg);
+ nni_mtx_fini(&l->lk);
+ NNI_FREE_STRUCT(l);
+ }
+}
+
+static int
+tls_listener_listen(void *arg)
+{
+ tls_listener *l = arg;
+ return (nng_stream_listener_listen(l->l));
+}
+
+static void
+tls_listener_accept(void *arg, nng_aio *aio)
+{
+ tls_listener * l = arg;
+ int rv;
+ nng_stream * tls;
+ nni_tls_common *com;
if (nni_aio_begin(aio) != 0) {
return;
}
- if ((tls = NNI_ALLOC_STRUCT(tls)) == NULL) {
- nni_aio_finish_error(aio, NNG_ENOMEM);
+ if ((rv = nni_tls_alloc(&tls)) != 0) {
+ nni_aio_finish_error(aio, rv);
return;
}
- if ((rv = nni_aio_init(&tls->aio, tls_conn_cb, tls)) != 0) {
+ com = (void *) tls;
+ if ((rv = nni_aio_init(&com->aio, tls_conn_cb, tls)) != 0) {
nni_aio_finish_error(aio, rv);
- NNI_FREE_STRUCT(tls);
+ nng_stream_free(tls);
return;
}
- tls->uaio = aio;
+ com->uaio = aio;
// Save a copy of the TLS configuration. This way we don't have
// to ensure that the dialer outlives the connection, because the
// only shared data is the configuration which is reference counted.
- nni_mtx_lock(&ep->lk);
- tls->cfg = ep->cfg;
- nng_tls_config_hold(tls->cfg);
- nni_mtx_unlock(&ep->lk);
+ nni_mtx_lock(&l->lk);
+ com->cfg = l->cfg;
+ nng_tls_config_hold(com->cfg);
+ nni_mtx_unlock(&l->lk);
if ((rv = nni_aio_schedule(aio, tls_conn_cancel, tls)) != 0) {
nni_aio_finish_error(aio, rv);
- nng_tls_free(tls);
+ nng_stream_free(tls);
return;
}
- nni_tcp_listener_accept(ep->tcp.l, tls->aio);
+ nng_stream_listener_accept(l->l, com->aio);
}
-int
-nni_tls_listener_getopt(
- nng_tls_listener *l, const char *name, void *buf, size_t *szp, nni_type t)
+static int
+tls_listener_set_config(void *arg, const void *buf, size_t sz, nni_type t)
{
- int rv;
- tls_ep *ep = (void *) l;
+ int rv;
+ nng_tls_config *cfg;
+ tls_listener * l = arg;
+ nng_tls_config *old;
- rv = nni_tcp_listener_getopt(ep->tcp.l, name, buf, szp, t);
- if (rv == NNG_ENOTSUP) {
- rv = nni_getopt(tls_ep_opts, name, ep, buf, szp, t);
+ if ((rv = nni_copyin_ptr((void **) &cfg, buf, sz, t)) != 0) {
+ return (rv);
+ }
+ if (cfg == NULL) {
+ return (NNG_EINVAL);
+ }
+
+ nni_mtx_lock(&l->lk);
+ old = l->cfg;
+ nng_tls_config_hold(cfg);
+ l->cfg = cfg;
+ nni_mtx_unlock(&l->lk);
+ if (old != NULL) {
+ nng_tls_config_free(old);
+ }
+ return (0);
+}
+
+static int
+tls_listener_get_config(void *arg, void *buf, size_t *szp, nni_type t)
+{
+ tls_listener * l = arg;
+ nng_tls_config *cfg;
+ int rv;
+ nni_mtx_lock(&l->lk);
+ if ((cfg = l->cfg) != NULL) {
+ nng_tls_config_hold(cfg);
+ }
+ if ((rv = nni_copyout_ptr(cfg, buf, szp, t)) != 0) {
+ nng_tls_config_free(cfg);
}
+ nni_mtx_unlock(&l->lk);
return (rv);
}
-int
-nni_tls_listener_setopt(nng_tls_listener *l, const char *name, const void *buf,
- size_t sz, nni_type t)
+static int
+tls_listener_set_server_name(void *arg, const void *buf, size_t sz, nni_type t)
+{
+ tls_listener *l = arg;
+ int rv;
+ if ((rv = tls_check_string(buf, sz, t)) == 0) {
+ nni_mtx_lock(&l->lk);
+ rv = nng_tls_config_server_name(l->cfg, buf);
+ nni_mtx_unlock(&l->lk);
+ }
+ return (rv);
+}
+
+static int
+tls_listener_set_auth_mode(void *arg, const void *buf, size_t sz, nni_type t)
{
- int rv;
- tls_ep *ep = (void *) l;
+ int mode;
+ int rv;
+ tls_listener *l = arg;
- rv = nni_tcp_listener_setopt(
- ep != NULL ? ep->tcp.l : NULL, name, buf, sz, t);
+ rv = nni_copyin_int(&mode, buf, sz, NNG_TLS_AUTH_MODE_NONE,
+ NNG_TLS_AUTH_MODE_REQUIRED, t);
+ if (rv == 0) {
+ nni_mtx_lock(&l->lk);
+ rv = nng_tls_config_auth_mode(l->cfg, mode);
+ nni_mtx_unlock(&l->lk);
+ }
+ return (rv);
+}
+
+static int
+tls_listener_set_ca_file(void *arg, const void *buf, size_t sz, nni_opt_type t)
+{
+ tls_listener *l = arg;
+ int rv;
+
+ if ((rv = tls_check_string(buf, sz, t)) == 0) {
+ nni_mtx_lock(&l->lk);
+ rv = nng_tls_config_ca_file(l->cfg, buf);
+ nni_mtx_unlock(&l->lk);
+ }
+ return (rv);
+}
+
+static int
+tls_listener_set_cert_key_file(
+ void *arg, const void *buf, size_t sz, nni_opt_type t)
+{
+ tls_listener *l = arg;
+ int rv;
+
+ if ((rv = tls_check_string(buf, sz, t)) == 0) {
+ nni_mtx_lock(&l->lk);
+ rv = nng_tls_config_cert_key_file(l->cfg, buf, NULL);
+ nni_mtx_unlock(&l->lk);
+ }
+ return (rv);
+}
+
+static const nni_option tls_listener_opts[] = {
+ {
+ .o_name = NNG_OPT_TLS_CONFIG,
+ .o_get = tls_listener_get_config,
+ .o_set = tls_listener_set_config,
+ },
+ {
+ .o_name = NNG_OPT_TLS_SERVER_NAME,
+ .o_set = tls_listener_set_server_name,
+ },
+ {
+ .o_name = NNG_OPT_TLS_CA_FILE,
+ .o_set = tls_listener_set_ca_file,
+ },
+ {
+ .o_name = NNG_OPT_TLS_CERT_KEY_FILE,
+ .o_set = tls_listener_set_cert_key_file,
+ },
+ {
+ .o_name = NNG_OPT_TLS_AUTH_MODE,
+ .o_set = tls_listener_set_auth_mode,
+ },
+ {
+ .o_name = NULL,
+ },
+};
+
+static int
+tls_listener_getx(
+ void *arg, const char *name, void *buf, size_t *szp, nni_type t)
+{
+ int rv;
+ tls_listener *l = arg;
+
+ rv = nni_stream_listener_getx(l->l, name, buf, szp, t);
if (rv == NNG_ENOTSUP) {
- rv = nni_setopt(tls_ep_opts, name, ep, buf, sz, t);
+ rv = nni_getopt(tls_listener_opts, name, l, buf, szp, t);
}
return (rv);
}
-// public versions of option handlers here
+static int
+tls_listener_setx(
+ void *arg, const char *name, const void *buf, size_t sz, nni_type t)
+{
+ int rv;
+ tls_listener *l = arg;
+
+ rv = nni_stream_listener_setx(l->l, name, buf, sz, t);
+ if (rv == NNG_ENOTSUP) {
+ rv = nni_setopt(tls_listener_opts, name, l, buf, sz, t);
+ }
+ return (rv);
+}
int
-nng_tls_listener_getopt(
- nng_tls_listener *l, const char *name, void *buf, size_t *szp)
+nni_tls_listener_alloc(nng_stream_listener **lp, const nng_url *url)
{
- return (nni_tls_listener_getopt(l, name, buf, szp, NNI_TYPE_OPAQUE));
+ tls_listener *l;
+ int rv;
+ nng_url myurl;
+
+ memcpy(&myurl, url, sizeof(myurl));
+ myurl.u_scheme = url->u_scheme + strlen("tls+");
+
+ if ((rv = nni_init()) != 0) {
+ return (rv);
+ }
+ if ((l = NNI_ALLOC_STRUCT(l)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+ nni_mtx_init(&l->lk);
+
+ if ((rv = nng_stream_listener_alloc_url(&l->l, &myurl)) != 0) {
+ nni_mtx_fini(&l->lk);
+ NNI_FREE_STRUCT(l);
+ return (rv);
+ }
+ if ((rv = nng_tls_config_alloc(&l->cfg, NNG_TLS_MODE_SERVER)) != 0) {
+ nng_stream_listener_free(l->l);
+ nni_mtx_fini(&l->lk);
+ NNI_FREE_STRUCT(l);
+ return (rv);
+ }
+ l->ops.sl_free = tls_listener_free;
+ l->ops.sl_close = tls_listener_close;
+ l->ops.sl_accept = tls_listener_accept;
+ l->ops.sl_listen = tls_listener_listen;
+ l->ops.sl_getx = tls_listener_getx;
+ l->ops.sl_setx = tls_listener_setx;
+ *lp = (void *) l;
+ return (0);
}
+// The following checks exist for socket configuration, when we need to
+// configure an option on a socket before any transport is configured
+// underneath.
+
+static int
+tls_check_config(const void *buf, size_t sz, nni_type t)
+{
+ int rv;
+ nng_tls_config *cfg;
+
+ if ((rv = nni_copyin_ptr((void **) &cfg, buf, sz, t)) != 0) {
+ return (rv);
+ }
+ if (cfg == NULL) {
+ return (NNG_EINVAL);
+ }
+ return (0);
+}
+
+static int
+tls_check_auth_mode(const void *buf, size_t sz, nni_type t)
+{
+ int mode;
+ int rv;
+
+ rv = nni_copyin_int(&mode, buf, sz, NNG_TLS_AUTH_MODE_NONE,
+ NNG_TLS_AUTH_MODE_REQUIRED, t);
+ return (rv);
+}
+
+static const nni_chkoption tls_chkopts[] = {
+ {
+ .o_name = NNG_OPT_TLS_CONFIG,
+ .o_check = tls_check_config,
+ },
+ {
+ .o_name = NNG_OPT_TLS_SERVER_NAME,
+ .o_check = tls_check_string,
+ },
+ {
+ .o_name = NNG_OPT_TLS_CA_FILE,
+ .o_check = tls_check_string,
+ },
+ {
+ .o_name = NNG_OPT_TLS_CERT_KEY_FILE,
+ .o_check = tls_check_string,
+ },
+ {
+ .o_name = NNG_OPT_TLS_AUTH_MODE,
+ .o_check = tls_check_auth_mode,
+ },
+ {
+ .o_name = NULL,
+ },
+};
+
int
-nng_tls_listener_setopt(
- nng_tls_listener *l, const char *name, const void *buf, size_t sz)
+nni_tls_checkopt(const char *name, const void *data, size_t sz, nni_type t)
{
- return (nni_tls_listener_setopt(l, name, buf, sz, NNI_TYPE_OPAQUE));
+ int rv;
+
+ rv = nni_chkopt(tls_chkopts, name, data, sz, t);
+ if (rv == NNG_ENOTSUP) {
+ rv = nni_stream_checkopt("tcp", name, data, sz, t);
+ }
+ return (rv);
}