aboutsummaryrefslogtreecommitdiff
path: root/src/supplemental/tls
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
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')
-rw-r--r--src/supplemental/tls/mbedtls/tls.c363
-rw-r--r--src/supplemental/tls/none/tls.c92
-rw-r--r--src/supplemental/tls/tls_api.h52
-rw-r--r--src/supplemental/tls/tls_common.c754
4 files changed, 667 insertions, 594 deletions
diff --git a/src/supplemental/tls/mbedtls/tls.c b/src/supplemental/tls/mbedtls/tls.c
index 9f1e8f83..d3816747 100644
--- a/src/supplemental/tls/mbedtls/tls.c
+++ b/src/supplemental/tls/mbedtls/tls.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>
//
@@ -28,10 +28,9 @@
#include "mbedtls/ssl.h"
#include "core/nng_impl.h"
+#include "core/tcp.h"
#include "supplemental/tls/tls_api.h"
-#include <nng/supplemental/tls/tls.h>
-
// Implementation note. This implementation buffers data between the TLS
// encryption layer (mbedTLS) and the underlying TCP socket. As a result,
// there may be some additional latency caused by buffer draining and
@@ -59,8 +58,9 @@ typedef struct nni_tls_certkey {
nni_list_node node;
} nni_tls_certkey;
-struct nni_tls {
- nni_tcp_conn * tcp;
+typedef struct {
+ nni_tls_common com;
+ nng_stream * tcp;
mbedtls_ssl_context ctx;
nng_tls_config * cfg; // kept so we can release it
nni_mtx lk;
@@ -81,7 +81,7 @@ struct nni_tls {
nni_list sends; // upper side sends
nni_list recvs; // upper recv aios
nni_aio * handshake; // handshake aio (upper)
-};
+} tls;
struct nng_tls_config {
mbedtls_ssl_config cfg_ctx;
@@ -100,18 +100,18 @@ struct nng_tls_config {
nni_list certkeys;
};
-static void nni_tls_send_cb(void *);
-static void nni_tls_recv_cb(void *);
+static void tls_send_cb(void *);
+static void tls_recv_cb(void *);
-static void nni_tls_do_send(nni_tls *);
-static void nni_tls_do_recv(nni_tls *);
-static void nni_tls_do_handshake(nni_tls *);
+static void tls_do_send(tls *);
+static void tls_do_recv(tls *);
+static void tls_do_handshake(tls *);
-static int nni_tls_net_send(void *, const unsigned char *, size_t);
-static int nni_tls_net_recv(void *, unsigned char *, size_t);
+static int tls_net_send(void *, const unsigned char *, size_t);
+static int tls_net_recv(void *, unsigned char *, size_t);
static void
-nni_tls_dbg(void *ctx, int level, const char *file, int line, const char *s)
+tls_dbg(void *ctx, int level, const char *file, int line, const char *s)
{
char buf[128];
NNI_ARG_UNUSED(ctx);
@@ -121,7 +121,7 @@ nni_tls_dbg(void *ctx, int level, const char *file, int line, const char *s)
}
static int
-nni_tls_get_entropy(void *arg, unsigned char *buf, size_t len)
+tls_get_entropy(void *arg, unsigned char *buf, size_t len)
{
NNI_ARG_UNUSED(arg);
while (len) {
@@ -137,7 +137,7 @@ nni_tls_get_entropy(void *arg, unsigned char *buf, size_t len)
}
static int
-nni_tls_random(void *arg, unsigned char *buf, size_t sz)
+tls_random(void *arg, unsigned char *buf, size_t sz)
{
#ifdef NNG_TLS_USE_CTR_DRBG
int rv;
@@ -149,7 +149,7 @@ nni_tls_random(void *arg, unsigned char *buf, size_t sz)
nni_mtx_unlock(&cfg->rng_lk);
return (rv);
#else
- return (nni_tls_get_entropy(arg, buf, sz));
+ return (tls_get_entropy(arg, buf, sz));
#endif
}
@@ -230,15 +230,15 @@ nni_tls_config_init(nng_tls_config **cpp, enum nng_tls_mode mode)
#ifdef NNG_TLS_USE_CTR_DRBG
mbedtls_ctr_drbg_init(&cfg->rng_ctx);
rv = mbedtls_ctr_drbg_seed(
- &cfg->rng_ctx, nni_tls_get_entropy, NULL, NULL, 0);
+ &cfg->rng_ctx, tls_get_entropy, NULL, NULL, 0);
if (rv != 0) {
nni_tls_config_fini(cfg);
return (rv);
}
#endif
- mbedtls_ssl_conf_rng(&cfg->cfg_ctx, nni_tls_random, cfg);
+ mbedtls_ssl_conf_rng(&cfg->cfg_ctx, tls_random, cfg);
- mbedtls_ssl_conf_dbg(&cfg->cfg_ctx, nni_tls_dbg, cfg);
+ mbedtls_ssl_conf_dbg(&cfg->cfg_ctx, tls_dbg, cfg);
*cpp = cfg;
return (0);
@@ -252,41 +252,12 @@ nni_tls_config_hold(nng_tls_config *cfg)
nni_mtx_unlock(&cfg->lk);
}
-void
-nni_tls_fini(nni_tls *tp)
-{
- // Shut it all down first.
- if (tp != NULL) {
- if (tp->tcp) {
- nni_tcp_conn_close(tp->tcp);
- }
- nni_aio_stop(tp->tcp_send);
- nni_aio_stop(tp->tcp_recv);
-
- // And finalize / free everything.
- if (tp->tcp) {
- nni_tcp_conn_fini(tp->tcp);
- }
- nni_aio_fini(tp->tcp_send);
- nni_aio_fini(tp->tcp_recv);
- mbedtls_ssl_free(&tp->ctx);
- 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
- nni_tls_config_fini(tp->cfg);
- }
- NNI_FREE_STRUCT(tp);
- }
-}
-
-// nni_tls_mkerr converts an mbed error to an NNG error. In all cases
+// tls_mkerr converts an mbed error to an NNG error. In all cases
// we just encode with NNG_ETRANERR.
static struct {
int tls;
int nng;
-} nni_tls_errs[] = {
+} tls_errs[] = {
{ MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE, NNG_EPEERAUTH },
{ MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED, NNG_EPEERAUTH },
{ MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED, NNG_EPEERAUTH },
@@ -300,60 +271,74 @@ static struct {
};
static int
-nni_tls_mkerr(int err)
+tls_mkerr(int err)
{
- for (int i = 0; nni_tls_errs[i].tls != 0; i++) {
- if (nni_tls_errs[i].tls == err) {
- return (nni_tls_errs[i].nng);
+ for (int i = 0; tls_errs[i].tls != 0; i++) {
+ if (tls_errs[i].tls == err) {
+ return (tls_errs[i].nng);
}
}
return (NNG_ECRYPTO);
}
-int
-nni_tls_init(nni_tls **tpp, nng_tls_config *cfg, nni_tcp_conn *tcp)
+// The common code should call this only after it has released
+// it's upper layer stuff.
+static void
+tls_free(void *arg)
{
- nni_tls *tp;
- int rv;
- bool on = true;
+ tls *tls = arg;
+
+ // Shut it all down first.
+ if (tls != NULL) {
+ if (tls->tcp != NULL) {
+ nng_stream_close(tls->tcp);
+ }
+ nni_aio_stop(tls->tcp_send);
+ nni_aio_stop(tls->tcp_recv);
- // During the handshake, disable Nagle to shorten the
- // negotiation. Once things are set up the caller can
- // re-enable Nagle if so desired.
- (void) nni_tcp_conn_setopt(
- tcp, NNG_OPT_TCP_NODELAY, &on, sizeof(on), NNI_TYPE_BOOL);
+ nni_aio_fini(tls->com.aio);
+ nng_tls_config_free(tls->com.cfg);
- if ((tp = NNI_ALLOC_STRUCT(tp)) == NULL) {
- return (NNG_ENOMEM);
+ // And finalize / free everything.
+ nng_stream_free(tls->tcp);
+ nni_aio_fini(tls->tcp_send);
+ nni_aio_fini(tls->tcp_recv);
+ mbedtls_ssl_free(&tls->ctx);
+ if (tls->recvbuf != NULL) {
+ nni_free(tls->recvbuf, NNG_TLS_MAX_RECV_SIZE);
+ }
+ if (tls->sendbuf != NULL) {
+ nni_free(tls->sendbuf, NNG_TLS_MAX_RECV_SIZE);
+ }
+ nni_mtx_fini(&tls->lk);
+ NNI_FREE_STRUCT(tls);
}
+}
+
+int
+nni_tls_start(nng_stream *arg, nng_stream *tcp)
+{
+ tls * tp = (void *) arg;
+ nng_tls_config *cfg = tp->com.cfg;
+ int rv;
+
if ((tp->recvbuf = nni_zalloc(NNG_TLS_MAX_RECV_SIZE)) == NULL) {
- NNI_FREE_STRUCT(tp);
return (NNG_ENOMEM);
}
if ((tp->sendbuf = nni_zalloc(NNG_TLS_MAX_SEND_SIZE)) == NULL) {
- nni_free(tp->sendbuf, NNG_TLS_MAX_RECV_SIZE);
- NNI_FREE_STRUCT(tp);
return (NNG_ENOMEM);
}
nni_mtx_lock(&cfg->lk);
// No more changes allowed to config.
cfg->active = true;
- cfg->refcnt++;
- tp->cfg = cfg;
nni_mtx_unlock(&cfg->lk);
- nni_aio_list_init(&tp->sends);
- nni_aio_list_init(&tp->recvs);
- nni_mtx_init(&tp->lk);
mbedtls_ssl_init(&tp->ctx);
- mbedtls_ssl_set_bio(
- &tp->ctx, tp, nni_tls_net_send, nni_tls_net_recv, NULL);
+ mbedtls_ssl_set_bio(&tp->ctx, tp, tls_net_send, tls_net_recv, NULL);
if ((rv = mbedtls_ssl_setup(&tp->ctx, &cfg->cfg_ctx)) != 0) {
- rv = nni_tls_mkerr(rv);
- nni_tls_fini(tp);
- return (rv);
+ return (tls_mkerr(rv));
}
if (cfg->server_name) {
@@ -362,25 +347,23 @@ nni_tls_init(nni_tls **tpp, nng_tls_config *cfg, nni_tcp_conn *tcp)
tp->tcp = tcp;
- if (((rv = nni_aio_init(&tp->tcp_send, nni_tls_send_cb, tp)) != 0) ||
- ((rv = nni_aio_init(&tp->tcp_recv, nni_tls_recv_cb, tp)) != 0)) {
- nni_tls_fini(tp);
+ if (((rv = nni_aio_init(&tp->tcp_send, tls_send_cb, tp)) != 0) ||
+ ((rv = nni_aio_init(&tp->tcp_recv, tls_recv_cb, tp)) != 0)) {
return (rv);
}
nni_mtx_lock(&tp->lk);
// Kick off a handshake operation.
- nni_tls_do_handshake(tp);
+ tls_do_handshake(tp);
nni_mtx_unlock(&tp->lk);
- *tpp = tp;
return (0);
}
static void
-nni_tls_cancel(nni_aio *aio, void *arg, int rv)
+tls_cancel(nni_aio *aio, void *arg, int rv)
{
- nni_tls *tp = arg;
+ tls *tp = arg;
nni_mtx_lock(&tp->lk);
if (nni_aio_list_active(aio)) {
nni_aio_list_remove(aio);
@@ -389,33 +372,16 @@ nni_tls_cancel(nni_aio *aio, void *arg, int rv)
nni_mtx_unlock(&tp->lk);
}
+// tls_send_cb is called when the underlying TCP send completes.
static void
-nni_tls_fail(nni_tls *tp, int rv)
-{
- nni_aio *aio;
- tp->tls_closed = true;
- nni_tcp_conn_close(tp->tcp);
- tp->tcp_closed = true;
- while ((aio = nni_list_first(&tp->recvs)) != NULL) {
- nni_list_remove(&tp->recvs, aio);
- nni_aio_finish_error(aio, rv);
- }
- while ((aio = nni_list_first(&tp->sends)) != NULL) {
- nni_list_remove(&tp->recvs, aio);
- nni_aio_finish_error(aio, rv);
- }
-}
-
-// nni_tls_send_cb is called when the underlying TCP send completes.
-static void
-nni_tls_send_cb(void *ctx)
+tls_send_cb(void *ctx)
{
- nni_tls *tp = ctx;
+ tls * tp = ctx;
nni_aio *aio = tp->tcp_send;
nni_mtx_lock(&tp->lk);
if (nni_aio_result(aio) != 0) {
- nni_tcp_conn_close(tp->tcp);
+ nng_stream_close(tp->tcp);
tp->tcp_closed = true;
} else {
size_t n = nni_aio_count(aio);
@@ -428,25 +394,24 @@ nni_tls_send_cb(void *ctx)
iov.iov_len = tp->sendlen;
nni_aio_set_iov(aio, 1, &iov);
nni_aio_set_timeout(aio, NNG_DURATION_INFINITE);
- nni_tcp_conn_send(tp->tcp, aio);
+ nng_stream_send(tp->tcp, aio);
nni_mtx_unlock(&tp->lk);
return;
}
tp->sendoff = 0;
tp->sending = false;
}
- if (!tp->hsdone) {
- nni_tls_do_handshake(tp);
- }
+
+ tls_do_handshake(tp);
if (tp->hsdone) {
- nni_tls_do_send(tp);
- nni_tls_do_recv(tp);
+ tls_do_send(tp);
+ tls_do_recv(tp);
}
nni_mtx_unlock(&tp->lk);
}
static void
-nni_tls_recv_start(nni_tls *tp)
+tls_recv_start(tls *tp)
{
nni_aio *aio;
nni_iov iov;
@@ -467,13 +432,13 @@ nni_tls_recv_start(nni_tls *tp)
iov.iov_len = NNG_TLS_MAX_RECV_SIZE;
nni_aio_set_iov(aio, 1, &iov);
nni_aio_set_timeout(tp->tcp_recv, NNG_DURATION_INFINITE);
- nni_tcp_conn_recv(tp->tcp, aio);
+ nng_stream_recv(tp->tcp, aio);
}
static void
-nni_tls_recv_cb(void *ctx)
+tls_recv_cb(void *ctx)
{
- nni_tls *tp = ctx;
+ tls * tp = ctx;
nni_aio *aio = tp->tcp_recv;
nni_mtx_lock(&tp->lk);
@@ -481,7 +446,7 @@ nni_tls_recv_cb(void *ctx)
if (nni_aio_result(aio) != 0) {
// Close the underlying TCP channel, but permit data we
// already received to continue to be received.
- nni_tcp_conn_close(tp->tcp);
+ nng_stream_close(tp->tcp);
tp->tcp_closed = true;
} else {
NNI_ASSERT(tp->recvlen == 0);
@@ -492,12 +457,10 @@ nni_tls_recv_cb(void *ctx)
// If we were closed (above), the upper layer will detect and
// react properly. Otherwise the upper layer will consume
// data.
- if (!tp->hsdone) {
- nni_tls_do_handshake(tp);
- }
+ tls_do_handshake(tp);
if (tp->hsdone) {
- nni_tls_do_recv(tp);
- nni_tls_do_send(tp);
+ tls_do_recv(tp);
+ tls_do_send(tp);
}
nni_mtx_unlock(&tp->lk);
@@ -511,10 +474,10 @@ nni_tls_recv_cb(void *ctx)
// ridiculous over queueing. This is always called with the pipe
// lock held, and never blocks.
static int
-nni_tls_net_send(void *ctx, const unsigned char *buf, size_t len)
+tls_net_send(void *ctx, const unsigned char *buf, size_t len)
{
- nni_tls *tp = ctx;
- nni_iov iov;
+ tls * tp = ctx;
+ nni_iov iov;
if (len > NNG_TLS_MAX_SEND_SIZE) {
len = NNG_TLS_MAX_SEND_SIZE;
@@ -538,22 +501,24 @@ nni_tls_net_send(void *ctx, const unsigned char *buf, size_t len)
iov.iov_len = len;
nni_aio_set_iov(tp->tcp_send, 1, &iov);
nni_aio_set_timeout(tp->tcp_send, NNG_DURATION_INFINITE);
- nni_tcp_conn_send(tp->tcp, tp->tcp_send);
+ nng_stream_send(tp->tcp, tp->tcp_send);
return (len);
}
static int
-nni_tls_net_recv(void *ctx, unsigned char *buf, size_t len)
+tls_net_recv(void *ctx, unsigned char *buf, size_t len)
{
- nni_tls *tp = ctx;
+ tls *tp = ctx;
// We should already be running with the pipe lock held,
// as we are running in that context.
- if (tp->tcp_closed && tp->recvlen == 0) {
- return (MBEDTLS_ERR_NET_RECV_FAILED);
- }
if (tp->recvlen == 0) {
+ if (tp->tcp_closed) {
+ // The underlying TCP transport has closed, and we
+ // have no more data in our receive buffer.
+ return (MBEDTLS_ERR_NET_RECV_FAILED);
+ }
len = MBEDTLS_ERR_SSL_WANT_READ;
} else {
if (len > tp->recvlen) {
@@ -564,16 +529,15 @@ nni_tls_net_recv(void *ctx, unsigned char *buf, size_t len)
tp->recvlen -= len;
}
- nni_tls_recv_start(tp);
+ tls_recv_start(tp);
return ((int) len);
}
-// nni_tls_send is the exported send function. It has a similar
-// calling convention as the platform TCP pipe.
-void
-nni_tls_send(nni_tls *tp, nni_aio *aio)
+static void
+tls_send(void *arg, nni_aio *aio)
{
- int rv;
+ int rv;
+ tls *tp = arg;
if (nni_aio_begin(aio) != 0) {
return;
@@ -584,20 +548,21 @@ nni_tls_send(nni_tls *tp, nni_aio *aio)
nni_aio_finish_error(aio, NNG_ECLOSED);
return;
}
- if ((rv = nni_aio_schedule(aio, nni_tls_cancel, tp)) != 0) {
+ if ((rv = nni_aio_schedule(aio, tls_cancel, tp)) != 0) {
nni_mtx_unlock(&tp->lk);
nni_aio_finish_error(aio, rv);
return;
}
nni_list_append(&tp->sends, aio);
- nni_tls_do_send(tp);
+ tls_do_send(tp);
nni_mtx_unlock(&tp->lk);
}
-void
-nni_tls_recv(nni_tls *tp, nni_aio *aio)
+static void
+tls_recv(void *arg, nni_aio *aio)
{
- int rv;
+ int rv;
+ tls *tp = arg;
if (nni_aio_begin(aio) != 0) {
return;
@@ -608,22 +573,22 @@ nni_tls_recv(nni_tls *tp, nni_aio *aio)
nni_aio_finish_error(aio, NNG_ECLOSED);
return;
}
- if ((rv = nni_aio_schedule(aio, nni_tls_cancel, tp)) != 0) {
+ if ((rv = nni_aio_schedule(aio, tls_cancel, tp)) != 0) {
nni_mtx_unlock(&tp->lk);
nni_aio_finish_error(aio, rv);
return;
}
nni_list_append(&tp->recvs, aio);
- nni_tls_do_recv(tp);
+ tls_do_recv(tp);
nni_mtx_unlock(&tp->lk);
}
static int
tls_get_verified(void *arg, void *buf, size_t *szp, nni_type t)
{
- nni_tls *tp = arg;
- bool v = (mbedtls_ssl_get_verify_result(&tp->ctx) == 0);
+ tls *tp = arg;
+ bool v = (mbedtls_ssl_get_verify_result(&tp->ctx) == 0);
return (nni_copyout_bool(v, buf, szp, t));
}
@@ -638,26 +603,28 @@ static const nni_option tls_options[] = {
},
};
-int
-nni_tls_setopt(
- nni_tls *tp, const char *name, const void *buf, size_t sz, nni_type t)
+static int
+tls_setx(void *arg, const char *name, const void *buf, size_t sz, nni_type t)
{
- int rv;
+ tls * tp = arg;
+ int rv;
+ nng_stream *tcp;
- if ((rv = nni_tcp_conn_setopt(tp->tcp, name, buf, sz, t)) !=
- NNG_ENOTSUP) {
+ tcp = (tp != NULL) ? tp->tcp : NULL;
+
+ if ((rv = nni_stream_setx(tcp, name, buf, sz, t)) != NNG_ENOTSUP) {
return (rv);
}
return (nni_setopt(tls_options, name, tp, buf, sz, t));
}
-int
-nni_tls_getopt(
- nni_tls *tp, const char *name, void *buf, size_t *szp, nni_type t)
+static int
+tls_getx(void *arg, const char *name, void *buf, size_t *szp, nni_type t)
{
- int rv;
+ tls *tp = arg;
+ int rv;
- if ((rv = nni_tcp_conn_getopt(tp->tcp, name, buf, szp, t)) !=
+ if ((rv = nni_stream_getx(tp->tcp, name, buf, szp, t)) !=
NNG_ENOTSUP) {
return (rv);
}
@@ -665,11 +632,12 @@ nni_tls_getopt(
}
static void
-nni_tls_do_handshake(nni_tls *tp)
+tls_do_handshake(tls *tp)
{
- int rv;
+ int rv;
+ nni_aio *aio;
- if (tp->tls_closed) {
+ if (tp->hsdone || tp->tls_closed) {
return;
}
rv = mbedtls_ssl_handshake(&tp->ctx);
@@ -686,15 +654,24 @@ nni_tls_do_handshake(nni_tls *tp)
default:
// some other error occurred, this causes us to tear it down
- nni_tls_fail(tp, nni_tls_mkerr(rv));
+ nng_stream_close(tp->tcp);
+ tp->tls_closed = true;
+ tp->tcp_closed = true;
+ rv = tls_mkerr(rv);
+
+ while (((aio = nni_list_first(&tp->recvs)) != NULL) ||
+ ((aio = nni_list_first(&tp->sends)) != NULL)) {
+ nni_aio_list_remove(aio);
+ nni_aio_finish_error(aio, rv);
+ }
}
}
-// nni_tls_do_send is called to try to send more data if we have not
+// tls_do_send is called to try to send more data if we have not
// yet completed the I/O. It also completes any transactions that
// *have* completed. It must be called with the lock held.
static void
-nni_tls_do_send(nni_tls *tp)
+tls_do_send(tls *tp)
{
nni_aio *aio;
@@ -732,7 +709,7 @@ nni_tls_do_send(nni_tls *tp)
// Want better diagnostics.
nni_aio_list_remove(aio);
if (n < 0) {
- nni_aio_finish_error(aio, nni_tls_mkerr(n));
+ nni_aio_finish_error(aio, tls_mkerr(n));
} else {
nni_aio_finish(aio, 0, n);
}
@@ -740,7 +717,7 @@ nni_tls_do_send(nni_tls *tp)
}
static void
-nni_tls_do_recv(nni_tls *tp)
+tls_do_recv(tls *tp)
{
nni_aio *aio;
@@ -777,16 +754,17 @@ nni_tls_do_recv(nni_tls *tp)
nni_aio_list_remove(aio);
if (n < 0) {
- nni_aio_finish_error(aio, nni_tls_mkerr(n));
+ nni_aio_finish_error(aio, tls_mkerr(n));
} else {
nni_aio_finish(aio, 0, n);
}
}
}
-void
-nni_tls_close(nni_tls *tp)
+static void
+tls_close(void *arg)
{
+ tls * tp = arg;
nni_aio *aio;
nni_aio_close(tp->tcp_send);
@@ -795,12 +773,8 @@ nni_tls_close(nni_tls *tp)
nni_mtx_lock(&tp->lk);
tp->tls_closed = true;
- while ((aio = nni_list_first(&tp->sends)) != NULL) {
- nni_aio_list_remove(aio);
- nni_aio_finish_error(aio, NNG_ECLOSED);
- }
-
- while ((aio = nni_list_first(&tp->recvs)) != NULL) {
+ while (((aio = nni_list_first(&tp->sends)) != NULL) ||
+ ((aio = nni_list_first(&tp->recvs)) != NULL)) {
nni_aio_list_remove(aio);
nni_aio_finish_error(aio, NNG_ECLOSED);
}
@@ -813,11 +787,36 @@ nni_tls_close(nni_tls *tp)
// connection at this point.
(void) mbedtls_ssl_close_notify(&tp->ctx);
} else {
- nni_tcp_conn_close(tp->tcp);
+ nng_stream_close(tp->tcp);
}
nni_mtx_unlock(&tp->lk);
}
+// This allocates a TLS structure, that can be used by the caller.
+// The reason we have this API is so that the base structure can be
+// embedded in the parent structure.
+int
+nni_tls_alloc(nng_stream **tlsp)
+{
+ tls *tp;
+
+ if ((tp = NNI_ALLOC_STRUCT(tp)) == NULL) {
+ return (NNG_ENOMEM);
+ }
+ nni_aio_list_init(&tp->sends);
+ nni_aio_list_init(&tp->recvs);
+ nni_mtx_init(&tp->lk);
+ tp->com.ops.s_close = tls_close;
+ tp->com.ops.s_free = tls_free;
+ tp->com.ops.s_send = tls_send;
+ tp->com.ops.s_recv = tls_recv;
+ tp->com.ops.s_getx = tls_getx;
+ tp->com.ops.s_setx = tls_setx;
+
+ *tlsp = (void *) tp;
+ return (0);
+}
+
int
nng_tls_config_server_name(nng_tls_config *cfg, const char *name)
{
@@ -882,14 +881,14 @@ nng_tls_config_ca_chain(
pem = (const uint8_t *) certs;
len = strlen(certs) + 1;
if ((rv = mbedtls_x509_crt_parse(&cfg->ca_certs, pem, len)) != 0) {
- rv = nni_tls_mkerr(rv);
+ rv = tls_mkerr(rv);
goto err;
}
if (crl != NULL) {
pem = (const uint8_t *) crl;
len = strlen(crl) + 1;
if ((rv = mbedtls_x509_crl_parse(&cfg->crl, pem, len)) != 0) {
- rv = nni_tls_mkerr(rv);
+ rv = tls_mkerr(rv);
goto err;
}
}
@@ -919,7 +918,7 @@ nng_tls_config_own_cert(
pem = (const uint8_t *) cert;
len = strlen(cert) + 1;
if ((rv = mbedtls_x509_crt_parse(&ck->crt, pem, len)) != 0) {
- rv = nni_tls_mkerr(rv);
+ rv = tls_mkerr(rv);
goto err;
}
@@ -928,7 +927,7 @@ nng_tls_config_own_cert(
rv = mbedtls_pk_parse_key(&ck->key, pem, len, (const uint8_t *) pass,
pass != NULL ? strlen(pass) : 0);
if (rv != 0) {
- rv = nni_tls_mkerr(rv);
+ rv = tls_mkerr(rv);
goto err;
}
@@ -941,7 +940,7 @@ nng_tls_config_own_cert(
rv = mbedtls_ssl_conf_own_cert(&cfg->cfg_ctx, &ck->crt, &ck->key);
if (rv != 0) {
nni_mtx_unlock(&cfg->lk);
- rv = nni_tls_mkerr(rv);
+ rv = tls_mkerr(rv);
goto err;
}
diff --git a/src/supplemental/tls/none/tls.c b/src/supplemental/tls/none/tls.c
index 257bb6b1..a1e70b73 100644
--- a/src/supplemental/tls/none/tls.c
+++ b/src/supplemental/tls/none/tls.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 2018 Devolutions <info@devolutions.net>
//
@@ -20,8 +20,6 @@
#include "core/nng_impl.h"
#include "supplemental/tls/tls_api.h"
-#include <nng/supplemental/tls/tls.h>
-
void
nni_tls_config_fini(nng_tls_config *cfg)
{
@@ -42,68 +40,6 @@ nni_tls_config_hold(nng_tls_config *cfg)
NNI_ARG_UNUSED(cfg);
}
-void
-nni_tls_fini(nni_tls *tp)
-{
- NNI_ARG_UNUSED(tp);
-}
-
-int
-nni_tls_init(nni_tls **tpp, nng_tls_config *cfg, nni_tcp_conn *tcp)
-{
- NNI_ARG_UNUSED(tpp);
- NNI_ARG_UNUSED(cfg);
- NNI_ARG_UNUSED(tcp);
-
- return (NNG_ENOTSUP);
-}
-
-// nni_tls_send is the exported send function. It has a similar
-// calling convention as the platform TCP pipe.
-void
-nni_tls_send(nni_tls *tp, nni_aio *aio)
-{
- NNI_ARG_UNUSED(tp);
- nni_aio_finish_error(aio, NNG_ENOTSUP);
-}
-
-void
-nni_tls_recv(nni_tls *tp, nni_aio *aio)
-{
- NNI_ARG_UNUSED(tp);
- nni_aio_finish_error(aio, NNG_ENOTSUP);
-}
-
-void
-nni_tls_close(nni_tls *tp)
-{
- NNI_ARG_UNUSED(tp);
-}
-
-int
-nni_tls_getopt(
- nni_tls *tp, const char *name, void *buf, size_t *szp, nni_type t)
-{
- NNI_ARG_UNUSED(tp);
- NNI_ARG_UNUSED(name);
- NNI_ARG_UNUSED(buf);
- NNI_ARG_UNUSED(szp);
- NNI_ARG_UNUSED(t);
- return (NNG_ENOTSUP);
-}
-
-int
-nni_tls_setopt(
- nni_tls *tp, const char *name, const void *buf, size_t sz, nni_type t)
-{
- NNI_ARG_UNUSED(tp);
- NNI_ARG_UNUSED(name);
- NNI_ARG_UNUSED(buf);
- NNI_ARG_UNUSED(sz);
- NNI_ARG_UNUSED(t);
- return (NNG_ENOTSUP);
-}
-
int
nng_tls_config_server_name(nng_tls_config *cfg, const char *name)
{
@@ -190,3 +126,29 @@ nng_tls_config_free(nng_tls_config *cfg)
{
NNI_ARG_UNUSED(cfg);
}
+
+int
+nni_tls_dialer_alloc(nng_stream_dialer **dp, const nng_url *url)
+{
+ NNI_ARG_UNUSED(dp);
+ NNI_ARG_UNUSED(url);
+ return (NNG_ENOTSUP);
+}
+
+int
+nni_tls_listener_alloc(nng_stream_listener **lp, const nng_url *url)
+{
+ NNI_ARG_UNUSED(lp);
+ NNI_ARG_UNUSED(url);
+ return (NNG_ENOTSUP);
+}
+
+int
+nni_tls_checkopt(const char *nm, const void *buf, size_t sz, nni_type t)
+{
+ NNI_ARG_UNUSED(nm);
+ NNI_ARG_UNUSED(buf);
+ NNI_ARG_UNUSED(sz);
+ NNI_ARG_UNUSED(t);
+ return (NNG_ENOTSUP);
+} \ No newline at end of file
diff --git a/src/supplemental/tls/tls_api.h b/src/supplemental/tls/tls_api.h
index 22dd68a0..4e6146b1 100644
--- a/src/supplemental/tls/tls_api.h
+++ b/src/supplemental/tls/tls_api.h
@@ -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>
//
@@ -12,12 +12,28 @@
#ifndef NNG_SUPPLEMENTAL_TLS_TLS_API_H
#define NNG_SUPPLEMENTAL_TLS_TLS_API_H
-#include <stdbool.h>
-
#include <nng/supplemental/tls/tls.h>
-// nni_tls represents the context for a single TLS stream.
-typedef struct nni_tls nni_tls;
+// This nni_tls_common structure represents the "base" structure for
+// an implementation to extend. One of these must be the first member
+// of the implementation specific TLS stream struct.
+typedef struct {
+ nng_stream ops;
+ nni_aio * aio; // system aio for connect/accept
+ nni_aio * uaio; // user aio for connect/accept
+ nng_tls_config *cfg;
+} nni_tls_common;
+
+// The implementation supplies this function to create the TLS connection
+// object. All fields will be zeroed.
+extern int nni_tls_alloc(nng_stream **);
+extern int nni_tls_dialer_alloc(nng_stream_dialer **, const nng_url *);
+extern int nni_tls_listener_alloc(nng_stream_listener **, const nng_url *);
+extern int nni_tls_checkopt(const char *, const void *, size_t, nni_type);
+
+// nni_tls_start is called by the common TLS dialer/listener completions
+// to start the TLS stream activity. This may also do allocations, etc.
+extern int nni_tls_start(nng_stream *, nng_stream *);
// nni_tls_config_init creates a new TLS configuration object.
// The object is created with a reference count of one.
@@ -34,30 +50,4 @@ extern void nni_tls_config_fini(nng_tls_config *);
// 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_tcp_conn *);
-extern void nni_tls_close(nni_tls *);
-extern void nni_tls_fini(nni_tls *);
-extern void nni_tls_send(nni_tls *, nng_aio *);
-extern void nni_tls_recv(nni_tls *, nng_aio *);
-
-extern int nni_tls_setopt(
- nni_tls *, const char *, const void *, size_t, nni_type);
-extern int nni_tls_getopt(nni_tls *, const char *, void *, size_t *, nni_type);
-
-extern int nni_tls_set(
- nng_tls *, const char *, const void *, size_t, nni_type);
-extern int nni_tls_get(nng_tls *, const char *, void *, size_t *, nni_type);
-
-extern int nni_tls_dialer_setopt(
- nng_tls_dialer *, const char *, const void *, size_t, nni_type);
-
-extern int nni_tls_dialer_getopt(
- nng_tls_dialer *, const char *, void *, size_t *, nni_type);
-
-extern int nni_tls_listener_setopt(
- nng_tls_listener *, const char *, const void *, size_t, nni_type);
-
-extern int nni_tls_listener_getopt(
- nng_tls_listener *, const char *, void *, size_t *, nni_type);
-
#endif // NNG_SUPPLEMENTAL_TLS_TLS_API_H
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);
}