diff options
Diffstat (limited to 'src/transport')
| -rw-r--r-- | src/transport/tls/tls.c | 70 | ||||
| -rw-r--r-- | src/transport/ws/CMakeLists.txt | 19 | ||||
| -rw-r--r-- | src/transport/ws/README.adoc | 38 | ||||
| -rw-r--r-- | src/transport/ws/websocket.c | 533 | ||||
| -rw-r--r-- | src/transport/ws/websocket.h | 62 | ||||
| -rw-r--r-- | src/transport/zerotier/zerotier.c | 15 |
6 files changed, 680 insertions, 57 deletions
diff --git a/src/transport/tls/tls.c b/src/transport/tls/tls.c index 8dcb3f60..9c794e64 100644 --- a/src/transport/tls/tls.c +++ b/src/transport/tls/tls.c @@ -10,7 +10,6 @@ #include <stdbool.h> #include <stdio.h> -#include <stdlib.h> #include <string.h> #include "core/nng_impl.h" @@ -498,46 +497,6 @@ nni_tls_pipe_getopt_remaddr(void *arg, void *v, size_t *szp) return (rv); } -static int -nni_tls_parse_pair(char *pair, char **hostp, char **servp) -{ - char *host, *serv, *end; - - if (pair[0] == '[') { - host = pair + 1; - // IP address enclosed ... for IPv6 usually. - if ((end = strchr(host, ']')) == NULL) { - return (NNG_EADDRINVAL); - } - *end = '\0'; - serv = end + 1; - if (*serv == ':') { - serv++; - } else if (*serv != '\0') { - return (NNG_EADDRINVAL); - } - } else { - host = pair; - serv = strchr(host, ':'); - if (serv != NULL) { - *serv = '\0'; - serv++; - } - } - if ((strlen(host) == 0) || (strcmp(host, "*") == 0)) { - *hostp = NULL; - } else { - *hostp = host; - } - if ((serv == NULL) || (strlen(serv) == 0)) { - *servp = NULL; - } else { - *servp = serv; - } - // Stash the port in big endian (network) byte order. - return (0); -} - // Note that the url *must* be in a modifiable buffer. int nni_tls_parse_url(char *url, char **lhost, char **lserv, char **rhost, @@ -555,8 +514,9 @@ nni_tls_parse_url(char *url, char **lhost, char **lserv, char **rhost, // is the second part. *h1 = '\0'; h1++; - if (((rv = nni_tls_parse_pair(h1, rhost, rserv)) != 0) || - ((rv = nni_tls_parse_pair(url, lhost, lserv)) != 0)) { + if (((rv = nni_tran_parse_host_port(h1, rhost, rserv)) != 0) || + ((rv = nni_tran_parse_host_port(url, lhost, lserv)) != + 0)) { return (rv); } if ((*rserv == NULL) || (*rhost == NULL)) { @@ -566,7 +526,7 @@ nni_tls_parse_url(char *url, char **lhost, char **lserv, char **rhost, } else if (mode == NNI_EP_MODE_DIAL) { *lhost = NULL; *lserv = NULL; - if ((rv = nni_tls_parse_pair(url, rhost, rserv)) != 0) { + if ((rv = nni_tran_parse_host_port(url, rhost, rserv)) != 0) { return (rv); } if ((*rserv == NULL) || (*rhost == NULL)) { @@ -577,7 +537,7 @@ nni_tls_parse_url(char *url, char **lhost, char **lserv, char **rhost, NNI_ASSERT(mode == NNI_EP_MODE_LISTEN); *rhost = NULL; *rserv = NULL; - if ((rv = nni_tls_parse_pair(url, lhost, lserv)) != 0) { + if ((rv = nni_tran_parse_host_port(url, lhost, lserv)) != 0) { return (rv); } // We have to have a port to listen on! @@ -657,9 +617,13 @@ nni_tls_ep_init(void **epp, const char *url, nni_sock *sock, int mode) return (NNG_EADDRINVAL); } + if ((rv = nni_aio_init(&aio, NULL, NULL)) != 0) { + return (rv); + } // Parse the URLs first. rv = nni_tls_parse_url(buf, &lhost, &lserv, &rhost, &rserv, mode); if (rv != 0) { + nni_aio_fini(aio); return (rv); } if (mode == NNI_EP_MODE_DIAL) { @@ -672,10 +636,6 @@ nni_tls_ep_init(void **epp, const char *url, nni_sock *sock, int mode) authmode = NNI_TLS_CONFIG_AUTH_MODE_NONE; } - if ((rv = nni_aio_init(&aio, NULL, NULL)) != 0) { - return (rv); - } - // XXX: arguably we could defer this part to the point we do a bind // or connect! @@ -683,7 +643,11 @@ nni_tls_ep_init(void **epp, const char *url, nni_sock *sock, int mode) aio->a_addr = &rsa; nni_plat_tcp_resolv(rhost, rserv, NNG_AF_UNSPEC, passive, aio); nni_aio_wait(aio); + nni_strfree(rserv); if ((rv = nni_aio_result(aio)) != 0) { + nni_strfree(rhost); + nni_strfree(lhost); + nni_strfree(lserv); nni_aio_fini(aio); return (rv); } @@ -695,7 +659,10 @@ nni_tls_ep_init(void **epp, const char *url, nni_sock *sock, int mode) aio->a_addr = &lsa; nni_plat_tcp_resolv(lhost, lserv, NNG_AF_UNSPEC, passive, aio); nni_aio_wait(aio); + nni_strfree(lhost); + nni_strfree(lserv); if ((rv = nni_aio_result(aio)) != 0) { + nni_strfree(rhost); nni_aio_fini(aio); return (rv); } @@ -705,12 +672,14 @@ nni_tls_ep_init(void **epp, const char *url, nni_sock *sock, int mode) nni_aio_fini(aio); if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) { + nni_strfree(rhost); return (NNG_ENOMEM); } nni_mtx_init(&ep->mtx); if (nni_strlcpy(ep->addr, url, sizeof(ep->addr)) >= sizeof(ep->addr)) { NNI_FREE_STRUCT(ep); + nni_strfree(rhost); return (NNG_EADDRINVAL); } @@ -718,15 +687,18 @@ nni_tls_ep_init(void **epp, const char *url, nni_sock *sock, int mode) ((rv = nni_tls_config_init(&ep->cfg, tlsmode)) != 0) || ((rv = nni_tls_config_auth_mode(ep->cfg, authmode)) != 0) || ((rv = nni_aio_init(&ep->aio, nni_tls_ep_cb, ep)) != 0)) { + nni_strfree(rhost); nni_tls_ep_fini(ep); return (rv); } if ((tlsmode == NNI_TLS_CONFIG_CLIENT) && (rhost != NULL)) { if ((rv = nni_tls_config_server_name(ep->cfg, rhost)) != 0) { + nni_strfree(rhost); nni_tls_ep_fini(ep); return (rv); } } + nni_strfree(rhost); ep->proto = nni_sock_proto(sock); ep->authmode = authmode; diff --git a/src/transport/ws/CMakeLists.txt b/src/transport/ws/CMakeLists.txt new file mode 100644 index 00000000..18842df9 --- /dev/null +++ b/src/transport/ws/CMakeLists.txt @@ -0,0 +1,19 @@ +# +# Copyright 2017 Staysail Systems, Inc. <info@staysail.tech> +# Copyright 2017 Capitar IT Group BV <info@capitar.com> +# +# This software is supplied under the terms of the MIT License, a +# copy of which should be located in the distribution where this +# file was obtained (LICENSE.txt). A copy of the license may also be +# found online at https://opensource.org/licenses/MIT. +# + +# WebSocket transport + +if (NNG_TRANSPORT_WS) + set(WS_SOURCES transport/ws/websocket.c transport/ws/websocket.h) + install(FILES websocket.h DESTINATION include/nng/transport/ws) + +endif() + +set(NNG_SOURCES ${NNG_SOURCES} ${WS_SOURCES} PARENT_SCOPE) diff --git a/src/transport/ws/README.adoc b/src/transport/ws/README.adoc new file mode 100644 index 00000000..e3101297 --- /dev/null +++ b/src/transport/ws/README.adoc @@ -0,0 +1,38 @@ += websocket transport + +This transport provides support for SP over websocket using TCP or TLS. +When using TCP, it is compatible with the libnanomsg legacy transport. +It also is compatible with mangos (both TCP and TLS). + +TLS support requires the mbedTLS library. + +We set the "protocol" such as "pair.sp.nanomsg.org" in the +Sec-WebSocket-Protocol field -- the client sets to the the server's +protocol - i.e. the protocol that the server speaks. For example, +if the the server is a REP, then a REQ client would send "rep.sp.nanomsg.org". + +The server sends the same value (it's own), per the WebSocket specs. (Note +that the client's protocol is never sent, but assumed to be complementary +to the protocol in the Sec-WebSocket-Protocol field.) + +Each SP message is a WebSocket message. + +WebSocket is defined in RFC 6455. + +== Design + +We unfortunately need to implement our own design for this -- the only +reasonable client library would be libcurl, and there is a dearth of +suitable server libraries. Since we don't have to support full HTTP, but +just the initial handshake, this isn't too tragic. + +== Multiple Server Sockets + +In order to support Multiple Server sockets listening on the same port, +the application must be long lived. We will set up a listener on the +configured TCP (or TLS) port, and examine the PATH supplied in the GET. +This will be used to match against the URL requested, and if the URL +matches we will create the appropriate pipe. + +If no server endpoint at that address can be found, we return an +HTTP error, and close the socket. diff --git a/src/transport/ws/websocket.c b/src/transport/ws/websocket.c new file mode 100644 index 00000000..8a73bcfb --- /dev/null +++ b/src/transport/ws/websocket.c @@ -0,0 +1,533 @@ +// +// Copyright 2017 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "core/nng_impl.h" +#include "supplemental/websocket/websocket.h" + +typedef struct ws_ep ws_ep; +typedef struct ws_pipe ws_pipe; + +struct ws_ep { + int mode; // NNI_EP_MODE_DIAL or NNI_EP_MODE_LISTEN + char * addr; + uint16_t lproto; // local protocol + uint16_t rproto; // remote protocol + size_t rcvmax; + char * protoname; + nni_list aios; + nni_mtx mtx; + nni_aio * connaio; + nni_aio * accaio; + nni_ws_listener *listener; + nni_ws_dialer * dialer; +}; + +struct ws_pipe { + int mode; // NNI_EP_MODE_DIAL or NNI_EP_MODE_LISTEN + nni_mtx mtx; + size_t rcvmax; // inherited from EP + bool closed; + uint16_t rproto; + uint16_t lproto; + nni_aio *user_txaio; + nni_aio *user_rxaio; + nni_aio *txaio; + nni_aio *rxaio; + nni_ws * ws; +}; + +static void +ws_pipe_send_cb(void *arg) +{ + ws_pipe *p = arg; + nni_aio *taio; + nni_aio *uaio; + + nni_mtx_lock(&p->mtx); + taio = p->txaio; + uaio = p->user_txaio; + p->user_txaio = NULL; + + if (uaio != NULL) { + int rv; + if ((rv = nni_aio_result(taio)) != 0) { + nni_aio_finish_error(uaio, rv); + } else { + nni_aio_finish(uaio, 0, 0); + } + } + nni_mtx_unlock(&p->mtx); +} + +static void +ws_pipe_recv_cb(void *arg) +{ + ws_pipe *p = arg; + nni_aio *raio = p->rxaio; + nni_aio *uaio; + int rv; + + nni_mtx_lock(&p->mtx); + uaio = p->user_rxaio; + p->user_rxaio = NULL; + if ((rv = nni_aio_result(raio)) != 0) { + if (uaio != NULL) { + nni_aio_finish_error(uaio, rv); + } + } else { + nni_msg *msg = nni_aio_get_msg(raio); + if (uaio != NULL) { + nni_aio_finish_msg(uaio, msg); + } else { + nni_msg_free(msg); + } + } + nni_mtx_unlock(&p->mtx); +} + +static void +ws_pipe_recv_cancel(nni_aio *aio, int rv) +{ + ws_pipe *p = aio->a_prov_data; + nni_mtx_lock(&p->mtx); + if (p->user_rxaio != aio) { + nni_mtx_unlock(&p->mtx); + return; + } + nni_aio_cancel(p->rxaio, rv); + nni_mtx_unlock(&p->mtx); +} + +static void +ws_pipe_recv(void *arg, nni_aio *aio) +{ + ws_pipe *p = arg; + + nni_mtx_lock(&p->mtx); + if (nni_aio_start(aio, ws_pipe_recv_cancel, p) != 0) { + nni_mtx_unlock(&p->mtx); + return; + } + p->user_rxaio = aio; + + nni_ws_recv_msg(p->ws, p->rxaio); + nni_mtx_unlock(&p->mtx); +} + +static void +ws_pipe_send_cancel(nni_aio *aio, int rv) +{ + ws_pipe *p = aio->a_prov_data; + nni_mtx_lock(&p->mtx); + if (p->user_txaio != aio) { + nni_mtx_unlock(&p->mtx); + return; + } + // This aborts the upper send, which will call back with an error + // when it is done. + nni_aio_cancel(p->txaio, rv); + nni_mtx_unlock(&p->mtx); +} + +static void +ws_pipe_send(void *arg, nni_aio *aio) +{ + ws_pipe *p = arg; + + nni_mtx_lock(&p->mtx); + if (nni_aio_start(aio, ws_pipe_send_cancel, p) != 0) { + nni_mtx_unlock(&p->mtx); + return; + } + p->user_txaio = aio; + nni_aio_set_msg(p->txaio, nni_aio_get_msg(aio)); + nni_aio_set_msg(aio, NULL); + + nni_ws_send_msg(p->ws, p->txaio); + nni_mtx_unlock(&p->mtx); +} + +static void +ws_pipe_fini(void *arg) +{ + ws_pipe *p = arg; + + nni_aio_stop(p->rxaio); + nni_aio_stop(p->txaio); + + nni_aio_fini(p->rxaio); + nni_aio_fini(p->txaio); + + if (p->ws) { + nni_ws_fini(p->ws); + } + nni_mtx_fini(&p->mtx); + NNI_FREE_STRUCT(p); +} + +static void +ws_pipe_close(void *arg) +{ + ws_pipe *p = arg; + + nni_mtx_lock(&p->mtx); + nni_ws_close(p->ws); + nni_mtx_unlock(&p->mtx); +} + +static int +ws_pipe_init(ws_pipe **pipep, ws_ep *ep, void *ws) +{ + ws_pipe *p; + int rv; + nni_aio *aio; + + if ((p = NNI_ALLOC_STRUCT(p)) == NULL) { + return (NNG_ENOMEM); + } + nni_mtx_init(&p->mtx); + + // Initialize AIOs. + if (((rv = nni_aio_init(&p->txaio, ws_pipe_send_cb, p)) != 0) || + ((rv = nni_aio_init(&p->rxaio, ws_pipe_recv_cb, p)) != 0)) { + ws_pipe_fini(p); + return (rv); + } + + p->mode = ep->mode; + p->rcvmax = ep->rcvmax; + // p->addr = ep->addr; + p->rproto = ep->rproto; + p->lproto = ep->lproto; + p->ws = ws; + + if ((aio = nni_list_first(&ep->aios)) != NULL) { + nni_aio_list_remove(aio); + nni_aio_finish_pipe(aio, p); + } + + *pipep = p; + return (0); +} + +static uint16_t +ws_pipe_peer(void *arg) +{ + ws_pipe *p = arg; + + return (p->rproto); +} + +static void +ws_pipe_start(void *arg, nni_aio *aio) +{ + if (nni_aio_start(aio, NULL, NULL) == 0) { + nni_aio_finish(aio, 0, 0); + } +} + +// We have very different approaches for server and client. +// Servers use the HTTP server framework, and a request methodology. + +static int +ws_ep_bind(void *arg) +{ + ws_ep *ep = arg; + return (nni_ws_listener_listen(ep->listener)); +} + +static void +ws_ep_cancel(nni_aio *aio, int rv) +{ + ws_ep *ep = aio->a_prov_data; + + nni_mtx_lock(&ep->mtx); + if (nni_aio_list_active(aio)) { + nni_aio_list_remove(aio); + nni_aio_finish_error(aio, rv); + } + nni_mtx_unlock(&ep->mtx); +} + +static void +ws_ep_accept(void *arg, nni_aio *aio) +{ + ws_ep *ep = arg; + + // We already bound, so we just need to look for an available + // pipe (created by the handler), and match it. + // Otherwise we stick the AIO in the accept list. + nni_mtx_lock(&ep->mtx); + if (nni_aio_start(aio, ws_ep_cancel, ep) != 0) { + nni_mtx_unlock(&ep->mtx); + return; + } + nni_list_append(&ep->aios, aio); + if (aio == nni_list_first(&ep->aios)) { + nni_ws_listener_accept(ep->listener, ep->accaio); + } + nni_mtx_unlock(&ep->mtx); +} + +static void +ws_ep_connect(void *arg, nni_aio *aio) +{ + ws_ep *ep = arg; + int rv; + + nni_mtx_lock(&ep->mtx); + NNI_ASSERT(nni_list_empty(&ep->aios)); + + // If we can't start, then its dying and we can't report + // either. + if ((rv = nni_aio_start(aio, ws_ep_cancel, ep)) != 0) { + nni_mtx_unlock(&ep->mtx); + return; + } + + nni_list_append(&ep->aios, aio); + nni_ws_dialer_dial(ep->dialer, ep->connaio); + nni_mtx_unlock(&ep->mtx); +} + +static int +ws_ep_setopt_recvmaxsz(void *arg, const void *v, size_t sz) +{ + ws_ep *ep = arg; + if (ep == NULL) { + return (nni_chkopt_size(v, sz, 0, NNI_MAXSZ)); + } + return (nni_setopt_size(&ep->rcvmax, v, sz, 0, NNI_MAXSZ)); +} + +static int +ws_ep_getopt_recvmaxsz(void *arg, void *v, size_t *szp) +{ + ws_ep *ep = arg; + return (nni_getopt_size(ep->rcvmax, v, szp)); +} + +static nni_tran_pipe_option ws_pipe_options[] = { +#if 0 + // clang-format off + { NNG_OPT_LOCADDR, ws_pipe_getopt_locaddr }, + { NNG_OPT_REMADDR, ws_pipe_getopt_remaddr }, + // clang-format on +#endif + // terminate list + { NULL, NULL } +}; + +static nni_tran_pipe ws_pipe_ops = { + .p_fini = ws_pipe_fini, + .p_start = ws_pipe_start, + .p_send = ws_pipe_send, + .p_recv = ws_pipe_recv, + .p_close = ws_pipe_close, + .p_peer = ws_pipe_peer, + .p_options = ws_pipe_options, +}; + +static nni_tran_ep_option ws_ep_options[] = { + { + .eo_name = NNG_OPT_RECVMAXSZ, + .eo_getopt = ws_ep_getopt_recvmaxsz, + .eo_setopt = ws_ep_setopt_recvmaxsz, + }, + // terminate list + { NULL, NULL, NULL }, +}; + +static void +ws_ep_fini(void *arg) +{ + ws_ep *ep = arg; + + nni_aio_stop(ep->accaio); + nni_aio_stop(ep->connaio); + nni_aio_fini(ep->accaio); + nni_aio_fini(ep->connaio); + if (ep->listener != NULL) { + nni_ws_listener_fini(ep->listener); + } + if (ep->dialer != NULL) { + nni_ws_dialer_fini(ep->dialer); + } + nni_strfree(ep->addr); + nni_strfree(ep->protoname); + nni_mtx_fini(&ep->mtx); + NNI_FREE_STRUCT(ep); +} + +static void +ws_ep_conn_cb(void *arg) +{ + ws_ep * ep = arg; + ws_pipe *p; + nni_aio *caio = ep->connaio; + nni_aio *uaio; + int rv; + nni_ws * ws = NULL; + + nni_mtx_lock(&ep->mtx); + if (nni_aio_result(caio) == 0) { + ws = nni_aio_get_pipe(caio); + } + if ((uaio = nni_list_first(&ep->aios)) == NULL) { + // The client stopped caring about this! + if (ws != NULL) { + nni_ws_fini(ws); + } + nni_mtx_unlock(&ep->mtx); + return; + } + nni_aio_list_remove(uaio); + NNI_ASSERT(nni_list_empty(&ep->aios)); + if ((rv = nni_aio_result(caio)) != 0) { + nni_aio_finish_error(uaio, rv); + } else if ((rv = ws_pipe_init(&p, ep, ws)) != 0) { + nni_ws_fini(ws); + nni_aio_finish_error(uaio, rv); + } else { + nni_aio_finish_pipe(uaio, p); + } + nni_mtx_unlock(&ep->mtx); +} + +static void +ws_ep_close(void *arg) +{ + ws_ep *ep = arg; + + if (ep->mode == NNI_EP_MODE_LISTEN) { + nni_ws_listener_close(ep->listener); + } else { + nni_ws_dialer_close(ep->dialer); + } +} + +static void +ws_ep_acc_cb(void *arg) +{ + ws_ep * ep = arg; + nni_aio *aaio = ep->accaio; + nni_aio *uaio; + int rv; + + nni_mtx_lock(&ep->mtx); + uaio = nni_list_first(&ep->aios); + if ((rv = nni_aio_result(aaio)) != 0) { + if (uaio != NULL) { + nni_aio_list_remove(uaio); + nni_aio_finish_error(uaio, rv); + } + } else { + nni_ws *ws = nni_aio_get_pipe(aaio); + if (uaio != NULL) { + ws_pipe *p; + // Make a pipe + nni_aio_list_remove(uaio); + if ((rv = ws_pipe_init(&p, ep, ws)) != 0) { + nni_ws_close(ws); + nni_aio_finish_error(uaio, rv); + } else { + nni_aio_finish_pipe(uaio, p); + } + } + } + if (!nni_list_empty(&ep->aios)) { + nni_ws_listener_accept(ep->listener, aaio); + } + nni_mtx_unlock(&ep->mtx); +} + +static int +ws_ep_init(void **epp, const char *url, nni_sock *sock, int mode) +{ + ws_ep * ep; + const char *pname; + int rv; + + if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) { + return (NNG_ENOMEM); + } + + nni_mtx_init(&ep->mtx); + + // List of pipes (server only). + nni_aio_list_init(&ep->aios); + + ep->mode = mode; + ep->lproto = nni_sock_proto(sock); + ep->rproto = nni_sock_peer(sock); + + if (mode == NNI_EP_MODE_DIAL) { + pname = nni_sock_peer_name(sock); + rv = nni_ws_dialer_init(&ep->dialer, url); + } else { + pname = nni_sock_proto_name(sock); + rv = nni_ws_listener_init(&ep->listener, url); + } + + if ((rv == 0) && ((ep->addr = nni_strdup(url)) == NULL)) { + rv = NNG_ENOMEM; + } + if ((rv != 0) || + ((rv = nni_aio_init(&ep->connaio, ws_ep_conn_cb, ep)) != 0) || + ((rv = nni_aio_init(&ep->accaio, ws_ep_acc_cb, ep)) != 0) || + ((rv = nni_asprintf(&ep->protoname, "%s.sp.nanomsg.org", pname)) != + 0)) { + ws_ep_fini(ep); + return (rv); + } + + *epp = ep; + return (0); +} +static int +ws_tran_init(void) +{ + return (0); +} + +static void +ws_tran_fini(void) +{ +} + +static nni_tran_ep ws_ep_ops = { + .ep_init = ws_ep_init, + .ep_fini = ws_ep_fini, + .ep_connect = ws_ep_connect, + .ep_bind = ws_ep_bind, + .ep_accept = ws_ep_accept, + .ep_close = ws_ep_close, + .ep_options = ws_ep_options, +}; + +static nni_tran ws_tran = { + .tran_version = NNI_TRANSPORT_VERSION, + .tran_scheme = "ws", + .tran_ep = &ws_ep_ops, + .tran_pipe = &ws_pipe_ops, + .tran_init = ws_tran_init, + .tran_fini = ws_tran_fini, +}; + +int +nng_ws_register(void) +{ + return (nni_tran_register(&ws_tran)); +} diff --git a/src/transport/ws/websocket.h b/src/transport/ws/websocket.h new file mode 100644 index 00000000..1beb6156 --- /dev/null +++ b/src/transport/ws/websocket.h @@ -0,0 +1,62 @@ +// +// Copyright 2017 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#ifndef NNG_TRANSPORT_WS_WEBSOCKET_H +#define NNG_TRANSPORT_WS_WEBSOCKET_H + +// TLS transport. This is used for communication via TLS v1.2 over TCP/IP. + +NNG_DECL int nng_ws_register(void); + +// TLS options. Note that these can only be set *before* the endpoint is +// started. Once started, it is no longer possible to alter the TLS +// configuration. + +// NNG_OPT_TLS_CA_CERT is a string with one or more X.509 certificates, +// representing the entire CA chain. The content may be either PEM or DER +// encoded. +#define NNG_OPT_TLS_CA_CERT "tls:ca-cert" + +// NNG_OPT_TLS_CRL is a PEM encoded CRL (revocation list). Multiple lists +// may be loaded by using this option multiple times. +#define NNG_OPT_TLS_CRL "tls:crl" + +// NNG_OPT_TLS_CERT is used to specify our own certificate. At present +// only one certificate may be supplied. (In the future it may be +// possible to call this multiple times, for servers that select different +// certificates depending upon client capabilities.) +#define NNG_OPT_TLS_CERT "tls:cert" + +// NNG_OPT_TLS_PRIVATE_KEY is used to specify the private key used +// with the given certificate. This should be called after setting +// the certificate. The private key may be in PEM or DER format. +// If in PEM encoded, a terminating ZERO byte should be included. +#define NNG_OPT_TLS_PRIVATE_KEY "tls:private-key" + +// NNG_OPT_TLS_PRIVATE_KEY_PASSWORD is used to specify a password +// used for the private key. The value is an ASCIIZ string. +#define NNG_OPT_TLS_PRIVATE_KEY_PASSWORD "tls:private-key-password" + +// NNG_OPT_TLS_AUTH_MODE is an integer indicating whether our +// peer should be verified or not. It is required on clients/dialers, +// and off on servers/listeners, by default. +#define NNG_OPT_TLS_AUTH_MODE "tls:auth-mode" + +extern int nng_tls_auth_mode_required; +extern int nng_tls_auth_mode_none; +extern int nng_tls_auth_mode_optional; + +// NNG_OPT_TLS_AUTH_VERIFIED is a boolean that can be read on pipes, +// indicating whether the peer certificate is verified. +#define NNG_OPT_TLS_AUTH_VERIFIED "tls:auth-verified" + +// XXX: TBD: Ciphersuite selection and reporting. Session reuse? + +#endif // NNG_TRANSPORT_WS_WEBSOCKET_H diff --git a/src/transport/zerotier/zerotier.c b/src/transport/zerotier/zerotier.c index 607c353c..16a29da1 100644 --- a/src/transport/zerotier/zerotier.c +++ b/src/transport/zerotier/zerotier.c @@ -1292,7 +1292,7 @@ zt_wire_packet_send_cb(void *arg) nni_aio * aio = arg; zt_send_hdr *hdr; - hdr = nni_aio_get_data(aio); + hdr = nni_aio_get_data(aio, 0); nni_free(hdr, hdr->len + sizeof(*hdr)); nni_aio_fini_cb(aio); } @@ -1355,7 +1355,7 @@ zt_wire_packet_send(ZT_Node *node, void *userptr, void *thr, int64_t socket, buf += sizeof(*hdr); memcpy(buf, data, len); - nni_aio_set_data(aio, hdr); + nni_aio_set_data(aio, hdr, 0); hdr->sa = addr; hdr->len = len; @@ -2001,7 +2001,7 @@ zt_pipe_ping_cb(void *arg) } if (p->zp_ping_try < p->zp_ping_count) { nni_time now = nni_clock(); - nni_aio_set_timeout(aio, now + p->zp_ping_time); + nni_aio_set_timeout(aio, p->zp_ping_time); // We want pings. We only send one if needed, but we // use the the timer to wake us up even if we aren't // going to send a ping. (We don't increment the try count @@ -2034,7 +2034,7 @@ zt_pipe_start(void *arg, nni_aio *aio) if ((p->zp_ping_count > 0) && (p->zp_ping_time != NNI_TIME_ZERO) && (p->zp_ping_time != NNI_TIME_NEVER) && (p->zp_ping_aio != NULL)) { p->zp_ping_try = 0; - nni_aio_set_timeout(aio, nni_clock() + p->zp_ping_time); + nni_aio_set_timeout(aio, p->zp_ping_time); if (nni_aio_start(p->zp_ping_aio, zt_pipe_cancel_ping, p) == 0) { p->zp_ping_active = 1; @@ -2456,7 +2456,7 @@ zt_ep_conn_req_cb(void *arg) } if (nni_list_first(&ep->ze_aios) != NULL) { - nni_aio_set_timeout(aio, nni_clock() + zt_conn_interval); + nni_aio_set_timeout(aio, zt_conn_interval); if (nni_aio_start(aio, zt_ep_conn_req_cancel, ep) == 0) { ep->ze_creq_active = 1; ep->ze_creq_try++; @@ -2479,8 +2479,7 @@ zt_ep_connect(void *arg, nni_aio *aio) nni_mtx_lock(&zt_lk); if (nni_aio_start(aio, zt_ep_cancel, ep) == 0) { - nni_time now = nni_clock(); - int rv; + int rv; // Clear the port so we get an ephemeral port. ep->ze_laddr &= ~((uint64_t) zt_port_mask); @@ -2498,7 +2497,7 @@ zt_ep_connect(void *arg, nni_aio *aio) ep->ze_running = 1; - nni_aio_set_timeout(ep->ze_creq_aio, now + zt_conn_interval); + nni_aio_set_timeout(ep->ze_creq_aio, zt_conn_interval); if (nni_aio_start( ep->ze_creq_aio, zt_ep_conn_req_cancel, ep) == 0) { |
