diff options
| author | Garrett D'Amore <garrett@damore.org> | 2019-01-21 22:40:10 -0800 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2019-02-16 19:22:27 -0800 |
| commit | 5cf750697624d4fd63cfe26921209d7c30e1a2d2 (patch) | |
| tree | bf11695e5f1ec5e400c87da0cc6ff23935a2eeff /src/supplemental/tls/tls_common.c | |
| parent | ca655b9db689ee0e655248b1a9f166b8db6cc984 (diff) | |
| download | nng-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.c | 754 |
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); } |
